@lapxo/bound 0.2.2 → 0.2.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/TARGET.bound +27 -19
- package/dist/host/native/loader.js +1 -1
- package/dist/host/native/module-closure.d.ts +35 -0
- package/dist/host/native/module-closure.js +34 -3
- package/dist/host/native/module-delivery.d.ts +62 -0
- package/dist/host/native/module-delivery.js +151 -0
- package/dist/host/native/module-syntax.js +3 -1
- package/dist/host/order.js +2 -0
- package/docs/contracts/closure-delivery.md +23 -0
- package/docs/contracts/closure-delivery.publication.json +25 -0
- package/package.json +13 -2
- package/receipts.bound +9759 -9625
- package/samples/module-delivery/inputs/delivery.json +1 -0
- package/samples/no/module-delivery/delivery.json +1 -0
- package/vectors/native/module-delivery.vector.json +32 -0
package/TARGET.bound
CHANGED
|
@@ -13,6 +13,7 @@ bound-lock/1 about="# Published contracts\n\nEvery public surface names its cont
|
|
|
13
13
|
bound-lock/1 about="# Pure object projection\n\n`@lapxo/bound/engine` exports `objectFold` and the existing `ObjectReading`, `ObjectRecord` and `ObjectContext` types. The CLI and receipt paths use that same implementation. Its Obligations 0.3.5 algebra is unchanged.\n\nThe input is authenticated and context-admitted effective history with selected deterministic forms and parameters. This function does not admit records, verify signatures, resolve content, run commands, select clocks or write storage. Applications must perform preparation before projection.\n\nWithin each epoch, a cell declaration precedes its uses in effective order. A same-epoch act before its cell refuses in preparation by name: `object context: cell not declared before <act-id>`. Lower-epoch cell declarations remain eligible even when their envelope arrives later. Effective sign/join order is preserved; transport arrival does not authorize arbitrary semantic reordering. The consumed Topos contract must be published before this export is admitted for release.\n\nOutputs preserve existing attributed origins, local and travelling marks, exact withdrawals, floor and ceiling parts and REQUIRED/FREE/FORBIDDEN/CONFLICT decisions. Raw object JSON is not a new canonical identity. Byte identity requires the existing declared reading projection.\n\nMalformed or unauthenticated records are outside this pure projector's input contract. Refusal, authority and interrupted-admission vectors exercise the host boundary; they do not claim cryptographic admission inside WASM. No host callback calculates an algebraic result in a WASM comparison.\n\n## Public conformance samples\n\n`samples/engine-interval` and `samples/engine-alphabet` are formed places: TARGET.bound, receipts.bound, package.json, the declared reader.js and inputs/sample.json. The instrument exercises the same projector against prepared fixtures; its reader is not a command users invoke. `fold <sample-directory> --check` verifies each portable receipt. Cold native `fold --as receipts` recomputes the declared conformance reading without a private store.\n\n`samples/no/engine-interval.json` and `samples/no/engine-alphabet.json` are negative data fixtures. Their captured native preparation refusal is `cell not declared before s-B`; no closed receipts are asserted for refusing input. The actual CLI vector is `vectors/engine-object.cli.json`. This conformance reader does not authenticate arbitrary signatures, coverage or clocks.\n\n\n## Optional WASM host adapter\n\nThe optional `@lapxo/bound/wasm` entry evaluates the existing pure projection in QuickJS WASM. It performs no admission, signature verification, state calculation of its own, transport, key discovery or effects. Host authentication must finish before records become projection inputs. A valid digest identifies bytes; it grants no authority or confinement guarantee.\n\nThe host supplies the trusted runtime/WASM/module digests, exact byte lengths, entry, aliases and limits. These expectations must come from its accepted configuration, independently of fetched place bytes. Closed request metadata and exact lengths are checked before copying, hashing or worker handoff. Shared assets refuse. Every supplied byte is verified and copied before execution; the closed runtime bundle has no imports and receives the already verified WASM binary. Guest imports resolve only within the verified module map. No second fetch occurs.\n\n`runWasmRequest` returns declared text, without inventing a JSON canonicalization or number policy. The caller's declared entry chooses the serialization contract. Memory and stack limits govern the guest; they do not describe total host/WASM initialization memory. Guest memory, stack and execution budgets are explicit host inputs. Initialization and execution times are separate readings, not a speed guarantee.\n\n`evaluateWasm` runs in a host worker. It accepts an AbortSignal and an explicit worker lifetime. Cancellation, timeout, malformed messages, failed serialization and worker errors terminate the worker and return no successful result. Guest state remains provisional until success; no host write port is supplied. A terminated computation produces no successful receipt. The direct `runWasmRequest` entry has deadline interruption but cannot asynchronously receive an external abort while synchronously executing; callers needing that contract use `evaluateWasm`.\n\n\n### Native optional WASM projection\n\nThe existing object view consumes an optional, authenticated live declaration `engine/object form=alphabet measure=id value=wasm@1`. With no selector it retains the ESM projection; a conflicting or unknown selector refuses. This profile selects only the explicit object view, not every other view of the place. The host admits and folds configuration with the existing authority and withdrawal rules before selecting execution.\n\nThe place declares five interval limits: `engine/wasm/memory`, `engine/wasm/stack` and `engine/wasm/response` in bytes; `engine/wasm/execution` and `engine/wasm/worker-lifetime` in milliseconds. Missing, ambiguous or invalid limits refuse; there is no inferred fallback. The installed instrument binds the guest module and supported form standings to their context implementation artifacts. A place cannot choose another verifier or executable through this selection; an unsupported form or different implementation refuses.\n\nContext initialization is measured before place execution. If observed initialized guest memory exceeds the declared memory budget, the operation refuses without running place code. Host initialization memory is outside that guest execution limit; the worker lifetime bounds the entire attempt. During execution the unchanged declared memory, stack and execution limits apply. SIGINT reaches the worker cancellation port; cancellation or failure emits no successful object result.\n\nFor the opt-in `wasm@1` profile, the host verifies the selected context implementation before importing it. Every SHA-256 member declared by the context offer’s `restsOn` is checked by digest, and the existing `moduleClosure` validates the imported closure. Missing, altered, undeclared or unresolved imported members refuse before context code executes. This establishes content identity and import closure, not correctness, authority or sandbox confinement. Admission still precedes projection, and this check grants no permission to reuse a retained answer as current.\n" at=witness:bound020-native-closure by=target form=alphabet measure=text role=writes scope=prose/en/files/contract-engine shape=docs/contracts/engine.md value=lock
|
|
14
14
|
bound-lock/1 about="# Reference inspection through the declared content port\n\n`bound fold '#bound:1?…'` inspects a semantic standing from the location explicitly carried by its reference. The acting place supplies an admitted `content-request/1` transport selection and finite time and response-byte limits. A locator selects neither executable code nor authority. The host performs transport; no reader acquires a network effect.\n\nThe shared reference decoder checks the canonical reference. The existing transport port supplies bytes under the place's selected mechanism and limits. The shared inspector verifies the blob digest, exact document wrapper, and canonical semantic standing digest in that order. A successful result names the supplying source, both identities, and `no encounters computed · unauthenticated`; it is inspection, never a grant, admission, signature proof or encounter calculation.\n\nDigest mismatch is an integrity refusal, never a fork. Timeout aborts the native HTTP request; oversized responses cancel the body. Failed, interrupted or invalid inspection returns no successful result. This operation has no write port: it does not admit declarations, write TARGET, write receipts or retain partially received bytes. `--check`, a selection view or effectful arguments with a reference refuse by name before transport.\n\nThe positive sample is the same canonical standing wrapper already used by the reference quartet, served at a local fixture location. The negative sample changes the served bytes while keeping the declared digest. The CLI vector runs on two unrelated places and records successful inspection, wrong blob, exceeded byte budget, timeout cancellation and refusal before transport. Request paths are recorded separately from the reference: the URL fragment is not sent in HTTP requests. Page code may read a fragment; secrecy is not claimed.\n\nExternal cancellation as a general API, signature/admission of transported claims, arbitrary source protocols without a declared host binding, CORS and another-machine portability remain separate demands. No source location is a permanent service requirement.\n\nThe executable publication vector binds the existing content-request/1 command port to /bin/cat over declared immutable fixture bytes. Preparation is outside the clock; the CLI call is measured. It covers two unrelated standings and integrity refusal without a server or reader network effect. Earlier HTTP byte-limit and timeout captures remain separate evidence; this vector does not remeasure HTTP.\n\n\n## Authenticated host opening\n\n`@lapxo/bound/reference` exports `inspectAuthenticatedReference`, `encodeReference` and `decodeReference`. The host supplies its authority snapshot and epoch, public signers and coverage, admitted signature eras, admission/origin policy, selected form standing and executable implementation, finite byte/record budgets and bounded transport and cryptographic ports. Neither source URL, carrier, digest nor embedded key grants authority.\n\nThe authenticated-standing@1 carrier and effective global standing projection are defined by the consumed Topos contract. Original signatures authenticate retained historical evidence; the snapshot commitment is checked against the current authority epoch. This opening does not grant permission to reuse an answer as current. Configuration history that needs an admitted standing fold refuses by name. Only fully verified records are returned, for the same pure projection in ESM or WASM; no writer or commit port is exposed.\n\nWithout the authenticated profile, the existing CLI reference branch remains explicitly unauthenticated inspection.\n\n\n### Native authenticated opening\n\nThe same reference command consumes `reference/authentication form=alphabet measure=id value=authenticated-standing@1` from the selected local place. Without that declaration the existing inspection remains explicitly unauthenticated. With it the host requires unique authenticated declarations for `engine/object` (`esm@1` or `wasm@1`), `reference/snapshot`, `reference/epoch`, `reference/proof-scope`, `reference/records`, `reference/policy`, `reference/form-implementation`, `reference/contracts/refusals` and `reference/contracts/standing` (all `measure=id`); the snapshot is a typed SHA-256 digest, epoch and record budget are safe integers, and the record budget is positive. The declared transport supplies its own existing byte and lifetime bounds.\n\nTrust comes from the local place's admitted keys, signature eras, snapshot and selected object interpretation, including origin and witness grants. No key, grant or verifier supplied by the carrier becomes host authority. The public path delegates signatures, historical authority, wire interpretation, effective order and context admission to the existing SDK and projects admitted records through the existing engine. Signature, coverage, era, effective-order, blob-integrity and semantic-identity failures refuse before any authenticated result or cell output.\n\nOpening prints the source, authenticated semantic standing, object results and authority-context identity. It does not land an act or emit a successful partial result. Existing private content-cache stamps and store accounting may be updated; those are distinct from the public place, its signed authority and its committed history. Inspection does not grant permission to reuse an old response as a current one.\n\nFor the opt-in `authenticated-standing@1` profile, the host checks the selected context offer’s SHA-256 `restsOn` members and uses the existing `moduleClosure` before importing that context. A missing, altered, undeclared or unresolved import refuses before context code executes. The same preparation applies when the explicit object view selects `wasm@1`; absent these opt-in profiles, the existing path is unchanged. Import closure proves neither correctness nor sandbox confinement, creates no authority, and does not authorize current-answer reuse.\n\n\n### Compatibility of published 0.2.0 carriers\n\nThe original weather and editorial carriers, their signatures and effective-order counterexamples remain byte-identical. `inspectAuthenticatedReference` accepts their independently supplied legacy trust tuple without inventing the newer contract commitments. Its native vector verifies both positive carriers and their arrival-equivalent projection, and rejects signature, coverage, era, effective-order, blob and semantic-standing failures. Authority and context preparation use the existing host and SDK; no replacement verifier or form algebra is supplied by the carrier.\n\nThis preserves the carrier/API contract, not an implicit native backend. The historical receiver TARGETs omit the explicit backend and interpretation-contract lines required by native opening in 0.2.1. They therefore refuse with `reference/backend` before transport; the vector asserts that refusal instead of re-signing or weakening the fixtures. No automatic ESM fallback is added. Native positive opening with the complete admitted context is demonstrated separately by the reference-export and reference-backend quartets, including ESM/WASM equality and altered-byte refusal. `compatibility.json` records every inherited condition and expected result; the no sample still contains the original bad signature.\n" at=witness:bound021-final-bindings by=target form=alphabet measure=text role=writes scope=prose/en/files/reference-port shape=docs/contracts/reference-port.md value=lock
|
|
15
15
|
bound-lock/1 about="# Using Bound\n\nThis guide covers the current CLI in a place whose wire and authority are already admitted. A fresh unsigned TARGET is a proposal, not a trusted project. The prepared repository is not yet a certified empty-clone bootstrap.\n\n## Before the first fold\n\nYou need the team's accepted TARGET and trust context, authentic bytes for each selected digest, and the readers/views that TARGET names. Do not borrow a neighbouring repository's ledger or copy node_modules to make a missing pin look available.\n\nThe published repository carries exactly TARGET.bound and receipts.bound as bound files. Local admission history lives in the ignored .bound/ store. Published standing excludes the signature envelope; owner public keys retain their signatures.\n\nStart by asking for help and folding the project. If a selected view is unavailable, use the named refusal and its fix; do not invent an output with a similar name.\n\n## Keys and coverage\n\nUse a named key already admitted by the project. The authority contract declares its public key, class and scope coverage. Signing uses a declared port. The lock names `keys/<who> measure=signer value=<name>`; `signer/timeout` and `signer/response-bytes` bound each invocation. The built-in `file` port reads a matching PKCS8 PEM outside the repository through `--key-file`. For a command port, the host supplies a `BOUND_SIGNERS` registry mapping that admitted name to `{ \"kind\": \"command\", \"executable\": \"...\", \"args\": [] }`. A repository declaration cannot authorize a program. `--signer <name>` must match the admitted selection.\n\nA new device must have its public key and coverage admitted by an authority that already covers the intended scope. The CLI does not currently certify silent key creation or tap-to-sign. This guide does not substitute a self-authorized fixture key for the team's authority.\n\nFor automation through the file port, supply the private key through the runner's secret storage to a temporary external file with restricted permissions. A command signer receives the lot once as canonical signed bytes, one line per record in order. It returns one canonical wire response per record, containing `by` and `sig`, in that same order. Bound verifies the entire reply against the admitted public key before any admission. Timeout, nonzero exit, missing or invalid replies refuse the whole lot; raw signer output is not logged. Hosts can keep private keys outside Bound through this port. Key generation, storage and rotation belong to the host. Do not print, commit or upload it. A source-control token and a Bound authority key have different purposes. Key rotation and revocation are changes to the admitted authority contract, not edits that erase prior signatures.\n\n## Proposal → signature → admission → reading\n\nPrepare the proposed lines outside the repository. Each line must use the current wire's fields, forms and required set. Configuration retains its legacy required fields, including `at`. Typed cells, claims and marks use their exact row grammar; `role=reads` or `at` cannot repair an incomplete typed record.\n\nA proposal names `by=target` and omits epoch/signature. The CLI assigns epoch from admitted history when signing. Never copy an epoch from an example or change a signed line's body.\n\nUse the signing and admission transaction in the README. Shell `&&` prevents a failed sign from being followed by land. Successful signing alone does not mean admission. Successful admission alone does not mean every requirement is paid. Fold after land and inspect its states, receipts and exit status.\n\nCLI sign authenticates wire inscriptions. It is different from the object's travelling ceiling sign. The selected Topos decodes spans and supplies origin/witness context; Bound must not guess those from by, widens or a path.\n\n## Reading and withdrawing\n\nAsk only for a view admitted by the project, such as cells. A local join widens that cell with a witness; it leaves the travelling ceiling live. A travelling require supplies a floor. Claims carry distinct origins; their signatures do not by themselves establish independent origins.\n\nFor typed histories, a negative record names the exact id in takes. Withdrawing a claim removes that live observation; withdrawing a join removes that local widening, not the sign. A fresh claim with the same content is a new identity, not resurrection of a withdrawn id. Re-delivery of the same signed bytes is idempotent.\n\nFor configuration, the negative line preserves the exact non-envelope selectors and changes value to withdraw. Do not withdraw and replace identical selectors in the same batch. Use a new epoch when superseding an alphabet declaration. Never withdraw evidence merely to obtain a green verdict.\n\n## Receipts and refusals\n\nreceipts.bound is native fold output. Do not write it by hand, use JSON from a test as a receipt, or copy receipts from another tree. Unchanged inputs can reuse verified region receipts; missing bytes require recomputation or a refusal. A duplicate receipt does not create another origin.\n\nREFUSE·wire means the current grammar does not admit the record. REFUSE·pin/release means named authentic content or its closure is unavailable or does not match. REFUSE·view means the requested view cannot be rendered under its contract. Authority refusal means the signer is not covered. Keep the line and the failed exit status; follow an explicit fix without changing the named digest or dropping a conflicting statement.\n\nrelease/blocks is policy read by the fold. Its admitted category links select existing obligations. The fold prints each missing reading or crossed ceiling as BLOCK; a blocked or incomplete policy is not READY. Read the captured verdict for the exact candidate instead of inferring acceptance from a successful render.\n\n## Repository and PR review\n\nThe accepted TARGET is independent of a contributor's scan. Commit native receipts and admitted renders, not local .bound/ state. A page disagreeing with TARGET must be re-rendered; a ceiling is not lowered to fit the page.\n\nA contribution is a proposed lot with the leaf changes rendered from it. Send that lot for admission by the team's coverage. Do not submit hand-edited lock output as already accepted. Check secrets, extra bound files, foreign vendoring and uncaptured page claims before review.\n\nA review includes the product fold, meaningful suites and verification of the rendered bytes. Preserve their actual output and exit status.\n\n## Declaring a demand\n\nA new demand records what remains to be proved. Admission does not create conformance evidence or pay it. An OWED line after land says the declaration was admitted and remains unpaid. Signing authority and conformance evidence are separate inputs.\n\nThe selected program projection reads declared requirements and handed evidence. Missing evidence stays unread; a missing elapsed-time reading is not zero. A dependency cannot close before its requirements and predecessors. Declaring a plan never certifies a release.\n" at=witness:declared-demand-close by=target form=alphabet measure=text role=writes scope=prose/en/files/public-2 shape=docs/usage.md value=lock
|
|
16
|
+
bound-lock/1 about="# Verified executable closure delivery\n\nNeeds are arbitrary declared names, not a kernel profile enumeration.\n\nAll requested entries share the existing moduleClosure traversal; no second walker, parser or algebra.\n\nHost requires already authenticated snapshot identities; a bundle digest establishes content identity, not authority or correctness.\n\nDelivery preserves each reached JS/JSON member and explicitly pinned notices byte for byte. Separate digests identify the closure manifest and the exact UTF-8 JSON container.\n\nCanonical delivery sorts needs, reached modules, library bindings and notices; duplicate needs do not duplicate code; unsupported executable forms refuse by name.\n\nMandatory member, source byte and response byte budgets apply before delivery. Pre-aborted or observed cancellation refuses. Synchronous work is not a preemptible execution sandbox.\n\nPortable ESM delivery refuses host builtins, runtime loader access, CommonJS loads, calculated/escaped loader expressions and unsupported URL spellings before entry execution.\n\nConsumer verifies the expected container digest and repeats the same closure preflight over exactly the delivered members. Derived import maps are never trusted as authority.\n\nThe host must verify actual mounted bytes again before execution; the test host demonstrates this but is not a public browser host.\n\nExisting native, program and worker custody remain unchanged. Acorn routes stay explicitly retained under A-F gate.\n\nNo external fetch or general demand resolver is introduced. Missing bytes remain outside completed delivery and must be resolved by the existing host contract.\n" at=witness:bound023-ed by=target form=alphabet measure=text role=writes scope=prose/en/files/closure-delivery shape=docs/contracts/closure-delivery.md value=lock
|
|
16
17
|
bound-lock/1 about="# Walk\n\n`bound fold --as walk@<resolution>` compares the admitted place with an authenticated peer inventory. Resolution is interpreted by the declared Topos selection and projection contract; it is not restricted to three fixed numbers. The wire declares region membership, context, origin and cuts. The output names touched regions, open regions and payload bytes; protocol and imported bytes carry their own units.\n\nForeign history retains its signed origin epoch. Sender keys authenticate that history and never grant coverage or independent origins in the receiver. Whole-region prefixes are verified before ingress. Import and the receiver-signed local receipt commit atomically; only that receipt advances the receiver's local epoch. Foreign withdrawals are confined to the same authenticated origin and exact identifier. A repeated valid delivery adds no lines and retains its existing import receipt. A rejected or interrupted ingress adds neither evidence nor a receipt.\n\nThe published sample uses the same compiled public reader on measurement and artifact places. It compares equal summaries, opens a differing region, exchanges at intermediate declared resolutions, converges by union, retains disagreement and verifies replay after a later local act. It rejects tampered payloads, missing records, unauthorized signatures, non-prefix epochs and undeclared context changes. It interrupts a real receiver signer and verifies unchanged ingress and local history. Dead-owner recovery is a separate host action; this view does not silently recover it. The typed object's origin-local claims and withdrawals are a separate conformance vector, not inferred from configuration counts.\n" at=witness:publish-native-walk-contract by=target form=alphabet measure=text role=writes scope=prose/en/files/view-walk shape=docs/contracts/view-walk.md value=lock
|
|
17
18
|
bound-lock/1 about="# fold\n\n`bound fold` reads the admitted place. Configuration output names readings and says no encounters computed; its counts are not independent-origin states. A declared cells view projects admitted typed history into Obligations. A selected world defines other views; its contract decides when empty output is valid. A refusal or nonzero status wins over any parseable diagnostic stdout. `--check` verifies receipts without inventing a missing reading. The published evidence vector folds fresh places, preserves admitted key attribution, reads a native receipt and checks exact withdrawals. The typed-object quartet covers object states separately.\n\n# land\n\n`bound land <lot>` admits authenticated lines through the same boundary used by signing and previews. Authority, coverage, historical wire and typed context remain distinct checks. Unknown wire and tampered signatures refuse. Exact redelivery returns ONCE; it does not append another origin or grant new authority. Withdrawals remain exact under their declared contract. A refusal does not append a partial act. The published evidence vector lands fresh places, refuses unauthorized writes and tampering, redelivers signed bytes and exercises exact withdrawals. The signing-port vector additionally checks interrupted or invalid command responses do not land a partial lot.\n\n# sign\n\n`bound sign <lot>` returns canonical signed lines after validating the whole lot. The admitted key selects a declared signer; `--signer` selects the same port explicitly. File and command mechanisms use one port. Topos signing-lot/1 frames canonical bytes in lot order, one invocation per lot, and returns signatures and public-key IDs. Verification checks the admitted public key, independently of the mechanism. A command is invoked without a shell and under declared bounds. No secret output is disclosed in refusals. Missing, invalid, partial, timed-out or failed responses refuse; `land` cannot commit their partial output. The sample compares file and command signatures and landed lines, checks invocation count and ledger hashes, and refuses an unknown wire version. The sample uses ephemeral keys outside the place; no owner key is included.\n\n# Committed act results\n\nThe opt-in `local-act@1` contract is selected by `wire/act-result`, `wire/act-result-scope` and `wire/act-result-context`. An admitted `view/act measure=id value=act` makes `bound fold --as act <identity>` available. Missing or conflicting declarations refuse; an absent profile preserves the historical interface. Topos defines the canonical record and result contract.\n\nAdmission publishes the original signed records, their logical placements and one native result receipt atomically. A failure before commit writes no partial act. The result names the committed digest and local epoch; replay returns the original result without another epoch or origin. A post-commit error is not a rollback. Read the committed result before deciding whether to retry.\n\nThe query verifies the record signatures and coverage against the authority snapshot at admission, and the native receipt against its retained provenance. Later key retirement or profile replacement cannot authorize a new act but does not erase a verifiable historical result. Admission is not conformance: the output says `admitted · conformance not asserted`. Missing or corrupt results refuse by name. Host paths and delivery counts are not identity inputs.\n\n## Release approval\n\n`fold --as release <approval-file>` verifies the external approval against the place authorizer, its admitted public key, coverage and signature era. Exactly one signed release/<tag> digest, release/artifact name and sources/archive URL are required. It prints `READY sha256:<digest> <name> <source>` or refuses with the coordinate and cause. This is an approval judgment, distinct from the place release-policy verdict. It never fetches, executes, signs or lands.\n\n## Standing admission\n\nA uses/ selection admits canonical standing bytes, never an archive. The bytes must already be held under their verified digest or in the single local coordinate explicitly named by needs. Admission checks identity and canonical form without fetching, executing or writing the content store. Missing or corrupt bytes refuse the whole lot. A corrupt held copy cannot be hidden by another source. Archives remain separate dependency declarations.\n\n\n## Declared reading identity\n\nA place selects both `wire/reading-context value=reading-context@1` and `wire/reading-receipt value=reading-receipt@1`. Partial or conflicting selections refuse. Every reader under this profile declares an input projection; a legacy reader is refused by name instead of receiving a new identity without its closure.\n\nThe host commits the full instrument reference, the verified capsule implementation, effective reader policy, declared transitive references, each input's actual bytes and dependent receipt identities. The process environment is captured explicitly: inherited variable values (hashed, never printed), the place working directory, child flags, runtime bytes and platform conditions. The same captured boundary is handed to execution and keys the capsule cache. These references grant neither authority nor independence and cannot prove undeclared inputs absent.\n\nAn unchanged cross-process fold reads retained receipts with zero opened readings. Changed input reopens that reading and its dependents; changing shared implementation, policy or execution conditions invalidates the readings that depend on them. The semantic receipt names the reading and result together; elapsed time and signature envelopes remain separate. Old receipts are not promoted.\n\nRetained evidence may be inspected without asserting a current response. Reusing a current response also requires the existing snapshot-access contract: matching principal, authorization, request, implementation and snapshot, declared freshness, and both inspection and reuse permission. Unknown or expired freshness, withdrawn permission or changed context refuse before running a provider. A new observation needs its own admitted act.\n\n`fold --check` verifies the retained published evidence and instrument. It opens no reader and grants no permission to assert an old response today. A live fold additionally compares the current captured execution boundary.\n" at=witness:complete-reading-context-with-native-reuse by=target form=alphabet measure=text role=writes scope=prose/en/files/contract-cli shape=docs/contracts/cli.md value=lock
|
|
18
19
|
bound-lock/1 about="## Typed cell, claim and mark records\n\nThe object profile is selected by admitted `wire/object/*` claims in a historical wire snapshot. The epoch of `wire/object/types` is its activation E; a typed record must have epoch >= E. An older record keeps the older grammar. Merely adding object words to `wire/fields` does not admit a typed profile.\n\n`fromLine` selects grammar before validating required fields: a record without `type` remains configuration, retaining its required `at`, `role`, `form`, `measure` and `value`; a typed record selects its exact required/allowed row. Configuration cannot carry object-only fields. An incomplete typed record receives no configuration defaults. The parse result distinguishes configuration from cell/claim/mark. `sign=+1|-1` is an object act, `sig` its signature envelope, and a host sign operation produces that envelope.\n\nThe common object envelope is `type`, `scope`, `id`, `epoch`, `by`, `sig`. Object records reject `at`: epoch orders acts, and `widens` names a local join witness. The following is the declared reference profile. The admitted row alphabets, not this table or a host decoder, are the source of required/allowed field permission.\n\n| Row | Fields in addition to the common envelope | Meaning |\n| --- | --- | --- |\n| cell | form, measure, params, restsOn, topos | Define a cell and its selected form/context. |\n| claim/positive | sign, origin, value | Observe an encoded span, sign=+1. |\n| claim/negative | sign, takes | Withdraw an exact claim ID, sign=-1. |\n| mark/travelling | sign, pole, reach, value | Ceiling sign: sign=+1, pole=ceiling, reach=travels. |\n| mark/local | sign, pole, reach, value, widens | Local join: sign=+1, pole=ceiling, reach=local; another mark, retaining the travelling sign. |\n| mark/floor-travelling | sign, pole, reach, value | Travelling require: sign=+1, pole=floor, reach=travels; no widens. |\n| mark/negative | sign, takes | Withdraw an exact mark ID, sign=-1; no pole/reach/widens. |\n\nEach row has both `wire/object/required/<row>` and `wire/object/allowed/<row>`. Unknown keys, missing required keys, floor/local, floor+widens, and travelling widening refuse without coercion. A configuration demand is unrelated to a floor mark. `by` authenticates a signing key; it is not an independent observation origin.\n\nFor a cell, `restsOn=none` represents no parents; otherwise it is a canonical byte-ordered alphabet of coordinates. Several parents are permitted. Only declared cell-coordinate edges form object rest; a directory prefix, a configuration artifact digest, and a host source location do not. Context validation rejects reachable cycles before algebraic parts are requested.\n\nThe cell's `topos` names folded standing, and its `params` identifies declared parameter bytes. A selected provider decodes values and supplies origin/witness authorization from admitted evidence. A host does not infer interval endpoints, map a key to an origin, or accept widens as its own witness. Missing pin, artifact, decoder, origin or witness refuses by cause. Cell definitions and pins are immutable in this profile; migration is not inferred.\n\n`objectHistory` preserves typed history separately from configuration; `validateObjectContext` checks IDs, cell ownership, exact takes, witness order and declared rest under the selected context. Exact redelivery is idempotent; one ID with different canonical content refuses. Signature-envelope differences never bypass verification.\n\nAfter admission, the instrument projects the acts into Obligations. Sign and require travel along declared rest; a witnessed join is local. Descendants inherit travelling marks without local widening. Live exact-ID withdrawals remain confined to their authenticated history. Keys, snapshots, signing devices and repeated receipts do not create independent origins. Compatible meets are not forks. Object states and their precedence come from Obligations; configuration folds do not compute object encounters.\n" at=witness:minimal-contract-015 by=target form=alphabet measure=text role=writes scope=prose/en/files/contract-typed-object shape=docs/contracts/typed-object.md value=lock
|
|
@@ -104,7 +105,7 @@ bound-lock/1 about="Rewriting hero, idea and the other section regions as compos
|
|
|
104
105
|
bound-lock/1 about="Source origin is distinct from local coordinates; requested verified bytes are handed to every declared eligible reader." at=policy:bound/015-plan by=target form=alphabet measure=status needs=docs/contracts/region/origin-input.md|samples/yes/region/origin-input.json|vectors/region/origin-input.json|samples/no/region/origin-input.json role=demands scope=region/origin-input value=present
|
|
105
106
|
bound-lock/1 about="The coordinate of the observed host implementation digest in the native receipt set." at=policy:bound/receipts by=target form=alphabet measure=id role=writes scope=audit/wire/receipt-instrument value=instrument/implementation
|
|
106
107
|
bound-lock/1 about="The exact owner-admitted K-U SDK archive. Its digest identifies retained bytes; public availability is a separate release prerequisite." at=witness:kernel-upgrade-043-sdk021 by=target form=alphabet measure=id needs=node_modules/@lapxo/topos role=reads scope=dep/topos shape=package value=sha256:50086958553b9376d600583f7dff354196bfeb41170fc6d1482ca7bea7c493e2
|
|
107
|
-
bound-lock/1 about="The fixture instrument receives the publication projection of already admitted folded configuration; historical signatures are not copied as local authority." at=witness:
|
|
108
|
+
bound-lock/1 about="The fixture instrument receives the publication projection of already admitted folded configuration; historical signatures are not copied as local authority." at=witness:bound023-ed by=target form=alphabet measure=digest role=writes scope=uses/process-readings value=sha256:c09a81778459c87d6dc8f3770ab0fb3f4eb7b7e950a13c5c4bdbac4767387147
|
|
108
109
|
bound-lock/1 about="The fourteen proposed local-mirror source URLs were withdrawn after their draft inputs were removed. Selected standing and runtime digests remain unchanged. No matching public world delivery has been verified for those bytes; clean native closure remains unpaid. Public sources must deliver the exact selected bytes, or an explicit reviewed world release and re-pin is required; no newest-by-URL or local-store substitution." at=policy:bound/019-public-source-ci by=target form=alphabet measure=text role=writes scope=rationale/019/public-source-delivery value=present
|
|
109
110
|
bound-lock/1 about="The host adapter parses literal JavaScript imports when identifying the implementation behind receipts. It executes no module and does not inventory domain exports, duplicates or literals. It does not enforce arbitrary dynamic-import closure or claim a capsule sandbox." at=policy:host-module-identity by=target form=alphabet measure=text role=writes scope=rationale/host/module-parser value=present
|
|
110
111
|
bound-lock/1 about="The native authenticated reference route opens separately signed carriers using externally declared host authority, forms and bounded transport; positive and named negative cases are measured by the selected publication world. A zero count is conditional on the identified fixed image and laid form content; it grants neither current-answer reuse nor final archive acceptance." at=policy:bound/020-public-api-coverage by=target form=interval measure=count needs=contract/published/authenticated-reference role=reads scope=contract/published/authenticated-reference value=0..0
|
|
@@ -320,7 +321,7 @@ bound-lock/1 about="the typescript tree world after its released capsule: said,
|
|
|
320
321
|
bound-lock/1 about="the vectors a place holds, a row per region, as the fold counts them from its receipts" at=policy:bound/regions by=target form=alphabet measure=receipts role=reads scope=region/vectors value=vector/**
|
|
321
322
|
bound-lock/1 about="the vectors world saying its own description in its own lock: the regions of 2fb13c6f unchanged, its prose under its key; packed from releases only, topos 0.1.2 and the algebra release, each laid from its digest" at=policy:bound/capsules by=target form=alphabet measure=id role=writes scope=dep/topos-json/own-what shape=dist/index.js value=sha256:5ec73255e3f089e3b9c7bc1d6351a07b8aa302a346fe16ed44cbcb67293c7891
|
|
322
323
|
bound-lock/1 about="the version the forge tags, read from the manifest" at=policy:bound/pipeline by=target form=alphabet measure=id role=writes scope=pipeline/version value="node -p \"require('./package.json').version\""
|
|
323
|
-
bound-lock/1 about="the version this place is bound at" at=witness:
|
|
324
|
+
bound-lock/1 about="the version this place is bound at" at=witness:bound023-ed-api by=target form=alphabet measure=id role=writes scope=version value=0.2.3
|
|
324
325
|
bound-lock/1 about="the writer that vouches each source at the digest a take judged it: a family the wire lists, which bound reads here and never spells" at=policy:bound/store by=target form=alphabet measure=id role=reads scope=store/vouches value=tree
|
|
325
326
|
bound-lock/1 about="this place is a package: class defaults of package resolve here" at=policy:bound/place by=target form=alphabet measure=id role=writes scope=place/kind value=package
|
|
326
327
|
bound-lock/1 about="topos-node with a thin manifest: no typesVersions, main or types, dev dependencies only where a line says so, and a bin field from the place bin/<name> lines" at=policy:bound/capsules by=target form=alphabet measure=id role=writes scope=dep/topos-node/thin-manifest shape=dist/index.js value=sha256:da1fd0bb74f72ae95bce5929055c50ccd150d8903ba5560d99df48bf236d8dc0
|
|
@@ -335,7 +336,7 @@ bound-lock/1 about="what the second head found, which leaves the place has writt
|
|
|
335
336
|
bound-lock/1 about="when the apart claim is withdrawn" at=policy:bound/door by=target form=alphabet measure=id role=writes scope=form/style/fold/back value=2.2
|
|
336
337
|
bound-lock/1 about="where a located world keeps each region file, by directory and extension, so the host loads the tree beside the pin" at=policy:bound/010 by=target form=alphabet measure=id role=writes scope=release/layout value=src/regions:.ts
|
|
337
338
|
bound-lock/1 about="who signs this place" at=policy:bound/010 by=target form=alphabet measure=id role=writes scope=author value=Lapxo
|
|
338
|
-
bound-lock/1 about="{\n \"name\": \"@lapxo/bound\",\n \"version\": \"0.2.
|
|
339
|
+
bound-lock/1 about="{\n \"name\": \"@lapxo/bound\",\n \"version\": \"0.2.3\",\n \"type\": \"module\",\n \"description\": \"Read the bounds you already wrote, fold them, and name the contradictions.\",\n \"main\": \"dist/cli/verb.js\",\n \"types\": \"dist/cli/verb.d.ts\",\n \"exports\": {\n \".\": {\n \"types\": \"./dist/cli/verb.d.ts\",\n \"default\": \"./dist/cli/verb.js\"\n },\n \"./package.json\": \"./package.json\",\n \"./engine\": {\n \"types\": \"./dist/engine/index.d.ts\",\n \"default\": \"./dist/engine/index.js\"\n },\n \"./wasm\": {\n \"types\": \"./dist/wasm/adapter.d.ts\",\n \"default\": \"./dist/wasm/adapter.js\"\n },\n \"./reference\": {\n \"types\": \"./dist/host/reference-authenticated.d.ts\",\n \"default\": \"./dist/host/reference-authenticated.js\"\n },\n \"./refusals\": \"./docs/contracts/refusals.bound\",\n \"./standing-contract\": \"./docs/contracts/standing.bound\",\n \"./reference/native\": {\n \"types\": \"./dist/host/reference-native-api.d.ts\",\n \"default\": \"./dist/host/reference-native-api.js\"\n },\n \"./closure/native\": {\n \"types\": \"./dist/host/native/module-delivery.d.ts\",\n \"default\": \"./dist/host/native/module-delivery.js\"\n }\n },\n \"scripts\": {\n \"test\": \"node --import ./test/setup.ts --test --test-concurrency=2 test/*.test.ts\",\n \"clean\": \"rm -rf dist .tsbuildinfo* tsconfig.tsbuildinfo\",\n \"build\": \"node --experimental-strip-types tools/build.ts\",\n \"prepack\": \"npm run build\"\n },\n \"files\": [\n \"LICENSE\",\n \"README.md\",\n \"CONTRIBUTING.md\",\n \"dist/**/*.js\",\n \"dist/cli/verb.d.ts\",\n \"dist/engine/index.d.ts\",\n \"dist/engine/object.d.ts\",\n \"dist/host/reference-authenticated.d.ts\",\n \"dist/host/reference-export.d.ts\",\n \"dist/host/reference-native-api.d.ts\",\n \"dist/host/reference-native.d.ts\",\n \"dist/host/reference-profile.d.ts\",\n \"dist/host/refusals.d.ts\",\n \"dist/wasm/adapter.d.ts\",\n \"TARGET.bound\",\n \"receipts.bound\",\n \"docs/usage.md\",\n \"docs/readme-assets/atlas.svg\",\n \"docs/contracts/*.md\",\n \"docs/contracts/publication-additions.inventory.json\",\n \"docs/contracts/engine-object-projection.publication.json\",\n \"samples/engine-alphabet/TARGET.bound\",\n \"samples/engine-alphabet/inputs/sample.json\",\n \"samples/engine-alphabet/package.json\",\n \"samples/engine-alphabet/reader.js\",\n \"samples/engine-alphabet/receipts.bound\",\n \"samples/engine-interval/TARGET.bound\",\n \"samples/engine-interval/inputs/sample.json\",\n \"samples/engine-interval/package.json\",\n \"samples/engine-interval/reader.js\",\n \"samples/engine-interval/receipts.bound\",\n \"samples/no/engine-order/TARGET.bound\",\n \"samples/no/engine-order/inputs/sample.json\",\n \"samples/no/engine-order/package.json\",\n \"samples/no/engine-order/reader.js\",\n \"vectors/engine-object.cli.json\",\n \"samples/reference-port/yes/catalog/TARGET.bound\",\n \"samples/reference-port/yes/catalog/standing.json\",\n \"samples/reference-port/no/catalog/standing.json\",\n \"samples/reference-port/yes/catalog/transport.json\",\n \"samples/reference-port/no/catalog/transport.json\",\n \"samples/reference-port/yes/route-notes/TARGET.bound\",\n \"samples/reference-port/yes/route-notes/standing.json\",\n \"samples/reference-port/no/route-notes/standing.json\",\n \"samples/reference-port/yes/route-notes/transport.json\",\n \"samples/reference-port/no/route-notes/transport.json\",\n \"vectors/reference-port.cli.json\",\n \"docs/contracts/reference-port.publication.json\",\n \"assets/wasm/*\",\n \"licenses/wasm/*\",\n \"samples/authenticated-reference/no.json\",\n \"samples/authenticated-reference/yes/editorial-state/TARGET.bound\",\n \"samples/authenticated-reference/yes/editorial-state/inputs/arrival.json\",\n \"samples/authenticated-reference/yes/editorial-state/inputs/coverage.json\",\n \"samples/authenticated-reference/yes/editorial-state/inputs/era.json\",\n \"samples/authenticated-reference/yes/editorial-state/inputs/order.json\",\n \"samples/authenticated-reference/yes/editorial-state/inputs/signature.json\",\n \"samples/authenticated-reference/yes/editorial-state/inputs/transport.arrival.json\",\n \"samples/authenticated-reference/yes/editorial-state/inputs/transport.coverage.json\",\n \"samples/authenticated-reference/yes/editorial-state/inputs/transport.era.json\",\n \"samples/authenticated-reference/yes/editorial-state/inputs/transport.order.json\",\n \"samples/authenticated-reference/yes/editorial-state/inputs/transport.signature.json\",\n \"samples/authenticated-reference/yes/editorial-state/inputs/transport.yes.json\",\n \"samples/authenticated-reference/yes/editorial-state/inputs/yes.json\",\n \"samples/authenticated-reference/yes/weather-reading/TARGET.bound\",\n \"samples/authenticated-reference/yes/weather-reading/inputs/arrival.json\",\n \"samples/authenticated-reference/yes/weather-reading/inputs/coverage.json\",\n \"samples/authenticated-reference/yes/weather-reading/inputs/era.json\",\n \"samples/authenticated-reference/yes/weather-reading/inputs/order.json\",\n \"samples/authenticated-reference/yes/weather-reading/inputs/signature.json\",\n \"samples/authenticated-reference/yes/weather-reading/inputs/transport.arrival.json\",\n \"samples/authenticated-reference/yes/weather-reading/inputs/transport.coverage.json\",\n \"samples/authenticated-reference/yes/weather-reading/inputs/transport.era.json\",\n \"samples/authenticated-reference/yes/weather-reading/inputs/transport.order.json\",\n \"samples/authenticated-reference/yes/weather-reading/inputs/transport.signature.json\",\n \"samples/authenticated-reference/yes/weather-reading/inputs/transport.yes.json\",\n \"samples/authenticated-reference/yes/weather-reading/inputs/yes.json\",\n \"samples/authenticated-reference/yes.json\",\n \"vectors/native/authenticated-reference-formation.vector.json\",\n \"vectors/native/authenticated-reference.cli.json\",\n \"vectors/native/authenticated-reference.vector.json\",\n \"samples/wasm/editorial-notes/TARGET.bound\",\n \"samples/wasm/editorial-notes/esm.bound\",\n \"samples/wasm/editorial-notes/no-deadline.bound\",\n \"samples/wasm/editorial-notes/no-memory.bound\",\n \"samples/wasm/editorial-notes/no-missing-limit.bound\",\n \"samples/wasm/editorial-notes/receipts.bound\",\n \"samples/wasm/water-level/TARGET.bound\",\n \"samples/wasm/water-level/esm.bound\",\n \"samples/wasm/water-level/no-deadline.bound\",\n \"samples/wasm/water-level/no-memory.bound\",\n \"samples/wasm/water-level/no-missing-limit.bound\",\n \"samples/wasm/water-level/receipts.bound\",\n \"vectors/wasm-object.cli.json\",\n \"docs/contracts/optional-wasm-adapter.publication.json\",\n \"docs/contracts/authenticated-reference.publication.json\",\n \"docs/contracts/native-publication.inventory.json\",\n \"docs/contracts/refusals.bound\",\n \"docs/contracts/standing.bound\",\n \"docs/contracts/reference-export.publication.json\",\n \"samples/reference-export/yes.json\",\n \"samples/reference-export/no.json\",\n \"vectors/native/reference-export.vector.json\",\n \"docs/contracts/standing.publication.json\",\n \"samples/standing/yes.json\",\n \"samples/standing/no.json\",\n \"vectors/native/standing.vector.json\",\n \"docs/contracts/refusals.publication.json\",\n \"samples/refusals/yes.json\",\n \"samples/refusals/no.json\",\n \"vectors/native/refusals.vector.json\",\n \"docs/contracts/reference-backend.publication.json\",\n \"samples/reference-backend/yes.json\",\n \"samples/reference-backend/no.json\",\n \"samples/reference-backend/world-fixture.json\",\n \"vectors/native/reference-backend.vector.json\",\n \"samples/authenticated-reference/compatibility.json\",\n \"dist/engine/ports.d.ts\",\n \"docs/contracts/host-ports.publication.json\",\n \"samples/host-ports/yes.json\",\n \"samples/host-ports/no.json\",\n \"vectors/native/host-ports.vector.json\",\n \"docs/contracts/readme.publication.json\",\n \"samples/readme/yes.json\",\n \"samples/readme/no.json\",\n \"vectors/native/readme.vector.json\",\n \"samples/engine-place/inputs/closure.json\",\n \"dist/host/native/module-delivery.d.ts\",\n \"dist/host/native/module-closure.d.ts\",\n \"docs/contracts/closure-delivery.md\",\n \"docs/contracts/closure-delivery.publication.json\",\n \"samples/module-delivery/inputs/delivery.json\",\n \"samples/no/module-delivery/delivery.json\",\n \"vectors/native/module-delivery.vector.json\"\n ],\n \"author\": \"Lapxo\",\n \"license\": \"MIT\",\n \"dependencies\": {\n \"@lapxo/obligations\": \"0.4.3\",\n \"@lapxo/topos\": \"^0.2.1\",\n \"acorn\": \"8.19.0\"\n },\n \"devDependencies\": {\n \"@types/node\": \"^20.0.0\",\n \"typescript\": \"^5.0.0\"\n },\n \"sideEffects\": false,\n \"engines\": {\n \"node\": \">=22.15\"\n },\n \"bin\": {\n \"bound\": \"./dist/cli/verb.js\"\n },\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"git+https://github.com/Lapxo/bound.git\"\n },\n \"homepage\": \"https://github.com/Lapxo/bound#readme\",\n \"bugs\": {\n \"url\": \"https://github.com/Lapxo/bound/issues\"\n },\n \"keywords\": [\n \"cli\",\n \"content-addressed\",\n \"provenance\",\n \"receipts\",\n \"constraints\",\n \"reproducible\"\n ]\n}\n" at=witness:bound023-ed-api by=target form=alphabet measure=text role=writes scope=prose/en/files/manifest shape=package.json value=lock
|
|
339
340
|
bound-lock/1 about="{\n \"profile\": \"quartet-process@1\",\n \"scope\": \"contract/published/additions\",\n \"surface\": [\n \"contract/published/engine-object-projection\",\n \"contract/published/reference-port\"\n ]\n}\n" at=policy:bound/020-publication-additions by=target form=alphabet measure=text role=writes scope=prose/en/files/publication-additions-inventory shape=docs/contracts/publication-additions.inventory.json value=lock
|
|
340
341
|
bound-lock/1 about="{\n \"profile\": \"quartet-process@1\",\n \"scope\": \"contract/published\",\n \"surface\": [\n \"contract/published/attest-evidence-view\",\n \"contract/published/cli/fold\",\n \"contract/published/cli/land\",\n \"contract/published/cli/sign\",\n \"contract/published/pipeline/archive\",\n \"contract/published/typed-object-sample\",\n \"contract/published/view/card\",\n \"contract/published/view/citation-file\",\n \"contract/published/view/explanation\",\n \"contract/published/view/guide\",\n \"contract/published/view/help\",\n \"contract/published/view/lines\",\n \"contract/published/view/manifest-render\",\n \"contract/published/view/programs\",\n \"contract/published/view/readme-historical\",\n \"contract/published/view/receipts\",\n \"contract/published/view/reference\",\n \"contract/published/view/release-workflow-render\",\n \"contract/published/view/tsconfig\",\n \"contract/published/view/usage-profile\",\n \"contract/published/view/walk\",\n \"contract/published/view/why\"\n ],\n \"note\": \"Explicit public-surface inventory. A selected coordinate without a descriptor is unpaid. Outstanding capability demands are not advertised implementations.\"\n}" at=witness:exact-archive-conformance by=target form=alphabet measure=text role=writes scope=prose/en/files/publication-inventory shape=docs/contracts/publication.inventory.json value=lock
|
|
341
342
|
bound-lock/1 about="{count} hold" at=policy:bound/010 by=target form=alphabet measure=text role=writes scope=prose/en/badge/held value=lock
|
|
@@ -464,7 +465,6 @@ bound-lock/1 at=witness:bound021-final-bindings by=target form=alphabet measure=
|
|
|
464
465
|
bound-lock/1 at=witness:bound021-final-bindings by=target form=alphabet measure=id needs=docs/contracts/reference-export.md role=demands scope=view/contract-reference-export shape=docs/contracts/reference-export.md value=text@3
|
|
465
466
|
bound-lock/1 at=witness:bound021-final-bindings by=target form=alphabet measure=id needs=docs/contracts/refusals.md role=demands scope=view/contract-refusals shape=docs/contracts/refusals.md value=text@3
|
|
466
467
|
bound-lock/1 at=witness:bound021-final-bindings by=target form=alphabet measure=id needs=docs/contracts/standing.md role=demands scope=view/contract-standing shape=docs/contracts/standing.md value=text@3
|
|
467
|
-
bound-lock/1 at=witness:bound021-final-bindings by=target form=alphabet measure=id role=writes scope=release/category/contract value=contract/published|contract/published/additions|contract/published/authenticated-reference|contract/published/optional-wasm-adapter|engine/prerequisite/**|contract/published/reference-export|contract/published/reference-backend|contract/published/standing|contract/published/refusals|contract/published/host-ports|contract/published/readme
|
|
468
468
|
bound-lock/1 at=witness:bound021-final-bindings by=target form=alphabet measure=reads role=writes scope=region/contract-host-ports value=prose/en/files/contract-host-ports
|
|
469
469
|
bound-lock/1 at=witness:bound021-final-bindings by=target form=alphabet measure=reads role=writes scope=region/contract-reference-backend value=prose/en/files/contract-reference-backend
|
|
470
470
|
bound-lock/1 at=witness:bound021-final-bindings by=target form=alphabet measure=reads role=writes scope=region/contract-reference-export value=prose/en/files/contract-reference-export
|
|
@@ -475,25 +475,33 @@ bound-lock/1 at=witness:bound021-retained-additions-binding by=target form=alpha
|
|
|
475
475
|
bound-lock/1 at=witness:bound021-retained-additions-binding by=target form=alphabet measure=digest role=writes scope=uses/publication-additions value=sha256:1e06815e421d5374f8f2fca48f7148e02c67cfa9a07873afca49a0d48ae74375
|
|
476
476
|
bound-lock/1 at=witness:bound021-retained-additions-binding by=target form=alphabet measure=id role=writes scope=sources/publication-additions value=https://github.com/Lapxo/bound/releases/download/v0.2.1/publication-additions-standing.bound
|
|
477
477
|
bound-lock/1 at=witness:bound021-retained-additions-binding by=target form=alphabet measure=id role=writes scope=sources/runtime-publication-additions value=https://github.com/Lapxo/bound/releases/download/v0.2.1/publication-additions-readings.tgz
|
|
478
|
-
bound-lock/1 at=witness:bound022-bootstrap-location by=target form=alphabet measure=digest role=writes scope=dep/runtime-process-readings shape=dist/index.js value=sha256:5c8229b9c82e551b88a646494de9afd96ad5895de4c058e54ff6d913fb9811ed
|
|
479
|
-
bound-lock/1 at=witness:bound022-bootstrap-location by=target form=alphabet measure=digest role=writes scope=dep/runtime-source-readings shape=dist/index.js value=sha256:481664ae355926dc366a521f5c48b77397c3c4228b85df58078474d0f42d761a
|
|
480
|
-
bound-lock/1 at=witness:bound022-bootstrap-location by=target form=alphabet measure=digest role=writes scope=uses/source-readings value=sha256:15275d5f750d146e511a7266d49611a74a42d9f65b0a4216e7818b27ebb642b3
|
|
481
478
|
bound-lock/1 at=witness:bound022-publication-image-and-context by=target form=alphabet measure=digest needs=README.md role=writes scope=contract/source/readme value=sha256:bc8277eaef68f8ab8a049607003502a1979fb58a36f9468d6224ec14df7e131f
|
|
482
|
-
bound-lock/1 at=witness:bound022-publication-image-and-context by=target form=alphabet measure=id role=writes scope=sources/publication-readings value=https://github.com/Lapxo/bound/releases/download/v0.2.2/legacy-publication-standing.bound
|
|
483
|
-
bound-lock/1 at=witness:bound022-publication-image-and-context by=target form=alphabet measure=id role=writes scope=sources/runtime-publication-readings value=https://github.com/Lapxo/bound/releases/download/v0.2.2/legacy-publication-readings.tgz
|
|
484
|
-
bound-lock/1 at=witness:bound022-restored-parallel-document-publication by=target form=alphabet measure=digest role=writes scope=dep/runtime-publication-readings shape=dist/provider.js value=sha256:46a14395eb9f8d6580477cc2daf4b29863aff14c2bba6423b55a8f0e6df376a2
|
|
485
|
-
bound-lock/1 at=witness:bound022-restored-parallel-document-publication by=target form=alphabet measure=digest role=writes scope=uses/publication-readings value=sha256:a18a6e176ddf97f428e506b831e22fa20930780462462bbe3cce6dff076c5d26
|
|
486
|
-
bound-lock/1 at=witness:bound022-standing-atomic-publication by=target form=alphabet measure=digest role=writes scope=dep/runtime-native-publication shape=dist/provider.js value=sha256:3ca044687042b016c9e6b97418a18d93aee0d2250b39dcd698953e794d527009
|
|
487
|
-
bound-lock/1 at=witness:bound022-standing-atomic-publication by=target form=alphabet measure=digest role=writes scope=uses/native-publication value=sha256:84155c3103fb7b0f970bb85e835753bd0af69e5ca2ffe6a443410af4fbd03e0e
|
|
488
479
|
bound-lock/1 at=witness:bound022/ep-complete-reading by=target form=alphabet measure=digest role=writes scope=dep/ep-closure-reader shape=entry.js value=sha256:4644ac239def863f6de1af850672a2435274eafff0974b187355597454faf34b
|
|
489
480
|
bound-lock/1 at=witness:bound022/ep-complete-reading by=target form=alphabet measure=digest role=writes scope=uses/ep-closure-reader value=sha256:b716942e45a272eb43b9790e2e62732471db4bd2a9c007ea4c66eb3453d0bf79
|
|
490
481
|
bound-lock/1 at=witness:bound022/ep-entry-shape by=target form=alphabet measure=id role=reads scope=wire/shapes value=decision|lock|package|reader|render|run|vector|view|entry.js
|
|
491
|
-
bound-lock/1 at=witness:
|
|
492
|
-
bound-lock/1 at=witness:
|
|
493
|
-
bound-lock/1 at=witness:
|
|
494
|
-
bound-lock/1 at=witness:
|
|
495
|
-
bound-lock/1 at=witness:
|
|
496
|
-
bound-lock/1 at=witness:
|
|
482
|
+
bound-lock/1 at=witness:bound023-ed by=target form=alphabet measure=coordinates role=writes scope=region/delivery value=samples/module-delivery/inputs/delivery.json
|
|
483
|
+
bound-lock/1 at=witness:bound023-ed by=target form=alphabet measure=digest role=writes scope=dep/runtime-native-publication shape=dist/provider.js value=sha256:e5948f8a0a771e4d2f75a762e28c3d2341bdd1881d91fdf27dd21e47b289dfad
|
|
484
|
+
bound-lock/1 at=witness:bound023-ed by=target form=alphabet measure=digest role=writes scope=dep/runtime-process-readings shape=dist/index.js value=sha256:49bcc25eaac2cd715a331f59ced51f781f8fe58a1f44fb81b5d1a25dfbf6a762
|
|
485
|
+
bound-lock/1 at=witness:bound023-ed by=target form=alphabet measure=digest role=writes scope=dep/runtime-publication-readings shape=dist/provider.js value=sha256:9a76b9599844ee2059b9b7f851092f518dce8804eabacb71c2dc0f0b5d252a49
|
|
486
|
+
bound-lock/1 at=witness:bound023-ed by=target form=alphabet measure=digest role=writes scope=dep/runtime-source-readings shape=dist/index.js value=sha256:a1f8150d7251f067701376fe30adbc62a4e5f36d83e785d16fff61bf7b76772e
|
|
487
|
+
bound-lock/1 at=witness:bound023-ed by=target form=alphabet measure=digest role=writes scope=uses/native-publication value=sha256:39839a40a628f2a7b98bfa0895703472b13f41758635a0bea4b8ec2c3eff4c28
|
|
488
|
+
bound-lock/1 at=witness:bound023-ed by=target form=alphabet measure=digest role=writes scope=uses/publication-readings value=sha256:50f0395d96d6d7c2d558f6bc5f033688eeed0865f28182768abb997fc345c528
|
|
489
|
+
bound-lock/1 at=witness:bound023-ed by=target form=alphabet measure=digest role=writes scope=uses/source-readings value=sha256:0b9eb6b57089c88ed1edff4c98b110ccaa024926e432a12ad530c6d1575fc4aa
|
|
490
|
+
bound-lock/1 at=witness:bound023-ed by=target form=alphabet measure=id needs=docs/contracts/closure-delivery.md role=demands scope=view/closure-delivery-contract shape=docs/contracts/closure-delivery.md value=text@3
|
|
491
|
+
bound-lock/1 at=witness:bound023-ed by=target form=alphabet measure=id role=writes scope=dep/runtime-closure-delivery shape=entry.js value=sha256:3ee0774f70b8e2a7f0c239e286d2fba890efe7a2b9da2a6b907d34e60c526c0d
|
|
492
|
+
bound-lock/1 at=witness:bound023-ed by=target form=alphabet measure=id role=writes scope=release/category/contract value=contract/published|contract/published/additions|contract/published/authenticated-reference|contract/published/optional-wasm-adapter|engine/prerequisite/**|contract/published/reference-export|contract/published/reference-backend|contract/published/standing|contract/published/refusals|contract/published/host-ports|contract/published/readme|delivery/violations
|
|
493
|
+
bound-lock/1 at=witness:bound023-ed by=target form=alphabet measure=id role=writes scope=sources/closure-delivery value=https://github.com/Lapxo/bound/releases/download/v0.2.3/closure-delivery-standing.bound
|
|
494
|
+
bound-lock/1 at=witness:bound023-ed by=target form=alphabet measure=id role=writes scope=sources/native-publication value=https://github.com/Lapxo/bound/releases/download/v0.2.3/native-publication-standing.bound
|
|
495
|
+
bound-lock/1 at=witness:bound023-ed by=target form=alphabet measure=id role=writes scope=sources/process-readings value=https://github.com/Lapxo/bound/releases/download/v0.2.3/process-standing.bound
|
|
496
|
+
bound-lock/1 at=witness:bound023-ed by=target form=alphabet measure=id role=writes scope=sources/publication-readings value=https://github.com/Lapxo/bound/releases/download/v0.2.3/legacy-publication-standing.bound
|
|
497
|
+
bound-lock/1 at=witness:bound023-ed by=target form=alphabet measure=id role=writes scope=sources/runtime-closure-delivery value=https://github.com/Lapxo/bound/releases/download/v0.2.3/closure-delivery-readings.tgz
|
|
498
|
+
bound-lock/1 at=witness:bound023-ed by=target form=alphabet measure=id role=writes scope=sources/runtime-native-publication value=https://github.com/Lapxo/bound/releases/download/v0.2.3/native-publication-readings.tgz
|
|
499
|
+
bound-lock/1 at=witness:bound023-ed by=target form=alphabet measure=id role=writes scope=sources/runtime-process-readings value=https://github.com/Lapxo/bound/releases/download/v0.2.3/process-readings.tgz
|
|
500
|
+
bound-lock/1 at=witness:bound023-ed by=target form=alphabet measure=id role=writes scope=sources/runtime-publication-readings value=https://github.com/Lapxo/bound/releases/download/v0.2.3/legacy-publication-readings.tgz
|
|
501
|
+
bound-lock/1 at=witness:bound023-ed by=target form=alphabet measure=id role=writes scope=sources/runtime-source-readings value=https://github.com/Lapxo/bound/releases/download/v0.2.3/source-readings.tgz
|
|
502
|
+
bound-lock/1 at=witness:bound023-ed by=target form=alphabet measure=id role=writes scope=sources/source-readings value=https://github.com/Lapxo/bound/releases/download/v0.2.3/source-standing.bound
|
|
503
|
+
bound-lock/1 at=witness:bound023-ed by=target form=alphabet measure=id role=writes scope=uses/closure-delivery value=sha256:ad759c5b607e89e1ea991b7aa62ae1e42ea3d08b2e1553875267572323a8e51c
|
|
504
|
+
bound-lock/1 at=witness:bound023-ed-obligation by=target form=interval measure=count role=reads scope=delivery/violations value=0..0
|
|
497
505
|
bound-lock/1 at=witness:engine-api-publication by=target form=alphabet measure=id needs=docs/contracts/engine.md role=demands scope=view/contract-engine shape=docs/contracts/engine.md value=text@3
|
|
498
506
|
bound-lock/1 at=witness:engine-api-publication by=target form=alphabet measure=reads role=writes scope=region/contract-engine value=prose/en/files/contract-engine
|
|
499
507
|
bound-lock/1 at=witness:kernel-upgrade-043 by=target form=alphabet measure=id role=writes scope=sources/obligations value=https://registry.npmjs.org/@lapxo/obligations/-/obligations-0.4.3.tgz
|
|
@@ -7,6 +7,7 @@ var __rewriteRelativeImportExtension = (this && this.__rewriteRelativeImportExte
|
|
|
7
7
|
return path;
|
|
8
8
|
};
|
|
9
9
|
import { sha256 as digest } from "../hash.js";
|
|
10
|
+
import { compareStrings as order } from "../order.js";
|
|
10
11
|
import { realpathSync } from 'node:fs';
|
|
11
12
|
import { dirname, join, relative, isAbsolute, sep } from 'node:path';
|
|
12
13
|
import { readBoundedFile } from "./bounded-file.js";
|
|
@@ -70,7 +71,6 @@ export function installNativeResolutionReuse(declaration) {
|
|
|
70
71
|
fail('invalid/ambiguous logical library coordinate');
|
|
71
72
|
namedCoordinates.add(coordinate);
|
|
72
73
|
}
|
|
73
|
-
const order = (a, b) => a < b ? -1 : a > b ? 1 : 0;
|
|
74
74
|
const identity = digest(Buffer.from(JSON.stringify([declaration.platform, files.map(member => [member.path, member.digest, member.bytes]).sort((a, b) => order(String(a[0]), String(b[0]))), [...libraries].sort(([a], [b]) => order(a, b)).map(([name, manifest]) => [name, manifest, coordinates.get(name) ?? null])])));
|
|
75
75
|
if (resolutionIdentity !== undefined) {
|
|
76
76
|
if (identity !== resolutionIdentity)
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
export interface ModuleClosureMember {
|
|
2
|
+
readonly digest: string;
|
|
3
|
+
readonly source: string;
|
|
4
|
+
}
|
|
5
|
+
export interface ModuleClosureSnapshot {
|
|
6
|
+
readonly identity: string;
|
|
7
|
+
readonly entry: string;
|
|
8
|
+
readonly members: ReadonlyMap<string, ModuleClosureMember>;
|
|
9
|
+
}
|
|
10
|
+
export interface ModuleClosureReading {
|
|
11
|
+
readonly snapshot: string;
|
|
12
|
+
readonly coordinate: string;
|
|
13
|
+
readonly digest: string;
|
|
14
|
+
}
|
|
15
|
+
export interface ModuleClosureLimits {
|
|
16
|
+
readonly members: number;
|
|
17
|
+
readonly bytes: number;
|
|
18
|
+
readonly portableESM?: boolean;
|
|
19
|
+
readonly signal?: AbortSignal;
|
|
20
|
+
}
|
|
21
|
+
/** Host-selected archive and entry, never a verifier assertion from the program.
|
|
22
|
+
* This proves content identity only; standing admission and runtime capabilities
|
|
23
|
+
* are separate prerequisites. Binary resources are not executable text members.
|
|
24
|
+
*/
|
|
25
|
+
export declare function moduleSnapshot(archive: Uint8Array, expected: string, entry: string): ModuleClosureSnapshot;
|
|
26
|
+
/** The host supplies authenticated snapshot identities and its library resolver.
|
|
27
|
+
* Each reached text member is verified here against its exact UTF-8 bytes.
|
|
28
|
+
* Authentication of the snapshot envelope remains a separate host prerequisite.
|
|
29
|
+
* A capsule cannot select either verifier or resolver.
|
|
30
|
+
* This reads declared module edges, not arbitrary I/O or a JavaScript sandbox. Computed edges are unpaid, never absent.
|
|
31
|
+
* Activation requires an admitted host policy; existing inventory callers are not silently changed.
|
|
32
|
+
*/
|
|
33
|
+
export declare function moduleClosure(snapshot: ModuleClosureSnapshot, library: (specifier: string, parent: ModuleClosureSnapshot) => ModuleClosureSnapshot | undefined): readonly ModuleClosureReading[];
|
|
34
|
+
/** Multiple needs share the existing traversal and one optional act budget. */
|
|
35
|
+
export declare function moduleClosures(snapshots: readonly ModuleClosureSnapshot[], library: (specifier: string, parent: ModuleClosureSnapshot) => ModuleClosureSnapshot | undefined, limits?: ModuleClosureLimits): readonly ModuleClosureReading[];
|
|
@@ -38,7 +38,14 @@ export function moduleSnapshot(archive, expected, entry) {
|
|
|
38
38
|
* Activation requires an admitted host policy; existing inventory callers are not silently changed.
|
|
39
39
|
*/
|
|
40
40
|
export function moduleClosure(snapshot, library) {
|
|
41
|
+
return moduleClosures([snapshot], library);
|
|
42
|
+
}
|
|
43
|
+
/** Multiple needs share the existing traversal and one optional act budget. */
|
|
44
|
+
export function moduleClosures(snapshots, library, limits) {
|
|
45
|
+
if (limits && (!Number.isSafeInteger(limits.members) || limits.members < 1 || !Number.isSafeInteger(limits.bytes) || limits.bytes < 1))
|
|
46
|
+
throw Error('REFUSE·module closure missing input resources');
|
|
41
47
|
const seen = new Map();
|
|
48
|
+
let totalBytes = 0;
|
|
42
49
|
const coordinate = (name) => {
|
|
43
50
|
const normalized = posix.normalize(name);
|
|
44
51
|
if (!name || name.includes('\0') || name.includes('\\') || posix.isAbsolute(name) || normalized === '..' || normalized.startsWith('../'))
|
|
@@ -46,12 +53,19 @@ export function moduleClosure(snapshot, library) {
|
|
|
46
53
|
return normalized;
|
|
47
54
|
};
|
|
48
55
|
const walk = (one, name) => {
|
|
56
|
+
if (limits?.signal?.aborted)
|
|
57
|
+
throw Error('REFUSE·module closure cancelled');
|
|
49
58
|
const at = coordinate(name), key = JSON.stringify([one.identity, at]);
|
|
59
|
+
if (limits?.portableESM && /[%?#]/.test(at))
|
|
60
|
+
throw Error('REFUSE·module closure unsupported URL coordinate ' + at);
|
|
50
61
|
const member = one.members.get(at);
|
|
51
62
|
if (member === undefined)
|
|
52
63
|
throw Error('REFUSE·module closure missing ' + one.identity + ' ' + at);
|
|
53
64
|
if (typeof member.source !== 'string' || !/^sha256:[0-9a-f]{64}$/.test(member.digest))
|
|
54
65
|
throw Error('REFUSE·module closure unnamed bytes ' + one.identity + ' ' + at);
|
|
66
|
+
const size = Buffer.byteLength(member.source, 'utf8');
|
|
67
|
+
if (limits && !seen.has(key) && (seen.size >= limits.members || size > limits.bytes - totalBytes))
|
|
68
|
+
throw Error('REFUSE·module closure input resources');
|
|
55
69
|
const bytes = Buffer.from(member.source, 'utf8');
|
|
56
70
|
if (bytes.toString('utf8') !== member.source)
|
|
57
71
|
throw Error('REFUSE·module closure invalid UTF-8 text ' + one.identity + ' ' + at);
|
|
@@ -63,18 +77,34 @@ export function moduleClosure(snapshot, library) {
|
|
|
63
77
|
throw Error('REFUSE·module closure conflicting member ' + one.identity + ' ' + at);
|
|
64
78
|
return;
|
|
65
79
|
}
|
|
80
|
+
totalBytes += size;
|
|
66
81
|
seen.set(key, { snapshot: one.identity, coordinate: at, digest: member.digest });
|
|
82
|
+
if (limits?.portableESM && !['.js', '.json'].includes(posix.extname(at)))
|
|
83
|
+
throw Error('REFUSE·module closure unsupported ESM member ' + at);
|
|
67
84
|
// JSON is data under the loader contract, not module syntax.
|
|
68
|
-
if (posix.extname(at) === '.json')
|
|
85
|
+
if (posix.extname(at) === '.json') {
|
|
86
|
+
if (limits?.portableESM) {
|
|
87
|
+
try {
|
|
88
|
+
JSON.parse(member.source);
|
|
89
|
+
}
|
|
90
|
+
catch {
|
|
91
|
+
throw Error('REFUSE·module closure invalid JSON member ' + at);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
69
94
|
return;
|
|
70
|
-
|
|
95
|
+
}
|
|
96
|
+
const syntax = moduleImportSyntax(member.source, at, limits?.portableESM ? { esmOnly: true } : undefined);
|
|
71
97
|
if (syntax.unresolved.length)
|
|
72
98
|
throw Error('REFUSE·module closure unresolved ' + at + ' ' + syntax.unresolved.join(' · '));
|
|
73
99
|
for (const specifier of syntax.imports) {
|
|
100
|
+
if (limits?.portableESM && /[%?#\\]/.test(specifier))
|
|
101
|
+
throw Error('REFUSE·module closure unsupported URL specifier ' + specifier + ' from ' + at);
|
|
74
102
|
// createRequire/registerHooks can select executable edges not present in this graph.
|
|
75
103
|
// Their runtime closure needs its own host contract; an arbitrary alias is not a literal edge.
|
|
76
104
|
if (specifier === 'node:module' || specifier === 'module')
|
|
77
105
|
throw Error('REFUSE·module closure runtime loader requires declared closure ' + specifier + ' from ' + at);
|
|
106
|
+
if (limits?.portableESM && (specifier.startsWith('node:') || builtinModules.includes(specifier)))
|
|
107
|
+
throw Error('REFUSE·module closure host builtin in portable delivery ' + specifier + ' from ' + at);
|
|
78
108
|
if (specifier.startsWith('node:')) {
|
|
79
109
|
if (!builtinModules.includes(specifier) && !builtinModules.includes(specifier.slice(5)))
|
|
80
110
|
throw Error('REFUSE·module closure unknown builtin ' + specifier + ' from ' + at);
|
|
@@ -94,6 +124,7 @@ export function moduleClosure(snapshot, library) {
|
|
|
94
124
|
walk(pinned, pinned.entry);
|
|
95
125
|
}
|
|
96
126
|
};
|
|
97
|
-
|
|
127
|
+
for (const snapshot of snapshots)
|
|
128
|
+
walk(snapshot, snapshot.entry);
|
|
98
129
|
return [...seen.values()];
|
|
99
130
|
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { type ModuleClosureSnapshot, type ModuleClosureLimits } from './module-closure.ts';
|
|
2
|
+
export { moduleSnapshot, type ModuleClosureSnapshot } from './module-closure.ts';
|
|
3
|
+
export interface ClosureDeliveryLimits extends Omit<ModuleClosureLimits, 'portableESM'> {
|
|
4
|
+
readonly responseBytes: number;
|
|
5
|
+
}
|
|
6
|
+
export interface ClosureNotice {
|
|
7
|
+
readonly snapshot: string;
|
|
8
|
+
readonly coordinate: string;
|
|
9
|
+
readonly digest: string;
|
|
10
|
+
readonly source: string;
|
|
11
|
+
}
|
|
12
|
+
export interface ClosureDeliveryManifest {
|
|
13
|
+
readonly format: 'esm-file-closure/1';
|
|
14
|
+
readonly needs: readonly {
|
|
15
|
+
name: string;
|
|
16
|
+
snapshot: string;
|
|
17
|
+
entry: string;
|
|
18
|
+
}[];
|
|
19
|
+
readonly modules: readonly {
|
|
20
|
+
snapshot: string;
|
|
21
|
+
coordinate: string;
|
|
22
|
+
digest: string;
|
|
23
|
+
path: string;
|
|
24
|
+
}[];
|
|
25
|
+
readonly libraries: readonly {
|
|
26
|
+
parent: string;
|
|
27
|
+
specifier: string;
|
|
28
|
+
snapshot: string;
|
|
29
|
+
entry: string;
|
|
30
|
+
}[];
|
|
31
|
+
readonly notices: readonly {
|
|
32
|
+
snapshot: string;
|
|
33
|
+
coordinate: string;
|
|
34
|
+
digest: string;
|
|
35
|
+
path: string;
|
|
36
|
+
}[];
|
|
37
|
+
}
|
|
38
|
+
export interface ClosureDelivery {
|
|
39
|
+
readonly closure: string;
|
|
40
|
+
readonly digest: string;
|
|
41
|
+
readonly bytes: Uint8Array;
|
|
42
|
+
readonly manifest: ClosureDeliveryManifest;
|
|
43
|
+
readonly files: readonly {
|
|
44
|
+
path: string;
|
|
45
|
+
source: string;
|
|
46
|
+
}[];
|
|
47
|
+
readonly importMap: {
|
|
48
|
+
imports: Record<string, string>;
|
|
49
|
+
scopes: Record<string, Record<string, string>>;
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
type Library = (specifier: string, parent: ModuleClosureSnapshot) => ModuleClosureSnapshot | undefined;
|
|
53
|
+
/** The host selects already authenticated snapshots and resolution, never the
|
|
54
|
+
* offered program. This prepares unchanged ESM files, not a JS sandbox, signer,
|
|
55
|
+
* browser host or symbol-pruning bundler. Existing native/Acorn routes remain.
|
|
56
|
+
*/
|
|
57
|
+
export declare function deliverModuleClosure(needs: readonly string[], entries: ReadonlyMap<string, ModuleClosureSnapshot>, library: Library, limits: ClosureDeliveryLimits, notices?: readonly ClosureNotice[]): ClosureDelivery;
|
|
58
|
+
/** Verify exact pinned delivery bytes and run the same pre-execution closure
|
|
59
|
+
* verifier again over the delivered set. No callbacks, install paths or verifier
|
|
60
|
+
* chosen by the payload. The returned import map is derived, never trusted input.
|
|
61
|
+
*/
|
|
62
|
+
export declare function verifyModuleDelivery(bytes: Uint8Array, expected: string, limits: ClosureDeliveryLimits): ClosureDelivery;
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import { posix } from 'node:path';
|
|
2
|
+
import { sha256, isSha256 } from "../hash.js";
|
|
3
|
+
import { archiveCoordinate } from "../archive.js";
|
|
4
|
+
import { compareStrings as compare } from "../order.js";
|
|
5
|
+
import { moduleClosures } from "./module-closure.js";
|
|
6
|
+
export { moduleSnapshot } from "./module-closure.js";
|
|
7
|
+
const fail = (why) => { throw Error('REFUSE·closure delivery ' + why); };
|
|
8
|
+
const key = (identity, coordinate) => JSON.stringify([identity, coordinate]);
|
|
9
|
+
const pathOf = (identity, coordinate) => {
|
|
10
|
+
if (!isSha256(identity))
|
|
11
|
+
return fail('snapshot identity is not SHA-256');
|
|
12
|
+
return 'modules/' + identity.slice(7) + '/' + coordinate;
|
|
13
|
+
};
|
|
14
|
+
const urlOf = (path) => './' + path.split('/').map(encodeURIComponent).join('/');
|
|
15
|
+
const resourceLimits = (limits) => {
|
|
16
|
+
if (!limits || !Number.isSafeInteger(limits.members) || limits.members < 1 || !Number.isSafeInteger(limits.bytes) || limits.bytes < 1 || !Number.isSafeInteger(limits.responseBytes) || limits.responseBytes < 1)
|
|
17
|
+
fail('missing resources');
|
|
18
|
+
if (limits.signal?.aborted)
|
|
19
|
+
fail('cancelled');
|
|
20
|
+
};
|
|
21
|
+
/** The host selects already authenticated snapshots and resolution, never the
|
|
22
|
+
* offered program. This prepares unchanged ESM files, not a JS sandbox, signer,
|
|
23
|
+
* browser host or symbol-pruning bundler. Existing native/Acorn routes remain.
|
|
24
|
+
*/
|
|
25
|
+
export function deliverModuleClosure(needs, entries, library, limits, notices = []) {
|
|
26
|
+
resourceLimits(limits);
|
|
27
|
+
if (!Array.isArray(notices) || notices.length >= limits.members)
|
|
28
|
+
fail('notice resources');
|
|
29
|
+
let noticeBytes = 0;
|
|
30
|
+
const noticePaths = new Set();
|
|
31
|
+
const retainedNotices = notices.map(n => {
|
|
32
|
+
if (!n || typeof n.coordinate !== 'string' || archiveCoordinate(n.coordinate) !== n.coordinate || typeof n.source !== 'string' || !isSha256(n.digest) || sha256(n.source) !== n.digest || (noticeBytes += Buffer.byteLength(n.source)) >= limits.bytes)
|
|
33
|
+
fail('notice bytes/resources');
|
|
34
|
+
const path = 'notices/' + pathOf(n.snapshot, n.coordinate).slice('modules/'.length);
|
|
35
|
+
if (noticePaths.has(path))
|
|
36
|
+
fail('duplicate notice');
|
|
37
|
+
noticePaths.add(path);
|
|
38
|
+
return { snapshot: n.snapshot, coordinate: n.coordinate, digest: n.digest, path };
|
|
39
|
+
}).sort((a, b) => compare(a.path, b.path));
|
|
40
|
+
if (!Array.isArray(needs) || !needs.length || needs.length > limits.members || needs.some(n => typeof n !== 'string' || !n || Buffer.byteLength(n) > limits.bytes))
|
|
41
|
+
fail('missing/oversized needs');
|
|
42
|
+
const requested = [...new Set(needs)].sort(compare), snapshots = new Map(), bindings = new Map();
|
|
43
|
+
const hold = (one) => {
|
|
44
|
+
if (!one || !isSha256(one.identity))
|
|
45
|
+
return fail('snapshot identity is not SHA-256');
|
|
46
|
+
const old = snapshots.get(one.identity);
|
|
47
|
+
// Different entry points may share one immutable snapshot, not different members.
|
|
48
|
+
if (old && old.members !== one.members)
|
|
49
|
+
fail('ambiguous snapshot members');
|
|
50
|
+
snapshots.set(one.identity, one);
|
|
51
|
+
return one;
|
|
52
|
+
};
|
|
53
|
+
const roots = requested.map(name => { const one = entries.get(name); if (!one)
|
|
54
|
+
return fail('unknown need ' + name); return hold(one); });
|
|
55
|
+
const reached = moduleClosures(roots, (specifier, parent) => {
|
|
56
|
+
const found = library(specifier, parent);
|
|
57
|
+
if (!found)
|
|
58
|
+
return;
|
|
59
|
+
const one = hold(found), at = key(parent.identity, specifier), binding = { parent: parent.identity, specifier, snapshot: one.identity, entry: one.entry }, old = bindings.get(at);
|
|
60
|
+
if (old && (old.snapshot !== one.identity || old.entry !== one.entry))
|
|
61
|
+
fail('ambiguous library resolution');
|
|
62
|
+
if (!old && bindings.size >= limits.members)
|
|
63
|
+
fail('library resources');
|
|
64
|
+
bindings.set(at, binding);
|
|
65
|
+
return one;
|
|
66
|
+
}, { ...limits, members: limits.members - notices.length, bytes: limits.bytes - noticeBytes, portableESM: true });
|
|
67
|
+
if (notices.some(n => !reached.some(r => r.snapshot === n.snapshot)))
|
|
68
|
+
fail('notice outside reached snapshots');
|
|
69
|
+
const modules = [...reached].sort((a, b) => compare(key(a.snapshot, a.coordinate), key(b.snapshot, b.coordinate))).map(r => ({ ...r, path: pathOf(r.snapshot, r.coordinate) }));
|
|
70
|
+
const files = modules.map(r => {
|
|
71
|
+
const source = snapshots.get(r.snapshot)?.members.get(r.coordinate)?.source;
|
|
72
|
+
if (source === undefined || sha256(source) !== r.digest)
|
|
73
|
+
fail('snapshot changed during delivery');
|
|
74
|
+
return { path: r.path, source: source };
|
|
75
|
+
});
|
|
76
|
+
for (const n of retainedNotices)
|
|
77
|
+
files.push({ path: n.path, source: notices.find(one => one.snapshot === n.snapshot && one.coordinate === n.coordinate).source });
|
|
78
|
+
const manifest = { format: 'esm-file-closure/1', needs: requested.map((name, i) => ({ name, snapshot: roots[i].identity, entry: posix.normalize(roots[i].entry) })), modules, libraries: [...bindings.values()].sort((a, b) => compare(key(a.parent, a.specifier), key(b.parent, b.specifier))), notices: retainedNotices };
|
|
79
|
+
const closure = sha256(JSON.stringify(manifest));
|
|
80
|
+
const bytes = Buffer.from(JSON.stringify({ manifest, files }), 'utf8');
|
|
81
|
+
if (bytes.length > limits.responseBytes)
|
|
82
|
+
fail('response resources');
|
|
83
|
+
if (limits.signal?.aborted)
|
|
84
|
+
fail('cancelled');
|
|
85
|
+
const imports = Object.fromEntries(manifest.needs.map(n => [n.name, urlOf(pathOf(n.snapshot, n.entry))]));
|
|
86
|
+
const scopes = {};
|
|
87
|
+
for (const b of manifest.libraries) {
|
|
88
|
+
const scope = './modules/' + b.parent.slice(7) + '/';
|
|
89
|
+
const values = scopes[scope] ?? (scopes[scope] = Object.create(null));
|
|
90
|
+
values[b.specifier] = urlOf(pathOf(b.snapshot, posix.normalize(b.entry)));
|
|
91
|
+
}
|
|
92
|
+
return { closure, digest: sha256(bytes), bytes: new Uint8Array(bytes), manifest, files, importMap: { imports, scopes } };
|
|
93
|
+
}
|
|
94
|
+
/** Verify exact pinned delivery bytes and run the same pre-execution closure
|
|
95
|
+
* verifier again over the delivered set. No callbacks, install paths or verifier
|
|
96
|
+
* chosen by the payload. The returned import map is derived, never trusted input.
|
|
97
|
+
*/
|
|
98
|
+
export function verifyModuleDelivery(bytes, expected, limits) {
|
|
99
|
+
resourceLimits(limits);
|
|
100
|
+
if (!(bytes instanceof Uint8Array) || bytes.byteLength > limits.responseBytes || !isSha256(expected) || sha256(bytes) !== expected)
|
|
101
|
+
fail('bundle bytes differ or exceed resources');
|
|
102
|
+
let value;
|
|
103
|
+
try {
|
|
104
|
+
value = JSON.parse(new TextDecoder('utf-8', { fatal: true }).decode(bytes));
|
|
105
|
+
}
|
|
106
|
+
catch {
|
|
107
|
+
return fail('invalid JSON bytes');
|
|
108
|
+
}
|
|
109
|
+
const manifest = value?.manifest;
|
|
110
|
+
if (manifest?.format !== 'esm-file-closure/1' || !Array.isArray(manifest.needs) || !Array.isArray(manifest.modules) || !Array.isArray(manifest.libraries) || !Array.isArray(manifest.notices) || !Array.isArray(value.files) || manifest.modules.length + manifest.notices.length > limits.members || value.files.length !== manifest.modules.length + manifest.notices.length || manifest.needs.length > limits.members || manifest.libraries.length > limits.members)
|
|
111
|
+
fail('invalid manifest resources');
|
|
112
|
+
const snapshots = new Map(), files = new Map();
|
|
113
|
+
let size = 0;
|
|
114
|
+
for (const file of value.files) {
|
|
115
|
+
if (typeof file?.path !== 'string' || typeof file.source !== 'string' || files.has(file.path) || (size += Buffer.byteLength(file.source)) > limits.bytes)
|
|
116
|
+
fail('invalid/duplicate file resources');
|
|
117
|
+
files.set(file.path, file.source);
|
|
118
|
+
}
|
|
119
|
+
for (const m of manifest.modules) {
|
|
120
|
+
if (!m || typeof m.coordinate !== 'string' || typeof m.path !== 'string' || m.path !== pathOf(m.snapshot, m.coordinate) || !isSha256(m.digest))
|
|
121
|
+
fail('invalid module');
|
|
122
|
+
const source = files.get(m.path);
|
|
123
|
+
if (source === undefined || sha256(source) !== m.digest)
|
|
124
|
+
fail('module bytes differ');
|
|
125
|
+
const members = snapshots.get(m.snapshot) ?? new Map();
|
|
126
|
+
if (members.has(m.coordinate))
|
|
127
|
+
fail('duplicate module');
|
|
128
|
+
members.set(m.coordinate, { source, digest: m.digest });
|
|
129
|
+
snapshots.set(m.snapshot, members);
|
|
130
|
+
}
|
|
131
|
+
const snapshot = (identity, entry) => { const members = snapshots.get(identity); if (!members || typeof entry !== 'string')
|
|
132
|
+
return fail('unknown snapshot/entry'); return { identity, entry, members }; };
|
|
133
|
+
const entries = new Map();
|
|
134
|
+
for (const n of manifest.needs) {
|
|
135
|
+
if (typeof n?.name !== 'string' || entries.has(n.name))
|
|
136
|
+
fail('invalid/duplicate need');
|
|
137
|
+
entries.set(n.name, snapshot(n.snapshot, n.entry));
|
|
138
|
+
}
|
|
139
|
+
const bindings = new Map();
|
|
140
|
+
for (const b of manifest.libraries) {
|
|
141
|
+
if (typeof b?.parent !== 'string' || typeof b.specifier !== 'string' || bindings.has(key(b.parent, b.specifier)))
|
|
142
|
+
fail('invalid/duplicate library');
|
|
143
|
+
bindings.set(key(b.parent, b.specifier), snapshot(b.snapshot, b.entry));
|
|
144
|
+
}
|
|
145
|
+
const notices = manifest.notices.map(n => { if (!n || typeof n.path !== 'string' || !files.has(n.path))
|
|
146
|
+
return fail('missing notice'); return { snapshot: n.snapshot, coordinate: n.coordinate, digest: n.digest, source: files.get(n.path) }; });
|
|
147
|
+
const prepared = deliverModuleClosure([...entries.keys()], entries, (specifier, parent) => bindings.get(key(parent.identity, specifier)), limits, notices);
|
|
148
|
+
if (prepared.digest !== expected)
|
|
149
|
+
fail('noncanonical, extra or unresolved delivery members');
|
|
150
|
+
return prepared;
|
|
151
|
+
}
|