@objectstack/objectql 7.8.0 → 8.0.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/dist/index.d.mts CHANGED
@@ -5,6 +5,7 @@ import { MetadataRepository, MetaRef, MetadataItem, PutOptions, PutResult, Delet
5
5
  import { ObjectStackProtocol, MetadataCacheRequest, MetadataCacheResponse, BatchUpdateRequest, BatchUpdateResponse, UpdateManyDataRequest, DeleteManyDataRequest, InstallPackageRequest, InstallPackageResponse } from '@objectstack/spec/api';
6
6
  import { IDataEngine, DriverInterface, Logger, Plugin, PluginContext, ObjectKernel } from '@objectstack/core';
7
7
  import { IFeedService, IRealtimeService, ICryptoProvider } from '@objectstack/spec/contracts';
8
+ import { Expression } from '@objectstack/spec';
8
9
 
9
10
  /**
10
11
  * Reserved namespaces that do not get FQN prefix applied.
@@ -525,7 +526,18 @@ declare class ObjectStackProtocolImplementation implements ObjectStackProtocol {
525
526
  } | undefined;
526
527
  shortcut?: string | undefined;
527
528
  bulkEnabled?: boolean | undefined;
528
- aiExposed?: boolean | undefined;
529
+ ai?: {
530
+ exposed: boolean;
531
+ description?: string | undefined;
532
+ category?: "data" | "flow" | "analytics" | "action" | "integration" | "vector_search" | "utility" | undefined;
533
+ paramHints?: Record<string, {
534
+ description?: string | undefined;
535
+ enum?: (string | number)[] | undefined;
536
+ examples?: unknown[] | undefined;
537
+ }> | undefined;
538
+ outputSchema?: Record<string, unknown> | undefined;
539
+ requiresConfirmation?: boolean | undefined;
540
+ } | undefined;
529
541
  recordIdParam?: string | undefined;
530
542
  recordIdField?: string | undefined;
531
543
  bodyShape?: "flat" | {
@@ -627,6 +639,17 @@ declare class ObjectStackProtocolImplementation implements ObjectStackProtocol {
627
639
  } | undefined;
628
640
  } | undefined;
629
641
  }[] | undefined;
642
+ subforms?: {
643
+ childObject: string;
644
+ relationshipField?: string | undefined;
645
+ columns?: any[] | undefined;
646
+ amountField?: string | undefined;
647
+ totalField?: string | undefined;
648
+ title?: string | undefined;
649
+ addLabel?: string | undefined;
650
+ minRows?: number | undefined;
651
+ maxRows?: number | undefined;
652
+ }[] | undefined;
630
653
  defaultSort?: {
631
654
  field: string;
632
655
  order: "asc" | "desc";
@@ -665,7 +688,7 @@ declare class ObjectStackProtocolImplementation implements ObjectStackProtocol {
665
688
  supportsVersioning: boolean;
666
689
  executionPinned: boolean;
667
690
  loadOrder: number;
668
- domain: "system" | "data" | "ui" | "automation" | "ai" | "security";
691
+ domain: "system" | "data" | "ai" | "ui" | "automation" | "security";
669
692
  description?: string | undefined;
670
693
  }[];
671
694
  }>;
@@ -719,6 +742,7 @@ declare class ObjectStackProtocolImplementation implements ObjectStackProtocol {
719
742
  type: string;
720
743
  packageId?: string;
721
744
  organizationId?: string;
745
+ previewDrafts?: boolean;
722
746
  }): Promise<{
723
747
  type: string;
724
748
  items: any[];
@@ -729,10 +753,11 @@ declare class ObjectStackProtocolImplementation implements ObjectStackProtocol {
729
753
  packageId?: string;
730
754
  organizationId?: string;
731
755
  state?: 'active' | 'draft';
756
+ previewDrafts?: boolean;
732
757
  }): Promise<{
733
758
  type: string;
734
759
  name: string;
735
- item: {} | null;
760
+ item: any;
736
761
  } | {
737
762
  editable: boolean;
738
763
  deletable: boolean;
@@ -1155,6 +1180,23 @@ declare class ObjectStackProtocolImplementation implements ObjectStackProtocol {
1155
1180
  * simply no-op, and a sync failure must not abort the publish.
1156
1181
  */
1157
1182
  private ensureObjectStorage;
1183
+ /**
1184
+ * Inverse of {@link ensureObjectStorage}: drop an object's physical table.
1185
+ * DESTRUCTIVE — deletes the table and all its rows. Only invoked when a
1186
+ * delete explicitly opts into storage teardown (see {@link deleteMetaItem}'s
1187
+ * `dropStorage`), so publishing an object solely to preview it can be undone
1188
+ * without leaving an orphan table. Best-effort: a failure is logged, not
1189
+ * thrown — the metadata delete already succeeded, and a stray table is
1190
+ * reclaimed by the next sync/drop rather than blocking the delete.
1191
+ */
1192
+ private dropObjectStorage;
1193
+ /**
1194
+ * Guard for storage teardown on delete. Drops a physical table only when
1195
+ * the caller opted in AND it is safe: object types only (others have no
1196
+ * table), active state only (drafts were never materialised), and never a
1197
+ * `sys_`-prefixed platform table.
1198
+ */
1199
+ private shouldDropStorage;
1158
1200
  saveMetaItem(request: {
1159
1201
  type: string;
1160
1202
  name: string;
@@ -1263,6 +1305,69 @@ declare class ObjectStackProtocolImplementation implements ObjectStackProtocol {
1263
1305
  code?: string;
1264
1306
  }>;
1265
1307
  }>;
1308
+ /**
1309
+ * Discard every pending DRAFT bound to a package — the NON-destructive
1310
+ * inverse of {@link publishPackageDrafts}. Drops only `state='draft'` rows
1311
+ * (via the per-item delete primitive), reverting the package to its last
1312
+ * published baseline; active/published metadata and physical tables are
1313
+ * left untouched.
1314
+ *
1315
+ * Use case: "I edited this app for a while and it turned out worse than
1316
+ * before — abandon all my changes." Routes through the sys_metadata path
1317
+ * (no metadata-service dependency, unlike `POST /packages/:id/revert`).
1318
+ */
1319
+ discardPackageDrafts(request: {
1320
+ packageId: string;
1321
+ organizationId?: string;
1322
+ actor?: string;
1323
+ }): Promise<{
1324
+ success: boolean;
1325
+ discardedCount: number;
1326
+ failedCount: number;
1327
+ discarded: Array<{
1328
+ type: string;
1329
+ name: string;
1330
+ }>;
1331
+ failed: Array<{
1332
+ type: string;
1333
+ name: string;
1334
+ error: string;
1335
+ code?: string;
1336
+ }>;
1337
+ }>;
1338
+ /**
1339
+ * Delete an ENTIRE package: every `sys_metadata` row bound to it (active
1340
+ * AND draft) and — by default — the physical table of each object it
1341
+ * defined. DESTRUCTIVE: removes the app and its data. Use case: "I don't
1342
+ * want this package anymore."
1343
+ *
1344
+ * Set `keepData: true` to remove the metadata but preserve object tables.
1345
+ * The `sys_`-table guard in {@link deleteMetaItem} still applies, so
1346
+ * platform storage is never dropped. Drafts are removed before active rows
1347
+ * so each object's table is torn down once. Per-item failures are collected
1348
+ * without aborting the rest.
1349
+ */
1350
+ deletePackage(request: {
1351
+ packageId: string;
1352
+ organizationId?: string;
1353
+ actor?: string;
1354
+ keepData?: boolean;
1355
+ }): Promise<{
1356
+ success: boolean;
1357
+ deletedCount: number;
1358
+ failedCount: number;
1359
+ deleted: Array<{
1360
+ type: string;
1361
+ name: string;
1362
+ state: string;
1363
+ }>;
1364
+ failed: Array<{
1365
+ type: string;
1366
+ name: string;
1367
+ error: string;
1368
+ code?: string;
1369
+ }>;
1370
+ }>;
1266
1371
  /**
1267
1372
  * Restore the body recorded at history `toVersion` as the new
1268
1373
  * live row. Writes a history event with `op='revert'`. 404
@@ -1331,6 +1436,13 @@ declare class ObjectStackProtocolImplementation implements ObjectStackProtocol {
1331
1436
  parentVersion?: string | null;
1332
1437
  actor?: string;
1333
1438
  state?: 'active' | 'draft';
1439
+ /**
1440
+ * When true, also drop the object's physical table after the metadata
1441
+ * is removed (object + active only; never `sys_`). Default false keeps
1442
+ * delete non-destructive to data. Used by the "discard a previewed
1443
+ * object" flow so a publish-to-preview leaves no orphan table.
1444
+ */
1445
+ dropStorage?: boolean;
1334
1446
  }): Promise<{
1335
1447
  success: boolean;
1336
1448
  message?: string;
@@ -1690,15 +1802,16 @@ interface ObjectQLHostContext {
1690
1802
  logger: Logger;
1691
1803
  [key: string]: any;
1692
1804
  }
1693
- /**
1694
- * ObjectQL Engine
1695
- *
1696
- * Implements the IDataEngine interface for data persistence.
1697
- * Acts as the reference implementation for:
1698
- * - CoreServiceName.data (CRUD)
1699
- * - CoreServiceName.metadata (Schema Registry)
1700
- */
1701
1805
  declare class ObjectQL implements IDataEngine {
1806
+ /**
1807
+ * Ambient transaction store (ADR-0034). While a `transaction()` callback
1808
+ * runs, the active transaction handle lives here so that EVERY data
1809
+ * operation — including internal reads done during a write (reference
1810
+ * checks, hooks, expand) — automatically binds to the same connection
1811
+ * instead of asking the pool for another one and deadlocking on the
1812
+ * single-connection SQLite pool.
1813
+ */
1814
+ private readonly txStore;
1702
1815
  private drivers;
1703
1816
  private defaultDriver;
1704
1817
  private logger;
@@ -1876,6 +1989,26 @@ declare class ObjectQL implements IDataEngine {
1876
1989
  * declarative `defaultValue: cel\`today()\``.
1877
1990
  */
1878
1991
  private applyFieldDefaults;
1992
+ /**
1993
+ * Generate values for empty `autonumber` fields on insert — ONLY for drivers
1994
+ * that do not generate them natively (memory, mongodb). For SQL-backed objects
1995
+ * the driver owns a persistent, atomic `_objectstack_sequences` table and
1996
+ * advertises `supports.autonumber === true`; the engine then defers entirely
1997
+ * and never pre-fills (so the persistent sequence is the single source of
1998
+ * truth — see #1603). Required-validation exempts `autonumber` either way, so
1999
+ * a `required` record number is never rejected for "missing" — the runtime
2000
+ * owns the value, not the client.
2001
+ *
2002
+ * In the fallback path the next value is `max(existing) + 1`, seeded once per
2003
+ * `object.field` from the store then incremented in memory (monotonic within
2004
+ * the process, resilient to deletions). `autonumberFormat` is honored, e.g.
2005
+ * `CASE-{0000}` → `CASE-0042`. NOTE: this in-memory seeding is single-instance.
2006
+ */
2007
+ private applyAutonumbers;
2008
+ /** Seed the autonumber counter from the current max numeric value in store. */
2009
+ private seedAutonumber;
2010
+ /** Apply an autonumber format like `CASE-{0000}`; default to the bare number. */
2011
+ private formatAutonumber;
1879
2012
  /**
1880
2013
  * Register contribution (Manifest)
1881
2014
  *
@@ -2042,6 +2175,27 @@ declare class ObjectQL implements IDataEngine {
2042
2175
  destroy(): Promise<void>;
2043
2176
  /** Maximum depth for recursive expand to prevent infinite loops */
2044
2177
  private static readonly MAX_EXPAND_DEPTH;
2178
+ private static readonly MAX_CASCADE_DEPTH;
2179
+ /** In-memory next-value cache per `object.field` for autonumber generation,
2180
+ * lazily seeded from the current max in the store. */
2181
+ private readonly autonumberCounters;
2182
+ /** Lazily-built index: child object name → roll-up summary descriptors on
2183
+ * parent objects that aggregate it. Invalidated when packages register. */
2184
+ private summaryIndex;
2185
+ /** Invalidate the cached roll-up summary index (call when metadata changes). */
2186
+ private invalidateSummaryIndex;
2187
+ /** Scan all registered objects for `summary` fields and index them by the
2188
+ * child object they aggregate, resolving the child→parent FK field. */
2189
+ private buildSummaryIndex;
2190
+ private getSummaryDescriptors;
2191
+ /**
2192
+ * Recompute roll-up `summary` fields on parent records after a child write.
2193
+ * For each affected parent (the FK value on the changed/old child record), it
2194
+ * aggregates the child collection and writes the result onto the parent's
2195
+ * summary field. Runs in the caller's execution context so it joins the same
2196
+ * transaction (e.g. the cross-object batch) when one is open.
2197
+ */
2198
+ private recomputeSummaries;
2045
2199
  /**
2046
2200
  * Post-process expand: resolve lookup/master_detail fields by batch-loading related records.
2047
2201
  *
@@ -2059,6 +2213,19 @@ declare class ObjectQL implements IDataEngine {
2059
2213
  findOne(objectName: string, query?: EngineQueryOptions): Promise<any>;
2060
2214
  insert(object: string, data: any | any[], options?: DataEngineInsertOptions): Promise<any>;
2061
2215
  update(object: string, data: any, options?: EngineUpdateOptions): Promise<any>;
2216
+ /**
2217
+ * Apply referential delete behavior for relations pointing AT this record,
2218
+ * before it is removed. For every registered object with a `master_detail`
2219
+ * or `lookup` field referencing `object`, honor the field's `deleteBehavior`:
2220
+ * - `cascade` → delete the dependent rows (recursively, so grandchildren
2221
+ * are handled by each child's own delete),
2222
+ * - `set_null` → clear the foreign key,
2223
+ * - `restrict` → refuse the delete when dependents exist.
2224
+ * `master_detail` defaults to `cascade` (the parent owns the child
2225
+ * lifecycle); `lookup` defaults to `set_null`. Only runs for single-id
2226
+ * deletes — multi/predicate deletes skip cascade (logged).
2227
+ */
2228
+ private cascadeDeleteRelations;
2062
2229
  delete(object: string, options?: EngineDeleteOptions): Promise<any>;
2063
2230
  count(object: string, query?: EngineCountOptions): Promise<number>;
2064
2231
  aggregate(object: string, query: EngineAggregateOptions): Promise<any[]>;
@@ -2163,6 +2330,16 @@ declare class ObjectQL implements IDataEngine {
2163
2330
  * table when absent (and alters to add new columns).
2164
2331
  */
2165
2332
  syncObjectSchema(objectName: string): Promise<void>;
2333
+ /**
2334
+ * Drop the physical storage (table/collection) backing an object — the
2335
+ * inverse of {@link syncObjectSchema}. DESTRUCTIVE: deletes all rows in the
2336
+ * table. Used by the protocol delete path when the caller explicitly opts
2337
+ * into storage teardown (e.g. discarding an object that was published only
2338
+ * to preview it). No-op when the object's driver does not expose `dropTable`.
2339
+ * Resolves the physical table name from the registered definition, falling
2340
+ * back to the bare name if the def was already removed.
2341
+ */
2342
+ dropObjectSchema(objectName: string): Promise<void>;
2166
2343
  /**
2167
2344
  * Get a registered driver by datasource name.
2168
2345
  * Alias matching @objectql/core datasource() API.
@@ -2544,7 +2721,15 @@ interface EvaluateRulesOptions {
2544
2721
  */
2545
2722
  declare function needsPriorRecord(objectSchema: {
2546
2723
  validations?: unknown[];
2724
+ fields?: Record<string, ConditionalFieldDef>;
2547
2725
  } | undefined | null): boolean;
2726
+ /** Field-level conditional rules (B2): a field is required / read-only when its
2727
+ * CEL predicate is TRUE over the record. */
2728
+ interface ConditionalFieldDef {
2729
+ requiredWhen?: string | Expression;
2730
+ conditionalRequired?: string | Expression;
2731
+ readonlyWhen?: string | Expression;
2732
+ }
2548
2733
  /**
2549
2734
  * Evaluate an object's declared validation rules against an incoming write.
2550
2735
  *
@@ -2554,6 +2739,7 @@ declare function needsPriorRecord(objectSchema: {
2554
2739
  */
2555
2740
  declare function evaluateValidationRules(objectSchema: {
2556
2741
  validations?: unknown[];
2742
+ fields?: Record<string, ConditionalFieldDef>;
2557
2743
  } | undefined | null, data: Record<string, unknown> | undefined | null, mode: Mode, opts?: EvaluateRulesOptions): void;
2558
2744
  /**
2559
2745
  * Introspection helper (ADR-0020 D3.3): given an object's schema, a state
package/dist/index.d.ts CHANGED
@@ -5,6 +5,7 @@ import { MetadataRepository, MetaRef, MetadataItem, PutOptions, PutResult, Delet
5
5
  import { ObjectStackProtocol, MetadataCacheRequest, MetadataCacheResponse, BatchUpdateRequest, BatchUpdateResponse, UpdateManyDataRequest, DeleteManyDataRequest, InstallPackageRequest, InstallPackageResponse } from '@objectstack/spec/api';
6
6
  import { IDataEngine, DriverInterface, Logger, Plugin, PluginContext, ObjectKernel } from '@objectstack/core';
7
7
  import { IFeedService, IRealtimeService, ICryptoProvider } from '@objectstack/spec/contracts';
8
+ import { Expression } from '@objectstack/spec';
8
9
 
9
10
  /**
10
11
  * Reserved namespaces that do not get FQN prefix applied.
@@ -525,7 +526,18 @@ declare class ObjectStackProtocolImplementation implements ObjectStackProtocol {
525
526
  } | undefined;
526
527
  shortcut?: string | undefined;
527
528
  bulkEnabled?: boolean | undefined;
528
- aiExposed?: boolean | undefined;
529
+ ai?: {
530
+ exposed: boolean;
531
+ description?: string | undefined;
532
+ category?: "data" | "flow" | "analytics" | "action" | "integration" | "vector_search" | "utility" | undefined;
533
+ paramHints?: Record<string, {
534
+ description?: string | undefined;
535
+ enum?: (string | number)[] | undefined;
536
+ examples?: unknown[] | undefined;
537
+ }> | undefined;
538
+ outputSchema?: Record<string, unknown> | undefined;
539
+ requiresConfirmation?: boolean | undefined;
540
+ } | undefined;
529
541
  recordIdParam?: string | undefined;
530
542
  recordIdField?: string | undefined;
531
543
  bodyShape?: "flat" | {
@@ -627,6 +639,17 @@ declare class ObjectStackProtocolImplementation implements ObjectStackProtocol {
627
639
  } | undefined;
628
640
  } | undefined;
629
641
  }[] | undefined;
642
+ subforms?: {
643
+ childObject: string;
644
+ relationshipField?: string | undefined;
645
+ columns?: any[] | undefined;
646
+ amountField?: string | undefined;
647
+ totalField?: string | undefined;
648
+ title?: string | undefined;
649
+ addLabel?: string | undefined;
650
+ minRows?: number | undefined;
651
+ maxRows?: number | undefined;
652
+ }[] | undefined;
630
653
  defaultSort?: {
631
654
  field: string;
632
655
  order: "asc" | "desc";
@@ -665,7 +688,7 @@ declare class ObjectStackProtocolImplementation implements ObjectStackProtocol {
665
688
  supportsVersioning: boolean;
666
689
  executionPinned: boolean;
667
690
  loadOrder: number;
668
- domain: "system" | "data" | "ui" | "automation" | "ai" | "security";
691
+ domain: "system" | "data" | "ai" | "ui" | "automation" | "security";
669
692
  description?: string | undefined;
670
693
  }[];
671
694
  }>;
@@ -719,6 +742,7 @@ declare class ObjectStackProtocolImplementation implements ObjectStackProtocol {
719
742
  type: string;
720
743
  packageId?: string;
721
744
  organizationId?: string;
745
+ previewDrafts?: boolean;
722
746
  }): Promise<{
723
747
  type: string;
724
748
  items: any[];
@@ -729,10 +753,11 @@ declare class ObjectStackProtocolImplementation implements ObjectStackProtocol {
729
753
  packageId?: string;
730
754
  organizationId?: string;
731
755
  state?: 'active' | 'draft';
756
+ previewDrafts?: boolean;
732
757
  }): Promise<{
733
758
  type: string;
734
759
  name: string;
735
- item: {} | null;
760
+ item: any;
736
761
  } | {
737
762
  editable: boolean;
738
763
  deletable: boolean;
@@ -1155,6 +1180,23 @@ declare class ObjectStackProtocolImplementation implements ObjectStackProtocol {
1155
1180
  * simply no-op, and a sync failure must not abort the publish.
1156
1181
  */
1157
1182
  private ensureObjectStorage;
1183
+ /**
1184
+ * Inverse of {@link ensureObjectStorage}: drop an object's physical table.
1185
+ * DESTRUCTIVE — deletes the table and all its rows. Only invoked when a
1186
+ * delete explicitly opts into storage teardown (see {@link deleteMetaItem}'s
1187
+ * `dropStorage`), so publishing an object solely to preview it can be undone
1188
+ * without leaving an orphan table. Best-effort: a failure is logged, not
1189
+ * thrown — the metadata delete already succeeded, and a stray table is
1190
+ * reclaimed by the next sync/drop rather than blocking the delete.
1191
+ */
1192
+ private dropObjectStorage;
1193
+ /**
1194
+ * Guard for storage teardown on delete. Drops a physical table only when
1195
+ * the caller opted in AND it is safe: object types only (others have no
1196
+ * table), active state only (drafts were never materialised), and never a
1197
+ * `sys_`-prefixed platform table.
1198
+ */
1199
+ private shouldDropStorage;
1158
1200
  saveMetaItem(request: {
1159
1201
  type: string;
1160
1202
  name: string;
@@ -1263,6 +1305,69 @@ declare class ObjectStackProtocolImplementation implements ObjectStackProtocol {
1263
1305
  code?: string;
1264
1306
  }>;
1265
1307
  }>;
1308
+ /**
1309
+ * Discard every pending DRAFT bound to a package — the NON-destructive
1310
+ * inverse of {@link publishPackageDrafts}. Drops only `state='draft'` rows
1311
+ * (via the per-item delete primitive), reverting the package to its last
1312
+ * published baseline; active/published metadata and physical tables are
1313
+ * left untouched.
1314
+ *
1315
+ * Use case: "I edited this app for a while and it turned out worse than
1316
+ * before — abandon all my changes." Routes through the sys_metadata path
1317
+ * (no metadata-service dependency, unlike `POST /packages/:id/revert`).
1318
+ */
1319
+ discardPackageDrafts(request: {
1320
+ packageId: string;
1321
+ organizationId?: string;
1322
+ actor?: string;
1323
+ }): Promise<{
1324
+ success: boolean;
1325
+ discardedCount: number;
1326
+ failedCount: number;
1327
+ discarded: Array<{
1328
+ type: string;
1329
+ name: string;
1330
+ }>;
1331
+ failed: Array<{
1332
+ type: string;
1333
+ name: string;
1334
+ error: string;
1335
+ code?: string;
1336
+ }>;
1337
+ }>;
1338
+ /**
1339
+ * Delete an ENTIRE package: every `sys_metadata` row bound to it (active
1340
+ * AND draft) and — by default — the physical table of each object it
1341
+ * defined. DESTRUCTIVE: removes the app and its data. Use case: "I don't
1342
+ * want this package anymore."
1343
+ *
1344
+ * Set `keepData: true` to remove the metadata but preserve object tables.
1345
+ * The `sys_`-table guard in {@link deleteMetaItem} still applies, so
1346
+ * platform storage is never dropped. Drafts are removed before active rows
1347
+ * so each object's table is torn down once. Per-item failures are collected
1348
+ * without aborting the rest.
1349
+ */
1350
+ deletePackage(request: {
1351
+ packageId: string;
1352
+ organizationId?: string;
1353
+ actor?: string;
1354
+ keepData?: boolean;
1355
+ }): Promise<{
1356
+ success: boolean;
1357
+ deletedCount: number;
1358
+ failedCount: number;
1359
+ deleted: Array<{
1360
+ type: string;
1361
+ name: string;
1362
+ state: string;
1363
+ }>;
1364
+ failed: Array<{
1365
+ type: string;
1366
+ name: string;
1367
+ error: string;
1368
+ code?: string;
1369
+ }>;
1370
+ }>;
1266
1371
  /**
1267
1372
  * Restore the body recorded at history `toVersion` as the new
1268
1373
  * live row. Writes a history event with `op='revert'`. 404
@@ -1331,6 +1436,13 @@ declare class ObjectStackProtocolImplementation implements ObjectStackProtocol {
1331
1436
  parentVersion?: string | null;
1332
1437
  actor?: string;
1333
1438
  state?: 'active' | 'draft';
1439
+ /**
1440
+ * When true, also drop the object's physical table after the metadata
1441
+ * is removed (object + active only; never `sys_`). Default false keeps
1442
+ * delete non-destructive to data. Used by the "discard a previewed
1443
+ * object" flow so a publish-to-preview leaves no orphan table.
1444
+ */
1445
+ dropStorage?: boolean;
1334
1446
  }): Promise<{
1335
1447
  success: boolean;
1336
1448
  message?: string;
@@ -1690,15 +1802,16 @@ interface ObjectQLHostContext {
1690
1802
  logger: Logger;
1691
1803
  [key: string]: any;
1692
1804
  }
1693
- /**
1694
- * ObjectQL Engine
1695
- *
1696
- * Implements the IDataEngine interface for data persistence.
1697
- * Acts as the reference implementation for:
1698
- * - CoreServiceName.data (CRUD)
1699
- * - CoreServiceName.metadata (Schema Registry)
1700
- */
1701
1805
  declare class ObjectQL implements IDataEngine {
1806
+ /**
1807
+ * Ambient transaction store (ADR-0034). While a `transaction()` callback
1808
+ * runs, the active transaction handle lives here so that EVERY data
1809
+ * operation — including internal reads done during a write (reference
1810
+ * checks, hooks, expand) — automatically binds to the same connection
1811
+ * instead of asking the pool for another one and deadlocking on the
1812
+ * single-connection SQLite pool.
1813
+ */
1814
+ private readonly txStore;
1702
1815
  private drivers;
1703
1816
  private defaultDriver;
1704
1817
  private logger;
@@ -1876,6 +1989,26 @@ declare class ObjectQL implements IDataEngine {
1876
1989
  * declarative `defaultValue: cel\`today()\``.
1877
1990
  */
1878
1991
  private applyFieldDefaults;
1992
+ /**
1993
+ * Generate values for empty `autonumber` fields on insert — ONLY for drivers
1994
+ * that do not generate them natively (memory, mongodb). For SQL-backed objects
1995
+ * the driver owns a persistent, atomic `_objectstack_sequences` table and
1996
+ * advertises `supports.autonumber === true`; the engine then defers entirely
1997
+ * and never pre-fills (so the persistent sequence is the single source of
1998
+ * truth — see #1603). Required-validation exempts `autonumber` either way, so
1999
+ * a `required` record number is never rejected for "missing" — the runtime
2000
+ * owns the value, not the client.
2001
+ *
2002
+ * In the fallback path the next value is `max(existing) + 1`, seeded once per
2003
+ * `object.field` from the store then incremented in memory (monotonic within
2004
+ * the process, resilient to deletions). `autonumberFormat` is honored, e.g.
2005
+ * `CASE-{0000}` → `CASE-0042`. NOTE: this in-memory seeding is single-instance.
2006
+ */
2007
+ private applyAutonumbers;
2008
+ /** Seed the autonumber counter from the current max numeric value in store. */
2009
+ private seedAutonumber;
2010
+ /** Apply an autonumber format like `CASE-{0000}`; default to the bare number. */
2011
+ private formatAutonumber;
1879
2012
  /**
1880
2013
  * Register contribution (Manifest)
1881
2014
  *
@@ -2042,6 +2175,27 @@ declare class ObjectQL implements IDataEngine {
2042
2175
  destroy(): Promise<void>;
2043
2176
  /** Maximum depth for recursive expand to prevent infinite loops */
2044
2177
  private static readonly MAX_EXPAND_DEPTH;
2178
+ private static readonly MAX_CASCADE_DEPTH;
2179
+ /** In-memory next-value cache per `object.field` for autonumber generation,
2180
+ * lazily seeded from the current max in the store. */
2181
+ private readonly autonumberCounters;
2182
+ /** Lazily-built index: child object name → roll-up summary descriptors on
2183
+ * parent objects that aggregate it. Invalidated when packages register. */
2184
+ private summaryIndex;
2185
+ /** Invalidate the cached roll-up summary index (call when metadata changes). */
2186
+ private invalidateSummaryIndex;
2187
+ /** Scan all registered objects for `summary` fields and index them by the
2188
+ * child object they aggregate, resolving the child→parent FK field. */
2189
+ private buildSummaryIndex;
2190
+ private getSummaryDescriptors;
2191
+ /**
2192
+ * Recompute roll-up `summary` fields on parent records after a child write.
2193
+ * For each affected parent (the FK value on the changed/old child record), it
2194
+ * aggregates the child collection and writes the result onto the parent's
2195
+ * summary field. Runs in the caller's execution context so it joins the same
2196
+ * transaction (e.g. the cross-object batch) when one is open.
2197
+ */
2198
+ private recomputeSummaries;
2045
2199
  /**
2046
2200
  * Post-process expand: resolve lookup/master_detail fields by batch-loading related records.
2047
2201
  *
@@ -2059,6 +2213,19 @@ declare class ObjectQL implements IDataEngine {
2059
2213
  findOne(objectName: string, query?: EngineQueryOptions): Promise<any>;
2060
2214
  insert(object: string, data: any | any[], options?: DataEngineInsertOptions): Promise<any>;
2061
2215
  update(object: string, data: any, options?: EngineUpdateOptions): Promise<any>;
2216
+ /**
2217
+ * Apply referential delete behavior for relations pointing AT this record,
2218
+ * before it is removed. For every registered object with a `master_detail`
2219
+ * or `lookup` field referencing `object`, honor the field's `deleteBehavior`:
2220
+ * - `cascade` → delete the dependent rows (recursively, so grandchildren
2221
+ * are handled by each child's own delete),
2222
+ * - `set_null` → clear the foreign key,
2223
+ * - `restrict` → refuse the delete when dependents exist.
2224
+ * `master_detail` defaults to `cascade` (the parent owns the child
2225
+ * lifecycle); `lookup` defaults to `set_null`. Only runs for single-id
2226
+ * deletes — multi/predicate deletes skip cascade (logged).
2227
+ */
2228
+ private cascadeDeleteRelations;
2062
2229
  delete(object: string, options?: EngineDeleteOptions): Promise<any>;
2063
2230
  count(object: string, query?: EngineCountOptions): Promise<number>;
2064
2231
  aggregate(object: string, query: EngineAggregateOptions): Promise<any[]>;
@@ -2163,6 +2330,16 @@ declare class ObjectQL implements IDataEngine {
2163
2330
  * table when absent (and alters to add new columns).
2164
2331
  */
2165
2332
  syncObjectSchema(objectName: string): Promise<void>;
2333
+ /**
2334
+ * Drop the physical storage (table/collection) backing an object — the
2335
+ * inverse of {@link syncObjectSchema}. DESTRUCTIVE: deletes all rows in the
2336
+ * table. Used by the protocol delete path when the caller explicitly opts
2337
+ * into storage teardown (e.g. discarding an object that was published only
2338
+ * to preview it). No-op when the object's driver does not expose `dropTable`.
2339
+ * Resolves the physical table name from the registered definition, falling
2340
+ * back to the bare name if the def was already removed.
2341
+ */
2342
+ dropObjectSchema(objectName: string): Promise<void>;
2166
2343
  /**
2167
2344
  * Get a registered driver by datasource name.
2168
2345
  * Alias matching @objectql/core datasource() API.
@@ -2544,7 +2721,15 @@ interface EvaluateRulesOptions {
2544
2721
  */
2545
2722
  declare function needsPriorRecord(objectSchema: {
2546
2723
  validations?: unknown[];
2724
+ fields?: Record<string, ConditionalFieldDef>;
2547
2725
  } | undefined | null): boolean;
2726
+ /** Field-level conditional rules (B2): a field is required / read-only when its
2727
+ * CEL predicate is TRUE over the record. */
2728
+ interface ConditionalFieldDef {
2729
+ requiredWhen?: string | Expression;
2730
+ conditionalRequired?: string | Expression;
2731
+ readonlyWhen?: string | Expression;
2732
+ }
2548
2733
  /**
2549
2734
  * Evaluate an object's declared validation rules against an incoming write.
2550
2735
  *
@@ -2554,6 +2739,7 @@ declare function needsPriorRecord(objectSchema: {
2554
2739
  */
2555
2740
  declare function evaluateValidationRules(objectSchema: {
2556
2741
  validations?: unknown[];
2742
+ fields?: Record<string, ConditionalFieldDef>;
2557
2743
  } | undefined | null, data: Record<string, unknown> | undefined | null, mode: Mode, opts?: EvaluateRulesOptions): void;
2558
2744
  /**
2559
2745
  * Introspection helper (ADR-0020 D3.3): given an object's schema, a state