@databricks/appkit 0.5.1 → 0.5.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 (172) hide show
  1. package/dist/appkit/package.js +1 -1
  2. package/dist/cli/commands/docs.js +1 -1
  3. package/dist/cli/commands/docs.js.map +1 -1
  4. package/dist/cli/commands/generate-types.js +5 -0
  5. package/dist/cli/commands/generate-types.js.map +1 -1
  6. package/dist/cli/commands/lint.js.map +1 -1
  7. package/dist/cli/commands/setup.js.map +1 -1
  8. package/dist/cli/index.js +3 -3
  9. package/dist/cli/index.js.map +1 -1
  10. package/dist/context/execution-context.js.map +1 -1
  11. package/dist/context/index.js +1 -1
  12. package/dist/context/index.js.map +1 -1
  13. package/dist/index.d.ts +5 -5
  14. package/dist/index.js +6 -6
  15. package/dist/index.js.map +1 -1
  16. package/dist/plugin/dev-reader.js +1 -1
  17. package/dist/plugin/dev-reader.js.map +1 -1
  18. package/dist/plugin/plugin.d.ts +2 -2
  19. package/dist/plugin/plugin.js +1 -1
  20. package/dist/{analytics → plugins/analytics}/analytics.d.ts +4 -4
  21. package/dist/plugins/analytics/analytics.d.ts.map +1 -0
  22. package/dist/{analytics → plugins/analytics}/analytics.js +9 -9
  23. package/dist/plugins/analytics/analytics.js.map +1 -0
  24. package/dist/{analytics → plugins/analytics}/defaults.js +1 -1
  25. package/dist/plugins/analytics/defaults.js.map +1 -0
  26. package/dist/{analytics → plugins/analytics}/query.js +6 -6
  27. package/dist/plugins/analytics/query.js.map +1 -0
  28. package/dist/plugins/analytics/types.d.ts +9 -0
  29. package/dist/plugins/analytics/types.d.ts.map +1 -0
  30. package/dist/plugins/index.js +5 -0
  31. package/dist/{server → plugins/server}/base-server.js +1 -1
  32. package/dist/plugins/server/base-server.js.map +1 -0
  33. package/dist/{server → plugins/server}/index.d.ts +3 -3
  34. package/dist/plugins/server/index.d.ts.map +1 -0
  35. package/dist/{server → plugins/server}/index.js +10 -10
  36. package/dist/plugins/server/index.js.map +1 -0
  37. package/dist/{server → plugins/server}/remote-tunnel/gate.js +1 -1
  38. package/dist/plugins/server/remote-tunnel/gate.js.map +1 -0
  39. package/dist/{server → plugins/server}/remote-tunnel/remote-tunnel-controller.js +2 -2
  40. package/dist/plugins/server/remote-tunnel/remote-tunnel-controller.js.map +1 -0
  41. package/dist/{server → plugins/server}/remote-tunnel/remote-tunnel-manager.js +2 -2
  42. package/dist/plugins/server/remote-tunnel/remote-tunnel-manager.js.map +1 -0
  43. package/dist/{server → plugins/server}/static-server.js +1 -1
  44. package/dist/plugins/server/static-server.js.map +1 -0
  45. package/dist/{server → plugins/server}/types.d.ts +3 -3
  46. package/dist/plugins/server/types.d.ts.map +1 -0
  47. package/dist/{server → plugins/server}/utils.js +1 -1
  48. package/dist/plugins/server/utils.js.map +1 -0
  49. package/dist/{server → plugins/server}/vite-dev-server.js +6 -6
  50. package/dist/plugins/server/vite-dev-server.js.map +1 -0
  51. package/dist/telemetry/telemetry-provider.js.map +1 -1
  52. package/docs/docs/api/appkit/Class.AppKitError/index.html +3 -3
  53. package/docs/docs/api/appkit/Class.AuthenticationError/index.html +3 -3
  54. package/docs/docs/api/appkit/Class.ConfigurationError/index.html +3 -3
  55. package/docs/docs/api/appkit/Class.ConnectionError/index.html +3 -3
  56. package/docs/docs/api/appkit/Class.ExecutionError/index.html +3 -3
  57. package/docs/docs/api/appkit/Class.InitializationError/index.html +3 -3
  58. package/docs/docs/api/appkit/Class.Plugin/index.html +3 -3
  59. package/docs/docs/api/appkit/Class.ServerError/index.html +3 -3
  60. package/docs/docs/api/appkit/Class.TunnelError/index.html +3 -3
  61. package/docs/docs/api/appkit/Class.ValidationError/index.html +3 -3
  62. package/docs/docs/api/appkit/Function.appKitTypesPlugin/index.html +3 -3
  63. package/docs/docs/api/appkit/Function.createApp/index.html +3 -3
  64. package/docs/docs/api/appkit/Function.getExecutionContext/index.html +3 -3
  65. package/docs/docs/api/appkit/Function.isSQLTypeMarker/index.html +3 -3
  66. package/docs/docs/api/appkit/Interface.BasePluginConfig/index.html +3 -3
  67. package/docs/docs/api/appkit/Interface.CacheConfig/index.html +3 -3
  68. package/docs/docs/api/appkit/Interface.ITelemetry/index.html +3 -3
  69. package/docs/docs/api/appkit/Interface.StreamExecutionSettings/index.html +3 -3
  70. package/docs/docs/api/appkit/Interface.TelemetryConfig/index.html +3 -3
  71. package/docs/docs/api/appkit/TypeAlias.IAppRouter/index.html +3 -3
  72. package/docs/docs/api/appkit/Variable.sql/index.html +3 -3
  73. package/docs/docs/api/appkit/index.html +3 -3
  74. package/docs/docs/api/appkit-ui/data/AreaChart/index.html +3 -3
  75. package/docs/docs/api/appkit-ui/data/BarChart/index.html +3 -3
  76. package/docs/docs/api/appkit-ui/data/DataTable/index.html +3 -3
  77. package/docs/docs/api/appkit-ui/data/DonutChart/index.html +3 -3
  78. package/docs/docs/api/appkit-ui/data/HeatmapChart/index.html +3 -3
  79. package/docs/docs/api/appkit-ui/data/LineChart/index.html +3 -3
  80. package/docs/docs/api/appkit-ui/data/PieChart/index.html +3 -3
  81. package/docs/docs/api/appkit-ui/data/RadarChart/index.html +3 -3
  82. package/docs/docs/api/appkit-ui/data/ScatterChart/index.html +3 -3
  83. package/docs/docs/api/appkit-ui/index.html +3 -3
  84. package/docs/docs/api/appkit-ui/styling/index.html +3 -3
  85. package/docs/docs/api/appkit-ui/ui/Accordion/index.html +3 -3
  86. package/docs/docs/api/appkit-ui/ui/Alert/index.html +3 -3
  87. package/docs/docs/api/appkit-ui/ui/AlertDialog/index.html +3 -3
  88. package/docs/docs/api/appkit-ui/ui/AspectRatio/index.html +3 -3
  89. package/docs/docs/api/appkit-ui/ui/Avatar/index.html +3 -3
  90. package/docs/docs/api/appkit-ui/ui/Badge/index.html +3 -3
  91. package/docs/docs/api/appkit-ui/ui/Breadcrumb/index.html +3 -3
  92. package/docs/docs/api/appkit-ui/ui/Button/index.html +3 -3
  93. package/docs/docs/api/appkit-ui/ui/ButtonGroup/index.html +3 -3
  94. package/docs/docs/api/appkit-ui/ui/Calendar/index.html +3 -3
  95. package/docs/docs/api/appkit-ui/ui/Card/index.html +3 -3
  96. package/docs/docs/api/appkit-ui/ui/Carousel/index.html +3 -3
  97. package/docs/docs/api/appkit-ui/ui/ChartContainer/index.html +3 -3
  98. package/docs/docs/api/appkit-ui/ui/Checkbox/index.html +3 -3
  99. package/docs/docs/api/appkit-ui/ui/Collapsible/index.html +3 -3
  100. package/docs/docs/api/appkit-ui/ui/Command/index.html +3 -3
  101. package/docs/docs/api/appkit-ui/ui/ContextMenu/index.html +3 -3
  102. package/docs/docs/api/appkit-ui/ui/Dialog/index.html +3 -3
  103. package/docs/docs/api/appkit-ui/ui/Drawer/index.html +3 -3
  104. package/docs/docs/api/appkit-ui/ui/DropdownMenu/index.html +3 -3
  105. package/docs/docs/api/appkit-ui/ui/Empty/index.html +3 -3
  106. package/docs/docs/api/appkit-ui/ui/Field/index.html +3 -3
  107. package/docs/docs/api/appkit-ui/ui/FormControl/index.html +3 -3
  108. package/docs/docs/api/appkit-ui/ui/HoverCard/index.html +3 -3
  109. package/docs/docs/api/appkit-ui/ui/Input/index.html +3 -3
  110. package/docs/docs/api/appkit-ui/ui/InputGroup/index.html +3 -3
  111. package/docs/docs/api/appkit-ui/ui/InputOTP/index.html +3 -3
  112. package/docs/docs/api/appkit-ui/ui/Item/index.html +3 -3
  113. package/docs/docs/api/appkit-ui/ui/Kbd/index.html +3 -3
  114. package/docs/docs/api/appkit-ui/ui/Label/index.html +3 -3
  115. package/docs/docs/api/appkit-ui/ui/Menubar/index.html +3 -3
  116. package/docs/docs/api/appkit-ui/ui/NavigationMenu/index.html +3 -3
  117. package/docs/docs/api/appkit-ui/ui/Pagination/index.html +3 -3
  118. package/docs/docs/api/appkit-ui/ui/Popover/index.html +3 -3
  119. package/docs/docs/api/appkit-ui/ui/Progress/index.html +3 -3
  120. package/docs/docs/api/appkit-ui/ui/RadioGroup/index.html +3 -3
  121. package/docs/docs/api/appkit-ui/ui/ResizableHandle/index.html +3 -3
  122. package/docs/docs/api/appkit-ui/ui/ScrollArea/index.html +3 -3
  123. package/docs/docs/api/appkit-ui/ui/Select/index.html +3 -3
  124. package/docs/docs/api/appkit-ui/ui/Separator/index.html +3 -3
  125. package/docs/docs/api/appkit-ui/ui/Sheet/index.html +3 -3
  126. package/docs/docs/api/appkit-ui/ui/Sidebar/index.html +3 -3
  127. package/docs/docs/api/appkit-ui/ui/Skeleton/index.html +3 -3
  128. package/docs/docs/api/appkit-ui/ui/Slider/index.html +3 -3
  129. package/docs/docs/api/appkit-ui/ui/Spinner/index.html +3 -3
  130. package/docs/docs/api/appkit-ui/ui/Switch/index.html +3 -3
  131. package/docs/docs/api/appkit-ui/ui/Table/index.html +3 -3
  132. package/docs/docs/api/appkit-ui/ui/Tabs/index.html +3 -3
  133. package/docs/docs/api/appkit-ui/ui/Textarea/index.html +3 -3
  134. package/docs/docs/api/appkit-ui/ui/Toaster/index.html +3 -3
  135. package/docs/docs/api/appkit-ui/ui/Toggle/index.html +3 -3
  136. package/docs/docs/api/appkit-ui/ui/ToggleGroup/index.html +3 -3
  137. package/docs/docs/api/appkit-ui/ui/Tooltip/index.html +3 -3
  138. package/docs/docs/api/index.html +3 -3
  139. package/docs/docs/app-management/index.html +3 -3
  140. package/docs/docs/architecture/index.html +3 -3
  141. package/docs/docs/category/development/index.html +3 -3
  142. package/docs/docs/configuration/index.html +3 -3
  143. package/docs/docs/core-principles/index.html +3 -3
  144. package/docs/docs/development/index.html +3 -3
  145. package/docs/docs/development/llm-guide/index.html +3 -3
  146. package/docs/docs/development/local-development/index.html +3 -3
  147. package/docs/docs/development/project-setup/index.html +3 -3
  148. package/docs/docs/development/remote-bridge/index.html +3 -3
  149. package/docs/docs/development/type-generation/index.html +3 -3
  150. package/docs/docs/index.html +3 -3
  151. package/docs/docs/plugins/index.html +3 -3
  152. package/package.json +1 -1
  153. package/dist/analytics/analytics.d.ts.map +0 -1
  154. package/dist/analytics/analytics.js.map +0 -1
  155. package/dist/analytics/defaults.js.map +0 -1
  156. package/dist/analytics/query.js.map +0 -1
  157. package/dist/analytics/types.d.ts +0 -9
  158. package/dist/analytics/types.d.ts.map +0 -1
  159. package/dist/server/base-server.js.map +0 -1
  160. package/dist/server/index.d.ts.map +0 -1
  161. package/dist/server/index.js.map +0 -1
  162. package/dist/server/remote-tunnel/gate.js.map +0 -1
  163. package/dist/server/remote-tunnel/remote-tunnel-controller.js.map +0 -1
  164. package/dist/server/remote-tunnel/remote-tunnel-manager.js.map +0 -1
  165. package/dist/server/static-server.js.map +0 -1
  166. package/dist/server/types.d.ts.map +0 -1
  167. package/dist/server/utils.js.map +0 -1
  168. package/dist/server/vite-dev-server.js.map +0 -1
  169. /package/dist/{analytics → plugins/analytics}/index.js +0 -0
  170. /package/dist/{server → plugins/server}/remote-tunnel/denied.html +0 -0
  171. /package/dist/{server → plugins/server}/remote-tunnel/index.html +0 -0
  172. /package/dist/{server → plugins/server}/remote-tunnel/wait.html +0 -0
@@ -1,6 +1,6 @@
1
1
  //#region package.json
2
2
  var name = "@databricks/appkit";
3
- var version = "0.5.1";
3
+ var version = "0.5.2";
4
4
 
5
5
  //#endregion
6
6
  export { name, version };
@@ -1,6 +1,6 @@
1
1
  import fs from "node:fs";
2
- import { fileURLToPath } from "node:url";
3
2
  import path from "node:path";
3
+ import { fileURLToPath } from "node:url";
4
4
  import { Command } from "commander";
5
5
 
6
6
  //#region src/cli/commands/docs.ts
