{"id":13410043,"url":"https://github.com/dynabloxjs/dynablox_opencloud","last_synced_at":"2025-10-20T16:24:13.842Z","repository":{"id":42577978,"uuid":"475240220","full_name":"dynabloxjs/dynablox_opencloud","owner":"dynabloxjs","description":"A Roblox OpenCloud API wrapper for Deno and NodeJS written in TypeScript.","archived":true,"fork":false,"pushed_at":"2022-12-18T06:17:39.000Z","size":309,"stargazers_count":12,"open_issues_count":0,"forks_count":2,"subscribers_count":0,"default_branch":"main","last_synced_at":"2024-10-19T04:09:22.618Z","etag":null,"topics":["api","deno","dynablox","nodejs","opencloud","rbx","roblox","roblox-api","roblox-dev"],"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/dynabloxjs.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2022-03-29T01:41:13.000Z","updated_at":"2024-07-15T19:41:46.000Z","dependencies_parsed_at":"2023-01-29T18:46:03.133Z","dependency_job_id":null,"html_url":"https://github.com/dynabloxjs/dynablox_opencloud","commit_stats":null,"previous_names":[],"tags_count":10,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dynabloxjs%2Fdynablox_opencloud","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dynabloxjs%2Fdynablox_opencloud/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dynabloxjs%2Fdynablox_opencloud/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dynabloxjs%2Fdynablox_opencloud/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dynabloxjs","download_url":"https://codeload.github.com/dynabloxjs/dynablox_opencloud/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":221481983,"owners_count":16829979,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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":["api","deno","dynablox","nodejs","opencloud","rbx","roblox","roblox-api","roblox-dev"],"created_at":"2024-07-30T20:01:04.670Z","updated_at":"2025-10-20T16:24:13.480Z","avatar_url":"https://github.com/dynabloxjs.png","language":"TypeScript","readme":"\u003e ### Active Development\n\u003e This module is currently in the initial development phase. Breaking changes may be introduced without warning before a stable 1.0.0 release. Check release notes of every release before updating.\n\n### \u003cp align=\"center\"\u003edynablox opencloud\u003c/p\u003e\n\u003cp align=\"center\"\u003e\n\u003cimg src=\"https://img.shields.io/github/license/dynabloxjs/dynablox_opencloud?style=flat-square\" /\u003e\n\u003cimg src=\"https://img.shields.io/github/v/release/dynabloxjs/dynablox_opencloud?style=flat-square\" /\u003e\n\u003cbr /\u003e\n\u003ca href=\"https://doc.deno.land/https://deno.land/x/dynablox_opencloud/mod.ts\"\u003edocs\u003c/a\u003e\n| \u003ca href=\"https://deno.land/x/dynablox_opencloud\"\u003edeno.land/x\u003c/a\u003e\n| \u003ca href=\"https://www.npmjs.com/package/@dynabloxjs/opencloud\"\u003enpm\u003c/a\u003e\n| \u003ca href=\"https://github.com/dynabloxjs/dynablox_opencloud/releases\"\u003erelease notes\u003c/a\u003e\n\u003c/p\u003e\n\nAn API wrapper for the OpenCloud Roblox API built using the Deno runtime, with support for NodeJS via transpilation.\n\n* **Compatible**: Built in TypeScript using Deno. Supported in NodeJS as a ES and CommonJS module via transpilation.\n* **API Error handling**: No matter the endpoint, errors are formatted into the same object format.\n* **Permission checked** (optional): Optional behavior to check if the current client has permissions for a resource before performing a request.\n\nThis is a stripped-down version of the original library, for Open Cloud.\n\n\u003cbr /\u003e\u003cbr /\u003e\n\n### Installation\n#### Node Installation\nSteps to install Node can be found [here](https://nodejs.org).\u003cbr /\u003e\n\nRun\n\n```\nnpm install @dynabloxjs/opencloud\n```\n\nor\n\n```\nyarn add @dynabloxjs/opencloud\n```\n\nto install. (**yarn add** requires [yarn](https://yarnpkg.com))\n\nImport it with CommonJS:\n\n```js\nconst dynablox = require(\"@dynabloxjs/opencloud\");\n```\n\nor ESModule:\n\n```js\nimport * as dynablox from \"@dynabloxjs/opencloud\";\n```\n\nFor pre-release builds:\n\nRun\n\n```\nnpm install dynabloxjs/dynablox_opencloud#node\n```\n\nor\n\n```\nyarn add dynabloxjs/dynablox_opencloud#node\n```\n\nto install the current pre-release build. (**yarn add** requires [yarn](https://yarnpkg.com))\n\n#### Deno Installation\nSteps to install Deno can be found [here](https://github.com/denoland/deno_install).\n\nUnlike Node or Python, Deno modules only need to be imported via a path (and then cached).\n\nOnce you have done the necessary steps, import it:\n\n```ts\nimport * as dynablox from \"https://deno.land/x/dynablox_opencloud/mod.ts\";\n``` \n\n*NOTE*: You can also specify a version by appending `@{version}` to the module name.\n\n... and it's done! Only the `--allow-net` flag is needed for Dynablox Open Cloud, see [more information about flags in the Deno manual](https://deno.land/manual/getting_started/permissions).\n\nFor pre-release builds:\n\nReplace `https://deno.land/x/dynablox_opencloud/mod.ts` with `https://raw.githubusercontent.com/dynabloxjs/dynablox_opencloud/main/mod.ts`, or clone onto your machine and import `mod.ts` from the downloaded folder in your code.\n\n### Starting Guide\n*NOTE: If you are not using tooling, you are silly.*\n\n### All Uses (Functional Programming)\nIn `BaseClient`, there is almost no usage of OOP. All APIs on Open Cloud endpoints can be accessed via `\u003cBaseClient\u003e.services`, though with little documentation.\n\nImport `BaseClient` from the module entrypoint, either the module name (NodeJS) or mod.ts (Deno)\nConstruct a new BaseClient with either API key or other credentials. \n```typescript\nconst client = new BaseClient({\n    credentials: {\n        type: \"APIKey\",\n        value: \"APIKEYHERE\"\n    }\n})\n```\n\n### Open Cloud (API Key, OOP)\nIn `OpenCloudClient`, it is mostly object-orientated, with all methods available on `\u003cOpenCloudClient\u003e` with clear documentation, though APIs on Open Cloud endpoints are still accessible via `\u003cBaseClient\u003e.services`.\n\nImport `OpenCloudClient` from the module entrypoint, either the module name (NodeJS) or mod.ts (Deno)\nConstruct a new OpenCloudClient with your APIKey.\n```typescript\nconst client = new OpenCloudClient({\n    credentialsValue: \"APIKEYHERE\",\n})\n```\n\n#### Permission Scopes\nIt is also possible to define **scopes** to tell the client what and what it can not access. \nThis is similar to the actual Scopes system Roblox uses for OpenCloud and oAuth.\n\nBy default, all scopes are allowed.\n```typescript\nconst client = new OpenCloudClient({\n    credentialsValue: \"APIKEYHERE\",\n    scopes: [{\n        // The scope type, see TSDoc for more options.\n        scopeType: \"universe-datastores.objects\",\n        // Allows for universe ID 13058 and datastoreName.\n        // a Target part can also be \"*\" to allow all. Some target parts may be optional.\n        targetParts: [\"13058\", \"datastoreName\"],\n        // Allows for reading entry values in the DataStore.\n        operations: [\"read\"],\n        // NOTE: this is optional. If set to `true`, `operations` is ignored.\n        allowAllOperations: false,\n    }]\n})\n```\n\n#### Ratelimiting\nThe OpenCloudClient also has a built-in ratelimit helper. If a ratelimit is reached, it will throw an OpenCloudClientError.\n\nYou can opt in for yielding behavior by setting `ratelimiterShouldYield` to `true`:\n```typescript\nconst client = new OpenCloudClient({\n    credentialsValue: \"APIKEYHERE\",\n    ratelimiterShouldYield: true,\n})\n```\n\nIt also exposes the Ratelimiter helper publicly, so you can have mutiple OpenCloudClients using the same ratelimit helper instance:\n```typescript\nconst client1 = new OpenCloudClient({\n    credentialsValue: \"APIKEYHERE\",\n});\n\nconst client2 = new OpenCloudClient({\n    credentialsValue: \"APIKEYHERE\",\n    ratelimiter: client1.ratelimiter,\n});\n```\n\n### Retries\nBy default, if a response is `500`, `502`, or `504` it will retry **5** times, each retry having a **250ms** timeout. It is possible to change it:\n```typescript\nconst client = new OpenCloudClient({\n    credentialsValue: \"APIKEYHERE\",\n    // Retry 5 more times on failed requests, if retrying is not wanted, set it to `0`.\n    requestRetryCount: 5,\n    // Each retry will take 250ms\n    requestRetryTimeout: 250\n});\n```\n\n#### Examples\n##### Publishing a Place\n\u003cdetails\u003e\n    \u003csummary\u003eDeno\u003c/summary\u003e\n\n```typescript\nimport { OpenCloudClient } from \"https://deno.land/x/dynablox_opencloud/mod.ts\";\n\nconst client = new OpenCloudClient({\n    credentialsValue: \"APIKEYHERE\",\n    scopes: [{\n        // Tell the client we have access to updating place data in the universe 13058, and no other universe.\n        scopeType: \"universe-places\",\n        targetParts: [\"13058\"],\n        operations: [\"write\"],\n    }],\n});\n\n// The methods have \"base\" because it doesn't actually make any HTTP requests.\nconst place = client.getBaseUniverse(13058).getBasePlace(1818);\n\nconst fileData = await Deno.readFile(\"./place.rbxl\");\n\n// Updates the content of the place for the Saved version type.\nconst placeVersion = await place.updateContents(fileData, \"Saved\");\n\nconsole.log(`Updated place to version ${placeVersion}`);\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n    \u003csummary\u003eNodeJS\u003c/summary\u003e\n\n```javascript\nconst { OpenCloudClient } = require(\"@dynabloxjs/opencloud\");\nconst fs = require(\"fs/promises\");\n\nconst client = new OpenCloudClient({\n    credentialsValue: \"APIKEYHERE\",\n    scopes: [{\n        // Tell the client we have access to updating place data in the universe 13058, and no other universe.\n        scopeType: \"universe-places\",\n        targetParts: [\"13058\"],\n        operations: [\"write\"],\n    }],\n});\n\n// The methods have \"base\" because it doesn't actually make any HTTP requests.\nconst place = client.getBaseUniverse(13058).getBasePlace(1818);\n\n(async () =\u003e {\n    const fileData = await fs.readFile(\"./place.rbxl\");\n    \n    // Updates the content of the place for the Saved version type.\n    const placeVersion = await place.updateContents(fileData, \"Saved\");\n    \n    console.log(`Updated place to version ${placeVersion}`);\n})();\n```\n\n\u003c/details\u003e\n\n##### Accessing DataStores\n\u003cdetails\u003e\n    \u003csummary\u003eDeno\u003c/summary\u003e\n\n```typescript\nimport { OpenCloudClient } from \"https://deno.land/x/dynablox_opencloud/mod.ts\";\n\nconst client = new OpenCloudClient({\n    credentialsValue: \"APIKEYHERE\",\n    scopes: [{\n        // Tell the client we have access to reading and listing DataStore objects on universe 13058 and not any other universe.\n        scopeType: \"universe-datastores.objects\",\n        targetParts: [\"13058\"],\n        operations: [\"read\", \"list\"],\n    }],\n});\n\n// The method has \"base\" because it doesn't actually make any HTTP requests.\nconst datastore = client.getBaseUniverse(13058).getStandardDataStore(\"TestStore\");\n\n// `ServicePage` has an async iterator implementation, let's use it.\nfor await (const keys of datastore.listEntries()) {\n    keys.forEach(({key}) =\u003e {\n        console.log(key);\n        if (key.startsWith(\"Player\")) {\n            const data = await datastore.getEntry(key);\n\n            console.log(`${key} data length: ${JSON.stringify(data).length}`);\n        }\n    });\n}\n\n// Or:\n// const keys = await datastore.listEntries().getCurrentPage();\n// keys.data.forEach(({key}) =\u003e ...);\n// Get more data:\n// const moreKeys = await keys.getNextPage();\n// moreKeys.data.forEach(({key}) =\u003e ...);\n```\n\u003c/details\u003e\n\n\u003cdetails\u003e\n    \u003csummary\u003eNodeJS\u003c/summary\u003e\n\n```javascript\nconst { OpenCloudClient } = require(\"@dynabloxjs/opencloud\");\n\nconst client = new OpenCloudClient({\n    credentialsValue: \"APIKEYHERE\",\n    scopes: [{\n        // Tell the client we have access to reading and listing DataStore objects on universe 13058 and not any other universe.\n        scopeType: \"universe-datastores.objects\",\n        targetParts: [\"13058\"],\n        operations: [\"read\", \"list\"],\n    }],\n});\n\n// The method has \"base\" because it doesn't actually make any HTTP requests.\nconst datastore = client.getBaseUniverse(13058).getStandardDataStore(\"TestStore\");\n\n(async () =\u003e {\n    // `ServicePage` has an async iterator implementation, let's use it.\n    for await (const keys of datastore.listEntries()) {\n        keys.forEach(({key}) =\u003e {\n            console.log(key);\n            if (key.startsWith(\"Player\")) {\n                const data = await datastore.getEntry(key);\n                \n                console.log(`${key} data length: ${JSON.stringify(data).length}`);\n            }\n        });\n    }\n\n    // Or:\n    // const keys = await datastore.listEntries().getCurrentPage();\n    // keys.data.forEach(({key}) =\u003e ...);\n    // Get more data:\n    // const moreKeys = await keys.getNextPage();\n    // moreKeys.data.forEach(({key}) =\u003e ...);\n})();\n```\n\n\u003c/details\u003e\n\n##### Posting a message to be read by MessagingService\n\u003cdetails\u003e\n    \u003csummary\u003eDeno\u003c/summary\u003e\n\n```typescript\nimport { OpenCloudClient } from \"https://deno.land/x/dynablox_opencloud/mod.ts\";\n\nconst client = new OpenCloudClient({\n    credentialsValue: \"APIKEYHERE\",\n    scopes: [{\n        // Tell the client we have access to publishing messages on universe 13058 and not any other universe.\n        scopeType: \"universe-messaging-service\",\n        targetParts: [\"13058\"],\n        operations: [\"publish\"],\n    }],\n});\n\n// The method has \"base\" because it doesn't actually make any HTTP requests.\nconst universe = client.getBaseUniverse(13058);\n\n// Post the message to the universe.\nawait universe.postMessage(\"CoolTopic\", { coolData: true });\n```\n\u003c/details\u003e\n\n\u003cdetails\u003e\n    \u003csummary\u003eNodeJS\u003c/summary\u003e\n\n```javascript\nconst { OpenCloudClient } = require(\"@dynabloxjs/opencloud\");\n\nconst client = new OpenCloudClient({\n    credentialsValue: \"APIKEYHERE\",\n    scopes: [{\n        // Tell the client we have access to publishing messages on universe 13058 and not any other universe.\n        scopeType: \"universe-messaging-service\",\n        targetParts: [\"13058\"],\n        operations: [\"publish\"],\n    }],\n});\n\n// The method has \"base\" because it doesn't actually make any HTTP requests.\nconst universe = client.getBaseUniverse(13058);\n\n(async() =\u003e {\n    // Post the message to the universe.\n    await universe.postMessage(\"CoolTopic\", { coolData: true });\n})();\n```\n\n\u003c/details\u003e\n\n## License\n[MIT License](https://github.com/dynabloxjs/dynablox_opencloud/blob/main/LICENSE)","funding_links":[],"categories":["Tools"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdynabloxjs%2Fdynablox_opencloud","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdynabloxjs%2Fdynablox_opencloud","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdynabloxjs%2Fdynablox_opencloud/lists"}