@prestack/thread 0.0.2 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (183) hide show
  1. package/CHANGELOG.md +98 -0
  2. package/dist/core/{asking.d.ts → answers.d.ts} +6 -14
  3. package/dist/core/{asking.js → answers.js} +13 -332
  4. package/dist/core/{asking.ts → answers.ts} +14 -357
  5. package/dist/core/attach.js +2 -2
  6. package/dist/core/attach.ts +2 -3
  7. package/dist/core/chain.js +4 -11
  8. package/dist/core/chain.ts +4 -3
  9. package/dist/core/client.d.ts +57 -0
  10. package/dist/core/client.js +186 -0
  11. package/dist/core/client.ts +227 -0
  12. package/dist/core/descend.d.ts +2 -0
  13. package/dist/core/descend.js +109 -16
  14. package/dist/core/descend.ts +120 -16
  15. package/dist/core/files.d.ts +45 -0
  16. package/dist/core/files.js +95 -0
  17. package/dist/core/files.ts +137 -0
  18. package/dist/core/init.d.ts +1 -0
  19. package/dist/core/init.js +10 -2
  20. package/dist/core/init.ts +8 -2
  21. package/dist/core/invoked.js +1 -1
  22. package/dist/core/invoked.ts +1 -1
  23. package/dist/core/rows.d.ts +2 -0
  24. package/dist/core/rows.js +65 -0
  25. package/dist/core/rows.ts +58 -0
  26. package/dist/core/tree.js +1 -1
  27. package/dist/core/tree.ts +1 -1
  28. package/dist/derivation/attach.js +0 -12
  29. package/dist/derivation/attach.ts +0 -12
  30. package/dist/derivation/generators/build.js +8 -7
  31. package/dist/derivation/generators/build.ts +8 -7
  32. package/dist/derivation/generators/release.d.ts +1 -1
  33. package/dist/derivation/generators/release.js +15 -23
  34. package/dist/derivation/generators/release.ts +15 -15
  35. package/dist/integrations/attach.js +1 -19
  36. package/dist/integrations/attach.ts +1 -19
  37. package/dist/integrations/generators/read.js +2 -2
  38. package/dist/integrations/generators/read.ts +4 -4
  39. package/dist/integrations/generators/vault.js +4 -12
  40. package/dist/integrations/generators/vault.ts +4 -4
  41. package/dist/integrations/module.js +5 -3
  42. package/dist/integrations/module.ts +5 -3
  43. package/dist/integrations/vault.js +5 -5
  44. package/dist/integrations/vault.ts +5 -5
  45. package/dist/integrity/attach.js +0 -12
  46. package/dist/integrity/attach.ts +0 -12
  47. package/dist/integrity/check-threads.js +1 -1
  48. package/dist/integrity/check-threads.ts +1 -1
  49. package/dist/integrity/constraint.d.ts +11 -2
  50. package/dist/integrity/constraint.js +163 -20
  51. package/dist/integrity/constraint.ts +174 -22
  52. package/dist/integrity/generators/compiler.js +1 -1
  53. package/dist/integrity/generators/compiler.ts +1 -1
  54. package/dist/integrity/generators/gate.js +8 -16
  55. package/dist/integrity/generators/gate.ts +8 -7
  56. package/dist/integrity/generators/publish.js +14 -26
  57. package/dist/integrity/generators/publish.ts +14 -17
  58. package/dist/integrity/generators/trial.d.ts +2 -2
  59. package/dist/integrity/generators/trial.js +108 -50
  60. package/dist/integrity/generators/trial.ts +107 -48
  61. package/dist/integrity/lint.js +3 -3
  62. package/dist/integrity/lint.ts +3 -3
  63. package/dist/integrity/lsp/diagnostics.js +1 -1
  64. package/dist/integrity/lsp/diagnostics.ts +1 -1
  65. package/dist/integrity/lsp/lint.js +1 -1
  66. package/dist/integrity/lsp/lint.ts +1 -1
  67. package/dist/integrity/slopnator.d.ts +1 -14
  68. package/dist/integrity/slopnator.js +8 -40
  69. package/dist/integrity/slopnator.ts +9 -51
  70. package/dist/integrity/slopnators/sl_broken_lineage.js +4 -2
  71. package/dist/integrity/slopnators/sl_broken_lineage.ts +4 -2
  72. package/dist/integrity/slopnators/sl_declared_elsewhere.js +24 -3
  73. package/dist/integrity/slopnators/sl_declared_elsewhere.ts +24 -3
  74. package/dist/integrity/slopnators/sl_derived_drift.js +10 -4
  75. package/dist/integrity/slopnators/sl_derived_drift.ts +10 -4
  76. package/dist/integrity/slopnators/sl_inert_island.js +7 -13
  77. package/dist/integrity/slopnators/sl_inert_island.ts +7 -16
  78. package/dist/integrity/slopnators/sl_inert_slopnator.js +8 -8
  79. package/dist/integrity/slopnators/sl_inert_slopnator.ts +8 -8
  80. package/dist/integrity/slopnators/sl_missing_row.js +14 -9
  81. package/dist/integrity/slopnators/sl_missing_row.ts +14 -10
  82. package/dist/integrity/slopnators/sl_no_child_process.js +8 -8
  83. package/dist/integrity/slopnators/sl_no_child_process.ts +8 -8
  84. package/dist/integrity/slopnators/sl_no_import_cycle.js +1 -1
  85. package/dist/integrity/slopnators/sl_no_import_cycle.ts +1 -1
  86. package/dist/integrity/slopnators/sl_no_such_command.js +20 -5
  87. package/dist/integrity/slopnators/sl_no_such_command.ts +22 -5
  88. package/dist/integrity/slopnators/sl_only_takes_a_literal.js +8 -8
  89. package/dist/integrity/slopnators/sl_only_takes_a_literal.ts +8 -8
  90. package/dist/integrity/slopnators/sl_stale_path.js +91 -18
  91. package/dist/integrity/slopnators/sl_stale_path.ts +97 -18
  92. package/dist/integrity/slopnators/sl_twice_meant.js +25 -2
  93. package/dist/integrity/slopnators/sl_twice_meant.ts +28 -2
  94. package/dist/integrity/slopnators/sl_twice_parented.js +26 -5
  95. package/dist/integrity/slopnators/sl_twice_parented.ts +26 -5
  96. package/dist/integrity/slopnators/sl_undeclared_node.js +18 -2
  97. package/dist/integrity/slopnators/sl_undeclared_node.ts +18 -2
  98. package/dist/integrity/slopnators/sl_undeclared_operation.js +3 -1
  99. package/dist/integrity/slopnators/sl_undeclared_operation.ts +3 -1
  100. package/dist/integrity/slopnators/sl_undeclared_variant.js +6 -2
  101. package/dist/integrity/slopnators/sl_undeclared_variant.ts +6 -2
  102. package/dist/integrity/slopnators/sl_ungoverned_island.js +3 -4
  103. package/dist/integrity/slopnators/sl_ungoverned_island.ts +3 -4
  104. package/dist/integrity/slopnators/sl_unkept_rows.js +1 -1
  105. package/dist/integrity/slopnators/sl_unkept_rows.ts +1 -1
  106. package/dist/integrity/slopnators/sl_unpaired_member.js +13 -8
  107. package/dist/integrity/slopnators/sl_unpaired_member.ts +16 -8
  108. package/dist/integrity/slopnators/sl_unpaired_slopnator.js +16 -3
  109. package/dist/integrity/slopnators/sl_unpaired_slopnator.ts +16 -3
  110. package/dist/integrity/slopnators/sl_unthreaded.d.ts +1 -0
  111. package/dist/integrity/slopnators/sl_unthreaded.js +18 -10
  112. package/dist/integrity/slopnators/sl_unthreaded.ts +19 -11
  113. package/dist/integrity/slopnators/sl_untranslated_key.js +1 -1
  114. package/dist/integrity/slopnators/sl_untranslated_key.ts +1 -1
  115. package/dist/integrity/slopnators/sl_unversioned.js +16 -2
  116. package/dist/integrity/slopnators/sl_unversioned.ts +16 -2
  117. package/dist/integrity/sweep.js +17 -3
  118. package/dist/integrity/sweep.ts +20 -3
  119. package/dist/knowledge/attach.js +0 -6
  120. package/dist/knowledge/attach.ts +0 -6
  121. package/dist/knowledge/generators/docsgen.js +12 -3
  122. package/dist/knowledge/generators/docsgen.ts +12 -2
  123. package/dist/knowledge/generators/glossary.js +1 -1
  124. package/dist/knowledge/generators/glossary.ts +1 -1
  125. package/dist/operations/attach.js +2 -26
  126. package/dist/operations/attach.ts +2 -27
  127. package/dist/operations/dispatch.js +2 -3
  128. package/dist/operations/dispatch.ts +2 -3
  129. package/dist/operations/generators/capability.js +4 -7
  130. package/dist/operations/generators/capability.ts +3 -6
  131. package/dist/operations/generators/compile.js +8 -13
  132. package/dist/operations/generators/compile.ts +8 -4
  133. package/dist/operations/generators/permits.js +4 -13
  134. package/dist/operations/generators/permits.ts +3 -3
  135. package/dist/operations/generators/seed.js +5 -2
  136. package/dist/operations/generators/seed.ts +6 -2
  137. package/dist/operations/generators/trial.js +10 -10
  138. package/dist/operations/generators/trial.ts +10 -10
  139. package/dist/operations/http.js +4 -1
  140. package/dist/operations/http.ts +6 -1
  141. package/package.json +2 -2
  142. package/dist/core/cli.d.ts +0 -2
  143. package/dist/core/cli.js +0 -1761
  144. package/dist/core/cli.ts +0 -2004
  145. package/dist/core/generators/meta.d.ts +0 -2
  146. package/dist/core/generators/meta.js +0 -829
  147. package/dist/core/generators/meta.ts +0 -1006
  148. package/dist/derivation/generators/derivation.d.ts +0 -3
  149. package/dist/derivation/generators/derivation.js +0 -273
  150. package/dist/derivation/generators/derivation.ts +0 -347
  151. package/dist/derivation/makers/release.d.ts +0 -1
  152. package/dist/derivation/makers/release.js +0 -107
  153. package/dist/derivation/makers/release.ts +0 -135
  154. package/dist/integrations/generators/secret.d.ts +0 -1
  155. package/dist/integrations/generators/secret.js +0 -233
  156. package/dist/integrations/generators/secret.ts +0 -289
  157. package/dist/integrations/generators/target.d.ts +0 -1
  158. package/dist/integrations/generators/target.js +0 -775
  159. package/dist/integrations/generators/target.ts +0 -944
  160. package/dist/integrity/generators/rule.d.ts +0 -2
  161. package/dist/integrity/generators/rule.js +0 -213
  162. package/dist/integrity/generators/rule.ts +0 -271
  163. package/dist/integrity/generators/seal.d.ts +0 -4
  164. package/dist/integrity/generators/seal.js +0 -101
  165. package/dist/integrity/generators/seal.ts +0 -117
  166. package/dist/integrity/sealed.d.ts +0 -1
  167. package/dist/integrity/sealed.js +0 -56
  168. package/dist/integrity/sealed.ts +0 -56
  169. package/dist/knowledge/generators/skills.d.ts +0 -1
  170. package/dist/knowledge/generators/skills.js +0 -222
  171. package/dist/knowledge/generators/skills.ts +0 -263
  172. package/dist/operations/generators/grant.d.ts +0 -1
  173. package/dist/operations/generators/grant.js +0 -267
  174. package/dist/operations/generators/grant.ts +0 -336
  175. package/dist/operations/generators/operation.d.ts +0 -1
  176. package/dist/operations/generators/operation.js +0 -811
  177. package/dist/operations/generators/operation.ts +0 -972
  178. package/dist/operations/makers/capability.d.ts +0 -1
  179. package/dist/operations/makers/capability.js +0 -117
  180. package/dist/operations/makers/capability.ts +0 -166
  181. package/dist/operations/makers/trial.d.ts +0 -1
  182. package/dist/operations/makers/trial.js +0 -413
  183. package/dist/operations/makers/trial.ts +0 -520
