@bjornpagen/bumbledb 0.20.2 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (192) hide show
  1. package/COOKBOOK.md +283 -1611
  2. package/README.md +156 -118
  3. package/dist/capacity.d.ts +16 -12
  4. package/dist/capacity.d.ts.map +1 -1
  5. package/dist/capacity.js +16 -48
  6. package/dist/capacity.js.map +1 -1
  7. package/dist/changes.d.ts +54 -0
  8. package/dist/changes.d.ts.map +1 -0
  9. package/dist/changes.js +245 -0
  10. package/dist/changes.js.map +1 -0
  11. package/dist/close.d.ts +24 -0
  12. package/dist/close.d.ts.map +1 -0
  13. package/dist/close.js +34 -0
  14. package/dist/close.js.map +1 -0
  15. package/dist/closed.d.ts +1 -3
  16. package/dist/closed.d.ts.map +1 -1
  17. package/dist/closed.js +24 -12
  18. package/dist/closed.js.map +1 -1
  19. package/dist/codec.d.ts +56 -0
  20. package/dist/codec.d.ts.map +1 -0
  21. package/dist/codec.js +289 -0
  22. package/dist/codec.js.map +1 -0
  23. package/dist/compile.d.ts +68 -0
  24. package/dist/compile.d.ts.map +1 -0
  25. package/dist/compile.js +75 -0
  26. package/dist/compile.js.map +1 -0
  27. package/dist/db-native.d.ts +170 -0
  28. package/dist/db-native.d.ts.map +1 -0
  29. package/dist/db-native.js +5 -0
  30. package/dist/db-native.js.map +1 -0
  31. package/dist/db.d.ts +101 -233
  32. package/dist/db.d.ts.map +1 -1
  33. package/dist/db.js +232 -1084
  34. package/dist/db.js.map +1 -1
  35. package/dist/errors.d.ts +57 -0
  36. package/dist/errors.d.ts.map +1 -0
  37. package/dist/errors.js +32 -0
  38. package/dist/errors.js.map +1 -0
  39. package/dist/face.d.ts.map +1 -1
  40. package/dist/face.js +2 -2
  41. package/dist/face.js.map +1 -1
  42. package/dist/fields.d.ts +65 -24
  43. package/dist/fields.d.ts.map +1 -1
  44. package/dist/fields.js +94 -24
  45. package/dist/fields.js.map +1 -1
  46. package/dist/index.d.ts +37 -32
  47. package/dist/index.d.ts.map +1 -1
  48. package/dist/index.js +17 -21
  49. package/dist/index.js.map +1 -1
  50. package/dist/internal/log.d.ts +24 -0
  51. package/dist/internal/log.d.ts.map +1 -0
  52. package/dist/internal/log.js +10 -0
  53. package/dist/internal/log.js.map +1 -0
  54. package/dist/law.d.ts +8 -13
  55. package/dist/law.d.ts.map +1 -1
  56. package/dist/law.js +6 -59
  57. package/dist/law.js.map +1 -1
  58. package/dist/lower.d.ts +0 -13
  59. package/dist/lower.d.ts.map +1 -1
  60. package/dist/lower.js +9 -17
  61. package/dist/lower.js.map +1 -1
  62. package/dist/migration.d.ts +33 -0
  63. package/dist/migration.d.ts.map +1 -0
  64. package/dist/migration.js +48 -0
  65. package/dist/migration.js.map +1 -0
  66. package/dist/native.d.ts +256 -301
  67. package/dist/native.d.ts.map +1 -1
  68. package/dist/native.js +65 -108
  69. package/dist/native.js.map +1 -1
  70. package/dist/query/atom.d.ts +24 -13
  71. package/dist/query/atom.d.ts.map +1 -1
  72. package/dist/query/atom.js +7 -3
  73. package/dist/query/atom.js.map +1 -1
  74. package/dist/query/compute.d.ts +68 -0
  75. package/dist/query/compute.d.ts.map +1 -0
  76. package/dist/query/compute.js +141 -0
  77. package/dist/query/compute.js.map +1 -0
  78. package/dist/query/find.d.ts +15 -8
  79. package/dist/query/find.d.ts.map +1 -1
  80. package/dist/query/find.js +6 -2
  81. package/dist/query/find.js.map +1 -1
  82. package/dist/query/lower.d.ts +23 -2
  83. package/dist/query/lower.d.ts.map +1 -1
  84. package/dist/query/lower.js +433 -80
  85. package/dist/query/lower.js.map +1 -1
  86. package/dist/query/parse-ir.d.ts.map +1 -1
  87. package/dist/query/parse-ir.js +17 -8
  88. package/dist/query/parse-ir.js.map +1 -1
  89. package/dist/query/run.d.ts +12 -2
  90. package/dist/query/run.d.ts.map +1 -1
  91. package/dist/query/run.js +26 -9
  92. package/dist/query/run.js.map +1 -1
  93. package/dist/query/scope.d.ts +47 -3
  94. package/dist/query/scope.d.ts.map +1 -1
  95. package/dist/query/scope.js +83 -19
  96. package/dist/query/scope.js.map +1 -1
  97. package/dist/relation.d.ts +3 -8
  98. package/dist/relation.d.ts.map +1 -1
  99. package/dist/relation.js +16 -10
  100. package/dist/relation.js.map +1 -1
  101. package/dist/result.d.ts +47 -0
  102. package/dist/result.d.ts.map +1 -0
  103. package/dist/result.js +50 -0
  104. package/dist/result.js.map +1 -0
  105. package/dist/rows.d.ts +69 -0
  106. package/dist/rows.d.ts.map +1 -0
  107. package/dist/rows.js +328 -0
  108. package/dist/rows.js.map +1 -0
  109. package/dist/runtime-codes.d.ts +2 -0
  110. package/dist/runtime-codes.d.ts.map +1 -0
  111. package/dist/runtime-codes.js +19 -0
  112. package/dist/runtime-codes.js.map +1 -0
  113. package/dist/runtime-errors.d.ts +106 -0
  114. package/dist/runtime-errors.d.ts.map +1 -0
  115. package/dist/runtime-errors.js +62 -0
  116. package/dist/runtime-errors.js.map +1 -0
  117. package/dist/runtime-native.d.ts +171 -0
  118. package/dist/runtime-native.d.ts.map +1 -0
  119. package/dist/runtime-native.js +5 -0
  120. package/dist/runtime-native.js.map +1 -0
  121. package/dist/runtime.d.ts +73 -0
  122. package/dist/runtime.d.ts.map +1 -0
  123. package/dist/runtime.js +293 -0
  124. package/dist/runtime.js.map +1 -0
  125. package/dist/scalar.d.ts +165 -0
  126. package/dist/scalar.d.ts.map +1 -0
  127. package/dist/scalar.js +344 -0
  128. package/dist/scalar.js.map +1 -0
  129. package/dist/schema.d.ts +1 -1
  130. package/dist/schema.d.ts.map +1 -1
  131. package/dist/schema.js +34 -37
  132. package/dist/schema.js.map +1 -1
  133. package/dist/shape.d.ts +28 -0
  134. package/dist/shape.d.ts.map +1 -0
  135. package/dist/shape.js +2 -0
  136. package/dist/shape.js.map +1 -0
  137. package/dist/spec.d.ts +27 -3
  138. package/dist/spec.d.ts.map +1 -1
  139. package/dist/spec.js +22 -1
  140. package/dist/spec.js.map +1 -1
  141. package/dist/statements.d.ts +16 -3
  142. package/dist/statements.d.ts.map +1 -1
  143. package/dist/statements.js +54 -28
  144. package/dist/statements.js.map +1 -1
  145. package/dist/uuid.d.ts +23 -0
  146. package/dist/uuid.d.ts.map +1 -0
  147. package/dist/uuid.js +54 -0
  148. package/dist/uuid.js.map +1 -0
  149. package/pack-provenance.json +7 -0
  150. package/package.json +12 -16
  151. package/src/capacity.ts +34 -54
  152. package/src/changes.ts +361 -0
  153. package/src/close.ts +53 -0
  154. package/src/closed.ts +25 -19
  155. package/src/codec.ts +379 -0
  156. package/src/compile.ts +149 -0
  157. package/src/db-native.ts +247 -0
  158. package/src/db.ts +461 -1632
  159. package/src/errors.ts +50 -0
  160. package/src/face.ts +2 -2
  161. package/src/fields.ts +182 -55
  162. package/src/index.ts +62 -126
  163. package/src/internal/log.ts +51 -0
  164. package/src/law.ts +13 -28
  165. package/src/lower.ts +9 -4
  166. package/src/migration.ts +69 -0
  167. package/src/native.ts +326 -487
  168. package/src/query/atom.ts +61 -25
  169. package/src/query/compute.ts +237 -0
  170. package/src/query/find.ts +31 -12
  171. package/src/query/lower.ts +531 -143
  172. package/src/query/parse-ir.ts +18 -13
  173. package/src/query/run.ts +32 -16
  174. package/src/query/scope.ts +140 -8
  175. package/src/relation.ts +17 -21
  176. package/src/result.ts +130 -0
  177. package/src/rows.ts +404 -0
  178. package/src/runtime-codes.ts +18 -0
  179. package/src/runtime-errors.ts +69 -0
  180. package/src/runtime-native.ts +242 -0
  181. package/src/runtime.ts +440 -0
  182. package/src/scalar.ts +560 -0
  183. package/src/schema.ts +35 -37
  184. package/src/shape.ts +31 -0
  185. package/src/spec.ts +33 -3
  186. package/src/statements.ts +75 -68
  187. package/src/uuid.ts +69 -0
  188. package/dist/marshal.d.ts +0 -44
  189. package/dist/marshal.d.ts.map +0 -1
  190. package/dist/marshal.js +0 -165
  191. package/dist/marshal.js.map +0 -1
  192. package/src/marshal.ts +0 -200
