@hexclave/shared 1.0.36 → 1.0.38

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 (103) hide show
  1. package/dist/ai/unified-prompts/reminders.js +2 -1
  2. package/dist/ai/unified-prompts/reminders.js.map +1 -1
  3. package/dist/ai/unified-prompts/skill-site-prompt-parts/ai-setup-prompt.js +2 -2
  4. package/dist/ai/unified-prompts/skill-site-prompt-parts/ai-setup-prompt.js.map +1 -1
  5. package/dist/config/format.js +10 -0
  6. package/dist/config/format.js.map +1 -1
  7. package/dist/config/schema.d.ts +147 -147
  8. package/dist/config-eval.d.ts +31 -0
  9. package/dist/config-eval.d.ts.map +1 -0
  10. package/dist/config-eval.js +117 -0
  11. package/dist/config-eval.js.map +1 -0
  12. package/dist/config-rendering.d.ts +3 -6
  13. package/dist/config-rendering.d.ts.map +1 -1
  14. package/dist/config-rendering.js +21 -69
  15. package/dist/config-rendering.js.map +1 -1
  16. package/dist/esm/ai/unified-prompts/reminders.js +2 -1
  17. package/dist/esm/ai/unified-prompts/reminders.js.map +1 -1
  18. package/dist/esm/ai/unified-prompts/skill-site-prompt-parts/ai-setup-prompt.js +2 -2
  19. package/dist/esm/ai/unified-prompts/skill-site-prompt-parts/ai-setup-prompt.js.map +1 -1
  20. package/dist/esm/config/format.js +10 -0
  21. package/dist/esm/config/format.js.map +1 -1
  22. package/dist/esm/config/schema.d.ts +147 -147
  23. package/dist/esm/config-eval.d.ts +31 -0
  24. package/dist/esm/config-eval.d.ts.map +1 -0
  25. package/dist/esm/config-eval.js +112 -0
  26. package/dist/esm/config-eval.js.map +1 -0
  27. package/dist/esm/config-rendering.d.ts +3 -6
  28. package/dist/esm/config-rendering.d.ts.map +1 -1
  29. package/dist/esm/config-rendering.js +15 -58
  30. package/dist/esm/config-rendering.js.map +1 -1
  31. package/dist/esm/hooks/use-async-callback.js +1 -1
  32. package/dist/esm/hooks/use-async-external-store.js +1 -1
  33. package/dist/esm/hooks/use-strict-memo.js +1 -1
  34. package/dist/esm/interface/admin-interface.d.ts +44 -2
  35. package/dist/esm/interface/admin-interface.d.ts.map +1 -1
  36. package/dist/esm/interface/admin-interface.js +55 -0
  37. package/dist/esm/interface/admin-interface.js.map +1 -1
  38. package/dist/esm/interface/admin-metrics.d.ts +12 -12
  39. package/dist/esm/interface/conversations.d.ts +31 -31
  40. package/dist/esm/interface/crud/current-user.d.ts +7 -7
  41. package/dist/esm/interface/crud/email-outbox.d.ts +158 -158
  42. package/dist/esm/interface/crud/invoices.d.ts +2 -2
  43. package/dist/esm/interface/crud/products.d.ts +15 -15
  44. package/dist/esm/interface/crud/products.d.ts.map +1 -1
  45. package/dist/esm/interface/crud/project-api-keys.d.ts +2 -2
  46. package/dist/esm/interface/crud/team-member-profiles.d.ts +18 -18
  47. package/dist/esm/interface/crud/transactions.d.ts +20 -20
  48. package/dist/esm/interface/crud/transactions.d.ts.map +1 -1
  49. package/dist/esm/interface/crud/users.d.ts +12 -12
  50. package/dist/esm/interface/plan-usage.d.ts +2 -2
  51. package/dist/esm/interface/webhooks.d.ts +2 -2
  52. package/dist/esm/known-errors.d.ts +1 -1
  53. package/dist/esm/schema-fields.d.ts +35 -2
  54. package/dist/esm/schema-fields.d.ts.map +1 -1
  55. package/dist/esm/schema-fields.js +53 -2
  56. package/dist/esm/schema-fields.js.map +1 -1
  57. package/dist/esm/sessions.d.ts +7 -7
  58. package/dist/esm/utils/jsx-editable-transpiler.js +2 -2
  59. package/dist/hooks/use-async-callback.js +1 -1
  60. package/dist/hooks/use-async-external-store.js +1 -1
  61. package/dist/hooks/use-strict-memo.js +1 -1
  62. package/dist/interface/admin-interface.d.ts +44 -2
  63. package/dist/interface/admin-interface.d.ts.map +1 -1
  64. package/dist/interface/admin-interface.js +55 -0
  65. package/dist/interface/admin-interface.js.map +1 -1
  66. package/dist/interface/admin-metrics.d.ts +12 -12
  67. package/dist/interface/conversations.d.ts +31 -31
  68. package/dist/interface/crud/current-user.d.ts +7 -7
  69. package/dist/interface/crud/email-outbox.d.ts +158 -158
  70. package/dist/interface/crud/invoices.d.ts +2 -2
  71. package/dist/interface/crud/products.d.ts +15 -15
  72. package/dist/interface/crud/products.d.ts.map +1 -1
  73. package/dist/interface/crud/project-api-keys.d.ts +2 -2
  74. package/dist/interface/crud/team-member-profiles.d.ts +18 -18
  75. package/dist/interface/crud/transactions.d.ts +20 -20
  76. package/dist/interface/crud/transactions.d.ts.map +1 -1
  77. package/dist/interface/crud/users.d.ts +12 -12
  78. package/dist/interface/plan-usage.d.ts +2 -2
  79. package/dist/interface/webhooks.d.ts +2 -2
  80. package/dist/known-errors.d.ts +1 -1
  81. package/dist/schema-fields.d.ts +35 -2
  82. package/dist/schema-fields.d.ts.map +1 -1
  83. package/dist/schema-fields.js +55 -1
  84. package/dist/schema-fields.js.map +1 -1
  85. package/dist/sessions.d.ts +7 -7
  86. package/dist/utils/jsx-editable-transpiler.js +4 -4
  87. package/package.json +2 -1
  88. package/src/ai/unified-prompts/reminders.ts +2 -1
  89. package/src/ai/unified-prompts/skill-site-prompt-parts/ai-setup-prompt.ts +2 -2
  90. package/src/config/format.ts +18 -0
  91. package/src/config-eval.ts +140 -0
  92. package/src/config-rendering.ts +23 -79
  93. package/src/interface/admin-interface.ts +85 -5
  94. package/src/schema-fields.ts +59 -1
  95. package/dist/esm/hexclave-config-file.d.ts +0 -38
  96. package/dist/esm/hexclave-config-file.d.ts.map +0 -1
  97. package/dist/esm/hexclave-config-file.js +0 -144
  98. package/dist/esm/hexclave-config-file.js.map +0 -1
  99. package/dist/hexclave-config-file.d.ts +0 -38
  100. package/dist/hexclave-config-file.d.ts.map +0 -1
  101. package/dist/hexclave-config-file.js +0 -153
  102. package/dist/hexclave-config-file.js.map +0 -1
  103. package/src/hexclave-config-file.ts +0 -215
