@databricks/appkit 0.36.0 → 0.38.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.
Files changed (160) hide show
  1. package/CLAUDE.md +3 -2
  2. package/NOTICE.md +1 -0
  3. package/dist/appkit/package.js +1 -1
  4. package/dist/cache/index.js +1 -2
  5. package/dist/cache/index.js.map +1 -1
  6. package/dist/cache/storage/persistent.js +1 -2
  7. package/dist/cache/storage/persistent.js.map +1 -1
  8. package/dist/cli/commands/plugin/add-resource/add-resource.js.map +1 -1
  9. package/dist/cli/commands/plugin/create/resource-defaults.js +2 -1
  10. package/dist/cli/commands/plugin/create/resource-defaults.js.map +1 -1
  11. package/dist/cli/commands/plugin/schema-resources.js +34 -51
  12. package/dist/cli/commands/plugin/schema-resources.js.map +1 -1
  13. package/dist/cli/commands/plugin/sync/sync.js +20 -6
  14. package/dist/cli/commands/plugin/sync/sync.js.map +1 -1
  15. package/dist/cli/commands/plugin/validate/validate-manifest.js +71 -157
  16. package/dist/cli/commands/plugin/validate/validate-manifest.js.map +1 -1
  17. package/dist/cli/commands/plugin/validate/validate.js +2 -2
  18. package/dist/cli/commands/plugin/validate/validate.js.map +1 -1
  19. package/dist/cli/commands/setup.js +2 -2
  20. package/dist/cli/commands/setup.js.map +1 -1
  21. package/dist/connectors/index.js +0 -1
  22. package/dist/connectors/jobs/client.js +1 -2
  23. package/dist/connectors/jobs/client.js.map +1 -1
  24. package/dist/connectors/lakebase/routing-pool.js +1 -2
  25. package/dist/connectors/lakebase/routing-pool.js.map +1 -1
  26. package/dist/connectors/sql-warehouse/client.js +1 -2
  27. package/dist/connectors/sql-warehouse/client.js.map +1 -1
  28. package/dist/context/execution-context.js +9 -13
  29. package/dist/context/execution-context.js.map +1 -1
  30. package/dist/context/index.js +3 -13
  31. package/dist/context/service-context.js +137 -136
  32. package/dist/context/service-context.js.map +1 -1
  33. package/dist/context/user-context.js +1 -5
  34. package/dist/context/user-context.js.map +1 -1
  35. package/dist/core/agent/create-agent.js +1 -2
  36. package/dist/core/agent/create-agent.js.map +1 -1
  37. package/dist/core/appkit.d.ts.map +1 -1
  38. package/dist/core/appkit.js +9 -37
  39. package/dist/core/appkit.js.map +1 -1
  40. package/dist/errors/authentication.js +44 -40
  41. package/dist/errors/authentication.js.map +1 -1
  42. package/dist/errors/base.js +86 -70
  43. package/dist/errors/base.js.map +1 -1
  44. package/dist/errors/configuration.js +70 -66
  45. package/dist/errors/configuration.js.map +1 -1
  46. package/dist/errors/connection.js +50 -46
  47. package/dist/errors/connection.js.map +1 -1
  48. package/dist/errors/execution.js +47 -43
  49. package/dist/errors/execution.js.map +1 -1
  50. package/dist/errors/index.js +10 -27
  51. package/dist/errors/initialization.js +38 -34
  52. package/dist/errors/initialization.js.map +1 -1
  53. package/dist/errors/server.js +34 -31
  54. package/dist/errors/server.js.map +1 -1
  55. package/dist/errors/tunnel.js +47 -43
  56. package/dist/errors/tunnel.js.map +1 -1
  57. package/dist/errors/validation.js +41 -37
  58. package/dist/errors/validation.js.map +1 -1
  59. package/dist/index.d.ts +1 -1
  60. package/dist/index.js +3 -9
  61. package/dist/plugin/dev-reader.js +1 -2
  62. package/dist/plugin/dev-reader.js.map +1 -1
  63. package/dist/plugin/interceptors/retry.js +1 -2
  64. package/dist/plugin/interceptors/retry.js.map +1 -1
  65. package/dist/plugin/interceptors/telemetry.js +1 -2
  66. package/dist/plugin/interceptors/telemetry.js.map +1 -1
  67. package/dist/plugin/plugin.d.ts +12 -4
  68. package/dist/plugin/plugin.d.ts.map +1 -1
  69. package/dist/plugin/plugin.js +59 -28
  70. package/dist/plugin/plugin.js.map +1 -1
  71. package/dist/plugins/agents/agents.d.ts +56 -3
  72. package/dist/plugins/agents/agents.d.ts.map +1 -1
  73. package/dist/plugins/agents/agents.js +160 -8
  74. package/dist/plugins/agents/agents.js.map +1 -1
  75. package/dist/plugins/agents/schemas.js +0 -1
  76. package/dist/plugins/agents/schemas.js.map +1 -1
  77. package/dist/plugins/analytics/analytics.js +1 -2
  78. package/dist/plugins/analytics/analytics.js.map +1 -1
  79. package/dist/plugins/analytics/manifest.js +9 -1
  80. package/dist/plugins/analytics/query.js +2 -4
  81. package/dist/plugins/analytics/query.js.map +1 -1
  82. package/dist/plugins/files/manifest.js +7 -1
  83. package/dist/plugins/files/plugin.js +3 -6
  84. package/dist/plugins/files/plugin.js.map +1 -1
  85. package/dist/plugins/genie/genie.js +1 -2
  86. package/dist/plugins/genie/genie.js.map +1 -1
  87. package/dist/plugins/genie/manifest.js +7 -1
  88. package/dist/plugins/jobs/plugin.js +2 -4
  89. package/dist/plugins/jobs/plugin.js.map +1 -1
  90. package/dist/plugins/lakebase/lakebase.js +1 -2
  91. package/dist/plugins/lakebase/lakebase.js.map +1 -1
  92. package/dist/plugins/lakebase/manifest.js +26 -4
  93. package/dist/plugins/server/index.js +1 -2
  94. package/dist/plugins/server/index.js.map +1 -1
  95. package/dist/plugins/server/vite-dev-server.js +1 -2
  96. package/dist/plugins/server/vite-dev-server.js.map +1 -1
  97. package/dist/plugins/serving/serving.js +1 -2
  98. package/dist/plugins/serving/serving.js.map +1 -1
  99. package/dist/registry/index.d.ts +1 -1
  100. package/dist/registry/manifest-loader.d.ts +4 -4
  101. package/dist/registry/manifest-loader.d.ts.map +1 -1
  102. package/dist/registry/manifest-loader.js +1 -2
  103. package/dist/registry/manifest-loader.js.map +1 -1
  104. package/dist/registry/resource-registry.js +1 -2
  105. package/dist/registry/resource-registry.js.map +1 -1
  106. package/dist/registry/types.d.ts +21 -7
  107. package/dist/registry/types.d.ts.map +1 -1
  108. package/dist/registry/types.generated.d.ts +1 -1
  109. package/dist/registry/types.generated.js +1 -1
  110. package/dist/registry/types.generated.js.map +1 -1
  111. package/dist/registry/types.js +3 -3
  112. package/dist/registry/types.js.map +1 -1
  113. package/dist/schemas/manifest.d.ts +1139 -0
  114. package/dist/schemas/manifest.d.ts.map +1 -0
  115. package/dist/schemas/manifest.js +524 -0
  116. package/dist/schemas/manifest.js.map +1 -0
  117. package/dist/shared/src/index.d.ts +1 -1
  118. package/dist/shared/src/plugin.d.ts +38 -7
  119. package/dist/shared/src/plugin.d.ts.map +1 -1
  120. package/dist/shared/src/schemas/manifest.d.ts +1110 -0
  121. package/dist/shared/src/schemas/manifest.d.ts.map +1 -0
  122. package/dist/stream/arrow-stream-processor.js +1 -2
  123. package/dist/stream/arrow-stream-processor.js.map +1 -1
  124. package/dist/stream/buffers.js +1 -2
  125. package/dist/stream/buffers.js.map +1 -1
  126. package/docs/api/appkit/Enumeration.ResourceType.md +1 -1
  127. package/docs/api/appkit/Interface.PluginManifest.md +57 -3
  128. package/docs/api/appkit/Interface.ResourceEntry.md +6 -4
  129. package/docs/api/appkit/Interface.ResourceRequirement.md +7 -61
  130. package/docs/api/appkit/TypeAlias.ResourceFieldEntry.md +6 -0
  131. package/docs/api/appkit/Variable.agents.md +1 -1
  132. package/docs/api/appkit.md +12 -12
  133. package/docs/app-management.md +1 -1
  134. package/docs/development/ai-assisted-development.md +2 -2
  135. package/docs/development/local-development.md +1 -1
  136. package/docs/development/remote-bridge.md +1 -1
  137. package/docs/development/templates.md +118 -12
  138. package/docs/development.md +1 -1
  139. package/docs/plugins/agents.md +8 -4
  140. package/docs/plugins/custom-plugins.md +33 -23
  141. package/docs/plugins/lakebase.md +1 -1
  142. package/docs/plugins/manifest.md +293 -0
  143. package/docs.md +2 -2
  144. package/llms.txt +3 -2
  145. package/package.json +3 -3
  146. package/sbom.cdx.json +1 -1
  147. package/dist/_virtual/_rolldown/runtime.js +0 -7
  148. package/dist/connectors/lakebase-v1/client.js +0 -15
  149. package/dist/connectors/lakebase-v1/client.js.map +0 -1
  150. package/dist/connectors/lakebase-v1/index.js +0 -3
  151. package/dist/context/index.js.map +0 -1
  152. package/dist/errors/index.js.map +0 -1
  153. package/dist/index.js.map +0 -1
  154. package/dist/schemas/plugin-manifest.generated.d.ts +0 -182
  155. package/dist/schemas/plugin-manifest.generated.d.ts.map +0 -1
  156. package/dist/schemas/plugin-manifest.schema.json +0 -489
  157. package/dist/schemas/template-plugins.schema.json +0 -113
  158. package/dist/shared/src/schemas/plugin-manifest.generated.d.ts +0 -182
  159. package/dist/shared/src/schemas/plugin-manifest.generated.d.ts.map +0 -1
  160. package/docs/api/appkit/Interface.ResourceFieldEntry.md +0 -82
@@ -1,8 +1,7 @@
1
- import { __esmMin } from "../_virtual/_rolldown/runtime.js";
2
1
  import { AuthenticationError } from "../errors/authentication.js";
3
2
  import { ConfigurationError } from "../errors/configuration.js";
4
3
  import { InitializationError } from "../errors/initialization.js";
5
- import { init_errors } from "../errors/index.js";
4
+ import "../errors/index.js";
6
5
  import { name, version } from "../appkit/package.js";
7
6
  import { createHash } from "node:crypto";
8
7
  import { ConfigError, WorkspaceClient } from "@databricks/sdk-experimental";
@@ -17,149 +16,151 @@ function getClientOptions() {
17
16
  ...isDev && { userAgentExtra: { mode: "dev" } }
18
17
  };
