@b9g/platform-cloudflare 0.1.9 → 0.1.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/index.js CHANGED
@@ -2,47 +2,68 @@
2
2
  // src/index.ts
3
3
  import {
4
4
  BasePlatform,
5
- loadConfig,
6
- createCacheFactory
5
+ CustomLoggerStorage
7
6
  } from "@b9g/platform";
7
+ import { createCacheFactory } from "@b9g/platform/runtime";
8
8
  import { CustomCacheStorage } from "@b9g/cache";
9
9
  import { getLogger } from "@logtape/logtape";
10
- var logger = getLogger(["platform-cloudflare"]);
10
+ import { CloudflareNativeCache } from "./caches.js";
11
+ var logger = getLogger(["shovel", "platform"]);
11
12
  var CloudflarePlatform = class extends BasePlatform {
12
13
  name;
13
14
  #options;
14
15
  #miniflare;
15
16
  #assetsMiniflare;
16
- // Separate instance for ASSETS binding
17
- #config;
18
17
  constructor(options = {}) {
19
18
  super(options);
20
19
  this.#miniflare = null;
21
20
  this.#assetsMiniflare = null;
22
21
  this.name = "cloudflare";
23
22
  const cwd = options.cwd ?? ".";
24
- this.#config = loadConfig(cwd);
25
23
  this.#options = {
26
24
  environment: options.environment ?? "production",
27
25
  assetsDirectory: options.assetsDirectory,
28
- cwd
26
+ cwd,
27
+ config: options.config
29
28
  };
30
29
  }
31
30
  /**
32
- * Create cache storage
33
- * Uses config from shovel.json with memory cache default.
34
- *
35
- * Note: This is for the platform/test runner context. Inside actual
36
- * Cloudflare Workers, native caches are available via globalThis.caches
37
- * (captured by the banner as globalThis.__cloudflareCaches).
31
+ * Create cache storage using config from shovel.json
32
+ * Default: Cloudflare's native Cache API
33
+ * Merges with runtime defaults (actual class references) for fallback behavior
38
34
  */
