@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
@@ -0,0 +1,465 @@
1
+ import * as disk from 'node:fs'
2
+ import { basename, dirname, isAbsolute, relative, resolve } from 'node:path'
3
+ import { env, pid } from 'node:process'
4
+
5
+ import { ORDERS, type Answer, type Attached, type Answering, type Kind, type Listed, type Measured, type Order, type Ran } from '../integrations/target.ts'
6
+
7
+ export type { Answering, Kind, Listed, Measured, Ran } from '../integrations/target.ts'
8
+
9
+ export const CHANNEL = 'THREAD_CHANNEL'
10
+
11
+ export const FOLDER = 'THREAD_FOLDER'
12
+
13
+ const WAITING = 180_000
14
+
15
+ const WORKING = 600_000
16
+
17
+ const ASKING = '-asking'
18
+
19
+ const ORDER = '-order'
20
+
21
+ const ANSWER = '-answer'
22
+
23
+ function overFiles(dir: string): Attached {
24
+ const idle = new Int32Array(new SharedArrayBuffer(4))
25
+ let spun = 0
26
+
27
+ const ask = (body: Order): Answer => {
28
+ spun += 1
29
+ const name = dir + '/' + String(pid) + '-' + String(spun)
30
+ const long = body.order === 'fetch' ? true : body.order === 'run'
31
+ const waits = long ? WORKING : WAITING
32
+ disk.writeFileSync(name + ASKING, JSON.stringify(body))
33
+ disk.renameSync(name + ASKING, name + ORDER)
34
+ const until = Date.now() + waits
35
+ for (;;) {
36
+ let held = ''
37
+ try {
38
+ held = disk.readFileSync(name + ANSWER, 'utf8')
39
+ } catch {
40
+ held = ''
41
+ }
42
+ if (held !== '') {
43
+ disk.rmSync(name + ANSWER, { force: true })
44
+ const said = JSON.parse(held) as Answer
45
+ if (said.answered === 'refused') throw new Error(String(said.because))
46
+ return said
47
+ }
48
+ if (Date.now() > until) {
49
+ throw new Error(
50
+ 'nothing answered ' + body.order + ' ' + body.at + ' for ' + String(Math.round(waits / 60_000)) +
51
+ ' minutes, so this stopped waiting rather than spinning forever. Whoever was answering is gone. ' +
52
+ 'Nothing here is half-written: one order is one file, and it was either answered or it was not.',
53
+ )
54
+ }
55
+ Atomics.wait(idle, 0, 0, 2)
56
+ }
57
+ }
58
+
59
+ const took = (body: Order): Answer => {
60
+ const said = ask(body)
61
+ const want = ORDERS[body.order]
62
+ if (said.answered !== want) {
63
+ throw new Error(
64
+ body.order + ' ' + body.at + ' was answered as ' + said.answered + ', and that order is answered as ' + want +
65
+ '. Whatever answered is not the copy of prestack this server sends orders to.',
66
+ )
67
+ }
68
+ return said
69
+ }
70
+
71
+ const kinds = new Map<string, Kind>()
72
+ const listed = new Map<string, readonly Listed[]>()
73
+ const reals = new Map<string, string>()
74
+
75
+ const listing = (at: string): readonly Listed[] => {
76
+ const held = listed.get(at)
77
+ if (held !== undefined) return held
78
+ const found = took({ order: 'list', at }).found as readonly Listed[]
79
+ listed.set(at, found)
80
+ return found
81
+ }
82
+
83
+ const kindOf = (at: string): Kind => {
84
+ const held = kinds.get(at)
85
+ if (held !== undefined) return held
86
+ const up = dirname(at)
87
+ if (up !== at && across(up)) {
88
+ const one = kindOf(up) === 'folder' ? listing(up).find((each) => each.name === basename(at)) : undefined
89
+ if (one === undefined) {
90
+ kinds.set(at, 'none')
91
+ return 'none'
92
+ }
93
+ if (one.kind !== 'other') {
94
+ kinds.set(at, one.kind)
95
+ return one.kind
96
+ }
97
+ }
98
+ const found = took({ order: 'kind', at }).found as Kind
99
+ kinds.set(at, found)
100
+ return found
101
+ }
102
+
103
+ const wrote = (at: string): void => {
104
+ kinds.set(at, 'file')
105
+ for (let child = at, up = dirname(at); up !== child && across(up); child = up, up = dirname(up)) {
106
+ const inside = listed.get(up)
107
+ if (inside !== undefined && !inside.some((each) => each.name === basename(child))) {
108
+ listed.set(up, [...inside, { name: basename(child), kind: child === at ? 'file' : 'folder' }])
109
+ }
110
+ kinds.set(up, 'folder')
111
+ }
112
+ }
113
+
114
+ const removed = (at: string): void => {
115
+ for (const key of [...kinds.keys()]) if (key.startsWith(at + '/')) kinds.delete(key)
116
+ for (const key of [...listed.keys()]) if (key === at || key.startsWith(at + '/')) listed.delete(key)
117
+ reals.clear()
118
+ kinds.set(at, 'none')
119
+ const inside = listed.get(dirname(at))
120
+ if (inside !== undefined) listed.set(dirname(at), inside.filter((each) => each.name !== basename(at)))
121
+ }
122
+
123
+ const unknown = (): void => {
124
+ kinds.clear()
125
+ listed.clear()
126
+ reals.clear()
127
+ }
128
+
129
+ return {
130
+ kind: kindOf,
131
+ read: (at) => String(took({ order: 'read', at }).said),
132
+ write: (at, said, mode) => {
133
+ took(mode === undefined ? { order: 'write', at, said } : { order: 'write', at, said, mode })
134
+ wrote(at)
135
+ },
136
+ list: listing,
137
+ stat: (at) => took({ order: 'stat', at }).found as Measured,
138
+ remove: (at) => {
139
+ took({ order: 'remove', at })
140
+ removed(at)
141
+ },
142
+ real: (at) => {
143
+ const held = reals.get(at)
144
+ if (held !== undefined) return held
145
+ const found = String(took({ order: 'real', at }).at)
146
+ reals.set(at, found)
147
+ return found
148
+ },
149
+ fetch: (at) => {
150
+ try {
151
+ return String(took({ order: 'fetch', at }).said)
152
+ } finally {
153
+ unknown()
154
+ }
155
+ },
156
+ run: (at, words) => {
157
+ try {
158
+ return took({ order: 'run', at, words }).found as Ran
159
+ } finally {
160
+ unknown()
161
+ }
162
+ },
163
+ }
164
+ }
165
+
166
+ const seam: { held?: Attached } = {}
167
+
168
+ const WHERE = env[CHANNEL]
169
+
170
+ if (WHERE !== undefined && WHERE !== '') seam.held = overFiles(WHERE)
171
+
172
+ export function answeredBy(one?: Attached): void {
173
+ seam.held = one
174
+ }
175
+
176
+ const placed = (at: string): string => {
177
+ const root = env[FOLDER] ?? ''
178
+ return root === '' ? at : resolve(root, at)
179
+ }
180
+
181
+ const within = (root: string, at: string): boolean => {
182
+ const step = relative(resolve(root), resolve(root, at))
183
+ return step === '' || (!step.startsWith('..') && !isAbsolute(step))
184
+ }
185
+
186
+ export function across(at: string): boolean {
187
+ const root = env[FOLDER] ?? ''
188
+ return seam.held !== undefined && root !== '' && within(root, at)
189
+ }
190
+
191
+ export function beyond(at: string): boolean {
192
+ const root = env[FOLDER] ?? ''
193
+ return seam.held !== undefined && root !== '' && !within(root, at)
194
+ }
195
+
196
+ function asked(at: unknown): Attached | undefined {
197
+ const one = seam.held
198
+ if (one === undefined) return undefined
199
+ const root = env[FOLDER] ?? ''
200
+ if (root === '') return typeof at === 'string' ? one : undefined
201
+ if (typeof at !== 'string') {
202
+ throw new Error('a path given as anything but text cannot be held to ' + root + ', the folder this answers for, so it was not used.')
203
+ }
204
+ if (within(root, at)) return one
205
+ throw new Error(
206
+ at + ' is outside ' + root + ', the folder this answers for. A command answering for a folder on another machine ' +
207
+ 'reaches that folder and nothing else, so nothing was read, written or removed.',
208
+ )
209
+ }
210
+
211
+ export function attached(): boolean {
212
+ return seam.held !== undefined
213
+ }
214
+
215
+ export function here(): Attached {
216
+ return seam.held ?? HERE
217
+ }
218
+
219
+ export function kind(at: string): Kind {
220
+ const one = asked(at)
221
+ return one === undefined ? HERE.kind(at) : one.kind(placed(at))
222
+ }
223
+
224
+ export function existsSync(at: disk.PathLike): boolean {
225
+ return typeof at === 'string' ? kind(at) !== 'none' : asked(at) === undefined && disk.existsSync(at)
226
+ }
227
+
228
+ export function readFileSync(at: disk.PathOrFileDescriptor, how?: BufferEncoding): string {
229
+ const one = asked(at)
230
+ return one === undefined ? disk.readFileSync(at, how ?? 'utf8') : one.read(placed(at as string))
231
+ }
232
+
233
+ export function writeFileSync(
234
+ at: disk.PathOrFileDescriptor,
235
+ said: string,
236
+ how?: BufferEncoding | { readonly encoding?: BufferEncoding; readonly mode?: number },
237
+ ): void {
238
+ const held = how === undefined || typeof how === 'string' ? { encoding: how, mode: undefined } : how
239
+ const one = asked(at)
240
+ if (one !== undefined) {
241
+ one.write(placed(at as string), said, held.mode)
242
+ return
243
+ }
244
+ if (typeof at === 'string') disk.mkdirSync(dirname(at), { recursive: true })
245
+ disk.writeFileSync(at, said, { encoding: held.encoding ?? 'utf8', ...(held.mode === undefined ? {} : { mode: held.mode }) })
246
+ }
247
+
248
+ export function createFileSync(at: string, said: string): boolean {
249
+ if (asked(at) !== undefined) {
250
+ throw new Error(at + ' is on a machine that answers orders, and only a file on this machine can be created for one command alone.')
251
+ }
252
+ disk.mkdirSync(dirname(at), { recursive: true })
253
+ try {
254
+ disk.writeFileSync(at, said, { encoding: 'utf8', flag: 'wx' })
255
+ return true
256
+ } catch (thrown) {
257
+ if ((thrown as NodeJS.ErrnoException).code === 'EEXIST') return false
258
+ throw thrown
259
+ }
260
+ }
261
+
262
+ export interface Named {
263
+ readonly name: string
264
+ readonly isFile: () => boolean
265
+ readonly isDirectory: () => boolean
266
+ }
267
+
268
+ export function readdirSync(at: disk.PathLike): string[]
269
+ export function readdirSync(at: disk.PathLike, how: { readonly withFileTypes: true }): readonly Named[]
270
+ export function readdirSync(at: disk.PathLike, how?: { readonly withFileTypes: true }): string[] | readonly Named[] {
271
+ const one = asked(at)
272
+ if (one === undefined) return how === undefined ? disk.readdirSync(at) : disk.readdirSync(at, how)
273
+ const held = one.list(placed(at as string))
274
+ return how === undefined
275
+ ? held.map((each) => each.name)
276
+ : held.map((each) => ({ name: each.name, isFile: () => each.kind === 'file', isDirectory: () => each.kind === 'folder' }))
277
+ }
278
+
279
+ export interface Held extends Named, Measured {
280
+ readonly mtimeMs: number
281
+ }
282
+
283
+ export function statSync(at: disk.PathLike): Held
284
+ export function statSync(at: disk.PathLike, how: { readonly throwIfNoEntry: false }): Held | undefined
285
+ export function statSync(at: disk.PathLike, how?: { readonly throwIfNoEntry: false }): Held | undefined {
286
+ const one = asked(at)
287
+ if (one === undefined) return (how === undefined ? disk.statSync(at) : disk.statSync(at, how)) as Held | undefined
288
+ const path = placed(at as string)
289
+ const held = one.kind(path)
290
+ if (held === 'none') {
291
+ if (how !== undefined) return undefined
292
+ throw new Error(`${path} is not there, so nothing can be said about it.`)
293
+ }
294
+ const measured = one.stat(path)
295
+ return {
296
+ name: path,
297
+ size: measured.size,
298
+ modified: measured.modified,
299
+ mtimeMs: measured.modified,
300
+ isFile: () => held === 'file',
301
+ isDirectory: () => held === 'folder',
302
+ }
303
+ }
304
+
305
+ export function rmSync(at: disk.PathLike, how?: disk.RmOptions): void {
306
+ const one = asked(at)
307
+ if (one === undefined) disk.rmSync(at, how)
308
+ else one.remove(placed(at as string))
309
+ }
310
+
311
+ export function rmdirSync(at: disk.PathLike): void {
312
+ const one = asked(at)
313
+ if (one === undefined) disk.rmdirSync(at)
314
+ else one.remove(placed(at as string))
315
+ }
316
+
317
+ export function renameSync(from: disk.PathLike, to: disk.PathLike): void {
318
+ const one = asked(from)
319
+ if (one === undefined) {
320
+ if (typeof to === 'string') disk.mkdirSync(dirname(to), { recursive: true })
321
+ disk.renameSync(from, to)
322
+ return
323
+ }
324
+ asked(to)
325
+ one.write(placed(to as string), one.read(placed(from as string)))
326
+ one.remove(placed(from as string))
327
+ }
328
+
329
+ export function appendFileSync(at: disk.PathOrFileDescriptor, said: string): void {
330
+ const one = asked(at)
331
+ if (one === undefined) {
332
+ disk.appendFileSync(at, said)
333
+ return
334
+ }
335
+ const path = placed(at as string)
336
+ one.write(path, `${one.kind(path) === 'none' ? '' : one.read(path)}${said}`)
337
+ }
338
+
339
+ export function realpathSync(at: disk.PathLike): string {
340
+ const one = asked(at)
341
+ return one === undefined ? disk.realpathSync(at as string) : one.real(placed(at as string))
342
+ }
343
+
344
+ const FILES_ONLY = ' is on this disk, and a disk holds files. '
345
+
346
+ export const HERE: Attached = {
347
+ kind: (at) => {
348
+ let held: disk.Stats | undefined
349
+ try {
350
+ held = disk.statSync(at, { throwIfNoEntry: false })
351
+ } catch (thrown) {
352
+ if ((thrown as NodeJS.ErrnoException).code === 'ERR_ACCESS_DENIED') return 'none'
353
+ throw thrown
354
+ }
355
+ if (held === undefined) return 'none'
356
+ return held.isFile() ? 'file' : held.isDirectory() ? 'folder' : 'other'
357
+ },
358
+ read: (at) => disk.readFileSync(at, 'utf8'),
359
+ write: (at, said, mode) => {
360
+ disk.mkdirSync(dirname(at), { recursive: true })
361
+ disk.writeFileSync(at, said, { encoding: 'utf8', ...(mode === undefined ? {} : { mode }) })
362
+ },
363
+ list: (at) =>
364
+ disk.readdirSync(at, { withFileTypes: true }).map((one) => ({
365
+ name: one.name,
366
+ kind: one.isFile() ? 'file' : one.isDirectory() ? 'folder' : 'other',
367
+ })),
368
+ stat: (at) => {
369
+ const held = disk.statSync(at)
370
+ return { size: held.size, modified: held.mtimeMs }
371
+ },
372
+ remove: (at) => {
373
+ if (disk.lstatSync(at, { throwIfNoEntry: false })?.isDirectory() === true) disk.rmdirSync(at)
374
+ else disk.rmSync(at)
375
+ },
376
+ real: (at) => disk.realpathSync(at),
377
+ fetch: (at) => {
378
+ throw new Error(at + FILES_ONLY + 'Installing what a tree depends on happens where somebody typed the command, so it cannot be ordered of this disk.')
379
+ },
380
+ run: (at) => {
381
+ throw new Error(at + FILES_ONLY + 'A program is started where somebody typed the command, so running one cannot be ordered of this disk.')
382
+ },
383
+ }
384
+
385
+ const GONE = 'is not in the scenario this trial stands, and while it runs the scenario is the whole tree.'
386
+
387
+ const MADE_UP = 'a trial answers orders against a tree it made up, so there is nowhere here to '
388
+
389
+ export function standing(root: string, given: ReadonlyMap<string, string>): Attached {
390
+ const flat = (at: string): string => {
391
+ let path = at
392
+ while (path.length > 1 && path.endsWith('/')) path = path.slice(0, -1)
393
+ return path
394
+ }
395
+ const under = (at: string): boolean => at.startsWith(root) || `${at}/` === root
396
+ const own = (at: string): boolean => under(at) && !at.slice(root.length).split('/').includes('node_modules')
397
+ const beside = (at: string): readonly Listed[] => {
398
+ try {
399
+ return HERE.list(at)
400
+ } catch {
401
+ return []
402
+ }
403
+ }
404
+
405
+ const held = new Map<string, string>(given)
406
+ const folders = new Set<string>()
407
+ const parents = (at: string): void => {
408
+ for (let up = dirname(at); under(`${up}/`); up = dirname(up)) folders.add(up)
409
+ }
410
+ for (const at of held.keys()) parents(at)
411
+
412
+ const answers: Answering = {
413
+ kind: (at) => (held.has(at) ? 'file' : folders.has(at) ? 'folder' : own(at) ? 'none' : HERE.kind(at)),
414
+ read: (at) => {
415
+ const said = held.get(at)
416
+ if (said !== undefined) return said
417
+ if (own(at)) throw new Error(`${at} ${GONE}`)
418
+ return HERE.read(at)
419
+ },
420
+ write: (at, said) => {
421
+ held.set(at, said)
422
+ parents(at)
423
+ },
424
+ list: (at) => {
425
+ const inside = new Map<string, Listed>()
426
+ const found = own(at) ? [] : folders.has(at) ? beside(at) : HERE.list(at)
427
+ for (const one of found) inside.set(one.name, { name: one.name, kind: one.kind === 'folder' ? 'folder' : 'file' })
428
+ for (const path of folders) if (dirname(path) === at) inside.set(basename(path), { name: basename(path), kind: 'folder' })
429
+ for (const path of held.keys()) if (dirname(path) === at) inside.set(basename(path), { name: basename(path), kind: 'file' })
430
+ return [...inside.values()]
431
+ },
432
+ stat: (at) => {
433
+ const said = held.get(at)
434
+ if (said !== undefined) return { size: said.length, modified: 0 }
435
+ if (folders.has(at)) return { size: 0, modified: 0 }
436
+ if (own(at)) throw new Error(`${at} ${GONE}`)
437
+ return HERE.stat(at)
438
+ },
439
+ remove: (at) => {
440
+ held.delete(at)
441
+ folders.delete(at)
442
+ },
443
+ real: (at) => (own(at) || held.has(at) || folders.has(at) ? at : HERE.real(at)),
444
+ }
445
+
446
+ return {
447
+ kind: (at) => answers.kind(flat(at)),
448
+ read: (at) => answers.read(flat(at)),
449
+ write: (at, said) => {
450
+ answers.write(flat(at), said)
451
+ },
452
+ list: (at) => answers.list(flat(at)),
453
+ stat: (at) => answers.stat(flat(at)),
454
+ remove: (at) => {
455
+ answers.remove(flat(at))
456
+ },
457
+ real: (at) => answers.real(flat(at)),
458
+ fetch: () => {
459
+ throw new Error(MADE_UP + 'install anything into.')
460
+ },
461
+ run: () => {
462
+ throw new Error(MADE_UP + 'run anything in.')
463
+ },
464
+ }
465
+ }
@@ -1,8 +1,8 @@
1
- import { stdout } from 'node:process';
2
- import { exit } from "../../core/invoked.js";
3
- import { TYPED, wordsIn } from "../../core/answers.js";
4
- import { descend } from "../../core/descend.js";
5
- const words = wordsIn([]);
1
+ import { argv, stdout } from 'node:process';
2
+ import { exit } from '../../core/invoked.js';
3
+ import { descend } from '../../core/descend.js';
4
+ import { THING as TYPED } from '../../core/scope.js';
5
+ const words = argv.slice(2).filter((one) => !one.startsWith('-'));
6
6
  const looking = words.join(' ').trim().toLowerCase();
