@danceroutine/tango-orm 1.2.0 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. package/dist/PostgresAdapter-BFdo_nIt.js +4 -0
  2. package/dist/{PostgresAdapter-C9a1XJRx.js → PostgresAdapter-CMiEpHya.js} +4 -52
  3. package/dist/PostgresAdapter-CMiEpHya.js.map +1 -0
  4. package/dist/PostgresClient-BQJZfEOT.js +68 -0
  5. package/dist/PostgresClient-BQJZfEOT.js.map +1 -0
  6. package/dist/SqliteAdapter-A-P9zUhP.js +4 -0
  7. package/dist/SqliteAdapter-CeqhyrPC.js +44 -0
  8. package/dist/SqliteAdapter-CeqhyrPC.js.map +1 -0
  9. package/dist/{SqliteAdapter-Dp6VRXmz.js → SqliteClient-CjOK9-ki.js} +20 -41
  10. package/dist/SqliteClient-CjOK9-ki.js.map +1 -0
  11. package/dist/connection/clients/DBClient.d.ts +6 -0
  12. package/dist/connection/clients/dialects/PostgresClient.d.ts +21 -5
  13. package/dist/connection/clients/dialects/SqliteClient.d.ts +13 -1
  14. package/dist/connection/index.js +5 -3
  15. package/dist/{connection-CVvycXus.js → connection-B_K2ZAf7.js} +7 -5
  16. package/dist/{connection-CVvycXus.js.map → connection-B_K2ZAf7.js.map} +1 -1
  17. package/dist/defaultRuntime-BPK9kWEW.js +447 -0
  18. package/dist/defaultRuntime-BPK9kWEW.js.map +1 -0
  19. package/dist/index.d.ts +2 -1
  20. package/dist/index.js +12 -9
  21. package/dist/manager/ManagerLike.d.ts +8 -8
  22. package/dist/manager/ModelManager.d.ts +15 -13
  23. package/dist/manager/index.js +6 -6
  24. package/dist/manager/internal/RuntimeBoundClient.d.ts +5 -1
  25. package/dist/{manager-CKUy1CIt.js → manager-C6oJ2tAF.js} +2 -2
  26. package/dist/{manager-CKUy1CIt.js.map → manager-C6oJ2tAF.js.map} +1 -1
  27. package/dist/query/QuerySet.d.ts +45 -30
  28. package/dist/query/compiler/QueryCompiler.d.ts +11 -1
  29. package/dist/query/domain/CompiledQuery.d.ts +21 -0
  30. package/dist/query/domain/RelationMeta.d.ts +3 -3
  31. package/dist/query/domain/RelationTyping.d.ts +74 -0
  32. package/dist/query/domain/index.d.ts +2 -0
  33. package/dist/query/index.js +1 -1
  34. package/dist/{query-BKt2nKIt.js → query-CWZ1cfjo.js} +221 -28
  35. package/dist/query-CWZ1cfjo.js.map +1 -0
  36. package/dist/{registerModelObjects-vsX6GzCN.js → registerModelObjects-Bva_f-Qh.js} +34 -134
  37. package/dist/registerModelObjects-Bva_f-Qh.js.map +1 -0
  38. package/dist/runtime/TangoRuntime.d.ts +17 -4
  39. package/dist/runtime/index.d.ts +3 -3
  40. package/dist/runtime/index.js +6 -6
  41. package/dist/runtime/internal/DBClientProvider.d.ts +12 -0
  42. package/dist/runtime/internal/PostgresDBClientProvider.d.ts +12 -0
  43. package/dist/runtime/internal/SqliteDBClientProvider.d.ts +16 -0
  44. package/dist/runtime/internal/createDBClientProvider.d.ts +5 -0
  45. package/dist/{runtime-BUpil272.js → runtime-ByXbpVBS.js} +3 -2
  46. package/dist/runtime-ByXbpVBS.js.map +1 -0
  47. package/dist/transaction/AtomicTransaction.d.ts +32 -0
  48. package/dist/transaction/UnitOfWork.d.ts +3 -0
  49. package/dist/transaction/atomic.d.ts +2 -0
  50. package/dist/transaction/index.d.ts +2 -0
  51. package/dist/transaction/index.js +5 -2
  52. package/dist/transaction/internal/context/AsyncLocalTransactionEngine.d.ts +21 -0
  53. package/dist/transaction/internal/context/CallbackRecord.d.ts +5 -0
  54. package/dist/transaction/internal/context/FrameBoundTransaction.d.ts +20 -0
  55. package/dist/transaction/internal/context/FrameTransactionHandle.d.ts +4 -0
  56. package/dist/transaction/internal/context/TransactionEngine.d.ts +16 -0
  57. package/dist/transaction/internal/context/TransactionFrame.d.ts +7 -0
  58. package/dist/transaction/internal/context/TransactionState.d.ts +10 -0
  59. package/dist/transaction/internal/context/index.d.ts +1 -0
  60. package/dist/{transaction-DooTMuAl.js → transaction-Cs0Z9tbW.js} +15 -3
  61. package/dist/transaction-Cs0Z9tbW.js.map +1 -0
  62. package/dist/validation/SQLValidationEngine.d.ts +3 -3
  63. package/package.json +6 -6
  64. package/dist/PostgresAdapter-C9a1XJRx.js.map +0 -1
  65. package/dist/PostgresAdapter-CBc1u8eT.js +0 -3
  66. package/dist/SqliteAdapter-BJKNxCvS.js +0 -3
  67. package/dist/SqliteAdapter-Dp6VRXmz.js.map +0 -1
  68. package/dist/query-BKt2nKIt.js.map +0 -1
  69. package/dist/registerModelObjects-vsX6GzCN.js.map +0 -1
  70. package/dist/runtime-BUpil272.js.map +0 -1
  71. package/dist/transaction-DooTMuAl.js.map +0 -1
@@ -1,18 +1,8 @@
1
- import { connectDB } from "./connection-CVvycXus.js";
2
- import { OrmSqlSafetyAdapter, QuerySet } from "./query-BKt2nKIt.js";
1
+ import { InternalRelationKind, OrmSqlSafetyAdapter, QuerySet } from "./query-CWZ1cfjo.js";
2
+ import { RuntimeBoundClient, TransactionEngine, getTangoRuntime } from "./defaultRuntime-BPK9kWEW.js";
3
3
  import { NotFoundError } from "@danceroutine/tango-core";
