@xylex-group/athena 2.0.0 → 2.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +47 -26
- package/dist/browser.cjs +3319 -0
- package/dist/browser.cjs.map +1 -0
- package/dist/browser.d.cts +25 -0
- package/dist/browser.d.ts +25 -0
- package/dist/browser.js +3276 -0
- package/dist/browser.js.map +1 -0
- package/dist/cli/index.cjs +599 -119
- package/dist/cli/index.cjs.map +1 -1
- package/dist/cli/index.d.cts +3 -2
- package/dist/cli/index.d.ts +3 -2
- package/dist/cli/index.js +600 -120
- package/dist/cli/index.js.map +1 -1
- package/dist/client-BX0NQqOn.d.ts +435 -0
- package/dist/client-dpAp-NZK.d.cts +435 -0
- package/dist/cookies.cjs +890 -0
- package/dist/cookies.cjs.map +1 -0
- package/dist/cookies.d.cts +174 -0
- package/dist/cookies.d.ts +174 -0
- package/dist/cookies.js +869 -0
- package/dist/cookies.js.map +1 -0
- package/dist/index.cjs +1378 -1023
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +8 -408
- package/dist/index.d.ts +8 -408
- package/dist/index.js +1379 -1024
- package/dist/index.js.map +1 -1
- package/dist/{model-form-CVOtC8jq.d.ts → model-form-2hqmoOUX.d.ts} +2 -2
- package/dist/{model-form-hXkvHS_3.d.cts → model-form-Cy-zaO0u.d.cts} +2 -2
- package/dist/pipeline-BOPszLsL.d.ts +8 -0
- package/dist/pipeline-E3FDbs4W.d.cts +8 -0
- package/dist/react.d.cts +4 -4
- package/dist/react.d.ts +4 -4
- package/dist/{types-BnzoaNRC.d.cts → types-BaBzjwXr.d.cts} +1 -1
- package/dist/{types-BnzoaNRC.d.ts → types-BaBzjwXr.d.ts} +1 -1
- package/dist/{pipeline-CQgV-Yfo.d.ts → types-CeBPrnGj.d.ts} +2 -7
- package/dist/{pipeline-C-cN0ACi.d.cts → types-CpqL-pZx.d.cts} +2 -7
- package/package.json +21 -1
package/dist/browser.cjs
ADDED
|
@@ -0,0 +1,3319 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// src/gateway/errors.ts
|
|
4
|
+
var AthenaGatewayError = class _AthenaGatewayError extends Error {
|
|
5
|
+
code;
|
|
6
|
+
status;
|
|
7
|
+
endpoint;
|
|
8
|
+
method;
|
|
9
|
+
requestId;
|
|
10
|
+
hint;
|
|
11
|
+
causeDetail;
|
|
12
|
+
constructor(input) {
|
|
13
|
+
super(input.message);
|
|
14
|
+
this.name = "AthenaGatewayError";
|
|
15
|
+
this.code = input.code;
|
|
16
|
+
this.status = input.status ?? 0;
|
|
17
|
+
this.endpoint = input.endpoint;
|
|
18
|
+
this.method = input.method;
|
|
19
|
+
this.requestId = input.requestId;
|
|
20
|
+
this.hint = input.hint;
|
|
21
|
+
this.causeDetail = input.cause;
|
|
22
|
+
}
|
|
23
|
+
toDetails() {
|
|
24
|
+
return {
|
|
25
|
+
code: this.code,
|
|
26
|
+
message: this.message,
|
|
27
|
+
status: this.status,
|
|
28
|
+
endpoint: this.endpoint,
|
|
29
|
+
method: this.method,
|
|
30
|
+
requestId: this.requestId,
|
|
31
|
+
hint: this.hint,
|
|
32
|
+
cause: this.causeDetail
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
static fromResponse(response, fallback) {
|
|
36
|
+
const details = response.errorDetails;
|
|
37
|
+
if (details) {
|
|
38
|
+
return new _AthenaGatewayError({
|
|
39
|
+
code: details.code,
|
|
40
|
+
message: details.message,
|
|
41
|
+
status: details.status,
|
|
42
|
+
endpoint: details.endpoint ?? fallback.endpoint,
|
|
43
|
+
method: details.method ?? fallback.method,
|
|
44
|
+
requestId: details.requestId ?? fallback.requestId,
|
|
45
|
+
hint: details.hint,
|
|
46
|
+
cause: details.cause
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
return new _AthenaGatewayError({
|
|
50
|
+
code: "HTTP_ERROR",
|
|
51
|
+
message: response.error ?? "Gateway request failed",
|
|
52
|
+
status: response.status,
|
|
53
|
+
endpoint: fallback.endpoint,
|
|
54
|
+
method: fallback.method,
|
|
55
|
+
requestId: fallback.requestId
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
function isAthenaGatewayError(error) {
|
|
60
|
+
return error instanceof AthenaGatewayError;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// src/gateway/client.ts
|
|
64
|
+
var DEFAULT_BASE_URL = "https://athena-db.com";
|
|
65
|
+
var DEFAULT_CLIENT = "railway_direct";
|
|
66
|
+
var FALLBACK_SDK_VERSION = "1.3.0";
|
|
67
|
+
var SDK_NAME = "xylex-group/athena";
|
|
68
|
+
var SDK_VERSION = typeof process !== "undefined" && process?.env?.npm_package_version ? process.env.npm_package_version : FALLBACK_SDK_VERSION;
|
|
69
|
+
var SDK_HEADER_VALUE = `${SDK_NAME} ${SDK_VERSION}`;
|
|
70
|
+
function parseResponseBody(rawText, contentType) {
|
|
71
|
+
if (!rawText) {
|
|
72
|
+
return { parsed: null, parseFailed: false };
|
|
73
|
+
}
|
|
74
|
+
const contentTypeSuggestsJson = contentType?.toLowerCase().includes("application/json") ?? false;
|
|
75
|
+
const looksJson = contentTypeSuggestsJson || rawText.startsWith("{") || rawText.startsWith("[");
|
|
76
|
+
if (!looksJson) {
|
|
77
|
+
return { parsed: rawText, parseFailed: false };
|
|
78
|
+
}
|
|
79
|
+
try {
|
|
80
|
+
return { parsed: JSON.parse(rawText), parseFailed: false };
|
|
81
|
+
} catch {
|
|
82
|
+
return { parsed: rawText, parseFailed: true };
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
function normalizeHeaderValue(value) {
|
|
86
|
+
return value ? value : void 0;
|
|
87
|
+
}
|
|
88
|
+
function isRecord(value) {
|
|
89
|
+
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
90
|
+
}
|
|
91
|
+
function resolveRequestId(headers) {
|
|
92
|
+
return headers.get("x-request-id") ?? headers.get("x-correlation-id") ?? headers.get("x-athena-request-id") ?? void 0;
|
|
93
|
+
}
|
|
94
|
+
function resolveErrorMessage(payload, fallback) {
|
|
95
|
+
if (isRecord(payload)) {
|
|
96
|
+
const messageCandidates = [payload.error, payload.message, payload.details];
|
|
97
|
+
for (const candidate of messageCandidates) {
|
|
98
|
+
if (typeof candidate === "string" && candidate.trim().length > 0) {
|
|
99
|
+
return candidate.trim();
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
if (typeof payload === "string" && payload.trim().length > 0) {
|
|
104
|
+
return payload.trim();
|
|
105
|
+
}
|
|
106
|
+
return fallback;
|
|
107
|
+
}
|
|
108
|
+
function detailsFromError(error) {
|
|
109
|
+
return error.toDetails();
|
|
110
|
+
}
|
|
111
|
+
function toQueryScalar(value) {
|
|
112
|
+
if (value === null || value === void 0) return "null";
|
|
113
|
+
if (typeof value === "boolean") return value ? "true" : "false";
|
|
114
|
+
if (typeof value === "number") return Number.isFinite(value) ? String(value) : "null";
|
|
115
|
+
return String(value);
|
|
116
|
+
}
|
|
117
|
+
function toQueryArray(values) {
|
|
118
|
+
return `{${values.map(toQueryScalar).join(",")}}`;
|
|
119
|
+
}
|
|
120
|
+
function toRpcArgumentQueryValue(value) {
|
|
121
|
+
if (Array.isArray(value)) return toQueryArray(value);
|
|
122
|
+
if (value && typeof value === "object") return JSON.stringify(value);
|
|
123
|
+
return toQueryScalar(value);
|
|
124
|
+
}
|
|
125
|
+
function toRpcFilterQueryValue(filter) {
|
|
126
|
+
const value = filter.value;
|
|
127
|
+
switch (filter.operator) {
|
|
128
|
+
case "in": {
|
|
129
|
+
if (!Array.isArray(value)) {
|
|
130
|
+
throw new AthenaGatewayError({
|
|
131
|
+
code: "UNKNOWN_ERROR",
|
|
132
|
+
message: `RPC filter "${filter.column}" with operator "in" requires an array value`,
|
|
133
|
+
status: 0
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
return `in.${toQueryArray(value)}`;
|
|
137
|
+
}
|
|
138
|
+
case "is":
|
|
139
|
+
return `is.${toQueryScalar(value)}`;
|
|
140
|
+
case "eq":
|
|
141
|
+
case "neq":
|
|
142
|
+
case "gt":
|
|
143
|
+
case "gte":
|
|
144
|
+
case "lt":
|
|
145
|
+
case "lte":
|
|
146
|
+
case "like":
|
|
147
|
+
case "ilike":
|
|
148
|
+
return `${filter.operator}.${toQueryScalar(value)}`;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
function buildRpcGetEndpoint(payload) {
|
|
152
|
+
const functionName = (payload.function_name ?? payload.function).trim();
|
|
153
|
+
if (!functionName) {
|
|
154
|
+
throw new AthenaGatewayError({
|
|
155
|
+
code: "UNKNOWN_ERROR",
|
|
156
|
+
message: "rpc requires a function name",
|
|
157
|
+
status: 0,
|
|
158
|
+
endpoint: "/gateway/rpc",
|
|
159
|
+
method: "GET"
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
const query = new URLSearchParams();
|
|
163
|
+
if (payload.schema) query.set("schema", payload.schema);
|
|
164
|
+
if (payload.select) query.set("select", payload.select);
|
|
165
|
+
if (payload.count) query.set("count", payload.count);
|
|
166
|
+
if (payload.head) query.set("head", "true");
|
|
167
|
+
if (typeof payload.limit === "number") query.set("limit", String(payload.limit));
|
|
168
|
+
if (typeof payload.offset === "number") query.set("offset", String(payload.offset));
|
|
169
|
+
if (payload.order?.column) {
|
|
170
|
+
query.set(
|
|
171
|
+
"order",
|
|
172
|
+
payload.order.ascending === false ? `${payload.order.column}.desc` : payload.order.column
|
|
173
|
+
);
|
|
174
|
+
}
|
|
175
|
+
if (payload.args) {
|
|
176
|
+
for (const [key, value] of Object.entries(payload.args)) {
|
|
177
|
+
query.set(key, toRpcArgumentQueryValue(value));
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
if (payload.filters?.length) {
|
|
181
|
+
for (const filter of payload.filters) {
|
|
182
|
+
if (payload.args && Object.prototype.hasOwnProperty.call(payload.args, filter.column)) {
|
|
183
|
+
throw new AthenaGatewayError({
|
|
184
|
+
code: "UNKNOWN_ERROR",
|
|
185
|
+
message: `RPC filter "${filter.column}" conflicts with RPC argument "${filter.column}" in GET mode`,
|
|
186
|
+
status: 0
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
query.set(filter.column, toRpcFilterQueryValue(filter));
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
const endpoint = `/rpc/${encodeURIComponent(functionName)}`;
|
|
193
|
+
const queryText = query.toString();
|
|
194
|
+
const withQuery = queryText ? `${endpoint}?${queryText}` : endpoint;
|
|
195
|
+
return withQuery;
|
|
196
|
+
}
|
|
197
|
+
function buildHeaders(config, options) {
|
|
198
|
+
const mergedStripNulls = options?.stripNulls ?? true;
|
|
199
|
+
const extraHeaders = {
|
|
200
|
+
...config.headers ?? {},
|
|
201
|
+
...options?.headers ?? {}
|
|
202
|
+
};
|
|
203
|
+
const headerClient = extraHeaders["x-athena-client"] ?? extraHeaders["X-Athena-Client"];
|
|
204
|
+
const finalClient = options?.client ?? config.client ?? (typeof headerClient === "string" ? headerClient : void 0) ?? DEFAULT_CLIENT;
|
|
205
|
+
const finalApiKey = options?.apiKey ?? config.apiKey;
|
|
206
|
+
const finalPublishEvent = options?.publishEvent ?? config.publishEvent;
|
|
207
|
+
const headers = {
|
|
208
|
+
"Content-Type": "application/json",
|
|
209
|
+
"X-Athena-Sdk": SDK_HEADER_VALUE
|
|
210
|
+
};
|
|
211
|
+
if (options?.userId ?? config.userId) {
|
|
212
|
+
headers["X-User-Id"] = options?.userId ?? config.userId ?? "";
|
|
213
|
+
}
|
|
214
|
+
if (options?.organizationId ?? config.organizationId) {
|
|
215
|
+
headers["X-Organization-Id"] = options?.organizationId ?? config.organizationId ?? "";
|
|
216
|
+
}
|
|
217
|
+
if (finalClient) {
|
|
218
|
+
headers["X-Athena-Client"] = finalClient;
|
|
219
|
+
}
|
|
220
|
+
const finalBackend = options?.backend ?? config.backend;
|
|
221
|
+
if (finalBackend) {
|
|
222
|
+
const type = typeof finalBackend === "string" ? finalBackend : finalBackend.type;
|
|
223
|
+
if (type) headers["X-Backend-Type"] = type;
|
|
224
|
+
}
|
|
225
|
+
if (typeof mergedStripNulls === "boolean") {
|
|
226
|
+
headers["X-Strip-Nulls"] = mergedStripNulls ? "true" : "false";
|
|
227
|
+
}
|
|
228
|
+
if (finalPublishEvent) {
|
|
229
|
+
headers["X-Publish-Event"] = finalPublishEvent;
|
|
230
|
+
}
|
|
231
|
+
if (finalApiKey) {
|
|
232
|
+
headers["apikey"] = finalApiKey;
|
|
233
|
+
headers["x-api-key"] = headers["x-api-key"] ?? finalApiKey;
|
|
234
|
+
}
|
|
235
|
+
const athenaClientKeys = ["x-athena-client", "X-Athena-Client"];
|
|
236
|
+
Object.entries(extraHeaders).forEach(([key, value]) => {
|
|
237
|
+
if (athenaClientKeys.includes(key)) return;
|
|
238
|
+
const normalized = normalizeHeaderValue(value);
|
|
239
|
+
if (normalized) {
|
|
240
|
+
headers[key] = normalized;
|
|
241
|
+
}
|
|
242
|
+
});
|
|
243
|
+
return headers;
|
|
244
|
+
}
|
|
245
|
+
async function callAthena(config, endpoint, method, payload, options) {
|
|
246
|
+
const baseUrl = (options?.baseUrl ?? config.baseUrl ?? DEFAULT_BASE_URL).replace(/\/$/, "");
|
|
247
|
+
const url = `${baseUrl}${endpoint}`;
|
|
248
|
+
const headers = buildHeaders(config, options);
|
|
249
|
+
try {
|
|
250
|
+
const requestInit = {
|
|
251
|
+
method,
|
|
252
|
+
headers
|
|
253
|
+
};
|
|
254
|
+
if (method !== "GET") {
|
|
255
|
+
requestInit.body = JSON.stringify(payload);
|
|
256
|
+
}
|
|
257
|
+
const response = await fetch(url, requestInit);
|
|
258
|
+
const rawText = await response.text();
|
|
259
|
+
const requestId = resolveRequestId(response.headers);
|
|
260
|
+
const parsedBody = parseResponseBody(
|
|
261
|
+
rawText ?? "",
|
|
262
|
+
response.headers.get("content-type")
|
|
263
|
+
);
|
|
264
|
+
if (parsedBody.parseFailed) {
|
|
265
|
+
const invalidJsonError = new AthenaGatewayError({
|
|
266
|
+
code: "INVALID_JSON",
|
|
267
|
+
message: "Gateway returned malformed JSON",
|
|
268
|
+
status: response.status,
|
|
269
|
+
endpoint,
|
|
270
|
+
method,
|
|
271
|
+
requestId,
|
|
272
|
+
hint: "Verify the gateway response body is valid JSON.",
|
|
273
|
+
cause: rawText.slice(0, 300)
|
|
274
|
+
});
|
|
275
|
+
return {
|
|
276
|
+
ok: false,
|
|
277
|
+
status: response.status,
|
|
278
|
+
data: null,
|
|
279
|
+
error: invalidJsonError.message,
|
|
280
|
+
errorDetails: detailsFromError(invalidJsonError),
|
|
281
|
+
raw: parsedBody.parsed
|
|
282
|
+
};
|
|
283
|
+
}
|
|
284
|
+
const parsed = parsedBody.parsed;
|
|
285
|
+
const parsedPayload = isRecord(parsed) ? parsed : null;
|
|
286
|
+
if (!response.ok) {
|
|
287
|
+
const httpError = new AthenaGatewayError({
|
|
288
|
+
code: "HTTP_ERROR",
|
|
289
|
+
message: resolveErrorMessage(
|
|
290
|
+
parsed,
|
|
291
|
+
`Athena gateway ${method} ${endpoint} failed with status ${response.status}`
|
|
292
|
+
),
|
|
293
|
+
status: response.status,
|
|
294
|
+
endpoint,
|
|
295
|
+
method,
|
|
296
|
+
requestId
|
|
297
|
+
});
|
|
298
|
+
return {
|
|
299
|
+
ok: false,
|
|
300
|
+
status: response.status,
|
|
301
|
+
data: null,
|
|
302
|
+
error: httpError.message,
|
|
303
|
+
errorDetails: detailsFromError(httpError),
|
|
304
|
+
raw: parsed
|
|
305
|
+
};
|
|
306
|
+
}
|
|
307
|
+
const payloadData = parsedPayload && "data" in parsedPayload ? parsedPayload.data : parsed;
|
|
308
|
+
const payloadCount = parsedPayload && "count" in parsedPayload ? typeof parsedPayload.count === "number" || parsedPayload.count === null ? parsedPayload.count : void 0 : void 0;
|
|
309
|
+
return {
|
|
310
|
+
ok: true,
|
|
311
|
+
status: response.status,
|
|
312
|
+
data: payloadData ?? null,
|
|
313
|
+
count: payloadCount,
|
|
314
|
+
error: void 0,
|
|
315
|
+
errorDetails: null,
|
|
316
|
+
raw: parsed
|
|
317
|
+
};
|
|
318
|
+
} catch (callError) {
|
|
319
|
+
const message = callError instanceof Error ? callError.message : String(callError);
|
|
320
|
+
const networkError = new AthenaGatewayError({
|
|
321
|
+
code: "NETWORK_ERROR",
|
|
322
|
+
message: `Network error while calling ${method} ${endpoint}: ${message}`,
|
|
323
|
+
endpoint,
|
|
324
|
+
method,
|
|
325
|
+
cause: message,
|
|
326
|
+
hint: "Check gateway URL, DNS, and network reachability."
|
|
327
|
+
});
|
|
328
|
+
return {
|
|
329
|
+
ok: false,
|
|
330
|
+
status: 0,
|
|
331
|
+
data: null,
|
|
332
|
+
error: networkError.message,
|
|
333
|
+
errorDetails: detailsFromError(networkError),
|
|
334
|
+
raw: null
|
|
335
|
+
};
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
function createAthenaGatewayClient(config = {}) {
|
|
339
|
+
return {
|
|
340
|
+
baseUrl: (config.baseUrl ?? DEFAULT_BASE_URL).replace(/\/$/, ""),
|
|
341
|
+
buildHeaders(options) {
|
|
342
|
+
return buildHeaders(config, options);
|
|
343
|
+
},
|
|
344
|
+
fetchGateway(payload, options) {
|
|
345
|
+
return callAthena(config, "/gateway/fetch", "POST", payload, options);
|
|
346
|
+
},
|
|
347
|
+
insertGateway(payload, options) {
|
|
348
|
+
return callAthena(config, "/gateway/insert", "PUT", payload, options);
|
|
349
|
+
},
|
|
350
|
+
updateGateway(payload, options) {
|
|
351
|
+
return callAthena(config, "/gateway/update", "POST", payload, options);
|
|
352
|
+
},
|
|
353
|
+
deleteGateway(payload, options) {
|
|
354
|
+
return callAthena(config, "/gateway/delete", "DELETE", payload, options);
|
|
355
|
+
},
|
|
356
|
+
rpcGateway(payload, options) {
|
|
357
|
+
if (options?.get) {
|
|
358
|
+
const endpoint = buildRpcGetEndpoint(payload);
|
|
359
|
+
return callAthena(config, endpoint, "GET", null, options);
|
|
360
|
+
}
|
|
361
|
+
return callAthena(config, "/gateway/rpc", "POST", payload, options);
|
|
362
|
+
},
|
|
363
|
+
queryGateway(payload, options) {
|
|
364
|
+
return callAthena(config, "/gateway/query", "POST", payload, options);
|
|
365
|
+
}
|
|
366
|
+
};
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
// src/sql-identifiers.ts
|
|
370
|
+
var SIMPLE_IDENTIFIER_PATTERN = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
371
|
+
var COMPOSITE_IDENTIFIER_PATTERN = /^[A-Za-z_][A-Za-z0-9_]*(?:\.[A-Za-z_][A-Za-z0-9_]*)*$/;
|
|
372
|
+
var ALIAS_PATTERN = /^([A-Za-z_][A-Za-z0-9_.]*)\s+(?:as\s+)?([A-Za-z_][A-Za-z0-9_]*)$/i;
|
|
373
|
+
function quoteIdentifierSegment(identifier2) {
|
|
374
|
+
return `"${identifier2.replace(/"/g, '""')}"`;
|
|
375
|
+
}
|
|
376
|
+
function quoteQualifiedIdentifier(identifier2) {
|
|
377
|
+
return identifier2.split(".").map((segment) => quoteIdentifierSegment(segment)).join(".");
|
|
378
|
+
}
|
|
379
|
+
function quoteSelectToken(token) {
|
|
380
|
+
if (token === "*") return token;
|
|
381
|
+
if (COMPOSITE_IDENTIFIER_PATTERN.test(token)) {
|
|
382
|
+
return quoteQualifiedIdentifier(token);
|
|
383
|
+
}
|
|
384
|
+
const aliasMatch = ALIAS_PATTERN.exec(token);
|
|
385
|
+
if (!aliasMatch) {
|
|
386
|
+
return token;
|
|
387
|
+
}
|
|
388
|
+
const [, baseIdentifier, aliasIdentifier] = aliasMatch;
|
|
389
|
+
if (!COMPOSITE_IDENTIFIER_PATTERN.test(baseIdentifier) || !SIMPLE_IDENTIFIER_PATTERN.test(aliasIdentifier)) {
|
|
390
|
+
return token;
|
|
391
|
+
}
|
|
392
|
+
return `${quoteQualifiedIdentifier(baseIdentifier)} AS ${quoteIdentifierSegment(aliasIdentifier)}`;
|
|
393
|
+
}
|
|
394
|
+
function canAutoQuoteToken(token) {
|
|
395
|
+
if (token === "*") return true;
|
|
396
|
+
if (COMPOSITE_IDENTIFIER_PATTERN.test(token)) return true;
|
|
397
|
+
const aliasMatch = ALIAS_PATTERN.exec(token);
|
|
398
|
+
if (!aliasMatch) return false;
|
|
399
|
+
const [, baseIdentifier, aliasIdentifier] = aliasMatch;
|
|
400
|
+
return COMPOSITE_IDENTIFIER_PATTERN.test(baseIdentifier) && SIMPLE_IDENTIFIER_PATTERN.test(aliasIdentifier);
|
|
401
|
+
}
|
|
402
|
+
function splitTopLevelCommaSeparated(input) {
|
|
403
|
+
const parts = [];
|
|
404
|
+
let buffer = "";
|
|
405
|
+
let singleQuoted = false;
|
|
406
|
+
let doubleQuoted = false;
|
|
407
|
+
let depth = 0;
|
|
408
|
+
for (let index = 0; index < input.length; index += 1) {
|
|
409
|
+
const char = input[index];
|
|
410
|
+
const next = index + 1 < input.length ? input[index + 1] : "";
|
|
411
|
+
if (singleQuoted) {
|
|
412
|
+
buffer += char;
|
|
413
|
+
if (char === "'" && next === "'") {
|
|
414
|
+
buffer += next;
|
|
415
|
+
index += 1;
|
|
416
|
+
continue;
|
|
417
|
+
}
|
|
418
|
+
if (char === "'") {
|
|
419
|
+
singleQuoted = false;
|
|
420
|
+
}
|
|
421
|
+
continue;
|
|
422
|
+
}
|
|
423
|
+
if (doubleQuoted) {
|
|
424
|
+
buffer += char;
|
|
425
|
+
if (char === '"' && next === '"') {
|
|
426
|
+
buffer += next;
|
|
427
|
+
index += 1;
|
|
428
|
+
continue;
|
|
429
|
+
}
|
|
430
|
+
if (char === '"') {
|
|
431
|
+
doubleQuoted = false;
|
|
432
|
+
}
|
|
433
|
+
continue;
|
|
434
|
+
}
|
|
435
|
+
if (char === "'") {
|
|
436
|
+
singleQuoted = true;
|
|
437
|
+
buffer += char;
|
|
438
|
+
continue;
|
|
439
|
+
}
|
|
440
|
+
if (char === '"') {
|
|
441
|
+
doubleQuoted = true;
|
|
442
|
+
buffer += char;
|
|
443
|
+
continue;
|
|
444
|
+
}
|
|
445
|
+
if (char === "(") {
|
|
446
|
+
depth += 1;
|
|
447
|
+
buffer += char;
|
|
448
|
+
continue;
|
|
449
|
+
}
|
|
450
|
+
if (char === ")") {
|
|
451
|
+
depth -= 1;
|
|
452
|
+
if (depth < 0) return null;
|
|
453
|
+
buffer += char;
|
|
454
|
+
continue;
|
|
455
|
+
}
|
|
456
|
+
if (char === "," && depth === 0) {
|
|
457
|
+
parts.push(buffer.trim());
|
|
458
|
+
buffer = "";
|
|
459
|
+
continue;
|
|
460
|
+
}
|
|
461
|
+
buffer += char;
|
|
462
|
+
}
|
|
463
|
+
if (singleQuoted || doubleQuoted || depth !== 0) {
|
|
464
|
+
return null;
|
|
465
|
+
}
|
|
466
|
+
if (buffer.trim().length > 0) {
|
|
467
|
+
parts.push(buffer.trim());
|
|
468
|
+
}
|
|
469
|
+
return parts;
|
|
470
|
+
}
|
|
471
|
+
function quoteSelectColumnsExpression(columns) {
|
|
472
|
+
const trimmed = columns.trim();
|
|
473
|
+
if (!trimmed || trimmed === "*") return trimmed || "*";
|
|
474
|
+
const tokens = splitTopLevelCommaSeparated(trimmed);
|
|
475
|
+
if (!tokens || tokens.length === 0) {
|
|
476
|
+
return trimmed;
|
|
477
|
+
}
|
|
478
|
+
if (!tokens.every(canAutoQuoteToken)) {
|
|
479
|
+
return trimmed;
|
|
480
|
+
}
|
|
481
|
+
return tokens.map(quoteSelectToken).join(", ");
|
|
482
|
+
}
|
|
483
|
+
var SqlIdentifierPath = class {
|
|
484
|
+
segments;
|
|
485
|
+
constructor(segments) {
|
|
486
|
+
this.segments = segments;
|
|
487
|
+
}
|
|
488
|
+
toSql() {
|
|
489
|
+
return this.segments.map(quoteIdentifierSegment).join(".");
|
|
490
|
+
}
|
|
491
|
+
toString() {
|
|
492
|
+
return this.toSql();
|
|
493
|
+
}
|
|
494
|
+
};
|
|
495
|
+
function identifier(...segments) {
|
|
496
|
+
const expandedSegments = segments.flatMap((segment) => segment.split(".")).map((segment) => segment.trim()).filter((segment) => segment.length > 0);
|
|
497
|
+
return new SqlIdentifierPath(expandedSegments);
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
// src/auth/client.ts
|
|
501
|
+
var DEFAULT_AUTH_BASE_URL = "http://localhost:3001/api/auth";
|
|
502
|
+
var FALLBACK_SDK_VERSION2 = "1.0.0";
|
|
503
|
+
var SDK_NAME2 = "xylex-group/athena-auth";
|
|
504
|
+
var SDK_VERSION2 = typeof process !== "undefined" && process?.env?.npm_package_version ? process.env.npm_package_version : FALLBACK_SDK_VERSION2;
|
|
505
|
+
var SDK_HEADER_VALUE2 = `${SDK_NAME2} ${SDK_VERSION2}`;
|
|
506
|
+
function normalizeBaseUrl(baseUrl) {
|
|
507
|
+
return (baseUrl ?? DEFAULT_AUTH_BASE_URL).replace(/\/$/, "");
|
|
508
|
+
}
|
|
509
|
+
function isRecord2(value) {
|
|
510
|
+
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
511
|
+
}
|
|
512
|
+
function normalizeHeaderValue2(value) {
|
|
513
|
+
return value ? value : void 0;
|
|
514
|
+
}
|
|
515
|
+
function parseResponseBody2(rawText, contentType) {
|
|
516
|
+
if (!rawText) {
|
|
517
|
+
return { parsed: null, parseFailed: false };
|
|
518
|
+
}
|
|
519
|
+
const contentTypeSuggestsJson = contentType?.toLowerCase().includes("application/json") ?? false;
|
|
520
|
+
const looksJson = contentTypeSuggestsJson || rawText.startsWith("{") || rawText.startsWith("[");
|
|
521
|
+
if (!looksJson) {
|
|
522
|
+
return { parsed: rawText, parseFailed: false };
|
|
523
|
+
}
|
|
524
|
+
try {
|
|
525
|
+
return { parsed: JSON.parse(rawText), parseFailed: false };
|
|
526
|
+
} catch {
|
|
527
|
+
return { parsed: rawText, parseFailed: true };
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
function resolveRequestId2(headers) {
|
|
531
|
+
return headers.get("x-request-id") ?? headers.get("x-correlation-id") ?? headers.get("x-athena-request-id") ?? void 0;
|
|
532
|
+
}
|
|
533
|
+
function resolveErrorMessage2(payload, fallback) {
|
|
534
|
+
if (isRecord2(payload)) {
|
|
535
|
+
const messageCandidates = [payload.error, payload.message, payload.details];
|
|
536
|
+
for (const candidate of messageCandidates) {
|
|
537
|
+
if (typeof candidate === "string" && candidate.trim().length > 0) {
|
|
538
|
+
return candidate.trim();
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
if (typeof payload === "string" && payload.trim().length > 0) {
|
|
543
|
+
return payload.trim();
|
|
544
|
+
}
|
|
545
|
+
return fallback;
|
|
546
|
+
}
|
|
547
|
+
function toErrorDetails(input) {
|
|
548
|
+
return {
|
|
549
|
+
code: input.code,
|
|
550
|
+
message: input.message,
|
|
551
|
+
status: input.status,
|
|
552
|
+
endpoint: input.endpoint,
|
|
553
|
+
method: input.method,
|
|
554
|
+
requestId: input.requestId,
|
|
555
|
+
hint: input.hint,
|
|
556
|
+
cause: input.cause
|
|
557
|
+
};
|
|
558
|
+
}
|
|
559
|
+
function mergeCallOptions(base, override) {
|
|
560
|
+
if (!base && !override) return void 0;
|
|
561
|
+
return {
|
|
562
|
+
...base,
|
|
563
|
+
...override,
|
|
564
|
+
headers: {
|
|
565
|
+
...base?.headers ?? {},
|
|
566
|
+
...override?.headers ?? {}
|
|
567
|
+
}
|
|
568
|
+
};
|
|
569
|
+
}
|
|
570
|
+
function extractFetchOptions(input) {
|
|
571
|
+
if (!input) {
|
|
572
|
+
return {
|
|
573
|
+
payload: void 0,
|
|
574
|
+
fetchOptions: void 0
|
|
575
|
+
};
|
|
576
|
+
}
|
|
577
|
+
const { fetchOptions, ...rest } = input;
|
|
578
|
+
const hasPayloadKeys = Object.keys(rest).length > 0;
|
|
579
|
+
return {
|
|
580
|
+
payload: hasPayloadKeys ? rest : void 0,
|
|
581
|
+
fetchOptions
|
|
582
|
+
};
|
|
583
|
+
}
|
|
584
|
+
function buildHeaders2(config, options) {
|
|
585
|
+
const headers = {
|
|
586
|
+
"Content-Type": "application/json",
|
|
587
|
+
"X-Athena-Sdk": SDK_HEADER_VALUE2
|
|
588
|
+
};
|
|
589
|
+
const apiKey = options?.apiKey ?? config.apiKey;
|
|
590
|
+
if (apiKey) {
|
|
591
|
+
headers.apikey = apiKey;
|
|
592
|
+
headers["x-api-key"] = apiKey;
|
|
593
|
+
}
|
|
594
|
+
const bearerToken = options?.bearerToken ?? config.bearerToken;
|
|
595
|
+
if (bearerToken) {
|
|
596
|
+
headers.Authorization = `Bearer ${bearerToken}`;
|
|
597
|
+
}
|
|
598
|
+
const mergedExtraHeaders = {
|
|
599
|
+
...config.headers ?? {},
|
|
600
|
+
...options?.headers ?? {}
|
|
601
|
+
};
|
|
602
|
+
Object.entries(mergedExtraHeaders).forEach(([key, value]) => {
|
|
603
|
+
const normalized = normalizeHeaderValue2(value);
|
|
604
|
+
if (normalized) {
|
|
605
|
+
headers[key] = normalized;
|
|
606
|
+
}
|
|
607
|
+
});
|
|
608
|
+
return headers;
|
|
609
|
+
}
|
|
610
|
+
function appendQueryParam(searchParams, key, value) {
|
|
611
|
+
if (value === void 0 || value === null) return;
|
|
612
|
+
if (Array.isArray(value)) {
|
|
613
|
+
value.forEach((item) => {
|
|
614
|
+
searchParams.append(key, String(item));
|
|
615
|
+
});
|
|
616
|
+
return;
|
|
617
|
+
}
|
|
618
|
+
searchParams.append(key, String(value));
|
|
619
|
+
}
|
|
620
|
+
function buildRequestUrl(baseUrl, endpoint, query) {
|
|
621
|
+
const url = `${baseUrl}${endpoint}`;
|
|
622
|
+
if (!query || Object.keys(query).length === 0) return url;
|
|
623
|
+
const searchParams = new URLSearchParams();
|
|
624
|
+
Object.entries(query).forEach(([key, value]) => appendQueryParam(searchParams, key, value));
|
|
625
|
+
const queryText = searchParams.toString();
|
|
626
|
+
return queryText ? `${url}?${queryText}` : url;
|
|
627
|
+
}
|
|
628
|
+
function inferDefaultMethod(endpoint) {
|
|
629
|
+
if (endpoint.startsWith("/reset-password/")) {
|
|
630
|
+
return "GET";
|
|
631
|
+
}
|
|
632
|
+
switch (endpoint) {
|
|
633
|
+
case "/get-session":
|
|
634
|
+
case "/list-sessions":
|
|
635
|
+
case "/verify-email":
|
|
636
|
+
case "/change-email/verify":
|
|
637
|
+
case "/delete-user/verify":
|
|
638
|
+
case "/email-list":
|
|
639
|
+
case "/email/list":
|
|
640
|
+
case "/delete-user/callback":
|
|
641
|
+
case "/list-accounts":
|
|
642
|
+
case "/passkey/generate-register-options":
|
|
643
|
+
case "/passkey/list-user-passkeys":
|
|
644
|
+
case "/.well-known/webauthn":
|
|
645
|
+
case "/admin/list-users":
|
|
646
|
+
case "/admin/athena-client/list":
|
|
647
|
+
case "/admin/audit-log/list":
|
|
648
|
+
case "/admin/email/get":
|
|
649
|
+
case "/admin/email-failure/list":
|
|
650
|
+
case "/admin/email-failure/get":
|
|
651
|
+
case "/admin/email-template/get":
|
|
652
|
+
case "/admin/email-template/list":
|
|
653
|
+
case "/admin/email/list":
|
|
654
|
+
case "/api-key/get":
|
|
655
|
+
case "/api-key/list":
|
|
656
|
+
case "/organization/get-full-organization":
|
|
657
|
+
case "/organization/list":
|
|
658
|
+
case "/organization/get-invitation":
|
|
659
|
+
case "/organization/list-invitations":
|
|
660
|
+
case "/organization/list-user-invitations":
|
|
661
|
+
case "/organization/list-members":
|
|
662
|
+
case "/organization/get-active-member":
|
|
663
|
+
case "/health":
|
|
664
|
+
case "/ok":
|
|
665
|
+
case "/error":
|
|
666
|
+
return "GET";
|
|
667
|
+
default:
|
|
668
|
+
return "POST";
|
|
669
|
+
}
|
|
670
|
+
}
|
|
671
|
+
async function callAuthEndpoint(config, context, body, query, options) {
|
|
672
|
+
const baseUrl = normalizeBaseUrl(options?.baseUrl ?? config.baseUrl);
|
|
673
|
+
const url = buildRequestUrl(baseUrl, context.endpoint, query);
|
|
674
|
+
const headers = buildHeaders2(config, options);
|
|
675
|
+
const credentials = options?.credentials ?? config.credentials ?? "include";
|
|
676
|
+
const requestInit = {
|
|
677
|
+
method: context.method,
|
|
678
|
+
headers,
|
|
679
|
+
credentials,
|
|
680
|
+
signal: options?.signal
|
|
681
|
+
};
|
|
682
|
+
if (context.method !== "GET") {
|
|
683
|
+
requestInit.body = JSON.stringify(body ?? {});
|
|
684
|
+
}
|
|
685
|
+
const fetcher = config.fetch ?? globalThis.fetch;
|
|
686
|
+
if (!fetcher) {
|
|
687
|
+
const details = toErrorDetails({
|
|
688
|
+
code: "UNKNOWN_ERROR",
|
|
689
|
+
message: "No fetch implementation available for auth client",
|
|
690
|
+
status: 0,
|
|
691
|
+
endpoint: context.endpoint,
|
|
692
|
+
method: context.method,
|
|
693
|
+
hint: "Use Node 18+ or provide `fetch` via createClient(..., { auth: { fetch } }) or createAuthClient({ fetch })"
|
|
694
|
+
});
|
|
695
|
+
return {
|
|
696
|
+
ok: false,
|
|
697
|
+
status: 0,
|
|
698
|
+
data: null,
|
|
699
|
+
error: details.message,
|
|
700
|
+
errorDetails: details,
|
|
701
|
+
raw: null
|
|
702
|
+
};
|
|
703
|
+
}
|
|
704
|
+
try {
|
|
705
|
+
const response = await fetcher(url, requestInit);
|
|
706
|
+
const rawText = await response.text();
|
|
707
|
+
const requestId = resolveRequestId2(response.headers);
|
|
708
|
+
const parsedBody = parseResponseBody2(rawText ?? "", response.headers.get("content-type"));
|
|
709
|
+
if (parsedBody.parseFailed) {
|
|
710
|
+
const details = toErrorDetails({
|
|
711
|
+
code: "INVALID_JSON",
|
|
712
|
+
message: "Auth server returned malformed JSON",
|
|
713
|
+
status: response.status,
|
|
714
|
+
endpoint: context.endpoint,
|
|
715
|
+
method: context.method,
|
|
716
|
+
requestId,
|
|
717
|
+
hint: "Verify the auth endpoint response body is valid JSON.",
|
|
718
|
+
cause: rawText.slice(0, 300)
|
|
719
|
+
});
|
|
720
|
+
return {
|
|
721
|
+
ok: false,
|
|
722
|
+
status: response.status,
|
|
723
|
+
data: null,
|
|
724
|
+
error: details.message,
|
|
725
|
+
errorDetails: details,
|
|
726
|
+
raw: parsedBody.parsed
|
|
727
|
+
};
|
|
728
|
+
}
|
|
729
|
+
const parsed = parsedBody.parsed;
|
|
730
|
+
if (!response.ok) {
|
|
731
|
+
const details = toErrorDetails({
|
|
732
|
+
code: "HTTP_ERROR",
|
|
733
|
+
message: resolveErrorMessage2(
|
|
734
|
+
parsed,
|
|
735
|
+
`Auth endpoint ${context.method} ${context.endpoint} failed with status ${response.status}`
|
|
736
|
+
),
|
|
737
|
+
status: response.status,
|
|
738
|
+
endpoint: context.endpoint,
|
|
739
|
+
method: context.method,
|
|
740
|
+
requestId
|
|
741
|
+
});
|
|
742
|
+
return {
|
|
743
|
+
ok: false,
|
|
744
|
+
status: response.status,
|
|
745
|
+
data: null,
|
|
746
|
+
error: details.message,
|
|
747
|
+
errorDetails: details,
|
|
748
|
+
raw: parsed
|
|
749
|
+
};
|
|
750
|
+
}
|
|
751
|
+
return {
|
|
752
|
+
ok: true,
|
|
753
|
+
status: response.status,
|
|
754
|
+
data: parsed ?? null,
|
|
755
|
+
error: null,
|
|
756
|
+
errorDetails: null,
|
|
757
|
+
raw: parsed
|
|
758
|
+
};
|
|
759
|
+
} catch (callError) {
|
|
760
|
+
const message = callError instanceof Error ? callError.message : String(callError);
|
|
761
|
+
const details = toErrorDetails({
|
|
762
|
+
code: "NETWORK_ERROR",
|
|
763
|
+
message: `Network error while calling ${context.method} ${context.endpoint}: ${message}`,
|
|
764
|
+
status: 0,
|
|
765
|
+
endpoint: context.endpoint,
|
|
766
|
+
method: context.method,
|
|
767
|
+
cause: message,
|
|
768
|
+
hint: "Check auth server URL, DNS, and network reachability."
|
|
769
|
+
});
|
|
770
|
+
return {
|
|
771
|
+
ok: false,
|
|
772
|
+
status: 0,
|
|
773
|
+
data: null,
|
|
774
|
+
error: details.message,
|
|
775
|
+
errorDetails: details,
|
|
776
|
+
raw: null
|
|
777
|
+
};
|
|
778
|
+
}
|
|
779
|
+
}
|
|
780
|
+
function executePostWithCompatibleInput(config, context, input, options) {
|
|
781
|
+
const { payload, fetchOptions } = extractFetchOptions(input);
|
|
782
|
+
const mergedOptions = mergeCallOptions(fetchOptions, options);
|
|
783
|
+
return callAuthEndpoint(config, context, payload ?? {}, void 0, mergedOptions);
|
|
784
|
+
}
|
|
785
|
+
function executePostWithOptionalInput(config, context, input, options) {
|
|
786
|
+
const { fetchOptions } = extractFetchOptions(input);
|
|
787
|
+
const mergedOptions = mergeCallOptions(fetchOptions, options);
|
|
788
|
+
return callAuthEndpoint(config, context, {}, void 0, mergedOptions);
|
|
789
|
+
}
|
|
790
|
+
function executeGetWithCompatibleInput(config, context, input, options) {
|
|
791
|
+
const { fetchOptions } = extractFetchOptions(input);
|
|
792
|
+
const mergedOptions = mergeCallOptions(fetchOptions, options);
|
|
793
|
+
return callAuthEndpoint(config, context, void 0, void 0, mergedOptions);
|
|
794
|
+
}
|
|
795
|
+
function executeGetWithQueryCompatibleInput(config, context, input, options) {
|
|
796
|
+
const { payload, fetchOptions } = extractFetchOptions(input);
|
|
797
|
+
const mergedOptions = mergeCallOptions(fetchOptions, options);
|
|
798
|
+
const query = payload?.query;
|
|
799
|
+
return callAuthEndpoint(
|
|
800
|
+
config,
|
|
801
|
+
context,
|
|
802
|
+
void 0,
|
|
803
|
+
query,
|
|
804
|
+
mergedOptions
|
|
805
|
+
);
|
|
806
|
+
}
|
|
807
|
+
function createAuthClient(config = {}) {
|
|
808
|
+
const normalizedBaseUrl = normalizeBaseUrl(config.baseUrl);
|
|
809
|
+
const resolvedConfig = {
|
|
810
|
+
...config,
|
|
811
|
+
baseUrl: normalizedBaseUrl
|
|
812
|
+
};
|
|
813
|
+
const request = (input, options) => {
|
|
814
|
+
const method = input.method ?? (input.body !== void 0 ? "POST" : inferDefaultMethod(input.endpoint));
|
|
815
|
+
const mergedOptions = mergeCallOptions(input.fetchOptions, options);
|
|
816
|
+
return callAuthEndpoint(
|
|
817
|
+
resolvedConfig,
|
|
818
|
+
{ endpoint: input.endpoint, method },
|
|
819
|
+
input.body,
|
|
820
|
+
input.query,
|
|
821
|
+
mergedOptions
|
|
822
|
+
);
|
|
823
|
+
};
|
|
824
|
+
const postGeneric = (endpoint, input, options) => {
|
|
825
|
+
const { payload, fetchOptions } = extractFetchOptions(input);
|
|
826
|
+
return request(
|
|
827
|
+
{
|
|
828
|
+
endpoint,
|
|
829
|
+
method: "POST",
|
|
830
|
+
body: payload ?? {},
|
|
831
|
+
fetchOptions
|
|
832
|
+
},
|
|
833
|
+
options
|
|
834
|
+
);
|
|
835
|
+
};
|
|
836
|
+
const getGeneric = (endpoint, input, options) => {
|
|
837
|
+
const { fetchOptions } = extractFetchOptions(input);
|
|
838
|
+
return request(
|
|
839
|
+
{
|
|
840
|
+
endpoint,
|
|
841
|
+
method: "GET",
|
|
842
|
+
fetchOptions
|
|
843
|
+
},
|
|
844
|
+
options
|
|
845
|
+
);
|
|
846
|
+
};
|
|
847
|
+
const getWithQuery = (endpoint, input, options) => {
|
|
848
|
+
const { payload, fetchOptions } = extractFetchOptions(input);
|
|
849
|
+
const query = payload?.query;
|
|
850
|
+
return request(
|
|
851
|
+
{
|
|
852
|
+
endpoint,
|
|
853
|
+
method: "GET",
|
|
854
|
+
query,
|
|
855
|
+
fetchOptions
|
|
856
|
+
},
|
|
857
|
+
options
|
|
858
|
+
);
|
|
859
|
+
};
|
|
860
|
+
const listUserEmailsWithFallback = async (input, options) => {
|
|
861
|
+
const primary = await getWithQuery(
|
|
862
|
+
"/email/list",
|
|
863
|
+
input,
|
|
864
|
+
options
|
|
865
|
+
);
|
|
866
|
+
if (primary.ok || primary.status !== 404 || primary.errorDetails?.code !== "HTTP_ERROR") {
|
|
867
|
+
return primary;
|
|
868
|
+
}
|
|
869
|
+
return getWithQuery(
|
|
870
|
+
"/email-list",
|
|
871
|
+
input,
|
|
872
|
+
options
|
|
873
|
+
);
|
|
874
|
+
};
|
|
875
|
+
const healthWithFallback = async (input, options) => {
|
|
876
|
+
const primary = await getGeneric("/health", input, options);
|
|
877
|
+
if (primary.ok || primary.status !== 404 || primary.errorDetails?.code !== "HTTP_ERROR") {
|
|
878
|
+
return primary;
|
|
879
|
+
}
|
|
880
|
+
const fallback = await getGeneric("/ok", input, options);
|
|
881
|
+
if (!fallback.ok) {
|
|
882
|
+
return {
|
|
883
|
+
...fallback,
|
|
884
|
+
data: null
|
|
885
|
+
};
|
|
886
|
+
}
|
|
887
|
+
const fallbackStatus = isRecord2(fallback.data) && typeof fallback.data.ok === "boolean" ? fallback.data.ok ? "ok" : "error" : "ok";
|
|
888
|
+
return {
|
|
889
|
+
...fallback,
|
|
890
|
+
data: {
|
|
891
|
+
status: fallbackStatus
|
|
892
|
+
}
|
|
893
|
+
};
|
|
894
|
+
};
|
|
895
|
+
const signOut = (input, options) => executePostWithOptionalInput(
|
|
896
|
+
resolvedConfig,
|
|
897
|
+
{ endpoint: "/sign-out", method: "POST" },
|
|
898
|
+
input,
|
|
899
|
+
options
|
|
900
|
+
);
|
|
901
|
+
const revokeSessions = (input, options) => executePostWithOptionalInput(
|
|
902
|
+
resolvedConfig,
|
|
903
|
+
{ endpoint: "/revoke-sessions", method: "POST" },
|
|
904
|
+
input,
|
|
905
|
+
options
|
|
906
|
+
);
|
|
907
|
+
const revokeOtherSessions = (input, options) => executePostWithOptionalInput(
|
|
908
|
+
resolvedConfig,
|
|
909
|
+
{ endpoint: "/revoke-other-sessions", method: "POST" },
|
|
910
|
+
input,
|
|
911
|
+
options
|
|
912
|
+
);
|
|
913
|
+
const revokeSession = (input, options) => executePostWithCompatibleInput(
|
|
914
|
+
resolvedConfig,
|
|
915
|
+
{ endpoint: "/revoke-session", method: "POST" },
|
|
916
|
+
input,
|
|
917
|
+
options
|
|
918
|
+
);
|
|
919
|
+
const deleteUser = (input, options) => {
|
|
920
|
+
const { payload, fetchOptions } = extractFetchOptions(input);
|
|
921
|
+
const mergedOptions = mergeCallOptions(fetchOptions, options);
|
|
922
|
+
return callAuthEndpoint(
|
|
923
|
+
resolvedConfig,
|
|
924
|
+
{ endpoint: "/delete-user", method: "POST" },
|
|
925
|
+
payload ?? {},
|
|
926
|
+
void 0,
|
|
927
|
+
mergedOptions
|
|
928
|
+
);
|
|
929
|
+
};
|
|
930
|
+
const deleteUserCallback = (input, options) => {
|
|
931
|
+
const { payload, fetchOptions } = extractFetchOptions(input);
|
|
932
|
+
const mergedOptions = mergeCallOptions(fetchOptions, options);
|
|
933
|
+
const query = payload ?? {};
|
|
934
|
+
return callAuthEndpoint(
|
|
935
|
+
resolvedConfig,
|
|
936
|
+
{ endpoint: "/delete-user/callback", method: "GET" },
|
|
937
|
+
void 0,
|
|
938
|
+
{
|
|
939
|
+
token: query.token,
|
|
940
|
+
callbackURL: query.callbackURL
|
|
941
|
+
},
|
|
942
|
+
mergedOptions
|
|
943
|
+
);
|
|
944
|
+
};
|
|
945
|
+
const resolveResetPasswordToken = (input, options) => {
|
|
946
|
+
const { payload, fetchOptions } = extractFetchOptions(input);
|
|
947
|
+
const mergedOptions = mergeCallOptions(fetchOptions, options);
|
|
948
|
+
const query = payload;
|
|
949
|
+
const token = query?.token?.trim();
|
|
950
|
+
if (!token) {
|
|
951
|
+
throw new Error("resolveResetPasswordToken requires a non-empty token");
|
|
952
|
+
}
|
|
953
|
+
const endpoint = `/reset-password/${encodeURIComponent(token)}`;
|
|
954
|
+
return callAuthEndpoint(
|
|
955
|
+
resolvedConfig,
|
|
956
|
+
{ endpoint, method: "GET" },
|
|
957
|
+
void 0,
|
|
958
|
+
query?.callbackURL ? { callbackURL: query.callbackURL } : void 0,
|
|
959
|
+
mergedOptions
|
|
960
|
+
);
|
|
961
|
+
};
|
|
962
|
+
const organization = {
|
|
963
|
+
create: (input, options) => executePostWithCompatibleInput(
|
|
964
|
+
resolvedConfig,
|
|
965
|
+
{ endpoint: "/organization/create", method: "POST" },
|
|
966
|
+
input,
|
|
967
|
+
options
|
|
968
|
+
),
|
|
969
|
+
update: (input, options) => executePostWithCompatibleInput(
|
|
970
|
+
resolvedConfig,
|
|
971
|
+
{ endpoint: "/organization/update", method: "POST" },
|
|
972
|
+
input,
|
|
973
|
+
options
|
|
974
|
+
),
|
|
975
|
+
delete: (input, options) => executePostWithCompatibleInput(
|
|
976
|
+
resolvedConfig,
|
|
977
|
+
{ endpoint: "/organization/delete", method: "POST" },
|
|
978
|
+
input,
|
|
979
|
+
options
|
|
980
|
+
),
|
|
981
|
+
setActive: (input, options) => executePostWithCompatibleInput(
|
|
982
|
+
resolvedConfig,
|
|
983
|
+
{ endpoint: "/organization/set-active", method: "POST" },
|
|
984
|
+
input,
|
|
985
|
+
options
|
|
986
|
+
),
|
|
987
|
+
list: (input, options) => getGeneric(
|
|
988
|
+
"/organization/list",
|
|
989
|
+
input,
|
|
990
|
+
options
|
|
991
|
+
),
|
|
992
|
+
getFull: (input, options) => executeGetWithQueryCompatibleInput(
|
|
993
|
+
resolvedConfig,
|
|
994
|
+
{ endpoint: "/organization/get-full-organization", method: "GET" },
|
|
995
|
+
input,
|
|
996
|
+
options
|
|
997
|
+
),
|
|
998
|
+
checkSlug: (input, options) => executePostWithCompatibleInput(
|
|
999
|
+
resolvedConfig,
|
|
1000
|
+
{ endpoint: "/organization/check-slug", method: "POST" },
|
|
1001
|
+
input,
|
|
1002
|
+
options
|
|
1003
|
+
),
|
|
1004
|
+
leave: (input, options) => executePostWithCompatibleInput(
|
|
1005
|
+
resolvedConfig,
|
|
1006
|
+
{ endpoint: "/organization/leave", method: "POST" },
|
|
1007
|
+
input,
|
|
1008
|
+
options
|
|
1009
|
+
),
|
|
1010
|
+
listUserInvitations: (input, options) => executeGetWithQueryCompatibleInput(
|
|
1011
|
+
resolvedConfig,
|
|
1012
|
+
{ endpoint: "/organization/list-user-invitations", method: "GET" },
|
|
1013
|
+
input,
|
|
1014
|
+
options
|
|
1015
|
+
),
|
|
1016
|
+
hasPermission: (input, options) => postGeneric(
|
|
1017
|
+
"/organization/has-permission",
|
|
1018
|
+
input,
|
|
1019
|
+
options
|
|
1020
|
+
),
|
|
1021
|
+
invitation: {
|
|
1022
|
+
cancel: (input, options) => executePostWithCompatibleInput(
|
|
1023
|
+
resolvedConfig,
|
|
1024
|
+
{ endpoint: "/organization/cancel-invitation", method: "POST" },
|
|
1025
|
+
input,
|
|
1026
|
+
options
|
|
1027
|
+
),
|
|
1028
|
+
accept: (input, options) => executePostWithCompatibleInput(
|
|
1029
|
+
resolvedConfig,
|
|
1030
|
+
{ endpoint: "/organization/accept-invitation", method: "POST" },
|
|
1031
|
+
input,
|
|
1032
|
+
options
|
|
1033
|
+
),
|
|
1034
|
+
get: (input, options) => executeGetWithQueryCompatibleInput(
|
|
1035
|
+
resolvedConfig,
|
|
1036
|
+
{ endpoint: "/organization/get-invitation", method: "GET" },
|
|
1037
|
+
input,
|
|
1038
|
+
options
|
|
1039
|
+
),
|
|
1040
|
+
reject: (input, options) => executePostWithCompatibleInput(
|
|
1041
|
+
resolvedConfig,
|
|
1042
|
+
{ endpoint: "/organization/reject-invitation", method: "POST" },
|
|
1043
|
+
input,
|
|
1044
|
+
options
|
|
1045
|
+
),
|
|
1046
|
+
list: (input, options) => executeGetWithQueryCompatibleInput(
|
|
1047
|
+
resolvedConfig,
|
|
1048
|
+
{ endpoint: "/organization/list-invitations", method: "GET" },
|
|
1049
|
+
input,
|
|
1050
|
+
options
|
|
1051
|
+
)
|
|
1052
|
+
},
|
|
1053
|
+
member: {
|
|
1054
|
+
remove: (input, options) => executePostWithCompatibleInput(
|
|
1055
|
+
resolvedConfig,
|
|
1056
|
+
{ endpoint: "/organization/remove-member", method: "POST" },
|
|
1057
|
+
input,
|
|
1058
|
+
options
|
|
1059
|
+
),
|
|
1060
|
+
updateRole: (input, options) => executePostWithCompatibleInput(
|
|
1061
|
+
resolvedConfig,
|
|
1062
|
+
{ endpoint: "/organization/update-member-role", method: "POST" },
|
|
1063
|
+
input,
|
|
1064
|
+
options
|
|
1065
|
+
),
|
|
1066
|
+
invite: (input, options) => executePostWithCompatibleInput(
|
|
1067
|
+
resolvedConfig,
|
|
1068
|
+
{ endpoint: "/organization/invite-member", method: "POST" },
|
|
1069
|
+
input,
|
|
1070
|
+
options
|
|
1071
|
+
),
|
|
1072
|
+
getActive: (input, options) => executeGetWithCompatibleInput(
|
|
1073
|
+
resolvedConfig,
|
|
1074
|
+
{ endpoint: "/organization/get-active-member", method: "GET" },
|
|
1075
|
+
input,
|
|
1076
|
+
options
|
|
1077
|
+
),
|
|
1078
|
+
list: (input, options) => executeGetWithQueryCompatibleInput(
|
|
1079
|
+
resolvedConfig,
|
|
1080
|
+
{ endpoint: "/organization/list-members", method: "GET" },
|
|
1081
|
+
input,
|
|
1082
|
+
options
|
|
1083
|
+
)
|
|
1084
|
+
}
|
|
1085
|
+
};
|
|
1086
|
+
const authResetPassword = Object.assign(
|
|
1087
|
+
(input, options) => executePostWithCompatibleInput(
|
|
1088
|
+
resolvedConfig,
|
|
1089
|
+
{ endpoint: "/reset-password", method: "POST" },
|
|
1090
|
+
input,
|
|
1091
|
+
options
|
|
1092
|
+
),
|
|
1093
|
+
{
|
|
1094
|
+
token: resolveResetPasswordToken
|
|
1095
|
+
}
|
|
1096
|
+
);
|
|
1097
|
+
const sessionRevokeBinding = (input, options) => {
|
|
1098
|
+
if (Array.isArray(input)) {
|
|
1099
|
+
if (input.length === 0) {
|
|
1100
|
+
throw new Error("session.revoke requires at least one session token");
|
|
1101
|
+
}
|
|
1102
|
+
if (input.length === 1) {
|
|
1103
|
+
return revokeSession(input[0], options);
|
|
1104
|
+
}
|
|
1105
|
+
return revokeSessions(void 0, options);
|
|
1106
|
+
}
|
|
1107
|
+
const parsed = input;
|
|
1108
|
+
const tokens = Array.isArray(parsed.tokens) ? parsed.tokens.filter((token2) => token2.trim().length > 0) : void 0;
|
|
1109
|
+
if (tokens && tokens.length > 1) {
|
|
1110
|
+
return revokeSessions(
|
|
1111
|
+
parsed.fetchOptions ? { fetchOptions: parsed.fetchOptions } : void 0,
|
|
1112
|
+
options
|
|
1113
|
+
);
|
|
1114
|
+
}
|
|
1115
|
+
if (tokens && tokens.length === 1) {
|
|
1116
|
+
return revokeSession(
|
|
1117
|
+
{ token: tokens[0], fetchOptions: parsed.fetchOptions },
|
|
1118
|
+
options
|
|
1119
|
+
);
|
|
1120
|
+
}
|
|
1121
|
+
const token = parsed.token?.trim();
|
|
1122
|
+
if (!token) {
|
|
1123
|
+
throw new Error("session.revoke requires a non-empty token or a non-empty token list");
|
|
1124
|
+
}
|
|
1125
|
+
return revokeSession(
|
|
1126
|
+
{
|
|
1127
|
+
token,
|
|
1128
|
+
fetchOptions: parsed.fetchOptions
|
|
1129
|
+
},
|
|
1130
|
+
options
|
|
1131
|
+
);
|
|
1132
|
+
};
|
|
1133
|
+
const adminUserSessionRevokeBinding = (input, options) => {
|
|
1134
|
+
const requireUserId = (userId) => {
|
|
1135
|
+
const trimmed = String(userId ?? "").trim();
|
|
1136
|
+
if (!trimmed) {
|
|
1137
|
+
throw new Error("admin.user.session.revoke requires a non-empty userId");
|
|
1138
|
+
}
|
|
1139
|
+
return trimmed;
|
|
1140
|
+
};
|
|
1141
|
+
const requireSinglePluralUserId = (sessions2) => {
|
|
1142
|
+
const uniqueUserIds = [...new Set(sessions2.map((session) => requireUserId(session.userId)))];
|
|
1143
|
+
if (uniqueUserIds.length !== 1) {
|
|
1144
|
+
throw new Error("admin.user.session.revoke requires the same userId across plural payloads");
|
|
1145
|
+
}
|
|
1146
|
+
return { userId: uniqueUserIds[0] };
|
|
1147
|
+
};
|
|
1148
|
+
if (Array.isArray(input)) {
|
|
1149
|
+
if (input.length === 0) {
|
|
1150
|
+
throw new Error("admin.user.session.revoke requires at least one payload item");
|
|
1151
|
+
}
|
|
1152
|
+
if (input.length === 1) {
|
|
1153
|
+
return postGeneric(
|
|
1154
|
+
"/admin/revoke-user-session",
|
|
1155
|
+
{
|
|
1156
|
+
...input[0],
|
|
1157
|
+
userId: requireUserId(input[0].userId)
|
|
1158
|
+
},
|
|
1159
|
+
options
|
|
1160
|
+
);
|
|
1161
|
+
}
|
|
1162
|
+
return postGeneric(
|
|
1163
|
+
"/admin/revoke-user-sessions",
|
|
1164
|
+
requireSinglePluralUserId(input),
|
|
1165
|
+
options
|
|
1166
|
+
);
|
|
1167
|
+
}
|
|
1168
|
+
const parsed = input;
|
|
1169
|
+
const sessions = parsed.sessions;
|
|
1170
|
+
if (sessions && sessions.length === 0) {
|
|
1171
|
+
throw new Error("admin.user.session.revoke requires at least one payload item");
|
|
1172
|
+
}
|
|
1173
|
+
if (sessions && sessions.length === 1) {
|
|
1174
|
+
return postGeneric(
|
|
1175
|
+
"/admin/revoke-user-session",
|
|
1176
|
+
{
|
|
1177
|
+
...sessions[0],
|
|
1178
|
+
userId: requireUserId(sessions[0].userId),
|
|
1179
|
+
fetchOptions: parsed.fetchOptions
|
|
1180
|
+
},
|
|
1181
|
+
options
|
|
1182
|
+
);
|
|
1183
|
+
}
|
|
1184
|
+
if (sessions && sessions.length > 1) {
|
|
1185
|
+
return postGeneric(
|
|
1186
|
+
"/admin/revoke-user-sessions",
|
|
1187
|
+
{
|
|
1188
|
+
...requireSinglePluralUserId(sessions),
|
|
1189
|
+
fetchOptions: parsed.fetchOptions
|
|
1190
|
+
},
|
|
1191
|
+
options
|
|
1192
|
+
);
|
|
1193
|
+
}
|
|
1194
|
+
const normalizedUserId = requireUserId(parsed.userId);
|
|
1195
|
+
if (!parsed.sessionToken) {
|
|
1196
|
+
return postGeneric(
|
|
1197
|
+
"/admin/revoke-user-sessions",
|
|
1198
|
+
{
|
|
1199
|
+
userId: normalizedUserId,
|
|
1200
|
+
fetchOptions: parsed.fetchOptions
|
|
1201
|
+
},
|
|
1202
|
+
options
|
|
1203
|
+
);
|
|
1204
|
+
}
|
|
1205
|
+
return postGeneric(
|
|
1206
|
+
"/admin/revoke-user-session",
|
|
1207
|
+
{
|
|
1208
|
+
...parsed,
|
|
1209
|
+
userId: normalizedUserId
|
|
1210
|
+
},
|
|
1211
|
+
options
|
|
1212
|
+
);
|
|
1213
|
+
};
|
|
1214
|
+
const auth = {
|
|
1215
|
+
getSession: (input, options) => getGeneric("/get-session", input, options),
|
|
1216
|
+
signOut,
|
|
1217
|
+
forgetPassword: (input, options) => postGeneric("/forget-password", input, options),
|
|
1218
|
+
resetPassword: authResetPassword,
|
|
1219
|
+
setPassword: (input, options) => postGeneric("/set-password", input, options),
|
|
1220
|
+
verifyEmail: (input, options) => {
|
|
1221
|
+
const queryInput = {
|
|
1222
|
+
query: {
|
|
1223
|
+
token: input.token,
|
|
1224
|
+
callbackURL: input.callbackURL
|
|
1225
|
+
},
|
|
1226
|
+
fetchOptions: input.fetchOptions
|
|
1227
|
+
};
|
|
1228
|
+
return getWithQuery(
|
|
1229
|
+
"/verify-email",
|
|
1230
|
+
queryInput,
|
|
1231
|
+
options
|
|
1232
|
+
);
|
|
1233
|
+
},
|
|
1234
|
+
sendVerificationEmail: (input, options) => postGeneric("/send-verification-email", input, options),
|
|
1235
|
+
changeEmail: (input, options) => postGeneric("/change-email", input, options),
|
|
1236
|
+
changeEmailVerify: (input, options) => getWithQuery("/change-email/verify", input, options),
|
|
1237
|
+
deleteUserVerify: (input, options) => getWithQuery("/delete-user/verify", input, options),
|
|
1238
|
+
changePassword: (input, options) => postGeneric("/change-password", input, options),
|
|
1239
|
+
user: {
|
|
1240
|
+
update: (input, options) => postGeneric("/update-user", input, options),
|
|
1241
|
+
delete: (input, options) => postGeneric("/delete-user", input, options),
|
|
1242
|
+
email: {
|
|
1243
|
+
list: listUserEmailsWithFallback
|
|
1244
|
+
}
|
|
1245
|
+
},
|
|
1246
|
+
session: {
|
|
1247
|
+
list: (input, options) => getGeneric("/list-sessions", input, options),
|
|
1248
|
+
revoke: sessionRevokeBinding,
|
|
1249
|
+
revokeOther: revokeOtherSessions
|
|
1250
|
+
},
|
|
1251
|
+
social: {
|
|
1252
|
+
link: (input, options) => postGeneric("/link-social", input, options)
|
|
1253
|
+
},
|
|
1254
|
+
account: {
|
|
1255
|
+
list: (input, options) => getGeneric("/list-accounts", input, options),
|
|
1256
|
+
unlink: (input, options) => postGeneric("/unlink-account", input, options)
|
|
1257
|
+
},
|
|
1258
|
+
deleteUser: {
|
|
1259
|
+
callback: deleteUserCallback
|
|
1260
|
+
},
|
|
1261
|
+
refreshToken: (input, options) => postGeneric("/refresh-token", input, options),
|
|
1262
|
+
getAccessToken: (input, options) => postGeneric("/get-access-token", input, options),
|
|
1263
|
+
health: healthWithFallback,
|
|
1264
|
+
ok: (input, options) => getGeneric("/ok", input, options),
|
|
1265
|
+
error: (input, options) => getGeneric("/error", input, options),
|
|
1266
|
+
twoFactor: {
|
|
1267
|
+
getTotpUri: (input, options) => postGeneric("/two-factor/get-totp-uri", input, options),
|
|
1268
|
+
verifyTotp: (input, options) => postGeneric("/two-factor/verify-totp", input, options),
|
|
1269
|
+
sendOtp: (input, options) => postGeneric("/two-factor/send-otp", input, options),
|
|
1270
|
+
verifyOtp: (input, options) => postGeneric("/two-factor/verify-otp", input, options),
|
|
1271
|
+
verifyBackupCode: (input, options) => postGeneric("/two-factor/verify-backup-code", input, options),
|
|
1272
|
+
generateBackupCodes: (input, options) => executePostWithCompatibleInput(
|
|
1273
|
+
resolvedConfig,
|
|
1274
|
+
{ endpoint: "/two-factor/generate-backup-codes", method: "POST" },
|
|
1275
|
+
input,
|
|
1276
|
+
options
|
|
1277
|
+
),
|
|
1278
|
+
enable: (input, options) => postGeneric("/two-factor/enable", input, options),
|
|
1279
|
+
disable: (input, options) => postGeneric("/two-factor/disable", input, options)
|
|
1280
|
+
},
|
|
1281
|
+
passkey: {
|
|
1282
|
+
generateRegisterOptions: (input, options) => getGeneric("/passkey/generate-register-options", input, options),
|
|
1283
|
+
generateAuthenticateOptions: (input, options) => postGeneric("/passkey/generate-authenticate-options", input, options),
|
|
1284
|
+
verifyRegistration: (input, options) => postGeneric("/passkey/verify-registration", input, options),
|
|
1285
|
+
verifyAuthentication: (input, options) => postGeneric("/passkey/verify-authentication", input, options),
|
|
1286
|
+
listUserPasskeys: (input, options) => getGeneric("/passkey/list-user-passkeys", input, options),
|
|
1287
|
+
deletePasskey: (input, options) => postGeneric("/passkey/delete-passkey", input, options),
|
|
1288
|
+
updatePasskey: (input, options) => postGeneric("/passkey/update-passkey", input, options),
|
|
1289
|
+
getRelatedOrigins: (input, options) => getGeneric("/.well-known/webauthn", input, options)
|
|
1290
|
+
},
|
|
1291
|
+
admin: {
|
|
1292
|
+
role: {
|
|
1293
|
+
set: (input, options) => postGeneric("/admin/set-role", input, options)
|
|
1294
|
+
},
|
|
1295
|
+
user: {
|
|
1296
|
+
list: (input, options) => getWithQuery("/admin/list-users", input, options),
|
|
1297
|
+
create: (input, options) => postGeneric("/admin/create-user", input, options),
|
|
1298
|
+
unban: (input, options) => postGeneric("/admin/unban-user", input, options),
|
|
1299
|
+
ban: (input, options) => postGeneric("/admin/ban-user", input, options),
|
|
1300
|
+
impersonate: (input, options) => postGeneric("/admin/impersonate-user", input, options),
|
|
1301
|
+
stopImpersonating: (input, options) => postGeneric("/admin/stop-impersonating", input, options),
|
|
1302
|
+
remove: (input, options) => postGeneric("/admin/remove-user", input, options),
|
|
1303
|
+
setPassword: (input, options) => postGeneric("/admin/set-user-password", input, options),
|
|
1304
|
+
session: {
|
|
1305
|
+
list: (input, options) => postGeneric("/admin/list-user-sessions", input, options),
|
|
1306
|
+
revoke: adminUserSessionRevokeBinding
|
|
1307
|
+
}
|
|
1308
|
+
},
|
|
1309
|
+
hasPermission: (input, options) => postGeneric("/admin/has-permission", input, options),
|
|
1310
|
+
apiKey: {
|
|
1311
|
+
create: (input, options) => postGeneric("/admin/api-key/create", input, options)
|
|
1312
|
+
},
|
|
1313
|
+
athenaClient: {
|
|
1314
|
+
create: (input, options) => postGeneric("/admin/athena-client/create", input, options),
|
|
1315
|
+
list: (input, options) => getWithQuery("/admin/athena-client/list", input, options)
|
|
1316
|
+
},
|
|
1317
|
+
auditLog: {
|
|
1318
|
+
list: (input, options) => getWithQuery("/admin/audit-log/list", input, options)
|
|
1319
|
+
},
|
|
1320
|
+
email: {
|
|
1321
|
+
list: (input, options) => getWithQuery("/admin/email/list", input, options),
|
|
1322
|
+
get: (input, options) => getWithQuery("/admin/email/get", input, options),
|
|
1323
|
+
create: (input, options) => postGeneric("/admin/email/create", input, options),
|
|
1324
|
+
update: (input, options) => postGeneric("/admin/email/update", input, options),
|
|
1325
|
+
delete: (input, options) => postGeneric("/admin/email/delete", input, options),
|
|
1326
|
+
failure: {
|
|
1327
|
+
list: (input, options) => getWithQuery("/admin/email-failure/list", input, options),
|
|
1328
|
+
get: (input, options) => getWithQuery("/admin/email-failure/get", input, options),
|
|
1329
|
+
create: (input, options) => postGeneric("/admin/email-failure/create", input, options),
|
|
1330
|
+
update: (input, options) => postGeneric("/admin/email-failure/update", input, options),
|
|
1331
|
+
delete: (input, options) => postGeneric("/admin/email-failure/delete", input, options)
|
|
1332
|
+
},
|
|
1333
|
+
template: {
|
|
1334
|
+
list: (input, options) => getWithQuery("/admin/email-template/list", input, options),
|
|
1335
|
+
get: (input, options) => getWithQuery("/admin/email-template/get", input, options),
|
|
1336
|
+
create: (input, options) => postGeneric("/admin/email-template/create", input, options),
|
|
1337
|
+
update: (input, options) => postGeneric("/admin/email-template/update", input, options),
|
|
1338
|
+
delete: (input, options) => postGeneric("/admin/email-template/delete", input, options)
|
|
1339
|
+
}
|
|
1340
|
+
},
|
|
1341
|
+
emailTemplate: {
|
|
1342
|
+
get: (input, options) => getWithQuery("/admin/email-template/get", input, options),
|
|
1343
|
+
create: (input, options) => postGeneric("/admin/email-template/create", input, options),
|
|
1344
|
+
delete: (input, options) => postGeneric("/admin/email-template/delete", input, options),
|
|
1345
|
+
list: (input, options) => getWithQuery("/admin/email-template/list", input, options),
|
|
1346
|
+
update: (input, options) => postGeneric("/admin/email-template/update", input, options)
|
|
1347
|
+
}
|
|
1348
|
+
},
|
|
1349
|
+
apiKey: {
|
|
1350
|
+
create: (input, options) => postGeneric("/api-key/create", input, options),
|
|
1351
|
+
get: (input, options) => getWithQuery("/api-key/get", input, options),
|
|
1352
|
+
update: (input, options) => postGeneric("/api-key/update", input, options),
|
|
1353
|
+
delete: (input, options) => postGeneric("/api-key/delete", input, options),
|
|
1354
|
+
list: (input, options) => getWithQuery("/api-key/list", input, options),
|
|
1355
|
+
verify: (input, options) => postGeneric("/api-key/verify", input, options),
|
|
1356
|
+
deleteAllExpired: (input, options) => executePostWithOptionalInput(
|
|
1357
|
+
resolvedConfig,
|
|
1358
|
+
{ endpoint: "/api-key/delete-all-expired-api-keys", method: "POST" },
|
|
1359
|
+
input,
|
|
1360
|
+
options
|
|
1361
|
+
)
|
|
1362
|
+
},
|
|
1363
|
+
signIn: {
|
|
1364
|
+
email: (input, options) => postGeneric("/sign-in/email", input, options),
|
|
1365
|
+
username: (input, options) => postGeneric("/sign-in/username", input, options),
|
|
1366
|
+
social: (input, options) => postGeneric("/sign-in/social", input, options)
|
|
1367
|
+
},
|
|
1368
|
+
signUp: {
|
|
1369
|
+
email: (input, options) => postGeneric("/sign-up/email", input, options)
|
|
1370
|
+
},
|
|
1371
|
+
organization,
|
|
1372
|
+
callback: {
|
|
1373
|
+
provider: (input, options) => {
|
|
1374
|
+
const { payload, fetchOptions } = extractFetchOptions(input);
|
|
1375
|
+
const parsed = payload;
|
|
1376
|
+
const provider = String(parsed?.provider ?? "").trim();
|
|
1377
|
+
if (!provider) {
|
|
1378
|
+
throw new Error("callback.provider requires a non-empty provider value");
|
|
1379
|
+
}
|
|
1380
|
+
const code = String(parsed?.code ?? "").trim();
|
|
1381
|
+
const state = String(parsed?.state ?? "").trim();
|
|
1382
|
+
if (!code || !state) {
|
|
1383
|
+
throw new Error("callback.provider requires non-empty code and state values");
|
|
1384
|
+
}
|
|
1385
|
+
const endpoint = `/callback/${encodeURIComponent(provider)}`;
|
|
1386
|
+
return request({
|
|
1387
|
+
endpoint,
|
|
1388
|
+
method: "GET",
|
|
1389
|
+
query: {
|
|
1390
|
+
code,
|
|
1391
|
+
state
|
|
1392
|
+
},
|
|
1393
|
+
fetchOptions
|
|
1394
|
+
}, options);
|
|
1395
|
+
}
|
|
1396
|
+
}
|
|
1397
|
+
};
|
|
1398
|
+
return {
|
|
1399
|
+
baseUrl: normalizedBaseUrl,
|
|
1400
|
+
request,
|
|
1401
|
+
signIn: {
|
|
1402
|
+
email: (input, options) => executePostWithCompatibleInput(
|
|
1403
|
+
resolvedConfig,
|
|
1404
|
+
{ endpoint: "/sign-in/email", method: "POST" },
|
|
1405
|
+
input,
|
|
1406
|
+
options
|
|
1407
|
+
),
|
|
1408
|
+
username: (input, options) => executePostWithCompatibleInput(
|
|
1409
|
+
resolvedConfig,
|
|
1410
|
+
{ endpoint: "/sign-in/username", method: "POST" },
|
|
1411
|
+
input,
|
|
1412
|
+
options
|
|
1413
|
+
),
|
|
1414
|
+
social: (input, options) => executePostWithCompatibleInput(
|
|
1415
|
+
resolvedConfig,
|
|
1416
|
+
{ endpoint: "/sign-in/social", method: "POST" },
|
|
1417
|
+
input,
|
|
1418
|
+
options
|
|
1419
|
+
)
|
|
1420
|
+
},
|
|
1421
|
+
signUp: {
|
|
1422
|
+
email: (input, options) => executePostWithCompatibleInput(
|
|
1423
|
+
resolvedConfig,
|
|
1424
|
+
{ endpoint: "/sign-up/email", method: "POST" },
|
|
1425
|
+
input,
|
|
1426
|
+
options
|
|
1427
|
+
)
|
|
1428
|
+
},
|
|
1429
|
+
signOut,
|
|
1430
|
+
logout: signOut,
|
|
1431
|
+
getSession: (input, options) => executeGetWithCompatibleInput(
|
|
1432
|
+
resolvedConfig,
|
|
1433
|
+
{ endpoint: "/get-session", method: "GET" },
|
|
1434
|
+
input,
|
|
1435
|
+
options
|
|
1436
|
+
),
|
|
1437
|
+
listSessions: (input, options) => executeGetWithCompatibleInput(
|
|
1438
|
+
resolvedConfig,
|
|
1439
|
+
{ endpoint: "/list-sessions", method: "GET" },
|
|
1440
|
+
input,
|
|
1441
|
+
options
|
|
1442
|
+
),
|
|
1443
|
+
revokeSession,
|
|
1444
|
+
clearSession: revokeSession,
|
|
1445
|
+
revokeSessions,
|
|
1446
|
+
clearSessions: revokeSessions,
|
|
1447
|
+
revokeOtherSessions,
|
|
1448
|
+
clearOtherSessions: revokeOtherSessions,
|
|
1449
|
+
forgetPassword: (input, options) => executePostWithCompatibleInput(
|
|
1450
|
+
resolvedConfig,
|
|
1451
|
+
{ endpoint: "/forget-password", method: "POST" },
|
|
1452
|
+
input,
|
|
1453
|
+
options
|
|
1454
|
+
),
|
|
1455
|
+
resetPassword: (input, options) => executePostWithCompatibleInput(
|
|
1456
|
+
resolvedConfig,
|
|
1457
|
+
{ endpoint: "/reset-password", method: "POST" },
|
|
1458
|
+
input,
|
|
1459
|
+
options
|
|
1460
|
+
),
|
|
1461
|
+
resolveResetPasswordToken,
|
|
1462
|
+
verifyEmail: (input, options) => {
|
|
1463
|
+
const { payload, fetchOptions } = extractFetchOptions(input);
|
|
1464
|
+
const mergedOptions = mergeCallOptions(fetchOptions, options);
|
|
1465
|
+
const query = payload;
|
|
1466
|
+
return callAuthEndpoint(
|
|
1467
|
+
resolvedConfig,
|
|
1468
|
+
{ endpoint: "/verify-email", method: "GET" },
|
|
1469
|
+
void 0,
|
|
1470
|
+
query ? {
|
|
1471
|
+
token: query.token,
|
|
1472
|
+
callbackURL: query.callbackURL
|
|
1473
|
+
} : void 0,
|
|
1474
|
+
mergedOptions
|
|
1475
|
+
);
|
|
1476
|
+
},
|
|
1477
|
+
sendVerificationEmail: (input, options) => executePostWithCompatibleInput(
|
|
1478
|
+
resolvedConfig,
|
|
1479
|
+
{ endpoint: "/send-verification-email", method: "POST" },
|
|
1480
|
+
input,
|
|
1481
|
+
options
|
|
1482
|
+
),
|
|
1483
|
+
changeEmail: (input, options) => executePostWithCompatibleInput(
|
|
1484
|
+
resolvedConfig,
|
|
1485
|
+
{ endpoint: "/change-email", method: "POST" },
|
|
1486
|
+
input,
|
|
1487
|
+
options
|
|
1488
|
+
),
|
|
1489
|
+
changePassword: (input, options) => executePostWithCompatibleInput(
|
|
1490
|
+
resolvedConfig,
|
|
1491
|
+
{ endpoint: "/change-password", method: "POST" },
|
|
1492
|
+
input,
|
|
1493
|
+
options
|
|
1494
|
+
),
|
|
1495
|
+
updateUser: (input, options) => executePostWithCompatibleInput(
|
|
1496
|
+
resolvedConfig,
|
|
1497
|
+
{ endpoint: "/update-user", method: "POST" },
|
|
1498
|
+
input,
|
|
1499
|
+
options
|
|
1500
|
+
),
|
|
1501
|
+
deleteUser,
|
|
1502
|
+
deleteUserCallback,
|
|
1503
|
+
linkSocial: (input, options) => executePostWithCompatibleInput(
|
|
1504
|
+
resolvedConfig,
|
|
1505
|
+
{ endpoint: "/link-social", method: "POST" },
|
|
1506
|
+
input,
|
|
1507
|
+
options
|
|
1508
|
+
),
|
|
1509
|
+
listAccounts: (input, options) => executeGetWithCompatibleInput(
|
|
1510
|
+
resolvedConfig,
|
|
1511
|
+
{ endpoint: "/list-accounts", method: "GET" },
|
|
1512
|
+
input,
|
|
1513
|
+
options
|
|
1514
|
+
),
|
|
1515
|
+
unlinkAccount: (input, options) => executePostWithCompatibleInput(
|
|
1516
|
+
resolvedConfig,
|
|
1517
|
+
{ endpoint: "/unlink-account", method: "POST" },
|
|
1518
|
+
input,
|
|
1519
|
+
options
|
|
1520
|
+
),
|
|
1521
|
+
refreshToken: (input, options) => executePostWithCompatibleInput(
|
|
1522
|
+
resolvedConfig,
|
|
1523
|
+
{ endpoint: "/refresh-token", method: "POST" },
|
|
1524
|
+
input,
|
|
1525
|
+
options
|
|
1526
|
+
),
|
|
1527
|
+
getAccessToken: (input, options) => executePostWithCompatibleInput(
|
|
1528
|
+
resolvedConfig,
|
|
1529
|
+
{ endpoint: "/get-access-token", method: "POST" },
|
|
1530
|
+
input,
|
|
1531
|
+
options
|
|
1532
|
+
),
|
|
1533
|
+
organization,
|
|
1534
|
+
auth
|
|
1535
|
+
};
|
|
1536
|
+
}
|
|
1537
|
+
|
|
1538
|
+
// src/auxiliaries.ts
|
|
1539
|
+
var AthenaErrorKind = {
|
|
1540
|
+
UniqueViolation: "unique_violation",
|
|
1541
|
+
NotFound: "not_found",
|
|
1542
|
+
Validation: "validation",
|
|
1543
|
+
Auth: "auth",
|
|
1544
|
+
RateLimit: "rate_limit",
|
|
1545
|
+
Transient: "transient",
|
|
1546
|
+
Unknown: "unknown"
|
|
1547
|
+
};
|
|
1548
|
+
var AthenaErrorCode = {
|
|
1549
|
+
UniqueViolation: "UNIQUE_VIOLATION",
|
|
1550
|
+
NotFound: "NOT_FOUND",
|
|
1551
|
+
ValidationFailed: "VALIDATION_FAILED",
|
|
1552
|
+
AuthUnauthorized: "AUTH_UNAUTHORIZED",
|
|
1553
|
+
AuthForbidden: "AUTH_FORBIDDEN",
|
|
1554
|
+
RateLimited: "RATE_LIMITED",
|
|
1555
|
+
NetworkUnavailable: "NETWORK_UNAVAILABLE",
|
|
1556
|
+
TransientFailure: "TRANSIENT_FAILURE",
|
|
1557
|
+
HttpFailure: "HTTP_FAILURE",
|
|
1558
|
+
Unknown: "UNKNOWN"
|
|
1559
|
+
};
|
|
1560
|
+
var AthenaErrorCategory = {
|
|
1561
|
+
Transport: "transport",
|
|
1562
|
+
Client: "client",
|
|
1563
|
+
Server: "server",
|
|
1564
|
+
Database: "database",
|
|
1565
|
+
Unknown: "unknown"
|
|
1566
|
+
};
|
|
1567
|
+
function parseBooleanFlag(rawValue, fallback) {
|
|
1568
|
+
if (!rawValue) return fallback;
|
|
1569
|
+
const normalized = rawValue.trim().toLowerCase();
|
|
1570
|
+
if (normalized === "1" || normalized === "true" || normalized === "yes" || normalized === "on") {
|
|
1571
|
+
return true;
|
|
1572
|
+
}
|
|
1573
|
+
if (normalized === "0" || normalized === "false" || normalized === "no" || normalized === "off") {
|
|
1574
|
+
return false;
|
|
1575
|
+
}
|
|
1576
|
+
return fallback;
|
|
1577
|
+
}
|
|
1578
|
+
var AthenaError = class extends Error {
|
|
1579
|
+
code;
|
|
1580
|
+
kind;
|
|
1581
|
+
category;
|
|
1582
|
+
status;
|
|
1583
|
+
retryable;
|
|
1584
|
+
requestId;
|
|
1585
|
+
context;
|
|
1586
|
+
raw;
|
|
1587
|
+
constructor(input) {
|
|
1588
|
+
super(input.message);
|
|
1589
|
+
this.name = "AthenaError";
|
|
1590
|
+
this.code = input.code;
|
|
1591
|
+
this.kind = input.kind;
|
|
1592
|
+
this.category = input.category;
|
|
1593
|
+
this.status = input.status;
|
|
1594
|
+
this.retryable = input.retryable ?? false;
|
|
1595
|
+
this.requestId = input.requestId;
|
|
1596
|
+
this.context = input.context;
|
|
1597
|
+
this.raw = input.raw;
|
|
1598
|
+
}
|
|
1599
|
+
};
|
|
1600
|
+
function isRecord3(value) {
|
|
1601
|
+
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
1602
|
+
}
|
|
1603
|
+
function isAthenaErrorKind(value) {
|
|
1604
|
+
return value === "unique_violation" || value === "not_found" || value === "validation" || value === "auth" || value === "rate_limit" || value === "transient" || value === "unknown";
|
|
1605
|
+
}
|
|
1606
|
+
function isAthenaErrorCode(value) {
|
|
1607
|
+
return value === "UNIQUE_VIOLATION" || value === "NOT_FOUND" || value === "VALIDATION_FAILED" || value === "AUTH_UNAUTHORIZED" || value === "AUTH_FORBIDDEN" || value === "RATE_LIMITED" || value === "NETWORK_UNAVAILABLE" || value === "TRANSIENT_FAILURE" || value === "HTTP_FAILURE" || value === "UNKNOWN";
|
|
1608
|
+
}
|
|
1609
|
+
function isAthenaErrorCategory(value) {
|
|
1610
|
+
return value === "transport" || value === "client" || value === "server" || value === "database" || value === "unknown";
|
|
1611
|
+
}
|
|
1612
|
+
function isNormalizedAthenaError(value) {
|
|
1613
|
+
return isRecord3(value) && isAthenaErrorKind(value.kind) && isAthenaErrorCode(value.code) && isAthenaErrorCategory(value.category) && typeof value.retryable === "boolean" && typeof value.message === "string" && "raw" in value;
|
|
1614
|
+
}
|
|
1615
|
+
function withContextOverrides(normalized, context) {
|
|
1616
|
+
if (!context?.table && !context?.operation) {
|
|
1617
|
+
return normalized;
|
|
1618
|
+
}
|
|
1619
|
+
return {
|
|
1620
|
+
...normalized,
|
|
1621
|
+
table: context.table ?? normalized.table,
|
|
1622
|
+
operation: context.operation ?? normalized.operation
|
|
1623
|
+
};
|
|
1624
|
+
}
|
|
1625
|
+
function resolveAttachedNormalizedError(resultOrError) {
|
|
1626
|
+
if (!isRecord3(resultOrError)) return void 0;
|
|
1627
|
+
if (!("__athenaNormalizedError" in resultOrError)) return void 0;
|
|
1628
|
+
const candidate = resultOrError.__athenaNormalizedError;
|
|
1629
|
+
return isNormalizedAthenaError(candidate) ? candidate : void 0;
|
|
1630
|
+
}
|
|
1631
|
+
function safeStringify(value) {
|
|
1632
|
+
try {
|
|
1633
|
+
const serialized = JSON.stringify(value);
|
|
1634
|
+
return serialized ?? String(value);
|
|
1635
|
+
} catch {
|
|
1636
|
+
return "[unserializable]";
|
|
1637
|
+
}
|
|
1638
|
+
}
|
|
1639
|
+
function contextHint(context) {
|
|
1640
|
+
if (!context?.identity) return void 0;
|
|
1641
|
+
const identity = typeof context.identity === "string" ? context.identity : safeStringify(context.identity);
|
|
1642
|
+
return `Identity: ${identity}`;
|
|
1643
|
+
}
|
|
1644
|
+
function isAthenaResultLike(value) {
|
|
1645
|
+
return isRecord3(value) && "status" in value && "error" in value && "data" in value && typeof value.status === "number";
|
|
1646
|
+
}
|
|
1647
|
+
function operationFromDetails(details) {
|
|
1648
|
+
if (!details?.endpoint) return void 0;
|
|
1649
|
+
if (details.endpoint === "/gateway/fetch" || details.endpoint === "/gateway/query") return "select";
|
|
1650
|
+
if (details.endpoint === "/gateway/insert") return "insert";
|
|
1651
|
+
if (details.endpoint === "/gateway/update") return "update";
|
|
1652
|
+
if (details.endpoint === "/gateway/delete") return "delete";
|
|
1653
|
+
if (details.endpoint === "/gateway/rpc" || details.endpoint.startsWith("/rpc/")) return "rpc";
|
|
1654
|
+
return void 0;
|
|
1655
|
+
}
|
|
1656
|
+
function matchRegex(input, patterns) {
|
|
1657
|
+
for (const pattern of patterns) {
|
|
1658
|
+
const match = pattern.exec(input);
|
|
1659
|
+
if (match?.[1]) return match[1];
|
|
1660
|
+
}
|
|
1661
|
+
return void 0;
|
|
1662
|
+
}
|
|
1663
|
+
function extractConstraint(message) {
|
|
1664
|
+
return matchRegex(message, [
|
|
1665
|
+
/unique constraint\s+["'`]([^"'`]+)["'`]/i,
|
|
1666
|
+
/constraint\s+["'`]([^"'`]+)["'`]/i
|
|
1667
|
+
]);
|
|
1668
|
+
}
|
|
1669
|
+
function extractTable(message) {
|
|
1670
|
+
return matchRegex(message, [
|
|
1671
|
+
/(?:table|relation)\s+["'`]([^"'`]+)["'`]/i,
|
|
1672
|
+
/on\s+table\s+([a-zA-Z0-9_.]+)/i
|
|
1673
|
+
]);
|
|
1674
|
+
}
|
|
1675
|
+
function classifyKind(status, code, message) {
|
|
1676
|
+
const lower = message.toLowerCase();
|
|
1677
|
+
const hasUniquePattern = lower.includes("unique constraint") || lower.includes("duplicate key") || lower.includes("already exists") || lower.includes("duplicate");
|
|
1678
|
+
const hasNotFoundPattern = lower.includes("not found") || lower.includes("no rows");
|
|
1679
|
+
const hasValidationPattern = lower.includes("validation") || lower.includes("invalid") || lower.includes("malformed");
|
|
1680
|
+
const hasAuthPattern = lower.includes("unauthorized") || lower.includes("forbidden") || lower.includes("auth");
|
|
1681
|
+
const hasRateLimitPattern = lower.includes("rate limit") || lower.includes("too many requests");
|
|
1682
|
+
const hasTransientPattern = lower.includes("timeout") || lower.includes("temporar") || lower.includes("connection reset") || lower.includes("socket") || lower.includes("deadlock");
|
|
1683
|
+
if (status === 409 || hasUniquePattern) return "unique_violation";
|
|
1684
|
+
if (status === 404 || hasNotFoundPattern) return "not_found";
|
|
1685
|
+
if (status === 401 || status === 403 || hasAuthPattern) return "auth";
|
|
1686
|
+
if (status === 429 || hasRateLimitPattern) return "rate_limit";
|
|
1687
|
+
if (status === 400 || status === 422 || hasValidationPattern) return "validation";
|
|
1688
|
+
if (code === "NETWORK_ERROR" || status === 0 || status !== void 0 && status >= 500 || hasTransientPattern) {
|
|
1689
|
+
return "transient";
|
|
1690
|
+
}
|
|
1691
|
+
return "unknown";
|
|
1692
|
+
}
|
|
1693
|
+
function toAthenaErrorCode(kind, status, gatewayCode) {
|
|
1694
|
+
if (gatewayCode === "NETWORK_ERROR" || kind === "transient" && status === 0) {
|
|
1695
|
+
return AthenaErrorCode.NetworkUnavailable;
|
|
1696
|
+
}
|
|
1697
|
+
switch (kind) {
|
|
1698
|
+
case "unique_violation":
|
|
1699
|
+
return AthenaErrorCode.UniqueViolation;
|
|
1700
|
+
case "not_found":
|
|
1701
|
+
return AthenaErrorCode.NotFound;
|
|
1702
|
+
case "validation":
|
|
1703
|
+
return AthenaErrorCode.ValidationFailed;
|
|
1704
|
+
case "rate_limit":
|
|
1705
|
+
return AthenaErrorCode.RateLimited;
|
|
1706
|
+
case "auth":
|
|
1707
|
+
if (status === 403) {
|
|
1708
|
+
return AthenaErrorCode.AuthForbidden;
|
|
1709
|
+
}
|
|
1710
|
+
return AthenaErrorCode.AuthUnauthorized;
|
|
1711
|
+
case "transient":
|
|
1712
|
+
return status !== void 0 && status >= 500 ? AthenaErrorCode.HttpFailure : AthenaErrorCode.TransientFailure;
|
|
1713
|
+
case "unknown":
|
|
1714
|
+
default:
|
|
1715
|
+
return status !== void 0 && status >= 400 ? AthenaErrorCode.HttpFailure : AthenaErrorCode.Unknown;
|
|
1716
|
+
}
|
|
1717
|
+
}
|
|
1718
|
+
function toAthenaErrorCategory(kind, status) {
|
|
1719
|
+
if (kind === "transient" && (status === 0 || status === void 0)) {
|
|
1720
|
+
return AthenaErrorCategory.Transport;
|
|
1721
|
+
}
|
|
1722
|
+
if (kind === "unique_violation") return AthenaErrorCategory.Database;
|
|
1723
|
+
if (kind === "validation" || kind === "auth" || kind === "not_found") return AthenaErrorCategory.Client;
|
|
1724
|
+
if (kind === "rate_limit" || kind === "transient") return AthenaErrorCategory.Server;
|
|
1725
|
+
return AthenaErrorCategory.Unknown;
|
|
1726
|
+
}
|
|
1727
|
+
function isRetryable(kind, status) {
|
|
1728
|
+
if (kind === "rate_limit" || kind === "transient") return true;
|
|
1729
|
+
return status !== void 0 && status >= 500;
|
|
1730
|
+
}
|
|
1731
|
+
function toGatewayCode(kind, status) {
|
|
1732
|
+
if (kind === "transient" && (status === 0 || status === void 0)) return "NETWORK_ERROR";
|
|
1733
|
+
if (kind === "validation") return "INVALID_JSON";
|
|
1734
|
+
if (status !== void 0 && status >= 400) return "HTTP_ERROR";
|
|
1735
|
+
return "UNKNOWN_ERROR";
|
|
1736
|
+
}
|
|
1737
|
+
function toAthenaGatewayError(source, fallbackMessage, context) {
|
|
1738
|
+
if (isAthenaGatewayError(source)) {
|
|
1739
|
+
return source;
|
|
1740
|
+
}
|
|
1741
|
+
if (isAthenaResultLike(source) && source.errorDetails) {
|
|
1742
|
+
return new AthenaGatewayError({
|
|
1743
|
+
code: source.errorDetails.code,
|
|
1744
|
+
message: source.error ?? source.errorDetails.message,
|
|
1745
|
+
status: source.status,
|
|
1746
|
+
endpoint: source.errorDetails.endpoint,
|
|
1747
|
+
method: source.errorDetails.method,
|
|
1748
|
+
requestId: source.errorDetails.requestId,
|
|
1749
|
+
hint: source.errorDetails.hint,
|
|
1750
|
+
cause: source.errorDetails.cause
|
|
1751
|
+
});
|
|
1752
|
+
}
|
|
1753
|
+
const normalized = normalizeAthenaError(source, context);
|
|
1754
|
+
const message = isAthenaResultLike(source) && source.error == null && source.errorDetails == null ? fallbackMessage : normalized.message || fallbackMessage;
|
|
1755
|
+
return new AthenaGatewayError({
|
|
1756
|
+
code: toGatewayCode(normalized.kind, normalized.status),
|
|
1757
|
+
message,
|
|
1758
|
+
status: normalized.status ?? 0,
|
|
1759
|
+
hint: normalized.constraint != null ? `Constraint: ${normalized.constraint}` : contextHint(context),
|
|
1760
|
+
cause: typeof normalized.raw === "string" ? normalized.raw : safeStringify(normalized.raw)
|
|
1761
|
+
});
|
|
1762
|
+
}
|
|
1763
|
+
function isOk(result) {
|
|
1764
|
+
return result.error == null && result.status >= 200 && result.status < 300;
|
|
1765
|
+
}
|
|
1766
|
+
function normalizeAthenaError(resultOrError, context) {
|
|
1767
|
+
const attached = resolveAttachedNormalizedError(resultOrError);
|
|
1768
|
+
if (attached) {
|
|
1769
|
+
return withContextOverrides(attached, context);
|
|
1770
|
+
}
|
|
1771
|
+
if (isAthenaResultLike(resultOrError)) {
|
|
1772
|
+
const details = resultOrError.errorDetails;
|
|
1773
|
+
const message2 = resultOrError.error ?? details?.message ?? `Athena ${context?.operation ?? operationFromDetails(details) ?? "request"} failed`;
|
|
1774
|
+
const operation = context?.operation ?? operationFromDetails(details);
|
|
1775
|
+
const table = context?.table ?? extractTable(message2);
|
|
1776
|
+
const constraint = extractConstraint(message2);
|
|
1777
|
+
const kind2 = classifyKind(resultOrError.status, details?.code, message2);
|
|
1778
|
+
const code = toAthenaErrorCode(kind2, resultOrError.status, details?.code);
|
|
1779
|
+
const category = toAthenaErrorCategory(kind2, resultOrError.status);
|
|
1780
|
+
return {
|
|
1781
|
+
kind: kind2,
|
|
1782
|
+
code,
|
|
1783
|
+
category,
|
|
1784
|
+
retryable: isRetryable(kind2, resultOrError.status),
|
|
1785
|
+
status: resultOrError.status,
|
|
1786
|
+
constraint,
|
|
1787
|
+
table,
|
|
1788
|
+
operation,
|
|
1789
|
+
message: message2,
|
|
1790
|
+
raw: resultOrError.raw
|
|
1791
|
+
};
|
|
1792
|
+
}
|
|
1793
|
+
if (isAthenaGatewayError(resultOrError)) {
|
|
1794
|
+
const details = resultOrError.toDetails();
|
|
1795
|
+
const operation = context?.operation ?? operationFromDetails(details);
|
|
1796
|
+
const table = context?.table ?? extractTable(resultOrError.message);
|
|
1797
|
+
const constraint = extractConstraint(resultOrError.message);
|
|
1798
|
+
const kind2 = classifyKind(resultOrError.status, resultOrError.code, resultOrError.message);
|
|
1799
|
+
const code = toAthenaErrorCode(kind2, resultOrError.status, resultOrError.code);
|
|
1800
|
+
const category = toAthenaErrorCategory(kind2, resultOrError.status);
|
|
1801
|
+
return {
|
|
1802
|
+
kind: kind2,
|
|
1803
|
+
code,
|
|
1804
|
+
category,
|
|
1805
|
+
retryable: isRetryable(kind2, resultOrError.status),
|
|
1806
|
+
status: resultOrError.status,
|
|
1807
|
+
constraint,
|
|
1808
|
+
table,
|
|
1809
|
+
operation,
|
|
1810
|
+
message: resultOrError.message,
|
|
1811
|
+
raw: resultOrError
|
|
1812
|
+
};
|
|
1813
|
+
}
|
|
1814
|
+
if (resultOrError instanceof Error) {
|
|
1815
|
+
const maybeStatus = isRecord3(resultOrError) && typeof resultOrError.status === "number" ? resultOrError.status : void 0;
|
|
1816
|
+
const kind2 = classifyKind(maybeStatus, void 0, resultOrError.message);
|
|
1817
|
+
return {
|
|
1818
|
+
kind: kind2,
|
|
1819
|
+
code: toAthenaErrorCode(kind2, maybeStatus),
|
|
1820
|
+
category: toAthenaErrorCategory(kind2, maybeStatus),
|
|
1821
|
+
retryable: isRetryable(kind2, maybeStatus),
|
|
1822
|
+
status: maybeStatus,
|
|
1823
|
+
constraint: extractConstraint(resultOrError.message),
|
|
1824
|
+
table: context?.table ?? extractTable(resultOrError.message),
|
|
1825
|
+
operation: context?.operation,
|
|
1826
|
+
message: resultOrError.message,
|
|
1827
|
+
raw: resultOrError
|
|
1828
|
+
};
|
|
1829
|
+
}
|
|
1830
|
+
const message = typeof resultOrError === "string" ? resultOrError : "Unknown Athena error";
|
|
1831
|
+
const kind = classifyKind(void 0, void 0, message);
|
|
1832
|
+
return {
|
|
1833
|
+
kind,
|
|
1834
|
+
code: toAthenaErrorCode(kind, void 0),
|
|
1835
|
+
category: toAthenaErrorCategory(kind, void 0),
|
|
1836
|
+
retryable: isRetryable(kind, void 0),
|
|
1837
|
+
status: void 0,
|
|
1838
|
+
constraint: extractConstraint(message),
|
|
1839
|
+
table: context?.table ?? extractTable(message),
|
|
1840
|
+
operation: context?.operation,
|
|
1841
|
+
message,
|
|
1842
|
+
raw: resultOrError
|
|
1843
|
+
};
|
|
1844
|
+
}
|
|
1845
|
+
function unwrapRows(result, options) {
|
|
1846
|
+
if (!isOk(result)) {
|
|
1847
|
+
throw toAthenaGatewayError(result, "Athena request failed", options?.context);
|
|
1848
|
+
}
|
|
1849
|
+
if (result.data == null) return [];
|
|
1850
|
+
return Array.isArray(result.data) ? result.data : [result.data];
|
|
1851
|
+
}
|
|
1852
|
+
function unwrap(result, options) {
|
|
1853
|
+
if (!isOk(result)) {
|
|
1854
|
+
throw toAthenaGatewayError(result, "Athena request failed", options?.context);
|
|
1855
|
+
}
|
|
1856
|
+
if (result.data == null && !options?.allowNull) {
|
|
1857
|
+
throw toAthenaGatewayError(result, "Expected data but received null", options?.context);
|
|
1858
|
+
}
|
|
1859
|
+
return result.data;
|
|
1860
|
+
}
|
|
1861
|
+
function unwrapOne(result, options) {
|
|
1862
|
+
const rows = unwrapRows(result, options);
|
|
1863
|
+
if (!rows.length) {
|
|
1864
|
+
if (options?.allowNull) return null;
|
|
1865
|
+
throw toAthenaGatewayError(result, "Expected one row but received none", options?.context);
|
|
1866
|
+
}
|
|
1867
|
+
if (options?.requireExactlyOne && rows.length !== 1) {
|
|
1868
|
+
throw toAthenaGatewayError(
|
|
1869
|
+
result,
|
|
1870
|
+
`Expected exactly one row but received ${rows.length}`,
|
|
1871
|
+
options.context
|
|
1872
|
+
);
|
|
1873
|
+
}
|
|
1874
|
+
return rows[0];
|
|
1875
|
+
}
|
|
1876
|
+
function requireSuccess(result, context) {
|
|
1877
|
+
if (!isOk(result)) {
|
|
1878
|
+
throw toAthenaGatewayError(
|
|
1879
|
+
result,
|
|
1880
|
+
`Athena ${context?.operation ?? "request"} failed`,
|
|
1881
|
+
context
|
|
1882
|
+
);
|
|
1883
|
+
}
|
|
1884
|
+
return result;
|
|
1885
|
+
}
|
|
1886
|
+
function requireAffected(result, options, context) {
|
|
1887
|
+
requireSuccess(result, context);
|
|
1888
|
+
const minimum = options?.min ?? 1;
|
|
1889
|
+
const count = result.count;
|
|
1890
|
+
if (count == null) {
|
|
1891
|
+
throw new AthenaGatewayError({
|
|
1892
|
+
code: "UNKNOWN_ERROR",
|
|
1893
|
+
status: result.status,
|
|
1894
|
+
message: "Expected affected row count but response.count is missing",
|
|
1895
|
+
hint: 'Set call option { count: "exact" } for mutation postcondition checks.',
|
|
1896
|
+
cause: safeStringify(result.raw)
|
|
1897
|
+
});
|
|
1898
|
+
}
|
|
1899
|
+
if (count < minimum) {
|
|
1900
|
+
throw new AthenaGatewayError({
|
|
1901
|
+
code: "UNKNOWN_ERROR",
|
|
1902
|
+
status: result.status,
|
|
1903
|
+
message: `Expected at least ${minimum} affected rows but received ${count}`,
|
|
1904
|
+
hint: contextHint(context),
|
|
1905
|
+
cause: safeStringify(result.raw)
|
|
1906
|
+
});
|
|
1907
|
+
}
|
|
1908
|
+
return count;
|
|
1909
|
+
}
|
|
1910
|
+
function applyBounds(value, options) {
|
|
1911
|
+
if (options?.min !== void 0 && value < options.min) return null;
|
|
1912
|
+
if (options?.max !== void 0 && value > options.max) return null;
|
|
1913
|
+
return value;
|
|
1914
|
+
}
|
|
1915
|
+
function parseIntegerString(value) {
|
|
1916
|
+
const normalized = value.trim();
|
|
1917
|
+
if (!/^[-+]?\d+$/.test(normalized)) return null;
|
|
1918
|
+
const parsed = Number(normalized);
|
|
1919
|
+
if (!Number.isFinite(parsed) || !Number.isInteger(parsed)) return null;
|
|
1920
|
+
return parsed;
|
|
1921
|
+
}
|
|
1922
|
+
function coerceInt(value, options) {
|
|
1923
|
+
if (value == null) return null;
|
|
1924
|
+
if (typeof value === "number") {
|
|
1925
|
+
if (!Number.isFinite(value) || !Number.isInteger(value)) return null;
|
|
1926
|
+
return applyBounds(value, options);
|
|
1927
|
+
}
|
|
1928
|
+
if (typeof value === "string") {
|
|
1929
|
+
const parsed = parseIntegerString(value);
|
|
1930
|
+
if (parsed == null) return null;
|
|
1931
|
+
return applyBounds(parsed, options);
|
|
1932
|
+
}
|
|
1933
|
+
if (typeof value === "bigint") {
|
|
1934
|
+
if (options?.strictBigInt) {
|
|
1935
|
+
if (value > BigInt(Number.MAX_SAFE_INTEGER) || value < BigInt(Number.MIN_SAFE_INTEGER)) {
|
|
1936
|
+
return null;
|
|
1937
|
+
}
|
|
1938
|
+
}
|
|
1939
|
+
const parsed = Number(value);
|
|
1940
|
+
if (!Number.isFinite(parsed) || !Number.isInteger(parsed)) return null;
|
|
1941
|
+
return applyBounds(parsed, options);
|
|
1942
|
+
}
|
|
1943
|
+
return null;
|
|
1944
|
+
}
|
|
1945
|
+
function assertInt(value, label = "value", options) {
|
|
1946
|
+
const parsed = coerceInt(value, options);
|
|
1947
|
+
if (parsed == null) {
|
|
1948
|
+
throw new TypeError(`${label} must be a finite integer`);
|
|
1949
|
+
}
|
|
1950
|
+
return parsed;
|
|
1951
|
+
}
|
|
1952
|
+
function defaultShouldRetry(error) {
|
|
1953
|
+
const normalized = normalizeAthenaError(error);
|
|
1954
|
+
return normalized.kind === "transient" || normalized.kind === "rate_limit";
|
|
1955
|
+
}
|
|
1956
|
+
function computeDelayMs(attempt, error, config) {
|
|
1957
|
+
const baseDelay = config.baseDelayMs;
|
|
1958
|
+
const rawDelay = typeof config.backoff === "function" ? config.backoff(attempt, error) : config.backoff === "linear" ? baseDelay * attempt : baseDelay * Math.pow(2, attempt - 1);
|
|
1959
|
+
const safeDelay = Number.isFinite(rawDelay) ? Math.max(0, rawDelay) : 0;
|
|
1960
|
+
const clamped = Math.min(config.maxDelayMs, safeDelay);
|
|
1961
|
+
const jitterFactor = typeof config.jitter === "number" ? Math.max(0, Math.min(1, config.jitter)) : config.jitter ? 0.2 : 0;
|
|
1962
|
+
if (!jitterFactor) return clamped;
|
|
1963
|
+
const deviation = clamped * jitterFactor;
|
|
1964
|
+
const offset = (Math.random() * 2 - 1) * deviation;
|
|
1965
|
+
return Math.max(0, clamped + offset);
|
|
1966
|
+
}
|
|
1967
|
+
function sleep(ms) {
|
|
1968
|
+
if (ms <= 0) return Promise.resolve();
|
|
1969
|
+
return new Promise((resolve) => {
|
|
1970
|
+
setTimeout(resolve, ms);
|
|
1971
|
+
});
|
|
1972
|
+
}
|
|
1973
|
+
async function withRetry(config, fn) {
|
|
1974
|
+
const retries = Math.max(0, Math.trunc(config.retries));
|
|
1975
|
+
const shouldRetry = config.shouldRetry ?? defaultShouldRetry;
|
|
1976
|
+
const resolvedConfig = {
|
|
1977
|
+
baseDelayMs: config.baseDelayMs ?? 100,
|
|
1978
|
+
maxDelayMs: config.maxDelayMs ?? 1e4,
|
|
1979
|
+
backoff: config.backoff ?? "exponential",
|
|
1980
|
+
jitter: config.jitter ?? false
|
|
1981
|
+
};
|
|
1982
|
+
for (let attempts = 0; attempts <= retries; attempts += 1) {
|
|
1983
|
+
try {
|
|
1984
|
+
return await fn();
|
|
1985
|
+
} catch (error) {
|
|
1986
|
+
if (attempts >= retries) {
|
|
1987
|
+
throw error;
|
|
1988
|
+
}
|
|
1989
|
+
const currentAttempt = attempts + 1;
|
|
1990
|
+
const retry = await shouldRetry(error, currentAttempt);
|
|
1991
|
+
if (!retry) {
|
|
1992
|
+
throw error;
|
|
1993
|
+
}
|
|
1994
|
+
const delay = computeDelayMs(currentAttempt, error, resolvedConfig);
|
|
1995
|
+
await sleep(delay);
|
|
1996
|
+
}
|
|
1997
|
+
}
|
|
1998
|
+
throw new Error("withRetry reached an unexpected state");
|
|
1999
|
+
}
|
|
2000
|
+
|
|
2001
|
+
// src/db/module.ts
|
|
2002
|
+
function createDbModule(input) {
|
|
2003
|
+
const db = {
|
|
2004
|
+
from(table) {
|
|
2005
|
+
return input.from(table);
|
|
2006
|
+
},
|
|
2007
|
+
select(table, columns, options) {
|
|
2008
|
+
return input.from(table).select(columns, options);
|
|
2009
|
+
},
|
|
2010
|
+
insert(table, values, options) {
|
|
2011
|
+
return Array.isArray(values) ? input.from(table).insert(values, options) : input.from(table).insert(values, options);
|
|
2012
|
+
},
|
|
2013
|
+
upsert(table, values, options) {
|
|
2014
|
+
return Array.isArray(values) ? input.from(table).upsert(values, options) : input.from(table).upsert(values, options);
|
|
2015
|
+
},
|
|
2016
|
+
update(table, values, options) {
|
|
2017
|
+
return input.from(table).update(values, options);
|
|
2018
|
+
},
|
|
2019
|
+
delete(table, options) {
|
|
2020
|
+
return input.from(table).delete(options);
|
|
2021
|
+
},
|
|
2022
|
+
rpc(fn, args, options) {
|
|
2023
|
+
return input.rpc(fn, args, options);
|
|
2024
|
+
},
|
|
2025
|
+
query(query, options) {
|
|
2026
|
+
return input.query(query, options);
|
|
2027
|
+
}
|
|
2028
|
+
};
|
|
2029
|
+
return db;
|
|
2030
|
+
}
|
|
2031
|
+
|
|
2032
|
+
// src/client.ts
|
|
2033
|
+
var DEFAULT_COLUMNS = "*";
|
|
2034
|
+
var UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
|
2035
|
+
var SAFE_CAST_PATTERN = /^[a-z_][a-z0-9_]*(?:\[\])?$/i;
|
|
2036
|
+
var ATHENA_NORMALIZED_ERROR_KEY = "__athenaNormalizedError";
|
|
2037
|
+
function formatResult(response) {
|
|
2038
|
+
const result = {
|
|
2039
|
+
data: response.data ?? null,
|
|
2040
|
+
error: response.error ?? null,
|
|
2041
|
+
errorDetails: response.errorDetails ?? null,
|
|
2042
|
+
status: response.status,
|
|
2043
|
+
raw: response.raw
|
|
2044
|
+
};
|
|
2045
|
+
if (response.count !== void 0) {
|
|
2046
|
+
result.count = response.count;
|
|
2047
|
+
}
|
|
2048
|
+
return result;
|
|
2049
|
+
}
|
|
2050
|
+
function attachNormalizedError(result, normalizedError) {
|
|
2051
|
+
Object.defineProperty(result, ATHENA_NORMALIZED_ERROR_KEY, {
|
|
2052
|
+
value: normalizedError,
|
|
2053
|
+
enumerable: false,
|
|
2054
|
+
configurable: true,
|
|
2055
|
+
writable: false
|
|
2056
|
+
});
|
|
2057
|
+
}
|
|
2058
|
+
function createResultFormatter(experimental) {
|
|
2059
|
+
if (!experimental?.enableErrorNormalization) {
|
|
2060
|
+
return formatResult;
|
|
2061
|
+
}
|
|
2062
|
+
return (response, context) => {
|
|
2063
|
+
const result = formatResult(response);
|
|
2064
|
+
if (result.error == null) {
|
|
2065
|
+
return result;
|
|
2066
|
+
}
|
|
2067
|
+
const normalizedError = normalizeAthenaError(result, context);
|
|
2068
|
+
attachNormalizedError(result, normalizedError);
|
|
2069
|
+
return result;
|
|
2070
|
+
};
|
|
2071
|
+
}
|
|
2072
|
+
function toSingleResult(response) {
|
|
2073
|
+
const payload = response.data;
|
|
2074
|
+
const singleData = Array.isArray(payload) ? payload.length ? payload[0] : null : payload ?? null;
|
|
2075
|
+
return {
|
|
2076
|
+
...response,
|
|
2077
|
+
data: singleData
|
|
2078
|
+
};
|
|
2079
|
+
}
|
|
2080
|
+
function mergeOptions(...options) {
|
|
2081
|
+
return options.reduce((acc, next) => {
|
|
2082
|
+
if (!next) return acc;
|
|
2083
|
+
return { ...acc, ...next };
|
|
2084
|
+
}, void 0);
|
|
2085
|
+
}
|
|
2086
|
+
function asAthenaJsonObject(value) {
|
|
2087
|
+
return value;
|
|
2088
|
+
}
|
|
2089
|
+
function asAthenaJsonObjectArray(values) {
|
|
2090
|
+
return values;
|
|
2091
|
+
}
|
|
2092
|
+
function createMutationQuery(executor, defaultColumns = DEFAULT_COLUMNS) {
|
|
2093
|
+
let selectedColumns = defaultColumns === null ? void 0 : defaultColumns;
|
|
2094
|
+
let selectedOptions;
|
|
2095
|
+
let promise = null;
|
|
2096
|
+
const run = (columns, options) => {
|
|
2097
|
+
const payloadColumns = columns ?? selectedColumns;
|
|
2098
|
+
const payloadOptions = options ?? selectedOptions;
|
|
2099
|
+
if (!promise) {
|
|
2100
|
+
promise = executor(payloadColumns, payloadOptions);
|
|
2101
|
+
}
|
|
2102
|
+
return promise;
|
|
2103
|
+
};
|
|
2104
|
+
const mutationQuery = {
|
|
2105
|
+
select(columns = selectedColumns, options) {
|
|
2106
|
+
selectedColumns = columns;
|
|
2107
|
+
selectedOptions = options ?? selectedOptions;
|
|
2108
|
+
return run(columns, options);
|
|
2109
|
+
},
|
|
2110
|
+
returning(columns = selectedColumns, options) {
|
|
2111
|
+
return mutationQuery.select(columns, options);
|
|
2112
|
+
},
|
|
2113
|
+
single(columns = selectedColumns, options) {
|
|
2114
|
+
selectedColumns = columns;
|
|
2115
|
+
selectedOptions = options ?? selectedOptions;
|
|
2116
|
+
return run(columns, options).then(toSingleResult);
|
|
2117
|
+
},
|
|
2118
|
+
maybeSingle(columns = selectedColumns, options) {
|
|
2119
|
+
return mutationQuery.single(columns, options);
|
|
2120
|
+
},
|
|
2121
|
+
then(onfulfilled, onrejected) {
|
|
2122
|
+
return run(selectedColumns, selectedOptions).then(onfulfilled, onrejected);
|
|
2123
|
+
},
|
|
2124
|
+
catch(onrejected) {
|
|
2125
|
+
return run(selectedColumns, selectedOptions).catch(onrejected);
|
|
2126
|
+
},
|
|
2127
|
+
finally(onfinally) {
|
|
2128
|
+
return run(selectedColumns, selectedOptions).finally(onfinally);
|
|
2129
|
+
}
|
|
2130
|
+
};
|
|
2131
|
+
return mutationQuery;
|
|
2132
|
+
}
|
|
2133
|
+
function getResourceId(state) {
|
|
2134
|
+
const candidate = state.conditions.find(
|
|
2135
|
+
(condition) => condition.operator === "eq" && (condition.column === "resource_id" || condition.column === "id")
|
|
2136
|
+
);
|
|
2137
|
+
return candidate?.value?.toString();
|
|
2138
|
+
}
|
|
2139
|
+
function stringifyFilterValue(value) {
|
|
2140
|
+
if (Array.isArray(value)) {
|
|
2141
|
+
return value.join(",");
|
|
2142
|
+
}
|
|
2143
|
+
return String(value);
|
|
2144
|
+
}
|
|
2145
|
+
function isUuidString(value) {
|
|
2146
|
+
return UUID_PATTERN.test(value.trim());
|
|
2147
|
+
}
|
|
2148
|
+
function isUuidIdentifierColumn(column) {
|
|
2149
|
+
return column === "id" || /(?:^|_)uuid(?:_|$)/i.test(column) || /_id$/i.test(column);
|
|
2150
|
+
}
|
|
2151
|
+
function shouldUseUuidTextComparison(column, value) {
|
|
2152
|
+
return typeof value === "string" && isUuidString(value) && isUuidIdentifierColumn(column);
|
|
2153
|
+
}
|
|
2154
|
+
function normalizeCast(cast) {
|
|
2155
|
+
const normalized = cast.trim().toLowerCase();
|
|
2156
|
+
if (!SAFE_CAST_PATTERN.test(normalized)) {
|
|
2157
|
+
throw new Error(`Invalid cast type "${cast}"`);
|
|
2158
|
+
}
|
|
2159
|
+
return normalized;
|
|
2160
|
+
}
|
|
2161
|
+
function escapeSqlStringLiteral(value) {
|
|
2162
|
+
return value.replace(/'/g, "''");
|
|
2163
|
+
}
|
|
2164
|
+
function toSqlLiteral(value) {
|
|
2165
|
+
if (value === null) return "NULL";
|
|
2166
|
+
if (typeof value === "number") return Number.isFinite(value) ? String(value) : "NULL";
|
|
2167
|
+
if (typeof value === "boolean") return value ? "TRUE" : "FALSE";
|
|
2168
|
+
return `'${escapeSqlStringLiteral(value)}'`;
|
|
2169
|
+
}
|
|
2170
|
+
function withCast(expression, cast) {
|
|
2171
|
+
if (!cast) return expression;
|
|
2172
|
+
return `${expression}::${normalizeCast(cast)}`;
|
|
2173
|
+
}
|
|
2174
|
+
function buildSelectColumnsClause(columns) {
|
|
2175
|
+
if (Array.isArray(columns)) {
|
|
2176
|
+
return columns.map((column) => quoteQualifiedIdentifier(column)).join(", ");
|
|
2177
|
+
}
|
|
2178
|
+
return quoteSelectColumnsExpression(columns);
|
|
2179
|
+
}
|
|
2180
|
+
function resolveTableNameForCall(tableName, schema) {
|
|
2181
|
+
if (!schema) return tableName;
|
|
2182
|
+
const normalizedSchema = schema.trim();
|
|
2183
|
+
if (!normalizedSchema) {
|
|
2184
|
+
throw new Error("schema option must be a non-empty string");
|
|
2185
|
+
}
|
|
2186
|
+
if (tableName.includes(".")) {
|
|
2187
|
+
if (tableName.startsWith(`${normalizedSchema}.`)) {
|
|
2188
|
+
return tableName;
|
|
2189
|
+
}
|
|
2190
|
+
throw new Error(
|
|
2191
|
+
`schema option "${normalizedSchema}" conflicts with schema-qualified table "${tableName}"`
|
|
2192
|
+
);
|
|
2193
|
+
}
|
|
2194
|
+
return `${normalizedSchema}.${tableName}`;
|
|
2195
|
+
}
|
|
2196
|
+
function conditionToSqlClause(condition) {
|
|
2197
|
+
if (!condition.column) return null;
|
|
2198
|
+
const column = withCast(quoteQualifiedIdentifier(condition.column), condition.column_cast);
|
|
2199
|
+
const value = condition.value;
|
|
2200
|
+
const sqlOperator = {
|
|
2201
|
+
eq: "=",
|
|
2202
|
+
neq: "!=",
|
|
2203
|
+
gt: ">",
|
|
2204
|
+
gte: ">=",
|
|
2205
|
+
lt: "<",
|
|
2206
|
+
lte: "<=",
|
|
2207
|
+
like: "LIKE",
|
|
2208
|
+
ilike: "ILIKE"
|
|
2209
|
+
};
|
|
2210
|
+
switch (condition.operator) {
|
|
2211
|
+
case "eq":
|
|
2212
|
+
case "neq":
|
|
2213
|
+
case "gt":
|
|
2214
|
+
case "gte":
|
|
2215
|
+
case "lt":
|
|
2216
|
+
case "lte":
|
|
2217
|
+
case "like":
|
|
2218
|
+
case "ilike": {
|
|
2219
|
+
if (Array.isArray(value) || value === void 0) return null;
|
|
2220
|
+
const rhs = withCast(toSqlLiteral(value), condition.value_cast);
|
|
2221
|
+
return `${column} ${sqlOperator[condition.operator]} ${rhs}`;
|
|
2222
|
+
}
|
|
2223
|
+
case "is": {
|
|
2224
|
+
if (value === null) return `${column} IS NULL`;
|
|
2225
|
+
if (value === true) return `${column} IS TRUE`;
|
|
2226
|
+
if (value === false) return `${column} IS FALSE`;
|
|
2227
|
+
return null;
|
|
2228
|
+
}
|
|
2229
|
+
case "in": {
|
|
2230
|
+
if (!Array.isArray(value)) return null;
|
|
2231
|
+
if (value.length === 0) return "FALSE";
|
|
2232
|
+
const values = value.map((item) => withCast(toSqlLiteral(item), condition.value_cast));
|
|
2233
|
+
return `${column} IN (${values.join(", ")})`;
|
|
2234
|
+
}
|
|
2235
|
+
default:
|
|
2236
|
+
return null;
|
|
2237
|
+
}
|
|
2238
|
+
}
|
|
2239
|
+
function buildTypedSelectQuery(input) {
|
|
2240
|
+
const whereClauses = [];
|
|
2241
|
+
for (const condition of input.conditions) {
|
|
2242
|
+
const clause = conditionToSqlClause(condition);
|
|
2243
|
+
if (!clause) return null;
|
|
2244
|
+
whereClauses.push(clause);
|
|
2245
|
+
}
|
|
2246
|
+
let limit = input.limit;
|
|
2247
|
+
let offset = input.offset;
|
|
2248
|
+
if (limit === void 0 && input.pageSize !== void 0) {
|
|
2249
|
+
limit = input.pageSize;
|
|
2250
|
+
}
|
|
2251
|
+
if (offset === void 0 && input.pageSize !== void 0 && input.currentPage !== void 0 && input.currentPage > 0) {
|
|
2252
|
+
offset = (input.currentPage - 1) * input.pageSize;
|
|
2253
|
+
}
|
|
2254
|
+
const sqlParts = [
|
|
2255
|
+
`SELECT ${buildSelectColumnsClause(input.columns)} FROM ${quoteQualifiedIdentifier(input.tableName)}`
|
|
2256
|
+
];
|
|
2257
|
+
if (whereClauses.length > 0) {
|
|
2258
|
+
sqlParts.push(`WHERE ${whereClauses.join(" AND ")}`);
|
|
2259
|
+
}
|
|
2260
|
+
if (input.order?.field) {
|
|
2261
|
+
const direction = input.order.direction === "descending" ? "DESC" : "ASC";
|
|
2262
|
+
sqlParts.push(`ORDER BY ${quoteQualifiedIdentifier(input.order.field)} ${direction}`);
|
|
2263
|
+
}
|
|
2264
|
+
if (limit !== void 0) {
|
|
2265
|
+
sqlParts.push(`LIMIT ${Math.max(0, Math.trunc(limit))}`);
|
|
2266
|
+
}
|
|
2267
|
+
if (offset !== void 0) {
|
|
2268
|
+
sqlParts.push(`OFFSET ${Math.max(0, Math.trunc(offset))}`);
|
|
2269
|
+
}
|
|
2270
|
+
return `${sqlParts.join(" ")};`;
|
|
2271
|
+
}
|
|
2272
|
+
function createFilterMethods(state, addCondition, self) {
|
|
2273
|
+
return {
|
|
2274
|
+
eq(column, value) {
|
|
2275
|
+
const columnName = String(column);
|
|
2276
|
+
if (shouldUseUuidTextComparison(columnName, value)) {
|
|
2277
|
+
addCondition("eq", columnName, value, { columnCast: "text" });
|
|
2278
|
+
} else {
|
|
2279
|
+
addCondition("eq", columnName, value);
|
|
2280
|
+
}
|
|
2281
|
+
return self;
|
|
2282
|
+
},
|
|
2283
|
+
eqCast(column, value, cast) {
|
|
2284
|
+
addCondition("eq", String(column), value, { valueCast: cast });
|
|
2285
|
+
return self;
|
|
2286
|
+
},
|
|
2287
|
+
eqUuid(column, value) {
|
|
2288
|
+
addCondition("eq", String(column), value, { valueCast: "uuid" });
|
|
2289
|
+
return self;
|
|
2290
|
+
},
|
|
2291
|
+
match(filters) {
|
|
2292
|
+
Object.entries(filters).forEach(([column, value]) => {
|
|
2293
|
+
if (value === void 0) {
|
|
2294
|
+
return;
|
|
2295
|
+
}
|
|
2296
|
+
if (shouldUseUuidTextComparison(column, value)) {
|
|
2297
|
+
addCondition("eq", column, value, { columnCast: "text" });
|
|
2298
|
+
} else {
|
|
2299
|
+
addCondition("eq", column, value);
|
|
2300
|
+
}
|
|
2301
|
+
});
|
|
2302
|
+
return self;
|
|
2303
|
+
},
|
|
2304
|
+
range(from, to) {
|
|
2305
|
+
state.offset = from;
|
|
2306
|
+
state.limit = to - from + 1;
|
|
2307
|
+
return self;
|
|
2308
|
+
},
|
|
2309
|
+
limit(count) {
|
|
2310
|
+
state.limit = count;
|
|
2311
|
+
return self;
|
|
2312
|
+
},
|
|
2313
|
+
offset(count) {
|
|
2314
|
+
state.offset = count;
|
|
2315
|
+
return self;
|
|
2316
|
+
},
|
|
2317
|
+
currentPage(value) {
|
|
2318
|
+
state.currentPage = value;
|
|
2319
|
+
return self;
|
|
2320
|
+
},
|
|
2321
|
+
pageSize(value) {
|
|
2322
|
+
state.pageSize = value;
|
|
2323
|
+
return self;
|
|
2324
|
+
},
|
|
2325
|
+
totalPages(value) {
|
|
2326
|
+
state.totalPages = value;
|
|
2327
|
+
return self;
|
|
2328
|
+
},
|
|
2329
|
+
order(column, options) {
|
|
2330
|
+
state.order = {
|
|
2331
|
+
field: String(column),
|
|
2332
|
+
direction: options?.ascending === false ? "descending" : "ascending"
|
|
2333
|
+
};
|
|
2334
|
+
return self;
|
|
2335
|
+
},
|
|
2336
|
+
gt(column, value) {
|
|
2337
|
+
addCondition("gt", String(column), value);
|
|
2338
|
+
return self;
|
|
2339
|
+
},
|
|
2340
|
+
gte(column, value) {
|
|
2341
|
+
addCondition("gte", String(column), value);
|
|
2342
|
+
return self;
|
|
2343
|
+
},
|
|
2344
|
+
lt(column, value) {
|
|
2345
|
+
addCondition("lt", String(column), value);
|
|
2346
|
+
return self;
|
|
2347
|
+
},
|
|
2348
|
+
lte(column, value) {
|
|
2349
|
+
addCondition("lte", String(column), value);
|
|
2350
|
+
return self;
|
|
2351
|
+
},
|
|
2352
|
+
neq(column, value) {
|
|
2353
|
+
addCondition("neq", String(column), value);
|
|
2354
|
+
return self;
|
|
2355
|
+
},
|
|
2356
|
+
like(column, value) {
|
|
2357
|
+
addCondition("like", String(column), value);
|
|
2358
|
+
return self;
|
|
2359
|
+
},
|
|
2360
|
+
ilike(column, value) {
|
|
2361
|
+
addCondition("ilike", String(column), value);
|
|
2362
|
+
return self;
|
|
2363
|
+
},
|
|
2364
|
+
is(column, value) {
|
|
2365
|
+
addCondition("is", String(column), value);
|
|
2366
|
+
return self;
|
|
2367
|
+
},
|
|
2368
|
+
in(column, values) {
|
|
2369
|
+
addCondition("in", String(column), values);
|
|
2370
|
+
return self;
|
|
2371
|
+
},
|
|
2372
|
+
contains(column, values) {
|
|
2373
|
+
addCondition("contains", String(column), values);
|
|
2374
|
+
return self;
|
|
2375
|
+
},
|
|
2376
|
+
containedBy(column, values) {
|
|
2377
|
+
addCondition("containedBy", String(column), values);
|
|
2378
|
+
return self;
|
|
2379
|
+
},
|
|
2380
|
+
not(columnOrExpression, operator, value) {
|
|
2381
|
+
const expression = String(columnOrExpression);
|
|
2382
|
+
if (operator != null && value !== void 0) {
|
|
2383
|
+
addCondition("not", void 0, `${expression}.${operator}.${stringifyFilterValue(value)}`);
|
|
2384
|
+
} else {
|
|
2385
|
+
addCondition("not", void 0, expression);
|
|
2386
|
+
}
|
|
2387
|
+
return self;
|
|
2388
|
+
},
|
|
2389
|
+
or(expression) {
|
|
2390
|
+
addCondition("or", void 0, expression);
|
|
2391
|
+
return self;
|
|
2392
|
+
}
|
|
2393
|
+
};
|
|
2394
|
+
}
|
|
2395
|
+
function toRpcSelect(columns) {
|
|
2396
|
+
if (!columns) return void 0;
|
|
2397
|
+
return Array.isArray(columns) ? columns.join(",") : columns;
|
|
2398
|
+
}
|
|
2399
|
+
function createRpcFilterMethods(filters, self) {
|
|
2400
|
+
const addFilter = (operator, column, value) => {
|
|
2401
|
+
filters.push({ column, operator, value });
|
|
2402
|
+
};
|
|
2403
|
+
return {
|
|
2404
|
+
eq(column, value) {
|
|
2405
|
+
addFilter("eq", column, value);
|
|
2406
|
+
return self;
|
|
2407
|
+
},
|
|
2408
|
+
neq(column, value) {
|
|
2409
|
+
addFilter("neq", column, value);
|
|
2410
|
+
return self;
|
|
2411
|
+
},
|
|
2412
|
+
gt(column, value) {
|
|
2413
|
+
addFilter("gt", column, value);
|
|
2414
|
+
return self;
|
|
2415
|
+
},
|
|
2416
|
+
gte(column, value) {
|
|
2417
|
+
addFilter("gte", column, value);
|
|
2418
|
+
return self;
|
|
2419
|
+
},
|
|
2420
|
+
lt(column, value) {
|
|
2421
|
+
addFilter("lt", column, value);
|
|
2422
|
+
return self;
|
|
2423
|
+
},
|
|
2424
|
+
lte(column, value) {
|
|
2425
|
+
addFilter("lte", column, value);
|
|
2426
|
+
return self;
|
|
2427
|
+
},
|
|
2428
|
+
like(column, value) {
|
|
2429
|
+
addFilter("like", column, value);
|
|
2430
|
+
return self;
|
|
2431
|
+
},
|
|
2432
|
+
ilike(column, value) {
|
|
2433
|
+
addFilter("ilike", column, value);
|
|
2434
|
+
return self;
|
|
2435
|
+
},
|
|
2436
|
+
is(column, value) {
|
|
2437
|
+
addFilter("is", column, value);
|
|
2438
|
+
return self;
|
|
2439
|
+
},
|
|
2440
|
+
in(column, values) {
|
|
2441
|
+
addFilter("in", column, values);
|
|
2442
|
+
return self;
|
|
2443
|
+
}
|
|
2444
|
+
};
|
|
2445
|
+
}
|
|
2446
|
+
function createRpcBuilder(functionName, args, baseOptions, client, formatGatewayResult) {
|
|
2447
|
+
const state = {
|
|
2448
|
+
filters: []
|
|
2449
|
+
};
|
|
2450
|
+
let selectedColumns;
|
|
2451
|
+
let selectedOptions;
|
|
2452
|
+
let promise = null;
|
|
2453
|
+
const executeRpc = async (columns, options) => {
|
|
2454
|
+
const mergedOptions = mergeOptions(baseOptions, options);
|
|
2455
|
+
const payload = {
|
|
2456
|
+
function: functionName,
|
|
2457
|
+
args,
|
|
2458
|
+
schema: mergedOptions?.schema,
|
|
2459
|
+
select: toRpcSelect(columns),
|
|
2460
|
+
filters: state.filters.length ? [...state.filters] : void 0,
|
|
2461
|
+
count: mergedOptions?.count,
|
|
2462
|
+
head: mergedOptions?.head,
|
|
2463
|
+
limit: state.limit,
|
|
2464
|
+
offset: state.offset,
|
|
2465
|
+
order: state.order
|
|
2466
|
+
};
|
|
2467
|
+
const response = await client.rpcGateway(payload, mergedOptions);
|
|
2468
|
+
return formatGatewayResult(response, { operation: "rpc" });
|
|
2469
|
+
};
|
|
2470
|
+
const run = (columns, options) => {
|
|
2471
|
+
const payloadColumns = columns ?? selectedColumns;
|
|
2472
|
+
const payloadOptions = options ?? selectedOptions;
|
|
2473
|
+
if (!promise) {
|
|
2474
|
+
promise = executeRpc(payloadColumns, payloadOptions);
|
|
2475
|
+
}
|
|
2476
|
+
return promise;
|
|
2477
|
+
};
|
|
2478
|
+
const builder = {};
|
|
2479
|
+
const filterMethods = createRpcFilterMethods(state.filters, builder);
|
|
2480
|
+
Object.assign(builder, filterMethods, {
|
|
2481
|
+
select(columns = selectedColumns, options) {
|
|
2482
|
+
selectedColumns = columns;
|
|
2483
|
+
selectedOptions = options ?? selectedOptions;
|
|
2484
|
+
return run(columns, options);
|
|
2485
|
+
},
|
|
2486
|
+
async single(columns, options) {
|
|
2487
|
+
const result = await run(columns, options);
|
|
2488
|
+
return toSingleResult(result);
|
|
2489
|
+
},
|
|
2490
|
+
maybeSingle(columns, options) {
|
|
2491
|
+
return builder.single(columns, options);
|
|
2492
|
+
},
|
|
2493
|
+
order(column, options) {
|
|
2494
|
+
state.order = { column, ascending: options?.ascending ?? true };
|
|
2495
|
+
return builder;
|
|
2496
|
+
},
|
|
2497
|
+
limit(count) {
|
|
2498
|
+
state.limit = count;
|
|
2499
|
+
return builder;
|
|
2500
|
+
},
|
|
2501
|
+
offset(count) {
|
|
2502
|
+
state.offset = count;
|
|
2503
|
+
return builder;
|
|
2504
|
+
},
|
|
2505
|
+
range(from, to) {
|
|
2506
|
+
state.offset = from;
|
|
2507
|
+
state.limit = to - from + 1;
|
|
2508
|
+
return builder;
|
|
2509
|
+
},
|
|
2510
|
+
then(onfulfilled, onrejected) {
|
|
2511
|
+
return run(selectedColumns, selectedOptions).then(onfulfilled, onrejected);
|
|
2512
|
+
},
|
|
2513
|
+
catch(onrejected) {
|
|
2514
|
+
return run(selectedColumns, selectedOptions).catch(onrejected);
|
|
2515
|
+
},
|
|
2516
|
+
finally(onfinally) {
|
|
2517
|
+
return run(selectedColumns, selectedOptions).finally(onfinally);
|
|
2518
|
+
}
|
|
2519
|
+
});
|
|
2520
|
+
return builder;
|
|
2521
|
+
}
|
|
2522
|
+
function createTableBuilder(tableName, client, formatGatewayResult) {
|
|
2523
|
+
const state = {
|
|
2524
|
+
conditions: []
|
|
2525
|
+
};
|
|
2526
|
+
const addCondition = (operator, column, value, hints) => {
|
|
2527
|
+
const condition = { operator };
|
|
2528
|
+
if (column) {
|
|
2529
|
+
condition.column = column;
|
|
2530
|
+
if (operator === "eq") {
|
|
2531
|
+
condition.eq_column = column;
|
|
2532
|
+
}
|
|
2533
|
+
}
|
|
2534
|
+
if (value !== void 0) {
|
|
2535
|
+
condition.value = value;
|
|
2536
|
+
if (operator === "eq") {
|
|
2537
|
+
condition.eq_value = value;
|
|
2538
|
+
}
|
|
2539
|
+
}
|
|
2540
|
+
if (hints?.valueCast) {
|
|
2541
|
+
condition.value_cast = hints.valueCast;
|
|
2542
|
+
if (operator === "eq") {
|
|
2543
|
+
condition.eq_value_cast = hints.valueCast;
|
|
2544
|
+
}
|
|
2545
|
+
}
|
|
2546
|
+
if (hints?.columnCast) {
|
|
2547
|
+
condition.column_cast = hints.columnCast;
|
|
2548
|
+
if (operator === "eq") {
|
|
2549
|
+
condition.eq_column_cast = hints.columnCast;
|
|
2550
|
+
}
|
|
2551
|
+
}
|
|
2552
|
+
state.conditions.push(condition);
|
|
2553
|
+
};
|
|
2554
|
+
const builder = {};
|
|
2555
|
+
const filterMethods = createFilterMethods(
|
|
2556
|
+
state,
|
|
2557
|
+
addCondition,
|
|
2558
|
+
builder
|
|
2559
|
+
);
|
|
2560
|
+
const runSelect = async (columns = DEFAULT_COLUMNS, options) => {
|
|
2561
|
+
const resolvedTableName = resolveTableNameForCall(tableName, options?.schema);
|
|
2562
|
+
const conditions = state.conditions.length ? state.conditions.map((condition) => ({ ...condition })) : void 0;
|
|
2563
|
+
const hasTypedEqualityComparison = conditions?.some(
|
|
2564
|
+
(condition) => condition.operator === "eq" && (condition.value_cast !== void 0 || condition.column_cast !== void 0)
|
|
2565
|
+
) ?? false;
|
|
2566
|
+
if (hasTypedEqualityComparison && !options?.head && !options?.count && conditions) {
|
|
2567
|
+
const query = buildTypedSelectQuery({
|
|
2568
|
+
tableName: resolvedTableName,
|
|
2569
|
+
columns,
|
|
2570
|
+
conditions,
|
|
2571
|
+
limit: state.limit,
|
|
2572
|
+
offset: state.offset,
|
|
2573
|
+
currentPage: state.currentPage,
|
|
2574
|
+
pageSize: state.pageSize,
|
|
2575
|
+
order: state.order
|
|
2576
|
+
});
|
|
2577
|
+
if (query) {
|
|
2578
|
+
const queryResponse = await client.queryGateway({ query }, options);
|
|
2579
|
+
return formatGatewayResult(queryResponse, { table: resolvedTableName, operation: "select" });
|
|
2580
|
+
}
|
|
2581
|
+
}
|
|
2582
|
+
const payload = {
|
|
2583
|
+
table_name: resolvedTableName,
|
|
2584
|
+
columns,
|
|
2585
|
+
conditions,
|
|
2586
|
+
limit: state.limit,
|
|
2587
|
+
offset: state.offset,
|
|
2588
|
+
current_page: state.currentPage,
|
|
2589
|
+
page_size: state.pageSize,
|
|
2590
|
+
total_pages: state.totalPages,
|
|
2591
|
+
sort_by: state.order,
|
|
2592
|
+
strip_nulls: options?.stripNulls ?? true,
|
|
2593
|
+
count: options?.count,
|
|
2594
|
+
head: options?.head
|
|
2595
|
+
};
|
|
2596
|
+
const response = await client.fetchGateway(payload, options);
|
|
2597
|
+
return formatGatewayResult(response, { table: resolvedTableName, operation: "select" });
|
|
2598
|
+
};
|
|
2599
|
+
const createSelectChain = (columns, options) => {
|
|
2600
|
+
const chain = {};
|
|
2601
|
+
const filterMethods2 = createFilterMethods(state, addCondition, chain);
|
|
2602
|
+
Object.assign(chain, filterMethods2, {
|
|
2603
|
+
async single(cols, opts) {
|
|
2604
|
+
const r = await runSelect(cols ?? columns, opts ?? options);
|
|
2605
|
+
return toSingleResult(r);
|
|
2606
|
+
},
|
|
2607
|
+
maybeSingle(cols, opts) {
|
|
2608
|
+
return chain.single(cols, opts);
|
|
2609
|
+
},
|
|
2610
|
+
then(onfulfilled, onrejected) {
|
|
2611
|
+
return runSelect(columns, options).then(onfulfilled, onrejected);
|
|
2612
|
+
},
|
|
2613
|
+
catch(onrejected) {
|
|
2614
|
+
return runSelect(columns, options).catch(onrejected);
|
|
2615
|
+
},
|
|
2616
|
+
finally(onfinally) {
|
|
2617
|
+
return runSelect(columns, options).finally(onfinally);
|
|
2618
|
+
}
|
|
2619
|
+
});
|
|
2620
|
+
return chain;
|
|
2621
|
+
};
|
|
2622
|
+
Object.assign(builder, filterMethods, {
|
|
2623
|
+
reset() {
|
|
2624
|
+
state.conditions = [];
|
|
2625
|
+
state.limit = void 0;
|
|
2626
|
+
state.offset = void 0;
|
|
2627
|
+
state.order = void 0;
|
|
2628
|
+
state.currentPage = void 0;
|
|
2629
|
+
state.pageSize = void 0;
|
|
2630
|
+
state.totalPages = void 0;
|
|
2631
|
+
return builder;
|
|
2632
|
+
},
|
|
2633
|
+
select(columns = DEFAULT_COLUMNS, options) {
|
|
2634
|
+
return createSelectChain(columns, options);
|
|
2635
|
+
},
|
|
2636
|
+
insert(values, options) {
|
|
2637
|
+
if (Array.isArray(values)) {
|
|
2638
|
+
const executeInsertMany = async (columns, selectOptions) => {
|
|
2639
|
+
const mergedOptions = mergeOptions(options, selectOptions);
|
|
2640
|
+
const resolvedTableName = resolveTableNameForCall(tableName, mergedOptions?.schema);
|
|
2641
|
+
const payload = {
|
|
2642
|
+
table_name: resolvedTableName,
|
|
2643
|
+
insert_body: asAthenaJsonObjectArray(values)
|
|
2644
|
+
};
|
|
2645
|
+
if (columns) payload.columns = columns;
|
|
2646
|
+
if (mergedOptions?.count) payload.count = mergedOptions.count;
|
|
2647
|
+
if (mergedOptions?.head) payload.head = mergedOptions.head;
|
|
2648
|
+
if (mergedOptions?.defaultToNull !== void 0) {
|
|
2649
|
+
payload.default_to_null = mergedOptions.defaultToNull;
|
|
2650
|
+
}
|
|
2651
|
+
const response = await client.insertGateway(payload, mergedOptions);
|
|
2652
|
+
return formatGatewayResult(response, { table: resolvedTableName, operation: "insert" });
|
|
2653
|
+
};
|
|
2654
|
+
return createMutationQuery(executeInsertMany);
|
|
2655
|
+
}
|
|
2656
|
+
const executeInsertOne = async (columns, selectOptions) => {
|
|
2657
|
+
const mergedOptions = mergeOptions(options, selectOptions);
|
|
2658
|
+
const resolvedTableName = resolveTableNameForCall(tableName, mergedOptions?.schema);
|
|
2659
|
+
const payload = {
|
|
2660
|
+
table_name: resolvedTableName,
|
|
2661
|
+
insert_body: asAthenaJsonObject(values)
|
|
2662
|
+
};
|
|
2663
|
+
if (columns) payload.columns = columns;
|
|
2664
|
+
if (mergedOptions?.count) payload.count = mergedOptions.count;
|
|
2665
|
+
if (mergedOptions?.head) payload.head = mergedOptions.head;
|
|
2666
|
+
if (mergedOptions?.defaultToNull !== void 0) {
|
|
2667
|
+
payload.default_to_null = mergedOptions.defaultToNull;
|
|
2668
|
+
}
|
|
2669
|
+
const response = await client.insertGateway(payload, mergedOptions);
|
|
2670
|
+
return formatGatewayResult(response, { table: resolvedTableName, operation: "insert" });
|
|
2671
|
+
};
|
|
2672
|
+
return createMutationQuery(executeInsertOne);
|
|
2673
|
+
},
|
|
2674
|
+
upsert(values, options) {
|
|
2675
|
+
if (Array.isArray(values)) {
|
|
2676
|
+
const executeUpsertMany = async (columns, selectOptions) => {
|
|
2677
|
+
const mergedOptions = mergeOptions(options, selectOptions);
|
|
2678
|
+
const resolvedTableName = resolveTableNameForCall(tableName, mergedOptions?.schema);
|
|
2679
|
+
const payload = {
|
|
2680
|
+
table_name: resolvedTableName,
|
|
2681
|
+
insert_body: asAthenaJsonObjectArray(values),
|
|
2682
|
+
update_body: options?.updateBody ? asAthenaJsonObject(options.updateBody) : void 0
|
|
2683
|
+
};
|
|
2684
|
+
if (columns) payload.columns = columns;
|
|
2685
|
+
if (options?.onConflict) payload.on_conflict = options.onConflict;
|
|
2686
|
+
if (mergedOptions?.count) payload.count = mergedOptions.count;
|
|
2687
|
+
if (mergedOptions?.head) payload.head = mergedOptions.head;
|
|
2688
|
+
if (mergedOptions?.defaultToNull !== void 0) {
|
|
2689
|
+
payload.default_to_null = mergedOptions.defaultToNull;
|
|
2690
|
+
}
|
|
2691
|
+
const response = await client.insertGateway(payload, mergedOptions);
|
|
2692
|
+
return formatGatewayResult(response, { table: resolvedTableName, operation: "insert" });
|
|
2693
|
+
};
|
|
2694
|
+
return createMutationQuery(executeUpsertMany);
|
|
2695
|
+
}
|
|
2696
|
+
const executeUpsertOne = async (columns, selectOptions) => {
|
|
2697
|
+
const mergedOptions = mergeOptions(options, selectOptions);
|
|
2698
|
+
const resolvedTableName = resolveTableNameForCall(tableName, mergedOptions?.schema);
|
|
2699
|
+
const payload = {
|
|
2700
|
+
table_name: resolvedTableName,
|
|
2701
|
+
insert_body: asAthenaJsonObject(values),
|
|
2702
|
+
update_body: options?.updateBody ? asAthenaJsonObject(options.updateBody) : void 0
|
|
2703
|
+
};
|
|
2704
|
+
if (columns) payload.columns = columns;
|
|
2705
|
+
if (options?.onConflict) payload.on_conflict = options.onConflict;
|
|
2706
|
+
if (mergedOptions?.count) payload.count = mergedOptions.count;
|
|
2707
|
+
if (mergedOptions?.head) payload.head = mergedOptions.head;
|
|
2708
|
+
if (mergedOptions?.defaultToNull !== void 0) {
|
|
2709
|
+
payload.default_to_null = mergedOptions.defaultToNull;
|
|
2710
|
+
}
|
|
2711
|
+
const response = await client.insertGateway(payload, mergedOptions);
|
|
2712
|
+
return formatGatewayResult(response, { table: resolvedTableName, operation: "insert" });
|
|
2713
|
+
};
|
|
2714
|
+
return createMutationQuery(executeUpsertOne);
|
|
2715
|
+
},
|
|
2716
|
+
update(values, options) {
|
|
2717
|
+
const executeUpdate = async (columns, selectOptions) => {
|
|
2718
|
+
const filters = state.conditions.length ? [...state.conditions] : void 0;
|
|
2719
|
+
const mergedOptions = mergeOptions(options, selectOptions);
|
|
2720
|
+
const resolvedTableName = resolveTableNameForCall(tableName, mergedOptions?.schema);
|
|
2721
|
+
const payload = {
|
|
2722
|
+
table_name: resolvedTableName,
|
|
2723
|
+
set: asAthenaJsonObject(values),
|
|
2724
|
+
conditions: filters,
|
|
2725
|
+
strip_nulls: mergedOptions?.stripNulls ?? true
|
|
2726
|
+
};
|
|
2727
|
+
if (state.order) payload.sort_by = state.order;
|
|
2728
|
+
if (state.currentPage !== void 0) payload.current_page = state.currentPage;
|
|
2729
|
+
if (state.pageSize !== void 0) payload.page_size = state.pageSize;
|
|
2730
|
+
if (state.totalPages !== void 0) payload.total_pages = state.totalPages;
|
|
2731
|
+
if (columns) payload.columns = columns;
|
|
2732
|
+
const response = await client.updateGateway(payload, mergedOptions);
|
|
2733
|
+
return formatGatewayResult(response, { table: resolvedTableName, operation: "update" });
|
|
2734
|
+
};
|
|
2735
|
+
const mutation = createMutationQuery(executeUpdate, null);
|
|
2736
|
+
const updateChain = {};
|
|
2737
|
+
const filterMethods2 = createFilterMethods(state, addCondition, updateChain);
|
|
2738
|
+
Object.assign(updateChain, filterMethods2, mutation);
|
|
2739
|
+
return updateChain;
|
|
2740
|
+
},
|
|
2741
|
+
delete(options) {
|
|
2742
|
+
const filters = state.conditions.length ? [...state.conditions] : void 0;
|
|
2743
|
+
const resourceId = options?.resourceId ?? getResourceId(state);
|
|
2744
|
+
if (!resourceId && !filters?.length) {
|
|
2745
|
+
throw new Error('delete requires a resource_id either via eq("resource_id", ...) or options.resourceId');
|
|
2746
|
+
}
|
|
2747
|
+
const executeDelete = async (columns, selectOptions) => {
|
|
2748
|
+
const mergedOptions = mergeOptions(options, selectOptions);
|
|
2749
|
+
const resolvedTableName = resolveTableNameForCall(tableName, mergedOptions?.schema);
|
|
2750
|
+
const payload = {
|
|
2751
|
+
table_name: resolvedTableName,
|
|
2752
|
+
resource_id: resourceId,
|
|
2753
|
+
conditions: filters
|
|
2754
|
+
};
|
|
2755
|
+
if (state.order) payload.sort_by = state.order;
|
|
2756
|
+
if (state.currentPage !== void 0) payload.current_page = state.currentPage;
|
|
2757
|
+
if (state.pageSize !== void 0) payload.page_size = state.pageSize;
|
|
2758
|
+
if (state.totalPages !== void 0) payload.total_pages = state.totalPages;
|
|
2759
|
+
if (columns) payload.columns = columns;
|
|
2760
|
+
const response = await client.deleteGateway(payload, mergedOptions);
|
|
2761
|
+
return formatGatewayResult(response, { table: resolvedTableName, operation: "delete" });
|
|
2762
|
+
};
|
|
2763
|
+
return createMutationQuery(executeDelete, null);
|
|
2764
|
+
},
|
|
2765
|
+
async single(columns, options) {
|
|
2766
|
+
const response = await builder.select(columns, options);
|
|
2767
|
+
return toSingleResult(response);
|
|
2768
|
+
},
|
|
2769
|
+
async maybeSingle(columns, options) {
|
|
2770
|
+
return builder.single(columns, options);
|
|
2771
|
+
}
|
|
2772
|
+
});
|
|
2773
|
+
return builder;
|
|
2774
|
+
}
|
|
2775
|
+
function createQueryBuilder(client, formatGatewayResult) {
|
|
2776
|
+
return async function query(query, options) {
|
|
2777
|
+
const normalizedQuery = query.trim();
|
|
2778
|
+
if (!normalizedQuery) {
|
|
2779
|
+
throw new Error("query requires a non-empty string");
|
|
2780
|
+
}
|
|
2781
|
+
const response = await client.queryGateway({ query: normalizedQuery }, options);
|
|
2782
|
+
return formatGatewayResult(response, { operation: "query" });
|
|
2783
|
+
};
|
|
2784
|
+
}
|
|
2785
|
+
function createClientFromConfig(config) {
|
|
2786
|
+
const gateway = createAthenaGatewayClient({
|
|
2787
|
+
baseUrl: config.baseUrl,
|
|
2788
|
+
apiKey: config.apiKey,
|
|
2789
|
+
client: config.client,
|
|
2790
|
+
backend: config.backend,
|
|
2791
|
+
headers: config.headers
|
|
2792
|
+
});
|
|
2793
|
+
const formatGatewayResult = createResultFormatter(config.experimental);
|
|
2794
|
+
const auth = createAuthClient(config.auth);
|
|
2795
|
+
const from = (table) => createTableBuilder(table, gateway, formatGatewayResult);
|
|
2796
|
+
const rpc = (fn, args, options) => {
|
|
2797
|
+
const normalizedFn = fn.trim();
|
|
2798
|
+
if (!normalizedFn) {
|
|
2799
|
+
throw new Error("rpc requires a function name");
|
|
2800
|
+
}
|
|
2801
|
+
return createRpcBuilder(
|
|
2802
|
+
normalizedFn,
|
|
2803
|
+
args,
|
|
2804
|
+
options,
|
|
2805
|
+
gateway,
|
|
2806
|
+
formatGatewayResult
|
|
2807
|
+
);
|
|
2808
|
+
};
|
|
2809
|
+
const query = createQueryBuilder(gateway, formatGatewayResult);
|
|
2810
|
+
const db = createDbModule({ from, rpc, query });
|
|
2811
|
+
return {
|
|
2812
|
+
from,
|
|
2813
|
+
db,
|
|
2814
|
+
rpc,
|
|
2815
|
+
query,
|
|
2816
|
+
auth: auth.auth
|
|
2817
|
+
};
|
|
2818
|
+
}
|
|
2819
|
+
var DEFAULT_BACKEND = { type: "athena" };
|
|
2820
|
+
function toBackendConfig(b) {
|
|
2821
|
+
if (!b) return DEFAULT_BACKEND;
|
|
2822
|
+
return typeof b === "string" ? { type: b } : b;
|
|
2823
|
+
}
|
|
2824
|
+
var AthenaClientBuilderImpl = class {
|
|
2825
|
+
baseUrl;
|
|
2826
|
+
apiKey;
|
|
2827
|
+
backendConfig = DEFAULT_BACKEND;
|
|
2828
|
+
clientName;
|
|
2829
|
+
defaultHeaders;
|
|
2830
|
+
isHealthTrackingEnabled = false;
|
|
2831
|
+
url(url) {
|
|
2832
|
+
this.baseUrl = url;
|
|
2833
|
+
return this;
|
|
2834
|
+
}
|
|
2835
|
+
key(apiKey) {
|
|
2836
|
+
this.apiKey = apiKey;
|
|
2837
|
+
return this;
|
|
2838
|
+
}
|
|
2839
|
+
backend(backend) {
|
|
2840
|
+
this.backendConfig = toBackendConfig(backend);
|
|
2841
|
+
return this;
|
|
2842
|
+
}
|
|
2843
|
+
client(clientName) {
|
|
2844
|
+
this.clientName = clientName;
|
|
2845
|
+
return this;
|
|
2846
|
+
}
|
|
2847
|
+
headers(headers) {
|
|
2848
|
+
this.defaultHeaders = headers;
|
|
2849
|
+
return this;
|
|
2850
|
+
}
|
|
2851
|
+
healthTracking(enabled) {
|
|
2852
|
+
this.isHealthTrackingEnabled = enabled;
|
|
2853
|
+
return this;
|
|
2854
|
+
}
|
|
2855
|
+
build() {
|
|
2856
|
+
if (!this.baseUrl || !this.apiKey) {
|
|
2857
|
+
throw new Error("AthenaClient requires url and key; call .url() and .key() before .build()");
|
|
2858
|
+
}
|
|
2859
|
+
return createClientFromConfig({
|
|
2860
|
+
baseUrl: this.baseUrl,
|
|
2861
|
+
apiKey: this.apiKey,
|
|
2862
|
+
client: this.clientName,
|
|
2863
|
+
backend: this.backendConfig,
|
|
2864
|
+
headers: this.defaultHeaders,
|
|
2865
|
+
healthTracking: this.isHealthTrackingEnabled
|
|
2866
|
+
});
|
|
2867
|
+
}
|
|
2868
|
+
};
|
|
2869
|
+
var AthenaClient = class _AthenaClient {
|
|
2870
|
+
/** Create a fluent builder for a strongly-typed Athena SDK client. */
|
|
2871
|
+
static builder() {
|
|
2872
|
+
return new AthenaClientBuilderImpl();
|
|
2873
|
+
}
|
|
2874
|
+
/** Build a client from process environment variables. */
|
|
2875
|
+
static fromEnvironment() {
|
|
2876
|
+
const url = process.env.ATHENA_URL ?? process.env.ATHENA_GATEWAY_URL;
|
|
2877
|
+
const key = process.env.ATHENA_API_KEY ?? process.env.ATHENA_GATEWAY_API_KEY;
|
|
2878
|
+
if (!url || !key) {
|
|
2879
|
+
throw new Error(
|
|
2880
|
+
"ATHENA_URL and ATHENA_API_KEY (or ATHENA_GATEWAY_URL and ATHENA_GATEWAY_API_KEY) are required"
|
|
2881
|
+
);
|
|
2882
|
+
}
|
|
2883
|
+
return _AthenaClient.builder().url(url).key(key).build();
|
|
2884
|
+
}
|
|
2885
|
+
};
|
|
2886
|
+
function createClient(url, apiKey, options) {
|
|
2887
|
+
return createClientFromConfig({
|
|
2888
|
+
baseUrl: url,
|
|
2889
|
+
apiKey,
|
|
2890
|
+
client: options?.client,
|
|
2891
|
+
backend: toBackendConfig(options?.backend),
|
|
2892
|
+
headers: options?.headers,
|
|
2893
|
+
auth: options?.auth,
|
|
2894
|
+
experimental: options?.experimental
|
|
2895
|
+
});
|
|
2896
|
+
}
|
|
2897
|
+
|
|
2898
|
+
// src/gateway/types.ts
|
|
2899
|
+
var Backend = {
|
|
2900
|
+
Athena: { type: "athena" },
|
|
2901
|
+
Postgrest: { type: "postgrest" },
|
|
2902
|
+
PostgreSQL: { type: "postgresql" },
|
|
2903
|
+
ScyllaDB: { type: "scylladb" }
|
|
2904
|
+
};
|
|
2905
|
+
|
|
2906
|
+
// src/schema/definitions.ts
|
|
2907
|
+
function defineModel(input) {
|
|
2908
|
+
return input;
|
|
2909
|
+
}
|
|
2910
|
+
function defineSchema(models) {
|
|
2911
|
+
return { models };
|
|
2912
|
+
}
|
|
2913
|
+
function defineDatabase(schemas) {
|
|
2914
|
+
return { schemas };
|
|
2915
|
+
}
|
|
2916
|
+
function defineRegistry(databases) {
|
|
2917
|
+
return databases;
|
|
2918
|
+
}
|
|
2919
|
+
|
|
2920
|
+
// src/schema/typed-client.ts
|
|
2921
|
+
var TenantHeaderMapper = class {
|
|
2922
|
+
constructor(tenantKeyMap) {
|
|
2923
|
+
this.tenantKeyMap = tenantKeyMap;
|
|
2924
|
+
}
|
|
2925
|
+
apply(baseHeaders, tenantContext) {
|
|
2926
|
+
const headers = {
|
|
2927
|
+
...baseHeaders ?? {}
|
|
2928
|
+
};
|
|
2929
|
+
for (const [tenantKey, headerName] of Object.entries(this.tenantKeyMap)) {
|
|
2930
|
+
const tenantValue = tenantContext[tenantKey];
|
|
2931
|
+
if (tenantValue === void 0 || tenantValue === null) {
|
|
2932
|
+
continue;
|
|
2933
|
+
}
|
|
2934
|
+
headers[headerName] = String(tenantValue);
|
|
2935
|
+
}
|
|
2936
|
+
return Object.keys(headers).length > 0 ? headers : void 0;
|
|
2937
|
+
}
|
|
2938
|
+
};
|
|
2939
|
+
var RegistryNavigator = class {
|
|
2940
|
+
constructor(registry) {
|
|
2941
|
+
this.registry = registry;
|
|
2942
|
+
}
|
|
2943
|
+
resolveModel(database, schema, model) {
|
|
2944
|
+
const databaseDef = this.registry[database];
|
|
2945
|
+
if (!databaseDef) {
|
|
2946
|
+
throw new Error(`Unknown database "${database}"`);
|
|
2947
|
+
}
|
|
2948
|
+
const schemaDef = databaseDef.schemas[schema];
|
|
2949
|
+
if (!schemaDef) {
|
|
2950
|
+
throw new Error(`Unknown schema "${schema}" in database "${database}"`);
|
|
2951
|
+
}
|
|
2952
|
+
const modelDef = schemaDef.models[model];
|
|
2953
|
+
if (!modelDef) {
|
|
2954
|
+
throw new Error(`Unknown model "${model}" in schema "${schema}"`);
|
|
2955
|
+
}
|
|
2956
|
+
return modelDef;
|
|
2957
|
+
}
|
|
2958
|
+
resolveTableName(schema, model, modelDef) {
|
|
2959
|
+
if (modelDef.meta.tableName) {
|
|
2960
|
+
return modelDef.meta.tableName;
|
|
2961
|
+
}
|
|
2962
|
+
const schemaName = modelDef.meta.schema ?? schema;
|
|
2963
|
+
const modelName = modelDef.meta.model ?? model;
|
|
2964
|
+
return `${schemaName}.${modelName}`;
|
|
2965
|
+
}
|
|
2966
|
+
};
|
|
2967
|
+
var TypedAthenaClientImpl = class _TypedAthenaClientImpl {
|
|
2968
|
+
registry;
|
|
2969
|
+
tenantKeyMap;
|
|
2970
|
+
tenantContext;
|
|
2971
|
+
db;
|
|
2972
|
+
baseClient;
|
|
2973
|
+
registryNavigator;
|
|
2974
|
+
tenantHeaderMapper;
|
|
2975
|
+
clientOptions;
|
|
2976
|
+
url;
|
|
2977
|
+
apiKey;
|
|
2978
|
+
constructor(input) {
|
|
2979
|
+
this.registry = input.registry;
|
|
2980
|
+
this.url = input.url;
|
|
2981
|
+
this.apiKey = input.apiKey;
|
|
2982
|
+
const tenantKeyMap = input.options?.tenantKeyMap ?? {};
|
|
2983
|
+
const tenantContext = input.options?.tenantContext ?? {};
|
|
2984
|
+
this.tenantKeyMap = tenantKeyMap;
|
|
2985
|
+
this.tenantContext = tenantContext;
|
|
2986
|
+
this.tenantHeaderMapper = new TenantHeaderMapper(tenantKeyMap);
|
|
2987
|
+
this.registryNavigator = new RegistryNavigator(input.registry);
|
|
2988
|
+
this.clientOptions = {
|
|
2989
|
+
backend: input.options?.backend,
|
|
2990
|
+
client: input.options?.client,
|
|
2991
|
+
headers: input.options?.headers
|
|
2992
|
+
};
|
|
2993
|
+
this.baseClient = createClient(this.url, this.apiKey, {
|
|
2994
|
+
backend: this.clientOptions.backend,
|
|
2995
|
+
client: this.clientOptions.client,
|
|
2996
|
+
headers: this.tenantHeaderMapper.apply(this.clientOptions.headers, tenantContext)
|
|
2997
|
+
});
|
|
2998
|
+
this.db = this.baseClient.db;
|
|
2999
|
+
}
|
|
3000
|
+
from(table) {
|
|
3001
|
+
return this.baseClient.from(table);
|
|
3002
|
+
}
|
|
3003
|
+
rpc(fn, args, options) {
|
|
3004
|
+
return this.baseClient.rpc(fn, args, options);
|
|
3005
|
+
}
|
|
3006
|
+
query(query, options) {
|
|
3007
|
+
return this.baseClient.query(query, options);
|
|
3008
|
+
}
|
|
3009
|
+
withTenantContext(context) {
|
|
3010
|
+
return new _TypedAthenaClientImpl({
|
|
3011
|
+
registry: this.registry,
|
|
3012
|
+
url: this.url,
|
|
3013
|
+
apiKey: this.apiKey,
|
|
3014
|
+
options: {
|
|
3015
|
+
...this.clientOptions,
|
|
3016
|
+
tenantKeyMap: this.tenantKeyMap,
|
|
3017
|
+
tenantContext: {
|
|
3018
|
+
...this.tenantContext,
|
|
3019
|
+
...context ?? {}
|
|
3020
|
+
}
|
|
3021
|
+
}
|
|
3022
|
+
});
|
|
3023
|
+
}
|
|
3024
|
+
fromModel(database, schema, model) {
|
|
3025
|
+
const modelDef = this.registryNavigator.resolveModel(database, schema, model);
|
|
3026
|
+
const tableName = this.registryNavigator.resolveTableName(schema, model, modelDef);
|
|
3027
|
+
return this.baseClient.from(tableName);
|
|
3028
|
+
}
|
|
3029
|
+
};
|
|
3030
|
+
function createTypedClient(registry, url, apiKey, options) {
|
|
3031
|
+
return new TypedAthenaClientImpl({
|
|
3032
|
+
registry,
|
|
3033
|
+
url,
|
|
3034
|
+
apiKey,
|
|
3035
|
+
options
|
|
3036
|
+
});
|
|
3037
|
+
}
|
|
3038
|
+
|
|
3039
|
+
// src/schema/model-form.ts
|
|
3040
|
+
function resolveNullishValue(mode) {
|
|
3041
|
+
if (mode === "undefined") return void 0;
|
|
3042
|
+
if (mode === "null") return null;
|
|
3043
|
+
return "";
|
|
3044
|
+
}
|
|
3045
|
+
function isRecord4(value) {
|
|
3046
|
+
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
3047
|
+
}
|
|
3048
|
+
function isNullableColumn(model, key) {
|
|
3049
|
+
const nullable = model.meta.nullable;
|
|
3050
|
+
return nullable?.[key] === true;
|
|
3051
|
+
}
|
|
3052
|
+
function toModelFormDefaults(model, values, options) {
|
|
3053
|
+
const source = values;
|
|
3054
|
+
if (!isRecord4(source)) {
|
|
3055
|
+
return {};
|
|
3056
|
+
}
|
|
3057
|
+
const mode = options?.nullishMode ?? "empty-string";
|
|
3058
|
+
const nullishValue = resolveNullishValue(mode);
|
|
3059
|
+
const result = {};
|
|
3060
|
+
for (const [key, value] of Object.entries(source)) {
|
|
3061
|
+
if (value === null && isNullableColumn(model, key)) {
|
|
3062
|
+
result[key] = nullishValue;
|
|
3063
|
+
continue;
|
|
3064
|
+
}
|
|
3065
|
+
result[key] = value;
|
|
3066
|
+
}
|
|
3067
|
+
return result;
|
|
3068
|
+
}
|
|
3069
|
+
function toModelPayload(model, formValues, options) {
|
|
3070
|
+
const emptyStringAsNull = options?.emptyStringAsNull ?? true;
|
|
3071
|
+
const stripUndefined = options?.stripUndefined ?? true;
|
|
3072
|
+
const result = {};
|
|
3073
|
+
for (const [key, rawValue] of Object.entries(formValues)) {
|
|
3074
|
+
if (rawValue === void 0 && stripUndefined) {
|
|
3075
|
+
continue;
|
|
3076
|
+
}
|
|
3077
|
+
if (emptyStringAsNull && rawValue === "" && isNullableColumn(model, key)) {
|
|
3078
|
+
result[key] = null;
|
|
3079
|
+
continue;
|
|
3080
|
+
}
|
|
3081
|
+
result[key] = rawValue;
|
|
3082
|
+
}
|
|
3083
|
+
return result;
|
|
3084
|
+
}
|
|
3085
|
+
function createModelFormAdapter(model) {
|
|
3086
|
+
return {
|
|
3087
|
+
model,
|
|
3088
|
+
toDefaults(values, options) {
|
|
3089
|
+
return toModelFormDefaults(model, values, options);
|
|
3090
|
+
},
|
|
3091
|
+
toInsert(values, options) {
|
|
3092
|
+
return toModelPayload(model, values, options);
|
|
3093
|
+
},
|
|
3094
|
+
toUpdate(values, options) {
|
|
3095
|
+
return toModelPayload(model, values, options);
|
|
3096
|
+
}
|
|
3097
|
+
};
|
|
3098
|
+
}
|
|
3099
|
+
|
|
3100
|
+
// src/generator/schema-selection.ts
|
|
3101
|
+
var DEFAULT_POSTGRES_SCHEMAS = ["public"];
|
|
3102
|
+
function collectSchemaNames(input) {
|
|
3103
|
+
if (!input) {
|
|
3104
|
+
return [];
|
|
3105
|
+
}
|
|
3106
|
+
const values = typeof input === "string" ? [input] : input;
|
|
3107
|
+
return values.flatMap((value) => String(value).split(","));
|
|
3108
|
+
}
|
|
3109
|
+
function normalizeSchemaSelection(input) {
|
|
3110
|
+
const schemas = [];
|
|
3111
|
+
const seen = /* @__PURE__ */ new Set();
|
|
3112
|
+
for (const value of collectSchemaNames(input)) {
|
|
3113
|
+
const schema = value.trim();
|
|
3114
|
+
if (!schema || seen.has(schema)) {
|
|
3115
|
+
continue;
|
|
3116
|
+
}
|
|
3117
|
+
seen.add(schema);
|
|
3118
|
+
schemas.push(schema);
|
|
3119
|
+
}
|
|
3120
|
+
return schemas.length > 0 ? schemas : [...DEFAULT_POSTGRES_SCHEMAS];
|
|
3121
|
+
}
|
|
3122
|
+
function resolveProviderSchemas(providerConfig) {
|
|
3123
|
+
if (providerConfig.kind === "postgres") {
|
|
3124
|
+
return normalizeSchemaSelection(providerConfig.schemas);
|
|
3125
|
+
}
|
|
3126
|
+
return [...DEFAULT_POSTGRES_SCHEMAS];
|
|
3127
|
+
}
|
|
3128
|
+
|
|
3129
|
+
// src/generator/postgres-type-mapping.ts
|
|
3130
|
+
var NUMBER_TYPES = /* @__PURE__ */ new Set([
|
|
3131
|
+
"int2",
|
|
3132
|
+
"int4",
|
|
3133
|
+
"float4",
|
|
3134
|
+
"float8",
|
|
3135
|
+
"smallint",
|
|
3136
|
+
"integer",
|
|
3137
|
+
"real",
|
|
3138
|
+
"double precision"
|
|
3139
|
+
]);
|
|
3140
|
+
var STRING_NUMERIC_TYPES = /* @__PURE__ */ new Set([
|
|
3141
|
+
"int8",
|
|
3142
|
+
"bigint",
|
|
3143
|
+
"serial8",
|
|
3144
|
+
"bigserial",
|
|
3145
|
+
"numeric",
|
|
3146
|
+
"decimal",
|
|
3147
|
+
"money"
|
|
3148
|
+
]);
|
|
3149
|
+
var TEXT_TYPES = /* @__PURE__ */ new Set([
|
|
3150
|
+
"char",
|
|
3151
|
+
"bpchar",
|
|
3152
|
+
"varchar",
|
|
3153
|
+
"character varying",
|
|
3154
|
+
"text",
|
|
3155
|
+
"citext",
|
|
3156
|
+
"name",
|
|
3157
|
+
"uuid",
|
|
3158
|
+
"date",
|
|
3159
|
+
"time",
|
|
3160
|
+
"timetz",
|
|
3161
|
+
"timestamp",
|
|
3162
|
+
"timestamptz",
|
|
3163
|
+
"interval",
|
|
3164
|
+
"inet",
|
|
3165
|
+
"cidr",
|
|
3166
|
+
"macaddr",
|
|
3167
|
+
"macaddr8",
|
|
3168
|
+
"point",
|
|
3169
|
+
"line",
|
|
3170
|
+
"lseg",
|
|
3171
|
+
"box",
|
|
3172
|
+
"path",
|
|
3173
|
+
"polygon",
|
|
3174
|
+
"circle",
|
|
3175
|
+
"bit",
|
|
3176
|
+
"varbit",
|
|
3177
|
+
"xml",
|
|
3178
|
+
"tsvector",
|
|
3179
|
+
"tsquery",
|
|
3180
|
+
"jsonpath"
|
|
3181
|
+
]);
|
|
3182
|
+
function normalizeTypeLabel(column) {
|
|
3183
|
+
const preferred = (column.udtName || column.dataType).toLowerCase().trim();
|
|
3184
|
+
if (column.arrayDimensions > 0 && preferred.startsWith("_")) {
|
|
3185
|
+
return preferred.slice(1);
|
|
3186
|
+
}
|
|
3187
|
+
return preferred;
|
|
3188
|
+
}
|
|
3189
|
+
function wrapArrayType(baseType, depth) {
|
|
3190
|
+
let wrapped = baseType;
|
|
3191
|
+
for (let index = 0; index < depth; index += 1) {
|
|
3192
|
+
wrapped = `Array<${wrapped}>`;
|
|
3193
|
+
}
|
|
3194
|
+
return wrapped;
|
|
3195
|
+
}
|
|
3196
|
+
function resolveScalarType(column) {
|
|
3197
|
+
const label = normalizeTypeLabel(column);
|
|
3198
|
+
if (NUMBER_TYPES.has(label)) {
|
|
3199
|
+
return "number";
|
|
3200
|
+
}
|
|
3201
|
+
if (STRING_NUMERIC_TYPES.has(label)) {
|
|
3202
|
+
return "string";
|
|
3203
|
+
}
|
|
3204
|
+
if (label === "bool" || label === "boolean") {
|
|
3205
|
+
return "boolean";
|
|
3206
|
+
}
|
|
3207
|
+
if (label === "bytea") {
|
|
3208
|
+
return "Buffer";
|
|
3209
|
+
}
|
|
3210
|
+
if (label === "json" || label === "jsonb") {
|
|
3211
|
+
return "Record<string, unknown>";
|
|
3212
|
+
}
|
|
3213
|
+
if (TEXT_TYPES.has(label)) {
|
|
3214
|
+
return "string";
|
|
3215
|
+
}
|
|
3216
|
+
if (label.endsWith("range") || label.endsWith("multirange")) {
|
|
3217
|
+
return "string";
|
|
3218
|
+
}
|
|
3219
|
+
return "unknown";
|
|
3220
|
+
}
|
|
3221
|
+
function resolveKindAwareType(column) {
|
|
3222
|
+
if (column.typeKind === "enum") {
|
|
3223
|
+
const values = column.enumValues ?? [];
|
|
3224
|
+
if (values.length === 0) {
|
|
3225
|
+
return "string";
|
|
3226
|
+
}
|
|
3227
|
+
return values.map((value) => `'${value.replace(/\\/g, "\\\\").replace(/'/g, "\\'")}'`).join(" | ");
|
|
3228
|
+
}
|
|
3229
|
+
if (column.typeKind === "composite") {
|
|
3230
|
+
return "Record<string, unknown>";
|
|
3231
|
+
}
|
|
3232
|
+
if (column.typeKind === "domain" || column.typeKind === "range" || column.typeKind === "multirange") {
|
|
3233
|
+
return "string";
|
|
3234
|
+
}
|
|
3235
|
+
return resolveScalarType(column);
|
|
3236
|
+
}
|
|
3237
|
+
function resolvePostgresColumnType(column) {
|
|
3238
|
+
const baseType = resolveKindAwareType(column);
|
|
3239
|
+
if (!column.arrayDimensions || column.arrayDimensions <= 0) {
|
|
3240
|
+
return baseType;
|
|
3241
|
+
}
|
|
3242
|
+
return wrapArrayType(baseType, column.arrayDimensions);
|
|
3243
|
+
}
|
|
3244
|
+
|
|
3245
|
+
// src/browser.ts
|
|
3246
|
+
function throwBrowserUnsupported(apiName) {
|
|
3247
|
+
throw new Error(
|
|
3248
|
+
`@xylex-group/athena: ${apiName} is not available in browser bundles. Use this API in a Node.js runtime.`
|
|
3249
|
+
);
|
|
3250
|
+
}
|
|
3251
|
+
function createPostgresIntrospectionProvider(_options) {
|
|
3252
|
+
return throwBrowserUnsupported("createPostgresIntrospectionProvider");
|
|
3253
|
+
}
|
|
3254
|
+
function defineGeneratorConfig(config) {
|
|
3255
|
+
return config;
|
|
3256
|
+
}
|
|
3257
|
+
function findGeneratorConfigPath(_cwd) {
|
|
3258
|
+
return throwBrowserUnsupported("findGeneratorConfigPath");
|
|
3259
|
+
}
|
|
3260
|
+
async function loadGeneratorConfig(_options = {}) {
|
|
3261
|
+
return throwBrowserUnsupported("loadGeneratorConfig");
|
|
3262
|
+
}
|
|
3263
|
+
function normalizeGeneratorConfig(_input) {
|
|
3264
|
+
return throwBrowserUnsupported("normalizeGeneratorConfig");
|
|
3265
|
+
}
|
|
3266
|
+
function generateArtifactsFromSnapshot(_snapshot, _config) {
|
|
3267
|
+
return throwBrowserUnsupported("generateArtifactsFromSnapshot");
|
|
3268
|
+
}
|
|
3269
|
+
function resolveGeneratorProvider(_providerConfig, _experimentalFlags) {
|
|
3270
|
+
return throwBrowserUnsupported("resolveGeneratorProvider");
|
|
3271
|
+
}
|
|
3272
|
+
async function runSchemaGenerator(_options = {}) {
|
|
3273
|
+
return throwBrowserUnsupported("runSchemaGenerator");
|
|
3274
|
+
}
|
|
3275
|
+
|
|
3276
|
+
exports.AthenaClient = AthenaClient;
|
|
3277
|
+
exports.AthenaError = AthenaError;
|
|
3278
|
+
exports.AthenaErrorCategory = AthenaErrorCategory;
|
|
3279
|
+
exports.AthenaErrorCode = AthenaErrorCode;
|
|
3280
|
+
exports.AthenaErrorKind = AthenaErrorKind;
|
|
3281
|
+
exports.AthenaGatewayError = AthenaGatewayError;
|
|
3282
|
+
exports.Backend = Backend;
|
|
3283
|
+
exports.DEFAULT_POSTGRES_SCHEMAS = DEFAULT_POSTGRES_SCHEMAS;
|
|
3284
|
+
exports.assertInt = assertInt;
|
|
3285
|
+
exports.coerceInt = coerceInt;
|
|
3286
|
+
exports.createAuthClient = createAuthClient;
|
|
3287
|
+
exports.createClient = createClient;
|
|
3288
|
+
exports.createModelFormAdapter = createModelFormAdapter;
|
|
3289
|
+
exports.createPostgresIntrospectionProvider = createPostgresIntrospectionProvider;
|
|
3290
|
+
exports.createTypedClient = createTypedClient;
|
|
3291
|
+
exports.defineDatabase = defineDatabase;
|
|
3292
|
+
exports.defineGeneratorConfig = defineGeneratorConfig;
|
|
3293
|
+
exports.defineModel = defineModel;
|
|
3294
|
+
exports.defineRegistry = defineRegistry;
|
|
3295
|
+
exports.defineSchema = defineSchema;
|
|
3296
|
+
exports.findGeneratorConfigPath = findGeneratorConfigPath;
|
|
3297
|
+
exports.generateArtifactsFromSnapshot = generateArtifactsFromSnapshot;
|
|
3298
|
+
exports.identifier = identifier;
|
|
3299
|
+
exports.isAthenaGatewayError = isAthenaGatewayError;
|
|
3300
|
+
exports.isOk = isOk;
|
|
3301
|
+
exports.loadGeneratorConfig = loadGeneratorConfig;
|
|
3302
|
+
exports.normalizeAthenaError = normalizeAthenaError;
|
|
3303
|
+
exports.normalizeGeneratorConfig = normalizeGeneratorConfig;
|
|
3304
|
+
exports.normalizeSchemaSelection = normalizeSchemaSelection;
|
|
3305
|
+
exports.parseBooleanFlag = parseBooleanFlag;
|
|
3306
|
+
exports.requireAffected = requireAffected;
|
|
3307
|
+
exports.requireSuccess = requireSuccess;
|
|
3308
|
+
exports.resolveGeneratorProvider = resolveGeneratorProvider;
|
|
3309
|
+
exports.resolvePostgresColumnType = resolvePostgresColumnType;
|
|
3310
|
+
exports.resolveProviderSchemas = resolveProviderSchemas;
|
|
3311
|
+
exports.runSchemaGenerator = runSchemaGenerator;
|
|
3312
|
+
exports.toModelFormDefaults = toModelFormDefaults;
|
|
3313
|
+
exports.toModelPayload = toModelPayload;
|
|
3314
|
+
exports.unwrap = unwrap;
|
|
3315
|
+
exports.unwrapOne = unwrapOne;
|
|
3316
|
+
exports.unwrapRows = unwrapRows;
|
|
3317
|
+
exports.withRetry = withRetry;
|
|
3318
|
+
//# sourceMappingURL=browser.cjs.map
|
|
3319
|
+
//# sourceMappingURL=browser.cjs.map
|