7
7
  const pass = descend();
8
8
  const said = (one) => (one.describes ?? '').replace(/\s+/g, ' ');
@@ -14,7 +14,7 @@ const carries = (one, list, file) => {
14
14
  };
15
15
  const shown = (one, list, pad, alone = false) => {
16
16
  const marks = [
17
- ...(one.by === undefined ? [] : [`written by \`${one.by}\``]),
17
+ ...(one.by === undefined ? [] : [`${list === 'stated' ? 'answers' : 'written by'} \`${one.by}\``]),
18
18
  ...(one.runs === undefined ? [] : [`checked by \`${one.runs}\``]),
19
19
  ...((one.requires ?? []).length === 0 ? [] : [`requires ${(one.requires ?? []).join(', ')}`]),
20
20
  ...((one.takes ?? []).length === 0 ? [] : [`takes ${(one.takes ?? []).join(', ')}`]),
@@ -1,10 +1,10 @@
1
- import { stdout } from 'node:process'
1
+ import { argv, stdout } from 'node:process'
2
2
 
3
3
  import { exit } from '../../core/invoked.ts'
4
- import { TYPED, wordsIn } from '../../core/answers.ts'
5
4
  import { descend, type Row } from '../../core/descend.ts'
5
+ import { THING as TYPED } from '../../core/scope.ts'
6
6
 
7
- const words = wordsIn([])
7
+ const words = argv.slice(2).filter((one) => !one.startsWith('-'))
8
8
 
9
9
  const looking = words.join(' ').trim().toLowerCase()
10
10
 
@@ -20,7 +20,7 @@ const carries = (one: Row, list: string, file: string): boolean => {
20
20
 
21
21
  const shown = (one: Row, list: string, pad: string, alone = false): readonly string[] => {
22
22
  const marks = [
23
- ...(one.by === undefined ? [] : [`written by \`${one.by}\``]),
23
+ ...(one.by === undefined ? [] : [`${list === 'stated' ? 'answers' : 'written by'} \`${one.by}\``]),
24
24
  ...(one.runs === undefined ? [] : [`checked by \`${one.runs}\``]),
25
25
  ...((one.requires ?? []).length === 0 ? [] : [`requires ${(one.requires ?? []).join(', ')}`]),
26
26
  ...((one.takes ?? []).length === 0 ? [] : [`takes ${(one.takes ?? []).join(', ')}`]),
@@ -1,21 +1,19 @@
1
- import { existsSync, readFileSync, writeFileSync } from "../../core/files.js";
2
- import { valuesIn } from "../../core/rows.js";
1
+ import { existsSync, readFileSync, writeFileSync } from '../disk.js';
2
+ import { valuesIn } from '../../core/rows.js';
3
3
  import { dirname, join, relative } from 'node:path';
4
4
  import { argv, stderr, stdout } from 'node:process';
5
- import { fileURLToPath } from 'node:url';
6
5
  import ts from 'typescript';
7
- import { exit } from "../../core/invoked.js";
8
- import { named as packageOf } from "../../core/scope.js";
9
- import { findTree, inTree, strayFiles } from "../../core/tree.js";
10
- import { unclassified, valued } from "../secret.js";
11
- import { refusals, servesBrowser } from "../target.js";
12
- import { ALGORITHM, KEY_BYTES, KEY_NAME, SEALED_AT, SEALED_NAME, VAULT_DIR } from "../vault.js";
6
+ import { exit } from '../../core/invoked.js';
7
+ import { named as packageOf } from '../../core/scope.js';
8
+ import { findTree, inTree, strayFiles } from '../../core/tree.js';
9
+ import { unclassified, valued } from '../secret.js';
10
+ import { refusals, servesBrowser } from '../target.js';
11
+ import { ALGORITHM, KEY_BYTES, KEY_NAME, SEALED_AT, SEALED_NAME, VAULT_DIR } from '../vault.js';
13
12
  const TREE = findTree();
14
13
  const AT = 'src/vault.ts';
15
14
  const here = (one) => relative(TREE.at, one).split('\\').join('/');
16
15
  const from = inTree(TREE, 'secrets.ts');
17
16
  const path = join(TREE.at, AT);
18
- const toward = relative(dirname(path), fileURLToPath(new URL('../vault.ts', import.meta.url))).split('\\').join('/');
19
17
  const declares = relative(dirname(path), from).split('\\').join('/');
20
18
  const sheet = declares.startsWith('.') ? declares : `./${declares}`;
21
19
  function refuse(because) {
@@ -148,12 +146,13 @@ async function reaching() {
148
146
  }
149
147
  async function stated() {
150
148
  const targets = await taken('targets.ts', 'TARGETS');
149
+ const integrations = await taken('targets.ts', 'INTEGRATIONS');
151
150
  const calls = await taken('targets.ts', 'CALLS');
152
151
  const entities = (await taken('entities.ts', 'ENTITIES')).map((one) => one.id);
153
152
  return [
154
153
  ...unclassified(secrets),
155
154
  ...valued(secrets),
156
- ...refusals(targets, secrets, calls, entities),
155
+ ...refusals(targets, secrets, calls, entities, integrations),
157
156
  ...(await reaching()),
158
157
  ];
159
158
  }
@@ -1,4 +1,4 @@
1
- import { existsSync, readFileSync, writeFileSync } from '../../core/files.ts'
1
+ import { existsSync, readFileSync, writeFileSync } from '../disk.ts'
2
2
  import { valuesIn } from '../../core/rows.ts'
3
3
  import { dirname, join, relative } from 'node:path'
4
4
  import { argv, stderr, stdout } from 'node:process'
@@ -11,7 +11,7 @@ import { named as packageOf } from '../../core/scope.ts'
11
11
  import { findTree, inTree, strayFiles } from '../../core/tree.ts'
12
12
 
13
13
  import { unclassified, valued, type Secret } from '../secret.ts'
14
- import { refusals, servesBrowser, type Call, type Target } from '../target.ts'
14
+ import { refusals, servesBrowser, type Call, type Integration, type Target } from '../target.ts'
15
15
  import { ALGORITHM, KEY_BYTES, KEY_NAME, SEALED_AT, SEALED_NAME, VAULT_DIR } from '../vault.ts'
16
16
 
17
17
  const TREE = findTree()
@@ -24,8 +24,6 @@ const from = inTree(TREE, 'secrets.ts')
24
24
 
25
25
  const path = join(TREE.at, AT)
26
26
 
27
- const toward = relative(dirname(path), fileURLToPath(new URL('../vault.ts', import.meta.url))).split('\\').join('/')
28
-
29
27
  const declares = relative(dirname(path), from).split('\\').join('/')
30
28
 
31
29
  const sheet = declares.startsWith('.') ? declares : `./${declares}`
@@ -160,12 +158,13 @@ async function reaching(): Promise<readonly string[]> {
160
158
 
161
159
  async function stated(): Promise<readonly string[]> {
162
160
  const targets = await taken<Target>('targets.ts', 'TARGETS')
161
+ const integrations = await taken<Integration>('targets.ts', 'INTEGRATIONS')
163
162
  const calls = await taken<Call>('targets.ts', 'CALLS')
164
163
  const entities = (await taken<{ readonly id: string }>('entities.ts', 'ENTITIES')).map((one) => one.id)
165
164
  return [
166
165
  ...unclassified(secrets),
167
166
  ...valued(secrets),
168
- ...refusals(targets, secrets, calls, entities),
167
+ ...refusals(targets, secrets, calls, entities, integrations),
169
168
  ...(await reaching()),
170
169
  ]
171
170
  }
@@ -1,4 +1,4 @@
1
- import type { Http } from './seams.ts';
1
+ import type { Http, HttpRequest, HttpResponse } from './target.ts';
2
2
  export declare const HTTP_CALL_ACTION = "http.call";
3
3
  export declare class HttpNotConfiguredError extends Error {
4
4
  constructor();
@@ -7,12 +7,15 @@ export declare class OutwardTransportError extends Error {
7
7
  readonly target: string;
8
8
  constructor(target: string, cause: unknown);
9
9
  }
10
+ export declare const refusedPath: (path: string) => string | undefined;
10
11
  export declare function outwardUrl(target: string, address: string, path: string): URL;
11
- export interface HttpSeamOptions {
12
- readonly transport?: typeof fetch;
13
- readonly timeoutMs?: number;
12
+ export interface HttpOptions {
13
+ readonly timeout?: number;
14
14
  }
15
- export declare function httpSeam(options?: HttpSeamOptions): Http;
15
+ export declare const STREAMED = "application/x-ndjson";
16
+ export declare const TOLD = "told";
17
+ export declare function called(request: HttpRequest, options?: HttpOptions): Promise<HttpResponse>;
18
+ export declare function sendingHttp(options?: HttpOptions): Http;
16
19
  export interface RecordedCall {
17
20
  readonly target: string;
18
21
  readonly method: string;
@@ -25,6 +28,7 @@ export interface ScriptedAnswer {
25
28
  readonly headers?: Readonly<Record<string, string>>;
26
29
  readonly body?: string;
27
30
  }
28
- export declare function recordingHttp(script?: Readonly<Record<string, ScriptedAnswer>>): Http & {
31
+ export type Scripted = ScriptedAnswer | readonly ScriptedAnswer[];
32
+ export declare function recordingHttp(script?: Readonly<Record<string, Scripted>>): Http & {
29
33
  readonly calls: readonly RecordedCall[];
30
34
  };