@prestack/thread 0.1.20 → 0.1.22

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 (148) hide show
  1. package/CHANGELOG.md +193 -0
  2. package/dist/core/attach.js +21 -0
  3. package/dist/core/descend.d.ts +2 -0
  4. package/dist/core/descend.js +18 -3
  5. package/dist/core/generators/commit.js +55 -3
  6. package/dist/core/generators/dev.d.ts +1 -0
  7. package/dist/core/generators/dev.js +68 -0
  8. package/dist/core/rows.d.ts +5 -0
  9. package/dist/core/rows.js +45 -0
  10. package/dist/core/tree.d.ts +1 -0
  11. package/dist/core/tree.js +7 -1
  12. package/dist/derivation/generators/build.d.ts +3 -1
  13. package/dist/derivation/generators/build.js +103 -22
  14. package/dist/derivation/generators/release.js +74 -26
  15. package/dist/derivation/release.js +3 -3
  16. package/dist/integrations/cli.d.ts +3 -9
  17. package/dist/integrations/cli.js +96 -36
  18. package/dist/integrations/declared.d.ts +8 -0
  19. package/dist/integrations/declared.js +22 -0
  20. package/dist/integrations/pglite.js +13 -3
  21. package/dist/integrations/target.d.ts +4 -1
  22. package/dist/integrations/target.js +20 -6
  23. package/dist/integrity/attach.js +1 -5
  24. package/dist/integrity/generators/publish.js +2 -1
  25. package/dist/integrity/slopnators/sl_stale_path.js +10 -0
  26. package/dist/integrity/slopnators/sl_unlisted_program.js +2 -2
  27. package/dist/operations/access.js +3 -2
  28. package/dist/operations/capabilities.d.ts +2 -0
  29. package/dist/operations/capabilities.js +2 -0
  30. package/dist/operations/generators/capability.js +234 -24
  31. package/dist/operations/generators/compile.d.ts +21 -0
  32. package/dist/operations/generators/compile.js +151 -51
  33. package/dist/operations/generators/permits.d.ts +2 -1
  34. package/dist/operations/generators/permits.js +52 -47
  35. package/dist/operations/generators/seed.d.ts +3 -0
  36. package/dist/operations/generators/seed.js +25 -3
  37. package/dist/operations/nodes.d.ts +2 -2
  38. package/package.json +1 -1
  39. package/dist/core/actor.ts +0 -21
  40. package/dist/core/attach.ts +0 -613
  41. package/dist/core/chain.ts +0 -145
  42. package/dist/core/condition.ts +0 -227
  43. package/dist/core/descend.ts +0 -1173
  44. package/dist/core/errors/catalogue.ts +0 -314
  45. package/dist/core/errors/classes.ts +0 -51
  46. package/dist/core/errors/error.ts +0 -152
  47. package/dist/core/errors/namespaces.ts +0 -19
  48. package/dist/core/finding.ts +0 -37
  49. package/dist/core/generators/commit.ts +0 -157
  50. package/dist/core/init.ts +0 -222
  51. package/dist/core/invoked.ts +0 -52
  52. package/dist/core/round.ts +0 -74
  53. package/dist/core/rows.ts +0 -459
  54. package/dist/core/scope.ts +0 -20
  55. package/dist/core/thread.ts +0 -29
  56. package/dist/core/tree.ts +0 -90
  57. package/dist/core/types.ts +0 -351
  58. package/dist/derivation/attach.ts +0 -57
  59. package/dist/derivation/generators/build.ts +0 -371
  60. package/dist/derivation/generators/check.ts +0 -118
  61. package/dist/derivation/generators/determinism.ts +0 -145
  62. package/dist/derivation/generators/release.ts +0 -236
  63. package/dist/derivation/release.ts +0 -43
  64. package/dist/integrations/attach.ts +0 -187
  65. package/dist/integrations/cli.ts +0 -615
  66. package/dist/integrations/disk.ts +0 -466
  67. package/dist/integrations/generators/read.ts +0 -127
  68. package/dist/integrations/generators/vault.ts +0 -210
  69. package/dist/integrations/https.ts +0 -216
  70. package/dist/integrations/pglite.ts +0 -206
  71. package/dist/integrations/secret.ts +0 -54
  72. package/dist/integrations/target.ts +0 -656
  73. package/dist/integrations/vault.ts +0 -148
  74. package/dist/integrity/attach.ts +0 -150
  75. package/dist/integrity/check-threads.ts +0 -166
  76. package/dist/integrity/constraint.ts +0 -1246
  77. package/dist/integrity/generators/compiler.ts +0 -138
  78. package/dist/integrity/generators/gate.ts +0 -227
  79. package/dist/integrity/generators/issues.ts +0 -160
  80. package/dist/integrity/generators/publish.ts +0 -232
  81. package/dist/integrity/generators/trial.ts +0 -359
  82. package/dist/integrity/lint.ts +0 -214
  83. package/dist/integrity/lsp/bin.ts +0 -44
  84. package/dist/integrity/lsp/diagnostics.ts +0 -92
  85. package/dist/integrity/lsp/findings.ts +0 -63
  86. package/dist/integrity/lsp/lint.ts +0 -124
  87. package/dist/integrity/lsp/protocol.ts +0 -78
  88. package/dist/integrity/lsp/server.ts +0 -224
  89. package/dist/integrity/slopnator.ts +0 -324
  90. package/dist/integrity/slopnators/sl_broken_lineage.ts +0 -38
  91. package/dist/integrity/slopnators/sl_declared_elsewhere.ts +0 -60
  92. package/dist/integrity/slopnators/sl_derived_drift.ts +0 -101
  93. package/dist/integrity/slopnators/sl_door_in_a_node.ts +0 -250
  94. package/dist/integrity/slopnators/sl_hardcoded_style.ts +0 -55
  95. package/dist/integrity/slopnators/sl_inert_island.ts +0 -84
  96. package/dist/integrity/slopnators/sl_inert_slopnator.ts +0 -93
  97. package/dist/integrity/slopnators/sl_missing_row.ts +0 -140
  98. package/dist/integrity/slopnators/sl_no_barrel.ts +0 -48
  99. package/dist/integrity/slopnators/sl_no_child_process.ts +0 -100
  100. package/dist/integrity/slopnators/sl_no_comment.ts +0 -43
  101. package/dist/integrity/slopnators/sl_no_dispatch_bypass.ts +0 -276
  102. package/dist/integrity/slopnators/sl_no_import_cycle.ts +0 -66
  103. package/dist/integrity/slopnators/sl_no_such_command.ts +0 -81
  104. package/dist/integrity/slopnators/sl_only_takes_a_literal.ts +0 -63
  105. package/dist/integrity/slopnators/sl_outside_an_operation.ts +0 -25
  106. package/dist/integrity/slopnators/sl_screen_holds_only_declared.ts +0 -70
  107. package/dist/integrity/slopnators/sl_secret_literal.ts +0 -68
  108. package/dist/integrity/slopnators/sl_stale_path.ts +0 -178
  109. package/dist/integrity/slopnators/sl_twice_meant.ts +0 -57
  110. package/dist/integrity/slopnators/sl_twice_parented.ts +0 -82
  111. package/dist/integrity/slopnators/sl_undeclared_crossing.ts +0 -481
  112. package/dist/integrity/slopnators/sl_undeclared_destination.ts +0 -113
  113. package/dist/integrity/slopnators/sl_undeclared_element.ts +0 -44
  114. package/dist/integrity/slopnators/sl_undeclared_list.ts +0 -358
  115. package/dist/integrity/slopnators/sl_undeclared_node.ts +0 -75
  116. package/dist/integrity/slopnators/sl_undeclared_operation.ts +0 -257
  117. package/dist/integrity/slopnators/sl_undeclared_variant.ts +0 -152
  118. package/dist/integrity/slopnators/sl_undeclared_webhook.ts +0 -108
  119. package/dist/integrity/slopnators/sl_underived_route.ts +0 -72
  120. package/dist/integrity/slopnators/sl_undescribed.ts +0 -65
  121. package/dist/integrity/slopnators/sl_ungoverned_island.ts +0 -60
  122. package/dist/integrity/slopnators/sl_unlisted_program.ts +0 -46
  123. package/dist/integrity/slopnators/sl_unnamed_island.ts +0 -41
  124. package/dist/integrity/slopnators/sl_unpaired_member.ts +0 -139
  125. package/dist/integrity/slopnators/sl_unpaired_slopnator.ts +0 -71
  126. package/dist/integrity/slopnators/sl_unprefixed_member.ts +0 -110
  127. package/dist/integrity/slopnators/sl_unthreaded.ts +0 -421
  128. package/dist/integrity/slopnators/sl_untranslated_key.ts +0 -140
  129. package/dist/integrity/slopnators/sl_unvaulted_secret.ts +0 -132
  130. package/dist/integrity/slopnators/sl_unversioned.ts +0 -52
  131. package/dist/integrity/sweep.ts +0 -395
  132. package/dist/knowledge/attach.ts +0 -327
  133. package/dist/knowledge/generators/docsgen.ts +0 -186
  134. package/dist/knowledge/generators/glossary.ts +0 -73
  135. package/dist/knowledge/glossary.ts +0 -6
  136. package/dist/operations/access.ts +0 -131
  137. package/dist/operations/attach.ts +0 -408
  138. package/dist/operations/capabilities.ts +0 -88
  139. package/dist/operations/dispatch.ts +0 -294
  140. package/dist/operations/error-results.ts +0 -31
  141. package/dist/operations/generators/capability.ts +0 -1054
  142. package/dist/operations/generators/compile.ts +0 -701
  143. package/dist/operations/generators/permits.ts +0 -224
  144. package/dist/operations/generators/seed.ts +0 -359
  145. package/dist/operations/generators/trial.ts +0 -666
  146. package/dist/operations/nodes.ts +0 -53
  147. package/dist/operations/operations.ts +0 -91
  148. package/dist/operations/result.ts +0 -28
