@opensaas/stack-core 0.23.0 → 0.25.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.
- package/.turbo/turbo-build.log +1 -1
- package/CHANGELOG.md +256 -0
- package/dist/access/access-filter.d.ts +39 -0
- package/dist/access/access-filter.d.ts.map +1 -1
- package/dist/access/access-filter.js +121 -0
- package/dist/access/access-filter.js.map +1 -1
- package/dist/access/field-access.d.ts +1 -0
- package/dist/access/field-access.d.ts.map +1 -1
- package/dist/access/field-access.js +79 -4
- package/dist/access/field-access.js.map +1 -1
- package/dist/access/field-access.test.js +213 -0
- package/dist/access/field-access.test.js.map +1 -1
- package/dist/access/index.d.ts +1 -1
- package/dist/access/index.d.ts.map +1 -1
- package/dist/access/index.js +1 -1
- package/dist/access/index.js.map +1 -1
- package/dist/access/types.d.ts +39 -0
- package/dist/access/types.d.ts.map +1 -1
- package/dist/config/index.d.ts +1 -1
- package/dist/config/index.d.ts.map +1 -1
- package/dist/config/types.d.ts +378 -0
- package/dist/config/types.d.ts.map +1 -1
- package/dist/context/index.d.ts +19 -1
- package/dist/context/index.d.ts.map +1 -1
- package/dist/context/index.js +153 -26
- package/dist/context/index.js.map +1 -1
- package/dist/context/nested-operations.d.ts +59 -3
- package/dist/context/nested-operations.d.ts.map +1 -1
- package/dist/context/nested-operations.js +552 -129
- package/dist/context/nested-operations.js.map +1 -1
- package/dist/context/transaction-boundary.d.ts +91 -0
- package/dist/context/transaction-boundary.d.ts.map +1 -0
- package/dist/context/transaction-boundary.js +329 -0
- package/dist/context/transaction-boundary.js.map +1 -0
- package/dist/context/write-pipeline.d.ts +15 -1
- package/dist/context/write-pipeline.d.ts.map +1 -1
- package/dist/context/write-pipeline.js +173 -10
- package/dist/context/write-pipeline.js.map +1 -1
- package/dist/fields/calendar-day.test.d.ts +2 -0
- package/dist/fields/calendar-day.test.d.ts.map +1 -0
- package/dist/fields/calendar-day.test.js +120 -0
- package/dist/fields/calendar-day.test.js.map +1 -0
- package/dist/fields/index.d.ts +18 -2
- package/dist/fields/index.d.ts.map +1 -1
- package/dist/fields/index.js +93 -17
- package/dist/fields/index.js.map +1 -1
- package/dist/hooks/index.d.ts +116 -0
- package/dist/hooks/index.d.ts.map +1 -1
- package/dist/hooks/index.js +154 -0
- package/dist/hooks/index.js.map +1 -1
- package/dist/validation/schema.test.js +222 -1
- package/dist/validation/schema.test.js.map +1 -1
- package/package.json +1 -1
- package/src/access/access-filter.ts +156 -0
- package/src/access/field-access.test.ts +255 -0
- package/src/access/field-access.ts +91 -5
- package/src/access/index.ts +1 -1
- package/src/access/types.ts +45 -0
- package/src/config/index.ts +2 -0
- package/src/config/types.ts +426 -0
- package/src/context/index.ts +207 -37
- package/src/context/nested-operations.ts +969 -143
- package/src/context/transaction-boundary.ts +440 -0
- package/src/context/write-pipeline.ts +234 -13
- package/src/fields/calendar-day.test.ts +140 -0
- package/src/fields/index.ts +96 -16
- package/src/hooks/index.ts +265 -0
- package/src/validation/schema.test.ts +266 -1
- package/tests/access.test.ts +24 -16
- package/tests/config.test.ts +30 -0
- package/tests/context.test.ts +481 -0
- package/tests/field-types.test.ts +17 -3
- package/tests/nested-access-and-hooks.test.ts +1130 -54
- package/tests/nested-operation-registry.test.ts +28 -3
- package/tests/nested-write-hooks.test.ts +864 -0
- package/tests/transaction-boundary-hooks.test.ts +465 -0
- package/tsconfig.tsbuildinfo +1 -1
package/src/config/types.ts
CHANGED
|
@@ -150,6 +150,125 @@ export type FieldAfterOperationHookArgs<
|
|
|
150
150
|
context: import('../access/types.js').AccessContext
|
|
151
151
|
}
|
|
152
152
|
|
|
153
|
+
/**
|
|
154
|
+
* Arguments for field-level beforeTransaction hook (#590 / ADR-0010).
|
|
155
|
+
*
|
|
156
|
+
* Transaction-boundary hooks run OUTSIDE the write's database transaction.
|
|
157
|
+
* `beforeTransaction` runs before the transaction opens, so it has the input
|
|
158
|
+
* data but no persisted `item` yet (and, for create, no `item` to read). For
|
|
159
|
+
* update/delete the existing `item` is best-effort: present for the top-level
|
|
160
|
+
* target (which the pipeline resolves before opening the transaction) and
|
|
161
|
+
* `undefined` for nested targets (not resolved at the boundary to avoid
|
|
162
|
+
* pre-transaction reads). Use it for non-transactional side effects (e.g.
|
|
163
|
+
* external API calls) whose compensation pairs with `afterTransaction`.
|
|
164
|
+
*/
|
|
165
|
+
export type FieldBeforeTransactionHookArgs<
|
|
166
|
+
TTypeInfo extends TypeInfo,
|
|
167
|
+
TFieldKey extends FieldKeys<TTypeInfo['fields']> = FieldKeys<TTypeInfo['fields']>,
|
|
168
|
+
> =
|
|
169
|
+
| {
|
|
170
|
+
listKey: string
|
|
171
|
+
fieldKey: TFieldKey
|
|
172
|
+
operation: 'create'
|
|
173
|
+
inputData: TTypeInfo['inputs']['create']
|
|
174
|
+
context: import('../access/types.js').AccessContext
|
|
175
|
+
}
|
|
176
|
+
| {
|
|
177
|
+
listKey: string
|
|
178
|
+
fieldKey: TFieldKey
|
|
179
|
+
operation: 'update'
|
|
180
|
+
inputData: TTypeInfo['inputs']['update']
|
|
181
|
+
item: TTypeInfo['item'] | undefined
|
|
182
|
+
context: import('../access/types.js').AccessContext
|
|
183
|
+
}
|
|
184
|
+
| {
|
|
185
|
+
listKey: string
|
|
186
|
+
fieldKey: TFieldKey
|
|
187
|
+
operation: 'delete'
|
|
188
|
+
item: TTypeInfo['item'] | undefined
|
|
189
|
+
context: import('../access/types.js').AccessContext
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* Arguments for field-level afterTransaction hook (#590 / ADR-0010).
|
|
194
|
+
*
|
|
195
|
+
* Runs AFTER the transaction settles and ALWAYS runs when its paired
|
|
196
|
+
* `beforeTransaction` ran (symmetric bracket). The `status` discriminant tells
|
|
197
|
+
* the hook whether the write committed or rolled back:
|
|
198
|
+
* - `committed`: the persisted `item`/`originalItem` are populated ONLY for the
|
|
199
|
+
* TOP-LEVEL record of the write. For NESTED lists they are `undefined` — the
|
|
200
|
+
* per-record persisted row is not reliably recoverable outside the
|
|
201
|
+
* transaction, and these hooks fire at per-(list, operation) granularity, not
|
|
202
|
+
* per record. For per-record nested compensation use the in-transaction
|
|
203
|
+
* `afterOperation` (which receives the correct nested `item`).
|
|
204
|
+
* - `rolled-back`: NO persisted `item`; the hook gets `inputData` and the
|
|
205
|
+
* `error` that caused the rollback so it can compensate for whatever
|
|
206
|
+
* `beforeTransaction` did externally.
|
|
207
|
+
*/
|
|
208
|
+
export type FieldAfterTransactionHookArgs<
|
|
209
|
+
TTypeInfo extends TypeInfo,
|
|
210
|
+
TFieldKey extends FieldKeys<TTypeInfo['fields']> = FieldKeys<TTypeInfo['fields']>,
|
|
211
|
+
> =
|
|
212
|
+
| {
|
|
213
|
+
listKey: string
|
|
214
|
+
fieldKey: TFieldKey
|
|
215
|
+
operation: 'create'
|
|
216
|
+
status: 'committed'
|
|
217
|
+
inputData: TTypeInfo['inputs']['create']
|
|
218
|
+
/** Persisted row — populated for the top-level list only; `undefined` for nested lists. */
|
|
219
|
+
item: TTypeInfo['item'] | undefined
|
|
220
|
+
context: import('../access/types.js').AccessContext
|
|
221
|
+
}
|
|
222
|
+
| {
|
|
223
|
+
listKey: string
|
|
224
|
+
fieldKey: TFieldKey
|
|
225
|
+
operation: 'create'
|
|
226
|
+
status: 'rolled-back'
|
|
227
|
+
inputData: TTypeInfo['inputs']['create']
|
|
228
|
+
error: unknown
|
|
229
|
+
context: import('../access/types.js').AccessContext
|
|
230
|
+
}
|
|
231
|
+
| {
|
|
232
|
+
listKey: string
|
|
233
|
+
fieldKey: TFieldKey
|
|
234
|
+
operation: 'update'
|
|
235
|
+
status: 'committed'
|
|
236
|
+
inputData: TTypeInfo['inputs']['update']
|
|
237
|
+
/** Pre-write row — populated for the top-level list only; `undefined` for nested lists. */
|
|
238
|
+
originalItem: TTypeInfo['item'] | undefined
|
|
239
|
+
/** Persisted row — populated for the top-level list only; `undefined` for nested lists. */
|
|
240
|
+
item: TTypeInfo['item'] | undefined
|
|
241
|
+
context: import('../access/types.js').AccessContext
|
|
242
|
+
}
|
|
243
|
+
| {
|
|
244
|
+
listKey: string
|
|
245
|
+
fieldKey: TFieldKey
|
|
246
|
+
operation: 'update'
|
|
247
|
+
status: 'rolled-back'
|
|
248
|
+
inputData: TTypeInfo['inputs']['update']
|
|
249
|
+
originalItem: TTypeInfo['item'] | undefined
|
|
250
|
+
error: unknown
|
|
251
|
+
context: import('../access/types.js').AccessContext
|
|
252
|
+
}
|
|
253
|
+
| {
|
|
254
|
+
listKey: string
|
|
255
|
+
fieldKey: TFieldKey
|
|
256
|
+
operation: 'delete'
|
|
257
|
+
status: 'committed'
|
|
258
|
+
/** Pre-write row — populated for the top-level list only; `undefined` for nested lists. */
|
|
259
|
+
originalItem: TTypeInfo['item'] | undefined
|
|
260
|
+
context: import('../access/types.js').AccessContext
|
|
261
|
+
}
|
|
262
|
+
| {
|
|
263
|
+
listKey: string
|
|
264
|
+
fieldKey: TFieldKey
|
|
265
|
+
operation: 'delete'
|
|
266
|
+
status: 'rolled-back'
|
|
267
|
+
originalItem: TTypeInfo['item'] | undefined
|
|
268
|
+
error: unknown
|
|
269
|
+
context: import('../access/types.js').AccessContext
|
|
270
|
+
}
|
|
271
|
+
|
|
153
272
|
/**
|
|
154
273
|
* Arguments for field-level resolveOutput hook
|
|
155
274
|
* Used to transform field values after database read
|
|
@@ -278,6 +397,53 @@ export type FieldHooks<
|
|
|
278
397
|
*/
|
|
279
398
|
afterOperation?: (args: FieldAfterOperationHookArgs<TTypeInfo, TFieldKey>) => Promise<void> | void
|
|
280
399
|
|
|
400
|
+
/**
|
|
401
|
+
* Perform side effects BEFORE the write's database transaction opens
|
|
402
|
+
* (#590 / ADR-0010 transaction-boundary hook).
|
|
403
|
+
*
|
|
404
|
+
* Unlike `beforeOperation` (which runs INSIDE the transaction and rolls back
|
|
405
|
+
* with it), this runs OUTSIDE the transaction — use it for non-transactional
|
|
406
|
+
* side effects such as external API calls that must not hold a DB transaction
|
|
407
|
+
* open and cannot be rolled back. If this throws, the write is aborted (the
|
|
408
|
+
* transaction never opens) and the paired `afterTransaction` fires with
|
|
409
|
+
* `status: 'rolled-back'`.
|
|
410
|
+
*
|
|
411
|
+
* @example
|
|
412
|
+
* ```typescript
|
|
413
|
+
* beforeTransaction: async ({ operation, inputData }) => {
|
|
414
|
+
* await externalApi.reserve(inputData.externalId)
|
|
415
|
+
* }
|
|
416
|
+
* ```
|
|
417
|
+
*/
|
|
418
|
+
beforeTransaction?: (
|
|
419
|
+
args: FieldBeforeTransactionHookArgs<TTypeInfo, TFieldKey>,
|
|
420
|
+
) => Promise<void> | void
|
|
421
|
+
|
|
422
|
+
/**
|
|
423
|
+
* Perform side effects AFTER the write's database transaction settles
|
|
424
|
+
* (#590 / ADR-0010 transaction-boundary hook).
|
|
425
|
+
*
|
|
426
|
+
* ALWAYS runs when the paired `beforeTransaction` ran (symmetric bracket),
|
|
427
|
+
* receiving `status: 'committed' | 'rolled-back'`. On `committed` it gets the
|
|
428
|
+
* persisted `item` ONLY for the top-level record (`undefined` for nested
|
|
429
|
+
* lists — use the in-transaction `afterOperation` for per-record nested
|
|
430
|
+
* compensation); on `rolled-back` it gets the `error` that caused the
|
|
431
|
+
* rollback and NO `item`, so it can compensate for whatever `beforeTransaction`
|
|
432
|
+
* did externally.
|
|
433
|
+
*
|
|
434
|
+
* @example
|
|
435
|
+
* ```typescript
|
|
436
|
+
* afterTransaction: async (args) => {
|
|
437
|
+
* if (args.status === 'rolled-back') {
|
|
438
|
+
* await externalApi.release(args.inputData.externalId)
|
|
439
|
+
* }
|
|
440
|
+
* }
|
|
441
|
+
* ```
|
|
442
|
+
*/
|
|
443
|
+
afterTransaction?: (
|
|
444
|
+
args: FieldAfterTransactionHookArgs<TTypeInfo, TFieldKey>,
|
|
445
|
+
) => Promise<void> | void
|
|
446
|
+
|
|
281
447
|
/**
|
|
282
448
|
* Transform field value after database read
|
|
283
449
|
* Called when returning results from query operations
|
|
@@ -1269,6 +1435,117 @@ export type AfterOperationHookArgs<
|
|
|
1269
1435
|
context: import('../access/types.js').AccessContext
|
|
1270
1436
|
}
|
|
1271
1437
|
|
|
1438
|
+
/**
|
|
1439
|
+
* Hook arguments for the list-level beforeTransaction hook (#590 / ADR-0010).
|
|
1440
|
+
*
|
|
1441
|
+
* Runs BEFORE the write's transaction opens (outside it). Has input data but no
|
|
1442
|
+
* persisted `item`. For update/delete the existing `item` is best-effort:
|
|
1443
|
+
* present for the top-level target (resolved before the transaction opens) and
|
|
1444
|
+
* `undefined` for nested targets. For non-transactional side effects whose
|
|
1445
|
+
* compensation pairs with `afterTransaction`.
|
|
1446
|
+
*/
|
|
1447
|
+
export type BeforeTransactionHookArgs<
|
|
1448
|
+
TOutput = Record<string, unknown>,
|
|
1449
|
+
TCreateInput = Record<string, unknown>,
|
|
1450
|
+
TUpdateInput = Record<string, unknown>,
|
|
1451
|
+
> =
|
|
1452
|
+
| {
|
|
1453
|
+
listKey: string
|
|
1454
|
+
operation: 'create'
|
|
1455
|
+
inputData: TCreateInput
|
|
1456
|
+
context: import('../access/types.js').AccessContext
|
|
1457
|
+
}
|
|
1458
|
+
| {
|
|
1459
|
+
listKey: string
|
|
1460
|
+
operation: 'update'
|
|
1461
|
+
inputData: TUpdateInput
|
|
1462
|
+
item: TOutput | undefined
|
|
1463
|
+
context: import('../access/types.js').AccessContext
|
|
1464
|
+
}
|
|
1465
|
+
| {
|
|
1466
|
+
listKey: string
|
|
1467
|
+
operation: 'delete'
|
|
1468
|
+
item: TOutput | undefined
|
|
1469
|
+
context: import('../access/types.js').AccessContext
|
|
1470
|
+
}
|
|
1471
|
+
|
|
1472
|
+
/**
|
|
1473
|
+
* Hook arguments for the list-level afterTransaction hook (#590 / ADR-0010).
|
|
1474
|
+
*
|
|
1475
|
+
* Runs AFTER the write's transaction settles and ALWAYS runs when the paired
|
|
1476
|
+
* `beforeTransaction` ran (symmetric bracket). The `status` discriminant tells
|
|
1477
|
+
* the hook whether the write committed or rolled back:
|
|
1478
|
+
* - `committed`: the persisted `item`/`originalItem` are populated ONLY for the
|
|
1479
|
+
* TOP-LEVEL record of the write. For NESTED lists they are `undefined` — the
|
|
1480
|
+
* per-record persisted row is not reliably recoverable outside the
|
|
1481
|
+
* transaction (recovering it would duplicate #569's in-transaction id-diff
|
|
1482
|
+
* machinery), and these hooks fire at per-(list, operation) granularity, not
|
|
1483
|
+
* per record. For per-record nested compensation use the in-transaction
|
|
1484
|
+
* `afterOperation` (which receives the correct nested `item`);
|
|
1485
|
+
* transaction-boundary hooks are for external-call compensation keyed off
|
|
1486
|
+
* `status`/`inputData`.
|
|
1487
|
+
* - `rolled-back`: NO persisted `item`; the hook gets `inputData` and the
|
|
1488
|
+
* `error` that caused the rollback so it can compensate.
|
|
1489
|
+
*/
|
|
1490
|
+
export type AfterTransactionHookArgs<
|
|
1491
|
+
TOutput = Record<string, unknown>,
|
|
1492
|
+
TCreateInput = Record<string, unknown>,
|
|
1493
|
+
TUpdateInput = Record<string, unknown>,
|
|
1494
|
+
> =
|
|
1495
|
+
| {
|
|
1496
|
+
listKey: string
|
|
1497
|
+
operation: 'create'
|
|
1498
|
+
status: 'committed'
|
|
1499
|
+
inputData: TCreateInput
|
|
1500
|
+
/** Persisted row — populated for the top-level list only; `undefined` for nested lists. */
|
|
1501
|
+
item: TOutput | undefined
|
|
1502
|
+
context: import('../access/types.js').AccessContext
|
|
1503
|
+
}
|
|
1504
|
+
| {
|
|
1505
|
+
listKey: string
|
|
1506
|
+
operation: 'create'
|
|
1507
|
+
status: 'rolled-back'
|
|
1508
|
+
inputData: TCreateInput
|
|
1509
|
+
error: unknown
|
|
1510
|
+
context: import('../access/types.js').AccessContext
|
|
1511
|
+
}
|
|
1512
|
+
| {
|
|
1513
|
+
listKey: string
|
|
1514
|
+
operation: 'update'
|
|
1515
|
+
status: 'committed'
|
|
1516
|
+
inputData: TUpdateInput
|
|
1517
|
+
/** Pre-write row — populated for the top-level list only; `undefined` for nested lists. */
|
|
1518
|
+
originalItem: TOutput | undefined
|
|
1519
|
+
/** Persisted row — populated for the top-level list only; `undefined` for nested lists. */
|
|
1520
|
+
item: TOutput | undefined
|
|
1521
|
+
context: import('../access/types.js').AccessContext
|
|
1522
|
+
}
|
|
1523
|
+
| {
|
|
1524
|
+
listKey: string
|
|
1525
|
+
operation: 'update'
|
|
1526
|
+
status: 'rolled-back'
|
|
1527
|
+
inputData: TUpdateInput
|
|
1528
|
+
originalItem: TOutput | undefined
|
|
1529
|
+
error: unknown
|
|
1530
|
+
context: import('../access/types.js').AccessContext
|
|
1531
|
+
}
|
|
1532
|
+
| {
|
|
1533
|
+
listKey: string
|
|
1534
|
+
operation: 'delete'
|
|
1535
|
+
status: 'committed'
|
|
1536
|
+
/** Pre-write row — populated for the top-level list only; `undefined` for nested lists. */
|
|
1537
|
+
originalItem: TOutput | undefined
|
|
1538
|
+
context: import('../access/types.js').AccessContext
|
|
1539
|
+
}
|
|
1540
|
+
| {
|
|
1541
|
+
listKey: string
|
|
1542
|
+
operation: 'delete'
|
|
1543
|
+
status: 'rolled-back'
|
|
1544
|
+
originalItem: TOutput | undefined
|
|
1545
|
+
error: unknown
|
|
1546
|
+
context: import('../access/types.js').AccessContext
|
|
1547
|
+
}
|
|
1548
|
+
|
|
1272
1549
|
export type Hooks<
|
|
1273
1550
|
TOutput = Record<string, unknown>,
|
|
1274
1551
|
TCreateInput = Record<string, unknown>,
|
|
@@ -1284,6 +1561,26 @@ export type Hooks<
|
|
|
1284
1561
|
afterOperation?: (
|
|
1285
1562
|
args: AfterOperationHookArgs<TOutput, TCreateInput, TUpdateInput>,
|
|
1286
1563
|
) => Promise<void>
|
|
1564
|
+
/**
|
|
1565
|
+
* Side effect BEFORE the write's transaction opens (#590 / ADR-0010).
|
|
1566
|
+
* Runs OUTSIDE the transaction — for non-transactional work (external API
|
|
1567
|
+
* calls). Throwing aborts the write; the paired `afterTransaction` then fires
|
|
1568
|
+
* with `status: 'rolled-back'`. See {@link BeforeTransactionHookArgs}.
|
|
1569
|
+
*/
|
|
1570
|
+
beforeTransaction?: (
|
|
1571
|
+
args: BeforeTransactionHookArgs<TOutput, TCreateInput, TUpdateInput>,
|
|
1572
|
+
) => Promise<void> | void
|
|
1573
|
+
/**
|
|
1574
|
+
* Side effect AFTER the write's transaction settles (#590 / ADR-0010).
|
|
1575
|
+
* ALWAYS runs when `beforeTransaction` ran; receives `committed | rolled-back`
|
|
1576
|
+
* + `error`. The persisted `item`/`originalItem` are present only on commit
|
|
1577
|
+
* AND only for the top-level record (`undefined` for nested lists). The
|
|
1578
|
+
* compensation half of the transaction-boundary bracket. See
|
|
1579
|
+
* {@link AfterTransactionHookArgs}.
|
|
1580
|
+
*/
|
|
1581
|
+
afterTransaction?: (
|
|
1582
|
+
args: AfterTransactionHookArgs<TOutput, TCreateInput, TUpdateInput>,
|
|
1583
|
+
) => Promise<void> | void
|
|
1287
1584
|
/**
|
|
1288
1585
|
* @deprecated Use 'validate' instead. This alias is provided for backwards compatibility.
|
|
1289
1586
|
*/
|
|
@@ -1402,6 +1699,68 @@ export type ListConfig<TTypeInfo extends TypeInfo> = {
|
|
|
1402
1699
|
*/
|
|
1403
1700
|
autoCreate?: boolean
|
|
1404
1701
|
}
|
|
1702
|
+
/**
|
|
1703
|
+
* UI configuration for this list (admin interface).
|
|
1704
|
+
*
|
|
1705
|
+
* Mirrors Keystone's list-level `ui` block. Currently only `listView`
|
|
1706
|
+
* defaults (columns + sort) are supported.
|
|
1707
|
+
*/
|
|
1708
|
+
ui?: ListUIConfig
|
|
1709
|
+
}
|
|
1710
|
+
|
|
1711
|
+
/**
|
|
1712
|
+
* List-level UI configuration for the admin interface.
|
|
1713
|
+
*
|
|
1714
|
+
* Mirrors Keystone's `ui` block on a list. Only the list-view defaults
|
|
1715
|
+
* (column selection/order and default sort) are supported today; other
|
|
1716
|
+
* Keystone concerns (`label`, `labelField`, `description`) are intentionally
|
|
1717
|
+
* deferred as they cover different concerns (navigation text and
|
|
1718
|
+
* relationship-picker labels rather than list-view defaults).
|
|
1719
|
+
*/
|
|
1720
|
+
export type ListUIConfig = {
|
|
1721
|
+
/**
|
|
1722
|
+
* Default list-view (table) configuration for this list, mirroring
|
|
1723
|
+
* Keystone's `ui.listView`.
|
|
1724
|
+
*/
|
|
1725
|
+
listView?: ListViewUIConfig
|
|
1726
|
+
}
|
|
1727
|
+
|
|
1728
|
+
/**
|
|
1729
|
+
* Default list-view (table) configuration for a list, mirroring Keystone's
|
|
1730
|
+
* `ui.listView`.
|
|
1731
|
+
*
|
|
1732
|
+
* When omitted, the admin UI falls back to its existing defaults: every
|
|
1733
|
+
* non-system field is shown as a column and no default sort is applied.
|
|
1734
|
+
*/
|
|
1735
|
+
export type ListViewUIConfig = {
|
|
1736
|
+
/**
|
|
1737
|
+
* The fields to show as columns in the list table, in order.
|
|
1738
|
+
*
|
|
1739
|
+
* Drives both the column **selection** and their **order**. When omitted,
|
|
1740
|
+
* all non-system fields are shown (current default behaviour).
|
|
1741
|
+
*
|
|
1742
|
+
* @example
|
|
1743
|
+
* ```typescript
|
|
1744
|
+
* ui: { listView: { initialColumns: ['title', 'status', 'author'] } }
|
|
1745
|
+
* ```
|
|
1746
|
+
*/
|
|
1747
|
+
initialColumns?: string[]
|
|
1748
|
+
/**
|
|
1749
|
+
* The default sort applied to the list table.
|
|
1750
|
+
*
|
|
1751
|
+
* When omitted, no default sort is applied (current default behaviour).
|
|
1752
|
+
*
|
|
1753
|
+
* @example
|
|
1754
|
+
* ```typescript
|
|
1755
|
+
* ui: { listView: { initialSort: { field: 'createdAt', direction: 'desc' } } }
|
|
1756
|
+
* ```
|
|
1757
|
+
*/
|
|
1758
|
+
initialSort?: {
|
|
1759
|
+
/** The field to sort by. Must be a field defined on the list. */
|
|
1760
|
+
field: string
|
|
1761
|
+
/** The sort direction. */
|
|
1762
|
+
direction: 'asc' | 'desc'
|
|
1763
|
+
}
|
|
1405
1764
|
}
|
|
1406
1765
|
|
|
1407
1766
|
/**
|
|
@@ -1611,6 +1970,40 @@ export type DatabaseConfig = {
|
|
|
1611
1970
|
* ```
|
|
1612
1971
|
*/
|
|
1613
1972
|
extendPrismaSchema?: (schema: string) => string
|
|
1973
|
+
/**
|
|
1974
|
+
* Override the Prisma `generator client { ... }` options the CLI emits for the
|
|
1975
|
+
* `.opensaas` prisma-client subtree.
|
|
1976
|
+
*
|
|
1977
|
+
* By default the generator emits `importFileExtension = "ts"` and
|
|
1978
|
+
* `moduleFormat = "esm"` so the whole generated bundle is statically
|
|
1979
|
+
* resolvable and matches the explicit `.ts` import-extension style the rest of
|
|
1980
|
+
* the `.opensaas` bundle uses (see ADR-0008). Supply this option only when you
|
|
1981
|
+
* need a different module/extension story (e.g. emitting `.js` extensions for a
|
|
1982
|
+
* Node-only consumer). Any value you provide wins; omitted keys fall back to
|
|
1983
|
+
* the `ts`/`esm` defaults.
|
|
1984
|
+
*
|
|
1985
|
+
* @example Emit `.js` extensions and CommonJS for a plain-Node consumer
|
|
1986
|
+
* ```typescript
|
|
1987
|
+
* db: {
|
|
1988
|
+
* provider: 'postgresql',
|
|
1989
|
+
* prismaGeneratorOptions: {
|
|
1990
|
+
* importFileExtension: 'js',
|
|
1991
|
+
* moduleFormat: 'commonjs',
|
|
1992
|
+
* },
|
|
1993
|
+
* // ... rest of config
|
|
1994
|
+
* }
|
|
1995
|
+
* ```
|
|
1996
|
+
*/
|
|
1997
|
+
prismaGeneratorOptions?: {
|
|
1998
|
+
/**
|
|
1999
|
+
* Value for the generator's `importFileExtension` option. Defaults to `'ts'`.
|
|
2000
|
+
*/
|
|
2001
|
+
importFileExtension?: 'ts' | 'js'
|
|
2002
|
+
/**
|
|
2003
|
+
* Value for the generator's `moduleFormat` option. Defaults to `'esm'`.
|
|
2004
|
+
*/
|
|
2005
|
+
moduleFormat?: 'esm' | 'commonjs'
|
|
2006
|
+
}
|
|
1614
2007
|
}
|
|
1615
2008
|
|
|
1616
2009
|
/**
|
|
@@ -2096,6 +2489,39 @@ export interface OutputConfig {
|
|
|
2096
2489
|
* @default ".opensaas"
|
|
2097
2490
|
*/
|
|
2098
2491
|
opensaasDir?: string
|
|
2492
|
+
/**
|
|
2493
|
+
* Opt in to an additional **Node build** of the Generated bundle.
|
|
2494
|
+
*
|
|
2495
|
+
* By default (omitted) the generator emits only the bundler-loadable `.ts`
|
|
2496
|
+
* form (ADR-0008): TypeScript with explicit `.ts` import extensions, traced
|
|
2497
|
+
* and transpiled by the host's bundler. That form cannot execute under plain
|
|
2498
|
+
* Node, so a live module that must run in BOTH a bundled and a bundler-less
|
|
2499
|
+
* runtime (e.g. better-auth's Prisma adapter, imported by the Next server AND
|
|
2500
|
+
* by a Playwright e2e helper or a build-time script) has no Node-loadable
|
|
2501
|
+
* entry to point at.
|
|
2502
|
+
*
|
|
2503
|
+
* Setting `buildTarget: 'node'` additionally compiles the bundle to a
|
|
2504
|
+
* plain-Node-loadable ESM form under `<opensaasDir>/dist/` (`.js` + `.d.ts`,
|
|
2505
|
+
* with a `{"type":"module"}` marker). The compiled entry is
|
|
2506
|
+
* `<opensaasDir>/dist/context.js`; a portable module imports it directly so
|
|
2507
|
+
* the bundler traces it AND plain Node executes it (one specifier, both
|
|
2508
|
+
* runtimes — see ADR-0011). The default `.ts` form is unchanged and still
|
|
2509
|
+
* emitted; the Node build is purely additive.
|
|
2510
|
+
*
|
|
2511
|
+
* `'node'` is the only target today. The field is a string-literal union so
|
|
2512
|
+
* future compiled targets can be added without a breaking change.
|
|
2513
|
+
*
|
|
2514
|
+
* @example
|
|
2515
|
+
* ```typescript
|
|
2516
|
+
* export default config({
|
|
2517
|
+
* output: { buildTarget: 'node' },
|
|
2518
|
+
* // ...
|
|
2519
|
+
* })
|
|
2520
|
+
* // Then import the compiled entry from a plain-Node consumer:
|
|
2521
|
+
* // const { rawOpensaasContext } = await import('./.opensaas/dist/context.js')
|
|
2522
|
+
* ```
|
|
2523
|
+
*/
|
|
2524
|
+
buildTarget?: 'node'
|
|
2099
2525
|
}
|
|
2100
2526
|
|
|
2101
2527
|
export interface OpenSaasConfig {
|