@xylex-group/athena 3.0.0 → 3.0.3

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 (70) hide show
  1. package/README.md +24 -10
  2. package/dist/{athena-auth-url-oLux_57a.d.cts → athena-request-headers-C7Jy-c_D.d.ts} +85 -1
  3. package/dist/{athena-auth-url-oLux_57a.d.ts → athena-request-headers-DujFFyMU.d.cts} +85 -1
  4. package/dist/billing.cjs +133 -21
  5. package/dist/billing.cjs.map +1 -1
  6. package/dist/billing.d.cts +41 -1
  7. package/dist/billing.d.ts +41 -1
  8. package/dist/billing.js +133 -21
  9. package/dist/billing.js.map +1 -1
  10. package/dist/browser.cjs +138 -45
  11. package/dist/browser.cjs.map +1 -1
  12. package/dist/browser.d.cts +9 -9
  13. package/dist/browser.d.ts +9 -9
  14. package/dist/browser.js +138 -45
  15. package/dist/browser.js.map +1 -1
  16. package/dist/cli/index.cjs +1038 -57
  17. package/dist/cli/index.cjs.map +1 -1
  18. package/dist/cli/index.d.cts +3 -3
  19. package/dist/cli/index.d.ts +3 -3
  20. package/dist/cli/index.js +1039 -58
  21. package/dist/cli/index.js.map +1 -1
  22. package/dist/index.cjs +977 -54
  23. package/dist/index.cjs.map +1 -1
  24. package/dist/index.d.cts +9 -9
  25. package/dist/index.d.ts +9 -9
  26. package/dist/index.js +978 -55
  27. package/dist/index.js.map +1 -1
  28. package/dist/{model-form-BKetpu6Q.d.ts → model-form-Dh0sisdL.d.ts} +1 -1
  29. package/dist/{model-form-BEfCGB5b.d.cts → model-form-oOAJUVd4.d.cts} +1 -1
  30. package/dist/{module-Bef_MAPO.d.ts → module-BruTcxe0.d.ts} +17 -5
  31. package/dist/{module-CrrSmpML.d.cts → module-CPG3ULxQ.d.cts} +17 -5
  32. package/dist/{module-8dSMcy0K.d.cts → module-C_ab-MM1.d.cts} +46 -12
  33. package/dist/{module-8dSMcy0K.d.ts → module-C_ab-MM1.d.ts} +46 -12
  34. package/dist/next/client.cjs +9817 -3
  35. package/dist/next/client.cjs.map +1 -1
  36. package/dist/next/client.d.cts +26 -1
  37. package/dist/next/client.d.ts +26 -1
  38. package/dist/next/client.js +9788 -4
  39. package/dist/next/client.js.map +1 -1
  40. package/dist/next/server.cjs +10398 -42
  41. package/dist/next/server.cjs.map +1 -1
  42. package/dist/next/server.d.cts +39 -4
  43. package/dist/next/server.d.ts +39 -4
  44. package/dist/next/server.js +10339 -43
  45. package/dist/next/server.js.map +1 -1
  46. package/dist/{pipeline-Dfsed4VD.d.cts → pipeline-CIzV9f7b.d.cts} +1 -1
  47. package/dist/{pipeline-BXFQbsUW.d.ts → pipeline-DNlc8Ayn.d.ts} +1 -1
  48. package/dist/proxy-request-headers-DGxdoyA0.d.cts +59 -0
  49. package/dist/proxy-request-headers-m4D2Tduy.d.ts +59 -0
  50. package/dist/react.cjs +7 -7
  51. package/dist/react.cjs.map +1 -1
  52. package/dist/react.d.cts +4 -4
  53. package/dist/react.d.ts +4 -4
  54. package/dist/react.js +7 -7
  55. package/dist/react.js.map +1 -1
  56. package/dist/social-providers.cjs +15 -11
  57. package/dist/social-providers.cjs.map +1 -1
  58. package/dist/social-providers.d.cts +17 -57
  59. package/dist/social-providers.d.ts +17 -57
  60. package/dist/social-providers.js +15 -11
  61. package/dist/social-providers.js.map +1 -1
  62. package/dist/{types-jClgDy1J.d.ts → types-B75PdABb.d.ts} +1 -1
  63. package/dist/{types-kO_Ut5wU.d.cts → types-CgCv5o6R.d.cts} +1 -1
  64. package/dist/{types-CK7cBQbC.d.ts → types-D6tZ9aoq.d.ts} +35 -2
  65. package/dist/{types-Z3-rsiM3.d.cts → types-DFr2cL1N.d.cts} +35 -2
  66. package/dist/utils.d.cts +4 -142
  67. package/dist/utils.d.ts +4 -142
  68. package/dist/{v3-client-G8JMOilK.d.cts → v3-client-CWfZHcKL.d.cts} +37 -21
  69. package/dist/{v3-client-CuCNy-JJ.d.ts → v3-client-DZp2NEhK.d.ts} +37 -21
  70. package/package.json +6 -3
package/dist/cli/index.js CHANGED
@@ -1,10 +1,766 @@
1
- import { mkdir, writeFile, stat } from 'fs/promises';
1
+ import { mkdir, writeFile, stat, readFile } from 'fs/promises';
2
2
  import { resolve, dirname, posix } from 'path';
3
3
  import { existsSync, readFileSync } from 'fs';
4
4
  import { pathToFileURL } from 'url';
5
5
 
6
6
  // src/generator/pipeline.ts
7
7
 
