@databricks/appkit 0.61.1 → 0.62.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CLAUDE.md +1 -0
- package/dist/agents/databricks.d.ts.map +1 -1
- package/dist/agents/databricks.js.map +1 -1
- package/dist/agents/supervisor-api.d.ts.map +1 -1
- package/dist/agents/supervisor-api.js.map +1 -1
- package/dist/app/index.d.ts.map +1 -1
- package/dist/app/index.js.map +1 -1
- package/dist/appkit/package.js +1 -1
- package/dist/cache/index.d.ts.map +1 -1
- package/dist/cache/index.js.map +1 -1
- package/dist/cache/storage/memory.js.map +1 -1
- package/dist/cache/storage/persistent.js.map +1 -1
- package/dist/cli/commands/codemod/index.js.map +1 -1
- package/dist/cli/commands/codemod/on-plugins-ready.js.map +1 -1
- package/dist/cli/commands/docs.js.map +1 -1
- package/dist/cli/commands/doctor/bundle.js.map +1 -1
- package/dist/cli/commands/doctor/index.js.map +1 -1
- package/dist/cli/commands/doctor/report.js.map +1 -1
- package/dist/cli/commands/doctor/resolve-targets.js.map +1 -1
- package/dist/cli/commands/doctor/run.js.map +1 -1
- package/dist/cli/commands/generate-types.js.map +1 -1
- package/dist/cli/commands/lint.js.map +1 -1
- package/dist/cli/commands/plugin/add-resource/add-resource.js.map +1 -1
- package/dist/cli/commands/plugin/create/create.js.map +1 -1
- package/dist/cli/commands/plugin/create/prompt-resource.js.map +1 -1
- package/dist/cli/commands/plugin/create/scaffold.js.map +1 -1
- package/dist/cli/commands/plugin/index.js.map +1 -1
- package/dist/cli/commands/plugin/list/list.js.map +1 -1
- package/dist/cli/commands/plugin/promote/promote.js.map +1 -1
- package/dist/cli/commands/plugin/sync/sync.js.map +1 -1
- package/dist/cli/commands/plugin/validate/validate-manifest.js.map +1 -1
- package/dist/cli/commands/plugin/validate/validate.js.map +1 -1
- package/dist/cli/commands/registry/add.js.map +1 -1
- package/dist/cli/commands/registry/client.js.map +1 -1
- package/dist/cli/commands/registry/config-writer.js.map +1 -1
- package/dist/cli/commands/registry/env-reconcile.js.map +1 -1
- package/dist/cli/commands/registry/env-writer.js.map +1 -1
- package/dist/cli/commands/registry/index.js.map +1 -1
- package/dist/cli/commands/registry/info.js.map +1 -1
- package/dist/cli/commands/registry/list.js.map +1 -1
- package/dist/cli/commands/registry/requirements.js.map +1 -1
- package/dist/cli/commands/registry/server-register.js.map +1 -1
- package/dist/cli/commands/registry/workspace-picker.js.map +1 -1
- package/dist/cli/commands/setup.js.map +1 -1
- package/dist/cli/index.js.map +1 -1
- package/dist/connectors/files/client.js.map +1 -1
- package/dist/connectors/lakebase/index.d.ts.map +1 -1
- package/dist/connectors/lakebase/index.js.map +1 -1
- package/dist/connectors/lakebase/pool-manager.d.ts.map +1 -1
- package/dist/connectors/lakebase/pool-manager.js.map +1 -1
- package/dist/connectors/lakebase/routing-pool.d.ts.map +1 -1
- package/dist/connectors/lakebase/routing-pool.js.map +1 -1
- package/dist/connectors/mcp/client.d.ts.map +1 -1
- package/dist/connectors/mcp/client.js.map +1 -1
- package/dist/connectors/sql-warehouse/client.js.map +1 -1
- package/dist/context/client-options.js.map +1 -1
- package/dist/context/execution-context.d.ts.map +1 -1
- package/dist/context/execution-context.js.map +1 -1
- package/dist/context/index.d.ts +1 -1
- package/dist/context/service-context.d.ts +55 -3
- package/dist/context/service-context.d.ts.map +1 -1
- package/dist/context/service-context.js.map +1 -1
- package/dist/core/agent/build-toolkit.js.map +1 -1
- package/dist/core/agent/load-agents.d.ts.map +1 -1
- package/dist/core/agent/load-agents.js.map +1 -1
- package/dist/core/agent/run-agent.d.ts.map +1 -1
- package/dist/core/agent/run-agent.js.map +1 -1
- package/dist/core/agent/toolkit-resolver.js.map +1 -1
- package/dist/core/agent/tools/define-tool.d.ts.map +1 -1
- package/dist/core/agent/tools/define-tool.js.map +1 -1
- package/dist/core/agent/tools/tool.d.ts.map +1 -1
- package/dist/core/agent/tools/tool.js.map +1 -1
- package/dist/core/agent/types.d.ts.map +1 -1
- package/dist/core/agent/types.js.map +1 -1
- package/dist/core/appkit.d.ts.map +1 -1
- package/dist/core/appkit.js.map +1 -1
- package/dist/core/lifecycle-manager.js.map +1 -1
- package/dist/core/plugin-context.d.ts +13 -0
- package/dist/core/plugin-context.d.ts.map +1 -1
- package/dist/core/plugin-context.js +12 -1
- package/dist/core/plugin-context.js.map +1 -1
- package/dist/errors/configuration.d.ts.map +1 -1
- package/dist/errors/configuration.js.map +1 -1
- package/dist/logging/logger.js.map +1 -1
- package/dist/logging/wide-event-emitter.js.map +1 -1
- package/dist/plugin/dev-reader.d.ts.map +1 -1
- package/dist/plugin/dev-reader.js.map +1 -1
- package/dist/plugin/interceptors/cache.js.map +1 -1
- package/dist/plugin/interceptors/retry.js.map +1 -1
- package/dist/plugin/interceptors/telemetry.js.map +1 -1
- package/dist/plugin/plugin.d.ts +2 -2
- package/dist/plugin/plugin.d.ts.map +1 -1
- package/dist/plugin/plugin.js.map +1 -1
- package/dist/plugins/agents/agents.d.ts.map +1 -1
- package/dist/plugins/agents/agents.js.map +1 -1
- package/dist/plugins/agents/event-translator.js.map +1 -1
- package/dist/plugins/agents/thread-store.js.map +1 -1
- package/dist/plugins/ai-search/ai-search.d.ts.map +1 -1
- package/dist/plugins/ai-search/ai-search.js.map +1 -1
- package/dist/plugins/analytics/analytics.d.ts.map +1 -1
- package/dist/plugins/analytics/analytics.js.map +1 -1
- package/dist/plugins/analytics/mv/cache.js.map +1 -1
- package/dist/plugins/analytics/mv/constants.js.map +1 -1
- package/dist/plugins/analytics/mv/formatters.js.map +1 -1
- package/dist/plugins/analytics/mv/metadata.js.map +1 -1
- package/dist/plugins/analytics/mv/registry.js.map +1 -1
- package/dist/plugins/analytics/mv/schemas.js.map +1 -1
- package/dist/plugins/analytics/query.js.map +1 -1
- package/dist/plugins/analytics/result-delivery.js.map +1 -1
- package/dist/plugins/files/helpers.js.map +1 -1
- package/dist/plugins/files/plugin.d.ts.map +1 -1
- package/dist/plugins/files/plugin.js.map +1 -1
- package/dist/plugins/files/types.d.ts.map +1 -1
- package/dist/plugins/genie/genie.d.ts.map +1 -1
- package/dist/plugins/genie/genie.js.map +1 -1
- package/dist/plugins/jobs/plugin.d.ts.map +1 -1
- package/dist/plugins/jobs/plugin.js.map +1 -1
- package/dist/plugins/jobs/types.d.ts.map +1 -1
- package/dist/plugins/lakebase/lakebase.d.ts.map +1 -1
- package/dist/plugins/lakebase/lakebase.js.map +1 -1
- package/dist/plugins/lakebase/types.d.ts.map +1 -1
- package/dist/plugins/server/base-server.js.map +1 -1
- package/dist/plugins/server/client-config-sanitizer.js.map +1 -1
- package/dist/plugins/server/index.d.ts.map +1 -1
- package/dist/plugins/server/index.js.map +1 -1
- package/dist/plugins/server/react-source-loc-vite-plugin.js.map +1 -1
- package/dist/plugins/server/remote-tunnel/remote-tunnel-controller.js.map +1 -1
- package/dist/plugins/server/remote-tunnel/remote-tunnel-manager.js.map +1 -1
- package/dist/plugins/server/static-server.js.map +1 -1
- package/dist/plugins/server/utils.js.map +1 -1
- package/dist/plugins/server/vite-dev-server.js.map +1 -1
- package/dist/plugins/serving/schema-filter.js.map +1 -1
- package/dist/plugins/serving/serving.d.ts.map +1 -1
- package/dist/plugins/serving/serving.js.map +1 -1
- package/dist/plugins/ui-variants/index.js.map +1 -1
- package/dist/registry/manifest-loader.d.ts.map +1 -1
- package/dist/registry/manifest-loader.js.map +1 -1
- package/dist/registry/resource-registry.d.ts.map +1 -1
- package/dist/registry/resource-registry.js.map +1 -1
- package/dist/registry/types.d.ts.map +1 -1
- package/dist/registry/types.js.map +1 -1
- package/dist/schemas/manifest.d.ts.map +1 -1
- package/dist/schemas/manifest.js.map +1 -1
- package/dist/schemas/metric-fqn.js.map +1 -1
- package/dist/shared/src/plugin.d.ts.map +1 -1
- package/dist/shared/src/schemas/manifest.d.ts.map +1 -1
- package/dist/shared/src/schemas/metric-fqn.js.map +1 -1
- package/dist/shared/src/schemas/metric-metadata-bundle.js.map +1 -1
- package/dist/shared/src/schemas/metric-source.js.map +1 -1
- package/dist/shared/src/sse/analytics.js.map +1 -1
- package/dist/shared/src/workspace-client/legacy.js.map +1 -1
- package/dist/shared/src/workspace-client/types.d.ts.map +1 -1
- package/dist/stream/sse-writer.js.map +1 -1
- package/dist/stream/stream-manager.d.ts.map +1 -1
- package/dist/stream/stream-manager.js.map +1 -1
- package/dist/stream/types.js.map +1 -1
- package/dist/telemetry/instrumentations.js.map +1 -1
- package/dist/telemetry/telemetry-manager.js.map +1 -1
- package/dist/telemetry/telemetry-provider.js.map +1 -1
- package/dist/telemetry/trace-sampler.js.map +1 -1
- package/dist/testing/expect-stream.d.ts +111 -0
- package/dist/testing/expect-stream.d.ts.map +1 -0
- package/dist/testing/expect-stream.js +154 -0
- package/dist/testing/expect-stream.js.map +1 -0
- package/dist/testing/fixtures.d.ts +257 -0
- package/dist/testing/fixtures.d.ts.map +1 -0
- package/dist/testing/fixtures.js +385 -0
- package/dist/testing/fixtures.js.map +1 -0
- package/dist/testing/index.d.ts +5 -0
- package/dist/testing/index.js +5 -0
- package/dist/testing/test-plugin-context.d.ts +158 -0
- package/dist/testing/test-plugin-context.d.ts.map +1 -0
- package/dist/testing/test-plugin-context.js +139 -0
- package/dist/testing/test-plugin-context.js.map +1 -0
- package/dist/type-generator/cache.js.map +1 -1
- package/dist/type-generator/index.js.map +1 -1
- package/dist/type-generator/migration.js.map +1 -1
- package/dist/type-generator/mv-registry/config.js.map +1 -1
- package/dist/type-generator/query-registry.js.map +1 -1
- package/dist/type-generator/serving/cache.js.map +1 -1
- package/dist/type-generator/serving/generator.js.map +1 -1
- package/dist/type-generator/serving/server-file-extractor.d.ts.map +1 -1
- package/dist/type-generator/serving/server-file-extractor.js.map +1 -1
- package/dist/type-generator/serving/vite-plugin.d.ts.map +1 -1
- package/dist/type-generator/serving/vite-plugin.js.map +1 -1
- package/dist/type-generator/vite-plugin.d.ts.map +1 -1
- package/dist/type-generator/vite-plugin.js.map +1 -1
- package/dist/workspace-client/legacy.js.map +1 -1
- package/dist/workspace-client/types.d.ts.map +1 -1
- package/docs/plugins/testing.md +245 -0
- package/llms.txt +1 -0
- package/package.json +15 -2
- package/sbom.cdx.json +1 -1
- package/skills/appkit-ui-variants/SKILL.md +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"manifest.js","names":[],"sources":["../../src/schemas/manifest.ts"],"sourcesContent":["/**\n * Zod-authoring module for AppKit plugin manifest schemas.\n *\n * Single source of truth for the plugin manifest contract. JSON Schema\n * artifacts published at the docs URL are emitted from these schemas via\n * `tools/generate-json-schema.ts` and live only in `docs/static/schemas/`\n * (no package-internal copies).\n *\n * - Cross-field constraints (cycle/dangling-reference checks, `<PROFILE>`\n * placeholder, post-scaffold instruction non-empty) are refinements\n * co-located with the shape they constrain. Validation is driven through\n * the Standard Schema interface from `validate-manifest.ts`.\n * - `templateFieldEntrySchema` is a transform that emits `origin` from\n * `localOnly`/`value`/`resolve`. The input slot is still allowed so\n * re-parsing previously-synced template manifests does not fail, but the\n * transform always overwrites it — drift-by-construction for hand-edits.\n * - `discoveryDescriptorSchema` is a discriminated union over a `type`\n * literal. The `kind` variant references one of the well-known\n * `resourceKind` values for which AppKit owns the CLI command map (see\n * `RESOURCE_KIND_COMMANDS` below). The `cli` variant is the escape hatch\n * carrying the existing free-form fields (with the `<PROFILE>`\n * refinement). Hierarchical context for volumes (catalog/schema parent\n * walk) is encoded via the kind's `parents` array, not via dependsOn.\n * - Scaffolding rule items carry a `maxLength` (120 chars) so\n * `rules.never[]` / `rules.must[]` / `rules.should[]` stay short\n * directives by contract, and the canonical `TEMPLATE_SCAFFOLDING`\n * constant lives co-located with the scaffolding schemas (sync.ts\n * imports it).\n */\n\nimport { z } from \"zod\";\nimport { PLUGIN_NAME_PATTERN } from \"../naming\";\n\n// ── Resource type + per-type permission enums ────────────────────────────\n\nexport const resourceTypeSchema = z\n .enum([\n \"secret\",\n \"job\",\n \"sql_warehouse\",\n \"serving_endpoint\",\n \"volume\",\n \"vector_search_index\",\n \"uc_function\",\n \"uc_connection\",\n \"database\",\n \"postgres\",\n \"genie_space\",\n \"experiment\",\n \"app\",\n ])\n .describe(\"Type of Databricks resource\");\n\nexport const secretPermissionSchema = z\n .enum([\"READ\", \"WRITE\", \"MANAGE\"])\n .describe(\"Permission for secret resources (order: weakest to strongest)\");\n\nexport const jobPermissionSchema = z\n .enum([\"CAN_VIEW\", \"CAN_MANAGE_RUN\", \"CAN_MANAGE\"])\n .describe(\"Permission for job resources (order: weakest to strongest)\");\n\nexport const sqlWarehousePermissionSchema = z\n .enum([\"CAN_USE\", \"CAN_MANAGE\"])\n .describe(\n \"Permission for SQL warehouse resources (order: weakest to strongest)\",\n );\n\nexport const servingEndpointPermissionSchema = z\n .enum([\"CAN_VIEW\", \"CAN_QUERY\", \"CAN_MANAGE\"])\n .describe(\n \"Permission for serving endpoint resources (order: weakest to strongest)\",\n );\n\nexport const volumePermissionSchema = z\n .enum([\"READ_VOLUME\", \"WRITE_VOLUME\"])\n .describe(\"Permission for Unity Catalog volume resources\");\n\nexport const vectorSearchIndexPermissionSchema = z\n .enum([\"SELECT\"])\n .describe(\"Permission for vector search index resources\");\n\nexport const ucFunctionPermissionSchema = z\n .enum([\"EXECUTE\"])\n .describe(\"Permission for Unity Catalog function resources\");\n\nexport const ucConnectionPermissionSchema = z\n .enum([\"USE_CONNECTION\"])\n .describe(\"Permission for Unity Catalog connection resources\");\n\nexport const databasePermissionSchema = z\n .enum([\"CAN_CONNECT_AND_CREATE\"])\n .describe(\"Permission for database resources\");\n\nexport const postgresPermissionSchema = z\n .enum([\"CAN_CONNECT_AND_CREATE\"])\n .describe(\"Permission for Postgres resources\");\n\nexport const genieSpacePermissionSchema = z\n .enum([\"CAN_VIEW\", \"CAN_RUN\", \"CAN_EDIT\", \"CAN_MANAGE\"])\n .describe(\n \"Permission for Genie Space resources (order: weakest to strongest)\",\n );\n\nexport const experimentPermissionSchema = z\n .enum([\"CAN_READ\", \"CAN_EDIT\", \"CAN_MANAGE\"])\n .describe(\n \"Permission for MLflow experiment resources (order: weakest to strongest)\",\n );\n\nexport const appPermissionSchema = z\n .enum([\"CAN_USE\"])\n .describe(\"Permission for Databricks App resources\");\n\n// ── Discovery descriptor (discriminated union) ───────────────────────────\n\n/**\n * Well-known Databricks resource kinds for which AppKit owns the CLI\n * command map. Plugins reference one of these via the `kind` variant of the\n * discovery descriptor; everything else falls back to the free-form `cli`\n * variant.\n *\n * Kept narrow on purpose: each entry costs an addition to\n * `RESOURCE_KIND_COMMANDS` below, which is the single source of truth for\n * how that kind is enumerated.\n */\nexport const resourceKindSchema = z\n .enum([\n \"warehouse\",\n \"genie_space\",\n \"postgres_project\",\n \"postgres_branch\",\n \"postgres_database\",\n \"volume\",\n ])\n .describe(\n \"Well-known Databricks resource kind whose listing command is owned by AppKit (see RESOURCE_KIND_COMMANDS).\",\n );\n\nexport const kindDiscoveryDescriptorSchema = z\n .object({\n type: z\n .literal(\"kind\")\n .describe(\n \"Discriminator: 'kind' uses the AppKit-owned command map for the named resourceKind.\",\n ),\n resourceKind: resourceKindSchema.describe(\n \"Reference to a well-known Databricks resource kind. AppKit owns the CLI command, response shape, and unwrap rules.\",\n ),\n select: z\n .string()\n .optional()\n .describe(\n \"Field name in the parsed CLI response used as the selected value (e.g., 'id'). Defaults to the kind's natural identifier when omitted.\",\n ),\n display: z\n .string()\n .optional()\n .describe(\n \"Field name in the parsed CLI response shown to the user in selection UI. Defaults to `select` if omitted.\",\n ),\n dependsOn: z\n .string()\n .optional()\n .describe(\n \"Name of a sibling field within the same resource that must be resolved first. Used to express ordering dependencies between resource fields.\",\n ),\n shortcut: z\n .string()\n .optional()\n .describe(\n \"Single-value fast-path command that returns exactly one value, skipping interactive selection.\",\n ),\n })\n .strict()\n .describe(\n \"Discovery via a well-known resource kind. AppKit owns the CLI command and unwrap rules for the named kind.\",\n );\n\n/**\n * Shell metacharacters rejected on free-form CLI command strings. Catches the\n * common foot-guns (statement separators, pipes, redirects via shell, command\n * substitution, newlines). Not a security boundary on its own — executors must\n * always pass these via argv, never shell-exec the string. Angle brackets are\n * permitted because `<PROFILE>` (and future `<…>` placeholders) are part of\n * the command-template convention.\n */\nconst SHELL_METACHAR_RE = /[;|&`$\\n\\r]/;\n\nexport const cliDiscoveryDescriptorSchema = z\n .object({\n type: z\n .literal(\"cli\")\n .describe(\n \"Discriminator: 'cli' uses a free-form Databricks CLI command supplied by the plugin.\",\n ),\n cliCommand: z\n .string()\n .describe(\n \"Databricks CLI command that lists resources. Must include <PROFILE>. Shell metacharacters (;|&`$ and newlines) are rejected; for first-party Databricks resources prefer the `kind` variant which uses AppKit's typed command map.\",\n ),\n selectField: z\n .string()\n .describe(\n \"jq-style path to the field used as the selected value (e.g., '.id', '.name').\",\n ),\n displayField: z\n .string()\n .optional()\n .describe(\n \"jq-style path to the field shown to the user in selection UI. Defaults to selectField if omitted.\",\n ),\n dependsOn: z\n .string()\n .optional()\n .describe(\n \"Name of a sibling field within the same resource that must be resolved first. Used to express ordering dependencies between resource fields.\",\n ),\n shortcut: z\n .string()\n .optional()\n .describe(\n \"Single-value fast-path command that returns exactly one value, skipping interactive selection. Shell metacharacters are rejected.\",\n ),\n })\n .strict()\n .refine((descriptor) => descriptor.cliCommand.includes(\"<PROFILE>\"), {\n message: \"must include <PROFILE> placeholder\",\n path: [\"cliCommand\"],\n })\n .refine((descriptor) => !SHELL_METACHAR_RE.test(descriptor.cliCommand), {\n message:\n \"must not contain shell metacharacters (;|&`$ or newlines); use the `kind` variant for typed Databricks resources\",\n path: [\"cliCommand\"],\n })\n .refine(\n (descriptor) =>\n descriptor.shortcut === undefined ||\n !SHELL_METACHAR_RE.test(descriptor.shortcut),\n {\n message: \"must not contain shell metacharacters (;|&`$ or newlines)\",\n path: [\"shortcut\"],\n },\n )\n .describe(\n \"Discovery via a free-form Databricks CLI command. Escape hatch — prefer the `kind` variant when a typed resourceKind covers the resource. This shape is intentionally minimal and may tighten further in future versions.\",\n );\n\nexport const discoveryDescriptorSchema = z\n .discriminatedUnion(\"type\", [\n kindDiscoveryDescriptorSchema,\n cliDiscoveryDescriptorSchema,\n ])\n .describe(\n \"Describes how the CLI discovers values for a resource field. 'kind' references a well-known Databricks resource kind whose command is owned by AppKit; 'cli' is the escape hatch carrying a free-form Databricks CLI command.\",\n );\n\n// ── Resource kind → CLI command map ──────────────────────────────────────\n\n/**\n * Descriptor for how a well-known resource kind is listed via the\n * Databricks CLI.\n *\n * - `command` is the CLI invocation template. It carries two kinds of\n * placeholders:\n * - `<PROFILE>` — substituted with the user's CLI profile by the runner.\n * - `{<fieldName>}` — substituted with the resolved value of the named\n * sibling field (used for `dependsOn` chains).\n * - `unwrap`, when set, is the JSON path into the response wrapper (e.g.,\n * `\"warehouses\"` for `{ warehouses: [...] }`). Omitted when the response\n * is already a flat array.\n * - `parents`, when set, lists transient query inputs the runner must\n * collect (as free-text prompts) before invoking the command. Each\n * `parents[i]` value substitutes the matching `{name}` placeholder in\n * the command string. Unlike `dependsOn` (which references a sibling\n * field on the same resource), `parents` covers inputs that aren't\n * persisted as fields on the resource.\n */\nexport type ResourceKindCommand = {\n command: string;\n unwrap?: string;\n parents?: readonly string[];\n};\n\n/**\n * Single source of truth for AppKit-owned discovery commands.\n *\n * To add a new resource kind: extend `resourceKindSchema` and add an entry\n * here. Plugins reference the kind via `discovery: { type: \"kind\",\n * resourceKind: \"...\" }` and inherit the command + response shape.\n *\n * `unwrap` defaults are unset: the existing core plugin manifests use simple\n * jq paths (`.id`, `.name`, `.full_name`), implying the listed CLI commands\n * return flat arrays. Refine in a follow-up if a kind's CLI returns wrapped\n * data.\n *\n * Volume's catalog/schema parent context is supplied via the `parents`\n * array, which the runner collects from the user as free-text prompts\n * before invoking the listing command.\n */\nexport const RESOURCE_KIND_COMMANDS: Record<\n z.infer<typeof resourceKindSchema>,\n { command: string; unwrap?: string; parents?: readonly string[] }\n> = {\n warehouse: {\n command: \"databricks warehouses list --profile <PROFILE> --output json\",\n },\n genie_space: {\n command: \"databricks genie list-spaces --profile <PROFILE> --output json\",\n },\n postgres_project: {\n command:\n \"databricks postgres list-projects --profile <PROFILE> --output json\",\n },\n postgres_branch: {\n // {project} is a placeholder for the resolved value of the `project`\n // sibling field (declared via `dependsOn: \"project\"` on the kind variant).\n // The Databricks CLI requires the parent project resource name (format\n // `projects/{project_id}`) as a positional argument.\n command:\n \"databricks postgres list-branches {project} --profile <PROFILE> --output json\",\n },\n postgres_database: {\n // {branch} is a placeholder for the resolved value of the `branch`\n // sibling field (declared via `dependsOn: \"branch\"` on the kind variant).\n command:\n \"databricks postgres list-databases {branch} --profile <PROFILE> --output json\",\n },\n volume: {\n // `parents` declares free-text user prompts the runner must collect before\n // invoking the discovery command. Each `parents[i]` value substitutes the\n // matching `{name}` placeholder in the command string above. Unlike\n // `dependsOn` (which references a sibling field on the same resource),\n // `parents` covers transient query inputs that aren't persisted as fields.\n command:\n \"databricks volumes list {catalog} {schema} --profile <PROFILE> --output json\",\n parents: [\"catalog\", \"schema\"] as const,\n },\n};\n\n// ── Resource field entry (plugin manifest variant) ───────────────────────\n\nexport const resourceFieldEntrySchema = z\n .object({\n env: z\n .string()\n .regex(/^[A-Z][A-Z0-9_]*$/)\n .optional()\n .describe(\"Environment variable name for this field\"),\n description: z\n .string()\n .optional()\n .describe(\"Human-readable description for this field\"),\n bundleIgnore: z\n .boolean()\n .optional()\n .describe(\n \"When true, this field is excluded from Databricks bundle configuration (databricks.yml) generation.\",\n ),\n examples: z\n .array(z.string())\n .optional()\n .describe(\"Example values showing the expected format for this field\"),\n localOnly: z\n .boolean()\n .optional()\n .describe(\n \"When true, this field is only generated for local .env files. The Databricks Apps platform auto-injects it at deploy time.\",\n ),\n value: z\n .string()\n .optional()\n .describe(\n \"Static value for this field. Used when no prompted or resolved value exists.\",\n ),\n resolve: z\n .string()\n .regex(/^[a-z_]+:[a-zA-Z]+$/)\n .optional()\n .describe(\n \"Named resolver prefixed by resource type (e.g., 'postgres:host'). The CLI resolves this value during the init prompt flow.\",\n ),\n discovery: discoveryDescriptorSchema.optional(),\n })\n .strict()\n .describe(\n \"Defines a single field for a resource. Each field has its own environment variable and optional description. Single-value types use one key (e.g. id); multi-value types (database, secret) use multiple (e.g. instance_name, database_name or scope, key).\",\n );\n\n// ── Resource requirement (per-type permission discriminator) ─────────────\n\n/**\n * Build a per-type variant. Each variant fixes `type` to a literal and constrains\n * `permission` to the matching enum, mirroring the existing JSON Schema's\n * `allOf + if/then` block. `fields` and the rest of the shape come from a\n * shared base.\n */\nconst resourceRequirementBaseShape = {\n alias: z\n .string()\n .min(1)\n .describe(\n \"Human-readable label for UI/display only. Deduplication uses resourceKey, not alias.\",\n ),\n resourceKey: z\n .string()\n .regex(/^[a-z][a-z0-9-]*$/)\n .describe(\n \"Stable key for machine use: deduplication, env naming, composite keys, app.yaml. Required for registry lookup.\",\n ),\n description: z\n .string()\n .min(1)\n .describe(\"Human-readable description of why this resource is needed\"),\n fields: z\n .record(z.string(), resourceFieldEntrySchema)\n .refine((obj) => Object.keys(obj).length >= 1, {\n message: \"fields must contain at least one entry\",\n })\n .optional()\n .describe(\n \"Map of field name to env and optional description. Single-value types use one key (e.g. id); multi-value (database, secret) use multiple (e.g. instance_name, database_name or scope, key).\",\n ),\n};\n\n/**\n * Adds the cycle/dangling-reference cross-field check to a resource variant.\n * Iterates the resource's `fields`, validates each `discovery.dependsOn` target\n * is a sibling field name, then runs DFS over the dependsOn graph to detect\n * cycles. Issue paths target either the offending field's `dependsOn` slot or\n * the resource itself for cycles.\n */\nfunction refineResourceDependsOn(\n resource: { fields?: Record<string, { discovery?: { dependsOn?: string } }> },\n ctx: z.core.$RefinementCtx,\n): void {\n if (!resource.fields) return;\n const fieldNames = new Set(Object.keys(resource.fields));\n\n // Pass 1: validate dependsOn references and build the dependency graph.\n const deps = new Map<string, string>();\n for (const [name, field] of Object.entries(resource.fields)) {\n const dep = field.discovery?.dependsOn;\n if (!dep) continue;\n if (!fieldNames.has(dep)) {\n ctx.addIssue({\n code: \"custom\",\n path: [\"fields\", name, \"discovery\", \"dependsOn\"],\n message: `references non-existent sibling field '${dep}'`,\n });\n }\n deps.set(name, dep);\n }\n\n // Pass 2: detect cycles via DFS. Emit one issue per cycle found.\n const visited = new Set<string>();\n const visiting = new Set<string>();\n\n function dfs(node: string, chain: string[]): string[] | null {\n if (visiting.has(node)) return [...chain, node];\n if (visited.has(node)) return null;\n visiting.add(node);\n const next = deps.get(node);\n if (next) {\n const cycle = dfs(next, [...chain, node]);\n if (cycle) return cycle;\n }\n visiting.delete(node);\n visited.add(node);\n return null;\n }\n\n for (const node of deps.keys()) {\n if (visited.has(node)) continue;\n const cycle = dfs(node, []);\n if (cycle) {\n ctx.addIssue({\n code: \"custom\",\n path: [],\n message: `discovery.dependsOn creates a cycle: ${cycle.join(\" → \")}`,\n });\n // One cycle error per resource is enough.\n break;\n }\n }\n}\n\nfunction makeResourceVariant<\n TType extends z.ZodLiteral<string>,\n TPerm extends z.ZodTypeAny,\n>(typeLiteral: TType, permission: TPerm) {\n return z\n .object({\n type: typeLiteral,\n ...resourceRequirementBaseShape,\n permission: permission.describe(\n \"Required permission level. Validated per resource type.\",\n ),\n })\n .strict()\n .superRefine(refineResourceDependsOn);\n}\n\nexport const resourceRequirementSchema = z\n .discriminatedUnion(\"type\", [\n makeResourceVariant(z.literal(\"secret\"), secretPermissionSchema),\n makeResourceVariant(z.literal(\"job\"), jobPermissionSchema),\n makeResourceVariant(\n z.literal(\"sql_warehouse\"),\n sqlWarehousePermissionSchema,\n ),\n makeResourceVariant(\n z.literal(\"serving_endpoint\"),\n servingEndpointPermissionSchema,\n ),\n makeResourceVariant(z.literal(\"volume\"), volumePermissionSchema),\n makeResourceVariant(\n z.literal(\"vector_search_index\"),\n vectorSearchIndexPermissionSchema,\n ),\n makeResourceVariant(z.literal(\"uc_function\"), ucFunctionPermissionSchema),\n makeResourceVariant(\n z.literal(\"uc_connection\"),\n ucConnectionPermissionSchema,\n ),\n makeResourceVariant(z.literal(\"database\"), databasePermissionSchema),\n makeResourceVariant(z.literal(\"postgres\"), postgresPermissionSchema),\n makeResourceVariant(z.literal(\"genie_space\"), genieSpacePermissionSchema),\n makeResourceVariant(z.literal(\"experiment\"), experimentPermissionSchema),\n makeResourceVariant(z.literal(\"app\"), appPermissionSchema),\n ])\n .describe(\n \"Declares a resource requirement for a plugin. Can be defined statically in a manifest or dynamically via getResourceRequirements().\",\n );\n\n// ── Config schema (recursive) ────────────────────────────────────────────\n\nexport const configSchemaPropertySchema: z.ZodType = z.lazy(() =>\n z\n .object({\n type: z.enum([\n \"object\",\n \"array\",\n \"string\",\n \"number\",\n \"boolean\",\n \"integer\",\n ]),\n description: z.string().optional(),\n default: z.unknown().optional(),\n enum: z.array(z.unknown()).optional(),\n properties: z.record(z.string(), configSchemaPropertySchema).optional(),\n items: configSchemaPropertySchema.optional(),\n minimum: z.number().optional(),\n maximum: z.number().optional(),\n minLength: z.number().int().min(0).optional(),\n maxLength: z.number().int().min(0).optional(),\n required: z.array(z.string()).optional(),\n // `additionalProperties` is a standard JSON Schema keyword used by core\n // plugin manifests (e.g., serving, ai-search, genie) to constrain\n // dictionary-shaped properties. Allowed on nested property entries as\n // either a boolean or a sub-schema, mirroring JSON Schema semantics.\n additionalProperties: z\n .union([z.boolean(), configSchemaPropertySchema])\n .optional(),\n })\n .strict(),\n);\n\nexport const configSchemaSchema: z.ZodType = z.lazy(() =>\n z\n .object({\n type: z.enum([\"object\", \"array\", \"string\", \"number\", \"boolean\"]),\n properties: z.record(z.string(), configSchemaPropertySchema).optional(),\n items: configSchemaSchema.optional(),\n required: z.array(z.string()).optional(),\n additionalProperties: z.boolean().optional(),\n })\n .strict(),\n);\n\n// ── Plugin-level scaffolding rules ───────────────────────────────────────\n\n/**\n * Per-item upper bound on plugin-level scaffolding rule strings. Matches the\n * template-level `SCAFFOLDING_RULE_MAX_LENGTH` defined below — rules at both\n * levels are short directives, not prose. The literal value lives here (and\n * not by reference to the template-side constant) because this declaration\n * is read in source order and the template constant is declared later.\n */\nconst PLUGIN_SCAFFOLDING_RULE_MAX_LENGTH = 120;\n\nconst pluginScaffoldingRuleItemSchema = z\n .string()\n .min(1)\n .max(\n PLUGIN_SCAFFOLDING_RULE_MAX_LENGTH,\n `rule entries must be ≤ ${PLUGIN_SCAFFOLDING_RULE_MAX_LENGTH} chars`,\n );\n\nexport const pluginScaffoldingRulesSchema = z\n .object({\n must: z\n .array(pluginScaffoldingRuleItemSchema)\n .optional()\n .describe(\"Actions the scaffolding agent must always perform.\"),\n should: z\n .array(pluginScaffoldingRuleItemSchema)\n .optional()\n .describe(\"Recommended actions for the scaffolding agent.\"),\n never: z\n .array(pluginScaffoldingRuleItemSchema)\n .optional()\n .describe(\"Actions the scaffolding agent must never perform.\"),\n })\n .strict()\n .superRefine((rules, ctx) => {\n // (a) Reject duplicate entries within any single array.\n const buckets: Array<[\"must\" | \"should\" | \"never\", string[] | undefined]> =\n [\n [\"must\", rules.must],\n [\"should\", rules.should],\n [\"never\", rules.never],\n ];\n for (const [bucketName, items] of buckets) {\n if (!items) continue;\n const seen = new Map<string, number>();\n items.forEach((item, idx) => {\n const prev = seen.get(item);\n if (prev === undefined) {\n seen.set(item, idx);\n return;\n }\n ctx.addIssue({\n code: \"custom\",\n path: [bucketName, idx],\n message: `duplicate rule entry: \"${item}\" already declared at index ${prev}`,\n });\n });\n }\n // (b) Reject a string that appears in more than one of must/should/never.\n type Bucket = \"must\" | \"should\" | \"never\";\n const owner = new Map<string, Bucket>();\n for (const [bucketName, items] of buckets) {\n if (!items) continue;\n for (let i = 0; i < items.length; i++) {\n const item = items[i];\n const existing = owner.get(item);\n if (existing === undefined) {\n owner.set(item, bucketName);\n continue;\n }\n if (existing !== bucketName) {\n ctx.addIssue({\n code: \"custom\",\n path: [bucketName, i],\n message: `rule entry \"${item}\" appears in both '${existing}' and '${bucketName}'; rules must belong to exactly one bucket`,\n });\n }\n }\n }\n })\n .describe(\n \"Structured rules for scaffolding agents declared at the plugin level. Each rule is a short directive (≤120 chars).\",\n );\n\n// ── Plugin manifest (root) ───────────────────────────────────────────────\n\nexport const pluginManifestSchema = z\n .object({\n $schema: z\n .string()\n .optional()\n .describe(\"Reference to the JSON Schema for validation\"),\n name: z\n .string()\n .regex(PLUGIN_NAME_PATTERN)\n .describe(\n \"Plugin identifier and JS binding. Must start with a lowercase letter; camelCase for multi-word names (e.g. aiSearch).\",\n ),\n displayName: z\n .string()\n .min(1)\n .describe(\"Human-readable display name for UI and CLI\"),\n description: z\n .string()\n .min(1)\n .describe(\"Brief description of what the plugin does\"),\n resources: z\n .object({\n required: z\n .array(resourceRequirementSchema)\n .describe(\n \"Resources that must be available for the plugin to function\",\n ),\n optional: z\n .array(resourceRequirementSchema)\n .describe(\n \"Resources that enhance functionality but are not mandatory\",\n ),\n })\n .strict()\n .describe(\"Databricks resource requirements for this plugin\"),\n config: z\n .object({\n schema: configSchemaSchema.optional(),\n })\n .strict()\n .optional()\n .describe(\"Configuration schema for the plugin\"),\n author: z.string().optional().describe(\"Author name or organization\"),\n version: z\n .string()\n .regex(/^\\d+\\.\\d+\\.\\d+(-[a-zA-Z0-9.]+)?$/)\n .optional()\n .describe(\"Plugin version (semver format)\"),\n repository: z\n .url()\n .optional()\n .describe(\"URL to the plugin's source repository\"),\n keywords: z\n .array(z.string())\n .optional()\n .describe(\"Keywords for plugin discovery\"),\n license: z.string().optional().describe(\"SPDX license identifier\"),\n onSetupMessage: z\n .string()\n .optional()\n .describe(\n \"Message displayed to the user after project initialization. Use this to inform about manual setup steps (e.g. environment variables, resource provisioning).\",\n ),\n hidden: z\n .boolean()\n .optional()\n .describe(\n \"When true, this plugin is excluded from the template plugins manifest (appkit.plugins.json) during sync.\",\n ),\n devOnly: z\n .boolean()\n .optional()\n .describe(\n \"When true, this plugin is only registered when NODE_ENV === 'development'. In any other environment createApp skips it entirely (not constructed, no routes, resources not validated). Use for dev-only tooling that must never run in a deployed app.\",\n ),\n stability: z\n .enum([\"beta\", \"ga\"])\n .optional()\n .describe(\n \"Plugin stability level. Beta plugins may have breaking API changes between minor releases but are on a path to GA. GA (general availability) plugins follow semver strictly.\",\n ),\n scaffolding: z\n .object({\n rules: pluginScaffoldingRulesSchema\n .optional()\n .describe(\n \"Structured rules for scaffolding agents declared at the plugin level.\",\n ),\n })\n .strict()\n .optional()\n .describe(\n \"Plugin-level scaffolding metadata consumed by scaffolding agents. Symmetric with template-level `scaffolding`.\",\n ),\n })\n .strict()\n .describe(\n \"Schema for Databricks AppKit plugin manifest files. Defines plugin metadata, resource requirements, and configuration options.\",\n );\n\n// ── Origin enum ──────────────────────────────────────────────────────────\n\nexport const originSchema = z\n .enum([\"user\", \"platform\", \"static\", \"cli\"])\n .describe(\n \"How the field value is determined. Computed during sync, not authored by plugin developers.\",\n );\n\n// ── Template field entry (origin computed by transform) ─────────────────\n\n/**\n * Derives the canonical origin of a resource field value from its shape.\n *\n * - `localOnly: true` → `\"platform\"` (auto-injected by the Databricks Apps\n * platform at deploy time; takes precedence over `value`/`resolve`).\n * - `value !== undefined` → `\"static\"` (hardcoded value).\n * - `resolve !== undefined` → `\"cli\"` (resolved by the CLI during init).\n * - else → `\"user\"` (user must provide the value at init time).\n *\n * The single source for this rule: `plugin sync`'s transform stamps `origin`\n * with it, and consumers that read an authored manifest (no stamped `origin`)\n * derive it through this rather than re-implementing the cascade.\n */\nexport function computeOriginFromField(field: {\n localOnly?: boolean;\n value?: string;\n resolve?: string;\n}): z.infer<typeof originSchema> {\n if (field.localOnly) return \"platform\";\n if (field.value !== undefined) return \"static\";\n if (field.resolve !== undefined) return \"cli\";\n return \"user\";\n}\n\n/**\n * Template field entry: extends the plugin manifest field entry with an\n * optional `origin` input slot, then runs a `.transform()` that overwrites\n * `origin` with the computed value. Allowing `origin` on input means\n * re-parsing a previously-synced template manifest does not fail; emitting\n * `origin` always means hand-edits in synced JSON are silently corrected\n * on the next parse — drift-by-construction.\n */\nexport const templateFieldEntrySchema = resourceFieldEntrySchema\n .extend({ origin: originSchema.optional() })\n .transform((field) => ({\n ...field,\n origin: computeOriginFromField(field),\n }));\n\n// ── Template resource requirement (uses templateFieldEntrySchema) ────────\n\nconst templateResourceRequirementBaseShape = {\n alias: z\n .string()\n .min(1)\n .describe(\"Human-readable label for UI/display only.\"),\n resourceKey: z\n .string()\n .regex(/^[a-z][a-z0-9-]*$/)\n .describe(\n \"Stable key for machine use: deduplication, env naming, composite keys.\",\n ),\n description: z\n .string()\n .min(1)\n .describe(\"Human-readable description of why this resource is needed\"),\n fields: z\n .record(z.string(), templateFieldEntrySchema)\n .refine((obj) => Object.keys(obj).length >= 1, {\n message: \"fields must contain at least one entry\",\n })\n .optional()\n .describe(\"Map of field name to field entry with computed origin.\"),\n};\n\nfunction makeTemplateResourceVariant<\n TType extends z.ZodLiteral<string>,\n TPerm extends z.ZodTypeAny,\n>(typeLiteral: TType, permission: TPerm) {\n return z\n .object({\n type: typeLiteral,\n ...templateResourceRequirementBaseShape,\n permission: permission.describe(\n \"Required permission level. Validated per resource type.\",\n ),\n })\n .strict()\n .superRefine(refineResourceDependsOn);\n}\n\nexport const templateResourceRequirementSchema = z\n .discriminatedUnion(\"type\", [\n makeTemplateResourceVariant(z.literal(\"secret\"), secretPermissionSchema),\n makeTemplateResourceVariant(z.literal(\"job\"), jobPermissionSchema),\n makeTemplateResourceVariant(\n z.literal(\"sql_warehouse\"),\n sqlWarehousePermissionSchema,\n ),\n makeTemplateResourceVariant(\n z.literal(\"serving_endpoint\"),\n servingEndpointPermissionSchema,\n ),\n makeTemplateResourceVariant(z.literal(\"volume\"), volumePermissionSchema),\n makeTemplateResourceVariant(\n z.literal(\"vector_search_index\"),\n vectorSearchIndexPermissionSchema,\n ),\n makeTemplateResourceVariant(\n z.literal(\"uc_function\"),\n ucFunctionPermissionSchema,\n ),\n makeTemplateResourceVariant(\n z.literal(\"uc_connection\"),\n ucConnectionPermissionSchema,\n ),\n makeTemplateResourceVariant(\n z.literal(\"database\"),\n databasePermissionSchema,\n ),\n makeTemplateResourceVariant(\n z.literal(\"postgres\"),\n postgresPermissionSchema,\n ),\n makeTemplateResourceVariant(\n z.literal(\"genie_space\"),\n genieSpacePermissionSchema,\n ),\n makeTemplateResourceVariant(\n z.literal(\"experiment\"),\n experimentPermissionSchema,\n ),\n makeTemplateResourceVariant(z.literal(\"app\"), appPermissionSchema),\n ])\n .describe(\n \"Resource requirement with template-specific field entries (includes computed origin).\",\n );\n\n// ── Template plugin (extends plugin manifest) ────────────────────────────\n\nexport const templatePluginSchema = z\n .object({\n name: z\n .string()\n .regex(PLUGIN_NAME_PATTERN)\n .describe(\n \"Plugin identifier and JS binding. Must start with a lowercase letter; camelCase for multi-word names (e.g. aiSearch).\",\n ),\n displayName: z\n .string()\n .min(1)\n .describe(\"Human-readable display name for UI and CLI\"),\n description: z\n .string()\n .min(1)\n .describe(\"Brief description of what the plugin does\"),\n package: z\n .string()\n .min(1)\n .describe(\"NPM package name that provides this plugin\"),\n requiredByTemplate: z\n .boolean()\n .optional()\n .describe(\n \"When true, this plugin is required by the template and cannot be deselected during CLI init. The user will only be prompted to configure its resources. When absent or false, the plugin is optional and the user can choose whether to include it.\",\n ),\n onSetupMessage: z\n .string()\n .optional()\n .describe(\n \"Message displayed to the user after project initialization. Use this to inform about manual setup steps (e.g. environment variables, resource provisioning).\",\n ),\n stability: z\n .enum([\"beta\", \"ga\"])\n .optional()\n .describe(\n \"Plugin stability level. Beta is heading to GA; APIs may change between minor releases. GA (general availability) follows semver.\",\n ),\n scaffolding: z\n .object({\n rules: pluginScaffoldingRulesSchema\n .optional()\n .describe(\n \"Structured rules for scaffolding agents propagated from the plugin manifest.\",\n ),\n })\n .strict()\n .optional()\n .describe(\n \"Plugin-level scaffolding metadata propagated from the plugin manifest.\",\n ),\n resources: z\n .object({\n required: z\n .array(templateResourceRequirementSchema)\n .describe(\n \"Resources that must be available for the plugin to function\",\n ),\n optional: z\n .array(templateResourceRequirementSchema)\n .describe(\n \"Resources that enhance functionality but are not mandatory\",\n ),\n })\n .strict()\n .describe(\"Databricks resource requirements for this plugin\"),\n })\n .strict()\n .describe(\"Plugin manifest with package source information\");\n\n// ── Scaffolding descriptor ───────────────────────────────────────────────\n\nexport const scaffoldingFlagSchema = z\n .object({\n description: z.string().describe(\"Human-readable description of the flag.\"),\n required: z.boolean().optional().describe(\"Whether this flag is required.\"),\n pattern: z\n .string()\n .optional()\n .describe(\"Regex pattern for validating the flag value.\"),\n default: z.string().optional().describe(\"Default value for this flag.\"),\n })\n .strict()\n .describe(\"A flag for the scaffolding command.\");\n\n/**\n * Per-item upper bound on scaffolding rule strings. The intent is to enforce\n * \"short directive\" by contract — long paragraphs fail validation and force\n * authors to split prose into discrete actionable items.\n */\nconst SCAFFOLDING_RULE_MAX_LENGTH = 120;\n\nconst scaffoldingRuleItemSchema = z\n .string()\n .max(\n SCAFFOLDING_RULE_MAX_LENGTH,\n `rule item must be ≤ ${SCAFFOLDING_RULE_MAX_LENGTH} chars`,\n );\n\nexport const scaffoldingRulesSchema = z\n .object({\n never: z\n .array(scaffoldingRuleItemSchema)\n .optional()\n .describe(\"Actions the scaffolding agent must never perform.\"),\n must: z\n .array(scaffoldingRuleItemSchema)\n .optional()\n .describe(\"Actions the scaffolding agent must always perform.\"),\n should: z\n .array(scaffoldingRuleItemSchema)\n .optional()\n .describe(\n \"Recommended actions for the scaffolding agent (parity with plugin-level rules).\",\n ),\n })\n .strict()\n .describe(\"Structured rules for scaffolding agents.\");\n\nexport const scaffoldingDescriptorSchema = z\n .object({\n command: z\n .string()\n .describe(\"The scaffolding command (e.g., 'databricks apps init').\"),\n flags: z\n .record(z.string(), scaffoldingFlagSchema)\n .optional()\n .describe(\"Map of flag name to flag descriptor.\"),\n rules: scaffoldingRulesSchema\n .optional()\n .describe(\"Structured rules for scaffolding agents.\"),\n })\n .strict()\n .describe(\n \"Describes the scaffolding command, flags, and rules for project initialization.\",\n );\n\n/**\n * Canonical scaffolding descriptor for the `databricks apps init` command,\n * embedded in v2.0 template manifests to guide scaffolding agents.\n *\n * Co-located with `scaffoldingDescriptorSchema` so any change to the rule set\n * (or the schema's `maxLength` ceiling) shows up next to its consumer. The\n * `satisfies` annotation gives compile-time validation that the literal\n * matches the schema's input shape; if a `must`/`never` entry exceeds the\n * `maxLength` ceiling at runtime, `scaffoldingDescriptorSchema.parse` would\n * surface the breach in tests.\n */\nexport const TEMPLATE_SCAFFOLDING = {\n command: \"databricks apps init\",\n flags: {\n \"--name\": {\n description:\n \"Project name — sets {{.projectName}} in package.json, databricks.yml, and .env. Required for non-interactive scaffolding.\",\n required: true,\n pattern: \"^[a-z][a-z0-9-]*$\",\n },\n \"--template\": {\n description: \"Template path (local directory or GitHub URL)\",\n required: false,\n },\n \"--version\": {\n description: \"AppKit version to use; defaults to auto-detected\",\n required: false,\n },\n \"--features\": {\n description:\n \"Plugins to enable (comma-separated, no spaces; must match keys in this manifest's plugins map)\",\n required: false,\n pattern: \"^[a-zA-Z0-9_-]+(,[a-zA-Z0-9_-]+)*$\",\n },\n \"--set\": {\n description:\n \"Set resource values (format: plugin.resourceKey.field=value, repeatable)\",\n required: false,\n },\n \"--output-dir\": {\n description: \"Directory to write the project to\",\n required: false,\n },\n \"--description\": {\n description: \"App description\",\n required: false,\n },\n \"--run\": {\n description: \"Run the app after creation (none, dev, dev-remote)\",\n required: false,\n },\n \"--auto-approve\": {\n description:\n \"Pass as a bare flag (no value) to skip prompts for optional resources. Not recommended for agent-driven init — conflicts with the 'ask user when in doubt' rule.\",\n required: false,\n },\n \"--profile\": {\n description:\n \"Databricks CLI profile to use for authentication (global flag)\",\n required: false,\n },\n },\n rules: {\n must: [\n \"Treat `databricks apps init` output as starter code, not requirements; adapt or replace it to match the requested app\",\n \"Keep all secrets and credentials only in app.yaml, databricks.yml, and/or .env\",\n ],\n should: [\"ask user when in doubt of resource to use for plugin\"],\n never: [\n \"guess resources when multiple or no options are available\",\n \"embed secrets in files that will go to the client-bundle\",\n ],\n },\n} satisfies z.infer<typeof scaffoldingDescriptorSchema>;\n\n// ── Template plugins manifest (root) ─────────────────────────────────────\n\nexport const templatePluginsManifestSchema = z\n .object({\n $schema: z\n .string()\n .optional()\n .describe(\"Reference to the JSON Schema for validation\"),\n version: z\n .enum([\"1.0\", \"1.1\", \"2.0\"])\n .describe(\"Schema version for the template plugins manifest\"),\n plugins: z\n .record(z.string(), templatePluginSchema)\n .describe(\"Map of plugin name to plugin manifest with package source\"),\n scaffolding: scaffoldingDescriptorSchema\n .optional()\n .describe(\n \"Describes the scaffolding command and its configuration for project initialization.\",\n ),\n })\n .strict()\n .superRefine((value, ctx) => {\n if (value.version === \"2.0\" && !value.scaffolding) {\n ctx.addIssue({\n code: \"custom\",\n path: [\"scaffolding\"],\n message: \"scaffolding is required when version is '2.0'\",\n });\n }\n })\n .describe(\n \"Aggregated plugin manifest for AppKit templates. Read by Databricks CLI during init to discover available plugins and their resource requirements.\",\n );\n\n// ── Inferred types ───────────────────────────────────────────────────────\n\nexport type ResourceType = z.infer<typeof resourceTypeSchema>;\nexport type SecretPermission = z.infer<typeof secretPermissionSchema>;\nexport type JobPermission = z.infer<typeof jobPermissionSchema>;\nexport type SqlWarehousePermission = z.infer<\n typeof sqlWarehousePermissionSchema\n>;\nexport type ServingEndpointPermission = z.infer<\n typeof servingEndpointPermissionSchema\n>;\nexport type VolumePermission = z.infer<typeof volumePermissionSchema>;\nexport type VectorSearchIndexPermission = z.infer<\n typeof vectorSearchIndexPermissionSchema\n>;\nexport type UcFunctionPermission = z.infer<typeof ucFunctionPermissionSchema>;\nexport type UcConnectionPermission = z.infer<\n typeof ucConnectionPermissionSchema\n>;\nexport type DatabasePermission = z.infer<typeof databasePermissionSchema>;\nexport type PostgresPermission = z.infer<typeof postgresPermissionSchema>;\nexport type GenieSpacePermission = z.infer<typeof genieSpacePermissionSchema>;\nexport type ExperimentPermission = z.infer<typeof experimentPermissionSchema>;\nexport type AppPermission = z.infer<typeof appPermissionSchema>;\nexport type ResourceKind = z.infer<typeof resourceKindSchema>;\nexport type KindDiscoveryDescriptor = z.infer<\n typeof kindDiscoveryDescriptorSchema\n>;\nexport type CliDiscoveryDescriptor = z.infer<\n typeof cliDiscoveryDescriptorSchema\n>;\nexport type DiscoveryDescriptor = z.infer<typeof discoveryDescriptorSchema>;\nexport type ResourceFieldEntry = z.infer<typeof resourceFieldEntrySchema>;\nexport type ResourceRequirement = z.infer<typeof resourceRequirementSchema>;\nexport type ConfigSchemaProperty = z.infer<typeof configSchemaPropertySchema>;\nexport type ConfigSchema = z.infer<typeof configSchemaSchema>;\nexport type PluginScaffoldingRules = z.infer<\n typeof pluginScaffoldingRulesSchema\n>;\nexport type PluginManifest = z.infer<typeof pluginManifestSchema>;\nexport type Origin = z.infer<typeof originSchema>;\n// Template-side types use `z.input` so callers can construct a TemplatePlugin\n// from a parsed PluginManifest before the field-level origin transform runs.\n// `writeManifest` parses every field through `templateFieldEntrySchema` at\n// write-time, so the on-disk shape always has origin populated. The runtime\n// invariant: origin is *always* present after sync writes; the type slot\n// stays optional so the in-memory pipeline does not need to fabricate origin\n// before assignment.\nexport type TemplateFieldEntry = z.input<typeof templateFieldEntrySchema>;\nexport type TemplateResourceRequirement = z.input<\n typeof templateResourceRequirementSchema\n>;\nexport type TemplatePlugin = z.input<typeof templatePluginSchema>;\nexport type ScaffoldingFlag = z.infer<typeof scaffoldingFlagSchema>;\nexport type ScaffoldingRules = z.infer<typeof scaffoldingRulesSchema>;\nexport type ScaffoldingDescriptor = z.infer<typeof scaffoldingDescriptorSchema>;\nexport type TemplatePluginsManifest = z.input<\n typeof templatePluginsManifestSchema\n>;\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"manifest.js","names":[],"sources":["../../src/schemas/manifest.ts"],"sourcesContent":["/**\n * Zod-authoring module for AppKit plugin manifest schemas.\n *\n * Single source of truth for the plugin manifest contract. JSON Schema\n * artifacts published at the docs URL are emitted from these schemas via\n * `tools/generate-json-schema.ts` and live only in `docs/static/schemas/`\n * (no package-internal copies).\n *\n * - Cross-field constraints (cycle/dangling-reference checks, `<PROFILE>`\n * placeholder, post-scaffold instruction non-empty) are refinements\n * co-located with the shape they constrain. Validation is driven through\n * the Standard Schema interface from `validate-manifest.ts`.\n * - `templateFieldEntrySchema` is a transform that emits `origin` from\n * `localOnly`/`value`/`resolve`. The input slot is still allowed so\n * re-parsing previously-synced template manifests does not fail, but the\n * transform always overwrites it — drift-by-construction for hand-edits.\n * - `discoveryDescriptorSchema` is a discriminated union over a `type`\n * literal. The `kind` variant references one of the well-known\n * `resourceKind` values for which AppKit owns the CLI command map (see\n * `RESOURCE_KIND_COMMANDS` below). The `cli` variant is the escape hatch\n * carrying the existing free-form fields (with the `<PROFILE>`\n * refinement). Hierarchical context for volumes (catalog/schema parent\n * walk) is encoded via the kind's `parents` array, not via dependsOn.\n * - Scaffolding rule items carry a `maxLength` (120 chars) so\n * `rules.never[]` / `rules.must[]` / `rules.should[]` stay short\n * directives by contract, and the canonical `TEMPLATE_SCAFFOLDING`\n * constant lives co-located with the scaffolding schemas (sync.ts\n * imports it).\n */\n\nimport { z } from \"zod\";\n\nimport { PLUGIN_NAME_PATTERN } from \"../naming\";\n\n// ── Resource type + per-type permission enums ────────────────────────────\n\nexport const resourceTypeSchema = z\n .enum([\n \"secret\",\n \"job\",\n \"sql_warehouse\",\n \"serving_endpoint\",\n \"volume\",\n \"vector_search_index\",\n \"uc_function\",\n \"uc_connection\",\n \"database\",\n \"postgres\",\n \"genie_space\",\n \"experiment\",\n \"app\",\n ])\n .describe(\"Type of Databricks resource\");\n\nexport const secretPermissionSchema = z\n .enum([\"READ\", \"WRITE\", \"MANAGE\"])\n .describe(\"Permission for secret resources (order: weakest to strongest)\");\n\nexport const jobPermissionSchema = z\n .enum([\"CAN_VIEW\", \"CAN_MANAGE_RUN\", \"CAN_MANAGE\"])\n .describe(\"Permission for job resources (order: weakest to strongest)\");\n\nexport const sqlWarehousePermissionSchema = z\n .enum([\"CAN_USE\", \"CAN_MANAGE\"])\n .describe(\n \"Permission for SQL warehouse resources (order: weakest to strongest)\",\n );\n\nexport const servingEndpointPermissionSchema = z\n .enum([\"CAN_VIEW\", \"CAN_QUERY\", \"CAN_MANAGE\"])\n .describe(\n \"Permission for serving endpoint resources (order: weakest to strongest)\",\n );\n\nexport const volumePermissionSchema = z\n .enum([\"READ_VOLUME\", \"WRITE_VOLUME\"])\n .describe(\"Permission for Unity Catalog volume resources\");\n\nexport const vectorSearchIndexPermissionSchema = z\n .enum([\"SELECT\"])\n .describe(\"Permission for vector search index resources\");\n\nexport const ucFunctionPermissionSchema = z\n .enum([\"EXECUTE\"])\n .describe(\"Permission for Unity Catalog function resources\");\n\nexport const ucConnectionPermissionSchema = z\n .enum([\"USE_CONNECTION\"])\n .describe(\"Permission for Unity Catalog connection resources\");\n\nexport const databasePermissionSchema = z\n .enum([\"CAN_CONNECT_AND_CREATE\"])\n .describe(\"Permission for database resources\");\n\nexport const postgresPermissionSchema = z\n .enum([\"CAN_CONNECT_AND_CREATE\"])\n .describe(\"Permission for Postgres resources\");\n\nexport const genieSpacePermissionSchema = z\n .enum([\"CAN_VIEW\", \"CAN_RUN\", \"CAN_EDIT\", \"CAN_MANAGE\"])\n .describe(\n \"Permission for Genie Space resources (order: weakest to strongest)\",\n );\n\nexport const experimentPermissionSchema = z\n .enum([\"CAN_READ\", \"CAN_EDIT\", \"CAN_MANAGE\"])\n .describe(\n \"Permission for MLflow experiment resources (order: weakest to strongest)\",\n );\n\nexport const appPermissionSchema = z\n .enum([\"CAN_USE\"])\n .describe(\"Permission for Databricks App resources\");\n\n// ── Discovery descriptor (discriminated union) ───────────────────────────\n\n/**\n * Well-known Databricks resource kinds for which AppKit owns the CLI\n * command map. Plugins reference one of these via the `kind` variant of the\n * discovery descriptor; everything else falls back to the free-form `cli`\n * variant.\n *\n * Kept narrow on purpose: each entry costs an addition to\n * `RESOURCE_KIND_COMMANDS` below, which is the single source of truth for\n * how that kind is enumerated.\n */\nexport const resourceKindSchema = z\n .enum([\n \"warehouse\",\n \"genie_space\",\n \"postgres_project\",\n \"postgres_branch\",\n \"postgres_database\",\n \"volume\",\n ])\n .describe(\n \"Well-known Databricks resource kind whose listing command is owned by AppKit (see RESOURCE_KIND_COMMANDS).\",\n );\n\nexport const kindDiscoveryDescriptorSchema = z\n .object({\n type: z\n .literal(\"kind\")\n .describe(\n \"Discriminator: 'kind' uses the AppKit-owned command map for the named resourceKind.\",\n ),\n resourceKind: resourceKindSchema.describe(\n \"Reference to a well-known Databricks resource kind. AppKit owns the CLI command, response shape, and unwrap rules.\",\n ),\n select: z\n .string()\n .optional()\n .describe(\n \"Field name in the parsed CLI response used as the selected value (e.g., 'id'). Defaults to the kind's natural identifier when omitted.\",\n ),\n display: z\n .string()\n .optional()\n .describe(\n \"Field name in the parsed CLI response shown to the user in selection UI. Defaults to `select` if omitted.\",\n ),\n dependsOn: z\n .string()\n .optional()\n .describe(\n \"Name of a sibling field within the same resource that must be resolved first. Used to express ordering dependencies between resource fields.\",\n ),\n shortcut: z\n .string()\n .optional()\n .describe(\n \"Single-value fast-path command that returns exactly one value, skipping interactive selection.\",\n ),\n })\n .strict()\n .describe(\n \"Discovery via a well-known resource kind. AppKit owns the CLI command and unwrap rules for the named kind.\",\n );\n\n/**\n * Shell metacharacters rejected on free-form CLI command strings. Catches the\n * common foot-guns (statement separators, pipes, redirects via shell, command\n * substitution, newlines). Not a security boundary on its own — executors must\n * always pass these via argv, never shell-exec the string. Angle brackets are\n * permitted because `<PROFILE>` (and future `<…>` placeholders) are part of\n * the command-template convention.\n */\nconst SHELL_METACHAR_RE = /[;|&`$\\n\\r]/;\n\nexport const cliDiscoveryDescriptorSchema = z\n .object({\n type: z\n .literal(\"cli\")\n .describe(\n \"Discriminator: 'cli' uses a free-form Databricks CLI command supplied by the plugin.\",\n ),\n cliCommand: z\n .string()\n .describe(\n \"Databricks CLI command that lists resources. Must include <PROFILE>. Shell metacharacters (;|&`$ and newlines) are rejected; for first-party Databricks resources prefer the `kind` variant which uses AppKit's typed command map.\",\n ),\n selectField: z\n .string()\n .describe(\n \"jq-style path to the field used as the selected value (e.g., '.id', '.name').\",\n ),\n displayField: z\n .string()\n .optional()\n .describe(\n \"jq-style path to the field shown to the user in selection UI. Defaults to selectField if omitted.\",\n ),\n dependsOn: z\n .string()\n .optional()\n .describe(\n \"Name of a sibling field within the same resource that must be resolved first. Used to express ordering dependencies between resource fields.\",\n ),\n shortcut: z\n .string()\n .optional()\n .describe(\n \"Single-value fast-path command that returns exactly one value, skipping interactive selection. Shell metacharacters are rejected.\",\n ),\n })\n .strict()\n .refine((descriptor) => descriptor.cliCommand.includes(\"<PROFILE>\"), {\n message: \"must include <PROFILE> placeholder\",\n path: [\"cliCommand\"],\n })\n .refine((descriptor) => !SHELL_METACHAR_RE.test(descriptor.cliCommand), {\n message:\n \"must not contain shell metacharacters (;|&`$ or newlines); use the `kind` variant for typed Databricks resources\",\n path: [\"cliCommand\"],\n })\n .refine(\n (descriptor) =>\n descriptor.shortcut === undefined ||\n !SHELL_METACHAR_RE.test(descriptor.shortcut),\n {\n message: \"must not contain shell metacharacters (;|&`$ or newlines)\",\n path: [\"shortcut\"],\n },\n )\n .describe(\n \"Discovery via a free-form Databricks CLI command. Escape hatch — prefer the `kind` variant when a typed resourceKind covers the resource. This shape is intentionally minimal and may tighten further in future versions.\",\n );\n\nexport const discoveryDescriptorSchema = z\n .discriminatedUnion(\"type\", [\n kindDiscoveryDescriptorSchema,\n cliDiscoveryDescriptorSchema,\n ])\n .describe(\n \"Describes how the CLI discovers values for a resource field. 'kind' references a well-known Databricks resource kind whose command is owned by AppKit; 'cli' is the escape hatch carrying a free-form Databricks CLI command.\",\n );\n\n// ── Resource kind → CLI command map ──────────────────────────────────────\n\n/**\n * Descriptor for how a well-known resource kind is listed via the\n * Databricks CLI.\n *\n * - `command` is the CLI invocation template. It carries two kinds of\n * placeholders:\n * - `<PROFILE>` — substituted with the user's CLI profile by the runner.\n * - `{<fieldName>}` — substituted with the resolved value of the named\n * sibling field (used for `dependsOn` chains).\n * - `unwrap`, when set, is the JSON path into the response wrapper (e.g.,\n * `\"warehouses\"` for `{ warehouses: [...] }`). Omitted when the response\n * is already a flat array.\n * - `parents`, when set, lists transient query inputs the runner must\n * collect (as free-text prompts) before invoking the command. Each\n * `parents[i]` value substitutes the matching `{name}` placeholder in\n * the command string. Unlike `dependsOn` (which references a sibling\n * field on the same resource), `parents` covers inputs that aren't\n * persisted as fields on the resource.\n */\nexport type ResourceKindCommand = {\n command: string;\n unwrap?: string;\n parents?: readonly string[];\n};\n\n/**\n * Single source of truth for AppKit-owned discovery commands.\n *\n * To add a new resource kind: extend `resourceKindSchema` and add an entry\n * here. Plugins reference the kind via `discovery: { type: \"kind\",\n * resourceKind: \"...\" }` and inherit the command + response shape.\n *\n * `unwrap` defaults are unset: the existing core plugin manifests use simple\n * jq paths (`.id`, `.name`, `.full_name`), implying the listed CLI commands\n * return flat arrays. Refine in a follow-up if a kind's CLI returns wrapped\n * data.\n *\n * Volume's catalog/schema parent context is supplied via the `parents`\n * array, which the runner collects from the user as free-text prompts\n * before invoking the listing command.\n */\nexport const RESOURCE_KIND_COMMANDS: Record<\n z.infer<typeof resourceKindSchema>,\n { command: string; unwrap?: string; parents?: readonly string[] }\n> = {\n warehouse: {\n command: \"databricks warehouses list --profile <PROFILE> --output json\",\n },\n genie_space: {\n command: \"databricks genie list-spaces --profile <PROFILE> --output json\",\n },\n postgres_project: {\n command:\n \"databricks postgres list-projects --profile <PROFILE> --output json\",\n },\n postgres_branch: {\n // {project} is a placeholder for the resolved value of the `project`\n // sibling field (declared via `dependsOn: \"project\"` on the kind variant).\n // The Databricks CLI requires the parent project resource name (format\n // `projects/{project_id}`) as a positional argument.\n command:\n \"databricks postgres list-branches {project} --profile <PROFILE> --output json\",\n },\n postgres_database: {\n // {branch} is a placeholder for the resolved value of the `branch`\n // sibling field (declared via `dependsOn: \"branch\"` on the kind variant).\n command:\n \"databricks postgres list-databases {branch} --profile <PROFILE> --output json\",\n },\n volume: {\n // `parents` declares free-text user prompts the runner must collect before\n // invoking the discovery command. Each `parents[i]` value substitutes the\n // matching `{name}` placeholder in the command string above. Unlike\n // `dependsOn` (which references a sibling field on the same resource),\n // `parents` covers transient query inputs that aren't persisted as fields.\n command:\n \"databricks volumes list {catalog} {schema} --profile <PROFILE> --output json\",\n parents: [\"catalog\", \"schema\"] as const,\n },\n};\n\n// ── Resource field entry (plugin manifest variant) ───────────────────────\n\nexport const resourceFieldEntrySchema = z\n .object({\n env: z\n .string()\n .regex(/^[A-Z][A-Z0-9_]*$/)\n .optional()\n .describe(\"Environment variable name for this field\"),\n description: z\n .string()\n .optional()\n .describe(\"Human-readable description for this field\"),\n bundleIgnore: z\n .boolean()\n .optional()\n .describe(\n \"When true, this field is excluded from Databricks bundle configuration (databricks.yml) generation.\",\n ),\n examples: z\n .array(z.string())\n .optional()\n .describe(\"Example values showing the expected format for this field\"),\n localOnly: z\n .boolean()\n .optional()\n .describe(\n \"When true, this field is only generated for local .env files. The Databricks Apps platform auto-injects it at deploy time.\",\n ),\n value: z\n .string()\n .optional()\n .describe(\n \"Static value for this field. Used when no prompted or resolved value exists.\",\n ),\n resolve: z\n .string()\n .regex(/^[a-z_]+:[a-zA-Z]+$/)\n .optional()\n .describe(\n \"Named resolver prefixed by resource type (e.g., 'postgres:host'). The CLI resolves this value during the init prompt flow.\",\n ),\n discovery: discoveryDescriptorSchema.optional(),\n })\n .strict()\n .describe(\n \"Defines a single field for a resource. Each field has its own environment variable and optional description. Single-value types use one key (e.g. id); multi-value types (database, secret) use multiple (e.g. instance_name, database_name or scope, key).\",\n );\n\n// ── Resource requirement (per-type permission discriminator) ─────────────\n\n/**\n * Build a per-type variant. Each variant fixes `type` to a literal and constrains\n * `permission` to the matching enum, mirroring the existing JSON Schema's\n * `allOf + if/then` block. `fields` and the rest of the shape come from a\n * shared base.\n */\nconst resourceRequirementBaseShape = {\n alias: z\n .string()\n .min(1)\n .describe(\n \"Human-readable label for UI/display only. Deduplication uses resourceKey, not alias.\",\n ),\n resourceKey: z\n .string()\n .regex(/^[a-z][a-z0-9-]*$/)\n .describe(\n \"Stable key for machine use: deduplication, env naming, composite keys, app.yaml. Required for registry lookup.\",\n ),\n description: z\n .string()\n .min(1)\n .describe(\"Human-readable description of why this resource is needed\"),\n fields: z\n .record(z.string(), resourceFieldEntrySchema)\n .refine((obj) => Object.keys(obj).length >= 1, {\n message: \"fields must contain at least one entry\",\n })\n .optional()\n .describe(\n \"Map of field name to env and optional description. Single-value types use one key (e.g. id); multi-value (database, secret) use multiple (e.g. instance_name, database_name or scope, key).\",\n ),\n};\n\n/**\n * Adds the cycle/dangling-reference cross-field check to a resource variant.\n * Iterates the resource's `fields`, validates each `discovery.dependsOn` target\n * is a sibling field name, then runs DFS over the dependsOn graph to detect\n * cycles. Issue paths target either the offending field's `dependsOn` slot or\n * the resource itself for cycles.\n */\nfunction refineResourceDependsOn(\n resource: { fields?: Record<string, { discovery?: { dependsOn?: string } }> },\n ctx: z.core.$RefinementCtx,\n): void {\n if (!resource.fields) return;\n const fieldNames = new Set(Object.keys(resource.fields));\n\n // Pass 1: validate dependsOn references and build the dependency graph.\n const deps = new Map<string, string>();\n for (const [name, field] of Object.entries(resource.fields)) {\n const dep = field.discovery?.dependsOn;\n if (!dep) continue;\n if (!fieldNames.has(dep)) {\n ctx.addIssue({\n code: \"custom\",\n path: [\"fields\", name, \"discovery\", \"dependsOn\"],\n message: `references non-existent sibling field '${dep}'`,\n });\n }\n deps.set(name, dep);\n }\n\n // Pass 2: detect cycles via DFS. Emit one issue per cycle found.\n const visited = new Set<string>();\n const visiting = new Set<string>();\n\n function dfs(node: string, chain: string[]): string[] | null {\n if (visiting.has(node)) return [...chain, node];\n if (visited.has(node)) return null;\n visiting.add(node);\n const next = deps.get(node);\n if (next) {\n const cycle = dfs(next, [...chain, node]);\n if (cycle) return cycle;\n }\n visiting.delete(node);\n visited.add(node);\n return null;\n }\n\n for (const node of deps.keys()) {\n if (visited.has(node)) continue;\n const cycle = dfs(node, []);\n if (cycle) {\n ctx.addIssue({\n code: \"custom\",\n path: [],\n message: `discovery.dependsOn creates a cycle: ${cycle.join(\" → \")}`,\n });\n // One cycle error per resource is enough.\n break;\n }\n }\n}\n\nfunction makeResourceVariant<\n TType extends z.ZodLiteral<string>,\n TPerm extends z.ZodTypeAny,\n>(typeLiteral: TType, permission: TPerm) {\n return z\n .object({\n type: typeLiteral,\n ...resourceRequirementBaseShape,\n permission: permission.describe(\n \"Required permission level. Validated per resource type.\",\n ),\n })\n .strict()\n .superRefine(refineResourceDependsOn);\n}\n\nexport const resourceRequirementSchema = z\n .discriminatedUnion(\"type\", [\n makeResourceVariant(z.literal(\"secret\"), secretPermissionSchema),\n makeResourceVariant(z.literal(\"job\"), jobPermissionSchema),\n makeResourceVariant(\n z.literal(\"sql_warehouse\"),\n sqlWarehousePermissionSchema,\n ),\n makeResourceVariant(\n z.literal(\"serving_endpoint\"),\n servingEndpointPermissionSchema,\n ),\n makeResourceVariant(z.literal(\"volume\"), volumePermissionSchema),\n makeResourceVariant(\n z.literal(\"vector_search_index\"),\n vectorSearchIndexPermissionSchema,\n ),\n makeResourceVariant(z.literal(\"uc_function\"), ucFunctionPermissionSchema),\n makeResourceVariant(\n z.literal(\"uc_connection\"),\n ucConnectionPermissionSchema,\n ),\n makeResourceVariant(z.literal(\"database\"), databasePermissionSchema),\n makeResourceVariant(z.literal(\"postgres\"), postgresPermissionSchema),\n makeResourceVariant(z.literal(\"genie_space\"), genieSpacePermissionSchema),\n makeResourceVariant(z.literal(\"experiment\"), experimentPermissionSchema),\n makeResourceVariant(z.literal(\"app\"), appPermissionSchema),\n ])\n .describe(\n \"Declares a resource requirement for a plugin. Can be defined statically in a manifest or dynamically via getResourceRequirements().\",\n );\n\n// ── Config schema (recursive) ────────────────────────────────────────────\n\nexport const configSchemaPropertySchema: z.ZodType = z.lazy(() =>\n z\n .object({\n type: z.enum([\n \"object\",\n \"array\",\n \"string\",\n \"number\",\n \"boolean\",\n \"integer\",\n ]),\n description: z.string().optional(),\n default: z.unknown().optional(),\n enum: z.array(z.unknown()).optional(),\n properties: z.record(z.string(), configSchemaPropertySchema).optional(),\n items: configSchemaPropertySchema.optional(),\n minimum: z.number().optional(),\n maximum: z.number().optional(),\n minLength: z.number().int().min(0).optional(),\n maxLength: z.number().int().min(0).optional(),\n required: z.array(z.string()).optional(),\n // `additionalProperties` is a standard JSON Schema keyword used by core\n // plugin manifests (e.g., serving, ai-search, genie) to constrain\n // dictionary-shaped properties. Allowed on nested property entries as\n // either a boolean or a sub-schema, mirroring JSON Schema semantics.\n additionalProperties: z\n .union([z.boolean(), configSchemaPropertySchema])\n .optional(),\n })\n .strict(),\n);\n\nexport const configSchemaSchema: z.ZodType = z.lazy(() =>\n z\n .object({\n type: z.enum([\"object\", \"array\", \"string\", \"number\", \"boolean\"]),\n properties: z.record(z.string(), configSchemaPropertySchema).optional(),\n items: configSchemaSchema.optional(),\n required: z.array(z.string()).optional(),\n additionalProperties: z.boolean().optional(),\n })\n .strict(),\n);\n\n// ── Plugin-level scaffolding rules ───────────────────────────────────────\n\n/**\n * Per-item upper bound on plugin-level scaffolding rule strings. Matches the\n * template-level `SCAFFOLDING_RULE_MAX_LENGTH` defined below — rules at both\n * levels are short directives, not prose. The literal value lives here (and\n * not by reference to the template-side constant) because this declaration\n * is read in source order and the template constant is declared later.\n */\nconst PLUGIN_SCAFFOLDING_RULE_MAX_LENGTH = 120;\n\nconst pluginScaffoldingRuleItemSchema = z\n .string()\n .min(1)\n .max(\n PLUGIN_SCAFFOLDING_RULE_MAX_LENGTH,\n `rule entries must be ≤ ${PLUGIN_SCAFFOLDING_RULE_MAX_LENGTH} chars`,\n );\n\nexport const pluginScaffoldingRulesSchema = z\n .object({\n must: z\n .array(pluginScaffoldingRuleItemSchema)\n .optional()\n .describe(\"Actions the scaffolding agent must always perform.\"),\n should: z\n .array(pluginScaffoldingRuleItemSchema)\n .optional()\n .describe(\"Recommended actions for the scaffolding agent.\"),\n never: z\n .array(pluginScaffoldingRuleItemSchema)\n .optional()\n .describe(\"Actions the scaffolding agent must never perform.\"),\n })\n .strict()\n .superRefine((rules, ctx) => {\n // (a) Reject duplicate entries within any single array.\n const buckets: Array<[\"must\" | \"should\" | \"never\", string[] | undefined]> =\n [\n [\"must\", rules.must],\n [\"should\", rules.should],\n [\"never\", rules.never],\n ];\n for (const [bucketName, items] of buckets) {\n if (!items) continue;\n const seen = new Map<string, number>();\n items.forEach((item, idx) => {\n const prev = seen.get(item);\n if (prev === undefined) {\n seen.set(item, idx);\n return;\n }\n ctx.addIssue({\n code: \"custom\",\n path: [bucketName, idx],\n message: `duplicate rule entry: \"${item}\" already declared at index ${prev}`,\n });\n });\n }\n // (b) Reject a string that appears in more than one of must/should/never.\n type Bucket = \"must\" | \"should\" | \"never\";\n const owner = new Map<string, Bucket>();\n for (const [bucketName, items] of buckets) {\n if (!items) continue;\n for (let i = 0; i < items.length; i++) {\n const item = items[i];\n const existing = owner.get(item);\n if (existing === undefined) {\n owner.set(item, bucketName);\n continue;\n }\n if (existing !== bucketName) {\n ctx.addIssue({\n code: \"custom\",\n path: [bucketName, i],\n message: `rule entry \"${item}\" appears in both '${existing}' and '${bucketName}'; rules must belong to exactly one bucket`,\n });\n }\n }\n }\n })\n .describe(\n \"Structured rules for scaffolding agents declared at the plugin level. Each rule is a short directive (≤120 chars).\",\n );\n\n// ── Plugin manifest (root) ───────────────────────────────────────────────\n\nexport const pluginManifestSchema = z\n .object({\n $schema: z\n .string()\n .optional()\n .describe(\"Reference to the JSON Schema for validation\"),\n name: z\n .string()\n .regex(PLUGIN_NAME_PATTERN)\n .describe(\n \"Plugin identifier and JS binding. Must start with a lowercase letter; camelCase for multi-word names (e.g. aiSearch).\",\n ),\n displayName: z\n .string()\n .min(1)\n .describe(\"Human-readable display name for UI and CLI\"),\n description: z\n .string()\n .min(1)\n .describe(\"Brief description of what the plugin does\"),\n resources: z\n .object({\n required: z\n .array(resourceRequirementSchema)\n .describe(\n \"Resources that must be available for the plugin to function\",\n ),\n optional: z\n .array(resourceRequirementSchema)\n .describe(\n \"Resources that enhance functionality but are not mandatory\",\n ),\n })\n .strict()\n .describe(\"Databricks resource requirements for this plugin\"),\n config: z\n .object({\n schema: configSchemaSchema.optional(),\n })\n .strict()\n .optional()\n .describe(\"Configuration schema for the plugin\"),\n author: z.string().optional().describe(\"Author name or organization\"),\n version: z\n .string()\n .regex(/^\\d+\\.\\d+\\.\\d+(-[a-zA-Z0-9.]+)?$/)\n .optional()\n .describe(\"Plugin version (semver format)\"),\n repository: z\n .url()\n .optional()\n .describe(\"URL to the plugin's source repository\"),\n keywords: z\n .array(z.string())\n .optional()\n .describe(\"Keywords for plugin discovery\"),\n license: z.string().optional().describe(\"SPDX license identifier\"),\n onSetupMessage: z\n .string()\n .optional()\n .describe(\n \"Message displayed to the user after project initialization. Use this to inform about manual setup steps (e.g. environment variables, resource provisioning).\",\n ),\n hidden: z\n .boolean()\n .optional()\n .describe(\n \"When true, this plugin is excluded from the template plugins manifest (appkit.plugins.json) during sync.\",\n ),\n devOnly: z\n .boolean()\n .optional()\n .describe(\n \"When true, this plugin is only registered when NODE_ENV === 'development'. In any other environment createApp skips it entirely (not constructed, no routes, resources not validated). Use for dev-only tooling that must never run in a deployed app.\",\n ),\n stability: z\n .enum([\"beta\", \"ga\"])\n .optional()\n .describe(\n \"Plugin stability level. Beta plugins may have breaking API changes between minor releases but are on a path to GA. GA (general availability) plugins follow semver strictly.\",\n ),\n scaffolding: z\n .object({\n rules: pluginScaffoldingRulesSchema\n .optional()\n .describe(\n \"Structured rules for scaffolding agents declared at the plugin level.\",\n ),\n })\n .strict()\n .optional()\n .describe(\n \"Plugin-level scaffolding metadata consumed by scaffolding agents. Symmetric with template-level `scaffolding`.\",\n ),\n })\n .strict()\n .describe(\n \"Schema for Databricks AppKit plugin manifest files. Defines plugin metadata, resource requirements, and configuration options.\",\n );\n\n// ── Origin enum ──────────────────────────────────────────────────────────\n\nexport const originSchema = z\n .enum([\"user\", \"platform\", \"static\", \"cli\"])\n .describe(\n \"How the field value is determined. Computed during sync, not authored by plugin developers.\",\n );\n\n// ── Template field entry (origin computed by transform) ─────────────────\n\n/**\n * Derives the canonical origin of a resource field value from its shape.\n *\n * - `localOnly: true` → `\"platform\"` (auto-injected by the Databricks Apps\n * platform at deploy time; takes precedence over `value`/`resolve`).\n * - `value !== undefined` → `\"static\"` (hardcoded value).\n * - `resolve !== undefined` → `\"cli\"` (resolved by the CLI during init).\n * - else → `\"user\"` (user must provide the value at init time).\n *\n * The single source for this rule: `plugin sync`'s transform stamps `origin`\n * with it, and consumers that read an authored manifest (no stamped `origin`)\n * derive it through this rather than re-implementing the cascade.\n */\nexport function computeOriginFromField(field: {\n localOnly?: boolean;\n value?: string;\n resolve?: string;\n}): z.infer<typeof originSchema> {\n if (field.localOnly) return \"platform\";\n if (field.value !== undefined) return \"static\";\n if (field.resolve !== undefined) return \"cli\";\n return \"user\";\n}\n\n/**\n * Template field entry: extends the plugin manifest field entry with an\n * optional `origin` input slot, then runs a `.transform()` that overwrites\n * `origin` with the computed value. Allowing `origin` on input means\n * re-parsing a previously-synced template manifest does not fail; emitting\n * `origin` always means hand-edits in synced JSON are silently corrected\n * on the next parse — drift-by-construction.\n */\nexport const templateFieldEntrySchema = resourceFieldEntrySchema\n .extend({ origin: originSchema.optional() })\n .transform((field) => ({\n ...field,\n origin: computeOriginFromField(field),\n }));\n\n// ── Template resource requirement (uses templateFieldEntrySchema) ────────\n\nconst templateResourceRequirementBaseShape = {\n alias: z\n .string()\n .min(1)\n .describe(\"Human-readable label for UI/display only.\"),\n resourceKey: z\n .string()\n .regex(/^[a-z][a-z0-9-]*$/)\n .describe(\n \"Stable key for machine use: deduplication, env naming, composite keys.\",\n ),\n description: z\n .string()\n .min(1)\n .describe(\"Human-readable description of why this resource is needed\"),\n fields: z\n .record(z.string(), templateFieldEntrySchema)\n .refine((obj) => Object.keys(obj).length >= 1, {\n message: \"fields must contain at least one entry\",\n })\n .optional()\n .describe(\"Map of field name to field entry with computed origin.\"),\n};\n\nfunction makeTemplateResourceVariant<\n TType extends z.ZodLiteral<string>,\n TPerm extends z.ZodTypeAny,\n>(typeLiteral: TType, permission: TPerm) {\n return z\n .object({\n type: typeLiteral,\n ...templateResourceRequirementBaseShape,\n permission: permission.describe(\n \"Required permission level. Validated per resource type.\",\n ),\n })\n .strict()\n .superRefine(refineResourceDependsOn);\n}\n\nexport const templateResourceRequirementSchema = z\n .discriminatedUnion(\"type\", [\n makeTemplateResourceVariant(z.literal(\"secret\"), secretPermissionSchema),\n makeTemplateResourceVariant(z.literal(\"job\"), jobPermissionSchema),\n makeTemplateResourceVariant(\n z.literal(\"sql_warehouse\"),\n sqlWarehousePermissionSchema,\n ),\n makeTemplateResourceVariant(\n z.literal(\"serving_endpoint\"),\n servingEndpointPermissionSchema,\n ),\n makeTemplateResourceVariant(z.literal(\"volume\"), volumePermissionSchema),\n makeTemplateResourceVariant(\n z.literal(\"vector_search_index\"),\n vectorSearchIndexPermissionSchema,\n ),\n makeTemplateResourceVariant(\n z.literal(\"uc_function\"),\n ucFunctionPermissionSchema,\n ),\n makeTemplateResourceVariant(\n z.literal(\"uc_connection\"),\n ucConnectionPermissionSchema,\n ),\n makeTemplateResourceVariant(\n z.literal(\"database\"),\n databasePermissionSchema,\n ),\n makeTemplateResourceVariant(\n z.literal(\"postgres\"),\n postgresPermissionSchema,\n ),\n makeTemplateResourceVariant(\n z.literal(\"genie_space\"),\n genieSpacePermissionSchema,\n ),\n makeTemplateResourceVariant(\n z.literal(\"experiment\"),\n experimentPermissionSchema,\n ),\n makeTemplateResourceVariant(z.literal(\"app\"), appPermissionSchema),\n ])\n .describe(\n \"Resource requirement with template-specific field entries (includes computed origin).\",\n );\n\n// ── Template plugin (extends plugin manifest) ────────────────────────────\n\nexport const templatePluginSchema = z\n .object({\n name: z\n .string()\n .regex(PLUGIN_NAME_PATTERN)\n .describe(\n \"Plugin identifier and JS binding. Must start with a lowercase letter; camelCase for multi-word names (e.g. aiSearch).\",\n ),\n displayName: z\n .string()\n .min(1)\n .describe(\"Human-readable display name for UI and CLI\"),\n description: z\n .string()\n .min(1)\n .describe(\"Brief description of what the plugin does\"),\n package: z\n .string()\n .min(1)\n .describe(\"NPM package name that provides this plugin\"),\n requiredByTemplate: z\n .boolean()\n .optional()\n .describe(\n \"When true, this plugin is required by the template and cannot be deselected during CLI init. The user will only be prompted to configure its resources. When absent or false, the plugin is optional and the user can choose whether to include it.\",\n ),\n onSetupMessage: z\n .string()\n .optional()\n .describe(\n \"Message displayed to the user after project initialization. Use this to inform about manual setup steps (e.g. environment variables, resource provisioning).\",\n ),\n stability: z\n .enum([\"beta\", \"ga\"])\n .optional()\n .describe(\n \"Plugin stability level. Beta is heading to GA; APIs may change between minor releases. GA (general availability) follows semver.\",\n ),\n scaffolding: z\n .object({\n rules: pluginScaffoldingRulesSchema\n .optional()\n .describe(\n \"Structured rules for scaffolding agents propagated from the plugin manifest.\",\n ),\n })\n .strict()\n .optional()\n .describe(\n \"Plugin-level scaffolding metadata propagated from the plugin manifest.\",\n ),\n resources: z\n .object({\n required: z\n .array(templateResourceRequirementSchema)\n .describe(\n \"Resources that must be available for the plugin to function\",\n ),\n optional: z\n .array(templateResourceRequirementSchema)\n .describe(\n \"Resources that enhance functionality but are not mandatory\",\n ),\n })\n .strict()\n .describe(\"Databricks resource requirements for this plugin\"),\n })\n .strict()\n .describe(\"Plugin manifest with package source information\");\n\n// ── Scaffolding descriptor ───────────────────────────────────────────────\n\nexport const scaffoldingFlagSchema = z\n .object({\n description: z.string().describe(\"Human-readable description of the flag.\"),\n required: z.boolean().optional().describe(\"Whether this flag is required.\"),\n pattern: z\n .string()\n .optional()\n .describe(\"Regex pattern for validating the flag value.\"),\n default: z.string().optional().describe(\"Default value for this flag.\"),\n })\n .strict()\n .describe(\"A flag for the scaffolding command.\");\n\n/**\n * Per-item upper bound on scaffolding rule strings. The intent is to enforce\n * \"short directive\" by contract — long paragraphs fail validation and force\n * authors to split prose into discrete actionable items.\n */\nconst SCAFFOLDING_RULE_MAX_LENGTH = 120;\n\nconst scaffoldingRuleItemSchema = z\n .string()\n .max(\n SCAFFOLDING_RULE_MAX_LENGTH,\n `rule item must be ≤ ${SCAFFOLDING_RULE_MAX_LENGTH} chars`,\n );\n\nexport const scaffoldingRulesSchema = z\n .object({\n never: z\n .array(scaffoldingRuleItemSchema)\n .optional()\n .describe(\"Actions the scaffolding agent must never perform.\"),\n must: z\n .array(scaffoldingRuleItemSchema)\n .optional()\n .describe(\"Actions the scaffolding agent must always perform.\"),\n should: z\n .array(scaffoldingRuleItemSchema)\n .optional()\n .describe(\n \"Recommended actions for the scaffolding agent (parity with plugin-level rules).\",\n ),\n })\n .strict()\n .describe(\"Structured rules for scaffolding agents.\");\n\nexport const scaffoldingDescriptorSchema = z\n .object({\n command: z\n .string()\n .describe(\"The scaffolding command (e.g., 'databricks apps init').\"),\n flags: z\n .record(z.string(), scaffoldingFlagSchema)\n .optional()\n .describe(\"Map of flag name to flag descriptor.\"),\n rules: scaffoldingRulesSchema\n .optional()\n .describe(\"Structured rules for scaffolding agents.\"),\n })\n .strict()\n .describe(\n \"Describes the scaffolding command, flags, and rules for project initialization.\",\n );\n\n/**\n * Canonical scaffolding descriptor for the `databricks apps init` command,\n * embedded in v2.0 template manifests to guide scaffolding agents.\n *\n * Co-located with `scaffoldingDescriptorSchema` so any change to the rule set\n * (or the schema's `maxLength` ceiling) shows up next to its consumer. The\n * `satisfies` annotation gives compile-time validation that the literal\n * matches the schema's input shape; if a `must`/`never` entry exceeds the\n * `maxLength` ceiling at runtime, `scaffoldingDescriptorSchema.parse` would\n * surface the breach in tests.\n */\nexport const TEMPLATE_SCAFFOLDING = {\n command: \"databricks apps init\",\n flags: {\n \"--name\": {\n description:\n \"Project name — sets {{.projectName}} in package.json, databricks.yml, and .env. Required for non-interactive scaffolding.\",\n required: true,\n pattern: \"^[a-z][a-z0-9-]*$\",\n },\n \"--template\": {\n description: \"Template path (local directory or GitHub URL)\",\n required: false,\n },\n \"--version\": {\n description: \"AppKit version to use; defaults to auto-detected\",\n required: false,\n },\n \"--features\": {\n description:\n \"Plugins to enable (comma-separated, no spaces; must match keys in this manifest's plugins map)\",\n required: false,\n pattern: \"^[a-zA-Z0-9_-]+(,[a-zA-Z0-9_-]+)*$\",\n },\n \"--set\": {\n description:\n \"Set resource values (format: plugin.resourceKey.field=value, repeatable)\",\n required: false,\n },\n \"--output-dir\": {\n description: \"Directory to write the project to\",\n required: false,\n },\n \"--description\": {\n description: \"App description\",\n required: false,\n },\n \"--run\": {\n description: \"Run the app after creation (none, dev, dev-remote)\",\n required: false,\n },\n \"--auto-approve\": {\n description:\n \"Pass as a bare flag (no value) to skip prompts for optional resources. Not recommended for agent-driven init — conflicts with the 'ask user when in doubt' rule.\",\n required: false,\n },\n \"--profile\": {\n description:\n \"Databricks CLI profile to use for authentication (global flag)\",\n required: false,\n },\n },\n rules: {\n must: [\n \"Treat `databricks apps init` output as starter code, not requirements; adapt or replace it to match the requested app\",\n \"Keep all secrets and credentials only in app.yaml, databricks.yml, and/or .env\",\n ],\n should: [\"ask user when in doubt of resource to use for plugin\"],\n never: [\n \"guess resources when multiple or no options are available\",\n \"embed secrets in files that will go to the client-bundle\",\n ],\n },\n} satisfies z.infer<typeof scaffoldingDescriptorSchema>;\n\n// ── Template plugins manifest (root) ─────────────────────────────────────\n\nexport const templatePluginsManifestSchema = z\n .object({\n $schema: z\n .string()\n .optional()\n .describe(\"Reference to the JSON Schema for validation\"),\n version: z\n .enum([\"1.0\", \"1.1\", \"2.0\"])\n .describe(\"Schema version for the template plugins manifest\"),\n plugins: z\n .record(z.string(), templatePluginSchema)\n .describe(\"Map of plugin name to plugin manifest with package source\"),\n scaffolding: scaffoldingDescriptorSchema\n .optional()\n .describe(\n \"Describes the scaffolding command and its configuration for project initialization.\",\n ),\n })\n .strict()\n .superRefine((value, ctx) => {\n if (value.version === \"2.0\" && !value.scaffolding) {\n ctx.addIssue({\n code: \"custom\",\n path: [\"scaffolding\"],\n message: \"scaffolding is required when version is '2.0'\",\n });\n }\n })\n .describe(\n \"Aggregated plugin manifest for AppKit templates. Read by Databricks CLI during init to discover available plugins and their resource requirements.\",\n );\n\n// ── Inferred types ───────────────────────────────────────────────────────\n\nexport type ResourceType = z.infer<typeof resourceTypeSchema>;\nexport type SecretPermission = z.infer<typeof secretPermissionSchema>;\nexport type JobPermission = z.infer<typeof jobPermissionSchema>;\nexport type SqlWarehousePermission = z.infer<\n typeof sqlWarehousePermissionSchema\n>;\nexport type ServingEndpointPermission = z.infer<\n typeof servingEndpointPermissionSchema\n>;\nexport type VolumePermission = z.infer<typeof volumePermissionSchema>;\nexport type VectorSearchIndexPermission = z.infer<\n typeof vectorSearchIndexPermissionSchema\n>;\nexport type UcFunctionPermission = z.infer<typeof ucFunctionPermissionSchema>;\nexport type UcConnectionPermission = z.infer<\n typeof ucConnectionPermissionSchema\n>;\nexport type DatabasePermission = z.infer<typeof databasePermissionSchema>;\nexport type PostgresPermission = z.infer<typeof postgresPermissionSchema>;\nexport type GenieSpacePermission = z.infer<typeof genieSpacePermissionSchema>;\nexport type ExperimentPermission = z.infer<typeof experimentPermissionSchema>;\nexport type AppPermission = z.infer<typeof appPermissionSchema>;\nexport type ResourceKind = z.infer<typeof resourceKindSchema>;\nexport type KindDiscoveryDescriptor = z.infer<\n typeof kindDiscoveryDescriptorSchema\n>;\nexport type CliDiscoveryDescriptor = z.infer<\n typeof cliDiscoveryDescriptorSchema\n>;\nexport type DiscoveryDescriptor = z.infer<typeof discoveryDescriptorSchema>;\nexport type ResourceFieldEntry = z.infer<typeof resourceFieldEntrySchema>;\nexport type ResourceRequirement = z.infer<typeof resourceRequirementSchema>;\nexport type ConfigSchemaProperty = z.infer<typeof configSchemaPropertySchema>;\nexport type ConfigSchema = z.infer<typeof configSchemaSchema>;\nexport type PluginScaffoldingRules = z.infer<\n typeof pluginScaffoldingRulesSchema\n>;\nexport type PluginManifest = z.infer<typeof pluginManifestSchema>;\nexport type Origin = z.infer<typeof originSchema>;\n// Template-side types use `z.input` so callers can construct a TemplatePlugin\n// from a parsed PluginManifest before the field-level origin transform runs.\n// `writeManifest` parses every field through `templateFieldEntrySchema` at\n// write-time, so the on-disk shape always has origin populated. The runtime\n// invariant: origin is *always* present after sync writes; the type slot\n// stays optional so the in-memory pipeline does not need to fabricate origin\n// before assignment.\nexport type TemplateFieldEntry = z.input<typeof templateFieldEntrySchema>;\nexport type TemplateResourceRequirement = z.input<\n typeof templateResourceRequirementSchema\n>;\nexport type TemplatePlugin = z.input<typeof templatePluginSchema>;\nexport type ScaffoldingFlag = z.infer<typeof scaffoldingFlagSchema>;\nexport type ScaffoldingRules = z.infer<typeof scaffoldingRulesSchema>;\nexport type ScaffoldingDescriptor = z.infer<typeof scaffoldingDescriptorSchema>;\nexport type TemplatePluginsManifest = z.input<\n typeof templatePluginsManifestSchema\n>;\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"metric-fqn.js","names":[],"sources":["../../src/schemas/metric-fqn.ts"],"sourcesContent":["/**\n * Unity Catalog object-name grammar\n * the single source of truth for metric view FQN (Fully Qualified Name).\n *\n * A metric view's `source` FQN is validated in two places that must agree:\n *\n * 1. The canonical Zod schema (`./metric-source.ts`), which composes the\n * three-part FQN regex from {@link UC_FQN_PATTERN} for IDE/CI and the\n * generated JSON schema (`docs/static/schemas/metric-source.schema.json`).\n * 2. The type-generator runtime (`packages/appkit/src/type-generator/mv-registry/config.ts`),\n * which imports {@link UC_FQN_PATTERN} as a plain value to validate each\n * dot-split segment.\n *\n *\n * A Unity Catalog object name:\n * - cannot exceed 255 characters ({@link MAX_UC_OBJECT_NAME_LENGTH}); and\n * - cannot contain any of these characters:\n * - period (`.`)\n * - space (U+0020)\n * - forward slash (`/`)\n * - all ASCII control characters (U+0000-U+001F)\n * - the DELETE character (U+007F)\n *\n * Every other character is permitted in a quoted name, including non-ASCII\n * letters (the docs demonstrate Chinese/Russian/Portuguese names) and hyphens.\n *\n * @note the regex is the per-segment character set; structure (3 parts) and length are intentionally left to the callers.\n */\n\nexport const MAX_UC_OBJECT_NAME_LENGTH = 255;\n\n/**\n * Basename of the metric-view declarations file, resolved inside a\n * `config/metric-views/` folder. Single source of truth shared by the analytics\n * runtime (`plugins/analytics/mv`), the type-generator, its Vite watcher, and\n * the `generate-types` CLI. It lives in this zod-free module (rather than the\n * canonical `metric-source.ts` schema) so the type-generator can import it\n * without pulling zod into its locked dependency graph.\n */\nexport const METRIC_CONFIG_FILE = \"definitions.json\";\n\n/**\n * Matches a single, non-empty Unity Catalog object name as it may appear in a backtick-quoted (delimited) identifier.\n *\n * @example\n * UC_FQN_PATTERN.test(\"revenue_metrics\"); // true\n * UC_FQN_PATTERN.test(\"prod-data\"); // true (hyphens are UC-legal)\n * UC_FQN_PATTERN.test(\"cafe\\u0301\"); // true (non-ASCII is UC-legal)\n * UC_FQN_PATTERN.test(\"bad name\"); // false (space is prohibited)\n * UC_FQN_PATTERN.test(\"a/b\"); // false (slash is prohibited)\n */\n//
|
|
1
|
+
{"version":3,"file":"metric-fqn.js","names":[],"sources":["../../src/schemas/metric-fqn.ts"],"sourcesContent":["/**\n * Unity Catalog object-name grammar\n * the single source of truth for metric view FQN (Fully Qualified Name).\n *\n * A metric view's `source` FQN is validated in two places that must agree:\n *\n * 1. The canonical Zod schema (`./metric-source.ts`), which composes the\n * three-part FQN regex from {@link UC_FQN_PATTERN} for IDE/CI and the\n * generated JSON schema (`docs/static/schemas/metric-source.schema.json`).\n * 2. The type-generator runtime (`packages/appkit/src/type-generator/mv-registry/config.ts`),\n * which imports {@link UC_FQN_PATTERN} as a plain value to validate each\n * dot-split segment.\n *\n *\n * A Unity Catalog object name:\n * - cannot exceed 255 characters ({@link MAX_UC_OBJECT_NAME_LENGTH}); and\n * - cannot contain any of these characters:\n * - period (`.`)\n * - space (U+0020)\n * - forward slash (`/`)\n * - all ASCII control characters (U+0000-U+001F)\n * - the DELETE character (U+007F)\n *\n * Every other character is permitted in a quoted name, including non-ASCII\n * letters (the docs demonstrate Chinese/Russian/Portuguese names) and hyphens.\n *\n * @note the regex is the per-segment character set; structure (3 parts) and length are intentionally left to the callers.\n */\n\nexport const MAX_UC_OBJECT_NAME_LENGTH = 255;\n\n/**\n * Basename of the metric-view declarations file, resolved inside a\n * `config/metric-views/` folder. Single source of truth shared by the analytics\n * runtime (`plugins/analytics/mv`), the type-generator, its Vite watcher, and\n * the `generate-types` CLI. It lives in this zod-free module (rather than the\n * canonical `metric-source.ts` schema) so the type-generator can import it\n * without pulling zod into its locked dependency graph.\n */\nexport const METRIC_CONFIG_FILE = \"definitions.json\";\n\n/**\n * Matches a single, non-empty Unity Catalog object name as it may appear in a backtick-quoted (delimited) identifier.\n *\n * @example\n * UC_FQN_PATTERN.test(\"revenue_metrics\"); // true\n * UC_FQN_PATTERN.test(\"prod-data\"); // true (hyphens are UC-legal)\n * UC_FQN_PATTERN.test(\"cafe\\u0301\"); // true (non-ASCII is UC-legal)\n * UC_FQN_PATTERN.test(\"bad name\"); // false (space is prohibited)\n * UC_FQN_PATTERN.test(\"a/b\"); // false (slash is prohibited)\n */\n// oxlint-disable-next-line no-control-regex -- UC explicitly prohibits ASCII control characters in object names; this negated class encodes that rule.\nexport const UC_FQN_PATTERN = /^[^\\x00-\\x20\\x7f./]+$/;\n\n/** A metric view FQN is exactly three segments: catalog.schema.metric_view. */\nconst FQN_SEGMENT_COUNT = 3;\n\n/**\n * Total predicate: is `fqn` a well-formed three-part UC metric view FQN?\n * Well-formed = exactly three non-empty, dot-separated segments, each a valid Unity Catalog object name per {@link UC_FQN_PATTERN}.\n * @example\n * isValidFqn(\"main.analytics.revenue\"); // true\n * isValidFqn(\"prod-data.analytics.rev\"); // true (hyphens are UC-legal)\n * isValidFqn(\"main.analytics\"); // false (only two segments)\n */\nexport function isValidFqn(fqn: string): boolean {\n const segments = fqn.split(\".\");\n if (segments.length !== FQN_SEGMENT_COUNT) {\n return false;\n }\n return segments.every((segment) => UC_FQN_PATTERN.test(segment));\n}\n\n/**\n * Quote a dot-separated FQN for safe interpolation into a Spark/Databricks SQL\n * statement.\n *\n * Each dot-split segment is wrapped in backtick-quoted-identifier syntax. The\n * one character that can break out of a backtick-quoted identifier is the\n * backtick itself, escaped by doubling (`` ` `` → `` `` ``) — so every backtick\n * inside a segment is doubled before the segment is wrapped. Control characters\n * and newlines have no valid escape inside a quoted identifier, so a segment\n * containing one is rejected outright.\n *\n * This is a pure, standalone escaper: it is intentionally independent of FQN\n * naming validation ({@link isValidFqn}). Naming validation decides whether an\n * FQN is an acceptable metric source; this function only guarantees that\n * whatever it is handed cannot break out of the quoted identifier it produces.\n * Grammar and quoting live together here so a metric source is validated and\n * escaped against one shared source of truth.\n *\n * An ordinary identifier is unchanged apart from the wrapping backticks:\n * `catalog.schema.view` → `` `catalog`.`schema`.`view` ``.\n *\n * @param fqn - Dot-separated identifier (e.g. `catalog.schema.view`).\n * @returns The backtick-quoted, escaped identifier ready for interpolation.\n * @throws If any segment contains a control character or newline.\n */\nexport function quoteFqnForSql(fqn: string): string {\n return fqn.split(\".\").map(quoteIdentifier).join(\".\");\n}\n\n/**\n * The Unicode \"control\" category (`\\p{Cc}`): C0 (incl. `\\n`, `\\r`, `\\t`), DEL,\n * and C1 — every control character/newline. These have no valid escape inside\n * a backtick-quoted identifier, so a name containing one cannot be safely\n * quoted and is rejected.\n */\nconst CONTROL_OR_NEWLINE = /\\p{Cc}/u;\n\nexport function isValidColumnName(name: string): boolean {\n return name.length > 0 && !CONTROL_OR_NEWLINE.test(name);\n}\n\n/**\n * Quote a single identifier (one column/measure/dimension name, or one FQN\n * segment) as a backtick-delimited identifier for safe SQL interpolation.\n *\n * @throws If `name` contains a control character or newline.\n */\nexport function quoteIdentifier(name: string): string {\n if (CONTROL_OR_NEWLINE.test(name)) {\n throw new Error(\n `Cannot quote identifier \"${name}\" for SQL: it contains a control character or newline, which has no valid escape inside a backtick-quoted identifier.`,\n );\n }\n // Double every backtick, then wrap in backticks.\n return `\\`${name.replace(/`/g, \"``\")}\\``;\n}\n"],"mappings":";;;;;;;;;AAuCA,MAAa,qBAAqB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin.d.ts","names":[],"sources":["../../../../shared/src/plugin.ts"],"mappings":";;;;;
|
|
1
|
+
{"version":3,"file":"plugin.d.ts","names":[],"sources":["../../../../shared/src/plugin.ts"],"mappings":";;;;;AAkBA;AAAA,UAAiB,UAAA;EACf,IAAA;EAmBa;;;;;;EAXb,qBAAA;EA+BoC;;;;;;;;;EApBpC,QAAA,KAAa,OAAA;EAEb,KAAA,IAAS,OAAA;EAET,YAAA,CAAa,MAAA,EAAQ,OAAA,CAAQ,MAAA;EAE7B,YAAA,IAAgB,iBAAA;EAEhB,uBAAA,KAA4B,WAAA;EAE5B,OAAA;EAEA,YAAA,KAAiB,MAAA;EAFjB;;;;EAQA,aAAA,EAAe,IAAA;IACb,OAAA;IACA,eAAA,GAAkB,gBAAA;EAAA;AAAA;;UAKL,gBAAA;EACf,IAAA;EACA,IAAA;EAAA,CAEC,GAAA;EAMD,SAAA,GAAY,gBAAA;AAAA;AAAA,KAGF,gBAAA;EAGN,MAAA;EACA,OAAA;EACA,IAAA;AAAA;AAAA,KAQM,WAAA;;;;;KAMA,iBAAA,KACN,gBAAA,YACM,UAAA,GAAa,UAAA,UACf,MAAA,EAAQ,CAAA,KAAM,CAAA;EACtB,cAAA,GAAiB,MAAA;EACjB,KAAA,GAAQ,WAAA;EAXa;;AAMvB;;EAUE,QAAA,EAAU,cAAA;EATN;;;;EAcJ,uBAAA,EAAyB,MAAA,EAAQ,CAAA,GAAI,mBAAA;AAAA;;;;;;;;;;UAYtB,cAAA,wCAAsD,IAAA,CACrE,gBAAA;EAiBA,IAAA,EAAM,KAAA;EACN,SAAA;IACE,QAAA,EAAU,IAAA,CAAK,mBAAA;IACf,QAAA,EAAU,IAAA,CAAK,mBAAA;EAAA;EAEjB,MAAA;IACE,MAAA,EAAQ,WAAA;EAAA;EAzCV;EA4CA,WAAA;EAvCA;EAyCA,WAAA;EAzCyB;EA2CzB,MAAA;EA3CwD;EA6CxD,OAAA;EAjCe;EAmCf,UAAA;EAnC6B;EAqC7B,QAAA;EAnBM;EAqBN,OAAA;EAnBY;EAqBZ,cAAA;EApBY;EAsBZ,MAAA;EA3CqE;EA6CrE,OAAA;EA7CyE;EA+CzE,SAAA;AAAA;;;;;;;;;;;;;;;UAiBe,mBAAA;EACf,IAAA;EACA,KAAA;EACA,WAAA;EACA,WAAA;EACA,UAAA;EACA,MAAA,EAAQ,MAAA,SAAe,kBAAA;EACvB,QAAA;AAAA;;AAkCF;;;;KAAY,aAAA,WAAwB,UAAA,IAClC,CAAA,sCAAqC,CAAA,GAAI,MAAA;;;;;;;;KAS/B,UAAA,QAAkB,GAAA,cAAgB,IAAA,mBAC1C,GAAA,GACA,GAAA;EAXuC;;;AAS3C;;EAQM,MAAA,GAAS,GAAA,EAAK,WAAA,KAAgB,GAAA;AAAA;;;;;;;;;;;KAaxB,SAAA,oBACS,UAAA,CAAW,iBAAA,gCAExB,CAAA,YAAa,CAAA,WAAY,UAAA,CAC7B,aAAA,CAAc,YAAA,CAAa,CAAA;;KAKnB,UAAA;EAAwB,MAAA,EAAQ,CAAA;EAAG,MAAA,EAAQ,CAAA;EAAG,IAAA,EAAM,CAAA;AAAA;;KAEpD,QAAA,4BACV,MAAA,GAAS,CAAA,KACN,UAAA,CAAW,CAAA,EAAG,CAAA,EAAG,CAAA;;KAGV,UAAA,GAAa,OAAA,CAAQ,MAAA;AAAA,KACrB,YAAA,GAAe,OAAA,CAAQ,QAAA;AAAA,KACvB,WAAA,GAAc,OAAA,CAAQ,OAAA;AAAA,KAEtB,UAAA;AAAA,KAEA,WAAA;EAnBqB,+DAqB/B,IAAA;EACA,MAAA,EAAQ,UAAA;EACR,IAAA;EACA,OAAA,GAAU,GAAA,EAAK,WAAA,EAAa,GAAA,EAAK,YAAA,KAAiB,OAAA,QA1BpB;EA4B9B,eAAA;AAAA;;KAIU,iBAAA,GAAoB,MAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"manifest.d.ts","names":[],"sources":["../../../../../shared/src/schemas/manifest.ts"],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"manifest.d.ts","names":[],"sources":["../../../../../shared/src/schemas/manifest.ts"],"mappings":";;;cAsVa,wBAAA,EAAwB,CAAA,CAAA,SAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cAsUxB,oBAAA,EAAoB,CAAA,CAAA,SAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAsgBrB,kBAAA,GAAqB,CAAA,CAAE,KAAA,QAAa,wBAAA;AAAA,KAOpC,cAAA,GAAiB,CAAA,CAAE,KAAA,QAAa,oBAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"metric-fqn.js","names":[],"sources":["../../../../../shared/src/schemas/metric-fqn.ts"],"sourcesContent":["/**\n * Unity Catalog object-name grammar\n * the single source of truth for metric view FQN (Fully Qualified Name).\n *\n * A metric view's `source` FQN is validated in two places that must agree:\n *\n * 1. The canonical Zod schema (`./metric-source.ts`), which composes the\n * three-part FQN regex from {@link UC_FQN_PATTERN} for IDE/CI and the\n * generated JSON schema (`docs/static/schemas/metric-source.schema.json`).\n * 2. The type-generator runtime (`packages/appkit/src/type-generator/mv-registry/config.ts`),\n * which imports {@link UC_FQN_PATTERN} as a plain value to validate each\n * dot-split segment.\n *\n *\n * A Unity Catalog object name:\n * - cannot exceed 255 characters ({@link MAX_UC_OBJECT_NAME_LENGTH}); and\n * - cannot contain any of these characters:\n * - period (`.`)\n * - space (U+0020)\n * - forward slash (`/`)\n * - all ASCII control characters (U+0000-U+001F)\n * - the DELETE character (U+007F)\n *\n * Every other character is permitted in a quoted name, including non-ASCII\n * letters (the docs demonstrate Chinese/Russian/Portuguese names) and hyphens.\n *\n * @note the regex is the per-segment character set; structure (3 parts) and length are intentionally left to the callers.\n */\n\nexport const MAX_UC_OBJECT_NAME_LENGTH = 255;\n\n/**\n * Basename of the metric-view declarations file, resolved inside a\n * `config/metric-views/` folder. Single source of truth shared by the analytics\n * runtime (`plugins/analytics/mv`), the type-generator, its Vite watcher, and\n * the `generate-types` CLI. It lives in this zod-free module (rather than the\n * canonical `metric-source.ts` schema) so the type-generator can import it\n * without pulling zod into its locked dependency graph.\n */\nexport const METRIC_CONFIG_FILE = \"definitions.json\";\n\n/**\n * Matches a single, non-empty Unity Catalog object name as it may appear in a backtick-quoted (delimited) identifier.\n *\n * @example\n * UC_FQN_PATTERN.test(\"revenue_metrics\"); // true\n * UC_FQN_PATTERN.test(\"prod-data\"); // true (hyphens are UC-legal)\n * UC_FQN_PATTERN.test(\"cafe\\u0301\"); // true (non-ASCII is UC-legal)\n * UC_FQN_PATTERN.test(\"bad name\"); // false (space is prohibited)\n * UC_FQN_PATTERN.test(\"a/b\"); // false (slash is prohibited)\n */\n//
|
|
1
|
+
{"version":3,"file":"metric-fqn.js","names":[],"sources":["../../../../../shared/src/schemas/metric-fqn.ts"],"sourcesContent":["/**\n * Unity Catalog object-name grammar\n * the single source of truth for metric view FQN (Fully Qualified Name).\n *\n * A metric view's `source` FQN is validated in two places that must agree:\n *\n * 1. The canonical Zod schema (`./metric-source.ts`), which composes the\n * three-part FQN regex from {@link UC_FQN_PATTERN} for IDE/CI and the\n * generated JSON schema (`docs/static/schemas/metric-source.schema.json`).\n * 2. The type-generator runtime (`packages/appkit/src/type-generator/mv-registry/config.ts`),\n * which imports {@link UC_FQN_PATTERN} as a plain value to validate each\n * dot-split segment.\n *\n *\n * A Unity Catalog object name:\n * - cannot exceed 255 characters ({@link MAX_UC_OBJECT_NAME_LENGTH}); and\n * - cannot contain any of these characters:\n * - period (`.`)\n * - space (U+0020)\n * - forward slash (`/`)\n * - all ASCII control characters (U+0000-U+001F)\n * - the DELETE character (U+007F)\n *\n * Every other character is permitted in a quoted name, including non-ASCII\n * letters (the docs demonstrate Chinese/Russian/Portuguese names) and hyphens.\n *\n * @note the regex is the per-segment character set; structure (3 parts) and length are intentionally left to the callers.\n */\n\nexport const MAX_UC_OBJECT_NAME_LENGTH = 255;\n\n/**\n * Basename of the metric-view declarations file, resolved inside a\n * `config/metric-views/` folder. Single source of truth shared by the analytics\n * runtime (`plugins/analytics/mv`), the type-generator, its Vite watcher, and\n * the `generate-types` CLI. It lives in this zod-free module (rather than the\n * canonical `metric-source.ts` schema) so the type-generator can import it\n * without pulling zod into its locked dependency graph.\n */\nexport const METRIC_CONFIG_FILE = \"definitions.json\";\n\n/**\n * Matches a single, non-empty Unity Catalog object name as it may appear in a backtick-quoted (delimited) identifier.\n *\n * @example\n * UC_FQN_PATTERN.test(\"revenue_metrics\"); // true\n * UC_FQN_PATTERN.test(\"prod-data\"); // true (hyphens are UC-legal)\n * UC_FQN_PATTERN.test(\"cafe\\u0301\"); // true (non-ASCII is UC-legal)\n * UC_FQN_PATTERN.test(\"bad name\"); // false (space is prohibited)\n * UC_FQN_PATTERN.test(\"a/b\"); // false (slash is prohibited)\n */\n// oxlint-disable-next-line no-control-regex -- UC explicitly prohibits ASCII control characters in object names; this negated class encodes that rule.\nexport const UC_FQN_PATTERN = /^[^\\x00-\\x20\\x7f./]+$/;\n\n/** A metric view FQN is exactly three segments: catalog.schema.metric_view. */\nconst FQN_SEGMENT_COUNT = 3;\n\n/**\n * Total predicate: is `fqn` a well-formed three-part UC metric view FQN?\n * Well-formed = exactly three non-empty, dot-separated segments, each a valid Unity Catalog object name per {@link UC_FQN_PATTERN}.\n * @example\n * isValidFqn(\"main.analytics.revenue\"); // true\n * isValidFqn(\"prod-data.analytics.rev\"); // true (hyphens are UC-legal)\n * isValidFqn(\"main.analytics\"); // false (only two segments)\n */\nexport function isValidFqn(fqn: string): boolean {\n const segments = fqn.split(\".\");\n if (segments.length !== FQN_SEGMENT_COUNT) {\n return false;\n }\n return segments.every((segment) => UC_FQN_PATTERN.test(segment));\n}\n\n/**\n * Quote a dot-separated FQN for safe interpolation into a Spark/Databricks SQL\n * statement.\n *\n * Each dot-split segment is wrapped in backtick-quoted-identifier syntax. The\n * one character that can break out of a backtick-quoted identifier is the\n * backtick itself, escaped by doubling (`` ` `` → `` `` ``) — so every backtick\n * inside a segment is doubled before the segment is wrapped. Control characters\n * and newlines have no valid escape inside a quoted identifier, so a segment\n * containing one is rejected outright.\n *\n * This is a pure, standalone escaper: it is intentionally independent of FQN\n * naming validation ({@link isValidFqn}). Naming validation decides whether an\n * FQN is an acceptable metric source; this function only guarantees that\n * whatever it is handed cannot break out of the quoted identifier it produces.\n * Grammar and quoting live together here so a metric source is validated and\n * escaped against one shared source of truth.\n *\n * An ordinary identifier is unchanged apart from the wrapping backticks:\n * `catalog.schema.view` → `` `catalog`.`schema`.`view` ``.\n *\n * @param fqn - Dot-separated identifier (e.g. `catalog.schema.view`).\n * @returns The backtick-quoted, escaped identifier ready for interpolation.\n * @throws If any segment contains a control character or newline.\n */\nexport function quoteFqnForSql(fqn: string): string {\n return fqn.split(\".\").map(quoteIdentifier).join(\".\");\n}\n\n/**\n * The Unicode \"control\" category (`\\p{Cc}`): C0 (incl. `\\n`, `\\r`, `\\t`), DEL,\n * and C1 — every control character/newline. These have no valid escape inside\n * a backtick-quoted identifier, so a name containing one cannot be safely\n * quoted and is rejected.\n */\nconst CONTROL_OR_NEWLINE = /\\p{Cc}/u;\n\nexport function isValidColumnName(name: string): boolean {\n return name.length > 0 && !CONTROL_OR_NEWLINE.test(name);\n}\n\n/**\n * Quote a single identifier (one column/measure/dimension name, or one FQN\n * segment) as a backtick-delimited identifier for safe SQL interpolation.\n *\n * @throws If `name` contains a control character or newline.\n */\nexport function quoteIdentifier(name: string): string {\n if (CONTROL_OR_NEWLINE.test(name)) {\n throw new Error(\n `Cannot quote identifier \"${name}\" for SQL: it contains a control character or newline, which has no valid escape inside a backtick-quoted identifier.`,\n );\n }\n // Double every backtick, then wrap in backticks.\n return `\\`${name.replace(/`/g, \"``\")}\\``;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA6BA,MAAa,4BAA4B;;;;;;;;;AAUzC,MAAa,qBAAqB;;;;;;;;;;;AAalC,MAAa,iBAAiB;;AAG9B,MAAM,oBAAoB;;;;;;;;;AAU1B,SAAgB,WAAW,KAAsB;CAC/C,MAAM,WAAW,IAAI,MAAM,IAAI;AAC/B,KAAI,SAAS,WAAW,kBACtB,QAAO;AAET,QAAO,SAAS,OAAO,YAAY,eAAe,KAAK,QAAQ,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;AA4BlE,SAAgB,eAAe,KAAqB;AAClD,QAAO,IAAI,MAAM,IAAI,CAAC,IAAI,gBAAgB,CAAC,KAAK,IAAI;;;;;;;;AAStD,MAAM,qBAAqB;AAE3B,SAAgB,kBAAkB,MAAuB;AACvD,QAAO,KAAK,SAAS,KAAK,CAAC,mBAAmB,KAAK,KAAK;;;;;;;;AAS1D,SAAgB,gBAAgB,MAAsB;AACpD,KAAI,mBAAmB,KAAK,KAAK,CAC/B,OAAM,IAAI,MACR,4BAA4B,KAAK,uHAClC;AAGH,QAAO,KAAK,KAAK,QAAQ,MAAM,KAAK,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"metric-metadata-bundle.js","names":[],"sources":["../../../../../shared/src/schemas/metric-metadata-bundle.ts"],"sourcesContent":["import { z } from \"zod\";\nimport { metricKeySchema } from \"./metric-source\";\n\n// Bundle format version.\nexport const METRIC_METADATA_BUNDLE_VERSION = 1;\nexport const METRIC_METADATA_FILE = \"metadata.generated.json\";\n\nconst columnDisplaySchema = z\n .object({\n type: z\n .string()\n .describe(\"SQL type of the column as reported by DESCRIBE.\"),\n display_name: z\n .string()\n .optional()\n .describe(\"Human label from the metric view's YAML `display_name`.\"),\n format: z\n .string()\n .optional()\n .describe(\n 'Spark number-format spec from the metric view\\'s YAML `format`, e.g. \"$#,##0.00\".',\n ),\n description: z\n .string()\n .optional()\n .describe(\"Column description from the metric view's YAML.\"),\n })\n // Non-strict: a newer generator may add per-column fields, and an older\n // runtime should keep serving the fields it does understand rather than\n // rejecting the whole bundle over one unknown key.\n .describe(\"Display metadata for a single metric-view column.\");\n\nconst metricEntryMetadataSchema = z\n .object({\n measures: z.record(z.string(), columnDisplaySchema),\n dimensions: z.record(z.string(), columnDisplaySchema),\n })\n .describe(\"Per-column display metadata for one metric view.\");\n\nexport const metricMetadataBundleSchema = z\n .object({\n version: z\n .number()\n .int()\n .describe(\n \"Bundle format version. Compared against METRIC_METADATA_BUNDLE_VERSION.\",\n ),\n metricViews: z\n .record(metricKeySchema, metricEntryMetadataSchema)\n .describe(\"Per-column display metadata, keyed by metric key.\"),\n })\n .describe(\n \"Schema for AppKit config/metric-views/metadata.generated.json — build-generated per-column display metadata for the analytics plugin's metric-view path. Generated; do not hand-edit.\",\n );\n\nexport type MetricMetadataBundle = z.infer<typeof metricMetadataBundleSchema>;\n"],"mappings":";;;;
|
|
1
|
+
{"version":3,"file":"metric-metadata-bundle.js","names":[],"sources":["../../../../../shared/src/schemas/metric-metadata-bundle.ts"],"sourcesContent":["import { z } from \"zod\";\n\nimport { metricKeySchema } from \"./metric-source\";\n\n// Bundle format version.\nexport const METRIC_METADATA_BUNDLE_VERSION = 1;\nexport const METRIC_METADATA_FILE = \"metadata.generated.json\";\n\nconst columnDisplaySchema = z\n .object({\n type: z\n .string()\n .describe(\"SQL type of the column as reported by DESCRIBE.\"),\n display_name: z\n .string()\n .optional()\n .describe(\"Human label from the metric view's YAML `display_name`.\"),\n format: z\n .string()\n .optional()\n .describe(\n 'Spark number-format spec from the metric view\\'s YAML `format`, e.g. \"$#,##0.00\".',\n ),\n description: z\n .string()\n .optional()\n .describe(\"Column description from the metric view's YAML.\"),\n })\n // Non-strict: a newer generator may add per-column fields, and an older\n // runtime should keep serving the fields it does understand rather than\n // rejecting the whole bundle over one unknown key.\n .describe(\"Display metadata for a single metric-view column.\");\n\nconst metricEntryMetadataSchema = z\n .object({\n measures: z.record(z.string(), columnDisplaySchema),\n dimensions: z.record(z.string(), columnDisplaySchema),\n })\n .describe(\"Per-column display metadata for one metric view.\");\n\nexport const metricMetadataBundleSchema = z\n .object({\n version: z\n .number()\n .int()\n .describe(\n \"Bundle format version. Compared against METRIC_METADATA_BUNDLE_VERSION.\",\n ),\n metricViews: z\n .record(metricKeySchema, metricEntryMetadataSchema)\n .describe(\"Per-column display metadata, keyed by metric key.\"),\n })\n .describe(\n \"Schema for AppKit config/metric-views/metadata.generated.json — build-generated per-column display metadata for the analytics plugin's metric-view path. Generated; do not hand-edit.\",\n );\n\nexport type MetricMetadataBundle = z.infer<typeof metricMetadataBundleSchema>;\n"],"mappings":";;;;AAKA,MAAa,iCAAiC;AAC9C,MAAa,uBAAuB;AAEpC,MAAM,sBAAsB,EACzB,OAAO;CACN,MAAM,EACH,QAAQ,CACR,SAAS,kDAAkD;CAC9D,cAAc,EACX,QAAQ,CACR,UAAU,CACV,SAAS,0DAA0D;CACtE,QAAQ,EACL,QAAQ,CACR,UAAU,CACV,SACC,qFACD;CACH,aAAa,EACV,QAAQ,CACR,UAAU,CACV,SAAS,kDAAkD;CAC/D,CAAC,CAID,SAAS,oDAAoD;AAEhE,MAAM,4BAA4B,EAC/B,OAAO;CACN,UAAU,EAAE,OAAO,EAAE,QAAQ,EAAE,oBAAoB;CACnD,YAAY,EAAE,OAAO,EAAE,QAAQ,EAAE,oBAAoB;CACtD,CAAC,CACD,SAAS,mDAAmD;AAE/D,MAAa,6BAA6B,EACvC,OAAO;CACN,SAAS,EACN,QAAQ,CACR,KAAK,CACL,SACC,0EACD;CACH,aAAa,EACV,OAAO,iBAAiB,0BAA0B,CAClD,SAAS,oDAAoD;CACjE,CAAC,CACD,SACC,wLACD"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"metric-source.js","names":[],"sources":["../../../../../shared/src/schemas/metric-source.ts"],"sourcesContent":["/**\n * AppKit metric-source schema.\n *\n * Single source of truth for `config/metric-views/definitions.json`\n * the config that activates the Analytics' metric-view path.\n *\n * `definitions.json` declares UC Metric Views under a single `metricViews` map.\n * Each entry binds a metric key to a UC metric view FQN plus the executor\n * the query runs as:\n * - `executor: \"app_service_principal\"` (default) — queried as the app service\n * principal (cache scope shared across all users).\n * - `executor: \"user\"` — queried as the requesting user (on-behalf-of;\n * cache scope per-user).\n *\n * A single map (rather than per-executor sections) makes metric keys unique\n * by construction — the same key cannot be declared twice with different\n * executors.\n */\n\nimport { z } from \"zod\";\nimport { MAX_UC_OBJECT_NAME_LENGTH, UC_FQN_PATTERN } from \"./metric-fqn\";\n\n/**\n * Safety cap on the number of declared metric views — a typo / DoS guard, NOT\n * a Unity Catalog limit. Mirrors the type-generator's `MAX_METRIC_VIEWS` so\n * runtime config validation and type generation accept exactly the same\n * configs (a config that fails generation must not silently pass at runtime).\n */\nconst MAX_METRIC_VIEWS = 200;\n\n/**\n * Whole-FQN length cap: three max-length UC object names plus the two dots.\n * The per-segment cap ({@link MAX_UC_OBJECT_NAME_LENGTH}) is enforced in the\n * `superRefine` below; this whole-string bound is the declarative half (it\n * serializes to a JSON-schema `maxLength`, whereas the per-segment check — like\n * the entry-count cap — cannot be expressed declaratively and lives in the\n * refinement, so it is a runtime/type-generator gate only).\n */\nconst MAX_FQN_LENGTH = MAX_UC_OBJECT_NAME_LENGTH * 3 + 2;\n\n/**\n * Three-part Unity Catalog FQN matcher, composed from the single-segment\n * {@link UC_FQN_PATTERN} so the per-segment grammar has exactly one source of\n * truth (shared by the type-generator runtime, which imports the zod-free\n * {@link UC_FQN_PATTERN} directly — see `./metric-fqn.ts`).\n *\n * `UC_FQN_PATTERN` is `^<segment>+$`; stripping its `^`/`$` anchors yields the\n * per-segment sub-pattern, which is joined with literal dots into\n * `^<segment>\\.<segment>\\.<segment>$`. Exactly three dot-separated segments,\n * each a valid UC object name. Arity (and the per-segment length cap) is also\n * enforced structurally by the type-generator's `resolveMetricConfig`.\n */\nconst UC_FQN_SEGMENT_SOURCE = UC_FQN_PATTERN.source\n .replace(/^\\^/, \"\")\n .replace(/\\$$/, \"\");\nconst UC_THREE_PART_FQN_PATTERN = new RegExp(\n `^${UC_FQN_SEGMENT_SOURCE}\\\\.${UC_FQN_SEGMENT_SOURCE}\\\\.${UC_FQN_SEGMENT_SOURCE}$`,\n);\n\nexport const metricKeySchema = z\n .string()\n .regex(/^[a-zA-Z_][a-zA-Z0-9_]*$/)\n .describe(\n \"Metric key. Must be a valid identifier (letters, digits, underscores; cannot start with a digit). Becomes the route key in POST /api/analytics/metric/:key, the hook argument in useMetricView('<key>', ...), and the MetricRegistry augmentation key.\",\n );\n\nexport const metricExecutorSchema = z\n .enum([\"app_service_principal\", \"user\"])\n .describe(\n \"Who the metric view is queried as. 'app_service_principal' (default) runs as the app service principal with a cache shared across all users; 'user' runs on-behalf-of the requesting user with a per-user cache.\",\n );\n\n/**\n * @note Entries are objects (rather than bare strings) at v1 so future per-entry\n * options (cacheTtl, defaultFilter, allowlists) can ship as additive\n * properties without a breaking change. `executor` is the first such option.\n */\nexport const metricEntrySchema = z\n .object({\n source: z\n .string()\n .regex(UC_THREE_PART_FQN_PATTERN)\n .max(MAX_FQN_LENGTH)\n .describe(\n \"Three-part Unity Catalog FQN of the metric view: <catalog>.<schema>.<metric_view>\",\n )\n .meta({\n examples: [\n \"appkit_demo.public.revenue_metrics\",\n \"main.analytics.customer_metrics\",\n ],\n }),\n executor: metricExecutorSchema.default(\"app_service_principal\"),\n })\n .strict()\n .describe(\n \"A single metric view source declaration: the UC FQN to query and the executor to query it as. Future per-entry options (cacheTtl, defaultFilter, allowlists) ship as additive properties.\",\n );\n\nexport const metricSourceSchema = z\n .object({\n $schema: z\n .string()\n .optional()\n .describe(\"Reference to the JSON Schema for validation\"),\n metricViews: z\n .record(metricKeySchema, metricEntrySchema)\n .optional()\n .describe(\n \"Metric view declarations, keyed by metric key. Each entry names the UC metric view to query and the executor it runs as.\",\n ),\n })\n .strict()\n .describe(\n \"Schema for AppKit config/metric-views/definitions.json — declares Unity Catalog Metric View sources for the analytics plugin's metric-view path. Each entry under 'metricViews' binds a metric key to a UC metric view FQN and an executor ('app_service_principal' shared cache, or 'user' per-user cache). Object form (rather than bare string) at v1 enables future per-entry option growth without breaking changes.\",\n )\n // Caps that cannot be expressed declaratively (zod 4's `z.record` has no\n // `.max`, and a per-dot-segment length bound isn't a whole-string\n // `maxLength`). Enforced here so runtime config validation matches the\n // type-generator's `resolveMetricConfig` exactly — a config that fails type\n // generation must not silently pass at runtime. These refinements are\n // invisible to `z.toJSONSchema`, so the generated JSON schema carries only\n // the declarative `maxLength` on `source`; runtime + type-generator remain\n // the authoritative gates for the entry-count and per-segment caps.\n .superRefine((value, ctx) => {\n const entries = value.metricViews ? Object.entries(value.metricViews) : [];\n\n if (entries.length > MAX_METRIC_VIEWS) {\n ctx.addIssue({\n code: \"custom\",\n message: `too many metric views: ${entries.length} declared, exceeding the maximum of ${MAX_METRIC_VIEWS}`,\n path: [\"metricViews\"],\n });\n }\n\n for (const [key, entry] of entries) {\n const segments = entry.source.split(\".\");\n for (let i = 0; i < segments.length; i++) {\n if (segments[i].length > MAX_UC_OBJECT_NAME_LENGTH) {\n ctx.addIssue({\n code: \"custom\",\n message: `metric source segment ${i + 1} is ${segments[i].length} characters, exceeding the per-segment maximum of ${MAX_UC_OBJECT_NAME_LENGTH}`,\n path: [\"metricViews\", key, \"source\"],\n });\n }\n }\n }\n });\n\nexport type MetricKey = z.infer<typeof metricKeySchema>;\nexport type MetricExecutor = z.infer<typeof metricExecutorSchema>;\nexport type MetricEntry = z.infer<typeof metricEntrySchema>;\nexport type MetricSource = z.infer<typeof metricSourceSchema>;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"metric-source.js","names":[],"sources":["../../../../../shared/src/schemas/metric-source.ts"],"sourcesContent":["/**\n * AppKit metric-source schema.\n *\n * Single source of truth for `config/metric-views/definitions.json`\n * the config that activates the Analytics' metric-view path.\n *\n * `definitions.json` declares UC Metric Views under a single `metricViews` map.\n * Each entry binds a metric key to a UC metric view FQN plus the executor\n * the query runs as:\n * - `executor: \"app_service_principal\"` (default) — queried as the app service\n * principal (cache scope shared across all users).\n * - `executor: \"user\"` — queried as the requesting user (on-behalf-of;\n * cache scope per-user).\n *\n * A single map (rather than per-executor sections) makes metric keys unique\n * by construction — the same key cannot be declared twice with different\n * executors.\n */\n\nimport { z } from \"zod\";\n\nimport { MAX_UC_OBJECT_NAME_LENGTH, UC_FQN_PATTERN } from \"./metric-fqn\";\n\n/**\n * Safety cap on the number of declared metric views — a typo / DoS guard, NOT\n * a Unity Catalog limit. Mirrors the type-generator's `MAX_METRIC_VIEWS` so\n * runtime config validation and type generation accept exactly the same\n * configs (a config that fails generation must not silently pass at runtime).\n */\nconst MAX_METRIC_VIEWS = 200;\n\n/**\n * Whole-FQN length cap: three max-length UC object names plus the two dots.\n * The per-segment cap ({@link MAX_UC_OBJECT_NAME_LENGTH}) is enforced in the\n * `superRefine` below; this whole-string bound is the declarative half (it\n * serializes to a JSON-schema `maxLength`, whereas the per-segment check — like\n * the entry-count cap — cannot be expressed declaratively and lives in the\n * refinement, so it is a runtime/type-generator gate only).\n */\nconst MAX_FQN_LENGTH = MAX_UC_OBJECT_NAME_LENGTH * 3 + 2;\n\n/**\n * Three-part Unity Catalog FQN matcher, composed from the single-segment\n * {@link UC_FQN_PATTERN} so the per-segment grammar has exactly one source of\n * truth (shared by the type-generator runtime, which imports the zod-free\n * {@link UC_FQN_PATTERN} directly — see `./metric-fqn.ts`).\n *\n * `UC_FQN_PATTERN` is `^<segment>+$`; stripping its `^`/`$` anchors yields the\n * per-segment sub-pattern, which is joined with literal dots into\n * `^<segment>\\.<segment>\\.<segment>$`. Exactly three dot-separated segments,\n * each a valid UC object name. Arity (and the per-segment length cap) is also\n * enforced structurally by the type-generator's `resolveMetricConfig`.\n */\nconst UC_FQN_SEGMENT_SOURCE = UC_FQN_PATTERN.source\n .replace(/^\\^/, \"\")\n .replace(/\\$$/, \"\");\nconst UC_THREE_PART_FQN_PATTERN = new RegExp(\n `^${UC_FQN_SEGMENT_SOURCE}\\\\.${UC_FQN_SEGMENT_SOURCE}\\\\.${UC_FQN_SEGMENT_SOURCE}$`,\n);\n\nexport const metricKeySchema = z\n .string()\n .regex(/^[a-zA-Z_][a-zA-Z0-9_]*$/)\n .describe(\n \"Metric key. Must be a valid identifier (letters, digits, underscores; cannot start with a digit). Becomes the route key in POST /api/analytics/metric/:key, the hook argument in useMetricView('<key>', ...), and the MetricRegistry augmentation key.\",\n );\n\nexport const metricExecutorSchema = z\n .enum([\"app_service_principal\", \"user\"])\n .describe(\n \"Who the metric view is queried as. 'app_service_principal' (default) runs as the app service principal with a cache shared across all users; 'user' runs on-behalf-of the requesting user with a per-user cache.\",\n );\n\n/**\n * @note Entries are objects (rather than bare strings) at v1 so future per-entry\n * options (cacheTtl, defaultFilter, allowlists) can ship as additive\n * properties without a breaking change. `executor` is the first such option.\n */\nexport const metricEntrySchema = z\n .object({\n source: z\n .string()\n .regex(UC_THREE_PART_FQN_PATTERN)\n .max(MAX_FQN_LENGTH)\n .describe(\n \"Three-part Unity Catalog FQN of the metric view: <catalog>.<schema>.<metric_view>\",\n )\n .meta({\n examples: [\n \"appkit_demo.public.revenue_metrics\",\n \"main.analytics.customer_metrics\",\n ],\n }),\n executor: metricExecutorSchema.default(\"app_service_principal\"),\n })\n .strict()\n .describe(\n \"A single metric view source declaration: the UC FQN to query and the executor to query it as. Future per-entry options (cacheTtl, defaultFilter, allowlists) ship as additive properties.\",\n );\n\nexport const metricSourceSchema = z\n .object({\n $schema: z\n .string()\n .optional()\n .describe(\"Reference to the JSON Schema for validation\"),\n metricViews: z\n .record(metricKeySchema, metricEntrySchema)\n .optional()\n .describe(\n \"Metric view declarations, keyed by metric key. Each entry names the UC metric view to query and the executor it runs as.\",\n ),\n })\n .strict()\n .describe(\n \"Schema for AppKit config/metric-views/definitions.json — declares Unity Catalog Metric View sources for the analytics plugin's metric-view path. Each entry under 'metricViews' binds a metric key to a UC metric view FQN and an executor ('app_service_principal' shared cache, or 'user' per-user cache). Object form (rather than bare string) at v1 enables future per-entry option growth without breaking changes.\",\n )\n // Caps that cannot be expressed declaratively (zod 4's `z.record` has no\n // `.max`, and a per-dot-segment length bound isn't a whole-string\n // `maxLength`). Enforced here so runtime config validation matches the\n // type-generator's `resolveMetricConfig` exactly — a config that fails type\n // generation must not silently pass at runtime. These refinements are\n // invisible to `z.toJSONSchema`, so the generated JSON schema carries only\n // the declarative `maxLength` on `source`; runtime + type-generator remain\n // the authoritative gates for the entry-count and per-segment caps.\n .superRefine((value, ctx) => {\n const entries = value.metricViews ? Object.entries(value.metricViews) : [];\n\n if (entries.length > MAX_METRIC_VIEWS) {\n ctx.addIssue({\n code: \"custom\",\n message: `too many metric views: ${entries.length} declared, exceeding the maximum of ${MAX_METRIC_VIEWS}`,\n path: [\"metricViews\"],\n });\n }\n\n for (const [key, entry] of entries) {\n const segments = entry.source.split(\".\");\n for (let i = 0; i < segments.length; i++) {\n if (segments[i].length > MAX_UC_OBJECT_NAME_LENGTH) {\n ctx.addIssue({\n code: \"custom\",\n message: `metric source segment ${i + 1} is ${segments[i].length} characters, exceeding the per-segment maximum of ${MAX_UC_OBJECT_NAME_LENGTH}`,\n path: [\"metricViews\", key, \"source\"],\n });\n }\n }\n }\n });\n\nexport type MetricKey = z.infer<typeof metricKeySchema>;\nexport type MetricExecutor = z.infer<typeof metricExecutorSchema>;\nexport type MetricEntry = z.infer<typeof metricEntrySchema>;\nexport type MetricSource = z.infer<typeof metricSourceSchema>;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;AA6BA,MAAM,mBAAmB;;;;;;;;;AAUzB,MAAM,iBAAiB,4BAA4B,IAAI;;;;;;;;;;;;;AAcvD,MAAM,wBAAwB,eAAe,OAC1C,QAAQ,OAAO,GAAG,CAClB,QAAQ,OAAO,GAAG;AACrB,MAAM,4BAA4B,IAAI,OACpC,IAAI,sBAAsB,KAAK,sBAAsB,KAAK,sBAAsB,GACjF;AAED,MAAa,kBAAkB,EAC5B,QAAQ,CACR,MAAM,2BAA2B,CACjC,SACC,yPACD;AAEH,MAAa,uBAAuB,EACjC,KAAK,CAAC,yBAAyB,OAAO,CAAC,CACvC,SACC,mNACD;;;;;;AAOH,MAAa,oBAAoB,EAC9B,OAAO;CACN,QAAQ,EACL,QAAQ,CACR,MAAM,0BAA0B,CAChC,IAAI,eAAe,CACnB,SACC,oFACD,CACA,KAAK,EACJ,UAAU,CACR,sCACA,kCACD,EACF,CAAC;CACJ,UAAU,qBAAqB,QAAQ,wBAAwB;CAChE,CAAC,CACD,QAAQ,CACR,SACC,4LACD;AAEH,MAAa,qBAAqB,EAC/B,OAAO;CACN,SAAS,EACN,QAAQ,CACR,UAAU,CACV,SAAS,8CAA8C;CAC1D,aAAa,EACV,OAAO,iBAAiB,kBAAkB,CAC1C,UAAU,CACV,SACC,2HACD;CACJ,CAAC,CACD,QAAQ,CACR,SACC,4ZACD,CASA,aAAa,OAAO,QAAQ;CAC3B,MAAM,UAAU,MAAM,cAAc,OAAO,QAAQ,MAAM,YAAY,GAAG,EAAE;AAE1E,KAAI,QAAQ,SAAS,iBACnB,KAAI,SAAS;EACX,MAAM;EACN,SAAS,0BAA0B,QAAQ,OAAO,sCAAsC;EACxF,MAAM,CAAC,cAAc;EACtB,CAAC;AAGJ,MAAK,MAAM,CAAC,KAAK,UAAU,SAAS;EAClC,MAAM,WAAW,MAAM,OAAO,MAAM,IAAI;AACxC,OAAK,IAAI,IAAI,GAAG,IAAI,SAAS,QAAQ,IACnC,KAAI,SAAS,GAAG,SAAS,0BACvB,KAAI,SAAS;GACX,MAAM;GACN,SAAS,yBAAyB,IAAI,EAAE,MAAM,SAAS,GAAG,OAAO,oDAAoD;GACrH,MAAM;IAAC;IAAe;IAAK;IAAS;GACrC,CAAC;;EAIR"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"analytics.js","names":[],"sources":["../../../../../shared/src/sse/analytics.ts"],"sourcesContent":["import { z } from \"zod\";\nimport type { MetricViewColumnDisplay } from \"../metric-metadata\";\n\n/**\n * Wire protocol for analytics SSE messages emitted by `/api/analytics/query`.\n *\n * The SSE channel carries only the JSON_ARRAY path (warehouse-readiness\n * events + a `result` message of rows). ARROW_STREAM does NOT use SSE —\n * the server streams the raw Arrow IPC bytes back on the query response body\n * (`_handleArrowStreamQuery`) and the client reads them directly\n * (`fetchArrowDirect`), so there is no `arrow` message type here.\n *\n * These schemas are the single source of truth for the JSON contract between\n * the server (`AnalyticsPlugin._handleQueryRoute`) and the client\n * (`useAnalyticsQuery`). Both sides validate with the same schema:\n *\n * - Server uses the typed builder (`makeResultMessage`) to construct messages\n * with compile-time guarantees that all required fields are present.\n * - Client calls `AnalyticsSseMessage.safeParse(JSON.parse(event.data))` to\n * fail loudly on a malformed payload instead of silently treating an\n * undefined field as data.\n */\n\n/** Successful row-shaped result (JSON_ARRAY format, or empty results). */\nexport const AnalyticsResultMessage = z.object({\n type: z.literal(\"result\"),\n // `data` is intentionally `z.array(z.unknown())` rather than a deep\n // row schema. Validating every row's keys for shape costs O(rows × cols)\n // CPU and main-thread blocking time on the *client* (the schema is\n // also reused for `safeParse` in `useAnalyticsQuery`); for large JSON\n // results that pushes hundreds of ms to seconds of TBT into the\n // render pipeline. The server constructs `data` via the typed\n // `makeResultMessage` builder, so the per-row shape is enforced at\n // the source, not at validation time. The TS-level interface below\n // narrows `data` to `Record<string, unknown>[]` for callers.\n data: z.array(z.unknown()).optional(),\n // Status is opaque metadata forwarded from the warehouse — keep it as\n // `unknown` so we don't bake the SDK's detailed shape into the contract.\n status: z.unknown().optional(),\n statement_id: z.string().optional(),\n // Per-column display metadata for a metric-view result; absent for plain\n // `/query` results. Kept loose for the same reason as `data` above.\n metadata: z.record(z.string(), z.unknown()).optional(),\n});\n\n/**\n * TS-level shape of a successful row-shaped result message.\n *\n * **Kept in sync by hand** with `AnalyticsResultMessage` above. The Zod\n * schema is intentionally loose (`z.array(z.unknown())` for `data`,\n * `z.record(z.string(), z.unknown())` for `metadata`) to keep client\n * validation cheap; this interface narrows `data` to\n * `Record<string, unknown>[]` and `metadata` to\n * `Record<string, MetricViewColumnDisplay>` so consumers don't have to cast\n * at every call site. If you add a field to the Zod schema, add it here too.\n */\nexport interface AnalyticsResultMessage {\n type: \"result\";\n data?: Record<string, unknown>[];\n status?: unknown;\n statement_id?: string;\n metadata?: Record<string, MetricViewColumnDisplay>;\n}\n\n/**\n * Every message the analytics SSE stream may emit. Currently only the\n * row-shaped `result` message (JSON_ARRAY path); `warehouse_status` and\n * `error` events are handled off-schema by the client. ARROW_STREAM never\n * uses SSE.\n */\nexport const AnalyticsSseMessage = AnalyticsResultMessage;\nexport type AnalyticsSseMessage = z.infer<typeof AnalyticsSseMessage>;\n\n// ────────────────────────────────────────────────────────────────────────────\n// Typed builder — call from the server route handler. The compiler enforces\n// that every required field is supplied, and the return type narrows so\n// downstream code (executeStream / SSE writer) keeps full type information.\n// ────────────────────────────────────────────────────────────────────────────\n\nexport function makeResultMessage(\n data: Record<string, unknown>[] | undefined,\n extras: {\n status?: unknown;\n statement_id?: string;\n metadata?: Record<string, MetricViewColumnDisplay>;\n } = {},\n): AnalyticsResultMessage {\n return { type: \"result\", data, ...extras };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"analytics.js","names":[],"sources":["../../../../../shared/src/sse/analytics.ts"],"sourcesContent":["import { z } from \"zod\";\n\nimport type { MetricViewColumnDisplay } from \"../metric-metadata\";\n\n/**\n * Wire protocol for analytics SSE messages emitted by `/api/analytics/query`.\n *\n * The SSE channel carries only the JSON_ARRAY path (warehouse-readiness\n * events + a `result` message of rows). ARROW_STREAM does NOT use SSE —\n * the server streams the raw Arrow IPC bytes back on the query response body\n * (`_handleArrowStreamQuery`) and the client reads them directly\n * (`fetchArrowDirect`), so there is no `arrow` message type here.\n *\n * These schemas are the single source of truth for the JSON contract between\n * the server (`AnalyticsPlugin._handleQueryRoute`) and the client\n * (`useAnalyticsQuery`). Both sides validate with the same schema:\n *\n * - Server uses the typed builder (`makeResultMessage`) to construct messages\n * with compile-time guarantees that all required fields are present.\n * - Client calls `AnalyticsSseMessage.safeParse(JSON.parse(event.data))` to\n * fail loudly on a malformed payload instead of silently treating an\n * undefined field as data.\n */\n\n/** Successful row-shaped result (JSON_ARRAY format, or empty results). */\nexport const AnalyticsResultMessage = z.object({\n type: z.literal(\"result\"),\n // `data` is intentionally `z.array(z.unknown())` rather than a deep\n // row schema. Validating every row's keys for shape costs O(rows × cols)\n // CPU and main-thread blocking time on the *client* (the schema is\n // also reused for `safeParse` in `useAnalyticsQuery`); for large JSON\n // results that pushes hundreds of ms to seconds of TBT into the\n // render pipeline. The server constructs `data` via the typed\n // `makeResultMessage` builder, so the per-row shape is enforced at\n // the source, not at validation time. The TS-level interface below\n // narrows `data` to `Record<string, unknown>[]` for callers.\n data: z.array(z.unknown()).optional(),\n // Status is opaque metadata forwarded from the warehouse — keep it as\n // `unknown` so we don't bake the SDK's detailed shape into the contract.\n status: z.unknown().optional(),\n statement_id: z.string().optional(),\n // Per-column display metadata for a metric-view result; absent for plain\n // `/query` results. Kept loose for the same reason as `data` above.\n metadata: z.record(z.string(), z.unknown()).optional(),\n});\n\n/**\n * TS-level shape of a successful row-shaped result message.\n *\n * **Kept in sync by hand** with `AnalyticsResultMessage` above. The Zod\n * schema is intentionally loose (`z.array(z.unknown())` for `data`,\n * `z.record(z.string(), z.unknown())` for `metadata`) to keep client\n * validation cheap; this interface narrows `data` to\n * `Record<string, unknown>[]` and `metadata` to\n * `Record<string, MetricViewColumnDisplay>` so consumers don't have to cast\n * at every call site. If you add a field to the Zod schema, add it here too.\n */\nexport interface AnalyticsResultMessage {\n type: \"result\";\n data?: Record<string, unknown>[];\n status?: unknown;\n statement_id?: string;\n metadata?: Record<string, MetricViewColumnDisplay>;\n}\n\n/**\n * Every message the analytics SSE stream may emit. Currently only the\n * row-shaped `result` message (JSON_ARRAY path); `warehouse_status` and\n * `error` events are handled off-schema by the client. ARROW_STREAM never\n * uses SSE.\n */\nexport const AnalyticsSseMessage = AnalyticsResultMessage;\nexport type AnalyticsSseMessage = z.infer<typeof AnalyticsSseMessage>;\n\n// ────────────────────────────────────────────────────────────────────────────\n// Typed builder — call from the server route handler. The compiler enforces\n// that every required field is supplied, and the return type narrows so\n// downstream code (executeStream / SSE writer) keeps full type information.\n// ────────────────────────────────────────────────────────────────────────────\n\nexport function makeResultMessage(\n data: Record<string, unknown>[] | undefined,\n extras: {\n status?: unknown;\n statement_id?: string;\n metadata?: Record<string, MetricViewColumnDisplay>;\n } = {},\n): AnalyticsResultMessage {\n return { type: \"result\", data, ...extras };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AAyBA,MAAa,yBAAyB,EAAE,OAAO;CAC7C,MAAM,EAAE,QAAQ,SAAS;CAUzB,MAAM,EAAE,MAAM,EAAE,SAAS,CAAC,CAAC,UAAU;CAGrC,QAAQ,EAAE,SAAS,CAAC,UAAU;CAC9B,cAAc,EAAE,QAAQ,CAAC,UAAU;CAGnC,UAAU,EAAE,OAAO,EAAE,QAAQ,EAAE,EAAE,SAAS,CAAC,CAAC,UAAU;CACvD,CAAC;AAoCF,SAAgB,kBACd,MACA,SAII,EAAE,EACkB;AACxB,QAAO;EAAE,MAAM;EAAU;EAAM,GAAG;EAAQ"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"legacy.js","names":[],"sources":["../../../../../shared/src/workspace-client/legacy.ts"],"sourcesContent":["/**\n * The single module in AppKit allowed to import `@databricks/sdk-experimental`\n * directly (enforced by the
|
|
1
|
+
{"version":3,"file":"legacy.js","names":[],"sources":["../../../../../shared/src/workspace-client/legacy.ts"],"sourcesContent":["/**\n * The single module in AppKit allowed to import `@databricks/sdk-experimental`\n * directly (enforced by the oxlint `no-restricted-imports` boundary rule). Every\n * other AppKit module reaches the SDK through the wrapper's re-exports and the\n * {@link WorkspaceClient} facade.\n *\n * Isolating the SDK here is what makes the incremental migration to the modular\n * Databricks SDK a localized change: to migrate a service, swap its getter in\n * `client.ts` from the legacy delegate to the modular client — nothing else in\n * the codebase imports the SDK, so the blast radius is one connector + its test.\n */\n\nimport type {\n ClientOptions,\n WorkspaceClient as SdkWorkspaceClient,\n} from \"@databricks/sdk-experimental\";\nimport * as SDK from \"@databricks/sdk-experimental\";\n\nconst { WorkspaceClient: SdkWorkspaceClientCtor } = SDK;\n\n/** The concrete legacy SDK client type. */\nexport type LegacyWorkspaceClient = SdkWorkspaceClient;\n\n/**\n * Options used to construct the wrapper. Mirrors the subset of the old SDK's\n * `Config` + `ClientOptions` that AppKit relies on today; we deliberately do\n * NOT re-expose every old-SDK config knob.\n */\nexport interface WorkspaceClientOptions {\n /** Databricks host, e.g. https://my-workspace.cloud.databricks.com. Defaults to DATABRICKS_HOST / profile resolution. */\n host?: string;\n /** `~/.databrickscfg` profile name. Used when no host/token is provided. */\n profile?: string;\n /** Bearer token. When set, `authType` defaults to \"pat\". */\n token?: string;\n /** Authentication strategy passed to the legacy client. */\n authType?: \"pat\";\n /**\n * SDK client options (product / productVersion / userAgentExtra) used to\n * stamp the outbound User-Agent. Produced by `getClientOptions()`; omitted\n * by build-time callers that don't stamp a User-Agent.\n */\n clientOptions?: ClientOptions;\n}\n\n/**\n * Construct a legacy `WorkspaceClient` from wrapper options.\n *\n * Centralised so the wrapper facade, the `.toLegacyWorkspaceClient()` escape\n * hatch, and any per-request OBO client all build it the same way.\n */\nexport function buildLegacyWorkspaceClient(\n opts: WorkspaceClientOptions,\n): LegacyWorkspaceClient {\n // Check `token !== undefined`, NOT truthiness: an explicitly-passed token\n // must stick to the PAT path even when it's an empty string. Falling through\n // to the default-auth branch on an empty OBO token would silently\n // authenticate as the service principal instead of failing — a privilege\n // escalation in the OBO path. An invalid/empty token should blow up loudly.\n const cfg =\n opts.token !== undefined\n ? { host: opts.host, token: opts.token, authType: opts.authType ?? \"pat\" }\n : opts.host\n ? { host: opts.host }\n : opts.profile\n ? { profile: opts.profile }\n : {};\n return new SdkWorkspaceClientCtor(cfg, opts.clientOptions);\n}\n\n// ── SDK type re-exports ──────────────────────────────────────────────\nexport type {\n CancellationToken,\n ClientOptions,\n} from \"@databricks/sdk-experimental\";\n// ── SDK value re-exports ─────────────────────────────────────────────\n//\n// AppKit modules import these from the wrapper instead of the SDK so the\n// boundary rule holds. `Context` bridges AbortSignal → CancellationToken\n// (serving/jobs/sql-warehouse); `Time`/`TimeUnits` drive genie polling;\n// `ConfigError` is matched in service-context's auth-failure handling.\n//\n// These are sourced off the namespace import rather than `export { ... } from`\n// because the SDK is CommonJS: its `Time` export is emitted as a getter that\n// calls `__importDefault(...)`, which defeats Node's static named-export\n// detection — a direct `export { Time }` throws \"does not provide an export\n// named 'Time'\" at ESM link time. `Time` is only reachable via the module\n// object, so we fall back to `SDK.default.Time` (matching the original genie\n// connector's `SDK.Time ?? SDK.default.Time` guard).\nexport const { ConfigError, Context, TimeUnits, loadConfigFile } = SDK;\nexport const Time =\n SDK.Time ?? (SDK as unknown as { default: typeof SDK }).default.Time;\n\n// Deep-import types used by the genie connector's waiter idiom. Not exposed\n// on the SDK's top-level index, so re-exported here to keep the genie\n// connector off a direct `@databricks/sdk-experimental/dist/**` import.\nexport type { GenieMessage } from \"@databricks/sdk-experimental/dist/apis/dashboards\";\nexport type { Waiter } from \"@databricks/sdk-experimental/dist/wait\";\n"],"mappings":";;;AAkBA,MAAM,EAAE,iBAAiB,2BAA2B;;;;;;;AAiCpD,SAAgB,2BACd,MACuB;AAcvB,QAAO,IAAI,uBAPT,KAAK,UAAU,SACX;EAAE,MAAM,KAAK;EAAM,OAAO,KAAK;EAAO,UAAU,KAAK,YAAY;EAAO,GACxE,KAAK,OACH,EAAE,MAAM,KAAK,MAAM,GACnB,KAAK,UACH,EAAE,SAAS,KAAK,SAAS,GACzB,EAAE,EAC2B,KAAK,cAAc;;AAsB5D,MAAa,EAAE,aAAa,SAAS,WAAW,mBAAmB;AACnE,MAAa,OACX,IAAI,QAAS,IAA2C,QAAQ"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","names":[],"sources":["../../../../../shared/src/workspace-client/types.ts"],"mappings":";;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"types.d.ts","names":[],"sources":["../../../../../shared/src/workspace-client/types.ts"],"mappings":";;;;;;;;;;;;UA6BiB,iBAAA;EAWA;EAAA,SATN,KAAA,EAAO,qBAAA;EAYa;EAAA,SATpB,UAAA,EAAY,qBAAA;EAYM;EAAA,SATlB,KAAA,EAAO,qBAAA;EAYM;EAAA,SATb,IAAA,EAAM,qBAAA;EAgBE;EAAA,SAbR,kBAAA,EAAoB,qBAAA;EAoBT;EAAA,SAjBX,gBAAA,EAAkB,qBAAA;EAwBA;EAAA,SArBlB,WAAA,EAAa,qBAAA;EAqB0B;;;;;EAAA,SAdvC,MAAA,EAAQ,qBAAA;;;;;;WAOR,SAAA,EAAW,qBAAA;;;;;;EAOpB,uBAAA,IAA2B,qBAAA;AAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sse-writer.js","names":[],"sources":["../../src/stream/sse-writer.ts"],"sourcesContent":["import type { IAppResponse } from \"shared\";\nimport { streamDefaults } from \"./defaults\";\nimport {\n type BufferedEvent,\n type SSEError,\n SSEErrorCode,\n SSEWarningCode,\n} from \"./types\";\nimport { StreamValidator } from \"./validator\";\n\nexport class SSEWriter {\n // setup SSE headers\n setupHeaders(res: IAppResponse): void {\n res.setHeader(\"Content-Type\", \"text/event-stream; charset=utf-8\");\n res.setHeader(\"Cache-Control\", \"no-cache, no-transform\");\n // X-Accel-Buffering: no — disables nginx-style proxy response buffering\n // for SSE (used by Cloudflare, AWS, GCP, and most corporate proxies).\n res.setHeader(\"X-Accel-Buffering\", \"no\");\n // Intentionally NOT setting:\n // - Connection: keep-alive (HTTP/2 forbids it; Node manages keep-alive)\n // - Content-Encoding: none (invalid value; can trigger 502/RST in\n // strict intermediaries)\n res.flushHeaders?.();\n }\n\n // write a single event to the response\n writeEvent(res: IAppResponse, eventId: string, event: any): void {\n if (res.writableEnded) return;\n\n const eventType = StreamValidator.sanitizeEventType(event.type);\n const eventData = JSON.stringify(event);\n\n res.write(`id: ${eventId}\\n`);\n res.write(`event: ${eventType}\\n`);\n res.write(`data: ${eventData}\\n\\n`);\n }\n writeError(\n res: IAppResponse,\n eventId: string,\n error: string,\n code: SSEErrorCode = SSEErrorCode.INTERNAL_ERROR,\n errorCode?: string,\n ): void {\n if (res.writableEnded) return;\n\n const errorData: SSEError = {\n error,\n code,\n ...(errorCode ? { errorCode } : {}),\n };\n\n res.write(`id: ${eventId}\\n`);\n res.write(`event: error\\n`);\n res.write(`data: ${JSON.stringify(errorData)}\\n\\n`);\n }\n\n // write a buffered event for replay\n writeBufferedEvent(res: IAppResponse, event: BufferedEvent): void {\n if (res.writableEnded) return;\n\n res.write(`id: ${event.id}\\n`);\n res.write(`event: ${event.type}\\n`);\n res.write(`data: ${event.data}\\n\\n`);\n }\n\n // write a buffer overflow warning\n writeBufferOverflowWarning(res: IAppResponse, lastEventId: string): void {\n if (res.writableEnded) return;\n\n try {\n res.write(`event: warning\\n`);\n res.write(\n `data: ${JSON.stringify({\n warning: \"Buffer overflow detected - some events were lost\",\n code: SSEWarningCode.BUFFER_OVERFLOW_RESTART,\n lastEventId,\n })}\\n\\n`,\n );\n } catch (_error) {\n // ignore write errors - client will ignore this event\n }\n }\n\n // start the heartbeat interval\n startHeartbeat(\n res: IAppResponse,\n signal: AbortSignal,\n interval?: number,\n ): NodeJS.Timeout {\n const heartbeatInterval = interval ?? streamDefaults.heartbeatInterval;\n\n return setInterval(() => {\n if (!signal.aborted && !res.writableEnded) {\n try {\n res.write(`: heartbeat\\n\\n`);\n } catch (_error) {\n // ignore write errors - client will ignore this event\n }\n }\n }, heartbeatInterval);\n }\n}\n"],"mappings":";;;;;
|
|
1
|
+
{"version":3,"file":"sse-writer.js","names":[],"sources":["../../src/stream/sse-writer.ts"],"sourcesContent":["import type { IAppResponse } from \"shared\";\n\nimport { streamDefaults } from \"./defaults\";\nimport {\n type BufferedEvent,\n type SSEError,\n SSEErrorCode,\n SSEWarningCode,\n} from \"./types\";\nimport { StreamValidator } from \"./validator\";\n\nexport class SSEWriter {\n // setup SSE headers\n setupHeaders(res: IAppResponse): void {\n res.setHeader(\"Content-Type\", \"text/event-stream; charset=utf-8\");\n res.setHeader(\"Cache-Control\", \"no-cache, no-transform\");\n // X-Accel-Buffering: no — disables nginx-style proxy response buffering\n // for SSE (used by Cloudflare, AWS, GCP, and most corporate proxies).\n res.setHeader(\"X-Accel-Buffering\", \"no\");\n // Intentionally NOT setting:\n // - Connection: keep-alive (HTTP/2 forbids it; Node manages keep-alive)\n // - Content-Encoding: none (invalid value; can trigger 502/RST in\n // strict intermediaries)\n res.flushHeaders?.();\n }\n\n // write a single event to the response\n writeEvent(res: IAppResponse, eventId: string, event: any): void {\n if (res.writableEnded) return;\n\n const eventType = StreamValidator.sanitizeEventType(event.type);\n const eventData = JSON.stringify(event);\n\n res.write(`id: ${eventId}\\n`);\n res.write(`event: ${eventType}\\n`);\n res.write(`data: ${eventData}\\n\\n`);\n }\n writeError(\n res: IAppResponse,\n eventId: string,\n error: string,\n code: SSEErrorCode = SSEErrorCode.INTERNAL_ERROR,\n errorCode?: string,\n ): void {\n if (res.writableEnded) return;\n\n const errorData: SSEError = {\n error,\n code,\n ...(errorCode ? { errorCode } : {}),\n };\n\n res.write(`id: ${eventId}\\n`);\n res.write(`event: error\\n`);\n res.write(`data: ${JSON.stringify(errorData)}\\n\\n`);\n }\n\n // write a buffered event for replay\n writeBufferedEvent(res: IAppResponse, event: BufferedEvent): void {\n if (res.writableEnded) return;\n\n res.write(`id: ${event.id}\\n`);\n res.write(`event: ${event.type}\\n`);\n res.write(`data: ${event.data}\\n\\n`);\n }\n\n // write a buffer overflow warning\n writeBufferOverflowWarning(res: IAppResponse, lastEventId: string): void {\n if (res.writableEnded) return;\n\n try {\n res.write(`event: warning\\n`);\n res.write(\n `data: ${JSON.stringify({\n warning: \"Buffer overflow detected - some events were lost\",\n code: SSEWarningCode.BUFFER_OVERFLOW_RESTART,\n lastEventId,\n })}\\n\\n`,\n );\n } catch (_error) {\n // ignore write errors - client will ignore this event\n }\n }\n\n // start the heartbeat interval\n startHeartbeat(\n res: IAppResponse,\n signal: AbortSignal,\n interval?: number,\n ): NodeJS.Timeout {\n const heartbeatInterval = interval ?? streamDefaults.heartbeatInterval;\n\n return setInterval(() => {\n if (!signal.aborted && !res.writableEnded) {\n try {\n res.write(`: heartbeat\\n\\n`);\n } catch (_error) {\n // ignore write errors - client will ignore this event\n }\n }\n }, heartbeatInterval);\n }\n}\n"],"mappings":";;;;;AAWA,IAAa,YAAb,MAAuB;CAErB,aAAa,KAAyB;AACpC,MAAI,UAAU,gBAAgB,mCAAmC;AACjE,MAAI,UAAU,iBAAiB,yBAAyB;AAGxD,MAAI,UAAU,qBAAqB,KAAK;AAKxC,MAAI,gBAAgB;;CAItB,WAAW,KAAmB,SAAiB,OAAkB;AAC/D,MAAI,IAAI,cAAe;EAEvB,MAAM,YAAY,gBAAgB,kBAAkB,MAAM,KAAK;EAC/D,MAAM,YAAY,KAAK,UAAU,MAAM;AAEvC,MAAI,MAAM,OAAO,QAAQ,IAAI;AAC7B,MAAI,MAAM,UAAU,UAAU,IAAI;AAClC,MAAI,MAAM,SAAS,UAAU,MAAM;;CAErC,WACE,KACA,SACA,OACA,OAAqB,aAAa,gBAClC,WACM;AACN,MAAI,IAAI,cAAe;EAEvB,MAAM,YAAsB;GAC1B;GACA;GACA,GAAI,YAAY,EAAE,WAAW,GAAG,EAAE;GACnC;AAED,MAAI,MAAM,OAAO,QAAQ,IAAI;AAC7B,MAAI,MAAM,iBAAiB;AAC3B,MAAI,MAAM,SAAS,KAAK,UAAU,UAAU,CAAC,MAAM;;CAIrD,mBAAmB,KAAmB,OAA4B;AAChE,MAAI,IAAI,cAAe;AAEvB,MAAI,MAAM,OAAO,MAAM,GAAG,IAAI;AAC9B,MAAI,MAAM,UAAU,MAAM,KAAK,IAAI;AACnC,MAAI,MAAM,SAAS,MAAM,KAAK,MAAM;;CAItC,2BAA2B,KAAmB,aAA2B;AACvE,MAAI,IAAI,cAAe;AAEvB,MAAI;AACF,OAAI,MAAM,mBAAmB;AAC7B,OAAI,MACF,SAAS,KAAK,UAAU;IACtB,SAAS;IACT,MAAM,eAAe;IACrB;IACD,CAAC,CAAC,MACJ;WACM,QAAQ;;CAMnB,eACE,KACA,QACA,UACgB;EAChB,MAAM,oBAAoB,YAAY,eAAe;AAErD,SAAO,kBAAkB;AACvB,OAAI,CAAC,OAAO,WAAW,CAAC,IAAI,cAC1B,KAAI;AACF,QAAI,MAAM,kBAAkB;YACrB,QAAQ;KAIlB,kBAAkB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stream-manager.d.ts","names":[],"sources":["../../src/stream/stream-manager.ts"],"mappings":";;;;;
|
|
1
|
+
{"version":3,"file":"stream-manager.d.ts","names":[],"sources":["../../src/stream/stream-manager.ts"],"mappings":";;;;;cAmBa,aAAA;EAAA,QACH,gBAAA;EAAA,QACA,cAAA;EAAA,QACA,SAAA;EAAA,QACA,YAAA;EAAA,QACA,SAAA;EAAA,QACA,iBAAA;cAEI,OAAA,GAAU,YAAA;EAahB,MAAA,CACJ,GAAA,EAAK,YAAA,EACL,OAAA,GAAU,MAAA,EAAQ,WAAA,KAAgB,cAAA,sBAClC,OAAA,GAAU,YAAA,EACV,QAAA,YACC,OAAA;EAsCH,QAAA,CAAA;EAaA,cAAA,CAAA;EAAA,QAKc,uBAAA;EAAA,QA+EA,gBAAA;EAAA,QAiFA,6BAAA;EAAA,QAwGN,eAAA;EAAA,QA6BA,yBAAA;EAAA,QAaA,wBAAA;EAAA,QAwBA,eAAA;EAAA,QAYA,gBAAA;EAAA,QAUA,mBAAA;EAAA,QAuBA,wBAAA;EAAA,QA8BA,gBAAA;AAAA"}
|