@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,206 @@
1
+ import type { Actor } from '../core/actor.ts'
2
+ import type { FieldList, Row, Store } from './target.ts'
3
+
4
+ const SHAPE = `
5
+ select table_name, column_name, data_type, is_nullable
6
+ from information_schema.columns
7
+ where table_schema = 'public'
8
+ order by table_name, column_name
9
+ `
10
+
11
+ const CONSTRAINTS = `
12
+ select tc.table_name, tc.constraint_type, kcu.column_name
13
+ from information_schema.table_constraints tc
14
+ left join information_schema.key_column_usage kcu on kcu.constraint_name = tc.constraint_name
15
+ where tc.table_schema = 'public'
16
+ order by tc.table_name, tc.constraint_type, kcu.column_name
17
+ `
18
+
19
+ interface Queried {
20
+ exec(sql: string): Promise<unknown>
21
+ query(sql: string, params?: readonly unknown[]): Promise<{ rows: readonly unknown[] }>
22
+ close(): Promise<void>
23
+ }
24
+
25
+ const MISSING =
26
+ 'a postgres living inside this process needs `@electric-sql/pglite`, and it is not installed. No package here ' +
27
+ 'declares it, because nothing needs one until a target is declared that keeps rows in one — install it in the ' +
28
+ 'app that declares that target. Carrying on without having opened one would be the drift this exists to catch, ' +
29
+ 'wearing a green tick'
30
+
31
+ async function opened(at?: string): Promise<Queried> {
32
+ let made: { PGlite: new (at?: string) => Queried }
33
+ try {
34
+ made = (await import('@electric-sql/pglite')) as unknown as { PGlite: new (at?: string) => Queried }
35
+ } catch {
36
+ throw new Error(MISSING)
37
+ }
38
+ return new made.PGlite(at)
39
+ }
40
+
41
+ const APPLIED = '"_thread_applied"'
42
+
43
+ async function caughtUp(made: Queried, history: readonly { readonly name: string; readonly sql: string }[]): Promise<void> {
44
+ if (history.length === 0) return
45
+ await made.exec('create table if not exists ' + APPLIED + ' ("name" text primary key)')
46
+ const done = new Set(
47
+ (await made.query('select "name" from ' + APPLIED)).rows.map((one) => String((one as { readonly name?: unknown }).name)),
48
+ )
49
+ for (const one of history) {
50
+ if (done.has(one.name)) continue
51
+ await made.exec(one.sql)
52
+ await made.query('insert into ' + APPLIED + ' ("name") values ($1)', [one.name])
53
+ }
54
+ }
55
+
56
+ export async function shapeOf(sql: readonly string[]): Promise<string> {
57
+ const db = await opened()
58
+ try {
59
+ for (const one of sql) await db.exec(one)
60
+ const columns = await db.query(SHAPE)
61
+ const constraints = await db.query(CONSTRAINTS)
62
+ return JSON.stringify({ columns: columns.rows, constraints: constraints.rows }, null, 2)
63
+ } finally {
64
+ await db.close()
65
+ }
66
+ }
67
+
68
+ export interface Kept {
69
+
70
+ readonly name: string
71
+
72
+ readonly schema: string
73
+
74
+ readonly tables: Readonly<Record<string, string>>
75
+
76
+ readonly address: Readonly<Record<string, string>>
77
+
78
+ readonly columns: Readonly<Record<string, readonly string[]>>
79
+
80
+ readonly at: string
81
+
82
+ readonly migrations?: readonly { readonly name: string; readonly sql: string }[]
83
+ }
84
+
85
+ export interface Stood {
86
+
87
+ readonly keeps: readonly string[]
88
+
89
+ readonly store: Store
90
+
91
+ seed(actor: Actor, rows: readonly { readonly entity: string; readonly row: Row }[]): Promise<void>
92
+
93
+ taken(actor: Actor): Promise<Readonly<Record<string, readonly Row[]>>>
94
+ }
95
+
96
+ export function standing(held: Omit<Kept, 'at'>): Stood {
97
+ const store = storing({ ...held, at: 'memory://', migrations: [] })
98
+ const keeps = Object.keys(held.tables)
99
+ return {
100
+ keeps,
101
+ store,
102
+ async seed(actor, rows) {
103
+ for (const one of rows) await store.insert(actor, one.entity, one.row)
104
+ },
105
+ async taken(actor) {
106
+ const found: Record<string, readonly Row[]> = {}
107
+ for (const entity of keeps) found[entity] = await store.list(actor, entity)
108
+ return found
109
+ },
110
+ }
111
+ }
112
+
113
+ export function storing(held: Kept): Store {
114
+ const q = (name: string): string => JSON.stringify(name)
115
+ const rowOf = (one: unknown): Row => one as Row
116
+ const known = (entity: string): readonly string[] => held.columns[entity] ?? []
117
+
118
+ const tableFor = (entity: string): string => {
119
+ const found = held.tables[entity]
120
+ if (found === undefined) throw new Error(entity + ' is not kept in ' + held.name + ', so it has no table here')
121
+ return found
122
+ }
123
+
124
+ const addressOf = (entity: string): string => {
125
+ const found = held.address[entity]
126
+ if (found === undefined) {
127
+ throw new Error(
128
+ entity + ' declares nothing that identifies one of its rows, so a row of it cannot be addressed here. ' +
129
+ 'Give it a value and say so with `thread create entity edit`.',
130
+ )
131
+ }
132
+ return found
133
+ }
134
+
135
+ let opening: Promise<Queried> | undefined
136
+
137
+ const db = async (): Promise<Queried> => {
138
+ opening ??= (async () => {
139
+ const made = await opened(held.at)
140
+ await caughtUp(made, held.migrations ?? [])
141
+ await made.exec(held.schema)
142
+ return made
143
+ })()
144
+ return await opening
145
+ }
146
+
147
+ return {
148
+ async insert(_actor, entity, row) {
149
+ const cols = known(entity)
150
+ const taken = cols.filter((one) => (row as Record<string, unknown>)[one] !== undefined)
151
+ const answered = await (await db()).query(
152
+ 'insert into ' + q(tableFor(entity)) + ' (' + taken.map(q).join(', ') + ') values (' +
153
+ taken.map((_, at) => '$' + String(at + 1)).join(', ') + ') returning *',
154
+ taken.map((one) => (row as Record<string, unknown>)[one]),
155
+ )
156
+ return rowOf(answered.rows[0])
157
+ },
158
+
159
+ async get(_actor, entity, key, fields: FieldList) {
160
+ const cols = known(entity)
161
+ const asked = fields.filter((one) => cols.includes(one as string)).map((one) => String(one))
162
+ const answered = await (await db()).query(
163
+ 'select ' + (asked.length === 0 ? '*' : asked.map(q).join(', ')) + ' from ' + q(tableFor(entity)) +
164
+ ' where ' + q(addressOf(entity)) + ' = $1 limit 1',
165
+ [key],
166
+ )
167
+ return answered.rows.length === 0 ? null : rowOf(answered.rows[0])
168
+ },
169
+
170
+ async list(_actor, entity, opts) {
171
+ const cols = known(entity)
172
+ const asked = Object.entries(opts?.where ?? {}).filter(([one]) => cols.includes(one))
173
+ const answered = await (await db()).query(
174
+ 'select * from ' + q(tableFor(entity)) +
175
+ (asked.length === 0 ? '' : ' where ' + asked.map(([one], at) => q(one) + ' = $' + String(at + 1)).join(' and ')) +
176
+ (opts?.limit === undefined ? '' : ' limit ' + String(opts.limit)),
177
+ asked.map(([, one]) => one),
178
+ )
179
+ return answered.rows.map(rowOf)
180
+ },
181
+
182
+ async update(_actor, entity, key, patch, expectedVersion) {
183
+ if (expectedVersion !== undefined) {
184
+ throw new Error(
185
+ held.name + ' keeps what ' + entity + ' declares and nothing else, so there is no version on a row to ' +
186
+ 'check an expected one against. Declare a value for it and compare that, or update without a version.',
187
+ )
188
+ }
189
+ const cols = known(entity)
190
+ const taken = Object.entries(patch).filter(([one]) => cols.includes(one))
191
+ if (taken.length === 0) throw new Error('nothing in this patch is a value ' + entity + ' declares')
192
+ const answered = await (await db()).query(
193
+ 'update ' + q(tableFor(entity)) + ' set ' +
194
+ taken.map(([one], at) => q(one) + ' = $' + String(at + 1)).join(', ') +
195
+ ' where ' + q(addressOf(entity)) + ' = $' + String(taken.length + 1) + ' returning *',
196
+ [...taken.map(([, one]) => one), key],
197
+ )
198
+ if (answered.rows.length === 0) throw new Error('record ' + String(key) + ' not found')
199
+ return rowOf(answered.rows[0])
200
+ },
201
+
202
+ async remove(_actor, entity, key) {
203
+ await (await db()).query('delete from ' + q(tableFor(entity)) + ' where ' + q(addressOf(entity)) + ' = $1', [key])
204
+ },
205
+ }
206
+ }
@@ -1,14 +1,20 @@
1
1
  import type { Member } from '../core/thread.ts';