8
+ // src/generator/artifact-merge.ts
9
+ var IMPORT_RE = /^import\s+(?:type\s+)?(?:\{([^}]*)\}|([A-Za-z_$][\w$]*))\s+from\s+(['"])([^'"]+)\3\s*;?\s*$/gm;
10
+ var DEFINE_EXPORT_RE = /export\s+const\s+([A-Za-z_$][\w$]*)\s*=\s*(define(?:Database|Registry))\s*\(\s*\{/g;
11
+ var META_EXPORT_RE = /export\s+const\s+__athena_schema_meta\s*=\s*\{/g;
12
+ var KNOWN_META_KEYS = /* @__PURE__ */ new Set([
13
+ "schemaVersion",
14
+ "generatedAt",
15
+ "database",
16
+ "outputPreset",
17
+ "outputFormat"
18
+ ]);
19
+ function detectNewline(source) {
20
+ return source.includes("\r\n") ? "\r\n" : "\n";
21
+ }
22
+ function detectStyle(source) {
23
+ const newline = detectNewline(source);
24
+ const single = (source.match(/'/g) ?? []).length;
25
+ const double = (source.match(/"/g) ?? []).length;
26
+ const quote = double > single ? '"' : "'";
27
+ const importLines = source.split(/\r?\n/).filter((line) => line.trimStart().startsWith("import "));
28
+ const semicolons = importLines.length > 0 ? importLines.filter((line) => line.trimEnd().endsWith(";")).length >= importLines.length / 2 : false;
29
+ const objectLines = source.split(/\r?\n/).map((line) => line.trim()).filter((line) => /^[A-Za-z0-9_'"]+\s*:\s*.+/.test(line));
30
+ const trailingComma = objectLines.length > 0 ? objectLines.filter((line) => line.endsWith(",")).length >= Math.ceil(objectLines.length / 2) : true;
31
+ const indentMatch = source.match(/\n([ \t]+)\S/);
32
+ const indent = indentMatch?.[1] ?? " ";
33
+ return { quote, semicolons, trailingComma, indent, newline };
34
+ }
35
+ function quoteString(value, quote) {
36
+ const escaped = value.replace(/\\/g, "\\\\").replace(new RegExp(quote, "g"), `\\${quote}`);
37
+ return `${quote}${escaped}${quote}`;
38
+ }
39
+ function parseNamedImports(source) {
40
+ const imports = [];
41
+ IMPORT_RE.lastIndex = 0;
42
+ let match;
43
+ while ((match = IMPORT_RE.exec(source)) !== null) {
44
+ const named = match[1];
45
+ const defaultName = match[2];
46
+ const module = match[4];
47
+ const names = named ? named.split(",").map((part) => part.trim()).filter(Boolean).map((part) => {
48
+ const alias = part.split(/\s+as\s+/);
49
+ return (alias[1] ?? alias[0]).trim();
50
+ }) : defaultName ? [defaultName] : [];
51
+ imports.push({
52
+ names,
53
+ module,
54
+ raw: match[0],
55
+ start: match.index,
56
+ end: match.index + match[0].length
57
+ });
58
+ }
59
+ return imports;
60
+ }
61
+ function findMatchingBrace(source, openIndex) {
62
+ let depth = 0;
63
+ let inSingle = false;
64
+ let inDouble = false;
65
+ let inTemplate = false;
66
+ let escaped = false;
67
+ for (let i = openIndex; i < source.length; i += 1) {
68
+ const ch = source[i];
69
+ if (escaped) {
70
+ escaped = false;
71
+ continue;
72
+ }
73
+ if (ch === "\\" && (inSingle || inDouble || inTemplate)) {
74
+ escaped = true;
75
+ continue;
76
+ }
77
+ if (!inDouble && !inTemplate && ch === "'") {
78
+ inSingle = !inSingle;
79
+ continue;
80
+ }
81
+ if (!inSingle && !inTemplate && ch === '"') {
82
+ inDouble = !inDouble;
83
+ continue;
84
+ }
85
+ if (!inSingle && !inDouble && ch === "`") {
86
+ inTemplate = !inTemplate;
87
+ continue;
88
+ }
89
+ if (inSingle || inDouble || inTemplate) {
90
+ continue;
91
+ }
92
+ if (ch === "{") {
93
+ depth += 1;
94
+ } else if (ch === "}") {
95
+ depth -= 1;
96
+ if (depth === 0) {
97
+ return i;
98
+ }
99
+ }
100
+ }
101
+ return -1;
102
+ }
103
+ function parseObjectEntries(body) {
104
+ const entries = [];
105
+ const lines = body.split(/\r?\n/);
106
+ for (const line of lines) {
107
+ const trimmed = line.trim();
108
+ if (!trimmed || trimmed.startsWith("//") || trimmed.startsWith("/*")) {
109
+ continue;
110
+ }
111
+ const withoutComma = trimmed.endsWith(",") ? trimmed.slice(0, -1).trimEnd() : trimmed;
112
+ const match = withoutComma.match(/^([A-Za-z_$][\w$]*|['"][^'"]+['"])\s*:\s*(.+)$/);
113
+ if (!match) {
114
+ continue;
115
+ }
116
+ const keyRaw = match[1];
117
+ const key = keyRaw.startsWith("'") || keyRaw.startsWith('"') ? keyRaw.slice(1, -1) : keyRaw;
118
+ entries.push({
119
+ key,
120
+ value: match[2].trim(),
121
+ raw: trimmed
122
+ });
123
+ }
124
+ return entries;
125
+ }
126
+ function parseDefineBlocks(source) {
127
+ const blocks = [];
128
+ DEFINE_EXPORT_RE.lastIndex = 0;
129
+ let match;
130
+ while ((match = DEFINE_EXPORT_RE.exec(source)) !== null) {
131
+ const exportName = match[1];
132
+ const callName = match[2];
133
+ const openBrace = match.index + match[0].lastIndexOf("{");
134
+ const closeBrace = findMatchingBrace(source, openBrace);
135
+ if (closeBrace < 0) {
136
+ continue;
137
+ }
138
+ const body = source.slice(openBrace + 1, closeBrace);
139
+ const fullEnd = (() => {
140
+ let i = closeBrace + 1;
141
+ while (i < source.length && /\s/.test(source[i])) i += 1;
142
+ if (source[i] === ")") i += 1;
143
+ while (i < source.length && /\s/.test(source[i])) i += 1;
144
+ if (source[i] === ";") i += 1;
145
+ return i;
146
+ })();
147
+ blocks.push({
148
+ kind: callName === "defineDatabase" ? "database" : "registry",
149
+ exportName,
150
+ callName,
151
+ entries: parseObjectEntries(body),
152
+ bodyStart: openBrace + 1,
153
+ bodyEnd: closeBrace,
154
+ fullStart: match.index,
155
+ fullEnd,
156
+ raw: source.slice(match.index, fullEnd)
157
+ });
158
+ }
159
+ return blocks;
160
+ }
161
+ function parseMetaBlock(source) {
162
+ META_EXPORT_RE.lastIndex = 0;
163
+ const match = META_EXPORT_RE.exec(source);
164
+ if (!match) {
165
+ return void 0;
166
+ }
167
+ const openBrace = match.index + match[0].lastIndexOf("{");
168
+ const closeBrace = findMatchingBrace(source, openBrace);
169
+ if (closeBrace < 0) {
170
+ return void 0;
171
+ }
172
+ let fullEnd = closeBrace + 1;
173
+ const after = source.slice(fullEnd);
174
+ const asConst = after.match(/^\s*as\s+const\s*;?/);
175
+ if (asConst) {
176
+ fullEnd += asConst[0].length;
177
+ } else if (source[fullEnd] === ";") {
178
+ fullEnd += 1;
179
+ }
180
+ return {
181
+ entries: parseObjectEntries(source.slice(openBrace + 1, closeBrace)),
182
+ bodyStart: openBrace + 1,
183
+ bodyEnd: closeBrace,
184
+ fullStart: match.index,
185
+ fullEnd,
186
+ raw: source.slice(match.index, fullEnd)
187
+ };
188
+ }
189
+ function hasImportBinding(imports, name, module) {
190
+ return imports.some(
191
+ (item) => item.names.includes(name) && (module === void 0)
192
+ );
193
+ }
194
+ function findImportForName(imports, name) {
195
+ return imports.find((item) => item.names.includes(name));
196
+ }
197
+ function normalizeModulePath(modulePath) {
198
+ return modulePath.replace(/\\/g, "/").replace(/^\.\//, "").replace(/\.ts$/, "");
199
+ }
200
+ function formatImport(names, modulePath, style) {
201
+ const body = `import { ${names.join(", ")} } from ${quoteString(modulePath, style.quote)}`;
202
+ return style.semicolons ? `${body};` : body;
203
+ }
204
+ function formatObjectEntry(key, value, style, isLast) {
205
+ const needsQuote = !/^[A-Za-z_$][\w$]*$/.test(key);
206
+ const renderedKey = needsQuote ? quoteString(key, style.quote) : key;
207
+ const comma = !isLast || style.trailingComma ? "," : "";
208
+ return `${style.indent}${renderedKey}: ${value}${comma}`;
209
+ }
210
+ function replaceRange(source, start, end, insertion) {
211
+ return source.slice(0, start) + insertion + source.slice(end);
212
+ }
213
+ function collectDuplicateKeys(entries) {
214
+ const seen = /* @__PURE__ */ new Set();
215
+ const dupes = [];
216
+ for (const entry of entries) {
217
+ if (seen.has(entry.key)) {
218
+ dupes.push(entry.key);
219
+ }
220
+ seen.add(entry.key);
221
+ }
222
+ return dupes;
223
+ }
224
+ function collectDuplicateImportBindings(imports) {
225
+ const seen = /* @__PURE__ */ new Set();
226
+ const dupes = [];
227
+ for (const item of imports) {
228
+ for (const name of item.names) {
229
+ if (seen.has(name)) {
230
+ dupes.push(name);
231
+ }
232
+ seen.add(name);
233
+ }
234
+ }
235
+ return dupes;
236
+ }
237
+ function lintArtifactSource(source, kind) {
238
+ const errors = [];
239
+ const imports = parseNamedImports(source);
240
+ const dupImports = collectDuplicateImportBindings(imports);
241
+ if (dupImports.length > 0) {
242
+ errors.push(`duplicate import bindings: ${dupImports.join(", ")}`);
243
+ }
244
+ const blocks = parseDefineBlocks(source).filter((block2) => block2.kind === kind);
245
+ if (blocks.length === 0) {
246
+ errors.push(`missing export const \u2026 = define${kind === "database" ? "Database" : "Registry"}({\u2026})`);
247
+ return errors;
248
+ }
249
+ if (blocks.length > 1) {
250
+ errors.push(`multiple define${kind === "database" ? "Database" : "Registry"} exports found`);
251
+ }
252
+ const block = blocks[0];
253
+ const dupKeys = collectDuplicateKeys(block.entries);
254
+ if (dupKeys.length > 0) {
255
+ errors.push(`duplicate object keys: ${dupKeys.join(", ")}`);
256
+ }
257
+ for (const entry of block.entries) {
258
+ const valueId = entry.value.match(/^[A-Za-z_$][\w$]*$/)?.[0];
259
+ if (valueId && !hasImportBinding(imports, valueId) && valueId !== block.exportName) {
260
+ if (!source.includes(`const ${valueId}`) && !source.includes(`function ${valueId}`)) {
261
+ errors.push(`value "${valueId}" for key "${entry.key}" is not imported`);
262
+ }
263
+ }
264
+ }
265
+ if (kind === "database" && !hasImportBinding(imports, "defineDatabase")) {
266
+ errors.push("missing defineDatabase import");
267
+ }
268
+ if (kind === "registry" && !hasImportBinding(imports, "defineRegistry")) {
269
+ errors.push("missing defineRegistry import");
270
+ }
271
+ return errors;
272
+ }
273
+ function preservedCustomUnits(existing, generated, kind) {
274
+ const custom = [];
275
+ const existingImports = parseNamedImports(existing);
276
+ const generatedImports = parseNamedImports(generated);
277
+ const generatedModules = new Set(generatedImports.map((item) => normalizeModulePath(item.module)));
278
+ const generatedNames = new Set(generatedImports.flatMap((item) => item.names));
279
+ for (const item of existingImports) {
280
+ const moduleNorm = normalizeModulePath(item.module);
281
+ if (moduleNorm.includes("@xylex-group/athena")) {
282
+ continue;
283
+ }
284
+ const unexpectedNames = item.names.filter((name) => !generatedNames.has(name));
285
+ if (unexpectedNames.length > 0 && !generatedModules.has(moduleNorm)) {
286
+ custom.push(`import { ${unexpectedNames.join(", ")} } from '${item.module}'`);
287
+ } else if (unexpectedNames.length > 0) {
288
+ custom.push(`import binding(s): ${unexpectedNames.join(", ")}`);
289
+ }
290
+ }
291
+ const existingBlocks = parseDefineBlocks(existing).filter((block) => block.kind === kind);
292
+ const generatedBlocks = parseDefineBlocks(generated).filter((block) => block.kind === kind);
293
+ const generatedKeys = new Set(generatedBlocks[0]?.entries.map((entry) => entry.key) ?? []);
294
+ for (const entry of existingBlocks[0]?.entries ?? []) {
295
+ if (!generatedKeys.has(entry.key)) {
296
+ custom.push(`${kind} entry: ${entry.key}: ${entry.value}`);
297
+ }
298
+ }
299
+ if (kind === "registry") {
300
+ const existingMeta = parseMetaBlock(existing);
301
+ const generatedMeta = parseMetaBlock(generated);
302
+ const generatedMetaKeys = new Set(generatedMeta?.entries.map((entry) => entry.key) ?? []);
303
+ for (const entry of existingMeta?.entries ?? []) {
304
+ if (!generatedMetaKeys.has(entry.key) && !KNOWN_META_KEYS.has(entry.key)) {
305
+ custom.push(`meta entry: ${entry.key}: ${entry.value}`);
306
+ }
307
+ }
308
+ }
309
+ const exportConstRe = /^export\s+const\s+([A-Za-z_$][\w$]*)\b/gm;
310
+ const generatedExports = /* @__PURE__ */ new Set();
311
+ let match;
312
+ exportConstRe.lastIndex = 0;
313
+ while ((match = exportConstRe.exec(generated)) !== null) {
314
+ generatedExports.add(match[1]);
315
+ }
316
+ exportConstRe.lastIndex = 0;
317
+ while ((match = exportConstRe.exec(existing)) !== null) {
318
+ if (!generatedExports.has(match[1]) && match[1] !== "__athena_schema_meta") {
319
+ custom.push(`export const ${match[1]}`);
320
+ }
321
+ }
322
+ return custom;
323
+ }
324
+ function insertImportAfterPackageImports(source, importLine, style) {
325
+ const imports = parseNamedImports(source);
326
+ if (imports.length === 0) {
327
+ return `${importLine}${style.newline}${source}`;
328
+ }
329
+ let anchor = imports[imports.length - 1];
330
+ for (let i = imports.length - 1; i >= 0; i -= 1) {
331
+ if (imports[i].module.startsWith(".")) {
332
+ anchor = imports[i];
333
+ break;
334
+ }
335
+ }
336
+ const insertAt = anchor.end;
337
+ const before = source.slice(0, insertAt);
338
+ const after = source.slice(insertAt);
339
+ const needsLeadingNl = !before.endsWith("\n");
340
+ const prefix = needsLeadingNl ? style.newline : "";
341
+ return `${before}${prefix}${importLine}${after.startsWith("\n") || after.startsWith("\r\n") ? "" : style.newline}${after}`;
342
+ }
343
+ function rewriteObjectBody(entries, style) {
344
+ if (entries.length === 0) {
345
+ return style.newline;
346
+ }
347
+ const lines = entries.map(
348
+ (entry, index) => formatObjectEntry(entry.key, entry.value, style, index === entries.length - 1)
349
+ );
350
+ return `${style.newline}${lines.join(style.newline)}${style.newline}`;
351
+ }
352
+ function mergeDatabaseArtifact(existing, generated) {
353
+ const style = detectStyle(existing);
354
+ const generatedStyle = detectStyle(generated);
355
+ const effectiveStyle = {
356
+ ...style,
357
+ // Prefer existing fingerprint; fall back to generated if existing is empty-ish
358
+ quote: existing.includes('"') || existing.includes("'") ? style.quote : generatedStyle.quote
359
+ };
360
+ const generatedImports = parseNamedImports(generated);
361
+ const existingBlocks = parseDefineBlocks(existing).filter((block) => block.kind === "database");
362
+ const generatedBlocks = parseDefineBlocks(generated).filter((block) => block.kind === "database");
363
+ if (existingBlocks.length === 0 || generatedBlocks.length === 0) {
364
+ return {
365
+ action: "skip",
366
+ skipReason: "merge-unparseable",
367
+ added: [],
368
+ preservedCustom: [],
369
+ conflicts: [],
370
+ lintErrors: [],
371
+ detail: "could not locate defineDatabase({\u2026}) export for merge"
372
+ };
373
+ }
374
+ const generatedBlock = generatedBlocks[0];
375
+ const conflicts = [];
376
+ const added = [];
377
+ let next = existing;
378
+ if (!hasImportBinding(parseNamedImports(next), "defineDatabase")) {
379
+ const pkgImport = generatedImports.find((item) => item.names.includes("defineDatabase"));
380
+ if (pkgImport) {
381
+ const line = formatImport(["defineDatabase"], pkgImport.module, effectiveStyle);
382
+ next = insertImportAfterPackageImports(next, line, effectiveStyle);
383
+ added.push("import defineDatabase");
384
+ }
385
+ }
386
+ let workingImports = parseNamedImports(next);
387
+ let workingBlocks = parseDefineBlocks(next).filter((block) => block.kind === "database");
388
+ let workingBlock = workingBlocks[0];
389
+ const entryMap = new Map(workingBlock.entries.map((entry) => [entry.key, entry]));
390
+ for (const desired of generatedBlock.entries) {
391
+ const existingEntry = entryMap.get(desired.key);
392
+ if (existingEntry) {
393
+ if (existingEntry.value !== desired.value) {
394
+ conflicts.push(
395
+ `key "${desired.key}" maps to ${existingEntry.value} (existing) vs ${desired.value} (generated)`
396
+ );
397
+ }
398
+ continue;
399
+ }
400
+ const desiredImport = generatedImports.find((item) => item.names.includes(desired.value));
401
+ if (desiredImport) {
402
+ const existingForName = findImportForName(workingImports, desired.value);
403
+ if (existingForName) {
404
+ if (normalizeModulePath(existingForName.module) !== normalizeModulePath(desiredImport.module)) {
405
+ conflicts.push(
406
+ `binding "${desired.value}" imported from '${existingForName.module}' vs '${desiredImport.module}'`
407
+ );
408
+ continue;
409
+ }
410
+ } else {
411
+ const line = formatImport([desired.value], desiredImport.module, effectiveStyle);
412
+ next = insertImportAfterPackageImports(next, line, effectiveStyle);
413
+ added.push(`import ${desired.value}`);
414
+ workingImports = parseNamedImports(next);
415
+ }
416
+ }
417
+ workingBlocks = parseDefineBlocks(next).filter((block) => block.kind === "database");
418
+ workingBlock = workingBlocks[0];
419
+ const nextEntries = [...workingBlock.entries, { key: desired.key, value: desired.value, raw: "" }];
420
+ const body = rewriteObjectBody(nextEntries, effectiveStyle);
421
+ next = replaceRange(next, workingBlock.bodyStart, workingBlock.bodyEnd, body);
422
+ entryMap.set(desired.key, { key: desired.key, value: desired.value, raw: "" });
423
+ added.push(`database entry: ${desired.key}`);
424
+ }
425
+ if (conflicts.length > 0 && added.length === 0) {
426
+ return {
427
+ action: "skip",
428
+ skipReason: "merge-conflict",
429
+ added: [],
430
+ preservedCustom: preservedCustomUnits(existing, generated, "database"),
431
+ conflicts,
432
+ lintErrors: [],
433
+ detail: conflicts.join("; ")
434
+ };
435
+ }
436
+ const lintErrors = lintArtifactSource(next, "database");
437
+ if (lintErrors.length > 0) {
438
+ return {
439
+ action: "skip",
440
+ skipReason: "merge-lint-failed",
441
+ added,
442
+ preservedCustom: preservedCustomUnits(existing, generated, "database"),
443
+ conflicts,
444
+ lintErrors,
445
+ detail: lintErrors.join("; ")
446
+ };
447
+ }
448
+ const preservedCustom = preservedCustomUnits(next, generated, "database");
449
+ if (next === existing || next.replace(/\r\n/g, "\n") === existing.replace(/\r\n/g, "\n")) {
450
+ return {
451
+ action: "unchanged",
452
+ content: existing,
453
+ skipReason: "already-current",
454
+ added: [],
455
+ preservedCustom,
456
+ conflicts,
457
+ lintErrors: [],
458
+ detail: conflicts.length > 0 ? conflicts.join("; ") : void 0
459
+ };
460
+ }
461
+ return {
462
+ action: "write",
463
+ content: next.endsWith("\n") ? next : `${next}${effectiveStyle.newline}`,
464
+ writeReason: "merged",
465
+ added,
466
+ preservedCustom,
467
+ conflicts,
468
+ lintErrors: []
469
+ };
470
+ }
471
+ function mergeMetaFields(existingMeta, generatedMeta) {
472
+ const added = [];
473
+ if (!generatedMeta) {
474
+ return { entries: existingMeta?.entries ?? [], changed: false, added };
475
+ }
476
+ if (!existingMeta) {
477
+ return {
478
+ entries: generatedMeta.entries,
479
+ changed: true,
480
+ added: generatedMeta.entries.map((entry) => `meta entry: ${entry.key}`)
481
+ };
482
+ }
483
+ const map = new Map(existingMeta.entries.map((entry) => [entry.key, entry]));
484
+ let changed = false;
485
+ for (const desired of generatedMeta.entries) {
486
+ const current = map.get(desired.key);
487
+ if (!current) {
488
+ map.set(desired.key, desired);
489
+ added.push(`meta entry: ${desired.key}`);
490
+ changed = true;
491
+ continue;
492
+ }
493
+ if (KNOWN_META_KEYS.has(desired.key) && current.value !== desired.value) {
494
+ map.set(desired.key, desired);
495
+ added.push(`meta refresh: ${desired.key}`);
496
+ changed = true;
497
+ }
498
+ }
499
+ const ordered = [];
500
+ const seen = /* @__PURE__ */ new Set();
501
+ for (const entry of existingMeta.entries) {
502
+ const next = map.get(entry.key);
503
+ if (next) {
504
+ ordered.push(next);
505
+ seen.add(entry.key);
506
+ }
507
+ }
508
+ for (const entry of generatedMeta.entries) {
509
+ if (!seen.has(entry.key)) {
510
+ const next = map.get(entry.key);
511
+ if (next) {
512
+ ordered.push(next);
513
+ seen.add(entry.key);
514
+ }
515
+ }
516
+ }
517
+ for (const [key, entry] of map) {
518
+ if (!seen.has(key)) {
519
+ ordered.push(entry);
520
+ }
521
+ }
522
+ return { entries: ordered, changed, added };
523
+ }
524
+ function mergeRegistryArtifact(existing, generated) {
525
+ const style = detectStyle(existing);
526
+ const effectiveStyle = style;
527
+ const generatedImports = parseNamedImports(generated);
528
+ const existingBlocks = parseDefineBlocks(existing).filter((block) => block.kind === "registry");
529
+ const generatedBlocks = parseDefineBlocks(generated).filter((block) => block.kind === "registry");
530
+ if (existingBlocks.length === 0 || generatedBlocks.length === 0) {
531
+ return {
532
+ action: "skip",
533
+ skipReason: "merge-unparseable",
534
+ added: [],
535
+ preservedCustom: [],
536
+ conflicts: [],
537
+ lintErrors: [],
538
+ detail: "could not locate defineRegistry({\u2026}) export for merge"
539
+ };
540
+ }
541
+ const existingBlock = existingBlocks[0];
542
+ const generatedBlock = generatedBlocks[0];
543
+ const conflicts = [];
544
+ const added = [];
545
+ let next = existing;
546
+ if (!hasImportBinding(parseNamedImports(next), "defineRegistry")) {
547
+ const pkgImport = generatedImports.find((item) => item.names.includes("defineRegistry"));
548
+ if (pkgImport) {
549
+ next = insertImportAfterPackageImports(
550
+ next,
551
+ formatImport(["defineRegistry"], pkgImport.module, effectiveStyle),
552
+ effectiveStyle
553
+ );
554
+ added.push("import defineRegistry");
555
+ }
556
+ }
557
+ const preferredDbValue = existingBlock.entries[0]?.value ?? generatedBlock.entries[0]?.value;
558
+ const generatedDbImport = generatedImports.find((item) => item.names.includes(generatedBlock.entries[0]?.value ?? "")) ?? generatedImports.find((item) => item.module.startsWith("."));
559
+ if (preferredDbValue && generatedDbImport) {
560
+ const existingForName = findImportForName(parseNamedImports(next), preferredDbValue);
561
+ if (!existingForName) {
562
+ const modulePath = generatedDbImport.module;
563
+ const importName = findImportForName(generatedImports, preferredDbValue)?.names[0] ?? generatedBlock.entries[0]?.value ?? preferredDbValue;
564
+ if (!hasImportBinding(parseNamedImports(next), importName)) {
565
+ next = insertImportAfterPackageImports(
566
+ next,
567
+ formatImport([importName], modulePath, effectiveStyle),
568
+ effectiveStyle
569
+ );
570
+ added.push(`import ${importName}`);
571
+ }
572
+ } else if (normalizeModulePath(existingForName.module) !== normalizeModulePath(generatedDbImport.module)) {
573
+ conflicts.push(
574
+ `binding "${preferredDbValue}" imported from '${existingForName.module}' vs '${generatedDbImport.module}'`
575
+ );
576
+ }
577
+ }
578
+ let workingBlocks = parseDefineBlocks(next).filter((block) => block.kind === "registry");
579
+ let workingBlock = workingBlocks[0];
580
+ const entryMap = new Map(workingBlock.entries.map((entry) => [entry.key, entry]));
581
+ for (const desired of generatedBlock.entries) {
582
+ const existingEntry = entryMap.get(desired.key);
583
+ if (existingEntry) {
584
+ continue;
585
+ }
586
+ const dbImport = parseNamedImports(next).find(
587
+ (item) => item.module.startsWith(".") && item.names.some((name) => name !== "defineRegistry")
588
+ );
589
+ const value = dbImport?.names[0] ?? desired.value;
590
+ const nextEntries = [...workingBlock.entries, { key: desired.key, value, raw: "" }];
591
+ const body = rewriteObjectBody(nextEntries, effectiveStyle);
592
+ next = replaceRange(next, workingBlock.bodyStart, workingBlock.bodyEnd, body);
593
+ entryMap.set(desired.key, { key: desired.key, value, raw: "" });
594
+ added.push(`registry entry: ${desired.key}`);
595
+ workingBlocks = parseDefineBlocks(next).filter((block) => block.kind === "registry");
596
+ workingBlock = workingBlocks[0];
597
+ }
598
+ const existingMeta = parseMetaBlock(next);
599
+ const generatedMeta = parseMetaBlock(generated);
600
+ const structuralAdded = added.length > 0;
601
+ if (generatedMeta) {
602
+ if (!existingMeta) {
603
+ const blocks = parseDefineBlocks(next).filter((block) => block.kind === "registry");
604
+ const insertAt = blocks[0]?.fullStart ?? next.length;
605
+ const metaBody = rewriteObjectBody(generatedMeta.entries, effectiveStyle);
606
+ const metaBlock = `export const __athena_schema_meta = {${metaBody}} as const${effectiveStyle.semicolons ? ";" : ""}${effectiveStyle.newline}${effectiveStyle.newline}`;
607
+ next = replaceRange(next, insertAt, insertAt, metaBlock);
608
+ added.push("__athena_schema_meta");
609
+ } else {
610
+ const desiredEntries = structuralAdded ? generatedMeta.entries : generatedMeta.entries.filter((entry) => {
611
+ return !existingMeta.entries.some((current) => current.key === entry.key);
612
+ });
613
+ if (structuralAdded) {
614
+ const merged = mergeMetaFields(existingMeta, generatedMeta);
615
+ if (merged.changed) {
616
+ const metaNow = parseMetaBlock(next);
617
+ if (metaNow) {
618
+ const body = rewriteObjectBody(merged.entries, effectiveStyle);
619
+ next = replaceRange(next, metaNow.bodyStart, metaNow.bodyEnd, body);
620
+ added.push(...merged.added);
621
+ }
622
+ }
623
+ } else if (desiredEntries.length > 0) {
624
+ const map = new Map(existingMeta.entries.map((entry) => [entry.key, entry]));
625
+ for (const entry of desiredEntries) {
626
+ map.set(entry.key, entry);
627
+ added.push(`meta entry: ${entry.key}`);
628
+ }
629
+ const ordered = [
630
+ ...existingMeta.entries.map((entry) => map.get(entry.key)),
631
+ ...desiredEntries.filter((entry) => !existingMeta.entries.some((e) => e.key === entry.key))
632
+ ];
633
+ const metaNow = parseMetaBlock(next);
634
+ if (metaNow) {
635
+ const body = rewriteObjectBody(ordered, effectiveStyle);
636
+ next = replaceRange(next, metaNow.bodyStart, metaNow.bodyEnd, body);
637
+ }
638
+ }
639
+ }
640
+ }
641
+ if (conflicts.length > 0 && added.length === 0) {
642
+ return {
643
+ action: "skip",
644
+ skipReason: "merge-conflict",
645
+ added: [],
646
+ preservedCustom: preservedCustomUnits(existing, generated, "registry"),
647
+ conflicts,
648
+ lintErrors: [],
649
+ detail: conflicts.join("; ")
650
+ };
651
+ }
652
+ const lintErrors = lintArtifactSource(next, "registry");
653
+ if (lintErrors.length > 0) {
654
+ return {
655
+ action: "skip",
656
+ skipReason: "merge-lint-failed",
657
+ added,
658
+ preservedCustom: preservedCustomUnits(existing, generated, "registry"),
659
+ conflicts,
660
+ lintErrors,
661
+ detail: lintErrors.join("; ")
662
+ };
663
+ }
664
+ const preservedCustom = preservedCustomUnits(next, generated, "registry");
665
+ if (next.replace(/\r\n/g, "\n") === existing.replace(/\r\n/g, "\n")) {
666
+ return {
667
+ action: "unchanged",
668
+ content: existing,
669
+ skipReason: "already-current",
670
+ added: [],
671
+ preservedCustom,
672
+ conflicts,
673
+ lintErrors: []
674
+ };
675
+ }
676
+ return {
677
+ action: "write",
678
+ content: next.endsWith("\n") ? next : `${next}${effectiveStyle.newline}`,
679
+ writeReason: "merged",
680
+ added,
681
+ preservedCustom,
682
+ conflicts,
683
+ lintErrors: []
684
+ };
685
+ }
686
+ function mergeProtectedArtifact(kind, existing, generated, policy) {
687
+ if (policy === "overwrite") {
688
+ if (existing.replace(/\r\n/g, "\n") === generated.replace(/\r\n/g, "\n")) {
689
+ return {
690
+ action: "unchanged",
691
+ content: existing,
692
+ skipReason: "already-current",
693
+ added: [],
694
+ preservedCustom: [],
695
+ conflicts: [],
696
+ lintErrors: []
697
+ };
698
+ }
699
+ return {
700
+ action: "write",
701
+ content: generated,
702
+ writeReason: "overwritten",
703
+ added: ["full overwrite"],
704
+ preservedCustom: [],
705
+ conflicts: [],
706
+ lintErrors: []
707
+ };
708
+ }
709
+ if (policy === "skip") {
710
+ return {
711
+ action: "skip",
712
+ skipReason: "protected-existing-file",
713
+ added: [],
714
+ preservedCustom: preservedCustomUnits(existing, generated, kind),
715
+ conflicts: [],
716
+ lintErrors: [],
717
+ detail: "artifactWrite policy is skip"
718
+ };
719
+ }
720
+ return kind === "database" ? mergeDatabaseArtifact(existing, generated) : mergeRegistryArtifact(existing, generated);
721
+ }
722
+ function resolveArtifactWritePlan(file, existingContent, policy) {
723
+ if (existingContent === null) {
724
+ return {
725
+ action: "write",
726
+ content: file.content,
727
+ writeReason: "created",
728
+ added: ["created"],
729
+ preservedCustom: [],
730
+ conflicts: [],
731
+ lintErrors: []
732
+ };
733
+ }
734
+ if (file.kind === "model" || file.kind === "schema" || policy === "always") {
735
+ if (existingContent.replace(/\r\n/g, "\n") === file.content.replace(/\r\n/g, "\n")) {
736
+ return {
737
+ action: "unchanged",
738
+ content: existingContent,
739
+ skipReason: "already-current",
740
+ added: [],
741
+ preservedCustom: [],
742
+ conflicts: [],
743
+ lintErrors: []
744
+ };
745
+ }
746
+ return {
747
+ action: "write",
748
+ content: file.content,
749
+ writeReason: existingContent ? "overwritten" : "created",
750
+ added: ["overwritten"],
751
+ preservedCustom: [],
752
+ conflicts: [],
753
+ lintErrors: []
754
+ };
755
+ }
756
+ return mergeProtectedArtifact(
757
+ file.kind,
758
+ existingContent,
759
+ file.content,
760
+ policy
761
+ );
762
+ }
763
+
8
764
  // src/utils/slugify.ts
9
765
  function slugify(input) {
10
766
  return input.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 64);
@@ -781,6 +1537,12 @@ var ATHENA_DIRECT_TARGETS = {
781
1537
  };
782
1538
  var DEFAULT_OUTPUT_FORMAT = "table-builder";
783
1539
  var DEFAULT_OUTPUT_PRESET = "athena-direct";
1540
+ var DEFAULT_ARTIFACT_WRITE_POLICY = "merge";
1541
+ var ARTIFACT_WRITE_POLICIES = /* @__PURE__ */ new Set([
1542
+ "merge",
1543
+ "skip",
1544
+ "overwrite"
1545
+ ]);
784
1546
  var DEFAULT_NAMING = {
785
1547
  modelType: "pascal",
786
1548
  modelConst: "camel",
@@ -1060,6 +1822,23 @@ function normalizeFilterConfig(input) {
1060
1822
  excludeTables: normalizeTableSelection(input?.excludeTables)
1061
1823
  };
1062
1824
  }
1825
+ function normalizeArtifactWritePolicy(value, fieldName) {
1826
+ if (value === void 0 || value === null || value === "") {
1827
+ return DEFAULT_ARTIFACT_WRITE_POLICY;
1828
+ }
1829
+ if (typeof value === "string" && ARTIFACT_WRITE_POLICIES.has(value)) {
1830
+ return value;
1831
+ }
1832
+ throw new Error(
1833
+ `Invalid output.artifactWrite.${fieldName}: expected one of merge | skip | overwrite, received ${JSON.stringify(value)}.`
1834
+ );
1835
+ }
1836
+ function normalizeArtifactWriteConfig(input) {
1837
+ return {
1838
+ database: normalizeArtifactWritePolicy(input?.database, "database"),
1839
+ registry: normalizeArtifactWritePolicy(input?.registry, "registry")
1840
+ };
1841
+ }
1063
1842
  function normalizeOutputConfig(output) {
1064
1843
  const preset = output?.preset ?? DEFAULT_OUTPUT_PRESET;
1065
1844
  return {
@@ -1071,7 +1850,8 @@ function normalizeOutputConfig(output) {
1071
1850
  },
1072
1851
  placeholderMap: {
1073
1852
  ...output?.placeholderMap ?? {}
1074
- }
1853
+ },
1854
+ artifactWrite: normalizeArtifactWriteConfig(output?.artifactWrite)
1075
1855
  };
1076
1856
  }
1077
1857
  function normalizeProviderConfig(provider) {
@@ -3220,7 +4000,7 @@ function buildRpcDebugSql(payload) {
3220
4000
  }
3221
4001
 
3222
4002
  // src/gateway/url.ts
3223
- var ATHENA_DEFAULT_BASE_URL = "https://athena-db.com";
4003
+ var ATHENA_DEFAULT_BASE_URL = "https://mirror2.athena-cluster.com";
3224
4004
  function describeReceivedValue(value) {
3225
4005
  if (value === void 0) return "undefined";
3226
4006
  if (value === null) return "null";
@@ -3243,14 +4023,14 @@ function normalizeAthenaGatewayBaseUrl(input, options = {}) {
3243
4023
  if (candidate === void 0 || candidate === null) {
3244
4024
  throw invalidBaseUrlError(
3245
4025
  `${label} must be a non-empty absolute http(s) URL. Received ${describeReceivedValue(input)}.`,
3246
- 'Set ATHENA_URL in the explicit env object (or pass createClient({ url, key })) to a full URL such as "https://mirror3.athena-db.com".'
4026
+ 'Set ATHENA_URL in the explicit env object (or pass createClient({ url, key })) to a full URL such as "https://mirror2.athena-cluster.com".'
3247
4027
  );
3248
4028
  }
3249
4029
  const trimmed = candidate.trim();
3250
4030
  if (!trimmed) {
3251
4031
  throw invalidBaseUrlError(
3252
4032
  `${label} must be a non-empty absolute http(s) URL. Received ${describeReceivedValue(candidate)}.`,
3253
- 'Set ATHENA_URL in the explicit env object (or pass createClient({ url, key })) to a full URL such as "https://mirror3.athena-db.com".'
4033
+ 'Set ATHENA_URL in the explicit env object (or pass createClient({ url, key })) to a full URL such as "https://mirror2.athena-cluster.com".'
3254
4034
  );
3255
4035
  }
3256
4036
  let parsed;
@@ -3259,13 +4039,13 @@ function normalizeAthenaGatewayBaseUrl(input, options = {}) {
3259
4039
  } catch {
3260
4040
  throw invalidBaseUrlError(
3261
4041
  `${label} must be a valid absolute http(s) URL. Received ${describeReceivedValue(candidate)}.`,
3262
- 'Use a full URL including the protocol, for example "https://mirror3.athena-db.com".'
4042
+ 'Use a full URL including the protocol, for example "https://mirror2.athena-cluster.com".'
3263
4043
  );
3264
4044
  }
3265
4045
  if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
3266
4046
  throw invalidBaseUrlError(
3267
4047
  `${label} must use http or https. Received ${JSON.stringify(trimmed)}.`,
3268
- 'Use an Athena gateway URL such as "https://mirror3.athena-db.com".'
4048
+ 'Use an Athena gateway URL such as "https://mirror2.athena-cluster.com".'
3269
4049
  );
3270
4050
  }
3271
4051
  if (parsed.search || parsed.hash) {
@@ -3288,7 +4068,7 @@ function buildAthenaGatewayUrl(baseUrl, path) {
3288
4068
 
3289
4069
  // package.json
3290
4070
  var package_default = {
3291
- version: "3.0.0"
4071
+ version: "3.0.3"
3292
4072
  };
3293
4073
 
3294
4074
  // src/sdk-version.ts
@@ -3698,7 +4478,7 @@ function createAthenaRequest(config, resolveContext) {
3698
4478
  }
3699
4479
 
3700
4480
  // src/gateway/client.ts
3701
- var DEFAULT_CLIENT = "railway_direct";
4481
+ var DEFAULT_CLIENT = "DEFAULT_CLIENT";
3702
4482
  var SDK_NAME2 = "xylex-group/athena";
3703
4483
  var SDK_HEADER_VALUE = buildSdkHeaderValue(SDK_NAME2);
3704
4484
  function parseResponseBody(rawText, contentType) {
@@ -10526,6 +11306,25 @@ function createBillingModule(config) {
10526
11306
  createCheckout(body, options) {
10527
11307
  return call("POST", "/billing/v1/checkouts", body, options);
10528
11308
  },
11309
+ listProducts(input, options) {
11310
+ return call(
11311
+ "GET",
11312
+ appendQuery3("/billing/v1/products", connectionQuery(input)),
11313
+ void 0,
11314
+ options
11315
+ );
11316
+ },
11317
+ listPrices(input, options) {
11318
+ return call(
11319
+ "GET",
11320
+ appendQuery3("/billing/v1/prices", {
11321
+ ...connectionQuery(input),
11322
+ ...input.productId ? { productId: input.productId } : {}
11323
+ }),
11324
+ void 0,
11325
+ options
11326
+ );
11327
+ },
10529
11328
  listCustomers(input, options) {
10530
11329
  return call(
10531
11330
  "GET",
@@ -10672,10 +11471,7 @@ function createBillingModule(config) {
10672
11471
  getRefund(id, input, options) {
10673
11472
  return call(
10674
11473
  "GET",
10675
- appendQuery3(withPathParam2("/billing/v1/refunds/{id}", "id", id), {
10676
- ...connectionQuery(input),
10677
- ...input.paymentId ? { paymentId: input.paymentId } : {}
10678
- }),
11474
+ appendQuery3(withPathParam2("/billing/v1/refunds/{id}", "id", id), connectionQuery(input)),
10679
11475
  void 0,
10680
11476
  options
10681
11477
  );
@@ -10683,10 +11479,7 @@ function createBillingModule(config) {
10683
11479
  cancelRefund(id, input, options) {
10684
11480
  return call(
10685
11481
  "POST",
10686
- appendQuery3(withPathParam2("/billing/v1/refunds/{id}/cancel", "id", id), {
10687
- ...connectionQuery(input),
10688
- ...input.paymentId ? { paymentId: input.paymentId } : {}
10689
- }),
11482
+ appendQuery3(withPathParam2("/billing/v1/refunds/{id}/cancel", "id", id), connectionQuery(input)),
10690
11483
  {},
10691
11484
  options
10692
11485
  );
@@ -10705,10 +11498,10 @@ function createBillingModule(config) {
10705
11498
  getSubscription(id, input, options) {
10706
11499
  return call(
10707
11500
  "GET",
10708
- appendQuery3(withPathParam2("/billing/v1/subscriptions/{id}", "id", id), {
10709
- ...connectionQuery(input),
10710
- ...input.customerId ? { customerId: input.customerId } : {}
10711
- }),
11501
+ appendQuery3(
11502
+ withPathParam2("/billing/v1/subscriptions/{id}", "id", id),
11503
+ connectionQuery(input)
11504
+ ),
10712
11505
  void 0,
10713
11506
  options
10714
11507
  );
@@ -10724,10 +11517,10 @@ function createBillingModule(config) {
10724
11517
  cancelSubscription(id, input, options) {
10725
11518
  return call(
10726
11519
  "POST",
10727
- appendQuery3(withPathParam2("/billing/v1/subscriptions/{id}/cancel", "id", id), {
10728
- ...connectionQuery(input),
10729
- customerId: input.customerId
10730
- }),
11520
+ appendQuery3(
11521
+ withPathParam2("/billing/v1/subscriptions/{id}/cancel", "id", id),
11522
+ connectionQuery(input)
11523
+ ),
10731
11524
  {},
10732
11525
  options
10733
11526
  );
@@ -10751,6 +11544,57 @@ function createBillingModule(config) {
10751
11544
  options
10752
11545
  );
10753
11546
  },
11547
+ listWebhooks(input, options) {
11548
+ return call(
11549
+ "GET",
11550
+ appendQuery3("/billing/v1/webhooks", connectionQuery(input)),
11551
+ void 0,
11552
+ options
11553
+ );
11554
+ },
11555
+ createWebhook(input, body, options) {
11556
+ return call(
11557
+ "POST",
11558
+ appendQuery3("/billing/v1/webhooks", connectionQuery(input)),
11559
+ body,
11560
+ options
11561
+ );
11562
+ },
11563
+ getWebhook(id, input, options) {
11564
+ return call(
11565
+ "GET",
11566
+ appendQuery3(withPathParam2("/billing/v1/webhooks/{id}", "id", id), connectionQuery(input)),
11567
+ void 0,
11568
+ options
11569
+ );
11570
+ },
11571
+ updateWebhook(id, input, body, options) {
11572
+ return call(
11573
+ "PATCH",
11574
+ appendQuery3(withPathParam2("/billing/v1/webhooks/{id}", "id", id), connectionQuery(input)),
11575
+ body,
11576
+ options
11577
+ );
11578
+ },
11579
+ deleteWebhook(id, input, options) {
11580
+ return call(
11581
+ "DELETE",
11582
+ appendQuery3(withPathParam2("/billing/v1/webhooks/{id}", "id", id), connectionQuery(input)),
11583
+ void 0,
11584
+ options
11585
+ );
11586
+ },
11587
+ testWebhook(id, input, options) {
11588
+ return call(
11589
+ "POST",
11590
+ appendQuery3(
11591
+ withPathParam2("/billing/v1/webhooks/{id}/test", "id", id),
11592
+ connectionQuery(input)
11593
+ ),
11594
+ {},
11595
+ options
11596
+ );
11597
+ },
10754
11598
  listConnections(clientName, options) {
10755
11599
  return call(
10756
11600
  "GET",
@@ -10928,6 +11772,31 @@ function createBillingModule(config) {
10928
11772
  };
10929
11773
  }
10930
11774
 
11775
+ // src/config/errors.ts
11776
+ var AthenaConfigurationError = class extends Error {
11777
+ code;
11778
+ service;
11779
+ constructor(code, message, service) {
11780
+ super(message);
11781
+ this.name = "AthenaConfigurationError";
11782
+ this.code = code;
11783
+ this.service = service;
11784
+ }
11785
+ };
11786
+
11787
+ // src/context/merge.ts
11788
+ function mergeAthenaRequestContexts(base, override) {
11789
+ if (!base && !override) return void 0;
11790
+ return {
11791
+ ...base,
11792
+ ...override,
11793
+ headers: base?.headers || override?.headers ? {
11794
+ ...base?.headers ?? {},
11795
+ ...override?.headers ?? {}
11796
+ } : void 0
11797
+ };
11798
+ }
11799
+
10931
11800
  // src/v3-client.ts
10932
11801
  var ENV_URL_KEYS = ["ATHENA_URL", "NEXT_PUBLIC_ATHENA_URL"];
10933
11802
  var ENV_DB_URL_KEYS = ["ATHENA_DB_URL", "ATHENA_GATEWAY_URL", "NEXT_PUBLIC_ATHENA_DB_API_URL"];
@@ -10938,15 +11807,6 @@ var ENV_STORAGE_URL_KEYS = ["ATHENA_STORAGE_URL", "NEXT_PUBLIC_ATHENA_STORAGE_UR
10938
11807
  var ENV_KEY_KEYS = ["ATHENA_API_KEY", "NEXT_PUBLIC_ATHENA_API_KEY", "ATHENA_GATEWAY_API_KEY", "X_API_KEY"];
10939
11808
  var ENV_CLIENT_KEYS = ["ATHENA_CLIENT", "NEXT_PUBLIC_ATHENA_CLIENT"];
10940
11809
  var MISSING_DB_SENTINEL = "https://athena.invalid/db";
10941
- var AthenaConfigurationError = class extends Error {
10942
- code = "ATHENA_SERVICE_NOT_CONFIGURED";
10943
- service;
10944
- constructor(service, message = `Athena ${service} is not configured.`) {
10945
- super(message);
10946
- this.name = "AthenaConfigurationError";
10947
- this.service = service;
10948
- }
10949
- };
10950
11810
  function readFirstEnv(env, keys) {
10951
11811
  for (const key of keys) {
10952
11812
  const value = env?.[key]?.trim();
@@ -10987,11 +11847,18 @@ function resolveCore(config) {
10987
11847
  chatWs: normalizeOptional(config.chat?.wsUrl) ?? (explicitRootWinsOverEnvServices && root ? toWebSocketUrl(root) : void 0) ?? readFirstEnv(env, ENV_CHAT_WS_URL_KEYS) ?? (root ? toWebSocketUrl(root) : void 0)
10988
11848
  };
10989
11849
  if (!urls.db && !urls.auth && !urls.chat && !urls.storage && !urls.billing) {
10990
- throw new AthenaConfigurationError("db", "Athena requires a unified URL or at least one configured service URL.");
11850
+ throw new AthenaConfigurationError(
11851
+ "ATHENA_NO_SERVICE_CONFIGURED",
11852
+ "Athena requires a unified URL or at least one configured service URL.",
11853
+ "db"
11854
+ );
10991
11855
  }
10992
11856
  const key = normalizeOptional(config.key) ?? readFirstEnv(env, ENV_KEY_KEYS);
10993
11857
  if (!key) {
10994
- throw new Error("Athena API key is required. Pass key or provide it through the explicit env object.");
11858
+ throw new AthenaConfigurationError(
11859
+ "ATHENA_API_KEY_REQUIRED",
11860
+ "Athena API key is required. Pass key or provide it through the explicit env object."
11861
+ );
10995
11862
  }
10996
11863
  const base = {
10997
11864
  config,
@@ -11004,18 +11871,10 @@ function resolveCore(config) {
11004
11871
  internalCore: createInternalClientCore(createInternalConfig(base))
11005
11872
  };
11006
11873
  }
11007
- function mergeContexts(base, override) {
11008
- if (!base && !override) return void 0;
11009
- return {
11010
- ...base,
11011
- ...override,
11012
- headers: base?.headers || override?.headers ? { ...base?.headers ?? {}, ...override?.headers ?? {} } : void 0
11013
- };
11014
- }
11015
11874
  async function resolveConfiguredContext(core, viewContext) {
11016
11875
  const configured = core.config.context;
11017
11876
  const base = typeof configured === "function" ? await configured() : configured;
11018
- return mergeContexts(base, viewContext);
11877
+ return mergeAthenaRequestContexts(base, viewContext);
11019
11878
  }
11020
11879
  function createInternalConfig(core) {
11021
11880
  const { config, urls } = core;
@@ -11048,7 +11907,13 @@ function createInternalConfig(core) {
11048
11907
  };
11049
11908
  }
11050
11909
  function serviceGuard(urls, service) {
11051
- if (!urls[service]) throw new AthenaConfigurationError(service);
11910
+ if (!urls[service]) {
11911
+ throw new AthenaConfigurationError(
11912
+ "ATHENA_SERVICE_NOT_CONFIGURED",
11913
+ `Athena ${service} is not configured.`,
11914
+ service
11915
+ );
11916
+ }
11052
11917
  }
11053
11918
  function createUnavailableNamespace(service, urls, path = []) {
11054
11919
  return new Proxy(() => void 0, {
@@ -11107,7 +11972,7 @@ function createClientView(core, viewContext) {
11107
11972
  return resolved.verifyConnection(options);
11108
11973
  },
11109
11974
  withContext(context) {
11110
- return createClientView(core, mergeContexts(viewContext, context));
11975
+ return createClientView(core, mergeAthenaRequestContexts(viewContext, context));
11111
11976
  }
11112
11977
  };
11113
11978
  return Object.freeze(client);
@@ -11658,9 +12523,6 @@ function resolveGeneratorProvider(providerConfig, experimentalFlags) {
11658
12523
  }
11659
12524
 
11660
12525
  // src/generator/pipeline.ts
11661
- function canOverwriteArtifact(file) {
11662
- return file.kind === "model" || file.kind === "schema";
11663
- }
11664
12526
  async function fileExists(path) {
11665
12527
  try {
11666
12528
  await stat(path);
@@ -11669,25 +12531,70 @@ async function fileExists(path) {
11669
12531
  return false;
11670
12532
  }
11671
12533
  }
11672
- async function writeArtifacts(files, cwd) {
12534
+ async function readExisting(path) {
12535
+ try {
12536
+ return await readFile(path, "utf8");
12537
+ } catch {
12538
+ return null;
12539
+ }
12540
+ }
12541
+ function policyForArtifact(file, config) {
12542
+ if (file.kind === "model" || file.kind === "schema") {
12543
+ return "always";
12544
+ }
12545
+ if (file.kind === "database") {
12546
+ return config.output.artifactWrite.database;
12547
+ }
12548
+ return config.output.artifactWrite.registry;
12549
+ }
12550
+ async function writeArtifacts(files, cwd, config, dryRun) {
11673
12551
  const writtenFiles = [];
12552
+ const writtenDetails = [];
11674
12553
  const skippedFiles = [];
11675
12554
  for (const file of files) {
11676
12555
  const absolutePath = resolve(cwd, file.path);
11677
- if (!canOverwriteArtifact(file) && await fileExists(absolutePath)) {
12556
+ const exists = await fileExists(absolutePath);
12557
+ const existingContent = exists ? await readExisting(absolutePath) : null;
12558
+ const policy = policyForArtifact(file, config);
12559
+ const plan = resolveArtifactWritePlan(file, existingContent, policy);
12560
+ if (plan.action === "skip" || plan.action === "unchanged") {
12561
+ skippedFiles.push({
12562
+ kind: file.kind,
12563
+ path: file.path,
12564
+ reason: plan.skipReason ?? "already-current",
12565
+ detail: plan.detail,
12566
+ preservedCustom: plan.preservedCustom.length > 0 ? plan.preservedCustom : void 0,
12567
+ conflicts: plan.conflicts.length > 0 ? plan.conflicts : void 0,
12568
+ lintErrors: plan.lintErrors.length > 0 ? plan.lintErrors : void 0
12569
+ });
12570
+ continue;
12571
+ }
12572
+ if (!plan.content || !plan.writeReason) {
11678
12573
  skippedFiles.push({
11679
12574
  kind: file.kind,
11680
12575
  path: file.path,
11681
- reason: "protected-existing-file"
12576
+ reason: "merge-lint-failed",
12577
+ detail: "merge produced no content",
12578
+ lintErrors: plan.lintErrors
11682
12579
  });
11683
12580
  continue;
11684
12581
  }
11685
- await mkdir(dirname(absolutePath), { recursive: true });
11686
- await writeFile(absolutePath, file.content, "utf8");
12582
+ if (!dryRun) {
12583
+ await mkdir(dirname(absolutePath), { recursive: true });
12584
+ await writeFile(absolutePath, plan.content, "utf8");
12585
+ }
11687
12586
  writtenFiles.push(file.path);
12587
+ writtenDetails.push({
12588
+ kind: file.kind,
12589
+ path: file.path,
12590
+ reason: plan.writeReason,
12591
+ added: plan.added.length > 0 ? plan.added : void 0,
12592
+ preservedCustom: plan.preservedCustom.length > 0 ? plan.preservedCustom : void 0
12593
+ });
11688
12594
  }
11689
12595
  return {
11690
12596
  writtenFiles,
12597
+ writtenDetails,
11691
12598
  skippedFiles
11692
12599
  };
11693
12600
  }
@@ -11703,12 +12610,18 @@ async function runSchemaGenerator(options = {}) {
11703
12610
  schemas: resolveProviderSchemas(config.provider)
11704
12611
  });
11705
12612
  const generated = generateArtifactsFromSnapshot(snapshot, config);
11706
- const writeResult = options.dryRun ? { writtenFiles: [], skippedFiles: [] } : await writeArtifacts(generated.files, cwd);
12613
+ const writeResult = await writeArtifacts(
12614
+ generated.files,
12615
+ cwd,
12616
+ config,
12617
+ options.dryRun === true
12618
+ );
11707
12619
  return {
11708
12620
  ...generated,
11709
12621
  configPath,
11710
12622
  config,
11711
12623
  writtenFiles: writeResult.writtenFiles,
12624
+ writtenDetails: writeResult.writtenDetails,
11712
12625
  skippedFiles: writeResult.skippedFiles
11713
12626
  };
11714
12627
  }
@@ -11998,10 +12911,52 @@ function logCliError(error, errorLog = console.error) {
11998
12911
  }
11999
12912
  function formatSkippedArtifactLine(artifact) {
12000
12913
  if (artifact.reason === "protected-existing-file") {
12001
- return ` [skip] ${artifact.path} (existing ${artifact.kind} artifacts are protected from overwrite; delete or retarget the file to regenerate it)`;
12914
+ return ` [skip] ${artifact.path} (existing ${artifact.kind} artifacts are protected from overwrite; set output.artifactWrite.${artifact.kind}="merge"|"overwrite" or delete/retarget the file)`;
12915
+ }
12916
+ if (artifact.reason === "already-current") {
12917
+ const custom = artifact.preservedCustom && artifact.preservedCustom.length > 0 ? `; preserves ${artifact.preservedCustom.length} non-generated unit(s)` : "";
12918
+ return ` [ok] ${artifact.path} (already current${custom})`;
12919
+ }
12920
+ if (artifact.reason === "merge-conflict") {
12921
+ return ` [skip] ${artifact.path} (merge conflict: ${artifact.detail ?? "see conflicts"}; file left unchanged)`;
12922
+ }
12923
+ if (artifact.reason === "merge-lint-failed") {
12924
+ return ` [skip] ${artifact.path} (merge lint failed: ${artifact.detail ?? "invalid merged TypeScript"}; file left unchanged)`;
12925
+ }
12926
+ if (artifact.reason === "merge-unparseable") {
12927
+ return ` [skip] ${artifact.path} (existing ${artifact.kind} artifact is not mergeable; delete, retarget, or set output.artifactWrite.${artifact.kind}="overwrite")`;
12002
12928
  }
12003
12929
  return ` [skip] ${artifact.path}`;
12004
12930
  }
12931
+ function formatWrittenArtifactLine(artifact) {
12932
+ if (artifact.reason === "merged") {
12933
+ const added = artifact.added && artifact.added.length > 0 ? ` +${artifact.added.length}: ${artifact.added.slice(0, 4).join(", ")}${artifact.added.length > 4 ? "\u2026" : ""}` : "";
12934
+ const custom = artifact.preservedCustom && artifact.preservedCustom.length > 0 ? `; preserves ${artifact.preservedCustom.length} non-generated unit(s)` : "";
12935
+ return ` [merge] ${artifact.path}${added}${custom}`;
12936
+ }
12937
+ if (artifact.reason === "overwritten") {
12938
+ return ` [write] ${artifact.path} (overwritten)`;
12939
+ }
12940
+ return ` - ${artifact.path}`;
12941
+ }
12942
+ function formatCustomPreserveWarnings(result) {
12943
+ const lines = [];
12944
+ for (const artifact of result.writtenDetails) {
12945
+ if (artifact.preservedCustom && artifact.preservedCustom.length > 0) {
12946
+ lines.push(
12947
+ ` [warn] ${artifact.path} preserves non-generated unit(s): ${artifact.preservedCustom.slice(0, 3).join("; ")}${artifact.preservedCustom.length > 3 ? "\u2026" : ""}`
12948
+ );
12949
+ }
12950
+ }
12951
+ for (const artifact of result.skippedFiles) {
12952
+ if (artifact.reason === "already-current" && artifact.preservedCustom && artifact.preservedCustom.length > 0) {
12953
+ lines.push(
12954
+ ` [warn] ${artifact.path} preserves non-generated unit(s): ${artifact.preservedCustom.slice(0, 3).join("; ")}${artifact.preservedCustom.length > 3 ? "\u2026" : ""}`
12955
+ );
12956
+ }
12957
+ }
12958
+ return lines;
12959
+ }
12005
12960
  async function runCLI(argv, runtime = {}) {
12006
12961
  const log = runtime.log ?? console.log;
12007
12962
  const errorLog = runtime.errorLog ?? console.error;
@@ -12043,18 +12998,44 @@ async function runCLI(argv, runtime = {}) {
12043
12998
  for (const file of result.files) {
12044
12999
  log(` - ${file.path}`);
12045
13000
  }
13001
+ if (result.writtenDetails?.length || result.skippedFiles?.length) {
13002
+ for (const artifact of result.writtenDetails ?? []) {
13003
+ if (artifact.kind === "database" || artifact.kind === "registry") {
13004
+ log(formatWrittenArtifactLine(artifact));
13005
+ }
13006
+ }
13007
+ for (const artifact of result.skippedFiles ?? []) {
13008
+ if (artifact.kind === "database" || artifact.kind === "registry") {
13009
+ log(formatSkippedArtifactLine(artifact));
13010
+ }
13011
+ }
13012
+ for (const line of formatCustomPreserveWarnings(result)) {
13013
+ log(line);
13014
+ }
13015
+ }
12046
13016
  return;
12047
13017
  }
12048
13018
  log(`Generated ${result.writtenFiles.length} files from ${result.configPath}`);
12049
13019
  for (const line of formatGeneratorModeLines(result)) {
12050
13020
  log(line);
12051
13021
  }
13022
+ const detailByPath = new Map(
13023
+ (result.writtenDetails ?? []).map((detail) => [detail.path, detail])
13024
+ );
12052
13025
  for (const filePath of result.writtenFiles) {
12053
- log(` - ${filePath}`);
13026
+ const detail = detailByPath.get(filePath);
13027
+ if (detail && (detail.reason === "merged" || detail.reason === "overwritten")) {
13028
+ log(formatWrittenArtifactLine(detail));
13029
+ } else {
13030
+ log(` - ${filePath}`);
13031
+ }
12054
13032
  }
12055
13033
  for (const artifact of result.skippedFiles) {
12056
13034
  log(formatSkippedArtifactLine(artifact));
12057
13035
  }
13036
+ for (const line of formatCustomPreserveWarnings(result)) {
13037
+ log(line);
13038
+ }
12058
13039
  }
12059
13040
 
12060
13041
  export { logCliError, parseCommand, runCLI, usage };