19
18
  }
20
- var ServiceContext;
21
- var init_service_context = __esmMin((() => {
22
- init_errors();
23
- ServiceContext = class ServiceContext {
24
- static instance = null;
25
- static initPromise = null;
26
- /**
27
- * Initialize the service context. Should be called once at app startup.
28
- * Safe to call multiple times - will return the same instance.
29
- *
30
- * @param options - Which shared resources to resolve (derived from plugin manifests).
31
- * @param client - Optional pre-configured WorkspaceClient to use instead
32
- * of creating one from environment credentials.
33
- */
34
- static async initialize(options, client) {
35
- if (ServiceContext.instance) return ServiceContext.instance;
36
- if (ServiceContext.initPromise) return ServiceContext.initPromise;
37
- ServiceContext.initPromise = ServiceContext.createContext(options, client);
38
- ServiceContext.instance = await ServiceContext.initPromise;
39
- return ServiceContext.instance;
40
- }
41
- /**
42
- * Get the initialized service context.
43
- * @throws Error if not initialized
44
- */
45
- static get() {
46
- if (!ServiceContext.instance) throw InitializationError.notInitialized("ServiceContext", "Call ServiceContext.initialize() first");
47
- return ServiceContext.instance;
48
- }
49
- /**
50
- * Check if the service context has been initialized.
51
- */
52
- static isInitialized() {
53
- return ServiceContext.instance !== null;
54
- }
55
- /**
56
- * Create a user context from request headers.
57
- *
58
- * @param token - The user's access token from x-forwarded-access-token header
59
- * @param userId - The user's ID from x-forwarded-user header
60
- * @param userName - Optional user name
61
- * @throws Error if token is not provided
62
- */
63
- static createUserContext(token, userId, userName, userEmail) {
64
- if (!token) throw AuthenticationError.missingToken("user token");
65
- const host = process.env.DATABRICKS_HOST;
66
- if (!host) throw ConfigurationError.missingEnvVar("DATABRICKS_HOST");
67
- const serviceCtx = ServiceContext.get();
19
+ /**
20
+ * ServiceContext is a singleton that manages the service principal's
21
+ * WorkspaceClient and shared resources like warehouse/workspace IDs.
22
+ *
23
+ * It's initialized once at app startup and provides the foundation
24
+ * for both service principal and user context execution.
25
+ */
26
+ var ServiceContext = class ServiceContext {
27
+ static instance = null;
28
+ static initPromise = null;
29
+ /**
30
+ * Initialize the service context. Should be called once at app startup.
31
+ * Safe to call multiple times - will return the same instance.
32
+ *
33
+ * @param options - Which shared resources to resolve (derived from plugin manifests).
34
+ * @param client - Optional pre-configured WorkspaceClient to use instead
35
+ * of creating one from environment credentials.
36
+ */
37
+ static async initialize(options, client) {
38
+ if (ServiceContext.instance) return ServiceContext.instance;
39
+ if (ServiceContext.initPromise) return ServiceContext.initPromise;
40
+ ServiceContext.initPromise = ServiceContext.createContext(options, client);
41
+ ServiceContext.instance = await ServiceContext.initPromise;
42
+ return ServiceContext.instance;
43
+ }
44
+ /**
45
+ * Get the initialized service context.
46
+ * @throws Error if not initialized
47
+ */
48
+ static get() {
49
+ if (!ServiceContext.instance) throw InitializationError.notInitialized("ServiceContext", "Call ServiceContext.initialize() first");
50
+ return ServiceContext.instance;
51
+ }
52
+ /**
53
+ * Check if the service context has been initialized.
54
+ */
55
+ static isInitialized() {
56
+ return ServiceContext.instance !== null;
57
+ }
58
+ /**
59
+ * Create a user context from request headers.
60
+ *
61
+ * @param token - The user's access token from x-forwarded-access-token header
62
+ * @param userId - The user's ID from x-forwarded-user header
63
+ * @param userName - Optional user name
64
+ * @throws Error if token is not provided
65
+ */
66
+ static createUserContext(token, userId, userName, userEmail) {
67
+ if (!token) throw AuthenticationError.missingToken("user token");
68
+ const host = process.env.DATABRICKS_HOST;
69
+ if (!host) throw ConfigurationError.missingEnvVar("DATABRICKS_HOST");
70
+ const serviceCtx = ServiceContext.get();
71
+ return {
72
+ client: new WorkspaceClient({
73
+ token,
74
+ host,
75
+ authType: "pat"
76
+ }, getClientOptions()),
77
+ userId,
78
+ userName,
79
+ userEmail,
80
+ tokenFingerprint: createHash("sha256").update(token).digest("hex").slice(0, 16),
81
+ warehouseId: serviceCtx.warehouseId,
82
+ workspaceId: serviceCtx.workspaceId,
83
+ isUserContext: true
84
+ };
85
+ }
86
+ /**
87
+ * Get the client options for WorkspaceClient.
88
+ * Exposed for testing purposes.
89
+ */
90
+ static getClientOptions() {
91
+ return getClientOptions();
92
+ }
93
+ static async createContext(options, client) {
94
+ try {
95
+ const wsClient = client ?? new WorkspaceClient({}, getClientOptions());
96
+ const [resolvedWorkspaceId, currentUser, resolvedWarehouseId] = await Promise.all([
97
+ ServiceContext.getWorkspaceId(wsClient),
98
+ wsClient.currentUser.me(),
99
+ options?.warehouseId ? ServiceContext.getWarehouseId(wsClient) : Promise.resolve(void 0)
100
+ ]);
101
+ if (!currentUser.id) throw ConfigurationError.resourceNotFound("Service user ID");
102
+ const warehouseId = options?.warehouseId && resolvedWarehouseId !== void 0 ? Promise.resolve(resolvedWarehouseId) : void 0;
68
103
  return {
69
- client: new WorkspaceClient({
70
- token,
71
- host,
72
- authType: "pat"
73
- }, getClientOptions()),
74
- userId,
75
- userName,
76
- userEmail,
77
- tokenFingerprint: createHash("sha256").update(token).digest("hex").slice(0, 16),
78
- warehouseId: serviceCtx.warehouseId,
79
- workspaceId: serviceCtx.workspaceId,
80
- isUserContext: true
104
+ client: wsClient,
105
+ serviceUserId: currentUser.id,
106
+ warehouseId,
107
+ workspaceId: Promise.resolve(resolvedWorkspaceId)
81
108
  };
109
+ } catch (e) {
110
+ if (e instanceof ConfigError) throw ConfigurationError.databricksAuthenticationSetupFailed(e.baseMessage, { cause: e });
111
+ throw e;
82
112
  }
83
- /**
84
- * Get the client options for WorkspaceClient.
85
- * Exposed for testing purposes.
86
- */
87
- static getClientOptions() {
88
- return getClientOptions();
89
- }
90
- static async createContext(options, client) {
91
- try {
92
- const wsClient = client ?? new WorkspaceClient({}, getClientOptions());
93
- const [resolvedWorkspaceId, currentUser, resolvedWarehouseId] = await Promise.all([
94
- ServiceContext.getWorkspaceId(wsClient),
95
- wsClient.currentUser.me(),
96
- options?.warehouseId ? ServiceContext.getWarehouseId(wsClient) : Promise.resolve(void 0)
97
- ]);
98
- if (!currentUser.id) throw ConfigurationError.resourceNotFound("Service user ID");
99
- const warehouseId = options?.warehouseId && resolvedWarehouseId !== void 0 ? Promise.resolve(resolvedWarehouseId) : void 0;
100
- return {
101
- client: wsClient,
102
- serviceUserId: currentUser.id,
103
- warehouseId,
104
- workspaceId: Promise.resolve(resolvedWorkspaceId)
105
- };
106
- } catch (e) {
107
- if (e instanceof ConfigError) throw ConfigurationError.databricksAuthenticationSetupFailed(e.baseMessage, { cause: e });
108
- throw e;
109
- }
110
- }
111
- static async getWorkspaceId(client) {
112
- if (process.env.DATABRICKS_WORKSPACE_ID) return process.env.DATABRICKS_WORKSPACE_ID;
113
+ }
114
+ static async getWorkspaceId(client) {
115
+ if (process.env.DATABRICKS_WORKSPACE_ID) return process.env.DATABRICKS_WORKSPACE_ID;
116
+ const response = await client.apiClient.request({
117
+ path: "/api/2.0/preview/scim/v2/Me",
118
+ method: "GET",
119
+ headers: new Headers(),
120
+ raw: false,
121
+ query: {},
122
+ responseHeaders: ["x-databricks-org-id"]
123
+ });
124
+ if (!response["x-databricks-org-id"]) throw ConfigurationError.resourceNotFound("Workspace ID");
125
+ return response["x-databricks-org-id"];
126
+ }
127
+ static async getWarehouseId(client) {
128
+ if (process.env.DATABRICKS_WAREHOUSE_ID) return process.env.DATABRICKS_WAREHOUSE_ID;
129
+ if (process.env.NODE_ENV === "development") {
113
130
  const response = await client.apiClient.request({
114
- path: "/api/2.0/preview/scim/v2/Me",
131
+ path: "/api/2.0/sql/warehouses",
115
132
  method: "GET",
116
133
  headers: new Headers(),
117
134
  raw: false,
118
- query: {},
119
- responseHeaders: ["x-databricks-org-id"]
135
+ query: { skip_cannot_use: "true" }
120
136
  });
121
- if (!response["x-databricks-org-id"]) throw ConfigurationError.resourceNotFound("Workspace ID");
122
- return response["x-databricks-org-id"];
123
- }
124
- static async getWarehouseId(client) {
125
- if (process.env.DATABRICKS_WAREHOUSE_ID) return process.env.DATABRICKS_WAREHOUSE_ID;
126
- if (process.env.NODE_ENV === "development") {
127
- const response = await client.apiClient.request({
128
- path: "/api/2.0/sql/warehouses",
129
- method: "GET",
130
- headers: new Headers(),
131
- raw: false,
132
- query: { skip_cannot_use: "true" }
133
- });
134
- const priorities = {
135
- RUNNING: 0,
136
- STOPPED: 1,
137
- STARTING: 2,
138
- STOPPING: 3,
139
- DELETED: 99,
140
- DELETING: 99
141
- };
142
- const warehouses = (response.warehouses || []).sort((a, b) => {
143
- return priorities[a.state] - priorities[b.state];
144
- });
145
- if (response.warehouses.length === 0) throw ConfigurationError.resourceNotFound("Warehouse ID", "Please configure the DATABRICKS_WAREHOUSE_ID environment variable");
146
- const firstWarehouse = warehouses[0];
147
- if (firstWarehouse.state === "DELETED" || firstWarehouse.state === "DELETING" || !firstWarehouse.id) throw ConfigurationError.resourceNotFound("Warehouse ID", "Please configure the DATABRICKS_WAREHOUSE_ID environment variable");
148
- return firstWarehouse.id;
149
- }
150
- throw ConfigurationError.resourceNotFound("Warehouse ID", "Please configure the DATABRICKS_WAREHOUSE_ID environment variable");
151
- }
152
- /**
153
- * Reset the service context. Only for testing purposes.
154
- */
155
- static reset() {
156
- ServiceContext.instance = null;
157
- ServiceContext.initPromise = null;
137
+ const priorities = {
138
+ RUNNING: 0,
139
+ STOPPED: 1,
140
+ STARTING: 2,
141
+ STOPPING: 3,
142
+ DELETED: 99,
143
+ DELETING: 99
144
+ };
145
+ const warehouses = (response.warehouses || []).sort((a, b) => {
146
+ return priorities[a.state] - priorities[b.state];
147
+ });
148
+ if (response.warehouses.length === 0) throw ConfigurationError.resourceNotFound("Warehouse ID", "Please configure the DATABRICKS_WAREHOUSE_ID environment variable");
149
+ const firstWarehouse = warehouses[0];
150
+ if (firstWarehouse.state === "DELETED" || firstWarehouse.state === "DELETING" || !firstWarehouse.id) throw ConfigurationError.resourceNotFound("Warehouse ID", "Please configure the DATABRICKS_WAREHOUSE_ID environment variable");
151
+ return firstWarehouse.id;
158
152
  }
159
- };
160
- }));
153
+ throw ConfigurationError.resourceNotFound("Warehouse ID", "Please configure the DATABRICKS_WAREHOUSE_ID environment variable");
154
+ }
155
+ /**
156
+ * Reset the service context. Only for testing purposes.
157
+ */
158
+ static reset() {
159
+ ServiceContext.instance = null;
160
+ ServiceContext.initPromise = null;
161
+ }
162
+ };
161
163
 
162
164
  //#endregion
163
- init_service_context();
164
- export { ServiceContext, init_service_context };
165
+ export { ServiceContext };
165
166
  //# sourceMappingURL=service-context.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"service-context.js","names":["productName","productVersion"],"sources":["../../src/context/service-context.ts"],"sourcesContent":["import { createHash } from \"node:crypto\";\nimport {\n type ClientOptions,\n ConfigError,\n type sql,\n WorkspaceClient,\n} from \"@databricks/sdk-experimental\";\nimport { coerce } from \"semver\";\nimport {\n name as productName,\n version as productVersion,\n} from \"../../package.json\";\nimport {\n AuthenticationError,\n ConfigurationError,\n InitializationError,\n} from \"../errors\";\nimport type { UserContext } from \"./user-context\";\n\n/**\n * Service context holds the service principal client and shared resources.\n * This is initialized once at app startup and shared across all requests.\n */\nexport interface ServiceContextState {\n /** WorkspaceClient authenticated as the service principal */\n client: WorkspaceClient;\n /** The service principal's user ID */\n serviceUserId: string;\n /** Promise that resolves to the warehouse ID (only present when a plugin requires `SQL_WAREHOUSE` resource) */\n warehouseId?: Promise<string>;\n /** Promise that resolves to the workspace ID */\n workspaceId: Promise<string>;\n}\n\nfunction getClientOptions(): ClientOptions {\n const isDev = process.env.NODE_ENV === \"development\";\n const semver = coerce(productVersion);\n const normalizedVersion = (semver?.version ??\n productVersion) as ClientOptions[\"productVersion\"];\n\n return {\n product: productName,\n productVersion: normalizedVersion,\n ...(isDev && { userAgentExtra: { mode: \"dev\" } }),\n };\n}\n\n/**\n * ServiceContext is a singleton that manages the service principal's\n * WorkspaceClient and shared resources like warehouse/workspace IDs.\n *\n * It's initialized once at app startup and provides the foundation\n * for both service principal and user context execution.\n */\nexport class ServiceContext {\n private static instance: ServiceContextState | null = null;\n private static initPromise: Promise<ServiceContextState> | null = null;\n\n /**\n * Initialize the service context. Should be called once at app startup.\n * Safe to call multiple times - will return the same instance.\n *\n * @param options - Which shared resources to resolve (derived from plugin manifests).\n * @param client - Optional pre-configured WorkspaceClient to use instead\n * of creating one from environment credentials.\n */\n static async initialize(\n options?: { warehouseId?: boolean },\n client?: WorkspaceClient,\n ): Promise<ServiceContextState> {\n if (ServiceContext.instance) {\n return ServiceContext.instance;\n }\n\n if (ServiceContext.initPromise) {\n return ServiceContext.initPromise;\n }\n\n ServiceContext.initPromise = ServiceContext.createContext(options, client);\n ServiceContext.instance = await ServiceContext.initPromise;\n return ServiceContext.instance;\n }\n\n /**\n * Get the initialized service context.\n * @throws Error if not initialized\n */\n static get(): ServiceContextState {\n if (!ServiceContext.instance) {\n throw InitializationError.notInitialized(\n \"ServiceContext\",\n \"Call ServiceContext.initialize() first\",\n );\n }\n return ServiceContext.instance;\n }\n\n /**\n * Check if the service context has been initialized.\n */\n static isInitialized(): boolean {\n return ServiceContext.instance !== null;\n }\n\n /**\n * Create a user context from request headers.\n *\n * @param token - The user's access token from x-forwarded-access-token header\n * @param userId - The user's ID from x-forwarded-user header\n * @param userName - Optional user name\n * @throws Error if token is not provided\n */\n static createUserContext(\n token: string,\n userId: string,\n userName?: string,\n userEmail?: string,\n ): UserContext {\n if (!token) {\n throw AuthenticationError.missingToken(\"user token\");\n }\n\n const host = process.env.DATABRICKS_HOST;\n if (!host) {\n throw ConfigurationError.missingEnvVar(\"DATABRICKS_HOST\");\n }\n\n const serviceCtx = ServiceContext.get();\n\n // Create user client with the OAuth token from Databricks Apps\n // Note: We use authType: \"pat\" because the token is passed as a Bearer token\n // just like a PAT, even though it's technically an OAuth token\n const userClient = new WorkspaceClient(\n {\n token,\n host,\n authType: \"pat\",\n },\n getClientOptions(),\n );\n\n const tokenFingerprint = createHash(\"sha256\")\n .update(token)\n .digest(\"hex\")\n .slice(0, 16);\n\n return {\n client: userClient,\n userId,\n userName,\n userEmail,\n tokenFingerprint,\n warehouseId: serviceCtx.warehouseId,\n workspaceId: serviceCtx.workspaceId,\n isUserContext: true,\n };\n }\n\n /**\n * Get the client options for WorkspaceClient.\n * Exposed for testing purposes.\n */\n static getClientOptions(): ClientOptions {\n return getClientOptions();\n }\n\n private static async createContext(\n options?: { warehouseId?: boolean },\n client?: WorkspaceClient,\n ): Promise<ServiceContextState> {\n try {\n const wsClient = client ?? new WorkspaceClient({}, getClientOptions());\n\n const [resolvedWorkspaceId, currentUser, resolvedWarehouseId] =\n await Promise.all([\n ServiceContext.getWorkspaceId(wsClient),\n wsClient.currentUser.me(),\n options?.warehouseId\n ? ServiceContext.getWarehouseId(wsClient)\n : Promise.resolve(undefined as string | undefined),\n ]);\n\n if (!currentUser.id) {\n throw ConfigurationError.resourceNotFound(\"Service user ID\");\n }\n\n const warehouseId =\n options?.warehouseId && resolvedWarehouseId !== undefined\n ? Promise.resolve(resolvedWarehouseId)\n : undefined;\n\n return {\n client: wsClient,\n serviceUserId: currentUser.id,\n warehouseId,\n workspaceId: Promise.resolve(resolvedWorkspaceId),\n };\n } catch (e) {\n if (e instanceof ConfigError) {\n throw ConfigurationError.databricksAuthenticationSetupFailed(\n e.baseMessage,\n { cause: e },\n );\n }\n throw e;\n }\n }\n\n private static async getWorkspaceId(\n client: WorkspaceClient,\n ): Promise<string> {\n if (process.env.DATABRICKS_WORKSPACE_ID) {\n return process.env.DATABRICKS_WORKSPACE_ID;\n }\n\n const response = (await client.apiClient.request({\n path: \"/api/2.0/preview/scim/v2/Me\",\n method: \"GET\",\n headers: new Headers(),\n raw: false,\n query: {},\n responseHeaders: [\"x-databricks-org-id\"],\n })) as { \"x-databricks-org-id\": string };\n\n if (!response[\"x-databricks-org-id\"]) {\n throw ConfigurationError.resourceNotFound(\"Workspace ID\");\n }\n\n return response[\"x-databricks-org-id\"];\n }\n\n private static async getWarehouseId(\n client: WorkspaceClient,\n ): Promise<string> {\n if (process.env.DATABRICKS_WAREHOUSE_ID) {\n return process.env.DATABRICKS_WAREHOUSE_ID;\n }\n\n if (process.env.NODE_ENV === \"development\") {\n const response = (await client.apiClient.request({\n path: \"/api/2.0/sql/warehouses\",\n method: \"GET\",\n headers: new Headers(),\n raw: false,\n query: {\n skip_cannot_use: \"true\",\n },\n })) as { warehouses: sql.EndpointInfo[] };\n\n const priorities: Record<sql.State, number> = {\n RUNNING: 0,\n STOPPED: 1,\n STARTING: 2,\n STOPPING: 3,\n DELETED: 99,\n DELETING: 99,\n };\n\n const warehouses = (response.warehouses || []).sort((a, b) => {\n return (\n priorities[a.state as sql.State] - priorities[b.state as sql.State]\n );\n });\n\n if (response.warehouses.length === 0) {\n throw ConfigurationError.resourceNotFound(\n \"Warehouse ID\",\n \"Please configure the DATABRICKS_WAREHOUSE_ID environment variable\",\n );\n }\n\n const firstWarehouse = warehouses[0];\n if (\n firstWarehouse.state === \"DELETED\" ||\n firstWarehouse.state === \"DELETING\" ||\n !firstWarehouse.id\n ) {\n throw ConfigurationError.resourceNotFound(\n \"Warehouse ID\",\n \"Please configure the DATABRICKS_WAREHOUSE_ID environment variable\",\n );\n }\n\n return firstWarehouse.id;\n }\n\n throw ConfigurationError.resourceNotFound(\n \"Warehouse ID\",\n \"Please configure the DATABRICKS_WAREHOUSE_ID environment variable\",\n );\n }\n\n /**\n * Reset the service context. Only for testing purposes.\n */\n static reset(): void {\n ServiceContext.instance = null;\n ServiceContext.initPromise = null;\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"service-context.js","names":["productName","productVersion"],"sources":["../../src/context/service-context.ts"],"sourcesContent":["import { createHash } from \"node:crypto\";\nimport {\n type ClientOptions,\n ConfigError,\n type sql,\n WorkspaceClient,\n} from \"@databricks/sdk-experimental\";\nimport { coerce } from \"semver\";\nimport {\n name as productName,\n version as productVersion,\n} from \"../../package.json\";\nimport {\n AuthenticationError,\n ConfigurationError,\n InitializationError,\n} from \"../errors\";\nimport type { UserContext } from \"./user-context\";\n\n/**\n * Service context holds the service principal client and shared resources.\n * This is initialized once at app startup and shared across all requests.\n */\nexport interface ServiceContextState {\n /** WorkspaceClient authenticated as the service principal */\n client: WorkspaceClient;\n /** The service principal's user ID */\n serviceUserId: string;\n /** Promise that resolves to the warehouse ID (only present when a plugin requires `SQL_WAREHOUSE` resource) */\n warehouseId?: Promise<string>;\n /** Promise that resolves to the workspace ID */\n workspaceId: Promise<string>;\n}\n\nfunction getClientOptions(): ClientOptions {\n const isDev = process.env.NODE_ENV === \"development\";\n const semver = coerce(productVersion);\n const normalizedVersion = (semver?.version ??\n productVersion) as ClientOptions[\"productVersion\"];\n\n return {\n product: productName,\n productVersion: normalizedVersion,\n ...(isDev && { userAgentExtra: { mode: \"dev\" } }),\n };\n}\n\n/**\n * ServiceContext is a singleton that manages the service principal's\n * WorkspaceClient and shared resources like warehouse/workspace IDs.\n *\n * It's initialized once at app startup and provides the foundation\n * for both service principal and user context execution.\n */\nexport class ServiceContext {\n private static instance: ServiceContextState | null = null;\n private static initPromise: Promise<ServiceContextState> | null = null;\n\n /**\n * Initialize the service context. Should be called once at app startup.\n * Safe to call multiple times - will return the same instance.\n *\n * @param options - Which shared resources to resolve (derived from plugin manifests).\n * @param client - Optional pre-configured WorkspaceClient to use instead\n * of creating one from environment credentials.\n */\n static async initialize(\n options?: { warehouseId?: boolean },\n client?: WorkspaceClient,\n ): Promise<ServiceContextState> {\n if (ServiceContext.instance) {\n return ServiceContext.instance;\n }\n\n if (ServiceContext.initPromise) {\n return ServiceContext.initPromise;\n }\n\n ServiceContext.initPromise = ServiceContext.createContext(options, client);\n ServiceContext.instance = await ServiceContext.initPromise;\n return ServiceContext.instance;\n }\n\n /**\n * Get the initialized service context.\n * @throws Error if not initialized\n */\n static get(): ServiceContextState {\n if (!ServiceContext.instance) {\n throw InitializationError.notInitialized(\n \"ServiceContext\",\n \"Call ServiceContext.initialize() first\",\n );\n }\n return ServiceContext.instance;\n }\n\n /**\n * Check if the service context has been initialized.\n */\n static isInitialized(): boolean {\n return ServiceContext.instance !== null;\n }\n\n /**\n * Create a user context from request headers.\n *\n * @param token - The user's access token from x-forwarded-access-token header\n * @param userId - The user's ID from x-forwarded-user header\n * @param userName - Optional user name\n * @throws Error if token is not provided\n */\n static createUserContext(\n token: string,\n userId: string,\n userName?: string,\n userEmail?: string,\n ): UserContext {\n if (!token) {\n throw AuthenticationError.missingToken(\"user token\");\n }\n\n const host = process.env.DATABRICKS_HOST;\n if (!host) {\n throw ConfigurationError.missingEnvVar(\"DATABRICKS_HOST\");\n }\n\n const serviceCtx = ServiceContext.get();\n\n // Create user client with the OAuth token from Databricks Apps\n // Note: We use authType: \"pat\" because the token is passed as a Bearer token\n // just like a PAT, even though it's technically an OAuth token\n const userClient = new WorkspaceClient(\n {\n token,\n host,\n authType: \"pat\",\n },\n getClientOptions(),\n );\n\n const tokenFingerprint = createHash(\"sha256\")\n .update(token)\n .digest(\"hex\")\n .slice(0, 16);\n\n return {\n client: userClient,\n userId,\n userName,\n userEmail,\n tokenFingerprint,\n warehouseId: serviceCtx.warehouseId,\n workspaceId: serviceCtx.workspaceId,\n isUserContext: true,\n };\n }\n\n /**\n * Get the client options for WorkspaceClient.\n * Exposed for testing purposes.\n */\n static getClientOptions(): ClientOptions {\n return getClientOptions();\n }\n\n private static async createContext(\n options?: { warehouseId?: boolean },\n client?: WorkspaceClient,\n ): Promise<ServiceContextState> {\n try {\n const wsClient = client ?? new WorkspaceClient({}, getClientOptions());\n\n const [resolvedWorkspaceId, currentUser, resolvedWarehouseId] =\n await Promise.all([\n ServiceContext.getWorkspaceId(wsClient),\n wsClient.currentUser.me(),\n options?.warehouseId\n ? ServiceContext.getWarehouseId(wsClient)\n : Promise.resolve(undefined as string | undefined),\n ]);\n\n if (!currentUser.id) {\n throw ConfigurationError.resourceNotFound(\"Service user ID\");\n }\n\n const warehouseId =\n options?.warehouseId && resolvedWarehouseId !== undefined\n ? Promise.resolve(resolvedWarehouseId)\n : undefined;\n\n return {\n client: wsClient,\n serviceUserId: currentUser.id,\n warehouseId,\n workspaceId: Promise.resolve(resolvedWorkspaceId),\n };\n } catch (e) {\n if (e instanceof ConfigError) {\n throw ConfigurationError.databricksAuthenticationSetupFailed(\n e.baseMessage,\n { cause: e },\n );\n }\n throw e;\n }\n }\n\n private static async getWorkspaceId(\n client: WorkspaceClient,\n ): Promise<string> {\n if (process.env.DATABRICKS_WORKSPACE_ID) {\n return process.env.DATABRICKS_WORKSPACE_ID;\n }\n\n const response = (await client.apiClient.request({\n path: \"/api/2.0/preview/scim/v2/Me\",\n method: \"GET\",\n headers: new Headers(),\n raw: false,\n query: {},\n responseHeaders: [\"x-databricks-org-id\"],\n })) as { \"x-databricks-org-id\": string };\n\n if (!response[\"x-databricks-org-id\"]) {\n throw ConfigurationError.resourceNotFound(\"Workspace ID\");\n }\n\n return response[\"x-databricks-org-id\"];\n }\n\n private static async getWarehouseId(\n client: WorkspaceClient,\n ): Promise<string> {\n if (process.env.DATABRICKS_WAREHOUSE_ID) {\n return process.env.DATABRICKS_WAREHOUSE_ID;\n }\n\n if (process.env.NODE_ENV === \"development\") {\n const response = (await client.apiClient.request({\n path: \"/api/2.0/sql/warehouses\",\n method: \"GET\",\n headers: new Headers(),\n raw: false,\n query: {\n skip_cannot_use: \"true\",\n },\n })) as { warehouses: sql.EndpointInfo[] };\n\n const priorities: Record<sql.State, number> = {\n RUNNING: 0,\n STOPPED: 1,\n STARTING: 2,\n STOPPING: 3,\n DELETED: 99,\n DELETING: 99,\n };\n\n const warehouses = (response.warehouses || []).sort((a, b) => {\n return (\n priorities[a.state as sql.State] - priorities[b.state as sql.State]\n );\n });\n\n if (response.warehouses.length === 0) {\n throw ConfigurationError.resourceNotFound(\n \"Warehouse ID\",\n \"Please configure the DATABRICKS_WAREHOUSE_ID environment variable\",\n );\n }\n\n const firstWarehouse = warehouses[0];\n if (\n firstWarehouse.state === \"DELETED\" ||\n firstWarehouse.state === \"DELETING\" ||\n !firstWarehouse.id\n ) {\n throw ConfigurationError.resourceNotFound(\n \"Warehouse ID\",\n \"Please configure the DATABRICKS_WAREHOUSE_ID environment variable\",\n );\n }\n\n return firstWarehouse.id;\n }\n\n throw ConfigurationError.resourceNotFound(\n \"Warehouse ID\",\n \"Please configure the DATABRICKS_WAREHOUSE_ID environment variable\",\n );\n }\n\n /**\n * Reset the service context. Only for testing purposes.\n */\n static reset(): void {\n ServiceContext.instance = null;\n ServiceContext.initPromise = null;\n }\n}\n"],"mappings":"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"}
@@ -1,5 +1,3 @@
1
- import { __esmMin } from "../_virtual/_rolldown/runtime.js";
2
-
3
1
  //#region src/context/user-context.ts
4
2
  /**
5
3
  * Check if an execution context is a user context.
@@ -7,9 +5,7 @@ import { __esmMin } from "../_virtual/_rolldown/runtime.js";
7
5
  function isUserContext(ctx) {
8
6
  return "isUserContext" in ctx && ctx.isUserContext === true;
9
7
  }
10
- var init_user_context = __esmMin((() => {}));
11
8
 
12
9
  //#endregion
13
- init_user_context();
14
- export { init_user_context, isUserContext };
10
+ export { isUserContext };
15
11
  //# sourceMappingURL=user-context.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"user-context.js","names":[],"sources":["../../src/context/user-context.ts"],"sourcesContent":["import type { ServiceContextState } from \"./service-context\";\n\n/**\n * User execution context extends the service context with user-specific data.\n * Created on-demand when asUser(req) is called.\n */\nexport interface UserContext {\n /** WorkspaceClient authenticated as the user */\n client: ServiceContextState[\"client\"];\n /** The user's ID (from request headers) */\n userId: string;\n /** The user's name (from request headers) */\n userName?: string;\n /** The user's email (from `x-forwarded-email` header) */\n userEmail?: string;\n /** Truncated SHA-256 hash of the user's OBO token, used to detect token rotation */\n tokenFingerprint?: string;\n /** Promise that resolves to the warehouse ID (inherited from service context, only present when a plugin requires `SQL_WAREHOUSE` resource) */\n warehouseId?: Promise<string>;\n /** Promise that resolves to the workspace ID (inherited from service context) */\n workspaceId: Promise<string>;\n /** Flag indicating this is a user context */\n isUserContext: true;\n}\n\n/**\n * Execution context can be either service or user context.\n */\nexport type ExecutionContext = ServiceContextState | UserContext;\n\n/**\n * Check if an execution context is a user context.\n */\nexport function isUserContext(ctx: ExecutionContext): ctx is UserContext {\n return \"isUserContext\" in ctx && ctx.isUserContext === true;\n}\n"],"mappings":";;;;;;AAiCA,SAAgB,cAAc,KAA2C;AACvE,QAAO,mBAAmB,OAAO,IAAI,kBAAkB"}
1
+ {"version":3,"file":"user-context.js","names":[],"sources":["../../src/context/user-context.ts"],"sourcesContent":["import type { ServiceContextState } from \"./service-context\";\n\n/**\n * User execution context extends the service context with user-specific data.\n * Created on-demand when asUser(req) is called.\n */\nexport interface UserContext {\n /** WorkspaceClient authenticated as the user */\n client: ServiceContextState[\"client\"];\n /** The user's ID (from request headers) */\n userId: string;\n /** The user's name (from request headers) */\n userName?: string;\n /** The user's email (from `x-forwarded-email` header) */\n userEmail?: string;\n /** Truncated SHA-256 hash of the user's OBO token, used to detect token rotation */\n tokenFingerprint?: string;\n /** Promise that resolves to the warehouse ID (inherited from service context, only present when a plugin requires `SQL_WAREHOUSE` resource) */\n warehouseId?: Promise<string>;\n /** Promise that resolves to the workspace ID (inherited from service context) */\n workspaceId: Promise<string>;\n /** Flag indicating this is a user context */\n isUserContext: true;\n}\n\n/**\n * Execution context can be either service or user context.\n */\nexport type ExecutionContext = ServiceContextState | UserContext;\n\n/**\n * Check if an execution context is a user context.\n */\nexport function isUserContext(ctx: ExecutionContext): ctx is UserContext {\n return \"isUserContext\" in ctx && ctx.isUserContext === true;\n}\n"],"mappings":";;;;AAiCA,SAAgB,cAAc,KAA2C;AACvE,QAAO,mBAAmB,OAAO,IAAI,kBAAkB"}
@@ -1,8 +1,7 @@
1
1
  import { ConfigurationError } from "../../errors/configuration.js";
2
- import { init_errors } from "../../errors/index.js";
2
+ import "../../errors/index.js";
3
3
 
4
4
  //#region src/core/agent/create-agent.ts
5
- init_errors();
6
5
  /**
7
6
  * Pure factory for agent definitions. Returns the passed-in definition after
8
7
  * cycle-detecting the sub-agent graph. Accepts the full `AgentDefinition` shape
@@ -1 +1 @@
1
- {"version":3,"file":"create-agent.js","names":[],"sources":["../../../src/core/agent/create-agent.ts"],"sourcesContent":["import { ConfigurationError } from \"../../errors\";\nimport type { AgentDefinition } from \"./types\";\n\n/**\n * Pure factory for agent definitions. Returns the passed-in definition after\n * cycle-detecting the sub-agent graph. Accepts the full `AgentDefinition` shape\n * and is safe to call at module top-level.\n *\n * The returned value is a plain `AgentDefinition` — no adapter construction,\n * no side effects. Register it with `agents({ agents: { name: def } })` or run\n * it standalone via `runAgent(def, input)`.\n *\n * @example\n * ```ts\n * const support = createAgent({\n * instructions: \"You help customers.\",\n * model: \"databricks-claude-sonnet-4-5\",\n * tools: {\n * get_weather: tool({ ... }),\n * },\n * });\n * ```\n */\nexport function createAgent(def: AgentDefinition): AgentDefinition {\n detectCycles(def);\n return def;\n}\n\n/**\n * Walks the `agents: { ... }` sub-agent tree via DFS and throws if a cycle is\n * found. Cycles would cause infinite recursion at tool-invocation time.\n */\nfunction detectCycles(def: AgentDefinition): void {\n const visiting = new Set<AgentDefinition>();\n const visited = new Set<AgentDefinition>();\n\n const walk = (current: AgentDefinition, path: string[]): void => {\n if (visited.has(current)) return;\n if (visiting.has(current)) {\n throw new ConfigurationError(\n `Agent sub-agent cycle detected: ${path.join(\" -> \")}`,\n );\n }\n visiting.add(current);\n for (const [childKey, child] of Object.entries(current.agents ?? {})) {\n walk(child, [...path, childKey]);\n }\n visiting.delete(current);\n visited.add(current);\n };\n\n walk(def, [def.name ?? \"(root)\"]);\n}\n"],"mappings":";;;;aAAkD;;;;;;;;;;;;;;;;;;;;;AAuBlD,SAAgB,YAAY,KAAuC;AACjE,cAAa,IAAI;AACjB,QAAO;;;;;;AAOT,SAAS,aAAa,KAA4B;CAChD,MAAM,2BAAW,IAAI,KAAsB;CAC3C,MAAM,0BAAU,IAAI,KAAsB;CAE1C,MAAM,QAAQ,SAA0B,SAAyB;AAC/D,MAAI,QAAQ,IAAI,QAAQ,CAAE;AAC1B,MAAI,SAAS,IAAI,QAAQ,CACvB,OAAM,IAAI,mBACR,mCAAmC,KAAK,KAAK,OAAO,GACrD;AAEH,WAAS,IAAI,QAAQ;AACrB,OAAK,MAAM,CAAC,UAAU,UAAU,OAAO,QAAQ,QAAQ,UAAU,EAAE,CAAC,CAClE,MAAK,OAAO,CAAC,GAAG,MAAM,SAAS,CAAC;AAElC,WAAS,OAAO,QAAQ;AACxB,UAAQ,IAAI,QAAQ;;AAGtB,MAAK,KAAK,CAAC,IAAI,QAAQ,SAAS,CAAC"}
1
+ {"version":3,"file":"create-agent.js","names":[],"sources":["../../../src/core/agent/create-agent.ts"],"sourcesContent":["import { ConfigurationError } from \"../../errors\";\nimport type { AgentDefinition } from \"./types\";\n\n/**\n * Pure factory for agent definitions. Returns the passed-in definition after\n * cycle-detecting the sub-agent graph. Accepts the full `AgentDefinition` shape\n * and is safe to call at module top-level.\n *\n * The returned value is a plain `AgentDefinition` — no adapter construction,\n * no side effects. Register it with `agents({ agents: { name: def } })` or run\n * it standalone via `runAgent(def, input)`.\n *\n * @example\n * ```ts\n * const support = createAgent({\n * instructions: \"You help customers.\",\n * model: \"databricks-claude-sonnet-4-5\",\n * tools: {\n * get_weather: tool({ ... }),\n * },\n * });\n * ```\n */\nexport function createAgent(def: AgentDefinition): AgentDefinition {\n detectCycles(def);\n return def;\n}\n\n/**\n * Walks the `agents: { ... }` sub-agent tree via DFS and throws if a cycle is\n * found. Cycles would cause infinite recursion at tool-invocation time.\n */\nfunction detectCycles(def: AgentDefinition): void {\n const visiting = new Set<AgentDefinition>();\n const visited = new Set<AgentDefinition>();\n\n const walk = (current: AgentDefinition, path: string[]): void => {\n if (visited.has(current)) return;\n if (visiting.has(current)) {\n throw new ConfigurationError(\n `Agent sub-agent cycle detected: ${path.join(\" -> \")}`,\n );\n }\n visiting.add(current);\n for (const [childKey, child] of Object.entries(current.agents ?? {})) {\n walk(child, [...path, childKey]);\n }\n visiting.delete(current);\n visited.add(current);\n };\n\n walk(def, [def.name ?? \"(root)\"]);\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;AAuBA,SAAgB,YAAY,KAAuC;AACjE,cAAa,IAAI;AACjB,QAAO;;;;;;AAOT,SAAS,aAAa,KAA4B;CAChD,MAAM,2BAAW,IAAI,KAAsB;CAC3C,MAAM,0BAAU,IAAI,KAAsB;CAE1C,MAAM,QAAQ,SAA0B,SAAyB;AAC/D,MAAI,QAAQ,IAAI,QAAQ,CAAE;AAC1B,MAAI,SAAS,IAAI,QAAQ,CACvB,OAAM,IAAI,mBACR,mCAAmC,KAAK,KAAK,OAAO,GACrD;AAEH,WAAS,IAAI,QAAQ;AACrB,OAAK,MAAM,CAAC,UAAU,UAAU,OAAO,QAAQ,QAAQ,UAAU,EAAE,CAAC,CAClE,MAAK,OAAO,CAAC,GAAG,MAAM,SAAS,CAAC;AAElC,WAAS,OAAO,QAAQ;AACxB,UAAQ,IAAI,QAAQ;;AAGtB,MAAK,KAAK,CAAC,IAAI,QAAQ,SAAS,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"appkit.d.ts","names":[],"sources":["../../src/core/appkit.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAkWsB,SAAA,WACV,UAAA,CAAW,iBAAA,qBAAA,CAErB,MAAA;EACE,OAAA,GAAU,CAAA;EACV,SAAA,GAAY,eAAA;EACZ,KAAA,GAAQ,WAAA;EACR,MAAA,GAAS,eAAA;EACT,cAAA,IAAkB,MAAA,EAAQ,SAAA,CAAU,CAAA,aAAc,OAAA;EAClD,wBAAA;AAAA,IAED,OAAA,CAAQ,SAAA,CAAU,CAAA"}
1
+ {"version":3,"file":"appkit.d.ts","names":[],"sources":["../../src/core/appkit.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBA+SsB,SAAA,WACV,UAAA,CAAW,iBAAA,qBAAA,CAErB,MAAA;EACE,OAAA,GAAU,CAAA;EACV,SAAA,GAAY,eAAA;EACZ,KAAA,GAAQ,WAAA;EACR,MAAA,GAAS,eAAA;EACT,cAAA,IAAkB,MAAA,EAAQ,SAAA,CAAU,CAAA,aAAc,OAAA;EAClD,wBAAA;AAAA,IAED,OAAA,CAAQ,SAAA,CAAU,CAAA"}
@@ -1,22 +1,20 @@
1
1
  import { createLogger } from "../logging/logger.js";
2
2
  import { version } from "../appkit/package.js";
3
3
  import { ServiceContext } from "../context/service-context.js";
4
- import { runInUserContext } from "../context/execution-context.js";
5
4
  import { TelemetryManager } from "../telemetry/telemetry-manager.js";
6
5
  import "../telemetry/index.js";
7
6
  import { CacheManager } from "../cache/index.js";
8
- import { init_context } from "../context/index.js";
7
+ import "../context/index.js";
9
8
  import { isInternalTelemetryEnabled } from "../internal-telemetry/config.js";
10
9
  import { TelemetryReporter } from "../internal-telemetry/reporter.js";
11
10
  import "../internal-telemetry/index.js";
12
- import { USER_CONTEXT_SYMBOL } from "../plugin/plugin.js";
11
+ import { isPlainObject } from "../plugin/plugin.js";
13
12
  import { ResourceType } from "../registry/types.generated.js";
14
13
  import { ResourceRegistry } from "../registry/resource-registry.js";
15
14
  import "../registry/index.js";
16
15
  import { PluginContext, isToolProvider } from "./plugin-context.js";
17
16
 
18
17
  //#region src/core/appkit.ts
19
- init_context();
20
18
  const logger = createLogger("appkit");
21
19
  var AppKit = class AppKit {
22
20
  #pluginInstances = {};
@@ -71,23 +69,7 @@ var AppKit = class AppKit {
71
69
  if (!Object.hasOwn(exports, key)) continue;
72
70
  const val = exports[key];
73
71
  if (typeof val === "function") exports[key] = val.bind(context);
74
- else if (AppKit.isPlainObject(val)) this.bindExportMethods(val, context);
75
- }
76
- }
77
- /**
78
- * Wraps all function properties in an exports object so they run
79
- * inside the given user context (via AsyncLocalStorage).
80
- * This ensures RoutingPool and other context-aware code sees the
81
- * user identity even though the function was obtained outside the proxy.
82
- */
83
- wrapExportsInUserContext(exports, userContext) {
84
- for (const key in exports) {
85
- if (!Object.hasOwn(exports, key)) continue;
86
- const val = exports[key];
87
- if (typeof val === "function") {
88
- const fn = val;
89
- exports[key] = (...args) => runInUserContext(userContext, () => fn(...args));
90
- } else if (AppKit.isPlainObject(val)) this.wrapExportsInUserContext(val, userContext);
72
+ else if (isPlainObject(val)) this.bindExportMethods(val, context);
91
73
  }
92
74
  }
93
75
  /**
@@ -97,6 +79,11 @@ var AppKit = class AppKit {
97
79
  * When `exports()` returns a callable (function), it is returned as-is
98
80
  * since the plugin manages its own `asUser` per-call (e.g. files plugin).
99
81
  * When it returns a plain object, the standard `asUser` wrapper is added.
82
+ *
83
+ * The OBO-side wrapping lives inside `Plugin.asUser` — calling
84
+ * `plugin.asUser(req).exports()` returns exports whose functions already
85
+ * run inside the user's AsyncLocalStorage scope. AppKit only adapts the
86
+ * shape; it does not own the user-context concept.
100
87
  */
101
88
  wrapWithAsUser(plugin) {
102
89
  const pluginExports = plugin.exports?.() ?? {};
@@ -106,24 +93,9 @@ var AppKit = class AppKit {
106
93
  if (typeof plugin.asUser !== "function") return objExports;
107
94
  return {
108
95
  ...objExports,
109
- asUser: (req) => {
110
- const userPlugin = plugin.asUser(req);
111
- const userContext = userPlugin[USER_CONTEXT_SYMBOL];
112
- const userExports = plugin.exports?.() ?? {};
113
- if (userContext) this.wrapExportsInUserContext(userExports, userContext);
114
- else this.bindExportMethods(userExports, userPlugin);
115
- return userExports;
116
- }
96
+ asUser: (req) => plugin.asUser(req).exports()
117
97
  };
118
98
  }
119
- /**
120
- * Returns true if the value is a plain object (not an array, Date, etc.).
121
- */
122
- static isPlainObject(value) {
123
- if (typeof value !== "object" || value === null) return false;
124
- const proto = Object.getPrototypeOf(value);
125
- return proto === Object.prototype || proto === null;
126
- }
127
99
  static async _createApp(config = {}) {
128
100
  TelemetryManager.initialize(config?.telemetry);
129
101
  await CacheManager.getInstance(config?.cache);
@@ -1 +1 @@
1
- {"version":3,"file":"appkit.js","names":["#context","#pluginInstances","#setupPromises","productVersion"],"sources":["../../src/core/appkit.ts"],"sourcesContent":["import type { WorkspaceClient } from \"@databricks/sdk-experimental\";\nimport type {\n BasePlugin,\n CacheConfig,\n InputPluginMap,\n OptionalConfigPluginDef,\n PluginConstructor,\n PluginData,\n PluginMap,\n} from \"shared\";\nimport { version as productVersion } from \"../../package.json\";\nimport { CacheManager } from \"../cache\";\nimport { runInUserContext, ServiceContext } from \"../context\";\nimport type { UserContext } from \"../context/user-context\";\nimport {\n isInternalTelemetryEnabled,\n TelemetryReporter,\n} from \"../internal-telemetry\";\nimport { createLogger } from \"../logging/logger\";\nimport { USER_CONTEXT_SYMBOL } from \"../plugin/plugin\";\nimport { ResourceRegistry, ResourceType } from \"../registry\";\nimport type { TelemetryConfig } from \"../telemetry\";\nimport { TelemetryManager } from \"../telemetry\";\nimport { isToolProvider, PluginContext } from \"./plugin-context\";\n\nconst logger = createLogger(\"appkit\");\n\nexport class AppKit<TPlugins extends InputPluginMap> {\n #pluginInstances: Record<string, BasePlugin> = {};\n #setupPromises: Promise<void>[] = [];\n #context: PluginContext;\n\n private constructor(config: { plugins: TPlugins }) {\n const { plugins, ...globalConfig } = config;\n\n this.#context = new PluginContext();\n\n const pluginEntries = Object.entries(plugins);\n\n const corePlugins = pluginEntries.filter(([_, p]) => {\n return (p?.plugin?.phase ?? \"normal\") === \"core\";\n });\n const normalPlugins = pluginEntries.filter(\n ([_, p]) => (p?.plugin?.phase ?? \"normal\") === \"normal\",\n );\n const deferredPlugins = pluginEntries.filter(\n ([_, p]) => (p?.plugin?.phase ?? \"normal\") === \"deferred\",\n );\n\n for (const [name, pluginData] of corePlugins) {\n if (pluginData) {\n this.createAndRegisterPlugin(globalConfig, name, pluginData, {\n context: this.#context,\n });\n }\n }\n\n for (const [name, pluginData] of normalPlugins) {\n if (pluginData) {\n this.createAndRegisterPlugin(globalConfig, name, pluginData, {\n context: this.#context,\n });\n }\n }\n\n for (const [name, pluginData] of deferredPlugins) {\n if (pluginData) {\n this.createAndRegisterPlugin(globalConfig, name, pluginData, {\n context: this.#context,\n });\n }\n }\n }\n\n private createAndRegisterPlugin<T extends PluginConstructor>(\n config: Omit<{ plugins: TPlugins }, \"plugins\">,\n name: string,\n pluginData: OptionalConfigPluginDef<T>,\n extraData?: Record<string, unknown>,\n ) {\n const { plugin: Plugin, config: pluginConfig } = pluginData;\n const baseConfig = {\n ...config,\n ...Plugin.DEFAULT_CONFIG,\n ...pluginConfig,\n name,\n ...extraData,\n };\n const pluginInstance = new Plugin(baseConfig);\n\n if (typeof pluginInstance.attachContext === \"function\") {\n pluginInstance.attachContext({\n context: this.#context,\n telemetryConfig: baseConfig.telemetry,\n });\n }\n\n this.#pluginInstances[name] = pluginInstance;\n\n this.#context.registerPlugin(name, pluginInstance);\n if (isToolProvider(pluginInstance)) {\n this.#context.registerToolProvider(name, pluginInstance);\n }\n\n this.#setupPromises.push(pluginInstance.setup());\n\n const self = this;\n\n Object.defineProperty(this, name, {\n get() {\n const plugin = self.#pluginInstances[name];\n return self.wrapWithAsUser(plugin);\n },\n enumerable: true,\n });\n }\n\n /**\n * Binds all function properties in an exports object to the given context.\n * Recurses into plain objects to handle nested APIs (e.g., volume APIs).\n */\n private bindExportMethods(\n exports: Record<string, unknown>,\n context: BasePlugin,\n ) {\n for (const key in exports) {\n if (!Object.hasOwn(exports, key)) continue;\n const val = exports[key];\n if (typeof val === \"function\") {\n exports[key] = (val as (...args: unknown[]) => unknown).bind(context);\n } else if (AppKit.isPlainObject(val)) {\n this.bindExportMethods(val as Record<string, unknown>, context);\n }\n }\n }\n\n /**\n * Wraps all function properties in an exports object so they run\n * inside the given user context (via AsyncLocalStorage).\n * This ensures RoutingPool and other context-aware code sees the\n * user identity even though the function was obtained outside the proxy.\n */\n private wrapExportsInUserContext(\n exports: Record<string, unknown>,\n userContext: UserContext,\n ) {\n for (const key in exports) {\n if (!Object.hasOwn(exports, key)) continue;\n const val = exports[key];\n if (typeof val === \"function\") {\n const fn = val as (...args: unknown[]) => unknown;\n exports[key] = (...args: unknown[]) =>\n runInUserContext(userContext, () => fn(...args));\n } else if (AppKit.isPlainObject(val)) {\n this.wrapExportsInUserContext(\n val as Record<string, unknown>,\n userContext,\n );\n }\n }\n }\n\n /**\n * Wraps a plugin's exports with an `asUser` method that returns\n * a user-scoped version of the exports.\n *\n * When `exports()` returns a callable (function), it is returned as-is\n * since the plugin manages its own `asUser` per-call (e.g. files plugin).\n * When it returns a plain object, the standard `asUser` wrapper is added.\n */\n private wrapWithAsUser<T extends BasePlugin>(plugin: T) {\n // If plugin doesn't implement exports(), return empty object\n const pluginExports = plugin.exports?.() ?? {};\n\n // If exports is a function, the plugin manages its own asUser pattern\n if (typeof pluginExports === \"function\") {\n return pluginExports;\n }\n\n const objExports = pluginExports as Record<string, unknown>;\n this.bindExportMethods(objExports, plugin);\n\n // If plugin doesn't support asUser (no asUser method), return exports as-is\n if (typeof (plugin as any).asUser !== \"function\") {\n return objExports;\n }\n\n return {\n ...objExports,\n /**\n * Execute operations using the user's identity from the request.\n * Returns user-scoped exports where all methods execute with the\n * user's Databricks credentials instead of the service principal.\n */\n asUser: (req: import(\"express\").Request) => {\n const userPlugin = (plugin as any).asUser(req);\n const userContext = (userPlugin as any)[\n USER_CONTEXT_SYMBOL\n ] as UserContext;\n const userExports = (plugin.exports?.() ?? {}) as Record<\n string,\n unknown\n >;\n // Wrap each export in runInUserContext instead of bind.\n // bind() bypasses the Proxy get trap, so methods called via bind\n // would not run inside the user's AsyncLocalStorage context.\n if (userContext) {\n this.wrapExportsInUserContext(userExports, userContext);\n } else {\n // Fallback for dev mode proxy (no userContext symbol)\n this.bindExportMethods(userExports, userPlugin);\n }\n return userExports;\n },\n };\n }\n\n /**\n * Returns true if the value is a plain object (not an array, Date, etc.).\n */\n private static isPlainObject(\n value: unknown,\n ): value is Record<string, unknown> {\n if (typeof value !== \"object\" || value === null) return false;\n const proto = Object.getPrototypeOf(value);\n return proto === Object.prototype || proto === null;\n }\n\n static async _createApp<\n T extends PluginData<PluginConstructor, unknown, string>[],\n >(\n config: {\n plugins?: T;\n telemetry?: TelemetryConfig;\n cache?: CacheConfig;\n client?: WorkspaceClient;\n onPluginsReady?: (appkit: PluginMap<T>) => void | Promise<void>;\n disableInternalTelemetry?: boolean;\n } = {},\n ): Promise<PluginMap<T>> {\n // Initialize core services\n TelemetryManager.initialize(config?.telemetry);\n await CacheManager.getInstance(config?.cache);\n\n const rawPlugins = config.plugins as T;\n\n // Collect manifest resources via registry\n const registry = new ResourceRegistry();\n registry.collectResources(rawPlugins);\n\n // Derive ServiceContext needs from what manifests declared\n const needsWarehouse = registry\n .getRequired()\n .some((r) => r.type === ResourceType.SQL_WAREHOUSE);\n await ServiceContext.initialize(\n { warehouseId: needsWarehouse },\n config?.client,\n );\n\n // Validate env vars\n registry.enforceValidation();\n\n const preparedPlugins = AppKit.preparePlugins(rawPlugins);\n const mergedConfig = {\n plugins: preparedPlugins,\n };\n\n const instance = new AppKit(mergedConfig);\n\n await Promise.all(instance.#setupPromises);\n await instance.#context.emitLifecycle(\"setup:complete\");\n\n const handle = instance as unknown as PluginMap<T>;\n\n if (config.onPluginsReady) {\n logger.debug(\"Running onPluginsReady hook\");\n await config.onPluginsReady(handle);\n logger.debug(\"onPluginsReady hook completed\");\n }\n\n if (isInternalTelemetryEnabled(config)) {\n AppKit.bootstrapInternalTelemetry();\n }\n\n const serverPlugin = instance.#pluginInstances.server;\n if (serverPlugin && typeof (serverPlugin as any).start === \"function\") {\n await (serverPlugin as any).start();\n }\n\n return handle;\n }\n\n private static bootstrapInternalTelemetry(): void {\n const serviceCtx = ServiceContext.get();\n const reporter = TelemetryReporter.initialize({\n workspaceId: serviceCtx.workspaceId,\n client: serviceCtx.client,\n appId: process.env.DATABRICKS_CLIENT_ID || \"\",\n appkitVersion: productVersion,\n });\n reporter.start();\n reporter.sendStartup().catch(() => {});\n }\n\n private static preparePlugins(\n plugins: PluginData<PluginConstructor, unknown, string>[],\n ) {\n const result: InputPluginMap = {};\n for (const currentPlugin of plugins) {\n result[currentPlugin.name] = {\n plugin: currentPlugin.plugin,\n config: currentPlugin.config as Record<string, unknown>,\n };\n }\n return result;\n }\n}\n\n/**\n * Bootstraps AppKit with the provided configuration.\n *\n * Initializes telemetry, cache, and service context, then registers plugins\n * in phase order (core, normal, deferred) and awaits their setup.\n * If a `onPluginsReady` callback is provided it runs after plugin setup but\n * before the server starts, giving you access to the full appkit handle\n * for registering custom routes or performing async setup.\n * The returned object maps each plugin name to its `exports()` API,\n * with an `asUser(req)` method for user-scoped execution.\n *\n * @returns A `PluginMap` keyed by plugin name with typed exports\n *\n * @example Minimal server\n * ```ts\n * import { createApp, server } from \"@databricks/appkit\";\n *\n * await createApp({\n * plugins: [server()],\n * });\n * ```\n *\n * @example Server with custom routes via onPluginsReady\n * ```ts\n * import { createApp, server, analytics } from \"@databricks/appkit\";\n *\n * await createApp({\n * plugins: [server(), analytics({})],\n * onPluginsReady(appkit) {\n * appkit.server.extend((app) => {\n * app.get(\"/custom\", (_req, res) => res.json({ ok: true }));\n * });\n * },\n * });\n * ```\n */\nexport async function createApp<\n T extends PluginData<PluginConstructor, unknown, string>[],\n>(\n config: {\n plugins?: T;\n telemetry?: TelemetryConfig;\n cache?: CacheConfig;\n client?: WorkspaceClient;\n onPluginsReady?: (appkit: PluginMap<T>) => void | Promise<void>;\n disableInternalTelemetry?: boolean;\n } = {},\n): Promise<PluginMap<T>> {\n return AppKit._createApp(config);\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;cAY8D;AAa9D,MAAM,SAAS,aAAa,SAAS;AAErC,IAAa,SAAb,MAAa,OAAwC;CACnD,mBAA+C,EAAE;CACjD,iBAAkC,EAAE;CACpC;CAEA,AAAQ,YAAY,QAA+B;EACjD,MAAM,EAAE,SAAS,GAAG,iBAAiB;AAErC,QAAKA,UAAW,IAAI,eAAe;EAEnC,MAAM,gBAAgB,OAAO,QAAQ,QAAQ;EAE7C,MAAM,cAAc,cAAc,QAAQ,CAAC,GAAG,OAAO;AACnD,WAAQ,GAAG,QAAQ,SAAS,cAAc;IAC1C;EACF,MAAM,gBAAgB,cAAc,QACjC,CAAC,GAAG,QAAQ,GAAG,QAAQ,SAAS,cAAc,SAChD;EACD,MAAM,kBAAkB,cAAc,QACnC,CAAC,GAAG,QAAQ,GAAG,QAAQ,SAAS,cAAc,WAChD;AAED,OAAK,MAAM,CAAC,MAAM,eAAe,YAC/B,KAAI,WACF,MAAK,wBAAwB,cAAc,MAAM,YAAY,EAC3D,SAAS,MAAKA,SACf,CAAC;AAIN,OAAK,MAAM,CAAC,MAAM,eAAe,cAC/B,KAAI,WACF,MAAK,wBAAwB,cAAc,MAAM,YAAY,EAC3D,SAAS,MAAKA,SACf,CAAC;AAIN,OAAK,MAAM,CAAC,MAAM,eAAe,gBAC/B,KAAI,WACF,MAAK,wBAAwB,cAAc,MAAM,YAAY,EAC3D,SAAS,MAAKA,SACf,CAAC;;CAKR,AAAQ,wBACN,QACA,MACA,YACA,WACA;EACA,MAAM,EAAE,QAAQ,QAAQ,QAAQ,iBAAiB;EACjD,MAAM,aAAa;GACjB,GAAG;GACH,GAAG,OAAO;GACV,GAAG;GACH;GACA,GAAG;GACJ;EACD,MAAM,iBAAiB,IAAI,OAAO,WAAW;AAE7C,MAAI,OAAO,eAAe,kBAAkB,WAC1C,gBAAe,cAAc;GAC3B,SAAS,MAAKA;GACd,iBAAiB,WAAW;GAC7B,CAAC;AAGJ,QAAKC,gBAAiB,QAAQ;AAE9B,QAAKD,QAAS,eAAe,MAAM,eAAe;AAClD,MAAI,eAAe,eAAe,CAChC,OAAKA,QAAS,qBAAqB,MAAM,eAAe;AAG1D,QAAKE,cAAe,KAAK,eAAe,OAAO,CAAC;EAEhD,MAAM,OAAO;AAEb,SAAO,eAAe,MAAM,MAAM;GAChC,MAAM;IACJ,MAAM,SAAS,MAAKD,gBAAiB;AACrC,WAAO,KAAK,eAAe,OAAO;;GAEpC,YAAY;GACb,CAAC;;;;;;CAOJ,AAAQ,kBACN,SACA,SACA;AACA,OAAK,MAAM,OAAO,SAAS;AACzB,OAAI,CAAC,OAAO,OAAO,SAAS,IAAI,CAAE;GAClC,MAAM,MAAM,QAAQ;AACpB,OAAI,OAAO,QAAQ,WACjB,SAAQ,OAAQ,IAAwC,KAAK,QAAQ;YAC5D,OAAO,cAAc,IAAI,CAClC,MAAK,kBAAkB,KAAgC,QAAQ;;;;;;;;;CAWrE,AAAQ,yBACN,SACA,aACA;AACA,OAAK,MAAM,OAAO,SAAS;AACzB,OAAI,CAAC,OAAO,OAAO,SAAS,IAAI,CAAE;GAClC,MAAM,MAAM,QAAQ;AACpB,OAAI,OAAO,QAAQ,YAAY;IAC7B,MAAM,KAAK;AACX,YAAQ,QAAQ,GAAG,SACjB,iBAAiB,mBAAmB,GAAG,GAAG,KAAK,CAAC;cACzC,OAAO,cAAc,IAAI,CAClC,MAAK,yBACH,KACA,YACD;;;;;;;;;;;CAaP,AAAQ,eAAqC,QAAW;EAEtD,MAAM,gBAAgB,OAAO,WAAW,IAAI,EAAE;AAG9C,MAAI,OAAO,kBAAkB,WAC3B,QAAO;EAGT,MAAM,aAAa;AACnB,OAAK,kBAAkB,YAAY,OAAO;AAG1C,MAAI,OAAQ,OAAe,WAAW,WACpC,QAAO;AAGT,SAAO;GACL,GAAG;GAMH,SAAS,QAAmC;IAC1C,MAAM,aAAc,OAAe,OAAO,IAAI;IAC9C,MAAM,cAAe,WACnB;IAEF,MAAM,cAAe,OAAO,WAAW,IAAI,EAAE;AAO7C,QAAI,YACF,MAAK,yBAAyB,aAAa,YAAY;QAGvD,MAAK,kBAAkB,aAAa,WAAW;AAEjD,WAAO;;GAEV;;;;;CAMH,OAAe,cACb,OACkC;AAClC,MAAI,OAAO,UAAU,YAAY,UAAU,KAAM,QAAO;EACxD,MAAM,QAAQ,OAAO,eAAe,MAAM;AAC1C,SAAO,UAAU,OAAO,aAAa,UAAU;;CAGjD,aAAa,WAGX,SAOI,EAAE,EACiB;AAEvB,mBAAiB,WAAW,QAAQ,UAAU;AAC9C,QAAM,aAAa,YAAY,QAAQ,MAAM;EAE7C,MAAM,aAAa,OAAO;EAG1B,MAAM,WAAW,IAAI,kBAAkB;AACvC,WAAS,iBAAiB,WAAW;EAGrC,MAAM,iBAAiB,SACpB,aAAa,CACb,MAAM,MAAM,EAAE,SAAS,aAAa,cAAc;AACrD,QAAM,eAAe,WACnB,EAAE,aAAa,gBAAgB,EAC/B,QAAQ,OACT;AAGD,WAAS,mBAAmB;EAO5B,MAAM,WAAW,IAAI,OAJA,EACnB,SAFsB,OAAO,eAAe,WAAW,EAGxD,CAEwC;AAEzC,QAAM,QAAQ,IAAI,UAASC,cAAe;AAC1C,QAAM,UAASF,QAAS,cAAc,iBAAiB;EAEvD,MAAM,SAAS;AAEf,MAAI,OAAO,gBAAgB;AACzB,UAAO,MAAM,8BAA8B;AAC3C,SAAM,OAAO,eAAe,OAAO;AACnC,UAAO,MAAM,gCAAgC;;AAG/C,MAAI,2BAA2B,OAAO,CACpC,QAAO,4BAA4B;EAGrC,MAAM,eAAe,UAASC,gBAAiB;AAC/C,MAAI,gBAAgB,OAAQ,aAAqB,UAAU,WACzD,OAAO,aAAqB,OAAO;AAGrC,SAAO;;CAGT,OAAe,6BAAmC;EAChD,MAAM,aAAa,eAAe,KAAK;EACvC,MAAM,WAAW,kBAAkB,WAAW;GAC5C,aAAa,WAAW;GACxB,QAAQ,WAAW;GACnB,OAAO,QAAQ,IAAI,wBAAwB;GAC3C,eAAeE;GAChB,CAAC;AACF,WAAS,OAAO;AAChB,WAAS,aAAa,CAAC,YAAY,GAAG;;CAGxC,OAAe,eACb,SACA;EACA,MAAM,SAAyB,EAAE;AACjC,OAAK,MAAM,iBAAiB,QAC1B,QAAO,cAAc,QAAQ;GAC3B,QAAQ,cAAc;GACtB,QAAQ,cAAc;GACvB;AAEH,SAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAwCX,eAAsB,UAGpB,SAOI,EAAE,EACiB;AACvB,QAAO,OAAO,WAAW,OAAO"}
1
+ {"version":3,"file":"appkit.js","names":["#context","#pluginInstances","#setupPromises","productVersion"],"sources":["../../src/core/appkit.ts"],"sourcesContent":["import type { WorkspaceClient } from \"@databricks/sdk-experimental\";\nimport type {\n BasePlugin,\n CacheConfig,\n InputPluginMap,\n OptionalConfigPluginDef,\n PluginConstructor,\n PluginData,\n PluginMap,\n} from \"shared\";\nimport { version as productVersion } from \"../../package.json\";\nimport { CacheManager } from \"../cache\";\nimport { ServiceContext } from \"../context\";\nimport {\n isInternalTelemetryEnabled,\n TelemetryReporter,\n} from \"../internal-telemetry\";\nimport { createLogger } from \"../logging/logger\";\nimport { isPlainObject } from \"../plugin/plugin\";\nimport { ResourceRegistry, ResourceType } from \"../registry\";\nimport type { TelemetryConfig } from \"../telemetry\";\nimport { TelemetryManager } from \"../telemetry\";\nimport { isToolProvider, PluginContext } from \"./plugin-context\";\n\nconst logger = createLogger(\"appkit\");\n\nexport class AppKit<TPlugins extends InputPluginMap> {\n #pluginInstances: Record<string, BasePlugin> = {};\n #setupPromises: Promise<void>[] = [];\n #context: PluginContext;\n\n private constructor(config: { plugins: TPlugins }) {\n const { plugins, ...globalConfig } = config;\n\n this.#context = new PluginContext();\n\n const pluginEntries = Object.entries(plugins);\n\n const corePlugins = pluginEntries.filter(([_, p]) => {\n return (p?.plugin?.phase ?? \"normal\") === \"core\";\n });\n const normalPlugins = pluginEntries.filter(\n ([_, p]) => (p?.plugin?.phase ?? \"normal\") === \"normal\",\n );\n const deferredPlugins = pluginEntries.filter(\n ([_, p]) => (p?.plugin?.phase ?? \"normal\") === \"deferred\",\n );\n\n for (const [name, pluginData] of corePlugins) {\n if (pluginData) {\n this.createAndRegisterPlugin(globalConfig, name, pluginData, {\n context: this.#context,\n });\n }\n }\n\n for (const [name, pluginData] of normalPlugins) {\n if (pluginData) {\n this.createAndRegisterPlugin(globalConfig, name, pluginData, {\n context: this.#context,\n });\n }\n }\n\n for (const [name, pluginData] of deferredPlugins) {\n if (pluginData) {\n this.createAndRegisterPlugin(globalConfig, name, pluginData, {\n context: this.#context,\n });\n }\n }\n }\n\n private createAndRegisterPlugin<T extends PluginConstructor>(\n config: Omit<{ plugins: TPlugins }, \"plugins\">,\n name: string,\n pluginData: OptionalConfigPluginDef<T>,\n extraData?: Record<string, unknown>,\n ) {\n const { plugin: Plugin, config: pluginConfig } = pluginData;\n const baseConfig = {\n ...config,\n ...Plugin.DEFAULT_CONFIG,\n ...pluginConfig,\n name,\n ...extraData,\n };\n const pluginInstance = new Plugin(baseConfig);\n\n if (typeof pluginInstance.attachContext === \"function\") {\n pluginInstance.attachContext({\n context: this.#context,\n telemetryConfig: baseConfig.telemetry,\n });\n }\n\n this.#pluginInstances[name] = pluginInstance;\n\n this.#context.registerPlugin(name, pluginInstance);\n if (isToolProvider(pluginInstance)) {\n this.#context.registerToolProvider(name, pluginInstance);\n }\n\n this.#setupPromises.push(pluginInstance.setup());\n\n const self = this;\n\n Object.defineProperty(this, name, {\n get() {\n const plugin = self.#pluginInstances[name];\n return self.wrapWithAsUser(plugin);\n },\n enumerable: true,\n });\n }\n\n /**\n * Binds all function properties in an exports object to the given context.\n * Recurses into plain objects to handle nested APIs (e.g., volume APIs).\n */\n private bindExportMethods(\n exports: Record<string, unknown>,\n context: BasePlugin,\n ) {\n for (const key in exports) {\n if (!Object.hasOwn(exports, key)) continue;\n const val = exports[key];\n if (typeof val === \"function\") {\n exports[key] = (val as (...args: unknown[]) => unknown).bind(context);\n } else if (isPlainObject(val)) {\n this.bindExportMethods(val as Record<string, unknown>, context);\n }\n }\n }\n\n /**\n * Wraps a plugin's exports with an `asUser` method that returns\n * a user-scoped version of the exports.\n *\n * When `exports()` returns a callable (function), it is returned as-is\n * since the plugin manages its own `asUser` per-call (e.g. files plugin).\n * When it returns a plain object, the standard `asUser` wrapper is added.\n *\n * The OBO-side wrapping lives inside `Plugin.asUser` — calling\n * `plugin.asUser(req).exports()` returns exports whose functions already\n * run inside the user's AsyncLocalStorage scope. AppKit only adapts the\n * shape; it does not own the user-context concept.\n */\n private wrapWithAsUser<T extends BasePlugin>(plugin: T) {\n // If plugin doesn't implement exports(), return empty object\n const pluginExports = plugin.exports?.() ?? {};\n\n // If exports is a function, the plugin manages its own asUser pattern\n if (typeof pluginExports === \"function\") {\n return pluginExports;\n }\n\n const objExports = pluginExports as Record<string, unknown>;\n this.bindExportMethods(objExports, plugin);\n\n // If plugin doesn't support asUser (no asUser method), return exports as-is\n if (typeof (plugin as any).asUser !== \"function\") {\n return objExports;\n }\n\n return {\n ...objExports,\n /**\n * Execute operations using the user's identity from the request.\n * Returns user-scoped exports where all methods execute with the\n * user's Databricks credentials instead of the service principal.\n */\n asUser: (req: import(\"express\").Request) =>\n (plugin as any).asUser(req).exports() as Record<string, unknown>,\n };\n }\n\n static async _createApp<\n T extends PluginData<PluginConstructor, unknown, string>[],\n >(\n config: {\n plugins?: T;\n telemetry?: TelemetryConfig;\n cache?: CacheConfig;\n client?: WorkspaceClient;\n onPluginsReady?: (appkit: PluginMap<T>) => void | Promise<void>;\n disableInternalTelemetry?: boolean;\n } = {},\n ): Promise<PluginMap<T>> {\n // Initialize core services\n TelemetryManager.initialize(config?.telemetry);\n await CacheManager.getInstance(config?.cache);\n\n const rawPlugins = config.plugins as T;\n\n // Collect manifest resources via registry\n const registry = new ResourceRegistry();\n registry.collectResources(rawPlugins);\n\n // Derive ServiceContext needs from what manifests declared\n const needsWarehouse = registry\n .getRequired()\n .some((r) => r.type === ResourceType.SQL_WAREHOUSE);\n await ServiceContext.initialize(\n { warehouseId: needsWarehouse },\n config?.client,\n );\n\n // Validate env vars\n registry.enforceValidation();\n\n const preparedPlugins = AppKit.preparePlugins(rawPlugins);\n const mergedConfig = {\n plugins: preparedPlugins,\n };\n\n const instance = new AppKit(mergedConfig);\n\n await Promise.all(instance.#setupPromises);\n await instance.#context.emitLifecycle(\"setup:complete\");\n\n const handle = instance as unknown as PluginMap<T>;\n\n if (config.onPluginsReady) {\n logger.debug(\"Running onPluginsReady hook\");\n await config.onPluginsReady(handle);\n logger.debug(\"onPluginsReady hook completed\");\n }\n\n if (isInternalTelemetryEnabled(config)) {\n AppKit.bootstrapInternalTelemetry();\n }\n\n const serverPlugin = instance.#pluginInstances.server;\n if (serverPlugin && typeof (serverPlugin as any).start === \"function\") {\n await (serverPlugin as any).start();\n }\n\n return handle;\n }\n\n private static bootstrapInternalTelemetry(): void {\n const serviceCtx = ServiceContext.get();\n const reporter = TelemetryReporter.initialize({\n workspaceId: serviceCtx.workspaceId,\n client: serviceCtx.client,\n appId: process.env.DATABRICKS_CLIENT_ID || \"\",\n appkitVersion: productVersion,\n });\n reporter.start();\n reporter.sendStartup().catch(() => {});\n }\n\n private static preparePlugins(\n plugins: PluginData<PluginConstructor, unknown, string>[],\n ) {\n const result: InputPluginMap = {};\n for (const currentPlugin of plugins) {\n result[currentPlugin.name] = {\n plugin: currentPlugin.plugin,\n config: currentPlugin.config as Record<string, unknown>,\n };\n }\n return result;\n }\n}\n\n/**\n * Bootstraps AppKit with the provided configuration.\n *\n * Initializes telemetry, cache, and service context, then registers plugins\n * in phase order (core, normal, deferred) and awaits their setup.\n * If a `onPluginsReady` callback is provided it runs after plugin setup but\n * before the server starts, giving you access to the full appkit handle\n * for registering custom routes or performing async setup.\n * The returned object maps each plugin name to its `exports()` API,\n * with an `asUser(req)` method for user-scoped execution.\n *\n * @returns A `PluginMap` keyed by plugin name with typed exports\n *\n * @example Minimal server\n * ```ts\n * import { createApp, server } from \"@databricks/appkit\";\n *\n * await createApp({\n * plugins: [server()],\n * });\n * ```\n *\n * @example Server with custom routes via onPluginsReady\n * ```ts\n * import { createApp, server, analytics } from \"@databricks/appkit\";\n *\n * await createApp({\n * plugins: [server(), analytics({})],\n * onPluginsReady(appkit) {\n * appkit.server.extend((app) => {\n * app.get(\"/custom\", (_req, res) => res.json({ ok: true }));\n * });\n * },\n * });\n * ```\n */\nexport async function createApp<\n T extends PluginData<PluginConstructor, unknown, string>[],\n>(\n config: {\n plugins?: T;\n telemetry?: TelemetryConfig;\n cache?: CacheConfig;\n client?: WorkspaceClient;\n onPluginsReady?: (appkit: PluginMap<T>) => void | Promise<void>;\n disableInternalTelemetry?: boolean;\n } = {},\n): Promise<PluginMap<T>> {\n return AppKit._createApp(config);\n}\n"],"mappings":"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"}