@xylex-group/athena 3.0.3 → 3.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (86) hide show
  1. package/README.md +1 -1
  2. package/dist/admin.cjs +55 -1
  3. package/dist/admin.cjs.map +1 -1
  4. package/dist/admin.d.cts +32 -8
  5. package/dist/admin.d.ts +32 -8
  6. package/dist/admin.js +54 -2
  7. package/dist/admin.js.map +1 -1
  8. package/dist/athena-auth-url-C1FbVmN6.d.cts +200 -0
  9. package/dist/athena-auth-url-C1FbVmN6.d.ts +200 -0
  10. package/dist/{athena-request-headers-C7Jy-c_D.d.ts → athena-request-headers-DzimbvOA.d.ts} +48 -200
  11. package/dist/{athena-request-headers-DujFFyMU.d.cts → athena-request-headers-Lr_m8xCV.d.cts} +48 -200
  12. package/dist/billing.cjs +1 -1
  13. package/dist/billing.cjs.map +1 -1
  14. package/dist/billing.js +1 -1
  15. package/dist/billing.js.map +1 -1
  16. package/dist/browser.cjs +912 -5
  17. package/dist/browser.cjs.map +1 -1
  18. package/dist/browser.d.cts +8 -7
  19. package/dist/browser.d.ts +8 -7
  20. package/dist/browser.js +881 -6
  21. package/dist/browser.js.map +1 -1
  22. package/dist/cli/index.cjs +7909 -7061
  23. package/dist/cli/index.cjs.map +1 -1
  24. package/dist/cli/index.d.cts +17 -10
  25. package/dist/cli/index.d.ts +17 -10
  26. package/dist/cli/index.js +7911 -7063
  27. package/dist/cli/index.js.map +1 -1
  28. package/dist/env.cjs +130 -0
  29. package/dist/env.cjs.map +1 -0
  30. package/dist/env.d.cts +70 -0
  31. package/dist/env.d.ts +70 -0
  32. package/dist/env.js +122 -0
  33. package/dist/env.js.map +1 -0
  34. package/dist/index.cjs +1570 -98
  35. package/dist/index.cjs.map +1 -1
  36. package/dist/index.d.cts +31 -8
  37. package/dist/index.d.ts +31 -8
  38. package/dist/index.js +1532 -100
  39. package/dist/index.js.map +1 -1
  40. package/dist/model-form-3Gr8rkdT.d.cts +281 -0
  41. package/dist/model-form-CotpEL7z.d.ts +281 -0
  42. package/dist/{module-CPG3ULxQ.d.cts → module-CQmOaDzP.d.cts} +4 -4
  43. package/dist/{module-BruTcxe0.d.ts → module-CWkUTcUc.d.ts} +4 -4
  44. package/dist/next/client.cjs +123 -7
  45. package/dist/next/client.cjs.map +1 -1
  46. package/dist/next/client.d.cts +4 -3
  47. package/dist/next/client.d.ts +4 -3
  48. package/dist/next/client.js +123 -7
  49. package/dist/next/client.js.map +1 -1
  50. package/dist/next/server.cjs +1130 -364
  51. package/dist/next/server.cjs.map +1 -1
  52. package/dist/next/server.d.cts +121 -8
  53. package/dist/next/server.d.ts +121 -8
  54. package/dist/next/server.js +1120 -365
  55. package/dist/next/server.js.map +1 -1
  56. package/dist/pipeline-BnRKO_Pd.d.cts +93 -0
  57. package/dist/pipeline-sWCmlFqu.d.ts +93 -0
  58. package/dist/{proxy-request-headers-m4D2Tduy.d.ts → proxy-request-headers-CttlcuRb.d.ts} +1 -1
  59. package/dist/{proxy-request-headers-DGxdoyA0.d.cts → proxy-request-headers-pIBSn1Fw.d.cts} +1 -1
  60. package/dist/react.cjs +672 -16
  61. package/dist/react.cjs.map +1 -1
  62. package/dist/react.d.cts +123 -8
  63. package/dist/react.d.ts +123 -8
  64. package/dist/react.js +671 -17
  65. package/dist/react.js.map +1 -1
  66. package/dist/schema-handlers-BtT_IQFi.d.cts +138 -0
  67. package/dist/schema-handlers-VjFDhIMw.d.ts +138 -0
  68. package/dist/social-providers.d.cts +1 -1
  69. package/dist/social-providers.d.ts +1 -1
  70. package/dist/{types-D6tZ9aoq.d.ts → types-BDX8zS7w.d.ts} +40 -1
  71. package/dist/{types-AOY-GLu8.d.cts → types-BVKpQmfY.d.cts} +11 -0
  72. package/dist/{types-AOY-GLu8.d.ts → types-BVKpQmfY.d.ts} +11 -0
  73. package/dist/{types-DFr2cL1N.d.cts → types-D-Am7YSd.d.cts} +40 -1
  74. package/dist/utils.cjs +30 -0
  75. package/dist/utils.cjs.map +1 -1
  76. package/dist/utils.d.cts +3 -2
  77. package/dist/utils.d.ts +3 -2
  78. package/dist/utils.js +30 -1
  79. package/dist/utils.js.map +1 -1
  80. package/dist/{v3-client-CWfZHcKL.d.cts → v3-client-G1SLeHRa.d.cts} +23 -1
  81. package/dist/{v3-client-DZp2NEhK.d.ts → v3-client-ao8BWQ8v.d.ts} +23 -1
  82. package/package.json +16 -2
  83. package/dist/model-form-Dh0sisdL.d.ts +0 -97
  84. package/dist/model-form-oOAJUVd4.d.cts +0 -97
  85. package/dist/pipeline-CIzV9f7b.d.cts +0 -8
  86. package/dist/pipeline-DNlc8Ayn.d.ts +0 -8
