@prestack/thread 0.0.1
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/CHANGELOG.md +192 -0
- package/dist/attach.d.ts +1 -0
- package/dist/attach.js +1 -0
- package/dist/core/actor.d.ts +12 -0
- package/dist/core/actor.js +8 -0
- package/dist/core/asking.d.ts +180 -0
- package/dist/core/asking.js +1109 -0
- package/dist/core/attach.d.ts +54 -0
- package/dist/core/attach.js +510 -0
- package/dist/core/chain.d.ts +16 -0
- package/dist/core/chain.js +114 -0
- package/dist/core/cli.d.ts +2 -0
- package/dist/core/cli.js +1682 -0
- package/dist/core/condition.d.ts +52 -0
- package/dist/core/condition.js +198 -0
- package/dist/core/descend.d.ts +81 -0
- package/dist/core/descend.js +879 -0
- package/dist/core/finding.d.ts +12 -0
- package/dist/core/finding.js +23 -0
- package/dist/core/generators/meta.d.ts +2 -0
- package/dist/core/generators/meta.js +823 -0
- package/dist/core/init.d.ts +15 -0
- package/dist/core/init.js +134 -0
- package/dist/core/invoked.d.ts +9 -0
- package/dist/core/invoked.js +41 -0
- package/dist/core/round.d.ts +1 -0
- package/dist/core/round.js +57 -0
- package/dist/core/rows.d.ts +26 -0
- package/dist/core/rows.js +354 -0
- package/dist/core/scope.d.ts +6 -0
- package/dist/core/scope.js +12 -0
- package/dist/core/thread.d.ts +26 -0
- package/dist/core/thread.js +5 -0
- package/dist/core/tree.d.ts +12 -0
- package/dist/core/tree.js +56 -0
- package/dist/core/types.d.ts +49 -0
- package/dist/core/types.js +311 -0
- package/dist/derivation/attach.d.ts +2 -0
- package/dist/derivation/attach.js +61 -0
- package/dist/derivation/generators/build.d.ts +16 -0
- package/dist/derivation/generators/build.js +217 -0
- package/dist/derivation/generators/check.d.ts +18 -0
- package/dist/derivation/generators/check.js +78 -0
- package/dist/derivation/generators/derivation.d.ts +3 -0
- package/dist/derivation/generators/derivation.js +273 -0
- package/dist/derivation/generators/determinism.d.ts +20 -0
- package/dist/derivation/generators/determinism.js +110 -0
- package/dist/derivation/generators/release.d.ts +3 -0
- package/dist/derivation/generators/release.js +183 -0
- package/dist/derivation/makers/release.d.ts +1 -0
- package/dist/derivation/makers/release.js +107 -0
- package/dist/derivation/release.d.ts +10 -0
- package/dist/derivation/release.js +12 -0
- package/dist/integrations/attach.d.ts +6 -0
- package/dist/integrations/attach.js +177 -0
- package/dist/integrations/generators/read.d.ts +1 -0
- package/dist/integrations/generators/read.js +92 -0
- package/dist/integrations/generators/sdk.d.ts +1 -0
- package/dist/integrations/generators/sdk.js +148 -0
- package/dist/integrations/generators/secret.d.ts +1 -0
- package/dist/integrations/generators/secret.js +233 -0
- package/dist/integrations/generators/target.d.ts +1 -0
- package/dist/integrations/generators/target.js +765 -0
- package/dist/integrations/generators/vault.d.ts +1 -0
- package/dist/integrations/generators/vault.js +164 -0
- package/dist/integrations/sdk.d.ts +6 -0
- package/dist/integrations/sdk.js +151 -0
- package/dist/integrations/secret.d.ts +16 -0
- package/dist/integrations/secret.js +30 -0
- package/dist/integrations/target.d.ts +49 -0
- package/dist/integrations/target.js +225 -0
- package/dist/integrations/vault.d.ts +12 -0
- package/dist/integrations/vault.js +104 -0
- package/dist/integrity/attach.d.ts +2 -0
- package/dist/integrity/attach.js +213 -0
- package/dist/integrity/check-threads.d.ts +10 -0
- package/dist/integrity/check-threads.js +153 -0
- package/dist/integrity/constraint.d.ts +16 -0
- package/dist/integrity/constraint.js +1105 -0
- package/dist/integrity/generators/compiler.d.ts +1 -0
- package/dist/integrity/generators/compiler.js +130 -0
- package/dist/integrity/generators/gate.d.ts +1 -0
- package/dist/integrity/generators/gate.js +172 -0
- package/dist/integrity/generators/issues.d.ts +1 -0
- package/dist/integrity/generators/issues.js +100 -0
- package/dist/integrity/generators/publish.d.ts +1 -0
- package/dist/integrity/generators/publish.js +186 -0
- package/dist/integrity/generators/rule.d.ts +2 -0
- package/dist/integrity/generators/rule.js +213 -0
- package/dist/integrity/generators/seal.d.ts +4 -0
- package/dist/integrity/generators/seal.js +101 -0
- package/dist/integrity/generators/trial.d.ts +39 -0
- package/dist/integrity/generators/trial.js +254 -0
- package/dist/integrity/lint.d.ts +50 -0
- package/dist/integrity/lint.js +161 -0
- package/dist/integrity/lsp/bin.d.ts +2 -0
- package/dist/integrity/lsp/bin.js +35 -0
- package/dist/integrity/lsp/diagnostics.d.ts +25 -0
- package/dist/integrity/lsp/diagnostics.js +57 -0
- package/dist/integrity/lsp/findings.d.ts +20 -0
- package/dist/integrity/lsp/findings.js +39 -0
- package/dist/integrity/lsp/lint.d.ts +7 -0
- package/dist/integrity/lsp/lint.js +95 -0
- package/dist/integrity/lsp/protocol.d.ts +20 -0
- package/dist/integrity/lsp/protocol.js +57 -0
- package/dist/integrity/lsp/server.d.ts +15 -0
- package/dist/integrity/lsp/server.js +171 -0
- package/dist/integrity/sealed.d.ts +1 -0
- package/dist/integrity/sealed.js +56 -0
- package/dist/integrity/slopnator.d.ts +90 -0
- package/dist/integrity/slopnator.js +267 -0
- package/dist/integrity/slopnators/sl_broken_lineage.d.ts +2 -0
- package/dist/integrity/slopnators/sl_broken_lineage.js +35 -0
- package/dist/integrity/slopnators/sl_declared_elsewhere.d.ts +2 -0
- package/dist/integrity/slopnators/sl_declared_elsewhere.js +33 -0
- package/dist/integrity/slopnators/sl_derived_drift.d.ts +8 -0
- package/dist/integrity/slopnators/sl_derived_drift.js +91 -0
- package/dist/integrity/slopnators/sl_hardcoded_style.d.ts +2 -0
- package/dist/integrity/slopnators/sl_hardcoded_style.js +46 -0
- package/dist/integrity/slopnators/sl_inert_island.d.ts +2 -0
- package/dist/integrity/slopnators/sl_inert_island.js +85 -0
- package/dist/integrity/slopnators/sl_inert_slopnator.d.ts +2 -0
- package/dist/integrity/slopnators/sl_inert_slopnator.js +76 -0
- package/dist/integrity/slopnators/sl_missing_row.d.ts +2 -0
- package/dist/integrity/slopnators/sl_missing_row.js +180 -0
- package/dist/integrity/slopnators/sl_no_barrel.d.ts +2 -0
- package/dist/integrity/slopnators/sl_no_barrel.js +41 -0
- package/dist/integrity/slopnators/sl_no_child_process.d.ts +2 -0
- package/dist/integrity/slopnators/sl_no_child_process.js +61 -0
- package/dist/integrity/slopnators/sl_no_comment.d.ts +2 -0
- package/dist/integrity/slopnators/sl_no_comment.js +41 -0
- package/dist/integrity/slopnators/sl_no_dispatch_bypass.d.ts +2 -0
- package/dist/integrity/slopnators/sl_no_dispatch_bypass.js +301 -0
- package/dist/integrity/slopnators/sl_no_import_cycle.d.ts +2 -0
- package/dist/integrity/slopnators/sl_no_import_cycle.js +42 -0
- package/dist/integrity/slopnators/sl_no_such_command.d.ts +2 -0
- package/dist/integrity/slopnators/sl_no_such_command.js +55 -0
- package/dist/integrity/slopnators/sl_only_takes_a_literal.d.ts +2 -0
- package/dist/integrity/slopnators/sl_only_takes_a_literal.js +59 -0
- package/dist/integrity/slopnators/sl_secret_literal.d.ts +2 -0
- package/dist/integrity/slopnators/sl_secret_literal.js +89 -0
- package/dist/integrity/slopnators/sl_stale_path.d.ts +2 -0
- package/dist/integrity/slopnators/sl_stale_path.js +92 -0
- package/dist/integrity/slopnators/sl_twice_meant.d.ts +2 -0
- package/dist/integrity/slopnators/sl_twice_meant.js +30 -0
- package/dist/integrity/slopnators/sl_twice_parented.d.ts +2 -0
- package/dist/integrity/slopnators/sl_twice_parented.js +34 -0
- package/dist/integrity/slopnators/sl_undeclared_crossing.d.ts +2 -0
- package/dist/integrity/slopnators/sl_undeclared_crossing.js +78 -0
- package/dist/integrity/slopnators/sl_undeclared_destination.d.ts +2 -0
- package/dist/integrity/slopnators/sl_undeclared_destination.js +56 -0
- package/dist/integrity/slopnators/sl_undeclared_element.d.ts +2 -0
- package/dist/integrity/slopnators/sl_undeclared_element.js +34 -0
- package/dist/integrity/slopnators/sl_undeclared_node.d.ts +2 -0
- package/dist/integrity/slopnators/sl_undeclared_node.js +59 -0
- package/dist/integrity/slopnators/sl_undeclared_operation.d.ts +2 -0
- package/dist/integrity/slopnators/sl_undeclared_operation.js +120 -0
- package/dist/integrity/slopnators/sl_undeclared_variant.d.ts +2 -0
- package/dist/integrity/slopnators/sl_undeclared_variant.js +117 -0
- package/dist/integrity/slopnators/sl_undescribed.d.ts +2 -0
- package/dist/integrity/slopnators/sl_undescribed.js +54 -0
- package/dist/integrity/slopnators/sl_ungoverned_island.d.ts +2 -0
- package/dist/integrity/slopnators/sl_ungoverned_island.js +58 -0
- package/dist/integrity/slopnators/sl_unkept_rows.d.ts +2 -0
- package/dist/integrity/slopnators/sl_unkept_rows.js +104 -0
- package/dist/integrity/slopnators/sl_unnamed_island.d.ts +2 -0
- package/dist/integrity/slopnators/sl_unnamed_island.js +37 -0
- package/dist/integrity/slopnators/sl_unpaired_member.d.ts +2 -0
- package/dist/integrity/slopnators/sl_unpaired_member.js +114 -0
- package/dist/integrity/slopnators/sl_unpaired_slopnator.d.ts +2 -0
- package/dist/integrity/slopnators/sl_unpaired_slopnator.js +60 -0
- package/dist/integrity/slopnators/sl_unprefixed_member.d.ts +2 -0
- package/dist/integrity/slopnators/sl_unprefixed_member.js +126 -0
- package/dist/integrity/slopnators/sl_unseamed_reach.d.ts +2 -0
- package/dist/integrity/slopnators/sl_unseamed_reach.js +73 -0
- package/dist/integrity/slopnators/sl_unthreaded.d.ts +56 -0
- package/dist/integrity/slopnators/sl_unthreaded.js +352 -0
- package/dist/integrity/slopnators/sl_untranslated_key.d.ts +2 -0
- package/dist/integrity/slopnators/sl_untranslated_key.js +157 -0
- package/dist/integrity/slopnators/sl_unversioned.d.ts +2 -0
- package/dist/integrity/slopnators/sl_unversioned.js +31 -0
- package/dist/integrity/sweep.d.ts +24 -0
- package/dist/integrity/sweep.js +264 -0
- package/dist/knowledge/attach.d.ts +2 -0
- package/dist/knowledge/attach.js +339 -0
- package/dist/knowledge/generators/docsgen.d.ts +1 -0
- package/dist/knowledge/generators/docsgen.js +145 -0
- package/dist/knowledge/generators/glossary.d.ts +1 -0
- package/dist/knowledge/generators/glossary.js +56 -0
- package/dist/knowledge/generators/skills.d.ts +1 -0
- package/dist/knowledge/generators/skills.js +222 -0
- package/dist/knowledge/glossary.d.ts +6 -0
- package/dist/knowledge/glossary.js +1 -0
- package/dist/operations/access.d.ts +27 -0
- package/dist/operations/access.js +61 -0
- package/dist/operations/attach.d.ts +6 -0
- package/dist/operations/attach.js +414 -0
- package/dist/operations/capabilities.d.ts +37 -0
- package/dist/operations/capabilities.js +35 -0
- package/dist/operations/cost.d.ts +14 -0
- package/dist/operations/cost.js +37 -0
- package/dist/operations/dispatch.d.ts +14 -0
- package/dist/operations/dispatch.js +327 -0
- package/dist/operations/error-results.d.ts +4 -0
- package/dist/operations/error-results.js +25 -0
- package/dist/operations/errors/catalog.d.ts +58 -0
- package/dist/operations/errors/catalog.js +91 -0
- package/dist/operations/errors/classes.d.ts +73 -0
- package/dist/operations/errors/classes.js +22 -0
- package/dist/operations/errors/errors.d.ts +52 -0
- package/dist/operations/errors/errors.js +257 -0
- package/dist/operations/generators/capability.d.ts +5 -0
- package/dist/operations/generators/capability.js +603 -0
- package/dist/operations/generators/compile.d.ts +2 -0
- package/dist/operations/generators/compile.js +541 -0
- package/dist/operations/generators/grant.d.ts +1 -0
- package/dist/operations/generators/grant.js +267 -0
- package/dist/operations/generators/operation.d.ts +1 -0
- package/dist/operations/generators/operation.js +811 -0
- package/dist/operations/generators/permits.d.ts +1 -0
- package/dist/operations/generators/permits.js +196 -0
- package/dist/operations/generators/seed.d.ts +20 -0
- package/dist/operations/generators/seed.js +285 -0
- package/dist/operations/generators/trial.d.ts +53 -0
- package/dist/operations/generators/trial.js +376 -0
- package/dist/operations/http.d.ts +30 -0
- package/dist/operations/http.js +121 -0
- package/dist/operations/makers/capability.d.ts +1 -0
- package/dist/operations/makers/capability.js +117 -0
- package/dist/operations/makers/trial.d.ts +1 -0
- package/dist/operations/makers/trial.js +413 -0
- package/dist/operations/memory.d.ts +104 -0
- package/dist/operations/memory.js +365 -0
- package/dist/operations/metering.d.ts +55 -0
- package/dist/operations/metering.js +247 -0
- package/dist/operations/nodes.d.ts +35 -0
- package/dist/operations/nodes.js +15 -0
- package/dist/operations/operations.d.ts +18 -0
- package/dist/operations/operations.js +5 -0
- package/dist/operations/queue-policy.d.ts +3 -0
- package/dist/operations/queue-policy.js +8 -0
- package/dist/operations/result.d.ts +19 -0
- package/dist/operations/result.js +10 -0
- package/dist/operations/seams.d.ts +239 -0
- package/dist/operations/seams.js +45 -0
- package/dist/operations/store.d.ts +14 -0
- package/dist/operations/store.js +1 -0
- package/package.json +16 -0
|
@@ -0,0 +1,414 @@
|
|
|
1
|
+
import { named } from "../core/scope.js";
|
|
2
|
+
import { quoted } from "../core/rows.js";
|
|
3
|
+
import { PERMITS_AT } from "./access.js";
|
|
4
|
+
import { CAPABILITIES_AT, CLIENT_AT, DECLARED_SEAMS_AT, DISPATCHING_AT, MCP_AT, OPENAPI_AT, SEAMS_AT } from "./capabilities.js";
|
|
5
|
+
import { DISPATCH_AT } from "./dispatch.js";
|
|
6
|
+
import { TRIALS_AT } from "./operations.js";
|
|
7
|
+
import { MEMBERS_LIST, NODES_FILE, OPERATIONS_FILE } from "./operations.js";
|
|
8
|
+
import { SUPPLIES } from "./seams.js";
|
|
9
|
+
const HOME = `node_modules/${named('operations')}/dist`;
|
|
10
|
+
const LISTS = ['declares', 'derives', 'seeds'];
|
|
11
|
+
const VERSION = 1;
|
|
12
|
+
const ROOT = 'operations';
|
|
13
|
+
const NODES_AT = '_threads/nodes.ts';
|
|
14
|
+
const OPERATIONS_AT = '_threads/operations.ts';
|
|
15
|
+
const DESCRIBES = 'Everything this app can be asked to do. Each operation is a named job built from steps, and every one of them runs the same way. Add one with `thread create operation`.';
|
|
16
|
+
export const TAKES = 'What one operation needs before it will run: the shape of its input, what it is expected to cost, and who is allowed to ask for it. Written once when the operation is created, then yours to change.';
|
|
17
|
+
export const WOVEN = 'The operation written out as one function. `thread compile` builds it from the steps declared for it, so nothing here is edited by hand — anything added here is gone the next time it is compiled.';
|
|
18
|
+
const NODES = 'Every kind of step an operation can be built from — a read, a branch, a loop. A step holds no code of its own: the work goes in a file written beside the operation that uses it.';
|
|
19
|
+
const HANDS = 'What each kind of step hands the code inside it to work with. These live in the package rather than in this app, so a step of the same kind means the same thing in every tree.';
|
|
20
|
+
const DISPATCH = 'Every operation runs through here and nowhere else. `thread compile` writes it for this app: before a run starts it checks who is asking, what the run may cost and whether the input is valid, then runs the operation and records what happened.';
|
|
21
|
+
const PROGRAM = 'Every row this package adds to an app, listed in one place so what it put there can be read rather than guessed at. `thread attach` writes back anything missing or edited.';
|
|
22
|
+
const TRIALS = 'What each operation actually did when it was run, recorded rather than written by hand. `thread trials` runs them against their example inputs and keeps the results; `thread trials --check` runs them again and refuses anything that has changed since.';
|
|
23
|
+
const CAPABILITIES = 'Which of this app\'s operations can be reached from outside, and how — as an MCP tool, a terminal command, or a web route. Everything here is worked out from the operations themselves except whether a surface is switched on, which is yours to set.';
|
|
24
|
+
const OPENAPI = 'This app\'s web API written as an OpenAPI document: the route, the verb and the input shape of every operation that answers on the web. Generated rather than written, so it cannot describe a route that is not there.';
|
|
25
|
+
const TOOLS = 'The tools an MCP client is offered: every operation switched on for that surface, with its own sentence and the shape of its input. Switching `mcp` off for an operation is how an agent is told it may not call it.';
|
|
26
|
+
const CLIENT = 'Every operation a page in this app may call. An operation that is switched off is absent from this file rather than listed and disabled, as is any operation needing a credential a browser must not hold.';
|
|
27
|
+
const SAID = {
|
|
28
|
+
sm_store: 'Reading and writing rows. An operation that requires it is handed get, list, insert, update and remove already bound to whoever asked, so every row it touches is written under the caller the log names.',
|
|
29
|
+
sm_search: 'Indexing a row and querying an index. Required by an operation that has to find something it cannot address by id.',
|
|
30
|
+
sm_queue: 'Handing work to something else to run later. Required by an operation that finishes before its effect does.',
|
|
31
|
+
sm_events: 'Announcing that something happened, to whoever is listening. Required by an operation other parts of an app react to.',
|
|
32
|
+
sm_clock: 'The current time. Required rather than read off the runtime, because an operation that reads the wall clock directly cannot be replayed and its trial cannot be trusted.',
|
|
33
|
+
sm_random: 'Randomness. Required for the same reason as the clock: a run nobody can reproduce is a run nobody can check.',
|
|
34
|
+
sm_vault: 'Resolving a secret by name, for the rare thing that is not a call — signing a webhook, checking a shared token. An operation that reaches a target does not need this: requiring the target hands its nodes calls with the credential already in them, which is the whole point of declaring one.',
|
|
35
|
+
sm_views: 'Reading through a declared view rather than a table. Required by an operation that reads what somebody else composed.',
|
|
36
|
+
sm_files: 'Putting a file somewhere, fetching one back, or handing out a signed link to one. Required rather than reached for, because a node that opens a path directly is doing work no record names.',
|
|
37
|
+
};
|
|
38
|
+
const OFFERED = SUPPLIES.map((id) => ({
|
|
39
|
+
id,
|
|
40
|
+
at: NODES_AT,
|
|
41
|
+
describes: SAID[id],
|
|
42
|
+
version: VERSION,
|
|
43
|
+
}));
|
|
44
|
+
const valued = (one) => {
|
|
45
|
+
if (typeof one === 'string')
|
|
46
|
+
return quoted(one);
|
|
47
|
+
if (Array.isArray(one))
|
|
48
|
+
return `[${one.map((each) => valued(each)).join(', ')}]`;
|
|
49
|
+
if (typeof one === 'object' && one !== null) {
|
|
50
|
+
return `{ ${Object.entries(one).map(([key, held]) => `${key}: ${valued(held)}`).join(', ')} }`;
|
|
51
|
+
}
|
|
52
|
+
return String(one);
|
|
53
|
+
};
|
|
54
|
+
export const said = (one, pad) => {
|
|
55
|
+
const { declares, derives, seeds, ...plain } = one;
|
|
56
|
+
const lines = [`${pad}{`];
|
|
57
|
+
for (const [key, held] of Object.entries(plain))
|
|
58
|
+
lines.push(`${pad} ${key}: ${valued(held)},`);
|
|
59
|
+
for (const list of LISTS) {
|
|
60
|
+
const held = one[list];
|
|
61
|
+
if (held === undefined)
|
|
62
|
+
continue;
|
|
63
|
+
lines.push(`${pad} ${list}: [`);
|
|
64
|
+
for (const child of held)
|
|
65
|
+
lines.push(said(child, `${pad} `));
|
|
66
|
+
lines.push(`${pad} ],`);
|
|
67
|
+
}
|
|
68
|
+
return [...lines, `${pad}},`].join('\n');
|
|
69
|
+
};
|
|
70
|
+
const ACCESS = 'Who may ask this app to do what. A row says which operations it permits, on what, to whom, and under what condition. Nothing is permitted by default: an operation no row grants here cannot be run at all.';
|
|
71
|
+
const PERMITS = 'The check compiled from the grants in _threads/access.ts: one branch per grant, so who may ask for what comes from one statement. Nobody edits it, because an edit here widens or narrows access nobody granted. An app that grants nothing permits nothing.';
|
|
72
|
+
const SEAMS = 'What this app hands its operations, written once and then yours. It starts by handing on everything src/_generated/seams.ts settles from your declarations. Replace a seam or add one by naming it in SEAMS: the queue, the events, telemetry, whatever a real deployment needs.';
|
|
73
|
+
const DECLARED_SEAMS = 'The seams your declarations settle. Rows go to the store each target derived, or to memory until one does; who is calling is read off the entity that names the caller; calls leave through http with credentials the vault opens. Nobody edits it: `thread capabilities` writes it again from the rows.';
|
|
74
|
+
const ACCESS_SOURCE = `import type { Grant } from './access.ts'
|
|
75
|
+
|
|
76
|
+
export const GRANTS: readonly Grant[] = []
|
|
77
|
+
`;
|
|
78
|
+
const shipped = () => ({
|
|
79
|
+
id: 'shipped',
|
|
80
|
+
at: `${HOME}/attach.js`,
|
|
81
|
+
describes: PROGRAM,
|
|
82
|
+
version: VERSION,
|
|
83
|
+
declares: [
|
|
84
|
+
{
|
|
85
|
+
id: 'operations',
|
|
86
|
+
at: OPERATIONS_AT,
|
|
87
|
+
describes: DESCRIBES,
|
|
88
|
+
version: VERSION,
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
id: 'nodes',
|
|
92
|
+
at: NODES_AT,
|
|
93
|
+
describes: NODES,
|
|
94
|
+
version: VERSION,
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
id: 'access',
|
|
98
|
+
at: '_threads/access.ts',
|
|
99
|
+
describes: ACCESS,
|
|
100
|
+
version: VERSION,
|
|
101
|
+
},
|
|
102
|
+
{
|
|
103
|
+
id: 'permits',
|
|
104
|
+
at: PERMITS_AT,
|
|
105
|
+
describes: PERMITS,
|
|
106
|
+
version: VERSION,
|
|
107
|
+
by: 'thread permits',
|
|
108
|
+
runs: 'thread permits --check',
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
id: 'dispatch',
|
|
112
|
+
at: DISPATCH_AT,
|
|
113
|
+
describes: DISPATCH,
|
|
114
|
+
version: VERSION,
|
|
115
|
+
by: 'thread compile',
|
|
116
|
+
runs: 'thread compile --check',
|
|
117
|
+
},
|
|
118
|
+
{
|
|
119
|
+
id: 'hands',
|
|
120
|
+
at: `${HOME}/nodes.js`,
|
|
121
|
+
describes: HANDS,
|
|
122
|
+
version: VERSION,
|
|
123
|
+
},
|
|
124
|
+
{
|
|
125
|
+
id: 'trials',
|
|
126
|
+
at: TRIALS_AT,
|
|
127
|
+
describes: TRIALS,
|
|
128
|
+
version: VERSION,
|
|
129
|
+
by: 'thread trials',
|
|
130
|
+
runs: 'thread trials --check',
|
|
131
|
+
},
|
|
132
|
+
{
|
|
133
|
+
id: 'capabilities',
|
|
134
|
+
at: CAPABILITIES_AT,
|
|
135
|
+
describes: CAPABILITIES,
|
|
136
|
+
version: VERSION,
|
|
137
|
+
by: 'thread capabilities',
|
|
138
|
+
runs: 'thread capabilities --check',
|
|
139
|
+
},
|
|
140
|
+
{
|
|
141
|
+
id: 'openapi',
|
|
142
|
+
at: OPENAPI_AT,
|
|
143
|
+
describes: OPENAPI,
|
|
144
|
+
version: VERSION,
|
|
145
|
+
by: 'thread capabilities',
|
|
146
|
+
runs: 'thread capabilities --check',
|
|
147
|
+
},
|
|
148
|
+
{
|
|
149
|
+
id: 'tools',
|
|
150
|
+
at: MCP_AT,
|
|
151
|
+
describes: TOOLS,
|
|
152
|
+
version: VERSION,
|
|
153
|
+
by: 'thread capabilities',
|
|
154
|
+
runs: 'thread capabilities --check',
|
|
155
|
+
},
|
|
156
|
+
{
|
|
157
|
+
id: 'client',
|
|
158
|
+
at: CLIENT_AT,
|
|
159
|
+
describes: CLIENT,
|
|
160
|
+
version: VERSION,
|
|
161
|
+
by: 'thread capabilities',
|
|
162
|
+
runs: 'thread capabilities --check',
|
|
163
|
+
},
|
|
164
|
+
{
|
|
165
|
+
id: 'dispatching',
|
|
166
|
+
at: DISPATCHING_AT,
|
|
167
|
+
describes: 'The operations this app declares, named wherever something reaches one. The framework ships an empty list and each app widens it, so a name written at a call site is accepted only when this app declared an operation by it.',
|
|
168
|
+
version: VERSION,
|
|
169
|
+
by: 'thread capabilities',
|
|
170
|
+
runs: 'thread capabilities --check',
|
|
171
|
+
},
|
|
172
|
+
{
|
|
173
|
+
id: 'seams',
|
|
174
|
+
at: SEAMS_AT,
|
|
175
|
+
describes: SEAMS,
|
|
176
|
+
version: VERSION,
|
|
177
|
+
by: 'thread capabilities',
|
|
178
|
+
},
|
|
179
|
+
{
|
|
180
|
+
id: 'declared-seams',
|
|
181
|
+
at: DECLARED_SEAMS_AT,
|
|
182
|
+
describes: DECLARED_SEAMS,
|
|
183
|
+
version: VERSION,
|
|
184
|
+
by: 'thread capabilities',
|
|
185
|
+
runs: 'thread capabilities --check',
|
|
186
|
+
},
|
|
187
|
+
{
|
|
188
|
+
id: 'nd_read',
|
|
189
|
+
at: NODES_AT,
|
|
190
|
+
describes: 'A node that only reads. It is handed the store and the search and nothing else, so it cannot write — the fetch an operation does before it decides anything.',
|
|
191
|
+
version: VERSION,
|
|
192
|
+
},
|
|
193
|
+
{
|
|
194
|
+
id: 'nd_action',
|
|
195
|
+
at: NODES_AT,
|
|
196
|
+
describes: 'A node that changes something — a write, a call out, a spend. It is handed everything, and it is where an operation keeps its effects rather than spreading them across the flow.',
|
|
197
|
+
version: VERSION,
|
|
198
|
+
},
|
|
199
|
+
{
|
|
200
|
+
id: 'nd_branch',
|
|
201
|
+
at: NODES_AT,
|
|
202
|
+
describes: 'A node that chooses. Its first block returns a name, and the way with that name is what runs, so a fork in the flow is visible in the declaration instead of buried in an if.',
|
|
203
|
+
version: VERSION,
|
|
204
|
+
},
|
|
205
|
+
{
|
|
206
|
+
id: 'nd_each',
|
|
207
|
+
at: NODES_AT,
|
|
208
|
+
describes: 'A node that runs once per item, in order, one at a time. Its block is handed a single item and never the collection, so it cannot reorder them or batch them behind your back.',
|
|
209
|
+
version: VERSION,
|
|
210
|
+
},
|
|
211
|
+
{
|
|
212
|
+
id: 'nd_parallel',
|
|
213
|
+
at: NODES_AT,
|
|
214
|
+
describes: 'A step that runs several blocks at once and answers when all of them have. They cannot see each other, so use it for work that does not depend on itself.',
|
|
215
|
+
version: VERSION,
|
|
216
|
+
},
|
|
217
|
+
{
|
|
218
|
+
id: 'nd_repeat',
|
|
219
|
+
at: NODES_AT,
|
|
220
|
+
describes: 'A step that runs its block again until the block says it is done — a retry, or an agent loop. A limit is required, so it cannot run forever.',
|
|
221
|
+
version: VERSION,
|
|
222
|
+
},
|
|
223
|
+
{
|
|
224
|
+
id: 'nd_stop',
|
|
225
|
+
at: NODES_AT,
|
|
226
|
+
describes: 'A step that ends the operation early with an answer. Whatever its block returns becomes the result, and nothing after it runs.',
|
|
227
|
+
version: VERSION,
|
|
228
|
+
},
|
|
229
|
+
...OFFERED,
|
|
230
|
+
],
|
|
231
|
+
});
|
|
232
|
+
const SHIPS = shipped();
|
|
233
|
+
const WHERE = {
|
|
234
|
+
nodes: { into: OPERATIONS_FILE, list: 'declares' },
|
|
235
|
+
dispatch: { into: OPERATIONS_FILE, list: 'declares' },
|
|
236
|
+
access: { into: OPERATIONS_FILE, list: 'declares' },
|
|
237
|
+
permits: { into: OPERATIONS_FILE, list: 'declares' },
|
|
238
|
+
'declared-seams': { into: OPERATIONS_FILE, list: 'declares' },
|
|
239
|
+
trials: { into: OPERATIONS_FILE, list: 'declares' },
|
|
240
|
+
capabilities: { into: OPERATIONS_FILE, list: 'declares' },
|
|
241
|
+
openapi: { into: OPERATIONS_FILE, list: 'declares' },
|
|
242
|
+
tools: { into: OPERATIONS_FILE, list: 'declares' },
|
|
243
|
+
client: { into: OPERATIONS_FILE, list: 'declares' },
|
|
244
|
+
dispatching: { into: OPERATIONS_FILE, list: 'declares' },
|
|
245
|
+
seams: { into: OPERATIONS_FILE, list: 'declares' },
|
|
246
|
+
hands: { into: NODES_FILE, list: 'declares' },
|
|
247
|
+
};
|
|
248
|
+
const placed = (id) => WHERE[id] ?? { into: NODES_FILE, list: MEMBERS_LIST };
|
|
249
|
+
const NODES_SOURCE = `import type { Threaded } from '../core/thread.ts'
|
|
250
|
+
import type { Node } from './nodes.ts'
|
|
251
|
+
|
|
252
|
+
export const NODES: Threaded = {
|
|
253
|
+
id: 'nodes',
|
|
254
|
+
at: ${quoted(NODES_AT)},
|
|
255
|
+
describes: ${quoted(NODES)},
|
|
256
|
+
version: ${String(VERSION)},
|
|
257
|
+
declares: [],
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
export const ${MEMBERS_LIST}: readonly Node[] = []
|
|
261
|
+
`;
|
|
262
|
+
const OPERATIONS_SOURCE = `import type { Member, Threaded } from '../core/thread.ts'
|
|
263
|
+
|
|
264
|
+
export const OPERATIONS: Threaded = {
|
|
265
|
+
id: 'operations',
|
|
266
|
+
at: ${quoted(OPERATIONS_AT)},
|
|
267
|
+
describes: ${quoted(DESCRIBES)},
|
|
268
|
+
version: ${String(VERSION)},
|
|
269
|
+
declares: [],
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
export const ${MEMBERS_LIST}: readonly Member[] = []
|
|
273
|
+
`;
|
|
274
|
+
const SEEDED = {
|
|
275
|
+
attaches: ['@prestack/thread/derivation/attach'],
|
|
276
|
+
id: 'operations',
|
|
277
|
+
declares: [
|
|
278
|
+
' {',
|
|
279
|
+
' id: \'operations\',',
|
|
280
|
+
' at: \'_threads/operations.ts\',',
|
|
281
|
+
' describes: \'Everything this app can be asked to do. Each operation is a named job built from steps, and every one of them runs the same way. Add one with `thread create operation`.\',',
|
|
282
|
+
' version: 1,',
|
|
283
|
+
' },',
|
|
284
|
+
].join('\n'),
|
|
285
|
+
};
|
|
286
|
+
const SHIPPED = [
|
|
287
|
+
{
|
|
288
|
+
into: 'derivation.ts',
|
|
289
|
+
list: 'GENERATORS',
|
|
290
|
+
id: 'capability-generator',
|
|
291
|
+
source: " {\n id: 'capability-generator',\n at: 'node_modules/@prestack/thread/dist/operations/generators/capability.js',\n describes: 'Writes what can be reached and how, and refuses it once it has drifted. It reads each operation for its name, what it does and the shape of its input, so adding or renaming one changes what is reachable without anybody editing a list.',\n version: 1,\n by: 'thread capabilities',\n runs: 'thread capabilities --check',\n },",
|
|
292
|
+
},
|
|
293
|
+
{
|
|
294
|
+
into: 'derivation.ts',
|
|
295
|
+
list: 'GENERATORS',
|
|
296
|
+
id: 'capability-noun',
|
|
297
|
+
source: " {\n id: 'capability-noun',\n at: 'node_modules/@prestack/thread/dist/operations/makers/capability.js',\n describes: 'Reads and changes what this app exposes. `thread create capability` lists every operation with the surfaces it answers on, and `edit` switches one on or off.',\n version: 1,\n by: 'thread create capability',\n },",
|
|
298
|
+
},
|
|
299
|
+
{
|
|
300
|
+
into: 'derivation.ts',
|
|
301
|
+
list: 'GENERATORS',
|
|
302
|
+
id: 'trial-noun',
|
|
303
|
+
source: " {\n id: 'trial-noun',\n at: 'node_modules/@prestack/thread/dist/operations/makers/trial.js',\n describes: 'Runs one operation against an input you supply, and records what happened. `thread run trial <operation>` asks for that input, because what to run an operation on is the one thing nothing else can work out for you.',\n version: 1,\n by: 'thread run trial',\n },",
|
|
304
|
+
},
|
|
305
|
+
{
|
|
306
|
+
into: 'derivation.ts',
|
|
307
|
+
list: 'GENERATORS',
|
|
308
|
+
id: 'seed-generator',
|
|
309
|
+
source: " {\n id: 'seed-generator',\n at: 'node_modules/@prestack/thread/dist/operations/generators/seed.js',\n describes: 'Writes every file an operation puts on disk. The wrapper around each step comes from the rows; the code inside it is yours and is put back untouched. Anything that no longer matches what it writes is refused, so a step cannot be added by editing the file.',\n version: 1,\n by: 'thread seed',\n runs: 'thread seed --check',\n },",
|
|
310
|
+
},
|
|
311
|
+
{
|
|
312
|
+
into: 'derivation.ts',
|
|
313
|
+
list: 'GENERATORS',
|
|
314
|
+
id: 'compile-generator',
|
|
315
|
+
source: " {\n id: 'compile-generator',\n at: 'node_modules/@prestack/thread/dist/operations/generators/compile.js',\n describes: 'Turns an operation\\'s steps into one function: each block bound where it is used, and each branch or loop written out as the real thing. What it writes imports nothing from this framework, so what ships is plain code.',\n version: 1,\n by: 'thread compile',\n runs: 'thread compile --check',\n },",
|
|
316
|
+
},
|
|
317
|
+
{
|
|
318
|
+
into: 'derivation.ts',
|
|
319
|
+
list: 'GENERATORS',
|
|
320
|
+
id: 'permits-generator',
|
|
321
|
+
source: " {\n id: 'permits-generator',\n at: 'node_modules/@prestack/thread/dist/operations/generators/permits.js',\n describes: 'Writes the check this app runs before any operation — one branch per grant, so who may ask for what comes from one statement rather than being repeated in every handler. It refuses a grant it cannot check honestly, such as one that would admit a caller nobody authenticated.',\n version: 1,\n by: 'thread permits',\n runs: 'thread permits --check',\n },",
|
|
322
|
+
},
|
|
323
|
+
{
|
|
324
|
+
into: 'derivation.ts',
|
|
325
|
+
list: 'GENERATORS',
|
|
326
|
+
id: 'grant-generator',
|
|
327
|
+
source: " {\n id: 'grant-generator',\n at: 'node_modules/@prestack/thread/dist/operations/generators/grant.js',\n describes: 'Records who may ask this app to do what. Run with nothing, it lists every operation and every grant already written. It builds the condition one answer at a time, offering only what the answer before it allows, so an impossible comparison is refused as it is typed.',\n version: 1,\n by: 'thread grant',\n },",
|
|
328
|
+
},
|
|
329
|
+
{
|
|
330
|
+
into: 'derivation.ts',
|
|
331
|
+
list: 'GENERATORS',
|
|
332
|
+
id: 'operation-noun',
|
|
333
|
+
source: " {\n id: 'operation-noun',\n at: 'node_modules/@prestack/thread/dist/operations/generators/operation.js',\n describes: 'Declares something this app can be asked to do, and the steps it is done in. This row is what makes `operation` one of the things `thread create` offers — the nouns are not a list inside the command, but rows like this one.',\n version: 1,\n by: 'thread create operation',\n },",
|
|
334
|
+
},
|
|
335
|
+
{
|
|
336
|
+
into: 'derivation.ts',
|
|
337
|
+
list: 'GENERATORS',
|
|
338
|
+
id: 'trial-generator',
|
|
339
|
+
source: " {\n id: 'trial-generator',\n at: 'node_modules/@prestack/thread/dist/operations/generators/trial.js',\n describes: 'Records what an operation does, and refuses it once it has changed. It runs the compiled operation through this app\\'s own dispatch, so what is checked is the code that ships. Time and randomness are pinned, so a run can be repeated.',\n version: 1,\n by: 'thread trials',\n runs: 'thread trials --check',\n },",
|
|
340
|
+
},
|
|
341
|
+
];
|
|
342
|
+
export const ATTACH = {
|
|
343
|
+
attaches: SEEDED.attaches,
|
|
344
|
+
id: SEEDED.id,
|
|
345
|
+
declares: SEEDED.declares,
|
|
346
|
+
writes: [
|
|
347
|
+
{ file: OPERATIONS_FILE, source: OPERATIONS_SOURCE },
|
|
348
|
+
{ file: NODES_FILE, source: NODES_SOURCE },
|
|
349
|
+
{ file: 'access.ts', source: ACCESS_SOURCE },
|
|
350
|
+
],
|
|
351
|
+
retires: [
|
|
352
|
+
{
|
|
353
|
+
into: 'operations.ts',
|
|
354
|
+
list: 'declares',
|
|
355
|
+
id: 'reference',
|
|
356
|
+
made: `${ROOT}/_docs.md`,
|
|
357
|
+
why: `the page stating what this app declares is written by \`${named('knowledge')}\` now, at docs.md, and it states every node rather than operations alone — a package documenting what another package declares would be one package authoring another's`,
|
|
358
|
+
},
|
|
359
|
+
{
|
|
360
|
+
into: 'derivation.ts',
|
|
361
|
+
list: 'GENERATORS',
|
|
362
|
+
id: 'create-generator',
|
|
363
|
+
why: '`thread create` is a command of the CLI itself now, so no row declares it. This package still makes operations, through the `operation-noun` row beside this one',
|
|
364
|
+
},
|
|
365
|
+
{
|
|
366
|
+
into: 'operations.ts',
|
|
367
|
+
list: 'declares',
|
|
368
|
+
id: 'identity',
|
|
369
|
+
made: `src/identity.${'ts'}`,
|
|
370
|
+
why: 'who is calling is answered in `src/seams.ts` now, beside the store it reads the caller\'s row from. One derived file says both, because both are read off the same rows',
|
|
371
|
+
},
|
|
372
|
+
{
|
|
373
|
+
into: 'operations.ts',
|
|
374
|
+
list: 'declares',
|
|
375
|
+
id: 'store',
|
|
376
|
+
made: `src/store.${'ts'}`,
|
|
377
|
+
why: 'where rows go is decided in `src/seams.ts` now, read off the targets this app declares. A second file that only re-exported one name said nothing the seams did not',
|
|
378
|
+
},
|
|
379
|
+
{
|
|
380
|
+
into: 'operations.ts',
|
|
381
|
+
list: 'declares',
|
|
382
|
+
id: 'rules-gate',
|
|
383
|
+
made: `src/rules.${'ts'}`,
|
|
384
|
+
why: '`rules` is what this app refuses, declared in _threads/rules.ts with `thread create rule`. Who may ask for what is `permits`, compiled from the grants and handed to dispatch by src/_generated/seams.ts, so a second file wearing the word said nothing the grants did not',
|
|
385
|
+
},
|
|
386
|
+
{
|
|
387
|
+
into: 'derivation.ts',
|
|
388
|
+
list: 'GENERATORS',
|
|
389
|
+
id: 'rules-generator',
|
|
390
|
+
why: 'the check compiled from the grants is `permits`, and `thread permits` writes it now, through the `permits-generator` row beside this one. A generator called `rules` read as the app\'s own rules, which are declared in _threads/rules.ts with `thread create rule`',
|
|
391
|
+
},
|
|
392
|
+
{
|
|
393
|
+
into: NODES_FILE,
|
|
394
|
+
list: MEMBERS_LIST,
|
|
395
|
+
id: 'sm_http',
|
|
396
|
+
why: 'a call goes to a place, and a place is a target — declare it with `thread create target` and require that instead. Asking for a bare transport is what made an operation impossible to try, because nothing said where it went',
|
|
397
|
+
},
|
|
398
|
+
{
|
|
399
|
+
into: NODES_FILE,
|
|
400
|
+
list: MEMBERS_LIST,
|
|
401
|
+
id: 'sm_llm',
|
|
402
|
+
why: 'a model is reached over https like any other vendor, so it is an `ht_` target with its calls declared beside it. Nothing was lost: its address and its key are now under the same rules as every other credential, and an operation that asks a model can now be tried',
|
|
403
|
+
},
|
|
404
|
+
],
|
|
405
|
+
rows: [
|
|
406
|
+
...(SHIPS.declares ?? [])
|
|
407
|
+
.filter((one) => one.id !== ROOT)
|
|
408
|
+
.map((one) => {
|
|
409
|
+
const where = placed(one.id);
|
|
410
|
+
return { into: where.into, list: where.list, id: one.id, source: said(one, where.list === 'declares' ? ' ' : ' ') };
|
|
411
|
+
}),
|
|
412
|
+
...SHIPPED,
|
|
413
|
+
],
|
|
414
|
+
};
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
export declare const SURFACES: readonly ["cli", "api", "mcp"];
|
|
2
|
+
export type Surface = (typeof SURFACES)[number];
|
|
3
|
+
export declare const isSurface: (one: string) => one is Surface;
|
|
4
|
+
export declare const CAPABILITIES_AT = "operations/_capabilities.json";
|
|
5
|
+
export declare const CLIENT_AT = "operations/_client.ts";
|
|
6
|
+
export declare const DISPATCHING_AT = "app/_generated/dispatching.ts";
|
|
7
|
+
export declare const routeAt: (operation: string) => string;
|
|
8
|
+
export declare const ROUTE = "The file that answers a request for this one operation. It imports the operation by name, hands it to this app's own dispatch with the seams and the caller its seams file supplies, and answers with the result \u2014 or with the status matching whatever dispatch refused it for. One per operation rather than one for all of them: a route that looked its operation up by a name off the path would hand dispatch something no check had ever seen, which reads exactly like a name that was checked. Switching the `api` surface off in the capabilities table stops this file being written at all, so the operation stops being served rather than being served and turned away.";
|
|
9
|
+
export declare const SEAMS_AT = "src/seams.ts";
|
|
10
|
+
export declare const DECLARED_SEAMS_AT = "src/_generated/seams.ts";
|
|
11
|
+
export declare const OPENAPI_AT = "operations/_openapi.json";
|
|
12
|
+
export declare const MCP_AT = "operations/_mcp.json";
|
|
13
|
+
export interface Capability {
|
|
14
|
+
readonly operation: string;
|
|
15
|
+
readonly describes: string;
|
|
16
|
+
readonly requires: readonly string[];
|
|
17
|
+
readonly nodes: readonly string[];
|
|
18
|
+
readonly input: unknown;
|
|
19
|
+
readonly live: readonly Surface[];
|
|
20
|
+
readonly browsable: boolean;
|
|
21
|
+
readonly local: boolean;
|
|
22
|
+
readonly mcp: {
|
|
23
|
+
readonly name: string;
|
|
24
|
+
readonly description: string;
|
|
25
|
+
readonly inputSchema: unknown;
|
|
26
|
+
};
|
|
27
|
+
readonly cli: {
|
|
28
|
+
readonly invocation: string;
|
|
29
|
+
readonly describes: string;
|
|
30
|
+
};
|
|
31
|
+
readonly api: {
|
|
32
|
+
readonly method: 'GET' | 'POST';
|
|
33
|
+
readonly path: string;
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
export declare const reachable: (one: Capability, surface: Surface) => boolean;
|
|
37
|
+
export declare function switched(text: string | undefined): ReadonlyMap<string, readonly Surface[]>;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
export const SURFACES = ['cli', 'api', 'mcp'];
|
|
2
|
+
export const isSurface = (one) => SURFACES.includes(one);
|
|
3
|
+
export const CAPABILITIES_AT = 'operations/_capabilities.json';
|
|
4
|
+
export const CLIENT_AT = 'operations/_client.ts';
|
|
5
|
+
export const DISPATCHING_AT = 'app/_generated/dispatching.ts';
|
|
6
|
+
export const routeAt = (operation) => `app/operations/${operation}/route.ts`;
|
|
7
|
+
export const ROUTE = 'The file that answers a request for this one operation. It imports the operation by name, hands it to this app\'s own dispatch with the seams and the caller its seams file supplies, and answers with the result — or with the status matching whatever dispatch refused it for. One per operation rather than one for all of them: a route that looked its operation up by a name off the path would hand dispatch something no check had ever seen, which reads exactly like a name that was checked. Switching the `api` surface off in the capabilities table stops this file being written at all, so the operation stops being served rather than being served and turned away.';
|
|
8
|
+
export const SEAMS_AT = 'src/seams.ts';
|
|
9
|
+
export const DECLARED_SEAMS_AT = 'src/_generated/seams.ts';
|
|
10
|
+
export const OPENAPI_AT = 'operations/_openapi.json';
|
|
11
|
+
export const MCP_AT = 'operations/_mcp.json';
|
|
12
|
+
export const reachable = (one, surface) => one.live.includes(surface);
|
|
13
|
+
export function switched(text) {
|
|
14
|
+
const found = new Map();
|
|
15
|
+
if (text === undefined || text.trim() === '')
|
|
16
|
+
return found;
|
|
17
|
+
let held;
|
|
18
|
+
try {
|
|
19
|
+
held = JSON.parse(text);
|
|
20
|
+
}
|
|
21
|
+
catch {
|
|
22
|
+
return found;
|
|
23
|
+
}
|
|
24
|
+
if (!Array.isArray(held))
|
|
25
|
+
return found;
|
|
26
|
+
for (const one of held) {
|
|
27
|
+
if (typeof one !== 'object' || one === null)
|
|
28
|
+
continue;
|
|
29
|
+
const row = one;
|
|
30
|
+
if (typeof row.operation !== 'string' || !Array.isArray(row.live))
|
|
31
|
+
continue;
|
|
32
|
+
found.set(row.operation, row.live.filter((each) => typeof each === 'string' && isSurface(each)));
|
|
33
|
+
}
|
|
34
|
+
return found;
|
|
35
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export interface CostAmount {
|
|
2
|
+
readonly usdMicroCents: number;
|
|
3
|
+
readonly chargedMicroCents: number;
|
|
4
|
+
readonly currency: string;
|
|
5
|
+
readonly meter: string;
|
|
6
|
+
}
|
|
7
|
+
export declare class InvalidCostError extends Error {
|
|
8
|
+
constructor(message: string);
|
|
9
|
+
}
|
|
10
|
+
export declare function assertValidCost(cost: CostAmount): void;
|
|
11
|
+
export declare const MICRO_CENTS_PER_CENT = 1000000;
|
|
12
|
+
export declare const MICRO_CENTS_PER_UNIT = 100000000;
|
|
13
|
+
export declare function toMicroCents(amount: number): number;
|
|
14
|
+
export declare function fromMicroCents(microCents: number): number;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
export class InvalidCostError extends Error {
|
|
2
|
+
constructor(message) {
|
|
3
|
+
super(message);
|
|
4
|
+
this.name = 'InvalidCostError';
|
|
5
|
+
}
|
|
6
|
+
}
|
|
7
|
+
function assertIntegerMicroCents(value, field) {
|
|
8
|
+
if (!Number.isFinite(value) || !Number.isInteger(value)) {
|
|
9
|
+
throw new InvalidCostError(`${field} must be an integer number of micro-cents, received ${value}. ` +
|
|
10
|
+
'Convert before recording — never round.');
|
|
11
|
+
}
|
|
12
|
+
if (value < 0)
|
|
13
|
+
throw new InvalidCostError(`${field} must not be negative, received ${value}`);
|
|
14
|
+
}
|
|
15
|
+
export function assertValidCost(cost) {
|
|
16
|
+
assertIntegerMicroCents(cost.usdMicroCents, 'usdMicroCents');
|
|
17
|
+
assertIntegerMicroCents(cost.chargedMicroCents, 'chargedMicroCents');
|
|
18
|
+
if (typeof cost.currency !== 'string' || cost.currency.trim() === '') {
|
|
19
|
+
throw new InvalidCostError('cost.currency is required and has no default — resolve it from real data (DATA.md §8)');
|
|
20
|
+
}
|
|
21
|
+
if (!/^[A-Z]{3}$/.test(cost.currency)) {
|
|
22
|
+
throw new InvalidCostError(`cost.currency must be an ISO-4217 code, received "${cost.currency}"`);
|
|
23
|
+
}
|
|
24
|
+
if (typeof cost.meter !== 'string' || cost.meter.trim() === '') {
|
|
25
|
+
throw new InvalidCostError('cost.meter is required — a cost with no meter cannot be quota-checked');
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
export const MICRO_CENTS_PER_CENT = 1_000_000;
|
|
29
|
+
export const MICRO_CENTS_PER_UNIT = 100_000_000;
|
|
30
|
+
export function toMicroCents(amount) {
|
|
31
|
+
if (!Number.isFinite(amount))
|
|
32
|
+
throw new InvalidCostError(`cannot convert ${amount} to micro-cents`);
|
|
33
|
+
return Math.round(amount * MICRO_CENTS_PER_UNIT);
|
|
34
|
+
}
|
|
35
|
+
export function fromMicroCents(microCents) {
|
|
36
|
+
return microCents / MICRO_CENTS_PER_UNIT;
|
|
37
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export declare const DISPATCH_AT = "operations/_dispatch.ts";
|
|
2
|
+
export declare const dispatched: (reached: Readonly<Record<string, {
|
|
3
|
+
readonly reach: string;
|
|
4
|
+
readonly address: string | null;
|
|
5
|
+
readonly sends: readonly {
|
|
6
|
+
readonly secret: string;
|
|
7
|
+
readonly header: string;
|
|
8
|
+
readonly prefix: string;
|
|
9
|
+
}[];
|
|
10
|
+
readonly calls: Readonly<Record<string, {
|
|
11
|
+
readonly method: string;
|
|
12
|
+
readonly path: string;
|
|
13
|
+
}>>;
|
|
14
|
+
}>>) => string;
|