From bf279539582e1113c0d134b984505260b56771aa Mon Sep 17 00:00:00 2001 From: Nathan Flurry Date: Wed, 22 Oct 2025 16:02:11 -0700 Subject: [PATCH 001/114] init rivet support --- templates/sync-rivet/.gitignore | 4 + templates/sync-rivet/LICENSE.md | 9 + templates/sync-rivet/README.md | 121 + templates/sync-rivet/arch.png | Bin 0 -> 470615 bytes .../sync-rivet/client/getBookmarkPreview.tsx | 31 + templates/sync-rivet/client/index.css | 88 + templates/sync-rivet/client/localStorage.ts | 23 + templates/sync-rivet/client/main.tsx | 23 + .../client/multiplayerAssetStore.tsx | 24 + templates/sync-rivet/client/pages/Room.tsx | 129 + templates/sync-rivet/client/pages/Root.tsx | 10 + templates/sync-rivet/client/vite-env.d.ts | 1 + templates/sync-rivet/index.html | 13 + templates/sync-rivet/package.json | 54 + templates/sync-rivet/public/favicon.ico | Bin 0 -> 15406 bytes templates/sync-rivet/server/registry.ts | 53 + templates/sync-rivet/server/server.ts | 8 + templates/sync-rivet/tsconfig.json | 27 + templates/sync-rivet/vite.config.ts | 15 + .../sync-rivet/worker-configuration.d.ts | 8202 +++++++++++++++++ yarn.lock | 471 +- 21 files changed, 9305 insertions(+), 1 deletion(-) create mode 100644 templates/sync-rivet/.gitignore create mode 100644 templates/sync-rivet/LICENSE.md create mode 100644 templates/sync-rivet/README.md create mode 100644 templates/sync-rivet/arch.png create mode 100644 templates/sync-rivet/client/getBookmarkPreview.tsx create mode 100644 templates/sync-rivet/client/index.css create mode 100644 templates/sync-rivet/client/localStorage.ts create mode 100644 templates/sync-rivet/client/main.tsx create mode 100644 templates/sync-rivet/client/multiplayerAssetStore.tsx create mode 100644 templates/sync-rivet/client/pages/Room.tsx create mode 100644 templates/sync-rivet/client/pages/Root.tsx create mode 100644 templates/sync-rivet/client/vite-env.d.ts create mode 100644 templates/sync-rivet/index.html create mode 100644 templates/sync-rivet/package.json create mode 100644 templates/sync-rivet/public/favicon.ico create mode 100644 templates/sync-rivet/server/registry.ts create mode 100644 templates/sync-rivet/server/server.ts create mode 100644 templates/sync-rivet/tsconfig.json create mode 100644 templates/sync-rivet/vite.config.ts create mode 100644 templates/sync-rivet/worker-configuration.d.ts diff --git a/templates/sync-rivet/.gitignore b/templates/sync-rivet/.gitignore new file mode 100644 index 000000000000..ce782f7dc934 --- /dev/null +++ b/templates/sync-rivet/.gitignore @@ -0,0 +1,4 @@ +/*/node_modules +node_modules +.yarn/ +dist/ diff --git a/templates/sync-rivet/LICENSE.md b/templates/sync-rivet/LICENSE.md new file mode 100644 index 000000000000..7de4c61fe721 --- /dev/null +++ b/templates/sync-rivet/LICENSE.md @@ -0,0 +1,9 @@ +MIT License + +Copyright (c) 2024 tldraw Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/templates/sync-rivet/README.md b/templates/sync-rivet/README.md new file mode 100644 index 000000000000..ee9ea3ff6a75 --- /dev/null +++ b/templates/sync-rivet/README.md @@ -0,0 +1,121 @@ +# tldraw sync server + +This is a production-ready backend for [tldraw sync](https://tldraw.dev/docs/sync). + +- Your client-side tldraw-based app can be served from anywhere you want. +- This backend uses [Cloudflare Workers](https://developers.cloudflare.com/workers/), and will need + to be deployed to your own Cloudflare account. +- Each whiteboard is synced via + [WebSockets](https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API) to a [Cloudflare + Durable Object](https://developers.cloudflare.com/durable-objects/). +- Whiteboards and any uploaded images/videos are stored in a [Cloudflare + R2](https://developers.cloudflare.com/r2/) bucket. +- Although unrelated to tldraw sync, this server also includes a component to fetch link previews + for URLs added to the canvas. + This is a minimal setup of the same system that powers multiplayer collaboration for hundreds of + thousands of rooms & users on www.tldraw.com. Because durable objects effectively create a mini + server instance for every single active room, we've never needed to worry about scale. Cloudflare + handles the tricky infrastructure work of ensuring there's only ever one instance of each room, and + making sure that every user gets connected to that instance. We've found that with this approach, + each room is able to handle about 50 simultaneous collaborators. + +## Overview + +[![architecture](./arch.png)](https://www.tldraw.com/ro/Yb_QHJFP9syPZq1YrV3YR?v=-255,-148,2025,1265&p=page) + +When a user opens a room, they connect via Workers to a durable object. Each durable object is like +its own miniature server. There's only ever one for each room, and all the users of that room +connect to it. When a user makes a change to the drawing, it's sent via a websocket connection to +the durable object for that room. The durable object applies the change to its in-memory copy of the +document, and broadcasts the change via websockets to all other connected clients. On a regular +schedule, the durable object persists its contents to an R2 bucket. When the last client leaves the +room, the durable object will shut down. + +Static assets like images and videos are too big to be synced via websockets and a durable object. +Instead, they're uploaded to workers which store them in the same R2 bucket as the rooms. When +they're downloaded, they're cached on cloudflare's edge network to reduce costs and make serving +them faster. + +## Development + +To install dependencies, run `yarn`. To start a local development server, run `yarn dev`. This will +start a [`vite`](https://vitejs.dev/) dev server running both your application frontend, and the +cloudflare workers backend via the [cloudflare vite +plugin](https://developers.cloudflare.com/workers/vite-plugin/). The app & server should now be +running at http://localhost:5137. + +The backend worker is under [`worker`](./worker/), and is split across several files: + +- **[`worker/worker.ts`](./worker/worker.ts):** the main entrypoint to the worker, defining each + route available. +- **[`worker/TldrawDurableObject.ts`](./worker/TldrawDurableObject.ts):** the sync durable object. + An instance of this is created for every active room. This exposes a + [`TLSocketRoom`](https://tldraw.dev/reference/sync-core/TLSocketRoom) over websockets, and + periodically saves room data to R2. +- **[`worker/assetUploads.ts`](./worker/assetUploads.ts):** uploads, downloads, and caching for + static assets like images and videos. +- **[`worker/bookmarkUnfurling.ts`](./worker/bookmarkUnfurling.ts):** extract URL metadata for bookmark shapes. + +The frontend client is under [`client`](./client): + +- **[`client/App.tsx`](./client/App.tsx):** the main client `` component. This connects our + sync backend to the `` component, wiring in assets and bookmark previews. +- **[`client/multiplayerAssetStore.tsx`](./client/multiplayerAssetStore.tsx):** how does the client + upload and retrieve assets like images & videos from the worker? +- **[`client/getBookmarkPreview.tsx`](./client/getBookmarkPreview.tsx):** how does the client fetch + bookmark previews from the worker? + + ## Custom shapes + +To add support for custom shapes, see the [tldraw sync custom shapes docs](https://tldraw.dev/docs/sync#Custom-shapes--bindings). + +## Adding cloudflare to your own repo + +If you already have an app using tldraw and want to use the system in this repo, you can copy and +paste the relevant parts to your own app. + +To add the server to your own app, copy the contents of the [`worker`](./worker/) folder and +[`./wrangler.toml`](./wrangler.toml) into your app. Add the dependencies from +[`package.json`](./package.json). You can run the worker using `wrangler dev` in the same folder as +`./wrangler.toml`. + +To point your existing client at the server defined in this repo, copy +[`client/multiplayerAssetStore.tsx`](./client/multiplayerAssetStore.tsx) and +[`client/getBookmarkPreview.tsx`](./client/getBookmarkPreview.tsx) into your app. Then, adapt the +code from [`client/App.tsx`](./client/App.tsx) to your own app. Adapt the `/api/` URLs used in each +of these files to point at your new `wrangler dev` server. + +## Deployment + +To deploy this example, you'll need to create a cloudflare account and create an R2 bucket to store +your data. Update `bucket_name = 'tldraw-content'` in [`wrangler.toml`](./wrangler.toml) with the +name of your new bucket. + +To actually deploy the app, first create a production build using `yarn build`. Then, run `yarn +wrangler deploy`. This will deploy the backend worker along with the frontend app to cloudflare. +This should give you a workers.dev URL, but you can also [configure a custom +domain](https://developers.cloudflare.com/workers/configuration/routing/custom-domains/). + +## License + +This project is provided under the MIT license found [here](https://github.com/tldraw/tldraw-sync-cloudflare/blob/main/LICENSE.md). The tldraw SDK is provided under the [tldraw license](https://github.com/tldraw/tldraw/blob/main/LICENSE.md). + +## Trademarks + +Copyright (c) 2024-present tldraw Inc. The tldraw name and logo are trademarks of tldraw. Please see our [trademark guidelines](https://github.com/tldraw/tldraw/blob/main/TRADEMARKS.md) for info on acceptable usage. + +## Distributions + +You can find tldraw on npm [here](https://www.npmjs.com/package/@tldraw/tldraw?activeTab=versions). + +## Contribution + +Please see our [contributing guide](https://github.com/tldraw/tldraw/blob/main/CONTRIBUTING.md). Found a bug? Please [submit an issue](https://github.com/tldraw/tldraw/issues/new). + +## Community + +Have questions, comments or feedback? [Join our discord](https://discord.tldraw.com/?utm_source=github&utm_medium=readme&utm_campaign=sociallink). For the latest news and release notes, visit [tldraw.dev](https://tldraw.dev). + +## Contact + +Find us on Twitter/X at [@tldraw](https://twitter.com/tldraw). diff --git a/templates/sync-rivet/arch.png b/templates/sync-rivet/arch.png new file mode 100644 index 0000000000000000000000000000000000000000..25c718f7c4af73b990f48fd681aeb4d3fdbfdf7a GIT binary patch literal 470615 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 m4HN;E+%YGnf62>mDS}!_=pZ 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 + + ) + } + + return +} + +function ConnectedRoom({ roomId, roomUri }: { roomId: string; roomUri: string }) { + const store = useSync({ + uri: roomUri, + assets: multiplayerAssetStore, + }) + + return ( + + { + editor.registerExternalAssetHandler('url', getBookmarkPreview) + }} + /> + + ) +} + +function RoomWrapper({ children, roomId }: { children: ReactNode; roomId?: string }) { + const [didCopy, setDidCopy] = useState(false) + + useEffect(() => { + if (!didCopy) return + const timeout = setTimeout(() => setDidCopy(false), 3000) + return () => clearTimeout(timeout) + }, [didCopy]) + + return ( +
+
+ +
{roomId}
+ +
+
{children}
+
+ ) +} + +function WifiIcon() { + return ( + + + + ) +} diff --git a/templates/sync-rivet/client/pages/Root.tsx b/templates/sync-rivet/client/pages/Root.tsx new file mode 100644 index 000000000000..5a48f3620ac0 --- /dev/null +++ b/templates/sync-rivet/client/pages/Root.tsx @@ -0,0 +1,10 @@ +import { Navigate } from 'react-router-dom' +import { uniqueId } from 'tldraw' +import { getLocalStorageItem, setLocalStorageItem } from '../localStorage' + +const myLocalRoomId = getLocalStorageItem('my-local-room-id') ?? 'test-room-' + uniqueId() +setLocalStorageItem('my-local-room-id', myLocalRoomId) + +export function Root() { + return +} diff --git a/templates/sync-rivet/client/vite-env.d.ts b/templates/sync-rivet/client/vite-env.d.ts new file mode 100644 index 000000000000..11f02fe2a006 --- /dev/null +++ b/templates/sync-rivet/client/vite-env.d.ts @@ -0,0 +1 @@ +/// diff --git a/templates/sync-rivet/index.html b/templates/sync-rivet/index.html new file mode 100644 index 000000000000..7e7c45fd9f74 --- /dev/null +++ b/templates/sync-rivet/index.html @@ -0,0 +1,13 @@ + + + + + + + tldraw multiplayer template + + +
+ + + diff --git a/templates/sync-rivet/package.json b/templates/sync-rivet/package.json new file mode 100644 index 000000000000..21f75a7d3ddb --- /dev/null +++ b/templates/sync-rivet/package.json @@ -0,0 +1,54 @@ +{ + "name": "tldraw-sync-rivet", + "private": true, + "version": "0.0.0", + "author": { + "name": "tldraw GB Ltd.", + "email": "hello@tldraw.com" + }, + "homepage": "https://tldraw.dev", + "license": "MIT", + "type": "module", + "tldraw_template": { + "repo": "tldraw/tldraw-sync-rivet", + "cli": { + "name": "Multiplayer", + "description": "Real-time multiplayer with a self-hosted backend.", + "shortDescription": "Real-time multiplayer.", + "order": 2 + }, + "scripts": { + "lint": null + } + }, + "scripts": { + "dev": "concurrently \"vite\" \"tsx --watch server/server.ts\" --names \"vite,server\" --prefix-colors \"blue,green\"", + "build": "tsc && vite build", + "lint": "yarn run -T tsx ../../internal/scripts/lint.ts", + "preview": "vite preview" + }, + "dependencies": { + "@hono/node-server": "^1.19.5", + "@hono/node-ws": "^1.2.0", + "@rivetkit/react": "https://pkg.pr.new/rivet-dev/rivet/@rivetkit/react@ea8ef90", + "@tldraw/sync": "workspace:*", + "@tldraw/sync-core": "workspace:*", + "@tldraw/tlschema": "workspace:*", + "itty-router": "^5.0.18", + "lodash.throttle": "^4.1.1", + "react": "^18.3.1", + "react-dom": "^18.3.1", + "react-router-dom": "^6.28.2", + "rivetkit": "https://pkg.pr.new/rivet-dev/rivet/rivetkit@ea8ef90", + "tldraw": "workspace:*" + }, + "devDependencies": { + "@types/lodash.throttle": "^4.1.9", + "@types/react": "^18.3.18", + "@types/react-dom": "^18.3.5", + "@vitejs/plugin-react-swc": "^3.10.2", + "concurrently": "^9.1.2", + "typescript": "^5.8.3", + "vite": "^7.0.1" + } +} diff --git a/templates/sync-rivet/public/favicon.ico b/templates/sync-rivet/public/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..05e2571c73e907bfc2ca81f2e2f3fb9d8e0434f8 GIT binary patch literal 15406 zcmeI2+lx(69LLwpP$M!!)Z{Ww#x=?So@#6L%CGkZ501`?Pa)~4_ zE=ev=C=YTS2?>eZFEiuwJ#*Hy)uB0SroGoP`&XaV+IyYf`hC}LpM6<-ZDWc|i778P zlo_+Cmod|gF_}#J_P7DY9AIB{b*_DkG1mthGmhWjf=By)ioDj=*0vVDLZS8r2l;+3 z)G_k=uJ}f}$y6FI`b>{cG?E#~{$HD&zK4V}C zNK0tejNs8w4R4`P+ZV~-xk8=!y<*OX#o%)MaqE|<%pOw^G9Qx?0%W*m=%4yL3I0skWBgOZ${zpr=-K#F zV~jt|#7U4EF6T?(hS6v0sa3r!En%A zU@ydJ+wFO0OM<)1C0sR6wsCDqN6TG1bMULRacxN->m2%VbvcV;aU^yb+YekjbM(84 z-)dM7U3r(_82-O;OL7jN*h$a78WTK{OLPtqe;H^_9M`c>tflt+?a8IylkkexG(jic zlk_2Pb)f6t2k_P2BTO3Wp$|jTe@xmpg4#kcX_aPauYq?Eno09aI2xMph+b(A@m;kY zg0#nVZM8AGvkX~#cjh7O%byJB{&yZOgUdP)Zi(71q8C9a%!3Qi0-@Lygl6yUx%+!1 z+j<8T(zW6edWTBCjQS|J3!&H#gzkjW_7P;qFqiG`p$q_>nmboU^p~)GI1v4x(5d-j zmDR73?HTY5e75I^)4XpGWYHx4>7^y7mI-cn4&)=kl-jK_`6`kFJZr*Eso& zw!Yx=JM}~8>z7}B_W$3X_G93y={}{;pz<1R6>!s6@#uOA6Y`2@Cv6Ks_XeL$$6#1= z3~U#}9B2mLP0wm~Uf=4hQZoy#uY9>+CaJsU5AKjys}1N%y0KlpAh5ZDCSc?_klJtIKRpg$o5 z`-sTfa0E0TcnH4FTacJq56nPoz+;y7(AQ6o2AqFs*Bbo00LLKBHK1=Gg8hCYcW>7i f>OtS8=-UooO>3LdSO* { + return { + room: undefined as TLSocketRoom | undefined, + }; + }, + actions: { + ping: async () => { + return { status: "ok" }; + }, + }, + onWebSocket: async (c, websocket: UniversalWebSocket, { request }) => { + const url = new URL(request.url); + const sessionId = url.searchParams.get("sessionId"); + + if (!sessionId) { + websocket.close(1008, "Missing sessionId"); + return; + } + + if (!c.vars.room) { + const initialSnapshot = c.state.snapshot || undefined; + c.vars.room = new TLSocketRoom({ + schema, + initialSnapshot, + }); + } + + c.vars.room.handleSocketConnect({ + sessionId, + socket: websocket, + }); + }, +}); + +export const registry = setup({ + use: { tldrawRoom }, +}); diff --git a/templates/sync-rivet/server/server.ts b/templates/sync-rivet/server/server.ts new file mode 100644 index 000000000000..b51ac47fe07e --- /dev/null +++ b/templates/sync-rivet/server/server.ts @@ -0,0 +1,8 @@ +import { registry } from "./registry"; + +registry.start({ + cors: { + origin: "http://localhost:5173", + credentials: true, + }, +}); diff --git a/templates/sync-rivet/tsconfig.json b/templates/sync-rivet/tsconfig.json new file mode 100644 index 000000000000..4e0b9a05cdbf --- /dev/null +++ b/templates/sync-rivet/tsconfig.json @@ -0,0 +1,27 @@ +{ + "compilerOptions": { + "target": "ES2020", + "useDefineForClassFields": true, + "lib": ["DOM", "DOM.Iterable", "ES2022"], + "module": "ESNext", + "skipLibCheck": true, + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "resolveJsonModule": true, + "isolatedModules": true, + "noEmit": true, + "jsx": "react-jsx", + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true, + "types": ["vite/client", "./worker-configuration.d.ts"] + }, + "include": ["client", "server", "worker", "vite.config.ts"], + "references": [ + { "path": "../../packages/sync" }, + { "path": "../../packages/sync-core" }, + { "path": "../../packages/tldraw" }, + { "path": "../../packages/tlschema" } + ] +} diff --git a/templates/sync-rivet/vite.config.ts b/templates/sync-rivet/vite.config.ts new file mode 100644 index 000000000000..2d78a06c414f --- /dev/null +++ b/templates/sync-rivet/vite.config.ts @@ -0,0 +1,15 @@ +import react from '@vitejs/plugin-react-swc' +import { defineConfig } from 'vite' + +// https://vitejs.dev/config/ +export default defineConfig(() => { + return { + plugins: [ + react( + /* EXCLUDE_FROM_TEMPLATE_EXPORT_START */ + { tsDecorators: true } + /* EXCLUDE_FROM_TEMPLATE_EXPORT_END */ + ), + ], + } +}) diff --git a/templates/sync-rivet/worker-configuration.d.ts b/templates/sync-rivet/worker-configuration.d.ts new file mode 100644 index 000000000000..dc8c7482af0f --- /dev/null +++ b/templates/sync-rivet/worker-configuration.d.ts @@ -0,0 +1,8202 @@ +/* eslint-disable */ +// Generated by Wrangler by running `wrangler types` (hash: d45bc36a51ae49551e7e1fdffb2538b0) +// Runtime types generated with workerd@1.20250617.0 2025-05-08 nodejs_compat +declare namespace Cloudflare { + interface Env { + TLDRAW_DURABLE_OBJECT: DurableObjectNamespace + TLDRAW_BUCKET: R2Bucket + } +} +interface Env extends Cloudflare.Env {} + +// Begin runtime types +/*! ***************************************************************************** +Copyright (c) Cloudflare. All rights reserved. +Copyright (c) Microsoft Corporation. All rights reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); you may not use +this file except in compliance with the License. You may obtain a copy of the +License at http://www.apache.org/licenses/LICENSE-2.0 +THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED +WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, +MERCHANTABLITY OR NON-INFRINGEMENT. +See the Apache Version 2.0 License for specific language governing permissions +and limitations under the License. +***************************************************************************** */ +/* eslint-disable */ +// noinspection JSUnusedGlobalSymbols +declare var onmessage: never +/** + * An abnormal event (called an exception) which occurs as a result of calling a method or accessing a property of a web API. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/DOMException) + */ +declare class DOMException extends Error { + constructor(message?: string, name?: string) + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/DOMException/message) */ + readonly message: string + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/DOMException/name) */ + readonly name: string + /** + * @deprecated + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/DOMException/code) + */ + readonly code: number + static readonly INDEX_SIZE_ERR: number + static readonly DOMSTRING_SIZE_ERR: number + static readonly HIERARCHY_REQUEST_ERR: number + static readonly WRONG_DOCUMENT_ERR: number + static readonly INVALID_CHARACTER_ERR: number + static readonly NO_DATA_ALLOWED_ERR: number + static readonly NO_MODIFICATION_ALLOWED_ERR: number + static readonly NOT_FOUND_ERR: number + static readonly NOT_SUPPORTED_ERR: number + static readonly INUSE_ATTRIBUTE_ERR: number + static readonly INVALID_STATE_ERR: number + static readonly SYNTAX_ERR: number + static readonly INVALID_MODIFICATION_ERR: number + static readonly NAMESPACE_ERR: number + static readonly INVALID_ACCESS_ERR: number + static readonly VALIDATION_ERR: number + static readonly TYPE_MISMATCH_ERR: number + static readonly SECURITY_ERR: number + static readonly NETWORK_ERR: number + static readonly ABORT_ERR: number + static readonly URL_MISMATCH_ERR: number + static readonly QUOTA_EXCEEDED_ERR: number + static readonly TIMEOUT_ERR: number + static readonly INVALID_NODE_TYPE_ERR: number + static readonly DATA_CLONE_ERR: number + get stack(): any + set stack(value: any) +} +type WorkerGlobalScopeEventMap = { + fetch: FetchEvent + scheduled: ScheduledEvent + queue: QueueEvent + unhandledrejection: PromiseRejectionEvent + rejectionhandled: PromiseRejectionEvent +} +declare abstract class WorkerGlobalScope extends EventTarget { + EventTarget: typeof EventTarget +} +/* [MDN Reference](https://developer.mozilla.org/docs/Web/API/console) */ +interface Console { + 'assert'(condition?: boolean, ...data: any[]): void + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/clear_static) */ + clear(): void + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/count_static) */ + count(label?: string): void + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/countReset_static) */ + countReset(label?: string): void + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/debug_static) */ + debug(...data: any[]): void + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/dir_static) */ + dir(item?: any, options?: any): void + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/dirxml_static) */ + dirxml(...data: any[]): void + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/error_static) */ + error(...data: any[]): void + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/group_static) */ + group(...data: any[]): void + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/groupCollapsed_static) */ + groupCollapsed(...data: any[]): void + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/groupEnd_static) */ + groupEnd(): void + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/info_static) */ + info(...data: any[]): void + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/log_static) */ + log(...data: any[]): void + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/table_static) */ + table(tabularData?: any, properties?: string[]): void + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/time_static) */ + time(label?: string): void + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/timeEnd_static) */ + timeEnd(label?: string): void + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/timeLog_static) */ + timeLog(label?: string, ...data: any[]): void + timeStamp(label?: string): void + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/trace_static) */ + trace(...data: any[]): void + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/warn_static) */ + warn(...data: any[]): void +} +declare const console: Console +type BufferSource = ArrayBufferView | ArrayBuffer +type TypedArray = + | Int8Array + | Uint8Array + | Uint8ClampedArray + | Int16Array + | Uint16Array + | Int32Array + | Uint32Array + | Float32Array + | Float64Array + | BigInt64Array + | BigUint64Array +declare namespace WebAssembly { + class CompileError extends Error { + constructor(message?: string) + } + class RuntimeError extends Error { + constructor(message?: string) + } + type ValueType = 'anyfunc' | 'externref' | 'f32' | 'f64' | 'i32' | 'i64' | 'v128' + interface GlobalDescriptor { + value: ValueType + mutable?: boolean + } + class Global { + constructor(descriptor: GlobalDescriptor, value?: any) + value: any + valueOf(): any + } + type ImportValue = ExportValue | number + type ModuleImports = Record + type Imports = Record + type ExportValue = Function | Global | Memory | Table + type Exports = Record + class Instance { + constructor(module: Module, imports?: Imports) + readonly exports: Exports + } + interface MemoryDescriptor { + initial: number + maximum?: number + shared?: boolean + } + class Memory { + constructor(descriptor: MemoryDescriptor) + readonly buffer: ArrayBuffer + grow(delta: number): number + } + type ImportExportKind = 'function' | 'global' | 'memory' | 'table' + interface ModuleExportDescriptor { + kind: ImportExportKind + name: string + } + interface ModuleImportDescriptor { + kind: ImportExportKind + module: string + name: string + } + abstract class Module { + static customSections(module: Module, sectionName: string): ArrayBuffer[] + static exports(module: Module): ModuleExportDescriptor[] + static imports(module: Module): ModuleImportDescriptor[] + } + type TableKind = 'anyfunc' | 'externref' + interface TableDescriptor { + element: TableKind + initial: number + maximum?: number + } + class Table { + constructor(descriptor: TableDescriptor, value?: any) + readonly length: number + get(index: number): any + grow(delta: number, value?: any): number + set(index: number, value?: any): void + } + function instantiate(module: Module, imports?: Imports): Promise + function validate(bytes: BufferSource): boolean +} +/** + * This ServiceWorker API interface represents the global execution context of a service worker. + * Available only in secure contexts. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/ServiceWorkerGlobalScope) + */ +interface ServiceWorkerGlobalScope extends WorkerGlobalScope { + DOMException: typeof DOMException + WorkerGlobalScope: typeof WorkerGlobalScope + btoa(data: string): string + atob(data: string): string + setTimeout(callback: (...args: any[]) => void, msDelay?: number): number + setTimeout( + callback: (...args: Args) => void, + msDelay?: number, + ...args: Args + ): number + clearTimeout(timeoutId: number | null): void + setInterval(callback: (...args: any[]) => void, msDelay?: number): number + setInterval( + callback: (...args: Args) => void, + msDelay?: number, + ...args: Args + ): number + clearInterval(timeoutId: number | null): void + queueMicrotask(task: Function): void + structuredClone(value: T, options?: StructuredSerializeOptions): T + reportError(error: any): void + fetch(input: RequestInfo | URL, init?: RequestInit): Promise + self: ServiceWorkerGlobalScope + crypto: Crypto + caches: CacheStorage + scheduler: Scheduler + performance: Performance + Cloudflare: Cloudflare + readonly origin: string + Event: typeof Event + ExtendableEvent: typeof ExtendableEvent + CustomEvent: typeof CustomEvent + PromiseRejectionEvent: typeof PromiseRejectionEvent + FetchEvent: typeof FetchEvent + TailEvent: typeof TailEvent + TraceEvent: typeof TailEvent + ScheduledEvent: typeof ScheduledEvent + MessageEvent: typeof MessageEvent + CloseEvent: typeof CloseEvent + ReadableStreamDefaultReader: typeof ReadableStreamDefaultReader + ReadableStreamBYOBReader: typeof ReadableStreamBYOBReader + ReadableStream: typeof ReadableStream + WritableStream: typeof WritableStream + WritableStreamDefaultWriter: typeof WritableStreamDefaultWriter + TransformStream: typeof TransformStream + ByteLengthQueuingStrategy: typeof ByteLengthQueuingStrategy + CountQueuingStrategy: typeof CountQueuingStrategy + ErrorEvent: typeof ErrorEvent + EventSource: typeof EventSource + ReadableStreamBYOBRequest: typeof ReadableStreamBYOBRequest + ReadableStreamDefaultController: typeof ReadableStreamDefaultController + ReadableByteStreamController: typeof ReadableByteStreamController + WritableStreamDefaultController: typeof WritableStreamDefaultController + TransformStreamDefaultController: typeof TransformStreamDefaultController + CompressionStream: typeof CompressionStream + DecompressionStream: typeof DecompressionStream + TextEncoderStream: typeof TextEncoderStream + TextDecoderStream: typeof TextDecoderStream + Headers: typeof Headers + Body: typeof Body + Request: typeof Request + Response: typeof Response + WebSocket: typeof WebSocket + WebSocketPair: typeof WebSocketPair + WebSocketRequestResponsePair: typeof WebSocketRequestResponsePair + AbortController: typeof AbortController + AbortSignal: typeof AbortSignal + TextDecoder: typeof TextDecoder + TextEncoder: typeof TextEncoder + navigator: Navigator + Navigator: typeof Navigator + URL: typeof URL + URLSearchParams: typeof URLSearchParams + URLPattern: typeof URLPattern + Blob: typeof Blob + File: typeof File + FormData: typeof FormData + Crypto: typeof Crypto + SubtleCrypto: typeof SubtleCrypto + CryptoKey: typeof CryptoKey + CacheStorage: typeof CacheStorage + Cache: typeof Cache + FixedLengthStream: typeof FixedLengthStream + IdentityTransformStream: typeof IdentityTransformStream + HTMLRewriter: typeof HTMLRewriter +} +declare function addEventListener( + type: Type, + handler: EventListenerOrEventListenerObject, + options?: EventTargetAddEventListenerOptions | boolean +): void +declare function removeEventListener( + type: Type, + handler: EventListenerOrEventListenerObject, + options?: EventTargetEventListenerOptions | boolean +): void +/** + * Dispatches a synthetic event event to target and returns true if either event's cancelable attribute value is false or its preventDefault() method was not invoked, and false otherwise. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/EventTarget/dispatchEvent) + */ +declare function dispatchEvent( + event: WorkerGlobalScopeEventMap[keyof WorkerGlobalScopeEventMap] +): boolean +/* [MDN Reference](https://developer.mozilla.org/docs/Web/API/Window/btoa) */ +declare function btoa(data: string): string +/* [MDN Reference](https://developer.mozilla.org/docs/Web/API/Window/atob) */ +declare function atob(data: string): string +/* [MDN Reference](https://developer.mozilla.org/docs/Web/API/Window/setTimeout) */ +declare function setTimeout(callback: (...args: any[]) => void, msDelay?: number): number +/* [MDN Reference](https://developer.mozilla.org/docs/Web/API/Window/setTimeout) */ +declare function setTimeout( + callback: (...args: Args) => void, + msDelay?: number, + ...args: Args +): number +/* [MDN Reference](https://developer.mozilla.org/docs/Web/API/Window/clearTimeout) */ +declare function clearTimeout(timeoutId: number | null): void +/* [MDN Reference](https://developer.mozilla.org/docs/Web/API/Window/setInterval) */ +declare function setInterval(callback: (...args: any[]) => void, msDelay?: number): number +/* [MDN Reference](https://developer.mozilla.org/docs/Web/API/Window/setInterval) */ +declare function setInterval( + callback: (...args: Args) => void, + msDelay?: number, + ...args: Args +): number +/* [MDN Reference](https://developer.mozilla.org/docs/Web/API/Window/clearInterval) */ +declare function clearInterval(timeoutId: number | null): void +/* [MDN Reference](https://developer.mozilla.org/docs/Web/API/Window/queueMicrotask) */ +declare function queueMicrotask(task: Function): void +/* [MDN Reference](https://developer.mozilla.org/docs/Web/API/Window/structuredClone) */ +declare function structuredClone(value: T, options?: StructuredSerializeOptions): T +/* [MDN Reference](https://developer.mozilla.org/docs/Web/API/Window/reportError) */ +declare function reportError(error: any): void +/* [MDN Reference](https://developer.mozilla.org/docs/Web/API/Window/fetch) */ +declare function fetch( + input: RequestInfo | URL, + init?: RequestInit +): Promise +declare const self: ServiceWorkerGlobalScope +/** + * The Web Crypto API provides a set of low-level functions for common cryptographic tasks. + * The Workers runtime implements the full surface of this API, but with some differences in + * the [supported algorithms](https://developers.cloudflare.com/workers/runtime-apis/web-crypto/#supported-algorithms) + * compared to those implemented in most browsers. + * + * [Cloudflare Docs Reference](https://developers.cloudflare.com/workers/runtime-apis/web-crypto/) + */ +declare const crypto: Crypto +/** + * The Cache API allows fine grained control of reading and writing from the Cloudflare global network cache. + * + * [Cloudflare Docs Reference](https://developers.cloudflare.com/workers/runtime-apis/cache/) + */ +declare const caches: CacheStorage +declare const scheduler: Scheduler +/** + * The Workers runtime supports a subset of the Performance API, used to measure timing and performance, + * as well as timing of subrequests and other operations. + * + * [Cloudflare Docs Reference](https://developers.cloudflare.com/workers/runtime-apis/performance/) + */ +declare const performance: Performance +declare const Cloudflare: Cloudflare +declare const origin: string +declare const navigator: Navigator +interface TestController {} +interface ExecutionContext { + waitUntil(promise: Promise): void + passThroughOnException(): void + props: any +} +type ExportedHandlerFetchHandler = ( + request: Request>, + env: Env, + ctx: ExecutionContext +) => Response | Promise +type ExportedHandlerTailHandler = ( + events: TraceItem[], + env: Env, + ctx: ExecutionContext +) => void | Promise +type ExportedHandlerTraceHandler = ( + traces: TraceItem[], + env: Env, + ctx: ExecutionContext +) => void | Promise +type ExportedHandlerTailStreamHandler = ( + event: TailStream.TailEvent, + env: Env, + ctx: ExecutionContext +) => TailStream.TailEventHandlerType | Promise +type ExportedHandlerScheduledHandler = ( + controller: ScheduledController, + env: Env, + ctx: ExecutionContext +) => void | Promise +type ExportedHandlerQueueHandler = ( + batch: MessageBatch, + env: Env, + ctx: ExecutionContext +) => void | Promise +type ExportedHandlerTestHandler = ( + controller: TestController, + env: Env, + ctx: ExecutionContext +) => void | Promise +interface ExportedHandler { + fetch?: ExportedHandlerFetchHandler + tail?: ExportedHandlerTailHandler + trace?: ExportedHandlerTraceHandler + tailStream?: ExportedHandlerTailStreamHandler + scheduled?: ExportedHandlerScheduledHandler + test?: ExportedHandlerTestHandler + email?: EmailExportedHandler + queue?: ExportedHandlerQueueHandler +} +interface StructuredSerializeOptions { + transfer?: any[] +} +/* [MDN Reference](https://developer.mozilla.org/docs/Web/API/PromiseRejectionEvent) */ +declare abstract class PromiseRejectionEvent extends Event { + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/PromiseRejectionEvent/promise) */ + readonly promise: Promise + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/PromiseRejectionEvent/reason) */ + readonly reason: any +} +declare abstract class Navigator { + sendBeacon( + url: string, + body?: + | ReadableStream + | string + | (ArrayBuffer | ArrayBufferView) + | Blob + | FormData + | URLSearchParams + | URLSearchParams + ): boolean + readonly userAgent: string + readonly hardwareConcurrency: number +} +/** + * The Workers runtime supports a subset of the Performance API, used to measure timing and performance, + * as well as timing of subrequests and other operations. + * + * [Cloudflare Docs Reference](https://developers.cloudflare.com/workers/runtime-apis/performance/) + */ +interface Performance { + /* [Cloudflare Docs Reference](https://developers.cloudflare.com/workers/runtime-apis/performance/#performancetimeorigin) */ + readonly timeOrigin: number + /* [Cloudflare Docs Reference](https://developers.cloudflare.com/workers/runtime-apis/performance/#performancenow) */ + now(): number +} +interface AlarmInvocationInfo { + readonly isRetry: boolean + readonly retryCount: number +} +interface Cloudflare { + readonly compatibilityFlags: Record +} +interface DurableObject { + fetch(request: Request): Response | Promise + alarm?(alarmInfo?: AlarmInvocationInfo): void | Promise + webSocketMessage?(ws: WebSocket, message: string | ArrayBuffer): void | Promise + webSocketClose?( + ws: WebSocket, + code: number, + reason: string, + wasClean: boolean + ): void | Promise + webSocketError?(ws: WebSocket, error: unknown): void | Promise +} +type DurableObjectStub = Fetcher< + T, + 'alarm' | 'webSocketMessage' | 'webSocketClose' | 'webSocketError' +> & { + readonly id: DurableObjectId + readonly name?: string +} +interface DurableObjectId { + toString(): string + equals(other: DurableObjectId): boolean + readonly name?: string +} +interface DurableObjectNamespace { + newUniqueId(options?: DurableObjectNamespaceNewUniqueIdOptions): DurableObjectId + idFromName(name: string): DurableObjectId + idFromString(id: string): DurableObjectId + get( + id: DurableObjectId, + options?: DurableObjectNamespaceGetDurableObjectOptions + ): DurableObjectStub + jurisdiction(jurisdiction: DurableObjectJurisdiction): DurableObjectNamespace +} +type DurableObjectJurisdiction = 'eu' | 'fedramp' | 'fedramp-high' +interface DurableObjectNamespaceNewUniqueIdOptions { + jurisdiction?: DurableObjectJurisdiction +} +type DurableObjectLocationHint = + | 'wnam' + | 'enam' + | 'sam' + | 'weur' + | 'eeur' + | 'apac' + | 'oc' + | 'afr' + | 'me' +interface DurableObjectNamespaceGetDurableObjectOptions { + locationHint?: DurableObjectLocationHint +} +interface DurableObjectState { + waitUntil(promise: Promise): void + readonly id: DurableObjectId + readonly storage: DurableObjectStorage + container?: Container + blockConcurrencyWhile(callback: () => Promise): Promise + acceptWebSocket(ws: WebSocket, tags?: string[]): void + getWebSockets(tag?: string): WebSocket[] + setWebSocketAutoResponse(maybeReqResp?: WebSocketRequestResponsePair): void + getWebSocketAutoResponse(): WebSocketRequestResponsePair | null + getWebSocketAutoResponseTimestamp(ws: WebSocket): Date | null + setHibernatableWebSocketEventTimeout(timeoutMs?: number): void + getHibernatableWebSocketEventTimeout(): number | null + getTags(ws: WebSocket): string[] + abort(reason?: string): void +} +interface DurableObjectTransaction { + get(key: string, options?: DurableObjectGetOptions): Promise + get(keys: string[], options?: DurableObjectGetOptions): Promise> + list(options?: DurableObjectListOptions): Promise> + put(key: string, value: T, options?: DurableObjectPutOptions): Promise + put(entries: Record, options?: DurableObjectPutOptions): Promise + delete(key: string, options?: DurableObjectPutOptions): Promise + delete(keys: string[], options?: DurableObjectPutOptions): Promise + rollback(): void + getAlarm(options?: DurableObjectGetAlarmOptions): Promise + setAlarm(scheduledTime: number | Date, options?: DurableObjectSetAlarmOptions): Promise + deleteAlarm(options?: DurableObjectSetAlarmOptions): Promise +} +interface DurableObjectStorage { + get(key: string, options?: DurableObjectGetOptions): Promise + get(keys: string[], options?: DurableObjectGetOptions): Promise> + list(options?: DurableObjectListOptions): Promise> + put(key: string, value: T, options?: DurableObjectPutOptions): Promise + put(entries: Record, options?: DurableObjectPutOptions): Promise + delete(key: string, options?: DurableObjectPutOptions): Promise + delete(keys: string[], options?: DurableObjectPutOptions): Promise + deleteAll(options?: DurableObjectPutOptions): Promise + transaction(closure: (txn: DurableObjectTransaction) => Promise): Promise + getAlarm(options?: DurableObjectGetAlarmOptions): Promise + setAlarm(scheduledTime: number | Date, options?: DurableObjectSetAlarmOptions): Promise + deleteAlarm(options?: DurableObjectSetAlarmOptions): Promise + sync(): Promise + sql: SqlStorage + transactionSync(closure: () => T): T + getCurrentBookmark(): Promise + getBookmarkForTime(timestamp: number | Date): Promise + onNextSessionRestoreBookmark(bookmark: string): Promise +} +interface DurableObjectListOptions { + start?: string + startAfter?: string + end?: string + prefix?: string + reverse?: boolean + limit?: number + allowConcurrency?: boolean + noCache?: boolean +} +interface DurableObjectGetOptions { + allowConcurrency?: boolean + noCache?: boolean +} +interface DurableObjectGetAlarmOptions { + allowConcurrency?: boolean +} +interface DurableObjectPutOptions { + allowConcurrency?: boolean + allowUnconfirmed?: boolean + noCache?: boolean +} +interface DurableObjectSetAlarmOptions { + allowConcurrency?: boolean + allowUnconfirmed?: boolean +} +declare class WebSocketRequestResponsePair { + constructor(request: string, response: string) + get request(): string + get response(): string +} +interface AnalyticsEngineDataset { + writeDataPoint(event?: AnalyticsEngineDataPoint): void +} +interface AnalyticsEngineDataPoint { + indexes?: ((ArrayBuffer | string) | null)[] + doubles?: number[] + blobs?: ((ArrayBuffer | string) | null)[] +} +/** + * An event which takes place in the DOM. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Event) + */ +declare class Event { + constructor(type: string, init?: EventInit) + /** + * Returns the type of event, e.g. "click", "hashchange", or "submit". + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Event/type) + */ + get type(): string + /** + * Returns the event's phase, which is one of NONE, CAPTURING_PHASE, AT_TARGET, and BUBBLING_PHASE. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Event/eventPhase) + */ + get eventPhase(): number + /** + * Returns true or false depending on how event was initialized. True if event invokes listeners past a ShadowRoot node that is the root of its target, and false otherwise. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Event/composed) + */ + get composed(): boolean + /** + * Returns true or false depending on how event was initialized. True if event goes through its target's ancestors in reverse tree order, and false otherwise. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Event/bubbles) + */ + get bubbles(): boolean + /** + * Returns true or false depending on how event was initialized. Its return value does not always carry meaning, but true can indicate that part of the operation during which event was dispatched, can be canceled by invoking the preventDefault() method. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Event/cancelable) + */ + get cancelable(): boolean + /** + * Returns true if preventDefault() was invoked successfully to indicate cancelation, and false otherwise. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Event/defaultPrevented) + */ + get defaultPrevented(): boolean + /** + * @deprecated + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Event/returnValue) + */ + get returnValue(): boolean + /** + * Returns the object whose event listener's callback is currently being invoked. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Event/currentTarget) + */ + get currentTarget(): EventTarget | undefined + /** + * Returns the object to which event is dispatched (its target). + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Event/target) + */ + get target(): EventTarget | undefined + /** + * @deprecated + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Event/srcElement) + */ + get srcElement(): EventTarget | undefined + /** + * Returns the event's timestamp as the number of milliseconds measured relative to the time origin. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Event/timeStamp) + */ + get timeStamp(): number + /** + * Returns true if event was dispatched by the user agent, and false otherwise. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Event/isTrusted) + */ + get isTrusted(): boolean + /** + * @deprecated + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Event/cancelBubble) + */ + get cancelBubble(): boolean + /** + * @deprecated + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Event/cancelBubble) + */ + set cancelBubble(value: boolean) + /** + * Invoking this method prevents event from reaching any registered event listeners after the current one finishes running and, when dispatched in a tree, also prevents event from reaching any other objects. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Event/stopImmediatePropagation) + */ + stopImmediatePropagation(): void + /** + * If invoked when the cancelable attribute value is true, and while executing a listener for the event with passive set to false, signals to the operation that caused event to be dispatched that it needs to be canceled. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Event/preventDefault) + */ + preventDefault(): void + /** + * When dispatched in a tree, invoking this method prevents event from reaching any objects other than the current object. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Event/stopPropagation) + */ + stopPropagation(): void + /** + * Returns the invocation target objects of event's path (objects on which listeners will be invoked), except for any nodes in shadow trees of which the shadow root's mode is "closed" that are not reachable from event's currentTarget. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Event/composedPath) + */ + composedPath(): EventTarget[] + static readonly NONE: number + static readonly CAPTURING_PHASE: number + static readonly AT_TARGET: number + static readonly BUBBLING_PHASE: number +} +interface EventInit { + bubbles?: boolean + cancelable?: boolean + composed?: boolean +} +type EventListener = (event: EventType) => void +interface EventListenerObject { + handleEvent(event: EventType): void +} +type EventListenerOrEventListenerObject = + | EventListener + | EventListenerObject +/** + * EventTarget is a DOM interface implemented by objects that can receive events and may have listeners for them. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/EventTarget) + */ +declare class EventTarget = Record> { + constructor() + /** + * Appends an event listener for events whose type attribute value is type. The callback argument sets the callback that will be invoked when the event is dispatched. + * + * The options argument sets listener-specific options. For compatibility this can be a boolean, in which case the method behaves exactly as if the value was specified as options's capture. + * + * When set to true, options's capture prevents callback from being invoked when the event's eventPhase attribute value is BUBBLING_PHASE. When false (or not present), callback will not be invoked when event's eventPhase attribute value is CAPTURING_PHASE. Either way, callback will be invoked if event's eventPhase attribute value is AT_TARGET. + * + * When set to true, options's passive indicates that the callback will not cancel the event by invoking preventDefault(). This is used to enable performance optimizations described in § 2.8 Observing event listeners. + * + * When set to true, options's once indicates that the callback will only be invoked once after which the event listener will be removed. + * + * If an AbortSignal is passed for options's signal, then the event listener will be removed when signal is aborted. + * + * The event listener is appended to target's event listener list and is not appended if it has the same type, callback, and capture. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/EventTarget/addEventListener) + */ + addEventListener( + type: Type, + handler: EventListenerOrEventListenerObject, + options?: EventTargetAddEventListenerOptions | boolean + ): void + /** + * Removes the event listener in target's event listener list with the same type, callback, and options. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/EventTarget/removeEventListener) + */ + removeEventListener( + type: Type, + handler: EventListenerOrEventListenerObject, + options?: EventTargetEventListenerOptions | boolean + ): void + /** + * Dispatches a synthetic event event to target and returns true if either event's cancelable attribute value is false or its preventDefault() method was not invoked, and false otherwise. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/EventTarget/dispatchEvent) + */ + dispatchEvent(event: EventMap[keyof EventMap]): boolean +} +interface EventTargetEventListenerOptions { + capture?: boolean +} +interface EventTargetAddEventListenerOptions { + capture?: boolean + passive?: boolean + once?: boolean + signal?: AbortSignal +} +interface EventTargetHandlerObject { + handleEvent: (event: Event) => any | undefined +} +/** + * A controller object that allows you to abort one or more DOM requests as and when desired. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/AbortController) + */ +declare class AbortController { + constructor() + /** + * Returns the AbortSignal object associated with this object. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/AbortController/signal) + */ + get signal(): AbortSignal + /** + * Invoking this method will set this object's AbortSignal's aborted flag and signal to any observers that the associated activity is to be aborted. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/AbortController/abort) + */ + abort(reason?: any): void +} +/** + * A signal object that allows you to communicate with a DOM request (such as a Fetch) and abort it if required via an AbortController object. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/AbortSignal) + */ +declare abstract class AbortSignal extends EventTarget { + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/AbortSignal/abort_static) */ + static abort(reason?: any): AbortSignal + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/AbortSignal/timeout_static) */ + static timeout(delay: number): AbortSignal + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/AbortSignal/any_static) */ + static any(signals: AbortSignal[]): AbortSignal + /** + * Returns true if this AbortSignal's AbortController has signaled to abort, and false otherwise. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/AbortSignal/aborted) + */ + get aborted(): boolean + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/AbortSignal/reason) */ + get reason(): any + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/AbortSignal/abort_event) */ + get onabort(): any | null + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/AbortSignal/abort_event) */ + set onabort(value: any | null) + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/AbortSignal/throwIfAborted) */ + throwIfAborted(): void +} +interface Scheduler { + wait(delay: number, maybeOptions?: SchedulerWaitOptions): Promise +} +interface SchedulerWaitOptions { + signal?: AbortSignal +} +/** + * Extends the lifetime of the install and activate events dispatched on the global scope as part of the service worker lifecycle. This ensures that any functional events (like FetchEvent) are not dispatched until it upgrades database schemas and deletes the outdated cache entries. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/ExtendableEvent) + */ +declare abstract class ExtendableEvent extends Event { + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/ExtendableEvent/waitUntil) */ + waitUntil(promise: Promise): void +} +/* [MDN Reference](https://developer.mozilla.org/docs/Web/API/CustomEvent) */ +declare class CustomEvent extends Event { + constructor(type: string, init?: CustomEventCustomEventInit) + /** + * Returns any custom data event was created with. Typically used for synthetic events. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/CustomEvent/detail) + */ + get detail(): T +} +interface CustomEventCustomEventInit { + bubbles?: boolean + cancelable?: boolean + composed?: boolean + detail?: any +} +/** + * A file-like object of immutable, raw data. Blobs represent data that isn't necessarily in a JavaScript-native format. The File interface is based on Blob, inheriting blob functionality and expanding it to support files on the user's system. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Blob) + */ +declare class Blob { + constructor(type?: ((ArrayBuffer | ArrayBufferView) | string | Blob)[], options?: BlobOptions) + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/Blob/size) */ + get size(): number + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/Blob/type) */ + get type(): string + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/Blob/slice) */ + slice(start?: number, end?: number, type?: string): Blob + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/Blob/arrayBuffer) */ + arrayBuffer(): Promise + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/Blob/bytes) */ + bytes(): Promise + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/Blob/text) */ + text(): Promise + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/Blob/stream) */ + stream(): ReadableStream +} +interface BlobOptions { + type?: string +} +/** + * Provides information about files and allows JavaScript in a web page to access their content. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/File) + */ +declare class File extends Blob { + constructor( + bits: ((ArrayBuffer | ArrayBufferView) | string | Blob)[] | undefined, + name: string, + options?: FileOptions + ) + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/File/name) */ + get name(): string + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/File/lastModified) */ + get lastModified(): number +} +interface FileOptions { + type?: string + lastModified?: number +} +/** + * The Cache API allows fine grained control of reading and writing from the Cloudflare global network cache. + * + * [Cloudflare Docs Reference](https://developers.cloudflare.com/workers/runtime-apis/cache/) + */ +declare abstract class CacheStorage { + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/CacheStorage/open) */ + open(cacheName: string): Promise + readonly default: Cache +} +/** + * The Cache API allows fine grained control of reading and writing from the Cloudflare global network cache. + * + * [Cloudflare Docs Reference](https://developers.cloudflare.com/workers/runtime-apis/cache/) + */ +declare abstract class Cache { + /* [Cloudflare Docs Reference](https://developers.cloudflare.com/workers/runtime-apis/cache/#delete) */ + delete(request: RequestInfo | URL, options?: CacheQueryOptions): Promise + /* [Cloudflare Docs Reference](https://developers.cloudflare.com/workers/runtime-apis/cache/#match) */ + match(request: RequestInfo | URL, options?: CacheQueryOptions): Promise + /* [Cloudflare Docs Reference](https://developers.cloudflare.com/workers/runtime-apis/cache/#put) */ + put(request: RequestInfo | URL, response: Response): Promise +} +interface CacheQueryOptions { + ignoreMethod?: boolean +} +/** + * The Web Crypto API provides a set of low-level functions for common cryptographic tasks. + * The Workers runtime implements the full surface of this API, but with some differences in + * the [supported algorithms](https://developers.cloudflare.com/workers/runtime-apis/web-crypto/#supported-algorithms) + * compared to those implemented in most browsers. + * + * [Cloudflare Docs Reference](https://developers.cloudflare.com/workers/runtime-apis/web-crypto/) + */ +declare abstract class Crypto { + /** + * Available only in secure contexts. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Crypto/subtle) + */ + get subtle(): SubtleCrypto + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/Crypto/getRandomValues) */ + getRandomValues< + T extends + | Int8Array + | Uint8Array + | Int16Array + | Uint16Array + | Int32Array + | Uint32Array + | BigInt64Array + | BigUint64Array, + >(buffer: T): T + /** + * Available only in secure contexts. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Crypto/randomUUID) + */ + randomUUID(): string + DigestStream: typeof DigestStream +} +/** + * This Web Crypto API interface provides a number of low-level cryptographic functions. It is accessed via the Crypto.subtle properties available in a window context (via Window.crypto). + * Available only in secure contexts. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/SubtleCrypto) + */ +declare abstract class SubtleCrypto { + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/SubtleCrypto/encrypt) */ + encrypt( + algorithm: string | SubtleCryptoEncryptAlgorithm, + key: CryptoKey, + plainText: ArrayBuffer | ArrayBufferView + ): Promise + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/SubtleCrypto/decrypt) */ + decrypt( + algorithm: string | SubtleCryptoEncryptAlgorithm, + key: CryptoKey, + cipherText: ArrayBuffer | ArrayBufferView + ): Promise + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/SubtleCrypto/sign) */ + sign( + algorithm: string | SubtleCryptoSignAlgorithm, + key: CryptoKey, + data: ArrayBuffer | ArrayBufferView + ): Promise + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/SubtleCrypto/verify) */ + verify( + algorithm: string | SubtleCryptoSignAlgorithm, + key: CryptoKey, + signature: ArrayBuffer | ArrayBufferView, + data: ArrayBuffer | ArrayBufferView + ): Promise + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/SubtleCrypto/digest) */ + digest( + algorithm: string | SubtleCryptoHashAlgorithm, + data: ArrayBuffer | ArrayBufferView + ): Promise + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/SubtleCrypto/generateKey) */ + generateKey( + algorithm: string | SubtleCryptoGenerateKeyAlgorithm, + extractable: boolean, + keyUsages: string[] + ): Promise + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/SubtleCrypto/deriveKey) */ + deriveKey( + algorithm: string | SubtleCryptoDeriveKeyAlgorithm, + baseKey: CryptoKey, + derivedKeyAlgorithm: string | SubtleCryptoImportKeyAlgorithm, + extractable: boolean, + keyUsages: string[] + ): Promise + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/SubtleCrypto/deriveBits) */ + deriveBits( + algorithm: string | SubtleCryptoDeriveKeyAlgorithm, + baseKey: CryptoKey, + length?: number | null + ): Promise + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/SubtleCrypto/importKey) */ + importKey( + format: string, + keyData: (ArrayBuffer | ArrayBufferView) | JsonWebKey, + algorithm: string | SubtleCryptoImportKeyAlgorithm, + extractable: boolean, + keyUsages: string[] + ): Promise + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/SubtleCrypto/exportKey) */ + exportKey(format: string, key: CryptoKey): Promise + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/SubtleCrypto/wrapKey) */ + wrapKey( + format: string, + key: CryptoKey, + wrappingKey: CryptoKey, + wrapAlgorithm: string | SubtleCryptoEncryptAlgorithm + ): Promise + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/SubtleCrypto/unwrapKey) */ + unwrapKey( + format: string, + wrappedKey: ArrayBuffer | ArrayBufferView, + unwrappingKey: CryptoKey, + unwrapAlgorithm: string | SubtleCryptoEncryptAlgorithm, + unwrappedKeyAlgorithm: string | SubtleCryptoImportKeyAlgorithm, + extractable: boolean, + keyUsages: string[] + ): Promise + timingSafeEqual(a: ArrayBuffer | ArrayBufferView, b: ArrayBuffer | ArrayBufferView): boolean +} +/** + * The CryptoKey dictionary of the Web Crypto API represents a cryptographic key. + * Available only in secure contexts. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/CryptoKey) + */ +declare abstract class CryptoKey { + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/CryptoKey/type) */ + readonly type: string + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/CryptoKey/extractable) */ + readonly extractable: boolean + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/CryptoKey/algorithm) */ + readonly algorithm: + | CryptoKeyKeyAlgorithm + | CryptoKeyAesKeyAlgorithm + | CryptoKeyHmacKeyAlgorithm + | CryptoKeyRsaKeyAlgorithm + | CryptoKeyEllipticKeyAlgorithm + | CryptoKeyArbitraryKeyAlgorithm + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/CryptoKey/usages) */ + readonly usages: string[] +} +interface CryptoKeyPair { + publicKey: CryptoKey + privateKey: CryptoKey +} +interface JsonWebKey { + kty: string + use?: string + key_ops?: string[] + alg?: string + ext?: boolean + crv?: string + x?: string + y?: string + d?: string + n?: string + e?: string + p?: string + q?: string + dp?: string + dq?: string + qi?: string + oth?: RsaOtherPrimesInfo[] + k?: string +} +interface RsaOtherPrimesInfo { + r?: string + d?: string + t?: string +} +interface SubtleCryptoDeriveKeyAlgorithm { + name: string + salt?: ArrayBuffer | ArrayBufferView + iterations?: number + hash?: string | SubtleCryptoHashAlgorithm + $public?: CryptoKey + info?: ArrayBuffer | ArrayBufferView +} +interface SubtleCryptoEncryptAlgorithm { + name: string + iv?: ArrayBuffer | ArrayBufferView + additionalData?: ArrayBuffer | ArrayBufferView + tagLength?: number + counter?: ArrayBuffer | ArrayBufferView + length?: number + label?: ArrayBuffer | ArrayBufferView +} +interface SubtleCryptoGenerateKeyAlgorithm { + name: string + hash?: string | SubtleCryptoHashAlgorithm + modulusLength?: number + publicExponent?: ArrayBuffer | ArrayBufferView + length?: number + namedCurve?: string +} +interface SubtleCryptoHashAlgorithm { + name: string +} +interface SubtleCryptoImportKeyAlgorithm { + name: string + hash?: string | SubtleCryptoHashAlgorithm + length?: number + namedCurve?: string + compressed?: boolean +} +interface SubtleCryptoSignAlgorithm { + name: string + hash?: string | SubtleCryptoHashAlgorithm + dataLength?: number + saltLength?: number +} +interface CryptoKeyKeyAlgorithm { + name: string +} +interface CryptoKeyAesKeyAlgorithm { + name: string + length: number +} +interface CryptoKeyHmacKeyAlgorithm { + name: string + hash: CryptoKeyKeyAlgorithm + length: number +} +interface CryptoKeyRsaKeyAlgorithm { + name: string + modulusLength: number + publicExponent: ArrayBuffer | ArrayBufferView + hash?: CryptoKeyKeyAlgorithm +} +interface CryptoKeyEllipticKeyAlgorithm { + name: string + namedCurve: string +} +interface CryptoKeyArbitraryKeyAlgorithm { + name: string + hash?: CryptoKeyKeyAlgorithm + namedCurve?: string + length?: number +} +declare class DigestStream extends WritableStream { + constructor(algorithm: string | SubtleCryptoHashAlgorithm) + readonly digest: Promise + get bytesWritten(): number | bigint +} +/** + * A decoder for a specific method, that is a specific character encoding, like utf-8, iso-8859-2, koi8, cp1261, gbk, etc. A decoder takes a stream of bytes as input and emits a stream of code points. For a more scalable, non-native library, see StringView – a C-like representation of strings based on typed arrays. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/TextDecoder) + */ +declare class TextDecoder { + constructor(label?: string, options?: TextDecoderConstructorOptions) + /** + * Returns the result of running encoding's decoder. The method can be invoked zero or more times with options's stream set to true, and then once without options's stream (or set to false), to process a fragmented input. If the invocation without options's stream (or set to false) has no input, it's clearest to omit both arguments. + * + * ``` + * var string = "", decoder = new TextDecoder(encoding), buffer; + * while(buffer = next_chunk()) { + * string += decoder.decode(buffer, {stream:true}); + * } + * string += decoder.decode(); // end-of-queue + * ``` + * + * If the error mode is "fatal" and encoding's decoder returns error, throws a TypeError. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/TextDecoder/decode) + */ + decode(input?: ArrayBuffer | ArrayBufferView, options?: TextDecoderDecodeOptions): string + get encoding(): string + get fatal(): boolean + get ignoreBOM(): boolean +} +/** + * TextEncoder takes a stream of code points as input and emits a stream of bytes. For a more scalable, non-native library, see StringView – a C-like representation of strings based on typed arrays. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/TextEncoder) + */ +declare class TextEncoder { + constructor() + /** + * Returns the result of running UTF-8's encoder. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/TextEncoder/encode) + */ + encode(input?: string): Uint8Array + /** + * Runs the UTF-8 encoder on source, stores the result of that operation into destination, and returns the progress made as an object wherein read is the number of converted code units of source and written is the number of bytes modified in destination. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/TextEncoder/encodeInto) + */ + encodeInto(input: string, buffer: ArrayBuffer | ArrayBufferView): TextEncoderEncodeIntoResult + get encoding(): string +} +interface TextDecoderConstructorOptions { + fatal: boolean + ignoreBOM: boolean +} +interface TextDecoderDecodeOptions { + stream: boolean +} +interface TextEncoderEncodeIntoResult { + read: number + written: number +} +/** + * Events providing information related to errors in scripts or in files. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/ErrorEvent) + */ +declare class ErrorEvent extends Event { + constructor(type: string, init?: ErrorEventErrorEventInit) + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/ErrorEvent/filename) */ + get filename(): string + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/ErrorEvent/message) */ + get message(): string + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/ErrorEvent/lineno) */ + get lineno(): number + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/ErrorEvent/colno) */ + get colno(): number + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/ErrorEvent/error) */ + get error(): any +} +interface ErrorEventErrorEventInit { + message?: string + filename?: string + lineno?: number + colno?: number + error?: any +} +/** + * Provides a way to easily construct a set of key/value pairs representing form fields and their values, which can then be easily sent using the XMLHttpRequest.send() method. It uses the same format a form would use if the encoding type were set to "multipart/form-data". + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/FormData) + */ +declare class FormData { + constructor() + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/FormData/append) */ + append(name: string, value: string): void + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/FormData/append) */ + append(name: string, value: Blob, filename?: string): void + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/FormData/delete) */ + delete(name: string): void + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/FormData/get) */ + get(name: string): (File | string) | null + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/FormData/getAll) */ + getAll(name: string): (File | string)[] + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/FormData/has) */ + has(name: string): boolean + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/FormData/set) */ + set(name: string, value: string): void + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/FormData/set) */ + set(name: string, value: Blob, filename?: string): void + /* Returns an array of key, value pairs for every entry in the list. */ + entries(): IterableIterator<[key: string, value: File | string]> + /* Returns a list of keys in the list. */ + keys(): IterableIterator + /* Returns a list of values in the list. */ + values(): IterableIterator + forEach( + callback: (this: This, value: File | string, key: string, parent: FormData) => void, + thisArg?: This + ): void + [Symbol.iterator](): IterableIterator<[key: string, value: File | string]> +} +interface ContentOptions { + html?: boolean +} +declare class HTMLRewriter { + constructor() + on(selector: string, handlers: HTMLRewriterElementContentHandlers): HTMLRewriter + onDocument(handlers: HTMLRewriterDocumentContentHandlers): HTMLRewriter + transform(response: Response): Response +} +interface HTMLRewriterElementContentHandlers { + element?(element: Element): void | Promise + comments?(comment: Comment): void | Promise + text?(element: Text): void | Promise +} +interface HTMLRewriterDocumentContentHandlers { + doctype?(doctype: Doctype): void | Promise + comments?(comment: Comment): void | Promise + text?(text: Text): void | Promise + end?(end: DocumentEnd): void | Promise +} +interface Doctype { + readonly name: string | null + readonly publicId: string | null + readonly systemId: string | null +} +interface Element { + tagName: string + readonly attributes: IterableIterator + readonly removed: boolean + readonly namespaceURI: string + getAttribute(name: string): string | null + hasAttribute(name: string): boolean + setAttribute(name: string, value: string): Element + removeAttribute(name: string): Element + before(content: string | ReadableStream | Response, options?: ContentOptions): Element + after(content: string | ReadableStream | Response, options?: ContentOptions): Element + prepend(content: string | ReadableStream | Response, options?: ContentOptions): Element + append(content: string | ReadableStream | Response, options?: ContentOptions): Element + replace(content: string | ReadableStream | Response, options?: ContentOptions): Element + remove(): Element + removeAndKeepContent(): Element + setInnerContent(content: string | ReadableStream | Response, options?: ContentOptions): Element + onEndTag(handler: (tag: EndTag) => void | Promise): void +} +interface EndTag { + name: string + before(content: string | ReadableStream | Response, options?: ContentOptions): EndTag + after(content: string | ReadableStream | Response, options?: ContentOptions): EndTag + remove(): EndTag +} +interface Comment { + text: string + readonly removed: boolean + before(content: string, options?: ContentOptions): Comment + after(content: string, options?: ContentOptions): Comment + replace(content: string, options?: ContentOptions): Comment + remove(): Comment +} +interface Text { + readonly text: string + readonly lastInTextNode: boolean + readonly removed: boolean + before(content: string | ReadableStream | Response, options?: ContentOptions): Text + after(content: string | ReadableStream | Response, options?: ContentOptions): Text + replace(content: string | ReadableStream | Response, options?: ContentOptions): Text + remove(): Text +} +interface DocumentEnd { + append(content: string, options?: ContentOptions): DocumentEnd +} +/** + * This is the event type for fetch events dispatched on the service worker global scope. It contains information about the fetch, including the request and how the receiver will treat the response. It provides the event.respondWith() method, which allows us to provide a response to this fetch. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/FetchEvent) + */ +declare abstract class FetchEvent extends ExtendableEvent { + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/FetchEvent/request) */ + readonly request: Request + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/FetchEvent/respondWith) */ + respondWith(promise: Response | Promise): void + passThroughOnException(): void +} +type HeadersInit = Headers | Iterable> | Record +/** + * This Fetch API interface allows you to perform various actions on HTTP request and response headers. These actions include retrieving, setting, adding to, and removing. A Headers object has an associated header list, which is initially empty and consists of zero or more name and value pairs.  You can add to this using methods like append() (see Examples.) In all methods of this interface, header names are matched by case-insensitive byte sequence. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Headers) + */ +declare class Headers { + constructor(init?: HeadersInit) + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/Headers/get) */ + get(name: string): string | null + getAll(name: string): string[] + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/Headers/getSetCookie) */ + getSetCookie(): string[] + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/Headers/has) */ + has(name: string): boolean + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/Headers/set) */ + set(name: string, value: string): void + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/Headers/append) */ + append(name: string, value: string): void + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/Headers/delete) */ + delete(name: string): void + forEach( + callback: (this: This, value: string, key: string, parent: Headers) => void, + thisArg?: This + ): void + /* Returns an iterator allowing to go through all key/value pairs contained in this object. */ + entries(): IterableIterator<[key: string, value: string]> + /* Returns an iterator allowing to go through all keys of the key/value pairs contained in this object. */ + keys(): IterableIterator + /* Returns an iterator allowing to go through all values of the key/value pairs contained in this object. */ + values(): IterableIterator + [Symbol.iterator](): IterableIterator<[key: string, value: string]> +} +type BodyInit = + | ReadableStream + | string + | ArrayBuffer + | ArrayBufferView + | Blob + | URLSearchParams + | FormData +declare abstract class Body { + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/Request/body) */ + get body(): ReadableStream | null + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/Request/bodyUsed) */ + get bodyUsed(): boolean + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/Request/arrayBuffer) */ + arrayBuffer(): Promise + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/Request/bytes) */ + bytes(): Promise + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/Request/text) */ + text(): Promise + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/Request/json) */ + json(): Promise + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/Request/formData) */ + formData(): Promise + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/Request/blob) */ + blob(): Promise +} +/** + * This Fetch API interface represents the response to a request. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Response) + */ +declare var Response: { + prototype: Response + new (body?: BodyInit | null, init?: ResponseInit): Response + error(): Response + redirect(url: string, status?: number): Response + json(any: any, maybeInit?: ResponseInit | Response): Response +} +/** + * This Fetch API interface represents the response to a request. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Response) + */ +interface Response extends Body { + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/Response/clone) */ + clone(): Response + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/Response/status) */ + status: number + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/Response/statusText) */ + statusText: string + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/Response/headers) */ + headers: Headers + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/Response/ok) */ + ok: boolean + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/Response/redirected) */ + redirected: boolean + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/Response/url) */ + url: string + webSocket: WebSocket | null + cf: any | undefined + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/Response/type) */ + type: 'default' | 'error' +} +interface ResponseInit { + status?: number + statusText?: string + headers?: HeadersInit + cf?: any + webSocket?: WebSocket | null + encodeBody?: 'automatic' | 'manual' +} +type RequestInfo> = + | Request + | string +/** + * This Fetch API interface represents a resource request. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Request) + */ +declare var Request: { + prototype: Request + new >( + input: RequestInfo | URL, + init?: RequestInit + ): Request +} +/** + * This Fetch API interface represents a resource request. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Request) + */ +interface Request> extends Body { + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/Request/clone) */ + clone(): Request + /** + * Returns request's HTTP method, which is "GET" by default. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Request/method) + */ + method: string + /** + * Returns the URL of request as a string. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Request/url) + */ + url: string + /** + * Returns a Headers object consisting of the headers associated with request. Note that headers added in the network layer by the user agent will not be accounted for in this object, e.g., the "Host" header. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Request/headers) + */ + headers: Headers + /** + * Returns the redirect mode associated with request, which is a string indicating how redirects for the request will be handled during fetching. A request will follow redirects by default. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Request/redirect) + */ + redirect: string + fetcher: Fetcher | null + /** + * Returns the signal associated with request, which is an AbortSignal object indicating whether or not request has been aborted, and its abort event handler. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Request/signal) + */ + signal: AbortSignal + cf: Cf | undefined + /** + * Returns request's subresource integrity metadata, which is a cryptographic hash of the resource being fetched. Its value consists of multiple hashes separated by whitespace. [SRI] + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Request/integrity) + */ + integrity: string + /** + * Returns a boolean indicating whether or not request can outlive the global in which it was created. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Request/keepalive) + */ + keepalive: boolean + /** + * Returns the cache mode associated with request, which is a string indicating how the request will interact with the browser's cache when fetching. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Request/cache) + */ + cache?: 'no-store' +} +interface RequestInit { + /* A string to set request's method. */ + method?: string + /* A Headers object, an object literal, or an array of two-item arrays to set request's headers. */ + headers?: HeadersInit + /* A BodyInit object or null to set request's body. */ + body?: BodyInit | null + /* A string indicating whether request follows redirects, results in an error upon encountering a redirect, or returns the redirect (in an opaque fashion). Sets request's redirect. */ + redirect?: string + fetcher?: Fetcher | null + cf?: Cf + /* A string indicating how the request will interact with the browser's cache to set request's cache. */ + cache?: 'no-store' + /* A cryptographic hash of the resource to be fetched by request. Sets request's integrity. */ + integrity?: string + /* An AbortSignal to set request's signal. */ + signal?: AbortSignal | null + encodeResponseBody?: 'automatic' | 'manual' +} +type Service = Fetcher +type Fetcher< + T extends Rpc.EntrypointBranded | undefined = undefined, + Reserved extends string = never, +> = (T extends Rpc.EntrypointBranded + ? Rpc.Provider + : unknown) & { + fetch(input: RequestInfo | URL, init?: RequestInit): Promise + connect(address: SocketAddress | string, options?: SocketOptions): Socket +} +interface KVNamespaceListKey { + name: Key + expiration?: number + metadata?: Metadata +} +type KVNamespaceListResult = + | { + list_complete: false + keys: KVNamespaceListKey[] + cursor: string + cacheStatus: string | null + } + | { + list_complete: true + keys: KVNamespaceListKey[] + cacheStatus: string | null + } +interface KVNamespace { + get(key: Key, options?: Partial>): Promise + get(key: Key, type: 'text'): Promise + get(key: Key, type: 'json'): Promise + get(key: Key, type: 'arrayBuffer'): Promise + get(key: Key, type: 'stream'): Promise + get(key: Key, options?: KVNamespaceGetOptions<'text'>): Promise + get( + key: Key, + options?: KVNamespaceGetOptions<'json'> + ): Promise + get(key: Key, options?: KVNamespaceGetOptions<'arrayBuffer'>): Promise + get(key: Key, options?: KVNamespaceGetOptions<'stream'>): Promise + get(key: Array, type: 'text'): Promise> + get( + key: Array, + type: 'json' + ): Promise> + get( + key: Array, + options?: Partial> + ): Promise> + get(key: Array, options?: KVNamespaceGetOptions<'text'>): Promise> + get( + key: Array, + options?: KVNamespaceGetOptions<'json'> + ): Promise> + list( + options?: KVNamespaceListOptions + ): Promise> + put( + key: Key, + value: string | ArrayBuffer | ArrayBufferView | ReadableStream, + options?: KVNamespacePutOptions + ): Promise + getWithMetadata( + key: Key, + options?: Partial> + ): Promise> + getWithMetadata( + key: Key, + type: 'text' + ): Promise> + getWithMetadata( + key: Key, + type: 'json' + ): Promise> + getWithMetadata( + key: Key, + type: 'arrayBuffer' + ): Promise> + getWithMetadata( + key: Key, + type: 'stream' + ): Promise> + getWithMetadata( + key: Key, + options: KVNamespaceGetOptions<'text'> + ): Promise> + getWithMetadata( + key: Key, + options: KVNamespaceGetOptions<'json'> + ): Promise> + getWithMetadata( + key: Key, + options: KVNamespaceGetOptions<'arrayBuffer'> + ): Promise> + getWithMetadata( + key: Key, + options: KVNamespaceGetOptions<'stream'> + ): Promise> + getWithMetadata( + key: Array, + type: 'text' + ): Promise>> + getWithMetadata( + key: Array, + type: 'json' + ): Promise>> + getWithMetadata( + key: Array, + options?: Partial> + ): Promise>> + getWithMetadata( + key: Array, + options?: KVNamespaceGetOptions<'text'> + ): Promise>> + getWithMetadata( + key: Array, + options?: KVNamespaceGetOptions<'json'> + ): Promise>> + delete(key: Key): Promise +} +interface KVNamespaceListOptions { + limit?: number + prefix?: string | null + cursor?: string | null +} +interface KVNamespaceGetOptions { + type: Type + cacheTtl?: number +} +interface KVNamespacePutOptions { + expiration?: number + expirationTtl?: number + metadata?: any | null +} +interface KVNamespaceGetWithMetadataResult { + value: Value | null + metadata: Metadata | null + cacheStatus: string | null +} +type QueueContentType = 'text' | 'bytes' | 'json' | 'v8' +interface Queue { + send(message: Body, options?: QueueSendOptions): Promise + sendBatch( + messages: Iterable>, + options?: QueueSendBatchOptions + ): Promise +} +interface QueueSendOptions { + contentType?: QueueContentType + delaySeconds?: number +} +interface QueueSendBatchOptions { + delaySeconds?: number +} +interface MessageSendRequest { + body: Body + contentType?: QueueContentType + delaySeconds?: number +} +interface QueueRetryOptions { + delaySeconds?: number +} +interface Message { + readonly id: string + readonly timestamp: Date + readonly body: Body + readonly attempts: number + retry(options?: QueueRetryOptions): void + ack(): void +} +interface QueueEvent extends ExtendableEvent { + readonly messages: readonly Message[] + readonly queue: string + retryAll(options?: QueueRetryOptions): void + ackAll(): void +} +interface MessageBatch { + readonly messages: readonly Message[] + readonly queue: string + retryAll(options?: QueueRetryOptions): void + ackAll(): void +} +interface R2Error extends Error { + readonly name: string + readonly code: number + readonly message: string + readonly action: string + readonly stack: any +} +interface R2ListOptions { + limit?: number + prefix?: string + cursor?: string + delimiter?: string + startAfter?: string + include?: ('httpMetadata' | 'customMetadata')[] +} +declare abstract class R2Bucket { + head(key: string): Promise + get( + key: string, + options: R2GetOptions & { + onlyIf: R2Conditional | Headers + } + ): Promise + get(key: string, options?: R2GetOptions): Promise + put( + key: string, + value: ReadableStream | ArrayBuffer | ArrayBufferView | string | null | Blob, + options?: R2PutOptions & { + onlyIf: R2Conditional | Headers + } + ): Promise + put( + key: string, + value: ReadableStream | ArrayBuffer | ArrayBufferView | string | null | Blob, + options?: R2PutOptions + ): Promise + createMultipartUpload(key: string, options?: R2MultipartOptions): Promise + resumeMultipartUpload(key: string, uploadId: string): R2MultipartUpload + delete(keys: string | string[]): Promise + list(options?: R2ListOptions): Promise +} +interface R2MultipartUpload { + readonly key: string + readonly uploadId: string + uploadPart( + partNumber: number, + value: ReadableStream | (ArrayBuffer | ArrayBufferView) | string | Blob, + options?: R2UploadPartOptions + ): Promise + abort(): Promise + complete(uploadedParts: R2UploadedPart[]): Promise +} +interface R2UploadedPart { + partNumber: number + etag: string +} +declare abstract class R2Object { + readonly key: string + readonly version: string + readonly size: number + readonly etag: string + readonly httpEtag: string + readonly checksums: R2Checksums + readonly uploaded: Date + readonly httpMetadata?: R2HTTPMetadata + readonly customMetadata?: Record + readonly range?: R2Range + readonly storageClass: string + readonly ssecKeyMd5?: string + writeHttpMetadata(headers: Headers): void +} +interface R2ObjectBody extends R2Object { + get body(): ReadableStream + get bodyUsed(): boolean + arrayBuffer(): Promise + bytes(): Promise + text(): Promise + json(): Promise + blob(): Promise +} +type R2Range = + | { + offset: number + length?: number + } + | { + offset?: number + length: number + } + | { + suffix: number + } +interface R2Conditional { + etagMatches?: string + etagDoesNotMatch?: string + uploadedBefore?: Date + uploadedAfter?: Date + secondsGranularity?: boolean +} +interface R2GetOptions { + onlyIf?: R2Conditional | Headers + range?: R2Range | Headers + ssecKey?: ArrayBuffer | string +} +interface R2PutOptions { + onlyIf?: R2Conditional | Headers + httpMetadata?: R2HTTPMetadata | Headers + customMetadata?: Record + md5?: (ArrayBuffer | ArrayBufferView) | string + sha1?: (ArrayBuffer | ArrayBufferView) | string + sha256?: (ArrayBuffer | ArrayBufferView) | string + sha384?: (ArrayBuffer | ArrayBufferView) | string + sha512?: (ArrayBuffer | ArrayBufferView) | string + storageClass?: string + ssecKey?: ArrayBuffer | string +} +interface R2MultipartOptions { + httpMetadata?: R2HTTPMetadata | Headers + customMetadata?: Record + storageClass?: string + ssecKey?: ArrayBuffer | string +} +interface R2Checksums { + readonly md5?: ArrayBuffer + readonly sha1?: ArrayBuffer + readonly sha256?: ArrayBuffer + readonly sha384?: ArrayBuffer + readonly sha512?: ArrayBuffer + toJSON(): R2StringChecksums +} +interface R2StringChecksums { + md5?: string + sha1?: string + sha256?: string + sha384?: string + sha512?: string +} +interface R2HTTPMetadata { + contentType?: string + contentLanguage?: string + contentDisposition?: string + contentEncoding?: string + cacheControl?: string + cacheExpiry?: Date +} +type R2Objects = { + objects: R2Object[] + delimitedPrefixes: string[] +} & ( + | { + truncated: true + cursor: string + } + | { + truncated: false + } +) +interface R2UploadPartOptions { + ssecKey?: ArrayBuffer | string +} +declare abstract class ScheduledEvent extends ExtendableEvent { + readonly scheduledTime: number + readonly cron: string + noRetry(): void +} +interface ScheduledController { + readonly scheduledTime: number + readonly cron: string + noRetry(): void +} +interface QueuingStrategy { + highWaterMark?: number | bigint + size?: (chunk: T) => number | bigint +} +interface UnderlyingSink { + type?: string + start?: (controller: WritableStreamDefaultController) => void | Promise + write?: (chunk: W, controller: WritableStreamDefaultController) => void | Promise + abort?: (reason: any) => void | Promise + close?: () => void | Promise +} +interface UnderlyingByteSource { + type: 'bytes' + autoAllocateChunkSize?: number + start?: (controller: ReadableByteStreamController) => void | Promise + pull?: (controller: ReadableByteStreamController) => void | Promise + cancel?: (reason: any) => void | Promise +} +interface UnderlyingSource { + type?: '' | undefined + start?: (controller: ReadableStreamDefaultController) => void | Promise + pull?: (controller: ReadableStreamDefaultController) => void | Promise + cancel?: (reason: any) => void | Promise + expectedLength?: number | bigint +} +interface Transformer { + readableType?: string + writableType?: string + start?: (controller: TransformStreamDefaultController) => void | Promise + transform?: (chunk: I, controller: TransformStreamDefaultController) => void | Promise + flush?: (controller: TransformStreamDefaultController) => void | Promise + cancel?: (reason: any) => void | Promise + expectedLength?: number +} +interface StreamPipeOptions { + /** + * Pipes this readable stream to a given writable stream destination. The way in which the piping process behaves under various error conditions can be customized with a number of passed options. It returns a promise that fulfills when the piping process completes successfully, or rejects if any errors were encountered. + * + * Piping a stream will lock it for the duration of the pipe, preventing any other consumer from acquiring a reader. + * + * Errors and closures of the source and destination streams propagate as follows: + * + * An error in this source readable stream will abort destination, unless preventAbort is truthy. The returned promise will be rejected with the source's error, or with any error that occurs during aborting the destination. + * + * An error in destination will cancel this source readable stream, unless preventCancel is truthy. The returned promise will be rejected with the destination's error, or with any error that occurs during canceling the source. + * + * When this source readable stream closes, destination will be closed, unless preventClose is truthy. The returned promise will be fulfilled once this process completes, unless an error is encountered while closing the destination, in which case it will be rejected with that error. + * + * If destination starts out closed or closing, this source readable stream will be canceled, unless preventCancel is true. The returned promise will be rejected with an error indicating piping to a closed stream failed, or with any error that occurs during canceling the source. + * + * The signal option can be set to an AbortSignal to allow aborting an ongoing pipe operation via the corresponding AbortController. In this case, this source readable stream will be canceled, and destination aborted, unless the respective options preventCancel or preventAbort are set. + */ + preventClose?: boolean + preventAbort?: boolean + preventCancel?: boolean + signal?: AbortSignal +} +type ReadableStreamReadResult = + | { + done: false + value: R + } + | { + done: true + value?: undefined + } +/** + * This Streams API interface represents a readable stream of byte data. The Fetch API offers a concrete instance of a ReadableStream through the body property of a Response object. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/ReadableStream) + */ +interface ReadableStream { + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/ReadableStream/locked) */ + get locked(): boolean + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/ReadableStream/cancel) */ + cancel(reason?: any): Promise + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/ReadableStream/getReader) */ + getReader(): ReadableStreamDefaultReader + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/ReadableStream/getReader) */ + getReader(options: ReadableStreamGetReaderOptions): ReadableStreamBYOBReader + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/ReadableStream/pipeThrough) */ + pipeThrough( + transform: ReadableWritablePair, + options?: StreamPipeOptions + ): ReadableStream + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/ReadableStream/pipeTo) */ + pipeTo(destination: WritableStream, options?: StreamPipeOptions): Promise + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/ReadableStream/tee) */ + tee(): [ReadableStream, ReadableStream] + values(options?: ReadableStreamValuesOptions): AsyncIterableIterator + [Symbol.asyncIterator](options?: ReadableStreamValuesOptions): AsyncIterableIterator +} +/** + * This Streams API interface represents a readable stream of byte data. The Fetch API offers a concrete instance of a ReadableStream through the body property of a Response object. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/ReadableStream) + */ +declare const ReadableStream: { + prototype: ReadableStream + new ( + underlyingSource: UnderlyingByteSource, + strategy?: QueuingStrategy + ): ReadableStream + new ( + underlyingSource?: UnderlyingSource, + strategy?: QueuingStrategy + ): ReadableStream +} +/* [MDN Reference](https://developer.mozilla.org/docs/Web/API/ReadableStreamDefaultReader) */ +declare class ReadableStreamDefaultReader { + constructor(stream: ReadableStream) + get closed(): Promise + cancel(reason?: any): Promise + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/ReadableStreamDefaultReader/read) */ + read(): Promise> + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/ReadableStreamDefaultReader/releaseLock) */ + releaseLock(): void +} +/* [MDN Reference](https://developer.mozilla.org/docs/Web/API/ReadableStreamBYOBReader) */ +declare class ReadableStreamBYOBReader { + constructor(stream: ReadableStream) + get closed(): Promise + cancel(reason?: any): Promise + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/ReadableStreamBYOBReader/read) */ + read(view: T): Promise> + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/ReadableStreamBYOBReader/releaseLock) */ + releaseLock(): void + readAtLeast( + minElements: number, + view: T + ): Promise> +} +interface ReadableStreamBYOBReaderReadableStreamBYOBReaderReadOptions { + min?: number +} +interface ReadableStreamGetReaderOptions { + /** + * Creates a ReadableStreamBYOBReader and locks the stream to the new reader. + * + * This call behaves the same way as the no-argument variant, except that it only works on readable byte streams, i.e. streams which were constructed specifically with the ability to handle "bring your own buffer" reading. The returned BYOB reader provides the ability to directly read individual chunks from the stream via its read() method, into developer-supplied buffers, allowing more precise control over allocation. + */ + mode: 'byob' +} +/* [MDN Reference](https://developer.mozilla.org/docs/Web/API/ReadableStreamBYOBRequest) */ +declare abstract class ReadableStreamBYOBRequest { + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/ReadableStreamBYOBRequest/view) */ + get view(): Uint8Array | null + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/ReadableStreamBYOBRequest/respond) */ + respond(bytesWritten: number): void + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/ReadableStreamBYOBRequest/respondWithNewView) */ + respondWithNewView(view: ArrayBuffer | ArrayBufferView): void + get atLeast(): number | null +} +/* [MDN Reference](https://developer.mozilla.org/docs/Web/API/ReadableStreamDefaultController) */ +declare abstract class ReadableStreamDefaultController { + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/ReadableStreamDefaultController/desiredSize) */ + get desiredSize(): number | null + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/ReadableStreamDefaultController/close) */ + close(): void + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/ReadableStreamDefaultController/enqueue) */ + enqueue(chunk?: R): void + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/ReadableStreamDefaultController/error) */ + error(reason: any): void +} +/* [MDN Reference](https://developer.mozilla.org/docs/Web/API/ReadableByteStreamController) */ +declare abstract class ReadableByteStreamController { + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/ReadableByteStreamController/byobRequest) */ + get byobRequest(): ReadableStreamBYOBRequest | null + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/ReadableByteStreamController/desiredSize) */ + get desiredSize(): number | null + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/ReadableByteStreamController/close) */ + close(): void + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/ReadableByteStreamController/enqueue) */ + enqueue(chunk: ArrayBuffer | ArrayBufferView): void + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/ReadableByteStreamController/error) */ + error(reason: any): void +} +/** + * This Streams API interface represents a controller allowing control of a WritableStream's state. When constructing a WritableStream, the underlying sink is given a corresponding WritableStreamDefaultController instance to manipulate. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/WritableStreamDefaultController) + */ +declare abstract class WritableStreamDefaultController { + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/WritableStreamDefaultController/signal) */ + get signal(): AbortSignal + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/WritableStreamDefaultController/error) */ + error(reason?: any): void +} +/* [MDN Reference](https://developer.mozilla.org/docs/Web/API/TransformStreamDefaultController) */ +declare abstract class TransformStreamDefaultController { + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/TransformStreamDefaultController/desiredSize) */ + get desiredSize(): number | null + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/TransformStreamDefaultController/enqueue) */ + enqueue(chunk?: O): void + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/TransformStreamDefaultController/error) */ + error(reason: any): void + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/TransformStreamDefaultController/terminate) */ + terminate(): void +} +interface ReadableWritablePair { + /** + * Provides a convenient, chainable way of piping this readable stream through a transform stream (or any other { writable, readable } pair). It simply pipes the stream into the writable side of the supplied pair, and returns the readable side for further use. + * + * Piping a stream will lock it for the duration of the pipe, preventing any other consumer from acquiring a reader. + */ + writable: WritableStream + readable: ReadableStream +} +/** + * This Streams API interface provides a standard abstraction for writing streaming data to a destination, known as a sink. This object comes with built-in backpressure and queuing. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/WritableStream) + */ +declare class WritableStream { + constructor(underlyingSink?: UnderlyingSink, queuingStrategy?: QueuingStrategy) + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/WritableStream/locked) */ + get locked(): boolean + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/WritableStream/abort) */ + abort(reason?: any): Promise + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/WritableStream/close) */ + close(): Promise + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/WritableStream/getWriter) */ + getWriter(): WritableStreamDefaultWriter +} +/** + * This Streams API interface is the object returned by WritableStream.getWriter() and once created locks the < writer to the WritableStream ensuring that no other streams can write to the underlying sink. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/WritableStreamDefaultWriter) + */ +declare class WritableStreamDefaultWriter { + constructor(stream: WritableStream) + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/WritableStreamDefaultWriter/closed) */ + get closed(): Promise + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/WritableStreamDefaultWriter/ready) */ + get ready(): Promise + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/WritableStreamDefaultWriter/desiredSize) */ + get desiredSize(): number | null + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/WritableStreamDefaultWriter/abort) */ + abort(reason?: any): Promise + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/WritableStreamDefaultWriter/close) */ + close(): Promise + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/WritableStreamDefaultWriter/write) */ + write(chunk?: W): Promise + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/WritableStreamDefaultWriter/releaseLock) */ + releaseLock(): void +} +/* [MDN Reference](https://developer.mozilla.org/docs/Web/API/TransformStream) */ +declare class TransformStream { + constructor( + transformer?: Transformer, + writableStrategy?: QueuingStrategy, + readableStrategy?: QueuingStrategy + ) + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/TransformStream/readable) */ + get readable(): ReadableStream + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/TransformStream/writable) */ + get writable(): WritableStream +} +declare class FixedLengthStream extends IdentityTransformStream { + constructor( + expectedLength: number | bigint, + queuingStrategy?: IdentityTransformStreamQueuingStrategy + ) +} +declare class IdentityTransformStream extends TransformStream< + ArrayBuffer | ArrayBufferView, + Uint8Array +> { + constructor(queuingStrategy?: IdentityTransformStreamQueuingStrategy) +} +interface IdentityTransformStreamQueuingStrategy { + highWaterMark?: number | bigint +} +interface ReadableStreamValuesOptions { + preventCancel?: boolean +} +/* [MDN Reference](https://developer.mozilla.org/docs/Web/API/CompressionStream) */ +declare class CompressionStream extends TransformStream { + constructor(format: 'gzip' | 'deflate' | 'deflate-raw') +} +/* [MDN Reference](https://developer.mozilla.org/docs/Web/API/DecompressionStream) */ +declare class DecompressionStream extends TransformStream< + ArrayBuffer | ArrayBufferView, + Uint8Array +> { + constructor(format: 'gzip' | 'deflate' | 'deflate-raw') +} +/* [MDN Reference](https://developer.mozilla.org/docs/Web/API/TextEncoderStream) */ +declare class TextEncoderStream extends TransformStream { + constructor() + get encoding(): string +} +/* [MDN Reference](https://developer.mozilla.org/docs/Web/API/TextDecoderStream) */ +declare class TextDecoderStream extends TransformStream { + constructor(label?: string, options?: TextDecoderStreamTextDecoderStreamInit) + get encoding(): string + get fatal(): boolean + get ignoreBOM(): boolean +} +interface TextDecoderStreamTextDecoderStreamInit { + fatal?: boolean + ignoreBOM?: boolean +} +/** + * This Streams API interface provides a built-in byte length queuing strategy that can be used when constructing streams. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/ByteLengthQueuingStrategy) + */ +declare class ByteLengthQueuingStrategy implements QueuingStrategy { + constructor(init: QueuingStrategyInit) + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/ByteLengthQueuingStrategy/highWaterMark) */ + get highWaterMark(): number + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/ByteLengthQueuingStrategy/size) */ + get size(): (chunk?: any) => number +} +/** + * This Streams API interface provides a built-in byte length queuing strategy that can be used when constructing streams. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/CountQueuingStrategy) + */ +declare class CountQueuingStrategy implements QueuingStrategy { + constructor(init: QueuingStrategyInit) + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/CountQueuingStrategy/highWaterMark) */ + get highWaterMark(): number + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/CountQueuingStrategy/size) */ + get size(): (chunk?: any) => number +} +interface QueuingStrategyInit { + /** + * Creates a new ByteLengthQueuingStrategy with the provided high water mark. + * + * Note that the provided high water mark will not be validated ahead of time. Instead, if it is negative, NaN, or not a number, the resulting ByteLengthQueuingStrategy will cause the corresponding stream constructor to throw. + */ + highWaterMark: number +} +interface ScriptVersion { + id?: string + tag?: string + message?: string +} +declare abstract class TailEvent extends ExtendableEvent { + readonly events: TraceItem[] + readonly traces: TraceItem[] +} +interface TraceItem { + readonly event: + | ( + | TraceItemFetchEventInfo + | TraceItemJsRpcEventInfo + | TraceItemScheduledEventInfo + | TraceItemAlarmEventInfo + | TraceItemQueueEventInfo + | TraceItemEmailEventInfo + | TraceItemTailEventInfo + | TraceItemCustomEventInfo + | TraceItemHibernatableWebSocketEventInfo + ) + | null + readonly eventTimestamp: number | null + readonly logs: TraceLog[] + readonly exceptions: TraceException[] + readonly diagnosticsChannelEvents: TraceDiagnosticChannelEvent[] + readonly scriptName: string | null + readonly entrypoint?: string + readonly scriptVersion?: ScriptVersion + readonly dispatchNamespace?: string + readonly scriptTags?: string[] + readonly outcome: string + readonly executionModel: string + readonly truncated: boolean + readonly cpuTime: number + readonly wallTime: number +} +interface TraceItemAlarmEventInfo { + readonly scheduledTime: Date +} +interface TraceItemCustomEventInfo {} +interface TraceItemScheduledEventInfo { + readonly scheduledTime: number + readonly cron: string +} +interface TraceItemQueueEventInfo { + readonly queue: string + readonly batchSize: number +} +interface TraceItemEmailEventInfo { + readonly mailFrom: string + readonly rcptTo: string + readonly rawSize: number +} +interface TraceItemTailEventInfo { + readonly consumedEvents: TraceItemTailEventInfoTailItem[] +} +interface TraceItemTailEventInfoTailItem { + readonly scriptName: string | null +} +interface TraceItemFetchEventInfo { + readonly response?: TraceItemFetchEventInfoResponse + readonly request: TraceItemFetchEventInfoRequest +} +interface TraceItemFetchEventInfoRequest { + readonly cf?: any + readonly headers: Record + readonly method: string + readonly url: string + getUnredacted(): TraceItemFetchEventInfoRequest +} +interface TraceItemFetchEventInfoResponse { + readonly status: number +} +interface TraceItemJsRpcEventInfo { + readonly rpcMethod: string +} +interface TraceItemHibernatableWebSocketEventInfo { + readonly getWebSocketEvent: + | TraceItemHibernatableWebSocketEventInfoMessage + | TraceItemHibernatableWebSocketEventInfoClose + | TraceItemHibernatableWebSocketEventInfoError +} +interface TraceItemHibernatableWebSocketEventInfoMessage { + readonly webSocketEventType: string +} +interface TraceItemHibernatableWebSocketEventInfoClose { + readonly webSocketEventType: string + readonly code: number + readonly wasClean: boolean +} +interface TraceItemHibernatableWebSocketEventInfoError { + readonly webSocketEventType: string +} +interface TraceLog { + readonly timestamp: number + readonly level: string + readonly message: any +} +interface TraceException { + readonly timestamp: number + readonly message: string + readonly name: string + readonly stack?: string +} +interface TraceDiagnosticChannelEvent { + readonly timestamp: number + readonly channel: string + readonly message: any +} +interface TraceMetrics { + readonly cpuTime: number + readonly wallTime: number +} +interface UnsafeTraceMetrics { + fromTrace(item: TraceItem): TraceMetrics +} +/** + * The URL interface represents an object providing static methods used for creating object URLs. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/URL) + */ +declare class URL { + constructor(url: string | URL, base?: string | URL) + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/URL/origin) */ + get origin(): string + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/URL/href) */ + get href(): string + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/URL/href) */ + set href(value: string) + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/URL/protocol) */ + get protocol(): string + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/URL/protocol) */ + set protocol(value: string) + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/URL/username) */ + get username(): string + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/URL/username) */ + set username(value: string) + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/URL/password) */ + get password(): string + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/URL/password) */ + set password(value: string) + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/URL/host) */ + get host(): string + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/URL/host) */ + set host(value: string) + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/URL/hostname) */ + get hostname(): string + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/URL/hostname) */ + set hostname(value: string) + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/URL/port) */ + get port(): string + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/URL/port) */ + set port(value: string) + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/URL/pathname) */ + get pathname(): string + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/URL/pathname) */ + set pathname(value: string) + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/URL/search) */ + get search(): string + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/URL/search) */ + set search(value: string) + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/URL/hash) */ + get hash(): string + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/URL/hash) */ + set hash(value: string) + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/URL/searchParams) */ + get searchParams(): URLSearchParams + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/URL/toJSON) */ + toJSON(): string + /*function toString() { [native code] }*/ + toString(): string + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/URL/canParse_static) */ + static canParse(url: string, base?: string): boolean + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/URL/parse_static) */ + static parse(url: string, base?: string): URL | null + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/URL/createObjectURL_static) */ + static createObjectURL(object: File | Blob): string + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/URL/revokeObjectURL_static) */ + static revokeObjectURL(object_url: string): void +} +/* [MDN Reference](https://developer.mozilla.org/docs/Web/API/URLSearchParams) */ +declare class URLSearchParams { + constructor(init?: Iterable> | Record | string) + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/URLSearchParams/size) */ + get size(): number + /** + * Appends a specified key/value pair as a new search parameter. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/URLSearchParams/append) + */ + append(name: string, value: string): void + /** + * Deletes the given search parameter, and its associated value, from the list of all search parameters. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/URLSearchParams/delete) + */ + delete(name: string, value?: string): void + /** + * Returns the first value associated to the given search parameter. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/URLSearchParams/get) + */ + get(name: string): string | null + /** + * Returns all the values association with a given search parameter. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/URLSearchParams/getAll) + */ + getAll(name: string): string[] + /** + * Returns a Boolean indicating if such a search parameter exists. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/URLSearchParams/has) + */ + has(name: string, value?: string): boolean + /** + * Sets the value associated to a given search parameter to the given value. If there were several values, delete the others. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/URLSearchParams/set) + */ + set(name: string, value: string): void + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/URLSearchParams/sort) */ + sort(): void + /* Returns an array of key, value pairs for every entry in the search params. */ + entries(): IterableIterator<[key: string, value: string]> + /* Returns a list of keys in the search params. */ + keys(): IterableIterator + /* Returns a list of values in the search params. */ + values(): IterableIterator + forEach( + callback: (this: This, value: string, key: string, parent: URLSearchParams) => void, + thisArg?: This + ): void + /*function toString() { [native code] } Returns a string containing a query string suitable for use in a URL. Does not include the question mark. */ + toString(): string + [Symbol.iterator](): IterableIterator<[key: string, value: string]> +} +declare class URLPattern { + constructor( + input?: string | URLPatternInit, + baseURL?: string | URLPatternOptions, + patternOptions?: URLPatternOptions + ) + get protocol(): string + get username(): string + get password(): string + get hostname(): string + get port(): string + get pathname(): string + get search(): string + get hash(): string + get hasRegExpGroups(): boolean + test(input?: string | URLPatternInit, baseURL?: string): boolean + exec(input?: string | URLPatternInit, baseURL?: string): URLPatternResult | null +} +interface URLPatternInit { + protocol?: string + username?: string + password?: string + hostname?: string + port?: string + pathname?: string + search?: string + hash?: string + baseURL?: string +} +interface URLPatternComponentResult { + input: string + groups: Record +} +interface URLPatternResult { + inputs: (string | URLPatternInit)[] + protocol: URLPatternComponentResult + username: URLPatternComponentResult + password: URLPatternComponentResult + hostname: URLPatternComponentResult + port: URLPatternComponentResult + pathname: URLPatternComponentResult + search: URLPatternComponentResult + hash: URLPatternComponentResult +} +interface URLPatternOptions { + ignoreCase?: boolean +} +/** + * A CloseEvent is sent to clients using WebSockets when the connection is closed. This is delivered to the listener indicated by the WebSocket object's onclose attribute. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/CloseEvent) + */ +declare class CloseEvent extends Event { + constructor(type: string, initializer?: CloseEventInit) + /** + * Returns the WebSocket connection close code provided by the server. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/CloseEvent/code) + */ + readonly code: number + /** + * Returns the WebSocket connection close reason provided by the server. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/CloseEvent/reason) + */ + readonly reason: string + /** + * Returns true if the connection closed cleanly; false otherwise. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/CloseEvent/wasClean) + */ + readonly wasClean: boolean +} +interface CloseEventInit { + code?: number + reason?: string + wasClean?: boolean +} +/** + * A message received by a target object. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/MessageEvent) + */ +declare class MessageEvent extends Event { + constructor(type: string, initializer: MessageEventInit) + /** + * Returns the data of the message. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/MessageEvent/data) + */ + readonly data: ArrayBuffer | string +} +interface MessageEventInit { + data: ArrayBuffer | string +} +type WebSocketEventMap = { + close: CloseEvent + message: MessageEvent + open: Event + error: ErrorEvent +} +/** + * Provides the API for creating and managing a WebSocket connection to a server, as well as for sending and receiving data on the connection. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/WebSocket) + */ +declare var WebSocket: { + prototype: WebSocket + new (url: string, protocols?: string[] | string): WebSocket + readonly READY_STATE_CONNECTING: number + readonly CONNECTING: number + readonly READY_STATE_OPEN: number + readonly OPEN: number + readonly READY_STATE_CLOSING: number + readonly CLOSING: number + readonly READY_STATE_CLOSED: number + readonly CLOSED: number +} +/** + * Provides the API for creating and managing a WebSocket connection to a server, as well as for sending and receiving data on the connection. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/WebSocket) + */ +interface WebSocket extends EventTarget { + accept(): void + /** + * Transmits data using the WebSocket connection. data can be a string, a Blob, an ArrayBuffer, or an ArrayBufferView. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/WebSocket/send) + */ + send(message: (ArrayBuffer | ArrayBufferView) | string): void + /** + * Closes the WebSocket connection, optionally using code as the the WebSocket connection close code and reason as the the WebSocket connection close reason. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/WebSocket/close) + */ + close(code?: number, reason?: string): void + serializeAttachment(attachment: any): void + deserializeAttachment(): any | null + /** + * Returns the state of the WebSocket object's connection. It can have the values described below. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/WebSocket/readyState) + */ + readyState: number + /** + * Returns the URL that was used to establish the WebSocket connection. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/WebSocket/url) + */ + url: string | null + /** + * Returns the subprotocol selected by the server, if any. It can be used in conjunction with the array form of the constructor's second argument to perform subprotocol negotiation. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/WebSocket/protocol) + */ + protocol: string | null + /** + * Returns the extensions selected by the server, if any. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/WebSocket/extensions) + */ + extensions: string | null +} +declare const WebSocketPair: { + new (): { + 0: WebSocket + 1: WebSocket + } +} +interface SqlStorage { + exec>( + query: string, + ...bindings: any[] + ): SqlStorageCursor + get databaseSize(): number + Cursor: typeof SqlStorageCursor + Statement: typeof SqlStorageStatement +} +declare abstract class SqlStorageStatement {} +type SqlStorageValue = ArrayBuffer | string | number | null +declare abstract class SqlStorageCursor> { + next(): + | { + done?: false + value: T + } + | { + done: true + value?: never + } + toArray(): T[] + one(): T + raw(): IterableIterator + columnNames: string[] + get rowsRead(): number + get rowsWritten(): number + [Symbol.iterator](): IterableIterator +} +interface Socket { + get readable(): ReadableStream + get writable(): WritableStream + get closed(): Promise + get opened(): Promise + get upgraded(): boolean + get secureTransport(): 'on' | 'off' | 'starttls' + close(): Promise + startTls(options?: TlsOptions): Socket +} +interface SocketOptions { + secureTransport?: string + allowHalfOpen: boolean + highWaterMark?: number | bigint +} +interface SocketAddress { + hostname: string + port: number +} +interface TlsOptions { + expectedServerHostname?: string +} +interface SocketInfo { + remoteAddress?: string + localAddress?: string +} +/* [MDN Reference](https://developer.mozilla.org/docs/Web/API/EventSource) */ +declare class EventSource extends EventTarget { + constructor(url: string, init?: EventSourceEventSourceInit) + /** + * Aborts any instances of the fetch algorithm started for this EventSource object, and sets the readyState attribute to CLOSED. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/EventSource/close) + */ + close(): void + /** + * Returns the URL providing the event stream. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/EventSource/url) + */ + get url(): string + /** + * Returns true if the credentials mode for connection requests to the URL providing the event stream is set to "include", and false otherwise. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/EventSource/withCredentials) + */ + get withCredentials(): boolean + /** + * Returns the state of this EventSource object's connection. It can have the values described below. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/EventSource/readyState) + */ + get readyState(): number + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/EventSource/open_event) */ + get onopen(): any | null + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/EventSource/open_event) */ + set onopen(value: any | null) + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/EventSource/message_event) */ + get onmessage(): any | null + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/EventSource/message_event) */ + set onmessage(value: any | null) + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/EventSource/error_event) */ + get onerror(): any | null + /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/EventSource/error_event) */ + set onerror(value: any | null) + static readonly CONNECTING: number + static readonly OPEN: number + static readonly CLOSED: number + static from(stream: ReadableStream): EventSource +} +interface EventSourceEventSourceInit { + withCredentials?: boolean + fetcher?: Fetcher +} +interface Container { + get running(): boolean + start(options?: ContainerStartupOptions): void + monitor(): Promise + destroy(error?: any): Promise + signal(signo: number): void + getTcpPort(port: number): Fetcher +} +interface ContainerStartupOptions { + entrypoint?: string[] + enableInternet: boolean + env?: Record +} +type AiImageClassificationInput = { + image: number[] +} +type AiImageClassificationOutput = { + score?: number + label?: string +}[] +declare abstract class BaseAiImageClassification { + inputs: AiImageClassificationInput + postProcessedOutputs: AiImageClassificationOutput +} +type AiImageToTextInput = { + image: number[] + prompt?: string + max_tokens?: number + temperature?: number + top_p?: number + top_k?: number + seed?: number + repetition_penalty?: number + frequency_penalty?: number + presence_penalty?: number + raw?: boolean + messages?: RoleScopedChatInput[] +} +type AiImageToTextOutput = { + description: string +} +declare abstract class BaseAiImageToText { + inputs: AiImageToTextInput + postProcessedOutputs: AiImageToTextOutput +} +type AiImageTextToTextInput = { + image: string + prompt?: string + max_tokens?: number + temperature?: number + ignore_eos?: boolean + top_p?: number + top_k?: number + seed?: number + repetition_penalty?: number + frequency_penalty?: number + presence_penalty?: number + raw?: boolean + messages?: RoleScopedChatInput[] +} +type AiImageTextToTextOutput = { + description: string +} +declare abstract class BaseAiImageTextToText { + inputs: AiImageTextToTextInput + postProcessedOutputs: AiImageTextToTextOutput +} +type AiObjectDetectionInput = { + image: number[] +} +type AiObjectDetectionOutput = { + score?: number + label?: string +}[] +declare abstract class BaseAiObjectDetection { + inputs: AiObjectDetectionInput + postProcessedOutputs: AiObjectDetectionOutput +} +type AiSentenceSimilarityInput = { + source: string + sentences: string[] +} +type AiSentenceSimilarityOutput = number[] +declare abstract class BaseAiSentenceSimilarity { + inputs: AiSentenceSimilarityInput + postProcessedOutputs: AiSentenceSimilarityOutput +} +type AiAutomaticSpeechRecognitionInput = { + audio: number[] +} +type AiAutomaticSpeechRecognitionOutput = { + text?: string + words?: { + word: string + start: number + end: number + }[] + vtt?: string +} +declare abstract class BaseAiAutomaticSpeechRecognition { + inputs: AiAutomaticSpeechRecognitionInput + postProcessedOutputs: AiAutomaticSpeechRecognitionOutput +} +type AiSummarizationInput = { + input_text: string + max_length?: number +} +type AiSummarizationOutput = { + summary: string +} +declare abstract class BaseAiSummarization { + inputs: AiSummarizationInput + postProcessedOutputs: AiSummarizationOutput +} +type AiTextClassificationInput = { + text: string +} +type AiTextClassificationOutput = { + score?: number + label?: string +}[] +declare abstract class BaseAiTextClassification { + inputs: AiTextClassificationInput + postProcessedOutputs: AiTextClassificationOutput +} +type AiTextEmbeddingsInput = { + text: string | string[] +} +type AiTextEmbeddingsOutput = { + shape: number[] + data: number[][] +} +declare abstract class BaseAiTextEmbeddings { + inputs: AiTextEmbeddingsInput + postProcessedOutputs: AiTextEmbeddingsOutput +} +type RoleScopedChatInput = { + role: 'user' | 'assistant' | 'system' | 'tool' | (string & NonNullable) + content: string + name?: string +} +type AiTextGenerationToolLegacyInput = { + name: string + description: string + parameters?: { + type: 'object' | (string & NonNullable) + properties: { + [key: string]: { + type: string + description?: string + } + } + required: string[] + } +} +type AiTextGenerationToolInput = { + type: 'function' | (string & NonNullable) + function: { + name: string + description: string + parameters?: { + type: 'object' | (string & NonNullable) + properties: { + [key: string]: { + type: string + description?: string + } + } + required: string[] + } + } +} +type AiTextGenerationFunctionsInput = { + name: string + code: string +} +type AiTextGenerationResponseFormat = { + type: string + json_schema?: any +} +type AiTextGenerationInput = { + prompt?: string + raw?: boolean + stream?: boolean + max_tokens?: number + temperature?: number + top_p?: number + top_k?: number + seed?: number + repetition_penalty?: number + frequency_penalty?: number + presence_penalty?: number + messages?: RoleScopedChatInput[] + response_format?: AiTextGenerationResponseFormat + tools?: + | AiTextGenerationToolInput[] + | AiTextGenerationToolLegacyInput[] + | (object & NonNullable) + functions?: AiTextGenerationFunctionsInput[] +} +type AiTextGenerationOutput = { + response?: string + tool_calls?: { + name: string + arguments: unknown + }[] +} +declare abstract class BaseAiTextGeneration { + inputs: AiTextGenerationInput + postProcessedOutputs: AiTextGenerationOutput +} +type AiTextToSpeechInput = { + prompt: string + lang?: string +} +type AiTextToSpeechOutput = + | Uint8Array + | { + audio: string + } +declare abstract class BaseAiTextToSpeech { + inputs: AiTextToSpeechInput + postProcessedOutputs: AiTextToSpeechOutput +} +type AiTextToImageInput = { + prompt: string + negative_prompt?: string + height?: number + width?: number + image?: number[] + image_b64?: string + mask?: number[] + num_steps?: number + strength?: number + guidance?: number + seed?: number +} +type AiTextToImageOutput = ReadableStream +declare abstract class BaseAiTextToImage { + inputs: AiTextToImageInput + postProcessedOutputs: AiTextToImageOutput +} +type AiTranslationInput = { + text: string + target_lang: string + source_lang?: string +} +type AiTranslationOutput = { + translated_text?: string +} +declare abstract class BaseAiTranslation { + inputs: AiTranslationInput + postProcessedOutputs: AiTranslationOutput +} +type Ai_Cf_Baai_Bge_Base_En_V1_5_Input = + | { + text: string | string[] + /** + * The pooling method used in the embedding process. `cls` pooling will generate more accurate embeddings on larger inputs - however, embeddings created with cls pooling are not compatible with embeddings generated with mean pooling. The default pooling method is `mean` in order for this to not be a breaking change, but we highly suggest using the new `cls` pooling for better accuracy. + */ + pooling?: 'mean' | 'cls' + } + | { + /** + * Batch of the embeddings requests to run using async-queue + */ + requests: { + text: string | string[] + /** + * The pooling method used in the embedding process. `cls` pooling will generate more accurate embeddings on larger inputs - however, embeddings created with cls pooling are not compatible with embeddings generated with mean pooling. The default pooling method is `mean` in order for this to not be a breaking change, but we highly suggest using the new `cls` pooling for better accuracy. + */ + pooling?: 'mean' | 'cls' + }[] + } +type Ai_Cf_Baai_Bge_Base_En_V1_5_Output = + | { + shape?: number[] + /** + * Embeddings of the requested text values + */ + data?: number[][] + /** + * The pooling method used in the embedding process. + */ + pooling?: 'mean' | 'cls' + } + | AsyncResponse +interface AsyncResponse { + /** + * The async request id that can be used to obtain the results. + */ + request_id?: string +} +declare abstract class Base_Ai_Cf_Baai_Bge_Base_En_V1_5 { + inputs: Ai_Cf_Baai_Bge_Base_En_V1_5_Input + postProcessedOutputs: Ai_Cf_Baai_Bge_Base_En_V1_5_Output +} +type Ai_Cf_Openai_Whisper_Input = + | string + | { + /** + * An array of integers that represent the audio data constrained to 8-bit unsigned integer values + */ + audio: number[] + } +interface Ai_Cf_Openai_Whisper_Output { + /** + * The transcription + */ + text: string + word_count?: number + words?: { + word?: string + /** + * The second this word begins in the recording + */ + start?: number + /** + * The ending second when the word completes + */ + end?: number + }[] + vtt?: string +} +declare abstract class Base_Ai_Cf_Openai_Whisper { + inputs: Ai_Cf_Openai_Whisper_Input + postProcessedOutputs: Ai_Cf_Openai_Whisper_Output +} +type Ai_Cf_Meta_M2M100_1_2B_Input = + | { + /** + * The text to be translated + */ + text: string + /** + * The language code of the source text (e.g., 'en' for English). Defaults to 'en' if not specified + */ + source_lang?: string + /** + * The language code to translate the text into (e.g., 'es' for Spanish) + */ + target_lang: string + } + | { + /** + * Batch of the embeddings requests to run using async-queue + */ + requests: { + /** + * The text to be translated + */ + text: string + /** + * The language code of the source text (e.g., 'en' for English). Defaults to 'en' if not specified + */ + source_lang?: string + /** + * The language code to translate the text into (e.g., 'es' for Spanish) + */ + target_lang: string + }[] + } +type Ai_Cf_Meta_M2M100_1_2B_Output = + | { + /** + * The translated text in the target language + */ + translated_text?: string + } + | AsyncResponse +declare abstract class Base_Ai_Cf_Meta_M2M100_1_2B { + inputs: Ai_Cf_Meta_M2M100_1_2B_Input + postProcessedOutputs: Ai_Cf_Meta_M2M100_1_2B_Output +} +type Ai_Cf_Baai_Bge_Small_En_V1_5_Input = + | { + text: string | string[] + /** + * The pooling method used in the embedding process. `cls` pooling will generate more accurate embeddings on larger inputs - however, embeddings created with cls pooling are not compatible with embeddings generated with mean pooling. The default pooling method is `mean` in order for this to not be a breaking change, but we highly suggest using the new `cls` pooling for better accuracy. + */ + pooling?: 'mean' | 'cls' + } + | { + /** + * Batch of the embeddings requests to run using async-queue + */ + requests: { + text: string | string[] + /** + * The pooling method used in the embedding process. `cls` pooling will generate more accurate embeddings on larger inputs - however, embeddings created with cls pooling are not compatible with embeddings generated with mean pooling. The default pooling method is `mean` in order for this to not be a breaking change, but we highly suggest using the new `cls` pooling for better accuracy. + */ + pooling?: 'mean' | 'cls' + }[] + } +type Ai_Cf_Baai_Bge_Small_En_V1_5_Output = + | { + shape?: number[] + /** + * Embeddings of the requested text values + */ + data?: number[][] + /** + * The pooling method used in the embedding process. + */ + pooling?: 'mean' | 'cls' + } + | AsyncResponse +declare abstract class Base_Ai_Cf_Baai_Bge_Small_En_V1_5 { + inputs: Ai_Cf_Baai_Bge_Small_En_V1_5_Input + postProcessedOutputs: Ai_Cf_Baai_Bge_Small_En_V1_5_Output +} +type Ai_Cf_Baai_Bge_Large_En_V1_5_Input = + | { + text: string | string[] + /** + * The pooling method used in the embedding process. `cls` pooling will generate more accurate embeddings on larger inputs - however, embeddings created with cls pooling are not compatible with embeddings generated with mean pooling. The default pooling method is `mean` in order for this to not be a breaking change, but we highly suggest using the new `cls` pooling for better accuracy. + */ + pooling?: 'mean' | 'cls' + } + | { + /** + * Batch of the embeddings requests to run using async-queue + */ + requests: { + text: string | string[] + /** + * The pooling method used in the embedding process. `cls` pooling will generate more accurate embeddings on larger inputs - however, embeddings created with cls pooling are not compatible with embeddings generated with mean pooling. The default pooling method is `mean` in order for this to not be a breaking change, but we highly suggest using the new `cls` pooling for better accuracy. + */ + pooling?: 'mean' | 'cls' + }[] + } +type Ai_Cf_Baai_Bge_Large_En_V1_5_Output = + | { + shape?: number[] + /** + * Embeddings of the requested text values + */ + data?: number[][] + /** + * The pooling method used in the embedding process. + */ + pooling?: 'mean' | 'cls' + } + | AsyncResponse +declare abstract class Base_Ai_Cf_Baai_Bge_Large_En_V1_5 { + inputs: Ai_Cf_Baai_Bge_Large_En_V1_5_Input + postProcessedOutputs: Ai_Cf_Baai_Bge_Large_En_V1_5_Output +} +type Ai_Cf_Unum_Uform_Gen2_Qwen_500M_Input = + | string + | { + /** + * The input text prompt for the model to generate a response. + */ + prompt?: string + /** + * If true, a chat template is not applied and you must adhere to the specific model's expected formatting. + */ + raw?: boolean + /** + * Controls the creativity of the AI's responses by adjusting how many possible words it considers. Lower values make outputs more predictable; higher values allow for more varied and creative responses. + */ + top_p?: number + /** + * Limits the AI to choose from the top 'k' most probable words. Lower values make responses more focused; higher values introduce more variety and potential surprises. + */ + top_k?: number + /** + * Random seed for reproducibility of the generation. + */ + seed?: number + /** + * Penalty for repeated tokens; higher values discourage repetition. + */ + repetition_penalty?: number + /** + * Decreases the likelihood of the model repeating the same lines verbatim. + */ + frequency_penalty?: number + /** + * Increases the likelihood of the model introducing new topics. + */ + presence_penalty?: number + image: number[] | (string & NonNullable) + /** + * The maximum number of tokens to generate in the response. + */ + max_tokens?: number + } +interface Ai_Cf_Unum_Uform_Gen2_Qwen_500M_Output { + description?: string +} +declare abstract class Base_Ai_Cf_Unum_Uform_Gen2_Qwen_500M { + inputs: Ai_Cf_Unum_Uform_Gen2_Qwen_500M_Input + postProcessedOutputs: Ai_Cf_Unum_Uform_Gen2_Qwen_500M_Output +} +type Ai_Cf_Openai_Whisper_Tiny_En_Input = + | string + | { + /** + * An array of integers that represent the audio data constrained to 8-bit unsigned integer values + */ + audio: number[] + } +interface Ai_Cf_Openai_Whisper_Tiny_En_Output { + /** + * The transcription + */ + text: string + word_count?: number + words?: { + word?: string + /** + * The second this word begins in the recording + */ + start?: number + /** + * The ending second when the word completes + */ + end?: number + }[] + vtt?: string +} +declare abstract class Base_Ai_Cf_Openai_Whisper_Tiny_En { + inputs: Ai_Cf_Openai_Whisper_Tiny_En_Input + postProcessedOutputs: Ai_Cf_Openai_Whisper_Tiny_En_Output +} +interface Ai_Cf_Openai_Whisper_Large_V3_Turbo_Input { + /** + * Base64 encoded value of the audio data. + */ + audio: string + /** + * Supported tasks are 'translate' or 'transcribe'. + */ + task?: string + /** + * The language of the audio being transcribed or translated. + */ + language?: string + /** + * Preprocess the audio with a voice activity detection model. + */ + vad_filter?: boolean + /** + * A text prompt to help provide context to the model on the contents of the audio. + */ + initial_prompt?: string + /** + * The prefix it appended the the beginning of the output of the transcription and can guide the transcription result. + */ + prefix?: string +} +interface Ai_Cf_Openai_Whisper_Large_V3_Turbo_Output { + transcription_info?: { + /** + * The language of the audio being transcribed or translated. + */ + language?: string + /** + * The confidence level or probability of the detected language being accurate, represented as a decimal between 0 and 1. + */ + language_probability?: number + /** + * The total duration of the original audio file, in seconds. + */ + duration?: number + /** + * The duration of the audio after applying Voice Activity Detection (VAD) to remove silent or irrelevant sections, in seconds. + */ + duration_after_vad?: number + } + /** + * The complete transcription of the audio. + */ + text: string + /** + * The total number of words in the transcription. + */ + word_count?: number + segments?: { + /** + * The starting time of the segment within the audio, in seconds. + */ + start?: number + /** + * The ending time of the segment within the audio, in seconds. + */ + end?: number + /** + * The transcription of the segment. + */ + text?: string + /** + * The temperature used in the decoding process, controlling randomness in predictions. Lower values result in more deterministic outputs. + */ + temperature?: number + /** + * The average log probability of the predictions for the words in this segment, indicating overall confidence. + */ + avg_logprob?: number + /** + * The compression ratio of the input to the output, measuring how much the text was compressed during the transcription process. + */ + compression_ratio?: number + /** + * The probability that the segment contains no speech, represented as a decimal between 0 and 1. + */ + no_speech_prob?: number + words?: { + /** + * The individual word transcribed from the audio. + */ + word?: string + /** + * The starting time of the word within the audio, in seconds. + */ + start?: number + /** + * The ending time of the word within the audio, in seconds. + */ + end?: number + }[] + }[] + /** + * The transcription in WebVTT format, which includes timing and text information for use in subtitles. + */ + vtt?: string +} +declare abstract class Base_Ai_Cf_Openai_Whisper_Large_V3_Turbo { + inputs: Ai_Cf_Openai_Whisper_Large_V3_Turbo_Input + postProcessedOutputs: Ai_Cf_Openai_Whisper_Large_V3_Turbo_Output +} +type Ai_Cf_Baai_Bge_M3_Input = + | BGEM3InputQueryAndContexts + | BGEM3InputEmbedding + | { + /** + * Batch of the embeddings requests to run using async-queue + */ + requests: (BGEM3InputQueryAndContexts1 | BGEM3InputEmbedding1)[] + } +interface BGEM3InputQueryAndContexts { + /** + * A query you wish to perform against the provided contexts. If no query is provided the model with respond with embeddings for contexts + */ + query?: string + /** + * List of provided contexts. Note that the index in this array is important, as the response will refer to it. + */ + contexts: { + /** + * One of the provided context content + */ + text?: string + }[] + /** + * When provided with too long context should the model error out or truncate the context to fit? + */ + truncate_inputs?: boolean +} +interface BGEM3InputEmbedding { + text: string | string[] + /** + * When provided with too long context should the model error out or truncate the context to fit? + */ + truncate_inputs?: boolean +} +interface BGEM3InputQueryAndContexts1 { + /** + * A query you wish to perform against the provided contexts. If no query is provided the model with respond with embeddings for contexts + */ + query?: string + /** + * List of provided contexts. Note that the index in this array is important, as the response will refer to it. + */ + contexts: { + /** + * One of the provided context content + */ + text?: string + }[] + /** + * When provided with too long context should the model error out or truncate the context to fit? + */ + truncate_inputs?: boolean +} +interface BGEM3InputEmbedding1 { + text: string | string[] + /** + * When provided with too long context should the model error out or truncate the context to fit? + */ + truncate_inputs?: boolean +} +type Ai_Cf_Baai_Bge_M3_Output = + | BGEM3OuputQuery + | BGEM3OutputEmbeddingForContexts + | BGEM3OuputEmbedding + | AsyncResponse +interface BGEM3OuputQuery { + response?: { + /** + * Index of the context in the request + */ + id?: number + /** + * Score of the context under the index. + */ + score?: number + }[] +} +interface BGEM3OutputEmbeddingForContexts { + response?: number[][] + shape?: number[] + /** + * The pooling method used in the embedding process. + */ + pooling?: 'mean' | 'cls' +} +interface BGEM3OuputEmbedding { + shape?: number[] + /** + * Embeddings of the requested text values + */ + data?: number[][] + /** + * The pooling method used in the embedding process. + */ + pooling?: 'mean' | 'cls' +} +declare abstract class Base_Ai_Cf_Baai_Bge_M3 { + inputs: Ai_Cf_Baai_Bge_M3_Input + postProcessedOutputs: Ai_Cf_Baai_Bge_M3_Output +} +interface Ai_Cf_Black_Forest_Labs_Flux_1_Schnell_Input { + /** + * A text description of the image you want to generate. + */ + prompt: string + /** + * The number of diffusion steps; higher values can improve quality but take longer. + */ + steps?: number +} +interface Ai_Cf_Black_Forest_Labs_Flux_1_Schnell_Output { + /** + * The generated image in Base64 format. + */ + image?: string +} +declare abstract class Base_Ai_Cf_Black_Forest_Labs_Flux_1_Schnell { + inputs: Ai_Cf_Black_Forest_Labs_Flux_1_Schnell_Input + postProcessedOutputs: Ai_Cf_Black_Forest_Labs_Flux_1_Schnell_Output +} +type Ai_Cf_Meta_Llama_3_2_11B_Vision_Instruct_Input = Prompt | Messages +interface Prompt { + /** + * The input text prompt for the model to generate a response. + */ + prompt: string + image?: number[] | (string & NonNullable) + /** + * If true, a chat template is not applied and you must adhere to the specific model's expected formatting. + */ + raw?: boolean + /** + * If true, the response will be streamed back incrementally using SSE, Server Sent Events. + */ + stream?: boolean + /** + * The maximum number of tokens to generate in the response. + */ + max_tokens?: number + /** + * Controls the randomness of the output; higher values produce more random results. + */ + temperature?: number + /** + * Adjusts the creativity of the AI's responses by controlling how many possible words it considers. Lower values make outputs more predictable; higher values allow for more varied and creative responses. + */ + top_p?: number + /** + * Limits the AI to choose from the top 'k' most probable words. Lower values make responses more focused; higher values introduce more variety and potential surprises. + */ + top_k?: number + /** + * Random seed for reproducibility of the generation. + */ + seed?: number + /** + * Penalty for repeated tokens; higher values discourage repetition. + */ + repetition_penalty?: number + /** + * Decreases the likelihood of the model repeating the same lines verbatim. + */ + frequency_penalty?: number + /** + * Increases the likelihood of the model introducing new topics. + */ + presence_penalty?: number + /** + * Name of the LoRA (Low-Rank Adaptation) model to fine-tune the base model. + */ + lora?: string +} +interface Messages { + /** + * An array of message objects representing the conversation history. + */ + messages: { + /** + * The role of the message sender (e.g., 'user', 'assistant', 'system', 'tool'). + */ + role?: string + /** + * The tool call id. Must be supplied for tool calls for Mistral-3. If you don't know what to put here you can fall back to 000000001 + */ + tool_call_id?: string + content?: + | string + | { + /** + * Type of the content provided + */ + type?: string + text?: string + image_url?: { + /** + * image uri with data (e.g. data:image/jpeg;base64,/9j/...). HTTP URL will not be accepted + */ + url?: string + } + }[] + | { + /** + * Type of the content provided + */ + type?: string + text?: string + image_url?: { + /** + * image uri with data (e.g. data:image/jpeg;base64,/9j/...). HTTP URL will not be accepted + */ + url?: string + } + } + }[] + image?: number[] | (string & NonNullable) + functions?: { + name: string + code: string + }[] + /** + * A list of tools available for the assistant to use. + */ + tools?: ( + | { + /** + * The name of the tool. More descriptive the better. + */ + name: string + /** + * A brief description of what the tool does. + */ + description: string + /** + * Schema defining the parameters accepted by the tool. + */ + parameters: { + /** + * The type of the parameters object (usually 'object'). + */ + type: string + /** + * List of required parameter names. + */ + required?: string[] + /** + * Definitions of each parameter. + */ + properties: { + [k: string]: { + /** + * The data type of the parameter. + */ + type: string + /** + * A description of the expected parameter. + */ + description: string + } + } + } + } + | { + /** + * Specifies the type of tool (e.g., 'function'). + */ + type: string + /** + * Details of the function tool. + */ + function: { + /** + * The name of the function. + */ + name: string + /** + * A brief description of what the function does. + */ + description: string + /** + * Schema defining the parameters accepted by the function. + */ + parameters: { + /** + * The type of the parameters object (usually 'object'). + */ + type: string + /** + * List of required parameter names. + */ + required?: string[] + /** + * Definitions of each parameter. + */ + properties: { + [k: string]: { + /** + * The data type of the parameter. + */ + type: string + /** + * A description of the expected parameter. + */ + description: string + } + } + } + } + } + )[] + /** + * If true, the response will be streamed back incrementally. + */ + stream?: boolean + /** + * The maximum number of tokens to generate in the response. + */ + max_tokens?: number + /** + * Controls the randomness of the output; higher values produce more random results. + */ + temperature?: number + /** + * Controls the creativity of the AI's responses by adjusting how many possible words it considers. Lower values make outputs more predictable; higher values allow for more varied and creative responses. + */ + top_p?: number + /** + * Limits the AI to choose from the top 'k' most probable words. Lower values make responses more focused; higher values introduce more variety and potential surprises. + */ + top_k?: number + /** + * Random seed for reproducibility of the generation. + */ + seed?: number + /** + * Penalty for repeated tokens; higher values discourage repetition. + */ + repetition_penalty?: number + /** + * Decreases the likelihood of the model repeating the same lines verbatim. + */ + frequency_penalty?: number + /** + * Increases the likelihood of the model introducing new topics. + */ + presence_penalty?: number +} +type Ai_Cf_Meta_Llama_3_2_11B_Vision_Instruct_Output = { + /** + * The generated text response from the model + */ + response?: string + /** + * An array of tool calls requests made during the response generation + */ + tool_calls?: { + /** + * The arguments passed to be passed to the tool call request + */ + arguments?: object + /** + * The name of the tool to be called + */ + name?: string + }[] +} +declare abstract class Base_Ai_Cf_Meta_Llama_3_2_11B_Vision_Instruct { + inputs: Ai_Cf_Meta_Llama_3_2_11B_Vision_Instruct_Input + postProcessedOutputs: Ai_Cf_Meta_Llama_3_2_11B_Vision_Instruct_Output +} +type Ai_Cf_Meta_Llama_3_3_70B_Instruct_Fp8_Fast_Input = + | Meta_Llama_3_3_70B_Instruct_Fp8_Fast_Prompt + | Meta_Llama_3_3_70B_Instruct_Fp8_Fast_Messages + | AsyncBatch +interface Meta_Llama_3_3_70B_Instruct_Fp8_Fast_Prompt { + /** + * The input text prompt for the model to generate a response. + */ + prompt: string + /** + * Name of the LoRA (Low-Rank Adaptation) model to fine-tune the base model. + */ + lora?: string + response_format?: JSONMode + /** + * If true, a chat template is not applied and you must adhere to the specific model's expected formatting. + */ + raw?: boolean + /** + * If true, the response will be streamed back incrementally using SSE, Server Sent Events. + */ + stream?: boolean + /** + * The maximum number of tokens to generate in the response. + */ + max_tokens?: number + /** + * Controls the randomness of the output; higher values produce more random results. + */ + temperature?: number + /** + * Adjusts the creativity of the AI's responses by controlling how many possible words it considers. Lower values make outputs more predictable; higher values allow for more varied and creative responses. + */ + top_p?: number + /** + * Limits the AI to choose from the top 'k' most probable words. Lower values make responses more focused; higher values introduce more variety and potential surprises. + */ + top_k?: number + /** + * Random seed for reproducibility of the generation. + */ + seed?: number + /** + * Penalty for repeated tokens; higher values discourage repetition. + */ + repetition_penalty?: number + /** + * Decreases the likelihood of the model repeating the same lines verbatim. + */ + frequency_penalty?: number + /** + * Increases the likelihood of the model introducing new topics. + */ + presence_penalty?: number +} +interface JSONMode { + type?: 'json_object' | 'json_schema' + json_schema?: unknown +} +interface Meta_Llama_3_3_70B_Instruct_Fp8_Fast_Messages { + /** + * An array of message objects representing the conversation history. + */ + messages: { + /** + * The role of the message sender (e.g., 'user', 'assistant', 'system', 'tool'). + */ + role: string + /** + * The content of the message as a string. + */ + content: string + }[] + functions?: { + name: string + code: string + }[] + /** + * A list of tools available for the assistant to use. + */ + tools?: ( + | { + /** + * The name of the tool. More descriptive the better. + */ + name: string + /** + * A brief description of what the tool does. + */ + description: string + /** + * Schema defining the parameters accepted by the tool. + */ + parameters: { + /** + * The type of the parameters object (usually 'object'). + */ + type: string + /** + * List of required parameter names. + */ + required?: string[] + /** + * Definitions of each parameter. + */ + properties: { + [k: string]: { + /** + * The data type of the parameter. + */ + type: string + /** + * A description of the expected parameter. + */ + description: string + } + } + } + } + | { + /** + * Specifies the type of tool (e.g., 'function'). + */ + type: string + /** + * Details of the function tool. + */ + function: { + /** + * The name of the function. + */ + name: string + /** + * A brief description of what the function does. + */ + description: string + /** + * Schema defining the parameters accepted by the function. + */ + parameters: { + /** + * The type of the parameters object (usually 'object'). + */ + type: string + /** + * List of required parameter names. + */ + required?: string[] + /** + * Definitions of each parameter. + */ + properties: { + [k: string]: { + /** + * The data type of the parameter. + */ + type: string + /** + * A description of the expected parameter. + */ + description: string + } + } + } + } + } + )[] + response_format?: JSONMode + /** + * If true, a chat template is not applied and you must adhere to the specific model's expected formatting. + */ + raw?: boolean + /** + * If true, the response will be streamed back incrementally using SSE, Server Sent Events. + */ + stream?: boolean + /** + * The maximum number of tokens to generate in the response. + */ + max_tokens?: number + /** + * Controls the randomness of the output; higher values produce more random results. + */ + temperature?: number + /** + * Adjusts the creativity of the AI's responses by controlling how many possible words it considers. Lower values make outputs more predictable; higher values allow for more varied and creative responses. + */ + top_p?: number + /** + * Limits the AI to choose from the top 'k' most probable words. Lower values make responses more focused; higher values introduce more variety and potential surprises. + */ + top_k?: number + /** + * Random seed for reproducibility of the generation. + */ + seed?: number + /** + * Penalty for repeated tokens; higher values discourage repetition. + */ + repetition_penalty?: number + /** + * Decreases the likelihood of the model repeating the same lines verbatim. + */ + frequency_penalty?: number + /** + * Increases the likelihood of the model introducing new topics. + */ + presence_penalty?: number +} +interface AsyncBatch { + requests?: { + /** + * User-supplied reference. This field will be present in the response as well it can be used to reference the request and response. It's NOT validated to be unique. + */ + external_reference?: string + /** + * Prompt for the text generation model + */ + prompt?: string + /** + * If true, the response will be streamed back incrementally using SSE, Server Sent Events. + */ + stream?: boolean + /** + * The maximum number of tokens to generate in the response. + */ + max_tokens?: number + /** + * Controls the randomness of the output; higher values produce more random results. + */ + temperature?: number + /** + * Adjusts the creativity of the AI's responses by controlling how many possible words it considers. Lower values make outputs more predictable; higher values allow for more varied and creative responses. + */ + top_p?: number + /** + * Random seed for reproducibility of the generation. + */ + seed?: number + /** + * Penalty for repeated tokens; higher values discourage repetition. + */ + repetition_penalty?: number + /** + * Decreases the likelihood of the model repeating the same lines verbatim. + */ + frequency_penalty?: number + /** + * Increases the likelihood of the model introducing new topics. + */ + presence_penalty?: number + response_format?: JSONMode + }[] +} +type Ai_Cf_Meta_Llama_3_3_70B_Instruct_Fp8_Fast_Output = + | { + /** + * The generated text response from the model + */ + response: string + /** + * Usage statistics for the inference request + */ + usage?: { + /** + * Total number of tokens in input + */ + prompt_tokens?: number + /** + * Total number of tokens in output + */ + completion_tokens?: number + /** + * Total number of input and output tokens + */ + total_tokens?: number + } + /** + * An array of tool calls requests made during the response generation + */ + tool_calls?: { + /** + * The arguments passed to be passed to the tool call request + */ + arguments?: object + /** + * The name of the tool to be called + */ + name?: string + }[] + } + | AsyncResponse +declare abstract class Base_Ai_Cf_Meta_Llama_3_3_70B_Instruct_Fp8_Fast { + inputs: Ai_Cf_Meta_Llama_3_3_70B_Instruct_Fp8_Fast_Input + postProcessedOutputs: Ai_Cf_Meta_Llama_3_3_70B_Instruct_Fp8_Fast_Output +} +interface Ai_Cf_Meta_Llama_Guard_3_8B_Input { + /** + * An array of message objects representing the conversation history. + */ + messages: { + /** + * The role of the message sender must alternate between 'user' and 'assistant'. + */ + role: 'user' | 'assistant' + /** + * The content of the message as a string. + */ + content: string + }[] + /** + * The maximum number of tokens to generate in the response. + */ + max_tokens?: number + /** + * Controls the randomness of the output; higher values produce more random results. + */ + temperature?: number + /** + * Dictate the output format of the generated response. + */ + response_format?: { + /** + * Set to json_object to process and output generated text as JSON. + */ + type?: string + } +} +interface Ai_Cf_Meta_Llama_Guard_3_8B_Output { + response?: + | string + | { + /** + * Whether the conversation is safe or not. + */ + safe?: boolean + /** + * A list of what hazard categories predicted for the conversation, if the conversation is deemed unsafe. + */ + categories?: string[] + } + /** + * Usage statistics for the inference request + */ + usage?: { + /** + * Total number of tokens in input + */ + prompt_tokens?: number + /** + * Total number of tokens in output + */ + completion_tokens?: number + /** + * Total number of input and output tokens + */ + total_tokens?: number + } +} +declare abstract class Base_Ai_Cf_Meta_Llama_Guard_3_8B { + inputs: Ai_Cf_Meta_Llama_Guard_3_8B_Input + postProcessedOutputs: Ai_Cf_Meta_Llama_Guard_3_8B_Output +} +interface Ai_Cf_Baai_Bge_Reranker_Base_Input { + /** + * A query you wish to perform against the provided contexts. + */ + query: string + /** + * Number of returned results starting with the best score. + */ + top_k?: number + /** + * List of provided contexts. Note that the index in this array is important, as the response will refer to it. + */ + contexts: { + /** + * One of the provided context content + */ + text?: string + }[] +} +interface Ai_Cf_Baai_Bge_Reranker_Base_Output { + response?: { + /** + * Index of the context in the request + */ + id?: number + /** + * Score of the context under the index. + */ + score?: number + }[] +} +declare abstract class Base_Ai_Cf_Baai_Bge_Reranker_Base { + inputs: Ai_Cf_Baai_Bge_Reranker_Base_Input + postProcessedOutputs: Ai_Cf_Baai_Bge_Reranker_Base_Output +} +type Ai_Cf_Qwen_Qwen2_5_Coder_32B_Instruct_Input = + | Qwen2_5_Coder_32B_Instruct_Prompt + | Qwen2_5_Coder_32B_Instruct_Messages +interface Qwen2_5_Coder_32B_Instruct_Prompt { + /** + * The input text prompt for the model to generate a response. + */ + prompt: string + /** + * Name of the LoRA (Low-Rank Adaptation) model to fine-tune the base model. + */ + lora?: string + response_format?: JSONMode + /** + * If true, a chat template is not applied and you must adhere to the specific model's expected formatting. + */ + raw?: boolean + /** + * If true, the response will be streamed back incrementally using SSE, Server Sent Events. + */ + stream?: boolean + /** + * The maximum number of tokens to generate in the response. + */ + max_tokens?: number + /** + * Controls the randomness of the output; higher values produce more random results. + */ + temperature?: number + /** + * Adjusts the creativity of the AI's responses by controlling how many possible words it considers. Lower values make outputs more predictable; higher values allow for more varied and creative responses. + */ + top_p?: number + /** + * Limits the AI to choose from the top 'k' most probable words. Lower values make responses more focused; higher values introduce more variety and potential surprises. + */ + top_k?: number + /** + * Random seed for reproducibility of the generation. + */ + seed?: number + /** + * Penalty for repeated tokens; higher values discourage repetition. + */ + repetition_penalty?: number + /** + * Decreases the likelihood of the model repeating the same lines verbatim. + */ + frequency_penalty?: number + /** + * Increases the likelihood of the model introducing new topics. + */ + presence_penalty?: number +} +interface Qwen2_5_Coder_32B_Instruct_Messages { + /** + * An array of message objects representing the conversation history. + */ + messages: { + /** + * The role of the message sender (e.g., 'user', 'assistant', 'system', 'tool'). + */ + role: string + /** + * The content of the message as a string. + */ + content: string + }[] + functions?: { + name: string + code: string + }[] + /** + * A list of tools available for the assistant to use. + */ + tools?: ( + | { + /** + * The name of the tool. More descriptive the better. + */ + name: string + /** + * A brief description of what the tool does. + */ + description: string + /** + * Schema defining the parameters accepted by the tool. + */ + parameters: { + /** + * The type of the parameters object (usually 'object'). + */ + type: string + /** + * List of required parameter names. + */ + required?: string[] + /** + * Definitions of each parameter. + */ + properties: { + [k: string]: { + /** + * The data type of the parameter. + */ + type: string + /** + * A description of the expected parameter. + */ + description: string + } + } + } + } + | { + /** + * Specifies the type of tool (e.g., 'function'). + */ + type: string + /** + * Details of the function tool. + */ + function: { + /** + * The name of the function. + */ + name: string + /** + * A brief description of what the function does. + */ + description: string + /** + * Schema defining the parameters accepted by the function. + */ + parameters: { + /** + * The type of the parameters object (usually 'object'). + */ + type: string + /** + * List of required parameter names. + */ + required?: string[] + /** + * Definitions of each parameter. + */ + properties: { + [k: string]: { + /** + * The data type of the parameter. + */ + type: string + /** + * A description of the expected parameter. + */ + description: string + } + } + } + } + } + )[] + response_format?: JSONMode + /** + * If true, a chat template is not applied and you must adhere to the specific model's expected formatting. + */ + raw?: boolean + /** + * If true, the response will be streamed back incrementally using SSE, Server Sent Events. + */ + stream?: boolean + /** + * The maximum number of tokens to generate in the response. + */ + max_tokens?: number + /** + * Controls the randomness of the output; higher values produce more random results. + */ + temperature?: number + /** + * Adjusts the creativity of the AI's responses by controlling how many possible words it considers. Lower values make outputs more predictable; higher values allow for more varied and creative responses. + */ + top_p?: number + /** + * Limits the AI to choose from the top 'k' most probable words. Lower values make responses more focused; higher values introduce more variety and potential surprises. + */ + top_k?: number + /** + * Random seed for reproducibility of the generation. + */ + seed?: number + /** + * Penalty for repeated tokens; higher values discourage repetition. + */ + repetition_penalty?: number + /** + * Decreases the likelihood of the model repeating the same lines verbatim. + */ + frequency_penalty?: number + /** + * Increases the likelihood of the model introducing new topics. + */ + presence_penalty?: number +} +type Ai_Cf_Qwen_Qwen2_5_Coder_32B_Instruct_Output = { + /** + * The generated text response from the model + */ + response: string + /** + * Usage statistics for the inference request + */ + usage?: { + /** + * Total number of tokens in input + */ + prompt_tokens?: number + /** + * Total number of tokens in output + */ + completion_tokens?: number + /** + * Total number of input and output tokens + */ + total_tokens?: number + } + /** + * An array of tool calls requests made during the response generation + */ + tool_calls?: { + /** + * The arguments passed to be passed to the tool call request + */ + arguments?: object + /** + * The name of the tool to be called + */ + name?: string + }[] +} +declare abstract class Base_Ai_Cf_Qwen_Qwen2_5_Coder_32B_Instruct { + inputs: Ai_Cf_Qwen_Qwen2_5_Coder_32B_Instruct_Input + postProcessedOutputs: Ai_Cf_Qwen_Qwen2_5_Coder_32B_Instruct_Output +} +type Ai_Cf_Qwen_Qwq_32B_Input = Qwen_Qwq_32B_Prompt | Qwen_Qwq_32B_Messages +interface Qwen_Qwq_32B_Prompt { + /** + * The input text prompt for the model to generate a response. + */ + prompt: string + /** + * JSON schema that should be fulfilled for the response. + */ + guided_json?: object + /** + * If true, a chat template is not applied and you must adhere to the specific model's expected formatting. + */ + raw?: boolean + /** + * If true, the response will be streamed back incrementally using SSE, Server Sent Events. + */ + stream?: boolean + /** + * The maximum number of tokens to generate in the response. + */ + max_tokens?: number + /** + * Controls the randomness of the output; higher values produce more random results. + */ + temperature?: number + /** + * Adjusts the creativity of the AI's responses by controlling how many possible words it considers. Lower values make outputs more predictable; higher values allow for more varied and creative responses. + */ + top_p?: number + /** + * Limits the AI to choose from the top 'k' most probable words. Lower values make responses more focused; higher values introduce more variety and potential surprises. + */ + top_k?: number + /** + * Random seed for reproducibility of the generation. + */ + seed?: number + /** + * Penalty for repeated tokens; higher values discourage repetition. + */ + repetition_penalty?: number + /** + * Decreases the likelihood of the model repeating the same lines verbatim. + */ + frequency_penalty?: number + /** + * Increases the likelihood of the model introducing new topics. + */ + presence_penalty?: number +} +interface Qwen_Qwq_32B_Messages { + /** + * An array of message objects representing the conversation history. + */ + messages: { + /** + * The role of the message sender (e.g., 'user', 'assistant', 'system', 'tool'). + */ + role?: string + /** + * The tool call id. Must be supplied for tool calls for Mistral-3. If you don't know what to put here you can fall back to 000000001 + */ + tool_call_id?: string + content?: + | string + | { + /** + * Type of the content provided + */ + type?: string + text?: string + image_url?: { + /** + * image uri with data (e.g. data:image/jpeg;base64,/9j/...). HTTP URL will not be accepted + */ + url?: string + } + }[] + | { + /** + * Type of the content provided + */ + type?: string + text?: string + image_url?: { + /** + * image uri with data (e.g. data:image/jpeg;base64,/9j/...). HTTP URL will not be accepted + */ + url?: string + } + } + }[] + functions?: { + name: string + code: string + }[] + /** + * A list of tools available for the assistant to use. + */ + tools?: ( + | { + /** + * The name of the tool. More descriptive the better. + */ + name: string + /** + * A brief description of what the tool does. + */ + description: string + /** + * Schema defining the parameters accepted by the tool. + */ + parameters: { + /** + * The type of the parameters object (usually 'object'). + */ + type: string + /** + * List of required parameter names. + */ + required?: string[] + /** + * Definitions of each parameter. + */ + properties: { + [k: string]: { + /** + * The data type of the parameter. + */ + type: string + /** + * A description of the expected parameter. + */ + description: string + } + } + } + } + | { + /** + * Specifies the type of tool (e.g., 'function'). + */ + type: string + /** + * Details of the function tool. + */ + function: { + /** + * The name of the function. + */ + name: string + /** + * A brief description of what the function does. + */ + description: string + /** + * Schema defining the parameters accepted by the function. + */ + parameters: { + /** + * The type of the parameters object (usually 'object'). + */ + type: string + /** + * List of required parameter names. + */ + required?: string[] + /** + * Definitions of each parameter. + */ + properties: { + [k: string]: { + /** + * The data type of the parameter. + */ + type: string + /** + * A description of the expected parameter. + */ + description: string + } + } + } + } + } + )[] + /** + * JSON schema that should be fufilled for the response. + */ + guided_json?: object + /** + * If true, a chat template is not applied and you must adhere to the specific model's expected formatting. + */ + raw?: boolean + /** + * If true, the response will be streamed back incrementally using SSE, Server Sent Events. + */ + stream?: boolean + /** + * The maximum number of tokens to generate in the response. + */ + max_tokens?: number + /** + * Controls the randomness of the output; higher values produce more random results. + */ + temperature?: number + /** + * Adjusts the creativity of the AI's responses by controlling how many possible words it considers. Lower values make outputs more predictable; higher values allow for more varied and creative responses. + */ + top_p?: number + /** + * Limits the AI to choose from the top 'k' most probable words. Lower values make responses more focused; higher values introduce more variety and potential surprises. + */ + top_k?: number + /** + * Random seed for reproducibility of the generation. + */ + seed?: number + /** + * Penalty for repeated tokens; higher values discourage repetition. + */ + repetition_penalty?: number + /** + * Decreases the likelihood of the model repeating the same lines verbatim. + */ + frequency_penalty?: number + /** + * Increases the likelihood of the model introducing new topics. + */ + presence_penalty?: number +} +type Ai_Cf_Qwen_Qwq_32B_Output = { + /** + * The generated text response from the model + */ + response: string + /** + * Usage statistics for the inference request + */ + usage?: { + /** + * Total number of tokens in input + */ + prompt_tokens?: number + /** + * Total number of tokens in output + */ + completion_tokens?: number + /** + * Total number of input and output tokens + */ + total_tokens?: number + } + /** + * An array of tool calls requests made during the response generation + */ + tool_calls?: { + /** + * The arguments passed to be passed to the tool call request + */ + arguments?: object + /** + * The name of the tool to be called + */ + name?: string + }[] +} +declare abstract class Base_Ai_Cf_Qwen_Qwq_32B { + inputs: Ai_Cf_Qwen_Qwq_32B_Input + postProcessedOutputs: Ai_Cf_Qwen_Qwq_32B_Output +} +type Ai_Cf_Mistralai_Mistral_Small_3_1_24B_Instruct_Input = + | Mistral_Small_3_1_24B_Instruct_Prompt + | Mistral_Small_3_1_24B_Instruct_Messages +interface Mistral_Small_3_1_24B_Instruct_Prompt { + /** + * The input text prompt for the model to generate a response. + */ + prompt: string + /** + * JSON schema that should be fulfilled for the response. + */ + guided_json?: object + /** + * If true, a chat template is not applied and you must adhere to the specific model's expected formatting. + */ + raw?: boolean + /** + * If true, the response will be streamed back incrementally using SSE, Server Sent Events. + */ + stream?: boolean + /** + * The maximum number of tokens to generate in the response. + */ + max_tokens?: number + /** + * Controls the randomness of the output; higher values produce more random results. + */ + temperature?: number + /** + * Adjusts the creativity of the AI's responses by controlling how many possible words it considers. Lower values make outputs more predictable; higher values allow for more varied and creative responses. + */ + top_p?: number + /** + * Limits the AI to choose from the top 'k' most probable words. Lower values make responses more focused; higher values introduce more variety and potential surprises. + */ + top_k?: number + /** + * Random seed for reproducibility of the generation. + */ + seed?: number + /** + * Penalty for repeated tokens; higher values discourage repetition. + */ + repetition_penalty?: number + /** + * Decreases the likelihood of the model repeating the same lines verbatim. + */ + frequency_penalty?: number + /** + * Increases the likelihood of the model introducing new topics. + */ + presence_penalty?: number +} +interface Mistral_Small_3_1_24B_Instruct_Messages { + /** + * An array of message objects representing the conversation history. + */ + messages: { + /** + * The role of the message sender (e.g., 'user', 'assistant', 'system', 'tool'). + */ + role?: string + /** + * The tool call id. Must be supplied for tool calls for Mistral-3. If you don't know what to put here you can fall back to 000000001 + */ + tool_call_id?: string + content?: + | string + | { + /** + * Type of the content provided + */ + type?: string + text?: string + image_url?: { + /** + * image uri with data (e.g. data:image/jpeg;base64,/9j/...). HTTP URL will not be accepted + */ + url?: string + } + }[] + | { + /** + * Type of the content provided + */ + type?: string + text?: string + image_url?: { + /** + * image uri with data (e.g. data:image/jpeg;base64,/9j/...). HTTP URL will not be accepted + */ + url?: string + } + } + }[] + functions?: { + name: string + code: string + }[] + /** + * A list of tools available for the assistant to use. + */ + tools?: ( + | { + /** + * The name of the tool. More descriptive the better. + */ + name: string + /** + * A brief description of what the tool does. + */ + description: string + /** + * Schema defining the parameters accepted by the tool. + */ + parameters: { + /** + * The type of the parameters object (usually 'object'). + */ + type: string + /** + * List of required parameter names. + */ + required?: string[] + /** + * Definitions of each parameter. + */ + properties: { + [k: string]: { + /** + * The data type of the parameter. + */ + type: string + /** + * A description of the expected parameter. + */ + description: string + } + } + } + } + | { + /** + * Specifies the type of tool (e.g., 'function'). + */ + type: string + /** + * Details of the function tool. + */ + function: { + /** + * The name of the function. + */ + name: string + /** + * A brief description of what the function does. + */ + description: string + /** + * Schema defining the parameters accepted by the function. + */ + parameters: { + /** + * The type of the parameters object (usually 'object'). + */ + type: string + /** + * List of required parameter names. + */ + required?: string[] + /** + * Definitions of each parameter. + */ + properties: { + [k: string]: { + /** + * The data type of the parameter. + */ + type: string + /** + * A description of the expected parameter. + */ + description: string + } + } + } + } + } + )[] + /** + * JSON schema that should be fufilled for the response. + */ + guided_json?: object + /** + * If true, a chat template is not applied and you must adhere to the specific model's expected formatting. + */ + raw?: boolean + /** + * If true, the response will be streamed back incrementally using SSE, Server Sent Events. + */ + stream?: boolean + /** + * The maximum number of tokens to generate in the response. + */ + max_tokens?: number + /** + * Controls the randomness of the output; higher values produce more random results. + */ + temperature?: number + /** + * Adjusts the creativity of the AI's responses by controlling how many possible words it considers. Lower values make outputs more predictable; higher values allow for more varied and creative responses. + */ + top_p?: number + /** + * Limits the AI to choose from the top 'k' most probable words. Lower values make responses more focused; higher values introduce more variety and potential surprises. + */ + top_k?: number + /** + * Random seed for reproducibility of the generation. + */ + seed?: number + /** + * Penalty for repeated tokens; higher values discourage repetition. + */ + repetition_penalty?: number + /** + * Decreases the likelihood of the model repeating the same lines verbatim. + */ + frequency_penalty?: number + /** + * Increases the likelihood of the model introducing new topics. + */ + presence_penalty?: number +} +type Ai_Cf_Mistralai_Mistral_Small_3_1_24B_Instruct_Output = { + /** + * The generated text response from the model + */ + response: string + /** + * Usage statistics for the inference request + */ + usage?: { + /** + * Total number of tokens in input + */ + prompt_tokens?: number + /** + * Total number of tokens in output + */ + completion_tokens?: number + /** + * Total number of input and output tokens + */ + total_tokens?: number + } + /** + * An array of tool calls requests made during the response generation + */ + tool_calls?: { + /** + * The arguments passed to be passed to the tool call request + */ + arguments?: object + /** + * The name of the tool to be called + */ + name?: string + }[] +} +declare abstract class Base_Ai_Cf_Mistralai_Mistral_Small_3_1_24B_Instruct { + inputs: Ai_Cf_Mistralai_Mistral_Small_3_1_24B_Instruct_Input + postProcessedOutputs: Ai_Cf_Mistralai_Mistral_Small_3_1_24B_Instruct_Output +} +type Ai_Cf_Google_Gemma_3_12B_It_Input = + | Google_Gemma_3_12B_It_Prompt + | Google_Gemma_3_12B_It_Messages +interface Google_Gemma_3_12B_It_Prompt { + /** + * The input text prompt for the model to generate a response. + */ + prompt: string + /** + * JSON schema that should be fufilled for the response. + */ + guided_json?: object + /** + * If true, a chat template is not applied and you must adhere to the specific model's expected formatting. + */ + raw?: boolean + /** + * If true, the response will be streamed back incrementally using SSE, Server Sent Events. + */ + stream?: boolean + /** + * The maximum number of tokens to generate in the response. + */ + max_tokens?: number + /** + * Controls the randomness of the output; higher values produce more random results. + */ + temperature?: number + /** + * Adjusts the creativity of the AI's responses by controlling how many possible words it considers. Lower values make outputs more predictable; higher values allow for more varied and creative responses. + */ + top_p?: number + /** + * Limits the AI to choose from the top 'k' most probable words. Lower values make responses more focused; higher values introduce more variety and potential surprises. + */ + top_k?: number + /** + * Random seed for reproducibility of the generation. + */ + seed?: number + /** + * Penalty for repeated tokens; higher values discourage repetition. + */ + repetition_penalty?: number + /** + * Decreases the likelihood of the model repeating the same lines verbatim. + */ + frequency_penalty?: number + /** + * Increases the likelihood of the model introducing new topics. + */ + presence_penalty?: number +} +interface Google_Gemma_3_12B_It_Messages { + /** + * An array of message objects representing the conversation history. + */ + messages: { + /** + * The role of the message sender (e.g., 'user', 'assistant', 'system', 'tool'). + */ + role?: string + content?: + | string + | { + /** + * Type of the content provided + */ + type?: string + text?: string + image_url?: { + /** + * image uri with data (e.g. data:image/jpeg;base64,/9j/...). HTTP URL will not be accepted + */ + url?: string + } + }[] + | { + /** + * Type of the content provided + */ + type?: string + text?: string + image_url?: { + /** + * image uri with data (e.g. data:image/jpeg;base64,/9j/...). HTTP URL will not be accepted + */ + url?: string + } + } + }[] + functions?: { + name: string + code: string + }[] + /** + * A list of tools available for the assistant to use. + */ + tools?: ( + | { + /** + * The name of the tool. More descriptive the better. + */ + name: string + /** + * A brief description of what the tool does. + */ + description: string + /** + * Schema defining the parameters accepted by the tool. + */ + parameters: { + /** + * The type of the parameters object (usually 'object'). + */ + type: string + /** + * List of required parameter names. + */ + required?: string[] + /** + * Definitions of each parameter. + */ + properties: { + [k: string]: { + /** + * The data type of the parameter. + */ + type: string + /** + * A description of the expected parameter. + */ + description: string + } + } + } + } + | { + /** + * Specifies the type of tool (e.g., 'function'). + */ + type: string + /** + * Details of the function tool. + */ + function: { + /** + * The name of the function. + */ + name: string + /** + * A brief description of what the function does. + */ + description: string + /** + * Schema defining the parameters accepted by the function. + */ + parameters: { + /** + * The type of the parameters object (usually 'object'). + */ + type: string + /** + * List of required parameter names. + */ + required?: string[] + /** + * Definitions of each parameter. + */ + properties: { + [k: string]: { + /** + * The data type of the parameter. + */ + type: string + /** + * A description of the expected parameter. + */ + description: string + } + } + } + } + } + )[] + /** + * JSON schema that should be fufilled for the response. + */ + guided_json?: object + /** + * If true, a chat template is not applied and you must adhere to the specific model's expected formatting. + */ + raw?: boolean + /** + * If true, the response will be streamed back incrementally using SSE, Server Sent Events. + */ + stream?: boolean + /** + * The maximum number of tokens to generate in the response. + */ + max_tokens?: number + /** + * Controls the randomness of the output; higher values produce more random results. + */ + temperature?: number + /** + * Adjusts the creativity of the AI's responses by controlling how many possible words it considers. Lower values make outputs more predictable; higher values allow for more varied and creative responses. + */ + top_p?: number + /** + * Limits the AI to choose from the top 'k' most probable words. Lower values make responses more focused; higher values introduce more variety and potential surprises. + */ + top_k?: number + /** + * Random seed for reproducibility of the generation. + */ + seed?: number + /** + * Penalty for repeated tokens; higher values discourage repetition. + */ + repetition_penalty?: number + /** + * Decreases the likelihood of the model repeating the same lines verbatim. + */ + frequency_penalty?: number + /** + * Increases the likelihood of the model introducing new topics. + */ + presence_penalty?: number +} +type Ai_Cf_Google_Gemma_3_12B_It_Output = { + /** + * The generated text response from the model + */ + response: string + /** + * Usage statistics for the inference request + */ + usage?: { + /** + * Total number of tokens in input + */ + prompt_tokens?: number + /** + * Total number of tokens in output + */ + completion_tokens?: number + /** + * Total number of input and output tokens + */ + total_tokens?: number + } + /** + * An array of tool calls requests made during the response generation + */ + tool_calls?: { + /** + * The arguments passed to be passed to the tool call request + */ + arguments?: object + /** + * The name of the tool to be called + */ + name?: string + }[] +} +declare abstract class Base_Ai_Cf_Google_Gemma_3_12B_It { + inputs: Ai_Cf_Google_Gemma_3_12B_It_Input + postProcessedOutputs: Ai_Cf_Google_Gemma_3_12B_It_Output +} +type Ai_Cf_Meta_Llama_4_Scout_17B_16E_Instruct_Input = + | Ai_Cf_Meta_Llama_4_Prompt + | Ai_Cf_Meta_Llama_4_Messages +interface Ai_Cf_Meta_Llama_4_Prompt { + /** + * The input text prompt for the model to generate a response. + */ + prompt: string + /** + * JSON schema that should be fulfilled for the response. + */ + guided_json?: object + response_format?: JSONMode + /** + * If true, a chat template is not applied and you must adhere to the specific model's expected formatting. + */ + raw?: boolean + /** + * If true, the response will be streamed back incrementally using SSE, Server Sent Events. + */ + stream?: boolean + /** + * The maximum number of tokens to generate in the response. + */ + max_tokens?: number + /** + * Controls the randomness of the output; higher values produce more random results. + */ + temperature?: number + /** + * Adjusts the creativity of the AI's responses by controlling how many possible words it considers. Lower values make outputs more predictable; higher values allow for more varied and creative responses. + */ + top_p?: number + /** + * Limits the AI to choose from the top 'k' most probable words. Lower values make responses more focused; higher values introduce more variety and potential surprises. + */ + top_k?: number + /** + * Random seed for reproducibility of the generation. + */ + seed?: number + /** + * Penalty for repeated tokens; higher values discourage repetition. + */ + repetition_penalty?: number + /** + * Decreases the likelihood of the model repeating the same lines verbatim. + */ + frequency_penalty?: number + /** + * Increases the likelihood of the model introducing new topics. + */ + presence_penalty?: number +} +interface Ai_Cf_Meta_Llama_4_Messages { + /** + * An array of message objects representing the conversation history. + */ + messages: { + /** + * The role of the message sender (e.g., 'user', 'assistant', 'system', 'tool'). + */ + role?: string + /** + * The tool call id. If you don't know what to put here you can fall back to 000000001 + */ + tool_call_id?: string + content?: + | string + | { + /** + * Type of the content provided + */ + type?: string + text?: string + image_url?: { + /** + * image uri with data (e.g. data:image/jpeg;base64,/9j/...). HTTP URL will not be accepted + */ + url?: string + } + }[] + | { + /** + * Type of the content provided + */ + type?: string + text?: string + image_url?: { + /** + * image uri with data (e.g. data:image/jpeg;base64,/9j/...). HTTP URL will not be accepted + */ + url?: string + } + } + }[] + functions?: { + name: string + code: string + }[] + /** + * A list of tools available for the assistant to use. + */ + tools?: ( + | { + /** + * The name of the tool. More descriptive the better. + */ + name: string + /** + * A brief description of what the tool does. + */ + description: string + /** + * Schema defining the parameters accepted by the tool. + */ + parameters: { + /** + * The type of the parameters object (usually 'object'). + */ + type: string + /** + * List of required parameter names. + */ + required?: string[] + /** + * Definitions of each parameter. + */ + properties: { + [k: string]: { + /** + * The data type of the parameter. + */ + type: string + /** + * A description of the expected parameter. + */ + description: string + } + } + } + } + | { + /** + * Specifies the type of tool (e.g., 'function'). + */ + type: string + /** + * Details of the function tool. + */ + function: { + /** + * The name of the function. + */ + name: string + /** + * A brief description of what the function does. + */ + description: string + /** + * Schema defining the parameters accepted by the function. + */ + parameters: { + /** + * The type of the parameters object (usually 'object'). + */ + type: string + /** + * List of required parameter names. + */ + required?: string[] + /** + * Definitions of each parameter. + */ + properties: { + [k: string]: { + /** + * The data type of the parameter. + */ + type: string + /** + * A description of the expected parameter. + */ + description: string + } + } + } + } + } + )[] + response_format?: JSONMode + /** + * JSON schema that should be fufilled for the response. + */ + guided_json?: object + /** + * If true, a chat template is not applied and you must adhere to the specific model's expected formatting. + */ + raw?: boolean + /** + * If true, the response will be streamed back incrementally using SSE, Server Sent Events. + */ + stream?: boolean + /** + * The maximum number of tokens to generate in the response. + */ + max_tokens?: number + /** + * Controls the randomness of the output; higher values produce more random results. + */ + temperature?: number + /** + * Adjusts the creativity of the AI's responses by controlling how many possible words it considers. Lower values make outputs more predictable; higher values allow for more varied and creative responses. + */ + top_p?: number + /** + * Limits the AI to choose from the top 'k' most probable words. Lower values make responses more focused; higher values introduce more variety and potential surprises. + */ + top_k?: number + /** + * Random seed for reproducibility of the generation. + */ + seed?: number + /** + * Penalty for repeated tokens; higher values discourage repetition. + */ + repetition_penalty?: number + /** + * Decreases the likelihood of the model repeating the same lines verbatim. + */ + frequency_penalty?: number + /** + * Increases the likelihood of the model introducing new topics. + */ + presence_penalty?: number +} +type Ai_Cf_Meta_Llama_4_Scout_17B_16E_Instruct_Output = { + /** + * The generated text response from the model + */ + response: string + /** + * Usage statistics for the inference request + */ + usage?: { + /** + * Total number of tokens in input + */ + prompt_tokens?: number + /** + * Total number of tokens in output + */ + completion_tokens?: number + /** + * Total number of input and output tokens + */ + total_tokens?: number + } + /** + * An array of tool calls requests made during the response generation + */ + tool_calls?: { + /** + * The tool call id. + */ + id?: string + /** + * Specifies the type of tool (e.g., 'function'). + */ + type?: string + /** + * Details of the function tool. + */ + function?: { + /** + * The name of the tool to be called + */ + name?: string + /** + * The arguments passed to be passed to the tool call request + */ + arguments?: object + } + }[] +} +declare abstract class Base_Ai_Cf_Meta_Llama_4_Scout_17B_16E_Instruct { + inputs: Ai_Cf_Meta_Llama_4_Scout_17B_16E_Instruct_Input + postProcessedOutputs: Ai_Cf_Meta_Llama_4_Scout_17B_16E_Instruct_Output +} +interface AiModels { + '@cf/huggingface/distilbert-sst-2-int8': BaseAiTextClassification + '@cf/stabilityai/stable-diffusion-xl-base-1.0': BaseAiTextToImage + '@cf/runwayml/stable-diffusion-v1-5-inpainting': BaseAiTextToImage + '@cf/runwayml/stable-diffusion-v1-5-img2img': BaseAiTextToImage + '@cf/lykon/dreamshaper-8-lcm': BaseAiTextToImage + '@cf/bytedance/stable-diffusion-xl-lightning': BaseAiTextToImage + '@cf/myshell-ai/melotts': BaseAiTextToSpeech + '@cf/microsoft/resnet-50': BaseAiImageClassification + '@cf/facebook/detr-resnet-50': BaseAiObjectDetection + '@cf/meta/llama-2-7b-chat-int8': BaseAiTextGeneration + '@cf/mistral/mistral-7b-instruct-v0.1': BaseAiTextGeneration + '@cf/meta/llama-2-7b-chat-fp16': BaseAiTextGeneration + '@hf/thebloke/llama-2-13b-chat-awq': BaseAiTextGeneration + '@hf/thebloke/mistral-7b-instruct-v0.1-awq': BaseAiTextGeneration + '@hf/thebloke/zephyr-7b-beta-awq': BaseAiTextGeneration + '@hf/thebloke/openhermes-2.5-mistral-7b-awq': BaseAiTextGeneration + '@hf/thebloke/neural-chat-7b-v3-1-awq': BaseAiTextGeneration + '@hf/thebloke/llamaguard-7b-awq': BaseAiTextGeneration + '@hf/thebloke/deepseek-coder-6.7b-base-awq': BaseAiTextGeneration + '@hf/thebloke/deepseek-coder-6.7b-instruct-awq': BaseAiTextGeneration + '@cf/deepseek-ai/deepseek-math-7b-instruct': BaseAiTextGeneration + '@cf/defog/sqlcoder-7b-2': BaseAiTextGeneration + '@cf/openchat/openchat-3.5-0106': BaseAiTextGeneration + '@cf/tiiuae/falcon-7b-instruct': BaseAiTextGeneration + '@cf/thebloke/discolm-german-7b-v1-awq': BaseAiTextGeneration + '@cf/qwen/qwen1.5-0.5b-chat': BaseAiTextGeneration + '@cf/qwen/qwen1.5-7b-chat-awq': BaseAiTextGeneration + '@cf/qwen/qwen1.5-14b-chat-awq': BaseAiTextGeneration + '@cf/tinyllama/tinyllama-1.1b-chat-v1.0': BaseAiTextGeneration + '@cf/microsoft/phi-2': BaseAiTextGeneration + '@cf/qwen/qwen1.5-1.8b-chat': BaseAiTextGeneration + '@cf/mistral/mistral-7b-instruct-v0.2-lora': BaseAiTextGeneration + '@hf/nousresearch/hermes-2-pro-mistral-7b': BaseAiTextGeneration + '@hf/nexusflow/starling-lm-7b-beta': BaseAiTextGeneration + '@hf/google/gemma-7b-it': BaseAiTextGeneration + '@cf/meta-llama/llama-2-7b-chat-hf-lora': BaseAiTextGeneration + '@cf/google/gemma-2b-it-lora': BaseAiTextGeneration + '@cf/google/gemma-7b-it-lora': BaseAiTextGeneration + '@hf/mistral/mistral-7b-instruct-v0.2': BaseAiTextGeneration + '@cf/meta/llama-3-8b-instruct': BaseAiTextGeneration + '@cf/fblgit/una-cybertron-7b-v2-bf16': BaseAiTextGeneration + '@cf/meta/llama-3-8b-instruct-awq': BaseAiTextGeneration + '@hf/meta-llama/meta-llama-3-8b-instruct': BaseAiTextGeneration + '@cf/meta/llama-3.1-8b-instruct': BaseAiTextGeneration + '@cf/meta/llama-3.1-8b-instruct-fp8': BaseAiTextGeneration + '@cf/meta/llama-3.1-8b-instruct-awq': BaseAiTextGeneration + '@cf/meta/llama-3.2-3b-instruct': BaseAiTextGeneration + '@cf/meta/llama-3.2-1b-instruct': BaseAiTextGeneration + '@cf/deepseek-ai/deepseek-r1-distill-qwen-32b': BaseAiTextGeneration + '@cf/facebook/bart-large-cnn': BaseAiSummarization + '@cf/llava-hf/llava-1.5-7b-hf': BaseAiImageToText + '@cf/baai/bge-base-en-v1.5': Base_Ai_Cf_Baai_Bge_Base_En_V1_5 + '@cf/openai/whisper': Base_Ai_Cf_Openai_Whisper + '@cf/meta/m2m100-1.2b': Base_Ai_Cf_Meta_M2M100_1_2B + '@cf/baai/bge-small-en-v1.5': Base_Ai_Cf_Baai_Bge_Small_En_V1_5 + '@cf/baai/bge-large-en-v1.5': Base_Ai_Cf_Baai_Bge_Large_En_V1_5 + '@cf/unum/uform-gen2-qwen-500m': Base_Ai_Cf_Unum_Uform_Gen2_Qwen_500M + '@cf/openai/whisper-tiny-en': Base_Ai_Cf_Openai_Whisper_Tiny_En + '@cf/openai/whisper-large-v3-turbo': Base_Ai_Cf_Openai_Whisper_Large_V3_Turbo + '@cf/baai/bge-m3': Base_Ai_Cf_Baai_Bge_M3 + '@cf/black-forest-labs/flux-1-schnell': Base_Ai_Cf_Black_Forest_Labs_Flux_1_Schnell + '@cf/meta/llama-3.2-11b-vision-instruct': Base_Ai_Cf_Meta_Llama_3_2_11B_Vision_Instruct + '@cf/meta/llama-3.3-70b-instruct-fp8-fast': Base_Ai_Cf_Meta_Llama_3_3_70B_Instruct_Fp8_Fast + '@cf/meta/llama-guard-3-8b': Base_Ai_Cf_Meta_Llama_Guard_3_8B + '@cf/baai/bge-reranker-base': Base_Ai_Cf_Baai_Bge_Reranker_Base + '@cf/qwen/qwen2.5-coder-32b-instruct': Base_Ai_Cf_Qwen_Qwen2_5_Coder_32B_Instruct + '@cf/qwen/qwq-32b': Base_Ai_Cf_Qwen_Qwq_32B + '@cf/mistralai/mistral-small-3.1-24b-instruct': Base_Ai_Cf_Mistralai_Mistral_Small_3_1_24B_Instruct + '@cf/google/gemma-3-12b-it': Base_Ai_Cf_Google_Gemma_3_12B_It + '@cf/meta/llama-4-scout-17b-16e-instruct': Base_Ai_Cf_Meta_Llama_4_Scout_17B_16E_Instruct +} +type AiOptions = { + /** + * Send requests as an asynchronous batch job, only works for supported models + * https://developers.cloudflare.com/workers-ai/features/batch-api + */ + queueRequest?: boolean + gateway?: GatewayOptions + returnRawResponse?: boolean + prefix?: string + extraHeaders?: object +} +type ConversionResponse = { + name: string + mimeType: string + format: 'markdown' + tokens: number + data: string +} +type AiModelsSearchParams = { + author?: string + hide_experimental?: boolean + page?: number + per_page?: number + search?: string + source?: number + task?: string +} +type AiModelsSearchObject = { + id: string + source: number + name: string + description: string + task: { + id: string + name: string + description: string + } + tags: string[] + properties: { + property_id: string + value: string + }[] +} +interface InferenceUpstreamError extends Error {} +interface AiInternalError extends Error {} +type AiModelListType = Record +declare abstract class Ai { + aiGatewayLogId: string | null + gateway(gatewayId: string): AiGateway + autorag(autoragId: string): AutoRAG + run< + Name extends keyof AiModelList, + Options extends AiOptions, + InputOptions extends AiModelList[Name]['inputs'], + >( + model: Name, + inputs: InputOptions, + options?: Options + ): Promise< + Options extends { + returnRawResponse: true + } + ? Response + : InputOptions extends { + stream: true + } + ? ReadableStream + : AiModelList[Name]['postProcessedOutputs'] + > + models(params?: AiModelsSearchParams): Promise + toMarkdown( + files: { + name: string + blob: Blob + }[], + options?: { + gateway?: GatewayOptions + extraHeaders?: object + } + ): Promise + toMarkdown( + files: { + name: string + blob: Blob + }, + options?: { + gateway?: GatewayOptions + extraHeaders?: object + } + ): Promise +} +type GatewayRetries = { + maxAttempts?: 1 | 2 | 3 | 4 | 5 + retryDelayMs?: number + backoff?: 'constant' | 'linear' | 'exponential' +} +type GatewayOptions = { + id: string + cacheKey?: string + cacheTtl?: number + skipCache?: boolean + metadata?: Record + collectLog?: boolean + eventId?: string + requestTimeoutMs?: number + retries?: GatewayRetries +} +type AiGatewayPatchLog = { + score?: number | null + feedback?: -1 | 1 | null + metadata?: Record | null +} +type AiGatewayLog = { + id: string + provider: string + model: string + model_type?: string + path: string + duration: number + request_type?: string + request_content_type?: string + status_code: number + response_content_type?: string + success: boolean + cached: boolean + tokens_in?: number + tokens_out?: number + metadata?: Record + step?: number + cost?: number + custom_cost?: boolean + request_size: number + request_head?: string + request_head_complete: boolean + response_size: number + response_head?: string + response_head_complete: boolean + created_at: Date +} +type AIGatewayProviders = + | 'workers-ai' + | 'anthropic' + | 'aws-bedrock' + | 'azure-openai' + | 'google-vertex-ai' + | 'huggingface' + | 'openai' + | 'perplexity-ai' + | 'replicate' + | 'groq' + | 'cohere' + | 'google-ai-studio' + | 'mistral' + | 'grok' + | 'openrouter' + | 'deepseek' + | 'cerebras' + | 'cartesia' + | 'elevenlabs' + | 'adobe-firefly' +type AIGatewayHeaders = { + 'cf-aig-metadata': Record | string + 'cf-aig-custom-cost': + | { + per_token_in?: number + per_token_out?: number + } + | { + total_cost?: number + } + | string + 'cf-aig-cache-ttl': number | string + 'cf-aig-skip-cache': boolean | string + 'cf-aig-cache-key': string + 'cf-aig-event-id': string + 'cf-aig-request-timeout': number | string + 'cf-aig-max-attempts': number | string + 'cf-aig-retry-delay': number | string + 'cf-aig-backoff': string + 'cf-aig-collect-log': boolean | string + Authorization: string + 'Content-Type': string + [key: string]: string | number | boolean | object +} +type AIGatewayUniversalRequest = { + provider: AIGatewayProviders | string // eslint-disable-line + endpoint: string + headers: Partial + query: unknown +} +interface AiGatewayInternalError extends Error {} +interface AiGatewayLogNotFound extends Error {} +declare abstract class AiGateway { + patchLog(logId: string, data: AiGatewayPatchLog): Promise + getLog(logId: string): Promise + run( + data: AIGatewayUniversalRequest | AIGatewayUniversalRequest[], + options?: { + gateway?: GatewayOptions + extraHeaders?: object + } + ): Promise + getUrl(provider?: AIGatewayProviders | string): Promise // eslint-disable-line +} +interface AutoRAGInternalError extends Error {} +interface AutoRAGNotFoundError extends Error {} +interface AutoRAGUnauthorizedError extends Error {} +interface AutoRAGNameNotSetError extends Error {} +type ComparisonFilter = { + key: string + type: 'eq' | 'ne' | 'gt' | 'gte' | 'lt' | 'lte' + value: string | number | boolean +} +type CompoundFilter = { + type: 'and' | 'or' + filters: ComparisonFilter[] +} +type AutoRagSearchRequest = { + query: string + filters?: CompoundFilter | ComparisonFilter + max_num_results?: number + ranking_options?: { + ranker?: string + score_threshold?: number + } + rewrite_query?: boolean +} +type AutoRagAiSearchRequest = AutoRagSearchRequest & { + stream?: boolean +} +type AutoRagAiSearchRequestStreaming = Omit & { + stream: true +} +type AutoRagSearchResponse = { + object: 'vector_store.search_results.page' + search_query: string + data: { + file_id: string + filename: string + score: number + attributes: Record + content: { + type: 'text' + text: string + }[] + }[] + has_more: boolean + next_page: string | null +} +type AutoRagListResponse = { + id: string + enable: boolean + type: string + source: string + vectorize_name: string + paused: boolean + status: string +}[] +type AutoRagAiSearchResponse = AutoRagSearchResponse & { + response: string +} +declare abstract class AutoRAG { + list(): Promise + search(params: AutoRagSearchRequest): Promise + aiSearch(params: AutoRagAiSearchRequestStreaming): Promise + aiSearch(params: AutoRagAiSearchRequest): Promise + aiSearch(params: AutoRagAiSearchRequest): Promise +} +interface BasicImageTransformations { + /** + * Maximum width in image pixels. The value must be an integer. + */ + width?: number + /** + * Maximum height in image pixels. The value must be an integer. + */ + height?: number + /** + * Resizing mode as a string. It affects interpretation of width and height + * options: + * - scale-down: Similar to contain, but the image is never enlarged. If + * the image is larger than given width or height, it will be resized. + * Otherwise its original size will be kept. + * - contain: Resizes to maximum size that fits within the given width and + * height. If only a single dimension is given (e.g. only width), the + * image will be shrunk or enlarged to exactly match that dimension. + * Aspect ratio is always preserved. + * - cover: Resizes (shrinks or enlarges) to fill the entire area of width + * and height. If the image has an aspect ratio different from the ratio + * of width and height, it will be cropped to fit. + * - crop: The image will be shrunk and cropped to fit within the area + * specified by width and height. The image will not be enlarged. For images + * smaller than the given dimensions it's the same as scale-down. For + * images larger than the given dimensions, it's the same as cover. + * See also trim. + * - pad: Resizes to the maximum size that fits within the given width and + * height, and then fills the remaining area with a background color + * (white by default). Use of this mode is not recommended, as the same + * effect can be more efficiently achieved with the contain mode and the + * CSS object-fit: contain property. + * - squeeze: Stretches and deforms to the width and height given, even if it + * breaks aspect ratio + */ + fit?: 'scale-down' | 'contain' | 'cover' | 'crop' | 'pad' | 'squeeze' + /** + * When cropping with fit: "cover", this defines the side or point that should + * be left uncropped. The value is either a string + * "left", "right", "top", "bottom", "auto", or "center" (the default), + * or an object {x, y} containing focal point coordinates in the original + * image expressed as fractions ranging from 0.0 (top or left) to 1.0 + * (bottom or right), 0.5 being the center. {fit: "cover", gravity: "top"} will + * crop bottom or left and right sides as necessary, but won’t crop anything + * from the top. {fit: "cover", gravity: {x:0.5, y:0.2}} will crop each side to + * preserve as much as possible around a point at 20% of the height of the + * source image. + */ + gravity?: + | 'left' + | 'right' + | 'top' + | 'bottom' + | 'center' + | 'auto' + | 'entropy' + | BasicImageTransformationsGravityCoordinates + /** + * Background color to add underneath the image. Applies only to images with + * transparency (such as PNG). Accepts any CSS color (#RRGGBB, rgba(…), + * hsl(…), etc.) + */ + background?: string + /** + * Number of degrees (90, 180, 270) to rotate the image by. width and height + * options refer to axes after rotation. + */ + rotate?: 0 | 90 | 180 | 270 | 360 +} +interface BasicImageTransformationsGravityCoordinates { + x?: number + y?: number + mode?: 'remainder' | 'box-center' +} +/** + * In addition to the properties you can set in the RequestInit dict + * that you pass as an argument to the Request constructor, you can + * set certain properties of a `cf` object to control how Cloudflare + * features are applied to that new Request. + * + * Note: Currently, these properties cannot be tested in the + * playground. + */ +interface RequestInitCfProperties extends Record { + cacheEverything?: boolean + /** + * A request's cache key is what determines if two requests are + * "the same" for caching purposes. If a request has the same cache key + * as some previous request, then we can serve the same cached response for + * both. (e.g. 'some-key') + * + * Only available for Enterprise customers. + */ + cacheKey?: string + /** + * This allows you to append additional Cache-Tag response headers + * to the origin response without modifications to the origin server. + * This will allow for greater control over the Purge by Cache Tag feature + * utilizing changes only in the Workers process. + * + * Only available for Enterprise customers. + */ + cacheTags?: string[] + /** + * Force response to be cached for a given number of seconds. (e.g. 300) + */ + cacheTtl?: number + /** + * Force response to be cached for a given number of seconds based on the Origin status code. + * (e.g. { '200-299': 86400, '404': 1, '500-599': 0 }) + */ + cacheTtlByStatus?: Record + scrapeShield?: boolean + apps?: boolean + image?: RequestInitCfPropertiesImage + minify?: RequestInitCfPropertiesImageMinify + mirage?: boolean + polish?: 'lossy' | 'lossless' | 'off' + r2?: RequestInitCfPropertiesR2 + /** + * Redirects the request to an alternate origin server. You can use this, + * for example, to implement load balancing across several origins. + * (e.g.us-east.example.com) + * + * Note - For security reasons, the hostname set in resolveOverride must + * be proxied on the same Cloudflare zone of the incoming request. + * Otherwise, the setting is ignored. CNAME hosts are allowed, so to + * resolve to a host under a different domain or a DNS only domain first + * declare a CNAME record within your own zone’s DNS mapping to the + * external hostname, set proxy on Cloudflare, then set resolveOverride + * to point to that CNAME record. + */ + resolveOverride?: string +} +interface RequestInitCfPropertiesImageDraw extends BasicImageTransformations { + /** + * Absolute URL of the image file to use for the drawing. It can be any of + * the supported file formats. For drawing of watermarks or non-rectangular + * overlays we recommend using PNG or WebP images. + */ + url: string + /** + * Floating-point number between 0 (transparent) and 1 (opaque). + * For example, opacity: 0.5 makes overlay semitransparent. + */ + opacity?: number + /** + * - If set to true, the overlay image will be tiled to cover the entire + * area. This is useful for stock-photo-like watermarks. + * - If set to "x", the overlay image will be tiled horizontally only + * (form a line). + * - If set to "y", the overlay image will be tiled vertically only + * (form a line). + */ + repeat?: true | 'x' | 'y' + /** + * Position of the overlay image relative to a given edge. Each property is + * an offset in pixels. 0 aligns exactly to the edge. For example, left: 10 + * positions left side of the overlay 10 pixels from the left edge of the + * image it's drawn over. bottom: 0 aligns bottom of the overlay with bottom + * of the background image. + * + * Setting both left & right, or both top & bottom is an error. + * + * If no position is specified, the image will be centered. + */ + top?: number + left?: number + bottom?: number + right?: number +} +interface RequestInitCfPropertiesImage extends BasicImageTransformations { + /** + * Device Pixel Ratio. Default 1. Multiplier for width/height that makes it + * easier to specify higher-DPI sizes in . + */ + dpr?: number + /** + * Allows you to trim your image. Takes dpr into account and is performed before + * resizing or rotation. + * + * It can be used as: + * - left, top, right, bottom - it will specify the number of pixels to cut + * off each side + * - width, height - the width/height you'd like to end up with - can be used + * in combination with the properties above + * - border - this will automatically trim the surroundings of an image based on + * it's color. It consists of three properties: + * - color: rgb or hex representation of the color you wish to trim (todo: verify the rgba bit) + * - tolerance: difference from color to treat as color + * - keep: the number of pixels of border to keep + */ + trim?: + | 'border' + | { + top?: number + bottom?: number + left?: number + right?: number + width?: number + height?: number + border?: + | boolean + | { + color?: string + tolerance?: number + keep?: number + } + } + /** + * Quality setting from 1-100 (useful values are in 60-90 range). Lower values + * make images look worse, but load faster. The default is 85. It applies only + * to JPEG and WebP images. It doesn’t have any effect on PNG. + */ + quality?: number | 'low' | 'medium-low' | 'medium-high' | 'high' + /** + * Output format to generate. It can be: + * - avif: generate images in AVIF format. + * - webp: generate images in Google WebP format. Set quality to 100 to get + * the WebP-lossless format. + * - json: instead of generating an image, outputs information about the + * image, in JSON format. The JSON object will contain image size + * (before and after resizing), source image’s MIME type, file size, etc. + * - jpeg: generate images in JPEG format. + * - png: generate images in PNG format. + */ + format?: 'avif' | 'webp' | 'json' | 'jpeg' | 'png' | 'baseline-jpeg' | 'png-force' | 'svg' + /** + * Whether to preserve animation frames from input files. Default is true. + * Setting it to false reduces animations to still images. This setting is + * recommended when enlarging images or processing arbitrary user content, + * because large GIF animations can weigh tens or even hundreds of megabytes. + * It is also useful to set anim:false when using format:"json" to get the + * response quicker without the number of frames. + */ + anim?: boolean + /** + * What EXIF data should be preserved in the output image. Note that EXIF + * rotation and embedded color profiles are always applied ("baked in" into + * the image), and aren't affected by this option. Note that if the Polish + * feature is enabled, all metadata may have been removed already and this + * option may have no effect. + * - keep: Preserve most of EXIF metadata, including GPS location if there's + * any. + * - copyright: Only keep the copyright tag, and discard everything else. + * This is the default behavior for JPEG files. + * - none: Discard all invisible EXIF metadata. Currently WebP and PNG + * output formats always discard metadata. + */ + metadata?: 'keep' | 'copyright' | 'none' + /** + * Strength of sharpening filter to apply to the image. Floating-point + * number between 0 (no sharpening, default) and 10 (maximum). 1.0 is a + * recommended value for downscaled images. + */ + sharpen?: number + /** + * Radius of a blur filter (approximate gaussian). Maximum supported radius + * is 250. + */ + blur?: number + /** + * Overlays are drawn in the order they appear in the array (last array + * entry is the topmost layer). + */ + draw?: RequestInitCfPropertiesImageDraw[] + /** + * Fetching image from authenticated origin. Setting this property will + * pass authentication headers (Authorization, Cookie, etc.) through to + * the origin. + */ + 'origin-auth'?: 'share-publicly' + /** + * Adds a border around the image. The border is added after resizing. Border + * width takes dpr into account, and can be specified either using a single + * width property, or individually for each side. + */ + border?: + | { + color: string + width: number + } + | { + color: string + top: number + right: number + bottom: number + left: number + } + /** + * Increase brightness by a factor. A value of 1.0 equals no change, a value + * of 0.5 equals half brightness, and a value of 2.0 equals twice as bright. + * 0 is ignored. + */ + brightness?: number + /** + * Increase contrast by a factor. A value of 1.0 equals no change, a value of + * 0.5 equals low contrast, and a value of 2.0 equals high contrast. 0 is + * ignored. + */ + contrast?: number + /** + * Increase exposure by a factor. A value of 1.0 equals no change, a value of + * 0.5 darkens the image, and a value of 2.0 lightens the image. 0 is ignored. + */ + gamma?: number + /** + * Increase contrast by a factor. A value of 1.0 equals no change, a value of + * 0.5 equals low contrast, and a value of 2.0 equals high contrast. 0 is + * ignored. + */ + saturation?: number + /** + * Flips the images horizontally, vertically, or both. Flipping is applied before + * rotation, so if you apply flip=h,rotate=90 then the image will be flipped + * horizontally, then rotated by 90 degrees. + */ + flip?: 'h' | 'v' | 'hv' + /** + * Slightly reduces latency on a cache miss by selecting a + * quickest-to-compress file format, at a cost of increased file size and + * lower image quality. It will usually override the format option and choose + * JPEG over WebP or AVIF. We do not recommend using this option, except in + * unusual circumstances like resizing uncacheable dynamically-generated + * images. + */ + compression?: 'fast' +} +interface RequestInitCfPropertiesImageMinify { + javascript?: boolean + css?: boolean + html?: boolean +} +interface RequestInitCfPropertiesR2 { + /** + * Colo id of bucket that an object is stored in + */ + bucketColoId?: number +} +/** + * Request metadata provided by Cloudflare's edge. + */ +type IncomingRequestCfProperties = IncomingRequestCfPropertiesBase & + IncomingRequestCfPropertiesBotManagementEnterprise & + IncomingRequestCfPropertiesCloudflareForSaaSEnterprise & + IncomingRequestCfPropertiesGeographicInformation & + IncomingRequestCfPropertiesCloudflareAccessOrApiShield +interface IncomingRequestCfPropertiesBase extends Record { + /** + * [ASN](https://www.iana.org/assignments/as-numbers/as-numbers.xhtml) of the incoming request. + * + * @example 395747 + */ + asn: number + /** + * The organization which owns the ASN of the incoming request. + * + * @example "Google Cloud" + */ + asOrganization: string + /** + * The original value of the `Accept-Encoding` header if Cloudflare modified it. + * + * @example "gzip, deflate, br" + */ + clientAcceptEncoding?: string + /** + * The number of milliseconds it took for the request to reach your worker. + * + * @example 22 + */ + clientTcpRtt?: number + /** + * The three-letter [IATA](https://en.wikipedia.org/wiki/IATA_airport_code) + * airport code of the data center that the request hit. + * + * @example "DFW" + */ + colo: string + /** + * Represents the upstream's response to a + * [TCP `keepalive` message](https://tldp.org/HOWTO/TCP-Keepalive-HOWTO/overview.html) + * from cloudflare. + * + * For workers with no upstream, this will always be `1`. + * + * @example 3 + */ + edgeRequestKeepAliveStatus: IncomingRequestCfPropertiesEdgeRequestKeepAliveStatus + /** + * The HTTP Protocol the request used. + * + * @example "HTTP/2" + */ + httpProtocol: string + /** + * The browser-requested prioritization information in the request object. + * + * If no information was set, defaults to the empty string `""` + * + * @example "weight=192;exclusive=0;group=3;group-weight=127" + * @default "" + */ + requestPriority: string + /** + * The TLS version of the connection to Cloudflare. + * In requests served over plaintext (without TLS), this property is the empty string `""`. + * + * @example "TLSv1.3" + */ + tlsVersion: string + /** + * The cipher for the connection to Cloudflare. + * In requests served over plaintext (without TLS), this property is the empty string `""`. + * + * @example "AEAD-AES128-GCM-SHA256" + */ + tlsCipher: string + /** + * Metadata containing the [`HELLO`](https://www.rfc-editor.org/rfc/rfc5246#section-7.4.1.2) and [`FINISHED`](https://www.rfc-editor.org/rfc/rfc5246#section-7.4.9) messages from this request's TLS handshake. + * + * If the incoming request was served over plaintext (without TLS) this field is undefined. + */ + tlsExportedAuthenticator?: IncomingRequestCfPropertiesExportedAuthenticatorMetadata +} +interface IncomingRequestCfPropertiesBotManagementBase { + /** + * Cloudflare’s [level of certainty](https://developers.cloudflare.com/bots/concepts/bot-score/) that a request comes from a bot, + * represented as an integer percentage between `1` (almost certainly a bot) and `99` (almost certainly human). + * + * @example 54 + */ + score: number + /** + * A boolean value that is true if the request comes from a good bot, like Google or Bing. + * Most customers choose to allow this traffic. For more details, see [Traffic from known bots](https://developers.cloudflare.com/firewall/known-issues-and-faq/#how-does-firewall-rules-handle-traffic-from-known-bots). + */ + verifiedBot: boolean + /** + * A boolean value that is true if the request originates from a + * Cloudflare-verified proxy service. + */ + corporateProxy: boolean + /** + * A boolean value that's true if the request matches [file extensions](https://developers.cloudflare.com/bots/reference/static-resources/) for many types of static resources. + */ + staticResource: boolean + /** + * List of IDs that correlate to the Bot Management heuristic detections made on a request (you can have multiple heuristic detections on the same request). + */ + detectionIds: number[] +} +interface IncomingRequestCfPropertiesBotManagement { + /** + * Results of Cloudflare's Bot Management analysis + */ + botManagement: IncomingRequestCfPropertiesBotManagementBase + /** + * Duplicate of `botManagement.score`. + * + * @deprecated + */ + clientTrustScore: number +} +interface IncomingRequestCfPropertiesBotManagementEnterprise + extends IncomingRequestCfPropertiesBotManagement { + /** + * Results of Cloudflare's Bot Management analysis + */ + botManagement: IncomingRequestCfPropertiesBotManagementBase & { + /** + * A [JA3 Fingerprint](https://developers.cloudflare.com/bots/concepts/ja3-fingerprint/) to help profile specific SSL/TLS clients + * across different destination IPs, Ports, and X509 certificates. + */ + ja3Hash: string + } +} +interface IncomingRequestCfPropertiesCloudflareForSaaSEnterprise { + /** + * Custom metadata set per-host in [Cloudflare for SaaS](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/). + * + * This field is only present if you have Cloudflare for SaaS enabled on your account + * and you have followed the [required steps to enable it]((https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/domain-support/custom-metadata/)). + */ + hostMetadata: HostMetadata +} +interface IncomingRequestCfPropertiesCloudflareAccessOrApiShield { + /** + * Information about the client certificate presented to Cloudflare. + * + * This is populated when the incoming request is served over TLS using + * either Cloudflare Access or API Shield (mTLS) + * and the presented SSL certificate has a valid + * [Certificate Serial Number](https://ldapwiki.com/wiki/Certificate%20Serial%20Number) + * (i.e., not `null` or `""`). + * + * Otherwise, a set of placeholder values are used. + * + * The property `certPresented` will be set to `"1"` when + * the object is populated (i.e. the above conditions were met). + */ + tlsClientAuth: + | IncomingRequestCfPropertiesTLSClientAuth + | IncomingRequestCfPropertiesTLSClientAuthPlaceholder +} +/** + * Metadata about the request's TLS handshake + */ +interface IncomingRequestCfPropertiesExportedAuthenticatorMetadata { + /** + * The client's [`HELLO` message](https://www.rfc-editor.org/rfc/rfc5246#section-7.4.1.2), encoded in hexadecimal + * + * @example "44372ba35fa1270921d318f34c12f155dc87b682cf36a790cfaa3ba8737a1b5d" + */ + clientHandshake: string + /** + * The server's [`HELLO` message](https://www.rfc-editor.org/rfc/rfc5246#section-7.4.1.2), encoded in hexadecimal + * + * @example "44372ba35fa1270921d318f34c12f155dc87b682cf36a790cfaa3ba8737a1b5d" + */ + serverHandshake: string + /** + * The client's [`FINISHED` message](https://www.rfc-editor.org/rfc/rfc5246#section-7.4.9), encoded in hexadecimal + * + * @example "084ee802fe1348f688220e2a6040a05b2199a761f33cf753abb1b006792d3f8b" + */ + clientFinished: string + /** + * The server's [`FINISHED` message](https://www.rfc-editor.org/rfc/rfc5246#section-7.4.9), encoded in hexadecimal + * + * @example "084ee802fe1348f688220e2a6040a05b2199a761f33cf753abb1b006792d3f8b" + */ + serverFinished: string +} +/** + * Geographic data about the request's origin. + */ +interface IncomingRequestCfPropertiesGeographicInformation { + /** + * The [ISO 3166-1 Alpha 2](https://www.iso.org/iso-3166-country-codes.html) country code the request originated from. + * + * If your worker is [configured to accept TOR connections](https://support.cloudflare.com/hc/en-us/articles/203306930-Understanding-Cloudflare-Tor-support-and-Onion-Routing), this may also be `"T1"`, indicating a request that originated over TOR. + * + * If Cloudflare is unable to determine where the request originated this property is omitted. + * + * The country code `"T1"` is used for requests originating on TOR. + * + * @example "GB" + */ + country?: Iso3166Alpha2Code | 'T1' + /** + * If present, this property indicates that the request originated in the EU + * + * @example "1" + */ + isEUCountry?: '1' + /** + * A two-letter code indicating the continent the request originated from. + * + * @example "AN" + */ + continent?: ContinentCode + /** + * The city the request originated from + * + * @example "Austin" + */ + city?: string + /** + * Postal code of the incoming request + * + * @example "78701" + */ + postalCode?: string + /** + * Latitude of the incoming request + * + * @example "30.27130" + */ + latitude?: string + /** + * Longitude of the incoming request + * + * @example "-97.74260" + */ + longitude?: string + /** + * Timezone of the incoming request + * + * @example "America/Chicago" + */ + timezone?: string + /** + * If known, the ISO 3166-2 name for the first level region associated with + * the IP address of the incoming request + * + * @example "Texas" + */ + region?: string + /** + * If known, the ISO 3166-2 code for the first-level region associated with + * the IP address of the incoming request + * + * @example "TX" + */ + regionCode?: string + /** + * Metro code (DMA) of the incoming request + * + * @example "635" + */ + metroCode?: string +} +/** Data about the incoming request's TLS certificate */ +interface IncomingRequestCfPropertiesTLSClientAuth { + /** Always `"1"`, indicating that the certificate was presented */ + certPresented: '1' + /** + * Result of certificate verification. + * + * @example "FAILED:self signed certificate" + */ + certVerified: Exclude + /** The presented certificate's revokation status. + * + * - A value of `"1"` indicates the certificate has been revoked + * - A value of `"0"` indicates the certificate has not been revoked + */ + certRevoked: '1' | '0' + /** + * The certificate issuer's [distinguished name](https://knowledge.digicert.com/generalinformation/INFO1745.html) + * + * @example "CN=cloudflareaccess.com, C=US, ST=Texas, L=Austin, O=Cloudflare" + */ + certIssuerDN: string + /** + * The certificate subject's [distinguished name](https://knowledge.digicert.com/generalinformation/INFO1745.html) + * + * @example "CN=*.cloudflareaccess.com, C=US, ST=Texas, L=Austin, O=Cloudflare" + */ + certSubjectDN: string + /** + * The certificate issuer's [distinguished name](https://knowledge.digicert.com/generalinformation/INFO1745.html) ([RFC 2253](https://www.rfc-editor.org/rfc/rfc2253.html) formatted) + * + * @example "CN=cloudflareaccess.com, C=US, ST=Texas, L=Austin, O=Cloudflare" + */ + certIssuerDNRFC2253: string + /** + * The certificate subject's [distinguished name](https://knowledge.digicert.com/generalinformation/INFO1745.html) ([RFC 2253](https://www.rfc-editor.org/rfc/rfc2253.html) formatted) + * + * @example "CN=*.cloudflareaccess.com, C=US, ST=Texas, L=Austin, O=Cloudflare" + */ + certSubjectDNRFC2253: string + /** The certificate issuer's distinguished name (legacy policies) */ + certIssuerDNLegacy: string + /** The certificate subject's distinguished name (legacy policies) */ + certSubjectDNLegacy: string + /** + * The certificate's serial number + * + * @example "00936EACBE07F201DF" + */ + certSerial: string + /** + * The certificate issuer's serial number + * + * @example "2489002934BDFEA34" + */ + certIssuerSerial: string + /** + * The certificate's Subject Key Identifier + * + * @example "BB:AF:7E:02:3D:FA:A6:F1:3C:84:8E:AD:EE:38:98:EC:D9:32:32:D4" + */ + certSKI: string + /** + * The certificate issuer's Subject Key Identifier + * + * @example "BB:AF:7E:02:3D:FA:A6:F1:3C:84:8E:AD:EE:38:98:EC:D9:32:32:D4" + */ + certIssuerSKI: string + /** + * The certificate's SHA-1 fingerprint + * + * @example "6b9109f323999e52259cda7373ff0b4d26bd232e" + */ + certFingerprintSHA1: string + /** + * The certificate's SHA-256 fingerprint + * + * @example "acf77cf37b4156a2708e34c4eb755f9b5dbbe5ebb55adfec8f11493438d19e6ad3f157f81fa3b98278453d5652b0c1fd1d71e5695ae4d709803a4d3f39de9dea" + */ + certFingerprintSHA256: string + /** + * The effective starting date of the certificate + * + * @example "Dec 22 19:39:00 2018 GMT" + */ + certNotBefore: string + /** + * The effective expiration date of the certificate + * + * @example "Dec 22 19:39:00 2018 GMT" + */ + certNotAfter: string +} +/** Placeholder values for TLS Client Authorization */ +interface IncomingRequestCfPropertiesTLSClientAuthPlaceholder { + certPresented: '0' + certVerified: 'NONE' + certRevoked: '0' + certIssuerDN: '' + certSubjectDN: '' + certIssuerDNRFC2253: '' + certSubjectDNRFC2253: '' + certIssuerDNLegacy: '' + certSubjectDNLegacy: '' + certSerial: '' + certIssuerSerial: '' + certSKI: '' + certIssuerSKI: '' + certFingerprintSHA1: '' + certFingerprintSHA256: '' + certNotBefore: '' + certNotAfter: '' +} +/** Possible outcomes of TLS verification */ +declare type CertVerificationStatus = + /** Authentication succeeded */ + | 'SUCCESS' + /** No certificate was presented */ + | 'NONE' + /** Failed because the certificate was self-signed */ + | 'FAILED:self signed certificate' + /** Failed because the certificate failed a trust chain check */ + | 'FAILED:unable to verify the first certificate' + /** Failed because the certificate not yet valid */ + | 'FAILED:certificate is not yet valid' + /** Failed because the certificate is expired */ + | 'FAILED:certificate has expired' + /** Failed for another unspecified reason */ + | 'FAILED' +/** + * An upstream endpoint's response to a TCP `keepalive` message from Cloudflare. + */ +declare type IncomingRequestCfPropertiesEdgeRequestKeepAliveStatus = + | 0 /** Unknown */ + | 1 /** no keepalives (not found) */ + | 2 /** no connection re-use, opening keepalive connection failed */ + | 3 /** no connection re-use, keepalive accepted and saved */ + | 4 /** connection re-use, refused by the origin server (`TCP FIN`) */ + | 5 /** connection re-use, accepted by the origin server */ +/** ISO 3166-1 Alpha-2 codes */ +declare type Iso3166Alpha2Code = + | 'AD' + | 'AE' + | 'AF' + | 'AG' + | 'AI' + | 'AL' + | 'AM' + | 'AO' + | 'AQ' + | 'AR' + | 'AS' + | 'AT' + | 'AU' + | 'AW' + | 'AX' + | 'AZ' + | 'BA' + | 'BB' + | 'BD' + | 'BE' + | 'BF' + | 'BG' + | 'BH' + | 'BI' + | 'BJ' + | 'BL' + | 'BM' + | 'BN' + | 'BO' + | 'BQ' + | 'BR' + | 'BS' + | 'BT' + | 'BV' + | 'BW' + | 'BY' + | 'BZ' + | 'CA' + | 'CC' + | 'CD' + | 'CF' + | 'CG' + | 'CH' + | 'CI' + | 'CK' + | 'CL' + | 'CM' + | 'CN' + | 'CO' + | 'CR' + | 'CU' + | 'CV' + | 'CW' + | 'CX' + | 'CY' + | 'CZ' + | 'DE' + | 'DJ' + | 'DK' + | 'DM' + | 'DO' + | 'DZ' + | 'EC' + | 'EE' + | 'EG' + | 'EH' + | 'ER' + | 'ES' + | 'ET' + | 'FI' + | 'FJ' + | 'FK' + | 'FM' + | 'FO' + | 'FR' + | 'GA' + | 'GB' + | 'GD' + | 'GE' + | 'GF' + | 'GG' + | 'GH' + | 'GI' + | 'GL' + | 'GM' + | 'GN' + | 'GP' + | 'GQ' + | 'GR' + | 'GS' + | 'GT' + | 'GU' + | 'GW' + | 'GY' + | 'HK' + | 'HM' + | 'HN' + | 'HR' + | 'HT' + | 'HU' + | 'ID' + | 'IE' + | 'IL' + | 'IM' + | 'IN' + | 'IO' + | 'IQ' + | 'IR' + | 'IS' + | 'IT' + | 'JE' + | 'JM' + | 'JO' + | 'JP' + | 'KE' + | 'KG' + | 'KH' + | 'KI' + | 'KM' + | 'KN' + | 'KP' + | 'KR' + | 'KW' + | 'KY' + | 'KZ' + | 'LA' + | 'LB' + | 'LC' + | 'LI' + | 'LK' + | 'LR' + | 'LS' + | 'LT' + | 'LU' + | 'LV' + | 'LY' + | 'MA' + | 'MC' + | 'MD' + | 'ME' + | 'MF' + | 'MG' + | 'MH' + | 'MK' + | 'ML' + | 'MM' + | 'MN' + | 'MO' + | 'MP' + | 'MQ' + | 'MR' + | 'MS' + | 'MT' + | 'MU' + | 'MV' + | 'MW' + | 'MX' + | 'MY' + | 'MZ' + | 'NA' + | 'NC' + | 'NE' + | 'NF' + | 'NG' + | 'NI' + | 'NL' + | 'NO' + | 'NP' + | 'NR' + | 'NU' + | 'NZ' + | 'OM' + | 'PA' + | 'PE' + | 'PF' + | 'PG' + | 'PH' + | 'PK' + | 'PL' + | 'PM' + | 'PN' + | 'PR' + | 'PS' + | 'PT' + | 'PW' + | 'PY' + | 'QA' + | 'RE' + | 'RO' + | 'RS' + | 'RU' + | 'RW' + | 'SA' + | 'SB' + | 'SC' + | 'SD' + | 'SE' + | 'SG' + | 'SH' + | 'SI' + | 'SJ' + | 'SK' + | 'SL' + | 'SM' + | 'SN' + | 'SO' + | 'SR' + | 'SS' + | 'ST' + | 'SV' + | 'SX' + | 'SY' + | 'SZ' + | 'TC' + | 'TD' + | 'TF' + | 'TG' + | 'TH' + | 'TJ' + | 'TK' + | 'TL' + | 'TM' + | 'TN' + | 'TO' + | 'TR' + | 'TT' + | 'TV' + | 'TW' + | 'TZ' + | 'UA' + | 'UG' + | 'UM' + | 'US' + | 'UY' + | 'UZ' + | 'VA' + | 'VC' + | 'VE' + | 'VG' + | 'VI' + | 'VN' + | 'VU' + | 'WF' + | 'WS' + | 'YE' + | 'YT' + | 'ZA' + | 'ZM' + | 'ZW' +/** The 2-letter continent codes Cloudflare uses */ +declare type ContinentCode = 'AF' | 'AN' | 'AS' | 'EU' | 'NA' | 'OC' | 'SA' +type CfProperties = + | IncomingRequestCfProperties + | RequestInitCfProperties +interface D1Meta { + duration: number + size_after: number + rows_read: number + rows_written: number + last_row_id: number + changed_db: boolean + changes: number + /** + * The region of the database instance that executed the query. + */ + served_by_region?: string + /** + * True if-and-only-if the database instance that executed the query was the primary. + */ + served_by_primary?: boolean + timings?: { + /** + * The duration of the SQL query execution by the database instance. It doesn't include any network time. + */ + sql_duration_ms: number + } +} +interface D1Response { + success: true + meta: D1Meta & Record + error?: never +} +type D1Result = D1Response & { + results: T[] +} +interface D1ExecResult { + count: number + duration: number +} +type D1SessionConstraint = + // Indicates that the first query should go to the primary, and the rest queries + // using the same D1DatabaseSession will go to any replica that is consistent with + // the bookmark maintained by the session (returned by the first query). + | 'first-primary' + // Indicates that the first query can go anywhere (primary or replica), and the rest queries + // using the same D1DatabaseSession will go to any replica that is consistent with + // the bookmark maintained by the session (returned by the first query). + | 'first-unconstrained' +type D1SessionBookmark = string +declare abstract class D1Database { + prepare(query: string): D1PreparedStatement + batch(statements: D1PreparedStatement[]): Promise[]> + exec(query: string): Promise + /** + * Creates a new D1 Session anchored at the given constraint or the bookmark. + * All queries executed using the created session will have sequential consistency, + * meaning that all writes done through the session will be visible in subsequent reads. + * + * @param constraintOrBookmark Either the session constraint or the explicit bookmark to anchor the created session. + */ + withSession(constraintOrBookmark?: D1SessionBookmark | D1SessionConstraint): D1DatabaseSession + /** + * @deprecated dump() will be removed soon, only applies to deprecated alpha v1 databases. + */ + dump(): Promise +} +declare abstract class D1DatabaseSession { + prepare(query: string): D1PreparedStatement + batch(statements: D1PreparedStatement[]): Promise[]> + /** + * @returns The latest session bookmark across all executed queries on the session. + * If no query has been executed yet, `null` is returned. + */ + getBookmark(): D1SessionBookmark | null +} +declare abstract class D1PreparedStatement { + bind(...values: unknown[]): D1PreparedStatement + first(colName: string): Promise + first>(): Promise + run>(): Promise> + all>(): Promise> + raw(options: { columnNames: true }): Promise<[string[], ...T[]]> + raw(options?: { columnNames?: false }): Promise +} +// `Disposable` was added to TypeScript's standard lib types in version 5.2. +// To support older TypeScript versions, define an empty `Disposable` interface. +// Users won't be able to use `using`/`Symbol.dispose` without upgrading to 5.2, +// but this will ensure type checking on older versions still passes. +// TypeScript's interface merging will ensure our empty interface is effectively +// ignored when `Disposable` is included in the standard lib. +interface Disposable {} +/** + * An email message that can be sent from a Worker. + */ +interface EmailMessage { + /** + * Envelope From attribute of the email message. + */ + readonly from: string + /** + * Envelope To attribute of the email message. + */ + readonly to: string +} +/** + * An email message that is sent to a consumer Worker and can be rejected/forwarded. + */ +interface ForwardableEmailMessage extends EmailMessage { + /** + * Stream of the email message content. + */ + readonly raw: ReadableStream + /** + * An [Headers object](https://developer.mozilla.org/en-US/docs/Web/API/Headers). + */ + readonly headers: Headers + /** + * Size of the email message content. + */ + readonly rawSize: number + /** + * Reject this email message by returning a permanent SMTP error back to the connecting client including the given reason. + * @param reason The reject reason. + * @returns void + */ + setReject(reason: string): void + /** + * Forward this email message to a verified destination address of the account. + * @param rcptTo Verified destination address. + * @param headers A [Headers object](https://developer.mozilla.org/en-US/docs/Web/API/Headers). + * @returns A promise that resolves when the email message is forwarded. + */ + forward(rcptTo: string, headers?: Headers): Promise + /** + * Reply to the sender of this email message with a new EmailMessage object. + * @param message The reply message. + * @returns A promise that resolves when the email message is replied. + */ + reply(message: EmailMessage): Promise +} +/** + * A binding that allows a Worker to send email messages. + */ +interface SendEmail { + send(message: EmailMessage): Promise +} +declare abstract class EmailEvent extends ExtendableEvent { + readonly message: ForwardableEmailMessage +} +declare type EmailExportedHandler = ( + message: ForwardableEmailMessage, + env: Env, + ctx: ExecutionContext +) => void | Promise +declare module 'cloudflare:email' { + let _EmailMessage: { + prototype: EmailMessage + new (from: string, to: string, raw: ReadableStream | string): EmailMessage + } + export { _EmailMessage as EmailMessage } +} +interface Hyperdrive { + /** + * Connect directly to Hyperdrive as if it's your database, returning a TCP socket. + * + * Calling this method returns an idential socket to if you call + * `connect("host:port")` using the `host` and `port` fields from this object. + * Pick whichever approach works better with your preferred DB client library. + * + * Note that this socket is not yet authenticated -- it's expected that your + * code (or preferably, the client library of your choice) will authenticate + * using the information in this class's readonly fields. + */ + connect(): Socket + /** + * A valid DB connection string that can be passed straight into the typical + * client library/driver/ORM. This will typically be the easiest way to use + * Hyperdrive. + */ + readonly connectionString: string + /* + * A randomly generated hostname that is only valid within the context of the + * currently running Worker which, when passed into `connect()` function from + * the "cloudflare:sockets" module, will connect to the Hyperdrive instance + * for your database. + */ + readonly host: string + /* + * The port that must be paired the the host field when connecting. + */ + readonly port: number + /* + * The username to use when authenticating to your database via Hyperdrive. + * Unlike the host and password, this will be the same every time + */ + readonly user: string + /* + * The randomly generated password to use when authenticating to your + * database via Hyperdrive. Like the host field, this password is only valid + * within the context of the currently running Worker instance from which + * it's read. + */ + readonly password: string + /* + * The name of the database to connect to. + */ + readonly database: string +} +// Copyright (c) 2024 Cloudflare, Inc. +// Licensed under the Apache 2.0 license found in the LICENSE file or at: +// https://opensource.org/licenses/Apache-2.0 +type ImageInfoResponse = + | { + format: 'image/svg+xml' + } + | { + format: string + fileSize: number + width: number + height: number + } +type ImageTransform = { + width?: number + height?: number + background?: string + blur?: number + border?: + | { + color?: string + width?: number + } + | { + top?: number + bottom?: number + left?: number + right?: number + } + brightness?: number + contrast?: number + fit?: 'scale-down' | 'contain' | 'pad' | 'squeeze' | 'cover' | 'crop' + flip?: 'h' | 'v' | 'hv' + gamma?: number + gravity?: + | 'left' + | 'right' + | 'top' + | 'bottom' + | 'center' + | 'auto' + | 'entropy' + | { + x?: number + y?: number + mode: 'remainder' | 'box-center' + } + rotate?: 0 | 90 | 180 | 270 + saturation?: number + sharpen?: number + trim?: + | 'border' + | { + top?: number + bottom?: number + left?: number + right?: number + width?: number + height?: number + border?: + | boolean + | { + color?: string + tolerance?: number + keep?: number + } + } +} +type ImageDrawOptions = { + opacity?: number + repeat?: boolean | string + top?: number + left?: number + bottom?: number + right?: number +} +type ImageOutputOptions = { + format: 'image/jpeg' | 'image/png' | 'image/gif' | 'image/webp' | 'image/avif' | 'rgb' | 'rgba' + quality?: number + background?: string +} +interface ImagesBinding { + /** + * Get image metadata (type, width and height) + * @throws {@link ImagesError} with code 9412 if input is not an image + * @param stream The image bytes + */ + info(stream: ReadableStream): Promise + /** + * Begin applying a series of transformations to an image + * @param stream The image bytes + * @returns A transform handle + */ + input(stream: ReadableStream): ImageTransformer +} +interface ImageTransformer { + /** + * Apply transform next, returning a transform handle. + * You can then apply more transformations, draw, or retrieve the output. + * @param transform + */ + transform(transform: ImageTransform): ImageTransformer + /** + * Draw an image on this transformer, returning a transform handle. + * You can then apply more transformations, draw, or retrieve the output. + * @param image The image (or transformer that will give the image) to draw + * @param options The options configuring how to draw the image + */ + draw( + image: ReadableStream | ImageTransformer, + options?: ImageDrawOptions + ): ImageTransformer + /** + * Retrieve the image that results from applying the transforms to the + * provided input + * @param options Options that apply to the output e.g. output format + */ + output(options: ImageOutputOptions): Promise +} +interface ImageTransformationResult { + /** + * The image as a response, ready to store in cache or return to users + */ + response(): Response + /** + * The content type of the returned image + */ + contentType(): string + /** + * The bytes of the response + */ + image(): ReadableStream +} +interface ImagesError extends Error { + readonly code: number + readonly message: string + readonly stack?: string +} +type Params

= Record +type EventContext = { + request: Request> + functionPath: string + waitUntil: (promise: Promise) => void + passThroughOnException: () => void + next: (input?: Request | string, init?: RequestInit) => Promise + env: Env & { + ASSETS: { + fetch: typeof fetch + } + } + params: Params

+ data: Data +} +type PagesFunction< + Env = unknown, + Params extends string = any, + Data extends Record = Record, +> = (context: EventContext) => Response | Promise +type EventPluginContext = { + request: Request> + functionPath: string + waitUntil: (promise: Promise) => void + passThroughOnException: () => void + next: (input?: Request | string, init?: RequestInit) => Promise + env: Env & { + ASSETS: { + fetch: typeof fetch + } + } + params: Params

) => Result> + : Result> + // Type for the callable part of an `Provider` if `T` is callable. + // This is intersected with methods/properties. + type MaybeCallableProvider = T extends (...args: any[]) => any ? MethodOrProperty : unknown + // Base type for all other types providing RPC-like interfaces. + // Rewrites all methods/properties to be `MethodOrProperty`s, while preserving callable types. + // `Reserved` names (e.g. stub method names like `dup()`) and symbols can't be accessed over RPC. + export type Provider< + T extends object, + Reserved extends string = never, + > = MaybeCallableProvider & { + [K in Exclude>]: MethodOrProperty + } +} +declare namespace Cloudflare { + interface Env {} +} +declare module 'cloudflare:workers' { + export type RpcStub = Rpc.Stub + export const RpcStub: { + new (value: T): Rpc.Stub + } + export abstract class RpcTarget implements Rpc.RpcTargetBranded { + [Rpc.__RPC_TARGET_BRAND]: never + } + // `protected` fields don't appear in `keyof`s, so can't be accessed over RPC + export abstract class WorkerEntrypoint implements Rpc.WorkerEntrypointBranded { + [Rpc.__WORKER_ENTRYPOINT_BRAND]: never + protected ctx: ExecutionContext + protected env: Env + constructor(ctx: ExecutionContext, env: Env) + fetch?(request: Request): Response | Promise + tail?(events: TraceItem[]): void | Promise + trace?(traces: TraceItem[]): void | Promise + scheduled?(controller: ScheduledController): void | Promise + queue?(batch: MessageBatch): void | Promise + test?(controller: TestController): void | Promise + } + export abstract class DurableObject implements Rpc.DurableObjectBranded { + [Rpc.__DURABLE_OBJECT_BRAND]: never + protected ctx: DurableObjectState + protected env: Env + constructor(ctx: DurableObjectState, env: Env) + fetch?(request: Request): Response | Promise + alarm?(alarmInfo?: AlarmInvocationInfo): void | Promise + webSocketMessage?(ws: WebSocket, message: string | ArrayBuffer): void | Promise + webSocketClose?( + ws: WebSocket, + code: number, + reason: string, + wasClean: boolean + ): void | Promise + webSocketError?(ws: WebSocket, error: unknown): void | Promise + } + export type WorkflowDurationLabel = + | 'second' + | 'minute' + | 'hour' + | 'day' + | 'week' + | 'month' + | 'year' + export type WorkflowSleepDuration = `${number} ${WorkflowDurationLabel}${'s' | ''}` | number + export type WorkflowDelayDuration = WorkflowSleepDuration + export type WorkflowTimeoutDuration = WorkflowSleepDuration + export type WorkflowRetentionDuration = WorkflowSleepDuration + export type WorkflowBackoff = 'constant' | 'linear' | 'exponential' + export type WorkflowStepConfig = { + retries?: { + limit: number + delay: WorkflowDelayDuration | number + backoff?: WorkflowBackoff + } + timeout?: WorkflowTimeoutDuration | number + } + export type WorkflowEvent = { + payload: Readonly + timestamp: Date + instanceId: string + } + export type WorkflowStepEvent = { + payload: Readonly + timestamp: Date + type: string + } + export abstract class WorkflowStep { + do>(name: string, callback: () => Promise): Promise + do>( + name: string, + config: WorkflowStepConfig, + callback: () => Promise + ): Promise + sleep: (name: string, duration: WorkflowSleepDuration) => Promise + sleepUntil: (name: string, timestamp: Date | number) => Promise + waitForEvent>( + name: string, + options: { + type: string + timeout?: WorkflowTimeoutDuration | number + } + ): Promise> + } + export abstract class WorkflowEntrypoint< + Env = unknown, + T extends Rpc.Serializable | unknown = unknown, + > implements Rpc.WorkflowEntrypointBranded + { + [Rpc.__WORKFLOW_ENTRYPOINT_BRAND]: never + protected ctx: ExecutionContext + protected env: Env + constructor(ctx: ExecutionContext, env: Env) + run(event: Readonly>, step: WorkflowStep): Promise + } + export const env: Cloudflare.Env +} +interface SecretsStoreSecret { + /** + * Get a secret from the Secrets Store, returning a string of the secret value + * if it exists, or throws an error if it does not exist + */ + get(): Promise +} +declare module 'cloudflare:sockets' { + function _connect(address: string | SocketAddress, options?: SocketOptions): Socket + export { _connect as connect } +} +declare namespace TailStream { + interface Header { + readonly name: string + readonly value: string + } + interface FetchEventInfo { + readonly type: 'fetch' + readonly method: string + readonly url: string + readonly cfJson: string + readonly headers: Header[] + } + interface JsRpcEventInfo { + readonly type: 'jsrpc' + readonly methodName: string + } + interface ScheduledEventInfo { + readonly type: 'scheduled' + readonly scheduledTime: Date + readonly cron: string + } + interface AlarmEventInfo { + readonly type: 'alarm' + readonly scheduledTime: Date + } + interface QueueEventInfo { + readonly type: 'queue' + readonly queueName: string + readonly batchSize: number + } + interface EmailEventInfo { + readonly type: 'email' + readonly mailFrom: string + readonly rcptTo: string + readonly rawSize: number + } + interface TraceEventInfo { + readonly type: 'trace' + readonly traces: (string | null)[] + } + interface HibernatableWebSocketEventInfoMessage { + readonly type: 'message' + } + interface HibernatableWebSocketEventInfoError { + readonly type: 'error' + } + interface HibernatableWebSocketEventInfoClose { + readonly type: 'close' + readonly code: number + readonly wasClean: boolean + } + interface HibernatableWebSocketEventInfo { + readonly type: 'hibernatableWebSocket' + readonly info: + | HibernatableWebSocketEventInfoClose + | HibernatableWebSocketEventInfoError + | HibernatableWebSocketEventInfoMessage + } + interface Resume { + readonly type: 'resume' + readonly attachment?: any + } + interface CustomEventInfo { + readonly type: 'custom' + } + interface FetchResponseInfo { + readonly type: 'fetch' + readonly statusCode: number + } + type EventOutcome = + | 'ok' + | 'canceled' + | 'exception' + | 'unknown' + | 'killSwitch' + | 'daemonDown' + | 'exceededCpu' + | 'exceededMemory' + | 'loadShed' + | 'responseStreamDisconnected' + | 'scriptNotFound' + interface ScriptVersion { + readonly id: string + readonly tag?: string + readonly message?: string + } + interface Trigger { + readonly traceId: string + readonly invocationId: string + readonly spanId: string + } + interface Onset { + readonly type: 'onset' + readonly dispatchNamespace?: string + readonly entrypoint?: string + readonly executionModel: string + readonly scriptName?: string + readonly scriptTags?: string[] + readonly scriptVersion?: ScriptVersion + readonly trigger?: Trigger + readonly info: + | FetchEventInfo + | JsRpcEventInfo + | ScheduledEventInfo + | AlarmEventInfo + | QueueEventInfo + | EmailEventInfo + | TraceEventInfo + | HibernatableWebSocketEventInfo + | Resume + | CustomEventInfo + } + interface Outcome { + readonly type: 'outcome' + readonly outcome: EventOutcome + readonly cpuTime: number + readonly wallTime: number + } + interface Hibernate { + readonly type: 'hibernate' + } + interface SpanOpen { + readonly type: 'spanOpen' + readonly name: string + readonly info?: FetchEventInfo | JsRpcEventInfo | Attributes + } + interface SpanClose { + readonly type: 'spanClose' + readonly outcome: EventOutcome + } + interface DiagnosticChannelEvent { + readonly type: 'diagnosticChannel' + readonly channel: string + readonly message: any + } + interface Exception { + readonly type: 'exception' + readonly name: string + readonly message: string + readonly stack?: string + } + interface Log { + readonly type: 'log' + readonly level: 'debug' | 'error' | 'info' | 'log' | 'warn' + readonly message: string + } + interface Return { + readonly type: 'return' + readonly info?: FetchResponseInfo + } + interface Link { + readonly type: 'link' + readonly label?: string + readonly traceId: string + readonly invocationId: string + readonly spanId: string + } + interface Attribute { + readonly name: string + readonly value: string | string[] | boolean | boolean[] | number | number[] | bigint | bigint[] + } + interface Attributes { + readonly type: 'attributes' + readonly info: Attribute[] + } + interface TailEvent { + readonly traceId: string + readonly invocationId: string + readonly spanId: string + readonly timestamp: Date + readonly sequence: number + readonly event: + | Onset + | Outcome + | Hibernate + | SpanOpen + | SpanClose + | DiagnosticChannelEvent + | Exception + | Log + | Return + | Link + | Attributes + } + type TailEventHandler = (event: TailEvent) => void | Promise + type TailEventHandlerName = + | 'outcome' + | 'hibernate' + | 'spanOpen' + | 'spanClose' + | 'diagnosticChannel' + | 'exception' + | 'log' + | 'return' + | 'link' + | 'attributes' + type TailEventHandlerObject = Record + type TailEventHandlerType = TailEventHandler | TailEventHandlerObject +} +// Copyright (c) 2022-2023 Cloudflare, Inc. +// Licensed under the Apache 2.0 license found in the LICENSE file or at: +// https://opensource.org/licenses/Apache-2.0 +/** + * Data types supported for holding vector metadata. + */ +type VectorizeVectorMetadataValue = string | number | boolean | string[] +/** + * Additional information to associate with a vector. + */ +type VectorizeVectorMetadata = + | VectorizeVectorMetadataValue + | Record +type VectorFloatArray = Float32Array | Float64Array +interface VectorizeError { + code?: number + error: string +} +/** + * Comparison logic/operation to use for metadata filtering. + * + * This list is expected to grow as support for more operations are released. + */ +type VectorizeVectorMetadataFilterOp = '$eq' | '$ne' +/** + * Filter criteria for vector metadata used to limit the retrieved query result set. + */ +type VectorizeVectorMetadataFilter = { + [field: string]: + | Exclude + | null + | { + [Op in VectorizeVectorMetadataFilterOp]?: Exclude< + VectorizeVectorMetadataValue, + string[] + > | null + } +} +/** + * Supported distance metrics for an index. + * Distance metrics determine how other "similar" vectors are determined. + */ +type VectorizeDistanceMetric = 'euclidean' | 'cosine' | 'dot-product' +/** + * Metadata return levels for a Vectorize query. + * + * Default to "none". + * + * @property all Full metadata for the vector return set, including all fields (including those un-indexed) without truncation. This is a more expensive retrieval, as it requires additional fetching & reading of un-indexed data. + * @property indexed Return all metadata fields configured for indexing in the vector return set. This level of retrieval is "free" in that no additional overhead is incurred returning this data. However, note that indexed metadata is subject to truncation (especially for larger strings). + * @property none No indexed metadata will be returned. + */ +type VectorizeMetadataRetrievalLevel = 'all' | 'indexed' | 'none' +interface VectorizeQueryOptions { + topK?: number + namespace?: string + returnValues?: boolean + returnMetadata?: boolean | VectorizeMetadataRetrievalLevel + filter?: VectorizeVectorMetadataFilter +} +/** + * Information about the configuration of an index. + */ +type VectorizeIndexConfig = + | { + dimensions: number + metric: VectorizeDistanceMetric + } + | { + preset: string // keep this generic, as we'll be adding more presets in the future and this is only in a read capacity + } +/** + * Metadata about an existing index. + * + * This type is exclusively for the Vectorize **beta** and will be deprecated once Vectorize RC is released. + * See {@link VectorizeIndexInfo} for its post-beta equivalent. + */ +interface VectorizeIndexDetails { + /** The unique ID of the index */ + readonly id: string + /** The name of the index. */ + name: string + /** (optional) A human readable description for the index. */ + description?: string + /** The index configuration, including the dimension size and distance metric. */ + config: VectorizeIndexConfig + /** The number of records containing vectors within the index. */ + vectorsCount: number +} +/** + * Metadata about an existing index. + */ +interface VectorizeIndexInfo { + /** The number of records containing vectors within the index. */ + vectorCount: number + /** Number of dimensions the index has been configured for. */ + dimensions: number + /** ISO 8601 datetime of the last processed mutation on in the index. All changes before this mutation will be reflected in the index state. */ + processedUpToDatetime: number + /** UUIDv4 of the last mutation processed by the index. All changes before this mutation will be reflected in the index state. */ + processedUpToMutation: number +} +/** + * Represents a single vector value set along with its associated metadata. + */ +interface VectorizeVector { + /** The ID for the vector. This can be user-defined, and must be unique. It should uniquely identify the object, and is best set based on the ID of what the vector represents. */ + id: string + /** The vector values */ + values: VectorFloatArray | number[] + /** The namespace this vector belongs to. */ + namespace?: string + /** Metadata associated with the vector. Includes the values of other fields and potentially additional details. */ + metadata?: Record +} +/** + * Represents a matched vector for a query along with its score and (if specified) the matching vector information. + */ +type VectorizeMatch = Pick, 'values'> & + Omit & { + /** The score or rank for similarity, when returned as a result */ + score: number + } +/** + * A set of matching {@link VectorizeMatch} for a particular query. + */ +interface VectorizeMatches { + matches: VectorizeMatch[] + count: number +} +/** + * Results of an operation that performed a mutation on a set of vectors. + * Here, `ids` is a list of vectors that were successfully processed. + * + * This type is exclusively for the Vectorize **beta** and will be deprecated once Vectorize RC is released. + * See {@link VectorizeAsyncMutation} for its post-beta equivalent. + */ +interface VectorizeVectorMutation { + /* List of ids of vectors that were successfully processed. */ + ids: string[] + /* Total count of the number of processed vectors. */ + count: number +} +/** + * Result type indicating a mutation on the Vectorize Index. + * Actual mutations are processed async where the `mutationId` is the unique identifier for the operation. + */ +interface VectorizeAsyncMutation { + /** The unique identifier for the async mutation operation containing the changeset. */ + mutationId: string +} +/** + * A Vectorize Vector Search Index for querying vectors/embeddings. + * + * This type is exclusively for the Vectorize **beta** and will be deprecated once Vectorize RC is released. + * See {@link Vectorize} for its new implementation. + */ +declare abstract class VectorizeIndex { + /** + * Get information about the currently bound index. + * @returns A promise that resolves with information about the current index. + */ + public describe(): Promise + /** + * Use the provided vector to perform a similarity search across the index. + * @param vector Input vector that will be used to drive the similarity search. + * @param options Configuration options to massage the returned data. + * @returns A promise that resolves with matched and scored vectors. + */ + public query( + vector: VectorFloatArray | number[], + options?: VectorizeQueryOptions + ): Promise + /** + * Insert a list of vectors into the index dataset. If a provided id exists, an error will be thrown. + * @param vectors List of vectors that will be inserted. + * @returns A promise that resolves with the ids & count of records that were successfully processed. + */ + public insert(vectors: VectorizeVector[]): Promise + /** + * Upsert a list of vectors into the index dataset. If a provided id exists, it will be replaced with the new values. + * @param vectors List of vectors that will be upserted. + * @returns A promise that resolves with the ids & count of records that were successfully processed. + */ + public upsert(vectors: VectorizeVector[]): Promise + /** + * Delete a list of vectors with a matching id. + * @param ids List of vector ids that should be deleted. + * @returns A promise that resolves with the ids & count of records that were successfully processed (and thus deleted). + */ + public deleteByIds(ids: string[]): Promise + /** + * Get a list of vectors with a matching id. + * @param ids List of vector ids that should be returned. + * @returns A promise that resolves with the raw unscored vectors matching the id set. + */ + public getByIds(ids: string[]): Promise +} +/** + * A Vectorize Vector Search Index for querying vectors/embeddings. + * + * Mutations in this version are async, returning a mutation id. + */ +declare abstract class Vectorize { + /** + * Get information about the currently bound index. + * @returns A promise that resolves with information about the current index. + */ + public describe(): Promise + /** + * Use the provided vector to perform a similarity search across the index. + * @param vector Input vector that will be used to drive the similarity search. + * @param options Configuration options to massage the returned data. + * @returns A promise that resolves with matched and scored vectors. + */ + public query( + vector: VectorFloatArray | number[], + options?: VectorizeQueryOptions + ): Promise + /** + * Use the provided vector-id to perform a similarity search across the index. + * @param vectorId Id for a vector in the index against which the index should be queried. + * @param options Configuration options to massage the returned data. + * @returns A promise that resolves with matched and scored vectors. + */ + public queryById(vectorId: string, options?: VectorizeQueryOptions): Promise + /** + * Insert a list of vectors into the index dataset. If a provided id exists, an error will be thrown. + * @param vectors List of vectors that will be inserted. + * @returns A promise that resolves with a unique identifier of a mutation containing the insert changeset. + */ + public insert(vectors: VectorizeVector[]): Promise + /** + * Upsert a list of vectors into the index dataset. If a provided id exists, it will be replaced with the new values. + * @param vectors List of vectors that will be upserted. + * @returns A promise that resolves with a unique identifier of a mutation containing the upsert changeset. + */ + public upsert(vectors: VectorizeVector[]): Promise + /** + * Delete a list of vectors with a matching id. + * @param ids List of vector ids that should be deleted. + * @returns A promise that resolves with a unique identifier of a mutation containing the delete changeset. + */ + public deleteByIds(ids: string[]): Promise + /** + * Get a list of vectors with a matching id. + * @param ids List of vector ids that should be returned. + * @returns A promise that resolves with the raw unscored vectors matching the id set. + */ + public getByIds(ids: string[]): Promise +} +/** + * The interface for "version_metadata" binding + * providing metadata about the Worker Version using this binding. + */ +type WorkerVersionMetadata = { + /** The ID of the Worker Version using this binding */ + id: string + /** The tag of the Worker Version using this binding */ + tag: string + /** The timestamp of when the Worker Version was uploaded */ + timestamp: string +} +interface DynamicDispatchLimits { + /** + * Limit CPU time in milliseconds. + */ + cpuMs?: number + /** + * Limit number of subrequests. + */ + subRequests?: number +} +interface DynamicDispatchOptions { + /** + * Limit resources of invoked Worker script. + */ + limits?: DynamicDispatchLimits + /** + * Arguments for outbound Worker script, if configured. + */ + outbound?: { + [key: string]: any + } +} +interface DispatchNamespace { + /** + * @param name Name of the Worker script. + * @param args Arguments to Worker script. + * @param options Options for Dynamic Dispatch invocation. + * @returns A Fetcher object that allows you to send requests to the Worker script. + * @throws If the Worker script does not exist in this dispatch namespace, an error will be thrown. + */ + get( + name: string, + args?: { + [key: string]: any + }, + options?: DynamicDispatchOptions + ): Fetcher +} +declare module 'cloudflare:workflows' { + /** + * NonRetryableError allows for a user to throw a fatal error + * that makes a Workflow instance fail immediately without triggering a retry + */ + export class NonRetryableError extends Error { + public constructor(message: string, name?: string) + } +} +declare abstract class Workflow { + /** + * Get a handle to an existing instance of the Workflow. + * @param id Id for the instance of this Workflow + * @returns A promise that resolves with a handle for the Instance + */ + public get(id: string): Promise + /** + * Create a new instance and return a handle to it. If a provided id exists, an error will be thrown. + * @param options Options when creating an instance including id and params + * @returns A promise that resolves with a handle for the Instance + */ + public create(options?: WorkflowInstanceCreateOptions): Promise + /** + * Create a batch of instances and return handle for all of them. If a provided id exists, an error will be thrown. + * `createBatch` is limited at 100 instances at a time or when the RPC limit for the batch (1MiB) is reached. + * @param batch List of Options when creating an instance including name and params + * @returns A promise that resolves with a list of handles for the created instances. + */ + public createBatch(batch: WorkflowInstanceCreateOptions[]): Promise +} +type WorkflowDurationLabel = 'second' | 'minute' | 'hour' | 'day' | 'week' | 'month' | 'year' +type WorkflowSleepDuration = `${number} ${WorkflowDurationLabel}${'s' | ''}` | number +type WorkflowRetentionDuration = WorkflowSleepDuration +interface WorkflowInstanceCreateOptions { + /** + * An id for your Workflow instance. Must be unique within the Workflow. + */ + id?: string + /** + * The event payload the Workflow instance is triggered with + */ + params?: PARAMS + /** + * The retention policy for Workflow instance. + * Defaults to the maximum retention period available for the owner's account. + */ + retention?: { + successRetention?: WorkflowRetentionDuration + errorRetention?: WorkflowRetentionDuration + } +} +type InstanceStatus = { + status: + | 'queued' // means that instance is waiting to be started (see concurrency limits) + | 'running' + | 'paused' + | 'errored' + | 'terminated' // user terminated the instance while it was running + | 'complete' + | 'waiting' // instance is hibernating and waiting for sleep or event to finish + | 'waitingForPause' // instance is finishing the current work to pause + | 'unknown' + error?: string + output?: object +} +interface WorkflowError { + code?: number + message: string +} +declare abstract class WorkflowInstance { + public id: string + /** + * Pause the instance. + */ + public pause(): Promise + /** + * Resume the instance. If it is already running, an error will be thrown. + */ + public resume(): Promise + /** + * Terminate the instance. If it is errored, terminated or complete, an error will be thrown. + */ + public terminate(): Promise + /** + * Restart the instance. + */ + public restart(): Promise + /** + * Returns the current status of the instance. + */ + public status(): Promise + /** + * Send an event to this instance. + */ + public sendEvent({ type, payload }: { type: string; payload: unknown }): Promise +} diff --git a/yarn.lock b/yarn.lock index 54bd47abb498..7810a1926c35 100644 --- a/yarn.lock +++ b/yarn.lock @@ -416,6 +416,17 @@ __metadata: languageName: node linkType: hard +"@asteasolutions/zod-to-openapi@npm:^7.3.0": + version: 7.3.4 + resolution: "@asteasolutions/zod-to-openapi@npm:7.3.4" + dependencies: + openapi3-ts: "npm:^4.1.2" + peerDependencies: + zod: ^3.20.2 + checksum: 10/05e336e3c94264000abb03a71743925e3a48d10771afa8cdd9e1cf0a944cc82b3371d272d961fa63584e8ee26bda43aa9fba2737f503e6853ff20f5cf30a718a + languageName: node + linkType: hard + "@aws-crypto/crc32@npm:5.2.0": version: 5.2.0 resolution: "@aws-crypto/crc32@npm:5.2.0" @@ -1848,6 +1859,20 @@ __metadata: languageName: node linkType: hard +"@bare-ts/lib@npm:^0.4.0": + version: 0.4.0 + resolution: "@bare-ts/lib@npm:0.4.0" + checksum: 10/c4f1940c714c9626d84cc1c6e3ce6d9897ed6ceed7d6b19a0d1c945daaa8e18cb954c3f7f99682fc815e0c2b800954ac190f96515a510f5cd820046bab62bc44 + languageName: node + linkType: hard + +"@bare-ts/lib@npm:~0.3.0": + version: 0.3.0 + resolution: "@bare-ts/lib@npm:0.3.0" + checksum: 10/06b5de1746c1cb2063521f5f45a59fcf869768b2e9962696e257bd8013f29b407d60ddcd366c09128348c72dc5ea7144810241adce09e9bb73e36c73a23433c0 + languageName: node + linkType: hard + "@bcoe/v8-coverage@npm:^1.0.2": version: 1.0.2 resolution: "@bcoe/v8-coverage@npm:1.0.2" @@ -1862,6 +1887,48 @@ __metadata: languageName: node linkType: hard +"@cbor-extract/cbor-extract-darwin-arm64@npm:2.2.0": + version: 2.2.0 + resolution: "@cbor-extract/cbor-extract-darwin-arm64@npm:2.2.0" + conditions: os=darwin & cpu=arm64 + languageName: node + linkType: hard + +"@cbor-extract/cbor-extract-darwin-x64@npm:2.2.0": + version: 2.2.0 + resolution: "@cbor-extract/cbor-extract-darwin-x64@npm:2.2.0" + conditions: os=darwin & cpu=x64 + languageName: node + linkType: hard + +"@cbor-extract/cbor-extract-linux-arm64@npm:2.2.0": + version: 2.2.0 + resolution: "@cbor-extract/cbor-extract-linux-arm64@npm:2.2.0" + conditions: os=linux & cpu=arm64 + languageName: node + linkType: hard + +"@cbor-extract/cbor-extract-linux-arm@npm:2.2.0": + version: 2.2.0 + resolution: "@cbor-extract/cbor-extract-linux-arm@npm:2.2.0" + conditions: os=linux & cpu=arm + languageName: node + linkType: hard + +"@cbor-extract/cbor-extract-linux-x64@npm:2.2.0": + version: 2.2.0 + resolution: "@cbor-extract/cbor-extract-linux-x64@npm:2.2.0" + conditions: os=linux & cpu=x64 + languageName: node + linkType: hard + +"@cbor-extract/cbor-extract-win32-x64@npm:2.2.0": + version: 2.2.0 + resolution: "@cbor-extract/cbor-extract-win32-x64@npm:2.2.0" + conditions: os=win32 & cpu=x64 + languageName: node + linkType: hard + "@clack/core@npm:1.0.0-alpha.1, @clack/core@npm:^1.0.0-alpha.1": version: 1.0.0-alpha.1 resolution: "@clack/core@npm:1.0.0-alpha.1" @@ -3478,6 +3545,61 @@ __metadata: languageName: node linkType: hard +"@hono/node-server@npm:^1.19.5": + version: 1.19.5 + resolution: "@hono/node-server@npm:1.19.5" + peerDependencies: + hono: ^4 + checksum: 10/fb1945f683742739acca673e0827c386c642c4edefb1bdbfb5ee0f464191cbcc845eda2544c5e34722c5281281c7164c4d953b7f3604ab0d98ede22d9c62d189 + languageName: node + linkType: hard + +"@hono/node-ws@npm:^1.2.0": + version: 1.2.0 + resolution: "@hono/node-ws@npm:1.2.0" + dependencies: + ws: "npm:^8.17.0" + peerDependencies: + "@hono/node-server": ^1.11.1 + hono: ^4.6.0 + checksum: 10/aa08d3994c238ebddab3435d07bb9f35fb88b5d280a6d10177c04cbc53858b2e6b05d4bb06d5f5c2afabf5327ffb3e2cf32764d1b22f0a38d3f67294266415ed + languageName: node + linkType: hard + +"@hono/standard-validator@npm:^0.1.3": + version: 0.1.5 + resolution: "@hono/standard-validator@npm:0.1.5" + peerDependencies: + "@standard-schema/spec": 1.0.0 + hono: ">=3.9.0" + checksum: 10/ac3b0aa9e43f28716939b3e30d03d0a1769be250189ee219e96b7cbf44fa6c346a18d8afe274d37a760e885adc74d87f324c21dbdf3915a4f78937977ade6047 + languageName: node + linkType: hard + +"@hono/zod-openapi@npm:^0.19.10": + version: 0.19.10 + resolution: "@hono/zod-openapi@npm:0.19.10" + dependencies: + "@asteasolutions/zod-to-openapi": "npm:^7.3.0" + "@hono/zod-validator": "npm:^0.7.1" + openapi3-ts: "npm:^4.5.0" + peerDependencies: + hono: ">=4.3.6" + zod: ">=3.0.0" + checksum: 10/879d5b579d27823f5a46d24e27a8f57970d839bb700a9ffc1f7f2970612092a4bc95ebdf5920d23bb565b545b825d084f52e707db8ccab764056497e45e39a2a + languageName: node + linkType: hard + +"@hono/zod-validator@npm:^0.7.1": + version: 0.7.4 + resolution: "@hono/zod-validator@npm:0.7.4" + peerDependencies: + hono: ">=3.9.0" + zod: ^3.25.0 || ^4.0.0 + checksum: 10/de90d806400f0d9dba91171ca0a5ecba7ce90ae029fa486457792b05ace41d84cec7deba92bb941e4eb2869caa184f52947e53bf7340567371bef250b3a4a891 + languageName: node + linkType: hard + "@humanfs/core@npm:^0.19.1": version: 0.19.1 resolution: "@humanfs/core@npm:0.19.1" @@ -5257,6 +5379,13 @@ __metadata: languageName: node linkType: hard +"@pinojs/redact@npm:^0.4.0": + version: 0.4.0 + resolution: "@pinojs/redact@npm:0.4.0" + checksum: 10/2210ffb6b38357853d47239fd0532cc9edb406325270a81c440a35cece22090127c30c2ead3eefa3e608f2244087485308e515c431f4f69b6bd2e16cbd32812b + languageName: node + linkType: hard + "@pkgjs/parseargs@npm:^0.11.0": version: 0.11.0 resolution: "@pkgjs/parseargs@npm:0.11.0" @@ -6780,6 +6909,58 @@ __metadata: languageName: node linkType: hard +"@rivetkit/engine-runner-protocol@https://pkg.pr.new/rivet-dev/rivet/@rivetkit/engine-runner-protocol@ea8ef90505afd87a43a711ceb9892efe17b98c4c": + version: 25.8.1 + resolution: "@rivetkit/engine-runner-protocol@https://pkg.pr.new/rivet-dev/rivet/@rivetkit/engine-runner-protocol@ea8ef90505afd87a43a711ceb9892efe17b98c4c" + dependencies: + "@bare-ts/lib": "npm:^0.4.0" + checksum: 10/873c09a2679e427e37333efa3b441f0ea88cba8d8b807cab1a4ffbc594ad7221c978f0b5a1bf8339336a8b73fca88a24a8c2f33962b492a46a0b7b7f285882b1 + languageName: node + linkType: hard + +"@rivetkit/engine-runner@https://pkg.pr.new/rivet-dev/rivet/@rivetkit/engine-runner@ea8ef90505afd87a43a711ceb9892efe17b98c4c": + version: 25.8.1 + resolution: "@rivetkit/engine-runner@https://pkg.pr.new/rivet-dev/rivet/@rivetkit/engine-runner@ea8ef90505afd87a43a711ceb9892efe17b98c4c" + dependencies: + "@rivetkit/engine-runner-protocol": "https://pkg.pr.new/rivet-dev/rivet/@rivetkit/engine-runner-protocol@ea8ef90505afd87a43a711ceb9892efe17b98c4c" + pino: "npm:^9.9.5" + uuid: "npm:^12.0.0" + ws: "npm:^8.18.3" + checksum: 10/07cc823e1c5ac46b767f1575849374cd3361fda38925432b1beaa1d894d7cec9bb30080979643f42d254f82fc30b56cc4281284bc927b7124c5646f0b78cdee6 + languageName: node + linkType: hard + +"@rivetkit/fast-json-patch@npm:^3.1.2": + version: 3.1.2 + resolution: "@rivetkit/fast-json-patch@npm:3.1.2" + checksum: 10/ec8a905a080bc9b075f126b608c8b5a2f00745e01c3e11176a1f0d615cfe4fa6cfb6d4adf287939321e516ad1283e7b0bef1e1899b7c8041b3fb20ecbaf513b4 + languageName: node + linkType: hard + +"@rivetkit/framework-base@https://pkg.pr.new/rivet-dev/rivet/@rivetkit/framework-base@ea8ef90505afd87a43a711ceb9892efe17b98c4c": + version: 2.0.20 + resolution: "@rivetkit/framework-base@https://pkg.pr.new/rivet-dev/rivet/@rivetkit/framework-base@ea8ef90505afd87a43a711ceb9892efe17b98c4c" + dependencies: + "@tanstack/store": "npm:^0.7.1" + rivetkit: "https://pkg.pr.new/rivet-dev/rivet/rivetkit@ea8ef90505afd87a43a711ceb9892efe17b98c4c" + checksum: 10/679a5095627012d897c62dca89eee982ad3377f2730c261f6d70f39d3ffa0f54014bba8f31bdd33fd269311352ae31c6165cced57e3159531c17a9943c312374 + languageName: node + linkType: hard + +"@rivetkit/react@https://pkg.pr.new/rivet-dev/rivet/@rivetkit/react@ea8ef90": + version: 2.0.20 + resolution: "@rivetkit/react@https://pkg.pr.new/rivet-dev/rivet/@rivetkit/react@ea8ef90" + dependencies: + "@rivetkit/framework-base": "https://pkg.pr.new/rivet-dev/rivet/@rivetkit/framework-base@ea8ef90505afd87a43a711ceb9892efe17b98c4c" + "@tanstack/react-store": "npm:^0.7.1" + rivetkit: "https://pkg.pr.new/rivet-dev/rivet/rivetkit@ea8ef90505afd87a43a711ceb9892efe17b98c4c" + peerDependencies: + react: ^18 || ^19 + react-dom: ^18 || ^19 + checksum: 10/5c8f66e7027c19e2762759c2d4fa83da6635d78f17b5d5ab6283d7003650b4dd0706f5be9970c1aedbda18d5f0f6b9c773848cd851a07da4128666fd26a1f25d + languageName: node + linkType: hard + "@rocicorp/lock@npm:^1.0.4": version: 1.0.4 resolution: "@rocicorp/lock@npm:1.0.4" @@ -8440,6 +8621,19 @@ __metadata: languageName: node linkType: hard +"@tanstack/react-store@npm:^0.7.1": + version: 0.7.7 + resolution: "@tanstack/react-store@npm:0.7.7" + dependencies: + "@tanstack/store": "npm:0.7.7" + use-sync-external-store: "npm:^1.5.0" + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + checksum: 10/3726a25d031cd9588dbf77ed76ba1f04a753746429234eac04a2b4fdad1001afc9e4a80f4297bfeed682935d6029eabb544d97d62879d6de7291e98ebc4ee4fc + languageName: node + linkType: hard + "@tanstack/react-virtual@npm:^3.8.1": version: 3.11.3 resolution: "@tanstack/react-virtual@npm:3.11.3" @@ -8452,6 +8646,13 @@ __metadata: languageName: node linkType: hard +"@tanstack/store@npm:0.7.7, @tanstack/store@npm:^0.7.1": + version: 0.7.7 + resolution: "@tanstack/store@npm:0.7.7" + checksum: 10/d278780a3b6e634fce4359481c4908c86180f0bb817cdbf65703e1ca9c1cdc5ad7a2bc13baa505357724d176541254783295d28e192b5fd0dff09f1b322000a5 + languageName: node + linkType: hard + "@tanstack/virtual-core@npm:3.11.3": version: 3.11.3 resolution: "@tanstack/virtual-core@npm:3.11.3" @@ -10218,6 +10419,13 @@ __metadata: languageName: node linkType: hard +"@types/retry@npm:0.12.2": + version: 0.12.2 + resolution: "@types/retry@npm:0.12.2" + checksum: 10/e5675035717b39ce4f42f339657cae9637cf0c0051cf54314a6a2c44d38d91f6544be9ddc0280587789b6afd056be5d99dbe3e9f4df68c286c36321579b1bf4a + languageName: node + linkType: hard + "@types/semver@npm:^7.5.8": version: 7.5.8 resolution: "@types/semver@npm:7.5.8" @@ -12775,6 +12983,49 @@ __metadata: languageName: node linkType: hard +"cbor-extract@npm:^2.2.0": + version: 2.2.0 + resolution: "cbor-extract@npm:2.2.0" + dependencies: + "@cbor-extract/cbor-extract-darwin-arm64": "npm:2.2.0" + "@cbor-extract/cbor-extract-darwin-x64": "npm:2.2.0" + "@cbor-extract/cbor-extract-linux-arm": "npm:2.2.0" + "@cbor-extract/cbor-extract-linux-arm64": "npm:2.2.0" + "@cbor-extract/cbor-extract-linux-x64": "npm:2.2.0" + "@cbor-extract/cbor-extract-win32-x64": "npm:2.2.0" + node-gyp: "npm:latest" + node-gyp-build-optional-packages: "npm:5.1.1" + dependenciesMeta: + "@cbor-extract/cbor-extract-darwin-arm64": + optional: true + "@cbor-extract/cbor-extract-darwin-x64": + optional: true + "@cbor-extract/cbor-extract-linux-arm": + optional: true + "@cbor-extract/cbor-extract-linux-arm64": + optional: true + "@cbor-extract/cbor-extract-linux-x64": + optional: true + "@cbor-extract/cbor-extract-win32-x64": + optional: true + bin: + download-cbor-prebuilds: bin/download-prebuilds.js + checksum: 10/c23bb69059407c1d7847d4347e9453336d0f1dfe0c82cf4cb0e91a48feb7d2ea453244b2b5823f7fe7e699745a29bab44fcb5e341fa940d290fab41a970db3ba + languageName: node + linkType: hard + +"cbor-x@npm:^1.6.0": + version: 1.6.0 + resolution: "cbor-x@npm:1.6.0" + dependencies: + cbor-extract: "npm:^2.2.0" + dependenciesMeta: + cbor-extract: + optional: true + checksum: 10/2e7dabbd920414ab2333324f3de79d5ebbbc465e8ec14a4c1b23714902ad149a94dfaed6a3c2370f6cd57ea47261df30a7b432d5960094d38c788e8c91093c3c + languageName: node + linkType: hard + "ccount@npm:^2.0.0": version: 2.0.1 resolution: "ccount@npm:2.0.1" @@ -14056,6 +14307,13 @@ __metadata: languageName: node linkType: hard +"detect-libc@npm:^2.0.1": + version: 2.1.2 + resolution: "detect-libc@npm:2.1.2" + checksum: 10/b736c8d97d5d46164c0d1bed53eb4e6a3b1d8530d460211e2d52f1c552875e706c58a5376854e4e54f8b828c9cada58c855288c968522eb93ac7696d65970766 + languageName: node + linkType: hard + "detect-node-es@npm:^1.1.0": version: 1.1.0 resolution: "detect-node-es@npm:1.1.0" @@ -17531,6 +17789,13 @@ __metadata: languageName: node linkType: hard +"hono@npm:^4.7.0": + version: 4.10.2 + resolution: "hono@npm:4.10.2" + checksum: 10/92223307d2340fdb25c657363908b4ee679e28a2b9fae3767201a5b923d8a71f5588ec8f9d041ebd4876f8eb06c0a8f5044990ce290b8e5bc37b25a371de393d + languageName: node + linkType: hard + "hookable@npm:^5.5.3": version: 5.5.3 resolution: "hookable@npm:5.5.3" @@ -18430,6 +18695,13 @@ __metadata: languageName: node linkType: hard +"is-network-error@npm:^1.0.0": + version: 1.3.0 + resolution: "is-network-error@npm:1.3.0" + checksum: 10/56dc0b8ed9c0bb72202058f172ad0c3121cf68772e8cbba343d3775f6e2ec7877d423cbcea45f4cedcd345de8693de1b52dfe0c6fc15d652c4aa98c2abf0185a + languageName: node + linkType: hard + "is-number-object@npm:^1.1.1": version: 1.1.1 resolution: "is-number-object@npm:1.1.1" @@ -21319,6 +21591,13 @@ __metadata: languageName: node linkType: hard +"nanoevents@npm:^9.1.0": + version: 9.1.0 + resolution: "nanoevents@npm:9.1.0" + checksum: 10/77abbc15c4efc15518a0075b604e5db045e5d6184f4d08892c771928a84f53b1dd46138902213f66e8a9989e6c930168ca6441b80ff9098aec83c01a782bd42b + languageName: node + linkType: hard + "nanoid@npm:3.3.1": version: 3.3.1 resolution: "nanoid@npm:3.3.1" @@ -21554,6 +21833,19 @@ __metadata: languageName: node linkType: hard +"node-gyp-build-optional-packages@npm:5.1.1": + version: 5.1.1 + resolution: "node-gyp-build-optional-packages@npm:5.1.1" + dependencies: + detect-libc: "npm:^2.0.1" + bin: + node-gyp-build-optional-packages: bin.js + node-gyp-build-optional-packages-optional: optional.js + node-gyp-build-optional-packages-test: build-test.js + checksum: 10/96dbeeba03fe5b9e86e1dc4491d7932cbf4c23f4ef8e63fb83bbbdcaf4553d8cbd5f23b9bc3632cb76a0739524f4b64f829daa5b608ebd72285ffdb03a9bdd81 + languageName: node + linkType: hard + "node-gyp-build@npm:^4.2.2": version: 4.8.0 resolution: "node-gyp-build@npm:4.8.0" @@ -21949,6 +22241,13 @@ __metadata: languageName: node linkType: hard +"on-change@npm:^5.0.1": + version: 5.0.1 + resolution: "on-change@npm:5.0.1" + checksum: 10/e22dbdb5dcc5b4686b759df5874c6fc83c5959ec2a27b1edbfd8b48e64fb22d6dca15da025cc3b4e49619b24642ad7d7bb3bb32b39cf8f84da0ffbf9134535b6 + languageName: node + linkType: hard + "on-exit-leak-free@npm:^2.1.0": version: 2.1.2 resolution: "on-exit-leak-free@npm:2.1.2" @@ -22054,6 +22353,15 @@ __metadata: languageName: node linkType: hard +"openapi3-ts@npm:^4.1.2, openapi3-ts@npm:^4.5.0": + version: 4.5.0 + resolution: "openapi3-ts@npm:4.5.0" + dependencies: + yaml: "npm:^2.8.0" + checksum: 10/83fc89459fc3b36049990a2b57eeff1b93d65550d110dcee3f822fd4bc009a0c3fae26d1064aced0736b72f31299f4cdef56c862fe95cf82384a182d30b76a4a + languageName: node + linkType: hard + "opencontrol@npm:0.0.6": version: 0.0.6 resolution: "opencontrol@npm:0.0.6" @@ -22280,6 +22588,17 @@ __metadata: languageName: node linkType: hard +"p-retry@npm:^6.2.1": + version: 6.2.1 + resolution: "p-retry@npm:6.2.1" + dependencies: + "@types/retry": "npm:0.12.2" + is-network-error: "npm:^1.0.0" + retry: "npm:^0.13.1" + checksum: 10/7104ef13703b155d70883b0d3654ecc03148407d2711a4516739cf93139e8bec383451e14925e25e3c1ae04dbace3ed53c26dc3853c1e9b9867fcbdde25f4cdc + languageName: node + linkType: hard + "p-some@npm:^5.0.0": version: 5.0.0 resolution: "p-some@npm:5.0.0" @@ -22839,6 +23158,27 @@ __metadata: languageName: node linkType: hard +"pino@npm:^9.5.0, pino@npm:^9.9.5": + version: 9.14.0 + resolution: "pino@npm:9.14.0" + dependencies: + "@pinojs/redact": "npm:^0.4.0" + atomic-sleep: "npm:^1.0.0" + on-exit-leak-free: "npm:^2.1.0" + pino-abstract-transport: "npm:^2.0.0" + pino-std-serializers: "npm:^7.0.0" + process-warning: "npm:^5.0.0" + quick-format-unescaped: "npm:^4.0.3" + real-require: "npm:^0.2.0" + safe-stable-stringify: "npm:^2.3.1" + sonic-boom: "npm:^4.0.1" + thread-stream: "npm:^3.0.0" + bin: + pino: bin.js + checksum: 10/918e1fc764885150cb2b4fae8249a0ece53275020a7ca389f994fa2fbbb17b6353cd736c2db3a3794fbac0351f8e3d58411fabe127e875e24151a8fa4cd0b2b5 + languageName: node + linkType: hard + "pirates@npm:^4.0.1": version: 4.0.6 resolution: "pirates@npm:4.0.6" @@ -24721,6 +25061,13 @@ __metadata: languageName: node linkType: hard +"retry@npm:^0.13.1": + version: 0.13.1 + resolution: "retry@npm:0.13.1" + checksum: 10/6125ec2e06d6e47e9201539c887defba4e47f63471db304c59e4b82fc63c8e89ca06a77e9d34939a9a42a76f00774b2f46c0d4a4cbb3e287268bd018ed69426d + languageName: node + linkType: hard + "reusify@npm:^1.0.4": version: 1.0.4 resolution: "reusify@npm:1.0.4" @@ -24779,6 +25126,76 @@ __metadata: languageName: node linkType: hard +"rivetkit@https://pkg.pr.new/rivet-dev/rivet/rivetkit@ea8ef90": + version: 2.0.20 + resolution: "rivetkit@https://pkg.pr.new/rivet-dev/rivet/rivetkit@ea8ef90" + dependencies: + "@bare-ts/lib": "npm:~0.3.0" + "@hono/standard-validator": "npm:^0.1.3" + "@hono/zod-openapi": "npm:^0.19.10" + "@rivetkit/engine-runner": "https://pkg.pr.new/rivet-dev/rivet/@rivetkit/engine-runner@ea8ef90505afd87a43a711ceb9892efe17b98c4c" + "@rivetkit/fast-json-patch": "npm:^3.1.2" + cbor-x: "npm:^1.6.0" + hono: "npm:^4.7.0" + invariant: "npm:^2.2.4" + nanoevents: "npm:^9.1.0" + on-change: "npm:^5.0.1" + p-retry: "npm:^6.2.1" + pino: "npm:^9.5.0" + zod: "npm:^3.25.76" + peerDependencies: + "@hono/node-server": ^1.14.0 + "@hono/node-ws": ^1.1.1 + eventsource: ^4.0.0 + ws: ^8.0.0 + peerDependenciesMeta: + "@hono/node-server": + optional: true + "@hono/node-ws": + optional: true + eventsource: + optional: true + ws: + optional: true + checksum: 10/54ce2b4b0116236412a14345d2e818f4d16e9a0fcb103c8f76e1fd94665a65e5953a63a9f037d1f4befb6a543cbb0a859ea2cb9583c1c58e4174af52355aaee2 + languageName: node + linkType: hard + +"rivetkit@https://pkg.pr.new/rivet-dev/rivet/rivetkit@ea8ef90505afd87a43a711ceb9892efe17b98c4c": + version: 2.0.20 + resolution: "rivetkit@https://pkg.pr.new/rivet-dev/rivet/rivetkit@ea8ef90505afd87a43a711ceb9892efe17b98c4c" + dependencies: + "@bare-ts/lib": "npm:~0.3.0" + "@hono/standard-validator": "npm:^0.1.3" + "@hono/zod-openapi": "npm:^0.19.10" + "@rivetkit/engine-runner": "https://pkg.pr.new/rivet-dev/rivet/@rivetkit/engine-runner@ea8ef90505afd87a43a711ceb9892efe17b98c4c" + "@rivetkit/fast-json-patch": "npm:^3.1.2" + cbor-x: "npm:^1.6.0" + hono: "npm:^4.7.0" + invariant: "npm:^2.2.4" + nanoevents: "npm:^9.1.0" + on-change: "npm:^5.0.1" + p-retry: "npm:^6.2.1" + pino: "npm:^9.5.0" + zod: "npm:^3.25.76" + peerDependencies: + "@hono/node-server": ^1.14.0 + "@hono/node-ws": ^1.1.1 + eventsource: ^4.0.0 + ws: ^8.0.0 + peerDependenciesMeta: + "@hono/node-server": + optional: true + "@hono/node-ws": + optional: true + eventsource: + optional: true + ws: + optional: true + checksum: 10/54ce2b4b0116236412a14345d2e818f4d16e9a0fcb103c8f76e1fd94665a65e5953a63a9f037d1f4befb6a543cbb0a859ea2cb9583c1c58e4174af52355aaee2 + languageName: node + linkType: hard + "rollup@npm:^4.43.0": version: 4.46.2 resolution: "rollup@npm:4.46.2" @@ -27004,6 +27421,33 @@ __metadata: languageName: unknown linkType: soft +"tldraw-sync-rivet@workspace:templates/sync-rivet": + version: 0.0.0-use.local + resolution: "tldraw-sync-rivet@workspace:templates/sync-rivet" + dependencies: + "@hono/node-server": "npm:^1.19.5" + "@hono/node-ws": "npm:^1.2.0" + "@rivetkit/react": "https://pkg.pr.new/rivet-dev/rivet/@rivetkit/react@ea8ef90" + "@tldraw/sync": "workspace:*" + "@tldraw/sync-core": "workspace:*" + "@tldraw/tlschema": "workspace:*" + "@types/lodash.throttle": "npm:^4.1.9" + "@types/react": "npm:^18.3.18" + "@types/react-dom": "npm:^18.3.5" + "@vitejs/plugin-react-swc": "npm:^3.10.2" + concurrently: "npm:^9.1.2" + itty-router: "npm:^5.0.18" + lodash.throttle: "npm:^4.1.1" + react: "npm:^18.3.1" + react-dom: "npm:^18.3.1" + react-router-dom: "npm:^6.28.2" + rivetkit: "https://pkg.pr.new/rivet-dev/rivet/rivetkit@ea8ef90" + tldraw: "workspace:*" + typescript: "npm:^5.8.3" + vite: "npm:^7.0.1" + languageName: unknown + linkType: soft + "tldraw-vite-example@workspace:templates/vite": version: 0.0.0-use.local resolution: "tldraw-vite-example@workspace:templates/vite" @@ -28248,6 +28692,15 @@ __metadata: languageName: node linkType: hard +"uuid@npm:^12.0.0": + version: 12.0.0 + resolution: "uuid@npm:12.0.0" + bin: + uuid: dist/bin/uuid + checksum: 10/18079c61ec2ca899d8df034ed543dc4844ec14d3bddc3099149d4c076a28c76dfc7434bcc5fafae8799f894da6acaa055bd7e97eedb6cba2840994f02849b801 + languageName: node + linkType: hard + "uuid@npm:^8.0.0, uuid@npm:^8.3.0": version: 8.3.2 resolution: "uuid@npm:8.3.2" @@ -29145,7 +29598,7 @@ __metadata: languageName: node linkType: hard -"ws@npm:^8.0.0, ws@npm:^8.16.0, ws@npm:^8.18.0, ws@npm:^8.18.1": +"ws@npm:^8.0.0, ws@npm:^8.16.0, ws@npm:^8.17.0, ws@npm:^8.18.0, ws@npm:^8.18.1, ws@npm:^8.18.3": version: 8.18.3 resolution: "ws@npm:8.18.3" peerDependencies: @@ -29301,6 +29754,15 @@ __metadata: languageName: node linkType: hard +"yaml@npm:^2.8.0": + version: 2.8.1 + resolution: "yaml@npm:2.8.1" + bin: + yaml: bin.mjs + checksum: 10/eae07b3947d405012672ec17ce27348aea7d1fa0534143355d24a43a58f5e05652157ea2182c4fe0604f0540be71f99f1173f9d61018379404507790dff17665 + languageName: node + linkType: hard + "yargs-parser@npm:20.2.4": version: 20.2.4 resolution: "yargs-parser@npm:20.2.4" @@ -29558,6 +30020,13 @@ __metadata: languageName: node linkType: hard +"zod@npm:^3.25.76": + version: 3.25.76 + resolution: "zod@npm:3.25.76" + checksum: 10/f0c963ec40cd96858451d1690404d603d36507c1fc9682f2dae59ab38b578687d542708a7fdbf645f77926f78c9ed558f57c3d3aa226c285f798df0c4da16995 + languageName: node + linkType: hard + "zod@npm:^4.1.8": version: 4.1.12 resolution: "zod@npm:4.1.12" From 572bb61b24d6976efa456f67f96cb08c2920180a Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 20 Oct 2025 11:22:10 +0000 Subject: [PATCH 002/114] [automated] update i18n strings (#6966) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR updates the i18n strings. ### Change type - [x] `other` --- > [!NOTE] > Adds new i18n key `95d2109dc8` ("Build with tldraw SDK") across all locales and compiled locale files. > > - **Internationalization**: > - Add new translation key `95d2109dc8` for "Build with tldraw SDK" in `apps/dotcom/client/public/tla/locales/*` and compiled `locales-compiled/*` across all supported languages. > > Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit bc1373b8d6b25e10b9883a0a042c1a53302c8744. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot). Co-authored-by: huppy-bot[bot] <128400622+huppy-bot[bot]@users.noreply.github.com> Co-authored-by: Mime Čuvalo --- .../client/public/tla/locales-compiled/ar.json | 6 ++++++ .../client/public/tla/locales-compiled/bn.json | 6 ++++++ .../client/public/tla/locales-compiled/ca.json | 6 ++++++ .../client/public/tla/locales-compiled/cs.json | 6 ++++++ .../client/public/tla/locales-compiled/da.json | 6 ++++++ .../client/public/tla/locales-compiled/de.json | 6 ++++++ .../client/public/tla/locales-compiled/el.json | 6 ++++++ .../client/public/tla/locales-compiled/es.json | 6 ++++++ .../client/public/tla/locales-compiled/fa.json | 6 ++++++ .../client/public/tla/locales-compiled/fi.json | 6 ++++++ .../client/public/tla/locales-compiled/fr.json | 6 ++++++ .../client/public/tla/locales-compiled/gl.json | 6 ++++++ .../client/public/tla/locales-compiled/gu-in.json | 6 ++++++ .../client/public/tla/locales-compiled/he.json | 6 ++++++ .../client/public/tla/locales-compiled/hi-in.json | 6 ++++++ .../client/public/tla/locales-compiled/hr.json | 6 ++++++ .../client/public/tla/locales-compiled/hu.json | 6 ++++++ .../client/public/tla/locales-compiled/id.json | 6 ++++++ .../client/public/tla/locales-compiled/it.json | 6 ++++++ .../client/public/tla/locales-compiled/ja.json | 6 ++++++ .../client/public/tla/locales-compiled/km-kh.json | 6 ++++++ .../client/public/tla/locales-compiled/kn.json | 6 ++++++ .../client/public/tla/locales-compiled/ko-kr.json | 6 ++++++ .../client/public/tla/locales-compiled/ml.json | 6 ++++++ .../client/public/tla/locales-compiled/mr.json | 6 ++++++ .../client/public/tla/locales-compiled/ms.json | 6 ++++++ .../client/public/tla/locales-compiled/ne.json | 6 ++++++ .../client/public/tla/locales-compiled/nl.json | 6 ++++++ .../client/public/tla/locales-compiled/no.json | 6 ++++++ .../client/public/tla/locales-compiled/pa.json | 6 ++++++ .../client/public/tla/locales-compiled/pl.json | 6 ++++++ .../client/public/tla/locales-compiled/pt-br.json | 6 ++++++ .../client/public/tla/locales-compiled/pt-pt.json | 6 ++++++ .../client/public/tla/locales-compiled/ro.json | 6 ++++++ .../client/public/tla/locales-compiled/ru.json | 6 ++++++ .../client/public/tla/locales-compiled/sl.json | 6 ++++++ .../client/public/tla/locales-compiled/so.json | 6 ++++++ .../client/public/tla/locales-compiled/sv.json | 6 ++++++ .../client/public/tla/locales-compiled/ta.json | 6 ++++++ .../client/public/tla/locales-compiled/te.json | 6 ++++++ .../client/public/tla/locales-compiled/th.json | 6 ++++++ .../client/public/tla/locales-compiled/tl.json | 6 ++++++ .../client/public/tla/locales-compiled/tr.json | 6 ++++++ .../client/public/tla/locales-compiled/uk.json | 6 ++++++ .../client/public/tla/locales-compiled/ur.json | 6 ++++++ .../client/public/tla/locales-compiled/vi.json | 6 ++++++ .../client/public/tla/locales-compiled/zh-cn.json | 6 ++++++ .../client/public/tla/locales-compiled/zh-tw.json | 6 ++++++ apps/dotcom/client/public/tla/locales/ar.json | 15 +++++++++------ apps/dotcom/client/public/tla/locales/bn.json | 15 +++++++++------ apps/dotcom/client/public/tla/locales/ca.json | 15 +++++++++------ apps/dotcom/client/public/tla/locales/cs.json | 15 +++++++++------ apps/dotcom/client/public/tla/locales/da.json | 15 +++++++++------ apps/dotcom/client/public/tla/locales/de.json | 15 +++++++++------ apps/dotcom/client/public/tla/locales/el.json | 15 +++++++++------ apps/dotcom/client/public/tla/locales/es.json | 15 +++++++++------ apps/dotcom/client/public/tla/locales/fa.json | 15 +++++++++------ apps/dotcom/client/public/tla/locales/fi.json | 15 +++++++++------ apps/dotcom/client/public/tla/locales/fr.json | 15 +++++++++------ apps/dotcom/client/public/tla/locales/gl.json | 15 +++++++++------ apps/dotcom/client/public/tla/locales/gu-in.json | 15 +++++++++------ apps/dotcom/client/public/tla/locales/he.json | 15 +++++++++------ apps/dotcom/client/public/tla/locales/hi-in.json | 15 +++++++++------ apps/dotcom/client/public/tla/locales/hr.json | 15 +++++++++------ apps/dotcom/client/public/tla/locales/hu.json | 15 +++++++++------ apps/dotcom/client/public/tla/locales/id.json | 15 +++++++++------ apps/dotcom/client/public/tla/locales/it.json | 15 +++++++++------ apps/dotcom/client/public/tla/locales/ja.json | 15 +++++++++------ apps/dotcom/client/public/tla/locales/km-kh.json | 15 +++++++++------ apps/dotcom/client/public/tla/locales/kn.json | 15 +++++++++------ apps/dotcom/client/public/tla/locales/ko-kr.json | 15 +++++++++------ apps/dotcom/client/public/tla/locales/ml.json | 15 +++++++++------ apps/dotcom/client/public/tla/locales/mr.json | 15 +++++++++------ apps/dotcom/client/public/tla/locales/ms.json | 15 +++++++++------ apps/dotcom/client/public/tla/locales/ne.json | 15 +++++++++------ apps/dotcom/client/public/tla/locales/nl.json | 15 +++++++++------ apps/dotcom/client/public/tla/locales/no.json | 15 +++++++++------ apps/dotcom/client/public/tla/locales/pa.json | 15 +++++++++------ apps/dotcom/client/public/tla/locales/pl.json | 15 +++++++++------ apps/dotcom/client/public/tla/locales/pt-br.json | 15 +++++++++------ apps/dotcom/client/public/tla/locales/pt-pt.json | 15 +++++++++------ apps/dotcom/client/public/tla/locales/ro.json | 15 +++++++++------ apps/dotcom/client/public/tla/locales/ru.json | 15 +++++++++------ apps/dotcom/client/public/tla/locales/sl.json | 15 +++++++++------ apps/dotcom/client/public/tla/locales/so.json | 15 +++++++++------ apps/dotcom/client/public/tla/locales/sv.json | 15 +++++++++------ apps/dotcom/client/public/tla/locales/ta.json | 15 +++++++++------ apps/dotcom/client/public/tla/locales/te.json | 15 +++++++++------ apps/dotcom/client/public/tla/locales/th.json | 15 +++++++++------ apps/dotcom/client/public/tla/locales/tl.json | 15 +++++++++------ apps/dotcom/client/public/tla/locales/tr.json | 15 +++++++++------ apps/dotcom/client/public/tla/locales/uk.json | 15 +++++++++------ apps/dotcom/client/public/tla/locales/ur.json | 15 +++++++++------ apps/dotcom/client/public/tla/locales/vi.json | 15 +++++++++------ apps/dotcom/client/public/tla/locales/zh-cn.json | 15 +++++++++------ apps/dotcom/client/public/tla/locales/zh-tw.json | 15 +++++++++------ 96 files changed, 720 insertions(+), 288 deletions(-) diff --git a/apps/dotcom/client/public/tla/locales-compiled/ar.json b/apps/dotcom/client/public/tla/locales-compiled/ar.json index 325d8f21b57a..214f73dc5f94 100644 --- a/apps/dotcom/client/public/tla/locales-compiled/ar.json +++ b/apps/dotcom/client/public/tla/locales-compiled/ar.json @@ -565,6 +565,12 @@ "value": "نسخ إلى ملفاتي" } ], + "95d2109dc8": [ + { + "type": 0, + "value": "البناء باستخدام SDK tldraw" + } + ], "96165d6df5": [ { "type": 0, diff --git a/apps/dotcom/client/public/tla/locales-compiled/bn.json b/apps/dotcom/client/public/tla/locales-compiled/bn.json index 88619aaf46a9..f4e98d2d97ba 100644 --- a/apps/dotcom/client/public/tla/locales-compiled/bn.json +++ b/apps/dotcom/client/public/tla/locales-compiled/bn.json @@ -561,6 +561,12 @@ "value": "আমার ফাইল কপি" } ], + "95d2109dc8": [ + { + "type": 0, + "value": "tldraw SDK দিয়ে তৈরি করুন" + } + ], "96165d6df5": [ { "type": 0, diff --git a/apps/dotcom/client/public/tla/locales-compiled/ca.json b/apps/dotcom/client/public/tla/locales-compiled/ca.json index 4fbe2a963bad..8219ee616710 100644 --- a/apps/dotcom/client/public/tla/locales-compiled/ca.json +++ b/apps/dotcom/client/public/tla/locales-compiled/ca.json @@ -565,6 +565,12 @@ "value": "Copia als meus fitxers" } ], + "95d2109dc8": [ + { + "type": 0, + "value": "Compilar amb el SDK de tldraw" + } + ], "96165d6df5": [ { "type": 0, diff --git a/apps/dotcom/client/public/tla/locales-compiled/cs.json b/apps/dotcom/client/public/tla/locales-compiled/cs.json index 269be1ff478b..3566b49d7ee9 100644 --- a/apps/dotcom/client/public/tla/locales-compiled/cs.json +++ b/apps/dotcom/client/public/tla/locales-compiled/cs.json @@ -565,6 +565,12 @@ "value": "Kopírovat do mých souborů" } ], + "95d2109dc8": [ + { + "type": 0, + "value": "Sestavení s tldraw SDK" + } + ], "96165d6df5": [ { "type": 0, diff --git a/apps/dotcom/client/public/tla/locales-compiled/da.json b/apps/dotcom/client/public/tla/locales-compiled/da.json index f5af6cd8ae27..4b0d3cd2211a 100644 --- a/apps/dotcom/client/public/tla/locales-compiled/da.json +++ b/apps/dotcom/client/public/tla/locales-compiled/da.json @@ -565,6 +565,12 @@ "value": "Kopier til mine filer" } ], + "95d2109dc8": [ + { + "type": 0, + "value": "Byg med tldraw SDK'et" + } + ], "96165d6df5": [ { "type": 0, diff --git a/apps/dotcom/client/public/tla/locales-compiled/de.json b/apps/dotcom/client/public/tla/locales-compiled/de.json index 9caeb7129f9c..3ec5d867507a 100644 --- a/apps/dotcom/client/public/tla/locales-compiled/de.json +++ b/apps/dotcom/client/public/tla/locales-compiled/de.json @@ -561,6 +561,12 @@ "value": "In meine Dateien kopieren" } ], + "95d2109dc8": [ + { + "type": 0, + "value": "Erstellen mit dem tldraw SDK" + } + ], "96165d6df5": [ { "type": 0, diff --git a/apps/dotcom/client/public/tla/locales-compiled/el.json b/apps/dotcom/client/public/tla/locales-compiled/el.json index 9a7ce2330726..c00257c3b873 100644 --- a/apps/dotcom/client/public/tla/locales-compiled/el.json +++ b/apps/dotcom/client/public/tla/locales-compiled/el.json @@ -565,6 +565,12 @@ "value": "Αντιγραφή στα αρχεία μου" } ], + "95d2109dc8": [ + { + "type": 0, + "value": "Δημιουργήστε με το tldraw SDK" + } + ], "96165d6df5": [ { "type": 0, diff --git a/apps/dotcom/client/public/tla/locales-compiled/es.json b/apps/dotcom/client/public/tla/locales-compiled/es.json index fdc8a9d68d23..4b3c5c060909 100644 --- a/apps/dotcom/client/public/tla/locales-compiled/es.json +++ b/apps/dotcom/client/public/tla/locales-compiled/es.json @@ -565,6 +565,12 @@ "value": "Copiar en mis archivos" } ], + "95d2109dc8": [ + { + "type": 0, + "value": "Construir con el SDK tldraw" + } + ], "96165d6df5": [ { "type": 0, diff --git a/apps/dotcom/client/public/tla/locales-compiled/fa.json b/apps/dotcom/client/public/tla/locales-compiled/fa.json index 8c0441c722a2..6c912ff06bed 100644 --- a/apps/dotcom/client/public/tla/locales-compiled/fa.json +++ b/apps/dotcom/client/public/tla/locales-compiled/fa.json @@ -561,6 +561,12 @@ "value": "در فایل های من کپی کنید" } ], + "95d2109dc8": [ + { + "type": 0, + "value": "با tldraw SDK بسازید" + } + ], "96165d6df5": [ { "type": 0, diff --git a/apps/dotcom/client/public/tla/locales-compiled/fi.json b/apps/dotcom/client/public/tla/locales-compiled/fi.json index ed9b9dfc3414..a46cef3181d6 100644 --- a/apps/dotcom/client/public/tla/locales-compiled/fi.json +++ b/apps/dotcom/client/public/tla/locales-compiled/fi.json @@ -565,6 +565,12 @@ "value": "Kopioi tiedostoihini" } ], + "95d2109dc8": [ + { + "type": 0, + "value": "Rakenna tldraw SDK:lla" + } + ], "96165d6df5": [ { "type": 0, diff --git a/apps/dotcom/client/public/tla/locales-compiled/fr.json b/apps/dotcom/client/public/tla/locales-compiled/fr.json index 330ef91b1cc0..5b891f05e37f 100644 --- a/apps/dotcom/client/public/tla/locales-compiled/fr.json +++ b/apps/dotcom/client/public/tla/locales-compiled/fr.json @@ -565,6 +565,12 @@ "value": "Copier dans mes fichiers" } ], + "95d2109dc8": [ + { + "type": 0, + "value": "Construire avec le SDK tldraw" + } + ], "96165d6df5": [ { "type": 0, diff --git a/apps/dotcom/client/public/tla/locales-compiled/gl.json b/apps/dotcom/client/public/tla/locales-compiled/gl.json index 7ef6419ab7fe..6d133c2b4b1d 100644 --- a/apps/dotcom/client/public/tla/locales-compiled/gl.json +++ b/apps/dotcom/client/public/tla/locales-compiled/gl.json @@ -565,6 +565,12 @@ "value": "Copiar nos meus ficheiros" } ], + "95d2109dc8": [ + { + "type": 0, + "value": "Compilar co SDK de tldraw" + } + ], "96165d6df5": [ { "type": 0, diff --git a/apps/dotcom/client/public/tla/locales-compiled/gu-in.json b/apps/dotcom/client/public/tla/locales-compiled/gu-in.json index bd43bde8dbc1..dc673a3e92c9 100644 --- a/apps/dotcom/client/public/tla/locales-compiled/gu-in.json +++ b/apps/dotcom/client/public/tla/locales-compiled/gu-in.json @@ -561,6 +561,12 @@ "value": "મારી ફાઇલોમાં કૉપિ કરો" } ], + "95d2109dc8": [ + { + "type": 0, + "value": "tldraw SDK વડે બનાવો" + } + ], "96165d6df5": [ { "type": 0, diff --git a/apps/dotcom/client/public/tla/locales-compiled/he.json b/apps/dotcom/client/public/tla/locales-compiled/he.json index a473dd5cf0dc..bbf6593ec18f 100644 --- a/apps/dotcom/client/public/tla/locales-compiled/he.json +++ b/apps/dotcom/client/public/tla/locales-compiled/he.json @@ -565,6 +565,12 @@ "value": "העתקה לקבצים שלי" } ], + "95d2109dc8": [ + { + "type": 0, + "value": "בנה עם ערכת פיתוח התוכנה tldraw" + } + ], "96165d6df5": [ { "type": 0, diff --git a/apps/dotcom/client/public/tla/locales-compiled/hi-in.json b/apps/dotcom/client/public/tla/locales-compiled/hi-in.json index f4a5f7a98980..b0bbc3f34d50 100644 --- a/apps/dotcom/client/public/tla/locales-compiled/hi-in.json +++ b/apps/dotcom/client/public/tla/locales-compiled/hi-in.json @@ -561,6 +561,12 @@ "value": "मेरी फाइलों में कॉपी करें" } ], + "95d2109dc8": [ + { + "type": 0, + "value": "tldraw SDK के साथ बनाएँ" + } + ], "96165d6df5": [ { "type": 0, diff --git a/apps/dotcom/client/public/tla/locales-compiled/hr.json b/apps/dotcom/client/public/tla/locales-compiled/hr.json index 5b9681233b3a..7bb365c223c6 100644 --- a/apps/dotcom/client/public/tla/locales-compiled/hr.json +++ b/apps/dotcom/client/public/tla/locales-compiled/hr.json @@ -565,6 +565,12 @@ "value": "Kopiraj u moje datoteke" } ], + "95d2109dc8": [ + { + "type": 0, + "value": "Izgradite s tldraw SDK-om" + } + ], "96165d6df5": [ { "type": 0, diff --git a/apps/dotcom/client/public/tla/locales-compiled/hu.json b/apps/dotcom/client/public/tla/locales-compiled/hu.json index a14e401d23ff..e436c1261c16 100644 --- a/apps/dotcom/client/public/tla/locales-compiled/hu.json +++ b/apps/dotcom/client/public/tla/locales-compiled/hu.json @@ -561,6 +561,12 @@ "value": "Másolás a fájljaim közé" } ], + "95d2109dc8": [ + { + "type": 0, + "value": "Fordítás a tldraw SDK-val" + } + ], "96165d6df5": [ { "type": 0, diff --git a/apps/dotcom/client/public/tla/locales-compiled/id.json b/apps/dotcom/client/public/tla/locales-compiled/id.json index 1aac82a3e075..15cefd3a17b3 100644 --- a/apps/dotcom/client/public/tla/locales-compiled/id.json +++ b/apps/dotcom/client/public/tla/locales-compiled/id.json @@ -565,6 +565,12 @@ "value": "Salin ke file saya" } ], + "95d2109dc8": [ + { + "type": 0, + "value": "Membangun dengan tldraw SDK" + } + ], "96165d6df5": [ { "type": 0, diff --git a/apps/dotcom/client/public/tla/locales-compiled/it.json b/apps/dotcom/client/public/tla/locales-compiled/it.json index b25f008dbebf..99d387c90361 100644 --- a/apps/dotcom/client/public/tla/locales-compiled/it.json +++ b/apps/dotcom/client/public/tla/locales-compiled/it.json @@ -565,6 +565,12 @@ "value": "Copia nei miei file" } ], + "95d2109dc8": [ + { + "type": 0, + "value": "Costruisci con l'SDK tldraw" + } + ], "96165d6df5": [ { "type": 0, diff --git a/apps/dotcom/client/public/tla/locales-compiled/ja.json b/apps/dotcom/client/public/tla/locales-compiled/ja.json index 93d8a2ee9e85..cb67d53811ae 100644 --- a/apps/dotcom/client/public/tla/locales-compiled/ja.json +++ b/apps/dotcom/client/public/tla/locales-compiled/ja.json @@ -561,6 +561,12 @@ "value": "自分のファイルにコピー" } ], + "95d2109dc8": [ + { + "type": 0, + "value": "tldraw SDKでビルドする" + } + ], "96165d6df5": [ { "type": 0, diff --git a/apps/dotcom/client/public/tla/locales-compiled/km-kh.json b/apps/dotcom/client/public/tla/locales-compiled/km-kh.json index 3e9370143d18..524443e733e0 100644 --- a/apps/dotcom/client/public/tla/locales-compiled/km-kh.json +++ b/apps/dotcom/client/public/tla/locales-compiled/km-kh.json @@ -565,6 +565,12 @@ "value": "ចម្លងទៅឯកសាររបស់ខ្ញុំ" } ], + "95d2109dc8": [ + { + "type": 0, + "value": "បង្កើតជាមួយ tldraw SDK" + } + ], "96165d6df5": [ { "type": 0, diff --git a/apps/dotcom/client/public/tla/locales-compiled/kn.json b/apps/dotcom/client/public/tla/locales-compiled/kn.json index eb0c15a4ba61..59936ad585cb 100644 --- a/apps/dotcom/client/public/tla/locales-compiled/kn.json +++ b/apps/dotcom/client/public/tla/locales-compiled/kn.json @@ -561,6 +561,12 @@ "value": "ನನ್ನ ಫೈಲ್‌ಗಳಿಗೆ ನಕಲಿಸಿ" } ], + "95d2109dc8": [ + { + "type": 0, + "value": "tldraw SDK ಬಳಸಿ ನಿರ್ಮಿಸಿ" + } + ], "96165d6df5": [ { "type": 0, diff --git a/apps/dotcom/client/public/tla/locales-compiled/ko-kr.json b/apps/dotcom/client/public/tla/locales-compiled/ko-kr.json index 7640474543c2..7d5f1b431c68 100644 --- a/apps/dotcom/client/public/tla/locales-compiled/ko-kr.json +++ b/apps/dotcom/client/public/tla/locales-compiled/ko-kr.json @@ -561,6 +561,12 @@ "value": "내 파일로 복사" } ], + "95d2109dc8": [ + { + "type": 0, + "value": "tldraw SDK로 빌드" + } + ], "96165d6df5": [ { "type": 0, diff --git a/apps/dotcom/client/public/tla/locales-compiled/ml.json b/apps/dotcom/client/public/tla/locales-compiled/ml.json index 174384baec25..14b00df36e1d 100644 --- a/apps/dotcom/client/public/tla/locales-compiled/ml.json +++ b/apps/dotcom/client/public/tla/locales-compiled/ml.json @@ -561,6 +561,12 @@ "value": "എൻ്റെ ഫയലുകളിലേക്ക് പകർത്തുക" } ], + "95d2109dc8": [ + { + "type": 0, + "value": "tldraw SDK ഉപയോഗിച്ച് നിർമ്മിക്കുക" + } + ], "96165d6df5": [ { "type": 0, diff --git a/apps/dotcom/client/public/tla/locales-compiled/mr.json b/apps/dotcom/client/public/tla/locales-compiled/mr.json index 98c5392fb936..af95ceab2e74 100644 --- a/apps/dotcom/client/public/tla/locales-compiled/mr.json +++ b/apps/dotcom/client/public/tla/locales-compiled/mr.json @@ -561,6 +561,12 @@ "value": "माझ्या फाइल्समध्ये कॉपी करा" } ], + "95d2109dc8": [ + { + "type": 0, + "value": "tldraw SDK वापरून तयार करा" + } + ], "96165d6df5": [ { "type": 0, diff --git a/apps/dotcom/client/public/tla/locales-compiled/ms.json b/apps/dotcom/client/public/tla/locales-compiled/ms.json index 81cff6829150..0728fd40ff7f 100644 --- a/apps/dotcom/client/public/tla/locales-compiled/ms.json +++ b/apps/dotcom/client/public/tla/locales-compiled/ms.json @@ -565,6 +565,12 @@ "value": "Salin ke fail saya" } ], + "95d2109dc8": [ + { + "type": 0, + "value": "Bina dengan tldraw SDK" + } + ], "96165d6df5": [ { "type": 0, diff --git a/apps/dotcom/client/public/tla/locales-compiled/ne.json b/apps/dotcom/client/public/tla/locales-compiled/ne.json index e51a04c6bab8..cf4bcafb625d 100644 --- a/apps/dotcom/client/public/tla/locales-compiled/ne.json +++ b/apps/dotcom/client/public/tla/locales-compiled/ne.json @@ -561,6 +561,12 @@ "value": "मेरो फाइलहरूमा प्रतिलिपि गर्नुहोस्" } ], + "95d2109dc8": [ + { + "type": 0, + "value": "tldraw SDK प्रयोग गरेर निर्माण गर्नुहोस्" + } + ], "96165d6df5": [ { "type": 0, diff --git a/apps/dotcom/client/public/tla/locales-compiled/nl.json b/apps/dotcom/client/public/tla/locales-compiled/nl.json index 44b98c454645..7c018d251609 100644 --- a/apps/dotcom/client/public/tla/locales-compiled/nl.json +++ b/apps/dotcom/client/public/tla/locales-compiled/nl.json @@ -561,6 +561,12 @@ "value": "Kopieer naar mijn bestanden" } ], + "95d2109dc8": [ + { + "type": 0, + "value": "Bouwen met de tldraw SDK" + } + ], "96165d6df5": [ { "type": 0, diff --git a/apps/dotcom/client/public/tla/locales-compiled/no.json b/apps/dotcom/client/public/tla/locales-compiled/no.json index 5870b3306aa6..33056775f6e4 100644 --- a/apps/dotcom/client/public/tla/locales-compiled/no.json +++ b/apps/dotcom/client/public/tla/locales-compiled/no.json @@ -565,6 +565,12 @@ "value": "Kopier til filene mine" } ], + "95d2109dc8": [ + { + "type": 0, + "value": "Bygg med tldraw SDK" + } + ], "96165d6df5": [ { "type": 0, diff --git a/apps/dotcom/client/public/tla/locales-compiled/pa.json b/apps/dotcom/client/public/tla/locales-compiled/pa.json index 6d5f45b8963c..e09c973f4402 100644 --- a/apps/dotcom/client/public/tla/locales-compiled/pa.json +++ b/apps/dotcom/client/public/tla/locales-compiled/pa.json @@ -561,6 +561,12 @@ "value": "ਮੇਰੀਆਂ ਫਾਈਲਾਂ ਵਿੱਚ ਕਾਪੀ ਕਰੋ" } ], + "95d2109dc8": [ + { + "type": 0, + "value": "tldraw SDK ਨਾਲ ਬਣਾਓ" + } + ], "96165d6df5": [ { "type": 0, diff --git a/apps/dotcom/client/public/tla/locales-compiled/pl.json b/apps/dotcom/client/public/tla/locales-compiled/pl.json index 896b8c764d29..288a892fc9f2 100644 --- a/apps/dotcom/client/public/tla/locales-compiled/pl.json +++ b/apps/dotcom/client/public/tla/locales-compiled/pl.json @@ -565,6 +565,12 @@ "value": "Kopiuj do moich plików" } ], + "95d2109dc8": [ + { + "type": 0, + "value": "Kompilacja z użyciem zestawu SDK tldraw" + } + ], "96165d6df5": [ { "type": 0, diff --git a/apps/dotcom/client/public/tla/locales-compiled/pt-br.json b/apps/dotcom/client/public/tla/locales-compiled/pt-br.json index c5f829158fa7..b92ae7d6ca51 100644 --- a/apps/dotcom/client/public/tla/locales-compiled/pt-br.json +++ b/apps/dotcom/client/public/tla/locales-compiled/pt-br.json @@ -565,6 +565,12 @@ "value": "Copiar para meus arquivos" } ], + "95d2109dc8": [ + { + "type": 0, + "value": "Construir com o SDK tldraw" + } + ], "96165d6df5": [ { "type": 0, diff --git a/apps/dotcom/client/public/tla/locales-compiled/pt-pt.json b/apps/dotcom/client/public/tla/locales-compiled/pt-pt.json index edbf766ce4df..206f8ebbbc37 100644 --- a/apps/dotcom/client/public/tla/locales-compiled/pt-pt.json +++ b/apps/dotcom/client/public/tla/locales-compiled/pt-pt.json @@ -565,6 +565,12 @@ "value": "Copiar para os meus ficheiros" } ], + "95d2109dc8": [ + { + "type": 0, + "value": "Construir com o SDK tldraw" + } + ], "96165d6df5": [ { "type": 0, diff --git a/apps/dotcom/client/public/tla/locales-compiled/ro.json b/apps/dotcom/client/public/tla/locales-compiled/ro.json index 1dae81fdc16e..c8f4104f11d5 100644 --- a/apps/dotcom/client/public/tla/locales-compiled/ro.json +++ b/apps/dotcom/client/public/tla/locales-compiled/ro.json @@ -565,6 +565,12 @@ "value": "Copiați în fișierele mele" } ], + "95d2109dc8": [ + { + "type": 0, + "value": "Construiți cu SDK-ul tldraw" + } + ], "96165d6df5": [ { "type": 0, diff --git a/apps/dotcom/client/public/tla/locales-compiled/ru.json b/apps/dotcom/client/public/tla/locales-compiled/ru.json index efd7027297c7..bc01f96ef03e 100644 --- a/apps/dotcom/client/public/tla/locales-compiled/ru.json +++ b/apps/dotcom/client/public/tla/locales-compiled/ru.json @@ -565,6 +565,12 @@ "value": "Скопировать в мои файлы" } ], + "95d2109dc8": [ + { + "type": 0, + "value": "Сборка с помощью tldraw SDK" + } + ], "96165d6df5": [ { "type": 0, diff --git a/apps/dotcom/client/public/tla/locales-compiled/sl.json b/apps/dotcom/client/public/tla/locales-compiled/sl.json index d1cd956312d7..a65c4e1c16b5 100644 --- a/apps/dotcom/client/public/tla/locales-compiled/sl.json +++ b/apps/dotcom/client/public/tla/locales-compiled/sl.json @@ -565,6 +565,12 @@ "value": "Kopiraj v moje datoteke" } ], + "95d2109dc8": [ + { + "type": 0, + "value": "Zgradite s kompletom za razvoj programske opreme tldraw" + } + ], "96165d6df5": [ { "type": 0, diff --git a/apps/dotcom/client/public/tla/locales-compiled/so.json b/apps/dotcom/client/public/tla/locales-compiled/so.json index 39faa4bbd615..5b26e603dab0 100644 --- a/apps/dotcom/client/public/tla/locales-compiled/so.json +++ b/apps/dotcom/client/public/tla/locales-compiled/so.json @@ -565,6 +565,12 @@ "value": "Ku koobbi faylalkayga" } ], + "95d2109dc8": [ + { + "type": 0, + "value": "Ku dhis tldraw SDK" + } + ], "96165d6df5": [ { "type": 0, diff --git a/apps/dotcom/client/public/tla/locales-compiled/sv.json b/apps/dotcom/client/public/tla/locales-compiled/sv.json index b46e9241ca50..5418379a3b8e 100644 --- a/apps/dotcom/client/public/tla/locales-compiled/sv.json +++ b/apps/dotcom/client/public/tla/locales-compiled/sv.json @@ -565,6 +565,12 @@ "value": "Kopiera till mina filer" } ], + "95d2109dc8": [ + { + "type": 0, + "value": "Bygg med tldraw SDK" + } + ], "96165d6df5": [ { "type": 0, diff --git a/apps/dotcom/client/public/tla/locales-compiled/ta.json b/apps/dotcom/client/public/tla/locales-compiled/ta.json index 4a339a5a80cf..bfd3c81bd429 100644 --- a/apps/dotcom/client/public/tla/locales-compiled/ta.json +++ b/apps/dotcom/client/public/tla/locales-compiled/ta.json @@ -561,6 +561,12 @@ "value": "எனது கோப்புகளுக்கு நகலெடுக்கவும்" } ], + "95d2109dc8": [ + { + "type": 0, + "value": "tldraw SDK உடன் உருவாக்கவும்" + } + ], "96165d6df5": [ { "type": 0, diff --git a/apps/dotcom/client/public/tla/locales-compiled/te.json b/apps/dotcom/client/public/tla/locales-compiled/te.json index 87f0175062e0..7b74b0462418 100644 --- a/apps/dotcom/client/public/tla/locales-compiled/te.json +++ b/apps/dotcom/client/public/tla/locales-compiled/te.json @@ -561,6 +561,12 @@ "value": "నా ఫైల్‌లకు కాపీ చేయండి" } ], + "95d2109dc8": [ + { + "type": 0, + "value": "tldraw SDK తో నిర్మించండి" + } + ], "96165d6df5": [ { "type": 0, diff --git a/apps/dotcom/client/public/tla/locales-compiled/th.json b/apps/dotcom/client/public/tla/locales-compiled/th.json index 00638e164eaf..e597f2dc48be 100644 --- a/apps/dotcom/client/public/tla/locales-compiled/th.json +++ b/apps/dotcom/client/public/tla/locales-compiled/th.json @@ -565,6 +565,12 @@ "value": "คัดลอกไปยังไฟล์ของฉัน" } ], + "95d2109dc8": [ + { + "type": 0, + "value": "สร้างด้วย tldraw SDK" + } + ], "96165d6df5": [ { "type": 0, diff --git a/apps/dotcom/client/public/tla/locales-compiled/tl.json b/apps/dotcom/client/public/tla/locales-compiled/tl.json index 68897c20f961..3de66ffff1f4 100644 --- a/apps/dotcom/client/public/tla/locales-compiled/tl.json +++ b/apps/dotcom/client/public/tla/locales-compiled/tl.json @@ -565,6 +565,12 @@ "value": "Kopyahin sa aking mga file" } ], + "95d2109dc8": [ + { + "type": 0, + "value": "Bumuo gamit ang tldraw SDK" + } + ], "96165d6df5": [ { "type": 0, diff --git a/apps/dotcom/client/public/tla/locales-compiled/tr.json b/apps/dotcom/client/public/tla/locales-compiled/tr.json index 646019d94668..6d8df3d894dc 100644 --- a/apps/dotcom/client/public/tla/locales-compiled/tr.json +++ b/apps/dotcom/client/public/tla/locales-compiled/tr.json @@ -561,6 +561,12 @@ "value": "Dosyalarıma kopyala" } ], + "95d2109dc8": [ + { + "type": 0, + "value": "tldraw SDK ile oluşturun" + } + ], "96165d6df5": [ { "type": 0, diff --git a/apps/dotcom/client/public/tla/locales-compiled/uk.json b/apps/dotcom/client/public/tla/locales-compiled/uk.json index 67d08707ae52..c4c554e97ed1 100644 --- a/apps/dotcom/client/public/tla/locales-compiled/uk.json +++ b/apps/dotcom/client/public/tla/locales-compiled/uk.json @@ -565,6 +565,12 @@ "value": "Копіювати в мої файли" } ], + "95d2109dc8": [ + { + "type": 0, + "value": "Збірка за допомогою tldraw SDK" + } + ], "96165d6df5": [ { "type": 0, diff --git a/apps/dotcom/client/public/tla/locales-compiled/ur.json b/apps/dotcom/client/public/tla/locales-compiled/ur.json index a6a687c5276b..4b7d15da21da 100644 --- a/apps/dotcom/client/public/tla/locales-compiled/ur.json +++ b/apps/dotcom/client/public/tla/locales-compiled/ur.json @@ -561,6 +561,12 @@ "value": "میری فائلوں میں کاپی کریں۔" } ], + "95d2109dc8": [ + { + "type": 0, + "value": "tldraw SDK کے ساتھ بنائیں" + } + ], "96165d6df5": [ { "type": 0, diff --git a/apps/dotcom/client/public/tla/locales-compiled/vi.json b/apps/dotcom/client/public/tla/locales-compiled/vi.json index dea7a70d3c7f..1c68edb18805 100644 --- a/apps/dotcom/client/public/tla/locales-compiled/vi.json +++ b/apps/dotcom/client/public/tla/locales-compiled/vi.json @@ -565,6 +565,12 @@ "value": "Sao chép vào tệp của tôi" } ], + "95d2109dc8": [ + { + "type": 0, + "value": "Xây dựng với SDK tldraw" + } + ], "96165d6df5": [ { "type": 0, diff --git a/apps/dotcom/client/public/tla/locales-compiled/zh-cn.json b/apps/dotcom/client/public/tla/locales-compiled/zh-cn.json index 3ebf30c89a6c..98b36a9878f2 100644 --- a/apps/dotcom/client/public/tla/locales-compiled/zh-cn.json +++ b/apps/dotcom/client/public/tla/locales-compiled/zh-cn.json @@ -565,6 +565,12 @@ "value": "复制到我的文件" } ], + "95d2109dc8": [ + { + "type": 0, + "value": "使用 tldraw SDK 构建" + } + ], "96165d6df5": [ { "type": 0, diff --git a/apps/dotcom/client/public/tla/locales-compiled/zh-tw.json b/apps/dotcom/client/public/tla/locales-compiled/zh-tw.json index bae64bed76d5..615033cb4676 100644 --- a/apps/dotcom/client/public/tla/locales-compiled/zh-tw.json +++ b/apps/dotcom/client/public/tla/locales-compiled/zh-tw.json @@ -565,6 +565,12 @@ "value": "複製到我的檔案" } ], + "95d2109dc8": [ + { + "type": 0, + "value": "使用 tldraw SDK 構建" + } + ], "96165d6df5": [ { "type": 0, diff --git a/apps/dotcom/client/public/tla/locales/ar.json b/apps/dotcom/client/public/tla/locales/ar.json index a8c0cb8250a7..7d6c11280c20 100644 --- a/apps/dotcom/client/public/tla/locales/ar.json +++ b/apps/dotcom/client/public/tla/locales/ar.json @@ -98,12 +98,6 @@ "47839e47a5": { "translation": "tldraw" }, - "7697920637": { - "translation": "يرجى إعادة التحميل" - }, - "764671e008": { - "translation": "تحدث معنا على Discord" - }, "4908687e50": { "translation": "هل أنت متأكد من أنك تريد نسيان هذا الملف؟" }, @@ -200,6 +194,12 @@ "761e93ede9": { "translation": "إدارة ملفات تعريف الارتباط" }, + "7697920637": { + "translation": "يرجى إعادة التحميل" + }, + "764671e008": { + "translation": "تحدث معنا على Discord" + }, "777f9e90cf": { "translation": "طلب غير صالح." }, @@ -257,6 +257,9 @@ "91e49bb0eb": { "translation": "نسخ إلى ملفاتي" }, + "95d2109dc8": { + "translation": "البناء باستخدام SDK tldraw" + }, "96165d6df5": { "translation": "هذا الشهر" }, diff --git a/apps/dotcom/client/public/tla/locales/bn.json b/apps/dotcom/client/public/tla/locales/bn.json index 7d49672ddb40..4483f5c7ddc8 100644 --- a/apps/dotcom/client/public/tla/locales/bn.json +++ b/apps/dotcom/client/public/tla/locales/bn.json @@ -98,12 +98,6 @@ "47839e47a5": { "translation": "tldraw" }, - "7697920637": { - "translation": "পুনরায় লোড করুন" - }, - "764671e008": { - "translation": "ডিসকর্ডে আমাদের সাথে চ্যাট করুন" - }, "4908687e50": { "translation": "আপনি কি নিশ্চিত আপনি এই ফাইলটি ভুলে যেতে চান?" }, @@ -200,6 +194,12 @@ "761e93ede9": { "translation": "কুকিজ পরিচালনা করুন" }, + "7697920637": { + "translation": "পুনরায় লোড করুন" + }, + "764671e008": { + "translation": "ডিসকর্ডে আমাদের সাথে চ্যাট করুন" + }, "777f9e90cf": { "translation": "অবৈধ অনুরোধ." }, @@ -257,6 +257,9 @@ "91e49bb0eb": { "translation": "আমার ফাইল কপি" }, + "95d2109dc8": { + "translation": "tldraw SDK দিয়ে তৈরি করুন" + }, "96165d6df5": { "translation": "এই মাসে" }, diff --git a/apps/dotcom/client/public/tla/locales/ca.json b/apps/dotcom/client/public/tla/locales/ca.json index b8724bbe57ea..62bfd31e22d0 100644 --- a/apps/dotcom/client/public/tla/locales/ca.json +++ b/apps/dotcom/client/public/tla/locales/ca.json @@ -98,12 +98,6 @@ "47839e47a5": { "translation": "tldraw" }, - "7697920637": { - "translation": "Torneu a carregar" - }, - "764671e008": { - "translation": "Xateja amb nosaltres a Discord" - }, "4908687e50": { "translation": "Esteu segur que voleu oblidar aquest fitxer?" }, @@ -200,6 +194,12 @@ "761e93ede9": { "translation": "Gestionar cookies" }, + "7697920637": { + "translation": "Torneu a carregar" + }, + "764671e008": { + "translation": "Xateja amb nosaltres a Discord" + }, "777f9e90cf": { "translation": "Sol·licitud no vàlida." }, @@ -257,6 +257,9 @@ "91e49bb0eb": { "translation": "Copia als meus fitxers" }, + "95d2109dc8": { + "translation": "Compilar amb el SDK de tldraw" + }, "96165d6df5": { "translation": "Aquest mes" }, diff --git a/apps/dotcom/client/public/tla/locales/cs.json b/apps/dotcom/client/public/tla/locales/cs.json index 3b1f61cb96c3..a5673db839fb 100644 --- a/apps/dotcom/client/public/tla/locales/cs.json +++ b/apps/dotcom/client/public/tla/locales/cs.json @@ -98,12 +98,6 @@ "47839e47a5": { "translation": "tldraw" }, - "7697920637": { - "translation": "Načtěte znovu" - }, - "764671e008": { - "translation": "Chatujte s námi na Discordu" - }, "4908687e50": { "translation": "Opravdu chcete tento soubor zapomenout?" }, @@ -200,6 +194,12 @@ "761e93ede9": { "translation": "Spravovat soubory cookie" }, + "7697920637": { + "translation": "Načtěte znovu" + }, + "764671e008": { + "translation": "Chatujte s námi na Discordu" + }, "777f9e90cf": { "translation": "Neplatný požadavek." }, @@ -257,6 +257,9 @@ "91e49bb0eb": { "translation": "Kopírovat do mých souborů" }, + "95d2109dc8": { + "translation": "Sestavení s tldraw SDK" + }, "96165d6df5": { "translation": "Tento měsíc" }, diff --git a/apps/dotcom/client/public/tla/locales/da.json b/apps/dotcom/client/public/tla/locales/da.json index f1c63640362c..ebbbd30a3d47 100644 --- a/apps/dotcom/client/public/tla/locales/da.json +++ b/apps/dotcom/client/public/tla/locales/da.json @@ -98,12 +98,6 @@ "47839e47a5": { "translation": "tltegn" }, - "7697920637": { - "translation": "Genindlæs venligst" - }, - "764671e008": { - "translation": "Chat med os på Discord" - }, "4908687e50": { "translation": "Er du sikker på, at du vil glemme denne fil?" }, @@ -200,6 +194,12 @@ "761e93ede9": { "translation": "Administrer cookies" }, + "7697920637": { + "translation": "Genindlæs venligst" + }, + "764671e008": { + "translation": "Chat med os på Discord" + }, "777f9e90cf": { "translation": "Ugyldig anmodning." }, @@ -257,6 +257,9 @@ "91e49bb0eb": { "translation": "Kopier til mine filer" }, + "95d2109dc8": { + "translation": "Byg med tldraw SDK'et" + }, "96165d6df5": { "translation": "Denne måned" }, diff --git a/apps/dotcom/client/public/tla/locales/de.json b/apps/dotcom/client/public/tla/locales/de.json index 04ebc0cff38f..83089192bbbf 100644 --- a/apps/dotcom/client/public/tla/locales/de.json +++ b/apps/dotcom/client/public/tla/locales/de.json @@ -98,12 +98,6 @@ "47839e47a5": { "translation": "tldraw" }, - "7697920637": { - "translation": "Bitte neu laden" - }, - "764671e008": { - "translation": "Chatten Sie mit uns auf Discord" - }, "4908687e50": { "translation": "Möchten Sie diese Datei wirklich vergessen?" }, @@ -200,6 +194,12 @@ "761e93ede9": { "translation": "Cookies anpassen" }, + "7697920637": { + "translation": "Bitte neu laden" + }, + "764671e008": { + "translation": "Chatten Sie mit uns auf Discord" + }, "777f9e90cf": { "translation": "Ungültige Anfrage." }, @@ -257,6 +257,9 @@ "91e49bb0eb": { "translation": "In meine Dateien kopieren" }, + "95d2109dc8": { + "translation": "Erstellen mit dem tldraw SDK" + }, "96165d6df5": { "translation": "Diesen Monat" }, diff --git a/apps/dotcom/client/public/tla/locales/el.json b/apps/dotcom/client/public/tla/locales/el.json index 9c4ba8acda68..b4e2b79ef541 100644 --- a/apps/dotcom/client/public/tla/locales/el.json +++ b/apps/dotcom/client/public/tla/locales/el.json @@ -98,12 +98,6 @@ "47839e47a5": { "translation": "tdraw" }, - "7697920637": { - "translation": "Παρακαλώ επαναφόρτωση" - }, - "764671e008": { - "translation": "Συνομιλήστε μαζί μας στο Discord" - }, "4908687e50": { "translation": "Είστε βέβαιοι ότι θέλετε να ξεχάσετε αυτό το αρχείο;" }, @@ -200,6 +194,12 @@ "761e93ede9": { "translation": "Διαχείριση cookies" }, + "7697920637": { + "translation": "Παρακαλώ επαναφόρτωση" + }, + "764671e008": { + "translation": "Συνομιλήστε μαζί μας στο Discord" + }, "777f9e90cf": { "translation": "Μη έγκυρο αίτημα." }, @@ -257,6 +257,9 @@ "91e49bb0eb": { "translation": "Αντιγραφή στα αρχεία μου" }, + "95d2109dc8": { + "translation": "Δημιουργήστε με το tldraw SDK" + }, "96165d6df5": { "translation": "Αυτόν τον μήνα" }, diff --git a/apps/dotcom/client/public/tla/locales/es.json b/apps/dotcom/client/public/tla/locales/es.json index 6a073c9dc7d8..dc803aa7cdb9 100644 --- a/apps/dotcom/client/public/tla/locales/es.json +++ b/apps/dotcom/client/public/tla/locales/es.json @@ -98,12 +98,6 @@ "47839e47a5": { "translation": "tldraw" }, - "7697920637": { - "translation": "Por favor recarga" - }, - "764671e008": { - "translation": "Chatea con nosotros en Discord" - }, "4908687e50": { "translation": "¿Seguro que quiere olvidar este archivo?" }, @@ -200,6 +194,12 @@ "761e93ede9": { "translation": "Administrar cookies" }, + "7697920637": { + "translation": "Por favor recarga" + }, + "764671e008": { + "translation": "Chatea con nosotros en Discord" + }, "777f9e90cf": { "translation": "Solicitud no válida." }, @@ -257,6 +257,9 @@ "91e49bb0eb": { "translation": "Copiar en mis archivos" }, + "95d2109dc8": { + "translation": "Construir con el SDK tldraw" + }, "96165d6df5": { "translation": "Este mes" }, diff --git a/apps/dotcom/client/public/tla/locales/fa.json b/apps/dotcom/client/public/tla/locales/fa.json index 376226848260..90ae5eb6f6f6 100644 --- a/apps/dotcom/client/public/tla/locales/fa.json +++ b/apps/dotcom/client/public/tla/locales/fa.json @@ -98,12 +98,6 @@ "47839e47a5": { "translation": "ترسیم کنید" }, - "7697920637": { - "translation": "لطفاً دوباره بارگیری کنید" - }, - "764671e008": { - "translation": "با ما در Discord چت کنید" - }, "4908687e50": { "translation": "آیا مطمئن هستید که می خواهید این فایل را فراموش کنید؟" }, @@ -200,6 +194,12 @@ "761e93ede9": { "translation": "مدیریت کوکی ها" }, + "7697920637": { + "translation": "لطفاً دوباره بارگیری کنید" + }, + "764671e008": { + "translation": "با ما در Discord چت کنید" + }, "777f9e90cf": { "translation": "درخواست نامعتبر" }, @@ -257,6 +257,9 @@ "91e49bb0eb": { "translation": "در فایل های من کپی کنید" }, + "95d2109dc8": { + "translation": "با tldraw SDK بسازید" + }, "96165d6df5": { "translation": "این ماه" }, diff --git a/apps/dotcom/client/public/tla/locales/fi.json b/apps/dotcom/client/public/tla/locales/fi.json index 405b62e7ad91..9642106f729d 100644 --- a/apps/dotcom/client/public/tla/locales/fi.json +++ b/apps/dotcom/client/public/tla/locales/fi.json @@ -98,12 +98,6 @@ "47839e47a5": { "translation": "tldraw" }, - "7697920637": { - "translation": "Lataa uudelleen" - }, - "764671e008": { - "translation": "Keskustele kanssamme Discordissa" - }, "4908687e50": { "translation": "Haluatko varmasti unohtaa tämän tiedoston?" }, @@ -200,6 +194,12 @@ "761e93ede9": { "translation": "Hallinnoi evästeitä" }, + "7697920637": { + "translation": "Lataa uudelleen" + }, + "764671e008": { + "translation": "Keskustele kanssamme Discordissa" + }, "777f9e90cf": { "translation": "Virheellinen pyyntö." }, @@ -257,6 +257,9 @@ "91e49bb0eb": { "translation": "Kopioi tiedostoihini" }, + "95d2109dc8": { + "translation": "Rakenna tldraw SDK:lla" + }, "96165d6df5": { "translation": "Tämä kuukausi" }, diff --git a/apps/dotcom/client/public/tla/locales/fr.json b/apps/dotcom/client/public/tla/locales/fr.json index ebc5ef0c37cc..912ca437766a 100644 --- a/apps/dotcom/client/public/tla/locales/fr.json +++ b/apps/dotcom/client/public/tla/locales/fr.json @@ -98,12 +98,6 @@ "47839e47a5": { "translation": "tldraw" }, - "7697920637": { - "translation": "Veuillez recharger" - }, - "764671e008": { - "translation": "Discutez avec nous sur Discord" - }, "4908687e50": { "translation": "Voulez-vous vraiment oublier ce fichier ?" }, @@ -200,6 +194,12 @@ "761e93ede9": { "translation": "Gérer les cookies" }, + "7697920637": { + "translation": "Veuillez recharger" + }, + "764671e008": { + "translation": "Discutez avec nous sur Discord" + }, "777f9e90cf": { "translation": "Demande invalide." }, @@ -257,6 +257,9 @@ "91e49bb0eb": { "translation": "Copier dans mes fichiers" }, + "95d2109dc8": { + "translation": "Construire avec le SDK tldraw" + }, "96165d6df5": { "translation": "Ce mois-ci" }, diff --git a/apps/dotcom/client/public/tla/locales/gl.json b/apps/dotcom/client/public/tla/locales/gl.json index 6e306af4fa15..07ca2ebffc45 100644 --- a/apps/dotcom/client/public/tla/locales/gl.json +++ b/apps/dotcom/client/public/tla/locales/gl.json @@ -98,12 +98,6 @@ "47839e47a5": { "translation": "tldraw" }, - "7697920637": { - "translation": "Volve cargar" - }, - "764671e008": { - "translation": "Chatea connosco en Discord" - }, "4908687e50": { "translation": "Estás seguro de que queres esquecer este ficheiro?" }, @@ -200,6 +194,12 @@ "761e93ede9": { "translation": "Xestionar cookies" }, + "7697920637": { + "translation": "Volve cargar" + }, + "764671e008": { + "translation": "Chatea connosco en Discord" + }, "777f9e90cf": { "translation": "Solicitude non válida." }, @@ -257,6 +257,9 @@ "91e49bb0eb": { "translation": "Copiar nos meus ficheiros" }, + "95d2109dc8": { + "translation": "Compilar co SDK de tldraw" + }, "96165d6df5": { "translation": "Este mes" }, diff --git a/apps/dotcom/client/public/tla/locales/gu-in.json b/apps/dotcom/client/public/tla/locales/gu-in.json index e6c2eeb5f55a..f69aaa5422dc 100644 --- a/apps/dotcom/client/public/tla/locales/gu-in.json +++ b/apps/dotcom/client/public/tla/locales/gu-in.json @@ -98,12 +98,6 @@ "47839e47a5": { "translation": "tldraw" }, - "7697920637": { - "translation": "કૃપા કરીને ફરીથી લોડ કરો" - }, - "764671e008": { - "translation": "ડિસ્કોર્ડ પર અમારી સાથે ચેટ કરો" - }, "4908687e50": { "translation": "શું તમે ખરેખર આ ફાઇલને ભૂલી જવા માંગો છો?" }, @@ -200,6 +194,12 @@ "761e93ede9": { "translation": "કૂકીઝ મેનેજ કરો" }, + "7697920637": { + "translation": "કૃપા કરીને ફરીથી લોડ કરો" + }, + "764671e008": { + "translation": "ડિસ્કોર્ડ પર અમારી સાથે ચેટ કરો" + }, "777f9e90cf": { "translation": "અમાન્ય વિનંતી." }, @@ -257,6 +257,9 @@ "91e49bb0eb": { "translation": "મારી ફાઇલોમાં કૉપિ કરો" }, + "95d2109dc8": { + "translation": "tldraw SDK વડે બનાવો" + }, "96165d6df5": { "translation": "આ મહિને" }, diff --git a/apps/dotcom/client/public/tla/locales/he.json b/apps/dotcom/client/public/tla/locales/he.json index 8944cdbcaf94..62cc7cbf6eb3 100644 --- a/apps/dotcom/client/public/tla/locales/he.json +++ b/apps/dotcom/client/public/tla/locales/he.json @@ -98,12 +98,6 @@ "47839e47a5": { "translation": "tldraw" }, - "7697920637": { - "translation": "נא לטעון מחדש" - }, - "764671e008": { - "translation": "צ'אט איתנו בדיסקורד" - }, "4908687e50": { "translation": "רוצה בוודאות לשכוח את הקובץ הזה?" }, @@ -200,6 +194,12 @@ "761e93ede9": { "translation": "נהל עוגיות" }, + "7697920637": { + "translation": "נא לטעון מחדש" + }, + "764671e008": { + "translation": "צ'אט איתנו בדיסקורד" + }, "777f9e90cf": { "translation": "בקשה לא חוקית." }, @@ -257,6 +257,9 @@ "91e49bb0eb": { "translation": "העתקה לקבצים שלי" }, + "95d2109dc8": { + "translation": "בנה עם ערכת פיתוח התוכנה tldraw" + }, "96165d6df5": { "translation": "החודש הזה" }, diff --git a/apps/dotcom/client/public/tla/locales/hi-in.json b/apps/dotcom/client/public/tla/locales/hi-in.json index 10df3ad7b61f..db019afc6b3f 100644 --- a/apps/dotcom/client/public/tla/locales/hi-in.json +++ b/apps/dotcom/client/public/tla/locales/hi-in.json @@ -98,12 +98,6 @@ "47839e47a5": { "translation": "tldraw" }, - "7697920637": { - "translation": "कृपया पुनः लोड करें" - }, - "764671e008": { - "translation": "डिस्कॉर्ड पर हमसे चैट करें" - }, "4908687e50": { "translation": "क्या आप वाकई इस फाइल को भूलना चाहते है?" }, @@ -200,6 +194,12 @@ "761e93ede9": { "translation": "कुकीज़ प्रबंधित करें" }, + "7697920637": { + "translation": "कृपया पुनः लोड करें" + }, + "764671e008": { + "translation": "डिस्कॉर्ड पर हमसे चैट करें" + }, "777f9e90cf": { "translation": "अमान्य रिक्वेस्ट।" }, @@ -257,6 +257,9 @@ "91e49bb0eb": { "translation": "मेरी फाइलों में कॉपी करें" }, + "95d2109dc8": { + "translation": "tldraw SDK के साथ बनाएँ" + }, "96165d6df5": { "translation": "इस महीने" }, diff --git a/apps/dotcom/client/public/tla/locales/hr.json b/apps/dotcom/client/public/tla/locales/hr.json index 1a67fb8deadf..826f93381f5d 100644 --- a/apps/dotcom/client/public/tla/locales/hr.json +++ b/apps/dotcom/client/public/tla/locales/hr.json @@ -98,12 +98,6 @@ "47839e47a5": { "translation": "tldraw" }, - "7697920637": { - "translation": "Molimo ponovno učitajte" - }, - "764671e008": { - "translation": "Razgovarajte s nama na Discordu" - }, "4908687e50": { "translation": "Jeste li sigurni da želite zaboraviti ovu datoteku?" }, @@ -200,6 +194,12 @@ "761e93ede9": { "translation": "Upravljanje kolačićima" }, + "7697920637": { + "translation": "Molimo ponovno učitajte" + }, + "764671e008": { + "translation": "Razgovarajte s nama na Discordu" + }, "777f9e90cf": { "translation": "Neispravan zahtjev." }, @@ -257,6 +257,9 @@ "91e49bb0eb": { "translation": "Kopiraj u moje datoteke" }, + "95d2109dc8": { + "translation": "Izgradite s tldraw SDK-om" + }, "96165d6df5": { "translation": "Ovaj mjesec" }, diff --git a/apps/dotcom/client/public/tla/locales/hu.json b/apps/dotcom/client/public/tla/locales/hu.json index 887ebea9c4b4..12dd1603a525 100644 --- a/apps/dotcom/client/public/tla/locales/hu.json +++ b/apps/dotcom/client/public/tla/locales/hu.json @@ -98,12 +98,6 @@ "47839e47a5": { "translation": "tldraw" }, - "7697920637": { - "translation": "Kérjük, töltse újra" - }, - "764671e008": { - "translation": "Csevegés velünk a Discordon" - }, "4908687e50": { "translation": "Biztosan elfelejti ezt a fájlt?" }, @@ -200,6 +194,12 @@ "761e93ede9": { "translation": "Cookie-k kezelése" }, + "7697920637": { + "translation": "Kérjük, töltse újra" + }, + "764671e008": { + "translation": "Csevegés velünk a Discordon" + }, "777f9e90cf": { "translation": "Érvénytelen kérés." }, @@ -257,6 +257,9 @@ "91e49bb0eb": { "translation": "Másolás a fájljaim közé" }, + "95d2109dc8": { + "translation": "Fordítás a tldraw SDK-val" + }, "96165d6df5": { "translation": "Ebben a hónapban" }, diff --git a/apps/dotcom/client/public/tla/locales/id.json b/apps/dotcom/client/public/tla/locales/id.json index d3dd4f071f9a..78596103f482 100644 --- a/apps/dotcom/client/public/tla/locales/id.json +++ b/apps/dotcom/client/public/tla/locales/id.json @@ -98,12 +98,6 @@ "47839e47a5": { "translation": "tldraw" }, - "7697920637": { - "translation": "Silakan muat ulang" - }, - "764671e008": { - "translation": "Ngobrol dengan kami di Discord" - }, "4908687e50": { "translation": "Yakin ingin mengabaikan file ini?" }, @@ -200,6 +194,12 @@ "761e93ede9": { "translation": "Kelola cookie" }, + "7697920637": { + "translation": "Silakan muat ulang" + }, + "764671e008": { + "translation": "Ngobrol dengan kami di Discord" + }, "777f9e90cf": { "translation": "Permintaan tidak valid." }, @@ -257,6 +257,9 @@ "91e49bb0eb": { "translation": "Salin ke file saya" }, + "95d2109dc8": { + "translation": "Membangun dengan tldraw SDK" + }, "96165d6df5": { "translation": "Bulan ini" }, diff --git a/apps/dotcom/client/public/tla/locales/it.json b/apps/dotcom/client/public/tla/locales/it.json index 8a66bee6d2aa..8aa558ae595a 100644 --- a/apps/dotcom/client/public/tla/locales/it.json +++ b/apps/dotcom/client/public/tla/locales/it.json @@ -98,12 +98,6 @@ "47839e47a5": { "translation": "tldraw" }, - "7697920637": { - "translation": "Per favore ricarica" - }, - "764671e008": { - "translation": "Chatta con noi su Discord" - }, "4908687e50": { "translation": "Confermi di voler dimenticare questo file?" }, @@ -200,6 +194,12 @@ "761e93ede9": { "translation": "Gestisci i cookie" }, + "7697920637": { + "translation": "Per favore ricarica" + }, + "764671e008": { + "translation": "Chatta con noi su Discord" + }, "777f9e90cf": { "translation": "Richiesta non valida." }, @@ -257,6 +257,9 @@ "91e49bb0eb": { "translation": "Copia nei miei file" }, + "95d2109dc8": { + "translation": "Costruisci con l'SDK tldraw" + }, "96165d6df5": { "translation": "Questo mese" }, diff --git a/apps/dotcom/client/public/tla/locales/ja.json b/apps/dotcom/client/public/tla/locales/ja.json index 316eb4fad847..d2a3952fc3b3 100644 --- a/apps/dotcom/client/public/tla/locales/ja.json +++ b/apps/dotcom/client/public/tla/locales/ja.json @@ -98,12 +98,6 @@ "47839e47a5": { "translation": "tldraw" }, - "7697920637": { - "translation": "再読み込みしてください" - }, - "764671e008": { - "translation": "Discordでチャットしましょう" - }, "4908687e50": { "translation": "このファイルを無視しても本当によろしいですか?" }, @@ -200,6 +194,12 @@ "761e93ede9": { "translation": "クッキーを管理する" }, + "7697920637": { + "translation": "再読み込みしてください" + }, + "764671e008": { + "translation": "Discordでチャットしましょう" + }, "777f9e90cf": { "translation": "無効なリクエストです。" }, @@ -257,6 +257,9 @@ "91e49bb0eb": { "translation": "自分のファイルにコピー" }, + "95d2109dc8": { + "translation": "tldraw SDKでビルドする" + }, "96165d6df5": { "translation": "今月" }, diff --git a/apps/dotcom/client/public/tla/locales/km-kh.json b/apps/dotcom/client/public/tla/locales/km-kh.json index 383f984dc9cf..33f296088de8 100644 --- a/apps/dotcom/client/public/tla/locales/km-kh.json +++ b/apps/dotcom/client/public/tla/locales/km-kh.json @@ -98,12 +98,6 @@ "47839e47a5": { "translation": "tldraw" }, - "7697920637": { - "translation": "សូមផ្ទុកឡើងវិញ" - }, - "764671e008": { - "translation": "ជជែកជាមួយពួកយើងនៅលើ Discord" - }, "4908687e50": { "translation": "តើអ្នកប្រាកដថាចង់បំភ្លេចឯកសារនេះទេ?" }, @@ -200,6 +194,12 @@ "761e93ede9": { "translation": "គ្រប់គ្រងខូគី" }, + "7697920637": { + "translation": "សូមផ្ទុកឡើងវិញ" + }, + "764671e008": { + "translation": "ជជែកជាមួយពួកយើងនៅលើ Discord" + }, "777f9e90cf": { "translation": "សំណើមិនត្រឹមត្រូវ។" }, @@ -257,6 +257,9 @@ "91e49bb0eb": { "translation": "ចម្លងទៅឯកសាររបស់ខ្ញុំ" }, + "95d2109dc8": { + "translation": "បង្កើតជាមួយ tldraw SDK" + }, "96165d6df5": { "translation": "ខែនេះ។" }, diff --git a/apps/dotcom/client/public/tla/locales/kn.json b/apps/dotcom/client/public/tla/locales/kn.json index 409ebe3229e7..fcfb873c0d23 100644 --- a/apps/dotcom/client/public/tla/locales/kn.json +++ b/apps/dotcom/client/public/tla/locales/kn.json @@ -98,12 +98,6 @@ "47839e47a5": { "translation": "ಡ್ರಾ" }, - "7697920637": { - "translation": "ದಯವಿಟ್ಟು ಮರುಲೋಡ್ ಮಾಡಿ" - }, - "764671e008": { - "translation": "ಡಿಸ್ಕಾರ್ಡ್‌ನಲ್ಲಿ ನಮ್ಮೊಂದಿಗೆ ಚಾಟ್ ಮಾಡಿ" - }, "4908687e50": { "translation": "ಈ ಫೈಲ್ ಅನ್ನು ಮರೆಯಲು ನೀವು ಖಚಿತವಾಗಿ ಬಯಸುವಿರಾ?" }, @@ -200,6 +194,12 @@ "761e93ede9": { "translation": "ಕುಕೀಗಳನ್ನು ನಿರ್ವಹಿಸಿ" }, + "7697920637": { + "translation": "ದಯವಿಟ್ಟು ಮರುಲೋಡ್ ಮಾಡಿ" + }, + "764671e008": { + "translation": "ಡಿಸ್ಕಾರ್ಡ್‌ನಲ್ಲಿ ನಮ್ಮೊಂದಿಗೆ ಚಾಟ್ ಮಾಡಿ" + }, "777f9e90cf": { "translation": "ಅಮಾನ್ಯ ವಿನಂತಿ." }, @@ -257,6 +257,9 @@ "91e49bb0eb": { "translation": "ನನ್ನ ಫೈಲ್‌ಗಳಿಗೆ ನಕಲಿಸಿ" }, + "95d2109dc8": { + "translation": "tldraw SDK ಬಳಸಿ ನಿರ್ಮಿಸಿ" + }, "96165d6df5": { "translation": "ಈ ತಿಂಗಳು" }, diff --git a/apps/dotcom/client/public/tla/locales/ko-kr.json b/apps/dotcom/client/public/tla/locales/ko-kr.json index f851029090d8..e1e6936b4592 100644 --- a/apps/dotcom/client/public/tla/locales/ko-kr.json +++ b/apps/dotcom/client/public/tla/locales/ko-kr.json @@ -98,12 +98,6 @@ "47839e47a5": { "translation": "tldraw" }, - "7697920637": { - "translation": "다시 로드해주세요" - }, - "764671e008": { - "translation": "Discord에서 우리와 채팅하세요" - }, "4908687e50": { "translation": "이 파일을 무시하시겠습니까?" }, @@ -200,6 +194,12 @@ "761e93ede9": { "translation": "쿠키 관리" }, + "7697920637": { + "translation": "다시 로드해주세요" + }, + "764671e008": { + "translation": "Discord에서 우리와 채팅하세요" + }, "777f9e90cf": { "translation": "유효하지 않은 요청입니다." }, @@ -257,6 +257,9 @@ "91e49bb0eb": { "translation": "내 파일로 복사" }, + "95d2109dc8": { + "translation": "tldraw SDK로 빌드" + }, "96165d6df5": { "translation": "이번 달" }, diff --git a/apps/dotcom/client/public/tla/locales/ml.json b/apps/dotcom/client/public/tla/locales/ml.json index ffcc5779f95e..63370cca017e 100644 --- a/apps/dotcom/client/public/tla/locales/ml.json +++ b/apps/dotcom/client/public/tla/locales/ml.json @@ -98,12 +98,6 @@ "47839e47a5": { "translation": "tldraw" }, - "7697920637": { - "translation": "ദയവായി വീണ്ടും ലോഡുചെയ്യുക" - }, - "764671e008": { - "translation": "ഡിസ്കോർഡിൽ ഞങ്ങളുമായി ചാറ്റ് ചെയ്യൂ" - }, "4908687e50": { "translation": "ഈ ഫയൽ മറക്കണമെന്ന് തീർച്ചയാണോ?" }, @@ -200,6 +194,12 @@ "761e93ede9": { "translation": "കുക്കികൾ നിയന്ത്രിക്കുക" }, + "7697920637": { + "translation": "ദയവായി വീണ്ടും ലോഡുചെയ്യുക" + }, + "764671e008": { + "translation": "ഡിസ്കോർഡിൽ ഞങ്ങളുമായി ചാറ്റ് ചെയ്യൂ" + }, "777f9e90cf": { "translation": "അസാധുവായ അഭ്യർത്ഥന." }, @@ -257,6 +257,9 @@ "91e49bb0eb": { "translation": "എൻ്റെ ഫയലുകളിലേക്ക് പകർത്തുക" }, + "95d2109dc8": { + "translation": "tldraw SDK ഉപയോഗിച്ച് നിർമ്മിക്കുക" + }, "96165d6df5": { "translation": "ഈ മാസം" }, diff --git a/apps/dotcom/client/public/tla/locales/mr.json b/apps/dotcom/client/public/tla/locales/mr.json index f1cade9fa09f..ac7b4700a4de 100644 --- a/apps/dotcom/client/public/tla/locales/mr.json +++ b/apps/dotcom/client/public/tla/locales/mr.json @@ -98,12 +98,6 @@ "47839e47a5": { "translation": "tldraw" }, - "7697920637": { - "translation": "कृपया रीलोड करा" - }, - "764671e008": { - "translation": "डिस्कॉर्डवर आमच्याशी गप्पा मारा" - }, "4908687e50": { "translation": "तुमची खात्री आहे की तुम्ही ही फाइल विसरू इच्छिता?" }, @@ -200,6 +194,12 @@ "761e93ede9": { "translation": "कुकीज व्यवस्थापित करा" }, + "7697920637": { + "translation": "कृपया रीलोड करा" + }, + "764671e008": { + "translation": "डिस्कॉर्डवर आमच्याशी गप्पा मारा" + }, "777f9e90cf": { "translation": "अवैध विनंती." }, @@ -257,6 +257,9 @@ "91e49bb0eb": { "translation": "माझ्या फाइल्समध्ये कॉपी करा" }, + "95d2109dc8": { + "translation": "tldraw SDK वापरून तयार करा" + }, "96165d6df5": { "translation": "या महिन्यात" }, diff --git a/apps/dotcom/client/public/tla/locales/ms.json b/apps/dotcom/client/public/tla/locales/ms.json index 0c368263c147..250f452d803e 100644 --- a/apps/dotcom/client/public/tla/locales/ms.json +++ b/apps/dotcom/client/public/tla/locales/ms.json @@ -98,12 +98,6 @@ "47839e47a5": { "translation": "tldraw" }, - "7697920637": { - "translation": "Sila muat semula" - }, - "764671e008": { - "translation": "Berbual dengan kami di Discord" - }, "4908687e50": { "translation": "Adakah anda pasti mahu melupakan fail ini?" }, @@ -200,6 +194,12 @@ "761e93ede9": { "translation": "Uruskan kuki" }, + "7697920637": { + "translation": "Sila muat semula" + }, + "764671e008": { + "translation": "Berbual dengan kami di Discord" + }, "777f9e90cf": { "translation": "Permintaan tidak sah." }, @@ -257,6 +257,9 @@ "91e49bb0eb": { "translation": "Salin ke fail saya" }, + "95d2109dc8": { + "translation": "Bina dengan tldraw SDK" + }, "96165d6df5": { "translation": "bulan ini" }, diff --git a/apps/dotcom/client/public/tla/locales/ne.json b/apps/dotcom/client/public/tla/locales/ne.json index 9c95ac829b7a..74866a6f46f2 100644 --- a/apps/dotcom/client/public/tla/locales/ne.json +++ b/apps/dotcom/client/public/tla/locales/ne.json @@ -98,12 +98,6 @@ "47839e47a5": { "translation": "tldraw" }, - "7697920637": { - "translation": "कृपया पुन: लोड गर्नुहोस्" - }, - "764671e008": { - "translation": "Discord मा हामीसँग कुराकानी गर्नुहोस्" - }, "4908687e50": { "translation": "के तपाइँ यो फाइल बिर्सन निश्चित हुनुहुन्छ?" }, @@ -200,6 +194,12 @@ "761e93ede9": { "translation": "कुकीहरू प्रबन्ध गर्नुहोस्" }, + "7697920637": { + "translation": "कृपया पुन: लोड गर्नुहोस्" + }, + "764671e008": { + "translation": "Discord मा हामीसँग कुराकानी गर्नुहोस्" + }, "777f9e90cf": { "translation": "अवैध अनुरोध।" }, @@ -257,6 +257,9 @@ "91e49bb0eb": { "translation": "मेरो फाइलहरूमा प्रतिलिपि गर्नुहोस्" }, + "95d2109dc8": { + "translation": "tldraw SDK प्रयोग गरेर निर्माण गर्नुहोस्" + }, "96165d6df5": { "translation": "यो महिना" }, diff --git a/apps/dotcom/client/public/tla/locales/nl.json b/apps/dotcom/client/public/tla/locales/nl.json index abfcf0178bf4..466f8a8f08df 100644 --- a/apps/dotcom/client/public/tla/locales/nl.json +++ b/apps/dotcom/client/public/tla/locales/nl.json @@ -98,12 +98,6 @@ "47839e47a5": { "translation": "tldraw" }, - "7697920637": { - "translation": "Gelieve opnieuw te laden" - }, - "764671e008": { - "translation": "Chat met ons op Discord" - }, "4908687e50": { "translation": "Weet u zeker dat u dit bestand wilt vergeten?" }, @@ -200,6 +194,12 @@ "761e93ede9": { "translation": "Cookies beheren" }, + "7697920637": { + "translation": "Gelieve opnieuw te laden" + }, + "764671e008": { + "translation": "Chat met ons op Discord" + }, "777f9e90cf": { "translation": "Ongeldig verzoek." }, @@ -257,6 +257,9 @@ "91e49bb0eb": { "translation": "Kopieer naar mijn bestanden" }, + "95d2109dc8": { + "translation": "Bouwen met de tldraw SDK" + }, "96165d6df5": { "translation": "Deze maand" }, diff --git a/apps/dotcom/client/public/tla/locales/no.json b/apps/dotcom/client/public/tla/locales/no.json index edb6bf8eed67..e70f4cf58910 100644 --- a/apps/dotcom/client/public/tla/locales/no.json +++ b/apps/dotcom/client/public/tla/locales/no.json @@ -98,12 +98,6 @@ "47839e47a5": { "translation": "tldra" }, - "7697920637": { - "translation": "Last inn på nytt" - }, - "764671e008": { - "translation": "Chat med oss ​​på Discord" - }, "4908687e50": { "translation": "Er du sikker på at du vil glemme denne filen?" }, @@ -200,6 +194,12 @@ "761e93ede9": { "translation": "Administrer informasjonskapsler" }, + "7697920637": { + "translation": "Last inn på nytt" + }, + "764671e008": { + "translation": "Chat med oss ​​på Discord" + }, "777f9e90cf": { "translation": "Ugyldig forespørsel." }, @@ -257,6 +257,9 @@ "91e49bb0eb": { "translation": "Kopier til filene mine" }, + "95d2109dc8": { + "translation": "Bygg med tldraw SDK" + }, "96165d6df5": { "translation": "Denne måneden" }, diff --git a/apps/dotcom/client/public/tla/locales/pa.json b/apps/dotcom/client/public/tla/locales/pa.json index 739cef679a8c..be8fe211e9fc 100644 --- a/apps/dotcom/client/public/tla/locales/pa.json +++ b/apps/dotcom/client/public/tla/locales/pa.json @@ -98,12 +98,6 @@ "47839e47a5": { "translation": "tldraw" }, - "7697920637": { - "translation": "ਕਿਰਪਾ ਕਰਕੇ ਰੀਲੋਡ ਕਰੋ" - }, - "764671e008": { - "translation": "ਡਿਸਕਾਰਡ 'ਤੇ ਸਾਡੇ ਨਾਲ ਗੱਲਬਾਤ ਕਰੋ" - }, "4908687e50": { "translation": "ਕੀ ਤੁਸੀਂ ਯਕੀਨੀ ਤੌਰ 'ਤੇ ਇਸ ਫ਼ਾਈਲ ਨੂੰ ਭੁੱਲਣਾ ਚਾਹੁੰਦੇ ਹੋ?" }, @@ -200,6 +194,12 @@ "761e93ede9": { "translation": "ਕੂਕੀਜ਼ ਦਾ ਪ੍ਰਬੰਧਨ ਕਰੋ" }, + "7697920637": { + "translation": "ਕਿਰਪਾ ਕਰਕੇ ਰੀਲੋਡ ਕਰੋ" + }, + "764671e008": { + "translation": "ਡਿਸਕਾਰਡ 'ਤੇ ਸਾਡੇ ਨਾਲ ਗੱਲਬਾਤ ਕਰੋ" + }, "777f9e90cf": { "translation": "ਅਵੈਧ ਬੇਨਤੀ।" }, @@ -257,6 +257,9 @@ "91e49bb0eb": { "translation": "ਮੇਰੀਆਂ ਫਾਈਲਾਂ ਵਿੱਚ ਕਾਪੀ ਕਰੋ" }, + "95d2109dc8": { + "translation": "tldraw SDK ਨਾਲ ਬਣਾਓ" + }, "96165d6df5": { "translation": "ਇਸ ਮਹੀਨੇ" }, diff --git a/apps/dotcom/client/public/tla/locales/pl.json b/apps/dotcom/client/public/tla/locales/pl.json index 13f97afdd152..1a52f45c2a14 100644 --- a/apps/dotcom/client/public/tla/locales/pl.json +++ b/apps/dotcom/client/public/tla/locales/pl.json @@ -98,12 +98,6 @@ "47839e47a5": { "translation": "tldraw" }, - "7697920637": { - "translation": "Proszę odświeżyć" - }, - "764671e008": { - "translation": "Porozmawiaj z nami na Discordzie" - }, "4908687e50": { "translation": "Czy na pewno chcesz zapomnieć ten plik?" }, @@ -200,6 +194,12 @@ "761e93ede9": { "translation": "Zarządzaj plikami cookie" }, + "7697920637": { + "translation": "Proszę odświeżyć" + }, + "764671e008": { + "translation": "Porozmawiaj z nami na Discordzie" + }, "777f9e90cf": { "translation": "Nieprawidłowe żądanie." }, @@ -257,6 +257,9 @@ "91e49bb0eb": { "translation": "Kopiuj do moich plików" }, + "95d2109dc8": { + "translation": "Kompilacja z użyciem zestawu SDK tldraw" + }, "96165d6df5": { "translation": "W tym miesiącu" }, diff --git a/apps/dotcom/client/public/tla/locales/pt-br.json b/apps/dotcom/client/public/tla/locales/pt-br.json index 4d4d858f3d31..3e5cd976d3ab 100644 --- a/apps/dotcom/client/public/tla/locales/pt-br.json +++ b/apps/dotcom/client/public/tla/locales/pt-br.json @@ -98,12 +98,6 @@ "47839e47a5": { "translation": "tldraw" }, - "7697920637": { - "translation": "Por favor recarregue" - }, - "764671e008": { - "translation": "Converse conosco no Discord" - }, "4908687e50": { "translation": "Tem certeza de que deseja esquecer este arquivo?" }, @@ -200,6 +194,12 @@ "761e93ede9": { "translation": "Gerenciar cookies" }, + "7697920637": { + "translation": "Por favor recarregue" + }, + "764671e008": { + "translation": "Converse conosco no Discord" + }, "777f9e90cf": { "translation": "Solicitação inválida." }, @@ -257,6 +257,9 @@ "91e49bb0eb": { "translation": "Copiar para meus arquivos" }, + "95d2109dc8": { + "translation": "Construir com o SDK tldraw" + }, "96165d6df5": { "translation": "Este mês" }, diff --git a/apps/dotcom/client/public/tla/locales/pt-pt.json b/apps/dotcom/client/public/tla/locales/pt-pt.json index fe91a12dd4d1..5b72eb4ab77c 100644 --- a/apps/dotcom/client/public/tla/locales/pt-pt.json +++ b/apps/dotcom/client/public/tla/locales/pt-pt.json @@ -98,12 +98,6 @@ "47839e47a5": { "translation": "tldraw" }, - "7697920637": { - "translation": "Por favor recarregue" - }, - "764671e008": { - "translation": "Converse conosco no Discord" - }, "4908687e50": { "translation": "Tem a certeza de que quer esquecer este ficheiro?" }, @@ -200,6 +194,12 @@ "761e93ede9": { "translation": "Gerenciar cookies" }, + "7697920637": { + "translation": "Por favor recarregue" + }, + "764671e008": { + "translation": "Converse conosco no Discord" + }, "777f9e90cf": { "translation": "Pedido inválido." }, @@ -257,6 +257,9 @@ "91e49bb0eb": { "translation": "Copiar para os meus ficheiros" }, + "95d2109dc8": { + "translation": "Construir com o SDK tldraw" + }, "96165d6df5": { "translation": "Este mês" }, diff --git a/apps/dotcom/client/public/tla/locales/ro.json b/apps/dotcom/client/public/tla/locales/ro.json index 77ee40862817..38542aeb477a 100644 --- a/apps/dotcom/client/public/tla/locales/ro.json +++ b/apps/dotcom/client/public/tla/locales/ro.json @@ -98,12 +98,6 @@ "47839e47a5": { "translation": "tldraw" }, - "7697920637": { - "translation": "Vă rugăm să reîncărcați" - }, - "764671e008": { - "translation": "Discutați cu noi pe Discord" - }, "4908687e50": { "translation": "Sigur vrei să uiți acest fișier?" }, @@ -200,6 +194,12 @@ "761e93ede9": { "translation": "Gestionați cookie-urile" }, + "7697920637": { + "translation": "Vă rugăm să reîncărcați" + }, + "764671e008": { + "translation": "Discutați cu noi pe Discord" + }, "777f9e90cf": { "translation": "Solicitare nevalidă." }, @@ -257,6 +257,9 @@ "91e49bb0eb": { "translation": "Copiați în fișierele mele" }, + "95d2109dc8": { + "translation": "Construiți cu SDK-ul tldraw" + }, "96165d6df5": { "translation": "Luna aceasta" }, diff --git a/apps/dotcom/client/public/tla/locales/ru.json b/apps/dotcom/client/public/tla/locales/ru.json index f42c0dfb6e83..aba5c046f522 100644 --- a/apps/dotcom/client/public/tla/locales/ru.json +++ b/apps/dotcom/client/public/tla/locales/ru.json @@ -98,12 +98,6 @@ "47839e47a5": { "translation": "tldraw" }, - "7697920637": { - "translation": "Пожалуйста, перезагрузите" - }, - "764671e008": { - "translation": "Пообщайтесь с нами в Discord" - }, "4908687e50": { "translation": "Вы уверены, что хотите забыть этот файл?" }, @@ -200,6 +194,12 @@ "761e93ede9": { "translation": "Управление куки-файлами" }, + "7697920637": { + "translation": "Пожалуйста, перезагрузите" + }, + "764671e008": { + "translation": "Пообщайтесь с нами в Discord" + }, "777f9e90cf": { "translation": "Неверный запрос." }, @@ -257,6 +257,9 @@ "91e49bb0eb": { "translation": "Скопировать в мои файлы" }, + "95d2109dc8": { + "translation": "Сборка с помощью tldraw SDK" + }, "96165d6df5": { "translation": "В этом месяце" }, diff --git a/apps/dotcom/client/public/tla/locales/sl.json b/apps/dotcom/client/public/tla/locales/sl.json index 8f54f4f3f5a3..57c51c99cd2d 100644 --- a/apps/dotcom/client/public/tla/locales/sl.json +++ b/apps/dotcom/client/public/tla/locales/sl.json @@ -98,12 +98,6 @@ "47839e47a5": { "translation": "tldraw" }, - "7697920637": { - "translation": "Ponovno naložite" - }, - "764671e008": { - "translation": "Klepetajte z nami na Discordu" - }, "4908687e50": { "translation": "Ali ste prepričani, da želite pozabiti to datoteko?" }, @@ -200,6 +194,12 @@ "761e93ede9": { "translation": "Upravljanje piškotkov" }, + "7697920637": { + "translation": "Ponovno naložite" + }, + "764671e008": { + "translation": "Klepetajte z nami na Discordu" + }, "777f9e90cf": { "translation": "Neveljavna zahteva." }, @@ -257,6 +257,9 @@ "91e49bb0eb": { "translation": "Kopiraj v moje datoteke" }, + "95d2109dc8": { + "translation": "Zgradite s kompletom za razvoj programske opreme tldraw" + }, "96165d6df5": { "translation": "Ta mesec" }, diff --git a/apps/dotcom/client/public/tla/locales/so.json b/apps/dotcom/client/public/tla/locales/so.json index 269034dff2ad..e0960309cbd2 100644 --- a/apps/dotcom/client/public/tla/locales/so.json +++ b/apps/dotcom/client/public/tla/locales/so.json @@ -98,12 +98,6 @@ "47839e47a5": { "translation": "tldraw" }, - "7697920637": { - "translation": "Fadlan dib u soo deji" - }, - "764671e008": { - "translation": "Nagala hadal Discord" - }, "4908687e50": { "translation": "Ma hubtaa inaad rabto inaad ilowdo faylkan?" }, @@ -200,6 +194,12 @@ "761e93ede9": { "translation": "Maamul cookies" }, + "7697920637": { + "translation": "Fadlan dib u soo deji" + }, + "764671e008": { + "translation": "Nagala hadal Discord" + }, "777f9e90cf": { "translation": "Codsi aan sax ahayn" }, @@ -257,6 +257,9 @@ "91e49bb0eb": { "translation": "Ku koobbi faylalkayga" }, + "95d2109dc8": { + "translation": "Ku dhis tldraw SDK" + }, "96165d6df5": { "translation": "Bishan" }, diff --git a/apps/dotcom/client/public/tla/locales/sv.json b/apps/dotcom/client/public/tla/locales/sv.json index 91208169534f..7f84adc6eb67 100644 --- a/apps/dotcom/client/public/tla/locales/sv.json +++ b/apps/dotcom/client/public/tla/locales/sv.json @@ -98,12 +98,6 @@ "47839e47a5": { "translation": "tldraw" }, - "7697920637": { - "translation": "Vänligen ladda om" - }, - "764671e008": { - "translation": "Chatta med oss ​​på Discord" - }, "4908687e50": { "translation": "Är du säker på att du vill glömma den här filen?" }, @@ -200,6 +194,12 @@ "761e93ede9": { "translation": "Hantera cookies" }, + "7697920637": { + "translation": "Vänligen ladda om" + }, + "764671e008": { + "translation": "Chatta med oss ​​på Discord" + }, "777f9e90cf": { "translation": "Ogiltig begäran." }, @@ -257,6 +257,9 @@ "91e49bb0eb": { "translation": "Kopiera till mina filer" }, + "95d2109dc8": { + "translation": "Bygg med tldraw SDK" + }, "96165d6df5": { "translation": "Denna månad" }, diff --git a/apps/dotcom/client/public/tla/locales/ta.json b/apps/dotcom/client/public/tla/locales/ta.json index ec99a15cb7b0..25ecc3b8fca7 100644 --- a/apps/dotcom/client/public/tla/locales/ta.json +++ b/apps/dotcom/client/public/tla/locales/ta.json @@ -98,12 +98,6 @@ "47839e47a5": { "translation": "வரைதல்" }, - "7697920637": { - "translation": "மீண்டும் ஏற்றவும்." - }, - "764671e008": { - "translation": "Discord-ல் எங்களுடன் அரட்டையடிக்கவும்" - }, "4908687e50": { "translation": "இந்தக் கோப்பை நிச்சயமாக மறக்க விரும்புகிறீர்களா?" }, @@ -200,6 +194,12 @@ "761e93ede9": { "translation": "குக்கீகளை நிர்வகிக்கவும்" }, + "7697920637": { + "translation": "மீண்டும் ஏற்றவும்." + }, + "764671e008": { + "translation": "Discord-ல் எங்களுடன் அரட்டையடிக்கவும்" + }, "777f9e90cf": { "translation": "தவறான கோரிக்கை." }, @@ -257,6 +257,9 @@ "91e49bb0eb": { "translation": "எனது கோப்புகளுக்கு நகலெடுக்கவும்" }, + "95d2109dc8": { + "translation": "tldraw SDK உடன் உருவாக்கவும்" + }, "96165d6df5": { "translation": "இந்த மாதம்" }, diff --git a/apps/dotcom/client/public/tla/locales/te.json b/apps/dotcom/client/public/tla/locales/te.json index eebcaefc0229..0e1df6e860ec 100644 --- a/apps/dotcom/client/public/tla/locales/te.json +++ b/apps/dotcom/client/public/tla/locales/te.json @@ -98,12 +98,6 @@ "47839e47a5": { "translation": "డ్రా" }, - "7697920637": { - "translation": "దయచేసి మళ్లీ లోడ్ చేయండి" - }, - "764671e008": { - "translation": "డిస్కార్డ్‌లో మాతో చాట్ చేయండి" - }, "4908687e50": { "translation": "మీరు ఖచ్చితంగా ఈ ఫైల్‌ను మర్చిపోవాలనుకుంటున్నారా?" }, @@ -200,6 +194,12 @@ "761e93ede9": { "translation": "కుక్కీలను నిర్వహించండి" }, + "7697920637": { + "translation": "దయచేసి మళ్లీ లోడ్ చేయండి" + }, + "764671e008": { + "translation": "డిస్కార్డ్‌లో మాతో చాట్ చేయండి" + }, "777f9e90cf": { "translation": "చెల్లని అభ్యర్థన." }, @@ -257,6 +257,9 @@ "91e49bb0eb": { "translation": "నా ఫైల్‌లకు కాపీ చేయండి" }, + "95d2109dc8": { + "translation": "tldraw SDK తో నిర్మించండి" + }, "96165d6df5": { "translation": "ఈ నెల" }, diff --git a/apps/dotcom/client/public/tla/locales/th.json b/apps/dotcom/client/public/tla/locales/th.json index 63ff99bed726..fcd78924fdb7 100644 --- a/apps/dotcom/client/public/tla/locales/th.json +++ b/apps/dotcom/client/public/tla/locales/th.json @@ -98,12 +98,6 @@ "47839e47a5": { "translation": "tldraw" }, - "7697920637": { - "translation": "กรุณาโหลดใหม่อีกครั้ง" - }, - "764671e008": { - "translation": "พูดคุยกับเราได้ที่ Discord" - }, "4908687e50": { "translation": "คุณแน่ใจหรือไม่ว่าต้องการลืมไฟล์นี้" }, @@ -200,6 +194,12 @@ "761e93ede9": { "translation": "จัดการคุกกี้" }, + "7697920637": { + "translation": "กรุณาโหลดใหม่อีกครั้ง" + }, + "764671e008": { + "translation": "พูดคุยกับเราได้ที่ Discord" + }, "777f9e90cf": { "translation": "คำขอไม่ถูกต้อง" }, @@ -257,6 +257,9 @@ "91e49bb0eb": { "translation": "คัดลอกไปยังไฟล์ของฉัน" }, + "95d2109dc8": { + "translation": "สร้างด้วย tldraw SDK" + }, "96165d6df5": { "translation": "เดือนนี้" }, diff --git a/apps/dotcom/client/public/tla/locales/tl.json b/apps/dotcom/client/public/tla/locales/tl.json index ebbed88dbda0..7d5a0bead2b7 100644 --- a/apps/dotcom/client/public/tla/locales/tl.json +++ b/apps/dotcom/client/public/tla/locales/tl.json @@ -98,12 +98,6 @@ "47839e47a5": { "translation": "tldraw" }, - "7697920637": { - "translation": "Paki-reload" - }, - "764671e008": { - "translation": "Makipag-chat sa amin sa Discord" - }, "4908687e50": { "translation": "Sigurado ka bang gusto mong kalimutan ang file na ito?" }, @@ -200,6 +194,12 @@ "761e93ede9": { "translation": "Pamahalaan ang cookies" }, + "7697920637": { + "translation": "Paki-reload" + }, + "764671e008": { + "translation": "Makipag-chat sa amin sa Discord" + }, "777f9e90cf": { "translation": "Di-wastong kahilingan." }, @@ -257,6 +257,9 @@ "91e49bb0eb": { "translation": "Kopyahin sa aking mga file" }, + "95d2109dc8": { + "translation": "Bumuo gamit ang tldraw SDK" + }, "96165d6df5": { "translation": "Ngayong buwan" }, diff --git a/apps/dotcom/client/public/tla/locales/tr.json b/apps/dotcom/client/public/tla/locales/tr.json index 8c0af6a4473e..72007b9c7c3e 100644 --- a/apps/dotcom/client/public/tla/locales/tr.json +++ b/apps/dotcom/client/public/tla/locales/tr.json @@ -98,12 +98,6 @@ "47839e47a5": { "translation": "tldraw" }, - "7697920637": { - "translation": "Lütfen yeniden yükleyin" - }, - "764671e008": { - "translation": "Discord'da bizimle sohbet edin" - }, "4908687e50": { "translation": "Bu dosyayı unutmak istediğinizden emin misiniz?" }, @@ -200,6 +194,12 @@ "761e93ede9": { "translation": "Çerezleri yönet" }, + "7697920637": { + "translation": "Lütfen yeniden yükleyin" + }, + "764671e008": { + "translation": "Discord'da bizimle sohbet edin" + }, "777f9e90cf": { "translation": "Geçersiz istek" }, @@ -257,6 +257,9 @@ "91e49bb0eb": { "translation": "Dosyalarıma kopyala" }, + "95d2109dc8": { + "translation": "tldraw SDK ile oluşturun" + }, "96165d6df5": { "translation": "Bu ay" }, diff --git a/apps/dotcom/client/public/tla/locales/uk.json b/apps/dotcom/client/public/tla/locales/uk.json index 6aff3bf764a6..2cbe293846b3 100644 --- a/apps/dotcom/client/public/tla/locales/uk.json +++ b/apps/dotcom/client/public/tla/locales/uk.json @@ -98,12 +98,6 @@ "47839e47a5": { "translation": "tldraw" }, - "7697920637": { - "translation": "Будь ласка, перезавантажте" - }, - "764671e008": { - "translation": "Спілкуйтеся з нами на Discord" - }, "4908687e50": { "translation": "Ви впевнені, що хочете забути цей файл?" }, @@ -200,6 +194,12 @@ "761e93ede9": { "translation": "Керувати файлами cookie" }, + "7697920637": { + "translation": "Будь ласка, перезавантажте" + }, + "764671e008": { + "translation": "Спілкуйтеся з нами на Discord" + }, "777f9e90cf": { "translation": "Недійсний запит." }, @@ -257,6 +257,9 @@ "91e49bb0eb": { "translation": "Копіювати в мої файли" }, + "95d2109dc8": { + "translation": "Збірка за допомогою tldraw SDK" + }, "96165d6df5": { "translation": "Цього місяця" }, diff --git a/apps/dotcom/client/public/tla/locales/ur.json b/apps/dotcom/client/public/tla/locales/ur.json index c2e6fe4adfe8..05ec72bcad8a 100644 --- a/apps/dotcom/client/public/tla/locales/ur.json +++ b/apps/dotcom/client/public/tla/locales/ur.json @@ -98,12 +98,6 @@ "47839e47a5": { "translation": "tldraw" }, - "7697920637": { - "translation": "براہ کرم دوبارہ لوڈ کریں۔" - }, - "764671e008": { - "translation": "Discord پر ہمارے ساتھ چیٹ کریں۔" - }, "4908687e50": { "translation": "کیا آپ واقعی اس فائل کو بھولنا چاہتے ہیں؟" }, @@ -200,6 +194,12 @@ "761e93ede9": { "translation": "کوکیز کا نظم کریں۔" }, + "7697920637": { + "translation": "براہ کرم دوبارہ لوڈ کریں۔" + }, + "764671e008": { + "translation": "Discord پر ہمارے ساتھ چیٹ کریں۔" + }, "777f9e90cf": { "translation": "غلط درخواست۔" }, @@ -257,6 +257,9 @@ "91e49bb0eb": { "translation": "میری فائلوں میں کاپی کریں۔" }, + "95d2109dc8": { + "translation": "tldraw SDK کے ساتھ بنائیں" + }, "96165d6df5": { "translation": "اس مہینے" }, diff --git a/apps/dotcom/client/public/tla/locales/vi.json b/apps/dotcom/client/public/tla/locales/vi.json index 20de7f575675..afb4effbbf9c 100644 --- a/apps/dotcom/client/public/tla/locales/vi.json +++ b/apps/dotcom/client/public/tla/locales/vi.json @@ -98,12 +98,6 @@ "47839e47a5": { "translation": "tldraw" }, - "7697920637": { - "translation": "Vui lòng tải lại" - }, - "764671e008": { - "translation": "Trò chuyện với chúng tôi trên Discord" - }, "4908687e50": { "translation": "Bạn có chắc chắn muốn quên tệp này không?" }, @@ -200,6 +194,12 @@ "761e93ede9": { "translation": "Quản lý cookie" }, + "7697920637": { + "translation": "Vui lòng tải lại" + }, + "764671e008": { + "translation": "Trò chuyện với chúng tôi trên Discord" + }, "777f9e90cf": { "translation": "Yêu cầu không hợp lệ." }, @@ -257,6 +257,9 @@ "91e49bb0eb": { "translation": "Sao chép vào tệp của tôi" }, + "95d2109dc8": { + "translation": "Xây dựng với SDK tldraw" + }, "96165d6df5": { "translation": "Tháng này" }, diff --git a/apps/dotcom/client/public/tla/locales/zh-cn.json b/apps/dotcom/client/public/tla/locales/zh-cn.json index 981be29a3bd8..9ba362222269 100644 --- a/apps/dotcom/client/public/tla/locales/zh-cn.json +++ b/apps/dotcom/client/public/tla/locales/zh-cn.json @@ -98,12 +98,6 @@ "47839e47a5": { "translation": "tldraw" }, - "7697920637": { - "translation": "请重新加载" - }, - "764671e008": { - "translation": "在 Discord 上与我们聊天" - }, "4908687e50": { "translation": "确定要忘记该文件吗?" }, @@ -200,6 +194,12 @@ "761e93ede9": { "translation": "管理 Cookie" }, + "7697920637": { + "translation": "请重新加载" + }, + "764671e008": { + "translation": "在 Discord 上与我们聊天" + }, "777f9e90cf": { "translation": "无效请求。" }, @@ -257,6 +257,9 @@ "91e49bb0eb": { "translation": "复制到我的文件" }, + "95d2109dc8": { + "translation": "使用 tldraw SDK 构建" + }, "96165d6df5": { "translation": "本月" }, diff --git a/apps/dotcom/client/public/tla/locales/zh-tw.json b/apps/dotcom/client/public/tla/locales/zh-tw.json index d49a5d04a43f..f852bc52928e 100644 --- a/apps/dotcom/client/public/tla/locales/zh-tw.json +++ b/apps/dotcom/client/public/tla/locales/zh-tw.json @@ -98,12 +98,6 @@ "47839e47a5": { "translation": "tldraw" }, - "7697920637": { - "translation": "請重新加載" - }, - "764671e008": { - "translation": "在 Discord 上與我們聊天" - }, "4908687e50": { "translation": "您確定要遺忘此檔案嗎?" }, @@ -200,6 +194,12 @@ "761e93ede9": { "translation": "管理cookies" }, + "7697920637": { + "translation": "請重新加載" + }, + "764671e008": { + "translation": "在 Discord 上與我們聊天" + }, "777f9e90cf": { "translation": "無效的請求。" }, @@ -257,6 +257,9 @@ "91e49bb0eb": { "translation": "複製到我的檔案" }, + "95d2109dc8": { + "translation": "使用 tldraw SDK 構建" + }, "96165d6df5": { "translation": "本月" }, From 6ba33c2b62494381420822ece01b9de2f24e9723 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mime=20=C4=8Cuvalo?= Date: Mon, 20 Oct 2025 12:26:15 +0100 Subject: [PATCH 003/114] analytics: fix regression on properties (#6967) @steveruizok oh i see - yeah this is a regression from last week's change https://github.com/tldraw/tldraw/pull/6924 this app will just hotfix by itself when i land this PR ### Change type - [ ] `bugfix` - [ ] `improvement` - [ ] `feature` - [ ] `api` - [x] `other` --- > [!NOTE] > Spread user properties in PostHog `identify` call instead of nesting them under `properties`. > > Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 76ea674504a88eec3772566503811908a3452190. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot). --- apps/analytics/src/analytics.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/analytics/src/analytics.tsx b/apps/analytics/src/analytics.tsx index e7b83aa51411..b7995bb2c899 100644 --- a/apps/analytics/src/analytics.tsx +++ b/apps/analytics/src/analytics.tsx @@ -184,7 +184,7 @@ export function identify(userId: string, properties?: { [key: string]: any }) { if (storedHasConsent !== 'opted-in') return posthog.identify(userId, { - properties, + ...properties, analytics_consent: true, }) ReactGA.set({ userId }) From 054b7b9f5f2d48590919fde7bad51dc1f896bf76 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mime=20=C4=8Cuvalo?= Date: Mon, 20 Oct 2025 13:57:47 +0100 Subject: [PATCH 004/114] workers: unify origin checks (#6951) We have disparate origin checks that are varying in domains, and we want to tighten up asset-upload as well. ### Change type - [ ] `bugfix` - [ ] `improvement` - [ ] `feature` - [ ] `api` - [x] `other` --- > [!NOTE] > Moves origin checks into shared utilities and applies unified CORS/origin middleware across workers, updating the request post-processing hook signature. > > - **Shared (worker-shared)**: > - **Origins utilities**: Add `isAllowedOrigin` and `blockUnknownOrigins` in `packages/worker-shared/src/origins.ts` and export from `index.ts`. > - **Request handling**: Change `handleApiRequest` `after` hook signature to `(response, request)` to support CORS helpers that need the request. > - **Workers**: > - **asset-upload-worker**: Switch CORS `origin` to `isAllowedOrigin`; add `blockUnknownOrigins` middleware; update to `corsify` via new hook signature. > - **sync-worker**: Replace local origin logic with shared `blockUnknownOrigins`/`isAllowedOrigin`; pass `request` to `corsify`; remove duplicated origin helpers. > - **image-resize-worker**: Reuse shared `isAllowedOrigin` for `isValidOrigin`; tidy imports. > > Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 60477d1e277131dcd393836c5106ca586b568e17. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot). --- apps/dotcom/asset-upload-worker/src/worker.ts | 5 +- apps/dotcom/image-resize-worker/src/worker.ts | 15 ++-- apps/dotcom/sync-worker/src/worker.ts | 44 +--------- packages/worker-shared/src/handleRequest.ts | 4 +- packages/worker-shared/src/index.ts | 1 + packages/worker-shared/src/origins.ts | 80 +++++++++++++++++++ 6 files changed, 99 insertions(+), 50 deletions(-) create mode 100644 packages/worker-shared/src/origins.ts diff --git a/apps/dotcom/asset-upload-worker/src/worker.ts b/apps/dotcom/asset-upload-worker/src/worker.ts index d76b8cafa226..004872173527 100644 --- a/apps/dotcom/asset-upload-worker/src/worker.ts +++ b/apps/dotcom/asset-upload-worker/src/worker.ts @@ -2,21 +2,24 @@ /// import { + blockUnknownOrigins, createRouter, handleApiRequest, handleUserAssetGet, handleUserAssetUpload, + isAllowedOrigin, notFound, } from '@tldraw/worker-shared' import { WorkerEntrypoint } from 'cloudflare:workers' import { cors } from 'itty-router' import { Environment } from './types' -const { preflight, corsify } = cors({ origin: '*' }) +const { preflight, corsify } = cors({ origin: isAllowedOrigin }) export default class Worker extends WorkerEntrypoint { readonly router = createRouter() .all('*', preflight) + .all('*', blockUnknownOrigins) .get('/uploads/:objectName', async (request) => { return handleUserAssetGet({ request, diff --git a/apps/dotcom/image-resize-worker/src/worker.ts b/apps/dotcom/image-resize-worker/src/worker.ts index 54f3197b608c..fbe6fe0c25be 100644 --- a/apps/dotcom/image-resize-worker/src/worker.ts +++ b/apps/dotcom/image-resize-worker/src/worker.ts @@ -1,6 +1,12 @@ import { APP_ASSET_UPLOAD_ENDPOINT } from '@tldraw/dotcom-shared' import { T } from '@tldraw/validate' -import { createRouter, handleApiRequest, notFound, parseRequestQuery } from '@tldraw/worker-shared' +import { + createRouter, + handleApiRequest, + isAllowedOrigin, + notFound, + parseRequestQuery, +} from '@tldraw/worker-shared' import { WorkerEntrypoint } from 'cloudflare:workers' declare const fetch: typeof import('@cloudflare/workers-types').fetch @@ -109,12 +115,7 @@ export default class Worker extends WorkerEntrypoint { return true } - return ( - origin.endsWith('.tldraw.com') || - origin.endsWith('.tldraw.xyz') || - origin.endsWith('.tldraw.dev') || - origin.endsWith('.tldraw.workers.dev') - ) + return isAllowedOrigin(origin) } } diff --git a/apps/dotcom/sync-worker/src/worker.ts b/apps/dotcom/sync-worker/src/worker.ts index 141b89fcc8ea..5156dff0aea5 100644 --- a/apps/dotcom/sync-worker/src/worker.ts +++ b/apps/dotcom/sync-worker/src/worker.ts @@ -10,10 +10,12 @@ import { schema, } from '@tldraw/dotcom-shared' import { + blockUnknownOrigins, createRouter, createSentry, handleApiRequest, handleUserAssetGet, + isAllowedOrigin, notFound, } from '@tldraw/worker-shared' import { WorkerEntrypoint } from 'cloudflare:workers' @@ -180,11 +182,11 @@ export default class Worker extends WorkerEntrypoint { request, env: this.env, ctx: this.ctx, - after: (response) => { + after: (response, request) => { const setCookies = response.headers.getAll('set-cookie') // unfortunately corsify mishandles the set-cookie header, so // we need to manually add it back in - const result = corsify(response) + const result = corsify(response, request) if ([...setCookies].length === 0) { return result } @@ -226,41 +228,3 @@ export default class Worker extends WorkerEntrypoint { } } } - -export function isAllowedOrigin(origin: string) { - if (!origin) return undefined - if (origin === 'http://localhost:3000') return origin - if (origin === 'http://localhost:5420') return origin - if (origin === 'https://meet.google.com') return origin - if (origin.endsWith('.tldraw.com')) return origin - if (origin.endsWith('.tldraw.dev')) return origin - if (origin.endsWith('.tldraw.club')) return origin - if (origin.endsWith('-tldraw.vercel.app')) return origin - return undefined -} - -async function blockUnknownOrigins(request: Request, env: Environment) { - // allow requests for the same origin (new rewrite routing for SPA) - if (request.headers.get('sec-fetch-site') === 'same-origin') { - return undefined - } - - if (new URL(request.url).pathname === '/auth/callback') { - // allow auth callback because we use the special cookie to verify - // the request - return undefined - } - - const origin = request.headers.get('origin') - - // if there's no origin, this cannot be a cross-origin request, so we allow it. - if (!origin) return undefined - - if (env.IS_LOCAL !== 'true' && !isAllowedOrigin(origin)) { - console.error('Attempting to connect from an invalid origin:', origin, env, request) - return new Response('Not allowed', { status: 403 }) - } - - // origin doesn't match, so we can continue - return undefined -} diff --git a/packages/worker-shared/src/handleRequest.ts b/packages/worker-shared/src/handleRequest.ts index 2c6034aa4f47..3e6ced238d1c 100644 --- a/packages/worker-shared/src/handleRequest.ts +++ b/packages/worker-shared/src/handleRequest.ts @@ -134,7 +134,7 @@ export async function handleApiRequest< request: Request env: Env ctx: Ctx - after(response: Response): Response | Promise + after(response: Response, request: Request): Response | Promise }) { let response try { @@ -152,7 +152,7 @@ export async function handleApiRequest< } try { - return await after(response) + return await after(response, request) } catch (error: any) { console.error(error.stack ?? error) // eslint-disable-next-line @typescript-eslint/no-deprecated diff --git a/packages/worker-shared/src/index.ts b/packages/worker-shared/src/index.ts index 6a08f5e3abd2..759c5bab577e 100644 --- a/packages/worker-shared/src/index.ts +++ b/packages/worker-shared/src/index.ts @@ -10,5 +10,6 @@ export { type ApiRoute, type ApiRouter, } from './handleRequest' +export { blockUnknownOrigins, isAllowedOrigin } from './origins' export { createSentry } from './sentry' export { handleUserAssetGet, handleUserAssetUpload } from './userAssetUploads' diff --git a/packages/worker-shared/src/origins.ts b/packages/worker-shared/src/origins.ts new file mode 100644 index 000000000000..443c336e158a --- /dev/null +++ b/packages/worker-shared/src/origins.ts @@ -0,0 +1,80 @@ +/** + * Validates if an origin is allowed to make cross-origin requests. + * Returns the origin if allowed, or undefined if blocked. + * + * @param origin - The origin header from the incoming request + * @returns The origin string if allowed, undefined otherwise + * + * @example + * ```ts + * const origin = request.headers.get('origin') + * const allowed = isAllowedOrigin(origin) + * if (allowed) { + * // Process the request + * } + * ``` + * + * @public + */ +export function isAllowedOrigin(origin: string) { + if (!origin) return undefined + if (origin === 'http://localhost:3000') return origin + if (origin === 'http://localhost:5420') return origin + if (origin === 'https://meet.google.com') return origin + if (origin.endsWith('.tldraw.com')) return origin + if (origin.endsWith('.tldraw.dev')) return origin + if (origin.endsWith('.tldraw.club')) return origin + if (origin.endsWith('.tldraw.xyz')) return origin + if (origin.endsWith('.tldraw.workers.dev')) return origin + if (origin.endsWith('-tldraw.vercel.app')) return origin + return undefined +} + +/** + * Middleware to block requests from unknown/unauthorized origins. + * Allows same-origin requests, auth callbacks, and requests from allowed origins. + * Returns undefined to continue processing, or a 403 Response to block the request. + * + * @param request - The incoming HTTP request + * @param env - Environment variables, must contain IS_LOCAL property + * @returns undefined to continue, or Response with 403 status to block + * + * @example + * ```ts + * router.all('*', async (request, env) => { + * const blocked = await blockUnknownOrigins(request, env) + * if (blocked) return blocked + * // Continue processing... + * }) + * ``` + * + * @public + */ +export async function blockUnknownOrigins( + request: Request, + env: { IS_LOCAL?: string } +): Promise { + // allow requests for the same origin (new rewrite routing for SPA) + if (request.headers.get('sec-fetch-site') === 'same-origin') { + return undefined + } + + if (new URL(request.url).pathname === '/auth/callback') { + // allow auth callback because we use the special cookie to verify + // the request + return undefined + } + + const origin = request.headers.get('origin') + + // if there's no origin, this cannot be a cross-origin request, so we allow it. + if (!origin) return undefined + + if (env.IS_LOCAL !== 'true' && !isAllowedOrigin(origin)) { + console.error('Attempting to connect from an invalid origin:', origin, env, request) + return new Response('Not allowed', { status: 403 }) + } + + // origin doesn't match, so we can continue + return undefined +} From fafd8261a790762e97770b281a11aff642fe294a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mime=20=C4=8Cuvalo?= Date: Mon, 20 Oct 2025 16:05:53 +0100 Subject: [PATCH 005/114] csp: allow analytics.google.com (#6969) ### Change type - [ ] `bugfix` - [ ] `improvement` - [ ] `feature` - [ ] `api` - [x] `other` --- > [!NOTE] > Adds `https://analytics.google.com` to CSP `connect-src` allowlist. > > Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 8e97fc56a6975196d0ff02a574e133238b4f837c. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot). --- apps/dotcom/client/src/utils/csp.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/dotcom/client/src/utils/csp.ts b/apps/dotcom/client/src/utils/csp.ts index fd58363830f2..36b02771a9f2 100644 --- a/apps/dotcom/client/src/utils/csp.ts +++ b/apps/dotcom/client/src/utils/csp.ts @@ -14,6 +14,7 @@ export const cspDirectives: { [key: string]: string[] } = { `https://*.ingest.sentry.io`, `https://*.ingest.us.sentry.io`, 'https://*.analytics.google.com', + 'https://analytics.google.com', 'https://www.google-analytics.com', 'https://*.googletagmanager.com', 'https://www.googletagmanager.com', From 9fd998ed72128c2eea9af9c92280305a27647c5b Mon Sep 17 00:00:00 2001 From: Steve Ruiz Date: Mon, 20 Oct 2025 19:07:50 -0400 Subject: [PATCH 006/114] worker-shared: move build dependencies to devDependencies (#6968) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary - Reorganized `packages/worker-shared/package.json` to correctly classify development and build-time dependencies - Moved `@cloudflare/workers-types`, `typescript`, and `lazyrepo` to `devDependencies` ## Rationale These dependencies are only needed during development and build time, not at runtime. This change: - Clarifies the actual runtime dependencies of the package - Follows best practices for dependency classification - May reduce bundle size in environments that distinguish between production and development dependencies ## Changes **Moved to devDependencies:** - `@cloudflare/workers-types` - TypeScript type definitions - `typescript` - Build-time compiler - `lazyrepo` - Build system tool **Remaining in dependencies:** - `@tldraw/utils` - `@tldraw/validate` - `cloudflare-workers-unfurl` - `itty-router` - `toucan-js` 🤖 Generated with [Claude Code](https://claude.com/claude-code) --- > [!NOTE] > Reclassifies build-only packages from dependencies to devDependencies in packages/worker-shared/package.json. > > - **package.json (worker-shared)**: > - **Dependency classification**: > - Moved `@cloudflare/workers-types`, `typescript`, and `lazyrepo` to `devDependencies`. > - Kept runtime deps: `@tldraw/utils`, `@tldraw/validate`, `cloudflare-workers-unfurl`, `itty-router`, `toucan-js`. > - **Dev tooling**: > - Ensured `vitest` remains in `devDependencies`. > > Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit cf8887d8297598c95480553061ae41777d7e0470. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot). --------- Co-authored-by: Claude --- packages/worker-shared/package.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/worker-shared/package.json b/packages/worker-shared/package.json index cb70ab0f1987..7e22164be862 100644 --- a/packages/worker-shared/package.json +++ b/packages/worker-shared/package.json @@ -9,16 +9,16 @@ "/* GOTCHA */": "files will include ./dist and index.d.ts by default, add any others you want to include in here", "files": [], "dependencies": { - "@cloudflare/workers-types": "^4.20250913.0", "@tldraw/utils": "workspace:*", "@tldraw/validate": "workspace:*", "cloudflare-workers-unfurl": "^0.0.8", "itty-router": "^5.0.18", - "lazyrepo": "0.0.0-alpha.27", - "toucan-js": "^3.4.0", - "typescript": "^5.8.3" + "toucan-js": "^3.4.0" }, "devDependencies": { + "@cloudflare/workers-types": "^4.20250913.0", + "lazyrepo": "0.0.0-alpha.27", + "typescript": "^5.8.3", "vitest": "^3.2.4" }, "scripts": { From d1764fb2c8e9ad2c76e16591336c222a273c08f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mitja=20Bezen=C5=A1ek?= Date: Tue, 21 Oct 2025 11:07:35 +0200 Subject: [PATCH 007/114] Improve hotfix pr checking (#6972) Add 15-minute timeout to dotcom hotfix script to prevent action timeouts. Now throws an error (sent to Discord) if PR checks don't complete in time, leaving 5 minutes buffer before the 20-minute GitHub Action timeout. ### Change type - [x] `improvement` --- > [!NOTE] > Adds a 15-minute timeout to the dotcom hotfix script while waiting for PR checks, throwing an error if not ready in time. > > - **Scripts**: > - `internal/scripts/trigger-dotcom-hotfix.ts` > - Add 15-minute maximum wait with elapsed-time tracking when polling PR `mergeable_state`. > - On timeout, log and throw an error with PR link. > - Retains initial 5-minute delay and 15s polling cadence. > > Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit c3dfe88188a8437d193bfcc09e54520efd716f60. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot). --- internal/scripts/trigger-dotcom-hotfix.ts | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/internal/scripts/trigger-dotcom-hotfix.ts b/internal/scripts/trigger-dotcom-hotfix.ts index 3577a77d08d2..c021cc6bd33a 100644 --- a/internal/scripts/trigger-dotcom-hotfix.ts +++ b/internal/scripts/trigger-dotcom-hotfix.ts @@ -72,10 +72,22 @@ This PR cherry-picks the changes from the original PR to the hotfixes branch for nicelog(`Created hotfix PR: ${hotfixBranchName} -> hotfixes`) nicelog(`Waiting for PR #${createdPr.data.number} to be ready for merge...`) + // Maximum wait time: 15 minutes total (action timeout is 20 mins, we need buffer for Discord notification) + const maxWaitTimeMs = 15 * 60 * 1000 + const startTime = Date.now() + // Wait for 5 minutes initially, then check every 15 seconds (our checks take at least 5 mins) await new Promise((resolve) => setTimeout(resolve, 5 * 60 * 1000)) while (true) { + // Check if we've exceeded the timeout + const elapsedTime = Date.now() - startTime + if (elapsedTime >= maxWaitTimeMs) { + nicelog(`Timeout: PR #${createdPr.data.number} checks did not complete in time`) + throw new Error( + `Hotfix PR #${createdPr.data.number} checks timed out after ${Math.round(elapsedTime / 60000)} minutes. Please check the PR manually: https://github.com/tldraw/tldraw/pull/${createdPr.data.number}` + ) + } const prStatus = await getPrDetailsByNumber(octokit, createdPr.data.number) nicelog(`PR #${createdPr.data.number} mergeable_state: ${prStatus.mergeable_state}`) From 5a683a5b204a76c6dfb55a10d0541d350fda2fa7 Mon Sep 17 00:00:00 2001 From: Steve Ruiz Date: Tue, 21 Oct 2025 07:57:03 -0400 Subject: [PATCH 008/114] Refactor analytics app to vanilla JS and modular architecture (#6964) This is a PR to improve our analytics banner. As part of the onboarding project, I had to get my head into the analytics work and figured I'd do a detail pass while I was here. As noted in greater detail by the bots below, the biggest change is **removing react** dependencies and just making the banner with DOM APIs. The reason for this is that we were shipping react / react-dom as part of the analytics script bundle, which seemed like a waste for two components. I also moved a lot of the **services** (like posthog, hubspot, etc) into their own files and into a common interface. If we want to add or remove services in the future, or if we want to adjust the functionality we're using for any of the services, then we can do that easily. We also add a new **analytics worker** that checks whether we need to show the cookie banner for a user, or whether we can opt them into analytics automatically. We're not using any ad trackers or selling people's medical data or any other sneaky stuff, so we're fine with providing an opt-out to users in California etc. The worker itself is very simple and uses cf-headers to identify the location of the IP request. Finally, I aligned the **design** of the components. The privacy preferences in particular needed some love, so love it got. We now use dark mode banners on light mode and light mode banners on dark mode for increased contrast. The next step of forced engagement would be immediate centered cookie wall, which tbh might be better than a sneaky thing crawling up the screen later. We'll iterate. None of the behavior should have changed materially, though a few things here and there will have been tightened up. I'd done a lot of work while still working in React (ie, using an external store for the consent) and confirmed things are doing what they should be. Reminder that this banner is currently only used on tldraw computer and tldraw.dev. We'll need to do similar work on tldraw.com (or perhaps migrate to using this analytics app instead). --- > [!NOTE] > Replaces React-based analytics with a modular vanilla JS implementation and introduces a Cloudflare worker to determine consent by geo, updating build, tests, and CI/deploy. > > - **Analytics app (vanilla, modular architecture)**: > - Replace React/Radix implementation with DOM-based components and a unified `Analytics` class (`apps/analytics/src/index.ts`, `components/`, `state/`, `types.ts`). > - Add modular services with a common interface: `PostHog`, `GA4`, `HubSpot`, `Reo` (`src/analytics-services/*`). > - Introduce cookie consent and theme state managers (`src/state/*`), consent banner and privacy dialog (`src/components/*`). > - Geo-based consent check utility calling worker (`src/utils/consent-check.ts`). > - Update styles to new tokens and compact UI (`src/styles.css`). > - Remove React build setup; adjust Vite/TS/Vitest configs and deps (`vite.config.ts`, `tsconfig.json`, `vitest.config.ts`, `package.json`). > - Add preview `index.html` and expose global API (`window.tlanalytics`). > - **Cloudflare analytics worker** (`apps/analytics-worker`): > - New worker to determine if explicit consent is required via `CF-IPCountry` with CORS and caching (`src/worker.ts`, `wrangler.toml`). > - Package, TS/Vitest configs, and docs (`CONTEXT.md`). > - **CI/Deploy**: > - New workflow to deploy analytics worker (`.github/workflows/deploy-analytics.yml`). > - Deployment script for worker and preview env handling (`internal/scripts/deploy-analytics.ts`, update `internal/scripts/lib/deploy.ts`). > - **Misc**: > - Add ignore rules for analytics public assets (`.prettierignore`). > > Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit e4db4dbee4a4f7db97ce130cef75000210e73c4a. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot). --------- Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com> --- .github/workflows/deploy-analytics.yml | 49 +++ .prettierignore | 1 + apps/analytics-worker/.gitignore | 2 + apps/analytics-worker/CONTEXT.md | 127 ++++++++ apps/analytics-worker/package.json | 28 ++ apps/analytics-worker/src/worker.ts | 115 +++++++ apps/analytics-worker/tsconfig.json | 7 + apps/analytics-worker/vitest.config.ts | 15 + apps/analytics-worker/wrangler.toml | 38 +++ apps/analytics/CONTEXT.md | 244 ++++++++------ apps/analytics/index.html | 40 +++ apps/analytics/package.json | 14 +- .../analytics-services/analytics-service.ts | 21 ++ apps/analytics/src/analytics-services/ga4.ts | 119 +++++++ .../src/analytics-services/hubspot.ts | 23 ++ .../src/analytics-services/posthog.ts | 56 ++++ apps/analytics/src/analytics-services/reo.ts | 39 +++ apps/analytics/src/analytics.tsx | 301 ------------------ .../src/components/CookieConsentBanner.ts | 85 +++++ .../src/components/PrivacySettingsDialog.ts | 132 ++++++++ apps/analytics/src/constants.ts | 20 ++ apps/analytics/src/index.ts | 232 +++++++++++--- .../src/state/cookie-consent-state.ts | 35 ++ apps/analytics/src/state/state.test.ts | 57 ++++ apps/analytics/src/state/state.ts | 59 ++++ apps/analytics/src/state/theme-state.ts | 47 +++ apps/analytics/src/styles.css | 270 ++++++++-------- apps/analytics/src/types.ts | 19 ++ apps/analytics/src/utils/consent-check.ts | 28 ++ .../src/{types.d.ts => vite-env.d.ts} | 2 + apps/analytics/tsconfig.json | 11 +- apps/analytics/vercel.json | 10 +- apps/analytics/vite.config.ts | 10 +- apps/analytics/vitest.config.ts | 6 + .../src/tla/hooks/useAnalyticsConsent.tsx | 1 + internal/scripts/deploy-analytics.ts | 107 +++++++ internal/scripts/lib/deploy.ts | 13 +- yarn.lock | 22 +- 38 files changed, 1807 insertions(+), 598 deletions(-) create mode 100644 .github/workflows/deploy-analytics.yml create mode 100644 apps/analytics-worker/.gitignore create mode 100644 apps/analytics-worker/CONTEXT.md create mode 100644 apps/analytics-worker/package.json create mode 100644 apps/analytics-worker/src/worker.ts create mode 100644 apps/analytics-worker/tsconfig.json create mode 100644 apps/analytics-worker/vitest.config.ts create mode 100644 apps/analytics-worker/wrangler.toml create mode 100644 apps/analytics/index.html create mode 100644 apps/analytics/src/analytics-services/analytics-service.ts create mode 100644 apps/analytics/src/analytics-services/ga4.ts create mode 100644 apps/analytics/src/analytics-services/hubspot.ts create mode 100644 apps/analytics/src/analytics-services/posthog.ts create mode 100644 apps/analytics/src/analytics-services/reo.ts delete mode 100644 apps/analytics/src/analytics.tsx create mode 100644 apps/analytics/src/components/CookieConsentBanner.ts create mode 100644 apps/analytics/src/components/PrivacySettingsDialog.ts create mode 100644 apps/analytics/src/constants.ts create mode 100644 apps/analytics/src/state/cookie-consent-state.ts create mode 100644 apps/analytics/src/state/state.test.ts create mode 100644 apps/analytics/src/state/state.ts create mode 100644 apps/analytics/src/state/theme-state.ts create mode 100644 apps/analytics/src/types.ts create mode 100644 apps/analytics/src/utils/consent-check.ts rename apps/analytics/src/{types.d.ts => vite-env.d.ts} (67%) create mode 100644 apps/analytics/vitest.config.ts create mode 100644 internal/scripts/deploy-analytics.ts diff --git a/.github/workflows/deploy-analytics.yml b/.github/workflows/deploy-analytics.yml new file mode 100644 index 000000000000..ac388ee750da --- /dev/null +++ b/.github/workflows/deploy-analytics.yml @@ -0,0 +1,49 @@ +name: Deploy analytics worker +permissions: + contents: read + deployments: write + +on: + pull_request: + push: + branches: + - main + - production + +env: + CI: 1 + PRINT_GITHUB_ANNOTATIONS: 1 + TLDRAW_ENV: ${{ (github.ref == 'refs/heads/production' && 'production') || (github.ref == 'refs/heads/main' && 'staging') || 'preview' }} + +defaults: + run: + shell: bash + +jobs: + deploy: + name: Deploy analytics worker to ${{ (github.ref == 'refs/heads/production' && 'production') || (github.ref == 'refs/heads/main' && 'staging') || 'preview' }} + timeout-minutes: 10 + runs-on: ubuntu-latest + environment: ${{ github.ref == 'refs/heads/production' && 'deploy-production' || 'deploy-staging' }} + concurrency: analytics-worker-${{ github.ref == 'refs/heads/production' && 'deploy-production' || github.ref }} + + steps: + - name: Check out code + uses: actions/checkout@v3 + with: + submodules: true + + - uses: ./.github/actions/setup + + - name: Build types + run: yarn build-types + + - name: Deploy + run: yarn tsx internal/scripts/deploy-analytics.ts + env: + RELEASE_COMMIT_HASH: ${{ github.sha }} + GH_TOKEN: ${{ github.token }} + + CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }} + CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} + DISCORD_DEPLOY_WEBHOOK_URL: ${{ secrets.DISCORD_DEPLOY_WEBHOOK_URL }} diff --git a/.prettierignore b/.prettierignore index 2931a5db746d..53e92c50dad6 100644 --- a/.prettierignore +++ b/.prettierignore @@ -30,6 +30,7 @@ apps/docs/content/reference/**/* **/.out/* **/.temp/* apps/dotcom/client/public/**/*.* +apps/analytics/public/**/* **/.clasp.json diff --git a/apps/analytics-worker/.gitignore b/apps/analytics-worker/.gitignore new file mode 100644 index 000000000000..b3e55cbeabd1 --- /dev/null +++ b/apps/analytics-worker/.gitignore @@ -0,0 +1,2 @@ +build +.wrangler \ No newline at end of file diff --git a/apps/analytics-worker/CONTEXT.md b/apps/analytics-worker/CONTEXT.md new file mode 100644 index 000000000000..cf7b55441b4b --- /dev/null +++ b/apps/analytics-worker/CONTEXT.md @@ -0,0 +1,127 @@ +# Analytics worker + +A Cloudflare Worker that determines whether users require explicit cookie consent based on their geographic location. + +## Purpose + +This worker supports the tldraw analytics system by providing geographic consent checking. It helps ensure compliance with privacy regulations like GDPR, UK PECR, FADP, and LGPD by identifying users in regions that require explicit opt-in for tracking. + +The worker is deployed to `tldraw-consent.workers.dev` and is called by the analytics app (`apps/analytics/`) during initialization. + +## How it works + +1. Receives GET request from analytics client +2. Reads user's country code from CloudFlare's `CF-IPCountry` header +3. Checks if country requires explicit consent +4. Returns JSON response indicating whether consent is required +5. Includes CORS headers for allowed tldraw origins + +## API + +**Endpoint**: `https://tldraw-consent.workers.dev` (or environment-specific variants) + +**Method**: `GET` + +**Response**: + +```json +{ + "requires_consent": boolean, + "country_code": string | null +} +``` + +**Caching**: Responses are cached for 1 hour (`Cache-Control: public, max-age=3600`) + +## Geographic consent rules + +Users in the following countries/regions require explicit consent: + +**EU Member States (GDPR)**: + +- Austria, Belgium, Bulgaria, Croatia, Cyprus, Czech Republic, Denmark, Estonia, Finland, France, Germany, Greece, Hungary, Ireland, Italy, Latvia, Lithuania, Luxembourg, Malta, Netherlands, Poland, Portugal, Romania, Slovakia, Slovenia, Spain, Sweden + +**EEA/EFTA (GDPR)**: + +- Iceland, Liechtenstein, Norway + +**Other regions**: + +- United Kingdom (UK PECR) +- Switzerland (FADP) +- Brazil (LGPD) + +**Default behavior**: If country code cannot be determined, the worker defaults to requiring consent (conservative approach for privacy compliance). + +## CORS configuration + +The worker allows cross-origin requests from: + +- `http://localhost:3000` - Local development +- `http://localhost:5420` - Local development +- `https://meet.google.com` - Google Meet integration +- `*.tldraw.com` - Production domains +- `*.tldraw.dev` - Development domains +- `*.tldraw.club` - Alternative domains +- `*.tldraw.xyz` - Alternative domains +- `*.tldraw.workers.dev` - Worker preview domains +- `*-tldraw.vercel.app` - Vercel preview deployments + +## Development + +### Running locally + +```bash +yarn dev # Start local development server +``` + +### Testing + +```bash +yarn test # Run tests +yarn test-ci # Run tests in CI mode +``` + +### Deployment + +The worker is deployed via GitHub Actions (`.github/workflows/deploy-analytics.yml`) which runs `internal/scripts/deploy-analytics.ts`. + +**Environments**: + +- **dev**: `tldraw-consent-dev` (for testing) +- **staging**: `tldraw-consent-staging` (deployed on push to `main`) +- **production**: `tldraw-consent` (deployed on push to `production`) + +## File structure + +- `src/worker.ts` - Main worker code +- `wrangler.toml` - Cloudflare Worker configuration +- `package.json` - Package configuration and scripts +- `tsconfig.json` - TypeScript configuration +- `vitest.config.ts` - Test configuration + +## Integration + +This worker is called by the analytics app during initialization: + +1. Analytics app loads in user's browser +2. If no existing consent preference is stored +3. App calls this worker to check if consent is required +4. Based on response, app either: + - Shows consent banner (requires_consent: true) + - Assumes implicit consent (requires_consent: false) + +See `apps/analytics/src/utils/consent-check.ts` for the client-side integration. + +## Dependencies + +- `@cloudflare/workers-types` - TypeScript types for Cloudflare Workers +- `wrangler` - Cloudflare Workers CLI tool + +## Notes + +- This is a standalone worker (not part of the analytics app bundle) +- Uses CloudFlare's edge network for low-latency responses worldwide +- Conservative default (require consent) ensures compliance even if geo-detection fails +- CORS preflight requests are handled with 24-hour cache +- Responses are cached to reduce load and improve performance diff --git a/apps/analytics-worker/package.json b/apps/analytics-worker/package.json new file mode 100644 index 000000000000..a00cc0927f0d --- /dev/null +++ b/apps/analytics-worker/package.json @@ -0,0 +1,28 @@ +{ + "name": "@tldraw/analytics-worker", + "description": "tldraw infinite canvas SDK (analytics worker).", + "version": "0.0.0", + "private": true, + "author": { + "name": "tldraw GB Ltd.", + "email": "hello@tldraw.com" + }, + "main": "./src/worker.ts", + "/* GOTCHA */": "files will include ./dist and index.d.ts by default, add any others you want to include in here", + "files": [], + "scripts": { + "dev": "yarn run -T tsx ../../internal/scripts/workers/dev.ts", + "test-ci": "yarn run -T vitest run --passWithNoTests", + "test": "yarn run -T vitest --passWithNoTests", + "test-coverage": "yarn run -T vitest run --coverage --passWithNoTests", + "check-bundle-size": "yarn run -T tsx ../../internal/scripts/check-worker-bundle.ts --entry src/worker.ts --size-limit-bytes 350000", + "lint": "yarn run -T tsx ../../internal/scripts/lint.ts" + }, + "devDependencies": { + "@cloudflare/workers-types": "^4.20250913.0", + "esbuild": "^0.25.6", + "lazyrepo": "0.0.0-alpha.27", + "typescript": "^5.8.3", + "wrangler": "^4.37.1" + } +} diff --git a/apps/analytics-worker/src/worker.ts b/apps/analytics-worker/src/worker.ts new file mode 100644 index 000000000000..f83f718a3a12 --- /dev/null +++ b/apps/analytics-worker/src/worker.ts @@ -0,0 +1,115 @@ +/// +/// + +/** + * Simple CloudFlare worker that returns whether the user requires cookie consent + * based on their geographic location (via CF-IPCountry header) + */ + +/** + * Validates if an origin is allowed to make cross-origin requests. + * Returns the origin if allowed, or undefined if blocked. + */ +function isAllowedOrigin(origin: string | null): string | undefined { + if (!origin) return undefined + if (origin === 'http://localhost:3000') return origin + if (origin === 'http://localhost:5420') return origin + if (origin === 'https://meet.google.com') return origin + if (origin.endsWith('.tldraw.com')) return origin + if (origin.endsWith('.tldraw.dev')) return origin + if (origin.endsWith('.tldraw.club')) return origin + if (origin.endsWith('.tldraw.xyz')) return origin + if (origin.endsWith('.tldraw.workers.dev')) return origin + if (origin.endsWith('-tldraw.vercel.app')) return origin + return undefined +} + +const EXPLICIT_CONSENT_COUNTRIES = [ + // EU Member States (GDPR) + 'AT', + 'BE', + 'BG', + 'HR', + 'CY', + 'CZ', + 'DK', + 'EE', + 'FI', + 'FR', + 'DE', + 'GR', + 'HU', + 'IE', + 'IT', + 'LV', + 'LT', + 'LU', + 'MT', + 'NL', + 'PL', + 'PT', + 'RO', + 'SK', + 'SI', + 'ES', + 'SE', + // EEA/EFTA (GDPR) + 'IS', + 'LI', + 'NO', + // Post-Brexit UK (UK PECR) + 'GB', + // Switzerland (FADP) + 'CH', + // Brazil (LGPD) + 'BR', +] + +export default { + async fetch(request: Request): Promise { + const origin = request.headers.get('origin') + const allowedOrigin = isAllowedOrigin(origin) + + // Handle CORS preflight + if (request.method === 'OPTIONS') { + const headers: Record = { + 'Access-Control-Allow-Methods': 'GET, OPTIONS', + 'Access-Control-Allow-Headers': 'Content-Type', + 'Access-Control-Max-Age': '86400', + } + if (allowedOrigin) { + headers['Access-Control-Allow-Origin'] = allowedOrigin + } + return new Response(null, { headers }) + } + + // Only allow GET requests + if (request.method !== 'GET') { + return new Response('Method not allowed', { status: 405 }) + } + + // Get country code from CloudFlare header + const countryCode = request.headers.get('CF-IPCountry') + + // Check if consent is required + // Default to requiring consent if country is unknown + const requiresConsent = !countryCode || EXPLICIT_CONSENT_COUNTRIES.includes(countryCode) + + // Return response with CORS headers + const headers: Record = { + 'Content-Type': 'application/json', + 'Cache-Control': 'public, max-age=3600', // Cache for 1 hour + } + if (allowedOrigin) { + headers['Access-Control-Allow-Origin'] = allowedOrigin + } + + return new Response( + JSON.stringify({ + requires_consent: requiresConsent, + country_code: countryCode, + }), + { headers } + ) + }, +} diff --git a/apps/analytics-worker/tsconfig.json b/apps/analytics-worker/tsconfig.json new file mode 100644 index 000000000000..71ee8ba34d3c --- /dev/null +++ b/apps/analytics-worker/tsconfig.json @@ -0,0 +1,7 @@ +{ + "extends": "../../internal/config/tsconfig.base.json", + "include": ["src", "scripts"], + "exclude": ["node_modules", "dist", ".tsbuild*"], + "compilerOptions": { "noEmit": true, "emitDeclarationOnly": false }, + "references": [] +} diff --git a/apps/analytics-worker/vitest.config.ts b/apps/analytics-worker/vitest.config.ts new file mode 100644 index 000000000000..28709f2f5e13 --- /dev/null +++ b/apps/analytics-worker/vitest.config.ts @@ -0,0 +1,15 @@ +/// +import { mergeConfig } from 'vitest/config' +import baseConfig from '../../internal/config/vitest/node-preset' + +// bemo-worker is a Node.js/Cloudflare Worker environment +export default mergeConfig(baseConfig, { + test: { + // Use node environment instead of jsdom for worker apps + environment: 'node', + // Module name mapping for path aliases + alias: { + '^~(.*)$': './src/$1', + }, + }, +}) diff --git a/apps/analytics-worker/wrangler.toml b/apps/analytics-worker/wrangler.toml new file mode 100644 index 000000000000..4712185da289 --- /dev/null +++ b/apps/analytics-worker/wrangler.toml @@ -0,0 +1,38 @@ +main = "src/worker.ts" +compatibility_date = "2024-06-20" +upload_source_maps = true + +#################### Environment names #################### + +# Dev environment +[env.dev] +name = "tldraw-consent-dev" + +# Staging environment +[env.staging] +name = "tldraw-consent-staging" + +# Staging environment +[env.preview] +name = "tldraw-consent-preview" + +# Production environment +[env.production] +name = "tldraw-consent" + + +#################### Version metadata #################### +[version_metadata] +binding = "CF_VERSION_METADATA" + +[env.dev.version_metadata] +binding = "CF_VERSION_METADATA" + +[env.preview.version_metadata] +binding = "CF_VERSION_METADATA" + +[env.staging.version_metadata] +binding = "CF_VERSION_METADATA" + +[env.production.version_metadata] +binding = "CF_VERSION_METADATA" diff --git a/apps/analytics/CONTEXT.md b/apps/analytics/CONTEXT.md index db0e90f0bb83..52ae6ad4a472 100644 --- a/apps/analytics/CONTEXT.md +++ b/apps/analytics/CONTEXT.md @@ -1,135 +1,201 @@ -# @tldraw/analytics +# Analytics app -The analytics app provides a privacy-compliant analytics tracking system for tldraw applications. It creates a standalone JavaScript library that can be embedded into websites to handle cookie consent, user tracking, and privacy settings. +A unified analytics library for tldraw.com that integrates multiple analytics services with cookie consent management. ## Purpose -This app builds a UMD (Universal Module Definition) library that provides: +This package provides a single, consolidated analytics interface that: -- Cookie consent banner with opt-in/opt-out functionality -- Privacy settings dialog -- Integration with multiple analytics providers (PostHog, Google Analytics 4, HubSpot, Reo) -- GDPR-compliant tracking with user consent management +- Integrates multiple analytics providers (PostHog, Google Analytics 4, HubSpot, Reo) +- Manages cookie consent with a UI banner and privacy settings dialog +- Exposes a unified API for tracking events, page views, and user identification +- Ensures analytics only run when users have opted in -## Architecture - -### Build system +The analytics script is built as a standalone JavaScript bundle that can be included in any tldraw web application. -- **Vite-based build**: Creates a single UMD library (`tl-analytics.js`) -- **React components**: Built with React 18 but bundled for standalone usage -- **CSS injection**: Styles are inlined and injected at runtime -- **External globals**: React and ReactDOM are expected as global dependencies +## Architecture ### Core components -**Analytics.tsx** - Main analytics component +**Analytics class** (`src/index.ts`) -- Cookie consent banner with theme detection -- Consent state management using cookies -- Integration with multiple analytics providers -- Conditional loading of tracking scripts based on consent +- Main entry point that orchestrates all analytics services +- Manages consent state and enables/disables services accordingly +- Exposes global `window.tlanalytics` API with methods: + - `identify(userId, properties)` - Identify a user across all services + - `reset()` - Reset user identity across all services (called on logout) + - `track(name, data)` - Track an event + - `page()` - Track a page view + - `gtag(...args)` - Access Google Analytics gtag function + - `openPrivacySettings()` - Show privacy settings dialog -**PrivacySettings.tsx** - Privacy settings dialog +**Analytics services** (`src/analytics-services/`) -- User-facing privacy controls -- Toggle analytics consent on/off -- Accessible dialog implementation using Radix UI +- Base `AnalyticsService` class defines common interface +- Each service (PostHog, GA4, HubSpot, Reo) extends the base class +- Lifecycle methods: + - `initialize()` - Set up service (runs regardless of consent) + - `enable()` - Enable tracking when consent is granted + - `disable()` - Disable tracking when consent is revoked + - `identify(userId, properties)` - Identify user + - `reset()` - Reset user identity (called on logout) + - `trackEvent(name, data)` - Track custom event + - `trackPageview()` - Track page view -**index.ts** - Entry point and global API +**State management** (`src/state/`) -- Exposes global `window.tlanalytics` object -- Provides functions: `page()`, `identify()`, `track()`, `gtag()`, `openPrivacySettings()` -- Handles DOM injection and component initialization +- `AnalyticsState` - Simple reactive state class with subscribe/notify pattern +- `CookieConsentState` - Manages consent state ('unknown' | 'opted-in' | 'opted-out') +- `ThemeState` - Manages theme for UI components ('light' | 'dark') -### Analytics providers +**UI components** (`src/components/`) -**PostHog** +- `CookieConsentBanner` - Shows cookie consent prompt when consent is unknown +- `PrivacySettingsDialog` - Allows users to review and change their consent preferences -- Primary analytics provider -- Hosted at `https://analytics.tldraw.com/i` -- Memory-only persistence when consent is denied -- Full localStorage+cookie persistence when opted in +### Consent flow -**Google Analytics 4** +1. On initialization, analytics reads consent from `allowTracking` cookie +2. If no existing consent decision: + - Check user location via CloudFlare worker (`shouldRequireConsent()`) + - Users in GDPR/LGPD regions default to 'unknown' (must opt in) + - Users in other regions default to 'opted-in' (implicit consent) +3. If consent is unknown, banner is shown +4. User actions (accept/opt-out) update the consent state +5. Consent state changes trigger enable/disable on all services +6. Only opted-in users have their events tracked -- Configured via `window.TL_GA4_MEASUREMENT_ID` -- Supports Google Ads integration via `window.TL_GOOGLE_ADS_ID` -- Consent-aware configuration -- Anonymized IP when consent is denied +**Geographic consent checking** (`src/utils/consent-check.ts`) -**HubSpot** +- Calls CloudFlare worker at `https://tldraw-consent.workers.dev` +- Worker uses `CF-IPCountry` header to determine user's country +- Requires explicit consent for EU, EEA, UK, Switzerland, Brazil +- Falls back to requiring consent if check fails or times out (2s timeout) +- Conservative default ensures compliance with privacy regulations -- Loaded conditionally with consent -- EU-hosted (js-eu1.hs-scripts.com) -- Account ID: 145620695 +### Integration with services -**Reo Analytics** +**PostHog** (`src/analytics-services/posthog.ts`) -- User session recording and analytics -- Client ID: 47839e47a5ed202 -- Conditional loading based on consent +- Product analytics and session recording +- Switches between memory and localStorage persistence based on consent -## Development +**Google Analytics 4** (`src/analytics-services/ga4.ts`) -### Scripts +- Web analytics via gtag.js +- Measurement ID provided via `window.TL_GA4_MEASUREMENT_ID` -- `yarn dev` - Start development server with Vite -- `yarn build` - Build UMD library to `public/tl-analytics.js` -- `yarn lint` - Run ESLint -- `yarn test` - Run Vitest (currently no tests) +**HubSpot** (`src/analytics-services/hubspot.ts`) -### Dependencies +- Marketing automation and CRM tracking +- Loaded via external script -- **js-cookie**: Cookie management -- **posthog-js**: PostHog analytics client -- **radix-ui**: Accessible UI primitives for dialogs and switches -- **react-ga4**: Google Analytics 4 integration -- **react/react-dom**: UI framework +**Reo** (`src/analytics-services/reo.ts`) -## Usage +- Analytics service +- Loaded via external script -The built library is designed to be included via script tag: +### CloudFlare consent worker -```html - - +```bash +yarn dev # Start development server +yarn build # Build for production +yarn test # Run tests ``` -## Privacy & compliance +### Testing -### Cookie management +Uses Vitest for unit testing. Test files are colocated with source files (e.g., `state.test.ts`). -- Uses `allowTracking` cookie to store consent -- Three states: 'unknown', 'opted-in', 'opted-out' -- Consent banner appears only for 'unknown' state +### Build output -### Data collection +Vite builds the app into two outputs: -- **Without consent**: Anonymous, memory-only tracking -- **With consent**: Full tracking with persistent storage -- **GDPR compliance**: User can opt-out at any time via privacy settings +1. JavaScript bundle in `public/` directory (via `vite build --outDir public`) +2. TypeScript compiled output in `dist/` (via `tsc`) -### Theme support +The built script can be included in HTML via: -- Automatic theme detection from document root styles -- Observes changes to `color-scheme` CSS property -- Applies appropriate styling for light/dark themes +```html + +``` -## Deployment +## Usage + +After the script loads, use the global API: + +```javascript +// Identify a user +window.tlanalytics.identify('user-123', { plan: 'pro' }) + +// Reset user identity (on logout) +window.tlanalytics.reset() + +// Track an event +window.tlanalytics.track('button_clicked', { button: 'upgrade' }) + +// Track a page view +window.tlanalytics.page() + +// Open privacy settings +window.tlanalytics.openPrivacySettings() +``` -The built library (`public/tl-analytics.js`) is deployed via Vercel configuration and can be hosted on CDN for inclusion in other tldraw applications and websites. +## Configuration + +Analytics services are configured via constants in `src/constants.ts` and environment variables: + +- `window.TL_GA4_MEASUREMENT_ID` - Google Analytics measurement ID +- `window.TL_GOOGLE_ADS_ID` - Google Ads ID (optional) +- PostHog, HubSpot, and Reo use hardcoded configuration in constants + +## Key files + +- `src/index.ts` - Main Analytics class and initialization +- `src/types.ts` - TypeScript types and global declarations +- `src/analytics-services/analytics-service.ts` - Base service class +- `src/analytics-services/*.ts` - Individual service implementations (PostHog, GA4, HubSpot, Reo) +- `src/state/state.ts` - Reactive state base class +- `src/state/cookie-consent-state.ts` - Consent management +- `src/state/theme-state.ts` - Theme management for UI components +- `src/utils/consent-check.ts` - Geographic consent checking utility +- `src/components/CookieConsentBanner.ts` - Consent banner UI +- `src/components/PrivacySettingsDialog.ts` - Privacy settings dialog UI +- `src/styles.css` - Component styles (inlined via Vite) + +## Dependencies + +- `posthog-js` - PostHog SDK +- `js-cookie` - Cookie management +- `vite` - Build tool +- `vitest` - Testing framework + +## Notes + +- This app does NOT use tldraw's `@tldraw/state` library - it has its own simple reactive state implementation +- The app is framework-agnostic - uses vanilla JavaScript/TypeScript +- All UI is created with vanilla DOM manipulation (no React) +- Styles are injected at runtime from the bundled CSS +- Services are enabled/disabled dynamically based on consent without page reload +- Error handling is implemented during initialization to prevent analytics failures from breaking the page +- User identity persists in memory during session for re-identification if consent changes +- Geographic consent checking uses a conservative approach - defaults to requiring consent on failure diff --git a/apps/analytics/index.html b/apps/analytics/index.html new file mode 100644 index 000000000000..4a6c37358bef --- /dev/null +++ b/apps/analytics/index.html @@ -0,0 +1,40 @@ + + + + + + Analytics Banner Preview + + + + + + + + + diff --git a/apps/analytics/package.json b/apps/analytics/package.json index c937c38317f4..c630596d6972 100644 --- a/apps/analytics/package.json +++ b/apps/analytics/package.json @@ -14,18 +14,14 @@ }, "dependencies": { "js-cookie": "^3.0.5", - "posthog-js": "^1.248.1", - "radix-ui": "^1.4.2", - "react": "^18.3.1", - "react-dom": "^18.3.1", - "react-ga4": "^2.1.0" + "posthog-js": "^1.248.1" }, "devDependencies": { + "@cloudflare/workers-types": "^4.20250913.0", "@types/js-cookie": "^3.0.6", - "@types/react": "^18.3.18", - "@types/react-dom": "^18.3.5", - "@vitejs/plugin-react": "^4.6.0", "typescript": "^5.8.3", - "vite": "^7.0.1" + "vite": "^7.0.1", + "vitest": "^3.2.4", + "wrangler": "^4.37.1" } } diff --git a/apps/analytics/src/analytics-services/analytics-service.ts b/apps/analytics/src/analytics-services/analytics-service.ts new file mode 100644 index 000000000000..c4af837f8ebc --- /dev/null +++ b/apps/analytics/src/analytics-services/analytics-service.ts @@ -0,0 +1,21 @@ +/* eslint-disable @typescript-eslint/no-unused-vars */ + +export class AnalyticsService { + protected isEnabled = false + // Initialize the service (regardless of cookie consent) + initialize(): void {} + // Clean up the service. + dispose(): void {} + // Enable the service when cookie consent is granted. + enable(): void {} + // Disable the service when cookie consent is revoked. + disable(): void {} + // Identify the user. + identify(userId: string, properties?: { [key: string]: any }): void {} + // Reset the user identity (call on logout). + reset(): void {} + // Track an event. + trackEvent(name: string, data?: { [key: string]: any }): void {} + // Track a pageview. + trackPageview(): void {} +} diff --git a/apps/analytics/src/analytics-services/ga4.ts b/apps/analytics/src/analytics-services/ga4.ts new file mode 100644 index 000000000000..d643036c564e --- /dev/null +++ b/apps/analytics/src/analytics-services/ga4.ts @@ -0,0 +1,119 @@ +import { AnalyticsService } from './analytics-service' + +// Extend Window with gtag and dataLayer (other Window properties declared in types.ts) +declare global { + interface Window { + gtag?(...args: any[]): void + dataLayer?: any[] + } +} + +// Helper to safely call gtag +function gtag(...args: any[]) { + if (typeof window !== 'undefined' && window.gtag) { + window.gtag(...args) + } +} + +export function ga4Gtag(...args: any[]) { + gtag(...args) +} + +class GA4AnalyticsService extends AnalyticsService { + private measurementId: string | undefined + private googleAdsId: string | undefined + + override initialize() { + if (typeof window === 'undefined') return + + this.measurementId = window.TL_GA4_MEASUREMENT_ID ?? undefined + this.googleAdsId = window.TL_GOOGLE_ADS_ID ?? undefined + + if (this.measurementId) { + gtag('consent', 'default', { + ad_storage: 'denied', + ad_user_data: 'denied', + ad_personalization: 'denied', + analytics_storage: 'denied', + // Wait for our cookie to load. + wait_for_update: 500, + }) + + // Initialize dataLayer + window.dataLayer = window.dataLayer || [] + window.gtag = function () { + // eslint-disable-next-line prefer-rest-params + window.dataLayer!.push(arguments) + } + gtag('js', new Date()) + + // Load the GA4 script + const script = document.createElement('script') + script.async = true + script.id = `gtag-${this.measurementId}` + script.src = `https://www.googletagmanager.com/gtag/js?id=${this.measurementId}` + document.head.appendChild(script) + + gtag('config', this.measurementId, { + anonymize_ip: true, + }) + } + + if (this.googleAdsId) { + gtag('config', this.googleAdsId) + } + } + + override dispose() { + const script = document.getElementById(`gtag-${this.measurementId}`) + if (script) script.remove() + } + + override enable() { + if (this.isEnabled) return + gtag('set', { anonymize_ip: false }) + gtag('consent', 'update', { + ad_user_data: 'granted', + ad_personalization: 'granted', + ad_storage: 'granted', + analytics_storage: 'granted', + }) + this.isEnabled = true + } + + override disable() { + if (!this.isEnabled) return + // Clear user properties + if (this.measurementId) { + gtag('config', this.measurementId, { + client_id: undefined, + user_id: undefined, + }) + } + gtag('set', { anonymize_ip: true }) + gtag('consent', 'update', { + ad_user_data: 'denied', + ad_personalization: 'denied', + ad_storage: 'denied', + analytics_storage: 'denied', + }) + this.isEnabled = false + } + + override identify(userId: string, properties?: { [key: string]: any }) { + gtag('set', { user_id: userId }) + if (properties) { + gtag('set', properties) + } + } + + override trackEvent(name: string, data?: { [key: string]: any }) { + gtag('event', name, data) + } + + override trackPageview() { + gtag('event', 'page_view') + } +} + +export const ga4Service = new GA4AnalyticsService() diff --git a/apps/analytics/src/analytics-services/hubspot.ts b/apps/analytics/src/analytics-services/hubspot.ts new file mode 100644 index 000000000000..e72acdb7a006 --- /dev/null +++ b/apps/analytics/src/analytics-services/hubspot.ts @@ -0,0 +1,23 @@ +import { HUBSPOT_SCRIPT_ID, HUBSPOT_SCRIPT_URL } from '../constants' +import { AnalyticsService } from './analytics-service' + +class HubspotAnalyticsService extends AnalyticsService { + // Does not need to be initialized + override enable() { + if (this.isEnabled) return + const hubspotScriptTag = document.createElement('script') + hubspotScriptTag.id = HUBSPOT_SCRIPT_ID + hubspotScriptTag.src = HUBSPOT_SCRIPT_URL + hubspotScriptTag.defer = true + document.head.appendChild(hubspotScriptTag) + this.isEnabled = true + } + + override dispose() { + const hubspotScriptTag = document.getElementById(HUBSPOT_SCRIPT_ID) + if (hubspotScriptTag) hubspotScriptTag.remove() + this.isEnabled = false + } +} + +export const hubspotService = new HubspotAnalyticsService() diff --git a/apps/analytics/src/analytics-services/posthog.ts b/apps/analytics/src/analytics-services/posthog.ts new file mode 100644 index 000000000000..48cd6e67ebb2 --- /dev/null +++ b/apps/analytics/src/analytics-services/posthog.ts @@ -0,0 +1,56 @@ +import _posthog from 'posthog-js' +import { POSTHOG_API_HOST, POSTHOG_TOKEN, POSTHOG_UI_HOST } from '../constants' +import { AnalyticsService } from './analytics-service' + +class PosthogAnalyticsService extends AnalyticsService { + override initialize() { + // Make posthog available globally + if (typeof window !== 'undefined') { + window.posthog = _posthog + } + + _posthog.init(POSTHOG_TOKEN, { + api_host: POSTHOG_API_HOST, + ui_host: POSTHOG_UI_HOST, + persistence: 'memory', + capture_pageview: 'history_change', + }) + } + + override enable() { + if (this.isEnabled) return + _posthog.set_config({ persistence: 'localStorage+cookie' }) + _posthog.opt_in_capturing() + this.isEnabled = true + } + + override disable() { + if (!this.isEnabled) return + _posthog.setPersonProperties({ analytics_consent: false }) + _posthog.reset() + _posthog.set_config({ persistence: 'memory' }) + _posthog.opt_out_capturing() + this.isEnabled = false + } + + override identify(userId: string, properties?: { [key: string]: any }) { + _posthog.identify(userId, { + ...properties, + analytics_consent: true, + }) + } + + override reset() { + _posthog.reset() + } + + override trackEvent(name: string, data?: { [key: string]: any }) { + _posthog.capture(name, data) + } + + override trackPageview() { + _posthog.capture('$pageview') + } +} + +export const posthogService = new PosthogAnalyticsService() diff --git a/apps/analytics/src/analytics-services/reo.ts b/apps/analytics/src/analytics-services/reo.ts new file mode 100644 index 000000000000..45957fb55377 --- /dev/null +++ b/apps/analytics/src/analytics-services/reo.ts @@ -0,0 +1,39 @@ +import { REO_CLIENT_ID, REO_SCRIPT_ID, REO_SCRIPT_URL } from '../constants' +import { AnalyticsService } from './analytics-service' + +class ReoAnalyticsService extends AnalyticsService { + override enable() { + if (this.isEnabled) return + const reoScriptTag = document.createElement('script') + reoScriptTag.id = REO_SCRIPT_ID + reoScriptTag.src = REO_SCRIPT_URL + reoScriptTag.defer = true + reoScriptTag.onload = () => window.Reo?.init?.({ clientID: REO_CLIENT_ID }) + document.head.appendChild(reoScriptTag) + this.isEnabled = true + } + + override disable() { + if (!this.isEnabled) return + window.Reo?.reset?.() + this.isEnabled = false + } + + override dispose() { + const reoScriptTag = document.getElementById(REO_SCRIPT_ID) + if (reoScriptTag) reoScriptTag.remove() + this.isEnabled = false + } + + override identify(userId: string, properties?: { [key: string]: any }) { + window.Reo?.identify?.({ + ...properties, + userId, + firstname: properties?.name || '', + username: properties?.email || '', + type: 'email', + }) + } +} + +export const reoService = new ReoAnalyticsService() diff --git a/apps/analytics/src/analytics.tsx b/apps/analytics/src/analytics.tsx deleted file mode 100644 index b7995bb2c899..000000000000 --- a/apps/analytics/src/analytics.tsx +++ /dev/null @@ -1,301 +0,0 @@ -import Cookies from 'js-cookie' -import posthog from 'posthog-js' -import { Dialog as _Dialog, Switch as _Switch } from 'radix-ui' -import { useEffect, useState } from 'react' -import ReactGA from 'react-ga4' -import './styles.css' - -type CookieConsent = 'unknown' | 'opted-in' | 'opted-out' -let isConfigured = false -let storedUserId: string = '' -let storedProperties: { [key: string]: any } | undefined = undefined -let storedHasConsent: CookieConsent = 'unknown' -window.posthog = posthog - -// Add theme detection -function getTheme() { - const html = document.documentElement - const colorScheme = html.getAttribute('style')?.includes('color-scheme: dark') ? 'dark' : 'light' - return colorScheme -} - -export default function Analytics() { - const [isLoaded, setIsLoaded] = useState(false) - const [hasConsent, setHasConsent] = useState('unknown') - const [theme, setTheme] = useState<'light' | 'dark'>(getTheme()) - - // Add theme observer - useEffect(() => { - const observer = new MutationObserver((mutations) => { - mutations.forEach((mutation) => { - if (mutation.attributeName === 'style') { - setTheme(getTheme()) - } - }) - }) - - observer.observe(document.documentElement, { - attributes: true, - attributeFilter: ['style'], - }) - - return () => observer.disconnect() - }, []) - - const onConsentChanged = (hasConsent: boolean) => { - Cookies.set('allowTracking', hasConsent ? 'true' : 'false') - setHasConsent(hasConsent ? 'opted-in' : 'opted-out') - track('consent_changed', { consent: hasConsent }) - } - - useEffect(() => { - const consent = Cookies.get('allowTracking') - setHasConsent(consent === 'true' ? 'opted-in' : consent === 'false' ? 'opted-out' : 'unknown') - setIsLoaded(true) - }, []) - - useEffect(() => { - if (!isConfigured) { - posthog.init('phc_i8oKgMzgV38sn3GfjswW9mevQ3gFlo7bJXekZFeDN6', { - api_host: 'https://analytics.tldraw.com/i', - ui_host: 'https://eu.i.posthog.com', - persistence: 'memory', - capture_pageview: 'history_change', - }) - - if (window.TL_GA4_MEASUREMENT_ID) { - ReactGA.gtag('consent', 'default', { - ad_storage: 'denied', - ad_user_data: 'denied', - ad_personalization: 'denied', - analytics_storage: 'denied', - // Wait for our cookie to load. - wait_for_update: 500, - }) - ReactGA.initialize(window.TL_GA4_MEASUREMENT_ID, { - gaOptions: { - anonymize_ip: true, - }, - }) - - // Add Google Ads configuration if present - if (window.TL_GOOGLE_ADS_ID) { - ReactGA.gtag('config', window.TL_GOOGLE_ADS_ID) - } - } - - isConfigured = true - } - - storedHasConsent = hasConsent - if (hasConsent === 'opted-in') { - posthog.set_config({ persistence: 'localStorage+cookie' }) - posthog.opt_in_capturing() - ReactGA.set({ anonymize_ip: false }) - - ReactGA.gtag('consent', 'update', { - ad_user_data: 'granted', - ad_personalization: 'granted', - ad_storage: 'granted', - analytics_storage: 'granted', - }) - - if (storedUserId && storedProperties) { - identify(storedUserId, storedProperties) - } - - // Add Hubspot analytics - if (!document.getElementById('hs-script-loader')) { - const hubspotScriptTag = document.createElement('script') - hubspotScriptTag.id = 'hs-script-loader' - hubspotScriptTag.src = `https://js-eu1.hs-scripts.com/145620695.js` - hubspotScriptTag.defer = true - document.head.appendChild(hubspotScriptTag) - } - - // Add Reo analytics - if (!document.getElementById('reo-script-loader')) { - const reoId = '47839e47a5ed202' - const reoScriptTag = document.createElement('script') - reoScriptTag.id = 'reo-script-loader' - reoScriptTag.src = `https://static.reo.dev/${reoId}/reo.js` - reoScriptTag.defer = true - reoScriptTag.onload = () => window.Reo.init({ clientID: reoId }) - document.head.appendChild(reoScriptTag) - } - } else { - posthog.setPersonProperties({ analytics_consent: false }) - posthog.reset() - posthog.set_config({ persistence: 'memory' }) - posthog.opt_out_capturing() - ReactGA.reset() - ReactGA.set({ anonymize_ip: true }) - ReactGA.gtag('consent', 'update', { - ad_user_data: 'denied', - ad_personalization: 'denied', - ad_storage: 'denied', - analytics_storage: 'denied', - }) - window.Reo?.reset?.() - } - }, [hasConsent]) - - if (!isLoaded || hasConsent !== 'unknown') return null - - return ( -

-

- We use cookies on this website. -
Learn more in our{' '} -
- Cookie Policy - - . -

-
- - -
-
- ) -} - -export function page() { - posthog.capture('$pageview') - ReactGA.send('pageview') -} - -export function identify(userId: string, properties?: { [key: string]: any }) { - storedUserId = userId - storedProperties = properties - - if (storedHasConsent !== 'opted-in') return - - posthog.identify(userId, { - ...properties, - analytics_consent: true, - }) - ReactGA.set({ userId }) - ReactGA.set(properties) - window.Reo?.identify?.({ - ...properties, - userId, - firstname: properties?.name || '', - username: properties?.email || '', - type: 'email', - }) -} - -export function track(name: string, data?: { [key: string]: any }) { - posthog.capture(name, data) - ReactGA.event(name, data) -} - -export function gtag(...args: any[]) { - if (storedHasConsent !== 'opted-in') return - // @ts-ignore - ReactGA.gtag accepts variable arguments - ReactGA.gtag(...args) -} - -export function PrivacySettings() { - const hasConsent: CookieConsent = - Cookies.get('allowTracking') === 'true' ? 'opted-in' : 'opted-out' - const [isChecked, setIsChecked] = useState(hasConsent === 'opted-in') - const [theme, setTheme] = useState<'light' | 'dark'>(getTheme()) - - // Add theme observer - useEffect(() => { - const observer = new MutationObserver((mutations) => { - mutations.forEach((mutation) => { - if (mutation.attributeName === 'style') { - setTheme(getTheme()) - } - }) - }) - - observer.observe(document.documentElement, { - attributes: true, - attributeFilter: ['style'], - }) - - return () => observer.disconnect() - }, []) - - const onChange = (checked: boolean) => { - Cookies.set('allowTracking', checked ? 'true' : 'false') - setIsChecked(checked) - } - - const onHide = () => { - // Need this for the settings to take effect on the consent banner. - window.location.reload() - } - - return ( - <_Dialog.Root open> - <_Dialog.Portal> - <_Dialog.Overlay className="tl-analytics-dialog" data-theme={theme} /> -
- <_Dialog.Content - onInteractOutside={onHide} - onPointerDownOutside={onHide} - onEscapeKeyDown={onHide} - className="tl-analytics-dialog-content" - > - <_Dialog.Title className="tl-analytics-dialog-title">Privacy settings - <_Dialog.Description className="tl-analytics-dialog-body"> - This website uses cookies to collect analytics from visitors. Read our{' '} - - cookie policy - {' '} - to learn more. - - <_Dialog.Close className="tl-analytics-dialog-close" asChild> - - - -
- -
- <_Switch.Root - className="tl-analytics-checkbox" - id="privacy-analytics" - checked={isChecked} - onCheckedChange={onChange} - > - <_Switch.Thumb /> - -
-
- -
- - - ) -} diff --git a/apps/analytics/src/components/CookieConsentBanner.ts b/apps/analytics/src/components/CookieConsentBanner.ts new file mode 100644 index 000000000000..7440434999df --- /dev/null +++ b/apps/analytics/src/components/CookieConsentBanner.ts @@ -0,0 +1,85 @@ +import { DOT_DEV_COOKIE_POLICY_URL } from '../constants' +import { CookieConsentState } from '../state/cookie-consent-state' +import { ThemeState } from '../state/theme-state' + +export function createCookieConsentBanner( + cookieConsentState: CookieConsentState, + themeState: ThemeState +): HTMLElement | null { + const consent = cookieConsentState.getValue() + const theme = themeState.getValue() + + // Don't show banner if consent is already given + if (consent !== 'unknown') return null + + // Create banner element + const banner = document.createElement('div') + banner.className = 'tl-analytics-banner' + banner.setAttribute('data-theme', theme) + + // Create content + banner.innerHTML = ` +

+ We use cookies on this website. +
+ Learn more in our Cookie Policy. +

+
+ + +
+ ` + + // Add event listeners + banner.addEventListener('click', (e: Event) => { + const target = e.target as HTMLElement + const action = target.closest('[data-action]')?.getAttribute('data-action') + if (action === 'opt-out') { + cookieConsentState.setValue('opted-out') + } else if (action === 'accept') { + cookieConsentState.setValue('opted-in') + } + }) + + const consentCleanup = cookieConsentState.subscribe((consent) => { + if (consent !== 'unknown') { + banner.remove() + } + }) + + // Watch for theme changes + const themeCleanup = themeState.subscribe((theme) => { + banner.setAttribute('data-theme', theme) + }) + + // Clean up observer when banner is removed + const originalRemove = banner.remove.bind(banner) + banner.remove = function () { + originalRemove() + themeCleanup() + consentCleanup() + } + + return banner +} + +// Auto-mount function for easy integration +export function mountCookieConsentBanner( + cookieConsentState: CookieConsentState, + themeState: ThemeState, + container: HTMLElement +): HTMLElement | null { + const existingBanner = document.querySelector('.tl-analytics-banner') + if (existingBanner) existingBanner.remove() + + const banner = createCookieConsentBanner(cookieConsentState, themeState) + if (banner) container.appendChild(banner) + + return banner +} diff --git a/apps/analytics/src/components/PrivacySettingsDialog.ts b/apps/analytics/src/components/PrivacySettingsDialog.ts new file mode 100644 index 000000000000..4993b48ad951 --- /dev/null +++ b/apps/analytics/src/components/PrivacySettingsDialog.ts @@ -0,0 +1,132 @@ +import { DOT_DEV_COOKIE_POLICY_URL } from '../constants' +import { CookieConsentState } from '../state/cookie-consent-state' +import { ThemeState } from '../state/theme-state' + +export function createPrivacySettingsDialog( + cookieConsentState: CookieConsentState, + themeState: ThemeState +): HTMLElement { + const consent = cookieConsentState.getValue() + const theme = themeState.getValue() + + // Create dialog container + const dialogContainer = document.createElement('div') + dialogContainer.className = 'tl-analytics-dialog' + + // Create overlay and dialog + const overlay = document.createElement('div') + overlay.className = 'tl-analytics-dialog__overlay' + overlay.setAttribute('data-theme', theme) + + const dialogWrapper = document.createElement('div') + dialogWrapper.className = 'tl-analytics-dialog__wrapper' + dialogWrapper.setAttribute('data-theme', theme) + + const dialog = document.createElement('div') + dialog.className = 'tl-analytics-dialog__content' + + // Create dialog content + dialog.innerHTML = ` +
+

Privacy settings

+ +
+

+ This website uses cookies to collect analytics from visitors. Read our + cookie policy + to learn more. +

+
+ +
+ +
+
+ ` + + // Add event listeners + const closeButton = dialog.querySelector('.tl-analytics-dialog__close') as HTMLButtonElement + const switchButton = dialog.querySelector('.tl-analytics-checkbox') as HTMLButtonElement + + function closeDialog() { + dialogContainer.remove() + } + + closeButton.addEventListener('click', closeDialog) + + // Close on overlay click + overlay.addEventListener('click', closeDialog) + + // Prevent closing when clicking inside dialog + dialog.addEventListener('click', (e: Event) => e.stopPropagation()) + + // Handle ESC key + function handleKeyDown(e: KeyboardEvent) { + if (e.key === 'Escape') { + closeDialog() + } + } + document.addEventListener('keydown', handleKeyDown) + + // Handle switch toggle + switchButton.addEventListener('click', () => { + const currentConsent = cookieConsentState.getValue() + cookieConsentState.setValue(currentConsent === 'opted-in' ? 'opted-out' : 'opted-in') + }) + + // Watch for consent changes + const cleanupConsent = cookieConsentState.subscribe((consent) => { + if (consent === 'opted-in') { + switchButton.classList.add('checked') + switchButton.setAttribute('aria-checked', 'true') + } else { + switchButton.classList.remove('checked') + switchButton.setAttribute('aria-checked', 'false') + } + }) + + // Watch for theme changes + const cleanupTheme = themeState.subscribe((theme) => { + overlay.setAttribute('data-theme', theme) + dialogWrapper.setAttribute('data-theme', theme) + }) + + // Clean up observer when dialog is removed + const originalRemove = dialogContainer.remove.bind(dialogContainer) + dialogContainer.remove = function () { + document.removeEventListener('keydown', handleKeyDown) + originalRemove() + cleanupTheme() + cleanupConsent() + } + + // Assemble dialog + dialogWrapper.appendChild(dialog) + dialogContainer.appendChild(overlay) + dialogContainer.appendChild(dialogWrapper) + + return dialogContainer +} + +// Auto-mount function for easy integration +export function mountPrivacySettingsDialog( + cookieConsentState: CookieConsentState, + themeState: ThemeState, + container: HTMLElement +): HTMLElement { + const existingDialog = document.querySelector('.tl-analytics-dialog') + if (existingDialog) existingDialog.remove() + + const dialog = createPrivacySettingsDialog(cookieConsentState, themeState) + if (dialog) container.appendChild(dialog) + + return dialog +} diff --git a/apps/analytics/src/constants.ts b/apps/analytics/src/constants.ts new file mode 100644 index 000000000000..54d3684f0828 --- /dev/null +++ b/apps/analytics/src/constants.ts @@ -0,0 +1,20 @@ +// All analytics use the same cookie policy URL. +export const DOT_DEV_COOKIE_POLICY_URL = 'https://tldraw.notion.site/devcookiepolicy' + +// All analytics use the same cookie to store consent. +export const CONSENT_COOKIE_NAME = 'allowTracking' +export const CONSENT_CHANGED_EVENT = 'tl-analytics-consent-changed' + +// All analytics are fed into the same HubSpot project. +export const HUBSPOT_SCRIPT_ID = 'hs-script-loader' +export const HUBSPOT_SCRIPT_URL = 'https://js-eu1.hs-scripts.com/145620695.js' + +// All analytics are fed into the same Reo project. +export const REO_SCRIPT_ID = 'reo-script-loader' +export const REO_CLIENT_ID = '47839e47a5ed202' +export const REO_SCRIPT_URL = `https://static.reo.dev/${REO_CLIENT_ID}/reo.js` + +// All analytics are fed into the same PostHog project. +export const POSTHOG_TOKEN = 'phc_i8oKgMzgV38sn3GfjswW9mevQ3gFlo7bJXekZFeDN6' +export const POSTHOG_API_HOST = 'https://analytics.tldraw.com/i' +export const POSTHOG_UI_HOST = 'https://eu.i.posthog.com' diff --git a/apps/analytics/src/index.ts b/apps/analytics/src/index.ts index d35083c7bd87..674d7af95619 100644 --- a/apps/analytics/src/index.ts +++ b/apps/analytics/src/index.ts @@ -1,53 +1,193 @@ -import React from 'react' -import { createRoot } from 'react-dom/client' -import Analytics, { gtag, identify, page, PrivacySettings, track } from './analytics' +import { ga4Gtag, ga4Service } from './analytics-services/ga4' +import { hubspotService } from './analytics-services/hubspot' +import { posthogService } from './analytics-services/posthog' +import { reoService } from './analytics-services/reo' +import { mountCookieConsentBanner } from './components/CookieConsentBanner' +import { mountPrivacySettingsDialog } from './components/PrivacySettingsDialog' +import { + clearCookieValue, + CookieConsentState, + cookieConsentToCookieValue, + cookieValueToCookieConsent, + getCookieValue, + setCookieValue, +} from './state/cookie-consent-state' +import { ThemeState } from './state/theme-state' import styles from './styles.css?inline' +import { CookieConsent } from './types' +import { shouldRequireConsent } from './utils/consent-check' -// Inject styles -const style = document.createElement('style') -style.textContent = styles -document.head.appendChild(style) - -// Create a container for our analytics component -const container = document.createElement('div') -container.id = 'tl-analytics-root' -document.body.appendChild(container) - -// Initialize the analytics component -const root = createRoot(container) -root.render(React.createElement(Analytics)) - -// Expose global functions -declare global { - interface Window { - tlanalytics: { - openPrivacySettings(): void - page(): void - identify(userId: string, properties?: { [key: string]: any }): void - track(name: string, data?: { [key: string]: any }): void - gtag(...args: any[]): void +class Analytics { + private userId = '' as string + private userProperties = {} as { [key: string]: any } | undefined + private consent = 'unknown' as CookieConsent + + private services = [posthogService, ga4Service, hubspotService, reoService] + + async initialize() { + // Inject styles + const style = document.createElement('style') + style.textContent = styles + document.head.appendChild(style) + + // Initialize the analytics services + for (const service of this.services) { + service.initialize() + } + + // Set up our mini reactive states + + const themeState = new ThemeState('light') + themeState.initialize() + + const cookieConsentState = new CookieConsentState('unknown') + cookieConsentState.initialize() + + // Subscribe to consent changes + cookieConsentState.subscribe((consent) => { + // Set (or clear) the cookie value + const cookieValue = cookieConsentToCookieValue(consent) + if (cookieValue) setCookieValue(cookieValue) + else clearCookieValue() + + // If the consent is the same as the current consent, do nothing + if (consent === this.consent) return + + this.consent = consent + + if (this.consent === 'opted-in') { + // Enable the analytics services only when consent is granted + for (const service of this.services) { + service.enable() + } + + // Identify the user if we have a userId. Most of the time + // identify() should be called off of the window.tlanalytics object, ie. in an app + // where we have a user id and properties for that app (like tldraw computer). We do + // it here, too, so that we can re-identify a user who has opted out of analytics + // and then opts back in within the same session. We would have their user id and properties + // in memory (from the first time they called identify) and would re-use them here. + if (this.userId) { + this.identify(this.userId, this.userProperties) + } + } else { + // Disable the analytics services when consent is revoked or when consent is unknown + for (const service of this.services) { + service.disable() + } + } + + // Track the consent change (after enabling or disabling) + this.track('consent_changed', { consent }) + }) + + // Now that we have our subscriber set up, determine the initial consent state. + // If the user has already made a choice (cookie exists), use that. + // Otherwise, check their location to determine if we need explicit consent. + const initialCookieValue = getCookieValue() + let initialConsent: CookieConsent + + if (initialCookieValue) { + // User has previously made a consent decision - respect it + initialConsent = cookieValueToCookieConsent(initialCookieValue) + } else { + // No existing consent decision - check if we need to ask based on location + const requiresConsent = await shouldRequireConsent() + initialConsent = requiresConsent ? 'unknown' : 'opted-in' + } + + // This will trigger the subscriber we set up earlier, which will + // enable/disable the analytics services accordingly + cookieConsentState.setValue(initialConsent) + + // Now that we have the consent value in memory, we can initialize + // the cookie consent banner and start showing some UI (if consent is unknown) + mountCookieConsentBanner(cookieConsentState, themeState, document.body) + + // ...also we stash a few things onto the window in case we need them elsewhere + window.tlanalytics = { + identify: this.identify.bind(this), + reset: this.reset.bind(this), + track: this.track.bind(this), + page: this.page.bind(this), + gtag: this.gtag.bind(this), + openPrivacySettings() { + mountPrivacySettingsDialog(cookieConsentState, themeState, document.body) + }, + } + } + + /** + * Wrap and guard google analytics tag. This should be called from window.tlanalytics, ie. in an app where we have a user id and properties for that app (like tldraw computer). + * + * @param args - The arguments to pass to the google analytics tag + * @returns void + */ + gtag(...args: any[]) { + if (this.consent !== 'opted-in') return + ga4Gtag(...args) + } + + /** + * Identify the user across all analytics services. This should be called from window.tlanalytics, ie. in an app where we have a user id and properties for that app (like tldraw computer). + * + * @param userId - The user id to identify the user by + * @param properties - The properties to identify the user by + * @returns void + */ + identify(userId: string, properties?: { [key: string]: any }) { + this.userId = userId + this.userProperties = properties + + if (this.consent !== 'opted-in') return + + for (const service of this.services) { + service.identify(userId, properties) + } + } + + /** + * Reset the user identity across all analytics services. This should be called from window.tlanalytics when a user logs out. + * + * @returns void + */ + reset() { + this.userId = '' + this.userProperties = undefined + + for (const service of this.services) { + service.reset() + } + } + + /** + * Track an event across all analytics services. This should be called from window.tlanalytics, ie. in an app where we have a user id and properties for that app (like tldraw computer). + * + * @param name - The name of the event to track + * @param data - The data to track with the event + * @returns void + */ + track(name: string, data?: { [key: string]: any }) { + for (const service of this.services) { + service.trackEvent(name, data) + } + } + + /** + * Track a page view across all analytics services. This should be called from window.tlanalytics, ie. in an app where we have a user id and properties for that app (like tldraw computer). + * + * @returns void + */ + page() { + for (const service of this.services) { + service.trackPageview() } - TL_GA4_MEASUREMENT_ID: string | undefined - TL_GOOGLE_ADS_ID?: string - Reo: any - posthog: any } } -// Create a container for the privacy settings dialog -const privacyContainer = document.createElement('div') -privacyContainer.id = 'tl-analytics-privacy-root' -document.body.appendChild(privacyContainer) - -const privacyRoot = createRoot(privacyContainer) - -// Expose the global function to open privacy settings -window.tlanalytics = { - openPrivacySettings: () => { - privacyRoot.render(React.createElement(PrivacySettings)) - }, - page, - identify, - track, - gtag, +try { + const analytics = new Analytics() + analytics.initialize() +} catch (error) { + console.error('Error initializing analytics manager:', error) } diff --git a/apps/analytics/src/state/cookie-consent-state.ts b/apps/analytics/src/state/cookie-consent-state.ts new file mode 100644 index 000000000000..f4bb8ab476c8 --- /dev/null +++ b/apps/analytics/src/state/cookie-consent-state.ts @@ -0,0 +1,35 @@ +import Cookies from 'js-cookie' +import { CONSENT_COOKIE_NAME } from '../constants' +import { type CookieConsent } from '../types' +import { AnalyticsState } from './state' + +export function cookieConsentToCookieValue(consent: CookieConsent): string | undefined { + switch (consent) { + case 'opted-in': + return 'true' + case 'opted-out': + return 'false' + case 'unknown': + return undefined + } +} + +export function getCookieValue(): string | undefined { + return Cookies.get(CONSENT_COOKIE_NAME) +} + +export function setCookieValue(value: string): void { + Cookies.set(CONSENT_COOKIE_NAME, value) +} + +export function clearCookieValue() { + Cookies.remove(CONSENT_COOKIE_NAME) +} + +export function cookieValueToCookieConsent(cookieValue: string | undefined): CookieConsent { + if (cookieValue === 'true') return 'opted-in' + if (cookieValue === 'false') return 'opted-out' + return 'unknown' +} + +export class CookieConsentState extends AnalyticsState {} diff --git a/apps/analytics/src/state/state.test.ts b/apps/analytics/src/state/state.test.ts new file mode 100644 index 000000000000..486bf4c04fa6 --- /dev/null +++ b/apps/analytics/src/state/state.test.ts @@ -0,0 +1,57 @@ +import { AnalyticsState } from './state' + +describe('mini reactive state', () => { + test('creates a state with an initial value', () => { + class MyState extends AnalyticsState {} + const myState = new MyState(10) + expect(myState.getValue()).toBe(10) + const myOtherState = new MyState(20) + expect(myOtherState.getValue()).toBe(20) + }) + + test('updates the state', () => { + class MyState extends AnalyticsState {} + const myState = new MyState(10) + myState.setValue(20) + expect(myState.getValue()).toBe(20) + }) + + test('handles subscribers', () => { + class MyState extends AnalyticsState {} + const myState = new MyState(10) + const fn = vi.fn() + myState.subscribe((value) => fn(value)) + myState.setValue(20) + expect(fn).toHaveBeenCalledWith(20) + expect(fn).toHaveBeenCalledOnce() + }) + + test('removes subscribers', () => { + class MyState extends AnalyticsState {} + const myState = new MyState(10) + const fn = vi.fn() + const unsubscribe = myState.subscribe((value) => fn(value)) + unsubscribe() + myState.setValue(20) + expect(fn).not.toHaveBeenCalled() + }) + + test('handles initializer / dispose', () => { + const someState = {} as { something?: boolean } + + class MyState extends AnalyticsState { + override initialize(): void { + someState.something = true + } + override dispose(): void { + delete someState.something + } + } + const myState = new MyState(10) + expect(someState.something).not.toBeDefined() + myState.initialize() + expect(someState.something).toBeDefined() + myState.dispose() + expect(someState.something).not.toBeDefined() + }) +}) diff --git a/apps/analytics/src/state/state.ts b/apps/analytics/src/state/state.ts new file mode 100644 index 000000000000..492ed76da2a1 --- /dev/null +++ b/apps/analytics/src/state/state.ts @@ -0,0 +1,59 @@ +export class AnalyticsState { + // The current value of the state. + protected value: T + + // Set of listeners to notify when the state changes. + protected listeners = new Set<(value: T) => void>() + + constructor(initialValue: T) { + this.value = initialValue + } + + /** + * Subscribe to the state change. + * + * @param listener - The listener to notify when the state changes. + * @returns A function to unsubscribe the listener. + */ + subscribe(listener: (value: T) => void): () => void { + this.listeners.add(listener) + return () => this.listeners.delete(listener) + } + + /** + * Notify all listeners of the state change. + */ + notify() { + this.listeners.forEach((listener) => listener(this.value)) + } + + /** + * Initialize the state. + */ + initialize(): void {} + + /** + * Clean up the state. + */ + dispose(): void {} + + /** + * Get the current value of the state. + * + * @returns The current value. + */ + getValue(): T { + return this.value + } + + /** + * Set the value of the state and notify all listeners. + * + * @param value - The new value to set. + */ + setValue(value: T): void { + if (value === this.value) return + this.value = value + this.notify() + } +} diff --git a/apps/analytics/src/state/theme-state.ts b/apps/analytics/src/state/theme-state.ts new file mode 100644 index 000000000000..539852462778 --- /dev/null +++ b/apps/analytics/src/state/theme-state.ts @@ -0,0 +1,47 @@ +// This module provides theme detection utilities for analytics components +// Since the analytics library is used on many sites, which all may use different themes, +// we use the most general way of detecting light or dark theme by checking the +// `color-scheme` CSS property on the `html` element. + +import { AnalyticsState } from './state' + +export class ThemeState extends AnalyticsState<'light' | 'dark'> { + private observer: MutationObserver | null = null + + override initialize(): void { + // If document is not available, default to light theme + if (typeof document === 'undefined') { + this.value = 'light' + return + } + + // Read initial theme from document + const docElm = document.documentElement + this.value = docElm.getAttribute('style')?.includes('color-scheme: dark') ? 'dark' : 'light' + + if (typeof MutationObserver === 'undefined') { + // weird browser, we just won't set up the observer (we won't be able to detect theme changes) + } else { + const observer = new MutationObserver((mutations) => { + if (mutations.some((mutation) => mutation.attributeName === 'style')) { + this.setValue( + docElm.getAttribute('style')?.includes('color-scheme: dark') ? 'dark' : 'light' + ) + } + }) + + observer.observe(document.documentElement, { + attributes: true, + attributeFilter: ['style'], + }) + + this.observer = observer + } + } + override dispose() { + if (this.observer) { + this.observer.disconnect() + this.observer = null + } + } +} diff --git a/apps/analytics/src/styles.css b/apps/analytics/src/styles.css index 4e0193669109..20eaf9ef9ee3 100644 --- a/apps/analytics/src/styles.css +++ b/apps/analytics/src/styles.css @@ -1,138 +1,126 @@ :root { - --tl-analytics-button-bg: #000000; - --tl-analytics-button-text: #ffffff; - --tl-analytics-bg: white; - --tl-analytics-text: #111827; - --tl-analytics-text-secondary: #374151; - --tl-analytics-border: #e5e7eb; - --tl-analytics-link: #3b82f6; - --tl-analytics-link-hover: #2563eb; - --tl-analytics-overlay: rgba(255, 255, 255, 0.9); - --tl-analytics-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06); -} - -[data-theme='dark'] { - --tl-analytics-button-bg: #ffffff; - --tl-analytics-button-text: #000000; - --tl-analytics-bg: #18181b; - --tl-analytics-text: #f4f4f5; - --tl-analytics-text-secondary: #a1a1aa; - --tl-analytics-border: #27272a; + --tl-analytics-button-bg: hsl(0, 0%, 100%); + --tl-analytics-button-text: hsl(235, 6.8%, 13.5%); + --tl-analytics-bg: hsl(235, 6.8%, 13.5%); + --tl-analytics-text: hsl(0, 9%, 94%); + --tl-analytics-text-secondary: hsl(204, 4%, 75%); --tl-analytics-link: #60a5fa; --tl-analytics-link-hover: #93c5fd; - --tl-analytics-overlay: rgba(0, 0, 0, 0.9); - --tl-analytics-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.3), 0 2px 4px -1px rgba(0, 0, 0, 0.2); + --tl-analytics-overlay: rgba(0, 0, 0, 0.2); + --tl-analytics-shadow: + 0px 1px 3px hsl(0, 0%, 0%, 66.6%), 0px 2px 6px hsl(0, 0%, 0%, 33%), + inset 0px 0px 0px 1px var(--tl-color-panel-contrast); } -#tl-analytics-root { - font-weight: 400; +[data-theme='dark'] { + --tl-analytics-button-bg: hsl(0, 0%, 0%); + --tl-analytics-button-text: hsl(0, 0%, 100%); + --tl-analytics-bg: hsl(0, 0%, 99%); + --tl-analytics-text: hsl(0, 0%, 0%); + --tl-analytics-text-secondary: hsl(204, 4%, 45%); + --tl-analytics-link: #3b82f6; + --tl-analytics-link-hover: #2563eb; + --tl-analytics-overlay: rgba(0, 0, 0, 0.45); + --tl-analytics-shadow: + 0px 0px 2px hsl(0, 0%, 0%, 16%), 0px 2px 3px hsl(0, 0%, 0%, 24%), + 0px 2px 6px hsl(0, 0%, 0%, 0.1), inset 0px 0px 0px 1px var(--tl-color-panel-contrast); } .tl-analytics-banner { position: fixed; z-index: 1000; - padding: 14px; + padding: 6px; border-radius: 8px; box-shadow: var(--tl-analytics-shadow); - border: 1px solid var(--tl-analytics-border); background-color: var(--tl-analytics-bg); display: flex; flex-direction: column; - gap: 12px; + gap: 4px; /* Inter is usually available on our properties */ font-family: 'Inter', sans-serif; + font-weight: 400; /* Safe area aware overrides */ - bottom: max(8px, env(safe-area-inset-bottom)); - left: max(8px, env(safe-area-inset-left)); - max-width: calc( - 100% - max(8px, env(safe-area-inset-left)) - max(8px, env(safe-area-inset-right)) - ); + bottom: max(4px, env(safe-area-inset-bottom)); + right: max(4px, env(safe-area-inset-right)); + max-width: 240px; /* Slide-in animation */ - transform: translateY(120%); - animation: slideUp 5s ease-in-out forwards; + transform: translateY(110%); + animation: slideUp 5s ease-in forwards; animation-delay: 2s; } @keyframes slideUp { - from { - transform: translateY(120%); + 0% { + transform: translateY(110%); } - to { + 100% { transform: translateY(0); } } -@media (min-width: 640px) { - .tl-analytics-banner { - flex-direction: row; - align-items: center; - gap: 32px; - } -} - -.tl-analytics-banner p { +.tl-analytics-banner__text { font-size: 12px; - line-height: 1.5; + line-height: 1.4; color: var(--tl-analytics-text); margin: 0; + padding: 8px 8px 12px; } -.tl-analytics-banner a { +.tl-analytics-banner__link { color: var(--tl-analytics-link); text-decoration: none; } -.tl-analytics-banner a:hover { +.tl-analytics-banner__link:hover { color: var(--tl-analytics-link-hover); } -.tl-analytics-buttons { +.tl-analytics-banner__buttons { display: flex; - gap: 16px; + gap: 4px; justify-content: space-between; width: 100%; -} - -@media (min-width: 640px) { - .tl-analytics-buttons { - width: auto; - } + flex-wrap: wrap; } .tl-analytics-button { - font-size: 14px; + font-size: 12px; cursor: pointer; text-decoration: none; border: none; - padding: 8px 16px; - border-radius: 100px; + padding: 4px 8px; + border-radius: 6px; + white-space: nowrap; + flex-shrink: 0; } -.tl-analytics-button-primary { +.tl-analytics-button--primary { + font-weight: 500; background-color: var(--tl-analytics-button-bg); color: var(--tl-analytics-button-text); - font-weight: 500; overflow: hidden; position: relative; + padding: 6px 6px; + min-width: 96px; } -.tl-analytics-button-text-wrapper { +.tl-analytics-button__text-wrapper { overflow: hidden; } -.tl-analytics-button-text { +.tl-analytics-button__text { display: inline-block; - animation: marquee 3s linear infinite; + animation: marquee 2.5s linear infinite; white-space: nowrap; - transform: translateX(100%); + transform: translateX(72px); } @keyframes marquee { 0% { - transform: translateX(100%); + transform: translateX(72px); } 100% { - transform: translateX(-100%); + transform: translateX(-72px); } } @@ -143,102 +131,125 @@ transform: translateY(0); } - .tl-analytics-button-text { + .tl-analytics-button__text { animation: none; transform: translateX(0); } } -.tl-analytics-button-secondary { +.tl-analytics-button--secondary { background: none; - color: var(--tl-analytics-text-secondary); - opacity: 0.82; - padding: 0px 0px; - margin: 0px 16px; -} - -.tl-analytics-button-secondary:hover { color: var(--tl-analytics-text); } .tl-analytics-dialog { + font-family: 'Inter', sans-serif; + color: var(--tl-analytics-text); position: fixed; inset: 0; - z-index: 100; - background-color: var(--tl-analytics-overlay); -} - -.tl-analytics-dialog-wrapper { - position: fixed; - inset: 0; - z-index: 150; + z-index: 10000; display: flex; flex-direction: column; align-items: center; justify-content: center; - height: 100vh; } -.tl-analytics-dialog-content { +.tl-analytics-dialog__overlay { + position: fixed; + inset: 0; + background-color: var(--tl-analytics-overlay); + z-index: 1; +} + +.tl-analytics-dialog__wrapper { + z-index: 2; +} + +.tl-analytics-dialog__content { position: relative; - max-width: 32rem; - padding: 2rem; + max-width: 350px; + min-width: 350px; background-color: var(--tl-analytics-bg); - border-radius: 0.375rem; + border-radius: 8px; box-shadow: var(--tl-analytics-shadow); - font-size: 1rem; + font-size: 12px; + line-height: 1.6; text-align: left; } -.tl-analytics-dialog-title { - font-weight: 700; +.tl-analytics-dialog__header { + height: 40px; + padding-left: 12px; + display: flex; + align-items: center; + justify-content: space-between; +} + +.tl-analytics-dialog__title { + font-weight: 500; + font-size: 12px; color: var(--tl-analytics-text); - margin: 0 0 1rem 0; + margin: 0; } -.tl-analytics-dialog-close { - position: absolute; - top: 8px; - right: 8px; +.tl-analytics-dialog__close { + position: relative; + height: 40px; + width: 40px; + display: flex; + align-items: center; + justify-content: center; padding: 4px; border: none; background: none; cursor: pointer; - color: var(--tl-analytics-text-secondary); + color: var(--tl-analytics-text); } -.tl-analytics-dialog-close:hover { - color: var(--tl-analytics-text); +@media (hover: hover) { + .tl-analytics-dialog__close::after { + content: ''; + position: absolute; + inset: 4px; + background-color: var(--tl-analytics-overlay); + border-radius: 4px; + opacity: 0; + } + .tl-analytics-dialog__close:hover::after { + opacity: 0.2; + } } -.tl-analytics-dialog-body { - margin-top: 1.5rem; +.tl-analytics-dialog__body { + margin: 12px; } -.tl-analytics-dialog-body p { - margin: 0 0 1rem 0; +.tl-analytics-dialog__body p { + margin: 0; color: var(--tl-analytics-text-secondary); } -.tl-analytics-dialog-body a { +.tl-analytics-dialog__body a { + display: inline-block; color: var(--tl-analytics-link); text-decoration: none; } -.tl-analytics-dialog-body a:hover { +.tl-analytics-dialog__body a:hover { color: var(--tl-analytics-link-hover); } -.tl-analytics-checkbox-group { +.tl-analytics-dialog__checkbox-group { display: flex; align-items: center; - gap: 8px; - margin-bottom: 1rem; + gap: 12px; + margin: 12px; + padding-bottom: 12px; } .tl-analytics-checkbox { - width: 3rem; - height: 1.75rem; + width: 32px; + height: 20px; background-color: var(--tl-analytics-text-secondary); border-radius: 9999px; position: relative; @@ -247,33 +258,36 @@ padding: 0; } -.tl-analytics-checkbox[data-state='checked'] { - background-color: var(--tl-analytics-link); -} - -.tl-analytics-checkbox > span { +.tl-analytics-checkbox__thumb { display: block; - width: 1.25rem; - height: 1.25rem; + width: 16px; + height: 16px; background-color: var(--tl-analytics-bg); border-radius: 9999px; transition: transform 100ms; - transform: translateX(0.25rem); + transform: translateX(2px); } -.tl-analytics-checkbox[data-state='checked'] > span { - transform: translateX(1.5rem); +.tl-analytics-checkbox[aria-checked='true'] { + background-color: var(--tl-analytics-link); } -.tl-analytics-checkbox-label { - margin-top: 1.5rem; - margin-bottom: 0.5rem; - color: var(--tl-analytics-text-secondary); +.tl-analytics-checkbox[aria-checked='true'] .tl-analytics-checkbox__thumb { + transform: translateX(14px); } -.tl-analytics-dialog-footer { - margin-top: 1.5rem; +.tl-analytics-checkbox__label { + margin: 0; + font-size: 12px; +} + +.tl-analytics-dialog__footer { + padding: 0 8px 8px; display: flex; justify-content: flex-end; - gap: 8px; + gap: 4px; +} + +body:has(.tl-analytics-dialog) .tl-analytics-banner { + opacity: 0; } diff --git a/apps/analytics/src/types.ts b/apps/analytics/src/types.ts new file mode 100644 index 000000000000..2a7eaca193c9 --- /dev/null +++ b/apps/analytics/src/types.ts @@ -0,0 +1,19 @@ +// Expose global functions +declare global { + interface Window { + tlanalytics: { + openPrivacySettings(): void + page(): void + identify(userId: string, properties?: { [key: string]: any }): void + reset(): void + track(name: string, data?: { [key: string]: any }): void + gtag(...args: any[]): void + } + TL_GA4_MEASUREMENT_ID: string | undefined + TL_GOOGLE_ADS_ID?: string + Reo: any + posthog: any + } +} + +export type CookieConsent = 'unknown' | 'opted-in' | 'opted-out' diff --git a/apps/analytics/src/utils/consent-check.ts b/apps/analytics/src/utils/consent-check.ts new file mode 100644 index 000000000000..cd69f89d587a --- /dev/null +++ b/apps/analytics/src/utils/consent-check.ts @@ -0,0 +1,28 @@ +/** + * Checks if consent is required based on CloudFlare geolocation headers + * + * @returns Promise - true if explicit consent is required, false ONLY if confident it's not + */ +export async function shouldRequireConsent(): Promise { + // CloudFlare provides the CF-IPCountry header on all requests + // Our consent worker checks this and returns whether consent is required + try { + const response = await fetch('https://tldraw-consent.workers.dev', { + // Use a short timeout to avoid delaying the page load + signal: AbortSignal.timeout(2000), + }) + if (response.ok) { + const data = await response.json() + // Worker returns { requires_consent: boolean, country_code: string } + if (typeof data.requires_consent === 'boolean') { + return data.requires_consent + } + } + } catch (error) { + // Fetch failed or timed out - will default to requiring consent + console.warn('Consent check failed, defaulting to requiring consent:', error) + } + + // Conservative default: require consent + return true +} diff --git a/apps/analytics/src/types.d.ts b/apps/analytics/src/vite-env.d.ts similarity index 67% rename from apps/analytics/src/types.d.ts rename to apps/analytics/src/vite-env.d.ts index ac8e774f165e..379944592791 100644 --- a/apps/analytics/src/types.d.ts +++ b/apps/analytics/src/vite-env.d.ts @@ -1,3 +1,5 @@ +/// + declare module '*.css?inline' { const content: string export default content diff --git a/apps/analytics/tsconfig.json b/apps/analytics/tsconfig.json index f74263ee2f1c..832e34e2662a 100644 --- a/apps/analytics/tsconfig.json +++ b/apps/analytics/tsconfig.json @@ -2,9 +2,16 @@ "extends": "../../internal/config/tsconfig.base.json", "compilerOptions": { "moduleResolution": "bundler", + "composite": false, + "declaration": false, + "declarationMap": false, "noEmit": true, - "emitDeclarationOnly": false + "emitDeclarationOnly": false, + "incremental": false, + "types": ["vite/client", "vitest/globals"], + "lib": ["dom", "DOM.Iterable", "esnext"] }, - "include": ["src", "src/analytics.tsx", "./vite.config.ts"], + "exclude": ["node_modules", "public", ".tsbuild*", "worker"], + "include": ["src", "./vite.config.ts", "./vitest.config.ts"], "references": [] } diff --git a/apps/analytics/vercel.json b/apps/analytics/vercel.json index f362bb1ab4bf..eafff625f38b 100644 --- a/apps/analytics/vercel.json +++ b/apps/analytics/vercel.json @@ -8,8 +8,14 @@ { "source": "/(.*)", "headers": [ - { "key": "Access-Control-Allow-Origin", "value": "*" }, - { "key": "Access-Control-Allow-Methods", "value": "GET, POST" } + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "Access-Control-Allow-Methods", + "value": "GET, POST" + } ] } ], diff --git a/apps/analytics/vite.config.ts b/apps/analytics/vite.config.ts index 0410b5d13aa6..0fcf629914aa 100644 --- a/apps/analytics/vite.config.ts +++ b/apps/analytics/vite.config.ts @@ -1,8 +1,7 @@ -import react from '@vitejs/plugin-react' import { defineConfig } from 'vite' export default defineConfig({ - plugins: [react()], + plugins: [], define: { 'process.env.NODE_ENV': JSON.stringify('production'), }, @@ -15,12 +14,7 @@ export default defineConfig({ formats: ['umd'], }, rollupOptions: { - output: { - globals: { - react: 'React', - 'react-dom': 'ReactDOM', - }, - }, + // React and ReactDOM are now bundled instead of external }, }, }) diff --git a/apps/analytics/vitest.config.ts b/apps/analytics/vitest.config.ts new file mode 100644 index 000000000000..686bc41cd365 --- /dev/null +++ b/apps/analytics/vitest.config.ts @@ -0,0 +1,6 @@ +/// +import { mergeConfig } from 'vitest/config' +import baseConfig from '../../internal/config/vitest/node-preset' + +// State package uses the standard node preset with no overrides +export default mergeConfig(baseConfig, {}) diff --git a/apps/dotcom/client/src/tla/hooks/useAnalyticsConsent.tsx b/apps/dotcom/client/src/tla/hooks/useAnalyticsConsent.tsx index d6307beb4e9a..8681e606ea29 100644 --- a/apps/dotcom/client/src/tla/hooks/useAnalyticsConsent.tsx +++ b/apps/dotcom/client/src/tla/hooks/useAnalyticsConsent.tsx @@ -36,6 +36,7 @@ export function useAnalyticsConsent() { // Immediately configure analytics for signed-out users configureAnalytics(newConsent, undefined) } + trackEvent('consent_changed', { consent: newConsent }) }, [isSignedIn, user, app] diff --git a/internal/scripts/deploy-analytics.ts b/internal/scripts/deploy-analytics.ts new file mode 100644 index 000000000000..3a07845dd77b --- /dev/null +++ b/internal/scripts/deploy-analytics.ts @@ -0,0 +1,107 @@ +import assert from 'assert' +import { readFileSync } from 'fs' +import path, { join } from 'path' +import toml from 'toml' +import { + createGithubDeployment, + getDeployInfo, + setWranglerPreviewConfig, + wranglerDeploy, +} from './lib/deploy' +import { Discord } from './lib/discord' +import { REPO_ROOT } from './lib/file' +import { makeEnv } from './lib/makeEnv' +import { nicelog } from './lib/nicelog' + +const workerDir = path.relative(process.cwd(), path.resolve(REPO_ROOT, './apps/analytics-worker')) + +// Do not use `process.env` directly in this script. Add your variable to `makeEnv` and use it via +// `env` instead. This makes sure that all required env vars are present. +const env = makeEnv([ + 'CLOUDFLARE_ACCOUNT_ID', + 'CLOUDFLARE_API_TOKEN', + 'DISCORD_DEPLOY_WEBHOOK_URL', + 'RELEASE_COMMIT_HASH', + 'TLDRAW_ENV', + 'GH_TOKEN', +]) + +const discord = new Discord({ + webhookUrl: env.DISCORD_DEPLOY_WEBHOOK_URL, + shouldNotify: env.TLDRAW_ENV === 'production', + totalSteps: 2, +}) + +const { previewId, sha } = getDeployInfo() + +async function main() { + assert( + env.TLDRAW_ENV === 'staging' || env.TLDRAW_ENV === 'production' || env.TLDRAW_ENV === 'preview', + 'TLDRAW_ENV must be staging or production or preview' + ) + + await discord.message(`--- **${env.TLDRAW_ENV} analytics worker deploy pre-flight** ---`) + + await discord.step('cloudflare deploy dry run', async () => { + await deployAnalyticsWorker({ dryRun: true }) + }) + + // --- point of no return! do the deploy for real --- // + + await discord.message(`--- **pre-flight complete, starting real analytics worker deploy** ---`) + + await discord.step('deploying analytics worker to cloudflare', async () => { + await deployAnalyticsWorker({ dryRun: false }) + }) + + // Get the worker name from wrangler.toml + const wranglerConfig = toml.parse(readFileSync(join(workerDir, 'wrangler.toml')).toString()) + const workerName = wranglerConfig?.env?.[env.TLDRAW_ENV]?.name || wranglerConfig?.name + if (!workerName) { + throw new Error('Could not find worker name in wrangler.toml') + } + + // Analytics worker uses default workers.dev domain + const deploymentUrl = `https://${workerName}.${env.CLOUDFLARE_ACCOUNT_ID}.workers.dev` + + nicelog('Creating deployment for', deploymentUrl) + await createGithubDeployment(env, { + app: 'analytics-worker', + deploymentUrl, + sha, + }) + + await discord.message(`**Deploy complete!**`) +} + +let didUpdateAnalyticsWorker = false +async function deployAnalyticsWorker({ dryRun }: { dryRun: boolean }) { + const workerId = `${previewId ?? env.TLDRAW_ENV}-tldraw-consent` + if (previewId && !didUpdateAnalyticsWorker) { + await setWranglerPreviewConfig(workerDir, { + name: workerId, + }) + didUpdateAnalyticsWorker = true + } + + await wranglerDeploy({ + location: workerDir, + dryRun, + env: env.TLDRAW_ENV, + vars: { + WORKER_NAME: workerId, + TLDRAW_ENV: env.TLDRAW_ENV, + }, + }) +} + +main().catch(async (err) => { + // don't notify discord on preview builds + if (env.TLDRAW_ENV !== 'preview') { + await discord.message(`${Discord.AT_TEAM_MENTION} Deploy failed: ${err.stack}`, { + always: true, + }) + } + console.error(err) + process.exit(1) +}) diff --git a/internal/scripts/lib/deploy.ts b/internal/scripts/lib/deploy.ts index 5323a561657b..afb18f8245e3 100644 --- a/internal/scripts/lib/deploy.ts +++ b/internal/scripts/lib/deploy.ts @@ -186,12 +186,13 @@ ${serviceBinding ? `services = [ {binding = "${serviceBinding.binding}", service const path = join(location, 'wrangler.toml') let data = readFileSync(path).toString() - if (data.includes('\n[env.preview]\n')) { - if (!data.includes(envPreviewSection)) { - data = data.replace('\n[env.preview]\n', envPreviewSection) - } else { - // it was already added? - } + + // Replace the entire [env.preview] section including all its properties + // Match from [env.preview] to the next section or end of file + const previewSectionRegex = /\n\[env\.preview\]\n(?:[^[](?:[^\n]*\n)*)?/ + + if (previewSectionRegex.test(data)) { + data = data.replace(previewSectionRegex, envPreviewSection) } else { data += envPreviewSection } diff --git a/yarn.lock b/yarn.lock index 7810a1926c35..e12b80a96024 100644 --- a/yarn.lock +++ b/yarn.lock @@ -9041,22 +9041,30 @@ __metadata: languageName: node linkType: hard +"@tldraw/analytics-worker@workspace:apps/analytics-worker": + version: 0.0.0-use.local + resolution: "@tldraw/analytics-worker@workspace:apps/analytics-worker" + dependencies: + "@cloudflare/workers-types": "npm:^4.20250913.0" + esbuild: "npm:^0.25.6" + lazyrepo: "npm:0.0.0-alpha.27" + typescript: "npm:^5.8.3" + wrangler: "npm:^4.37.1" + languageName: unknown + linkType: soft + "@tldraw/analytics@workspace:apps/analytics": version: 0.0.0-use.local resolution: "@tldraw/analytics@workspace:apps/analytics" dependencies: + "@cloudflare/workers-types": "npm:^4.20250913.0" "@types/js-cookie": "npm:^3.0.6" - "@types/react": "npm:^18.3.18" - "@types/react-dom": "npm:^18.3.5" - "@vitejs/plugin-react": "npm:^4.6.0" js-cookie: "npm:^3.0.5" posthog-js: "npm:^1.248.1" - radix-ui: "npm:^1.4.2" - react: "npm:^18.3.1" - react-dom: "npm:^18.3.1" - react-ga4: "npm:^2.1.0" typescript: "npm:^5.8.3" vite: "npm:^7.0.1" + vitest: "npm:^3.2.4" + wrangler: "npm:^4.37.1" languageName: unknown linkType: soft From 250c3a6cdafd375ab760d3f8fd4f6f716282a9b9 Mon Sep 17 00:00:00 2001 From: Steve Ruiz Date: Tue, 21 Oct 2025 08:34:59 -0400 Subject: [PATCH 009/114] Add analytics tracking to sidebar dotdev link actions (#6954) Enhanced the ExternalLink component to support an optional eventName prop for analytics tracking. Updated the TlaSidebarDotDevLink to track clicks and dismissals using the trackEvent utility. ### Change type - [ ] `bugfix` - [ ] `improvement` - [ ] `feature` - [ ] `api` - [x] `other` --- > [!NOTE] > Add optional analytics tracking to `ExternalLink` and wire up tracking for sidebar dotdev link and feedback dialog links. > > - **Analytics**: > - Enhance `ExternalLink` (`apps/dotcom/client/src/tla/components/ExternalLink/ExternalLink.tsx`): > - Accepts optional `eventName` prop; fires `trackEvent(eventName, { link })` on click and preserves existing `onClick`. > - Sidebar (`apps/dotcom/client/src/tla/components/TlaSidebar/components/TlaSidebarDotDevLink.tsx`): > - Track link click via `eventName="sidebar-dotdev-link-clicked"`. > - Track dismiss button via `trackEvent('sidebar-dotdev-link-dismissed')`. > - Feedback dialog (`apps/dotcom/client/src/tla/components/dialogs/SubmitFeedbackDialog.tsx`): > - Add `eventName` to Discord and GitHub `ExternalLink`s to track clicks. > > Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit f91ccbde8c20ec9dc826def40ac50b1e64f621e5. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot). --- .../components/ExternalLink/ExternalLink.tsx | 16 ++++++++++---- .../components/TlaSidebarDotDevLink.tsx | 10 ++++++++- .../dialogs/SubmitFeedbackDialog.tsx | 22 +++++++++++++++---- 3 files changed, 39 insertions(+), 9 deletions(-) diff --git a/apps/dotcom/client/src/tla/components/ExternalLink/ExternalLink.tsx b/apps/dotcom/client/src/tla/components/ExternalLink/ExternalLink.tsx index af85e3a6cd4f..32b3c86533d9 100644 --- a/apps/dotcom/client/src/tla/components/ExternalLink/ExternalLink.tsx +++ b/apps/dotcom/client/src/tla/components/ExternalLink/ExternalLink.tsx @@ -1,10 +1,18 @@ import { ComponentProps } from 'react' import { Link } from 'react-router-dom' +import { trackEvent } from '../../../utils/analytics' -export function ExternalLink(props: ComponentProps) { +export function ExternalLink(props: ComponentProps & { eventName?: string }) { + const { eventName, ...rest } = props return ( - - {props.children} - + { + if (eventName) trackEvent(eventName, { link: rest.to ?? '' }) + rest.onClick?.(e) + }} + /> ) } diff --git a/apps/dotcom/client/src/tla/components/TlaSidebar/components/TlaSidebarDotDevLink.tsx b/apps/dotcom/client/src/tla/components/TlaSidebar/components/TlaSidebarDotDevLink.tsx index e0e6ddc123b9..e5c2cb455164 100644 --- a/apps/dotcom/client/src/tla/components/TlaSidebar/components/TlaSidebarDotDevLink.tsx +++ b/apps/dotcom/client/src/tla/components/TlaSidebar/components/TlaSidebarDotDevLink.tsx @@ -1,5 +1,6 @@ import classNames from 'classnames' import { TldrawUiIcon, useLocalStorageState } from 'tldraw' +import { trackEvent } from '../../../../utils/analytics' import { F } from '../../../utils/i18n' import { ExternalLink } from '../../ExternalLink/ExternalLink' import styles from '../sidebar.module.css' @@ -13,6 +14,10 @@ export function TlaSidebarDotDevLink() { { + setShowDotDevLink(false) + }} > @@ -22,7 +27,10 @@ export function TlaSidebarDotDevLink() { data-testid="tla-sidebar-dotdev-dismiss-button" aria-label="Dismiss" className={classNames(styles.sidebarDotDevDismissButton, styles.hoverable)} - onClick={() => setShowDotDevLink(false)} + onClick={() => { + trackEvent('sidebar-dotdev-link-dismissed') + setShowDotDevLink(false) + }} > diff --git a/apps/dotcom/client/src/tla/components/dialogs/SubmitFeedbackDialog.tsx b/apps/dotcom/client/src/tla/components/dialogs/SubmitFeedbackDialog.tsx index 1738f1bc0f18..d3dc588846b5 100644 --- a/apps/dotcom/client/src/tla/components/dialogs/SubmitFeedbackDialog.tsx +++ b/apps/dotcom/client/src/tla/components/dialogs/SubmitFeedbackDialog.tsx @@ -50,12 +50,18 @@ function SignedOutSubmitFeedbackDialog() {

+ data: Data + pluginArgs: PluginArgs +} +type PagesPluginFunction< + Env = unknown, + Params extends string = any, + Data extends Record = Record, + PluginArgs = unknown, +> = (context: EventPluginContext) => Response | Promise +declare module 'assets:*' { + export const onRequest: PagesFunction +} +// Copyright (c) 2022-2023 Cloudflare, Inc. +// Licensed under the Apache 2.0 license found in the LICENSE file or at: +// https://opensource.org/licenses/Apache-2.0 +declare module 'cloudflare:pipelines' { + export abstract class PipelineTransformationEntrypoint< + Env = unknown, + I extends PipelineRecord = PipelineRecord, + O extends PipelineRecord = PipelineRecord, + > { + protected env: Env + protected ctx: ExecutionContext + constructor(ctx: ExecutionContext, env: Env) + /** + * run recieves an array of PipelineRecord which can be + * transformed and returned to the pipeline + * @param records Incoming records from the pipeline to be transformed + * @param metadata Information about the specific pipeline calling the transformation entrypoint + * @returns A promise containing the transformed PipelineRecord array + */ + public run(records: I[], metadata: PipelineBatchMetadata): Promise + } + export type PipelineRecord = Record + export type PipelineBatchMetadata = { + pipelineId: string + pipelineName: string + } + export interface Pipeline { + /** + * The Pipeline interface represents the type of a binding to a Pipeline + * + * @param records The records to send to the pipeline + */ + send(records: T[]): Promise + } +} +// PubSubMessage represents an incoming PubSub message. +// The message includes metadata about the broker, the client, and the payload +// itself. +// https://developers.cloudflare.com/pub-sub/ +interface PubSubMessage { + // Message ID + readonly mid: number + // MQTT broker FQDN in the form mqtts://BROKER.NAMESPACE.cloudflarepubsub.com:PORT + readonly broker: string + // The MQTT topic the message was sent on. + readonly topic: string + // The client ID of the client that published this message. + readonly clientId: string + // The unique identifier (JWT ID) used by the client to authenticate, if token + // auth was used. + readonly jti?: string + // A Unix timestamp (seconds from Jan 1, 1970), set when the Pub/Sub Broker + // received the message from the client. + readonly receivedAt: number + // An (optional) string with the MIME type of the payload, if set by the + // client. + readonly contentType: string + // Set to 1 when the payload is a UTF-8 string + // https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901063 + readonly payloadFormatIndicator: number + // Pub/Sub (MQTT) payloads can be UTF-8 strings, or byte arrays. + // You can use payloadFormatIndicator to inspect this before decoding. + payload: string | Uint8Array +} +// JsonWebKey extended by kid parameter +interface JsonWebKeyWithKid extends JsonWebKey { + // Key Identifier of the JWK + readonly kid: string +} +interface RateLimitOptions { + key: string +} +interface RateLimitOutcome { + success: boolean +} +interface RateLimit { + /** + * Rate limit a request based on the provided options. + * @see https://developers.cloudflare.com/workers/runtime-apis/bindings/rate-limit/ + * @returns A promise that resolves with the outcome of the rate limit. + */ + limit(options: RateLimitOptions): Promise +} +// Namespace for RPC utility types. Unfortunately, we can't use a `module` here as these types need +// to referenced by `Fetcher`. This is included in the "importable" version of the types which +// strips all `module` blocks. +declare namespace Rpc { + // Branded types for identifying `WorkerEntrypoint`/`DurableObject`/`Target`s. + // TypeScript uses *structural* typing meaning anything with the same shape as type `T` is a `T`. + // For the classes exported by `cloudflare:workers` we want *nominal* typing (i.e. we only want to + // accept `WorkerEntrypoint` from `cloudflare:workers`, not any other class with the same shape) + export const __RPC_STUB_BRAND: '__RPC_STUB_BRAND' + export const __RPC_TARGET_BRAND: '__RPC_TARGET_BRAND' + export const __WORKER_ENTRYPOINT_BRAND: '__WORKER_ENTRYPOINT_BRAND' + export const __DURABLE_OBJECT_BRAND: '__DURABLE_OBJECT_BRAND' + export const __WORKFLOW_ENTRYPOINT_BRAND: '__WORKFLOW_ENTRYPOINT_BRAND' + export interface RpcTargetBranded { + [__RPC_TARGET_BRAND]: never + } + export interface WorkerEntrypointBranded { + [__WORKER_ENTRYPOINT_BRAND]: never + } + export interface DurableObjectBranded { + [__DURABLE_OBJECT_BRAND]: never + } + export interface WorkflowEntrypointBranded { + [__WORKFLOW_ENTRYPOINT_BRAND]: never + } + export type EntrypointBranded = + | WorkerEntrypointBranded + | DurableObjectBranded + | WorkflowEntrypointBranded + // Types that can be used through `Stub`s + export type Stubable = RpcTargetBranded | ((...args: any[]) => any) + // Types that can be passed over RPC + // The reason for using a generic type here is to build a serializable subset of structured + // cloneable composite types. This allows types defined with the "interface" keyword to pass the + // serializable check as well. Otherwise, only types defined with the "type" keyword would pass. + type Serializable = + // Structured cloneables + | BaseType + // Structured cloneable composites + | Map< + T extends Map ? Serializable : never, + T extends Map ? Serializable : never + > + | Set ? Serializable : never> + | ReadonlyArray ? Serializable : never> + | { + [K in keyof T]: K extends number | string ? Serializable : never + } + // Special types + | Stub + // Serialized as stubs, see `Stubify` + | Stubable + // Base type for all RPC stubs, including common memory management methods. + // `T` is used as a marker type for unwrapping `Stub`s later. + interface StubBase extends Disposable { + [__RPC_STUB_BRAND]: T + dup(): this + } + export type Stub = Provider & StubBase + // This represents all the types that can be sent as-is over an RPC boundary + type BaseType = + | void + | undefined + | null + | boolean + | number + | bigint + | string + | TypedArray + | ArrayBuffer + | DataView + | Date + | Error + | RegExp + | ReadableStream + | WritableStream + | Request + | Response + | Headers + // Recursively rewrite all `Stubable` types with `Stub`s + // prettier-ignore + type Stubify = T extends Stubable ? Stub : T extends Map ? Map, Stubify> : T extends Set ? Set> : T extends Array ? Array> : T extends ReadonlyArray ? ReadonlyArray> : T extends BaseType ? T : T extends { + [key: string | number]: any; + } ? { + [K in keyof T]: Stubify; + } : T; + // Recursively rewrite all `Stub`s with the corresponding `T`s. + // Note we use `StubBase` instead of `Stub` here to avoid circular dependencies: + // `Stub` depends on `Provider`, which depends on `Unstubify`, which would depend on `Stub`. + // prettier-ignore + type Unstubify = T extends StubBase ? V : T extends Map ? Map, Unstubify> : T extends Set ? Set> : T extends Array ? Array> : T extends ReadonlyArray ? ReadonlyArray> : T extends BaseType ? T : T extends { + [key: string | number]: unknown; + } ? { + [K in keyof T]: Unstubify; + } : T; + type UnstubifyAll = { + [I in keyof A]: Unstubify + } + // Utility type for adding `Provider`/`Disposable`s to `object` types only. + // Note `unknown & T` is equivalent to `T`. + type MaybeProvider = T extends object ? Provider : unknown + type MaybeDisposable = T extends object ? Disposable : unknown + // Type for method return or property on an RPC interface. + // - Stubable types are replaced by stubs. + // - Serializable types are passed by value, with stubable types replaced by stubs + // and a top-level `Disposer`. + // Everything else can't be passed over PRC. + // Technically, we use custom thenables here, but they quack like `Promise`s. + // Intersecting with `(Maybe)Provider` allows pipelining. + // prettier-ignore + type Result = R extends Stubable ? Promise> & Provider : R extends Serializable ? Promise & MaybeDisposable> & MaybeProvider : never; + // Type for method or property on an RPC interface. + // For methods, unwrap `Stub`s in parameters, and rewrite returns to be `Result`s. + // Unwrapping `Stub`s allows calling with `Stubable` arguments. + // For properties, rewrite types to be `Result`s. + // In each case, unwrap `Promise`s. + type MethodOrProperty = V extends (...args: infer P) => infer R + ? (...args: UnstubifyAll

K0l9-vU(NiNtTPnyjuOx|58xMb9lc^XdGb+U@J&$?@1-DM8JKp z7s+gWgAyRt4|fIP&{b;;`w;1MTXqCbYaMx;3iNhAniPwq>j8leAVr`J%OoXib0#wi zG=|H=?BI;>nCb(&K7p9!Oz~sOA%MyGaF$#O7}zS+^}y*cC6ln(;nKoN9KuISO(h!| zCX)1z5X(g`%D8T`)UUXQ|DdfjnAfmWm-;p6<<@FU+SgvC|Mh2_Ir~bRm-xhB2?WvX z+I>XR)hL`bxqSZz!ewIkRH?eoD#*YhdGysazrGO`PDM)QdDqi+%As%GC8JM|8dIcH zJ&dfR41N++oD7zQ#~_dsiHXD-L+WgI$lND9?Uoq! zFXI2$G<>&7aU?FQY2I8n<@yqtA88+^PPtd6MEfo}!1Gsz`4}jf++~}u)CZ{df=foU zWKhn@_R-Ql8lei`$WMr4LrS%iGJjF@tf}huIDTv`L8kl(y;;Vvk*ifH_0DD`OlYo) zV&KRleo{7{;t0itR4~a zq2rl13?>OLsaWuSNJrp{O6nyCAL zE)>w>pxnuM7XI1H-Yq|mrCq z9{B4TOy82b#WLkuAnneWon2$@7*yEa*XDl_fCX(`Yqe`+cD~6WiU=L+J5c&5SBKJv zt6zU%Bc7YmVKBIYkE(2q-7DTC&zLkEIJi9)aLY~|`zr#@)-Is07Mc`yE~Q37%0BYg zB0oeecU4hWm?jDDbhRv?P4}}zxDje%47?T+A}c3<>J^ldafA6-04YiHnQtP zYP^Dcd;!x()OqZGoOE!zv-x|fwI^RA(L!T6;qCjP=XqkzYGX!KMV~0X+KQB0~qcf|ZQq z0nQID=Yx2vEo`08O4_#@7^(d>jtmhrKuY-9#PDf+I26k$3K$%8?R?)zG%H$W50Mg1 z!x$B1%3qUOQ{8=f3*~dcirij&PkRxNQ6=J#kPXWAM6Jo)JHs<1Im%YR6|VIw-ev!T zrf$nS#l^si1yL=osq@L=6WhhZ>3U48&41^YJe8}T_&SKTNxE$sBObHQpwGVvl&hG~ z29wv?{8s+=`lYu{dL9j#ei*F9$3+n@WZ)^!5Gn*F)y2h6oySIdhV5LZS1f+@Y#v7{ zic|r+QC!)IqLtF>WVWbeBbVIqqN)U&tI%65dgG^c{B(fG7xQMl538j!MYs8X9$I%j zkw4kjia$CjU-At-DMvLAl$x5MhvR`GdV=FFeJJurF6%Xev*`}&GwU^HVNQkice(4x zl!^=?O+zrU@3CHPmTOHAwb_7_cv-vR5Z+tLiWt#SX^17iqTyH#Zn2oL%GcW!%Art{PhX?Z+;5}fF&jfbO z6I!H$hs<;&z4=2-%{sFSiG%?GVk}>E2%&5f0rzQ>|1(H|ZCg#axv-%PtD6%Kd;Fzxg3oO{{^`TbQ=|%fo2e*1BItgL3}3WaN2E3)_A+#4ZTEy`ZWx<X&e#yvrPJ&P!(y8U3G;KUa4(wEx+a?37FBXDX%$t54q);o|Th|*IwqJD; zwUsdG(iM$%!+WZ=Z1NIGW85P-SgX=azHRbIYkG^>)b?b@w{?Jb%W{7$+SPX#!N z$R^8Rxk*)TSgRj=s~$U4AUpF~%Ft{v*f}p0-s0D)i1vPVb@BpeK<$<+lGAFuKe#Q* z))yuwRz0;+Rq@S$2Vuh|rue_S# z=>*MQIc&_p5p@Z;#O~dNA0H!Rv+{HG<0Y8>{NMJ!5_=W6=u))GSG;nCFwNl~$;3e( z^d7pPB)@ zO?e{n-6ydNs>EWNVj(4T88AEA1CvibQ3X;Obyx}7;Y-?$_tm<_H>wp!&khN!=|!w3 z-Z-iU7d!nhTP3zr`wE~ObzX`mFDbb7beY%u*uH$F?GGE)VPw|yY&JPD+UAMHx5mb6 zST{BiYA_7@13>IbpONOGT~Aham$uS(!tE|^t#Bf0UtOlu6ingi1LBugYD*bi6e<_G zPfIC(-D#NQyjEjY{g4-k4?EQ&r8&8~+n^w3(q4xWt`9gPe&bW}lLc+1RL)=lmEMt$ zA_5hU_S&wj(O&8$mHZi?m9r>nYr2P@E>fP)J>MFfwaynu^ZAAB!eE=V2g`SG<$;;s zV{x4XDm6OChK(TCO7=CYlAL&4x32dsQ;8?=k^&2uUBUNc>6)P%?rPXbj$RmZK9K0d z_^WYzQ{d2^%IgFLjS0)wdjcLlliT2oc4wxppzRwfIcOVR2LbNN*|;6BSbkPc>35pf z8!Yy&@)@?aEUC{3PW<6tD8W^6;@`HFtBJeJ?$G-%+8q@IVm7)@4}K5be|bmZ*R&yW znYe(UK{^6L|BV8v{u0A`_A&D@=Zj*z7mN?ln}LzCIvZH z7acThci}D(jyNHoJc`j-gtkb2o~F-9@yFm%zk@X1^|ybO#e-k;FVqK_y3%Y!M$0(B zjH@2cx4kiN>%e5K$H<53pP$C;4jk&PSTUC}I)0*$CHtLIF4R*MTHs#b#N1sNHdo@1 z-00!cTfR=qnNGvP*xAi}M)xWtWBahVjnUKUfYqMZ;smKbHPxk&6MOXMw}ZQzYRfmY z6rL#5yEfg1X}p*_lx#!crws$@z-<*3ux->^DKy()WC%=Zly(p=;71-Y#v&i~_TBBC z{X?!yf1zGf0gc9wWH+%O%WK=&CaBN{q2B@Ybela4nOtDMr}h4&Sdq5o$U@R@EpTZJ zIA12HSld&*^3Cfk-}5DKW+wK>@0_|nA?WkcDv`%I|qcL-&4f& zUHQiOqH2)*tQuUISG+fIFI+V<0UVSqo6!=`dnJwy`vqtS_jok{%5M|n*^dPE zWAyrJz66R>#yw<;q9kXYk9)tgiebw$`dOptF{ZjPrR4c!RCIkN_0=7Cf%%00u*>vq zsTW*_!prH>kf~h#lTa!+4%mE+IlCN{e7-VbrY}t@sn(bUoCQ2;*0}$qj*5;w1WZJM z@o&t_YkG~!TfOSYQ!312>dpgWnlqvd^{5J#M!4PLJS{8X$kdBt348FM`_cMh^dFSr zllkM(oD=qv%0*DpLicWa!w2@Cc!zmEElSRYE*r=58k~tCn@2+jg9HB**m51Msf#VkfiR zWxf929Ai7B;D`@eK!0)}>0K~$;H9mrH4@KGJI4&o!PqvzMM$B_Ux3I!s$WSG6(CN+ zy6NDKOW+JDlX>*|wn8mS2wSheYc9N&bvL}e$v&UaU#ook_|TAcF9u6KT(M0i>@cX` zpZ?(p)w(olgp+puDDz3z=2Jy}mgXGii=U-hk9+40LbCC9<^=CUE6HN{Z*!PRJd5H) z(WDF9v4Vcz_qYIVlQ5&!n%$o&JG-(uxn*!svUn)_gJX}B;gu())`iB`HzyvwaZAz! zKYkb9^d%|7;BjdwP_i~4_GTN8^^ckp?ZqFD|A848km-lyeOvpU=}|NtdsGqrz`Bbr zfK60!M^}CaCdI?~ne&KB_nL{_ERn*#KR8Rf49?WruY_9H1C2)g$c5vPPj1(B332T# zt@a-Sc(IX}1s0X9Qf4FRx69oGw4drEX!}sv8~WGcmJlCO9(6wp{aKxdVBN0uGP(R; zBeRGc%De@pdTGSOjaY$_YB6fZ9L5Mq%yEw`gwY<4 zG>QX+(|f#yY%&aym<>M(K%@?F=|4;U({%0u zM1P*8G^?Mgkqxu)FxK92z)TfCu&3mMSSsW7h#pX4U0=|*T>v-?NDbNtHW!r1u!NQbsvv8VH>aj&NzK$@mbAb? z_;mB5x3gq}9_T~X0DMK0*&#T9XWA33FZTEeYLfTf6OMNhVp`l}-RK)|=!sezZ_-~)`}Phk_<`>+~_NR+QG)OxK@ zGB}D9k5rO?JD7=`!BIZMH7JxA?LAcy4QtdAQ{~X!^Wwe$5)p4BTw|X?u!)8S`odFX zMwImB2*ZD+(`A~=#I@saB5-5!Wk+f;!fmI)s%Hbah)rpsvfs_f^i4lS6FMg!LS?}v z&z$64FS~3$k-rS#im2*_zjHt}v!TBa_%=PP}?Jr_$g6@}L z^mYorBh>;x%ZYH>d<(G2t1|R|GP<5!g;?|#9bgW+Lk2~KQx>j$0QcyGU6^&eU6`|O z({gxt1?``vmz|}Tqg#hl>aL4^plZ^@WORmG@X ztiPP#B7g<=cSp0UYd~oU0w=ff4=s}J^>u;^jor*-%C)H57DecK*PC(*zVqJp)vY+y zp6Auc7XnVzoqBAi^WMl$>%RZyK2N83kw!IwkC!cKcljK;Jo)z4({+^@Ke;-_7Iwbt z-@NFj+R9&EsBv1Mv;>ro^9yitcW{-&mC1wc3Y=crK%uc0I1&DM^4!#;1j){zWvRng z+4fp#QeU0&FWk7iF0U2xKBtWeZt|A2>YX^rBUTZuwvgMblD`5P{P-?y?NHtzUCWG! z@6isV-bdprxUT&@tD^H>_IA!6(P#auVW;0+(nTrfySTxNj=;Uj4bClBhl0uYctk)O zR0(YYXK^_R7ZfKg8W8OWA~T79vjBc3oJZ3yNp16K-5|rHgD4c- z^ud;W-++Yp_^mM3dk1t9=|*zrDbW61pAd6AH$N}tWMIINrZD5aLh=WW$Y|2BKXX^Q zL~08fegjczZjSR=kJjS@EBv{KyQ@~{8aejrs=1ql<7w142GZ7>4ELA!ynU;RJ5Y4l zOkghH6PODS*+`oQ^;84eXGliR>-)%q>ERrk>bh)-@1SqP$mj2Jo-=4&VkhA=LwO&+ zvxUkZQ<%FwsGMr(~8KEfuC*d-e=dNKLcU+$H+wD+xNw)kevEUL9Eu`egj_(2Gzppf^;adG-sx1d7a&Hh4h7mXLafEOzqeuor< zsAz^TYMEdu^1&_7yh~veRc#C4aPgn2-^3e?;R=TL$V@qECD2EbUc&j)5_#@tznI{A z(8-%V(kij8&2@lTsyk;<3|Wf|hs`Q~+6CJ2fLWsGqqi%7h`&#^lc}OS>$`ZkdOtLO z#cAcXjvI7LTde^QII(j{o?*$=-r&|fkw==luc{9xihnG_6|!-jkNbBPH5_21CPlS_ z1xYI(E=?h$61>j0%{T_DydSAMA}gF!`Zq;+nJB23*IvHH`n~?jnohKHqf5vDDCC|T z3h94A38{pk_ghOTh{MpZX5p;|{{{+;MIioKwV!-#O2?iyA3TXHel}2UMF(X=4&-3U z@}tLPdfRzN*`JLA2NMx<<#Xab7Jkklk1Uo9M{@J$WFiCn$1>~h{eGq%z6@a^{g{1? zCjNPxdH_uMoZt$z=J1t*qW8+olc+kIKQzK9*~Ayh_7sK{Rw)^w!K}@V>M9}Ujir>o|*Si z5{|wWJdIiMUC&S07;h}Up?)v_aP{o?NcCwr$FIcKiK`1{-D5o|$X>~)9WNgRSmJML zrlW-gtn-4=n0&*)efjSp^OE|8-c#=}IVCU8<*!*z4CWhDlxQy|c5Vj-5kFceSlGgu z8u95=IpJc0&an(sS?srd@j(yaNHBUET3Zr3XDvQ&u%<>E`Bbi}#G+yk~0;mFf>Gl6M$o7L4ui>94eVe(r9?ORn$jri_jM z4&+fJ!DL#!cv5@xd&22r@{kKc%T1SWTy%eqc?XBf9Y+i&Gg3*}n3ToT{Nnns7+F_yMFuXuFtKcKE%RiZ_-<}9w}T+xE!h7LbI@Au3Gyo zjmATlTX#OtBjunN#tLky>Y`YfgE{}V)LW+^P{N;tvPUCj?~lUSVu|ceRS0k75)tdy zCS91jUzZN?z;7uvTHz1%(iLNWe4&vgBF01WY9|Bl%ZC@`-{_0p+-l9VlDNkAyN9+f89;#t$BJCeNvv~ql2XFM(Vz-w@yJ;pr zHe}u-$-7c19r3hatm<=tvd#c|76l(0#R}H=+WKt3 z+3<@VQ*jEbA(=dq53@P&l95S#KATrdH?!s{Hzp*!(sr^jpRVNa`b<1M-^7v3!hbg3 zM`zJ!OTB)g@o>Sn*MRvBX&_A< z)mM&U1yY(O9ogEOIcmScD#G_FhVGJ7Y<7>Oq`#qdIPLLPq=VgVibqr@w}4SlKi)Rc z{XN_-u>*xezg(%hIs#jU1%%Ng!&m;07ju&mj0!&3c?-?jJf|3f91`K3UA+)eM?XK` z>lX?C1pfW`^=Q!`oVaE#(`$pfa7fwR8n*e?Y(%g{w@5lzcEDMOnK->pD8E2{BjGMszlf#mo7vZN9B)!Wl6*~H4Q`jI_N7G#9X3vKU%Z+M&hWxvK&h(>H z&fcnEGAWC5?v*+BYYD$^I_Sy9yUao`@@aYe_ENmy+{a56CDe&WF9K@c6}I0nEqJZA zHEU6w>AqE6cF%v!+wcCE&6vP~*c1M}u5y@q_o@xN(%>bmA&<`>z`F%07bjokNbz(I)VDNmeHc1|3RJB5d$IS4>vN9^+ z`ThCK+NKSGVU}LCT&_9h_wU{*U8Z|IC05HW<1-o?S=Dw?S}T&Tpm4GC3ZIQaF3x-} zt2FKhY^?fEx%ld=Pl4pc)i(nE+BN!{3b_XfwZqo~{3L6fjeS1pQANgQV(;T5{7MAZ zZY48wsT}QuVE9>x3|$BB%nXol)x zUs)X*{NT`uf5q+Bz-dh8utrmX6@bpji^S9qUgk+|>36ADcp@=cUw^$Rq__|H2zAq^ zH?Gl%@u7y@%pO;JbeP&DY^rx|8JYycBM{Fo$tfua+u0o96gV$zCP+v%1?l*ll@D=}t|Gw}YR(QGg!1KDU>59tz@hrZKrHjdLx?_@)3!U>}48s;%)j0WHtJ9zER)QSN zPXdfOqHpZ8#@pXnrB^0~qB{^$bBC~0EJ!wLWA5D#^PfLZ$*wvXu&u#>cI4{h9&3h~;wwgeta3if zmpge&=QCD?(w`a6Sma5wC}RsVVA?~&74oWv?y7^q1nmB3w9<{CvG!^Bz*{SDxMx;w zhBa8lFD&r{f&9O9KZ(O==E!Vr0}DUmC=IBok%!y4Y+>RvEViUFRATuT?yA~lJZ)3# zk>OXf*I`CG_|Ty0^xW#m1xwnIJw}Z$9B?cH7GEqE940&*_NDEsXFY#(_Nt)y4J0+& zvBB;}RG~?GzZuC%s$?WgV$R?!lz!~s^4#yc|3t?=ikcIvUHzOkT!i&rc+qc>&*)f6 zXFsLb>b-TfwCw>-BKx`IX1Ai=R!ark4(lf~u=AQRLlu^YS*!9kobnsJ&Wv4J#wa&z z#)sUC)W4Fb$AJD zR&Q4KqIlZ~++g&eTlp)V&8cF2wk%}BJFR1}$uFe&?Ah9zESDFR$p#9%gd(lVBH>FTolX!Hs+51u=m-nrxt(RVSnpUKgO<@=?UlFVh#F2=N3)B z4_bO*Z8{Mv4mdPpw$V}0y_Qg4e|+G?bbELaq@wvbZn0VsI;lkJ80eKhPeDu?#zVvU zvo-7I!vvT z<+&xrLae`ZIr!XNcg8w?)}Jn>rIQ2Z0)*2y6>o^@#S zC8yJ!8scGpfpz3znT+JKY-EehD_F5s1(QLZJ#3?s|BBO^uD{*;#~KlMuc+pM@A=v! z@vPE)mSplW=yu~<>j8F*&*?Xp7v&DD>6^C|9bvl(WIf*(%YjZa*`j-AJhVLE8e}kocGYS_5Jul zZo?gK|68exIu`ZlnPJH*0f|KRo9^rPfF%+rEU{dECCd35J}&DXGBQDS2fp5UQbr&b ztX=tq`AhK;h$GSj-^9#@d?E{K0r^t&(J=| zT%;v>+@WAjHuY=k-}aY|r1_@-25(o*l}|#Cg%3NNRKktpzJHFd>=kAI!eF#era* z?6z2fva8z?ONLgad%5jB5zc_mBl6kuu?qcI+Xb@kH85M5NyR!o2&qH0GhH6Zzbv{O zjPR#7=a!*uq_Mi5T$|m+nrp!bWl#kPbu{lI`M<9bc(Ncvlj1b&o8^Vdnwiw*0#r2z z*0}`2Z}hHpxlZ3+m8jQDJvR8&e0Y=OrD{G4DKDqNP&~8#75p7Xll#Q_RO0?N{r#}g z-+hX?UxxkH2YcH z+t*>6Y2!AgkIMybD%^M|S8IPAaq9vlO`Y3A1$kiPl&g@Ur-OYd_EU|0SU36`PvlEp zCfQGL{W**~isActODOv+8FXlOxkE?rKQ2jxeAs}l$Uv@%nJqKVLTsO3qq!PQbiP)$ z<6+=GvO!=RZKQ)|hgc$dS~4HQjY`>fEoiOcz<8+i)BS;U$}*PviEBwj#DjnOdE#{& zqFFu|?DQm01lQuv_0I1LB-}9Fz4TNo?-6UvZ{BPa?aov{{P>^urB0?=zLQsX4nu`5 zgm_hdZVUsD5Dk2mGP_m(uTPIy5K|51TUo`3++cmydb(BI!A!@h{2@Q<6;N%C-#JHe zQr!}uj=@N_7Wt%B`faBvQz^-mU0!q6*$7%_C|DNa!e!h^33Qy+>e?Z&X&5J?36rTp z3x&s~iLg8M(Dz8(ophtXYj2$Sa{ytY>yMNp5`&lTZ**Iyu*6lHZ5VWI7g&sOS8O)@ zde$_2`o4Ve{aH0}ou|Wzv{t@zx&*f4WNOAR*@};0W+o=}<&-7r4dTq4mTDH_$xA|rRFu=6%4+aUuCPZd*P+6~u7+sTSu!;EDsR>7Z`SN@hdUZV+!x-+*2tkN zs&;e8n8~KPwZ1MGNcu~jpBcK(n+w7I1xiI z7iHLELV!3!npcPFG%NFwiD5ASyTPtVEN@LdHfgD})d9s^s?d^1e|!N}`RG(4KO*-) z7?FEdKdBys=#46`3T6$hI&59uDGL$bTn>GnD5>GGR<&l5xr=WS&2ukQ;GsKhBMwc{ zl^e~L*Ll`DPl1}8PnJjwWAUr)Uj<(c>hTRP<29lD7xvli@xzJd{w04|b&&j}xa|vq zA4@t8->1+fo1iO<$|FngQ@B1iIulAL8n|VrMa5*ixe&78MSj`XkI=DmP4QN~T*fc# zH*P&VUyJ14>ae>$vO8nOcqO@@?46mlO_&rT3 ziKA5+K@5|awLR8W>V1>nIg3`6!5N2%B*7XM_HUyySif)?R|5U%9)gHp`(M7TziO;q z>6YGw+I_qr8jcQ?`WqCoePju~H@FY!w}TuS{2ls^_=!Io(KVbQ02ihXQ#@>+GGO<$ z|04}CsWWW~r#-*-I#o1c4{JX}HRPV@{)7y@WTr+s9kgG}$dkOzfq;*!g_F1VckRC1 z_xgqZBO`!UV-QA93%VaEMLlyLYz>(%{C#nZWm>C}`?7roR?m{|lOq z28a&ST*eu~{vGF*@|p;cviRR#lNeRt&4}K)|~40 znh0{J_KL~N!9aY?@-T-jkwlP0(zH?Bn|Cs&ScJj1>((Gaj#2^lu6IZgd&r|J^7nzW zmaSznACxSb{|w>9%mfVv3^nrvfU0q6(e)nHp8-Z2sz5b?+ivM>z=ae+So!NSGycs4 zVLYBrqwX_@%?!H zEchdi+_KQ#kMt;Cz7hN7vfHURo&C&@2R4V=Z9)^Z@>$Q}+jGibXC_++2FR-W1vh#h zi}%9TcgUQ@dt@ctdG_YB6LiFT*Hh=hUjyA{D3nJJ_yVw?_W5LQu3doz(S8~u$Q}4U ztk~9&l}GQE#@Z$U;Cn69aw<|9d47b7Ygw`76zy^p@U*fF)SdH{@wD<4ZheEHUxyBg z`_I4zypow+KV1W_UcX%Ey+Cb~fi18*zt?4%zlZ{|@pYsf-+5)A59SGTX6lMh_q6&BN%Bca zkQo3ob*Ozf;25DtKFq-g^D1om<*H)_>u_UXD2B zKtALw|95A>)=^xO-7bqBXkolh4B>cs$89ql@q;u$v-XPbT#>w~IFy||QXXTT;k=W0 za7TOQE!REvkBG`t_!1#p0&+&Y=j;NB^3iR9Sat+ri|nG;n3I=tgYrzjT~v53PNJWU zSf59^-~q93O%kD`I&}{= za2ho|8mc=37l~oUHb5p)M2@u|q65uXBYrLQ6?EN|k7HNYB=!hIA7;77pBa3>I4G?# zsl2uNT0yG#=EKEtdU+pJjFK{sKGP}cO+xrwX2k5gkepD9H;T5Cly1rGYL@3|ZkFes zaEr7(ee`U|<;zAeeYgA438jcDW25@FT}XXW=+I=EqS3z%B|_?xm5CM59k8gBseKdX zJ3UnKkyE1|(j}k?n1H<7pzS$g2a4O|Bm9*I8pHZ`azR2=r);S>l=m&J-O8eXM40=+kh|tR z(uDY6qh$M&Gdx0o}EL=vn&D;OWH-|nC(CJsoUfRl%0mJaJQ6A z&}K29D~+b^k;=V52&MXhsFdegxIa~<(oc0kEyr%j$${rY_W94(6^W2Hp@aK>5?7zC zDfgnSL+nGA=&A7D2ONmG4SEy5zpk&wo}3EDc8%Of#f=QHx&!ug@(<%Gvbn?d@FMl~ zE!&Io8AZN_-2Pu|L_OEZO96{jza$f{n6eESYa7($xc@*t=e@qiilLy1Bl?d(3?sp} z5=j$IIW~rC^4At$l1U3>)pP~AVOx~(!TOglx(1~k2Zo#xiLI8hE5w7g6VrgrJf-s- zkN7c>9}8x9Ck{6IwAW(|Mtja8ac!*Ji1=>C6rul;YDWhOR*wDAs*ILMGFXV|Ks7X^ zF#m5yD`oSw9LVv`A8DElLGC#zT+fq!PptlQ|KZ0(YtS>`mlYxf2=ZuTyZ9*4-xh+I ziLiVvMnIuS4bCeO8(Nfdv{xPC`fKk$1i4?sJ0d$KDgE>0!hXH-W>i&`J~zlExw zLF(rY>)D8g4dl*a)T3*W10KR!@l%bylB7M%0uFk-H@3U`}d<^ioyXV;vtm{Bl zIGh!pTKhK(Fi17bQu>s9$X$8`;AV>}I;H(xc^cNyYY=>WuI3sSCqnin*)jJMOCH_3 zc)ekZnbV(qjIPdYZJn9&ueX9se)?a05tCN&N84cGHUR*?{af7QRC^O6W`lblqEs$-YMK+PVGVk zv_-uCPegpm;P`146?*Ssv2zD1UVcSGputnE&t;Ur(%a%b0uGEkre-v^_@0ca6UXL) zG;9c}iMfex^4@_#@?n+;lVJ3K-51vGlL~7U&sY6jQ>DFAqrq*4q7V+job)cB?_{NU zN4X&qUQL(h3aT{;-O7}F!T6Ibn!*kNJ+8#?4!gTeA4&giBKYys#OUYfU?tOBs~)GAu#r}{Y z?3At`9RwPrn4-?15C6^gR3CyFEgzd_IQ}7!|K>aFY9Q!}GJwI)bY>9xF%SNi42ekx z$Ob8f^+;ImFVuOl?lhwY1xWQ7z!q?F%X1)PCxJDE#L_`C)>8#61Kq~;FxTmdr;Re| zm=Z$#s~*Pv>J}~zi1;u$uh}Y0C=V`ff&HzpXjTF_h#x5z;%GNy66{1i5qyR6!yf`t>%hg}jpSbupZa5;TKjY)U8fgK^+NibZ5bP2th z{u2YP;EXfRGr!+rX%x05A2RoU5ofV(b5nu$$;RcN_;Q<^i$E7D`Kt>ps~}V1bngtUO{8Cl`JhZUHF$8wbg7f@`^wl+ zhmt;P>wllnFwPyEmH&hr8Rl{i{+Is%Dq_RX734X?=jN_{6uV4-66X$Edg1~CE1zvH zl7St?i#OOe@W_9b7 z)h$s_`9VjVSpjp)0?T^!vwa*u@^j#5=V_QZvjOGn=KXfl;?;+1x%rvg;3f3&+O{WY z*HTH0n`6*buFa4KG1u}E26j+ZkoYqPfj14LD%;gGU@8pJB;}-zUXmwL0lPkg1!K_N zb=^i!bo`2AZXBpq75IkeDyVvgOwcFc3jRnc*&y|>-rVO|yVR)HJ95_nPJRn%@1b2L ztV$pO0#YIYw?_bO-9>3Mn0@s$f){R(Z^lF|uY5&~zW<_c^t z0w2rjJbe<8NB=PRZEqc_?e27s%+~Y&r4oO}CY5QJ3z{Z_XS?;l9=+62y zVE1%M@q`5^ROs#*Zr-clu1fl^%ym?&djQqWZ3l0R{v2hXtNo*GYV2~f3XxbcPhH=M z4H@pI&>-PM5&xywp=yorlL(aM2Y!cD%pIJ}tw&W$OS-DO$LXtv*ZlK1B1ky}M)yF} zB<_8n{m|ftxwvV7$mQfTb*-&Y!@z0M0ZX|+JOhAJ0U#lKoojgl0@@9$eRTZZ|AGO{ zRWCggL|3ayBqk~5O{f;KNfUw`ODXJaF(MkBvFIA!o&t}apPala7aP@V_0sZhfiX-pEfAZ;zQQzz-lT z*0)>+3w;Rcbq^p$?DK5m_#m(^Gk<6GmT(&nV%%{L2ZyC3@G z|Aj1rWSJ%siJg1Dlj!;1bdjGw^$}T3c#3>V0x8Ku*nXKBPksB1x~$@sS8C4Kte%?Z z0hLWN{qVL${U`c5x3PQ7e^rnvLWM+u-et)7iE2}r?%84Pr27xnQXC=h$?$e-K|lks z!Zz8S@r;)eX_~;`&S2H5;B5#rgB}bGsD}2^%GS++2df4LY;`Vug*zn3OKXn`2dPZ+ z6l;KQd_0c=@BqY!Codd_s7KrlwNoMGr>pmpF03zB3T{^)>D10O{P^?Gp8PM2H0c8# zV51jj_UKpeb5i?|4HotW@AveW*8Qw$f-{}Csk$+8p*8nj?c(cZ`DIc18v~r`7eL@P zI$6L-X)M9gerbVRRtvbx#vb{k#{sFs+T2`eC;4ba04J&AkeJy$0AcJf_Qy~H8JU=U z9DDAJGT(|`?XWJNfP>$af;DS)4@(=5e!p);g5~(EsgD~Qf*JOY1ul4Vmx*yDFT_={qEdB&W>wVivK$ClrtpWpHcLhBv zd=gL|rk5JMDYV$Mx5V;F^h>Ohq)DA$x&3K*McAbgF{GR}rc_!rR-x9(T*qpCO!Vx( z%>&-z&)~>X$96k_-b-5M;!PWB6p=$=s+6~ABti^iAMddXI%E*&GXbzfpGx-47IDB8 z?EJJ09?{sv+MaX_7Eo)&;_UAt?50IcH z2iq|(t3wTW3cQN7jNYOaN~#7bjO8}rw`{akt@rqR?Z`(b{U<@MOY9jb!L6DgFY+UE zW89ULj%>AmQGL1PbG#kUGQ=tSOMUy{rOk4u>`_taCrr+mq*(HVPaQAagfxNF@pK#h zUQ84`5YbNRnZD7FEYknyFF*ZhpvfQzmlMkuKaAMjZkLKTu%N3aNY}d$KgPETBNya} z#0nLEeJA|2UNULjt%Sj~pJh9x za+e61M*yzINt`OFgP)J9g2DFRieSW*_OHPbMbElQLNG{aLs5b!V0crA2T@`PebSQ^ z)mt&WyYp9e_bRIQFcR7oU!mif^nct4I|IfFEl1oRsTAi~^{aOjq820S>^M|Eh#&9Q z@yGr@6pi(6CUrb;&B$X!x&yb-KLv!_9I#z!t3u-7_Xy04>|XMjTTV0CRGj7tuwNo7 zyg+0UHpj-QB55s?It#usIJt&ENAE|0_NQ^a3@d^Bukv?@BXC}FlF_(N9v|Rw;Sc>L?-LPoAbwr>U%tvTIyzSHn&#JU(3jl&R92Id&z)Q2N|7Pk-Et^m z5*N9o(HDqOmF6h@%Z!m#0=A&%4z#gy*$Se3sV6{%AvDM5j-(4`nCG@kG*5+7{h|Bm z=HFIw%uGTl7=#>ipThk>0{h~B3C423P5+;mOEA0=KbY0q{(T3`b?mZ_z`1>{A;}<;(YVmgMGy zE`dd<>kvy?R%U+c&uPmius6!e&<_sK(J|GpGX(MfujjF+KvW?Zk|_tyhVvb37Vxj< zMM94EgM!mI z#Ey{2M2w2+%Qk;d9vG0IfyT}7?C2r*%YPF*LiWRnM5m{i!*fE}9==Y#X~eL(XhU!( zY3XxOh$Fx(caP5W6GNU7v~c@7#rbdVEm-TdUa_AB1?Q=ivSJ>vH(YcIoO3P(ueH7~ z02(qS#9a%1kV#ok70_FV+VHQ*TR6DGXm4=aDj3B4zvZ!uAxn&=0ApgkSxvi)AY|1G z5EWVW7O=nu-`#mO@LE{FW_ra{^}VeFLq95DItgU}sz9$UDqyAe^`3KSxn={F%7#We z8OT<<&PPSBRQFz9qy0N!DTiNrPj!sbjXeR!h-mZC034Nq2#y`yGiqPM|t*MP!OD|4FUG8aEfOlFj8m; zA{ltQ>bF;^`Uam39z7;8>^b^uZGU?>rSA%agK=6P3uCULDU0wk%3BIaUrJ72iY0WY z{@cO2%6}=O`MlBweCgsvK6!Q$;A+gqoj^wUKjPR^;C1JEB)j|nQZLEe9CYUI9&If4 znFP-Qt)oUAiakI7K?7#!r=k)_rS|-{3QTG1TKNP53AqDFx9meC*7?*^_F(f9f==R|G%CPsFsyTv;0}#1e(XE0!L@ve`4ojrP`P>`xGmue|0yu!5&tj+Lb$0UJ~|2R6vX z_Ga(yk!I^gFDren0y{gz@a(|AlEB6m(1)(O(Nc{q>rYi{ew&eG4 zLh>;pllEMnT0Knf{cKPJd%h%OWUp?Av6KC0njH zpf@KZxxdS+b0O40Y8Bkaa(Je4`;9mey>63vg0G*J>OUrehWjEi(4 z{KsBk&I;AI6-4I<3K092o8d~!qNcVIp33Y-SjTR=Ck^GB^sHTvehc)D@DmTZe*QXl zoHfgUO)NY(MBmMASeF+`hEbKw;5F`c^?P+wfPsi_r)=G-cWat=4+72G1@QiO;d0w| zrLY>Sx;4e`kbeaTSo+maBCNx4sp)wiV5mjp^B3$isvr_Z?|8UJfY&(y_umrc;g>2! zj@UW1Bl=$n7?U||+!6_0tp42l!FopA+Zsm6g@|WlO$3jFRHv}5Ub(k3UOLsaC>0x} zVs(1UiKO0e3uvRrOzqo+f1-o1=`&RaoTm13K13Aszr`<;`nEVLriWZqEOC=WZtp zaR7zqjZoZQO~kaNBsq%{5nptTjj*Zg6u!&T?Gp!z1s)|L5KQEUF3~WmNo!M-^-QmE zezk7Sbf%O$OVB;`tkHqKF)mBiH@{j$|F4k?fyiKWCZYCao*}aR#SBdon#kez&N*{m zz}~I_?S&Fxu|Giv`9Oc!6V7B|PM(Bd{D%GUd&Ju*xh7WX^$G;E(B5pFGe{`If1av- zUq*G(aC^=-QnHJpm=+6~77Jb;S4(lh>errjp?`3NV$QnqY4uNB{My*en#T_&aTjEt zI%?CfyK7K7^wcz}cF(vMZzdhM<=yA-x#A1RMV`3zVcH_j|GTq1(V_^I4P0HKIIEm2 z2o&eD|36W)8<6w|ZV^mxygWOuXJ`DeJ8TbO-se)EziBT`g4r`%W}R{Bczq~-26oIM zN8)6;!JS4=Aej74i#zHxxswtK;5`AV!3oWN@B2-%Y{eoaz?KbewIii=`pt80CfwUu; zl$Sdk_XKXFbsn|b3>=u8tVc~C_v$rp*U~eyLC{^Q@I)bU-#cnZNu9cMZ7=DFRh5v$ zW!axW;0|{lOM5Mphr1^({74VyPIdYYc}hLSUGGfS7qOt|DK^HZy-rPPm3Zl{ZKGAr zLrIVHEB}En;8zSV<6j9Y**qD$c2Ca+_0wEU0n3D#2r)vS-w5S63}k3LAp-?G*FEjf zc&rxAqV_E6L%*Kyn8gHJMT#i!u9o6#Nz_?j_D3NhO93t>BxQ+bt6q)4-~tG1vTho7!`%_VXPzC8pS6{hslVn#6{p zA{*ci39ghtJkA)rxFvE+?F(<&K%8UwrC}2tuK)WS>IX5B2w4nRY4F~Dztlg`&X^cb z-}JibDBr7F(qC?DTs`T6v$!PiG7RzXXXn$(n_HCWJ}1lzvmn5*zXp9A_Et^7m|GR$Mf)(C`3?TXl_ zmN^OLs@o8EV?ogi*-w=qQ9Dvm&xrB+ZE<_kgRcgu5+h|XJwWmQiwMWqP*(tn3=361 z=qdQ|tAf_?GC(L=`UqfMBLEC1GqLJdfuAfYS)8xJ8mAnS3rsP^eZYz|A#8HxoN0_M zrPbXzRIpt-3qUU!VXgt3FW$~W+u*xQU{kQ56RQQ}VswGf1AHq_F zCE{1}B+E);9WJ(*+Mz9MD0Nqu=%e_lnco^Ep8j9cjDXTxqzMc(%s}MXxwFK^#wS-N zLOfh&kp7Gvoa_R)U@vOD4ys!LLLsmqOh{uZwG4P$TA_wZK5AIp;P^}gVh_?Pv@4Q9 zF*XUBhwE(Piw-Yok8=>@a>w6}hpeOtpFO2(ep)W0>q1Caw!Mu|62QM+?}H#6LMa6Z z)5(YDU1QwO7hPY{_&1(p`Om#bH=%-#6OiA~iy5@gyTCdg@q7b7IN}C&u0L7b9dvYu z%>`7|NLTp)$i~k_9dHN5FMz zhPbEn*qdpiut#bWdiMWU`U1{Xj!0id0qcpnz`cP|27b+7@>b6)**ZdTJ1^T$4dDRI zv-q7<#oXchEP{(xC*s%lgK6+EWVB5lMA~9^p=fr+W+3Jw!0Usd_*1jD{VG4UVcixY z)XjR)ih3n4B&oV)AtCRnuMS9jWcrU#5Znh^L6~{(c6dFD20dt`ED_;%M`-#XAYU_i z^qdpwzj*)540o?VNh}`Svk{o=gqGku$oPx6o%c5NTEL`f>k#eMtZVo|? zuiWa7g}-ez#4_rrEu2x2EJ3qBqBQMKzKnya?FUg^1-&8WyLtgh0=YnN_%9zLM<~EP z9FO?@AD_@BWRIWC#-I>32D{T%_c!b$ZS2s3gjU_LX3`VY1HNzu3C{VtIk40ZffGbP z_GC28Z6Qbi>?0(^^=Rqamt#J7Ap6)I=AQvom%fb+{u(X6ca{#_zIQ6@=G`fZ;>1`Q z)^`yBs5=v30kL2E%`3);C9A@C>4E04Zx!L&SebWLi2!L)}b=vPaajEIIA4P4E>;`F%69!GMf7liu)x`uo-ygtuiEq{oA>6-g7W}Uql)b!`9i-$SRLTgNdcAEcbH;5(w=LXKdbVr~m)Z3^< zY!Kr3q6F49+x(>kKplAzM_(=4@Sko?t)&sHk9G!_D{{^Ts6+NGXqjVLt-i*k?Iz`$msh8WYP#OXLQKQ| z+|ETzoN<2dB=Yl3LfI&$-+^N<4KUlFjQ0*$ubaSB1&p5U+zm&FsbP5DnAkxvEhriO zZ~FK@ABc1HL4(D<;zKOJdXnT5`ZZp|v6pn`bv&mPX>-8mH92msP@X5iK?(FQGcSuo zKtNUEad$1~r%@yW&E*U~=E>i%(ciMdpSJGdiKBC+j`*By)|S3c(gHT_1Uay!1U@_x zPf>d)2JNj3^P$}baXxzzu|&b4V=F#y7^N_v#A?t9DY+r(BH#*ubn(9g(BC%FuPt>A z=e3#U4J2#T(0!@Pjpg0%4SYli!KY(wC=3&!2?Gv!xfor$5{LHN{f5UVb_Y~0=m%zb zud~MnWUJEO83QTK=c_+y$V|zy>R*DY&m)4>f6Gb!c~y@F9D{vDu?iVTO^CU<{8?sK zh7zNZt%1^Q$PDF3q5&PcadR9NfMAPAaEwvxruyV5A9kkDRolx!1&64tauqEe{_7L? zU`6Wg-6T2RzyJH@&#mD$1}E24t zx%pYy=Sq0dhUlL~U&C&hGW%TDY?%4~N#FnZRH*EDzt|c+wb+;6FUFOJ<$Lk>ClR0T zcgnBYy7D;tkes2uI{*&K1QH&1fNsjMV-=*+)@aM=(Xa?I@xD-DVDp|e0I>hgl+VA{ zeC6vc(7^`nZzrXkrdOI6g4eQqI*40Sj-HU170{`pKE$GAEabwTg-WPrEto`YlQNO1Zs4G7wK0A)`kunLGZ@Pcc*SShdoR_O}PRRQ-8+}t1T z<3wkbtD8VY`;Ug=B3$tIs;ElLlmGrWJ|tg(*k+j$U^Kq!2Q*i==s?gM1-eX;e3we>qQY{9_Eq=*o-UZ!9 z;U(2L{5u}}#}*JRLmT!sYd$Ygzu%Ch?XnHp25j{iP6~nUzCLpfc(`Lo>yppdT6I}e z6w{x)L0a{sY}EkB6Z>~UL|!Hry7mbjD--7lgK99b!MSkG%C^WCyhgEqH%A~M#~CMi z66-*S69N`>J&s4j3Jh*n{kJ$Ms$B5ifhVf?md&BeC{piD*wp02m&X{ilb1zj!K>+?MBpIiIf zbUe`TAoq_@WVw1Gl-&ArZ3`xziBEq62oQ}GkZ<2wJLU-2{Q%M97Dtr*5XIvQ+9Ui4 zK*i9(FcF83ZKzJ;qaEOCmpP=EfHUg?&g?bj&zJg6@y8k{^KpB3{1zho^?GN-fVLb2 zpnF@NaL4sb#V=tz0I!iZ1-qy0^7=bSDJMg5osuKvgSuU>rlu;JF;wB=$GHmVo-%)v z^sG`tL~DHJ&*Dii1$eBlkA4X_4J3K6VCGhr)4;a=<1S?&8Y;8=RFad?aqZ1IMD~i( zegSV*%z6Jc6>2_2VYfdnxCmt+4FRYlLrdjE{R-_t2&?pU)4MmJd<5gQ2c&9L0OU(0 z^PjInJ5h!*saF1o9H{u;f!8@}3fxXFh_oapILcrxW@zOiP}cgEW<1KuP*(pVk9zEO z?9^&P`OBA5SWSFn1`qS?{x4Uzc=Ty)mj2QI&wlgJ5FeD<%82nFx%KRS+B9j=u?CO> zc+n9wz`j)hn@*xZ#RnwMH6Rjch_6Vg62A}=|GG`}#Qn|kR^sVs>?ktcbpF6Ba&j3b7hL2UwGgF5g8*1wqBx&{vKgTg zJGR@*_i24ZKciRN&Kjpk8_}j{0cX5f>H_#8g{JU%r_Zne$d>*GAN_KCo{Z~bNdd*# zj@e*HhnF4Q&}B5ttF&V<(bs8!CWhXlUFG}B^4D|2F3O3&rMsc=q(T?~sb?M!u*|vg zUVrH8G{{M`mQ9sVQ6T}cPsxvldS?_IT`7^(HrWcF3BGw06aV?*cnk%#4v_}?cM-qJ zMI-M`+zuga3$O%q5U{L4!0M&{Hj#^Ep6IfxqEfS<`S#&czLkO|o%Y-5k|ESWNp$LC z#-t~8MJO2j_*c0hA7UcTsQoj26L&FyBsw~`e|Ze4{#EQ4M#9hijAUWb3g#j}ZXD2h0pxzZUYqra?XREc=s#SmKNGIp^k<&x zp3%3Oe*%N^rlc6ZCBs5i1-KfjK);2FKQX6z07-gdHT&{|hH|u&3TG#4mTMjpV8f3RH`JaUR&u(H)l@Xat7@kldu zn+IJPv%#LV-;~|Bbbg?Z^3m-iGG<>}exQHuwp;J?@ez^$$a~r;VFbPv?n`#aK zOERP#67H}yPt?GAXrhY>Xf%61cjGr3X}34$@?am@+>WbNo#f(QD*%4pvL*Pn+4SUk`pvzCXlwpS-0AH}LhVs|q zWEmH@urgr5QVHWqO{+^J|@`ND0cX>&0fPbC`FhslgugX z48(r@sY07JcuoOrCKd2Xy3m5yz`g~DM!hg=+=zJOEs;#9l9mh4#r+Yho^Y!kfe@6u zYNZ~c5>VMN<;mP+6ElMpw4~up}V*2{r8YG=Q(iXL0IN$c4h4oUKgKA z?({F`g`2rNJGs_?Yn8PN~Ie3qh~t3HndGEfuNZ}3RQ&p7X8WVHYGgZ2G<$T~+|A+r z0kzEmHM6!4W_7nmt8Bu12q)36dVNeOC)6qbr~nJQaj{K>S{%l#j7t4y7I zG=z%Fii>(!^LGb$+Sc-Pilp;P2%e%0M*KL;s-noRC<0*~r%bepsiNu#)Eh3p#<2ab z{_CIFrKlw4$b~Vcmp_|%DmhZ(Ae`lYYvK++>$0g7U)s#jcUts07QqkWlzuGo#2E+2L(%KvDJ<6thCTYklm+inbVF$qekZQ8Bs z_jTmSx%T$qU>^z7>Nnoir+s6CW3mGt-(~bezmAQ$$;*ewIkYSmxt=&;GmpSi($W-V zV))_wc8ne>%Q@G3wGLN?3dK%OkZx+kc2ZJOv;B#uB{m^Bt%SF4-?rGP`=WTTTJuc9 zO)mQ&&(*}QGxjJkLcjVrxK5?^_};ewZ5ug7X0JMJ(=*0~(D zH+Z0@f`K@SY6MDYIdYWp#5|J+LoWvQ&Kbyt)RHbU~F zgk26-@UY4Wbg((pgbl)4snu?V2<^VlaWaVq>!l&g`}+O%La&%3a#-!+y$O`zGxw9( z;zTNj#Dh-#BxBhtOQlUY0(NU9S(x<)a~~|%=Y<);#R}lEP4SD3trS=T7ToWvOh=6e zj4s`q5H%KBZ2Yn+&cSA8Hhg_~T%Fx%ZCLGa56SMdTB_tkJFJNWb2hH`%j8DcjX5w* z+hIgTMq0MU+og`Hb;gc4F0(pp_c|Vonz=FN*VnO`cB7)V>yA`daB9yz9d<(2$_JZ_ z^Eid-pd!Kax$OKprb{B*p*7omMk=+Ar7L9!Q_DtgT+7AO=r+@8BniPJ)=HZ`ic;oH zwoKEjVlDjo#`uG=bMn2yH&!QAJpA9BxLK$SyM21@Ju+I)8vPtVg@%`1O?Ie*T}e!SF$uB_mVG(ynD1a z##}yPS^OGN#%fw8rPuY&syk-vCAGlJ;Yx8&JLY_1^s{yA-4%+1?ugqP9;)&wrKPaD zCL;{3G5I@d zfNM}qCx-|ZbuT42k(7McUKy4r8MjNkKq)+ehh_|)s6XAww`^HVzfoef8D+ij$*(=1 z#{LdPhRhZ9(w-+xMfjuxZ6QX+@fTRD##D-3Y2{`3Zfpqk78Dt_Bh2bq+3SyswwDKG zFY+(Y0?1|T*Iro&b2Y0wxanZ9*yp`9ZrQ;;lg$`6Q4yP;EN!3i><}gIXXB}r%GzL* z0{fju!py#bS2@P6_B+3MVZxTQ4RreKIRAm@14)x=1pk`RyNh6OTZ73TrLWCYXH84h zJj+ijP;#z#ghKh|ut%{5M$Ik4Llo05B@g0xkB{d!JG4%(uf5?e$(U^38*`Fnt64`= z+1Tzk46*p~<}#<*X>O9o$h$m~Pv6Vd7Z?+ruLlJYY=Q{grdhjpg}@=0nyUpb&**Fa zMQbCQ!G2j0>5?SFqWS&lkZ7%AOHHR{jZwc~xBehrRgbCH)EYgdgWX~17X=H1$c+31 z-R>Ai9q*Rczok^n#t=C?5|IoUP5Lz59Wr_ro1Gt3jXZ@l>Kf_}`BA$nJ0jr%hC}d+ zq&*2IV$APH4h%1KQusRWPx?LQ*kvZi3>65mYmQWEH%yODD0z}wn;#WLQn^wjHG8T4 z%%x?TyZ2~53|A`~!YB>ol_4^&Y8Prd7}1o&6(pXb7ldnhsJKah=i&)A`Pl=Zm%O(g4QbbWo z3=uh0PJ4O~e0liU^24f&u& zu_VTL>vx?8ZL&nZ4|6SS#b-8JX~JW;^cY6Rm(7m*9Zfc-9&I*d=RH~eNVhoIB*HG{ zcQG=d*0KEvS|biY~%a9vC>4OpCMhC!Y9@l6M+=Z_?WvW+HwF z;W87oA6q5aTShzT1m0;`cRtt_$PjRk91Tr}sG%wl>>J(M4wIk`!|xVhpOibtDm8Y` zN+`^p605K7_4?7Y4dn+~CX~-XymbVdH>x)*!~Qi+~#}OV-xPU!!Mg6 zs>}UyE1R>j4C>iytA54$9g}`EY(h@EPapR?h$v2%wHJTjHGB6=f-3U1iMms6!7&_{ zu>`5&)dC_{1fAEVC-=(Wr`|*}pHih}lLFYRxz8Nt6WPblPAe4}Y*HT4LqS>nobNnF z(p)K)UsZ)>rTkkK;V}hrBXeV9Adu;FzgGc4zzW!K%!ghem{SM(Tdv6^SpTfnNyqs>I8NrQ*#tHNnMOa==?0plvM4Y=;4T6BmYEGybLSlNT z!R*LQxdcWUtWo3Z0XpgTMq`Rz4;Muo^&RXk49lMu>Ph#ZSmqQ{*$!+lGc#SmsxM{Q z8rDx_B_`IUiZO~D^`mikc(}_drQ9{xOG|C~5L5jU%|$7|SB~TSl{TxI=X1dOthN=# zSKj*knfRPgLak0(1>8+8>r8f|i9U^Ixoa&)4yDIBq&Pzk7h7QnLMl0mhT4O)4>NNg z%q&mT6P!+Ei^g4#N|nNLb92LdY-}vH3~mf?bqn^ZN>oWSRgr30zFnz5J5{vbUhPuT zIo`Jj&YCld9Kt2K`9!6j)4^ob__>muZ2Mw@%bLR?qTGyIj*?@xh0-)s>v$^4+r`Mp zXf`5K9wC+>lQnRYLb55T$(LZ9cqZs!&q5AYPpGf2ueVhqw?k29%vSjB;6=d~XWpxM zHA_q}cUQTY?TxX0`W;&9^02C+7|-@4_>NYJ-`T>sVl}uBc(qH(bW_OgxZ5Ejr^@Py zzufBxHGkQ>q^*+gMJlG$)KpxrkwUNKc>ejgMav(C>1}IHE0@16l~-v2a~pZ_16t0v zKNT(1`E3>WfbJr zqC6-cF@Q=Az&VH{QX5ME4dZn8*mL?chU3B}dSC1CWwsy8v;xvK1l3hb@pdD0A_r~P zB%I(`X^aW>@0>TjiRIGH=cq(8M0fAX6JzS!9brM&L+GT&Lv*0rww%3j`jha}=Y zDna{#op;^2%k{rlh!Sm?tgLs&d6kNe0F;i|f)owf4L5R1vV!Ku9kT;Pc9j8|50hlL zj;!0tyXHC+eWe?wqH^1A#6iia0G2(@rdcEDY7d7Q4w4{V7}=C|CTR3ilff;<9OmOw zwv2oR8Kcgg?XJ|OlU?B<7h1YCT;pKX=)kjb7?j1t9FgU#YIC>jifLB!k}CK!v(WCJ zLTu6_gcRi48(APnOdDm`e)g=MU7|U=XS$#7cCx&=MQJ)h++dP@?HFvXwnwCzp<(fN z6+@6N$fM0JBH0L`-JzzX{FmCJ`h+xS70~QfKqWR4LZtkh8_h$a(+_uSg+TQ=a&5Ma zd5Tnf^=FCxx9<-$cK+lprUJ}}9jS&p_5Dmskx;=(j|p-?Ft~81F;xb@?*{|Q zH8$x}`_Y;ji;{+et|~7LqZuKTB9v+p+ zuBX(ws!m(1^`Tyugol>&e8j8C2J8jwRw9yvk1hM|WC(@$KBzxCu@bQjEoGE%gh>5@S7vn7FZ1ChbAl^>Uag|KM(JVd?#FaRe<9oBdn)y=F6s#OYnE?d z%{;yLC}`pB)f&|{CYRVmHrMGbKOemH>QI!lKQ2`K`dxFnlbq{{;)fuOua6ny8Cu7q z-iVdO30s{`)YC*^7bVGotA-{fkv93c;rY~V>Nk}hai?g=%NHAq-0&?W$$fF{yB~_F zoNSZ}P?B=|D%m_g6?^pm2?sz64z#Fy@LeA3YHg9J@bi;^-mlvj zXxIEEM*!i=4v4^HFb4!Ko*rlUq=eJ>@nfe*B?6^9)zT+*&v~?>DZ(^^~#I<@m z&T+4&|Q(S_;>2u5Rl zHxwAI7&2HdA56dU01y;3IFGP=TLA3R8i+PLxpIb0;RKcgG5QS6P@)F84cl?;J%iM~ zGQu21CYRU4+MA;>Tvv8ay3Aaewf3jz`ckDx-#$!wIY=aXoMv!~Yn01$#QtEm#z9fb zxchxpjv~*%z#A5~DO?Er;rdmrmLXC%7m|~S<#?PCh8Io*G(v*8mfuOu*wr7IjNBt) zbd@%(0eDxOrit?=ueHrhvJ6g5-3gD!6&{i$7J3_Z3syQh03Ln(~_*(!IAi4v2{)oa~k4f<4|b7ZAKnGFmz(1hv?v1cx{@$sggyv_S@p$Tli zDWQPxiOT&odPT5Y2(3Ip;0g)wlnxM<(tqI#Nd0ZJmzO4tZm1AM=4qDl8xpI*YIe#H z577$?=@bQO4gm;%*Bn54*4a%!7TA^W8><=E&IOWhg1jqLFz#iOZ^y~rID0j+ zP-1E#C%BaBdVSrQYvq)G2T^e898Latp#m<)c;H`b~a#$Nm$a6xAYDEw#J-eT=X(Bqxip3Yen zkSqMKfmDQ|A2k{baelEH43>Xba)1%MpNM8dH1jJF4ATG?v`)~r-Asa`@-S^^1p4<| zAm#EWz6JMB)gtHOpS)2hmZ2C5Ll0KvD`S0n)Htpg+Qu0FzCf!dK}Z+A6rF^sOfXRf z`yfp`REk~1G*4|Q*|=_UbSyv*41LFPtaAQloYwpr>_@gs*ISBVh^%!)W_8AGEgka!1mqS^nhnT? zv;TluH4bQI!=H64gxp|O;FYs4L(VJmVrBe!hGepju3uj60gdsmPtG-D-k`o<`j`Ia z)1?W2s@zkhAV}QB^{^h*fBy!ew*C_NQM==LvsDE zv(Z|YNi|QNndE+lkA`n=Gs+ytj@b80_xh)4Bzuf^hY;TxB@fe2a1fWtO^7Y%LY@^o z^}Rs;&icY?%KaW$;nRo0cI)4~wLvV1inHq8t`J%{w4r&MfK7cY-6vP1*a~N=w0-o# z=2#rg0H`&a5joZ2(p?FWcgf7mx=p@w6@xwZww?kWp(ETk0*GW?6n|8vranq=%z8%c zw8C+4k{rVCxEw&BwXE77uTgcsv}hv-oNpq7Qk>C!5+bsNMR?)stH_UoDVIxzvgJOp z-I9E+l7l}{M|%qo=T^n1HyMww`j-yjsd`pl@xqz%^v5^we5-bu`05UxQtUSo24xI0 z+#%7igT1GmlhT`PTWee0&hwghv0U?l^Hwq_JFVe{{S*Qy*&9o7utC*vwq`w)z0D4` zNFL(>j5x(ncAFk&0WQC+&xSN$@J0!dt_Tk83r5hM&OpxiVfYBO*-RWW`I2B;LgQ*J+%!k=&kN?vnKLz;9?eO~Curd<_1>IxfrJRh6 zJD%^EI>}cYj^ZQxYMt!pQL-OI>Fo`Pj=t=wOkieFcp&+YdqMR{fs@oA3xnIK@-k}O~5ZF)l{XGclNxShC^_r=iTNd z;fO#}a&c_+Vkwh?J7$`ibyu&>9BIrC`#cg4g>Mrm1gc65XPeC>qYctTL{n0EN3&~D zThnNn?5qALHP-(wFfV)Qt0yMDYM@fQo72u3>+)c3_$s2Dl16FNBxG$&qo~OBc7132 zyUv`ai^E$LhaXLvU1!NFq`pd4iM|pH2>_g*^qepoh(a%{XOc)(ORuig3E4?zucanH~A^L{q%R(nhzz-R1ps`HRU={lUg6 z;DQ}C35ozcRL=t#Jc&LYdN5DP#|(y3eqaUa=ubA19!2eaZ94ql^CzXt?#h_(3%GcBdh53n{b9?8&*-(xxP4lKA7+DCD3Y~ap&aZ zoarhbi@Hd~&%M}fgk_GbJTg@&$rwVaiuqoMJn->BtsXe6)A8ko?Ww|>?|!ptA_xy6 zEL@s064uODA|WP~a&^^g*lP)_6xSQEQ3`NRuUxAr9DMTl@z*r_pso7j_H4^WTt;pV zj`_oW^h;lpL&{cIC^ITZUXJ;Ch=cQ#gmtp{8?#J{TFQOb3z5!q4jJ{lW@G9xymoox zvkKTVAcrSyiOa7$%o+ij9oN>{%_U2|)BS0$F*@RP#mVJVsi+dNJ&|#f2*q4ga^bX& z^_NX(V;#5UO(Smej*%6in?GeM4PvANW8#`VfiaopfuhYR^qXf}_%A2Mxw%&&WGaIB zEbju?`1=@3DEilQ(*hueG|rQ)K;_rtbynt3|GG4tRK!9)_2Q zTD2meDLm`8y4zuv+r1Ly8O`c;!$qXJKUT~A)RhPp2J;iI3Mq~BrA%H>ApOxVv#f8( z#v^GH0MpQhDZ?;d!?h0;m6X~9%C`9yblHtX7iN% z6P;u>H`m@CvM4AQ+xK2y?42f~U&(CzR2M={7|*F&lw&_lP`@0R=c*OVzjUhutg!r2 zzpT)WV!f_F$4he<{psVk2ZN~)*Y6lRtCJ>+EqBL@w3{96mX^$cgopVA`@%Y6cyOet z78A3`e6pBsUcOs*mWB*fO-q|NZLHKddVAICRXCsH?#gX1EP^PI<~--OTV&y>HlFdL zaSfFfKDeiYJwBf3QYLu3P9H>N4JX%h9ZtRPRYJ!*q3@1Ilr2|?cj(x6(Yj&P?a=T! z3^r@mo?m~Uc+tp7?nJ`^%!eIphNe4-(oTX2u0%53p1(ImKndI>%198pXYdHa+{E@p z1Q4qQ19-i>Fs*Bali~}^Gyig$!l!nF1dHjGjv$!N3?jEU(U6_!m*N$ZY zCv!Dh4i66(S;DJN#qv@8xvF{x9D>&J2W4X!kTqMj+=x44uuuICThw=#B&DQ`3or4s zsBfiFnnet1xv?(9W^Jt%MQf6TwDw<*$kF5$Sjv)H`N-u)TEvA6B)4mOZ=7d%WsYZF z?kJJl;?;MoIg9`jA$G<@%O@_Q1fQqDMt&lGfrg}*M`322+SO z5TJpPW)+j(!}MskX(#4T^7yIYJTM>Lt+h%u|A2rdVGd#pDqh>TYh$I^8+pT@zmGrE zL$O-}3{cah9%GIfe`fJ^5VhyarCt{_b~@~>jWQSObw@M@Bwli&nZu{=7SUR(-V-*o zTmO82`3`!1mO%DWAH|Bw=?~-0Wvw&2ZwH+Xh7Kw*>MlDl)O3NRjHfDvuY9h>C5$o5 zyv7O}*Q!;`Bj>s~b#hc^kl<&=t6eN(S(FS9}RpRHnwE}beN?JUs?HwIz zEd68;OlLXJ#!X#8`^dreumIQ|QVm8pO7KC4nQMmO!vZR)MId4OeQE|YNJJU8+24)o z;-mMZ8)B+#mCv=lzJK#v`HsUhvG(OcG(bbI=_Ynj^2ixrejA|qdFE{^P4sL>G`0{W zag^ZdcK>WUv&3U@aq$yn=_T~E`;DPq<5?aSRk|+RBw`6oJD@c#i|)EM(_ZuUhk6dzCO9|EAQ02Iz2M} zZ_ZirD^sLVUoBdx28-%^*Gj6vF!4GUnZQFU;|2hn=|hfT-(#h_lV4KVL`g-nge~?X z-`KMfkJW9od`JONdq+3{T_e0}%Xy=jbT-(qyj*#DhgVUuXW9{KMedr#v)lXEQAe%{ zaz6p8D+wHLqDB*u7bPisG_!A9igAJE{64zw;bp9qXW^SR0NZq8#})wDYzh$jNaG0v zTz7ZRhY(Bq1E1SF{GTqH9;ei4I;z>wV5%F;%u)cO*}2PM znh8JgF+zBl#8{iSBV?a%naDweJI6wWuoH_g`8m3x*&d+PaB zuUw<|(Or`t2G%mJhQpjv9{R*%)STNamHSfxk8J7*N_=Ch^YUbj&NP^b7@vm1v!y6I zXt)guSnRi-Nqy2|c9PlQz%Z9T!N{Zm$|DtbLQ|$h>e9b;gZ^K3)SFpO$jN+N33Q4` zwcCT2K+A+`Y?zx7HK7ZAQ3048bYZ3jBWGirDXfV86k&y>LP92!yKl`}M@x+d+gpOh z-%4zK4gDmRBA?zJ#ovP^^o;n`j$@F^`w;S5W11SQPP=Pi5Tp|q=S_CX$Mc9CwT167 znP*iUsJg`ZMSrL#-Hj8bQ+MOxMqWke1ol*$feOXU>?pl}?Mguj@$4O&B@@ffKBNP7 zkpyteikM=~Q$VoI(3}ljS7R!dT&+_z9L*{%F+nKu+pID8(Tu?q_RByeF=)pd@8$;& zBO6U7cQp-|iFX4mT8Arx$~0X^itILMn=eCqQFYA5H}{%LFWv;IBvMGS@3t?FvnT3X>M93Dc>P$O zLSzouvAK;ZCaZK@AUg83IO)>IcuS8%bkq$OtQjGbD;pxOaL^Dh7`$*f+iD$G2%Bqz z03%y&#g~9`2B39U~?-e>i85||ph--tvW28tsb+bH} z$n_`3Nr#c8f9WFs1ESkqEF)3)KNoxoL$ZgVJ2ny+r#pzcdA{GBSS$^ zcZ{ECfnwrq7w4;hg1JaU>%Clnt}F1zYxs(q%<>Pb2=Y|;rV;COjmKU(AHOR)1<0G5 zf4dBjHl`GT&7dGGWCUJyI-Y{eiegg0jPfYWC^$fod=*+)gyuU~#k zt*uJi}?TK4| z>RT|c6x~_*Oov$ntQi$Q^9yuf5A816@eHMtydLOKxC3s|7q`V6gRlV7l&Mi+H$zK) zAM-lyWESq?n~vr`Hm6DYx~Hy{Uk68-kf%4rLd$}Ks&0z<6E>Ung}9@EOW}EhqN+>d zDGCkni1^>IKcDSS+k)1MVWFnK`|fT`t+x8*{y*0mzddhwvZvNt;+b=xc7P01hloj9 zT(Caj?%nTzwjT_UVB-acBLEkV^2^1$BQTS2r@M~m^m zuqBa=1Z=~75ALwO&PJ2UTjv#P2IzbP%Mlf@2F~COT7pRtw2@%>(>52M0W?KxE=v1@ zHZS(=9X8(cd0+o9i}NpONzfFl$Nhh9Qknps7-+hVD6KQN{mBm-V0(U11{Vpu9|Lyc z6{t1j(+CSR3+@YymV{2dSd_R$8Y#k*x5Ei0ra|xdfB$ml!UX=NtfVlf(L|@7N`BzCes}LEXqWMoS6!K76+?O4j9tIrZ-4>S=l2G=Y#q?Q@kS9W zPl;y@@QQ6vXYo^)0Z9CQg`O~3)z2qhAl2uc8+)_ut<0eg71gPZ%V4?hGmi$pAI5*j0;*3eb>Ch6l7`_eWkh z;V|Aq2wEeY$9B=hr5w+my`|Ou`%s_%0|Y@tT5zSrA`yeEnG)c>($92qXlSNDE4aK% z*>HMU(geJfOcz%L@L)I(ufM>sfG00Igw>e&+2Kt7n7o<+EhOX>|M}NFTG2f!yi)eA}Qh?S{jW^!RgDYt`nZh7odbod!%aaWYi2 zbM}J@#ROoz7$`ZS98fkd>5d{o$A}Vh1MCzC$_eW?f zMQKsrDdT$Tf&0gSCMe%67sE7zq1d(Ivw!uv)E!18U`s}HiH73=wf%%_Ulxpcqh#}o z9)}*d0jSZslJNW?KVz(1`?|{Sa>MVB0_#u)RQQgfO?~O%x08XatJB~mdwhYigFr4| zyrP6))qAxr6>qINA?ui@TSJUFCc^#hN@mQA&%_2fWr-JsU!aU1r{(BI6M#! zZk=x9XjyhlfbUK5$k;T%;{T}5Q1$RJG!88w*VSwiT2!` zj)^6+Y8i=**ZtNG&(&A6pKTd;m4cN^$|HaEPT^}9(~nzX7q22tzn9v)T2c(%r#t5hd{e0 z?F%bZ`mfoBH$2)EsLWxE|F+UN3O&1LaFdg~yq_sOV;ZO8dHDlJ!u`wBd#ZttP&_Jt zAqK_4e9ZQc2zGq}s_Q^#cky2DvRO`Of{>GcI`PZ4uch&OX;mUwh}AJ6C!OIU-Ay1p z#;BF3Lt7G_ot^D?%$WGJK~(srg1@w$#8 z66lBFpr^`Tcc!(GFvqoX4?bW_Gs!B#Kf8=lvwYVQa3vrqW6~?Ol94t67e{Jm4Bb zjjLIR8iIyxUY*a3^0nw{>Jx$o890g<}tHyU_q(; zTha-}r7s_fL6GMLk4SkMDM$5m555*2=bV9HUpYm=?o1GuOA1}2$y(` z-4R0skPvqW*^N_e#S3k97WbV6qUO~agLvec`u=?W1MNk$NTTY*~n5(6$9J~>+T z!V^x@EkV(Sb|aHNj>J)TXChyLiviG0fN@v$>(>nf)yE&7FL)Yzi6udUihmQF&Eud{ zU~={Cx{1AJAOw5f-4ead{C1xO9R0k5=GCG!AHe3|Avor^awo$XLt$Uh=XMVTzXG6P z76#{lHZ8Ibj_d$(gVz|>7hOAuIg!$)GQqEhpOX{Lc;d4~Eaz3rRP8PFzUtiSVSiVR ztm;5k1IiYYh`?9P=xF;;cW>z+R)A0PjvlsZNRTDp^$Zi4n{=55Czg|#mpOta3 zLXqYdwF=(|Jg4#{p>F+|!(t!=fmEFr7p_BreE3Jt%)0<~y!|y7F8y|>zU@HvJo-#0 zDd>!YTDm{S#~#k?*d)~wK!D7qS!b59*Qc891(fUN4CPE0F|%r?u+CSxWG@p%MaAh> z=bq7fN*Xgu+2T?T4h{i(PTTjy#~hDLk`YCh4{e9Vu+^if?jb-`ALF?)tpe%DFAR6P zM(oL-aM3&Vj}OXubRWG0)(+Ry=;_jwgT)?G$$^9kyhUQvDLKUmG60h-h(Ds|*=WKK z6ftj`)vw-lSWMM*)p{x`8yzBYpyslNP@Kf13p%JBYnjMJqKOyu5q9$}r$#HXSg(DH%PN6!z`IImKb(%LOmBUXvI(Ng;3Y6F5b-rPt483<@{1*c^m5!c)sh6)@x3I)*@BaapsM< zeYFyoq?WmnC@aRP17k|nvSTiL8V8AH^^sXiOpCp>e%q@EC0DDdw;o>U!lNEA`$Hgt z3Psi($@~Cr@3I8-ZAkZb&2@iL8ofX2Mib2f`@`25pZY!Rr0ycyD(B-^fl}Kfzy~Jj z)E$Qn8RZp_`f4eR{Y*Ww|Dy>glbjE;N|Dw>Rt$We`BVH22eT^p7rBR_$r3N1IY&H< z;s6_716jFh6HjB_(eg~^_=!x}>&)$=zMa8wTHbNXfZh%G@=kkqynrseJ#rH`n)a|W zo0OTE8Hz~-E^|X)j=?+)=E1;9RR9vuNWv4fXqAE~U^L&qFEy2mygs|X_WrK4Vm@1G z*;~D2wz`=smD9nCeTDL^AL-PSkBpj56J3{XSDu{?zs%(Y^1m2PUH=k+{R#K`O8rwb zYGq&36I~r?D-Z>J`iU+#i5S%x0Yhw1xLYEyMp){5nPKeXWWfEl+lyKr@jgW3CghxvhJZ=hA&6~6Z5JbbM)i;}9d0j}n^ zyaFMmhh$TEtfZmdWZB4&!e^HAA8P|t)Q1Z;1AwuEQbRE<94-_-AobXs^Cx!IlA}_9 zF~XA3v)PJ_2iX=8^AGE_&&uZHf%Gz<=42OPd6M$>6aKzz`gcz!WOx|81jXc-+u6~$ z<;Ek@HlV{$ape8}vABm%Vy?@n;t{qo7dZHSEO9mopFPy9{^ag=1v-(_HK!ZzA|v4p zw~TD-h4$i#)p9-=scEQEa2h!O5|&`|V<7jQJbL6a8*1t3SmnG~&eNBtA&`6*A?WB* zKHVd7^pve?;X%FbaM>=#^(zh1w0EV>d7Lj#-PtNQl6B5e;s1gG^Gq-dB$`?f0YMfD z5GO2&f%jX4mVw4&2?bO&ZluQ#uun{+C%CG1-_!nhdF=bLb!KjEkD^;*=R+x44|AIDUTenR9aI@Ufx%TJe$Q>X5i zxZ`Fw7qbcaZFq5yVo^tmeJ>IWXWku(g5Uro1xT(o?^>g%T=&FpjFrXAfQ9~$(a?#M zwt~d1#O4v^&14YAGo%E(l}nFrJE3_HKtmG}Ce|LK$Vg0llCNe8_?@(L;|D=oj>$8G}(tgrsOV>tVowzg$C>N}>|cLqlG)Ib9~?}&MA>Q2r@ z$K$t*K~|miXUg)_jnTsYH~1D zY$AOImeY;)^A2jV)C%#?CAKrV%Qf>e)|%)gH0dBH+)!P9c(Ru&Ki~Zh^c)^IUM4n7 zj0P2gd6taxQUI->hyP=VnX`Fbb_b6!qo1W6qOp{7Z2LP%d5wk8a8T{hgZ+Weq+Ypz zd1S@}C+${T36KVf7sSb8*_HOi@BAp#);-)7p!E7srNsN7VsFHyoJCdP+V1B}QDo_0 zaAcU0rlEB`&*}Y!lax1e2Z_kLcd;_Na1}l(4QGGMJ+!C@!PCv&Dn172YID3;!nDT1zh-Z( z8db|>{j*5N`ephYA756|P)BqxEHJ`xEsL=#GHommuzSGj8d!gVHv;h^)Z`nrZvEqf zmCe2`e`>6%Lj!D{`1c*fuKW8@)zBcDd$P2F+`(ISdxF7-LF}eioR}ElCZvvwJE$IU zN7r(&sf6%=IL`BvywMfvqsO-P0NZAU?L|1D!8 z=PvT-81x8ncY=_sT9X(SMmJ02Z2u8qD)!<4bn9IhTI88Yqr^HF|Hu{s8Uwd16-1RKVJO>fa)#eHT8_fg5L0Qhps*NJOu2}ab zxF#Mc%bjj1pS00qz^ra97TZApZU^&$&1aZ^f`&Pa_m3<~LlBhxrljS(SFam2!;p7<9|zs9lGMq=rj6$ z@82K4Kkmol{`QB*sg7&BuGhX^&)3CSvv(o+`{OK?Kybyqp(roHs@J7u69j7ESX||2 zFM>`a;X_Xw1F5;d6>ii}@G9^JR}!sX3Jbegc;)OMaUhzxBZZ-^3v4Y_nGn`)A>CPd>pMN z(H3rWEMJp$5X*n~G9&1kDwmah@c#BcgJe3lgGta2S45vP{jaT`iY=%ADK#R z*GTjI;cUqh$zc_IkpJy+Y1T_4#L42$tCq40Q;vIx`hLdO{PdS=>l7@LPNQ=CpT|Bc z2COS@IBw+Wzt^u*<%m#B8Z`qzs8)dqErGER@o3**)TD3TLYiC*g!6Tq*#&vj6f;R* zvJ1+d1H0R6O}RnBOz*-8&s3M~@ESIo?8=`!+i5P+Grit41}a#>K%k(+S-wJEZI(e= z*c1%(f^?d0>Q3>;SV@ts%Kt7B$uqt}Z%h}PmP5o32s5~>G znNV&p^3#*i>0b$My<+&m* zGwCrIXKPM&yy~2-HQQN!HXTcy*p#WRh)GTKyhV)T^bc0bheSt5pB`nBjb%|xA2iz8 zh2z|#gzvfUFYJFldvt4iVBajanjUIWFmtrTPKV%UHWQD~N+#{y@?CrN;@OWO#p6d% zKK396pmxtFJF;JFNn5=Tbk-)Yxnu^>K)R$3bO4AkIdUl;4d?0CjkUQyediNNC^%zR zHak?UJKnaR)$BT%lxUW*IJf*#Hw3gwh+fPIJ_V)cSTO0iZg|a|!$bn#y9n|>Sun_9 z*nrhva%5+~rV!30u)RUws@4z#D$ZFEc6fL+f%s*s`Uu;Z46zih%Q}~@8ud>(d}U3K zW&8N@^yW!1U&8We3Xo=cIjz$Nw3mnHovR)(4s8SXwY2)*Mt}<7vos3gcH+vsa~TBv z;p=;%B6L*RwhD&pUGSUQP{y@?T-%+R$PC66S-D>YRhYTW4RW#PE(}j+EO>0ARCUkM zI2;vbbJS4T^DH#^-f(7VXZhvWeEIzQm7XlYqq$D&!X_X*AKid|n4}l?{jyVAEBVZi zHlFIrDYI06v&NusP*wHVT5`P9VyH^nqVlH^y|T*wb1k?$MYsA5Wu+th(NYwwIp0@tYmwhrmY~YDkaK{7 ziledb$Z@35MJyFY*R7kQvLx_t?+P2~p>#=6Cx(eH*rtIl0s_M{(b)9w&7yiIU-7XU>v3Oy zptlhWKt*VMSX9+la=X2~{g%x40OAtHh44?HnE9CPmGb$_;S544_g_5|lCCNjP~TMS zij{F5CXZ&TM#AIFTP$i#X}*1&ly$beSv53V5MG3e>hITj!#hJ_?bw9~j0;7@qjqwu zmR^7k69aBSC%0RNke0enH(phL0Z4fHjZTsqI9gfAS5Gk7j;i|x{l&&)6UGnIN+bX6 z<|~!~Tl6hiO(VztDY}|hbnAH(`nHjd5}2v9T2_UNxWv#!<-UjVdY^W={p}$U=3^B& zW}@3#f_BrOY<`92(J`x|_`)sux^A1{phVHaTb!{bm(YlR(1$1?+?j}Qr*j#tm7Y$Z z{0xdBC^DQnkUXlojNo#>ZDPZAPGhRS^yROr={rIuKW+h>E^;@>6@cTd+dnfGskOZ; zYGv28?53-06>3{3H)_GXhip#F{eDR9n zM^sS`bG%)jrcryrE3V=T& z;r8pLuJi zE30aAILIb&0!zx|LOonhFs!kqq=zoU0+#_wvVsizqVA?FTxzAD_8!cM`VlGljYrHL1cIJKC;O_H5dt1np|^yoo^v4O9&uI65JzsvVPHxdpd zDm8W*tK+dxd~fWoT*VRk98DCn`gq48d1o&>$!$hK+iJ))_ZG3xEceBfDe5&P&%3;h zAj5k_EMe~gN`KXdQDz2Y7vrmzmYS~EP3O2Z(mG8hE%}KyM*wt5=6=Z*WzGl@ll#su zsVe{mn3|dSWuY8sBt}C-#)5R#pdwEHru%Nz&So3Qu^qf$C%4a_vjZX9(!EI8XdB z0)wTzh03EcSlM65O&0HoDo1usIo(|IV%w*Qx=;2z8lCvO4AL1z_4VMI(LWucahZ{{ z4K}m9vqVi}+$P)xZt&lYW=AvgGfP1UB_TgT-%O83i2^RV_vw`>-&PLqkU_1fs+TiJ z=PTC-nd^K>EblAI$pzk6Y}`&QDY-tZ9IdOy0$>rsq%U%ozYInT17t(v@k%$gl0M{u zm<2KzN(b&_rEcb&-98INR$f&r(uT&pO{v>HxVl**(YoUAM03o`Up>y@nU3 z>3dC(L!3s^ms*X0nLVKm+X|nN`L2Bj6r@JPUt?>dj5hJEk3T9>}akQ!S=Dm&}QZ;Ka zcd)0(vAX4hyCNflx0T}LJyx^<1DyJIlNU);FX(7y)xO&K6Zv8eB#Ha*wa&bHvi+*S z9dDMIl+9zirbE7crn_^E{YDUF27GeQb^E7k;{^(<@b#uIfmSI!AB#5O1xM#unG-I7 zEZL$^Ti-%<*acxHa4mK(_$;A{ry}KzlWXtjEOK=!Q;Lf_&lKCw^(Kyjl=p+x?T6q> zK8p!Qt7sflWWO#Y5k8f9qlvcqS6a-2r7_mywS{aRgv$YI`h;gX-j z99!e+4SCM$AA~>&+I$N7LQf?90S6ee#jh-9A(GOiU;!sFkrnrj3I)erG{55PcdnuF z&l&rg1}NI&n}W@xh`Q(kL{Aarj6vrw6`JH}rx^7Tj;;o&J0@r=K>#JCjy#9}KFKh! zoH3h|2DT3d@F*EaIHgGRh9WQlYE$R zmP*5{DVO@z+m)&B=_Xc+R0?LOx!l+JhPmPI*N1|gDxpw0zme9Ge1*5J5E~3%sx~__ z@YJu4lm=(JoR>ATqOoLf|% z2_(c}{9&ZDf4tVIslsJTEGvJUG=z(yt+ITL(rn)je!p-mS~*Q{ATvEJn>BefU`jE86ozdr)^ zU&)fe5fv3Xd1c|zAX1d-u#p*Rj6J9YXx*y>iA{CkagWiZWumb!3duXZ&s$aj8?&kg zR(*jnN^QO4Hv9E<0!r{mzC*#m2oc zHpI>v4xo9rWn`}I-EMYicBQ1Ek{J}<6Pm2r_;F=ZE`dU`f_i?hr6}!gwRi-lI{EyJ ze(?Tok8x8Si70tzC80AJbrrBUzJ6l2(R{)K>QAY!-eH2mguhET_-lLaW95s4WJ8~>1P@=z&l9@+FlhmqSa`H{3mN zrlE+lXC>)SNTIB7A=6_j>kC6%0KrA2eoyVu&!Pq%2+Mzp(@|+_Ws2gOi&>T4yu|Km z8MxJ9l!^RA^peU?OVQ4dM!-5H*2z@VFq>>?wQwi34fehBX(~WiUUpeiXXWCG1RQ%O zcd+tjs0`;T`8dJtlWZ}>Y~I_wOFx&U(#=xD{lv$bZyJB`C!3%iFpIJ6Tg~Y1{|;Ij zj(wA&k~T5Pc)T+&boRyre=UKfI}i$?;ZnUR;;Qo+EdwE!-z^Ki;p~FeP^mpZQKlll za{DWd6g6^bB4$uF1ytk#d;mk3I@%@pCy#p869MFfQ50`9%Jpa|C~bVcHKTUJ$b6fv zOUC@8py3y_4zmnCFJwg287MJU0t!(v;2}KJOHk3|oPKfTa=2jMK0hl9o z(QzkvfuBmHOJCT3Hs5@f03x$bpf3IOFs&(LCzAq7BAb^O8I6c zg+=xrzH=?#Co#0V{_{u4y+o(A;gb2XU5{^p%UOCB%ToAeEsZC-`S$D{x(@S=kbLO# zeqBHZMPZpx6t+6{jv9SOBy1IBqz2uxh4!V%uR4E$?s=JjHUWzN-@qZUynLCwmncsp=^kvm}ono7QGuIBS+gn%kvGd%2UOVj@@3GD<11 zu5x>3LbuE|Ll%J9QcaYiie)0je}2_H&qhNs#d18I_VRJ0Q1?dF+)Z;vjuvpeniIfT z4Sf3uz^mtyj90tz2}v~BI+&h;MD`dR3#NW|9+&cU(5L-2%gamImv6zkUXUC9OHo3M zd01u`Re}4s@IBN0Otao;P#V2#u5>yTZMQ)6$q~fw>XW1CkB=FpWAyZo^$p{peW}uo z(3c#3#z*bcPj;htLuJz6CmWqXCW+?^nOq|aPN!d?p38+x>J*6-PE$AV*1d07|AruY z?n5*5YpNp)w>^f>Jam7%djEBF^nmr^hpA9RZBfJeRC}q7F_fALpfkS|OqRXosAYWj z2!Ci_Ee3Ru!3H57?2yu+`dArxXW*awfnNJ{4L##uN*Qu0k?Jv@GKbCM5L6Gi-U%); zJ~Y2i{SdP~U5`hhyKVl2WL6cx%|0qMo3ngw;DL>e^@FB}JJrVf0KN)A<9`(rCOc@bvpg6kb5q<-x)eB!&=hyGpDTl|}Ylv2l zWr|Nx&2&-^SfcnZ;4zRrA`9VT=7~P`UEn&oB5uj6cfW|yVw6clS}V6ok>d7m19=38 z|DcEsK~HBp6P;|73>F6$1Cud@#e4)N6pHGOQKB`aC2DLQsX22zpwzpj}hnGapvFKFAJE#r4UQ4DPOZC&rV3Kivhz?blA z0SdvikK_!;)UFg`wH2sn|C0;x5rTglAE*Sdq+NVfeyAME@kZcHEg?J`*Sca;MLY{_ zm;4^6Z%l|DPP-<-F=GKd(nsKR2;^WrY#0=0JzF9f%lx)?lpq0I-Ny+!L=+ZYBXc`8 z@tpvt4`d{ZS`_ZV&?^ds@Sp_opymD_7UB;c09@B3`^?sVdd>Zn#f4ULooK?DXm_qy zi!!4cmC7u$UenwzvuoA#kElP4ECWzI*rP0d?cT>LX<1hx#0?z-o)tC1lT-4D!%&s0 z^_I!*15olOH{Te=)AcE!e4e}|`8jh--2f;Lp@ss^Z~FHzqqO4%xR)Y8i<47ua3@!I z=8u<&@W*&!cGbIWk%k=TL=9gS5B5ooR`6QwOn<>cV^~T6TC7r?XUd0Fl$1VYt6%;3 zI#@I!IY{shXT>B#>97|O+LZ*=VNgAAjR?@zb2g`y(6SKX;`!zIz@6GDotrTJO=C&? ze{dE0uk&O8Q4;~md*_b|L4FCTzq|*Ys;yfEC`03c{Jdw~U-4DD?5f|}RtJ9YF(kzM z0ZL){iQmbhvmPPsXk|&I-BwWc8~{jCv!>1eJWT2GU2auO#5rc!N z`GygN^%VYJwWgV2NLfEpZXpFa=P!p<#L7sSq zK~0m|8>N21u8RZpcD41DHr=ohpp%7&EA%`&D3?*DYbQlSC(t33A2y(`@&B$s0I*9J z!tUfECXBe=v3)#vSSuUi+wpo9aO}xovDbe{0tg^Zm(mqSsvVgIV=2ktiEp6dE<6D6 zf*u@E61_Q%`9?APvR8>INhUkO={{?K*)emoFE8r(ZD*XB*gX24j>SHprI3gsm(fOt_fVOW+;ie{KiSpgVujb261S7puco_h^_fOwN`Xo--P+Eh4 z0;Y0s8cZoSP>^hmcOEq3?BbF7EJtM#qL9qX4G|gRS%Ot>0tu^Y3VydcLj^7{M%*eYd5@8K%y1E3IfSP zu+83p+yv7h7VaBGDcgNf4knz44h~N=TjtIo?9G(&F;6DwJyu3)`{AeJAGQXs$%IgF z7{pN(O5p4PNJ9>oXX}gDJK8@_OOJ)=STw#RLi9nex&2%4#fa1hhcZn7NU!1G$o>yD zBu+P|{iKeCkyU)kE9R8_=|5v;=c z9Mp_-xfre@_4J4-|Iv=m??qJihX;H-Wbm@>t6M;kw$Ud>2QPDU09$|8LsxdxxTzT^ z4F#Y~Bv^bw>4iC3>{4PeS7|bvIoqzQS)lLo(4p`QOJp_+R zK>xP~k@xCoxoDJWa_f@-~HWxR+jc64EpJ$vUm>S!EihhXa50AInlUXGK89BIbCAISLu)MB{Z-Yw9@z&iPiNeubHcav=_VfshzHI;DpsB!% z0)yB8o(#On4IX;57QzUsbP&)nVPjOw|+Gy^nzwM!`Hj39&2p9qCtYXJ5 z34rIq5F;#Wy~A1_B}!O25d!c$Dd*o`cEuQCk8M0t_O8#MZA&K~7IdOX-3+V=+U(~+ z57ME7CprXlP+yur>1W6hpwY#ZyG|xKByAL0^{7Iml zsQ~HhfregTh<<1*hs8XtYLRa-Wu4_A&p9w!Ap}C05$GF{0iYY;*2ryubIgFe64c!g z@WL&m)$(%DNoa|#8;jS>Zhy zo)$Ye;v%WG2F$q9{_vmm7K~-mLE#^JF>!+W*)M0X{D7Vs`@{1TIh{+4n4d%jS{@Jp z2#$%RewWh0YodXKnaKwnknPg}w&FPoNid=jZgBqJUIVx_9`UvWdIm!JX5?SZ1TEFU z^mIkw2-DU!6@+nvAg9*f@Bsy^1SBsJS-}Y{2XynaDjUx90v!pUoIG<1-yaLV{S)BV zM>LfsR7UvT!+!}88$pGT0KWeGNcE&O{eRPeQ0~73B#p7oI{MfC_T#=PUH@VZrkz80 z+I&z3c!2`&f@cTR%w1zbq6l^!FbU#faJU@(FdH~!grEfKeNF%qBMe!vR1L7%bwtlbznhY~aN!jK-_K2l)F0&l@1f3=lr(4YegO zJgz_#4oe6j(LL;8V1}s}x6G5Plo(Vk3c?oDGIb1;*Y~3V08GecW01AY`{9{h%;Dlk9?j;sm z$IV`jKezUR%>}wmo59JG-T~WUp%(!&+Mib29}p>Z zZAH{DP7n4g-?bf;!Rgr~%>WQd=okH9q_uXRZodCFM%^mRW7?5gVNvB)1-i4xi~UxR zy!~K=o-XzhV4~aUpLIy36@aL)I$4E*(90M8=?H=eKkLHGmxMdxRah#)#UPF1{YC=2 z(7$LZ&ya)CyiZT|jy+;XedE(-ebMPnw7SN%&*2(*aEqH`0r zuVSt2yD*(s*kV=xm?;^Sg4>k?NqN)&N4oNi+TJ>b! z#u_FCx!NY|_d={7Yt3wY6Xd{v&WaR*tTl8u6n;0j7bA35RY&NxCK7mrFt+UX@`3+r zWUN{wACtY68~b|DU8y3nXmuxl(msptofp!sOb6bjsY%QK5ko6dpny4{zFvP#QTPD= z;~)b91}0~K!}#f&FQfBEhk^oh(nWkPI|sW_)o;(07duNXVkMKBP&H`% z^)UsG5IBgU<*9qrKpOzVMSaIV7-L{PJZSLPm}p*cmBmw8a9He+n2el*boJjEES>OO z-W2dC>5=JsyPi(5y_Edm+O}-ax8m*zj5VSQ2lANKZlb`BOAMvTzCL@XiEh}6kRgu7 z1}wuzpbjDb?a&=yAd2DZvJyL^I;SlR4VYTMQ^9P3nwehmfRr}WSkwQScUI!0?@ZZDt?xh7rPgJrrBz3{s(TbtPGy&N zvdGy%i?VP)wN%HHz4PNW+pIPDMZW2*dTfu5-@4ceYBRZxez*5Im^#iebCv)@GGmaX zwp-hL524?G^91nY8DdFtz#N=ZSWlNCbGVOH zl_R^hbXvh(v_Ji6l!{%Ea`5zHGZ$U;eb*b{^^ad24=pf@odr_Wr89Ap7ghp!H0;4~ zauP!_cWRmv= zHYRNaPR2~d)rV5Blvu#zVM133fu}|b=FmEhrI@rGPT5G>7QuZ{%n|pa3C`n z@FPx=CNfrV8zcWU)qo=`0AlHqHgMZiDK|O|{TM6d2_Yuf0r|Y2I#>rE`^lk+$E z(4r?b+2{oA9$tAXw9J>-pB&q=FHxqV3l%Q=@gwgxmN_1Q=rxiEXye%q{WM2oIN)bQ9(tg|sHR{}KWobDo z3yzh8_g97K`>gQKLKr4!KS^LxU-BQLz-~K$qkqC|1XRsmGQ()b>b^r4akKv~xqcPr zLPZ`-L$RdPP}qoufx+MV)(xBDfI8(k%ZpEePa@;UOD-^YV1$2L?fY;*Tf+0?j0_%d zI3%UuO-uB-f$ma-Bbh;0%cKpDM?YH6txcY$4`3&kV`cz+Hh63B?|HgdcG6bbrN;>P zMrY}|*FkF{_zF;I$@~vMGf;mh&JOc{8ou8K)+0vA?KE}-0RF0fPmNeO-G7EbIZ1Q1 zBaHGaPXD8LbZUhYd$oq86d;!ex&JtcQ|3Cskah5Z21b`&mC^$r0eV9DwkR%;N>3I* zRY}jrEX?W9g)HIzI`M-o7UXQtQ?mrFiFzF?yP=()E4%6Z@z}vYSgZJ!>fU~TDd>}Z zi^AkzZq^YTDj@E5-}DQV@n(Uy+J#^i*9O@fpqvntj1B0+LZ`BRP}cJfC>d+5g2tBN z@5AzEZK+S({39x$pZ%bK7!S0ZVBpii#@;xQK}@`>!5=j!L4nS3IGAmN#@aFPv0L2Wk`sw0u}8IB|k&`K`LC&5K#9J!U;&6LU4(} z-^`-*#8|ZZfM9{@{aT#QC;GR99*LFQF5kNhy+(~DM@pf`mi6l1-r||+YS}5nz}vs7 zXq4j?mG2mM85G=pJLP2dSOVQ8sRh|n%yQTSBd-XkTuoY%kMzUDVCMPj#`e!W6oLI0 zTz$|(g&n(I437VVSDW_T%dvWcDy#8Ds^(Q!UDq42=}%$$*p#{KEC2c8OrlpB?B`{~ z$VXziv2m4Eng^j`rj#o_&gxgjp*Iufv$XLEhoYC4x0}>%rw`uv;MMbaOFSea{Y>?X zrZ6>vVG-`4*DHd>cBYU0*#M$L8S+`|`X8S@ z;3`t-2de$jO)DpVGBGHbrOH!QfYN)fS$t)1)rsv&qV`lZkp7bXVPJV(2EMD)aAIg{ zK46IY`b?~0Y0SM5O&gB+dzVp)hMepU&zxVy76eEv7H^8$Fc~vvAL^tOh)X(zh1jHO zpa-*QY{DMn;iwYcSns{?biOFM#5n_w(+^zK6fny!4pK z6{px%IaQCs9ar`kr+?Q^rK${~bhy40(Kdm!GGoRD9!miQAwFzYkLEIU;*VyPp(g3% ztvulyiP$~(Oji)&-)y@9J%$aiUVxsd~ zMEB^m;>0~bdJ+#dOVLePW!_2__FXgv*R{G>hlC^Dugu%B@0`;`UCR~MA&a;-+Lp_d z&C+-b_^Hzv`c4z9M=g@q z%YA3g@Iv}kJz;EltPKJTXpeMx=W%fQe|GfVA&^xWZgsxfnu+?n>q>E|Chqa3Y(UKq ze7F5{ca`A1E!*_EO3~`^r)IyjaWSVs>Q5G>Nyop#Xl%7nifA)DiYz}*>%P&ji=gk% zqgIC9aU_Gz69;#he3H7#T!qV9C|6{%AUbJ8Q@BH_Jljyw+mc^(R)=EfXvSa`)z!Qi za~JwpP$+_4SvNf$>04eH>Gd*r+l5=7#~f!B{P9My`WwCe6|-0;-`huBm6fNG zIw%EOSMSf|m07MirD~dsbHt0dDeW$(?xW_sk4p8d@)0DzJeZ}J5H@Uj0v9ic^DD21 z8C8FBfJ^iDxqOhYBWs&<2m9Exh!t=eE$4d{c0^ZMY{n4K6@3p8opRs zvEq>gaF7NLedllXxh~IB*RDnm@c?-sKx?eS_UQ4(=!+OeSDP2$khPa2IsBE^>OZJpEp#H*3M=!SS){ zgX#$=Z`au%ZHqVM{mX_b6E+NzIRQ3X-j-c(5$--D}{b6ot+ zHMe2ZFAgpNP*@ZOWv6g(>+t3)_Qi!~37@uF)K)!}>=U`ujpIm|Yp4m+x|>84!RsgG z?yTYZ>u2zBFJyI8Hky;hMQu5#QH$KLKi+2Uq|8#$0Ju6eBi93uQc8T)3J*mKDBeta3l)P6|&MU|ShPHm! z-n}>rWSsGO-fB7abHTu)0O*-G>MiW zrZ!fq@)|(~oSmy~^iiU7q4qhWL|NVMDGU-wElMJ`8w$4#hGw_cnv<*^o?&Own;N{5 zb78uVs%5r(rLo`w!G1DgA*gi8$giK(^_i5Tyz|zE!s>UVZt%I{fr>Uin%1G6mF?q( zPUU=u(rST&qcw2TqvioPul2EPjX2va!tBqoy|;jZUkvqF%t<@su&6Y+tR6%5twke^ z)qsKg$3tu#jvBm!yfIPQmJZr8CrdBi>wG^wS+3~xxa7)88+#T?dnk{4&h3#A z)%F|GKH3;IfoCP#Z133voL5(VhFDN!pX_Qnix}YFuhQSVQuZCdmoRkvNdy~?&=qH= z;}*i9@9zok@Pb{w1>dlz_bHY=*w1CW3y>|W@_cSIBBuUSla9{?H5)*=yjpD-j=HK3$+r8XKYG3A!-~%vd)QEM@WQriB3Do!)wbjU^?O+|#B85v zJoEBeTcYvv`1Mdu_Lw`Q$R@3H+koM@uuOf<1En7cgx3xq2lw?U(%QHO>as76c*X(n zX7n?xIKmTecqX~yaC%&|Xxa9Cq!T5_&drn3YI?&W&_Ubvo?2RF=F3Gp<+#;1l^W~c zqQ~>aw~dA}SEL4`NeC2jXSUX265RF^7Xr53R3@KS)s9}EUEaG(2CO>@>E3(J$)sY? zpZJ#_YanTrdG5+v&5Y))3Akai^&NyTQ|n5M0AWxK>`DN>}en9?y~h=hAb2 zA+kQ=z0)b{tXVA5n8>i3Rya1qFDNT*X$!w&^(mxA3z+>k_RSOCRnqrXJR|*`_Jc_g z0aFQU1!Lhe{Fzx@mc$)aPNe?R&rc70b-q2s1{)Qjq9~i|6An7i@v`FZBM#^6xQTG_ z)?lz7rX;v{Y0P;}_fVn@sA{DmoA?bEw?b{QCmDErnlmGQ8!9+Bq7YwKej{V|BXoQP;f7NLg3cRdmC6#&fsOKQG;tsh_VW{H1!4d?kH^N2f% z>q&y|Denq;8(zj^DTy|TJf2uJl1}Tt~)12 z9U8l+#5>j#sA;NbOI3?ooF;cuOB=o2dnp~9byG@$S6m~`r z>#ei8B5HY}Or(wM$BQ|V1fl`ww@t6Uedv4X=Zo5$Y8=vbD<3A)$rtX3&vbJ_y!vrr zY1UL~KJe7s^^ZVn8(UOr2y5kbky!VqD_$=Pu?1abA$0lZ?-FDDy4y zTf4O^bJ}a8Pl#1nSaIO!){1kt-BLJe+G19o)STA-(-$Rm=-|xwD4&m33~VpVSPaga)(wwjGoRzQ!=hO z^nj_cA_8_$^9}F*F=l&?w;gZ`*e&la;DyFN_Ukj36!5ynI#V%56WloImp?69I4%}x zV%cps7RmS4+C^yWg0)mk~HTwjk~HGGud zGd%jSHO0==VX`QCdBV2(?97|D-hvVtL zx+`qqqTe93oBZKvCY}N;dY|oK{2vI(#Kf)QXkgIPEEvanjIjY>BXrMoHZF+&Wt{WG zC~JqPU8T=#yaOsqh&rfL+%z*jN|P%3nW(C;h$a4MeJVC#dx@2T&cBCX-bHyxKfT;JgbJuzHEKW3)Fj&EuA z#qKc}$06se`|XTJqZob?_gb_*d9g~HJZM9tcVW8dt7=P7uOVKJ^_tvtZXj1aRRdvv z)mN$K4m=_q$*gW7l9pN^?{G>nri1tX`rX!bcj8YxA~yCd&RzVhDUPk(6PER-O(tjgIj zeDr+&+0araCz}PhsO$Esj416z(jMcYq`g(s)y0+31x{h+jdSIljK19K;U=>+=2zG9 z7ibLee)f8nuzGXZ%qyLp*4W}qYq<*l(&m$~dTU72_Pe;K+v?NsrRDMNh5agG*I?Sw zy>eu{n%Pk9e{IYam}LI4*fe(!&pl_dHqgSkk1aysql& z*uZWF(6q)H?A~wAs9#h4_s8=F>MU2}CSp!K>b%Wa{`(dSue6#2#K zaVyy0)HUpH+(!6&gT;sLheoMTBerbQCWMpuy;L!v?7 zr~>7_6UCJ4S@x}#Y0nsT{PNM!%xUeKS$)PYy1Vxy^2+$emv2;teuYRBx7->3QCPFVghH_?O1FLh3(c#&wB!o}3a-0Ko0#-d4iJHXGnt>z&m-CO~agx|cR424OM2@BI)_$yFBf2lr^`yGnUGyvaz(QnF zWW*wow$oeZyVrkf`kH)Tbb}c!wf;2+m@J;)ntsmW@l-svh%?3K+uz%q7;9m?ERcd| zDU~78Oy@S!HJqo6=_Y2 zrNym3ZS)wd@L9}UlXsj=jC*d@^y4m4xo-Wwwm$m4MH~7i9G@50?XHGVbLQtpkcrz0 zN^}=feE;xlykzFr2MOBiaOq`<#8BsY;%@PwlUxa+>x)(E?pyIw)*qQdoM$c7NQ>w0 zbAUH{4jcoPy8tg#5&eee@Hqea;WRU;my`ZCW@hHLT9meU*GUy27n<76k+wS3dVW!= zk_*V3JH6rDsor0;9a>n|{TH>?1=Fruvn73|HzN@KzGD#F7D*pE)i$syOSUZ|8dKe0 zv>A}JH)S^Y;y1a|80b8N!tX>K|Le@ZNkyvW5C1HbaDnYr%^ZEwyy#H>uN#fT5ivq~ zem#V3cDX%jQu4d;`V%YpY@(Gjd?VWHzEh}%fZqe02eH8Vndyduyu$CzW2q2NQ1~oD zKrDiF3g1EzG=l6jy6&*tyhhwJm%uBe=qqZr;6bye{k6D!KR>v?|3hJh!z^){Yo{Uq zn21IY;{heXU^Nv$Pfuv;W?lTtKmJu>BnV|$!^~7W7&JenP+hiSNu+sH>{IA~U+7an z)h`?I+d6{elQ59D-oq&HP-S92ut@6JOf;?4_j#6S3+eOe_i7Un<5UImZv;O}Ecl__1{&!CQC%O#!&i`}-#@+az ge;o1u2aedI4OyDcMhyx%9|3=EOUU0si0OI#Kgkg!m;e9( literal 0 HcmV?d00001 diff --git a/templates/sync-rivet/client/getBookmarkPreview.tsx b/templates/sync-rivet/client/getBookmarkPreview.tsx new file mode 100644 index 000000000000..2aa7942af34c --- /dev/null +++ b/templates/sync-rivet/client/getBookmarkPreview.tsx @@ -0,0 +1,31 @@ +import { AssetRecordType, TLAsset, TLBookmarkAsset, getHashForString } from 'tldraw' + +export async function getBookmarkPreview({ url }: { url: string }): Promise { + const asset: TLBookmarkAsset = { + id: AssetRecordType.createId(getHashForString(url)), + typeName: 'asset', + type: 'bookmark', + meta: {}, + props: { + src: url, + description: '', + image: '', + favicon: '', + title: '', + }, + } + + try { + const response = await fetch(`/api/unfurl?url=${encodeURIComponent(url)}`) + const data: any = await response.json() + + asset.props.description = data?.description ?? '' + asset.props.image = data?.image ?? '' + asset.props.favicon = data?.favicon ?? '' + asset.props.title = data?.title ?? '' + } catch { + // Failed to fetch preview data, return asset with default values + } + + return asset +} diff --git a/templates/sync-rivet/client/index.css b/templates/sync-rivet/client/index.css new file mode 100644 index 000000000000..b1f73c6a0551 --- /dev/null +++ b/templates/sync-rivet/client/index.css @@ -0,0 +1,88 @@ +@import url('https://fonts.googleapis.com/css2?family=Inter:wght@500;700&display=swap'); +@import url('tldraw/tldraw.css'); + +body { + font-family: 'Inter', sans-serif; + overscroll-behavior: none; +} + +.RoomWrapper { + --background: white; + --text: hsl(0, 0%, 20%); + --gray-light: #f5f5f5; + --gray-dark: #e5e5e5; + --black-transparent-lighter: rgba(0, 0, 0, 0.15); + --black-transparent-light: rgba(0, 0, 0, 0.4); + --black-transparent-dark: rgba(0, 0, 0, 0.6); + --black-transparent-darker: rgba(0, 0, 0, 0.7); + --focus: hsl(217, 89%, 61%); + --whiteboard: hsl(240, 5%, 96%); + color-scheme: light; +} + +:root:has(.tl-theme__dark) .RoomWrapper { + --background: black; + --text: hsl(0, 9%, 94%); + --gray-light: #333; + --gray-dark: #444; + --black-transparent-lighter: rgba(255, 255, 255, 0.15); + --black-transparent-light: rgba(255, 255, 255, 0.4); + --black-transparent-dark: rgba(255, 255, 255, 0.6); + --black-transparent-darker: rgba(255, 255, 255, 0.7); + --focus: hsl(217, 89%, 61%); + --whiteboard: hsl(240, 5%, 6.5%); + color-scheme: dark; +} + +.RoomWrapper { + display: flex; + flex-direction: column; + position: absolute; + inset: 0px; +} + +.RoomWrapper-header { + display: flex; + flex-direction: row; + justify-content: flex-start; + align-items: center; + padding: 8px 16px; + gap: 16px; + background: var(--background); + border-bottom: 1px solid var(--gray-dark); + color: var(--text); + font-size: 14px; +} + +.RoomWrapper-copy { + background: var(--black-transparent-lighter); + border: 1px solid var(--gray-dark); + border-radius: 4px; + padding: 4px 12px; + height: 24px; + cursor: pointer; + position: relative; + text-align: center; +} + +.RoomWrapper-copy:has(.RoomWrapper-copied) { + color: transparent; +} + +.RoomWrapper-copied { + color: var(--text); + position: absolute; + inset: 0; + display: flex; + align-items: center; + justify-content: center; +} + +.RoomWrapper-copy:hover { + border: 1px solid var(--black-transparent-lighter); +} + +.RoomWrapper-content { + position: relative; + flex: 1; +} diff --git a/templates/sync-rivet/client/localStorage.ts b/templates/sync-rivet/client/localStorage.ts new file mode 100644 index 000000000000..aab55e16614b --- /dev/null +++ b/templates/sync-rivet/client/localStorage.ts @@ -0,0 +1,23 @@ +export function getLocalStorageItem(key: string): string | null { + try { + return localStorage.getItem(key) + } catch { + return null + } +} + +export function setLocalStorageItem(key: string, value: string): void { + try { + localStorage.setItem(key, value) + } catch { + // localStorage not available + } +} + +export function removeLocalStorageItem(key: string): void { + try { + localStorage.removeItem(key) + } catch { + // localStorage not available + } +} diff --git a/templates/sync-rivet/client/main.tsx b/templates/sync-rivet/client/main.tsx new file mode 100644 index 000000000000..df2ebf1765de --- /dev/null +++ b/templates/sync-rivet/client/main.tsx @@ -0,0 +1,23 @@ +import React from 'react' +import ReactDOM from 'react-dom/client' +import { createBrowserRouter, RouterProvider } from 'react-router-dom' +import './index.css' +import { Room } from './pages/Room' +import { Root } from './pages/Root' + +const router = createBrowserRouter([ + { + path: '/', + element: , + }, + { + path: '/:roomId', + element: , + }, +]) + +ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render( + + + +) diff --git a/templates/sync-rivet/client/multiplayerAssetStore.tsx b/templates/sync-rivet/client/multiplayerAssetStore.tsx new file mode 100644 index 000000000000..bb371ae1325d --- /dev/null +++ b/templates/sync-rivet/client/multiplayerAssetStore.tsx @@ -0,0 +1,24 @@ +import { TLAssetStore, uniqueId } from 'tldraw' + +export const multiplayerAssetStore: TLAssetStore = { + async upload(_asset, file) { + const id = uniqueId() + const objectName = `${id}-${file.name}`.replace(/[^a-zA-Z0-9.]/g, '-') + const url = `/api/uploads/${objectName}` + + const response = await fetch(url, { + method: 'POST', + body: file, + }) + + if (!response.ok) { + throw new Error(`Failed to upload asset: ${response.statusText}`) + } + + return { src: url } + }, + + resolve(asset) { + return asset.props.src + }, +} diff --git a/templates/sync-rivet/client/pages/Room.tsx b/templates/sync-rivet/client/pages/Room.tsx new file mode 100644 index 000000000000..fdfc52045715 --- /dev/null +++ b/templates/sync-rivet/client/pages/Room.tsx @@ -0,0 +1,129 @@ +import { createClient } from 'rivetkit/client' +import { useSync } from '@tldraw/sync' +import { ReactNode, useEffect, useMemo, useState } from 'react' +import { useParams } from 'react-router-dom' +import { Tldraw } from 'tldraw' +import { getBookmarkPreview } from '../getBookmarkPreview' +import { multiplayerAssetStore } from '../multiplayerAssetStore' + +const rivetUrl = import.meta.env.VITE_RIVET_ENDPOINT || 'http://localhost:6420' +const rivetToken = import.meta.env.VITE_RIVET_TOKEN +const rivetNamespace = import.meta.env.VITE_RIVET_NAMESPACE + +const client = createClient({ + endpoint: rivetUrl, + token: rivetToken, + namespace: rivetNamespace, +}) + +export function Room() { + const { roomId } = useParams<{ roomId: string }>() + const [roomUri, setRoomUri] = useState(undefined) + + useEffect(() => { + const loadRoomUri = async () => { + const actorId = await client.tldrawRoom.getOrCreate(roomId!).resolve(); + + const wsOrigin = rivetUrl.replace(/^http/, 'ws') + const params = new URLSearchParams({ + x_rivet_target: 'actor', + x_rivet_actor: actorId, + }) + + if (rivetToken) { + params.set('x_rivet_token', rivetToken) + } + if (rivetNamespace) { + params.set('x_rivet_namespace', rivetNamespace) + } + + const wsUrl = `${wsOrigin}/raw/websocket?${params.toString()}` + setRoomUri(wsUrl) + } + + if (roomId) { + loadRoomUri() + } + }, [roomId]) + + if (!roomUri || !roomId) { + return ( + +