selfstore 1.8.30 → 1.8.32
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -1
- package/dist/advanced.d.ts +11 -10
- package/dist/advanced.js +1 -1
- package/dist/backups.d.ts +8 -7
- package/dist/{cache-ilsK3Tki.d.ts → cache-BEv-Har2.d.ts} +2 -1
- package/dist/{chunk-A6OQP7DR.js → chunk-HRYIQSTH.js} +3 -3
- package/dist/{chunk-A6OQP7DR.js.map → chunk-HRYIQSTH.js.map} +1 -1
- package/dist/{chunk-2TIRUEXR.js → chunk-HVHQLPP6.js} +13 -5
- package/dist/chunk-HVHQLPP6.js.map +1 -0
- package/dist/{connect-DMFxtXYO.d.ts → connect-CDazV36v.d.ts} +7 -6
- package/dist/{drive-DvnzpjLM.d.ts → drive-CwlKlowN.d.ts} +4 -3
- package/dist/flows.d.ts +10 -9
- package/dist/flows.js +2 -2
- package/dist/groups.d.ts +5 -3
- package/dist/households.d.ts +4 -3
- package/dist/index.d.ts +20 -13
- package/dist/index.js +25 -6
- package/dist/index.js.map +1 -1
- package/dist/{local-CGYx16zM.d.ts → local-DytMg5GC.d.ts} +4 -3
- package/dist/{machine-ALMkT3mk.d.ts → machine-Dhbx3Eut.d.ts} +2 -1
- package/dist/{manager-B-gb3lIn.d.ts → manager-CnlIs-hY.d.ts} +5 -4
- package/dist/passkey.d.ts +2 -1
- package/dist/proof.d.ts +18 -10
- package/dist/proof.js +6 -1
- package/dist/proof.js.map +1 -1
- package/dist/{s3-iiFYjype.d.ts → s3-Bexn9kzT.d.ts} +4 -3
- package/dist/{simple-B430fbx0.d.ts → simple-cLzoTGhN.d.ts} +8 -7
- package/dist/{store-CZOqxDj5.d.ts → store-DSPbCCtM.d.ts} +3 -2
- package/dist/sync.d.ts +2 -1
- package/dist/widgets.d.ts +10 -8
- package/dist/widgets.js +2 -2
- package/package.json +5 -4
- package/dist/chunk-2TIRUEXR.js.map +0 -1
package/dist/proof.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/proof/proof.ts","../src/proof/der.ts","../src/proof/reach.ts","../src/proof/rfc3161.ts","../src/proof/journal.ts"],"names":["refused","hex"],"mappings":"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","file":"proof.js","sourcesContent":["// Proof of existence for the user's own documents: the bytes never leave the\n// device, only their SHA-256 does. A notary dates that digest; the receipt it\n// hands back is kept next to the file, in the user's own storage, and anyone\n// holding the file and the receipt can check the two still belong together.\n\nimport { sha256Hex } from '../selfstore/digest';\nimport { isSelfstoreError, SelfstoreError } from '../selfstore/errors';\nimport { toBytes, type FileBytes } from '../simple/bytes';\nimport type { SimpleRecord } from '../simple/simple';\n\n/**\n * What a notary hands back for one digest. `evidence` is the notary's own\n * material (a timestamp token, an inclusion path, a download address), as\n * strings - base64 for bytes - so a receipt is plain JSON and survives every\n * destination a store can write to.\n */\nexport interface Receipt {\n\t/** The notary that issued it (`Notary.name`). */\n\treadonly notary: string;\n\t/** Lowercase hex SHA-256 of the document. */\n\treadonly hash: string;\n\t/** The label sent with the deposit, if any. */\n\treadonly label?: string;\n\t/** ISO 8601 instant the notary vouches for (its clock, not the device's). */\n\treadonly depositedAt: string;\n\t/** False while the notary still has something to add (an anchor, a seal). */\n\treadonly complete: boolean;\n\treadonly evidence: Readonly<Record<string, string>>;\n}\n\n/**\n * Anyone who dates a digest. `deposit` must never see more than the digest and\n * the label; `complete` is called later - the next day, the next launch - and\n * returns the same receipt with whatever the notary could not give at once.\n * A notary that is final on deposit returns its argument unchanged.\n */\nexport interface Notary {\n\treadonly name: string;\n\tdeposit(hash: string, label?: string): Promise<Receipt>;\n\tcomplete(receipt: Receipt): Promise<Receipt>;\n}\n\n/** A receipt as `prove()` keeps it: the notary's, plus what the device measured. */\nexport interface Proof extends Receipt {\n\treadonly kind: 'selfstore-proof';\n\treadonly version: 1;\n\treadonly algorithm: 'SHA-256';\n\t/** Size of the document in bytes. */\n\treadonly size: number;\n\t/** The store file the proof belongs to, when there is one. */\n\treadonly file?: string;\n}\n\n/** Where proofs are kept: the simple store fits as is. */\nexport interface ProofShelf {\n\tput(collection: string, record: SimpleRecord): Promise<void>;\n}\n\n/** The collection `prove()` and `completeProof()` write to. */\nexport const PROOFS = 'proofs';\n\nexport interface ProveOptions {\n\tnotary: Notary;\n\t/** Sent to the notary with the digest. A TYPE ('invoice', 'inventory'),\n\t * never a name or a piece of the content: it leaves the device. */\n\tlabel?: string;\n\t/** Keep the proof in this store, under `PROOFS`, keyed by `file` or by hash. */\n\tstore?: ProofShelf;\n\t/** Id of the store file the document is (as `putFile` returned it). */\n\tfile?: string;\n}\n\n/** The result of `verify()`. */\nexport interface ProofCheck {\n\t/** The bytes hash to the receipt's digest (and size, when it carries one). */\n\treadonly matches: boolean;\n\t/** What the bytes hash to now. */\n\treadonly hash: string;\n\t/** Whether the notary had finished with this receipt. */\n\treadonly complete: boolean;\n}\n\nconst HEX_DIGEST = /^[0-9a-f]{64}$/;\n\nfunction refused(message: string): SelfstoreError {\n\treturn new SelfstoreError('NOTARY_REFUSED', message);\n}\n\n/** A notary that answers for another digest, or for another notary, is not believed. */\nfunction checkAnswer(answer: Receipt, hash: string, notary: Notary): void {\n\tif (typeof answer?.hash !== 'string' || answer.hash.toLowerCase() !== hash) {\n\t\tthrow refused(`${notary.name} answered for another digest`);\n\t}\n\tif (answer.notary !== notary.name) {\n\t\tthrow refused(`receipt names ${String(answer.notary)}, not ${notary.name}`);\n\t}\n\tif (Number.isNaN(Date.parse(answer.depositedAt))) {\n\t\tthrow refused(`${notary.name} gave no readable deposit time`);\n\t}\n}\n\nasync function shelve(proof: Proof, store: ProofShelf | undefined): Promise<void> {\n\tif (store) await store.put(PROOFS, { ...proof, id: proof.file ?? proof.hash });\n}\n\n/**\n * Hash `blob` on the device, deposit the digest with `options.notary`, and\n * return the proof - kept in `options.store` too when one is given. Only the\n * digest and the label leave the device.\n *\n * Throws NOTARY_UNAVAILABLE when the notary cannot be reached (retry later)\n * and NOTARY_REFUSED when it refuses or answers for something else.\n */\nexport async function prove(blob: FileBytes, options: ProveOptions): Promise<Proof> {\n\tconst bytes = await toBytes(blob);\n\tconst hash = await sha256Hex(bytes);\n\tconst answer = await options.notary.deposit(hash, options.label);\n\tcheckAnswer(answer, hash, options.notary);\n\tconst proof: Proof = {\n\t\t...answer,\n\t\thash,\n\t\tkind: 'selfstore-proof',\n\t\tversion: 1,\n\t\talgorithm: 'SHA-256',\n\t\tsize: bytes.length,\n\t\t...(options.file === undefined ? {} : { file: options.file })\n\t};\n\tawait shelve(proof, options.store);\n\treturn proof;\n}\n\n/**\n * Ask the notary for what it could not give on deposit. A complete proof is\n * returned as is, without a call. The fields the device measured are kept;\n * the notary may only add to its own.\n */\nexport async function completeProof(\n\tproof: Proof,\n\toptions: { notary: Notary; store?: ProofShelf }\n): Promise<Proof> {\n\tif (proof.complete) return proof;\n\tconst answer = await options.notary.complete(proof);\n\tcheckAnswer(answer, proof.hash, options.notary);\n\tconst completed: Proof = {\n\t\t...answer,\n\t\thash: proof.hash,\n\t\tkind: proof.kind,\n\t\tversion: proof.version,\n\t\talgorithm: proof.algorithm,\n\t\tsize: proof.size,\n\t\t...(proof.file === undefined ? {} : { file: proof.file })\n\t};\n\tawait shelve(completed, options.store);\n\treturn completed;\n}\n\n/**\n * Hash `blob` again and compare it with the receipt. This proves the bytes are\n * the ones the receipt names; that the receipt itself is genuine is what the\n * notary's evidence is for, checked with the notary's own verifier.\n *\n * Throws BAD_FORMAT on a receipt that carries no SHA-256 digest at all - a\n * damaged receipt is not a document that changed.\n */\nexport async function verify(\n\tblob: FileBytes,\n\treceipt: Pick<Receipt, 'hash' | 'complete'> & { size?: number }\n): Promise<ProofCheck> {\n\tconst expected = typeof receipt?.hash === 'string' ? receipt.hash.toLowerCase() : '';\n\tif (!HEX_DIGEST.test(expected)) {\n\t\tthrow new SelfstoreError('BAD_FORMAT', 'the receipt carries no SHA-256 digest');\n\t}\n\tconst bytes = await toBytes(blob);\n\tconst hash = await sha256Hex(bytes);\n\tconst sizeAgrees = receipt.size === undefined || receipt.size === bytes.length;\n\treturn { matches: hash === expected && sizeAgrees, hash, complete: receipt.complete === true };\n}\n\n/** Where proofs are read back from: the simple store fits as is. */\nexport interface ProofLibrary extends ProofShelf {\n\tall(collection: string): readonly SimpleRecord[];\n}\n\nfunction isProof(record: SimpleRecord): boolean {\n\treturn (\n\t\trecord.kind === 'selfstore-proof' &&\n\t\ttypeof record.hash === 'string' &&\n\t\tHEX_DIGEST.test(record.hash) &&\n\t\ttypeof record.notary === 'string' &&\n\t\ttypeof record.complete === 'boolean'\n\t);\n}\n\n/**\n * Every proof kept in `store`, oldest deposit first. Records that are not\n * proofs - another app's, a damaged one - are skipped rather than trusted.\n */\nexport function proofsIn(store: Pick<ProofLibrary, 'all'>): Proof[] {\n\treturn store\n\t\t.all(PROOFS)\n\t\t.filter(isProof)\n\t\t.map((record) => {\n\t\t\tconst { id: _id, ...proof } = record;\n\t\t\treturn proof as unknown as Proof;\n\t\t})\n\t\t.sort((a, b) => Date.parse(a.depositedAt) - Date.parse(b.depositedAt));\n}\n\n/** What `completePending()` did, proof by proof. */\nexport interface PendingRound {\n\t/** Finished this round, and written back to the store. */\n\treadonly completed: readonly Proof[];\n\t/** Still waiting: the notary has nothing to add yet, could not be reached,\n\t * or is not among the notaries given. Ask again on a later launch. */\n\treadonly pending: readonly Proof[];\n\t/** The notary answered for something else; kept as it was, not overwritten. */\n\treadonly refused: readonly Proof[];\n}\n\nfunction isCode(error: unknown, code: string): boolean {\n\treturn isSelfstoreError(error) && error.code === code;\n}\n\n/**\n * Ask each notary to finish the incomplete proofs it issued - the call an app\n * makes at launch, since a notary that anchors its digests finishes a receipt\n * hours after the deposit. A notary that cannot be reached is not asked again\n * this round; a proof whose notary is not in `notaries` waits. Only a proof\n * that came back complete is written to the store.\n */\nexport async function completePending(options: {\n\tstore: ProofLibrary;\n\tnotaries: readonly Notary[];\n}): Promise<PendingRound> {\n\tconst byName = new Map(options.notaries.map((notary) => [notary.name, notary]));\n\tconst unreachable = new Set<string>();\n\tconst completed: Proof[] = [];\n\tconst pending: Proof[] = [];\n\tconst refused: Proof[] = [];\n\tfor (const proof of proofsIn(options.store)) {\n\t\tif (proof.complete) continue;\n\t\tconst notary = byName.get(proof.notary);\n\t\tif (notary === undefined || unreachable.has(notary.name)) {\n\t\t\tpending.push(proof);\n\t\t\tcontinue;\n\t\t}\n\t\ttry {\n\t\t\tconst answer = await completeProof(proof, { notary });\n\t\t\tif (answer.complete) {\n\t\t\t\tawait shelve(answer, options.store);\n\t\t\t\tcompleted.push(answer);\n\t\t\t} else {\n\t\t\t\tpending.push(proof);\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tif (isCode(error, 'NOTARY_UNAVAILABLE')) {\n\t\t\t\tunreachable.add(notary.name);\n\t\t\t\tpending.push(proof);\n\t\t\t} else if (isCode(error, 'NOTARY_REFUSED')) {\n\t\t\t\trefused.push(proof);\n\t\t\t} else {\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t}\n\t}\n\treturn { completed, pending, refused };\n}\n","// The few DER shapes an RFC 3161 exchange needs, and no more. A timestamp\n// request is five fields and the reply is read along one path, so a general\n// ASN.1 library would be a fourth runtime dependency for two functions.\n\n/** One decoded TLV: `start` and `end` bound its CONTENT. */\nexport interface DerNode {\n\treadonly tag: number;\n\treadonly start: number;\n\treadonly end: number;\n}\n\nexport class DerError extends Error {}\n\nfunction encodeLength(length: number): Uint8Array {\n\tif (length < 0x80) return Uint8Array.of(length);\n\tconst bytes: number[] = [];\n\tfor (let rest = length; rest > 0; rest = Math.floor(rest / 256)) bytes.unshift(rest % 256);\n\treturn Uint8Array.of(0x80 | bytes.length, ...bytes);\n}\n\n/** Encode one TLV around already-encoded content. */\nexport function tlv(tag: number, ...parts: Uint8Array[]): Uint8Array {\n\tconst length = parts.reduce((sum, part) => sum + part.length, 0);\n\tconst head = encodeLength(length);\n\tconst out = new Uint8Array(1 + head.length + length);\n\tout[0] = tag;\n\tout.set(head, 1);\n\tlet at = 1 + head.length;\n\tfor (const part of parts) {\n\t\tout.set(part, at);\n\t\tat += part.length;\n\t}\n\treturn out;\n}\n\n/** Read the TLV that starts at `offset`. Indefinite lengths are BER, not DER: refused. */\nexport function readNode(bytes: Uint8Array, offset: number, limit = bytes.length): DerNode {\n\tif (offset + 2 > limit) throw new DerError('truncated header');\n\tconst tag = bytes[offset];\n\tconst first = bytes[offset + 1];\n\tlet start = offset + 2;\n\tlet length = first;\n\tif (first & 0x80) {\n\t\tconst count = first & 0x7f;\n\t\tif (count === 0 || count > 4) throw new DerError('unsupported length');\n\t\tif (start + count > limit) throw new DerError('truncated length');\n\t\tlength = 0;\n\t\tfor (let i = 0; i < count; i++) length = length * 256 + bytes[start + i];\n\t\tstart += count;\n\t}\n\tconst end = start + length;\n\tif (end > limit) throw new DerError('content runs past its parent');\n\treturn { tag, start, end };\n}\n\n/** The direct children of a constructed node. */\nexport function childrenOf(bytes: Uint8Array, node: DerNode): DerNode[] {\n\tconst out: DerNode[] = [];\n\tfor (let at = node.start; at < node.end;) {\n\t\tconst child = readNode(bytes, at, node.end);\n\t\tout.push(child);\n\t\tat = child.end;\n\t}\n\treturn out;\n}\n\n/** The node's content, or a refusal when its tag is not the one expected. */\nexport function expectTag(node: DerNode | undefined, tag: number): DerNode {\n\tif (node?.tag !== tag) throw new DerError(`expected tag 0x${tag.toString(16)}`);\n\treturn node;\n}\n\nexport function contentOf(bytes: Uint8Array, node: DerNode): Uint8Array {\n\treturn bytes.subarray(node.start, node.end);\n}\n","// One way to call a notary over HTTP, so every adapter maps the same failures\n// to the same codes: unreachable, overloaded or rate-limited is worth a retry,\n// any other refusal is not.\n\nimport { SelfstoreError } from '../selfstore/errors';\n\n/** Fetch `url`, throwing NOTARY_UNAVAILABLE or NOTARY_REFUSED instead of returning a failure. */\nexport async function reach(\n\tsend: typeof fetch,\n\turl: string,\n\tinit: RequestInit | undefined,\n\twho: string\n): Promise<Response> {\n\tlet response: Response;\n\ttry {\n\t\tresponse = await send(url, init);\n\t} catch (e) {\n\t\tthrow new SelfstoreError(\n\t\t\t'NOTARY_UNAVAILABLE',\n\t\t\t`${who} could not be reached: ${(e as Error).message}`\n\t\t);\n\t}\n\tif (!response.ok) {\n\t\tconst code =\n\t\t\tresponse.status >= 500 || response.status === 429 ? 'NOTARY_UNAVAILABLE' : 'NOTARY_REFUSED';\n\t\tthrow new SelfstoreError(code, `${who} answered ${response.status}`);\n\t}\n\treturn response;\n}\n","// A notary over any RFC 3161 time-stamping authority. The authority signs the\n// digest and the time in one token, so the receipt is complete on deposit: the\n// token (the `.tsr` file) is the evidence, and `openssl ts -verify` checks it\n// against the authority's certificate without this library.\n\nimport { fromBase64, toBase64 } from '../selfstore/base64';\nimport { hex } from '../selfstore/digest';\nimport { SelfstoreError } from '../selfstore/errors';\nimport { childrenOf, contentOf, DerError, expectTag, readNode, tlv, type DerNode } from './der';\nimport type { Notary, Receipt } from './proof';\nimport { reach } from './reach';\n\nconst SEQUENCE = 0x30;\nconst INTEGER = 0x02;\nconst OCTET_STRING = 0x04;\nconst OID = 0x06;\nconst GENERALIZED_TIME = 0x18;\nconst EXPLICIT_0 = 0xa0;\n\n/** id-sha256, 2.16.840.1.101.3.4.2.1, with its NULL parameters. */\nconst SHA256_ALGORITHM = tlv(\n\tSEQUENCE,\n\ttlv(OID, Uint8Array.of(0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01)),\n\tUint8Array.of(0x05, 0x00)\n);\n\nexport interface Rfc3161Options {\n\t/** The authority's endpoint. In a browser it must answer CORS, or sit\n\t * behind a relay of yours that does: most public authorities do not. */\n\turl: string;\n\t/** Receipt `notary` field. Defaults to 'rfc3161'. */\n\tname?: string;\n\t/** Injected for tests and relays; defaults to the global fetch. */\n\tfetch?: typeof fetch;\n}\n\n/** What a timestamp token says, read without checking its signature. */\nexport interface TimestampToken {\n\t/** Lowercase hex of the digest the authority stamped. */\n\treadonly hash: string;\n\t/** ISO 8601 instant the authority signed. */\n\treadonly time: string;\n\t/** The nonce echoed back, as lowercase hex, when there is one. */\n\treadonly nonce?: string;\n}\n\nfunction hexToBytes(hex: string): Uint8Array {\n\treturn Uint8Array.from(hex.match(/../g) ?? [], (pair) => Number.parseInt(pair, 16));\n}\n\n/** Leading zero bytes are DER's sign padding, not part of the value. */\nfunction integerHex(bytes: Uint8Array): string {\n\tlet at = 0;\n\twhile (at < bytes.length - 1 && bytes[at] === 0) at++;\n\treturn hex(bytes.subarray(at));\n}\n\n/** Eight random bytes, positive and minimal as a DER INTEGER. */\nfunction newNonce(): Uint8Array {\n\tconst nonce = crypto.getRandomValues(new Uint8Array(8));\n\tnonce[0] = (nonce[0] & 0x3f) | 0x40;\n\treturn nonce;\n}\n\n/** A TimeStampReq (RFC 3161 section 2.4.1) for a SHA-256 digest, asking for the certificate. */\nexport function timestampRequest(hash: string, nonce: Uint8Array): Uint8Array {\n\treturn tlv(\n\t\tSEQUENCE,\n\t\ttlv(INTEGER, Uint8Array.of(1)),\n\t\ttlv(SEQUENCE, SHA256_ALGORITHM, tlv(OCTET_STRING, hexToBytes(hash))),\n\t\ttlv(INTEGER, nonce),\n\t\tUint8Array.of(0x01, 0x01, 0xff)\n\t);\n}\n\n/** YYYYMMDDHHMMSS[.fff]Z to ISO 8601. */\nfunction generalizedTime(text: string): string {\n\tconst parts = /^(\\d{4})(\\d{2})(\\d{2})(\\d{2})(\\d{2})(\\d{2})(\\.\\d+)?Z$/.exec(text);\n\tif (parts === null) throw new DerError(`unreadable time ${text}`);\n\tconst [, y, mo, d, h, mi, s, fraction] = parts;\n\treturn new Date(`${y}-${mo}-${d}T${h}:${mi}:${s}${fraction ?? ''}Z`).toISOString();\n}\n\n/** TimeStampResp: the status, or the token when it was granted. */\nfunction tokenOf(bytes: Uint8Array): DerNode {\n\tconst [statusInfo, token] = childrenOf(bytes, expectTag(readNode(bytes, 0), SEQUENCE));\n\tconst status = expectTag(childrenOf(bytes, expectTag(statusInfo, SEQUENCE))[0], INTEGER);\n\tconst code = Number.parseInt(integerHex(contentOf(bytes, status)), 16);\n\t// 0 granted, 1 granted with modifications; anything else is a refusal.\n\tif (code > 1) {\n\t\tthrow new SelfstoreError(\n\t\t\t'NOTARY_REFUSED',\n\t\t\t`the authority refused the request (status ${code})`\n\t\t);\n\t}\n\treturn expectTag(token, SEQUENCE);\n}\n\n/** ContentInfo > SignedData > EncapsulatedContentInfo > TSTInfo. */\nfunction tstInfoOf(bytes: Uint8Array, token: DerNode): DerNode {\n\tconst signedData = expectTag(\n\t\tchildrenOf(bytes, expectTag(childrenOf(bytes, token)[1], EXPLICIT_0))[0],\n\t\tSEQUENCE\n\t);\n\tconst encapsulated = expectTag(childrenOf(bytes, signedData)[2], SEQUENCE);\n\tconst wrapper = expectTag(childrenOf(bytes, encapsulated)[1], EXPLICIT_0);\n\tconst octets = expectTag(childrenOf(bytes, wrapper)[0], OCTET_STRING);\n\treturn expectTag(readNode(bytes, octets.start, octets.end), SEQUENCE);\n}\n\n/**\n * Read the digest, the time and the nonce out of a TimeStampResp (the `.tsr`\n * file). It does NOT check the authority's signature - that is what\n * `openssl ts -verify` is for; it is what tells a token for another document\n * apart before anything is kept. Throws NOTARY_REFUSED on a refusal or on\n * anything that is not a timestamp reply.\n */\nexport function readTimestampReply(bytes: Uint8Array): TimestampToken {\n\ttry {\n\t\tconst tstInfo = tstInfoOf(bytes, tokenOf(bytes));\n\t\t// version, policy, messageImprint, serialNumber, genTime, then optional\n\t\t// accuracy, ordering and nonce - the nonce is the only INTEGER among them.\n\t\tconst [, , imprint, , time, ...rest] = childrenOf(bytes, tstInfo);\n\t\tconst digest = expectTag(childrenOf(bytes, expectTag(imprint, SEQUENCE))[1], OCTET_STRING);\n\t\tconst nonce = rest.find((node) => node.tag === INTEGER);\n\t\tconst genTime = new TextDecoder().decode(contentOf(bytes, expectTag(time, GENERALIZED_TIME)));\n\t\treturn {\n\t\t\thash: hex(contentOf(bytes, digest)),\n\t\t\ttime: generalizedTime(genTime),\n\t\t\t...(nonce ? { nonce: integerHex(contentOf(bytes, nonce)) } : {})\n\t\t};\n\t} catch (e) {\n\t\tif (e instanceof SelfstoreError) throw e;\n\t\tthrow new SelfstoreError('NOTARY_REFUSED', `not a timestamp reply: ${(e as Error).message}`);\n\t}\n}\n\nasync function post(options: Rfc3161Options, body: Uint8Array): Promise<Uint8Array> {\n\tconst response = await reach(\n\t\toptions.fetch ?? globalThis.fetch,\n\t\toptions.url,\n\t\t{\n\t\t\tmethod: 'POST',\n\t\t\theaders: { 'content-type': 'application/timestamp-query' },\n\t\t\tbody: body as BodyInit\n\t\t},\n\t\t'the authority'\n\t);\n\treturn new Uint8Array(await response.arrayBuffer());\n}\n\n/**\n * A notary over an RFC 3161 time-stamping authority. The receipt is complete\n * on deposit; its evidence is the reply, base64 under `tsr`, and the\n * authority's address under `tsa`. The label is never sent: RFC 3161 has no\n * field for it, so it stays on the receipt.\n */\nexport function rfc3161Notary(options: Rfc3161Options): Notary {\n\tconst name = options.name ?? 'rfc3161';\n\treturn {\n\t\tname,\n\t\tasync deposit(hash: string, label?: string): Promise<Receipt> {\n\t\t\tconst nonce = newNonce();\n\t\t\tconst reply = await post(options, timestampRequest(hash, nonce));\n\t\t\tconst token = readTimestampReply(reply);\n\t\t\tif (token.hash !== hash) {\n\t\t\t\tthrow new SelfstoreError('NOTARY_REFUSED', 'the authority stamped another digest');\n\t\t\t}\n\t\t\tif (token.nonce !== integerHex(nonce)) {\n\t\t\t\tthrow new SelfstoreError('NOTARY_REFUSED', 'the reply does not answer this request');\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tnotary: name,\n\t\t\t\thash,\n\t\t\t\t...(label === undefined ? {} : { label }),\n\t\t\t\tdepositedAt: token.time,\n\t\t\t\tcomplete: true,\n\t\t\t\tevidence: { tsr: toBase64(reply), tsa: options.url }\n\t\t\t};\n\t\t},\n\t\tcomplete(receipt: Receipt): Promise<Receipt> {\n\t\t\treturn Promise.resolve(receipt);\n\t\t}\n\t};\n}\n\n/** The `.tsr` bytes of an RFC 3161 receipt, to offer as a download. */\nexport function timestampReplyOf(receipt: Pick<Receipt, 'evidence'>): Uint8Array | undefined {\n\tconst tsr = receipt.evidence.tsr;\n\treturn tsr === undefined ? undefined : fromBase64(tsr);\n}\n","// A notary over a public digest journal: a service that takes a SHA-256 with\n// no account, writes it as one line of a public deposits file, and folds that\n// file into a Merkle tree it anchors in Bitcoin (OpenTimestamps) and often\n// stamps under RFC 3161 too. The deposit answers at once with the journal's\n// own receipt; the anchor comes hours later, so `complete` is what fetches it.\n//\n// The protocol, relative to the journal's base URL:\n// POST /api/depots {\"sha256\", \"libelle\"?} -> 201\n// {\"id\", \"jour\", \"place\", \"ligne\", \"recu\": {\"sha256\", \"depose\", ...}}\n// GET /empreintes/depots.jsonl one JSON line per deposit, in order, with \"recu\" = id\n// GET /tours.json {\"tours\": [{\"id\", \"racine\", \"depots\", \"ots\", \"bloc\",\n// \"horodatage\", \"fichiers\"}]}; a tour covers the\n// first `depots` lines of the deposits file\n// GET /empreintes/<tour>.racine.ots, /empreintes/<tour>.racine.tsr\n\nimport { toBase64 } from '../selfstore/base64';\nimport { SelfstoreError } from '../selfstore/errors';\nimport type { Notary, Receipt } from './proof';\nimport { reach } from './reach';\n\nexport interface JournalOptions {\n\t/** The journal's base URL, e.g. 'https://journal.example'. */\n\turl: string;\n\t/** Receipt `notary` field. Defaults to 'digest-journal'. */\n\tname?: string;\n\t/** Injected for tests and relays; defaults to the global fetch. */\n\tfetch?: typeof fetch;\n}\n\ninterface Deposit {\n\tid: string;\n\tligne: string;\n\trecu: { sha256: string; depose: string };\n}\n\ninterface Tour {\n\tid: string;\n\tracine: string;\n\tdepots: number;\n\tots: string;\n\tbloc: number | null;\n\thorodatage: string | null;\n\tfichiers?: string[];\n}\n\nconst HEX_ID = /^[0-9a-f]{64}$/;\n\nfunction refused(message: string): SelfstoreError {\n\treturn new SelfstoreError('NOTARY_REFUSED', message);\n}\n\nfunction readDeposit(body: unknown): Deposit {\n\tconst d = body as Partial<Deposit> | null;\n\tif (\n\t\ttypeof d?.id !== 'string' ||\n\t\t!HEX_ID.test(d.id) ||\n\t\ttypeof d.ligne !== 'string' ||\n\t\ttypeof d.recu?.sha256 !== 'string' ||\n\t\ttypeof d.recu.depose !== 'string'\n\t) {\n\t\tthrow refused('the journal answered without a receipt');\n\t}\n\treturn d as Deposit;\n}\n\nfunction parseLine(text: string): { recu?: string; sha256?: string } {\n\ttry {\n\t\treturn JSON.parse(text) as { recu?: string; sha256?: string };\n\t} catch {\n\t\tthrow refused('the journal published an unreadable deposits file');\n\t}\n}\n\n/** 1-based rank of the deposit line whose receipt id is `id`, or 0. */\nfunction rankOf(deposits: string, id: string, hash: string): number {\n\tconst lines = deposits.split('\\n').filter(Boolean);\n\tfor (const [index, text] of lines.entries()) {\n\t\tconst line = parseLine(text);\n\t\tif (line.recu !== id) continue;\n\t\tif (line.sha256 !== hash) throw refused('the journal lists this receipt for another digest');\n\t\treturn index + 1;\n\t}\n\treturn 0;\n}\n\n/**\n * A notary over a public digest journal (the protocol is at the top of this\n * file). The label is sent as the journal's `libelle`: keep it a TYPE.\n *\n * On deposit the receipt is incomplete; its evidence holds the journal's\n * address, the receipt `id`, the public `line` and the journal's own `receipt`\n * as JSON - the file its verifier reads. `complete` finds the first tour that\n * covers the line and, once that tour is anchored in Bitcoin, completes the\n * receipt with `tour`, `root`, `block`, the `.ots` proof and, when the journal\n * stamped that root, the `.tsr` token (both base64). Checking the Merkle path\n * from the line to the root is the journal's verifier's job.\n */\nexport function digestJournalNotary(options: JournalOptions): Notary {\n\tconst name = options.name ?? 'digest-journal';\n\tconst base = options.url.replace(/\\/+$/, '');\n\tconst send = options.fetch ?? globalThis.fetch;\n\tconst get = (path: string): Promise<Response> =>\n\t\treach(send, `${base}${path}`, undefined, 'the journal');\n\tconst bytesOf = async (path: string): Promise<string> =>\n\t\ttoBase64(new Uint8Array(await (await get(path)).arrayBuffer()));\n\n\treturn {\n\t\tname,\n\t\tasync deposit(hash: string, label?: string): Promise<Receipt> {\n\t\t\tconst response = await reach(\n\t\t\t\tsend,\n\t\t\t\t`${base}/api/depots`,\n\t\t\t\t{\n\t\t\t\t\tmethod: 'POST',\n\t\t\t\t\theaders: { 'content-type': 'application/json' },\n\t\t\t\t\tbody: JSON.stringify({ sha256: hash, ...(label === undefined ? {} : { libelle: label }) })\n\t\t\t\t},\n\t\t\t\t'the journal'\n\t\t\t);\n\t\t\tconst deposit = readDeposit(await response.json().catch(() => null));\n\t\t\treturn {\n\t\t\t\tnotary: name,\n\t\t\t\thash: deposit.recu.sha256,\n\t\t\t\t...(label === undefined ? {} : { label }),\n\t\t\t\tdepositedAt: deposit.recu.depose,\n\t\t\t\tcomplete: false,\n\t\t\t\tevidence: {\n\t\t\t\t\tjournal: base,\n\t\t\t\t\tid: deposit.id,\n\t\t\t\t\tline: deposit.ligne,\n\t\t\t\t\treceipt: JSON.stringify(deposit.recu)\n\t\t\t\t}\n\t\t\t};\n\t\t},\n\t\tasync complete(receipt: Receipt): Promise<Receipt> {\n\t\t\tconst id = receipt.evidence.id;\n\t\t\tif (id === undefined) throw refused('the receipt carries no journal id');\n\t\t\tconst rank = rankOf(await (await get('/empreintes/depots.jsonl')).text(), id, receipt.hash);\n\t\t\tif (rank === 0) return receipt;\n\t\t\tconst { tours } = (await (await get('/tours.json')).json()) as { tours: Tour[] };\n\t\t\tconst tour = tours.find((t) => t.depots >= rank);\n\t\t\tif (tour?.ots !== 'bitcoin') return receipt;\n\t\t\tconst stamped = tour.horodatage !== null && tour.fichiers?.includes(`${tour.id}.racine.tsr`);\n\t\t\treturn {\n\t\t\t\t...receipt,\n\t\t\t\tcomplete: true,\n\t\t\t\tevidence: {\n\t\t\t\t\t...receipt.evidence,\n\t\t\t\t\ttour: tour.id,\n\t\t\t\t\troot: tour.racine,\n\t\t\t\t\t...(tour.bloc === null ? {} : { block: String(tour.bloc) }),\n\t\t\t\t\tots: await bytesOf(`/empreintes/${tour.id}.racine.ots`),\n\t\t\t\t\t...(stamped ? { tsr: await bytesOf(`/empreintes/${tour.id}.racine.tsr`) } : {})\n\t\t\t\t}\n\t\t\t};\n\t\t}\n\t};\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/proof/proof.ts","../src/proof/der.ts","../src/proof/reach.ts","../src/proof/rfc3161.ts","../src/proof/journal.ts"],"names":["refused","hex"],"mappings":"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","file":"proof.js","sourcesContent":["// Proof of existence for the user's own documents: the bytes never leave the\n// device, only their SHA-256 does. A notary dates that digest; the receipt it\n// hands back is kept next to the file, in the user's own storage, and anyone\n// holding the file and the receipt can check the two still belong together.\n\nimport { sha256Hex } from '../selfstore/digest';\nimport { isSelfstoreError, SelfstoreError } from '../selfstore/errors';\nimport { toBytes, type FileBytes } from '../simple/bytes';\nimport type { SimpleRecord } from '../simple/simple';\n\n/**\n * What a notary hands back for one digest. `evidence` is the notary's own\n * material (a timestamp token, an inclusion path, a download address), as\n * strings - base64 for bytes - so a receipt is plain JSON and survives every\n * destination a store can write to.\n */\nexport interface Receipt {\n\t/** The notary that issued it (`Notary.name`). */\n\treadonly notary: string;\n\t/** Lowercase hex SHA-256 of the document. */\n\treadonly hash: string;\n\t/** The label sent with the deposit, if any. */\n\treadonly label?: string;\n\t/** ISO 8601 instant the notary vouches for (its clock, not the device's). */\n\treadonly depositedAt: string;\n\t/** False while the notary still has something to add (an anchor, a seal). */\n\treadonly complete: boolean;\n\treadonly evidence: Readonly<Record<string, string>>;\n}\n\n/**\n * Anyone who dates a digest. `deposit` must never see more than the digest and\n * the label; `complete` is called later - the next day, the next launch - and\n * returns the same receipt with whatever the notary could not give at once.\n * A notary that is final on deposit returns its argument unchanged.\n */\nexport interface Notary {\n\treadonly name: string;\n\tdeposit(hash: string, label?: string): Promise<Receipt>;\n\tcomplete(receipt: Receipt): Promise<Receipt>;\n}\n\n/** A receipt as `prove()` keeps it: the notary's, plus what the device measured. */\nexport interface Proof extends Receipt {\n\treadonly kind: 'selfstore-proof';\n\treadonly version: 1;\n\treadonly algorithm: 'SHA-256';\n\t/** Size of the document in bytes. */\n\treadonly size: number;\n\t/** The store file the proof belongs to, when there is one. */\n\treadonly file?: string;\n}\n\n/** Where proofs are kept: the simple store fits as is. */\nexport interface ProofShelf {\n\tput(collection: string, record: SimpleRecord): Promise<void>;\n}\n\n/** The collection `prove()` and `completeProof()` write to. */\nexport const PROOFS = 'proofs';\n\nexport interface ProveOptions {\n\tnotary: Notary;\n\t/** Sent to the notary with the digest. A TYPE ('invoice', 'inventory'),\n\t * never a name or a piece of the content: it leaves the device. */\n\tlabel?: string;\n\t/** Keep the proof in this store, under `PROOFS`, keyed by `file` or by hash. */\n\tstore?: ProofShelf;\n\t/** Id of the store file the document is (as `putFile` returned it). */\n\tfile?: string;\n}\n\n/** The result of `verify()`. */\nexport interface ProofCheck {\n\t/** The bytes hash to the receipt's digest (and size, when it carries one). */\n\treadonly matches: boolean;\n\t/** What the bytes hash to now. */\n\treadonly hash: string;\n\t/** Whether the notary had finished with this receipt. */\n\treadonly complete: boolean;\n}\n\nconst HEX_DIGEST = /^[0-9a-f]{64}$/;\n\nfunction refused(message: string): SelfstoreError {\n\treturn new SelfstoreError('NOTARY_REFUSED', message);\n}\n\n/** A notary that answers for another digest, or for another notary, is not believed. */\nfunction checkAnswer(answer: Receipt, hash: string, notary: Notary): void {\n\tif (typeof answer?.hash !== 'string' || answer.hash.toLowerCase() !== hash) {\n\t\tthrow refused(`${notary.name} answered for another digest`);\n\t}\n\tif (answer.notary !== notary.name) {\n\t\tthrow refused(`receipt names ${String(answer.notary)}, not ${notary.name}`);\n\t}\n\tif (Number.isNaN(Date.parse(answer.depositedAt))) {\n\t\tthrow refused(`${notary.name} gave no readable deposit time`);\n\t}\n}\n\nasync function shelve(proof: Proof, store: ProofShelf | undefined): Promise<void> {\n\tif (store) await store.put(PROOFS, { ...proof, id: proof.file ?? proof.hash });\n}\n\n/**\n * Hash `blob` on the device, deposit the digest with `options.notary`, and\n * return the proof - kept in `options.store` too when one is given. Only the\n * digest and the label leave the device.\n *\n * Throws NOTARY_UNAVAILABLE when the notary cannot be reached (retry later)\n * and NOTARY_REFUSED when it refuses or answers for something else.\n */\nexport async function prove(blob: FileBytes, options: ProveOptions): Promise<Proof> {\n\tconst bytes = await toBytes(blob);\n\tconst hash = await sha256Hex(bytes);\n\tconst answer = await options.notary.deposit(hash, options.label);\n\tcheckAnswer(answer, hash, options.notary);\n\tconst proof: Proof = {\n\t\t...answer,\n\t\thash,\n\t\tkind: 'selfstore-proof',\n\t\tversion: 1,\n\t\talgorithm: 'SHA-256',\n\t\tsize: bytes.length,\n\t\t...(options.file === undefined ? {} : { file: options.file })\n\t};\n\tawait shelve(proof, options.store);\n\treturn proof;\n}\n\n/**\n * Ask the notary for what it could not give on deposit. A complete proof is\n * returned as is, without a call. The fields the device measured are kept;\n * the notary may only add to its own.\n */\nexport async function completeProof(\n\tproof: Proof,\n\toptions: { notary: Notary; store?: ProofShelf }\n): Promise<Proof> {\n\tif (proof.complete) return proof;\n\tconst answer = await options.notary.complete(proof);\n\tcheckAnswer(answer, proof.hash, options.notary);\n\tconst completed: Proof = {\n\t\t...answer,\n\t\thash: proof.hash,\n\t\tkind: proof.kind,\n\t\tversion: proof.version,\n\t\talgorithm: proof.algorithm,\n\t\tsize: proof.size,\n\t\t...(proof.file === undefined ? {} : { file: proof.file })\n\t};\n\tawait shelve(completed, options.store);\n\treturn completed;\n}\n\n/**\n * Hash `blob` again and compare it with the receipt. This proves the bytes are\n * the ones the receipt names; that the receipt itself is genuine is what the\n * notary's evidence is for, checked with the notary's own verifier.\n *\n * Throws BAD_FORMAT on a receipt that carries no SHA-256 digest at all - a\n * damaged receipt is not a document that changed.\n */\nexport async function verify(\n\tblob: FileBytes,\n\treceipt: Pick<Receipt, 'hash' | 'complete'> & { size?: number }\n): Promise<ProofCheck> {\n\tconst expected = typeof receipt?.hash === 'string' ? receipt.hash.toLowerCase() : '';\n\tif (!HEX_DIGEST.test(expected)) {\n\t\tthrow new SelfstoreError('BAD_FORMAT', 'the receipt carries no SHA-256 digest');\n\t}\n\tconst bytes = await toBytes(blob);\n\tconst hash = await sha256Hex(bytes);\n\tconst sizeAgrees = receipt.size === undefined || receipt.size === bytes.length;\n\treturn { matches: hash === expected && sizeAgrees, hash, complete: receipt.complete === true };\n}\n\n/** Where proofs are read back from: the simple store fits as is. */\nexport interface ProofLibrary extends ProofShelf {\n\tall(collection: string): readonly SimpleRecord[];\n}\n\nfunction isProof(record: SimpleRecord): boolean {\n\treturn (\n\t\trecord.kind === 'selfstore-proof' &&\n\t\ttypeof record.hash === 'string' &&\n\t\tHEX_DIGEST.test(record.hash) &&\n\t\ttypeof record.notary === 'string' &&\n\t\ttypeof record.complete === 'boolean'\n\t);\n}\n\n/**\n * Every proof kept in `store`, oldest deposit first. Records that are not\n * proofs - another app's, a damaged one - are skipped rather than trusted.\n */\nexport function proofsIn(store: Pick<ProofLibrary, 'all'>): Proof[] {\n\treturn store\n\t\t.all(PROOFS)\n\t\t.filter(isProof)\n\t\t.map((record) => {\n\t\t\tconst { id: _id, ...proof } = record;\n\t\t\treturn proof as unknown as Proof;\n\t\t})\n\t\t.sort((a, b) => Date.parse(a.depositedAt) - Date.parse(b.depositedAt));\n}\n\n/** What `completePending()` did, proof by proof. */\nexport interface PendingRound {\n\t/** Finished this round, and written back to the store. */\n\treadonly completed: readonly Proof[];\n\t/** Still waiting: the notary has nothing to add yet, could not be reached,\n\t * or is not among the notaries given. Ask again on a later launch. */\n\treadonly pending: readonly Proof[];\n\t/** The notary answered for something else; kept as it was, not overwritten. */\n\treadonly refused: readonly Proof[];\n}\n\nfunction isCode(error: unknown, code: string): boolean {\n\treturn isSelfstoreError(error) && error.code === code;\n}\n\n/**\n * Ask each notary to finish the incomplete proofs it issued - the call an app\n * makes at launch, since a notary that anchors its digests finishes a receipt\n * hours after the deposit. A notary that cannot be reached is not asked again\n * this round; a proof whose notary is not in `notaries` waits. Only a proof\n * that came back complete is written to the store.\n */\nexport async function completePending(options: {\n\tstore: ProofLibrary;\n\tnotaries: readonly Notary[];\n}): Promise<PendingRound> {\n\tconst byName = new Map(options.notaries.map((notary) => [notary.name, notary]));\n\tconst unreachable = new Set<string>();\n\tconst completed: Proof[] = [];\n\tconst pending: Proof[] = [];\n\tconst refused: Proof[] = [];\n\tfor (const proof of proofsIn(options.store)) {\n\t\tif (proof.complete) continue;\n\t\tconst notary = byName.get(proof.notary);\n\t\tif (notary === undefined || unreachable.has(notary.name)) {\n\t\t\tpending.push(proof);\n\t\t\tcontinue;\n\t\t}\n\t\ttry {\n\t\t\tconst answer = await completeProof(proof, { notary });\n\t\t\tif (answer.complete) {\n\t\t\t\tawait shelve(answer, options.store);\n\t\t\t\tcompleted.push(answer);\n\t\t\t} else {\n\t\t\t\tpending.push(proof);\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tif (isCode(error, 'NOTARY_UNAVAILABLE')) {\n\t\t\t\tunreachable.add(notary.name);\n\t\t\t\tpending.push(proof);\n\t\t\t} else if (isCode(error, 'NOTARY_REFUSED')) {\n\t\t\t\trefused.push(proof);\n\t\t\t} else {\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t}\n\t}\n\treturn { completed, pending, refused };\n}\n","// The few DER shapes an RFC 3161 exchange needs, and no more. A timestamp\n// request is five fields and the reply is read along one path, so a general\n// ASN.1 library would be a fourth runtime dependency for two functions.\n\n/** One decoded TLV: `start` and `end` bound its CONTENT. */\nexport interface DerNode {\n\treadonly tag: number;\n\treadonly start: number;\n\treadonly end: number;\n}\n\nexport class DerError extends Error {}\n\nfunction encodeLength(length: number): Uint8Array {\n\tif (length < 0x80) return Uint8Array.of(length);\n\tconst bytes: number[] = [];\n\tfor (let rest = length; rest > 0; rest = Math.floor(rest / 256)) bytes.unshift(rest % 256);\n\treturn Uint8Array.of(0x80 | bytes.length, ...bytes);\n}\n\n/** Encode one TLV around already-encoded content. */\nexport function tlv(tag: number, ...parts: Uint8Array[]): Uint8Array {\n\tconst length = parts.reduce((sum, part) => sum + part.length, 0);\n\tconst head = encodeLength(length);\n\tconst out = new Uint8Array(1 + head.length + length);\n\tout[0] = tag;\n\tout.set(head, 1);\n\tlet at = 1 + head.length;\n\tfor (const part of parts) {\n\t\tout.set(part, at);\n\t\tat += part.length;\n\t}\n\treturn out;\n}\n\n/** Read the TLV that starts at `offset`. Indefinite lengths are BER, not DER: refused. */\nexport function readNode(bytes: Uint8Array, offset: number, limit = bytes.length): DerNode {\n\tif (offset + 2 > limit) throw new DerError('truncated header');\n\tconst tag = bytes[offset];\n\tconst first = bytes[offset + 1];\n\tlet start = offset + 2;\n\tlet length = first;\n\tif (first & 0x80) {\n\t\tconst count = first & 0x7f;\n\t\tif (count === 0 || count > 4) throw new DerError('unsupported length');\n\t\tif (start + count > limit) throw new DerError('truncated length');\n\t\tlength = 0;\n\t\tfor (let i = 0; i < count; i++) length = length * 256 + bytes[start + i];\n\t\tstart += count;\n\t}\n\tconst end = start + length;\n\tif (end > limit) throw new DerError('content runs past its parent');\n\treturn { tag, start, end };\n}\n\n/** The direct children of a constructed node. */\nexport function childrenOf(bytes: Uint8Array, node: DerNode): DerNode[] {\n\tconst out: DerNode[] = [];\n\tfor (let at = node.start; at < node.end;) {\n\t\tconst child = readNode(bytes, at, node.end);\n\t\tout.push(child);\n\t\tat = child.end;\n\t}\n\treturn out;\n}\n\n/** The node's content, or a refusal when its tag is not the one expected. */\nexport function expectTag(node: DerNode | undefined, tag: number): DerNode {\n\tif (node?.tag !== tag) throw new DerError(`expected tag 0x${tag.toString(16)}`);\n\treturn node;\n}\n\nexport function contentOf(bytes: Uint8Array, node: DerNode): Uint8Array {\n\treturn bytes.subarray(node.start, node.end);\n}\n","// One way to call a notary over HTTP, so every adapter maps the same failures\n// to the same codes: unreachable, overloaded or rate-limited is worth a retry,\n// any other refusal is not.\n\nimport { SelfstoreError } from '../selfstore/errors';\n\n/** Fetch `url`, throwing NOTARY_UNAVAILABLE or NOTARY_REFUSED instead of returning a failure. */\nexport async function reach(\n\tsend: typeof fetch,\n\turl: string,\n\tinit: RequestInit | undefined,\n\twho: string\n): Promise<Response> {\n\tlet response: Response;\n\ttry {\n\t\tresponse = await send(url, init);\n\t} catch (e) {\n\t\tthrow new SelfstoreError(\n\t\t\t'NOTARY_UNAVAILABLE',\n\t\t\t`${who} could not be reached: ${(e as Error).message}`\n\t\t);\n\t}\n\tif (!response.ok) {\n\t\tconst code =\n\t\t\tresponse.status >= 500 || response.status === 429 ? 'NOTARY_UNAVAILABLE' : 'NOTARY_REFUSED';\n\t\tthrow new SelfstoreError(code, `${who} answered ${response.status}`);\n\t}\n\treturn response;\n}\n","// A notary over any RFC 3161 time-stamping authority. The authority signs the\n// digest and the time in one token, so the receipt is complete on deposit: the\n// token (the `.tsr` file) is the evidence, and `openssl ts -verify` checks it\n// against the authority's certificate without this library.\n\nimport { fromBase64, toBase64 } from '../selfstore/base64';\nimport { hex } from '../selfstore/digest';\nimport { SelfstoreError } from '../selfstore/errors';\nimport { childrenOf, contentOf, DerError, expectTag, readNode, tlv, type DerNode } from './der';\nimport type { Notary, Receipt } from './proof';\nimport { reach } from './reach';\n\nconst SEQUENCE = 0x30;\nconst INTEGER = 0x02;\nconst OCTET_STRING = 0x04;\nconst OID = 0x06;\nconst GENERALIZED_TIME = 0x18;\nconst EXPLICIT_0 = 0xa0;\n\n/** id-sha256, 2.16.840.1.101.3.4.2.1, with its NULL parameters. */\nconst SHA256_ALGORITHM = tlv(\n\tSEQUENCE,\n\ttlv(OID, Uint8Array.of(0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01)),\n\tUint8Array.of(0x05, 0x00)\n);\n\nexport interface Rfc3161Options {\n\t/** The authority's endpoint. In a browser it must answer CORS, or sit\n\t * behind a relay of yours that does: most public authorities do not. */\n\turl: string;\n\t/** Receipt `notary` field. Defaults to 'rfc3161'. */\n\tname?: string;\n\t/** Injected for tests and relays; defaults to the global fetch. */\n\tfetch?: typeof fetch;\n}\n\n/** What a timestamp token says, read without checking its signature. */\nexport interface TimestampToken {\n\t/** Lowercase hex of the digest the authority stamped. */\n\treadonly hash: string;\n\t/** ISO 8601 instant the authority signed. */\n\treadonly time: string;\n\t/** The nonce echoed back, as lowercase hex, when there is one. */\n\treadonly nonce?: string;\n}\n\nfunction hexToBytes(hex: string): Uint8Array {\n\treturn Uint8Array.from(hex.match(/../g) ?? [], (pair) => Number.parseInt(pair, 16));\n}\n\n/** Leading zero bytes are DER's sign padding, not part of the value. */\nfunction integerHex(bytes: Uint8Array): string {\n\tlet at = 0;\n\twhile (at < bytes.length - 1 && bytes[at] === 0) at++;\n\treturn hex(bytes.subarray(at));\n}\n\n/** Eight random bytes, positive and minimal as a DER INTEGER. */\nfunction newNonce(): Uint8Array {\n\tconst nonce = crypto.getRandomValues(new Uint8Array(8));\n\tnonce[0] = (nonce[0] & 0x3f) | 0x40;\n\treturn nonce;\n}\n\n/** A TimeStampReq (RFC 3161 section 2.4.1) for a SHA-256 digest, asking for the certificate. */\nexport function timestampRequest(hash: string, nonce: Uint8Array): Uint8Array {\n\treturn tlv(\n\t\tSEQUENCE,\n\t\ttlv(INTEGER, Uint8Array.of(1)),\n\t\ttlv(SEQUENCE, SHA256_ALGORITHM, tlv(OCTET_STRING, hexToBytes(hash))),\n\t\ttlv(INTEGER, nonce),\n\t\tUint8Array.of(0x01, 0x01, 0xff)\n\t);\n}\n\n/** YYYYMMDDHHMMSS[.fff]Z to ISO 8601. */\nfunction generalizedTime(text: string): string {\n\tconst parts = /^(\\d{4})(\\d{2})(\\d{2})(\\d{2})(\\d{2})(\\d{2})(\\.\\d+)?Z$/.exec(text);\n\tif (parts === null) throw new DerError(`unreadable time ${text}`);\n\tconst [, y, mo, d, h, mi, s, fraction] = parts;\n\treturn new Date(`${y}-${mo}-${d}T${h}:${mi}:${s}${fraction ?? ''}Z`).toISOString();\n}\n\n/** TimeStampResp: the status, or the token when it was granted. */\nfunction tokenOf(bytes: Uint8Array): DerNode {\n\tconst [statusInfo, token] = childrenOf(bytes, expectTag(readNode(bytes, 0), SEQUENCE));\n\tconst status = expectTag(childrenOf(bytes, expectTag(statusInfo, SEQUENCE))[0], INTEGER);\n\tconst code = Number.parseInt(integerHex(contentOf(bytes, status)), 16);\n\t// 0 granted, 1 granted with modifications; anything else is a refusal.\n\tif (code > 1) {\n\t\tthrow new SelfstoreError(\n\t\t\t'NOTARY_REFUSED',\n\t\t\t`the authority refused the request (status ${code})`\n\t\t);\n\t}\n\treturn expectTag(token, SEQUENCE);\n}\n\n/** ContentInfo > SignedData > EncapsulatedContentInfo > TSTInfo. */\nfunction tstInfoOf(bytes: Uint8Array, token: DerNode): DerNode {\n\tconst signedData = expectTag(\n\t\tchildrenOf(bytes, expectTag(childrenOf(bytes, token)[1], EXPLICIT_0))[0],\n\t\tSEQUENCE\n\t);\n\tconst encapsulated = expectTag(childrenOf(bytes, signedData)[2], SEQUENCE);\n\tconst wrapper = expectTag(childrenOf(bytes, encapsulated)[1], EXPLICIT_0);\n\tconst octets = expectTag(childrenOf(bytes, wrapper)[0], OCTET_STRING);\n\treturn expectTag(readNode(bytes, octets.start, octets.end), SEQUENCE);\n}\n\n/**\n * Read the digest, the time and the nonce out of a TimeStampResp (the `.tsr`\n * file). It does NOT check the authority's signature - that is what\n * `openssl ts -verify` is for; it is what tells a token for another document\n * apart before anything is kept. Throws NOTARY_REFUSED on a refusal or on\n * anything that is not a timestamp reply.\n */\nexport function readTimestampReply(bytes: Uint8Array): TimestampToken {\n\ttry {\n\t\tconst tstInfo = tstInfoOf(bytes, tokenOf(bytes));\n\t\t// version, policy, messageImprint, serialNumber, genTime, then optional\n\t\t// accuracy, ordering and nonce - the nonce is the only INTEGER among them.\n\t\tconst [, , imprint, , time, ...rest] = childrenOf(bytes, tstInfo);\n\t\tconst digest = expectTag(childrenOf(bytes, expectTag(imprint, SEQUENCE))[1], OCTET_STRING);\n\t\tconst nonce = rest.find((node) => node.tag === INTEGER);\n\t\tconst genTime = new TextDecoder().decode(contentOf(bytes, expectTag(time, GENERALIZED_TIME)));\n\t\treturn {\n\t\t\thash: hex(contentOf(bytes, digest)),\n\t\t\ttime: generalizedTime(genTime),\n\t\t\t...(nonce ? { nonce: integerHex(contentOf(bytes, nonce)) } : {})\n\t\t};\n\t} catch (e) {\n\t\tif (e instanceof SelfstoreError) throw e;\n\t\tthrow new SelfstoreError('NOTARY_REFUSED', `not a timestamp reply: ${(e as Error).message}`);\n\t}\n}\n\nasync function post(options: Rfc3161Options, body: Uint8Array): Promise<Uint8Array> {\n\tconst response = await reach(\n\t\toptions.fetch ?? globalThis.fetch,\n\t\toptions.url,\n\t\t{\n\t\t\tmethod: 'POST',\n\t\t\theaders: { 'content-type': 'application/timestamp-query' },\n\t\t\tbody: body as BodyInit\n\t\t},\n\t\t'the authority'\n\t);\n\treturn new Uint8Array(await response.arrayBuffer());\n}\n\n/**\n * A notary over an RFC 3161 time-stamping authority. The receipt is complete\n * on deposit; its evidence is the reply, base64 under `tsr`, and the\n * authority's address under `tsa`. The label is never sent: RFC 3161 has no\n * field for it, so it stays on the receipt.\n */\nexport function rfc3161Notary(options: Rfc3161Options): Notary {\n\tconst name = options.name ?? 'rfc3161';\n\treturn {\n\t\tname,\n\t\tasync deposit(hash: string, label?: string): Promise<Receipt> {\n\t\t\tconst nonce = newNonce();\n\t\t\tconst reply = await post(options, timestampRequest(hash, nonce));\n\t\t\tconst token = readTimestampReply(reply);\n\t\t\tif (token.hash !== hash) {\n\t\t\t\tthrow new SelfstoreError('NOTARY_REFUSED', 'the authority stamped another digest');\n\t\t\t}\n\t\t\tif (token.nonce !== integerHex(nonce)) {\n\t\t\t\tthrow new SelfstoreError('NOTARY_REFUSED', 'the reply does not answer this request');\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tnotary: name,\n\t\t\t\thash,\n\t\t\t\t...(label === undefined ? {} : { label }),\n\t\t\t\tdepositedAt: token.time,\n\t\t\t\tcomplete: true,\n\t\t\t\tevidence: { tsr: toBase64(reply), tsa: options.url }\n\t\t\t};\n\t\t},\n\t\tcomplete(receipt: Receipt): Promise<Receipt> {\n\t\t\treturn Promise.resolve(receipt);\n\t\t}\n\t};\n}\n\n/** The `.tsr` bytes of an RFC 3161 receipt, to offer as a download. */\nexport function timestampReplyOf(receipt: Pick<Receipt, 'evidence'>): Uint8Array | undefined {\n\tconst tsr = receipt.evidence.tsr;\n\treturn tsr === undefined ? undefined : fromBase64(tsr);\n}\n","// A notary over a public digest journal: a service that takes a SHA-256 with\n// no account, writes it as one line of a public deposits file, and folds that\n// file into a Merkle tree it anchors in Bitcoin (OpenTimestamps) and often\n// stamps under RFC 3161 too. The deposit answers at once with the journal's\n// own receipt; the anchor comes hours later, so `complete` is what fetches it.\n//\n// The protocol, relative to the journal's base URL:\n// POST /api/depots {\"sha256\", \"libelle\"?, \"type\"?} -> 201\n// {\"id\", \"jour\", \"place\", \"ligne\", \"recu\": {\"sha256\", \"depose\", ...}}\n// GET /empreintes/depots.jsonl one JSON line per deposit, in order, with \"recu\" = id\n// GET /tours.json {\"tours\": [{\"id\", \"racine\", \"depots\", \"ots\", \"bloc\",\n// \"horodatage\", \"fichiers\"}]}; a tour covers the\n// first `depots` lines of the deposits file\n// GET /empreintes/<tour>.racine.ots, /empreintes/<tour>.racine.tsr\n\nimport { toBase64 } from '../selfstore/base64';\nimport { SelfstoreError } from '../selfstore/errors';\nimport type { Notary, Receipt } from './proof';\nimport { reach } from './reach';\n\nexport interface JournalOptions {\n\t/** The journal's base URL, e.g. 'https://journal.example'. */\n\turl: string;\n\t/** Receipt `notary` field. Defaults to 'digest-journal'. */\n\tname?: string;\n\t/**\n\t * The journal's deposit type, sent as `type` with every deposit (a journal\n\t * that issues typed receipts, such as a permit display, keys them on it).\n\t * None by default: the deposit is the journal's ordinary one.\n\t */\n\ttype?: string;\n\t/** Injected for tests and relays; defaults to the global fetch. */\n\tfetch?: typeof fetch;\n}\n\ninterface Deposit {\n\tid: string;\n\tligne: string;\n\trecu: { sha256: string; depose: string };\n}\n\ninterface Tour {\n\tid: string;\n\tracine: string;\n\tdepots: number;\n\tots: string;\n\tbloc: number | null;\n\thorodatage: string | null;\n\tfichiers?: string[];\n}\n\nconst HEX_ID = /^[0-9a-f]{64}$/;\n\nfunction refused(message: string): SelfstoreError {\n\treturn new SelfstoreError('NOTARY_REFUSED', message);\n}\n\nfunction readDeposit(body: unknown): Deposit {\n\tconst d = body as Partial<Deposit> | null;\n\tif (\n\t\ttypeof d?.id !== 'string' ||\n\t\t!HEX_ID.test(d.id) ||\n\t\ttypeof d.ligne !== 'string' ||\n\t\ttypeof d.recu?.sha256 !== 'string' ||\n\t\ttypeof d.recu.depose !== 'string'\n\t) {\n\t\tthrow refused('the journal answered without a receipt');\n\t}\n\treturn d as Deposit;\n}\n\nfunction parseLine(text: string): { recu?: string; sha256?: string } {\n\ttry {\n\t\treturn JSON.parse(text) as { recu?: string; sha256?: string };\n\t} catch {\n\t\tthrow refused('the journal published an unreadable deposits file');\n\t}\n}\n\n/** 1-based rank of the deposit line whose receipt id is `id`, or 0. */\nfunction rankOf(deposits: string, id: string, hash: string): number {\n\tconst lines = deposits.split('\\n').filter(Boolean);\n\tfor (const [index, text] of lines.entries()) {\n\t\tconst line = parseLine(text);\n\t\tif (line.recu !== id) continue;\n\t\tif (line.sha256 !== hash) throw refused('the journal lists this receipt for another digest');\n\t\treturn index + 1;\n\t}\n\treturn 0;\n}\n\n/**\n * A notary over a public digest journal (the protocol is at the top of this\n * file). The label is sent as the journal's `libelle`: keep it a TYPE, unless\n * the journal's `type` (an option of the notary) says what the label is.\n *\n * On deposit the receipt is incomplete; its evidence holds the journal's\n * address, the receipt `id`, the public `line` and the journal's own `receipt`\n * as JSON - the file its verifier reads. `complete` finds the first tour that\n * covers the line and, once that tour is anchored in Bitcoin, completes the\n * receipt with `tour`, `root`, `block`, the `.ots` proof and, when the journal\n * stamped that root, the `.tsr` token (both base64). Checking the Merkle path\n * from the line to the root is the journal's verifier's job.\n */\nexport function digestJournalNotary(options: JournalOptions): Notary {\n\tconst name = options.name ?? 'digest-journal';\n\tconst base = options.url.replace(/\\/+$/, '');\n\tconst typed = options.type === undefined ? {} : { type: options.type };\n\tconst send = options.fetch ?? globalThis.fetch;\n\tconst get = (path: string): Promise<Response> =>\n\t\treach(send, `${base}${path}`, undefined, 'the journal');\n\tconst bytesOf = async (path: string): Promise<string> =>\n\t\ttoBase64(new Uint8Array(await (await get(path)).arrayBuffer()));\n\n\treturn {\n\t\tname,\n\t\tasync deposit(hash: string, label?: string): Promise<Receipt> {\n\t\t\tconst response = await reach(\n\t\t\t\tsend,\n\t\t\t\t`${base}/api/depots`,\n\t\t\t\t{\n\t\t\t\t\tmethod: 'POST',\n\t\t\t\t\theaders: { 'content-type': 'application/json' },\n\t\t\t\t\tbody: JSON.stringify({\n\t\t\t\t\t\tsha256: hash,\n\t\t\t\t\t\t...(label === undefined ? {} : { libelle: label }),\n\t\t\t\t\t\t...typed\n\t\t\t\t\t})\n\t\t\t\t},\n\t\t\t\t'the journal'\n\t\t\t);\n\t\t\tconst deposit = readDeposit(await response.json().catch(() => null));\n\t\t\treturn {\n\t\t\t\tnotary: name,\n\t\t\t\thash: deposit.recu.sha256,\n\t\t\t\t...(label === undefined ? {} : { label }),\n\t\t\t\tdepositedAt: deposit.recu.depose,\n\t\t\t\tcomplete: false,\n\t\t\t\tevidence: {\n\t\t\t\t\tjournal: base,\n\t\t\t\t\tid: deposit.id,\n\t\t\t\t\tline: deposit.ligne,\n\t\t\t\t\treceipt: JSON.stringify(deposit.recu)\n\t\t\t\t}\n\t\t\t};\n\t\t},\n\t\tasync complete(receipt: Receipt): Promise<Receipt> {\n\t\t\tconst id = receipt.evidence.id;\n\t\t\tif (id === undefined) throw refused('the receipt carries no journal id');\n\t\t\tconst rank = rankOf(await (await get('/empreintes/depots.jsonl')).text(), id, receipt.hash);\n\t\t\tif (rank === 0) return receipt;\n\t\t\tconst { tours } = (await (await get('/tours.json')).json()) as { tours: Tour[] };\n\t\t\tconst tour = tours.find((t) => t.depots >= rank);\n\t\t\tif (tour?.ots !== 'bitcoin') return receipt;\n\t\t\tconst stamped = tour.horodatage !== null && tour.fichiers?.includes(`${tour.id}.racine.tsr`);\n\t\t\treturn {\n\t\t\t\t...receipt,\n\t\t\t\tcomplete: true,\n\t\t\t\tevidence: {\n\t\t\t\t\t...receipt.evidence,\n\t\t\t\t\ttour: tour.id,\n\t\t\t\t\troot: tour.racine,\n\t\t\t\t\t...(tour.bloc === null ? {} : { block: String(tour.bloc) }),\n\t\t\t\t\tots: await bytesOf(`/empreintes/${tour.id}.racine.ots`),\n\t\t\t\t\t...(stamped ? { tsr: await bytesOf(`/empreintes/${tour.id}.racine.tsr`) } : {})\n\t\t\t\t}\n\t\t\t};\n\t\t}\n\t};\n}\n"]}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { B as BackupTarget, P as PeerSource } from './store-
|
|
2
|
-
import { K as KV } from './cache-
|
|
1
|
+
import { B as BackupTarget, P as PeerSource } from './store-DSPbCCtM.js';
|
|
2
|
+
import { K as KV } from './cache-BEv-Har2.js';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* WebDAV backup target: the store re-writes one .selfstore file on a WebDAV
|
|
@@ -109,4 +109,5 @@ declare function fromSession(opts: {
|
|
|
109
109
|
kv: KV;
|
|
110
110
|
}): Promise<BackupTarget | null>;
|
|
111
111
|
|
|
112
|
-
export {
|
|
112
|
+
export { connect$1 as a, fromSession$1 as b, connect as c, fromSession as f, peer as p };
|
|
113
|
+
export type { S3Config as S, WebdavConfig as W, S3ConnectOptions as d, WebdavConnectOptions as e, WebdavPeerOptions as g };
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { a as Snapshot, b as PasswordPolicy, c as SnapshotFile, B as BackupTarget, d as StatusDescriptor, S as StoreError, e as LocalStoreState, L as LocalStore } from './store-
|
|
2
|
-
import { L as LocalCache, K as KV } from './cache-
|
|
1
|
+
import { a as Snapshot, b as PasswordPolicy, c as SnapshotFile, B as BackupTarget, d as StatusDescriptor, S as StoreError, e as LocalStoreState, L as LocalStore } from './store-DSPbCCtM.js';
|
|
2
|
+
import { L as LocalCache, K as KV } from './cache-BEv-Har2.js';
|
|
3
3
|
import { SyncConfig } from './sync.js';
|
|
4
|
-
import { R as ResumeOffer, C as ConnectTargets } from './connect-
|
|
5
|
-
import { f as BackupsManager } from './manager-
|
|
6
|
-
import { a as DriveAuth } from './drive-
|
|
7
|
-
import { W as WebdavConfig, S as S3Config } from './s3-
|
|
4
|
+
import { R as ResumeOffer, C as ConnectTargets } from './connect-CDazV36v.js';
|
|
5
|
+
import { f as BackupsManager } from './manager-CnlIs-hY.js';
|
|
6
|
+
import { a as DriveAuth } from './drive-CwlKlowN.js';
|
|
7
|
+
import { W as WebdavConfig, S as S3Config } from './s3-Bexn9kzT.js';
|
|
8
8
|
|
|
9
9
|
/** What a file body may be handed in as. */
|
|
10
10
|
type FileBytes = Uint8Array | ArrayBuffer | Blob;
|
|
@@ -264,4 +264,5 @@ interface SimpleStore<S extends Record<string, SimpleRecord> = Record<string, Si
|
|
|
264
264
|
*/
|
|
265
265
|
declare function selfstore<S extends Record<string, SimpleRecord> = Record<string, SimpleRecord>>(app: string, options?: SimpleOptions): Promise<SimpleStore<S>>;
|
|
266
266
|
|
|
267
|
-
export {
|
|
267
|
+
export { selfstore as s };
|
|
268
|
+
export type { CacheUnlock as C, FileBytes as F, PutFileInput as P, SimpleRecord as S, ConnectOutcome as a, SimpleOptions as b, SimpleStore as c };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { G as GroupIdentity, S as SignedManifest, L as LocalCache } from './cache-
|
|
1
|
+
import { G as GroupIdentity, S as SignedManifest, L as LocalCache } from './cache-BEv-Har2.js';
|
|
2
2
|
import { CollectionChanges, Conflict, SyncConfig } from './sync.js';
|
|
3
3
|
|
|
4
4
|
/** A binary attachment (image, PDF, any bytes). */
|
|
@@ -631,4 +631,5 @@ interface LocalStore {
|
|
|
631
631
|
}
|
|
632
632
|
declare function createLocalStore(opts: LocalStoreOptions): LocalStore;
|
|
633
633
|
|
|
634
|
-
export { AuthExpiredError as A,
|
|
634
|
+
export { AuthExpiredError as A, errorLabelKey as C, isAuthExpired as D, isReservedStoreMode as F, isSelfstoreError as G, RESERVED_COLLECTION_PREFIX as R, RESERVED_STORE_MODES as l, SelfstoreError as o, checkPasswordPolicy as x, createLocalStore as y, deriveStatus as z };
|
|
635
|
+
export type { BackupTarget as B, EncodeOptions as E, Header as H, KdfParams as K, LocalStore as L, MirrorState as M, PeerSource as P, StoreError as S, TargetKind as T, Snapshot as a, PasswordPolicy as b, SnapshotFile as c, StatusDescriptor as d, LocalStoreState as e, BuiltinTargetKind as f, LocalStoreOptions as g, Mode as h, PasswordCheck as i, PasswordRequirement as j, PeerState as k, RecipientStanza as m, ReplicaState as n, SelfstoreErrorCode as p, Severity as q, StatusAction as r, StatusInput as s, StorageState as t, StoreGroupConfig as u, SyncJournalEntry as v, SyncSource as w };
|
package/dist/sync.d.ts
CHANGED
|
@@ -105,4 +105,5 @@ interface CollectionChanges {
|
|
|
105
105
|
* result means the states are equivalent. Feeds the sync journal. */
|
|
106
106
|
declare function changes(before: Record<string, unknown[]>, after: Record<string, unknown[]>, config: SyncConfig): Record<string, CollectionChanges>;
|
|
107
107
|
|
|
108
|
-
export {
|
|
108
|
+
export { changes, createMeta, createNode, detectConflicts, merge, stamp };
|
|
109
|
+
export type { ColMeta, CollectionChanges, Conflict, Hlc, Id, MergeResult, MergeStrategy, ReplicaState, SyncConfig, SyncMeta };
|
package/dist/widgets.d.ts
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
|
-
import { S as StoreLike
|
|
1
|
+
import { S as StoreLike } from './connect-CDazV36v.js';
|
|
2
|
+
import { FlowHost, ConnectTargets, ConnectFlowOptions, ConnectKind, ConnectFlow } from './flows.js';
|
|
2
3
|
import { ShareEngine, ShareLevel, ShareFlow, JoinEngine, JoinFlow, ReplicaFlow } from './flows.js';
|
|
3
|
-
import {
|
|
4
|
-
import './store-
|
|
5
|
-
import './cache-
|
|
4
|
+
import { BackupsManager } from './backups.js';
|
|
5
|
+
import './store-DSPbCCtM.js';
|
|
6
|
+
import './cache-BEv-Har2.js';
|
|
6
7
|
import './sync.js';
|
|
7
|
-
import './drive-
|
|
8
|
-
import './s3-
|
|
9
|
-
import './machine-
|
|
8
|
+
import './drive-CwlKlowN.js';
|
|
9
|
+
import './s3-Bexn9kzT.js';
|
|
10
|
+
import './machine-Dhbx3Eut.js';
|
|
10
11
|
|
|
11
12
|
/** Flat key -> string map; widgets merge a partial override over EN defaults. */
|
|
12
13
|
type WidgetLabels = Record<string, string>;
|
|
@@ -878,4 +879,5 @@ declare function defineAccount(prefix?: string): void;
|
|
|
878
879
|
* above when size matters. */
|
|
879
880
|
declare function defineSelfstoreWidgets(prefix?: string): void;
|
|
880
881
|
|
|
881
|
-
export {
|
|
882
|
+
export { FlowWidget, SelfstoreAccountElement, SelfstoreBackupsElement, SelfstoreConnectElement, SelfstoreDestinationElement, SelfstoreGateElement, SelfstoreJoinElement, SelfstoreShareElement, SelfstoreStatusElement, SelfstoreStorageElement, defaultIcons, defineAccount, defineBackups, defineConnect, defineDestination, defineGate, defineJoin, defineSelfstoreWidgets, defineShare, defineStatus, defineStorage };
|
|
883
|
+
export type { BackupsAction, DestinationAction, ShareAction, WebdavPreset, WidgetLabels };
|
package/dist/widgets.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { saveToDisk, datedName } from './chunk-Q3NO477P.js';
|
|
2
|
-
import { connectFlow, shareFlow, joinFlow } from './chunk-
|
|
2
|
+
import { connectFlow, shareFlow, joinFlow } from './chunk-HRYIQSTH.js';
|
|
3
3
|
import './chunk-JDDWWQEB.js';
|
|
4
|
-
import { isOpenSupported } from './chunk-
|
|
4
|
+
import { isOpenSupported } from './chunk-HVHQLPP6.js';
|
|
5
5
|
import './chunk-2BNTCXQN.js';
|
|
6
6
|
import './chunk-25U6AKIX.js';
|
|
7
7
|
import './chunk-LF3CC2P3.js';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "selfstore",
|
|
3
|
-
"version": "1.8.
|
|
3
|
+
"version": "1.8.32",
|
|
4
4
|
"description": "Local-first storage for browser apps: an IndexedDB working copy, portable encrypted ZIP backups (AES-256-GCM over Argon2id), durable homes (disk, Google Drive, WebDAV) and a serverless multi-device merge.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -126,7 +126,8 @@
|
|
|
126
126
|
"idb": "^8.0.3"
|
|
127
127
|
},
|
|
128
128
|
"overrides": {
|
|
129
|
-
"esbuild": "^0.28.1"
|
|
129
|
+
"esbuild": "^0.28.1",
|
|
130
|
+
"zod": "4.6.7"
|
|
130
131
|
},
|
|
131
132
|
"devDependencies": {
|
|
132
133
|
"@eslint/js": "^10.0.1",
|
|
@@ -137,13 +138,13 @@
|
|
|
137
138
|
"eslint-plugin-sonarjs": "^4.2.0",
|
|
138
139
|
"fake-indexeddb": "^6.2.5",
|
|
139
140
|
"globals": "^17.7.0",
|
|
140
|
-
"happy-dom": "^21.0.
|
|
141
|
+
"happy-dom": "^21.0.4",
|
|
141
142
|
"jscpd": "^5.0.12",
|
|
142
143
|
"knip": "^6.29.0",
|
|
143
144
|
"lint-staged": "^17.2.0",
|
|
144
145
|
"prettier": "^3.9.6",
|
|
145
146
|
"simple-git-hooks": "^2.13.1",
|
|
146
|
-
"tsup": "^
|
|
147
|
+
"tsup": "^9.0.0",
|
|
147
148
|
"typescript": "^6.0.3",
|
|
148
149
|
"typescript-eslint": "^8.65.0",
|
|
149
150
|
"vitest": "^5.0.0",
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/persistence/targets/desktop.ts","../src/persistence/targets/file.ts"],"names":["connect","openExisting","fromSession"],"mappings":"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","file":"chunk-2TIRUEXR.js","sourcesContent":["/**\n * Disk-file backup target for a desktop shell (Tauri, and anything exposing the\n * same filesystem and dialog calls).\n *\n * The browser's File System Access API is Chromium-only and, inside a native\n * webview, usually absent altogether: on macOS and Linux the shell embeds\n * WebKit, which never shipped it. So the file destination would silently\n * degrade to download-on-demand in the one place where writing a real file is\n * easiest. This target restores it.\n *\n * What changes against the browser target is what gets persisted: a PATH, not a\n * handle. A path survives a restart, an app update and a backup of the profile\n * directory, and it needs no permission to be re-granted at each launch. The\n * store therefore reconnects silently where the browser asks for a click.\n *\n * The shell's own calls are INJECTED, never imported: this library keeps three\n * runtime dependencies, and a desktop toolkit is not going to be the fourth for\n * the sake of the web build that will never call it.\n */\n\nimport type { BackupTarget } from '../target';\nimport type { KV } from '../cache';\nimport { SelfstoreError } from '../../selfstore';\n\nconst PATH_KEY = 'desktopFilePath';\n\n/** Filter shape shared by the save and open dialogs. */\nexport interface DesktopDialogFilter {\n\tname: string;\n\textensions: string[];\n}\n\n/**\n * The filesystem and dialog calls this target needs, shaped so a host can pass\n * its shell's functions straight through with no adapter of its own.\n *\n * With Tauri v2 the whole wiring is the two plugin imports:\n *\n * ```ts\n * import { readFile, writeFile, stat, exists } from '@tauri-apps/plugin-fs';\n * import { save, open } from '@tauri-apps/plugin-dialog';\n * import { useDesktopFiles } from 'selfstore';\n *\n * useDesktopFiles({ readFile, writeFile, stat, exists, save, open });\n * ```\n *\n * Do that once at start-up and every `file` destination in this library runs on\n * a real path. Nothing else in a host changes.\n */\nexport interface DesktopFileBridge {\n\treadFile(path: string): Promise<Uint8Array>;\n\twriteFile(path: string, data: Uint8Array): Promise<void>;\n\t/** File metadata. Only `mtime` is read, and a shell that cannot report it\n\t * may leave it absent: the store then falls back to its own bookkeeping. */\n\tstat(path: string): Promise<{ mtime?: Date | number | null } | null>;\n\texists(path: string): Promise<boolean>;\n\t/** Save dialog. Resolves to the chosen path, or null when cancelled. */\n\tsave(options: { defaultPath?: string; filters?: DesktopDialogFilter[] }): Promise<string | null>;\n\t/** Open dialog. Resolves to the chosen path, or null when cancelled. The\n\t * array form is accepted so a host can pass its shell's function unchanged. */\n\topen(options: {\n\t\tmultiple?: boolean;\n\t\tfilters?: DesktopDialogFilter[];\n\t}): Promise<string | string[] | null>;\n}\n\nlet bridge: DesktopFileBridge | null = null;\n\n/**\n * Register the desktop shell's filesystem and dialog calls. Call once at\n * start-up, before opening the store. Passing null unregisters, which is what a\n * test wants between cases.\n */\nexport function useDesktopFiles(b: DesktopFileBridge | null): void {\n\tbridge = b;\n}\n\n/** True once a shell has been registered: the file destination then writes a\n * real path instead of asking the browser for a handle. */\nexport function hasDesktopFiles(): boolean {\n\treturn bridge != null;\n}\n\nconst FILTERS: DesktopDialogFilter[] = [{ name: 'Backup', extensions: ['zip'] }];\n\n/** Last path segment, for the label. Windows and POSIX separators both, since\n * the same build runs on either. */\nfunction baseName(path: string): string {\n\tconst parts = path.split(/[\\\\/]/);\n\treturn parts[parts.length - 1] || path;\n}\n\n/** Epoch milliseconds as the version marker, or null when the shell cannot\n * tell. Never throws: a marker that cannot be read is \"cannot tell\", and the\n * store treats that as no information rather than as a fault. */\nasync function markerOf(b: DesktopFileBridge, path: string): Promise<string | null> {\n\ttry {\n\t\tconst info = await b.stat(path);\n\t\tconst mtime = info?.mtime;\n\t\tif (mtime == null) return null;\n\t\tconst ms = mtime instanceof Date ? mtime.getTime() : Number(mtime);\n\t\treturn Number.isFinite(ms) ? String(ms) : null;\n\t} catch {\n\t\treturn null;\n\t}\n}\n\n/** Only the first path, whichever shape the shell's open dialog returns. */\nfunction firstPath(picked: string | string[] | null): string | null {\n\tif (picked == null) return null;\n\treturn Array.isArray(picked) ? (picked[0] ?? null) : picked;\n}\n\nfunction fromPath(path: string, b: DesktopFileBridge, kv: KV): BackupTarget {\n\t// reconnect() can move the destination to another file, so the path the\n\t// closure writes to has to be able to change under the object the store\n\t// already holds.\n\tlet current = path;\n\treturn {\n\t\tkind: 'file',\n\t\tget label(): string {\n\t\t\treturn baseName(current);\n\t\t},\n\t\tasync save(blob: Blob): Promise<string | null> {\n\t\t\ttry {\n\t\t\t\tawait b.writeFile(current, new Uint8Array(await blob.arrayBuffer()));\n\t\t\t} catch (e) {\n\t\t\t\t// No AuthExpiredError here on purpose. A desktop write fails because\n\t\t\t\t// the disk is full, the volume is unplugged or the file is locked by\n\t\t\t\t// another program - all transient, all resolved without the user\n\t\t\t\t// re-granting anything. Raising the reconnect gate would ask them to\n\t\t\t\t// re-pick a file that is exactly where they left it.\n\t\t\t\tthrow new SelfstoreError('TARGET_WRITE_FAILED', `File write failed: ${String(e)}`);\n\t\t\t}\n\t\t\treturn markerOf(b, current);\n\t\t},\n\t\tasync load(): Promise<Blob | null> {\n\t\t\ttry {\n\t\t\t\tconst bytes = await b.readFile(current);\n\t\t\t\treturn new Blob([new Uint8Array(bytes)]);\n\t\t\t} catch {\n\t\t\t\t// A path chosen through the save dialog names a file that does not\n\t\t\t\t// exist yet. \"No backup there\" is the honest answer, not a failure.\n\t\t\t\treturn null;\n\t\t\t}\n\t\t},\n\t\tasync stat(): Promise<string | null> {\n\t\t\treturn markerOf(b, current);\n\t\t},\n\t\tasync isReady(): Promise<boolean> {\n\t\t\t// A desktop write needs no user gesture and no grant that can lapse, so\n\t\t\t// the answer is yes even when the file is not there yet: refusing until\n\t\t\t// it exists would deadlock the very first save, which is what creates\n\t\t\t// it. A volume that went away surfaces when save() throws, and that\n\t\t\t// reads as transient - which is what an unplugged drive is.\n\t\t\treturn true;\n\t\t},\n\t\tasync reconnect(): Promise<boolean> {\n\t\t\tconst picked = await b.save({ defaultPath: current, filters: FILTERS });\n\t\t\tif (!picked) return false;\n\t\t\tcurrent = picked;\n\t\t\tawait kv.set(PATH_KEY, picked);\n\t\t\treturn true;\n\t\t},\n\t\tasync disconnect(): Promise<void> {\n\t\t\tawait kv.del(PATH_KEY);\n\t\t}\n\t};\n}\n\nexport interface DesktopConnectOptions {\n\t/** Where the chosen path is persisted across launches. */\n\tkv: KV;\n\t/** Suggested name for the backup file. */\n\tfileName: string;\n}\n\n/** Ask for a file to write the backup to, and remember it. Null when the user\n * cancelled, or when no shell is registered. */\nexport async function connect(opts: DesktopConnectOptions): Promise<BackupTarget | null> {\n\tif (!bridge) return null;\n\tconst picked = await bridge.save({ defaultPath: opts.fileName, filters: FILTERS });\n\tif (!picked) return null;\n\tawait opts.kv.set(PATH_KEY, picked);\n\treturn fromPath(picked, bridge, opts.kv);\n}\n\n/** Ask for an EXISTING backup file and adopt it as the destination; the connect\n * journey then reads it like any backup. Null when cancelled. */\nexport async function openExisting(opts: { kv: KV }): Promise<BackupTarget | null> {\n\tif (!bridge) return null;\n\tconst picked = firstPath(await bridge.open({ multiple: false, filters: FILTERS }));\n\tif (!picked) return null;\n\tawait opts.kv.set(PATH_KEY, picked);\n\treturn fromPath(picked, bridge, opts.kv);\n}\n\n/** Rebuild the target from the path kept in a past launch, or null. Unlike the\n * browser handle this needs no permission check, so a desktop app reopens on\n * its file with nothing asked of the user. */\nexport async function fromSession(opts: { kv: KV }): Promise<BackupTarget | null> {\n\tif (!bridge) return null;\n\tconst path = await opts.kv.get<string>(PATH_KEY);\n\treturn path ? fromPath(path, bridge, opts.kv) : null;\n}\n","/**\n * Disk-file backup target (Chromium only). The user picks a backup file once via\n * the File System Access API; the store then re-writes that real file on every\n * change. The handle is persisted through the injected KV, so the target stays\n * storage-agnostic. The browser re-confirms write permission once per session\n * (a one-click reconnect).\n */\n\nimport type { BackupTarget } from '../target';\nimport type { KV } from '../cache';\nimport { AuthExpiredError, SelfstoreError, type SelfstoreErrorCode } from '../../selfstore';\nimport * as desktop from './desktop';\n\nconst HANDLE_KEY = 'fileHandle';\n\ninterface FileHandle {\n\tname: string;\n\tcreateWritable(): Promise<{ write(data: Blob): Promise<void>; close(): Promise<void> }>;\n\tgetFile(): Promise<File>;\n\tqueryPermission(d: { mode: 'read' | 'readwrite' }): Promise<PermissionState>;\n\trequestPermission(d: { mode: 'read' | 'readwrite' }): Promise<PermissionState>;\n}\n\ninterface PickerWindow {\n\tshowSaveFilePicker?: (o: {\n\t\tsuggestedName?: string;\n\t\ttypes?: { description: string; accept: Record<string, string[]> }[];\n\t}) => Promise<FileHandle>;\n\tshowOpenFilePicker?: (o: {\n\t\tmultiple?: boolean;\n\t\ttypes?: { description: string; accept: Record<string, string[]> }[];\n\t}) => Promise<FileHandle[]>;\n}\n\nexport interface FileConnectOptions {\n\t/** Where the picked file handle is persisted across sessions. */\n\tkv: KV;\n\t/** Suggested name for the backup file the user creates/picks. */\n\tfileName: string;\n}\n\n/** Set once a picker that EXISTS has refused to open. Presence is not\n * capability: some browsers ship the methods and throw on call unless a flag\n * is turned on, so a host that trusts `'showSaveFilePicker' in window` offers\n * a file mode that can never work, and the button looks broken. The attempt is\n * the only honest probe there is - it costs one click, once. */\nlet refused = false;\n\n/** Was the call made inside a live user gesture?\n *\n * A picker REQUIRES transient activation, and a call made without one throws\n * the same DOMException as a browser that ships the picker and refuses it. Read\n * as a refusal, one mistimed call condemns the file mode for the whole session:\n * the host then falls back to manual downloads on a Chrome that was never\n * asked properly. A throw only teaches us about the browser when the browser\n * was actually allowed to answer. Undefined support (no userActivation) reads\n * as \"cannot tell\" - and cannot-tell must not accuse. */\nfunction insideGesture(): boolean {\n\tconst ua = typeof navigator !== 'undefined' ? navigator.userActivation : undefined;\n\treturn ua ? ua.isActive : true;\n}\n\n/** True when a re-writable file can be picked: a registered desktop shell, or\n * a browser that ships the File System Access API (Chromium) and has not\n * already refused to open a picker in this session.\n *\n * A desktop shell answers first and unconditionally. Inside a native webview\n * the browser probe is not merely negative, it is misleading: WebKit never\n * shipped the API, so the honest capability there is the shell's, and asking\n * the webview instead would degrade the file mode in the one environment where\n * writing a real file is easiest. */\nexport function isSupported(): boolean {\n\tif (desktop.hasDesktopFiles()) return true;\n\treturn !refused && typeof window !== 'undefined' && 'showSaveFilePicker' in window;\n}\n\n/** True when the browser can let the user point at an EXISTING file. Hosts must\n * gate that gesture on this: unlike creating, it has no download fallback, so\n * offering it where it cannot run leaves a button that answers nothing. The\n * refusal is shared with `isSupported` - a browser that refuses one picker\n * refuses the family. */\nexport function isOpenSupported(): boolean {\n\tif (desktop.hasDesktopFiles()) return true;\n\treturn !refused && typeof window !== 'undefined' && 'showOpenFilePicker' in window;\n}\n\n/** Run a picker. Cancelling and refusing both mean \"no file\", but only a\n * refusal says something about the browser - and it must not surface as an\n * error, or the host reports a fault where it should offer another way. */\nasync function ask<T>(open: () => Promise<T>): Promise<T | null> {\n\tconst asked = insideGesture();\n\ttry {\n\t\treturn await open();\n\t} catch (e) {\n\t\tif (e instanceof DOMException && e.name === 'AbortError') return null; // user cancelled\n\t\t// Outside a gesture the browser refused the CALL, not the feature: keep\n\t\t// the file mode intact so the host can ask again from a real click.\n\t\trefused = asked;\n\t\treturn null;\n\t}\n}\n\n/** Give a browser exception the stable code the target contract requires, so a\n * host reads WHICH kind of failure it hit instead of a DOMException name.\n *\n * Untyped, everything the handle throws lands in the store's default branch -\n * \"transient, the next save retries\" - and that is the one reading always\n * wrong here: no amount of retrying re-grants a permission, and a file that\n * was deleted does not come back on its own. Both then loop forever while the\n * store keeps reporting the data as saved. */\nfunction asTargetError(e: unknown, transient: SelfstoreErrorCode, what: string): Error {\n\tconst name = e instanceof DOMException ? e.name : '';\n\t// Revoked or denied: only a user gesture re-grants it, which is exactly what\n\t// the reconnect gate asks for.\n\tif (name === 'NotAllowedError' || name === 'SecurityError') {\n\t\treturn new AuthExpiredError('File permission was revoked.');\n\t}\n\t// Deleted, renamed, or on a volume that is no longer mounted. Permanent as\n\t// far as this handle goes: reconnecting means pointing at a file again.\n\tif (name === 'NotFoundError') {\n\t\treturn new SelfstoreError('TARGET_GONE', `${what}: the backup file is no longer there.`);\n\t}\n\treturn new SelfstoreError(transient, `${what}: ${String(e)}`);\n}\n\nfunction fromHandle(handle: FileHandle, kv: KV): BackupTarget {\n\treturn {\n\t\tkind: 'file',\n\t\tlabel: handle.name,\n\t\tasync save(blob: Blob): Promise<string | null> {\n\t\t\ttry {\n\t\t\t\tconst writable = await handle.createWritable();\n\t\t\t\tawait writable.write(blob);\n\t\t\t\tawait writable.close();\n\t\t\t} catch (e) {\n\t\t\t\tthrow asTargetError(e, 'TARGET_WRITE_FAILED', 'File write failed');\n\t\t\t}\n\t\t\ttry {\n\t\t\t\t// The file's new mtime = OUR write's version marker (shared-disk case).\n\t\t\t\treturn String((await handle.getFile()).lastModified);\n\t\t\t} catch {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t},\n\t\tasync load(): Promise<Blob | null> {\n\t\t\t// A read that fails is NOT a destination that is empty: returning null\n\t\t\t// here would tell the store \"no backup there\", and the connect that\n\t\t\t// follows would overwrite the file this read merely failed to open.\n\t\t\ttry {\n\t\t\t\treturn await handle.getFile();\n\t\t\t} catch (e) {\n\t\t\t\tthrow asTargetError(e, 'TARGET_UNAVAILABLE', 'File read failed');\n\t\t\t}\n\t\t},\n\t\tasync stat(): Promise<string | null> {\n\t\t\ttry {\n\t\t\t\treturn String((await handle.getFile()).lastModified);\n\t\t\t} catch {\n\t\t\t\treturn null; // permission not granted yet: \"cannot tell\", never throws\n\t\t\t}\n\t\t},\n\t\tasync isReady(): Promise<boolean> {\n\t\t\treturn (await handle.queryPermission({ mode: 'readwrite' })) === 'granted';\n\t\t},\n\t\tasync reconnect(): Promise<boolean> {\n\t\t\treturn (await handle.requestPermission({ mode: 'readwrite' })) === 'granted';\n\t\t},\n\t\tasync disconnect(): Promise<void> {\n\t\t\tawait kv.del(HANDLE_KEY);\n\t\t}\n\t};\n}\n\n/** Prompt the user to choose/create the backup file. Persists the handle for\n * next sessions. Returns the target, or null if cancelled - or if the browser\n * refused to open a picker at all, which `isSupported()` then reports. */\nexport async function connect(opts: FileConnectOptions): Promise<BackupTarget | null> {\n\tif (desktop.hasDesktopFiles()) return desktop.connect(opts);\n\tconst picker = (window as unknown as PickerWindow).showSaveFilePicker;\n\tif (!picker) return null;\n\tconst handle = await ask(() =>\n\t\tpicker({\n\t\t\tsuggestedName: opts.fileName,\n\t\t\ttypes: [{ description: 'Backup', accept: { 'application/zip': ['.zip'] } }]\n\t\t})\n\t);\n\tif (!handle) return null;\n\tawait opts.kv.set(HANDLE_KEY, handle);\n\treturn fromHandle(handle, opts.kv);\n}\n\n/** Prompt the user to pick an EXISTING backup file and adopt it as the\n * destination (the connect journey then reads it like any backup: password,\n * conflict, resume). Tries to raise the grant to readwrite up front so the\n * first save does not stall on a second prompt. Returns null if cancelled. */\nexport async function openExisting(opts: { kv: KV }): Promise<BackupTarget | null> {\n\tif (desktop.hasDesktopFiles()) return desktop.openExisting(opts);\n\tconst picker = (window as unknown as PickerWindow).showOpenFilePicker;\n\tif (!picker) return null;\n\tconst picked = await ask(() =>\n\t\tpicker({\n\t\t\tmultiple: false,\n\t\t\ttypes: [{ description: 'Backup', accept: { 'application/zip': ['.zip'] } }]\n\t\t})\n\t);\n\tconst handle = picked?.[0];\n\tif (!handle) return null;\n\t// The upgrade to readwrite is a COURTESY, not a condition. It can fail for a\n\t// reason that has nothing to do with the file - the open picker consumes the\n\t// transient activation a permission prompt needs, so a browser may answer\n\t// 'prompt' without ever asking anyone. Throwing the picked file away then\n\t// dropped the host back on its own screen with nothing said and nothing\n\t// changed: the user pointed at their file and the app appeared to ignore it.\n\t// So we adopt it either way. Reading works on the grant the picker gave, and\n\t// a write that cannot happen raises the store's own reconnect gate, whose\n\t// one click re-asks from inside a real gesture - the only place it can work.\n\t// Outside `ask`: a refusal here is about THIS file, never about the picker,\n\t// which has just proved it opens.\n\ttry {\n\t\tawait handle.requestPermission({ mode: 'readwrite' });\n\t} catch {\n\t\t/* no prompt was possible: the reconnect gesture will ask for real */\n\t}\n\tawait opts.kv.set(HANDLE_KEY, handle);\n\treturn fromHandle(handle, opts.kv);\n}\n\n/** Rebuild the target from what a past session persisted, or null. On a desktop\n * shell that is a path and it reconnects silently; in a browser it is a handle\n * and the first write may still ask for the permission back. */\nexport async function fromSession(opts: { kv: KV }): Promise<BackupTarget | null> {\n\tif (desktop.hasDesktopFiles()) return desktop.fromSession(opts);\n\tconst handle = await opts.kv.get<FileHandle>(HANDLE_KEY);\n\treturn handle ? fromHandle(handle, opts.kv) : null;\n}\n"]}
|