@@ -0,0 +1,112 @@
1
+ import { showOnboardingHexclaveConfigValue } from "./config-authoring.js";
2
+ import { existsSync, readFileSync } from "fs";
3
+ import { createJiti } from "jiti";
4
+ import path from "path";
5
+ import { detectConfigImportPackage } from "./config-rendering.js";
6
+
7
+ //#region src/config-eval.ts
8
+ const jiti = createJiti(import.meta.url, { moduleCache: false });
9
+ /**
10
+ * Thrown when a config file evaluates successfully but its exported `config`
11
+ * isn't a usable shape (missing, or not an object / "show-onboarding" string).
12
+ * Distinct from the underlying loader errors jiti throws, so callers can tell a
13
+ * malformed config apart from a file that simply failed to load.
14
+ */
15
+ var ConfigFileEvalError = class extends Error {
16
+ constructor(message) {
17
+ super(message);
18
+ this.name = "ConfigFileEvalError";
19
+ }
20
+ };
21
+ /**
22
+ * Walks up from `dir` to find the nearest `package.json` and returns the
23
+ * best SDK package to use for the `HexclaveConfig` type import.
24
+ */
25
+ function detectImportPackageFromDir(dir) {
26
+ let current = dir;
27
+ while (true) {
28
+ const pkgPath = path.join(current, "package.json");
29
+ if (existsSync(pkgPath)) try {
30
+ const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
31
+ return detectConfigImportPackage([...Object.keys(pkg.dependencies ?? {}), ...Object.keys(pkg.devDependencies ?? {})]);
32
+ } catch {
33
+ return;
34
+ }
35
+ const parent = path.dirname(current);
36
+ if (parent === current) break;
37
+ current = parent;
38
+ }
39
+ }
40
+ function isRecord(value) {
41
+ return value != null && typeof value === "object" && !Array.isArray(value);
42
+ }
43
+ function invalidConfigShape(filePath) {
44
+ return new ConfigFileEvalError(`Invalid config in ${filePath}. The file must export a plain \`config\` object or "${showOnboardingHexclaveConfigValue}".`);
45
+ }
46
+ /**
47
+ * Evaluates config file content using jiti and returns the exported `config`
48
+ * value.
49
+ *
50
+ * WARNING: This executes arbitrary code via `jiti.evalModule` — only use on
51
+ * content that is fully operator-controlled (local filesystem). Never call
52
+ * this on untrusted input (e.g. content fetched from a remote repository).
53
+ */
54
+ function evalConfigFileContent(content, filePath) {
55
+ if (content.trim() === "") return {};
56
+ const resolvedPath = path.isAbsolute(filePath) ? filePath : path.resolve(filePath);
57
+ const mod = jiti.evalModule(content, { filename: resolvedPath });
58
+ if (!isRecord(mod)) throw invalidConfigShape(filePath);
59
+ const config = mod.config;
60
+ if (config === void 0) throw invalidConfigShape(filePath);
61
+ if (typeof config === "string") {
62
+ if (config !== showOnboardingHexclaveConfigValue) throw new ConfigFileEvalError(`Invalid config in ${filePath}. String config values must be "${showOnboardingHexclaveConfigValue}", got "${config}".`);
63
+ return config;
64
+ }
65
+ if (isRecord(config)) return config;
66
+ throw invalidConfigShape(filePath);
67
+ }
68
+ (void 0)?.test("evalConfigFileContent parses static config exports", ({ expect }) => {
69
+ expect(evalConfigFileContent(`
70
+ import type { StackConfig } from "@hexclave/js";
71
+ export const config: StackConfig = {
72
+ auth: { allowSignUp: true },
73
+ payments: { testMode: false },
74
+ };
75
+ `, "stack.config.ts")).toMatchInlineSnapshot(`
76
+ {
77
+ "auth": {
78
+ "allowSignUp": true,
79
+ },
80
+ "payments": {
81
+ "testMode": false,
82
+ },
83
+ }
84
+ `);
85
+ });
86
+ (void 0)?.test("evalConfigFileContent parses show-onboarding", ({ expect }) => {
87
+ expect(evalConfigFileContent("export const config = \"show-onboarding\";", "stack.config.ts")).toBe("show-onboarding");
88
+ });
89
+ (void 0)?.test("evalConfigFileContent rejects content without config export", ({ expect }) => {
90
+ expect(() => evalConfigFileContent("export const other = {};", "stack.config.ts")).toThrow(/must export/);
91
+ });
92
+ (void 0)?.test("evalConfigFileContent rejects arbitrary string config values", ({ expect }) => {
93
+ expect(() => evalConfigFileContent("export const config = \"arbitrary-string\";", "stack.config.ts")).toThrow(/must be "show-onboarding"/);
94
+ });
95
+ (void 0)?.test("evalConfigFileContent rejects unresolvable config factories", ({ expect }) => {
96
+ expect(() => evalConfigFileContent("export const config = makeConfig();", "stack.config.ts")).toThrow();
97
+ });
98
+ (void 0)?.test("evalConfigFileContent rejects missing config import targets", ({ expect }) => {
99
+ expect(() => evalConfigFileContent(`
100
+ import missingConfigPart from "./missing-config-part";
101
+ export const config = { auth: missingConfigPart };
102
+ `, "/tmp/hexclave-missing-import-config.ts")).toThrow();
103
+ });
104
+ (void 0)?.test("evalConfigFileContent surfaces invalid syntax as a loader error, not ConfigFileEvalError", ({ expect }) => {
105
+ const evalInvalid = () => evalConfigFileContent("export const config = {", "stack.config.ts");
106
+ expect(evalInvalid).toThrow();
107
+ expect(evalInvalid).not.toThrow(ConfigFileEvalError);
108
+ });
109
+
110
+ //#endregion
111
+ export { ConfigFileEvalError, detectImportPackageFromDir, evalConfigFileContent };
112
+ //# sourceMappingURL=config-eval.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config-eval.js","names":[],"sources":["../../src/config-eval.ts"],"sourcesContent":["import { existsSync, readFileSync } from \"fs\";\nimport { createJiti } from \"jiti\";\nimport path from \"path\";\nimport { showOnboardingHexclaveConfigValue } from \"./config-authoring\";\nimport { detectConfigImportPackage } from \"./config-rendering\";\n\nconst jiti = createJiti(import.meta.url, { moduleCache: false });\n\n/**\n * Thrown when a config file evaluates successfully but its exported `config`\n * isn't a usable shape (missing, or not an object / \"show-onboarding\" string).\n * Distinct from the underlying loader errors jiti throws, so callers can tell a\n * malformed config apart from a file that simply failed to load.\n */\nexport class ConfigFileEvalError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"ConfigFileEvalError\";\n }\n}\n\n/**\n * Walks up from `dir` to find the nearest `package.json` and returns the\n * best SDK package to use for the `HexclaveConfig` type import.\n */\nexport function detectImportPackageFromDir(dir: string): string | undefined {\n let current = dir;\n while (true) {\n const pkgPath = path.join(current, \"package.json\");\n if (existsSync(pkgPath)) {\n try {\n const pkg = JSON.parse(readFileSync(pkgPath, \"utf-8\"));\n const deps = [\n ...Object.keys(pkg.dependencies ?? {}),\n ...Object.keys(pkg.devDependencies ?? {}),\n ];\n return detectConfigImportPackage(deps);\n } catch {\n return undefined;\n }\n }\n const parent = path.dirname(current);\n if (parent === current) break;\n current = parent;\n }\n return undefined;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return value != null && typeof value === \"object\" && !Array.isArray(value);\n}\n\n/** A config object, or the `\"show-onboarding\"` sentinel that stands in for one. */\nexport type ParsedConfigValue = Record<string, unknown> | typeof showOnboardingHexclaveConfigValue;\n\nfunction invalidConfigShape(filePath: string): ConfigFileEvalError {\n return new ConfigFileEvalError(`Invalid config in ${filePath}. The file must export a plain \\`config\\` object or \"${showOnboardingHexclaveConfigValue}\".`);\n}\n\n/**\n * Evaluates config file content using jiti and returns the exported `config`\n * value.\n *\n * WARNING: This executes arbitrary code via `jiti.evalModule` — only use on\n * content that is fully operator-controlled (local filesystem). Never call\n * this on untrusted input (e.g. content fetched from a remote repository).\n */\nexport function evalConfigFileContent(content: string, filePath: string): ParsedConfigValue {\n if (content.trim() === \"\") return {};\n const resolvedPath = path.isAbsolute(filePath) ? filePath : path.resolve(filePath);\n const mod: unknown = jiti.evalModule(content, { filename: resolvedPath });\n if (!isRecord(mod)) {\n throw invalidConfigShape(filePath);\n }\n const config = mod.config;\n if (config === undefined) {\n throw invalidConfigShape(filePath);\n }\n if (typeof config === \"string\") {\n if (config !== showOnboardingHexclaveConfigValue) {\n throw new ConfigFileEvalError(`Invalid config in ${filePath}. String config values must be \"${showOnboardingHexclaveConfigValue}\", got \"${config}\".`);\n }\n return config;\n }\n if (isRecord(config)) return config;\n throw invalidConfigShape(filePath);\n}\n\n// --- inline vitest tests ---\n\nimport.meta.vitest?.test(\"evalConfigFileContent parses static config exports\", ({ expect }) => {\n expect(evalConfigFileContent(`\n import type { StackConfig } from \"@hexclave/js\";\n export const config: StackConfig = {\n auth: { allowSignUp: true },\n payments: { testMode: false },\n };\n `, \"stack.config.ts\")).toMatchInlineSnapshot(`\n {\n \"auth\": {\n \"allowSignUp\": true,\n },\n \"payments\": {\n \"testMode\": false,\n },\n }\n `);\n});\n\nimport.meta.vitest?.test(\"evalConfigFileContent parses show-onboarding\", ({ expect }) => {\n expect(evalConfigFileContent('export const config = \"show-onboarding\";', \"stack.config.ts\")).toBe(\"show-onboarding\");\n});\n\nimport.meta.vitest?.test(\"evalConfigFileContent rejects content without config export\", ({ expect }) => {\n expect(() => evalConfigFileContent(\"export const other = {};\", \"stack.config.ts\")).toThrow(/must export/);\n});\n\nimport.meta.vitest?.test(\"evalConfigFileContent rejects arbitrary string config values\", ({ expect }) => {\n expect(() => evalConfigFileContent('export const config = \"arbitrary-string\";', \"stack.config.ts\")).toThrow(/must be \"show-onboarding\"/);\n});\n\nimport.meta.vitest?.test(\"evalConfigFileContent rejects unresolvable config factories\", ({ expect }) => {\n expect(() => evalConfigFileContent(\"export const config = makeConfig();\", \"stack.config.ts\")).toThrow();\n});\n\nimport.meta.vitest?.test(\"evalConfigFileContent rejects missing config import targets\", ({ expect }) => {\n expect(() => evalConfigFileContent(`\n import missingConfigPart from \"./missing-config-part\";\n export const config = { auth: missingConfigPart };\n `, \"/tmp/hexclave-missing-import-config.ts\")).toThrow();\n});\n\nimport.meta.vitest?.test(\"evalConfigFileContent surfaces invalid syntax as a loader error, not ConfigFileEvalError\", ({ expect }) => {\n // A malformed file fails inside jiti's parser, so the thrown error is a loader\n // error — NOT a ConfigFileEvalError. Callers depend on that distinction to route\n // it to \"Failed to load config file\" rather than \"Invalid config\".\n const evalInvalid = () => evalConfigFileContent(\"export const config = {\", \"stack.config.ts\");\n expect(evalInvalid).toThrow();\n expect(evalInvalid).not.toThrow(ConfigFileEvalError);\n});\n"],"mappings":";;;;;;;AAMA,MAAM,OAAO,WAAW,OAAO,KAAK,KAAK,EAAE,aAAa,OAAO,CAAC;;;;;;;AAQhE,IAAa,sBAAb,cAAyC,MAAM;CAC7C,YAAY,SAAiB;AAC3B,QAAM,QAAQ;AACd,OAAK,OAAO;;;;;;;AAQhB,SAAgB,2BAA2B,KAAiC;CAC1E,IAAI,UAAU;AACd,QAAO,MAAM;EACX,MAAM,UAAU,KAAK,KAAK,SAAS,eAAe;AAClD,MAAI,WAAW,QAAQ,CACrB,KAAI;GACF,MAAM,MAAM,KAAK,MAAM,aAAa,SAAS,QAAQ,CAAC;AAKtD,UAAO,0BAJM,CACX,GAAG,OAAO,KAAK,IAAI,gBAAgB,EAAE,CAAC,EACtC,GAAG,OAAO,KAAK,IAAI,mBAAmB,EAAE,CAAC,CAC1C,CACqC;UAChC;AACN;;EAGJ,MAAM,SAAS,KAAK,QAAQ,QAAQ;AACpC,MAAI,WAAW,QAAS;AACxB,YAAU;;;AAKd,SAAS,SAAS,OAAkD;AAClE,QAAO,SAAS,QAAQ,OAAO,UAAU,YAAY,CAAC,MAAM,QAAQ,MAAM;;AAM5E,SAAS,mBAAmB,UAAuC;AACjE,QAAO,IAAI,oBAAoB,qBAAqB,SAAS,uDAAuD,kCAAkC,IAAI;;;;;;;;;;AAW5J,SAAgB,sBAAsB,SAAiB,UAAqC;AAC1F,KAAI,QAAQ,MAAM,KAAK,GAAI,QAAO,EAAE;CACpC,MAAM,eAAe,KAAK,WAAW,SAAS,GAAG,WAAW,KAAK,QAAQ,SAAS;CAClF,MAAM,MAAe,KAAK,WAAW,SAAS,EAAE,UAAU,cAAc,CAAC;AACzE,KAAI,CAAC,SAAS,IAAI,CAChB,OAAM,mBAAmB,SAAS;CAEpC,MAAM,SAAS,IAAI;AACnB,KAAI,WAAW,OACb,OAAM,mBAAmB,SAAS;AAEpC,KAAI,OAAO,WAAW,UAAU;AAC9B,MAAI,WAAW,kCACb,OAAM,IAAI,oBAAoB,qBAAqB,SAAS,kCAAkC,kCAAkC,UAAU,OAAO,IAAI;AAEvJ,SAAO;;AAET,KAAI,SAAS,OAAO,CAAE,QAAO;AAC7B,OAAM,mBAAmB,SAAS;;CAKpC,SAAW,KAAC,uDAAyD,EAAA,aAAa;AAChF,QAAO,sBAAsB;;;;;;KAM1B,kBAAkB,CAAC,CAAC,sBAAsB;;;;;;;;;IAS3C;EACF;CAEF,SAAW,KAAC,iDAAgD,EAAA,aAAgB;AAC1E,QAAO,sBAAsB,8CAA4C,kBAAkB,CAAC,CAAC,KAAK,kBAAkB;EACpH;CAEF,SAAW,KAAC,gEAAmE,EAAA,aAAY;AACzF,cAAa,sBAAsB,4BAA4B,kBAAkB,CAAC,CAAC,QAAQ,cAAc;EACzG;CAEF,SAAW,KAAC,iEAAoE,EAAA,aAAY;AAC1F,cAAa,sBAAsB,+CAA6C,kBAAkB,CAAC,CAAC,QAAQ,4BAA4B;EACxI;CAEF,SAAW,KAAC,gEAAgE,EAAA,aAAe;AACzF,cAAa,sBAAsB,uCAAuC,kBAAkB,CAAC,CAAC,SAAS;EACvG;CAEF,SAAW,KAAC,gEAAkE,EAAA,aAAa;AACzF,cAAa,sBAAsB;;;KAGhC,yCAAyC,CAAC,CAAC,SAAS;EACvD;CAEF,SAAW,KAAC,6FAAmF,EAAA,aAAyB;CAItH,MAAM,oBAAoB,sBAAsB,2BAA2B,kBAAkB;AAC7F,QAAO,YAAY,CAAC,SAAS;AAC7B,QAAO,YAAY,CAAC,IAAI,QAAQ,oBAAoB;EACpD"}
@@ -1,5 +1,3 @@
1
- import { hexclaveConfigFileExportsConfig, parseHexclaveConfigFileContent, renderConfigFileContent, tryParseHexclaveConfigFileContent } from "./hexclave-config-file";
2
-
3
1
  //#region src/config-rendering.d.ts
