{"id":15715738,"url":"https://github.com/osaton/do-proxy","last_synced_at":"2026-02-17T16:33:56.203Z","repository":{"id":64031357,"uuid":"571012578","full_name":"osaton/do-proxy","owner":"osaton","description":"Durable Object Proxy","archived":false,"fork":false,"pushed_at":"2024-06-03T07:11:20.000Z","size":1611,"stargazers_count":2,"open_issues_count":5,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-10-25T06:36:42.919Z","etag":null,"topics":["cloudflare","cloudflare-workers","durableobject","durableobjects"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/osaton.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-11-26T21:39:42.000Z","updated_at":"2023-06-30T19:28:50.000Z","dependencies_parsed_at":"2024-03-09T12:24:39.828Z","dependency_job_id":"6e63b35a-2d2b-452d-a5ae-ff18110e423d","html_url":"https://github.com/osaton/do-proxy","commit_stats":{"total_commits":93,"total_committers":3,"mean_commits":31.0,"dds":"0.23655913978494625","last_synced_commit":"53393495337efc85683448d8c5387251922f6fce"},"previous_names":[],"tags_count":11,"template":false,"template_full_name":null,"purl":"pkg:github/osaton/do-proxy","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/osaton%2Fdo-proxy","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/osaton%2Fdo-proxy/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/osaton%2Fdo-proxy/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/osaton%2Fdo-proxy/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/osaton","download_url":"https://codeload.github.com/osaton/do-proxy/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/osaton%2Fdo-proxy/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29549796,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-17T14:33:00.708Z","status":"ssl_error","status_checked_at":"2026-02-17T14:32:58.657Z","response_time":100,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cloudflare","cloudflare-workers","durableobject","durableobjects"],"created_at":"2024-10-03T21:42:35.946Z","updated_at":"2026-02-17T16:33:51.194Z","avatar_url":"https://github.com/osaton.png","language":"TypeScript","readme":"# Durable Object Proxy (do-proxy)\n\n[![Types included](https://badgen.net/npm/types/do-proxy?style=flat-square)](https://www.npmjs.com/package/do-proxy)\n[![Bundle Size](https://badgen.net/bundlephobia/minzip/do-proxy?style=flat-square)](https://bundlephobia.com/result?p=do-proxy)\n[![Bundle Size](https://badgen.net/bundlephobia/dependency-count/do-proxy?style=flat-square)](https://bundlephobia.com/result?p=do-proxy)\n[![Version](https://img.shields.io/npm/v/do-proxy.svg?style=flat-square)](https://npmjs.com/package/do-proxy)\n\n\u003e Simple interface for accessing [Cloudflare Durable Objects](https://developers.cloudflare.com/workers/learning/using-durable-objects/)' storage and class methods.\n\nThis library handles request building, fetching and responding behind the scenes via lightweight proxy object which provides interface for accessing DO instance's storage and class methods.\n\n## Install\n\n```text\nnpm install do-proxy\n```\n\n## Examples\n\n- [Todo app](https://stackblitz.com/fork/github/osaton/do-proxy/tree/main/examples/todo-storage?file=src%2Findex.ts\u0026terminal='start-stackblitz') utilizing `storage` and `batch` methods\n- [Todo app](https://stackblitz.com/fork/github/osaton/do-proxy/tree/main/examples/todo-class?file=src%2Findex.ts\u0026terminal='start-stackblitz') extending `DOProxy` class and utilizing `class` methods\n\n## Usage briefly\n\nMake your Durable Object class methods accessible by extending the `DOProxy`.\n\n```ts\nimport { DOProxy } from 'do-proxy';\nclass MyDOClass extends DOProxy {\n  // Arguments \u0026 return values have to be JSON serialiazable\n  myClassMethod(param: string) {\n    // Do what ever you would do inside DO\n  }\n}\n```\n\nInside your Worker's `fetch` method:\n\n```ts\n// Get `DurableObjectNamespace` wrapped inside our proxy\nconst MY_DO_BINDING = MyDOClass.wrap(env.MY_DO_BINDING);\n// You can use the default namespace methods or shorthand methods `getByName` \u0026 `getById`\nconst stub = MY_DO_BINDING.getByName('name');\n\n// You can access instance's storage methods\nconst res1 = await stub.storage.get('my-store');\n// You can also access your class's methods.\nconst res2 = await stub.class.myClassMethod('foo');\n\n// Or handle both with a single fetch behind the scenes using `batch` method\nconst [res3, res4] = await stub.batch(() =\u003e [\n  stub.storage.get('my-store'),\n  stub.class.myClassMethod('foo'),\n]);\n```\n\n## Usage\n\nYou can use `DOProxy` as is for Durable Object bindings. This enables you to use [`storage`](#storage-methods) methods.\n\nHere we expect you to have DO class `Todo` bound to `TODO` inside `wrangler.toml`:\n\n```ts\nimport { DOProxy } from 'do-proxy';\nexport { DOProxy as Todo };\nexport default {\n  async fetch(req: Request, env: any) {\n    const TODO = DOProxy.wrap(env.TODO);\n    const stub = TODO.getByName('name');\n    await todo.storage.put('todo:1', 'has to be done');\n    const list = Object.fromEntries(await todo.storage.list());\n    return Response.json(list);\n  },\n};\n```\n\nOr you can extend it, which enables you to call class methods via `class` property:\n\n```ts\nimport { DOProxy } from 'do-proxy';\n\nclass Todo extends DOProxy {\n  state: DurableObjectState;\n  constructor(state: DurableObjectState) {\n    super(state);\n    this.state = state;\n  }\n  async add(todo: string) {\n    const id = Math.ceil(Math.random() * 100);\n    this.state.storage.put(`todo:${id}`, todo);\n    return id;\n  }\n\n  async get(id: number) {\n    return this.state.storage.get(`todo:${id}`);\n  }\n}\nexport default {\n  async fetch(req: Request, env: any) {\n    const stub = Todo.wrap(env.TODO).getByName('my-todos');\n    const id = await stub.class.add('has to be done');\n    const todo = await stub.class.get(id);\n    return Response.json({\n      id,\n      todo,\n    });\n  },\n};\nexport { Todo };\n```\n\nYou can also utilize the [`batch`](#batch) method which allows you to run multiple methods with one fetch request to DO instance:\n\n```ts\n// See previous example for `Todo` details\nconst [, , list] = await stub.batch(() =\u003e [\n  stub.class.add('my todo'),\n  stub.class.add('my other todo'),\n  stub.storage.list(),\n]);\n\nreturn Response.json(Object.fromEntries(list as Map\u003cstring, string\u003e));\n```\n\n## `storage` methods\n\n`DOProxy` can be used as Durable Object class as is. It gives you access to Durable Object instance's [Transactional storage API](https://developers.cloudflare.com/workers/runtime-apis/durable-objects/#transactional-storage-api) methods (excluding `transaction` which can't be proxied because of JSON serialization. See [batch method](#batch)).\n\nAvailable methods: `DurableObjectStubProxy.storage.get|put|delete|deleteAll|list|getAlarm|setAlarm|deleteAlarm|sync`\n\n## `batch` method\n\nIf you need to invoke Durable Object instance's multiple times, `DurableObjectStubProxy` has a `batch` method which allows you to run multiple method calls inside one fetch request.\n\nMethod calls passed to `batch` will be run in sequence.\n\n```ts\nconst COUNTER = Counter.wrap(env.Counter);\nconst stub = COUNTER.get(COUNTER.newUniqueId());\n\nawait stub.batch(() =\u003e [\n  stub.class.increment(),\n  stub.class.increment(),\n  stub.storage.deleteAll(),\n  stub.class.increment(),\n]); // =\u003e [1, 2, null, 1]\n```\n\n## static `wrap(binding: DurableObjectNamespace): DurableObjectNamespaceProxy`\n\nThis method return `DurableObjectNamespace` wrapped inside proxy.\nIt has all the same methods that `DurableObjectNamespace`:\n\n- `newUniqueId(options?: DurableObjectNamespaceNewUniqueIdOptions | undefined): DurableObjectId`;\n- `idFromName(name: string): DurableObjectId`\n- `idFromString(id: string): DurableObjectId`\n- `get(id: DurableObjectId): DurableObjectStubProxy`\n\nIt also has some custom shorthand methods:\n\n- `getByName(name: string): DurableObjectStubProxy`: Shorthand for `DO.get(DO.idFromName('foo'))`\n- `getByString(id: string): DurableObjectStubProxy`: Shorthand for `DO.get(DO.idFromString(hexId))`\n\n`get` Method returns `DurableObjectStubProxy` instead of `DurableObjectStub`.\n\n## `DurableObjectStubProxy` properties\n\n- `id: DurableObjectId`\n- `stub: DurableObjectStub`: The actual stub if you need access to it\n- `storage: Object`: Storage methods\n- `batch: (callback: () =\u003e Promise\u003cunknown\u003e[]) =\u003e unknown[]`\n- `class: Object|undefined`: All the class methods if `wrap` was called on an extended class\n\n## Limitations\n\nRemember that we are still doing fetch requests even if it is done in the background, so everything sent to `class` and `storage` methods must be JSON serializable.\n\n## Other libraries\n\nNot the Durable Object proxy you were looking for?\n\n- [`do-proxy`](https://github.com/fisherdarling/do-proxy) for Rust by [@fisherdarling](https://www.github.com/fisherdarling)\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fosaton%2Fdo-proxy","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fosaton%2Fdo-proxy","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fosaton%2Fdo-proxy/lists"}