@bjornpagen/bumbledb 1.3.1 → 2.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 (290) hide show
  1. package/COOKBOOK.md +153 -77
  2. package/README.md +107 -41
  3. package/dist/alternatives.d.ts +5 -6
  4. package/dist/alternatives.d.ts.map +1 -1
  5. package/dist/alternatives.js +5 -6
  6. package/dist/alternatives.js.map +1 -1
  7. package/dist/bin.d.ts +3 -0
  8. package/dist/bin.d.ts.map +1 -0
  9. package/dist/bin.js +85 -0
  10. package/dist/bin.js.map +1 -0
  11. package/dist/capacity.d.ts +14 -17
  12. package/dist/capacity.d.ts.map +1 -1
  13. package/dist/capacity.js +7 -7
  14. package/dist/capacity.js.map +1 -1
  15. package/dist/changes.d.ts +32 -40
  16. package/dist/changes.d.ts.map +1 -1
  17. package/dist/changes.js +86 -104
  18. package/dist/changes.js.map +1 -1
  19. package/dist/closed.d.ts +2 -2
  20. package/dist/closed.d.ts.map +1 -1
  21. package/dist/closed.js +5 -5
  22. package/dist/closed.js.map +1 -1
  23. package/dist/codec.d.ts +13 -27
  24. package/dist/codec.d.ts.map +1 -1
  25. package/dist/codec.js +20 -21
  26. package/dist/codec.js.map +1 -1
  27. package/dist/compile.d.ts +26 -50
  28. package/dist/compile.d.ts.map +1 -1
  29. package/dist/compile.js +75 -64
  30. package/dist/compile.js.map +1 -1
  31. package/dist/database/database.d.ts +98 -0
  32. package/dist/database/database.d.ts.map +1 -0
  33. package/dist/database/database.js +249 -0
  34. package/dist/database/database.js.map +1 -0
  35. package/dist/database/driver.d.ts +40 -0
  36. package/dist/database/driver.d.ts.map +1 -0
  37. package/dist/database/driver.js +68 -0
  38. package/dist/database/driver.js.map +1 -0
  39. package/dist/database/fs.d.ts +12 -0
  40. package/dist/database/fs.d.ts.map +1 -0
  41. package/dist/database/fs.js +120 -0
  42. package/dist/database/fs.js.map +1 -0
  43. package/dist/database/generate.d.ts +26 -0
  44. package/dist/database/generate.d.ts.map +1 -0
  45. package/dist/database/generate.js +102 -0
  46. package/dist/database/generate.js.map +1 -0
  47. package/dist/database/hosted.d.ts +32 -0
  48. package/dist/database/hosted.d.ts.map +1 -0
  49. package/dist/database/hosted.js +44 -0
  50. package/dist/database/hosted.js.map +1 -0
  51. package/dist/database/io.d.ts +94 -0
  52. package/dist/database/io.d.ts.map +1 -0
  53. package/dist/database/io.js +35 -0
  54. package/dist/database/io.js.map +1 -0
  55. package/dist/database/mem.d.ts +26 -0
  56. package/dist/database/mem.d.ts.map +1 -0
  57. package/dist/database/mem.js +67 -0
  58. package/dist/database/mem.js.map +1 -0
  59. package/dist/database/migration.d.ts +55 -0
  60. package/dist/database/migration.d.ts.map +1 -0
  61. package/dist/database/migration.js +46 -0
  62. package/dist/database/migration.js.map +1 -0
  63. package/dist/database/s3.d.ts +36 -0
  64. package/dist/database/s3.d.ts.map +1 -0
  65. package/dist/database/s3.js +141 -0
  66. package/dist/database/s3.js.map +1 -0
  67. package/dist/db.d.ts +44 -128
  68. package/dist/db.d.ts.map +1 -1
  69. package/dist/db.js +163 -287
  70. package/dist/db.js.map +1 -1
  71. package/dist/engine.d.ts +7 -0
  72. package/dist/engine.d.ts.map +1 -0
  73. package/dist/engine.js +2 -0
  74. package/dist/engine.js.map +1 -0
  75. package/dist/errors.d.ts +152 -46
  76. package/dist/errors.d.ts.map +1 -1
  77. package/dist/errors.js +107 -19
  78. package/dist/errors.js.map +1 -1
  79. package/dist/face.d.ts +5 -5
  80. package/dist/face.d.ts.map +1 -1
  81. package/dist/face.js +6 -6
  82. package/dist/face.js.map +1 -1
  83. package/dist/fields.d.ts +4 -5
  84. package/dist/fields.d.ts.map +1 -1
  85. package/dist/fields.js +3 -3
  86. package/dist/fields.js.map +1 -1
  87. package/dist/index.d.ts +60 -57
  88. package/dist/index.d.ts.map +1 -1
  89. package/dist/index.js +27 -28
  90. package/dist/index.js.map +1 -1
  91. package/dist/judgment.d.ts +1 -1
  92. package/dist/judgment.js +1 -1
  93. package/dist/law.d.ts +16 -68
  94. package/dist/law.d.ts.map +1 -1
  95. package/dist/law.js +3 -3
  96. package/dist/law.js.map +1 -1
  97. package/dist/lower.d.ts +3 -3
  98. package/dist/lower.d.ts.map +1 -1
  99. package/dist/lower.js +35 -39
  100. package/dist/lower.js.map +1 -1
  101. package/dist/native/addon.d.ts +23 -0
  102. package/dist/native/addon.d.ts.map +1 -0
  103. package/dist/native/addon.js +15 -0
  104. package/dist/native/addon.js.map +1 -0
  105. package/dist/native/binding.d.ts +996 -0
  106. package/dist/native/json.d.ts +14 -0
  107. package/dist/native/json.d.ts.map +1 -0
  108. package/dist/native/json.js +73 -0
  109. package/dist/native/json.js.map +1 -0
  110. package/dist/native/load.d.ts +9 -0
  111. package/dist/native/load.d.ts.map +1 -0
  112. package/dist/native/load.js +30 -0
  113. package/dist/native/load.js.map +1 -0
  114. package/dist/native/op.d.ts +29 -0
  115. package/dist/native/op.d.ts.map +1 -0
  116. package/dist/native/op.js +50 -0
  117. package/dist/native/op.js.map +1 -0
  118. package/dist/query/atom.d.ts +13 -14
  119. package/dist/query/atom.d.ts.map +1 -1
  120. package/dist/query/atom.js +2 -2
  121. package/dist/query/atom.js.map +1 -1
  122. package/dist/query/compute.d.ts +4 -4
  123. package/dist/query/compute.d.ts.map +1 -1
  124. package/dist/query/compute.js +4 -4
  125. package/dist/query/compute.js.map +1 -1
  126. package/dist/query/find.d.ts +8 -8
  127. package/dist/query/find.d.ts.map +1 -1
  128. package/dist/query/find.js +1 -1
  129. package/dist/query/lower.d.ts +22 -17
  130. package/dist/query/lower.d.ts.map +1 -1
  131. package/dist/query/lower.js +230 -343
  132. package/dist/query/lower.js.map +1 -1
  133. package/dist/query/run.d.ts +5 -5
  134. package/dist/query/run.d.ts.map +1 -1
  135. package/dist/query/run.js +32 -15
  136. package/dist/query/run.js.map +1 -1
  137. package/dist/query/scope.d.ts +20 -28
  138. package/dist/query/scope.d.ts.map +1 -1
  139. package/dist/query/scope.js +7 -7
  140. package/dist/query/scope.js.map +1 -1
  141. package/dist/query/segments.d.ts +2 -2
  142. package/dist/query/segments.d.ts.map +1 -1
  143. package/dist/query/segments.js +3 -3
  144. package/dist/query/segments.js.map +1 -1
  145. package/dist/relation.d.ts +1 -1
  146. package/dist/relation.d.ts.map +1 -1
  147. package/dist/relation.js +4 -4
  148. package/dist/relation.js.map +1 -1
  149. package/dist/result.d.ts +15 -22
  150. package/dist/result.d.ts.map +1 -1
  151. package/dist/result.js +30 -39
  152. package/dist/result.js.map +1 -1
  153. package/dist/rows.d.ts +9 -33
  154. package/dist/rows.d.ts.map +1 -1
  155. package/dist/rows.js +8 -12
  156. package/dist/rows.js.map +1 -1
  157. package/dist/runtime.d.ts +17 -20
  158. package/dist/runtime.d.ts.map +1 -1
  159. package/dist/runtime.js +41 -205
  160. package/dist/runtime.js.map +1 -1
  161. package/dist/scalar.d.ts +4 -4
  162. package/dist/scalar.d.ts.map +1 -1
  163. package/dist/scalar.js +24 -8
  164. package/dist/scalar.js.map +1 -1
  165. package/dist/schema.d.ts +7 -18
  166. package/dist/schema.d.ts.map +1 -1
  167. package/dist/schema.js +18 -228
  168. package/dist/schema.js.map +1 -1
  169. package/dist/selection.d.ts +4 -4
  170. package/dist/selection.d.ts.map +1 -1
  171. package/dist/selection.js +5 -5
  172. package/dist/selection.js.map +1 -1
  173. package/dist/shape.d.ts +5 -5
  174. package/dist/shape.d.ts.map +1 -1
  175. package/dist/spec.d.ts +7 -79
  176. package/dist/spec.d.ts.map +1 -1
  177. package/dist/spec.js.map +1 -1
  178. package/dist/statements.d.ts +3 -3
  179. package/dist/statements.d.ts.map +1 -1
  180. package/dist/statements.js +10 -10
  181. package/dist/statements.js.map +1 -1
  182. package/dist/uuid.d.ts +1 -1
  183. package/dist/uuid.d.ts.map +1 -1
  184. package/dist/uuid.js +1 -1
  185. package/dist/uuid.js.map +1 -1
  186. package/dist/values.d.ts +2 -2
  187. package/dist/values.d.ts.map +1 -1
  188. package/dist/values.js +2 -2
  189. package/dist/values.js.map +1 -1
  190. package/package.json +18 -18
  191. package/src/alternatives.ts +7 -8
  192. package/src/bin.ts +82 -0
  193. package/src/capacity.ts +20 -23
  194. package/src/changes.ts +134 -191
  195. package/src/closed.ts +5 -5
  196. package/src/codec.ts +35 -49
  197. package/src/compile.ts +91 -113
  198. package/src/database/database.ts +413 -0
  199. package/src/database/driver.ts +134 -0
  200. package/src/database/fs.ts +119 -0
  201. package/src/database/generate.ts +116 -0
  202. package/src/database/hosted.ts +102 -0
  203. package/src/database/io.ts +134 -0
  204. package/src/database/mem.ts +113 -0
  205. package/src/database/migration.ts +107 -0
  206. package/src/database/s3.ts +231 -0
  207. package/src/db.ts +290 -547
  208. package/src/engine.ts +14 -0
  209. package/src/errors.ts +118 -39
  210. package/src/face.ts +9 -9
  211. package/src/fields.ts +6 -7
  212. package/src/index.ts +92 -105
  213. package/src/judgment.ts +1 -1
  214. package/src/law.ts +18 -70
  215. package/src/lower.ts +61 -72
  216. package/src/native/addon.ts +54 -0
  217. package/src/native/binding.d.ts +996 -0
  218. package/src/native/json.ts +100 -0
  219. package/src/native/load.ts +31 -0
  220. package/src/native/op.ts +73 -0
  221. package/src/query/atom.ts +15 -16
  222. package/src/query/compute.ts +7 -7
  223. package/src/query/find.ts +8 -8
  224. package/src/query/lower.ts +270 -392
  225. package/src/query/run.ts +42 -21
  226. package/src/query/scope.ts +29 -37
  227. package/src/query/segments.ts +4 -4
  228. package/src/relation.ts +4 -4
  229. package/src/result.ts +53 -80
  230. package/src/rows.ts +18 -46
  231. package/src/runtime.ts +50 -277
  232. package/src/scalar.ts +32 -12
  233. package/src/schema.ts +23 -284
  234. package/src/selection.ts +6 -6
  235. package/src/shape.ts +5 -5
  236. package/src/spec.ts +7 -85
  237. package/src/statements.ts +11 -11
  238. package/src/uuid.ts +1 -1
  239. package/src/values.ts +4 -4
  240. package/dist/close.d.ts +0 -24
  241. package/dist/close.d.ts.map +0 -1
  242. package/dist/close.js +0 -34
  243. package/dist/close.js.map +0 -1
  244. package/dist/db-native.d.ts +0 -189
  245. package/dist/db-native.d.ts.map +0 -1
  246. package/dist/db-native.js +0 -13
  247. package/dist/db-native.js.map +0 -1
  248. package/dist/internal/log.d.ts +0 -26
  249. package/dist/internal/log.d.ts.map +0 -1
  250. package/dist/internal/log.js +0 -12
  251. package/dist/internal/log.js.map +0 -1
  252. package/dist/native.d.ts +0 -562
  253. package/dist/native.d.ts.map +0 -1
  254. package/dist/native.js +0 -123
  255. package/dist/native.js.map +0 -1
  256. package/dist/query/description.d.ts +0 -41
  257. package/dist/query/description.d.ts.map +0 -1
  258. package/dist/query/description.js +0 -311
  259. package/dist/query/description.js.map +0 -1
  260. package/dist/query/parse-ir.d.ts +0 -10
  261. package/dist/query/parse-ir.d.ts.map +0 -1
  262. package/dist/query/parse-ir.js +0 -280
  263. package/dist/query/parse-ir.js.map +0 -1
  264. package/dist/runtime-codes.d.ts +0 -2
  265. package/dist/runtime-codes.d.ts.map +0 -1
  266. package/dist/runtime-codes.js +0 -19
  267. package/dist/runtime-codes.js.map +0 -1
  268. package/dist/runtime-errors.d.ts +0 -138
  269. package/dist/runtime-errors.d.ts.map +0 -1
  270. package/dist/runtime-errors.js +0 -111
  271. package/dist/runtime-errors.js.map +0 -1
  272. package/dist/runtime-native.d.ts +0 -136
  273. package/dist/runtime-native.d.ts.map +0 -1
  274. package/dist/runtime-native.js +0 -5
  275. package/dist/runtime-native.js.map +0 -1
  276. package/dist/schema-file.d.ts +0 -7
  277. package/dist/schema-file.d.ts.map +0 -1
  278. package/dist/schema-file.js +0 -24
  279. package/dist/schema-file.js.map +0 -1
  280. package/pack-provenance.json +0 -7
  281. package/src/close.ts +0 -53
  282. package/src/db-native.ts +0 -235
  283. package/src/internal/log.ts +0 -46
  284. package/src/native.ts +0 -736
  285. package/src/query/description.ts +0 -424
  286. package/src/query/parse-ir.ts +0 -293
  287. package/src/runtime-codes.ts +0 -18
  288. package/src/runtime-errors.ts +0 -122
  289. package/src/runtime-native.ts +0 -181
  290. package/src/schema-file.ts +0 -38