4
2
  /**
5
3
  * Given a list of dependency names (from package.json), returns the SDK
@@ -8,10 +6,9 @@ import { hexclaveConfigFileExportsConfig, parseHexclaveConfigFileContent, render
8
6
  */
9
7
  declare function detectConfigImportPackage(dependencies: string[]): string | undefined;
10
8
  /**
11
- * Walks up from `dir` to find the nearest `package.json` and returns the
12
- * best SDK package to use for the `HexclaveConfig` type import.
9
+ * Renders a config object into the source text of a `stack.config.ts` file.
13
10
  */
14
- declare function detectImportPackageFromDir(dir: string): string | undefined;
11
+ declare function renderConfigFileContent(config: unknown, importPackage?: string): string;
15
12
  //#endregion
16
- export { detectConfigImportPackage, detectImportPackageFromDir, hexclaveConfigFileExportsConfig, parseHexclaveConfigFileContent, renderConfigFileContent, tryParseHexclaveConfigFileContent };
13
+ export { detectConfigImportPackage, renderConfigFileContent };
17
14
  //# sourceMappingURL=config-rendering.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"config-rendering.d.ts","names":[],"sources":["../../src/config-rendering.ts"],"mappings":";;;;AA6BA;;;;iBAAgB,yBAAA,CAA0B,YAAA;AAa1C;;;;AAAA,iBAAgB,0BAAA,CAA2B,GAAA"}