2
2
  export declare const SECRECY: {
3
- readonly server: "sec_";
4
- readonly public: "pub_";
3
+ readonly server: 'sec_';
5
4
  };
6
5
  export declare const SAID: Readonly<Record<keyof typeof SECRECY, string>>;
6
+ export interface Vault {
7
+ resolve(refs: readonly string[]): Promise<Readonly<Record<string, string>>>;
8
+ }
7
9
  export interface Secret extends Member {
8
10
  readonly sends?: {
9
11
  readonly header: string;
10
12
  readonly prefix?: string;
11
13
  };
14
+ readonly signs?: {
15
+ readonly header: string;
16
+ readonly prefix?: string;
17
+ };
12
18
  }
13
19
  export declare function secrecyOf(id: string): keyof typeof SECRECY | undefined;
14
20
  export declare const isServerOnly: (id: string) => boolean;
@@ -1,10 +1,8 @@
1
1
  export const SECRECY = {
2
2
  server: 'sec_',
3
- public: 'pub_',
4
3
  };
5
4
  export const SAID = {
6
- server: 'A value only a server may ever hold — an API key, a connection string, a signing secret. Everything a browser bundle reaches is in the bundle and belongs to whoever opens the page, so a target requiring one of these is refused a browser entry when it is built rather than when somebody reads it.',
7
- public: 'A value that may reach a browser: a base url, a publishable key, a project id. It is still a secret and still lives in the sealed store, because it still differs between a sandbox and production and nothing else here keeps that difference. What it is not is a thing that has to be withheld.',
5
+ server: 'A value only a server may ever hold: an API key, a connection string, a signing key. Every secret is one of these. A value anybody may read is not a secret and is never sealed — the address of a place this app calls and a header every call carries are written on the target row, and only a credential goes into the vault. Everything a browser bundle reaches is in the bundle and belongs to whoever opens the page, so a target requiring a secret is refused a browser entry when it is built rather than when somebody reads it.',
8
6
  };
