sqlstack 2.0.0 → 3.1.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 (156) hide show
  1. package/dist/cjs/codegen/generateManifest.d.ts +12 -0
  2. package/dist/cjs/codegen/generateManifest.d.ts.map +1 -1
  3. package/dist/cjs/codegen/generateManifest.js +21 -11
  4. package/dist/cjs/codegen/generateManifest.js.map +1 -1
  5. package/dist/cjs/core/resolver.d.ts +25 -12
  6. package/dist/cjs/core/resolver.d.ts.map +1 -1
  7. package/dist/cjs/core/resolver.js +66 -20
  8. package/dist/cjs/core/resolver.js.map +1 -1
  9. package/dist/cjs/core/sourceScanResolver.d.ts +25 -0
  10. package/dist/cjs/core/sourceScanResolver.d.ts.map +1 -0
  11. package/dist/cjs/core/sourceScanResolver.js +56 -0
  12. package/dist/cjs/core/sourceScanResolver.js.map +1 -0
  13. package/dist/cjs/decorators/query.d.ts.map +1 -1
  14. package/dist/cjs/decorators/query.js +276 -245
  15. package/dist/cjs/decorators/query.js.map +1 -1
  16. package/dist/cjs/families/sqliteFamily.d.ts +26 -0
  17. package/dist/cjs/families/sqliteFamily.d.ts.map +1 -0
  18. package/dist/cjs/families/sqliteFamily.js +187 -0
  19. package/dist/cjs/families/sqliteFamily.js.map +1 -0
  20. package/dist/cjs/family.d.ts +69 -0
  21. package/dist/cjs/family.d.ts.map +1 -0
  22. package/dist/cjs/family.js +206 -0
  23. package/dist/cjs/family.js.map +1 -0
  24. package/dist/cjs/familyBinding.d.ts +22 -0
  25. package/dist/cjs/familyBinding.d.ts.map +1 -0
  26. package/dist/cjs/familyBinding.js +22 -0
  27. package/dist/cjs/familyBinding.js.map +1 -0
  28. package/dist/cjs/index.d.ts +10 -1
  29. package/dist/cjs/index.d.ts.map +1 -1
  30. package/dist/cjs/index.js +17 -2
  31. package/dist/cjs/index.js.map +1 -1
  32. package/dist/cjs/ioc.d.ts +22 -0
  33. package/dist/cjs/ioc.d.ts.map +1 -0
  34. package/dist/cjs/ioc.js +35 -0
  35. package/dist/cjs/ioc.js.map +1 -0
  36. package/dist/cjs/run.d.ts +29 -0
  37. package/dist/cjs/run.d.ts.map +1 -0
  38. package/dist/cjs/run.js +38 -0
  39. package/dist/cjs/run.js.map +1 -0
  40. package/dist/cjs/runtime.d.ts +25 -0
  41. package/dist/cjs/runtime.d.ts.map +1 -0
  42. package/dist/cjs/runtime.js +133 -0
  43. package/dist/cjs/runtime.js.map +1 -0
  44. package/dist/cjs/stack.d.ts +101 -0
  45. package/dist/cjs/stack.d.ts.map +1 -0
  46. package/dist/cjs/stack.js +288 -0
  47. package/dist/cjs/stack.js.map +1 -0
  48. package/dist/cjs/testing/builder.d.ts +29 -0
  49. package/dist/cjs/testing/builder.d.ts.map +1 -0
  50. package/dist/cjs/testing/builder.js +131 -0
  51. package/dist/cjs/testing/builder.js.map +1 -0
  52. package/dist/cjs/testing/index.d.ts +14 -0
  53. package/dist/cjs/testing/index.d.ts.map +1 -0
  54. package/dist/cjs/testing/index.js +22 -0
  55. package/dist/cjs/testing/index.js.map +1 -0
  56. package/dist/cjs/testing/postgres/allocator.d.ts +17 -0
  57. package/dist/cjs/testing/postgres/allocator.d.ts.map +1 -0
  58. package/dist/cjs/testing/postgres/allocator.js +54 -0
  59. package/dist/cjs/testing/postgres/allocator.js.map +1 -0
  60. package/dist/cjs/testing/postgres/database.d.ts +21 -0
  61. package/dist/cjs/testing/postgres/database.d.ts.map +1 -0
  62. package/dist/cjs/testing/postgres/database.js +39 -0
  63. package/dist/cjs/testing/postgres/database.js.map +1 -0
  64. package/dist/cjs/testing/postgres/loadData.d.ts +31 -0
  65. package/dist/cjs/testing/postgres/loadData.d.ts.map +1 -0
  66. package/dist/cjs/testing/postgres/loadData.js +184 -0
  67. package/dist/cjs/testing/postgres/loadData.js.map +1 -0
  68. package/dist/cjs/testing/postgres/server.d.ts +19 -0
  69. package/dist/cjs/testing/postgres/server.d.ts.map +1 -0
  70. package/dist/cjs/testing/postgres/server.js +78 -0
  71. package/dist/cjs/testing/postgres/server.js.map +1 -0
  72. package/dist/cjs/testing/schema/ddl.d.ts +5 -0
  73. package/dist/cjs/testing/schema/ddl.d.ts.map +1 -0
  74. package/dist/cjs/testing/schema/ddl.js +70 -0
  75. package/dist/cjs/testing/schema/ddl.js.map +1 -0
  76. package/dist/cjs/testing/schema/normalize.d.ts +7 -0
  77. package/dist/cjs/testing/schema/normalize.d.ts.map +1 -0
  78. package/dist/cjs/testing/schema/normalize.js +202 -0
  79. package/dist/cjs/testing/schema/normalize.js.map +1 -0
  80. package/dist/cjs/testing/schema/parser.d.ts +9 -0
  81. package/dist/cjs/testing/schema/parser.d.ts.map +1 -0
  82. package/dist/cjs/testing/schema/parser.js +80 -0
  83. package/dist/cjs/testing/schema/parser.js.map +1 -0
  84. package/dist/cjs/testing/schema/types.d.ts +63 -0
  85. package/dist/cjs/testing/schema/types.d.ts.map +1 -0
  86. package/dist/cjs/testing/schema/types.js +6 -0
  87. package/dist/cjs/testing/schema/types.js.map +1 -0
  88. package/dist/cjs/testing/sqlite/builder.d.ts +24 -0
  89. package/dist/cjs/testing/sqlite/builder.d.ts.map +1 -0
  90. package/dist/cjs/testing/sqlite/builder.js +134 -0
  91. package/dist/cjs/testing/sqlite/builder.js.map +1 -0
  92. package/dist/cjs/testing/sqlite/database.d.ts +18 -0
  93. package/dist/cjs/testing/sqlite/database.d.ts.map +1 -0
  94. package/dist/cjs/testing/sqlite/database.js +123 -0
  95. package/dist/cjs/testing/sqlite/database.js.map +1 -0
  96. package/dist/cjs/testing/sqlite/loadData.d.ts +7 -0
  97. package/dist/cjs/testing/sqlite/loadData.d.ts.map +1 -0
  98. package/dist/cjs/testing/sqlite/loadData.js +55 -0
  99. package/dist/cjs/testing/sqlite/loadData.js.map +1 -0
  100. package/dist/cjs/transactions.d.ts +14 -5
  101. package/dist/cjs/transactions.d.ts.map +1 -1
  102. package/dist/cjs/transactions.js +40 -24
  103. package/dist/cjs/transactions.js.map +1 -1
  104. package/dist/esm/codegen/generateManifest.js +20 -11
  105. package/dist/esm/codegen/generateManifest.js.map +1 -1
  106. package/dist/esm/core/resolver.js +59 -19
  107. package/dist/esm/core/resolver.js.map +1 -1
  108. package/dist/esm/core/sourceScanResolver.js +51 -0
  109. package/dist/esm/core/sourceScanResolver.js.map +1 -0
  110. package/dist/esm/decorators/query.js +278 -247
  111. package/dist/esm/decorators/query.js.map +1 -1
  112. package/dist/esm/families/sqliteFamily.js +151 -0
  113. package/dist/esm/families/sqliteFamily.js.map +1 -0
  114. package/dist/esm/family.js +202 -0
  115. package/dist/esm/family.js.map +1 -0
  116. package/dist/esm/familyBinding.js +18 -0
  117. package/dist/esm/familyBinding.js.map +1 -0
  118. package/dist/esm/index.js +10 -1
  119. package/dist/esm/index.js.map +1 -1
  120. package/dist/esm/ioc.js +32 -0
  121. package/dist/esm/ioc.js.map +1 -0
  122. package/dist/esm/run.js +34 -0
  123. package/dist/esm/run.js.map +1 -0
  124. package/dist/esm/runtime.js +94 -0
  125. package/dist/esm/runtime.js.map +1 -0
  126. package/dist/esm/stack.js +251 -0
  127. package/dist/esm/stack.js.map +1 -0
  128. package/dist/esm/testing/builder.js +95 -0
  129. package/dist/esm/testing/builder.js.map +1 -0
  130. package/dist/esm/testing/index.js +9 -0
  131. package/dist/esm/testing/index.js.map +1 -0
  132. package/dist/esm/testing/postgres/allocator.js +49 -0
  133. package/dist/esm/testing/postgres/allocator.js.map +1 -0
  134. package/dist/esm/testing/postgres/database.js +36 -0
  135. package/dist/esm/testing/postgres/database.js.map +1 -0
  136. package/dist/esm/testing/postgres/loadData.js +176 -0
  137. package/dist/esm/testing/postgres/loadData.js.map +1 -0
  138. package/dist/esm/testing/postgres/server.js +69 -0
  139. package/dist/esm/testing/postgres/server.js.map +1 -0
  140. package/dist/esm/testing/schema/ddl.js +65 -0
  141. package/dist/esm/testing/schema/ddl.js.map +1 -0
  142. package/dist/esm/testing/schema/normalize.js +164 -0
  143. package/dist/esm/testing/schema/normalize.js.map +1 -0
  144. package/dist/esm/testing/schema/parser.js +43 -0
  145. package/dist/esm/testing/schema/parser.js.map +1 -0
  146. package/dist/esm/testing/schema/types.js +5 -0
  147. package/dist/esm/testing/schema/types.js.map +1 -0
  148. package/dist/esm/testing/sqlite/builder.js +98 -0
  149. package/dist/esm/testing/sqlite/builder.js.map +1 -0
  150. package/dist/esm/testing/sqlite/database.js +85 -0
  151. package/dist/esm/testing/sqlite/database.js.map +1 -0
  152. package/dist/esm/testing/sqlite/loadData.js +48 -0
  153. package/dist/esm/testing/sqlite/loadData.js.map +1 -0
  154. package/dist/esm/transactions.js +39 -24
  155. package/dist/esm/transactions.js.map +1 -1
  156. package/package.json +19 -2
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+ /**
3
+ * Types for the sqlstack/testing versioned YAML test-schema.
4
+ */
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../../src/testing/schema/types.ts"],"names":[],"mappings":";AAAA;;GAEG","sourcesContent":["/**\n * Types for the sqlstack/testing versioned YAML test-schema.\n */\n\nexport interface TestColumnInput {\n type: string;\n nullable?: boolean;\n primary?: boolean;\n unique?: boolean;\n /** Raw SQL default expression (emitted verbatim into DDL). */\n default?: string | number | boolean;\n /** Reference target: \"table.column\" or \"table(column)\". */\n references?: string;\n}\n\nexport interface TestTableInput {\n columns: Record<string, string | TestColumnInput>;\n}\n\nexport interface TestSchemaInput {\n version: number;\n dialect: string;\n tables?: Record<string, TestTableInput>;\n sql?: string[];\n}\n\nexport interface NormalizedReference {\n readonly table: string;\n readonly column: string;\n}\n\nexport interface NormalizedColumn {\n readonly name: string;\n readonly type: string;\n readonly nullable: boolean;\n readonly primary: boolean;\n readonly unique: boolean;\n readonly hasDefault: boolean;\n readonly default?: string | number | boolean;\n readonly references?: NormalizedReference;\n}\n\nexport interface NormalizedTable {\n readonly name: string;\n readonly columns: readonly NormalizedColumn[];\n readonly primaryKey: readonly string[];\n}\n\nexport type RawSqlEntry =\n | { readonly kind: 'inline'; readonly index: number; readonly sql: string }\n | {\n readonly kind: 'file';\n readonly index: number;\n readonly sourcePath: string;\n readonly resolvedPath: string;\n };\n\nexport interface NormalizedTestSchema {\n readonly version: 1;\n readonly dialect: 'postgres' | 'sqlite';\n readonly tables: readonly NormalizedTable[];\n readonly sql: readonly RawSqlEntry[];\n readonly source: string;\n}\n\nexport interface ParseTestSchemaOptions {\n sourceDir?: string;\n sourceLabel?: string;\n}\n"]}
@@ -0,0 +1,24 @@
1
+ import type { NormalizedTestSchema, ParseTestSchemaOptions } from '../schema/types';
2
+ import { TestSqliteDatabase } from './database';
3
+ import { DataOperation, Row } from './loadData';
4
+ export interface TestSqliteOptions extends ParseTestSchemaOptions {
5
+ /**
6
+ * Storage for the test database. Defaults to `'file'`: an owned temporary
7
+ * file, removed on `dispose()`. Pass `'memory'` to opt back into an isolated
8
+ * `:memory:` database — only worth it for a test that opens many databases
9
+ * and never touches restart behavior.
10
+ */
11
+ mode?: 'memory' | 'file';
12
+ /** Legacy alias for `mode`. `false` selects `:memory:`. */
13
+ fileBacked?: boolean;
14
+ /** Legacy alias for `mode`. `false` selects `:memory:`. */
15
+ tempFile?: boolean;
16
+ }
17
+ export interface TestSqliteBuilder {
18
+ readonly schema: NormalizedTestSchema;
19
+ readonly ops: readonly DataOperation[];
20
+ data(rows: Record<string, Row[]>): TestSqliteBuilder;
21
+ build(): Promise<TestSqliteDatabase>;
22
+ }
23
+ export declare function testSqlite(schema: string | object, options?: TestSqliteOptions): TestSqliteBuilder;
24
+ //# sourceMappingURL=builder.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"builder.d.ts","sourceRoot":"","sources":["../../../../src/testing/sqlite/builder.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,oBAAoB,EAAE,sBAAsB,EAAE,MAAM,iBAAiB,CAAC;AACpF,OAAO,EAAwB,kBAAkB,EAAmB,MAAM,YAAY,CAAC;AACvF,OAAO,EAAe,aAAa,EAAc,GAAG,EAAgB,MAAM,YAAY,CAAC;AAEvF,MAAM,WAAW,iBAAkB,SAAQ,sBAAsB;IAC/D;;;;;OAKG;IACH,IAAI,CAAC,EAAE,QAAQ,GAAG,MAAM,CAAC;IACzB,2DAA2D;IAC3D,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,2DAA2D;IAC3D,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,MAAM,EAAE,oBAAoB,CAAC;IACtC,QAAQ,CAAC,GAAG,EAAE,SAAS,aAAa,EAAE,CAAC;IACvC,IAAI,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,EAAE,CAAC,GAAG,iBAAiB,CAAC;IACrD,KAAK,IAAI,OAAO,CAAC,kBAAkB,CAAC,CAAC;CACtC;AAoFD,wBAAgB,UAAU,CACxB,MAAM,EAAE,MAAM,GAAG,MAAM,EACvB,OAAO,GAAE,iBAAsB,GAC9B,iBAAiB,CAcnB"}
@@ -0,0 +1,134 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.testSqlite = testSqlite;
37
+ const fs = __importStar(require("node:fs"));
38
+ const ddl_1 = require("../schema/ddl");
39
+ const parser_1 = require("../schema/parser");
40
+ const database_1 = require("./database");
41
+ const loadData_1 = require("./loadData");
42
+ function readRawSql(schema) {
43
+ return schema.sql.map((entry) => {
44
+ if (entry.kind === 'inline') {
45
+ return { label: `sql entry #${entry.index} (inline)`, sql: entry.sql };
46
+ }
47
+ try {
48
+ return {
49
+ label: `sql entry #${entry.index} (${entry.sourcePath})`,
50
+ sql: fs.readFileSync(entry.resolvedPath, 'utf8'),
51
+ };
52
+ }
53
+ catch (err) {
54
+ throw new database_1.TestSqliteError(`Cannot read raw SQL file for sql entry #${entry.index}: ${entry.resolvedPath} ` +
55
+ `(authored as "${entry.sourcePath}" in ${schema.source}): ${err.message}`);
56
+ }
57
+ });
58
+ }
59
+ async function executeRaw(handle, sql) {
60
+ const conn = handle.conn;
61
+ if (typeof conn?.exec === 'function') {
62
+ await conn.exec(sql);
63
+ }
64
+ else {
65
+ await handle.db.query(sql, []);
66
+ }
67
+ }
68
+ function makeBuilder(state) {
69
+ return {
70
+ schema: state.schema,
71
+ ops: state.ops,
72
+ data(rows) {
73
+ return makeBuilder({
74
+ ...state,
75
+ ops: [...state.ops, ...(0, loadData_1.toOperations)(state.schema, rows)],
76
+ });
77
+ },
78
+ async build() {
79
+ const rawSql = readRawSql(state.schema);
80
+ const ddl = (0, ddl_1.generateDdl)(state.schema);
81
+ const effective = (0, loadData_1.composeRows)(state.schema, state.ops);
82
+ const fileBacked = state.options.mode
83
+ ? state.options.mode === 'file'
84
+ : state.options.fileBacked !== false && state.options.tempFile !== false;
85
+ const handle = await (0, database_1.createDatabaseHandle)(fileBacked);
86
+ try {
87
+ for (const statement of ddl) {
88
+ try {
89
+ await handle.db.query(statement, []);
90
+ }
91
+ catch (err) {
92
+ throw new database_1.TestSqliteError(`Failed to apply structured DDL from ${state.schema.source}: ${err.message}\n` +
93
+ `Statement:\n${statement}`);
94
+ }
95
+ }
96
+ for (const entry of rawSql) {
97
+ try {
98
+ await executeRaw(handle, entry.sql);
99
+ }
100
+ catch (err) {
101
+ throw new database_1.TestSqliteError(`Failed to apply raw ${entry.label} from ${state.schema.source}: ${err.message}`);
102
+ }
103
+ }
104
+ await (0, loadData_1.insertRows)((sql, params) => handle.db.query(sql, params), state.schema, effective);
105
+ return handle;
106
+ }
107
+ catch (err) {
108
+ await handle.dispose();
109
+ throw err;
110
+ }
111
+ },
112
+ };
113
+ }
114
+ function testSqlite(schema, options = {}) {
115
+ const normalized = isNormalizedSchema(schema)
116
+ ? schema
117
+ : (0, parser_1.parseTestSchema)(schema, options);
118
+ if (normalized.dialect !== 'sqlite') {
119
+ throw new database_1.TestSqliteError(`testSqlite requires a schema with dialect: sqlite (received: ${normalized.dialect})`);
120
+ }
121
+ return makeBuilder({
122
+ schema: normalized,
123
+ ops: [],
124
+ options: Object.freeze({ ...options }),
125
+ });
126
+ }
127
+ function isNormalizedSchema(input) {
128
+ return (!!input &&
129
+ typeof input === 'object' &&
130
+ Array.isArray(input.tables) &&
131
+ Array.isArray(input.sql) &&
132
+ typeof input.source === 'string');
133
+ }
134
+ //# sourceMappingURL=builder.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"builder.js","sourceRoot":"","sources":["../../../../src/testing/sqlite/builder.ts"],"names":[],"mappings":"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","sourcesContent":["import * as fs from 'node:fs';\nimport { generateDdl } from '../schema/ddl';\nimport { parseTestSchema } from '../schema/parser';\nimport type { NormalizedTestSchema, ParseTestSchemaOptions } from '../schema/types';\nimport { createDatabaseHandle, TestSqliteDatabase, TestSqliteError } from './database';\nimport { composeRows, DataOperation, insertRows, Row, toOperations } from './loadData';\n\nexport interface TestSqliteOptions extends ParseTestSchemaOptions {\n /**\n * Storage for the test database. Defaults to `'file'`: an owned temporary\n * file, removed on `dispose()`. Pass `'memory'` to opt back into an isolated\n * `:memory:` database — only worth it for a test that opens many databases\n * and never touches restart behavior.\n */\n mode?: 'memory' | 'file';\n /** Legacy alias for `mode`. `false` selects `:memory:`. */\n fileBacked?: boolean;\n /** Legacy alias for `mode`. `false` selects `:memory:`. */\n tempFile?: boolean;\n}\n\nexport interface TestSqliteBuilder {\n readonly schema: NormalizedTestSchema;\n readonly ops: readonly DataOperation[];\n data(rows: Record<string, Row[]>): TestSqliteBuilder;\n build(): Promise<TestSqliteDatabase>;\n}\n\ninterface BuilderState {\n readonly schema: NormalizedTestSchema;\n readonly ops: readonly DataOperation[];\n readonly options: Readonly<TestSqliteOptions>;\n}\n\nfunction readRawSql(schema: NormalizedTestSchema): { label: string; sql: string }[] {\n return schema.sql.map((entry) => {\n if (entry.kind === 'inline') {\n return { label: `sql entry #${entry.index} (inline)`, sql: entry.sql };\n }\n try {\n return {\n label: `sql entry #${entry.index} (${entry.sourcePath})`,\n sql: fs.readFileSync(entry.resolvedPath, 'utf8'),\n };\n } catch (err) {\n throw new TestSqliteError(\n `Cannot read raw SQL file for sql entry #${entry.index}: ${entry.resolvedPath} ` +\n `(authored as \"${entry.sourcePath}\" in ${schema.source}): ${(err as Error).message}`\n );\n }\n });\n}\n\nasync function executeRaw(handle: TestSqliteDatabase, sql: string): Promise<void> {\n const conn = handle.conn as { exec?: (sql: string) => unknown };\n if (typeof conn?.exec === 'function') {\n await conn.exec(sql);\n } else {\n await handle.db.query(sql, []);\n }\n}\n\nfunction makeBuilder(state: BuilderState): TestSqliteBuilder {\n return {\n schema: state.schema,\n ops: state.ops,\n data(rows: Record<string, Row[]>): TestSqliteBuilder {\n return makeBuilder({\n ...state,\n ops: [...state.ops, ...toOperations(state.schema, rows)],\n });\n },\n async build(): Promise<TestSqliteDatabase> {\n const rawSql = readRawSql(state.schema);\n const ddl = generateDdl(state.schema);\n const effective = composeRows(state.schema, state.ops);\n const fileBacked = state.options.mode\n ? state.options.mode === 'file'\n : state.options.fileBacked !== false && state.options.tempFile !== false;\n const handle = await createDatabaseHandle(fileBacked);\n try {\n for (const statement of ddl) {\n try {\n await handle.db.query(statement, []);\n } catch (err) {\n throw new TestSqliteError(\n `Failed to apply structured DDL from ${state.schema.source}: ${(err as Error).message}\\n` +\n `Statement:\\n${statement}`\n );\n }\n }\n for (const entry of rawSql) {\n try {\n await executeRaw(handle, entry.sql);\n } catch (err) {\n throw new TestSqliteError(\n `Failed to apply raw ${entry.label} from ${state.schema.source}: ${(err as Error).message}`\n );\n }\n }\n await insertRows((sql, params) => handle.db.query(sql, params), state.schema, effective);\n return handle;\n } catch (err) {\n await handle.dispose();\n throw err;\n }\n },\n };\n}\n\nexport function testSqlite(\n schema: string | object,\n options: TestSqliteOptions = {}\n): TestSqliteBuilder {\n const normalized = isNormalizedSchema(schema)\n ? schema\n : parseTestSchema(schema as string | object, options);\n if (normalized.dialect !== 'sqlite') {\n throw new TestSqliteError(\n `testSqlite requires a schema with dialect: sqlite (received: ${normalized.dialect})`\n );\n }\n return makeBuilder({\n schema: normalized,\n ops: [],\n options: Object.freeze({ ...options }),\n });\n}\n\nfunction isNormalizedSchema(input: unknown): input is NormalizedTestSchema {\n return (\n !!input &&\n typeof input === 'object' &&\n Array.isArray((input as NormalizedTestSchema).tables) &&\n Array.isArray((input as NormalizedTestSchema).sql) &&\n typeof (input as NormalizedTestSchema).source === 'string'\n );\n}\n"]}
@@ -0,0 +1,18 @@
1
+ import { SqlStackError } from '../../core/errors';
2
+ import type { Database } from '../../registry';
3
+ export declare class TestSqliteError extends SqlStackError {
4
+ constructor(message: string);
5
+ }
6
+ export interface TestSqliteDatabase {
7
+ /** The live sqlstack SQLite adapter, suitable for direct injection. */
8
+ readonly db: Database;
9
+ /** The underlying better-sqlite3 (or sqlite3) connection. */
10
+ readonly conn: unknown;
11
+ /** Absolute database path in file mode; undefined for :memory:. */
12
+ readonly path?: string;
13
+ query(sql: string, params?: readonly unknown[]): Promise<unknown>;
14
+ /** Close the connection and remove owned temporary files. Idempotent. */
15
+ dispose(): Promise<void>;
16
+ }
17
+ export declare function createDatabaseHandle(fileBacked: boolean): Promise<TestSqliteDatabase>;
18
+ //# sourceMappingURL=database.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"database.d.ts","sourceRoot":"","sources":["../../../../src/testing/sqlite/database.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAClD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAE/C,qBAAa,eAAgB,SAAQ,aAAa;gBACpC,OAAO,EAAE,MAAM;CAI5B;AAED,MAAM,WAAW,kBAAkB;IACjC,uEAAuE;IACvE,QAAQ,CAAC,EAAE,EAAE,QAAQ,CAAC;IACtB,6DAA6D;IAC7D,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IACvB,mEAAmE;IACnE,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,SAAS,OAAO,EAAE,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAClE,yEAAyE;IACzE,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CAC1B;AAyBD,wBAAsB,oBAAoB,CACxC,UAAU,EAAE,OAAO,GAClB,OAAO,CAAC,kBAAkB,CAAC,CA+C7B"}
@@ -0,0 +1,123 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.TestSqliteError = void 0;
37
+ exports.createDatabaseHandle = createDatabaseHandle;
38
+ const fs = __importStar(require("node:fs"));
39
+ const os = __importStar(require("node:os"));
40
+ const path = __importStar(require("node:path"));
41
+ const sqlite_1 = require("../../adapters/sqlite");
42
+ const errors_1 = require("../../core/errors");
43
+ class TestSqliteError extends errors_1.SqlStackError {
44
+ constructor(message) {
45
+ super(message);
46
+ this.name = 'TestSqliteError';
47
+ }
48
+ }
49
+ exports.TestSqliteError = TestSqliteError;
50
+ /**
51
+ * Temp directories for file-backed handles that were never disposed. Tests are
52
+ * expected to call `dispose()`, but a failed assertion can skip it; this keeps
53
+ * an abandoned directory from outliving the worker process.
54
+ */
55
+ const abandonedDirectories = new Set();
56
+ let exitCleanupRegistered = false;
57
+ function trackDirectory(directory) {
58
+ abandonedDirectories.add(directory);
59
+ if (exitCleanupRegistered)
60
+ return;
61
+ exitCleanupRegistered = true;
62
+ process.once('exit', () => {
63
+ for (const dir of abandonedDirectories) {
64
+ try {
65
+ fs.rmSync(dir, { recursive: true, force: true });
66
+ }
67
+ catch {
68
+ /* best-effort cleanup */
69
+ }
70
+ }
71
+ });
72
+ }
73
+ async function createDatabaseHandle(fileBacked) {
74
+ let directory;
75
+ let filename = ':memory:';
76
+ if (fileBacked) {
77
+ directory = fs.mkdtempSync(path.join(os.tmpdir(), 'sqlstack-test-'));
78
+ filename = path.join(directory, 'database.sqlite');
79
+ trackDirectory(directory);
80
+ }
81
+ let db;
82
+ try {
83
+ db = await (0, sqlite_1.createSqliteDb)(filename);
84
+ }
85
+ catch (err) {
86
+ if (directory) {
87
+ fs.rmSync(directory, { recursive: true, force: true });
88
+ abandonedDirectories.delete(directory);
89
+ }
90
+ const message = err.message;
91
+ if (message.includes('No SQLite driver available')) {
92
+ throw new TestSqliteError('testSqlite requires the optional peer "better-sqlite3".');
93
+ }
94
+ throw new TestSqliteError(`Failed to create SQLite test database: ${message}`);
95
+ }
96
+ let disposed = false;
97
+ return {
98
+ db,
99
+ conn: db.conn,
100
+ path: fileBacked ? filename : undefined,
101
+ async query(sql, params = []) {
102
+ if (disposed)
103
+ throw new TestSqliteError('Test SQLite database has been disposed.');
104
+ return db.query(sql, [...params]);
105
+ },
106
+ async dispose() {
107
+ if (disposed)
108
+ return;
109
+ disposed = true;
110
+ try {
111
+ await db.close();
112
+ }
113
+ catch {
114
+ /* connection may already be closed */
115
+ }
116
+ if (directory) {
117
+ fs.rmSync(directory, { recursive: true, force: true });
118
+ abandonedDirectories.delete(directory);
119
+ }
120
+ },
121
+ };
122
+ }
123
+ //# sourceMappingURL=database.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"database.js","sourceRoot":"","sources":["../../../../src/testing/sqlite/database.ts"],"names":[],"mappings":"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","sourcesContent":["import * as fs from 'node:fs';\nimport * as os from 'node:os';\nimport * as path from 'node:path';\nimport { createSqliteDb } from '../../adapters/sqlite';\nimport { SqlStackError } from '../../core/errors';\nimport type { Database } from '../../registry';\n\nexport class TestSqliteError extends SqlStackError {\n constructor(message: string) {\n super(message);\n this.name = 'TestSqliteError';\n }\n}\n\nexport interface TestSqliteDatabase {\n /** The live sqlstack SQLite adapter, suitable for direct injection. */\n readonly db: Database;\n /** The underlying better-sqlite3 (or sqlite3) connection. */\n readonly conn: unknown;\n /** Absolute database path in file mode; undefined for :memory:. */\n readonly path?: string;\n query(sql: string, params?: readonly unknown[]): Promise<unknown>;\n /** Close the connection and remove owned temporary files. Idempotent. */\n dispose(): Promise<void>;\n}\n\n/**\n * Temp directories for file-backed handles that were never disposed. Tests are\n * expected to call `dispose()`, but a failed assertion can skip it; this keeps\n * an abandoned directory from outliving the worker process.\n */\nconst abandonedDirectories = new Set<string>();\nlet exitCleanupRegistered = false;\n\nfunction trackDirectory(directory: string): void {\n abandonedDirectories.add(directory);\n if (exitCleanupRegistered) return;\n exitCleanupRegistered = true;\n process.once('exit', () => {\n for (const dir of abandonedDirectories) {\n try {\n fs.rmSync(dir, { recursive: true, force: true });\n } catch {\n /* best-effort cleanup */\n }\n }\n });\n}\n\nexport async function createDatabaseHandle(\n fileBacked: boolean\n): Promise<TestSqliteDatabase> {\n let directory: string | undefined;\n let filename = ':memory:';\n if (fileBacked) {\n directory = fs.mkdtempSync(path.join(os.tmpdir(), 'sqlstack-test-'));\n filename = path.join(directory, 'database.sqlite');\n trackDirectory(directory);\n }\n\n let db: Database;\n try {\n db = await createSqliteDb(filename);\n } catch (err) {\n if (directory) {\n fs.rmSync(directory, { recursive: true, force: true });\n abandonedDirectories.delete(directory);\n }\n const message = (err as Error).message;\n if (message.includes('No SQLite driver available')) {\n throw new TestSqliteError('testSqlite requires the optional peer \"better-sqlite3\".');\n }\n throw new TestSqliteError(`Failed to create SQLite test database: ${message}`);\n }\n\n let disposed = false;\n return {\n db,\n conn: db.conn,\n path: fileBacked ? filename : undefined,\n async query(sql: string, params: readonly unknown[] = []) {\n if (disposed) throw new TestSqliteError('Test SQLite database has been disposed.');\n return db.query(sql, [...params]);\n },\n async dispose() {\n if (disposed) return;\n disposed = true;\n try {\n await db.close();\n } catch {\n /* connection may already be closed */\n }\n if (directory) {\n fs.rmSync(directory, { recursive: true, force: true });\n abandonedDirectories.delete(directory);\n }\n },\n };\n}\n"]}
@@ -0,0 +1,7 @@
1
+ import type { NormalizedTestSchema } from '../schema/types';
2
+ import { TestDataError, composeRows, planInsertOrder, toOperations } from '../postgres/loadData';
3
+ import type { DataOperation, Row } from '../postgres/loadData';
4
+ export { TestDataError, composeRows, planInsertOrder, toOperations };
5
+ export type { DataOperation, Row };
6
+ export declare function insertRows(query: (sql: string, params: unknown[]) => Promise<unknown>, schema: NormalizedTestSchema, effective: Map<string, Row[]>): Promise<void>;
7
+ //# sourceMappingURL=loadData.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loadData.d.ts","sourceRoot":"","sources":["../../../../src/testing/sqlite/loadData.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAC;AAC5D,OAAO,EACL,aAAa,EACb,WAAW,EACX,eAAe,EACf,YAAY,EACb,MAAM,sBAAsB,CAAC;AAC9B,OAAO,KAAK,EAAE,aAAa,EAAE,GAAG,EAAE,MAAM,sBAAsB,CAAC;AAE/D,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,eAAe,EAAE,YAAY,EAAE,CAAC;AACrE,YAAY,EAAE,aAAa,EAAE,GAAG,EAAE,CAAC;AAEnC,wBAAsB,UAAU,CAC9B,KAAK,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,OAAO,CAAC,OAAO,CAAC,EAC3D,MAAM,EAAE,oBAAoB,EAC5B,SAAS,EAAE,GAAG,CAAC,MAAM,EAAE,GAAG,EAAE,CAAC,GAC5B,OAAO,CAAC,IAAI,CAAC,CAwCf"}
@@ -0,0 +1,55 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.toOperations = exports.planInsertOrder = exports.composeRows = exports.TestDataError = void 0;
4
+ exports.insertRows = insertRows;
5
+ const ddl_1 = require("../schema/ddl");
6
+ const loadData_1 = require("../postgres/loadData");
7
+ Object.defineProperty(exports, "TestDataError", { enumerable: true, get: function () { return loadData_1.TestDataError; } });
8
+ Object.defineProperty(exports, "composeRows", { enumerable: true, get: function () { return loadData_1.composeRows; } });
9
+ Object.defineProperty(exports, "planInsertOrder", { enumerable: true, get: function () { return loadData_1.planInsertOrder; } });
10
+ Object.defineProperty(exports, "toOperations", { enumerable: true, get: function () { return loadData_1.toOperations; } });
11
+ async function insertRows(query, schema, effective) {
12
+ const order = (0, loadData_1.planInsertOrder)(schema, [...effective.keys()]);
13
+ const declared = new Map(schema.tables.map((table) => [
14
+ table.name,
15
+ table.columns.map((column) => column.name),
16
+ ]));
17
+ for (const tableName of order) {
18
+ const rows = effective.get(tableName);
19
+ const columnOrder = declared.get(tableName);
20
+ const batches = new Map();
21
+ for (const row of rows) {
22
+ const columns = columnOrder.filter((column) => row[column] !== undefined);
23
+ const signature = columns.join(',');
24
+ const batch = batches.get(signature) ?? { columns, rows: [] };
25
+ batch.rows.push(row);
26
+ batches.set(signature, batch);
27
+ }
28
+ for (const { columns, rows: batchRows } of batches.values()) {
29
+ if (columns.length === 0) {
30
+ for (let i = 0; i < batchRows.length; i++) {
31
+ await run(query, tableName, `INSERT INTO ${(0, ddl_1.quoteIdent)(tableName)} DEFAULT VALUES`, []);
32
+ }
33
+ continue;
34
+ }
35
+ const params = [];
36
+ const tuples = batchRows.map((row) => {
37
+ const placeholders = columns.map((column) => {
38
+ params.push(row[column]);
39
+ return '?';
40
+ });
41
+ return `(${placeholders.join(', ')})`;
42
+ });
43
+ await run(query, tableName, `INSERT INTO ${(0, ddl_1.quoteIdent)(tableName)} (${columns.map(ddl_1.quoteIdent).join(', ')}) VALUES ${tuples.join(', ')}`, params);
44
+ }
45
+ }
46
+ }
47
+ async function run(query, tableName, sql, params) {
48
+ try {
49
+ await query(sql, params);
50
+ }
51
+ catch (err) {
52
+ throw new loadData_1.TestDataError(`Failed to insert scenario rows into table "${tableName}": ${err.message}`);
53
+ }
54
+ }
55
+ //# sourceMappingURL=loadData.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loadData.js","sourceRoot":"","sources":["../../../../src/testing/sqlite/loadData.ts"],"names":[],"mappings":"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","sourcesContent":["import { quoteIdent } from '../schema/ddl';\nimport type { NormalizedTestSchema } from '../schema/types';\nimport {\n TestDataError,\n composeRows,\n planInsertOrder,\n toOperations,\n} from '../postgres/loadData';\nimport type { DataOperation, Row } from '../postgres/loadData';\n\nexport { TestDataError, composeRows, planInsertOrder, toOperations };\nexport type { DataOperation, Row };\n\nexport async function insertRows(\n query: (sql: string, params: unknown[]) => Promise<unknown>,\n schema: NormalizedTestSchema,\n effective: Map<string, Row[]>\n): Promise<void> {\n const order = planInsertOrder(schema, [...effective.keys()]);\n const declared = new Map(schema.tables.map((table) => [\n table.name,\n table.columns.map((column) => column.name),\n ]));\n for (const tableName of order) {\n const rows = effective.get(tableName)!;\n const columnOrder = declared.get(tableName)!;\n const batches = new Map<string, { columns: string[]; rows: Row[] }>();\n for (const row of rows) {\n const columns = columnOrder.filter((column) => row[column] !== undefined);\n const signature = columns.join(',');\n const batch = batches.get(signature) ?? { columns, rows: [] };\n batch.rows.push(row);\n batches.set(signature, batch);\n }\n for (const { columns, rows: batchRows } of batches.values()) {\n if (columns.length === 0) {\n for (let i = 0; i < batchRows.length; i++) {\n await run(query, tableName, `INSERT INTO ${quoteIdent(tableName)} DEFAULT VALUES`, []);\n }\n continue;\n }\n const params: unknown[] = [];\n const tuples = batchRows.map((row) => {\n const placeholders = columns.map((column) => {\n params.push(row[column]);\n return '?';\n });\n return `(${placeholders.join(', ')})`;\n });\n await run(\n query,\n tableName,\n `INSERT INTO ${quoteIdent(tableName)} (${columns.map(quoteIdent).join(', ')}) VALUES ${tuples.join(', ')}`,\n params\n );\n }\n }\n}\n\nasync function run(\n query: (sql: string, params: unknown[]) => Promise<unknown>,\n tableName: string,\n sql: string,\n params: unknown[]\n): Promise<void> {\n try {\n await query(sql, params);\n } catch (err) {\n throw new TestDataError(\n `Failed to insert scenario rows into table \"${tableName}\": ${(err as Error).message}`\n );\n }\n}\n"]}
@@ -1,4 +1,5 @@
1
1
  import type { Database, QueryResult } from './registry';
