@prestack/thread 0.1.3 → 0.1.5

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 (270) hide show
  1. package/CHANGELOG.md +563 -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 +38 -67
  7. package/dist/core/attach.ts +34 -80
  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 +91 -23
  14. package/dist/core/descend.ts +90 -21
  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 +1 -1
  27. package/dist/core/init.js +51 -5
  28. package/dist/core/init.ts +58 -5
  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/scope.d.ts +1 -0
  38. package/dist/core/scope.js +1 -0
  39. package/dist/core/scope.ts +2 -0
  40. package/dist/core/thread.d.ts +3 -3
  41. package/dist/core/tree.d.ts +4 -1
  42. package/dist/core/tree.js +26 -6
  43. package/dist/core/tree.ts +29 -6
  44. package/dist/core/types.d.ts +3 -3
  45. package/dist/core/types.js +3 -1
  46. package/dist/core/types.ts +2 -1
  47. package/dist/derivation/attach.js +3 -2
  48. package/dist/derivation/attach.ts +2 -1
  49. package/dist/derivation/generators/build.js +6 -6
  50. package/dist/derivation/generators/build.ts +1 -1
  51. package/dist/derivation/generators/check.js +1 -1
  52. package/dist/derivation/generators/determinism.js +1 -1
  53. package/dist/derivation/generators/release.js +60 -47
  54. package/dist/derivation/generators/release.ts +66 -43
  55. package/dist/derivation/release.d.ts +7 -3
  56. package/dist/derivation/release.js +14 -1
  57. package/dist/derivation/release.ts +22 -2
  58. package/dist/integrations/attach.d.ts +4 -0
  59. package/dist/integrations/attach.js +37 -56
  60. package/dist/integrations/attach.ts +54 -60
  61. package/dist/integrations/cli.d.ts +37 -0
  62. package/dist/integrations/cli.js +440 -0
  63. package/dist/integrations/cli.ts +543 -0
  64. package/dist/{core/files.d.ts → integrations/disk.d.ts} +16 -24
  65. package/dist/integrations/disk.js +435 -0
  66. package/dist/integrations/disk.ts +465 -0
  67. package/dist/integrations/generators/read.js +6 -6
  68. package/dist/integrations/generators/read.ts +4 -4
  69. package/dist/integrations/generators/vault.js +10 -11
  70. package/dist/integrations/generators/vault.ts +4 -5
  71. package/dist/{operations/http.d.ts → integrations/https.d.ts} +10 -6
  72. package/dist/integrations/https.js +170 -0
  73. package/dist/integrations/https.ts +216 -0
  74. package/dist/integrations/pglite.d.ts +26 -0
  75. package/dist/integrations/pglite.js +143 -0
  76. package/dist/integrations/pglite.ts +206 -0
  77. package/dist/integrations/secret.d.ts +8 -2
  78. package/dist/integrations/secret.js +3 -5
  79. package/dist/integrations/secret.ts +10 -6
  80. package/dist/integrations/target.d.ts +155 -14
  81. package/dist/integrations/target.js +171 -50
  82. package/dist/integrations/target.ts +377 -61
  83. package/dist/integrations/vault.d.ts +1 -0
  84. package/dist/integrations/vault.js +20 -5
  85. package/dist/integrations/vault.ts +17 -5
  86. package/dist/integrity/attach.js +8 -77
  87. package/dist/integrity/attach.ts +7 -76
  88. package/dist/integrity/check-threads.js +5 -5
  89. package/dist/integrity/check-threads.ts +2 -2
  90. package/dist/integrity/constraint.d.ts +0 -1
  91. package/dist/integrity/constraint.js +267 -366
  92. package/dist/integrity/constraint.ts +267 -375
  93. package/dist/integrity/generators/compiler.js +14 -17
  94. package/dist/integrity/generators/compiler.ts +10 -15
  95. package/dist/integrity/generators/gate.js +15 -15
  96. package/dist/integrity/generators/gate.ts +10 -10
  97. package/dist/integrity/generators/issues.js +7 -7
  98. package/dist/integrity/generators/publish.js +39 -57
  99. package/dist/integrity/generators/publish.ts +44 -55
  100. package/dist/integrity/generators/trial.d.ts +3 -3
  101. package/dist/integrity/generators/trial.js +133 -165
  102. package/dist/integrity/generators/trial.ts +145 -169
  103. package/dist/integrity/lint.js +9 -13
  104. package/dist/integrity/lint.ts +7 -10
  105. package/dist/integrity/lsp/bin.js +5 -4
  106. package/dist/integrity/lsp/bin.ts +3 -1
  107. package/dist/integrity/lsp/diagnostics.js +3 -3
  108. package/dist/integrity/lsp/diagnostics.ts +1 -1
  109. package/dist/integrity/lsp/lint.js +19 -30
  110. package/dist/integrity/lsp/lint.ts +16 -32
  111. package/dist/integrity/lsp/server.js +3 -3
  112. package/dist/integrity/slopnator.d.ts +3 -13
  113. package/dist/integrity/slopnator.js +59 -38
  114. package/dist/integrity/slopnator.ts +54 -38
  115. package/dist/integrity/slopnators/sl_broken_lineage.js +2 -2
  116. package/dist/integrity/slopnators/sl_declared_elsewhere.js +1 -1
  117. package/dist/integrity/slopnators/sl_derived_drift.js +4 -4
  118. package/dist/integrity/slopnators/sl_derived_drift.ts +1 -1
  119. package/dist/integrity/slopnators/sl_door_in_a_node.js +220 -0
  120. package/dist/integrity/slopnators/sl_door_in_a_node.ts +250 -0
  121. package/dist/integrity/slopnators/sl_inert_island.js +10 -8
  122. package/dist/integrity/slopnators/sl_inert_island.ts +8 -6
  123. package/dist/integrity/slopnators/sl_missing_row.js +6 -51
  124. package/dist/integrity/slopnators/sl_missing_row.ts +4 -50
  125. package/dist/integrity/slopnators/sl_no_barrel.js +1 -1
  126. package/dist/integrity/slopnators/sl_no_child_process.js +36 -18
  127. package/dist/integrity/slopnators/sl_no_child_process.ts +44 -18
  128. package/dist/integrity/slopnators/sl_no_dispatch_bypass.js +80 -149
  129. package/dist/integrity/slopnators/sl_no_dispatch_bypass.ts +95 -147
  130. package/dist/integrity/slopnators/sl_no_import_cycle.js +15 -4
  131. package/dist/integrity/slopnators/sl_no_import_cycle.ts +20 -4
  132. package/dist/integrity/slopnators/sl_no_such_command.js +2 -2
  133. package/dist/integrity/slopnators/sl_no_such_command.ts +1 -1
  134. package/dist/integrity/slopnators/sl_outside_an_operation.js +20 -0
  135. package/dist/integrity/slopnators/sl_outside_an_operation.ts +25 -0
  136. package/dist/integrity/slopnators/sl_screen_holds_only_declared.d.ts +2 -0
  137. package/dist/integrity/slopnators/sl_screen_holds_only_declared.js +61 -0
  138. package/dist/integrity/slopnators/sl_screen_holds_only_declared.ts +70 -0
  139. package/dist/integrity/slopnators/sl_secret_literal.js +1 -33
  140. package/dist/integrity/slopnators/sl_secret_literal.ts +1 -33
  141. package/dist/integrity/slopnators/sl_stale_path.js +5 -22
  142. package/dist/integrity/slopnators/sl_stale_path.ts +4 -20
  143. package/dist/integrity/slopnators/sl_twice_meant.js +1 -1
  144. package/dist/integrity/slopnators/sl_twice_parented.js +29 -5
  145. package/dist/integrity/slopnators/sl_twice_parented.ts +28 -4
  146. package/dist/integrity/slopnators/sl_undeclared_crossing.d.ts +4 -1
  147. package/dist/integrity/slopnators/sl_undeclared_crossing.js +426 -62
  148. package/dist/integrity/slopnators/sl_undeclared_crossing.ts +454 -70
  149. package/dist/integrity/slopnators/sl_undeclared_destination.js +59 -25
  150. package/dist/integrity/slopnators/sl_undeclared_destination.ts +69 -21
  151. package/dist/integrity/slopnators/sl_undeclared_list.d.ts +2 -0
  152. package/dist/integrity/slopnators/sl_undeclared_list.js +363 -0
  153. package/dist/integrity/slopnators/sl_undeclared_list.ts +358 -0
  154. package/dist/integrity/slopnators/sl_undeclared_node.js +1 -11
  155. package/dist/integrity/slopnators/sl_undeclared_node.ts +0 -10
  156. package/dist/integrity/slopnators/sl_undeclared_operation.js +111 -29
  157. package/dist/integrity/slopnators/sl_undeclared_operation.ts +134 -26
  158. package/dist/integrity/slopnators/sl_undeclared_variant.js +2 -2
  159. package/dist/integrity/slopnators/sl_undeclared_webhook.d.ts +2 -0
  160. package/dist/integrity/slopnators/sl_undeclared_webhook.js +90 -0
  161. package/dist/integrity/slopnators/sl_undeclared_webhook.ts +108 -0
  162. package/dist/integrity/slopnators/sl_underived_route.d.ts +2 -0
  163. package/dist/integrity/slopnators/sl_underived_route.js +61 -0
  164. package/dist/integrity/slopnators/sl_underived_route.ts +72 -0
  165. package/dist/integrity/slopnators/sl_ungoverned_island.js +3 -3
  166. package/dist/integrity/slopnators/sl_ungoverned_island.ts +1 -1
  167. package/dist/integrity/slopnators/sl_unlisted_program.d.ts +2 -0
  168. package/dist/integrity/slopnators/sl_unlisted_program.js +39 -0
  169. package/dist/integrity/slopnators/sl_unlisted_program.ts +40 -0
  170. package/dist/integrity/slopnators/sl_unnamed_island.js +1 -1
  171. package/dist/integrity/slopnators/sl_unpaired_member.js +3 -3
  172. package/dist/integrity/slopnators/sl_unpaired_member.ts +1 -1
  173. package/dist/integrity/slopnators/sl_unpaired_slopnator.js +4 -4
  174. package/dist/integrity/slopnators/sl_unpaired_slopnator.ts +1 -1
  175. package/dist/integrity/slopnators/sl_unprefixed_member.js +5 -31
  176. package/dist/integrity/slopnators/sl_unprefixed_member.ts +2 -28
  177. package/dist/integrity/slopnators/sl_unthreaded.js +11 -7
  178. package/dist/integrity/slopnators/sl_unthreaded.ts +6 -7
  179. package/dist/integrity/slopnators/sl_untranslated_key.js +2 -25
  180. package/dist/integrity/slopnators/sl_untranslated_key.ts +1 -25
  181. package/dist/integrity/slopnators/sl_unvaulted_secret.d.ts +2 -0
  182. package/dist/integrity/slopnators/sl_unvaulted_secret.js +107 -0
  183. package/dist/integrity/slopnators/sl_unvaulted_secret.ts +132 -0
  184. package/dist/integrity/slopnators/sl_unversioned.js +6 -4
  185. package/dist/integrity/slopnators/sl_unversioned.ts +5 -3
  186. package/dist/integrity/sweep.d.ts +1 -0
  187. package/dist/integrity/sweep.js +105 -42
  188. package/dist/integrity/sweep.ts +115 -42
  189. package/dist/knowledge/attach.js +4 -3
  190. package/dist/knowledge/attach.ts +3 -2
  191. package/dist/knowledge/generators/docsgen.js +8 -6
  192. package/dist/knowledge/generators/docsgen.ts +4 -2
  193. package/dist/knowledge/generators/glossary.js +4 -4
  194. package/dist/knowledge/generators/glossary.ts +1 -1
  195. package/dist/operations/access.d.ts +23 -0
  196. package/dist/operations/access.js +28 -1
  197. package/dist/operations/access.ts +43 -0
  198. package/dist/operations/attach.js +33 -113
  199. package/dist/operations/attach.ts +51 -117
  200. package/dist/operations/capabilities.d.ts +14 -5
  201. package/dist/operations/capabilities.js +13 -4
  202. package/dist/operations/capabilities.ts +27 -8
  203. package/dist/operations/dispatch.d.ts +8 -2
  204. package/dist/operations/dispatch.js +128 -185
  205. package/dist/operations/dispatch.ts +138 -191
  206. package/dist/operations/error-results.d.ts +1 -1
  207. package/dist/operations/error-results.js +2 -2
  208. package/dist/operations/error-results.ts +2 -2
  209. package/dist/operations/generators/capability.d.ts +11 -1
  210. package/dist/operations/generators/capability.js +481 -224
  211. package/dist/operations/generators/capability.ts +562 -233
  212. package/dist/operations/generators/compile.js +66 -39
  213. package/dist/operations/generators/compile.ts +78 -39
  214. package/dist/operations/generators/permits.js +11 -12
  215. package/dist/operations/generators/permits.ts +3 -4
  216. package/dist/operations/generators/seed.d.ts +1 -0
  217. package/dist/operations/generators/seed.js +19 -17
  218. package/dist/operations/generators/seed.ts +22 -14
  219. package/dist/operations/generators/trial.d.ts +6 -8
  220. package/dist/operations/generators/trial.js +200 -70
  221. package/dist/operations/generators/trial.ts +230 -93
  222. package/dist/operations/nodes.d.ts +15 -16
  223. package/dist/operations/nodes.ts +16 -17
  224. package/dist/operations/operations.d.ts +40 -4
  225. package/dist/operations/operations.js +1 -0
  226. package/dist/operations/operations.ts +61 -4
  227. package/dist/operations/result.d.ts +2 -2
  228. package/dist/operations/result.ts +2 -2
  229. package/package.json +1 -4
  230. package/dist/core/answers.d.ts +0 -171
  231. package/dist/core/answers.js +0 -789
  232. package/dist/core/answers.ts +0 -999
  233. package/dist/core/client.d.ts +0 -63
  234. package/dist/core/client.js +0 -249
  235. package/dist/core/client.ts +0 -289
  236. package/dist/core/files.js +0 -171
  237. package/dist/core/files.ts +0 -222
  238. package/dist/integrations/module.d.ts +0 -6
  239. package/dist/integrations/module.js +0 -153
  240. package/dist/integrations/module.ts +0 -191
  241. package/dist/integrity/slopnators/sl_unkept_rows.js +0 -104
  242. package/dist/integrity/slopnators/sl_unkept_rows.ts +0 -111
  243. package/dist/integrity/slopnators/sl_unseamed_reach.js +0 -73
  244. package/dist/integrity/slopnators/sl_unseamed_reach.ts +0 -79
  245. package/dist/operations/cost.d.ts +0 -14
  246. package/dist/operations/cost.js +0 -37
  247. package/dist/operations/cost.ts +0 -58
  248. package/dist/operations/errors/errors.d.ts +0 -52
  249. package/dist/operations/http.js +0 -124
  250. package/dist/operations/http.ts +0 -169
  251. package/dist/operations/memory.d.ts +0 -104
  252. package/dist/operations/memory.js +0 -365
  253. package/dist/operations/memory.ts +0 -470
  254. package/dist/operations/metering.d.ts +0 -55
  255. package/dist/operations/metering.js +0 -247
  256. package/dist/operations/metering.ts +0 -328
  257. package/dist/operations/queue-policy.d.ts +0 -3
  258. package/dist/operations/queue-policy.js +0 -8
  259. package/dist/operations/queue-policy.ts +0 -10
  260. package/dist/operations/seams.d.ts +0 -239
  261. package/dist/operations/seams.js +0 -45
  262. package/dist/operations/seams.ts +0 -364
  263. package/dist/operations/store.d.ts +0 -14
  264. package/dist/operations/store.js +0 -1
  265. package/dist/operations/store.ts +0 -29
  266. /package/dist/{operations → core}/errors/classes.d.ts +0 -0
  267. /package/dist/{operations → core}/errors/classes.js +0 -0
  268. /package/dist/{operations → core}/errors/classes.ts +0 -0
  269. /package/dist/integrity/slopnators/{sl_unkept_rows.d.ts → sl_door_in_a_node.d.ts} +0 -0
  270. /package/dist/integrity/slopnators/{sl_unseamed_reach.d.ts → sl_outside_an_operation.d.ts} +0 -0
