@databricks/appkit 0.0.2

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 (166) hide show
  1. package/CLAUDE.md +3 -0
  2. package/DCO +25 -0
  3. package/LICENSE +203 -0
  4. package/NOTICE.md +73 -0
  5. package/README.md +35 -0
  6. package/bin/setup-claude.js +190 -0
  7. package/dist/_virtual/rolldown_runtime.js +39 -0
  8. package/dist/analytics/analytics.d.ts +31 -0
  9. package/dist/analytics/analytics.d.ts.map +1 -0
  10. package/dist/analytics/analytics.js +149 -0
  11. package/dist/analytics/analytics.js.map +1 -0
  12. package/dist/analytics/defaults.js +17 -0
  13. package/dist/analytics/defaults.js.map +1 -0
  14. package/dist/analytics/index.js +3 -0
  15. package/dist/analytics/query.js +50 -0
  16. package/dist/analytics/query.js.map +1 -0
  17. package/dist/analytics/types.d.ts +9 -0
  18. package/dist/analytics/types.d.ts.map +1 -0
  19. package/dist/app/index.d.ts +23 -0
  20. package/dist/app/index.d.ts.map +1 -0
  21. package/dist/app/index.js +49 -0
  22. package/dist/app/index.js.map +1 -0
  23. package/dist/appkit/package.js +7 -0
  24. package/dist/appkit/package.js.map +1 -0
  25. package/dist/cache/defaults.js +14 -0
  26. package/dist/cache/defaults.js.map +1 -0
  27. package/dist/cache/index.d.ts +119 -0
  28. package/dist/cache/index.d.ts.map +1 -0
  29. package/dist/cache/index.js +307 -0
  30. package/dist/cache/index.js.map +1 -0
  31. package/dist/cache/storage/defaults.js +16 -0
  32. package/dist/cache/storage/defaults.js.map +1 -0
  33. package/dist/cache/storage/index.js +4 -0
  34. package/dist/cache/storage/memory.js +87 -0
  35. package/dist/cache/storage/memory.js.map +1 -0
  36. package/dist/cache/storage/persistent.js +211 -0
  37. package/dist/cache/storage/persistent.js.map +1 -0
  38. package/dist/connectors/index.js +6 -0
  39. package/dist/connectors/lakebase/client.js +348 -0
  40. package/dist/connectors/lakebase/client.js.map +1 -0
  41. package/dist/connectors/lakebase/defaults.js +13 -0
  42. package/dist/connectors/lakebase/defaults.js.map +1 -0
  43. package/dist/connectors/lakebase/index.js +3 -0
  44. package/dist/connectors/sql-warehouse/client.js +284 -0
  45. package/dist/connectors/sql-warehouse/client.js.map +1 -0
  46. package/dist/connectors/sql-warehouse/defaults.js +12 -0
  47. package/dist/connectors/sql-warehouse/defaults.js.map +1 -0
  48. package/dist/connectors/sql-warehouse/index.js +3 -0
  49. package/dist/core/appkit.d.ts +14 -0
  50. package/dist/core/appkit.d.ts.map +1 -0
  51. package/dist/core/appkit.js +66 -0
  52. package/dist/core/appkit.js.map +1 -0
  53. package/dist/core/index.js +3 -0
  54. package/dist/index.d.ts +15 -0
  55. package/dist/index.js +21 -0
  56. package/dist/index.js.map +1 -0
  57. package/dist/plugin/dev-reader.d.ts +20 -0
  58. package/dist/plugin/dev-reader.d.ts.map +1 -0
  59. package/dist/plugin/dev-reader.js +63 -0
  60. package/dist/plugin/dev-reader.js.map +1 -0
  61. package/dist/plugin/index.js +4 -0
  62. package/dist/plugin/interceptors/cache.js +15 -0
  63. package/dist/plugin/interceptors/cache.js.map +1 -0
  64. package/dist/plugin/interceptors/retry.js +32 -0
  65. package/dist/plugin/interceptors/retry.js.map +1 -0
  66. package/dist/plugin/interceptors/telemetry.js +33 -0
  67. package/dist/plugin/interceptors/telemetry.js.map +1 -0
  68. package/dist/plugin/interceptors/timeout.js +35 -0
  69. package/dist/plugin/interceptors/timeout.js.map +1 -0
  70. package/dist/plugin/plugin.d.ts +43 -0
  71. package/dist/plugin/plugin.d.ts.map +1 -0
  72. package/dist/plugin/plugin.js +119 -0
  73. package/dist/plugin/plugin.js.map +1 -0
  74. package/dist/plugin/to-plugin.d.ts +7 -0
  75. package/dist/plugin/to-plugin.d.ts.map +1 -0
  76. package/dist/plugin/to-plugin.js +12 -0
  77. package/dist/plugin/to-plugin.js.map +1 -0
  78. package/dist/server/base-server.js +24 -0
  79. package/dist/server/base-server.js.map +1 -0
  80. package/dist/server/index.d.ts +100 -0
  81. package/dist/server/index.d.ts.map +1 -0
  82. package/dist/server/index.js +224 -0
  83. package/dist/server/index.js.map +1 -0
  84. package/dist/server/remote-tunnel/denied.html +68 -0
  85. package/dist/server/remote-tunnel/gate.js +51 -0
  86. package/dist/server/remote-tunnel/gate.js.map +1 -0
  87. package/dist/server/remote-tunnel/index.html +165 -0
  88. package/dist/server/remote-tunnel/remote-tunnel-controller.js +100 -0
  89. package/dist/server/remote-tunnel/remote-tunnel-controller.js.map +1 -0
  90. package/dist/server/remote-tunnel/remote-tunnel-manager.js +320 -0
  91. package/dist/server/remote-tunnel/remote-tunnel-manager.js.map +1 -0
  92. package/dist/server/remote-tunnel/wait.html +158 -0
  93. package/dist/server/static-server.js +47 -0
  94. package/dist/server/static-server.js.map +1 -0
  95. package/dist/server/types.d.ts +14 -0
  96. package/dist/server/types.d.ts.map +1 -0
  97. package/dist/server/utils.js +70 -0
  98. package/dist/server/utils.js.map +1 -0
  99. package/dist/server/vite-dev-server.js +103 -0
  100. package/dist/server/vite-dev-server.js.map +1 -0
  101. package/dist/shared/src/cache.d.ts +62 -0
  102. package/dist/shared/src/cache.d.ts.map +1 -0
  103. package/dist/shared/src/execute.d.ts +46 -0
  104. package/dist/shared/src/execute.d.ts.map +1 -0
  105. package/dist/shared/src/plugin.d.ts +50 -0
  106. package/dist/shared/src/plugin.d.ts.map +1 -0
  107. package/dist/shared/src/sql/helpers.d.ts +160 -0
  108. package/dist/shared/src/sql/helpers.d.ts.map +1 -0
  109. package/dist/shared/src/sql/helpers.js +103 -0
  110. package/dist/shared/src/sql/helpers.js.map +1 -0
  111. package/dist/shared/src/sql/types.d.ts +34 -0
  112. package/dist/shared/src/sql/types.d.ts.map +1 -0
  113. package/dist/shared/src/tunnel.d.ts +30 -0
  114. package/dist/shared/src/tunnel.d.ts.map +1 -0
  115. package/dist/stream/arrow-stream-processor.js +154 -0
  116. package/dist/stream/arrow-stream-processor.js.map +1 -0
  117. package/dist/stream/buffers.js +88 -0
  118. package/dist/stream/buffers.js.map +1 -0
  119. package/dist/stream/defaults.js +14 -0
  120. package/dist/stream/defaults.js.map +1 -0
  121. package/dist/stream/index.js +6 -0
  122. package/dist/stream/sse-writer.js +61 -0
  123. package/dist/stream/sse-writer.js.map +1 -0
  124. package/dist/stream/stream-manager.d.ts +27 -0
  125. package/dist/stream/stream-manager.d.ts.map +1 -0
  126. package/dist/stream/stream-manager.js +191 -0
  127. package/dist/stream/stream-manager.js.map +1 -0
  128. package/dist/stream/stream-registry.js +54 -0
  129. package/dist/stream/stream-registry.js.map +1 -0
  130. package/dist/stream/types.js +14 -0
  131. package/dist/stream/types.js.map +1 -0
  132. package/dist/stream/validator.js +25 -0
  133. package/dist/stream/validator.js.map +1 -0
  134. package/dist/telemetry/config.js +20 -0
  135. package/dist/telemetry/config.js.map +1 -0
  136. package/dist/telemetry/index.d.ts +4 -0
  137. package/dist/telemetry/index.js +8 -0
  138. package/dist/telemetry/instrumentations.js +38 -0
  139. package/dist/telemetry/instrumentations.js.map +1 -0
  140. package/dist/telemetry/noop.js +54 -0
  141. package/dist/telemetry/noop.js.map +1 -0
  142. package/dist/telemetry/telemetry-manager.js +113 -0
  143. package/dist/telemetry/telemetry-manager.js.map +1 -0
  144. package/dist/telemetry/telemetry-provider.js +82 -0
  145. package/dist/telemetry/telemetry-provider.js.map +1 -0
  146. package/dist/telemetry/types.d.ts +74 -0
  147. package/dist/telemetry/types.d.ts.map +1 -0
  148. package/dist/type-generator/vite-plugin.d.ts +22 -0
  149. package/dist/type-generator/vite-plugin.d.ts.map +1 -0
  150. package/dist/type-generator/vite-plugin.js +49 -0
  151. package/dist/type-generator/vite-plugin.js.map +1 -0
  152. package/dist/utils/databricks-client-middleware.d.ts +17 -0
  153. package/dist/utils/databricks-client-middleware.d.ts.map +1 -0
  154. package/dist/utils/databricks-client-middleware.js +117 -0
  155. package/dist/utils/databricks-client-middleware.js.map +1 -0
  156. package/dist/utils/env-validator.js +14 -0
  157. package/dist/utils/env-validator.js.map +1 -0
  158. package/dist/utils/index.js +26 -0
  159. package/dist/utils/index.js.map +1 -0
  160. package/dist/utils/merge.js +25 -0
  161. package/dist/utils/merge.js.map +1 -0
  162. package/dist/utils/vite-config-merge.js +22 -0
  163. package/dist/utils/vite-config-merge.js.map +1 -0
  164. package/llms.txt +193 -0
  165. package/package.json +70 -0
  166. package/scripts/postinstall.js +6 -0