@@ -1 +1 @@
1
- {"version":3,"file":"docs.js","names":[],"sources":["../../../src/cli/commands/docs.ts"],"sourcesContent":["import { Command } from \"commander\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = path.dirname(__filename);\n\nfunction findPackageRoot(): string {\n let dir = __dirname;\n while (dir !== path.parse(dir).root) {\n if (fs.existsSync(path.join(dir, \"package.json\"))) {\n return dir;\n }\n dir = path.dirname(dir);\n }\n throw new Error(\"Could not find package root\");\n}\n\nfunction runDocs(docPath?: string) {\n const packageRoot = findPackageRoot();\n\n if (!docPath) {\n // Display llms.txt by default\n const llmsPath = path.join(packageRoot, \"llms.txt\");\n\n if (!fs.existsSync(llmsPath)) {\n console.error(\"Error: llms.txt not found in package\");\n process.exit(1);\n }\n\n const content = fs.readFileSync(llmsPath, \"utf-8\");\n console.log(content);\n return;\n }\n\n // Handle path - remove leading ./ and / first, then strip prefixes\n let normalizedPath = docPath;\n\n // Strip leading ./ or /\n normalizedPath = normalizedPath.replace(/^\\.\\//, \"\");\n normalizedPath = normalizedPath.replace(/^\\//, \"\");\n\n // Remove /appkit/docs/ or docs/ prefix since files are in packageRoot/docs/\n normalizedPath = normalizedPath.replace(/^appkit\\/docs\\//, \"\");\n normalizedPath = normalizedPath.replace(/^docs\\//, \"\");\n\n const fullPath = path.join(packageRoot, \"docs\", normalizedPath);\n\n if (!fs.existsSync(fullPath)) {\n console.error(`Error: Documentation file not found: ${docPath}`);\n console.error(`Tried: ${fullPath}`);\n process.exit(1);\n }\n\n const content = fs.readFileSync(fullPath, \"utf-8\");\n console.log(content);\n}\n\nexport const docsCommand = new Command(\"docs\")\n .description(\"Display embedded documentation\")\n .argument(\n \"[path]\",\n \"Path to specific documentation file (e.g., /appkit/docs/api/appkit-ui/components/Sidebar.md)\",\n )\n .action(runDocs);\n"],"mappings":";;;;;;AAKA,MAAM,aAAa,cAAc,OAAO,KAAK,IAAI;AACjD,MAAM,YAAY,KAAK,QAAQ,WAAW;AAE1C,SAAS,kBAA0B;CACjC,IAAI,MAAM;AACV,QAAO,QAAQ,KAAK,MAAM,IAAI,CAAC,MAAM;AACnC,MAAI,GAAG,WAAW,KAAK,KAAK,KAAK,eAAe,CAAC,CAC/C,QAAO;AAET,QAAM,KAAK,QAAQ,IAAI;;AAEzB,OAAM,IAAI,MAAM,8BAA8B;;AAGhD,SAAS,QAAQ,SAAkB;CACjC,MAAM,cAAc,iBAAiB;AAErC,KAAI,CAAC,SAAS;EAEZ,MAAM,WAAW,KAAK,KAAK,aAAa,WAAW;AAEnD,MAAI,CAAC,GAAG,WAAW,SAAS,EAAE;AAC5B,WAAQ,MAAM,uCAAuC;AACrD,WAAQ,KAAK,EAAE;;EAGjB,MAAM,UAAU,GAAG,aAAa,UAAU,QAAQ;AAClD,UAAQ,IAAI,QAAQ;AACpB;;CAIF,IAAI,iBAAiB;AAGrB,kBAAiB,eAAe,QAAQ,SAAS,GAAG;AACpD,kBAAiB,eAAe,QAAQ,OAAO,GAAG;AAGlD,kBAAiB,eAAe,QAAQ,mBAAmB,GAAG;AAC9D,kBAAiB,eAAe,QAAQ,WAAW,GAAG;CAEtD,MAAM,WAAW,KAAK,KAAK,aAAa,QAAQ,eAAe;AAE/D,KAAI,CAAC,GAAG,WAAW,SAAS,EAAE;AAC5B,UAAQ,MAAM,wCAAwC,UAAU;AAChE,UAAQ,MAAM,UAAU,WAAW;AACnC,UAAQ,KAAK,EAAE;;CAGjB,MAAM,UAAU,GAAG,aAAa,UAAU,QAAQ;AAClD,SAAQ,IAAI,QAAQ;;AAGtB,MAAa,cAAc,IAAI,QAAQ,OAAO,CAC3C,YAAY,iCAAiC,CAC7C,SACC,UACA,+FACD,CACA,OAAO,QAAQ"}
1
+ {"version":3,"file":"docs.js","names":[],"sources":["../../../src/cli/commands/docs.ts"],"sourcesContent":["import fs from \"node:fs\";\nimport path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { Command } from \"commander\";\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = path.dirname(__filename);\n\nfunction findPackageRoot(): string {\n let dir = __dirname;\n while (dir !== path.parse(dir).root) {\n if (fs.existsSync(path.join(dir, \"package.json\"))) {\n return dir;\n }\n dir = path.dirname(dir);\n }\n throw new Error(\"Could not find package root\");\n}\n\nfunction runDocs(docPath?: string) {\n const packageRoot = findPackageRoot();\n\n if (!docPath) {\n // Display llms.txt by default\n const llmsPath = path.join(packageRoot, \"llms.txt\");\n\n if (!fs.existsSync(llmsPath)) {\n console.error(\"Error: llms.txt not found in package\");\n process.exit(1);\n }\n\n const content = fs.readFileSync(llmsPath, \"utf-8\");\n console.log(content);\n return;\n }\n\n // Handle path - remove leading ./ and / first, then strip prefixes\n let normalizedPath = docPath;\n\n // Strip leading ./ or /\n normalizedPath = normalizedPath.replace(/^\\.\\//, \"\");\n normalizedPath = normalizedPath.replace(/^\\//, \"\");\n\n // Remove /appkit/docs/ or docs/ prefix since files are in packageRoot/docs/\n normalizedPath = normalizedPath.replace(/^appkit\\/docs\\//, \"\");\n normalizedPath = normalizedPath.replace(/^docs\\//, \"\");\n\n const fullPath = path.join(packageRoot, \"docs\", normalizedPath);\n\n if (!fs.existsSync(fullPath)) {\n console.error(`Error: Documentation file not found: ${docPath}`);\n console.error(`Tried: ${fullPath}`);\n process.exit(1);\n }\n\n const content = fs.readFileSync(fullPath, \"utf-8\");\n console.log(content);\n}\n\nexport const docsCommand = new Command(\"docs\")\n .description(\"Display embedded documentation\")\n .argument(\n \"[path]\",\n \"Path to specific documentation file (e.g., /appkit/docs/api/appkit-ui/components/Sidebar.md)\",\n )\n .action(runDocs);\n"],"mappings":";;;;;;AAKA,MAAM,aAAa,cAAc,OAAO,KAAK,IAAI;AACjD,MAAM,YAAY,KAAK,QAAQ,WAAW;AAE1C,SAAS,kBAA0B;CACjC,IAAI,MAAM;AACV,QAAO,QAAQ,KAAK,MAAM,IAAI,CAAC,MAAM;AACnC,MAAI,GAAG,WAAW,KAAK,KAAK,KAAK,eAAe,CAAC,CAC/C,QAAO;AAET,QAAM,KAAK,QAAQ,IAAI;;AAEzB,OAAM,IAAI,MAAM,8BAA8B;;AAGhD,SAAS,QAAQ,SAAkB;CACjC,MAAM,cAAc,iBAAiB;AAErC,KAAI,CAAC,SAAS;EAEZ,MAAM,WAAW,KAAK,KAAK,aAAa,WAAW;AAEnD,MAAI,CAAC,GAAG,WAAW,SAAS,EAAE;AAC5B,WAAQ,MAAM,uCAAuC;AACrD,WAAQ,KAAK,EAAE;;EAGjB,MAAM,UAAU,GAAG,aAAa,UAAU,QAAQ;AAClD,UAAQ,IAAI,QAAQ;AACpB;;CAIF,IAAI,iBAAiB;AAGrB,kBAAiB,eAAe,QAAQ,SAAS,GAAG;AACpD,kBAAiB,eAAe,QAAQ,OAAO,GAAG;AAGlD,kBAAiB,eAAe,QAAQ,mBAAmB,GAAG;AAC9D,kBAAiB,eAAe,QAAQ,WAAW,GAAG;CAEtD,MAAM,WAAW,KAAK,KAAK,aAAa,QAAQ,eAAe;AAE/D,KAAI,CAAC,GAAG,WAAW,SAAS,EAAE;AAC5B,UAAQ,MAAM,wCAAwC,UAAU;AAChE,UAAQ,MAAM,UAAU,WAAW;AACnC,UAAQ,KAAK,EAAE;;CAGjB,MAAM,UAAU,GAAG,aAAa,UAAU,QAAQ;AAClD,SAAQ,IAAI,QAAQ;;AAGtB,MAAa,cAAc,IAAI,QAAQ,OAAO,CAC3C,YAAY,iCAAiC,CAC7C,SACC,UACA,+FACD,CACA,OAAO,QAAQ"}
@@ -1,3 +1,4 @@
1
+ import fs from "node:fs";
1
2
  import path from "node:path";
2
3
  import { Command } from "commander";
3
4
 
