@typedstandards/verify-core 0.8.0 → 0.8.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -6,6 +6,50 @@ references are to `npstorey/civic-ai-tools-website` (#119 is the offline-crypto
6
6
  hardening arc; #116 is the standalone-verifier arc this package was extracted
7
7
  in).
8
8
 
9
+ ## 0.8.1 — 2026-08-17
10
+
11
+ - Removed the `prepare` (install-time build) script (typedstandards#39).
12
+ A fresh `npm ci` at the monorepo root previously failed in workspace
13
+ `prepare` ordering (produce-core's tsc ran before this package's dist
14
+ existed), and npm 10.x runs workspace `prepare` even under
15
+ `--ignore-scripts`. Builds are now explicit (`npm run build:verify-core`,
16
+ then `npm run build`; CI does the same). Published tarballs are unchanged —
17
+ `prepublishOnly` still builds at publish — but installing this package from
18
+ git no longer auto-builds `dist`.
19
+ - Docs only, no behavior change: removed reference-deployment framing from
20
+ published JSDoc/README (typedstandards#44 P3, findings B10/B11). Four
21
+ sites — `verifyBlobRef`'s JSDoc, the exported `FetchLike` type's JSDoc, the
22
+ README's Fetch note, and `trust-registry.ts` — no longer treat
23
+ civicaitools.org as the rule's rationale or "the platform" as the sole
24
+ publisher. The plain-GET/no-custom-headers requirement now derives from
25
+ CORS behavior itself (a custom header triggers a preflight, rejectable at
26
+ a redirecting host), with the reference redirect kept as a named example;
27
+ `trust-registry.ts`'s header states its actual contract (pure, registry
28
+ passed in, loading is the caller's job) instead of pointing at an unshipped
29
+ server file; each publisher is understood to have its own registry, named
30
+ by `trustRegistryUrl`. No exported type, signature, or runtime behavior
31
+ changed — most consumer-visible via `FetchLike`'s JSDoc in the published
32
+ `.d.ts`.
33
+ - Docs correction, no behavior change: scopes the plain-GET/CORS claim above
34
+ by execution environment (typedstandards#44 P4). The unscoped version was
35
+ disproved during a live browser session: a cross-origin redirect response
36
+ must itself carry CORS headers, or a browser's fetch fails regardless of
37
+ how simple the triggering request was — a plain GET only avoids the
38
+ *preflight* rejection, it does not make a redirect chain transparent in a
39
+ browser. The claim had been verified only from Node/curl, where that
40
+ constraint does not exist, then stated unconditionally. Now scoped: a
41
+ plain GET avoids the preflight failure mode (kept, unchanged); a browser
42
+ additionally needs the redirect response itself to carry CORS headers
43
+ (the missing half, now stated); server-side/Node fetches follow redirects
44
+ without that constraint (why the unscoped claim read true when written).
45
+ Same three verify-core sites P3 touched for this class — `verifyBlobRef`'s
46
+ JSDoc (`blob-ref.ts`), the exported `FetchLike` type's JSDoc (`types.ts`),
47
+ and the README's Fetch note — plus the equivalent explanation and its
48
+ cross-reference in typedstandards.org's client-side verify flow
49
+ (`apps/web`, outside this published package). No exported type, signature,
50
+ or runtime behavior changed — consumer-visible via `FetchLike`'s JSDoc in
51
+ the published `.d.ts` and the README.
52
+
9
53
  ## 0.8.0 — 2026-08-01
10
54
 
11
55
  - New export: `ED25519_SPKI_PREFIX` (`signature.ts`) — the fixed 12-byte
package/README.md CHANGED
@@ -34,9 +34,13 @@ edge, and in Node.
34
34
  injects its `fetch`, the browser injects `window.fetch`, tests inject a stub.
35
35
 
36
36
  > **Fetch note.** A `FetchLike` should issue **plain GETs with no custom request
37
- > headers**. A custom header triggers a CORS preflight, and a preflight `OPTIONS`
38
- > hitting civicaitools.org's site-wide 307 to its canonical host can be rejected.
39
- > A simple GET follows the 307 transparently.
37
+ > headers**. A custom header makes the request non-simple and triggers a CORS
38
+ > preflight; a preflight `OPTIONS` against a host that redirects can be rejected
39
+ > there, so a plain GET avoids that failure mode — e.g. civicaitools.org's
40
+ > site-wide 307 to its canonical host. That's necessary but not sufficient in a
41
+ > browser, though: a cross-origin redirect response must itself carry CORS
42
+ > headers, or the fetch fails regardless of the request's simplicity.
43
+ > Server-side/Node fetches follow redirects without that constraint.
40
44
 
41
45
  ## Usage
42
46
 
@@ -43,9 +43,15 @@ export interface BlobFetchOptions {
43
43
  * Fetch a blob and verify that its SHA-256 matches the reference hash and that
44
44
  * its byte size matches the metadata. Returns a structured result; never throws.
45
45
  *
46
- * Fetches over HTTPS without auth (Vercel Blob public access is the storage
47
- * default for evidence content). A plain GET with no custom headers, so it
48
- * follows civicaitools.org's canonical-host 307 without a CORS preflight.
46
+ * Fetches over HTTPS with no auth and no custom request headers — evidence
47
+ * content is expected to be publicly readable, and a custom header would make
48
+ * the request non-simple, triggering a CORS preflight. A preflight `OPTIONS`
49
+ * against a host that redirects can be rejected there, so a plain GET avoids
50
+ * that failure mode — e.g. civicaitools.org's canonical-host 307. That's
51
+ * necessary but not sufficient in a browser, though: a cross-origin redirect
52
+ * response must itself carry CORS headers, or the fetch fails regardless of
53
+ * the request's simplicity. Server-side/Node fetches follow redirects
54
+ * without that constraint.
49
55
  */
50
56
  export declare function verifyBlobRef(ref: BlobRef, options?: BlobFetchOptions): Promise<BlobRefVerifyResult>;
51
57
  /**
package/dist/blob-ref.js CHANGED
@@ -56,9 +56,15 @@ function resolveFetch(options) {
56
56
  * Fetch a blob and verify that its SHA-256 matches the reference hash and that
57
57
  * its byte size matches the metadata. Returns a structured result; never throws.
58
58
  *
59
- * Fetches over HTTPS without auth (Vercel Blob public access is the storage
60
- * default for evidence content). A plain GET with no custom headers, so it
61
- * follows civicaitools.org's canonical-host 307 without a CORS preflight.
59
+ * Fetches over HTTPS with no auth and no custom request headers — evidence
60
+ * content is expected to be publicly readable, and a custom header would make
61
+ * the request non-simple, triggering a CORS preflight. A preflight `OPTIONS`
62
+ * against a host that redirects can be rejected there, so a plain GET avoids
63
+ * that failure mode — e.g. civicaitools.org's canonical-host 307. That's
64
+ * necessary but not sufficient in a browser, though: a cross-origin redirect
65
+ * response must itself carry CORS headers, or the fetch fails regardless of
66
+ * the request's simplicity. Server-side/Node fetches follow redirects
67
+ * without that constraint.
62
68
  */
63
69
  export async function verifyBlobRef(ref, options = {}) {
64
70
  let parsed;
@@ -40,8 +40,8 @@ export interface KeyTrustResult {
40
40
  */
41
41
  export declare function legacyEmbeddedKeyTrust(): KeyTrustResult;
42
42
  /**
43
- * Verify that a `(kid, publicKey)` pair is trusted by the platform registry,
44
- * applying the rotation semantics documented in the P5 plan:
43
+ * Verify that a `(kid, publicKey)` pair is trusted by the registry, applying
44
+ * the rotation semantics documented in the P5 plan:
45
45
  * - `active` → trusted.
46
46
  * - `deprecated` → trusted only when `packageIntegratedTime` precedes
47
47
  * `deprecatedAt` (preventive rotation — pre-deprecation signatures remain
@@ -1,16 +1,19 @@
1
1
  // Trust registry types + key-trust evaluation (spec §8.3.3, §9.2 check #5) —
2
2
  // browser-safe.
3
3
  //
4
- // The platform publishes its authorized signing keys at a `/.well-known/*`
5
- // registry. Verification treats it as the source of truth for which
6
- // `(kid, publicKey)` pairs are allowed and their rotation state: keys absent or
7
- // revoked fail verification regardless of cryptographic correctness — a locally
8
- // valid signature from an unrecognised key is still not "trusted evidence".
4
+ // Each publisher publishes its own authorized signing keys at a
5
+ // `/.well-known/*` registry, named by the package's declared
6
+ // `trustRegistryUrl`. Verification treats the resolved registry as the source
7
+ // of truth for which `(kid, publicKey)` pairs are allowed and their rotation
8
+ // state: keys absent or revoked fail verification regardless of cryptographic
9
+ // correctness — a locally valid signature from an unrecognised key is still
10
+ // not "trusted evidence".
9
11
  //
10
- // These functions are pure (registry passed IN as data). The server `verify.ts`
11
- // keeps the registry LOADER (build-time embedded import + fs + fetch fallback,
12
- // all server-only); WS3's browser client fetches the registry from the sidecar's
13
- // `trustRegistryUrl`. Both then hand the parsed registry to `verifyKeyTrust`.
12
+ // These functions are pure: the registry is passed IN as already-parsed data.
13
+ // Loading it — however a caller chooses to (a build-time embed, a filesystem
14
+ // read, a network fetch, or some mix) — is entirely the caller's job; this
15
+ // module has no opinion on how a registry was obtained, only on what it means
16
+ // once handed to `verifyKeyTrust`.
14
17
  export const KEY_TRUST_STATUSES = [
15
18
  'active', // active key — package is trusted
16
19
  'deprecated_valid', // deprecated key, but package was signed before deprecation
@@ -30,8 +33,8 @@ export function legacyEmbeddedKeyTrust() {
30
33
  return { status: 'legacy_embedded', verified: false };
31
34
  }
32
35
  /**
33
- * Verify that a `(kid, publicKey)` pair is trusted by the platform registry,
34
- * applying the rotation semantics documented in the P5 plan:
36
+ * Verify that a `(kid, publicKey)` pair is trusted by the registry, applying
37
+ * the rotation semantics documented in the P5 plan:
35
38
  * - `active` → trusted.
36
39
  * - `deprecated` → trusted only when `packageIntegratedTime` precedes
37
40
  * `deprecatedAt` (preventive rotation — pre-deprecation signatures remain
package/dist/types.d.ts CHANGED
@@ -24,10 +24,15 @@ export type CaptureMethod = 'chat-flow-stream' | 'claude-code-jsonl-readback' |
24
24
  * never reaches for `node:*` or a hardcoded global — see the ESLint
25
25
  * `no-restricted-imports` guard scoped to this directory.
26
26
  *
27
- * Per the WS1 prod smoke test: the injected fetcher should issue plain GETs with
28
- * NO custom request headers (a custom header triggers a CORS preflight, and a
29
- * preflight OPTIONS hitting civicaitools.org's site-wide 307 to its canonical
30
- * host can be rejected). A simple GET follows the 307 transparently.
27
+ * Per the WS1 prod smoke test: the injected fetcher should issue plain GETs
28
+ * with NO custom request headers — a custom header makes the request
29
+ * non-simple and triggers a CORS preflight; a preflight `OPTIONS` against a
30
+ * host that redirects can be rejected there, so a plain GET avoids that
31
+ * failure mode — e.g. civicaitools.org's site-wide 307 to its canonical
32
+ * host. That's necessary but not sufficient in a browser, though: per the
33
+ * Fetch spec, a cross-origin redirect response must itself carry CORS
34
+ * headers, or the fetch fails regardless of the request's simplicity.
35
+ * Server-side/Node fetches follow redirects without that constraint.
31
36
  */
32
37
  export type FetchLike = (input: string, init?: {
33
38
  signal?: AbortSignal;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@typedstandards/verify-core",
3
- "version": "0.8.0",
3
+ "version": "0.8.1",
4
4
  "description": "Portable, browser-safe verification core for Typed Standards evidence packages — the §9.2 check suite, single-sourced so it verifies identically on a server and in the browser.",
5
5
  "license": "MIT",
6
6
  "author": "Nathan Storey",
@@ -28,7 +28,6 @@
28
28
  "clean": "rm -rf dist tsconfig.tsbuildinfo",
29
29
  "typecheck": "tsc -p tsconfig.json --noEmit",
30
30
  "test": "node --test --experimental-strip-types \"src/**/*.test.ts\"",
31
- "prepare": "npm run build",
32
31
  "prepublishOnly": "npm run clean && npm run build"
33
32
  },
34
33
  "dependencies": {