2
+ import type { DatabaseEntry } from './stack';
2
3
  export type TransactionOptions = {
3
4
  db?: string;
4
5
  lazy?: boolean;
@@ -6,8 +7,9 @@ export type TransactionOptions = {
6
7
  };
7
8
  export declare class TransactionHandle {
8
9
  #private;
9
- readonly dbName: string;
10
- constructor(dbName: string, state: TxState, owned: boolean);
10
+ readonly entry: DatabaseEntry;
11
+ constructor(entry: DatabaseEntry, state: TxState, owned: boolean);
12
+ get dbName(): string;
11
13
  ensureStarted(): Promise<void>;
12
14
  rollbackOnly(errorToThrow?: unknown): void;
13
15
  commit(): Promise<void>;
@@ -17,7 +19,7 @@ export declare class TransactionHandle {
17
19
  finishOnError(err: unknown): Promise<void>;
18
20
  }
19
21
  declare class TxState {
20
- readonly dbName: string;
22
+ readonly entry: DatabaseEntry;
21
23
  readonly db: Database;
22
24
  readonly options: Required<Pick<TransactionOptions, 'lazy'>> & Pick<TransactionOptions, 'nested'>;
23
25
  depth: number;
@@ -27,7 +29,7 @@ declare class TxState {
27
29
  rollbackError: unknown | undefined;
28
30
  private txDb;
29
31
  private releaseFn;
30
- constructor(dbName: string, db: Database, options: TransactionOptions | undefined);
32
+ constructor(entry: DatabaseEntry, options: TransactionOptions | undefined);
31
33
  get activeDb(): Database;
32
34
  ensureStarted(): Promise<void>;
33
35
  query(sql: string, params: unknown[]): Promise<QueryResult>;
@@ -37,7 +39,14 @@ declare class TxState {
37
39
  finishOnSuccess(): Promise<void>;
38
40
  finishOnError(err: unknown): Promise<void>;
39
41
  }
42
+ /**
43
+ * @deprecated Synchronous lookup against the legacy global registry only.
44
+ * Under an active IoC root, use `currentTransactionFor(entry)` with an entry
45
+ * from the root's SqlStack (`stack.getEntry(name)`).
46
+ */
40
47
  export declare function currentTransaction(db?: string): TransactionHandle | undefined;
48
+ /** Active transaction handle for a concrete database entry, if any. */
49
+ export declare function currentTransactionFor(entry: DatabaseEntry): TransactionHandle | undefined;
41
50
  export declare function withTransaction<T>(fn: () => Promise<T>, options?: TransactionOptions): Promise<T>;
42
51
  export type TransactionDecorator = {
43
52
  (target: any, prop: string | symbol, desc: PropertyDescriptor): void;
@@ -47,6 +56,6 @@ export declare const transaction: TransactionDecorator;
47
56
  export type ActiveTransaction = {
48
57
  query(sql: string, params: unknown[]): Promise<QueryResult>;
49
58
  };
50
- export declare function getActiveTransaction(dbName: string): ActiveTransaction | undefined;
59
+ export declare function getActiveTransaction(entry: DatabaseEntry): ActiveTransaction | undefined;
51
60
  export {};
52
61
  //# sourceMappingURL=transactions.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"transactions.d.ts","sourceRoot":"","sources":["../../src/transactions.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAKxD,MAAM,MAAM,kBAAkB,GAAG;IAC/B,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,CAAC;AA0BF,qBAAa,iBAAiB;;IAC5B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;gBAKZ,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO;IAMpD,aAAa;IAInB,YAAY,CAAC,YAAY,CAAC,EAAE,OAAO;IAO7B,MAAM;IAKN,QAAQ;IAKR,OAAO;IAKP,eAAe;IAMf,aAAa,CAAC,GAAG,EAAE,OAAO;CAKjC;AAED,cAAM,OAAO;IACX,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,EAAE,EAAE,QAAQ,CAAC;IACtB,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAC,IAAI,CAAC,kBAAkB,EAAE,MAAM,CAAC,CAAC,GAAG,IAAI,CAAC,kBAAkB,EAAE,QAAQ,CAAC,CAAC;IAClG,KAAK,SAAK;IACV,OAAO,UAAS;IAChB,SAAS,UAAS;IAClB,YAAY,UAAS;IACrB,aAAa,EAAE,OAAO,GAAG,SAAS,CAAC;IAEnC,OAAO,CAAC,IAAI,CAAuB;IACnC,OAAO,CAAC,SAAS,CAAoC;gBAEzC,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,kBAAkB,GAAG,SAAS;IASjF,IAAI,QAAQ,IAAI,QAAQ,CAEvB;IAEK,aAAa;IAuCb,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,WAAW,CAAC;IAK3D,eAAe;IAUf,iBAAiB;IAUjB,OAAO;IASP,eAAe;IAaf,aAAa,CAAC,GAAG,EAAE,OAAO;CAWjC;AAwBD,wBAAgB,kBAAkB,CAAC,EAAE,CAAC,EAAE,MAAM,GAAG,iBAAiB,GAAG,SAAS,CAO7E;AAED,wBAAsB,eAAe,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,EAAE,kBAAkB,GAAG,OAAO,CAAC,CAAC,CAAC,CAkBvG;AAED,MAAM,MAAM,oBAAoB,GAAG;IACjC,CAAC,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,IAAI,EAAE,kBAAkB,GAAG,IAAI,CAAC;IACrE,CAAC,OAAO,CAAC,EAAE,kBAAkB,GAAG,CAAC,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,IAAI,EAAE,kBAAkB,KAAK,IAAI,CAAC;CACxG,CAAC;AAEF,eAAO,MAAM,WAAW,EAAE,oBAYlB,CAAC;AAST,MAAM,MAAM,iBAAiB,GAAG;IAC9B,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;CAC7D,CAAC;AAEF,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,MAAM,GAAG,iBAAiB,GAAG,SAAS,CAGlF"}
1
+ {"version":3,"file":"transactions.d.ts","sourceRoot":"","sources":["../../src/transactions.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAGxD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAG7C,MAAM,MAAM,kBAAkB,GAAG;IAC/B,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,CAAC;AA6BF,qBAAa,iBAAiB;;IAC5B,QAAQ,CAAC,KAAK,EAAE,aAAa,CAAC;gBAKlB,KAAK,EAAE,aAAa,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO;IAMhE,IAAI,MAAM,IAAI,MAAM,CAEnB;IAEK,aAAa;IAInB,YAAY,CAAC,YAAY,CAAC,EAAE,OAAO;IAO7B,MAAM;IAKN,QAAQ;IAKR,OAAO;IAKP,eAAe;IAMf,aAAa,CAAC,GAAG,EAAE,OAAO;CAKjC;AAED,cAAM,OAAO;IACX,QAAQ,CAAC,KAAK,EAAE,aAAa,CAAC;IAC9B,QAAQ,CAAC,EAAE,EAAE,QAAQ,CAAC;IACtB,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAC,IAAI,CAAC,kBAAkB,EAAE,MAAM,CAAC,CAAC,GAAG,IAAI,CAAC,kBAAkB,EAAE,QAAQ,CAAC,CAAC;IAClG,KAAK,SAAK;IACV,OAAO,UAAS;IAChB,SAAS,UAAS;IAClB,YAAY,UAAS;IACrB,aAAa,EAAE,OAAO,GAAG,SAAS,CAAC;IAEnC,OAAO,CAAC,IAAI,CAAuB;IACnC,OAAO,CAAC,SAAS,CAAoC;gBAEzC,KAAK,EAAE,aAAa,EAAE,OAAO,EAAE,kBAAkB,GAAG,SAAS;IASzE,IAAI,QAAQ,IAAI,QAAQ,CAEvB;IAEK,aAAa;IAuCb,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,WAAW,CAAC;IAK3D,eAAe;IAUf,iBAAiB;IAUjB,OAAO;IASP,eAAe;IAaf,aAAa,CAAC,GAAG,EAAE,OAAO;CAWjC;AAuBD;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,EAAE,CAAC,EAAE,MAAM,GAAG,iBAAiB,GAAG,SAAS,CAO7E;AAED,uEAAuE;AACvE,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,aAAa,GAAG,iBAAiB,GAAG,SAAS,CAKzF;AAED,wBAAsB,eAAe,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,EAAE,kBAAkB,GAAG,OAAO,CAAC,CAAC,CAAC,CAkBvG;AAED,MAAM,MAAM,oBAAoB,GAAG;IACjC,CAAC,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,IAAI,EAAE,kBAAkB,GAAG,IAAI,CAAC;IACrE,CAAC,OAAO,CAAC,EAAE,kBAAkB,GAAG,CAAC,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,IAAI,EAAE,kBAAkB,KAAK,IAAI,CAAC;CACxG,CAAC;AAEF,eAAO,MAAM,WAAW,EAAE,oBAYlB,CAAC;AAST,MAAM,MAAM,iBAAiB,GAAG;IAC9B,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;CAC7D,CAAC;AAEF,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,aAAa,GAAG,iBAAiB,GAAG,SAAS,CAGxF"}