@@ -11,6 +12,10 @@ async function runGenerateTypes(rootDir, outFile, warehouseId, options) {
11
12
  const resolvedRootDir = rootDir || process.cwd();
12
13
  const resolvedOutFile = outFile || path.join(process.cwd(), "client/src/appKitTypes.d.ts");
13
14
  const queryFolder = path.join(resolvedRootDir, "config/queries");
15
+ if (!fs.existsSync(queryFolder)) {
16
+ console.warn(`Warning: No queries found at ${queryFolder}. Skipping type generation.`);
17
+ return;
18
+ }
14
19
  const resolvedWarehouseId = warehouseId || process.env.DATABRICKS_WAREHOUSE_ID;
15
20
  if (!resolvedWarehouseId) {
16
21
  console.error("Error: DATABRICKS_WAREHOUSE_ID is not set. Please provide it as an argument or environment variable.");
@@ -1 +1 @@
1
- {"version":3,"file":"generate-types.js","names":[],"sources":["../../../src/cli/commands/generate-types.ts"],"sourcesContent":["import { Command } from \"commander\";\nimport path from \"node:path\";\n\n/**\n * Generate types command implementation\n */\nasync function runGenerateTypes(\n rootDir?: string,\n outFile?: string,\n warehouseId?: string,\n options?: { noCache?: boolean },\n) {\n try {\n // Try to import the type generator from @databricks/appkit\n const { generateFromEntryPoint } = await import(\n \"@databricks/appkit/type-generator\"\n );\n\n const resolvedRootDir = rootDir || process.cwd();\n const resolvedOutFile =\n outFile || path.join(process.cwd(), \"client/src/appKitTypes.d.ts\");\n\n const queryFolder = path.join(resolvedRootDir, \"config/queries\");\n\n const resolvedWarehouseId =\n warehouseId || process.env.DATABRICKS_WAREHOUSE_ID;\n if (!resolvedWarehouseId) {\n console.error(\n \"Error: DATABRICKS_WAREHOUSE_ID is not set. Please provide it as an argument or environment variable.\",\n );\n process.exit(1);\n }\n\n await generateFromEntryPoint({\n queryFolder,\n outFile: resolvedOutFile,\n warehouseId: resolvedWarehouseId,\n noCache: options?.noCache || false,\n });\n } catch (error) {\n if (\n error instanceof Error &&\n error.message.includes(\"Cannot find module\")\n ) {\n console.error(\n \"Error: The 'generate-types' command is only available in @databricks/appkit.\",\n );\n console.error(\"Please install @databricks/appkit to use this command.\");\n process.exit(1);\n }\n throw error;\n }\n}\n\nexport const generateTypesCommand = new Command(\"generate-types\")\n .description(\"Generate TypeScript types from SQL queries\")\n .argument(\"[rootDir]\", \"Root directory of the project\", process.cwd())\n .argument(\n \"[outFile]\",\n \"Output file path\",\n path.join(process.cwd(), \"client/src/appKitTypes.d.ts\"),\n )\n .argument(\"[warehouseId]\", \"Databricks warehouse ID\")\n .option(\"--no-cache\", \"Disable caching for type generation\")\n .action(runGenerateTypes);\n"],"mappings":";;;;;;;AAMA,eAAe,iBACb,SACA,SACA,aACA,SACA;AACA,KAAI;EAEF,MAAM,EAAE,2BAA2B,MAAM,OACvC;EAGF,MAAM,kBAAkB,WAAW,QAAQ,KAAK;EAChD,MAAM,kBACJ,WAAW,KAAK,KAAK,QAAQ,KAAK,EAAE,8BAA8B;EAEpE,MAAM,cAAc,KAAK,KAAK,iBAAiB,iBAAiB;EAEhE,MAAM,sBACJ,eAAe,QAAQ,IAAI;AAC7B,MAAI,CAAC,qBAAqB;AACxB,WAAQ,MACN,uGACD;AACD,WAAQ,KAAK,EAAE;;AAGjB,QAAM,uBAAuB;GAC3B;GACA,SAAS;GACT,aAAa;GACb,SAAS,SAAS,WAAW;GAC9B,CAAC;UACK,OAAO;AACd,MACE,iBAAiB,SACjB,MAAM,QAAQ,SAAS,qBAAqB,EAC5C;AACA,WAAQ,MACN,+EACD;AACD,WAAQ,MAAM,yDAAyD;AACvE,WAAQ,KAAK,EAAE;;AAEjB,QAAM;;;AAIV,MAAa,uBAAuB,IAAI,QAAQ,iBAAiB,CAC9D,YAAY,6CAA6C,CACzD,SAAS,aAAa,iCAAiC,QAAQ,KAAK,CAAC,CACrE,SACC,aACA,oBACA,KAAK,KAAK,QAAQ,KAAK,EAAE,8BAA8B,CACxD,CACA,SAAS,iBAAiB,0BAA0B,CACpD,OAAO,cAAc,sCAAsC,CAC3D,OAAO,iBAAiB"}
1
+ {"version":3,"file":"generate-types.js","names":[],"sources":["../../../src/cli/commands/generate-types.ts"],"sourcesContent":["import fs from \"node:fs\";\nimport path from \"node:path\";\nimport { Command } from \"commander\";\n\n/**\n * Generate types command implementation\n */\nasync function runGenerateTypes(\n rootDir?: string,\n outFile?: string,\n warehouseId?: string,\n options?: { noCache?: boolean },\n) {\n try {\n // Try to import the type generator from @databricks/appkit\n const { generateFromEntryPoint } = await import(\n \"@databricks/appkit/type-generator\"\n );\n\n const resolvedRootDir = rootDir || process.cwd();\n const resolvedOutFile =\n outFile || path.join(process.cwd(), \"client/src/appKitTypes.d.ts\");\n\n const queryFolder = path.join(resolvedRootDir, \"config/queries\");\n if (!fs.existsSync(queryFolder)) {\n console.warn(\n `Warning: No queries found at ${queryFolder}. Skipping type generation.`,\n );\n return;\n }\n\n const resolvedWarehouseId =\n warehouseId || process.env.DATABRICKS_WAREHOUSE_ID;\n if (!resolvedWarehouseId) {\n console.error(\n \"Error: DATABRICKS_WAREHOUSE_ID is not set. Please provide it as an argument or environment variable.\",\n );\n process.exit(1);\n }\n\n await generateFromEntryPoint({\n queryFolder,\n outFile: resolvedOutFile,\n warehouseId: resolvedWarehouseId,\n noCache: options?.noCache || false,\n });\n } catch (error) {\n if (\n error instanceof Error &&\n error.message.includes(\"Cannot find module\")\n ) {\n console.error(\n \"Error: The 'generate-types' command is only available in @databricks/appkit.\",\n );\n console.error(\"Please install @databricks/appkit to use this command.\");\n process.exit(1);\n }\n throw error;\n }\n}\n\nexport const generateTypesCommand = new Command(\"generate-types\")\n .description(\"Generate TypeScript types from SQL queries\")\n .argument(\"[rootDir]\", \"Root directory of the project\", process.cwd())\n .argument(\n \"[outFile]\",\n \"Output file path\",\n path.join(process.cwd(), \"client/src/appKitTypes.d.ts\"),\n )\n .argument(\"[warehouseId]\", \"Databricks warehouse ID\")\n .option(\"--no-cache\", \"Disable caching for type generation\")\n .action(runGenerateTypes);\n"],"mappings":";;;;;;;;AAOA,eAAe,iBACb,SACA,SACA,aACA,SACA;AACA,KAAI;EAEF,MAAM,EAAE,2BAA2B,MAAM,OACvC;EAGF,MAAM,kBAAkB,WAAW,QAAQ,KAAK;EAChD,MAAM,kBACJ,WAAW,KAAK,KAAK,QAAQ,KAAK,EAAE,8BAA8B;EAEpE,MAAM,cAAc,KAAK,KAAK,iBAAiB,iBAAiB;AAChE,MAAI,CAAC,GAAG,WAAW,YAAY,EAAE;AAC/B,WAAQ,KACN,gCAAgC,YAAY,6BAC7C;AACD;;EAGF,MAAM,sBACJ,eAAe,QAAQ,IAAI;AAC7B,MAAI,CAAC,qBAAqB;AACxB,WAAQ,MACN,uGACD;AACD,WAAQ,KAAK,EAAE;;AAGjB,QAAM,uBAAuB;GAC3B;GACA,SAAS;GACT,aAAa;GACb,SAAS,SAAS,WAAW;GAC9B,CAAC;UACK,OAAO;AACd,MACE,iBAAiB,SACjB,MAAM,QAAQ,SAAS,qBAAqB,EAC5C;AACA,WAAQ,MACN,+EACD;AACD,WAAQ,MAAM,yDAAyD;AACvE,WAAQ,KAAK,EAAE;;AAEjB,QAAM;;;AAIV,MAAa,uBAAuB,IAAI,QAAQ,iBAAiB,CAC9D,YAAY,6CAA6C,CACzD,SAAS,aAAa,iCAAiC,QAAQ,KAAK,CAAC,CACrE,SACC,aACA,oBACA,KAAK,KAAK,QAAQ,KAAK,EAAE,8BAA8B,CACxD,CACA,SAAS,iBAAiB,0BAA0B,CACpD,OAAO,cAAc,sCAAsC,CAC3D,OAAO,iBAAiB"}
@@ -1 +1 @@
1
- {"version":3,"file":"lint.js","names":[],"sources":["../../../src/cli/commands/lint.ts"],"sourcesContent":["import { Command } from \"commander\";\nimport { parse, Lang } from \"@ast-grep/napi\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\n\ninterface Rule {\n id: string;\n pattern: string;\n message: string;\n includeTests?: boolean;\n filter?: (code: string) => boolean;\n}\n\nconst rules: Rule[] = [\n {\n id: \"no-double-type-assertion\",\n pattern: \"$X as unknown as $Y\",\n message:\n \"Avoid double type assertion (as unknown as). Use proper type guards or fix the source type.\",\n },\n {\n id: \"no-as-any\",\n pattern: \"$X as any\",\n message:\n 'Avoid \"as any\" type assertion. Use proper typing or unknown with type guards.',\n includeTests: false, // acceptable in test mocks\n },\n {\n id: \"no-array-index-key\",\n pattern: \"key={$IDX}\",\n message:\n \"Avoid using array index as React key. Use a stable unique identifier.\",\n filter: (code) => /key=\\{(idx|index|i)\\}/.test(code),\n },\n {\n id: \"no-parse-float-without-validation\",\n pattern: \"parseFloat($X).toFixed($Y)\",\n message:\n \"parseFloat can return NaN. Validate input or use toNumber() helper from shared/types.ts.\",\n },\n];\n\nfunction isTestFile(filePath: string): boolean {\n return (\n /\\.(test|spec)\\.(ts|tsx)$/.test(filePath) || filePath.includes(\"/tests/\")\n );\n}\n\nfunction findTsFiles(dir: string, files: string[] = []): string[] {\n const entries = fs.readdirSync(dir, { withFileTypes: true });\n\n for (const entry of entries) {\n const fullPath = path.join(dir, entry.name);\n\n if (entry.isDirectory()) {\n if ([\"node_modules\", \"dist\", \"build\", \".git\"].includes(entry.name))\n continue;\n findTsFiles(fullPath, files);\n } else if (entry.isFile() && /\\.(ts|tsx)$/.test(entry.name)) {\n files.push(fullPath);\n }\n }\n\n return files;\n}\n\ninterface Violation {\n file: string;\n line: number;\n column: number;\n rule: string;\n message: string;\n code: string;\n}\n\nfunction lintFile(filePath: string, rules: Rule[]): Violation[] {\n const violations: Violation[] = [];\n const content = fs.readFileSync(filePath, \"utf-8\");\n const lang = filePath.endsWith(\".tsx\") ? Lang.Tsx : Lang.TypeScript;\n const testFile = isTestFile(filePath);\n\n const ast = parse(lang, content);\n const root = ast.root();\n\n for (const rule of rules) {\n // skip rules that don't apply to test files\n if (testFile && rule.includeTests === false) continue;\n\n const matches = root.findAll(rule.pattern);\n\n for (const match of matches) {\n const code = match.text();\n\n if (rule.filter && !rule.filter(code)) continue;\n\n const range = match.range();\n violations.push({\n file: filePath,\n line: range.start.line + 1,\n column: range.start.column + 1,\n rule: rule.id,\n message: rule.message,\n code: code.length > 80 ? `${code.slice(0, 77)}...` : code,\n });\n }\n }\n\n return violations;\n}\n\n/**\n * Lint command implementation\n */\nfunction runLint() {\n const rootDir = process.cwd();\n const files = findTsFiles(rootDir);\n\n console.log(`Scanning ${files.length} TypeScript files...\\n`);\n\n const allViolations: Violation[] = [];\n\n for (const file of files) {\n const violations = lintFile(file, rules);\n allViolations.push(...violations);\n }\n\n if (allViolations.length === 0) {\n console.log(\"No ast-grep lint violations found.\");\n process.exit(0);\n }\n\n console.log(`Found ${allViolations.length} violation(s):\\n`);\n\n for (const v of allViolations) {\n const relPath = path.relative(rootDir, v.file);\n console.log(`${relPath}:${v.line}:${v.column}`);\n console.log(` ${v.rule}: ${v.message}`);\n console.log(` > ${v.code}\\n`);\n }\n\n process.exit(1);\n}\n\nexport const lintCommand = new Command(\"lint\")\n .description(\"Run AST-based linting on TypeScript files\")\n .action(runLint);\n"],"mappings":";;;;;;AAaA,MAAM,QAAgB;CACpB;EACE,IAAI;EACJ,SAAS;EACT,SACE;EACH;CACD;EACE,IAAI;EACJ,SAAS;EACT,SACE;EACF,cAAc;EACf;CACD;EACE,IAAI;EACJ,SAAS;EACT,SACE;EACF,SAAS,SAAS,wBAAwB,KAAK,KAAK;EACrD;CACD;EACE,IAAI;EACJ,SAAS;EACT,SACE;EACH;CACF;AAED,SAAS,WAAW,UAA2B;AAC7C,QACE,2BAA2B,KAAK,SAAS,IAAI,SAAS,SAAS,UAAU;;AAI7E,SAAS,YAAY,KAAa,QAAkB,EAAE,EAAY;CAChE,MAAM,UAAU,GAAG,YAAY,KAAK,EAAE,eAAe,MAAM,CAAC;AAE5D,MAAK,MAAM,SAAS,SAAS;EAC3B,MAAM,WAAW,KAAK,KAAK,KAAK,MAAM,KAAK;AAE3C,MAAI,MAAM,aAAa,EAAE;AACvB,OAAI;IAAC;IAAgB;IAAQ;IAAS;IAAO,CAAC,SAAS,MAAM,KAAK,CAChE;AACF,eAAY,UAAU,MAAM;aACnB,MAAM,QAAQ,IAAI,cAAc,KAAK,MAAM,KAAK,CACzD,OAAM,KAAK,SAAS;;AAIxB,QAAO;;AAYT,SAAS,SAAS,UAAkB,OAA4B;CAC9D,MAAM,aAA0B,EAAE;CAClC,MAAM,UAAU,GAAG,aAAa,UAAU,QAAQ;CAClD,MAAM,OAAO,SAAS,SAAS,OAAO,GAAG,KAAK,MAAM,KAAK;CACzD,MAAM,WAAW,WAAW,SAAS;CAGrC,MAAM,OADM,MAAM,MAAM,QAAQ,CACf,MAAM;AAEvB,MAAK,MAAM,QAAQ,OAAO;AAExB,MAAI,YAAY,KAAK,iBAAiB,MAAO;EAE7C,MAAM,UAAU,KAAK,QAAQ,KAAK,QAAQ;AAE1C,OAAK,MAAM,SAAS,SAAS;GAC3B,MAAM,OAAO,MAAM,MAAM;AAEzB,OAAI,KAAK,UAAU,CAAC,KAAK,OAAO,KAAK,CAAE;GAEvC,MAAM,QAAQ,MAAM,OAAO;AAC3B,cAAW,KAAK;IACd,MAAM;IACN,MAAM,MAAM,MAAM,OAAO;IACzB,QAAQ,MAAM,MAAM,SAAS;IAC7B,MAAM,KAAK;IACX,SAAS,KAAK;IACd,MAAM,KAAK,SAAS,KAAK,GAAG,KAAK,MAAM,GAAG,GAAG,CAAC,OAAO;IACtD,CAAC;;;AAIN,QAAO;;;;;AAMT,SAAS,UAAU;CACjB,MAAM,UAAU,QAAQ,KAAK;CAC7B,MAAM,QAAQ,YAAY,QAAQ;AAElC,SAAQ,IAAI,YAAY,MAAM,OAAO,wBAAwB;CAE7D,MAAM,gBAA6B,EAAE;AAErC,MAAK,MAAM,QAAQ,OAAO;EACxB,MAAM,aAAa,SAAS,MAAM,MAAM;AACxC,gBAAc,KAAK,GAAG,WAAW;;AAGnC,KAAI,cAAc,WAAW,GAAG;AAC9B,UAAQ,IAAI,qCAAqC;AACjD,UAAQ,KAAK,EAAE;;AAGjB,SAAQ,IAAI,SAAS,cAAc,OAAO,kBAAkB;AAE5D,MAAK,MAAM,KAAK,eAAe;EAC7B,MAAM,UAAU,KAAK,SAAS,SAAS,EAAE,KAAK;AAC9C,UAAQ,IAAI,GAAG,QAAQ,GAAG,EAAE,KAAK,GAAG,EAAE,SAAS;AAC/C,UAAQ,IAAI,KAAK,EAAE,KAAK,IAAI,EAAE,UAAU;AACxC,UAAQ,IAAI,OAAO,EAAE,KAAK,IAAI;;AAGhC,SAAQ,KAAK,EAAE;;AAGjB,MAAa,cAAc,IAAI,QAAQ,OAAO,CAC3C,YAAY,4CAA4C,CACxD,OAAO,QAAQ"}
1
+ {"version":3,"file":"lint.js","names":[],"sources":["../../../src/cli/commands/lint.ts"],"sourcesContent":["import fs from \"node:fs\";\nimport path from \"node:path\";\nimport { Lang, parse } from \"@ast-grep/napi\";\nimport { Command } from \"commander\";\n\ninterface Rule {\n id: string;\n pattern: string;\n message: string;\n includeTests?: boolean;\n filter?: (code: string) => boolean;\n}\n\nconst rules: Rule[] = [\n {\n id: \"no-double-type-assertion\",\n pattern: \"$X as unknown as $Y\",\n message:\n \"Avoid double type assertion (as unknown as). Use proper type guards or fix the source type.\",\n },\n {\n id: \"no-as-any\",\n pattern: \"$X as any\",\n message:\n 'Avoid \"as any\" type assertion. Use proper typing or unknown with type guards.',\n includeTests: false, // acceptable in test mocks\n },\n {\n id: \"no-array-index-key\",\n pattern: \"key={$IDX}\",\n message:\n \"Avoid using array index as React key. Use a stable unique identifier.\",\n filter: (code) => /key=\\{(idx|index|i)\\}/.test(code),\n },\n {\n id: \"no-parse-float-without-validation\",\n pattern: \"parseFloat($X).toFixed($Y)\",\n message:\n \"parseFloat can return NaN. Validate input or use toNumber() helper from shared/types.ts.\",\n },\n];\n\nfunction isTestFile(filePath: string): boolean {\n return (\n /\\.(test|spec)\\.(ts|tsx)$/.test(filePath) || filePath.includes(\"/tests/\")\n );\n}\n\nfunction findTsFiles(dir: string, files: string[] = []): string[] {\n const entries = fs.readdirSync(dir, { withFileTypes: true });\n\n for (const entry of entries) {\n const fullPath = path.join(dir, entry.name);\n\n if (entry.isDirectory()) {\n if ([\"node_modules\", \"dist\", \"build\", \".git\"].includes(entry.name))\n continue;\n findTsFiles(fullPath, files);\n } else if (entry.isFile() && /\\.(ts|tsx)$/.test(entry.name)) {\n files.push(fullPath);\n }\n }\n\n return files;\n}\n\ninterface Violation {\n file: string;\n line: number;\n column: number;\n rule: string;\n message: string;\n code: string;\n}\n\nfunction lintFile(filePath: string, rules: Rule[]): Violation[] {\n const violations: Violation[] = [];\n const content = fs.readFileSync(filePath, \"utf-8\");\n const lang = filePath.endsWith(\".tsx\") ? Lang.Tsx : Lang.TypeScript;\n const testFile = isTestFile(filePath);\n\n const ast = parse(lang, content);\n const root = ast.root();\n\n for (const rule of rules) {\n // skip rules that don't apply to test files\n if (testFile && rule.includeTests === false) continue;\n\n const matches = root.findAll(rule.pattern);\n\n for (const match of matches) {\n const code = match.text();\n\n if (rule.filter && !rule.filter(code)) continue;\n\n const range = match.range();\n violations.push({\n file: filePath,\n line: range.start.line + 1,\n column: range.start.column + 1,\n rule: rule.id,\n message: rule.message,\n code: code.length > 80 ? `${code.slice(0, 77)}...` : code,\n });\n }\n }\n\n return violations;\n}\n\n/**\n * Lint command implementation\n */\nfunction runLint() {\n const rootDir = process.cwd();\n const files = findTsFiles(rootDir);\n\n console.log(`Scanning ${files.length} TypeScript files...\\n`);\n\n const allViolations: Violation[] = [];\n\n for (const file of files) {\n const violations = lintFile(file, rules);\n allViolations.push(...violations);\n }\n\n if (allViolations.length === 0) {\n console.log(\"No ast-grep lint violations found.\");\n process.exit(0);\n }\n\n console.log(`Found ${allViolations.length} violation(s):\\n`);\n\n for (const v of allViolations) {\n const relPath = path.relative(rootDir, v.file);\n console.log(`${relPath}:${v.line}:${v.column}`);\n console.log(` ${v.rule}: ${v.message}`);\n console.log(` > ${v.code}\\n`);\n }\n\n process.exit(1);\n}\n\nexport const lintCommand = new Command(\"lint\")\n .description(\"Run AST-based linting on TypeScript files\")\n .action(runLint);\n"],"mappings":";;;;;;AAaA,MAAM,QAAgB;CACpB;EACE,IAAI;EACJ,SAAS;EACT,SACE;EACH;CACD;EACE,IAAI;EACJ,SAAS;EACT,SACE;EACF,cAAc;EACf;CACD;EACE,IAAI;EACJ,SAAS;EACT,SACE;EACF,SAAS,SAAS,wBAAwB,KAAK,KAAK;EACrD;CACD;EACE,IAAI;EACJ,SAAS;EACT,SACE;EACH;CACF;AAED,SAAS,WAAW,UAA2B;AAC7C,QACE,2BAA2B,KAAK,SAAS,IAAI,SAAS,SAAS,UAAU;;AAI7E,SAAS,YAAY,KAAa,QAAkB,EAAE,EAAY;CAChE,MAAM,UAAU,GAAG,YAAY,KAAK,EAAE,eAAe,MAAM,CAAC;AAE5D,MAAK,MAAM,SAAS,SAAS;EAC3B,MAAM,WAAW,KAAK,KAAK,KAAK,MAAM,KAAK;AAE3C,MAAI,MAAM,aAAa,EAAE;AACvB,OAAI;IAAC;IAAgB;IAAQ;IAAS;IAAO,CAAC,SAAS,MAAM,KAAK,CAChE;AACF,eAAY,UAAU,MAAM;aACnB,MAAM,QAAQ,IAAI,cAAc,KAAK,MAAM,KAAK,CACzD,OAAM,KAAK,SAAS;;AAIxB,QAAO;;AAYT,SAAS,SAAS,UAAkB,OAA4B;CAC9D,MAAM,aAA0B,EAAE;CAClC,MAAM,UAAU,GAAG,aAAa,UAAU,QAAQ;CAClD,MAAM,OAAO,SAAS,SAAS,OAAO,GAAG,KAAK,MAAM,KAAK;CACzD,MAAM,WAAW,WAAW,SAAS;CAGrC,MAAM,OADM,MAAM,MAAM,QAAQ,CACf,MAAM;AAEvB,MAAK,MAAM,QAAQ,OAAO;AAExB,MAAI,YAAY,KAAK,iBAAiB,MAAO;EAE7C,MAAM,UAAU,KAAK,QAAQ,KAAK,QAAQ;AAE1C,OAAK,MAAM,SAAS,SAAS;GAC3B,MAAM,OAAO,MAAM,MAAM;AAEzB,OAAI,KAAK,UAAU,CAAC,KAAK,OAAO,KAAK,CAAE;GAEvC,MAAM,QAAQ,MAAM,OAAO;AAC3B,cAAW,KAAK;IACd,MAAM;IACN,MAAM,MAAM,MAAM,OAAO;IACzB,QAAQ,MAAM,MAAM,SAAS;IAC7B,MAAM,KAAK;IACX,SAAS,KAAK;IACd,MAAM,KAAK,SAAS,KAAK,GAAG,KAAK,MAAM,GAAG,GAAG,CAAC,OAAO;IACtD,CAAC;;;AAIN,QAAO;;;;;AAMT,SAAS,UAAU;CACjB,MAAM,UAAU,QAAQ,KAAK;CAC7B,MAAM,QAAQ,YAAY,QAAQ;AAElC,SAAQ,IAAI,YAAY,MAAM,OAAO,wBAAwB;CAE7D,MAAM,gBAA6B,EAAE;AAErC,MAAK,MAAM,QAAQ,OAAO;EACxB,MAAM,aAAa,SAAS,MAAM,MAAM;AACxC,gBAAc,KAAK,GAAG,WAAW;;AAGnC,KAAI,cAAc,WAAW,GAAG;AAC9B,UAAQ,IAAI,qCAAqC;AACjD,UAAQ,KAAK,EAAE;;AAGjB,SAAQ,IAAI,SAAS,cAAc,OAAO,kBAAkB;AAE5D,MAAK,MAAM,KAAK,eAAe;EAC7B,MAAM,UAAU,KAAK,SAAS,SAAS,EAAE,KAAK;AAC9C,UAAQ,IAAI,GAAG,QAAQ,GAAG,EAAE,KAAK,GAAG,EAAE,SAAS;AAC/C,UAAQ,IAAI,KAAK,EAAE,KAAK,IAAI,EAAE,UAAU;AACxC,UAAQ,IAAI,OAAO,EAAE,KAAK,IAAI;;AAGhC,SAAQ,KAAK,EAAE;;AAGjB,MAAa,cAAc,IAAI,QAAQ,OAAO,CAC3C,YAAY,4CAA4C,CACxD,OAAO,QAAQ"}
@@ -1 +1 @@
1
- {"version":3,"file":"setup.js","names":[],"sources":["../../../src/cli/commands/setup.ts"],"sourcesContent":["import { Command } from \"commander\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\n\nconst PACKAGES = [\n { name: \"@databricks/appkit\", description: \"Backend SDK\" },\n {\n name: \"@databricks/appkit-ui\",\n description: \"UI Integration, Charts, Tables, SSE, and more.\",\n },\n];\n\nconst SECTION_START = \"<!-- appkit-instructions-start -->\";\nconst SECTION_END = \"<!-- appkit-instructions-end -->\";\n\n/**\n * Find which AppKit packages are installed by checking for package.json\n */\nfunction findInstalledPackages() {\n const cwd = process.cwd();\n const installed = [];\n\n for (const pkg of PACKAGES) {\n const packagePath = path.join(\n cwd,\n \"node_modules\",\n pkg.name,\n \"package.json\",\n );\n if (fs.existsSync(packagePath)) {\n installed.push(pkg);\n }\n }\n\n return installed;\n}\n\n/**\n * Generate the AppKit section content\n */\nfunction generateSection(packages: typeof PACKAGES) {\n const links = packages\n .map((pkg) => {\n const docPath = `./node_modules/${pkg.name}/CLAUDE.md`;\n return `- **${pkg.name}** (${pkg.description}): [${docPath}](${docPath})`;\n })\n .join(\"\\n\");\n\n return `${SECTION_START}\n## Databricks AppKit\n\nThis project uses Databricks AppKit packages. For AI assistant guidance on using these packages, refer to:\n\n${links}\n${SECTION_END}`;\n}\n\n/**\n * Generate standalone CLAUDE.md content (when no existing file)\n */\nfunction generateStandalone(packages: typeof PACKAGES) {\n const links = packages\n .map((pkg) => {\n const docPath = `./node_modules/${pkg.name}/CLAUDE.md`;\n return `- **${pkg.name}** (${pkg.description}): [${docPath}](${docPath})`;\n })\n .join(\"\\n\");\n\n return `# AI Assistant Instructions\n\n${SECTION_START}\n## Databricks AppKit\n\nThis project uses Databricks AppKit packages. For AI assistant guidance on using these packages, refer to:\n\n${links}\n${SECTION_END}\n`;\n}\n\n/**\n * Update existing content with AppKit section\n */\nfunction updateContent(existingContent: string, packages: typeof PACKAGES) {\n const newSection = generateSection(packages);\n\n // Check if AppKit section already exists\n const startIndex = existingContent.indexOf(SECTION_START);\n const endIndex = existingContent.indexOf(SECTION_END);\n\n if (startIndex !== -1 && endIndex !== -1) {\n // Replace existing section\n const before = existingContent.substring(0, startIndex);\n const after = existingContent.substring(endIndex + SECTION_END.length);\n return before + newSection + after;\n }\n\n // Append section to end\n return `${existingContent.trimEnd()}\\n\\n${newSection}\\n`;\n}\n\n/**\n * Setup command implementation\n */\nfunction runSetup(options: { write?: boolean }) {\n const shouldWrite = options.write;\n\n // Find installed packages\n const installed = findInstalledPackages();\n\n if (installed.length === 0) {\n console.log(\"No @databricks/appkit packages found in node_modules.\");\n console.log(\"\\nMake sure you've installed at least one of:\");\n PACKAGES.forEach((pkg) => {\n console.log(` - ${pkg.name}`);\n });\n process.exit(1);\n }\n\n console.log(\"Detected packages:\");\n installed.forEach((pkg) => {\n console.log(` ✓ ${pkg.name}`);\n });\n\n const claudePath = path.join(process.cwd(), \"CLAUDE.md\");\n const existingContent = fs.existsSync(claudePath)\n ? fs.readFileSync(claudePath, \"utf-8\")\n : null;\n\n let finalContent: string;\n let action: string;\n\n if (existingContent) {\n finalContent = updateContent(existingContent, installed);\n action = existingContent.includes(SECTION_START) ? \"Updated\" : \"Added to\";\n } else {\n finalContent = generateStandalone(installed);\n action = \"Created\";\n }\n\n if (shouldWrite) {\n fs.writeFileSync(claudePath, finalContent);\n console.log(`\\n✓ ${action} CLAUDE.md`);\n console.log(` Path: ${claudePath}`);\n } else {\n console.log(\"\\nTo create/update CLAUDE.md, run:\");\n console.log(\" npx appkit setup --write\\n\");\n\n if (existingContent) {\n console.log(\n `This will ${\n existingContent.includes(SECTION_START)\n ? \"update the existing\"\n : \"add a new\"\n } AppKit section.\\n`,\n );\n }\n\n console.log(\"Preview of AppKit section:\\n\");\n console.log(\"─\".repeat(50));\n console.log(generateSection(installed));\n console.log(\"─\".repeat(50));\n }\n}\n\nexport const setupCommand = new Command(\"setup\")\n .description(\"Setup CLAUDE.md with AppKit package references\")\n .option(\"-w, --write\", \"Create or update CLAUDE.md file in current directory\")\n .action(runSetup);\n"],"mappings":"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"}
1
+ {"version":3,"file":"setup.js","names":[],"sources":["../../../src/cli/commands/setup.ts"],"sourcesContent":["import fs from \"node:fs\";\nimport path from \"node:path\";\nimport { Command } from \"commander\";\n\nconst PACKAGES = [\n { name: \"@databricks/appkit\", description: \"Backend SDK\" },\n {\n name: \"@databricks/appkit-ui\",\n description: \"UI Integration, Charts, Tables, SSE, and more.\",\n },\n];\n\nconst SECTION_START = \"<!-- appkit-instructions-start -->\";\nconst SECTION_END = \"<!-- appkit-instructions-end -->\";\n\n/**\n * Find which AppKit packages are installed by checking for package.json\n */\nfunction findInstalledPackages() {\n const cwd = process.cwd();\n const installed = [];\n\n for (const pkg of PACKAGES) {\n const packagePath = path.join(\n cwd,\n \"node_modules\",\n pkg.name,\n \"package.json\",\n );\n if (fs.existsSync(packagePath)) {\n installed.push(pkg);\n }\n }\n\n return installed;\n}\n\n/**\n * Generate the AppKit section content\n */\nfunction generateSection(packages: typeof PACKAGES) {\n const links = packages\n .map((pkg) => {\n const docPath = `./node_modules/${pkg.name}/CLAUDE.md`;\n return `- **${pkg.name}** (${pkg.description}): [${docPath}](${docPath})`;\n })\n .join(\"\\n\");\n\n return `${SECTION_START}\n## Databricks AppKit\n\nThis project uses Databricks AppKit packages. For AI assistant guidance on using these packages, refer to:\n\n${links}\n${SECTION_END}`;\n}\n\n/**\n * Generate standalone CLAUDE.md content (when no existing file)\n */\nfunction generateStandalone(packages: typeof PACKAGES) {\n const links = packages\n .map((pkg) => {\n const docPath = `./node_modules/${pkg.name}/CLAUDE.md`;\n return `- **${pkg.name}** (${pkg.description}): [${docPath}](${docPath})`;\n })\n .join(\"\\n\");\n\n return `# AI Assistant Instructions\n\n${SECTION_START}\n## Databricks AppKit\n\nThis project uses Databricks AppKit packages. For AI assistant guidance on using these packages, refer to:\n\n${links}\n${SECTION_END}\n`;\n}\n\n/**\n * Update existing content with AppKit section\n */\nfunction updateContent(existingContent: string, packages: typeof PACKAGES) {\n const newSection = generateSection(packages);\n\n // Check if AppKit section already exists\n const startIndex = existingContent.indexOf(SECTION_START);\n const endIndex = existingContent.indexOf(SECTION_END);\n\n if (startIndex !== -1 && endIndex !== -1) {\n // Replace existing section\n const before = existingContent.substring(0, startIndex);\n const after = existingContent.substring(endIndex + SECTION_END.length);\n return before + newSection + after;\n }\n\n // Append section to end\n return `${existingContent.trimEnd()}\\n\\n${newSection}\\n`;\n}\n\n/**\n * Setup command implementation\n */\nfunction runSetup(options: { write?: boolean }) {\n const shouldWrite = options.write;\n\n // Find installed packages\n const installed = findInstalledPackages();\n\n if (installed.length === 0) {\n console.log(\"No @databricks/appkit packages found in node_modules.\");\n console.log(\"\\nMake sure you've installed at least one of:\");\n PACKAGES.forEach((pkg) => {\n console.log(` - ${pkg.name}`);\n });\n process.exit(1);\n }\n\n console.log(\"Detected packages:\");\n installed.forEach((pkg) => {\n console.log(` ✓ ${pkg.name}`);\n });\n\n const claudePath = path.join(process.cwd(), \"CLAUDE.md\");\n const existingContent = fs.existsSync(claudePath)\n ? fs.readFileSync(claudePath, \"utf-8\")\n : null;\n\n let finalContent: string;\n let action: string;\n\n if (existingContent) {\n finalContent = updateContent(existingContent, installed);\n action = existingContent.includes(SECTION_START) ? \"Updated\" : \"Added to\";\n } else {\n finalContent = generateStandalone(installed);\n action = \"Created\";\n }\n\n if (shouldWrite) {\n fs.writeFileSync(claudePath, finalContent);\n console.log(`\\n✓ ${action} CLAUDE.md`);\n console.log(` Path: ${claudePath}`);\n } else {\n console.log(\"\\nTo create/update CLAUDE.md, run:\");\n console.log(\" npx appkit setup --write\\n\");\n\n if (existingContent) {\n console.log(\n `This will ${\n existingContent.includes(SECTION_START)\n ? \"update the existing\"\n : \"add a new\"\n } AppKit section.\\n`,\n );\n }\n\n console.log(\"Preview of AppKit section:\\n\");\n console.log(\"─\".repeat(50));\n console.log(generateSection(installed));\n console.log(\"─\".repeat(50));\n }\n}\n\nexport const setupCommand = new Command(\"setup\")\n .description(\"Setup CLAUDE.md with AppKit package references\")\n .option(\"-w, --write\", \"Create or update CLAUDE.md file in current directory\")\n .action(runSetup);\n"],"mappings":"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"}
package/dist/cli/index.js CHANGED
@@ -1,11 +1,11 @@
1
1
  #!/usr/bin/env node
2
- import { setupCommand } from "./commands/setup.js";
2
+ import { docsCommand } from "./commands/docs.js";
3
3
  import { generateTypesCommand } from "./commands/generate-types.js";
4
4
  import { lintCommand } from "./commands/lint.js";
5
- import { docsCommand } from "./commands/docs.js";
5
+ import { setupCommand } from "./commands/setup.js";
6
6
  import { readFileSync } from "node:fs";
7
- import { fileURLToPath } from "node:url";
8
7
  import { dirname, join } from "node:path";
8
+ import { fileURLToPath } from "node:url";
9
9
  import { Command } from "commander";
10
10
 
11
11
  //#region src/cli/index.ts
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../src/cli/index.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport { readFileSync } from \"node:fs\";\nimport { fileURLToPath } from \"node:url\";\nimport { dirname, join } from \"node:path\";\nimport { Command } from \"commander\";\nimport { setupCommand } from \"./commands/setup.js\";\nimport { generateTypesCommand } from \"./commands/generate-types.js\";\nimport { lintCommand } from \"./commands/lint.js\";\nimport { docsCommand } from \"./commands/docs.js\";\n\nconst __dirname = dirname(fileURLToPath(import.meta.url));\nconst pkgPath = join(__dirname, \"../../package.json\");\nconst pkg = JSON.parse(readFileSync(pkgPath, \"utf-8\"));\n\nconst cmd = new Command();\n\ncmd\n .name(\"appkit\")\n .description(\"CLI tools for Databricks AppKit\")\n .version(pkg.version);\n\ncmd.addCommand(setupCommand);\ncmd.addCommand(generateTypesCommand);\ncmd.addCommand(lintCommand);\ncmd.addCommand(docsCommand);\n\ncmd.parse();\n"],"mappings":";;;;;;;;;;;AAYA,MAAM,UAAU,KADE,QAAQ,cAAc,OAAO,KAAK,IAAI,CAAC,EACzB,qBAAqB;AACrD,MAAM,MAAM,KAAK,MAAM,aAAa,SAAS,QAAQ,CAAC;AAEtD,MAAM,MAAM,IAAI,SAAS;AAEzB,IACG,KAAK,SAAS,CACd,YAAY,kCAAkC,CAC9C,QAAQ,IAAI,QAAQ;AAEvB,IAAI,WAAW,aAAa;AAC5B,IAAI,WAAW,qBAAqB;AACpC,IAAI,WAAW,YAAY;AAC3B,IAAI,WAAW,YAAY;AAE3B,IAAI,OAAO"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../src/cli/index.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport { readFileSync } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { Command } from \"commander\";\nimport { docsCommand } from \"./commands/docs.js\";\nimport { generateTypesCommand } from \"./commands/generate-types.js\";\nimport { lintCommand } from \"./commands/lint.js\";\nimport { setupCommand } from \"./commands/setup.js\";\n\nconst __dirname = dirname(fileURLToPath(import.meta.url));\nconst pkgPath = join(__dirname, \"../../package.json\");\nconst pkg = JSON.parse(readFileSync(pkgPath, \"utf-8\"));\n\nconst cmd = new Command();\n\ncmd\n .name(\"appkit\")\n .description(\"CLI tools for Databricks AppKit\")\n .version(pkg.version);\n\ncmd.addCommand(setupCommand);\ncmd.addCommand(generateTypesCommand);\ncmd.addCommand(lintCommand);\ncmd.addCommand(docsCommand);\n\ncmd.parse();\n"],"mappings":";;;;;;;;;;;AAYA,MAAM,UAAU,KADE,QAAQ,cAAc,OAAO,KAAK,IAAI,CAAC,EACzB,qBAAqB;AACrD,MAAM,MAAM,KAAK,MAAM,aAAa,SAAS,QAAQ,CAAC;AAEtD,MAAM,MAAM,IAAI,SAAS;AAEzB,IACG,KAAK,SAAS,CACd,YAAY,kCAAkC,CAC9C,QAAQ,IAAI,QAAQ;AAEvB,IAAI,WAAW,aAAa;AAC5B,IAAI,WAAW,qBAAqB;AACpC,IAAI,WAAW,YAAY;AAC3B,IAAI,WAAW,YAAY;AAE3B,IAAI,OAAO"}
@@ -1 +1 @@
1
- {"version":3,"file":"execution-context.js","names":[],"sources":["../../src/context/execution-context.ts"],"sourcesContent":["import { AsyncLocalStorage } from \"node:async_hooks\";\nimport { ServiceContext } from \"./service-context\";\nimport {\n isUserContext,\n type ExecutionContext,\n type UserContext,\n} from \"./user-context\";\n\n/**\n * AsyncLocalStorage for execution context.\n * Used to pass user context through the call stack without explicit parameters.\n */\nconst executionContextStorage = new AsyncLocalStorage<UserContext>();\n\n/**\n * Run a function in the context of a user.\n * All calls within the function will have access to the user context.\n *\n * @param userContext - The user context to use\n * @param fn - The function to run\n * @returns The result of the function\n */\nexport function runInUserContext<T>(userContext: UserContext, fn: () => T): T {\n return executionContextStorage.run(userContext, fn);\n}\n\n/**\n * Get the current execution context.\n *\n * - If running inside a user context (via asUser), returns the user context\n * - Otherwise, returns the service context\n *\n * @throws Error if ServiceContext is not initialized\n */\nexport function getExecutionContext(): ExecutionContext {\n const userContext = executionContextStorage.getStore();\n if (userContext) {\n return userContext;\n }\n return ServiceContext.get();\n}\n\n/**\n * Get the current user ID for cache keying and telemetry.\n *\n * Returns the user ID if in user context, otherwise the service user ID.\n */\nexport function getCurrentUserId(): string {\n const ctx = getExecutionContext();\n if (isUserContext(ctx)) {\n return ctx.userId;\n }\n return ctx.serviceUserId;\n}\n\n/**\n * Get the WorkspaceClient for the current execution context.\n */\nexport function getWorkspaceClient() {\n return getExecutionContext().client;\n}\n\n/**\n * Get the warehouse ID promise.\n */\nexport function getWarehouseId(): Promise<string> {\n return getExecutionContext().warehouseId;\n}\n\n/**\n * Get the workspace ID promise.\n */\nexport function getWorkspaceId(): Promise<string> {\n return getExecutionContext().workspaceId;\n}\n\n/**\n * Check if currently running in a user context.\n */\nexport function isInUserContext(): boolean {\n const ctx = executionContextStorage.getStore();\n return ctx !== undefined;\n}\n"],"mappings":";;;;;;;;;;;;;;AAsBA,SAAgB,iBAAoB,aAA0B,IAAgB;AAC5E,QAAO,wBAAwB,IAAI,aAAa,GAAG;;;;;;;;;;AAWrD,SAAgB,sBAAwC;CACtD,MAAM,cAAc,wBAAwB,UAAU;AACtD,KAAI,YACF,QAAO;AAET,QAAO,eAAe,KAAK;;;;;;;AAQ7B,SAAgB,mBAA2B;CACzC,MAAM,MAAM,qBAAqB;AACjC,KAAI,cAAc,IAAI,CACpB,QAAO,IAAI;AAEb,QAAO,IAAI;;;;;AAMb,SAAgB,qBAAqB;AACnC,QAAO,qBAAqB,CAAC;;;;;AAM/B,SAAgB,iBAAkC;AAChD,QAAO,qBAAqB,CAAC;;;;;AAM/B,SAAgB,iBAAkC;AAChD,QAAO,qBAAqB,CAAC;;;;;AAM/B,SAAgB,kBAA2B;AAEzC,QADY,wBAAwB,UAAU,KAC/B;;;;uBAhFkC;oBAK3B;CAMlB,0BAA0B,IAAI,mBAAgC"}
1
+ {"version":3,"file":"execution-context.js","names":[],"sources":["../../src/context/execution-context.ts"],"sourcesContent":["import { AsyncLocalStorage } from \"node:async_hooks\";\nimport { ServiceContext } from \"./service-context\";\nimport {\n type ExecutionContext,\n isUserContext,\n type UserContext,\n} from \"./user-context\";\n\n/**\n * AsyncLocalStorage for execution context.\n * Used to pass user context through the call stack without explicit parameters.\n */\nconst executionContextStorage = new AsyncLocalStorage<UserContext>();\n\n/**\n * Run a function in the context of a user.\n * All calls within the function will have access to the user context.\n *\n * @param userContext - The user context to use\n * @param fn - The function to run\n * @returns The result of the function\n */\nexport function runInUserContext<T>(userContext: UserContext, fn: () => T): T {\n return executionContextStorage.run(userContext, fn);\n}\n\n/**\n * Get the current execution context.\n *\n * - If running inside a user context (via asUser), returns the user context\n * - Otherwise, returns the service context\n *\n * @throws Error if ServiceContext is not initialized\n */\nexport function getExecutionContext(): ExecutionContext {\n const userContext = executionContextStorage.getStore();\n if (userContext) {\n return userContext;\n }\n return ServiceContext.get();\n}\n\n/**\n * Get the current user ID for cache keying and telemetry.\n *\n * Returns the user ID if in user context, otherwise the service user ID.\n */\nexport function getCurrentUserId(): string {\n const ctx = getExecutionContext();\n if (isUserContext(ctx)) {\n return ctx.userId;\n }\n return ctx.serviceUserId;\n}\n\n/**\n * Get the WorkspaceClient for the current execution context.\n */\nexport function getWorkspaceClient() {\n return getExecutionContext().client;\n}\n\n/**\n * Get the warehouse ID promise.\n */\nexport function getWarehouseId(): Promise<string> {\n return getExecutionContext().warehouseId;\n}\n\n/**\n * Get the workspace ID promise.\n */\nexport function getWorkspaceId(): Promise<string> {\n return getExecutionContext().workspaceId;\n}\n\n/**\n * Check if currently running in a user context.\n */\nexport function isInUserContext(): boolean {\n const ctx = executionContextStorage.getStore();\n return ctx !== undefined;\n}\n"],"mappings":";;;;;;;;;;;;;;AAsBA,SAAgB,iBAAoB,aAA0B,IAAgB;AAC5E,QAAO,wBAAwB,IAAI,aAAa,GAAG;;;;;;;;;;AAWrD,SAAgB,sBAAwC;CACtD,MAAM,cAAc,wBAAwB,UAAU;AACtD,KAAI,YACF,QAAO;AAET,QAAO,eAAe,KAAK;;;;;;;AAQ7B,SAAgB,mBAA2B;CACzC,MAAM,MAAM,qBAAqB;AACjC,KAAI,cAAc,IAAI,CACpB,QAAO,IAAI;AAEb,QAAO,IAAI;;;;;AAMb,SAAgB,qBAAqB;AACnC,QAAO,qBAAqB,CAAC;;;;;AAM/B,SAAgB,iBAAkC;AAChD,QAAO,qBAAqB,CAAC;;;;;AAM/B,SAAgB,iBAAkC;AAChD,QAAO,qBAAqB,CAAC;;;;;AAM/B,SAAgB,kBAA2B;AAEzC,QADY,wBAAwB,UAAU,KAC/B;;;;uBAhFkC;oBAK3B;CAMlB,0BAA0B,IAAI,mBAAgC"}
@@ -16,9 +16,9 @@ var context_exports = /* @__PURE__ */ __exportAll({
16
16
  runInUserContext: () => runInUserContext
17
17
  });
