@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,25 +1,26 @@
1
- import { existsSync, readFileSync, writeFileSync } from '../../core/files.ts'
1
+ import { existsSync, readFileSync, writeFileSync, type Answering, type Listed } from '../../integrations/disk.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
6
  import { ANONYMOUS, type Actor } from '../../core/actor.ts'
7
- import { ROOT, TREE, descend } from '../../core/descend.ts'
7
+ import { ROOT, descend } from '../../core/descend.ts'
8
8
  import { exit, invoked } from '../../core/invoked.ts'
9
+ import { reachOf, standsHere, type Call, type Row, type Target } from '../../integrations/target.ts'
9
10
 
10
- import { recordingHttp, type ScriptedAnswer } from '../http.ts'
11
- import { inMemorySeams, type Sink } from '../memory.ts'
11
+ import { recordingHttp, type RecordedCall, type Scripted, type ScriptedAnswer } from '../../integrations/https.ts'
12
+ import { standing, type Kept, type Stood } from '../../integrations/pglite.ts'
12
13
  import { TRIALS_AT, type Operation } from '../operations.ts'
13
14
  import { PERMITS_AT } from '../access.ts'
14
15
  import type { Result } from '../result.ts'
15
- import type { Row, Seams } from '../seams.ts'
16
+ import type { Vault } from '../../integrations/secret.ts'
16
17
  import { operations, types } from './seed.ts'
17
18
 
18
19
  export { TRIALS_AT }
19
20
 
20
21
  const DISPATCH_AT = 'operations/_dispatch.ts'
21
22
 
22
- const ENTITIES_AT = `${TREE}entities.ts`
23
+
23
24
 
24
25
  const ACCESS_AT = '_threads/access.ts'
25
26
 
@@ -36,9 +37,11 @@ export interface Scenario {
36
37
 
37
38
  readonly rows?: readonly { readonly entity: string; readonly row: Row }[]
38
39
 
39
- readonly answers?: Readonly<Record<string, ScriptedAnswer>>
40
+ readonly answers?: Readonly<Record<string, Scripted>>
40
41
 
41
42
  readonly views?: Readonly<Record<string, readonly unknown[]>>
43
+
44
+ readonly files?: Readonly<Record<string, string>>
42
45
  }
43
46
 
