@objectstack/objectql 2.0.7 → 3.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.
@@ -1,5 +1,5 @@
1
1
 
2
- > @objectstack/objectql@2.0.7 build /home/runner/work/spec/spec/packages/objectql
2
+ > @objectstack/objectql@3.0.0 build /home/runner/work/spec/spec/packages/objectql
3
3
  > tsup --config ../../tsup.config.ts
4
4
 
5
5
  CLI Building entry: src/index.ts
@@ -10,13 +10,13 @@
10
10
  CLI Cleaning output folder
11
11
  ESM Build start
12
12
  CJS Build start
13
- CJS dist/index.js 73.19 KB
14
- CJS dist/index.js.map 146.61 KB
15
- CJS ⚡️ Build success in 118ms
16
- ESM dist/index.mjs 71.64 KB
17
- ESM dist/index.mjs.map 145.73 KB
18
- ESM ⚡️ Build success in 146ms
13
+ ESM dist/index.mjs 75.55 KB
14
+ ESM dist/index.mjs.map 152.89 KB
15
+ ESM ⚡️ Build success in 120ms
16
+ CJS dist/index.js 77.09 KB
17
+ CJS dist/index.js.map 153.77 KB
18
+ CJS ⚡️ Build success in 127ms
19
19
  DTS Build start
20
- DTS ⚡️ Build success in 13509ms
21
- DTS dist/index.d.mts 71.96 KB
22
- DTS dist/index.d.ts 71.96 KB
20
+ DTS ⚡️ Build success in 13686ms
21
+ DTS dist/index.d.mts 75.15 KB
22
+ DTS dist/index.d.ts 75.15 KB
package/CHANGELOG.md CHANGED
@@ -1,5 +1,18 @@
1
1
  # @objectstack/objectql
2
2
 
3
+ ## 3.0.0
4
+
5
+ ### Major Changes
6
+
7
+ - Release v3.0.0 — unified version bump for all ObjectStack packages.
8
+
9
+ ### Patch Changes
10
+
11
+ - Updated dependencies
12
+ - @objectstack/spec@3.0.0
13
+ - @objectstack/core@3.0.0
14
+ - @objectstack/types@3.0.0
15
+
3
16
  ## 2.0.7
4
17
 
5
18
  ### Patch Changes
package/dist/index.d.mts CHANGED
@@ -353,6 +353,8 @@ declare class SchemaRegistry {
353
353
  threshold: number;
354
354
  } | undefined;
355
355
  } | undefined;
356
+ group?: string | undefined;
357
+ conditionalRequired?: string | undefined;
356
358
  inlineHelpText?: string | undefined;
357
359
  trackFeedHistory?: boolean | undefined;
358
360
  caseSensitive?: boolean | undefined;
@@ -430,6 +432,12 @@ declare class SchemaRegistry {
430
432
  description?: string | undefined;
431
433
  }[]> | undefined;
432
434
  }> | undefined;
435
+ displayNameField?: string | undefined;
436
+ recordName?: {
437
+ type: "text" | "autonumber";
438
+ displayFormat?: string | undefined;
439
+ startNumber?: number | undefined;
440
+ } | undefined;
433
441
  titleFormat?: string | undefined;
434
442
  compactLayout?: string[] | undefined;