39
35
  async createCaches() {
40
- return new CustomCacheStorage(
41
- createCacheFactory({ config: this.#config, defaultProvider: "cloudflare" })
36
+ const runtimeDefaults = {
37
+ default: { impl: CloudflareNativeCache }
38
+ };
39
+ const userCaches = this.#options.config?.caches ?? {};
40
+ const configs = {};
41
+ const allNames = /* @__PURE__ */ new Set([
42
+ ...Object.keys(runtimeDefaults),
43
+ ...Object.keys(userCaches)
44
+ ]);
45
+ for (const name of allNames) {
46
+ configs[name] = { ...runtimeDefaults[name], ...userCaches[name] };
47
+ }
48
+ return new CustomCacheStorage(createCacheFactory({ configs }));
49
+ }
50
+ /**
51
+ * Create directory storage for Cloudflare Workers
52
+ * Directories must be configured via shovel.json (no platform defaults)
53
+ */
54
+ async createDirectories() {
55
+ throw new Error(
56
+ "Cloudflare Workers do not have default directories. Configure directories in shovel.json using Cloudflare directory classes."
42
57
  );
43
58
  }
44
59
  /**
45
- * Create "server" for Cloudflare Workers (which is really just the handler)
60
+ * Create logger storage for Cloudflare Workers
61
+ */
62
+ async createLoggers() {
63
+ return new CustomLoggerStorage((categories) => getLogger(categories));
64
+ }
65
+ /**
66
+ * Create "server" for Cloudflare Workers (stub for Platform interface)
46
67
  */
47
68
  createServer(handler, _options = {}) {
48
69
  return {
@@ -61,34 +82,22 @@ var CloudflarePlatform = class extends BasePlatform {
61
82
  }
62
83
  };
63
84
  }
64
- /**
65
- * Load ServiceWorker-style entrypoint using miniflare (workerd)
66
- *
67
- * Note: In production Cloudflare Workers, the banner/footer wrapper code
68
- * handles request dispatch directly - loadServiceWorker is only used for
69
- * local development with miniflare.
70
- */
71
- async loadServiceWorker(entrypoint, _options = {}) {
72
- return this.#loadServiceWorkerWithMiniflare(entrypoint);
73
- }
74
85
  /**
75
86
  * Load ServiceWorker using miniflare (workerd) for dev mode
76
87
  */
77
- async #loadServiceWorkerWithMiniflare(entrypoint) {
88
+ async loadServiceWorker(entrypoint, _options = {}) {
78
89
  logger.info("Starting miniflare dev server", { entrypoint });
79
90
  const { Miniflare } = await import("miniflare");
80
91
  const miniflareOptions = {
81
- modules: false,
82
- // ServiceWorker format (not ES modules)
92
+ modules: true,
83
93
  scriptPath: entrypoint,
84
- // Enable CF-compatible APIs
85
94
  compatibilityDate: "2024-09-23",
86
95
  compatibilityFlags: ["nodejs_compat"]
87
96
  };
88
97
  this.#miniflare = new Miniflare(miniflareOptions);
89
98
  await this.#miniflare.ready;
90
99
  if (this.#options.assetsDirectory) {
91
- logger.info("Setting up separate ASSETS binding", {
100
+ logger.info("Setting up ASSETS binding", {
92
101
  directory: this.#options.assetsDirectory
93
102
  });
94
103
  this.#assetsMiniflare = new Miniflare({
@@ -101,9 +110,17 @@ var CloudflarePlatform = class extends BasePlatform {
101
110
  compatibilityDate: "2024-09-23"
102
111
  });
103
112
  await this.#assetsMiniflare.ready;
104
- logger.info("ASSETS binding available", {});
105
113
  }
106
114
  const mf = this.#miniflare;
115
+ const assetsMf = this.#assetsMiniflare;
116
+ const disposeInstance = async () => {
117
+ await mf.dispose();
118
+ this.#miniflare = null;
119
+ if (assetsMf) {
120
+ await assetsMf.dispose();
121
+ this.#assetsMiniflare = null;
122
+ }
123
+ };
107
124
  const instance = {
108
125
  runtime: mf,
109
126
  handleRequest: async (request) => {
@@ -124,16 +141,11 @@ var CloudflarePlatform = class extends BasePlatform {
124
141
  get ready() {
125
142
  return true;
126
143
  },
127
- dispose: async () => {
128
- await mf.dispose();
129
- }
144
+ dispose: disposeInstance
130
145
  };
131
146
  logger.info("Miniflare dev server ready", {});
132
147
  return instance;
133
148
  }
134
- /**
135
- * Dispose of platform resources
136
- */
137
149
  async dispose() {
138
150
  if (this.#miniflare) {
139
151
  await this.#miniflare.dispose();
@@ -144,219 +156,84 @@ var CloudflarePlatform = class extends BasePlatform {
144
156
  this.#assetsMiniflare = null;
145
157
  }
146
158
  }
147
- };
148
- function createOptionsFromEnv(env) {
149
- return {
150
- environment: env.ENVIRONMENT || "production"
151
- };
152
- }
153
- function generateWranglerConfig(options) {
154
- const {
155
- name,
156
- entrypoint,
157
- cacheAdapter: _cacheAdapter,
158
- filesystemAdapter,
159
- kvNamespaces = [],
160
- r2Buckets = [],
161
- d1Databases = []
162
- } = options;
163
- const autoKVNamespaces = [];
164
- const autoR2Buckets = filesystemAdapter === "r2" ? ["STORAGE_R2"] : [];
165
- const allKVNamespaces = [.../* @__PURE__ */ new Set([...kvNamespaces, ...autoKVNamespaces])];
166
- const allR2Buckets = [.../* @__PURE__ */ new Set([...r2Buckets, ...autoR2Buckets])];
167
- return `# Generated wrangler.toml for Shovel app
168
- name = "${name}"
169
- main = "${entrypoint}"
170
- compatibility_date = "2024-09-23"
171
- compatibility_flags = ["nodejs_compat"]
159
+ /**
160
+ * Get virtual entry wrapper for Cloudflare Workers
161
+ *
162
+ * Wraps user code with:
163
+ * 1. Config import (shovel:config virtual module)
164
+ * 2. Runtime initialization (ServiceWorkerGlobals)
165
+ * 3. User code import (registers fetch handlers)
166
+ * 4. ES module export for Cloudflare Workers format
167
+ *
168
+ * Note: Unlike Node/Bun, Cloudflare bundles user code inline, so the
169
+ * entryPath is embedded directly in the wrapper.
170
+ */
171
+ getEntryWrapper(entryPath, _options) {
172
+ const safePath = JSON.stringify(entryPath);
173
+ return `// Cloudflare Worker Entry
174
+ import { config } from "shovel:config";
175
+ import { initializeRuntime, createFetchHandler } from "@b9g/platform-cloudflare/runtime";
172
176
 
173
- # ServiceWorker format (since Shovel apps are ServiceWorker-style)
174
- usage_model = "bundled"
177
+ const registration = await initializeRuntime(config);
175
178
 
176
- # KV bindings${allKVNamespaces.length > 0 ? "\n" + allKVNamespaces.map(
177
- (kv) => `[[kv_namespaces]]
178
- binding = "${kv}"
179
- id = "your-kv-namespace-id"
180
- preview_id = "your-preview-kv-namespace-id"`
181
- ).join("\n\n") : ""}
179
+ import ${safePath};
182
180
 
183
- # R2 bindings${allR2Buckets.length > 0 ? "\n" + allR2Buckets.map(
184
- (bucket) => `[[r2_buckets]]
185
- binding = "${bucket}"
186
- bucket_name = "your-bucket-name"`
187
- ).join("\n\n") : ""}
181
+ // Run ServiceWorker lifecycle (install/activate events for migrations, cache warmup, etc.)
182
+ await registration.install();
183
+ await registration.activate();
188
184
 
189
- # D1 bindings
190
- ${d1Databases.map(
191
- (db) => `[[d1_databases]]
192
- binding = "${db}"
193
- database_name = "your-database-name"
194
- database_id = "your-database-id"`
195
- ).join("\n\n")}
185
+ export default { fetch: createFetchHandler(registration) };
196
186
  `;
197
- }
198
- var cloudflareWorkerBanner = `// Cloudflare Worker ES Module wrapper
199
- let serviceWorkerGlobals = null;
200
-
201
- // Capture native Cloudflare caches before any framework code runs
202
- const nativeCaches = globalThis.caches;
203
-
204
- // Set up ServiceWorker environment
205
- if (typeof globalThis.self === 'undefined') {
206
- globalThis.self = globalThis;
207
- }
208
-
209
- // Store native caches for access via globalThis.__cloudflareCaches
210
- globalThis.__cloudflareCaches = nativeCaches;
211
-
212
- // Capture fetch event handlers
213
- const fetchHandlers = [];
214
- const originalAddEventListener = globalThis.addEventListener;
215
- globalThis.addEventListener = function(type, handler, options) {
216
- if (type === 'fetch') {
217
- fetchHandlers.push(handler);
218
- } else {
219
- originalAddEventListener?.call(this, type, handler, options);
220
- }
187
+ }
188
+ /**
189
+ * Get Cloudflare-specific esbuild configuration
190
+ *
191
+ * Note: Cloudflare Workers natively support import.meta.env, so no define alias
192
+ * is needed. The nodejs_compat flag enables node:* built-in modules at runtime,
193
+ * so we externalize them during bundling.
194
+ */
195
+ getESBuildConfig() {
196
+ return {
197
+ platform: "browser",
198
+ conditions: ["worker", "browser"],
199
+ // Externalize node builtins - available at runtime via nodejs_compat flag
200
+ // Include both node:* prefix and bare module names for compatibility
201
+ external: [
202
+ "node:*",
203
+ "path",
204
+ "fs",
205
+ "fs/promises",
206
+ "crypto",
207
+ "util",
208
+ "stream",
209
+ "buffer",
210
+ "events"
211
+ ],
212
+ // Cloudflare bundles user code inline via `import "user-entry"`
213
+ bundlesUserCodeInline: true
214
+ };
215
+ }
216
+ /**
217
+ * Get Cloudflare-specific defaults for config generation
218
+ */
219
+ getDefaults() {
220
+ return {
221
+ caches: {
222
+ default: {
223
+ module: "@b9g/platform-cloudflare/caches"
224
+ }
225
+ },
226
+ directories: {
227
+ public: {
228
+ module: "@b9g/platform-cloudflare/directories",
229
+ export: "CloudflareAssetsDirectory"
230
+ }
231
+ }
232
+ };
233
+ }
221
234
  };
222
-
223
- // Create a promise-based FetchEvent that can be awaited
224
- class FetchEvent {
225
- constructor(type, init) {
226
- this.type = type;
227
- this.request = init.request;
228
- this._response = null;
229
- this._responsePromise = new Promise((resolve) => {
230
- this._resolveResponse = resolve;
231
- });
232
- }
233
-
234
- respondWith(response) {
235
- this._response = response;
236
- this._resolveResponse(response);
237
- }
238
-
239
- async waitUntil(promise) {
240
- await promise;
241
- }
242
- }`;
243
- var cloudflareWorkerFooter = `
244
- // Export ES Module for Cloudflare Workers
245
- export default {
246
- async fetch(request, env, ctx) {
247
- try {
248
- // Set up ServiceWorker-like dirs API for bundled deployment
249
- if (!globalThis.self.dirs) {
250
- // For bundled deployment, assets are served via static middleware
251
- // not through the dirs API
252
- globalThis.self.dirs = {
253
- async open(directoryName) {
254
- if (directoryName === 'assets') {
255
- // Return a minimal interface that indicates no files available
256
- // The assets middleware will fall back to dev mode behavior
257
- return {
258
- async getFileHandle(fileName) {
259
- throw new Error(\`NotFoundError: \${fileName} not found in bundled assets\`);
260
- }
261
- };
262
- }
263
- throw new Error(\`Directory \${directoryName} not available in bundled deployment\`);
264
- }
265
- };
266
- }
267
-
268
- // Set up caches API
269
- if (!globalThis.self.caches) {
270
- globalThis.self.caches = globalThis.caches;
271
- }
272
-
273
- // Ensure request.url is a string
274
- if (typeof request.url !== 'string') {
275
- return new Response('Invalid request URL: ' + typeof request.url, { status: 500 });
276
- }
277
-
278
- // Create proper FetchEvent-like object
279
- let responseReceived = null;
280
- const event = {
281
- request,
282
- respondWith: (response) => { responseReceived = response; }
283
- };
284
-
285
- // Helper for error responses
286
- const createErrorResponse = (err) => {
287
- const isDev = typeof import.meta !== "undefined" && import.meta.env?.MODE !== "production";
288
- if (isDev) {
289
- const escapeHtml = (str) => str.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
290
- return new Response(\`<!DOCTYPE html>
291
- <html>
292
- <head>
293
- <title>500 Internal Server Error</title>
294
- <style>
295
- body { font-family: system-ui, sans-serif; padding: 2rem; max-width: 800px; margin: 0 auto; }
296
- h1 { color: #c00; }
297
- .message { font-size: 1.2em; color: #333; }
298
- pre { background: #f5f5f5; padding: 1rem; overflow-x: auto; border-radius: 4px; }
299
- </style>
300
- </head>
301
- <body>
302
- <h1>500 Internal Server Error</h1>
303
- <p class="message">\${escapeHtml(err.message)}</p>
304
- <pre>\${escapeHtml(err.stack || "No stack trace available")}</pre>
305
- </body>
306
- </html>\`, { status: 500, headers: { "Content-Type": "text/html; charset=utf-8" } });
307
- } else {
308
- return new Response("Internal Server Error", { status: 500, headers: { "Content-Type": "text/plain" } });
309
- }
310
- };
311
-
312
- // Dispatch to ServiceWorker fetch handlers
313
- for (const handler of fetchHandlers) {
314
- try {
315
- await handler(event);
316
- if (responseReceived) {
317
- return responseReceived;
318
- }
319
- } catch (error) {
320
- console.error("Handler error:", error);
321
- return createErrorResponse(error);
322
- }
323
- }
324
-
325
- return new Response('No ServiceWorker handler', { status: 404 });
326
- } catch (topLevelError) {
327
- console.error("Top-level error:", topLevelError);
328
- const isDev = typeof import.meta !== "undefined" && import.meta.env?.MODE !== "production";
329
- if (isDev) {
330
- const escapeHtml = (str) => String(str).replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
331
- return new Response(\`<!DOCTYPE html>
332
- <html>
333
- <head>
334
- <title>500 Internal Server Error</title>
335
- <style>
336
- body { font-family: system-ui, sans-serif; padding: 2rem; max-width: 800px; margin: 0 auto; }
337
- h1 { color: #c00; }
338
- .message { font-size: 1.2em; color: #333; }
339
- pre { background: #f5f5f5; padding: 1rem; overflow-x: auto; border-radius: 4px; }
340
- </style>
341
- </head>
342
- <body>
343
- <h1>500 Internal Server Error</h1>
344
- <p class="message">\${escapeHtml(topLevelError.message)}</p>
345
- <pre>\${escapeHtml(topLevelError.stack || "No stack trace available")}</pre>
346
- </body>
347
- </html>\`, { status: 500, headers: { "Content-Type": "text/html; charset=utf-8" } });
348
- } else {
349
- return new Response("Internal Server Error", { status: 500, headers: { "Content-Type": "text/plain" } });
350
- }
351
- }
352
- }
353
- };`;
354
235
  var src_default = CloudflarePlatform;
355
236
  export {
356
237
  CloudflarePlatform,
357
- cloudflareWorkerBanner,
358
- cloudflareWorkerFooter,
359
- createOptionsFromEnv,
360
- src_default as default,
361
- generateWranglerConfig
238
+ src_default as default
362
239
  };
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Cloudflare Worker Runtime
3
+ *
4
+ * This module provides runtime initialization for Cloudflare Workers.
5
+ * It is imported by the entry wrapper, not by user code.
6
+ */
7
+ import { ShovelServiceWorkerRegistration, ShovelFetchEvent, type ShovelFetchEventInit, type ShovelConfig } from "@b9g/platform/runtime";
8
+ export type { ShovelConfig };
9
+ /**
10
+ * Cloudflare's ExecutionContext - passed to each request handler
11
+ */
12
+ export interface ExecutionContext {
13
+ waitUntil(promise: Promise<unknown>): void;
14
+ passThroughOnException(): void;
15
+ }
16
+ /**
17
+ * Options for CloudflareFetchEvent constructor
18
+ */
19
+ export interface CloudflareFetchEventInit extends ShovelFetchEventInit {
20
+ /** Cloudflare environment bindings (KV, R2, D1, etc.) */
21
+ env: Record<string, unknown>;
22
+ }
23
+ /**
24
+ * Cloudflare-specific FetchEvent with env bindings.
25
+ *
26
+ * Extends ShovelFetchEvent to add the `env` property for accessing
27
+ * Cloudflare bindings (KV namespaces, R2 buckets, D1 databases, etc.)
28
+ */
29
+ export declare class CloudflareFetchEvent extends ShovelFetchEvent {
30
+ /** Cloudflare environment bindings (KV, R2, D1, Durable Objects, etc.) */
31
+ readonly env: Record<string, unknown>;
32
+ constructor(request: Request, options: CloudflareFetchEventInit);
33
+ }
34
+ /**
35
+ * Initialize the Cloudflare runtime with ServiceWorkerGlobals
36
+ *
37
+ * @param config - Shovel configuration from shovel:config virtual module
38
+ * @returns The ServiceWorker registration for handling requests
39
+ */
40
+ export declare function initializeRuntime(config: ShovelConfig): Promise<ShovelServiceWorkerRegistration>;
41
+ /**
42
+ * Create the ES module fetch handler for Cloudflare Workers
43
+ *
44
+ * Creates a CloudflareFetchEvent with env bindings and waitUntil hook,
45
+ * then delegates to registration.handleEvent()
46
+ */
47
+ export declare function createFetchHandler(registration: ShovelServiceWorkerRegistration): (request: Request, env: unknown, ctx: ExecutionContext) => Promise<Response>;
package/src/runtime.js ADDED
@@ -0,0 +1,65 @@
1
+ /// <reference types="./runtime.d.ts" />
2
+ // src/runtime.ts
3
+ import {
4
+ ServiceWorkerGlobals,
5
+ ShovelServiceWorkerRegistration,
6
+ ShovelFetchEvent,
7
+ CustomLoggerStorage,
8
+ configureLogging,
9
+ createCacheFactory,
10
+ createDirectoryFactory
11
+ } from "@b9g/platform/runtime";
12
+ import { CustomCacheStorage } from "@b9g/cache";
13
+ import { CustomDirectoryStorage } from "@b9g/filesystem";
14
+ import { getLogger } from "@logtape/logtape";
15
+ import { envStorage } from "./variables.js";
16
+ var CloudflareFetchEvent = class extends ShovelFetchEvent {
17
+ /** Cloudflare environment bindings (KV, R2, D1, Durable Objects, etc.) */
18
+ env;
19
+ constructor(request, options) {
20
+ super(request, options);
21
+ this.env = options.env;
22
+ }
23
+ };
24
+ var _registration = null;
25
+ var _globals = null;
26
+ async function initializeRuntime(config) {
27
+ if (_registration) {
28
+ return _registration;
29
+ }
30
+ if (config.logging) {
31
+ await configureLogging(config.logging);
32
+ }
33
+ _registration = new ShovelServiceWorkerRegistration();
34
+ const caches = new CustomCacheStorage(
35
+ createCacheFactory({ configs: config.caches ?? {} })
36
+ );
37
+ const directories = new CustomDirectoryStorage(
38
+ createDirectoryFactory(config.directories ?? {})
39
+ );
40
+ _globals = new ServiceWorkerGlobals({
41
+ registration: _registration,
42
+ caches,
43
+ directories,
44
+ loggers: new CustomLoggerStorage((cats) => getLogger(cats))
45
+ });
46
+ _globals.install();
47
+ return _registration;
48
+ }
49
+ function createFetchHandler(registration) {
50
+ return async (request, env, ctx) => {
51
+ const event = new CloudflareFetchEvent(request, {
52
+ env,
53
+ platformWaitUntil: (promise) => ctx.waitUntil(promise)
54
+ });
55
+ return envStorage.run(
56
+ env,
57
+ () => registration.handleRequest(event)
58
+ );
59
+ };
60
+ }
61
+ export {
62
+ CloudflareFetchEvent,
63
+ createFetchHandler,
64
+ initializeRuntime
65
+ };
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Cloudflare Environment Storage
3
+ *
4
+ * Provides per-request access to Cloudflare's env object (KV, R2, D1 bindings, etc.)
5
+ * via AsyncContext. Used by directory implementations to resolve bindings at runtime.
6
+ */
7
+ /**
8
+ * Per-request storage for Cloudflare's env object.
9
+ * Set by createFetchHandler() via envStorage.run().
10
+ */
11
+ export declare const envStorage: any;
12
+ /**
13
+ * Get the current Cloudflare env or throw if not in request context.
14
+ */
15
+ export declare function getEnv(): Record<string, unknown>;
@@ -0,0 +1,17 @@
1
+ /// <reference types="./variables.d.ts" />
2
+ // src/variables.ts
3
+ import { AsyncContext } from "@b9g/async-context";
4
+ var envStorage = new AsyncContext.Variable();
5
+ function getEnv() {
6
+ const env = envStorage.get();
7
+ if (!env) {
8
+ throw new Error(
9
+ "Cloudflare env not available. Are you accessing bindings outside of a request context?"
10
+ );
11
+ }
12
+ return env;
13
+ }
14
+ export {
15
+ envStorage,
16
+ getEnv
17
+ };
@@ -1,55 +0,0 @@
1
- /**
2
- * CFAssetsDirectoryHandle - FileSystemDirectoryHandle over CF ASSETS binding
3
- *
4
- * Wraps Cloudflare's Workers Static Assets binding to provide the standard
5
- * File System Access API interface, enabling shovel's `self.dirs.open("dist")`
6
- * to work seamlessly with bundled static assets.
7
- *
8
- * @example
9
- * ```ts
10
- * // In production CF Worker
11
- * const dist = new CFAssetsDirectoryHandle(env.ASSETS, "/assets");
12
- * const file = await dist.getFileHandle("style.abc123.css");
13
- * const content = await (await file.getFile()).text();
14
- * ```
15
- */
16
- /**
17
- * Cloudflare ASSETS binding interface
18
- */
19
- export interface CFAssetsBinding {
20
- fetch(request: Request | string): Promise<Response>;
21
- }
22
- /**
23
- * FileSystemDirectoryHandle implementation over Cloudflare ASSETS binding.
24
- *
25
- * Provides read-only access to static assets deployed with a CF Worker.
26
- * Directory listing is not supported (ASSETS binding limitation).
27
- */
28
- export declare class CFAssetsDirectoryHandle implements FileSystemDirectoryHandle {
29
- #private;
30
- readonly kind: "directory";
31
- readonly name: string;
32
- constructor(assets: CFAssetsBinding, basePath?: string);
33
- getFileHandle(name: string, _options?: FileSystemGetFileOptions): Promise<FileSystemFileHandle>;
34
- getDirectoryHandle(name: string, _options?: FileSystemGetDirectoryOptions): Promise<FileSystemDirectoryHandle>;
35
- removeEntry(_name: string, _options?: FileSystemRemoveOptions): Promise<void>;
36
- resolve(_possibleDescendant: FileSystemHandle): Promise<string[] | null>;
37
- entries(): AsyncIterableIterator<[string, FileSystemHandle]>;
38
- keys(): AsyncIterableIterator<string>;
39
- values(): AsyncIterableIterator<FileSystemHandle>;
40
- [Symbol.asyncIterator](): AsyncIterableIterator<[string, FileSystemHandle]>;
41
- isSameEntry(other: FileSystemHandle): Promise<boolean>;
42
- }
43
- /**
44
- * FileSystemFileHandle implementation for CF ASSETS binding files.
45
- */
46
- export declare class CFAssetsFileHandle implements FileSystemFileHandle {
47
- #private;
48
- readonly kind: "file";
49
- readonly name: string;
50
- constructor(assets: CFAssetsBinding, path: string, name: string);
51
- getFile(): Promise<File>;
52
- createWritable(_options?: FileSystemCreateWritableOptions): Promise<FileSystemWritableFileStream>;
53
- createSyncAccessHandle(): Promise<FileSystemSyncAccessHandle>;
54
- isSameEntry(other: FileSystemHandle): Promise<boolean>;
55
- }