@prestack/thread 0.0.1 → 0.0.3
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.
- package/dist/core/actor.ts +20 -0
- package/dist/core/asking.d.ts +0 -1
- package/dist/core/asking.js +0 -1
- package/dist/core/asking.ts +1342 -0
- package/dist/core/attach.js +2 -2
- package/dist/core/attach.ts +585 -0
- package/dist/core/chain.js +8 -1
- package/dist/core/chain.ts +148 -0
- package/dist/core/cli.js +97 -18
- package/dist/core/cli.ts +2004 -0
- package/dist/core/condition.ts +227 -0
- package/dist/core/descend.d.ts +1 -0
- package/dist/core/descend.js +36 -0
- package/dist/core/descend.ts +1001 -0
- package/dist/core/finding.ts +38 -0
- package/dist/core/generators/meta.js +6 -0
- package/dist/core/generators/meta.ts +1006 -0
- package/dist/core/init.ts +170 -0
- package/dist/core/invoked.ts +47 -0
- package/dist/core/round.ts +57 -0
- package/dist/core/rows.ts +369 -0
- package/dist/core/scope.ts +18 -0
- package/dist/core/thread.ts +29 -0
- package/dist/core/tree.ts +67 -0
- package/dist/core/types.ts +350 -0
- package/dist/derivation/attach.js +1 -1
- package/dist/derivation/attach.ts +68 -0
- package/dist/derivation/generators/build.ts +232 -0
- package/dist/derivation/generators/check.ts +118 -0
- package/dist/derivation/generators/derivation.ts +347 -0
- package/dist/derivation/generators/determinism.ts +145 -0
- package/dist/derivation/generators/release.js +19 -9
- package/dist/derivation/generators/release.ts +213 -0
- package/dist/derivation/makers/release.ts +135 -0
- package/dist/derivation/release.ts +23 -0
- package/dist/integrations/attach.js +2 -2
- package/dist/integrations/attach.ts +207 -0
- package/dist/integrations/generators/read.ts +127 -0
- package/dist/integrations/generators/secret.ts +289 -0
- package/dist/integrations/generators/target.js +16 -6
- package/dist/integrations/generators/target.ts +944 -0
- package/dist/integrations/generators/vault.js +46 -14
- package/dist/integrations/generators/vault.ts +212 -0
- package/dist/integrations/{sdk.js → module.js} +4 -4
- package/dist/integrations/module.ts +189 -0
- package/dist/integrations/secret.ts +50 -0
- package/dist/integrations/target.d.ts +3 -1
- package/dist/integrations/target.js +14 -11
- package/dist/integrations/target.ts +340 -0
- package/dist/integrations/vault.d.ts +2 -0
- package/dist/integrations/vault.js +4 -2
- package/dist/integrations/vault.ts +136 -0
- package/dist/integrity/attach.ts +234 -0
- package/dist/integrity/check-threads.js +2 -26
- package/dist/integrity/check-threads.ts +166 -0
- package/dist/integrity/constraint.ts +1202 -0
- package/dist/integrity/generators/compiler.ts +161 -0
- package/dist/integrity/generators/gate.ts +201 -0
- package/dist/integrity/generators/issues.ts +160 -0
- package/dist/integrity/generators/publish.js +14 -5
- package/dist/integrity/generators/publish.ts +247 -0
- package/dist/integrity/generators/rule.ts +271 -0
- package/dist/integrity/generators/seal.ts +117 -0
- package/dist/integrity/generators/trial.ts +320 -0
- package/dist/integrity/lint.ts +227 -0
- package/dist/integrity/lsp/bin.ts +42 -0
- package/dist/integrity/lsp/diagnostics.ts +92 -0
- package/dist/integrity/lsp/findings.ts +63 -0
- package/dist/integrity/lsp/lint.ts +140 -0
- package/dist/integrity/lsp/protocol.ts +78 -0
- package/dist/integrity/lsp/server.ts +224 -0
- package/dist/integrity/sealed.js +2 -2
- package/dist/integrity/sealed.ts +56 -0
- package/dist/integrity/slopnator.ts +350 -0
- package/dist/integrity/slopnators/sl_broken_lineage.ts +36 -0
- package/dist/integrity/slopnators/sl_declared_elsewhere.ts +39 -0
- package/dist/integrity/slopnators/sl_derived_drift.ts +98 -0
- package/dist/integrity/slopnators/sl_hardcoded_style.ts +55 -0
- package/dist/integrity/slopnators/sl_inert_island.ts +91 -0
- package/dist/integrity/slopnators/sl_inert_slopnator.ts +93 -0
- package/dist/integrity/slopnators/sl_missing_row.ts +182 -0
- package/dist/integrity/slopnators/sl_no_barrel.ts +48 -0
- package/dist/integrity/slopnators/sl_no_child_process.ts +74 -0
- package/dist/integrity/slopnators/sl_no_comment.ts +43 -0
- package/dist/integrity/slopnators/sl_no_dispatch_bypass.ts +328 -0
- package/dist/integrity/slopnators/sl_no_import_cycle.ts +50 -0
- package/dist/integrity/slopnators/sl_no_such_command.ts +64 -0
- package/dist/integrity/slopnators/sl_only_takes_a_literal.ts +63 -0
- package/dist/integrity/slopnators/sl_secret_literal.ts +100 -0
- package/dist/integrity/slopnators/sl_stale_path.ts +94 -0
- package/dist/integrity/slopnators/sl_twice_meant.ts +31 -0
- package/dist/integrity/slopnators/sl_twice_parented.ts +37 -0
- package/dist/integrity/slopnators/sl_undeclared_crossing.ts +87 -0
- package/dist/integrity/slopnators/sl_undeclared_destination.ts +65 -0
- package/dist/integrity/slopnators/sl_undeclared_element.ts +44 -0
- package/dist/integrity/slopnators/sl_undeclared_node.ts +69 -0
- package/dist/integrity/slopnators/sl_undeclared_operation.ts +147 -0
- package/dist/integrity/slopnators/sl_undeclared_variant.ts +148 -0
- package/dist/integrity/slopnators/sl_undescribed.ts +65 -0
- package/dist/integrity/slopnators/sl_ungoverned_island.ts +61 -0
- package/dist/integrity/slopnators/sl_unkept_rows.ts +111 -0
- package/dist/integrity/slopnators/sl_unnamed_island.ts +41 -0
- package/dist/integrity/slopnators/sl_unpaired_member.ts +131 -0
- package/dist/integrity/slopnators/sl_unpaired_slopnator.ts +58 -0
- package/dist/integrity/slopnators/sl_unprefixed_member.ts +136 -0
- package/dist/integrity/slopnators/sl_unseamed_reach.ts +79 -0
- package/dist/integrity/slopnators/sl_unthreaded.ts +419 -0
- package/dist/integrity/slopnators/sl_untranslated_key.ts +164 -0
- package/dist/integrity/slopnators/sl_unversioned.ts +36 -0
- package/dist/integrity/sweep.ts +307 -0
- package/dist/knowledge/attach.ts +350 -0
- package/dist/knowledge/generators/docsgen.ts +174 -0
- package/dist/knowledge/generators/glossary.ts +73 -0
- package/dist/knowledge/generators/skills.ts +263 -0
- package/dist/knowledge/glossary.ts +6 -0
- package/dist/operations/access.ts +88 -0
- package/dist/operations/attach.ts +475 -0
- package/dist/operations/capabilities.ts +65 -0
- package/dist/operations/cost.ts +58 -0
- package/dist/operations/dispatch.ts +348 -0
- package/dist/operations/error-results.ts +31 -0
- package/dist/operations/errors/catalog.ts +168 -0
- package/dist/operations/errors/classes.ts +51 -0
- package/dist/operations/errors/errors.ts +314 -0
- package/dist/operations/generators/capability.js +29 -19
- package/dist/operations/generators/capability.ts +704 -0
- package/dist/operations/generators/compile.js +20 -1
- package/dist/operations/generators/compile.ts +643 -0
- package/dist/operations/generators/grant.ts +336 -0
- package/dist/operations/generators/operation.ts +972 -0
- package/dist/operations/generators/permits.ts +223 -0
- package/dist/operations/generators/seed.ts +347 -0
- package/dist/operations/generators/trial.js +4 -1
- package/dist/operations/generators/trial.ts +529 -0
- package/dist/operations/http.ts +164 -0
- package/dist/operations/makers/capability.ts +166 -0
- package/dist/operations/makers/trial.ts +520 -0
- package/dist/operations/memory.ts +470 -0
- package/dist/operations/metering.ts +328 -0
- package/dist/operations/nodes.ts +54 -0
- package/dist/operations/operations.ts +32 -0
- package/dist/operations/queue-policy.ts +10 -0
- package/dist/operations/result.ts +28 -0
- package/dist/operations/seams.d.ts +4 -4
- package/dist/operations/seams.ts +364 -0
- package/dist/operations/store.ts +29 -0
- package/package.json +8 -1
- package/dist/integrations/generators/sdk.d.ts +0 -1
- package/dist/integrations/generators/sdk.js +0 -148
- /package/dist/integrations/{sdk.d.ts → module.d.ts} +0 -0
|
@@ -0,0 +1,364 @@
|
|
|
1
|
+
import type { Actor } from '../core/actor.ts'
|
|
2
|
+
|
|
3
|
+
export type { FieldList, ReadField, Row, Store } from './store.ts'
|
|
4
|
+
|
|
5
|
+
import type { FieldList, Row, Store } from './store.ts'
|
|
6
|
+
|
|
7
|
+
export interface Span {
|
|
8
|
+
ok(): void
|
|
9
|
+
error(e: unknown): void
|
|
10
|
+
end(): void
|
|
11
|
+
}
|
|
12
|
+
export interface Telemetry {
|
|
13
|
+
start(action: string, run: string, tags: Record<string, unknown>): Span
|
|
14
|
+
|
|
15
|
+
record?(span: {
|
|
16
|
+
readonly key: string
|
|
17
|
+
readonly traceId: string
|
|
18
|
+
readonly spanId: string
|
|
19
|
+
readonly durationMs: number
|
|
20
|
+
readonly ok: boolean
|
|
21
|
+
readonly attrs?: Record<string, unknown>
|
|
22
|
+
|
|
23
|
+
readonly actor?: Actor
|
|
24
|
+
|
|
25
|
+
readonly nodeId?: string
|
|
26
|
+
|
|
27
|
+
readonly workflowId?: string
|
|
28
|
+
|
|
29
|
+
readonly error?: string
|
|
30
|
+
}): void
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export type PropertyValue = string | number | boolean | null | readonly (string | number | boolean)[]
|
|
34
|
+
|
|
35
|
+
export type LogLevel = 'info' | 'warn' | 'error'
|
|
36
|
+
|
|
37
|
+
export interface Log {
|
|
38
|
+
write(level: LogLevel, action: string, actor: Actor, data: Record<string, unknown>): void
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export interface AuditRecord {
|
|
42
|
+
readonly action: string
|
|
43
|
+
readonly outcome: AuditOutcome
|
|
44
|
+
|
|
45
|
+
readonly subject: { type: string; id: string }
|
|
46
|
+
|
|
47
|
+
readonly changed?: readonly string[]
|
|
48
|
+
|
|
49
|
+
readonly because?: string
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export interface Audit {
|
|
53
|
+
append(actor: Actor, record: AuditRecord): Promise<void>
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export interface ErrorRecord {
|
|
57
|
+
readonly code: string
|
|
58
|
+
readonly class: string
|
|
59
|
+
readonly action: string
|
|
60
|
+
readonly because?: string
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export interface Errors {
|
|
64
|
+
record(actor: Actor, error: ErrorRecord): Promise<void>
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export interface Search {
|
|
68
|
+
index(actor: Actor, entity: string, row: Row): Promise<void>
|
|
69
|
+
query(actor: Actor, entity: string, q: string): Promise<Row[]>
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export interface Views {
|
|
73
|
+
query<T = Record<string, unknown>>(
|
|
74
|
+
actor: Actor,
|
|
75
|
+
sql: string,
|
|
76
|
+
params: readonly unknown[],
|
|
77
|
+
): Promise<readonly T[]>
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export interface Cost {
|
|
81
|
+
meter(action: string, actor: Actor, units?: number): void
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export interface Idempotency {
|
|
85
|
+
check(key: string | undefined, action: string): Promise<unknown | null>
|
|
86
|
+
store(key: string | undefined, action: string, output: unknown): Promise<void>
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export interface PlatformEvent {
|
|
90
|
+
kind: string
|
|
91
|
+
entity?: string
|
|
92
|
+
id?: string
|
|
93
|
+
run?: string
|
|
94
|
+
actor: string | null
|
|
95
|
+
at: number
|
|
96
|
+
|
|
97
|
+
payload?: Readonly<Record<string, unknown>>
|
|
98
|
+
}
|
|
99
|
+
export interface EventBus {
|
|
100
|
+
publish(event: PlatformEvent): Promise<void>
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
export interface RateLimiter {
|
|
104
|
+
check(actor: Actor, action: string, operation?: string): Promise<boolean>
|
|
105
|
+
|
|
106
|
+
checkPolicy(actor: Actor, policy: string): Promise<boolean>
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
export interface FeatureGate {
|
|
110
|
+
check(actor: Actor, feature: string): Promise<boolean>
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
export interface QuotaHold {
|
|
114
|
+
readonly ok: boolean
|
|
115
|
+
|
|
116
|
+
readonly behavior: string | null
|
|
117
|
+
readonly retryAfterSeconds: number
|
|
118
|
+
|
|
119
|
+
commit(actual: number): Promise<void>
|
|
120
|
+
|
|
121
|
+
release(): Promise<void>
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
export interface Quotas {
|
|
125
|
+
reserve(actor: Actor, meter: string, estimate: number): Promise<QuotaHold>
|
|
126
|
+
|
|
127
|
+
lower?(actor: Actor, meter: string, amount: number): Promise<void>
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
export interface Outbox {
|
|
131
|
+
emit(actor: Actor, event: PlatformEvent): Promise<void>
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
export interface Transactional {
|
|
135
|
+
transaction<T>(actor: Actor, fn: () => Promise<T>): Promise<T>
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
export function isTransactional(store: Store): store is Store & Transactional {
|
|
139
|
+
return typeof (store as Partial<Transactional>).transaction === 'function'
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
export interface Job<T = unknown> {
|
|
143
|
+
id: string
|
|
144
|
+
kind: string
|
|
145
|
+
payload: T
|
|
146
|
+
attempts: number
|
|
147
|
+
|
|
148
|
+
actor: Actor
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
export interface EnqueueOpts {
|
|
152
|
+
|
|
153
|
+
runAt?: number
|
|
154
|
+
|
|
155
|
+
dedupeKey?: string
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
export interface SchedulerSeam {
|
|
159
|
+
|
|
160
|
+
readonly endpoint: string
|
|
161
|
+
|
|
162
|
+
readonly secret: string
|
|
163
|
+
|
|
164
|
+
register(app: { id: string; endpoint: string; secret: string }): Promise<void>
|
|
165
|
+
schedule(call: {
|
|
166
|
+
appId: string
|
|
167
|
+
runAt: Date
|
|
168
|
+
reason: string
|
|
169
|
+
runId?: string
|
|
170
|
+
|
|
171
|
+
dedupeKey?: string
|
|
172
|
+
}): Promise<string>
|
|
173
|
+
cancelForRun(appId: string, runId: string): Promise<void>
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
export interface Queue {
|
|
177
|
+
enqueue<T>(actor: Actor, kind: string, payload: T, opts?: EnqueueOpts): Promise<string>
|
|
178
|
+
|
|
179
|
+
poll(kinds: string[], limit: number, now: number): Promise<Job[]>
|
|
180
|
+
|
|
181
|
+
ack(id: string): Promise<void>
|
|
182
|
+
|
|
183
|
+
fail(id: string, error: string, now: number): Promise<void>
|
|
184
|
+
|
|
185
|
+
deadLetter(id: string, error: string): Promise<void>
|
|
186
|
+
|
|
187
|
+
deadLetters(): Promise<Job[]>
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
export interface Files {
|
|
191
|
+
|
|
192
|
+
put(actor: Actor, key: string, body: Uint8Array, contentType: string): Promise<{ size: number }>
|
|
193
|
+
|
|
194
|
+
get(actor: Actor, key: string): Promise<{ body: Uint8Array; contentType: string } | null>
|
|
195
|
+
|
|
196
|
+
signedUrl(actor: Actor, key: string, expiresInSeconds: number): Promise<string>
|
|
197
|
+
|
|
198
|
+
remove(actor: Actor, key: string): Promise<void>
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
export interface Clock {
|
|
202
|
+
|
|
203
|
+
now(): number
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
export interface Random {
|
|
207
|
+
|
|
208
|
+
next(): number
|
|
209
|
+
|
|
210
|
+
uuid(): string
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
export type HttpMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE'
|
|
214
|
+
|
|
215
|
+
export interface HttpRequest {
|
|
216
|
+
|
|
217
|
+
readonly target: string
|
|
218
|
+
|
|
219
|
+
readonly address: string
|
|
220
|
+
readonly method: HttpMethod
|
|
221
|
+
|
|
222
|
+
readonly path: string
|
|
223
|
+
|
|
224
|
+
readonly headers?: Readonly<Record<string, string>>
|
|
225
|
+
|
|
226
|
+
readonly body?: Uint8Array
|
|
227
|
+
readonly contentType?: string
|
|
228
|
+
|
|
229
|
+
readonly idempotencyKey?: string
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
export interface HttpResponse {
|
|
233
|
+
readonly status: number
|
|
234
|
+
readonly headers: Readonly<Record<string, string>>
|
|
235
|
+
readonly body: Uint8Array
|
|
236
|
+
|
|
237
|
+
readonly bytesSent: number
|
|
238
|
+
readonly bytesReceived: number
|
|
239
|
+
readonly durationMs: number
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
export interface Http {
|
|
243
|
+
|
|
244
|
+
call(request: HttpRequest): Promise<HttpResponse>
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
export interface Vault {
|
|
248
|
+
|
|
249
|
+
resolve(refs: readonly string[]): Promise<Readonly<Record<string, string>>>
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
export interface Seams {
|
|
253
|
+
|
|
254
|
+
store?: Store
|
|
255
|
+
search?: Search
|
|
256
|
+
events?: EventBus
|
|
257
|
+
queue?: Queue
|
|
258
|
+
|
|
259
|
+
telemetry?: Telemetry
|
|
260
|
+
log: Log
|
|
261
|
+
audit: Audit
|
|
262
|
+
errors: Errors
|
|
263
|
+
cost?: Cost
|
|
264
|
+
idempotency?: Idempotency
|
|
265
|
+
rateLimiter?: RateLimiter
|
|
266
|
+
|
|
267
|
+
flush?: () => Promise<void>
|
|
268
|
+
|
|
269
|
+
scheduler?: SchedulerSeam
|
|
270
|
+
|
|
271
|
+
featureGate?: FeatureGate
|
|
272
|
+
|
|
273
|
+
permits?: {
|
|
274
|
+
check(
|
|
275
|
+
actor: Actor,
|
|
276
|
+
action: string,
|
|
277
|
+
resource: Row | null,
|
|
278
|
+
): Promise<{ readonly allow: boolean; readonly because?: string }>
|
|
279
|
+
}
|
|
280
|
+
quotas?: Quotas
|
|
281
|
+
outbox?: Outbox
|
|
282
|
+
|
|
283
|
+
drainKick?: () => void
|
|
284
|
+
|
|
285
|
+
vault?: Vault
|
|
286
|
+
|
|
287
|
+
views?: Views
|
|
288
|
+
|
|
289
|
+
clock: Clock
|
|
290
|
+
random: Random
|
|
291
|
+
|
|
292
|
+
files?: Files
|
|
293
|
+
|
|
294
|
+
http?: Http
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
export type AuditOutcome = 'ok' | 'denied' | 'rate_limited' | 'failed' | 'feature_denied' | 'quota_exceeded'
|
|
298
|
+
|
|
299
|
+
export function isRow(v: unknown): v is Row {
|
|
300
|
+
return typeof v === 'object' && v !== null && typeof (v as { id?: unknown }).id === 'string'
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
export const SUPPLY = {
|
|
304
|
+
sm_store: 'store',
|
|
305
|
+
sm_search: 'search',
|
|
306
|
+
sm_queue: 'queue',
|
|
307
|
+
sm_events: 'events',
|
|
308
|
+
sm_clock: 'clock',
|
|
309
|
+
sm_random: 'random',
|
|
310
|
+
sm_vault: 'vault',
|
|
311
|
+
sm_views: 'views',
|
|
312
|
+
sm_files: 'files',
|
|
313
|
+
} as const satisfies Readonly<Record<string, keyof Seams>>
|
|
314
|
+
|
|
315
|
+
export type Supplied = keyof typeof SUPPLY
|
|
316
|
+
|
|
317
|
+
export const SUPPLIES: readonly Supplied[] = Object.keys(SUPPLY) as readonly Supplied[]
|
|
318
|
+
|
|
319
|
+
export const supplies = (one: string): one is Supplied => one in SUPPLY
|
|
320
|
+
|
|
321
|
+
export type Handed<R extends string = Supplied> = { readonly actor: Actor } & {
|
|
322
|
+
readonly [K in R as K extends Supplied ? (typeof SUPPLY)[K] : K]: K extends Supplied
|
|
323
|
+
? NonNullable<Seams[(typeof SUPPLY)[K]]>
|
|
324
|
+
: Readonly<
|
|
325
|
+
Record<
|
|
326
|
+
string,
|
|
327
|
+
(given?: {
|
|
328
|
+
readonly fills?: Readonly<Record<string, string | number>>
|
|
329
|
+
readonly json?: unknown
|
|
330
|
+
readonly body?: Uint8Array
|
|
331
|
+
readonly contentType?: string
|
|
332
|
+
}) => Promise<HttpResponse>
|
|
333
|
+
>
|
|
334
|
+
>
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
export type Reads<H> = Pick<H, Extract<keyof H, 'actor' | 'store' | 'search' | 'views'>>
|
|
338
|
+
|
|
339
|
+
export const SAID: Readonly<Record<keyof Seams, string>> = {
|
|
340
|
+
store: 'where rows are kept: insert, get, list, update and remove, bound to whoever asked',
|
|
341
|
+
search: 'indexing a row and querying an index, for what cannot be found by id',
|
|
342
|
+
events: 'announcing that something happened, to whoever is listening',
|
|
343
|
+
queue: 'handing work to something else to run later',
|
|
344
|
+
telemetry: 'the span opened around every run, and where it is recorded',
|
|
345
|
+
log: 'the line written for every run: its outcome, who was allowed, what it spent',
|
|
346
|
+
audit: 'the record of what was done, by whom, to what',
|
|
347
|
+
errors: 'the record of every failure, by code and class',
|
|
348
|
+
cost: 'metering what a run spent',
|
|
349
|
+
idempotency: 'remembering an answer under its key, so a repeated request is answered once',
|
|
350
|
+
rateLimiter: 'refusing a caller who asks too often',
|
|
351
|
+
flush: 'what runs when the process is about to stop, so nothing buffered is lost',
|
|
352
|
+
scheduler: 'registering this app with a scheduler and booking a later run',
|
|
353
|
+
featureGate: 'refusing an operation the caller\'s plan does not include',
|
|
354
|
+
permits: 'the gate every operation passes: who may ask for what, from the grants',
|
|
355
|
+
quotas: 'reserving what a run may spend before it starts, and settling it after',
|
|
356
|
+
outbox: 'events written with the transaction and published after it commits',
|
|
357
|
+
drainKick: 'nudging the queue worker that work has arrived',
|
|
358
|
+
vault: 'opening a secret by name at the moment of use',
|
|
359
|
+
views: 'reading through a declared view rather than a table',
|
|
360
|
+
clock: 'the current time',
|
|
361
|
+
random: 'randomness: a number, a uuid',
|
|
362
|
+
files: 'putting a file somewhere, fetching one back, handing out a signed link to one',
|
|
363
|
+
http: 'how a call leaves the process, and what it comes back with',
|
|
364
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { Actor } from '../core/actor.ts'
|
|
2
|
+
|
|
3
|
+
export type Row = Record<string, unknown>
|
|
4
|
+
|
|
5
|
+
export type ReadField = `fld_${string}` | `rel_${string}` | (string & {})
|
|
6
|
+
|
|
7
|
+
export type FieldList = readonly [ReadField, ...ReadField[]]
|
|
8
|
+
|
|
9
|
+
export interface Store {
|
|
10
|
+
insert(actor: Actor, entity: string, row: Row): Promise<Row>
|
|
11
|
+
|
|
12
|
+
get(actor: Actor, entity: string, key: string | number, fields: FieldList): Promise<Row | null>
|
|
13
|
+
|
|
14
|
+
list(
|
|
15
|
+
actor: Actor,
|
|
16
|
+
entity: string,
|
|
17
|
+
opts?: { limit?: number; where?: Readonly<Record<string, string | number | boolean | null>> },
|
|
18
|
+
): Promise<Row[]>
|
|
19
|
+
|
|
20
|
+
update(
|
|
21
|
+
actor: Actor,
|
|
22
|
+
entity: string,
|
|
23
|
+
key: string | number,
|
|
24
|
+
patch: Record<string, unknown>,
|
|
25
|
+
expectedVersion?: number,
|
|
26
|
+
): Promise<Row>
|
|
27
|
+
|
|
28
|
+
remove(actor: Actor, entity: string, key: string | number): Promise<void>
|
|
29
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@prestack/thread",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.3",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"files": [
|
|
6
6
|
"dist",
|
|
@@ -12,5 +12,12 @@
|
|
|
12
12
|
},
|
|
13
13
|
"bin": {
|
|
14
14
|
"thread": "dist/core/cli.js"
|
|
15
|
+
},
|
|
16
|
+
"dependencies": {
|
|
17
|
+
"esbuild": "^0.28.2",
|
|
18
|
+
"eslint": "^10.9.1",
|
|
19
|
+
"typescript": "^6.0.0",
|
|
20
|
+
"typescript-eslint": "^8.68.0",
|
|
21
|
+
"zod": "^4.5.4"
|
|
15
22
|
}
|
|
16
23
|
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,148 +0,0 @@
|
|
|
1
|
-
var __rewriteRelativeImportExtension = (this && this.__rewriteRelativeImportExtension) || function (path, preserveJsx) {
|
|
2
|
-
if (typeof path === "string" && /^\.\.?\//.test(path)) {
|
|
3
|
-
return path.replace(/\.(tsx)$|((?:\.d)?)((?:\.[^./]+?)?)\.([cm]?)ts$/i, function (m, tsx, d, ext, cm) {
|
|
4
|
-
return tsx ? preserveJsx ? ".jsx" : ".js" : d && (!ext || !cm) ? m : (d + ext + "." + cm.toLowerCase() + "js");
|
|
5
|
-
});
|
|
6
|
-
}
|
|
7
|
-
return path;
|
|
8
|
-
};
|
|
9
|
-
import { spawnSync } from 'node:child_process';
|
|
10
|
-
import { readFileSync, writeFileSync } from 'node:fs';
|
|
11
|
-
import { relative } from 'node:path';
|
|
12
|
-
import { stdout } from 'node:process';
|
|
13
|
-
import { generators } from "../../core/chain.js";
|
|
14
|
-
import { exit } from "../../core/invoked.js";
|
|
15
|
-
import { asking, given, nouns, refuse, slug, wordsIn } from "../../core/asking.js";
|
|
16
|
-
import { listBounds, withRow } from "../../core/rows.js";
|
|
17
|
-
import { named as packageOf } from "../../core/scope.js";
|
|
18
|
-
import { findTree, inTree } from "../../core/tree.js";
|
|
19
|
-
const TREE = findTree();
|
|
20
|
-
const FILE = 'derivation.ts';
|
|
21
|
-
const LIST = 'GENERATORS';
|
|
22
|
-
const OWNER = 'integrations';
|
|
23
|
-
const DECLARES = 'declares';
|
|
24
|
-
const NAME = /^[a-z][a-z0-9_]*$/;
|
|
25
|
-
const PACKAGE = /^(?:@[a-z0-9][a-z0-9._-]*\/)?[a-z0-9][a-z0-9._-]*$/;
|
|
26
|
-
const PREFIX = 'sdk_';
|
|
27
|
-
const here = (one) => relative(TREE.at, one).split('\\').join('/');
|
|
28
|
-
const path = inTree(TREE, FILE);
|
|
29
|
-
const at = here(path);
|
|
30
|
-
import { quoted } from "../../core/rows.js";
|
|
31
|
-
const words = wordsIn([]);
|
|
32
|
-
const rows = await generators(TREE);
|
|
33
|
-
const already = rows.filter((one) => typeof one.id === 'string' && one.id.startsWith(PREFIX));
|
|
34
|
-
const first = words[0];
|
|
35
|
-
if (first === undefined) {
|
|
36
|
-
stdout.write(already.length === 0
|
|
37
|
-
? 'sdk: no SDK declared yet.\n'
|
|
38
|
-
: `sdk: ${String(already.length)} declared:\n${already
|
|
39
|
-
.map((one) => ` ${(one.by ?? '').slice('thread run '.length)} — ${one.describes ?? ''}`)
|
|
40
|
-
.join('\n')}\n`);
|
|
41
|
-
stdout.write('\nthread create sdk <name> — installs an npm package, asks what it is for and which declared secret it\n' +
|
|
42
|
-
'needs, and declares it. Then `thread run <name> <method>` calls it, resolving the credential through the\n' +
|
|
43
|
-
'vault at the moment of the call. `<method>` is dot-separated for a namespaced one, e.g. `customers.list`.\n');
|
|
44
|
-
exit(0);
|
|
45
|
-
}
|
|
46
|
-
const name = slug(first);
|
|
47
|
-
if (name === '')
|
|
48
|
-
refuse('an SDK has to be called something — `thread create sdk <name>`');
|
|
49
|
-
if (!NAME.test(name))
|
|
50
|
-
refuse(`"${name}" cannot be the name of an SDK — it is written in lower_snake_case`);
|
|
51
|
-
const claimed = nouns(rows, 'run').get(name);
|
|
52
|
-
if (claimed !== undefined) {
|
|
53
|
-
refuse(`\`thread run ${name}\` already resolves to ${claimed} — that name is taken`);
|
|
54
|
-
}
|
|
55
|
-
const { ask, shut } = asking(given());
|
|
56
|
-
const npmPackage = (await ask('package', 'npm package to install: ')).trim();
|
|
57
|
-
if (npmPackage === '') {
|
|
58
|
-
shut();
|
|
59
|
-
refuse('an SDK installs something — the npm package is what `npm install` is given');
|
|
60
|
-
}
|
|
61
|
-
if (!PACKAGE.test(npmPackage)) {
|
|
62
|
-
shut();
|
|
63
|
-
refuse(`"${npmPackage}" does not read as an npm package name`);
|
|
64
|
-
}
|
|
65
|
-
const describes = (await ask('describes', 'what is it for? ')).trim();
|
|
66
|
-
if (describes === '') {
|
|
67
|
-
shut();
|
|
68
|
-
refuse('an SDK says what it is for — the sentence is what somebody reads before running it');
|
|
69
|
-
}
|
|
70
|
-
let secrets = [];
|
|
71
|
-
try {
|
|
72
|
-
const taken = (await import(__rewriteRelativeImportExtension(new URL(`file://${inTree(TREE, 'secrets.ts')}`).href)));
|
|
73
|
-
secrets = taken.SECRETS ?? [];
|
|
74
|
-
}
|
|
75
|
-
catch {
|
|
76
|
-
secrets = [];
|
|
77
|
-
}
|
|
78
|
-
const carrying = (await ask('requires', `which secret does it need — ${secrets.map((one) => one.id).join(', ') || '(none declared yet)'}\n` +
|
|
79
|
-
' If this SDK needs a url, a key, a token or a password to work, IT GOES HERE and nowhere else.\n' +
|
|
80
|
-
' Declare it first with `thread create secret`, then name it here, comma-separated. It is resolved\n' +
|
|
81
|
-
' through the vault at the moment of the call and is never written into any file.\n' +
|
|
82
|
-
' Blank only if the SDK genuinely needs no credential at all — a declaration with the wrong answer\n' +
|
|
83
|
-
' here does not fail now, it fails at the call with the vendor\'s own error.\n' +
|
|
84
|
-
' > '))
|
|
85
|
-
.split(',')
|
|
86
|
-
.map((one) => one.trim())
|
|
87
|
-
.filter((one) => one !== '');
|
|
88
|
-
shut();
|
|
89
|
-
for (const one of carrying) {
|
|
90
|
-
if (!secrets.some((each) => each.id === one)) {
|
|
91
|
-
refuse(`\`${one}\` is not a secret this app declares. Declare it first with \`thread create secret\` — a credential is given to something that said it needed it, or not at all.`);
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
let text;
|
|
95
|
-
try {
|
|
96
|
-
text = readFileSync(path, 'utf8');
|
|
97
|
-
}
|
|
98
|
-
catch {
|
|
99
|
-
refuse(`${at} could not be read. Attach \`${packageOf('derivation')}\` first — that is what writes it.`);
|
|
100
|
-
}
|
|
101
|
-
const where = listBounds(text, LIST);
|
|
102
|
-
if (where === undefined)
|
|
103
|
-
refuse(`${at} states no \`${LIST}\` list to declare a generator in`);
|
|
104
|
-
stdout.write(`sdk: installing ${npmPackage} …\n`);
|
|
105
|
-
const installed = spawnSync('npm', ['install', npmPackage], { cwd: TREE.at, encoding: 'utf8', stdio: ['ignore', 'pipe', 'pipe'] });
|
|
106
|
-
if (installed.status !== 0) {
|
|
107
|
-
refuse(`\`npm install ${npmPackage}\` failed, so nothing was declared:\n${`${installed.stdout ?? ''}${installed.stderr ?? ''}`.trim()}`);
|
|
108
|
-
}
|
|
109
|
-
stdout.write(`sdk: installed ${npmPackage}.\n`);
|
|
110
|
-
const fileAt = `_threads/sdk_${name}.ts`;
|
|
111
|
-
const SOURCE = `import { run } from '../sdk.ts'
|
|
112
|
-
|
|
113
|
-
await run({ name: ${quoted(name)}, module: ${quoted(npmPackage)}, requires: [${carrying.map(quoted).join(', ')}] })
|
|
114
|
-
`;
|
|
115
|
-
writeFileSync(inTree(TREE, `sdk_${name}.ts`), SOURCE, 'utf8');
|
|
116
|
-
const row = [
|
|
117
|
-
' {',
|
|
118
|
-
` id: ${quoted(`${PREFIX}${name}`)},`,
|
|
119
|
-
` at: ${quoted(fileAt)},`,
|
|
120
|
-
` describes: ${quoted(describes)},`,
|
|
121
|
-
' version: 1,',
|
|
122
|
-
` by: ${quoted(`thread run ${name}`)},`,
|
|
123
|
-
...(carrying.length === 0 ? [] : [` requires: [${carrying.map(quoted).join(', ')}],`]),
|
|
124
|
-
' },',
|
|
125
|
-
].join('\n');
|
|
126
|
-
writeFileSync(path, withRow(text, where, row), 'utf8');
|
|
127
|
-
const owner = inTree(TREE, `${OWNER}.ts`);
|
|
128
|
-
let owned = '';
|
|
129
|
-
try {
|
|
130
|
-
owned = readFileSync(owner, 'utf8');
|
|
131
|
-
}
|
|
132
|
-
catch {
|
|
133
|
-
refuse(`${OWNER}.ts could not be read, so there is nothing to declare this under.`);
|
|
134
|
-
}
|
|
135
|
-
const under = listBounds(owned, DECLARES);
|
|
136
|
-
if (under === undefined)
|
|
137
|
-
refuse(`${OWNER}.ts states no \`${DECLARES}\` list to declare this in`);
|
|
138
|
-
writeFileSync(owner, withRow(owned, under, [
|
|
139
|
-
' {',
|
|
140
|
-
` id: ${quoted(`${PREFIX}${name}`)},`,
|
|
141
|
-
` at: ${quoted(fileAt)},`,
|
|
142
|
-
` describes: ${quoted(describes)},`,
|
|
143
|
-
' version: 1,',
|
|
144
|
-
' },',
|
|
145
|
-
].join('\n')), 'utf8');
|
|
146
|
-
stdout.write(`sdk: declared ${name} — ${npmPackage}, reached with \`thread run ${name} <method>\`. ` +
|
|
147
|
-
`${carrying.length === 0 ? 'It needs no secret.' : `It resolves ${carrying.join(', ')} through the vault at call time.`}\n`);
|
|
148
|
-
exit(0);
|
|
File without changes
|