functionalscript 0.24.0 → 0.26.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. package/fs/asserts/proof.f.d.ts +8 -0
  2. package/fs/asserts/proof.f.js +51 -0
  3. package/fs/bnf/data/proof.f.js +7 -17
  4. package/fs/bnf/module.f.d.ts +10 -0
  5. package/fs/bnf/module.f.js +10 -0
  6. package/fs/bnf/testlib.f.js +4 -9
  7. package/fs/cas/module.f.d.ts +2 -10
  8. package/fs/cas/module.f.js +48 -52
  9. package/fs/cas/proof.f.js +21 -12
  10. package/fs/ci/common/module.f.d.ts +2 -0
  11. package/fs/ci/common/module.f.js +4 -1
  12. package/fs/ci/config/module.f.d.ts +2 -2
  13. package/fs/ci/config/module.f.js +2 -2
  14. package/fs/ci/module.f.d.ts +2 -4
  15. package/fs/ci/module.f.js +11 -9
  16. package/fs/ci/node/module.f.js +4 -2
  17. package/fs/ci/proof.f.js +8 -5
  18. package/fs/cli/module.f.d.ts +9 -0
  19. package/fs/cli/module.f.js +24 -0
  20. package/fs/cli/proof.f.d.ts +9 -0
  21. package/fs/cli/proof.f.js +86 -0
  22. package/fs/crypto/sha2/module.f.js +32 -36
  23. package/fs/crypto/vdf/module.f.d.ts +21 -0
  24. package/fs/crypto/vdf/module.f.js +57 -0
  25. package/fs/crypto/vdf/proof.f.d.ts +32 -0
  26. package/fs/crypto/vdf/proof.f.js +135 -0
  27. package/fs/dev/index/module.f.d.ts +1 -8
  28. package/fs/dev/index/module.f.js +1 -1
  29. package/fs/effects/node/module.f.d.ts +1 -1
  30. package/fs/emergent_testing/module.f.d.ts +1 -1
  31. package/fs/emergent_testing/module.f.js +2 -2
  32. package/fs/emergent_testing/proof.f.js +1 -1
  33. package/fs/fjs/module.f.js +34 -24
  34. package/fs/json/module.f.d.ts +25 -9
  35. package/fs/json/module.f.js +25 -3
  36. package/fs/json/rpc/module.f.d.ts +109 -0
  37. package/fs/json/rpc/module.f.js +84 -0
  38. package/fs/json/rpc/proof.f.d.ts +35 -0
  39. package/fs/json/rpc/proof.f.js +68 -0
  40. package/fs/json/schema/module.f.d.ts +76 -0
  41. package/fs/json/schema/module.f.js +112 -0
  42. package/fs/json/schema/proof.f.d.ts +33 -0
  43. package/fs/json/schema/proof.f.js +71 -0
  44. package/fs/mcp/module.f.d.ts +88 -0
  45. package/fs/mcp/module.f.js +69 -0
  46. package/fs/sul/level/literal/proof.f.d.ts +1 -0
  47. package/fs/sul/level/literal/proof.f.js +6 -0
  48. package/fs/types/array/module.f.d.ts +7 -0
  49. package/fs/types/array/module.f.js +7 -0
  50. package/fs/types/prime_field/module.f.d.ts +8 -0
  51. package/fs/types/prime_field/module.f.js +37 -5
  52. package/fs/types/prime_field/proof.f.d.ts +3 -0
  53. package/fs/types/prime_field/proof.f.js +27 -2
  54. package/fs/types/rtti/parse/module.f.d.ts +28 -0
  55. package/fs/types/rtti/parse/module.f.js +35 -5
  56. package/fs/types/rtti/ts/module.f.d.ts +46 -3
  57. package/fs/types/rtti/validate/module.f.js +5 -0
  58. package/fs/website/module.f.d.ts +1 -2
  59. package/fs/website/module.f.js +1 -1
  60. package/fs/website/proof.f.d.ts +1 -1
  61. package/fs/website/proof.f.js +3 -3
  62. package/package.json +4 -4
