{"_id":"@eidos.space/graft-remote","_rev":"6-ecf63230bf8f9fda998b1cf25a399f37","name":"@eidos.space/graft-remote","dist-tags":{"latest":"0.2.4"},"versions":{"0.1.0":{"name":"@eidos.space/graft-remote","version":"0.1.0","license":"MIT","_id":"@eidos.space/graft-remote@0.1.0","maintainers":[{"name":"agodrich","email":"dreama9ain@gmail.com"}],"homepage":"https://github.com/eidos-space/graft","bugs":{"url":"https://github.com/eidos-space/graft/issues"},"dist":{"shasum":"f813266605b1b8a73e640384602c34fab83b4a5e","tarball":"https://registry.npmjs.org/@eidos.space/graft-remote/-/graft-remote-0.1.0.tgz","fileCount":19,"integrity":"sha512-Js84WFgutZ0h9vu1YAZYqD+F0N2H1JbJgV6pmciiQ1tBzaHYeIy3okKmxhznqG1mTPr89XHeVu1sFKK4nmob1Q==","signatures":[{"sig":"MEQCIFys07AQbQkhyj6aLqffPfrHHwRPiaUQlv4R+w6d8lYQAiAbaRZ0HCDV8OUeHGUad6M/WMn61+5aUncJDiGyytPKiQ==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@eidos.space%2fgraft-remote@0.1.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":94026},"main":"./dist/index.js","type":"module","_from":"file:/home/runner/work/graft/graft/release-assets/graft-remote/eidos.space-graft-remote-0.1.0.tgz","types":"./dist/index.d.ts","engines":{"node":">=20"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"scripts":{"test":"vitest run --pool=threads --maxWorkers=1","build":"node -e \"require('node:fs').rmSync('dist', { recursive: true, force: true })\" && tsc -p tsconfig.build.json","check":"tsc -p tsconfig.json --noEmit"},"_npmUser":{"name":"agodrich","email":"dreama9ain@gmail.com"},"_resolved":"/home/runner/work/graft/graft/release-assets/graft-remote/eidos.space-graft-remote-0.1.0.tgz","_integrity":"sha512-Js84WFgutZ0h9vu1YAZYqD+F0N2H1JbJgV6pmciiQ1tBzaHYeIy3okKmxhznqG1mTPr89XHeVu1sFKK4nmob1Q==","repository":{"url":"git+https://github.com/eidos-space/graft.git","type":"git","directory":"packages/graft-remote"},"_npmVersion":"11.16.0","description":"Framework-neutral types and protocol engine for Graft remote services","directories":{},"sideEffects":false,"_nodeVersion":"24.18.0","publishConfig":{"access":"public","provenance":true},"_hasShrinkwrap":false,"devDependencies":{"vitest":"4.1.10","typescript":"7.0.2"},"_npmOperationalInternal":{"tmp":"tmp/graft-remote_0.1.0_1785352808017_0.05100620934344069","host":"s3://npm-registry-packages-npm-production"}},"0.2.0":{"name":"@eidos.space/graft-remote","version":"0.2.0","license":"MIT","_id":"@eidos.space/graft-remote@0.2.0","maintainers":[{"name":"agodrich","email":"dreama9ain@gmail.com"}],"homepage":"https://github.com/eidos-space/graft","bugs":{"url":"https://github.com/eidos-space/graft/issues"},"dist":{"shasum":"5b59f7ac673f16c4395d707acbc830b9d5fcc2d0","tarball":"https://registry.npmjs.org/@eidos.space/graft-remote/-/graft-remote-0.2.0.tgz","fileCount":19,"integrity":"sha512-O1ynq3Ra52jMbgoOVd0dqSs09f9/3I8twqbbKiFBVkQX/njOA6ud+9V/5XHf0CIIfB6Eo6arJz28gDtIWNU1Bw==","signatures":[{"sig":"MEUCIF0w4I2MuY0rxPhQHIVGFL/IjtnTuYaHeOhvk9endtTUAiEAvGWOZKNSD0fD2K+SG7Eb38Y6nuaygo2GNVLpM2c+9lc=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@eidos.space%2fgraft-remote@0.2.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":112060},"main":"./dist/index.js","type":"module","_from":"file:/home/runner/work/graft/graft/release-assets/graft-remote/eidos.space-graft-remote-0.2.0.tgz","types":"./dist/index.d.ts","engines":{"node":">=20"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"scripts":{"test":"vitest run --pool=threads --maxWorkers=1","build":"node -e \"require('node:fs').rmSync('dist', { recursive: true, force: true })\" && tsc -p tsconfig.build.json","check":"tsc -p tsconfig.json --noEmit"},"_npmUser":{"name":"agodrich","email":"dreama9ain@gmail.com"},"_resolved":"/home/runner/work/graft/graft/release-assets/graft-remote/eidos.space-graft-remote-0.2.0.tgz","_integrity":"sha512-O1ynq3Ra52jMbgoOVd0dqSs09f9/3I8twqbbKiFBVkQX/njOA6ud+9V/5XHf0CIIfB6Eo6arJz28gDtIWNU1Bw==","repository":{"url":"git+https://github.com/eidos-space/graft.git","type":"git","directory":"packages/graft-remote"},"_npmVersion":"11.16.0","description":"Framework-neutral types and protocol engine for Graft remote services","directories":{},"sideEffects":false,"_nodeVersion":"24.18.0","publishConfig":{"access":"public","provenance":true},"_hasShrinkwrap":false,"devDependencies":{"vitest":"4.1.10","typescript":"7.0.2"},"_npmOperationalInternal":{"tmp":"tmp/graft-remote_0.2.0_1785411160378_0.8015354879728203","host":"s3://npm-registry-packages-npm-production"}},"0.2.1":{"name":"@eidos.space/graft-remote","version":"0.2.1","license":"MIT","_id":"@eidos.space/graft-remote@0.2.1","maintainers":[{"name":"agodrich","email":"dreama9ain@gmail.com"}],"homepage":"https://github.com/eidos-space/graft","bugs":{"url":"https://github.com/eidos-space/graft/issues"},"dist":{"shasum":"c429c4198be12b0ea3004feb2679d8512873078f","tarball":"https://registry.npmjs.org/@eidos.space/graft-remote/-/graft-remote-0.2.1.tgz","fileCount":19,"integrity":"sha512-Lnh/PmhBbhoI02/+gi605qZQdNA6e222iwtKJz9P0sECs8UH9TofXtu0nOTcyE5iUMBeJqj9WMy2WjK2flO96g==","signatures":[{"sig":"MEUCIQCBESGMhnlhj27Juj0X4D0agzU0hyQw/vJ269oOtCpaqwIgCVAaZybCYBqu+3Xfq82PlmGEuhwPnjjWYAJXl3B2RSw=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@eidos.space%2fgraft-remote@0.2.1","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":131855},"main":"./dist/index.js","type":"module","_from":"file:/home/runner/work/graft/graft/release-assets/graft-remote/eidos.space-graft-remote-0.2.1.tgz","types":"./dist/index.d.ts","engines":{"node":">=20"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"scripts":{"test":"vitest run --pool=threads --maxWorkers=1","build":"node -e \"require('node:fs').rmSync('dist', { recursive: true, force: true })\" && tsc -p tsconfig.build.json","check":"tsc -p tsconfig.json --noEmit"},"_npmUser":{"name":"agodrich","email":"dreama9ain@gmail.com"},"_resolved":"/home/runner/work/graft/graft/release-assets/graft-remote/eidos.space-graft-remote-0.2.1.tgz","_integrity":"sha512-Lnh/PmhBbhoI02/+gi605qZQdNA6e222iwtKJz9P0sECs8UH9TofXtu0nOTcyE5iUMBeJqj9WMy2WjK2flO96g==","repository":{"url":"git+https://github.com/eidos-space/graft.git","type":"git","directory":"packages/graft-remote"},"_npmVersion":"11.16.0","description":"Framework-neutral types and protocol engine for Graft remote services","directories":{},"sideEffects":false,"_nodeVersion":"24.18.0","publishConfig":{"access":"public","provenance":true},"_hasShrinkwrap":false,"devDependencies":{"vitest":"4.1.10","typescript":"7.0.2"},"_npmOperationalInternal":{"tmp":"tmp/graft-remote_0.2.1_1785654977406_0.8379424892128542","host":"s3://npm-registry-packages-npm-production"}},"0.2.2":{"name":"@eidos.space/graft-remote","version":"0.2.2","license":"MIT","_id":"@eidos.space/graft-remote@0.2.2","maintainers":[{"name":"agodrich","email":"dreama9ain@gmail.com"}],"homepage":"https://github.com/eidos-space/graft","bugs":{"url":"https://github.com/eidos-space/graft/issues"},"dist":{"shasum":"a9bd70b3153f0271d25f561e6b9a7e85fe8c3d1a","tarball":"https://registry.npmjs.org/@eidos.space/graft-remote/-/graft-remote-0.2.2.tgz","fileCount":19,"integrity":"sha512-1s0/yVfUwbli4ZkDF13nz9e30Gq/+HbmKO9VAsZu/FVbLp3WJjrb10FyVi6zK8Hd5ebGkMj6rGaxAwlBHanfkg==","signatures":[{"sig":"MEUCIETJIDwTPKqmqjUTqPCgWETIpt1s3PXTDLkMZWCljH9CAiEA2JUoFZTv5OBdd0D94J8BKGC0zsPJThgKJEjlN6TQP6c=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@eidos.space%2fgraft-remote@0.2.2","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":137649},"main":"./dist/index.js","type":"module","_from":"file:/home/runner/work/graft/graft/release-assets/graft-remote/eidos.space-graft-remote-0.2.2.tgz","types":"./dist/index.d.ts","engines":{"node":">=20"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"scripts":{"test":"vitest run --pool=threads --maxWorkers=1","build":"node -e \"require('node:fs').rmSync('dist', { recursive: true, force: true })\" && tsc -p tsconfig.build.json","check":"tsc -p tsconfig.json --noEmit"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:0347efc0-4ed1-4347-aa21-3d2f7c5b870a"}},"_resolved":"/home/runner/work/graft/graft/release-assets/graft-remote/eidos.space-graft-remote-0.2.2.tgz","_integrity":"sha512-1s0/yVfUwbli4ZkDF13nz9e30Gq/+HbmKO9VAsZu/FVbLp3WJjrb10FyVi6zK8Hd5ebGkMj6rGaxAwlBHanfkg==","repository":{"url":"git+https://github.com/eidos-space/graft.git","type":"git","directory":"packages/graft-remote"},"_npmVersion":"11.16.0","description":"Framework-neutral types and protocol engine for Graft remote services","directories":{},"sideEffects":false,"_nodeVersion":"24.18.0","publishConfig":{"access":"public","provenance":true},"_hasShrinkwrap":false,"devDependencies":{"vitest":"4.1.10","typescript":"7.0.2"},"_npmOperationalInternal":{"tmp":"tmp/graft-remote_0.2.2_1786631471063_0.17228203716263302","host":"s3://npm-registry-packages-npm-production"}},"0.2.3":{"name":"@eidos.space/graft-remote","version":"0.2.3","license":"MIT","_id":"@eidos.space/graft-remote@0.2.3","maintainers":[{"name":"agodrich","email":"dreama9ain@gmail.com"}],"homepage":"https://github.com/eidos-space/graft","bugs":{"url":"https://github.com/eidos-space/graft/issues"},"dist":{"shasum":"35d58d705042ce06a0983032b1915dd977670e94","tarball":"https://registry.npmjs.org/@eidos.space/graft-remote/-/graft-remote-0.2.3.tgz","fileCount":19,"integrity":"sha512-/o98bDen6Bg2e1q9b8iJX/xkn0KmqI13Y1L6Wc72akEaho0xLl5o15jtSPnwvRR8+JfIRnJb2RynvZINM8ujVg==","signatures":[{"sig":"MEQCICtm6nFv3iyz7TduAE7nGc1rL5sZrvvwJd/aTkGtkhMvAiACNdqkAQ+l6zgML6N5dfz/HeqzstC3jaYUAsNw7/4SIg==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@eidos.space%2fgraft-remote@0.2.3","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":161448},"main":"./dist/index.js","type":"module","_from":"file:/home/runner/work/graft/graft/release-assets/graft-remote/eidos.space-graft-remote-0.2.3.tgz","types":"./dist/index.d.ts","engines":{"node":">=20"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"scripts":{"test":"vitest run --pool=threads --maxWorkers=1","build":"node -e \"require('node:fs').rmSync('dist', { recursive: true, force: true })\" && tsc -p tsconfig.build.json","check":"tsc -p tsconfig.json --noEmit"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:0347efc0-4ed1-4347-aa21-3d2f7c5b870a"}},"_resolved":"/home/runner/work/graft/graft/release-assets/graft-remote/eidos.space-graft-remote-0.2.3.tgz","_integrity":"sha512-/o98bDen6Bg2e1q9b8iJX/xkn0KmqI13Y1L6Wc72akEaho0xLl5o15jtSPnwvRR8+JfIRnJb2RynvZINM8ujVg==","repository":{"url":"git+https://github.com/eidos-space/graft.git","type":"git","directory":"packages/graft-remote"},"_npmVersion":"11.16.0","description":"Framework-neutral types and protocol engine for Graft remote services","directories":{},"sideEffects":false,"_nodeVersion":"24.19.0","publishConfig":{"access":"public","provenance":true},"_hasShrinkwrap":false,"devDependencies":{"vitest":"4.1.10","typescript":"7.0.2"},"_npmOperationalInternal":{"tmp":"tmp/graft-remote_0.2.3_1786935921212_0.9452818260831992","host":"s3://npm-registry-packages-npm-production"}},"0.2.4":{"name":"@eidos.space/graft-remote","version":"0.2.4","description":"Framework-neutral types and protocol engine for Graft remote services","type":"module","license":"MIT","repository":{"type":"git","url":"git+https://github.com/eidos-space/graft.git","directory":"packages/graft-remote"},"homepage":"https://github.com/eidos-space/graft","sideEffects":false,"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"main":"./dist/index.js","types":"./dist/index.d.ts","devDependencies":{"typescript":"7.0.2","vitest":"4.1.10"},"engines":{"node":">=20"},"publishConfig":{"access":"public","provenance":true},"scripts":{"build":"node -e \"require('node:fs').rmSync('dist', { recursive: true, force: true })\" && tsc -p tsconfig.build.json","check":"tsc -p tsconfig.json --noEmit","test":"vitest run --pool=threads --maxWorkers=1"},"_id":"@eidos.space/graft-remote@0.2.4","bugs":{"url":"https://github.com/eidos-space/graft/issues"},"_integrity":"sha512-2n2J/fNooUy1WYPV1CARV0V8rrE/GG1ffk8P3crNPrZ7K5dvEkRzsE1WoPJ1RPD5eI4YJdbSMizuNXrWqT+ueQ==","_resolved":"/home/runner/work/graft/graft/release-assets/graft-remote/eidos.space-graft-remote-0.2.4.tgz","_from":"file:/home/runner/work/graft/graft/release-assets/graft-remote/eidos.space-graft-remote-0.2.4.tgz","_nodeVersion":"24.20.0","_npmVersion":"11.16.0","dist":{"integrity":"sha512-2n2J/fNooUy1WYPV1CARV0V8rrE/GG1ffk8P3crNPrZ7K5dvEkRzsE1WoPJ1RPD5eI4YJdbSMizuNXrWqT+ueQ==","shasum":"cfe2777180f1c61ec11ac8214a2bcb30cc17983e","tarball":"https://registry.npmjs.org/@eidos.space/graft-remote/-/graft-remote-0.2.4.tgz","fileCount":19,"unpackedSize":163942,"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@eidos.space%2fgraft-remote@0.2.4","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIF4G1gJf3viCA4cjhia3znuiFQ8ZdoO20hCGO2uFhy9dAiAhybLvdL358GFGV6Ocmku2GCDwsiYkXOUGJxO2RqUmSQ=="}]},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:0347efc0-4ed1-4347-aa21-3d2f7c5b870a"}},"directories":{},"maintainers":[{"name":"agodrich","email":"dreama9ain@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/graft-remote_0.2.4_1788862751843_0.8208354614968056"},"_hasShrinkwrap":false}},"time":{"created":"2026-07-29T19:20:07.790Z","modified":"2026-09-08T10:19:12.315Z","0.1.0":"2026-07-29T19:20:08.167Z","0.2.0":"2026-07-30T11:32:40.538Z","0.2.1":"2026-08-02T07:16:17.547Z","0.2.2":"2026-08-13T14:31:11.250Z","0.2.3":"2026-08-17T03:05:21.355Z","0.2.4":"2026-09-08T10:19:11.989Z"},"bugs":{"url":"https://github.com/eidos-space/graft/issues"},"license":"MIT","homepage":"https://github.com/eidos-space/graft","repository":{"type":"git","url":"git+https://github.com/eidos-space/graft.git","directory":"packages/graft-remote"},"description":"Framework-neutral types and protocol engine for Graft remote services","maintainers":[{"name":"agodrich","email":"dreama9ain@gmail.com"}],"readme":"# `@eidos.space/graft-remote`\n\nFramework-neutral types and protocol engine for the Graft remote service\nprotocol.\n\nThis package owns protocol negotiation, validation, range reads, cursor\npagination, mutation semantics, error responses, and the repository backend\ncontract. It depends only on standard Fetch API types. HTTP framework routing\nbelongs in a separate adapter.\n\n## Install\n\n```bash\nnpm install @eidos.space/graft-remote\n```\n\nUse `@eidos.space/graft-remote-hono` when the host application uses Hono, and\n`@eidos.space/graft-remote-cloudflare` for the reusable R2/Durable Object\nbackend.\n\n## Create a transport adapter\n\nA router extracts route parameters and passes them, the standard `Request`, and\nits own framework or runtime context to the protocol engine:\n\n```ts\nimport {\n  GraftProtocolError,\n  createGraftRemoteHandler,\n  type GraftRouteParameters,\n} from \"@eidos.space/graft-remote\";\n\ninterface RuntimeContext {\n  repositories: RepositoryStore;\n}\n\ninterface User {\n  id: string;\n}\n\nconst handleRemote = createGraftRemoteHandler<RuntimeContext, User>({\n  limits: {\n    maxRequestBytes: 64 * 1024 * 1024,\n    multipartPartBytes: 16 * 1024 * 1024,\n  },\n  async authenticate({ request }) {\n    return await authenticateRequest(request);\n  },\n\n  async authorize({ action, principal, repository }) {\n    if (\n      principal === undefined ||\n      !(await canAccess(principal, action, repository))\n    ) {\n      throw new GraftProtocolError(\n        403,\n        \"forbidden\",\n        \"Repository access denied\",\n      );\n    }\n  },\n\n  backend({ adapterContext, repository }) {\n    return adapterContext.repositories.open(repository.id);\n  },\n});\n\nexport function dispatchRemote(\n  request: Request,\n  route: GraftRouteParameters,\n  runtime: RuntimeContext,\n): Promise<Response> {\n  return handleRemote({ request, route, adapterContext: runtime });\n}\n```\n\nThe adapter is responsible only for matching these route values:\n\n- `namespace`\n- `repository`\n- optional `operation`\n- optional slash-containing `objectPath`\n\nThe engine validates all values and returns a standard `Response`, including\nprotocol error responses.\n\n## Implement the backend\n\nImplement `GraftRepositoryBackend` for the storage system you already use:\n\n```ts\ninterface GraftRepositoryBackend {\n  head(path: string): MaybePromise<GraftObjectMetadata | null>;\n  get(path: string, range?: GraftByteRange): MaybePromise<GraftObject | null>;\n  put(path: string, value: Uint8Array<ArrayBuffer>): MaybePromise<void>;\n  delete(path: string): MaybePromise<void>;\n  putIfAbsent(\n    path: string,\n    value: Uint8Array<ArrayBuffer> | ReadableStream<Uint8Array>,\n    kind: \"transactional\" | \"immutable\",\n    options?: { contentLength?: number },\n  ): MaybePromise<boolean>;\n  compareAndSwap(\n    path: string,\n    expected: Uint8Array<ArrayBuffer> | undefined,\n    replacement: Uint8Array<ArrayBuffer>,\n  ): MaybePromise<boolean>;\n  compareAndDelete(\n    path: string,\n    expected: Uint8Array<ArrayBuffer> | undefined,\n  ): MaybePromise<boolean>;\n  list(query: GraftListQuery): MaybePromise<GraftListResult>;\n  multipart?: GraftMultipartBackend;\n}\n```\n\nBackend guarantees:\n\n- `compareAndSwap` and `compareAndDelete` are atomic.\n- `putIfAbsent` atomically creates only when the path is absent.\n- `list` returns at most `query.limit` paths, sorted by UTF-8 byte order, after\n  `query.after`, and restricted to `query.prefix`. It may also return matching\n  `entries` with object sizes so aggregate downloads can declare their exact\n  transfer length without a second metadata lookup.\n- Immutable request bodies remain streams when the adapter storage supports it.\n- `read-bundle` batches up to 256 explicit immutable reads behind one\n  authentication/authorization round and streams sorted, length-delimited\n  frames without buffering object bodies in memory.\n- `fetch-bundle` resolves one branch ref and streams only the bounded pack/index\n  set reachable after the client's `have` commit. Pack ancestry remains a hint;\n  clients still verify every content-addressed object and retain ordinary fetch\n  as the compatibility and completeness fallback.\n- `upload-bundle` lists immutable keys and streams each `get` body into one\n  clone response without buffering the repository in memory. Its exact framed\n  length is exposed through `Content-Length` and\n  `x-graft-bundle-total-bytes`, allowing clone clients to report total size,\n  percentage, and estimated time remaining before the body finishes.\n- `options.contentLength` is the exact length of a framed immutable body, such\n  as each object in a `receive-pack` or `receive-bundle` request.\n- `multipart` optionally stores one logical immutable object through resumable\n  parts. The protocol engine advertises it as `multipart-object`, validates\n  every part against `limits.multipartPartBytes`, and keeps the final object at\n  the original repository path.\n- Repository instances are isolated by `repository.id`.\n\n## Authentication and authorization\n\nThe engine does not prescribe an account system. `authenticate` returns the\nhost application's principal; `authorize` receives that principal with the\n`discover`, `read`, or `write` action, concrete operation, repository, and\noptional object path.\n\nThis supports bearer tokens, sessions, signed requests, identity-aware proxies,\nmutual TLS, or an SSH gateway without placing account or ACL formats in the\nwire protocol.\n\n`repositoryId` can map a visible namespace/name to an internal tenant ID.\nReturning `null` from `backend` reports a missing repository. `onError` can\nreport failures without taking over protocol response formatting.\n\n## Development\n\nFrom the Graft repository root:\n\n```bash\npnpm --filter @eidos.space/graft-remote check\npnpm --filter @eidos.space/graft-remote test\npnpm --filter @eidos.space/graft-remote build\n```\n","readmeFilename":"README.md"}