435
443
  search?: {
@@ -457,7 +465,7 @@ declare class SchemaRegistry {
457
465
  label: string | {
458
466
  key: string;
459
467
  defaultValue?: string | undefined;
460
- params?: Record<string, any> | undefined;
468
+ params?: Record<string, string | number | boolean> | undefined;
461
469
  };
462
470
  active: boolean;
463
471
  isDefault: boolean;
@@ -465,7 +473,7 @@ declare class SchemaRegistry {
465
473
  description?: string | {
466
474
  key: string;
467
475
  defaultValue?: string | undefined;
468
- params?: Record<string, any> | undefined;
476
+ params?: Record<string, string | number | boolean> | undefined;
469
477
  } | undefined;
470
478
  icon?: string | undefined;
471
479
  branding?: {
@@ -486,7 +494,7 @@ declare class SchemaRegistry {
486
494
  ariaLabel?: string | {
487
495
  key: string;
488
496
  defaultValue?: string | undefined;
489
- params?: Record<string, any> | undefined;
497
+ params?: Record<string, string | number | boolean> | undefined;
490
498
  } | undefined;
491
499
  ariaDescribedBy?: string | undefined;
492
500
  role?: string | undefined;
@@ -797,10 +805,12 @@ declare class SchemaRegistry {
797
805
  } | undefined;
798
806
  } | undefined;
799
807
  };
800
- status: "error" | "disabled" | "installed" | "installing" | "uninstalling";
808
+ status: "error" | "disabled" | "installed" | "installing" | "upgrading" | "uninstalling";
801
809
  enabled: boolean;
802
810
  installedAt?: string | undefined;
803
811
  updatedAt?: string | undefined;
812
+ installedVersion?: string | undefined;
813
+ previousVersion?: string | undefined;
804
814
  statusChangedAt?: string | undefined;
805
815
  errorMessage?: string | undefined;
806
816
  settings?: Record<string, unknown> | undefined;
@@ -1356,6 +1366,7 @@ declare class ObjectQL implements IDataEngine {
1356
1366
  private logger;
1357
1367
  private hooks;
1358
1368
  private middlewares;
1369
+ private actions;
1359
1370
  private hostContext;
1360
1371
  constructor(hostContext?: Record<string, any>);
1361
1372
  /**
@@ -1387,6 +1398,24 @@ declare class ObjectQL implements IDataEngine {
1387
1398
  priority?: number;
1388
1399
  }): void;
1389
1400
  triggerHooks(event: string, context: HookContext): Promise<void>;
1401
+ /**
1402
+ * Register a named action on an object.
1403
+ * Actions are custom business logic callable via `repo.execute(actionName, params)`.
1404
+ *
1405
+ * @param objectName Target object
1406
+ * @param actionName Unique action name within the object
1407
+ * @param handler Handler function
1408
+ * @param packageName Optional package owner (for cleanup)
1409
+ */
1410
+ registerAction(objectName: string, actionName: string, handler: (ctx: any) => Promise<any> | any, packageName?: string): void;
1411
+ /**
1412
+ * Execute a named action on an object.
1413
+ */
1414
+ executeAction(objectName: string, actionName: string, ctx: any): Promise<any>;
1415
+ /**
1416
+ * Remove all actions registered by a specific package.
1417
+ */
1418
+ removeActionsByPackage(packageName: string): void;
1390
1419
  /**
1391
1420
  * Register a middleware function
1392
1421
  * Middlewares execute in onion model around every data operation.
@@ -1590,6 +1619,8 @@ declare class ObjectQL implements IDataEngine {
1590
1619
  threshold: number;
1591
1620
  } | undefined;
1592
1621
  } | undefined;
1622
+ group?: string | undefined;
1623
+ conditionalRequired?: string | undefined;
1593
1624
  inlineHelpText?: string | undefined;
1594
1625
  trackFeedHistory?: boolean | undefined;
1595
1626
  caseSensitive?: boolean | undefined;
@@ -1667,6 +1698,12 @@ declare class ObjectQL implements IDataEngine {
1667
1698
  description?: string | undefined;
1668
1699
  }[]> | undefined;
1669
1700
  }> | undefined;
1701
+ displayNameField?: string | undefined;
1702
+ recordName?: {
1703
+ type: "text" | "autonumber";
1704
+ displayFormat?: string | undefined;
1705
+ startNumber?: number | undefined;
1706
+ } | undefined;
1670
1707
  titleFormat?: string | undefined;
1671
1708
  compactLayout?: string[] | undefined;
1672
1709
  search?: {
@@ -1731,21 +1768,41 @@ declare class ObjectQL implements IDataEngine {
1731
1768
  }
1732
1769
  /**
1733
1770
  * Repository scoped to a single object, bound to an execution context.
1771
+ *
1772
+ * Provides both IDataEngine-style methods (find, insert, update, delete)
1773
+ * and convenience aliases (create, updateById, deleteById) matching
1774
+ * the @objectql/core ObjectRepository API.
1734
1775
  */
1735
1776
  declare class ObjectRepository {
1736
1777
  private objectName;
1737
1778
  private context;
1738
1779
  private engine;
1739
- constructor(objectName: string, context: ExecutionContext, engine: IDataEngine);
1780
+ constructor(objectName: string, context: ExecutionContext, engine: IDataEngine & {
1781
+ executeAction?: (o: string, a: string, c: any) => Promise<any>;
1782
+ });
1740
1783
  find(query?: any): Promise<any[]>;
1741
1784
  findOne(query?: any): Promise<any>;
1742
1785
  insert(data: any): Promise<any>;
1786
+ /** Alias for insert() — matches @objectql/core convention */
1787
+ create(data: any): Promise<any>;
1743
1788
  update(data: any, options?: any): Promise<any>;
1789
+ /** Update a single record by ID */
1790
+ updateById(id: string | number, data: any): Promise<any>;
1744
1791
  delete(options?: any): Promise<any>;
1792
+ /** Delete a single record by ID */
1793
+ deleteById(id: string | number): Promise<any>;
1745
1794
  count(query?: any): Promise<number>;
1795
+ /** Aggregate query */
1796
+ aggregate(query?: any): Promise<any[]>;
1797
+ /** Execute a named action registered on this object */
1798
+ execute(actionName: string, params?: any): Promise<any>;
1746
1799
  }
1747
1800
  /**
1748
1801
  * Scoped execution context with object() accessor.
1802
+ *
1803
+ * Provides identity (userId, tenantId/spaceId, roles),
1804
+ * repository access via object(), privilege escalation via sudo(),
1805
+ * and transactional execution via transaction().
1749
1806
  */
1750
1807
  declare class ScopedContext {
1751
1808
  private executionContext;
@@ -1755,9 +1812,25 @@ declare class ScopedContext {
1755
1812
  object(name: string): ObjectRepository;
1756
1813
  /** Create an elevated (system) context */
1757
1814
  sudo(): ScopedContext;
1815
+ /**
1816
+ * Execute a callback within a database transaction.
1817
+ *
1818
+ * The callback receives a new ScopedContext whose operations
1819
+ * share the same transaction handle. If the callback throws,
1820
+ * the transaction is rolled back; otherwise it is committed.
1821
+ *
1822
+ * Falls back to non-transactional execution if the driver
1823
+ * does not support transactions.
1824
+ */
1825
+ transaction(callback: (trxCtx: ScopedContext) => Promise<any>): Promise<any>;
1758
1826
  get userId(): string | undefined;
1759
1827
  get tenantId(): string | undefined;
1828
+ /** Alias for tenantId — matches ObjectQLContext.spaceId convention */
1829
+ get spaceId(): string | undefined;
1760
1830
  get roles(): string[];
1831
+ get isSystem(): boolean;
1832
+ /** Internal: expose the transaction handle for driver-level access */
1833
+ get transactionHandle(): unknown;
1761
1834
  }
1762
1835
 
1763
1836
  /**
package/dist/index.d.ts CHANGED
@@ -353,6 +353,8 @@ declare class SchemaRegistry {
353
353
  threshold: number;
354
354
  } | undefined;
355
355
  } | undefined;
356
+ group?: string | undefined;
357
+ conditionalRequired?: string | undefined;
356
358
  inlineHelpText?: string | undefined;
357
359
  trackFeedHistory?: boolean | undefined;
358
360
  caseSensitive?: boolean | undefined;
@@ -430,6 +432,12 @@ declare class SchemaRegistry {
430
432
  description?: string | undefined;
431
433
  }[]> | undefined;
432
434
  }> | undefined;
435
+ displayNameField?: string | undefined;
436
+ recordName?: {
437
+ type: "text" | "autonumber";
438
+ displayFormat?: string | undefined;
439
+ startNumber?: number | undefined;
440
+ } | undefined;
433
441
  titleFormat?: string | undefined;
434
442
  compactLayout?: string[] | undefined;
435
443
  search?: {
@@ -457,7 +465,7 @@ declare class SchemaRegistry {
457
465
  label: string | {
458
466
  key: string;
459
467
  defaultValue?: string | undefined;
460
- params?: Record<string, any> | undefined;
468
+ params?: Record<string, string | number | boolean> | undefined;
461
469
  };
462
470
  active: boolean;
463
471
  isDefault: boolean;
@@ -465,7 +473,7 @@ declare class SchemaRegistry {
465
473
  description?: string | {
466
474
  key: string;
467
475
  defaultValue?: string | undefined;
468
- params?: Record<string, any> | undefined;
476
+ params?: Record<string, string | number | boolean> | undefined;
469
477
  } | undefined;
470
478
  icon?: string | undefined;
471
479
  branding?: {
@@ -486,7 +494,7 @@ declare class SchemaRegistry {
486
494
  ariaLabel?: string | {
487
495
  key: string;
488
496
  defaultValue?: string | undefined;
489
- params?: Record<string, any> | undefined;
497
+ params?: Record<string, string | number | boolean> | undefined;
490
498
  } | undefined;
491
499
  ariaDescribedBy?: string | undefined;
492
500
  role?: string | undefined;
@@ -797,10 +805,12 @@ declare class SchemaRegistry {
797
805
  } | undefined;
798
806
  } | undefined;
799
807
  };
800
- status: "error" | "disabled" | "installed" | "installing" | "uninstalling";
808
+ status: "error" | "disabled" | "installed" | "installing" | "upgrading" | "uninstalling";
801
809
  enabled: boolean;
802
810
  installedAt?: string | undefined;
803
811
  updatedAt?: string | undefined;
812
+ installedVersion?: string | undefined;
813
+ previousVersion?: string | undefined;
804
814
  statusChangedAt?: string | undefined;
805
815
  errorMessage?: string | undefined;
806
816
  settings?: Record<string, unknown> | undefined;
@@ -1356,6 +1366,7 @@ declare class ObjectQL implements IDataEngine {
1356
1366
  private logger;
1357
1367
  private hooks;
1358
1368
  private middlewares;
1369
+ private actions;
1359
1370
  private hostContext;
1360
1371
  constructor(hostContext?: Record<string, any>);
1361
1372
  /**
@@ -1387,6 +1398,24 @@ declare class ObjectQL implements IDataEngine {
1387
1398
  priority?: number;
1388
1399
  }): void;
1389
1400
  triggerHooks(event: string, context: HookContext): Promise<void>;
1401
+ /**
1402
+ * Register a named action on an object.
1403
+ * Actions are custom business logic callable via `repo.execute(actionName, params)`.
1404
+ *
1405
+ * @param objectName Target object
1406
+ * @param actionName Unique action name within the object
1407
+ * @param handler Handler function
1408
+ * @param packageName Optional package owner (for cleanup)
1409
+ */
1410
+ registerAction(objectName: string, actionName: string, handler: (ctx: any) => Promise<any> | any, packageName?: string): void;
1411
+ /**
1412
+ * Execute a named action on an object.
1413
+ */
1414
+ executeAction(objectName: string, actionName: string, ctx: any): Promise<any>;
1415
+ /**
1416
+ * Remove all actions registered by a specific package.
1417
+ */
1418
+ removeActionsByPackage(packageName: string): void;
1390
1419
  /**
1391
1420
  * Register a middleware function
1392
1421
  * Middlewares execute in onion model around every data operation.
@@ -1590,6 +1619,8 @@ declare class ObjectQL implements IDataEngine {
1590
1619
  threshold: number;
1591
1620
  } | undefined;
1592
1621
  } | undefined;
1622
+ group?: string | undefined;
1623
+ conditionalRequired?: string | undefined;
1593
1624
  inlineHelpText?: string | undefined;
1594
1625
  trackFeedHistory?: boolean | undefined;
1595
1626
  caseSensitive?: boolean | undefined;
@@ -1667,6 +1698,12 @@ declare class ObjectQL implements IDataEngine {
1667
1698
  description?: string | undefined;
1668
1699
  }[]> | undefined;
1669
1700
  }> | undefined;
1701
+ displayNameField?: string | undefined;
1702
+ recordName?: {
1703
+ type: "text" | "autonumber";
1704
+ displayFormat?: string | undefined;
1705
+ startNumber?: number | undefined;
1706
+ } | undefined;
1670
1707
  titleFormat?: string | undefined;
1671
1708
  compactLayout?: string[] | undefined;
1672
1709
  search?: {
@@ -1731,21 +1768,41 @@ declare class ObjectQL implements IDataEngine {
1731
1768
  }
1732
1769
  /**
1733
1770
  * Repository scoped to a single object, bound to an execution context.
1771
+ *
1772
+ * Provides both IDataEngine-style methods (find, insert, update, delete)
1773
+ * and convenience aliases (create, updateById, deleteById) matching
1774
+ * the @objectql/core ObjectRepository API.
1734
1775
  */
1735
1776
  declare class ObjectRepository {
1736
1777
  private objectName;
1737
1778
  private context;
1738
1779
  private engine;
1739
- constructor(objectName: string, context: ExecutionContext, engine: IDataEngine);
1780
+ constructor(objectName: string, context: ExecutionContext, engine: IDataEngine & {
1781
+ executeAction?: (o: string, a: string, c: any) => Promise<any>;
1782
+ });
1740
1783
  find(query?: any): Promise<any[]>;
1741
1784
  findOne(query?: any): Promise<any>;
1742
1785
  insert(data: any): Promise<any>;
1786
+ /** Alias for insert() — matches @objectql/core convention */
1787
+ create(data: any): Promise<any>;
1743
1788
  update(data: any, options?: any): Promise<any>;
1789
+ /** Update a single record by ID */
1790
+ updateById(id: string | number, data: any): Promise<any>;
1744
1791
  delete(options?: any): Promise<any>;
1792
+ /** Delete a single record by ID */
1793
+ deleteById(id: string | number): Promise<any>;
1745
1794
  count(query?: any): Promise<number>;
1795
+ /** Aggregate query */
1796
+ aggregate(query?: any): Promise<any[]>;
1797
+ /** Execute a named action registered on this object */
1798
+ execute(actionName: string, params?: any): Promise<any>;
1746
1799
  }
1747
1800
  /**
1748
1801
  * Scoped execution context with object() accessor.
1802
+ *
1803
+ * Provides identity (userId, tenantId/spaceId, roles),
1804
+ * repository access via object(), privilege escalation via sudo(),
1805
+ * and transactional execution via transaction().
1749
1806
  */
1750
1807
  declare class ScopedContext {
1751
1808
  private executionContext;
@@ -1755,9 +1812,25 @@ declare class ScopedContext {
1755
1812
  object(name: string): ObjectRepository;
1756
1813
  /** Create an elevated (system) context */
1757
1814
  sudo(): ScopedContext;
1815
+ /**
1816
+ * Execute a callback within a database transaction.
1817
+ *
1818
+ * The callback receives a new ScopedContext whose operations
1819
+ * share the same transaction handle. If the callback throws,
1820
+ * the transaction is rolled back; otherwise it is committed.
1821
+ *
1822
+ * Falls back to non-transactional execution if the driver
1823
+ * does not support transactions.
1824
+ */
1825
+ transaction(callback: (trxCtx: ScopedContext) => Promise<any>): Promise<any>;
1758
1826
  get userId(): string | undefined;
1759
1827
  get tenantId(): string | undefined;
1828
+ /** Alias for tenantId — matches ObjectQLContext.spaceId convention */
1829
+ get spaceId(): string | undefined;
1760
1830
  get roles(): string[];
1831
+ get isSystem(): boolean;
1832
+ /** Internal: expose the transaction handle for driver-level access */
1833
+ get transactionHandle(): unknown;
1761
1834
  }
1762
1835
 
1763
1836
  /**
package/dist/index.js CHANGED
@@ -1120,6 +1120,8 @@ var ObjectQL = class {
1120
1120
  ]);
1121
1121
  // Middleware chain (onion model)
1122
1122
  this.middlewares = [];
1123
+ // Action registry: key = "objectName:actionName"
1124
+ this.actions = /* @__PURE__ */ new Map();
1123
1125
  // Host provided context additions (e.g. Server router)
1124
1126
  this.hostContext = {};
1125
1127
  this.hostContext = hostContext;
@@ -1209,6 +1211,43 @@ var ObjectQL = class {
1209
1211
  await entry.handler(context);
1210
1212
  }
1211
1213
  }
1214
+ // ========================================
1215
+ // Action System
1216
+ // ========================================
1217
+ /**
1218
+ * Register a named action on an object.
1219
+ * Actions are custom business logic callable via `repo.execute(actionName, params)`.
1220
+ *
1221
+ * @param objectName Target object
1222
+ * @param actionName Unique action name within the object
1223
+ * @param handler Handler function
1224
+ * @param packageName Optional package owner (for cleanup)
1225
+ */
1226
+ registerAction(objectName, actionName, handler, packageName) {
1227
+ const key = `${objectName}:${actionName}`;
1228
+ this.actions.set(key, { handler, package: packageName });
1229
+ this.logger.debug("Registered action", { objectName, actionName, package: packageName });
1230
+ }
1231
+ /**
1232
+ * Execute a named action on an object.
1233
+ */
1234
+ async executeAction(objectName, actionName, ctx) {
1235
+ const entry = this.actions.get(`${objectName}:${actionName}`);
1236
+ if (!entry) {
1237
+ throw new Error(`Action '${actionName}' on object '${objectName}' not found`);
1238
+ }
1239
+ return entry.handler(ctx);
1240
+ }
1241
+ /**
1242
+ * Remove all actions registered by a specific package.
1243
+ */
1244
+ removeActionsByPackage(packageName) {
1245
+ for (const [key, entry] of this.actions.entries()) {
1246
+ if (entry.package === packageName) {
1247
+ this.actions.delete(key);
1248
+ }
1249
+ }
1250
+ }
1212
1251
  /**
1213
1252
  * Register a middleware function
1214
1253
  * Middlewares execute in onion model around every data operation.
@@ -1876,24 +1915,61 @@ var ObjectRepository = class {
1876
1915
  context: this.context
1877
1916
  });
1878
1917
  }
1918
+ /** Alias for insert() — matches @objectql/core convention */
1919
+ async create(data) {
1920
+ return this.insert(data);
1921
+ }
1879
1922
  async update(data, options = {}) {
1880
1923
  return this.engine.update(this.objectName, data, {
1881
1924
  ...options,
1882
1925
  context: this.context
1883
1926
  });
1884
1927
  }
1928
+ /** Update a single record by ID */
1929
+ async updateById(id, data) {
1930
+ return this.engine.update(this.objectName, { ...data, _id: id }, {
1931
+ filter: { _id: id },
1932
+ context: this.context
1933
+ });
1934
+ }
1885
1935
  async delete(options = {}) {
1886
1936
  return this.engine.delete(this.objectName, {
1887
1937
  ...options,
1888
1938
  context: this.context
1889
1939
  });
1890
1940
  }
1941
+ /** Delete a single record by ID */
1942
+ async deleteById(id) {
1943
+ return this.engine.delete(this.objectName, {
1944
+ filter: { _id: id },
1945
+ context: this.context
1946
+ });
1947
+ }
1891
1948
  async count(query = {}) {
1892
1949
  return this.engine.count(this.objectName, {
1893
1950
  ...query,
1894
1951
  context: this.context
1895
1952
  });
1896
1953
  }
1954
+ /** Aggregate query */
1955
+ async aggregate(query = {}) {
1956
+ return this.engine.aggregate(this.objectName, {
1957
+ ...query,
1958
+ context: this.context
1959
+ });
1960
+ }
1961
+ /** Execute a named action registered on this object */
1962
+ async execute(actionName, params) {
1963
+ if (this.engine.executeAction) {
1964
+ return this.engine.executeAction(this.objectName, actionName, {
1965
+ ...params,
1966
+ userId: this.context.userId,
1967
+ tenantId: this.context.tenantId,
1968
+ roles: this.context.roles
1969
+ });
1970
+ }
1971
+ throw new Error(`Actions not supported by engine`);
1972
+ }
1897
1973
  };
1898
1974
  var ScopedContext = class _ScopedContext {
1899
1975
  constructor(executionContext, engine) {
@@ -1911,15 +1987,58 @@ var ScopedContext = class _ScopedContext {
1911
1987
  this.engine
1912
1988
  );
1913
1989
  }
1990
+ /**
1991
+ * Execute a callback within a database transaction.
1992
+ *
1993
+ * The callback receives a new ScopedContext whose operations
1994
+ * share the same transaction handle. If the callback throws,
1995
+ * the transaction is rolled back; otherwise it is committed.
1996
+ *
1997
+ * Falls back to non-transactional execution if the driver
1998
+ * does not support transactions.
1999
+ */
2000
+ async transaction(callback) {
2001
+ const engine = this.engine;
2002
+ const driver = engine.defaultDriver ? engine.drivers?.get(engine.defaultDriver) : void 0;
2003
+ if (!driver?.beginTransaction) {
2004
+ return callback(this);
2005
+ }
2006
+ const trx = await driver.beginTransaction();
2007
+ const trxCtx = new _ScopedContext(
2008
+ { ...this.executionContext, transaction: trx },
2009
+ this.engine
2010
+ );
2011
+ try {
2012
+ const result = await callback(trxCtx);
2013
+ if (driver.commit) await driver.commit(trx);
2014
+ else if (driver.commitTransaction) await driver.commitTransaction(trx);
2015
+ return result;
2016
+ } catch (error) {
2017
+ if (driver.rollback) await driver.rollback(trx);
2018
+ else if (driver.rollbackTransaction) await driver.rollbackTransaction(trx);
2019
+ throw error;
2020
+ }
2021
+ }
1914
2022
  get userId() {
1915
2023
  return this.executionContext.userId;
1916
2024
  }
1917
2025
  get tenantId() {
1918
2026
  return this.executionContext.tenantId;
1919
2027
  }
2028
+ /** Alias for tenantId — matches ObjectQLContext.spaceId convention */
2029
+ get spaceId() {
2030
+ return this.executionContext.tenantId;
2031
+ }
1920
2032
  get roles() {
1921
2033
  return this.executionContext.roles;
1922
2034
  }
2035
+ get isSystem() {
2036
+ return this.executionContext.isSystem;
2037
+ }
2038
+ /** Internal: expose the transaction handle for driver-level access */
2039
+ get transactionHandle() {
2040
+ return this.executionContext.transaction;
2041
+ }
1923
2042
  };
1924
2043
 
1925
2044
  // src/metadata-facade.ts