@prestack/thread 0.1.2 → 0.1.4

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 (265) hide show
  1. package/CHANGELOG.md +193 -0
  2. package/dist/core/actor.d.ts +1 -1
  3. package/dist/core/actor.js +5 -4
  4. package/dist/core/actor.ts +5 -4
  5. package/dist/core/attach.d.ts +0 -7
  6. package/dist/core/attach.js +67 -58
  7. package/dist/core/attach.ts +61 -68
  8. package/dist/core/chain.js +13 -17
  9. package/dist/core/chain.ts +11 -15
  10. package/dist/core/condition.d.ts +4 -4
  11. package/dist/core/condition.js +2 -2
  12. package/dist/core/descend.d.ts +4 -2
  13. package/dist/core/descend.js +89 -21
  14. package/dist/core/descend.ts +86 -17
  15. package/dist/core/errors/catalogue.d.ts +52 -0
  16. package/dist/{operations/errors/errors.js → core/errors/catalogue.js} +1 -1
  17. package/dist/{operations/errors/errors.ts → core/errors/catalogue.ts} +1 -1
  18. package/dist/{operations/errors/catalog.d.ts → core/errors/error.d.ts} +2 -3
  19. package/dist/{operations/errors/catalog.js → core/errors/error.js} +1 -16
  20. package/dist/{operations/errors/catalog.ts → core/errors/error.ts} +3 -19
  21. package/dist/core/errors/namespaces.d.ts +3 -0
  22. package/dist/core/errors/namespaces.js +15 -0
  23. package/dist/core/errors/namespaces.ts +19 -0
  24. package/dist/core/finding.js +2 -2
  25. package/dist/core/finding.ts +1 -2
  26. package/dist/core/init.d.ts +0 -2
  27. package/dist/core/init.js +51 -15
  28. package/dist/core/init.ts +58 -15
  29. package/dist/core/invoked.d.ts +1 -1
  30. package/dist/core/invoked.js +3 -1
  31. package/dist/core/invoked.ts +5 -2
  32. package/dist/core/round.js +36 -22
  33. package/dist/core/round.ts +26 -9
  34. package/dist/core/rows.d.ts +4 -0
  35. package/dist/core/rows.js +31 -2
  36. package/dist/core/rows.ts +33 -1
  37. package/dist/core/thread.d.ts +3 -3
  38. package/dist/core/tree.d.ts +4 -1
  39. package/dist/core/tree.js +26 -6
  40. package/dist/core/tree.ts +29 -6
  41. package/dist/core/types.d.ts +3 -3
  42. package/dist/core/types.js +3 -1
  43. package/dist/core/types.ts +2 -1
  44. package/dist/derivation/attach.js +1 -1
  45. package/dist/derivation/generators/build.js +6 -6
  46. package/dist/derivation/generators/build.ts +1 -1
  47. package/dist/derivation/generators/check.js +1 -1
  48. package/dist/derivation/generators/determinism.js +1 -1
  49. package/dist/derivation/generators/release.js +60 -47
  50. package/dist/derivation/generators/release.ts +66 -43
  51. package/dist/derivation/release.d.ts +7 -3
  52. package/dist/derivation/release.js +14 -1
  53. package/dist/derivation/release.ts +22 -2
  54. package/dist/integrations/attach.d.ts +4 -0
  55. package/dist/integrations/attach.js +33 -54
  56. package/dist/integrations/attach.ts +50 -57
  57. package/dist/integrations/cli.d.ts +37 -0
  58. package/dist/integrations/cli.js +440 -0
  59. package/dist/integrations/cli.ts +543 -0
  60. package/dist/{core/files.d.ts → integrations/disk.d.ts} +16 -20
  61. package/dist/integrations/disk.js +435 -0
  62. package/dist/integrations/disk.ts +465 -0
  63. package/dist/integrations/generators/read.js +6 -6
  64. package/dist/integrations/generators/read.ts +4 -4
  65. package/dist/integrations/generators/vault.js +10 -11
  66. package/dist/integrations/generators/vault.ts +4 -5
  67. package/dist/{operations/http.d.ts → integrations/https.d.ts} +10 -6
  68. package/dist/integrations/https.js +170 -0
  69. package/dist/integrations/https.ts +216 -0
  70. package/dist/integrations/pglite.d.ts +26 -0
  71. package/dist/integrations/pglite.js +143 -0
  72. package/dist/integrations/pglite.ts +206 -0
  73. package/dist/integrations/secret.d.ts +8 -2
  74. package/dist/integrations/secret.js +3 -5
  75. package/dist/integrations/secret.ts +10 -6
  76. package/dist/integrations/target.d.ts +155 -14
  77. package/dist/integrations/target.js +171 -50
  78. package/dist/integrations/target.ts +377 -61
  79. package/dist/integrations/vault.d.ts +1 -0
  80. package/dist/integrations/vault.js +20 -5
  81. package/dist/integrations/vault.ts +17 -5
  82. package/dist/integrity/attach.js +3 -73
  83. package/dist/integrity/attach.ts +1 -71
  84. package/dist/integrity/check-threads.js +5 -5
  85. package/dist/integrity/check-threads.ts +2 -2
  86. package/dist/integrity/constraint.d.ts +0 -1
  87. package/dist/integrity/constraint.js +267 -366
  88. package/dist/integrity/constraint.ts +267 -375
  89. package/dist/integrity/generators/compiler.js +14 -17
  90. package/dist/integrity/generators/compiler.ts +10 -15
  91. package/dist/integrity/generators/gate.js +15 -15
  92. package/dist/integrity/generators/gate.ts +10 -10
  93. package/dist/integrity/generators/issues.js +7 -7
  94. package/dist/integrity/generators/publish.js +39 -57
  95. package/dist/integrity/generators/publish.ts +44 -55
  96. package/dist/integrity/generators/trial.d.ts +3 -3
  97. package/dist/integrity/generators/trial.js +133 -161
  98. package/dist/integrity/generators/trial.ts +145 -165
  99. package/dist/integrity/lint.js +9 -13
  100. package/dist/integrity/lint.ts +7 -10
  101. package/dist/integrity/lsp/bin.js +5 -4
  102. package/dist/integrity/lsp/bin.ts +3 -1
  103. package/dist/integrity/lsp/diagnostics.js +3 -3
  104. package/dist/integrity/lsp/diagnostics.ts +1 -1
  105. package/dist/integrity/lsp/lint.js +19 -30
  106. package/dist/integrity/lsp/lint.ts +16 -32
  107. package/dist/integrity/lsp/server.js +3 -3
  108. package/dist/integrity/slopnator.d.ts +3 -13
  109. package/dist/integrity/slopnator.js +58 -37
  110. package/dist/integrity/slopnator.ts +53 -37
  111. package/dist/integrity/slopnators/sl_broken_lineage.js +2 -2
  112. package/dist/integrity/slopnators/sl_declared_elsewhere.js +1 -1
  113. package/dist/integrity/slopnators/sl_derived_drift.js +4 -4
  114. package/dist/integrity/slopnators/sl_derived_drift.ts +1 -1
  115. package/dist/integrity/slopnators/sl_door_in_a_node.js +220 -0
  116. package/dist/integrity/slopnators/sl_door_in_a_node.ts +250 -0
  117. package/dist/integrity/slopnators/sl_inert_island.js +10 -8
  118. package/dist/integrity/slopnators/sl_inert_island.ts +8 -6
  119. package/dist/integrity/slopnators/sl_missing_row.js +6 -51
  120. package/dist/integrity/slopnators/sl_missing_row.ts +4 -50
  121. package/dist/integrity/slopnators/sl_no_barrel.js +1 -1
  122. package/dist/integrity/slopnators/sl_no_child_process.js +36 -18
  123. package/dist/integrity/slopnators/sl_no_child_process.ts +44 -18
  124. package/dist/integrity/slopnators/sl_no_dispatch_bypass.js +80 -149
  125. package/dist/integrity/slopnators/sl_no_dispatch_bypass.ts +95 -147
  126. package/dist/integrity/slopnators/sl_no_import_cycle.js +15 -4
  127. package/dist/integrity/slopnators/sl_no_import_cycle.ts +20 -4
  128. package/dist/integrity/slopnators/sl_no_such_command.js +2 -2
  129. package/dist/integrity/slopnators/sl_no_such_command.ts +1 -1
  130. package/dist/integrity/slopnators/sl_outside_an_operation.js +20 -0
  131. package/dist/integrity/slopnators/sl_outside_an_operation.ts +25 -0
  132. package/dist/integrity/slopnators/sl_screen_holds_only_declared.d.ts +2 -0
  133. package/dist/integrity/slopnators/sl_screen_holds_only_declared.js +61 -0
  134. package/dist/integrity/slopnators/sl_screen_holds_only_declared.ts +70 -0
  135. package/dist/integrity/slopnators/sl_secret_literal.js +1 -33
  136. package/dist/integrity/slopnators/sl_secret_literal.ts +1 -33
  137. package/dist/integrity/slopnators/sl_stale_path.js +5 -22
  138. package/dist/integrity/slopnators/sl_stale_path.ts +4 -20
  139. package/dist/integrity/slopnators/sl_twice_meant.js +1 -1
  140. package/dist/integrity/slopnators/sl_twice_parented.js +29 -5
  141. package/dist/integrity/slopnators/sl_twice_parented.ts +28 -4
  142. package/dist/integrity/slopnators/sl_undeclared_crossing.d.ts +4 -1
  143. package/dist/integrity/slopnators/sl_undeclared_crossing.js +426 -62
  144. package/dist/integrity/slopnators/sl_undeclared_crossing.ts +454 -70
  145. package/dist/integrity/slopnators/sl_undeclared_destination.js +59 -25
  146. package/dist/integrity/slopnators/sl_undeclared_destination.ts +69 -21
  147. package/dist/integrity/slopnators/sl_undeclared_list.d.ts +2 -0
  148. package/dist/integrity/slopnators/sl_undeclared_list.js +363 -0
  149. package/dist/integrity/slopnators/sl_undeclared_list.ts +358 -0
  150. package/dist/integrity/slopnators/sl_undeclared_node.js +1 -11
  151. package/dist/integrity/slopnators/sl_undeclared_node.ts +0 -10
  152. package/dist/integrity/slopnators/sl_undeclared_operation.js +111 -29
  153. package/dist/integrity/slopnators/sl_undeclared_operation.ts +134 -26
  154. package/dist/integrity/slopnators/sl_undeclared_variant.js +2 -2
  155. package/dist/integrity/slopnators/sl_undeclared_webhook.d.ts +2 -0
  156. package/dist/integrity/slopnators/sl_undeclared_webhook.js +90 -0
  157. package/dist/integrity/slopnators/sl_undeclared_webhook.ts +108 -0
  158. package/dist/integrity/slopnators/sl_underived_route.d.ts +2 -0
  159. package/dist/integrity/slopnators/sl_underived_route.js +61 -0
  160. package/dist/integrity/slopnators/sl_underived_route.ts +72 -0
  161. package/dist/integrity/slopnators/sl_ungoverned_island.js +3 -3
  162. package/dist/integrity/slopnators/sl_ungoverned_island.ts +1 -1
  163. package/dist/integrity/slopnators/sl_unlisted_program.d.ts +2 -0
  164. package/dist/integrity/slopnators/sl_unlisted_program.js +39 -0
  165. package/dist/integrity/slopnators/sl_unlisted_program.ts +40 -0
  166. package/dist/integrity/slopnators/sl_unnamed_island.js +1 -1
  167. package/dist/integrity/slopnators/sl_unpaired_member.js +3 -3
  168. package/dist/integrity/slopnators/sl_unpaired_member.ts +1 -1
  169. package/dist/integrity/slopnators/sl_unpaired_slopnator.js +4 -4
  170. package/dist/integrity/slopnators/sl_unpaired_slopnator.ts +1 -1
  171. package/dist/integrity/slopnators/sl_unprefixed_member.js +5 -31
  172. package/dist/integrity/slopnators/sl_unprefixed_member.ts +2 -28
  173. package/dist/integrity/slopnators/sl_unthreaded.js +11 -7
  174. package/dist/integrity/slopnators/sl_unthreaded.ts +6 -7
  175. package/dist/integrity/slopnators/sl_untranslated_key.js +2 -25
  176. package/dist/integrity/slopnators/sl_untranslated_key.ts +1 -25
  177. package/dist/integrity/slopnators/sl_unvaulted_secret.d.ts +2 -0
  178. package/dist/integrity/slopnators/sl_unvaulted_secret.js +107 -0
  179. package/dist/integrity/slopnators/sl_unvaulted_secret.ts +132 -0
  180. package/dist/integrity/slopnators/sl_unversioned.js +6 -4
  181. package/dist/integrity/slopnators/sl_unversioned.ts +5 -3
  182. package/dist/integrity/sweep.d.ts +1 -0
  183. package/dist/integrity/sweep.js +105 -42
  184. package/dist/integrity/sweep.ts +115 -42
  185. package/dist/knowledge/attach.js +1 -1
  186. package/dist/knowledge/generators/docsgen.js +8 -6
  187. package/dist/knowledge/generators/docsgen.ts +4 -2
  188. package/dist/knowledge/generators/glossary.js +4 -4
  189. package/dist/knowledge/generators/glossary.ts +1 -1
  190. package/dist/operations/access.d.ts +23 -0
  191. package/dist/operations/access.js +28 -1
  192. package/dist/operations/access.ts +43 -0
  193. package/dist/operations/attach.js +28 -109
  194. package/dist/operations/attach.ts +46 -113
  195. package/dist/operations/capabilities.d.ts +14 -5
  196. package/dist/operations/capabilities.js +13 -4
  197. package/dist/operations/capabilities.ts +27 -8
  198. package/dist/operations/dispatch.d.ts +8 -2
  199. package/dist/operations/dispatch.js +128 -185
  200. package/dist/operations/dispatch.ts +138 -191
  201. package/dist/operations/error-results.d.ts +1 -1
  202. package/dist/operations/error-results.js +2 -2
  203. package/dist/operations/error-results.ts +2 -2
  204. package/dist/operations/generators/capability.d.ts +11 -1
  205. package/dist/operations/generators/capability.js +481 -224
  206. package/dist/operations/generators/capability.ts +562 -233
  207. package/dist/operations/generators/compile.js +66 -39
  208. package/dist/operations/generators/compile.ts +78 -39
  209. package/dist/operations/generators/permits.js +11 -12
  210. package/dist/operations/generators/permits.ts +3 -4
  211. package/dist/operations/generators/seed.d.ts +1 -0
  212. package/dist/operations/generators/seed.js +19 -17
  213. package/dist/operations/generators/seed.ts +22 -14
  214. package/dist/operations/generators/trial.d.ts +6 -8
  215. package/dist/operations/generators/trial.js +200 -70
  216. package/dist/operations/generators/trial.ts +230 -93
  217. package/dist/operations/nodes.d.ts +15 -16
  218. package/dist/operations/nodes.ts +16 -17
  219. package/dist/operations/operations.d.ts +40 -4
  220. package/dist/operations/operations.js +1 -0
  221. package/dist/operations/operations.ts +61 -4
  222. package/dist/operations/result.d.ts +2 -2
  223. package/dist/operations/result.ts +2 -2
  224. package/package.json +1 -4
  225. package/dist/core/answers.d.ts +0 -171
  226. package/dist/core/answers.js +0 -789
  227. package/dist/core/answers.ts +0 -999
  228. package/dist/core/client.d.ts +0 -57
  229. package/dist/core/client.js +0 -247
  230. package/dist/core/client.ts +0 -286
  231. package/dist/core/files.js +0 -145
  232. package/dist/core/files.ts +0 -193
  233. package/dist/integrations/module.d.ts +0 -6
  234. package/dist/integrations/module.js +0 -153
  235. package/dist/integrations/module.ts +0 -191
  236. package/dist/integrity/slopnators/sl_unkept_rows.js +0 -104
  237. package/dist/integrity/slopnators/sl_unkept_rows.ts +0 -111
  238. package/dist/integrity/slopnators/sl_unseamed_reach.js +0 -73
  239. package/dist/integrity/slopnators/sl_unseamed_reach.ts +0 -79
  240. package/dist/operations/cost.d.ts +0 -14
  241. package/dist/operations/cost.js +0 -37
  242. package/dist/operations/cost.ts +0 -58
  243. package/dist/operations/errors/errors.d.ts +0 -52
  244. package/dist/operations/http.js +0 -124
  245. package/dist/operations/http.ts +0 -169
  246. package/dist/operations/memory.d.ts +0 -104
  247. package/dist/operations/memory.js +0 -365
  248. package/dist/operations/memory.ts +0 -470
  249. package/dist/operations/metering.d.ts +0 -55
  250. package/dist/operations/metering.js +0 -247
  251. package/dist/operations/metering.ts +0 -328
  252. package/dist/operations/queue-policy.d.ts +0 -3
  253. package/dist/operations/queue-policy.js +0 -8
  254. package/dist/operations/queue-policy.ts +0 -10
  255. package/dist/operations/seams.d.ts +0 -239
  256. package/dist/operations/seams.js +0 -45
  257. package/dist/operations/seams.ts +0 -364
  258. package/dist/operations/store.d.ts +0 -14
  259. package/dist/operations/store.js +0 -1
  260. package/dist/operations/store.ts +0 -29
  261. /package/dist/{operations → core}/errors/classes.d.ts +0 -0
  262. /package/dist/{operations → core}/errors/classes.js +0 -0
  263. /package/dist/{operations → core}/errors/classes.ts +0 -0
  264. /package/dist/integrity/slopnators/{sl_unkept_rows.d.ts → sl_door_in_a_node.d.ts} +0 -0
  265. /package/dist/integrity/slopnators/{sl_unseamed_reach.d.ts → sl_outside_an_operation.d.ts} +0 -0
