@vielzeug/archive 26.11.17 → 26.11.18

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.
@@ -0,0 +1,2 @@
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});let e=require("@vielzeug/spell");var sha256Hex=async e=>[...new Uint8Array(await crypto.subtle.digest(`SHA-256`,new TextEncoder().encode(e)))].map(e=>e.toString(16).padStart(2,`0`)).join(``);function canonicalJson(e,t=!1,n){let r=new Set,text=e=>/[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?<![\uD800-\uDBFF])[\uDC00-\uDFFF]/u.test(e)?null:JSON.stringify(e),serialize=(e,n)=>{if(e===null)return`null`;if(typeof e==`string`)return text(e);if(typeof e==`boolean`)return String(e);if(typeof e==`number`)return Number.isFinite(e)?JSON.stringify(e):null;if(typeof e!=`object`||r.has(e))return null;let i=Array.isArray(e),a=Object.getPrototypeOf(e);if(!i&&a!==Object.prototype&&a!==null||i&&a!==Array.prototype)return null;r.add(e);try{let r=[],a=Reflect.ownKeys(e);if(i){if(a.length!==e.length+1)return null;for(let t=0;t<e.length;t++){let i=Object.getOwnPropertyDescriptor(e,String(t));if(!i||!i.enumerable||!(`value`in i))return null;let a=serialize(i.value,Array.isArray(n)?n[t]:void 0);if(a===null)return null;r.push(a)}return`[${r.join(`,`)}]`}if(a.some(e=>typeof e!=`string`))return null;for(let i of Object.keys(e).sort()){let a=Object.getOwnPropertyDescriptor(e,i);if(!a||!(`value`in a))return null;let o=typeof n==`object`&&n?n:null;if(a.value===void 0&&t&&(o===null||!Object.hasOwn(o,i)))continue;let s=text(i),c=serialize(a.value,o===null?void 0:Reflect.get(o,i));if(s===null||c===null)return null;r.push(`${s}:${c}`)}return Object.keys(e).length===a.length?`{${r.join(`,`)}}`:null}finally{r.delete(e)}};try{return serialize(e,n)}catch{return null}}function canonicalObjectJson(e,t=!1,n){return typeof e!=`object`||!e||Array.isArray(e)?null:canonicalJson(e,t,n)}var t=`archive_session`,n=`/api/v1`,r=2592e3,i=3600,sessionCookieValue=(e,r)=>`${t}=${e}; HttpOnly; SameSite=Strict; Path=${n}; Max-Age=${r.maxAgeSeconds}${r.secure?`; Secure`:``}`,a=`x-archive-publisher`,o=`X-Archive-Account`,s=`x-archive-request`,c=1,l=1,u=1,d=`archive-operator`,f=/^[a-z0-9-]{1,32}$/,p=e.s.string().uuid(),m=e.s.string().isoDateTime(),h=e.s.string().regex(/^[0-9a-f]{64}$/),g=/[\p{Cs}\p{Cc}]/u,isWellFormedText=e=>!g.test(e),textString=()=>e.s.string().check(isWellFormedText),_=textString().trim().max(24),v=e.s.object({id:p,name:_}),y=e.s.object({id:p,name:_,operator:e.s.boolean()}).nullable(),b=e.s.object({createdAt:m,email:e.s.string().email(),id:p,lastSignInAt:m.nullable()}),x=e.s.object({ids:e.s.array(p)}),S=e.s.object({cursor:e.s.string().nullable(),ids:e.s.array(p)}),C=e.s.object({id:p,likeCount:e.s.number().int().min(0).max(2**53-1),liked:e.s.boolean()}),w=Object.freeze({aliasChars:24,cursorChars:1024,idempotencyRetentionMs:1728e5,likeStateIds:50,maxPageSize:50,maxPublications:50,pageSize:10,payloadBytes:8192,publicCacheSeconds:30,reportReasonChars:256,requestBytes:12288,searchChars:64,searchTerms:6,tagsPerEntry:16,titleChars:128,vocabChars:64}),T=e.s.object({aliasChars:e.s.number().int().min(1),cursorChars:e.s.number().int().min(1),idempotencyRetentionMs:e.s.number().int().min(1),likeStateIds:e.s.number().int().min(1),maxPageSize:e.s.number().int().min(1),maxPublications:e.s.number().int().min(1),pageSize:e.s.number().int().min(1),payloadBytes:e.s.number().int().min(1),publicCacheSeconds:e.s.number().int().min(0),reportReasonChars:e.s.number().int().min(1),requestBytes:e.s.number().int().min(1),searchChars:e.s.number().int().min(1),searchTerms:e.s.number().int().min(1),tagsPerEntry:e.s.number().int().min(1),titleChars:e.s.number().int().min(1),vocabChars:e.s.number().int().min(1)}),E=e.s.object({dbSchemaVersion:e.s.number().int().min(0).nullable(),features:e.s.object({likes:e.s.boolean(),publishing:e.s.boolean()}),limits:T,reason:e.s.enum([`database-unavailable`,`schema-mismatch`]).nullable(),schemaVersion:e.s.literal(1),status:e.s.enum([`ok`,`degraded`])}),D=e.s.object({dbSchemaVersion:e.s.number().int().min(0).nullable(),reason:e.s.enum([`configuration-unavailable`,`database-unavailable`,`schema-mismatch`]).nullable(),schemaVersion:e.s.literal(1),status:e.s.enum([`ok`,`degraded`])}),O=[`account-changed`,`auth-unavailable`,`bad-request`,`conflict`,`forbidden`,`gone`,`internal`,`invalid-payload`,`likes-disabled`,`method-not-allowed`,`not-found`,`publisher-changed`,`publishing-disabled`,`quota`,`rate-limited`,`record-unavailable`,`timeout`,`too-large`,`unauthenticated`,`unavailable`,`unsupported-media`],k=e.s.object({error:e.s.object({code:e.s.enum(O),message:e.s.string().min(1).max(256),requestId:p}).strict()}).strict(),A=e.s.object({ok:e.s.literal(!0)}).strict(),j=e.s.object({filters:e.s.array(e.s.string().min(1).max(w.vocabChars)),name:e.s.string().regex(f),tags:e.s.array(e.s.string().min(1).max(w.vocabChars))}),M=e.s.object({cursor:e.s.string().nullable(),reports:e.s.array(e.s.object({createdAt:m,entryId:p,entryTitle:e.s.string().min(1).max(w.titleChars),id:p,reason:e.s.string().min(1).max(w.reportReasonChars),reporter:v,resolvedAt:m.nullable()}))}),N=e.s.object({cursor:e.s.string().nullable(),reports:e.s.array(e.s.object({collection:e.s.string().regex(f),createdAt:m,entryId:p,id:p,reason:e.s.string().min(1).max(w.reportReasonChars),resolvedAt:m.nullable()}))}),P=[`hide`,`unhide`,`remove`,`erase-publisher`],F=e.s.object({actions:e.s.array(e.s.object({action:e.s.enum(P),collection:e.s.string().regex(f).nullable(),createdAt:m,id:p,operatorId:p,targetId:p})),cursor:e.s.string().nullable()}),I=e.s.enum([`liked`,`recent`]),ArchiveError=class extends Error{constructor(e,t){super(e,t),this.name=new.target.name}},ArchiveDefinitionError=class extends ArchiveError{},ArchiveDerivationError=class extends ArchiveError{stage;constructor(e,t,n){super(t,n),this.stage=e}},envelopeShape=(t,n)=>({author:v,contentHash:h,contentVersion:e.s.literal(n),id:p,likeCount:e.s.number().int().min(0).max(2**53-1),payload:t,publishedAt:m,revision:e.s.number().int().min(1).max(2**53-1),schemaVersion:e.s.literal(1),updatedAt:m});function defineArchiveCollection(t){let{canonicalize:n,contentVersion:r,index:i,name:a,payloadSchema:o}=t;if(typeof i!=`function`||!o||typeof o.safeParse!=`function`||n!==void 0&&typeof n!=`function`)throw new ArchiveDefinitionError(`Collection requires a payload schema and synchronous indexing/canonicalization functions.`);if(t.filters!==void 0&&!Array.isArray(t.filters)||t.tags!==void 0&&!Array.isArray(t.tags))throw new ArchiveDefinitionError(`Collection vocabularies must be arrays.`);let s=Object.freeze([...t.filters??[]]),c=Object.freeze([...t.tags??[]]);if(typeof a!=`string`||!f.test(a))throw new ArchiveDefinitionError(`Archive collection name must match [a-z0-9-]{1,32}: ${JSON.stringify(a)}`);if(!Number.isSafeInteger(r)||r<1)throw new ArchiveDefinitionError(`Archive collection ${a}: contentVersion must be a safe integer >= 1.`);let validateVocabulary=(e,t)=>{for(let n of t)if(typeof n!=`string`||n.length===0||n.length>w.vocabChars||!isWellFormedText(n))throw new ArchiveDefinitionError(`Archive collection ${a}: every ${e} value must be well-formed text of 1..${w.vocabChars} chars.`)};validateVocabulary(`filters`,s),validateVocabulary(`tags`,c);let l=new Set(s),u=new Set(c),derive=async e=>{let t=`schema`;try{if(canonicalObjectJson(e)===null)return null;let a=o.safeParse(e);if(!a.success)return null;let s=canonicalObjectJson(a.data,!0,e);if(s===null)throw new ArchiveDerivationError(t,`Payload schema produced invalid or lossy JSON.`);t=`canonicalize`;let c=canonicalObjectJson(n===void 0?a.data:n(a.data),!0,JSON.parse(s));if(c===null)throw new ArchiveDerivationError(t,`Canonicalization produced invalid JSON.`);t=`schema`;let d=o.safeParse(JSON.parse(c));if(!d.success)throw new ArchiveDerivationError(n===void 0?`schema`:`canonicalize`,`Canonical payload is outside the payload schema.`,{cause:d.error});let f=canonicalObjectJson(d.data,!0,JSON.parse(c));if(f===null||f!==c)throw new ArchiveDerivationError(t,`Payload schema is not stable on canonical JSON.`);if(n!==void 0){let e=o.parse(JSON.parse(f));if(t=`canonicalize`,canonicalObjectJson(n(e),!0)!==f)throw new ArchiveDerivationError(t,`Canonicalization is not idempotent.`)}t=`index`;let{filter:p,tags:m,title:h}=i(d.data);if(canonicalObjectJson(d.data,!0)!==f)throw new ArchiveDerivationError(t,`Indexing mutated the canonical payload.`);if(typeof h!=`string`||!Array.isArray(m))throw new ArchiveDerivationError(t,`Indexing must return a string title and a tags array.`);let g=h.trim();if(g.length===0||g.length>w.titleChars||!isWellFormedText(g))return null;if(p!==null&&(typeof p!=`string`||!isWellFormedText(p)))throw new ArchiveDerivationError(t,`Indexing returned an invalid filter.`);let _=[];for(let e of m){if(typeof e!=`string`||!isWellFormedText(e))throw new ArchiveDerivationError(t,`Indexing returned an invalid tag.`);_.includes(e)||_.push(e)}if(p!==null&&!l.has(p)||_.some(e=>!u.has(e)))throw new ArchiveDerivationError(t,`Indexing returned a value outside the declared vocabularies.`);return _.length>w.tagsPerEntry||new TextEncoder().encode(f).byteLength>w.payloadBytes?null:(t=`hash`,{canonicalJson:f,contentHash:await sha256Hex(`{"contentVersion":${r},"payload":${f}}`),contentVersion:r,filter:p,tags:_,title:g})}catch(e){throw e instanceof ArchiveDerivationError?e:new ArchiveDerivationError(t,`Collection content derivation failed.`,{cause:e})}},d=e.s.object(envelopeShape(o,r)),m=e.s.object({...envelopeShape(o,r),clientKey:p,hidden:e.s.boolean()}),h={entry:d,ownedEntries:e.s.object({entries:e.s.array(m)}),ownedEntry:m,page:e.s.object({cursor:e.s.string().nullable(),entries:e.s.array(d)}),publishInput:e.s.object({clientKey:p,payload:o}),updateInput:e.s.object({expectedRevision:e.s.number().int().min(1).max(2**53-1),payload:o})};return Object.freeze({contentVersion:r,contract:Object.freeze(h),derive,filters:s,name:a,tags:c})}exports.ACCOUNT_HEADER=o,exports.ARCHIVE_COLLECTION_NAME_PATTERN=f,exports.ARCHIVE_CONTRACT_VERSION=c,exports.ARCHIVE_ERROR_CODES=O,exports.ARCHIVE_LIMITS=w,exports.ARCHIVE_MODERATION_ACTIONS=P,exports.ARCHIVE_OPERATOR_ROLE=d,exports.ARCHIVE_SCHEMA_VERSION=l,exports.AUTH_SCHEMA_VERSION=u,exports.ArchiveDefinitionError=ArchiveDefinitionError,exports.ArchiveDerivationError=ArchiveDerivationError,exports.ArchiveError=ArchiveError,exports.ILL_FORMED_TEXT=g,exports.OPERATOR_SESSION_MAX_AGE_SECONDS=i,exports.PUBLISHER_HEADER=a,exports.REQUEST_MARKER_HEADER=s,exports.SESSION_COOKIE_NAME=t,exports.SESSION_COOKIE_PATH=n,exports.SESSION_MAX_AGE_SECONDS=r,exports.archiveAccountSchema=b,exports.archiveAliasSchema=_,exports.archiveAuthHealthSchema=D,exports.archiveAuthorSchema=v,exports.archiveCollectionMetaSchema=j,exports.archiveErrorResponseSchema=k,exports.archiveHealthSchema=E,exports.archiveIdentitySchema=y,exports.archiveLikeStateSchema=C,exports.archiveLikedIdsSchema=x,exports.archiveLikesPageSchema=S,exports.archiveLimitsSchema=T,exports.archiveModerationLogSchema=F,exports.archiveOkSchema=A,exports.archiveOwnReportsSchema=N,exports.archiveReportsSchema=M,exports.archiveSortSchema=I,exports.defineArchiveCollection=defineArchiveCollection,exports.hex64Schema=h,exports.isWellFormedText=isWellFormedText,exports.isoTimestampSchema=m,exports.sessionCookieValue=sessionCookieValue,exports.uuidSchema=p;
2
+ //# sourceMappingURL=archive.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"archive.cjs","names":["s","s","_vielzeug_spell","text","byte","active","value","array","prototype","fields","keys","i","descriptor","item","source","key","sourceObject","omitUndefinedFields","name","omissionSource","SESSION_COOKIE_NAME","SESSION_COOKIE_PATH","SESSION_MAX_AGE_SECONDS","OPERATOR_SESSION_MAX_AGE_SECONDS","token","options","PUBLISHER_HEADER","ACCOUNT_HEADER","REQUEST_MARKER_HEADER","ARCHIVE_CONTRACT_VERSION","ARCHIVE_SCHEMA_VERSION","AUTH_SCHEMA_VERSION","ARCHIVE_OPERATOR_ROLE","ARCHIVE_COLLECTION_NAME_PATTERN","uuidSchema","isoTimestampSchema","hex64Schema","ILL_FORMED_TEXT","archiveAliasSchema","archiveAuthorSchema","archiveIdentitySchema","archiveAccountSchema","archiveLikedIdsSchema","archiveLikesPageSchema","archiveLikeStateSchema","ARCHIVE_LIMITS","archiveLimitsSchema","archiveHealthSchema","archiveAuthHealthSchema","ARCHIVE_ERROR_CODES","archiveErrorResponseSchema","archiveOkSchema","archiveCollectionMetaSchema","archiveReportsSchema","archiveOwnReportsSchema","ARCHIVE_MODERATION_ACTIONS","archiveModerationLogSchema","archiveSortSchema","message","opts","stage","contentVersion","definition","index","payloadSchema","canonicalize","filters","tags","values","kind","filterValues","tagValues","raw","parsed","parsedJson","normalizedJson","revalidated","canonicalJson","repeatedPayload","rawTags","rawTitle","title","filter","uniqueTags","tag","cause","entrySchema","ownedEntrySchema","contract"],"sources":["../src/_crypto.ts","../src/_json.ts","../src/contract.ts","../src/errors.ts","../src/collection.ts"],"sourcesContent":["/**\n * The one SHA-256→hex helper shared by both server surfaces: the collection content\n * hash (browser-safe root) and the issuer's sign-in-link token hash. Web Crypto\n * only; no D1, JWKS or binding machinery.\n */\nexport const sha256Hex = async (text: string): Promise<string> =>\n [...new Uint8Array(await crypto.subtle.digest('SHA-256', new TextEncoder().encode(text)))]\n .map((byte) => byte.toString(16).padStart(2, '0'))\n .join('');\n","/** Canonical JSON rejects values JSON.stringify would silently discard or coerce. */\nexport function canonicalJson(value: unknown, omitUndefinedFields = false, omissionSource?: unknown): string | null {\n const active = new Set<object>();\n const text = (value: string): string | null => {\n if (/[\\uD800-\\uDBFF](?![\\uDC00-\\uDFFF])|(?<![\\uD800-\\uDBFF])[\\uDC00-\\uDFFF]/u.test(value)) return null;\n return JSON.stringify(value);\n };\n const serialize = (value: unknown, source?: unknown): string | null => {\n if (value === null) return 'null';\n if (typeof value === 'string') return text(value);\n if (typeof value === 'boolean') return String(value);\n if (typeof value === 'number') return Number.isFinite(value) ? JSON.stringify(value) : null;\n if (typeof value !== 'object' || active.has(value)) return null;\n const array = Array.isArray(value);\n const prototype = Object.getPrototypeOf(value);\n if (!array && prototype !== Object.prototype && prototype !== null) return null;\n if (array && prototype !== Array.prototype) return null;\n active.add(value);\n try {\n const fields: string[] = [];\n const keys = Reflect.ownKeys(value);\n if (array) {\n if (keys.length !== value.length + 1) return null;\n for (let i = 0; i < value.length; i++) {\n const descriptor = Object.getOwnPropertyDescriptor(value, String(i));\n if (!descriptor || !descriptor.enumerable || !('value' in descriptor)) return null;\n const item = serialize(descriptor.value, Array.isArray(source) ? source[i] : undefined);\n if (item === null) return null;\n fields.push(item);\n }\n return `[${fields.join(',')}]`;\n }\n if (keys.some((key) => typeof key !== 'string')) return null;\n for (const key of Object.keys(value).sort()) {\n const descriptor = Object.getOwnPropertyDescriptor(value, key);\n if (!descriptor || !('value' in descriptor)) return null;\n const sourceObject = source !== null && typeof source === 'object' ? source : null;\n // Spell materializes absent optional object fields as undefined.\n if (\n descriptor.value === undefined &&\n omitUndefinedFields &&\n (sourceObject === null || !Object.hasOwn(sourceObject, key))\n )\n continue;\n const name = text(key);\n const item = serialize(descriptor.value, sourceObject === null ? undefined : Reflect.get(sourceObject, key));\n if (name === null || item === null) return null;\n fields.push(`${name}:${item}`);\n }\n if (Object.keys(value).length !== keys.length) return null;\n return `{${fields.join(',')}}`;\n } finally {\n active.delete(value);\n }\n };\n try {\n return serialize(value, omissionSource);\n } catch {\n return null;\n }\n}\n\nexport function canonicalObjectJson(\n value: unknown,\n omitUndefinedFields = false,\n omissionSource?: unknown,\n): string | null {\n if (value === null || typeof value !== 'object' || Array.isArray(value)) return null;\n return canonicalJson(value, omitUndefinedFields, omissionSource);\n}\n","import { type InferOutput, type Schema, s } from '@vielzeug/spell';\n\n/** Shared naming: one place so the client, Worker and issuer cannot drift. */\nexport const SESSION_COOKIE_NAME = 'archive_session';\nexport const SESSION_COOKIE_PATH = '/api/v1';\n/**\n * The maximum age a session JWT may carry, and the cookie Max-Age an issuer sets:\n * a long-lived signed-in state. The Worker rejects older tokens at this bound.\n */\nexport const SESSION_MAX_AGE_SECONDS = 30 * 24 * 60 * 60;\nexport const OPERATOR_SESSION_MAX_AGE_SECONDS = 60 * 60;\n\n/**\n * The full Set-Cookie value for the session cookie: name, token and the security\n * attributes every issuer and the Worker must agree on — HttpOnly, SameSite=Strict,\n * the contract Path, Max-Age, and Secure in production. Issuers mint with the\n * session's max age; the Worker and issuers clear with `maxAgeSeconds: 0`. Never\n * hand-compose the attributes: the cookie's CSRF and theft posture is contract,\n * not per-issuer choice.\n */\nexport const sessionCookieValue = (token: string, options: { maxAgeSeconds: number; secure: boolean }): string =>\n `${SESSION_COOKIE_NAME}=${token}; HttpOnly; SameSite=Strict; Path=${SESSION_COOKIE_PATH}; Max-Age=${options.maxAgeSeconds}${options.secure ? '; Secure' : ''}`;\n\nexport const PUBLISHER_HEADER = 'x-archive-publisher';\n/** Pins account erasure to the issuer account shown when confirmation began. */\nexport const ACCOUNT_HEADER = 'X-Archive-Account';\nexport const REQUEST_MARKER_HEADER = 'x-archive-request';\n/** The wire-contract version advertised by health and stamped on every entry envelope. */\nexport const ARCHIVE_CONTRACT_VERSION = 1;\n/**\n * The storage schema version: the `archive_schema_meta` stamp the package's migration\n * writes and the Worker reads back through health. A mismatch answers `degraded`\n * instead of `ok` — a stale database is the most likely deployment fault.\n */\nexport const ARCHIVE_SCHEMA_VERSION = 1;\n/** Canonical issuer database initialization stamp. */\nexport const AUTH_SCHEMA_VERSION = 1;\n/** The `roles` claim value a session JWT carries for operator authority (moderation). */\nexport const ARCHIVE_OPERATOR_ROLE = 'archive-operator';\n/** The routable collection-name rule: lowercase `[a-z0-9-]`, at most 32 chars. */\nexport const ARCHIVE_COLLECTION_NAME_PATTERN = /^[a-z0-9-]{1,32}$/;\n\n// Exported schemas carry explicit public `Schema<Output>` annotations: the concrete\n// spell schema classes are not part of spell's public export surface, so inferred\n// types would not be portable across package declaration files.\nexport const uuidSchema: Schema<string> = s.string().uuid();\nexport const isoTimestampSchema: Schema<string> = s.string().isoDateTime();\nexport const hex64Schema: Schema<string> = s.string().regex(/^[0-9a-f]{64}$/);\n/** Well-formed user text: no lone UTF-16 surrogates, no C0/C1/DEL control characters. */\nexport const ILL_FORMED_TEXT = /[\\p{Cs}\\p{Cc}]/u;\nexport const isWellFormedText = (value: string): boolean => !ILL_FORMED_TEXT.test(value);\nconst textString = () => s.string().check(isWellFormedText);\n/** The one alias rule, shared by identity mutations and every emitted DTO. */\nexport const archiveAliasSchema: Schema<string> = textString().trim().max(24);\n\nexport const archiveAuthorSchema: Schema<{ id: string; name: string }> = s.object({\n id: uuidSchema,\n name: archiveAliasSchema,\n});\nexport const archiveIdentitySchema: Schema<{ id: string; name: string; operator: boolean } | null> = s\n .object({ id: uuidSchema, name: archiveAliasSchema, operator: s.boolean() })\n .nullable();\nexport type ArchiveIdentity = InferOutput<typeof archiveIdentitySchema>;\n/** The issuer account metadata export; its id is the session subject, not a publisher id. */\nexport const archiveAccountSchema: Schema<{\n createdAt: string;\n email: string;\n id: string;\n lastSignInAt: string | null;\n}> = s.object({\n createdAt: isoTimestampSchema,\n email: s.string().email(),\n id: uuidSchema,\n lastSignInAt: isoTimestampSchema.nullable(),\n});\nexport type ArchiveAccount = InferOutput<typeof archiveAccountSchema>;\nexport const archiveLikedIdsSchema: Schema<{ ids: string[] }> = s.object({ ids: s.array(uuidSchema) });\nexport const archiveLikesPageSchema: Schema<{ cursor: string | null; ids: string[] }> = s.object({\n cursor: s.string().nullable(),\n ids: s.array(uuidSchema),\n});\nexport type ArchiveLikesPage = InferOutput<typeof archiveLikesPageSchema>;\nexport const archiveLikeStateSchema: Schema<{ id: string; likeCount: number; liked: boolean }> = s.object({\n id: uuidSchema,\n likeCount: s.number().int().min(0).max(Number.MAX_SAFE_INTEGER),\n liked: s.boolean(),\n});\n\n/** Application bounds shared by handlers, the health route, and clients. */\nexport const ARCHIVE_LIMITS = Object.freeze({\n aliasChars: 24,\n cursorChars: 1024,\n idempotencyRetentionMs: 48 * 60 * 60 * 1000,\n likeStateIds: 50,\n maxPageSize: 50,\n maxPublications: 50,\n pageSize: 10,\n payloadBytes: 8192,\n publicCacheSeconds: 30,\n /** One free-text moderation reason: trimmed, non-empty, at most this many chars. */\n reportReasonChars: 256,\n requestBytes: 12 * 1024,\n searchChars: 64,\n searchTerms: 6,\n tagsPerEntry: 16,\n titleChars: 128,\n /** One declared filter or tag value: well-formed, non-empty, at most this many chars. */\n vocabChars: 64,\n});\nexport const archiveLimitsSchema: Schema<{\n aliasChars: number;\n cursorChars: number;\n idempotencyRetentionMs: number;\n likeStateIds: number;\n maxPageSize: number;\n maxPublications: number;\n pageSize: number;\n payloadBytes: number;\n publicCacheSeconds: number;\n reportReasonChars: number;\n requestBytes: number;\n searchChars: number;\n searchTerms: number;\n tagsPerEntry: number;\n titleChars: number;\n vocabChars: number;\n}> = s.object({\n aliasChars: s.number().int().min(1),\n cursorChars: s.number().int().min(1),\n idempotencyRetentionMs: s.number().int().min(1),\n likeStateIds: s.number().int().min(1),\n maxPageSize: s.number().int().min(1),\n maxPublications: s.number().int().min(1),\n pageSize: s.number().int().min(1),\n payloadBytes: s.number().int().min(1),\n publicCacheSeconds: s.number().int().min(0),\n reportReasonChars: s.number().int().min(1),\n requestBytes: s.number().int().min(1),\n searchChars: s.number().int().min(1),\n searchTerms: s.number().int().min(1),\n tagsPerEntry: s.number().int().min(1),\n titleChars: s.number().int().min(1),\n vocabChars: s.number().int().min(1),\n});\nexport const archiveHealthSchema: Schema<{\n /** The storage schema stamp (`archive_schema_meta`) the database actually carries. */\n dbSchemaVersion: number | null;\n features: { likes: boolean; publishing: boolean };\n limits: InferOutput<typeof archiveLimitsSchema>;\n schemaVersion: 1;\n /** 'degraded' when the database's storage schema does not match the Worker's. */\n status: 'ok' | 'degraded';\n reason: 'database-unavailable' | 'schema-mismatch' | null;\n}> = s.object({\n dbSchemaVersion: s.number().int().min(0).nullable(),\n features: s.object({ likes: s.boolean(), publishing: s.boolean() }),\n limits: archiveLimitsSchema,\n reason: s.enum(['database-unavailable', 'schema-mismatch'] as const).nullable(),\n schemaVersion: s.literal(ARCHIVE_CONTRACT_VERSION),\n status: s.enum(['ok', 'degraded'] as const),\n});\nexport type ArchiveHealth = InferOutput<typeof archiveHealthSchema>;\n\nexport const archiveAuthHealthSchema: Schema<{\n dbSchemaVersion: number | null;\n schemaVersion: 1;\n status: 'ok' | 'degraded';\n reason: 'configuration-unavailable' | 'database-unavailable' | 'schema-mismatch' | null;\n}> = s.object({\n dbSchemaVersion: s.number().int().min(0).nullable(),\n reason: s.enum(['configuration-unavailable', 'database-unavailable', 'schema-mismatch'] as const).nullable(),\n schemaVersion: s.literal(AUTH_SCHEMA_VERSION),\n status: s.enum(['ok', 'degraded'] as const),\n});\nexport type AuthHealth = InferOutput<typeof archiveAuthHealthSchema>;\n\n/** The Worker's full error-code vocabulary — the contract both sides test against. */\nexport const ARCHIVE_ERROR_CODES = [\n 'account-changed',\n 'auth-unavailable',\n 'bad-request',\n 'conflict',\n 'forbidden',\n 'gone',\n 'internal',\n 'invalid-payload',\n 'likes-disabled',\n 'method-not-allowed',\n 'not-found',\n 'publisher-changed',\n 'publishing-disabled',\n 'quota',\n 'rate-limited',\n 'record-unavailable',\n 'timeout',\n 'too-large',\n 'unauthenticated',\n 'unavailable',\n 'unsupported-media',\n] as const;\nexport type ArchiveErrorCode = (typeof ARCHIVE_ERROR_CODES)[number];\n\n/**\n * The error envelope every route answers failures with: `{ error: { code, message,\n * requestId } }`. Clients validate against this one schema — an envelope carrying an\n * unknown code or malformed fields is not an archive error at all.\n */\nexport const archiveErrorResponseSchema: Schema<{\n error: { code: ArchiveErrorCode; message: string; requestId: string };\n}> = s\n .object({\n error: s\n .object({\n code: s.enum(ARCHIVE_ERROR_CODES),\n message: s.string().min(1).max(256),\n requestId: uuidSchema,\n })\n .strict(),\n })\n .strict();\nexport type ArchiveErrorResponse = InferOutput<typeof archiveErrorResponseSchema>;\n\n/** The sign-out acknowledgement: the only non-collection response body, shared by both sides. */\nexport const archiveOkSchema: Schema<{ ok: true }> = s.object({ ok: s.literal(true) }).strict();\n\n/** One collection's public self-description: its name and declared query vocabularies. */\nexport const archiveCollectionMetaSchema: Schema<{\n filters: string[];\n name: string;\n tags: string[];\n}> = s.object({\n filters: s.array(s.string().min(1).max(ARCHIVE_LIMITS.vocabChars)),\n name: s.string().regex(ARCHIVE_COLLECTION_NAME_PATTERN),\n tags: s.array(s.string().min(1).max(ARCHIVE_LIMITS.vocabChars)),\n});\nexport type ArchiveCollectionMeta = InferOutput<typeof archiveCollectionMetaSchema>;\n\n/** One reader report an operator reviews: what was reported, why, and by whom. */\nexport const archiveReportsSchema: Schema<{\n cursor: string | null;\n reports: {\n id: string;\n createdAt: string;\n entryId: string;\n entryTitle: string;\n reason: string;\n reporter: { id: string; name: string };\n resolvedAt: string | null;\n }[];\n}> = s.object({\n cursor: s.string().nullable(),\n reports: s.array(\n s.object({\n createdAt: isoTimestampSchema,\n entryId: uuidSchema,\n entryTitle: s.string().min(1).max(ARCHIVE_LIMITS.titleChars),\n id: uuidSchema,\n reason: s.string().min(1).max(ARCHIVE_LIMITS.reportReasonChars),\n reporter: archiveAuthorSchema,\n resolvedAt: isoTimestampSchema.nullable(),\n }),\n ),\n});\nexport type ArchiveReports = InferOutput<typeof archiveReportsSchema>;\nexport const archiveOwnReportsSchema: Schema<{\n cursor: string | null;\n reports: {\n collection: string;\n createdAt: string;\n entryId: string;\n id: string;\n reason: string;\n resolvedAt: string | null;\n }[];\n}> = s.object({\n cursor: s.string().nullable(),\n reports: s.array(\n s.object({\n collection: s.string().regex(ARCHIVE_COLLECTION_NAME_PATTERN),\n createdAt: isoTimestampSchema,\n entryId: uuidSchema,\n id: uuidSchema,\n reason: s.string().min(1).max(ARCHIVE_LIMITS.reportReasonChars),\n resolvedAt: isoTimestampSchema.nullable(),\n }),\n ),\n});\nexport type ArchiveOwnReports = InferOutput<typeof archiveOwnReportsSchema>;\n\n/** The moderation actions an operator can take; the audit log's whole vocabulary. */\nexport const ARCHIVE_MODERATION_ACTIONS = ['hide', 'unhide', 'remove', 'erase-publisher'] as const;\nexport type ArchiveModerationAction = (typeof ARCHIVE_MODERATION_ACTIONS)[number];\n\n/**\n * The operator accountability log: one row per effective moderation action, newest\n * first. Operator and target travel as opaque ids only — no names (they change), no\n * content — so the log stays honest after renames and survives the erasures it records.\n */\nexport const archiveModerationLogSchema: Schema<{\n cursor: string | null;\n actions: {\n id: string;\n action: ArchiveModerationAction;\n collection: string | null;\n createdAt: string;\n operatorId: string;\n targetId: string;\n }[];\n}> = s.object({\n actions: s.array(\n s.object({\n action: s.enum(ARCHIVE_MODERATION_ACTIONS),\n collection: s.string().regex(ARCHIVE_COLLECTION_NAME_PATTERN).nullable(),\n createdAt: isoTimestampSchema,\n id: uuidSchema,\n operatorId: uuidSchema,\n targetId: uuidSchema,\n }),\n ),\n cursor: s.string().nullable(),\n});\nexport type ArchiveModerationLog = InferOutput<typeof archiveModerationLogSchema>;\n\n/** How the online list ranks entries: explicit modes only, no vague composites. */\nexport type ArchiveSort = 'liked' | 'recent';\nexport const archiveSortSchema: Schema<ArchiveSort> = s.enum(['liked', 'recent'] as const);\n\n/**\n * One page of archive entries. Every list in the package pages forward-only: the\n * cursor walks toward the oldest entry and is null after the last page.\n */\nexport interface ArchivePage<T> {\n /** Cursor for the next page; null after the last. */\n cursor: string | null;\n entries: readonly T[];\n}\n","export class ArchiveError extends Error {\n constructor(message: string, opts?: ErrorOptions) {\n super(message, opts);\n this.name = new.target.name;\n }\n}\n\nexport class ArchiveDefinitionError extends ArchiveError {}\n\nexport type ArchiveDerivationStage = 'canonicalize' | 'hash' | 'index' | 'schema';\n\n/** A collection callback or core runtime fault, not invalid submitted content. */\nexport class ArchiveDerivationError extends ArchiveError {\n readonly stage: ArchiveDerivationStage;\n\n constructor(stage: ArchiveDerivationStage, message: string, opts?: ErrorOptions) {\n super(message, opts);\n this.stage = stage;\n }\n}\n","import { type Schema, s } from '@vielzeug/spell';\nimport { sha256Hex } from './_crypto';\nimport { canonicalObjectJson } from './_json';\nimport {\n ARCHIVE_COLLECTION_NAME_PATTERN,\n ARCHIVE_CONTRACT_VERSION,\n ARCHIVE_LIMITS,\n type ArchivePage,\n archiveAuthorSchema,\n hex64Schema,\n isoTimestampSchema,\n isWellFormedText,\n uuidSchema,\n} from './contract';\nimport { ArchiveDefinitionError, ArchiveDerivationError, type ArchiveDerivationStage } from './errors';\n\n/**\n * Stored payloads are canonical by construction: `derive` validates, normalizes and\n * byte-pins every payload before it is stored, and the package's schema policy is\n * to reset/reseed databases when canonicalization semantics change. The emitted\n * entry schemas therefore embed the plain payload schema — re-parsing a stored\n * payload re-runs its (write-time-stable, hence idempotent) schema, never a\n * parallel re-canonicalization.\n */\n\n/**\n * The one seam between a deployment's content and the archive core. A collection\n * declares its payload schema and derives its list dimensions; the core owns\n * everything else — parsing, canonical serialization, the content hash, the emitted\n * envelope schemas, and every storage bound. Collections never hash, never size,\n * and never hand-write the envelope.\n */\n\n/** What `index` derives from one validated payload: the list dimensions plus the FTS title. */\nexport interface ArchiveIndexing<F extends string = string, T extends string = string> {\n /** One scalar-filter value from the declared vocabulary, or null for \"no filter\". */\n filter: F | null;\n /** Tag values from the declared vocabulary; duplicates collapse in first-seen order. */\n tags: readonly T[];\n /** The searchable title; the core trims and bounds it. */\n title: string;\n}\n\n/** The definition a deployment writes; `defineArchiveCollection` derives the rest. */\nexport interface ArchiveCollectionDefinition<\n P extends object,\n C extends number,\n F extends string = never,\n T extends string = never,\n> {\n /**\n * Normalizes a parsed payload to its storage form — fixed key order, sorted\n * order-insensitive lists — so equivalent content hashes identically. Omit when\n * the payload is already canonical; a result that leaves the payload schema is\n * a derivation fault at derive time, never stored. Must be idempotent.\n */\n canonicalize?(payload: P): P;\n /** The collection's payload-format version; stored and re-emitted with every entry. */\n contentVersion: C;\n /** Valid scalar-filter values; a query param outside the vocabulary is 400. */\n filters?: readonly F[];\n /** Derives the list dimensions and the searchable title from the canonical payload. */\n index(payload: P): ArchiveIndexing<NoInfer<F>, NoInfer<T>>;\n /** The URL + storage dimension this collection owns: lowercase `[a-z0-9-]`, at most 32 chars. */\n name: string;\n /** The strict payload schema: the whole content contract, parsed before anything derives. */\n payloadSchema: Schema<P, unknown>;\n /** Valid tag values. */\n tags?: readonly T[];\n}\n\n/** Everything the archive stores and re-identifies by, derived once per publish and update. */\nexport interface ArchiveDerivation {\n /** The stored bytes: the canonical payload, serialized with fixed key order. */\n canonicalJson: string;\n /** SHA-256 hex over `{contentVersion, payload}`: identical content hashes identically. */\n contentHash: string;\n /** The collection's declared payload-format version. */\n contentVersion: number;\n filter: string | null;\n tags: readonly string[];\n title: string;\n}\n\n/** The envelope fields every emitted entry carries; the payload stays the collection's. */\nexport interface ArchiveEntry<P = unknown, C extends number = number> {\n author: { id: string; name: string };\n contentHash: string;\n /** The collection's payload-format version, literal-pinned by the definition. */\n contentVersion: C;\n id: string;\n likeCount: number;\n payload: P;\n publishedAt: string;\n revision: number;\n /** The archive wire-contract version, pinned by the core. */\n schemaVersion: typeof ARCHIVE_CONTRACT_VERSION;\n updatedAt: string;\n}\n\n/** The private owner view: the emitted entry plus the create retry key and moderation state. */\nexport interface ArchiveOwnedEntry<P = unknown, C extends number = number> extends ArchiveEntry<P, C> {\n /** The create retry key; public routes never emit it. */\n clientKey: string;\n /** True while an operator has removed the entry from public view (still owned, frozen for edits). */\n hidden: boolean;\n}\n\n/**\n * The wire schemas one collection shares with its client: every request and response\n * envelope for this collection's routes, composed from the payload schema, so the\n * client and the Worker parse the same bytes with the same rules.\n */\nexport interface ArchiveContract<P = unknown, C extends number = number> {\n /** The public entry emitted by list, detail and publish/update responses. */\n entry: Schema<ArchiveEntry<P, C>>;\n /** The own-publications response: `{ entries: ArchiveOwnedEntry[] }`. */\n ownedEntries: Schema<{ entries: ArchiveOwnedEntry<P, C>[] }>;\n /** The private owner entry — the public entry plus the create retry key. */\n ownedEntry: Schema<ArchiveOwnedEntry<P, C>>;\n /** One list page: entries plus the forward/backward cursors around it. */\n page: Schema<ArchivePage<ArchiveEntry<P, C>>>;\n /** The publish request: `{ clientKey, payload }`. */\n publishInput: Schema<{ clientKey: string; payload: P }, unknown>;\n /** The update request: `{ expectedRevision, payload }`. */\n updateInput: Schema<{ expectedRevision: number; payload: P }, unknown>;\n}\n\n/** One registered collection: the derived runtime seam the Worker consumes. */\nexport interface ArchiveCollection<P extends object = object, C extends number = number> {\n readonly contentVersion: C;\n /** The collection's wire schemas, shared with its client. */\n readonly contract: ArchiveContract<P, C>;\n /**\n * Validates an untrusted payload and derives everything the archive stores.\n * Null rejects invalid content: JSON/schema failures, title/tag bounds or the\n * canonical payload byte ceiling. Routes answer 422 `invalid-payload` for null.\n * Callback failures and deployment invariant violations throw ArchiveDerivationError.\n */\n readonly derive: (raw: unknown) => Promise<ArchiveDerivation | null>;\n readonly filters: readonly string[];\n readonly name: string;\n readonly tags: readonly string[];\n}\n\n/** The envelope shape shared by the public and owned compositions. */\nconst envelopeShape = <P, C extends number>(payload: Schema<P>, contentVersion: C) =>\n ({\n author: archiveAuthorSchema,\n contentHash: hex64Schema,\n contentVersion: s.literal(contentVersion),\n id: uuidSchema,\n likeCount: s.number().int().min(0).max(Number.MAX_SAFE_INTEGER),\n payload,\n publishedAt: isoTimestampSchema,\n revision: s.number().int().min(1).max(Number.MAX_SAFE_INTEGER),\n schemaVersion: s.literal(ARCHIVE_CONTRACT_VERSION),\n updatedAt: isoTimestampSchema,\n }) as const;\n\n/**\n * Builds one collection from its definition. Malformed definitions fail here, at\n * registration time — never mid-request: the name must be a routable `[a-z0-9-]`\n * segment, the content version a positive integer, and every declared filter and\n * tag value well-formed text of `1..vocabChars` chars — the bound cursors and the\n * meta route both rely on it. The core derives everything else per payload:\n * parsing, canonical serialization, hashing over the collection's versioned\n * envelope, the emitted-entry schemas, and every storage bound.\n */\nexport function defineArchiveCollection<\n P extends object,\n const C extends number,\n const F extends string = never,\n const T extends string = never,\n>(definition: ArchiveCollectionDefinition<P, C, F, T>): ArchiveCollection<P, C> {\n const { canonicalize, contentVersion, index, name, payloadSchema } = definition;\n if (\n typeof index !== 'function' ||\n !payloadSchema ||\n typeof payloadSchema.safeParse !== 'function' ||\n (canonicalize !== undefined && typeof canonicalize !== 'function')\n ) {\n throw new ArchiveDefinitionError(\n 'Collection requires a payload schema and synchronous indexing/canonicalization functions.',\n );\n }\n if (\n (definition.filters !== undefined && !Array.isArray(definition.filters)) ||\n (definition.tags !== undefined && !Array.isArray(definition.tags))\n ) {\n throw new ArchiveDefinitionError('Collection vocabularies must be arrays.');\n }\n const filters = Object.freeze([...(definition.filters ?? [])]);\n const tags = Object.freeze([...(definition.tags ?? [])]);\n if (typeof name !== 'string' || !ARCHIVE_COLLECTION_NAME_PATTERN.test(name)) {\n throw new ArchiveDefinitionError(`Archive collection name must match [a-z0-9-]{1,32}: ${JSON.stringify(name)}`);\n }\n if (!Number.isSafeInteger(contentVersion) || contentVersion < 1) {\n throw new ArchiveDefinitionError(`Archive collection ${name}: contentVersion must be a safe integer >= 1.`);\n }\n const validateVocabulary = (kind: 'filters' | 'tags', values: readonly string[]): void => {\n for (const value of values) {\n if (\n typeof value !== 'string' ||\n value.length === 0 ||\n value.length > ARCHIVE_LIMITS.vocabChars ||\n !isWellFormedText(value)\n ) {\n throw new ArchiveDefinitionError(\n `Archive collection ${name}: every ${kind} value must be well-formed text of 1..${ARCHIVE_LIMITS.vocabChars} chars.`,\n );\n }\n }\n };\n validateVocabulary('filters', filters);\n validateVocabulary('tags', tags);\n const filterValues = new Set<string>(filters);\n const tagValues = new Set<string>(tags);\n\n const derive = async (raw: unknown): Promise<ArchiveDerivation | null> => {\n let stage: ArchiveDerivationStage = 'schema';\n try {\n if (canonicalObjectJson(raw) === null) return null;\n const parsed = payloadSchema.safeParse(raw);\n if (!parsed.success) return null;\n const parsedJson = canonicalObjectJson(parsed.data, true, raw);\n if (parsedJson === null)\n throw new ArchiveDerivationError(stage, 'Payload schema produced invalid or lossy JSON.');\n stage = 'canonicalize';\n const canonical = canonicalize === undefined ? parsed.data : canonicalize(parsed.data);\n // A canonicalize step that leaves the payload schema is a collection bug, not data to store.\n const normalizedJson = canonicalObjectJson(canonical, true, JSON.parse(parsedJson));\n if (normalizedJson === null) throw new ArchiveDerivationError(stage, 'Canonicalization produced invalid JSON.');\n stage = 'schema';\n const revalidated = payloadSchema.safeParse(JSON.parse(normalizedJson));\n if (!revalidated.success)\n throw new ArchiveDerivationError(\n canonicalize === undefined ? 'schema' : 'canonicalize',\n 'Canonical payload is outside the payload schema.',\n { cause: revalidated.error },\n );\n const canonicalJson = canonicalObjectJson(revalidated.data, true, JSON.parse(normalizedJson));\n if (canonicalJson === null || canonicalJson !== normalizedJson)\n throw new ArchiveDerivationError(stage, 'Payload schema is not stable on canonical JSON.');\n if (canonicalize !== undefined) {\n const repeatedPayload = payloadSchema.parse(JSON.parse(canonicalJson));\n stage = 'canonicalize';\n const repeated = canonicalize(repeatedPayload);\n if (canonicalObjectJson(repeated, true) !== canonicalJson)\n throw new ArchiveDerivationError(stage, 'Canonicalization is not idempotent.');\n }\n\n stage = 'index';\n const { filter, tags: rawTags, title: rawTitle } = index(revalidated.data);\n // Indexing may read the final parsed value, but must not change the stored content.\n if (canonicalObjectJson(revalidated.data, true) !== canonicalJson)\n throw new ArchiveDerivationError(stage, 'Indexing mutated the canonical payload.');\n if (typeof rawTitle !== 'string' || !Array.isArray(rawTags))\n throw new ArchiveDerivationError(stage, 'Indexing must return a string title and a tags array.');\n const title = rawTitle.trim();\n if (title.length === 0 || title.length > ARCHIVE_LIMITS.titleChars || !isWellFormedText(title)) return null;\n if (filter !== null && (typeof filter !== 'string' || !isWellFormedText(filter)))\n throw new ArchiveDerivationError(stage, 'Indexing returned an invalid filter.');\n const uniqueTags: string[] = [];\n for (const tag of rawTags) {\n if (typeof tag !== 'string' || !isWellFormedText(tag))\n throw new ArchiveDerivationError(stage, 'Indexing returned an invalid tag.');\n if (!uniqueTags.includes(tag)) uniqueTags.push(tag);\n }\n // A derivation outside the declared vocabulary would store a row no list query\n // can reach — the query route 400s the very value the collection derived.\n if ((filter !== null && !filterValues.has(filter)) || uniqueTags.some((tag) => !tagValues.has(tag)))\n throw new ArchiveDerivationError(stage, 'Indexing returned a value outside the declared vocabularies.');\n if (uniqueTags.length > ARCHIVE_LIMITS.tagsPerEntry) return null;\n\n if (new TextEncoder().encode(canonicalJson).byteLength > ARCHIVE_LIMITS.payloadBytes) return null;\n stage = 'hash';\n const contentHash = await sha256Hex(`{\"contentVersion\":${contentVersion},\"payload\":${canonicalJson}}`);\n return { canonicalJson, contentHash, contentVersion, filter, tags: uniqueTags, title };\n } catch (cause) {\n if (cause instanceof ArchiveDerivationError) throw cause;\n throw new ArchiveDerivationError(stage, 'Collection content derivation failed.', { cause });\n }\n };\n\n // The cast pins the envelope's payload member to the collection's output type:\n // `payloadSchema` is `Schema<P, unknown>` (input unknown), and inference through\n // the generic shape helper would widen the member to `unknown`.\n const entrySchema: Schema<ArchiveEntry<P, C>> = s.object(envelopeShape(payloadSchema as Schema<P>, contentVersion));\n const ownedEntrySchema: Schema<ArchiveOwnedEntry<P, C>> = s.object({\n ...envelopeShape(payloadSchema as Schema<P>, contentVersion),\n clientKey: uuidSchema,\n hidden: s.boolean(),\n });\n const contract: ArchiveContract<P, C> = {\n entry: entrySchema,\n ownedEntries: s.object({ entries: s.array(ownedEntrySchema) }),\n ownedEntry: ownedEntrySchema,\n page: s.object({\n cursor: s.string().nullable(),\n entries: s.array(entrySchema),\n }),\n publishInput: s.object({ clientKey: uuidSchema, payload: payloadSchema }),\n updateInput: s.object({\n expectedRevision: s.number().int().min(1).max(Number.MAX_SAFE_INTEGER),\n payload: payloadSchema,\n }),\n };\n\n return Object.freeze({ contentVersion, contract: Object.freeze(contract), derive, filters, name, tags });\n}\n"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ var Archive=(function(e,t){Object.defineProperty(e,Symbol.toStringTag,{value:`Module`});var sha256Hex=async e=>[...new Uint8Array(await crypto.subtle.digest(`SHA-256`,new TextEncoder().encode(e)))].map(e=>e.toString(16).padStart(2,`0`)).join(``);function canonicalJson(e,t=!1,n){let r=new Set,text=e=>/[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?<![\uD800-\uDBFF])[\uDC00-\uDFFF]/u.test(e)?null:JSON.stringify(e),serialize=(e,n)=>{if(e===null)return`null`;if(typeof e==`string`)return text(e);if(typeof e==`boolean`)return String(e);if(typeof e==`number`)return Number.isFinite(e)?JSON.stringify(e):null;if(typeof e!=`object`||r.has(e))return null;let i=Array.isArray(e),a=Object.getPrototypeOf(e);if(!i&&a!==Object.prototype&&a!==null||i&&a!==Array.prototype)return null;r.add(e);try{let r=[],a=Reflect.ownKeys(e);if(i){if(a.length!==e.length+1)return null;for(let t=0;t<e.length;t++){let i=Object.getOwnPropertyDescriptor(e,String(t));if(!i||!i.enumerable||!(`value`in i))return null;let a=serialize(i.value,Array.isArray(n)?n[t]:void 0);if(a===null)return null;r.push(a)}return`[${r.join(`,`)}]`}if(a.some(e=>typeof e!=`string`))return null;for(let i of Object.keys(e).sort()){let a=Object.getOwnPropertyDescriptor(e,i);if(!a||!(`value`in a))return null;let o=typeof n==`object`&&n?n:null;if(a.value===void 0&&t&&(o===null||!Object.hasOwn(o,i)))continue;let s=text(i),c=serialize(a.value,o===null?void 0:Reflect.get(o,i));if(s===null||c===null)return null;r.push(`${s}:${c}`)}return Object.keys(e).length===a.length?`{${r.join(`,`)}}`:null}finally{r.delete(e)}};try{return serialize(e,n)}catch{return null}}function canonicalObjectJson(e,t=!1,n){return typeof e!=`object`||!e||Array.isArray(e)?null:canonicalJson(e,t,n)}var n=`archive_session`,r=`/api/v1`,i=2592e3,a=3600,sessionCookieValue=(e,t)=>`${n}=${e}; HttpOnly; SameSite=Strict; Path=${r}; Max-Age=${t.maxAgeSeconds}${t.secure?`; Secure`:``}`,o=`x-archive-publisher`,s=`X-Archive-Account`,c=`x-archive-request`,l=1,u=1,d=1,f=`archive-operator`,p=/^[a-z0-9-]{1,32}$/,m=t.s.string().uuid(),h=t.s.string().isoDateTime(),g=t.s.string().regex(/^[0-9a-f]{64}$/),_=/[\p{Cs}\p{Cc}]/u,isWellFormedText=e=>!_.test(e),textString=()=>t.s.string().check(isWellFormedText),v=textString().trim().max(24),y=t.s.object({id:m,name:v}),b=t.s.object({id:m,name:v,operator:t.s.boolean()}).nullable(),x=t.s.object({createdAt:h,email:t.s.string().email(),id:m,lastSignInAt:h.nullable()}),S=t.s.object({ids:t.s.array(m)}),C=t.s.object({cursor:t.s.string().nullable(),ids:t.s.array(m)}),w=t.s.object({id:m,likeCount:t.s.number().int().min(0).max(2**53-1),liked:t.s.boolean()}),T=Object.freeze({aliasChars:24,cursorChars:1024,idempotencyRetentionMs:1728e5,likeStateIds:50,maxPageSize:50,maxPublications:50,pageSize:10,payloadBytes:8192,publicCacheSeconds:30,reportReasonChars:256,requestBytes:12288,searchChars:64,searchTerms:6,tagsPerEntry:16,titleChars:128,vocabChars:64}),E=t.s.object({aliasChars:t.s.number().int().min(1),cursorChars:t.s.number().int().min(1),idempotencyRetentionMs:t.s.number().int().min(1),likeStateIds:t.s.number().int().min(1),maxPageSize:t.s.number().int().min(1),maxPublications:t.s.number().int().min(1),pageSize:t.s.number().int().min(1),payloadBytes:t.s.number().int().min(1),publicCacheSeconds:t.s.number().int().min(0),reportReasonChars:t.s.number().int().min(1),requestBytes:t.s.number().int().min(1),searchChars:t.s.number().int().min(1),searchTerms:t.s.number().int().min(1),tagsPerEntry:t.s.number().int().min(1),titleChars:t.s.number().int().min(1),vocabChars:t.s.number().int().min(1)}),D=t.s.object({dbSchemaVersion:t.s.number().int().min(0).nullable(),features:t.s.object({likes:t.s.boolean(),publishing:t.s.boolean()}),limits:E,reason:t.s.enum([`database-unavailable`,`schema-mismatch`]).nullable(),schemaVersion:t.s.literal(1),status:t.s.enum([`ok`,`degraded`])}),O=t.s.object({dbSchemaVersion:t.s.number().int().min(0).nullable(),reason:t.s.enum([`configuration-unavailable`,`database-unavailable`,`schema-mismatch`]).nullable(),schemaVersion:t.s.literal(1),status:t.s.enum([`ok`,`degraded`])}),k=[`account-changed`,`auth-unavailable`,`bad-request`,`conflict`,`forbidden`,`gone`,`internal`,`invalid-payload`,`likes-disabled`,`method-not-allowed`,`not-found`,`publisher-changed`,`publishing-disabled`,`quota`,`rate-limited`,`record-unavailable`,`timeout`,`too-large`,`unauthenticated`,`unavailable`,`unsupported-media`],A=t.s.object({error:t.s.object({code:t.s.enum(k),message:t.s.string().min(1).max(256),requestId:m}).strict()}).strict(),j=t.s.object({ok:t.s.literal(!0)}).strict(),M=t.s.object({filters:t.s.array(t.s.string().min(1).max(T.vocabChars)),name:t.s.string().regex(p),tags:t.s.array(t.s.string().min(1).max(T.vocabChars))}),N=t.s.object({cursor:t.s.string().nullable(),reports:t.s.array(t.s.object({createdAt:h,entryId:m,entryTitle:t.s.string().min(1).max(T.titleChars),id:m,reason:t.s.string().min(1).max(T.reportReasonChars),reporter:y,resolvedAt:h.nullable()}))}),P=t.s.object({cursor:t.s.string().nullable(),reports:t.s.array(t.s.object({collection:t.s.string().regex(p),createdAt:h,entryId:m,id:m,reason:t.s.string().min(1).max(T.reportReasonChars),resolvedAt:h.nullable()}))}),F=[`hide`,`unhide`,`remove`,`erase-publisher`],I=t.s.object({actions:t.s.array(t.s.object({action:t.s.enum(F),collection:t.s.string().regex(p).nullable(),createdAt:h,id:m,operatorId:m,targetId:m})),cursor:t.s.string().nullable()}),L=t.s.enum([`liked`,`recent`]),ArchiveError=class extends Error{constructor(e,t){super(e,t),this.name=new.target.name}},ArchiveDefinitionError=class extends ArchiveError{},ArchiveDerivationError=class extends ArchiveError{stage;constructor(e,t,n){super(t,n),this.stage=e}},envelopeShape=(e,n)=>({author:y,contentHash:g,contentVersion:t.s.literal(n),id:m,likeCount:t.s.number().int().min(0).max(2**53-1),payload:e,publishedAt:h,revision:t.s.number().int().min(1).max(2**53-1),schemaVersion:t.s.literal(1),updatedAt:h});function defineArchiveCollection(e){let{canonicalize:n,contentVersion:r,index:i,name:a,payloadSchema:o}=e;if(typeof i!=`function`||!o||typeof o.safeParse!=`function`||n!==void 0&&typeof n!=`function`)throw new ArchiveDefinitionError(`Collection requires a payload schema and synchronous indexing/canonicalization functions.`);if(e.filters!==void 0&&!Array.isArray(e.filters)||e.tags!==void 0&&!Array.isArray(e.tags))throw new ArchiveDefinitionError(`Collection vocabularies must be arrays.`);let s=Object.freeze([...e.filters??[]]),c=Object.freeze([...e.tags??[]]);if(typeof a!=`string`||!p.test(a))throw new ArchiveDefinitionError(`Archive collection name must match [a-z0-9-]{1,32}: ${JSON.stringify(a)}`);if(!Number.isSafeInteger(r)||r<1)throw new ArchiveDefinitionError(`Archive collection ${a}: contentVersion must be a safe integer >= 1.`);let validateVocabulary=(e,t)=>{for(let n of t)if(typeof n!=`string`||n.length===0||n.length>T.vocabChars||!isWellFormedText(n))throw new ArchiveDefinitionError(`Archive collection ${a}: every ${e} value must be well-formed text of 1..${T.vocabChars} chars.`)};validateVocabulary(`filters`,s),validateVocabulary(`tags`,c);let l=new Set(s),u=new Set(c),derive=async e=>{let t=`schema`;try{if(canonicalObjectJson(e)===null)return null;let a=o.safeParse(e);if(!a.success)return null;let s=canonicalObjectJson(a.data,!0,e);if(s===null)throw new ArchiveDerivationError(t,`Payload schema produced invalid or lossy JSON.`);t=`canonicalize`;let c=canonicalObjectJson(n===void 0?a.data:n(a.data),!0,JSON.parse(s));if(c===null)throw new ArchiveDerivationError(t,`Canonicalization produced invalid JSON.`);t=`schema`;let d=o.safeParse(JSON.parse(c));if(!d.success)throw new ArchiveDerivationError(n===void 0?`schema`:`canonicalize`,`Canonical payload is outside the payload schema.`,{cause:d.error});let f=canonicalObjectJson(d.data,!0,JSON.parse(c));if(f===null||f!==c)throw new ArchiveDerivationError(t,`Payload schema is not stable on canonical JSON.`);if(n!==void 0){let e=o.parse(JSON.parse(f));if(t=`canonicalize`,canonicalObjectJson(n(e),!0)!==f)throw new ArchiveDerivationError(t,`Canonicalization is not idempotent.`)}t=`index`;let{filter:p,tags:m,title:h}=i(d.data);if(canonicalObjectJson(d.data,!0)!==f)throw new ArchiveDerivationError(t,`Indexing mutated the canonical payload.`);if(typeof h!=`string`||!Array.isArray(m))throw new ArchiveDerivationError(t,`Indexing must return a string title and a tags array.`);let g=h.trim();if(g.length===0||g.length>T.titleChars||!isWellFormedText(g))return null;if(p!==null&&(typeof p!=`string`||!isWellFormedText(p)))throw new ArchiveDerivationError(t,`Indexing returned an invalid filter.`);let _=[];for(let e of m){if(typeof e!=`string`||!isWellFormedText(e))throw new ArchiveDerivationError(t,`Indexing returned an invalid tag.`);_.includes(e)||_.push(e)}if(p!==null&&!l.has(p)||_.some(e=>!u.has(e)))throw new ArchiveDerivationError(t,`Indexing returned a value outside the declared vocabularies.`);return _.length>T.tagsPerEntry||new TextEncoder().encode(f).byteLength>T.payloadBytes?null:(t=`hash`,{canonicalJson:f,contentHash:await sha256Hex(`{"contentVersion":${r},"payload":${f}}`),contentVersion:r,filter:p,tags:_,title:g})}catch(e){throw e instanceof ArchiveDerivationError?e:new ArchiveDerivationError(t,`Collection content derivation failed.`,{cause:e})}},d=t.s.object(envelopeShape(o,r)),f=t.s.object({...envelopeShape(o,r),clientKey:m,hidden:t.s.boolean()}),h={entry:d,ownedEntries:t.s.object({entries:t.s.array(f)}),ownedEntry:f,page:t.s.object({cursor:t.s.string().nullable(),entries:t.s.array(d)}),publishInput:t.s.object({clientKey:m,payload:o}),updateInput:t.s.object({expectedRevision:t.s.number().int().min(1).max(2**53-1),payload:o})};return Object.freeze({contentVersion:r,contract:Object.freeze(h),derive,filters:s,name:a,tags:c})}return e.ACCOUNT_HEADER=s,e.ARCHIVE_COLLECTION_NAME_PATTERN=p,e.ARCHIVE_CONTRACT_VERSION=l,e.ARCHIVE_ERROR_CODES=k,e.ARCHIVE_LIMITS=T,e.ARCHIVE_MODERATION_ACTIONS=F,e.ARCHIVE_OPERATOR_ROLE=f,e.ARCHIVE_SCHEMA_VERSION=u,e.AUTH_SCHEMA_VERSION=d,e.ArchiveDefinitionError=ArchiveDefinitionError,e.ArchiveDerivationError=ArchiveDerivationError,e.ArchiveError=ArchiveError,e.ILL_FORMED_TEXT=_,e.OPERATOR_SESSION_MAX_AGE_SECONDS=a,e.PUBLISHER_HEADER=o,e.REQUEST_MARKER_HEADER=c,e.SESSION_COOKIE_NAME=n,e.SESSION_COOKIE_PATH=r,e.SESSION_MAX_AGE_SECONDS=i,e.archiveAccountSchema=x,e.archiveAliasSchema=v,e.archiveAuthHealthSchema=O,e.archiveAuthorSchema=y,e.archiveCollectionMetaSchema=M,e.archiveErrorResponseSchema=A,e.archiveHealthSchema=D,e.archiveIdentitySchema=b,e.archiveLikeStateSchema=w,e.archiveLikedIdsSchema=S,e.archiveLikesPageSchema=C,e.archiveLimitsSchema=E,e.archiveModerationLogSchema=I,e.archiveOkSchema=j,e.archiveOwnReportsSchema=P,e.archiveReportsSchema=N,e.archiveSortSchema=L,e.defineArchiveCollection=defineArchiveCollection,e.hex64Schema=g,e.isWellFormedText=isWellFormedText,e.isoTimestampSchema=h,e.sessionCookieValue=sessionCookieValue,e.uuidSchema=m,e})({},Spell);
2
+ //# sourceMappingURL=archive.iife.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"archive.iife.js","names":["s","s","exports","text","byte","active","value","array","prototype","fields","keys","i","descriptor","item","source","key","sourceObject","omitUndefinedFields","name","omissionSource","SESSION_COOKIE_NAME","SESSION_COOKIE_PATH","SESSION_MAX_AGE_SECONDS","OPERATOR_SESSION_MAX_AGE_SECONDS","token","options","PUBLISHER_HEADER","ACCOUNT_HEADER","REQUEST_MARKER_HEADER","ARCHIVE_CONTRACT_VERSION","ARCHIVE_SCHEMA_VERSION","AUTH_SCHEMA_VERSION","ARCHIVE_OPERATOR_ROLE","ARCHIVE_COLLECTION_NAME_PATTERN","uuidSchema","_vielzeug_spell","isoTimestampSchema","hex64Schema","ILL_FORMED_TEXT","archiveAliasSchema","archiveAuthorSchema","archiveIdentitySchema","archiveAccountSchema","archiveLikedIdsSchema","archiveLikesPageSchema","archiveLikeStateSchema","ARCHIVE_LIMITS","archiveLimitsSchema","archiveHealthSchema","archiveAuthHealthSchema","ARCHIVE_ERROR_CODES","archiveErrorResponseSchema","archiveOkSchema","archiveCollectionMetaSchema","archiveReportsSchema","archiveOwnReportsSchema","ARCHIVE_MODERATION_ACTIONS","archiveModerationLogSchema","archiveSortSchema","message","opts","stage","contentVersion","definition","index","payloadSchema","canonicalize","filters","tags","values","kind","filterValues","tagValues","raw","parsed","parsedJson","normalizedJson","revalidated","canonicalJson","repeatedPayload","rawTags","rawTitle","title","filter","uniqueTags","tag","cause","entrySchema","ownedEntrySchema","contract"],"sources":["../src/_crypto.ts","../src/_json.ts","../src/contract.ts","../src/errors.ts","../src/collection.ts"],"sourcesContent":["/**\n * The one SHA-256→hex helper shared by both server surfaces: the collection content\n * hash (browser-safe root) and the issuer's sign-in-link token hash. Web Crypto\n * only; no D1, JWKS or binding machinery.\n */\nexport const sha256Hex = async (text: string): Promise<string> =>\n [...new Uint8Array(await crypto.subtle.digest('SHA-256', new TextEncoder().encode(text)))]\n .map((byte) => byte.toString(16).padStart(2, '0'))\n .join('');\n","/** Canonical JSON rejects values JSON.stringify would silently discard or coerce. */\nexport function canonicalJson(value: unknown, omitUndefinedFields = false, omissionSource?: unknown): string | null {\n const active = new Set<object>();\n const text = (value: string): string | null => {\n if (/[\\uD800-\\uDBFF](?![\\uDC00-\\uDFFF])|(?<![\\uD800-\\uDBFF])[\\uDC00-\\uDFFF]/u.test(value)) return null;\n return JSON.stringify(value);\n };\n const serialize = (value: unknown, source?: unknown): string | null => {\n if (value === null) return 'null';\n if (typeof value === 'string') return text(value);\n if (typeof value === 'boolean') return String(value);\n if (typeof value === 'number') return Number.isFinite(value) ? JSON.stringify(value) : null;\n if (typeof value !== 'object' || active.has(value)) return null;\n const array = Array.isArray(value);\n const prototype = Object.getPrototypeOf(value);\n if (!array && prototype !== Object.prototype && prototype !== null) return null;\n if (array && prototype !== Array.prototype) return null;\n active.add(value);\n try {\n const fields: string[] = [];\n const keys = Reflect.ownKeys(value);\n if (array) {\n if (keys.length !== value.length + 1) return null;\n for (let i = 0; i < value.length; i++) {\n const descriptor = Object.getOwnPropertyDescriptor(value, String(i));\n if (!descriptor || !descriptor.enumerable || !('value' in descriptor)) return null;\n const item = serialize(descriptor.value, Array.isArray(source) ? source[i] : undefined);\n if (item === null) return null;\n fields.push(item);\n }\n return `[${fields.join(',')}]`;\n }\n if (keys.some((key) => typeof key !== 'string')) return null;\n for (const key of Object.keys(value).sort()) {\n const descriptor = Object.getOwnPropertyDescriptor(value, key);\n if (!descriptor || !('value' in descriptor)) return null;\n const sourceObject = source !== null && typeof source === 'object' ? source : null;\n // Spell materializes absent optional object fields as undefined.\n if (\n descriptor.value === undefined &&\n omitUndefinedFields &&\n (sourceObject === null || !Object.hasOwn(sourceObject, key))\n )\n continue;\n const name = text(key);\n const item = serialize(descriptor.value, sourceObject === null ? undefined : Reflect.get(sourceObject, key));\n if (name === null || item === null) return null;\n fields.push(`${name}:${item}`);\n }\n if (Object.keys(value).length !== keys.length) return null;\n return `{${fields.join(',')}}`;\n } finally {\n active.delete(value);\n }\n };\n try {\n return serialize(value, omissionSource);\n } catch {\n return null;\n }\n}\n\nexport function canonicalObjectJson(\n value: unknown,\n omitUndefinedFields = false,\n omissionSource?: unknown,\n): string | null {\n if (value === null || typeof value !== 'object' || Array.isArray(value)) return null;\n return canonicalJson(value, omitUndefinedFields, omissionSource);\n}\n","import { type InferOutput, type Schema, s } from '@vielzeug/spell';\n\n/** Shared naming: one place so the client, Worker and issuer cannot drift. */\nexport const SESSION_COOKIE_NAME = 'archive_session';\nexport const SESSION_COOKIE_PATH = '/api/v1';\n/**\n * The maximum age a session JWT may carry, and the cookie Max-Age an issuer sets:\n * a long-lived signed-in state. The Worker rejects older tokens at this bound.\n */\nexport const SESSION_MAX_AGE_SECONDS = 30 * 24 * 60 * 60;\nexport const OPERATOR_SESSION_MAX_AGE_SECONDS = 60 * 60;\n\n/**\n * The full Set-Cookie value for the session cookie: name, token and the security\n * attributes every issuer and the Worker must agree on — HttpOnly, SameSite=Strict,\n * the contract Path, Max-Age, and Secure in production. Issuers mint with the\n * session's max age; the Worker and issuers clear with `maxAgeSeconds: 0`. Never\n * hand-compose the attributes: the cookie's CSRF and theft posture is contract,\n * not per-issuer choice.\n */\nexport const sessionCookieValue = (token: string, options: { maxAgeSeconds: number; secure: boolean }): string =>\n `${SESSION_COOKIE_NAME}=${token}; HttpOnly; SameSite=Strict; Path=${SESSION_COOKIE_PATH}; Max-Age=${options.maxAgeSeconds}${options.secure ? '; Secure' : ''}`;\n\nexport const PUBLISHER_HEADER = 'x-archive-publisher';\n/** Pins account erasure to the issuer account shown when confirmation began. */\nexport const ACCOUNT_HEADER = 'X-Archive-Account';\nexport const REQUEST_MARKER_HEADER = 'x-archive-request';\n/** The wire-contract version advertised by health and stamped on every entry envelope. */\nexport const ARCHIVE_CONTRACT_VERSION = 1;\n/**\n * The storage schema version: the `archive_schema_meta` stamp the package's migration\n * writes and the Worker reads back through health. A mismatch answers `degraded`\n * instead of `ok` — a stale database is the most likely deployment fault.\n */\nexport const ARCHIVE_SCHEMA_VERSION = 1;\n/** Canonical issuer database initialization stamp. */\nexport const AUTH_SCHEMA_VERSION = 1;\n/** The `roles` claim value a session JWT carries for operator authority (moderation). */\nexport const ARCHIVE_OPERATOR_ROLE = 'archive-operator';\n/** The routable collection-name rule: lowercase `[a-z0-9-]`, at most 32 chars. */\nexport const ARCHIVE_COLLECTION_NAME_PATTERN = /^[a-z0-9-]{1,32}$/;\n\n// Exported schemas carry explicit public `Schema<Output>` annotations: the concrete\n// spell schema classes are not part of spell's public export surface, so inferred\n// types would not be portable across package declaration files.\nexport const uuidSchema: Schema<string> = s.string().uuid();\nexport const isoTimestampSchema: Schema<string> = s.string().isoDateTime();\nexport const hex64Schema: Schema<string> = s.string().regex(/^[0-9a-f]{64}$/);\n/** Well-formed user text: no lone UTF-16 surrogates, no C0/C1/DEL control characters. */\nexport const ILL_FORMED_TEXT = /[\\p{Cs}\\p{Cc}]/u;\nexport const isWellFormedText = (value: string): boolean => !ILL_FORMED_TEXT.test(value);\nconst textString = () => s.string().check(isWellFormedText);\n/** The one alias rule, shared by identity mutations and every emitted DTO. */\nexport const archiveAliasSchema: Schema<string> = textString().trim().max(24);\n\nexport const archiveAuthorSchema: Schema<{ id: string; name: string }> = s.object({\n id: uuidSchema,\n name: archiveAliasSchema,\n});\nexport const archiveIdentitySchema: Schema<{ id: string; name: string; operator: boolean } | null> = s\n .object({ id: uuidSchema, name: archiveAliasSchema, operator: s.boolean() })\n .nullable();\nexport type ArchiveIdentity = InferOutput<typeof archiveIdentitySchema>;\n/** The issuer account metadata export; its id is the session subject, not a publisher id. */\nexport const archiveAccountSchema: Schema<{\n createdAt: string;\n email: string;\n id: string;\n lastSignInAt: string | null;\n}> = s.object({\n createdAt: isoTimestampSchema,\n email: s.string().email(),\n id: uuidSchema,\n lastSignInAt: isoTimestampSchema.nullable(),\n});\nexport type ArchiveAccount = InferOutput<typeof archiveAccountSchema>;\nexport const archiveLikedIdsSchema: Schema<{ ids: string[] }> = s.object({ ids: s.array(uuidSchema) });\nexport const archiveLikesPageSchema: Schema<{ cursor: string | null; ids: string[] }> = s.object({\n cursor: s.string().nullable(),\n ids: s.array(uuidSchema),\n});\nexport type ArchiveLikesPage = InferOutput<typeof archiveLikesPageSchema>;\nexport const archiveLikeStateSchema: Schema<{ id: string; likeCount: number; liked: boolean }> = s.object({\n id: uuidSchema,\n likeCount: s.number().int().min(0).max(Number.MAX_SAFE_INTEGER),\n liked: s.boolean(),\n});\n\n/** Application bounds shared by handlers, the health route, and clients. */\nexport const ARCHIVE_LIMITS = Object.freeze({\n aliasChars: 24,\n cursorChars: 1024,\n idempotencyRetentionMs: 48 * 60 * 60 * 1000,\n likeStateIds: 50,\n maxPageSize: 50,\n maxPublications: 50,\n pageSize: 10,\n payloadBytes: 8192,\n publicCacheSeconds: 30,\n /** One free-text moderation reason: trimmed, non-empty, at most this many chars. */\n reportReasonChars: 256,\n requestBytes: 12 * 1024,\n searchChars: 64,\n searchTerms: 6,\n tagsPerEntry: 16,\n titleChars: 128,\n /** One declared filter or tag value: well-formed, non-empty, at most this many chars. */\n vocabChars: 64,\n});\nexport const archiveLimitsSchema: Schema<{\n aliasChars: number;\n cursorChars: number;\n idempotencyRetentionMs: number;\n likeStateIds: number;\n maxPageSize: number;\n maxPublications: number;\n pageSize: number;\n payloadBytes: number;\n publicCacheSeconds: number;\n reportReasonChars: number;\n requestBytes: number;\n searchChars: number;\n searchTerms: number;\n tagsPerEntry: number;\n titleChars: number;\n vocabChars: number;\n}> = s.object({\n aliasChars: s.number().int().min(1),\n cursorChars: s.number().int().min(1),\n idempotencyRetentionMs: s.number().int().min(1),\n likeStateIds: s.number().int().min(1),\n maxPageSize: s.number().int().min(1),\n maxPublications: s.number().int().min(1),\n pageSize: s.number().int().min(1),\n payloadBytes: s.number().int().min(1),\n publicCacheSeconds: s.number().int().min(0),\n reportReasonChars: s.number().int().min(1),\n requestBytes: s.number().int().min(1),\n searchChars: s.number().int().min(1),\n searchTerms: s.number().int().min(1),\n tagsPerEntry: s.number().int().min(1),\n titleChars: s.number().int().min(1),\n vocabChars: s.number().int().min(1),\n});\nexport const archiveHealthSchema: Schema<{\n /** The storage schema stamp (`archive_schema_meta`) the database actually carries. */\n dbSchemaVersion: number | null;\n features: { likes: boolean; publishing: boolean };\n limits: InferOutput<typeof archiveLimitsSchema>;\n schemaVersion: 1;\n /** 'degraded' when the database's storage schema does not match the Worker's. */\n status: 'ok' | 'degraded';\n reason: 'database-unavailable' | 'schema-mismatch' | null;\n}> = s.object({\n dbSchemaVersion: s.number().int().min(0).nullable(),\n features: s.object({ likes: s.boolean(), publishing: s.boolean() }),\n limits: archiveLimitsSchema,\n reason: s.enum(['database-unavailable', 'schema-mismatch'] as const).nullable(),\n schemaVersion: s.literal(ARCHIVE_CONTRACT_VERSION),\n status: s.enum(['ok', 'degraded'] as const),\n});\nexport type ArchiveHealth = InferOutput<typeof archiveHealthSchema>;\n\nexport const archiveAuthHealthSchema: Schema<{\n dbSchemaVersion: number | null;\n schemaVersion: 1;\n status: 'ok' | 'degraded';\n reason: 'configuration-unavailable' | 'database-unavailable' | 'schema-mismatch' | null;\n}> = s.object({\n dbSchemaVersion: s.number().int().min(0).nullable(),\n reason: s.enum(['configuration-unavailable', 'database-unavailable', 'schema-mismatch'] as const).nullable(),\n schemaVersion: s.literal(AUTH_SCHEMA_VERSION),\n status: s.enum(['ok', 'degraded'] as const),\n});\nexport type AuthHealth = InferOutput<typeof archiveAuthHealthSchema>;\n\n/** The Worker's full error-code vocabulary — the contract both sides test against. */\nexport const ARCHIVE_ERROR_CODES = [\n 'account-changed',\n 'auth-unavailable',\n 'bad-request',\n 'conflict',\n 'forbidden',\n 'gone',\n 'internal',\n 'invalid-payload',\n 'likes-disabled',\n 'method-not-allowed',\n 'not-found',\n 'publisher-changed',\n 'publishing-disabled',\n 'quota',\n 'rate-limited',\n 'record-unavailable',\n 'timeout',\n 'too-large',\n 'unauthenticated',\n 'unavailable',\n 'unsupported-media',\n] as const;\nexport type ArchiveErrorCode = (typeof ARCHIVE_ERROR_CODES)[number];\n\n/**\n * The error envelope every route answers failures with: `{ error: { code, message,\n * requestId } }`. Clients validate against this one schema — an envelope carrying an\n * unknown code or malformed fields is not an archive error at all.\n */\nexport const archiveErrorResponseSchema: Schema<{\n error: { code: ArchiveErrorCode; message: string; requestId: string };\n}> = s\n .object({\n error: s\n .object({\n code: s.enum(ARCHIVE_ERROR_CODES),\n message: s.string().min(1).max(256),\n requestId: uuidSchema,\n })\n .strict(),\n })\n .strict();\nexport type ArchiveErrorResponse = InferOutput<typeof archiveErrorResponseSchema>;\n\n/** The sign-out acknowledgement: the only non-collection response body, shared by both sides. */\nexport const archiveOkSchema: Schema<{ ok: true }> = s.object({ ok: s.literal(true) }).strict();\n\n/** One collection's public self-description: its name and declared query vocabularies. */\nexport const archiveCollectionMetaSchema: Schema<{\n filters: string[];\n name: string;\n tags: string[];\n}> = s.object({\n filters: s.array(s.string().min(1).max(ARCHIVE_LIMITS.vocabChars)),\n name: s.string().regex(ARCHIVE_COLLECTION_NAME_PATTERN),\n tags: s.array(s.string().min(1).max(ARCHIVE_LIMITS.vocabChars)),\n});\nexport type ArchiveCollectionMeta = InferOutput<typeof archiveCollectionMetaSchema>;\n\n/** One reader report an operator reviews: what was reported, why, and by whom. */\nexport const archiveReportsSchema: Schema<{\n cursor: string | null;\n reports: {\n id: string;\n createdAt: string;\n entryId: string;\n entryTitle: string;\n reason: string;\n reporter: { id: string; name: string };\n resolvedAt: string | null;\n }[];\n}> = s.object({\n cursor: s.string().nullable(),\n reports: s.array(\n s.object({\n createdAt: isoTimestampSchema,\n entryId: uuidSchema,\n entryTitle: s.string().min(1).max(ARCHIVE_LIMITS.titleChars),\n id: uuidSchema,\n reason: s.string().min(1).max(ARCHIVE_LIMITS.reportReasonChars),\n reporter: archiveAuthorSchema,\n resolvedAt: isoTimestampSchema.nullable(),\n }),\n ),\n});\nexport type ArchiveReports = InferOutput<typeof archiveReportsSchema>;\nexport const archiveOwnReportsSchema: Schema<{\n cursor: string | null;\n reports: {\n collection: string;\n createdAt: string;\n entryId: string;\n id: string;\n reason: string;\n resolvedAt: string | null;\n }[];\n}> = s.object({\n cursor: s.string().nullable(),\n reports: s.array(\n s.object({\n collection: s.string().regex(ARCHIVE_COLLECTION_NAME_PATTERN),\n createdAt: isoTimestampSchema,\n entryId: uuidSchema,\n id: uuidSchema,\n reason: s.string().min(1).max(ARCHIVE_LIMITS.reportReasonChars),\n resolvedAt: isoTimestampSchema.nullable(),\n }),\n ),\n});\nexport type ArchiveOwnReports = InferOutput<typeof archiveOwnReportsSchema>;\n\n/** The moderation actions an operator can take; the audit log's whole vocabulary. */\nexport const ARCHIVE_MODERATION_ACTIONS = ['hide', 'unhide', 'remove', 'erase-publisher'] as const;\nexport type ArchiveModerationAction = (typeof ARCHIVE_MODERATION_ACTIONS)[number];\n\n/**\n * The operator accountability log: one row per effective moderation action, newest\n * first. Operator and target travel as opaque ids only — no names (they change), no\n * content — so the log stays honest after renames and survives the erasures it records.\n */\nexport const archiveModerationLogSchema: Schema<{\n cursor: string | null;\n actions: {\n id: string;\n action: ArchiveModerationAction;\n collection: string | null;\n createdAt: string;\n operatorId: string;\n targetId: string;\n }[];\n}> = s.object({\n actions: s.array(\n s.object({\n action: s.enum(ARCHIVE_MODERATION_ACTIONS),\n collection: s.string().regex(ARCHIVE_COLLECTION_NAME_PATTERN).nullable(),\n createdAt: isoTimestampSchema,\n id: uuidSchema,\n operatorId: uuidSchema,\n targetId: uuidSchema,\n }),\n ),\n cursor: s.string().nullable(),\n});\nexport type ArchiveModerationLog = InferOutput<typeof archiveModerationLogSchema>;\n\n/** How the online list ranks entries: explicit modes only, no vague composites. */\nexport type ArchiveSort = 'liked' | 'recent';\nexport const archiveSortSchema: Schema<ArchiveSort> = s.enum(['liked', 'recent'] as const);\n\n/**\n * One page of archive entries. Every list in the package pages forward-only: the\n * cursor walks toward the oldest entry and is null after the last page.\n */\nexport interface ArchivePage<T> {\n /** Cursor for the next page; null after the last. */\n cursor: string | null;\n entries: readonly T[];\n}\n","export class ArchiveError extends Error {\n constructor(message: string, opts?: ErrorOptions) {\n super(message, opts);\n this.name = new.target.name;\n }\n}\n\nexport class ArchiveDefinitionError extends ArchiveError {}\n\nexport type ArchiveDerivationStage = 'canonicalize' | 'hash' | 'index' | 'schema';\n\n/** A collection callback or core runtime fault, not invalid submitted content. */\nexport class ArchiveDerivationError extends ArchiveError {\n readonly stage: ArchiveDerivationStage;\n\n constructor(stage: ArchiveDerivationStage, message: string, opts?: ErrorOptions) {\n super(message, opts);\n this.stage = stage;\n }\n}\n","import { type Schema, s } from '@vielzeug/spell';\nimport { sha256Hex } from './_crypto';\nimport { canonicalObjectJson } from './_json';\nimport {\n ARCHIVE_COLLECTION_NAME_PATTERN,\n ARCHIVE_CONTRACT_VERSION,\n ARCHIVE_LIMITS,\n type ArchivePage,\n archiveAuthorSchema,\n hex64Schema,\n isoTimestampSchema,\n isWellFormedText,\n uuidSchema,\n} from './contract';\nimport { ArchiveDefinitionError, ArchiveDerivationError, type ArchiveDerivationStage } from './errors';\n\n/**\n * Stored payloads are canonical by construction: `derive` validates, normalizes and\n * byte-pins every payload before it is stored, and the package's schema policy is\n * to reset/reseed databases when canonicalization semantics change. The emitted\n * entry schemas therefore embed the plain payload schema — re-parsing a stored\n * payload re-runs its (write-time-stable, hence idempotent) schema, never a\n * parallel re-canonicalization.\n */\n\n/**\n * The one seam between a deployment's content and the archive core. A collection\n * declares its payload schema and derives its list dimensions; the core owns\n * everything else — parsing, canonical serialization, the content hash, the emitted\n * envelope schemas, and every storage bound. Collections never hash, never size,\n * and never hand-write the envelope.\n */\n\n/** What `index` derives from one validated payload: the list dimensions plus the FTS title. */\nexport interface ArchiveIndexing<F extends string = string, T extends string = string> {\n /** One scalar-filter value from the declared vocabulary, or null for \"no filter\". */\n filter: F | null;\n /** Tag values from the declared vocabulary; duplicates collapse in first-seen order. */\n tags: readonly T[];\n /** The searchable title; the core trims and bounds it. */\n title: string;\n}\n\n/** The definition a deployment writes; `defineArchiveCollection` derives the rest. */\nexport interface ArchiveCollectionDefinition<\n P extends object,\n C extends number,\n F extends string = never,\n T extends string = never,\n> {\n /**\n * Normalizes a parsed payload to its storage form — fixed key order, sorted\n * order-insensitive lists — so equivalent content hashes identically. Omit when\n * the payload is already canonical; a result that leaves the payload schema is\n * a derivation fault at derive time, never stored. Must be idempotent.\n */\n canonicalize?(payload: P): P;\n /** The collection's payload-format version; stored and re-emitted with every entry. */\n contentVersion: C;\n /** Valid scalar-filter values; a query param outside the vocabulary is 400. */\n filters?: readonly F[];\n /** Derives the list dimensions and the searchable title from the canonical payload. */\n index(payload: P): ArchiveIndexing<NoInfer<F>, NoInfer<T>>;\n /** The URL + storage dimension this collection owns: lowercase `[a-z0-9-]`, at most 32 chars. */\n name: string;\n /** The strict payload schema: the whole content contract, parsed before anything derives. */\n payloadSchema: Schema<P, unknown>;\n /** Valid tag values. */\n tags?: readonly T[];\n}\n\n/** Everything the archive stores and re-identifies by, derived once per publish and update. */\nexport interface ArchiveDerivation {\n /** The stored bytes: the canonical payload, serialized with fixed key order. */\n canonicalJson: string;\n /** SHA-256 hex over `{contentVersion, payload}`: identical content hashes identically. */\n contentHash: string;\n /** The collection's declared payload-format version. */\n contentVersion: number;\n filter: string | null;\n tags: readonly string[];\n title: string;\n}\n\n/** The envelope fields every emitted entry carries; the payload stays the collection's. */\nexport interface ArchiveEntry<P = unknown, C extends number = number> {\n author: { id: string; name: string };\n contentHash: string;\n /** The collection's payload-format version, literal-pinned by the definition. */\n contentVersion: C;\n id: string;\n likeCount: number;\n payload: P;\n publishedAt: string;\n revision: number;\n /** The archive wire-contract version, pinned by the core. */\n schemaVersion: typeof ARCHIVE_CONTRACT_VERSION;\n updatedAt: string;\n}\n\n/** The private owner view: the emitted entry plus the create retry key and moderation state. */\nexport interface ArchiveOwnedEntry<P = unknown, C extends number = number> extends ArchiveEntry<P, C> {\n /** The create retry key; public routes never emit it. */\n clientKey: string;\n /** True while an operator has removed the entry from public view (still owned, frozen for edits). */\n hidden: boolean;\n}\n\n/**\n * The wire schemas one collection shares with its client: every request and response\n * envelope for this collection's routes, composed from the payload schema, so the\n * client and the Worker parse the same bytes with the same rules.\n */\nexport interface ArchiveContract<P = unknown, C extends number = number> {\n /** The public entry emitted by list, detail and publish/update responses. */\n entry: Schema<ArchiveEntry<P, C>>;\n /** The own-publications response: `{ entries: ArchiveOwnedEntry[] }`. */\n ownedEntries: Schema<{ entries: ArchiveOwnedEntry<P, C>[] }>;\n /** The private owner entry — the public entry plus the create retry key. */\n ownedEntry: Schema<ArchiveOwnedEntry<P, C>>;\n /** One list page: entries plus the forward/backward cursors around it. */\n page: Schema<ArchivePage<ArchiveEntry<P, C>>>;\n /** The publish request: `{ clientKey, payload }`. */\n publishInput: Schema<{ clientKey: string; payload: P }, unknown>;\n /** The update request: `{ expectedRevision, payload }`. */\n updateInput: Schema<{ expectedRevision: number; payload: P }, unknown>;\n}\n\n/** One registered collection: the derived runtime seam the Worker consumes. */\nexport interface ArchiveCollection<P extends object = object, C extends number = number> {\n readonly contentVersion: C;\n /** The collection's wire schemas, shared with its client. */\n readonly contract: ArchiveContract<P, C>;\n /**\n * Validates an untrusted payload and derives everything the archive stores.\n * Null rejects invalid content: JSON/schema failures, title/tag bounds or the\n * canonical payload byte ceiling. Routes answer 422 `invalid-payload` for null.\n * Callback failures and deployment invariant violations throw ArchiveDerivationError.\n */\n readonly derive: (raw: unknown) => Promise<ArchiveDerivation | null>;\n readonly filters: readonly string[];\n readonly name: string;\n readonly tags: readonly string[];\n}\n\n/** The envelope shape shared by the public and owned compositions. */\nconst envelopeShape = <P, C extends number>(payload: Schema<P>, contentVersion: C) =>\n ({\n author: archiveAuthorSchema,\n contentHash: hex64Schema,\n contentVersion: s.literal(contentVersion),\n id: uuidSchema,\n likeCount: s.number().int().min(0).max(Number.MAX_SAFE_INTEGER),\n payload,\n publishedAt: isoTimestampSchema,\n revision: s.number().int().min(1).max(Number.MAX_SAFE_INTEGER),\n schemaVersion: s.literal(ARCHIVE_CONTRACT_VERSION),\n updatedAt: isoTimestampSchema,\n }) as const;\n\n/**\n * Builds one collection from its definition. Malformed definitions fail here, at\n * registration time — never mid-request: the name must be a routable `[a-z0-9-]`\n * segment, the content version a positive integer, and every declared filter and\n * tag value well-formed text of `1..vocabChars` chars — the bound cursors and the\n * meta route both rely on it. The core derives everything else per payload:\n * parsing, canonical serialization, hashing over the collection's versioned\n * envelope, the emitted-entry schemas, and every storage bound.\n */\nexport function defineArchiveCollection<\n P extends object,\n const C extends number,\n const F extends string = never,\n const T extends string = never,\n>(definition: ArchiveCollectionDefinition<P, C, F, T>): ArchiveCollection<P, C> {\n const { canonicalize, contentVersion, index, name, payloadSchema } = definition;\n if (\n typeof index !== 'function' ||\n !payloadSchema ||\n typeof payloadSchema.safeParse !== 'function' ||\n (canonicalize !== undefined && typeof canonicalize !== 'function')\n ) {\n throw new ArchiveDefinitionError(\n 'Collection requires a payload schema and synchronous indexing/canonicalization functions.',\n );\n }\n if (\n (definition.filters !== undefined && !Array.isArray(definition.filters)) ||\n (definition.tags !== undefined && !Array.isArray(definition.tags))\n ) {\n throw new ArchiveDefinitionError('Collection vocabularies must be arrays.');\n }\n const filters = Object.freeze([...(definition.filters ?? [])]);\n const tags = Object.freeze([...(definition.tags ?? [])]);\n if (typeof name !== 'string' || !ARCHIVE_COLLECTION_NAME_PATTERN.test(name)) {\n throw new ArchiveDefinitionError(`Archive collection name must match [a-z0-9-]{1,32}: ${JSON.stringify(name)}`);\n }\n if (!Number.isSafeInteger(contentVersion) || contentVersion < 1) {\n throw new ArchiveDefinitionError(`Archive collection ${name}: contentVersion must be a safe integer >= 1.`);\n }\n const validateVocabulary = (kind: 'filters' | 'tags', values: readonly string[]): void => {\n for (const value of values) {\n if (\n typeof value !== 'string' ||\n value.length === 0 ||\n value.length > ARCHIVE_LIMITS.vocabChars ||\n !isWellFormedText(value)\n ) {\n throw new ArchiveDefinitionError(\n `Archive collection ${name}: every ${kind} value must be well-formed text of 1..${ARCHIVE_LIMITS.vocabChars} chars.`,\n );\n }\n }\n };\n validateVocabulary('filters', filters);\n validateVocabulary('tags', tags);\n const filterValues = new Set<string>(filters);\n const tagValues = new Set<string>(tags);\n\n const derive = async (raw: unknown): Promise<ArchiveDerivation | null> => {\n let stage: ArchiveDerivationStage = 'schema';\n try {\n if (canonicalObjectJson(raw) === null) return null;\n const parsed = payloadSchema.safeParse(raw);\n if (!parsed.success) return null;\n const parsedJson = canonicalObjectJson(parsed.data, true, raw);\n if (parsedJson === null)\n throw new ArchiveDerivationError(stage, 'Payload schema produced invalid or lossy JSON.');\n stage = 'canonicalize';\n const canonical = canonicalize === undefined ? parsed.data : canonicalize(parsed.data);\n // A canonicalize step that leaves the payload schema is a collection bug, not data to store.\n const normalizedJson = canonicalObjectJson(canonical, true, JSON.parse(parsedJson));\n if (normalizedJson === null) throw new ArchiveDerivationError(stage, 'Canonicalization produced invalid JSON.');\n stage = 'schema';\n const revalidated = payloadSchema.safeParse(JSON.parse(normalizedJson));\n if (!revalidated.success)\n throw new ArchiveDerivationError(\n canonicalize === undefined ? 'schema' : 'canonicalize',\n 'Canonical payload is outside the payload schema.',\n { cause: revalidated.error },\n );\n const canonicalJson = canonicalObjectJson(revalidated.data, true, JSON.parse(normalizedJson));\n if (canonicalJson === null || canonicalJson !== normalizedJson)\n throw new ArchiveDerivationError(stage, 'Payload schema is not stable on canonical JSON.');\n if (canonicalize !== undefined) {\n const repeatedPayload = payloadSchema.parse(JSON.parse(canonicalJson));\n stage = 'canonicalize';\n const repeated = canonicalize(repeatedPayload);\n if (canonicalObjectJson(repeated, true) !== canonicalJson)\n throw new ArchiveDerivationError(stage, 'Canonicalization is not idempotent.');\n }\n\n stage = 'index';\n const { filter, tags: rawTags, title: rawTitle } = index(revalidated.data);\n // Indexing may read the final parsed value, but must not change the stored content.\n if (canonicalObjectJson(revalidated.data, true) !== canonicalJson)\n throw new ArchiveDerivationError(stage, 'Indexing mutated the canonical payload.');\n if (typeof rawTitle !== 'string' || !Array.isArray(rawTags))\n throw new ArchiveDerivationError(stage, 'Indexing must return a string title and a tags array.');\n const title = rawTitle.trim();\n if (title.length === 0 || title.length > ARCHIVE_LIMITS.titleChars || !isWellFormedText(title)) return null;\n if (filter !== null && (typeof filter !== 'string' || !isWellFormedText(filter)))\n throw new ArchiveDerivationError(stage, 'Indexing returned an invalid filter.');\n const uniqueTags: string[] = [];\n for (const tag of rawTags) {\n if (typeof tag !== 'string' || !isWellFormedText(tag))\n throw new ArchiveDerivationError(stage, 'Indexing returned an invalid tag.');\n if (!uniqueTags.includes(tag)) uniqueTags.push(tag);\n }\n // A derivation outside the declared vocabulary would store a row no list query\n // can reach — the query route 400s the very value the collection derived.\n if ((filter !== null && !filterValues.has(filter)) || uniqueTags.some((tag) => !tagValues.has(tag)))\n throw new ArchiveDerivationError(stage, 'Indexing returned a value outside the declared vocabularies.');\n if (uniqueTags.length > ARCHIVE_LIMITS.tagsPerEntry) return null;\n\n if (new TextEncoder().encode(canonicalJson).byteLength > ARCHIVE_LIMITS.payloadBytes) return null;\n stage = 'hash';\n const contentHash = await sha256Hex(`{\"contentVersion\":${contentVersion},\"payload\":${canonicalJson}}`);\n return { canonicalJson, contentHash, contentVersion, filter, tags: uniqueTags, title };\n } catch (cause) {\n if (cause instanceof ArchiveDerivationError) throw cause;\n throw new ArchiveDerivationError(stage, 'Collection content derivation failed.', { cause });\n }\n };\n\n // The cast pins the envelope's payload member to the collection's output type:\n // `payloadSchema` is `Schema<P, unknown>` (input unknown), and inference through\n // the generic shape helper would widen the member to `unknown`.\n const entrySchema: Schema<ArchiveEntry<P, C>> = s.object(envelopeShape(payloadSchema as Schema<P>, contentVersion));\n const ownedEntrySchema: Schema<ArchiveOwnedEntry<P, C>> = s.object({\n ...envelopeShape(payloadSchema as Schema<P>, contentVersion),\n clientKey: uuidSchema,\n hidden: s.boolean(),\n });\n const contract: ArchiveContract<P, C> = {\n entry: entrySchema,\n ownedEntries: s.object({ entries: s.array(ownedEntrySchema) }),\n ownedEntry: ownedEntrySchema,\n page: s.object({\n cursor: s.string().nullable(),\n entries: s.array(entrySchema),\n }),\n publishInput: s.object({ clientKey: uuidSchema, payload: payloadSchema }),\n updateInput: s.object({\n expectedRevision: s.number().int().min(1).max(Number.MAX_SAFE_INTEGER),\n payload: payloadSchema,\n }),\n };\n\n return Object.freeze({ contentVersion, contract: Object.freeze(contract), derive, filters, name, tags });\n}\n"],"mappings":"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"}
@@ -0,0 +1,299 @@
1
+ import { s as e } from "@vielzeug/spell";
2
+ // src/_crypto.ts
3
+ var sha256Hex = async (e) => [...new Uint8Array(await crypto.subtle.digest("SHA-256", new TextEncoder().encode(e)))].map((e) => e.toString(16).padStart(2, "0")).join("");
4
+ // src/_json.ts
5
+ function canonicalJson(e, t = !1, n) {
6
+ let r = /* @__PURE__ */ new Set(), text = (e) => /[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?<![\uD800-\uDBFF])[\uDC00-\uDFFF]/u.test(e) ? null : JSON.stringify(e), serialize = (e, n) => {
7
+ if (e === null) return "null";
8
+ if (typeof e == "string") return text(e);
9
+ if (typeof e == "boolean") return String(e);
10
+ if (typeof e == "number") return Number.isFinite(e) ? JSON.stringify(e) : null;
11
+ if (typeof e != "object" || r.has(e)) return null;
12
+ let i = Array.isArray(e), a = Object.getPrototypeOf(e);
13
+ if (!i && a !== Object.prototype && a !== null || i && a !== Array.prototype) return null;
14
+ r.add(e);
15
+ try {
16
+ let r = [], a = Reflect.ownKeys(e);
17
+ if (i) {
18
+ if (a.length !== e.length + 1) return null;
19
+ for (let t = 0; t < e.length; t++) {
20
+ let i = Object.getOwnPropertyDescriptor(e, String(t));
21
+ if (!i || !i.enumerable || !("value" in i)) return null;
22
+ let a = serialize(i.value, Array.isArray(n) ? n[t] : void 0);
23
+ if (a === null) return null;
24
+ r.push(a);
25
+ }
26
+ return `[${r.join(",")}]`;
27
+ }
28
+ if (a.some((e) => typeof e != "string")) return null;
29
+ for (let i of Object.keys(e).sort()) {
30
+ let a = Object.getOwnPropertyDescriptor(e, i);
31
+ if (!a || !("value" in a)) return null;
32
+ let o = typeof n == "object" && n ? n : null;
33
+ if (a.value === void 0 && t && (o === null || !Object.hasOwn(o, i))) continue;
34
+ let s = text(i), c = serialize(a.value, o === null ? void 0 : Reflect.get(o, i));
35
+ if (s === null || c === null) return null;
36
+ r.push(`${s}:${c}`);
37
+ }
38
+ return Object.keys(e).length === a.length ? `{${r.join(",")}}` : null;
39
+ } finally {
40
+ r.delete(e);
41
+ }
42
+ };
43
+ try {
44
+ return serialize(e, n);
45
+ } catch {
46
+ return null;
47
+ }
48
+ }
49
+ function canonicalObjectJson(e, t = !1, n) {
50
+ return typeof e != "object" || !e || Array.isArray(e) ? null : canonicalJson(e, t, n);
51
+ }
52
+ // src/contract.ts
53
+ var t = "archive_session", n = "/api/v1", r = 2592e3, i = 3600, sessionCookieValue = (e, r) => `${t}=${e}; HttpOnly; SameSite=Strict; Path=${n}; Max-Age=${r.maxAgeSeconds}${r.secure ? "; Secure" : ""}`, a = "x-archive-publisher", o = "X-Archive-Account", s = "x-archive-request", c = 1, l = 1, u = 1, d = "archive-operator", f = /^[a-z0-9-]{1,32}$/, p = e.string().uuid(), m = e.string().isoDateTime(), h = e.string().regex(/^[0-9a-f]{64}$/), g = /[\p{Cs}\p{Cc}]/u, isWellFormedText = (e) => !g.test(e), textString = () => e.string().check(isWellFormedText), _ = textString().trim().max(24), v = e.object({
54
+ id: p,
55
+ name: _
56
+ }), y = e.object({
57
+ id: p,
58
+ name: _,
59
+ operator: e.boolean()
60
+ }).nullable(), b = e.object({
61
+ createdAt: m,
62
+ email: e.string().email(),
63
+ id: p,
64
+ lastSignInAt: m.nullable()
65
+ }), x = e.object({ ids: e.array(p) }), S = e.object({
66
+ cursor: e.string().nullable(),
67
+ ids: e.array(p)
68
+ }), C = e.object({
69
+ id: p,
70
+ likeCount: e.number().int().min(0).max(2 ** 53 - 1),
71
+ liked: e.boolean()
72
+ }), w = Object.freeze({
73
+ aliasChars: 24,
74
+ cursorChars: 1024,
75
+ idempotencyRetentionMs: 1728e5,
76
+ likeStateIds: 50,
77
+ maxPageSize: 50,
78
+ maxPublications: 50,
79
+ pageSize: 10,
80
+ payloadBytes: 8192,
81
+ publicCacheSeconds: 30,
82
+ reportReasonChars: 256,
83
+ requestBytes: 12288,
84
+ searchChars: 64,
85
+ searchTerms: 6,
86
+ tagsPerEntry: 16,
87
+ titleChars: 128,
88
+ vocabChars: 64
89
+ }), T = e.object({
90
+ aliasChars: e.number().int().min(1),
91
+ cursorChars: e.number().int().min(1),
92
+ idempotencyRetentionMs: e.number().int().min(1),
93
+ likeStateIds: e.number().int().min(1),
94
+ maxPageSize: e.number().int().min(1),
95
+ maxPublications: e.number().int().min(1),
96
+ pageSize: e.number().int().min(1),
97
+ payloadBytes: e.number().int().min(1),
98
+ publicCacheSeconds: e.number().int().min(0),
99
+ reportReasonChars: e.number().int().min(1),
100
+ requestBytes: e.number().int().min(1),
101
+ searchChars: e.number().int().min(1),
102
+ searchTerms: e.number().int().min(1),
103
+ tagsPerEntry: e.number().int().min(1),
104
+ titleChars: e.number().int().min(1),
105
+ vocabChars: e.number().int().min(1)
106
+ }), E = e.object({
107
+ dbSchemaVersion: e.number().int().min(0).nullable(),
108
+ features: e.object({
109
+ likes: e.boolean(),
110
+ publishing: e.boolean()
111
+ }),
112
+ limits: T,
113
+ reason: e.enum(["database-unavailable", "schema-mismatch"]).nullable(),
114
+ schemaVersion: e.literal(1),
115
+ status: e.enum(["ok", "degraded"])
116
+ }), D = e.object({
117
+ dbSchemaVersion: e.number().int().min(0).nullable(),
118
+ reason: e.enum([
119
+ "configuration-unavailable",
120
+ "database-unavailable",
121
+ "schema-mismatch"
122
+ ]).nullable(),
123
+ schemaVersion: e.literal(1),
124
+ status: e.enum(["ok", "degraded"])
125
+ }), O = [
126
+ "account-changed",
127
+ "auth-unavailable",
128
+ "bad-request",
129
+ "conflict",
130
+ "forbidden",
131
+ "gone",
132
+ "internal",
133
+ "invalid-payload",
134
+ "likes-disabled",
135
+ "method-not-allowed",
136
+ "not-found",
137
+ "publisher-changed",
138
+ "publishing-disabled",
139
+ "quota",
140
+ "rate-limited",
141
+ "record-unavailable",
142
+ "timeout",
143
+ "too-large",
144
+ "unauthenticated",
145
+ "unavailable",
146
+ "unsupported-media"
147
+ ], k = e.object({ error: e.object({
148
+ code: e.enum(O),
149
+ message: e.string().min(1).max(256),
150
+ requestId: p
151
+ }).strict() }).strict(), A = e.object({ ok: e.literal(!0) }).strict(), j = e.object({
152
+ filters: e.array(e.string().min(1).max(w.vocabChars)),
153
+ name: e.string().regex(f),
154
+ tags: e.array(e.string().min(1).max(w.vocabChars))
155
+ }), M = e.object({
156
+ cursor: e.string().nullable(),
157
+ reports: e.array(e.object({
158
+ createdAt: m,
159
+ entryId: p,
160
+ entryTitle: e.string().min(1).max(w.titleChars),
161
+ id: p,
162
+ reason: e.string().min(1).max(w.reportReasonChars),
163
+ reporter: v,
164
+ resolvedAt: m.nullable()
165
+ }))
166
+ }), N = e.object({
167
+ cursor: e.string().nullable(),
168
+ reports: e.array(e.object({
169
+ collection: e.string().regex(f),
170
+ createdAt: m,
171
+ entryId: p,
172
+ id: p,
173
+ reason: e.string().min(1).max(w.reportReasonChars),
174
+ resolvedAt: m.nullable()
175
+ }))
176
+ }), P = [
177
+ "hide",
178
+ "unhide",
179
+ "remove",
180
+ "erase-publisher"
181
+ ], F = e.object({
182
+ actions: e.array(e.object({
183
+ action: e.enum(P),
184
+ collection: e.string().regex(f).nullable(),
185
+ createdAt: m,
186
+ id: p,
187
+ operatorId: p,
188
+ targetId: p
189
+ })),
190
+ cursor: e.string().nullable()
191
+ }), I = e.enum(["liked", "recent"]), ArchiveError = class extends Error {
192
+ constructor(e, t) {
193
+ super(e, t), this.name = new.target.name;
194
+ }
195
+ }, ArchiveDefinitionError = class extends ArchiveError {}, ArchiveDerivationError = class extends ArchiveError {
196
+ stage;
197
+ constructor(e, t, n) {
198
+ super(t, n), this.stage = e;
199
+ }
200
+ }, envelopeShape = (t, n) => ({
201
+ author: v,
202
+ contentHash: h,
203
+ contentVersion: e.literal(n),
204
+ id: p,
205
+ likeCount: e.number().int().min(0).max(2 ** 53 - 1),
206
+ payload: t,
207
+ publishedAt: m,
208
+ revision: e.number().int().min(1).max(2 ** 53 - 1),
209
+ schemaVersion: e.literal(1),
210
+ updatedAt: m
211
+ });
212
+ function defineArchiveCollection(t) {
213
+ let { canonicalize: n, contentVersion: r, index: i, name: a, payloadSchema: o } = t;
214
+ if (typeof i != "function" || !o || typeof o.safeParse != "function" || n !== void 0 && typeof n != "function") throw new ArchiveDefinitionError("Collection requires a payload schema and synchronous indexing/canonicalization functions.");
215
+ if (t.filters !== void 0 && !Array.isArray(t.filters) || t.tags !== void 0 && !Array.isArray(t.tags)) throw new ArchiveDefinitionError("Collection vocabularies must be arrays.");
216
+ let s = Object.freeze([...t.filters ?? []]), c = Object.freeze([...t.tags ?? []]);
217
+ if (typeof a != "string" || !f.test(a)) throw new ArchiveDefinitionError(`Archive collection name must match [a-z0-9-]{1,32}: ${JSON.stringify(a)}`);
218
+ if (!Number.isSafeInteger(r) || r < 1) throw new ArchiveDefinitionError(`Archive collection ${a}: contentVersion must be a safe integer >= 1.`);
219
+ let validateVocabulary = (e, t) => {
220
+ for (let n of t) if (typeof n != "string" || n.length === 0 || n.length > w.vocabChars || !isWellFormedText(n)) throw new ArchiveDefinitionError(`Archive collection ${a}: every ${e} value must be well-formed text of 1..${w.vocabChars} chars.`);
221
+ };
222
+ validateVocabulary("filters", s), validateVocabulary("tags", c);
223
+ let l = new Set(s), u = new Set(c), derive = async (e) => {
224
+ let t = "schema";
225
+ try {
226
+ if (canonicalObjectJson(e) === null) return null;
227
+ let a = o.safeParse(e);
228
+ if (!a.success) return null;
229
+ let s = canonicalObjectJson(a.data, !0, e);
230
+ if (s === null) throw new ArchiveDerivationError(t, "Payload schema produced invalid or lossy JSON.");
231
+ t = "canonicalize";
232
+ let c = canonicalObjectJson(n === void 0 ? a.data : n(a.data), !0, JSON.parse(s));
233
+ if (c === null) throw new ArchiveDerivationError(t, "Canonicalization produced invalid JSON.");
234
+ t = "schema";
235
+ let d = o.safeParse(JSON.parse(c));
236
+ if (!d.success) throw new ArchiveDerivationError(n === void 0 ? "schema" : "canonicalize", "Canonical payload is outside the payload schema.", { cause: d.error });
237
+ let f = canonicalObjectJson(d.data, !0, JSON.parse(c));
238
+ if (f === null || f !== c) throw new ArchiveDerivationError(t, "Payload schema is not stable on canonical JSON.");
239
+ if (n !== void 0) {
240
+ let e = o.parse(JSON.parse(f));
241
+ if (t = "canonicalize", canonicalObjectJson(n(e), !0) !== f) throw new ArchiveDerivationError(t, "Canonicalization is not idempotent.");
242
+ }
243
+ t = "index";
244
+ let { filter: p, tags: m, title: h } = i(d.data);
245
+ if (canonicalObjectJson(d.data, !0) !== f) throw new ArchiveDerivationError(t, "Indexing mutated the canonical payload.");
246
+ if (typeof h != "string" || !Array.isArray(m)) throw new ArchiveDerivationError(t, "Indexing must return a string title and a tags array.");
247
+ let g = h.trim();
248
+ if (g.length === 0 || g.length > w.titleChars || !isWellFormedText(g)) return null;
249
+ if (p !== null && (typeof p != "string" || !isWellFormedText(p))) throw new ArchiveDerivationError(t, "Indexing returned an invalid filter.");
250
+ let _ = [];
251
+ for (let e of m) {
252
+ if (typeof e != "string" || !isWellFormedText(e)) throw new ArchiveDerivationError(t, "Indexing returned an invalid tag.");
253
+ _.includes(e) || _.push(e);
254
+ }
255
+ if (p !== null && !l.has(p) || _.some((e) => !u.has(e))) throw new ArchiveDerivationError(t, "Indexing returned a value outside the declared vocabularies.");
256
+ return _.length > w.tagsPerEntry || new TextEncoder().encode(f).byteLength > w.payloadBytes ? null : (t = "hash", {
257
+ canonicalJson: f,
258
+ contentHash: await sha256Hex(`{"contentVersion":${r},"payload":${f}}`),
259
+ contentVersion: r,
260
+ filter: p,
261
+ tags: _,
262
+ title: g
263
+ });
264
+ } catch (e) {
265
+ throw e instanceof ArchiveDerivationError ? e : new ArchiveDerivationError(t, "Collection content derivation failed.", { cause: e });
266
+ }
267
+ }, d = e.object(envelopeShape(o, r)), m = e.object({
268
+ ...envelopeShape(o, r),
269
+ clientKey: p,
270
+ hidden: e.boolean()
271
+ }), h = {
272
+ entry: d,
273
+ ownedEntries: e.object({ entries: e.array(m) }),
274
+ ownedEntry: m,
275
+ page: e.object({
276
+ cursor: e.string().nullable(),
277
+ entries: e.array(d)
278
+ }),
279
+ publishInput: e.object({
280
+ clientKey: p,
281
+ payload: o
282
+ }),
283
+ updateInput: e.object({
284
+ expectedRevision: e.number().int().min(1).max(2 ** 53 - 1),
285
+ payload: o
286
+ })
287
+ };
288
+ return Object.freeze({
289
+ contentVersion: r,
290
+ contract: Object.freeze(h),
291
+ derive,
292
+ filters: s,
293
+ name: a,
294
+ tags: c
295
+ });
296
+ }
297
+ export { o as ACCOUNT_HEADER, f as ARCHIVE_COLLECTION_NAME_PATTERN, c as ARCHIVE_CONTRACT_VERSION, O as ARCHIVE_ERROR_CODES, w as ARCHIVE_LIMITS, P as ARCHIVE_MODERATION_ACTIONS, d as ARCHIVE_OPERATOR_ROLE, l as ARCHIVE_SCHEMA_VERSION, u as AUTH_SCHEMA_VERSION, ArchiveDefinitionError, ArchiveDerivationError, ArchiveError, g as ILL_FORMED_TEXT, i as OPERATOR_SESSION_MAX_AGE_SECONDS, a as PUBLISHER_HEADER, s as REQUEST_MARKER_HEADER, t as SESSION_COOKIE_NAME, n as SESSION_COOKIE_PATH, r as SESSION_MAX_AGE_SECONDS, b as archiveAccountSchema, _ as archiveAliasSchema, D as archiveAuthHealthSchema, v as archiveAuthorSchema, j as archiveCollectionMetaSchema, k as archiveErrorResponseSchema, E as archiveHealthSchema, y as archiveIdentitySchema, C as archiveLikeStateSchema, x as archiveLikedIdsSchema, S as archiveLikesPageSchema, T as archiveLimitsSchema, F as archiveModerationLogSchema, A as archiveOkSchema, N as archiveOwnReportsSchema, M as archiveReportsSchema, I as archiveSortSchema, defineArchiveCollection, h as hex64Schema, isWellFormedText, m as isoTimestampSchema, sessionCookieValue, p as uuidSchema };
298
+
299
+ //# sourceMappingURL=archive.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"archive.js","names":["text","byte","active","value","array","prototype","fields","keys","i","descriptor","item","source","key","sourceObject","omitUndefinedFields","name","omissionSource","SESSION_COOKIE_NAME","SESSION_COOKIE_PATH","SESSION_MAX_AGE_SECONDS","OPERATOR_SESSION_MAX_AGE_SECONDS","token","options","PUBLISHER_HEADER","ACCOUNT_HEADER","REQUEST_MARKER_HEADER","ARCHIVE_CONTRACT_VERSION","ARCHIVE_SCHEMA_VERSION","AUTH_SCHEMA_VERSION","ARCHIVE_OPERATOR_ROLE","ARCHIVE_COLLECTION_NAME_PATTERN","uuidSchema","s","isoTimestampSchema","hex64Schema","ILL_FORMED_TEXT","archiveAliasSchema","archiveAuthorSchema","archiveIdentitySchema","archiveAccountSchema","archiveLikedIdsSchema","archiveLikesPageSchema","archiveLikeStateSchema","ARCHIVE_LIMITS","archiveLimitsSchema","archiveHealthSchema","archiveAuthHealthSchema","ARCHIVE_ERROR_CODES","archiveErrorResponseSchema","archiveOkSchema","archiveCollectionMetaSchema","archiveReportsSchema","archiveOwnReportsSchema","ARCHIVE_MODERATION_ACTIONS","archiveModerationLogSchema","archiveSortSchema","message","opts","stage","contentVersion","definition","index","payloadSchema","canonicalize","filters","tags","values","kind","filterValues","tagValues","raw","parsed","parsedJson","normalizedJson","revalidated","canonicalJson","repeatedPayload","rawTags","rawTitle","title","filter","uniqueTags","tag","cause","entrySchema","ownedEntrySchema","contract"],"sources":["../src/_crypto.ts","../src/_json.ts","../src/contract.ts","../src/errors.ts","../src/collection.ts"],"sourcesContent":["/**\n * The one SHA-256→hex helper shared by both server surfaces: the collection content\n * hash (browser-safe root) and the issuer's sign-in-link token hash. Web Crypto\n * only; no D1, JWKS or binding machinery.\n */\nexport const sha256Hex = async (text: string): Promise<string> =>\n [...new Uint8Array(await crypto.subtle.digest('SHA-256', new TextEncoder().encode(text)))]\n .map((byte) => byte.toString(16).padStart(2, '0'))\n .join('');\n","/** Canonical JSON rejects values JSON.stringify would silently discard or coerce. */\nexport function canonicalJson(value: unknown, omitUndefinedFields = false, omissionSource?: unknown): string | null {\n const active = new Set<object>();\n const text = (value: string): string | null => {\n if (/[\\uD800-\\uDBFF](?![\\uDC00-\\uDFFF])|(?<![\\uD800-\\uDBFF])[\\uDC00-\\uDFFF]/u.test(value)) return null;\n return JSON.stringify(value);\n };\n const serialize = (value: unknown, source?: unknown): string | null => {\n if (value === null) return 'null';\n if (typeof value === 'string') return text(value);\n if (typeof value === 'boolean') return String(value);\n if (typeof value === 'number') return Number.isFinite(value) ? JSON.stringify(value) : null;\n if (typeof value !== 'object' || active.has(value)) return null;\n const array = Array.isArray(value);\n const prototype = Object.getPrototypeOf(value);\n if (!array && prototype !== Object.prototype && prototype !== null) return null;\n if (array && prototype !== Array.prototype) return null;\n active.add(value);\n try {\n const fields: string[] = [];\n const keys = Reflect.ownKeys(value);\n if (array) {\n if (keys.length !== value.length + 1) return null;\n for (let i = 0; i < value.length; i++) {\n const descriptor = Object.getOwnPropertyDescriptor(value, String(i));\n if (!descriptor || !descriptor.enumerable || !('value' in descriptor)) return null;\n const item = serialize(descriptor.value, Array.isArray(source) ? source[i] : undefined);\n if (item === null) return null;\n fields.push(item);\n }\n return `[${fields.join(',')}]`;\n }\n if (keys.some((key) => typeof key !== 'string')) return null;\n for (const key of Object.keys(value).sort()) {\n const descriptor = Object.getOwnPropertyDescriptor(value, key);\n if (!descriptor || !('value' in descriptor)) return null;\n const sourceObject = source !== null && typeof source === 'object' ? source : null;\n // Spell materializes absent optional object fields as undefined.\n if (\n descriptor.value === undefined &&\n omitUndefinedFields &&\n (sourceObject === null || !Object.hasOwn(sourceObject, key))\n )\n continue;\n const name = text(key);\n const item = serialize(descriptor.value, sourceObject === null ? undefined : Reflect.get(sourceObject, key));\n if (name === null || item === null) return null;\n fields.push(`${name}:${item}`);\n }\n if (Object.keys(value).length !== keys.length) return null;\n return `{${fields.join(',')}}`;\n } finally {\n active.delete(value);\n }\n };\n try {\n return serialize(value, omissionSource);\n } catch {\n return null;\n }\n}\n\nexport function canonicalObjectJson(\n value: unknown,\n omitUndefinedFields = false,\n omissionSource?: unknown,\n): string | null {\n if (value === null || typeof value !== 'object' || Array.isArray(value)) return null;\n return canonicalJson(value, omitUndefinedFields, omissionSource);\n}\n","import { type InferOutput, type Schema, s } from '@vielzeug/spell';\n\n/** Shared naming: one place so the client, Worker and issuer cannot drift. */\nexport const SESSION_COOKIE_NAME = 'archive_session';\nexport const SESSION_COOKIE_PATH = '/api/v1';\n/**\n * The maximum age a session JWT may carry, and the cookie Max-Age an issuer sets:\n * a long-lived signed-in state. The Worker rejects older tokens at this bound.\n */\nexport const SESSION_MAX_AGE_SECONDS = 30 * 24 * 60 * 60;\nexport const OPERATOR_SESSION_MAX_AGE_SECONDS = 60 * 60;\n\n/**\n * The full Set-Cookie value for the session cookie: name, token and the security\n * attributes every issuer and the Worker must agree on — HttpOnly, SameSite=Strict,\n * the contract Path, Max-Age, and Secure in production. Issuers mint with the\n * session's max age; the Worker and issuers clear with `maxAgeSeconds: 0`. Never\n * hand-compose the attributes: the cookie's CSRF and theft posture is contract,\n * not per-issuer choice.\n */\nexport const sessionCookieValue = (token: string, options: { maxAgeSeconds: number; secure: boolean }): string =>\n `${SESSION_COOKIE_NAME}=${token}; HttpOnly; SameSite=Strict; Path=${SESSION_COOKIE_PATH}; Max-Age=${options.maxAgeSeconds}${options.secure ? '; Secure' : ''}`;\n\nexport const PUBLISHER_HEADER = 'x-archive-publisher';\n/** Pins account erasure to the issuer account shown when confirmation began. */\nexport const ACCOUNT_HEADER = 'X-Archive-Account';\nexport const REQUEST_MARKER_HEADER = 'x-archive-request';\n/** The wire-contract version advertised by health and stamped on every entry envelope. */\nexport const ARCHIVE_CONTRACT_VERSION = 1;\n/**\n * The storage schema version: the `archive_schema_meta` stamp the package's migration\n * writes and the Worker reads back through health. A mismatch answers `degraded`\n * instead of `ok` — a stale database is the most likely deployment fault.\n */\nexport const ARCHIVE_SCHEMA_VERSION = 1;\n/** Canonical issuer database initialization stamp. */\nexport const AUTH_SCHEMA_VERSION = 1;\n/** The `roles` claim value a session JWT carries for operator authority (moderation). */\nexport const ARCHIVE_OPERATOR_ROLE = 'archive-operator';\n/** The routable collection-name rule: lowercase `[a-z0-9-]`, at most 32 chars. */\nexport const ARCHIVE_COLLECTION_NAME_PATTERN = /^[a-z0-9-]{1,32}$/;\n\n// Exported schemas carry explicit public `Schema<Output>` annotations: the concrete\n// spell schema classes are not part of spell's public export surface, so inferred\n// types would not be portable across package declaration files.\nexport const uuidSchema: Schema<string> = s.string().uuid();\nexport const isoTimestampSchema: Schema<string> = s.string().isoDateTime();\nexport const hex64Schema: Schema<string> = s.string().regex(/^[0-9a-f]{64}$/);\n/** Well-formed user text: no lone UTF-16 surrogates, no C0/C1/DEL control characters. */\nexport const ILL_FORMED_TEXT = /[\\p{Cs}\\p{Cc}]/u;\nexport const isWellFormedText = (value: string): boolean => !ILL_FORMED_TEXT.test(value);\nconst textString = () => s.string().check(isWellFormedText);\n/** The one alias rule, shared by identity mutations and every emitted DTO. */\nexport const archiveAliasSchema: Schema<string> = textString().trim().max(24);\n\nexport const archiveAuthorSchema: Schema<{ id: string; name: string }> = s.object({\n id: uuidSchema,\n name: archiveAliasSchema,\n});\nexport const archiveIdentitySchema: Schema<{ id: string; name: string; operator: boolean } | null> = s\n .object({ id: uuidSchema, name: archiveAliasSchema, operator: s.boolean() })\n .nullable();\nexport type ArchiveIdentity = InferOutput<typeof archiveIdentitySchema>;\n/** The issuer account metadata export; its id is the session subject, not a publisher id. */\nexport const archiveAccountSchema: Schema<{\n createdAt: string;\n email: string;\n id: string;\n lastSignInAt: string | null;\n}> = s.object({\n createdAt: isoTimestampSchema,\n email: s.string().email(),\n id: uuidSchema,\n lastSignInAt: isoTimestampSchema.nullable(),\n});\nexport type ArchiveAccount = InferOutput<typeof archiveAccountSchema>;\nexport const archiveLikedIdsSchema: Schema<{ ids: string[] }> = s.object({ ids: s.array(uuidSchema) });\nexport const archiveLikesPageSchema: Schema<{ cursor: string | null; ids: string[] }> = s.object({\n cursor: s.string().nullable(),\n ids: s.array(uuidSchema),\n});\nexport type ArchiveLikesPage = InferOutput<typeof archiveLikesPageSchema>;\nexport const archiveLikeStateSchema: Schema<{ id: string; likeCount: number; liked: boolean }> = s.object({\n id: uuidSchema,\n likeCount: s.number().int().min(0).max(Number.MAX_SAFE_INTEGER),\n liked: s.boolean(),\n});\n\n/** Application bounds shared by handlers, the health route, and clients. */\nexport const ARCHIVE_LIMITS = Object.freeze({\n aliasChars: 24,\n cursorChars: 1024,\n idempotencyRetentionMs: 48 * 60 * 60 * 1000,\n likeStateIds: 50,\n maxPageSize: 50,\n maxPublications: 50,\n pageSize: 10,\n payloadBytes: 8192,\n publicCacheSeconds: 30,\n /** One free-text moderation reason: trimmed, non-empty, at most this many chars. */\n reportReasonChars: 256,\n requestBytes: 12 * 1024,\n searchChars: 64,\n searchTerms: 6,\n tagsPerEntry: 16,\n titleChars: 128,\n /** One declared filter or tag value: well-formed, non-empty, at most this many chars. */\n vocabChars: 64,\n});\nexport const archiveLimitsSchema: Schema<{\n aliasChars: number;\n cursorChars: number;\n idempotencyRetentionMs: number;\n likeStateIds: number;\n maxPageSize: number;\n maxPublications: number;\n pageSize: number;\n payloadBytes: number;\n publicCacheSeconds: number;\n reportReasonChars: number;\n requestBytes: number;\n searchChars: number;\n searchTerms: number;\n tagsPerEntry: number;\n titleChars: number;\n vocabChars: number;\n}> = s.object({\n aliasChars: s.number().int().min(1),\n cursorChars: s.number().int().min(1),\n idempotencyRetentionMs: s.number().int().min(1),\n likeStateIds: s.number().int().min(1),\n maxPageSize: s.number().int().min(1),\n maxPublications: s.number().int().min(1),\n pageSize: s.number().int().min(1),\n payloadBytes: s.number().int().min(1),\n publicCacheSeconds: s.number().int().min(0),\n reportReasonChars: s.number().int().min(1),\n requestBytes: s.number().int().min(1),\n searchChars: s.number().int().min(1),\n searchTerms: s.number().int().min(1),\n tagsPerEntry: s.number().int().min(1),\n titleChars: s.number().int().min(1),\n vocabChars: s.number().int().min(1),\n});\nexport const archiveHealthSchema: Schema<{\n /** The storage schema stamp (`archive_schema_meta`) the database actually carries. */\n dbSchemaVersion: number | null;\n features: { likes: boolean; publishing: boolean };\n limits: InferOutput<typeof archiveLimitsSchema>;\n schemaVersion: 1;\n /** 'degraded' when the database's storage schema does not match the Worker's. */\n status: 'ok' | 'degraded';\n reason: 'database-unavailable' | 'schema-mismatch' | null;\n}> = s.object({\n dbSchemaVersion: s.number().int().min(0).nullable(),\n features: s.object({ likes: s.boolean(), publishing: s.boolean() }),\n limits: archiveLimitsSchema,\n reason: s.enum(['database-unavailable', 'schema-mismatch'] as const).nullable(),\n schemaVersion: s.literal(ARCHIVE_CONTRACT_VERSION),\n status: s.enum(['ok', 'degraded'] as const),\n});\nexport type ArchiveHealth = InferOutput<typeof archiveHealthSchema>;\n\nexport const archiveAuthHealthSchema: Schema<{\n dbSchemaVersion: number | null;\n schemaVersion: 1;\n status: 'ok' | 'degraded';\n reason: 'configuration-unavailable' | 'database-unavailable' | 'schema-mismatch' | null;\n}> = s.object({\n dbSchemaVersion: s.number().int().min(0).nullable(),\n reason: s.enum(['configuration-unavailable', 'database-unavailable', 'schema-mismatch'] as const).nullable(),\n schemaVersion: s.literal(AUTH_SCHEMA_VERSION),\n status: s.enum(['ok', 'degraded'] as const),\n});\nexport type AuthHealth = InferOutput<typeof archiveAuthHealthSchema>;\n\n/** The Worker's full error-code vocabulary — the contract both sides test against. */\nexport const ARCHIVE_ERROR_CODES = [\n 'account-changed',\n 'auth-unavailable',\n 'bad-request',\n 'conflict',\n 'forbidden',\n 'gone',\n 'internal',\n 'invalid-payload',\n 'likes-disabled',\n 'method-not-allowed',\n 'not-found',\n 'publisher-changed',\n 'publishing-disabled',\n 'quota',\n 'rate-limited',\n 'record-unavailable',\n 'timeout',\n 'too-large',\n 'unauthenticated',\n 'unavailable',\n 'unsupported-media',\n] as const;\nexport type ArchiveErrorCode = (typeof ARCHIVE_ERROR_CODES)[number];\n\n/**\n * The error envelope every route answers failures with: `{ error: { code, message,\n * requestId } }`. Clients validate against this one schema — an envelope carrying an\n * unknown code or malformed fields is not an archive error at all.\n */\nexport const archiveErrorResponseSchema: Schema<{\n error: { code: ArchiveErrorCode; message: string; requestId: string };\n}> = s\n .object({\n error: s\n .object({\n code: s.enum(ARCHIVE_ERROR_CODES),\n message: s.string().min(1).max(256),\n requestId: uuidSchema,\n })\n .strict(),\n })\n .strict();\nexport type ArchiveErrorResponse = InferOutput<typeof archiveErrorResponseSchema>;\n\n/** The sign-out acknowledgement: the only non-collection response body, shared by both sides. */\nexport const archiveOkSchema: Schema<{ ok: true }> = s.object({ ok: s.literal(true) }).strict();\n\n/** One collection's public self-description: its name and declared query vocabularies. */\nexport const archiveCollectionMetaSchema: Schema<{\n filters: string[];\n name: string;\n tags: string[];\n}> = s.object({\n filters: s.array(s.string().min(1).max(ARCHIVE_LIMITS.vocabChars)),\n name: s.string().regex(ARCHIVE_COLLECTION_NAME_PATTERN),\n tags: s.array(s.string().min(1).max(ARCHIVE_LIMITS.vocabChars)),\n});\nexport type ArchiveCollectionMeta = InferOutput<typeof archiveCollectionMetaSchema>;\n\n/** One reader report an operator reviews: what was reported, why, and by whom. */\nexport const archiveReportsSchema: Schema<{\n cursor: string | null;\n reports: {\n id: string;\n createdAt: string;\n entryId: string;\n entryTitle: string;\n reason: string;\n reporter: { id: string; name: string };\n resolvedAt: string | null;\n }[];\n}> = s.object({\n cursor: s.string().nullable(),\n reports: s.array(\n s.object({\n createdAt: isoTimestampSchema,\n entryId: uuidSchema,\n entryTitle: s.string().min(1).max(ARCHIVE_LIMITS.titleChars),\n id: uuidSchema,\n reason: s.string().min(1).max(ARCHIVE_LIMITS.reportReasonChars),\n reporter: archiveAuthorSchema,\n resolvedAt: isoTimestampSchema.nullable(),\n }),\n ),\n});\nexport type ArchiveReports = InferOutput<typeof archiveReportsSchema>;\nexport const archiveOwnReportsSchema: Schema<{\n cursor: string | null;\n reports: {\n collection: string;\n createdAt: string;\n entryId: string;\n id: string;\n reason: string;\n resolvedAt: string | null;\n }[];\n}> = s.object({\n cursor: s.string().nullable(),\n reports: s.array(\n s.object({\n collection: s.string().regex(ARCHIVE_COLLECTION_NAME_PATTERN),\n createdAt: isoTimestampSchema,\n entryId: uuidSchema,\n id: uuidSchema,\n reason: s.string().min(1).max(ARCHIVE_LIMITS.reportReasonChars),\n resolvedAt: isoTimestampSchema.nullable(),\n }),\n ),\n});\nexport type ArchiveOwnReports = InferOutput<typeof archiveOwnReportsSchema>;\n\n/** The moderation actions an operator can take; the audit log's whole vocabulary. */\nexport const ARCHIVE_MODERATION_ACTIONS = ['hide', 'unhide', 'remove', 'erase-publisher'] as const;\nexport type ArchiveModerationAction = (typeof ARCHIVE_MODERATION_ACTIONS)[number];\n\n/**\n * The operator accountability log: one row per effective moderation action, newest\n * first. Operator and target travel as opaque ids only — no names (they change), no\n * content — so the log stays honest after renames and survives the erasures it records.\n */\nexport const archiveModerationLogSchema: Schema<{\n cursor: string | null;\n actions: {\n id: string;\n action: ArchiveModerationAction;\n collection: string | null;\n createdAt: string;\n operatorId: string;\n targetId: string;\n }[];\n}> = s.object({\n actions: s.array(\n s.object({\n action: s.enum(ARCHIVE_MODERATION_ACTIONS),\n collection: s.string().regex(ARCHIVE_COLLECTION_NAME_PATTERN).nullable(),\n createdAt: isoTimestampSchema,\n id: uuidSchema,\n operatorId: uuidSchema,\n targetId: uuidSchema,\n }),\n ),\n cursor: s.string().nullable(),\n});\nexport type ArchiveModerationLog = InferOutput<typeof archiveModerationLogSchema>;\n\n/** How the online list ranks entries: explicit modes only, no vague composites. */\nexport type ArchiveSort = 'liked' | 'recent';\nexport const archiveSortSchema: Schema<ArchiveSort> = s.enum(['liked', 'recent'] as const);\n\n/**\n * One page of archive entries. Every list in the package pages forward-only: the\n * cursor walks toward the oldest entry and is null after the last page.\n */\nexport interface ArchivePage<T> {\n /** Cursor for the next page; null after the last. */\n cursor: string | null;\n entries: readonly T[];\n}\n","export class ArchiveError extends Error {\n constructor(message: string, opts?: ErrorOptions) {\n super(message, opts);\n this.name = new.target.name;\n }\n}\n\nexport class ArchiveDefinitionError extends ArchiveError {}\n\nexport type ArchiveDerivationStage = 'canonicalize' | 'hash' | 'index' | 'schema';\n\n/** A collection callback or core runtime fault, not invalid submitted content. */\nexport class ArchiveDerivationError extends ArchiveError {\n readonly stage: ArchiveDerivationStage;\n\n constructor(stage: ArchiveDerivationStage, message: string, opts?: ErrorOptions) {\n super(message, opts);\n this.stage = stage;\n }\n}\n","import { type Schema, s } from '@vielzeug/spell';\nimport { sha256Hex } from './_crypto';\nimport { canonicalObjectJson } from './_json';\nimport {\n ARCHIVE_COLLECTION_NAME_PATTERN,\n ARCHIVE_CONTRACT_VERSION,\n ARCHIVE_LIMITS,\n type ArchivePage,\n archiveAuthorSchema,\n hex64Schema,\n isoTimestampSchema,\n isWellFormedText,\n uuidSchema,\n} from './contract';\nimport { ArchiveDefinitionError, ArchiveDerivationError, type ArchiveDerivationStage } from './errors';\n\n/**\n * Stored payloads are canonical by construction: `derive` validates, normalizes and\n * byte-pins every payload before it is stored, and the package's schema policy is\n * to reset/reseed databases when canonicalization semantics change. The emitted\n * entry schemas therefore embed the plain payload schema — re-parsing a stored\n * payload re-runs its (write-time-stable, hence idempotent) schema, never a\n * parallel re-canonicalization.\n */\n\n/**\n * The one seam between a deployment's content and the archive core. A collection\n * declares its payload schema and derives its list dimensions; the core owns\n * everything else — parsing, canonical serialization, the content hash, the emitted\n * envelope schemas, and every storage bound. Collections never hash, never size,\n * and never hand-write the envelope.\n */\n\n/** What `index` derives from one validated payload: the list dimensions plus the FTS title. */\nexport interface ArchiveIndexing<F extends string = string, T extends string = string> {\n /** One scalar-filter value from the declared vocabulary, or null for \"no filter\". */\n filter: F | null;\n /** Tag values from the declared vocabulary; duplicates collapse in first-seen order. */\n tags: readonly T[];\n /** The searchable title; the core trims and bounds it. */\n title: string;\n}\n\n/** The definition a deployment writes; `defineArchiveCollection` derives the rest. */\nexport interface ArchiveCollectionDefinition<\n P extends object,\n C extends number,\n F extends string = never,\n T extends string = never,\n> {\n /**\n * Normalizes a parsed payload to its storage form — fixed key order, sorted\n * order-insensitive lists — so equivalent content hashes identically. Omit when\n * the payload is already canonical; a result that leaves the payload schema is\n * a derivation fault at derive time, never stored. Must be idempotent.\n */\n canonicalize?(payload: P): P;\n /** The collection's payload-format version; stored and re-emitted with every entry. */\n contentVersion: C;\n /** Valid scalar-filter values; a query param outside the vocabulary is 400. */\n filters?: readonly F[];\n /** Derives the list dimensions and the searchable title from the canonical payload. */\n index(payload: P): ArchiveIndexing<NoInfer<F>, NoInfer<T>>;\n /** The URL + storage dimension this collection owns: lowercase `[a-z0-9-]`, at most 32 chars. */\n name: string;\n /** The strict payload schema: the whole content contract, parsed before anything derives. */\n payloadSchema: Schema<P, unknown>;\n /** Valid tag values. */\n tags?: readonly T[];\n}\n\n/** Everything the archive stores and re-identifies by, derived once per publish and update. */\nexport interface ArchiveDerivation {\n /** The stored bytes: the canonical payload, serialized with fixed key order. */\n canonicalJson: string;\n /** SHA-256 hex over `{contentVersion, payload}`: identical content hashes identically. */\n contentHash: string;\n /** The collection's declared payload-format version. */\n contentVersion: number;\n filter: string | null;\n tags: readonly string[];\n title: string;\n}\n\n/** The envelope fields every emitted entry carries; the payload stays the collection's. */\nexport interface ArchiveEntry<P = unknown, C extends number = number> {\n author: { id: string; name: string };\n contentHash: string;\n /** The collection's payload-format version, literal-pinned by the definition. */\n contentVersion: C;\n id: string;\n likeCount: number;\n payload: P;\n publishedAt: string;\n revision: number;\n /** The archive wire-contract version, pinned by the core. */\n schemaVersion: typeof ARCHIVE_CONTRACT_VERSION;\n updatedAt: string;\n}\n\n/** The private owner view: the emitted entry plus the create retry key and moderation state. */\nexport interface ArchiveOwnedEntry<P = unknown, C extends number = number> extends ArchiveEntry<P, C> {\n /** The create retry key; public routes never emit it. */\n clientKey: string;\n /** True while an operator has removed the entry from public view (still owned, frozen for edits). */\n hidden: boolean;\n}\n\n/**\n * The wire schemas one collection shares with its client: every request and response\n * envelope for this collection's routes, composed from the payload schema, so the\n * client and the Worker parse the same bytes with the same rules.\n */\nexport interface ArchiveContract<P = unknown, C extends number = number> {\n /** The public entry emitted by list, detail and publish/update responses. */\n entry: Schema<ArchiveEntry<P, C>>;\n /** The own-publications response: `{ entries: ArchiveOwnedEntry[] }`. */\n ownedEntries: Schema<{ entries: ArchiveOwnedEntry<P, C>[] }>;\n /** The private owner entry — the public entry plus the create retry key. */\n ownedEntry: Schema<ArchiveOwnedEntry<P, C>>;\n /** One list page: entries plus the forward/backward cursors around it. */\n page: Schema<ArchivePage<ArchiveEntry<P, C>>>;\n /** The publish request: `{ clientKey, payload }`. */\n publishInput: Schema<{ clientKey: string; payload: P }, unknown>;\n /** The update request: `{ expectedRevision, payload }`. */\n updateInput: Schema<{ expectedRevision: number; payload: P }, unknown>;\n}\n\n/** One registered collection: the derived runtime seam the Worker consumes. */\nexport interface ArchiveCollection<P extends object = object, C extends number = number> {\n readonly contentVersion: C;\n /** The collection's wire schemas, shared with its client. */\n readonly contract: ArchiveContract<P, C>;\n /**\n * Validates an untrusted payload and derives everything the archive stores.\n * Null rejects invalid content: JSON/schema failures, title/tag bounds or the\n * canonical payload byte ceiling. Routes answer 422 `invalid-payload` for null.\n * Callback failures and deployment invariant violations throw ArchiveDerivationError.\n */\n readonly derive: (raw: unknown) => Promise<ArchiveDerivation | null>;\n readonly filters: readonly string[];\n readonly name: string;\n readonly tags: readonly string[];\n}\n\n/** The envelope shape shared by the public and owned compositions. */\nconst envelopeShape = <P, C extends number>(payload: Schema<P>, contentVersion: C) =>\n ({\n author: archiveAuthorSchema,\n contentHash: hex64Schema,\n contentVersion: s.literal(contentVersion),\n id: uuidSchema,\n likeCount: s.number().int().min(0).max(Number.MAX_SAFE_INTEGER),\n payload,\n publishedAt: isoTimestampSchema,\n revision: s.number().int().min(1).max(Number.MAX_SAFE_INTEGER),\n schemaVersion: s.literal(ARCHIVE_CONTRACT_VERSION),\n updatedAt: isoTimestampSchema,\n }) as const;\n\n/**\n * Builds one collection from its definition. Malformed definitions fail here, at\n * registration time — never mid-request: the name must be a routable `[a-z0-9-]`\n * segment, the content version a positive integer, and every declared filter and\n * tag value well-formed text of `1..vocabChars` chars — the bound cursors and the\n * meta route both rely on it. The core derives everything else per payload:\n * parsing, canonical serialization, hashing over the collection's versioned\n * envelope, the emitted-entry schemas, and every storage bound.\n */\nexport function defineArchiveCollection<\n P extends object,\n const C extends number,\n const F extends string = never,\n const T extends string = never,\n>(definition: ArchiveCollectionDefinition<P, C, F, T>): ArchiveCollection<P, C> {\n const { canonicalize, contentVersion, index, name, payloadSchema } = definition;\n if (\n typeof index !== 'function' ||\n !payloadSchema ||\n typeof payloadSchema.safeParse !== 'function' ||\n (canonicalize !== undefined && typeof canonicalize !== 'function')\n ) {\n throw new ArchiveDefinitionError(\n 'Collection requires a payload schema and synchronous indexing/canonicalization functions.',\n );\n }\n if (\n (definition.filters !== undefined && !Array.isArray(definition.filters)) ||\n (definition.tags !== undefined && !Array.isArray(definition.tags))\n ) {\n throw new ArchiveDefinitionError('Collection vocabularies must be arrays.');\n }\n const filters = Object.freeze([...(definition.filters ?? [])]);\n const tags = Object.freeze([...(definition.tags ?? [])]);\n if (typeof name !== 'string' || !ARCHIVE_COLLECTION_NAME_PATTERN.test(name)) {\n throw new ArchiveDefinitionError(`Archive collection name must match [a-z0-9-]{1,32}: ${JSON.stringify(name)}`);\n }\n if (!Number.isSafeInteger(contentVersion) || contentVersion < 1) {\n throw new ArchiveDefinitionError(`Archive collection ${name}: contentVersion must be a safe integer >= 1.`);\n }\n const validateVocabulary = (kind: 'filters' | 'tags', values: readonly string[]): void => {\n for (const value of values) {\n if (\n typeof value !== 'string' ||\n value.length === 0 ||\n value.length > ARCHIVE_LIMITS.vocabChars ||\n !isWellFormedText(value)\n ) {\n throw new ArchiveDefinitionError(\n `Archive collection ${name}: every ${kind} value must be well-formed text of 1..${ARCHIVE_LIMITS.vocabChars} chars.`,\n );\n }\n }\n };\n validateVocabulary('filters', filters);\n validateVocabulary('tags', tags);\n const filterValues = new Set<string>(filters);\n const tagValues = new Set<string>(tags);\n\n const derive = async (raw: unknown): Promise<ArchiveDerivation | null> => {\n let stage: ArchiveDerivationStage = 'schema';\n try {\n if (canonicalObjectJson(raw) === null) return null;\n const parsed = payloadSchema.safeParse(raw);\n if (!parsed.success) return null;\n const parsedJson = canonicalObjectJson(parsed.data, true, raw);\n if (parsedJson === null)\n throw new ArchiveDerivationError(stage, 'Payload schema produced invalid or lossy JSON.');\n stage = 'canonicalize';\n const canonical = canonicalize === undefined ? parsed.data : canonicalize(parsed.data);\n // A canonicalize step that leaves the payload schema is a collection bug, not data to store.\n const normalizedJson = canonicalObjectJson(canonical, true, JSON.parse(parsedJson));\n if (normalizedJson === null) throw new ArchiveDerivationError(stage, 'Canonicalization produced invalid JSON.');\n stage = 'schema';\n const revalidated = payloadSchema.safeParse(JSON.parse(normalizedJson));\n if (!revalidated.success)\n throw new ArchiveDerivationError(\n canonicalize === undefined ? 'schema' : 'canonicalize',\n 'Canonical payload is outside the payload schema.',\n { cause: revalidated.error },\n );\n const canonicalJson = canonicalObjectJson(revalidated.data, true, JSON.parse(normalizedJson));\n if (canonicalJson === null || canonicalJson !== normalizedJson)\n throw new ArchiveDerivationError(stage, 'Payload schema is not stable on canonical JSON.');\n if (canonicalize !== undefined) {\n const repeatedPayload = payloadSchema.parse(JSON.parse(canonicalJson));\n stage = 'canonicalize';\n const repeated = canonicalize(repeatedPayload);\n if (canonicalObjectJson(repeated, true) !== canonicalJson)\n throw new ArchiveDerivationError(stage, 'Canonicalization is not idempotent.');\n }\n\n stage = 'index';\n const { filter, tags: rawTags, title: rawTitle } = index(revalidated.data);\n // Indexing may read the final parsed value, but must not change the stored content.\n if (canonicalObjectJson(revalidated.data, true) !== canonicalJson)\n throw new ArchiveDerivationError(stage, 'Indexing mutated the canonical payload.');\n if (typeof rawTitle !== 'string' || !Array.isArray(rawTags))\n throw new ArchiveDerivationError(stage, 'Indexing must return a string title and a tags array.');\n const title = rawTitle.trim();\n if (title.length === 0 || title.length > ARCHIVE_LIMITS.titleChars || !isWellFormedText(title)) return null;\n if (filter !== null && (typeof filter !== 'string' || !isWellFormedText(filter)))\n throw new ArchiveDerivationError(stage, 'Indexing returned an invalid filter.');\n const uniqueTags: string[] = [];\n for (const tag of rawTags) {\n if (typeof tag !== 'string' || !isWellFormedText(tag))\n throw new ArchiveDerivationError(stage, 'Indexing returned an invalid tag.');\n if (!uniqueTags.includes(tag)) uniqueTags.push(tag);\n }\n // A derivation outside the declared vocabulary would store a row no list query\n // can reach — the query route 400s the very value the collection derived.\n if ((filter !== null && !filterValues.has(filter)) || uniqueTags.some((tag) => !tagValues.has(tag)))\n throw new ArchiveDerivationError(stage, 'Indexing returned a value outside the declared vocabularies.');\n if (uniqueTags.length > ARCHIVE_LIMITS.tagsPerEntry) return null;\n\n if (new TextEncoder().encode(canonicalJson).byteLength > ARCHIVE_LIMITS.payloadBytes) return null;\n stage = 'hash';\n const contentHash = await sha256Hex(`{\"contentVersion\":${contentVersion},\"payload\":${canonicalJson}}`);\n return { canonicalJson, contentHash, contentVersion, filter, tags: uniqueTags, title };\n } catch (cause) {\n if (cause instanceof ArchiveDerivationError) throw cause;\n throw new ArchiveDerivationError(stage, 'Collection content derivation failed.', { cause });\n }\n };\n\n // The cast pins the envelope's payload member to the collection's output type:\n // `payloadSchema` is `Schema<P, unknown>` (input unknown), and inference through\n // the generic shape helper would widen the member to `unknown`.\n const entrySchema: Schema<ArchiveEntry<P, C>> = s.object(envelopeShape(payloadSchema as Schema<P>, contentVersion));\n const ownedEntrySchema: Schema<ArchiveOwnedEntry<P, C>> = s.object({\n ...envelopeShape(payloadSchema as Schema<P>, contentVersion),\n clientKey: uuidSchema,\n hidden: s.boolean(),\n });\n const contract: ArchiveContract<P, C> = {\n entry: entrySchema,\n ownedEntries: s.object({ entries: s.array(ownedEntrySchema) }),\n ownedEntry: ownedEntrySchema,\n page: s.object({\n cursor: s.string().nullable(),\n entries: s.array(entrySchema),\n }),\n publishInput: s.object({ clientKey: uuidSchema, payload: payloadSchema }),\n updateInput: s.object({\n expectedRevision: s.number().int().min(1).max(Number.MAX_SAFE_INTEGER),\n payload: payloadSchema,\n }),\n };\n\n return Object.freeze({ contentVersion, contract: Object.freeze(contract), derive, filters, name, tags });\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vielzeug/archive",
3
- "version": "26.11.17",
3
+ "version": "26.11.18",
4
4
  "description": "Community content publishing for Cloudflare Workers + D1: a hardened Worker core over per-collection payload schemas",
5
5
  "repository": {
6
6
  "type": "git",
@@ -52,7 +52,8 @@
52
52
  "registry": "https://registry.npmjs.org/"
53
53
  },
54
54
  "scripts": {
55
- "build": "vite build && bun run --silent build:types",
55
+ "build": "vite build && bun run --silent build:bundle && bun run --silent build:types",
56
+ "build:bundle": "vite build --config vite.bundle.config.ts",
56
57
  "build:types": "tsc -p tsconfig.declarations.json",
57
58
  "fix": "biome check --write src test",
58
59
  "lint": "biome ci src test",
@@ -62,7 +63,7 @@
62
63
  "test:types": "tsc -p tsconfig.json --noEmit"
63
64
  },
64
65
  "dependencies": {
65
- "@vielzeug/spell": "26.11.17",
66
+ "@vielzeug/spell": "26.11.18",
66
67
  "jose": "6.2.15"
67
68
  },
68
69
  "devDependencies": {