@@ -0,0 +1,102 @@
1
+ /**
2
+ * The migrations directory: one `NNNN_name/` per migration holding the schema it migrates to
3
+ * (`schema.json`, the engine's spec, and `schema.ts`, the same schema as SDK code) and its
4
+ * `migration.ts`; `index.ts` bundles them in order. A migration's hash covers its id and its
5
+ * `schema.json`, so editing either after it ran is caught by `check`.
6
+ */
7
+ import { createHash } from "node:crypto";
8
+ import * as fs from "node:fs";
9
+ import * as path from "node:path";
10
+ import { compiledOf } from "../compile.js";
11
+ import { AuthoringError } from "../errors.js";
12
+ import { lower } from "../lower.js";
13
+ import { addon } from "../native/addon.js";
14
+ import { schemaDescriptor } from "../schema.js";
15
+ const DIRECTORY = /^([0-9]{4})_([A-Za-z0-9_]+)$/;
16
+ /** The `schema.json` text of a schema: its lowered spec, formatted for review. */
17
+ function specText(theory) {
18
+ return `${JSON.stringify(lower(schemaDescriptor(theory)), null, "\t")}\n`;
19
+ }
20
+ /** A migration's hash: sha256 over its id and its `schema.json` text. */
21
+ function migrationHash(id, spec) {
22
+ return createHash("sha256").update(`${id}\n${spec}`).digest("hex");
23
+ }
24
+ /** The migration directories under `root`, in order. */
25
+ function migrationIds(root) {
26
+ if (!fs.existsSync(root))
27
+ return [];
28
+ return fs
29
+ .readdirSync(root, { withFileTypes: true })
30
+ .filter((entry) => entry.isDirectory() && DIRECTORY.test(entry.name))
31
+ .map((entry) => entry.name)
32
+ .sort();
33
+ }
34
+ function indexText(ids) {
35
+ const imports = ids.map((id) => `import m${id.slice(0, 4)} from "./${id}/migration.ts"`);
36
+ const list = ids.map((id) => `m${id.slice(0, 4)}`).join(", ");
37
+ return `${imports.join("\n")}\n\nexport const migrations = [${list}] as const\n`;
38
+ }
39
+ function migrationText(id, hash, previous) {
40
+ const lines = ['import { Migration } from "@bjornpagen/bumbledb"'];
41
+ if (previous !== undefined)
42
+ lines.push(`import { schema as from } from "../${previous}/schema.ts"`);
43
+ lines.push('import { schema as to } from "./schema.ts"', "");
44
+ lines.push(previous === undefined
45
+ ? `export default Migration.make({ id: "${id}", hash: "${hash}", to })`
46
+ : `export default Migration.make({ id: "${id}", hash: "${hash}", from, to })`);
47
+ return `${lines.join("\n")}\n`;
48
+ }
49
+ /**
50
+ * Adds a migration to `schema` under `root` when it differs from the last migration's schema, and
51
+ * rewrites `index.ts`.
52
+ */
53
+ function generate(root, theory, name) {
54
+ if (!/^[A-Za-z0-9_]+$/.test(name))
55
+ throw new AuthoringError({ message: `migration name ${name}: letters, digits and _` });
56
+ const ids = migrationIds(root);
57
+ const spec = specText(theory);
58
+ const previous = ids.at(-1);
59
+ if (previous !== undefined && fs.readFileSync(path.join(root, previous, "schema.json"), "utf8") === spec) {
60
+ return { _tag: "Unchanged" };
61
+ }
62
+ const bindings = addon.schemaBindings(compiledOf(schemaDescriptor(theory)).handle);
63
+ if (bindings._tag === "Unrepresentable") {
64
+ throw new AuthoringError({ message: `schema ${theory.name}: ${bindings.coordinate}: ${bindings.reason}` });
65
+ }
66
+ const number = previous === undefined ? 1 : Number(previous.slice(0, 4)) + 1;
67
+ const id = `${number.toString().padStart(4, "0")}_${name}`;
68
+ const directory = path.join(root, id);
69
+ fs.mkdirSync(directory, { recursive: true });
70
+ fs.writeFileSync(path.join(directory, "schema.json"), spec);
71
+ fs.writeFileSync(path.join(directory, "schema.ts"), bindings.source);
72
+ fs.writeFileSync(path.join(directory, "migration.ts"), migrationText(id, migrationHash(id, spec), previous));
73
+ fs.writeFileSync(path.join(root, "index.ts"), indexText([...ids, id]));
74
+ return { _tag: "Created", id };
75
+ }
76
+ /** Everything `check` found wrong; empty when the directory is consistent with `schema`. */
77
+ function check(root, theory, bundled) {
78
+ const problems = [];
79
+ const ids = migrationIds(root);
80
+ if (ids.length === 0)
81
+ return [`${root}: no migrations; run bumbledb generate`];
82
+ if (fs.readFileSync(path.join(root, "index.ts"), "utf8") !== indexText(ids)) {
83
+ problems.push(`${root}/index.ts does not list the migration directories in order; run bumbledb generate`);
84
+ }
85
+ ids.forEach((id, index) => {
86
+ const spec = fs.readFileSync(path.join(root, id, "schema.json"), "utf8");
87
+ const migration = bundled[index];
88
+ if (migration === undefined || migration.id !== id) {
89
+ problems.push(`${id}: not bundled at position ${index + 1}`);
90
+ }
91
+ else if (migration.hash !== migrationHash(id, spec)) {
92
+ problems.push(`${id}: its hash does not match its schema.json; a migration is never edited after it runs`);
93
+ }
94
+ });
95
+ const last = ids.at(-1);
96
+ if (last !== undefined && fs.readFileSync(path.join(root, last, "schema.json"), "utf8") !== specText(theory)) {
97
+ problems.push(`the schema differs from ${last}; run bumbledb generate`);
98
+ }
99
+ return problems;
100
+ }
101
+ export { check, generate, migrationHash, migrationIds, specText };
102
+ //# sourceMappingURL=generate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generate.js","sourceRoot":"","sources":["../../src/database/generate.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,32 @@
1
+ import type { ChangesRef } from "../native/addon.ts";
2
+ import type { CopyPair, ExternalObject, HeadOut, HostedHandle, SettledOut } from "../native/binding.d.ts";
3
+ import type { MachinePort } from "./driver.ts";
4
+ type HostedRef = ExternalObject<HostedHandle>;
5
+ /** One machine request. `request` ids are 32 hex digits; `revision` present is an exact-revision precondition. */
6
+ type HostedRequest = {
7
+ readonly _tag: "Open";
8
+ } | {
9
+ readonly _tag: "Sync";
10
+ } | {
11
+ readonly _tag: "Resolve";
12
+ readonly request: string;
13
+ } | {
14
+ readonly _tag: "Freeze";
15
+ readonly leaseMillis: bigint;
16
+ } | {
17
+ readonly _tag: "Submit";
18
+ readonly request: string;
19
+ readonly revision: bigint | null;
20
+ readonly changes: ChangesRef;
21
+ } | {
22
+ readonly _tag: "Migrate";
23
+ readonly step: number;
24
+ readonly base: bigint;
25
+ readonly copy: readonly CopyPair[];
26
+ readonly rows: ChangesRef;
27
+ };
28
+ /** A port over one hosted machine; `onHead` sees every head a step reports. */
29
+ declare function hostedPort(hosted: HostedRef, onHead: (head: HeadOut) => void): MachinePort<HostedRequest, SettledOut>;
30
+ export type { HostedRef, HostedRequest };
31
+ export { hostedPort };
32
+ //# sourceMappingURL=hosted.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hosted.d.ts","sourceRoot":"","sources":["../../src/database/hosted.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,UAAU,EAAgB,MAAM,oBAAoB,CAAA;AAElE,OAAO,KAAK,EACX,QAAQ,EACR,cAAc,EACd,OAAO,EACP,YAAY,EAEZ,UAAU,EAEV,MAAM,wBAAwB,CAAA;AAE/B,OAAO,KAAK,EAAE,WAAW,EAAQ,MAAM,aAAa,CAAA;AAGpD,KAAK,SAAS,GAAG,cAAc,CAAC,YAAY,CAAC,CAAA;AAE7C,kHAAkH;AAClH,KAAK,aAAa,GACf;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GACzB;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GACzB;IAAE,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GACtD;IAAE,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IAAC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;CAAE,GACzD;IACA,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAA;IACvB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;IAChC,QAAQ,CAAC,OAAO,EAAE,UAAU,CAAA;CAC3B,GACD;IACA,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAA;IACxB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,IAAI,EAAE,SAAS,QAAQ,EAAE,CAAA;IAClC,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAA;CACxB,CAAA;AAMJ,+EAA+E;AAC/E,iBAAS,UAAU,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,GAAG,WAAW,CAAC,aAAa,EAAE,UAAU,CAAC,CAiD9G;AAED,YAAY,EAAE,SAAS,EAAE,aAAa,EAAE,CAAA;AACxC,OAAO,EAAE,UAAU,EAAE,CAAA"}
@@ -0,0 +1,44 @@
1
+ /**
2
+ * The addon's hosted machine as a driver port. A hosted step is never cancelled: its output carries
3
+ * requests the machine then waits on, so every step runs to completion even when its caller is
4
+ * interrupted.
5
+ */
6
+ import { Effect } from "effect";
7
+ import { addon } from "../native/addon.js";
8
+ import { call } from "../native/op.js";
9
+ function outcomeIn(result) {
10
+ return result._tag === "Keys" ? { _tag: "Keys", keys: [...result.keys] } : result;
11
+ }
12
+ /** A port over one hosted machine; `onHead` sees every head a step reports. */
13
+ function hostedPort(hosted, onHead) {
14
+ const step = (operation, start) => call(operation, start, addon.hostedStepTake).pipe(Effect.tap((out) => Effect.sync(() => {
15
+ if (out.head !== undefined)
16
+ onHead(out.head);
17
+ })), Effect.uninterruptible);
18
+ return {
19
+ request: (ticket, request) => {
20
+ switch (request._tag) {
21
+ case "Open":
22
+ case "Sync":
23
+ return step(`Database.${request._tag}`, (done) => addon.hostedStep(hosted, { _tag: request._tag, ticket }, done));
24
+ case "Resolve":
25
+ return step("Database.resolve", (done) => addon.hostedStep(hosted, { _tag: "Resolve", ticket, request: request.request }, done));
26
+ case "Freeze":
27
+ return step("Database.freeze", (done) => addon.hostedStep(hosted, { _tag: "Freeze", ticket, leaseMillis: request.leaseMillis }, done));
28
+ case "Submit":
29
+ return step("Database.submit", (done) => addon.hostedSubmit(hosted, ticket, request.request, request.revision, request.changes, done));
30
+ case "Migrate":
31
+ return step("Database.migrate", (done) => addon.hostedMigrate(hosted, ticket, request.step, request.base, [...request.copy], request.rows, done));
32
+ }
33
+ },
34
+ respond: (response) => {
35
+ const { id, date, result } = response;
36
+ return result._tag === "Body"
37
+ ? step("Database.respond", (done) => addon.hostedRespondBody(hosted, id, date, result.lastModified, result.bytes, done))
38
+ : step("Database.respond", (done) => addon.hostedRespond(hosted, id, date, outcomeIn(result), done));
39
+ },
40
+ close: step("Database.close", (done) => addon.hostedStep(hosted, { _tag: "Close" }, done))
41
+ };
42
+ }
43
+ export { hostedPort };
44
+ //# sourceMappingURL=hosted.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hosted.js","sourceRoot":"","sources":["../../src/database/hosted.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,94 @@
1
+ /**
2
+ * The object-store side of the hosted log. The log machine emits `IoRequest`s as data; this module
3
+ * runs them against an `ObjectStore` and turns every outcome into an `IoResponse`. Reads are
4
+ * idempotent and retried here; a create-only PUT is never retried here, because the machine
5
+ * resolves an ambiguous PUT by reading the key back.
6
+ */
7
+ import type { Duration } from "effect";
8
+ import { Effect, Schedule } from "effect";
9
+ import { DbError } from "../errors.ts";
10
+ import type { BucketOut, IoRequestOut } from "../native/binding.d.ts";
11
+ /** `Log` is the commit log (`log/`, an S3 Express directory bucket); `Checkpoints` holds `ckpt/` and `mig/`. */
12
+ type Bucket = BucketOut;
13
+ /** One request from the machine. `key` is relative to the database prefix. */
14
+ type IoRequest = IoRequestOut;
15
+ /** Unix milliseconds on the store's clock. */
16
+ type Millis = bigint;
17
+ /** Where a GET delivers the object: returned in memory, or written to a local file. */
18
+ type Target = {
19
+ readonly _tag: "Memory";
20
+ } | {
21
+ readonly _tag: "File";
22
+ readonly path: string;
23
+ };
24
+ /** What a create-only PUT uploads: bytes in memory, or a local file. */
25
+ type Body = {
26
+ readonly _tag: "Bytes";
27
+ readonly bytes: Uint8Array;
28
+ } | {
29
+ readonly _tag: "File";
30
+ readonly path: string;
31
+ };
32
+ type Fetched = {
33
+ readonly _tag: "Body";
34
+ readonly bytes: Uint8Array;
35
+ readonly lastModified: Millis;
36
+ } | {
37
+ readonly _tag: "Saved";
38
+ readonly lastModified: Millis;
39
+ } | {
40
+ readonly _tag: "Missing";
41
+ };
42
+ /** `Occupied`: the key exists, or, for a log object, another conditional write to it was in progress. */
43
+ type Created = {
44
+ readonly _tag: "Created";
45
+ } | {
46
+ readonly _tag: "Occupied";
47
+ };
48
+ type Listed = {
49
+ readonly _tag: "Keys";
50
+ readonly keys: readonly string[];
51
+ };
52
+ type Deleted = {
53
+ readonly _tag: "Deleted";
54
+ };
55
+ /** `Failed` covers everything a store could not answer definitively: 5xx, timeouts, transport. */
56
+ type IoResult = Fetched | Created | Listed | Deleted | {
57
+ readonly _tag: "Failed";
58
+ };
59
+ interface IoResponse {
60
+ readonly id: bigint;
61
+ /** The store's `Date` header, when it sent one. */
62
+ readonly date: Millis | null;
63
+ readonly result: IoResult;
64
+ }
65
+ /** A store answer plus the store's clock reading. */
66
+ interface Reply<R> {
67
+ readonly date: Millis | null;
68
+ readonly result: R;
69
+ }
70
+ /**
71
+ * The four verbs the log needs. Keys arrive relative; a store owns its own prefix. LIST and DELETE
72
+ * exist only for `Checkpoints`: LIST order on an Express bucket is not lexicographic, and a `log/`
73
+ * key must never disappear.
74
+ */
75
+ interface ObjectStore {
76
+ readonly get: (bucket: Bucket, key: string, target: Target) => Effect.Effect<Reply<Fetched>, DbError>;
77
+ readonly putIfAbsent: (bucket: Bucket, key: string, body: Body) => Effect.Effect<Reply<Created>, DbError>;
78
+ /** Checkpoint keys under `prefix` after `startAfter`, in lexicographic order. */
79
+ readonly list: (prefix: string, startAfter: string | null, maxKeys: number) => Effect.Effect<Reply<Listed>, DbError>;
80
+ /** Deletes one checkpoint key; deleting a missing key succeeds. */
81
+ readonly delete: (key: string) => Effect.Effect<Reply<Deleted>, DbError>;
82
+ }
83
+ interface ExecutorOptions {
84
+ /** Bound on one store call; a call that exceeds it counts as `Failed` (or is retried, for a read). */
85
+ readonly timeout: Duration.Input;
86
+ /** Retry policy for GET, LIST and DELETE. */
87
+ readonly readRetry: Schedule.Schedule<unknown, unknown>;
88
+ }
89
+ declare const defaultExecutorOptions: ExecutorOptions;
90
+ /** Runs one request to an `IoResponse`; it never fails. */
91
+ declare function execute(store: ObjectStore, request: IoRequest, options?: ExecutorOptions): Effect.Effect<IoResponse>;
92
+ export type { Body, Bucket, Created, Deleted, ExecutorOptions, Fetched, IoRequest, IoResponse, IoResult, Listed, Millis, ObjectStore, Reply, Target };
93
+ export { defaultExecutorOptions, execute };
94
+ //# sourceMappingURL=io.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"io.d.ts","sourceRoot":"","sources":["../../src/database/io.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,35 @@
1
+ import { Effect, Schedule } from "effect";
2
+ import { DbError } from "../errors.js";
3
+ const defaultExecutorOptions = {
4
+ timeout: "10 seconds",
5
+ readRetry: Schedule.exponential("20 millis").pipe(Schedule.jittered, Schedule.upTo({ times: 4 }))
6
+ };
7
+ function refused(request) {
8
+ return Effect.fail(new DbError({ operation: `ObjectStore.${request.op._tag}`, reason: { _tag: "InvalidArgument" } }));
9
+ }
10
+ function dispatch(store, request) {
11
+ const { bucket, key, op } = request;
12
+ switch (op._tag) {
13
+ case "GetMemory":
14
+ return store.get(bucket, key, { _tag: "Memory" });
15
+ case "GetFile":
16
+ return store.get(bucket, key, { _tag: "File", path: op.path });
17
+ case "PutBytes":
18
+ return store.putIfAbsent(bucket, key, { _tag: "Bytes", bytes: op.bytes });
19
+ case "PutFile":
20
+ return store.putIfAbsent(bucket, key, { _tag: "File", path: op.path });
21
+ case "List":
22
+ return bucket === "Checkpoints" ? store.list(key, op.startAfter ?? null, op.maxKeys) : refused(request);
23
+ case "Delete":
24
+ return bucket === "Checkpoints" ? store.delete(key) : refused(request);
25
+ }
26
+ }
27
+ /** Runs one request to an `IoResponse`; it never fails. */
28
+ function execute(store, request, options = defaultExecutorOptions) {
29
+ const once = Effect.timeout(dispatch(store, request), options.timeout);
30
+ const write = request.op._tag === "PutBytes" || request.op._tag === "PutFile";
31
+ const attempts = write ? once : Effect.retry(once, options.readRetry);
32
+ return attempts.pipe(Effect.map((reply) => ({ id: request.id, date: reply.date, result: reply.result })), Effect.catch(() => Effect.succeed({ id: request.id, date: null, result: { _tag: "Failed" } })));
33
+ }
34
+ export { defaultExecutorOptions, execute };
35
+ //# sourceMappingURL=io.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"io.js","sourceRoot":"","sources":["../../src/database/io.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ import type { Bucket, Millis, ObjectStore } from "./io.ts";
2
+ type Verb = "get" | "putIfAbsent" | "list" | "delete";
3
+ /** `Fail`: the call fails before it has any effect. `Lose`: the call takes effect, then fails, like a lost response. */
4
+ type Fault = "Fail" | "Lose";
5
+ interface MemStoreOptions {
6
+ /** The store clock behind `Date` and `Last-Modified`. Defaults to a counter that ticks once per call. */
7
+ readonly clock?: () => Millis;
8
+ /** Picks the fault, if any, for each call. */
9
+ readonly fault?: (call: {
10
+ readonly verb: Verb;
11
+ readonly bucket: Bucket;
12
+ readonly key: string;
13
+ }) => Fault | undefined;
14
+ }
15
+ /** An in-memory store with the create-only semantics of S3, and deterministic fault injection for tests. */
16
+ interface MemStore extends ObjectStore {
17
+ /** A copy of the objects currently in `bucket`, by key. */
18
+ readonly objects: (bucket: Bucket) => ReadonlyMap<string, Uint8Array>;
19
+ }
20
+ declare function make(options?: MemStoreOptions): MemStore;
21
+ declare const MemStore: Readonly<{
22
+ make: typeof make;
23
+ }>;
24
+ export type { Fault, MemStoreOptions };
25
+ export { MemStore };
26
+ //# sourceMappingURL=mem.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mem.d.ts","sourceRoot":"","sources":["../../src/database/mem.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAQ,MAAM,EAAqC,MAAM,EAAE,WAAW,EAAiB,MAAM,SAAS,CAAA;AAElH,KAAK,IAAI,GAAG,KAAK,GAAG,aAAa,GAAG,MAAM,GAAG,QAAQ,CAAA;AAErD,wHAAwH;AACxH,KAAK,KAAK,GAAG,MAAM,GAAG,MAAM,CAAA;AAE5B,UAAU,eAAe;IACxB,yGAAyG;IACzG,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,MAAM,CAAA;IAC7B,8CAA8C;IAC9C,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,EAAE;QAAE,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC;QAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;KAAE,KAAK,KAAK,GAAG,SAAS,CAAA;CACpH;AAOD,4GAA4G;AAC5G,UAAU,QAAS,SAAQ,WAAW;IACrC,2DAA2D;IAC3D,QAAQ,CAAC,OAAO,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,WAAW,CAAC,MAAM,EAAE,UAAU,CAAC,CAAA;CACrE;AAMD,iBAAS,IAAI,CAAC,OAAO,GAAE,eAAoB,GAAG,QAAQ,CA2ErD;AAED,QAAA,MAAM,QAAQ;;EAA0B,CAAA;AAExC,YAAY,EAAE,KAAK,EAAE,eAAe,EAAE,CAAA;AACtC,OAAO,EAAE,QAAQ,EAAE,CAAA"}
@@ -0,0 +1,67 @@
1
+ import * as fs from "node:fs/promises";
2
+ import { Effect } from "effect";
3
+ import { DbError } from "../errors.js";
4
+ function failure(operation) {
5
+ return new DbError({ operation, reason: { _tag: "Io", kind: "Injected" } });
6
+ }
7
+ function make(options = {}) {
8
+ let ticks = 0n;
9
+ const clock = options.clock ??
10
+ (() => {
11
+ ticks += 1n;
12
+ return ticks;
13
+ });
14
+ const buckets = { Log: new Map(), Checkpoints: new Map() };
15
+ function run(verb, bucket, key, body) {
16
+ return Effect.suspend(() => {
17
+ const fault = options.fault?.({ verb, bucket, key });
18
+ const operation = `MemStore.${verb}`;
19
+ if (fault === "Fail")
20
+ return Effect.fail(failure(operation));
21
+ const now = clock();
22
+ return Effect.flatMap(body(now), (result) => fault === "Lose" ? Effect.fail(failure(operation)) : Effect.succeed({ date: now, result }));
23
+ });
24
+ }
25
+ const io = (operation, f) => Effect.tryPromise({
26
+ try: f,
27
+ catch: () => new DbError({ operation, reason: { _tag: "Io", kind: "File" } })
28
+ });
29
+ return {
30
+ get: (bucket, key, target) => run("get", bucket, key, () => {
31
+ const stored = buckets[bucket].get(key);
32
+ if (stored === undefined)
33
+ return Effect.succeed({ _tag: "Missing" });
34
+ if (target._tag === "Memory") {
35
+ return Effect.succeed({ _tag: "Body", bytes: stored.bytes.slice(), lastModified: stored.lastModified });
36
+ }
37
+ return io("MemStore.get", () => fs.writeFile(target.path, stored.bytes)).pipe(Effect.as({ _tag: "Saved", lastModified: stored.lastModified }));
38
+ }),
39
+ putIfAbsent: (bucket, key, body) => run("putIfAbsent", bucket, key, (now) => {
40
+ const bytes = body._tag === "Bytes"
41
+ ? Effect.succeed(body.bytes.slice())
42
+ : io("MemStore.putIfAbsent", () => fs.readFile(body.path)).pipe(Effect.map((buffer) => new Uint8Array(buffer)));
43
+ return Effect.map(bytes, (owned) => {
44
+ const objects = buckets[bucket];
45
+ if (objects.has(key))
46
+ return { _tag: "Occupied" };
47
+ objects.set(key, { bytes: owned, lastModified: now });
48
+ return { _tag: "Created" };
49
+ });
50
+ }),
51
+ list: (prefix, startAfter, maxKeys) => run("list", "Checkpoints", prefix, () => {
52
+ const keys = [...buckets.Checkpoints.keys()]
53
+ .filter((key) => key.startsWith(prefix) && (startAfter === null || key > startAfter))
54
+ .sort()
55
+ .slice(0, maxKeys);
56
+ return Effect.succeed({ _tag: "Keys", keys });
57
+ }),
58
+ delete: (key) => run("delete", "Checkpoints", key, () => {
59
+ buckets.Checkpoints.delete(key);
60
+ return Effect.succeed({ _tag: "Deleted" });
61
+ }),
62
+ objects: (bucket) => new Map([...buckets[bucket]].map(([key, stored]) => [key, stored.bytes.slice()]))
63
+ };
64
+ }
65
+ const MemStore = Object.freeze({ make });
66
+ export { MemStore };
67
+ //# sourceMappingURL=mem.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mem.js","sourceRoot":"","sources":["../../src/database/mem.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,55 @@
1
+ import type { Effect, Scope } from "effect";
2
+ import type { ChangeDraft } from "../changes.ts";
3
+ import type { QueryReader } from "../db.ts";
4
+ import type { DbError } from "../errors.ts";
5
+ import type { AnySchema } from "../schema.ts";
6
+ /** What `populate` reads from (the database at the old schema) and writes into (rows at the new one). */
7
+ interface PopulateContext<From extends AnySchema, To extends AnySchema> {
8
+ readonly from: QueryReader<From>;
9
+ readonly into: ChangeDraft<To>;
10
+ }
11
+ /**
12
+ * Computes the rows a migration adds at its new schema, reading the database at the old one.
13
+ * Relations that keep their name and fields are copied unchanged without code.
14
+ */
15
+ type Populate<From extends AnySchema, To extends AnySchema> = (context: PopulateContext<From, To>) => Effect.Effect<void, DbError, Scope.Scope>;
16
+ /**
17
+ * One bundled migration: its stable `id` (the directory name), the content `hash` that
18
+ * `bumbledb generate` wrote (64 hex digits), and the schema it migrates to. The first migration of a
19
+ * bundle has no `from`: it is the initial schema, and its `populate` seeds a newly created database
20
+ * once.
21
+ */
22
+ interface Migration<From extends AnySchema | undefined = AnySchema | undefined, To extends AnySchema = AnySchema> {
23
+ readonly id: string;
24
+ readonly hash: string;
25
+ readonly from: From;
26
+ readonly to: To;
27
+ readonly populate?: Populate<From extends AnySchema ? From : To, To>;
28
+ }
29
+ /** Any migration of a bundle; its `populate` is read back through {@link populateOf}. */
30
+ interface AnyMigration {
31
+ readonly id: string;
32
+ readonly hash: string;
33
+ readonly from: AnySchema | undefined;
34
+ readonly to: AnySchema;
35
+ readonly populate?: unknown;
36
+ }
37
+ /** A bundle: the initial migration first, then each migration from its predecessor's schema. */
38
+ type Migrations = readonly [AnyMigration, ...AnyMigration[]];
39
+ declare function make<To extends AnySchema, From extends AnySchema = never>(input: {
40
+ readonly id: string;
41
+ readonly hash: string;
42
+ readonly from?: From;
43
+ readonly to: To;
44
+ readonly populate?: Populate<[From] extends [never] ? To : From, To>;
45
+ }): Migration<[From] extends [never] ? undefined : From, To>;
46
+ /** The populate step of a migration `make` built. */
47
+ declare function populateOf(migration: AnyMigration): Populate<AnySchema, AnySchema> | undefined;
48
+ /** Checks that each migration starts from its predecessor's schema and that ids are unique. */
49
+ declare function verifyBundle(migrations: Migrations): void;
50
+ declare const Migration: Readonly<{
51
+ make: typeof make;
52
+ }>;
53
+ export type { AnyMigration, Migrations, Populate, PopulateContext };
54
+ export { Migration, populateOf, verifyBundle };
55
+ //# sourceMappingURL=migration.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"migration.d.ts","sourceRoot":"","sources":["../../src/database/migration.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,46 @@
1
+ import { AuthoringError } from "../errors.js";
2
+ import { schemaDescriptor, schemasAgree } from "../schema.js";
3
+ const HASH = /^[0-9a-f]{64}$/;
4
+ const ID = /^[0-9]{4}_[A-Za-z0-9_]+$/;
5
+ function make(input) {
6
+ if (!ID.test(input.id))
7
+ throw new AuthoringError({ message: `migration ${input.id}: an id is NNNN_name` });
8
+ if (!HASH.test(input.hash))
9
+ throw new AuthoringError({ message: `migration ${input.id}: a hash is 64 hex digits` });
10
+ const migration = {
11
+ id: input.id,
12
+ hash: input.hash,
13
+ from: input.from === undefined ? undefined : schemaDescriptor(input.from),
14
+ to: schemaDescriptor(input.to),
15
+ ...(input.populate === undefined ? {} : { populate: input.populate })
16
+ };
17
+ return Object.freeze(migration);
18
+ }
19
+ /** The populate step of a migration `make` built. */
20
+ function populateOf(migration) {
21
+ return migration.populate;
22
+ }
23
+ /** Checks that each migration starts from its predecessor's schema and that ids are unique. */
24
+ function verifyBundle(migrations) {
25
+ const ids = new Set();
26
+ migrations.forEach((migration, index) => {
27
+ if (ids.has(migration.id))
28
+ throw new AuthoringError({ message: `migrations: ${migration.id} appears twice` });
29
+ ids.add(migration.id);
30
+ const previous = migrations[index - 1];
31
+ if (previous === undefined) {
32
+ if (migration.from !== undefined) {
33
+ throw new AuthoringError({ message: `migrations: the first migration ${migration.id} has no from schema` });
34
+ }
35
+ return;
36
+ }
37
+ if (migration.from === undefined || !schemasAgree(migration.from, previous.to)) {
38
+ throw new AuthoringError({
39
+ message: `migrations: ${migration.id} must start from the schema ${previous.id} migrates to`
40
+ });
41
+ }
42
+ });
43
+ }
44
+ const Migration = Object.freeze({ make });
45
+ export { Migration, populateOf, verifyBundle };
46
+ //# sourceMappingURL=migration.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"migration.js","sourceRoot":"","sources":["../../src/database/migration.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAA;AAE7C,OAAO,EAAE,gBAAgB,EAAE,YAAY,EAAE,MAAM,cAAc,CAAA;AA0C7D,MAAM,IAAI,GAAG,gBAAgB,CAAA;AAC7B,MAAM,EAAE,GAAG,0BAA0B,CAAA;AASrC,SAAS,IAAI,CAAC,KAMb;IACA,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;QAAE,MAAM,IAAI,cAAc,CAAC,EAAE,OAAO,EAAE,aAAa,KAAK,CAAC,EAAE,sBAAsB,EAAE,CAAC,CAAA;IAC1G,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC;QAAE,MAAM,IAAI,cAAc,CAAC,EAAE,OAAO,EAAE,aAAa,KAAK,CAAC,EAAE,2BAA2B,EAAE,CAAC,CAAA;IACnH,MAAM,SAAS,GAAG;QACjB,EAAE,EAAE,KAAK,CAAC,EAAE;QACZ,IAAI,EAAE,KAAK,CAAC,IAAI;QAChB,IAAI,EAAE,KAAK,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,gBAAgB,CAAC,KAAK,CAAC,IAAI,CAAC;QACzE,EAAE,EAAE,gBAAgB,CAAC,KAAK,CAAC,EAAE,CAAC;QAC9B,GAAG,CAAC,KAAK,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,KAAK,CAAC,QAAQ,EAAE,CAAC;KACrE,CAAA;IACD,OAAO,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,CAAA;AAChC,CAAC;AAED,qDAAqD;AACrD,SAAS,UAAU,CAAC,SAAuB;IAC1C,OAAO,SAAS,CAAC,QAAsD,CAAA;AACxE,CAAC;AAED,+FAA+F;AAC/F,SAAS,YAAY,CAAC,UAAsB;IAC3C,MAAM,GAAG,GAAG,IAAI,GAAG,EAAU,CAAA;IAC7B,UAAU,CAAC,OAAO,CAAC,CAAC,SAAS,EAAE,KAAK,EAAE,EAAE;QACvC,IAAI,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC;YAAE,MAAM,IAAI,cAAc,CAAC,EAAE,OAAO,EAAE,eAAe,SAAS,CAAC,EAAE,gBAAgB,EAAE,CAAC,CAAA;QAC7G,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC,CAAA;QACrB,MAAM,QAAQ,GAAG,UAAU,CAAC,KAAK,GAAG,CAAC,CAAC,CAAA;QACtC,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;YAC5B,IAAI,SAAS,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;gBAClC,MAAM,IAAI,cAAc,CAAC,EAAE,OAAO,EAAE,mCAAmC,SAAS,CAAC,EAAE,qBAAqB,EAAE,CAAC,CAAA;YAC5G,CAAC;YACD,OAAM;QACP,CAAC;QACD,IAAI,SAAS,CAAC,IAAI,KAAK,SAAS,IAAI,CAAC,YAAY,CAAC,SAAS,CAAC,IAAI,EAAE,QAAQ,CAAC,EAAE,CAAC,EAAE,CAAC;YAChF,MAAM,IAAI,cAAc,CAAC;gBACxB,OAAO,EAAE,eAAe,SAAS,CAAC,EAAE,+BAA+B,QAAQ,CAAC,EAAE,cAAc;aAC5F,CAAC,CAAA;QACH,CAAC;IACF,CAAC,CAAC,CAAA;AACH,CAAC;AAED,MAAM,SAAS,GAAG,MAAM,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,CAAC,CAAA;AAGzC,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,YAAY,EAAE,CAAA"}
@@ -0,0 +1,36 @@
1
+ import type { ObjectStore } from "./io.ts";
2
+ /**
3
+ * The part of an AWS SDK v3 `S3Client` the store calls. Declared here so the package's types do not
4
+ * require the optional `@aws-sdk/client-s3` peer.
5
+ */
6
+ interface S3Sender {
7
+ send(command: never, options: {
8
+ readonly abortSignal: AbortSignal;
9
+ }): Promise<unknown>;
10
+ }
11
+ interface S3StoreOptions {
12
+ /**
13
+ * The application's own `S3Client`: it owns credentials, region, endpoint and SDK retries. Its
14
+ * connections resolve DNS on libuv's thread pool, 4 threads by default, which serializes a cold
15
+ * open's parallel reads where lookups are slow.
16
+ */
17
+ readonly client: S3Sender;
18
+ /** The commit log bucket, ideally an S3 Express directory bucket (`name--azid--x-s3`). */
19
+ readonly log: {
20
+ readonly bucket: string;
21
+ };
22
+ /** The checkpoint bucket: an S3 Standard bucket, whose LIST is lexicographic. */
23
+ readonly checkpoints: {
24
+ readonly bucket: string;
25
+ };
26
+ /** Prepended to every key; empty, or ending in `/`. */
27
+ readonly prefix: string;
28
+ }
29
+ /** A store over the application's AWS SDK v3 client. Every key lives under `prefix`. */
30
+ declare function make(options: S3StoreOptions): ObjectStore;
31
+ declare const S3Store: Readonly<{
32
+ make: typeof make;
33
+ }>;
34
+ export type { S3Sender, S3StoreOptions };
35
+ export { S3Store };
36
+ //# sourceMappingURL=s3.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"s3.d.ts","sourceRoot":"","sources":["../../src/database/s3.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAA2D,WAAW,EAAiB,MAAM,SAAS,CAAA;AAMlH;;;GAGG;AACH,UAAU,QAAQ;IACjB,IAAI,CAAC,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE;QAAE,QAAQ,CAAC,WAAW,EAAE,WAAW,CAAA;KAAE,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;CACtF;AAED,UAAU,cAAc;IACvB;;;;OAIG;IACH,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAA;IACzB,0FAA0F;IAC1F,QAAQ,CAAC,GAAG,EAAE;QAAE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAA;IACzC,iFAAiF;IACjF,QAAQ,CAAC,WAAW,EAAE;QAAE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAA;IACjD,uDAAuD;IACvD,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CACvB;AA8ED,wFAAwF;AACxF,iBAAS,IAAI,CAAC,OAAO,EAAE,cAAc,GAAG,WAAW,CAiHlD;AAED,QAAA,MAAM,OAAO;;EAA0B,CAAA;AAEvC,YAAY,EAAE,QAAQ,EAAE,cAAc,EAAE,CAAA;AACxC,OAAO,EAAE,OAAO,EAAE,CAAA"}