Inspector page: static SvelteKit site with /inspect (plan step 5)
A prerendered static site (adapter-static) with a landing page and
/inspect, which runs spec §63 steps 1 to 8 on a .dkc chosen with the file
picker, dropped anywhere on the page, or taken from the official fixtures
bundled at build time. It shows every step, the decoded header, the unlock
date in UTC and local time, and each extension's id, version, criticality,
length and hex, with a text view and an informative CBOR diagnostic view,
all escaped and labelled as unauthenticated before step 15. Copiar JSON
copies the exact "datekeys inspect -json" view.
No network: a hash-mode Content-Security-Policy with connect-src 'self'
is the first element of every page, and scripts/check-build.mjs verifies
it, the fixtures and the absence of external URLs after every build.
Large files are read only up to what steps 1 to 8 need.
Reviewed for design and accessibility (WCAG AA contrast, keyboard,
focus, live status, 360 px), security and correctness; 262 tests pass,
svelte-check has no warnings.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2 weeks ago
|
|
|
// The tests of src/lib. Vitest prefers this file to vite.config.ts, the
|
|
|
|
|
// SvelteKit configuration of the page, so the library tests run without the
|
|
|
|
|
// SvelteKit plugin; the page helpers in src/lib/inspector import the library
|
|
|
|
|
// by relative paths and need no $lib alias.
|
TypeScript implementation of DateKeys v0.8.2, steps 1 to 8
Canonical CBOR codec of the spec §58 profile, hand-written schema codecs
(profile, PUBLIC_HEADER, CONTROL_CBOR, .dkk, extensions), DKC1/DKK1
framing, a strict age header parser, dk1_ parsing and nanosecond date to
round resolution, and inspect (spec §63 steps 1 to 8) with the same checks
and view as "datekeys inspect -json". No runtime dependencies.
216 tests, cbor.ts at 100 % coverage, typecheck of the library without
Node types. A differential comparison with the Go reference at afb44a3
found no verdict, code or step disagreement in about 336,000 inputs. The
harness for the future Go vector files runs them when they appear.
vite 8.3.0 is declared explicitly: it is a required peer of vitest 5.0.1
that legacy-peer-deps does not install.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2 weeks ago
|
|
|
import { defineConfig } from 'vitest/config';
|
|
|
|
|
|
|
|
|
|
export default defineConfig({
|
|
|
|
|
test: {
|
|
|
|
|
include: ['src/**/*.test.ts'],
|
|
|
|
|
// BLS12-381 point checks and the 65 536-extension cases take a moment.
|
|
|
|
|
testTimeout: 30_000,
|
|
|
|
|
coverage: {
|
|
|
|
|
provider: 'v8',
|
Inspector page: static SvelteKit site with /inspect (plan step 5)
A prerendered static site (adapter-static) with a landing page and
/inspect, which runs spec §63 steps 1 to 8 on a .dkc chosen with the file
picker, dropped anywhere on the page, or taken from the official fixtures
bundled at build time. It shows every step, the decoded header, the unlock
date in UTC and local time, and each extension's id, version, criticality,
length and hex, with a text view and an informative CBOR diagnostic view,
all escaped and labelled as unauthenticated before step 15. Copiar JSON
copies the exact "datekeys inspect -json" view.
No network: a hash-mode Content-Security-Policy with connect-src 'self'
is the first element of every page, and scripts/check-build.mjs verifies
it, the fixtures and the absence of external URLs after every build.
Large files are read only up to what steps 1 to 8 need.
Reviewed for design and accessibility (WCAG AA contrast, keyboard,
focus, live status, 360 px), security and correctness; 262 tests pass,
svelte-check has no warnings.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2 weeks ago
|
|
|
include: ['src/lib/dkc/**/*.ts', 'src/lib/inspector/**/*.ts'],
|
|
|
|
|
exclude: ['src/lib/**/*.test.ts', 'src/lib/dkc/testing/**', 'src/lib/dkc/index.ts'],
|
TypeScript implementation of DateKeys v0.8.2, steps 1 to 8
Canonical CBOR codec of the spec §58 profile, hand-written schema codecs
(profile, PUBLIC_HEADER, CONTROL_CBOR, .dkk, extensions), DKC1/DKK1
framing, a strict age header parser, dk1_ parsing and nanosecond date to
round resolution, and inspect (spec §63 steps 1 to 8) with the same checks
and view as "datekeys inspect -json". No runtime dependencies.
216 tests, cbor.ts at 100 % coverage, typecheck of the library without
Node types. A differential comparison with the Go reference at afb44a3
found no verdict, code or step disagreement in about 336,000 inputs. The
harness for the future Go vector files runs them when they appear.
vite 8.3.0 is declared explicitly: it is a required peer of vitest 5.0.1
that legacy-peer-deps does not install.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2 weeks ago
|
|
|
reporter: ['text', 'html', 'json-summary'],
|
|
|
|
|
thresholds: {
|
Phase 2, step 4: local release verification
src/lib/dkc/release.ts is provider.Verify of the Go reference (spec §17,
§51, §63 step 10), in its order and with its texts:
- the round within the profile (ERR_DATEKEY_INVALID);
- the round of the release before the signature (ERR_ROUND_MISMATCH);
- the length of the signature;
- the pinned public key (ERR_UNKNOWN_PROFILE when it does not decode;
the point at infinity fails the verification, as with kyber);
- the signature (ERR_RELEASE_INVALID): the canonical encoding of a point
of G1 other than the point at infinity, gated by bls12381.ts, that
verifies on @noble/curves 2.4.0 as the BLS signature of
SHA-256(uint64be(round)), hashed with the RFC 9380 DST of G1.
Nothing noble throws becomes anything but ERR_RELEASE_INVALID, and no
text of noble is copied. Only Quicknet's scheme is verified (plan
decision 3): another scheme fails with ERR_UNKNOWN_PROFILE after the
round checks. It also defines ReleaseSource, with the contract for
network sources and correction 6, and suppliedRelease, the release that
the caller hands over (unverified, so step 10 checks it). index.ts does
not re-export it yet.
release.test.ts:
- replays TestVerifyRejects of the reference, with exact texts;
- accepts the published releases of rounds 1000, 1001, 2000 and 1004
(the last one recovered from the x + p encoding of the corpus, which
shows that encoding is the published signature re-encoded);
- shows the DST of G2, the one bls-unchained-on-g1 uses, fails;
- gives the code of each of the 7 corpus cases that fail at step 10,
with the round that inspect reads from the capsule.
ibe.failure.test.ts becomes noble.failure.test.ts and also fails noble's
BLS verification. Coverage of release.ts is 100 % and is now a
threshold. The site does not change.
npm run verify is green: 2,404 tests.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 week ago
|
|
|
// The codec is covered completely (plan §7), and so are the IBE and
|
|
|
|
|
// the release verification (plan of phase 2, section 10, steps 3
|
|
|
|
|
// and 4).
|
TypeScript implementation of DateKeys v0.8.2, steps 1 to 8
Canonical CBOR codec of the spec §58 profile, hand-written schema codecs
(profile, PUBLIC_HEADER, CONTROL_CBOR, .dkk, extensions), DKC1/DKK1
framing, a strict age header parser, dk1_ parsing and nanosecond date to
round resolution, and inspect (spec §63 steps 1 to 8) with the same checks
and view as "datekeys inspect -json". No runtime dependencies.
216 tests, cbor.ts at 100 % coverage, typecheck of the library without
Node types. A differential comparison with the Go reference at afb44a3
found no verdict, code or step disagreement in about 336,000 inputs. The
harness for the future Go vector files runs them when they appear.
vite 8.3.0 is declared explicitly: it is a required peer of vitest 5.0.1
that legacy-peer-deps does not install.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2 weeks ago
|
|
|
'src/lib/dkc/cbor.ts': { 100: true },
|
Phase 2, step 3: the tlock IBE on noble 2, checked against Go
src/lib/dkc/ibe.ts is DecryptCCAonG2 of drand/kyber encrypt/ibe, the
decryption of tlock.TimeUnlock for Quicknet, on @noble/curves 2.4.0
(plan of phase 2, section 4). It adds nothing that kyber would reject:
- the signature and U pass the canonical-encoding gate of bls12381.ts,
which rejects the point at infinity too;
- H2 hashes GT in the order of kilic, never with noble's Fp12.toBytes;
- H3 and H4 follow kyber, including the rejection sampling of r, and
r = 0 never proves;
- roundIdentity is drand's DigestBeacon;
- the stanza body is exactly U || V || W, 128 bytes, as in tlock.
Errors are IbeError with a fixed reason (length, encoding, identity,
proof) and message: none carries sigma, the message, r or input bytes.
Anything noble throws past the gate is a proof failure. sigma and the
hashes derived from it are wiped on every path. The file keeps the MIT
notice of tlock-js, whose structure it follows. index.ts does not
re-export it yet; the opening of step 5 will use it.
scripts/ibe-go-vectors.go writes src/lib/dkc/testing/ibe-vectors.json
with kyber, tlock and age:
- the GT of e(G1, G2) and of its square, with H2;
- H3, including inputs accepted at the second and third iteration, and
H4;
- round identities;
- for the tlock stanza of every official fixture, the pairing, sigma, r
and the file key. tlock.TimeUnlock unwraps that file key, and age
opens OUTER_TIME_AGE with it;
- messages of 0, 1, 16 and 32 bytes encrypted by EncryptCCAonG2;
- kyber's verdict on eleven edited copies of the time_only stanza.
It restates the unexported H2, H3 and H4 and checks them on every
fixture against tlock and U = r·G2.
ibe.test.ts replays every vector and opens OUTER_TIME_AGE of each
fixture through age-encryption with a custom Identity: the header MAC
and STREAM verify, and a time_only fixture yields its control_cbor. It
also gates all 157 BLS edge encodings as the Go reference decodes them
and checks the fixed error texts. ibe.failure.test.ts mocks a noble
failure. Coverage of ibe.ts is 100 % and is now a threshold. The site
does not change.
npm run verify is green: 2,397 tests.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 week ago
|
|
|
'src/lib/dkc/ibe.ts': { 100: true },
|
Phase 2, step 4: local release verification
src/lib/dkc/release.ts is provider.Verify of the Go reference (spec §17,
§51, §63 step 10), in its order and with its texts:
- the round within the profile (ERR_DATEKEY_INVALID);
- the round of the release before the signature (ERR_ROUND_MISMATCH);
- the length of the signature;
- the pinned public key (ERR_UNKNOWN_PROFILE when it does not decode;
the point at infinity fails the verification, as with kyber);
- the signature (ERR_RELEASE_INVALID): the canonical encoding of a point
of G1 other than the point at infinity, gated by bls12381.ts, that
verifies on @noble/curves 2.4.0 as the BLS signature of
SHA-256(uint64be(round)), hashed with the RFC 9380 DST of G1.
Nothing noble throws becomes anything but ERR_RELEASE_INVALID, and no
text of noble is copied. Only Quicknet's scheme is verified (plan
decision 3): another scheme fails with ERR_UNKNOWN_PROFILE after the
round checks. It also defines ReleaseSource, with the contract for
network sources and correction 6, and suppliedRelease, the release that
the caller hands over (unverified, so step 10 checks it). index.ts does
not re-export it yet.
release.test.ts:
- replays TestVerifyRejects of the reference, with exact texts;
- accepts the published releases of rounds 1000, 1001, 2000 and 1004
(the last one recovered from the x + p encoding of the corpus, which
shows that encoding is the published signature re-encoded);
- shows the DST of G2, the one bls-unchained-on-g1 uses, fails;
- gives the code of each of the 7 corpus cases that fail at step 10,
with the round that inspect reads from the capsule.
ibe.failure.test.ts becomes noble.failure.test.ts and also fails noble's
BLS verification. Coverage of release.ts is 100 % and is now a
threshold. The site does not change.
npm run verify is green: 2,404 tests.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 week ago
|
|
|
'src/lib/dkc/release.ts': { 100: true },
|
Specification 0.15: the release object, a release in hand and step 9.c
- SPEC_VERSION 0.15, version 0.4.0-dev; testdata synced from datekeys-go
at 3c3e737 (v0.15), which adds vectors/release.json and releases/ and
the field source of mutations.json.
- releaseobject.ts, without noble, as provider/release.go and archive.go
of Go: encodeRelease, decodeRelease with the layers of step 10 (size of
1 to 1024 bytes, type and version, schema), parseRelease, which reads
drand's JSON as encoding/json does, the ReleaseSupplier of a release in
hand (encodedRelease) and ReleaseArchive, the informative local archive,
whose failures are ERR_RELEASE_UNAVAILABLE; all with Go's texts.
- verifyRelease compares the chain hash a release names with the pinned
profile first (ERR_PROFILE_MISMATCH).
- open takes OpenOptions.release, exclusive with source: it is not compared
with the clock (step 9.c, option B), Opened.clockBehind reports a clock
behind it, and it is decoded at step 10; a network source is still never
asked before the round time. The verified release carries the chain hash
of the pinned profile.
- vectors.test.ts runs release.json and every file of releases/, and the
mutation corpus with the source of each case, as testkit's singleSource;
scripts/mutation-go-texts.go does the same, and testing/mutation-texts.json
is regenerated: the spec field, "round not reached yet" now ok, and the
four new cases.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
23 hours ago
|
|
|
'src/lib/dkc/releaseobject.ts': { 100: true },
|
Phase 2, step 5a: open capsules, steps 9 to 18, in memory
src/lib/dkc/open.ts runs steps 9 to 18 of spec §63 on top of the steps
1 to 8 of inspectWith. It follows capsule.Open of the Go reference, with
its checks, codes and texts:
- step 9: the access credentials (the .dkk as an object, then its
capsule_id and capsule_digest), then the release, never before the
round time. Any failure of the source is ERR_RELEASE_UNAVAILABLE
alone, keeping its text and its cause (correction 6);
- step 10: verifyRelease;
- steps 11 to 13: OUTER_TIME_AGE, the structure against access_policy
and INNER_ACCESS_AGE;
- steps 14 to 18: CONTROL_CBOR, header_binding, I_PAYLOAD, PAYLOAD_AGE
and the commit.
The three age files open with the Decrypter of age-encryption and
identities that apply the rules of Go's agewrap: the tlock identity on
ibe.ts, and the access and payload identities on x25519.ts. A failure of
age that no identity reports is ERR_INTEGRITY with the fixed reason of
its phase, header or STREAM, never the text of age-encryption. The
plaintext is decrypted in memory and returned only after step 18.
Streaming to OPFS is step 5b.
src/lib/dkc/x25519.ts opens one age X25519 stanza at a time, in the
order of age's X25519Identity. Step 13 must try every identity on every
stanza (spec §36), and age-encryption's Decrypter stops at the first.
Its primitives are the ones age-encryption uses: X25519 and HKDF from
noble curves and hashes, and ChaCha20-Poly1305 from @noble/ciphers
2.4.0. The author approved declaring that package as a direct
dependency on 2026-09-28; it is the copy already installed and bundled.
The guards now allow ciphers, and x25519.ts in the noble allowlist.
src/lib/dkc/bech32.ts ports age's internal/bech32, with its MIT notice,
to read AGE-SECRET-KEY-1 identities.
Tests:
- vectors.test.ts runs all 65 cases of the mutation corpus through open.
Each gives the code and the step of Go, and no case that fails without
the network requests a release. This includes the 34 cases of steps 9
to 18 that were skipped, so the suite no longer skips any test.
- open.test.ts:
- the five official fixtures open to their plaintext, with each
credential, with the checks and details of the reference;
- the unusable noncritical extensions are reported;
- the source failures and the clock;
- age failures by phase;
- CONTROL_CBOR that does not decode, and a low-order share in
INNER_ACCESS_AGE, through an OUTER_TIME_AGE resealed with the FK_TIME
of the Go vectors;
- the texts of the identities.
- x25519.test.ts checks against age-encryption both ways and against the
Go-written stanzas of the fixtures, and covers every low-order share.
- bech32.test.ts has the vectors of the reference.
x25519.ts and bech32.ts are at 100 % coverage, now thresholds. open.ts
is at 100 % of lines; the one branch left is the one for an error that
is not a DateKeysError.
index.ts does not re-export the opening yet. The page imports index.ts,
and re-exporting would pull noble into /inspect (58.7 to 84.9 KB gzip)
even unused; step 8 will load it on demand. The site does not change.
npm run verify is green: 2,490 tests.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 week ago
|
|
|
// The stanza X25519 and its Bech32 identities (step 5).
|
|
|
|
|
'src/lib/dkc/x25519.ts': { 100: true },
|
|
|
|
|
'src/lib/dkc/bech32.ts': { 100: true },
|
Phase 2, step 5b: open from a Blob, streaming to an output
open(dkc, opts) now takes a Uint8Array or a Blob, such as a File.
- Of a Blob it reads only the prefix that steps 1 to 8 need.
inspectedLength and readCapsule move from src/lib/inspector/load.ts to
src/lib/dkc/prefix.ts, and the page imports them from the library.
- The .dkk capsule_digest is computed over the Blob's stream with the
new src/lib/dkc/digest.ts, an incremental SHA-256 on @noble/hashes,
since Web Crypto hashes whole buffers only. digest.ts joins the noble
allowlist of the guards.
- PAYLOAD_AGE is decrypted in streaming.
The plaintext goes to memory, as before, or to opts.output, a
WritableStream. The output is written as age authenticates each chunk,
closed only after step 18, and aborted after any failure at any step,
even before step 17 (spec §56). A failure of the output is ERR_INTEGRITY
with its text, as Go keeps the error of the writer of the plaintext.
Tests:
- the fixtures from Blobs, to memory and to an output;
- a truncated two-chunk payload whose first chunk reached the output
before the abort;
- early failures that never write;
- write and close failures, and an abort that fails;
- a .dkk without capsule_digest;
- the whole mutation corpus again as Blobs into an output, aborted in
every case;
- digest.ts against Web Crypto.
Coverage of digest.ts is 100 % and a threshold.
Checked in the browser (dev server, real OPFS). time_only.dkc, two
STREAM chunks, opened from a Blob into FileSystemFileHandle.createWritable
gives 78,000 bytes with the SHA-256 of its sidecar. The same file
truncated fails at step 17, and the OPFS file keeps its previous
content. The quota check, the temporary file and the download belong to
the page, in step 8.
npm run verify is green: 2,560 tests. The site does not change.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 week ago
|
|
|
'src/lib/dkc/digest.ts': { 100: true },
|
Phase 2, step 7: tlock encryption, checked against Go both ways
- ibe.ts gains encryptOnG2RFC9380, EncryptCCAonG2 of kyber with the
suite of tlock for Quicknet. Qid is H(id) on G1 with the RFC 9380 DST,
sigma comes from crypto.getRandomValues, U = r·G2, V = sigma XOR
H2(e(Qid, key)^r) and W = msg XOR H4(sigma). The key passes the
canonical gate, and sigma and the masks are wiped. encryptOnG2WithSigma
takes a given sigma, for the vectors only; index.ts exports neither.
- tlock.ts adds timeRecipient, the age-encryption Recipient of
OUTER_TIME_AGE, as Go's agewrap.TimeRecipient. It writes the stanza
"tlock <round> <chain hash>" with the checks and texts of
NewTimeRecipient: the scheme and the pinned key, then the round range.
age-encryption has no labels, so the writer of phase 3 adds it alone.
Vectors, in src/lib/dkc/testing/tlock-vectors.json from
scripts/tlock-go-vectors.go:
- Fixed-sigma encryptions of 1, 16 and 32 bytes for rounds 1000 and
1001. Go restates EncryptCCAonG2, since kyber draws sigma itself, and
checks the restatement with ibe.DecryptCCAonG2 and tlock.TimeUnlock.
encryptOnG2WithSigma reproduces them byte for byte.
- The samples of scripts/tlock-ts-samples.mjs, which Node runs on the
TypeScript sources: IBE bodies and age files that this library made
for rounds 1000 and 1001. Go opened every one: the bodies with
tlock.TimeUnlock and the age files with age.Decrypt and
agewrap.NewTimeIdentity, the identity of step 11. It got the same
file keys and plaintexts, and the samples are frozen with those
verdicts.
tlock.test.ts replays both blocks, the random round trip, the
rejections with their texts, and an age file sealed with timeRecipient
and opened with the step-11 identity of open.ts. Coverage of ibe.ts and
tlock.ts is 100 %, now a threshold for tlock.ts too. Step 6 of the plan
is recorded as done: the canonicality amendment is in spec-v0.8.2.
npm run verify is green: 2,567 tests. The site does not change.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 week ago
|
|
|
// The tlock recipient (step 7).
|
|
|
|
|
'src/lib/dkc/tlock.ts': { 100: true },
|
Phase 2, step 8: the open action of /inspect
After steps 1 to 8, a valid capsule whose date has passed on the device
clock can be opened in the page: steps 9 to 18 of spec section 63 with
open, loaded on demand with a dynamic import (opener.ts), so noble and
age-encryption stay out of the first load of every page.
- The release is supplied directly by the person (spec 63, step 10):
drand's JSON answer or the bare signature, pasted after opening the
drand URL the page links to, or the release in the record of an
official fixture. The page never fetches it and reads only its round
and signature (spec 11, 13). The CSP is unchanged.
- time_and_key credentials: a .dkk (readAccessKey reads at most
12 bytes + 16 MiB + 1) or age identities, one per line.
- The plaintext of the person's own file goes to a temporary OPFS file
(tempfile.ts), committed only after step 18 (spec 56), offered for
download and deleted on request, with another capsule, on pagehide
and, if left over, on the next visit. One directory and one Web Lock
per tab keep other tabs' clean-up away from files in use. Without
OPFS, or when the browser refuses it, capsules up to 64 MiB open in
memory. An opening in progress stops when another capsule is loaded.
- opening.ts builds the page model of steps 9 to 18 as the reference
records them; fixtures show their plaintext and compare its SHA-256
with their record.
- licenses.txt: the notices of tlock-js (ibe.ts) and age (bech32.ts),
the license of every package in the client bundle, Vite's and
rolldown's runtime code, and the site's own license. check-build now
fails if a notice is missing, or if a page loads noble, @scure/base
or age-encryption with its first load.
- The home page no longer says that the page never asks for keys.
Checked in the browser on the production build: the time_only,
time_and_key_portable (with its .dkk) and time_and_key_recipients (with
a pasted identity) fixtures open with the SHA-256 of their records; a
tampered signature fails at step 10 and a tampered STREAM chunk at step
17, with no download and no file left; an own file opens to OPFS,
downloads without a CSP violation and is deleted with its lock; a left
over directory goes on the next visit; no request leaves the origin.
An adversarial review (four dimensions, each finding checked by a
refuter) confirmed 15 findings, all fixed here.
2611 tests; coverage 100 % of the new modules, now a threshold.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 week ago
|
|
|
// The prefix reads, and the opening of the page (step 8).
|
|
|
|
|
'src/lib/dkc/prefix.ts': { 100: true },
|
|
|
|
|
'src/lib/inspector/fixtures.ts': { 100: true },
|
|
|
|
|
'src/lib/inspector/opener.ts': { 100: true },
|
|
|
|
|
'src/lib/inspector/opening.ts': { 100: true },
|
|
|
|
|
'src/lib/inspector/release-input.ts': { 100: true },
|
|
|
|
|
'src/lib/inspector/tempfile.ts': { 100: true },
|
|
|
|
|
// The pieces of the writer (plan of phase 3, step 2) and the age
|
|
|
|
|
// files shared by the opening and the writer.
|
|
|
|
|
'src/lib/dkc/recipient.ts': { 100: true },
|
|
|
|
|
'src/lib/dkc/random.ts': { 100: true },
|
|
|
|
|
'src/lib/dkc/agefile.ts': { 100: true },
|
|
|
|
|
'src/lib/dkc/padding.ts': { 100: true },
|
Phase 3, steps 3 and 4: the writer of capsule format 2
encrypt(src, opts) writes a .dkc of format 2 and, when asked, a portable
.dkk (spec §61, §62, §62.1), in the order and with the texts and codes
of capsule.Encrypt:
- L known in advance: the size of a Uint8Array or a Blob, or the length
declared with a ReadableStream; a source of another length fails with
Go's texts;
- reforzado padding by default, or bloque256;
- 1 to 16 credentials, canonical and not of low order, a dummy in each
slot left, whose scalar is wiped once its public key is derived, and
a uniform order of the 16;
- SEALED_CONTROL_LEN from the formula of §62.1, checked against the
real seal;
- the self-checks of rule 11, plus OUTER_TIME_AGE under the reader's
rules and the header of PAYLOAD_AGE opened by I_PAYLOAD before
anything is written.
The content is streamed in pieces of 64 KiB, then the zeros of the
padding, into memory (up to MAX_MEMORY_DKC) or an output that is closed
only once the capsule is complete and checked and aborted on any
failure. The core in writer.ts takes its random values from the caller:
encrypt.ts passes crypto.getRandomValues, and only testing/encrypt.ts
fixes them.
Tests: the deterministic sections of the seven format 2 fixtures of Go
byte for byte; round trips with open for both policies, 1 to 16
credentials and every padding boundary; the invalid options; streaming
and failures of the source and the output; the internal errors with
age-encryption replaced by a spy; a property loop (50 seeds per run,
500 by hand).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 week ago
|
|
|
// The writer (plan of phase 3, steps 3 and 4).
|
|
|
|
|
'src/lib/dkc/writer.ts': { 100: true },
|
|
|
|
|
'src/lib/dkc/encrypt.ts': { 100: true },
|
Phase 3, steps 6 and 7: the create page
/create seals a person's file into a .dkc of format 2 and, when asked, a
portable .dkk, in the browser and without network, with the decisions the
author confirmed in step 6: time_only by default, the zone of the device
with a selector, the warnings of §53 and §50 beyond 365 days, a notice of
preliminary protocol, and files named capsula-<opening time, UTC>.
- lengths.ts: sealedControlLength moves out of writer.ts, and
capsuleLength gives the size of the .dkc before writing it; the
property loop checks it on every capsule (500 seeds pass).
- datekey.ts: LONG_HORIZON_SECONDS and isLongHorizon.
- src/lib/inspector: localtime.ts (local times of a zone as UTC instants,
a skipped time refused, a repeated one taken at its later instant),
create-input.ts (the form, checked in its order) and creator.ts (the
writing, loaded on demand), all at 100 %.
- The .dkc goes to an OPFS temporary file, committed only when complete
and checked, or to memory up to 64 MiB; the writing can be cancelled.
The .dkk stays in memory only; losing it when it is the only
credential asks for confirmation.
- /inspect also cleans the temporary files of /create, and check-build
checks the code loaded on demand of both pages.
Checked in the browser on the production build: a capsule made for four
minutes later opened afterwards in /inspect with the pasted release and
with datekeys decrypt of Go over the network, to the same content. An
adversarial review found one major and eight minor issues, all fixed.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 week ago
|
|
|
// The page of step 7: the lengths known before writing, the local
|
|
|
|
|
// times, the form and the writing loaded on demand.
|
|
|
|
|
'src/lib/dkc/lengths.ts': { 100: true },
|
|
|
|
|
'src/lib/inspector/localtime.ts': { 100: true },
|
|
|
|
|
'src/lib/inspector/create-input.ts': { 100: true },
|
|
|
|
|
'src/lib/inspector/creator.ts': { 100: true },
|
Format 3, step 5: the CRC-32 and the layout of the ZIP of the page
The page delivers the files of a format 3 capsule in a ZIP of its own
(design of format 3, section 5): stored entries with UTF-8 names, no
data descriptors and no entries for folders. The head gives every size
before any byte arrives, so the layout is known in advance and each file
is a contiguous range of the ZIP, offered as a download of its own. The
CRC-32 of an entry is patched in its local header after its bytes.
Times go in DOS, in UTC and clipped to 1980-2107, in the NTFS extra
field, which governs, and in the extended timestamp when they fit in 32
signed bits. ZIP64 applies by the size or offset of an entry and by the
number of entries or the size of the central directory.
Both modules live in src/lib/inspector: the reference has no ZIP, only
the page. Coverage 100 %.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 week ago
|
|
|
// Format 3 (plan of format 3 in datekeys-ts): the rules of the paths
|
Format 3, step 2: the codec of BODY, the security area and the head
body.ts, security.ts and head.ts port format3.go of the Go reference at
spec-v0.10:
- body.ts: the frame of BODY (spec 29.2), AREA_LEN, SECURITY_LEN and
HEAD_LEN with their limits, and the zeros of the security area, all
ERR_INTEGRITY.
- security.ts: the empty SECURITY_CBOR that writers write, and the
verdicts X, F0, F1, S0, S1 and S2 of spec 29.7 with the Spanish lines
of the official SDK. The evaluation never fails and carries no code.
- head.ts: HEAD_CBOR in the layers of spec 69.1: R1 and R8 in the CDDL,
R8 by UTF-8 bytes and not by the UTF-16 order of JavaScript strings;
then the comment, the declared author, the paths with pathrule.ts, the
layout of the files, R7 and R9, all ERR_HEAD_INVALID; and the critical
extensions of the new extension object "head". decodeWrittenHead
leaves the extensions to the caller, for the self-check of the writer.
ERR_HEAD_INVALID becomes the 19th normative code, with its gloss.
Tests: the cases of format3_test.go and a few more, with the error
texts and the verdicts of the reference byte for byte, taken from it at
spec-v0.10 with a scratch program. Coverage 100 %.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 week ago
|
|
|
// and texts of the head, the codec of BODY, of the security area and of
|
|
|
|
|
// the head, step 17 and its sink, the ZIP in which the page delivers
|
|
|
|
|
// files, and what the pages show and check of the files.
|
Format 3, step 5: the CRC-32 and the layout of the ZIP of the page
The page delivers the files of a format 3 capsule in a ZIP of its own
(design of format 3, section 5): stored entries with UTF-8 names, no
data descriptors and no entries for folders. The head gives every size
before any byte arrives, so the layout is known in advance and each file
is a contiguous range of the ZIP, offered as a download of its own. The
CRC-32 of an entry is patched in its local header after its bytes.
Times go in DOS, in UTC and clipped to 1980-2107, in the NTFS extra
field, which governs, and in the extended timestamp when they fit in 32
signed bits. ZIP64 applies by the size or offset of an entry and by the
number of entries or the size of the central directory.
Both modules live in src/lib/inspector: the reference has no ZIP, only
the page. Coverage 100 %.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 week ago
|
|
|
'src/lib/dkc/pathrule.ts': { 100: true },
|
Format 3, step 2: the codec of BODY, the security area and the head
body.ts, security.ts and head.ts port format3.go of the Go reference at
spec-v0.10:
- body.ts: the frame of BODY (spec 29.2), AREA_LEN, SECURITY_LEN and
HEAD_LEN with their limits, and the zeros of the security area, all
ERR_INTEGRITY.
- security.ts: the empty SECURITY_CBOR that writers write, and the
verdicts X, F0, F1, S0, S1 and S2 of spec 29.7 with the Spanish lines
of the official SDK. The evaluation never fails and carries no code.
- head.ts: HEAD_CBOR in the layers of spec 69.1: R1 and R8 in the CDDL,
R8 by UTF-8 bytes and not by the UTF-16 order of JavaScript strings;
then the comment, the declared author, the paths with pathrule.ts, the
layout of the files, R7 and R9, all ERR_HEAD_INVALID; and the critical
extensions of the new extension object "head". decodeWrittenHead
leaves the extensions to the caller, for the self-check of the writer.
ERR_HEAD_INVALID becomes the 19th normative code, with its gloss.
Tests: the cases of format3_test.go and a few more, with the error
texts and the verdicts of the reference byte for byte, taken from it at
spec-v0.10 with a scratch program. Coverage 100 %.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 week ago
|
|
|
'src/lib/dkc/body.ts': { 100: true },
|
|
|
|
|
'src/lib/dkc/security.ts': { 100: true },
|
|
|
|
|
'src/lib/dkc/head.ts': { 100: true },
|
Format 3, step 3: read capsule format 3 of spec v0.10
Syncs testdata with datekeys-go at the tag spec-v0.10 (cc35d2c) and
moves the reader to the DateKeys Protocol Specification v0.10. The
three capsule formats are read.
- framing: FORMAT_3, and isPadded for formats 2 and 3. control: schema
version 3, with the keys 6 and 7 of version 2. SPEC_VERSION is 0.10.
- open: OpenOptions.sink receives the files of a format 3 capsule
(sink.ts: Sink with begin, create, commit and abort, as capsule.Sink,
and MemorySink). Without one, open rejects with a TypeError right
after step 2, before any request, as ErrSinkRequired. Opened gains
head, verdicts, areaLen and unusableHeadExtensions.
- open3.ts: step 17 of format 3 in its substeps 17.2 to 17.8, as
openBody of the reference: a failure of age or a plaintext whose
length is not P prevails, the first failing substep decides, and the
codes other than ERR_INTEGRITY are reported only after reading
PAYLOAD_AGE to its end. Reads grow with the bytes received, never
with the lengths BODY declares. A failure of the sink is ERR_INTEGRITY
with its text, and the sink is aborted once after begin.
- The page: opener.ts opens the fixtures of format 3 into a
MemorySink; the open panel says that it does not deliver their files
yet, and the glosses of the steps name format 3. check-build.mjs
refuses to ship the heads, salts, comments and paths of the format 3
fixtures.
Tests: the 21 fixtures, format 3 laid out byte by byte from its record
and opened into a sink with its files and verdicts; the 209 cases of
the corpus from memory and from a Blob, with the code, the step and,
new, the exact text of capsule.Open, frozen by
scripts/mutation-go-texts.go in testing/mutation-texts.json, which
replays the corpus as internal/testkit does (its extension validator
texts included); the 5110 differential cases over 14 bases; paths,
path_fold, head_schema and security vectors; the control of schema
version 3 in cbor.json; and step 17 on crafted plaintexts sealed again
to I_PAYLOAD, whose texts capsule.Open gives on the same plaintexts.
ibe-vectors.json gains the nine format 3 fixtures from
scripts/ibe-go-vectors.go; the twelve before are unchanged.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 week ago
|
|
|
'src/lib/dkc/open3.ts': { 100: true },
|
|
|
|
|
'src/lib/dkc/sink.ts': { 100: true },
|
Format 3, step 5: the CRC-32 and the layout of the ZIP of the page
The page delivers the files of a format 3 capsule in a ZIP of its own
(design of format 3, section 5): stored entries with UTF-8 names, no
data descriptors and no entries for folders. The head gives every size
before any byte arrives, so the layout is known in advance and each file
is a contiguous range of the ZIP, offered as a download of its own. The
CRC-32 of an entry is patched in its local header after its bytes.
Times go in DOS, in UTC and clipped to 1980-2107, in the NTFS extra
field, which governs, and in the extended timestamp when they fit in 32
signed bits. ZIP64 applies by the size or offset of an entry and by the
number of entries or the size of the central directory.
Both modules live in src/lib/inspector: the reference has no ZIP, only
the page. Coverage 100 %.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 week ago
|
|
|
'src/lib/inspector/crc32.ts': { 100: true },
|
|
|
|
|
'src/lib/inspector/zip.ts': { 100: true },
|
Format 3, step 5: the ZIP sink of the page, which archive/zip reads
zipsink.ts is the sink of the page for a format 3 capsule (design of
format 3, section 5). Its files go to the temporary file of OPFS: the
file itself when the capsule holds one file of one segment, and
otherwise a ZIP of stored entries laid out from the head before any
byte arrives. Each local header is written at its offset, the bytes of
the file follow as open delivers them, the CRC-32 of the entry is
patched in its header with a positioned write, and commit writes the
central directory and closes the file; abort discards it, also when
the opening failed before begin. Each file is a contiguous range of the
file written (ranges), and zipOf makes the same ZIP in memory as a Blob
of its parts.
tempfile.ts: the writable of a temporary file takes TempChunk, bytes at
the position of the file or at a given one, as
FileSystemWritableFileStream does; cancellable is generic.
Interoperability: scripts/zip-ts-samples.mjs writes the samples of
testing/zip.ts with ZipSink, and scripts/zip-go-read.go reads them with
archive/zip of the Go standard library: names out of ASCII with bit 11,
stored entries, their CRC-32 and sizes, the times of the extra fields
in 1970, at 2^31 - 1 and after it, in 9999 and the time of the round for
a file without one, and 65535 entries, ZIP64 by their number. The
reading is frozen in testing/zip-vectors.json, and zipsink.test.ts
writes each sample again, requires its SHA-256 and computes the entries
Go must have read. zipsink.ts is covered at 100 %.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 week ago
|
|
|
'src/lib/inspector/zipsink.ts': { 100: true },
|
Format 3, step 6: /inspect opens format 3
The page opens capsules of format 3. The files go to the temporary
file through a ZipSink, a lone file of one segment as it is and a ZIP
otherwise, or to memory; the page shows the verdicts first, then the
declared author and the comment as unchecked text of the creator, and
then each path as text in a bdi, with its size, its mtime and the
warnings of the CLI of the reference, compared by their key of R7.
- files.ts: pathWarnings, fileFacts, and the names and order of the
downloads: the file itself when it is the only one, with the ZIP of
its folder second (decision 8), or the ZIP and each file.
- opener.ts: OpenedFiles, and noRoom when the ZIP does not fit.
- zipsink.ts: NoRoom, thrown by begin before writing anything.
- check-build.mjs: the tables of pathrule-tables.ts never come with
the first load of a page, and do come with the code on demand of
/inspect and /create.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 week ago
|
|
|
'src/lib/inspector/files.ts': { 100: true },
|
Format 3, step 7: /create with files and folders
The page seals files and folders, chosen or dropped, with a comment
and a declared author, into a capsule of format 3.
- create-files.ts, with the first load: the files as the person chose
them, a dropped folder walked with webkitGetAsEntry and named first
in each path as webkitRelativePath does, the files of a system left
out of folders as collect.go leaves them out (strings.EqualFold for
.DS_Store, Thumbs.db and desktop.ini, ._* and __MACOSX), and the
list of editable paths.
- create-check.ts, on demand with the tables: every problem of every
path, and of the comment and the author, in Spanish, from the
violations of pathrule.ts. A property test holds that the page sees
no problem exactly when checkPath and checkTree accept the paths.
- lengths.ts: measureFiles, headLengthOf and bodyLengthOf, so that
the exact size is planned again without sorting the files again.
- creator.ts: several files, the comment and the author, the progress
of both readings of encryptFiles, the cancellation in the first
one, and the room checked before reading anything.
Checked in Chromium: Go's datekeys decrypt and /inspect open a capsule
that the page wrote, with its six files, their mtimes, the author and
the comment.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
7 days ago
|
|
|
'src/lib/inspector/create-files.ts': { 100: true },
|
|
|
|
|
'src/lib/inspector/create-check.ts': { 100: true },
|
/inspect asks drand for the release when the person asks
The author found copying the release of the round tedious. A button,
"Pedir la firma a drand", fetches it from the three public relays of
the CLI of the reference, as its client does: raced, 6 s, at most
8 KiB an answer, no redirects, and the randomness checked against the
signature; step 10 still verifies the signature with the pinned key,
so a relay cannot make the page accept a false one. It is the only
connection the page makes to another site, and only on that click: the
CSP allows those three origins in connect-src, check-build.mjs
requires exactly them, and the footer says so. Pasting by hand still
works. Checked in Chromium: api2.drand.sh gave the release of round
32668196 and the capsule opened.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
7 days ago
|
|
|
'src/lib/inspector/drand.ts': { 100: true },
|
Key of words v2: salted with capsule_id, lowered with Unicode 18.0.0
As the spec v0.11 draft decides after its review (38.1), and as the Go
reference does from 2213b8c:
- dkc/wordkey.ts replaces inspector/wordkey.ts. The salt carries the
capsule_id too, so the same words give another key in each capsule;
the words are lowered with the new LOWERCASE table of pathrule.ts,
loaded on demand; checkWords refuses controls, invisible and
unassigned code points and counts only different words of three
letters or more, with the errors of Go. New vector of 38.1.
- encryptFiles takes the words and derives their key once it has drawn
capsule_id; the creator passes them, and the opener salts them with
the capsule_id of the capsule.
- /create asks for the words twice and shows how they are kept; the form
checks them with the tables of the platform, and the writer again with
those of Unicode 18.0.0.
- The tables, regenerated with the lower case, and testdata synced from
2213b8c; the frozen texts of Go for the invalid options, updated.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
6 days ago
|
|
|
'src/lib/dkc/wordkey.ts': { 100: true },
|
Random words: readWordList, checkWordList, generateWords and wordBits
wordlist.ts does what wordkey.Generate, CheckList and Bits of Go do at
27a75ee, with their texts: generateWords draws different words, 7 by
default, with crypto.getRandomValues; wordBits is their strength;
checkWordList refuses a list of fewer than 2048 words, with two words that
are one once normalized or with a character outside the alphabet of its
language, which the code gives and not the list. readWordList takes a list
only with the SHA-256 pinned for its language, in UTF-8 and accepted by
checkWordList: no list is trusted, not even those of DateKeys.
wordkey.ts gains wordRules, which loads the Unicode tables once for a
caller that reads many words; normalizeWords and checkWords use it.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
12 hours ago
|
|
|
'src/lib/dkc/wordlist.ts': { 100: true },
|
The sealing and the envelope of the locator, and its documentation
ageio.ts reads and writes age files as filippo.io/age v1.3.2, with its
texts and its order of random draws, which Go's locator copies; it uses
only the noble modules that x25519.ts already uses. envelope.ts is Open,
Info.OpenLocator, OpenEnvelope, Seal and NewEnvelope of package locator
at spec-v0.12, with an injectable random source read in the order of Go.
- locator-seal.json (scripts/locator-seal-go-vectors.go): with the same
seed, seal and newEnvelope write the bytes of Go;
- locator-interop.json (scripts/locator-ts-samples.mjs and
locator-go-verdicts.go): Go opens what this library writes, up to a
.dkc of 16 MiB and one byte;
- vectors.test.ts runs all of testdata/vectors/locator.json with the
texts of Go, instead of its spec field only.
Shared files: dependencies.test.ts lets ageio.ts import noble and keeps
the four locator modules out of index.ts; check-build.mjs fails when a
page loads the locator with its first load; vitest.config.ts holds them
at 100 % coverage; ibe.ts updates the comment of encryptOnG2WithSigma;
README and CHANGELOG describe the port.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 day ago
|
|
|
// The locator of datekeys.capsule: its data, its addresses and their
|
|
|
|
|
// IP addresses, its plaintext, and the age files of its sealing and of
|
|
|
|
|
// the envelope.
|
|
|
|
|
'src/lib/dkc/locator.ts': { 100: true },
|
|
|
|
|
'src/lib/dkc/ipaddr.ts': { 100: true },
|
|
|
|
|
'src/lib/dkc/ageio.ts': { 100: true },
|
|
|
|
|
'src/lib/dkc/envelope.ts': { 100: true },
|
Author keys of alg 1 and Ed25519 signing in own code, as Go's authorkey
authorkey.ts ports the package authorkey of datekeys-go at spec-v0.12:
generate with an injectable random source, fromSeed, publicKey, sign,
clear, secret, a toString that hides the secret, publicString, parsePublic
(canonical, on the curve, not of small order), parseSecret, marshal, and
the key file encrypted with age and scrypt of work factor 16, read with a
maximum of 16, 64 KiB and the lines of bufio.Scanner, with the error texts
of Go and of Go's age byte for byte. Key strings are read as Go strings,
with the case and space tables of Go's package unicode (gounicode.ts,
generated by scripts/go-unicode-tables.go).
ed25519sign.ts is crypto_sign of TweetNaCl, as the Dart port, with the
SHA-512 of @noble/hashes: exact arithmetic in Float64Array, secrets never
in BigInt. No new package or module: age-encryption writes the scrypt
stanza, and the STREAM of a key file uses the ChaCha20-Poly1305 and HKDF
already imported.
scripts/authorkey-go-vectors.go, the generator of the Dart port with this
library's output, writes testing/authorkey-vectors.json in an export of
datekeys-go at spec-v0.12: 234 signatures, scalars, keys, Generate and
Encrypt with Go's draws (reproduced byte for byte), 1288 key strings,
3240 runes at the edges of the tables and 130 key files.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 day ago
|
|
|
// The author keys, their signing and the tables of Go they read with.
|
|
|
|
|
'src/lib/dkc/authorkey.ts': { 100: true },
|
|
|
|
|
'src/lib/dkc/ed25519sign.ts': { 100: true },
|
|
|
|
|
'src/lib/dkc/gounicode.ts': { 100: true },
|
TypeScript implementation of DateKeys v0.8.2, steps 1 to 8
Canonical CBOR codec of the spec §58 profile, hand-written schema codecs
(profile, PUBLIC_HEADER, CONTROL_CBOR, .dkk, extensions), DKC1/DKK1
framing, a strict age header parser, dk1_ parsing and nanosecond date to
round resolution, and inspect (spec §63 steps 1 to 8) with the same checks
and view as "datekeys inspect -json". No runtime dependencies.
216 tests, cbor.ts at 100 % coverage, typecheck of the library without
Node types. A differential comparison with the Go reference at afb44a3
found no verdict, code or step disagreement in about 336,000 inputs. The
harness for the future Go vector files runs them when they appear.
vite 8.3.0 is declared explicitly: it is a required peer of vitest 5.0.1
that legacy-peer-deps does not install.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2 weeks ago
|
|
|
'src/lib/dkc/**/*.ts': { statements: 95, branches: 90, functions: 95, lines: 95 },
|
Inspector page: static SvelteKit site with /inspect (plan step 5)
A prerendered static site (adapter-static) with a landing page and
/inspect, which runs spec §63 steps 1 to 8 on a .dkc chosen with the file
picker, dropped anywhere on the page, or taken from the official fixtures
bundled at build time. It shows every step, the decoded header, the unlock
date in UTC and local time, and each extension's id, version, criticality,
length and hex, with a text view and an informative CBOR diagnostic view,
all escaped and labelled as unauthenticated before step 15. Copiar JSON
copies the exact "datekeys inspect -json" view.
No network: a hash-mode Content-Security-Policy with connect-src 'self'
is the first element of every page, and scripts/check-build.mjs verifies
it, the fixtures and the absence of external URLs after every build.
Large files are read only up to what steps 1 to 8 need.
Reviewed for design and accessibility (WCAG AA contrast, keyboard,
focus, live status, 360 px), security and correctness; 262 tests pass,
svelte-check has no warnings.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2 weeks ago
|
|
|
// The page model and helpers of the inspector (plan §8, phase 1).
|
|
|
|
|
'src/lib/inspector/**/*.ts': { statements: 95, branches: 90, functions: 95, lines: 95 },
|
TypeScript implementation of DateKeys v0.8.2, steps 1 to 8
Canonical CBOR codec of the spec §58 profile, hand-written schema codecs
(profile, PUBLIC_HEADER, CONTROL_CBOR, .dkk, extensions), DKC1/DKK1
framing, a strict age header parser, dk1_ parsing and nanosecond date to
round resolution, and inspect (spec §63 steps 1 to 8) with the same checks
and view as "datekeys inspect -json". No runtime dependencies.
216 tests, cbor.ts at 100 % coverage, typecheck of the library without
Node types. A differential comparison with the Go reference at afb44a3
found no verdict, code or step disagreement in about 336,000 inputs. The
harness for the future Go vector files runs them when they appear.
vite 8.3.0 is declared explicitly: it is a required peer of vitest 5.0.1
that legacy-peer-deps does not install.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2 weeks ago
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
});
|