@xylex-group/better-auth-athena 1.0.8 → 1.0.9
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.
- package/README.md +1 -1
- package/dist/index.cjs +207 -67
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +207 -67
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# better-auth-athena
|
|
2
2
|
|
|
3
|
-
current version: `1.0.
|
|
3
|
+
current version: `1.0.9`
|
|
4
4
|
A Better-Auth database adapter for the `@xylex-group/athena` gateway. It lets Better-Auth read and write data through Athena while keeping column names in `snake_case` as required by the gateway.
|
|
5
5
|
|
|
6
6
|
## Installation
|
package/dist/index.cjs
CHANGED
|
@@ -271,23 +271,11 @@ function updateMethod(deps) {
|
|
|
271
271
|
const debugUpdates = process?.env?.ATHENA_ADAPTER_DEBUG_UPDATES === "1";
|
|
272
272
|
const debugLog = (event, extra) => {
|
|
273
273
|
if (!debugUpdates) return;
|
|
274
|
-
console.info("[AthenaAdapter][update]", {
|
|
275
|
-
event,
|
|
276
|
-
model,
|
|
277
|
-
...extra
|
|
278
|
-
});
|
|
274
|
+
console.info("[AthenaAdapter][update]", { event, model, ...extra });
|
|
279
275
|
};
|
|
280
|
-
const build = (
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
for (const clause of where) {
|
|
284
|
-
b2 = applyWhere(b2, clause.field, clause.operator, clause.value);
|
|
285
|
-
}
|
|
286
|
-
return b2;
|
|
287
|
-
}
|
|
288
|
-
let b = db.from(model).update(updateData, {
|
|
289
|
-
updateBody: { data: updateData, set: updateData }
|
|
290
|
-
});
|
|
276
|
+
const build = (shape) => {
|
|
277
|
+
const values = shape === "plain" ? updateData : { data: updateData, set: updateData };
|
|
278
|
+
let b = db.from(model).update(values);
|
|
291
279
|
for (const clause of where) {
|
|
292
280
|
b = applyWhere(b, clause.field, clause.operator, clause.value);
|
|
293
281
|
}
|
|
@@ -297,26 +285,99 @@ function updateMethod(deps) {
|
|
|
297
285
|
const { data: result, error } = await b.select();
|
|
298
286
|
return { result, error };
|
|
299
287
|
};
|
|
300
|
-
const
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
const
|
|
304
|
-
|
|
305
|
-
const
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
288
|
+
const directGatewayUpdate = async () => {
|
|
289
|
+
const { url, apiKey, client, headers: extraHeaders } = deps.getConnectionConfig();
|
|
290
|
+
const base = url.replace(/\/$/, "");
|
|
291
|
+
const conditions = where.map((clause) => {
|
|
292
|
+
const column = hasUppercase(clause.field) ? toSnakeCase(clause.field) : clause.field;
|
|
293
|
+
const value = clause.value;
|
|
294
|
+
switch (clause.operator) {
|
|
295
|
+
case "ne":
|
|
296
|
+
return { operator: "neq", column, value };
|
|
297
|
+
case "contains":
|
|
298
|
+
return { operator: "like", column, value: `%${value}%` };
|
|
299
|
+
case "starts_with":
|
|
300
|
+
return { operator: "like", column, value: `${String(value)}%` };
|
|
301
|
+
case "ends_with":
|
|
302
|
+
return { operator: "like", column, value: `%${String(value)}` };
|
|
303
|
+
case "eq":
|
|
304
|
+
return { operator: "eq", column, eq_column: column, value, eq_value: value };
|
|
305
|
+
default:
|
|
306
|
+
return { operator: clause.operator, column, value };
|
|
307
|
+
}
|
|
308
|
+
});
|
|
309
|
+
const requestHeaders = {
|
|
310
|
+
"Content-Type": "application/json",
|
|
311
|
+
"apikey": apiKey,
|
|
312
|
+
"x-api-key": apiKey,
|
|
313
|
+
"X-Athena-Client": client ?? "railway_direct",
|
|
314
|
+
"X-Backend-Type": "athena",
|
|
315
|
+
"X-Strip-Nulls": "true",
|
|
316
|
+
...extraHeaders ?? {}
|
|
317
|
+
};
|
|
318
|
+
const payloads = [
|
|
319
|
+
{ table_name: model, data: updateData, set: updateData, conditions, strip_nulls: true },
|
|
320
|
+
{
|
|
321
|
+
table_name: model,
|
|
322
|
+
columns: Object.entries(updateData).map(([column, value]) => ({ column, value })),
|
|
323
|
+
conditions,
|
|
324
|
+
strip_nulls: true
|
|
325
|
+
}
|
|
326
|
+
];
|
|
327
|
+
for (const payload of payloads) {
|
|
328
|
+
const res = await fetch(`${base}/gateway/update`, {
|
|
329
|
+
method: "POST",
|
|
330
|
+
headers: requestHeaders,
|
|
331
|
+
body: JSON.stringify(payload)
|
|
332
|
+
});
|
|
333
|
+
const raw = await res.text();
|
|
334
|
+
let parsed = null;
|
|
335
|
+
try {
|
|
336
|
+
parsed = JSON.parse(raw);
|
|
337
|
+
} catch {
|
|
338
|
+
parsed = raw;
|
|
339
|
+
}
|
|
340
|
+
const fetchError = parsed?.error ?? parsed?.message ?? null;
|
|
341
|
+
const fetchData = parsed?.data ?? null;
|
|
342
|
+
if (!fetchError || isSuccessMessageInError(fetchError)) {
|
|
343
|
+
debugLog("direct_gateway_succeeded");
|
|
344
|
+
return { result: fetchData, error: null };
|
|
345
|
+
}
|
|
346
|
+
debugLog("direct_gateway_shape_failed", { error: String(fetchError) });
|
|
347
|
+
if (!String(fetchError).toLowerCase().includes("update payload required")) {
|
|
348
|
+
return { result: null, error: String(fetchError) };
|
|
311
349
|
}
|
|
312
|
-
debugLog("retry_succeeded", { shape: "updateBody(data/set)" });
|
|
313
|
-
const row2 = Array.isArray(retry.result) ? retry.result[0] : retry.result;
|
|
314
|
-
return row2 ? mapRowToBetterAuth(row2) : null;
|
|
315
350
|
}
|
|
351
|
+
return { result: null, error: "update payload required: all gateway formats exhausted" };
|
|
352
|
+
};
|
|
353
|
+
const isPayloadError = (e) => String(e).toLowerCase().includes("update payload required");
|
|
354
|
+
const first = await run(build("plain"));
|
|
355
|
+
if (!first.error || isSuccessMessageInError(first.error)) {
|
|
356
|
+
debugLog("primary_succeeded", { shape: "plain" });
|
|
357
|
+
const row2 = Array.isArray(first.result) ? first.result[0] : first.result;
|
|
358
|
+
return row2 ? mapRowToBetterAuth(row2) : null;
|
|
359
|
+
}
|
|
360
|
+
debugLog("primary_failed", { error: String(first.error) });
|
|
361
|
+
if (!isPayloadError(first.error)) {
|
|
316
362
|
throw new Error(`[AthenaAdapter] update on "${model}" failed: ${first.error}`);
|
|
317
363
|
}
|
|
318
|
-
|
|
319
|
-
|
|
364
|
+
const second = await run(build("wrapped"));
|
|
365
|
+
if (!second.error || isSuccessMessageInError(second.error)) {
|
|
366
|
+
debugLog("wrapped_succeeded", { shape: "data/set" });
|
|
367
|
+
const row2 = Array.isArray(second.result) ? second.result[0] : second.result;
|
|
368
|
+
return row2 ? mapRowToBetterAuth(row2) : null;
|
|
369
|
+
}
|
|
370
|
+
debugLog("wrapped_failed", { error: String(second.error) });
|
|
371
|
+
if (!isPayloadError(second.error)) {
|
|
372
|
+
throw new Error(`[AthenaAdapter] update on "${model}" failed: ${second.error}`);
|
|
373
|
+
}
|
|
374
|
+
const direct = await directGatewayUpdate();
|
|
375
|
+
if (direct.error && !isSuccessMessageInError(direct.error)) {
|
|
376
|
+
debugLog("direct_gateway_final_failed", { error: String(direct.error) });
|
|
377
|
+
throw new Error(`[AthenaAdapter] update on "${model}" failed: ${direct.error}`);
|
|
378
|
+
}
|
|
379
|
+
debugLog("direct_gateway_succeeded");
|
|
380
|
+
const row = Array.isArray(direct.result) ? direct.result[0] : direct.result;
|
|
320
381
|
return row ? mapRowToBetterAuth(row) : null;
|
|
321
382
|
};
|
|
322
383
|
}
|
|
@@ -334,23 +395,11 @@ function updateManyMethod(deps) {
|
|
|
334
395
|
const debugUpdates = process.env.ATHENA_ADAPTER_DEBUG_UPDATES === "1";
|
|
335
396
|
const debugLog = (event, extra) => {
|
|
336
397
|
if (!debugUpdates) return;
|
|
337
|
-
console.info("[AthenaAdapter][updateMany]", {
|
|
338
|
-
event,
|
|
339
|
-
model,
|
|
340
|
-
...extra
|
|
341
|
-
});
|
|
398
|
+
console.info("[AthenaAdapter][updateMany]", { event, model, ...extra });
|
|
342
399
|
};
|
|
343
|
-
const build = (
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
for (const clause of where) {
|
|
347
|
-
b2 = applyWhere(b2, clause.field, clause.operator, clause.value);
|
|
348
|
-
}
|
|
349
|
-
return b2;
|
|
350
|
-
}
|
|
351
|
-
let b = db.from(model).update(updateData, {
|
|
352
|
-
updateBody: { data: updateData, set: updateData }
|
|
353
|
-
});
|
|
400
|
+
const build = (shape) => {
|
|
401
|
+
const values = shape === "plain" ? updateData : { data: updateData, set: updateData };
|
|
402
|
+
let b = db.from(model).update(values);
|
|
354
403
|
for (const clause of where) {
|
|
355
404
|
b = applyWhere(b, clause.field, clause.operator, clause.value);
|
|
356
405
|
}
|
|
@@ -360,27 +409,98 @@ function updateManyMethod(deps) {
|
|
|
360
409
|
const { data: result, error } = await b.select();
|
|
361
410
|
return { result, error };
|
|
362
411
|
};
|
|
363
|
-
const
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
const
|
|
367
|
-
|
|
368
|
-
const
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
412
|
+
const directGatewayUpdateMany = async () => {
|
|
413
|
+
const { url, apiKey, client, headers: extraHeaders } = deps.getConnectionConfig();
|
|
414
|
+
const base = url.replace(/\/$/, "");
|
|
415
|
+
const conditions = where.map((clause) => {
|
|
416
|
+
const column = hasUppercase(clause.field) ? toSnakeCase(clause.field) : clause.field;
|
|
417
|
+
const value = clause.value;
|
|
418
|
+
switch (clause.operator) {
|
|
419
|
+
case "ne":
|
|
420
|
+
return { operator: "neq", column, value };
|
|
421
|
+
case "contains":
|
|
422
|
+
return { operator: "like", column, value: `%${value}%` };
|
|
423
|
+
case "starts_with":
|
|
424
|
+
return { operator: "like", column, value: `${String(value)}%` };
|
|
425
|
+
case "ends_with":
|
|
426
|
+
return { operator: "like", column, value: `%${String(value)}` };
|
|
427
|
+
case "eq":
|
|
428
|
+
return { operator: "eq", column, eq_column: column, value, eq_value: value };
|
|
429
|
+
default:
|
|
430
|
+
return { operator: clause.operator, column, value };
|
|
431
|
+
}
|
|
432
|
+
});
|
|
433
|
+
const requestHeaders = {
|
|
434
|
+
"Content-Type": "application/json",
|
|
435
|
+
"apikey": apiKey,
|
|
436
|
+
"x-api-key": apiKey,
|
|
437
|
+
"X-Athena-Client": client ?? "railway_direct",
|
|
438
|
+
"X-Backend-Type": "athena",
|
|
439
|
+
"X-Strip-Nulls": "true",
|
|
440
|
+
...extraHeaders ?? {}
|
|
441
|
+
};
|
|
442
|
+
const payloads = [
|
|
443
|
+
{ table_name: model, data: updateData, set: updateData, conditions, strip_nulls: true },
|
|
444
|
+
{
|
|
445
|
+
table_name: model,
|
|
446
|
+
columns: Object.entries(updateData).map(([column, value]) => ({ column, value })),
|
|
447
|
+
conditions,
|
|
448
|
+
strip_nulls: true
|
|
449
|
+
}
|
|
450
|
+
];
|
|
451
|
+
for (const payload of payloads) {
|
|
452
|
+
const res = await fetch(`${base}/gateway/update`, {
|
|
453
|
+
method: "POST",
|
|
454
|
+
headers: requestHeaders,
|
|
455
|
+
body: JSON.stringify(payload)
|
|
456
|
+
});
|
|
457
|
+
const raw = await res.text();
|
|
458
|
+
let parsed = null;
|
|
459
|
+
try {
|
|
460
|
+
parsed = JSON.parse(raw);
|
|
461
|
+
} catch {
|
|
462
|
+
parsed = raw;
|
|
463
|
+
}
|
|
464
|
+
const fetchError = parsed?.error ?? parsed?.message ?? null;
|
|
465
|
+
const fetchData = parsed?.data ?? null;
|
|
466
|
+
if (!fetchError || isSuccessMessageInError(fetchError)) {
|
|
467
|
+
debugLog("direct_gateway_succeeded");
|
|
468
|
+
return { result: fetchData, error: null };
|
|
469
|
+
}
|
|
470
|
+
debugLog("direct_gateway_shape_failed", { error: String(fetchError) });
|
|
471
|
+
if (!String(fetchError).toLowerCase().includes("update payload required")) {
|
|
472
|
+
return { result: null, error: String(fetchError) };
|
|
374
473
|
}
|
|
375
|
-
debugLog("retry_succeeded", { shape: "updateBody(data/set)" });
|
|
376
|
-
return Array.isArray(retry.result) ? retry.result.length : retry.result ? 1 : 0;
|
|
377
474
|
}
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
475
|
+
return { result: null, error: "update payload required: all gateway formats exhausted" };
|
|
476
|
+
};
|
|
477
|
+
const countResult = (r) => Array.isArray(r) ? r.length : r ? 1 : 0;
|
|
478
|
+
const isPayloadError = (e) => String(e).toLowerCase().includes("update payload required");
|
|
479
|
+
const first = await run(build("plain"));
|
|
480
|
+
if (!first.error || isSuccessMessageInError(first.error)) {
|
|
481
|
+
debugLog("primary_succeeded", { shape: "plain" });
|
|
482
|
+
return countResult(first.result);
|
|
381
483
|
}
|
|
382
|
-
debugLog("
|
|
383
|
-
|
|
484
|
+
debugLog("primary_failed", { error: String(first.error) });
|
|
485
|
+
if (!isPayloadError(first.error)) {
|
|
486
|
+
throw new Error(`[AthenaAdapter] updateMany on "${model}" failed: ${first.error}`);
|
|
487
|
+
}
|
|
488
|
+
const second = await run(build("wrapped"));
|
|
489
|
+
if (!second.error || isSuccessMessageInError(second.error)) {
|
|
490
|
+
debugLog("wrapped_succeeded", { shape: "data/set" });
|
|
491
|
+
return countResult(second.result);
|
|
492
|
+
}
|
|
493
|
+
debugLog("wrapped_failed", { error: String(second.error) });
|
|
494
|
+
if (!isPayloadError(second.error)) {
|
|
495
|
+
throw new Error(`[AthenaAdapter] updateMany on "${model}" failed: ${second.error}`);
|
|
496
|
+
}
|
|
497
|
+
const direct = await directGatewayUpdateMany();
|
|
498
|
+
if (direct.error && !isSuccessMessageInError(direct.error)) {
|
|
499
|
+
debugLog("direct_gateway_final_failed", { error: String(direct.error) });
|
|
500
|
+
throw new Error(`[AthenaAdapter] updateMany on "${model}" failed: ${direct.error}`);
|
|
501
|
+
}
|
|
502
|
+
debugLog("direct_gateway_succeeded");
|
|
503
|
+
return countResult(direct.result);
|
|
384
504
|
};
|
|
385
505
|
}
|
|
386
506
|
|
|
@@ -713,7 +833,27 @@ var athenaAdapter = (config) => {
|
|
|
713
833
|
}
|
|
714
834
|
return dbClient;
|
|
715
835
|
}
|
|
716
|
-
|
|
836
|
+
function getConnectionConfig() {
|
|
837
|
+
if (shouldUseFixedConfig) {
|
|
838
|
+
return {
|
|
839
|
+
url: config.url,
|
|
840
|
+
apiKey: config.apiKey,
|
|
841
|
+
client: config.client,
|
|
842
|
+
headers: config.headers
|
|
843
|
+
};
|
|
844
|
+
}
|
|
845
|
+
const { config: globalConfig } = getAthenaGlobalConfig({
|
|
846
|
+
configPath: config.configPath,
|
|
847
|
+
watch: false
|
|
848
|
+
});
|
|
849
|
+
return {
|
|
850
|
+
url: config.url ?? globalConfig.athena.url,
|
|
851
|
+
apiKey: config.apiKey ?? globalConfig.athena.apiKey,
|
|
852
|
+
client: config.client ?? globalConfig.athena.client,
|
|
853
|
+
headers: config.headers
|
|
854
|
+
};
|
|
855
|
+
}
|
|
856
|
+
const deps = { ensureDbClient, getConnectionConfig, headers: config.headers };
|
|
717
857
|
return (0, import_adapters.createAdapterFactory)({
|
|
718
858
|
config: {
|
|
719
859
|
adapterId: "athena",
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/config.ts","../src/utils.ts","../src/methods/create.ts","../src/methods/update.ts","../src/methods/update-many.ts","../src/methods/delete.ts","../src/methods/delete-many.ts","../src/methods/find-one.ts","../src/methods/find-many.ts","../src/methods/count.ts"],"sourcesContent":["import {\r\n createAdapterFactory,\r\n type AdapterFactory,\r\n type DBAdapterDebugLogOption,\r\n} from \"better-auth/adapters\";\r\nimport type { BetterAuthOptions } from \"better-auth\";\r\nimport { createClient } from \"@xylex-group/athena\";\r\nimport { getAthenaGlobalConfig } from \"./config\";\r\nimport { createMethod } from \"./methods/create\";\r\nimport { updateMethod } from \"./methods/update\";\r\nimport { updateManyMethod } from \"./methods/update-many\";\r\nimport { deleteMethod } from \"./methods/delete\";\r\nimport { deleteManyMethod } from \"./methods/delete-many\";\r\nimport { findOneMethod } from \"./methods/find-one\";\r\nimport { findManyMethod } from \"./methods/find-many\";\r\nimport { countMethod } from \"./methods/count\";\r\n\r\n/**\r\n * Configuration options for the Athena adapter.\r\n */\r\nexport interface AthenaAdapterConfig {\r\n /**\r\n * The URL of your Athena gateway.\r\n */\r\n url?: string;\r\n /**\r\n * The API key for authenticating with the Athena gateway.\r\n */\r\n apiKey?: string;\r\n /**\r\n * The client name sent in requests to the Athena gateway.\r\n */\r\n client?: string;\r\n\r\n /**\r\n * Optional override for the YAML config path.\r\n * Defaults to `./config.yaml` (resolved from `process.cwd()`).\r\n */\r\n configPath?: string;\r\n\r\n /**\r\n * When enabled, the adapter will reload `config.yaml` on changes.\r\n *\r\n * @default true\r\n */\r\n watchConfig?: boolean;\r\n /**\r\n * Helps you debug issues with the adapter.\r\n */\r\n debugLogs?: DBAdapterDebugLogOption;\r\n /**\r\n * If the table names in the schema are plural.\r\n *\r\n * @default false\r\n */\r\n usePlural?: boolean;\r\n\r\n /**\r\n * Optional headers sent with every request (e.g. `X-User-Id` if your gateway requires it for delete).\r\n */\r\n headers?: Record<string, string>;\r\n}\r\n\r\n/**\r\n * Create a Better-Auth database adapter backed by @xylex-group/athena.\r\n *\r\n * Column names are kept in snake_case as required by the Athena gateway.\r\n *\r\n * @example\r\n * ```ts\r\n * import { betterAuth } from \"better-auth\";\r\n * import { athenaAdapter } from \"better-auth-athena\";\r\n *\r\n * export const auth = betterAuth({\r\n * database: athenaAdapter({\r\n * url: process.env.ATHENA_URL!,\r\n * apiKey: process.env.ATHENA_API_KEY!,\r\n * client: \"my-app\",\r\n * }),\r\n * });\r\n * ```\r\n */\r\nexport const athenaAdapter = (\r\n config: AthenaAdapterConfig,\r\n): AdapterFactory<BetterAuthOptions> => {\r\n let dbClient: any | null = null;\r\n let lastDbConfigVersion = -1;\r\n\r\n const shouldUseFixedConfig =\r\n typeof config.url === \"string\" &&\r\n config.url.length > 0 &&\r\n typeof config.apiKey === \"string\" &&\r\n config.apiKey.length > 0;\r\n\r\n function ensureDbClient(): any {\r\n if (shouldUseFixedConfig) {\r\n if (!dbClient) {\r\n dbClient = createClient(config.url!, config.apiKey!, {\r\n client: config.client,\r\n ...(config.headers && { headers: config.headers }),\r\n } as any);\r\n }\r\n return dbClient;\r\n }\r\n\r\n const { config: globalConfig, version } = getAthenaGlobalConfig({\r\n configPath: config.configPath,\r\n watch: config.watchConfig ?? true,\r\n });\r\n\r\n const url = config.url ?? globalConfig.athena.url;\r\n const apiKey = config.apiKey ?? globalConfig.athena.apiKey;\r\n const client = config.client ?? globalConfig.athena.client;\r\n\r\n if (!url || !apiKey) {\r\n throw new Error(\r\n `[AthenaAdapter] Missing Athena connection details. Set both 'athena.url' and 'athena.apiKey' in config.yaml (or pass 'url'/'apiKey' to athenaAdapter).`,\r\n );\r\n }\r\n\r\n if (!dbClient || version !== lastDbConfigVersion) {\r\n dbClient = createClient(url, apiKey, {\r\n client,\r\n ...(config.headers && { headers: config.headers }),\r\n } as any);\r\n lastDbConfigVersion = version;\r\n }\r\n\r\n return dbClient;\r\n }\r\n\r\n const deps = { ensureDbClient, headers: config.headers };\r\n\r\n return createAdapterFactory({\r\n config: {\r\n adapterId: \"athena\",\r\n adapterName: \"Athena Adapter\",\r\n usePlural: config.usePlural ?? false,\r\n debugLogs: config.debugLogs ?? false,\r\n supportsJSON: true,\r\n supportsDates: true,\r\n supportsBooleans: true,\r\n supportsNumericIds: true,\r\n supportsUUIDs: true,\r\n supportsArrays: true,\r\n },\r\n adapter: () => {\r\n return {\r\n create: createMethod(deps),\r\n update: updateMethod(deps),\r\n updateMany: updateManyMethod(deps),\r\n delete: deleteMethod(deps),\r\n deleteMany: deleteManyMethod(deps),\r\n findOne: findOneMethod(deps),\r\n findMany: findManyMethod(deps),\r\n count: countMethod(deps),\r\n options: {\r\n debugLogs: config.debugLogs ?? false,\r\n \r\n },\r\n };\r\n },\r\n });\r\n};\r\n\r\n// For testing purposes, we export the internal config function to allow resetting the cached client between tests.\r\nexport { getAthenaGlobalConfig } from \"./config\";\r\n","import fs from \"node:fs\";\r\nimport path from \"node:path\";\r\nimport YAML from \"yaml\";\r\n\r\nexport type AthenaGlobalConfig = {\r\n athena: {\r\n url: string;\r\n apiKey: string;\r\n client?: string;\r\n };\r\n};\r\n\r\n// Defaults written to `config.yaml` if it doesn't exist.\r\n// These values are intentionally placeholders; the adapter will throw if\r\n// `url`/`apiKey` are still unset when used.\r\nexport const defaultAthenaGlobalConfig: AthenaGlobalConfig = {\r\n athena: {\r\n url: \"https://mirror3.athena-db.com\",\r\n apiKey: \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoiYXV0aGVudGljYXRlZCIsImVtYWlsIjoiZmxvcmlzQHh5bGV4LmFpIiwiZXhwIjoyNDk3MDMzNjY2fQ.LdPqTGaFq5pTokW1DA81WFjmG4nReJCOSKr3mFtXNoA\",\r\n client: \"athena_logging\",\r\n },\r\n};\r\n\r\nexport const DEFAULT_CONFIG_FILENAME = \"config.yaml\";\r\n\r\nfunction resolveConfigPath(configPath?: string): string {\r\n if (configPath) return path.resolve(configPath);\r\n return path.resolve(process.cwd(), DEFAULT_CONFIG_FILENAME);\r\n}\r\n\r\nlet cached: AthenaGlobalConfig | null = null;\r\nlet cachedConfigPath: string | null = null;\r\nlet version = 0;\r\n\r\nlet watcher: fs.FSWatcher | null = null;\r\n\r\nfunction isObject(value: unknown): value is Record<string, unknown> {\r\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\r\n}\r\n\r\nfunction deepMerge<T extends Record<string, unknown>>(\r\n base: T,\r\n partial: unknown,\r\n): T {\r\n if (!isObject(partial)) return base;\r\n const out: Record<string, unknown> = { ...base };\r\n for (const [k, v] of Object.entries(partial)) {\r\n if (v && isObject(v) && isObject(out[k])) {\r\n out[k] = deepMerge(out[k] as Record<string, unknown>, v);\r\n } else {\r\n out[k] = v;\r\n }\r\n }\r\n return out as T;\r\n}\r\n\r\nfunction ensureConfigFile(configPath: string): void {\r\n const dir = path.dirname(configPath);\r\n if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });\r\n\r\n if (!fs.existsSync(configPath)) {\r\n const yaml = YAML.stringify(defaultAthenaGlobalConfig);\r\n fs.writeFileSync(configPath, yaml, \"utf-8\");\r\n }\r\n}\r\n\r\nfunction readConfigFromDisk(configPath: string): AthenaGlobalConfig {\r\n ensureConfigFile(configPath);\r\n const raw = fs.readFileSync(configPath, \"utf-8\");\r\n const parsed = YAML.parse(raw) as unknown;\r\n return deepMerge(defaultAthenaGlobalConfig, parsed);\r\n}\r\n\r\nfunction startWatcher(configPath: string): void {\r\n // Avoid multiple watchers when multiple adapter instances are created.\r\n if (cachedConfigPath !== null && cachedConfigPath !== configPath && watcher) {\r\n try {\r\n watcher.close();\r\n } catch {\r\n // ignore\r\n }\r\n watcher = null;\r\n }\r\n if (watcher || cachedConfigPath === configPath) return;\r\n\r\n try {\r\n watcher = fs.watch(configPath, { persistent: false }, (event) => {\r\n if (event !== \"change\" && event !== \"rename\") return;\r\n try {\r\n cached = readConfigFromDisk(configPath);\r\n version += 1;\r\n } catch {\r\n // Keep last known good config if reload fails.\r\n }\r\n });\r\n cachedConfigPath = configPath;\r\n } catch {\r\n // If watching isn't supported in the environment, just run without it.\r\n }\r\n}\r\n\r\nexport function getAthenaGlobalConfig(options?: {\r\n configPath?: string;\r\n watch?: boolean;\r\n}): { config: AthenaGlobalConfig; version: number } {\r\n const configPath = resolveConfigPath(options?.configPath);\r\n const shouldWatch = options?.watch ?? true;\r\n\r\n if (!cached || cachedConfigPath !== configPath) {\r\n cached = readConfigFromDisk(configPath);\r\n cachedConfigPath = configPath;\r\n version += 1;\r\n }\r\n\r\n if (shouldWatch) startWatcher(configPath);\r\n\r\n return { config: cached, version };\r\n}\r\n","/**\r\n * Shared helpers and types for the Athena adapter.\r\n */\r\n\r\nexport function toSnakeCase(key: string): string {\r\n return key\r\n .replace(/([a-z0-9])([A-Z])/g, \"$1_$2\")\r\n .replace(/__/g, \"_\")\r\n .toLowerCase();\r\n}\r\n\r\nexport function toCamelCase(key: string): string {\r\n return key.replace(/_([a-z0-9])/g, (_, ch: string) => ch.toUpperCase());\r\n}\r\n\r\nexport function hasUppercase(key: string): boolean {\r\n return /[A-Z]/.test(key);\r\n}\r\n\r\nexport function mapKeys<T extends Record<string, unknown>>(\r\n obj: T,\r\n mapKey: (k: string) => string,\r\n): Record<string, unknown> {\r\n const out: Record<string, unknown> = {};\r\n for (const [k, v] of Object.entries(obj)) out[mapKey(k)] = v;\r\n return out;\r\n}\r\n\r\nexport function mapRowToBetterAuth<T>(row: T): T {\r\n if (!row || typeof row !== \"object\") return row;\r\n if (Array.isArray(row)) return row.map(mapRowToBetterAuth) as unknown as T;\r\n return mapKeys(row as Record<string, unknown>, toCamelCase) as T;\r\n}\r\n\r\nexport function isLikelyIsoDateString(value: string): boolean {\r\n if (!/^\\d{4}-\\d{2}-\\d{2}T/.test(value)) return false;\r\n const ms = Date.parse(value);\r\n return Number.isFinite(ms);\r\n}\r\n\r\nexport function isTimestampKey(key: string): boolean {\r\n return key.endsWith(\"At\") || key.endsWith(\"_at\") || key === \"expires\";\r\n}\r\n\r\nexport function coerceDateFields<T extends Record<string, unknown>>(data: T): T {\r\n const out: Record<string, unknown> = { ...data };\r\n for (const [key, val] of Object.entries(out)) {\r\n if (val == null) continue;\r\n if (\r\n typeof val === \"string\" &&\r\n isTimestampKey(key) &&\r\n isLikelyIsoDateString(val)\r\n ) {\r\n out[key] = new Date(val);\r\n }\r\n }\r\n return out as T;\r\n}\r\n\r\nexport function toDbRecord<T extends Record<string, unknown>>(\r\n data: T,\r\n): Record<string, unknown> {\r\n const withDbKeys = mapKeys(data, (k) =>\r\n hasUppercase(k) ? toSnakeCase(k) : k,\r\n );\r\n return coerceDateFields(withDbKeys);\r\n}\r\n\r\nexport type AthenaFilterBuilder = {\r\n eq(col: string, val: unknown): AthenaFilterBuilder;\r\n neq(col: string, val: unknown): AthenaFilterBuilder;\r\n gt(col: string, val: unknown): AthenaFilterBuilder;\r\n gte(col: string, val: unknown): AthenaFilterBuilder;\r\n lt(col: string, val: unknown): AthenaFilterBuilder;\r\n lte(col: string, val: unknown): AthenaFilterBuilder;\r\n in(col: string, vals: unknown[]): AthenaFilterBuilder;\r\n not(col: string, op?: string, val?: unknown): AthenaFilterBuilder;\r\n like(col: string, val: string): AthenaFilterBuilder;\r\n delete?(): { select(): Promise<{ data: unknown; error: unknown }> };\r\n select?(columns?: string): Promise<{ data: unknown; error: unknown }> | { select(): Promise<{ data: unknown; error: unknown }> };\r\n};\r\n\r\nexport type WhereClause = { field: string; operator: string; value: unknown };\r\n\r\nconst defaultColumnMapper = (col: string) =>\r\n hasUppercase(col) ? toSnakeCase(col) : col;\r\n\r\nexport function applyWhere(\r\n builder: AthenaFilterBuilder,\r\n field: string,\r\n operator: string,\r\n value: unknown,\r\n columnMapper: (col: string) => string = defaultColumnMapper,\r\n): AthenaFilterBuilder {\r\n const dbField = columnMapper(field);\r\n switch (operator) {\r\n case \"eq\":\r\n return builder.eq(dbField, value);\r\n case \"ne\":\r\n return builder.neq(dbField, value);\r\n case \"gt\":\r\n return builder.gt(dbField, value);\r\n case \"gte\":\r\n return builder.gte(dbField, value);\r\n case \"lt\":\r\n return builder.lt(dbField, value);\r\n case \"lte\":\r\n return builder.lte(dbField, value);\r\n case \"in\":\r\n return builder.in(dbField, value as unknown[]);\r\n case \"not_in\":\r\n return builder.not(dbField, \"in\", value);\r\n case \"contains\":\r\n return builder.like(dbField, `%${value}%`);\r\n case \"starts_with\":\r\n return builder.like(dbField, `${value}%`);\r\n case \"ends_with\":\r\n return builder.like(dbField, `%${value}`);\r\n default:\r\n return builder.eq(dbField, value);\r\n }\r\n}\r\n\r\nexport function isMissingColumnError(error: unknown): boolean {\r\n const msg = String(error ?? \"\");\r\n return (\r\n msg.includes(\"specified column does not exist\") ||\r\n msg.includes(\"column does not exist\")\r\n );\r\n}\r\n\r\n/** True when the Athena gateway returns a success message in the error field (treat as success). */\r\nexport function isSuccessMessageInError(error: unknown): boolean {\r\n const msg = String(error ?? \"\").toLowerCase();\r\n return (\r\n msg === \"data inserted successfully\" ||\r\n msg === \"data updated successfully\" ||\r\n msg === \"data deleted successfully\"\r\n );\r\n}\r\n\r\nexport function snakeMapper(col: string): string {\r\n return hasUppercase(col) ? toSnakeCase(col) : col;\r\n}\r\n\r\nexport function identityMapper(col: string): string {\r\n return col;\r\n}\r\n\r\n/** Get value from row by field name (camelCase or snake_case). */\r\nfunction getRowValue(row: Record<string, unknown>, field: string): unknown {\r\n if (Object.prototype.hasOwnProperty.call(row, field)) return row[field];\r\n const snake = hasUppercase(field) ? toSnakeCase(field) : field;\r\n return row[snake];\r\n}\r\n\r\n/**\r\n * Filter rows in-memory by where clauses (fallback when gateway does not apply filters).\r\n * Supports eq, ne, in, not_in; row keys may be camelCase or snake_case.\r\n */\r\nexport function filterRowsByWhere(\r\n rows: Record<string, unknown>[],\r\n where: WhereClause[],\r\n): Record<string, unknown>[] {\r\n if (!where.length) return rows;\r\n return rows.filter((row) => {\r\n for (const { field, operator, value } of where) {\r\n const rowVal = getRowValue(row, field);\r\n switch (operator) {\r\n case \"eq\":\r\n if (rowVal !== value) return false;\r\n break;\r\n case \"ne\":\r\n if (rowVal === value) return false;\r\n break;\r\n case \"in\":\r\n if (!Array.isArray(value) || !value.includes(rowVal)) return false;\r\n break;\r\n case \"not_in\":\r\n if (Array.isArray(value) && value.includes(rowVal)) return false;\r\n break;\r\n default:\r\n if (rowVal !== value) return false;\r\n }\r\n }\r\n return true;\r\n });\r\n}\r\n","import { toDbRecord, mapRowToBetterAuth, isSuccessMessageInError } from \"../utils\";\r\n\r\nexport type CreateDeps = {\r\n ensureDbClient: () => any;\r\n};\r\n\r\nexport function createMethod(deps: CreateDeps) {\r\n const { ensureDbClient } = deps;\r\n\r\n return async function create<T extends Record<string, unknown>>({\r\n model,\r\n data,\r\n }: {\r\n model: string;\r\n data: T;\r\n select?: string[];\r\n }) {\r\n const db = ensureDbClient();\r\n const insertData = toDbRecord(data);\r\n const { data: result, error } = await db\r\n .from(model)\r\n .insert(insertData)\r\n .select();\r\n\r\n if (error && !isSuccessMessageInError(error)) {\r\n throw new Error(`[AthenaAdapter] create on \"${model}\" failed: ${error}`);\r\n }\r\n\r\n const row = Array.isArray(result) ? result[0] : result;\r\n return mapRowToBetterAuth((row ?? insertData) as T);\r\n };\r\n}\r\n","import type { WhereClause, AthenaFilterBuilder } from \"../utils\";\r\nimport {\r\n toDbRecord,\r\n mapRowToBetterAuth,\r\n applyWhere,\r\n isSuccessMessageInError,\r\n} from \"../utils\";\r\n\r\nexport type UpdateDeps = {\r\n ensureDbClient: () => any;\r\n};\r\n\r\nexport function updateMethod(deps: UpdateDeps) {\r\n const { ensureDbClient } = deps;\r\n\r\n return async function update<T>({\r\n model,\r\n where,\r\n update,\r\n }: {\r\n model: string;\r\n where: WhereClause[];\r\n update: T;\r\n }) {\r\n const db = ensureDbClient();\r\n const updateData = toDbRecord(update as Record<string, unknown>);\r\n const debugUpdates = process?.env?.ATHENA_ADAPTER_DEBUG_UPDATES === \"1\";\r\n const debugLog = (event: string, extra?: Record<string, unknown>) => {\r\n if (!debugUpdates) return;\r\n console.info(\"[AthenaAdapter][update]\", {\r\n event,\r\n model,\r\n ...extra,\r\n });\r\n };\r\n const build = (useRetryShape: boolean) => {\r\n // Primary shape: modern gateway/client combinations accept plain update values.\r\n if (!useRetryShape) {\r\n let b = db.from(model).update(updateData as any) as AthenaFilterBuilder;\r\n for (const clause of where) {\r\n b = applyWhere(b, clause.field, clause.operator, clause.value);\r\n }\r\n return b;\r\n }\r\n\r\n // Retry shape: explicit wrappers for gateways expecting data/set.\r\n let b = db\r\n .from(model)\r\n .update(updateData as any, {\r\n updateBody: { data: updateData, set: updateData },\r\n } as any) as AthenaFilterBuilder;\r\n for (const clause of where) {\r\n b = applyWhere(b, clause.field, clause.operator, clause.value);\r\n }\r\n return b;\r\n };\r\n\r\n const run = async (b: AthenaFilterBuilder) => {\r\n const { data: result, error } = await (b as any).select();\r\n return { result, error };\r\n };\r\n\r\n const first = await run(build(false));\r\n if (first.error && !isSuccessMessageInError(first.error)) {\r\n debugLog(\"primary_failed\", { error: String(first.error) });\r\n const msg = String(first.error);\r\n if (msg.toLowerCase().includes(\"update payload required\")) {\r\n const retry = await run(build(true));\r\n if (retry.error && !isSuccessMessageInError(retry.error)) {\r\n debugLog(\"retry_failed\", { error: String(retry.error) });\r\n throw new Error(\r\n `[AthenaAdapter] update on \"${model}\" failed: ${retry.error}`,\r\n );\r\n }\r\n debugLog(\"retry_succeeded\", { shape: \"updateBody(data/set)\" });\r\n const row = Array.isArray(retry.result)\r\n ? (retry.result[0] as unknown)\r\n : (retry.result as unknown);\r\n return (row ? mapRowToBetterAuth(row as T) : null) as T | null;\r\n }\r\n\r\n throw new Error(`[AthenaAdapter] update on \"${model}\" failed: ${first.error}`);\r\n }\r\n\r\n debugLog(\"primary_succeeded\", { shape: \"plain\" });\r\n\r\n const row = Array.isArray(first.result)\r\n ? (first.result[0] as unknown)\r\n : (first.result as unknown);\r\n return (row ? mapRowToBetterAuth(row as T) : null) as T | null;\r\n };\r\n}\r\n","import type { WhereClause, AthenaFilterBuilder } from \"../utils\";\r\nimport { toDbRecord, applyWhere, isSuccessMessageInError } from \"../utils\";\r\n\r\nexport type UpdateManyDeps = {\r\n ensureDbClient: () => any;\r\n};\r\n\r\nexport function updateManyMethod(deps: UpdateManyDeps) {\r\n const { ensureDbClient } = deps;\r\n\r\n return async function updateMany({\r\n model,\r\n where,\r\n update,\r\n }: {\r\n model: string;\r\n where: WhereClause[];\r\n update: Record<string, unknown>;\r\n }) {\r\n const db = ensureDbClient();\r\n const updateData = toDbRecord(update);\r\n const debugUpdates = process.env.ATHENA_ADAPTER_DEBUG_UPDATES === \"1\";\r\n const debugLog = (event: string, extra?: Record<string, unknown>) => {\r\n if (!debugUpdates) return;\r\n console.info(\"[AthenaAdapter][updateMany]\", {\r\n event,\r\n model,\r\n ...extra,\r\n });\r\n };\r\n const build = (useRetryShape: boolean) => {\r\n if (!useRetryShape) {\r\n let b = db.from(model).update(updateData as any) as AthenaFilterBuilder;\r\n for (const clause of where) {\r\n b = applyWhere(b, clause.field, clause.operator, clause.value);\r\n }\r\n return b;\r\n }\r\n\r\n let b = db\r\n .from(model)\r\n .update(updateData as any, {\r\n updateBody: { data: updateData, set: updateData },\r\n } as any) as AthenaFilterBuilder;\r\n for (const clause of where) {\r\n b = applyWhere(b, clause.field, clause.operator, clause.value);\r\n }\r\n return b;\r\n };\r\n\r\n const run = async (b: AthenaFilterBuilder) => {\r\n const { data: result, error } = await (b as any).select();\r\n return { result, error };\r\n };\r\n\r\n const first = await run(build(false));\r\n if (first.error && !isSuccessMessageInError(first.error)) {\r\n debugLog(\"primary_failed\", { error: String(first.error) });\r\n const msg = String(first.error);\r\n if (msg.toLowerCase().includes(\"update payload required\")) {\r\n const retry = await run(build(true));\r\n if (retry.error && !isSuccessMessageInError(retry.error)) {\r\n debugLog(\"retry_failed\", { error: String(retry.error) });\r\n throw new Error(\r\n `[AthenaAdapter] updateMany on \"${model}\" failed: ${retry.error}`,\r\n );\r\n }\r\n debugLog(\"retry_succeeded\", { shape: \"updateBody(data/set)\" });\r\n return Array.isArray(retry.result) ? retry.result.length : retry.result ? 1 : 0;\r\n }\r\n\r\n throw new Error(\r\n `[AthenaAdapter] updateMany on \"${model}\" failed: ${first.error}`,\r\n );\r\n }\r\n\r\n debugLog(\"primary_succeeded\", { shape: \"plain\" });\r\n\r\n return Array.isArray(first.result) ? first.result.length : first.result ? 1 : 0;\r\n };\r\n}\r\n","import type { WhereClause, AthenaFilterBuilder } from \"../utils\";\r\nimport { applyWhere, isSuccessMessageInError } from \"../utils\";\r\n\r\nexport type DeleteDeps = {\r\n ensureDbClient: () => any;\r\n headers?: Record<string, string>;\r\n};\r\n\r\nexport function deleteMethod(deps: DeleteDeps) {\r\n const { ensureDbClient, headers } = deps;\r\n\r\n return async function del({\r\n model,\r\n where,\r\n }: {\r\n model: string;\r\n where: WhereClause[];\r\n }) {\r\n const db = ensureDbClient();\r\n let builder = db.from(model) as AthenaFilterBuilder;\r\n\r\n for (const clause of where) {\r\n builder = applyWhere(\r\n builder,\r\n clause.field,\r\n clause.operator,\r\n clause.value,\r\n );\r\n }\r\n\r\n const { error } = await (builder as any).delete(\r\n headers ? ({ headers } as any) : undefined,\r\n );\r\n\r\n if (error && !isSuccessMessageInError(error)) {\r\n throw new Error(\r\n `[AthenaAdapter] delete on \"${model}\" failed: ${error}`,\r\n );\r\n }\r\n };\r\n}\r\n","import type { WhereClause, AthenaFilterBuilder } from \"../utils\";\r\nimport { applyWhere, isSuccessMessageInError } from \"../utils\";\r\n\r\nexport type DeleteManyDeps = {\r\n ensureDbClient: () => any;\r\n headers?: Record<string, string>;\r\n};\r\n\r\nexport function deleteManyMethod(deps: DeleteManyDeps) {\r\n const { ensureDbClient, headers } = deps;\r\n\r\n return async function deleteMany({\r\n model,\r\n where,\r\n }: {\r\n model: string;\r\n where: WhereClause[];\r\n }) {\r\n const db = ensureDbClient();\r\n const mainBuilder = db.from(model) as AthenaFilterBuilder;\r\n let builder = mainBuilder;\r\n\r\n for (const clause of where) {\r\n builder = applyWhere(\r\n builder,\r\n clause.field,\r\n clause.operator,\r\n clause.value,\r\n );\r\n }\r\n\r\n const { data: result, error } = await (builder as any).delete(\r\n headers ? ({ headers } as any) : undefined,\r\n ).select();\r\n\r\n if (error && !isSuccessMessageInError(error)) {\r\n throw new Error(\r\n `[AthenaAdapter] deleteMany on \"${model}\" failed: ${error}`,\r\n );\r\n }\r\n\r\n const deletedCount = Array.isArray(result) ? result.length : result ? 1 : 0;\r\n // Fallback: if the live gateway doesn't apply `in` conditions correctly,\r\n // delete rows one-by-one so counts are stable for e2e tests.\r\n const inClause = where.find(\r\n (c) => c.operator === \"in\" && c.value != null,\r\n );\r\n if (\r\n inClause &&\r\n Array.isArray(inClause.value) &&\r\n deletedCount < inClause.value.length\r\n ) {\r\n let n = 0;\r\n for (const v of inClause.value) {\r\n const b = db.from(model);\r\n const filtered = applyWhere(\r\n b as any,\r\n inClause.field,\r\n \"eq\",\r\n v,\r\n );\r\n const { data: rowData, error: rowErr } = await (filtered as any).delete(\r\n headers ? ({ headers } as any) : undefined,\r\n ).select();\r\n if (rowErr && isSuccessMessageInError(rowErr)) continue;\r\n n += Array.isArray(rowData) ? rowData.length : rowData ? 1 : 0;\r\n }\r\n return n;\r\n }\r\n\r\n return deletedCount;\r\n };\r\n}\r\n","import type { WhereClause } from \"../utils\";\r\nimport {\r\n applyWhere,\r\n mapRowToBetterAuth,\r\n isMissingColumnError,\r\n snakeMapper,\r\n identityMapper,\r\n filterRowsByWhere,\r\n} from \"../utils\";\r\n\r\nexport type FindOneDeps = {\r\n ensureDbClient: () => any;\r\n};\r\n\r\nexport function findOneMethod(deps: FindOneDeps) {\r\n const { ensureDbClient } = deps;\r\n\r\n return async function findOne<T>({\r\n model,\r\n where,\r\n select,\r\n }: {\r\n model: string;\r\n where: WhereClause[];\r\n select?: string[];\r\n join?: unknown;\r\n }) {\r\n const db = ensureDbClient();\r\n\r\n const run = async (columnMapper: (col: string) => string) => {\r\n const columns =\r\n select && select.length > 0\r\n ? select.map((c) => columnMapper(c)).join(\", \")\r\n : undefined;\r\n\r\n let builder = db.from(model).select(columns);\r\n\r\n for (const clause of where) {\r\n builder = applyWhere(\r\n builder,\r\n clause.field,\r\n clause.operator,\r\n clause.value,\r\n columnMapper,\r\n );\r\n }\r\n\r\n const { data: result, error } = await builder.limit(1);\r\n return { result, error };\r\n };\r\n\r\n const first = await run(snakeMapper);\r\n if (first.error) {\r\n if (isMissingColumnError(first.error)) {\r\n const retry = await run(identityMapper);\r\n if (retry.error) {\r\n throw new Error(\r\n `[AthenaAdapter] findOne on \"${model}\" failed: ${retry.error}`,\r\n );\r\n }\r\n\r\n const rows = Array.isArray(retry.result)\r\n ? retry.result\r\n : retry.result\r\n ? [retry.result]\r\n : [];\r\n const row = rows[0] ?? null;\r\n return (row ? mapRowToBetterAuth(row as T) : null) as T | null;\r\n }\r\n\r\n throw new Error(\r\n `[AthenaAdapter] findOne on \"${model}\" failed: ${first.error}`,\r\n );\r\n }\r\n\r\n const rows = Array.isArray(first.result)\r\n ? first.result\r\n : first.result\r\n ? [first.result]\r\n : [];\r\n const row = rows[0] ?? null;\r\n if (!row) return null;\r\n\r\n const mapped = mapRowToBetterAuth(row as T) as T;\r\n const filtered = filterRowsByWhere(\r\n [mapped as unknown as Record<string, unknown>],\r\n where,\r\n );\r\n return (filtered[0] ? mapped : null) as T | null;\r\n };\r\n}\r\n","import type { WhereClause } from \"../utils\";\r\nimport {\r\n applyWhere,\r\n mapRowToBetterAuth,\r\n isMissingColumnError,\r\n snakeMapper,\r\n identityMapper,\r\n filterRowsByWhere,\r\n} from \"../utils\";\r\n\r\nexport type FindManyDeps = {\r\n ensureDbClient: () => any;\r\n};\r\n\r\nexport function findManyMethod(deps: FindManyDeps) {\r\n const { ensureDbClient } = deps;\r\n\r\n const isTransientGatewayError = (error: unknown): boolean => {\r\n const message = String(error ?? \"\").toLowerCase();\r\n return (\r\n message.includes(\"application failed to respond\") ||\r\n message.includes(\"timeout\") ||\r\n message.includes(\"timed out\") ||\r\n message.includes(\"gateway timeout\") ||\r\n message.includes(\"econnreset\") ||\r\n message.includes(\"connection reset\")\r\n );\r\n };\r\n\r\n return async function findMany<T>({\r\n model,\r\n where,\r\n limit,\r\n sortBy,\r\n offset,\r\n select,\r\n }: {\r\n model: string;\r\n where?: WhereClause[];\r\n limit: number;\r\n select?: string[];\r\n sortBy?: { field: string; direction: \"asc\" | \"desc\" };\r\n offset?: number;\r\n join?: unknown;\r\n }) {\r\n const db = ensureDbClient();\r\n\r\n const run = async (\r\n columnMapper: (col: string) => string,\r\n opts?: { skipWhere?: boolean; limitOverride?: number; offsetOverride?: number },\r\n ) => {\r\n const columns =\r\n select && select.length > 0\r\n ? select.map((c) => columnMapper(c)).join(\", \")\r\n : undefined;\r\n\r\n let builder = db.from(model).select(columns);\r\n\r\n if (!opts?.skipWhere && where) {\r\n for (const clause of where) {\r\n builder = applyWhere(\r\n builder,\r\n clause.field,\r\n clause.operator,\r\n clause.value,\r\n columnMapper,\r\n );\r\n }\r\n }\r\n\r\n const effectiveLimit = opts?.limitOverride ?? limit;\r\n const effectiveOffset = opts?.offsetOverride ?? offset;\r\n\r\n if (effectiveLimit !== undefined) {\r\n builder = builder.limit(effectiveLimit);\r\n }\r\n\r\n if (effectiveOffset !== undefined) {\r\n builder = builder.offset(effectiveOffset);\r\n }\r\n\r\n const { data: result, error } = await builder;\r\n return { result, error };\r\n };\r\n\r\n let first = await run(snakeMapper);\r\n if (first.error && isTransientGatewayError(first.error)) {\r\n const retry = await run(snakeMapper);\r\n if (!retry.error) first = retry;\r\n }\r\n\r\n const pickRows = (res: unknown) =>\r\n (Array.isArray(res) ? res : []) as Record<string, unknown>[];\r\n\r\n const applySort = (rows: T[]) => {\r\n if (!sortBy) return rows;\r\n const sortField = sortBy.field;\r\n rows.sort((a, b) => {\r\n const aVal = (a as Record<string, unknown>)[sortField];\r\n const bVal = (b as Record<string, unknown>)[sortField];\r\n if (aVal == null && bVal == null) return 0;\r\n if (aVal == null) return sortBy.direction === \"asc\" ? -1 : 1;\r\n if (bVal == null) return sortBy.direction === \"asc\" ? 1 : -1;\r\n const cmp =\r\n typeof aVal === \"string\" && typeof bVal === \"string\"\r\n ? aVal.localeCompare(bVal)\r\n : aVal < bVal\r\n ? -1\r\n : aVal > bVal\r\n ? 1\r\n : 0;\r\n return sortBy.direction === \"asc\" ? cmp : -cmp;\r\n });\r\n return rows;\r\n };\r\n\r\n const mapAndSort = (rows: Record<string, unknown>[]) => {\r\n const betterAuthRows = rows.map((r) => mapRowToBetterAuth(r)) as unknown as T[];\r\n\r\n if (!where?.length) return applySort(betterAuthRows);\r\n\r\n const filtered = filterRowsByWhere(\r\n betterAuthRows as unknown as Record<string, unknown>[],\r\n where,\r\n ) as unknown as T[];\r\n\r\n // If filtering changed the row set, the gateway likely ignored `where`\r\n // (or applied it before limiting/offset). In that case, re-apply sorting\r\n // and slice using the requested offset/limit.\r\n if (filtered.length !== betterAuthRows.length) {\r\n const off = offset ?? 0;\r\n const end = limit !== undefined ? off + limit : undefined;\r\n return applySort(filtered).slice(off, end);\r\n }\r\n\r\n return applySort(filtered);\r\n };\r\n\r\n const postFilterAndSlice = (rows: Record<string, unknown>[]) => {\r\n const mappedSorted = mapAndSort(rows);\r\n const off = offset ?? 0;\r\n const end = limit !== undefined ? off + limit : undefined;\r\n return mappedSorted.slice(off, end);\r\n };\r\n\r\n if (first.error) {\r\n if (isMissingColumnError(first.error)) {\r\n const retry = await run(identityMapper);\r\n if (retry.error) {\r\n throw new Error(\r\n `[AthenaAdapter] findMany on \"${model}\" failed: ${retry.error}`,\r\n );\r\n }\r\n const retryRows = pickRows(retry.result);\r\n // Decisive fallback: if gateway-side `where` yields empty/insufficient rows,\r\n // fetch a broader candidate set and apply `where`/sort/offset/limit in-memory.\r\n if (where?.length) {\r\n const broad = await run(identityMapper, {\r\n skipWhere: true,\r\n limitOverride: Math.max((offset ?? 0) + (limit ?? 0) + 500, 5000),\r\n offsetOverride: 0,\r\n });\r\n if (!broad.error) return postFilterAndSlice(pickRows(broad.result));\r\n }\r\n return mapAndSort(retryRows);\r\n }\r\n\r\n throw new Error(\r\n `[AthenaAdapter] findMany on \"${model}\" failed: ${first.error}`,\r\n );\r\n }\r\n\r\n const firstRows = pickRows(first.result);\r\n if (where?.length) {\r\n const broad = await run(snakeMapper, {\r\n skipWhere: true,\r\n limitOverride: Math.max((offset ?? 0) + (limit ?? 0) + 500, 5000),\r\n offsetOverride: 0,\r\n });\r\n if (!broad.error) return postFilterAndSlice(pickRows(broad.result));\r\n }\r\n return mapAndSort(firstRows);\r\n };\r\n}\r\n","import type { WhereClause } from \"../utils\";\r\nimport {\r\n applyWhere,\r\n isMissingColumnError,\r\n snakeMapper,\r\n identityMapper,\r\n} from \"../utils\";\r\n\r\nexport type CountDeps = {\r\n ensureDbClient: () => any;\r\n};\r\n\r\nexport function countMethod(deps: CountDeps) {\r\n const { ensureDbClient } = deps;\r\n\r\n return async function count({\r\n model,\r\n where,\r\n }: {\r\n model: string;\r\n where?: WhereClause[];\r\n }) {\r\n const db = ensureDbClient();\r\n\r\n const run = async (columnMapper: (col: string) => string) => {\r\n let builder = db.from(model).select();\r\n\r\n if (where) {\r\n for (const clause of where) {\r\n builder = applyWhere(\r\n builder,\r\n clause.field,\r\n clause.operator,\r\n clause.value,\r\n columnMapper,\r\n );\r\n }\r\n }\r\n\r\n const { data: result, error } = await builder;\r\n return { result, error };\r\n };\r\n\r\n const first = await run(snakeMapper);\r\n if (first.error) {\r\n if (isMissingColumnError(first.error)) {\r\n const retry = await run(identityMapper);\r\n if (retry.error) {\r\n throw new Error(\r\n `[AthenaAdapter] count on \"${model}\" failed: ${retry.error}`,\r\n );\r\n }\r\n return Array.isArray(retry.result) ? retry.result.length : 0;\r\n }\r\n throw new Error(\r\n `[AthenaAdapter] count on \"${model}\" failed: ${first.error}`,\r\n );\r\n }\r\n\r\n return Array.isArray(first.result) ? first.result.length : 0;\r\n };\r\n}\r\n"],"mappings":"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","names":["path","fs","YAML","b","row","b","rows","row","version"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/config.ts","../src/utils.ts","../src/methods/create.ts","../src/methods/update.ts","../src/methods/update-many.ts","../src/methods/delete.ts","../src/methods/delete-many.ts","../src/methods/find-one.ts","../src/methods/find-many.ts","../src/methods/count.ts"],"sourcesContent":["import {\r\n createAdapterFactory,\r\n type AdapterFactory,\r\n type DBAdapterDebugLogOption,\r\n} from \"better-auth/adapters\";\r\nimport type { BetterAuthOptions } from \"better-auth\";\r\nimport { createClient } from \"@xylex-group/athena\";\r\nimport { getAthenaGlobalConfig } from \"./config\";\r\nimport { createMethod } from \"./methods/create\";\r\nimport { updateMethod } from \"./methods/update\";\r\nimport { updateManyMethod } from \"./methods/update-many\";\r\nimport { deleteMethod } from \"./methods/delete\";\r\nimport { deleteManyMethod } from \"./methods/delete-many\";\r\nimport { findOneMethod } from \"./methods/find-one\";\r\nimport { findManyMethod } from \"./methods/find-many\";\r\nimport { countMethod } from \"./methods/count\";\r\n\r\n/**\r\n * Configuration options for the Athena adapter.\r\n */\r\nexport interface AthenaAdapterConfig {\r\n /**\r\n * The URL of your Athena gateway.\r\n */\r\n url?: string;\r\n /**\r\n * The API key for authenticating with the Athena gateway.\r\n */\r\n apiKey?: string;\r\n /**\r\n * The client name sent in requests to the Athena gateway.\r\n */\r\n client?: string;\r\n\r\n /**\r\n * Optional override for the YAML config path.\r\n * Defaults to `./config.yaml` (resolved from `process.cwd()`).\r\n */\r\n configPath?: string;\r\n\r\n /**\r\n * When enabled, the adapter will reload `config.yaml` on changes.\r\n *\r\n * @default true\r\n */\r\n watchConfig?: boolean;\r\n /**\r\n * Helps you debug issues with the adapter.\r\n */\r\n debugLogs?: DBAdapterDebugLogOption;\r\n /**\r\n * If the table names in the schema are plural.\r\n *\r\n * @default false\r\n */\r\n usePlural?: boolean;\r\n\r\n /**\r\n * Optional headers sent with every request (e.g. `X-User-Id` if your gateway requires it for delete).\r\n */\r\n headers?: Record<string, string>;\r\n}\r\n\r\n/**\r\n * Create a Better-Auth database adapter backed by @xylex-group/athena.\r\n *\r\n * Column names are kept in snake_case as required by the Athena gateway.\r\n *\r\n * @example\r\n * ```ts\r\n * import { betterAuth } from \"better-auth\";\r\n * import { athenaAdapter } from \"better-auth-athena\";\r\n *\r\n * export const auth = betterAuth({\r\n * database: athenaAdapter({\r\n * url: process.env.ATHENA_URL!,\r\n * apiKey: process.env.ATHENA_API_KEY!,\r\n * client: \"my-app\",\r\n * }),\r\n * });\r\n * ```\r\n */\r\nexport const athenaAdapter = (\r\n config: AthenaAdapterConfig,\r\n): AdapterFactory<BetterAuthOptions> => {\r\n let dbClient: any | null = null;\r\n let lastDbConfigVersion = -1;\r\n\r\n const shouldUseFixedConfig =\r\n typeof config.url === \"string\" &&\r\n config.url.length > 0 &&\r\n typeof config.apiKey === \"string\" &&\r\n config.apiKey.length > 0;\r\n\r\n function ensureDbClient(): any {\r\n if (shouldUseFixedConfig) {\r\n if (!dbClient) {\r\n dbClient = createClient(config.url!, config.apiKey!, {\r\n client: config.client,\r\n ...(config.headers && { headers: config.headers }),\r\n } as any);\r\n }\r\n return dbClient;\r\n }\r\n\r\n const { config: globalConfig, version } = getAthenaGlobalConfig({\r\n configPath: config.configPath,\r\n watch: config.watchConfig ?? true,\r\n });\r\n\r\n const url = config.url ?? globalConfig.athena.url;\r\n const apiKey = config.apiKey ?? globalConfig.athena.apiKey;\r\n const client = config.client ?? globalConfig.athena.client;\r\n\r\n if (!url || !apiKey) {\r\n throw new Error(\r\n `[AthenaAdapter] Missing Athena connection details. Set both 'athena.url' and 'athena.apiKey' in config.yaml (or pass 'url'/'apiKey' to athenaAdapter).`,\r\n );\r\n }\r\n\r\n if (!dbClient || version !== lastDbConfigVersion) {\r\n dbClient = createClient(url, apiKey, {\r\n client,\r\n ...(config.headers && { headers: config.headers }),\r\n } as any);\r\n lastDbConfigVersion = version;\r\n }\r\n\r\n return dbClient;\r\n }\r\n\r\n function getConnectionConfig() {\r\n if (shouldUseFixedConfig) {\r\n return {\r\n url: config.url!,\r\n apiKey: config.apiKey!,\r\n client: config.client,\r\n headers: config.headers,\r\n };\r\n }\r\n const { config: globalConfig } = getAthenaGlobalConfig({\r\n configPath: config.configPath,\r\n watch: false,\r\n });\r\n return {\r\n url: config.url ?? globalConfig.athena.url,\r\n apiKey: config.apiKey ?? globalConfig.athena.apiKey,\r\n client: config.client ?? globalConfig.athena.client,\r\n headers: config.headers,\r\n };\r\n }\r\n\r\n const deps = { ensureDbClient, getConnectionConfig, headers: config.headers };\r\n\r\n return createAdapterFactory({\r\n config: {\r\n adapterId: \"athena\",\r\n adapterName: \"Athena Adapter\",\r\n usePlural: config.usePlural ?? false,\r\n debugLogs: config.debugLogs ?? false,\r\n supportsJSON: true,\r\n supportsDates: true,\r\n supportsBooleans: true,\r\n supportsNumericIds: true,\r\n supportsUUIDs: true,\r\n supportsArrays: true,\r\n },\r\n adapter: () => {\r\n return {\r\n create: createMethod(deps),\r\n update: updateMethod(deps),\r\n updateMany: updateManyMethod(deps),\r\n delete: deleteMethod(deps),\r\n deleteMany: deleteManyMethod(deps),\r\n findOne: findOneMethod(deps),\r\n findMany: findManyMethod(deps),\r\n count: countMethod(deps),\r\n options: {\r\n debugLogs: config.debugLogs ?? false,\r\n\r\n },\r\n };\r\n },\r\n });\r\n};\r\n\r\n// For testing purposes, we export the internal config function to allow resetting the cached client between tests.\r\nexport { getAthenaGlobalConfig } from \"./config\";\r\n","import fs from \"node:fs\";\r\nimport path from \"node:path\";\r\nimport YAML from \"yaml\";\r\n\r\nexport type AthenaGlobalConfig = {\r\n athena: {\r\n url: string;\r\n apiKey: string;\r\n client?: string;\r\n };\r\n};\r\n\r\n// Defaults written to `config.yaml` if it doesn't exist.\r\n// These values are intentionally placeholders; the adapter will throw if\r\n// `url`/`apiKey` are still unset when used.\r\nexport const defaultAthenaGlobalConfig: AthenaGlobalConfig = {\r\n athena: {\r\n url: \"https://mirror3.athena-db.com\",\r\n apiKey: \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoiYXV0aGVudGljYXRlZCIsImVtYWlsIjoiZmxvcmlzQHh5bGV4LmFpIiwiZXhwIjoyNDk3MDMzNjY2fQ.LdPqTGaFq5pTokW1DA81WFjmG4nReJCOSKr3mFtXNoA\",\r\n client: \"athena_logging\",\r\n },\r\n};\r\n\r\nexport const DEFAULT_CONFIG_FILENAME = \"config.yaml\";\r\n\r\nfunction resolveConfigPath(configPath?: string): string {\r\n if (configPath) return path.resolve(configPath);\r\n return path.resolve(process.cwd(), DEFAULT_CONFIG_FILENAME);\r\n}\r\n\r\nlet cached: AthenaGlobalConfig | null = null;\r\nlet cachedConfigPath: string | null = null;\r\nlet version = 0;\r\n\r\nlet watcher: fs.FSWatcher | null = null;\r\n\r\nfunction isObject(value: unknown): value is Record<string, unknown> {\r\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\r\n}\r\n\r\nfunction deepMerge<T extends Record<string, unknown>>(\r\n base: T,\r\n partial: unknown,\r\n): T {\r\n if (!isObject(partial)) return base;\r\n const out: Record<string, unknown> = { ...base };\r\n for (const [k, v] of Object.entries(partial)) {\r\n if (v && isObject(v) && isObject(out[k])) {\r\n out[k] = deepMerge(out[k] as Record<string, unknown>, v);\r\n } else {\r\n out[k] = v;\r\n }\r\n }\r\n return out as T;\r\n}\r\n\r\nfunction ensureConfigFile(configPath: string): void {\r\n const dir = path.dirname(configPath);\r\n if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });\r\n\r\n if (!fs.existsSync(configPath)) {\r\n const yaml = YAML.stringify(defaultAthenaGlobalConfig);\r\n fs.writeFileSync(configPath, yaml, \"utf-8\");\r\n }\r\n}\r\n\r\nfunction readConfigFromDisk(configPath: string): AthenaGlobalConfig {\r\n ensureConfigFile(configPath);\r\n const raw = fs.readFileSync(configPath, \"utf-8\");\r\n const parsed = YAML.parse(raw) as unknown;\r\n return deepMerge(defaultAthenaGlobalConfig, parsed);\r\n}\r\n\r\nfunction startWatcher(configPath: string): void {\r\n // Avoid multiple watchers when multiple adapter instances are created.\r\n if (cachedConfigPath !== null && cachedConfigPath !== configPath && watcher) {\r\n try {\r\n watcher.close();\r\n } catch {\r\n // ignore\r\n }\r\n watcher = null;\r\n }\r\n if (watcher || cachedConfigPath === configPath) return;\r\n\r\n try {\r\n watcher = fs.watch(configPath, { persistent: false }, (event) => {\r\n if (event !== \"change\" && event !== \"rename\") return;\r\n try {\r\n cached = readConfigFromDisk(configPath);\r\n version += 1;\r\n } catch {\r\n // Keep last known good config if reload fails.\r\n }\r\n });\r\n cachedConfigPath = configPath;\r\n } catch {\r\n // If watching isn't supported in the environment, just run without it.\r\n }\r\n}\r\n\r\nexport function getAthenaGlobalConfig(options?: {\r\n configPath?: string;\r\n watch?: boolean;\r\n}): { config: AthenaGlobalConfig; version: number } {\r\n const configPath = resolveConfigPath(options?.configPath);\r\n const shouldWatch = options?.watch ?? true;\r\n\r\n if (!cached || cachedConfigPath !== configPath) {\r\n cached = readConfigFromDisk(configPath);\r\n cachedConfigPath = configPath;\r\n version += 1;\r\n }\r\n\r\n if (shouldWatch) startWatcher(configPath);\r\n\r\n return { config: cached, version };\r\n}\r\n","/**\r\n * Shared helpers and types for the Athena adapter.\r\n */\r\n\r\nexport function toSnakeCase(key: string): string {\r\n return key\r\n .replace(/([a-z0-9])([A-Z])/g, \"$1_$2\")\r\n .replace(/__/g, \"_\")\r\n .toLowerCase();\r\n}\r\n\r\nexport function toCamelCase(key: string): string {\r\n return key.replace(/_([a-z0-9])/g, (_, ch: string) => ch.toUpperCase());\r\n}\r\n\r\nexport function hasUppercase(key: string): boolean {\r\n return /[A-Z]/.test(key);\r\n}\r\n\r\nexport function mapKeys<T extends Record<string, unknown>>(\r\n obj: T,\r\n mapKey: (k: string) => string,\r\n): Record<string, unknown> {\r\n const out: Record<string, unknown> = {};\r\n for (const [k, v] of Object.entries(obj)) out[mapKey(k)] = v;\r\n return out;\r\n}\r\n\r\nexport function mapRowToBetterAuth<T>(row: T): T {\r\n if (!row || typeof row !== \"object\") return row;\r\n if (Array.isArray(row)) return row.map(mapRowToBetterAuth) as unknown as T;\r\n return mapKeys(row as Record<string, unknown>, toCamelCase) as T;\r\n}\r\n\r\nexport function isLikelyIsoDateString(value: string): boolean {\r\n if (!/^\\d{4}-\\d{2}-\\d{2}T/.test(value)) return false;\r\n const ms = Date.parse(value);\r\n return Number.isFinite(ms);\r\n}\r\n\r\nexport function isTimestampKey(key: string): boolean {\r\n return key.endsWith(\"At\") || key.endsWith(\"_at\") || key === \"expires\";\r\n}\r\n\r\nexport function coerceDateFields<T extends Record<string, unknown>>(data: T): T {\r\n const out: Record<string, unknown> = { ...data };\r\n for (const [key, val] of Object.entries(out)) {\r\n if (val == null) continue;\r\n if (\r\n typeof val === \"string\" &&\r\n isTimestampKey(key) &&\r\n isLikelyIsoDateString(val)\r\n ) {\r\n out[key] = new Date(val);\r\n }\r\n }\r\n return out as T;\r\n}\r\n\r\nexport function toDbRecord<T extends Record<string, unknown>>(\r\n data: T,\r\n): Record<string, unknown> {\r\n const withDbKeys = mapKeys(data, (k) =>\r\n hasUppercase(k) ? toSnakeCase(k) : k,\r\n );\r\n return coerceDateFields(withDbKeys);\r\n}\r\n\r\nexport type AthenaFilterBuilder = {\r\n eq(col: string, val: unknown): AthenaFilterBuilder;\r\n neq(col: string, val: unknown): AthenaFilterBuilder;\r\n gt(col: string, val: unknown): AthenaFilterBuilder;\r\n gte(col: string, val: unknown): AthenaFilterBuilder;\r\n lt(col: string, val: unknown): AthenaFilterBuilder;\r\n lte(col: string, val: unknown): AthenaFilterBuilder;\r\n in(col: string, vals: unknown[]): AthenaFilterBuilder;\r\n not(col: string, op?: string, val?: unknown): AthenaFilterBuilder;\r\n like(col: string, val: string): AthenaFilterBuilder;\r\n delete?(): { select(): Promise<{ data: unknown; error: unknown }> };\r\n select?(columns?: string): Promise<{ data: unknown; error: unknown }> | { select(): Promise<{ data: unknown; error: unknown }> };\r\n};\r\n\r\nexport type WhereClause = { field: string; operator: string; value: unknown };\r\n\r\nconst defaultColumnMapper = (col: string) =>\r\n hasUppercase(col) ? toSnakeCase(col) : col;\r\n\r\nexport function applyWhere(\r\n builder: AthenaFilterBuilder,\r\n field: string,\r\n operator: string,\r\n value: unknown,\r\n columnMapper: (col: string) => string = defaultColumnMapper,\r\n): AthenaFilterBuilder {\r\n const dbField = columnMapper(field);\r\n switch (operator) {\r\n case \"eq\":\r\n return builder.eq(dbField, value);\r\n case \"ne\":\r\n return builder.neq(dbField, value);\r\n case \"gt\":\r\n return builder.gt(dbField, value);\r\n case \"gte\":\r\n return builder.gte(dbField, value);\r\n case \"lt\":\r\n return builder.lt(dbField, value);\r\n case \"lte\":\r\n return builder.lte(dbField, value);\r\n case \"in\":\r\n return builder.in(dbField, value as unknown[]);\r\n case \"not_in\":\r\n return builder.not(dbField, \"in\", value);\r\n case \"contains\":\r\n return builder.like(dbField, `%${value}%`);\r\n case \"starts_with\":\r\n return builder.like(dbField, `${value}%`);\r\n case \"ends_with\":\r\n return builder.like(dbField, `%${value}`);\r\n default:\r\n return builder.eq(dbField, value);\r\n }\r\n}\r\n\r\nexport function isMissingColumnError(error: unknown): boolean {\r\n const msg = String(error ?? \"\");\r\n return (\r\n msg.includes(\"specified column does not exist\") ||\r\n msg.includes(\"column does not exist\")\r\n );\r\n}\r\n\r\n/** True when the Athena gateway returns a success message in the error field (treat as success). */\r\nexport function isSuccessMessageInError(error: unknown): boolean {\r\n const msg = String(error ?? \"\").toLowerCase();\r\n return (\r\n msg === \"data inserted successfully\" ||\r\n msg === \"data updated successfully\" ||\r\n msg === \"data deleted successfully\"\r\n );\r\n}\r\n\r\nexport function snakeMapper(col: string): string {\r\n return hasUppercase(col) ? toSnakeCase(col) : col;\r\n}\r\n\r\nexport function identityMapper(col: string): string {\r\n return col;\r\n}\r\n\r\n/** Get value from row by field name (camelCase or snake_case). */\r\nfunction getRowValue(row: Record<string, unknown>, field: string): unknown {\r\n if (Object.prototype.hasOwnProperty.call(row, field)) return row[field];\r\n const snake = hasUppercase(field) ? toSnakeCase(field) : field;\r\n return row[snake];\r\n}\r\n\r\n/**\r\n * Filter rows in-memory by where clauses (fallback when gateway does not apply filters).\r\n * Supports eq, ne, in, not_in; row keys may be camelCase or snake_case.\r\n */\r\nexport function filterRowsByWhere(\r\n rows: Record<string, unknown>[],\r\n where: WhereClause[],\r\n): Record<string, unknown>[] {\r\n if (!where.length) return rows;\r\n return rows.filter((row) => {\r\n for (const { field, operator, value } of where) {\r\n const rowVal = getRowValue(row, field);\r\n switch (operator) {\r\n case \"eq\":\r\n if (rowVal !== value) return false;\r\n break;\r\n case \"ne\":\r\n if (rowVal === value) return false;\r\n break;\r\n case \"in\":\r\n if (!Array.isArray(value) || !value.includes(rowVal)) return false;\r\n break;\r\n case \"not_in\":\r\n if (Array.isArray(value) && value.includes(rowVal)) return false;\r\n break;\r\n default:\r\n if (rowVal !== value) return false;\r\n }\r\n }\r\n return true;\r\n });\r\n}\r\n","import { toDbRecord, mapRowToBetterAuth, isSuccessMessageInError } from \"../utils\";\r\n\r\nexport type CreateDeps = {\r\n ensureDbClient: () => any;\r\n};\r\n\r\nexport function createMethod(deps: CreateDeps) {\r\n const { ensureDbClient } = deps;\r\n\r\n return async function create<T extends Record<string, unknown>>({\r\n model,\r\n data,\r\n }: {\r\n model: string;\r\n data: T;\r\n select?: string[];\r\n }) {\r\n const db = ensureDbClient();\r\n const insertData = toDbRecord(data);\r\n const { data: result, error } = await db\r\n .from(model)\r\n .insert(insertData)\r\n .select();\r\n\r\n if (error && !isSuccessMessageInError(error)) {\r\n throw new Error(`[AthenaAdapter] create on \"${model}\" failed: ${error}`);\r\n }\r\n\r\n const row = Array.isArray(result) ? result[0] : result;\r\n return mapRowToBetterAuth((row ?? insertData) as T);\r\n };\r\n}\r\n","import type { WhereClause, AthenaFilterBuilder } from \"../utils\";\r\nimport {\r\n toDbRecord,\r\n mapRowToBetterAuth,\r\n applyWhere,\r\n isSuccessMessageInError,\r\n toSnakeCase,\r\n hasUppercase,\r\n} from \"../utils\";\r\n\r\nexport type GatewayConnectionConfig = {\r\n url: string;\r\n apiKey: string;\r\n client?: string;\r\n headers?: Record<string, string>;\r\n};\r\n\r\nexport type UpdateDeps = {\r\n ensureDbClient: () => any;\r\n getConnectionConfig: () => GatewayConnectionConfig;\r\n};\r\n\r\nexport function updateMethod(deps: UpdateDeps) {\r\n const { ensureDbClient } = deps;\r\n\r\n return async function update<T>({\r\n model,\r\n where,\r\n update,\r\n }: {\r\n model: string;\r\n where: WhereClause[];\r\n update: T;\r\n }) {\r\n const db = ensureDbClient();\r\n const updateData = toDbRecord(update as Record<string, unknown>);\r\n const debugUpdates = process?.env?.ATHENA_ADAPTER_DEBUG_UPDATES === \"1\";\r\n const debugLog = (event: string, extra?: Record<string, unknown>) => {\r\n if (!debugUpdates) return;\r\n console.info(\"[AthenaAdapter][update]\", { event, model, ...extra });\r\n };\r\n\r\n // Build an Athena filter-builder chain with one of two update_body shapes.\r\n const build = (shape: \"plain\" | \"wrapped\") => {\r\n const values =\r\n shape === \"plain\"\r\n ? (updateData as any)\r\n : ({ data: updateData, set: updateData } as any);\r\n let b = db.from(model).update(values) as AthenaFilterBuilder;\r\n for (const clause of where) {\r\n b = applyWhere(b, clause.field, clause.operator, clause.value);\r\n }\r\n return b;\r\n };\r\n\r\n const run = async (b: AthenaFilterBuilder) => {\r\n const { data: result, error } = await (b as any).select();\r\n return { result, error };\r\n };\r\n\r\n // Direct fetch to the gateway — bypasses update_body wrapping entirely.\r\n // Tries top-level { data, set } then top-level { columns: [...] }.\r\n const directGatewayUpdate = async () => {\r\n const { url, apiKey, client, headers: extraHeaders } = deps.getConnectionConfig();\r\n const base = url.replace(/\\/$/, \"\");\r\n const conditions = where.map((clause) => {\r\n const column = hasUppercase(clause.field) ? toSnakeCase(clause.field) : clause.field;\r\n const value = clause.value;\r\n switch (clause.operator) {\r\n case \"ne\": return { operator: \"neq\", column, value };\r\n case \"contains\": return { operator: \"like\", column, value: `%${value}%` };\r\n case \"starts_with\": return { operator: \"like\", column, value: `${String(value)}%` };\r\n case \"ends_with\": return { operator: \"like\", column, value: `%${String(value)}` };\r\n case \"eq\": return { operator: \"eq\", column, eq_column: column, value, eq_value: value };\r\n default: return { operator: clause.operator, column, value };\r\n }\r\n });\r\n const requestHeaders: Record<string, string> = {\r\n \"Content-Type\": \"application/json\",\r\n \"apikey\": apiKey,\r\n \"x-api-key\": apiKey,\r\n \"X-Athena-Client\": client ?? \"railway_direct\",\r\n \"X-Backend-Type\": \"athena\",\r\n \"X-Strip-Nulls\": \"true\",\r\n ...(extraHeaders ?? {}),\r\n };\r\n const payloads = [\r\n { table_name: model, data: updateData, set: updateData, conditions, strip_nulls: true },\r\n {\r\n table_name: model,\r\n columns: Object.entries(updateData).map(([column, value]) => ({ column, value })),\r\n conditions,\r\n strip_nulls: true,\r\n },\r\n ];\r\n for (const payload of payloads) {\r\n const res = await fetch(`${base}/gateway/update`, {\r\n method: \"POST\",\r\n headers: requestHeaders,\r\n body: JSON.stringify(payload),\r\n });\r\n const raw = await res.text();\r\n let parsed: any = null;\r\n try { parsed = JSON.parse(raw); } catch { parsed = raw; }\r\n const fetchError = parsed?.error ?? parsed?.message ?? null;\r\n const fetchData = parsed?.data ?? null;\r\n if (!fetchError || isSuccessMessageInError(fetchError)) {\r\n debugLog(\"direct_gateway_succeeded\");\r\n return { result: fetchData, error: null as string | null };\r\n }\r\n debugLog(\"direct_gateway_shape_failed\", { error: String(fetchError) });\r\n if (!String(fetchError).toLowerCase().includes(\"update payload required\")) {\r\n return { result: null, error: String(fetchError) };\r\n }\r\n }\r\n return { result: null, error: \"update payload required: all gateway formats exhausted\" };\r\n };\r\n\r\n const isPayloadError = (e: unknown) =>\r\n String(e).toLowerCase().includes(\"update payload required\");\r\n\r\n // 1. Plain update_body\r\n const first = await run(build(\"plain\"));\r\n if (!first.error || isSuccessMessageInError(first.error)) {\r\n debugLog(\"primary_succeeded\", { shape: \"plain\" });\r\n const row = Array.isArray(first.result) ? (first.result[0] as unknown) : (first.result as unknown);\r\n return (row ? mapRowToBetterAuth(row as T) : null) as T | null;\r\n }\r\n debugLog(\"primary_failed\", { error: String(first.error) });\r\n if (!isPayloadError(first.error)) {\r\n throw new Error(`[AthenaAdapter] update on \"${model}\" failed: ${first.error}`);\r\n }\r\n\r\n // 2. Wrapped { data, set } update_body\r\n const second = await run(build(\"wrapped\"));\r\n if (!second.error || isSuccessMessageInError(second.error)) {\r\n debugLog(\"wrapped_succeeded\", { shape: \"data/set\" });\r\n const row = Array.isArray(second.result) ? (second.result[0] as unknown) : (second.result as unknown);\r\n return (row ? mapRowToBetterAuth(row as T) : null) as T | null;\r\n }\r\n debugLog(\"wrapped_failed\", { error: String(second.error) });\r\n if (!isPayloadError(second.error)) {\r\n throw new Error(`[AthenaAdapter] update on \"${model}\" failed: ${second.error}`);\r\n }\r\n\r\n // 3. Direct fetch with top-level fields\r\n const direct = await directGatewayUpdate();\r\n if (direct.error && !isSuccessMessageInError(direct.error)) {\r\n debugLog(\"direct_gateway_final_failed\", { error: String(direct.error) });\r\n throw new Error(`[AthenaAdapter] update on \"${model}\" failed: ${direct.error}`);\r\n }\r\n debugLog(\"direct_gateway_succeeded\");\r\n const row = Array.isArray(direct.result)\r\n ? (direct.result[0] as unknown)\r\n : (direct.result as unknown);\r\n return (row ? mapRowToBetterAuth(row as T) : null) as T | null;\r\n };\r\n}\r\n","import type { WhereClause, AthenaFilterBuilder } from \"../utils\";\r\nimport {\r\n toDbRecord,\r\n applyWhere,\r\n isSuccessMessageInError,\r\n toSnakeCase,\r\n hasUppercase,\r\n} from \"../utils\";\r\nimport type { GatewayConnectionConfig } from \"./update\";\r\n\r\nexport type UpdateManyDeps = {\r\n ensureDbClient: () => any;\r\n getConnectionConfig: () => GatewayConnectionConfig;\r\n};\r\n\r\nexport function updateManyMethod(deps: UpdateManyDeps) {\r\n const { ensureDbClient } = deps;\r\n\r\n return async function updateMany({\r\n model,\r\n where,\r\n update,\r\n }: {\r\n model: string;\r\n where: WhereClause[];\r\n update: Record<string, unknown>;\r\n }) {\r\n const db = ensureDbClient();\r\n const updateData = toDbRecord(update);\r\n const debugUpdates = process.env.ATHENA_ADAPTER_DEBUG_UPDATES === \"1\";\r\n const debugLog = (event: string, extra?: Record<string, unknown>) => {\r\n if (!debugUpdates) return;\r\n console.info(\"[AthenaAdapter][updateMany]\", { event, model, ...extra });\r\n };\r\n\r\n const build = (shape: \"plain\" | \"wrapped\") => {\r\n const values =\r\n shape === \"plain\"\r\n ? (updateData as any)\r\n : ({ data: updateData, set: updateData } as any);\r\n let b = db.from(model).update(values) as AthenaFilterBuilder;\r\n for (const clause of where) {\r\n b = applyWhere(b, clause.field, clause.operator, clause.value);\r\n }\r\n return b;\r\n };\r\n\r\n const run = async (b: AthenaFilterBuilder) => {\r\n const { data: result, error } = await (b as any).select();\r\n return { result, error };\r\n };\r\n\r\n const directGatewayUpdateMany = async () => {\r\n const { url, apiKey, client, headers: extraHeaders } = deps.getConnectionConfig();\r\n const base = url.replace(/\\/$/, \"\");\r\n const conditions = where.map((clause) => {\r\n const column = hasUppercase(clause.field) ? toSnakeCase(clause.field) : clause.field;\r\n const value = clause.value;\r\n switch (clause.operator) {\r\n case \"ne\": return { operator: \"neq\", column, value };\r\n case \"contains\": return { operator: \"like\", column, value: `%${value}%` };\r\n case \"starts_with\": return { operator: \"like\", column, value: `${String(value)}%` };\r\n case \"ends_with\": return { operator: \"like\", column, value: `%${String(value)}` };\r\n case \"eq\": return { operator: \"eq\", column, eq_column: column, value, eq_value: value };\r\n default: return { operator: clause.operator, column, value };\r\n }\r\n });\r\n const requestHeaders: Record<string, string> = {\r\n \"Content-Type\": \"application/json\",\r\n \"apikey\": apiKey,\r\n \"x-api-key\": apiKey,\r\n \"X-Athena-Client\": client ?? \"railway_direct\",\r\n \"X-Backend-Type\": \"athena\",\r\n \"X-Strip-Nulls\": \"true\",\r\n ...(extraHeaders ?? {}),\r\n };\r\n const payloads = [\r\n { table_name: model, data: updateData, set: updateData, conditions, strip_nulls: true },\r\n {\r\n table_name: model,\r\n columns: Object.entries(updateData).map(([column, value]) => ({ column, value })),\r\n conditions,\r\n strip_nulls: true,\r\n },\r\n ];\r\n for (const payload of payloads) {\r\n const res = await fetch(`${base}/gateway/update`, {\r\n method: \"POST\",\r\n headers: requestHeaders,\r\n body: JSON.stringify(payload),\r\n });\r\n const raw = await res.text();\r\n let parsed: any = null;\r\n try { parsed = JSON.parse(raw); } catch { parsed = raw; }\r\n const fetchError = parsed?.error ?? parsed?.message ?? null;\r\n const fetchData = parsed?.data ?? null;\r\n if (!fetchError || isSuccessMessageInError(fetchError)) {\r\n debugLog(\"direct_gateway_succeeded\");\r\n return { result: fetchData, error: null as string | null };\r\n }\r\n debugLog(\"direct_gateway_shape_failed\", { error: String(fetchError) });\r\n if (!String(fetchError).toLowerCase().includes(\"update payload required\")) {\r\n return { result: null, error: String(fetchError) };\r\n }\r\n }\r\n return { result: null, error: \"update payload required: all gateway formats exhausted\" };\r\n };\r\n\r\n const countResult = (r: unknown) =>\r\n Array.isArray(r) ? r.length : r ? 1 : 0;\r\n\r\n const isPayloadError = (e: unknown) =>\r\n String(e).toLowerCase().includes(\"update payload required\");\r\n\r\n // 1. Plain\r\n const first = await run(build(\"plain\"));\r\n if (!first.error || isSuccessMessageInError(first.error)) {\r\n debugLog(\"primary_succeeded\", { shape: \"plain\" });\r\n return countResult(first.result);\r\n }\r\n debugLog(\"primary_failed\", { error: String(first.error) });\r\n if (!isPayloadError(first.error)) {\r\n throw new Error(`[AthenaAdapter] updateMany on \"${model}\" failed: ${first.error}`);\r\n }\r\n\r\n // 2. Wrapped\r\n const second = await run(build(\"wrapped\"));\r\n if (!second.error || isSuccessMessageInError(second.error)) {\r\n debugLog(\"wrapped_succeeded\", { shape: \"data/set\" });\r\n return countResult(second.result);\r\n }\r\n debugLog(\"wrapped_failed\", { error: String(second.error) });\r\n if (!isPayloadError(second.error)) {\r\n throw new Error(`[AthenaAdapter] updateMany on \"${model}\" failed: ${second.error}`);\r\n }\r\n\r\n // 3. Direct fetch\r\n const direct = await directGatewayUpdateMany();\r\n if (direct.error && !isSuccessMessageInError(direct.error)) {\r\n debugLog(\"direct_gateway_final_failed\", { error: String(direct.error) });\r\n throw new Error(`[AthenaAdapter] updateMany on \"${model}\" failed: ${direct.error}`);\r\n }\r\n debugLog(\"direct_gateway_succeeded\");\r\n return countResult(direct.result);\r\n };\r\n}\r\n","import type { WhereClause, AthenaFilterBuilder } from \"../utils\";\r\nimport { applyWhere, isSuccessMessageInError } from \"../utils\";\r\n\r\nexport type DeleteDeps = {\r\n ensureDbClient: () => any;\r\n headers?: Record<string, string>;\r\n};\r\n\r\nexport function deleteMethod(deps: DeleteDeps) {\r\n const { ensureDbClient, headers } = deps;\r\n\r\n return async function del({\r\n model,\r\n where,\r\n }: {\r\n model: string;\r\n where: WhereClause[];\r\n }) {\r\n const db = ensureDbClient();\r\n let builder = db.from(model) as AthenaFilterBuilder;\r\n\r\n for (const clause of where) {\r\n builder = applyWhere(\r\n builder,\r\n clause.field,\r\n clause.operator,\r\n clause.value,\r\n );\r\n }\r\n\r\n const { error } = await (builder as any).delete(\r\n headers ? ({ headers } as any) : undefined,\r\n );\r\n\r\n if (error && !isSuccessMessageInError(error)) {\r\n throw new Error(\r\n `[AthenaAdapter] delete on \"${model}\" failed: ${error}`,\r\n );\r\n }\r\n };\r\n}\r\n","import type { WhereClause, AthenaFilterBuilder } from \"../utils\";\r\nimport { applyWhere, isSuccessMessageInError } from \"../utils\";\r\n\r\nexport type DeleteManyDeps = {\r\n ensureDbClient: () => any;\r\n headers?: Record<string, string>;\r\n};\r\n\r\nexport function deleteManyMethod(deps: DeleteManyDeps) {\r\n const { ensureDbClient, headers } = deps;\r\n\r\n return async function deleteMany({\r\n model,\r\n where,\r\n }: {\r\n model: string;\r\n where: WhereClause[];\r\n }) {\r\n const db = ensureDbClient();\r\n const mainBuilder = db.from(model) as AthenaFilterBuilder;\r\n let builder = mainBuilder;\r\n\r\n for (const clause of where) {\r\n builder = applyWhere(\r\n builder,\r\n clause.field,\r\n clause.operator,\r\n clause.value,\r\n );\r\n }\r\n\r\n const { data: result, error } = await (builder as any).delete(\r\n headers ? ({ headers } as any) : undefined,\r\n ).select();\r\n\r\n if (error && !isSuccessMessageInError(error)) {\r\n throw new Error(\r\n `[AthenaAdapter] deleteMany on \"${model}\" failed: ${error}`,\r\n );\r\n }\r\n\r\n const deletedCount = Array.isArray(result) ? result.length : result ? 1 : 0;\r\n // Fallback: if the live gateway doesn't apply `in` conditions correctly,\r\n // delete rows one-by-one so counts are stable for e2e tests.\r\n const inClause = where.find(\r\n (c) => c.operator === \"in\" && c.value != null,\r\n );\r\n if (\r\n inClause &&\r\n Array.isArray(inClause.value) &&\r\n deletedCount < inClause.value.length\r\n ) {\r\n let n = 0;\r\n for (const v of inClause.value) {\r\n const b = db.from(model);\r\n const filtered = applyWhere(\r\n b as any,\r\n inClause.field,\r\n \"eq\",\r\n v,\r\n );\r\n const { data: rowData, error: rowErr } = await (filtered as any).delete(\r\n headers ? ({ headers } as any) : undefined,\r\n ).select();\r\n if (rowErr && isSuccessMessageInError(rowErr)) continue;\r\n n += Array.isArray(rowData) ? rowData.length : rowData ? 1 : 0;\r\n }\r\n return n;\r\n }\r\n\r\n return deletedCount;\r\n };\r\n}\r\n","import type { WhereClause } from \"../utils\";\r\nimport {\r\n applyWhere,\r\n mapRowToBetterAuth,\r\n isMissingColumnError,\r\n snakeMapper,\r\n identityMapper,\r\n filterRowsByWhere,\r\n} from \"../utils\";\r\n\r\nexport type FindOneDeps = {\r\n ensureDbClient: () => any;\r\n};\r\n\r\nexport function findOneMethod(deps: FindOneDeps) {\r\n const { ensureDbClient } = deps;\r\n\r\n return async function findOne<T>({\r\n model,\r\n where,\r\n select,\r\n }: {\r\n model: string;\r\n where: WhereClause[];\r\n select?: string[];\r\n join?: unknown;\r\n }) {\r\n const db = ensureDbClient();\r\n\r\n const run = async (columnMapper: (col: string) => string) => {\r\n const columns =\r\n select && select.length > 0\r\n ? select.map((c) => columnMapper(c)).join(\", \")\r\n : undefined;\r\n\r\n let builder = db.from(model).select(columns);\r\n\r\n for (const clause of where) {\r\n builder = applyWhere(\r\n builder,\r\n clause.field,\r\n clause.operator,\r\n clause.value,\r\n columnMapper,\r\n );\r\n }\r\n\r\n const { data: result, error } = await builder.limit(1);\r\n return { result, error };\r\n };\r\n\r\n const first = await run(snakeMapper);\r\n if (first.error) {\r\n if (isMissingColumnError(first.error)) {\r\n const retry = await run(identityMapper);\r\n if (retry.error) {\r\n throw new Error(\r\n `[AthenaAdapter] findOne on \"${model}\" failed: ${retry.error}`,\r\n );\r\n }\r\n\r\n const rows = Array.isArray(retry.result)\r\n ? retry.result\r\n : retry.result\r\n ? [retry.result]\r\n : [];\r\n const row = rows[0] ?? null;\r\n return (row ? mapRowToBetterAuth(row as T) : null) as T | null;\r\n }\r\n\r\n throw new Error(\r\n `[AthenaAdapter] findOne on \"${model}\" failed: ${first.error}`,\r\n );\r\n }\r\n\r\n const rows = Array.isArray(first.result)\r\n ? first.result\r\n : first.result\r\n ? [first.result]\r\n : [];\r\n const row = rows[0] ?? null;\r\n if (!row) return null;\r\n\r\n const mapped = mapRowToBetterAuth(row as T) as T;\r\n const filtered = filterRowsByWhere(\r\n [mapped as unknown as Record<string, unknown>],\r\n where,\r\n );\r\n return (filtered[0] ? mapped : null) as T | null;\r\n };\r\n}\r\n","import type { WhereClause } from \"../utils\";\r\nimport {\r\n applyWhere,\r\n mapRowToBetterAuth,\r\n isMissingColumnError,\r\n snakeMapper,\r\n identityMapper,\r\n filterRowsByWhere,\r\n} from \"../utils\";\r\n\r\nexport type FindManyDeps = {\r\n ensureDbClient: () => any;\r\n};\r\n\r\nexport function findManyMethod(deps: FindManyDeps) {\r\n const { ensureDbClient } = deps;\r\n\r\n const isTransientGatewayError = (error: unknown): boolean => {\r\n const message = String(error ?? \"\").toLowerCase();\r\n return (\r\n message.includes(\"application failed to respond\") ||\r\n message.includes(\"timeout\") ||\r\n message.includes(\"timed out\") ||\r\n message.includes(\"gateway timeout\") ||\r\n message.includes(\"econnreset\") ||\r\n message.includes(\"connection reset\")\r\n );\r\n };\r\n\r\n return async function findMany<T>({\r\n model,\r\n where,\r\n limit,\r\n sortBy,\r\n offset,\r\n select,\r\n }: {\r\n model: string;\r\n where?: WhereClause[];\r\n limit: number;\r\n select?: string[];\r\n sortBy?: { field: string; direction: \"asc\" | \"desc\" };\r\n offset?: number;\r\n join?: unknown;\r\n }) {\r\n const db = ensureDbClient();\r\n\r\n const run = async (\r\n columnMapper: (col: string) => string,\r\n opts?: { skipWhere?: boolean; limitOverride?: number; offsetOverride?: number },\r\n ) => {\r\n const columns =\r\n select && select.length > 0\r\n ? select.map((c) => columnMapper(c)).join(\", \")\r\n : undefined;\r\n\r\n let builder = db.from(model).select(columns);\r\n\r\n if (!opts?.skipWhere && where) {\r\n for (const clause of where) {\r\n builder = applyWhere(\r\n builder,\r\n clause.field,\r\n clause.operator,\r\n clause.value,\r\n columnMapper,\r\n );\r\n }\r\n }\r\n\r\n const effectiveLimit = opts?.limitOverride ?? limit;\r\n const effectiveOffset = opts?.offsetOverride ?? offset;\r\n\r\n if (effectiveLimit !== undefined) {\r\n builder = builder.limit(effectiveLimit);\r\n }\r\n\r\n if (effectiveOffset !== undefined) {\r\n builder = builder.offset(effectiveOffset);\r\n }\r\n\r\n const { data: result, error } = await builder;\r\n return { result, error };\r\n };\r\n\r\n let first = await run(snakeMapper);\r\n if (first.error && isTransientGatewayError(first.error)) {\r\n const retry = await run(snakeMapper);\r\n if (!retry.error) first = retry;\r\n }\r\n\r\n const pickRows = (res: unknown) =>\r\n (Array.isArray(res) ? res : []) as Record<string, unknown>[];\r\n\r\n const applySort = (rows: T[]) => {\r\n if (!sortBy) return rows;\r\n const sortField = sortBy.field;\r\n rows.sort((a, b) => {\r\n const aVal = (a as Record<string, unknown>)[sortField];\r\n const bVal = (b as Record<string, unknown>)[sortField];\r\n if (aVal == null && bVal == null) return 0;\r\n if (aVal == null) return sortBy.direction === \"asc\" ? -1 : 1;\r\n if (bVal == null) return sortBy.direction === \"asc\" ? 1 : -1;\r\n const cmp =\r\n typeof aVal === \"string\" && typeof bVal === \"string\"\r\n ? aVal.localeCompare(bVal)\r\n : aVal < bVal\r\n ? -1\r\n : aVal > bVal\r\n ? 1\r\n : 0;\r\n return sortBy.direction === \"asc\" ? cmp : -cmp;\r\n });\r\n return rows;\r\n };\r\n\r\n const mapAndSort = (rows: Record<string, unknown>[]) => {\r\n const betterAuthRows = rows.map((r) => mapRowToBetterAuth(r)) as unknown as T[];\r\n\r\n if (!where?.length) return applySort(betterAuthRows);\r\n\r\n const filtered = filterRowsByWhere(\r\n betterAuthRows as unknown as Record<string, unknown>[],\r\n where,\r\n ) as unknown as T[];\r\n\r\n // If filtering changed the row set, the gateway likely ignored `where`\r\n // (or applied it before limiting/offset). In that case, re-apply sorting\r\n // and slice using the requested offset/limit.\r\n if (filtered.length !== betterAuthRows.length) {\r\n const off = offset ?? 0;\r\n const end = limit !== undefined ? off + limit : undefined;\r\n return applySort(filtered).slice(off, end);\r\n }\r\n\r\n return applySort(filtered);\r\n };\r\n\r\n const postFilterAndSlice = (rows: Record<string, unknown>[]) => {\r\n const mappedSorted = mapAndSort(rows);\r\n const off = offset ?? 0;\r\n const end = limit !== undefined ? off + limit : undefined;\r\n return mappedSorted.slice(off, end);\r\n };\r\n\r\n if (first.error) {\r\n if (isMissingColumnError(first.error)) {\r\n const retry = await run(identityMapper);\r\n if (retry.error) {\r\n throw new Error(\r\n `[AthenaAdapter] findMany on \"${model}\" failed: ${retry.error}`,\r\n );\r\n }\r\n const retryRows = pickRows(retry.result);\r\n // Decisive fallback: if gateway-side `where` yields empty/insufficient rows,\r\n // fetch a broader candidate set and apply `where`/sort/offset/limit in-memory.\r\n if (where?.length) {\r\n const broad = await run(identityMapper, {\r\n skipWhere: true,\r\n limitOverride: Math.max((offset ?? 0) + (limit ?? 0) + 500, 5000),\r\n offsetOverride: 0,\r\n });\r\n if (!broad.error) return postFilterAndSlice(pickRows(broad.result));\r\n }\r\n return mapAndSort(retryRows);\r\n }\r\n\r\n throw new Error(\r\n `[AthenaAdapter] findMany on \"${model}\" failed: ${first.error}`,\r\n );\r\n }\r\n\r\n const firstRows = pickRows(first.result);\r\n if (where?.length) {\r\n const broad = await run(snakeMapper, {\r\n skipWhere: true,\r\n limitOverride: Math.max((offset ?? 0) + (limit ?? 0) + 500, 5000),\r\n offsetOverride: 0,\r\n });\r\n if (!broad.error) return postFilterAndSlice(pickRows(broad.result));\r\n }\r\n return mapAndSort(firstRows);\r\n };\r\n}\r\n","import type { WhereClause } from \"../utils\";\r\nimport {\r\n applyWhere,\r\n isMissingColumnError,\r\n snakeMapper,\r\n identityMapper,\r\n} from \"../utils\";\r\n\r\nexport type CountDeps = {\r\n ensureDbClient: () => any;\r\n};\r\n\r\nexport function countMethod(deps: CountDeps) {\r\n const { ensureDbClient } = deps;\r\n\r\n return async function count({\r\n model,\r\n where,\r\n }: {\r\n model: string;\r\n where?: WhereClause[];\r\n }) {\r\n const db = ensureDbClient();\r\n\r\n const run = async (columnMapper: (col: string) => string) => {\r\n let builder = db.from(model).select();\r\n\r\n if (where) {\r\n for (const clause of where) {\r\n builder = applyWhere(\r\n builder,\r\n clause.field,\r\n clause.operator,\r\n clause.value,\r\n columnMapper,\r\n );\r\n }\r\n }\r\n\r\n const { data: result, error } = await builder;\r\n return { result, error };\r\n };\r\n\r\n const first = await run(snakeMapper);\r\n if (first.error) {\r\n if (isMissingColumnError(first.error)) {\r\n const retry = await run(identityMapper);\r\n if (retry.error) {\r\n throw new Error(\r\n `[AthenaAdapter] count on \"${model}\" failed: ${retry.error}`,\r\n );\r\n }\r\n return Array.isArray(retry.result) ? retry.result.length : 0;\r\n }\r\n throw new Error(\r\n `[AthenaAdapter] count on \"${model}\" failed: ${first.error}`,\r\n );\r\n }\r\n\r\n return Array.isArray(first.result) ? first.result.length : 0;\r\n };\r\n}\r\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,sBAIO;AAEP,oBAA6B;;;ACN7B,qBAAe;AACf,uBAAiB;AACjB,kBAAiB;AAaV,IAAM,4BAAgD;AAAA,EAC3D,QAAQ;AAAA,IACN,KAAK;AAAA,IACL,QAAQ;AAAA,IACR,QAAQ;AAAA,EACV;AACF;AAEO,IAAM,0BAA0B;AAEvC,SAAS,kBAAkB,YAA6B;AACtD,MAAI,WAAY,QAAO,iBAAAA,QAAK,QAAQ,UAAU;AAC9C,SAAO,iBAAAA,QAAK,QAAQ,QAAQ,IAAI,GAAG,uBAAuB;AAC5D;AAEA,IAAI,SAAoC;AACxC,IAAI,mBAAkC;AACtC,IAAI,UAAU;AAEd,IAAI,UAA+B;AAEnC,SAAS,SAAS,OAAkD;AAClE,SAAO,OAAO,UAAU,YAAY,UAAU,QAAQ,CAAC,MAAM,QAAQ,KAAK;AAC5E;AAEA,SAAS,UACP,MACA,SACG;AACH,MAAI,CAAC,SAAS,OAAO,EAAG,QAAO;AAC/B,QAAM,MAA+B,EAAE,GAAG,KAAK;AAC/C,aAAW,CAAC,GAAG,CAAC,KAAK,OAAO,QAAQ,OAAO,GAAG;AAC5C,QAAI,KAAK,SAAS,CAAC,KAAK,SAAS,IAAI,CAAC,CAAC,GAAG;AACxC,UAAI,CAAC,IAAI,UAAU,IAAI,CAAC,GAA8B,CAAC;AAAA,IACzD,OAAO;AACL,UAAI,CAAC,IAAI;AAAA,IACX;AAAA,EACF;AACA,SAAO;AACT;AAEA,SAAS,iBAAiB,YAA0B;AAClD,QAAM,MAAM,iBAAAA,QAAK,QAAQ,UAAU;AACnC,MAAI,CAAC,eAAAC,QAAG,WAAW,GAAG,EAAG,gBAAAA,QAAG,UAAU,KAAK,EAAE,WAAW,KAAK,CAAC;AAE9D,MAAI,CAAC,eAAAA,QAAG,WAAW,UAAU,GAAG;AAC9B,UAAM,OAAO,YAAAC,QAAK,UAAU,yBAAyB;AACrD,mBAAAD,QAAG,cAAc,YAAY,MAAM,OAAO;AAAA,EAC5C;AACF;AAEA,SAAS,mBAAmB,YAAwC;AAClE,mBAAiB,UAAU;AAC3B,QAAM,MAAM,eAAAA,QAAG,aAAa,YAAY,OAAO;AAC/C,QAAM,SAAS,YAAAC,QAAK,MAAM,GAAG;AAC7B,SAAO,UAAU,2BAA2B,MAAM;AACpD;AAEA,SAAS,aAAa,YAA0B;AAE9C,MAAI,qBAAqB,QAAQ,qBAAqB,cAAc,SAAS;AAC3E,QAAI;AACF,cAAQ,MAAM;AAAA,IAChB,QAAQ;AAAA,IAER;AACA,cAAU;AAAA,EACZ;AACA,MAAI,WAAW,qBAAqB,WAAY;AAEhD,MAAI;AACF,cAAU,eAAAD,QAAG,MAAM,YAAY,EAAE,YAAY,MAAM,GAAG,CAAC,UAAU;AAC/D,UAAI,UAAU,YAAY,UAAU,SAAU;AAC9C,UAAI;AACF,iBAAS,mBAAmB,UAAU;AACtC,mBAAW;AAAA,MACb,QAAQ;AAAA,MAER;AAAA,IACF,CAAC;AACD,uBAAmB;AAAA,EACrB,QAAQ;AAAA,EAER;AACF;AAEO,SAAS,sBAAsB,SAGc;AAClD,QAAM,aAAa,kBAAkB,SAAS,UAAU;AACxD,QAAM,cAAc,SAAS,SAAS;AAEtC,MAAI,CAAC,UAAU,qBAAqB,YAAY;AAC9C,aAAS,mBAAmB,UAAU;AACtC,uBAAmB;AACnB,eAAW;AAAA,EACb;AAEA,MAAI,YAAa,cAAa,UAAU;AAExC,SAAO,EAAE,QAAQ,QAAQ,QAAQ;AACnC;;;ACjHO,SAAS,YAAY,KAAqB;AAC/C,SAAO,IACJ,QAAQ,sBAAsB,OAAO,EACrC,QAAQ,OAAO,GAAG,EAClB,YAAY;AACjB;AAEO,SAAS,YAAY,KAAqB;AAC/C,SAAO,IAAI,QAAQ,gBAAgB,CAAC,GAAG,OAAe,GAAG,YAAY,CAAC;AACxE;AAEO,SAAS,aAAa,KAAsB;AACjD,SAAO,QAAQ,KAAK,GAAG;AACzB;AAEO,SAAS,QACd,KACA,QACyB;AACzB,QAAM,MAA+B,CAAC;AACtC,aAAW,CAAC,GAAG,CAAC,KAAK,OAAO,QAAQ,GAAG,EAAG,KAAI,OAAO,CAAC,CAAC,IAAI;AAC3D,SAAO;AACT;AAEO,SAAS,mBAAsB,KAAW;AAC/C,MAAI,CAAC,OAAO,OAAO,QAAQ,SAAU,QAAO;AAC5C,MAAI,MAAM,QAAQ,GAAG,EAAG,QAAO,IAAI,IAAI,kBAAkB;AACzD,SAAO,QAAQ,KAAgC,WAAW;AAC5D;AAEO,SAAS,sBAAsB,OAAwB;AAC5D,MAAI,CAAC,sBAAsB,KAAK,KAAK,EAAG,QAAO;AAC/C,QAAM,KAAK,KAAK,MAAM,KAAK;AAC3B,SAAO,OAAO,SAAS,EAAE;AAC3B;AAEO,SAAS,eAAe,KAAsB;AACnD,SAAO,IAAI,SAAS,IAAI,KAAK,IAAI,SAAS,KAAK,KAAK,QAAQ;AAC9D;AAEO,SAAS,iBAAoD,MAAY;AAC9E,QAAM,MAA+B,EAAE,GAAG,KAAK;AAC/C,aAAW,CAAC,KAAK,GAAG,KAAK,OAAO,QAAQ,GAAG,GAAG;AAC5C,QAAI,OAAO,KAAM;AACjB,QACE,OAAO,QAAQ,YACf,eAAe,GAAG,KAClB,sBAAsB,GAAG,GACzB;AACA,UAAI,GAAG,IAAI,IAAI,KAAK,GAAG;AAAA,IACzB;AAAA,EACF;AACA,SAAO;AACT;AAEO,SAAS,WACd,MACyB;AACzB,QAAM,aAAa;AAAA,IAAQ;AAAA,IAAM,CAAC,MAChC,aAAa,CAAC,IAAI,YAAY,CAAC,IAAI;AAAA,EACrC;AACA,SAAO,iBAAiB,UAAU;AACpC;AAkBA,IAAM,sBAAsB,CAAC,QAC3B,aAAa,GAAG,IAAI,YAAY,GAAG,IAAI;AAElC,SAAS,WACd,SACA,OACA,UACA,OACA,eAAwC,qBACnB;AACrB,QAAM,UAAU,aAAa,KAAK;AAClC,UAAQ,UAAU;AAAA,IAChB,KAAK;AACH,aAAO,QAAQ,GAAG,SAAS,KAAK;AAAA,IAClC,KAAK;AACH,aAAO,QAAQ,IAAI,SAAS,KAAK;AAAA,IACnC,KAAK;AACH,aAAO,QAAQ,GAAG,SAAS,KAAK;AAAA,IAClC,KAAK;AACH,aAAO,QAAQ,IAAI,SAAS,KAAK;AAAA,IACnC,KAAK;AACH,aAAO,QAAQ,GAAG,SAAS,KAAK;AAAA,IAClC,KAAK;AACH,aAAO,QAAQ,IAAI,SAAS,KAAK;AAAA,IACnC,KAAK;AACH,aAAO,QAAQ,GAAG,SAAS,KAAkB;AAAA,IAC/C,KAAK;AACH,aAAO,QAAQ,IAAI,SAAS,MAAM,KAAK;AAAA,IACzC,KAAK;AACH,aAAO,QAAQ,KAAK,SAAS,IAAI,KAAK,GAAG;AAAA,IAC3C,KAAK;AACH,aAAO,QAAQ,KAAK,SAAS,GAAG,KAAK,GAAG;AAAA,IAC1C,KAAK;AACH,aAAO,QAAQ,KAAK,SAAS,IAAI,KAAK,EAAE;AAAA,IAC1C;AACE,aAAO,QAAQ,GAAG,SAAS,KAAK;AAAA,EACpC;AACF;AAEO,SAAS,qBAAqB,OAAyB;AAC5D,QAAM,MAAM,OAAO,SAAS,EAAE;AAC9B,SACE,IAAI,SAAS,iCAAiC,KAC9C,IAAI,SAAS,uBAAuB;AAExC;AAGO,SAAS,wBAAwB,OAAyB;AAC/D,QAAM,MAAM,OAAO,SAAS,EAAE,EAAE,YAAY;AAC5C,SACE,QAAQ,gCACR,QAAQ,+BACR,QAAQ;AAEZ;AAEO,SAAS,YAAY,KAAqB;AAC/C,SAAO,aAAa,GAAG,IAAI,YAAY,GAAG,IAAI;AAChD;AAEO,SAAS,eAAe,KAAqB;AAClD,SAAO;AACT;AAGA,SAAS,YAAY,KAA8B,OAAwB;AACzE,MAAI,OAAO,UAAU,eAAe,KAAK,KAAK,KAAK,EAAG,QAAO,IAAI,KAAK;AACtE,QAAM,QAAQ,aAAa,KAAK,IAAI,YAAY,KAAK,IAAI;AACzD,SAAO,IAAI,KAAK;AAClB;AAMO,SAAS,kBACd,MACA,OAC2B;AAC3B,MAAI,CAAC,MAAM,OAAQ,QAAO;AAC1B,SAAO,KAAK,OAAO,CAAC,QAAQ;AAC1B,eAAW,EAAE,OAAO,UAAU,MAAM,KAAK,OAAO;AAC9C,YAAM,SAAS,YAAY,KAAK,KAAK;AACrC,cAAQ,UAAU;AAAA,QAChB,KAAK;AACH,cAAI,WAAW,MAAO,QAAO;AAC7B;AAAA,QACF,KAAK;AACH,cAAI,WAAW,MAAO,QAAO;AAC7B;AAAA,QACF,KAAK;AACH,cAAI,CAAC,MAAM,QAAQ,KAAK,KAAK,CAAC,MAAM,SAAS,MAAM,EAAG,QAAO;AAC7D;AAAA,QACF,KAAK;AACH,cAAI,MAAM,QAAQ,KAAK,KAAK,MAAM,SAAS,MAAM,EAAG,QAAO;AAC3D;AAAA,QACF;AACE,cAAI,WAAW,MAAO,QAAO;AAAA,MACjC;AAAA,IACF;AACA,WAAO;AAAA,EACT,CAAC;AACH;;;ACrLO,SAAS,aAAa,MAAkB;AAC7C,QAAM,EAAE,eAAe,IAAI;AAE3B,SAAO,eAAe,OAA0C;AAAA,IAC9D;AAAA,IACA;AAAA,EACF,GAIG;AACD,UAAM,KAAK,eAAe;AAC1B,UAAM,aAAa,WAAW,IAAI;AAClC,UAAM,EAAE,MAAM,QAAQ,MAAM,IAAI,MAAM,GACnC,KAAK,KAAK,EACV,OAAO,UAAU,EACjB,OAAO;AAEV,QAAI,SAAS,CAAC,wBAAwB,KAAK,GAAG;AAC5C,YAAM,IAAI,MAAM,8BAA8B,KAAK,aAAa,KAAK,EAAE;AAAA,IACzE;AAEA,UAAM,MAAM,MAAM,QAAQ,MAAM,IAAI,OAAO,CAAC,IAAI;AAChD,WAAO,mBAAoB,OAAO,UAAgB;AAAA,EACpD;AACF;;;ACTO,SAAS,aAAa,MAAkB;AAC7C,QAAM,EAAE,eAAe,IAAI;AAE3B,SAAO,eAAe,OAAU;AAAA,IAC9B;AAAA,IACA;AAAA,IACA;AAAA,EACF,GAIG;AACD,UAAM,KAAK,eAAe;AAC1B,UAAM,aAAa,WAAW,MAAiC;AAC/D,UAAM,eAAe,SAAS,KAAK,iCAAiC;AACpE,UAAM,WAAW,CAAC,OAAe,UAAoC;AACnE,UAAI,CAAC,aAAc;AACnB,cAAQ,KAAK,2BAA2B,EAAE,OAAO,OAAO,GAAG,MAAM,CAAC;AAAA,IACpE;AAGA,UAAM,QAAQ,CAAC,UAA+B;AAC5C,YAAM,SACJ,UAAU,UACL,aACA,EAAE,MAAM,YAAY,KAAK,WAAW;AAC3C,UAAI,IAAI,GAAG,KAAK,KAAK,EAAE,OAAO,MAAM;AACpC,iBAAW,UAAU,OAAO;AAC1B,YAAI,WAAW,GAAG,OAAO,OAAO,OAAO,UAAU,OAAO,KAAK;AAAA,MAC/D;AACA,aAAO;AAAA,IACT;AAEA,UAAM,MAAM,OAAO,MAA2B;AAC5C,YAAM,EAAE,MAAM,QAAQ,MAAM,IAAI,MAAO,EAAU,OAAO;AACxD,aAAO,EAAE,QAAQ,MAAM;AAAA,IACzB;AAIA,UAAM,sBAAsB,YAAY;AACtC,YAAM,EAAE,KAAK,QAAQ,QAAQ,SAAS,aAAa,IAAI,KAAK,oBAAoB;AAChF,YAAM,OAAO,IAAI,QAAQ,OAAO,EAAE;AAClC,YAAM,aAAa,MAAM,IAAI,CAAC,WAAW;AACvC,cAAM,SAAS,aAAa,OAAO,KAAK,IAAI,YAAY,OAAO,KAAK,IAAI,OAAO;AAC/E,cAAM,QAAQ,OAAO;AACrB,gBAAQ,OAAO,UAAU;AAAA,UACvB,KAAK;AAAM,mBAAO,EAAE,UAAU,OAAO,QAAQ,MAAM;AAAA,UACnD,KAAK;AAAY,mBAAO,EAAE,UAAU,QAAQ,QAAQ,OAAO,IAAI,KAAK,IAAI;AAAA,UACxE,KAAK;AAAe,mBAAO,EAAE,UAAU,QAAQ,QAAQ,OAAO,GAAG,OAAO,KAAK,CAAC,IAAI;AAAA,UAClF,KAAK;AAAa,mBAAO,EAAE,UAAU,QAAQ,QAAQ,OAAO,IAAI,OAAO,KAAK,CAAC,GAAG;AAAA,UAChF,KAAK;AAAM,mBAAO,EAAE,UAAU,MAAM,QAAQ,WAAW,QAAQ,OAAO,UAAU,MAAM;AAAA,UACtF;AAAS,mBAAO,EAAE,UAAU,OAAO,UAAU,QAAQ,MAAM;AAAA,QAC7D;AAAA,MACF,CAAC;AACD,YAAM,iBAAyC;AAAA,QAC7C,gBAAgB;AAAA,QAChB,UAAU;AAAA,QACV,aAAa;AAAA,QACb,mBAAmB,UAAU;AAAA,QAC7B,kBAAkB;AAAA,QAClB,iBAAiB;AAAA,QACjB,GAAI,gBAAgB,CAAC;AAAA,MACvB;AACA,YAAM,WAAW;AAAA,QACf,EAAE,YAAY,OAAO,MAAM,YAAY,KAAK,YAAY,YAAY,aAAa,KAAK;AAAA,QACtF;AAAA,UACE,YAAY;AAAA,UACZ,SAAS,OAAO,QAAQ,UAAU,EAAE,IAAI,CAAC,CAAC,QAAQ,KAAK,OAAO,EAAE,QAAQ,MAAM,EAAE;AAAA,UAChF;AAAA,UACA,aAAa;AAAA,QACf;AAAA,MACF;AACA,iBAAW,WAAW,UAAU;AAC9B,cAAM,MAAM,MAAM,MAAM,GAAG,IAAI,mBAAmB;AAAA,UAChD,QAAQ;AAAA,UACR,SAAS;AAAA,UACT,MAAM,KAAK,UAAU,OAAO;AAAA,QAC9B,CAAC;AACD,cAAM,MAAM,MAAM,IAAI,KAAK;AAC3B,YAAI,SAAc;AAClB,YAAI;AAAE,mBAAS,KAAK,MAAM,GAAG;AAAA,QAAG,QAAQ;AAAE,mBAAS;AAAA,QAAK;AACxD,cAAM,aAAa,QAAQ,SAAS,QAAQ,WAAW;AACvD,cAAM,YAAY,QAAQ,QAAQ;AAClC,YAAI,CAAC,cAAc,wBAAwB,UAAU,GAAG;AACtD,mBAAS,0BAA0B;AACnC,iBAAO,EAAE,QAAQ,WAAW,OAAO,KAAsB;AAAA,QAC3D;AACA,iBAAS,+BAA+B,EAAE,OAAO,OAAO,UAAU,EAAE,CAAC;AACrE,YAAI,CAAC,OAAO,UAAU,EAAE,YAAY,EAAE,SAAS,yBAAyB,GAAG;AACzE,iBAAO,EAAE,QAAQ,MAAM,OAAO,OAAO,UAAU,EAAE;AAAA,QACnD;AAAA,MACF;AACA,aAAO,EAAE,QAAQ,MAAM,OAAO,yDAAyD;AAAA,IACzF;AAEA,UAAM,iBAAiB,CAAC,MACtB,OAAO,CAAC,EAAE,YAAY,EAAE,SAAS,yBAAyB;AAG5D,UAAM,QAAQ,MAAM,IAAI,MAAM,OAAO,CAAC;AACtC,QAAI,CAAC,MAAM,SAAS,wBAAwB,MAAM,KAAK,GAAG;AACxD,eAAS,qBAAqB,EAAE,OAAO,QAAQ,CAAC;AAChD,YAAME,OAAM,MAAM,QAAQ,MAAM,MAAM,IAAK,MAAM,OAAO,CAAC,IAAiB,MAAM;AAChF,aAAQA,OAAM,mBAAmBA,IAAQ,IAAI;AAAA,IAC/C;AACA,aAAS,kBAAkB,EAAE,OAAO,OAAO,MAAM,KAAK,EAAE,CAAC;AACzD,QAAI,CAAC,eAAe,MAAM,KAAK,GAAG;AAChC,YAAM,IAAI,MAAM,8BAA8B,KAAK,aAAa,MAAM,KAAK,EAAE;AAAA,IAC/E;AAGA,UAAM,SAAS,MAAM,IAAI,MAAM,SAAS,CAAC;AACzC,QAAI,CAAC,OAAO,SAAS,wBAAwB,OAAO,KAAK,GAAG;AAC1D,eAAS,qBAAqB,EAAE,OAAO,WAAW,CAAC;AACnD,YAAMA,OAAM,MAAM,QAAQ,OAAO,MAAM,IAAK,OAAO,OAAO,CAAC,IAAiB,OAAO;AACnF,aAAQA,OAAM,mBAAmBA,IAAQ,IAAI;AAAA,IAC/C;AACA,aAAS,kBAAkB,EAAE,OAAO,OAAO,OAAO,KAAK,EAAE,CAAC;AAC1D,QAAI,CAAC,eAAe,OAAO,KAAK,GAAG;AACjC,YAAM,IAAI,MAAM,8BAA8B,KAAK,aAAa,OAAO,KAAK,EAAE;AAAA,IAChF;AAGA,UAAM,SAAS,MAAM,oBAAoB;AACzC,QAAI,OAAO,SAAS,CAAC,wBAAwB,OAAO,KAAK,GAAG;AAC1D,eAAS,+BAA+B,EAAE,OAAO,OAAO,OAAO,KAAK,EAAE,CAAC;AACvE,YAAM,IAAI,MAAM,8BAA8B,KAAK,aAAa,OAAO,KAAK,EAAE;AAAA,IAChF;AACA,aAAS,0BAA0B;AACnC,UAAM,MAAM,MAAM,QAAQ,OAAO,MAAM,IAClC,OAAO,OAAO,CAAC,IACf,OAAO;AACZ,WAAQ,MAAM,mBAAmB,GAAQ,IAAI;AAAA,EAC/C;AACF;;;AC9IO,SAAS,iBAAiB,MAAsB;AACrD,QAAM,EAAE,eAAe,IAAI;AAE3B,SAAO,eAAe,WAAW;AAAA,IAC/B;AAAA,IACA;AAAA,IACA;AAAA,EACF,GAIG;AACD,UAAM,KAAK,eAAe;AAC1B,UAAM,aAAa,WAAW,MAAM;AACpC,UAAM,eAAe,QAAQ,IAAI,iCAAiC;AAClE,UAAM,WAAW,CAAC,OAAe,UAAoC;AACnE,UAAI,CAAC,aAAc;AACnB,cAAQ,KAAK,+BAA+B,EAAE,OAAO,OAAO,GAAG,MAAM,CAAC;AAAA,IACxE;AAEA,UAAM,QAAQ,CAAC,UAA+B;AAC5C,YAAM,SACJ,UAAU,UACL,aACA,EAAE,MAAM,YAAY,KAAK,WAAW;AAC3C,UAAI,IAAI,GAAG,KAAK,KAAK,EAAE,OAAO,MAAM;AACpC,iBAAW,UAAU,OAAO;AAC1B,YAAI,WAAW,GAAG,OAAO,OAAO,OAAO,UAAU,OAAO,KAAK;AAAA,MAC/D;AACA,aAAO;AAAA,IACT;AAEA,UAAM,MAAM,OAAO,MAA2B;AAC5C,YAAM,EAAE,MAAM,QAAQ,MAAM,IAAI,MAAO,EAAU,OAAO;AACxD,aAAO,EAAE,QAAQ,MAAM;AAAA,IACzB;AAEA,UAAM,0BAA0B,YAAY;AAC1C,YAAM,EAAE,KAAK,QAAQ,QAAQ,SAAS,aAAa,IAAI,KAAK,oBAAoB;AAChF,YAAM,OAAO,IAAI,QAAQ,OAAO,EAAE;AAClC,YAAM,aAAa,MAAM,IAAI,CAAC,WAAW;AACvC,cAAM,SAAS,aAAa,OAAO,KAAK,IAAI,YAAY,OAAO,KAAK,IAAI,OAAO;AAC/E,cAAM,QAAQ,OAAO;AACrB,gBAAQ,OAAO,UAAU;AAAA,UACvB,KAAK;AAAM,mBAAO,EAAE,UAAU,OAAO,QAAQ,MAAM;AAAA,UACnD,KAAK;AAAY,mBAAO,EAAE,UAAU,QAAQ,QAAQ,OAAO,IAAI,KAAK,IAAI;AAAA,UACxE,KAAK;AAAe,mBAAO,EAAE,UAAU,QAAQ,QAAQ,OAAO,GAAG,OAAO,KAAK,CAAC,IAAI;AAAA,UAClF,KAAK;AAAa,mBAAO,EAAE,UAAU,QAAQ,QAAQ,OAAO,IAAI,OAAO,KAAK,CAAC,GAAG;AAAA,UAChF,KAAK;AAAM,mBAAO,EAAE,UAAU,MAAM,QAAQ,WAAW,QAAQ,OAAO,UAAU,MAAM;AAAA,UACtF;AAAS,mBAAO,EAAE,UAAU,OAAO,UAAU,QAAQ,MAAM;AAAA,QAC7D;AAAA,MACF,CAAC;AACD,YAAM,iBAAyC;AAAA,QAC7C,gBAAgB;AAAA,QAChB,UAAU;AAAA,QACV,aAAa;AAAA,QACb,mBAAmB,UAAU;AAAA,QAC7B,kBAAkB;AAAA,QAClB,iBAAiB;AAAA,QACjB,GAAI,gBAAgB,CAAC;AAAA,MACvB;AACA,YAAM,WAAW;AAAA,QACf,EAAE,YAAY,OAAO,MAAM,YAAY,KAAK,YAAY,YAAY,aAAa,KAAK;AAAA,QACtF;AAAA,UACE,YAAY;AAAA,UACZ,SAAS,OAAO,QAAQ,UAAU,EAAE,IAAI,CAAC,CAAC,QAAQ,KAAK,OAAO,EAAE,QAAQ,MAAM,EAAE;AAAA,UAChF;AAAA,UACA,aAAa;AAAA,QACf;AAAA,MACF;AACA,iBAAW,WAAW,UAAU;AAC9B,cAAM,MAAM,MAAM,MAAM,GAAG,IAAI,mBAAmB;AAAA,UAChD,QAAQ;AAAA,UACR,SAAS;AAAA,UACT,MAAM,KAAK,UAAU,OAAO;AAAA,QAC9B,CAAC;AACD,cAAM,MAAM,MAAM,IAAI,KAAK;AAC3B,YAAI,SAAc;AAClB,YAAI;AAAE,mBAAS,KAAK,MAAM,GAAG;AAAA,QAAG,QAAQ;AAAE,mBAAS;AAAA,QAAK;AACxD,cAAM,aAAa,QAAQ,SAAS,QAAQ,WAAW;AACvD,cAAM,YAAY,QAAQ,QAAQ;AAClC,YAAI,CAAC,cAAc,wBAAwB,UAAU,GAAG;AACtD,mBAAS,0BAA0B;AACnC,iBAAO,EAAE,QAAQ,WAAW,OAAO,KAAsB;AAAA,QAC3D;AACA,iBAAS,+BAA+B,EAAE,OAAO,OAAO,UAAU,EAAE,CAAC;AACrE,YAAI,CAAC,OAAO,UAAU,EAAE,YAAY,EAAE,SAAS,yBAAyB,GAAG;AACzE,iBAAO,EAAE,QAAQ,MAAM,OAAO,OAAO,UAAU,EAAE;AAAA,QACnD;AAAA,MACF;AACA,aAAO,EAAE,QAAQ,MAAM,OAAO,yDAAyD;AAAA,IACzF;AAEA,UAAM,cAAc,CAAC,MACnB,MAAM,QAAQ,CAAC,IAAI,EAAE,SAAS,IAAI,IAAI;AAExC,UAAM,iBAAiB,CAAC,MACtB,OAAO,CAAC,EAAE,YAAY,EAAE,SAAS,yBAAyB;AAG5D,UAAM,QAAQ,MAAM,IAAI,MAAM,OAAO,CAAC;AACtC,QAAI,CAAC,MAAM,SAAS,wBAAwB,MAAM,KAAK,GAAG;AACxD,eAAS,qBAAqB,EAAE,OAAO,QAAQ,CAAC;AAChD,aAAO,YAAY,MAAM,MAAM;AAAA,IACjC;AACA,aAAS,kBAAkB,EAAE,OAAO,OAAO,MAAM,KAAK,EAAE,CAAC;AACzD,QAAI,CAAC,eAAe,MAAM,KAAK,GAAG;AAChC,YAAM,IAAI,MAAM,kCAAkC,KAAK,aAAa,MAAM,KAAK,EAAE;AAAA,IACnF;AAGA,UAAM,SAAS,MAAM,IAAI,MAAM,SAAS,CAAC;AACzC,QAAI,CAAC,OAAO,SAAS,wBAAwB,OAAO,KAAK,GAAG;AAC1D,eAAS,qBAAqB,EAAE,OAAO,WAAW,CAAC;AACnD,aAAO,YAAY,OAAO,MAAM;AAAA,IAClC;AACA,aAAS,kBAAkB,EAAE,OAAO,OAAO,OAAO,KAAK,EAAE,CAAC;AAC1D,QAAI,CAAC,eAAe,OAAO,KAAK,GAAG;AACjC,YAAM,IAAI,MAAM,kCAAkC,KAAK,aAAa,OAAO,KAAK,EAAE;AAAA,IACpF;AAGA,UAAM,SAAS,MAAM,wBAAwB;AAC7C,QAAI,OAAO,SAAS,CAAC,wBAAwB,OAAO,KAAK,GAAG;AAC1D,eAAS,+BAA+B,EAAE,OAAO,OAAO,OAAO,KAAK,EAAE,CAAC;AACvE,YAAM,IAAI,MAAM,kCAAkC,KAAK,aAAa,OAAO,KAAK,EAAE;AAAA,IACpF;AACA,aAAS,0BAA0B;AACnC,WAAO,YAAY,OAAO,MAAM;AAAA,EAClC;AACF;;;ACzIO,SAAS,aAAa,MAAkB;AAC7C,QAAM,EAAE,gBAAgB,QAAQ,IAAI;AAEpC,SAAO,eAAe,IAAI;AAAA,IACxB;AAAA,IACA;AAAA,EACF,GAGG;AACD,UAAM,KAAK,eAAe;AAC1B,QAAI,UAAU,GAAG,KAAK,KAAK;AAE3B,eAAW,UAAU,OAAO;AAC1B,gBAAU;AAAA,QACR;AAAA,QACA,OAAO;AAAA,QACP,OAAO;AAAA,QACP,OAAO;AAAA,MACT;AAAA,IACF;AAEA,UAAM,EAAE,MAAM,IAAI,MAAO,QAAgB;AAAA,MACvC,UAAW,EAAE,QAAQ,IAAY;AAAA,IACnC;AAEA,QAAI,SAAS,CAAC,wBAAwB,KAAK,GAAG;AAC5C,YAAM,IAAI;AAAA,QACR,8BAA8B,KAAK,aAAa,KAAK;AAAA,MACvD;AAAA,IACF;AAAA,EACF;AACF;;;AChCO,SAAS,iBAAiB,MAAsB;AACrD,QAAM,EAAE,gBAAgB,QAAQ,IAAI;AAEpC,SAAO,eAAe,WAAW;AAAA,IAC/B;AAAA,IACA;AAAA,EACF,GAGG;AACD,UAAM,KAAK,eAAe;AAC1B,UAAM,cAAc,GAAG,KAAK,KAAK;AACjC,QAAI,UAAU;AAEd,eAAW,UAAU,OAAO;AAC1B,gBAAU;AAAA,QACR;AAAA,QACA,OAAO;AAAA,QACP,OAAO;AAAA,QACP,OAAO;AAAA,MACT;AAAA,IACF;AAEA,UAAM,EAAE,MAAM,QAAQ,MAAM,IAAI,MAAO,QAAgB;AAAA,MACrD,UAAW,EAAE,QAAQ,IAAY;AAAA,IACnC,EAAE,OAAO;AAET,QAAI,SAAS,CAAC,wBAAwB,KAAK,GAAG;AAC5C,YAAM,IAAI;AAAA,QACR,kCAAkC,KAAK,aAAa,KAAK;AAAA,MAC3D;AAAA,IACF;AAEA,UAAM,eAAe,MAAM,QAAQ,MAAM,IAAI,OAAO,SAAS,SAAS,IAAI;AAG1E,UAAM,WAAW,MAAM;AAAA,MACrB,CAAC,MAAM,EAAE,aAAa,QAAQ,EAAE,SAAS;AAAA,IAC3C;AACA,QACE,YACA,MAAM,QAAQ,SAAS,KAAK,KAC5B,eAAe,SAAS,MAAM,QAC9B;AACA,UAAI,IAAI;AACR,iBAAW,KAAK,SAAS,OAAO;AAC9B,cAAM,IAAI,GAAG,KAAK,KAAK;AACvB,cAAM,WAAW;AAAA,UACf;AAAA,UACA,SAAS;AAAA,UACT;AAAA,UACA;AAAA,QACF;AACA,cAAM,EAAE,MAAM,SAAS,OAAO,OAAO,IAAI,MAAO,SAAiB;AAAA,UAC/D,UAAW,EAAE,QAAQ,IAAY;AAAA,QACnC,EAAE,OAAO;AACT,YAAI,UAAU,wBAAwB,MAAM,EAAG;AAC/C,aAAK,MAAM,QAAQ,OAAO,IAAI,QAAQ,SAAS,UAAU,IAAI;AAAA,MAC/D;AACA,aAAO;AAAA,IACT;AAEA,WAAO;AAAA,EACT;AACF;;;AC1DO,SAAS,cAAc,MAAmB;AAC/C,QAAM,EAAE,eAAe,IAAI;AAE3B,SAAO,eAAe,QAAW;AAAA,IAC/B;AAAA,IACA;AAAA,IACA;AAAA,EACF,GAKG;AACD,UAAM,KAAK,eAAe;AAE1B,UAAM,MAAM,OAAO,iBAA0C;AAC3D,YAAM,UACJ,UAAU,OAAO,SAAS,IACtB,OAAO,IAAI,CAAC,MAAM,aAAa,CAAC,CAAC,EAAE,KAAK,IAAI,IAC5C;AAEN,UAAI,UAAU,GAAG,KAAK,KAAK,EAAE,OAAO,OAAO;AAE3C,iBAAW,UAAU,OAAO;AAC1B,kBAAU;AAAA,UACR;AAAA,UACA,OAAO;AAAA,UACP,OAAO;AAAA,UACP,OAAO;AAAA,UACP;AAAA,QACF;AAAA,MACF;AAEA,YAAM,EAAE,MAAM,QAAQ,MAAM,IAAI,MAAM,QAAQ,MAAM,CAAC;AACrD,aAAO,EAAE,QAAQ,MAAM;AAAA,IACzB;AAEA,UAAM,QAAQ,MAAM,IAAI,WAAW;AACnC,QAAI,MAAM,OAAO;AACf,UAAI,qBAAqB,MAAM,KAAK,GAAG;AACrC,cAAM,QAAQ,MAAM,IAAI,cAAc;AACtC,YAAI,MAAM,OAAO;AACf,gBAAM,IAAI;AAAA,YACR,+BAA+B,KAAK,aAAa,MAAM,KAAK;AAAA,UAC9D;AAAA,QACF;AAEA,cAAMC,QAAO,MAAM,QAAQ,MAAM,MAAM,IACnC,MAAM,SACN,MAAM,SACJ,CAAC,MAAM,MAAM,IACb,CAAC;AACP,cAAMC,OAAMD,MAAK,CAAC,KAAK;AACvB,eAAQC,OAAM,mBAAmBA,IAAQ,IAAI;AAAA,MAC/C;AAEA,YAAM,IAAI;AAAA,QACR,+BAA+B,KAAK,aAAa,MAAM,KAAK;AAAA,MAC9D;AAAA,IACF;AAEA,UAAM,OAAO,MAAM,QAAQ,MAAM,MAAM,IACnC,MAAM,SACN,MAAM,SACJ,CAAC,MAAM,MAAM,IACb,CAAC;AACP,UAAM,MAAM,KAAK,CAAC,KAAK;AACvB,QAAI,CAAC,IAAK,QAAO;AAEjB,UAAM,SAAS,mBAAmB,GAAQ;AAC1C,UAAM,WAAW;AAAA,MACf,CAAC,MAA4C;AAAA,MAC7C;AAAA,IACF;AACA,WAAQ,SAAS,CAAC,IAAI,SAAS;AAAA,EACjC;AACF;;;AC5EO,SAAS,eAAe,MAAoB;AACjD,QAAM,EAAE,eAAe,IAAI;AAE3B,QAAM,0BAA0B,CAAC,UAA4B;AAC3D,UAAM,UAAU,OAAO,SAAS,EAAE,EAAE,YAAY;AAChD,WACE,QAAQ,SAAS,+BAA+B,KAChD,QAAQ,SAAS,SAAS,KAC1B,QAAQ,SAAS,WAAW,KAC5B,QAAQ,SAAS,iBAAiB,KAClC,QAAQ,SAAS,YAAY,KAC7B,QAAQ,SAAS,kBAAkB;AAAA,EAEvC;AAEA,SAAO,eAAe,SAAY;AAAA,IAChC;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,GAQG;AACD,UAAM,KAAK,eAAe;AAE1B,UAAM,MAAM,OACV,cACA,SACG;AACH,YAAM,UACJ,UAAU,OAAO,SAAS,IACtB,OAAO,IAAI,CAAC,MAAM,aAAa,CAAC,CAAC,EAAE,KAAK,IAAI,IAC5C;AAEN,UAAI,UAAU,GAAG,KAAK,KAAK,EAAE,OAAO,OAAO;AAE3C,UAAI,CAAC,MAAM,aAAa,OAAO;AAC7B,mBAAW,UAAU,OAAO;AAC1B,oBAAU;AAAA,YACR;AAAA,YACA,OAAO;AAAA,YACP,OAAO;AAAA,YACP,OAAO;AAAA,YACP;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAEA,YAAM,iBAAiB,MAAM,iBAAiB;AAC9C,YAAM,kBAAkB,MAAM,kBAAkB;AAEhD,UAAI,mBAAmB,QAAW;AAChC,kBAAU,QAAQ,MAAM,cAAc;AAAA,MACxC;AAEA,UAAI,oBAAoB,QAAW;AACjC,kBAAU,QAAQ,OAAO,eAAe;AAAA,MAC1C;AAEA,YAAM,EAAE,MAAM,QAAQ,MAAM,IAAI,MAAM;AACtC,aAAO,EAAE,QAAQ,MAAM;AAAA,IACzB;AAEA,QAAI,QAAQ,MAAM,IAAI,WAAW;AACjC,QAAI,MAAM,SAAS,wBAAwB,MAAM,KAAK,GAAG;AACvD,YAAM,QAAQ,MAAM,IAAI,WAAW;AACnC,UAAI,CAAC,MAAM,MAAO,SAAQ;AAAA,IAC5B;AAEA,UAAM,WAAW,CAAC,QACf,MAAM,QAAQ,GAAG,IAAI,MAAM,CAAC;AAE/B,UAAM,YAAY,CAAC,SAAc;AAC/B,UAAI,CAAC,OAAQ,QAAO;AACpB,YAAM,YAAY,OAAO;AACzB,WAAK,KAAK,CAAC,GAAG,MAAM;AAClB,cAAM,OAAQ,EAA8B,SAAS;AACrD,cAAM,OAAQ,EAA8B,SAAS;AACrD,YAAI,QAAQ,QAAQ,QAAQ,KAAM,QAAO;AACzC,YAAI,QAAQ,KAAM,QAAO,OAAO,cAAc,QAAQ,KAAK;AAC3D,YAAI,QAAQ,KAAM,QAAO,OAAO,cAAc,QAAQ,IAAI;AAC1D,cAAM,MACJ,OAAO,SAAS,YAAY,OAAO,SAAS,WACxC,KAAK,cAAc,IAAI,IACvB,OAAO,OACL,KACA,OAAO,OACL,IACA;AACV,eAAO,OAAO,cAAc,QAAQ,MAAM,CAAC;AAAA,MAC7C,CAAC;AACD,aAAO;AAAA,IACT;AAEA,UAAM,aAAa,CAAC,SAAoC;AACtD,YAAM,iBAAiB,KAAK,IAAI,CAAC,MAAM,mBAAmB,CAAC,CAAC;AAE5D,UAAI,CAAC,OAAO,OAAQ,QAAO,UAAU,cAAc;AAEnD,YAAM,WAAW;AAAA,QACf;AAAA,QACA;AAAA,MACF;AAKA,UAAI,SAAS,WAAW,eAAe,QAAQ;AAC7C,cAAM,MAAM,UAAU;AACtB,cAAM,MAAM,UAAU,SAAY,MAAM,QAAQ;AAChD,eAAO,UAAU,QAAQ,EAAE,MAAM,KAAK,GAAG;AAAA,MAC3C;AAEA,aAAO,UAAU,QAAQ;AAAA,IAC3B;AAEA,UAAM,qBAAqB,CAAC,SAAoC;AAC9D,YAAM,eAAe,WAAW,IAAI;AACpC,YAAM,MAAM,UAAU;AACtB,YAAM,MAAM,UAAU,SAAY,MAAM,QAAQ;AAChD,aAAO,aAAa,MAAM,KAAK,GAAG;AAAA,IACpC;AAEA,QAAI,MAAM,OAAO;AACf,UAAI,qBAAqB,MAAM,KAAK,GAAG;AACrC,cAAM,QAAQ,MAAM,IAAI,cAAc;AACtC,YAAI,MAAM,OAAO;AACf,gBAAM,IAAI;AAAA,YACR,gCAAgC,KAAK,aAAa,MAAM,KAAK;AAAA,UAC/D;AAAA,QACF;AACA,cAAM,YAAY,SAAS,MAAM,MAAM;AAGvC,YAAI,OAAO,QAAQ;AACjB,gBAAM,QAAQ,MAAM,IAAI,gBAAgB;AAAA,YACtC,WAAW;AAAA,YACX,eAAe,KAAK,KAAK,UAAU,MAAM,SAAS,KAAK,KAAK,GAAI;AAAA,YAChE,gBAAgB;AAAA,UAClB,CAAC;AACD,cAAI,CAAC,MAAM,MAAO,QAAO,mBAAmB,SAAS,MAAM,MAAM,CAAC;AAAA,QACpE;AACA,eAAO,WAAW,SAAS;AAAA,MAC7B;AAEA,YAAM,IAAI;AAAA,QACR,gCAAgC,KAAK,aAAa,MAAM,KAAK;AAAA,MAC/D;AAAA,IACF;AAEA,UAAM,YAAY,SAAS,MAAM,MAAM;AACvC,QAAI,OAAO,QAAQ;AACjB,YAAM,QAAQ,MAAM,IAAI,aAAa;AAAA,QACnC,WAAW;AAAA,QACX,eAAe,KAAK,KAAK,UAAU,MAAM,SAAS,KAAK,KAAK,GAAI;AAAA,QAChE,gBAAgB;AAAA,MAClB,CAAC;AACD,UAAI,CAAC,MAAM,MAAO,QAAO,mBAAmB,SAAS,MAAM,MAAM,CAAC;AAAA,IACpE;AACA,WAAO,WAAW,SAAS;AAAA,EAC7B;AACF;;;AC3KO,SAAS,YAAY,MAAiB;AAC3C,QAAM,EAAE,eAAe,IAAI;AAE3B,SAAO,eAAe,MAAM;AAAA,IAC1B;AAAA,IACA;AAAA,EACF,GAGG;AACD,UAAM,KAAK,eAAe;AAE1B,UAAM,MAAM,OAAO,iBAA0C;AAC3D,UAAI,UAAU,GAAG,KAAK,KAAK,EAAE,OAAO;AAEpC,UAAI,OAAO;AACT,mBAAW,UAAU,OAAO;AAC1B,oBAAU;AAAA,YACR;AAAA,YACA,OAAO;AAAA,YACP,OAAO;AAAA,YACP,OAAO;AAAA,YACP;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAEA,YAAM,EAAE,MAAM,QAAQ,MAAM,IAAI,MAAM;AACtC,aAAO,EAAE,QAAQ,MAAM;AAAA,IACzB;AAEA,UAAM,QAAQ,MAAM,IAAI,WAAW;AACnC,QAAI,MAAM,OAAO;AACf,UAAI,qBAAqB,MAAM,KAAK,GAAG;AACrC,cAAM,QAAQ,MAAM,IAAI,cAAc;AACtC,YAAI,MAAM,OAAO;AACf,gBAAM,IAAI;AAAA,YACR,6BAA6B,KAAK,aAAa,MAAM,KAAK;AAAA,UAC5D;AAAA,QACF;AACA,eAAO,MAAM,QAAQ,MAAM,MAAM,IAAI,MAAM,OAAO,SAAS;AAAA,MAC7D;AACA,YAAM,IAAI;AAAA,QACR,6BAA6B,KAAK,aAAa,MAAM,KAAK;AAAA,MAC5D;AAAA,IACF;AAEA,WAAO,MAAM,QAAQ,MAAM,MAAM,IAAI,MAAM,OAAO,SAAS;AAAA,EAC7D;AACF;;;AVqBO,IAAM,gBAAgB,CAC3B,WACsC;AACtC,MAAI,WAAuB;AAC3B,MAAI,sBAAsB;AAE1B,QAAM,uBACJ,OAAO,OAAO,QAAQ,YACtB,OAAO,IAAI,SAAS,KACpB,OAAO,OAAO,WAAW,YACzB,OAAO,OAAO,SAAS;AAEzB,WAAS,iBAAsB;AAC7B,QAAI,sBAAsB;AACxB,UAAI,CAAC,UAAU;AACb,uBAAW,4BAAa,OAAO,KAAM,OAAO,QAAS;AAAA,UACnD,QAAQ,OAAO;AAAA,UACf,GAAI,OAAO,WAAW,EAAE,SAAS,OAAO,QAAQ;AAAA,QAClD,CAAQ;AAAA,MACV;AACA,aAAO;AAAA,IACT;AAEA,UAAM,EAAE,QAAQ,cAAc,SAAAC,SAAQ,IAAI,sBAAsB;AAAA,MAC9D,YAAY,OAAO;AAAA,MACnB,OAAO,OAAO,eAAe;AAAA,IAC/B,CAAC;AAED,UAAM,MAAM,OAAO,OAAO,aAAa,OAAO;AAC9C,UAAM,SAAS,OAAO,UAAU,aAAa,OAAO;AACpD,UAAM,SAAS,OAAO,UAAU,aAAa,OAAO;AAEpD,QAAI,CAAC,OAAO,CAAC,QAAQ;AACnB,YAAM,IAAI;AAAA,QACR;AAAA,MACF;AAAA,IACF;AAEA,QAAI,CAAC,YAAYA,aAAY,qBAAqB;AAChD,qBAAW,4BAAa,KAAK,QAAQ;AAAA,QACnC;AAAA,QACA,GAAI,OAAO,WAAW,EAAE,SAAS,OAAO,QAAQ;AAAA,MAClD,CAAQ;AACR,4BAAsBA;AAAA,IACxB;AAEA,WAAO;AAAA,EACT;AAEA,WAAS,sBAAsB;AAC7B,QAAI,sBAAsB;AACxB,aAAO;AAAA,QACL,KAAK,OAAO;AAAA,QACZ,QAAQ,OAAO;AAAA,QACf,QAAQ,OAAO;AAAA,QACf,SAAS,OAAO;AAAA,MAClB;AAAA,IACF;AACA,UAAM,EAAE,QAAQ,aAAa,IAAI,sBAAsB;AAAA,MACrD,YAAY,OAAO;AAAA,MACnB,OAAO;AAAA,IACT,CAAC;AACD,WAAO;AAAA,MACL,KAAK,OAAO,OAAO,aAAa,OAAO;AAAA,MACvC,QAAQ,OAAO,UAAU,aAAa,OAAO;AAAA,MAC7C,QAAQ,OAAO,UAAU,aAAa,OAAO;AAAA,MAC7C,SAAS,OAAO;AAAA,IAClB;AAAA,EACF;AAEA,QAAM,OAAO,EAAE,gBAAgB,qBAAqB,SAAS,OAAO,QAAQ;AAE5E,aAAO,sCAAqB;AAAA,IAC1B,QAAQ;AAAA,MACN,WAAW;AAAA,MACX,aAAa;AAAA,MACb,WAAW,OAAO,aAAa;AAAA,MAC/B,WAAW,OAAO,aAAa;AAAA,MAC/B,cAAc;AAAA,MACd,eAAe;AAAA,MACf,kBAAkB;AAAA,MAClB,oBAAoB;AAAA,MACpB,eAAe;AAAA,MACf,gBAAgB;AAAA,IAClB;AAAA,IACA,SAAS,MAAM;AACb,aAAO;AAAA,QACL,QAAQ,aAAa,IAAI;AAAA,QACzB,QAAQ,aAAa,IAAI;AAAA,QACzB,YAAY,iBAAiB,IAAI;AAAA,QACjC,QAAQ,aAAa,IAAI;AAAA,QACzB,YAAY,iBAAiB,IAAI;AAAA,QACjC,SAAS,cAAc,IAAI;AAAA,QAC3B,UAAU,eAAe,IAAI;AAAA,QAC7B,OAAO,YAAY,IAAI;AAAA,QACvB,SAAS;AAAA,UACP,WAAW,OAAO,aAAa;AAAA,QAEjC;AAAA,MACF;AAAA,IACF;AAAA,EACF,CAAC;AACH;","names":["path","fs","YAML","row","rows","row","version"]}
|
package/dist/index.js
CHANGED
|
@@ -238,23 +238,11 @@ function updateMethod(deps) {
|
|
|
238
238
|
const debugUpdates = process?.env?.ATHENA_ADAPTER_DEBUG_UPDATES === "1";
|
|
239
239
|
const debugLog = (event, extra) => {
|
|
240
240
|
if (!debugUpdates) return;
|
|
241
|
-
console.info("[AthenaAdapter][update]", {
|
|
242
|
-
event,
|
|
243
|
-
model,
|
|
244
|
-
...extra
|
|
245
|
-
});
|
|
241
|
+
console.info("[AthenaAdapter][update]", { event, model, ...extra });
|
|
246
242
|
};
|
|
247
|
-
const build = (
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
for (const clause of where) {
|
|
251
|
-
b2 = applyWhere(b2, clause.field, clause.operator, clause.value);
|
|
252
|
-
}
|
|
253
|
-
return b2;
|
|
254
|
-
}
|
|
255
|
-
let b = db.from(model).update(updateData, {
|
|
256
|
-
updateBody: { data: updateData, set: updateData }
|
|
257
|
-
});
|
|
243
|
+
const build = (shape) => {
|
|
244
|
+
const values = shape === "plain" ? updateData : { data: updateData, set: updateData };
|
|
245
|
+
let b = db.from(model).update(values);
|
|
258
246
|
for (const clause of where) {
|
|
259
247
|
b = applyWhere(b, clause.field, clause.operator, clause.value);
|
|
260
248
|
}
|
|
@@ -264,26 +252,99 @@ function updateMethod(deps) {
|
|
|
264
252
|
const { data: result, error } = await b.select();
|
|
265
253
|
return { result, error };
|
|
266
254
|
};
|
|
267
|
-
const
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
const
|
|
271
|
-
|
|
272
|
-
const
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
255
|
+
const directGatewayUpdate = async () => {
|
|
256
|
+
const { url, apiKey, client, headers: extraHeaders } = deps.getConnectionConfig();
|
|
257
|
+
const base = url.replace(/\/$/, "");
|
|
258
|
+
const conditions = where.map((clause) => {
|
|
259
|
+
const column = hasUppercase(clause.field) ? toSnakeCase(clause.field) : clause.field;
|
|
260
|
+
const value = clause.value;
|
|
261
|
+
switch (clause.operator) {
|
|
262
|
+
case "ne":
|
|
263
|
+
return { operator: "neq", column, value };
|
|
264
|
+
case "contains":
|
|
265
|
+
return { operator: "like", column, value: `%${value}%` };
|
|
266
|
+
case "starts_with":
|
|
267
|
+
return { operator: "like", column, value: `${String(value)}%` };
|
|
268
|
+
case "ends_with":
|
|
269
|
+
return { operator: "like", column, value: `%${String(value)}` };
|
|
270
|
+
case "eq":
|
|
271
|
+
return { operator: "eq", column, eq_column: column, value, eq_value: value };
|
|
272
|
+
default:
|
|
273
|
+
return { operator: clause.operator, column, value };
|
|
274
|
+
}
|
|
275
|
+
});
|
|
276
|
+
const requestHeaders = {
|
|
277
|
+
"Content-Type": "application/json",
|
|
278
|
+
"apikey": apiKey,
|
|
279
|
+
"x-api-key": apiKey,
|
|
280
|
+
"X-Athena-Client": client ?? "railway_direct",
|
|
281
|
+
"X-Backend-Type": "athena",
|
|
282
|
+
"X-Strip-Nulls": "true",
|
|
283
|
+
...extraHeaders ?? {}
|
|
284
|
+
};
|
|
285
|
+
const payloads = [
|
|
286
|
+
{ table_name: model, data: updateData, set: updateData, conditions, strip_nulls: true },
|
|
287
|
+
{
|
|
288
|
+
table_name: model,
|
|
289
|
+
columns: Object.entries(updateData).map(([column, value]) => ({ column, value })),
|
|
290
|
+
conditions,
|
|
291
|
+
strip_nulls: true
|
|
292
|
+
}
|
|
293
|
+
];
|
|
294
|
+
for (const payload of payloads) {
|
|
295
|
+
const res = await fetch(`${base}/gateway/update`, {
|
|
296
|
+
method: "POST",
|
|
297
|
+
headers: requestHeaders,
|
|
298
|
+
body: JSON.stringify(payload)
|
|
299
|
+
});
|
|
300
|
+
const raw = await res.text();
|
|
301
|
+
let parsed = null;
|
|
302
|
+
try {
|
|
303
|
+
parsed = JSON.parse(raw);
|
|
304
|
+
} catch {
|
|
305
|
+
parsed = raw;
|
|
306
|
+
}
|
|
307
|
+
const fetchError = parsed?.error ?? parsed?.message ?? null;
|
|
308
|
+
const fetchData = parsed?.data ?? null;
|
|
309
|
+
if (!fetchError || isSuccessMessageInError(fetchError)) {
|
|
310
|
+
debugLog("direct_gateway_succeeded");
|
|
311
|
+
return { result: fetchData, error: null };
|
|
312
|
+
}
|
|
313
|
+
debugLog("direct_gateway_shape_failed", { error: String(fetchError) });
|
|
314
|
+
if (!String(fetchError).toLowerCase().includes("update payload required")) {
|
|
315
|
+
return { result: null, error: String(fetchError) };
|
|
278
316
|
}
|
|
279
|
-
debugLog("retry_succeeded", { shape: "updateBody(data/set)" });
|
|
280
|
-
const row2 = Array.isArray(retry.result) ? retry.result[0] : retry.result;
|
|
281
|
-
return row2 ? mapRowToBetterAuth(row2) : null;
|
|
282
317
|
}
|
|
318
|
+
return { result: null, error: "update payload required: all gateway formats exhausted" };
|
|
319
|
+
};
|
|
320
|
+
const isPayloadError = (e) => String(e).toLowerCase().includes("update payload required");
|
|
321
|
+
const first = await run(build("plain"));
|
|
322
|
+
if (!first.error || isSuccessMessageInError(first.error)) {
|
|
323
|
+
debugLog("primary_succeeded", { shape: "plain" });
|
|
324
|
+
const row2 = Array.isArray(first.result) ? first.result[0] : first.result;
|
|
325
|
+
return row2 ? mapRowToBetterAuth(row2) : null;
|
|
326
|
+
}
|
|
327
|
+
debugLog("primary_failed", { error: String(first.error) });
|
|
328
|
+
if (!isPayloadError(first.error)) {
|
|
283
329
|
throw new Error(`[AthenaAdapter] update on "${model}" failed: ${first.error}`);
|
|
284
330
|
}
|
|
285
|
-
|
|
286
|
-
|
|
331
|
+
const second = await run(build("wrapped"));
|
|
332
|
+
if (!second.error || isSuccessMessageInError(second.error)) {
|
|
333
|
+
debugLog("wrapped_succeeded", { shape: "data/set" });
|
|
334
|
+
const row2 = Array.isArray(second.result) ? second.result[0] : second.result;
|
|
335
|
+
return row2 ? mapRowToBetterAuth(row2) : null;
|
|
336
|
+
}
|
|
337
|
+
debugLog("wrapped_failed", { error: String(second.error) });
|
|
338
|
+
if (!isPayloadError(second.error)) {
|
|
339
|
+
throw new Error(`[AthenaAdapter] update on "${model}" failed: ${second.error}`);
|
|
340
|
+
}
|
|
341
|
+
const direct = await directGatewayUpdate();
|
|
342
|
+
if (direct.error && !isSuccessMessageInError(direct.error)) {
|
|
343
|
+
debugLog("direct_gateway_final_failed", { error: String(direct.error) });
|
|
344
|
+
throw new Error(`[AthenaAdapter] update on "${model}" failed: ${direct.error}`);
|
|
345
|
+
}
|
|
346
|
+
debugLog("direct_gateway_succeeded");
|
|
347
|
+
const row = Array.isArray(direct.result) ? direct.result[0] : direct.result;
|
|
287
348
|
return row ? mapRowToBetterAuth(row) : null;
|
|
288
349
|
};
|
|
289
350
|
}
|
|
@@ -301,23 +362,11 @@ function updateManyMethod(deps) {
|
|
|
301
362
|
const debugUpdates = process.env.ATHENA_ADAPTER_DEBUG_UPDATES === "1";
|
|
302
363
|
const debugLog = (event, extra) => {
|
|
303
364
|
if (!debugUpdates) return;
|
|
304
|
-
console.info("[AthenaAdapter][updateMany]", {
|
|
305
|
-
event,
|
|
306
|
-
model,
|
|
307
|
-
...extra
|
|
308
|
-
});
|
|
365
|
+
console.info("[AthenaAdapter][updateMany]", { event, model, ...extra });
|
|
309
366
|
};
|
|
310
|
-
const build = (
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
for (const clause of where) {
|
|
314
|
-
b2 = applyWhere(b2, clause.field, clause.operator, clause.value);
|
|
315
|
-
}
|
|
316
|
-
return b2;
|
|
317
|
-
}
|
|
318
|
-
let b = db.from(model).update(updateData, {
|
|
319
|
-
updateBody: { data: updateData, set: updateData }
|
|
320
|
-
});
|
|
367
|
+
const build = (shape) => {
|
|
368
|
+
const values = shape === "plain" ? updateData : { data: updateData, set: updateData };
|
|
369
|
+
let b = db.from(model).update(values);
|
|
321
370
|
for (const clause of where) {
|
|
322
371
|
b = applyWhere(b, clause.field, clause.operator, clause.value);
|
|
323
372
|
}
|
|
@@ -327,27 +376,98 @@ function updateManyMethod(deps) {
|
|
|
327
376
|
const { data: result, error } = await b.select();
|
|
328
377
|
return { result, error };
|
|
329
378
|
};
|
|
330
|
-
const
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
const
|
|
334
|
-
|
|
335
|
-
const
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
379
|
+
const directGatewayUpdateMany = async () => {
|
|
380
|
+
const { url, apiKey, client, headers: extraHeaders } = deps.getConnectionConfig();
|
|
381
|
+
const base = url.replace(/\/$/, "");
|
|
382
|
+
const conditions = where.map((clause) => {
|
|
383
|
+
const column = hasUppercase(clause.field) ? toSnakeCase(clause.field) : clause.field;
|
|
384
|
+
const value = clause.value;
|
|
385
|
+
switch (clause.operator) {
|
|
386
|
+
case "ne":
|
|
387
|
+
return { operator: "neq", column, value };
|
|
388
|
+
case "contains":
|
|
389
|
+
return { operator: "like", column, value: `%${value}%` };
|
|
390
|
+
case "starts_with":
|
|
391
|
+
return { operator: "like", column, value: `${String(value)}%` };
|
|
392
|
+
case "ends_with":
|
|
393
|
+
return { operator: "like", column, value: `%${String(value)}` };
|
|
394
|
+
case "eq":
|
|
395
|
+
return { operator: "eq", column, eq_column: column, value, eq_value: value };
|
|
396
|
+
default:
|
|
397
|
+
return { operator: clause.operator, column, value };
|
|
398
|
+
}
|
|
399
|
+
});
|
|
400
|
+
const requestHeaders = {
|
|
401
|
+
"Content-Type": "application/json",
|
|
402
|
+
"apikey": apiKey,
|
|
403
|
+
"x-api-key": apiKey,
|
|
404
|
+
"X-Athena-Client": client ?? "railway_direct",
|
|
405
|
+
"X-Backend-Type": "athena",
|
|
406
|
+
"X-Strip-Nulls": "true",
|
|
407
|
+
...extraHeaders ?? {}
|
|
408
|
+
};
|
|
409
|
+
const payloads = [
|
|
410
|
+
{ table_name: model, data: updateData, set: updateData, conditions, strip_nulls: true },
|
|
411
|
+
{
|
|
412
|
+
table_name: model,
|
|
413
|
+
columns: Object.entries(updateData).map(([column, value]) => ({ column, value })),
|
|
414
|
+
conditions,
|
|
415
|
+
strip_nulls: true
|
|
416
|
+
}
|
|
417
|
+
];
|
|
418
|
+
for (const payload of payloads) {
|
|
419
|
+
const res = await fetch(`${base}/gateway/update`, {
|
|
420
|
+
method: "POST",
|
|
421
|
+
headers: requestHeaders,
|
|
422
|
+
body: JSON.stringify(payload)
|
|
423
|
+
});
|
|
424
|
+
const raw = await res.text();
|
|
425
|
+
let parsed = null;
|
|
426
|
+
try {
|
|
427
|
+
parsed = JSON.parse(raw);
|
|
428
|
+
} catch {
|
|
429
|
+
parsed = raw;
|
|
430
|
+
}
|
|
431
|
+
const fetchError = parsed?.error ?? parsed?.message ?? null;
|
|
432
|
+
const fetchData = parsed?.data ?? null;
|
|
433
|
+
if (!fetchError || isSuccessMessageInError(fetchError)) {
|
|
434
|
+
debugLog("direct_gateway_succeeded");
|
|
435
|
+
return { result: fetchData, error: null };
|
|
436
|
+
}
|
|
437
|
+
debugLog("direct_gateway_shape_failed", { error: String(fetchError) });
|
|
438
|
+
if (!String(fetchError).toLowerCase().includes("update payload required")) {
|
|
439
|
+
return { result: null, error: String(fetchError) };
|
|
341
440
|
}
|
|
342
|
-
debugLog("retry_succeeded", { shape: "updateBody(data/set)" });
|
|
343
|
-
return Array.isArray(retry.result) ? retry.result.length : retry.result ? 1 : 0;
|
|
344
441
|
}
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
442
|
+
return { result: null, error: "update payload required: all gateway formats exhausted" };
|
|
443
|
+
};
|
|
444
|
+
const countResult = (r) => Array.isArray(r) ? r.length : r ? 1 : 0;
|
|
445
|
+
const isPayloadError = (e) => String(e).toLowerCase().includes("update payload required");
|
|
446
|
+
const first = await run(build("plain"));
|
|
447
|
+
if (!first.error || isSuccessMessageInError(first.error)) {
|
|
448
|
+
debugLog("primary_succeeded", { shape: "plain" });
|
|
449
|
+
return countResult(first.result);
|
|
348
450
|
}
|
|
349
|
-
debugLog("
|
|
350
|
-
|
|
451
|
+
debugLog("primary_failed", { error: String(first.error) });
|
|
452
|
+
if (!isPayloadError(first.error)) {
|
|
453
|
+
throw new Error(`[AthenaAdapter] updateMany on "${model}" failed: ${first.error}`);
|
|
454
|
+
}
|
|
455
|
+
const second = await run(build("wrapped"));
|
|
456
|
+
if (!second.error || isSuccessMessageInError(second.error)) {
|
|
457
|
+
debugLog("wrapped_succeeded", { shape: "data/set" });
|
|
458
|
+
return countResult(second.result);
|
|
459
|
+
}
|
|
460
|
+
debugLog("wrapped_failed", { error: String(second.error) });
|
|
461
|
+
if (!isPayloadError(second.error)) {
|
|
462
|
+
throw new Error(`[AthenaAdapter] updateMany on "${model}" failed: ${second.error}`);
|
|
463
|
+
}
|
|
464
|
+
const direct = await directGatewayUpdateMany();
|
|
465
|
+
if (direct.error && !isSuccessMessageInError(direct.error)) {
|
|
466
|
+
debugLog("direct_gateway_final_failed", { error: String(direct.error) });
|
|
467
|
+
throw new Error(`[AthenaAdapter] updateMany on "${model}" failed: ${direct.error}`);
|
|
468
|
+
}
|
|
469
|
+
debugLog("direct_gateway_succeeded");
|
|
470
|
+
return countResult(direct.result);
|
|
351
471
|
};
|
|
352
472
|
}
|
|
353
473
|
|
|
@@ -680,7 +800,27 @@ var athenaAdapter = (config) => {
|
|
|
680
800
|
}
|
|
681
801
|
return dbClient;
|
|
682
802
|
}
|
|
683
|
-
|
|
803
|
+
function getConnectionConfig() {
|
|
804
|
+
if (shouldUseFixedConfig) {
|
|
805
|
+
return {
|
|
806
|
+
url: config.url,
|
|
807
|
+
apiKey: config.apiKey,
|
|
808
|
+
client: config.client,
|
|
809
|
+
headers: config.headers
|
|
810
|
+
};
|
|
811
|
+
}
|
|
812
|
+
const { config: globalConfig } = getAthenaGlobalConfig({
|
|
813
|
+
configPath: config.configPath,
|
|
814
|
+
watch: false
|
|
815
|
+
});
|
|
816
|
+
return {
|
|
817
|
+
url: config.url ?? globalConfig.athena.url,
|
|
818
|
+
apiKey: config.apiKey ?? globalConfig.athena.apiKey,
|
|
819
|
+
client: config.client ?? globalConfig.athena.client,
|
|
820
|
+
headers: config.headers
|
|
821
|
+
};
|
|
822
|
+
}
|
|
823
|
+
const deps = { ensureDbClient, getConnectionConfig, headers: config.headers };
|
|
684
824
|
return createAdapterFactory({
|
|
685
825
|
config: {
|
|
686
826
|
adapterId: "athena",
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/config.ts","../src/utils.ts","../src/methods/create.ts","../src/methods/update.ts","../src/methods/update-many.ts","../src/methods/delete.ts","../src/methods/delete-many.ts","../src/methods/find-one.ts","../src/methods/find-many.ts","../src/methods/count.ts"],"sourcesContent":["import {\r\n createAdapterFactory,\r\n type AdapterFactory,\r\n type DBAdapterDebugLogOption,\r\n} from \"better-auth/adapters\";\r\nimport type { BetterAuthOptions } from \"better-auth\";\r\nimport { createClient } from \"@xylex-group/athena\";\r\nimport { getAthenaGlobalConfig } from \"./config\";\r\nimport { createMethod } from \"./methods/create\";\r\nimport { updateMethod } from \"./methods/update\";\r\nimport { updateManyMethod } from \"./methods/update-many\";\r\nimport { deleteMethod } from \"./methods/delete\";\r\nimport { deleteManyMethod } from \"./methods/delete-many\";\r\nimport { findOneMethod } from \"./methods/find-one\";\r\nimport { findManyMethod } from \"./methods/find-many\";\r\nimport { countMethod } from \"./methods/count\";\r\n\r\n/**\r\n * Configuration options for the Athena adapter.\r\n */\r\nexport interface AthenaAdapterConfig {\r\n /**\r\n * The URL of your Athena gateway.\r\n */\r\n url?: string;\r\n /**\r\n * The API key for authenticating with the Athena gateway.\r\n */\r\n apiKey?: string;\r\n /**\r\n * The client name sent in requests to the Athena gateway.\r\n */\r\n client?: string;\r\n\r\n /**\r\n * Optional override for the YAML config path.\r\n * Defaults to `./config.yaml` (resolved from `process.cwd()`).\r\n */\r\n configPath?: string;\r\n\r\n /**\r\n * When enabled, the adapter will reload `config.yaml` on changes.\r\n *\r\n * @default true\r\n */\r\n watchConfig?: boolean;\r\n /**\r\n * Helps you debug issues with the adapter.\r\n */\r\n debugLogs?: DBAdapterDebugLogOption;\r\n /**\r\n * If the table names in the schema are plural.\r\n *\r\n * @default false\r\n */\r\n usePlural?: boolean;\r\n\r\n /**\r\n * Optional headers sent with every request (e.g. `X-User-Id` if your gateway requires it for delete).\r\n */\r\n headers?: Record<string, string>;\r\n}\r\n\r\n/**\r\n * Create a Better-Auth database adapter backed by @xylex-group/athena.\r\n *\r\n * Column names are kept in snake_case as required by the Athena gateway.\r\n *\r\n * @example\r\n * ```ts\r\n * import { betterAuth } from \"better-auth\";\r\n * import { athenaAdapter } from \"better-auth-athena\";\r\n *\r\n * export const auth = betterAuth({\r\n * database: athenaAdapter({\r\n * url: process.env.ATHENA_URL!,\r\n * apiKey: process.env.ATHENA_API_KEY!,\r\n * client: \"my-app\",\r\n * }),\r\n * });\r\n * ```\r\n */\r\nexport const athenaAdapter = (\r\n config: AthenaAdapterConfig,\r\n): AdapterFactory<BetterAuthOptions> => {\r\n let dbClient: any | null = null;\r\n let lastDbConfigVersion = -1;\r\n\r\n const shouldUseFixedConfig =\r\n typeof config.url === \"string\" &&\r\n config.url.length > 0 &&\r\n typeof config.apiKey === \"string\" &&\r\n config.apiKey.length > 0;\r\n\r\n function ensureDbClient(): any {\r\n if (shouldUseFixedConfig) {\r\n if (!dbClient) {\r\n dbClient = createClient(config.url!, config.apiKey!, {\r\n client: config.client,\r\n ...(config.headers && { headers: config.headers }),\r\n } as any);\r\n }\r\n return dbClient;\r\n }\r\n\r\n const { config: globalConfig, version } = getAthenaGlobalConfig({\r\n configPath: config.configPath,\r\n watch: config.watchConfig ?? true,\r\n });\r\n\r\n const url = config.url ?? globalConfig.athena.url;\r\n const apiKey = config.apiKey ?? globalConfig.athena.apiKey;\r\n const client = config.client ?? globalConfig.athena.client;\r\n\r\n if (!url || !apiKey) {\r\n throw new Error(\r\n `[AthenaAdapter] Missing Athena connection details. Set both 'athena.url' and 'athena.apiKey' in config.yaml (or pass 'url'/'apiKey' to athenaAdapter).`,\r\n );\r\n }\r\n\r\n if (!dbClient || version !== lastDbConfigVersion) {\r\n dbClient = createClient(url, apiKey, {\r\n client,\r\n ...(config.headers && { headers: config.headers }),\r\n } as any);\r\n lastDbConfigVersion = version;\r\n }\r\n\r\n return dbClient;\r\n }\r\n\r\n const deps = { ensureDbClient, headers: config.headers };\r\n\r\n return createAdapterFactory({\r\n config: {\r\n adapterId: \"athena\",\r\n adapterName: \"Athena Adapter\",\r\n usePlural: config.usePlural ?? false,\r\n debugLogs: config.debugLogs ?? false,\r\n supportsJSON: true,\r\n supportsDates: true,\r\n supportsBooleans: true,\r\n supportsNumericIds: true,\r\n supportsUUIDs: true,\r\n supportsArrays: true,\r\n },\r\n adapter: () => {\r\n return {\r\n create: createMethod(deps),\r\n update: updateMethod(deps),\r\n updateMany: updateManyMethod(deps),\r\n delete: deleteMethod(deps),\r\n deleteMany: deleteManyMethod(deps),\r\n findOne: findOneMethod(deps),\r\n findMany: findManyMethod(deps),\r\n count: countMethod(deps),\r\n options: {\r\n debugLogs: config.debugLogs ?? false,\r\n \r\n },\r\n };\r\n },\r\n });\r\n};\r\n\r\n// For testing purposes, we export the internal config function to allow resetting the cached client between tests.\r\nexport { getAthenaGlobalConfig } from \"./config\";\r\n","import fs from \"node:fs\";\r\nimport path from \"node:path\";\r\nimport YAML from \"yaml\";\r\n\r\nexport type AthenaGlobalConfig = {\r\n athena: {\r\n url: string;\r\n apiKey: string;\r\n client?: string;\r\n };\r\n};\r\n\r\n// Defaults written to `config.yaml` if it doesn't exist.\r\n// These values are intentionally placeholders; the adapter will throw if\r\n// `url`/`apiKey` are still unset when used.\r\nexport const defaultAthenaGlobalConfig: AthenaGlobalConfig = {\r\n athena: {\r\n url: \"https://mirror3.athena-db.com\",\r\n apiKey: \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoiYXV0aGVudGljYXRlZCIsImVtYWlsIjoiZmxvcmlzQHh5bGV4LmFpIiwiZXhwIjoyNDk3MDMzNjY2fQ.LdPqTGaFq5pTokW1DA81WFjmG4nReJCOSKr3mFtXNoA\",\r\n client: \"athena_logging\",\r\n },\r\n};\r\n\r\nexport const DEFAULT_CONFIG_FILENAME = \"config.yaml\";\r\n\r\nfunction resolveConfigPath(configPath?: string): string {\r\n if (configPath) return path.resolve(configPath);\r\n return path.resolve(process.cwd(), DEFAULT_CONFIG_FILENAME);\r\n}\r\n\r\nlet cached: AthenaGlobalConfig | null = null;\r\nlet cachedConfigPath: string | null = null;\r\nlet version = 0;\r\n\r\nlet watcher: fs.FSWatcher | null = null;\r\n\r\nfunction isObject(value: unknown): value is Record<string, unknown> {\r\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\r\n}\r\n\r\nfunction deepMerge<T extends Record<string, unknown>>(\r\n base: T,\r\n partial: unknown,\r\n): T {\r\n if (!isObject(partial)) return base;\r\n const out: Record<string, unknown> = { ...base };\r\n for (const [k, v] of Object.entries(partial)) {\r\n if (v && isObject(v) && isObject(out[k])) {\r\n out[k] = deepMerge(out[k] as Record<string, unknown>, v);\r\n } else {\r\n out[k] = v;\r\n }\r\n }\r\n return out as T;\r\n}\r\n\r\nfunction ensureConfigFile(configPath: string): void {\r\n const dir = path.dirname(configPath);\r\n if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });\r\n\r\n if (!fs.existsSync(configPath)) {\r\n const yaml = YAML.stringify(defaultAthenaGlobalConfig);\r\n fs.writeFileSync(configPath, yaml, \"utf-8\");\r\n }\r\n}\r\n\r\nfunction readConfigFromDisk(configPath: string): AthenaGlobalConfig {\r\n ensureConfigFile(configPath);\r\n const raw = fs.readFileSync(configPath, \"utf-8\");\r\n const parsed = YAML.parse(raw) as unknown;\r\n return deepMerge(defaultAthenaGlobalConfig, parsed);\r\n}\r\n\r\nfunction startWatcher(configPath: string): void {\r\n // Avoid multiple watchers when multiple adapter instances are created.\r\n if (cachedConfigPath !== null && cachedConfigPath !== configPath && watcher) {\r\n try {\r\n watcher.close();\r\n } catch {\r\n // ignore\r\n }\r\n watcher = null;\r\n }\r\n if (watcher || cachedConfigPath === configPath) return;\r\n\r\n try {\r\n watcher = fs.watch(configPath, { persistent: false }, (event) => {\r\n if (event !== \"change\" && event !== \"rename\") return;\r\n try {\r\n cached = readConfigFromDisk(configPath);\r\n version += 1;\r\n } catch {\r\n // Keep last known good config if reload fails.\r\n }\r\n });\r\n cachedConfigPath = configPath;\r\n } catch {\r\n // If watching isn't supported in the environment, just run without it.\r\n }\r\n}\r\n\r\nexport function getAthenaGlobalConfig(options?: {\r\n configPath?: string;\r\n watch?: boolean;\r\n}): { config: AthenaGlobalConfig; version: number } {\r\n const configPath = resolveConfigPath(options?.configPath);\r\n const shouldWatch = options?.watch ?? true;\r\n\r\n if (!cached || cachedConfigPath !== configPath) {\r\n cached = readConfigFromDisk(configPath);\r\n cachedConfigPath = configPath;\r\n version += 1;\r\n }\r\n\r\n if (shouldWatch) startWatcher(configPath);\r\n\r\n return { config: cached, version };\r\n}\r\n","/**\r\n * Shared helpers and types for the Athena adapter.\r\n */\r\n\r\nexport function toSnakeCase(key: string): string {\r\n return key\r\n .replace(/([a-z0-9])([A-Z])/g, \"$1_$2\")\r\n .replace(/__/g, \"_\")\r\n .toLowerCase();\r\n}\r\n\r\nexport function toCamelCase(key: string): string {\r\n return key.replace(/_([a-z0-9])/g, (_, ch: string) => ch.toUpperCase());\r\n}\r\n\r\nexport function hasUppercase(key: string): boolean {\r\n return /[A-Z]/.test(key);\r\n}\r\n\r\nexport function mapKeys<T extends Record<string, unknown>>(\r\n obj: T,\r\n mapKey: (k: string) => string,\r\n): Record<string, unknown> {\r\n const out: Record<string, unknown> = {};\r\n for (const [k, v] of Object.entries(obj)) out[mapKey(k)] = v;\r\n return out;\r\n}\r\n\r\nexport function mapRowToBetterAuth<T>(row: T): T {\r\n if (!row || typeof row !== \"object\") return row;\r\n if (Array.isArray(row)) return row.map(mapRowToBetterAuth) as unknown as T;\r\n return mapKeys(row as Record<string, unknown>, toCamelCase) as T;\r\n}\r\n\r\nexport function isLikelyIsoDateString(value: string): boolean {\r\n if (!/^\\d{4}-\\d{2}-\\d{2}T/.test(value)) return false;\r\n const ms = Date.parse(value);\r\n return Number.isFinite(ms);\r\n}\r\n\r\nexport function isTimestampKey(key: string): boolean {\r\n return key.endsWith(\"At\") || key.endsWith(\"_at\") || key === \"expires\";\r\n}\r\n\r\nexport function coerceDateFields<T extends Record<string, unknown>>(data: T): T {\r\n const out: Record<string, unknown> = { ...data };\r\n for (const [key, val] of Object.entries(out)) {\r\n if (val == null) continue;\r\n if (\r\n typeof val === \"string\" &&\r\n isTimestampKey(key) &&\r\n isLikelyIsoDateString(val)\r\n ) {\r\n out[key] = new Date(val);\r\n }\r\n }\r\n return out as T;\r\n}\r\n\r\nexport function toDbRecord<T extends Record<string, unknown>>(\r\n data: T,\r\n): Record<string, unknown> {\r\n const withDbKeys = mapKeys(data, (k) =>\r\n hasUppercase(k) ? toSnakeCase(k) : k,\r\n );\r\n return coerceDateFields(withDbKeys);\r\n}\r\n\r\nexport type AthenaFilterBuilder = {\r\n eq(col: string, val: unknown): AthenaFilterBuilder;\r\n neq(col: string, val: unknown): AthenaFilterBuilder;\r\n gt(col: string, val: unknown): AthenaFilterBuilder;\r\n gte(col: string, val: unknown): AthenaFilterBuilder;\r\n lt(col: string, val: unknown): AthenaFilterBuilder;\r\n lte(col: string, val: unknown): AthenaFilterBuilder;\r\n in(col: string, vals: unknown[]): AthenaFilterBuilder;\r\n not(col: string, op?: string, val?: unknown): AthenaFilterBuilder;\r\n like(col: string, val: string): AthenaFilterBuilder;\r\n delete?(): { select(): Promise<{ data: unknown; error: unknown }> };\r\n select?(columns?: string): Promise<{ data: unknown; error: unknown }> | { select(): Promise<{ data: unknown; error: unknown }> };\r\n};\r\n\r\nexport type WhereClause = { field: string; operator: string; value: unknown };\r\n\r\nconst defaultColumnMapper = (col: string) =>\r\n hasUppercase(col) ? toSnakeCase(col) : col;\r\n\r\nexport function applyWhere(\r\n builder: AthenaFilterBuilder,\r\n field: string,\r\n operator: string,\r\n value: unknown,\r\n columnMapper: (col: string) => string = defaultColumnMapper,\r\n): AthenaFilterBuilder {\r\n const dbField = columnMapper(field);\r\n switch (operator) {\r\n case \"eq\":\r\n return builder.eq(dbField, value);\r\n case \"ne\":\r\n return builder.neq(dbField, value);\r\n case \"gt\":\r\n return builder.gt(dbField, value);\r\n case \"gte\":\r\n return builder.gte(dbField, value);\r\n case \"lt\":\r\n return builder.lt(dbField, value);\r\n case \"lte\":\r\n return builder.lte(dbField, value);\r\n case \"in\":\r\n return builder.in(dbField, value as unknown[]);\r\n case \"not_in\":\r\n return builder.not(dbField, \"in\", value);\r\n case \"contains\":\r\n return builder.like(dbField, `%${value}%`);\r\n case \"starts_with\":\r\n return builder.like(dbField, `${value}%`);\r\n case \"ends_with\":\r\n return builder.like(dbField, `%${value}`);\r\n default:\r\n return builder.eq(dbField, value);\r\n }\r\n}\r\n\r\nexport function isMissingColumnError(error: unknown): boolean {\r\n const msg = String(error ?? \"\");\r\n return (\r\n msg.includes(\"specified column does not exist\") ||\r\n msg.includes(\"column does not exist\")\r\n );\r\n}\r\n\r\n/** True when the Athena gateway returns a success message in the error field (treat as success). */\r\nexport function isSuccessMessageInError(error: unknown): boolean {\r\n const msg = String(error ?? \"\").toLowerCase();\r\n return (\r\n msg === \"data inserted successfully\" ||\r\n msg === \"data updated successfully\" ||\r\n msg === \"data deleted successfully\"\r\n );\r\n}\r\n\r\nexport function snakeMapper(col: string): string {\r\n return hasUppercase(col) ? toSnakeCase(col) : col;\r\n}\r\n\r\nexport function identityMapper(col: string): string {\r\n return col;\r\n}\r\n\r\n/** Get value from row by field name (camelCase or snake_case). */\r\nfunction getRowValue(row: Record<string, unknown>, field: string): unknown {\r\n if (Object.prototype.hasOwnProperty.call(row, field)) return row[field];\r\n const snake = hasUppercase(field) ? toSnakeCase(field) : field;\r\n return row[snake];\r\n}\r\n\r\n/**\r\n * Filter rows in-memory by where clauses (fallback when gateway does not apply filters).\r\n * Supports eq, ne, in, not_in; row keys may be camelCase or snake_case.\r\n */\r\nexport function filterRowsByWhere(\r\n rows: Record<string, unknown>[],\r\n where: WhereClause[],\r\n): Record<string, unknown>[] {\r\n if (!where.length) return rows;\r\n return rows.filter((row) => {\r\n for (const { field, operator, value } of where) {\r\n const rowVal = getRowValue(row, field);\r\n switch (operator) {\r\n case \"eq\":\r\n if (rowVal !== value) return false;\r\n break;\r\n case \"ne\":\r\n if (rowVal === value) return false;\r\n break;\r\n case \"in\":\r\n if (!Array.isArray(value) || !value.includes(rowVal)) return false;\r\n break;\r\n case \"not_in\":\r\n if (Array.isArray(value) && value.includes(rowVal)) return false;\r\n break;\r\n default:\r\n if (rowVal !== value) return false;\r\n }\r\n }\r\n return true;\r\n });\r\n}\r\n","import { toDbRecord, mapRowToBetterAuth, isSuccessMessageInError } from \"../utils\";\r\n\r\nexport type CreateDeps = {\r\n ensureDbClient: () => any;\r\n};\r\n\r\nexport function createMethod(deps: CreateDeps) {\r\n const { ensureDbClient } = deps;\r\n\r\n return async function create<T extends Record<string, unknown>>({\r\n model,\r\n data,\r\n }: {\r\n model: string;\r\n data: T;\r\n select?: string[];\r\n }) {\r\n const db = ensureDbClient();\r\n const insertData = toDbRecord(data);\r\n const { data: result, error } = await db\r\n .from(model)\r\n .insert(insertData)\r\n .select();\r\n\r\n if (error && !isSuccessMessageInError(error)) {\r\n throw new Error(`[AthenaAdapter] create on \"${model}\" failed: ${error}`);\r\n }\r\n\r\n const row = Array.isArray(result) ? result[0] : result;\r\n return mapRowToBetterAuth((row ?? insertData) as T);\r\n };\r\n}\r\n","import type { WhereClause, AthenaFilterBuilder } from \"../utils\";\r\nimport {\r\n toDbRecord,\r\n mapRowToBetterAuth,\r\n applyWhere,\r\n isSuccessMessageInError,\r\n} from \"../utils\";\r\n\r\nexport type UpdateDeps = {\r\n ensureDbClient: () => any;\r\n};\r\n\r\nexport function updateMethod(deps: UpdateDeps) {\r\n const { ensureDbClient } = deps;\r\n\r\n return async function update<T>({\r\n model,\r\n where,\r\n update,\r\n }: {\r\n model: string;\r\n where: WhereClause[];\r\n update: T;\r\n }) {\r\n const db = ensureDbClient();\r\n const updateData = toDbRecord(update as Record<string, unknown>);\r\n const debugUpdates = process?.env?.ATHENA_ADAPTER_DEBUG_UPDATES === \"1\";\r\n const debugLog = (event: string, extra?: Record<string, unknown>) => {\r\n if (!debugUpdates) return;\r\n console.info(\"[AthenaAdapter][update]\", {\r\n event,\r\n model,\r\n ...extra,\r\n });\r\n };\r\n const build = (useRetryShape: boolean) => {\r\n // Primary shape: modern gateway/client combinations accept plain update values.\r\n if (!useRetryShape) {\r\n let b = db.from(model).update(updateData as any) as AthenaFilterBuilder;\r\n for (const clause of where) {\r\n b = applyWhere(b, clause.field, clause.operator, clause.value);\r\n }\r\n return b;\r\n }\r\n\r\n // Retry shape: explicit wrappers for gateways expecting data/set.\r\n let b = db\r\n .from(model)\r\n .update(updateData as any, {\r\n updateBody: { data: updateData, set: updateData },\r\n } as any) as AthenaFilterBuilder;\r\n for (const clause of where) {\r\n b = applyWhere(b, clause.field, clause.operator, clause.value);\r\n }\r\n return b;\r\n };\r\n\r\n const run = async (b: AthenaFilterBuilder) => {\r\n const { data: result, error } = await (b as any).select();\r\n return { result, error };\r\n };\r\n\r\n const first = await run(build(false));\r\n if (first.error && !isSuccessMessageInError(first.error)) {\r\n debugLog(\"primary_failed\", { error: String(first.error) });\r\n const msg = String(first.error);\r\n if (msg.toLowerCase().includes(\"update payload required\")) {\r\n const retry = await run(build(true));\r\n if (retry.error && !isSuccessMessageInError(retry.error)) {\r\n debugLog(\"retry_failed\", { error: String(retry.error) });\r\n throw new Error(\r\n `[AthenaAdapter] update on \"${model}\" failed: ${retry.error}`,\r\n );\r\n }\r\n debugLog(\"retry_succeeded\", { shape: \"updateBody(data/set)\" });\r\n const row = Array.isArray(retry.result)\r\n ? (retry.result[0] as unknown)\r\n : (retry.result as unknown);\r\n return (row ? mapRowToBetterAuth(row as T) : null) as T | null;\r\n }\r\n\r\n throw new Error(`[AthenaAdapter] update on \"${model}\" failed: ${first.error}`);\r\n }\r\n\r\n debugLog(\"primary_succeeded\", { shape: \"plain\" });\r\n\r\n const row = Array.isArray(first.result)\r\n ? (first.result[0] as unknown)\r\n : (first.result as unknown);\r\n return (row ? mapRowToBetterAuth(row as T) : null) as T | null;\r\n };\r\n}\r\n","import type { WhereClause, AthenaFilterBuilder } from \"../utils\";\r\nimport { toDbRecord, applyWhere, isSuccessMessageInError } from \"../utils\";\r\n\r\nexport type UpdateManyDeps = {\r\n ensureDbClient: () => any;\r\n};\r\n\r\nexport function updateManyMethod(deps: UpdateManyDeps) {\r\n const { ensureDbClient } = deps;\r\n\r\n return async function updateMany({\r\n model,\r\n where,\r\n update,\r\n }: {\r\n model: string;\r\n where: WhereClause[];\r\n update: Record<string, unknown>;\r\n }) {\r\n const db = ensureDbClient();\r\n const updateData = toDbRecord(update);\r\n const debugUpdates = process.env.ATHENA_ADAPTER_DEBUG_UPDATES === \"1\";\r\n const debugLog = (event: string, extra?: Record<string, unknown>) => {\r\n if (!debugUpdates) return;\r\n console.info(\"[AthenaAdapter][updateMany]\", {\r\n event,\r\n model,\r\n ...extra,\r\n });\r\n };\r\n const build = (useRetryShape: boolean) => {\r\n if (!useRetryShape) {\r\n let b = db.from(model).update(updateData as any) as AthenaFilterBuilder;\r\n for (const clause of where) {\r\n b = applyWhere(b, clause.field, clause.operator, clause.value);\r\n }\r\n return b;\r\n }\r\n\r\n let b = db\r\n .from(model)\r\n .update(updateData as any, {\r\n updateBody: { data: updateData, set: updateData },\r\n } as any) as AthenaFilterBuilder;\r\n for (const clause of where) {\r\n b = applyWhere(b, clause.field, clause.operator, clause.value);\r\n }\r\n return b;\r\n };\r\n\r\n const run = async (b: AthenaFilterBuilder) => {\r\n const { data: result, error } = await (b as any).select();\r\n return { result, error };\r\n };\r\n\r\n const first = await run(build(false));\r\n if (first.error && !isSuccessMessageInError(first.error)) {\r\n debugLog(\"primary_failed\", { error: String(first.error) });\r\n const msg = String(first.error);\r\n if (msg.toLowerCase().includes(\"update payload required\")) {\r\n const retry = await run(build(true));\r\n if (retry.error && !isSuccessMessageInError(retry.error)) {\r\n debugLog(\"retry_failed\", { error: String(retry.error) });\r\n throw new Error(\r\n `[AthenaAdapter] updateMany on \"${model}\" failed: ${retry.error}`,\r\n );\r\n }\r\n debugLog(\"retry_succeeded\", { shape: \"updateBody(data/set)\" });\r\n return Array.isArray(retry.result) ? retry.result.length : retry.result ? 1 : 0;\r\n }\r\n\r\n throw new Error(\r\n `[AthenaAdapter] updateMany on \"${model}\" failed: ${first.error}`,\r\n );\r\n }\r\n\r\n debugLog(\"primary_succeeded\", { shape: \"plain\" });\r\n\r\n return Array.isArray(first.result) ? first.result.length : first.result ? 1 : 0;\r\n };\r\n}\r\n","import type { WhereClause, AthenaFilterBuilder } from \"../utils\";\r\nimport { applyWhere, isSuccessMessageInError } from \"../utils\";\r\n\r\nexport type DeleteDeps = {\r\n ensureDbClient: () => any;\r\n headers?: Record<string, string>;\r\n};\r\n\r\nexport function deleteMethod(deps: DeleteDeps) {\r\n const { ensureDbClient, headers } = deps;\r\n\r\n return async function del({\r\n model,\r\n where,\r\n }: {\r\n model: string;\r\n where: WhereClause[];\r\n }) {\r\n const db = ensureDbClient();\r\n let builder = db.from(model) as AthenaFilterBuilder;\r\n\r\n for (const clause of where) {\r\n builder = applyWhere(\r\n builder,\r\n clause.field,\r\n clause.operator,\r\n clause.value,\r\n );\r\n }\r\n\r\n const { error } = await (builder as any).delete(\r\n headers ? ({ headers } as any) : undefined,\r\n );\r\n\r\n if (error && !isSuccessMessageInError(error)) {\r\n throw new Error(\r\n `[AthenaAdapter] delete on \"${model}\" failed: ${error}`,\r\n );\r\n }\r\n };\r\n}\r\n","import type { WhereClause, AthenaFilterBuilder } from \"../utils\";\r\nimport { applyWhere, isSuccessMessageInError } from \"../utils\";\r\n\r\nexport type DeleteManyDeps = {\r\n ensureDbClient: () => any;\r\n headers?: Record<string, string>;\r\n};\r\n\r\nexport function deleteManyMethod(deps: DeleteManyDeps) {\r\n const { ensureDbClient, headers } = deps;\r\n\r\n return async function deleteMany({\r\n model,\r\n where,\r\n }: {\r\n model: string;\r\n where: WhereClause[];\r\n }) {\r\n const db = ensureDbClient();\r\n const mainBuilder = db.from(model) as AthenaFilterBuilder;\r\n let builder = mainBuilder;\r\n\r\n for (const clause of where) {\r\n builder = applyWhere(\r\n builder,\r\n clause.field,\r\n clause.operator,\r\n clause.value,\r\n );\r\n }\r\n\r\n const { data: result, error } = await (builder as any).delete(\r\n headers ? ({ headers } as any) : undefined,\r\n ).select();\r\n\r\n if (error && !isSuccessMessageInError(error)) {\r\n throw new Error(\r\n `[AthenaAdapter] deleteMany on \"${model}\" failed: ${error}`,\r\n );\r\n }\r\n\r\n const deletedCount = Array.isArray(result) ? result.length : result ? 1 : 0;\r\n // Fallback: if the live gateway doesn't apply `in` conditions correctly,\r\n // delete rows one-by-one so counts are stable for e2e tests.\r\n const inClause = where.find(\r\n (c) => c.operator === \"in\" && c.value != null,\r\n );\r\n if (\r\n inClause &&\r\n Array.isArray(inClause.value) &&\r\n deletedCount < inClause.value.length\r\n ) {\r\n let n = 0;\r\n for (const v of inClause.value) {\r\n const b = db.from(model);\r\n const filtered = applyWhere(\r\n b as any,\r\n inClause.field,\r\n \"eq\",\r\n v,\r\n );\r\n const { data: rowData, error: rowErr } = await (filtered as any).delete(\r\n headers ? ({ headers } as any) : undefined,\r\n ).select();\r\n if (rowErr && isSuccessMessageInError(rowErr)) continue;\r\n n += Array.isArray(rowData) ? rowData.length : rowData ? 1 : 0;\r\n }\r\n return n;\r\n }\r\n\r\n return deletedCount;\r\n };\r\n}\r\n","import type { WhereClause } from \"../utils\";\r\nimport {\r\n applyWhere,\r\n mapRowToBetterAuth,\r\n isMissingColumnError,\r\n snakeMapper,\r\n identityMapper,\r\n filterRowsByWhere,\r\n} from \"../utils\";\r\n\r\nexport type FindOneDeps = {\r\n ensureDbClient: () => any;\r\n};\r\n\r\nexport function findOneMethod(deps: FindOneDeps) {\r\n const { ensureDbClient } = deps;\r\n\r\n return async function findOne<T>({\r\n model,\r\n where,\r\n select,\r\n }: {\r\n model: string;\r\n where: WhereClause[];\r\n select?: string[];\r\n join?: unknown;\r\n }) {\r\n const db = ensureDbClient();\r\n\r\n const run = async (columnMapper: (col: string) => string) => {\r\n const columns =\r\n select && select.length > 0\r\n ? select.map((c) => columnMapper(c)).join(\", \")\r\n : undefined;\r\n\r\n let builder = db.from(model).select(columns);\r\n\r\n for (const clause of where) {\r\n builder = applyWhere(\r\n builder,\r\n clause.field,\r\n clause.operator,\r\n clause.value,\r\n columnMapper,\r\n );\r\n }\r\n\r\n const { data: result, error } = await builder.limit(1);\r\n return { result, error };\r\n };\r\n\r\n const first = await run(snakeMapper);\r\n if (first.error) {\r\n if (isMissingColumnError(first.error)) {\r\n const retry = await run(identityMapper);\r\n if (retry.error) {\r\n throw new Error(\r\n `[AthenaAdapter] findOne on \"${model}\" failed: ${retry.error}`,\r\n );\r\n }\r\n\r\n const rows = Array.isArray(retry.result)\r\n ? retry.result\r\n : retry.result\r\n ? [retry.result]\r\n : [];\r\n const row = rows[0] ?? null;\r\n return (row ? mapRowToBetterAuth(row as T) : null) as T | null;\r\n }\r\n\r\n throw new Error(\r\n `[AthenaAdapter] findOne on \"${model}\" failed: ${first.error}`,\r\n );\r\n }\r\n\r\n const rows = Array.isArray(first.result)\r\n ? first.result\r\n : first.result\r\n ? [first.result]\r\n : [];\r\n const row = rows[0] ?? null;\r\n if (!row) return null;\r\n\r\n const mapped = mapRowToBetterAuth(row as T) as T;\r\n const filtered = filterRowsByWhere(\r\n [mapped as unknown as Record<string, unknown>],\r\n where,\r\n );\r\n return (filtered[0] ? mapped : null) as T | null;\r\n };\r\n}\r\n","import type { WhereClause } from \"../utils\";\r\nimport {\r\n applyWhere,\r\n mapRowToBetterAuth,\r\n isMissingColumnError,\r\n snakeMapper,\r\n identityMapper,\r\n filterRowsByWhere,\r\n} from \"../utils\";\r\n\r\nexport type FindManyDeps = {\r\n ensureDbClient: () => any;\r\n};\r\n\r\nexport function findManyMethod(deps: FindManyDeps) {\r\n const { ensureDbClient } = deps;\r\n\r\n const isTransientGatewayError = (error: unknown): boolean => {\r\n const message = String(error ?? \"\").toLowerCase();\r\n return (\r\n message.includes(\"application failed to respond\") ||\r\n message.includes(\"timeout\") ||\r\n message.includes(\"timed out\") ||\r\n message.includes(\"gateway timeout\") ||\r\n message.includes(\"econnreset\") ||\r\n message.includes(\"connection reset\")\r\n );\r\n };\r\n\r\n return async function findMany<T>({\r\n model,\r\n where,\r\n limit,\r\n sortBy,\r\n offset,\r\n select,\r\n }: {\r\n model: string;\r\n where?: WhereClause[];\r\n limit: number;\r\n select?: string[];\r\n sortBy?: { field: string; direction: \"asc\" | \"desc\" };\r\n offset?: number;\r\n join?: unknown;\r\n }) {\r\n const db = ensureDbClient();\r\n\r\n const run = async (\r\n columnMapper: (col: string) => string,\r\n opts?: { skipWhere?: boolean; limitOverride?: number; offsetOverride?: number },\r\n ) => {\r\n const columns =\r\n select && select.length > 0\r\n ? select.map((c) => columnMapper(c)).join(\", \")\r\n : undefined;\r\n\r\n let builder = db.from(model).select(columns);\r\n\r\n if (!opts?.skipWhere && where) {\r\n for (const clause of where) {\r\n builder = applyWhere(\r\n builder,\r\n clause.field,\r\n clause.operator,\r\n clause.value,\r\n columnMapper,\r\n );\r\n }\r\n }\r\n\r\n const effectiveLimit = opts?.limitOverride ?? limit;\r\n const effectiveOffset = opts?.offsetOverride ?? offset;\r\n\r\n if (effectiveLimit !== undefined) {\r\n builder = builder.limit(effectiveLimit);\r\n }\r\n\r\n if (effectiveOffset !== undefined) {\r\n builder = builder.offset(effectiveOffset);\r\n }\r\n\r\n const { data: result, error } = await builder;\r\n return { result, error };\r\n };\r\n\r\n let first = await run(snakeMapper);\r\n if (first.error && isTransientGatewayError(first.error)) {\r\n const retry = await run(snakeMapper);\r\n if (!retry.error) first = retry;\r\n }\r\n\r\n const pickRows = (res: unknown) =>\r\n (Array.isArray(res) ? res : []) as Record<string, unknown>[];\r\n\r\n const applySort = (rows: T[]) => {\r\n if (!sortBy) return rows;\r\n const sortField = sortBy.field;\r\n rows.sort((a, b) => {\r\n const aVal = (a as Record<string, unknown>)[sortField];\r\n const bVal = (b as Record<string, unknown>)[sortField];\r\n if (aVal == null && bVal == null) return 0;\r\n if (aVal == null) return sortBy.direction === \"asc\" ? -1 : 1;\r\n if (bVal == null) return sortBy.direction === \"asc\" ? 1 : -1;\r\n const cmp =\r\n typeof aVal === \"string\" && typeof bVal === \"string\"\r\n ? aVal.localeCompare(bVal)\r\n : aVal < bVal\r\n ? -1\r\n : aVal > bVal\r\n ? 1\r\n : 0;\r\n return sortBy.direction === \"asc\" ? cmp : -cmp;\r\n });\r\n return rows;\r\n };\r\n\r\n const mapAndSort = (rows: Record<string, unknown>[]) => {\r\n const betterAuthRows = rows.map((r) => mapRowToBetterAuth(r)) as unknown as T[];\r\n\r\n if (!where?.length) return applySort(betterAuthRows);\r\n\r\n const filtered = filterRowsByWhere(\r\n betterAuthRows as unknown as Record<string, unknown>[],\r\n where,\r\n ) as unknown as T[];\r\n\r\n // If filtering changed the row set, the gateway likely ignored `where`\r\n // (or applied it before limiting/offset). In that case, re-apply sorting\r\n // and slice using the requested offset/limit.\r\n if (filtered.length !== betterAuthRows.length) {\r\n const off = offset ?? 0;\r\n const end = limit !== undefined ? off + limit : undefined;\r\n return applySort(filtered).slice(off, end);\r\n }\r\n\r\n return applySort(filtered);\r\n };\r\n\r\n const postFilterAndSlice = (rows: Record<string, unknown>[]) => {\r\n const mappedSorted = mapAndSort(rows);\r\n const off = offset ?? 0;\r\n const end = limit !== undefined ? off + limit : undefined;\r\n return mappedSorted.slice(off, end);\r\n };\r\n\r\n if (first.error) {\r\n if (isMissingColumnError(first.error)) {\r\n const retry = await run(identityMapper);\r\n if (retry.error) {\r\n throw new Error(\r\n `[AthenaAdapter] findMany on \"${model}\" failed: ${retry.error}`,\r\n );\r\n }\r\n const retryRows = pickRows(retry.result);\r\n // Decisive fallback: if gateway-side `where` yields empty/insufficient rows,\r\n // fetch a broader candidate set and apply `where`/sort/offset/limit in-memory.\r\n if (where?.length) {\r\n const broad = await run(identityMapper, {\r\n skipWhere: true,\r\n limitOverride: Math.max((offset ?? 0) + (limit ?? 0) + 500, 5000),\r\n offsetOverride: 0,\r\n });\r\n if (!broad.error) return postFilterAndSlice(pickRows(broad.result));\r\n }\r\n return mapAndSort(retryRows);\r\n }\r\n\r\n throw new Error(\r\n `[AthenaAdapter] findMany on \"${model}\" failed: ${first.error}`,\r\n );\r\n }\r\n\r\n const firstRows = pickRows(first.result);\r\n if (where?.length) {\r\n const broad = await run(snakeMapper, {\r\n skipWhere: true,\r\n limitOverride: Math.max((offset ?? 0) + (limit ?? 0) + 500, 5000),\r\n offsetOverride: 0,\r\n });\r\n if (!broad.error) return postFilterAndSlice(pickRows(broad.result));\r\n }\r\n return mapAndSort(firstRows);\r\n };\r\n}\r\n","import type { WhereClause } from \"../utils\";\r\nimport {\r\n applyWhere,\r\n isMissingColumnError,\r\n snakeMapper,\r\n identityMapper,\r\n} from \"../utils\";\r\n\r\nexport type CountDeps = {\r\n ensureDbClient: () => any;\r\n};\r\n\r\nexport function countMethod(deps: CountDeps) {\r\n const { ensureDbClient } = deps;\r\n\r\n return async function count({\r\n model,\r\n where,\r\n }: {\r\n model: string;\r\n where?: WhereClause[];\r\n }) {\r\n const db = ensureDbClient();\r\n\r\n const run = async (columnMapper: (col: string) => string) => {\r\n let builder = db.from(model).select();\r\n\r\n if (where) {\r\n for (const clause of where) {\r\n builder = applyWhere(\r\n builder,\r\n clause.field,\r\n clause.operator,\r\n clause.value,\r\n columnMapper,\r\n );\r\n }\r\n }\r\n\r\n const { data: result, error } = await builder;\r\n return { result, error };\r\n };\r\n\r\n const first = await run(snakeMapper);\r\n if (first.error) {\r\n if (isMissingColumnError(first.error)) {\r\n const retry = await run(identityMapper);\r\n if (retry.error) {\r\n throw new Error(\r\n `[AthenaAdapter] count on \"${model}\" failed: ${retry.error}`,\r\n );\r\n }\r\n return Array.isArray(retry.result) ? retry.result.length : 0;\r\n }\r\n throw new Error(\r\n `[AthenaAdapter] count on \"${model}\" failed: ${first.error}`,\r\n );\r\n }\r\n\r\n return Array.isArray(first.result) ? first.result.length : 0;\r\n };\r\n}\r\n"],"mappings":"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","names":["b","row","b","rows","row","version"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/config.ts","../src/utils.ts","../src/methods/create.ts","../src/methods/update.ts","../src/methods/update-many.ts","../src/methods/delete.ts","../src/methods/delete-many.ts","../src/methods/find-one.ts","../src/methods/find-many.ts","../src/methods/count.ts"],"sourcesContent":["import {\r\n createAdapterFactory,\r\n type AdapterFactory,\r\n type DBAdapterDebugLogOption,\r\n} from \"better-auth/adapters\";\r\nimport type { BetterAuthOptions } from \"better-auth\";\r\nimport { createClient } from \"@xylex-group/athena\";\r\nimport { getAthenaGlobalConfig } from \"./config\";\r\nimport { createMethod } from \"./methods/create\";\r\nimport { updateMethod } from \"./methods/update\";\r\nimport { updateManyMethod } from \"./methods/update-many\";\r\nimport { deleteMethod } from \"./methods/delete\";\r\nimport { deleteManyMethod } from \"./methods/delete-many\";\r\nimport { findOneMethod } from \"./methods/find-one\";\r\nimport { findManyMethod } from \"./methods/find-many\";\r\nimport { countMethod } from \"./methods/count\";\r\n\r\n/**\r\n * Configuration options for the Athena adapter.\r\n */\r\nexport interface AthenaAdapterConfig {\r\n /**\r\n * The URL of your Athena gateway.\r\n */\r\n url?: string;\r\n /**\r\n * The API key for authenticating with the Athena gateway.\r\n */\r\n apiKey?: string;\r\n /**\r\n * The client name sent in requests to the Athena gateway.\r\n */\r\n client?: string;\r\n\r\n /**\r\n * Optional override for the YAML config path.\r\n * Defaults to `./config.yaml` (resolved from `process.cwd()`).\r\n */\r\n configPath?: string;\r\n\r\n /**\r\n * When enabled, the adapter will reload `config.yaml` on changes.\r\n *\r\n * @default true\r\n */\r\n watchConfig?: boolean;\r\n /**\r\n * Helps you debug issues with the adapter.\r\n */\r\n debugLogs?: DBAdapterDebugLogOption;\r\n /**\r\n * If the table names in the schema are plural.\r\n *\r\n * @default false\r\n */\r\n usePlural?: boolean;\r\n\r\n /**\r\n * Optional headers sent with every request (e.g. `X-User-Id` if your gateway requires it for delete).\r\n */\r\n headers?: Record<string, string>;\r\n}\r\n\r\n/**\r\n * Create a Better-Auth database adapter backed by @xylex-group/athena.\r\n *\r\n * Column names are kept in snake_case as required by the Athena gateway.\r\n *\r\n * @example\r\n * ```ts\r\n * import { betterAuth } from \"better-auth\";\r\n * import { athenaAdapter } from \"better-auth-athena\";\r\n *\r\n * export const auth = betterAuth({\r\n * database: athenaAdapter({\r\n * url: process.env.ATHENA_URL!,\r\n * apiKey: process.env.ATHENA_API_KEY!,\r\n * client: \"my-app\",\r\n * }),\r\n * });\r\n * ```\r\n */\r\nexport const athenaAdapter = (\r\n config: AthenaAdapterConfig,\r\n): AdapterFactory<BetterAuthOptions> => {\r\n let dbClient: any | null = null;\r\n let lastDbConfigVersion = -1;\r\n\r\n const shouldUseFixedConfig =\r\n typeof config.url === \"string\" &&\r\n config.url.length > 0 &&\r\n typeof config.apiKey === \"string\" &&\r\n config.apiKey.length > 0;\r\n\r\n function ensureDbClient(): any {\r\n if (shouldUseFixedConfig) {\r\n if (!dbClient) {\r\n dbClient = createClient(config.url!, config.apiKey!, {\r\n client: config.client,\r\n ...(config.headers && { headers: config.headers }),\r\n } as any);\r\n }\r\n return dbClient;\r\n }\r\n\r\n const { config: globalConfig, version } = getAthenaGlobalConfig({\r\n configPath: config.configPath,\r\n watch: config.watchConfig ?? true,\r\n });\r\n\r\n const url = config.url ?? globalConfig.athena.url;\r\n const apiKey = config.apiKey ?? globalConfig.athena.apiKey;\r\n const client = config.client ?? globalConfig.athena.client;\r\n\r\n if (!url || !apiKey) {\r\n throw new Error(\r\n `[AthenaAdapter] Missing Athena connection details. Set both 'athena.url' and 'athena.apiKey' in config.yaml (or pass 'url'/'apiKey' to athenaAdapter).`,\r\n );\r\n }\r\n\r\n if (!dbClient || version !== lastDbConfigVersion) {\r\n dbClient = createClient(url, apiKey, {\r\n client,\r\n ...(config.headers && { headers: config.headers }),\r\n } as any);\r\n lastDbConfigVersion = version;\r\n }\r\n\r\n return dbClient;\r\n }\r\n\r\n function getConnectionConfig() {\r\n if (shouldUseFixedConfig) {\r\n return {\r\n url: config.url!,\r\n apiKey: config.apiKey!,\r\n client: config.client,\r\n headers: config.headers,\r\n };\r\n }\r\n const { config: globalConfig } = getAthenaGlobalConfig({\r\n configPath: config.configPath,\r\n watch: false,\r\n });\r\n return {\r\n url: config.url ?? globalConfig.athena.url,\r\n apiKey: config.apiKey ?? globalConfig.athena.apiKey,\r\n client: config.client ?? globalConfig.athena.client,\r\n headers: config.headers,\r\n };\r\n }\r\n\r\n const deps = { ensureDbClient, getConnectionConfig, headers: config.headers };\r\n\r\n return createAdapterFactory({\r\n config: {\r\n adapterId: \"athena\",\r\n adapterName: \"Athena Adapter\",\r\n usePlural: config.usePlural ?? false,\r\n debugLogs: config.debugLogs ?? false,\r\n supportsJSON: true,\r\n supportsDates: true,\r\n supportsBooleans: true,\r\n supportsNumericIds: true,\r\n supportsUUIDs: true,\r\n supportsArrays: true,\r\n },\r\n adapter: () => {\r\n return {\r\n create: createMethod(deps),\r\n update: updateMethod(deps),\r\n updateMany: updateManyMethod(deps),\r\n delete: deleteMethod(deps),\r\n deleteMany: deleteManyMethod(deps),\r\n findOne: findOneMethod(deps),\r\n findMany: findManyMethod(deps),\r\n count: countMethod(deps),\r\n options: {\r\n debugLogs: config.debugLogs ?? false,\r\n\r\n },\r\n };\r\n },\r\n });\r\n};\r\n\r\n// For testing purposes, we export the internal config function to allow resetting the cached client between tests.\r\nexport { getAthenaGlobalConfig } from \"./config\";\r\n","import fs from \"node:fs\";\r\nimport path from \"node:path\";\r\nimport YAML from \"yaml\";\r\n\r\nexport type AthenaGlobalConfig = {\r\n athena: {\r\n url: string;\r\n apiKey: string;\r\n client?: string;\r\n };\r\n};\r\n\r\n// Defaults written to `config.yaml` if it doesn't exist.\r\n// These values are intentionally placeholders; the adapter will throw if\r\n// `url`/`apiKey` are still unset when used.\r\nexport const defaultAthenaGlobalConfig: AthenaGlobalConfig = {\r\n athena: {\r\n url: \"https://mirror3.athena-db.com\",\r\n apiKey: \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoiYXV0aGVudGljYXRlZCIsImVtYWlsIjoiZmxvcmlzQHh5bGV4LmFpIiwiZXhwIjoyNDk3MDMzNjY2fQ.LdPqTGaFq5pTokW1DA81WFjmG4nReJCOSKr3mFtXNoA\",\r\n client: \"athena_logging\",\r\n },\r\n};\r\n\r\nexport const DEFAULT_CONFIG_FILENAME = \"config.yaml\";\r\n\r\nfunction resolveConfigPath(configPath?: string): string {\r\n if (configPath) return path.resolve(configPath);\r\n return path.resolve(process.cwd(), DEFAULT_CONFIG_FILENAME);\r\n}\r\n\r\nlet cached: AthenaGlobalConfig | null = null;\r\nlet cachedConfigPath: string | null = null;\r\nlet version = 0;\r\n\r\nlet watcher: fs.FSWatcher | null = null;\r\n\r\nfunction isObject(value: unknown): value is Record<string, unknown> {\r\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\r\n}\r\n\r\nfunction deepMerge<T extends Record<string, unknown>>(\r\n base: T,\r\n partial: unknown,\r\n): T {\r\n if (!isObject(partial)) return base;\r\n const out: Record<string, unknown> = { ...base };\r\n for (const [k, v] of Object.entries(partial)) {\r\n if (v && isObject(v) && isObject(out[k])) {\r\n out[k] = deepMerge(out[k] as Record<string, unknown>, v);\r\n } else {\r\n out[k] = v;\r\n }\r\n }\r\n return out as T;\r\n}\r\n\r\nfunction ensureConfigFile(configPath: string): void {\r\n const dir = path.dirname(configPath);\r\n if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });\r\n\r\n if (!fs.existsSync(configPath)) {\r\n const yaml = YAML.stringify(defaultAthenaGlobalConfig);\r\n fs.writeFileSync(configPath, yaml, \"utf-8\");\r\n }\r\n}\r\n\r\nfunction readConfigFromDisk(configPath: string): AthenaGlobalConfig {\r\n ensureConfigFile(configPath);\r\n const raw = fs.readFileSync(configPath, \"utf-8\");\r\n const parsed = YAML.parse(raw) as unknown;\r\n return deepMerge(defaultAthenaGlobalConfig, parsed);\r\n}\r\n\r\nfunction startWatcher(configPath: string): void {\r\n // Avoid multiple watchers when multiple adapter instances are created.\r\n if (cachedConfigPath !== null && cachedConfigPath !== configPath && watcher) {\r\n try {\r\n watcher.close();\r\n } catch {\r\n // ignore\r\n }\r\n watcher = null;\r\n }\r\n if (watcher || cachedConfigPath === configPath) return;\r\n\r\n try {\r\n watcher = fs.watch(configPath, { persistent: false }, (event) => {\r\n if (event !== \"change\" && event !== \"rename\") return;\r\n try {\r\n cached = readConfigFromDisk(configPath);\r\n version += 1;\r\n } catch {\r\n // Keep last known good config if reload fails.\r\n }\r\n });\r\n cachedConfigPath = configPath;\r\n } catch {\r\n // If watching isn't supported in the environment, just run without it.\r\n }\r\n}\r\n\r\nexport function getAthenaGlobalConfig(options?: {\r\n configPath?: string;\r\n watch?: boolean;\r\n}): { config: AthenaGlobalConfig; version: number } {\r\n const configPath = resolveConfigPath(options?.configPath);\r\n const shouldWatch = options?.watch ?? true;\r\n\r\n if (!cached || cachedConfigPath !== configPath) {\r\n cached = readConfigFromDisk(configPath);\r\n cachedConfigPath = configPath;\r\n version += 1;\r\n }\r\n\r\n if (shouldWatch) startWatcher(configPath);\r\n\r\n return { config: cached, version };\r\n}\r\n","/**\r\n * Shared helpers and types for the Athena adapter.\r\n */\r\n\r\nexport function toSnakeCase(key: string): string {\r\n return key\r\n .replace(/([a-z0-9])([A-Z])/g, \"$1_$2\")\r\n .replace(/__/g, \"_\")\r\n .toLowerCase();\r\n}\r\n\r\nexport function toCamelCase(key: string): string {\r\n return key.replace(/_([a-z0-9])/g, (_, ch: string) => ch.toUpperCase());\r\n}\r\n\r\nexport function hasUppercase(key: string): boolean {\r\n return /[A-Z]/.test(key);\r\n}\r\n\r\nexport function mapKeys<T extends Record<string, unknown>>(\r\n obj: T,\r\n mapKey: (k: string) => string,\r\n): Record<string, unknown> {\r\n const out: Record<string, unknown> = {};\r\n for (const [k, v] of Object.entries(obj)) out[mapKey(k)] = v;\r\n return out;\r\n}\r\n\r\nexport function mapRowToBetterAuth<T>(row: T): T {\r\n if (!row || typeof row !== \"object\") return row;\r\n if (Array.isArray(row)) return row.map(mapRowToBetterAuth) as unknown as T;\r\n return mapKeys(row as Record<string, unknown>, toCamelCase) as T;\r\n}\r\n\r\nexport function isLikelyIsoDateString(value: string): boolean {\r\n if (!/^\\d{4}-\\d{2}-\\d{2}T/.test(value)) return false;\r\n const ms = Date.parse(value);\r\n return Number.isFinite(ms);\r\n}\r\n\r\nexport function isTimestampKey(key: string): boolean {\r\n return key.endsWith(\"At\") || key.endsWith(\"_at\") || key === \"expires\";\r\n}\r\n\r\nexport function coerceDateFields<T extends Record<string, unknown>>(data: T): T {\r\n const out: Record<string, unknown> = { ...data };\r\n for (const [key, val] of Object.entries(out)) {\r\n if (val == null) continue;\r\n if (\r\n typeof val === \"string\" &&\r\n isTimestampKey(key) &&\r\n isLikelyIsoDateString(val)\r\n ) {\r\n out[key] = new Date(val);\r\n }\r\n }\r\n return out as T;\r\n}\r\n\r\nexport function toDbRecord<T extends Record<string, unknown>>(\r\n data: T,\r\n): Record<string, unknown> {\r\n const withDbKeys = mapKeys(data, (k) =>\r\n hasUppercase(k) ? toSnakeCase(k) : k,\r\n );\r\n return coerceDateFields(withDbKeys);\r\n}\r\n\r\nexport type AthenaFilterBuilder = {\r\n eq(col: string, val: unknown): AthenaFilterBuilder;\r\n neq(col: string, val: unknown): AthenaFilterBuilder;\r\n gt(col: string, val: unknown): AthenaFilterBuilder;\r\n gte(col: string, val: unknown): AthenaFilterBuilder;\r\n lt(col: string, val: unknown): AthenaFilterBuilder;\r\n lte(col: string, val: unknown): AthenaFilterBuilder;\r\n in(col: string, vals: unknown[]): AthenaFilterBuilder;\r\n not(col: string, op?: string, val?: unknown): AthenaFilterBuilder;\r\n like(col: string, val: string): AthenaFilterBuilder;\r\n delete?(): { select(): Promise<{ data: unknown; error: unknown }> };\r\n select?(columns?: string): Promise<{ data: unknown; error: unknown }> | { select(): Promise<{ data: unknown; error: unknown }> };\r\n};\r\n\r\nexport type WhereClause = { field: string; operator: string; value: unknown };\r\n\r\nconst defaultColumnMapper = (col: string) =>\r\n hasUppercase(col) ? toSnakeCase(col) : col;\r\n\r\nexport function applyWhere(\r\n builder: AthenaFilterBuilder,\r\n field: string,\r\n operator: string,\r\n value: unknown,\r\n columnMapper: (col: string) => string = defaultColumnMapper,\r\n): AthenaFilterBuilder {\r\n const dbField = columnMapper(field);\r\n switch (operator) {\r\n case \"eq\":\r\n return builder.eq(dbField, value);\r\n case \"ne\":\r\n return builder.neq(dbField, value);\r\n case \"gt\":\r\n return builder.gt(dbField, value);\r\n case \"gte\":\r\n return builder.gte(dbField, value);\r\n case \"lt\":\r\n return builder.lt(dbField, value);\r\n case \"lte\":\r\n return builder.lte(dbField, value);\r\n case \"in\":\r\n return builder.in(dbField, value as unknown[]);\r\n case \"not_in\":\r\n return builder.not(dbField, \"in\", value);\r\n case \"contains\":\r\n return builder.like(dbField, `%${value}%`);\r\n case \"starts_with\":\r\n return builder.like(dbField, `${value}%`);\r\n case \"ends_with\":\r\n return builder.like(dbField, `%${value}`);\r\n default:\r\n return builder.eq(dbField, value);\r\n }\r\n}\r\n\r\nexport function isMissingColumnError(error: unknown): boolean {\r\n const msg = String(error ?? \"\");\r\n return (\r\n msg.includes(\"specified column does not exist\") ||\r\n msg.includes(\"column does not exist\")\r\n );\r\n}\r\n\r\n/** True when the Athena gateway returns a success message in the error field (treat as success). */\r\nexport function isSuccessMessageInError(error: unknown): boolean {\r\n const msg = String(error ?? \"\").toLowerCase();\r\n return (\r\n msg === \"data inserted successfully\" ||\r\n msg === \"data updated successfully\" ||\r\n msg === \"data deleted successfully\"\r\n );\r\n}\r\n\r\nexport function snakeMapper(col: string): string {\r\n return hasUppercase(col) ? toSnakeCase(col) : col;\r\n}\r\n\r\nexport function identityMapper(col: string): string {\r\n return col;\r\n}\r\n\r\n/** Get value from row by field name (camelCase or snake_case). */\r\nfunction getRowValue(row: Record<string, unknown>, field: string): unknown {\r\n if (Object.prototype.hasOwnProperty.call(row, field)) return row[field];\r\n const snake = hasUppercase(field) ? toSnakeCase(field) : field;\r\n return row[snake];\r\n}\r\n\r\n/**\r\n * Filter rows in-memory by where clauses (fallback when gateway does not apply filters).\r\n * Supports eq, ne, in, not_in; row keys may be camelCase or snake_case.\r\n */\r\nexport function filterRowsByWhere(\r\n rows: Record<string, unknown>[],\r\n where: WhereClause[],\r\n): Record<string, unknown>[] {\r\n if (!where.length) return rows;\r\n return rows.filter((row) => {\r\n for (const { field, operator, value } of where) {\r\n const rowVal = getRowValue(row, field);\r\n switch (operator) {\r\n case \"eq\":\r\n if (rowVal !== value) return false;\r\n break;\r\n case \"ne\":\r\n if (rowVal === value) return false;\r\n break;\r\n case \"in\":\r\n if (!Array.isArray(value) || !value.includes(rowVal)) return false;\r\n break;\r\n case \"not_in\":\r\n if (Array.isArray(value) && value.includes(rowVal)) return false;\r\n break;\r\n default:\r\n if (rowVal !== value) return false;\r\n }\r\n }\r\n return true;\r\n });\r\n}\r\n","import { toDbRecord, mapRowToBetterAuth, isSuccessMessageInError } from \"../utils\";\r\n\r\nexport type CreateDeps = {\r\n ensureDbClient: () => any;\r\n};\r\n\r\nexport function createMethod(deps: CreateDeps) {\r\n const { ensureDbClient } = deps;\r\n\r\n return async function create<T extends Record<string, unknown>>({\r\n model,\r\n data,\r\n }: {\r\n model: string;\r\n data: T;\r\n select?: string[];\r\n }) {\r\n const db = ensureDbClient();\r\n const insertData = toDbRecord(data);\r\n const { data: result, error } = await db\r\n .from(model)\r\n .insert(insertData)\r\n .select();\r\n\r\n if (error && !isSuccessMessageInError(error)) {\r\n throw new Error(`[AthenaAdapter] create on \"${model}\" failed: ${error}`);\r\n }\r\n\r\n const row = Array.isArray(result) ? result[0] : result;\r\n return mapRowToBetterAuth((row ?? insertData) as T);\r\n };\r\n}\r\n","import type { WhereClause, AthenaFilterBuilder } from \"../utils\";\r\nimport {\r\n toDbRecord,\r\n mapRowToBetterAuth,\r\n applyWhere,\r\n isSuccessMessageInError,\r\n toSnakeCase,\r\n hasUppercase,\r\n} from \"../utils\";\r\n\r\nexport type GatewayConnectionConfig = {\r\n url: string;\r\n apiKey: string;\r\n client?: string;\r\n headers?: Record<string, string>;\r\n};\r\n\r\nexport type UpdateDeps = {\r\n ensureDbClient: () => any;\r\n getConnectionConfig: () => GatewayConnectionConfig;\r\n};\r\n\r\nexport function updateMethod(deps: UpdateDeps) {\r\n const { ensureDbClient } = deps;\r\n\r\n return async function update<T>({\r\n model,\r\n where,\r\n update,\r\n }: {\r\n model: string;\r\n where: WhereClause[];\r\n update: T;\r\n }) {\r\n const db = ensureDbClient();\r\n const updateData = toDbRecord(update as Record<string, unknown>);\r\n const debugUpdates = process?.env?.ATHENA_ADAPTER_DEBUG_UPDATES === \"1\";\r\n const debugLog = (event: string, extra?: Record<string, unknown>) => {\r\n if (!debugUpdates) return;\r\n console.info(\"[AthenaAdapter][update]\", { event, model, ...extra });\r\n };\r\n\r\n // Build an Athena filter-builder chain with one of two update_body shapes.\r\n const build = (shape: \"plain\" | \"wrapped\") => {\r\n const values =\r\n shape === \"plain\"\r\n ? (updateData as any)\r\n : ({ data: updateData, set: updateData } as any);\r\n let b = db.from(model).update(values) as AthenaFilterBuilder;\r\n for (const clause of where) {\r\n b = applyWhere(b, clause.field, clause.operator, clause.value);\r\n }\r\n return b;\r\n };\r\n\r\n const run = async (b: AthenaFilterBuilder) => {\r\n const { data: result, error } = await (b as any).select();\r\n return { result, error };\r\n };\r\n\r\n // Direct fetch to the gateway — bypasses update_body wrapping entirely.\r\n // Tries top-level { data, set } then top-level { columns: [...] }.\r\n const directGatewayUpdate = async () => {\r\n const { url, apiKey, client, headers: extraHeaders } = deps.getConnectionConfig();\r\n const base = url.replace(/\\/$/, \"\");\r\n const conditions = where.map((clause) => {\r\n const column = hasUppercase(clause.field) ? toSnakeCase(clause.field) : clause.field;\r\n const value = clause.value;\r\n switch (clause.operator) {\r\n case \"ne\": return { operator: \"neq\", column, value };\r\n case \"contains\": return { operator: \"like\", column, value: `%${value}%` };\r\n case \"starts_with\": return { operator: \"like\", column, value: `${String(value)}%` };\r\n case \"ends_with\": return { operator: \"like\", column, value: `%${String(value)}` };\r\n case \"eq\": return { operator: \"eq\", column, eq_column: column, value, eq_value: value };\r\n default: return { operator: clause.operator, column, value };\r\n }\r\n });\r\n const requestHeaders: Record<string, string> = {\r\n \"Content-Type\": \"application/json\",\r\n \"apikey\": apiKey,\r\n \"x-api-key\": apiKey,\r\n \"X-Athena-Client\": client ?? \"railway_direct\",\r\n \"X-Backend-Type\": \"athena\",\r\n \"X-Strip-Nulls\": \"true\",\r\n ...(extraHeaders ?? {}),\r\n };\r\n const payloads = [\r\n { table_name: model, data: updateData, set: updateData, conditions, strip_nulls: true },\r\n {\r\n table_name: model,\r\n columns: Object.entries(updateData).map(([column, value]) => ({ column, value })),\r\n conditions,\r\n strip_nulls: true,\r\n },\r\n ];\r\n for (const payload of payloads) {\r\n const res = await fetch(`${base}/gateway/update`, {\r\n method: \"POST\",\r\n headers: requestHeaders,\r\n body: JSON.stringify(payload),\r\n });\r\n const raw = await res.text();\r\n let parsed: any = null;\r\n try { parsed = JSON.parse(raw); } catch { parsed = raw; }\r\n const fetchError = parsed?.error ?? parsed?.message ?? null;\r\n const fetchData = parsed?.data ?? null;\r\n if (!fetchError || isSuccessMessageInError(fetchError)) {\r\n debugLog(\"direct_gateway_succeeded\");\r\n return { result: fetchData, error: null as string | null };\r\n }\r\n debugLog(\"direct_gateway_shape_failed\", { error: String(fetchError) });\r\n if (!String(fetchError).toLowerCase().includes(\"update payload required\")) {\r\n return { result: null, error: String(fetchError) };\r\n }\r\n }\r\n return { result: null, error: \"update payload required: all gateway formats exhausted\" };\r\n };\r\n\r\n const isPayloadError = (e: unknown) =>\r\n String(e).toLowerCase().includes(\"update payload required\");\r\n\r\n // 1. Plain update_body\r\n const first = await run(build(\"plain\"));\r\n if (!first.error || isSuccessMessageInError(first.error)) {\r\n debugLog(\"primary_succeeded\", { shape: \"plain\" });\r\n const row = Array.isArray(first.result) ? (first.result[0] as unknown) : (first.result as unknown);\r\n return (row ? mapRowToBetterAuth(row as T) : null) as T | null;\r\n }\r\n debugLog(\"primary_failed\", { error: String(first.error) });\r\n if (!isPayloadError(first.error)) {\r\n throw new Error(`[AthenaAdapter] update on \"${model}\" failed: ${first.error}`);\r\n }\r\n\r\n // 2. Wrapped { data, set } update_body\r\n const second = await run(build(\"wrapped\"));\r\n if (!second.error || isSuccessMessageInError(second.error)) {\r\n debugLog(\"wrapped_succeeded\", { shape: \"data/set\" });\r\n const row = Array.isArray(second.result) ? (second.result[0] as unknown) : (second.result as unknown);\r\n return (row ? mapRowToBetterAuth(row as T) : null) as T | null;\r\n }\r\n debugLog(\"wrapped_failed\", { error: String(second.error) });\r\n if (!isPayloadError(second.error)) {\r\n throw new Error(`[AthenaAdapter] update on \"${model}\" failed: ${second.error}`);\r\n }\r\n\r\n // 3. Direct fetch with top-level fields\r\n const direct = await directGatewayUpdate();\r\n if (direct.error && !isSuccessMessageInError(direct.error)) {\r\n debugLog(\"direct_gateway_final_failed\", { error: String(direct.error) });\r\n throw new Error(`[AthenaAdapter] update on \"${model}\" failed: ${direct.error}`);\r\n }\r\n debugLog(\"direct_gateway_succeeded\");\r\n const row = Array.isArray(direct.result)\r\n ? (direct.result[0] as unknown)\r\n : (direct.result as unknown);\r\n return (row ? mapRowToBetterAuth(row as T) : null) as T | null;\r\n };\r\n}\r\n","import type { WhereClause, AthenaFilterBuilder } from \"../utils\";\r\nimport {\r\n toDbRecord,\r\n applyWhere,\r\n isSuccessMessageInError,\r\n toSnakeCase,\r\n hasUppercase,\r\n} from \"../utils\";\r\nimport type { GatewayConnectionConfig } from \"./update\";\r\n\r\nexport type UpdateManyDeps = {\r\n ensureDbClient: () => any;\r\n getConnectionConfig: () => GatewayConnectionConfig;\r\n};\r\n\r\nexport function updateManyMethod(deps: UpdateManyDeps) {\r\n const { ensureDbClient } = deps;\r\n\r\n return async function updateMany({\r\n model,\r\n where,\r\n update,\r\n }: {\r\n model: string;\r\n where: WhereClause[];\r\n update: Record<string, unknown>;\r\n }) {\r\n const db = ensureDbClient();\r\n const updateData = toDbRecord(update);\r\n const debugUpdates = process.env.ATHENA_ADAPTER_DEBUG_UPDATES === \"1\";\r\n const debugLog = (event: string, extra?: Record<string, unknown>) => {\r\n if (!debugUpdates) return;\r\n console.info(\"[AthenaAdapter][updateMany]\", { event, model, ...extra });\r\n };\r\n\r\n const build = (shape: \"plain\" | \"wrapped\") => {\r\n const values =\r\n shape === \"plain\"\r\n ? (updateData as any)\r\n : ({ data: updateData, set: updateData } as any);\r\n let b = db.from(model).update(values) as AthenaFilterBuilder;\r\n for (const clause of where) {\r\n b = applyWhere(b, clause.field, clause.operator, clause.value);\r\n }\r\n return b;\r\n };\r\n\r\n const run = async (b: AthenaFilterBuilder) => {\r\n const { data: result, error } = await (b as any).select();\r\n return { result, error };\r\n };\r\n\r\n const directGatewayUpdateMany = async () => {\r\n const { url, apiKey, client, headers: extraHeaders } = deps.getConnectionConfig();\r\n const base = url.replace(/\\/$/, \"\");\r\n const conditions = where.map((clause) => {\r\n const column = hasUppercase(clause.field) ? toSnakeCase(clause.field) : clause.field;\r\n const value = clause.value;\r\n switch (clause.operator) {\r\n case \"ne\": return { operator: \"neq\", column, value };\r\n case \"contains\": return { operator: \"like\", column, value: `%${value}%` };\r\n case \"starts_with\": return { operator: \"like\", column, value: `${String(value)}%` };\r\n case \"ends_with\": return { operator: \"like\", column, value: `%${String(value)}` };\r\n case \"eq\": return { operator: \"eq\", column, eq_column: column, value, eq_value: value };\r\n default: return { operator: clause.operator, column, value };\r\n }\r\n });\r\n const requestHeaders: Record<string, string> = {\r\n \"Content-Type\": \"application/json\",\r\n \"apikey\": apiKey,\r\n \"x-api-key\": apiKey,\r\n \"X-Athena-Client\": client ?? \"railway_direct\",\r\n \"X-Backend-Type\": \"athena\",\r\n \"X-Strip-Nulls\": \"true\",\r\n ...(extraHeaders ?? {}),\r\n };\r\n const payloads = [\r\n { table_name: model, data: updateData, set: updateData, conditions, strip_nulls: true },\r\n {\r\n table_name: model,\r\n columns: Object.entries(updateData).map(([column, value]) => ({ column, value })),\r\n conditions,\r\n strip_nulls: true,\r\n },\r\n ];\r\n for (const payload of payloads) {\r\n const res = await fetch(`${base}/gateway/update`, {\r\n method: \"POST\",\r\n headers: requestHeaders,\r\n body: JSON.stringify(payload),\r\n });\r\n const raw = await res.text();\r\n let parsed: any = null;\r\n try { parsed = JSON.parse(raw); } catch { parsed = raw; }\r\n const fetchError = parsed?.error ?? parsed?.message ?? null;\r\n const fetchData = parsed?.data ?? null;\r\n if (!fetchError || isSuccessMessageInError(fetchError)) {\r\n debugLog(\"direct_gateway_succeeded\");\r\n return { result: fetchData, error: null as string | null };\r\n }\r\n debugLog(\"direct_gateway_shape_failed\", { error: String(fetchError) });\r\n if (!String(fetchError).toLowerCase().includes(\"update payload required\")) {\r\n return { result: null, error: String(fetchError) };\r\n }\r\n }\r\n return { result: null, error: \"update payload required: all gateway formats exhausted\" };\r\n };\r\n\r\n const countResult = (r: unknown) =>\r\n Array.isArray(r) ? r.length : r ? 1 : 0;\r\n\r\n const isPayloadError = (e: unknown) =>\r\n String(e).toLowerCase().includes(\"update payload required\");\r\n\r\n // 1. Plain\r\n const first = await run(build(\"plain\"));\r\n if (!first.error || isSuccessMessageInError(first.error)) {\r\n debugLog(\"primary_succeeded\", { shape: \"plain\" });\r\n return countResult(first.result);\r\n }\r\n debugLog(\"primary_failed\", { error: String(first.error) });\r\n if (!isPayloadError(first.error)) {\r\n throw new Error(`[AthenaAdapter] updateMany on \"${model}\" failed: ${first.error}`);\r\n }\r\n\r\n // 2. Wrapped\r\n const second = await run(build(\"wrapped\"));\r\n if (!second.error || isSuccessMessageInError(second.error)) {\r\n debugLog(\"wrapped_succeeded\", { shape: \"data/set\" });\r\n return countResult(second.result);\r\n }\r\n debugLog(\"wrapped_failed\", { error: String(second.error) });\r\n if (!isPayloadError(second.error)) {\r\n throw new Error(`[AthenaAdapter] updateMany on \"${model}\" failed: ${second.error}`);\r\n }\r\n\r\n // 3. Direct fetch\r\n const direct = await directGatewayUpdateMany();\r\n if (direct.error && !isSuccessMessageInError(direct.error)) {\r\n debugLog(\"direct_gateway_final_failed\", { error: String(direct.error) });\r\n throw new Error(`[AthenaAdapter] updateMany on \"${model}\" failed: ${direct.error}`);\r\n }\r\n debugLog(\"direct_gateway_succeeded\");\r\n return countResult(direct.result);\r\n };\r\n}\r\n","import type { WhereClause, AthenaFilterBuilder } from \"../utils\";\r\nimport { applyWhere, isSuccessMessageInError } from \"../utils\";\r\n\r\nexport type DeleteDeps = {\r\n ensureDbClient: () => any;\r\n headers?: Record<string, string>;\r\n};\r\n\r\nexport function deleteMethod(deps: DeleteDeps) {\r\n const { ensureDbClient, headers } = deps;\r\n\r\n return async function del({\r\n model,\r\n where,\r\n }: {\r\n model: string;\r\n where: WhereClause[];\r\n }) {\r\n const db = ensureDbClient();\r\n let builder = db.from(model) as AthenaFilterBuilder;\r\n\r\n for (const clause of where) {\r\n builder = applyWhere(\r\n builder,\r\n clause.field,\r\n clause.operator,\r\n clause.value,\r\n );\r\n }\r\n\r\n const { error } = await (builder as any).delete(\r\n headers ? ({ headers } as any) : undefined,\r\n );\r\n\r\n if (error && !isSuccessMessageInError(error)) {\r\n throw new Error(\r\n `[AthenaAdapter] delete on \"${model}\" failed: ${error}`,\r\n );\r\n }\r\n };\r\n}\r\n","import type { WhereClause, AthenaFilterBuilder } from \"../utils\";\r\nimport { applyWhere, isSuccessMessageInError } from \"../utils\";\r\n\r\nexport type DeleteManyDeps = {\r\n ensureDbClient: () => any;\r\n headers?: Record<string, string>;\r\n};\r\n\r\nexport function deleteManyMethod(deps: DeleteManyDeps) {\r\n const { ensureDbClient, headers } = deps;\r\n\r\n return async function deleteMany({\r\n model,\r\n where,\r\n }: {\r\n model: string;\r\n where: WhereClause[];\r\n }) {\r\n const db = ensureDbClient();\r\n const mainBuilder = db.from(model) as AthenaFilterBuilder;\r\n let builder = mainBuilder;\r\n\r\n for (const clause of where) {\r\n builder = applyWhere(\r\n builder,\r\n clause.field,\r\n clause.operator,\r\n clause.value,\r\n );\r\n }\r\n\r\n const { data: result, error } = await (builder as any).delete(\r\n headers ? ({ headers } as any) : undefined,\r\n ).select();\r\n\r\n if (error && !isSuccessMessageInError(error)) {\r\n throw new Error(\r\n `[AthenaAdapter] deleteMany on \"${model}\" failed: ${error}`,\r\n );\r\n }\r\n\r\n const deletedCount = Array.isArray(result) ? result.length : result ? 1 : 0;\r\n // Fallback: if the live gateway doesn't apply `in` conditions correctly,\r\n // delete rows one-by-one so counts are stable for e2e tests.\r\n const inClause = where.find(\r\n (c) => c.operator === \"in\" && c.value != null,\r\n );\r\n if (\r\n inClause &&\r\n Array.isArray(inClause.value) &&\r\n deletedCount < inClause.value.length\r\n ) {\r\n let n = 0;\r\n for (const v of inClause.value) {\r\n const b = db.from(model);\r\n const filtered = applyWhere(\r\n b as any,\r\n inClause.field,\r\n \"eq\",\r\n v,\r\n );\r\n const { data: rowData, error: rowErr } = await (filtered as any).delete(\r\n headers ? ({ headers } as any) : undefined,\r\n ).select();\r\n if (rowErr && isSuccessMessageInError(rowErr)) continue;\r\n n += Array.isArray(rowData) ? rowData.length : rowData ? 1 : 0;\r\n }\r\n return n;\r\n }\r\n\r\n return deletedCount;\r\n };\r\n}\r\n","import type { WhereClause } from \"../utils\";\r\nimport {\r\n applyWhere,\r\n mapRowToBetterAuth,\r\n isMissingColumnError,\r\n snakeMapper,\r\n identityMapper,\r\n filterRowsByWhere,\r\n} from \"../utils\";\r\n\r\nexport type FindOneDeps = {\r\n ensureDbClient: () => any;\r\n};\r\n\r\nexport function findOneMethod(deps: FindOneDeps) {\r\n const { ensureDbClient } = deps;\r\n\r\n return async function findOne<T>({\r\n model,\r\n where,\r\n select,\r\n }: {\r\n model: string;\r\n where: WhereClause[];\r\n select?: string[];\r\n join?: unknown;\r\n }) {\r\n const db = ensureDbClient();\r\n\r\n const run = async (columnMapper: (col: string) => string) => {\r\n const columns =\r\n select && select.length > 0\r\n ? select.map((c) => columnMapper(c)).join(\", \")\r\n : undefined;\r\n\r\n let builder = db.from(model).select(columns);\r\n\r\n for (const clause of where) {\r\n builder = applyWhere(\r\n builder,\r\n clause.field,\r\n clause.operator,\r\n clause.value,\r\n columnMapper,\r\n );\r\n }\r\n\r\n const { data: result, error } = await builder.limit(1);\r\n return { result, error };\r\n };\r\n\r\n const first = await run(snakeMapper);\r\n if (first.error) {\r\n if (isMissingColumnError(first.error)) {\r\n const retry = await run(identityMapper);\r\n if (retry.error) {\r\n throw new Error(\r\n `[AthenaAdapter] findOne on \"${model}\" failed: ${retry.error}`,\r\n );\r\n }\r\n\r\n const rows = Array.isArray(retry.result)\r\n ? retry.result\r\n : retry.result\r\n ? [retry.result]\r\n : [];\r\n const row = rows[0] ?? null;\r\n return (row ? mapRowToBetterAuth(row as T) : null) as T | null;\r\n }\r\n\r\n throw new Error(\r\n `[AthenaAdapter] findOne on \"${model}\" failed: ${first.error}`,\r\n );\r\n }\r\n\r\n const rows = Array.isArray(first.result)\r\n ? first.result\r\n : first.result\r\n ? [first.result]\r\n : [];\r\n const row = rows[0] ?? null;\r\n if (!row) return null;\r\n\r\n const mapped = mapRowToBetterAuth(row as T) as T;\r\n const filtered = filterRowsByWhere(\r\n [mapped as unknown as Record<string, unknown>],\r\n where,\r\n );\r\n return (filtered[0] ? mapped : null) as T | null;\r\n };\r\n}\r\n","import type { WhereClause } from \"../utils\";\r\nimport {\r\n applyWhere,\r\n mapRowToBetterAuth,\r\n isMissingColumnError,\r\n snakeMapper,\r\n identityMapper,\r\n filterRowsByWhere,\r\n} from \"../utils\";\r\n\r\nexport type FindManyDeps = {\r\n ensureDbClient: () => any;\r\n};\r\n\r\nexport function findManyMethod(deps: FindManyDeps) {\r\n const { ensureDbClient } = deps;\r\n\r\n const isTransientGatewayError = (error: unknown): boolean => {\r\n const message = String(error ?? \"\").toLowerCase();\r\n return (\r\n message.includes(\"application failed to respond\") ||\r\n message.includes(\"timeout\") ||\r\n message.includes(\"timed out\") ||\r\n message.includes(\"gateway timeout\") ||\r\n message.includes(\"econnreset\") ||\r\n message.includes(\"connection reset\")\r\n );\r\n };\r\n\r\n return async function findMany<T>({\r\n model,\r\n where,\r\n limit,\r\n sortBy,\r\n offset,\r\n select,\r\n }: {\r\n model: string;\r\n where?: WhereClause[];\r\n limit: number;\r\n select?: string[];\r\n sortBy?: { field: string; direction: \"asc\" | \"desc\" };\r\n offset?: number;\r\n join?: unknown;\r\n }) {\r\n const db = ensureDbClient();\r\n\r\n const run = async (\r\n columnMapper: (col: string) => string,\r\n opts?: { skipWhere?: boolean; limitOverride?: number; offsetOverride?: number },\r\n ) => {\r\n const columns =\r\n select && select.length > 0\r\n ? select.map((c) => columnMapper(c)).join(\", \")\r\n : undefined;\r\n\r\n let builder = db.from(model).select(columns);\r\n\r\n if (!opts?.skipWhere && where) {\r\n for (const clause of where) {\r\n builder = applyWhere(\r\n builder,\r\n clause.field,\r\n clause.operator,\r\n clause.value,\r\n columnMapper,\r\n );\r\n }\r\n }\r\n\r\n const effectiveLimit = opts?.limitOverride ?? limit;\r\n const effectiveOffset = opts?.offsetOverride ?? offset;\r\n\r\n if (effectiveLimit !== undefined) {\r\n builder = builder.limit(effectiveLimit);\r\n }\r\n\r\n if (effectiveOffset !== undefined) {\r\n builder = builder.offset(effectiveOffset);\r\n }\r\n\r\n const { data: result, error } = await builder;\r\n return { result, error };\r\n };\r\n\r\n let first = await run(snakeMapper);\r\n if (first.error && isTransientGatewayError(first.error)) {\r\n const retry = await run(snakeMapper);\r\n if (!retry.error) first = retry;\r\n }\r\n\r\n const pickRows = (res: unknown) =>\r\n (Array.isArray(res) ? res : []) as Record<string, unknown>[];\r\n\r\n const applySort = (rows: T[]) => {\r\n if (!sortBy) return rows;\r\n const sortField = sortBy.field;\r\n rows.sort((a, b) => {\r\n const aVal = (a as Record<string, unknown>)[sortField];\r\n const bVal = (b as Record<string, unknown>)[sortField];\r\n if (aVal == null && bVal == null) return 0;\r\n if (aVal == null) return sortBy.direction === \"asc\" ? -1 : 1;\r\n if (bVal == null) return sortBy.direction === \"asc\" ? 1 : -1;\r\n const cmp =\r\n typeof aVal === \"string\" && typeof bVal === \"string\"\r\n ? aVal.localeCompare(bVal)\r\n : aVal < bVal\r\n ? -1\r\n : aVal > bVal\r\n ? 1\r\n : 0;\r\n return sortBy.direction === \"asc\" ? cmp : -cmp;\r\n });\r\n return rows;\r\n };\r\n\r\n const mapAndSort = (rows: Record<string, unknown>[]) => {\r\n const betterAuthRows = rows.map((r) => mapRowToBetterAuth(r)) as unknown as T[];\r\n\r\n if (!where?.length) return applySort(betterAuthRows);\r\n\r\n const filtered = filterRowsByWhere(\r\n betterAuthRows as unknown as Record<string, unknown>[],\r\n where,\r\n ) as unknown as T[];\r\n\r\n // If filtering changed the row set, the gateway likely ignored `where`\r\n // (or applied it before limiting/offset). In that case, re-apply sorting\r\n // and slice using the requested offset/limit.\r\n if (filtered.length !== betterAuthRows.length) {\r\n const off = offset ?? 0;\r\n const end = limit !== undefined ? off + limit : undefined;\r\n return applySort(filtered).slice(off, end);\r\n }\r\n\r\n return applySort(filtered);\r\n };\r\n\r\n const postFilterAndSlice = (rows: Record<string, unknown>[]) => {\r\n const mappedSorted = mapAndSort(rows);\r\n const off = offset ?? 0;\r\n const end = limit !== undefined ? off + limit : undefined;\r\n return mappedSorted.slice(off, end);\r\n };\r\n\r\n if (first.error) {\r\n if (isMissingColumnError(first.error)) {\r\n const retry = await run(identityMapper);\r\n if (retry.error) {\r\n throw new Error(\r\n `[AthenaAdapter] findMany on \"${model}\" failed: ${retry.error}`,\r\n );\r\n }\r\n const retryRows = pickRows(retry.result);\r\n // Decisive fallback: if gateway-side `where` yields empty/insufficient rows,\r\n // fetch a broader candidate set and apply `where`/sort/offset/limit in-memory.\r\n if (where?.length) {\r\n const broad = await run(identityMapper, {\r\n skipWhere: true,\r\n limitOverride: Math.max((offset ?? 0) + (limit ?? 0) + 500, 5000),\r\n offsetOverride: 0,\r\n });\r\n if (!broad.error) return postFilterAndSlice(pickRows(broad.result));\r\n }\r\n return mapAndSort(retryRows);\r\n }\r\n\r\n throw new Error(\r\n `[AthenaAdapter] findMany on \"${model}\" failed: ${first.error}`,\r\n );\r\n }\r\n\r\n const firstRows = pickRows(first.result);\r\n if (where?.length) {\r\n const broad = await run(snakeMapper, {\r\n skipWhere: true,\r\n limitOverride: Math.max((offset ?? 0) + (limit ?? 0) + 500, 5000),\r\n offsetOverride: 0,\r\n });\r\n if (!broad.error) return postFilterAndSlice(pickRows(broad.result));\r\n }\r\n return mapAndSort(firstRows);\r\n };\r\n}\r\n","import type { WhereClause } from \"../utils\";\r\nimport {\r\n applyWhere,\r\n isMissingColumnError,\r\n snakeMapper,\r\n identityMapper,\r\n} from \"../utils\";\r\n\r\nexport type CountDeps = {\r\n ensureDbClient: () => any;\r\n};\r\n\r\nexport function countMethod(deps: CountDeps) {\r\n const { ensureDbClient } = deps;\r\n\r\n return async function count({\r\n model,\r\n where,\r\n }: {\r\n model: string;\r\n where?: WhereClause[];\r\n }) {\r\n const db = ensureDbClient();\r\n\r\n const run = async (columnMapper: (col: string) => string) => {\r\n let builder = db.from(model).select();\r\n\r\n if (where) {\r\n for (const clause of where) {\r\n builder = applyWhere(\r\n builder,\r\n clause.field,\r\n clause.operator,\r\n clause.value,\r\n columnMapper,\r\n );\r\n }\r\n }\r\n\r\n const { data: result, error } = await builder;\r\n return { result, error };\r\n };\r\n\r\n const first = await run(snakeMapper);\r\n if (first.error) {\r\n if (isMissingColumnError(first.error)) {\r\n const retry = await run(identityMapper);\r\n if (retry.error) {\r\n throw new Error(\r\n `[AthenaAdapter] count on \"${model}\" failed: ${retry.error}`,\r\n );\r\n }\r\n return Array.isArray(retry.result) ? retry.result.length : 0;\r\n }\r\n throw new Error(\r\n `[AthenaAdapter] count on \"${model}\" failed: ${first.error}`,\r\n );\r\n }\r\n\r\n return Array.isArray(first.result) ? first.result.length : 0;\r\n };\r\n}\r\n"],"mappings":"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","names":["row","rows","row","version"]}
|