You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
refactor: auto-generate SDK from route tree, single entry point
Rework the typed SDK to auto-discover ALL commands from the Stricli
route tree with zero manual config:
- generate-sdk.ts walks the entire route tree recursively, discovers
44 commands, generates typed methods using CLI route names as-is
(sdk.org.list, sdk.dashboard.widget.add)
- Return types derived from __jsonSchema (PR #582) via
extractSchemaFields() — commands with schemas get typed returns,
others default to unknown
- Positional params derived from introspection placeholder strings
- createSentrySDK() is now the single public API (default export)
- sdk.run() escape hatch replaces the standalone sentry() function
- SentryError/SentryOptions extracted to sdk-types.ts to break
circular deps between index.ts and sdk-invoke.ts
* **getConfigDir and getAuthToken read global process.env directly**: \`src/lib/env.ts\` provides a module-level env registry: \`getEnv()\` defaults to \`process.env\`, \`setEnv(env)\` swaps it. Library entry (\`src/index.ts\`) calls \`setEnv({ ...process.env, ...overrides })\` before running commands, restores in \`finally\`. All ~14 files that previously read \`process.env.SENTRY\_\*\` directly now use \`getEnv().SENTRY\_\*\`. Key files ported: \`db/auth.ts\`, \`db/index.ts\`, \`db/schema.ts\`, \`constants.ts\`, \`resolve-target.ts\`, \`telemetry.ts\`, \`formatters/plain-detect.ts\`, \`sentry-url-parser.ts\` (which also WRITES to env), \`logger.ts\`, \`response-cache.ts\`, \`api/infrastructure.ts\`, \`dsn/env.ts\`, \`version-check.ts\`, \`oauth.ts\`. CLI mode never calls \`setEnv()\` so behavior is unchanged. Tests using \`useTestConfigDir()\` continue to work since \`getEnv()\` defaults to \`process.env\`.
* **Library API: variadic sentry() function with last-arg options detection**: The \`sentry()\` library export in \`src/index.ts\` uses variadic args with optional trailing options object: \`sentry("issue", "list", { token: "..." })\`. Last-arg detection: if final arg is an object (not string), it's \`SentryOptions\`. Options: \`token?\` (auth override, auto-fills from \`SENTRY\_AUTH\_TOKEN\`/\`SENTRY\_TOKEN\` env vars), \`text?\` (return human-readable string instead of parsed JSON), \`cwd?\` (working directory for DSN detection). Default behavior: JSON output via \`SENTRY\_OUTPUT\_FORMAT=json\` env var. Zero-copy return via \`captureObject\` duck-type on Writer — skips JSON.stringify/parse round-trip. Non-zero exit throws \`SentryError\` with \`.exitCode\` and \`.stderr\`. If \`capturedResult\` exists when an error is thrown (OutputError pattern), returns the data instead of throwing. Env isolation via \`setEnv({ ...process.env })\` — consumer's \`process.env\` never mutated. \`createSentrySDK(options?)\` provides typed namespace API that invokes commands directly via \`Command.loader()\`, bypassing Stricli's string dispatch.
906
+
* **Library API: createSentrySDK() is the single entry point**: \`createSentrySDK(options?)\` in \`src/index.ts\` is the sole public API. It returns a typed SDK object with methods for every CLI command plus a \`run(...args)\` escape hatch. The standalone variadic \`sentry()\` function has been removed. \`SentryError\` and \`SentryOptions\` live in \`src/lib/sdk-types.ts\` (shared module to avoid circular deps between \`index.ts\` ↔ \`sdk-invoke.ts\`) and are re-exported from \`index.ts\`. Env isolation via \`setEnv()\`, zero-copy \`captureObject\` return, and \`OutputError\` → data recovery patterns are handled by \`buildInvoker()\` (typed methods) and \`buildRunner()\` (run escape hatch) in \`sdk-invoke.ts\`. Options: \`token?\`, \`text?\` (run-only), \`cwd?\`. Default JSON output via \`SENTRY\_OUTPUT\_FORMAT=json\` env var. Non-zero exit throws \`SentryError\` with \`.exitCode\` and \`.stderr\`.
* **Library mode telemetry strips all global-polluting Sentry integrations**: When \`initSentry(enabled, { libraryMode: true })\` is called, the Sentry SDK initializes without integrations that pollute the host process. \`LIBRARY\_EXCLUDED\_INTEGRATIONS\` extends the base set with: \`OnUncaughtException\`, \`OnUnhandledRejection\`, \`ProcessSession\` (process listeners), \`Http\`/\`NodeFetch\` (trace header injection), \`FunctionToString\` (wraps \`Function.prototype.toString\`), \`ChildProcess\`/\`NodeContext\`. Also disables \`enableLogs\` and \`sendClientReports\` (both use timers/\`beforeExit\`), and skips \`process.on('beforeExit')\` handler registration. Keeps pure integrations: \`eventFiltersIntegration\`, \`linkedErrorsIntegration\`. Library entry manually calls \`client.flush(3000)\` after command completion (both success and error paths via \`flushTelemetry()\` helper). Only unavoidable global: \`globalThis.\_\_SENTRY\_\_\[SDK\_VERSION]\`.
* **Typed SDK uses direct Command.loader() invocation bypassing Stricli dispatch**: \`createSentrySDK(options?)\` in \`src/index.ts\` builds a typed namespace API (\`sdk.organizations.list()\`, \`sdk.issues.get()\`) generated by \`script/generate-sdk.ts\`. At runtime, \`src/lib/sdk-invoke.ts\` resolves commands by walking the Stricli route tree via \`routes.getRoutingTargetForInput()\`, caches the \`Command\` objects, then calls \`command.loader()\` to get the wrapped func and invokes it with \`func.call(context, flags, ...args)\`. This bypasses Stricli's string scanning, route resolution, and flag parsing entirely — flags are passed as typed objects. The codegen script introspects flag definitions (kind, default, optional, variadic) at build time and generates TypeScript parameter interfaces. Return types use a manual type map (~20 entries) until schema registration on OutputConfig is implemented (#566).
912
+
* **Typed SDK uses direct Command.loader() invocation bypassing Stricli dispatch**: \`createSentrySDK(options?)\` in \`src/index.ts\` builds a typed namespace API (\`sdk.org.list()\`, \`sdk.issue.view()\`) generated by \`script/generate-sdk.ts\`. At runtime, \`src/lib/sdk-invoke.ts\` resolves commands via Stricli route tree, caches \`Command\` objects, and calls \`command.loader()\` directly — bypassing string dispatch and flag parsing. The standalone variadic \`sentry()\` function has been removed: typed SDK methods are the primary path, with \`sdk.run()\` as an escape hatch for arbitrary CLI strings (interactive commands like \`auth login\`, raw \`api\` passthrough). The codegen auto-discovers ALL commands from the route tree with zero config, using CLI route names as-is (\`org.list\`, \`dashboard.widget.add\`). Return types are derived from \`__jsonSchema\` when present, otherwise \`unknown\`. Positional patterns are derived from introspection placeholder strings. Hidden routes (plural aliases) are skipped.
* **OutputError propagates via throw instead of process.exit()**: The \`process.exit()\` call in \`command.ts\` (OutputError handler) is replaced with \`throw err\` to support library mode. \`OutputError\` is re-thrown through Stricli via \`exceptionWhileRunningCommand\` in \`app.ts\` (added before the \`AuthError\` check), so Stricli never writes an error message for it. In CLI mode (\`cli.ts\`), OutputError is caught and \`process.exitCode\` is set silently without writing to stderr (data was already rendered). In library mode (\`index.ts\`), the catch block checks if \`capturedResult\` has data (the OutputError's payload was rendered to stdout via \`captureObject\` before the throw) and returns it instead of throwing \`SentryError\`. This eliminates the only \`process.exit()\` outside of \`bin.ts\`.
* **SDK codegen auto-generates all commands from route tree**: \`script/generate-sdk.ts\` walks the entire Stricli route tree via \`discoverCommands()\`, skipping hidden routes (plural aliases). For each visible command: extracts flags via introspection, derives positional params from placeholder strings, checks \`__jsonSchema\` for typed return types (via \`extractSchemaFields()\`), and generates TypeScript param interfaces + method implementations. Naming uses CLI route path as-is: \`["org", "list"]\` → \`sdk.org.list()\`, \`["dashboard", "widget", "add"]\` → \`sdk.dashboard.widget.add()\`. Slash-separated positional names (e.g. \`org/project\`) are converted to camelCase (\`orgProject\`). Dotted field names in schemas are quoted (\`"span.op"\`). No manual config table — all 44+ commands are auto-discovered. Return types default to \`unknown\` when no schema is registered.
0 commit comments