4
4
  import { ModelRegistry, registerModelAugmentor } from "@danceroutine/tango-schema";
5
- import { loadConfig, loadConfigFromProjectRoot } from "@danceroutine/tango-config";
6
5
 
7
- //#region src/query/domain/internal/InternalRelationKind.ts
8
- const InternalRelationKind = {
9
- HAS_MANY: "hasMany",
10
- BELONGS_TO: "belongsTo",
11
- HAS_ONE: "hasOne",
12
- MANY_TO_MANY: "manyToMany"
13
- };
14
-
15
- //#endregion
16
6
  //#region src/manager/internal/MutationCompiler.ts
17
7
  var MutationCompiler = class {
18
8
  constructor(dialect) {
@@ -57,34 +47,6 @@ var MutationCompiler = class {
57
47
  }
58
48
  };
59
49
 
60
- //#endregion
61
- //#region src/manager/internal/RuntimeBoundClient.ts
62
- var RuntimeBoundClient = class {
63
- constructor(runtime) {
64
- this.runtime = runtime;
65
- }
66
- async query(sql, params) {
67
- const client = await this.runtime.getClient();
68
- return client.query(sql, params);
69
- }
70
- async begin() {
71
- const client = await this.runtime.getClient();
72
- await client.begin();
73
- }
74
- async commit() {
75
- const client = await this.runtime.getClient();
76
- await client.commit();
77
- }
78
- async rollback() {
79
- const client = await this.runtime.getClient();
80
- await client.rollback();
81
- }
82
- async close() {
83
- const client = await this.runtime.getClient();
84
- await client.close();
85
- }
86
- };
87
-
88
50
  //#endregion
89
51
  //#region src/manager/ModelManager.ts
90
52
  const sqlSafetyAdapter = new OrmSqlSafetyAdapter();
@@ -96,8 +58,10 @@ var ModelManager = class ModelManager {
96
58
  model;
97
59
  client;
98
60
  dialect;
61
+ runtime;
99
62
  constructor(model, runtime) {
100
63
  this.model = model;
64
+ this.runtime = runtime;
101
65
  this.client = new RuntimeBoundClient(runtime);
102
66
  this.dialect = runtime.getDialect();
103
67
  this.mutationCompiler = new MutationCompiler(this.dialect);
@@ -134,15 +98,16 @@ var ModelManager = class ModelManager {
134
98
  const owner = ModelRegistry.getOwner(model);
135
99
  const relations = owner.getResolvedRelationGraph().byModel.get(model.metadata.key);
136
100
  if (relations && relations.size > 0) rawMeta.relations = Object.fromEntries(Array.from(relations.entries()).filter(([, relation]) => relation.kind !== InternalRelationKind.MANY_TO_MANY).map(([name, relation]) => {
137
- const isForwardReference = relation.kind === InternalRelationKind.BELONGS_TO;
138
- const sourceKey = isForwardReference ? relation.localFieldName : relation.targetFieldName;
139
- const targetKey = isForwardReference ? relation.targetFieldName : relation.localFieldName;
101
+ const targetModel = owner.getByKey(relation.targetModelKey);
102
+ const targetColumns = Object.fromEntries(targetModel.metadata.fields.map((field) => [field.name, field.type]));
103
+ const sourceKey = relation.kind === InternalRelationKind.BELONGS_TO ? relation.localFieldName : relation.targetFieldName;
104
+ const targetKey = relation.kind === InternalRelationKind.BELONGS_TO ? relation.targetFieldName : relation.localFieldName;
140
105
  return [name, {
141
106
  kind: relation.kind,
142
- table: owner.getByKey(relation.targetModelKey).metadata.table,
143
- targetPk: targetKey,
144
- localKey: sourceKey,
145
- foreignKey: relation.localFieldName,
107
+ table: targetModel.metadata.table,
108
+ sourceKey,
109
+ targetKey,
110
+ targetColumns,
146
111
  alias: relation.alias
147
112
  }];
148
113
  }));
@@ -182,7 +147,8 @@ var ModelManager = class ModelManager {
182
147
  await this.model.hooks?.afterCreate?.({
183
148
  record: created,
184
149
  model: this.model,
185
- manager: this
150
+ manager: this,
151
+ transaction: this.getHookTransaction()
186
152
  });
187
153
  return created;
188
154
  }
@@ -205,7 +171,8 @@ var ModelManager = class ModelManager {
205
171
  previous: current,
206
172
  record: updated,
207
173
  model: this.model,
208
- manager: this
174
+ manager: this,
175
+ transaction: this.getHookTransaction()
209
176
  });
210
177
  return updated;
211
178
  }
@@ -215,7 +182,8 @@ var ModelManager = class ModelManager {
215
182
  id,
216
183
  current,
217
184
  model: this.model,
218
- manager: this
185
+ manager: this,
186
+ transaction: this.getHookTransaction()
219
187
  });
220
188
  const validatedPlan = sqlSafetyAdapter.validate({
221
189
  kind: "delete",
@@ -227,7 +195,8 @@ var ModelManager = class ModelManager {
227
195
  id,
228
196
  previous: current,
229
197
  model: this.model,
230
- manager: this
198
+ manager: this,
199
+ transaction: this.getHookTransaction()
231
200
  });
232
201
  }
233
202
  async bulkCreate(inputs) {
@@ -236,7 +205,8 @@ var ModelManager = class ModelManager {
236
205
  const batchPrepared = await this.model.hooks?.beforeBulkCreate?.({
237
206
  rows: perRowPrepared,
238
207
  model: this.model,
239
- manager: this
208
+ manager: this,
209
+ transaction: this.getHookTransaction()
240
210
  }) ?? perRowPrepared;
241
211
  const preparedKeys = Object.keys(batchPrepared[0] ?? {});
242
212
  if (preparedKeys.length === 0) throw new Error(`Cannot create ${this.model.metadata.name} without any values.`);
@@ -251,12 +221,14 @@ var ModelManager = class ModelManager {
251
221
  await Promise.all(result.rows.map((record) => this.model.hooks?.afterCreate?.({
252
222
  record,
253
223
  model: this.model,
254
- manager: this
224
+ manager: this,
225
+ transaction: this.getHookTransaction()
255
226
  })));
256
227
  await this.model.hooks?.afterBulkCreate?.({
257
228
  records: result.rows,
258
229
  model: this.model,
259
- manager: this
230
+ manager: this,
231
+ transaction: this.getHookTransaction()
260
232
  });
261
233
  return result.rows;
262
234
  }
@@ -264,7 +236,8 @@ var ModelManager = class ModelManager {
264
236
  return await this.model.hooks?.beforeCreate?.({
265
237
  data,
266
238
  model: this.model,
267
- manager: this
239
+ manager: this,
240
+ transaction: this.getHookTransaction()
268
241
  }) ?? data;
269
242
  }
270
243
  async runBeforeUpdate(id, patch, current) {
@@ -273,88 +246,15 @@ var ModelManager = class ModelManager {
273
246
  patch,
274
247
  current,
275
248
  model: this.model,
276
- manager: this
249
+ manager: this,
250
+ transaction: this.getHookTransaction()
277
251
  }) ?? patch;
278
252
  }
279
- };
280
-
281
- //#endregion
282
- //#region src/runtime/TangoRuntime.ts
283
- var TangoRuntime = class TangoRuntime {
284
- static BRAND = "tango.orm.runtime";
285
- __tangoBrand = TangoRuntime.BRAND;
286
- loadedConfig;
287
- clientPromise = null;
288
- constructor(loadLoadedConfig) {
289
- this.loadedConfig = loadLoadedConfig();
290
- }
291
- /**
292
- * Narrow an unknown value to `TangoRuntime`.
293
- */
294
- static isTangoRuntime(value) {
295
- return typeof value === "object" && value !== null && value.__tangoBrand === TangoRuntime.BRAND;
296
- }
297
- /**
298
- * Return the loaded Tango config snapshot for the active environment.
299
- */
300
- getConfig() {
301
- return this.loadedConfig;
302
- }
303
- /**
304
- * Return the configured SQL dialect for the current runtime.
305
- */
306
- getDialect() {
307
- return this.loadedConfig.current.db.adapter;
308
- }
309
- /**
310
- * Return the shared DB client, creating it once on first access.
311
- */
312
- async getClient() {
313
- if (!this.clientPromise) {
314
- const db = this.loadedConfig.current.db;
315
- this.clientPromise = connectDB({
316
- adapter: db.adapter,
317
- url: db.url,
318
- host: db.host,
319
- port: db.port,
320
- database: db.database,
321
- user: db.user,
322
- password: db.password,
323
- filename: db.filename,
324
- maxConnections: db.maxConnections
325
- });
326
- }
327
- return this.clientPromise;
328
- }
329
- /**
330
- * Close and clear the cached DB client so tests can start fresh.
331
- */
332
- async reset() {
333
- if (!this.clientPromise) return;
334
- const client = await this.clientPromise;
335
- this.clientPromise = null;
336
- await client.close();
253
+ getHookTransaction() {
254
+ return TransactionEngine.forRuntime(this.runtime).getActiveTransaction();
337
255
  }
338
256
  };
339
257
 
340
- //#endregion
341
- //#region src/runtime/defaultRuntime.ts
342
- let defaultRuntime = null;
343
- function initializeTangoRuntime(fromFile) {
344
- defaultRuntime = new TangoRuntime(() => loadConfig(fromFile));
345
- return defaultRuntime;
346
- }
347
- function getTangoRuntime() {
348
- if (!defaultRuntime) defaultRuntime = new TangoRuntime(() => loadConfigFromProjectRoot());
349
- return defaultRuntime;
350
- }
351
- async function resetTangoRuntime() {
352
- if (!defaultRuntime) return;
353
- const runtime = defaultRuntime;
354
- defaultRuntime = null;
355
- await runtime.reset();
356
- }
357
-
358
258
  //#endregion
359
259
  //#region src/manager/registerModelObjects.ts
360
260
  const managerCache = new WeakMap();
@@ -383,5 +283,5 @@ function registerModelObjects() {
383
283
  }
384
284
 
385
285
  //#endregion
386
- export { ModelManager, TangoRuntime, getTangoRuntime, initializeTangoRuntime, registerModelObjects, resetTangoRuntime };
387
- //# sourceMappingURL=registerModelObjects-vsX6GzCN.js.map
286
+ export { ModelManager, registerModelObjects };
287
+ //# sourceMappingURL=registerModelObjects-Bva_f-Qh.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registerModelObjects-Bva_f-Qh.js","names":["dialect: Dialect","plan: ValidatedInsertSqlPlan","values: readonly unknown[]","plan: ValidatedUpdateSqlPlan","id: unknown","plan: ValidatedDeleteSqlPlan","valueRows: ReadonlyArray<ReadonlyArray<unknown>>","count: number","index: number","model: ModelLike<TModelRow>","runtime: TangoRuntime","value: unknown","rawMeta: TableMeta","id: TModelRow[keyof TModelRow]","input: Partial<TModelRow>","patch: Partial<TModelRow>","inputs: Partial<TModelRow>[]","batchPrepared: Partial<TModelRow>[]","data: Partial<TModelRow>","current: TModelRow","model: SchemaModel<TSchema, TKey>"],"sources":["../src/manager/internal/MutationCompiler.ts","../src/manager/ModelManager.ts","../src/manager/registerModelObjects.ts"],"sourcesContent":["import type { CompiledQuery, Dialect } from '../../query/domain/index';\nimport type {\n ValidatedDeleteSqlPlan,\n ValidatedInsertSqlPlan,\n ValidatedUpdateSqlPlan,\n} from '../../validation/SQLValidationEngine';\n\n/**\n * Internal compiler for manager-owned INSERT/UPDATE/DELETE statements.\n */\nexport class MutationCompiler {\n constructor(private readonly dialect: Dialect) {}\n\n compileInsert(plan: ValidatedInsertSqlPlan, values: readonly unknown[]): CompiledQuery {\n return {\n sql: `INSERT INTO ${plan.meta.table} (${plan.writeKeys.join(', ')}) VALUES (${this.buildValuePlaceholders(plan.writeKeys.length)}) RETURNING *`,\n params: values,\n };\n }\n\n compileUpdate(plan: ValidatedUpdateSqlPlan, values: readonly unknown[], id: unknown): CompiledQuery {\n const sets = plan.writeKeys.map((key, index) => `${key} = ${this.placeholder(index + 1)}`).join(', ');\n const whereParam = this.placeholder(plan.writeKeys.length + 1);\n\n return {\n sql: `UPDATE ${plan.meta.table} SET ${sets} WHERE ${plan.meta.pk} = ${whereParam} RETURNING *`,\n params: [...values, id],\n };\n }\n\n compileDelete(plan: ValidatedDeleteSqlPlan, id: unknown): CompiledQuery {\n return {\n sql: `DELETE FROM ${plan.meta.table} WHERE ${plan.meta.pk} = ${this.placeholder(1)}`,\n params: [id],\n };\n }\n\n compileBulkInsert(plan: ValidatedInsertSqlPlan, valueRows: ReadonlyArray<ReadonlyArray<unknown>>): CompiledQuery {\n const columnCount = plan.writeKeys.length;\n const placeholders = valueRows\n .map((_row, rowIndex) => {\n const offset = rowIndex * columnCount;\n return `(${plan.writeKeys.map((_, colIndex) => this.placeholder(offset + colIndex + 1)).join(', ')})`;\n })\n .join(', ');\n\n return {\n sql: `INSERT INTO ${plan.meta.table} (${plan.writeKeys.join(', ')}) VALUES ${placeholders} RETURNING *`,\n params: valueRows.flat(),\n };\n }\n\n private buildValuePlaceholders(count: number): string {\n return Array.from({ length: count }, (_value, index) => this.placeholder(index + 1)).join(', ');\n }\n\n private placeholder(index: number): string {\n return this.dialect === 'postgres' ? `$${index}` : '?';\n }\n}\n","import { NotFoundError } from '@danceroutine/tango-core';\nimport { ModelRegistry, type ModelWriteHooks } from '@danceroutine/tango-schema';\nimport type { FilterInput, RelationMeta, TableMeta } from '../query/domain/index';\nimport { InternalRelationKind } from '../query/domain/internal/InternalRelationKind';\nimport type { QuerySet } from '../query/index';\nimport { QuerySet as QuerySetClass } from '../query/index';\nimport type { Dialect, QueryExecutor } from '../query/index';\nimport type { TangoRuntime } from '../runtime/TangoRuntime';\nimport { OrmSqlSafetyAdapter } from '../validation';\nimport { TransactionEngine } from '../transaction/internal/context';\nimport type { ManagerLike } from './ManagerLike';\nimport { MutationCompiler } from './internal/MutationCompiler';\nimport { RuntimeBoundClient } from './internal/RuntimeBoundClient';\n\nconst sqlSafetyAdapter = new OrmSqlSafetyAdapter();\n\ntype FieldLike = {\n name: string;\n type: string;\n primaryKey?: boolean;\n};\n\ntype ModelLike<TModelRow extends Record<string, unknown>> = {\n metadata: {\n key?: string;\n name: string;\n table: string;\n fields: FieldLike[];\n };\n schema: {\n parse(input: unknown): TModelRow;\n };\n hooks?: ModelWriteHooks<TModelRow>;\n};\n\n/**\n * Model-backed data access API exposed as `Model.objects`.\n */\nexport class ModelManager<TModelRow extends Record<string, unknown>, TSourceModel = unknown>\n implements ManagerLike<TModelRow, TSourceModel>\n{\n static readonly BRAND = 'tango.orm.model_manager' as const;\n readonly __tangoBrand: typeof ModelManager.BRAND = ModelManager.BRAND;\n private readonly queryExecutor: QueryExecutor<TModelRow>;\n private readonly mutationCompiler: MutationCompiler;\n private readonly model: ModelLike<TModelRow>;\n private readonly client: RuntimeBoundClient;\n private readonly dialect: Dialect;\n private readonly runtime: TangoRuntime;\n\n constructor(model: ModelLike<TModelRow>, runtime: TangoRuntime) {\n this.model = model;\n this.runtime = runtime;\n this.client = new RuntimeBoundClient(runtime);\n this.dialect = runtime.getDialect() as Dialect;\n this.mutationCompiler = new MutationCompiler(this.dialect);\n this.queryExecutor = {\n get meta() {\n return ModelManager.createTableMeta(model);\n },\n client: this.client,\n dialect: this.dialect,\n run: async (compiled) => {\n const result = await this.client.query<TModelRow>(compiled.sql, compiled.params);\n return result.rows;\n },\n };\n }\n\n get meta(): TableMeta {\n return ModelManager.createTableMeta(this.model);\n }\n\n /**\n * Narrow an unknown value to `ModelManager`.\n */\n static isModelManager<TModelRow extends Record<string, unknown>>(value: unknown): value is ModelManager<TModelRow> {\n return (\n typeof value === 'object' &&\n value !== null &&\n (value as { __tangoBrand?: unknown }).__tangoBrand === ModelManager.BRAND\n );\n }\n\n private static createTableMeta<TModelRow extends Record<string, unknown>>(model: ModelLike<TModelRow>): TableMeta {\n const pkField = model.metadata.fields.find((field) => field.primaryKey);\n if (!pkField) {\n throw new Error(`Model '${model.metadata.name}' cannot attach a manager without a primary key field.`);\n }\n\n const rawMeta: TableMeta = {\n table: model.metadata.table,\n pk: pkField.name,\n columns: Object.fromEntries(model.metadata.fields.map((field) => [field.name, field.type])),\n };\n\n if (model.metadata.key) {\n const owner = ModelRegistry.getOwner(model as never);\n const relations = owner.getResolvedRelationGraph().byModel.get(model.metadata.key);\n if (relations && relations.size > 0) {\n // This metadata is recomputed on access today. Most application tables have a small relation set, so\n // keeping this path direct is acceptable until profiling points to a dedicated manager-meta cache.\n rawMeta.relations = Object.fromEntries(\n Array.from(relations.entries())\n .filter(([, relation]) => relation.kind !== InternalRelationKind.MANY_TO_MANY)\n .map(([name, relation]) => {\n const targetModel = owner.getByKey(relation.targetModelKey)!;\n // Query planning needs the target model's SQL-facing shape so joined and prefetched rows can be\n // selected, normalized, and attached without leaking internal alias columns.\n const targetColumns = Object.fromEntries(\n targetModel.metadata.fields.map((field) => [field.name, field.type])\n );\n // Forward relations join from this table's FK to the target key. Reverse relations flip that:\n // this table's primary key matches the target model's FK back to this model.\n const sourceKey =\n relation.kind === InternalRelationKind.BELONGS_TO\n ? relation.localFieldName\n : relation.targetFieldName;\n const targetKey =\n relation.kind === InternalRelationKind.BELONGS_TO\n ? relation.targetFieldName\n : relation.localFieldName;\n\n return [\n name,\n {\n kind: relation.kind as RelationMeta['kind'],\n table: targetModel.metadata.table,\n sourceKey: sourceKey as string,\n targetKey: targetKey as string,\n targetColumns,\n alias: relation.alias,\n },\n ];\n })\n );\n }\n }\n\n const validatedMeta = sqlSafetyAdapter.validate({\n kind: 'insert',\n meta: rawMeta,\n writeKeys: Object.keys(rawMeta.columns),\n }).meta;\n\n if (rawMeta.relations) {\n validatedMeta.relations = rawMeta.relations;\n }\n\n return validatedMeta;\n }\n\n query(): QuerySet<TModelRow, TModelRow, TSourceModel> {\n return new QuerySetClass<TModelRow, TModelRow, TSourceModel>(this.queryExecutor, {});\n }\n\n async findById(id: TModelRow[keyof TModelRow]): Promise<TModelRow | null> {\n const filter = { [this.meta.pk]: id } as unknown as FilterInput<TModelRow>;\n return this.query().filter(filter).fetchOne();\n }\n\n async getOrThrow(id: TModelRow[keyof TModelRow]): Promise<TModelRow> {\n const result = await this.findById(id);\n if (!result) {\n throw new NotFoundError(`${this.model.metadata.name} with ${this.meta.pk}=${String(id)} not found`);\n }\n return result;\n }\n\n async create(input: Partial<TModelRow>): Promise<TModelRow> {\n const prepared = await this.runBeforeCreate(input);\n const preparedKeys = Object.keys(prepared);\n if (preparedKeys.length === 0) {\n throw new Error(`Cannot create ${this.model.metadata.name} without any values.`);\n }\n\n const validatedPlan = sqlSafetyAdapter.validate({\n kind: 'insert',\n meta: this.meta,\n writeKeys: preparedKeys,\n });\n const compiled = this.mutationCompiler.compileInsert(\n validatedPlan,\n preparedKeys.map((key) => prepared[key as keyof TModelRow])\n );\n const result = await this.queryExecutor.client.query<TModelRow>(compiled.sql, compiled.params);\n const created = result.rows[0]!;\n await this.model.hooks?.afterCreate?.({\n record: created,\n model: this.model,\n manager: this,\n transaction: this.getHookTransaction(),\n });\n return created;\n }\n\n async update(id: TModelRow[keyof TModelRow], patch: Partial<TModelRow>): Promise<TModelRow> {\n const current = await this.getOrThrow(id);\n const prepared = await this.runBeforeUpdate(id, patch, current);\n const preparedKeys = Object.keys(prepared);\n if (preparedKeys.length === 0) {\n throw new Error(`Cannot update ${this.model.metadata.name} without any values.`);\n }\n\n const validatedPlan = sqlSafetyAdapter.validate({\n kind: 'update',\n meta: this.meta,\n writeKeys: preparedKeys,\n });\n const compiled = this.mutationCompiler.compileUpdate(\n validatedPlan,\n preparedKeys.map((key) => prepared[key as keyof TModelRow]),\n id\n );\n const result = await this.queryExecutor.client.query<TModelRow>(compiled.sql, compiled.params);\n const updated = result.rows[0]!;\n await this.model.hooks?.afterUpdate?.({\n id,\n patch: prepared,\n previous: current,\n record: updated,\n model: this.model,\n manager: this,\n transaction: this.getHookTransaction(),\n });\n return updated;\n }\n\n async delete(id: TModelRow[keyof TModelRow]): Promise<void> {\n const current = await this.getOrThrow(id);\n await this.model.hooks?.beforeDelete?.({\n id,\n current,\n model: this.model,\n manager: this,\n transaction: this.getHookTransaction(),\n });\n const validatedPlan = sqlSafetyAdapter.validate({\n kind: 'delete',\n meta: this.meta,\n });\n const compiled = this.mutationCompiler.compileDelete(validatedPlan, id);\n await this.queryExecutor.client.query(compiled.sql, compiled.params);\n await this.model.hooks?.afterDelete?.({\n id,\n previous: current,\n model: this.model,\n manager: this,\n transaction: this.getHookTransaction(),\n });\n }\n\n async bulkCreate(inputs: Partial<TModelRow>[]): Promise<TModelRow[]> {\n if (inputs.length === 0) {\n return [];\n }\n\n const perRowPrepared = await Promise.all(inputs.map((input) => this.runBeforeCreate(input)));\n const batchPrepared: Partial<TModelRow>[] =\n (await this.model.hooks?.beforeBulkCreate?.({\n rows: perRowPrepared,\n model: this.model,\n manager: this,\n transaction: this.getHookTransaction(),\n })) ?? perRowPrepared;\n const preparedKeys = Object.keys(batchPrepared[0] ?? {});\n if (preparedKeys.length === 0) {\n throw new Error(`Cannot create ${this.model.metadata.name} without any values.`);\n }\n\n const validatedPlan = sqlSafetyAdapter.validate({\n kind: 'insert',\n meta: this.meta,\n writeKeys: preparedKeys,\n });\n const valueRows = batchPrepared.map((input) => preparedKeys.map((key) => input[key as keyof TModelRow]));\n const compiled = this.mutationCompiler.compileBulkInsert(validatedPlan, valueRows);\n const result = await this.queryExecutor.client.query<TModelRow>(compiled.sql, compiled.params);\n await Promise.all(\n result.rows.map((record) =>\n this.model.hooks?.afterCreate?.({\n record,\n model: this.model,\n manager: this,\n transaction: this.getHookTransaction(),\n })\n )\n );\n await this.model.hooks?.afterBulkCreate?.({\n records: result.rows,\n model: this.model,\n manager: this,\n transaction: this.getHookTransaction(),\n });\n return result.rows;\n }\n\n private async runBeforeCreate(data: Partial<TModelRow>): Promise<Partial<TModelRow>> {\n return (\n (await this.model.hooks?.beforeCreate?.({\n data,\n model: this.model,\n manager: this,\n transaction: this.getHookTransaction(),\n })) ?? data\n );\n }\n\n private async runBeforeUpdate(\n id: TModelRow[keyof TModelRow],\n patch: Partial<TModelRow>,\n current: TModelRow\n ): Promise<Partial<TModelRow>> {\n return (\n (await this.model.hooks?.beforeUpdate?.({\n id,\n patch,\n current,\n model: this.model,\n manager: this,\n transaction: this.getHookTransaction(),\n })) ?? patch\n );\n }\n\n private getHookTransaction() {\n return TransactionEngine.forRuntime(this.runtime).getActiveTransaction();\n }\n}\n","import type { z } from 'zod';\nimport type { Model as SchemaModel, PersistedModelOutput } from '@danceroutine/tango-schema/domain';\nimport { registerModelAugmentor } from '@danceroutine/tango-schema';\nimport { ModelManager } from './ModelManager';\nimport type { TangoRuntime } from '../runtime/TangoRuntime';\nimport { getTangoRuntime } from '../runtime/defaultRuntime';\n\nconst managerCache = new WeakMap<object, { runtime: TangoRuntime; manager: ModelManager<Record<string, unknown>> }>();\nlet hasRegisteredModelObjects = false;\n\ntype AugmentableSchemaModel<TSchema extends z.ZodObject<z.ZodRawShape>> = {\n metadata: {\n key?: string;\n name: string;\n table: string;\n fields: Array<{ name: string; type: string; primaryKey?: boolean }>;\n };\n schema: {\n parse(input: unknown): PersistedModelOutput<TSchema>;\n };\n hooks?: SchemaModel<TSchema>['hooks'];\n};\n\nfunction defineObjectsProperty<TSchema extends z.ZodObject<z.ZodRawShape>, TKey extends string>(\n model: SchemaModel<TSchema, TKey>\n): void {\n Object.defineProperty(model, 'objects', {\n configurable: true,\n enumerable: true,\n get() {\n const runtime = getTangoRuntime();\n const cached = managerCache.get(model);\n if (cached && cached.runtime === runtime) {\n return cached.manager;\n }\n\n const manager = new ModelManager<PersistedModelOutput<TSchema>, SchemaModel<TSchema, TKey>>(\n model as unknown as AugmentableSchemaModel<TSchema>,\n runtime\n );\n managerCache.set(model, {\n runtime,\n manager: manager as ModelManager<Record<string, unknown>>,\n });\n return manager;\n },\n });\n}\n\n/**\n * Install the schema model augmentor that exposes `Model.objects`.\n * This registration is idempotent so multiple Tango entrypoints can safely call it.\n */\nexport function registerModelObjects(): void {\n if (hasRegisteredModelObjects) {\n return;\n }\n\n registerModelAugmentor(defineObjectsProperty);\n hasRegisteredModelObjects = true;\n}\n"],"mappings":"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"}
@@ -1,15 +1,17 @@
1
1
  import type { LoadedConfig } from '@danceroutine/tango-config';
2
2
  import type { DBClient } from '../connection/index';
3
3
  import type { Dialect } from '../query/domain/index';
4
+ import type { TransactionClientLease } from './internal/DBClientProvider';
4
5
  /**
5
6
  * Framework-owned database runtime that resolves Tango config and lazily
6
- * creates the shared DB client used by manager-backed models.
7
+ * creates the shared connection provider used by manager-backed models.
7
8
  */
8
9
  export declare class TangoRuntime {
9
10
  static readonly BRAND: "tango.orm.runtime";
10
11
  readonly __tangoBrand: typeof TangoRuntime.BRAND;
11
12
  private readonly loadedConfig;
12
- private clientPromise;
13
+ private providerPromise;
14
+ private runtimeClientPromise;
13
15
  constructor(loadLoadedConfig: () => LoadedConfig);
14
16
  /**
15
17
  * Narrow an unknown value to `TangoRuntime`.
@@ -24,11 +26,22 @@ export declare class TangoRuntime {
24
26
  */
25
27
  getDialect(): Dialect;
26
28
  /**
27
- * Return the shared DB client, creating it once on first access.
29
+ * Return the runtime-bound DB client facade used by manager-backed code.
28
30
  */
29
31
  getClient(): Promise<DBClient>;
30
32
  /**
31
- * Close and clear the cached DB client so tests can start fresh.
33
+ * Execute SQL through the autocommit path owned by this runtime.
34
+ */
35
+ query<T = unknown>(sql: string, params?: readonly unknown[]): Promise<{
36
+ rows: T[];
37
+ }>;
38
+ /**
39
+ * Lease a transaction-scoped client for `transaction.atomic(...)`.
40
+ */
41
+ leaseTransactionClient(): Promise<TransactionClientLease>;
42
+ /**
43
+ * Close and clear the cached runtime resources so tests can start fresh.
32
44
  */
33
45
  reset(): Promise<void>;
46
+ private getProvider;
34
47
  }
@@ -1,12 +1,12 @@
1
1
  import type { z } from 'zod';
2
2
  import type { ModelManager } from '../manager/ModelManager';
3
- import type { PersistedModelOutput } from '@danceroutine/tango-schema/domain';
3
+ import type { Model, PersistedModelOutput } from '@danceroutine/tango-schema/domain';
4
4
  /**
5
5
  * Domain boundary barrel: centralizes Tango runtime ownership APIs.
6
6
  */
7
7
  declare global {
8
- interface TangoSchemaModelAugmentations<TSchema extends z.ZodObject<z.ZodRawShape> = z.ZodObject<z.ZodRawShape>> {
9
- readonly objects: ModelManager<PersistedModelOutput<TSchema>>;
8
+ interface TangoSchemaModelAugmentations<TSchema extends z.ZodObject<z.ZodRawShape> = z.ZodObject<z.ZodRawShape>, TKey extends string = string> {
9
+ readonly objects: ModelManager<PersistedModelOutput<TSchema>, Model<TSchema, TKey>>;
10
10
  }
11
11
  }
12
12
  export { registerModelObjects } from '../manager/registerModelObjects';
@@ -1,8 +1,8 @@
1
- import "../PostgresAdapter-C9a1XJRx.js";
2
- import "../SqliteAdapter-Dp6VRXmz.js";
3
- import "../connection-CVvycXus.js";
4
- import { TangoRuntime, getTangoRuntime, initializeTangoRuntime, registerModelObjects, resetTangoRuntime } from "../registerModelObjects-vsX6GzCN.js";
5
- import "../query-BKt2nKIt.js";
6
- import "../runtime-BUpil272.js";
1
+ import "../PostgresClient-BQJZfEOT.js";
2
+ import "../SqliteClient-CjOK9-ki.js";
3
+ import "../query-CWZ1cfjo.js";
4
+ import { TangoRuntime, getTangoRuntime, initializeTangoRuntime, resetTangoRuntime } from "../defaultRuntime-BPK9kWEW.js";
5
+ import { registerModelObjects } from "../registerModelObjects-Bva_f-Qh.js";
6
+ import "../runtime-ByXbpVBS.js";
7
7
 
8
8
  export { TangoRuntime, getTangoRuntime, initializeTangoRuntime, registerModelObjects, resetTangoRuntime };
@@ -0,0 +1,12 @@
1
+ import type { DBClient } from '../../connection/clients/DBClient';
2
+ export interface TransactionClientLease {
3
+ readonly client: DBClient;
4
+ release(): Promise<void>;
5
+ }
6
+ export interface DBClientProvider {
7
+ query<T = unknown>(sql: string, params?: readonly unknown[]): Promise<{
8
+ rows: T[];
9
+ }>;
10
+ leaseTransactionClient(): Promise<TransactionClientLease>;
11
+ reset(): Promise<void>;
12
+ }
@@ -0,0 +1,12 @@
1
+ import type { AdapterConfig } from '../../connection/adapters/Adapter';
2
+ import type { DBClientProvider, TransactionClientLease } from './DBClientProvider';
3
+ export declare class PostgresDBClientProvider implements DBClientProvider {
4
+ private readonly pool;
5
+ private activeLeaseCount;
6
+ constructor(config: AdapterConfig);
7
+ query<T = unknown>(sql: string, params?: readonly unknown[]): Promise<{
8
+ rows: T[];
9
+ }>;
10
+ leaseTransactionClient(): Promise<TransactionClientLease>;
11
+ reset(): Promise<void>;
12
+ }
@@ -0,0 +1,16 @@
1
+ import type { AdapterConfig } from '../../connection/adapters/Adapter';
2
+ import type { DBClientProvider, TransactionClientLease } from './DBClientProvider';
3
+ export declare class SqliteDBClientProvider implements DBClientProvider {
4
+ private readonly filename;
5
+ private readonly Database;
6
+ private readonly autocommitClient;
7
+ private activeLeaseCount;
8
+ constructor(config?: AdapterConfig);
9
+ query<T = unknown>(sql: string, params?: readonly unknown[]): Promise<{
10
+ rows: T[];
11
+ }>;
12
+ leaseTransactionClient(): Promise<TransactionClientLease>;
13
+ reset(): Promise<void>;
14
+ private openClient;
15
+ private getDatabaseCtor;
16
+ }
@@ -0,0 +1,5 @@
1
+ import type { AdapterConfig } from '../../connection/adapters/Adapter';
2
+ import type { DBClientProvider } from './DBClientProvider';
3
+ export declare function createDBClientProvider(config: AdapterConfig & {
4
+ adapter: string;
5
+ }): DBClientProvider;
@@ -1,5 +1,6 @@
1
1
  import { __export } from "./chunk-DLY2FNSh.js";
2
- import { TangoRuntime, getTangoRuntime, initializeTangoRuntime, registerModelObjects, resetTangoRuntime } from "./registerModelObjects-vsX6GzCN.js";
2
+ import { TangoRuntime, getTangoRuntime, initializeTangoRuntime, resetTangoRuntime } from "./defaultRuntime-BPK9kWEW.js";
3
+ import { registerModelObjects } from "./registerModelObjects-Bva_f-Qh.js";
3
4
 
4
5
  //#region src/runtime/index.ts
5
6
  var runtime_exports = {};
@@ -14,4 +15,4 @@ registerModelObjects();
14
15
 
15
16
  //#endregion
16
17
  export { runtime_exports };
17
- //# sourceMappingURL=runtime-BUpil272.js.map
18
+ //# sourceMappingURL=runtime-ByXbpVBS.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runtime-ByXbpVBS.js","names":[],"sources":["../src/runtime/index.ts"],"sourcesContent":["import type { z } from 'zod';\nimport type { ModelManager } from '../manager/ModelManager';\nimport type { Model, PersistedModelOutput } from '@danceroutine/tango-schema/domain';\nimport { registerModelObjects } from '../manager/registerModelObjects';\n\n/**\n * Domain boundary barrel: centralizes Tango runtime ownership APIs.\n */\n\ndeclare global {\n interface TangoSchemaModelAugmentations<\n TSchema extends z.ZodObject<z.ZodRawShape> = z.ZodObject<z.ZodRawShape>,\n TKey extends string = string,\n > {\n readonly objects: ModelManager<PersistedModelOutput<TSchema>, Model<TSchema, TKey>>;\n }\n}\n\nregisterModelObjects();\n\nexport { registerModelObjects } from '../manager/registerModelObjects';\nexport { TangoRuntime } from './TangoRuntime';\nexport { getTangoRuntime, initializeTangoRuntime, resetTangoRuntime } from './defaultRuntime';\n"],"mappings":";;;;;;;;;;;;;AAkBA,sBAAsB"}
@@ -0,0 +1,32 @@
1
+ export interface OnCommitOptions {
2
+ robust?: boolean;
3
+ }
4
+ export interface SavepointOptions {
5
+ throwOnError?: boolean;
6
+ }
7
+ /**
8
+ * Result returned by `tx.savepoint(...)`.
9
+ */
10
+ export type SavepointResult<T> = {
11
+ ok: true;
12
+ value: T;
13
+ } | {
14
+ ok: false;
15
+ error: unknown;
16
+ };
17
+ export interface AtomicTransaction {
18
+ /**
19
+ * Register a callback that should run only after the outermost transaction commit succeeds.
20
+ */
21
+ onCommit(callback: () => void, options?: OnCommitOptions): void;
22
+ /**
23
+ * Run work inside a nested savepoint and, by default, capture rollback as a result object instead of throwing.
24
+ */
25
+ savepoint<T>(work: (tx: AtomicTransaction) => Promise<T> | T): Promise<SavepointResult<T>>;
26
+ savepoint<T>(work: (tx: AtomicTransaction) => Promise<T> | T, options: {
27
+ throwOnError: false;
28
+ }): Promise<SavepointResult<T>>;
29
+ savepoint<T>(work: (tx: AtomicTransaction) => Promise<T> | T, options: {
30
+ throwOnError: true;
31
+ }): Promise<T>;
32
+ }
@@ -15,6 +15,9 @@ import type { DBClient } from '../connection/clients/DBClient';
15
15
  * throw error;
16
16
  * }
17
17
  * ```
18
+ *
19
+ * @deprecated Use `transaction.atomic(async (tx) => { ... })` for application
20
+ * transaction workflows. `UnitOfWork` remains exported only for compatibility.
18
21
  */
19
22
  export declare class UnitOfWork {
20
23
  static readonly BRAND: "tango.orm.unit_of_work";
@@ -0,0 +1,2 @@
1
+ import type { AtomicTransaction } from './AtomicTransaction';
2
+ export declare function atomic<T>(work: (tx: AtomicTransaction) => Promise<T> | T): Promise<T>;
@@ -1,4 +1,6 @@
1
1
  /**
2
2
  * Domain boundary barrel: centralizes this subdomain's public contract.
3
3
  */
4
+ export { atomic } from './atomic';
5
+ export type { AtomicTransaction, OnCommitOptions, SavepointOptions, SavepointResult } from './AtomicTransaction';
4
6
  export { UnitOfWork } from './UnitOfWork';
@@ -1,3 +1,6 @@
1
- import { UnitOfWork } from "../transaction-DooTMuAl.js";
1
+ import "../PostgresClient-BQJZfEOT.js";
2
+ import "../SqliteClient-CjOK9-ki.js";
3
+ import "../defaultRuntime-BPK9kWEW.js";
4
+ import { UnitOfWork, atomic } from "../transaction-Cs0Z9tbW.js";
2
5
 
3
- export { UnitOfWork };
6
+ export { UnitOfWork, atomic };
@@ -0,0 +1,21 @@
1
+ import type { TangoRuntime } from '../../../runtime/TangoRuntime';
2
+ import type { TransactionClientLease } from '../../../runtime/internal/DBClientProvider';
3
+ import type { AtomicTransaction, SavepointOptions, SavepointResult } from '../../AtomicTransaction';
4
+ import type { TransactionState } from './TransactionState';
5
+ export declare class AsyncLocalTransactionEngine {
6
+ private readonly logger;
7
+ private readonly storage;
8
+ assertNoActiveAtomicTransaction(): void;
9
+ getActiveTransaction(runtime: TangoRuntime): AtomicTransaction | undefined;
10
+ getActiveLease(runtime: TangoRuntime): TransactionClientLease | undefined;
11
+ atomic<T>(runtime: TangoRuntime, work: (tx: AtomicTransaction) => Promise<T> | T): Promise<T>;
12
+ runSavepoint<T>(state: TransactionState, work: (tx: AtomicTransaction) => Promise<T> | T, options: SavepointOptions): Promise<T | SavepointResult<T>>;
13
+ private runNested;
14
+ private pushFrame;
15
+ private popFrame;
16
+ private rollbackOuter;
17
+ private runCommittedCallbacks;
18
+ private deactivateAllFrames;
19
+ private attachCause;
20
+ private isErrorValue;
21
+ }
@@ -0,0 +1,5 @@
1
+ export type CallbackRecord = {
2
+ order: number;
3
+ callback: () => void;
4
+ robust: boolean;
5
+ };
@@ -0,0 +1,20 @@
1
+ import type { AtomicTransaction, OnCommitOptions, SavepointResult } from '../../AtomicTransaction';
2
+ import type { AsyncLocalTransactionEngine } from './AsyncLocalTransactionEngine';
3
+ import type { TransactionFrame } from './TransactionFrame';
4
+ import type { TransactionState } from './TransactionState';
5
+ export declare class FrameBoundTransaction implements AtomicTransaction {
6
+ private readonly engine;
7
+ private readonly state;
8
+ private readonly frame;
9
+ private active;
10
+ constructor(engine: AsyncLocalTransactionEngine, state: TransactionState, frame: TransactionFrame);
11
+ onCommit(callback: () => void, options?: OnCommitOptions): void;
12
+ savepoint<T>(work: (tx: AtomicTransaction) => Promise<T> | T): Promise<SavepointResult<T>>;
13
+ savepoint<T>(work: (tx: AtomicTransaction) => Promise<T> | T, options: {
14
+ throwOnError: false;
15
+ }): Promise<SavepointResult<T>>;
16
+ savepoint<T>(work: (tx: AtomicTransaction) => Promise<T> | T, options: {
17
+ throwOnError: true;
18
+ }): Promise<T>;
19
+ deactivate(): void;
20
+ }
@@ -0,0 +1,4 @@
1
+ import type { AtomicTransaction } from '../../AtomicTransaction';
2
+ export interface FrameTransactionHandle extends AtomicTransaction {
3
+ deactivate(): void;
4
+ }
@@ -0,0 +1,16 @@
1
+ import type { TangoRuntime } from '../../../runtime/TangoRuntime';
2
+ import type { TransactionClientLease } from '../../../runtime/internal/DBClientProvider';
3
+ import type { AtomicTransaction } from '../../AtomicTransaction';
4
+ /**
5
+ * Runtime-bound transaction facade used by internal ORM/runtime components.
6
+ */
7
+ export declare class TransactionEngine {
8
+ private readonly runtime;
9
+ private static readonly engine;
10
+ private constructor();
11
+ static forRuntime(runtime: TangoRuntime): TransactionEngine;
12
+ static assertNoActiveAtomicTransaction(): void;
13
+ getActiveTransaction(): AtomicTransaction | undefined;
14
+ getActiveLease(): TransactionClientLease | undefined;
15
+ atomic<T>(work: (tx: AtomicTransaction) => Promise<T> | T): Promise<T>;
16
+ }
@@ -0,0 +1,7 @@
1
+ import type { CallbackRecord } from './CallbackRecord';
2
+ import type { FrameTransactionHandle } from './FrameTransactionHandle';
3
+ export type TransactionFrame = {
4
+ callbacks: CallbackRecord[];
5
+ facade: FrameTransactionHandle;
6
+ savepointName?: string;
7
+ };
@@ -0,0 +1,10 @@
1
+ import type { TangoRuntime } from '../../../runtime/TangoRuntime';
2
+ import type { TransactionClientLease } from '../../../runtime/internal/DBClientProvider';
3
+ import type { TransactionFrame } from './TransactionFrame';
4
+ export type TransactionState = {
5
+ runtime: TangoRuntime;
6
+ lease: TransactionClientLease;
7
+ frames: TransactionFrame[];
8
+ nextCallbackOrder: number;
9
+ nextSavepointId: number;
10
+ };
@@ -0,0 +1 @@
1
+ export { TransactionEngine } from './TransactionEngine';