@@ -1,52 +1,112 @@
1
- import { SECRECY, secrecyOf } from "./secret.js";
1
+ import { join } from 'node:path';
2
+ import { execPath } from 'node:process';
3
+ import { SECRECY, secrecyOf } from './secret.js';
2
4
  export const REACH = {
3
5
  postgres: 'pg_',
4
6
  pglite: 'pl_',
5
7
  browser: 'zu_',
6
8
  https: 'ht_',
7
- module: 'mod_',
8
9
  cli: 'cli_',
10
+ disk: 'dsk_',
11
+ sdk: 'sdk_',
12
+ };
13
+ export const ADDRESS = {
14
+ row: 'reached at the address written on its row, which anybody may read',
15
+ secret: 'reached at a secret, because its address is a connection string and a connection string carries a password',
16
+ nothing: 'addressed by nothing',
9
17
  };
10
18
  export const HOLDS = {
11
- postgres: { takes: 'entities', from: 'server', addressed: true, arrives: null, migrations: true, references: true, sql: true, driver: 'postgres' },
12
- pglite: { takes: 'entities', from: 'either', addressed: true, arrives: null, migrations: true, references: true, sql: true, driver: '@electric-sql/pglite' },
13
- browser: { takes: 'entities', from: 'browser', addressed: false, arrives: null, migrations: false, references: false, sql: false, driver: 'zustand' },
14
- https: { takes: 'calls', from: 'either', addressed: true, arrives: null, migrations: false, references: false, sql: false, driver: null },
15
- module: { takes: 'names', from: 'either', addressed: false, arrives: 'npm', migrations: false, references: false, sql: false, driver: null },
16
- cli: { takes: 'names', from: 'server', addressed: false, arrives: 'machine', migrations: false, references: false, sql: false, driver: null },
19
+ postgres: { takes: 'entities', from: 'server', addressed: 'secret', migrations: true, references: true, sql: true, driver: 'postgres' },
20
+ pglite: { takes: 'entities', from: 'either', addressed: 'nothing', migrations: true, references: true, sql: true, driver: '@electric-sql/pglite' },
21
+ browser: { takes: 'entities', from: 'browser', addressed: 'nothing', migrations: false, references: false, sql: false, driver: 'zustand' },
22
+ https: { takes: 'calls', from: 'either', addressed: 'row', migrations: false, references: false, sql: false, driver: null },
23
+ cli: { takes: 'calls', from: 'server', addressed: 'nothing', migrations: false, references: false, sql: false, driver: null },
24
+ disk: { takes: null, from: 'server', addressed: 'nothing', migrations: false, references: false, sql: false, driver: null },
25
+ sdk: { takes: 'calls', from: 'server', addressed: 'nothing', migrations: false, references: false, sql: false, driver: null },
17
26
  };
