From b51c62957cb38403a1228210966a65820f098f24 Mon Sep 17 00:00:00 2001 From: Okiki Ojo Date: Sat, 6 Jun 2026 01:59:05 +0000 Subject: [PATCH] feat(cloudflare): run bundle execution through compiled wasm modules Update the Worker to consume the shared edge request pipeline, import esbuild's wasm module through Wrangler's CompiledWasm rule, and mirror Deno's response and cache behavior more closely. This commit also adds KV-safe cache key hashing, badge cache invalidation by bundle key, R2-backed file responses, and the .well-known assets needed for public API metadata. The goal is to make the Cloudflare deployment behave like the existing Deno endpoint without relying on runtime wasm compilation that workerd rejects. Pulling these pieces together keeps the Worker deployable while preserving observable API behavior for cached JSON, badges, bundle files, and static discovery routes. --- cloudflare/package.json | 5 +- cloudflare/public/.well-known/ai-plugin.json | 18 + cloudflare/public/.well-known/logo.png | Bin 0 -> 117677 bytes cloudflare/public/.well-known/openapi.yaml | 1822 +++++++++++++++++ .../src/durable-objects/bundle-coordinator.ts | 8 +- cloudflare/src/index.ts | 338 +-- cloudflare/src/result.ts | 9 +- cloudflare/src/shims.d.ts | 16 + cloudflare/src/storage.ts | 95 +- cloudflare/tsconfig.json | 8 +- cloudflare/worker-configuration.d.ts | 32 + cloudflare/wrangler.jsonc | 7 + pnpm-lock.yaml | 134 +- 13 files changed, 2244 insertions(+), 248 deletions(-) create mode 100644 cloudflare/public/.well-known/ai-plugin.json create mode 100644 cloudflare/public/.well-known/logo.png create mode 100644 cloudflare/public/.well-known/openapi.yaml create mode 100644 cloudflare/src/shims.d.ts diff --git a/cloudflare/package.json b/cloudflare/package.json index 538b31d..ec425cc 100644 --- a/cloudflare/package.json +++ b/cloudflare/package.json @@ -6,14 +6,15 @@ "dependencies": { "@bundle/compress": "workspace:*", "@bundle/core": "workspace:*", - "@bundle/utils": "workspace:*" + "@bundle/utils": "workspace:*", + "@nick/dispose": "npm:@jsr/nick__dispose@^1" }, "devDependencies": { "@cloudflare/vitest-pool-workers": "^0.8.34", "@cloudflare/workers-types": "^4.20260410.0", "typescript": "^5.8.3", "vitest": "^3.1.2", - "wrangler": "^4.13.2" + "wrangler": "^4.98.0" }, "scripts": { "dev": "wrangler dev", diff --git a/cloudflare/public/.well-known/ai-plugin.json b/cloudflare/public/.well-known/ai-plugin.json new file mode 100644 index 0000000..d7f4bfd --- /dev/null +++ b/cloudflare/public/.well-known/ai-plugin.json @@ -0,0 +1,18 @@ +{ + "schema_version": "v1", + "name_for_human": "Bundlejs API Plugin", + "name_for_model": "bundlejs_api", + "description_for_human": "Plugin for bundling, treeshaking, transpiling, compressing and minification of JavaScript and TypeScript code", + "description_for_model": "Plugin for bundling, treeshaking, transpiling, compressing and minification of JavaScript and TypeScript code.", + "auth": { + "type": "none" + }, + "api": { + "type": "openapi", + "url": "https://deno.bundlejs.com/.well-known/openapi.yaml", + "is_user_authenticated": false + }, + "logo_url": "https://deno.bundlejs.com/.well-known/logo.png", + "contact_email": "hey@okikio.dev", + "legal_info_url": "https://github.com/okikio/bundlejs/blob/deno-edge/LICENSE" +} \ No newline at end of file diff --git a/cloudflare/public/.well-known/logo.png b/cloudflare/public/.well-known/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..3f2ca4550afc96c1f64b577575d879c292d57063 GIT binary patch literal 117677 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