18
18
  var init_context = __esmMin((() => {
19
+ init_execution_context();
19
20
  init_service_context();
20
21
  init_user_context();
21
- init_execution_context();
22
22
  }));
23
23
 
24
24
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../src/context/index.ts"],"sourcesContent":["export { ServiceContext, type ServiceContextState } from \"./service-context\";\n\nexport {\n isUserContext,\n type ExecutionContext,\n type UserContext,\n} from \"./user-context\";\n\nexport {\n getExecutionContext,\n getCurrentUserId,\n getWorkspaceClient,\n getWarehouseId,\n getWorkspaceId,\n isInUserContext,\n runInUserContext,\n} from \"./execution-context\";\n"],"mappings":";;;;;;;;;;;;;;;;;;uBAA6E;oBAMrD;yBAUK"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../src/context/index.ts"],"sourcesContent":["export {\n getCurrentUserId,\n getExecutionContext,\n getWarehouseId,\n getWorkspaceClient,\n getWorkspaceId,\n isInUserContext,\n runInUserContext,\n} from \"./execution-context\";\nexport { ServiceContext, type ServiceContextState } from \"./service-context\";\nexport {\n type ExecutionContext,\n isUserContext,\n type UserContext,\n} from \"./user-context\";\n"],"mappings":";;;;;;;;;;;;;;;;;;yBAQ6B;uBACgD;oBAKrD"}
package/dist/index.d.ts CHANGED
@@ -3,11 +3,9 @@ import { CacheConfig } from "./shared/src/cache.js";
3
3
  import { StreamExecutionSettings } from "./shared/src/execute.js";
