@xylex-group/athena 2.7.0 → 2.8.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 +218 -18
- package/dist/browser.cjs +2173 -675
- package/dist/browser.cjs.map +1 -1
- package/dist/browser.d.cts +8 -7
- package/dist/browser.d.ts +8 -7
- package/dist/browser.js +2167 -676
- package/dist/browser.js.map +1 -1
- package/dist/cli/index.cjs +2068 -559
- package/dist/cli/index.cjs.map +1 -1
- package/dist/cli/index.d.cts +3 -3
- package/dist/cli/index.d.ts +3 -3
- package/dist/cli/index.js +2068 -559
- package/dist/cli/index.js.map +1 -1
- package/dist/index.cjs +2815 -945
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +8 -7
- package/dist/index.d.ts +8 -7
- package/dist/index.js +2809 -946
- package/dist/index.js.map +1 -1
- package/dist/{model-form-AKYrgede.d.ts → model-form-Cx3wtvi8.d.ts} +963 -93
- package/dist/{model-form-ehfqLuG7.d.cts → model-form-_ugfOXao.d.cts} +963 -93
- package/dist/{pipeline-BfCWSRYl.d.cts → pipeline-BtD-Uo5X.d.cts} +1 -1
- package/dist/{pipeline-BUsR9XlO.d.ts → pipeline-yCIZNJHE.d.ts} +1 -1
- package/dist/{react-email-BQzmXBDE.d.cts → react-email-CiiSVa9F.d.cts} +121 -10
- package/dist/{react-email-BrVRp80B.d.ts → react-email-WN8UU3AL.d.ts} +121 -10
- package/dist/react.cjs +1 -1
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.cts +4 -4
- package/dist/react.d.ts +4 -4
- package/dist/react.js +1 -1
- package/dist/react.js.map +1 -1
- package/dist/{types-t_TVqnmp.d.ts → types-89EfjLjV.d.cts} +48 -5
- package/dist/{types-BSIsyss1.d.cts → types-C2kiTt6-.d.ts} +48 -5
- package/dist/{types-BsyRW49r.d.cts → types-g8G6J0xE.d.cts} +26 -1
- package/dist/{types-BsyRW49r.d.ts → types-g8G6J0xE.d.ts} +26 -1
- package/package.json +28 -57
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# athena-js
|
|
2
2
|
|
|
3
|
-
current version: `2.
|
|
3
|
+
current version: `2.8.2`
|
|
4
4
|
`@xylex-group/athena` is a database driver and API gateway SDK that lets you interact with SQL backends over HTTP through a fluent builder API. It ships a typed query builder for Node.js / server environments plus Athena-native React hooks for client-side use.
|
|
5
5
|
|
|
6
6
|
## Install
|
|
@@ -24,10 +24,14 @@ npm install react # React >=17 required for the hook
|
|
|
24
24
|
```ts
|
|
25
25
|
import { createClient } from "@xylex-group/athena";
|
|
26
26
|
|
|
27
|
-
const athenaClient = createClient(
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
27
|
+
const athenaClient = createClient(
|
|
28
|
+
ATHENA_URL,
|
|
29
|
+
ATHENA_API_KEY,
|
|
30
|
+
{
|
|
31
|
+
client: "CLIENT_NAME",
|
|
32
|
+
backend: { type: "athena" },
|
|
33
|
+
},
|
|
34
|
+
);
|
|
31
35
|
|
|
32
36
|
const { data, error } = await athenaClient.from("orchestral_sections").findMany({
|
|
33
37
|
select: {
|
|
@@ -47,6 +51,34 @@ if (error) {
|
|
|
47
51
|
}
|
|
48
52
|
```
|
|
49
53
|
|
|
54
|
+
`createClient(url, key)` is the canonical SDK shape. The SDK treats `url` as the public unified Athena base URL and derives:
|
|
55
|
+
|
|
56
|
+
- DB: `${url}/db`
|
|
57
|
+
- Auth: `${url}/auth`
|
|
58
|
+
- Storage: `${url}/storage`
|
|
59
|
+
|
|
60
|
+
You can still override individual services when needed:
|
|
61
|
+
|
|
62
|
+
```ts
|
|
63
|
+
const athena = createClient({
|
|
64
|
+
key: ATHENA_API_KEY,
|
|
65
|
+
db: { url: process.env.ATHENA_DB_URL },
|
|
66
|
+
auth: { url: process.env.ATHENA_AUTH_URL },
|
|
67
|
+
storage: { url: process.env.ATHENA_STORAGE_URL },
|
|
68
|
+
});
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
Legacy top-level aliases are also supported:
|
|
72
|
+
|
|
73
|
+
```ts
|
|
74
|
+
const athena = createClient({
|
|
75
|
+
key: ATHENA_API_KEY,
|
|
76
|
+
gatewayUrl: process.env.ATHENA_DB_URL,
|
|
77
|
+
authUrl: process.env.ATHENA_AUTH_URL,
|
|
78
|
+
storageUrl: process.env.ATHENA_STORAGE_URL,
|
|
79
|
+
});
|
|
80
|
+
```
|
|
81
|
+
|
|
50
82
|
Example version baseline: SDK `@xylex-group/athena` `2.4.0`, Athena server `3.12.3` verified on 2026-06-04.
|
|
51
83
|
|
|
52
84
|
`.findMany({ select, where, orderBy, limit })` is the clean canonical read surface.
|
|
@@ -238,28 +270,38 @@ It also supports dynamic `baseURL` host resolution plus static/dynamic
|
|
|
238
270
|
|
|
239
271
|
For the full details and current scope, see [`docs/auth/server-bootstrap.mdx`](docs/auth/server-bootstrap.mdx).
|
|
240
272
|
|
|
241
|
-
### Typed schema registry (
|
|
273
|
+
### Typed schema registry (table-first)
|
|
242
274
|
|
|
243
|
-
You can keep `createClient(...).from<T>(...)` as-is, or opt into a typed registry:
|
|
275
|
+
You can keep `createClient(...).from<T>(...)` as-is, or opt into a typed registry with the new Zero-style table DSL:
|
|
244
276
|
|
|
245
277
|
```ts
|
|
246
278
|
import {
|
|
279
|
+
boolean,
|
|
247
280
|
createTypedClient,
|
|
248
281
|
defineDatabase,
|
|
249
|
-
defineModel,
|
|
250
282
|
defineRegistry,
|
|
251
283
|
defineSchema,
|
|
284
|
+
enumeration,
|
|
285
|
+
json,
|
|
286
|
+
string,
|
|
287
|
+
table,
|
|
252
288
|
} from "@xylex-group/athena";
|
|
253
289
|
|
|
290
|
+
const users = table("users")
|
|
291
|
+
.schema("public")
|
|
292
|
+
.columns({
|
|
293
|
+
id: string().generated(),
|
|
294
|
+
email: string(),
|
|
295
|
+
active: boolean().defaulted(),
|
|
296
|
+
mood: enumeration(["happy", "sad"] as const).optional(),
|
|
297
|
+
settings: json<{ theme: "light" | "dark" }>(),
|
|
298
|
+
})
|
|
299
|
+
.primaryKey("id");
|
|
300
|
+
|
|
254
301
|
const registry = defineRegistry({
|
|
255
302
|
primary: defineDatabase({
|
|
256
303
|
public: defineSchema({
|
|
257
|
-
users
|
|
258
|
-
meta: {
|
|
259
|
-
primaryKey: ["id"],
|
|
260
|
-
nullable: { id: false, email: false },
|
|
261
|
-
},
|
|
262
|
-
}),
|
|
304
|
+
users,
|
|
263
305
|
}),
|
|
264
306
|
}),
|
|
265
307
|
});
|
|
@@ -274,8 +316,45 @@ await typed
|
|
|
274
316
|
.withTenantContext({ organizationId: "org_1" })
|
|
275
317
|
.fromModel("primary", "public", "users")
|
|
276
318
|
.select("*");
|
|
319
|
+
|
|
320
|
+
const insert = users.schemas.form.parse({
|
|
321
|
+
email: "ada@example.com",
|
|
322
|
+
mood: "",
|
|
323
|
+
settings: { theme: "light" },
|
|
324
|
+
});
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
You can also pass that native Athena table/model value directly into the root client to avoid repeating the string table target:
|
|
328
|
+
|
|
329
|
+
```ts
|
|
330
|
+
const result = await athena.from(users)
|
|
331
|
+
.select("id, email, active")
|
|
332
|
+
.eq("active", true)
|
|
333
|
+
.order("created_at", { ascending: false })
|
|
334
|
+
.limit(25);
|
|
277
335
|
```
|
|
278
336
|
|
|
337
|
+
This is the viable opt-in short form because the `users` value carries runtime target metadata. A generic-only call like `from<UserPublicSchema>()` cannot resolve a table at runtime after TypeScript erases types.
|
|
338
|
+
|
|
339
|
+
If you want compile-time validation for simple string selects and RPC column names, enable the experimental strict mode:
|
|
340
|
+
|
|
341
|
+
```ts
|
|
342
|
+
const strictAthena = createClient(ATHENA_URL, ATHENA_API_KEY, {
|
|
343
|
+
experimental: {
|
|
344
|
+
typecheckColumns: true,
|
|
345
|
+
},
|
|
346
|
+
});
|
|
347
|
+
|
|
348
|
+
await strictAthena.from(users).select("id, email").order("created_at");
|
|
349
|
+
|
|
350
|
+
// compile-time error
|
|
351
|
+
strictAthena.from(users).select("id, missing_column");
|
|
352
|
+
```
|
|
353
|
+
|
|
354
|
+
For the DB helper surface, use `strictAthena.db.from<UserRow>("users").select("id, email")` when you want inline typed column validation. `strictAthena.db.select<UserRow>("users")` still gives a typed row-aware chain, but it does not accept inline typed column arguments.
|
|
355
|
+
|
|
356
|
+
`defineModel(...)` remains fully supported for compatibility and manual contracts.
|
|
357
|
+
|
|
279
358
|
For full details, see [`docs/typed-schema-registry.md`](./docs/typed-schema-registry.md).
|
|
280
359
|
|
|
281
360
|
For exhaustive method-by-method documentation with usage snippets (root client, runtime builders, auth bindings, react runtime, cookies, and utils), see [`docs/complete-method-reference.md`](./docs/complete-method-reference.md).
|
|
@@ -294,15 +373,98 @@ athena-js generate --help
|
|
|
294
373
|
athena-js help generate
|
|
295
374
|
```
|
|
296
375
|
|
|
376
|
+
Out of the box, `athena-js generate` now works without an `athena.config.*` file in the common cases:
|
|
377
|
+
|
|
378
|
+
```bash
|
|
379
|
+
DATABASE_URL=postgres://postgres:postgres@127.0.0.1:5432/app_db athena-js generate --dry-run
|
|
380
|
+
```
|
|
381
|
+
|
|
382
|
+
```bash
|
|
383
|
+
ATHENA_URL=https://athena-db.com ATHENA_API_KEY=secret ATHENA_GENERATOR_DB=app_db athena-js generate --dry-run
|
|
384
|
+
```
|
|
385
|
+
|
|
386
|
+
Smallest direct-mode config file:
|
|
387
|
+
|
|
388
|
+
```ts
|
|
389
|
+
import { defineGeneratorConfig } from "@xylex-group/athena";
|
|
390
|
+
|
|
391
|
+
export default defineGeneratorConfig({
|
|
392
|
+
provider: {
|
|
393
|
+
kind: "postgres",
|
|
394
|
+
mode: "direct",
|
|
395
|
+
},
|
|
396
|
+
});
|
|
397
|
+
```
|
|
398
|
+
|
|
399
|
+
Smallest table-builder config:
|
|
400
|
+
|
|
401
|
+
```ts
|
|
402
|
+
import { defineGeneratorConfig } from "@xylex-group/athena";
|
|
403
|
+
|
|
404
|
+
export default defineGeneratorConfig({
|
|
405
|
+
provider: {
|
|
406
|
+
kind: "postgres",
|
|
407
|
+
mode: "direct",
|
|
408
|
+
},
|
|
409
|
+
output: {
|
|
410
|
+
format: "table-builder",
|
|
411
|
+
},
|
|
412
|
+
});
|
|
413
|
+
```
|
|
414
|
+
|
|
415
|
+
Important:
|
|
416
|
+
|
|
417
|
+
- `output.format = "table-builder"` is stable generator behavior, not an experimental flag.
|
|
418
|
+
- `experimental.findManyAst` is a separate runtime transport opt-in for `findMany(...)`; it does not enable generated table artifacts.
|
|
419
|
+
- the default generator mode is still legacy `define-model`, and the default model target is still schema-scoped (`athena/models/{schema_kebab}/{model_kebab}.ts`)
|
|
420
|
+
- if you want flat `athena/models/*.ts` files, set `output.targets.model = "athena/models/{model_kebab}.ts"` (or `ATHENA_GENERATOR_MODEL_TARGET=athena/models/{model_kebab}.ts`); multi-schema collisions are still auto-scoped by schema when needed
|
|
421
|
+
|
|
422
|
+
Common copy-paste starts:
|
|
423
|
+
|
|
424
|
+
```bash
|
|
425
|
+
# direct postgres, no config file
|
|
426
|
+
DATABASE_URL=postgres://postgres:postgres@127.0.0.1:5432/app_db athena-js generate --dry-run
|
|
427
|
+
|
|
428
|
+
# direct postgres + Zero-style output + multiple schemas
|
|
429
|
+
DATABASE_URL=postgres://postgres:postgres@127.0.0.1:5432/app_db \
|
|
430
|
+
ATHENA_GENERATOR_OUTPUT_FORMAT=table-builder \
|
|
431
|
+
ATHENA_GENERATOR_SCHEMAS=public,analytics \
|
|
432
|
+
athena-js generate --dry-run
|
|
433
|
+
|
|
434
|
+
# gateway-only CI job, no config file
|
|
435
|
+
ATHENA_URL=https://athena-db.com \
|
|
436
|
+
ATHENA_API_KEY=secret \
|
|
437
|
+
ATHENA_GENERATOR_DB=app_db \
|
|
438
|
+
athena-js generate --dry-run
|
|
439
|
+
```
|
|
440
|
+
|
|
441
|
+
Smallest gateway table-builder config:
|
|
442
|
+
|
|
443
|
+
```ts
|
|
444
|
+
import { defineGeneratorConfig } from "@xylex-group/athena";
|
|
445
|
+
|
|
446
|
+
export default defineGeneratorConfig({
|
|
447
|
+
provider: {
|
|
448
|
+
kind: "postgres",
|
|
449
|
+
mode: "gateway",
|
|
450
|
+
},
|
|
451
|
+
output: {
|
|
452
|
+
format: "table-builder",
|
|
453
|
+
},
|
|
454
|
+
});
|
|
455
|
+
```
|
|
456
|
+
|
|
297
457
|
Generator supports:
|
|
298
458
|
|
|
299
459
|
- PostgreSQL direct introspection (`provider.mode = "direct"`, `provider.connectionString` from your `PG_URL`/`DATABASE_URL`)
|
|
300
460
|
- PostgreSQL gateway-only introspection (`provider.mode = "gateway"` via Athena `POST /gateway/query`)
|
|
301
|
-
- Multiple schema syncs such as `public` plus `athena`, with schema-safe default output paths
|
|
461
|
+
- Multiple schema syncs such as `public` plus `athena`, with schema-safe default output paths
|
|
462
|
+
- Two output formats: legacy `define-model` artifacts (default) or the new Zero-style `table-builder` format via `output.format`
|
|
302
463
|
- Placeholder-driven output paths
|
|
303
464
|
- Feature flags (`features.emitRegistry`, `features.emitRelations`)
|
|
304
465
|
- Typed env-backed config fields via `generatorEnv(...)` for connection strings, schema lists, naming styles, flags, and placeholder maps
|
|
305
466
|
|
|
467
|
+
For copy-paste quickstarts and more example profiles, see [`docs/generator-quickstart.md`](./docs/generator-quickstart.md).
|
|
306
468
|
For full generator configuration and troubleshooting, see [`docs/generator-config.md`](./docs/generator-config.md).
|
|
307
469
|
For full CLI commands, help behavior, and troubleshooting, see [`docs/cli-command-reference.md`](./docs/cli-command-reference.md).
|
|
308
470
|
For CI/CD pipelines and generated-file branch policy, see [`docs/generator-cicd.md`](./docs/generator-cicd.md).
|
|
@@ -375,7 +537,7 @@ requireAffected(inserted, { min: 1 }, { table: "users", operation: "insert" });
|
|
|
375
537
|
### Structured errors by default
|
|
376
538
|
|
|
377
539
|
```ts
|
|
378
|
-
import { createClient
|
|
540
|
+
import { createClient } from "@xylex-group/athena";
|
|
379
541
|
|
|
380
542
|
const athena = createClient(ATHENA_URL, ATHENA_API_KEY);
|
|
381
543
|
|
|
@@ -391,13 +553,13 @@ if (error) {
|
|
|
391
553
|
|
|
392
554
|
`result.error` already carries normalized `kind` values (`unique_violation`, `validation`, `auth`, `rate_limit`, `transient`, etc.) plus operation metadata.
|
|
393
555
|
|
|
394
|
-
`normalizeAthenaError(
|
|
556
|
+
`normalizeAthenaError(...)` is deprecated. Prefer `result.error` on failed results and the structured fields already attached to thrown SDK errors.
|
|
395
557
|
|
|
396
558
|
### Query tracing (experimental)
|
|
397
559
|
|
|
398
560
|
```ts
|
|
399
561
|
const athena = createClient(ATHENA_URL, ATHENA_API_KEY, {
|
|
400
|
-
experimental: { traceQueries: true },
|
|
562
|
+
experimental: { traceQueries: true, debugAst: true },
|
|
401
563
|
});
|
|
402
564
|
```
|
|
403
565
|
|
|
@@ -426,6 +588,44 @@ const athena = createClient(ATHENA_URL, ATHENA_API_KEY, {
|
|
|
426
588
|
});
|
|
427
589
|
```
|
|
428
590
|
|
|
591
|
+
If you also enable `debugAst: true`, every traced operation includes a normalized AST, and successful results expose the same AST through `getAthenaDebugAst(...)`:
|
|
592
|
+
|
|
593
|
+
```ts
|
|
594
|
+
import { createClient, getAthenaDebugAst } from "@xylex-group/athena";
|
|
595
|
+
|
|
596
|
+
const athena = createClient(ATHENA_URL, ATHENA_API_KEY, {
|
|
597
|
+
experimental: {
|
|
598
|
+
debugAst: true,
|
|
599
|
+
},
|
|
600
|
+
});
|
|
601
|
+
|
|
602
|
+
const result = await athena.from("users").eq("id", 1).select("id");
|
|
603
|
+
const ast = getAthenaDebugAst(result);
|
|
604
|
+
```
|
|
605
|
+
|
|
606
|
+
This works across the runtime operation families too:
|
|
607
|
+
|
|
608
|
+
```ts
|
|
609
|
+
const inserted = await athena
|
|
610
|
+
.from("users")
|
|
611
|
+
.insert({ email: "ada@example.com" })
|
|
612
|
+
.select("id,email");
|
|
613
|
+
|
|
614
|
+
const insertedAst = getAthenaDebugAst(inserted);
|
|
615
|
+
|
|
616
|
+
const rpcResult = await athena
|
|
617
|
+
.rpc("list_users", { role: "admin" })
|
|
618
|
+
.eq("active", true)
|
|
619
|
+
.select("id,email");
|
|
620
|
+
|
|
621
|
+
const rpcAst = getAthenaDebugAst(rpcResult);
|
|
622
|
+
|
|
623
|
+
const sqlResult = await athena.query<{ id: number }>("select id from users where active = true");
|
|
624
|
+
const sqlAst = getAthenaDebugAst(sqlResult);
|
|
625
|
+
```
|
|
626
|
+
|
|
627
|
+
If `traceQueries` is enabled too, the same normalized AST is emitted on each `AthenaQueryTraceEvent.ast`.
|
|
628
|
+
|
|
429
629
|
### Read retries (experimental)
|
|
430
630
|
|
|
431
631
|
```ts
|