package/src/rows.ts ADDED
@@ -0,0 +1,404 @@
1
+ import { AuthoringError, SdkInvariantError } from "#errors.ts"
2
+ /**
3
+ * The successor row codec: fact object ⇄ positional cell array by field
4
+ * ordinal, schema-directed, in ONE place. The write side lowers named host
5
+ * objects to rows in the relation's field-declaration order (declaration
6
+ * order = ordinal ids); the read side decodes owned rows back to named
7
+ * objects of BARE structural values. This module is the one fact⇄row
8
+ * projector. It covers the COMPLETE successor value roster: bool, u64, i64,
9
+ * f64, uuid, str, bytes<N>, discrete intervals and dense float intervals,
10
+ * plus the closed-handle bijection (name ⇄ declaration-order row id).
11
+ *
12
+ * Cells here are OWNED plain host values; the native boundary re-judges
13
+ * every crossing against its resident sealed roster. Shape misuse throws
14
+ * the pure {@link AuthoringError}; the Effect ingestion boundary catches
15
+ * and types it (never an untracked partial draft). SharedArrayBuffer-backed
16
+ * views are refused before any copy. Host length is judged before string
17
+ * scans and byte copies (TS-004).
18
+ */
19
+ import type { AnyClosedRoster, AnyField } from "#fields.ts"
20
+ import { isFloatIntervalValue, isIntervalValue, literalShapeError, rosterOf } from "#fields.ts"
21
+ import type { AnyRelation, Fact, RelationData } from "#relation.ts"
22
+ import { Uuid } from "#uuid.ts"
23
+
24
+ /** Converter-granularity host cell wall (64 KiB). One oversize cell refuses. */
25
+ const HOST_CELL_MAX = 65536n
26
+
27
+ /**
28
+ * One owned cell at the private bridge boundary. The declared sealed field
29
+ * type disambiguates the union: `string` is text, an `uuid` in its
30
+ * canonical hyphenated UUID spelling (chapter 35), or a closed handle
31
+ * before lowering (closed handles cross as `bigint` row ids),
32
+ * `Uint8Array` is `bytes<N>`, `{ start, end }` bigints are a discrete
33
+ * interval and numbers a dense float interval.
34
+ */
35
+ type CellValue =
36
+ | boolean
37
+ | bigint
38
+ | number
39
+ | string
40
+ | Uint8Array
41
+ | { readonly start: bigint; readonly end: bigint }
42
+ | { readonly start: number; readonly end: number }
43
+
44
+ interface FlatRows {
45
+ readonly rows: bigint
46
+ readonly cells: readonly CellValue[]
47
+ /** Conservative charged byte size of the owned cells (input accounting). */
48
+ readonly bytes: bigint
49
+ }
50
+
51
+ function recordOf(fact: object): Readonly<Record<string, unknown>> {
52
+ if (typeof fact !== "object" && typeof fact !== "function") {
53
+ throw new AuthoringError({ message: "fact object is not string-indexable" })
54
+ }
55
+ return fact as Readonly<Record<string, unknown>>
56
+ }
57
+
58
+ function refuseShared(context: string, value: Uint8Array): void {
59
+ if (!(value.buffer instanceof ArrayBuffer)) {
60
+ throw new AuthoringError({
61
+ message: `${context}: SharedArrayBuffer-backed views are refused — make a synchronized stable copy into ordinary unshared input first`
62
+ })
63
+ }
64
+ }
65
+
66
+ /**
67
+ * Cheap host charge before any string scan or byte copy (TS-004). UTF-16
68
+ * code units × 2 upper-bounds UTF-8; byte views charge their length.
69
+ */
70
+ function hostCellCharge(value: unknown): bigint {
71
+ if (typeof value === "string") {
72
+ return BigInt(value.length) * 2n
73
+ }
74
+ if (value instanceof Uint8Array) {
75
+ return BigInt(value.byteLength)
76
+ }
77
+ if (typeof value === "boolean") {
78
+ return 1n
79
+ }
80
+ if (typeof value === "bigint" || typeof value === "number") {
81
+ return 8n
82
+ }
83
+ if (value !== null && typeof value === "object" && "start" in value && "end" in value) {
84
+ return 16n
85
+ }
86
+ return 0n
87
+ }
88
+
89
+ function assertHostCellFits(context: string, value: unknown, limit: bigint): bigint {
90
+ const charge = hostCellCharge(value)
91
+ if (charge > limit) {
92
+ throw new AuthoringError({
93
+ message: `${context}: host cell of ${charge} bytes exceeds the ${limit}-byte converter bound — refuse before copy or scan`
94
+ })
95
+ }
96
+ return charge
97
+ }
98
+
99
+ /**
100
+ * The write half of the closed bijection: one handle NAME to its u64 row
101
+ * id (declaration order = row ids). An unknown name is a pointed refusal
102
+ * naming the vocabulary and its roster.
103
+ */
104
+ function closedCellOf(context: string, closed: AnyClosedRoster, name: string): CellValue {
105
+ const id = closed.handles.indexOf(name)
106
+ if (id === -1) {
107
+ throw new AuthoringError({
108
+ message: `${context}: "${name}" is not a handle of ${closed.name} — the roster is ${closed.handles.join(", ")}`
109
+ })
110
+ }
111
+ return BigInt(id)
112
+ }
113
+
114
+ function handleOf(context: string, closed: AnyClosedRoster, cell: unknown): string {
115
+ if (typeof cell !== "bigint") {
116
+ throw literalShapeError(context, `a ${closed.name} handle id (bigint)`, cell)
117
+ }
118
+ const handle = closed.handles[Number(cell)]
119
+ if (handle === undefined) {
120
+ throw new AuthoringError({
121
+ message: `${context}: id ${cell} is outside the ${closed.name} roster (${closed.handles.join(", ")})`
122
+ })
123
+ }
124
+ return handle
125
+ }
126
+
127
+ /** Conservative owned-byte charge of one cell (host accounting, not wire). */
128
+ function cellBytes(cell: CellValue): bigint {
129
+ if (typeof cell === "boolean") {
130
+ return 1n
131
+ }
132
+ if (typeof cell === "bigint" || typeof cell === "number") {
133
+ return 8n
134
+ }
135
+ if (typeof cell === "string") {
136
+ // UTF-16 code units × 2 is a cheap safe upper bound before exact
137
+ // UTF-8 conversion is charged natively (chapter 35: reject oversize
138
+ // cells with cheap length bounds before costly conversion).
139
+ return BigInt(cell.length) * 2n
140
+ }
141
+ if (cell instanceof Uint8Array) {
142
+ return BigInt(cell.byteLength)
143
+ }
144
+ return 16n
145
+ }
146
+
147
+ function cellOf(context: string, field: AnyField, value: unknown): CellValue {
148
+ const roster = rosterOf(field)
149
+ if (roster !== undefined) {
150
+ if (typeof value !== "string") {
151
+ throw literalShapeError(context, `a ${roster.name} handle name (string)`, value)
152
+ }
153
+ return closedCellOf(context, roster, value)
154
+ }
155
+ switch (field.kind) {
156
+ case "bool": {
157
+ if (typeof value !== "boolean") {
158
+ throw literalShapeError(context, "boolean", value)
159
+ }
160
+ return value
161
+ }
162
+ case "u64":
163
+ case "i64": {
164
+ if (typeof value !== "bigint") {
165
+ throw literalShapeError(context, "bigint", value)
166
+ }
167
+ return value
168
+ }
169
+ case "str": {
170
+ if (typeof value !== "string") {
171
+ throw literalShapeError(context, "string", value)
172
+ }
173
+ assertHostCellFits(context, value, HOST_CELL_MAX)
174
+ if (!value.isWellFormed()) {
175
+ throw literalShapeError(context, "well-formed string", value)
176
+ }
177
+ return value
178
+ }
179
+ case "f64": {
180
+ if (typeof value !== "number") {
181
+ throw literalShapeError(context, "number", value)
182
+ }
183
+ return value
184
+ }
185
+ case "uuid": {
186
+ if (!Uuid.isUuid(value)) {
187
+ throw literalShapeError(context, "a UUID (canonical UUID text)", value)
188
+ }
189
+ // Chapter 35: uuid crosses the bridge as the canonical
190
+ // canonical hyphenated UUID STRING (the native marshal's spelling),
191
+ // never as sixteen raw bytes.
192
+ return value
193
+ }
194
+ case "bytes": {
195
+ if (!(value instanceof Uint8Array)) {
196
+ throw literalShapeError(context, "Uint8Array", value)
197
+ }
198
+ refuseShared(context, value)
199
+ assertHostCellFits(context, value, HOST_CELL_MAX)
200
+ if (value.byteLength !== field.width) {
201
+ throw new AuthoringError({
202
+ message: `${context}: bytes<${field.width}> takes exactly ${field.width} bytes (got ${value.byteLength})`
203
+ })
204
+ }
205
+ // Owned copy at the ownership boundary: later caller mutation
206
+ // cannot change an accepted cell.
207
+ return Uint8Array.from(value)
208
+ }
209
+ case "interval": {
210
+ if (field.element === "f64") {
211
+ if (!isFloatIntervalValue(value)) {
212
+ throw literalShapeError(context, "float interval ({ start, end } numbers)", value)
213
+ }
214
+ if (Number.isNaN(value.start) || Number.isNaN(value.end)) {
215
+ throw new AuthoringError({ message: `${context}: a float interval endpoint cannot be NaN` })
216
+ }
217
+ const start = Object.is(value.start, -0) ? 0 : value.start
218
+ const end = Object.is(value.end, -0) ? 0 : value.end
219
+ if (!(start < end)) {
220
+ throw new AuthoringError({
221
+ message: `${context}: a float interval is half-open and nonempty (start < end strictly)`
222
+ })
223
+ }
224
+ return { start, end }
225
+ }
226
+ if (!isIntervalValue(value)) {
227
+ throw literalShapeError(context, "interval ({ start, end } bigints)", value)
228
+ }
229
+ return { start: value.start, end: value.end }
230
+ }
231
+ }
232
+ }
233
+
234
+ /**
235
+ * The flat projector: every fact's cells land in ONE row-major cell array
236
+ * (length rows × arity) with the row count and charged byte size counted
237
+ * while projecting. Missing-field refusal and per-cell judgment are
238
+ * {@link cellOf}'s, byte for byte.
239
+ */
240
+ function flatRowsOf(data: RelationData, facts: Iterable<object>): FlatRows {
241
+ const cells: CellValue[] = []
242
+ let rows = 0n
243
+ let bytes = 0n
244
+ for (const fact of facts) {
245
+ rows += 1n
246
+ const record = recordOf(fact)
247
+ for (const declared of data.fields) {
248
+ const value = record[declared.name]
249
+ if (value === undefined) {
250
+ throw new AuthoringError({ message: `relation ${data.name}: fact is missing field ${declared.name}` })
251
+ }
252
+ const cell = cellOf(`relation ${data.name} field ${declared.name}`, declared.field, value)
253
+ bytes += cellBytes(cell)
254
+ cells.push(cell)
255
+ }
256
+ }
257
+ return { rows, cells, bytes }
258
+ }
259
+
260
+ function keyCellsOf(
261
+ data: RelationData,
262
+ projection: readonly string[],
263
+ key: Readonly<Record<string, unknown>>
264
+ ): CellValue[] {
265
+ for (const supplied of Object.keys(key)) {
266
+ if (key[supplied] !== undefined && !projection.includes(supplied)) {
267
+ throw new AuthoringError({
268
+ message: `relation ${data.name}: key object carries field ${supplied} outside the primary key projection (${projection.join(", ")})`
269
+ })
270
+ }
271
+ }
272
+ return projection.map(function marshalKeyCell(fieldName) {
273
+ const declared = data.fields.find(function byName(candidate) {
274
+ return candidate.name === fieldName
275
+ })
276
+ if (declared === undefined) {
277
+ throw new AuthoringError({
278
+ message: `relation ${data.name}: key projection cites unknown field ${fieldName}`
279
+ })
280
+ }
281
+ const value = key[fieldName]
282
+ if (value === undefined) {
283
+ throw new AuthoringError({
284
+ message: `relation ${data.name}: key object is missing field ${fieldName} — get reads through the primary (first-declared) key, whose projection is (${projection.join(", ")})`
285
+ })
286
+ }
287
+ return cellOf(`relation ${data.name} key field ${fieldName}`, declared.field, value)
288
+ })
289
+ }
290
+
291
+ function decodeCell(context: string, field: AnyField, cell: unknown): unknown {
292
+ const roster = rosterOf(field)
293
+ if (roster !== undefined) {
294
+ return handleOf(context, roster, cell)
295
+ }
296
+ switch (field.kind) {
297
+ case "bool": {
298
+ if (typeof cell !== "boolean") {
299
+ throw new SdkInvariantError({ message: `${context}: expected boolean cell` })
300
+ }
301
+ return cell
302
+ }
303
+ case "u64":
304
+ case "i64": {
305
+ if (typeof cell !== "bigint") {
306
+ throw new SdkInvariantError({ message: `${context}: expected bigint cell` })
307
+ }
308
+ return cell
309
+ }
310
+ case "f64": {
311
+ if (typeof cell !== "number") {
312
+ throw new SdkInvariantError({ message: `${context}: expected number cell` })
313
+ }
314
+ return cell
315
+ }
316
+ case "str": {
317
+ if (typeof cell !== "string") {
318
+ throw new SdkInvariantError({ message: `${context}: expected string cell` })
319
+ }
320
+ return cell
321
+ }
322
+ case "uuid": {
323
+ // The native renderer spells uuid as the canonical
324
+ // canonical hyphenated UUID string (marshal.rs `uuid_hex`); the read
325
+ // side revalidates the spelling and keeps the string value.
326
+ if (!Uuid.isUuid(cell)) {
327
+ throw new SdkInvariantError({
328
+ message: `${context}: expected an uuid cell (canonical UUID text)`
329
+ })
330
+ }
331
+ return cell
332
+ }
333
+ case "bytes": {
334
+ if (!(cell instanceof Uint8Array)) {
335
+ throw new SdkInvariantError({ message: `${context}: expected owned bytes` })
336
+ }
337
+ return cell
338
+ }
339
+ case "interval": {
340
+ if (field.element === "f64") {
341
+ if (!isFloatIntervalValue(cell)) {
342
+ throw new SdkInvariantError({ message: `${context}: expected a float interval cell` })
343
+ }
344
+ return Object.freeze({ start: cell.start, end: cell.end })
345
+ }
346
+ if (!isIntervalValue(cell)) {
347
+ throw new SdkInvariantError({ message: `${context}: expected an integer interval cell` })
348
+ }
349
+ return Object.freeze({ start: cell.start, end: cell.end })
350
+ }
351
+ }
352
+ }
353
+
354
+ function isCompleteFact<R extends AnyRelation>(
355
+ relation: R,
356
+ decoded: Readonly<Record<string, unknown>>
357
+ ): decoded is Readonly<Record<string, unknown>> & Fact<R> {
358
+ return relation.data.fields.every(function present(declared) {
359
+ return decoded[declared.name] !== undefined
360
+ })
361
+ }
362
+
363
+ /**
364
+ * The read half: one owned positional row into a plain frozen record in
365
+ * declared field order — the SAME fields and shapes on every row (chapter
366
+ * 35's stable row shape rule; no Proxy, no per-cell closures).
367
+ */
368
+ function factOfCells<R extends AnyRelation>(relation: R, row: readonly unknown[]): Fact<R> {
369
+ const data = relation.data
370
+ if (row.length !== data.fields.length) {
371
+ throw new SdkInvariantError({
372
+ message: `relation ${data.name}: row arity ${row.length} does not match the ${data.fields.length} declared fields`
373
+ })
374
+ }
375
+ const decoded: Record<string, unknown> = {}
376
+ data.fields.forEach(function decodeOne(declared, ordinal) {
377
+ const cell = row[ordinal]
378
+ if (cell === undefined) {
379
+ throw new SdkInvariantError({
380
+ message: `relation ${data.name}: row cell ${ordinal} (${declared.name}) is absent`
381
+ })
382
+ }
383
+ decoded[declared.name] = decodeCell(`relation ${data.name} field ${declared.name}`, declared.field, cell)
384
+ })
385
+ Object.freeze(decoded)
386
+ if (!isCompleteFact(relation, decoded)) {
387
+ throw new SdkInvariantError({ message: `relation ${data.name}: decoded row is not a complete fact` })
388
+ }
389
+ return decoded
390
+ }
391
+
392
+ export type { CellValue, FlatRows }
393
+ export {
394
+ assertHostCellFits,
395
+ cellBytes,
396
+ cellOf,
397
+ decodeCell,
398
+ factOfCells,
399
+ flatRowsOf,
400
+ handleOf,
401
+ hostCellCharge,
402
+ keyCellsOf,
403
+ recordOf
404
+ }
@@ -0,0 +1,18 @@
1
+ // Generated from the exact native runtimeErrorCodes export; do not edit.
2
+ export const runtimeErrorCodes = [
3
+ "RuntimeAlreadyLive",
4
+ "ForeignRuntime",
5
+ "ClosedHandle",
6
+ "SpentHandle",
7
+ "QueueFull",
8
+ "InvalidArgument",
9
+ "Internal",
10
+ "DirectoryBusy",
11
+ "WriterBusy",
12
+ "InvalidPath",
13
+ "Io",
14
+ "ResourceLimit",
15
+ "Engine",
16
+ "Cancelled",
17
+ "DeadlineExceeded"
18
+ ] as const
@@ -0,0 +1,69 @@
1
+ import { Schema } from "effect"
2
+ import { runtimeErrorCodes } from "#runtime-codes.ts"
3
+
4
+ export { runtimeErrorCodes } from "#runtime-codes.ts"
5
+
6
+ const ResourceLimit = Schema.Struct({
7
+ _tag: Schema.Literal("ResourceLimit"),
8
+ dimension: Schema.String,
9
+ used: Schema.BigInt,
10
+ requested: Schema.BigInt,
11
+ limit: Schema.BigInt
12
+ })
13
+ const PlainReason = Schema.Struct({
14
+ _tag: Schema.Literals(
15
+ runtimeErrorCodes.filter((code) => code !== "ResourceLimit" && code !== "Io" && code !== "Engine")
16
+ )
17
+ })
18
+ const Io = Schema.Struct({
19
+ _tag: Schema.Literal("Io"),
20
+ kind: Schema.String,
21
+ osCode: Schema.optional(Schema.Number)
22
+ })
23
+ /** A typed engine refusal crossing the executor: core family tag + message. */
24
+ const Engine = Schema.Struct({
25
+ _tag: Schema.Literal("Engine"),
26
+ kind: Schema.String,
27
+ message: Schema.String
28
+ })
29
+ export const DbReason = Schema.Union([ResourceLimit, Io, Engine, PlainReason])
30
+ export class DbError extends Schema.TaggedError<DbError>()("DbError", {
31
+ operation: Schema.String,
32
+ reason: DbReason
33
+ }) {
34
+ get code() {
35
+ return this.reason._tag
36
+ }
37
+ }
38
+
39
+ const decodeReason = Schema.decodeUnknownOption(DbReason)
40
+ export function dbError(operation: string, cause: unknown): DbError {
41
+ const decoded = decodeReason(cause)
42
+ return new DbError({ operation, reason: decoded._tag === "Some" ? decoded.value : { _tag: "Internal" } })
43
+ }
44
+
45
+ const Outstanding = Schema.Struct({
46
+ phase: Schema.Literals(["open", "closing", "closed"]),
47
+ queued: Schema.BigInt,
48
+ active: Schema.BigInt,
49
+ retained: Schema.BigInt,
50
+ owners: Schema.BigInt,
51
+ databases: Schema.BigInt,
52
+ natives: Schema.BigInt,
53
+ inputBytes: Schema.BigInt,
54
+ workingBytes: Schema.BigInt,
55
+ scratchBytes: Schema.BigInt,
56
+ resultBytes: Schema.BigInt
57
+ })
58
+ export type OutstandingWork = typeof Outstanding.Type
59
+ const Close = Schema.Union([
60
+ Schema.Struct({ kind: Schema.Literal("closed") }),
61
+ Schema.Struct({ kind: Schema.Literal("incomplete"), outstanding: Outstanding }),
62
+ Schema.Struct({ kind: Schema.Literal("failed"), error: DbError })
63
+ ])
64
+ export type CloseReport = typeof Close.Type
65
+
66
+ export class CloseFailure extends Schema.TaggedError<CloseFailure>()("CloseFailure", {
67
+ operation: Schema.String,
68
+ report: Close
69
+ }) {}