@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,191 +0,0 @@
1
- import { spawnSync } from 'node:child_process'
2
- import { argv, stderr, stdout } from 'node:process'
3
-
4
- import type { Env } from '../core/actor.ts'
5
- import { answer, asking, given, unasked, wordsIn } from '../core/answers.ts'
6
- import { readFileSync } from '../core/files.ts'
7
- import { exit } from '../core/invoked.ts'
8
- import { valuesIn } from '../core/rows.ts'
9
- import { findTree, inTree } from '../core/tree.ts'
10
-
11
- import { REACH, reachOf, type Target } from './target.ts'
12
- import { opened } from './vault.ts'
13
-
14
- const PRODUCTION = '--production'
15
-
16
- const METHOD = /^[A-Za-z_$][\w$]*(?:\.[A-Za-z_$][\w$]*)*$/
17
-
18
- function isClass(fn: (...args: readonly unknown[]) => unknown): boolean {
19
- return /^class[\s{]/.test(Function.prototype.toString.call(fn))
20
- }
21
-
22
- const ASKS: readonly { readonly key: string; readonly says: string }[] = [
23
- {
24
- key: 'args',
25
- says: 'a JSON value — an array for positional arguments, anything else for one, blank for none',
26
- },
27
- ]
28
-
29
- const TAKES: readonly string[] = ASKS.map((one) => one.key)
30
-
31
- const ASKED: readonly string[] = ASKS.map((one) => `\`${one.key}\`: ${one.says}`)
32
-
33
- export async function ran(name: string): Promise<void> {
34
- const say = (because: string): never => {
35
- stderr.write(`${name}: ${because}\n`)
36
- exit(1)
37
- }
38
-
39
- const tree = findTree()
40
- let targets: readonly Target[] = []
41
- try {
42
- const taken = valuesIn(readFileSync(inTree(tree, 'targets.ts'))) as {
43
- TARGETS?: readonly Target[]
44
- }
45
- targets = taken.TARGETS ?? []
46
- } catch {
47
- return say('`_threads/targets.ts` could not be read, so nothing says what this integration is.')
48
- }
49
-
50
- const mine = targets.find((one) => one.id === `${REACH.cli}${name}` || one.id === `${REACH.module}${name}`)
51
- if (mine === undefined) {
52
- return say(
53
- `no target called \`${REACH.cli}${name}\` or \`${REACH.module}${name}\` is declared here, so this command should ` +
54
- 'not exist. Declare it with `thread create target`, or take its row out of `_threads/derivation.ts`.',
55
- )
56
- }
57
-
58
- const does = mine.offers ?? []
59
- const passed = argv.slice(2)
60
- const sub = passed[0]
61
-
62
- if (sub === undefined) {
63
- stdout.write(
64
- `${name}: ${mine.describes}\n\n${String(does.length)} command(s), read off \`${mine.uses ?? ''}\` when \`${mine.id}\` was declared:\n` +
65
- `${does.join(', ') || '(none were readable — name them with `thread create target edit`)'}\n\n` +
66
- `thread run ${name} <command> [anything else] — arguments and flags reach \`${mine.uses ?? ''}\` untouched.\n` +
67
- `It takes ${String(ASKED.length)} answer(s): ${ASKED.join('; ')}.\n`,
68
- )
69
- exit(0)
70
- }
71
-
72
- if (!does.includes(sub)) {
73
- return say(
74
- `\`${sub}\` is not one of the ${String(does.length)} command(s) \`${mine.uses ?? ''}\` stated when \`${mine.id}\` ` +
75
- `was declared. It declared: ${does.join(', ') || '(nothing)'}. If the tool has changed, read it again with ` +
76
- `\`thread create target edit ${mine.id}\`.`,
77
- )
78
- }
79
-
80
- if (reachOf(mine.id) === 'module') {
81
- return run({ name, module: mine.uses ?? '', requires: mine.requires })
82
- }
83
-
84
- const went = spawnSync(mine.uses ?? '', passed, { cwd: tree.at, stdio: 'inherit' })
85
- exit(went.status ?? 1)
86
- }
87
-
88
- export async function run(declared: {
89
- readonly name: string
90
- readonly module: string
91
- readonly requires: readonly string[]
92
- }): Promise<void> {
93
- const refuse = (because: string): never => {
94
- stderr.write(`${declared.name}: ${because}\n`)
95
- exit(1)
96
- }
97
-
98
- const method = wordsIn([])[0]
99
- if (method === undefined) {
100
- return refuse(
101
- `takes the method to call, dot-separated for a namespaced one — e.g. \`thread run ${declared.name} customers.list\`.`,
102
- )
103
- }
104
- if (!METHOD.test(method)) {
105
- return refuse(`\`${method}\` is not a method path — one name, or names joined by dots, e.g. \`customers.list\``)
106
- }
107
-
108
- const piped = given()
109
- unasked(piped, TAKES, `\`thread run ${declared.name} ${method}\``)
110
- const { ask, shut } = asking(piped)
111
- const typed = (
112
- piped.length > 0
113
- ? (answer(piped, TAKES[0] ?? 'args') ?? '')
114
- : await ask('args', 'args, as JSON — an array for positional arguments, anything else for one (blank for none): ')
115
- ).trim()
116
- shut()
117
-
118
- let args: unknown[] = []
119
- if (typed !== '') {
120
- let parsed: unknown
121
- try {
122
- parsed = JSON.parse(typed)
123
- } catch (thrown) {
124
- return refuse(`that is not JSON: ${thrown instanceof Error ? thrown.message : String(thrown)}. Nothing was called.`)
125
- }
126
- args = Array.isArray(parsed) ? parsed : [parsed]
127
- }
128
-
129
- const env: Env = argv.includes(PRODUCTION) ? 'production' : 'sandbox'
130
-
131
- const opening = opened(findTree().at, declared.requires, env)
132
- let resolved: Readonly<Record<string, string>>
133
- try {
134
- resolved = await opening(declared.requires)
135
- } catch (thrown) {
136
- return refuse(thrown instanceof Error ? thrown.message : String(thrown))
137
- }
138
- const credentials = declared.requires.map((one) => resolved[one] ?? '')
139
-
140
- let mod: Record<string, unknown>
141
- try {
142
- mod = (await import(declared.module)) as Record<string, unknown>
143
- } catch (thrown) {
144
- return refuse(
145
- `\`${declared.module}\` could not be imported: ${thrown instanceof Error ? thrown.message : String(thrown)}. It was ` +
146
- `installed when this was declared — if it is gone, \`npm install ${declared.module}\` puts it back.`,
147
- )
148
- }
149
-
150
- const entry: unknown = mod.default ?? mod
151
-
152
- const asFunction = entry as (...a: readonly unknown[]) => unknown
153
- const asConstructor = entry as new (...a: readonly unknown[]) => unknown
154
-
155
- const REACHES = new Set(['constructor', '__proto__', 'prototype'])
156
-
157
- const client: unknown =
158
- typeof entry !== 'function' ? entry : isClass(asFunction) ? Reflect.construct(asConstructor, credentials) : asFunction(...credentials)
159
-
160
- let owner: unknown = client
161
- let target: unknown = client
162
- for (const segment of method.split('.')) {
163
- if (REACHES.has(segment)) {
164
- return refuse(
165
- `\`${segment}\` is not an operation of \`${declared.module}\` — it is a step every JavaScript value has, and ` +
166
- 'walking to it leaves what was installed. What may run here is what the module exports, and a person fixed that ' +
167
- 'set when they declared it.',
168
- )
169
- }
170
- owner = target
171
- target = (target as Record<string, unknown> | null | undefined)?.[segment]
172
- }
173
- if (typeof target !== 'function') {
174
- return refuse(`\`${method}\` on \`${declared.module}\` is ${target === undefined ? 'nothing' : `a ${typeof target}`}, not a method that can be called`)
175
- }
176
-
177
- let result: unknown
178
- try {
179
- result = await (target as (...a: unknown[]) => unknown).apply(owner, args)
180
- } catch (thrown) {
181
- return refuse(`\`${method}\` on \`${declared.module}\` threw: ${thrown instanceof Error ? thrown.message : String(thrown)}`)
182
- }
183
-
184
- stdout.write(`${declared.name}: ${method} (${env})\n`)
185
- try {
186
- stdout.write(`${JSON.stringify(result, null, 2)}\n`)
187
- } catch {
188
- stdout.write(`${String(result)}\n`)
189
- }
190
- exit(0)
191
- }
@@ -1,104 +0,0 @@
1
- import { existsSync, readdirSync, readFileSync } from "../../core/files.js";
2
- import { resolve } from 'node:path';
3
- const STORES = 'src/stores';
4
- /* What hands an operation its seams, seeded once and then the app's own. */
5
- const SEAMS = 'src/seams.ts';
6
- /* What the declarations settle, which the seams file is expected to hand on. */
7
- const DECLARED = 'DECLARED';
8
- /*
9
- * WHAT THIS READS, AND WHY IT READS THAT RATHER THAN THE TARGETS SHEET.
10
- *
11
- * A target that keeps entities derives a store of its own, written by `thread schema` into
12
- * `src/stores/<target>.ts`. So one of those files existing IS the fact that this app declares
13
- * somewhere to keep rows — already resolved, by the command that resolved it, with no second reading
14
- * of what a reach can hold and no chance of the two disagreeing about it.
15
- *
16
- * Where rows go is settled in `src/_generated/seams.ts`, which `thread capabilities` writes from those
17
- * stores and refuses when it drifts. The one place it can still go wrong is `src/seams.ts`, which is
18
- * the app's own: an app that stops handing on what was settled there hands its operations a store
19
- * that keeps nothing, while the tables are written, the migrations are written, and the gate is green.
20
- */
21
- function held(root, at) {
22
- const path = resolve(root, at);
23
- try {
24
- return existsSync(path) ? readFileSync(path, 'utf8') : '';
25
- }
26
- catch {
27
- return '';
28
- }
29
- }
30
- function derived(root) {
31
- const at = resolve(root, STORES);
32
- try {
33
- return existsSync(at) ? readdirSync(at).filter((one) => one.endsWith('.ts')) : [];
34
- }
35
- catch {
36
- return [];
37
- }
38
- }
39
- export const slopnator = {
40
- checks: (root) => {
41
- const stores = derived(root);
42
- if (stores.length === 0)
43
- return [];
44
- /*
45
- * AN APP WITH NOTHING THAT HANDS A STORE TO AN OPERATION IS NOT KEEPING ROWS THROUGH ONE, SO
46
- * THERE IS NOTHING TO REFUSE.
47
- *
48
- * The seams file is seeded by `thread capabilities`, which ships in the operations package — so
49
- * an app that attached data and integrity and nothing else has no seams and no command that
50
- * seeds one. Its absence means rows go nowhere yet, which is a state to pass rather than refuse:
51
- * nothing is being lost, because nothing is being kept.
52
- */
53
- const where = held(root, SEAMS);
54
- if (where === '')
55
- return [];
56
- if (where.includes(DECLARED))
57
- return [];
58
- return [
59
- `${STORES} holds ${stores.join(', ')} and ${SEAMS} no longer hands on ${DECLARED}, so every row this app keeps goes ` +
60
- 'somewhere that is gone the moment it stops. The tables are written, the migrations are written, the gate is ' +
61
- `green, and the database is never opened. Spread ${DECLARED} back into SEAMS, or name its store there`,
62
- ];
63
- },
64
- proves: {
65
- wrong: [
66
- {
67
- files: [
68
- { at: 'src/stores/pl_probe.ts', source: 'export const store = {}\n' },
69
- {
70
- at: 'src/seams.ts',
71
- source: "import { inMemorySeams } from '../../operations/memory.ts'\n\nexport const SEAMS = inMemorySeams().seams\n",
72
- },
73
- ],
74
- at: 'src/seams.ts',
75
- },
76
- ],
77
- right: [
78
- {
79
- files: [
80
- { at: 'src/stores/pl_probe.ts', source: 'export const store = {}\n' },
81
- {
82
- at: 'src/seams.ts',
83
- source: "import { DECLARED } from './_generated/seams.ts'\n\nexport const SEAMS = { ...DECLARED }\n",
84
- },
85
- ],
86
- at: 'src/seams.ts',
87
- },
88
- /* An app that derived a store and has nothing handing one to an operation — data attached, operations not. */
89
- {
90
- files: [{ at: 'src/stores/pl_probe.ts', source: 'export const store = {}\n' }],
91
- at: 'src/seams.ts',
92
- },
93
- {
94
- files: [
95
- {
96
- at: 'src/seams.ts',
97
- source: "import { inMemorySeams } from '../../operations/memory.ts'\n\nexport const SEAMS = inMemorySeams().seams\n",
98
- },
99
- ],
100
- at: 'src/seams.ts',
101
- },
102
- ],
103
- },
104
- };
@@ -1,111 +0,0 @@
1
- import { existsSync, readdirSync, readFileSync } from '../../core/files.ts'
2
- import { resolve } from 'node:path'
3
-
4
- import type { Slopnator } from '../slopnator.ts'
5
-
6
- const STORES = 'src/stores'
7
-
8
- /* What hands an operation its seams, seeded once and then the app's own. */
9
- const SEAMS = 'src/seams.ts'
10
-
11
- /* What the declarations settle, which the seams file is expected to hand on. */
12
- const DECLARED = 'DECLARED'
13
-
14
- /*
15
- * WHAT THIS READS, AND WHY IT READS THAT RATHER THAN THE TARGETS SHEET.
16
- *
17
- * A target that keeps entities derives a store of its own, written by `thread schema` into
18
- * `src/stores/<target>.ts`. So one of those files existing IS the fact that this app declares
19
- * somewhere to keep rows — already resolved, by the command that resolved it, with no second reading
20
- * of what a reach can hold and no chance of the two disagreeing about it.
21
- *
22
- * Where rows go is settled in `src/_generated/seams.ts`, which `thread capabilities` writes from those
23
- * stores and refuses when it drifts. The one place it can still go wrong is `src/seams.ts`, which is
24
- * the app's own: an app that stops handing on what was settled there hands its operations a store
25
- * that keeps nothing, while the tables are written, the migrations are written, and the gate is green.
26
- */
27
- function held(root: string, at: string): string {
28
- const path = resolve(root, at)
29
- try {
30
- return existsSync(path) ? readFileSync(path, 'utf8') : ''
31
- } catch {
32
- return ''
33
- }
34
- }
35
-
36
- function derived(root: string): readonly string[] {
37
- const at = resolve(root, STORES)
38
- try {
39
- return existsSync(at) ? readdirSync(at).filter((one) => one.endsWith('.ts')) : []
40
- } catch {
41
- return []
42
- }
43
- }
44
-
45
- export const slopnator: Slopnator = {
46
- checks: (root) => {
47
- const stores = derived(root)
48
- if (stores.length === 0) return []
49
-
50
- /*
51
- * AN APP WITH NOTHING THAT HANDS A STORE TO AN OPERATION IS NOT KEEPING ROWS THROUGH ONE, SO
52
- * THERE IS NOTHING TO REFUSE.
53
- *
54
- * The seams file is seeded by `thread capabilities`, which ships in the operations package — so
55
- * an app that attached data and integrity and nothing else has no seams and no command that
56
- * seeds one. Its absence means rows go nowhere yet, which is a state to pass rather than refuse:
57
- * nothing is being lost, because nothing is being kept.
58
- */
59
- const where = held(root, SEAMS)
60
- if (where === '') return []
61
-
62
- if (where.includes(DECLARED)) return []
63
-
64
- return [
65
- `${STORES} holds ${stores.join(', ')} and ${SEAMS} no longer hands on ${DECLARED}, so every row this app keeps goes ` +
66
- 'somewhere that is gone the moment it stops. The tables are written, the migrations are written, the gate is ' +
67
- `green, and the database is never opened. Spread ${DECLARED} back into SEAMS, or name its store there`,
68
- ]
69
- },
70
- proves: {
71
- wrong: [
72
- {
73
- files: [
74
- { at: 'src/stores/pl_probe.ts', source: 'export const store = {}\n' },
75
- {
76
- at: 'src/seams.ts',
77
- source: "import { inMemorySeams } from '../../operations/memory.ts'\n\nexport const SEAMS = inMemorySeams().seams\n",
78
- },
79
- ],
80
- at: 'src/seams.ts',
81
- },
82
- ],
83
- right: [
84
- {
85
- files: [
86
- { at: 'src/stores/pl_probe.ts', source: 'export const store = {}\n' },
87
- {
88
- at: 'src/seams.ts',
89
- source: "import { DECLARED } from './_generated/seams.ts'\n\nexport const SEAMS = { ...DECLARED }\n",
90
- },
91
- ],
92
- at: 'src/seams.ts',
93
- },
94
-
95
- /* An app that derived a store and has nothing handing one to an operation — data attached, operations not. */
96
- {
97
- files: [{ at: 'src/stores/pl_probe.ts', source: 'export const store = {}\n' }],
98
- at: 'src/seams.ts',
99
- },
100
- {
101
- files: [
102
- {
103
- at: 'src/seams.ts',
104
- source: "import { inMemorySeams } from '../../operations/memory.ts'\n\nexport const SEAMS = inMemorySeams().seams\n",
105
- },
106
- ],
107
- at: 'src/seams.ts',
108
- },
109
- ],
110
- },
111
- }
@@ -1,73 +0,0 @@
1
- import { isBuiltin } from 'node:module';
2
- import { parser } from 'typescript-eslint';
3
- const CODE = /\.(?:ts|tsx|mts|cts|js|jsx|mjs|cjs)$/;
4
- const MENTIONS = /\bimport\b|\brequire\s*\(/;
5
- function reached(node, seen, found) {
6
- if (typeof node !== 'object' || node === null)
7
- return;
8
- if (seen.has(node))
9
- return;
10
- seen.add(node);
11
- if (Array.isArray(node)) {
12
- for (const each of node)
13
- reached(each, seen, found);
14
- return;
15
- }
16
- const one = node;
17
- const type = one['type'];
18
- if (type === 'ImportDeclaration' || type === 'ImportExpression' || type === 'ExportNamedDeclaration' || type === 'ExportAllDeclaration') {
19
- const source = one['source'];
20
- if (typeof source?.value === 'string')
21
- found(source.value);
22
- }
23
- if (type === 'CallExpression') {
24
- const callee = one['callee'];
25
- if (callee?.type === 'Identifier' && callee.name === 'require') {
26
- const first = one['arguments']?.[0];
27
- if (typeof first?.value === 'string')
28
- found(first.value);
29
- }
30
- }
31
- for (const held of Object.values(one))
32
- reached(held, seen, found);
33
- }
34
- export const slopnator = {
35
- holds: (_node, at) => {
36
- if (!CODE.test(at.filename))
37
- return false;
38
- const text = String(at.text);
39
- if (!MENTIONS.test(text))
40
- return false;
41
- let ast;
42
- try {
43
- ast = parser.parseForESLint(text, {
44
- range: true,
45
- ecmaVersion: 'latest',
46
- sourceType: 'module',
47
- ecmaFeatures: { jsx: true },
48
- }).ast;
49
- }
50
- catch {
51
- return false;
52
- }
53
- const taken = new Set();
54
- reached(ast, new WeakSet(), (one) => {
55
- if (isBuiltin(one))
56
- taken.add(one);
57
- });
58
- if (taken.size === 0)
59
- return false;
60
- return `this reaches ${[...taken].sort().join(', ')} straight from the runtime, and a node is handed everything it may touch`;
61
- },
62
- proves: {
63
- wrong: [
64
- "import { readFileSync } from 'node:fs'\nexport const node = readFileSync\n",
65
- "const { spawn } = require('child_process')\nexport const node = spawn\n",
66
- "export const node = async () => await import('node:net')\n",
67
- ],
68
- right: [
69
- "import { nd_read } from '../../operations/nodes.ts'\nexport const node = nd_read(async (hands) => await hands.store.get('a', 'b'))\n",
70
- "import type { In } from './input.ts'\nexport const node = null as unknown as In\n",
71
- ],
72
- },
73
- };
@@ -1,79 +0,0 @@
1
- import { isBuiltin } from 'node:module'
2
-
3
- import { parser } from 'typescript-eslint'
4
-
5
- import type { Slopnator } from '../slopnator.ts'
6
-
7
- const CODE = /\.(?:ts|tsx|mts|cts|js|jsx|mjs|cjs)$/
8
-
9
- const MENTIONS = /\bimport\b|\brequire\s*\(/
10
-
11
- function reached(node: unknown, seen: WeakSet<object>, found: (one: string) => void): void {
12
- if (typeof node !== 'object' || node === null) return
13
- if (seen.has(node)) return
14
- seen.add(node)
15
-
16
- if (Array.isArray(node)) {
17
- for (const each of node) reached(each, seen, found)
18
- return
19
- }
20
-
21
- const one = node as Record<string, unknown>
22
- const type = one['type']
23
-
24
- if (type === 'ImportDeclaration' || type === 'ImportExpression' || type === 'ExportNamedDeclaration' || type === 'ExportAllDeclaration') {
25
- const source = one['source'] as { readonly value?: unknown } | null | undefined
26
- if (typeof source?.value === 'string') found(source.value)
27
- }
28
-
29
- if (type === 'CallExpression') {
30
- const callee = one['callee'] as { readonly type?: unknown; readonly name?: unknown } | null | undefined
31
- if (callee?.type === 'Identifier' && callee.name === 'require') {
32
- const first = (one['arguments'] as readonly { readonly value?: unknown }[] | undefined)?.[0]
33
- if (typeof first?.value === 'string') found(first.value)
34
- }
35
- }
36
-
37
- for (const held of Object.values(one)) reached(held, seen, found)
38
- }
39
-
40
- export const slopnator: Slopnator = {
41
- holds: (_node, at) => {
42
- if (!CODE.test(at.filename)) return false
43
-
44
- const text = String(at.text)
45
- if (!MENTIONS.test(text)) return false
46
-
47
- let ast: unknown
48
- try {
49
- ast = (parser.parseForESLint as (text: string, options: unknown) => { readonly ast: unknown })(text, {
50
- range: true,
51
- ecmaVersion: 'latest',
52
- sourceType: 'module',
53
- ecmaFeatures: { jsx: true },
54
- }).ast
55
- } catch {
56
- return false
57
- }
58
-
59
- const taken = new Set<string>()
60
- reached(ast, new WeakSet<object>(), (one) => {
61
- if (isBuiltin(one)) taken.add(one)
62
- })
63
-
64
- if (taken.size === 0) return false
65
-
66
- return `this reaches ${[...taken].sort().join(', ')} straight from the runtime, and a node is handed everything it may touch`
67
- },
68
- proves: {
69
- wrong: [
70
- "import { readFileSync } from 'node:fs'\nexport const node = readFileSync\n",
71
- "const { spawn } = require('child_process')\nexport const node = spawn\n",
72
- "export const node = async () => await import('node:net')\n",
73
- ],
74
- right: [
75
- "import { nd_read } from '../../operations/nodes.ts'\nexport const node = nd_read(async (hands) => await hands.store.get('a', 'b'))\n",
76
- "import type { In } from './input.ts'\nexport const node = null as unknown as In\n",
77
- ],
78
- },
79
- }
@@ -1,14 +0,0 @@
1
- export interface CostAmount {
2
- readonly usdMicroCents: number;
3
- readonly chargedMicroCents: number;
4
- readonly currency: string;
5
- readonly meter: string;
6
- }
7
- export declare class InvalidCostError extends Error {
8
- constructor(message: string);
9
- }
10
- export declare function assertValidCost(cost: CostAmount): void;
11
- export declare const MICRO_CENTS_PER_CENT = 1000000;
12
- export declare const MICRO_CENTS_PER_UNIT = 100000000;
13
- export declare function toMicroCents(amount: number): number;
14
- export declare function fromMicroCents(microCents: number): number;
@@ -1,37 +0,0 @@
1
- export class InvalidCostError extends Error {
2
- constructor(message) {
3
- super(message);
4
- this.name = 'InvalidCostError';
5
- }
6
- }
7
- function assertIntegerMicroCents(value, field) {
8
- if (!Number.isFinite(value) || !Number.isInteger(value)) {
9
- throw new InvalidCostError(`${field} must be an integer number of micro-cents, received ${value}. ` +
10
- 'Convert before recording — never round.');
11
- }
12
- if (value < 0)
13
- throw new InvalidCostError(`${field} must not be negative, received ${value}`);
14
- }
15
- export function assertValidCost(cost) {
16
- assertIntegerMicroCents(cost.usdMicroCents, 'usdMicroCents');
17
- assertIntegerMicroCents(cost.chargedMicroCents, 'chargedMicroCents');
18
- if (typeof cost.currency !== 'string' || cost.currency.trim() === '') {
19
- throw new InvalidCostError('cost.currency is required and has no default — resolve it from real data (DATA.md §8)');
20
- }
21
- if (!/^[A-Z]{3}$/.test(cost.currency)) {
22
- throw new InvalidCostError(`cost.currency must be an ISO-4217 code, received "${cost.currency}"`);
23
- }
24
- if (typeof cost.meter !== 'string' || cost.meter.trim() === '') {
25
- throw new InvalidCostError('cost.meter is required — a cost with no meter cannot be quota-checked');
26
- }
27
- }
28
- export const MICRO_CENTS_PER_CENT = 1_000_000;
29
- export const MICRO_CENTS_PER_UNIT = 100_000_000;
30
- export function toMicroCents(amount) {
31
- if (!Number.isFinite(amount))
32
- throw new InvalidCostError(`cannot convert ${amount} to micro-cents`);
33
- return Math.round(amount * MICRO_CENTS_PER_UNIT);
34
- }
35
- export function fromMicroCents(microCents) {
36
- return microCents / MICRO_CENTS_PER_UNIT;
37
- }
@@ -1,58 +0,0 @@
1
- export interface CostAmount {
2
-
3
- readonly usdMicroCents: number
4
-
5
- readonly chargedMicroCents: number
6
-
7
- readonly currency: string
8
-
9
- readonly meter: string
10
- }
11
-
12
- export class InvalidCostError extends Error {
13
- constructor(message: string) {
14
- super(message)
15
- this.name = 'InvalidCostError'
16
- }
17
- }
18
-
19
- function assertIntegerMicroCents(value: number, field: string): void {
20
- if (!Number.isFinite(value) || !Number.isInteger(value)) {
21
-
22
- throw new InvalidCostError(
23
- `${field} must be an integer number of micro-cents, received ${value}. ` +
24
- 'Convert before recording — never round.',
25
- )
26
- }
27
- if (value < 0) throw new InvalidCostError(`${field} must not be negative, received ${value}`)
28
- }
29
-
30
- export function assertValidCost(cost: CostAmount): void {
31
- assertIntegerMicroCents(cost.usdMicroCents, 'usdMicroCents')
32
- assertIntegerMicroCents(cost.chargedMicroCents, 'chargedMicroCents')
33
-
34
- if (typeof cost.currency !== 'string' || cost.currency.trim() === '') {
35
- throw new InvalidCostError(
36
- 'cost.currency is required and has no default — resolve it from real data (DATA.md §8)',
37
- )
38
- }
39
- if (!/^[A-Z]{3}$/.test(cost.currency)) {
40
- throw new InvalidCostError(`cost.currency must be an ISO-4217 code, received "${cost.currency}"`)
41
- }
42
- if (typeof cost.meter !== 'string' || cost.meter.trim() === '') {
43
- throw new InvalidCostError('cost.meter is required — a cost with no meter cannot be quota-checked')
44
- }
45
- }
46
-
47
- export const MICRO_CENTS_PER_CENT = 1_000_000
48
-
49
- export const MICRO_CENTS_PER_UNIT = 100_000_000
50
-
51
- export function toMicroCents(amount: number): number {
52
- if (!Number.isFinite(amount)) throw new InvalidCostError(`cannot convert ${amount} to micro-cents`)
53
- return Math.round(amount * MICRO_CENTS_PER_UNIT)
54
- }
55
-
56
- export function fromMicroCents(microCents: number): number {
57
- return microCents / MICRO_CENTS_PER_UNIT
58
- }