4
4
  import { isSQLTypeMarker, sql } from "./shared/src/sql/helpers.js";
5
5
  import { CacheManager } from "./cache/index.js";
6
+ import { getExecutionContext } from "./context/execution-context.js";
6
7
  import { ITelemetry, TelemetryConfig } from "./telemetry/types.js";
7
8
  import { Counter, Histogram, SeverityNumber, Span, SpanStatusCode } from "./telemetry/index.js";
8
- import { Plugin } from "./plugin/plugin.js";
9
- import { toPlugin } from "./plugin/to-plugin.js";
10
- import { analytics } from "./analytics/analytics.js";
11
9
  import { createApp } from "./core/appkit.js";
12
10
  import { AppKitError } from "./errors/base.js";
13
11
  import { AuthenticationError } from "./errors/authentication.js";
@@ -18,7 +16,9 @@ import { InitializationError } from "./errors/initialization.js";
18
16
  import { ServerError } from "./errors/server.js";
19
17
  import { TunnelError } from "./errors/tunnel.js";
20
18
  import { ValidationError } from "./errors/validation.js";
21
- import { server } from "./server/index.js";
19
+ import { Plugin } from "./plugin/plugin.js";
20
+ import { toPlugin } from "./plugin/to-plugin.js";
21
+ import { analytics } from "./plugins/analytics/analytics.js";
22
+ import { server } from "./plugins/server/index.js";
22
23
  import { appKitTypesPlugin } from "./type-generator/vite-plugin.js";
23
- import { getExecutionContext } from "./context/execution-context.js";
24
24
  export { AppKitError, AuthenticationError, type BasePluginConfig, type CacheConfig, CacheManager, ConfigurationError, ConnectionError, type Counter, ExecutionError, type Histogram, type IAppRouter, type ITelemetry, InitializationError, Plugin, ServerError, SeverityNumber, type Span, SpanStatusCode, type StreamExecutionSettings, type TelemetryConfig, TunnelError, ValidationError, analytics, appKitTypesPlugin, createApp, getExecutionContext, isSQLTypeMarker, server, sql, toPlugin };
package/dist/index.js CHANGED
@@ -13,19 +13,19 @@ import { init_errors } from "./errors/index.js";
13
13
  import { getExecutionContext } from "./context/execution-context.js";
14
14
  import { init_context } from "./context/index.js";
15
15
  import { CacheManager } from "./cache/index.js";
16
+ import { createApp } from "./core/appkit.js";
17
+ import "./core/index.js";
16
18
  import { Plugin } from "./plugin/plugin.js";
17
19
  import { toPlugin } from "./plugin/to-plugin.js";
18
20
  import "./plugin/index.js";
19
- import { analytics } from "./analytics/analytics.js";
20
- import "./analytics/index.js";
21
- import { createApp } from "./core/appkit.js";
22
- import "./core/index.js";
21
+ import { analytics } from "./plugins/analytics/analytics.js";
23
22
  import { appKitTypesPlugin } from "./type-generator/vite-plugin.js";
24
- import { server } from "./server/index.js";
23
+ import { server } from "./plugins/server/index.js";
24
+ import "./plugins/index.js";
25
25
 
26
26
  //#region src/index.ts
27
- init_errors();
28
27
  init_context();
28
+ init_errors();
29
29
 
30
30
  //#endregion
31
31
  export { AppKitError, AuthenticationError, CacheManager, ConfigurationError, ConnectionError, ExecutionError, InitializationError, Plugin, ServerError, SeverityNumber, SpanStatusCode, TunnelError, ValidationError, analytics, appKitTypesPlugin, createApp, getExecutionContext, isSQLTypeMarker, server, sql, toPlugin };
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../src/index.ts"],"sourcesContent":["/**\n * @packageDocumentation\n *\n * Core library for building Databricks applications with type-safe SQL queries,\n * plugin architecture, and React integration.\n */\n\n// Types from shared\nexport type {\n BasePluginConfig,\n CacheConfig,\n IAppRouter,\n StreamExecutionSettings,\n} from \"shared\";\nexport { isSQLTypeMarker, sql } from \"shared\";\nexport { analytics } from \"./analytics\";\nexport { CacheManager } from \"./cache\";\nexport { createApp } from \"./core\";\n// Errors\nexport {\n AppKitError,\n AuthenticationError,\n ConfigurationError,\n ConnectionError,\n ExecutionError,\n InitializationError,\n ServerError,\n TunnelError,\n ValidationError,\n} from \"./errors\";\n// Plugin authoring\nexport { Plugin, toPlugin } from \"./plugin\";\nexport { server } from \"./server\";\n// Telemetry (for advanced custom telemetry)\nexport {\n type Counter,\n type Histogram,\n type ITelemetry,\n SeverityNumber,\n type Span,\n SpanStatusCode,\n type TelemetryConfig,\n} from \"./telemetry\";\n\n// Vite plugin and type generation\nexport { appKitTypesPlugin } from \"./type-generator/vite-plugin\";\nexport { getExecutionContext } from \"./context\";\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;aA6BkB;cAiB8B"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../src/index.ts"],"sourcesContent":["/**\n * @packageDocumentation\n *\n * Core library for building Databricks applications with type-safe SQL queries,\n * plugin architecture, and React integration.\n */\n\n// Types from shared\nexport type {\n BasePluginConfig,\n CacheConfig,\n IAppRouter,\n StreamExecutionSettings,\n} from \"shared\";\nexport { isSQLTypeMarker, sql } from \"shared\";\nexport { CacheManager } from \"./cache\";\nexport { getExecutionContext } from \"./context\";\nexport { createApp } from \"./core\";\n// Errors\nexport {\n AppKitError,\n AuthenticationError,\n ConfigurationError,\n ConnectionError,\n ExecutionError,\n InitializationError,\n ServerError,\n TunnelError,\n ValidationError,\n} from \"./errors\";\n// Plugin authoring\nexport { Plugin, toPlugin } from \"./plugin\";\nexport { analytics, server } from \"./plugins\";\n// Telemetry (for advanced custom telemetry)\nexport {\n type Counter,\n type Histogram,\n type ITelemetry,\n SeverityNumber,\n type Span,\n SpanStatusCode,\n type TelemetryConfig,\n} from \"./telemetry\";\n// Vite plugin and type generation\nexport { appKitTypesPlugin } from \"./type-generator/vite-plugin\";\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;cAgBgD;aAa9B"}
@@ -1,7 +1,7 @@
1
1
  import { createLogger } from "../logging/logger.js";