@@ -0,0 +1,86 @@
1
+ import { pure } from "../effects/module.f.js";
2
+ import {} from "../effects/node/module.f.js";
3
+ import { emptyState, virtual } from "../effects/node/virtual/module.f.js";
4
+ import { dispatch } from "./module.f.js";
5
+ const makeOptions = (args) => ({
6
+ args,
7
+ env: {},
8
+ std: { stdout: { isTTY: false }, stderr: { isTTY: false } },
9
+ testContext: { test: async () => { } },
10
+ bunTestContext: { test: async () => { } },
11
+ playwrightTestContext: { test: async () => { } },
12
+ engine: 'node',
13
+ });
14
+ const echoCommands = [
15
+ {
16
+ names: ['echo', 'e'],
17
+ description: 'Print the first argument',
18
+ handler: ({ args: [arg = ''] }) => pure(arg.length),
19
+ },
20
+ ];
21
+ const run = (commands) => (args) => virtual(emptyState)(dispatch(commands)(makeOptions(args)));
22
+ export const proof = {
23
+ knownCommand: () => {
24
+ const [, code] = run(echoCommands)(['echo', 'hello']);
25
+ if (code !== 5) {
26
+ throw ['expected length 5', code];
27
+ }
28
+ },
29
+ alias: () => {
30
+ const [, code] = run(echoCommands)(['e', 'hi']);
31
+ if (code !== 2) {
32
+ throw ['expected length 2', code];
33
+ }
34
+ },
35
+ noArgs: () => {
36
+ const [state, code] = run(echoCommands)([]);
37
+ if (code !== 1) {
38
+ throw ['expected exit 1', code];
39
+ }
40
+ if (state.stderr.length === 0) {
41
+ throw 'expected error in stderr';
42
+ }
43
+ },
44
+ unknownCommand: () => {
45
+ const [state, code] = run(echoCommands)(['bogus']);
46
+ if (code !== 1) {
47
+ throw ['expected exit 1', code];
48
+ }
49
+ if (state.stderr.length === 0) {
50
+ throw 'expected error in stderr';
51
+ }
52
+ },
53
+ help: () => {
54
+ const [state, code] = run(echoCommands)(['help']);
55
+ if (code !== 0) {
56
+ throw ['expected exit 0', code];
57
+ }
58
+ if (!state.stdout.includes('echo')) {
59
+ throw 'expected command name in stdout';
60
+ }
61
+ if (!state.stdout.includes('help')) {
62
+ throw 'expected help entry in stdout';
63
+ }
64
+ },
65
+ errorIncludesAvailable: () => {
66
+ const [state] = run(echoCommands)(['bogus']);
67
+ if (!state.stderr.includes('echo')) {
68
+ throw 'expected available commands in error';
69
+ }
70
+ },
71
+ handlerReceivesRemainingArgs: () => {
72
+ const captured = [];
73
+ const commands = [{
74
+ names: ['grab'],
75
+ description: 'Capture args',
76
+ handler: ({ args }) => {
77
+ captured.push(...args);
78
+ return pure(0);
79
+ },
80
+ }];
81
+ run(commands)(['grab', 'a', 'b', 'c']);
82
+ if (captured.join(',') !== 'a,b,c') {
83
+ throw ['unexpected args', captured];
84
+ }
85
+ },
86
+ };
@@ -9,47 +9,43 @@ const base = ({ logBitLen, k, bs0, bs1, ss0, ss1 }) => {
9
9
  const r = bitLength - d;
10
10
  return (n) => n >> d | n << r;
11
11
  };
