litedbmodel 2.0.2 → 2.2.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 (193) hide show
  1. package/README.md +7 -0
  2. package/dist/DBConditions.d.ts.map +1 -1
  3. package/dist/DBConditions.js +16 -1
  4. package/dist/DBConditions.js.map +1 -1
  5. package/dist/DBHandler.d.ts.map +1 -1
  6. package/dist/DBHandler.js +6 -0
  7. package/dist/DBHandler.js.map +1 -1
  8. package/dist/DBModel.d.ts +84 -2
  9. package/dist/DBModel.d.ts.map +1 -1
  10. package/dist/DBModel.js +312 -29
  11. package/dist/DBModel.js.map +1 -1
  12. package/dist/decorators.d.ts +52 -0
  13. package/dist/decorators.d.ts.map +1 -1
  14. package/dist/decorators.js +127 -24
  15. package/dist/decorators.js.map +1 -1
  16. package/dist/drivers/mysql.d.ts.map +1 -1
  17. package/dist/drivers/mysql.js +12 -2
  18. package/dist/drivers/mysql.js.map +1 -1
  19. package/dist/drivers/postgres.d.ts.map +1 -1
  20. package/dist/drivers/postgres.js +13 -2
  21. package/dist/drivers/postgres.js.map +1 -1
  22. package/dist/drivers/sqlite.d.ts +2 -0
  23. package/dist/drivers/sqlite.d.ts.map +1 -1
  24. package/dist/drivers/sqlite.js +49 -4
  25. package/dist/drivers/sqlite.js.map +1 -1
  26. package/dist/index.cjs +10741 -0
  27. package/dist/index.d.cts +1 -0
  28. package/dist/scp/coltype.d.ts +108 -0
  29. package/dist/scp/coltype.d.ts.map +1 -1
  30. package/dist/scp/coltype.js +293 -6
  31. package/dist/scp/coltype.js.map +1 -1
  32. package/dist/scp/connection-routing.d.ts +312 -0
  33. package/dist/scp/connection-routing.d.ts.map +1 -0
  34. package/dist/scp/connection-routing.js +394 -0
  35. package/dist/scp/connection-routing.js.map +1 -0
  36. package/dist/scp/dbmodel-runtime.d.ts +101 -0
  37. package/dist/scp/dbmodel-runtime.d.ts.map +1 -0
  38. package/dist/scp/dbmodel-runtime.js +174 -0
  39. package/dist/scp/dbmodel-runtime.js.map +1 -0
  40. package/dist/scp/decorator-adapter.d.ts +196 -0
  41. package/dist/scp/decorator-adapter.d.ts.map +1 -0
  42. package/dist/scp/decorator-adapter.js +286 -0
  43. package/dist/scp/decorator-adapter.js.map +1 -0
  44. package/dist/scp/emit/emitter.d.ts +108 -0
  45. package/dist/scp/emit/emitter.d.ts.map +1 -0
  46. package/dist/scp/emit/emitter.js +782 -0
  47. package/dist/scp/emit/emitter.js.map +1 -0
  48. package/dist/scp/emit/endpoint.d.ts +248 -0
  49. package/dist/scp/emit/endpoint.d.ts.map +1 -0
  50. package/dist/scp/emit/endpoint.js +20 -0
  51. package/dist/scp/emit/endpoint.js.map +1 -0
  52. package/dist/scp/emit/index.d.ts +11 -0
  53. package/dist/scp/emit/index.d.ts.map +1 -0
  54. package/dist/scp/emit/index.js +13 -0
  55. package/dist/scp/emit/index.js.map +1 -0
  56. package/dist/scp/errors.d.ts +45 -1
  57. package/dist/scp/errors.d.ts.map +1 -1
  58. package/dist/scp/errors.js +47 -1
  59. package/dist/scp/errors.js.map +1 -1
  60. package/dist/scp/exec-context.d.ts +390 -0
  61. package/dist/scp/exec-context.d.ts.map +1 -0
  62. package/dist/scp/exec-context.js +540 -0
  63. package/dist/scp/exec-context.js.map +1 -0
  64. package/dist/scp/grouping.d.ts +32 -0
  65. package/dist/scp/grouping.d.ts.map +1 -0
  66. package/dist/scp/grouping.js +0 -0
  67. package/dist/scp/grouping.js.map +1 -0
  68. package/dist/scp/index.cjs +6432 -17579
  69. package/dist/scp/index.d.cts +1 -0
  70. package/dist/scp/index.d.mts +1 -0
  71. package/dist/scp/index.d.ts +51 -52
  72. package/dist/scp/index.d.ts.map +1 -1
  73. package/dist/scp/index.js +189 -152
  74. package/dist/scp/index.js.map +1 -1
  75. package/dist/scp/index.mjs +6067 -3659
  76. package/dist/scp/leaf-transport.d.ts +50 -0
  77. package/dist/scp/leaf-transport.d.ts.map +1 -0
  78. package/dist/scp/leaf-transport.js +92 -0
  79. package/dist/scp/leaf-transport.js.map +1 -0
  80. package/dist/scp/leaves.d.ts +174 -0
  81. package/dist/scp/leaves.d.ts.map +1 -0
  82. package/dist/scp/leaves.js +287 -0
  83. package/dist/scp/leaves.js.map +1 -0
  84. package/dist/scp/limit-config.d.ts +118 -0
  85. package/dist/scp/limit-config.d.ts.map +1 -0
  86. package/dist/scp/limit-config.js +126 -0
  87. package/dist/scp/limit-config.js.map +1 -0
  88. package/dist/scp/makesql/compile-relation.d.ts +49 -23
  89. package/dist/scp/makesql/compile-relation.d.ts.map +1 -1
  90. package/dist/scp/makesql/compile-relation.js +101 -76
  91. package/dist/scp/makesql/compile-relation.js.map +1 -1
  92. package/dist/scp/makesql/compile-select.d.ts +45 -10
  93. package/dist/scp/makesql/compile-select.d.ts.map +1 -1
  94. package/dist/scp/makesql/compile-select.js +50 -10
  95. package/dist/scp/makesql/compile-select.js.map +1 -1
  96. package/dist/scp/makesql/handler.d.ts +1 -1
  97. package/dist/scp/makesql/handler.d.ts.map +1 -1
  98. package/dist/scp/makesql/index.d.ts +7 -10
  99. package/dist/scp/makesql/index.d.ts.map +1 -1
  100. package/dist/scp/makesql/index.js +19 -30
  101. package/dist/scp/makesql/index.js.map +1 -1
  102. package/dist/scp/makesql/json-array.d.ts +65 -0
  103. package/dist/scp/makesql/json-array.d.ts.map +1 -1
  104. package/dist/scp/makesql/json-array.js +99 -10
  105. package/dist/scp/makesql/json-array.js.map +1 -1
  106. package/dist/scp/makesql/json-batch.d.ts.map +1 -1
  107. package/dist/scp/makesql/json-batch.js +21 -19
  108. package/dist/scp/makesql/json-batch.js.map +1 -1
  109. package/dist/scp/makesql/makesql.d.ts +1 -1
  110. package/dist/scp/makesql/makesql.d.ts.map +1 -1
  111. package/dist/scp/makesql/mysql-returning.d.ts +93 -0
  112. package/dist/scp/makesql/mysql-returning.d.ts.map +1 -0
  113. package/dist/scp/makesql/mysql-returning.js +215 -0
  114. package/dist/scp/makesql/mysql-returning.js.map +1 -0
  115. package/dist/scp/makesql/outtype.d.ts +75 -34
  116. package/dist/scp/makesql/outtype.d.ts.map +1 -1
  117. package/dist/scp/makesql/outtype.js +91 -118
  118. package/dist/scp/makesql/outtype.js.map +1 -1
  119. package/dist/scp/makesql/pool-executor.d.ts +135 -13
  120. package/dist/scp/makesql/pool-executor.d.ts.map +1 -1
  121. package/dist/scp/makesql/pool-executor.js +229 -21
  122. package/dist/scp/makesql/pool-executor.js.map +1 -1
  123. package/dist/scp/makesql/tx.d.ts +107 -22
  124. package/dist/scp/makesql/tx.d.ts.map +1 -1
  125. package/dist/scp/makesql/tx.js +451 -97
  126. package/dist/scp/makesql/tx.js.map +1 -1
  127. package/dist/scp/makesql/writeouttype.d.ts +7 -8
  128. package/dist/scp/makesql/writeouttype.d.ts.map +1 -1
  129. package/dist/scp/makesql/writeouttype.js +8 -7
  130. package/dist/scp/makesql/writeouttype.js.map +1 -1
  131. package/dist/scp/middleware.d.ts +287 -0
  132. package/dist/scp/middleware.d.ts.map +1 -0
  133. package/dist/scp/middleware.js +358 -0
  134. package/dist/scp/middleware.js.map +1 -0
  135. package/dist/scp/relation.d.ts +80 -9
  136. package/dist/scp/relation.d.ts.map +1 -1
  137. package/dist/scp/relation.js +198 -78
  138. package/dist/scp/relation.js.map +1 -1
  139. package/dist/scp/tx-options.d.ts +136 -0
  140. package/dist/scp/tx-options.d.ts.map +1 -0
  141. package/dist/scp/tx-options.js +184 -0
  142. package/dist/scp/tx-options.js.map +1 -0
  143. package/dist/scp/write-bundle.d.ts +131 -0
  144. package/dist/scp/write-bundle.d.ts.map +1 -0
  145. package/dist/scp/write-bundle.js +160 -0
  146. package/dist/scp/write-bundle.js.map +1 -0
  147. package/dist/types.d.ts +7 -0
  148. package/dist/types.d.ts.map +1 -1
  149. package/dist/types.js.map +1 -1
  150. package/docs/BENCHMARK.md +58 -56
  151. package/docs/benchmark-chart.svg +166 -166
  152. package/docs/design/phase-a-execution-context.md +139 -0
  153. package/package.json +16 -9
  154. package/dist/scp/authoring-sql.d.ts +0 -134
  155. package/dist/scp/authoring-sql.d.ts.map +0 -1
  156. package/dist/scp/authoring-sql.js +0 -191
  157. package/dist/scp/authoring-sql.js.map +0 -1
  158. package/dist/scp/authoring.d.ts +0 -155
  159. package/dist/scp/authoring.d.ts.map +0 -1
  160. package/dist/scp/authoring.js +0 -162
  161. package/dist/scp/authoring.js.map +0 -1
  162. package/dist/scp/catalog.d.ts +0 -94
  163. package/dist/scp/catalog.d.ts.map +0 -1
  164. package/dist/scp/catalog.js +0 -234
  165. package/dist/scp/catalog.js.map +0 -1
  166. package/dist/scp/codegen.d.ts +0 -189
  167. package/dist/scp/codegen.d.ts.map +0 -1
  168. package/dist/scp/codegen.js +0 -421
  169. package/dist/scp/codegen.js.map +0 -1
  170. package/dist/scp/find-filter-guard.d.ts +0 -68
  171. package/dist/scp/find-filter-guard.d.ts.map +0 -1
  172. package/dist/scp/find-filter-guard.js +0 -88
  173. package/dist/scp/find-filter-guard.js.map +0 -1
  174. package/dist/scp/guard.d.ts +0 -43
  175. package/dist/scp/guard.d.ts.map +0 -1
  176. package/dist/scp/guard.js +0 -134
  177. package/dist/scp/guard.js.map +0 -1
  178. package/dist/scp/makesql/authoring-compile.d.ts +0 -90
  179. package/dist/scp/makesql/authoring-compile.d.ts.map +0 -1
  180. package/dist/scp/makesql/authoring-compile.js +0 -494
  181. package/dist/scp/makesql/authoring-compile.js.map +0 -1
  182. package/dist/scp/makesql/ir.d.ts +0 -42
  183. package/dist/scp/makesql/ir.d.ts.map +0 -1
  184. package/dist/scp/makesql/ir.js +0 -66
  185. package/dist/scp/makesql/ir.js.map +0 -1
  186. package/dist/scp/makesql/static-bundle.d.ts +0 -187
  187. package/dist/scp/makesql/static-bundle.d.ts.map +0 -1
  188. package/dist/scp/makesql/static-bundle.js +0 -1113
  189. package/dist/scp/makesql/static-bundle.js.map +0 -1
  190. package/dist/scp/runtime.d.ts +0 -242
  191. package/dist/scp/runtime.d.ts.map +0 -1
  192. package/dist/scp/runtime.js +0 -400
  193. package/dist/scp/runtime.js.map +0 -1