2
2
  import { TunnelError } from "../errors/tunnel.js";
3
3
  import { init_errors } from "../errors/index.js";
4
- import { isRemoteTunnelAllowedByEnv } from "../server/remote-tunnel/gate.js";
4
+ import { isRemoteTunnelAllowedByEnv } from "../plugins/server/remote-tunnel/gate.js";
5
5
  import { randomUUID } from "node:crypto";
6
6
 
7
7
  //#region src/plugin/dev-reader.ts
@@ -1 +1 @@
1
- {"version":3,"file":"dev-reader.js","names":[],"sources":["../../src/plugin/dev-reader.ts"],"sourcesContent":["import { randomUUID } from \"node:crypto\";\nimport type { TunnelConnection } from \"shared\";\nimport { isRemoteTunnelAllowedByEnv } from \"@/server/remote-tunnel/gate\";\nimport { TunnelError } from \"../errors\";\nimport { createLogger } from \"../logging/logger\";\n\nconst logger = createLogger(\"plugin:dev-reader\");\n\ntype TunnelConnectionGetter = (\n req: import(\"express\").Request,\n) => TunnelConnection | null;\n\n/**\n * This class is used to read files from the local filesystem in dev mode\n * through the WebSocket tunnel.\n */\nexport class DevFileReader {\n private static instance: DevFileReader | null = null;\n private getTunnelForRequest: TunnelConnectionGetter | null = null;\n\n private constructor() {}\n\n static getInstance(): DevFileReader {\n if (!DevFileReader.instance) {\n DevFileReader.instance = new Proxy(new DevFileReader(), {\n /**\n * We proxy the reader to return a noop function if the remote server is disabled.\n */\n get(target, prop, receiver) {\n if (isRemoteTunnelAllowedByEnv()) {\n return Reflect.get(target, prop, receiver);\n }\n\n const value = Reflect.get(target, prop, receiver);\n\n if (typeof value === \"function\") {\n return function noop() {\n logger.debug(\"Noop: %s (remote server disabled)\", String(prop));\n return Promise.resolve(\"\");\n };\n }\n\n return value;\n },\n set(target, prop, value, receiver) {\n return Reflect.set(target, prop, value, receiver);\n },\n });\n }\n\n return DevFileReader.instance;\n }\n\n registerTunnelGetter(getter: TunnelConnectionGetter) {\n this.getTunnelForRequest = getter;\n }\n\n async readFile(\n filePath: string,\n req: import(\"express\").Request,\n ): Promise<string> {\n if (!this.getTunnelForRequest) {\n throw TunnelError.getterNotRegistered();\n }\n const tunnel = this.getTunnelForRequest(req);\n\n if (!tunnel) {\n throw TunnelError.noConnection();\n }\n\n const { ws, pendingFileReads } = tunnel;\n const requestId = randomUUID();\n\n return new Promise((resolve, reject) => {\n const timeout = setTimeout(() => {\n pendingFileReads.delete(requestId);\n reject(new Error(`File read timeout: ${filePath}`));\n }, 10000);\n\n pendingFileReads.set(requestId, { resolve, reject, timeout });\n\n ws.send(\n JSON.stringify({\n type: \"file:read\",\n requestId,\n path: filePath,\n }),\n );\n });\n }\n\n async readdir(\n dirPath: string,\n req: import(\"express\").Request,\n ): Promise<string[]> {\n if (!this.getTunnelForRequest) {\n throw TunnelError.getterNotRegistered();\n }\n const tunnel = this.getTunnelForRequest(req);\n\n if (!tunnel) {\n throw TunnelError.noConnection();\n }\n\n const { ws, pendingFileReads } = tunnel;\n const requestId = randomUUID();\n\n return new Promise((resolve, reject) => {\n const timeout = setTimeout(() => {\n pendingFileReads.delete(requestId);\n reject(new Error(`Directory read timeout: ${dirPath}`));\n }, 10000);\n\n pendingFileReads.set(requestId, {\n resolve: (data: string) => {\n try {\n const files = JSON.parse(data);\n // Validate it's an array of strings\n if (!Array.isArray(files)) {\n reject(\n new Error(\n \"Invalid directory listing format: expected array, got \" +\n typeof files,\n ),\n );\n return;\n }\n if (!files.every((f) => typeof f === \"string\")) {\n reject(\n new Error(\n \"Invalid directory listing format: expected array of strings\",\n ),\n );\n return;\n }\n resolve(files);\n } catch (error) {\n reject(\n new Error(\n `Failed to parse directory listing: ${(error as Error).message}`,\n ),\n );\n }\n },\n reject,\n timeout,\n });\n\n ws.send(\n JSON.stringify({\n type: \"dir:list\",\n requestId,\n path: dirPath,\n }),\n );\n });\n }\n}\n"],"mappings":";;;;;;;aAGwC;AAGxC,MAAM,SAAS,aAAa,oBAAoB;;;;;AAUhD,IAAa,gBAAb,MAAa,cAAc;CACzB,OAAe,WAAiC;CAChD,AAAQ,sBAAqD;CAE7D,AAAQ,cAAc;CAEtB,OAAO,cAA6B;AAClC,MAAI,CAAC,cAAc,SACjB,eAAc,WAAW,IAAI,MAAM,IAAI,eAAe,EAAE;GAItD,IAAI,QAAQ,MAAM,UAAU;AAC1B,QAAI,4BAA4B,CAC9B,QAAO,QAAQ,IAAI,QAAQ,MAAM,SAAS;IAG5C,MAAM,QAAQ,QAAQ,IAAI,QAAQ,MAAM,SAAS;AAEjD,QAAI,OAAO,UAAU,WACnB,QAAO,SAAS,OAAO;AACrB,YAAO,MAAM,qCAAqC,OAAO,KAAK,CAAC;AAC/D,YAAO,QAAQ,QAAQ,GAAG;;AAI9B,WAAO;;GAET,IAAI,QAAQ,MAAM,OAAO,UAAU;AACjC,WAAO,QAAQ,IAAI,QAAQ,MAAM,OAAO,SAAS;;GAEpD,CAAC;AAGJ,SAAO,cAAc;;CAGvB,qBAAqB,QAAgC;AACnD,OAAK,sBAAsB;;CAG7B,MAAM,SACJ,UACA,KACiB;AACjB,MAAI,CAAC,KAAK,oBACR,OAAM,YAAY,qBAAqB;EAEzC,MAAM,SAAS,KAAK,oBAAoB,IAAI;AAE5C,MAAI,CAAC,OACH,OAAM,YAAY,cAAc;EAGlC,MAAM,EAAE,IAAI,qBAAqB;EACjC,MAAM,YAAY,YAAY;AAE9B,SAAO,IAAI,SAAS,SAAS,WAAW;GACtC,MAAM,UAAU,iBAAiB;AAC/B,qBAAiB,OAAO,UAAU;AAClC,2BAAO,IAAI,MAAM,sBAAsB,WAAW,CAAC;MAClD,IAAM;AAET,oBAAiB,IAAI,WAAW;IAAE;IAAS;IAAQ;IAAS,CAAC;AAE7D,MAAG,KACD,KAAK,UAAU;IACb,MAAM;IACN;IACA,MAAM;IACP,CAAC,CACH;IACD;;CAGJ,MAAM,QACJ,SACA,KACmB;AACnB,MAAI,CAAC,KAAK,oBACR,OAAM,YAAY,qBAAqB;EAEzC,MAAM,SAAS,KAAK,oBAAoB,IAAI;AAE5C,MAAI,CAAC,OACH,OAAM,YAAY,cAAc;EAGlC,MAAM,EAAE,IAAI,qBAAqB;EACjC,MAAM,YAAY,YAAY;AAE9B,SAAO,IAAI,SAAS,SAAS,WAAW;GACtC,MAAM,UAAU,iBAAiB;AAC/B,qBAAiB,OAAO,UAAU;AAClC,2BAAO,IAAI,MAAM,2BAA2B,UAAU,CAAC;MACtD,IAAM;AAET,oBAAiB,IAAI,WAAW;IAC9B,UAAU,SAAiB;AACzB,SAAI;MACF,MAAM,QAAQ,KAAK,MAAM,KAAK;AAE9B,UAAI,CAAC,MAAM,QAAQ,MAAM,EAAE;AACzB,8BACE,IAAI,MACF,2DACE,OAAO,MACV,CACF;AACD;;AAEF,UAAI,CAAC,MAAM,OAAO,MAAM,OAAO,MAAM,SAAS,EAAE;AAC9C,8BACE,IAAI,MACF,8DACD,CACF;AACD;;AAEF,cAAQ,MAAM;cACP,OAAO;AACd,6BACE,IAAI,MACF,sCAAuC,MAAgB,UACxD,CACF;;;IAGL;IACA;IACD,CAAC;AAEF,MAAG,KACD,KAAK,UAAU;IACb,MAAM;IACN;IACA,MAAM;IACP,CAAC,CACH;IACD"}
1
+ {"version":3,"file":"dev-reader.js","names":[],"sources":["../../src/plugin/dev-reader.ts"],"sourcesContent":["import { randomUUID } from \"node:crypto\";\nimport type { TunnelConnection } from \"shared\";\nimport { isRemoteTunnelAllowedByEnv } from \"@/plugins/server/remote-tunnel/gate\";\nimport { TunnelError } from \"../errors\";\nimport { createLogger } from \"../logging/logger\";\n\nconst logger = createLogger(\"plugin:dev-reader\");\n\ntype TunnelConnectionGetter = (\n req: import(\"express\").Request,\n) => TunnelConnection | null;\n\n/**\n * This class is used to read files from the local filesystem in dev mode\n * through the WebSocket tunnel.\n */\nexport class DevFileReader {\n private static instance: DevFileReader | null = null;\n private getTunnelForRequest: TunnelConnectionGetter | null = null;\n\n private constructor() {}\n\n static getInstance(): DevFileReader {\n if (!DevFileReader.instance) {\n DevFileReader.instance = new Proxy(new DevFileReader(), {\n /**\n * We proxy the reader to return a noop function if the remote server is disabled.\n */\n get(target, prop, receiver) {\n if (isRemoteTunnelAllowedByEnv()) {\n return Reflect.get(target, prop, receiver);\n }\n\n const value = Reflect.get(target, prop, receiver);\n\n if (typeof value === \"function\") {\n return function noop() {\n logger.debug(\"Noop: %s (remote server disabled)\", String(prop));\n return Promise.resolve(\"\");\n };\n }\n\n return value;\n },\n set(target, prop, value, receiver) {\n return Reflect.set(target, prop, value, receiver);\n },\n });\n }\n\n return DevFileReader.instance;\n }\n\n registerTunnelGetter(getter: TunnelConnectionGetter) {\n this.getTunnelForRequest = getter;\n }\n\n async readFile(\n filePath: string,\n req: import(\"express\").Request,\n ): Promise<string> {\n if (!this.getTunnelForRequest) {\n throw TunnelError.getterNotRegistered();\n }\n const tunnel = this.getTunnelForRequest(req);\n\n if (!tunnel) {\n throw TunnelError.noConnection();\n }\n\n const { ws, pendingFileReads } = tunnel;\n const requestId = randomUUID();\n\n return new Promise((resolve, reject) => {\n const timeout = setTimeout(() => {\n pendingFileReads.delete(requestId);\n reject(new Error(`File read timeout: ${filePath}`));\n }, 10000);\n\n pendingFileReads.set(requestId, { resolve, reject, timeout });\n\n ws.send(\n JSON.stringify({\n type: \"file:read\",\n requestId,\n path: filePath,\n }),\n );\n });\n }\n\n async readdir(\n dirPath: string,\n req: import(\"express\").Request,\n ): Promise<string[]> {\n if (!this.getTunnelForRequest) {\n throw TunnelError.getterNotRegistered();\n }\n const tunnel = this.getTunnelForRequest(req);\n\n if (!tunnel) {\n throw TunnelError.noConnection();\n }\n\n const { ws, pendingFileReads } = tunnel;\n const requestId = randomUUID();\n\n return new Promise((resolve, reject) => {\n const timeout = setTimeout(() => {\n pendingFileReads.delete(requestId);\n reject(new Error(`Directory read timeout: ${dirPath}`));\n }, 10000);\n\n pendingFileReads.set(requestId, {\n resolve: (data: string) => {\n try {\n const files = JSON.parse(data);\n // Validate it's an array of strings\n if (!Array.isArray(files)) {\n reject(\n new Error(\n \"Invalid directory listing format: expected array, got \" +\n typeof files,\n ),\n );\n return;\n }\n if (!files.every((f) => typeof f === \"string\")) {\n reject(\n new Error(\n \"Invalid directory listing format: expected array of strings\",\n ),\n );\n return;\n }\n resolve(files);\n } catch (error) {\n reject(\n new Error(\n `Failed to parse directory listing: ${(error as Error).message}`,\n ),\n );\n }\n },\n reject,\n timeout,\n });\n\n ws.send(\n JSON.stringify({\n type: \"dir:list\",\n requestId,\n path: dirPath,\n }),\n );\n });\n }\n}\n"],"mappings":";;;;;;;aAGwC;AAGxC,MAAM,SAAS,aAAa,oBAAoB;;;;;AAUhD,IAAa,gBAAb,MAAa,cAAc;CACzB,OAAe,WAAiC;CAChD,AAAQ,sBAAqD;CAE7D,AAAQ,cAAc;CAEtB,OAAO,cAA6B;AAClC,MAAI,CAAC,cAAc,SACjB,eAAc,WAAW,IAAI,MAAM,IAAI,eAAe,EAAE;GAItD,IAAI,QAAQ,MAAM,UAAU;AAC1B,QAAI,4BAA4B,CAC9B,QAAO,QAAQ,IAAI,QAAQ,MAAM,SAAS;IAG5C,MAAM,QAAQ,QAAQ,IAAI,QAAQ,MAAM,SAAS;AAEjD,QAAI,OAAO,UAAU,WACnB,QAAO,SAAS,OAAO;AACrB,YAAO,MAAM,qCAAqC,OAAO,KAAK,CAAC;AAC/D,YAAO,QAAQ,QAAQ,GAAG;;AAI9B,WAAO;;GAET,IAAI,QAAQ,MAAM,OAAO,UAAU;AACjC,WAAO,QAAQ,IAAI,QAAQ,MAAM,OAAO,SAAS;;GAEpD,CAAC;AAGJ,SAAO,cAAc;;CAGvB,qBAAqB,QAAgC;AACnD,OAAK,sBAAsB;;CAG7B,MAAM,SACJ,UACA,KACiB;AACjB,MAAI,CAAC,KAAK,oBACR,OAAM,YAAY,qBAAqB;EAEzC,MAAM,SAAS,KAAK,oBAAoB,IAAI;AAE5C,MAAI,CAAC,OACH,OAAM,YAAY,cAAc;EAGlC,MAAM,EAAE,IAAI,qBAAqB;EACjC,MAAM,YAAY,YAAY;AAE9B,SAAO,IAAI,SAAS,SAAS,WAAW;GACtC,MAAM,UAAU,iBAAiB;AAC/B,qBAAiB,OAAO,UAAU;AAClC,2BAAO,IAAI,MAAM,sBAAsB,WAAW,CAAC;MAClD,IAAM;AAET,oBAAiB,IAAI,WAAW;IAAE;IAAS;IAAQ;IAAS,CAAC;AAE7D,MAAG,KACD,KAAK,UAAU;IACb,MAAM;IACN;IACA,MAAM;IACP,CAAC,CACH;IACD;;CAGJ,MAAM,QACJ,SACA,KACmB;AACnB,MAAI,CAAC,KAAK,oBACR,OAAM,YAAY,qBAAqB;EAEzC,MAAM,SAAS,KAAK,oBAAoB,IAAI;AAE5C,MAAI,CAAC,OACH,OAAM,YAAY,cAAc;EAGlC,MAAM,EAAE,IAAI,qBAAqB;EACjC,MAAM,YAAY,YAAY;AAE9B,SAAO,IAAI,SAAS,SAAS,WAAW;GACtC,MAAM,UAAU,iBAAiB;AAC/B,qBAAiB,OAAO,UAAU;AAClC,2BAAO,IAAI,MAAM,2BAA2B,UAAU,CAAC;MACtD,IAAM;AAET,oBAAiB,IAAI,WAAW;IAC9B,UAAU,SAAiB;AACzB,SAAI;MACF,MAAM,QAAQ,KAAK,MAAM,KAAK;AAE9B,UAAI,CAAC,MAAM,QAAQ,MAAM,EAAE;AACzB,8BACE,IAAI,MACF,2DACE,OAAO,MACV,CACF;AACD;;AAEF,UAAI,CAAC,MAAM,OAAO,MAAM,OAAO,MAAM,SAAS,EAAE;AAC9C,8BACE,IAAI,MACF,8DACD,CACF;AACD;;AAEF,cAAQ,MAAM;cACP,OAAO;AACd,6BACE,IAAI,MACF,sCAAuC,MAAgB,UACxD,CACF;;;IAGL;IACA;IACD,CAAC;AAEF,MAAG,KACD,KAAK,UAAU;IACb,MAAM;IACN;IACA,MAAM;IACP,CAAC,CACH;IACD"}
@@ -1,9 +1,9 @@
1
1
  import { BasePlugin, BasePluginConfig, IAppResponse, PluginEndpointMap, PluginPhase, RouteConfig } from "../shared/src/plugin.js";