12
- const bigSigma = ([a, b, c]) => {
12
+ const sigma = third => (a, b, c) => {
13
13
  const ra = rotr(a);
14
14
  const rb = rotr(b);
15
- const rc = rotr(c);
16
- return (x) => ra(x) ^ rb(x) ^ rc(x);
15
+ const rc = third(c);
16
+ return x => ra(x) ^ rb(x) ^ rc(x);
17
17
  };
18
- const bigSigma0 = bigSigma(bs0);
19
- const bigSigma1 = bigSigma(bs1);
20
- const smallSigma = ([a, b, c]) => {
21
- const ra = rotr(a);
22
- const rb = rotr(b);
23
- return (x) => ra(x) ^ rb(x) ^ (x >> c);
24
- };
25
- const smallSigma0 = smallSigma(ss0);
26
- const smallSigma1 = smallSigma(ss1);
18
+ const bigSigma = sigma(rotr);
19
+ const smallSigma = sigma(c => x => x >> c);
20
+ const bigSigma0 = bigSigma(...bs0);
21
+ const bigSigma1 = bigSigma(...bs1);
22
+ const smallSigma0 = smallSigma(...ss0);
23
+ const smallSigma1 = smallSigma(...ss1);
27
24
  const ch = (x, y, z) => x & y ^ ~x & z;
28
25
  const maj = (x, y, z) => x & y ^ x & z ^ y & z;
29
26
  const m = mask(bitLength);
30
- const wi = ([a0, a1, a2, a3]) => (smallSigma1(a0) + a1 + smallSigma0(a2) + a3) & m;
31
- const nextW = ([w0, w1, w2, w3, w4, w5, w6, w7, w8, w9, wA, wB, wC, wD, wE, wF]) => {
32
- w0 = wi([wE, w9, w1, w0]);
33
- w1 = wi([wF, wA, w2, w1]);
34
- w2 = wi([w0, wB, w3, w2]);
35
- w3 = wi([w1, wC, w4, w3]);
36
- w4 = wi([w2, wD, w5, w4]);
37
- w5 = wi([w3, wE, w6, w5]);
38
- w6 = wi([w4, wF, w7, w6]);
39
- w7 = wi([w5, w0, w8, w7]);
40
- w8 = wi([w6, w1, w9, w8]);
41
- w9 = wi([w7, w2, wA, w9]);
42
- wA = wi([w8, w3, wB, wA]);
43
- wB = wi([w9, w4, wC, wB]);
44
- wC = wi([wA, w5, wD, wC]);
45
- wD = wi([wB, w6, wE, wD]);
46
- wE = wi([wC, w7, wF, wE]);
47
- wF = wi([wD, w8, w0, wF]);
27
+ const wi = (a0, a1, a2, a3) => (smallSigma1(a0) + a1 + smallSigma0(a2) + a3) & m;
28
+ const nextW = (w0, w1, w2, w3, w4, w5, w6, w7, w8, w9, wA, wB, wC, wD, wE, wF) => {
29
+ w0 = wi(wE, w9, w1, w0);
30
+ w1 = wi(wF, wA, w2, w1);
31
+ w2 = wi(w0, wB, w3, w2);
32
+ w3 = wi(w1, wC, w4, w3);
33
+ w4 = wi(w2, wD, w5, w4);
34
+ w5 = wi(w3, wE, w6, w5);
35
+ w6 = wi(w4, wF, w7, w6);
36
+ w7 = wi(w5, w0, w8, w7);
37
+ w8 = wi(w6, w1, w9, w8);
38
+ w9 = wi(w7, w2, wA, w9);
39
+ wA = wi(w8, w3, wB, wA);
40
+ wB = wi(w9, w4, wC, wB);
41
+ wC = wi(wA, w5, wD, wC);
42
+ wD = wi(wB, w6, wE, wD);
43
+ wE = wi(wC, w7, wF, wE);
44
+ wF = wi(wD, w8, w0, wF);
48
45
  return [w0, w1, w2, w3, w4, w5, w6, w7, w8, w9, wA, wB, wC, wD, wE, wF];
49
46
  };
50
47
  const kLength = k.length;
51
- const compressV16 = ([a0, b0, c0, d0, e0, f0, g0, h0]) => (data) => {
52
- let w = data;
48
+ const compressV16 = (a0, b0, c0, d0, e0, f0, g0, h0) => w => {
53
49
  let a = a0;
54
50
  let b = b0;
55
51
  let c = c0;
@@ -77,7 +73,7 @@ const base = ({ logBitLen, k, bs0, bs1, ss0, ss1 }) => {
77
73
  if (i === kLength) {
78
74
  break;
79
75
  }
80
- w = nextW(w);
76
+ w = nextW(...w);
81
77
  }
82
78
  return [
83
79
  (a0 + a) & m,
@@ -90,10 +86,10 @@ const base = ({ logBitLen, k, bs0, bs1, ss0, ss1 }) => {
90
86
  (h0 + h) & m,
91
87
  ];
92
88
  };
93
- const at = (u) => (i) => (u >> (i << logBitLen)) & m;
94
- const compress = (i) => (u) => {
89
+ const at = u => i => (u >> (i << logBitLen)) & m;
90
+ const compress = i => u => {
95
91
  const a = at(u);
96
- return compressV16(i)([
92
+ return compressV16(...i)([
97
93
  a(15n),
98
94
  a(14n),
99
95
  a(13n),
@@ -0,0 +1,21 @@
1
+ import type { Nullable } from '../../types/nullable/module.f.ts';
2
+ /** Sloth VDF modulus (3072-bit safe prime, same as reference implementations). */
3
+ export declare const p = 170082004324204494273811327264862981553264701145937538369570764779791492622392118654022654452947093285873855529044371650895045691292912712699015605832276411308653107069798639938826015099738961427172366594187783204437869906954750443653318078358839409699824714551430573905637228307966826784684174483831608534979n;
4
+ /**
5
+ * Sloth VDF over prime `modulus` (`p ≡ 3 (mod 4)`).
6
+ */
7
+ export type Sloth = {
8
+ readonly p: bigint;
9
+ readonly quadRes: (x: bigint) => boolean;
10
+ readonly modSqrt: (x: bigint) => bigint;
11
+ /** Sequential Sloth permutation; `null` when `steps < 0`. */
12
+ readonly eval: (steps: bigint) => (x: bigint) => Nullable<bigint>;
13
+ /** Fast verification of {@link Sloth.eval}; `false` when `steps < 0`. */
14
+ readonly verify: (steps: bigint) => (x: bigint) => (y: bigint) => boolean;
15
+ };
16
+ /**
17
+ * Builds Sloth VDF operations over `modulus`.
18
+ */
19
+ export declare const sloth_vdf: (modulus: bigint) => Sloth;
20
+ /** Sloth VDF over {@link p}. */
21
+ export declare const sloth: Sloth;
@@ -0,0 +1,57 @@
1
+ /**
2
+ * Sloth verifiable delay function over a fixed 3072-bit safe prime.
3
+ *
4
+ * @module
5
+ *
6
+ * @example
7
+ *
8
+ * ```ts
9
+ * import { sloth } from './module.f.ts'
10
+ *
11
+ * const steps = 4n
12
+ * const x = 42n
13
+ * const y = sloth.eval(steps)(x)
14
+ * if (y === null || !sloth.verify(steps)(x)(y)) { throw y }
15
+ * ```
16
+ */
17
+ import { modSqrt, prime_field } from "../../types/prime_field/module.f.js";
18
+ /** Sloth VDF modulus (3072-bit safe prime, same as reference implementations). */
19
+ export const p = 0xf2346eae06a233882814ff16f6a076d3b8f2161c5c92171c0b7b84eed4e9475bcce0c13bde34512afdf90f41ab9b86dcf834f85e04b27fadee712eed23a1d4e58cd1b09d9bfb10696d614f119179a40c49dc8762edc29e8115263913237e14718cbcd4dc6b35bace13f8cdb1b5156c50c47b4aaee0820c874e2864cb854367c3n;
20
+ const repeatSeq = (steps) => (f) => (value) => {
21
+ let v = value;
22
+ let i = 0n;
23
+ while (i < steps) {
24
+ v = f(v);
25
+ i = i + 1n;
26
+ }
27
+ return v;
28
+ };
29
+ /**
30
+ * Builds Sloth VDF operations over `modulus`.
31
+ */
32
+ export const sloth_vdf = (modulus) => {
33
+ const field = prime_field(modulus);
34
+ const { neg, pow2, reduce, quadRes } = field;
35
+ const root = modSqrt(field);
36
+ const squareLoop = (steps) => (value) => repeatSeq(steps)(pow2)(reduce(value));
37
+ const modSqrtLoop = (steps) => (value) => repeatSeq(steps)(root)(reduce(value));
38
+ const evalSteps = (steps) => (x) => steps < 0n ? null : modSqrtLoop(steps)(x);
39
+ const verifySteps = (steps) => (x) => (y) => {
40
+ if (steps < 0n) {
41
+ return false;
42
+ }
43
+ const input = reduce(x);
44
+ const squared = squareLoop(steps)(y);
45
+ const value = quadRes(squared) ? squared : neg(squared);
46
+ return input === value || neg(input) === value;
47
+ };
48
+ return {
49
+ p: modulus,
50
+ quadRes,
51
+ modSqrt: root,
52
+ eval: evalSteps,
53
+ verify: verifySteps,
54
+ };
55
+ };
56
+ /** Sloth VDF over {@link p}. */
57
+ export const sloth = sloth_vdf(p);
@@ -0,0 +1,32 @@
1
+ export declare const proof: {
2
+ p: {
3
+ matchesField: () => void;
4
+ };
5
+ eval: {
6
+ steps100: () => void;
7
+ steps10: () => void;
8
+ steps6: () => void;
9
+ steps4: () => void;
10
+ zeroSteps: () => void;
11
+ negativeSteps: () => void;
12
+ };
13
+ verify: {
14
+ steps100: () => void;
15
+ steps10: () => void;
16
+ steps6: () => void;
17
+ steps4: () => void;
18
+ tampered: () => void;
19
+ wrongY: () => void;
20
+ zeroSteps: () => void;
21
+ negativeSteps: () => void;
22
+ invalidY: () => void;
23
+ };
24
+ modSqrt: {
25
+ roundTrip: () => void;
26
+ nonResidue: () => void;
27
+ };
28
+ quadRes: {
29
+ one: () => void;
30
+ nonResidue: () => void;
31
+ };
32
+ };
@@ -0,0 +1,135 @@
1
+ import { sloth, p } from "./module.f.js";
2
+ const { eval: evalVdf, verify, modSqrt, quadRes } = sloth;
3
+ // `eval(steps)(x)` expected values for {@link p}; same Sloth algorithm as
4
+ // https://github.com/hyperhyperspace/pulsar/blob/main/src/model/SlothVDF.ts and
5
+ // https://github.com/jose-compu/dignity.js/blob/main/src/security/sloth-vdf.js
6
+ const sampleX = 123456789n;
7
+ const largeX = 12345678901234567890n;
8
+ const smallX = 42n;
9
+ const nonResidue = 2n;
10
+ const sampleY = 72412151236937799598582816305571618206681207952550127764586725290711141789888684237028784568532880529360450375677852568362636821341317217048062977639333459511661887862128325859969604061461913896412260750881385045152117694320409864730924775539555636460819549547999218170813228857928921642957426089461925313163n;
11
+ const smallY = 145151597037272685697451525487035431973338817762329243361437778785747534269376083577375382484815474368317818719265551745910148543423765263685177263740373969289084400977118144482329577335929842301331443392042760708529572252015473334998752211959790788326970269713683808382892472572910797612141527200051803670965n;
12
+ const y6 = 116287514643100261336025249676072556421566393377742705567032370320583145555855278910304225489766306768040386612082033279417845047304479679877515174322332386599890348932893235091525789175564701751964775040887336849457197662999383850490808701700264064812615988837073981567599117932005435532913423970502774287312n;
13
+ const y4 = 64401150265223443694244964595084197237814157534040219819342647664782563317539559768554855806938965782018778040933157632467146168153951260465261118025222264314070274636967492909984790708532033331622332323767105919809000393624013423095812833452440384602112677364631962445309757177309466319657219548312354433189n;
14
+ export const proof = {
15
+ p: {
16
+ matchesField: () => {
17
+ if (sloth.p !== p) {
18
+ throw [sloth.p, p];
19
+ }
20
+ },
21
+ },
22
+ eval: {
23
+ steps100: () => {
24
+ const y = evalVdf(100n)(sampleX);
25
+ if (y !== sampleY) {
26
+ throw [y, sampleY];
27
+ }
28
+ },
29
+ steps10: () => {
30
+ const y = evalVdf(10n)(smallX);
31
+ if (y !== smallY) {
32
+ throw [y, smallY];
33
+ }
34
+ },
35
+ steps6: () => {
36
+ const y = evalVdf(6n)(largeX);
37
+ if (y !== y6) {
38
+ throw [y, y6];
39
+ }
40
+ },
41
+ steps4: () => {
42
+ const y = evalVdf(4n)(smallX);
43
+ if (y !== y4) {
44
+ throw [y, y4];
45
+ }
46
+ },
47
+ zeroSteps: () => {
48
+ const y = evalVdf(0n)(sampleX);
49
+ if (y !== sampleX % p) {
50
+ throw [y, sampleX % p];
51
+ }
52
+ },
53
+ negativeSteps: () => {
54
+ const y = evalVdf(-1n)(sampleX);
55
+ if (y !== null) {
56
+ throw y;
57
+ }
58
+ },
59
+ },
60
+ verify: {
61
+ steps100: () => {
62
+ if (!verify(100n)(sampleX)(sampleY)) {
63
+ throw false;
64
+ }
65
+ },
66
+ steps10: () => {
67
+ if (!verify(10n)(smallX)(smallY)) {
68
+ throw false;
69
+ }
70
+ },
71
+ steps6: () => {
72
+ if (!verify(6n)(largeX)(y6)) {
73
+ throw false;
74
+ }
75
+ },
76
+ steps4: () => {
77
+ if (!verify(4n)(smallX)(y4)) {
78
+ throw false;
79
+ }
80
+ },
81
+ tampered: () => {
82
+ if (verify(4n)(smallX)((y4 + 1n) % p)) {
83
+ throw (y4 + 1n) % p;
84
+ }
85
+ },
86
+ wrongY: () => {
87
+ if (verify(100n)(sampleX)(sampleY + 1n)) {
88
+ throw sampleY + 1n;
89
+ }
90
+ },
91
+ zeroSteps: () => {
92
+ if (!verify(0n)(sampleX)(sampleX % p)) {
93
+ throw [sampleX % p];
94
+ }
95
+ },
96
+ negativeSteps: () => {
97
+ if (verify(-1n)(sampleX)(sampleY)) {
98
+ throw sampleY;
99
+ }
100
+ },
101
+ invalidY: () => {
102
+ if (verify(100n)(sampleX)(0n)) {
103
+ throw 0n;
104
+ }
105
+ },
106
+ },
107
+ modSqrt: {
108
+ roundTrip: () => {
109
+ const x = 999n;
110
+ if (!verify(1n)(x)(modSqrt(x))) {
111
+ throw modSqrt(x);
112
+ }
113
+ },
114
+ nonResidue: () => {
115
+ if (quadRes(nonResidue)) {
116
+ throw nonResidue;
117
+ }
118
+ if (!verify(1n)(nonResidue)(modSqrt(nonResidue))) {
119
+ throw modSqrt(nonResidue);
120
+ }
121
+ },
122
+ },
123
+ quadRes: {
124
+ one: () => {
125
+ if (!quadRes(1n)) {
126
+ throw 1n;
127
+ }
128
+ },
129
+ nonResidue: () => {
130
+ if (quadRes(nonResidue)) {
131
+ throw nonResidue;
132
+ }
133
+ },
134
+ },
135
+ };
@@ -1,8 +1 @@
1
- /**
2
- * Entry point for the `index` developer program: re-exports `index4` from the
3
- * parent `dev` module as the default `NodeProgram`.
4
- *
5
- * @module
6
- */
7
- import { index4 } from '../module.f.ts';
8
- export default index4;
1
+ export declare const main: import("../../effects/node/module.f.ts").NodeProgram;
@@ -5,4 +5,4 @@
5
5
  * @module
6
6
  */
7
7
  import { index4 } from "../module.f.js";
8
- export default index4;
8
+ export const main = index4;
@@ -166,7 +166,7 @@ export type NodeEffect<T> = Effect<NodeOp, T>;
166
166
  * "fail with a message" program for a `NodeProgram`. For non-`1` exit codes,
167
167
  * compose `error(s).step(() => pure(n))` directly.
168
168
  */
169
- export declare const errorExit: (s: string) => Effect<NodeOp, number>;
169
+ export declare const errorExit: (s: string) => Effect<Write, number>;
170
170
  export type NodeOperationMap = ToAsyncOperationMap<NodeOp>;
171
171
  /**
172
172
  * The environment variables.
@@ -117,7 +117,7 @@ export declare const defaultTest: (file: string, path: Path, { fn, throws }: Tes
117
117
  /**
118
118
  * The terminal/GitHub reporter used by `fjs t`. Output goes through
119
119
  * `csiWrite`, so ANSI styles are stripped on non-TTY streams. When
120
- * `GITHUB_ACTION` is set, failures are emitted as `::error` workflow
120
+ * `GITHUB_ACTIONS` is set, failures are emitted as `::error` workflow
121
121
  * annotations instead of colored lines. Exported as a factory so the
122
122
  * GitHub format path can be exercised directly from tests.
123
123
  */
@@ -220,7 +220,7 @@ const fmtResultLine = (file, path, color, label, duration) => `${fmtImport(file,
220
220
  /**
221
221
  * The terminal/GitHub reporter used by `fjs t`. Output goes through
222
222
  * `csiWrite`, so ANSI styles are stripped on non-TTY streams. When
223
- * `GITHUB_ACTION` is set, failures are emitted as `::error` workflow
223
+ * `GITHUB_ACTIONS` is set, failures are emitted as `::error` workflow
224
224
  * annotations instead of colored lines. Exported as a factory so the
225
225
  * GitHub format path can be exercised directly from tests.
226
226
  */
@@ -232,7 +232,7 @@ export const defaultReporter = (options) => {
232
232
  };
233
233
  const csiLog = line('stdout');
234
234
  const csiError = line('stderr');
235
- const isGitHub = options.env['GITHUB_ACTION'] !== undefined;
235
+ const isGitHub = options.env['GITHUB_ACTIONS'] !== undefined;
236
236
  return {
237
237
  // https://github.com/OndraM/ci-detector/blob/main/src/Ci/GitHubActions.php
238
238
  result: (file, path, { result: [s, v], duration }, throws) => s === 'ok'
@@ -17,7 +17,7 @@ const makeReporter = () => {
17
17
  const noopTestContext = { test: todo };
18
18
  const options = (initCwd, github = false) => ({
19
19
  args: [],
20
- env: { INIT_CWD: initCwd, ...(github ? { GITHUB_ACTION: 'true' } : {}) },
20
+ env: { INIT_CWD: initCwd, ...(github ? { GITHUB_ACTIONS: 'true' } : {}) },
21
21
  std: { stdout: { isTTY: false }, stderr: { isTTY: false } },
22
22
  testContext: noopTestContext,
23
23
  bunTestContext: noopTestContext,
@@ -6,32 +6,42 @@
6
6
  import { compile } from "../djs/module.f.js";
7
7
  import { main as testMain } from "../emergent_testing/module.f.js";
8
8
  import { main as casMain } from "../cas/module.f.js";
9
- import { import_, errorExit } from "../effects/node/module.f.js";
10
- export const main = options => {
11
- const [command, ...rest] = options.args;
12
- switch (command) {
13
- case 'test':
14
- case 't':
15
- return testMain({ ...options, args: rest });
16
- case 'compile':
17
- case 'c':
18
- return compile(rest);
19
- case 'cas':
20
- case 's':
21
- return casMain(rest);
22
- case 'run':
23
- case 'r': {
24
- const [file, ...args] = rest;
9
+ import { main as ciMain } from "../ci/module.f.js";
10
+ import { import_ } from "../effects/node/module.f.js";
11
+ import { dispatch } from "../cli/module.f.js";
12
+ const commands = [
13
+ {
14
+ names: ['test', 't'],
15
+ description: 'Run the FunctionalScript test suite',
16
+ handler: testMain,
17
+ },
18
+ {
19
+ names: ['compile', 'c'],
20
+ description: 'Compile a FunctionalScript module to JavaScript',
21
+ handler: ({ args }) => compile(args),
22
+ },
23
+ {
24
+ names: ['cas', 's'],
25
+ description: 'Content-addressable storage operations',
26
+ handler: casMain,
27
+ },
28
+ {
29
+ names: ['ci', 'i'],
30
+ description: 'Generate the GitHub Actions CI workflow',
31
+ handler: ciMain,
32
+ },
33
+ {
34
+ names: ['run', 'r'],
35
+ description: 'Run a FunctionalScript module as a NodeProgram',
36
+ handler: options => {
37
+ const [file, ...args] = options.args;
25
38
  return import_(file).step(([s, v]) => {
26
39
  if (s === 'error') {
27
40
  throw v;
28
41
  }
29
- return v.default({ ...options, args });
42
+ return v.main({ ...options, args });
30
43
  });
31
- }
32
- case undefined:
33
- return errorExit('Error: command is required');
34
- default:
35
- return errorExit(`Error: Unknown command "${command}"`);
36
- }
37
- };
44
+ },
45
+ },
46
+ ];
47
+ export const main = dispatch(commands);
@@ -1,18 +1,34 @@
1
1
  /**
2
- * JSON tree types and utilities: `Primitive`/`Unknown` value shapes,
3
- * `setProperty` for immutable nested updates, and a `stringify` built from the
4
- * serializer wraps.
2
+ * JSON value types, rtti schemas, and utilities: `serialize`, `stringify`,
3
+ * `parse`, and `setProperty` for immutable nested updates.
4
+ *
5
+ * The JSON value types (`Unknown`, `Primitive`) are derived from the rtti
6
+ * schemas defined here, so the schema is the single source of truth — no
7
+ * hand-written types to keep in sync.
5
8
  *
6
9
  * @module
7
10
  */
8
11
  import { type List } from '../types/list/module.f.ts';
9
12
  import { type Entry as ObjectEntry } from '../types/object/module.f.ts';
10
- type Object = {
11
- readonly [k in string]: Unknown;
12
- };
13
- type Array = readonly Unknown[];
14
- export type Primitive = boolean | string | number | null;
15
- export type Unknown = Primitive | Object | Array;
13
+ import type { Ts } from '../types/rtti/ts/module.f.ts';
14
+ /** rtti schema matching any JSON primitive: `null`, `boolean`, `number`, or `string`. */
15
+ export declare const primitive: import("../types/rtti/module.f.ts").Or<[null, import("../types/rtti/module.f.ts").Boolean, import("../types/rtti/module.f.ts").Number, import("../types/rtti/module.f.ts").String]>;
16
+ /**
17
+ * rtti schema matching any JSON value: a primitive, an array of JSON values,
18
+ * or an object whose values are JSON values. Self-referential via a thunk;
19
+ * rtti instantiates array/record item validators lazily so recursion terminates
20
+ * on acyclic input.
21
+ *
22
+ * A struct field typed `unknown` is **required when present** — unlike rtti
23
+ * core's `unknown`, the JSON `unknown` excludes `undefined`.
24
+ */
25
+ export declare const unknown: () => readonly ["or", import("../types/rtti/module.f.ts").Or<[null, import("../types/rtti/module.f.ts").Boolean, import("../types/rtti/module.f.ts").Number, import("../types/rtti/module.f.ts").String]>, import("../types/rtti/module.f.ts").Type1<"record", () => readonly ["or", import("../types/rtti/module.f.ts").Or<[null, import("../types/rtti/module.f.ts").Boolean, import("../types/rtti/module.f.ts").Number, import("../types/rtti/module.f.ts").String]>, import("../types/rtti/module.f.ts").Type1<"record", /*elided*/ any>, import("../types/rtti/module.f.ts").Type1<"array", /*elided*/ any>]>, import("../types/rtti/module.f.ts").Type1<"array", () => readonly ["or", import("../types/rtti/module.f.ts").Or<[null, import("../types/rtti/module.f.ts").Boolean, import("../types/rtti/module.f.ts").Number, import("../types/rtti/module.f.ts").String]>, import("../types/rtti/module.f.ts").Type1<"record", /*elided*/ any>, import("../types/rtti/module.f.ts").Type1<"array", /*elided*/ any>]>];
26
+ /** rtti schema matching a JSON object: `{ readonly [k: string]: Unknown }`. */
27
+ export declare const object: import("../types/rtti/module.f.ts").Type1<"record", () => readonly ["or", import("../types/rtti/module.f.ts").Or<[null, import("../types/rtti/module.f.ts").Boolean, import("../types/rtti/module.f.ts").Number, import("../types/rtti/module.f.ts").String]>, import("../types/rtti/module.f.ts").Type1<"record", /*elided*/ any>, import("../types/rtti/module.f.ts").Type1<"array", /*elided*/ any>]>;
28
+ /** rtti schema matching a JSON array: `readonly Unknown[]`. */
29
+ export declare const array: import("../types/rtti/module.f.ts").Type1<"array", () => readonly ["or", import("../types/rtti/module.f.ts").Or<[null, import("../types/rtti/module.f.ts").Boolean, import("../types/rtti/module.f.ts").Number, import("../types/rtti/module.f.ts").String]>, import("../types/rtti/module.f.ts").Type1<"record", /*elided*/ any>, import("../types/rtti/module.f.ts").Type1<"array", /*elided*/ any>]>;
30
+ export type Primitive = Ts<typeof primitive>;
31
+ export type Unknown = Ts<typeof unknown>;
16
32
  export declare const setProperty: (value: Unknown) => (path: List<string>) => (src: Unknown) => Unknown;
17
33
  export type Entry = ObjectEntry<Unknown>;
18
34
  type Entries = List<Entry>;
@@ -1,7 +1,10 @@
1
1
  /**
2
- * JSON tree types and utilities: `Primitive`/`Unknown` value shapes,
3
- * `setProperty` for immutable nested updates, and a `stringify` built from the
4
- * serializer wraps.
2
+ * JSON value types, rtti schemas, and utilities: `serialize`, `stringify`,
3
+ * `parse`, and `setProperty` for immutable nested updates.
4
+ *
5
+ * The JSON value types (`Unknown`, `Primitive`) are derived from the rtti
6
+ * schemas defined here, so the schema is the single source of truth — no
7
+ * hand-written types to keep in sync.
5
8
  *
6
9
  * @module
7
10
  */
@@ -10,6 +13,25 @@ import { concat } from "../types/string/module.f.js";
10
13
  import { at } from "../types/object/module.f.js";
11
14
  import { compose, fn } from "../types/function/module.f.js";
12
15
  import { objectWrap, arrayWrap, stringSerialize, numberSerialize, nullSerialize, boolSerialize } from "./serializer/module.f.js";
16
+ import { boolean as rttiBoolean, number as rttiNumber, string as rttiString, or, record, array as rttiArray } from "../types/rtti/module.f.js";
17
+ // ── rtti schemas ──────────────────────────────────────────────────────────────
18
+ /** rtti schema matching any JSON primitive: `null`, `boolean`, `number`, or `string`. */
19
+ export const primitive = or(null, rttiBoolean, rttiNumber, rttiString);
20
+ /**
21
+ * rtti schema matching any JSON value: a primitive, an array of JSON values,
22
+ * or an object whose values are JSON values. Self-referential via a thunk;
23
+ * rtti instantiates array/record item validators lazily so recursion terminates
24
+ * on acyclic input.
25
+ *
26
+ * A struct field typed `unknown` is **required when present** — unlike rtti
27
+ * core's `unknown`, the JSON `unknown` excludes `undefined`.
28
+ */
29
+ export const unknown = () => ['or', primitive, object, array];
30
+ /** rtti schema matching a JSON object: `{ readonly [k: string]: Unknown }`. */
31
+ export const object = record(unknown);
32
+ /** rtti schema matching a JSON array: `readonly Unknown[]`. */
33
+ export const array = rttiArray(unknown);
34
+ // ── JSON utilities ────────────────────────────────────────────────────────────
13
35
  const { entries } = Object;
14
36
  export const setProperty = value => {
15
37
  const f = path => src => {