@@ -1,351 +0,0 @@
1
- export const VALUE_TYPES = ['text', 'number', 'boolean', 'date', 'timestamp', 'json'] as const
2
-
3
- export type ValueType = (typeof VALUE_TYPES)[number]
4
-
5
- export const KEYBOARDS = ['text', 'numeric', 'decimal', 'tel', 'email', 'url', 'search'] as const
6
-
7
- export type Keyboard = (typeof KEYBOARDS)[number]
8
-
9
- export const ENTRY_MODES = ['plain', 'calculator', 'masked'] as const
10
-
11
- export type EntryMode = (typeof ENTRY_MODES)[number]
12
-
13
- export type Checked = { readonly ok: true; readonly value: unknown } | { readonly ok: false; readonly because: string }
14
-
15
- export const held = (value: unknown): Checked => ({ ok: true, value })
16
-
17
- export const refused = (because: string): Checked => ({ ok: false, because })
18
-
19
- export interface Facts {
20
- readonly locale?: string
21
- readonly currency?: string
22
- readonly min?: number
23
- readonly max?: number
24
- readonly maxLen?: number
25
- readonly maxBytes?: number
26
- readonly maxDepth?: number
27
- readonly options?: readonly string[]
28
- readonly now?: number
29
- }
30
-
31
- export interface Format {
32
- readonly name: string
33
- readonly type: ValueType
34
- readonly check: (raw: unknown, facts: Facts) => Checked
35
- readonly shown?: (value: unknown, facts: Facts) => string
36
- readonly keyboard?: Keyboard
37
- readonly accepts?: RegExp
38
- readonly maxChars?: number
39
- readonly entry?: EntryMode
40
- readonly mask?: string
41
- readonly secret?: boolean
42
- readonly autocomplete?: string
43
- readonly requires?: readonly string[]
44
- }
45
-
46
- export function stripControl(text: string): string {
47
- let out = ''
48
- for (const character of text) {
49
- const point = character.codePointAt(0) ?? 0
50
- const control = point <= 0x08 || point === 0x0b || point === 0x0c || (point >= 0x0e && point <= 0x1f) || (point >= 0x7f && point <= 0x9f)
51
- if (!control) out += character
52
- }
53
- return out
54
- }
55
-
56
- const numeric = (raw: unknown): number => (typeof raw === 'number' ? raw : Number(raw))
57
-
58
- const SCHEMES = new Set(['http:', 'https:', 'mailto:', 'tel:'])
59
-
60
- export const BOUNDED: Readonly<Partial<Record<ValueType, string>>> = {
61
- text: 'number of characters',
62
- number: 'value',
63
- }
64
-
65
- function bounded(one: number, facts: Facts): Checked {
66
- if (facts.min !== undefined && one < facts.min) return refused('format.number.below_min')
67
- if (facts.max !== undefined && one > facts.max) return refused('format.number.above_max')
68
- return held(one)
69
- }
70
-
71
- function depthWithin(value: unknown, limit: number, depth = 0): boolean {
72
- if (depth > limit) return false
73
- if (Array.isArray(value)) return value.every((one) => depthWithin(one, limit, depth + 1))
74
- if (value !== null && typeof value === 'object') return Object.values(value).every((one) => depthWithin(one, limit, depth + 1))
75
- return true
76
- }
77
-
78
- const instant = (raw: unknown): Checked =>
79
- typeof raw === 'string' && !Number.isNaN(Date.parse(raw))
80
- ? held(new Date(raw).toISOString())
81
- : refused('format.timestamp.unreadable')
82
-
83
- const dated = (value: unknown, facts: Facts, options: Intl.DateTimeFormatOptions): string =>
84
- new Intl.DateTimeFormat(facts.locale, options).format(new Date(String(value)))
85
-
86
- export const FORMATS: readonly Format[] = [
87
- {
88
- name: 'text',
89
- type: 'text',
90
- keyboard: 'text',
91
- check: (raw, facts) => {
92
- if (typeof raw !== 'string') return refused('format.text.not_text')
93
- const clean = stripControl(raw).trim()
94
- return facts.maxLen !== undefined && clean.length > facts.maxLen ? refused('format.text.too_long') : held(clean)
95
- },
96
- },
97
- {
98
- name: 'email',
99
- type: 'text',
100
- keyboard: 'email',
101
- autocomplete: 'email',
102
- check: (raw) => {
103
- if (typeof raw !== 'string') return refused('format.email.invalid')
104
- const one = raw.trim().toLowerCase()
105
- return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(one) ? held(one) : refused('format.email.invalid')
106
- },
107
- },
108
- {
109
- name: 'tel',
110
- type: 'text',
111
- keyboard: 'tel',
112
- accepts: /[0-9+]/,
113
- maxChars: 16,
114
- autocomplete: 'tel',
115
- check: (raw) => {
116
- if (typeof raw !== 'string') return refused('format.tel.invalid')
117
- const digits = raw.replace(/[^\d+]/g, '')
118
- return /^\+?\d{6,15}$/.test(digits) ? held(digits) : refused('format.tel.invalid')
119
- },
120
- },
121
- {
122
- name: 'url',
123
- type: 'text',
124
- keyboard: 'url',
125
- check: (raw) => {
126
- if (typeof raw !== 'string') return refused('format.url.invalid')
127
- let parsed: URL
128
- try {
129
- parsed = new URL(raw.trim())
130
- } catch {
131
- return refused('format.url.invalid')
132
- }
133
- return SCHEMES.has(parsed.protocol) ? held(parsed.toString()) : refused('format.url.scheme')
134
- },
135
- },
136
- {
137
- name: 'password',
138
- type: 'text',
139
- secret: true,
140
- maxChars: 256,
141
- autocomplete: 'current-password',
142
- check: (raw) => (typeof raw === 'string' && raw.length >= 8 ? held(raw) : refused('format.password.too_short')),
143
- },
144
- {
145
- name: 'otp',
146
- type: 'text',
147
- keyboard: 'numeric',
148
- accepts: /\d/,
149
- maxChars: 6,
150
- autocomplete: 'one-time-code',
151
- check: (raw) => (typeof raw === 'string' && /^\d{6}$/.test(raw) ? held(raw) : refused('format.otp.invalid')),
152
- },
153
- {
154
- name: 'ref',
155
- type: 'text',
156
- check: (raw) => (typeof raw === 'string' && /^ref:[a-z0-9/_-]+$/i.test(raw) ? held(raw) : refused('format.ref.invalid')),
157
- },
158
-
159
- {
160
- name: 'choice',
161
- type: 'text',
162
- requires: ['options'],
163
- check: (raw, facts) => {
164
- if (facts.options === undefined) return refused('format.choice.undeclared_options')
165
- return typeof raw === 'string' && facts.options.includes(raw) ? held(raw) : refused('format.choice.undeclared')
166
- },
167
- },
168
- {
169
- name: 'number',
170
- type: 'number',
171
- keyboard: 'decimal',
172
- accepts: /[0-9.,-]/,
173
- check: (raw, facts) => {
174
- const one = numeric(raw)
175
- return Number.isFinite(one) ? bounded(one, facts) : refused('format.number.invalid')
176
- },
177
- },
178
- {
179
- name: 'integer',
180
- type: 'number',
181
- keyboard: 'numeric',
182
- accepts: /[0-9-]/,
183
- check: (raw, facts) => {
184
- const one = numeric(raw)
185
- return Number.isInteger(one) ? bounded(one, facts) : refused('format.integer.invalid')
186
- },
187
- },
188
- {
189
- name: 'money',
190
- type: 'number',
191
- keyboard: 'decimal',
192
- accepts: /[0-9]/,
193
- entry: 'calculator',
194
- requires: ['currency'],
195
- check: (raw, facts) => {
196
- const one = numeric(raw)
197
- return Number.isFinite(one) ? bounded(one, facts) : refused('format.money.invalid')
198
- },
199
- shown: (value, facts) =>
200
- facts.currency === undefined
201
- ? String(value)
202
- : new Intl.NumberFormat(facts.locale, { style: 'currency', currency: facts.currency }).format(Number(value)),
203
- },
204
- {
205
- name: 'percent',
206
- type: 'number',
207
- keyboard: 'decimal',
208
- accepts: /[0-9.,]/,
209
- check: (raw) => {
210
- const one = numeric(raw)
211
- return Number.isFinite(one) && one >= 0 && one <= 100 ? held(one) : refused('format.percent.range')
212
- },
213
- shown: (value, facts) =>
214
- new Intl.NumberFormat(facts.locale, { style: 'percent', maximumFractionDigits: 1 }).format(Number(value) / 100),
215
- },
216
- {
217
- name: 'duration',
218
- type: 'number',
219
- keyboard: 'numeric',
220
- accepts: /[0-9]/,
221
- check: (raw) => {
222
- const one = numeric(raw)
223
- if (!Number.isFinite(one)) return refused('format.number.invalid')
224
- return one < 0 ? refused('format.duration.negative') : held(one)
225
- },
226
- },
227
- {
228
- name: 'rating',
229
- type: 'number',
230
- keyboard: 'numeric',
231
- accepts: /[0-9]/,
232
- check: (raw, facts) => {
233
- const one = numeric(raw)
234
- const ceiling = facts.max ?? 5
235
- return Number.isInteger(one) && one >= 1 && one <= ceiling ? held(one) : refused('format.rating.range')
236
- },
237
- },
238
- {
239
- name: 'boolean',
240
- type: 'boolean',
241
- check: (raw) => {
242
- if (typeof raw === 'boolean') return held(raw)
243
- if (raw === 'true' || raw === 'false') return held(raw === 'true')
244
- return refused('format.boolean.invalid')
245
- },
246
- },
247
- {
248
- name: 'date',
249
- type: 'date',
250
- keyboard: 'numeric',
251
- accepts: /[0-9-]/,
252
- maxChars: 10,
253
- mask: '0000-00-00',
254
- entry: 'masked',
255
- check: (raw) => {
256
- if (typeof raw !== 'string' || !/^\d{4}-\d{2}-\d{2}$/.test(raw)) return refused('format.date.shape')
257
- return Number.isNaN(Date.parse(raw)) ? refused('format.date.invalid') : held(raw)
258
- },
259
- shown: (value, facts) => dated(`${String(value)}T00:00:00Z`, facts, { dateStyle: 'medium', timeZone: 'UTC' }),
260
- },
261
- {
262
- name: 'timestamp',
263
- type: 'timestamp',
264
- check: instant,
265
- shown: (value, facts) => dated(value, facts, { dateStyle: 'medium', timeStyle: 'short' }),
266
- },
267
- {
268
- name: 'elapsed',
269
- type: 'timestamp',
270
- check: instant,
271
- requires: ['now'],
272
- shown: (value, facts) => {
273
- const now = facts.now
274
- if (now === undefined) return String(value)
275
- const gap = Date.parse(String(value)) - now
276
- const UNITS: readonly (readonly [Intl.RelativeTimeFormatUnit, number])[] = [
277
- ['year', 31_536_000_000],
278
- ['month', 2_592_000_000],
279
- ['week', 604_800_000],
280
- ['day', 86_400_000],
281
- ['hour', 3_600_000],
282
- ['minute', 60_000],
283
- ['second', 1000],
284
- ]
285
- const spoken = new Intl.RelativeTimeFormat(facts.locale, { numeric: 'auto' })
286
- for (const [unit, span] of UNITS) {
287
- if (Math.abs(gap) >= span) return spoken.format(Math.trunc(gap / span), unit)
288
- }
289
- return spoken.format(0, 'second')
290
- },
291
- },
292
- {
293
- name: 'json',
294
- type: 'json',
295
- check: (raw, facts) => {
296
- if (facts.maxDepth !== undefined && !depthWithin(raw, facts.maxDepth)) return refused('format.json.too_deep')
297
- const size = JSON.stringify(raw)?.length ?? 0
298
- return facts.maxBytes !== undefined && size > facts.maxBytes ? refused('format.json.too_large') : held(raw)
299
- },
300
- },
301
- {
302
- name: 'geo',
303
- type: 'json',
304
- check: (raw) => {
305
- if (raw === null || typeof raw !== 'object') return refused('format.geo.invalid')
306
- const { lat, lng } = raw as { lat?: unknown; lng?: unknown }
307
- const within = typeof lat === 'number' && lat >= -90 && lat <= 90 && typeof lng === 'number' && lng >= -180 && lng <= 180
308
- return within ? held({ lat, lng }) : refused('format.geo.invalid')
309
- },
310
- },
311
- {
312
- name: 'richtext',
313
- type: 'json',
314
- check: (raw) => {
315
- if (raw === null || typeof raw !== 'object') return refused('format.richtext.invalid')
316
- const blocks = (raw as { blocks?: unknown }).blocks
317
- return Array.isArray(blocks) ? held({ blocks }) : refused('format.richtext.invalid')
318
- },
319
- },
320
- ]
321
-
322
- const BY_NAME = new Map(FORMATS.map((one) => [one.name, one]))
323
-
324
- export function formatsOf(type: ValueType): readonly Format[] {
325
- return FORMATS.filter((one) => one.type === type)
326
- }
327
-
328
- export function formatNamed(name: string): Format | undefined {
329
- return BY_NAME.get(name)
330
- }
331
-
332
- export function plainFormat(type: ValueType): Format {
333
- const one = BY_NAME.get(type)
334
- if (one === undefined) throw new Error(`no plain format is declared for value type "${type}"`)
335
- return one
336
- }
337
-
338
- export function formatFor(type: ValueType, name: string | undefined): Format | undefined {
339
- const one = name === undefined ? plainFormat(type) : BY_NAME.get(name)
340
- return one === undefined || one.type !== type ? undefined : one
341
- }
342
-
343
- export function checkValue(type: ValueType, name: string | undefined, raw: unknown, facts: Facts = {}): Checked {
344
- const one = formatFor(type, name)
345
- return one === undefined ? refused(`format.unusable.${name ?? type}`) : one.check(raw, facts)
346
- }
347
-
348
- export function showValue(type: ValueType, name: string | undefined, value: unknown, facts: Facts = {}): string {
349
- const one = formatFor(type, name)
350
- return one?.shown === undefined ? String(value) : one.shown(value, facts)
351
- }
@@ -1,57 +0,0 @@
1
- import type { Attaching } from '../core/attach.ts'
2
-
3
- import { SHAPED } from '../core/init.ts'
4
- import { quoted } from '../core/rows.ts'
5
-
6
- const DESCRIBES =
7
- 'What turns a declaration into a file: the rows that state something is to be made, and the generators that make it. They are kept apart so you can read what an app declares without opening the machinery that builds it.'
8
-
9
- const DERIVATION_SOURCE = [
10
- `import type { Threaded } from '${SHAPED}'`,
11
- '',
12
- 'export const DERIVATION: Threaded = {',
13
- " id: 'derivation',",
14
- " at: '_threads/derivation.ts',",
15
- ` describes: ${quoted(DESCRIBES)},`,
16
- ' version: 1,',
17
- ' derives: [],',
18
- '}',
19
- '',
20
- 'export const GENERATORS: readonly Threaded[] = []',
21
- '',
22
- ].join('\n')
23
-
24
- const SEEDED = {
25
- attaches: [] as const,
26
- id: 'derivation',
27
- declares: [
28
- ' {',
29
- ' id: \'derivation\',',
30
- ' at: \'_threads/derivation.ts\',',
31
- ' describes: \'What turns a declaration into a file: the rows that state something is to be made, and the generators that make it. They are kept apart so you can read what an app declares without opening the machinery that builds it.\',',
32
- ' version: 1,',
33
- ' },',
34
- ].join('\n'),
35
- }
36
-
37
- const SHIPPED: readonly { readonly into: string; readonly list: string; readonly id: string; readonly source: string }[] = [
38
- {
39
- into: 'derivation.ts',
40
- list: 'GENERATORS',
41
- id: 'build-generator',
42
- source: " {\n id: 'build-generator',\n at: 'node_modules/@prestack/thread/dist/derivation/generators/build.js',\n describes: 'The builder of what this app ships — it reads the row that derives an artifact to learn the entry it comes from, and refuses to resolve any file inside the app the descent never reaches, so a file nothing declares has no way into the thing that runs.',\n version: 1,\n by: 'thread build',\n runs: 'thread build --check',\n },",
43
- },
44
- {
45
- into: 'derivation.ts',
46
- list: 'GENERATORS',
47
- id: 'release-generator',
48
- source: " {\n id: 'release-generator',\n at: 'node_modules/@prestack/thread/dist/derivation/generators/release.js',\n describes: 'The writer of what a host reads to run this app — it derives the config from what the app already declares, its own build and start commands and the names of every secret it says it must be given, and refuses to write while this app installs a package of this framework as a dependency, because what a host runs may hold nothing of the scaffolding that assembled it.',\n version: 1,\n by: 'thread release',\n runs: 'thread release --check',\n },",
49
- },
50
- ]
51
- export const ATTACH: Attaching = {
52
- attaches: SEEDED.attaches,
53
- id: SEEDED.id,
54
- declares: SEEDED.declares,
55
- writes: [{ file: 'derivation.ts', source: DERIVATION_SOURCE }],
56
- rows: SHIPPED,
57
- }