1
+ {"version":3,"file":"config-rendering.d.ts","names":[],"sources":["../../src/config-rendering.ts"],"mappings":";;AA4BA;;;;iBAAgB,yBAAA,CAA0B,YAAA;AAY1C;;;AAAA,iBAAgB,uBAAA,CAAwB,MAAA,WAAiB,aAAA"}
@@ -1,8 +1,7 @@
1
- import { existsSync, readFileSync } from "fs";
2
- import path from "path";
3
- import { hexclaveConfigFileExportsConfig, parseHexclaveConfigFileContent, renderConfigFileContent, tryParseHexclaveConfigFileContent } from "./hexclave-config-file.js";
1
+ import { isValidConfig, normalize } from "./config/format.js";
4
2
 
5
3
  //#region src/config-rendering.ts
4
+ const DEFAULT_CONFIG_IMPORT_PACKAGE = "@hexclave/js";
6
5
  /**
7
6
  * Packages that export the `HexclaveConfig` type, in priority order.
8
7
  * The first match found in a project's dependencies wins. Hexclave-branded
@@ -30,23 +29,19 @@ function detectConfigImportPackage(dependencies) {
30
29
  for (const pkg of CONFIG_IMPORT_PACKAGES) if (dependencies.includes(pkg)) return pkg;
31
30
  }
32
31
  /**
33
- * Walks up from `dir` to find the nearest `package.json` and returns the
34
- * best SDK package to use for the `HexclaveConfig` type import.
32
+ * Renders a config object into the source text of a `stack.config.ts` file.
35
33
  */