9
7
  export function secrecyOf(id) {
10
8
  return Object.keys(SECRECY).find((one) => id.startsWith(SECRECY[one]));
@@ -12,8 +10,8 @@ export function secrecyOf(id) {
12
10
  export const isServerOnly = (id) => secrecyOf(id) === 'server';
13
11
  export const unclassified = (secrets) => secrets
14
12
  .filter((one) => secrecyOf(one.id) === undefined)
15
- .map((one) => `\`${one.id}\` wears neither \`${SECRECY.server}\` nor \`${SECRECY.public}\`, so nothing can tell whether it may ` +
16
- 'reach a browser — and that prefix is the only thing standing between a server credential and a bundle');
13
+ .map((one) => one.id + ' does not wear ' + SECRECY.server + ', and every secret does: that prefix says only a server may ever hold the value. ' +
14
+ 'A value anybody may read is not a secret. Write it on the row that needs it, as the address of a target or a header every call carries, and take this row out');
17
15
  const VALUED = ['value', 'secret', 'key', 'token', 'password', 'env'];
18
16
  export const valued = (secrets) => {
19
17
  const found = [];
@@ -2,19 +2,23 @@ import type { Member } from '../core/thread.ts'
2
2
 
3
3
  export const SECRECY = {
4
4
  server: 'sec_',
5
- public: 'pub_',
6
5
  } as const satisfies Readonly<Record<string, string>>
7
6
 
8
7
  export const SAID: Readonly<Record<keyof typeof SECRECY, string>> = {
9
8
  server:
10
- 'A value only a server may ever hold — an API key, a connection string, a signing secret. Everything a browser bundle reaches is in the bundle and belongs to whoever opens the page, so a target requiring one of these is refused a browser entry when it is built rather than when somebody reads it.',
11
- public:
12
- 'A value that may reach a browser: a base url, a publishable key, a project id. It is still a secret and still lives in the sealed store, because it still differs between a sandbox and production and nothing else here keeps that difference. What it is not is a thing that has to be withheld.',
9
+ 'A value only a server may ever hold: an API key, a connection string, a signing key. Every secret is one of these. A value anybody may read is not a secret and is never sealed — the address of a place this app calls and a header every call carries are written on the target row, and only a credential goes into the vault. Everything a browser bundle reaches is in the bundle and belongs to whoever opens the page, so a target requiring a secret is refused a browser entry when it is built rather than when somebody reads it.',
10
+ }
11
+
12
+ export interface Vault {
13
+
14
+ resolve(refs: readonly string[]): Promise<Readonly<Record<string, string>>>
13
15
  }
14
16
 
15
17
  export interface Secret extends Member {
16
18
 
17
19
  readonly sends?: { readonly header: string; readonly prefix?: string }
20
+
21
+ readonly signs?: { readonly header: string; readonly prefix?: string }
18
22
  }
19
23
 
20
24
  export function secrecyOf(id: string): keyof typeof SECRECY | undefined {
@@ -28,8 +32,8 @@ export const unclassified = (secrets: readonly Secret[]): readonly string[] =>
28
32
  .filter((one) => secrecyOf(one.id) === undefined)
29
33
  .map(
30
34
  (one) =>
31
- `\`${one.id}\` wears neither \`${SECRECY.server}\` nor \`${SECRECY.public}\`, so nothing can tell whether it may ` +
32
- 'reach a browser — and that prefix is the only thing standing between a server credential and a bundle',
35
+ one.id + ' does not wear ' + SECRECY.server + ', and every secret does: that prefix says only a server may ever hold the value. ' +
36
+ 'A value anybody may read is not a secret. Write it on the row that needs it, as the address of a target or a header every call carries, and take this row out',
33
37
  )
34
38
 
35
39
  const VALUED = ['value', 'secret', 'key', 'token', 'password', 'env']
@@ -1,19 +1,26 @@
1
1
  import type { Member } from '../core/thread.ts';
2
+ import type { Actor } from '../core/actor.ts';
2
3
  import { type Secret } from './secret.ts';
3
4
  export declare const REACH: {
4
- readonly postgres: "pg_";
5
- readonly pglite: "pl_";
6
- readonly browser: "zu_";
7
- readonly https: "ht_";
8
- readonly module: "mod_";
9
- readonly cli: "cli_";
5
+ readonly postgres: 'pg_';
6
+ readonly pglite: 'pl_';
7
+ readonly browser: 'zu_';
8
+ readonly https: 'ht_';
9
+ readonly cli: 'cli_';
10
+ readonly disk: 'dsk_';
11
+ readonly sdk: 'sdk_';
10
12
  };
11
13
  export type Reach = keyof typeof REACH;
14
+ export declare const ADDRESS: {
15
+ readonly row: 'reached at the address written on its row, which anybody may read';
16
+ readonly secret: 'reached at a secret, because its address is a connection string and a connection string carries a password';
17
+ readonly nothing: 'addressed by nothing';
18
+ };
19
+ export type Addressed = keyof typeof ADDRESS;
12
20
  export interface Holds {
13
- readonly takes: 'entities' | 'calls' | 'names';
21
+ readonly takes: 'entities' | 'calls' | null;
14
22
  readonly from: 'server' | 'browser' | 'either';
15
- readonly addressed: boolean;
16
- readonly arrives: 'npm' | 'machine' | null;
23
+ readonly addressed: Addressed;
17
24
  readonly migrations: boolean;
18
25
  readonly references: boolean;
19
26
  readonly sql: boolean;
@@ -21,31 +28,165 @@ export interface Holds {
21
28
  }
22
29
  export declare const HOLDS: Readonly<Record<Reach, Holds>>;
23
30
  export declare const SAID: Readonly<Record<Reach, string>>;
31
+ export declare const OPENS: Readonly<Record<Reach, readonly string[]>>;
32
+ export type Kind = 'file' | 'folder' | 'other' | 'none';
33
+ export interface Listed {
34
+ readonly name: string;
35
+ readonly kind: Exclude<Kind, 'none'>;
36
+ }
37
+ export interface Measured {
38
+ readonly size: number;
39
+ readonly modified: number;
40
+ }
41
+ export interface Answering {
42
+ readonly kind: (at: string) => Kind;
43
+ readonly read: (at: string) => string;
44
+ readonly write: (at: string, said: string, mode?: number) => void;
45
+ readonly list: (at: string) => readonly Listed[];
46
+ readonly stat: (at: string) => Measured;
47
+ readonly remove: (at: string) => void;
48
+ readonly real: (at: string) => string;
49
+ }
50
+ export interface Attached extends Answering {
51
+ readonly fetch: (at: string) => string;
52
+ readonly run: (at: string, words: readonly string[]) => Ran;
53
+ }
54
+ export declare const ORDERS: {
55
+ readonly kind: 'kind';
56
+ readonly read: 'read';
57
+ readonly write: 'written';
58
+ readonly list: 'list';
59
+ readonly stat: 'stat';
60
+ readonly remove: 'removed';
61
+ readonly real: 'real';
62
+ readonly fetch: 'fetched';
63
+ readonly run: 'ran';
64
+ };
65
+ export interface Order {
66
+ readonly order: keyof typeof ORDERS;
67
+ readonly at: string;
68
+ readonly said?: string;
69
+ readonly mode?: number;
70
+ readonly words?: readonly string[];
71
+ }
72
+ export interface Answer {
73
+ readonly answered: string;
74
+ readonly found?: unknown;
75
+ readonly said?: string;
76
+ readonly at?: string;
77
+ readonly because?: string;
78
+ }
79
+ export interface Recorded {
80
+ readonly order: Order;
81
+ readonly answered: Answer;
82
+ }
83
+ export interface How {
84
+ readonly at?: string;
85
+ readonly hears?: string;
86
+ readonly of?: string;
87
+ readonly answered?: readonly Answer[];
88
+ readonly recording?: readonly Recorded[];
89
+ readonly answering?: number;
90
+ }
91
+ export interface Ran {
92
+ readonly there: boolean;
93
+ readonly ok: boolean;
94
+ readonly code: number;
95
+ readonly out: string;
96
+ readonly err: string;
97
+ readonly killed: string | null;
98
+ readonly why: string;
99
+ readonly of?: string;
100
+ readonly asks?: readonly Order[];
101
+ readonly lost?: string;
102
+ }
103
+ export type Running<C extends string = string> = Readonly<Record<C, (args: readonly string[], shows?: boolean | 'errors' | 'tee', within?: number, how?: How) => Promise<Ran>>>;
104
+ export type Calling<C extends string = string> = {
105
+ readonly [K in C]: (given?: unknown) => Promise<unknown>;
106
+ };
107
+ export type HttpMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
108
+ export interface HttpRequest {
109
+ readonly target: string;
110
+ readonly address: string;
111
+ readonly method: HttpMethod;
112
+ readonly path: string;
113
+ readonly headers?: Readonly<Record<string, string>>;
114
+ readonly body?: Uint8Array;
115
+ readonly contentType?: string;
116
+ readonly idempotencyKey?: string;
117
+ readonly told?: (said: unknown) => void;
118
+ }
119
+ export interface HttpResponse {
120
+ readonly status: number;
121
+ readonly headers: Readonly<Record<string, string>>;
122
+ readonly body: Uint8Array;
123
+ }
124
+ export interface Http {
125
+ call(request: HttpRequest, within?: number): Promise<HttpResponse>;
126
+ }
127
+ export type Row = Record<string, unknown>;
128
+ export type PropertyValue = string | number | boolean | null | readonly (string | number | boolean)[];
129
+ export declare function isRow(v: unknown): v is Row;
130
+ export type ReadField = `fld_${string}` | `rel_${string}` | (string & {});
131
+ export type FieldList = readonly [ReadField, ...ReadField[]];
132
+ export interface Store {
133
+ insert(actor: Actor, entity: string, row: Row): Promise<Row>;
134
+ get(actor: Actor, entity: string, key: string | number, fields: FieldList): Promise<Row | null>;
135
+ list(actor: Actor, entity: string, opts?: {
136
+ limit?: number;
137
+ where?: Readonly<Record<string, string | number | boolean | null>>;
138
+ }): Promise<Row[]>;
139
+ update(actor: Actor, entity: string, key: string | number, patch: Record<string, unknown>, expectedVersion?: number): Promise<Row>;
140
+ remove(actor: Actor, entity: string, key: string | number): Promise<void>;
141
+ }
142
+ export interface Transactional {
143
+ transaction<T>(actor: Actor, fn: () => Promise<T>): Promise<T>;
144
+ }
145
+ export declare function isTransactional(store: Store): store is Store & Transactional;
146
+ export interface Integration extends Member {
147
+ readonly needs?: Readonly<Record<string, string>>;
148
+ }
24
149
  export interface Target extends Member {
150
+ readonly of: string;
25
151
  readonly takes: readonly string[];
26
152
  readonly requires: readonly string[];
27
- readonly uses?: string;
28
- readonly offers?: readonly string[];
153
+ readonly address?: string;
154
+ readonly headers?: Readonly<Record<string, string>>;
155
+ }
156
+ export interface Webhook extends Member {
157
+ readonly of: string;
158
+ readonly path: string;
159
+ readonly arrives?: string;
160
+ readonly invokes: string;
29
161
  }
30
162
  export interface Call extends Member {
31
163
  readonly of: string;
32
- readonly method: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
164
+ readonly method?: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
33
165
  readonly path: string;
34
166
  }
35
167
  export declare const CALL_PREFIX = "cl_";
36
168
  export declare const fills: (one: Call) => readonly string[];
37
169
  export declare function reachOf(id: string): Reach | undefined;
170
+ export declare const standsHere: (one: Target, targets: readonly Target[]) => boolean;
38
171
  export declare function holdsOf(id: string): Holds | undefined;
172
+ export declare function requirable(targets: readonly Target[], calls: readonly Call[]): readonly Target[];
39
173
  export declare function driverOf(id: string): string | null;
40
174
  export declare function addressOf(one: Target, secrets: readonly Secret[]): Secret | undefined;
41
175
  export declare function credentialsOf(one: Target, secrets: readonly Secret[]): readonly Secret[];
42
176
  export declare function servesBrowser(one: Target, secrets: readonly Secret[]): true | string;
43
177
  export declare const unreachable: (targets: readonly Target[]) => readonly string[];
178
+ export declare const LOCKFILES: Readonly<Record<string, string>>;
179
+ export declare const PACKAGER = "packager";
180
+ export declare const managerOf: (at: string, there: (path: string) => boolean) => string;
181
+ export declare function programOf(name: string, at: string, there: (path: string) => boolean): string | undefined;
182
+ export declare const unlisted: (name: string) => string;
44
183
  export declare function misnamed(target: string, name: string): string | undefined;
45
184
  export declare function misaccepted(targets: readonly Target[], entities: readonly string[], calls: readonly Call[]): readonly string[];
185
+ export declare const placedAt: (targets: readonly Target[], id: string) => string;
186
+ export declare function placed(one: Target): readonly string[];
46
187
  export declare function unaddressed(targets: readonly Target[], secrets: readonly Secret[]): readonly string[];
47
188
  export declare function unheld(targets: readonly Target[], secrets: readonly Secret[]): readonly string[];
48
189
  export declare function unanswered(calls: readonly Call[], targets: readonly Target[]): readonly string[];
49
- export declare function misused(targets: readonly Target[]): readonly string[];
50
- export declare function refusals(targets: readonly Target[], secrets: readonly Secret[], calls: readonly Call[], entities: readonly string[]): readonly string[];
190
+ export declare function unplaced(targets: readonly Target[], integrations: readonly Integration[]): readonly string[];
191
+ export declare function refusals(targets: readonly Target[], secrets: readonly Secret[], calls: readonly Call[], entities: readonly string[], integrations: readonly Integration[]): readonly string[];
51
192
  export declare function targetOf(entity: string, targets: readonly Target[]): Target | string;