2
2
  import { PluginExecutionSettings, StreamExecuteHandler, StreamExecutionSettings } from "../shared/src/execute.js";
3
- import { AppManager } from "../app/index.js";
4
3
  import { CacheManager } from "../cache/index.js";
5
- import { StreamManager } from "../stream/stream-manager.js";
6
4
  import { ITelemetry } from "../telemetry/types.js";
5
+ import { AppManager } from "../app/index.js";
6
+ import { StreamManager } from "../stream/stream-manager.js";
7
7
  import { DevFileReader } from "./dev-reader.js";
8
8
  import express from "express";
9
9
 
@@ -9,8 +9,8 @@ import { deepMerge } from "../utils/merge.js";
9
9
  import { ServiceContext } from "../context/service-context.js";
10
10
  import { getCurrentUserId, runInUserContext } from "../context/execution-context.js";
11
11
  import { init_context } from "../context/index.js";
12
- import { AppManager } from "../app/index.js";
13
12
  import { CacheManager } from "../cache/index.js";
13
+ import { AppManager } from "../app/index.js";
14
14
  import { StreamManager } from "../stream/stream-manager.js";
15
15
  import "../stream/index.js";
16
16
  import { DevFileReader } from "./dev-reader.js";
@@ -1,11 +1,11 @@
1
- import { IAppRouter, ToPlugin } from "../shared/src/plugin.js";
2
- import { SQLTypeMarker } from "../shared/src/sql/types.js";
3
- import { Plugin } from "../plugin/plugin.js";
1
+ import { IAppRouter, ToPlugin } from "../../shared/src/plugin.js";
2
+ import { SQLTypeMarker } from "../../shared/src/sql/types.js";
3
+ import { Plugin } from "../../plugin/plugin.js";
4
4
  import { IAnalyticsConfig } from "./types.js";
5
5
  import { WorkspaceClient } from "@databricks/sdk-experimental";
6
6
  import express from "express";
7
7
 