package/dist/react.cjs CHANGED
@@ -413,7 +413,7 @@ function buildAthenaRequestHeaders(input) {
413
413
 
414
414
  // package.json
415
415
  var package_default = {
416
- version: "3.0.3"
416
+ version: "3.3.0"
417
417
  };
418
418
 
419
419
  // src/sdk-version.ts
@@ -1064,7 +1064,8 @@ function stableSerialize(value, seen) {
1064
1064
  if (value === void 0) return "undefined";
1065
1065
  const valueType = typeof value;
1066
1066
  if (valueType === "string") return `"${value}"`;
1067
- if (valueType === "number") return Number.isFinite(value) ? String(value) : "null";
1067
+ if (valueType === "number")
1068
+ return Number.isFinite(value) ? String(value) : "null";
1068
1069
  if (valueType === "boolean") return value ? "true" : "false";
1069
1070
  if (valueType === "bigint") return `${String(value)}n`;
1070
1071
  if (valueType === "symbol") return `symbol:${String(value)}`;
@@ -1145,7 +1146,8 @@ async function runWithRetry(execute, options) {
1145
1146
  }
1146
1147
  function errorMessageFromUnknown(error) {
1147
1148
  if (typeof error === "string" && error.trim()) return error.trim();
1148
- if (error instanceof Error && error.message.trim()) return error.message.trim();
1149
+ if (error instanceof Error && error.message.trim())
1150
+ return error.message.trim();
1149
1151
  if (isRecord2(error)) {
1150
1152
  const messageCandidate = error.message ?? error.error;
1151
1153
  if (typeof messageCandidate === "string" && messageCandidate.trim()) {
@@ -1364,7 +1366,11 @@ var AthenaQueryClient = class {
1364
1366
  const key = this.getMutationKeyToken(mutationKey);
1365
1367
  const entry = this.ensureMutationEntry(key);
1366
1368
  entry.activeRequestId = ++this.requestCounter;
1367
- this.setMutationState(entry, createInitialMutationState(), "mutation_reset");
1369
+ this.setMutationState(
1370
+ entry,
1371
+ createInitialMutationState(),
1372
+ "mutation_reset"
1373
+ );
1368
1374
  }
1369
1375
  async executeQuery(input) {
1370
1376
  const entry = this.ensureQueryEntry(input.queryKeyToken);
@@ -1426,7 +1432,10 @@ var AthenaQueryClient = class {
1426
1432
  );
1427
1433
  }
1428
1434
  const rawResult = await input.queryFn();
1429
- const normalized = normalizeAthenaResult(rawResult, input.select);
1435
+ const normalized = normalizeAthenaResult(
1436
+ rawResult,
1437
+ input.select
1438
+ );
1430
1439
  if (normalized.error) {
1431
1440
  throw {
1432
1441
  __athenaNormalizedError: normalized.error,
@@ -1514,7 +1523,10 @@ var AthenaQueryClient = class {
1514
1523
  this.inflightQueries.delete(input.queryKeyToken);
1515
1524
  }
1516
1525
  });
1517
- this.inflightQueries.set(input.queryKeyToken, executionPromise);
1526
+ this.inflightQueries.set(
1527
+ input.queryKeyToken,
1528
+ executionPromise
1529
+ );
1518
1530
  return executionPromise;
1519
1531
  }
1520
1532
  async executeMutation(input) {
@@ -1560,7 +1572,10 @@ var AthenaQueryClient = class {
1560
1572
  );
1561
1573
  }
1562
1574
  const rawResult = await input.mutationFn(input.variables);
1563
- const normalized = normalizeAthenaResult(rawResult, input.select);
1575
+ const normalized = normalizeAthenaResult(
1576
+ rawResult,
1577
+ input.select
1578
+ );
1564
1579
  if (normalized.error) {
1565
1580
  throw {
1566
1581
  __athenaNormalizedError: normalized.error,
@@ -1997,6 +2012,430 @@ function useMutation(options) {
1997
2012
  lastRequest: snapshot.lastRequest
1998
2013
  };
1999
2014
  }
2015
+
2016
+ // src/query-debug-ast.ts
2017
+ var ATHENA_DEBUG_AST_KEY = "__athenaDebugAst";
2018
+ function getAthenaDebugAst(value) {
2019
+ if (!value || typeof value !== "object" && typeof value !== "function") {
2020
+ return null;
2021
+ }
2022
+ return value[ATHENA_DEBUG_AST_KEY] ?? null;
2023
+ }
2024
+
2025
+ // src/query/read-query.ts
2026
+ function normalizeAthenaReadQueryOrderBy(orderBy) {
2027
+ if (!orderBy) {
2028
+ return [];
2029
+ }
2030
+ const list = Array.isArray(orderBy) ? orderBy : [orderBy];
2031
+ return list.filter(
2032
+ (entry) => entry && typeof entry.column === "string" && entry.column.trim().length > 0
2033
+ );
2034
+ }
2035
+ function isRecord3(value) {
2036
+ return typeof value === "object" && value !== null && !Array.isArray(value);
2037
+ }
2038
+ function flattenAthenaRowValue(row, column) {
2039
+ if (!column.relation) {
2040
+ return row[column.column];
2041
+ }
2042
+ const relationValue = row[column.relation.name];
2043
+ if (Array.isArray(relationValue)) {
2044
+ return relationValue.map((entry) => isRecord3(entry) ? entry[column.column] : void 0).filter((entry) => entry !== void 0);
2045
+ }
2046
+ if (isRecord3(relationValue)) {
2047
+ return relationValue[column.column];
2048
+ }
2049
+ return void 0;
2050
+ }
2051
+ function resolveFlatRowKey(row, index, preferredKey) {
2052
+ const preferredValue = preferredKey && preferredKey in row ? row[preferredKey] : void 0;
2053
+ if (preferredValue !== void 0 && preferredValue !== null && `${preferredValue}`.trim().length > 0) {
2054
+ return String(preferredValue);
2055
+ }
2056
+ for (const [key, value] of Object.entries(row)) {
2057
+ if (key === "__rowKey") {
2058
+ continue;
2059
+ }
2060
+ if (value === void 0 || value === null) {
2061
+ continue;
2062
+ }
2063
+ if (Array.isArray(value)) {
2064
+ if (value.length > 0) {
2065
+ return `${key}-${value.join("-")}`;
2066
+ }
2067
+ continue;
2068
+ }
2069
+ const nextValue = String(value).trim();
2070
+ if (nextValue.length > 0) {
2071
+ return nextValue;
2072
+ }
2073
+ }
2074
+ return `row-${index + 1}`;
2075
+ }
2076
+ function flattenAthenaReadQueryRows(rows, columns, preferredKey) {
2077
+ return rows.map((entry, index) => {
2078
+ const sourceRow = isRecord3(entry) ? entry : {};
2079
+ const flatRow = columns.reduce(
2080
+ (currentRow, column) => {
2081
+ currentRow[column.key] = flattenAthenaRowValue(sourceRow, column);
2082
+ return currentRow;
2083
+ },
2084
+ { __rowKey: "" }
2085
+ );
2086
+ flatRow.__rowKey = resolveFlatRowKey(flatRow, index, preferredKey);
2087
+ return flatRow;
2088
+ });
2089
+ }
2090
+ function buildAthenaReadQuerySelectString(columns) {
2091
+ const baseColumns = columns.filter((column) => !column.relation).map((column) => column.column);
2092
+ const relationGroups = /* @__PURE__ */ new Map();
2093
+ for (const column of columns) {
2094
+ if (!column.relation) {
2095
+ continue;
2096
+ }
2097
+ const groupKey = [
2098
+ column.relation.name,
2099
+ column.relation.schema ?? "",
2100
+ column.relation.table
2101
+ ].join(":");
2102
+ const existingGroup = relationGroups.get(groupKey);
2103
+ if (existingGroup) {
2104
+ if (!existingGroup.columns.includes(column.column)) {
2105
+ existingGroup.columns.push(column.column);
2106
+ }
2107
+ continue;
2108
+ }
2109
+ relationGroups.set(groupKey, {
2110
+ columns: [column.column],
2111
+ relation: column.relation
2112
+ });
2113
+ }
2114
+ const relationColumns = [...relationGroups.values()].map(
2115
+ ({ columns: relationColumns2, relation }) => {
2116
+ const relationTarget = relation.schema ? `${relation.schema}.${relation.table}` : relation.table;
2117
+ return `${relation.name}:${relationTarget}(${relationColumns2.join(",")})`;
2118
+ }
2119
+ );
2120
+ return [...baseColumns, ...relationColumns].join(",");
2121
+ }
2122
+ function buildAthenaReadQueryFindManySelect(columns) {
2123
+ const select = {};
2124
+ for (const column of columns) {
2125
+ if (!column.relation) {
2126
+ select[column.column] = true;
2127
+ continue;
2128
+ }
2129
+ const existingRelation = select[column.relation.name];
2130
+ if (existingRelation && existingRelation !== true && isRecord3(existingRelation.select)) {
2131
+ existingRelation.select[column.column] = true;
2132
+ continue;
2133
+ }
2134
+ select[column.relation.name] = {
2135
+ ...column.relation.schema ? { schema: column.relation.schema } : {},
2136
+ select: {
2137
+ [column.column]: true
2138
+ }
2139
+ };
2140
+ }
2141
+ return select;
2142
+ }
2143
+ function buildAthenaReadQueryFindManyWhere(filters) {
2144
+ if (!filters?.length) {
2145
+ return;
2146
+ }
2147
+ return filters.reduce(
2148
+ (where, filter) => {
2149
+ const operator = filter.operator ?? "eq";
2150
+ where[filter.column] = operator === "eq" ? filter.value : { [operator]: filter.value };
2151
+ return where;
2152
+ },
2153
+ {}
2154
+ );
2155
+ }
2156
+ function buildAthenaReadQueryFindManyOrderBy(orderBy) {
2157
+ const normalized = normalizeAthenaReadQueryOrderBy(orderBy);
2158
+ if (normalized.length === 0) {
2159
+ return;
2160
+ }
2161
+ if (normalized.length === 1) {
2162
+ const primary = normalized[0];
2163
+ if (!primary) {
2164
+ return;
2165
+ }
2166
+ return {
2167
+ ascending: primary.direction !== "desc",
2168
+ column: primary.column
2169
+ };
2170
+ }
2171
+ return Object.fromEntries(
2172
+ normalized.map((entry) => [
2173
+ entry.column,
2174
+ entry.direction === "desc" ? "desc" : "asc"
2175
+ ])
2176
+ );
2177
+ }
2178
+ function applyAthenaReadQueryFilters(queryBuilder, filters) {
2179
+ if (!filters?.length) {
2180
+ return queryBuilder;
2181
+ }
2182
+ return filters.reduce((currentBuilder, filter) => {
2183
+ const operator = filter.operator ?? "eq";
2184
+ const builderMethod = currentBuilder[operator];
2185
+ if (typeof builderMethod !== "function") {
2186
+ return currentBuilder;
2187
+ }
2188
+ return builderMethod.call(currentBuilder, filter.column, filter.value);
2189
+ }, queryBuilder);
2190
+ }
2191
+ function applyAthenaReadQuerySelectOrder(queryBuilder, orderBy) {
2192
+ const normalized = normalizeAthenaReadQueryOrderBy(orderBy);
2193
+ if (normalized.length === 0) {
2194
+ return queryBuilder;
2195
+ }
2196
+ return normalized.reduce(
2197
+ (builder, entry) => builder.order(entry.column, {
2198
+ ascending: entry.direction !== "desc"
2199
+ }),
2200
+ queryBuilder
2201
+ );
2202
+ }
2203
+ function clampAthenaReadQueryTotalItems(totalItems, limit) {
2204
+ if (!limit || limit < 1) {
2205
+ return totalItems;
2206
+ }
2207
+ return Math.min(totalItems, limit);
2208
+ }
2209
+ function resolveCountValue(...candidates) {
2210
+ for (const candidate of candidates) {
2211
+ if (typeof candidate === "number" && Number.isFinite(candidate)) {
2212
+ return Math.max(0, Math.trunc(candidate));
2213
+ }
2214
+ }
2215
+ return 0;
2216
+ }
2217
+ function resolveTotalItemsFromPage({
2218
+ countCandidates,
2219
+ limit,
2220
+ page,
2221
+ pageSize,
2222
+ rowCount
2223
+ }) {
2224
+ const exactCount = resolveCountValue(...countCandidates);
2225
+ if (exactCount > 0) {
2226
+ return clampAthenaReadQueryTotalItems(exactCount, limit);
2227
+ }
2228
+ if (rowCount > 0) {
2229
+ const base = (page - 1) * pageSize + rowCount;
2230
+ const synthetic = rowCount >= pageSize ? base + 1 : base;
2231
+ return clampAthenaReadQueryTotalItems(synthetic, limit);
2232
+ }
2233
+ return clampAthenaReadQueryTotalItems(exactCount, limit);
2234
+ }
2235
+ function resolveAthenaReadQueryPageFetch({
2236
+ page,
2237
+ pageSize,
2238
+ limit
2239
+ }) {
2240
+ const safePage = Math.max(1, Math.trunc(page) || 1);
2241
+ const safePageSize = Math.max(1, Math.trunc(pageSize) || 1);
2242
+ if (!limit || limit < 1) {
2243
+ return { page: safePage, pageSize: safePageSize, shouldFetch: true };
2244
+ }
2245
+ const totalCap = Math.trunc(limit);
2246
+ const offset = (safePage - 1) * safePageSize;
2247
+ if (offset >= totalCap) {
2248
+ return { page: safePage, pageSize: safePageSize, shouldFetch: false };
2249
+ }
2250
+ return {
2251
+ page: safePage,
2252
+ pageSize: Math.min(safePageSize, totalCap - offset),
2253
+ shouldFetch: true
2254
+ };
2255
+ }
2256
+ async function executeAthenaReadQuery({
2257
+ client,
2258
+ page,
2259
+ pageSize,
2260
+ query
2261
+ }) {
2262
+ const db = client.db;
2263
+ const baseBuilder = db.from(query.table, {
2264
+ schema: query.schema
2265
+ });
2266
+ const countBuilder = applyAthenaReadQueryFilters(
2267
+ db.from(query.table, { schema: query.schema }),
2268
+ query.filters
2269
+ );
2270
+ const countResult = await countBuilder.select(query.countColumn, {
2271
+ count: "exact",
2272
+ head: true
2273
+ });
2274
+ const pageFetch = resolveAthenaReadQueryPageFetch({
2275
+ limit: query.limit,
2276
+ page,
2277
+ pageSize
2278
+ });
2279
+ if (!pageFetch.shouldFetch) {
2280
+ return {
2281
+ rows: [],
2282
+ totalItems: resolveTotalItemsFromPage({
2283
+ countCandidates: [countResult.count],
2284
+ limit: query.limit,
2285
+ page: pageFetch.page,
2286
+ pageSize,
2287
+ rowCount: 0
2288
+ })
2289
+ };
2290
+ }
2291
+ if ((query.mode ?? "findMany") === "select") {
2292
+ const selectBuilder = applyAthenaReadQuerySelectOrder(
2293
+ applyAthenaReadQueryFilters(baseBuilder, query.filters),
2294
+ query.orderBy
2295
+ );
2296
+ const result2 = await selectBuilder.currentPage(pageFetch.page).pageSize(pageFetch.pageSize).select(buildAthenaReadQuerySelectString(query.columns), {
2297
+ count: "exact"
2298
+ });
2299
+ const rows2 = flattenAthenaReadQueryRows(
2300
+ Array.isArray(result2.data) ? result2.data : [],
2301
+ query.columns,
2302
+ query.rowKey
2303
+ );
2304
+ return {
2305
+ debugAst: getAthenaDebugAst(result2) ?? void 0,
2306
+ rows: rows2,
2307
+ totalItems: resolveTotalItemsFromPage({
2308
+ countCandidates: [countResult.count, result2.count],
2309
+ limit: query.limit,
2310
+ page: pageFetch.page,
2311
+ pageSize,
2312
+ rowCount: rows2.length
2313
+ })
2314
+ };
2315
+ }
2316
+ const findManyOrderBy = buildAthenaReadQueryFindManyOrderBy(query.orderBy);
2317
+ const findManyOptions = {
2318
+ ...findManyOrderBy ? { orderBy: findManyOrderBy } : {},
2319
+ select: buildAthenaReadQueryFindManySelect(query.columns),
2320
+ ...query.filters?.length ? { where: buildAthenaReadQueryFindManyWhere(query.filters) } : {}
2321
+ };
2322
+ const result = await baseBuilder.currentPage(pageFetch.page).pageSize(pageFetch.pageSize).findMany(findManyOptions);
2323
+ const rows = flattenAthenaReadQueryRows(
2324
+ Array.isArray(result.data) ? result.data : [],
2325
+ query.columns,
2326
+ query.rowKey
2327
+ );
2328
+ return {
2329
+ debugAst: getAthenaDebugAst(result) ?? void 0,
2330
+ rows,
2331
+ totalItems: resolveTotalItemsFromPage({
2332
+ countCandidates: [countResult.count, result.count],
2333
+ limit: query.limit,
2334
+ page: pageFetch.page,
2335
+ pageSize,
2336
+ rowCount: rows.length
2337
+ })
2338
+ };
2339
+ }
2340
+
2341
+ // src/react/use-athena-read-query.ts
2342
+ var DEFAULT_PAGE = 1;
2343
+ var DEFAULT_PAGE_SIZE = 10;
2344
+ function isReadQueryRunnable(query) {
2345
+ return query.table.trim().length > 0 && query.columns.length > 0 && query.countColumn.trim().length > 0;
2346
+ }
2347
+ function useAthenaReadQuery({
2348
+ client,
2349
+ query,
2350
+ page = DEFAULT_PAGE,
2351
+ pageSize = DEFAULT_PAGE_SIZE,
2352
+ enabled = true,
2353
+ queryKey,
2354
+ queryKeyPrefix,
2355
+ refetchOnMount,
2356
+ refetchOnWindowFocus,
2357
+ refetchOnReconnect,
2358
+ retry
2359
+ }) {
2360
+ const resolvedPage = page > 0 ? Math.trunc(page) : DEFAULT_PAGE;
2361
+ const resolvedPageSize = pageSize > 0 ? Math.trunc(pageSize) : DEFAULT_PAGE_SIZE;
2362
+ const queryEnabled = enabled && !!client && isReadQueryRunnable(query);
2363
+ const defaultQueryKey = React.useMemo(
2364
+ () => [
2365
+ "athena",
2366
+ "read-query",
2367
+ query.mode ?? "findMany",
2368
+ query.table,
2369
+ query.schema,
2370
+ query.columns,
2371
+ query.filters,
2372
+ query.limit,
2373
+ query.orderBy,
2374
+ query.rowKey,
2375
+ query.countColumn,
2376
+ resolvedPage,
2377
+ resolvedPageSize
2378
+ ],
2379
+ [
2380
+ query.columns,
2381
+ query.countColumn,
2382
+ query.filters,
2383
+ query.limit,
2384
+ query.mode,
2385
+ query.orderBy,
2386
+ query.rowKey,
2387
+ query.schema,
2388
+ query.table,
2389
+ resolvedPage,
2390
+ resolvedPageSize
2391
+ ]
2392
+ );
2393
+ const resolvedQueryKey = React.useMemo(() => {
2394
+ if (queryKey !== void 0) {
2395
+ return queryKey;
2396
+ }
2397
+ if (queryKeyPrefix !== void 0) {
2398
+ const prefix = Array.isArray(queryKeyPrefix) ? queryKeyPrefix : [queryKeyPrefix];
2399
+ return [...prefix, ...defaultQueryKey];
2400
+ }
2401
+ return defaultQueryKey;
2402
+ }, [defaultQueryKey, queryKey, queryKeyPrefix]);
2403
+ const result = useQuery({
2404
+ enabled: queryEnabled,
2405
+ queryKey: resolvedQueryKey,
2406
+ queryFn: async () => {
2407
+ if (!client) {
2408
+ throw new Error("Athena client is required to run the read query.");
2409
+ }
2410
+ return executeAthenaReadQuery({
2411
+ client,
2412
+ page: resolvedPage,
2413
+ pageSize: resolvedPageSize,
2414
+ query
2415
+ });
2416
+ },
2417
+ refetchOnMount,
2418
+ refetchOnWindowFocus,
2419
+ refetchOnReconnect,
2420
+ retry
2421
+ });
2422
+ return {
2423
+ data: result.data,
2424
+ rows: result.data?.rows ?? [],
2425
+ totalItems: result.data?.totalItems ?? 0,
2426
+ debugAst: result.data?.debugAst,
2427
+ page: resolvedPage,
2428
+ pageSize: resolvedPageSize,
2429
+ error: result.error,
2430
+ isLoading: result.isLoading,
2431
+ isFetching: result.isFetching,
2432
+ isSuccess: result.isSuccess,
2433
+ isError: result.isError,
2434
+ status: result.status,
2435
+ refetch: result.refetch,
2436
+ reset: result.reset
2437
+ };
2438
+ }
2000
2439
  function resolveGetSession(authClient) {
2001
2440
  if ("getSession" in authClient && typeof authClient.getSession === "function") {
2002
2441
  return authClient.getSession;
@@ -2004,7 +2443,16 @@ function resolveGetSession(authClient) {
2004
2443
  if ("auth" in authClient && authClient.auth && typeof authClient.auth.getSession === "function") {
2005
2444
  return authClient.auth.getSession;
2006
2445
  }
2007
- throw new Error("useSession requires an auth-capable client (createClient(...).auth)");
2446
+ throw new Error(
2447
+ "useSession requires an auth-capable client (createClient(...).auth)"
2448
+ );
2449
+ }
2450
+ function toFallbackErrorDetails(code, message, status) {
2451
+ return {
2452
+ code,
2453
+ message,
2454
+ status
2455
+ };
2008
2456
  }
2009
2457
  function useSession(authClient, options = {}) {
2010
2458
  const enabled = options.enabled ?? true;
@@ -2022,11 +2470,6 @@ function useSession(authClient, options = {}) {
2022
2470
  React.useEffect(() => {
2023
2471
  dataRef.current = data;
2024
2472
  }, [data]);
2025
- const toFallbackErrorDetails = (code, message, status) => ({
2026
- code,
2027
- message,
2028
- status
2029
- });
2030
2473
  const runFetch = React.useCallback(async () => {
2031
2474
  const requestId = ++requestIdRef.current;
2032
2475
  const hasData = dataRef.current !== null;
@@ -2089,6 +2532,211 @@ function useSession(authClient, options = {}) {
2089
2532
  refetch
2090
2533
  };
2091
2534
  }
2535
+
2536
+ // src/admin/index.ts
2537
+ function resolveAdminPermissionClient(client) {
2538
+ if (!client || typeof client !== "object") {
2539
+ return null;
2540
+ }
2541
+ const record = client;
2542
+ const nestedAuth = record.auth;
2543
+ if (nestedAuth && typeof nestedAuth === "object" && nestedAuth !== null && "admin" in nestedAuth) {
2544
+ return client;
2545
+ }
2546
+ if ("admin" in record) {
2547
+ return { auth: client };
2548
+ }
2549
+ return null;
2550
+ }
2551
+ function buildAdminAuthFetchOptions(credentials = {}) {
2552
+ const cookie = credentials.cookie?.trim() || void 0;
2553
+ const bearerToken = credentials.bearerToken?.trim() || void 0;
2554
+ const headers = {};
2555
+ if (cookie) {
2556
+ headers.cookie = cookie;
2557
+ }
2558
+ if (bearerToken) {
2559
+ headers.authorization = `Bearer ${bearerToken}`;
2560
+ }
2561
+ return {
2562
+ credentials: "include",
2563
+ ...bearerToken ? { bearerToken } : {},
2564
+ ...Object.keys(headers).length > 0 ? { headers } : {}
2565
+ };
2566
+ }
2567
+ function hasAdminRole(session) {
2568
+ const role = session?.user?.role;
2569
+ if (!role) {
2570
+ return false;
2571
+ }
2572
+ return role.split(",").map((item) => item.trim().toLowerCase()).includes("admin");
2573
+ }
2574
+ function mergeAdminFetchOptions(input) {
2575
+ const fromCredentials = input.credentials ? buildAdminAuthFetchOptions(input.credentials) : void 0;
2576
+ const explicit = input.fetchOptions;
2577
+ if (!fromCredentials && !explicit) {
2578
+ return void 0;
2579
+ }
2580
+ if (!fromCredentials) {
2581
+ return explicit;
2582
+ }
2583
+ if (!explicit) {
2584
+ return fromCredentials;
2585
+ }
2586
+ return {
2587
+ ...fromCredentials,
2588
+ ...explicit,
2589
+ headers: {
2590
+ ...fromCredentials.headers ?? {},
2591
+ ...explicit.headers ?? {}
2592
+ }
2593
+ };
2594
+ }
2595
+ async function hasAdminPermission(client, input) {
2596
+ if (!input.session?.user?.id) {
2597
+ return false;
2598
+ }
2599
+ if (input.allowRoleBypass !== false && hasAdminRole(input.session)) {
2600
+ return true;
2601
+ }
2602
+ const fetchOptions = mergeAdminFetchOptions(input);
2603
+ const result = await client.auth.admin.hasPermission(
2604
+ {
2605
+ permission: input.permission,
2606
+ permissions: input.permissions,
2607
+ ...fetchOptions ? { fetchOptions } : {}
2608
+ },
2609
+ input.requestOptions
2610
+ );
2611
+ return Boolean(result.ok && result.data?.success);
2612
+ }
2613
+
2614
+ // src/react/use-admin-permission.ts
2615
+ var DEFAULT_ADMIN_PERMISSIONS = [
2616
+ "admin:read"
2617
+ ];
2618
+ function serializePermissions(permissions, permission) {
2619
+ return JSON.stringify({
2620
+ permission: permission ?? null,
2621
+ permissions: permissions ?? DEFAULT_ADMIN_PERMISSIONS
2622
+ });
2623
+ }
2624
+ function useAdminPermission(client, options = {}) {
2625
+ const enabled = options.enabled ?? true;
2626
+ const sessionProvided = "session" in options;
2627
+ const sessionFromOptions = sessionProvided ? options.session ?? null : void 0;
2628
+ const permissionsKey = serializePermissions(options.permissions, options.permission);
2629
+ const allowRoleBypass = options.allowRoleBypass;
2630
+ const fetchOptions = options.fetchOptions;
2631
+ const requestOptions = options.requestOptions;
2632
+ const optionsRef = React.useRef(options);
2633
+ optionsRef.current = options;
2634
+ const sessionState = useSession(client, {
2635
+ ...options.sessionOptions,
2636
+ enabled: enabled && !sessionProvided && !!client
2637
+ });
2638
+ const session = sessionProvided ? sessionFromOptions ?? null : sessionState.data;
2639
+ const sessionPending = !sessionProvided && sessionState.isPending;
2640
+ const sessionUserId = session?.user?.id ?? null;
2641
+ const sessionRole = session?.user?.role ?? null;
2642
+ const [allowed, setAllowed] = React.useState(false);
2643
+ const [error, setError] = React.useState(null);
2644
+ const [isChecking, setIsChecking] = React.useState(enabled);
2645
+ const requestIdRef = React.useRef(0);
2646
+ const mountedRef = React.useRef(true);
2647
+ const runCheck = React.useCallback(async () => {
2648
+ const requestId = ++requestIdRef.current;
2649
+ const current = optionsRef.current;
2650
+ const permissions = current.permissions ?? DEFAULT_ADMIN_PERMISSIONS;
2651
+ if (!enabled || !client) {
2652
+ if (mountedRef.current && requestId === requestIdRef.current) {
2653
+ setAllowed(false);
2654
+ setError(null);
2655
+ setIsChecking(false);
2656
+ }
2657
+ return false;
2658
+ }
2659
+ setIsChecking(true);
2660
+ try {
2661
+ const permissionClient = resolveAdminPermissionClient(client);
2662
+ if (!permissionClient) {
2663
+ throw new Error(
2664
+ "useAdminPermission requires an Athena client with auth.admin (createClient(...) or auth bindings)"
2665
+ );
2666
+ }
2667
+ const resolvedSession = sessionProvided ? current.session ?? null : sessionState.data;
2668
+ const nextAllowed = await hasAdminPermission(permissionClient, {
2669
+ session: resolvedSession,
2670
+ permissions,
2671
+ permission: current.permission,
2672
+ allowRoleBypass: current.allowRoleBypass,
2673
+ fetchOptions: current.fetchOptions,
2674
+ requestOptions: current.requestOptions
2675
+ });
2676
+ if (!mountedRef.current || requestId !== requestIdRef.current) {
2677
+ return nextAllowed;
2678
+ }
2679
+ setAllowed(nextAllowed);
2680
+ setError(null);
2681
+ return nextAllowed;
2682
+ } catch (checkError) {
2683
+ if (!mountedRef.current || requestId !== requestIdRef.current) {
2684
+ return false;
2685
+ }
2686
+ const nextError = checkError instanceof Error ? checkError : new Error("Failed to resolve admin permission");
2687
+ setAllowed(false);
2688
+ setError(nextError);
2689
+ return false;
2690
+ } finally {
2691
+ if (mountedRef.current && requestId === requestIdRef.current) {
2692
+ setIsChecking(false);
2693
+ }
2694
+ }
2695
+ }, [client, enabled, sessionProvided, sessionState.data]);
2696
+ React.useEffect(() => {
2697
+ mountedRef.current = true;
2698
+ return () => {
2699
+ mountedRef.current = false;
2700
+ };
2701
+ }, []);
2702
+ React.useEffect(() => {
2703
+ if (!enabled) {
2704
+ setAllowed(false);
2705
+ setError(null);
2706
+ setIsChecking(false);
2707
+ return;
2708
+ }
2709
+ if (!sessionProvided && sessionState.isPending) {
2710
+ setIsChecking(true);
2711
+ return;
2712
+ }
2713
+ void runCheck();
2714
+ }, [
2715
+ allowRoleBypass,
2716
+ enabled,
2717
+ fetchOptions,
2718
+ permissionsKey,
2719
+ requestOptions,
2720
+ runCheck,
2721
+ sessionPending,
2722
+ sessionProvided,
2723
+ sessionRole,
2724
+ sessionUserId
2725
+ ]);
2726
+ const refetch = React.useCallback(async () => {
2727
+ if (!sessionProvided) {
2728
+ await sessionState.refetch();
2729
+ }
2730
+ return await runCheck();
2731
+ }, [runCheck, sessionProvided, sessionState]);
2732
+ return {
2733
+ allowed,
2734
+ isPending: enabled && (sessionPending || isChecking),
2735
+ error,
2736
+ session,
2737
+ refetch
2738
+ };
2739
+ }
2092
2740
  function useAthenaSessionClient(baseClient, options = {}) {
2093
2741
  const sessionState = useSession(baseClient, options);
2094
2742
  const scopedClient = React.useMemo(
@@ -2193,7 +2841,13 @@ function isStorageUploadInput(input) {
2193
2841
  return Boolean(input) && typeof input === "object" && "files" in input && "s3_id" in input;
2194
2842
  }
2195
2843
  function useStorageFiles(options) {
2196
- const { storage, input, enabled = true, callOptions, refreshIntervalMs } = options;
2844
+ const {
2845
+ storage,
2846
+ input,
2847
+ enabled = true,
2848
+ callOptions,
2849
+ refreshIntervalMs
2850
+ } = options;
2197
2851
  const [data, setData] = React__namespace.useState(null);
2198
2852
  const [loading, setLoading] = React__namespace.useState(false);
2199
2853
  const [error, setError] = React__namespace.useState(null);
@@ -2291,7 +2945,7 @@ function resolveNullishValue(mode) {
2291
2945
  if (mode === "null") return null;
2292
2946
  return "";
2293
2947
  }
2294
- function isRecord3(value) {
2948
+ function isRecord4(value) {
2295
2949
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
2296
2950
  }
2297
2951
  function isNullableColumn(model, key) {
@@ -2300,7 +2954,7 @@ function isNullableColumn(model, key) {
2300
2954
  }
2301
2955
  function toModelFormDefaults(model, values, options) {
2302
2956
  const source = values;
2303
- if (!isRecord3(source)) {
2957
+ if (!isRecord4(source)) {
2304
2958
  return {};
2305
2959
  }
2306
2960
  const mode = options?.nullishMode ?? "empty-string";
@@ -2355,8 +3009,10 @@ exports.createModelFormAdapter = createModelFormAdapter;
2355
3009
  exports.isAthenaGatewayError = isAthenaGatewayError;
2356
3010
  exports.toModelFormDefaults = toModelFormDefaults;
2357
3011
  exports.toModelPayload = toModelPayload;
3012
+ exports.useAdminPermission = useAdminPermission;
2358
3013
  exports.useAthenaGateway = useAthenaGateway;
2359
3014
  exports.useAthenaQueryClient = useAthenaQueryClient;
3015
+ exports.useAthenaReadQuery = useAthenaReadQuery;
2360
3016
  exports.useAthenaSessionClient = useAthenaSessionClient;
2361
3017
  exports.useMutation = useMutation;
2362
3018
  exports.useQuery = useQuery;