@prestack/thread 0.1.3 → 0.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +563 -0
- package/dist/core/actor.d.ts +1 -1
- package/dist/core/actor.js +5 -4
- package/dist/core/actor.ts +5 -4
- package/dist/core/attach.d.ts +0 -7
- package/dist/core/attach.js +38 -67
- package/dist/core/attach.ts +34 -80
- package/dist/core/chain.js +13 -17
- package/dist/core/chain.ts +11 -15
- package/dist/core/condition.d.ts +4 -4
- package/dist/core/condition.js +2 -2
- package/dist/core/descend.d.ts +4 -2
- package/dist/core/descend.js +91 -23
- package/dist/core/descend.ts +90 -21
- package/dist/core/errors/catalogue.d.ts +52 -0
- package/dist/{operations/errors/errors.js → core/errors/catalogue.js} +1 -1
- package/dist/{operations/errors/errors.ts → core/errors/catalogue.ts} +1 -1
- package/dist/{operations/errors/catalog.d.ts → core/errors/error.d.ts} +2 -3
- package/dist/{operations/errors/catalog.js → core/errors/error.js} +1 -16
- package/dist/{operations/errors/catalog.ts → core/errors/error.ts} +3 -19
- package/dist/core/errors/namespaces.d.ts +3 -0
- package/dist/core/errors/namespaces.js +15 -0
- package/dist/core/errors/namespaces.ts +19 -0
- package/dist/core/finding.js +2 -2
- package/dist/core/finding.ts +1 -2
- package/dist/core/init.d.ts +1 -1
- package/dist/core/init.js +51 -5
- package/dist/core/init.ts +58 -5
- package/dist/core/invoked.d.ts +1 -1
- package/dist/core/invoked.js +3 -1
- package/dist/core/invoked.ts +5 -2
- package/dist/core/round.js +36 -22
- package/dist/core/round.ts +26 -9
- package/dist/core/rows.d.ts +4 -0
- package/dist/core/rows.js +31 -2
- package/dist/core/rows.ts +33 -1
- package/dist/core/scope.d.ts +1 -0
- package/dist/core/scope.js +1 -0
- package/dist/core/scope.ts +2 -0
- package/dist/core/thread.d.ts +3 -3
- package/dist/core/tree.d.ts +4 -1
- package/dist/core/tree.js +26 -6
- package/dist/core/tree.ts +29 -6
- package/dist/core/types.d.ts +3 -3
- package/dist/core/types.js +3 -1
- package/dist/core/types.ts +2 -1
- package/dist/derivation/attach.js +3 -2
- package/dist/derivation/attach.ts +2 -1
- package/dist/derivation/generators/build.js +6 -6
- package/dist/derivation/generators/build.ts +1 -1
- package/dist/derivation/generators/check.js +1 -1
- package/dist/derivation/generators/determinism.js +1 -1
- package/dist/derivation/generators/release.js +60 -47
- package/dist/derivation/generators/release.ts +66 -43
- package/dist/derivation/release.d.ts +7 -3
- package/dist/derivation/release.js +14 -1
- package/dist/derivation/release.ts +22 -2
- package/dist/integrations/attach.d.ts +4 -0
- package/dist/integrations/attach.js +37 -56
- package/dist/integrations/attach.ts +54 -60
- package/dist/integrations/cli.d.ts +37 -0
- package/dist/integrations/cli.js +440 -0
- package/dist/integrations/cli.ts +543 -0
- package/dist/{core/files.d.ts → integrations/disk.d.ts} +16 -24
- package/dist/integrations/disk.js +435 -0
- package/dist/integrations/disk.ts +465 -0
- package/dist/integrations/generators/read.js +6 -6
- package/dist/integrations/generators/read.ts +4 -4
- package/dist/integrations/generators/vault.js +10 -11
- package/dist/integrations/generators/vault.ts +4 -5
- package/dist/{operations/http.d.ts → integrations/https.d.ts} +10 -6
- package/dist/integrations/https.js +170 -0
- package/dist/integrations/https.ts +216 -0
- package/dist/integrations/pglite.d.ts +26 -0
- package/dist/integrations/pglite.js +143 -0
- package/dist/integrations/pglite.ts +206 -0
- package/dist/integrations/secret.d.ts +8 -2
- package/dist/integrations/secret.js +3 -5
- package/dist/integrations/secret.ts +10 -6
- package/dist/integrations/target.d.ts +155 -14
- package/dist/integrations/target.js +171 -50
- package/dist/integrations/target.ts +377 -61
- package/dist/integrations/vault.d.ts +1 -0
- package/dist/integrations/vault.js +20 -5
- package/dist/integrations/vault.ts +17 -5
- package/dist/integrity/attach.js +8 -77
- package/dist/integrity/attach.ts +7 -76
- package/dist/integrity/check-threads.js +5 -5
- package/dist/integrity/check-threads.ts +2 -2
- package/dist/integrity/constraint.d.ts +0 -1
- package/dist/integrity/constraint.js +267 -366
- package/dist/integrity/constraint.ts +267 -375
- package/dist/integrity/generators/compiler.js +14 -17
- package/dist/integrity/generators/compiler.ts +10 -15
- package/dist/integrity/generators/gate.js +15 -15
- package/dist/integrity/generators/gate.ts +10 -10
- package/dist/integrity/generators/issues.js +7 -7
- package/dist/integrity/generators/publish.js +39 -57
- package/dist/integrity/generators/publish.ts +44 -55
- package/dist/integrity/generators/trial.d.ts +3 -3
- package/dist/integrity/generators/trial.js +133 -165
- package/dist/integrity/generators/trial.ts +145 -169
- package/dist/integrity/lint.js +9 -13
- package/dist/integrity/lint.ts +7 -10
- package/dist/integrity/lsp/bin.js +5 -4
- package/dist/integrity/lsp/bin.ts +3 -1
- package/dist/integrity/lsp/diagnostics.js +3 -3
- package/dist/integrity/lsp/diagnostics.ts +1 -1
- package/dist/integrity/lsp/lint.js +19 -30
- package/dist/integrity/lsp/lint.ts +16 -32
- package/dist/integrity/lsp/server.js +3 -3
- package/dist/integrity/slopnator.d.ts +3 -13
- package/dist/integrity/slopnator.js +59 -38
- package/dist/integrity/slopnator.ts +54 -38
- package/dist/integrity/slopnators/sl_broken_lineage.js +2 -2
- package/dist/integrity/slopnators/sl_declared_elsewhere.js +1 -1
- package/dist/integrity/slopnators/sl_derived_drift.js +4 -4
- package/dist/integrity/slopnators/sl_derived_drift.ts +1 -1
- package/dist/integrity/slopnators/sl_door_in_a_node.js +220 -0
- package/dist/integrity/slopnators/sl_door_in_a_node.ts +250 -0
- package/dist/integrity/slopnators/sl_inert_island.js +10 -8
- package/dist/integrity/slopnators/sl_inert_island.ts +8 -6
- package/dist/integrity/slopnators/sl_missing_row.js +6 -51
- package/dist/integrity/slopnators/sl_missing_row.ts +4 -50
- package/dist/integrity/slopnators/sl_no_barrel.js +1 -1
- package/dist/integrity/slopnators/sl_no_child_process.js +36 -18
- package/dist/integrity/slopnators/sl_no_child_process.ts +44 -18
- package/dist/integrity/slopnators/sl_no_dispatch_bypass.js +80 -149
- package/dist/integrity/slopnators/sl_no_dispatch_bypass.ts +95 -147
- package/dist/integrity/slopnators/sl_no_import_cycle.js +15 -4
- package/dist/integrity/slopnators/sl_no_import_cycle.ts +20 -4
- package/dist/integrity/slopnators/sl_no_such_command.js +2 -2
- package/dist/integrity/slopnators/sl_no_such_command.ts +1 -1
- package/dist/integrity/slopnators/sl_outside_an_operation.js +20 -0
- package/dist/integrity/slopnators/sl_outside_an_operation.ts +25 -0
- package/dist/integrity/slopnators/sl_screen_holds_only_declared.d.ts +2 -0
- package/dist/integrity/slopnators/sl_screen_holds_only_declared.js +61 -0
- package/dist/integrity/slopnators/sl_screen_holds_only_declared.ts +70 -0
- package/dist/integrity/slopnators/sl_secret_literal.js +1 -33
- package/dist/integrity/slopnators/sl_secret_literal.ts +1 -33
- package/dist/integrity/slopnators/sl_stale_path.js +5 -22
- package/dist/integrity/slopnators/sl_stale_path.ts +4 -20
- package/dist/integrity/slopnators/sl_twice_meant.js +1 -1
- package/dist/integrity/slopnators/sl_twice_parented.js +29 -5
- package/dist/integrity/slopnators/sl_twice_parented.ts +28 -4
- package/dist/integrity/slopnators/sl_undeclared_crossing.d.ts +4 -1
- package/dist/integrity/slopnators/sl_undeclared_crossing.js +426 -62
- package/dist/integrity/slopnators/sl_undeclared_crossing.ts +454 -70
- package/dist/integrity/slopnators/sl_undeclared_destination.js +59 -25
- package/dist/integrity/slopnators/sl_undeclared_destination.ts +69 -21
- package/dist/integrity/slopnators/sl_undeclared_list.d.ts +2 -0
- package/dist/integrity/slopnators/sl_undeclared_list.js +363 -0
- package/dist/integrity/slopnators/sl_undeclared_list.ts +358 -0
- package/dist/integrity/slopnators/sl_undeclared_node.js +1 -11
- package/dist/integrity/slopnators/sl_undeclared_node.ts +0 -10
- package/dist/integrity/slopnators/sl_undeclared_operation.js +111 -29
- package/dist/integrity/slopnators/sl_undeclared_operation.ts +134 -26
- package/dist/integrity/slopnators/sl_undeclared_variant.js +2 -2
- package/dist/integrity/slopnators/sl_undeclared_webhook.d.ts +2 -0
- package/dist/integrity/slopnators/sl_undeclared_webhook.js +90 -0
- package/dist/integrity/slopnators/sl_undeclared_webhook.ts +108 -0
- package/dist/integrity/slopnators/sl_underived_route.d.ts +2 -0
- package/dist/integrity/slopnators/sl_underived_route.js +61 -0
- package/dist/integrity/slopnators/sl_underived_route.ts +72 -0
- package/dist/integrity/slopnators/sl_ungoverned_island.js +3 -3
- package/dist/integrity/slopnators/sl_ungoverned_island.ts +1 -1
- package/dist/integrity/slopnators/sl_unlisted_program.d.ts +2 -0
- package/dist/integrity/slopnators/sl_unlisted_program.js +39 -0
- package/dist/integrity/slopnators/sl_unlisted_program.ts +40 -0
- package/dist/integrity/slopnators/sl_unnamed_island.js +1 -1
- package/dist/integrity/slopnators/sl_unpaired_member.js +3 -3
- package/dist/integrity/slopnators/sl_unpaired_member.ts +1 -1
- package/dist/integrity/slopnators/sl_unpaired_slopnator.js +4 -4
- package/dist/integrity/slopnators/sl_unpaired_slopnator.ts +1 -1
- package/dist/integrity/slopnators/sl_unprefixed_member.js +5 -31
- package/dist/integrity/slopnators/sl_unprefixed_member.ts +2 -28
- package/dist/integrity/slopnators/sl_unthreaded.js +11 -7
- package/dist/integrity/slopnators/sl_unthreaded.ts +6 -7
- package/dist/integrity/slopnators/sl_untranslated_key.js +2 -25
- package/dist/integrity/slopnators/sl_untranslated_key.ts +1 -25
- package/dist/integrity/slopnators/sl_unvaulted_secret.d.ts +2 -0
- package/dist/integrity/slopnators/sl_unvaulted_secret.js +107 -0
- package/dist/integrity/slopnators/sl_unvaulted_secret.ts +132 -0
- package/dist/integrity/slopnators/sl_unversioned.js +6 -4
- package/dist/integrity/slopnators/sl_unversioned.ts +5 -3
- package/dist/integrity/sweep.d.ts +1 -0
- package/dist/integrity/sweep.js +105 -42
- package/dist/integrity/sweep.ts +115 -42
- package/dist/knowledge/attach.js +4 -3
- package/dist/knowledge/attach.ts +3 -2
- package/dist/knowledge/generators/docsgen.js +8 -6
- package/dist/knowledge/generators/docsgen.ts +4 -2
- package/dist/knowledge/generators/glossary.js +4 -4
- package/dist/knowledge/generators/glossary.ts +1 -1
- package/dist/operations/access.d.ts +23 -0
- package/dist/operations/access.js +28 -1
- package/dist/operations/access.ts +43 -0
- package/dist/operations/attach.js +33 -113
- package/dist/operations/attach.ts +51 -117
- package/dist/operations/capabilities.d.ts +14 -5
- package/dist/operations/capabilities.js +13 -4
- package/dist/operations/capabilities.ts +27 -8
- package/dist/operations/dispatch.d.ts +8 -2
- package/dist/operations/dispatch.js +128 -185
- package/dist/operations/dispatch.ts +138 -191
- package/dist/operations/error-results.d.ts +1 -1
- package/dist/operations/error-results.js +2 -2
- package/dist/operations/error-results.ts +2 -2
- package/dist/operations/generators/capability.d.ts +11 -1
- package/dist/operations/generators/capability.js +481 -224
- package/dist/operations/generators/capability.ts +562 -233
- package/dist/operations/generators/compile.js +66 -39
- package/dist/operations/generators/compile.ts +78 -39
- package/dist/operations/generators/permits.js +11 -12
- package/dist/operations/generators/permits.ts +3 -4
- package/dist/operations/generators/seed.d.ts +1 -0
- package/dist/operations/generators/seed.js +19 -17
- package/dist/operations/generators/seed.ts +22 -14
- package/dist/operations/generators/trial.d.ts +6 -8
- package/dist/operations/generators/trial.js +200 -70
- package/dist/operations/generators/trial.ts +230 -93
- package/dist/operations/nodes.d.ts +15 -16
- package/dist/operations/nodes.ts +16 -17
- package/dist/operations/operations.d.ts +40 -4
- package/dist/operations/operations.js +1 -0
- package/dist/operations/operations.ts +61 -4
- package/dist/operations/result.d.ts +2 -2
- package/dist/operations/result.ts +2 -2
- package/package.json +1 -4
- package/dist/core/answers.d.ts +0 -171
- package/dist/core/answers.js +0 -789
- package/dist/core/answers.ts +0 -999
- package/dist/core/client.d.ts +0 -63
- package/dist/core/client.js +0 -249
- package/dist/core/client.ts +0 -289
- package/dist/core/files.js +0 -171
- package/dist/core/files.ts +0 -222
- package/dist/integrations/module.d.ts +0 -6
- package/dist/integrations/module.js +0 -153
- package/dist/integrations/module.ts +0 -191
- package/dist/integrity/slopnators/sl_unkept_rows.js +0 -104
- package/dist/integrity/slopnators/sl_unkept_rows.ts +0 -111
- package/dist/integrity/slopnators/sl_unseamed_reach.js +0 -73
- package/dist/integrity/slopnators/sl_unseamed_reach.ts +0 -79
- package/dist/operations/cost.d.ts +0 -14
- package/dist/operations/cost.js +0 -37
- package/dist/operations/cost.ts +0 -58
- package/dist/operations/errors/errors.d.ts +0 -52
- package/dist/operations/http.js +0 -124
- package/dist/operations/http.ts +0 -169
- package/dist/operations/memory.d.ts +0 -104
- package/dist/operations/memory.js +0 -365
- package/dist/operations/memory.ts +0 -470
- package/dist/operations/metering.d.ts +0 -55
- package/dist/operations/metering.js +0 -247
- package/dist/operations/metering.ts +0 -328
- package/dist/operations/queue-policy.d.ts +0 -3
- package/dist/operations/queue-policy.js +0 -8
- package/dist/operations/queue-policy.ts +0 -10
- package/dist/operations/seams.d.ts +0 -239
- package/dist/operations/seams.js +0 -45
- package/dist/operations/seams.ts +0 -364
- package/dist/operations/store.d.ts +0 -14
- package/dist/operations/store.js +0 -1
- package/dist/operations/store.ts +0 -29
- /package/dist/{operations → core}/errors/classes.d.ts +0 -0
- /package/dist/{operations → core}/errors/classes.js +0 -0
- /package/dist/{operations → core}/errors/classes.ts +0 -0
- /package/dist/integrity/slopnators/{sl_unkept_rows.d.ts → sl_door_in_a_node.d.ts} +0 -0
- /package/dist/integrity/slopnators/{sl_unseamed_reach.d.ts → sl_outside_an_operation.d.ts} +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { existsSync, readFileSync, readdirSync } from
|
|
1
|
+
import { existsSync, readFileSync, readdirSync } from '../../integrations/disk.js';
|
|
2
2
|
import { resolve } from 'node:path';
|
|
3
|
-
import { foldersGoverned, here, islandsDeclared, rowsIn } from
|
|
4
|
-
import { findTree } from
|
|
3
|
+
import { foldersGoverned, here, islandsDeclared, rowsIn } from './sl_unthreaded.js';
|
|
4
|
+
import { findTree } from '../../core/tree.js';
|
|
5
5
|
const ROOT = findTree().at;
|
|
6
6
|
const TREE = `${findTree().name}/`;
|
|
7
7
|
const seeding = (one) => {
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { existsSync, readFileSync } from
|
|
1
|
+
import { existsSync, readFileSync } from '../../integrations/disk.js';
|
|
2
2
|
import { join, resolve } from 'node:path';
|
|
3
|
-
import { SEEDED, SHIPPED, slopnatorName } from
|
|
4
|
-
import { here } from
|
|
5
|
-
import { findTree } from
|
|
3
|
+
import { SEEDED, SHIPPED, slopnatorName } from '../slopnator.js';
|
|
4
|
+
import { here } from './sl_unthreaded.js';
|
|
5
|
+
import { findTree } from '../../core/tree.js';
|
|
6
6
|
const ROOT = findTree().at;
|
|
7
7
|
const TREE = `${findTree().name}/`;
|
|
8
8
|
const ID = /^ {4}id:\s*'([^']+)'/gm;
|
|
@@ -1,38 +1,12 @@
|
|
|
1
|
-
import { inCode, listBounds, matched } from
|
|
2
|
-
import { PREFIXES } from
|
|
3
|
-
import { here, parses, unreadable } from
|
|
1
|
+
import { inCode, listBounds, matched } from '../../core/rows.js';
|
|
2
|
+
import { PREFIXES } from '../../core/thread.js';
|
|
3
|
+
import { here, parses, unreadable } from './sl_unthreaded.js';
|
|
4
4
|
const MEMBERS = 'MEMBERS';
|
|
5
|
-
/*
|
|
6
|
-
* Which prefixes a tree file's member list may hold.
|
|
7
|
-
*
|
|
8
|
-
* The file is the key because the list is named the same in both: `MEMBERS` in the operations tree
|
|
9
|
-
* holds what an app can be asked to do, and `MEMBERS` in the nodes tree holds the spans an operation
|
|
10
|
-
* is built from. Nothing in TypeScript separates them — both are arrays of rows carrying a string id
|
|
11
|
-
* — so an operation declared among the nodes, or a node among the operations, typechecks, attaches,
|
|
12
|
-
* seeds a body and reads as agreed by everything downstream.
|
|
13
|
-
*
|
|
14
|
-
* What an operation may wear is not written here. `@thread/core/thread` pairs each word an
|
|
15
|
-
* operation can be with the prefix its id takes, and `thread create` puts that prefix on — so the
|
|
16
|
-
* command that makes them and the law that refuses them read one list. Written out again here,
|
|
17
|
-
* a kind added over there would be a kind this refuses.
|
|
18
|
-
*/
|
|
19
5
|
const TAKES = {
|
|
20
6
|
'operations.ts': Object.values(PREFIXES),
|
|
21
|
-
'nodes.ts': ['nd_'
|
|
7
|
+
'nodes.ts': ['nd_'],
|
|
22
8
|
};
|
|
23
9
|
const ID = /\bid:\s*'((?:[^'\\]|\\.)*)'/;
|
|
24
|
-
/*
|
|
25
|
-
* The id of every row sitting directly in the list, and no deeper.
|
|
26
|
-
*
|
|
27
|
-
* Depth is the whole of it: a member row states its own id, and the `seeds` and `derives` rows under
|
|
28
|
-
* it state theirs, which are neither operations nor nodes — `wf_send_invoice_body` is a body, not
|
|
29
|
-
* something an app can be asked to do. Reading every id in the list would refuse those children for
|
|
30
|
-
* lacking a prefix they were never meant to wear.
|
|
31
|
-
*
|
|
32
|
-
* The braces are read off `inCode`, not off the raw text. Counting characters directly desynced on a
|
|
33
|
-
* `describes:` holding a brace, and this package already ships the mask and the matcher for exactly
|
|
34
|
-
* that — a second, weaker walker beside them is the drift they exist to prevent.
|
|
35
|
-
*/
|
|
36
10
|
function directly(text, open, close) {
|
|
37
11
|
const code = inCode(text);
|
|
38
12
|
const found = [];
|
|
@@ -107,7 +81,7 @@ export const slopnator = {
|
|
|
107
81
|
files: [
|
|
108
82
|
{
|
|
109
83
|
at: '_threads/operations.ts',
|
|
110
|
-
source: "import type { Member, Threaded } from '../../core/thread.ts'\n\nexport const OPERATIONS: Threaded = {\n id: 'operations',\n at: '_threads/operations.ts',\n describes: 'what an app can be asked to do',\n version: 1,\n}\n\nexport const MEMBERS: readonly Member[] = [\n {\n id: '
|
|
84
|
+
source: "import type { Member, Threaded } from '../../core/thread.ts'\n\nexport const OPERATIONS: Threaded = {\n id: 'operations',\n at: '_threads/operations.ts',\n describes: 'what an app can be asked to do',\n version: 1,\n}\n\nexport const MEMBERS: readonly Member[] = [\n {\n id: 'wf_prestack_client',\n at: '_threads/operations.ts',\n describes: 'sends what you typed to the agent',\n version: 1,\n seeds: [\n {\n id: 'wf_prestack_client_body',\n at: 'operations/wf_prestack_client.ts',\n describes: 'the operation itself',\n },\n ],\n },\n]\n",
|
|
111
85
|
},
|
|
112
86
|
],
|
|
113
87
|
at: '_threads/operations.ts',
|
|
@@ -6,39 +6,13 @@ import { here, parses, unreadable } from './sl_unthreaded.ts'
|
|
|
6
6
|
|
|
7
7
|
const MEMBERS = 'MEMBERS'
|
|
8
8
|
|
|
9
|
-
/*
|
|
10
|
-
* Which prefixes a tree file's member list may hold.
|
|
11
|
-
*
|
|
12
|
-
* The file is the key because the list is named the same in both: `MEMBERS` in the operations tree
|
|
13
|
-
* holds what an app can be asked to do, and `MEMBERS` in the nodes tree holds the spans an operation
|
|
14
|
-
* is built from. Nothing in TypeScript separates them — both are arrays of rows carrying a string id
|
|
15
|
-
* — so an operation declared among the nodes, or a node among the operations, typechecks, attaches,
|
|
16
|
-
* seeds a body and reads as agreed by everything downstream.
|
|
17
|
-
*
|
|
18
|
-
* What an operation may wear is not written here. `@thread/core/thread` pairs each word an
|
|
19
|
-
* operation can be with the prefix its id takes, and `thread create` puts that prefix on — so the
|
|
20
|
-
* command that makes them and the law that refuses them read one list. Written out again here,
|
|
21
|
-
* a kind added over there would be a kind this refuses.
|
|
22
|
-
*/
|
|
23
9
|
const TAKES: Readonly<Record<string, readonly string[]>> = {
|
|
24
10
|
'operations.ts': Object.values(PREFIXES),
|
|
25
|
-
'nodes.ts': ['nd_'
|
|
11
|
+
'nodes.ts': ['nd_'],
|
|
26
12
|
}
|
|
27
13
|
|
|
28
14
|
const ID = /\bid:\s*'((?:[^'\\]|\\.)*)'/
|
|
29
15
|
|
|
30
|
-
/*
|
|
31
|
-
* The id of every row sitting directly in the list, and no deeper.
|
|
32
|
-
*
|
|
33
|
-
* Depth is the whole of it: a member row states its own id, and the `seeds` and `derives` rows under
|
|
34
|
-
* it state theirs, which are neither operations nor nodes — `wf_send_invoice_body` is a body, not
|
|
35
|
-
* something an app can be asked to do. Reading every id in the list would refuse those children for
|
|
36
|
-
* lacking a prefix they were never meant to wear.
|
|
37
|
-
*
|
|
38
|
-
* The braces are read off `inCode`, not off the raw text. Counting characters directly desynced on a
|
|
39
|
-
* `describes:` holding a brace, and this package already ships the mask and the matcher for exactly
|
|
40
|
-
* that — a second, weaker walker beside them is the drift they exist to prevent.
|
|
41
|
-
*/
|
|
42
16
|
function directly(text: string, open: number, close: number): readonly string[] {
|
|
43
17
|
const code = inCode(text)
|
|
44
18
|
const found: string[] = []
|
|
@@ -116,7 +90,7 @@ export const slopnator: Slopnator = {
|
|
|
116
90
|
{
|
|
117
91
|
at: '_threads/operations.ts',
|
|
118
92
|
source:
|
|
119
|
-
"import type { Member, Threaded } from '../../core/thread.ts'\n\nexport const OPERATIONS: Threaded = {\n id: 'operations',\n at: '_threads/operations.ts',\n describes: 'what an app can be asked to do',\n version: 1,\n}\n\nexport const MEMBERS: readonly Member[] = [\n {\n id: '
|
|
93
|
+
"import type { Member, Threaded } from '../../core/thread.ts'\n\nexport const OPERATIONS: Threaded = {\n id: 'operations',\n at: '_threads/operations.ts',\n describes: 'what an app can be asked to do',\n version: 1,\n}\n\nexport const MEMBERS: readonly Member[] = [\n {\n id: 'wf_prestack_client',\n at: '_threads/operations.ts',\n describes: 'sends what you typed to the agent',\n version: 1,\n seeds: [\n {\n id: 'wf_prestack_client_body',\n at: 'operations/wf_prestack_client.ts',\n describes: 'the operation itself',\n },\n ],\n },\n]\n",
|
|
120
94
|
},
|
|
121
95
|
],
|
|
122
96
|
at: '_threads/operations.ts',
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { parser } from 'typescript-eslint';
|
|
2
|
-
import { LISTS as LINEAGE, descend, forget as forgetDescent, read, reached as fromThread, threading } from
|
|
3
|
-
import { findTree } from
|
|
2
|
+
import { LISTS as LINEAGE, descend, forget as forgetDescent, read, reached as fromThread, threading } from '../../core/descend.js';
|
|
3
|
+
import { findTree } from '../../core/tree.js';
|
|
4
4
|
const TREE_AT = findTree();
|
|
5
5
|
const ROOT = `${TREE_AT.at.split('\\').join('/')}/`;
|
|
6
6
|
const TREE = TREE_AT.name;
|
|
@@ -11,7 +11,6 @@ let threaders;
|
|
|
11
11
|
let tree;
|
|
12
12
|
const parsed = new Map();
|
|
13
13
|
const broke = new Map();
|
|
14
|
-
const SAID = new Set(['at', 'id', 'describes']);
|
|
15
14
|
const keyOf = (property) => {
|
|
16
15
|
if (property.computed === true)
|
|
17
16
|
return undefined;
|
|
@@ -38,13 +37,13 @@ function rows(node, list, found, hoisted) {
|
|
|
38
37
|
const element = one?.type === 'Identifier' && one.name !== undefined ? hoisted.get(one.name) : one;
|
|
39
38
|
if (element === null || element === undefined || element.type !== 'ObjectExpression')
|
|
40
39
|
continue;
|
|
40
|
+
const strings = {};
|
|
41
41
|
const said = {};
|
|
42
42
|
for (const property of element.properties ?? []) {
|
|
43
43
|
const key = keyOf(property);
|
|
44
44
|
const held = property.value;
|
|
45
|
-
if (key !== undefined &&
|
|
46
|
-
|
|
47
|
-
}
|
|
45
|
+
if (key !== undefined && held?.type === 'Literal' && typeof held.value === 'string')
|
|
46
|
+
strings[key] = held.value;
|
|
48
47
|
if ((key === 'governs' || key === 'wears') && held?.type === 'ArrayExpression') {
|
|
49
48
|
said[key] = (held.elements ?? [])
|
|
50
49
|
.map((one) => (one?.type === 'Literal' && typeof one.value === 'string' ? one.value : undefined))
|
|
@@ -53,6 +52,12 @@ function rows(node, list, found, hoisted) {
|
|
|
53
52
|
if (key !== undefined && LISTS.has(key) && held?.type === 'ArrayExpression')
|
|
54
53
|
rows(held, key, found, hoisted);
|
|
55
54
|
}
|
|
55
|
+
if (strings['at'] !== undefined)
|
|
56
|
+
said.at = strings['at'];
|
|
57
|
+
if (strings['id'] !== undefined)
|
|
58
|
+
said.id = strings['id'];
|
|
59
|
+
if (strings['describes'] !== undefined)
|
|
60
|
+
said.describes = strings['describes'];
|
|
56
61
|
if (said.at !== undefined || said.id !== undefined)
|
|
57
62
|
found.push({ list, ...said });
|
|
58
63
|
}
|
|
@@ -335,7 +340,6 @@ export const slopnator = {
|
|
|
335
340
|
},
|
|
336
341
|
],
|
|
337
342
|
right: [
|
|
338
|
-
"export const HELD: Threaded = {\n declares: [\n {\n at: 'threads/probe.tsx',\n },\n ],\n}",
|
|
339
343
|
{
|
|
340
344
|
files: [
|
|
341
345
|
{ at: 'thread/core/thread.ts', source: "export interface Threaded {\n readonly id?: string\n readonly at?: string\n readonly describes?: string\n readonly declares?: readonly Threaded[]\n readonly derives?: readonly Threaded[]\n readonly seeds?: readonly Threaded[]\n}\n" },
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { readFileSync } from '../../
|
|
1
|
+
import { readFileSync } from '../../integrations/disk.ts'
|
|
2
2
|
import { resolve } from 'node:path'
|
|
3
3
|
|
|
4
4
|
import { parser } from 'typescript-eslint'
|
|
@@ -35,8 +35,6 @@ export interface Meaning {
|
|
|
35
35
|
readonly describes: string
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
-
const SAID = new Set(['at', 'id', 'describes'])
|
|
39
|
-
|
|
40
38
|
interface Held {
|
|
41
39
|
readonly type?: string
|
|
42
40
|
readonly kind?: string
|
|
@@ -83,13 +81,12 @@ function rows(node: Held, list: Reach['list'], found: Reach[], hoisted: Readonly
|
|
|
83
81
|
for (const one of node.elements ?? []) {
|
|
84
82
|
const element = one?.type === 'Identifier' && one.name !== undefined ? hoisted.get(one.name) : one
|
|
85
83
|
if (element === null || element === undefined || element.type !== 'ObjectExpression') continue
|
|
84
|
+
const strings: Record<string, string> = {}
|
|
86
85
|
const said: { at?: string; id?: string; describes?: string; governs?: readonly string[]; wears?: readonly string[] } = {}
|
|
87
86
|
for (const property of element.properties ?? []) {
|
|
88
87
|
const key = keyOf(property)
|
|
89
88
|
const held = property.value as Held | undefined
|
|
90
|
-
if (key !== undefined &&
|
|
91
|
-
said[key as 'at' | 'id' | 'describes'] = held.value
|
|
92
|
-
}
|
|
89
|
+
if (key !== undefined && held?.type === 'Literal' && typeof held.value === 'string') strings[key] = held.value
|
|
93
90
|
if ((key === 'governs' || key === 'wears') && held?.type === 'ArrayExpression') {
|
|
94
91
|
said[key] = (held.elements ?? [])
|
|
95
92
|
.map((one) => (one?.type === 'Literal' && typeof one.value === 'string' ? one.value : undefined))
|
|
@@ -97,6 +94,9 @@ function rows(node: Held, list: Reach['list'], found: Reach[], hoisted: Readonly
|
|
|
97
94
|
}
|
|
98
95
|
if (key !== undefined && LISTS.has(key) && held?.type === 'ArrayExpression') rows(held, key as Reach['list'], found, hoisted)
|
|
99
96
|
}
|
|
97
|
+
if (strings['at'] !== undefined) said.at = strings['at']
|
|
98
|
+
if (strings['id'] !== undefined) said.id = strings['id']
|
|
99
|
+
if (strings['describes'] !== undefined) said.describes = strings['describes']
|
|
100
100
|
if (said.at !== undefined || said.id !== undefined) found.push({ list, ...said })
|
|
101
101
|
}
|
|
102
102
|
}
|
|
@@ -402,7 +402,6 @@ export const slopnator: Slopnator = {
|
|
|
402
402
|
},
|
|
403
403
|
],
|
|
404
404
|
right: [
|
|
405
|
-
"export const HELD: Threaded = {\n declares: [\n {\n at: 'threads/probe.tsx',\n },\n ],\n}",
|
|
406
405
|
{
|
|
407
406
|
files: [
|
|
408
407
|
{ at: 'thread/core/thread.ts', source: "export interface Threaded {\n readonly id?: string\n readonly at?: string\n readonly describes?: string\n readonly declares?: readonly Threaded[]\n readonly derives?: readonly Threaded[]\n readonly seeds?: readonly Threaded[]\n}\n" },
|
|
@@ -1,31 +1,8 @@
|
|
|
1
|
-
import { existsSync, readFileSync, readdirSync } from
|
|
1
|
+
import { existsSync, readFileSync, readdirSync } from '../../integrations/disk.js';
|
|
2
2
|
import { join } from 'node:path';
|
|
3
|
-
import { named as packageOf } from
|
|
4
|
-
/*
|
|
5
|
-
* A KEY THE INTERFACE NAMES AND A LANGUAGE DOES NOT ANSWER.
|
|
6
|
-
*
|
|
7
|
-
* "i18n keys must be translated OR ITS AN ERROR ... a new constraint.ts row and slopnator that
|
|
8
|
-
* checks i18n entries against the keys in the UI and if there's anything missing in whatever
|
|
9
|
-
* file, it's a build error, compile error, gate error, everything. Cannot be allowed."
|
|
10
|
-
* — founder, 2026-08-29
|
|
11
|
-
*
|
|
12
|
-
* The generator already writes a line into every language file for every key it finds, so a key is
|
|
13
|
-
* never structurally absent — what it cannot do is invent the sentence. This is the half that
|
|
14
|
-
* refuses: a line holding nothing is a key nobody has answered, and an app that ships one shows a
|
|
15
|
-
* person an empty button.
|
|
16
|
-
*
|
|
17
|
-
* Deliberately independent of the generator rather than calling it. A check that runs the thing it
|
|
18
|
-
* is checking passes whenever that thing passes, which is no check at all — this reads the files
|
|
19
|
-
* that are actually on disk and compares them to the markup that is actually there.
|
|
20
|
-
*/
|
|
3
|
+
import { named as packageOf } from '../../core/scope.js';
|
|
21
4
|
const SKIP = new Set(['node_modules', '.next', '.git', 'dist', '_generated']);
|
|
22
5
|
const CODE = /\.(tsx?|jsx?)$/;
|
|
23
|
-
/*
|
|
24
|
-
* Which props carry a key, read off the installed package's own declarations.
|
|
25
|
-
*
|
|
26
|
-
* A list written here would go stale the first time an element gained a prop — silently, by finding
|
|
27
|
-
* fewer keys than there are, which is the failure this whole law exists to prevent.
|
|
28
|
-
*/
|
|
29
6
|
const TYPED = /readonly\s+([A-Za-z][A-Za-z0-9]*)\??\s*:\s*MessageKey\b/g;
|
|
30
7
|
function walk(at, found = []) {
|
|
31
8
|
let entries;
|
|
@@ -1,37 +1,13 @@
|
|
|
1
|
-
import { existsSync, readFileSync, readdirSync } from '../../
|
|
1
|
+
import { existsSync, readFileSync, readdirSync } from '../../integrations/disk.ts'
|
|
2
2
|
import { join } from 'node:path'
|
|
3
3
|
|
|
4
4
|
import type { Slopnator } from '../slopnator.ts'
|
|
5
5
|
import { named as packageOf } from '../../core/scope.ts'
|
|
6
6
|
|
|
7
|
-
/*
|
|
8
|
-
* A KEY THE INTERFACE NAMES AND A LANGUAGE DOES NOT ANSWER.
|
|
9
|
-
*
|
|
10
|
-
* "i18n keys must be translated OR ITS AN ERROR ... a new constraint.ts row and slopnator that
|
|
11
|
-
* checks i18n entries against the keys in the UI and if there's anything missing in whatever
|
|
12
|
-
* file, it's a build error, compile error, gate error, everything. Cannot be allowed."
|
|
13
|
-
* — founder, 2026-08-29
|
|
14
|
-
*
|
|
15
|
-
* The generator already writes a line into every language file for every key it finds, so a key is
|
|
16
|
-
* never structurally absent — what it cannot do is invent the sentence. This is the half that
|
|
17
|
-
* refuses: a line holding nothing is a key nobody has answered, and an app that ships one shows a
|
|
18
|
-
* person an empty button.
|
|
19
|
-
*
|
|
20
|
-
* Deliberately independent of the generator rather than calling it. A check that runs the thing it
|
|
21
|
-
* is checking passes whenever that thing passes, which is no check at all — this reads the files
|
|
22
|
-
* that are actually on disk and compares them to the markup that is actually there.
|
|
23
|
-
*/
|
|
24
|
-
|
|
25
7
|
const SKIP = new Set(['node_modules', '.next', '.git', 'dist', '_generated'])
|
|
26
8
|
|
|
27
9
|
const CODE = /\.(tsx?|jsx?)$/
|
|
28
10
|
|
|
29
|
-
/*
|
|
30
|
-
* Which props carry a key, read off the installed package's own declarations.
|
|
31
|
-
*
|
|
32
|
-
* A list written here would go stale the first time an element gained a prop — silently, by finding
|
|
33
|
-
* fewer keys than there are, which is the failure this whole law exists to prevent.
|
|
34
|
-
*/
|
|
35
11
|
const TYPED = /readonly\s+([A-Za-z][A-Za-z0-9]*)\??\s*:\s*MessageKey\b/g
|
|
36
12
|
|
|
37
13
|
function walk(at: string, found: string[] = []): readonly string[] {
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { descend, read, reached } from '../../core/descend.js';
|
|
2
|
+
import { rowsIn } from './sl_unthreaded.js';
|
|
3
|
+
const SECRETS = 'secrets';
|
|
4
|
+
function wears() {
|
|
5
|
+
const found = new Set();
|
|
6
|
+
descend();
|
|
7
|
+
for (const at of reached()) {
|
|
8
|
+
const text = read(at);
|
|
9
|
+
if (text === undefined)
|
|
10
|
+
continue;
|
|
11
|
+
let waiting = [];
|
|
12
|
+
for (const one of rowsIn(text)) {
|
|
13
|
+
if (one.id === undefined)
|
|
14
|
+
continue;
|
|
15
|
+
if (one.list === 'declares') {
|
|
16
|
+
waiting.push(one.id);
|
|
17
|
+
continue;
|
|
18
|
+
}
|
|
19
|
+
if (one.list !== undefined)
|
|
20
|
+
continue;
|
|
21
|
+
if (one.id === SECRETS) {
|
|
22
|
+
for (const id of waiting) {
|
|
23
|
+
const cut = id.indexOf('_');
|
|
24
|
+
if (cut > 0)
|
|
25
|
+
found.add(id.slice(0, cut + 1));
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
waiting = [];
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
return [...found];
|
|
32
|
+
}
|
|
33
|
+
const HOLDS = 'process';
|
|
34
|
+
const ENV = 'env';
|
|
35
|
+
const isEnv = (one) => one?.type === 'MemberExpression' &&
|
|
36
|
+
one.object?.type === 'Identifier' &&
|
|
37
|
+
one.object.name === HOLDS &&
|
|
38
|
+
one.property?.type === 'Identifier' &&
|
|
39
|
+
one.property.name === ENV;
|
|
40
|
+
function stated(node, ancestors) {
|
|
41
|
+
if (node === undefined)
|
|
42
|
+
return undefined;
|
|
43
|
+
if (node.type === 'Literal' && typeof node.value === 'string')
|
|
44
|
+
return node.value;
|
|
45
|
+
if (node.type !== 'Identifier' || node.name === undefined)
|
|
46
|
+
return undefined;
|
|
47
|
+
for (const one of ancestors) {
|
|
48
|
+
const body = one.body;
|
|
49
|
+
for (const each of Array.isArray(body) ? body : []) {
|
|
50
|
+
const line = each;
|
|
51
|
+
const held = line.type === 'ExportNamedDeclaration' ? line.declaration : line;
|
|
52
|
+
if (held?.type !== 'VariableDeclaration')
|
|
53
|
+
continue;
|
|
54
|
+
for (const said of held.declarations ?? []) {
|
|
55
|
+
if (said.id?.type !== 'Identifier' || said.id.name !== node.name)
|
|
56
|
+
continue;
|
|
57
|
+
return said.init?.type === 'Literal' && typeof said.init.value === 'string' ? said.init.value : undefined;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return undefined;
|
|
62
|
+
}
|
|
63
|
+
export const slopnator = {
|
|
64
|
+
on: ['MemberExpression'],
|
|
65
|
+
holds: (node, at) => {
|
|
66
|
+
const held = node;
|
|
67
|
+
if (!isEnv(held.object))
|
|
68
|
+
return false;
|
|
69
|
+
const up = at.ancestors();
|
|
70
|
+
const parent = up[up.length - 1];
|
|
71
|
+
if (parent?.type === 'AssignmentExpression' && parent.left === held)
|
|
72
|
+
return false;
|
|
73
|
+
const name = held.computed === true ? stated(held.property, up) : held.property?.name;
|
|
74
|
+
if (name === undefined) {
|
|
75
|
+
return ('this takes a value out of the environment under a name nobody reading the file can see, so it can name ' +
|
|
76
|
+
'any secret this app declares. A declared value is opened by the vault, which refuses a name no row states ' +
|
|
77
|
+
'and a value nothing sealed, and neither of those refusals can happen here');
|
|
78
|
+
}
|
|
79
|
+
const wearing = wears().find((one) => name.toLowerCase().startsWith(one));
|
|
80
|
+
if (wearing === undefined)
|
|
81
|
+
return false;
|
|
82
|
+
return (name +
|
|
83
|
+
' wears the prefix ' +
|
|
84
|
+
wearing +
|
|
85
|
+
', so it names a secret, and this takes it from the environment instead of the vault — past the check that a ' +
|
|
86
|
+
'row declares it, and past the sealed store the value was written to');
|
|
87
|
+
},
|
|
88
|
+
proves: {
|
|
89
|
+
wrong: [
|
|
90
|
+
'const key = process.env[named.toUpperCase()]',
|
|
91
|
+
{
|
|
92
|
+
files: [
|
|
93
|
+
{ at: 'thread/core/thread.ts', source: "export interface Threaded {\n readonly id?: string\n readonly at?: string\n readonly describes?: string\n readonly declares?: readonly Threaded[]\n readonly derives?: readonly Threaded[]\n readonly seeds?: readonly Threaded[]\n}\n" },
|
|
94
|
+
{ at: 'threads/thread.ts', source: "import type { Threaded } from '../thread/core/thread.ts'\n\nexport const THREAD: Threaded = {\n declares: [\n {\n at: 'threads/_probe_secrets.ts',\n },\n ],\n}\n" },
|
|
95
|
+
{ at: 'threads/_probe_secrets.ts', source: "import type { Threaded } from '../thread/core/thread.ts'\n\nexport const SECRETS: Threaded = {\n id: 'secrets',\n declares: [\n {\n id: 'sec_model',\n at: 'threads/_probe_secrets.ts',\n },\n ],\n}\n" },
|
|
96
|
+
{ at: 'probe.tsx', source: "const key = process.env['SEC_MODEL']\n" },
|
|
97
|
+
],
|
|
98
|
+
at: 'probe.tsx',
|
|
99
|
+
},
|
|
100
|
+
],
|
|
101
|
+
right: [
|
|
102
|
+
"const mode = process.env['NODE_ENV']",
|
|
103
|
+
"const DEPTH = 'THREAD_DEPTH'\n\nconst depth = Number(process.env[DEPTH] ?? '0')",
|
|
104
|
+
"const held = opened(['sec_model'])",
|
|
105
|
+
],
|
|
106
|
+
},
|
|
107
|
+
};
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import type { Slopnator } from '../slopnator.ts'
|
|
2
|
+
|
|
3
|
+
import { descend, read, reached } from '../../core/descend.ts'
|
|
4
|
+
import { rowsIn } from './sl_unthreaded.ts'
|
|
5
|
+
|
|
6
|
+
interface Held {
|
|
7
|
+
readonly type?: string
|
|
8
|
+
readonly name?: string
|
|
9
|
+
readonly value?: unknown
|
|
10
|
+
readonly computed?: boolean
|
|
11
|
+
readonly object?: Held
|
|
12
|
+
readonly property?: Held
|
|
13
|
+
readonly init?: Held
|
|
14
|
+
readonly id?: Held
|
|
15
|
+
readonly declaration?: Held
|
|
16
|
+
readonly declarations?: readonly Held[]
|
|
17
|
+
readonly left?: Held
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const SECRETS = 'secrets'
|
|
21
|
+
|
|
22
|
+
function wears(): readonly string[] {
|
|
23
|
+
const found = new Set<string>()
|
|
24
|
+
|
|
25
|
+
descend()
|
|
26
|
+
|
|
27
|
+
for (const at of reached()) {
|
|
28
|
+
const text = read(at)
|
|
29
|
+
if (text === undefined) continue
|
|
30
|
+
|
|
31
|
+
let waiting: string[] = []
|
|
32
|
+
for (const one of rowsIn(text)) {
|
|
33
|
+
if (one.id === undefined) continue
|
|
34
|
+
if (one.list === 'declares') {
|
|
35
|
+
waiting.push(one.id)
|
|
36
|
+
continue
|
|
37
|
+
}
|
|
38
|
+
if (one.list !== undefined) continue
|
|
39
|
+
if (one.id === SECRETS) {
|
|
40
|
+
for (const id of waiting) {
|
|
41
|
+
const cut = id.indexOf('_')
|
|
42
|
+
if (cut > 0) found.add(id.slice(0, cut + 1))
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
waiting = []
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return [...found]
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const HOLDS = 'process'
|
|
53
|
+
|
|
54
|
+
const ENV = 'env'
|
|
55
|
+
|
|
56
|
+
const isEnv = (one: Held | undefined): boolean =>
|
|
57
|
+
one?.type === 'MemberExpression' &&
|
|
58
|
+
one.object?.type === 'Identifier' &&
|
|
59
|
+
one.object.name === HOLDS &&
|
|
60
|
+
one.property?.type === 'Identifier' &&
|
|
61
|
+
one.property.name === ENV
|
|
62
|
+
|
|
63
|
+
function stated(node: Held | undefined, ancestors: readonly unknown[]): string | undefined {
|
|
64
|
+
if (node === undefined) return undefined
|
|
65
|
+
if (node.type === 'Literal' && typeof node.value === 'string') return node.value
|
|
66
|
+
if (node.type !== 'Identifier' || node.name === undefined) return undefined
|
|
67
|
+
for (const one of ancestors) {
|
|
68
|
+
const body = (one as { readonly body?: unknown }).body
|
|
69
|
+
for (const each of Array.isArray(body) ? (body as readonly unknown[]) : []) {
|
|
70
|
+
const line = each as Held
|
|
71
|
+
const held = line.type === 'ExportNamedDeclaration' ? line.declaration : line
|
|
72
|
+
if (held?.type !== 'VariableDeclaration') continue
|
|
73
|
+
for (const said of held.declarations ?? []) {
|
|
74
|
+
if (said.id?.type !== 'Identifier' || said.id.name !== node.name) continue
|
|
75
|
+
return said.init?.type === 'Literal' && typeof said.init.value === 'string' ? said.init.value : undefined
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return undefined
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export const slopnator: Slopnator = {
|
|
83
|
+
on: ['MemberExpression'],
|
|
84
|
+
holds: (node, at) => {
|
|
85
|
+
const held = node as Held
|
|
86
|
+
if (!isEnv(held.object)) return false
|
|
87
|
+
|
|
88
|
+
const up = at.ancestors()
|
|
89
|
+
const parent = up[up.length - 1] as Held | undefined
|
|
90
|
+
if (parent?.type === 'AssignmentExpression' && parent.left === held) return false
|
|
91
|
+
|
|
92
|
+
const name = held.computed === true ? stated(held.property, up) : held.property?.name
|
|
93
|
+
|
|
94
|
+
if (name === undefined) {
|
|
95
|
+
return (
|
|
96
|
+
'this takes a value out of the environment under a name nobody reading the file can see, so it can name ' +
|
|
97
|
+
'any secret this app declares. A declared value is opened by the vault, which refuses a name no row states ' +
|
|
98
|
+
'and a value nothing sealed, and neither of those refusals can happen here'
|
|
99
|
+
)
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
const wearing = wears().find((one) => name.toLowerCase().startsWith(one))
|
|
103
|
+
if (wearing === undefined) return false
|
|
104
|
+
|
|
105
|
+
return (
|
|
106
|
+
name +
|
|
107
|
+
' wears the prefix ' +
|
|
108
|
+
wearing +
|
|
109
|
+
', so it names a secret, and this takes it from the environment instead of the vault — past the check that a ' +
|
|
110
|
+
'row declares it, and past the sealed store the value was written to'
|
|
111
|
+
)
|
|
112
|
+
},
|
|
113
|
+
proves: {
|
|
114
|
+
wrong: [
|
|
115
|
+
'const key = process.env[named.toUpperCase()]',
|
|
116
|
+
{
|
|
117
|
+
files: [
|
|
118
|
+
{ at: 'thread/core/thread.ts', source: "export interface Threaded {\n readonly id?: string\n readonly at?: string\n readonly describes?: string\n readonly declares?: readonly Threaded[]\n readonly derives?: readonly Threaded[]\n readonly seeds?: readonly Threaded[]\n}\n" },
|
|
119
|
+
{ at: 'threads/thread.ts', source: "import type { Threaded } from '../thread/core/thread.ts'\n\nexport const THREAD: Threaded = {\n declares: [\n {\n at: 'threads/_probe_secrets.ts',\n },\n ],\n}\n" },
|
|
120
|
+
{ at: 'threads/_probe_secrets.ts', source: "import type { Threaded } from '../thread/core/thread.ts'\n\nexport const SECRETS: Threaded = {\n id: 'secrets',\n declares: [\n {\n id: 'sec_model',\n at: 'threads/_probe_secrets.ts',\n },\n ],\n}\n" },
|
|
121
|
+
{ at: 'probe.tsx', source: "const key = process.env['SEC_MODEL']\n" },
|
|
122
|
+
],
|
|
123
|
+
at: 'probe.tsx',
|
|
124
|
+
},
|
|
125
|
+
],
|
|
126
|
+
right: [
|
|
127
|
+
"const mode = process.env['NODE_ENV']",
|
|
128
|
+
"const DEPTH = 'THREAD_DEPTH'\n\nconst depth = Number(process.env[DEPTH] ?? '0')",
|
|
129
|
+
"const held = opened(['sec_model'])",
|
|
130
|
+
],
|
|
131
|
+
},
|
|
132
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { here, parses, rowsIn } from
|
|
1
|
+
import { here, parses, rowsIn } from './sl_unthreaded.js';
|
|
2
2
|
export const slopnator = {
|
|
3
3
|
holds: (_node, at) => {
|
|
4
4
|
const path = here(at.filename);
|
|
@@ -25,7 +25,8 @@ export const slopnator = {
|
|
|
25
25
|
files: [
|
|
26
26
|
{ at: 'thread/core/thread.ts', source: "export interface Threaded {\n readonly id?: string\n readonly at?: string\n readonly describes?: string\n readonly declares?: readonly Threaded[]\n readonly derives?: readonly Threaded[]\n readonly seeds?: readonly Threaded[]\n}\n" },
|
|
27
27
|
{ at: 'threads/thread.ts', source: "import type { Threaded } from '../thread/core/thread.ts'\n\nexport const THREAD: Threaded = {\n declares: [\n {\n at: 'threads/_unversioned_probe.ts',\n },\n ],\n}\n" },
|
|
28
|
-
{ at: 'threads/_unversioned_probe.ts', source: "import type { Threaded } from '../thread/core/thread.ts'\n\nexport const L: Threaded = {\n id: 'a-law',\n at: '
|
|
28
|
+
{ at: 'threads/_unversioned_probe.ts', source: "import type { Threaded } from '../thread/core/thread.ts'\n\nexport const L: Threaded = {\n id: 'a-law',\n at: 'thread/integrity/constraint.ts',\n describes: 'A rule that must be enforced.',\n}\n" },
|
|
29
|
+
{ at: 'thread/integrity/constraint.ts', source: 'export const CONSTRAINTS = []\n' },
|
|
29
30
|
],
|
|
30
31
|
at: 'threads/_unversioned_probe.ts',
|
|
31
32
|
},
|
|
@@ -35,11 +36,12 @@ export const slopnator = {
|
|
|
35
36
|
files: [
|
|
36
37
|
{ at: 'thread/core/thread.ts', source: "export interface Threaded {\n readonly id?: string\n readonly at?: string\n readonly describes?: string\n readonly declares?: readonly Threaded[]\n readonly derives?: readonly Threaded[]\n readonly seeds?: readonly Threaded[]\n}\n" },
|
|
37
38
|
{ at: 'threads/thread.ts', source: "import type { Threaded } from '../thread/core/thread.ts'\n\nexport const THREAD: Threaded = {\n declares: [\n {\n at: 'threads/_unversioned_probe.ts',\n },\n ],\n}\n" },
|
|
38
|
-
{ at: 'threads/_unversioned_probe.ts', source: "import type { Threaded } from '../thread/core/thread.ts'\n\nexport const L: Threaded = {\n id: 'a-law',\n at: '
|
|
39
|
+
{ at: 'threads/_unversioned_probe.ts', source: "import type { Threaded } from '../thread/core/thread.ts'\n\nexport const L: Threaded = {\n id: 'a-law',\n at: 'thread/integrity/constraint.ts',\n describes: 'A rule that must be enforced.',\n version: 3,\n}\n" },
|
|
40
|
+
{ at: 'thread/integrity/constraint.ts', source: 'export const CONSTRAINTS = []\n' },
|
|
39
41
|
],
|
|
40
42
|
at: 'threads/_unversioned_probe.ts',
|
|
41
43
|
},
|
|
42
|
-
"export const HELPER = {\n id: 'a-helper',\n at: 'threads/
|
|
44
|
+
"export const HELPER = {\n id: 'a-helper',\n at: 'threads/core.ts',\n describes: 'Nothing conforms to this.',\n}",
|
|
43
45
|
],
|
|
44
46
|
},
|
|
45
47
|
};
|
|
@@ -30,7 +30,8 @@ export const slopnator: Slopnator = {
|
|
|
30
30
|
files: [
|
|
31
31
|
{ at: 'thread/core/thread.ts', source: "export interface Threaded {\n readonly id?: string\n readonly at?: string\n readonly describes?: string\n readonly declares?: readonly Threaded[]\n readonly derives?: readonly Threaded[]\n readonly seeds?: readonly Threaded[]\n}\n" },
|
|
32
32
|
{ at: 'threads/thread.ts', source: "import type { Threaded } from '../thread/core/thread.ts'\n\nexport const THREAD: Threaded = {\n declares: [\n {\n at: 'threads/_unversioned_probe.ts',\n },\n ],\n}\n" },
|
|
33
|
-
{ at: 'threads/_unversioned_probe.ts', source: "import type { Threaded } from '../thread/core/thread.ts'\n\nexport const L: Threaded = {\n id: 'a-law',\n at: '
|
|
33
|
+
{ at: 'threads/_unversioned_probe.ts', source: "import type { Threaded } from '../thread/core/thread.ts'\n\nexport const L: Threaded = {\n id: 'a-law',\n at: 'thread/integrity/constraint.ts',\n describes: 'A rule that must be enforced.',\n}\n" },
|
|
34
|
+
{ at: 'thread/integrity/constraint.ts', source: 'export const CONSTRAINTS = []\n' },
|
|
34
35
|
],
|
|
35
36
|
at: 'threads/_unversioned_probe.ts',
|
|
36
37
|
},
|
|
@@ -40,11 +41,12 @@ export const slopnator: Slopnator = {
|
|
|
40
41
|
files: [
|
|
41
42
|
{ at: 'thread/core/thread.ts', source: "export interface Threaded {\n readonly id?: string\n readonly at?: string\n readonly describes?: string\n readonly declares?: readonly Threaded[]\n readonly derives?: readonly Threaded[]\n readonly seeds?: readonly Threaded[]\n}\n" },
|
|
42
43
|
{ at: 'threads/thread.ts', source: "import type { Threaded } from '../thread/core/thread.ts'\n\nexport const THREAD: Threaded = {\n declares: [\n {\n at: 'threads/_unversioned_probe.ts',\n },\n ],\n}\n" },
|
|
43
|
-
{ at: 'threads/_unversioned_probe.ts', source: "import type { Threaded } from '../thread/core/thread.ts'\n\nexport const L: Threaded = {\n id: 'a-law',\n at: '
|
|
44
|
+
{ at: 'threads/_unversioned_probe.ts', source: "import type { Threaded } from '../thread/core/thread.ts'\n\nexport const L: Threaded = {\n id: 'a-law',\n at: 'thread/integrity/constraint.ts',\n describes: 'A rule that must be enforced.',\n version: 3,\n}\n" },
|
|
45
|
+
{ at: 'thread/integrity/constraint.ts', source: 'export const CONSTRAINTS = []\n' },
|
|
44
46
|
],
|
|
45
47
|
at: 'threads/_unversioned_probe.ts',
|
|
46
48
|
},
|
|
47
|
-
"export const HELPER = {\n id: 'a-helper',\n at: 'threads/
|
|
49
|
+
"export const HELPER = {\n id: 'a-helper',\n at: 'threads/core.ts',\n describes: 'Nothing conforms to this.',\n}",
|
|
48
50
|
],
|
|
49
51
|
},
|
|
50
52
|
}
|