functionalscript 0.33.0 → 0.34.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.
- package/README.md +1 -1
- package/fs/asserts/module.f.d.ts +1 -1
- package/fs/asserts/module.f.js +4 -1
- package/fs/bnf/data/module.f.d.ts +0 -103
- package/fs/bnf/data/module.f.js +10 -246
- package/fs/bnf/data/proof.f.d.ts +0 -10
- package/fs/bnf/data/proof.f.js +2 -642
- package/fs/bnf/descent/module.f.d.ts +56 -0
- package/fs/bnf/descent/module.f.js +119 -0
- package/fs/bnf/descent/proof.f.d.ts +5 -0
- package/fs/bnf/descent/proof.f.js +296 -0
- package/fs/bnf/ll1/module.f.d.ts +72 -0
- package/fs/bnf/ll1/module.f.js +153 -0
- package/fs/bnf/ll1/proof.f.d.ts +9 -0
- package/fs/bnf/ll1/proof.f.js +358 -0
- package/fs/cas/cli/module.f.d.ts +6 -0
- package/fs/cas/cli/module.f.js +56 -0
- package/fs/cas/cli/proof.f.d.ts +14 -0
- package/fs/cas/cli/proof.f.js +149 -0
- package/fs/cas/mcp/module.f.d.ts +9 -17
- package/fs/cas/mcp/module.f.js +116 -84
- package/fs/cas/mcp/proof.f.d.ts +5 -1
- package/fs/cas/mcp/proof.f.js +74 -32
- package/fs/cas/module.f.d.ts +35 -15
- package/fs/cas/module.f.js +168 -131
- package/fs/cas/proof.f.d.ts +16 -13
- package/fs/cas/proof.f.js +255 -121
- package/fs/ci/config/module.f.d.ts +14 -14
- package/fs/ci/config/module.f.js +14 -14
- package/fs/djs/tokenizer-new/module.f.js +1 -1
- package/fs/djs/tokenizer-new/proof.f.d.ts +2 -0
- package/fs/djs/tokenizer-new/proof.f.js +357 -229
- package/fs/effects/list/module.f.d.ts +31 -0
- package/fs/effects/list/module.f.js +16 -0
- package/fs/effects/module.f.d.ts +11 -5
- package/fs/effects/module.f.js +16 -6
- package/fs/effects/node/module.f.d.ts +29 -3
- package/fs/effects/node/module.f.js +35 -1
- package/fs/effects/node/module.js +32 -18
- package/fs/effects/node/virtual/module.f.js +57 -0
- package/fs/effects/proof.f.d.ts +4 -0
- package/fs/effects/proof.f.js +18 -1
- package/fs/fjs/module.f.js +2 -8
- package/fs/html/module.f.js +6 -8
- package/fs/mcp/module.f.d.ts +1 -1
- package/fs/mime/module.f.d.ts +101 -5
- package/fs/mime/module.f.js +159 -6
- package/fs/mime/proof.f.d.ts +25 -0
- package/fs/mime/proof.f.js +193 -3
- package/fs/text/code_point/module.f.d.ts +39 -2
- package/fs/text/code_point/module.f.js +74 -2
- package/fs/text/code_point/proof.f.d.ts +8 -0
- package/fs/text/code_point/proof.f.js +72 -0
- package/fs/text/utf16/module.f.js +4 -26
- package/fs/text/utf8/module.f.d.ts +27 -0
- package/fs/text/utf8/module.f.js +8 -14
- package/fs/types/function/operator/module.f.d.ts +26 -0
- package/fs/types/list/module.f.d.ts +3 -0
- package/fs/types/result/module.d.ts +2 -4
- package/fs/types/result/module.js +9 -3
- package/package.json +3 -3
- package/issues/demo/data/data.f.js +0 -12
- package/issues/demo/data/shared.f.js +0 -3
- package/issues/demo/fs/app.js +0 -4
- package/issues/demo/fs/math.f.js +0 -4
- package/issues/demo/sample/proof.f.js +0 -13
- /package/{issues → todo}/031-json.f.d.ts +0 -0
- /package/{issues → todo}/031-json.f.js +0 -0
- /package/{issues → todo}/proof.f.d.ts +0 -0
- /package/{issues → todo}/proof.f.js +0 -0
package/fs/cas/proof.f.js
CHANGED
|
@@ -1,160 +1,294 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { length, maxLength, msb, vec, vec8 } from "../types/bit_vec/module.f.js";
|
|
2
|
+
import { cBase32ToVec, vecToCBase32 } from "../cbase32/module.f.js";
|
|
2
3
|
import { computeSync, sha256 } from "../crypto/sha2/module.f.js";
|
|
3
|
-
import {
|
|
4
|
+
import { fileCas, casAddFile, casUpload } from "./module.f.js";
|
|
4
5
|
import { pure } from "../effects/module.f.js";
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
|
|
10
|
-
const
|
|
6
|
+
import { mkdir, writeFile, rm, readFile, access } from "../effects/node/module.f.js";
|
|
7
|
+
import { error, ok } from "../types/result/module.f.js";
|
|
8
|
+
import { emptyState, virtual } from "../effects/node/virtual/module.f.js";
|
|
9
|
+
import { join } from "../path/module.f.js";
|
|
10
|
+
import { nonEmpty, empty } from "../effects/list/module.f.js";
|
|
11
|
+
const testDir = './test-cas-cli';
|
|
12
|
+
// Create a 128 KiB big file content (at the max Vec size limit)
|
|
13
|
+
// This tests the boundary where files are at the chunk size limit
|
|
14
|
+
const createBigFileContent = () => {
|
|
15
|
+
const byteCount = 128n * 1024n; // 128 KiB
|
|
16
|
+
// Create a repeating pattern: 0x42 repeated across the file
|
|
17
|
+
return vec(byteCount * 8n)(0x42424242n);
|
|
18
|
+
};
|
|
19
|
+
// Test adding a big file and verifying the hash
|
|
20
|
+
const testAddBigFile = () => mkdir(testDir, { recursive: true }).step(() => {
|
|
21
|
+
const bigContent = createBigFileContent();
|
|
22
|
+
const bigFilePath = `${testDir}/big-file.bin`;
|
|
23
|
+
return writeFile(bigFilePath, bigContent).step(writeRes => {
|
|
24
|
+
if (writeRes[0] === 'error') {
|
|
25
|
+
throw new Error(`Failed to write test file: ${writeRes[1]}`);
|
|
26
|
+
}
|
|
27
|
+
const cas = fileCas(sha256)(testDir);
|
|
28
|
+
return casAddFile(cas)(bigFilePath).step(addRes => {
|
|
29
|
+
if (addRes[0] === 'error') {
|
|
30
|
+
throw new Error(`Failed to add file to CAS: ${addRes[1]}`);
|
|
31
|
+
}
|
|
32
|
+
const hash = addRes[1];
|
|
33
|
+
// Verify hash is 256 bits (SHA-256)
|
|
34
|
+
if (length(hash) !== 256n) {
|
|
35
|
+
throw new Error(`Expected hash length 256 bits, got ${length(hash)}`);
|
|
36
|
+
}
|
|
37
|
+
// Verify hash can be encoded/decoded
|
|
38
|
+
const hashCBase32 = vecToCBase32(hash);
|
|
39
|
+
const decodedHash = cBase32ToVec(hashCBase32);
|
|
40
|
+
if (decodedHash === null) {
|
|
41
|
+
throw new Error('Failed to decode hash from base32');
|
|
42
|
+
}
|
|
43
|
+
return rm(testDir).step(() => pure(undefined));
|
|
44
|
+
});
|
|
45
|
+
});
|
|
46
|
+
});
|
|
47
|
+
// Test adding and retrieving a big file
|
|
48
|
+
const testAddAndGetBigFile = () => mkdir(testDir, { recursive: true })
|
|
49
|
+
.step(() => {
|
|
50
|
+
const bigContent = createBigFileContent();
|
|
51
|
+
const bigFilePath = `${testDir}/big-file.bin`;
|
|
52
|
+
return writeFile(bigFilePath, bigContent)
|
|
53
|
+
.step(writeRes => {
|
|
54
|
+
if (writeRes[0] === 'error') {
|
|
55
|
+
throw new Error(`Failed to write test file: ${writeRes[1]}`);
|
|
56
|
+
}
|
|
57
|
+
const cas = fileCas(sha256)(testDir);
|
|
58
|
+
return casAddFile(cas)(bigFilePath)
|
|
59
|
+
.step(addRes => {
|
|
60
|
+
if (addRes[0] === 'error') {
|
|
61
|
+
throw new Error(`Failed to add file to CAS: ${addRes[1]}`);
|
|
62
|
+
}
|
|
63
|
+
const hash = addRes[1];
|
|
64
|
+
const storedPath = cas.url(hash);
|
|
65
|
+
// Verify file is stored at the expected location
|
|
66
|
+
return readFile(storedPath).step(readRes => {
|
|
67
|
+
if (readRes[0] === 'error') {
|
|
68
|
+
throw new Error(`Failed to read stored file: ${readRes[1]}`);
|
|
69
|
+
}
|
|
70
|
+
const storedContent = readRes[1];
|
|
71
|
+
// Verify content is the same size as original
|
|
72
|
+
const storedLen = length(storedContent);
|
|
73
|
+
const originalLen = length(bigContent);
|
|
74
|
+
if (storedLen !== originalLen) {
|
|
75
|
+
throw new Error(`Content size mismatch: stored ${storedLen} bits, expected ${originalLen} bits`);
|
|
76
|
+
}
|
|
77
|
+
return rm(testDir).step(() => pure(undefined));
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
});
|
|
81
|
+
});
|
|
11
82
|
export const proof = {
|
|
12
|
-
|
|
83
|
+
addBigFile: testAddBigFile,
|
|
84
|
+
addAndGetBigFile: testAddAndGetBigFile,
|
|
85
|
+
//
|
|
86
|
+
casWriteRead: () => {
|
|
87
|
+
// Round-trip a single-chunk payload through the real streaming CAS: `write` returns
|
|
88
|
+
// the content hash, and `read` streams the same bytes back as `ok` chunk items.
|
|
13
89
|
const content = vec8(0x2an);
|
|
14
|
-
const
|
|
15
|
-
const
|
|
16
|
-
|
|
17
|
-
|
|
90
|
+
const c = fileCas(sha256)('.');
|
|
91
|
+
const payload = nonEmpty(ok(content), empty());
|
|
92
|
+
const [state1, writeResult] = virtual(emptyState)(c.write(payload));
|
|
93
|
+
if (writeResult[0] !== 'ok') {
|
|
94
|
+
throw ['expected write ok', writeResult];
|
|
18
95
|
}
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
},
|
|
23
|
-
mainAddWrongArgs: () => {
|
|
24
|
-
const [finalState, exitCode] = virtual(emptyState)(main(makeOptions(['add'])));
|
|
25
|
-
if (exitCode !== 1) {
|
|
26
|
-
throw ['expected exit 1', exitCode];
|
|
96
|
+
const hash = writeResult[1];
|
|
97
|
+
if (length(hash) !== 256n) {
|
|
98
|
+
throw ['expected 256-bit hash', length(hash)];
|
|
27
99
|
}
|
|
28
|
-
if (
|
|
29
|
-
throw '
|
|
100
|
+
if (msb.cmp(hash)(computeSync(sha256)([content])) !== 0) {
|
|
101
|
+
throw 'write hash mismatch';
|
|
30
102
|
}
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
103
|
+
const drain = (acc) => (stream) => stream.step((node) => {
|
|
104
|
+
if (node === undefined) {
|
|
105
|
+
return pure(ok(acc));
|
|
106
|
+
}
|
|
107
|
+
const { first, tail } = node;
|
|
108
|
+
if (first[0] === 'error') {
|
|
109
|
+
return pure(first);
|
|
110
|
+
}
|
|
111
|
+
return drain([...acc, first[1]])(tail);
|
|
112
|
+
});
|
|
113
|
+
const [, readResult] = virtual(state1)(drain([])(c.read(hash)));
|
|
114
|
+
if (readResult[0] !== 'ok') {
|
|
115
|
+
throw ['expected read ok', readResult];
|
|
38
116
|
}
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
if (exitCode2 !== 0) {
|
|
42
|
-
throw ['expected get exit 0', exitCode2];
|
|
117
|
+
if (msb.cmp(msb.listToVec(readResult[1]))(content) !== 0) {
|
|
118
|
+
throw 'read content mismatch';
|
|
43
119
|
}
|
|
44
120
|
},
|
|
45
|
-
|
|
46
|
-
//
|
|
47
|
-
const
|
|
48
|
-
const
|
|
49
|
-
const
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
const [finalState, exitCode] = virtual(emptyState)(main(makeOptions(['get', hashStr, 'output'])));
|
|
53
|
-
if (exitCode !== 1) {
|
|
54
|
-
throw ['expected exit 1', exitCode];
|
|
121
|
+
casReadMissingShard: () => {
|
|
122
|
+
// A missing shard surfaces as an explicit error *item*, never as end-of-stream.
|
|
123
|
+
const c = fileCas(sha256)('.');
|
|
124
|
+
const hash = computeSync(sha256)([vec8(0x2an)]);
|
|
125
|
+
const node = virtual(emptyState)(c.read(hash))[1];
|
|
126
|
+
if (node === undefined) {
|
|
127
|
+
throw 'missing shard must not be EOF';
|
|
55
128
|
}
|
|
56
|
-
if (
|
|
57
|
-
throw 'expected error
|
|
129
|
+
if (node.first[0] !== 'error') {
|
|
130
|
+
throw ['expected error item', node.tail];
|
|
58
131
|
}
|
|
59
132
|
},
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
133
|
+
casWriteMultiChunk: () => {
|
|
134
|
+
// A multi-chunk payload streams through `writeBytes` chunk-by-chunk (the lease is
|
|
135
|
+
// renewed between chunks); the hash equals the SHA-256 of the concatenated bytes,
|
|
136
|
+
// and read streams the same content back.
|
|
137
|
+
const chunks = [vec8(0x11n), vec8(0x22n), vec8(0x33n)];
|
|
138
|
+
const c = fileCas(sha256)('.');
|
|
139
|
+
const payload = chunks.reduceRight((tail, chunk) => nonEmpty(ok(chunk), tail), empty());
|
|
140
|
+
const [state1, writeResult] = virtual(emptyState)(c.write(payload));
|
|
141
|
+
if (writeResult[0] !== 'ok') {
|
|
142
|
+
throw ['expected write ok', writeResult];
|
|
64
143
|
}
|
|
65
|
-
|
|
66
|
-
|
|
144
|
+
const hash = writeResult[1];
|
|
145
|
+
if (msb.cmp(hash)(computeSync(sha256)(chunks)) !== 0) {
|
|
146
|
+
throw 'multi-chunk write hash mismatch';
|
|
67
147
|
}
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
148
|
+
const drain = (acc) => (stream) => stream.step((node) => {
|
|
149
|
+
if (node === undefined) {
|
|
150
|
+
return pure(ok(acc));
|
|
151
|
+
}
|
|
152
|
+
const { first, tail } = node;
|
|
153
|
+
if (first[0] === 'error') {
|
|
154
|
+
return pure(first);
|
|
155
|
+
}
|
|
156
|
+
return drain([...acc, first[1]])(tail);
|
|
157
|
+
});
|
|
158
|
+
const [, readResult] = virtual(state1)(drain([])(c.read(hash)));
|
|
159
|
+
if (readResult[0] !== 'ok') {
|
|
160
|
+
throw ['expected read ok', readResult];
|
|
73
161
|
}
|
|
74
|
-
|
|
75
|
-
|
|
162
|
+
const expected = msb.concat(msb.concat(chunks[0])(chunks[1]))(chunks[2]);
|
|
163
|
+
if (msb.cmp(msb.listToVec(readResult[1]))(expected) !== 0) {
|
|
164
|
+
throw 'multi-chunk read content mismatch';
|
|
76
165
|
}
|
|
77
166
|
},
|
|
78
|
-
|
|
167
|
+
casWriteDedup: () => {
|
|
168
|
+
// Same content ⇒ same hash; the second upload's replace-`rename` publishes over the
|
|
169
|
+
// first, leaving exactly one shard in the store.
|
|
79
170
|
const content = vec8(0x2an);
|
|
80
|
-
const
|
|
81
|
-
const
|
|
82
|
-
const [,
|
|
83
|
-
|
|
84
|
-
|
|
171
|
+
const c = fileCas(sha256)('.');
|
|
172
|
+
const payload = () => nonEmpty(ok(content), empty());
|
|
173
|
+
const [state1, w1] = virtual(emptyState)(c.write(payload()));
|
|
174
|
+
const [state2, w2] = virtual(state1)(c.write(payload()));
|
|
175
|
+
if (w1[0] !== 'ok' || w2[0] !== 'ok') {
|
|
176
|
+
throw ['expected both writes ok', w1, w2];
|
|
177
|
+
}
|
|
178
|
+
if (msb.cmp(w1[1])(w2[1]) !== 0) {
|
|
179
|
+
throw 'dedup hash mismatch';
|
|
180
|
+
}
|
|
181
|
+
const [, hashes] = virtual(state2)(c.list());
|
|
182
|
+
if (hashes.length !== 1) {
|
|
183
|
+
throw ['expected one shard after dedup', hashes.length];
|
|
85
184
|
}
|
|
86
185
|
},
|
|
87
|
-
|
|
88
|
-
//
|
|
89
|
-
//
|
|
90
|
-
const
|
|
91
|
-
|
|
92
|
-
|
|
186
|
+
casWriteErrorItemAborts: () => {
|
|
187
|
+
// An error item mid-stream deletes the partial staging file and fails; nothing is
|
|
188
|
+
// published, so the store stays empty.
|
|
189
|
+
const c = fileCas(sha256)('.');
|
|
190
|
+
const okItem = ok(vec8(0x11n));
|
|
191
|
+
const errItem = error({ code: 'BOOM' });
|
|
192
|
+
const payload = nonEmpty(okItem, nonEmpty(errItem, empty()));
|
|
193
|
+
const [state1, result] = virtual(emptyState)(c.write(payload));
|
|
194
|
+
if (result[0] !== 'error') {
|
|
195
|
+
throw ['expected write error', result];
|
|
93
196
|
}
|
|
94
|
-
|
|
95
|
-
|
|
197
|
+
const [, hashes] = virtual(state1)(c.list());
|
|
198
|
+
if (hashes.length !== 0) {
|
|
199
|
+
throw ['expected nothing published on abort', hashes];
|
|
96
200
|
}
|
|
97
201
|
},
|
|
98
|
-
|
|
99
|
-
//
|
|
100
|
-
//
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
202
|
+
casWriteReadExceedsMaxLength: () => {
|
|
203
|
+
// The point of streaming: a payload larger than a single `Vec`'s `maxLength`
|
|
204
|
+
// (128 KiB) must round-trip. `write` lands the chunks on disk without ever
|
|
205
|
+
// holding them as one `Vec`, and `read` streams them back the same way — so the
|
|
206
|
+
// round-trip is verified by hashing the read stream incrementally rather than
|
|
207
|
+
// concatenating it (which would itself overflow `maxLength`).
|
|
208
|
+
const big = vec(maxLength)(0xabn); // one full-size chunk: exactly maxLength bits
|
|
209
|
+
const tail = vec8(0x2an); // one more byte ⇒ total > maxLength
|
|
210
|
+
const chunks = [big, tail];
|
|
211
|
+
const c = fileCas(sha256)('.');
|
|
212
|
+
const payload = chunks.reduceRight((tl, chunk) => nonEmpty(ok(chunk), tl), empty());
|
|
213
|
+
const [state1, w] = virtual(emptyState)(c.write(payload));
|
|
214
|
+
if (w[0] !== 'ok') {
|
|
215
|
+
throw ['expected write ok', w];
|
|
216
|
+
}
|
|
217
|
+
const hash = w[1];
|
|
218
|
+
if (msb.cmp(hash)(computeSync(sha256)(chunks)) !== 0) {
|
|
219
|
+
throw 'oversized write hash mismatch';
|
|
105
220
|
}
|
|
106
|
-
|
|
107
|
-
|
|
221
|
+
// Fold the read stream straight into a fresh SHA-2 state — never one `Vec`.
|
|
222
|
+
const rehash = (state) => (stream) => stream.step((node) => {
|
|
223
|
+
if (node === undefined) {
|
|
224
|
+
return pure(ok(sha256.end(state)));
|
|
225
|
+
}
|
|
226
|
+
const { first, tail } = node;
|
|
227
|
+
if (first[0] === 'error') {
|
|
228
|
+
return pure(first);
|
|
229
|
+
}
|
|
230
|
+
return rehash(sha256.append(first[1])(state))(tail);
|
|
231
|
+
});
|
|
232
|
+
const [, readBack] = virtual(state1)(rehash(sha256.init)(c.read(hash)));
|
|
233
|
+
if (readBack[0] !== 'ok') {
|
|
234
|
+
throw ['expected read ok', readBack];
|
|
108
235
|
}
|
|
109
|
-
if (
|
|
110
|
-
throw '
|
|
236
|
+
if (msb.cmp(readBack[1])(hash) !== 0) {
|
|
237
|
+
throw 'oversized read-back hash mismatch';
|
|
111
238
|
}
|
|
112
239
|
},
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
240
|
+
casWriteGcReclaimsExpired: () => {
|
|
241
|
+
// A staging file whose deadline is in the past is reclaimed by the GC that `write`
|
|
242
|
+
// runs before staging its own file.
|
|
243
|
+
const stalePath = join('.', '.cas', '_stage', '0000000000000000000-stale');
|
|
244
|
+
const state0 = {
|
|
245
|
+
...emptyState,
|
|
246
|
+
epochNs: 1_000_000,
|
|
247
|
+
root: { '.cas': { '_stage': { '0000000000000000000-stale': [vec8(0x99n)] } } },
|
|
248
|
+
};
|
|
249
|
+
const content = vec8(0x2an);
|
|
250
|
+
const c = fileCas(sha256)('.');
|
|
251
|
+
const x = c.write(nonEmpty(ok(content), empty()));
|
|
252
|
+
const [state1, w] = virtual(state0)(x);
|
|
253
|
+
if (w[0] !== 'ok') {
|
|
254
|
+
throw ['expected write ok', w];
|
|
117
255
|
}
|
|
118
|
-
|
|
119
|
-
|
|
256
|
+
const [, present] = virtual(state1)(access(stalePath));
|
|
257
|
+
if (present[0] !== 'error') {
|
|
258
|
+
throw 'expected GC to reclaim the expired staging file';
|
|
120
259
|
}
|
|
121
260
|
},
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
261
|
+
casUploadSuccess: () => {
|
|
262
|
+
// A successful upload returns the hash and deletes the source file from cas_upload/.
|
|
263
|
+
const content = vec8(0x2an);
|
|
264
|
+
const state0 = { ...emptyState, root: { 'cas_upload': { 'myfile': [content] } } };
|
|
265
|
+
const [state1, result] = virtual(state0)(casUpload('.')('myfile'));
|
|
266
|
+
if (result[0] !== 'ok') {
|
|
267
|
+
throw ['expected casUpload ok', result];
|
|
126
268
|
}
|
|
127
|
-
if (
|
|
128
|
-
throw 'expected
|
|
269
|
+
if (length(result[1]) !== 256n) {
|
|
270
|
+
throw ['expected 256-bit hash', length(result[1])];
|
|
129
271
|
}
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
const
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
list: () => pure([]),
|
|
136
|
-
};
|
|
137
|
-
const [, hash] = run({})(undefined)(c.write(empty));
|
|
138
|
-
// sha256 of empty input produces a 256-bit hash
|
|
139
|
-
assert(hash !== undefined);
|
|
140
|
-
if (length(hash) !== 256n) {
|
|
141
|
-
throw ['expected 256-bit hash', length(hash)];
|
|
272
|
+
// Source must be deleted after successful publish.
|
|
273
|
+
const srcPath = join('.', 'cas_upload', 'myfile');
|
|
274
|
+
const [, srcAccess] = virtual(state1)(access(srcPath));
|
|
275
|
+
if (srcAccess[0] !== 'error') {
|
|
276
|
+
throw 'expected source to be deleted after successful upload';
|
|
142
277
|
}
|
|
143
278
|
},
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
const [, readResult] = run({})(undefined)(c.read(empty));
|
|
152
|
-
if (readResult !== stored) {
|
|
153
|
-
throw ['read should pass through', readResult];
|
|
279
|
+
casUploadFailureKeepsSource: () => {
|
|
280
|
+
// A missing source file causes write to fail; casUpload returns error and the
|
|
281
|
+
// source is left in place (trivially: it was never there, but the upload is not published).
|
|
282
|
+
const state0 = { ...emptyState, root: {} };
|
|
283
|
+
const [state1, result] = virtual(state0)(casUpload('.')('nonexistent'));
|
|
284
|
+
if (result[0] !== 'error') {
|
|
285
|
+
throw ['expected casUpload to fail on missing source', result];
|
|
154
286
|
}
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
287
|
+
// Nothing published to the store.
|
|
288
|
+
const c = fileCas(sha256)('.');
|
|
289
|
+
const [, hashes] = virtual(state1)(c.list());
|
|
290
|
+
if (hashes.length !== 0) {
|
|
291
|
+
throw ['expected nothing published on failed upload', hashes];
|
|
158
292
|
}
|
|
159
293
|
},
|
|
160
294
|
};
|
|
@@ -7,8 +7,8 @@
|
|
|
7
7
|
*/
|
|
8
8
|
export declare const images: {
|
|
9
9
|
readonly ubuntu: {
|
|
10
|
-
readonly intel: "ubuntu-
|
|
11
|
-
readonly arm: "ubuntu-
|
|
10
|
+
readonly intel: "ubuntu-26.04";
|
|
11
|
+
readonly arm: "ubuntu-26.04-arm";
|
|
12
12
|
};
|
|
13
13
|
readonly macos: {
|
|
14
14
|
readonly intel: "macos-26-intel";
|
|
@@ -19,24 +19,24 @@ export declare const images: {
|
|
|
19
19
|
readonly arm: "windows-11-arm";
|
|
20
20
|
};
|
|
21
21
|
};
|
|
22
|
-
export declare const functionalscript: "0.
|
|
22
|
+
export declare const functionalscript: "0.33.0";
|
|
23
23
|
export declare const bun = "1.3.14";
|
|
24
|
-
export declare const deno = "2.
|
|
25
|
-
export declare const playwright = "1.61.
|
|
24
|
+
export declare const deno = "2.9.0";
|
|
25
|
+
export declare const playwright = "1.61.1";
|
|
26
26
|
export declare const node: {
|
|
27
|
-
readonly default: "26.
|
|
28
|
-
readonly node22: "22.23.
|
|
29
|
-
readonly node24: "24.
|
|
27
|
+
readonly default: "26.4.0";
|
|
28
|
+
readonly node22: "22.23.1";
|
|
29
|
+
readonly node24: "24.18.0";
|
|
30
30
|
};
|
|
31
|
-
export declare const wasmtime = "
|
|
31
|
+
export declare const wasmtime = "46.0.1";
|
|
32
32
|
export declare const wasmer = "7.1.0";
|
|
33
|
-
export declare const tsgo = "7.0.0-dev.
|
|
33
|
+
export declare const tsgo = "7.0.0-dev.20260627.2";
|
|
34
34
|
export declare const actions: {
|
|
35
35
|
readonly 'actions/checkout': "v7";
|
|
36
|
-
readonly 'actions/setup-node': "v6";
|
|
37
|
-
readonly 'actions/cache': "
|
|
38
|
-
readonly 'denoland/setup-deno': "v2";
|
|
39
|
-
readonly 'oven-sh/setup-bun': "v2";
|
|
36
|
+
readonly 'actions/setup-node': "v6.4.0";
|
|
37
|
+
readonly 'actions/cache': "v6.1.0";
|
|
38
|
+
readonly 'denoland/setup-deno': "v2.0.4";
|
|
39
|
+
readonly 'oven-sh/setup-bun': "v2.2.0";
|
|
40
40
|
readonly 'bytecodealliance/actions/wasmtime/setup': "v1";
|
|
41
41
|
readonly 'wasmerio/setup-wasmer': "v3.1";
|
|
42
42
|
readonly 'dtolnay/rust-toolchain': "1.96.0";
|
package/fs/ci/config/module.f.js
CHANGED
|
@@ -8,8 +8,8 @@
|
|
|
8
8
|
// https://docs.github.com/en/actions/reference/runners/github-hosted-runners#standard-github-hosted-runners-for-public-repositories
|
|
9
9
|
export const images = {
|
|
10
10
|
ubuntu: {
|
|
11
|
-
intel: 'ubuntu-
|
|
12
|
-
arm: 'ubuntu-
|
|
11
|
+
intel: 'ubuntu-26.04',
|
|
12
|
+
arm: 'ubuntu-26.04-arm'
|
|
13
13
|
},
|
|
14
14
|
macos: {
|
|
15
15
|
intel: 'macos-26-intel',
|
|
@@ -24,25 +24,25 @@ export const images = {
|
|
|
24
24
|
// published FunctionalScript release; do not tie it to package.json's current
|
|
25
25
|
// in-repo version. A separate maintenance job advances this pin.
|
|
26
26
|
// https://www.npmjs.com/package/functionalscript
|
|
27
|
-
export const functionalscript = '0.
|
|
27
|
+
export const functionalscript = '0.33.0';
|
|
28
28
|
// https://bun.sh/
|
|
29
29
|
export const bun = '1.3.14';
|
|
30
30
|
// https://deno.com/
|
|
31
|
-
export const deno = '2.
|
|
31
|
+
export const deno = '2.9.0';
|
|
32
32
|
// https://www.npmjs.com/package/playwright
|
|
33
|
-
export const playwright = '1.61.
|
|
33
|
+
export const playwright = '1.61.1';
|
|
34
34
|
// https://nodejs.org/en/download
|
|
35
35
|
export const node = {
|
|
36
|
-
default: '26.
|
|
37
|
-
node22: '22.23.
|
|
38
|
-
node24: '24.
|
|
36
|
+
default: '26.4.0',
|
|
37
|
+
node22: '22.23.1',
|
|
38
|
+
node24: '24.18.0',
|
|
39
39
|
};
|
|
40
40
|
// https://github.com/bytecodealliance/wasmtime/releases
|
|
41
|
-
export const wasmtime = '
|
|
41
|
+
export const wasmtime = '46.0.1';
|
|
42
42
|
// https://github.com/wasmerio/wasmer/releases
|
|
43
43
|
export const wasmer = '7.1.0';
|
|
44
44
|
// https://www.npmjs.com/package/@typescript/native-preview?activeTab=versions
|
|
45
|
-
export const tsgo = '7.0.0-dev.
|
|
45
|
+
export const tsgo = '7.0.0-dev.20260627.2';
|
|
46
46
|
// GitHub Action versions used by CI step builders. The key is the action
|
|
47
47
|
// `owner/name`; call sites compose the full ref as
|
|
48
48
|
// `` `${name}@${actions[name]}` ``.
|
|
@@ -51,13 +51,13 @@ export const actions = {
|
|
|
51
51
|
// https://github.com/marketplace/actions/checkout
|
|
52
52
|
'actions/checkout': 'v7',
|
|
53
53
|
// https://github.com/marketplace/actions/setup-node-js-environment
|
|
54
|
-
'actions/setup-node': 'v6',
|
|
54
|
+
'actions/setup-node': 'v6.4.0',
|
|
55
55
|
// https://github.com/marketplace/actions/cache
|
|
56
|
-
'actions/cache': '
|
|
56
|
+
'actions/cache': 'v6.1.0',
|
|
57
57
|
// https://github.com/marketplace/actions/setup-deno
|
|
58
|
-
'denoland/setup-deno': 'v2',
|
|
58
|
+
'denoland/setup-deno': 'v2.0.4',
|
|
59
59
|
// https://github.com/marketplace/actions/setup-bun
|
|
60
|
-
'oven-sh/setup-bun': 'v2',
|
|
60
|
+
'oven-sh/setup-bun': 'v2.2.0',
|
|
61
61
|
// https://github.com/bytecodealliance/actions
|
|
62
62
|
'bytecodealliance/actions/wasmtime/setup': 'v1',
|
|
63
63
|
// https://github.com/wasmerio/setup-wasmer
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* @module
|
|
5
5
|
*/
|
|
6
|
-
import { descentParser } from "../../bnf/
|
|
6
|
+
import { descentParser } from "../../bnf/descent/module.f.js";
|
|
7
7
|
import { eof, join0Plus, max, none, not, notSet, oneEncode, option, range, remove, repeat, repeat0Plus, repeat1Plus, set, unicodeRange } from "../../bnf/module.f.js";
|
|
8
8
|
import { todo } from "../../asserts/module.f.js";
|
|
9
9
|
export const parse = (input) => {
|