@@ -0,0 +1,540 @@
1
+ "use strict";
2
+ /**
3
+ * litedbmodel v2 SCP — the **ExecutionContext + central execute/run seam** (Phase A / #75).
4
+ *
5
+ * This module is the CONTRACT-DEFINING artifact for Phase A: it fixes the shape every runtime
6
+ * (TS here; rust #76 / go #77 / py #78 / php #79 port it) follows. It replaces the raw `driver`
7
+ * parameter threaded through `executeBundle` / `executeReadGraph` / `executeTransaction` with an
8
+ * {@link ExecutionContext} that carries:
9
+ *
10
+ * 1. a **connection provider** — {@link ExecutionContext.connectionFor}`(intent)` resolves WHICH
11
+ * connection a statement runs on (tx-owned / reader / writer / named-DB; Phase A only wires the
12
+ * tx-owned + single-DB cases, the rest are B/C/D on this same seam);
13
+ * 2. a **middleware chain** — {@link ExecutionContext.middleware}, wrapping every SQL (empty in
14
+ * Phase A = passthrough; the registration API is Phase D — this is only the hook point);
15
+ * 3. {@link ExecutionContext.withConnection}`(conn, tx)` — derive a tx-scoped ctx that pins ONE
16
+ * connection so every statement in a transaction body runs on it.
17
+ *
18
+ * ## The central seam (§2 of the design) — ALL SQL funnels through here
19
+ *
20
+ * ```
21
+ * execute(ctx, sql, params) -> Rows // SELECT / RETURNING reads
22
+ * run(ctx, sql, params) -> RunInfo // INSERT/UPDATE/DELETE, BEGIN/COMMIT/ROLLBACK
23
+ * ```
24
+ *
25
+ * Both do the SAME three things, in order:
26
+ * ① run the middleware chain (empty ⇒ passthrough, behavior unchanged);
27
+ * ② resolve the connection via `ctx.connectionFor(intent)`;
28
+ * ③ execute on that connection (the ONLY driver contact point).
29
+ *
30
+ * Every direct `driver.prepare(sql).all()/run()` in the read / tx / relation path is replaced by a
31
+ * call through this seam. A `grep` for `.prepare(` outside this file's connection adapters must come
32
+ * up empty in the runtime SQL path — that is the AC.
33
+ *
34
+ * ## Two flavors — sync (SQLite) and async (live PG / MySQL)
35
+ *
36
+ * The in-process better-sqlite3 path is **synchronous** (and must stay byte-identical to the frozen
37
+ * conformance corpus), so it uses a {@link SyncConnection} and the {@link execute} / {@link run}
38
+ * seam. The live PG / MySQL path is **async + pooled**, where per-execution connection ownership is
39
+ * what actually fixes the concurrent-tx isolation bug; it uses an {@link AsyncConnection} and the
40
+ * {@link executeAsync} / {@link runAsync} seam plus {@link withTransactionAsync}.
41
+ *
42
+ * Both flavors implement the SAME contract shape (`connectionFor` / `middleware` / `withConnection`
43
+ * / a central seam / `withTransaction`); the native ports mirror whichever their runtime needs
44
+ * (rust/go = the owned-connection async model; py = contextvars; php = the single-connection sync
45
+ * model — same contract, no ALS since PHP is 1-request-1-process).
46
+ *
47
+ * ## Per-execution connection ownership (§3) — the concurrent-tx fix
48
+ *
49
+ * A transaction acquires ONE connection, scopes it into an {@link AsyncLocalStorage} ctx, runs its
50
+ * body (every statement resolves that connection via `connectionFor`), COMMITs/ROLLBACKs, and
51
+ * releases it. Concurrent transactions each run in their own ALS ctx with their own connection —
52
+ * **isolated**. There is NO driver-global single-slot writer (the shared-slot model — `pool.query`
53
+ * per statement, or a `Mutex<Option<writer>>` — is what corrupts concurrent transactions; see the
54
+ * `test/integration/tx-isolation` proof).
55
+ */
56
+ Object.defineProperty(exports, "__esModule", { value: true });
57
+ exports.PooledAsyncContext = exports.MiddlewareChain = void 0;
58
+ exports.execute = execute;
59
+ exports.executeSafe = executeSafe;
60
+ exports.run = run;
61
+ exports.executeAsync = executeAsync;
62
+ exports.runAsync = runAsync;
63
+ exports.runGuarded = runGuarded;
64
+ exports.runGuardedAsync = runGuardedAsync;
65
+ exports.connectionForDriver = connectionForDriver;
66
+ exports.contextForDriver = contextForDriver;
67
+ exports.contextForConnection = contextForConnection;
68
+ exports.runWithPinnedAsyncConnection = runWithPinnedAsyncConnection;
69
+ exports.currentPinnedAsyncConnection = currentPinnedAsyncConnection;
70
+ exports.withTransactionAsync = withTransactionAsync;
71
+ exports.transaction = transaction;
72
+ exports.withTransactionSync = withTransactionSync;
73
+ const node_async_hooks_1 = require("node:async_hooks");
74
+ const tx_options_1 = require("./tx-options");
75
+ const connection_routing_1 = require("./connection-routing");
76
+ const middleware_1 = require("./middleware");
77
+ /**
78
+ * The ordered middleware chain a ctx carries (§4). `wrap` folds the middlewares around `next`
79
+ * (the connection-resolve + execute terminal). An EMPTY chain is a pure passthrough — `wrap`
80
+ * returns `next(sql, params)` verbatim, so an unregistered chain is byte-identical. The chain is
81
+ * generic over the seam result type `T` so ONE shape serves both the sync (`Rows`/`RunInfo`) and
82
+ * async (`Promise<…>`) seams.
83
+ *
84
+ * The stack is resolved by a {@link MiddlewareStackSource} at EACH `wrap` (Phase D) rather than
85
+ * captured at construction, so registration (`DBModel.use`) that happens after the ctx is built is
86
+ * still honored and per-execution-scope registries (concurrent isolation) resolve correctly. A chain
87
+ * constructed with an explicit fixed stack (or none) still works — that stack is its constant source.
88
+ */
89
+ class MiddlewareChain {
90
+ /** Resolve the CURRENT registered SQL-level middlewares, outermost first, at `wrap` time. */
91
+ source;
92
+ constructor(stackOrSource = []) {
93
+ this.source = typeof stackOrSource === 'function' ? stackOrSource : () => stackOrSource;
94
+ }
95
+ /** Is the chain empty RIGHT NOW (⇒ this `wrap` is a guaranteed passthrough)? */
96
+ get isEmpty() {
97
+ return this.source().length === 0;
98
+ }
99
+ /** Fold the chain around `next`, then invoke it. Empty chain ⇒ `next(sql, params)` verbatim. */
100
+ wrap(sql, params, next) {
101
+ const stack = this.source();
102
+ if (stack.length === 0)
103
+ return next(sql, params);
104
+ let fn = next;
105
+ for (let i = stack.length - 1; i >= 0; i--) {
106
+ const mw = stack[i];
107
+ const inner = fn;
108
+ fn = (s, p) => mw(s, p, inner);
109
+ }
110
+ return fn(sql, params);
111
+ }
112
+ }
113
+ exports.MiddlewareChain = MiddlewareChain;
114
+ // ── The central seam (§2) — the ONLY place SQL meets a connection ─────────────
115
+ /**
116
+ * Central READ seam (sync): ① middleware chain, ② resolve the connection, ③ execute. Every read
117
+ * (primary read node, relation batch) funnels through here.
118
+ */
119
+ function execute(ctx, sql, params, intent = { write: false }) {
120
+ return ctx.middleware.wrap(sql, params, (s, p) => ctx.connectionFor(intent).execute(s, p));
121
+ }
122
+ /**
123
+ * Central READ seam (sync) in `safeIntegers` mode (§2 + the #59 BIGINT-exact read). Same
124
+ * middleware → connectionFor → execute path, but the terminal runs the SELECT in exact-integer mode
125
+ * so int8/BIGINT columns materialize without rounding. Used by the read walker for a BIGINT-
126
+ * projecting node; a non-BIGINT node uses the plain {@link execute}.
127
+ */
128
+ function executeSafe(ctx, sql, params, intent = { write: false }) {
129
+ return ctx.middleware.wrap(sql, params, (s, p) => ctx.connectionFor(intent).executeSafeIntegers(s, p));
130
+ }
131
+ /**
132
+ * Central WRITE seam (sync): ① middleware chain, ② resolve the connection, ③ run. Every write and
133
+ * every tx-control statement (BEGIN/COMMIT/ROLLBACK) funnels through here (writes ⇒ `intent.write`).
134
+ */
135
+ function run(ctx, sql, params, intent = { write: true }) {
136
+ return ctx.middleware.wrap(sql, params, (s, p) => ctx.connectionFor(intent).run(s, p));
137
+ }
138
+ /** Central READ seam (async) — the live PG / MySQL twin of {@link execute}. */
139
+ function executeAsync(ctx, sql, params, intent = { write: false }) {
140
+ return ctx.middleware.wrap(sql, params, (s, p) => ctx.connectionFor(intent).execute(s, p));
141
+ }
142
+ /** Central WRITE seam (async) — the live PG / MySQL twin of {@link run}. */
143
+ function runAsync(ctx, sql, params, intent = { write: true }) {
144
+ return ctx.middleware.wrap(sql, params, (s, p) => ctx.connectionFor(intent).run(s, p));
145
+ }
146
+ /**
147
+ * GUARDED write seam (sync): enforce the write=tx guard ({@link checkWriteAllowed}) for a
148
+ * DATA-mutating statement, then delegate to {@link run}. A write issued OUTSIDE a transaction throws
149
+ * {@link WriteOutsideTransactionError}; a write in a {@link withReadOnly} scope throws
150
+ * {@link WriteInReadOnlyContextError}. Tx-control statements (BEGIN/COMMIT/ROLLBACK/SET) are NOT
151
+ * guarded — the tx runtime issues them to OPEN the very scope the guard checks. This is the seam a
152
+ * bare model-level write (create/update/delete/upsert/batch) goes through.
153
+ */
154
+ function runGuarded(ctx, sql, params, operation, modelName) {
155
+ (0, tx_options_1.checkWriteAllowed)(operation, modelName);
156
+ return run(ctx, sql, params, { write: true });
157
+ }
158
+ /**
159
+ * GUARDED write seam (async) — the live PG / MySQL twin of {@link runGuarded}. The guard is enforced
160
+ * inside the returned promise (an async caller gets a REJECTED promise, never a synchronous throw).
161
+ */
162
+ async function runGuardedAsync(ctx, sql, params, operation, modelName) {
163
+ (0, tx_options_1.checkWriteAllowed)(operation, modelName);
164
+ return runAsync(ctx, sql, params, { write: true });
165
+ }
166
+ /** Adapt a better-sqlite3 `Database` to the {@link SyncConnection} seam (the ONE driver contact). */
167
+ function connectionForDriver(driver) {
168
+ return {
169
+ execute(sql, params) {
170
+ return driver.prepare(sql).all(...params);
171
+ },
172
+ executeSafeIntegers(sql, params) {
173
+ const stmt = driver.prepare(sql);
174
+ // better-sqlite3: run in exact-integer mode so int8/BIGINT arrives as a bigint (the #59 hole:
175
+ // a JS number would round it). A driver without the toggle degrades to a plain `.all` (its
176
+ // rows come back in whatever exact form it natively uses — pg/mysql string BIGINT).
177
+ if (typeof stmt.safeIntegers === 'function')
178
+ stmt.safeIntegers(true);
179
+ return stmt.all(...params);
180
+ },
181
+ run(sql, params) {
182
+ return driver.prepare(sql).run(...params);
183
+ },
184
+ };
185
+ }
186
+ /**
187
+ * A thin, single-DB, middleware-free {@link ExecutionContext} over ONE connection. A tx-scoped ctx
188
+ * (`withConnection(conn, true)`) pins that connection for every `connectionFor` — this is the
189
+ * per-execution connection ownership (§3). Absent a pinned tx connection, it returns the base
190
+ * connection (the single-DB Phase A case; reader/writer/named-DB routing is B/C/D on this seam).
191
+ */
192
+ class BasicContext {
193
+ middleware;
194
+ base;
195
+ /** The pinned tx connection (present ⇒ this is a tx-scoped ctx; every statement uses it). */
196
+ pinned;
197
+ constructor(base, middleware, pinned) {
198
+ this.base = base;
199
+ this.middleware = middleware;
200
+ this.pinned = pinned;
201
+ }
202
+ connectionFor(_intent) {
203
+ // Phase A resolution: the tx-owned (pinned) connection wins; else the single base connection.
204
+ // Reader/writer split (§3-2/3) + named-DB routing (§3-4) extend HERE in B/C/D.
205
+ return this.pinned ?? this.base;
206
+ }
207
+ withConnection(conn, tx) {
208
+ return new BasicContext(this.base, this.middleware, tx ? conn : null);
209
+ }
210
+ }
211
+ /**
212
+ * **Backward-compat wrapper (§6).** Wrap a raw better-sqlite3 `Database` in a thin
213
+ * {@link ExecutionContext}: reader = writer = the same driver, a single DB. Its middleware chain
214
+ * resolves the ambient/global SQL-level {@link import('./middleware').MiddlewareRegistry} at wrap
215
+ * time (Phase D), so a middleware registered via `DBModel.use(...)` intercepts the SQL — and, when
216
+ * NO middleware is registered, the chain is empty and the seam is a pure passthrough to
217
+ * `driver.prepare(...).all()/run()`, i.e. **byte-identical** (the conformance/livedb runners
218
+ * register none, so they are unchanged).
219
+ */
220
+ function contextForDriver(driver) {
221
+ return new BasicContext(connectionForDriver(driver), new MiddlewareChain(middleware_1.activeSqlMiddlewares), null);
222
+ }
223
+ /**
224
+ * Build a sync ctx directly over a {@link SyncConnection} (for a caller that already owns a
225
+ * connection adapter — e.g. a non-better-sqlite3 sync backend). Same single-DB / ambient-middleware
226
+ * shape as {@link contextForDriver}.
227
+ */
228
+ function contextForConnection(conn) {
229
+ return new BasicContext(conn, new MiddlewareChain(middleware_1.activeSqlMiddlewares), null);
230
+ }
231
+ /** Per-async-execution ambient ctx: the ALS slot carrying the tx-scoped connection (§3). */
232
+ const asyncCtxStore = new node_async_hooks_1.AsyncLocalStorage();
233
+ /**
234
+ * A pooled async {@link AsyncExecutionContext}. Outside a transaction, `connectionFor` acquires a
235
+ * fresh pooled connection per statement (the existing read fan-out model — each concurrent sibling
236
+ * on its own connection). Inside a transaction, {@link withTransactionAsync} pins ONE acquired
237
+ * connection into the ALS store; `connectionFor` returns THAT for every statement in the body, so
238
+ * the whole tx runs on one owned connection — isolated from concurrent transactions.
239
+ *
240
+ * NB: outside a tx, `connectionFor` returns a **per-statement** owned connection wrapper that
241
+ * acquires-runs-releases; the read walker issues one statement per `executeAsync`, matching the
242
+ * existing `SqlExecutorAsync` "acquire per exec" semantics byte-for-byte.
243
+ */
244
+ class PooledAsyncContext {
245
+ middleware;
246
+ /**
247
+ * The full routing config (§3 steps 2-4): the multi-DB {@link ConnectionRegistry} + the
248
+ * {@link WriterStickyClock}. A ctx built from a single `pool` synthesizes a default-only registry
249
+ * (reader === writer) + an always-false sticky clock, so its resolution is byte-identical to the
250
+ * Phase A/B single-pool path. A ctx built with a {@link RoutingConfig} (via {@link setConfig})
251
+ * gets reader/writer separation, writer-sticky, and named-DB routing.
252
+ */
253
+ routing;
254
+ /**
255
+ * Construct from EITHER a single {@link AsyncConnectionPool} (backward-compat: default connection,
256
+ * reader === writer, sticky disabled — byte-identical to Phase A/B) OR a full {@link RoutingConfig}
257
+ * (Phase C: reader/writer separation + writer-sticky + named-DB routing).
258
+ */
259
+ constructor(poolOrRouting, middleware = new MiddlewareChain(middleware_1.activeSqlMiddlewares)) {
260
+ this.middleware = middleware;
261
+ this.routing = isRoutingConfig(poolOrRouting)
262
+ ? poolOrRouting
263
+ : // Single-pool backward-compat: default-only registry (reader === writer) + a sticky clock
264
+ // that is NEVER marked (so `isSticky()` stays false) ⇒ every intent lands on the one pool.
265
+ { registry: connection_routing_1.ConnectionRegistry.singleDefault(poolOrRouting), sticky: new connection_routing_1.WriterStickyClock({ useWriterAfterTransaction: false }) };
266
+ }
267
+ connectionFor(intent) {
268
+ // STEP 1 (§3): inside a tx, the ALS-pinned owned connection wins — every statement on the SAME
269
+ // conn (the per-execution ownership the concurrent-tx fix depends on). The tx pin is a per-scope
270
+ // fact only the ctx's ALS holds, so it is resolved HERE, before the pool-selection steps.
271
+ const pinned = asyncCtxStore.getStore();
272
+ if (pinned !== undefined)
273
+ return pinned;
274
+ // STEPS 2-4 (§3): named-DB → reader/writer split → writer-sticky/withWriter. `resolvePool`
275
+ // returns WHICH pool serves this intent; the returned wrapper acquires/runs/releases one owned
276
+ // connection per statement (the read fan-out: each concurrent sibling on its own connection).
277
+ const pool = (0, connection_routing_1.resolvePool)(intent, this.routing);
278
+ return {
279
+ async execute(sql, params) {
280
+ const c = await pool.acquire();
281
+ try {
282
+ return await c.execute(sql, params);
283
+ }
284
+ finally {
285
+ await pool.release(c);
286
+ }
287
+ },
288
+ async run(sql, params) {
289
+ const c = await pool.acquire();
290
+ try {
291
+ return await c.run(sql, params);
292
+ }
293
+ finally {
294
+ await pool.release(c);
295
+ }
296
+ },
297
+ };
298
+ }
299
+ withConnection(_conn, _tx) {
300
+ // Deriving a tx-scoped ctx pins the connection via the ALS run in withTransactionAsync (not by
301
+ // mutating this object); the derived ctx shares the routing + middleware and is never used to
302
+ // acquire (the ALS-pinned connection wins in `connectionFor`).
303
+ return this;
304
+ }
305
+ /**
306
+ * The WRITER pool of the connection a transaction runs against (so `withTransactionAsync` acquires
307
+ * the tx's owned connection from the right pool). A transaction is a write ⇒ the writer pool of the
308
+ * named connection (`intent.db`). Absent `db` ⇒ the default connection's writer.
309
+ */
310
+ connectionPoolFor(intent = { write: true }) {
311
+ return this.routing.registry.pairFor(intent.db).writer;
312
+ }
313
+ /** The default connection's writer pool (backward-compat accessor for the single-DB tx path). */
314
+ get connectionPool() {
315
+ return this.routing.registry.pairFor(undefined).writer;
316
+ }
317
+ /** The writer-sticky clock (the tx runtime `.mark()`s it on a successful write/commit). */
318
+ get stickyClock() {
319
+ return this.routing.sticky;
320
+ }
321
+ }
322
+ exports.PooledAsyncContext = PooledAsyncContext;
323
+ /** Narrow the {@link PooledAsyncContext} ctor arg: is it a {@link RoutingConfig} (vs. a bare pool)? */
324
+ function isRoutingConfig(x) {
325
+ return typeof x === 'object' && x !== null && 'registry' in x && 'sticky' in x;
326
+ }
327
+ /**
328
+ * Run `fn` inside the ALS scope with `conn` pinned as the ambient tx connection (§3). Every
329
+ * `connectionFor` inside `fn` (async boundaries included) returns `conn`. This is the TS
330
+ * per-execution ownership mechanism (v1 `DBModel.ts` `txContext.run`); the native ports use
331
+ * task-local (rust) / `context.Context` (go) / contextvars (py) / an explicit arg (php) for the
332
+ * SAME effect.
333
+ */
334
+ function runWithPinnedAsyncConnection(conn, fn) {
335
+ return asyncCtxStore.run(conn, fn);
336
+ }
337
+ /**
338
+ * The tx-owned connection pinned in the CURRENT async scope, or `undefined` if not inside a
339
+ * transaction. {@link withTransactionAsync} reads this to detect a NESTED transaction (an inner
340
+ * `withTransactionAsync` running inside an outer's ALS scope joins the outer instead of opening a
341
+ * new physical transaction). The native ports read their task-local / contextvar / `context.Context`
342
+ * for the SAME nested detection.
343
+ */
344
+ function currentPinnedAsyncConnection() {
345
+ return asyncCtxStore.getStore();
346
+ }
347
+ /**
348
+ * Is `err` a broken/stale connection (retryable via reconnect)? Defaulted here to a message/-code
349
+ * heuristic matching `src/connection-errors.ts` so exec-context needs no cross-module import; the
350
+ * runtime passes the shared {@link import('../connection-errors').isConnectionError} in explicitly.
351
+ */
352
+ function defaultIsConnectionError(err) {
353
+ const message = err.message || '';
354
+ const code = err.code || '';
355
+ return (message.includes('Connection terminated') ||
356
+ message.includes('Client has encountered a connection error') ||
357
+ message.includes('ECONNRESET') ||
358
+ message.includes('ECONNREFUSED') ||
359
+ message.includes('Connection lost') ||
360
+ message.includes('This socket has been ended by the other party') ||
361
+ code === 'ECONNRESET' ||
362
+ code === 'ECONNREFUSED' ||
363
+ code === 'EPIPE' ||
364
+ code === 'PROTOCOL_CONNECTION_LOST');
365
+ }
366
+ /**
367
+ * Run a transaction with **per-execution connection ownership** (§3, the concurrent-tx fix) plus the
368
+ * full Phase B tx-completeness contract (#81): isolation level, nested-tx join, rollbackOnly, and
369
+ * whole-tx retry with per-attempt connection acquisition.
370
+ *
371
+ * **Per attempt** (up to `retryLimit`):
372
+ * 1. acquire ONE fresh connection from the pool (a retry after a connection error thus RECONNECTS);
373
+ * 2. pin it into the ALS ctx (`runWithPinnedAsyncConnection`) so EVERY statement `fn` issues
374
+ * resolves THAT connection — never a fresh pooled one;
375
+ * 3. issue the isolation-aware BEGIN ({@link beginStatements}: PG `BEGIN ISOLATION LEVEL …`;
376
+ * MySQL a preceding `SET TRANSACTION ISOLATION LEVEL …` then `BEGIN`);
377
+ * 4. run `fn(txCtx)` → `COMMIT` (or `ROLLBACK` if `rollbackOnly`, still returning the body result);
378
+ * 5. on a body/commit error `ROLLBACK` and either RETRY (retryable error + attempts remain, with
379
+ * exponential backoff `retryDuration·2^(k-1)`) or re-raise;
380
+ * 6. release the connection back to the pool (DESTROYED if the ROLLBACK itself failed, or the whole
381
+ * tx errored non-cleanly — a poisoned connection must not re-enter the pool).
382
+ *
383
+ * **Nested**: if a tx-owned connection is ALREADY pinned in the ALS (an outer `withTransactionAsync`
384
+ * on this async chain), the inner call JOINS the outer — it runs `fn` directly on the outer's ctx
385
+ * with NO new BEGIN/COMMIT/acquire, so the whole nested body is one physical transaction (an inner
386
+ * error propagates and rolls back the WHOLE tx). Mirrors v1 `DBModel.transaction` :2794-2797.
387
+ *
388
+ * Concurrent (non-nested) `withTransactionAsync` calls each acquire a DISTINCT connection and pin it
389
+ * in their OWN ALS scope, so their writes never cross-talk — the isolation the shared-slot model
390
+ * violates. This is the reference the native ports (#82-85) mirror.
391
+ */
392
+ async function withTransactionAsync(ctx, fn, opts = {}, dialect = 'postgres', isConnectionError = defaultIsConnectionError, connection) {
393
+ // NESTED-TX JOIN (§ mirror v1 :2794): already inside a tx on this async chain ⇒ join the outer.
394
+ // No new connection, no BEGIN/COMMIT — the inner body is part of the outer physical transaction.
395
+ const outerConn = currentPinnedAsyncConnection();
396
+ if (outerConn !== undefined) {
397
+ // Reuse the outer's ctx (the pinned conn already wins in `connectionFor`). Isolation/retry/
398
+ // rollbackOnly options on a NESTED call are ignored — the outer transaction owns them.
399
+ return fn(ctx.withConnection(outerConn, true));
400
+ }
401
+ const resolved = (0, tx_options_1.resolveTxOptions)(opts);
402
+ const begins = (0, tx_options_1.beginStatements)(dialect, resolved.isolation);
403
+ // Named-DB routing (§3-4): a transaction is a write ⇒ acquire from the WRITER pool of the target
404
+ // connection (`connection` name, or the default). Single-DB ⇒ the one default writer pool.
405
+ const pool = ctx.connectionPoolFor({ write: true, ...(connection !== undefined ? { db: connection } : {}) });
406
+ let attempt = 0;
407
+ for (;;) {
408
+ attempt++;
409
+ const conn = await pool.acquire();
410
+ const txCtx = ctx.withConnection(conn, true);
411
+ // One attempt: BEGIN…body…COMMIT/ROLLBACK on the pinned conn. Returns `{ ok, value }` on success
412
+ // or `{ ok:false, error }` on failure — so the release + retry decision happens OUTSIDE the ALS
413
+ // run and the connection is released EXACTLY once per attempt.
414
+ let poisoned = false;
415
+ const attemptResult = await runWithPinnedAsyncConnection(conn, async () => {
416
+ for (const begin of begins)
417
+ await runAsync(txCtx, begin, []);
418
+ try {
419
+ // Mark the body as "inside a transaction" so a nested write's guard (`checkWriteAllowed`)
420
+ // and nested-tx detection see an active tx. The connection pin (above) and this marker share
421
+ // the SAME async scope.
422
+ const r = await (0, tx_options_1.runInTransactionScope)(() => fn(txCtx));
423
+ // rollbackOnly (dry-run): ROLLBACK but still return the body result — no committed change.
424
+ await runAsync(txCtx, resolved.rollbackOnly ? 'ROLLBACK' : 'COMMIT', []);
425
+ return { ok: true, value: r };
426
+ }
427
+ catch (error) {
428
+ try {
429
+ await runAsync(txCtx, 'ROLLBACK', []);
430
+ }
431
+ catch {
432
+ poisoned = true; // ROLLBACK failed ⇒ the connection is in an unknown state; drop it.
433
+ }
434
+ return { ok: false, error };
435
+ }
436
+ });
437
+ // An errored attempt saw a failed statement — destroy the (possibly poisoned) conn so a retry
438
+ // reconnects on a fresh one; a clean success returns the conn to the pool.
439
+ await pool.release(conn, poisoned || !attemptResult.ok);
440
+ if (attemptResult.ok) {
441
+ // WRITER-STICKY (§3-2, read-your-writes): a committed tx marks the sticky clock so subsequent
442
+ // reads within `writerStickyDuration` route to the writer pool (v1 `_lastTransactionTime`). A
443
+ // rollbackOnly (dry-run) tx committed NOTHING ⇒ it does NOT arm stickiness, and a tx that opted
444
+ // OUT per-transaction (`useWriterAfterTransaction: false`) does not arm it either — mirror v1
445
+ // `DBModel.transaction` :3126. The GLOBAL setting still has the last word: `mark()` is a no-op
446
+ // on a clock the deployment disabled, so a per-tx `true` cannot force stickiness on (v1 :487).
447
+ if (!resolved.rollbackOnly && resolved.useWriterAfterTransaction)
448
+ ctx.stickyClock.mark();
449
+ return attemptResult.value;
450
+ }
451
+ const { error } = attemptResult;
452
+ if (resolved.retryOnError && attempt < resolved.retryLimit && (0, tx_options_1.isRetryableTxError)(error, isConnectionError)) {
453
+ await (0, tx_options_1.sleep)(resolved.retryDuration * Math.pow(2, attempt - 1));
454
+ continue; // RETRY the whole transaction on a fresh connection
455
+ }
456
+ throw error;
457
+ }
458
+ }
459
+ // ── The PUBLIC user-controlled transaction boundary (§ Phase B-core / #86) ─────
460
+ /**
461
+ * **The public user-controlled transaction boundary** (#86) — the REAL transaction feature v2 was
462
+ * missing. `transaction(ctx, fn, options?)` opens ONE boundary the caller wraps around MULTIPLE
463
+ * arbitrary operations so they commit or roll back TOGETHER:
464
+ *
465
+ * ```ts
466
+ * await transaction(ctx, async () => {
467
+ * await A.create(...); // ← every op inside joins this ONE boundary:
468
+ * await B.update(...); // one connection, one BEGIN…COMMIT, all-or-nothing.
469
+ * }, { isolation: 'serializable' });
470
+ * ```
471
+ *
472
+ * ## What it does (v1 `DBModel.transaction` :2787 parity, on the SCP seam)
473
+ *
474
+ * It acquires ONE pooled connection, issues the isolation-aware `BEGIN`
475
+ * ({@link import('./tx-options').beginStatements}), PINS that connection into the ALS ctx, runs
476
+ * `fn`, then `COMMIT` (or `ROLLBACK` on a body error / `options.rollbackOnly`), with the #81 retry
477
+ * loop (deadlock / serialization / connection error) wrapped around the WHOLE boundary. It is a thin
478
+ * façade over {@link withTransactionAsync}: the ONE mechanism — the same acquire → pin → BEGIN →
479
+ * body → COMMIT/ROLLBACK → release + retry — powers both.
480
+ *
481
+ * ## The ambient-tx JOIN — how operations participate (the core #86 fix)
482
+ *
483
+ * `fn` takes NO connection argument. Instead the pinned connection lives in the ALS
484
+ * ({@link currentPinnedAsyncConnection}) + the "inside a transaction" marker
485
+ * ({@link import('./tx-options').runInTransactionScope}). Every operation `fn` issues — a live-DB
486
+ * write via {@link import('./makesql/tx').executeTransactionAsync}, a read via the async read seam —
487
+ * detects that ambient pinned connection and runs its statements on THAT connection **without opening
488
+ * its own BEGIN/COMMIT** (`withTransactionAsync`'s nested-join, :495). So N operations inside one
489
+ * `transaction(fn)` produce exactly ONE BEGIN + ONE COMMIT on ONE connection. Outside a
490
+ * `transaction(fn)` the ambient pin is absent, so a bare write's own `executeTransactionAsync` sees
491
+ * no ambient tx and the write=tx guard fires ({@link WriteOutsideTransactionError}).
492
+ *
493
+ * NESTED `transaction()` joins the outer (one physical BEGIN/COMMIT; an inner error rolls back the
494
+ * WHOLE tx) — again via `withTransactionAsync`'s nested-join. Isolation/retry/rollbackOnly options on
495
+ * a nested call are ignored (the outer owns them). This is the API REFERENCE the native ports
496
+ * (#82-85) mirror.
497
+ */
498
+ function transaction(ctx, fn, options = {}, dialect = 'postgres', isConnectionError = defaultIsConnectionError, connection) {
499
+ // The boundary is `withTransactionAsync` with a body that ignores the tx ctx — ambient operations
500
+ // resolve the pinned connection through the ALS, not an explicit arg (v1 `txContext.run(func)`).
501
+ // `connection` (Phase C-2) routes the tx to a NAMED connection's writer pool (default when absent).
502
+ return withTransactionAsync(ctx, () => fn(), options, dialect, isConnectionError, connection);
503
+ }
504
+ /**
505
+ * **The SYNC transaction boundary (#141)** — the sync twin of {@link withTransactionAsync} for the
506
+ * in-process better-sqlite3 runtime. Pins ONE connection for the whole transaction (BEGIN…COMMIT on
507
+ * the same conn — the per-execution ownership the async path gets from the pool), issues the
508
+ * isolation-aware `BEGIN` ({@link beginStatements}), runs `fn(txCtx)` inside the tx scope marker
509
+ * (`runInTransactionScope` — so a nested write's guard/detection sees an active tx), then COMMITs or
510
+ * ROLLBACKs by the body's signal:
511
+ * - `{ commit: true, value }` → `COMMIT`, return `value`;
512
+ * - `{ commit: false, value }` → `ROLLBACK`, return `value` (a gate short-circuit / rollbackOnly —
513
+ * no committed change, but the body result is still returned, e.g. the short-circuit reason);
514
+ * - a THROW from `fn` → best-effort `ROLLBACK`, re-raise (the caller maps the driver error).
515
+ *
516
+ * Every statement `fn` issues resolves the pinned tx connection via `connectionFor` (the tx-owned
517
+ * conn), so the whole body runs atomically on one connection. This is the boundary the write/tx leaf
518
+ * path runs inside; the tx-control statements (BEGIN/COMMIT/ROLLBACK) go through the seam here, while
519
+ * the body's data statements ride the `executeSQL` transport leaf.
520
+ */
521
+ function withTransactionSync(outer, fn, dialect = 'sqlite', isolation) {
522
+ const ctx = outer.withConnection(outer.connectionFor({ write: true }), true);
523
+ for (const begin of (0, tx_options_1.beginStatements)(dialect, isolation))
524
+ run(ctx, begin, []);
525
+ try {
526
+ const r = (0, tx_options_1.runInTransactionScope)(() => fn(ctx));
527
+ run(ctx, r.commit ? 'COMMIT' : 'ROLLBACK', []);
528
+ return r.value;
529
+ }
530
+ catch (e) {
531
+ try {
532
+ run(ctx, 'ROLLBACK', []);
533
+ }
534
+ catch {
535
+ /* ROLLBACK best-effort; the caller surfaces the original failure */
536
+ }
537
+ throw e;
538
+ }
539
+ }
540
+ //# sourceMappingURL=exec-context.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"exec-context.js","sourceRoot":"","sources":["../../src/scp/exec-context.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,32 @@
1
+ /**
2
+ * litedbmodel v2 SCP — the SHARED relation-grouping core (#141).
3
+ *
4
+ * The ONE implementation of relation key-identity + dedupe + parent grouping, used by BOTH surfaces
5
+ * so there is a single source of truth (no duplicated grouping logic):
6
+ *
7
+ * - the EAGER graph — the op-independent `pluck` / `group` leaves (`./leaves`), run by bc
8
+ * `bindBehaviors` (N+1-free: `parents → pluck → executeSQL(WHERE fk = ANY(keys)) → group`);
9
+ * - the RUNTIME lazy / declarative path — `./relation` `runRelationOp` / `distributeToParent`, the
10
+ * typed-object lazy prototype getters + declarative `with` (a lazy relation can't be a baked
11
+ * graph — it fires on property access — so it keeps this grouping at runtime, over the SAME core).
12
+ *
13
+ * Nothing here touches SQL or a driver: it is pure in-memory grouping over already-fetched rows.
14
+ */
15
+ /** The stringified key identity for dedupe/grouping. Single scalar → `String(v)`; tuple → joined. */
16
+ export declare function keyIdentity(values: readonly unknown[]): string;
17
+ /**
18
+ * The deduped, non-null key TUPLES of `rows` over `keyCols` (insertion order preserved —
19
+ * deterministic). A tuple is dropped if ANY of its key columns is null/undefined (no partial keys);
20
+ * deduped on the stringified tuple identity (so `1` and `"1"` collapse exactly as `String(v)`).
21
+ */
22
+ export declare function dedupeKeyTuples(rows: readonly Record<string, unknown>[], keyCols: readonly string[]): unknown[][];
23
+ /** Group `children` by their `fkCols` tuple identity (a null/undefined key drops the child). */
24
+ export declare function groupByKey(children: readonly Record<string, unknown>[], fkCols: readonly string[]): Map<string, Record<string, unknown>[]>;
25
+ /**
26
+ * Distribute grouped children onto ONE parent per cardinality: `single === false` (hasMany) → the
27
+ * child list (`[]` when none); `single === true` (belongsTo/hasOne) → the single child (or `null`).
28
+ * Keyed by the parent's `pkCols` tuple identity. `null`/`[]` is the declared cardinality's empty
29
+ * representation, not an ad-hoc default.
30
+ */
31
+ export declare function attachToParent(parent: Record<string, unknown>, pkCols: readonly string[], byKey: Map<string, Record<string, unknown>[]>, single: boolean): Record<string, unknown>[] | Record<string, unknown> | null;
32
+ //# sourceMappingURL=grouping.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"grouping.d.ts","sourceRoot":"","sources":["../../src/scp/grouping.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAKH,qGAAqG;AACrG,wBAAgB,WAAW,CAAC,MAAM,EAAE,SAAS,OAAO,EAAE,GAAG,MAAM,CAO9D;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,EAAE,OAAO,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,EAAE,EAAE,CAYjH;AAED,gGAAgG;AAChG,wBAAgB,UAAU,CACxB,QAAQ,EAAE,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,EAC5C,MAAM,EAAE,SAAS,MAAM,EAAE,GACxB,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC,CAWxC;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAC5B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,MAAM,EAAE,SAAS,MAAM,EAAE,EACzB,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC,EAC7C,MAAM,EAAE,OAAO,GACd,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAK5D"}
Binary file
@@ -0,0 +1 @@
1
+ {"version":3,"file":"grouping.js","sourceRoot":"","sources":["../../src/scp/grouping.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;GAaG;;AAMH,kCAOC;AAOD,0CAYC;AAGD,gCAcC;AAQD,wCAUC;AAjED,wFAAwF;AACxF,MAAM,OAAO,GAAG,GAAG,CAAC;AAEpB,qGAAqG;AACrG,SAAgB,WAAW,CAAC,MAA0B;IACpD,kGAAkG;IAClG,uGAAuG;IACvG,gFAAgF;IAChF,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;IAClD,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,GAAG,OAAO,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IACrF,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;AACpD,CAAC;AAED;;;;GAIG;AACH,SAAgB,eAAe,CAAC,IAAwC,EAAE,OAA0B;IAClG,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAC/B,MAAM,GAAG,GAAgB,EAAE,CAAC;IAC5B,KAAK,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC;QACrB,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACvC,IAAI,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,SAAS,IAAI,CAAC,KAAK,IAAI,CAAC;YAAE,SAAS;QAC/D,MAAM,EAAE,GAAG,WAAW,CAAC,KAAK,CAAC,CAAC;QAC9B,IAAI,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;YAAE,SAAS;QAC3B,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QACb,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAClB,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,gGAAgG;AAChG,SAAgB,UAAU,CACxB,QAA4C,EAC5C,MAAyB;IAEzB,MAAM,KAAK,GAAG,IAAI,GAAG,EAAqC,CAAC;IAC3D,KAAK,MAAM,CAAC,IAAI,QAAQ,EAAE,CAAC;QACzB,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;QAC1C,IAAI,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,SAAS,IAAI,CAAC,KAAK,IAAI,CAAC;YAAE,SAAS;QAC/D,MAAM,CAAC,GAAG,WAAW,CAAC,KAAK,CAAC,CAAC;QAC7B,MAAM,IAAI,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;QAC1B,IAAI,IAAI,KAAK,SAAS;YAAE,KAAK,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;;YACrC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACpB,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;;;GAKG;AACH,SAAgB,cAAc,CAC5B,MAA+B,EAC/B,MAAyB,EACzB,KAA6C,EAC7C,MAAe;IAEf,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;IAC3C,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,SAAS,IAAI,CAAC,KAAK,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC,CAAC;IAC1G,IAAI,CAAC,MAAM;QAAE,OAAO,IAAI,IAAI,EAAE,CAAC;IAC/B,OAAO,IAAI,KAAK,SAAS,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AAChE,CAAC"}