36
- function detectImportPackageFromDir(dir) {
37
- let current = dir;
38
- while (true) {
39
- const pkgPath = path.join(current, "package.json");
40
- if (existsSync(pkgPath)) try {
41
- const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
42
- return detectConfigImportPackage([...Object.keys(pkg.dependencies ?? {}), ...Object.keys(pkg.devDependencies ?? {})]);
43
- } catch {
44
- return;
45
- }
46
- const parent = path.dirname(current);
47
- if (parent === current) break;
48
- current = parent;
49
- }
34
+ function renderConfigFileContent(config, importPackage) {
35
+ if (!isValidConfig(config)) throw new Error("Invalid config: expected a plain object.");
36
+ const droppedKeys = [];
37
+ const normalizedConfig = normalize(config, {
38
+ onDotIntoNonObject: "ignore",
39
+ onDotIntoNull: "empty-object",
40
+ droppedKeys
41
+ });
42
+ if (droppedKeys.length > 0) throw new Error(`Config has conflicting keys that would be dropped during normalization: ${droppedKeys.map((k) => JSON.stringify(k)).join(", ")}`);
43
+ const pkg = importPackage ?? DEFAULT_CONFIG_IMPORT_PACKAGE;
44
+ return `${`import type { HexclaveConfig } from "${pkg.startsWith("@hexclave/") ? `${pkg}/config` : pkg}";`}\n\nexport const config: HexclaveConfig = ${JSON.stringify(normalizedConfig, null, 2)};\n`;
50
45
  }
51
46
  (void 0)?.test("renderConfigFileContent normalizes config exports", ({ expect }) => {
52
47
  expect(renderConfigFileContent({
@@ -63,44 +58,6 @@ function detectImportPackageFromDir(dir) {
63
58
  }
64
59
  };`);
65
60
  });
66
- (void 0)?.test("parseHexclaveConfigFileContent parses static config exports", ({ expect }) => {
67
- expect(parseHexclaveConfigFileContent(`
68
- import type { StackConfig } from "@hexclave/js";
69
- export const config: StackConfig = {
70
- auth: { allowSignUp: true },
71
- payments: { testMode: false },
72
- };
73
- `, "stack.config.ts")).toMatchInlineSnapshot(`
74
- {
75
- "auth": {
76
- "allowSignUp": true,
77
- },
78
- "payments": {
79
- "testMode": false,
80
- },
81
- }
82
- `);
83
- });
84
- (void 0)?.test("parseHexclaveConfigFileContent parses show-onboarding", ({ expect }) => {
85
- expect(parseHexclaveConfigFileContent("export const config = \"show-onboarding\";", "stack.config.ts")).toBe("show-onboarding");
86
- });
87
- (void 0)?.test("parseHexclaveConfigFileContent rejects dynamic config exports", ({ expect }) => {
88
- expect(() => parseHexclaveConfigFileContent("export const config = makeConfig();", "stack.config.ts")).toThrow(/Unsupported config expression/);
89
- });
90
- (void 0)?.test("tryParseHexclaveConfigFileContent returns the config for static exports", ({ expect }) => {
91
- expect(tryParseHexclaveConfigFileContent("export const config = { auth: { allowSignUp: true } };", "stack.config.ts")).toEqual({ auth: { allowSignUp: true } });
92
- });
93
- (void 0)?.test("tryParseHexclaveConfigFileContent returns null for non-static exports", ({ expect }) => {
94
- expect(tryParseHexclaveConfigFileContent("export const config = makeConfig();", "stack.config.ts")).toBeNull();
95
- expect(tryParseHexclaveConfigFileContent("import x from \"./x.txt\" with { type: \"text\" };\nexport const config = { a: x };", "stack.config.ts")).toBeNull();
96
- expect(tryParseHexclaveConfigFileContent("export const config = {", "stack.config.ts")).toBeNull();
97
- });
98
- (void 0)?.test("hexclaveConfigFileExportsConfig detects a config export", ({ expect }) => {
99
- expect(hexclaveConfigFileExportsConfig("export const config = { a: 1 };", "stack.config.ts")).toBe(true);
100
- expect(hexclaveConfigFileExportsConfig("import x from \"./x.txt\" with { type: \"text\" };\nexport const config = { a: x };", "stack.config.ts")).toBe(true);
101
- expect(hexclaveConfigFileExportsConfig("export const notConfig = { a: 1 };", "stack.config.ts")).toBe(false);
102
- expect(hexclaveConfigFileExportsConfig("export const config = {", "stack.config.ts")).toBe(false);
103
- });
104
61
  (void 0)?.test("renderConfigFileContent rejects conflicting dotted keys", ({ expect }) => {
105
62
  expect(() => renderConfigFileContent({
106
63
  "a.b": 1,
@@ -132,5 +89,5 @@ function detectImportPackageFromDir(dir) {
132
89
  });
133
90
 
134
91
  //#endregion
135
- export { detectConfigImportPackage, detectImportPackageFromDir, hexclaveConfigFileExportsConfig, parseHexclaveConfigFileContent, renderConfigFileContent, tryParseHexclaveConfigFileContent };
92
+ export { detectConfigImportPackage, renderConfigFileContent };
136
93
  //# sourceMappingURL=config-rendering.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"config-rendering.js","names":[],"sources":["../../src/config-rendering.ts"],"sourcesContent":["import { existsSync, readFileSync } from \"fs\";\nimport path from \"path\";\nimport { hexclaveConfigFileExportsConfig, parseHexclaveConfigFileContent, renderConfigFileContent, tryParseHexclaveConfigFileContent } from \"./hexclave-config-file\";\nexport { hexclaveConfigFileExportsConfig, parseHexclaveConfigFileContent, renderConfigFileContent, tryParseHexclaveConfigFileContent };\n\n/**\n * Packages that export the `HexclaveConfig` type, in priority order.\n * The first match found in a project's dependencies wins. Hexclave-branded\n * packages come first (canonical); the legacy `@stackframe/*` names remain\n * so projects pinned to the last legacy release still render a config file\n * that compiles against their installed SDK.\n */\nconst CONFIG_IMPORT_PACKAGES = [\n \"@hexclave/next\",\n \"@hexclave/react\",\n \"@hexclave/tanstack-start\",\n \"@hexclave/js\",\n \"@hexclave/template\",\n \"@stackframe/stack\",\n \"@stackframe/react\",\n \"@stackframe/js\",\n \"@stackframe/template\",\n] as const;\n\n/**\n * Given a list of dependency names (from package.json), returns the SDK\n * package that should be used for the `HexclaveConfig` import, or `undefined`\n * if none of the known packages are installed.\n */\nexport function detectConfigImportPackage(dependencies: string[]): string | undefined {\n for (const pkg of CONFIG_IMPORT_PACKAGES) {\n if (dependencies.includes(pkg)) {\n return pkg;\n }\n }\n return undefined;\n}\n\n/**\n * Walks up from `dir` to find the nearest `package.json` and returns the\n * best SDK package to use for the `HexclaveConfig` type import.\n */\nexport function detectImportPackageFromDir(dir: string): string | undefined {\n let current = dir;\n while (true) {\n const pkgPath = path.join(current, \"package.json\");\n if (existsSync(pkgPath)) {\n try {\n const pkg = JSON.parse(readFileSync(pkgPath, \"utf-8\"));\n const deps = [\n ...Object.keys(pkg.dependencies ?? {}),\n ...Object.keys(pkg.devDependencies ?? {}),\n ];\n return detectConfigImportPackage(deps);\n } catch {\n return undefined;\n }\n }\n const parent = path.dirname(current);\n if (parent === current) break;\n current = parent;\n }\n return undefined;\n}\n\nimport.meta.vitest?.test(\"renderConfigFileContent normalizes config exports\", ({ expect }) => {\n expect(renderConfigFileContent({\n \"payments.items.todos.displayName\": \"Todo Slots\",\n \"payments.items.todos.customerType\": \"user\",\n })).toContain(`export const config: HexclaveConfig = {\n \"payments\": {\n \"items\": {\n \"todos\": {\n \"displayName\": \"Todo Slots\",\n \"customerType\": \"user\"\n }\n }\n }\n};`);\n});\n\nimport.meta.vitest?.test(\"parseHexclaveConfigFileContent parses static config exports\", ({ expect }) => {\n expect(parseHexclaveConfigFileContent(`\n import type { StackConfig } from \"@hexclave/js\";\n export const config: StackConfig = {\n auth: { allowSignUp: true },\n payments: { testMode: false },\n };\n `, \"stack.config.ts\")).toMatchInlineSnapshot(`\n {\n \"auth\": {\n \"allowSignUp\": true,\n },\n \"payments\": {\n \"testMode\": false,\n },\n }\n `);\n});\n\nimport.meta.vitest?.test(\"parseHexclaveConfigFileContent parses show-onboarding\", ({ expect }) => {\n expect(parseHexclaveConfigFileContent('export const config = \"show-onboarding\";', \"stack.config.ts\")).toBe(\"show-onboarding\");\n});\n\nimport.meta.vitest?.test(\"parseHexclaveConfigFileContent rejects dynamic config exports\", ({ expect }) => {\n expect(() => parseHexclaveConfigFileContent(\"export const config = makeConfig();\", \"stack.config.ts\")).toThrow(/Unsupported config expression/);\n});\n\nimport.meta.vitest?.test(\"tryParseHexclaveConfigFileContent returns the config for static exports\", ({ expect }) => {\n expect(tryParseHexclaveConfigFileContent(\"export const config = { auth: { allowSignUp: true } };\", \"stack.config.ts\")).toEqual({\n auth: { allowSignUp: true },\n });\n});\n\nimport.meta.vitest?.test(\"tryParseHexclaveConfigFileContent returns null for non-static exports\", ({ expect }) => {\n // Wrapped in a helper call (e.g. defineStackConfig) -> not a plain literal.\n expect(tryParseHexclaveConfigFileContent(\"export const config = makeConfig();\", \"stack.config.ts\")).toBeNull();\n // References an imported value -> has structure to preserve.\n expect(tryParseHexclaveConfigFileContent('import x from \"./x.txt\" with { type: \"text\" };\\nexport const config = { a: x };', \"stack.config.ts\")).toBeNull();\n // Syntax error.\n expect(tryParseHexclaveConfigFileContent(\"export const config = {\", \"stack.config.ts\")).toBeNull();\n});\n\nimport.meta.vitest?.test(\"hexclaveConfigFileExportsConfig detects a config export\", ({ expect }) => {\n expect(hexclaveConfigFileExportsConfig(\"export const config = { a: 1 };\", \"stack.config.ts\")).toBe(true);\n expect(hexclaveConfigFileExportsConfig('import x from \"./x.txt\" with { type: \"text\" };\\nexport const config = { a: x };', \"stack.config.ts\")).toBe(true);\n expect(hexclaveConfigFileExportsConfig(\"export const notConfig = { a: 1 };\", \"stack.config.ts\")).toBe(false);\n expect(hexclaveConfigFileExportsConfig(\"export const config = {\", \"stack.config.ts\")).toBe(false);\n});\n\nimport.meta.vitest?.test(\"renderConfigFileContent rejects conflicting dotted keys\", ({ expect }) => {\n expect(() => renderConfigFileContent({\n \"a.b\": 1,\n \"a.b.c\": 2,\n })).toThrowError(/conflicting keys.*\"a\\.b\\.c\"/);\n});\n\nimport.meta.vitest?.test(\"renderConfigFileContent rejects invalid config exports\", ({ expect }) => {\n expect(() => renderConfigFileContent(null)).toThrowErrorMatchingInlineSnapshot(\n `[Error: Invalid config: expected a plain object.]`,\n );\n});\n\nimport.meta.vitest?.test(\"renderConfigFileContent uses custom import package\", ({ expect }) => {\n const content = renderConfigFileContent({}, \"@hexclave/next\");\n expect(content).toContain('import type { HexclaveConfig } from \"@hexclave/next/config\";');\n});\n\nimport.meta.vitest?.test(\"renderConfigFileContent defaults to @hexclave/js\", ({ expect }) => {\n const content = renderConfigFileContent({});\n expect(content).toContain('import type { HexclaveConfig } from \"@hexclave/js/config\";');\n});\n\nimport.meta.vitest?.test(\"renderConfigFileContent keeps legacy @stackframe packages on their root entrypoint\", ({ expect }) => {\n // The lightweight `/config` subpath only exists on Hexclave-branded packages;\n // already-published @stackframe/* releases predate it.\n const content = renderConfigFileContent({}, \"@stackframe/next\");\n expect(content).toContain('import type { HexclaveConfig } from \"@stackframe/next\";');\n});\n\nimport.meta.vitest?.test(\"detectConfigImportPackage picks first matching package by priority\", ({ expect }) => {\n expect(detectConfigImportPackage([\"@hexclave/next\", \"@hexclave/js\"])).toBe(\"@hexclave/next\");\n expect(detectConfigImportPackage([\"@hexclave/react\", \"@hexclave/js\"])).toBe(\"@hexclave/react\");\n expect(detectConfigImportPackage([\"@hexclave/js\"])).toBe(\"@hexclave/js\");\n expect(detectConfigImportPackage([\"@hexclave/tanstack-start\"])).toBe(\"@hexclave/tanstack-start\");\n // Hexclave names take priority over legacy stackframe names when both appear.\n expect(detectConfigImportPackage([\"@stackframe/stack\", \"@hexclave/next\"])).toBe(\"@hexclave/next\");\n // Legacy fallback still works for projects pinned to the last @stackframe/* release.\n expect(detectConfigImportPackage([\"@stackframe/stack\"])).toBe(\"@stackframe/stack\");\n expect(detectConfigImportPackage([\"@stackframe/template\"])).toBe(\"@stackframe/template\");\n expect(detectConfigImportPackage([\"lodash\", \"express\"])).toBeUndefined();\n expect(detectConfigImportPackage([])).toBeUndefined();\n});\n"],"mappings":"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"}
1
+ {"version":3,"file":"config-rendering.js","names":[],"sources":["../../src/config-rendering.ts"],"sourcesContent":["import { isValidConfig, normalize } from \"./config/format\";\n\nconst DEFAULT_CONFIG_IMPORT_PACKAGE = \"@hexclave/js\";\n\n/**\n * Packages that export the `HexclaveConfig` type, in priority order.\n * The first match found in a project's dependencies wins. Hexclave-branded\n * packages come first (canonical); the legacy `@stackframe/*` names remain\n * so projects pinned to the last legacy release still render a config file\n * that compiles against their installed SDK.\n */\nconst CONFIG_IMPORT_PACKAGES = [\n \"@hexclave/next\",\n \"@hexclave/react\",\n \"@hexclave/tanstack-start\",\n \"@hexclave/js\",\n \"@hexclave/template\",\n \"@stackframe/stack\",\n \"@stackframe/react\",\n \"@stackframe/js\",\n \"@stackframe/template\",\n] as const;\n\n/**\n * Given a list of dependency names (from package.json), returns the SDK\n * package that should be used for the `HexclaveConfig` import, or `undefined`\n * if none of the known packages are installed.\n */\nexport function detectConfigImportPackage(dependencies: string[]): string | undefined {\n for (const pkg of CONFIG_IMPORT_PACKAGES) {\n if (dependencies.includes(pkg)) {\n return pkg;\n }\n }\n return undefined;\n}\n\n/**\n * Renders a config object into the source text of a `stack.config.ts` file.\n */\nexport function renderConfigFileContent(config: unknown, importPackage?: string): string {\n if (!isValidConfig(config)) {\n throw new Error(\"Invalid config: expected a plain object.\");\n }\n\n const droppedKeys: string[] = [];\n const normalizedConfig = normalize(config, {\n onDotIntoNonObject: \"ignore\",\n onDotIntoNull: \"empty-object\",\n droppedKeys,\n });\n if (droppedKeys.length > 0) {\n throw new Error(`Config has conflicting keys that would be dropped during normalization: ${droppedKeys.map(k => JSON.stringify(k)).join(\", \")}`);\n }\n const pkg = importPackage ?? DEFAULT_CONFIG_IMPORT_PACKAGE;\n const importSpecifier = pkg.startsWith(\"@hexclave/\") ? `${pkg}/config` : pkg;\n const importLine = `import type { HexclaveConfig } from \"${importSpecifier}\";`;\n return `${importLine}\\n\\nexport const config: HexclaveConfig = ${JSON.stringify(normalizedConfig, null, 2)};\\n`;\n}\n\n// --- inline vitest tests ---\n\nimport.meta.vitest?.test(\"renderConfigFileContent normalizes config exports\", ({ expect }) => {\n expect(renderConfigFileContent({\n \"payments.items.todos.displayName\": \"Todo Slots\",\n \"payments.items.todos.customerType\": \"user\",\n })).toContain(`export const config: HexclaveConfig = {\n \"payments\": {\n \"items\": {\n \"todos\": {\n \"displayName\": \"Todo Slots\",\n \"customerType\": \"user\"\n }\n }\n }\n};`);\n});\n\nimport.meta.vitest?.test(\"renderConfigFileContent rejects conflicting dotted keys\", ({ expect }) => {\n expect(() => renderConfigFileContent({\n \"a.b\": 1,\n \"a.b.c\": 2,\n })).toThrowError(/conflicting keys.*\"a\\.b\\.c\"/);\n});\n\nimport.meta.vitest?.test(\"renderConfigFileContent rejects invalid config exports\", ({ expect }) => {\n expect(() => renderConfigFileContent(null)).toThrowErrorMatchingInlineSnapshot(\n `[Error: Invalid config: expected a plain object.]`,\n );\n});\n\nimport.meta.vitest?.test(\"renderConfigFileContent uses custom import package\", ({ expect }) => {\n const content = renderConfigFileContent({}, \"@hexclave/next\");\n expect(content).toContain('import type { HexclaveConfig } from \"@hexclave/next/config\";');\n});\n\nimport.meta.vitest?.test(\"renderConfigFileContent defaults to @hexclave/js\", ({ expect }) => {\n const content = renderConfigFileContent({});\n expect(content).toContain('import type { HexclaveConfig } from \"@hexclave/js/config\";');\n});\n\nimport.meta.vitest?.test(\"renderConfigFileContent keeps legacy @stackframe packages on their root entrypoint\", ({ expect }) => {\n const content = renderConfigFileContent({}, \"@stackframe/next\");\n expect(content).toContain('import type { HexclaveConfig } from \"@stackframe/next\";');\n});\n\nimport.meta.vitest?.test(\"detectConfigImportPackage picks first matching package by priority\", ({ expect }) => {\n expect(detectConfigImportPackage([\"@hexclave/next\", \"@hexclave/js\"])).toBe(\"@hexclave/next\");\n expect(detectConfigImportPackage([\"@hexclave/react\", \"@hexclave/js\"])).toBe(\"@hexclave/react\");\n expect(detectConfigImportPackage([\"@hexclave/js\"])).toBe(\"@hexclave/js\");\n expect(detectConfigImportPackage([\"@hexclave/tanstack-start\"])).toBe(\"@hexclave/tanstack-start\");\n expect(detectConfigImportPackage([\"@stackframe/stack\", \"@hexclave/next\"])).toBe(\"@hexclave/next\");\n expect(detectConfigImportPackage([\"@stackframe/stack\"])).toBe(\"@stackframe/stack\");\n expect(detectConfigImportPackage([\"@stackframe/template\"])).toBe(\"@stackframe/template\");\n expect(detectConfigImportPackage([\"lodash\", \"express\"])).toBeUndefined();\n expect(detectConfigImportPackage([])).toBeUndefined();\n});\n"],"mappings":";;;AAEA,MAAM,gCAAgC;;;;;;;;AAStC,MAAM,yBAAyB;CAC7B;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACD;;;;;;AAOD,SAAgB,0BAA0B,cAA4C;AACpF,MAAK,MAAM,OAAO,uBAChB,KAAI,aAAa,SAAS,IAAI,CAC5B,QAAO;;;;;AASb,SAAgB,wBAAwB,QAAiB,eAAgC;AACvF,KAAI,CAAC,cAAc,OAAO,CACxB,OAAM,IAAI,MAAM,2CAA2C;CAG7D,MAAM,cAAwB,EAAE;CAChC,MAAM,mBAAmB,UAAU,QAAQ;EACzC,oBAAoB;EACpB,eAAe;EACf;EACD,CAAC;AACF,KAAI,YAAY,SAAS,EACvB,OAAM,IAAI,MAAM,2EAA2E,YAAY,KAAI,MAAK,KAAK,UAAU,EAAE,CAAC,CAAC,KAAK,KAAK,GAAG;CAElJ,MAAM,MAAM,iBAAiB;AAG7B,QAAO,GADY,wCADK,IAAI,WAAW,aAAa,GAAG,GAAG,IAAI,WAAW,IACE,IACtD,4CAA4C,KAAK,UAAU,kBAAkB,MAAM,EAAE,CAAC;;CAK7G,SAAW,KAAC,sDAAwD,EAAA,aAAa;AAC/E,QAAO,wBAAwB;EAC7B,oCAAoC;EACpC,qCAAqC;EACtC,CAAC,CAAC,CAAC,UAAU;;;;;;;;;IASZ;EACF;CAEF,SAAW,KAAC,4DAAgE,EAAC,aAAU;AACrF,cAAa,wBAAwB;EACnC,OAAO;EACP,SAAS;EACV,CAAC,CAAC,CAAC,aAAa,8BAA8B;EAC/C;CAEF,SAAW,KAAC,2DAA6D,EAAA,aAAa;AACpF,cAAa,wBAAwB,KAAK,CAAC,CAAC,mCAC1C,oDACD;EACD;CAEF,SAAW,KAAC,uDAAyD,EAAA,aAAa;AAEhF,QADgB,wBAAwB,EAAE,EAAE,iBAAiB,CAC9C,CAAC,UAAU,iEAA+D;EACzF;CAEF,SAAW,KAAC,qDAAmD,EAAQ,aAAS;AAE9E,QADgB,wBAAwB,EAAE,CAAC,CAC5B,CAAC,UAAU,+DAA6D;EACvF;CAEF,SAAW,KAAC,uFAAsF,EAAA,aAAgB;AAEhH,QADgB,wBAAwB,EAAE,EAAE,mBAAmB,CAChD,CAAC,UAAU,4DAA0D;EACpF;CAEF,SAAW,KAAC,uEAAwE,EAAA,aAAc;AAChG,QAAO,0BAA0B,CAAC,kBAAkB,eAAe,CAAC,CAAC,CAAC,KAAK,iBAAiB;AAC5F,QAAO,0BAA0B,CAAC,mBAAmB,eAAe,CAAC,CAAC,CAAC,KAAK,kBAAkB;AAC9F,QAAO,0BAA0B,CAAC,eAAe,CAAC,CAAC,CAAC,KAAK,eAAe;AACxE,QAAO,0BAA0B,CAAC,2BAA2B,CAAC,CAAC,CAAC,KAAK,2BAA2B;AAChG,QAAO,0BAA0B,CAAC,qBAAqB,iBAAiB,CAAC,CAAC,CAAC,KAAK,iBAAiB;AACjG,QAAO,0BAA0B,CAAC,oBAAoB,CAAC,CAAC,CAAC,KAAK,oBAAoB;AAClF,QAAO,0BAA0B,CAAC,uBAAuB,CAAC,CAAC,CAAC,KAAK,uBAAuB;AACxF,QAAO,0BAA0B,CAAC,UAAU,UAAU,CAAC,CAAC,CAAC,eAAe;AACxE,QAAO,0BAA0B,EAAE,CAAC,CAAC,CAAC,eAAe;EACrD"}
@@ -1,5 +1,5 @@
1
- import React from "react";
2
1
  import { captureError } from "../utils/errors.js";
2
+ import React from "react";
3
3
 
4
4
  //#region src/hooks/use-async-callback.tsx
5
5
  function useAsyncCallback(callback, deps) {
@@ -1,5 +1,5 @@
1
- import { useEffect, useState } from "react";
2
1
  import { AsyncResult } from "../utils/results.js";
2
+ import { useEffect, useState } from "react";
3
3
 
4
4
  //#region src/hooks/use-async-external-store.tsx
5
5
  function useAsyncExternalStore(subscribe) {
@@ -1,5 +1,5 @@
1
- import { useId, useInsertionEffect } from "react";
2
1
  import { Result } from "../utils/results.js";
2
+ import { useId, useInsertionEffect } from "react";
3
3
 
4
4
  //#region src/hooks/use-strict-memo.tsx
5
5
  const cached = /* @__PURE__ */ new Map();
@@ -1,10 +1,10 @@
1
1
  import * as yup$1 from "yup";
2
2
  import { Result } from "../utils/results";
3
+ import { EnvironmentConfigOverrideOverride } from "../config/schema";
3
4
  import { KnownErrors } from "../known-errors";
4
- import { RestrictedReason, branchConfigSourceSchema } from "../schema-fields";
5
+ import { ConfigAgentRunApi, RestrictedReason, branchConfigSourceSchema } from "../schema-fields";
5
6
  import { AccessToken, InternalSession, RefreshToken } from "../sessions";
6
7
  import { MoneyAmount } from "../utils/currency-constants";
7
- import { PlanUsageResponse, PlanUsageResponse as PlanUsageResponse$1 } from "./plan-usage";
8
8
  import { AnalyticsClickmapDevice, AnalyticsClickmapKind, AnalyticsClickmapResponse, AnalyticsClickmapTokenResponse, MetricsResponse, MetricsUserCounts, UserActivityResponse } from "./admin-metrics";
9
9
  import { AnalyticsQueryOptions, AnalyticsQueryResponse } from "./crud/analytics";
10
10
  import { EmailOutboxCrud } from "./crud/email-outbox";
@@ -16,6 +16,7 @@ import { AdminGetSessionReplayAllEventsResponse, AdminGetSessionReplayChunkEvent
16
16
  import { SvixTokenCrud } from "./crud/svix-token";
17
17
  import { TeamPermissionDefinitionsCrud } from "./crud/team-permissions";
18
18
  import { Transaction, TransactionType } from "./crud/transactions";
19
+ import { PlanUsageResponse, PlanUsageResponse as PlanUsageResponse$1 } from "./plan-usage";
19
20
  import { HexclaveServerInterface, ServerAuthApplicationOptions } from "./server-interface";
20
21
 
21
22
  //#region src/interface/admin-interface.d.ts
@@ -246,6 +247,47 @@ declare class HexclaveAdminInterface extends HexclaveServerInterface {
246
247
  updateConfigOverride(level: "project" | "branch" | "environment", configOverrideOverride: any): Promise<void>;
247
248
  getPushedConfigSource(): Promise<BranchConfigSourceApi>;
248
249
  unlinkPushedConfigSource(): Promise<void>;
250
+ /**
251
+ * Reads a specific config-agent run's state (or `null`) for the linked GitHub
252
+ * repo. Polled by the dashboard — using the id returned by `applyConfigViaAgent`
253
+ * — for live progress and the review diff. Runs are independent, so each is
254
+ * addressed by its own id rather than "the" run on the branch.
255
+ */
256
+ getConfigAgentRun(runId: string): Promise<ConfigAgentRunApi | null>;
257
+ /**
258
+ * Applies a dashboard config change to the linked GitHub repo by running the
259
+ * config agent in a sandbox (server-side). Returns immediately with the new run's
260
+ * `id`; poll `getConfigAgentRun(id)` for progress. The GitHub access token is the
261
+ * caller's own OAuth token and is used transiently server-side.
262
+ */
263
+ applyConfigViaAgent(options: {
264
+ configUpdate: EnvironmentConfigOverrideOverride;
265
+ githubAccessToken: string;
266
+ }): Promise<{
267
+ status: "started";
268
+ id: string;
269
+ }>;
270
+ /**
271
+ * Cancels a specific in-flight agent-driven config write: hard-stops the sandbox
272
+ * so the agent stops mid-work. Also cancels runs in `awaiting_review`. No revert
273
+ * — if the agent already pushed, the commit stays. Returns `not-running` if the
274
+ * run is gone or already terminal.
275
+ */
276
+ cancelConfigAgentRun(runId: string): Promise<{
277
+ status: "cancelling" | "not-running";
278
+ }>;
279
+ /**
280
+ * Commits a specific run's reviewed change to GitHub. Only valid when that run is in
281
+ * `awaiting_review` status; the change (diff + base commit) was captured at apply time
282
+ * and is rebuilt + pushed via the GitHub API here, so no live sandbox is involved.
283
+ * Returns `not-awaiting-review` if the run isn't in a committable state.
284
+ */
285
+ commitConfigAgentRun(runId: string, options: {
286
+ githubAccessToken: string;
287
+ commitMessage?: string;
288
+ }): Promise<{
289
+ status: "committing" | "not-awaiting-review";
290
+ }>;
249
291
  resetConfigOverrideKeys(level: "branch" | "environment", keys: string[]): Promise<void>;
250
292
  createEmailTemplate(displayName: string): Promise<{
251
293
  id: string;
@@ -1 +1 @@
1
- {"version":3,"file":"admin-interface.d.ts","names":[],"sources":["../../../src/interface/admin-interface.ts"],"mappings":"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"}
1
+ {"version":3,"file":"admin-interface.d.ts","names":[],"sources":["../../../src/interface/admin-interface.ts"],"mappings":"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"}
@@ -350,6 +350,61 @@ var HexclaveAdminInterface = class extends HexclaveServerInterface {
350
350
  async unlinkPushedConfigSource() {
351
351
  await this.sendAdminRequest(`/internal/config/source`, { method: "DELETE" }, null);
352
352
  }
353
+ /**
354
+ * Reads a specific config-agent run's state (or `null`) for the linked GitHub
355
+ * repo. Polled by the dashboard — using the id returned by `applyConfigViaAgent`
356
+ * — for live progress and the review diff. Runs are independent, so each is
357
+ * addressed by its own id rather than "the" run on the branch.
358
+ */
359
+ async getConfigAgentRun(runId) {
360
+ return (await (await this.sendAdminRequest(`/internal/config/github/run?run_id=${encodeURIComponent(runId)}`, { method: "GET" }, null)).json()).agent_run ?? null;
361
+ }
362
+ /**
363
+ * Applies a dashboard config change to the linked GitHub repo by running the
364
+ * config agent in a sandbox (server-side). Returns immediately with the new run's
365
+ * `id`; poll `getConfigAgentRun(id)` for progress. The GitHub access token is the
366
+ * caller's own OAuth token and is used transiently server-side.
367
+ */
368
+ async applyConfigViaAgent(options) {
369
+ return await (await this.sendAdminRequest(`/internal/config/github/apply`, {
370
+ method: "POST",
371
+ headers: { "content-type": "application/json" },
372
+ body: JSON.stringify({
373
+ github_access_token: options.githubAccessToken,
374
+ config_update_string: JSON.stringify(options.configUpdate)
375
+ })
376
+ }, null)).json();
377
+ }
378
+ /**
379
+ * Cancels a specific in-flight agent-driven config write: hard-stops the sandbox
380
+ * so the agent stops mid-work. Also cancels runs in `awaiting_review`. No revert
381
+ * — if the agent already pushed, the commit stays. Returns `not-running` if the
382
+ * run is gone or already terminal.
383
+ */
384
+ async cancelConfigAgentRun(runId) {
385
+ return await (await this.sendAdminRequest(`/internal/config/github/cancel`, {
386
+ method: "POST",
387
+ headers: { "content-type": "application/json" },
388
+ body: JSON.stringify({ run_id: runId })
389
+ }, null)).json();
390
+ }
391
+ /**
392
+ * Commits a specific run's reviewed change to GitHub. Only valid when that run is in
393
+ * `awaiting_review` status; the change (diff + base commit) was captured at apply time
394
+ * and is rebuilt + pushed via the GitHub API here, so no live sandbox is involved.
395
+ * Returns `not-awaiting-review` if the run isn't in a committable state.
396
+ */
397
+ async commitConfigAgentRun(runId, options) {
398
+ return await (await this.sendAdminRequest(`/internal/config/github/commit`, {
399
+ method: "POST",
400
+ headers: { "content-type": "application/json" },
401
+ body: JSON.stringify({
402
+ run_id: runId,
403
+ github_access_token: options.githubAccessToken,
404
+ ...options.commitMessage ? { commit_message: options.commitMessage } : {}
405
+ })
406
+ }, null)).json();
407
+ }
353
408
  async resetConfigOverrideKeys(level, keys) {
354
409
  await this.sendAdminRequest(`/internal/config/override/${level}/reset-keys`, {
355
410
  method: "POST",