@@ -1,104 +0,0 @@
1
- import { existsSync, readdirSync, readFileSync } from "../../core/files.js";
2
- import { resolve } from 'node:path';
3
- const STORES = 'src/stores';
4
- /* What hands an operation its seams, seeded once and then the app's own. */
5
- const SEAMS = 'src/seams.ts';
6
- /* What the declarations settle, which the seams file is expected to hand on. */
7
- const DECLARED = 'DECLARED';
8
- /*
9
- * WHAT THIS READS, AND WHY IT READS THAT RATHER THAN THE TARGETS SHEET.
10
- *
11
- * A target that keeps entities derives a store of its own, written by `thread schema` into
12
- * `src/stores/<target>.ts`. So one of those files existing IS the fact that this app declares
13
- * somewhere to keep rows — already resolved, by the command that resolved it, with no second reading
14
- * of what a reach can hold and no chance of the two disagreeing about it.
15
- *
16
- * Where rows go is settled in `src/_generated/seams.ts`, which `thread capabilities` writes from those
17
- * stores and refuses when it drifts. The one place it can still go wrong is `src/seams.ts`, which is
18
- * the app's own: an app that stops handing on what was settled there hands its operations a store
19
- * that keeps nothing, while the tables are written, the migrations are written, and the gate is green.
20
- */
21
- function held(root, at) {
22
- const path = resolve(root, at);
23
- try {
24
- return existsSync(path) ? readFileSync(path, 'utf8') : '';
25
- }
26
- catch {
27
- return '';
28
- }
29
- }
30
- function derived(root) {
31
- const at = resolve(root, STORES);
32
- try {
33
- return existsSync(at) ? readdirSync(at).filter((one) => one.endsWith('.ts')) : [];
34
- }
35
- catch {
36
- return [];
37
- }
38
- }
39
- export const slopnator = {
40
- checks: (root) => {
41
- const stores = derived(root);
42
- if (stores.length === 0)
43
- return [];
44
- /*
45
- * AN APP WITH NOTHING THAT HANDS A STORE TO AN OPERATION IS NOT KEEPING ROWS THROUGH ONE, SO
46
- * THERE IS NOTHING TO REFUSE.
47
- *
48
- * The seams file is seeded by `thread capabilities`, which ships in the operations package — so
49
- * an app that attached data and integrity and nothing else has no seams and no command that
50
- * seeds one. Its absence means rows go nowhere yet, which is a state to pass rather than refuse:
51
- * nothing is being lost, because nothing is being kept.
52
- */
53
- const where = held(root, SEAMS);
54
- if (where === '')
55
- return [];
56
- if (where.includes(DECLARED))
57
- return [];
58
- return [
59
- `${STORES} holds ${stores.join(', ')} and ${SEAMS} no longer hands on ${DECLARED}, so every row this app keeps goes ` +
60
- 'somewhere that is gone the moment it stops. The tables are written, the migrations are written, the gate is ' +
61
- `green, and the database is never opened. Spread ${DECLARED} back into SEAMS, or name its store there`,
62
- ];
63
- },
64
- proves: {
65
- wrong: [
66
- {
67
- files: [
68
- { at: 'src/stores/pl_probe.ts', source: 'export const store = {}\n' },
69
- {
70
- at: 'src/seams.ts',
71
- source: "import { inMemorySeams } from '../../operations/memory.ts'\n\nexport const SEAMS = inMemorySeams().seams\n",
72
- },
73
- ],
74
- at: 'src/seams.ts',
75
- },
76
- ],
77
- right: [
78
- {
79
- files: [
80
- { at: 'src/stores/pl_probe.ts', source: 'export const store = {}\n' },
81
- {
82
- at: 'src/seams.ts',
83
- source: "import { DECLARED } from './_generated/seams.ts'\n\nexport const SEAMS = { ...DECLARED }\n",
84
- },
85
- ],
86
- at: 'src/seams.ts',
87
- },
88
- /* An app that derived a store and has nothing handing one to an operation — data attached, operations not. */
89
- {
90
- files: [{ at: 'src/stores/pl_probe.ts', source: 'export const store = {}\n' }],
91
- at: 'src/seams.ts',
92
- },
93
- {
94
- files: [
95
- {
96
- at: 'src/seams.ts',
97
- source: "import { inMemorySeams } from '../../operations/memory.ts'\n\nexport const SEAMS = inMemorySeams().seams\n",
98
- },
99
- ],
100
- at: 'src/seams.ts',
101
- },
102
- ],
103
- },
104
- };
@@ -1,111 +0,0 @@
1
- import { existsSync, readdirSync, readFileSync } from '../../core/files.ts'
2
- import { resolve } from 'node:path'
3
-
4
- import type { Slopnator } from '../slopnator.ts'
5
-
6
- const STORES = 'src/stores'
7
-
8
- /* What hands an operation its seams, seeded once and then the app's own. */
9
- const SEAMS = 'src/seams.ts'
10
-
11
- /* What the declarations settle, which the seams file is expected to hand on. */
12
- const DECLARED = 'DECLARED'
13
-
14
- /*
15
- * WHAT THIS READS, AND WHY IT READS THAT RATHER THAN THE TARGETS SHEET.
16
- *
17
- * A target that keeps entities derives a store of its own, written by `thread schema` into
18
- * `src/stores/<target>.ts`. So one of those files existing IS the fact that this app declares
19
- * somewhere to keep rows — already resolved, by the command that resolved it, with no second reading
20
- * of what a reach can hold and no chance of the two disagreeing about it.
21
- *
22
- * Where rows go is settled in `src/_generated/seams.ts`, which `thread capabilities` writes from those
23
- * stores and refuses when it drifts. The one place it can still go wrong is `src/seams.ts`, which is
24
- * the app's own: an app that stops handing on what was settled there hands its operations a store
25
- * that keeps nothing, while the tables are written, the migrations are written, and the gate is green.
26
- */
27
- function held(root: string, at: string): string {
28
- const path = resolve(root, at)
29
- try {
30
- return existsSync(path) ? readFileSync(path, 'utf8') : ''
31
- } catch {
32
- return ''
33
- }
34
- }
35
-
36
- function derived(root: string): readonly string[] {
37
- const at = resolve(root, STORES)
38
- try {
39
- return existsSync(at) ? readdirSync(at).filter((one) => one.endsWith('.ts')) : []
40
- } catch {
41
- return []
42
- }
43
- }
44
-
45
- export const slopnator: Slopnator = {
46
- checks: (root) => {
47
- const stores = derived(root)
48
- if (stores.length === 0) return []
49
-
50
- /*
51
- * AN APP WITH NOTHING THAT HANDS A STORE TO AN OPERATION IS NOT KEEPING ROWS THROUGH ONE, SO
52
- * THERE IS NOTHING TO REFUSE.
53
- *
54
- * The seams file is seeded by `thread capabilities`, which ships in the operations package — so
55
- * an app that attached data and integrity and nothing else has no seams and no command that
56
- * seeds one. Its absence means rows go nowhere yet, which is a state to pass rather than refuse:
57
- * nothing is being lost, because nothing is being kept.
58
- */
59
- const where = held(root, SEAMS)
60
- if (where === '') return []
61
-
62
- if (where.includes(DECLARED)) return []
63
-
64
- return [
65
- `${STORES} holds ${stores.join(', ')} and ${SEAMS} no longer hands on ${DECLARED}, so every row this app keeps goes ` +
66
- 'somewhere that is gone the moment it stops. The tables are written, the migrations are written, the gate is ' +
67
- `green, and the database is never opened. Spread ${DECLARED} back into SEAMS, or name its store there`,
68
- ]
69
- },
70
- proves: {
71
- wrong: [
72
- {
73
- files: [
74
- { at: 'src/stores/pl_probe.ts', source: 'export const store = {}\n' },
75
- {
76
- at: 'src/seams.ts',
77
- source: "import { inMemorySeams } from '../../operations/memory.ts'\n\nexport const SEAMS = inMemorySeams().seams\n",
78
- },
79
- ],
80
- at: 'src/seams.ts',
81
- },
82
- ],
83
- right: [
84
- {
85
- files: [
86
- { at: 'src/stores/pl_probe.ts', source: 'export const store = {}\n' },
87
- {
88
- at: 'src/seams.ts',
89
- source: "import { DECLARED } from './_generated/seams.ts'\n\nexport const SEAMS = { ...DECLARED }\n",
90
- },
91
- ],
92
- at: 'src/seams.ts',
93
- },
94
-
95
- /* An app that derived a store and has nothing handing one to an operation — data attached, operations not. */
96
- {
97
- files: [{ at: 'src/stores/pl_probe.ts', source: 'export const store = {}\n' }],
98
- at: 'src/seams.ts',
99
- },
100
- {
101
- files: [
102
- {
103
- at: 'src/seams.ts',
104
- source: "import { inMemorySeams } from '../../operations/memory.ts'\n\nexport const SEAMS = inMemorySeams().seams\n",
105
- },
106
- ],
107
- at: 'src/seams.ts',
108
- },
109
- ],
110
- },
111
- }
@@ -1,73 +0,0 @@
1
- import { isBuiltin } from 'node:module';
2
- import { parser } from 'typescript-eslint';
3
- const CODE = /\.(?:ts|tsx|mts|cts|js|jsx|mjs|cjs)$/;
4
- const MENTIONS = /\bimport\b|\brequire\s*\(/;
5
- function reached(node, seen, found) {
6
- if (typeof node !== 'object' || node === null)
7
- return;
8
- if (seen.has(node))
9
- return;
10
- seen.add(node);
11
- if (Array.isArray(node)) {
12
- for (const each of node)
13
- reached(each, seen, found);
14
- return;
15
- }
16
- const one = node;
17
- const type = one['type'];
18
- if (type === 'ImportDeclaration' || type === 'ImportExpression' || type === 'ExportNamedDeclaration' || type === 'ExportAllDeclaration') {
19
- const source = one['source'];
20
- if (typeof source?.value === 'string')
21
- found(source.value);
22
- }
23
- if (type === 'CallExpression') {
24
- const callee = one['callee'];
25
- if (callee?.type === 'Identifier' && callee.name === 'require') {
26
- const first = one['arguments']?.[0];
27
- if (typeof first?.value === 'string')
28
- found(first.value);
29
- }
30
- }
31
- for (const held of Object.values(one))
32
- reached(held, seen, found);
33
- }
34
- export const slopnator = {
35
- holds: (_node, at) => {
36
- if (!CODE.test(at.filename))
37
- return false;
38
- const text = String(at.text);
39
- if (!MENTIONS.test(text))
40
- return false;
41
- let ast;
42
- try {
43
- ast = parser.parseForESLint(text, {
44
- range: true,
45
- ecmaVersion: 'latest',
46
- sourceType: 'module',
47
- ecmaFeatures: { jsx: true },
48
- }).ast;
49
- }
50
- catch {
51
- return false;
52
- }
53
- const taken = new Set();
54
- reached(ast, new WeakSet(), (one) => {
55
- if (isBuiltin(one))
56
- taken.add(one);
57
- });
58
- if (taken.size === 0)
59
- return false;
60
- return `this reaches ${[...taken].sort().join(', ')} straight from the runtime, and a node is handed everything it may touch`;
61
- },
62
- proves: {
63
- wrong: [
64
- "import { readFileSync } from 'node:fs'\nexport const node = readFileSync\n",
65
- "const { spawn } = require('child_process')\nexport const node = spawn\n",
66
- "export const node = async () => await import('node:net')\n",
67
- ],
68
- right: [
69
- "import { nd_read } from '../../operations/nodes.ts'\nexport const node = nd_read(async (hands) => await hands.store.get('a', 'b'))\n",
70
- "import type { In } from './input.ts'\nexport const node = null as unknown as In\n",
71
- ],
72
- },
73
- };
@@ -1,79 +0,0 @@
1
- import { isBuiltin } from 'node:module'
2
-
3
- import { parser } from 'typescript-eslint'
4
-
5
- import type { Slopnator } from '../slopnator.ts'
6
-
7
- const CODE = /\.(?:ts|tsx|mts|cts|js|jsx|mjs|cjs)$/
8
-
9
- const MENTIONS = /\bimport\b|\brequire\s*\(/
10
-
11
- function reached(node: unknown, seen: WeakSet<object>, found: (one: string) => void): void {
12
- if (typeof node !== 'object' || node === null) return
13
- if (seen.has(node)) return
14
- seen.add(node)
15
-
16
- if (Array.isArray(node)) {
17
- for (const each of node) reached(each, seen, found)
18
- return
19
- }
20
-
21
- const one = node as Record<string, unknown>
22
- const type = one['type']
23
-
24
- if (type === 'ImportDeclaration' || type === 'ImportExpression' || type === 'ExportNamedDeclaration' || type === 'ExportAllDeclaration') {
25
- const source = one['source'] as { readonly value?: unknown } | null | undefined
26
- if (typeof source?.value === 'string') found(source.value)
27
- }
28
-
29
- if (type === 'CallExpression') {
30
- const callee = one['callee'] as { readonly type?: unknown; readonly name?: unknown } | null | undefined
31
- if (callee?.type === 'Identifier' && callee.name === 'require') {
32
- const first = (one['arguments'] as readonly { readonly value?: unknown }[] | undefined)?.[0]
33
- if (typeof first?.value === 'string') found(first.value)
34
- }
35
- }
36
-
37
- for (const held of Object.values(one)) reached(held, seen, found)
38
- }
39
-
40
- export const slopnator: Slopnator = {
41
- holds: (_node, at) => {
42
- if (!CODE.test(at.filename)) return false
43
-
44
- const text = String(at.text)
45
- if (!MENTIONS.test(text)) return false
46
-
47
- let ast: unknown
48
- try {
49
- ast = (parser.parseForESLint as (text: string, options: unknown) => { readonly ast: unknown })(text, {
50
- range: true,
51
- ecmaVersion: 'latest',
52
- sourceType: 'module',
53
- ecmaFeatures: { jsx: true },
54
- }).ast
55
- } catch {
56
- return false
57
- }
58
-
59
- const taken = new Set<string>()
60
- reached(ast, new WeakSet<object>(), (one) => {
61
- if (isBuiltin(one)) taken.add(one)
62
- })
63
-
64
- if (taken.size === 0) return false
65
-
66
- return `this reaches ${[...taken].sort().join(', ')} straight from the runtime, and a node is handed everything it may touch`
67
- },
68
- proves: {
69
- wrong: [
70
- "import { readFileSync } from 'node:fs'\nexport const node = readFileSync\n",
71
- "const { spawn } = require('child_process')\nexport const node = spawn\n",
72
- "export const node = async () => await import('node:net')\n",
73
- ],
74
- right: [
75
- "import { nd_read } from '../../operations/nodes.ts'\nexport const node = nd_read(async (hands) => await hands.store.get('a', 'b'))\n",
76
- "import type { In } from './input.ts'\nexport const node = null as unknown as In\n",
77
- ],
78
- },
79
- }
@@ -1,14 +0,0 @@
1
- export interface CostAmount {
2
- readonly usdMicroCents: number;
3
- readonly chargedMicroCents: number;
4
- readonly currency: string;
5
- readonly meter: string;
6
- }
7
- export declare class InvalidCostError extends Error {
8
- constructor(message: string);
9
- }
10
- export declare function assertValidCost(cost: CostAmount): void;
11
- export declare const MICRO_CENTS_PER_CENT = 1000000;
12
- export declare const MICRO_CENTS_PER_UNIT = 100000000;
13
- export declare function toMicroCents(amount: number): number;
14
- export declare function fromMicroCents(microCents: number): number;
@@ -1,37 +0,0 @@
1
- export class InvalidCostError extends Error {
2
- constructor(message) {
3
- super(message);
4
- this.name = 'InvalidCostError';
5
- }
6
- }
7
- function assertIntegerMicroCents(value, field) {
8
- if (!Number.isFinite(value) || !Number.isInteger(value)) {
9
- throw new InvalidCostError(`${field} must be an integer number of micro-cents, received ${value}. ` +
10
- 'Convert before recording — never round.');
11
- }
12
- if (value < 0)
13
- throw new InvalidCostError(`${field} must not be negative, received ${value}`);
14
- }
15
- export function assertValidCost(cost) {
16
- assertIntegerMicroCents(cost.usdMicroCents, 'usdMicroCents');
17
- assertIntegerMicroCents(cost.chargedMicroCents, 'chargedMicroCents');
18
- if (typeof cost.currency !== 'string' || cost.currency.trim() === '') {
19
- throw new InvalidCostError('cost.currency is required and has no default — resolve it from real data (DATA.md §8)');
20
- }
21
- if (!/^[A-Z]{3}$/.test(cost.currency)) {
22
- throw new InvalidCostError(`cost.currency must be an ISO-4217 code, received "${cost.currency}"`);
23
- }
24
- if (typeof cost.meter !== 'string' || cost.meter.trim() === '') {
25
- throw new InvalidCostError('cost.meter is required — a cost with no meter cannot be quota-checked');
26
- }
27
- }
28
- export const MICRO_CENTS_PER_CENT = 1_000_000;
29
- export const MICRO_CENTS_PER_UNIT = 100_000_000;
30
- export function toMicroCents(amount) {
31
- if (!Number.isFinite(amount))
32
- throw new InvalidCostError(`cannot convert ${amount} to micro-cents`);
33
- return Math.round(amount * MICRO_CENTS_PER_UNIT);
34
- }
35
- export function fromMicroCents(microCents) {
36
- return microCents / MICRO_CENTS_PER_UNIT;
37
- }
@@ -1,58 +0,0 @@
1
- export interface CostAmount {
2
-
3
- readonly usdMicroCents: number
4
-
5
- readonly chargedMicroCents: number
6
-
7
- readonly currency: string
8
-
9
- readonly meter: string
10
- }
11
-
12
- export class InvalidCostError extends Error {
13
- constructor(message: string) {
14
- super(message)
15
- this.name = 'InvalidCostError'
16
- }
17
- }
18
-
19
- function assertIntegerMicroCents(value: number, field: string): void {
20
- if (!Number.isFinite(value) || !Number.isInteger(value)) {
21
-
22
- throw new InvalidCostError(
23
- `${field} must be an integer number of micro-cents, received ${value}. ` +
24
- 'Convert before recording — never round.',
25
- )
26
- }
27
- if (value < 0) throw new InvalidCostError(`${field} must not be negative, received ${value}`)
28
- }
29
-
30
- export function assertValidCost(cost: CostAmount): void {
31
- assertIntegerMicroCents(cost.usdMicroCents, 'usdMicroCents')
32
- assertIntegerMicroCents(cost.chargedMicroCents, 'chargedMicroCents')
33
-
34
- if (typeof cost.currency !== 'string' || cost.currency.trim() === '') {
35
- throw new InvalidCostError(
36
- 'cost.currency is required and has no default — resolve it from real data (DATA.md §8)',
37
- )
38
- }
39
- if (!/^[A-Z]{3}$/.test(cost.currency)) {
40
- throw new InvalidCostError(`cost.currency must be an ISO-4217 code, received "${cost.currency}"`)
41
- }
42
- if (typeof cost.meter !== 'string' || cost.meter.trim() === '') {
43
- throw new InvalidCostError('cost.meter is required — a cost with no meter cannot be quota-checked')
44
- }
45
- }
46
-
47
- export const MICRO_CENTS_PER_CENT = 1_000_000
48
-
49
- export const MICRO_CENTS_PER_UNIT = 100_000_000
50
-
51
- export function toMicroCents(amount: number): number {
52
- if (!Number.isFinite(amount)) throw new InvalidCostError(`cannot convert ${amount} to micro-cents`)
53
- return Math.round(amount * MICRO_CENTS_PER_UNIT)
54
- }
55
-
56
- export function fromMicroCents(microCents: number): number {
57
- return microCents / MICRO_CENTS_PER_UNIT
58
- }
@@ -1,52 +0,0 @@
1
- export declare const AuthUnauthenticated: import("./catalog.ts").ErrorFactory<"auth.unauthenticated">;
2
- export declare const AuthInvalidCredentials: import("./catalog.ts").ErrorFactory<"auth.invalid_credentials">;
3
- export declare const AuthTokenExpired: import("./catalog.ts").ErrorFactory<"auth.token_expired">;
4
- export declare const AuthTokenReused: import("./catalog.ts").ErrorFactory<"auth.token_reused">;
5
- export declare const AuthSessionRevoked: import("./catalog.ts").ErrorFactory<"auth.session_revoked">;
6
- export declare const AuthDenied: import("./catalog.ts").ErrorFactory<"auth.denied">;
7
- export declare const QuotaExceeded: import("./catalog.ts").ErrorFactory<"quota.exceeded">;
8
- export declare const QuotaReservationExpired: import("./catalog.ts").ErrorFactory<"quota.reservation_expired">;
9
- export declare const RateLimitExceeded: import("./catalog.ts").ErrorFactory<"rate_limit.exceeded">;
10
- export declare const FeatureNotInPlan: import("./catalog.ts").ErrorFactory<"feature.not_in_plan">;
11
- export declare const DbNotFound: import("./catalog.ts").ErrorFactory<"db.not_found">;
12
- export declare const DbConstraintViolation: import("./catalog.ts").ErrorFactory<"db.constraint_violation">;
13
- export declare const DbAlreadyExists: import("./catalog.ts").ErrorFactory<"db.already_exists">;
14
- export declare const DbConflict: import("./catalog.ts").ErrorFactory<"db.conflict">;
15
- export declare const DbMigrationChecksumMismatch: import("./catalog.ts").ErrorFactory<"db.migration_checksum_mismatch">;
16
- export declare const DbDestructiveWithoutDryRun: import("./catalog.ts").ErrorFactory<"db.destructive_without_dry_run">;
17
- export declare const DbRoundTripBudgetExceeded: import("./catalog.ts").ErrorFactory<"db.round_trip_budget_exceeded">;
18
- export declare const DbCursorInvalid: import("./catalog.ts").ErrorFactory<"db.cursor_invalid">;
19
- export declare const DbCursorExpired: import("./catalog.ts").ErrorFactory<"db.cursor_expired">;
20
- export declare const WorkflowNodeFailed: import("./catalog.ts").ErrorFactory<"workflow.node_failed">;
21
- export declare const WorkflowInvalidTransition: import("./catalog.ts").ErrorFactory<"workflow.invalid_transition">;
22
- export declare const WorkflowCompensationFailed: import("./catalog.ts").ErrorFactory<"workflow.compensation_failed">;
23
- export declare const WorkflowAlreadyRunning: import("./catalog.ts").ErrorFactory<"workflow.already_running">;
24
- export declare const QueueJobFailed: import("./catalog.ts").ErrorFactory<"queue.job_failed">;
25
- export declare const QueueDlqExhausted: import("./catalog.ts").ErrorFactory<"queue.dlq_exhausted">;
26
- export declare const AiProviderUnavailable: import("./catalog.ts").ErrorFactory<"ai.provider_unavailable">;
27
- export declare const AiSchemaValidationFailed: import("./catalog.ts").ErrorFactory<"ai.schema_validation_failed">;
28
- export declare const AiToolNotInMask: import("./catalog.ts").ErrorFactory<"ai.tool_not_in_mask">;
29
- export declare const AiNodeCapExceeded: import("./catalog.ts").ErrorFactory<"ai.node_cap_exceeded">;
30
- export declare const SearchIndexFailed: import("./catalog.ts").ErrorFactory<"search.index_failed">;
31
- export declare const SearchQueryInvalid: import("./catalog.ts").ErrorFactory<"search.query_invalid">;
32
- export declare const CommsChannelKindUndeclared: import("./catalog.ts").ErrorFactory<"comms.channel_kind_undeclared">;
33
- export declare const CommsChannelKindUndescribed: import("./catalog.ts").ErrorFactory<"comms.channel_kind_undescribed">;
34
- export declare const CommsChannelKindUnlabelled: import("./catalog.ts").ErrorFactory<"comms.channel_kind_unlabelled">;
35
- export declare const CommsChannelKindUndocumented: import("./catalog.ts").ErrorFactory<"comms.channel_kind_undocumented">;
36
- export declare const CommsChannelKindDuplicate: import("./catalog.ts").ErrorFactory<"comms.channel_kind_duplicate">;
37
- export declare const ConfigInvalid: import("./catalog.ts").ErrorFactory<"config.invalid">;
38
- export declare const ConfigMissingEnv: import("./catalog.ts").ErrorFactory<"config.missing_env">;
39
- export declare const ConfigSecretInPublicVar: import("./catalog.ts").ErrorFactory<"config.secret_in_public_var">;
40
- export declare const ConfigCredentialInvalid: import("./catalog.ts").ErrorFactory<"config.credential_invalid">;
41
- export declare const ConfigScopeMissing: import("./catalog.ts").ErrorFactory<"config.scope_missing">;
42
- export declare const ConfigResourceNotFound: import("./catalog.ts").ErrorFactory<"config.resource_not_found">;
43
- export declare const ConfigDestinationIncompatible: import("./catalog.ts").ErrorFactory<"config.destination_incompatible">;
44
- export declare const ConfigBlocksExit: import("./catalog.ts").ErrorFactory<"config.blocks_exit">;
45
- export declare const NetTimeout: import("./catalog.ts").ErrorFactory<"net.timeout">;
46
- export declare const NetUpstreamUnavailable: import("./catalog.ts").ErrorFactory<"net.upstream_unavailable">;
47
- export declare const NetDestinationRefused: import("./catalog.ts").ErrorFactory<"net.destination_refused">;
48
- export declare const InternalUnexpected: import("./catalog.ts").ErrorFactory<"internal.unexpected">;
49
- export declare const InternalNotImplemented: import("./catalog.ts").ErrorFactory<"internal.not_implemented">;
50
- export declare const InternalInvalidArgument: import("./catalog.ts").ErrorFactory<"internal.invalid_argument">;
51
- export declare const PLATFORM_ERRORS: readonly [import("./catalog.ts").ErrorFactory<"auth.unauthenticated">, import("./catalog.ts").ErrorFactory<"auth.invalid_credentials">, import("./catalog.ts").ErrorFactory<"auth.token_expired">, import("./catalog.ts").ErrorFactory<"auth.token_reused">, import("./catalog.ts").ErrorFactory<"auth.session_revoked">, import("./catalog.ts").ErrorFactory<"auth.denied">, import("./catalog.ts").ErrorFactory<"quota.exceeded">, import("./catalog.ts").ErrorFactory<"quota.reservation_expired">, import("./catalog.ts").ErrorFactory<"rate_limit.exceeded">, import("./catalog.ts").ErrorFactory<"feature.not_in_plan">, import("./catalog.ts").ErrorFactory<"db.not_found">, import("./catalog.ts").ErrorFactory<"db.constraint_violation">, import("./catalog.ts").ErrorFactory<"db.already_exists">, import("./catalog.ts").ErrorFactory<"db.conflict">, import("./catalog.ts").ErrorFactory<"db.migration_checksum_mismatch">, import("./catalog.ts").ErrorFactory<"db.destructive_without_dry_run">, import("./catalog.ts").ErrorFactory<"db.round_trip_budget_exceeded">, import("./catalog.ts").ErrorFactory<"db.cursor_invalid">, import("./catalog.ts").ErrorFactory<"db.cursor_expired">, import("./catalog.ts").ErrorFactory<"workflow.node_failed">, import("./catalog.ts").ErrorFactory<"workflow.invalid_transition">, import("./catalog.ts").ErrorFactory<"workflow.compensation_failed">, import("./catalog.ts").ErrorFactory<"workflow.already_running">, import("./catalog.ts").ErrorFactory<"queue.job_failed">, import("./catalog.ts").ErrorFactory<"queue.dlq_exhausted">, import("./catalog.ts").ErrorFactory<"ai.provider_unavailable">, import("./catalog.ts").ErrorFactory<"ai.schema_validation_failed">, import("./catalog.ts").ErrorFactory<"ai.tool_not_in_mask">, import("./catalog.ts").ErrorFactory<"ai.node_cap_exceeded">, import("./catalog.ts").ErrorFactory<"search.index_failed">, import("./catalog.ts").ErrorFactory<"search.query_invalid">, import("./catalog.ts").ErrorFactory<"comms.channel_kind_undeclared">, import("./catalog.ts").ErrorFactory<"comms.channel_kind_undescribed">, import("./catalog.ts").ErrorFactory<"comms.channel_kind_unlabelled">, import("./catalog.ts").ErrorFactory<"comms.channel_kind_undocumented">, import("./catalog.ts").ErrorFactory<"comms.channel_kind_duplicate">, import("./catalog.ts").ErrorFactory<"config.invalid">, import("./catalog.ts").ErrorFactory<"config.missing_env">, import("./catalog.ts").ErrorFactory<"config.secret_in_public_var">, import("./catalog.ts").ErrorFactory<"config.credential_invalid">, import("./catalog.ts").ErrorFactory<"config.scope_missing">, import("./catalog.ts").ErrorFactory<"config.resource_not_found">, import("./catalog.ts").ErrorFactory<"config.destination_incompatible">, import("./catalog.ts").ErrorFactory<"config.blocks_exit">, import("./catalog.ts").ErrorFactory<"net.timeout">, import("./catalog.ts").ErrorFactory<"net.upstream_unavailable">, import("./catalog.ts").ErrorFactory<"net.destination_refused">, import("./catalog.ts").ErrorFactory<"internal.unexpected">, import("./catalog.ts").ErrorFactory<"internal.not_implemented">, import("./catalog.ts").ErrorFactory<"internal.invalid_argument">];
52
- export type PlatformErrorCode = (typeof PLATFORM_ERRORS)[number]['def']['code'];
@@ -1,124 +0,0 @@
1
- import { payloadBytes } from "./metering.js";
2
- import { ValidationError } from "./result.js";
3
- export const HTTP_CALL_ACTION = 'http.call';
4
- export class HttpNotConfiguredError extends Error {
5
- constructor() {
6
- super('no outward seam is configured. `http.call` needs `seams.http`, which is the transport an app ' +
7
- 'wires — which hosts it may reach is declared in its tree and is not this seam\'s business.');
8
- this.name = 'HttpNotConfiguredError';
9
- }
10
- }
11
- export class OutwardTransportError extends Error {
12
- target;
13
- constructor(target, cause) {
14
- super(`outward call to "${target}" never reached it: ${cause instanceof Error ? cause.message : String(cause)}`);
15
- this.target = target;
16
- this.name = 'OutwardTransportError';
17
- }
18
- }
19
- export function outwardUrl(target, address, path) {
20
- let base;
21
- try {
22
- base = new URL(address);
23
- }
24
- catch {
25
- throw new ValidationError(`the address resolved for "${target}" is not an absolute URL: ${JSON.stringify(address)}`);
26
- }
27
- if (base.protocol !== 'https:') {
28
- throw new ValidationError(`outward calls go over https only, and "${target}" resolved to ${base.protocol.replace(':', '')}`);
29
- }
30
- if (base.search !== '' || base.hash !== '') {
31
- throw new ValidationError(`the address for "${target}" carries a query or a fragment — those belong to the call`);
32
- }
33
- if (!path.startsWith('/')) {
34
- throw new ValidationError(`an outward path starts with "/", and "${path}" does not`);
35
- }
36
- if (path.startsWith('//')) {
37
- throw new ValidationError(`the path "${path}" is protocol-relative, which points at another host`);
38
- }
39
- const url = new URL(`${base.origin}${base.pathname.replace(/\/$/, '')}${path}`);
40
- if (url.origin !== base.origin) {
41
- throw new ValidationError(`the path "${path}" resolves to ${url.origin}, which is not where "${target}" is`);
42
- }
43
- return url;
44
- }
45
- function requestBytes(headers, body) {
46
- return payloadBytes(headers) + (body === undefined ? 0 : body.byteLength);
47
- }
48
- function wireBody(body) {
49
- const copy = new ArrayBuffer(body.byteLength);
50
- new Uint8Array(copy).set(body);
51
- return copy;
52
- }
53
- const DEFAULT_TIMEOUT_MS = 10_000;
54
- export function httpSeam(options = {}) {
55
- const send = options.transport ?? fetch;
56
- const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
57
- return {
58
- async call(request) {
59
- const url = outwardUrl(request.target, request.address, request.path);
60
- const headers = { ...request.headers };
61
- if (request.contentType !== undefined)
62
- headers['content-type'] = request.contentType;
63
- if (request.idempotencyKey !== undefined)
64
- headers['idempotency-key'] = request.idempotencyKey;
65
- const bytesSent = requestBytes(headers, request.body);
66
- const startedAt = Date.now();
67
- let response;
68
- try {
69
- response = await send(url.toString(), {
70
- method: request.method,
71
- headers,
72
- ...(request.body === undefined ? {} : { body: wireBody(request.body) }),
73
- signal: AbortSignal.timeout(timeoutMs),
74
- });
75
- }
76
- catch (error) {
77
- throw new OutwardTransportError(request.target, error);
78
- }
79
- const body = new Uint8Array(await response.arrayBuffer());
80
- const responseHeaders = Object.fromEntries(response.headers.entries());
81
- return {
82
- status: response.status,
83
- headers: responseHeaders,
84
- body,
85
- bytesSent,
86
- bytesReceived: payloadBytes(responseHeaders) + body.byteLength,
87
- durationMs: Date.now() - startedAt,
88
- };
89
- },
90
- };
91
- }
92
- const REDACTED = '(sent)';
93
- export function recordingHttp(script = {}) {
94
- const calls = [];
95
- const decoder = new TextDecoder();
96
- return {
97
- calls,
98
- async call(request) {
99
- outwardUrl(request.target, request.address, request.path);
100
- const body = request.body === undefined ? '' : decoder.decode(request.body);
101
- calls.push({
102
- target: request.target,
103
- method: request.method,
104
- path: request.path,
105
- headers: Object.fromEntries(Object.keys(request.headers ?? {}).map((one) => [one, REDACTED])),
106
- body,
107
- });
108
- const answer = script[`${request.method} ${request.path}`];
109
- if (answer === undefined) {
110
- throw new Error(`this scenario scripts no answer for "${request.method} ${request.path}", so nothing here knows what ${request.target} would say. Add that key to the scenario's answers — a call answered by something nobody scripted proves it was made and nothing about what came back.`);
111
- }
112
- const answered = new TextEncoder().encode(answer.body ?? '');
113
- const headers = answer.headers ?? {};
114
- return {
115
- status: answer.status,
116
- headers,
117
- body: answered,
118
- bytesSent: requestBytes({ ...request.headers }, request.body),
119
- bytesReceived: payloadBytes(headers) + answered.byteLength,
120
- durationMs: 0,
121
- };
122
- },
123
- };
124
- }