@@ -1,4 +1,5 @@
1
1
  import { named } from "../core/scope.js";
2
+ import { LISTS } from "../core/descend.js";
2
3
  import { quoted } from "../core/rows.js";
3
4
  import { PERMITS_AT } from "./access.js";
4
5
  import { CAPABILITIES_AT, CLIENT_AT, DECLARED_SEAMS_AT, DISPATCHING_AT, MCP_AT, OPENAPI_AT, SEAMS_AT } from "./capabilities.js";
@@ -7,7 +8,6 @@ import { TRIALS_AT } from "./operations.js";
7
8
  import { MEMBERS_LIST, NODES_FILE, OPERATIONS_FILE } from "./operations.js";
8
9
  import { SUPPLIES } from "./seams.js";
9
10
  const HOME = `node_modules/${named('operations')}/dist`;
10
- const LISTS = ['declares', 'derives', 'seeds'];
11
11
  const VERSION = 1;
12
12
  const ROOT = 'operations';
13
13
  const NODES_AT = '_threads/nodes.ts';
@@ -70,7 +70,7 @@ export const said = (one, pad) => {
70
70
  const ACCESS = 'Who may ask this app to do what. A row says which operations it permits, on what, to whom, and under what condition. Nothing is permitted by default: an operation no row grants here cannot be run at all.';
71
71
  const PERMITS = 'The check compiled from the grants in _threads/access.ts: one branch per grant, so who may ask for what comes from one statement. Nobody edits it, because an edit here widens or narrows access nobody granted. An app that grants nothing permits nothing.';
72
72
  const SEAMS = 'What this app hands its operations, written once and then yours. It starts by handing on everything src/_generated/seams.ts settles from your declarations. Replace a seam or add one by naming it in SEAMS: the queue, the events, telemetry, whatever a real deployment needs.';
73
- const DECLARED_SEAMS = 'The seams your declarations settle. Rows go to the store each target derived, or to memory until one does; who is calling is read off the entity that names the caller; calls leave through http with credentials the vault opens. Nobody edits it: `thread capabilities` writes it again from the rows.';
73
+ const DECLARED_SEAMS = 'The seams your declarations settle. Rows go to the store each target derived, and until one does no store is handed, so an operation that needs one is refused; who is calling is read off the entity that names the caller; calls leave through http with credentials the vault opens. Nobody edits it: `thread capabilities` writes it again from the rows.';
74
74
  const ACCESS_SOURCE = `import type { Grant } from './access.ts'
75
75
 
76
76
  export const GRANTS: readonly Grant[] = []
@@ -290,18 +290,6 @@ const SHIPPED = [
290
290
  id: 'capability-generator',
291
291
  source: " {\n id: 'capability-generator',\n at: 'node_modules/@prestack/thread/dist/operations/generators/capability.js',\n describes: 'Writes what can be reached and how, and refuses it once it has drifted. It reads each operation for its name, what it does and the shape of its input, so adding or renaming one changes what is reachable without anybody editing a list.',\n version: 1,\n by: 'thread capabilities',\n runs: 'thread capabilities --check',\n },",
292
292
  },
293
- {
294
- into: 'derivation.ts',
295
- list: 'GENERATORS',
296
- id: 'capability-noun',
297
- source: " {\n id: 'capability-noun',\n at: 'node_modules/@prestack/thread/dist/operations/makers/capability.js',\n describes: 'Reads and changes what this app exposes. `thread create capability` lists every operation with the surfaces it answers on, and `edit` switches one on or off.',\n version: 1,\n by: 'thread create capability',\n },",
298
- },
299
- {
300
- into: 'derivation.ts',
301
- list: 'GENERATORS',
302
- id: 'trial-noun',
303
- source: " {\n id: 'trial-noun',\n at: 'node_modules/@prestack/thread/dist/operations/makers/trial.js',\n describes: 'Runs one operation against an input you supply, and records what happened. `thread run trial <operation>` asks for that input, because what to run an operation on is the one thing nothing else can work out for you.',\n version: 1,\n by: 'thread run trial',\n },",
304
- },
305
293
  {
306
294
  into: 'derivation.ts',
307
295
  list: 'GENERATORS',
@@ -320,18 +308,6 @@ const SHIPPED = [
320
308
  id: 'permits-generator',
321
309
  source: " {\n id: 'permits-generator',\n at: 'node_modules/@prestack/thread/dist/operations/generators/permits.js',\n describes: 'Writes the check this app runs before any operation — one branch per grant, so who may ask for what comes from one statement rather than being repeated in every handler. It refuses a grant it cannot check honestly, such as one that would admit a caller nobody authenticated.',\n version: 1,\n by: 'thread permits',\n runs: 'thread permits --check',\n },",
322
310
  },
323
- {
324
- into: 'derivation.ts',
325
- list: 'GENERATORS',
326
- id: 'grant-generator',
327
- source: " {\n id: 'grant-generator',\n at: 'node_modules/@prestack/thread/dist/operations/generators/grant.js',\n describes: 'Records who may ask this app to do what. Run with nothing, it lists every operation and every grant already written. It builds the condition one answer at a time, offering only what the answer before it allows, so an impossible comparison is refused as it is typed.',\n version: 1,\n by: 'thread grant',\n },",
328
- },
329
- {
330
- into: 'derivation.ts',
331
- list: 'GENERATORS',
332
- id: 'operation-noun',
333
- source: " {\n id: 'operation-noun',\n at: 'node_modules/@prestack/thread/dist/operations/generators/operation.js',\n describes: 'Declares something this app can be asked to do, and the steps it is done in. This row is what makes `operation` one of the things `thread create` offers — the nouns are not a list inside the command, but rows like this one.',\n version: 1,\n by: 'thread create operation',\n },",
334
- },
335
311
  {
336
312
  into: 'derivation.ts',
337
313
  list: 'GENERATORS',
@@ -1,6 +1,7 @@
1
1
  import type { Attaching } from '../core/attach.ts'
2
2
  import { named } from '../core/scope.ts'
3
3
 
4
+ import { LISTS } from '../core/descend.ts'
4
5
  import { quoted } from '../core/rows.ts'
5
6
  import type { Threaded } from '../core/thread.ts'
6
7
 
@@ -13,8 +14,6 @@ import { SUPPLIES, type Supplied } from './seams.ts'
13
14
 
14
15
  const HOME = `node_modules/${named('operations')}/dist`
15
16
 
16
- const LISTS = ['declares', 'derives', 'seeds'] as const
17
-
18
17
  const VERSION = 1
19
18
 
20
19
  const ROOT = 'operations'
@@ -115,7 +114,7 @@ const SEAMS =
115
114
  'What this app hands its operations, written once and then yours. It starts by handing on everything src/_generated/seams.ts settles from your declarations. Replace a seam or add one by naming it in SEAMS: the queue, the events, telemetry, whatever a real deployment needs.'
116
115
 
117
116
  const DECLARED_SEAMS =
118
- 'The seams your declarations settle. Rows go to the store each target derived, or to memory until one does; who is calling is read off the entity that names the caller; calls leave through http with credentials the vault opens. Nobody edits it: `thread capabilities` writes it again from the rows.'
117
+ 'The seams your declarations settle. Rows go to the store each target derived, and until one does no store is handed, so an operation that needs one is refused; who is calling is read off the entity that names the caller; calls leave through http with credentials the vault opens. Nobody edits it: `thread capabilities` writes it again from the rows.'
119
118
 
120
119
  const ACCESS_SOURCE = `import type { Grant } from './access.ts'
121
120
 
@@ -348,18 +347,6 @@ const SHIPPED: readonly { readonly into: string; readonly list: string; readonly
348
347
  id: 'capability-generator',
349
348
  source: " {\n id: 'capability-generator',\n at: 'node_modules/@prestack/thread/dist/operations/generators/capability.js',\n describes: 'Writes what can be reached and how, and refuses it once it has drifted. It reads each operation for its name, what it does and the shape of its input, so adding or renaming one changes what is reachable without anybody editing a list.',\n version: 1,\n by: 'thread capabilities',\n runs: 'thread capabilities --check',\n },",
350
349
  },
351
- {
352
- into: 'derivation.ts',
353
- list: 'GENERATORS',
354
- id: 'capability-noun',
355
- source: " {\n id: 'capability-noun',\n at: 'node_modules/@prestack/thread/dist/operations/makers/capability.js',\n describes: 'Reads and changes what this app exposes. `thread create capability` lists every operation with the surfaces it answers on, and `edit` switches one on or off.',\n version: 1,\n by: 'thread create capability',\n },",
356
- },
357
- {
358
- into: 'derivation.ts',
359
- list: 'GENERATORS',
360
- id: 'trial-noun',
361
- source: " {\n id: 'trial-noun',\n at: 'node_modules/@prestack/thread/dist/operations/makers/trial.js',\n describes: 'Runs one operation against an input you supply, and records what happened. `thread run trial <operation>` asks for that input, because what to run an operation on is the one thing nothing else can work out for you.',\n version: 1,\n by: 'thread run trial',\n },",
362
- },
363
350
  {
364
351
  into: 'derivation.ts',
365
352
  list: 'GENERATORS',
@@ -378,18 +365,6 @@ const SHIPPED: readonly { readonly into: string; readonly list: string; readonly
378
365
  id: 'permits-generator',
379
366
  source: " {\n id: 'permits-generator',\n at: 'node_modules/@prestack/thread/dist/operations/generators/permits.js',\n describes: 'Writes the check this app runs before any operation — one branch per grant, so who may ask for what comes from one statement rather than being repeated in every handler. It refuses a grant it cannot check honestly, such as one that would admit a caller nobody authenticated.',\n version: 1,\n by: 'thread permits',\n runs: 'thread permits --check',\n },",
380
367
  },
381
- {
382
- into: 'derivation.ts',
383
- list: 'GENERATORS',
384
- id: 'grant-generator',
385
- source: " {\n id: 'grant-generator',\n at: 'node_modules/@prestack/thread/dist/operations/generators/grant.js',\n describes: 'Records who may ask this app to do what. Run with nothing, it lists every operation and every grant already written. It builds the condition one answer at a time, offering only what the answer before it allows, so an impossible comparison is refused as it is typed.',\n version: 1,\n by: 'thread grant',\n },",
386
- },
387
- {
388
- into: 'derivation.ts',
389
- list: 'GENERATORS',
390
- id: 'operation-noun',
391
- source: " {\n id: 'operation-noun',\n at: 'node_modules/@prestack/thread/dist/operations/generators/operation.js',\n describes: 'Declares something this app can be asked to do, and the steps it is done in. This row is what makes `operation` one of the things `thread create` offers — the nouns are not a list inside the command, but rows like this one.',\n version: 1,\n by: 'thread create operation',\n },",
392
- },
393
368
  {
394
369
  into: 'derivation.ts',
395
370
  list: 'GENERATORS',
@@ -171,9 +171,8 @@ export const dispatched = (reached) => [
171
171
  ' operation: Operation<I, R>,',
172
172
  ' rawInput: unknown,',
173
173
  ' asking: Actor,',
174
- ' handed: Seams,',
174
+ ' seams: Seams,',
175
175
  '): Promise<Result<unknown>> {',
176
- ' const seams = running(handed)',
177
176
  ' const id = operation.id',
178
177
  ' const who = person(asking)',
179
178
  ' const run = who?.run ?? seams.random.uuid()',
@@ -186,7 +185,7 @@ export const dispatched = (reached) => [
186
185
  ' let granted: string | undefined',
187
186
  '',
188
187
  ' const sank = (what: string) => (thrown: unknown): void => {',
189
- " seams.log?.write('error', id, actor, {",
188
+ " seams.log.write('error', id, actor, {",
190
189
  ' [`${what}_failed`]: thrown instanceof Error ? thrown.message : String(thrown),',
191
190
  ' })',
192
191
  ' }',
@@ -192,9 +192,8 @@ export const dispatched = (
192
192
  ' operation: Operation<I, R>,',
193
193
  ' rawInput: unknown,',
194
194
  ' asking: Actor,',
195
- ' handed: Seams,',
195
+ ' seams: Seams,',
196
196
  '): Promise<Result<unknown>> {',
197
- ' const seams = running(handed)',
198
197
  ' const id = operation.id',
199
198
  ' const who = person(asking)',
200
199
  ' const run = who?.run ?? seams.random.uuid()',
@@ -207,7 +206,7 @@ export const dispatched = (
207
206
  ' let granted: string | undefined',
208
207
  '',
209
208
  ' const sank = (what: string) => (thrown: unknown): void => {',
210
- " seams.log?.write('error', id, actor, {",
209
+ " seams.log.write('error', id, actor, {",
211
210
  ' [`${what}_failed`]: thrown instanceof Error ? thrown.message : String(thrown),',
212
211
  ' })',
213
212
  ' }',
@@ -6,11 +6,11 @@ var __rewriteRelativeImportExtension = (this && this.__rewriteRelativeImportExte
6
6
  }
7
7
  return path;
8
8
  };
9
- import { existsSync, mkdirSync, readdirSync, readFileSync, writeFileSync } from 'node:fs';
10
- import { dirname, resolve } from 'node:path';
9
+ import { existsSync, readdirSync, readFileSync, writeFileSync } from "../../core/files.js";
10
+ import { resolve } from 'node:path';
11
11
  import { argv, stdout } from 'node:process';
12
12
  import { pathToFileURL } from 'node:url';
13
- import { marked, wordsIn } from "../../core/asking.js";
13
+ import { marked, wordsIn } from "../../core/answers.js";
14
14
  import { ROOT, TREE, descend } from "../../core/descend.js";
15
15
  import { exit, invoked } from "../../core/invoked.js";
16
16
  import { named as packageOf } from "../../core/scope.js";
@@ -460,7 +460,7 @@ const width = Math.max(...Object.keys(HANDED).map((one) => one.length));
460
460
  const handing = (stores, keeping, vaulted) => [
461
461
  `capabilities: seeded ${SEAMS_AT} — what this app hands its operations, and yours from here.`,
462
462
  ` It hands on everything ${DECLARED_SEAMS_AT} settles from your declarations: rows go to ` +
463
- (stores.length === 0 ? 'memory until a target keeps entities' : stores.join(', ')) +
463
+ (stores.length === 0 ? 'no store yet — no target keeps entities, so an operation that needs one is refused' : stores.join(', ')) +
464
464
  `, who is asking is ${keeping ? 'read off the entity that names the caller' : 'nobody until an entity names the caller'}, ` +
465
465
  `calls leave through http${vaulted ? ' with credentials opened by the vault' : ''}.`,
466
466
  ' Replace a seam, or add one, by naming it in SEAMS. Every seam an operation can be handed:',
@@ -561,7 +561,6 @@ if (invoked(import.meta.url)) {
561
561
  console.error(`capabilities: ${DECLARED_SEAMS_AT} is not what the declarations settle. Run \`thread capabilities\` and commit the result.`);
562
562
  }
563
563
  else {
564
- mkdirSync(dirname(at), { recursive: true });
565
564
  writeFileSync(at, text, 'utf8');
566
565
  console.log(`capabilities: wrote ${DECLARED_SEAMS_AT} — the seams your targets, entities, grants and secrets settle.`);
567
566
  }
@@ -573,7 +572,6 @@ if (invoked(import.meta.url)) {
573
572
  console.error(`capabilities: ${SEAMS_AT} is not there, and it is what hands every operation its seams. Run \`thread capabilities\` — it seeds the file once, and from then on it is yours.`);
574
573
  }
575
574
  else {
576
- mkdirSync(dirname(seed), { recursive: true });
577
575
  writeFileSync(seed, seeded(), 'utf8');
578
576
  stdout.write(handing(stores, keeping, vaulted));
579
577
  }
@@ -603,7 +601,6 @@ if (invoked(import.meta.url)) {
603
601
  }
604
602
  for (const one of written) {
605
603
  const path = resolve(ROOT, one.at);
606
- mkdirSync(dirname(path), { recursive: true });
607
604
  writeFileSync(path, one.text);
608
605
  }
609
606
  const shipped = found.filter(held).length;
@@ -1,9 +1,9 @@
1
- import { existsSync, mkdirSync, readdirSync, readFileSync, writeFileSync } from 'node:fs'
1
+ import { existsSync, readdirSync, readFileSync, writeFileSync } from '../../core/files.ts'
2
2
  import { dirname, resolve } from 'node:path'
3
3
  import { argv, stdout } from 'node:process'
4
4
  import { pathToFileURL } from 'node:url'
5
5
 
6
- import { marked, wordsIn } from '../../core/asking.ts'
6
+ import { marked, wordsIn } from '../../core/answers.ts'
7
7
  import { ROOT, TREE, descend } from '../../core/descend.ts'
8
8
  import { exit, invoked } from '../../core/invoked.ts'
9
9
  import { named as packageOf } from '../../core/scope.ts'
@@ -509,7 +509,7 @@ const handing = (stores: readonly string[], keeping: boolean, vaulted: boolean):
509
509
  [
510
510
  `capabilities: seeded ${SEAMS_AT} — what this app hands its operations, and yours from here.`,
511
511
  ` It hands on everything ${DECLARED_SEAMS_AT} settles from your declarations: rows go to ` +
512
- (stores.length === 0 ? 'memory until a target keeps entities' : stores.join(', ')) +
512
+ (stores.length === 0 ? 'no store yet — no target keeps entities, so an operation that needs one is refused' : stores.join(', ')) +
513
513
  `, who is asking is ${keeping ? 'read off the entity that names the caller' : 'nobody until an entity names the caller'}, ` +
514
514
  `calls leave through http${vaulted ? ' with credentials opened by the vault' : ''}.`,
515
515
  ' Replace a seam, or add one, by naming it in SEAMS. Every seam an operation can be handed:',
@@ -635,7 +635,6 @@ if (invoked(import.meta.url)) {
635
635
  `capabilities: ${DECLARED_SEAMS_AT} is not what the declarations settle. Run \`thread capabilities\` and commit the result.`,
636
636
  )
637
637
  } else {
638
- mkdirSync(dirname(at), { recursive: true })
639
638
  writeFileSync(at, text, 'utf8')
640
639
  console.log(`capabilities: wrote ${DECLARED_SEAMS_AT} — the seams your targets, entities, grants and secrets settle.`)
641
640
  }
@@ -649,7 +648,6 @@ if (invoked(import.meta.url)) {
649
648
  `capabilities: ${SEAMS_AT} is not there, and it is what hands every operation its seams. Run \`thread capabilities\` — it seeds the file once, and from then on it is yours.`,
650
649
  )
651
650
  } else {
652
- mkdirSync(dirname(seed), { recursive: true })
653
651
  writeFileSync(seed, seeded(), 'utf8')
654
652
  stdout.write(handing(stores, keeping, vaulted))
655
653
  }
@@ -690,7 +688,6 @@ if (invoked(import.meta.url)) {
690
688
 
691
689
  for (const one of written) {
692
690
  const path = resolve(ROOT, one.at)
693
- mkdirSync(dirname(path), { recursive: true })
694
691
  writeFileSync(path, one.text)
695
692
  }
696
693
 
@@ -1,19 +1,11 @@
1
- var __rewriteRelativeImportExtension = (this && this.__rewriteRelativeImportExtension) || function (path, preserveJsx) {
2
- if (typeof path === "string" && /^\.\.?\//.test(path)) {
3
- return path.replace(/\.(tsx)$|((?:\.d)?)((?:\.[^./]+?)?)\.([cm]?)ts$/i, function (m, tsx, d, ext, cm) {
4
- return tsx ? preserveJsx ? ".jsx" : ".js" : d && (!ext || !cm) ? m : (d + ext + "." + cm.toLowerCase() + "js");
5
- });
6
- }
7
- return path;
8
- };
9
- import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
10
- import { dirname, resolve } from 'node:path';
1
+ import { existsSync, readFileSync, writeFileSync } from "../../core/files.js";
2
+ import { resolve } from 'node:path';
11
3
  import { argv, stdout } from 'node:process';
12
4
  import ts from 'typescript';
13
5
  import { ROOT, descend } from "../../core/descend.js";
14
6
  import { runChecker } from "../../core/finding.js";
15
7
  import { exit, invoked } from "../../core/invoked.js";
16
- import { inCode } from "../../core/rows.js";
8
+ import { inCode, valuesIn } from "../../core/rows.js";
17
9
  import { addressOf, credentialsOf, reachOf } from "../../integrations/target.js";
18
10
  import { DISPATCH_AT, dispatched } from "../dispatch.js";
19
11
  import { SUPPLIES } from "../seams.js";
@@ -24,7 +16,7 @@ async function reaching() {
24
16
  if (!existsSync(path))
25
17
  return [];
26
18
  try {
27
- const taken = (await import(__rewriteRelativeImportExtension(new URL(`file://${path}`).href)));
19
+ const taken = valuesIn(readFileSync(path, 'utf8'));
28
20
  return taken[list] ?? [];
29
21
  }
30
22
  catch {
@@ -488,6 +480,10 @@ async function planned() {
488
480
  return found;
489
481
  }
490
482
  function checked(plan) {
483
+ if (plan.length === 0) {
484
+ stdout.write('compile: no operation here states a body to compile, so there is nothing to check.\n');
485
+ exit(0);
486
+ }
491
487
  const findings = plan.flatMap((one) => {
492
488
  const path = resolve(ROOT, one.at);
493
489
  if (one.because !== undefined) {
@@ -538,7 +534,6 @@ export async function compile(say = true) {
538
534
  const path = resolve(ROOT, one.at);
539
535
  if (existsSync(path) && readFileSync(path, 'utf8') === one.text)
540
536
  continue;
541
- mkdirSync(dirname(path), { recursive: true });
542
537
  writeFileSync(path, one.text, 'utf8');
543
538
  written += 1;
544
539
  if (say)
@@ -1,4 +1,4 @@
1
- import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs'
1
+ import { existsSync, readFileSync, writeFileSync } from '../../core/files.ts'
2
2
  import { dirname, resolve } from 'node:path'
3
3
  import { argv, stdout } from 'node:process'
4
4
 
@@ -7,7 +7,7 @@ import ts from 'typescript'
7
7
  import { ROOT, descend } from '../../core/descend.ts'
8
8
  import { runChecker, type Finding } from '../../core/finding.ts'
9
9
  import { exit, invoked } from '../../core/invoked.ts'
10
- import { inCode } from '../../core/rows.ts'
10
+ import { inCode, valuesIn } from '../../core/rows.ts'
11
11
 
12
12
  import { addressOf, credentialsOf, reachOf, type Call, type Target } from '../../integrations/target.ts'
13
13
  import type { Secret } from '../../integrations/secret.ts'
@@ -21,7 +21,7 @@ async function reaching(): Promise<Readonly<Record<string, ReturnType<typeof rea
21
21
  const path = resolve(ROOT, `_threads/${file}`)
22
22
  if (!existsSync(path)) return []
23
23
  try {
24
- const taken = (await import(new URL(`file://${path}`).href)) as Record<string, readonly T[] | undefined>
24
+ const taken = valuesIn(readFileSync(path, 'utf8')) as Record<string, readonly T[] | undefined>
25
25
  return taken[list] ?? []
26
26
  } catch {
27
27
  return []
@@ -568,6 +568,11 @@ async function planned(): Promise<readonly Wanted[]> {
568
568
  }
569
569
 
570
570
  function checked(plan: readonly Wanted[]): void {
571
+ if (plan.length === 0) {
572
+ stdout.write('compile: no operation here states a body to compile, so there is nothing to check.\n')
573
+ exit(0)
574
+ }
575
+
571
576
  const findings: Finding[] = plan.flatMap((one): Finding[] => {
572
577
  const path = resolve(ROOT, one.at)
573
578
 
@@ -622,7 +627,6 @@ export async function compile(say: boolean = true): Promise<number> {
622
627
  }
623
628
  const path = resolve(ROOT, one.at)
624
629
  if (existsSync(path) && readFileSync(path, 'utf8') === one.text) continue
625
- mkdirSync(dirname(path), { recursive: true })
626
630
  writeFileSync(path, one.text, 'utf8')
627
631
  written += 1
628
632
  if (say) stdout.write(`compile: wrote ${one.at}\n`)
@@ -1,15 +1,7 @@
1
- var __rewriteRelativeImportExtension = (this && this.__rewriteRelativeImportExtension) || function (path, preserveJsx) {
2
- if (typeof path === "string" && /^\.\.?\//.test(path)) {
3
- return path.replace(/\.(tsx)$|((?:\.d)?)((?:\.[^./]+?)?)\.([cm]?)ts$/i, function (m, tsx, d, ext, cm) {
4
- return tsx ? preserveJsx ? ".jsx" : ".js" : d && (!ext || !cm) ? m : (d + ext + "." + cm.toLowerCase() + "js");
5
- });
6
- }
7
- return path;
8
- };
9
- import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
10
- import { dirname, resolve } from 'node:path';
1
+ import { existsSync, readFileSync, writeFileSync } from "../../core/files.js";
2
+ import { valuesIn } from "../../core/rows.js";
3
+ import { resolve } from 'node:path';
11
4
  import { argv, stderr, stdout } from 'node:process';
12
- import { pathToFileURL } from 'node:url';
13
5
  import { exit } from "../../core/invoked.js";
14
6
  import { PUBLIC_ROLE as PUBLIC } from "../../core/actor.js";
15
7
  import { ROOT, descend } from "../../core/descend.js";
@@ -35,7 +27,7 @@ async function taken(file, name, what) {
35
27
  stop(`${at} is where this app states ${what}, and it is not there`);
36
28
  let held;
37
29
  try {
38
- held = (await import(__rewriteRelativeImportExtension(pathToFileURL(at).href)));
30
+ held = valuesIn(readFileSync(at));
39
31
  }
40
32
  catch (thrown) {
41
33
  stop(`${at} could not be read: ${thrown instanceof Error ? thrown.message : String(thrown)}. A tree whose access ` +
@@ -190,7 +182,6 @@ if (CHECKING) {
190
182
  runChecker('permits', findings, count);
191
183
  exit(findings.length === 0 ? 0 : 1);
192
184
  }
193
- mkdirSync(dirname(permitted), { recursive: true });
194
185
  writeFileSync(permitted, content);
195
186
  stdout.write(`permits: wrote ${PERMITS_AT} — ${count}. ${DECLARED_SEAMS_AT} hands it to dispatch as the gate every operation passes; ` +
196
187
  '`thread grant` adds a grant, and a refusal no grant can say is an invariant on the entity, or a rule from `thread create rule`.\n');
@@ -1,4 +1,5 @@
1
- import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs'
1
+ import { existsSync, readFileSync, writeFileSync } from '../../core/files.ts'
2
+ import { valuesIn } from '../../core/rows.ts'
2
3
  import { dirname, resolve } from 'node:path'
3
4
  import { argv, stderr, stdout } from 'node:process'
4
5
  import { pathToFileURL } from 'node:url'
@@ -36,7 +37,7 @@ async function taken<T>(file: string, name: string, what: string): Promise<reado
36
37
  if (!existsSync(at)) stop(`${at} is where this app states ${what}, and it is not there`)
37
38
  let held: Record<string, unknown>
38
39
  try {
39
- held = (await import(pathToFileURL(at).href)) as Record<string, unknown>
40
+ held = valuesIn(readFileSync(at)) as Record<string, unknown>
40
41
  } catch (thrown) {
41
42
  stop(
42
43
  `${at} could not be read: ${thrown instanceof Error ? thrown.message : String(thrown)}. A tree whose access ` +
@@ -215,7 +216,6 @@ if (CHECKING) {
215
216
  exit(findings.length === 0 ? 0 : 1)
216
217
  }
217
218
 
218
- mkdirSync(dirname(permitted), { recursive: true })
219
219
  writeFileSync(permitted, content)
220
220
  stdout.write(
221
221
  `permits: wrote ${PERMITS_AT} — ${count}. ${DECLARED_SEAMS_AT} hands it to dispatch as the gate every operation passes; ` +
@@ -1,4 +1,4 @@
1
- import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
1
+ import { existsSync, readFileSync, writeFileSync } from "../../core/files.js";
2
2
  import { dirname, relative, resolve } from 'node:path';
3
3
  import { argv, stdout } from 'node:process';
4
4
  import { fileURLToPath } from 'node:url';
@@ -194,6 +194,10 @@ function planned(bodies) {
194
194
  return found;
195
195
  }
196
196
  function checked(plan) {
197
+ if (plan.length === 0) {
198
+ stdout.write('seed: this app declares no operation and no node type of its own, so there is no file to write or check.\n');
199
+ exit(0);
200
+ }
197
201
  const findings = plan.flatMap((one) => {
198
202
  const path = resolve(ROOT, one.at);
199
203
  if (one.because !== undefined) {
@@ -267,7 +271,6 @@ export function seed(bodies = new Map(), say = true) {
267
271
  }
268
272
  if (held === one.text)
269
273
  continue;
270
- mkdirSync(dirname(path), { recursive: true });
271
274
  writeFileSync(path, one.text, 'utf8');
272
275
  written += 1;
273
276
  if (say)
@@ -1,4 +1,4 @@
1
- import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs'
1
+ import { existsSync, readFileSync, writeFileSync } from '../../core/files.ts'
2
2
  import { dirname, relative, resolve } from 'node:path'
3
3
  import { argv, stdout } from 'node:process'
4
4
  import { fileURLToPath } from 'node:url'
@@ -249,6 +249,11 @@ function planned(bodies: ReadonlyMap<string, string>): readonly Wanted[] {
249
249
  }
250
250
 
251
251
  function checked(plan: readonly Wanted[]): void {
252
+ if (plan.length === 0) {
253
+ stdout.write('seed: this app declares no operation and no node type of its own, so there is no file to write or check.\n')
254
+ exit(0)
255
+ }
256
+
252
257
  const findings: Finding[] = plan.flatMap((one): Finding[] => {
253
258
  const path = resolve(ROOT, one.at)
254
259
 
@@ -332,7 +337,6 @@ export function seed(bodies: ReadonlyMap<string, string> = new Map(), say: boole
332
337
  }
333
338
  if (held === one.text) continue
334
339
 
335
- mkdirSync(dirname(path), { recursive: true })
336
340
  writeFileSync(path, one.text, 'utf8')
337
341
  written += 1
338
342
  if (say) stdout.write(`seed: wrote ${one.at}\n`)
@@ -6,8 +6,8 @@ var __rewriteRelativeImportExtension = (this && this.__rewriteRelativeImportExte
6
6
  }
7
7
  return path;
8
8
  };
9
- import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
10
- import { dirname, resolve } from 'node:path';
9
+ import { existsSync, readFileSync, writeFileSync } from "../../core/files.js";
10
+ import { resolve } from 'node:path';
11
11
  import { argv, stdout } from 'node:process';
12
12
  import { pathToFileURL } from 'node:url';
13
13
  import { ANONYMOUS } from "../../core/actor.js";
@@ -59,11 +59,8 @@ function seamsFor(one, scenario, stood, gate, known) {
59
59
  ...(known === undefined ? {} : { entities: known.entities, keys: known.keys }),
60
60
  });
61
61
  const found = made.seams;
62
- found['permits'] = gate ?? {
63
- check() {
64
- return Promise.resolve({ allow: true, because: 'this app derives no gate, so nothing here can refuse' });
65
- },
66
- };
62
+ if (gate !== undefined)
63
+ found['permits'] = gate;
67
64
  found['clock'] = { now: () => WHEN };
68
65
  let drawn = 0;
69
66
  found['random'] = {
@@ -239,8 +236,10 @@ async function standing() {
239
236
  const taken = (await import(__rewriteRelativeImportExtension(pathToFileURL(at).href)));
240
237
  held = taken.SECRETS ?? [];
241
238
  }
242
- catch {
243
- return {};
239
+ catch (thrown) {
240
+ return (`_threads/secrets.ts is there and could not be read: ${thrown instanceof Error ? thrown.message : String(thrown)}. ` +
241
+ 'A secrets sheet that cannot be read reports exactly like an app that declares none, so every trial would run ' +
242
+ 'as though nothing were sealed and pass having proved that');
244
243
  }
245
244
  const found = {};
246
245
  for (const one of held) {
@@ -257,6 +256,8 @@ export async function record() {
257
256
  if (declared.length === 0)
258
257
  return { trials: [], refusals: [] };
259
258
  const stood = await standing();
259
+ if (typeof stood === 'string')
260
+ return { trials: [], refusals: [stood] };
260
261
  const at = resolve(ROOT, DISPATCH_AT);
261
262
  if (!existsSync(at)) {
262
263
  return {
@@ -371,7 +372,6 @@ if (invoked(import.meta.url)) {
371
372
  exit(1);
372
373
  }
373
374
  const at = resolve(ROOT, TRIALS_AT);
374
- mkdirSync(dirname(at), { recursive: true });
375
375
  writeFileSync(at, printed(trials));
376
376
  const measured = trials.filter((one) => one.measured).length;
377
377
  stdout.write(`trial: wrote ${TRIALS_AT} — ${String(trials.length)} trial(s) from ${String(measured)} run(s) that reached an operation.\n`);
@@ -1,4 +1,4 @@
1
- import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs'
1
+ import { existsSync, readFileSync, writeFileSync } from '../../core/files.ts'
2
2
  import { dirname, resolve } from 'node:path'
3
3
  import { argv, stdout } from 'node:process'
4
4
  import { pathToFileURL } from 'node:url'
@@ -116,11 +116,7 @@ function seamsFor(
116
116
 
117
117
  const found = made.seams as unknown as Record<string, unknown>
118
118
 
119
- found['permits'] = gate ?? {
120
- check() {
121
- return Promise.resolve({ allow: true, because: 'this app derives no gate, so nothing here can refuse' })
122
- },
123
- }
119
+ if (gate !== undefined) found['permits'] = gate
124
120
  found['clock'] = { now: () => WHEN }
125
121
 
126
122
  let drawn = 0
@@ -335,7 +331,7 @@ export function unproven(run: Run): readonly string[] {
335
331
  return said
336
332
  }
337
333
 
338
- async function standing(): Promise<Readonly<Record<string, string>>> {
334
+ async function standing(): Promise<Readonly<Record<string, string>> | string> {
339
335
  const at = resolve(ROOT, '_threads/secrets.ts')
340
336
  if (!existsSync(at)) return {}
341
337
  let held: readonly { readonly id: string; readonly sends?: unknown }[]
@@ -344,8 +340,12 @@ async function standing(): Promise<Readonly<Record<string, string>>> {
344
340
  readonly SECRETS?: readonly { readonly id: string; readonly sends?: unknown }[]
345
341
  }
346
342
  held = taken.SECRETS ?? []
347
- } catch {
348
- return {}
343
+ } catch (thrown) {
344
+ return (
345
+ `_threads/secrets.ts is there and could not be read: ${thrown instanceof Error ? thrown.message : String(thrown)}. ` +
346
+ 'A secrets sheet that cannot be read reports exactly like an app that declares none, so every trial would run ' +
347
+ 'as though nothing were sealed and pass having proved that'
348
+ )
349
349
  }
350
350
  const found: Record<string, string> = {}
351
351
  for (const one of held) {
@@ -364,6 +364,7 @@ export async function record(): Promise<{ readonly trials: readonly Trial[]; rea
364
364
  if (declared.length === 0) return { trials: [], refusals: [] }
365
365
 
366
366
  const stood = await standing()
367
+ if (typeof stood === 'string') return { trials: [], refusals: [stood] }
367
368
 
368
369
  const at = resolve(ROOT, DISPATCH_AT)
369
370
  if (!existsSync(at)) {
@@ -519,7 +520,6 @@ if (invoked(import.meta.url)) {
519
520
  }
520
521
 
521
522
  const at = resolve(ROOT, TRIALS_AT)
522
- mkdirSync(dirname(at), { recursive: true })
523
523
  writeFileSync(at, printed(trials))
524
524
  const measured = trials.filter((one) => one.measured).length
525
525
  stdout.write(
@@ -105,7 +105,10 @@ export function recordingHttp(script = {}) {
105
105
  headers: Object.fromEntries(Object.keys(request.headers ?? {}).map((one) => [one, REDACTED])),
106
106
  body,
107
107
  });
108
- const answer = script[`${request.method} ${request.path}`] ?? { status: 404, body: '{"message":"not scripted"}' };
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
+ }
109
112
  const answered = new TextEncoder().encode(answer.body ?? '');
110
113
  const headers = answer.headers ?? {};
111
114
  return {
@@ -147,7 +147,12 @@ export function recordingHttp(
147
147
  body,
148
148
  })
149
149
 
150
- const answer = script[`${request.method} ${request.path}`] ?? { status: 404, body: '{"message":"not scripted"}' }
150
+ const answer = script[`${request.method} ${request.path}`]
151
+ if (answer === undefined) {
152
+ throw new Error(
153
+ `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.`,
154
+ )
155
+ }
151
156
  const answered = new TextEncoder().encode(answer.body ?? '')
152
157
  const headers = answer.headers ?? {}
153
158
  return {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@prestack/thread",
3
- "version": "0.0.2",
3
+ "version": "0.1.0",
4
4
  "type": "module",
5
5
  "files": [
6
6
  "dist",
@@ -11,7 +11,7 @@
11
11
  "./*": "./dist/*.js"
12
12
  },
13
13
  "bin": {
14
- "thread": "dist/core/cli.js"
14
+ "thread": "dist/core/client.js"
15
15
  },
16
16
  "dependencies": {
17
17
  "esbuild": "^0.28.2",
@@ -1,2 +0,0 @@
1
- #!/usr/bin/env node
2
- export {};