t13>UEwhk7FKk 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 + `q` or `query` represents the module, e.g. react, vue, etc... + + You can add (import) in-front of a specific module to make it an import instead of an export + example: + > + react,react-dom,(import)spring-easing + - name: treeshake + in: query + description: + > + Represents the export/imports to treeshake. + Treeshake export object using this custom format + + `treeshake` represents the export/imports to treeshake. + The treeshake syntax allows for specifying multiple exports per package, through this syntax + + ```ts + "[{ x,y,z }],[*],[* as X],[{ type xyz }]" + // to + export { x, y, z } from "..."; + export * from "..."; + export * as X from "..."; + export { type xyz } from "..."; + ``` + required: false + schema: + type: string + example: + > + [*],[{default}] + - name: badge + in: query + description: Generate a badge. + required: false + schema: + oneOf: + - type: boolean + - type: string + enum: ["detailed", "minified", "uncompressed"] + - name: badge-style + in: query + description: Badge styles supported by shields.io. + required: false + schema: + type: string + enum: ["flat", "plastic", "flat-square", "for-the-badge", "social"] + - name: badge-raster + in: query + description: The badge as a png image. + required: false + schema: + type: boolean + - name: png + in: query + description: The badge as a png image. + required: false + schema: + type: boolean + - name: file + in: query + description: Resulting bundled code. + required: false + schema: + type: boolean + - name: analysis + in: query + description: Esbuild generate visual analysis. + required: false + schema: + oneOf: + - type: boolean + - type: string + enum: ["verbose"] + - name: metafile + in: query + description: Esbuild bundle metafile. + required: false + schema: + type: boolean + - name: config + in: query + required: false + description: Bundlejs's Config in JSON form, with support for esbuild options in the esbuild field, and "package.json" in the "package.json" field + schema: + type: string + format: json + example: + > + { + "cdn": "https://unpkg.com", + "compression": "gzip", + "analysis": true, + "polyfill": false, + "tsx": false, + "package.json": { + "name": "bundled-code", + "version": "0.0.0", + "dependencies": { + "react": "^16" + } + }, + "esbuild": { + "target": [ + "esnext", + ], + "format": "esm", + "bundle": true, + "minify": true, + "treeShaking": true, + "platform": "browser", + "sourcemap": false, + "external": ["react"], + "alias": { + "react-dom": "https://esm.sh/react-dom" + } + }, + } + - name: polyfill + in: query + description: Polyfill Node built-ins. + required: false + schema: + type: boolean + - name: sourcemap + in: query + description: Esbuild sourcemap. + required: false + schema: + oneOf: + - type: boolean + - type: string + enum: ["inline", "external"] + - name: minify + in: query + description: Esbuild minify. + required: false + schema: + type: boolean + - name: format + in: query + description: Esbuild format. + required: false + schema: + type: string + enum: ["iife", "cjs", "esm"] + - name: warnings + in: query + description: Lists warnings for a particular bundle. + required: false + schema: + type: boolean + - name: raw + in: query + description: The raw result of the bundle. + required: false + schema: + type: boolean + - name: text + in: query + description: Represents the input code as a string. + required: false + schema: + type: string + - name: share + in: query + description: Represents the compressed string version of the input code (compressed using @amoutonbrady/lz-string). + required: false + schema: + type: string + - name: tsx + in: query + description: Support JSX and TSX. + required: false + schema: + type: boolean + responses: + '200': + description: + > + Bundled code, analysis, badge or JSON response. + + The URL breakdown is, + + ```ts + /? + q=(import)@okikio/emitter,(import)@okikio/animate,(import)@okikio/animate,(import)@okikio/animate,(import)@okikio/animate,@okikio/animate,@okikio/animate,@okikio/animate,@okikio/animate& + treeshake=[T],[{ animate }],[{ animate as B }],[* as TR],[{ type animate }],[*],[{ animate as A }],[* as PR],[{ animate }]& + text="export * as PR18 from \"@okikio/animate\";\nexport { animate as animate2 } from \"@okikio/animate\";"& + share=MYewdgziA2CmB00QHMAUAiAwiG6CUQA& + config={"cdn":"skypack","compression":"brotli","esbuild":{"format":"cjs","minify":false,"treeShaking":false}}& + bundle + ``` + + * `q` or `query` represents the module, e.g. `react`, `vue`, etc... + You can add `(import)` in-front of a specific module to make it an import instead of an export + + * `treeshake` represents the export/imports to treeshake. + The treeshake syntax allows for specifying multiple exports per package, through this syntax + + ```ts + "[{ x,y,z }],[*],[* as X],[{ type xyz }]" + // to + export { x, y, z } from "..."; + export * from "..."; + export * as X from "..."; + export { type xyz } from "..."; + ``` + + The square brackets represent seperate packages, and everything inside the squarebrackets, are the exported methods, types, etc... + + * `text` represents the input code as a string (it's used for short input code) + * `share` represents compressed string version of the input code (it's used for large input code) + * `config` represents the bundle configuration to use when building the bundle + * `bundle` tells **bundlejs** to bundle the input code on start-up. This isn't on by default for security reasons. I want to discourage people from sending large complex bundles that crash browsers or that take a long time to load, especially before the input code is properly verified as non-malicious. So, if you want to bundle the code on startup, you have to manually add `&bundle` to the end of the url yourself. + + The reason why I decided on this syntax is because it allows for a lot of flexibility, and transparency concerning what is being bundled. I also wanted to make it easy to share bundle session between users. + + You can add (import) in-front of a specific module to make it an import instead of an export, treeshake represents the export/imports to treeshake. + + The treeshake syntax allows for specifying multiple exports per package, through this syntax + content: + application/json: + schema: + type: object + properties: + query: + type: string + rawQuery: + type: string + version: + type: string + nullable: true + versions: + type: array + items: + type: string + nullable: true + config: + type: object + additionalProperties: true + input: + type: string + size: + type: object + properties: + type: + type: string + rawUncompressedSize: + type: integer + uncompressedSize: + type: string + rawCompressedSize: + type: integer + compressedSize: + type: string + size: + type: string + time: + type: string + rawTime: + type: integer + fileId: + type: string + fileUrl: + type: string + fileHTMLUrl: + type: string + application/javascript: + schema: + type: string + image/svg+xml: + schema: + type: string + example: + > + + + 5.51 kB (gzip): bundlejs + + + + + + + + + + + + + + + + 5.51 kB (gzip) + + bundlejs + + + + + image/png: + schema: + type: string + format: binary + text/plain: + schema: + type: string + example: "index.js 12.9kb 100.0%\n ├ http-url:https://unpkg.com/react@18.2.0/cjs/react.production.min.js 6.3kb 49.0%\n ├ http-url:https://unpkg.com/spring-easing@2.1.2/lib/index.mjs 4.3kb 33.1%\n ├ http-url:https://unpkg.com/react@18.2.0/index.js 50b 0.4%\n └ virtual-filesystem:/index.ts 16b 0.1%" + '400': + description: Bad request + '404': + description: Package not found + content: + text/plain: + schema: + type: string + example: "✘ [ERROR] [getRequest] Failed at request (https://unpkg.com/reac@0.0.0)\nError: Couldn't load https://unpkg.com/reac@0.0.0/index.js (404 code) [plugin cdn-url]\n\n virtual-filesystem:/index.ts:2:14:\n\n 2 │ export * from \"reac\";\n ╵ ~~~~~~" + '500': + description: Internal server error + + /badge: + get: + operationId: getBundleBadge + summary: Bundle, treeshake and minify JavaScript and TypeScript code, and respond with a badge. + parameters: + - name: q + in: query + description: Represents the modules to bundle. + required: false + schema: + type: string + description: + > + `q` or `query` represents the module, e.g. react, vue, etc... + + You can add (import) in-front of a specific module to make it an import instead of an export + example: + > + react,react-dom,(import)spring-easing + - name: treeshake + in: query + description: + > + Represents the export/imports to treeshake. + Treeshake export object using this custom format + + `treeshake` represents the export/imports to treeshake. + The treeshake syntax allows for specifying multiple exports per package, through this syntax + + ```ts + "[{ x,y,z }],[*],[* as X],[{ type xyz }]" + // to + export { x, y, z } from "..."; + export * from "..."; + export * as X from "..."; + export { type xyz } from "..."; + ``` + required: false + schema: + type: string + example: + > + [*],[{default}] + - name: badge + in: query + description: Generate a badge. + required: false + schema: + oneOf: + - type: boolean + - type: string + enum: ["detailed", "minified", "uncompressed"] + - name: badge-style + in: query + description: Badge styles supported by shields.io. + required: false + schema: + type: string + enum: ["flat", "plastic", "flat-square", "for-the-badge", "social"] + - name: badge-raster + in: query + description: The badge as a png image. + required: false + schema: + type: boolean + - name: png + in: query + description: The badge as a png image. + required: false + schema: + type: boolean + - name: config + in: query + required: false + description: Bundlejs's Config in JSON form, with support for esbuild options in the esbuild field, and "package.json" in the "package.json" field + schema: + type: string + format: json + example: + > + { + "cdn": "https://unpkg.com", + "compression": "gzip", + "analysis": true, + "polyfill": false, + "tsx": false, + "package.json": { + "name": "bundled-code", + "version": "0.0.0", + "dependencies": { + "react": "^16" + } + }, + "esbuild": { + "target": [ + "esnext", + ], + "format": "esm", + "bundle": true, + "minify": true, + "treeShaking": true, + "platform": "browser", + "sourcemap": false, + "external": ["react"], + "alias": { + "react-dom": "https://esm.sh/react-dom" + } + }, + } + - name: polyfill + in: query + description: Polyfill Node built-ins. + required: false + schema: + type: boolean + - name: sourcemap + in: query + description: Esbuild sourcemap. + required: false + schema: + oneOf: + - type: boolean + - type: string + enum: ["inline", "external"] + - name: minify + in: query + description: Esbuild minify. + required: false + schema: + type: boolean + - name: format + in: query + description: Esbuild format. + required: false + schema: + type: string + enum: ["iife", "cjs", "esm"] + - name: text + in: query + description: Represents the input code as a string. + required: false + schema: + type: string + - name: share + in: query + description: Represents the compressed string version of the input code (compressed using @amoutonbrady/lz-string). + required: false + schema: + type: string + - name: tsx + in: query + description: Support JSX and TSX. + required: false + schema: + type: boolean + responses: + '200': + description: + > + Bundled code, analysis, badge or JSON response. + + The URL breakdown is, + + ```ts + /? + q=(import)@okikio/emitter,(import)@okikio/animate,(import)@okikio/animate,(import)@okikio/animate,(import)@okikio/animate,@okikio/animate,@okikio/animate,@okikio/animate,@okikio/animate& + treeshake=[T],[{ animate }],[{ animate as B }],[* as TR],[{ type animate }],[*],[{ animate as A }],[* as PR],[{ animate }]& + text="export * as PR18 from \"@okikio/animate\";\nexport { animate as animate2 } from \"@okikio/animate\";"& + share=MYewdgziA2CmB00QHMAUAiAwiG6CUQA& + config={"cdn":"skypack","compression":"brotli","esbuild":{"format":"cjs","minify":false,"treeShaking":false}}& + bundle + ``` + + * `q` or `query` represents the module, e.g. `react`, `vue`, etc... + You can add `(import)` in-front of a specific module to make it an import instead of an export + + * `treeshake` represents the export/imports to treeshake. + The treeshake syntax allows for specifying multiple exports per package, through this syntax + + ```ts + "[{ x,y,z }],[*],[* as X],[{ type xyz }]" + // to + export { x, y, z } from "..."; + export * from "..."; + export * as X from "..."; + export { type xyz } from "..."; + ``` + + The square brackets represent seperate packages, and everything inside the squarebrackets, are the exported methods, types, etc... + + * `text` represents the input code as a string (it's used for short input code) + * `share` represents compressed string version of the input code (it's used for large input code) + * `config` represents the bundle configuration to use when building the bundle + * `bundle` tells **bundlejs** to bundle the input code on start-up. This isn't on by default for security reasons. I want to discourage people from sending large complex bundles that crash browsers or that take a long time to load, especially before the input code is properly verified as non-malicious. So, if you want to bundle the code on startup, you have to manually add `&bundle` to the end of the url yourself. + + The reason why I decided on this syntax is because it allows for a lot of flexibility, and transparency concerning what is being bundled. I also wanted to make it easy to share bundle session between users. + + You can add (import) in-front of a specific module to make it an import instead of an export, treeshake represents the export/imports to treeshake. + + The treeshake syntax allows for specifying multiple exports per package, through this syntax + content: + image/svg+xml: + schema: + type: string + example: + > + + + 5.51 kB (gzip): bundlejs + + + + + + + + + + + + + + + + 5.51 kB (gzip) + + bundlejs + + + + image/png: + schema: + type: string + format: binary + '400': + description: Bad request + '404': + description: Package not found + content: + text/plain: + schema: + type: string + example: "✘ [ERROR] [getRequest] Failed at request (https://unpkg.com/reac@0.0.0)\nError: Couldn't load https://unpkg.com/reac@0.0.0/index.js (404 code) [plugin cdn-url]\n\n virtual-filesystem:/index.ts:2:14:\n\n 2 │ export * from \"reac\";\n ╵ ~~~~~~" + '500': + description: Internal server error + + /badge/raster: + get: + operationId: getBundleBadgeRasterPNG + summary: Bundle, treeshake and minify JavaScript and TypeScript code and respond with a badge raster badge (think png). + parameters: + - name: q + in: query + description: Represents the modules to bundle. + required: false + schema: + type: string + description: + > + `q` or `query` represents the module, e.g. react, vue, etc... + + You can add (import) in-front of a specific module to make it an import instead of an export + example: + > + react,react-dom,(import)spring-easing + - name: treeshake + in: query + description: + > + Represents the export/imports to treeshake. + Treeshake export object using this custom format + + `treeshake` represents the export/imports to treeshake. + The treeshake syntax allows for specifying multiple exports per package, through this syntax + + ```ts + "[{ x,y,z }],[*],[* as X],[{ type xyz }]" + // to + export { x, y, z } from "..."; + export * from "..."; + export * as X from "..."; + export { type xyz } from "..."; + ``` + required: false + schema: + type: string + example: + > + [*],[{default}] + - name: badge + in: query + description: Generate a badge. + required: false + schema: + oneOf: + - type: boolean + - type: string + enum: ["detailed", "minified", "uncompressed"] + - name: badge-style + in: query + description: Badge styles supported by shields.io. + required: false + schema: + type: string + enum: ["flat", "plastic", "flat-square", "for-the-badge", "social"] + - name: badge-raster + in: query + description: The badge as a png image. + required: false + schema: + type: boolean + - name: png + in: query + description: The badge as a png image. + required: false + schema: + type: boolean + - name: config + in: query + required: false + description: Bundlejs's Config in JSON form, with support for esbuild options in the esbuild field, and "package.json" in the "package.json" field + schema: + type: string + format: json + example: + > + { + "cdn": "https://unpkg.com", + "compression": "gzip", + "analysis": true, + "polyfill": false, + "tsx": false, + "package.json": { + "name": "bundled-code", + "version": "0.0.0", + "dependencies": { + "react": "^16" + } + }, + "esbuild": { + "target": [ + "esnext", + ], + "format": "esm", + "bundle": true, + "minify": true, + "treeShaking": true, + "platform": "browser", + "sourcemap": false, + "external": ["react"], + "alias": { + "react-dom": "https://esm.sh/react-dom" + } + }, + } + - name: polyfill + in: query + description: Polyfill Node built-ins. + required: false + schema: + type: boolean + - name: sourcemap + in: query + description: Esbuild sourcemap. + required: false + schema: + oneOf: + - type: boolean + - type: string + enum: ["inline", "external"] + - name: minify + in: query + description: Esbuild minify. + required: false + schema: + type: boolean + - name: format + in: query + description: Esbuild format. + required: false + schema: + type: string + enum: ["iife", "cjs", "esm"] + - name: text + in: query + description: Represents the input code as a string. + required: false + schema: + type: string + - name: share + in: query + description: Represents the compressed string version of the input code (compressed using @amoutonbrady/lz-string). + required: false + schema: + type: string + - name: tsx + in: query + description: Support JSX and TSX. + required: false + schema: + type: boolean + responses: + '200': + description: + > + Bundled code, analysis, badge or JSON response. + + The URL breakdown is, + + ```ts + /? + q=(import)@okikio/emitter,(import)@okikio/animate,(import)@okikio/animate,(import)@okikio/animate,(import)@okikio/animate,@okikio/animate,@okikio/animate,@okikio/animate,@okikio/animate& + treeshake=[T],[{ animate }],[{ animate as B }],[* as TR],[{ type animate }],[*],[{ animate as A }],[* as PR],[{ animate }]& + text="export * as PR18 from \"@okikio/animate\";\nexport { animate as animate2 } from \"@okikio/animate\";"& + share=MYewdgziA2CmB00QHMAUAiAwiG6CUQA& + config={"cdn":"skypack","compression":"brotli","esbuild":{"format":"cjs","minify":false,"treeShaking":false}}& + bundle + ``` + + * `q` or `query` represents the module, e.g. `react`, `vue`, etc... + You can add `(import)` in-front of a specific module to make it an import instead of an export + + * `treeshake` represents the export/imports to treeshake. + The treeshake syntax allows for specifying multiple exports per package, through this syntax + + ```ts + "[{ x,y,z }],[*],[* as X],[{ type xyz }]" + // to + export { x, y, z } from "..."; + export * from "..."; + export * as X from "..."; + export { type xyz } from "..."; + ``` + + The square brackets represent seperate packages, and everything inside the squarebrackets, are the exported methods, types, etc... + + * `text` represents the input code as a string (it's used for short input code) + * `share` represents compressed string version of the input code (it's used for large input code) + * `config` represents the bundle configuration to use when building the bundle + * `bundle` tells **bundlejs** to bundle the input code on start-up. This isn't on by default for security reasons. I want to discourage people from sending large complex bundles that crash browsers or that take a long time to load, especially before the input code is properly verified as non-malicious. So, if you want to bundle the code on startup, you have to manually add `&bundle` to the end of the url yourself. + + The reason why I decided on this syntax is because it allows for a lot of flexibility, and transparency concerning what is being bundled. I also wanted to make it easy to share bundle session between users. + + You can add (import) in-front of a specific module to make it an import instead of an export, treeshake represents the export/imports to treeshake. + + The treeshake syntax allows for specifying multiple exports per package, through this syntax + content: + image/png: + schema: + type: string + format: binary + '400': + description: Bad request + '404': + description: Package not found + content: + text/plain: + schema: + type: string + example: "✘ [ERROR] [getRequest] Failed at request (https://unpkg.com/reac@0.0.0)\nError: Couldn't load https://unpkg.com/reac@0.0.0/index.js (404 code) [plugin cdn-url]\n\n virtual-filesystem:/index.ts:2:14:\n\n 2 │ export * from \"reac\";\n ╵ ~~~~~~" + '500': + description: Internal server error + + /file: + get: + operationId: getBundledFile + summary: Bundle, treeshake and minify JavaScript and TypeScript code and respond with the actual javascript bundle. + parameters: + - name: q + in: query + description: Represents the modules to bundle. + required: false + schema: + type: string + description: + > + `q` or `query` represents the module, e.g. react, vue, etc... + + You can add (import) in-front of a specific module to make it an import instead of an export + example: + > + react,react-dom,(import)spring-easing + - name: treeshake + in: query + description: + > + Represents the export/imports to treeshake. + Treeshake export object using this custom format + + `treeshake` represents the export/imports to treeshake. + The treeshake syntax allows for specifying multiple exports per package, through this syntax + + ```ts + "[{ x,y,z }],[*],[* as X],[{ type xyz }]" + // to + export { x, y, z } from "..."; + export * from "..."; + export * as X from "..."; + export { type xyz } from "..."; + ``` + required: false + schema: + type: string + example: + > + [*],[{default}] + - name: file + in: query + description: Resulting bundled code. + required: false + schema: + type: boolean + - name: config + in: query + required: false + description: Bundlejs's Config in JSON form, with support for esbuild options in the esbuild field, and "package.json" in the "package.json" field + schema: + type: string + format: json + example: + > + { + "cdn": "https://unpkg.com", + "compression": "gzip", + "analysis": true, + "polyfill": false, + "tsx": false, + "package.json": { + "name": "bundled-code", + "version": "0.0.0", + "dependencies": { + "react": "^16" + } + }, + "esbuild": { + "target": [ + "esnext", + ], + "format": "esm", + "bundle": true, + "minify": true, + "treeShaking": true, + "platform": "browser", + "sourcemap": false, + "external": ["react"], + "alias": { + "react-dom": "https://esm.sh/react-dom" + } + }, + } + - name: polyfill + in: query + description: Polyfill Node built-ins. + required: false + schema: + type: boolean + - name: sourcemap + in: query + description: Esbuild sourcemap. + required: false + schema: + oneOf: + - type: boolean + - type: string + enum: ["inline", "external"] + - name: minify + in: query + description: Esbuild minify. + required: false + schema: + type: boolean + - name: format + in: query + description: Esbuild format. + required: false + schema: + type: string + enum: ["iife", "cjs", "esm"] + - name: text + in: query + description: Represents the input code as a string. + required: false + schema: + type: string + - name: share + in: query + description: Represents the compressed string version of the input code (compressed using @amoutonbrady/lz-string). + required: false + schema: + type: string + - name: tsx + in: query + description: Support JSX and TSX. + required: false + schema: + type: boolean + responses: + '200': + description: + > + Bundled code, analysis, badge or JSON response. + + The URL breakdown is, + + ```ts + /? + q=(import)@okikio/emitter,(import)@okikio/animate,(import)@okikio/animate,(import)@okikio/animate,(import)@okikio/animate,@okikio/animate,@okikio/animate,@okikio/animate,@okikio/animate& + treeshake=[T],[{ animate }],[{ animate as B }],[* as TR],[{ type animate }],[*],[{ animate as A }],[* as PR],[{ animate }]& + text="export * as PR18 from \"@okikio/animate\";\nexport { animate as animate2 } from \"@okikio/animate\";"& + share=MYewdgziA2CmB00QHMAUAiAwiG6CUQA& + config={"cdn":"skypack","compression":"brotli","esbuild":{"format":"cjs","minify":false,"treeShaking":false}}& + bundle + ``` + + * `q` or `query` represents the module, e.g. `react`, `vue`, etc... + You can add `(import)` in-front of a specific module to make it an import instead of an export + + * `treeshake` represents the export/imports to treeshake. + The treeshake syntax allows for specifying multiple exports per package, through this syntax + + ```ts + "[{ x,y,z }],[*],[* as X],[{ type xyz }]" + // to + export { x, y, z } from "..."; + export * from "..."; + export * as X from "..."; + export { type xyz } from "..."; + ``` + + The square brackets represent seperate packages, and everything inside the squarebrackets, are the exported methods, types, etc... + + * `text` represents the input code as a string (it's used for short input code) + * `share` represents compressed string version of the input code (it's used for large input code) + * `config` represents the bundle configuration to use when building the bundle + * `bundle` tells **bundlejs** to bundle the input code on start-up. This isn't on by default for security reasons. I want to discourage people from sending large complex bundles that crash browsers or that take a long time to load, especially before the input code is properly verified as non-malicious. So, if you want to bundle the code on startup, you have to manually add `&bundle` to the end of the url yourself. + + The reason why I decided on this syntax is because it allows for a lot of flexibility, and transparency concerning what is being bundled. I also wanted to make it easy to share bundle session between users. + + You can add (import) in-front of a specific module to make it an import instead of an export, treeshake represents the export/imports to treeshake. + + The treeshake syntax allows for specifying multiple exports per package, through this syntax + content: + application/javascript: + schema: + type: string + '400': + description: Bad request + '404': + description: Package not found + content: + text/plain: + schema: + type: string + example: "✘ [ERROR] [getRequest] Failed at request (https://unpkg.com/reac@0.0.0)\nError: Couldn't load https://unpkg.com/reac@0.0.0/index.js (404 code) [plugin cdn-url]\n\n virtual-filesystem:/index.ts:2:14:\n\n 2 │ export * from \"reac\";\n ╵ ~~~~~~" + '500': + description: Internal server error + + /analysis: + get: + operationId: getBundleAnalysis + summary: Bundle, treeshake and minify JavaScript and TypeScript code and respond with the bundle analysis, in esbuild analysis format. + parameters: + - name: q + in: query + description: Represents the modules to bundle. + required: false + schema: + type: string + description: + > + `q` or `query` represents the module, e.g. react, vue, etc... + + You can add (import) in-front of a specific module to make it an import instead of an export + example: + > + react,react-dom,(import)spring-easing + - name: treeshake + in: query + description: + > + Represents the export/imports to treeshake. + Treeshake export object using this custom format + + `treeshake` represents the export/imports to treeshake. + The treeshake syntax allows for specifying multiple exports per package, through this syntax + + ```ts + "[{ x,y,z }],[*],[* as X],[{ type xyz }]" + // to + export { x, y, z } from "..."; + export * from "..."; + export * as X from "..."; + export { type xyz } from "..."; + ``` + required: false + schema: + type: string + example: + > + [*],[{default}] + - name: analysis + in: query + description: Esbuild generate visual analysis. + required: false + schema: + oneOf: + - type: boolean + - type: string + enum: ["verbose"] + - name: config + in: query + required: false + description: Bundlejs's Config in JSON form, with support for esbuild options in the esbuild field, and "package.json" in the "package.json" field + schema: + type: string + format: json + example: + > + { + "cdn": "https://unpkg.com", + "compression": "gzip", + "analysis": true, + "polyfill": false, + "tsx": false, + "package.json": { + "name": "bundled-code", + "version": "0.0.0", + "dependencies": { + "react": "^16" + } + }, + "esbuild": { + "target": [ + "esnext", + ], + "format": "esm", + "bundle": true, + "minify": true, + "treeShaking": true, + "platform": "browser", + "sourcemap": false, + "external": ["react"], + "alias": { + "react-dom": "https://esm.sh/react-dom" + } + }, + } + - name: polyfill + in: query + description: Polyfill Node built-ins. + required: false + schema: + type: boolean + - name: sourcemap + in: query + description: Esbuild sourcemap. + required: false + schema: + oneOf: + - type: boolean + - type: string + enum: ["inline", "external"] + - name: minify + in: query + description: Esbuild minify. + required: false + schema: + type: boolean + - name: format + in: query + description: Esbuild format. + required: false + schema: + type: string + enum: ["iife", "cjs", "esm"] + - name: text + in: query + description: Represents the input code as a string. + required: false + schema: + type: string + - name: share + in: query + description: Represents the compressed string version of the input code (compressed using @amoutonbrady/lz-string). + required: false + schema: + type: string + - name: tsx + in: query + description: Support JSX and TSX. + required: false + schema: + type: boolean + responses: + '200': + description: + > + Bundled code, analysis, badge or JSON response. + + The URL breakdown is, + + ```ts + /? + q=(import)@okikio/emitter,(import)@okikio/animate,(import)@okikio/animate,(import)@okikio/animate,(import)@okikio/animate,@okikio/animate,@okikio/animate,@okikio/animate,@okikio/animate& + treeshake=[T],[{ animate }],[{ animate as B }],[* as TR],[{ type animate }],[*],[{ animate as A }],[* as PR],[{ animate }]& + text="export * as PR18 from \"@okikio/animate\";\nexport { animate as animate2 } from \"@okikio/animate\";"& + share=MYewdgziA2CmB00QHMAUAiAwiG6CUQA& + config={"cdn":"skypack","compression":"brotli","esbuild":{"format":"cjs","minify":false,"treeShaking":false}}& + bundle + ``` + + * `q` or `query` represents the module, e.g. `react`, `vue`, etc... + You can add `(import)` in-front of a specific module to make it an import instead of an export + + * `treeshake` represents the export/imports to treeshake. + The treeshake syntax allows for specifying multiple exports per package, through this syntax + + ```ts + "[{ x,y,z }],[*],[* as X],[{ type xyz }]" + // to + export { x, y, z } from "..."; + export * from "..."; + export * as X from "..."; + export { type xyz } from "..."; + ``` + + The square brackets represent seperate packages, and everything inside the squarebrackets, are the exported methods, types, etc... + + * `text` represents the input code as a string (it's used for short input code) + * `share` represents compressed string version of the input code (it's used for large input code) + * `config` represents the bundle configuration to use when building the bundle + * `bundle` tells **bundlejs** to bundle the input code on start-up. This isn't on by default for security reasons. I want to discourage people from sending large complex bundles that crash browsers or that take a long time to load, especially before the input code is properly verified as non-malicious. So, if you want to bundle the code on startup, you have to manually add `&bundle` to the end of the url yourself. + + The reason why I decided on this syntax is because it allows for a lot of flexibility, and transparency concerning what is being bundled. I also wanted to make it easy to share bundle session between users. + + You can add (import) in-front of a specific module to make it an import instead of an export, treeshake represents the export/imports to treeshake. + + The treeshake syntax allows for specifying multiple exports per package, through this syntax + content: + text/plain: + schema: + type: string + example: "index.js 12.9kb 100.0%\n ├ http-url:https://unpkg.com/react@18.2.0/cjs/react.production.min.js 6.3kb 49.0%\n ├ http-url:https://unpkg.com/spring-easing@2.1.2/lib/index.mjs 4.3kb 33.1%\n ├ http-url:https://unpkg.com/react@18.2.0/index.js 50b 0.4%\n └ virtual-filesystem:/index.ts 16b 0.1%" + '400': + description: Bad request + '404': + description: Package not found + content: + text/plain: + schema: + type: string + example: "✘ [ERROR] [getRequest] Failed at request (https://unpkg.com/reac@0.0.0)\nError: Couldn't load https://unpkg.com/reac@0.0.0/index.js (404 code) [plugin cdn-url]\n\n virtual-filesystem:/index.ts:2:14:\n\n 2 │ export * from \"reac\";\n ╵ ~~~~~~" + '500': + description: Internal server error + + /metafile: + get: + operationId: getBundleMetafileFromEsbuild + summary: Bundle, treeshake and minify JavaScript and TypeScript code and respond with it's metafile. + parameters: + - name: q + in: query + description: Represents the modules to bundle. + required: false + schema: + type: string + description: + > + `q` or `query` represents the module, e.g. react, vue, etc... + + You can add (import) in-front of a specific module to make it an import instead of an export + example: + > + react,react-dom,(import)spring-easing + - name: treeshake + in: query + description: + > + Represents the export/imports to treeshake. + Treeshake export object using this custom format + + `treeshake` represents the export/imports to treeshake. + The treeshake syntax allows for specifying multiple exports per package, through this syntax + + ```ts + "[{ x,y,z }],[*],[* as X],[{ type xyz }]" + // to + export { x, y, z } from "..."; + export * from "..."; + export * as X from "..."; + export { type xyz } from "..."; + ``` + required: false + schema: + type: string + example: + > + [*],[{default}] + - name: metafile + in: query + description: Esbuild bundle metafile. + required: false + schema: + type: boolean + - name: config + in: query + required: false + description: Bundlejs's Config in JSON form, with support for esbuild options in the esbuild field, and "package.json" in the "package.json" field + schema: + type: string + format: json + example: + > + { + "cdn": "https://unpkg.com", + "compression": "gzip", + "analysis": true, + "polyfill": false, + "tsx": false, + "package.json": { + "name": "bundled-code", + "version": "0.0.0", + "dependencies": { + "react": "^16" + } + }, + "esbuild": { + "target": [ + "esnext", + ], + "format": "esm", + "bundle": true, + "minify": true, + "treeShaking": true, + "platform": "browser", + "sourcemap": false, + "external": ["react"], + "alias": { + "react-dom": "https://esm.sh/react-dom" + } + }, + } + - name: polyfill + in: query + description: Polyfill Node built-ins. + required: false + schema: + type: boolean + - name: sourcemap + in: query + description: Esbuild sourcemap. + required: false + schema: + oneOf: + - type: boolean + - type: string + enum: ["inline", "external"] + - name: minify + in: query + description: Esbuild minify. + required: false + schema: + type: boolean + - name: format + in: query + description: Esbuild format. + required: false + schema: + type: string + enum: ["iife", "cjs", "esm"] + - name: warnings + in: query + description: Lists warnings for a particular bundle. + required: false + schema: + type: boolean + - name: share + in: query + description: Represents the compressed string version of the input code (compressed using @amoutonbrady/lz-string). + required: false + schema: + type: string + - name: tsx + in: query + description: Support JSX and TSX. + required: false + schema: + type: boolean + responses: + '200': + description: + > + Bundled code, analysis, badge or JSON response. + + The URL breakdown is, + + ```ts + /? + q=(import)@okikio/emitter,(import)@okikio/animate,(import)@okikio/animate,(import)@okikio/animate,(import)@okikio/animate,@okikio/animate,@okikio/animate,@okikio/animate,@okikio/animate& + treeshake=[T],[{ animate }],[{ animate as B }],[* as TR],[{ type animate }],[*],[{ animate as A }],[* as PR],[{ animate }]& + text="export * as PR18 from \"@okikio/animate\";\nexport { animate as animate2 } from \"@okikio/animate\";"& + share=MYewdgziA2CmB00QHMAUAiAwiG6CUQA& + config={"cdn":"skypack","compression":"brotli","esbuild":{"format":"cjs","minify":false,"treeShaking":false}}& + bundle + ``` + + * `q` or `query` represents the module, e.g. `react`, `vue`, etc... + You can add `(import)` in-front of a specific module to make it an import instead of an export + + * `treeshake` represents the export/imports to treeshake. + The treeshake syntax allows for specifying multiple exports per package, through this syntax + + ```ts + "[{ x,y,z }],[*],[* as X],[{ type xyz }]" + // to + export { x, y, z } from "..."; + export * from "..."; + export * as X from "..."; + export { type xyz } from "..."; + ``` + + The square brackets represent seperate packages, and everything inside the squarebrackets, are the exported methods, types, etc... + + * `text` represents the input code as a string (it's used for short input code) + * `share` represents compressed string version of the input code (it's used for large input code) + * `config` represents the bundle configuration to use when building the bundle + * `bundle` tells **bundlejs** to bundle the input code on start-up. This isn't on by default for security reasons. I want to discourage people from sending large complex bundles that crash browsers or that take a long time to load, especially before the input code is properly verified as non-malicious. So, if you want to bundle the code on startup, you have to manually add `&bundle` to the end of the url yourself. + + The reason why I decided on this syntax is because it allows for a lot of flexibility, and transparency concerning what is being bundled. I also wanted to make it easy to share bundle session between users. + + You can add (import) in-front of a specific module to make it an import instead of an export, treeshake represents the export/imports to treeshake. + + The treeshake syntax allows for specifying multiple exports per package, through this syntax + content: + text/plain: + schema: + type: string + example: "index.js 12.9kb 100.0%\n ├ http-url:https://unpkg.com/react@18.2.0/cjs/react.production.min.js 6.3kb 49.0%\n ├ http-url:https://unpkg.com/spring-easing@2.1.2/lib/index.mjs 4.3kb 33.1%\n ├ http-url:https://unpkg.com/react@18.2.0/index.js 50b 0.4%\n └ virtual-filesystem:/index.ts 16b 0.1%" + '400': + description: Bad request + '404': + description: Package not found + content: + text/plain: + schema: + type: string + example: "✘ [ERROR] [getRequest] Failed at request (https://unpkg.com/reac@0.0.0)\nError: Couldn't load https://unpkg.com/reac@0.0.0/index.js (404 code) [plugin cdn-url]\n\n virtual-filesystem:/index.ts:2:14:\n\n 2 │ export * from \"reac\";\n ╵ ~~~~~~" + '500': + description: Internal server error + + /warnings: + get: + operationId: getBundleWarnings + summary: Bundle, treeshake and minify JavaScript and TypeScript code and respond with a list of warnings that may potentially causes issues. + parameters: + - name: q + in: query + description: Represents the modules to bundle. + required: false + schema: + type: string + description: + > + `q` or `query` represents the module, e.g. react, vue, etc... + + You can add (import) in-front of a specific module to make it an import instead of an export + example: + > + react,react-dom,(import)spring-easing + - name: treeshake + in: query + description: + > + Represents the export/imports to treeshake. + Treeshake export object using this custom format + + `treeshake` represents the export/imports to treeshake. + The treeshake syntax allows for specifying multiple exports per package, through this syntax + + ```ts + "[{ x,y,z }],[*],[* as X],[{ type xyz }]" + // to + export { x, y, z } from "..."; + export * from "..."; + export * as X from "..."; + export { type xyz } from "..."; + ``` + required: false + schema: + type: string + example: + > + [*],[{default}] + - name: file + in: query + description: Resulting bundled code. + required: false + schema: + type: boolean + - name: config + in: query + required: false + description: Bundlejs's Config in JSON form, with support for esbuild options in the esbuild field, and "package.json" in the "package.json" field + schema: + type: string + format: json + example: + > + { + "cdn": "https://unpkg.com", + "compression": "gzip", + "analysis": true, + "polyfill": false, + "tsx": false, + "package.json": { + "name": "bundled-code", + "version": "0.0.0", + "dependencies": { + "react": "^16" + } + }, + "esbuild": { + "target": [ + "esnext", + ], + "format": "esm", + "bundle": true, + "minify": true, + "treeShaking": true, + "platform": "browser", + "sourcemap": false, + "external": ["react"], + "alias": { + "react-dom": "https://esm.sh/react-dom" + } + }, + } + - name: polyfill + in: query + description: Polyfill Node built-ins. + required: false + schema: + type: boolean + - name: sourcemap + in: query + description: Esbuild sourcemap. + required: false + schema: + oneOf: + - type: boolean + - type: string + enum: ["inline", "external"] + - name: minify + in: query + description: Esbuild minify. + required: false + schema: + type: boolean + - name: format + in: query + description: Esbuild format. + required: false + schema: + type: string + enum: ["iife", "cjs", "esm"] + - name: text + in: query + description: Represents the input code as a string. + required: false + schema: + type: string + - name: share + in: query + description: Represents the compressed string version of the input code (compressed using @amoutonbrady/lz-string). + required: false + schema: + type: string + - name: tsx + in: query + description: Support JSX and TSX. + required: false + schema: + type: boolean + responses: + '200': + description: + > + Bundled code, analysis, badge or JSON response. + + The URL breakdown is, + + ```ts + /? + q=(import)@okikio/emitter,(import)@okikio/animate,(import)@okikio/animate,(import)@okikio/animate,(import)@okikio/animate,@okikio/animate,@okikio/animate,@okikio/animate,@okikio/animate& + treeshake=[T],[{ animate }],[{ animate as B }],[* as TR],[{ type animate }],[*],[{ animate as A }],[* as PR],[{ animate }]& + text="export * as PR18 from \"@okikio/animate\";\nexport { animate as animate2 } from \"@okikio/animate\";"& + share=MYewdgziA2CmB00QHMAUAiAwiG6CUQA& + config={"cdn":"skypack","compression":"brotli","esbuild":{"format":"cjs","minify":false,"treeShaking":false}}& + bundle + ``` + + * `q` or `query` represents the module, e.g. `react`, `vue`, etc... + You can add `(import)` in-front of a specific module to make it an import instead of an export + + * `treeshake` represents the export/imports to treeshake. + The treeshake syntax allows for specifying multiple exports per package, through this syntax + + ```ts + "[{ x,y,z }],[*],[* as X],[{ type xyz }]" + // to + export { x, y, z } from "..."; + export * from "..."; + export * as X from "..."; + export { type xyz } from "..."; + ``` + + The square brackets represent seperate packages, and everything inside the squarebrackets, are the exported methods, types, etc... + + * `text` represents the input code as a string (it's used for short input code) + * `share` represents compressed string version of the input code (it's used for large input code) + * `config` represents the bundle configuration to use when building the bundle + * `bundle` tells **bundlejs** to bundle the input code on start-up. This isn't on by default for security reasons. I want to discourage people from sending large complex bundles that crash browsers or that take a long time to load, especially before the input code is properly verified as non-malicious. So, if you want to bundle the code on startup, you have to manually add `&bundle` to the end of the url yourself. + + The reason why I decided on this syntax is because it allows for a lot of flexibility, and transparency concerning what is being bundled. I also wanted to make it easy to share bundle session between users. + + You can add (import) in-front of a specific module to make it an import instead of an export, treeshake represents the export/imports to treeshake. + + The treeshake syntax allows for specifying multiple exports per package, through this syntax + content: + text/plain: + schema: + type: string + '400': + description: Bad request + '404': + description: Package not found + content: + text/plain: + schema: + type: string + example: "✘ [ERROR] [getRequest] Failed at request (https://unpkg.com/reac@0.0.0)\nError: Couldn't load https://unpkg.com/reac@0.0.0/index.js (404 code) [plugin cdn-url]\n\n virtual-filesystem:/index.ts:2:14:\n\n 2 │ export * from \"reac\";\n ╵ ~~~~~~" + '500': + description: Internal server error + + /raw: + get: + operationId: getRawBundleMetadataAsJSON + summary: Bundle, treeshake and minify JavaScript and TypeScript code and respond with a JSON object listing the raw metadata with no extra processing. + parameters: + - name: q + in: query + description: Represents the modules to bundle. + required: false + schema: + type: string + description: + > + `q` or `query` represents the module, e.g. react, vue, etc... + + You can add (import) in-front of a specific module to make it an import instead of an export + example: + > + react,react-dom,(import)spring-easing + - name: treeshake + in: query + description: + > + Represents the export/imports to treeshake. + Treeshake export object using this custom format + + `treeshake` represents the export/imports to treeshake. + The treeshake syntax allows for specifying multiple exports per package, through this syntax + + ```ts + "[{ x,y,z }],[*],[* as X],[{ type xyz }]" + // to + export { x, y, z } from "..."; + export * from "..."; + export * as X from "..."; + export { type xyz } from "..."; + ``` + required: false + schema: + type: string + example: + > + [*],[{default}] + - name: config + in: query + required: false + description: Bundlejs's Config in JSON form, with support for esbuild options in the esbuild field, and "package.json" in the "package.json" field + schema: + type: string + format: json + example: + > + { + "cdn": "https://unpkg.com", + "compression": "gzip", + "analysis": true, + "polyfill": false, + "tsx": false, + "package.json": { + "name": "bundled-code", + "version": "0.0.0", + "dependencies": { + "react": "^16" + } + }, + "esbuild": { + "target": [ + "esnext", + ], + "format": "esm", + "bundle": true, + "minify": true, + "treeShaking": true, + "platform": "browser", + "sourcemap": false, + "external": ["react"], + "alias": { + "react-dom": "https://esm.sh/react-dom" + } + }, + } + - name: polyfill + in: query + description: Polyfill Node built-ins. + required: false + schema: + type: boolean + - name: sourcemap + in: query + description: Esbuild sourcemap. + required: false + schema: + oneOf: + - type: boolean + - type: string + enum: ["inline", "external"] + - name: minify + in: query + description: Esbuild minify. + required: false + schema: + type: boolean + - name: format + in: query + description: Esbuild format. + required: false + schema: + type: string + enum: ["iife", "cjs", "esm"] + - name: raw + in: query + description: The raw result of the bundle. + required: false + schema: + type: boolean + - name: text + in: query + description: Represents the input code as a string. + required: false + schema: + type: string + - name: share + in: query + description: Represents the compressed string version of the input code (compressed using @amoutonbrady/lz-string). + required: false + schema: + type: string + - name: tsx + in: query + description: Support JSX and TSX. + required: false + schema: + type: boolean + responses: + '200': + description: + > + Bundled code, analysis, badge or JSON response. + + The URL breakdown is, + + ```ts + /? + q=(import)@okikio/emitter,(import)@okikio/animate,(import)@okikio/animate,(import)@okikio/animate,(import)@okikio/animate,@okikio/animate,@okikio/animate,@okikio/animate,@okikio/animate& + treeshake=[T],[{ animate }],[{ animate as B }],[* as TR],[{ type animate }],[*],[{ animate as A }],[* as PR],[{ animate }]& + text="export * as PR18 from \"@okikio/animate\";\nexport { animate as animate2 } from \"@okikio/animate\";"& + share=MYewdgziA2CmB00QHMAUAiAwiG6CUQA& + config={"cdn":"skypack","compression":"brotli","esbuild":{"format":"cjs","minify":false,"treeShaking":false}}& + bundle + ``` + + * `q` or `query` represents the module, e.g. `react`, `vue`, etc... + You can add `(import)` in-front of a specific module to make it an import instead of an export + + * `treeshake` represents the export/imports to treeshake. + The treeshake syntax allows for specifying multiple exports per package, through this syntax + + ```ts + "[{ x,y,z }],[*],[* as X],[{ type xyz }]" + // to + export { x, y, z } from "..."; + export * from "..."; + export * as X from "..."; + export { type xyz } from "..."; + ``` + + The square brackets represent seperate packages, and everything inside the squarebrackets, are the exported methods, types, etc... + + * `text` represents the input code as a string (it's used for short input code) + * `share` represents compressed string version of the input code (it's used for large input code) + * `config` represents the bundle configuration to use when building the bundle + * `bundle` tells **bundlejs** to bundle the input code on start-up. This isn't on by default for security reasons. I want to discourage people from sending large complex bundles that crash browsers or that take a long time to load, especially before the input code is properly verified as non-malicious. So, if you want to bundle the code on startup, you have to manually add `&bundle` to the end of the url yourself. + + The reason why I decided on this syntax is because it allows for a lot of flexibility, and transparency concerning what is being bundled. I also wanted to make it easy to share bundle session between users. + + You can add (import) in-front of a specific module to make it an import instead of an export, treeshake represents the export/imports to treeshake. + + The treeshake syntax allows for specifying multiple exports per package, through this syntax + content: + application/json: + schema: + type: object + properties: + query: + type: string + rawQuery: + type: string + version: + type: string + nullable: true + versions: + type: array + items: + type: string + nullable: true + config: + type: object + additionalProperties: true + input: + type: string + size: + type: object + properties: + type: + type: string + rawUncompressedSize: + type: integer + uncompressedSize: + type: string + rawCompressedSize: + type: integer + compressedSize: + type: string + size: + type: string + time: + type: string + rawTime: + type: integer + fileId: + type: string + fileUrl: + type: string + fileHTMLUrl: + type: string + '400': + description: Bad request + '404': + description: Package not found + content: + text/plain: + schema: + type: string + example: "✘ [ERROR] [getRequest] Failed at request (https://unpkg.com/reac@0.0.0)\nError: Couldn't load https://unpkg.com/reac@0.0.0/index.js (404 code) [plugin cdn-url]\n\n virtual-filesystem:/index.ts:2:14:\n\n 2 │ export * from \"reac\";\n ╵ ~~~~~~" + '500': + description: Internal server error + \ No newline at end of file diff --git a/cloudflare/src/durable-objects/bundle-coordinator.ts b/cloudflare/src/durable-objects/bundle-coordinator.ts index 291c582..9738ae4 100644 --- a/cloudflare/src/durable-objects/bundle-coordinator.ts +++ b/cloudflare/src/durable-objects/bundle-coordinator.ts @@ -30,9 +30,11 @@ function mapRow(row: CoordinatorRow | null | undefined): CoordinatorRecord | nul }; } -export class BundleCoordinator extends DurableObject { - constructor(ctx: DurableObjectState, env: unknown) { - super(ctx, env); +export class BundleCoordinator { + ctx: DurableObjectState; + + constructor(ctx: DurableObjectState, _env: unknown) { + this.ctx = ctx; ctx.blockConcurrencyWhile(async () => { this.ctx.storage.sql.exec(` diff --git a/cloudflare/src/index.ts b/cloudflare/src/index.ts index 5ef7898..c5c069c 100644 --- a/cloudflare/src/index.ts +++ b/cloudflare/src/index.ts @@ -1,11 +1,13 @@ import { executePreparedBundle } from "../../edge/execute.ts"; import type { BundleResult } from "../../edge/bundle.ts"; -import { getPackageResultKey, prepareBundleRequest } from "../../edge/request.ts"; +import { prepareBundleRequest } from "../../edge/request.ts"; +import { getPackageResultKey, headers } from "../../edge/constants.ts"; import { generateWorkerResult } from "./result.ts"; import type { Env } from "./types.ts"; +import ESBUILD_WASM_MODULE from "../../core/esbuild.wasm"; import { createCachedBadgeResponse, - deleteCachedBadge, + deleteCachedBadgeKey, deleteBundleArtifact, deleteCachedBundleResult, getArtifactKey, @@ -17,152 +19,184 @@ import { export { BundleCoordinator } from "./durable-objects/bundle-coordinator.ts"; -const CORS_HEADERS = { - "Access-Control-Allow-Origin": "*", - "Access-Control-Allow-Methods": "GET, POST, OPTIONS" -} as const; - -function isStaticRoute(pathname: string): boolean { - return pathname.startsWith("/.well-known/") || ["/favicon.ico", "/robots.txt", "/llms.txt", "/sw.js"].includes(pathname); +/** + * Cloudflare Workers entrypoint that aims to mirror `edge/mod.ts` (Deno Deploy) + * as closely as practical. + * + * Design goals: + * - Preserve the observable behavior of the Deno handler (routes, status codes, + * cache semantics, headers), but implement persistence using Workers bindings + * (KV for JSON/badge cache; R2 for bundle artifacts). + * - Keep runtime-specific logic *thin* here; shared request parsing + execution + * live in `edge/request.ts` and `edge/execute.ts`. + */ + +async function deleteAllKv(env: Env): Promise { + let deleted = 0; + let cursor: string | undefined = undefined; + + do { + const page = await env.BUNDLE_CACHE.list({ cursor }); + const keys = page.keys.map((entry) => entry.name); + + await Promise.all(keys.map((name) => env.BUNDLE_CACHE.delete(name))); + deleted += keys.length; + + cursor = page.cursor; + } while (cursor); + + return deleted; } -function json(data: unknown, init: ResponseInit = {}): Response { - return Response.json(data, { - ...init, - headers: { - ...CORS_HEADERS, - ...(init.headers ?? {}) - } - }); +async function deleteAllArtifacts(env: Env): Promise { + let deleted = 0; + let cursor: string | undefined = undefined; + + do { + const page = await env.BUNDLE_ARTIFACTS.list({ cursor }); + const keys = page.objects.map((obj) => obj.key); + + await Promise.all(keys.map((key) => env.BUNDLE_ARTIFACTS.delete(key))); + deleted += keys.length; + + cursor = page.truncated ? page.cursor : undefined; + } while (cursor); + + return deleted; } -function isBundleRoute(pathname: string): boolean { - return [ - "/", - "/analysis", - "/analyze", - "/badge", - "/badge/raster", - "/badge-raster", - "/bundle", - "/delete-cache", - "/file", - "/metafile", - "/no-cache", - "/raw", - "/warnings" - ].includes(pathname); +function contentTypeForWellKnown(ext: string): string { + if (ext === ".png") return "image/png"; + if (ext === ".yaml") return "text/yaml"; + return "application/json"; } export default { async fetch(request: Request, env: Env): Promise { - if (request.method === "OPTIONS") { - return new Response(null, { - status: 204, - headers: CORS_HEADERS - }); - } - const url = new URL(request.url); - if (isStaticRoute(url.pathname)) { - return env.ASSETS.fetch(request); + if (url.pathname === "/favicon.ico") { + return Response.redirect("https://bundlejs.com/favicon/favicon-api.ico"); } - if (url.searchParams.has("docs")) { - return Response.redirect("https://blog.okikio.dev/documenting-an-online-bundler-bundlejs#heading-configuration"); + if (url.pathname === "/apple-touch-icon.png" || url.pathname === "/apple-touch-icon-precomposed.png") { + return Response.redirect("https://bundlejs.com/favicon/apple-touch-icon.png"); } - if (url.pathname === "/healthz") { - return json({ - ok: true, - runtime: "cloudflare-workers", - mode: "bundle-execution" - }); + if (url.pathname === "/sw.js" || url.pathname === "/robots.txt" || url.pathname === "/llms.txt") { + return Response.json({ message: "no" }); } - if (url.pathname.startsWith("/jobs/")) { - const bundleKey = url.pathname.slice("/jobs/".length).trim(); - - if (!bundleKey) { - return json({ message: "Missing bundle key." }, { status: 400 }); - } + if (url.pathname.startsWith("/.well-known/")) { + const assetResponse = await env.ASSETS.fetch(request); + const ext = url.pathname.includes(".") ? `.${url.pathname.split(".").pop()}` : ""; + + return new Response(await assetResponse.arrayBuffer(), { + status: assetResponse.status, + headers: [ + ...headers, + ["Cache-Control", "max-age=180, public"], + ["Content-Type", contentTypeForWellKnown(ext)], + ], + }); + } - const stub = env.BUNDLE_COORDINATOR.get(env.BUNDLE_COORDINATOR.idFromName(bundleKey)); - const status = await stub.getStatus(bundleKey); + if (url.searchParams.has("docs")) { + return Response.redirect("https://blog.okikio.dev/documenting-an-online-bundler-bundlejs#heading-configuration"); + } - if (!status) { - return json({ bundleKey, status: "unknown" }, { status: 404 }); + const badgeQuery = url.searchParams.has("badge") || ["/badge", "/badge/raster", "/badge-raster"].includes(url.pathname); + const badgeResult = url.searchParams.get("badge"); + const badgeStyle = url.searchParams.get("badge-style"); + const badgeRasterQuery = + url.searchParams.has("badge-raster") || + url.searchParams.has("png") || + ["/badge/raster", "/badge-raster"].includes(url.pathname); + + const fileCheck = url.searchParams.has("file") || url.pathname === "/file"; + + const preparedRequest = await prepareBundleRequest(url); + const { + badgeID, + badgeKey, + bundleKey, + exportAll, + jsonKey, + modules, + mutationQueries, + shareQuery, + textQuery, + } = preparedRequest; + + const artifactKey = getArtifactKey(bundleKey); + const startedAt = Date.now(); + + if (url.pathname === "/clear-all-cache-123") { + const clearArtifacts = url.searchParams.has("gist") || url.searchParams.has("gists"); + + if (clearArtifacts) { + await deleteAllKv(env); + await deleteAllArtifacts(env); + return new Response("Started clearing cache including gists!\n\nCleared entire cache + gists...careful now.", { + headers: { + "Content-Type": "text/plain", + "x-content-type-options": "nosniff", + }, + }); } - return json(status); + await deleteAllKv(env); + return new Response("Started clearing cache!\nCleared entire cache", { + headers: { + "Content-Type": "text/plain", + "x-content-type-options": "nosniff", + }, + }); } - if (isBundleRoute(url.pathname)) { - const preparedRequest = await prepareBundleRequest(url); - const { - badgeID, - badgeKey, - bundleKey, - exportAll, - initialValue, - jsonKey, - modules, - mutationQueries, - query, - shareQuery, - textQuery, - versions - } = preparedRequest; - const artifactKey = getArtifactKey(bundleKey); - const stub = env.BUNDLE_COORDINATOR.get(env.BUNDLE_COORDINATOR.idFromName(bundleKey)); - const existingStatus = await stub.getStatus(bundleKey); - const fileQuery = url.searchParams.has("file") || url.pathname === "/file"; - const badgeQuery = url.searchParams.has("badge") || ["/badge", "/badge/raster", "/badge-raster"].includes(url.pathname); - const packageCacheKey = modules.length === 1 && exportAll && !mutationQueries && modules[0]?.[1] === "export" - ? `${getPackageResultKey(modules[0][0])}/${jsonKey}` - : null; - const startedAt = Date.now(); - - if (url.pathname === "/delete-cache") { - await deleteCachedBundleResult(env, jsonKey); - - if (packageCacheKey) { - await deleteCachedBundleResult(env, packageCacheKey); - } + if (url.pathname === "/delete-cache") { + try { + const packageCacheKey = modules.length === 1 && exportAll && !mutationQueries && modules[0]?.[1] === "export" + ? `${getPackageResultKey(modules[0][0])}/${jsonKey}` + : null; - await deleteCachedBadge(env, badgeID); + await deleteCachedBundleResult(env, jsonKey); + if (packageCacheKey) await deleteCachedBundleResult(env, packageCacheKey); + await deleteCachedBadgeKey(env, badgeKey); await deleteBundleArtifact(env, artifactKey); - await stub.clear(); - - return json({ - message: "Deleted bundle cache entries.", - bundleKey, - jsonKey, - packageCacheKey, - artifactKey - }); + // Intentionally matches the Deno handler's plain-text response. + return new Response("Deleted from cache!"); + } catch (error) { + console.warn(error); + return new Response("Error, deleting from cache"); } + } - let cachedResult = null as BundleResult | null; - + try { if (url.pathname !== "/no-cache") { - cachedResult = await getCachedBundleResult(env, jsonKey); + const packageCacheKey = modules.length === 1 && exportAll && !mutationQueries && modules[0]?.[1] === "export" + ? `${getPackageResultKey(modules[0][0])}/${jsonKey}` + : null; + + let cachedResult: BundleResult | null = await getCachedBundleResult(env, jsonKey); if (!cachedResult && packageCacheKey) { cachedResult = await getCachedBundleResult(env, packageCacheKey); } if (badgeQuery && cachedResult) { - const cachedBadge = await getCachedBadge(env, badgeID); - + const cachedBadge = await getCachedBadge(env, badgeKey, badgeID); if (cachedBadge) { return createCachedBadgeResponse(cachedBadge); } + } else if (badgeQuery && !cachedResult) { + await deleteCachedBadgeKey(env, badgeKey); } - if (cachedResult) { + const fileAvailable = !fileCheck ? true : Boolean(await env.BUNDLE_ARTIFACTS.head(artifactKey)); + + if (cachedResult && fileAvailable) { return await generateWorkerResult( env, [badgeKey, badgeID], @@ -174,67 +208,45 @@ export default { ); } } + } catch (error) { + console.warn("error-using-cache:", error); + } - if (existingStatus?.status === "running") { - return json({ - message: "A bundle build is already running for this bundle key.", - bundleKey, - query, - initialValue, - jsonKey, - modules, - versions, - coordinatorStatus: existingStatus - }, { status: 202 }); - } - - if (!existingStatus) { - await stub.initialize(bundleKey, jsonKey); - } - - await stub.markRunning(bundleKey); - - try { - const [response, resultText] = await executePreparedBundle(url, preparedRequest); - - if (!response.ok) { - const errorMessage = await response.clone().text(); - await stub.markFailed(bundleKey, errorMessage || `Bundle request failed with status ${response.status}.`); - return response; - } - - const value = await response.clone().json() as BundleResult; + const [response, resultText] = await executePreparedBundle(url, preparedRequest, { wasmModule: ESBUILD_WASM_MODULE }); - await putBundleArtifact(env, artifactKey, resultText); - await putCachedBundleResult(env, jsonKey, value); - await deleteCachedBadge(env, badgeID); + if (!response.ok) { + const responseHeaders = response.headers; + const status = response.status; + return new Response(await response.arrayBuffer(), { + headers: responseHeaders, + status, + }); + } - if (packageCacheKey) { - await putCachedBundleResult(env, packageCacheKey, value); - } + const value: BundleResult = await response.json(); - await stub.markComplete(bundleKey, artifactKey, jsonKey); - - return await generateWorkerResult( - env, - [badgeKey, badgeID], - [value, resultText], - url, - false, - Date.now() - startedAt, - artifactKey - ); - } catch (error) { - const message = error instanceof Error ? error.message : String(error); - await stub.markFailed(bundleKey, message); + try { + await putBundleArtifact(env, artifactKey, resultText); + await putCachedBundleResult(env, jsonKey, value); - return json({ - bundleKey, - error: message - }, { status: 500 }); + if (modules.length === 1 && exportAll && !(shareQuery || textQuery) && modules[0]?.[1] === "export") { + const packageCacheKey = `${getPackageResultKey(modules[0][0])}/${jsonKey}`; + await putCachedBundleResult(env, packageCacheKey, value, { permanent: true }); } + + await deleteCachedBadgeKey(env, badgeKey); + } catch (error) { + console.warn(error); } - return env.ASSETS.fetch(request); + return await generateWorkerResult( + env, + [badgeKey, badgeID], + [value, resultText], + url, + false, + Date.now() - startedAt, + artifactKey + ); } } satisfies ExportedHandler; \ No newline at end of file diff --git a/cloudflare/src/result.ts b/cloudflare/src/result.ts index fd1fde4..72151cc 100644 --- a/cloudflare/src/result.ts +++ b/cloudflare/src/result.ts @@ -6,6 +6,7 @@ import { ansi } from "@bundle/utils"; import { LOGGER_INFO, dispatchEvent, getEsbuild } from "@bundle/core"; import { headers } from "../../edge/constants.ts"; import styleText from "../../edge/style.ts"; +import { docs } from "../../edge/docs.ts"; import type { Env } from "./types.ts"; import { getBundleArtifactText, putCachedBadge } from "./storage.ts"; @@ -50,6 +51,8 @@ export async function generateWorkerResult( duration: number, artifactKey?: string | null ) { + // This function intentionally mirrors `edge/generate-result.ts`. + // Any divergence here is observable by clients, so treat changes as API changes. const noCache = ["/no-cache", "/clear-cache", "/delete-cache"].includes(url.pathname); const analysisQuery = url.searchParams.has("analysis") || url.searchParams.has("analyze") || @@ -118,7 +121,7 @@ export async function generateWorkerResult( } const imgShield = badgeRasterQuery ? new Uint8Array(await imgFetch.arrayBuffer()) : await imgFetch.text(); - await putCachedBadge(env, badgeID, { + await putCachedBadge(env, badgeKey, badgeID, { body: typeof imgShield === "string" ? imgShield : encodeBase64(imgShield), contentType: badgeRasterQuery ? "image/png" : "image/svg+xml", encoding: typeof imgShield === "string" ? "text" : "base64" @@ -135,6 +138,8 @@ export async function generateWorkerResult( } if (fileQuery) { + // Deno Deploy uses a stored gist id (`value.fileId`) for `?file`. + // Workers store the raw bundle text in R2 under `artifactKey`. const fileResult = resultText ?? (artifactKey ? await getBundleArtifactText(env, artifactKey) : null); if (fileResult === null || fileResult === undefined) { @@ -209,7 +214,9 @@ export async function generateWorkerResult( } const { metafile: _metafile, warnings: _warnings, ...usefulInfo } = value; + const addDocs = (url.search === "" ? docs : ""); const finalResult = Object.assign({}, usefulInfo, + addDocs, cached ? { time: timeFormatter.format(duration / 1000, "seconds"), rawTime: duration diff --git a/cloudflare/src/shims.d.ts b/cloudflare/src/shims.d.ts new file mode 100644 index 0000000..44a35cd --- /dev/null +++ b/cloudflare/src/shims.d.ts @@ -0,0 +1,16 @@ +declare module "flow-remove-types" { + type FlowRemoveTypesOptions = { + pretty?: boolean; + all?: boolean; + }; + + type FlowRemoveTypesResult = { + toString(): string; + generateMap(): unknown; + }; + + export default function flowRemoveTypes( + source: string, + options?: FlowRemoveTypesOptions + ): FlowRemoveTypesResult; +} diff --git a/cloudflare/src/storage.ts b/cloudflare/src/storage.ts index 9db0512..1aae862 100644 --- a/cloudflare/src/storage.ts +++ b/cloudflare/src/storage.ts @@ -3,7 +3,41 @@ import { headers } from "../../edge/constants.ts"; import type { Env } from "./types.ts"; const BUNDLE_CACHE_TTL_SECONDS = 60 * 60 * 24; -const BADGE_CACHE_TTL_SECONDS = 60 * 60 * 24; +const KV_KEY_BYTE_LIMIT = 512; + +const kvKeyEncoder = new TextEncoder(); + +function utf8ByteLength(value: string): number { + return kvKeyEncoder.encode(value).byteLength; +} + +function toBase64Url(bytes: Uint8Array): string { + let binary = ""; + for (let index = 0; index < bytes.length; index += 1) { + binary += String.fromCharCode(bytes[index]!); + } + + return btoa(binary) + .replace(/\+/g, "-") + .replace(/\//g, "_") + .replace(/=+$/g, ""); +} + +async function sha256Base64Url(value: string): Promise { + const digest = await crypto.subtle.digest("SHA-256", kvKeyEncoder.encode(value)); + return toBase64Url(new Uint8Array(digest)); +} + +function keyDebugPrefix(key: string): string { + // Keeps keys somewhat inspectable when listed, without risking non-ascii bytes. + return key.slice(0, 32).replace(/[^A-Za-z0-9_-]/g, "_"); +} + +async function toKvSafeKey(key: string): Promise { + if (utf8ByteLength(key) <= KV_KEY_BYTE_LIMIT) return key; + const hash = await sha256Base64Url(key); + return `h:${hash}:${keyDebugPrefix(key)}`; +} export type StoredBadge = { body: string; @@ -11,6 +45,8 @@ export type StoredBadge = { encoding: "text" | "base64"; }; +type BadgeHash = Record; + function decodeBase64(base64: string): Uint8Array { const binary = atob(base64); const bytes = new Uint8Array(binary.length); @@ -32,36 +68,57 @@ export function getArtifactKey(bundleKey: string): string { return `bundles/${bundleKey}/index.js`; } -export function getBadgeCacheKey(badgeID: string): string { - return `badge/${badgeID}`; -} - export async function getCachedBundleResult(env: Env, key: string): Promise { - return await env.BUNDLE_CACHE.get(key, "json"); + return await env.BUNDLE_CACHE.get(await toKvSafeKey(key), "json"); } -export async function putCachedBundleResult(env: Env, key: string, value: BundleResult): Promise { - await env.BUNDLE_CACHE.put(key, JSON.stringify(value), { - expirationTtl: BUNDLE_CACHE_TTL_SECONDS - }); +export async function putCachedBundleResult( + env: Env, + key: string, + value: BundleResult, + options: { permanent?: boolean } = {} +): Promise { + // Deno Deploy: + // - stores the primary `jsonKey` entry with a 24h TTL + // - stores the per-package permanent entry without expiry + await env.BUNDLE_CACHE.put( + await toKvSafeKey(key), + JSON.stringify(value), + options.permanent + ? undefined + : { + expirationTtl: BUNDLE_CACHE_TTL_SECONDS, + } + ); } export async function deleteCachedBundleResult(env: Env, key: string): Promise { - await env.BUNDLE_CACHE.delete(key); + await env.BUNDLE_CACHE.delete(await toKvSafeKey(key)); } -export async function deleteCachedBadge(env: Env, badgeID: string): Promise { - await env.BUNDLE_CACHE.delete(getBadgeCacheKey(badgeID)); +export async function deleteCachedBadgeKey(env: Env, badgeKey: string): Promise { + // Mirrors `redis.del(badgeKey)` in the Deno handler. + // This wipes all badge variants for the bundle in one operation. + await env.BUNDLE_CACHE.delete(await toKvSafeKey(badgeKey)); } -export async function getCachedBadge(env: Env, badgeID: string): Promise { - return await env.BUNDLE_CACHE.get(getBadgeCacheKey(badgeID), "json"); +async function getBadgeHash(env: Env, badgeKey: string): Promise { + return await env.BUNDLE_CACHE.get(await toKvSafeKey(badgeKey), "json"); } -export async function putCachedBadge(env: Env, badgeID: string, badge: StoredBadge): Promise { - await env.BUNDLE_CACHE.put(getBadgeCacheKey(badgeID), JSON.stringify(badge), { - expirationTtl: BADGE_CACHE_TTL_SECONDS - }); +export async function getCachedBadge(env: Env, badgeKey: string, badgeID: string): Promise { + // Equivalent to `redis.hget(badgeKey, badgeID)`. + const hash = await getBadgeHash(env, badgeKey); + if (!hash || typeof hash !== "object") return null; + return hash[badgeID] ?? null; +} + +export async function putCachedBadge(env: Env, badgeKey: string, badgeID: string, badge: StoredBadge): Promise { + // Equivalent to `redis.hset(badgeKey, { [badgeID]: ... })`. + // KV doesn't support hash fields natively, so we store a JSON object. + const hash = (await getBadgeHash(env, badgeKey)) ?? {}; + hash[badgeID] = badge; + await env.BUNDLE_CACHE.put(await toKvSafeKey(badgeKey), JSON.stringify(hash)); } export async function putBundleArtifact(env: Env, artifactKey: string, content: string): Promise { diff --git a/cloudflare/tsconfig.json b/cloudflare/tsconfig.json index 0e576f6..9068e1e 100644 --- a/cloudflare/tsconfig.json +++ b/cloudflare/tsconfig.json @@ -1,11 +1,13 @@ { "compilerOptions": { - "target": "ES2023", + "target": "ES2024", "module": "ESNext", "moduleResolution": "Bundler", "lib": [ - "ES2023", - "WebWorker" + "ES2024", + "ESNext.Disposable", + "WebWorker", + "WebWorker.Iterable" ], "strict": true, "noEmit": true, diff --git a/cloudflare/worker-configuration.d.ts b/cloudflare/worker-configuration.d.ts index f2d4c1f..c93478b 100644 --- a/cloudflare/worker-configuration.d.ts +++ b/cloudflare/worker-configuration.d.ts @@ -20,6 +20,24 @@ declare interface KVNamespacePutOptions { metadata?: unknown; } +declare interface KVNamespaceListKey { + name: string; + expiration?: number; + metadata?: unknown; +} + +declare interface KVNamespaceListResult { + keys: KVNamespaceListKey[]; + list_complete: boolean; + cursor?: string; +} + +declare interface KVNamespaceListOptions { + prefix?: string; + limit?: number; + cursor?: string; +} + declare interface KVNamespace { get(key: string): Promise; get(key: string, type: "json"): Promise; @@ -27,6 +45,7 @@ declare interface KVNamespace { get(key: string, type: "arrayBuffer"): Promise; put(key: string, value: string | ArrayBuffer | ArrayBufferView | ReadableStream, options?: KVNamespacePutOptions): Promise; delete(key: string): Promise; + list(options?: KVNamespaceListOptions): Promise; } declare interface R2HTTPMetadata { @@ -56,8 +75,16 @@ declare interface R2ObjectBody extends R2Object { json(): Promise; } +declare interface R2Objects { + objects: R2Object[]; + truncated: boolean; + cursor?: string; +} + declare interface R2Bucket { get(key: string, options?: unknown): Promise; + head(key: string): Promise; + list(options?: { prefix?: string; limit?: number; cursor?: string; delimiter?: string }): Promise; put(key: string, value: ReadableStream | ArrayBuffer | ArrayBufferView | string | null | Blob, options?: R2PutOptions): Promise; delete(key: string | string[]): Promise; } @@ -90,4 +117,9 @@ declare abstract class DurableObject { declare interface ExportedHandler { fetch(request: Request, env: Env, ctx: ExecutionContext): Response | Promise; +} + +declare module "*.wasm" { + const module: WebAssembly.Module; + export default module; } \ No newline at end of file diff --git a/cloudflare/wrangler.jsonc b/cloudflare/wrangler.jsonc index fe4d458..9d95fb7 100644 --- a/cloudflare/wrangler.jsonc +++ b/cloudflare/wrangler.jsonc @@ -3,6 +3,13 @@ "name": "bundlejs-api-cloudflare", "main": "src/index.ts", "compatibility_date": "2026-04-12", + "compatibility_flags": ["nodejs_compat"], + "rules": [ + { + "type": "CompiledWasm", + "globs": ["**/*.wasm"] + } + ], "assets": { "directory": "./public", "binding": "ASSETS", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 174f4d4..346946a 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -19,6 +19,9 @@ importers: '@bundle/utils': specifier: workspace:* version: link:../utils + '@nick/dispose': + specifier: npm:@jsr/nick__dispose@^1 + version: '@jsr/nick__dispose@1.1.0' devDependencies: '@cloudflare/vitest-pool-workers': specifier: ^0.8.34 @@ -33,8 +36,8 @@ importers: specifier: ^3.1.2 version: 3.2.4 wrangler: - specifier: ^4.13.2 - version: 4.81.1(@cloudflare/workers-types@4.20260412.1) + specifier: ^4.98.0 + version: 4.98.0(@cloudflare/workers-types@4.20260412.1) compress: dependencies: @@ -44,6 +47,9 @@ importers: core: dependencies: + '@bundle/compress': + specifier: workspace:* + version: link:../compress '@bundle/utils': specifier: workspace:* version: link:../utils @@ -108,7 +114,7 @@ importers: specifier: npm:@jsr/std__assert@^1 version: '@jsr/std__assert@1.0.19' '@std/async': - specifier: npm:@jsr/std__async@^1 + specifier: npm:@jsr/std__async@1.2 version: '@jsr/std__async@1.2.0' '@std/bytes': specifier: npm:@jsr/std__bytes@^1 @@ -159,15 +165,15 @@ packages: resolution: {integrity: sha512-+tv3z+SPp+gqTIcImN9o0hqE9xyfQjI1XD9pL6NuKjua9B1y7mNYv0S9cP+QEbA4ppVgGZEmKOvHX5G5Ei1CVA==} engines: {node: '>=18.0.0'} - '@cloudflare/kv-asset-handler@0.4.2': - resolution: {integrity: sha512-SIOD2DxrRRwQ+jgzlXCqoEFiKOFqaPjhnNTGKXSRLvp1HiOvapLaFG2kEr9dYQTYe8rKrd9uvDUzmAITeNyaHQ==} - engines: {node: '>=18.0.0'} + '@cloudflare/kv-asset-handler@0.5.0': + resolution: {integrity: sha512-jxQYkj8dSIzc0cD6cMMNdOc1UVjqSqu8BZdor5s8cGjW2I8BjODt/kWPVdY+u9zj3ms75Q5qaZgnxUad83+eAg==} + engines: {node: '>=22.0.0'} - '@cloudflare/unenv-preset@2.16.0': - resolution: {integrity: sha512-8ovsRpwzPoEqPUzoErAYVv8l3FMZNeBVQfJTvtzP4AgLSRGZISRfuChFxHWUQd3n6cnrwkuTGxT+2cGo8EsyYg==} + '@cloudflare/unenv-preset@2.16.1': + resolution: {integrity: sha512-ECxObrMfyTl5bhQf/lZCXwo5G6xX9IAUo+nDMKK4SZ8m4Jvvxp52vilxyySSWh2YTZz8+HQ07qGH/2rEom1vDw==} peerDependencies: unenv: 2.0.0-rc.24 - workerd: 1.20260301.1 || ~1.20260302.1 || ~1.20260303.1 || ~1.20260304.1 || >1.20260305.0 <2.0.0-0 + workerd: '>1.20260305.0 <2.0.0-0' peerDependenciesMeta: workerd: optional: true @@ -194,8 +200,8 @@ packages: cpu: [x64] os: [darwin] - '@cloudflare/workerd-darwin-64@1.20260409.1': - resolution: {integrity: sha512-h/bkaC0HJL63aqAGnV0oagqpBiTSstabODThkeMSbG8kctl0Jb4jlq1pNHJPmYGazFNtfyagrUZFb6HN22GX7w==} + '@cloudflare/workerd-darwin-64@1.20260603.1': + resolution: {integrity: sha512-cEXDWu6V3ZrpmwWkM4OJE9AeXjdAgOY5rh8EHhcBVCuP5rxnzUbPzLtrVOHx0UUUAcCrFq0Xsa6mZKL1VUZsKQ==} engines: {node: '>=16'} cpu: [x64] os: [darwin] @@ -206,8 +212,8 @@ packages: cpu: [arm64] os: [darwin] - '@cloudflare/workerd-darwin-arm64@1.20260409.1': - resolution: {integrity: sha512-HTAC+B9uSYcm+GjN3UYJjuun19GqYtK1bAFJ0KECXyfsgIDwH1MTzxbTxzJpZUbWLw8s0jcwCU06MWZj6cgnxQ==} + '@cloudflare/workerd-darwin-arm64@1.20260603.1': + resolution: {integrity: sha512-uBPK4LaWJNbbCYwPnUAehlHbbVulhVZPZsdcAhBPfZhHb3QAuAEPAQepO/P67R3V6Cni4YGx1fLbL8A5wwoaNA==} engines: {node: '>=16'} cpu: [arm64] os: [darwin] @@ -218,8 +224,8 @@ packages: cpu: [x64] os: [linux] - '@cloudflare/workerd-linux-64@1.20260409.1': - resolution: {integrity: sha512-QIoNq5cgmn1ko8qlngmgZLXQr2KglrjvIwVFOyJI3rbIpt8631n/YMzHPiOWgt38Cb6tcni8fXOzkcvIX2lBDg==} + '@cloudflare/workerd-linux-64@1.20260603.1': + resolution: {integrity: sha512-ht9l6/8Tk7Rp6kA4S9oFZ4X8u0VjnnFdmU/6B3fnABYKREYTKh2RdOqXqXxcp5eNJseireKnWik/hQOPK1CutQ==} engines: {node: '>=16'} cpu: [x64] os: [linux] @@ -230,8 +236,8 @@ packages: cpu: [arm64] os: [linux] - '@cloudflare/workerd-linux-arm64@1.20260409.1': - resolution: {integrity: sha512-HJGBMTfPDb0GCjwdxWFx63wS20TYDVmtOuA5KVri/CiFnit71y++kmseVmemjsgLFFIzoEAuFG/xUh1FJLo6tg==} + '@cloudflare/workerd-linux-arm64@1.20260603.1': + resolution: {integrity: sha512-LJZ6x00rAjSrobV4m0ZW0TpH5ilBbKcWBzlH+y+KOUsIE/CpTuhAzKV43TbSnFLRX5+jrWKiz2v0hO91lPXy6A==} engines: {node: '>=16'} cpu: [arm64] os: [linux] @@ -242,8 +248,8 @@ packages: cpu: [x64] os: [win32] - '@cloudflare/workerd-windows-64@1.20260409.1': - resolution: {integrity: sha512-GttFO0+TvE0rJNQbDlxC6kq2Q7uFxoZRo74Z9d/trUrLgA14HEVTTXobYyiWrDZ9Qp2W5KN1CrXQXiko0zE38Q==} + '@cloudflare/workerd-windows-64@1.20260603.1': + resolution: {integrity: sha512-DvwqkXMAJRPoDN4PxapAwhlz/6ouD+6R1ttbAEK3cWD/QBvFF5STx7Ds/9Irf+rBly3np3uHWkeX+wZnNFEuzA==} engines: {node: '>=16'} cpu: [x64] os: [win32] @@ -1623,9 +1629,9 @@ packages: engines: {node: '>=18.0.0'} hasBin: true - miniflare@4.20260409.0: - resolution: {integrity: sha512-ayl6To4av0YuXsSivGgWLj+Ug8xZ0Qz3sGV8+Ok2LhNVl6m8m5ktEBM3LX9iT9MtLZRJwBlJrKcraNs/DlZQfA==} - engines: {node: '>=18.0.0'} + miniflare@4.20260603.0: + resolution: {integrity: sha512-+kMQYB82gC8MPOuojHur3icQsUeZUEJ+Sphuo5rVC3Ri9txBLAW/mH33b9OVrpmkogQeaaqPS4tPtugJZhk5Kw==} + engines: {node: '>=22.0.0'} hasBin: true ms@2.1.3: @@ -1753,14 +1759,14 @@ packages: uncrypto@0.1.3: resolution: {integrity: sha512-Ql87qFHB3s/De2ClA9e0gsnS6zXG27SkTiSJwjCc9MebbfapQfuPzumMIUMi38ezPZVNFcHI9sUIepeQfw8J8Q==} - undici@7.24.4: - resolution: {integrity: sha512-BM/JzwwaRXxrLdElV2Uo6cTLEjhSb3WXboncJamZ15NgUURmvlXvxa6xkwIOILIjPNo9i8ku136ZvWV0Uly8+w==} - engines: {node: '>=20.18.1'} - undici@7.24.7: resolution: {integrity: sha512-H/nlJ/h0ggGC+uRL3ovD+G0i4bqhvsDOpbDv7At5eFLlj2b41L8QliGbnl2H7SnDiYhENphh1tQFJZf+MyfLsQ==} engines: {node: '>=20.18.1'} + undici@7.24.8: + resolution: {integrity: sha512-6KQ/+QxK49Z/p3HO6E5ZCZWNnCasyZLa5ExaVYyvPxUwKtbCPMKELJOqh7EqOle0t9cH/7d2TaaTRRa6Nhs4YQ==} + engines: {node: '>=20.18.1'} + unenv@2.0.0-rc.21: resolution: {integrity: sha512-Wj7/AMtE9MRnAXa6Su3Lk0LNCfqDYgfwVjwRFVum9U7wsto1imuHqk4kTm7Jni+5A0Hn7dttL6O/zjvUvoo+8A==} @@ -1856,8 +1862,8 @@ packages: engines: {node: '>=16'} hasBin: true - workerd@1.20260409.1: - resolution: {integrity: sha512-kuWP20fAaqaLBqLbvUfY9nCF6c3C78L60G9lS6eVwBf+v8trVFIsAdLB/FtrnKm7vgVvpDzvFAfB80VIiVj95w==} + workerd@1.20260603.1: + resolution: {integrity: sha512-NPcbhI1++CS+fnELyXtsIR52en+5kwr/OrKeiQeYXGy10HxmPdsQBv9N+DU7hJIOOmBHhOGAAsoGDjyiQ2YCaA==} engines: {node: '>=16'} hasBin: true @@ -1871,12 +1877,12 @@ packages: '@cloudflare/workers-types': optional: true - wrangler@4.81.1: - resolution: {integrity: sha512-fppPXi+W2KJ5bx1zxdUYe1e7CHj5cWPFVBPXy8hSMZhrHeIojMe3ozAktAOw1voVuQjXzbZJf/GVKyVeSjbF8w==} - engines: {node: '>=20.3.0'} + wrangler@4.98.0: + resolution: {integrity: sha512-cXfFUuF4rMIvE0hiMnXjEAB27ERryaCgquBJdUoPIjFzYYE1rbRdMUkEdQ18qDPUtsPvhJdqxLntixT9OfSzQw==} + engines: {node: '>=22.0.0'} hasBin: true peerDependencies: - '@cloudflare/workers-types': ^4.20260409.1 + '@cloudflare/workers-types': ^4.20260603.1 peerDependenciesMeta: '@cloudflare/workers-types': optional: true @@ -1893,6 +1899,18 @@ packages: utf-8-validate: optional: true + ws@8.20.1: + resolution: {integrity: sha512-It4dO0K5v//JtTXuPkfEOaI3uUN87iYPnqo/ZzqCoG3g8uhA66QUMs/SrM0YK7/NAu+r4LMh/9dq2A7k+rHs+w==} + engines: {node: '>=10.0.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: '>=5.0.2' + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + youch-core@0.3.3: resolution: {integrity: sha512-ho7XuGjLaJ2hWHoK8yFnsUGy2Y5uDpqSTq1FkHLK4/oqKtyUU1AFbOOxY4IpC9f0fTLjwYbslUz0Po5BpD1wrA==} @@ -1911,13 +1929,13 @@ snapshots: dependencies: mime: 3.0.0 - '@cloudflare/kv-asset-handler@0.4.2': {} + '@cloudflare/kv-asset-handler@0.5.0': {} - '@cloudflare/unenv-preset@2.16.0(unenv@2.0.0-rc.24)(workerd@1.20260409.1)': + '@cloudflare/unenv-preset@2.16.1(unenv@2.0.0-rc.24)(workerd@1.20260603.1)': dependencies: unenv: 2.0.0-rc.24 optionalDependencies: - workerd: 1.20260409.1 + workerd: 1.20260603.1 '@cloudflare/unenv-preset@2.7.3(unenv@2.0.0-rc.21)(workerd@1.20250906.0)': dependencies: @@ -1945,31 +1963,31 @@ snapshots: '@cloudflare/workerd-darwin-64@1.20250906.0': optional: true - '@cloudflare/workerd-darwin-64@1.20260409.1': + '@cloudflare/workerd-darwin-64@1.20260603.1': optional: true '@cloudflare/workerd-darwin-arm64@1.20250906.0': optional: true - '@cloudflare/workerd-darwin-arm64@1.20260409.1': + '@cloudflare/workerd-darwin-arm64@1.20260603.1': optional: true '@cloudflare/workerd-linux-64@1.20250906.0': optional: true - '@cloudflare/workerd-linux-64@1.20260409.1': + '@cloudflare/workerd-linux-64@1.20260603.1': optional: true '@cloudflare/workerd-linux-arm64@1.20250906.0': optional: true - '@cloudflare/workerd-linux-arm64@1.20260409.1': + '@cloudflare/workerd-linux-arm64@1.20260603.1': optional: true '@cloudflare/workerd-windows-64@1.20250906.0': optional: true - '@cloudflare/workerd-windows-64@1.20260409.1': + '@cloudflare/workerd-windows-64@1.20260603.1': optional: true '@cloudflare/workers-types@4.20260412.1': {} @@ -2991,13 +3009,13 @@ snapshots: - bufferutil - utf-8-validate - miniflare@4.20260409.0: + miniflare@4.20260603.0: dependencies: '@cspotcode/source-map-support': 0.8.1 sharp: 0.34.5 - undici: 7.24.4 - workerd: 1.20260409.1 - ws: 8.18.0 + undici: 7.24.8 + workerd: 1.20260603.1 + ws: 8.20.1 youch: 4.1.0-beta.10 transitivePeerDependencies: - bufferutil @@ -3167,10 +3185,10 @@ snapshots: uncrypto@0.1.3: {} - undici@7.24.4: {} - undici@7.24.7: {} + undici@7.24.8: {} + unenv@2.0.0-rc.21: dependencies: defu: 6.1.7 @@ -3271,13 +3289,13 @@ snapshots: '@cloudflare/workerd-linux-arm64': 1.20250906.0 '@cloudflare/workerd-windows-64': 1.20250906.0 - workerd@1.20260409.1: + workerd@1.20260603.1: optionalDependencies: - '@cloudflare/workerd-darwin-64': 1.20260409.1 - '@cloudflare/workerd-darwin-arm64': 1.20260409.1 - '@cloudflare/workerd-linux-64': 1.20260409.1 - '@cloudflare/workerd-linux-arm64': 1.20260409.1 - '@cloudflare/workerd-windows-64': 1.20260409.1 + '@cloudflare/workerd-darwin-64': 1.20260603.1 + '@cloudflare/workerd-darwin-arm64': 1.20260603.1 + '@cloudflare/workerd-linux-64': 1.20260603.1 + '@cloudflare/workerd-linux-arm64': 1.20260603.1 + '@cloudflare/workerd-windows-64': 1.20260603.1 wrangler@4.35.0(@cloudflare/workers-types@4.20260412.1): dependencies: @@ -3296,16 +3314,16 @@ snapshots: - bufferutil - utf-8-validate - wrangler@4.81.1(@cloudflare/workers-types@4.20260412.1): + wrangler@4.98.0(@cloudflare/workers-types@4.20260412.1): dependencies: - '@cloudflare/kv-asset-handler': 0.4.2 - '@cloudflare/unenv-preset': 2.16.0(unenv@2.0.0-rc.24)(workerd@1.20260409.1) + '@cloudflare/kv-asset-handler': 0.5.0 + '@cloudflare/unenv-preset': 2.16.1(unenv@2.0.0-rc.24)(workerd@1.20260603.1) blake3-wasm: 2.1.5 esbuild: 0.27.3 - miniflare: 4.20260409.0 + miniflare: 4.20260603.0 path-to-regexp: 6.3.0 unenv: 2.0.0-rc.24 - workerd: 1.20260409.1 + workerd: 1.20260603.1 optionalDependencies: '@cloudflare/workers-types': 4.20260412.1 fsevents: 2.3.3 @@ -3315,6 +3333,8 @@ snapshots: ws@8.18.0: {} + ws@8.20.1: {} + youch-core@0.3.3: dependencies: '@poppinss/exception': 1.2.3 -- 2.51.2