@@ -0,0 +1,149 @@
1
+ import { getRequestContext, getWorkspaceClient } from "../utils/databricks-client-middleware.js";
2
+ import { init_utils } from "../utils/index.js";
3
+ import { SQLWarehouseConnector } from "../connectors/sql-warehouse/client.js";
4
+ import "../connectors/index.js";
5
+ import { Plugin } from "../plugin/plugin.js";
6
+ import { toPlugin } from "../plugin/to-plugin.js";
7
+ import "../plugin/index.js";
8
+ import { queryDefaults } from "./defaults.js";
9
+ import { QueryProcessor } from "./query.js";
10
+
11
+ //#region src/analytics/analytics.ts
12
+ init_utils();
13
+ var AnalyticsPlugin = class extends Plugin {
14
+ static {
15
+ this.description = "Analytics plugin for data analysis";
16
+ }
17
+ constructor(config) {
18
+ super(config);
19
+ this.name = "analytics";
20
+ this.envVars = [];
21
+ this.requiresDatabricksClient = true;
22
+ this.config = config;
23
+ this.queryProcessor = new QueryProcessor();
24
+ this.SQLClient = new SQLWarehouseConnector({
25
+ timeout: config.timeout,
26
+ telemetry: config.telemetry
27
+ });
28
+ }
29
+ injectRoutes(router) {
30
+ this.route(router, {
31
+ name: "arrow",
32
+ method: "get",
33
+ path: "/arrow-result/:jobId",
34
+ handler: async (req, res) => {
35
+ await this._handleArrowRoute(req, res);
36
+ }
37
+ });
38
+ this.route(router, {
39
+ name: "arrowAsUser",
40
+ method: "get",
41
+ path: "/users/me/arrow-result/:jobId",
42
+ handler: async (req, res) => {
43
+ await this._handleArrowRoute(req, res, { asUser: true });
44
+ }
45
+ });
46
+ this.route(router, {
47
+ name: "queryAsUser",
48
+ method: "post",
49
+ path: "/users/me/query/:query_key",
50
+ handler: async (req, res) => {
51
+ await this._handleQueryRoute(req, res, { asUser: true });
52
+ }
53
+ });
54
+ this.route(router, {
55
+ name: "query",
56
+ method: "post",
57
+ path: "/query/:query_key",
58
+ handler: async (req, res) => {
59
+ await this._handleQueryRoute(req, res, { asUser: false });
60
+ }
61
+ });
62
+ }
63
+ async _handleArrowRoute(req, res, { asUser = false } = {}) {
64
+ try {
65
+ const { jobId } = req.params;
66
+ const workspaceClient = getWorkspaceClient(asUser);
67
+ console.log(`Processing Arrow job request: ${jobId} for plugin: ${this.name}`);
68
+ const result = await this.getArrowData(workspaceClient, jobId);
69
+ res.setHeader("Content-Type", "application/octet-stream");
70
+ res.setHeader("Content-Length", result.data.length.toString());
71
+ res.setHeader("Cache-Control", "public, max-age=3600");
72
+ console.log(`Sending Arrow buffer: ${result.data.length} bytes for job ${jobId}`);
73
+ res.send(Buffer.from(result.data));
74
+ } catch (error) {
75
+ console.error(`Arrow job error for ${this.name}:`, error);
76
+ res.status(404).json({
77
+ error: error instanceof Error ? error.message : "Arrow job not found",
78
+ plugin: this.name
79
+ });
80
+ }
81
+ }
82
+ async _handleQueryRoute(req, res, { asUser = false } = {}) {
83
+ const { query_key } = req.params;
84
+ const { parameters, format = "JSON" } = req.body;
85
+ const queryParameters = format === "ARROW" ? {
86
+ formatParameters: {
87
+ disposition: "EXTERNAL_LINKS",
88
+ format: "ARROW_STREAM"
89
+ },
90
+ type: "arrow"
91
+ } : { type: "result" };
92
+ const requestContext = getRequestContext();
93
+ const userKey = asUser ? requestContext.userId : requestContext.serviceUserId;
94
+ if (!query_key) {
95
+ res.status(400).json({ error: "query_key is required" });
96
+ return;
97
+ }
98
+ const query = await this.app.getAppQuery(query_key, req, this.devFileReader);
99
+ if (!query) {
100
+ res.status(404).json({ error: "Query not found" });
101
+ return;
102
+ }
103
+ const hashedQuery = this.queryProcessor.hashQuery(query);
104
+ const streamExecutionSettings = { default: {
105
+ ...queryDefaults,
106
+ cache: {
107
+ ...queryDefaults.cache,
108
+ cacheKey: [
109
+ "analytics:query",
110
+ query_key,
111
+ JSON.stringify(parameters),
112
+ JSON.stringify(format),
113
+ hashedQuery,
114
+ userKey
115
+ ]
116
+ }
117
+ } };
118
+ await this.executeStream(res, async (signal) => {
119
+ const processedParams = await this.queryProcessor.processQueryParams(query, parameters);
120
+ const result = await this.query(query, processedParams, queryParameters.formatParameters, signal, { asUser });
121
+ return {
122
+ type: queryParameters.type,
123
+ ...result
124
+ };
125
+ }, streamExecutionSettings, userKey);
126
+ }
127
+ async query(query, parameters, formatParameters, signal, { asUser = false } = {}) {
128
+ const requestContext = getRequestContext();
129
+ const workspaceClient = getWorkspaceClient(asUser);
130
+ const { statement, parameters: sqlParameters } = this.queryProcessor.convertToSQLParameters(query, parameters);
131
+ return (await this.SQLClient.executeStatement(workspaceClient, {
132
+ statement,
133
+ warehouse_id: await requestContext.warehouseId,
134
+ parameters: sqlParameters,
135
+ ...formatParameters
136
+ }, signal)).result;
137
+ }
138
+ async getArrowData(workspaceClient, jobId, signal) {
139
+ return await this.SQLClient.getArrowData(workspaceClient, jobId, signal);
140
+ }
141
+ async shutdown() {
142
+ this.streamManager.abortAll();
143
+ }
144
+ };
145
+ const analytics = toPlugin(AnalyticsPlugin, "analytics");
146
+
147
+ //#endregion
148
+ export { AnalyticsPlugin, analytics };
149
+ //# sourceMappingURL=analytics.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"analytics.js","names":["streamExecutionSettings: StreamExecutionSettings"],"sources":["../../src/analytics/analytics.ts"],"sourcesContent":["import type { WorkspaceClient } from \"@databricks/sdk-experimental\";\nimport type {\n IAppRouter,\n PluginExecuteConfig,\n SQLTypeMarker,\n StreamExecutionSettings,\n} from \"shared\";\nimport { SQLWarehouseConnector } from \"../connectors\";\nimport { Plugin, toPlugin } from \"../plugin\";\nimport type { Request, Response } from \"../utils\";\nimport { getRequestContext, getWorkspaceClient } from \"../utils\";\nimport { queryDefaults } from \"./defaults\";\nimport { QueryProcessor } from \"./query\";\nimport type {\n AnalyticsQueryResponse,\n IAnalyticsConfig,\n IAnalyticsQueryRequest,\n} from \"./types\";\n\nexport class AnalyticsPlugin extends Plugin {\n name = \"analytics\";\n envVars = [];\n requiresDatabricksClient = true;\n\n protected static description = \"Analytics plugin for data analysis\";\n protected declare config: IAnalyticsConfig;\n\n // analytics services\n private SQLClient: SQLWarehouseConnector;\n private queryProcessor: QueryProcessor;\n\n constructor(config: IAnalyticsConfig) {\n super(config);\n this.config = config;\n this.queryProcessor = new QueryProcessor();\n\n this.SQLClient = new SQLWarehouseConnector({\n timeout: config.timeout,\n telemetry: config.telemetry,\n });\n }\n\n injectRoutes(router: IAppRouter) {\n this.route(router, {\n name: \"arrow\",\n method: \"get\",\n path: \"/arrow-result/:jobId\",\n handler: async (req: Request, res: Response) => {\n await this._handleArrowRoute(req, res);\n },\n });\n\n this.route(router, {\n name: \"arrowAsUser\",\n method: \"get\",\n path: \"/users/me/arrow-result/:jobId\",\n handler: async (req: Request, res: Response) => {\n await this._handleArrowRoute(req, res, { asUser: true });\n },\n });\n\n this.route<AnalyticsQueryResponse>(router, {\n name: \"queryAsUser\",\n method: \"post\",\n path: \"/users/me/query/:query_key\",\n handler: async (req: Request, res: Response) => {\n await this._handleQueryRoute(req, res, { asUser: true });\n },\n });\n\n this.route<AnalyticsQueryResponse>(router, {\n name: \"query\",\n method: \"post\",\n path: \"/query/:query_key\",\n handler: async (req: Request, res: Response) => {\n await this._handleQueryRoute(req, res, { asUser: false });\n },\n });\n }\n\n private async _handleArrowRoute(\n req: Request,\n res: Response,\n { asUser = false }: { asUser?: boolean } = {},\n ): Promise<void> {\n try {\n const { jobId } = req.params;\n\n const workspaceClient = getWorkspaceClient(asUser);\n\n console.log(\n `Processing Arrow job request: ${jobId} for plugin: ${this.name}`,\n );\n\n const result = await this.getArrowData(workspaceClient, jobId);\n\n res.setHeader(\"Content-Type\", \"application/octet-stream\");\n res.setHeader(\"Content-Length\", result.data.length.toString());\n res.setHeader(\"Cache-Control\", \"public, max-age=3600\");\n\n console.log(\n `Sending Arrow buffer: ${result.data.length} bytes for job ${jobId}`,\n );\n res.send(Buffer.from(result.data));\n } catch (error) {\n console.error(`Arrow job error for ${this.name}:`, error);\n res.status(404).json({\n error: error instanceof Error ? error.message : \"Arrow job not found\",\n plugin: this.name,\n });\n }\n }\n\n private async _handleQueryRoute(\n req: Request,\n res: Response,\n { asUser = false }: { asUser?: boolean } = {},\n ): Promise<void> {\n const { query_key } = req.params;\n const { parameters, format = \"JSON\" } = req.body as IAnalyticsQueryRequest;\n const queryParameters =\n format === \"ARROW\"\n ? {\n formatParameters: {\n disposition: \"EXTERNAL_LINKS\",\n format: \"ARROW_STREAM\",\n },\n type: \"arrow\",\n }\n : {\n type: \"result\",\n };\n\n const requestContext = getRequestContext();\n const userKey = asUser\n ? requestContext.userId\n : requestContext.serviceUserId;\n\n if (!query_key) {\n res.status(400).json({ error: \"query_key is required\" });\n return;\n }\n\n const query = await this.app.getAppQuery(\n query_key,\n req,\n this.devFileReader,\n );\n\n if (!query) {\n res.status(404).json({ error: \"Query not found\" });\n return;\n }\n\n const hashedQuery = this.queryProcessor.hashQuery(query);\n\n const defaultConfig: PluginExecuteConfig = {\n ...queryDefaults,\n cache: {\n ...queryDefaults.cache,\n cacheKey: [\n \"analytics:query\",\n query_key,\n JSON.stringify(parameters),\n JSON.stringify(format),\n hashedQuery,\n userKey,\n ],\n },\n };\n\n const streamExecutionSettings: StreamExecutionSettings = {\n default: defaultConfig,\n };\n\n await this.executeStream(\n res,\n async (signal) => {\n const processedParams = await this.queryProcessor.processQueryParams(\n query,\n parameters,\n );\n\n const result = await this.query(\n query,\n processedParams,\n queryParameters.formatParameters,\n signal,\n {\n asUser,\n },\n );\n\n return { type: queryParameters.type, ...result };\n },\n streamExecutionSettings,\n userKey,\n );\n }\n\n async query(\n query: string,\n parameters?: Record<string, SQLTypeMarker | null | undefined>,\n formatParameters?: Record<string, any>,\n signal?: AbortSignal,\n { asUser = false }: { asUser?: boolean } = {},\n ): Promise<any> {\n const requestContext = getRequestContext();\n const workspaceClient = getWorkspaceClient(asUser);\n\n const { statement, parameters: sqlParameters } =\n this.queryProcessor.convertToSQLParameters(query, parameters);\n\n const response = await this.SQLClient.executeStatement(\n workspaceClient,\n {\n statement,\n warehouse_id: await requestContext.warehouseId,\n parameters: sqlParameters,\n ...formatParameters,\n },\n signal,\n );\n\n return response.result;\n }\n\n // If we need arrow stream in more plugins we can define this as a base method in the core plugin class\n // and have a generic endpoint for each plugin that consumes this arrow data.\n protected async getArrowData(\n workspaceClient: WorkspaceClient,\n jobId: string,\n signal?: AbortSignal,\n ): Promise<ReturnType<typeof this.SQLClient.getArrowData>> {\n return await this.SQLClient.getArrowData(workspaceClient, jobId, signal);\n }\n\n async shutdown(): Promise<void> {\n this.streamManager.abortAll();\n }\n}\n\nexport const analytics = toPlugin<\n typeof AnalyticsPlugin,\n IAnalyticsConfig,\n \"analytics\"\n>(AnalyticsPlugin, \"analytics\");\n"],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ //#region src/analytics/defaults.ts
2
+ const queryDefaults = {
3
+ cache: {
4
+ enabled: true,
5
+ ttl: 3600
6
+ },
7
+ retry: {
8
+ enabled: true,
9
+ initialDelay: 1500,
10
+ attempts: 3
11
+ },
12
+ timeout: 18e3
13
+ };
14
+
15
+ //#endregion
16
+ export { queryDefaults };
17
+ //# sourceMappingURL=defaults.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"defaults.js","names":["queryDefaults: PluginExecuteConfig"],"sources":["../../src/analytics/defaults.ts"],"sourcesContent":["import type { PluginExecuteConfig } from \"shared\";\n\nexport const queryDefaults: PluginExecuteConfig = {\n cache: {\n enabled: true,\n ttl: 3600,\n },\n retry: {\n enabled: true,\n initialDelay: 1500,\n attempts: 3,\n },\n timeout: 18000,\n};\n"],"mappings":";AAEA,MAAaA,gBAAqC;CAChD,OAAO;EACL,SAAS;EACT,KAAK;EACN;CACD,OAAO;EACL,SAAS;EACT,cAAc;EACd,UAAU;EACX;CACD,SAAS;CACV"}
@@ -0,0 +1,3 @@
1
+ import { AnalyticsPlugin, analytics } from "./analytics.js";
2
+
3
+ export { };
@@ -0,0 +1,50 @@
1
+ import { isSQLTypeMarker, sql } from "../shared/src/sql/helpers.js";
2
+ import { getRequestContext } from "../utils/databricks-client-middleware.js";
3
+ import { init_utils } from "../utils/index.js";
4
+ import { createHash } from "node:crypto";
5
+
6
+ //#region src/analytics/query.ts
7
+ init_utils();
8
+ var QueryProcessor = class {
9
+ async processQueryParams(query, parameters) {
10
+ const processed = { ...parameters };
11
+ const paramMatches = query.matchAll(/:([a-zA-Z_]\w*)/g);
12
+ if (new Set(Array.from(paramMatches, (m) => m[1])).has("workspaceId") && !processed.workspaceId) {
13
+ const workspaceId = await getRequestContext().workspaceId;
14
+ if (workspaceId) processed.workspaceId = sql.string(workspaceId);
15
+ }
16
+ return processed;
17
+ }
18
+ hashQuery(query) {
19
+ return createHash("md5").update(query).digest("hex");
20
+ }
21
+ convertToSQLParameters(query, parameters) {
22
+ const sqlParameters = [];
23
+ if (parameters) {
24
+ const queryParamMatches = query.matchAll(/:([a-zA-Z_]\w*)/g);
25
+ const queryParams = new Set(Array.from(queryParamMatches, (m) => m[1]));
26
+ for (const key of Object.keys(parameters)) if (!queryParams.has(key)) throw new Error(`Parameter "${key}" not found in query. Valid parameters: ${Array.from(queryParams).join(", ") || "none"}`);
27
+ for (const [key, value] of Object.entries(parameters)) {
28
+ const parameter = this._createParameter(key, value);
29
+ if (parameter) sqlParameters.push(parameter);
30
+ }
31
+ }
32
+ return {
33
+ statement: query,
34
+ parameters: sqlParameters
35
+ };
36
+ }
37
+ _createParameter(key, value) {
38
+ if (value === null || value === void 0) return null;
39
+ if (!isSQLTypeMarker(value)) throw new Error(`Parameter "${key}" must be a SQL type. Use sql.string(), sql.number(), sql.date(), sql.timestamp(), or sql.boolean().`);
40
+ return {
41
+ name: key,
42
+ value: value.value,
43
+ type: value.__sql_type
44
+ };
45
+ }
46
+ };
47
+
48
+ //#endregion
49
+ export { QueryProcessor };
50
+ //# sourceMappingURL=query.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"query.js","names":["sqlHelpers","sqlParameters: sql.StatementParameterListItem[]"],"sources":["../../src/analytics/query.ts"],"sourcesContent":["import { createHash } from \"node:crypto\";\nimport type { sql } from \"@databricks/sdk-experimental\";\nimport { isSQLTypeMarker, type SQLTypeMarker, sql as sqlHelpers } from \"shared\";\nimport { getRequestContext } from \"../utils\";\n\ntype SQLParameterValue = SQLTypeMarker | null | undefined;\n\nexport class QueryProcessor {\n async processQueryParams(\n query: string,\n parameters?: Record<string, SQLParameterValue>,\n ): Promise<Record<string, SQLParameterValue>> {\n const processed = { ...parameters };\n\n // extract all params from the query\n const paramMatches = query.matchAll(/:([a-zA-Z_]\\w*)/g);\n const queryParams = new Set(Array.from(paramMatches, (m) => m[1]));\n\n // auto-inject workspaceId if needed and not provided\n if (queryParams.has(\"workspaceId\") && !processed.workspaceId) {\n const requestContext = getRequestContext();\n const workspaceId = await requestContext.workspaceId;\n if (workspaceId) {\n processed.workspaceId = sqlHelpers.string(workspaceId);\n }\n }\n\n return processed;\n }\n\n hashQuery(query: string): string {\n return createHash(\"md5\").update(query).digest(\"hex\");\n }\n\n convertToSQLParameters(\n query: string,\n parameters?: Record<string, SQLParameterValue>,\n ): { statement: string; parameters: sql.StatementParameterListItem[] } {\n const sqlParameters: sql.StatementParameterListItem[] = [];\n\n if (parameters) {\n // extract all params from the query\n const queryParamMatches = query.matchAll(/:([a-zA-Z_]\\w*)/g);\n const queryParams = new Set(Array.from(queryParamMatches, (m) => m[1]));\n\n // only allow parameters that exist in the query\n for (const key of Object.keys(parameters)) {\n if (!queryParams.has(key)) {\n throw new Error(\n `Parameter \"${key}\" not found in query. Valid parameters: ${\n Array.from(queryParams).join(\", \") || \"none\"\n }`,\n );\n }\n }\n\n // convert parameters to SQL parameters\n for (const [key, value] of Object.entries(parameters)) {\n const parameter = this._createParameter(key, value);\n if (parameter) {\n sqlParameters.push(parameter);\n }\n }\n }\n\n return { statement: query, parameters: sqlParameters };\n }\n\n private _createParameter(\n key: string,\n value: SQLParameterValue,\n ): sql.StatementParameterListItem | null {\n if (value === null || value === undefined) {\n return null;\n }\n\n if (!isSQLTypeMarker(value)) {\n throw new Error(\n `Parameter \"${key}\" must be a SQL type. Use sql.string(), sql.number(), sql.date(), sql.timestamp(), or sql.boolean().`,\n );\n }\n\n return {\n name: key,\n value: value.value,\n type: value.__sql_type,\n };\n }\n}\n"],"mappings":";;;;;;YAG6C;AAI7C,IAAa,iBAAb,MAA4B;CAC1B,MAAM,mBACJ,OACA,YAC4C;EAC5C,MAAM,YAAY,EAAE,GAAG,YAAY;EAGnC,MAAM,eAAe,MAAM,SAAS,mBAAmB;AAIvD,MAHoB,IAAI,IAAI,MAAM,KAAK,eAAe,MAAM,EAAE,GAAG,CAAC,CAGlD,IAAI,cAAc,IAAI,CAAC,UAAU,aAAa;GAE5D,MAAM,cAAc,MADG,mBAAmB,CACD;AACzC,OAAI,YACF,WAAU,cAAcA,IAAW,OAAO,YAAY;;AAI1D,SAAO;;CAGT,UAAU,OAAuB;AAC/B,SAAO,WAAW,MAAM,CAAC,OAAO,MAAM,CAAC,OAAO,MAAM;;CAGtD,uBACE,OACA,YACqE;EACrE,MAAMC,gBAAkD,EAAE;AAE1D,MAAI,YAAY;GAEd,MAAM,oBAAoB,MAAM,SAAS,mBAAmB;GAC5D,MAAM,cAAc,IAAI,IAAI,MAAM,KAAK,oBAAoB,MAAM,EAAE,GAAG,CAAC;AAGvE,QAAK,MAAM,OAAO,OAAO,KAAK,WAAW,CACvC,KAAI,CAAC,YAAY,IAAI,IAAI,CACvB,OAAM,IAAI,MACR,cAAc,IAAI,0CAChB,MAAM,KAAK,YAAY,CAAC,KAAK,KAAK,IAAI,SAEzC;AAKL,QAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,WAAW,EAAE;IACrD,MAAM,YAAY,KAAK,iBAAiB,KAAK,MAAM;AACnD,QAAI,UACF,eAAc,KAAK,UAAU;;;AAKnC,SAAO;GAAE,WAAW;GAAO,YAAY;GAAe;;CAGxD,AAAQ,iBACN,KACA,OACuC;AACvC,MAAI,UAAU,QAAQ,UAAU,OAC9B,QAAO;AAGT,MAAI,CAAC,gBAAgB,MAAM,CACzB,OAAM,IAAI,MACR,cAAc,IAAI,sGACnB;AAGH,SAAO;GACL,MAAM;GACN,OAAO,MAAM;GACb,MAAM,MAAM;GACb"}
@@ -0,0 +1,9 @@
1
+ import { BasePluginConfig } from "../shared/src/plugin.js";
2
+
3
+ //#region src/analytics/types.d.ts
4
+ interface IAnalyticsConfig extends BasePluginConfig {
5
+ timeout?: number;
6
+ }
7
+ //#endregion
8
+ export { IAnalyticsConfig };
9
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","names":[],"sources":["../../src/analytics/types.ts"],"sourcesContent":[],"mappings":";;;UAEiB,gBAAA,SAAyB;;AAA1C"}
@@ -0,0 +1,23 @@
1
+ //#region src/app/index.d.ts
2
+ interface RequestLike {
3
+ query?: Record<string, any>;
4
+ headers: Record<string, string | string[] | undefined>;
5
+ }
6
+ interface DevFileReader {
7
+ readFile(filePath: string, req: RequestLike): Promise<string>;
8
+ }
9
+ declare class AppManager {
10
+ /**
11
+ * Retrieves a query file by key from the queries directory
12
+ * In dev mode with a request context, reads from local filesystem via WebSocket
13
+ * @param queryKey - The query file name (without extension)
14
+ * @param req - Optional request object to detect dev mode
15
+ * @param devFileReader - Optional DevFileReader instance to read files from local filesystem
16
+ * @returns The query content as a string
17
+ * @throws Error if query key is invalid or file not found
18
+ */
19
+ getAppQuery(queryKey: string, req?: RequestLike, devFileReader?: DevFileReader): Promise<string | null>;
20
+ }
21
+ //#endregion
22
+ export { AppManager };
23
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../../src/app/index.ts"],"sourcesContent":[],"mappings":";UAGU,WAAA;EAAA,KAAA,CAAA,EACA,MADW,CAAA,MAAA,EAAA,GAAA,CAAA;EAAA,OAAA,EAEV,MAFU,CAAA,MAAA,EAAA,MAAA,GAAA,MAAA,EAAA,GAAA,SAAA,CAAA;;UAKX,aAAA,CAHC;EAAM,QAAA,CAAA,QAAA,EAAA,MAAA,EAAA,GAAA,EAIiB,WAJjB,CAAA,EAI+B,OAJ/B,CAAA,MAAA,CAAA;AAAA;AAGM,cAIV,UAAA,CAJU;;;;AAIvB;;;;;;sCAYU,6BACU,gBACf"}
@@ -0,0 +1,49 @@
1
+ import fs from "node:fs/promises";
2
+ import path from "node:path";
3
+
4
+ //#region src/app/index.ts
5
+ var AppManager = class {
6
+ /**
7
+ * Retrieves a query file by key from the queries directory
8
+ * In dev mode with a request context, reads from local filesystem via WebSocket
9
+ * @param queryKey - The query file name (without extension)
10
+ * @param req - Optional request object to detect dev mode
11
+ * @param devFileReader - Optional DevFileReader instance to read files from local filesystem
12
+ * @returns The query content as a string
13
+ * @throws Error if query key is invalid or file not found
14
+ */
15
+ async getAppQuery(queryKey, req, devFileReader) {
16
+ if (!queryKey || !/^[a-zA-Z0-9_-]+$/.test(queryKey)) {
17
+ console.error(`Invalid query key format: "${queryKey}". Only alphanumeric characters, underscores, and hyphens are allowed.`);
18
+ return null;
19
+ }
20
+ const queryFilePath = path.join(process.cwd(), "config/queries", `${queryKey}.sql`);
21
+ const resolvedPath = path.resolve(queryFilePath);
22
+ const queriesDir = path.resolve(process.cwd(), "config/queries");
23
+ if (!resolvedPath.startsWith(queriesDir)) {
24
+ console.error(`Invalid query path: path traversal detected`);
25
+ return null;
26
+ }
27
+ if (req?.query?.dev !== void 0 && devFileReader && req) try {
28
+ const relativePath = path.relative(process.cwd(), resolvedPath);
29
+ return await devFileReader.readFile(relativePath, req);
30
+ } catch (error) {
31
+ console.error(`Failed to read query "${queryKey}" from dev tunnel: ${error.message}`);
32
+ return null;
33
+ }
34
+ try {
35
+ return await fs.readFile(resolvedPath, "utf8");
36
+ } catch (error) {
37
+ if (error.code === "ENOENT") {
38
+ console.error(`Query "${queryKey}" not found at path: ${resolvedPath}`);
39
+ return null;
40
+ }
41
+ console.error(`Failed to read query "${queryKey}" from server filesystem: ${error.message}`);
42
+ return null;
43
+ }
44
+ }
45
+ };
46
+
47
+ //#endregion
48
+ export { AppManager };
49
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../src/app/index.ts"],"sourcesContent":["import fs from \"node:fs/promises\";\nimport path from \"node:path\";\n\ninterface RequestLike {\n query?: Record<string, any>;\n headers: Record<string, string | string[] | undefined>;\n}\n\ninterface DevFileReader {\n readFile(filePath: string, req: RequestLike): Promise<string>;\n}\n\nexport class AppManager {\n /**\n * Retrieves a query file by key from the queries directory\n * In dev mode with a request context, reads from local filesystem via WebSocket\n * @param queryKey - The query file name (without extension)\n * @param req - Optional request object to detect dev mode\n * @param devFileReader - Optional DevFileReader instance to read files from local filesystem\n * @returns The query content as a string\n * @throws Error if query key is invalid or file not found\n */\n async getAppQuery(\n queryKey: string,\n req?: RequestLike,\n devFileReader?: DevFileReader,\n ): Promise<string | null> {\n // Security: Sanitize query key to prevent path traversal\n if (!queryKey || !/^[a-zA-Z0-9_-]+$/.test(queryKey)) {\n console.error(\n `Invalid query key format: \"${queryKey}\". Only alphanumeric characters, underscores, and hyphens are allowed.`,\n );\n return null;\n }\n\n const queryFilePath = path.join(\n process.cwd(),\n \"config/queries\",\n `${queryKey}.sql`,\n );\n\n // Security: Validate resolved path is within queries directory\n const resolvedPath = path.resolve(queryFilePath);\n const queriesDir = path.resolve(process.cwd(), \"config/queries\");\n\n if (!resolvedPath.startsWith(queriesDir)) {\n console.error(`Invalid query path: path traversal detected`);\n return null;\n }\n\n // Check if we're in dev mode and should use WebSocket\n const isDevMode = req?.query?.dev !== undefined;\n\n if (isDevMode && devFileReader && req) {\n try {\n // Read from local filesystem via WebSocket tunnel\n const relativePath = path.relative(process.cwd(), resolvedPath);\n return await devFileReader.readFile(relativePath, req);\n } catch (error) {\n console.error(\n `Failed to read query \"${queryKey}\" from dev tunnel: ${(error as Error).message}`,\n );\n return null;\n }\n }\n\n // Production mode: read from server filesystem\n try {\n const query = await fs.readFile(resolvedPath, \"utf8\");\n return query;\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") {\n console.error(`Query \"${queryKey}\" not found at path: ${resolvedPath}`);\n return null;\n }\n console.error(\n `Failed to read query \"${queryKey}\" from server filesystem: ${(error as Error).message}`,\n );\n return null;\n }\n }\n}\n\nexport type { DevFileReader, RequestLike };\n"],"mappings":";;;;AAYA,IAAa,aAAb,MAAwB;;;;;;;;;;CAUtB,MAAM,YACJ,UACA,KACA,eACwB;AAExB,MAAI,CAAC,YAAY,CAAC,mBAAmB,KAAK,SAAS,EAAE;AACnD,WAAQ,MACN,8BAA8B,SAAS,wEACxC;AACD,UAAO;;EAGT,MAAM,gBAAgB,KAAK,KACzB,QAAQ,KAAK,EACb,kBACA,GAAG,SAAS,MACb;EAGD,MAAM,eAAe,KAAK,QAAQ,cAAc;EAChD,MAAM,aAAa,KAAK,QAAQ,QAAQ,KAAK,EAAE,iBAAiB;AAEhE,MAAI,CAAC,aAAa,WAAW,WAAW,EAAE;AACxC,WAAQ,MAAM,8CAA8C;AAC5D,UAAO;;AAMT,MAFkB,KAAK,OAAO,QAAQ,UAErB,iBAAiB,IAChC,KAAI;GAEF,MAAM,eAAe,KAAK,SAAS,QAAQ,KAAK,EAAE,aAAa;AAC/D,UAAO,MAAM,cAAc,SAAS,cAAc,IAAI;WAC/C,OAAO;AACd,WAAQ,MACN,yBAAyB,SAAS,qBAAsB,MAAgB,UACzE;AACD,UAAO;;AAKX,MAAI;AAEF,UADc,MAAM,GAAG,SAAS,cAAc,OAAO;WAE9C,OAAO;AACd,OAAK,MAAgC,SAAS,UAAU;AACtD,YAAQ,MAAM,UAAU,SAAS,uBAAuB,eAAe;AACvE,WAAO;;AAET,WAAQ,MACN,yBAAyB,SAAS,4BAA6B,MAAgB,UAChF;AACD,UAAO"}
@@ -0,0 +1,7 @@
1
+ //#region package.json
2
+ var name = "@databricks/appkit";
3
+ var version = "0.0.2";
4
+
5
+ //#endregion
6
+ export { name, version };
7
+ //# sourceMappingURL=package.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"package.js","names":[],"sources":["../../package.json"],"sourcesContent":[""],"mappings":""}
@@ -0,0 +1,14 @@
1
+ //#region src/cache/defaults.ts
2
+ /** Default configuration for cache */
3
+ const cacheDefaults = {
4
+ enabled: true,
5
+ ttl: 3600,
6
+ maxSize: 1e3,
7
+ cacheKey: [],
8
+ cleanupProbability: .01,
9
+ strictPersistence: false
10
+ };
11
+
12
+ //#endregion
13
+ export { cacheDefaults };
14
+ //# sourceMappingURL=defaults.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"defaults.js","names":["cacheDefaults: CacheConfig"],"sources":["../../src/cache/defaults.ts"],"sourcesContent":["import type { CacheConfig } from \"shared\";\n\n/** Default configuration for cache */\nexport const cacheDefaults: CacheConfig = {\n enabled: true,\n ttl: 3600, // 1 hour\n maxSize: 1000, // 1000 entries\n cacheKey: [], // no cache key by default\n cleanupProbability: 0.01, // 1% probability of triggering cleanup on each get operation\n strictPersistence: false, // if false, use in-memory storage if lakebase is unavailable\n};\n"],"mappings":";;AAGA,MAAaA,gBAA6B;CACxC,SAAS;CACT,KAAK;CACL,SAAS;CACT,UAAU,EAAE;CACZ,oBAAoB;CACpB,mBAAmB;CACpB"}
@@ -0,0 +1,119 @@
1
+ import { CacheConfig } from "../shared/src/cache.js";
2
+
3
+ //#region src/cache/index.d.ts
4
+
5
+ /**
6
+ * Cache manager class to handle cache operations.
7
+ * Can be used with in-memory storage or persistent storage (Lakebase).
8
+ *
9
+ * The cache is automatically initialized by AppKit. Use `getInstanceSync()` to access
10
+ * the singleton instance after initialization.
11
+ *
12
+ * @example
13
+ * ```typescript
14
+ * const cache = CacheManager.getInstanceSync();
15
+ * const result = await cache.getOrExecute(["users", userId], () => fetchUser(userId), userKey);
16
+ * ```
17
+ */
18
+ declare class CacheManager {
19
+ private static readonly MIN_CLEANUP_INTERVAL_MS;
20
+ private readonly name;
21
+ private static instance;
22
+ private static initPromise;
23
+ private storage;
24
+ private config;
25
+ private inFlightRequests;
26
+ private cleanupInProgress;
27
+ private lastCleanupAttempt;
28
+ private telemetry;
29
+ private telemetryMetrics;
30
+ private constructor();
31
+ /**
32
+ * Get the singleton instance of the cache manager (sync version).
33
+ *
34
+ * Throws if not initialized - ensure AppKit.create() has completed first.
35
+ * @returns CacheManager instance
36
+ */
37
+ static getInstanceSync(): CacheManager;
38
+ /**
39
+ * Initialize and get the singleton instance of the cache manager.
40
+ * Called internally by AppKit - prefer `getInstanceSync()` for plugin access.
41
+ * @param userConfig - User configuration for the cache manager
42
+ * @returns CacheManager instance
43
+ * @internal
44
+ */
45
+ static getInstance(userConfig?: Partial<CacheConfig>): Promise<CacheManager>;
46
+ /**
47
+ * Create a new cache manager instance
48
+ *
49
+ * Storage selection logic:
50
+ * 1. If `storage` provided and healthy → use provided storage
51
+ * 2. If `storage` provided but unhealthy → fallback to InMemory (or disable if strictPersistence)
52
+ * 3. If no `storage` provided and Lakebase available → use Lakebase
53
+ * 4. If no `storage` provided and Lakebase unavailable → fallback to InMemory (or disable if strictPersistence)
54
+ *
55
+ * @param userConfig - User configuration for the cache manager
56
+ * @returns CacheManager instance
57
+ */
58
+ private static create;
59
+ /**
60
+ * Get or execute a function and cache the result
61
+ * @param key - Cache key
62
+ * @param fn - Function to execute
63
+ * @param userKey - User key
64
+ * @param options - Options for the cache
65
+ * @returns Promise of the result
66
+ */
67
+ getOrExecute<T>(key: (string | number | object)[], fn: () => Promise<T>, userKey: string, options?: {
68
+ ttl?: number;
69
+ }): Promise<T>;
70
+ /**
71
+ * Get a cached value
72
+ * @param key - Cache key
73
+ * @returns Promise of the value or null if not found or expired
74
+ */
75
+ get<T>(key: string): Promise<T | null>;
76
+ /** Probabilistically trigger cleanup of expired entries (fire-and-forget) */
77
+ private maybeCleanup;
78
+ /**
79
+ * Set a value in the cache
80
+ * @param key - Cache key
81
+ * @param value - Value to set
82
+ * @param options - Options for the cache
83
+ * @returns Promise of the result
84
+ */
85
+ set<T>(key: string, value: T, options?: {
86
+ ttl?: number;
87
+ }): Promise<void>;
88
+ /**
89
+ * Delete a value from the cache
90
+ * @param key - Cache key
91
+ * @returns Promise of the result
92
+ */
93
+ delete(key: string): Promise<void>;
94
+ /** Clear the cache */
95
+ clear(): Promise<void>;
96
+ /**
97
+ * Check if a value exists in the cache
98
+ * @param key - Cache key
99
+ * @returns Promise of true if the value exists, false otherwise
100
+ */
101
+ has(key: string): Promise<boolean>;
102
+ /**
103
+ * Generate a cache key
104
+ * @param parts - Parts of the key
105
+ * @param userKey - User key
106
+ * @returns Cache key
107
+ */
108
+ generateKey(parts: (string | number | object)[], userKey: string): string;
109
+ /** Close the cache */
110
+ close(): Promise<void>;
111
+ /**
112
+ * Check if the storage is healthy
113
+ * @returns Promise of true if the storage is healthy, false otherwise
114
+ */
115
+ isStorageHealthy(): Promise<boolean>;
116
+ }
117
+ //#endregion
118
+ export { CacheManager };
119
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../../src/cache/index.ts"],"sourcesContent":[],"mappings":";;;;;;AAuBA;;;;;;;;;;;AAwQqC,cAxQxB,YAAA,CAwQwB;0BAAR,uBAAA;mBAkDlB,IAAA;iBAEN,QAAA;iBAawB,WAAA;UAMZ,OAAA;UAUS,MAAA;UA0BT,gBAAA;UAQW,iBAAA;EAAO,QAAA,kBAAA;;;;;;;;;;4BA3UP;;;;;;;;kCAkBX,QAAQ,eACpB,QAAQ;;;;;;;;;;;;;;;;;;;;;;+DAuGC,QAAQ;;MAGjB,QAAQ;;;;;;uBA2FgB,QAAQ;;;;;;;;;;6BAkD1B;;MAEN;;;;;;uBAawB;;WAMZ;;;;;;oBAUS;;;;;;;;;WA0BT;;;;;sBAQW"}