18
27
  export const SAID = {
19
28
  postgres: 'A postgres this app connects to over the network. It keeps entities and holds everything a declaration can state about their shape — tables, references and invariants — so what is kept here is held to that shape by the database itself rather than by whatever remembered to check. Who may touch a row is not asked of it: that is answered by the app, against the caller who actually arrived. It is reached from a server only: a connection to it from a page is a database somebody else can open. This is where a thing goes when losing it would matter.',
20
- pglite: 'A postgres running inside the process that opened it. It keeps entities and holds tables, references and invariants, exactly as the networked one does — what differs is who can reach it, not what it can be told to hold. What belongs here is what the caller is already entitled to see: a local copy, a working set, an offline cache.',
29
+ pglite: 'A postgres running inside the process that opened it. It keeps entities and holds tables, references and invariants, exactly as the networked one does — what differs is who can reach it, not what it can be told to hold. It is addressed by nothing: its files sit under .thread beside the tree, in a folder named after the target, so nobody types a path and a fresh clone starts it empty. What belongs here is what the caller is already entitled to see: a local copy, a working set, an offline cache.',
21
30
  browser: 'A store in the browser, held in memory the viewer owns. It keeps entities and it is addressed by nothing, because it is already where the code runs. It holds no migration, because a page load builds it from nothing every time. What belongs here is what the interface needs to be responsive and can afford to lose.',
22
- https: 'Something this app calls over https — a vendor, a service, another app. It accepts calls rather than entities: each is declared with the verb and the path it takes, so a node names the call and never writes a url. Its address and its credential are both secrets, and whether it may be reached from a browser is decided by which kind of secret it needs rather than by the reach itself.',
23
- module: 'Something this app brings in from outside the repository and calls — an npm package, an SDK, an installer. Declaring one installs it and reads the methods it publishes, then asks which of them this app may call. What is picked is written down, and a method that is not on that list is refused before the package is imported: what can ever run is fixed when the target is declared, not by whoever calls it. A credential is named only if it needs one, and it comes from the vault at the moment of the call and is never written anywhere. A package you only import is a dependency rather than one of these, and the manifest already declares it.',
24
- cli: 'A program this app runs as a command — git is the one that made this necessary. It is not installed, because it is not a dependency: it is either on the machine or it is not, and declaring one checks that it is there and says what to do when it is not. What it accepts is its subcommands, read off the program itself at the moment it is declared and written down: the whole surface the tool really has, because it was asked rather than typed, and a subcommand that is not on that list never runs. Declaring one is what brings `thread run <name>` into being, so the CLI grows a command by the app stating an integration rather than by anybody writing a verb — and an app that has not declared it has no such command at all.',
31
+ https: 'Something this app calls over https — a vendor, a service, another app. It accepts calls rather than entities: each is declared with the verb and the path it takes, so a node names the call and never writes a url. Where it is goes on its row as address, and a header every call carries goes on its row as headers, because both are facts anybody may read; a credential it sends is a secret, and requiring one is what keeps the target out of a browser.',
32
+ cli: 'A program this app runs as a command. git is the one that made this necessary. It is not installed, because it is not a dependency: it is on the machine or it is not, and a run finds out. What it accepts is the words it is asked with, declared beside it as calls with thread create target call: a subcommand where the program has them, and the option that selects what it does where it has none, each spelled the way the program spells it. A word that is not declared never runs. The program is the one the target is named after, so declaring one runs nothing and reads nothing off the machine. An operation that requires it is handed one function per declared word, and that is the only way this app ever runs it.',
33
+ disk: 'The disk this app runs on. It answers a fixed set of orders — is this there, read it, write it, list what is beside it, how big it is, remove it, and what it really is — and those orders are the same for every disk, because they are what a filesystem does rather than what any one of them chose to offer. None of them runs anything: a disk holds files and a program that installs packages is not a file order, which is why installing what a tree depends on happens where somebody typed the command and is not something a disk can be asked for. It is reached from a server only: a page has no filesystem. A trial stands one of these up out of its own scenario, so a rule can be measured against files that exist for the length of that run and nothing is written where you work.',
34
+ sdk: 'A package this app calls inside its own process — a vendor\'s SDK, fetched from npm, a git link or a tarball. It accepts calls rather than entities: the file this target declares exports `calls`, each call names the function there it runs as its path, and that file is the only place the package is imported, so an operation names the call and never the package. The integration it is part of names what to fetch in needs, and declaring the integration fetches it. It runs where the app runs, so it is addressed by nothing and reached from a server only.',
35
+ };
36
+ const on = (host, names) => names.map((one) => host + '.' + one);
37
+ const driverOfReach = (one) => {
38
+ const driver = HOLDS[one].driver;
39
+ return driver === null ? [] : ['import ' + driver];
40
+ };
41
+ export const OPENS = {
42
+ postgres: driverOfReach('postgres'),
43
+ pglite: driverOfReach('pglite'),
44
+ browser: driverOfReach('browser'),
45
+ https: [
46
+ 'fetch',
47
+ 'XMLHttpRequest',
48
+ 'WebSocket',
49
+ 'EventSource',
50
+ ...on('window', ['fetch']),
51
+ ...on('navigator', ['sendBeacon']),
52
+ 'import node:http',
53
+ 'import node:https',
54
+ 'import node:http2',
55
+ 'import node:net',
56
+ 'import node:tls',
57
+ 'import node:dgram',
58
+ 'import node:dns',
59
+ ],
60
+ cli: ['import node:child_process', 'import node:worker_threads', 'import node:cluster'],
61
+ disk: ['import node:fs', 'import node:fs/promises'],
62
+ sdk: [],
63
+ };
64
+ export const ORDERS = {
65
+ kind: 'kind',
66
+ read: 'read',
67
+ write: 'written',
68
+ list: 'list',
69
+ stat: 'stat',
70
+ remove: 'removed',
71
+ real: 'real',
72
+ fetch: 'fetched',
73
+ run: 'ran',
25
74
  };