44
47
  export interface Trial {
@@ -53,7 +56,6 @@ export interface Trial {
53
56
 
54
57
  readonly kept: unknown
55
58
 
56
- readonly observed: unknown
57
59
 
58
60
  readonly called: unknown
59
61
  }
@@ -99,55 +101,185 @@ const asking = (scenario: Scenario): Actor => ({
99
101
  ...(scenario.actor ?? ANONYMOUS),
100
102
  run: 'trial',
101
103
  replay: `trial_${scenario.id}`,
104
+ moment: new Date(WHEN).toISOString(),
102
105
  })
103
106
 
104
- function seamsFor(
105
- one: Operation<unknown>,
106
- scenario: Scenario,
107
- stood: Readonly<Record<string, string>>,
108
- gate?: NonNullable<Seams['permits']>,
109
- known?: { readonly entities: ReadonlyMap<string, ReadonlySet<string>>; readonly keys: ReadonlyMap<string, string> },
110
- ): { readonly seams: Seams; readonly sink: Sink; readonly kept: () => unknown; readonly calls: () => unknown } {
111
- const made = inMemorySeams({
112
- secrets: stood,
113
- ...(scenario.views === undefined ? {} : { views: scenario.views }),
114
- ...(known === undefined ? {} : { entities: known.entities, keys: known.keys }),
115
- })
116
-
117
- const found = made.seams as unknown as Record<string, unknown>
118
-
119
- if (gate !== undefined) found['permits'] = gate
120
- found['clock'] = { now: () => WHEN }
121
-
122
- let drawn = 0
123
- found['random'] = {
124
- next: () => {
125
- drawn += 1
126
- return drawn / 100
107
+ function programmed(word: string, names: readonly string[]): Record<string, unknown> {
108
+ const made: Record<string, unknown> = {}
109
+ for (const order of names) {
110
+ made[order] = (): never => {
111
+ throw new Error(
112
+ word + ' was asked to run ' + order + ', and this scenario says nothing about what that did. A trial stands a ' +
113
+ 'disk up out of the files its scenario states, and there is nowhere yet to state what a program or a package answered, so ' +
114
+ 'a scenario cannot give either an order. This says that rather than inventing a result for one.',
115
+ )
116
+ }
117
+ }
118
+ return made
119
+ }
120
+
121
+ function packaged(
122
+ word: string,
123
+ names: readonly string[],
124
+ script: Readonly<Record<string, Scripted>>,
125
+ into: RecordedCall[],
126
+ ): Record<string, unknown> {
127
+ const spent = new Map<string, number>()
128
+ const made: Record<string, unknown> = {}
129
+ for (const name of names) {
130
+ made[name] = async (given?: unknown): Promise<unknown> => {
131
+ const key = word + ' ' + name
132
+ into.push({ target: word, method: 'CALL', path: name, headers: {}, body: JSON.stringify(stable(given ?? null)) })
133
+ const held = script[key]
134
+ if (held === undefined) {
135
+ throw new Error(
136
+ 'this scenario scripts no answer for "' + key + '", so nothing here knows what ' + word + ' would hand back. Add ' +
137
+ 'that key to the scenario\'s answers, with what the call returns written as JSON in its body.',
138
+ )
139
+ }
140
+ const each = Array.isArray(held) ? (held as readonly ScriptedAnswer[]) : undefined
141
+ const at = spent.get(key) ?? 0
142
+ spent.set(key, at + 1)
143
+ const answer = each === undefined ? (held as ScriptedAnswer) : each[at]
144
+ if (answer === undefined) {
145
+ throw new Error(
146
+ 'this scenario scripts ' + String(each?.length ?? 0) + ' answer(s) for "' + key + '" and it has now been called ' +
147
+ String(at + 1) + ' time(s). A node that calls the same thing again needs one answer per call, in the order they come back.',
148
+ )
149
+ }
150
+ if (answer.status !== 200) throw new Error(answer.body ?? word + ' ' + name + ' failed with ' + String(answer.status))
151
+ return answer.body === undefined ? undefined : (JSON.parse(answer.body) as unknown)
152
+ }
153
+ }
154
+ return made
155
+ }
156
+
157
+ function disked(files: Readonly<Record<string, string>>): Answering {
158
+ const held = new Map<string, string>(Object.entries(files))
159
+ const under = (at: string): boolean => [...held.keys()].some((one) => one.startsWith(at + '/'))
160
+ const gone = (at: string): Error =>
161
+ new Error(at + ' is not in this scenario, and a trial answers a file order against the files its scenario states')
162
+ return {
163
+ kind: (at) => (held.has(at) ? 'file' : under(at) ? 'folder' : 'none'),
164
+ read: (at) => {
165
+ const said = held.get(at)
166
+ if (said === undefined) throw gone(at)
167
+ return said
168
+ },
169
+ write: (at, said) => {
170
+ held.set(at, said)
171
+ },
172
+ list: (at) => {
173
+ const inside = new Map<string, Listed>()
174
+ for (const one of held.keys()) {
175
+ if (!one.startsWith(at + '/')) continue
176
+ const rest = one.slice(at.length + 1)
177
+ const cut = rest.indexOf('/')
178
+ const name = cut === -1 ? rest : rest.slice(0, cut)
179
+ inside.set(name, { name, kind: cut === -1 ? 'file' : 'folder' })
180
+ }
181
+ return [...inside.values()]
182
+ },
183
+ stat: (at) => {
184
+ const said = held.get(at)
185
+ if (said === undefined) throw gone(at)
186
+ return { size: said.length, modified: 0 }
187
+ },
188
+ remove: (at) => {
189
+ held.delete(at)
127
190
  },
128
- uuid: () => {
129
- drawn += 1
130
- return `00000000-0000-4000-8000-${String(drawn).padStart(12, '0')}`
191
+ real: (at) => at,
192
+ }
193
+ }
194
+
195
+ function vaulting(stood: Readonly<Record<string, string>>): Vault {
196
+ return {
197
+ async resolve(refs) {
198
+ const found: Record<string, string> = {}
199
+ for (const ref of refs) {
200
+ const value = stood[ref]
201
+ if (value === undefined) {
202
+ throw new Error(
203
+ ref + ' is not a secret this app declares, so a trial has nothing to stand in for it. Declare it with ' +
204
+ '`thread create secret`, or stop requiring the target that asks for it.',
205
+ )
206
+ }
207
+ found[ref] = value
208
+ }
209
+ return found
131
210
  },
132
211
  }
212
+ }
133
213
 
214
+ async function standingStore(row: Target): Promise<Stood | string> {
215
+ const said = row.derives?.find((each) => each.id === row.id + '_store')?.at
216
+ if (said === undefined) {
217
+ return row.id + ' keeps rows and its row derives no store, so a trial has nothing to stand up. Run `thread schema`'
218
+ }
219
+ const at = resolve(ROOT, said)
220
+ if (!existsSync(at)) return said + ' is not there, so ' + row.id + ' cannot be stood up. Run `thread schema`'
221
+ const made = (await import(pathToFileURL(at).href)) as { readonly kept?: Kept }
222
+ const held = made.kept
223
+ if (held === undefined) {
224
+ return said + ' says nothing about what ' + row.id + ' keeps or with what schema. Run `thread schema`'
225
+ }
226
+ return standing(held)
227
+ }
228
+
229
+ async function openedFor(
230
+ one: Operation<unknown>,
231
+ scenario: Scenario,
232
+ stood: Readonly<Record<string, string>>,
233
+ targets: readonly Target[] = [],
234
+ calls: readonly Call[] = [],
235
+ ): Promise<{
236
+ readonly opened: Readonly<Record<string, unknown>>
237
+ readonly opening: Vault
238
+ readonly stores: readonly Stood[]
239
+ readonly calls: () => unknown
240
+ } | string> {
134
241
  const recorder = recordingHttp(scenario.answers ?? {})
135
- found['http'] = recorder
242
+ const packages: RecordedCall[] = []
243
+ const opening = vaulting(stood)
244
+ const opened: Record<string, unknown> = {}
245
+ const stores: Stood[] = []
246
+
247
+ const answering = (row: Target): readonly string[] =>
248
+ calls.filter((each) => each.of === row.id && row.takes.includes(each.id)).map((each) => each.id.replace(/^cl_/, ''))
249
+ for (const word of one.requires) {
250
+ const row = targets.find((each) => each.id === word)
251
+ if (row === undefined || !standsHere(row, targets)) continue
252
+ const reach = reachOf(row.id)
253
+ if (reach === 'disk') opened[word] = disked(scenario.files ?? {})
254
+ else if (reach === 'cli') opened[word] = programmed(word, answering(row))
255
+ else if (reach === 'https') opened[word] = recorder
256
+ else if (reach === 'sdk') opened[word] = packaged(word, answering(row), scenario.answers ?? {}, packages)
257
+ else {
258
+ const held = await standingStore(row)
259
+ if (typeof held === 'string') return held
260
+ opened[word] = held.store
261
+ stores.push(held)
262
+ }
263
+ }
264
+
136
265
 
137
- return { seams: made.seams, sink: made.sink, kept: () => made.store, calls: () => recorder.calls }
266
+
267
+ return { opened, opening, stores, calls: () => [...recorder['calls'], ...packages] }
138
268
  }
139
269
 
140
- function entered(sink: Sink): boolean {
141
- return sink.logs.some((one) => {
142
- const data = one.data as Record<string, unknown> | undefined
143
- return data !== undefined && 'observability' in data
144
- })
270
+ const BEFORE = new Set(['denied', 'invalid'])
271
+
272
+ function entered(result: unknown): boolean {
273
+ if (typeof result !== 'object' || result === null) return false
274
+ const held = result as { readonly ok?: unknown; readonly code?: unknown }
275
+ if (held.ok === true) return true
276
+ return held.ok === false && !BEFORE.has(String(held.code))
145
277
  }
146
278
 
147
279
  function denied(result: unknown): boolean {
148
280
  if (typeof result !== 'object' || result === null) return false
149
281
  const held = result as { readonly ok?: unknown; readonly code?: unknown }
150
- return held.ok === false && held.code === 'denied'
282
+ return held.ok === false && BEFORE.has(String(held.code))
151
283
  }
152
284
 
153
285
  export async function runScenario(
@@ -157,38 +289,48 @@ export async function runScenario(
157
289
  operation: Operation<unknown>,
158
290
  input: unknown,
159
291
  actor: Actor,
160
- seams: Seams,
292
+ opened: Readonly<Record<string, unknown>>,
293
+ opening: Vault,
161
294
  ) => Promise<Result<unknown>>,
162
295
  stood: Readonly<Record<string, string>> = {},
163
- gate?: NonNullable<Seams['permits']>,
164
- known?: { readonly entities: ReadonlyMap<string, ReadonlySet<string>>; readonly keys: ReadonlyMap<string, string> },
165
- ): Promise<Trial> {
296
+ targets: readonly Target[] = [],
297
+ calls: readonly Call[] = [],
298
+ ): Promise<Trial | string> {
166
299
 
167
- const made = seamsFor(one, scenario, stood, gate, known)
300
+ const made = await openedFor(one, scenario, stood, targets, calls)
301
+ if (typeof made === 'string') return made
168
302
 
169
303
  const actor = asking(scenario)
170
304
 
171
- for (const seeded of scenario.rows ?? []) {
172
- const held = made.seams.store
173
- if (held === undefined) throw new Error(String(seeded.entity) + " cannot be seeded: these seams keep no rows")
174
- await held.insert(actor, seeded.entity, seeded.row)
305
+ for (const each of scenario.rows ?? []) {
306
+ const held = made.stores.find((store) => store.keeps.includes(each.entity))
307
+ if (held === undefined) {
308
+ return (
309
+ '`' + one.id + '` is tried with a row of "' + each.entity + '" and no target it requires keeps that entity, ' +
310
+ 'so there is nowhere to put it. Require the target that keeps it, or take that row off the scenario'
311
+ )
312
+ }
313
+ await held.seed(actor, [each])
175
314
  }
176
315
 
177
316
  let result: unknown
178
317
  try {
179
- result = await dispatch(one, scenario.input, actor, made.seams)
318
+ result = await dispatch(one, scenario['input'], actor, made.opened, made.opening)
180
319
  } catch (thrown) {
181
320
  result = { threw: thrown instanceof Error ? thrown.message : String(thrown) }
182
321
  }
183
322
 
323
+ const kept: Record<string, unknown> = {}
324
+ for (const held of made.stores) Object.assign(kept, await held.taken(actor))
325
+
184
326
  return {
185
327
  operation: one.id,
186
328
  scenario: scenario.id,
187
329
  refused: denied(result),
188
- measured: entered(made.sink),
330
+ measured: entered(result),
189
331
  result,
190
- kept: made.kept(),
191
- observed: made.sink,
332
+ kept,
333
+
192
334
  called: made.calls(),
193
335
  }
194
336
  }
@@ -252,15 +394,15 @@ export function compared(was: readonly Trial[], now: readonly Trial[]): Run {
252
394
 
253
395
  if (one.refused && one.measured) {
254
396
  failures.push(
255
- 'this app\'s own gate denied the caller and the run REACHED THE OPERATION anyway — dispatch let a ' +
256
- 'denied request through to the compiled function, which is the gate not holding rather than a trial drifting',
397
+ 'this run was refused before the operation could start and REACHED THE OPERATION anyway — dispatch let a ' +
398
+ 'refused request through to the compiled function, which is the gate not holding rather than a trial drifting',
257
399
  )
258
400
  }
259
401
 
260
402
  if (older === undefined) {
261
403
  failures.push('no trial holds this scenario. Run `thread trials` and commit the result')
262
404
  } else {
263
- for (const part of ['result', 'kept', 'observed'] as const) {
405
+ for (const part of ['result', 'kept', 'called'] as const) {
264
406
  const then = printed(older[part])
265
407
  const said = printed(one[part])
266
408
  if (then === said) continue
@@ -318,7 +460,7 @@ export function unproven(run: Run): readonly string[] {
318
460
  const how = [
319
461
  denied === 0
320
462
  ? ''
321
- : `${String(denied)} were denied by this app's own gate, which proves the gate turns somebody away and nothing whatever about the operation`,
463
+ : `${String(denied)} were refused before the operation could start — by the gate, or because what they were given is not what it takes — which proves the refusal and nothing whatever about the operation`,
322
464
  neither === 0 ? '' : `${String(neither)} neither reached it nor were denied`,
323
465
  ].filter((one) => one !== '')
324
466
 
@@ -331,13 +473,13 @@ export function unproven(run: Run): readonly string[] {
331
473
  return said
332
474
  }
333
475
 
334
- async function standing(): Promise<Readonly<Record<string, string>> | string> {
476
+ async function standIns(): Promise<Readonly<Record<string, string>> | string> {
335
477
  const at = resolve(ROOT, '_threads/secrets.ts')
336
478
  if (!existsSync(at)) return {}
337
- let held: readonly { readonly id: string; readonly sends?: unknown }[]
479
+ let held: readonly { readonly id: string; readonly sends?: unknown; readonly signs?: unknown }[]
338
480
  try {
339
481
  const taken = (await import(pathToFileURL(at).href)) as {
340
- readonly SECRETS?: readonly { readonly id: string; readonly sends?: unknown }[]
482
+ readonly SECRETS?: readonly { readonly id: string; readonly sends?: unknown; readonly signs?: unknown }[]
341
483
  }
342
484
  held = taken.SECRETS ?? []
343
485
  } catch (thrown) {
@@ -349,11 +491,26 @@ async function standing(): Promise<Readonly<Record<string, string>> | string> {
349
491
  }
350
492
  const found: Record<string, string> = {}
351
493
  for (const one of held) {
352
- found[one.id] = one.sends === undefined ? `https://${one.id.replace(/_/g, '-')}.invalid` : `${one.id}-stood-in-for`
494
+ found[one.id] = one.sends === undefined && one.signs === undefined ? `https://${one.id.replace(/_/g, '-')}.invalid` : `${one.id}-stood-in-for`
353
495
  }
354
496
  return found
355
497
  }
356
498
 
499
+ async function reaching(): Promise<{ readonly targets: readonly Target[]; readonly calls: readonly Call[] } | string> {
500
+ const at = resolve(ROOT, '_threads/targets.ts')
501
+ if (!existsSync(at)) return { targets: [], calls: [] }
502
+ try {
503
+ const taken = (await import(pathToFileURL(at).href)) as { readonly TARGETS?: readonly Target[]; readonly CALLS?: readonly Call[] }
504
+ return { targets: taken.TARGETS ?? [], calls: taken.CALLS ?? [] }
505
+ } catch (thrown) {
506
+ return (
507
+ `_threads/targets.ts is there and could not be read: ${thrown instanceof Error ? thrown.message : String(thrown)}. ` +
508
+ 'Which disk a trial hands an operation is read from that sheet, so every trial would run with no disk at all and ' +
509
+ 'the failures would name the operation instead of the sheet'
510
+ )
511
+ }
512
+ }
513
+
357
514
  export async function record(): Promise<{ readonly trials: readonly Trial[]; readonly refusals: readonly string[] }> {
358
515
  const pass = descend()
359
516
  const known = types(pass)
@@ -363,9 +520,13 @@ export async function record(): Promise<{ readonly trials: readonly Trial[]; rea
363
520
  const declared = [...operations(pass, known)].filter(([, one]) => one.body !== undefined)
364
521
  if (declared.length === 0) return { trials: [], refusals: [] }
365
522
 
366
- const stood = await standing()
523
+ const stood = await standIns()
367
524
  if (typeof stood === 'string') return { trials: [], refusals: [stood] }
368
525
 
526
+ const reached = await reaching()
527
+ if (typeof reached === 'string') return { trials: [], refusals: [reached] }
528
+ const { targets, calls } = reached
529
+
369
530
  const at = resolve(ROOT, DISPATCH_AT)
370
531
  if (!existsSync(at)) {
371
532
  return {
@@ -380,7 +541,8 @@ export async function record(): Promise<{ readonly trials: readonly Trial[]; rea
380
541
  operation: Operation<unknown>,
381
542
  input: unknown,
382
543
  actor: Actor,
383
- seams: Seams,
544
+ opened: Readonly<Record<string, unknown>>,
545
+ opening: Vault,
384
546
  ) => Promise<Result<unknown>>
385
547
  }
386
548
  const dispatch = made.dispatch
@@ -388,28 +550,6 @@ export async function record(): Promise<{ readonly trials: readonly Trial[]; rea
388
550
  return { trials: [], refusals: [`${DISPATCH_AT} exports no \`dispatch\`, so nothing here can run an operation`] }
389
551
  }
390
552
 
391
- const kept = resolve(ROOT, ENTITIES_AT)
392
- const entities = new Map<string, ReadonlySet<string>>()
393
- const keys = new Map<string, string>()
394
- if (existsSync(kept)) {
395
- const sheet = (await import(pathToFileURL(kept).href)) as {
396
- readonly ENTITIES?: readonly {
397
- readonly id: string
398
- readonly holds?: readonly { readonly id: string }[]
399
- readonly links?: readonly { readonly id: string }[]
400
- readonly must?: readonly { readonly unique?: readonly string[] }[]
401
- }[]
402
- }
403
- for (const one of sheet.ENTITIES ?? []) {
404
- entities.set(
405
- one.id,
406
- new Set([...(one.holds ?? []).map((each) => each.id), ...(one.links ?? []).map((each) => `${each.id}_id`)]),
407
- )
408
- const named = (one.must ?? []).flatMap((each) => (each.unique?.length === 1 ? [each.unique[0] as string] : []))
409
- if (named.length === 1) keys.set(one.id, named[0] as string)
410
- }
411
- }
412
-
413
553
  const permitted = resolve(ROOT, ACCESS_AT)
414
554
  const may = new Map<string, string[]>()
415
555
  if (existsSync(permitted)) {
@@ -438,11 +578,6 @@ export async function record(): Promise<{ readonly trials: readonly Trial[]; rea
438
578
  refusals: [`${PERMITS_AT} exports no \`permits\`, so a trial cannot be answered by the gate this app derives`],
439
579
  }
440
580
  }
441
- const gate: NonNullable<Seams['permits']> | undefined =
442
- permits === undefined
443
- ? undefined
444
- : { check: (actor, action, resource) => Promise.resolve(permits(actor, action, resource)) }
445
-
446
581
  for (const [id, one] of [...declared].sort((a, b) => compare(a[0], b[0]))) {
447
582
  if (one.body === undefined) continue
448
583
  const from = resolve(ROOT, one.body)
@@ -471,7 +606,9 @@ export async function record(): Promise<{ readonly trials: readonly Trial[]; rea
471
606
  }
472
607
 
473
608
  for (const scenario of scenarios) {
474
- trials.push(await runScenario(operation, scenario, dispatch, stood, gate, { entities, keys }))
609
+ const ran = await runScenario(operation, scenario, dispatch, stood, targets, calls)
610
+ if (typeof ran === 'string') refusals.push(ran)
611
+ else trials.push(ran)
475
612
  }
476
613
  }
477
614
 
@@ -1,6 +1,5 @@
1
1
  import type { Threaded } from '../core/thread.ts';
2
- import type { Operation } from './operations.ts';
3
- import type { Handed, Reads, Supplied } from './seams.ts';
2
+ import type { Opened, Operation, Reads } from './operations.ts';
4
3
  export interface Node extends Threaded {
5
4
  readonly version: number;
6
5
  }
@@ -9,27 +8,27 @@ export declare const STOPPED: unique symbol;
9
8
  export declare function stopped(thrown: unknown): {
10
9
  readonly value: unknown;
11
10
  } | undefined;
12
- export declare const nd_read: <I, R extends string = Supplied>(block: (hands: Reads<Handed<R>>, held: Held<I>) => Promise<unknown>) => {
13
- type: "nd_read";
11
+ export declare const nd_read: <I, R extends string = never>(block: (opened: Reads<Opened<R>>, held: Held<I>) => Promise<unknown>) => {
12
+ type: 'nd_read';
14
13
  };
15
- export declare const nd_action: <I, R extends string = Supplied>(block: (hands: Handed<R>, held: Held<I>) => Promise<unknown>) => {
16
- type: "nd_action";
14
+ export declare const nd_action: <I, R extends string = never>(block: (opened: Opened<R>, held: Held<I>) => Promise<unknown>) => {
15
+ type: 'nd_action';
17
16
  };
18
- export declare const nd_branch: <I, R extends string = Supplied>(choose: (hands: Reads<Handed<R>>, held: Held<I>) => Promise<string>, ways: Readonly<Record<string, (hands: Handed<R>, held: Held<I>) => Promise<unknown>>>) => {
19
- type: "nd_branch";
17
+ export declare const nd_branch: <I, R extends string = never>(choose: (opened: Reads<Opened<R>>, held: Held<I>) => Promise<string>, ways: Readonly<Record<string, (opened: Opened<R>, held: Held<I>) => Promise<unknown>>>) => {
18
+ type: 'nd_branch';
20
19
  };
21
- export declare const nd_each: <I, R extends string = Supplied>(over: (held: Held<I>) => readonly unknown[], block: (item: unknown, hands: Handed<R>, held: Held<I>) => Promise<unknown>) => {
22
- type: "nd_each";
20
+ export declare const nd_each: <I, R extends string = never>(over: (held: Held<I>) => readonly unknown[], block: (item: unknown, opened: Opened<R>, held: Held<I>) => Promise<unknown>) => {
21
+ type: 'nd_each';
23
22
  };
24
- export declare const nd_parallel: <I, R extends string = Supplied>(blocks: readonly ((hands: Handed<R>, held: Held<I>) => Promise<unknown>)[]) => {
25
- type: "nd_parallel";
23
+ export declare const nd_parallel: <I, R extends string = never>(blocks: readonly ((opened: Opened<R>, held: Held<I>) => Promise<unknown>)[]) => {
24
+ type: 'nd_parallel';
26
25
  };
27
- export declare const nd_repeat: <I, R extends string = Supplied>(ceiling: number, block: (pass: number, carried: unknown, hands: Handed<R>, held: Held<I>) => Promise<{
26
+ export declare const nd_repeat: <I, R extends string = never>(ceiling: number, block: (pass: number, carried: unknown, opened: Opened<R>, held: Held<I>) => Promise<{
28
27
  readonly done: boolean;
29
28
  readonly value: unknown;
30
29
  }>) => {
31
- type: "nd_repeat";
30
+ type: 'nd_repeat';
32
31
  };
33
- export declare const nd_stop: <I, R extends string = Supplied>(block: (hands: Reads<Handed<R>>, held: Held<I>) => Promise<unknown>) => {
34
- type: "nd_stop";
32
+ export declare const nd_stop: <I, R extends string = never>(block: (opened: Reads<Opened<R>>, held: Held<I>) => Promise<unknown>) => {
33
+ type: 'nd_stop';
35
34
  };
@@ -1,7 +1,6 @@
1
1
  import type { Threaded } from '../core/thread.ts'
2
2
 
3
- import type { Operation } from './operations.ts'
4
- import type { Handed, Reads, Supplied } from './seams.ts'
3
+ import type { Opened, Operation, Reads } from './operations.ts'
5
4
 
6
5
  export interface Node extends Threaded {
7
6
  readonly version: number
@@ -17,38 +16,38 @@ export function stopped(thrown: unknown): { readonly value: unknown } | undefine
17
16
  return { value: (thrown as { readonly value?: unknown }).value }
18
17
  }
19
18
 
20
- export const nd_read = <I, R extends string = Supplied>(
21
- block: (hands: Reads<Handed<R>>, held: Held<I>) => Promise<unknown>,
19
+ export const nd_read = <I, R extends string = never>(
20
+ block: (opened: Reads<Opened<R>>, held: Held<I>) => Promise<unknown>,
22
21
  ) => ({ type: 'nd_read' as const })
23
22
 
24
- export const nd_action = <I, R extends string = Supplied>(
25
- block: (hands: Handed<R>, held: Held<I>) => Promise<unknown>,
23
+ export const nd_action = <I, R extends string = never>(
24
+ block: (opened: Opened<R>, held: Held<I>) => Promise<unknown>,
26
25
  ) => ({ type: 'nd_action' as const })
27
26
 
28
- export const nd_branch = <I, R extends string = Supplied>(
29
- choose: (hands: Reads<Handed<R>>, held: Held<I>) => Promise<string>,
30
- ways: Readonly<Record<string, (hands: Handed<R>, held: Held<I>) => Promise<unknown>>>,
27
+ export const nd_branch = <I, R extends string = never>(
28
+ choose: (opened: Reads<Opened<R>>, held: Held<I>) => Promise<string>,
29
+ ways: Readonly<Record<string, (opened: Opened<R>, held: Held<I>) => Promise<unknown>>>,
31
30
  ) => ({ type: 'nd_branch' as const })
32
31
 
33
- export const nd_each = <I, R extends string = Supplied>(
32
+ export const nd_each = <I, R extends string = never>(
34
33
  over: (held: Held<I>) => readonly unknown[],
35
- block: (item: unknown, hands: Handed<R>, held: Held<I>) => Promise<unknown>,
34
+ block: (item: unknown, opened: Opened<R>, held: Held<I>) => Promise<unknown>,
36
35
  ) => ({ type: 'nd_each' as const })
37
36
 
38
- export const nd_parallel = <I, R extends string = Supplied>(
39
- blocks: readonly ((hands: Handed<R>, held: Held<I>) => Promise<unknown>)[],
37
+ export const nd_parallel = <I, R extends string = never>(
38
+ blocks: readonly ((opened: Opened<R>, held: Held<I>) => Promise<unknown>)[],
40
39
  ) => ({ type: 'nd_parallel' as const })
41
40
 
42
- export const nd_repeat = <I, R extends string = Supplied>(
41
+ export const nd_repeat = <I, R extends string = never>(
43
42
  ceiling: number,
44
43
  block: (
45
44
  pass: number,
46
45
  carried: unknown,
47
- hands: Handed<R>,
46
+ opened: Opened<R>,
48
47
  held: Held<I>,
49
48
  ) => Promise<{ readonly done: boolean; readonly value: unknown }>,
50
49
  ) => ({ type: 'nd_repeat' as const })
51
50
 
52
- export const nd_stop = <I, R extends string = Supplied>(
53
- block: (hands: Reads<Handed<R>>, held: Held<I>) => Promise<unknown>,
51
+ export const nd_stop = <I, R extends string = never>(
52
+ block: (opened: Reads<Opened<R>>, held: Held<I>) => Promise<unknown>,
54
53
  ) => ({ type: 'nd_stop' as const })
@@ -1,18 +1,54 @@
1
1
  import type { z } from 'zod';
2
+ import type { Actor } from '../core/actor.ts';
2
3
  import type { Member } from '../core/thread.ts';
3
- import type { Handed, Row, Supplied } from './seams.ts';
4
+ import { REACH, type Answering, type Calling, type HttpResponse, type Row, type Running, type Store } from '../integrations/target.ts';
5
+ import type { Surface } from './capabilities.ts';
4
6
  export declare const OPERATIONS_FILE = "operations.ts";
5
7
  export declare const TRIALS_AT = "operations/_trials.json";
6
8
  export declare const NODES_FILE = "nodes.ts";
7
9
  export declare const MEMBERS_LIST = "MEMBERS";
8
- export interface Operation<I = unknown, R extends string = Supplied> {
10
+ export interface Reaching {
11
+ }
12
+ type CallsOf<K extends string> = K extends keyof Reaching ? (Reaching[K] extends string ? Reaching[K] : string) : string;
13
+ export type Opened<R extends string = never> = {
14
+ readonly actor: Actor;
15
+ readonly tell: (said: unknown) => void;
16
+ } & {
17
+ readonly [K in R]: K extends `${typeof REACH.disk}${string}` ? Answering : K extends `${typeof REACH.cli}${string}` ? Running<CallsOf<K>> : K extends `${typeof REACH.postgres}${string}` | `${typeof REACH.pglite}${string}` | `${typeof REACH.browser}${string}` ? Store : K extends `${typeof REACH.sdk}${string}` ? Calling<CallsOf<K>> : Readonly<Record<CallsOf<K>, (given?: {
18
+ readonly fills?: Readonly<Record<string, string | number>>;
19
+ readonly json?: unknown;
20
+ readonly body?: Uint8Array;
21
+ readonly contentType?: string;
22
+ readonly told?: (said: unknown) => void;
23
+ }) => Promise<HttpResponse>>>;
24
+ };
25
+ export type Reads<H> = {
26
+ readonly [K in keyof H]: H[K] extends Store ? Pick<Store, 'get' | 'list'> : H[K];
27
+ };
28
+ export declare const WINDOWS: readonly ['second', 'minute', 'hour', 'day', 'week', 'month'];
29
+ export type Window = (typeof WINDOWS)[number];
30
+ export interface Allowance {
31
+ readonly runs: number;
32
+ readonly per: Window;
33
+ }
34
+ export interface Counting {
35
+ readonly seen: (key: string, per: Window) => Promise<number>;
36
+ }
37
+ export interface Operation<I = unknown, R extends string = never> {
9
38
  readonly id: string;
10
39
  readonly input: z.ZodType<I>;
11
40
  readonly requires: readonly string[];
12
- readonly run: (hands: Handed<R>, held: {
41
+ readonly webhooks?: readonly string[];
42
+ readonly off?: readonly Surface[];
43
+ readonly signed?: boolean;
44
+ readonly entitled?: string;
45
+ readonly rate?: Allowance;
46
+ readonly quota?: Allowance;
47
+ readonly run: (opened: Opened<R>, held: {
13
48
  readonly input: I;
14
49
  } & Readonly<Record<string, unknown>>) => Promise<unknown>;
15
- readonly estimate: number;
50
+ readonly timeout: number;
16
51
  readonly resource: (input: I) => Row | null;
17
52
  }
18
53
  export declare const OPERATIONS: readonly Member[];
54
+ export {};