8
- //#region src/analytics/analytics.d.ts
8
+ //#region src/plugins/analytics/analytics.d.ts
9
9
  declare class AnalyticsPlugin extends Plugin {
10
10
  name: string;
11
11
  protected envVars: string[];
@@ -0,0 +1 @@
1
+ {"version":3,"file":"analytics.d.ts","names":[],"sources":["../../../src/plugins/analytics/analytics.ts"],"sourcesContent":[],"mappings":";;;;;;;;cA0Ba,eAAA,SAAwB,MAAA;;;EAAxB,iBAAA,WAAgB,EAAA,MAAA;EAAA,UAAA,MAAA,EAKD,gBALC;UAKD,SAAA;UAMN,cAAA;aAWC,CAAA,MAAA,EAXD,gBAWC;cA0BN,CAAA,MAAA,EA1BM,UA0BN,CAAA,EAAA,IAAA;;;;;mBA2CZ,CAAA,GAAA,EA3CI,OAAA,CAAQ,OA2CZ,EAAA,GAAA,EA1CI,OAAA,CAAQ,QA0CZ,CAAA,EAzCA,OAyCA,CAAA,IAAA,CAAA;;;;;mBAkHA,CAAA,GAAA,EApHI,OAAA,CAAQ,OAoHZ,EAAA,GAAA,EAnHI,OAAA,CAAQ,QAmHZ,CAAA,EAlHA,OAkHA,CAAA,IAAA,CAAA;;;;;;;;;;;;;AAqDL;;;OAAsB,CAAA,KAAA,EAAA,MAAA,EAAA,UAAA,CAAA,EAxDL,MAwDK,CAAA,MAAA,EAxDU,aAwDV,GAAA,IAAA,GAAA,SAAA,CAAA,EAAA,gBAAA,CAAA,EAvDC,MAuDD,CAAA,MAAA,EAAA,GAAA,CAAA,EAAA,MAAA,CAAA,EAtDT,WAsDS,CAAA,EArDjB,OAqDiB,CAAA,GAAA,CAAA;;;;0CA5BD,yCAER,cACR,QAAQ;cAIO;;;;;;;;;wCAnCH,eAAe,sDACT,8BACV,gBACR;;;;;;cAqDQ,WAAS,gBAAA,iBAAA"}
@@ -1,15 +1,15 @@
1
- import { createLogger } from "../logging/logger.js";
2
- import { getCurrentUserId, getWarehouseId, getWorkspaceClient } from "../context/execution-context.js";
3
- import { init_context } from "../context/index.js";
4
- import { SQLWarehouseConnector } from "../connectors/sql-warehouse/client.js";
5
- import "../connectors/index.js";
6
- import { Plugin } from "../plugin/plugin.js";
7
- import { toPlugin } from "../plugin/to-plugin.js";
8
- import "../plugin/index.js";
1
+ import { createLogger } from "../../logging/logger.js";
2
+ import { getCurrentUserId, getWarehouseId, getWorkspaceClient } from "../../context/execution-context.js";
3
+ import { init_context } from "../../context/index.js";
4
+ import { SQLWarehouseConnector } from "../../connectors/sql-warehouse/client.js";
5
+ import "../../connectors/index.js";
6
+ import { Plugin } from "../../plugin/plugin.js";
7
+ import { toPlugin } from "../../plugin/to-plugin.js";
8
+ import "../../plugin/index.js";
9
9
  import { queryDefaults } from "./defaults.js";
10
10
  import { QueryProcessor } from "./query.js";
11
11
 
12
- //#region src/analytics/analytics.ts
12
+ //#region src/plugins/analytics/analytics.ts
13
13
  init_context();
14
14
  const logger = createLogger("analytics");
15
15
  var AnalyticsPlugin = class extends Plugin {
@@ -0,0 +1 @@
1
+ {"version":3,"file":"analytics.js","names":[],"sources":["../../../src/plugins/analytics/analytics.ts"],"sourcesContent":["import type { WorkspaceClient } from \"@databricks/sdk-experimental\";\nimport type express from \"express\";\nimport type {\n IAppRouter,\n PluginExecuteConfig,\n SQLTypeMarker,\n StreamExecutionSettings,\n} from \"shared\";\nimport { SQLWarehouseConnector } from \"../../connectors\";\nimport {\n getCurrentUserId,\n getWarehouseId,\n getWorkspaceClient,\n} from \"../../context\";\nimport { createLogger } from \"../../logging/logger\";\nimport { Plugin, toPlugin } from \"../../plugin\";\nimport { queryDefaults } from \"./defaults\";\nimport { QueryProcessor } from \"./query\";\nimport type {\n AnalyticsQueryResponse,\n IAnalyticsConfig,\n IAnalyticsQueryRequest,\n} from \"./types\";\n\nconst logger = createLogger(\"analytics\");\n\nexport class AnalyticsPlugin extends Plugin {\n name = \"analytics\";\n protected envVars: string[] = [];\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 // Service principal endpoints\n this.route(router, {\n name: \"arrow\",\n method: \"get\",\n path: \"/arrow-result/:jobId\",\n handler: async (req: express.Request, res: express.Response) => {\n await this._handleArrowRoute(req, res);\n },\n });\n\n this.route<AnalyticsQueryResponse>(router, {\n name: \"query\",\n method: \"post\",\n path: \"/query/:query_key\",\n handler: async (req: express.Request, res: express.Response) => {\n await this._handleQueryRoute(req, res);\n },\n });\n }\n\n /**\n * Handle Arrow data download requests.\n * When called via asUser(req), uses the user's Databricks credentials.\n */\n async _handleArrowRoute(\n req: express.Request,\n res: express.Response,\n ): Promise<void> {\n try {\n const { jobId } = req.params;\n const workspaceClient = getWorkspaceClient();\n\n logger.debug(\"Processing Arrow job request for jobId=%s\", jobId);\n\n const event = logger.event(req);\n event?.setComponent(\"analytics\", \"getArrowData\").setContext(\"analytics\", {\n job_id: jobId,\n 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 logger.debug(\n \"Sending Arrow buffer: %d bytes for job %s\",\n result.data.length,\n jobId,\n );\n res.send(Buffer.from(result.data));\n } catch (error) {\n logger.error(\"Arrow job error: %O\", 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 /**\n * Handle SQL query execution requests.\n * When called via asUser(req), uses the user's Databricks credentials.\n */\n async _handleQueryRoute(\n req: express.Request,\n res: express.Response,\n ): Promise<void> {\n const { query_key } = req.params;\n const { parameters, format = \"JSON\" } = req.body as IAnalyticsQueryRequest;\n\n // Request-scoped logging with WideEvent tracking\n logger.debug(req, \"Executing query: %s (format=%s)\", query_key, format);\n\n const event = logger.event(req);\n event?.setComponent(\"analytics\", \"executeQuery\").setContext(\"analytics\", {\n query_key,\n format,\n parameter_count: parameters ? Object.keys(parameters).length : 0,\n plugin: this.name,\n });\n\n if (!query_key) {\n res.status(400).json({ error: \"query_key is required\" });\n return;\n }\n\n const queryResult = await this.app.getAppQuery(\n query_key,\n req,\n this.devFileReader,\n );\n\n if (!queryResult) {\n res.status(404).json({ error: \"Query not found\" });\n return;\n }\n\n const { query, isAsUser } = queryResult;\n\n // get execution context - user-scoped if .obo.sql, otherwise service principal\n const executor = isAsUser ? this.asUser(req) : this;\n const userKey = getCurrentUserId();\n const executorKey = isAsUser ? userKey : \"global\";\n\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 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 executorKey,\n ],\n },\n };\n\n const streamExecutionSettings: StreamExecutionSettings = {\n default: defaultConfig,\n };\n\n await executor.executeStream(\n res,\n async (signal) => {\n const processedParams = await this.queryProcessor.processQueryParams(\n query,\n parameters,\n );\n\n const result = await executor.query(\n query,\n processedParams,\n queryParameters.formatParameters,\n signal,\n );\n\n return { type: queryParameters.type, ...result };\n },\n streamExecutionSettings,\n executorKey,\n );\n }\n\n /**\n * Execute a SQL query using the current execution context.\n *\n * When called directly: uses service principal credentials.\n * When called via asUser(req).query(...): uses user's credentials.\n *\n * @example\n * ```typescript\n * // Service principal execution\n * const result = await analytics.query(\"SELECT * FROM table\")\n *\n * // User context execution (in route handler)\n * const result = await this.asUser(req).query(\"SELECT * FROM table\")\n * ```\n */\n async query(\n query: string,\n parameters?: Record<string, SQLTypeMarker | null | undefined>,\n formatParameters?: Record<string, any>,\n signal?: AbortSignal,\n ): Promise<any> {\n const workspaceClient = getWorkspaceClient();\n const warehouseId = await getWarehouseId();\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: warehouseId,\n parameters: sqlParameters,\n ...formatParameters,\n },\n signal,\n );\n\n return response.result;\n }\n\n /**\n * Get Arrow-formatted data for a completed query job.\n */\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 /**\n * Returns the public exports for the analytics plugin.\n * Note: `asUser()` is automatically added by AppKit.\n */\n exports() {\n return {\n /**\n * Execute a SQL query using service principal credentials.\n */\n query: this.query,\n };\n }\n}\n\n/**\n * @internal\n */\nexport const analytics = toPlugin<\n typeof AnalyticsPlugin,\n IAnalyticsConfig,\n \"analytics\"\n>(AnalyticsPlugin, \"analytics\");\n"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- //#region src/analytics/defaults.ts
1
+ //#region src/plugins/analytics/defaults.ts
2
2
  const queryDefaults = {
3
3
  cache: {
4
4
  enabled: true,
@@ -0,0 +1 @@
1
+ {"version":3,"file":"defaults.js","names":[],"sources":["../../../src/plugins/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,MAAa,gBAAqC;CAChD,OAAO;EACL,SAAS;EACT,KAAK;EACN;CACD,OAAO;EACL,SAAS;EACT,cAAc;EACd,UAAU;EACX;CACD,SAAS;CACV"}
@@ -1,11 +1,11 @@
1
- import { isSQLTypeMarker, sql } from "../shared/src/sql/helpers.js";
2
- import { ValidationError } from "../errors/validation.js";
3
- import { init_errors } from "../errors/index.js";
4
- import { getWorkspaceId } from "../context/execution-context.js";
5
- import { init_context } from "../context/index.js";
1
+ import { isSQLTypeMarker, sql } from "../../shared/src/sql/helpers.js";
2
+ import { ValidationError } from "../../errors/validation.js";
3
+ import { init_errors } from "../../errors/index.js";
4
+ import { getWorkspaceId } from "../../context/execution-context.js";
5
+ import { init_context } from "../../context/index.js";
6
6
  import { createHash } from "node:crypto";
7
7
 
8
- //#region src/analytics/query.ts
8
+ //#region src/plugins/analytics/query.ts
9
9
  init_context();
10
10
  init_errors();
11
11
  var QueryProcessor = class {
@@ -0,0 +1 @@
1
+ {"version":3,"file":"query.js","names":["sqlHelpers"],"sources":["../../../src/plugins/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 { getWorkspaceId } from \"../../context\";\nimport { ValidationError } from \"../../errors\";\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 workspaceId = await getWorkspaceId();\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 const validParams = Array.from(queryParams).join(\", \") || \"none\";\n throw ValidationError.invalidValue(\n key,\n parameters[key],\n `a parameter defined in the query (valid: ${validParams})`,\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 ValidationError.invalidValue(\n key,\n value,\n \"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":";;;;;;;;cAG+C;aACA;AAI/C,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;GAC5D,MAAM,cAAc,MAAM,gBAAgB;AAC1C,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,MAAM,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,EAAE;IACzB,MAAM,cAAc,MAAM,KAAK,YAAY,CAAC,KAAK,KAAK,IAAI;AAC1D,UAAM,gBAAgB,aACpB,KACA,WAAW,MACX,4CAA4C,YAAY,GACzD;;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,gBAAgB,aACpB,KACA,OACA,2FACD;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/plugins/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/plugins/analytics/types.ts"],"sourcesContent":[],"mappings":";;;UAEiB,gBAAA,SAAyB;;AAA1C"}
@@ -0,0 +1,5 @@
1
+ import { AnalyticsPlugin, analytics } from "./analytics/analytics.js";
2
+ import "./analytics/index.js";
3
+ import { ServerPlugin, server } from "./server/index.js";
4
+
5
+ export { };
@@ -1,6 +1,6 @@
1
1
  import { getConfigScript } from "./utils.js";
2
2
 
3
- //#region src/server/base-server.ts
3
+ //#region src/plugins/server/base-server.ts
4
4
  /**
5
5
  * Base server for the AppKit.
6
6
  *
@@ -0,0 +1 @@
1
+ {"version":3,"file":"base-server.js","names":[],"sources":["../../../src/plugins/server/base-server.ts"],"sourcesContent":["import type express from \"express\";\nimport { getConfigScript, type PluginEndpoints } from \"./utils\";\n\n/**\n * Base server for the AppKit.\n *\n * Abstract base class that provides common functionality for serving\n * frontend applications. Subclasses implement specific serving strategies\n * (Vite dev server, static file server, etc.).\n */\nexport abstract class BaseServer {\n protected app: express.Application;\n protected endpoints: PluginEndpoints;\n\n constructor(app: express.Application, endpoints: PluginEndpoints = {}) {\n this.app = app;\n this.endpoints = endpoints;\n }\n\n abstract setup(): void | Promise<void>;\n\n async close(): Promise<void> {}\n\n protected getConfigScript(): string {\n return getConfigScript(this.endpoints);\n }\n}\n"],"mappings":";;;;;;;;;;AAUA,IAAsB,aAAtB,MAAiC;CAC/B,AAAU;CACV,AAAU;CAEV,YAAY,KAA0B,YAA6B,EAAE,EAAE;AACrE,OAAK,MAAM;AACX,OAAK,YAAY;;CAKnB,MAAM,QAAuB;CAE7B,AAAU,kBAA0B;AAClC,SAAO,gBAAgB,KAAK,UAAU"}
@@ -1,10 +1,10 @@
1
- import { PluginPhase, TelemetryOptions, ToPlugin } from "../shared/src/plugin.js";
2
- import { Plugin } from "../plugin/plugin.js";
1
+ import { PluginPhase, TelemetryOptions, ToPlugin } from "../../shared/src/plugin.js";
2
+ import { Plugin } from "../../plugin/plugin.js";
3
3
  import { ServerConfig } from "./types.js";
4
4
  import express from "express";
5
5
  import { Server } from "node:http";
6
6
 
7
- //#region src/server/index.d.ts
7
+ //#region src/plugins/server/index.d.ts
8
8
 
9
9
  /**
10
10
  * Server plugin for the AppKit.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../../../src/plugins/server/index.ts"],"sourcesContent":[],"mappings":";;;;;;;;;;AAkCA;;;;;;;;;;;;AAwDiB,cAxDJ,YAAA,SAAqB,MAAA,CAwDjB;SAsPM,cAAQ,EAAA;IAxMhB,SAAA,EAAA,OAAA;IAAU,IAAA,EAAA,MAAA;IAtGS,IAAA,EAAA,MAAA;EAAM,CAAA;EA+T3B,IAAA,EAAA,QAGZ;EAAA,UAAA,OAAA,EAAA,MAAA,EAAA;UAHkB,iBAAA;UAAA,MAAA;UAAA,aAAA;EAAA,QAAA,sBAAA;oBAlTS;;gBAEZ;sBAEM;;WAaT;;;;;;;;;gBAAA;;;;;;;;;;;;WA0BI,QAAQ,OAAA,CAAQ;;;;;;;;;eA8ClB;;;;;;;;mBAmBI,OAAA,CAAQ;;;;;;;;;;;;;;;;;;;;;;;;iBAjEV,QAAQ,OAAA,CAAQ;;qBAsPV,OAAA,CAAQ;;qBAxMhB;;;;;;;;;kBAAU;;;;;;;cAyNZ,QAAM,gBAAA,cAAA"}
@@ -1,11 +1,11 @@
1
- import { instrumentations } from "../telemetry/instrumentations.js";
2
- import { createLogger } from "../logging/logger.js";
3
- import "../telemetry/index.js";
4
- import { ServerError } from "../errors/server.js";
5
- import { init_errors } from "../errors/index.js";
6
- import { Plugin } from "../plugin/plugin.js";
7
- import { toPlugin } from "../plugin/to-plugin.js";
8
- import "../plugin/index.js";
1
+ import { instrumentations } from "../../telemetry/instrumentations.js";
2
+ import { createLogger } from "../../logging/logger.js";
3
+ import "../../telemetry/index.js";
4
+ import { ServerError } from "../../errors/server.js";
5
+ import { init_errors } from "../../errors/index.js";
6
+ import { Plugin } from "../../plugin/plugin.js";
7
+ import { toPlugin } from "../../plugin/to-plugin.js";
8
+ import "../../plugin/index.js";
9
9
  import { RemoteTunnelController } from "./remote-tunnel/remote-tunnel-controller.js";
10
10
  import { getRoutes } from "./utils.js";
11
11
  import { StaticServer } from "./static-server.js";
@@ -15,7 +15,7 @@ import fs from "node:fs";
15
15
  import dotenv from "dotenv";
16
16
  import express from "express";
17
17
 
18
- //#region src/server/index.ts
18
+ //#region src/plugins/server/index.ts
19
19
  init_errors();
20
20
  dotenv.config({ path: path.resolve(process.cwd(), "./.env") });
21
21
  const logger = createLogger("server");
@@ -240,5 +240,5 @@ const EXCLUDED_PLUGINS = [ServerPlugin.name];
240
240
  const server = toPlugin(ServerPlugin, "server");
241
241
 
242
242
  //#endregion
243
- export { server };
243
+ export { ServerPlugin, server };
244
244
  //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../../src/plugins/server/index.ts"],"sourcesContent":["import fs from \"node:fs\";\nimport type { Server as HTTPServer } from \"node:http\";\nimport path from \"node:path\";\nimport dotenv from \"dotenv\";\nimport express from \"express\";\nimport type { PluginPhase } from \"shared\";\nimport { ServerError } from \"../../errors\";\nimport { createLogger } from \"../../logging/logger\";\nimport { Plugin, toPlugin } from \"../../plugin\";\nimport { instrumentations } from \"../../telemetry\";\nimport { RemoteTunnelController } from \"./remote-tunnel/remote-tunnel-controller\";\nimport { StaticServer } from \"./static-server\";\nimport type { ServerConfig } from \"./types\";\nimport { getRoutes, type PluginEndpoints } from \"./utils\";\nimport { ViteDevServer } from \"./vite-dev-server\";\n\ndotenv.config({ path: path.resolve(process.cwd(), \"./.env\") });\n\nconst logger = createLogger(\"server\");\n\n/**\n * Server plugin for the AppKit.\n *\n * This plugin is responsible for starting the server and serving the static files.\n * It also handles the remote tunneling for development purposes.\n *\n * @example\n * ```ts\n * createApp({\n * plugins: [server(), telemetryExamples(), analytics({})],\n * });\n * ```\n *\n */\nexport class ServerPlugin extends Plugin {\n public static DEFAULT_CONFIG = {\n autoStart: true,\n host: process.env.FLASK_RUN_HOST || \"0.0.0.0\",\n port: Number(process.env.DATABRICKS_APP_PORT) || 8000,\n };\n\n public name = \"server\" as const;\n protected envVars: string[] = [];\n private serverApplication: express.Application;\n private server: HTTPServer | null;\n private viteDevServer?: ViteDevServer;\n private remoteTunnelController?: RemoteTunnelController;\n protected declare config: ServerConfig;\n private serverExtensions: ((app: express.Application) => void)[] = [];\n static phase: PluginPhase = \"deferred\";\n\n constructor(config: ServerConfig) {\n super(config);\n this.config = config;\n this.serverApplication = express();\n this.server = null;\n this.serverExtensions = [];\n this.telemetry.registerInstrumentations([\n instrumentations.http,\n instrumentations.express,\n ]);\n }\n\n /** Setup the server plugin. */\n async setup() {\n if (this.shouldAutoStart()) {\n await this.start();\n }\n }\n\n /** Get the server configuration. */\n getConfig() {\n const { plugins: _plugins, ...config } = this.config;\n\n return config;\n }\n\n /** Check if the server should auto start. */\n shouldAutoStart() {\n return this.config.autoStart;\n }\n\n /**\n * Start the server.\n *\n * This method starts the server and sets up the frontend.\n * It also sets up the remote tunneling if enabled.\n *\n * @returns The express application.\n */\n async start(): Promise<express.Application> {\n this.serverApplication.use(express.json());\n\n const endpoints = await this.extendRoutes();\n\n for (const extension of this.serverExtensions) {\n extension(this.serverApplication);\n }\n\n // register remote tunnel controller (before static/vite)\n this.remoteTunnelController = new RemoteTunnelController(\n this.devFileReader,\n );\n this.serverApplication.use(this.remoteTunnelController.middleware);\n\n await this.setupFrontend(endpoints);\n\n const server = this.serverApplication.listen(\n this.config.port ?? ServerPlugin.DEFAULT_CONFIG.port,\n this.config.host ?? ServerPlugin.DEFAULT_CONFIG.host,\n () => this.logStartupInfo(),\n );\n\n this.server = server;\n\n // attach server to remote tunnel controller\n this.remoteTunnelController.setServer(server);\n\n process.on(\"SIGTERM\", () => this._gracefulShutdown());\n process.on(\"SIGINT\", () => this._gracefulShutdown());\n\n if (process.env.NODE_ENV === \"development\") {\n const allRoutes = getRoutes(this.serverApplication._router.stack);\n console.dir(allRoutes, { depth: null });\n }\n return this.serverApplication;\n }\n\n /**\n * Get the low level node.js http server instance.\n *\n * Only use this method if you need to access the server instance for advanced usage like a custom websocket server, etc.\n *\n * @throws {Error} If the server is not started or autoStart is true.\n * @returns {HTTPServer} The server instance.\n */\n getServer(): HTTPServer {\n if (this.shouldAutoStart()) {\n throw ServerError.autoStartConflict(\"get server\");\n }\n\n if (!this.server) {\n throw ServerError.notStarted();\n }\n\n return this.server;\n }\n\n /**\n * Extend the server with custom routes or middleware.\n *\n * @param fn - A function that receives the express application.\n * @returns The server plugin instance for chaining.\n * @throws {Error} If autoStart is true.\n */\n extend(fn: (app: express.Application) => void) {\n if (this.shouldAutoStart()) {\n throw ServerError.autoStartConflict(\"extend server\");\n }\n\n this.serverExtensions.push(fn);\n return this;\n }\n\n /**\n * Setup the routes with the plugins.\n *\n * This method goes through all the plugins and injects the routes into the server application.\n * Returns a map of plugin names to their registered named endpoints.\n */\n private async extendRoutes(): Promise<PluginEndpoints> {\n const endpoints: PluginEndpoints = {};\n\n if (!this.config.plugins) return endpoints;\n\n this.serverApplication.get(\"/health\", (_, res) => {\n res.status(200).json({ status: \"ok\" });\n });\n this.registerEndpoint(\"health\", \"/health\");\n\n for (const plugin of Object.values(this.config.plugins)) {\n if (EXCLUDED_PLUGINS.includes(plugin.name)) continue;\n\n if (plugin?.injectRoutes && typeof plugin.injectRoutes === \"function\") {\n const router = express.Router();\n\n plugin.injectRoutes(router);\n\n const basePath = `/api/${plugin.name}`;\n this.serverApplication.use(basePath, router);\n\n // Collect named endpoints from the plugin\n endpoints[plugin.name] = plugin.getEndpoints();\n }\n }\n\n return endpoints;\n }\n\n /**\n * Setup frontend serving based on environment:\n * - If staticPath is explicitly provided: use static server\n * - Dev mode (no staticPath): Vite for HMR\n * - Production (no staticPath): Static files auto-detected\n */\n private async setupFrontend(endpoints: PluginEndpoints) {\n const isDev = process.env.NODE_ENV === \"development\";\n const hasExplicitStaticPath = this.config.staticPath !== undefined;\n\n // explict static path provided\n if (hasExplicitStaticPath) {\n const staticServer = new StaticServer(\n this.serverApplication,\n this.config.staticPath as string,\n endpoints,\n );\n staticServer.setup();\n return;\n }\n\n // auto-detection based on environment\n if (isDev) {\n this.viteDevServer = new ViteDevServer(this.serverApplication, endpoints);\n await this.viteDevServer.setup();\n return;\n }\n\n // auto-detection based on static path\n const staticPath = ServerPlugin.findStaticPath();\n if (staticPath) {\n const staticServer = new StaticServer(\n this.serverApplication,\n staticPath,\n endpoints,\n );\n\n staticServer.setup();\n }\n }\n\n private static findStaticPath() {\n const staticPaths = [\"dist\", \"client/dist\", \"build\", \"public\", \"out\"];\n const cwd = process.cwd();\n for (const p of staticPaths) {\n const fullPath = path.resolve(cwd, p);\n if (fs.existsSync(path.resolve(fullPath, \"index.html\"))) {\n logger.debug(\"Static files: serving from %s\", fullPath);\n return fullPath;\n }\n }\n return undefined;\n }\n\n private logStartupInfo() {\n const isDev = process.env.NODE_ENV === \"development\";\n const hasExplicitStaticPath = this.config.staticPath !== undefined;\n const port = this.config.port ?? ServerPlugin.DEFAULT_CONFIG.port;\n const host = this.config.host ?? ServerPlugin.DEFAULT_CONFIG.host;\n\n logger.info(\"Server running on http://%s:%d\", host, port);\n\n if (hasExplicitStaticPath) {\n logger.info(\"Mode: static (%s)\", this.config.staticPath);\n } else if (isDev) {\n logger.info(\"Mode: development (Vite HMR)\");\n } else {\n logger.info(\"Mode: production (static)\");\n }\n\n const remoteServerController = this.remoteTunnelController;\n if (!remoteServerController) {\n logger.debug(\"Remote tunnel: disabled (controller not initialized)\");\n } else {\n logger.debug(\n \"Remote tunnel: %s; %s\",\n remoteServerController.isAllowedByEnv() ? \"allowed\" : \"blocked\",\n remoteServerController.isActive() ? \"active\" : \"inactive\",\n );\n }\n }\n\n private async _gracefulShutdown() {\n logger.info(\"Starting graceful shutdown...\");\n\n if (this.viteDevServer) {\n await this.viteDevServer.close();\n }\n\n if (this.remoteTunnelController) {\n this.remoteTunnelController.cleanup();\n }\n\n // 1. abort active operations from plugins\n if (this.config.plugins) {\n for (const plugin of Object.values(this.config.plugins)) {\n if (plugin.abortActiveOperations) {\n try {\n plugin.abortActiveOperations();\n } catch (err) {\n logger.error(\n \"Error aborting operations for plugin %s: %O\",\n plugin.name,\n err,\n );\n }\n }\n }\n }\n\n // 2. close the server\n if (this.server) {\n this.server.close(() => {\n logger.debug(\"Server closed gracefully\");\n process.exit(0);\n });\n\n // 3. timeout to force shutdown after 15 seconds\n setTimeout(() => {\n logger.debug(\"Force shutdown after timeout\");\n process.exit(1);\n }, 15000);\n } else {\n process.exit(0);\n }\n }\n\n /**\n * Returns the public exports for the server plugin.\n * Exposes server management methods.\n */\n exports() {\n const self = this;\n return {\n /** Start the server */\n start: this.start,\n /** Extend the server with custom routes or middleware */\n extend(fn: (app: express.Application) => void) {\n self.extend(fn);\n return this;\n },\n /** Get the underlying HTTP server instance */\n getServer: this.getServer,\n /** Get the server configuration */\n getConfig: this.getConfig,\n };\n }\n}\n\nconst EXCLUDED_PLUGINS = [ServerPlugin.name];\n\n/**\n * @internal\n */\nexport const server = toPlugin<typeof ServerPlugin, ServerConfig, \"server\">(\n ServerPlugin,\n \"server\",\n);\n"],"mappings":"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"}