75
+ export function isRow(v) {
76
+ return typeof v === 'object' && v !== null && typeof v.id === 'string';
77
+ }
78
+ export function isTransactional(store) {
79
+ return typeof store.transaction === 'function';
80
+ }
26
81
  export const CALL_PREFIX = 'cl_';
27
82
  const FILLED = /\{([a-z][a-z0-9_]*)\}/g;
28
83
  export const fills = (one) => [...one.path.matchAll(FILLED)].map((each) => each[1] ?? '');
29
84
  export function reachOf(id) {
30
85
  return Object.keys(REACH).find((one) => id.startsWith(REACH[one]));
31
86
  }
87
+ export const standsHere = (one, targets) => !one.requires.some((each) => targets.some((two) => two.id === each));
32
88
  export function holdsOf(id) {
33
89
  const what = reachOf(id);
34
90
  return what === undefined ? undefined : HOLDS[what];
35
91
  }
92
+ export function requirable(targets, calls) {
93
+ const declared = new Set(calls.map((one) => one.id));
94
+ return targets.filter((one) => holdsOf(one.id)?.takes !== 'calls' || one.takes.some((each) => declared.has(each)));
95
+ }
36
96
  export function driverOf(id) {
37
97
  return holdsOf(id)?.driver ?? null;
38
98
  }
39
99
  export function addressOf(one, secrets) {
40
- if (holdsOf(one.id)?.addressed !== true)
100
+ if (holdsOf(one.id)?.addressed !== 'secret')
41
101
  return undefined;
42
102
  const held = new Map(secrets.map((each) => [each.id, each]));
43
- return one.requires.map((each) => held.get(each)).find((each) => each !== undefined && each.sends === undefined);
103
+ return one.requires.map((each) => held.get(each)).find((each) => each !== undefined && each.sends === undefined && each.signs === undefined);
44
104
  }
45
105
  export function credentialsOf(one, secrets) {
46
106
  const held = new Map(secrets.map((each) => [each.id, each]));
47
107
  return one.requires
48
108
  .map((each) => held.get(each))
49
- .filter((each) => each !== undefined && each.sends !== undefined);
109
+ .filter((each) => each !== undefined && (each.sends !== undefined || each.signs !== undefined));
50
110
  }
51
111
  export function servesBrowser(one, secrets) {
52
112
  const holds = holdsOf(one.id);
@@ -73,23 +133,41 @@ export const unreachable = (targets) => targets
73
133
  .filter((one) => reachOf(one.id) === undefined)
74
134
  .map((one) => `\`${one.id}\` wears none of the prefixes a target is reached by (${Object.values(REACH).join(', ')}), so ` +
75
135
  'nothing can tell how to reach it — and how a thing is reached decides what may be declared for it');
136
+ export const LOCKFILES = {
137
+ 'pnpm-lock.yaml': 'pnpm',
138
+ 'yarn.lock': 'yarn',
139
+ 'bun.lockb': 'bun',
140
+ 'package-lock.json': 'npm',
141
+ };
142
+ export const PACKAGER = 'packager';
143
+ const NAMED = ['git', 'thread'];
144
+ const RUNTIME = 'node';
145
+ export const managerOf = (at, there) => Object.entries(LOCKFILES).find(([lock]) => there(join(at, lock)))?.[1] ?? 'npm';
146
+ export function programOf(name, at, there) {
147
+ if (NAMED.includes(name))
148
+ return name;
149
+ if (name === RUNTIME)
150
+ return execPath;
151
+ if (name === PACKAGER)
152
+ return managerOf(at, there);
153
+ const installed = join(at, 'node_modules', '.bin', name);
154
+ return there(installed) ? installed : undefined;
155
+ }
156
+ export const unlisted = (name) => '`' + REACH.cli + name + '` names ' + name + ', and nothing lists a program by that name: it is not under node_modules/.bin, so this tree did not install it; it is not git, node or thread; and it is not `' + PACKAGER + '`, the word for whichever package manager the lockfile picks. A program the tree did not install is whatever the machine happens to have, and a target on that is a shell by another name. Add the package that provides it and declare the target again, or ask for it through a declared call on `' + REACH.cli + PACKAGER + '`';
76
157
  const SHAPED = {
77
- module: /^[A-Za-z_$][\w$]*(?:\.[A-Za-z_$][\w$]*)*$/,
78
- cli: /^[a-z][a-z0-9-]*$/,
158
+ cli: /^-{0,2}[A-Za-z][A-Za-z0-9-]*$/,
79
159
  };
80
160
  const EVERY_VALUE = new Set(['constructor', '__proto__', 'prototype']);
81
161
  export function misnamed(target, name) {
82
162
  const reach = reachOf(target);
83
- if (reach !== 'module' && reach !== 'cli')
163
+ if (reach !== 'cli')
84
164
  return undefined;
85
165
  if (EVERY_VALUE.has(name)) {
86
- return (`\`${name}\` is a step every JavaScript value has rather than something \`${target}\` offers, and walking to ` +
166
+ return (`\`${name}\` is a step every JavaScript value has rather than something \`${target}\` answers to, and walking to ` +
87
167
  'it leaves what was declared');
88
168
  }
89
169
  if (!SHAPED[reach].test(name)) {
90
- return reach === 'module'
91
- ? `\`${name}\` is not a method path — one name, or names joined by dots, e.g. \`customers.list\``
92
- : `\`${name}\` is not a subcommand — one word as the program spells it, e.g. \`commit\` or \`rev-parse\``;
170
+ return name + ' is not one word as the program spells it. Give a subcommand, e.g. commit or rev-parse, or, where the program has none, the option that selects what it does, e.g. -p';
93
171
  }
94
172
  return undefined;
95
173
  }
@@ -106,10 +184,8 @@ export function misaccepted(targets, entities, calls) {
106
184
  continue;
107
185
  if (holds.takes === 'calls' && isCall.has(named))
108
186
  continue;
109
- if (holds.takes === 'names') {
110
- found.push(`\`${one.id}\` is reached as ${String(reachOf(one.id))} and its \`takes\` names "${named}" — what an ` +
111
- 'installed package or a program responds to goes in `offers`, not here. `takes` is a demand, and the ' +
112
- 'descent requires every word on one to be coined by a row in this tree; a method name never can be');
187
+ if (holds.takes === null) {
188
+ found.push(`\`${one.id}\` takes "${named}", and a ${String(reachOf(one.id))} takes nothing: it answers the orders every ${String(reachOf(one.id))} answers, stated once on the target itself`);
113
189
  continue;
114
190
  }
115
191
  found.push(`\`${one.id}\` is reached over ${String(reachOf(one.id))} and so accepts ${holds.takes}, and its \`takes\` names ` +
@@ -118,6 +194,36 @@ export function misaccepted(targets, entities, calls) {
118
194
  }
119
195
  return found;
120
196
  }
197
+ export const placedAt = (targets, id) => targets.find((one) => one.id === id)?.address ?? '';
198
+ export function placed(one) {
199
+ const said = one.address;
200
+ if (said === undefined) {
201
+ return [one.id + ' is reached over https and its row says nothing about where. Give it an address: the absolute url every call on it is written from, scheme and host and nothing after the path'];
202
+ }
203
+ let held;
204
+ try {
205
+ held = new URL(said);
206
+ }
207
+ catch {
208
+ return [one.id + ' has the address ' + JSON.stringify(said) + ', and that is not an absolute url. Write the whole of it, scheme and host'];
209
+ }
210
+ if ([held.search, held.hash].some((each) => each !== '')) {
211
+ return [one.id + ' has the address ' + said + ', which carries a query or a fragment. Those belong to a call, so an address ends at its path'];
212
+ }
213
+ const wrong = Object.entries(one.headers ?? {}).filter(([, value]) => typeof value !== 'string');
214
+ if (wrong.length > 0) {
215
+ return [one.id + ' carries the header ' + String(wrong[0]?.[0] ?? '') + ' with a value that is not text. A header every call carries is written as text, exactly as it goes on the wire'];
216
+ }
217
+ return [];
218
+ }
219
+ const stated = (one, holds) => {
220
+ if (holds.addressed === 'row')
221
+ return placed(one);
222
+ const carried = [...(one.address === undefined ? [] : ['an address']), ...(one.headers === undefined ? [] : ['headers'])];
223
+ if (carried.length === 0)
224
+ return [];
225
+ return [one.id + ' carries ' + carried.join(' and ') + ', and a ' + String(reachOf(one.id)) + ' is ' + ADDRESS[holds.addressed] + '. Take it off the row'];
226
+ };
121
227
  export function unaddressed(targets, secrets) {
122
228
  const held = new Map(secrets.map((one) => [one.id, one]));
123
229
  const found = [];
@@ -125,13 +231,14 @@ export function unaddressed(targets, secrets) {
125
231
  const holds = holdsOf(one.id);
126
232
  if (holds === undefined)
127
233
  continue;
234
+ found.push(...stated(one, holds));
128
235
  const addresses = one.requires
129
236
  .map((each) => held.get(each))
130
- .filter((each) => each !== undefined && each.sends === undefined);
131
- if (!holds.addressed) {
132
- if (holds.arrives === null && addresses.length > 0) {
133
- found.push(`\`${one.id}\` is reached over ${String(reachOf(one.id))}, which is addressed by nothing and needs nothing to ` +
134
- `reach it, and it requires \`${addresses[0]?.id ?? ''}\` — there is nowhere for that value to go`);
237
+ .filter((each) => each !== undefined && each.sends === undefined && each.signs === undefined);
238
+ if (holds.addressed !== 'secret') {
239
+ if (addresses.length > 0) {
240
+ found.push(one.id + ' is reached over ' + String(reachOf(one.id)) + ', which is ' + ADDRESS[holds.addressed] + ', and it requires ' +
241
+ (addresses[0]?.id ?? '') + ', a secret with nowhere to be sent. A secret is a credential: give it the header it goes on with sends, or take it off this row');
135
242
  }
136
243
  continue;
137
244
  }
@@ -148,14 +255,15 @@ export function unaddressed(targets, secrets) {
148
255
  return found;
149
256
  }
150
257
  export function unheld(targets, secrets) {
151
- const known = new Set(secrets.map((one) => one.id));
258
+ const known = new Set([...secrets.map((one) => one.id), ...targets.map((one) => one.id)]);
152
259
  const found = [];
153
260
  for (const one of targets) {
154
261
  for (const named of one.requires) {
155
262
  if (known.has(named))
156
263
  continue;
157
- found.push(`\`${one.id}\` requires "${named}", and this app declares no secret by that name. A secret is declared before it ` +
158
- 'is required, so the one place saying who may hold a value is never whichever place happened to need it');
264
+ found.push(`\`${one.id}\` requires "${named}", and this app declares no secret and no target by that name. A secret is declared before it ` +
265
+ 'is required, and a target before it is reached through, so the one place saying who holds a value, or ' +
266
+ 'answers for a reach, is never whichever place happened to need it');
159
267
  }
160
268
  }
161
269
  return found;
@@ -171,8 +279,22 @@ export function unanswered(calls, targets) {
171
279
  }
172
280
  const holds = holdsOf(of.id);
173
281
  if (holds !== undefined && holds.takes !== 'calls') {
174
- found.push(`\`${one.id}\` is a call on \`${of.id}\`, which is reached over ${String(reachOf(of.id))} and keeps entities. ` +
175
- 'A place you keep rows in is not a place you issue verbs at');
282
+ found.push(holds.takes === 'entities'
283
+ ? `\`${one.id}\` is a call on \`${of.id}\`, which is reached over ${String(reachOf(of.id))} and keeps entities. A place you keep rows in is not a place you issue verbs at`
284
+ : `\`${one.id}\` is a call on \`${of.id}\`, which is a ${String(reachOf(of.id))} and answers the orders every ${String(reachOf(of.id))} answers, so nothing is declared on it. A node is handed those orders by requiring it`);
285
+ continue;
286
+ }
287
+ if (reachOf(of.id) === 'https' && one.method === undefined) {
288
+ found.push(`\`${one.id}\` is a call over https and states no method. A call over https says its verb: GET, POST, PUT, PATCH or DELETE`);
289
+ continue;
290
+ }
291
+ if (reachOf(of.id) !== 'https' && one.method !== undefined) {
292
+ found.push(`\`${one.id}\` states the method ${one.method}, and \`${of.id}\` is a ${String(reachOf(of.id))}. A subcommand or a method has no http verb, so take \`method\` off that row`);
293
+ continue;
294
+ }
295
+ const shaped = misnamed(of.id, one.path);
296
+ if (shaped !== undefined) {
297
+ found.push(`\`${one.id}\` is a call on \`${of.id}\`, and its path ${shaped}`);
176
298
  continue;
177
299
  }
178
300
  if (!of.takes.includes(one.id)) {
@@ -182,33 +304,32 @@ export function unanswered(calls, targets) {
182
304
  }
183
305
  return found;
184
306
  }
185
- export function misused(targets) {
307
+ export function unplaced(targets, integrations) {
308
+ const known = new Set(integrations.map((one) => one.id));
186
309
  const found = [];
187
310
  for (const one of targets) {
188
- const holds = holdsOf(one.id);
189
- if (holds === undefined)
311
+ const named = one.of ?? '';
312
+ if (named === '') {
313
+ found.push(`\`${one.id}\` names no integration, and every target is one way into something outside this app — a vendor, ` +
314
+ 'a service, a program on the machine. Say which one it reaches into: `thread create integration` lists ' +
315
+ 'the ones already declared and declares another');
190
316
  continue;
191
- if (holds.arrives !== null && (one.uses ?? '') === '') {
192
- found.push(`\`${one.id}\` is reached as ${String(reachOf(one.id))} and does not say what it uses — ` +
193
- `${holds.arrives === 'npm' ? 'the npm package to install' : 'the program to run'} goes in \`uses\`, because the ` +
194
- 'id is what this app calls it and not what it is');
195
- continue;
196
- }
197
- if (holds.arrives === null && one.uses !== undefined) {
198
- found.push(`\`${one.id}\` is reached over ${String(reachOf(one.id))}, where nothing is installed and nothing is spawned, ` +
199
- `and it states \`uses: '${one.uses}'\` — there is nothing for that name to be`);
200
317
  }
318
+ if (known.has(named))
319
+ continue;
320
+ found.push(`\`${one.id}\` is part of "${named}", and this app declares no integration by that name. Declare it with ` +
321
+ '`thread create integration`, or point this row at one already declared');
201
322
  }
202
323
  return found;
203
324
  }
204
- export function refusals(targets, secrets, calls, entities) {
325
+ export function refusals(targets, secrets, calls, entities, integrations) {
205
326
  return [
206
327
  ...unreachable(targets),
328
+ ...unplaced(targets, integrations),
207
329
  ...unheld(targets, secrets),
208
330
  ...unaddressed(targets, secrets),
209
331
  ...unanswered(calls, targets),
210
332
  ...misaccepted(targets, entities, calls),
211
- ...misused(targets),
212
333
  ];
213
334
  }
214
335
  export function targetOf(entity, targets) {