Deploy.
This commit is contained in:
+957
@@ -0,0 +1,957 @@
|
||||
# 🔥 Miniflare
|
||||
|
||||
**Miniflare** is a simulator for developing and testing
|
||||
[**Cloudflare Workers**](https://workers.cloudflare.com/), powered by
|
||||
[`workerd`](https://github.com/cloudflare/workerd).
|
||||
|
||||
> :warning: Miniflare is a lower level API designed for tools creators, for
|
||||
> locally developing Workers use tools built on top of Miniflare such
|
||||
> as [Wrangler](../wrangler/README.md) or the [Cloudflare Vite plugin](../vite-plugin-cloudflare/README.md).
|
||||
|
||||
## Quick Start
|
||||
|
||||
```shell
|
||||
$ npm install miniflare --save-dev
|
||||
```
|
||||
|
||||
```js
|
||||
import { Miniflare } from "miniflare";
|
||||
|
||||
// Create a new Miniflare instance, starting a workerd server
|
||||
const mf = new Miniflare({
|
||||
script: `addEventListener("fetch", (event) => {
|
||||
event.respondWith(new Response("Hello Miniflare!"));
|
||||
})`,
|
||||
});
|
||||
|
||||
// Send a request to the workerd server, the host is ignored
|
||||
const response = await mf.dispatchFetch("http://localhost:8787/");
|
||||
console.log(await response.text()); // Hello Miniflare!
|
||||
|
||||
// Cleanup Miniflare, shutting down the workerd server
|
||||
await mf.dispose();
|
||||
```
|
||||
|
||||
## API
|
||||
|
||||
### `type Awaitable<T>`
|
||||
|
||||
`T | Promise<T>`
|
||||
|
||||
Represents a value that can be `await`ed. Used in callback types to allow
|
||||
`Promise`s to be returned if necessary.
|
||||
|
||||
### `type Json`
|
||||
|
||||
`string | number | boolean | null | Record<string, Json> | Json[]`
|
||||
|
||||
Represents a JSON-serialisable value.
|
||||
|
||||
### `type ModuleRuleType`
|
||||
|
||||
`"ESModule" | "CommonJS" | "Text" | "Data" | "CompiledWasm"`
|
||||
|
||||
Represents how a module's contents should be interpreted.
|
||||
|
||||
- `"ESModule"`: interpret as
|
||||
[ECMAScript module](https://tc39.es/ecma262/#sec-modules)
|
||||
- `"CommonJS"`: interpret as
|
||||
[CommonJS module](https://nodejs.org/api/modules.html#modules-commonjs-modules)
|
||||
- `"Text"`: interpret as UTF8-encoded data, expose in runtime with
|
||||
`string`-typed `default` export
|
||||
- `"Data"`: interpret as arbitrary binary data, expose in runtime with
|
||||
`ArrayBuffer`-typed `default` export
|
||||
- `"CompiledWasm"`: interpret as binary WebAssembly module data, expose in
|
||||
runtime with `WebAssembly.Module`-typed `default` export
|
||||
|
||||
### `interface ModuleDefinition`
|
||||
|
||||
Represents a manually defined module.
|
||||
|
||||
- `type: ModuleRuleType`
|
||||
|
||||
How this module's contents should be interpreted.
|
||||
|
||||
- `path: string`
|
||||
|
||||
Path of this module. The module's "name" will be obtained by converting this
|
||||
to a relative path. The original path will be used to read `contents` if it's
|
||||
omitted.
|
||||
|
||||
- `contents?: string | Uint8Array`
|
||||
|
||||
Contents override for this module. Binary data should be passed as
|
||||
`Uint8Array`s. If omitted, will be read from `path`.
|
||||
|
||||
### `interface ModuleRule`
|
||||
|
||||
Represents a rule for identifying the `ModuleRuleType` of automatically located
|
||||
modules.
|
||||
|
||||
- `type: ModuleRuleType`
|
||||
|
||||
How to interpret modules that match the `include` patterns.
|
||||
|
||||
- `include: string[]`
|
||||
|
||||
Glob patterns to match located module paths against (e.g. `["**/*.txt"]`).
|
||||
|
||||
- `fallthrough?: boolean`
|
||||
|
||||
If `true`, ignore any further rules of this `type`. This is useful for
|
||||
disabling the built-in `ESModule` and `CommonJS` rules that match `*.mjs` and
|
||||
`*.js`/`*.cjs` files respectively.
|
||||
|
||||
### `type Persistence`
|
||||
|
||||
`boolean | string | undefined`
|
||||
|
||||
Represents where data should be persisted, if anywhere.
|
||||
|
||||
- If this is `undefined`, it defaults to `true` if `defaultPersistRoot` is set
|
||||
or otherwise defaults to `false`.
|
||||
- If this is`false`, data will be stored in-memory and only
|
||||
persist between `Miniflare#setOptions()` calls, not restarts nor
|
||||
`new Miniflare` instances.
|
||||
- If this is `true`, data will be stored in a subdirectory of the `defaultPersistRoot` path if `defaultPersistRoot` is set
|
||||
or otherwise will be stored in a subdirectory of `$PWD/.mf`.
|
||||
- If this looks like a URL, then:
|
||||
- If the protocol is `memory:`, data will be stored in-memory as above.
|
||||
- If the protocol is `file:`, data will be stored on the file-system, in the
|
||||
specified directory (e.g. `file:///path/to/directory`).
|
||||
- Otherwise, if this is just a regular `string`, data will be stored on the
|
||||
file-system, using the value as the directory path.
|
||||
|
||||
### `enum LogLevel`
|
||||
|
||||
`NONE, ERROR, WARN, INFO, DEBUG, VERBOSE`
|
||||
|
||||
Controls which messages Miniflare logs. All messages at or below the selected
|
||||
level will be logged.
|
||||
|
||||
### `interface LogOptions`
|
||||
|
||||
- `prefix?: string`
|
||||
|
||||
String to add before the level prefix when logging messages. Defaults to `mf`.
|
||||
|
||||
- `suffix?: string`
|
||||
|
||||
String to add after the level prefix when logging messages.
|
||||
|
||||
### `class Log`
|
||||
|
||||
- `constructor(level?: LogLevel, opts?: LogOptions)`
|
||||
|
||||
Creates a new logger that logs all messages at or below the specified level to
|
||||
the `console`.
|
||||
|
||||
- `error(message: Error)`
|
||||
|
||||
Logs a message at the `ERROR` level. If the constructed log `level` is less
|
||||
than `ERROR`, `throw`s the `message` instead.
|
||||
|
||||
- `warn(message: string)`
|
||||
|
||||
Logs a message at the `WARN` level.
|
||||
|
||||
- `info(message: string)`
|
||||
|
||||
Logs a message at the `INFO` level.
|
||||
|
||||
- `debug(message: string)`
|
||||
|
||||
Logs a message at the `DEBUG` level.
|
||||
|
||||
- `verbose(message: string)`
|
||||
|
||||
Logs a message at the `VERBOSE` level.
|
||||
|
||||
### `class NoOpLog extends Log`
|
||||
|
||||
- `constructor()`
|
||||
|
||||
Creates a new logger that logs nothing to the `console`, and always `throw`s
|
||||
`message`s logged at the `ERROR` level.
|
||||
|
||||
### `interface QueueProducerOptions`
|
||||
|
||||
- `queueName: string`
|
||||
|
||||
The name of the queue where messages will be sent by the producer.
|
||||
|
||||
- `deliveryDelay?: number`
|
||||
|
||||
Default number of seconds to delay the delivery of messages to consumers.
|
||||
Value between `0` (no delay) and `42300` (12 hours).
|
||||
|
||||
### `interface QueueConsumerOptions`
|
||||
|
||||
- `maxBatchSize?: number`
|
||||
|
||||
Maximum number of messages allowed in each batch. Defaults to `5`.
|
||||
|
||||
- `maxBatchTimeout?: number`
|
||||
|
||||
Maximum number of seconds to wait for a full batch. If a message is sent, and
|
||||
this timeout elapses, a partial batch will be dispatched. Defaults to `1`.
|
||||
|
||||
- `maxRetries?: number`
|
||||
|
||||
Maximum number of times to retry dispatching a message, if handling it throws,
|
||||
or it is explicitly retried. Defaults to `2`.
|
||||
|
||||
- `deadLetterQueue?: string`
|
||||
|
||||
Name of another Queue to send a message on if it fails processing after
|
||||
`maxRetries`. If this isn't specified, failed messages will be discarded.
|
||||
|
||||
- `retryDelay?: number`
|
||||
|
||||
Number of seconds to delay the (re-)delivery of messages by default. Value
|
||||
between `0` (no delay) and `42300` (12 hours).
|
||||
|
||||
### `interface WorkerOptions`
|
||||
|
||||
Options for an individual Worker/"nanoservice". All bindings are accessible on
|
||||
the global scope in service-worker format Workers, or via the 2nd `env`
|
||||
parameter in module format Workers.
|
||||
|
||||
### `interface WorkflowOptions`
|
||||
|
||||
- `name: string`
|
||||
|
||||
The name of the Workflow.
|
||||
|
||||
- `className: string`
|
||||
|
||||
The name of the class exported from the Worker that implements the `WorkflowEntrypoint`.
|
||||
|
||||
- `scriptName?`: string
|
||||
|
||||
The name of the script that includes the `WorkflowEntrypoint`. This is optional because it defaults to the current script if not set.
|
||||
|
||||
#### Core
|
||||
|
||||
- `name?: string`
|
||||
|
||||
Unique name for this worker. Only required if multiple `workers` are
|
||||
specified.
|
||||
|
||||
- `rootPath?: string`
|
||||
|
||||
Path against which all other path options for this Worker are resolved
|
||||
relative to. This path is itself resolved relative to the `rootPath` from
|
||||
`SharedOptions` if multiple workers are specified. Defaults to the current
|
||||
working directory.
|
||||
|
||||
- `script?: string`
|
||||
|
||||
JavaScript code for this worker. If this is a service worker format Worker, it
|
||||
must not have any imports. If this is a modules format Worker, it must not
|
||||
have any _npm_ imports, and `modules: true` must be set. If it does have
|
||||
imports, `scriptPath` must also be set so Miniflare knows where to resolve
|
||||
them relative to.
|
||||
|
||||
- `scriptPath?: string`
|
||||
|
||||
Path of JavaScript entrypoint. If this is a service worker format Worker, it
|
||||
must not have any imports. If this is a modules format Worker, it must not
|
||||
have any _npm_ imports, and `modules: true` must be set.
|
||||
|
||||
- `modules?: boolean | ModuleDefinition[]`
|
||||
- If `true`, Miniflare will treat `script`/`scriptPath` as an ES Module and
|
||||
automatically locate transitive module dependencies according to
|
||||
`modulesRules`. Note that automatic location is not perfect: if the
|
||||
specifier to a dynamic `import()` or `require()` is not a string literal, an
|
||||
exception will be thrown.
|
||||
|
||||
- If set to an array, modules can be defined manually. Transitive dependencies
|
||||
must also be defined. Note the first module must be the entrypoint and have
|
||||
type `"ESModule"`.
|
||||
|
||||
- `modulesRoot?: string`
|
||||
|
||||
If `modules` is set to `true` or an array, modules' "name"s will be their
|
||||
`path`s relative to this value. This ensures file paths in stack traces are
|
||||
correct.
|
||||
|
||||
<!-- prettier-ignore-start -->
|
||||
<!-- (for disabling `;` insertion in `js` code block) -->
|
||||
|
||||
- `modulesRules?: ModuleRule[]`
|
||||
|
||||
Rules for identifying the `ModuleRuleType` of automatically located modules
|
||||
when `modules: true` is set. Note the following default rules are always
|
||||
included at the end:
|
||||
|
||||
```js
|
||||
[
|
||||
{ type: "ESModule", include: ["**/*.mjs"] },
|
||||
{ type: "CommonJS", include: ["**/*.js", "**/*.cjs"] },
|
||||
]
|
||||
```
|
||||
|
||||
> If `script` and `scriptPath` are set, and `modules` is set to an array,
|
||||
> `modules` takes priority for a Worker's code, followed by `script`, then
|
||||
> `scriptPath`.
|
||||
|
||||
<!-- prettier-ignore-end -->
|
||||
|
||||
- `compatibilityDate?: string`
|
||||
|
||||
[Compatibility date](https://developers.cloudflare.com/workers/platform/compatibility-dates/)
|
||||
to use for this Worker. Defaults to a date far in the past.
|
||||
|
||||
- `compatibilityFlags?: string[]`
|
||||
|
||||
[Compatibility flags](https://developers.cloudflare.com/workers/platform/compatibility-dates/)
|
||||
to use for this Worker.
|
||||
|
||||
- `bindings?: Record<string, Json>`
|
||||
|
||||
Record mapping binding name to arbitrary JSON-serialisable values to inject as
|
||||
bindings into this Worker.
|
||||
|
||||
- `wasmBindings?: Record<string, string>`
|
||||
|
||||
Record mapping binding name to paths containing binary WebAssembly module data
|
||||
to inject as `WebAssembly.Module` bindings into this Worker.
|
||||
|
||||
- `textBlobBindings?: Record<string, string>`
|
||||
|
||||
Record mapping binding name to paths containing UTF8-encoded data to inject as
|
||||
`string` bindings into this Worker.
|
||||
|
||||
- `dataBlobBindings?: Record<string, string>`
|
||||
|
||||
Record mapping binding name to paths containing arbitrary binary data to
|
||||
inject as `ArrayBuffer` bindings into this Worker.
|
||||
|
||||
- `serviceBindings?: Record<string, string | typeof kCurrentWorker | { name: string | typeof kCurrentWorker, entrypoint?: string } | { network: Network } | { external: ExternalServer } | { disk: DiskDirectory } | { node: (req: http.IncomingMessage, res: http.ServerResponse, miniflare: Miniflare) => Awaitable<void> } | (request: Request, miniflare: Miniflare) => Awaitable<Response>>`
|
||||
|
||||
Record mapping binding name to service designators to inject as
|
||||
`{ fetch: typeof fetch }`
|
||||
[service bindings](https://developers.cloudflare.com/workers/platform/bindings/about-service-bindings/)
|
||||
into this Worker.
|
||||
- If the designator is a `string`, requests will be dispatched to the Worker
|
||||
with that `name`.
|
||||
- If the designator is `(await import("miniflare")).kCurrentWorker`, requests
|
||||
will be dispatched to the Worker defining the binding.
|
||||
- If the designator is an object of the form `{ name: ..., entrypoint: ... }`,
|
||||
requests will be dispatched to the entrypoint named `entrypoint` in the
|
||||
Worker named `name`. The `entrypoint` defaults to `default`, meaning
|
||||
`{ name: "a" }` is the same as `"a"`. If `name` is
|
||||
`(await import("miniflare")).kCurrentWorker`, requests will be dispatched to
|
||||
the Worker defining the binding.
|
||||
- If the designator is an object of the form `{ network: { ... } }`, where
|
||||
`network` is a
|
||||
[`workerd` `Network` struct](https://github.com/cloudflare/workerd/blob/bdbd6075c7c53948050c52d22f2dfa37bf376253/src/workerd/server/workerd.capnp#L555-L598),
|
||||
requests will be dispatched according to the `fetch`ed URL.
|
||||
- If the designator is an object of the form `{ external: { ... } }` where
|
||||
`external` is a
|
||||
[`workerd` `ExternalServer` struct](https://github.com/cloudflare/workerd/blob/bdbd6075c7c53948050c52d22f2dfa37bf376253/src/workerd/server/workerd.capnp#L504-L553),
|
||||
requests will be dispatched to the specified remote server.
|
||||
- If the designator is an object of the form `{ disk: { ... } }` where `disk`
|
||||
is a
|
||||
[`workerd` `DiskDirectory` struct](https://github.com/cloudflare/workerd/blob/bdbd6075c7c53948050c52d22f2dfa37bf376253/src/workerd/server/workerd.capnp#L600-L643),
|
||||
requests will be dispatched to an HTTP service backed by an on-disk
|
||||
directory.
|
||||
- If the designator is an object of the form `{ node: (req: http.IncomingMessage, res: http.ServerResponse, miniflare: Miniflare) => Awaitable<void> }`, requests will be dispatched to your custom Node handler. This allows you to access data and functions defined in Node.js from your Worker using Node.js `req` and `res` objects. Note, `miniflare` will be the `Miniflare` instance dispatching the request.
|
||||
- If the designator is a function with the signature `(request: Request, miniflare: Miniflare) => Response`, requests will be dispatched to your custom
|
||||
fetch handler. This allows you to access data and functions defined in Node.js
|
||||
from your Worker using fetch `Request` and `Response` objects. Note, `miniflare` will be the `Miniflare` instance
|
||||
dispatching the request.
|
||||
|
||||
<!--prettier-ignore-start-->
|
||||
|
||||
- `wrappedBindings?: Record<string, string | { scriptName: string, entrypoint?: string, bindings?: Record<string, Json> }>`
|
||||
|
||||
Record mapping binding name to designators to inject as
|
||||
[wrapped bindings](https://github.com/cloudflare/workerd/blob/bfcef2d850514c569c039cb84c43bc046af4ffb9/src/workerd/server/workerd.capnp#L469-L487) into this Worker.
|
||||
Wrapped bindings allow custom bindings to be written as JavaScript functions
|
||||
accepting an `env` parameter of "inner bindings" and returning the value to
|
||||
bind. A `string` designator is equivalent to `{ scriptName: <string> }`.
|
||||
`scriptName`'s bindings will be used as "inner bindings". JSON `bindings` in
|
||||
the `designator` also become "inner bindings" and will override any of
|
||||
`scriptName` bindings with the same name. The Worker named `scriptName`...
|
||||
|
||||
- Must define a single `ESModule` as its source, using
|
||||
`{ modules: true, script: "..." }`, `{ modules: true, scriptPath: "..." }`,
|
||||
or `{ modules: [...] }`
|
||||
- Must provide the function to use for the wrapped binding as an `entrypoint`
|
||||
named export or a default export if `entrypoint` is omitted
|
||||
- Must not be the first/entrypoint worker
|
||||
- Must not be bound to with service or Durable Object bindings
|
||||
- Must not define `compatibilityDate` or `compatibilityFlags`
|
||||
- Must not define `outboundService`
|
||||
- Must not directly or indirectly have a wrapped binding to itself
|
||||
- Must not be used as an argument to `Miniflare#getWorker()`
|
||||
|
||||
<details>
|
||||
<summary><b>Wrapped Bindings Example</b></summary>
|
||||
|
||||
```ts
|
||||
import { Miniflare } from "miniflare";
|
||||
const store = new Map<string, string>();
|
||||
const mf = new Miniflare({
|
||||
workers: [
|
||||
{
|
||||
wrappedBindings: {
|
||||
MINI_KV: {
|
||||
scriptName: "mini-kv", // Use Worker named `mini-kv` for implementation
|
||||
bindings: { NAMESPACE: "ns" }, // Override `NAMESPACE` inner binding
|
||||
},
|
||||
},
|
||||
modules: true,
|
||||
script: `export default {
|
||||
async fetch(request, env, ctx) {
|
||||
// Example usage of wrapped binding
|
||||
await env.MINI_KV.set("key", "value");
|
||||
return new Response(await env.MINI_KV.get("key"));
|
||||
}
|
||||
}`,
|
||||
},
|
||||
{
|
||||
name: "mini-kv",
|
||||
serviceBindings: {
|
||||
// Function-valued service binding for accessing Node.js state
|
||||
async STORE(request) {
|
||||
const { pathname } = new URL(request.url);
|
||||
const key = pathname.substring(1);
|
||||
if (request.method === "GET") {
|
||||
const value = store.get(key);
|
||||
const status = value === undefined ? 404 : 200;
|
||||
return new Response(value ?? null, { status });
|
||||
} else if (request.method === "PUT") {
|
||||
const value = await request.text();
|
||||
store.set(key, value);
|
||||
return new Response(null, { status: 204 });
|
||||
} else if (request.method === "DELETE") {
|
||||
store.delete(key);
|
||||
return new Response(null, { status: 204 });
|
||||
} else {
|
||||
return new Response(null, { status: 405 });
|
||||
}
|
||||
},
|
||||
},
|
||||
modules: true,
|
||||
script: `
|
||||
// Implementation of binding
|
||||
class MiniKV {
|
||||
constructor(env) {
|
||||
this.STORE = env.STORE;
|
||||
this.baseURL = "http://x/" + (env.NAMESPACE ?? "") + ":";
|
||||
}
|
||||
async get(key) {
|
||||
const res = await this.STORE.fetch(this.baseURL + key);
|
||||
return res.status === 404 ? null : await res.text();
|
||||
}
|
||||
async set(key, body) {
|
||||
await this.STORE.fetch(this.baseURL + key, { method: "PUT", body });
|
||||
}
|
||||
async delete(key) {
|
||||
await this.STORE.fetch(this.baseURL + key, { method: "DELETE" });
|
||||
}
|
||||
}
|
||||
|
||||
// env has the type { STORE: Fetcher, NAMESPACE?: string }
|
||||
export default function (env) {
|
||||
return new MiniKV(env);
|
||||
}
|
||||
`,
|
||||
},
|
||||
],
|
||||
});
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
> :warning: `wrappedBindings` are only supported in modules format Workers.
|
||||
|
||||
<!--prettier-ignore-end-->
|
||||
|
||||
- `outboundService?: string | { network: Network } | { external: ExternalServer } | { disk: DiskDirectory } | { node: (req: http.IncomingMessage, res: http.ServerResponse, miniflare: Miniflare) => Awaitable<void> } | (request: Request, miniflare: Miniflare) => Awaitable<Response>`
|
||||
|
||||
Dispatch this Worker's global `fetch()` and `connect()` requests to the
|
||||
configured service. Service designators follow the same rules above for
|
||||
`serviceBindings`.
|
||||
|
||||
- `fetchMock?: import("undici").MockAgent`
|
||||
|
||||
An [`undici` `MockAgent`](https://undici.nodejs.org/#/docs/api/MockAgent) to
|
||||
dispatch this Worker's global `fetch()` requests through.
|
||||
|
||||
> :warning: `outboundService` and `fetchMock` are mutually exclusive options.
|
||||
> At most one of them may be specified per Worker.
|
||||
|
||||
- `routes?: string[]`
|
||||
|
||||
Array of route patterns for this Worker. These follow the same
|
||||
[routing rules](https://developers.cloudflare.com/workers/platform/triggers/routes/#matching-behavior)
|
||||
as deployed Workers. If no routes match, Miniflare will fallback to the Worker
|
||||
defined first.
|
||||
|
||||
- `defaultPersistRoot?: string`
|
||||
|
||||
Specifies the default directory where Miniflare will write persisted data when persistence is enabled.
|
||||
|
||||
```js
|
||||
// Without `defaultPersistRoot`
|
||||
new Miniflare({
|
||||
kvPersist: undefined, // → "/(tmp)/kv"
|
||||
d1Persist: true, // → "$PWD/.mf/d1"
|
||||
r2Persist: false, // → "/(tmp)/r2"
|
||||
cachePersist: "/my-cache", // → "/my-cache"
|
||||
});
|
||||
|
||||
// With `defaultPersistRoot`
|
||||
new Miniflare({
|
||||
defaultPersistRoot: "/storage",
|
||||
kvPersist: undefined, // → "/storage/kv"
|
||||
d1Persist: true, // → "/storage/d1"
|
||||
r2Persist: false, // → "/(tmp)/r2"
|
||||
cachePersist: "/my-cache", // → "/my-cache"
|
||||
});
|
||||
```
|
||||
|
||||
#### Cache
|
||||
|
||||
- `cache?: boolean`
|
||||
|
||||
If `false`, default and named caches will be disabled. The Cache API will
|
||||
still be available, it just won't cache anything.
|
||||
|
||||
- `cacheWarnUsage?: boolean`
|
||||
|
||||
If `true`, the first use of the Cache API will log a warning stating that the
|
||||
Cache API is unsupported on `workers.dev` subdomains.
|
||||
|
||||
#### Durable Objects
|
||||
|
||||
- `durableObjects?: Record<string, string | { className: string, scriptName?: string, useSQLite?: boolean }>`
|
||||
|
||||
Record mapping binding name to Durable Object class designators to inject as
|
||||
`DurableObjectNamespace` bindings into this Worker.
|
||||
- If the designator is a `string`, it should be the name of a `class` exported
|
||||
by this Worker.
|
||||
- If the designator is an object, and `scriptName` is `undefined`, `className`
|
||||
should be the name of a `class` exported by this Worker.
|
||||
- Otherwise, `className` should be the name of a `class` exported by the
|
||||
Worker with a `name` of `scriptName`.
|
||||
- To use the Durable Object SQLite API you must pass `useSQLite: true`.
|
||||
|
||||
#### KV
|
||||
|
||||
- `kvNamespaces?: Record<string, string> | string[]`
|
||||
|
||||
Record mapping binding name to KV namespace IDs to inject as `KVNamespace`
|
||||
bindings into this Worker. Different Workers may bind to the same namespace ID
|
||||
with different binding names. If a `string[]` of binding names is specified,
|
||||
the binding name and KV namespace ID are assumed to be the same.
|
||||
|
||||
- `sitePath?: string`
|
||||
|
||||
Path to serve Workers Sites files from. If set, `__STATIC_CONTENT` and
|
||||
`__STATIC_CONTENT_MANIFEST` bindings will be injected into this Worker. In
|
||||
modules mode, `__STATIC_CONTENT_MANIFEST` will also be exposed as a module
|
||||
with a `string`-typed `default` export, containing the JSON-stringified
|
||||
manifest. Note Workers Sites files are never cached in Miniflare.
|
||||
|
||||
- `siteInclude?: string[]`
|
||||
|
||||
If set, only files with paths matching these glob patterns will be served.
|
||||
|
||||
- `siteExclude?: string[]`
|
||||
|
||||
If set, only files with paths _not_ matching these glob patterns will be
|
||||
served.
|
||||
- `assetsPath?: string`
|
||||
|
||||
Path to serve Workers assets from.
|
||||
- `assetsKVBindingName?: string`
|
||||
Name of the binding to the KV namespace that the assets are in. If `assetsPath` is set, this binding will be injected into this Worker.
|
||||
|
||||
- `assetsManifestBindingName?: string`
|
||||
Name of the binding to an `ArrayBuffer` containing the binary-encoded assets manifest. If `assetsPath` is set, this binding will be injected into this Worker.
|
||||
|
||||
#### R2
|
||||
|
||||
- `r2Buckets?: Record<string, string> | string[]`
|
||||
|
||||
Record mapping binding name to R2 bucket names to inject as `R2Bucket`
|
||||
bindings into this Worker. Different Workers may bind to the same bucket name
|
||||
with different binding names. If a `string[]` of binding names is specified,
|
||||
the binding name and bucket name are assumed to be the same.
|
||||
|
||||
#### D1
|
||||
|
||||
- `d1Databases?: Record<string, string> | string[]`
|
||||
|
||||
Record mapping binding name to D1 database IDs to inject as `D1Database`
|
||||
bindings into this Worker. Note binding names starting with `__D1_BETA__` are
|
||||
injected as `Fetcher` bindings instead, and must be wrapped with a facade to
|
||||
provide the expected `D1Database` API. Different Workers may bind to the same
|
||||
database ID with different binding names. If a `string[]` of binding names is
|
||||
specified, the binding name and database ID are assumed to be the same.
|
||||
|
||||
#### Queues
|
||||
|
||||
- `queueProducers?: Record<string, QueueProducerOptions> | string[]`
|
||||
|
||||
Record mapping binding name to queue options to inject as `WorkerQueue` bindings
|
||||
into this Worker. Different Workers may bind to the same queue name with
|
||||
different binding names. If a `string[]` of binding names is specified, the
|
||||
binding name and queue name (part of the queue options) are assumed to be the same.
|
||||
|
||||
- `queueConsumers?: Record<string, QueueConsumerOptions> | string[]`
|
||||
|
||||
Record mapping queue name to consumer options. Messages enqueued on the
|
||||
corresponding queues will be dispatched to this Worker. Note each queue can
|
||||
have at most one consumer. If a `string[]` of queue names is specified,
|
||||
default consumer options will be used.
|
||||
|
||||
#### Assets
|
||||
|
||||
- `directory?: string`
|
||||
Path to serve Workers static asset files from.
|
||||
|
||||
- `binding?: string`
|
||||
Binding name to inject as a `Fetcher` binding to allow access to static assets from within the Worker.
|
||||
|
||||
- `assetOptions?: { html_handling?: HTMLHandlingOptions, not_found_handling?: NotFoundHandlingOptions}`
|
||||
Configuration for file-based asset routing - see [docs](https://developers.cloudflare.com/workers/static-assets/routing/#routing-configuration) for options
|
||||
|
||||
#### Pipelines
|
||||
|
||||
- `pipelines?: Record<string, PipelineOptions> | string[]`
|
||||
|
||||
Record mapping binding name to a Pipeline. Different workers may bind to the same Pipeline with different bindings
|
||||
names. If a `string[]` of pipeline names, the binding and Pipeline name are assumed to be the same.
|
||||
|
||||
#### Workflows
|
||||
|
||||
- `workflows?: WorkflowOptions[]`
|
||||
Configuration for one or more Workflows in your project.
|
||||
|
||||
#### Browser Run
|
||||
|
||||
- `browserRendering: BrowserRenderingOptions`
|
||||
|
||||
#### Analytics Engine, Sending Email, Vectorize and Workers for Platforms
|
||||
|
||||
_Not yet supported_
|
||||
|
||||
If you need support for these locally, consider using the `wrappedBindings`
|
||||
option to mock them out.
|
||||
|
||||
#### Workers AI
|
||||
|
||||
_Not yet supported_
|
||||
|
||||
If you need support for these locally, consider using the `serviceBindings`
|
||||
option to mock them out.
|
||||
|
||||
### `interface SharedOptions`
|
||||
|
||||
Options shared between all Workers/"nanoservices".
|
||||
|
||||
#### Core
|
||||
|
||||
- `rootPath?: string`
|
||||
|
||||
Path against which all other path options for this instance are resolved
|
||||
relative to. Defaults to the current working directory.
|
||||
|
||||
- `host?: string`
|
||||
|
||||
Hostname that the `workerd` server should listen on. Defaults to `127.0.0.1`.
|
||||
|
||||
- `port?: number`
|
||||
|
||||
Port that the `workerd` server should listen on. Tries to default to `8787`,
|
||||
but falls back to a random free port if this is in use. Note if a manually
|
||||
specified port is in use, Miniflare throws an error, rather than attempting to
|
||||
find a free port.
|
||||
|
||||
- `https?: boolean`
|
||||
|
||||
If `true`, start an HTTPS server using a pre-generated self-signed certificate
|
||||
for `localhost`. Note this certificate is not valid for any other hostnames or
|
||||
IP addresses. If you need to access the HTTPS server from another device,
|
||||
you'll need to generate your own certificate and use the other `https*`
|
||||
options below.
|
||||
|
||||
```shell
|
||||
$ openssl req -newkey rsa:2048 -nodes -keyout key.pem -x509 -days 365 -out cert.pem
|
||||
```
|
||||
|
||||
```js
|
||||
new Miniflare({
|
||||
httpsKeyPath: "key.pem",
|
||||
httpsCertPath: "cert.pem",
|
||||
});
|
||||
```
|
||||
|
||||
- `httpsKey?: string`
|
||||
|
||||
When one of `httpsCert` or `httpCertPath` is also specified, starts an HTTPS
|
||||
server using the value of this option as the PEM encoded private key.
|
||||
|
||||
- `httpsKeyPath?: string`
|
||||
|
||||
When one of `httpsCert` or `httpCertPath` is also specified, starts an HTTPS
|
||||
server using the PEM encoded private key stored at this file path.
|
||||
|
||||
- `httpsCert?: string`
|
||||
|
||||
When one of `httpsKey` or `httpsKeyPath` is also specified, starts an HTTPS
|
||||
server using the value of this option as the PEM encoded certificate chain.
|
||||
|
||||
- `httpsCertPath?: string`
|
||||
|
||||
When one of `httpsKey` or `httpsKeyPath` is also specified, starts an HTTPS
|
||||
server using the PEM encoded certificate chain stored at this file path.
|
||||
|
||||
- `inspectorPort?: number`
|
||||
|
||||
Port that `workerd` should start a DevTools inspector server on. Visit
|
||||
`chrome://inspect` in a Chromium-based browser to connect to this. This can be
|
||||
used to see detailed `console.log`s, profile CPU usage, and will eventually
|
||||
allow step-through debugging.
|
||||
|
||||
- `verbose?: boolean`
|
||||
|
||||
Enable `workerd`'s `--verbose` flag for verbose logging. This can be used to
|
||||
see simplified `console.log`s.
|
||||
|
||||
- `log?: Log`
|
||||
|
||||
Logger implementation for Miniflare's errors, warnings and informative
|
||||
messages.
|
||||
|
||||
- `upstream?: string`
|
||||
|
||||
URL to use as the origin for incoming requests. If specified, all incoming
|
||||
`request.url`s will be rewritten to start with this string. This is especially
|
||||
useful when testing Workers that act as a proxy, and not as origins
|
||||
themselves.
|
||||
|
||||
When `upstream` is set, the `Host` header is rewritten to match the upstream
|
||||
server. To preserve the original hostname, Miniflare adds an
|
||||
`MF-Original-Hostname` header containing the original `Host` value:
|
||||
|
||||
```js
|
||||
export default {
|
||||
async fetch(request) {
|
||||
// When upstream is set, Host header contains the upstream hostname
|
||||
const upstreamHost = request.headers.get("Host");
|
||||
// Original hostname is preserved in MF-Original-Hostname
|
||||
const originalHost = request.headers.get("MF-Original-Hostname");
|
||||
return new Response(
|
||||
`Original: ${originalHost}, Upstream: ${upstreamHost}`
|
||||
);
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
- `cf?: boolean | string | Record<string, any>`
|
||||
|
||||
Controls the object returned from incoming `Request`'s `cf` property.
|
||||
- If set to a falsy value, an object with default placeholder values will be
|
||||
used
|
||||
- If set to an object, that object will be used
|
||||
- If set to `true`, a real `cf` object will be fetched from a trusted
|
||||
Cloudflare endpoint and cached in `node_modules/.mf` for 30 days
|
||||
- If set to a `string`, a real `cf` object will be fetched and cached at the
|
||||
provided path for 30 days
|
||||
|
||||
- `liveReload?: boolean`
|
||||
|
||||
If `true`, Miniflare will inject a script into HTML responses that
|
||||
automatically reloads the page in-browser whenever the Miniflare instance's
|
||||
options are updated.
|
||||
|
||||
- `unsafeDevRegistryPath?: string`
|
||||
|
||||
Path to the dev registry directory. This allows Miniflare to automatically
|
||||
discover external services and Durable Objects running on another miniflare instance and connect them.
|
||||
|
||||
- `unsafeDevRegistryDurableObjectProxy?: boolean`
|
||||
|
||||
If `true`, Miniflare will automatically proxy requests to Durable Objects
|
||||
bound to external services and register all Workers' Durable Objects in the dev registry.
|
||||
|
||||
- `unsafeHandleDevRegistryUpdate?: (registry: WorkerRegistry) => void`
|
||||
|
||||
Callback invoked when the dev registry is updated with changes to bound services.
|
||||
Receives a copy of the updated registry object. Useful for reacting to external
|
||||
service changes during development.
|
||||
|
||||
- `unsafeRuntimeEnv?: Record<string, string>`
|
||||
|
||||
Extra environment variables to set on the spawned `workerd` subprocess.
|
||||
Merged on top of `process.env` and Miniflare's own defaults — most notably
|
||||
`TZ=UTC`, which Miniflare sets to match the production Cloudflare runtime so
|
||||
that `Date` and `Intl` APIs inside the Worker observe UTC during local
|
||||
development. Use this option to override those defaults, for example to test
|
||||
timezone-dependent code with `unsafeRuntimeEnv: { TZ: "Europe/London" }`.
|
||||
|
||||
#### Cache, Durable Objects, KV, R2 and D1
|
||||
|
||||
- `cachePersist?: Persistence`
|
||||
|
||||
Where to persist data cached in default or named caches. See docs for
|
||||
`Persistence`.
|
||||
|
||||
- `durableObjectsPersist?: Persistence`
|
||||
|
||||
Where to persist data stored in Durable Objects. See docs for `Persistence`.
|
||||
|
||||
- `kvPersist?: Persistence`
|
||||
|
||||
Where to persist data stored in KV namespaces. See docs for `Persistence`.
|
||||
|
||||
- `r2Persist?: Persistence`
|
||||
|
||||
Where to persist data stored in R2 buckets. See docs for `Persistence`.
|
||||
|
||||
- `d1Persist?: Persistence`
|
||||
|
||||
Where to persist data stored in D1 databases. See docs for `Persistence`.
|
||||
|
||||
- `workflowsPersist?: Persistence`
|
||||
|
||||
Where to persist data stored in Workflows. See docs for `Persistence`.
|
||||
|
||||
#### Analytics Engine, Sending Email, Vectorize, Workers AI and Workers for Platforms
|
||||
|
||||
_Not yet supported_
|
||||
|
||||
### `type MiniflareOptions`
|
||||
|
||||
`SharedOptions & (WorkerOptions | { workers: WorkerOptions[] })`
|
||||
|
||||
Miniflare accepts either a single Worker configuration or multiple Worker
|
||||
configurations in the `workers` array. When specifying an array of Workers, the
|
||||
first Worker is designated the entrypoint and will receive all incoming HTTP
|
||||
requests. Some options are shared between all workers and should always be
|
||||
defined at the top-level.
|
||||
|
||||
### `class Miniflare`
|
||||
|
||||
- `constructor(opts: MiniflareOptions)`
|
||||
|
||||
Creates a Miniflare instance and starts a new `workerd` HTTP server
|
||||
listening on the configured `host` and `port`.
|
||||
|
||||
- `setOptions(opts: MiniflareOptions)`
|
||||
|
||||
Updates the configuration for this Miniflare instance and restarts the
|
||||
`workerd` server. Note unlike Miniflare 2, this does _not_ merge the new
|
||||
configuration with the old configuration. Note that calling this function will
|
||||
invalidate any existing values returned by the `Miniflare#get*()` methods,
|
||||
preventing them from being used.
|
||||
|
||||
- `ready: Promise<URL>`
|
||||
|
||||
Returns a `Promise` that resolves with a `http` `URL` to the `workerd` server
|
||||
once it has started and is able to accept requests.
|
||||
|
||||
- `dispatchFetch(input: RequestInfo, init?: RequestInit): Promise<Response>`
|
||||
|
||||
Sends a HTTP request to the `workerd` server, dispatching a `fetch` event in
|
||||
the entrypoint Worker. Returns a `Promise` that resolves with the response.
|
||||
Note that this implicitly waits for the `ready` `Promise` to resolve, there's
|
||||
no need to do that yourself first. Additionally, the host of the request's URL
|
||||
is always ignored and replaced with the `workerd` server's.
|
||||
|
||||
- `getBindings<Env extends Record<string, unknown> = Record<string, unknown>>(workerName?: string): Promise<Env>`
|
||||
|
||||
Returns a `Promise` that resolves with a record mapping binding names to
|
||||
bindings, for all bindings in the Worker with the specified `workerName`. If
|
||||
`workerName` is not specified, defaults to the entrypoint Worker.
|
||||
|
||||
- `getWorker(workerName?: string): Promise<Fetcher>`
|
||||
|
||||
Returns a `Promise` that resolves with a
|
||||
[`Fetcher`](https://workers-types.pages.dev/experimental/#Fetcher) pointing to
|
||||
the specified `workerName`. If `workerName` is not specified, defaults to the
|
||||
entrypoint Worker. Note this `Fetcher` uses the experimental
|
||||
[`service_binding_extra_handlers`](https://github.com/cloudflare/workerd/blob/1d9158af7ca1389474982c76ace9e248320bec77/src/workerd/io/compatibility-date.capnp#L290-L297)
|
||||
compatibility flag to expose
|
||||
[`scheduled()`](https://workers-types.pages.dev/experimental/#Fetcher.scheduled)
|
||||
and [`queue()`](https://workers-types.pages.dev/experimental/#Fetcher.queue)
|
||||
methods for dispatching `scheduled` and `queue` events.
|
||||
|
||||
- `getCaches(): Promise<CacheStorage>`
|
||||
|
||||
Returns a `Promise` that resolves with the
|
||||
[`CacheStorage`](https://developers.cloudflare.com/workers/runtime-apis/cache/)
|
||||
instance of the entrypoint Worker. This means if `cache: false` is set on the
|
||||
entrypoint, calling methods on the resolved value won't do anything.
|
||||
|
||||
- `getD1Database(bindingName: string, workerName?: string): Promise<D1Database>`
|
||||
|
||||
Returns a `Promise` that resolves with the
|
||||
[`D1Database`](https://developers.cloudflare.com/d1/platform/client-api/)
|
||||
instance corresponding to the specified `bindingName` of `workerName`. Note
|
||||
`bindingName` must not begin with `__D1_BETA__`. If `workerName` is not
|
||||
specified, defaults to the entrypoint Worker.
|
||||
|
||||
- `getDurableObjectNamespace(bindingName: string, workerName?: string): Promise<DurableObjectNamespace>`
|
||||
|
||||
Returns a `Promise` that resolves with the
|
||||
[`DurableObjectNamespace`](https://developers.cloudflare.com/workers/runtime-apis/durable-objects/#access-a-durable-object-from-a-worker)
|
||||
instance corresponding to the specified `bindingName` of `workerName`. If
|
||||
`workerName` is not specified, defaults to the entrypoint Worker.
|
||||
|
||||
- `getKVNamespace(bindingName: string, workerName?: string): Promise<KVNamespace>`
|
||||
|
||||
Returns a `Promise` that resolves with the
|
||||
[`KVNamespace`](https://developers.cloudflare.com/workers/runtime-apis/kv/)
|
||||
instance corresponding to the specified `bindingName` of `workerName`. If
|
||||
`workerName` is not specified, defaults to the entrypoint Worker.
|
||||
|
||||
- `getQueueProducer<Body>(bindingName: string, workerName?: string): Promise<Queue<Body>>`
|
||||
|
||||
Returns a `Promise` that resolves with the
|
||||
[`Queue`](https://developers.cloudflare.com/queues/platform/javascript-apis/)
|
||||
producer instance corresponding to the specified `bindingName` of
|
||||
`workerName`. If `workerName` is not specified, defaults to the entrypoint
|
||||
Worker.
|
||||
|
||||
- `getR2Bucket(bindingName: string, workerName?: string): Promise<R2Bucket>`
|
||||
|
||||
Returns a `Promise` that resolves with the
|
||||
[`R2Bucket`](https://developers.cloudflare.com/r2/api/workers/workers-api-reference/)
|
||||
producer instance corresponding to the specified `bindingName` of
|
||||
`workerName`. If `workerName` is not specified, defaults to the entrypoint
|
||||
Worker.
|
||||
|
||||
- `dispose(): Promise<void>`
|
||||
|
||||
Cleans up the Miniflare instance, and shuts down the `workerd` server. Note
|
||||
that after this is called, `Miniflare#setOptions()` and
|
||||
`Miniflare#dispatchFetch()` cannot be called. Additionally, calling this
|
||||
function will invalidate any values returned by the `Miniflare#get*()`
|
||||
methods, preventing them from being used.
|
||||
|
||||
- `getCf(): Promise<Record<string, any>>`
|
||||
|
||||
Returns the same object returned from incoming `Request`'s `cf` property. This
|
||||
object depends on the `cf` property from `SharedOptions`.
|
||||
|
||||
## Configuration
|
||||
|
||||
### Local `workerd`
|
||||
|
||||
You can override the `workerd` binary being used by miniflare with a your own local build by setting the `MINIFLARE_WORKERD_PATH` environment variable.
|
||||
|
||||
For example:
|
||||
|
||||
```shell
|
||||
$ export MINIFLARE_WORKERD_PATH="<WORKERD_REPO_DIR>/bazel-bin/src/workerd/server/workerd"
|
||||
```
|
||||
|
||||
For debugging purposes, you can also set `MINIFLARE_WORKERD_CONFIG_DEBUG=<file_path>` which will dump the workerd config to the specified file path.
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
#!/usr/bin/env node
|
||||
const { Log } = require(".");
|
||||
|
||||
const log = new Log();
|
||||
log.error(
|
||||
[
|
||||
"`miniflare@3` no longer includes a CLI. Please use `npx wrangler dev` instead.",
|
||||
"As of `wrangler@3`, this will use Miniflare by default.",
|
||||
"See https://miniflare.dev/get-started/migrating for more details.",
|
||||
].join("\n")
|
||||
);
|
||||
Generated
Vendored
+1
@@ -0,0 +1 @@
|
||||
import{Fn as e,Wn as t,qn as n}from"./index-BwGGYgiP.js";var r=n(t(),1),i=new Map([[`bold`,r.createElement(r.Fragment,null,r.createElement(`path`,{d:`M244,56v48a12,12,0,0,1-12,12H184a12,12,0,1,1,0-24H201.1l-19-17.38c-.13-.12-.26-.24-.38-.37A76,76,0,1,0,127,204h1a75.53,75.53,0,0,0,52.15-20.72,12,12,0,0,1,16.49,17.45A99.45,99.45,0,0,1,128,228h-1.37A100,100,0,1,1,198.51,57.06L220,76.72V56a12,12,0,0,1,24,0Z`}))],[`duotone`,r.createElement(r.Fragment,null,r.createElement(`path`,{d:`M216,128a88,88,0,1,1-88-88A88,88,0,0,1,216,128Z`,opacity:`0.2`}),r.createElement(`path`,{d:`M240,56v48a8,8,0,0,1-8,8H184a8,8,0,0,1,0-16H211.4L184.81,71.64l-.25-.24a80,80,0,1,0-1.67,114.78,8,8,0,0,1,11,11.63A95.44,95.44,0,0,1,128,224h-1.32A96,96,0,1,1,195.75,60L224,85.8V56a8,8,0,1,1,16,0Z`}))],[`fill`,r.createElement(r.Fragment,null,r.createElement(`path`,{d:`M240,56v48a8,8,0,0,1-8,8H184a8,8,0,0,1-5.66-13.66l17-17-10.55-9.65-.25-.24a80,80,0,1,0-1.67,114.78,8,8,0,1,1,11,11.63A95.44,95.44,0,0,1,128,224h-1.32A96,96,0,1,1,195.75,60l10.93,10L226.34,50.3A8,8,0,0,1,240,56Z`}))],[`light`,r.createElement(r.Fragment,null,r.createElement(`path`,{d:`M238,56v48a6,6,0,0,1-6,6H184a6,6,0,0,1,0-12h32.55l-30.38-27.8c-.06-.06-.12-.13-.19-.19a82,82,0,1,0-1.7,117.65,6,6,0,0,1,8.24,8.73A93.46,93.46,0,0,1,128,222h-1.28A94,94,0,1,1,194.37,61.4L226,90.35V56a6,6,0,1,1,12,0Z`}))],[`regular`,r.createElement(r.Fragment,null,r.createElement(`path`,{d:`M240,56v48a8,8,0,0,1-8,8H184a8,8,0,0,1,0-16H211.4L184.81,71.64l-.25-.24a80,80,0,1,0-1.67,114.78,8,8,0,0,1,11,11.63A95.44,95.44,0,0,1,128,224h-1.32A96,96,0,1,1,195.75,60L224,85.8V56a8,8,0,1,1,16,0Z`}))],[`thin`,r.createElement(r.Fragment,null,r.createElement(`path`,{d:`M236,56v48a4,4,0,0,1-4,4H184a4,4,0,0,1,0-8h37.7L187.53,68.69l-.13-.12a84,84,0,1,0-1.75,120.51,4,4,0,0,1,5.5,5.82A91.43,91.43,0,0,1,128,220h-1.26A92,92,0,1,1,193,62.84l35,32.05V56a4,4,0,1,1,8,0Z`}))]]),a=r.forwardRef((t,n)=>r.createElement(e,{ref:n,...t,weights:i}));a.displayName=`ArrowClockwiseIcon`;export{a as t};
|
||||
+1
@@ -0,0 +1 @@
|
||||
import{t as e}from"./Copy.es--li34FWs.js";import{Et as t,Gn as n,In as r,Wn as i,jn as a,qn as o,wt as s}from"./index-BwGGYgiP.js";var c=n(),l=o(i(),1),u=(e,t)=>Math.floor(Math.random()*(t-e+1)+e),d=(e,t)=>(Math.random()*(t-e)+e).toFixed(2),f=({minWidth:e=30,maxWidth:t=100,minDuration:n=1.3,maxDuration:i=1.7,minDelay:a=0,maxDelay:o=.5,blockHeight:s,className:f})=>{let{width:p,duration:m,delay:h}=(0,l.useMemo)(()=>({width:u(e,t),duration:d(n,i),delay:d(a,o)}),[e,t,n,i,a,o]),g={"--skeleton-width":`${p}%`,"--shimmer-duration":`${m}s`,"--shimmer-delay":`${h}s`},_=(0,c.jsx)(`div`,{className:r(`skeleton-line`,f),style:g});return s===void 0?_:(0,c.jsx)(`div`,{className:`flex items-center`,style:{height:typeof s==`number`?`${s}px`:s},children:_})},p={size:{sm:{classes:`text-sm h-10 gap-0.5`,description:`Compact breadcrumbs for dense UIs`},base:{classes:`text-base h-12 gap-1`,description:`Default breadcrumbs size`}}},m={size:`base`};function h({size:e=m.size}={}){return r(`group mr-4 flex min-w-0 grow items-center overflow-hidden whitespace-nowrap`,p.size[e].classes)}var g=({href:e,icon:n,children:r})=>(0,c.jsxs)(t(),{to:e,className:`flex min-w-0 max-w-full items-center gap-1 text-kumo-subtle no-underline`,children:[!!n&&(0,c.jsx)(`span`,{className:`flex shrink-0 items-center`,children:n}),(0,c.jsx)(`span`,{className:`truncate`,children:r})]});function _({children:e,icon:t,loading:n}){return n?(0,c.jsxs)(`div`,{className:`flex w-[125px] min-w-0 items-center gap-1`,children:[t&&(0,c.jsx)(`span`,{className:`flex shrink-0 items-center`,children:t}),(0,c.jsx)(f,{})]}):(0,c.jsxs)(`div`,{className:`flex min-w-0 max-w-full items-center gap-1 font-medium`,"aria-current":`page`,children:[t&&(0,c.jsx)(`span`,{className:`flex shrink-0 items-center`,children:t}),(0,c.jsx)(`span`,{className:`truncate`,children:e})]})}function v(){return(0,c.jsx)(`span`,{className:`flex shrink-0 items-center text-kumo-inactive`,"aria-hidden":`true`,children:(0,c.jsx)(`svg`,{width:`24`,height:`24`,fill:`none`,viewBox:`0 0 24 24`,children:(0,c.jsx)(`path`,{stroke:`currentColor`,strokeLinecap:`round`,strokeLinejoin:`round`,strokeWidth:`1.5`,d:`M10.75 8.75L14.25 12L10.75 15.25`})})})}function y(){return(0,c.jsx)(`span`,{className:`flex shrink-0 items-center text-kumo-subtle`,"aria-hidden":!0,children:`...`})}function b({text:t}){let[n,r]=(0,l.useState)(!1);return(0,l.useEffect)(()=>{if(!n)return;let e=setTimeout(()=>r(!1),2e3);return()=>clearTimeout(e)},[n]),(0,c.jsx)(s,{variant:`ghost`,shape:`square`,size:`sm`,className:`opacity-0 transition-[opacity] group-hover:opacity-100`,onClick:async()=>{if(t)try{await navigator.clipboard.writeText(t),r(!0)}catch(e){console.error(`Failed to copy deeplink:`,e)}},title:`Click to copy`,"aria-label":`Copy`,children:n?(0,c.jsx)(a,{weight:`bold`,className:`text-kumo-success`}):(0,c.jsx)(e,{weight:`regular`})})}function x({children:e,size:t=`base`,className:n}){let i=l.Children.toArray(e),a=C(i);return(0,c.jsxs)(`nav`,{className:r(h({size:t}),n),"aria-label":`breadcrumb`,children:[(0,c.jsx)(`div`,{className:`contents sm:hidden`,children:a}),(0,c.jsx)(`div`,{className:`hidden sm:contents`,children:i})]})}function S(e,t){return(0,l.isValidElement)(e)&&e.type===t}function C(e){let t=e.filter(e=>S(e,g)||S(e,_));if(t.length<=2)return e;let[n,r]=t.slice(-2),i=[(0,c.jsx)(y,{},`kumo-breadcrumb-mobile-ellipsis`),(0,c.jsx)(v,{},`kumo-breadcrumb-mobile-separator-leading`),(0,l.cloneElement)(n,{key:`kumo-breadcrumb-mobile-parent`}),(0,c.jsx)(v,{},`kumo-breadcrumb-mobile-separator-trailing`),(0,l.cloneElement)(r,{key:`kumo-breadcrumb-mobile-current`})],a=e.filter(e=>!S(e,g)&&!S(e,_)&&!S(e,v));return[...i,...a]}x.Link=g,x.Current=_,x.Separator=v,x.Clipboard=b;function w({children:e,icon:t,items:n,title:r}){return(0,c.jsxs)(`div`,{className:`box-border flex min-h-14.5 shrink-0 items-center gap-2 border-b border-kumo-fill bg-kumo-elevated px-6 text-sm`,children:[(0,c.jsxs)(x,{children:[(0,c.jsx)(x.Current,{icon:(0,c.jsx)(t,{className:`h-4 w-4`}),children:r}),n.map((e,t)=>(0,c.jsxs)(l.Fragment,{children:[(0,c.jsx)(x.Separator,{}),e]},t))]}),e]})}export{x as n,f as r,w as t};
|
||||
+1
@@ -0,0 +1 @@
|
||||
import{Fn as e,Wn as t,qn as n}from"./index-BwGGYgiP.js";var r=n(t(),1),i=new Map([[`bold`,r.createElement(r.Fragment,null,r.createElement(`path`,{d:`M216,28H88A12,12,0,0,0,76,40V76H40A12,12,0,0,0,28,88V216a12,12,0,0,0,12,12H168a12,12,0,0,0,12-12V180h36a12,12,0,0,0,12-12V40A12,12,0,0,0,216,28ZM156,204H52V100H156Zm48-48H180V88a12,12,0,0,0-12-12H100V52H204Z`}))],[`duotone`,r.createElement(r.Fragment,null,r.createElement(`path`,{d:`M216,40V168H168V88H88V40Z`,opacity:`0.2`}),r.createElement(`path`,{d:`M216,32H88a8,8,0,0,0-8,8V80H40a8,8,0,0,0-8,8V216a8,8,0,0,0,8,8H168a8,8,0,0,0,8-8V176h40a8,8,0,0,0,8-8V40A8,8,0,0,0,216,32ZM160,208H48V96H160Zm48-48H176V88a8,8,0,0,0-8-8H96V48H208Z`}))],[`fill`,r.createElement(r.Fragment,null,r.createElement(`path`,{d:`M216,32H88a8,8,0,0,0-8,8V80H40a8,8,0,0,0-8,8V216a8,8,0,0,0,8,8H168a8,8,0,0,0,8-8V176h40a8,8,0,0,0,8-8V40A8,8,0,0,0,216,32Zm-8,128H176V88a8,8,0,0,0-8-8H96V48H208Z`}))],[`light`,r.createElement(r.Fragment,null,r.createElement(`path`,{d:`M216,34H88a6,6,0,0,0-6,6V82H40a6,6,0,0,0-6,6V216a6,6,0,0,0,6,6H168a6,6,0,0,0,6-6V174h42a6,6,0,0,0,6-6V40A6,6,0,0,0,216,34ZM162,210H46V94H162Zm48-48H174V88a6,6,0,0,0-6-6H94V46H210Z`}))],[`regular`,r.createElement(r.Fragment,null,r.createElement(`path`,{d:`M216,32H88a8,8,0,0,0-8,8V80H40a8,8,0,0,0-8,8V216a8,8,0,0,0,8,8H168a8,8,0,0,0,8-8V176h40a8,8,0,0,0,8-8V40A8,8,0,0,0,216,32ZM160,208H48V96H160Zm48-48H176V88a8,8,0,0,0-8-8H96V48H208Z`}))],[`thin`,r.createElement(r.Fragment,null,r.createElement(`path`,{d:`M216,36H88a4,4,0,0,0-4,4V84H40a4,4,0,0,0-4,4V216a4,4,0,0,0,4,4H168a4,4,0,0,0,4-4V172h44a4,4,0,0,0,4-4V40A4,4,0,0,0,216,36ZM164,212H44V92H164Zm48-48H172V88a4,4,0,0,0-4-4H92V44H212Z`}))]]),a=r.forwardRef((t,n)=>r.createElement(e,{ref:n,...t,weights:i}));a.displayName=`CopyIcon`;export{a as t};
|
||||
+1
@@ -0,0 +1 @@
|
||||
import{t as e}from"./Copy.es--li34FWs.js";import{Gn as t,In as n,Wn as r,jn as i,qn as a,wt as o}from"./index-BwGGYgiP.js";var s=a(r(),1),c=t();function l({text:t}){let[r,a]=(0,s.useState)(!1);return(0,c.jsx)(o,{className:n(`h-6 w-6 p-0 opacity-0 transition-[opacity,background-color,color] group-hover/cell:opacity-100`,{"text-kumo-success opacity-100":r}),onClick:async()=>{await navigator.clipboard.writeText(t),a(!0),setTimeout(()=>a(!1),1500)},"aria-label":r?`Copied`:`Copy to clipboard`,variant:`ghost`,shape:`square`,children:r?(0,c.jsx)(i,{size:14,weight:`bold`}):(0,c.jsx)(e,{size:14})})}export{l as t};
|
||||
+1
@@ -0,0 +1 @@
|
||||
import{Fn as e,Wn as t,qn as n}from"./index-BwGGYgiP.js";var r=n(t(),1),i=new Map([[`bold`,r.createElement(r.Fragment,null,r.createElement(`path`,{d:`M144,128a16,16,0,1,1-16-16A16,16,0,0,1,144,128ZM60,112a16,16,0,1,0,16,16A16,16,0,0,0,60,112Zm136,0a16,16,0,1,0,16,16A16,16,0,0,0,196,112Z`}))],[`duotone`,r.createElement(r.Fragment,null,r.createElement(`path`,{d:`M240,96v64a16,16,0,0,1-16,16H32a16,16,0,0,1-16-16V96A16,16,0,0,1,32,80H224A16,16,0,0,1,240,96Z`,opacity:`0.2`}),r.createElement(`path`,{d:`M140,128a12,12,0,1,1-12-12A12,12,0,0,1,140,128Zm56-12a12,12,0,1,0,12,12A12,12,0,0,0,196,116ZM60,116a12,12,0,1,0,12,12A12,12,0,0,0,60,116Z`}))],[`fill`,r.createElement(r.Fragment,null,r.createElement(`path`,{d:`M224,80H32A16,16,0,0,0,16,96v64a16,16,0,0,0,16,16H224a16,16,0,0,0,16-16V96A16,16,0,0,0,224,80ZM60,140a12,12,0,1,1,12-12A12,12,0,0,1,60,140Zm68,0a12,12,0,1,1,12-12A12,12,0,0,1,128,140Zm68,0a12,12,0,1,1,12-12A12,12,0,0,1,196,140Z`}))],[`light`,r.createElement(r.Fragment,null,r.createElement(`path`,{d:`M138,128a10,10,0,1,1-10-10A10,10,0,0,1,138,128ZM60,118a10,10,0,1,0,10,10A10,10,0,0,0,60,118Zm136,0a10,10,0,1,0,10,10A10,10,0,0,0,196,118Z`}))],[`regular`,r.createElement(r.Fragment,null,r.createElement(`path`,{d:`M140,128a12,12,0,1,1-12-12A12,12,0,0,1,140,128Zm56-12a12,12,0,1,0,12,12A12,12,0,0,0,196,116ZM60,116a12,12,0,1,0,12,12A12,12,0,0,0,60,116Z`}))],[`thin`,r.createElement(r.Fragment,null,r.createElement(`path`,{d:`M136,128a8,8,0,1,1-8-8A8,8,0,0,1,136,128Zm-76-8a8,8,0,1,0,8,8A8,8,0,0,0,60,120Zm136,0a8,8,0,1,0,8,8A8,8,0,0,0,196,120Z`}))]]),a=r.forwardRef((t,n)=>r.createElement(e,{ref:n,...t,weights:i}));a.displayName=`DotsThreeIcon`;export{a as t};
|
||||
+1
@@ -0,0 +1 @@
|
||||
import{Fn as e,Wn as t,qn as n}from"./index-BwGGYgiP.js";var r=n(t(),1),i=new Map([[`bold`,r.createElement(r.Fragment,null,r.createElement(`path`,{d:`M230.14,70.54,185.46,25.85a20,20,0,0,0-28.29,0L33.86,149.17A19.85,19.85,0,0,0,28,163.31V208a20,20,0,0,0,20,20H92.69a19.86,19.86,0,0,0,14.14-5.86L230.14,98.82a20,20,0,0,0,0-28.28ZM93,180l71-71,11,11-71,71ZM76,163,65,152l71-71,11,11ZM52,173l15.51,15.51h0L83,204H52ZM192,103,153,64l18.34-18.34,39,39Z`}))],[`duotone`,r.createElement(r.Fragment,null,r.createElement(`path`,{d:`M221.66,90.34,192,120,136,64l29.66-29.66a8,8,0,0,1,11.31,0L221.66,79A8,8,0,0,1,221.66,90.34Z`,opacity:`0.2`}),r.createElement(`path`,{d:`M227.31,73.37,182.63,28.68a16,16,0,0,0-22.63,0L36.69,152A15.86,15.86,0,0,0,32,163.31V208a16,16,0,0,0,16,16H92.69A15.86,15.86,0,0,0,104,219.31L227.31,96a16,16,0,0,0,0-22.63ZM51.31,160,136,75.31,152.69,92,68,176.68ZM48,179.31,76.69,208H48Zm48,25.38L79.31,188,164,103.31,180.69,120Zm96-96L147.31,64l24-24L216,84.68Z`}))],[`fill`,r.createElement(r.Fragment,null,r.createElement(`path`,{d:`M227.31,73.37,182.63,28.68a16,16,0,0,0-22.63,0L36.69,152A15.86,15.86,0,0,0,32,163.31V208a16,16,0,0,0,16,16H92.69A15.86,15.86,0,0,0,104,219.31L227.31,96a16,16,0,0,0,0-22.63ZM51.31,160l90.35-90.35,16.68,16.69L68,176.68ZM48,179.31,76.69,208H48Zm48,25.38L79.31,188l90.35-90.35h0l16.68,16.69Z`}))],[`light`,r.createElement(r.Fragment,null,r.createElement(`path`,{d:`M225.9,74.78,181.21,30.09a14,14,0,0,0-19.8,0L38.1,153.41a13.94,13.94,0,0,0-4.1,9.9V208a14,14,0,0,0,14,14H92.69a13.94,13.94,0,0,0,9.9-4.1L225.9,94.58a14,14,0,0,0,0-19.8ZM48.49,160,136,72.48,155.51,92,68,179.51ZM46,208V174.48L81.51,210H48A2,2,0,0,1,46,208Zm50-.49L76.49,188,164,100.48,183.51,120ZM217.41,86.1,192,111.51,144.49,64,169.9,38.58a2,2,0,0,1,2.83,0l44.68,44.69a2,2,0,0,1,0,2.83Z`}))],[`regular`,r.createElement(r.Fragment,null,r.createElement(`path`,{d:`M227.31,73.37,182.63,28.68a16,16,0,0,0-22.63,0L36.69,152A15.86,15.86,0,0,0,32,163.31V208a16,16,0,0,0,16,16H92.69A15.86,15.86,0,0,0,104,219.31L227.31,96a16,16,0,0,0,0-22.63ZM51.31,160,136,75.31,152.69,92,68,176.68ZM48,179.31,76.69,208H48Zm48,25.38L79.31,188,164,103.31,180.69,120Zm96-96L147.31,64l24-24L216,84.68Z`}))],[`thin`,r.createElement(r.Fragment,null,r.createElement(`path`,{d:`M224.49,76.2,179.8,31.51a12,12,0,0,0-17,0L39.52,154.83A11.9,11.9,0,0,0,36,163.31V208a12,12,0,0,0,12,12H92.69a12,12,0,0,0,8.48-3.51L224.48,93.17a12,12,0,0,0,0-17ZM45.66,160,136,69.65,158.34,92,68,182.34ZM44,208V169.66l21.17,21.17h0L86.34,212H48A4,4,0,0,1,44,208Zm52,2.34L73.66,188,164,97.65,186.34,120ZM218.83,87.51,192,114.34,141.66,64l26.82-26.83a4,4,0,0,1,5.66,0l44.69,44.68a4,4,0,0,1,0,5.66Z`}))]]),a=r.forwardRef((t,n)=>r.createElement(e,{ref:n,...t,weights:i}));a.displayName=`PencilIcon`;export{a as t};
|
||||
+1
@@ -0,0 +1 @@
|
||||
import{Fn as e,Wn as t,qn as n}from"./index-BwGGYgiP.js";var r=n(t(),1),i=new Map([[`bold`,r.createElement(r.Fragment,null,r.createElement(`path`,{d:`M216.49,104.49l-80,80a12,12,0,0,1-17,0l-80-80a12,12,0,0,1,17-17L128,159l71.51-71.52a12,12,0,0,1,17,17Z`}))],[`duotone`,r.createElement(r.Fragment,null,r.createElement(`path`,{d:`M208,96l-80,80L48,96Z`,opacity:`0.2`}),r.createElement(`path`,{d:`M215.39,92.94A8,8,0,0,0,208,88H48a8,8,0,0,0-5.66,13.66l80,80a8,8,0,0,0,11.32,0l80-80A8,8,0,0,0,215.39,92.94ZM128,164.69,67.31,104H188.69Z`}))],[`fill`,r.createElement(r.Fragment,null,r.createElement(`path`,{d:`M213.66,101.66l-80,80a8,8,0,0,1-11.32,0l-80-80A8,8,0,0,1,48,88H208a8,8,0,0,1,5.66,13.66Z`}))],[`light`,r.createElement(r.Fragment,null,r.createElement(`path`,{d:`M212.24,100.24l-80,80a6,6,0,0,1-8.48,0l-80-80a6,6,0,0,1,8.48-8.48L128,167.51l75.76-75.75a6,6,0,0,1,8.48,8.48Z`}))],[`regular`,r.createElement(r.Fragment,null,r.createElement(`path`,{d:`M213.66,101.66l-80,80a8,8,0,0,1-11.32,0l-80-80A8,8,0,0,1,53.66,90.34L128,164.69l74.34-74.35a8,8,0,0,1,11.32,11.32Z`}))],[`thin`,r.createElement(r.Fragment,null,r.createElement(`path`,{d:`M210.83,98.83l-80,80a4,4,0,0,1-5.66,0l-80-80a4,4,0,0,1,5.66-5.66L128,170.34l77.17-77.17a4,4,0,1,1,5.66,5.66Z`}))]]),a=new Map([[`bold`,r.createElement(r.Fragment,null,r.createElement(`path`,{d:`M228,128a12,12,0,0,1-12,12H140v76a12,12,0,0,1-24,0V140H40a12,12,0,0,1,0-24h76V40a12,12,0,0,1,24,0v76h76A12,12,0,0,1,228,128Z`}))],[`duotone`,r.createElement(r.Fragment,null,r.createElement(`path`,{d:`M216,56V200a16,16,0,0,1-16,16H56a16,16,0,0,1-16-16V56A16,16,0,0,1,56,40H200A16,16,0,0,1,216,56Z`,opacity:`0.2`}),r.createElement(`path`,{d:`M224,128a8,8,0,0,1-8,8H136v80a8,8,0,0,1-16,0V136H40a8,8,0,0,1,0-16h80V40a8,8,0,0,1,16,0v80h80A8,8,0,0,1,224,128Z`}))],[`fill`,r.createElement(r.Fragment,null,r.createElement(`path`,{d:`M208,32H48A16,16,0,0,0,32,48V208a16,16,0,0,0,16,16H208a16,16,0,0,0,16-16V48A16,16,0,0,0,208,32ZM184,136H136v48a8,8,0,0,1-16,0V136H72a8,8,0,0,1,0-16h48V72a8,8,0,0,1,16,0v48h48a8,8,0,0,1,0,16Z`}))],[`light`,r.createElement(r.Fragment,null,r.createElement(`path`,{d:`M222,128a6,6,0,0,1-6,6H134v82a6,6,0,0,1-12,0V134H40a6,6,0,0,1,0-12h82V40a6,6,0,0,1,12,0v82h82A6,6,0,0,1,222,128Z`}))],[`regular`,r.createElement(r.Fragment,null,r.createElement(`path`,{d:`M224,128a8,8,0,0,1-8,8H136v80a8,8,0,0,1-16,0V136H40a8,8,0,0,1,0-16h80V40a8,8,0,0,1,16,0v80h80A8,8,0,0,1,224,128Z`}))],[`thin`,r.createElement(r.Fragment,null,r.createElement(`path`,{d:`M220,128a4,4,0,0,1-4,4H132v84a4,4,0,0,1-8,0V132H40a4,4,0,0,1,0-8h84V40a4,4,0,0,1,8,0v84h84A4,4,0,0,1,220,128Z`}))]]),o=r.forwardRef((t,n)=>r.createElement(e,{ref:n,...t,weights:i}));o.displayName=`CaretDownIcon`;var s=r.forwardRef((t,n)=>r.createElement(e,{ref:n,...t,weights:a}));s.displayName=`PlusIcon`;export{o as n,s as t};
|
||||
+1
@@ -0,0 +1 @@
|
||||
import{Fn as e,Gn as t,Wn as n,qn as r,wt as i,zn as a}from"./index-BwGGYgiP.js";var o=r(n(),1),s=new Map([[`bold`,o.createElement(o.Fragment,null,o.createElement(`path`,{d:`M240.26,186.1,152.81,34.23h0a28.74,28.74,0,0,0-49.62,0L15.74,186.1a27.45,27.45,0,0,0,0,27.71A28.31,28.31,0,0,0,40.55,228h174.9a28.31,28.31,0,0,0,24.79-14.19A27.45,27.45,0,0,0,240.26,186.1Zm-20.8,15.7a4.46,4.46,0,0,1-4,2.2H40.55a4.46,4.46,0,0,1-4-2.2,3.56,3.56,0,0,1,0-3.73L124,46.2a4.77,4.77,0,0,1,8,0l87.44,151.87A3.56,3.56,0,0,1,219.46,201.8ZM116,136V104a12,12,0,0,1,24,0v32a12,12,0,0,1-24,0Zm28,40a16,16,0,1,1-16-16A16,16,0,0,1,144,176Z`}))],[`duotone`,o.createElement(o.Fragment,null,o.createElement(`path`,{d:`M215.46,216H40.54C27.92,216,20,202.79,26.13,192.09L113.59,40.22c6.3-11,22.52-11,28.82,0l87.46,151.87C236,202.79,228.08,216,215.46,216Z`,opacity:`0.2`}),o.createElement(`path`,{d:`M236.8,188.09,149.35,36.22h0a24.76,24.76,0,0,0-42.7,0L19.2,188.09a23.51,23.51,0,0,0,0,23.72A24.35,24.35,0,0,0,40.55,224h174.9a24.35,24.35,0,0,0,21.33-12.19A23.51,23.51,0,0,0,236.8,188.09ZM222.93,203.8a8.5,8.5,0,0,1-7.48,4.2H40.55a8.5,8.5,0,0,1-7.48-4.2,7.59,7.59,0,0,1,0-7.72L120.52,44.21a8.75,8.75,0,0,1,15,0l87.45,151.87A7.59,7.59,0,0,1,222.93,203.8ZM120,144V104a8,8,0,0,1,16,0v40a8,8,0,0,1-16,0Zm20,36a12,12,0,1,1-12-12A12,12,0,0,1,140,180Z`}))],[`fill`,o.createElement(o.Fragment,null,o.createElement(`path`,{d:`M236.8,188.09,149.35,36.22h0a24.76,24.76,0,0,0-42.7,0L19.2,188.09a23.51,23.51,0,0,0,0,23.72A24.35,24.35,0,0,0,40.55,224h174.9a24.35,24.35,0,0,0,21.33-12.19A23.51,23.51,0,0,0,236.8,188.09ZM120,104a8,8,0,0,1,16,0v40a8,8,0,0,1-16,0Zm8,88a12,12,0,1,1,12-12A12,12,0,0,1,128,192Z`}))],[`light`,o.createElement(o.Fragment,null,o.createElement(`path`,{d:`M235.07,189.09,147.61,37.22h0a22.75,22.75,0,0,0-39.22,0L20.93,189.09a21.53,21.53,0,0,0,0,21.72A22.35,22.35,0,0,0,40.55,222h174.9a22.35,22.35,0,0,0,19.6-11.19A21.53,21.53,0,0,0,235.07,189.09ZM224.66,204.8a10.46,10.46,0,0,1-9.21,5.2H40.55a10.46,10.46,0,0,1-9.21-5.2,9.51,9.51,0,0,1,0-9.72L118.79,43.21a10.75,10.75,0,0,1,18.42,0l87.46,151.87A9.51,9.51,0,0,1,224.66,204.8ZM122,144V104a6,6,0,0,1,12,0v40a6,6,0,0,1-12,0Zm16,36a10,10,0,1,1-10-10A10,10,0,0,1,138,180Z`}))],[`regular`,o.createElement(o.Fragment,null,o.createElement(`path`,{d:`M236.8,188.09,149.35,36.22h0a24.76,24.76,0,0,0-42.7,0L19.2,188.09a23.51,23.51,0,0,0,0,23.72A24.35,24.35,0,0,0,40.55,224h174.9a24.35,24.35,0,0,0,21.33-12.19A23.51,23.51,0,0,0,236.8,188.09ZM222.93,203.8a8.5,8.5,0,0,1-7.48,4.2H40.55a8.5,8.5,0,0,1-7.48-4.2,7.59,7.59,0,0,1,0-7.72L120.52,44.21a8.75,8.75,0,0,1,15,0l87.45,151.87A7.59,7.59,0,0,1,222.93,203.8ZM120,144V104a8,8,0,0,1,16,0v40a8,8,0,0,1-16,0Zm20,36a12,12,0,1,1-12-12A12,12,0,0,1,140,180Z`}))],[`thin`,o.createElement(o.Fragment,null,o.createElement(`path`,{d:`M233.34,190.09,145.88,38.22h0a20.75,20.75,0,0,0-35.76,0L22.66,190.09a19.52,19.52,0,0,0,0,19.71A20.36,20.36,0,0,0,40.54,220H215.46a20.36,20.36,0,0,0,17.86-10.2A19.52,19.52,0,0,0,233.34,190.09ZM226.4,205.8a12.47,12.47,0,0,1-10.94,6.2H40.54a12.47,12.47,0,0,1-10.94-6.2,11.45,11.45,0,0,1,0-11.72L117.05,42.21a12.76,12.76,0,0,1,21.9,0L226.4,194.08A11.45,11.45,0,0,1,226.4,205.8ZM124,144V104a4,4,0,0,1,8,0v40a4,4,0,0,1-8,0Zm12,36a8,8,0,1,1-8-8A8,8,0,0,1,136,180Z`}))]]),c=o.forwardRef((t,n)=>o.createElement(e,{ref:n,...t,weights:s}));c.displayName=`WarningIcon`;var l=t(),u=`An unknown error occurred. Please report this issue to Cloudflare.`;function d({error:e}){let t=(`errors`in e?e.errors?.[0]?.message:e.message)??u;return(0,l.jsxs)(`div`,{className:`text-text-secondary flex flex-1 flex-col items-center justify-center space-y-4 p-12 text-center`,children:[(0,l.jsx)(c,{size:48}),(0,l.jsx)(`h2`,{className:`text-text text-3xl font-bold`,children:`Something went wrong`}),(0,l.jsx)(`p`,{className:`text-text-secondary text-sm font-light`,children:t}),(0,l.jsx)(a,{to:`/`,children:(0,l.jsx)(i,{variant:`secondary`,children:`Go home`})})]})}export{d as t};
|
||||
+1
File diff suppressed because one or more lines are too long
+25
File diff suppressed because one or more lines are too long
+1
@@ -0,0 +1 @@
|
||||
import{Gn as e,Ln as t}from"./index-BwGGYgiP.js";var n=e(),r=()=>(0,n.jsx)(t,{});export{r as component};
|
||||
+1
@@ -0,0 +1 @@
|
||||
import{st as e}from"./index-BwGGYgiP.js";var t=e;export{t as notFoundComponent};
|
||||
+1
@@ -0,0 +1 @@
|
||||
import{t as e}from"./ResourceError-DwVOufwC.js";var t=e;export{t as errorComponent};
|
||||
+1
@@ -0,0 +1 @@
|
||||
import{t as e}from"./ResourceError-DwVOufwC.js";var t=e;export{t as errorComponent};
|
||||
+1
File diff suppressed because one or more lines are too long
+1
@@ -0,0 +1 @@
|
||||
import{t as e}from"./ResourceError-DwVOufwC.js";var t=e;export{t as errorComponent};
|
||||
+1
@@ -0,0 +1 @@
|
||||
import{Gn as e,Ln as t}from"./index-BwGGYgiP.js";var n=e(),r=()=>(0,n.jsx)(t,{});export{r as component};
|
||||
+1
File diff suppressed because one or more lines are too long
+1
@@ -0,0 +1 @@
|
||||
import{st as e}from"./index-BwGGYgiP.js";var t=e;export{t as notFoundComponent};
|
||||
+1
@@ -0,0 +1 @@
|
||||
import{t as e}from"./ResourceError-DwVOufwC.js";var t=e;export{t as errorComponent};
|
||||
+1
@@ -0,0 +1 @@
|
||||
import{st as e}from"./index-BwGGYgiP.js";var t=e;export{t as notFoundComponent};
|
||||
+1
@@ -0,0 +1 @@
|
||||
import{a as e,i as t,n,r,t as i}from"./TableSelect-HrnHFgor.js";import{t as a}from"./Pencil.es-DwL8uC1Z.js";import{n as o}from"./dialog-oqh8l3l3zutpibxx-TbiRttKB.js";import{t as s}from"./Breadcrumbs-7fG3Aw2e.js";import{Gn as c,Hn as l,Rn as u,Un as d,Vn as f,Wn as p,c as m,l as h,ot as g,qn as _,tt as v,wt as y}from"./index-BwGGYgiP.js";var b=_(p()),x=c(),S=u(`__root__`);function C(){let c=m.useParams(),u=m.useLoaderData(),p=m.useSearch(),_=f(),C=d(),w=S.useLoaderData(),T=l(),E=(0,b.useRef)(p.table),D=(0,b.useRef)(null),[O,k]=(0,b.useState)(p.table),[A,j]=(0,b.useState)(!1),[M,N]=(0,b.useState)(null),P=(0,b.useMemo)(()=>new h(c.databaseId),[c.databaseId]),F=(0,b.useMemo)(()=>v(w.workers,T.location.searchStr)?.bindings?.d1?.find(e=>e.id===c.databaseId)?.bindingName,[w.workers,T.location.searchStr,c.databaseId]),I=(0,b.useMemo)(()=>({databaseId:c.databaseId,type:`d1`}),[c.databaseId]),L=(0,b.useCallback)(e=>{k(e),E.current!==e&&(E.current=e,_({replace:!0,search:t=>({...t,table:e}),to:`.`}))},[_]),R=(0,b.useCallback)(async()=>{j(!0);try{await Promise.all([C.invalidate(),D.current?.refreshSchema(),new Promise(e=>setTimeout(e,250))])}finally{j(!1)}},[C]),z=(0,b.useCallback)(async()=>{await R(),_({replace:!0,search:e=>({...e,table:void 0}),to:`.`})},[R,_]),B=(0,b.useCallback)(()=>{O&&N({schemaName:`main`,tableName:O})},[O]),V=(0,b.useCallback)(()=>{N(null)},[]),H=(0,b.useCallback)(()=>{M&&(D.current?.closeTableTabs(M.schemaName,M.tableName),z())},[M,z]);return(0,x.jsxs)(`div`,{className:`flex h-full flex-col`,children:[(0,x.jsxs)(s,{icon:g,title:`D1`,items:[(0,x.jsx)(`span`,{className:`flex items-center gap-1.5`,children:F&&F!==c.databaseId?(0,x.jsxs)(x.Fragment,{children:[F,(0,x.jsxs)(`span`,{className:`text-kumo-subtle`,children:[`(`,c.databaseId,`)`]})]}):c.databaseId},`database-id`),(0,x.jsx)(i,{selectedTable:p.table,studioRef:D,tables:u.tables},`table-selector`)],children:[(0,x.jsx)(`div`,{className:`flex-1`}),(0,x.jsx)(y,{"aria-label":`Refresh tables`,className:`disabled:cursor-progress`,disabled:A,onClick:R,shape:`square`,children:(0,x.jsx)(e,{className:A?`animate-spin`:void 0,size:14})}),(0,x.jsx)(n,{currentTable:O,driver:P}),(0,x.jsx)(y,{"aria-label":`Edit table schema`,disabled:!O,icon:a,onClick:()=>{O&&D.current?.openEditTableTab(`main`,O)},children:`Edit Schema`}),(0,x.jsx)(y,{"aria-label":`Delete table`,disabled:!O,icon:o,onClick:B,variant:`secondary-destructive`,children:`Delete Table`})]}),M&&(0,x.jsx)(r,{closeModal:V,driver:P,isOpen:!0,onSuccess:H,schemaName:M.schemaName,tableName:M.tableName}),(0,x.jsx)(`div`,{className:`flex-1 overflow-hidden bg-kumo-elevated`,children:(0,x.jsx)(t,{driver:P,initialTable:p.table,onTableChange:L,ref:D,resource:I},c.databaseId)})]})}export{C as component};
|
||||
+1
@@ -0,0 +1 @@
|
||||
import{t as e}from"./ResourceError-DwVOufwC.js";var t=e;export{t as errorComponent};
|
||||
+1
File diff suppressed because one or more lines are too long
+1
@@ -0,0 +1 @@
|
||||
import{st as e}from"./index-BwGGYgiP.js";var t=e;export{t as notFoundComponent};
|
||||
+1
@@ -0,0 +1 @@
|
||||
import{t as e}from"./ResourceError-DwVOufwC.js";var t=e;export{t as errorComponent};
|
||||
+1
File diff suppressed because one or more lines are too long
+1
@@ -0,0 +1 @@
|
||||
import{t as e}from"./ResourceError-DwVOufwC.js";var t=e;export{t as errorComponent};
|
||||
+1
@@ -0,0 +1 @@
|
||||
import{st as e}from"./index-BwGGYgiP.js";var t=e;export{t as notFoundComponent};
|
||||
+1
@@ -0,0 +1 @@
|
||||
import{a as e,i as t,n,r,t as i}from"./TableSelect-HrnHFgor.js";import{t as a}from"./Pencil.es-DwL8uC1Z.js";import{n as o}from"./dialog-oqh8l3l3zutpibxx-TbiRttKB.js";import{n as s,t as c}from"./Breadcrumbs-7fG3Aw2e.js";import{Gn as l,Un as u,Vn as d,Wn as f,at as p,n as m,qn as h,r as g,wt as _,zn as v}from"./index-BwGGYgiP.js";var y=h(f()),b=l();function x(){let l=m.useParams(),f=m.useLoaderData(),{namespaceId:h,objectId:x,objectName:S}=f,C=m.useSearch(),w=d(),T=u(),E=(0,y.useRef)(C.table),D=(0,y.useRef)(null),[O,k]=(0,y.useState)(C.table),[A,j]=(0,y.useState)(!1),[M,N]=(0,y.useState)(null),P=(0,y.useMemo)(()=>new g(h,x,S),[h,x,S]),F=(0,y.useMemo)(()=>({namespaceId:h,objectId:l.objectId,type:`do`}),[h,l.objectId]),I=(0,y.useCallback)(e=>{k(e),E.current!==e&&(E.current=e,w({replace:!0,search:t=>({...t,table:e}),to:`.`}))},[w]),L=(0,y.useCallback)(async()=>{j(!0);try{await Promise.all([T.invalidate(),D.current?.refreshSchema(),new Promise(e=>setTimeout(e,250))])}finally{j(!1)}},[T]),R=(0,y.useCallback)(async()=>{await L(),w({replace:!0,search:e=>({...e,table:void 0}),to:`.`})},[L,w]),z=(0,y.useCallback)(()=>{O&&N({schemaName:`main`,tableName:O})},[O]),B=(0,y.useCallback)(()=>{N(null)},[]),V=(0,y.useCallback)(()=>{M&&(D.current?.closeTableTabs(M.schemaName,M.tableName),R())},[M,R]),H=l.objectId.length>16?`${l.objectId.slice(0,8)}...${l.objectId.slice(-8)}`:l.objectId;return(0,b.jsxs)(`div`,{className:`flex h-full flex-col`,children:[(0,b.jsxs)(c,{icon:p,items:[(0,b.jsx)(v,{className:`flex items-center gap-1.5`,params:{className:l.className},to:`/do/$className`,children:l.className},`class-name`),(0,b.jsxs)(`span`,{className:`flex items-center gap-1 font-mono text-xs [&_button]:opacity-100`,title:l.objectId,children:[H,(0,b.jsx)(s.Clipboard,{text:l.objectId})]},`object-id`),(0,b.jsx)(i,{selectedTable:C.table,studioRef:D,tables:f.tables},`table-selector`)],title:`Durable Objects`,children:[(0,b.jsx)(`div`,{className:`flex-1`}),(0,b.jsx)(_,{"aria-label":`Refresh tables`,className:`disabled:cursor-progress`,disabled:A,onClick:L,shape:`square`,children:(0,b.jsx)(e,{className:A?`animate-spin`:void 0,size:14})}),(0,b.jsx)(n,{currentTable:O,driver:P}),(0,b.jsx)(_,{"aria-label":`Edit table schema`,disabled:!O,icon:a,onClick:()=>{O&&D.current?.openEditTableTab(`main`,O)},children:`Edit Schema`}),(0,b.jsx)(_,{"aria-label":`Delete table`,disabled:!O,icon:o,onClick:z,variant:`secondary-destructive`,children:`Delete Table`})]}),M&&(0,b.jsx)(r,{closeModal:B,driver:P,isOpen:!0,onSuccess:V,schemaName:M.schemaName,tableName:M.tableName}),(0,b.jsx)(`div`,{className:`flex-1 overflow-hidden`,children:(0,b.jsx)(t,{driver:P,initialTable:C.table,onTableChange:I,ref:D,resource:F},`${h}-${l.objectId}`)})]})}export{x as component};
|
||||
+1
@@ -0,0 +1 @@
|
||||
import{t as e}from"./ResourceError-DwVOufwC.js";var t=e;export{t as errorComponent};
|
||||
+1
@@ -0,0 +1 @@
|
||||
import{Gn as e,Ln as t}from"./index-BwGGYgiP.js";var n=e(),r=()=>(0,n.jsx)(t,{});export{r as component};
|
||||
+1
@@ -0,0 +1 @@
|
||||
import{t as e}from"./ResourceError-DwVOufwC.js";var t=e;export{t as errorComponent};
|
||||
+1
File diff suppressed because one or more lines are too long
+1
@@ -0,0 +1 @@
|
||||
import{st as e}from"./index-BwGGYgiP.js";var t=e;export{t as notFoundComponent};
|
||||
+1
@@ -0,0 +1 @@
|
||||
import{t as e}from"./ResourceError-DwVOufwC.js";var t=e;export{t as errorComponent};
|
||||
+1
@@ -0,0 +1 @@
|
||||
import{Fn as e,Wn as t,qn as n}from"./index-BwGGYgiP.js";var r=n(t(),1),i=new Map([[`bold`,r.createElement(r.Fragment,null,r.createElement(`path`,{d:`M228,128a12,12,0,0,1-12,12H40a12,12,0,0,1,0-24H216A12,12,0,0,1,228,128ZM40,76H216a12,12,0,0,0,0-24H40a12,12,0,0,0,0,24ZM216,180H40a12,12,0,0,0,0,24H216a12,12,0,0,0,0-24Z`}))],[`duotone`,r.createElement(r.Fragment,null,r.createElement(`path`,{d:`M216,64V192H40V64Z`,opacity:`0.2`}),r.createElement(`path`,{d:`M224,128a8,8,0,0,1-8,8H40a8,8,0,0,1,0-16H216A8,8,0,0,1,224,128ZM40,72H216a8,8,0,0,0,0-16H40a8,8,0,0,0,0,16ZM216,184H40a8,8,0,0,0,0,16H216a8,8,0,0,0,0-16Z`}))],[`fill`,r.createElement(r.Fragment,null,r.createElement(`path`,{d:`M208,32H48A16,16,0,0,0,32,48V208a16,16,0,0,0,16,16H208a16,16,0,0,0,16-16V48A16,16,0,0,0,208,32ZM192,184H64a8,8,0,0,1,0-16H192a8,8,0,0,1,0,16Zm0-48H64a8,8,0,0,1,0-16H192a8,8,0,0,1,0,16Zm0-48H64a8,8,0,0,1,0-16H192a8,8,0,0,1,0,16Z`}))],[`light`,r.createElement(r.Fragment,null,r.createElement(`path`,{d:`M222,128a6,6,0,0,1-6,6H40a6,6,0,0,1,0-12H216A6,6,0,0,1,222,128ZM40,70H216a6,6,0,0,0,0-12H40a6,6,0,0,0,0,12ZM216,186H40a6,6,0,0,0,0,12H216a6,6,0,0,0,0-12Z`}))],[`regular`,r.createElement(r.Fragment,null,r.createElement(`path`,{d:`M224,128a8,8,0,0,1-8,8H40a8,8,0,0,1,0-16H216A8,8,0,0,1,224,128ZM40,72H216a8,8,0,0,0,0-16H40a8,8,0,0,0,0,16ZM216,184H40a8,8,0,0,0,0,16H216a8,8,0,0,0,0-16Z`}))],[`thin`,r.createElement(r.Fragment,null,r.createElement(`path`,{d:`M220,128a4,4,0,0,1-4,4H40a4,4,0,0,1,0-8H216A4,4,0,0,1,220,128ZM40,68H216a4,4,0,0,0,0-8H40a4,4,0,0,0,0,8ZM216,188H40a4,4,0,0,0,0,8H216a4,4,0,0,0,0-8Z`}))]]),a=r.forwardRef((t,n)=>r.createElement(e,{ref:n,...t,weights:i}));a.displayName=`ListIcon`;async function o(e,t=300){let[n]=await Promise.all([e,new Promise(e=>setTimeout(e,t))]);return n}export{a as n,o as t};
|
||||
Generated
Vendored
+1
@@ -0,0 +1 @@
|
||||
import{t as e}from"./label-latndvb1ngem7we8-DtCVY6UF.js";import{$t as t,At as n,Fn as r,Gn as i,Ht as a,In as o,Ut as s,Wn as c,_n as l,jn as u,qn as d,xn as f,zt as p}from"./index-BwGGYgiP.js";var m=d(c(),1),h=new Map([[`bold`,m.createElement(m.Fragment,null,m.createElement(`path`,{d:`M228,128a12,12,0,0,1-12,12H40a12,12,0,0,1,0-24H216A12,12,0,0,1,228,128Z`}))],[`duotone`,m.createElement(m.Fragment,null,m.createElement(`path`,{d:`M216,56V200a16,16,0,0,1-16,16H56a16,16,0,0,1-16-16V56A16,16,0,0,1,56,40H200A16,16,0,0,1,216,56Z`,opacity:`0.2`}),m.createElement(`path`,{d:`M224,128a8,8,0,0,1-8,8H40a8,8,0,0,1,0-16H216A8,8,0,0,1,224,128Z`}))],[`fill`,m.createElement(m.Fragment,null,m.createElement(`path`,{d:`M208,32H48A16,16,0,0,0,32,48V208a16,16,0,0,0,16,16H208a16,16,0,0,0,16-16V48A16,16,0,0,0,208,32ZM184,136H72a8,8,0,0,1,0-16H184a8,8,0,0,1,0,16Z`}))],[`light`,m.createElement(m.Fragment,null,m.createElement(`path`,{d:`M222,128a6,6,0,0,1-6,6H40a6,6,0,0,1,0-12H216A6,6,0,0,1,222,128Z`}))],[`regular`,m.createElement(m.Fragment,null,m.createElement(`path`,{d:`M224,128a8,8,0,0,1-8,8H40a8,8,0,0,1,0-16H216A8,8,0,0,1,224,128Z`}))],[`thin`,m.createElement(m.Fragment,null,m.createElement(`path`,{d:`M220,128a4,4,0,0,1-4,4H40a4,4,0,0,1,0-8H216A4,4,0,0,1,220,128Z`}))]]),g=m.forwardRef((e,t)=>m.createElement(r,{ref:t,...e,weights:h}));g.displayName=`MinusIcon`;var _=i(),v=(0,m.createContext)({controlFirst:!0}),y=(0,m.forwardRef)(({className:n,checked:r,indeterminate:i,disabled:c,variant:d=`default`,label:f,labelTooltip:p,controlFirst:m=!0,onCheckedChange:h,onValueChange:v,onChange:y,required:b,name:x,...S},C)=>{let w=(0,_.jsx)(t,{ref:C,name:x,checked:r,indeterminate:i,disabled:c,onCheckedChange:(e,t)=>{h?.(e),v?.(e),y&&y(Object.assign(t.event,{target:{checked:e}}))},className:o(`relative flex h-4 w-4 items-center justify-center rounded-sm border-0 bg-kumo-base ring after:absolute after:-inset-x-3 after:-inset-y-2`,d===`error`?`ring-kumo-danger`:`ring-kumo-line`,!c&&`hover:ring-kumo-hairline focus-visible:ring-kumo-hairline`,`data-[checked]:bg-kumo-contrast data-[checked]:ring-kumo-contrast data-[indeterminate]:bg-kumo-contrast data-[indeterminate]:ring-kumo-contrast`,c&&`cursor-not-allowed opacity-50`,n),...S,children:(0,_.jsx)(l,{keepMounted:!0,className:`flex items-center justify-center text-kumo-inverse data-[unchecked]:invisible`,render:(e,t)=>(0,_.jsx)(`span`,{...e,children:t.indeterminate?(0,_.jsx)(g,{weight:`bold`,size:12}):(0,_.jsx)(u,{weight:`bold`,size:12})})})});return f?(0,_.jsx)(a,{className:`inline-flex`,children:(0,_.jsxs)(s,{className:o(`!m-0 !min-h-0 !text-base inline-flex items-center gap-2`,m?`flex-row`:`flex-row-reverse justify-end`,c?`cursor-not-allowed`:`cursor-pointer`),children:[w,(0,_.jsx)(e,{showOptional:b===!1,tooltip:p,asContent:!0,children:f})]})}):w});y.displayName=`Checkbox`;var b=(0,m.forwardRef)(({className:e,checked:n,indeterminate:r,disabled:i,variant:a=`default`,label:s,value:c,onCheckedChange:d,onValueChange:f,name:p},h)=>{let{controlFirst:y}=(0,m.useContext)(v);return(0,_.jsxs)(`label`,{className:o(`m-0 relative inline-flex items-center gap-2`,!y&&`flex-row-reverse justify-end`,i?`cursor-not-allowed opacity-50`:`cursor-pointer`,e),children:[(0,_.jsx)(t,{ref:h,value:c,name:p,checked:n,indeterminate:r,disabled:i,onCheckedChange:e=>{d?.(e),f?.(e)},className:o(`peer relative flex h-4 w-4 items-center justify-center rounded-sm border-0 bg-kumo-base ring after:absolute after:-inset-x-3 after:-inset-y-2`,a===`error`?`ring-kumo-danger`:`ring-kumo-line`,!i&&`group-hover:ring-kumo-hairline hover:ring-kumo-hairline focus-visible:ring-kumo-hairline`,`data-[checked]:bg-kumo-contrast data-[checked]:ring-kumo-contrast data-[indeterminate]:bg-kumo-contrast data-[indeterminate]:ring-kumo-contrast`),children:(0,_.jsx)(l,{keepMounted:!0,className:`flex items-center justify-center text-kumo-inverse data-[unchecked]:invisible`,render:(e,t)=>(0,_.jsx)(`span`,{...e,children:t.indeterminate?(0,_.jsx)(g,{weight:`bold`,size:12}):(0,_.jsx)(u,{weight:`bold`,size:12})})})}),(0,_.jsx)(`span`,{className:`text-base text-kumo-default`,children:s})]})});b.displayName=`Checkbox.Item`;function x({legend:e,children:t,error:r,description:i,defaultValue:a,value:s,onValueChange:c,allValues:l,disabled:u,controlFirst:d=!0,className:m}){return(0,_.jsx)(v.Provider,{value:{controlFirst:d},children:(0,_.jsx)(f,{defaultValue:a,value:s,onValueChange:c,allValues:l,disabled:u,children:(0,_.jsxs)(n,{className:o(`flex flex-col gap-4`,m),children:[(0,_.jsx)(p,{className:`text-base font-medium text-kumo-default`,children:e}),(0,_.jsx)(`div`,{className:`flex flex-col gap-2`,children:t}),r&&(0,_.jsx)(`p`,{className:`text-sm text-kumo-danger`,children:r}),i&&(0,_.jsx)(`p`,{className:`text-sm text-kumo-subtle`,children:i})]})})})}var S=Object.assign(y,{Item:b,Group:x});S.displayName=`Checkbox`;export{S as t};
|
||||
Generated
Vendored
+1
File diff suppressed because one or more lines are too long
Generated
Vendored
+1
File diff suppressed because one or more lines are too long
+1
@@ -0,0 +1 @@
|
||||
import{Fn as e,Wn as t,qn as n}from"./index-BwGGYgiP.js";var r=n(t(),1),i=new Map([[`bold`,r.createElement(r.Fragment,null,r.createElement(`path`,{d:`M71.51,88.49a12,12,0,0,1,17-17L116,99V24a12,12,0,0,1,24,0V99l27.51-27.52a12,12,0,0,1,17,17l-48,48a12,12,0,0,1-17,0ZM224,116H188a12,12,0,0,0,0,24h32v56H36V140H68a12,12,0,0,0,0-24H32a20,20,0,0,0-20,20v64a20,20,0,0,0,20,20H224a20,20,0,0,0,20-20V136A20,20,0,0,0,224,116Zm-20,52a16,16,0,1,0-16,16A16,16,0,0,0,204,168Z`}))],[`duotone`,r.createElement(r.Fragment,null,r.createElement(`path`,{d:`M232,136v64a8,8,0,0,1-8,8H32a8,8,0,0,1-8-8V136a8,8,0,0,1,8-8H224A8,8,0,0,1,232,136Z`,opacity:`0.2`}),r.createElement(`path`,{d:`M240,136v64a16,16,0,0,1-16,16H32a16,16,0,0,1-16-16V136a16,16,0,0,1,16-16H72a8,8,0,0,1,0,16H32v64H224V136H184a8,8,0,0,1,0-16h40A16,16,0,0,1,240,136Zm-117.66-2.34a8,8,0,0,0,11.32,0l48-48a8,8,0,0,0-11.32-11.32L136,108.69V24a8,8,0,0,0-16,0v84.69L85.66,74.34A8,8,0,0,0,74.34,85.66ZM200,168a12,12,0,1,0-12,12A12,12,0,0,0,200,168Z`}))],[`fill`,r.createElement(r.Fragment,null,r.createElement(`path`,{d:`M74.34,85.66A8,8,0,0,1,85.66,74.34L120,108.69V24a8,8,0,0,1,16,0v84.69l34.34-34.35a8,8,0,0,1,11.32,11.32l-48,48a8,8,0,0,1-11.32,0ZM240,136v64a16,16,0,0,1-16,16H32a16,16,0,0,1-16-16V136a16,16,0,0,1,16-16H84.4a4,4,0,0,1,2.83,1.17L111,145A24,24,0,0,0,145,145l23.8-23.8A4,4,0,0,1,171.6,120H224A16,16,0,0,1,240,136Zm-40,32a12,12,0,1,0-12,12A12,12,0,0,0,200,168Z`}))],[`light`,r.createElement(r.Fragment,null,r.createElement(`path`,{d:`M238,136v64a14,14,0,0,1-14,14H32a14,14,0,0,1-14-14V136a14,14,0,0,1,14-14H72a6,6,0,0,1,0,12H32a2,2,0,0,0-2,2v64a2,2,0,0,0,2,2H224a2,2,0,0,0,2-2V136a2,2,0,0,0-2-2H184a6,6,0,0,1,0-12h40A14,14,0,0,1,238,136Zm-114.24-3.76a6,6,0,0,0,8.48,0l48-48a6,6,0,0,0-8.48-8.48L134,113.51V24a6,6,0,0,0-12,0v89.51L84.24,75.76a6,6,0,0,0-8.48,8.48ZM198,168a10,10,0,1,0-10,10A10,10,0,0,0,198,168Z`}))],[`regular`,r.createElement(r.Fragment,null,r.createElement(`path`,{d:`M240,136v64a16,16,0,0,1-16,16H32a16,16,0,0,1-16-16V136a16,16,0,0,1,16-16H72a8,8,0,0,1,0,16H32v64H224V136H184a8,8,0,0,1,0-16h40A16,16,0,0,1,240,136Zm-117.66-2.34a8,8,0,0,0,11.32,0l48-48a8,8,0,0,0-11.32-11.32L136,108.69V24a8,8,0,0,0-16,0v84.69L85.66,74.34A8,8,0,0,0,74.34,85.66ZM200,168a12,12,0,1,0-12,12A12,12,0,0,0,200,168Z`}))],[`thin`,r.createElement(r.Fragment,null,r.createElement(`path`,{d:`M236,136v64a12,12,0,0,1-12,12H32a12,12,0,0,1-12-12V136a12,12,0,0,1,12-12H72a4,4,0,0,1,0,8H32a4,4,0,0,0-4,4v64a4,4,0,0,0,4,4H224a4,4,0,0,0,4-4V136a4,4,0,0,0-4-4H184a4,4,0,0,1,0-8h40A12,12,0,0,1,236,136Zm-110.83-5.17a4,4,0,0,0,5.66,0l48-48a4,4,0,1,0-5.66-5.66L132,118.34V24a4,4,0,0,0-8,0v94.34L82.83,77.17a4,4,0,0,0-5.66,5.66ZM196,168a8,8,0,1,0-8,8A8,8,0,0,0,196,168Z`}))]]),a=r.forwardRef((t,n)=>r.createElement(e,{ref:n,...t,weights:i}));a.displayName=`DownloadIcon`;var o=[`B`,`kB`,`MB`,`GB`,`TB`,`PB`,`EB`,`ZB`,`YB`],s=[`B`,`KiB`,`MiB`,`GiB`,`TiB`,`PiB`,`EiB`,`ZiB`,`YiB`],c=[`b`,`kbit`,`Mbit`,`Gbit`,`Tbit`,`Pbit`,`Ebit`,`Zbit`,`Ybit`],l=[`b`,`kibit`,`Mibit`,`Gibit`,`Tibit`,`Pibit`,`Eibit`,`Zibit`,`Yibit`],u=(e,t,n)=>{let r=e;return typeof t==`string`||Array.isArray(t)?r=e.toLocaleString(t,n):(t===!0||n!==void 0)&&(r=e.toLocaleString(void 0,n)),r},d=e=>{if(typeof e==`number`)return Math.log10(e);let t=e.toString(10);return t.length+Math.log10(`0.${t.slice(0,15)}`)},f=e=>typeof e==`number`?Math.log(e):d(e)*Math.log(10),p=(e,t)=>{if(typeof e==`number`)return e/t;let n=e/BigInt(t),r=e%BigInt(t);return Number(n)+Number(r)/t},m=(e,t)=>{if(t===void 0)return e;if(typeof t!=`number`||!Number.isSafeInteger(t)||t<0)throw TypeError(`Expected fixedWidth to be a non-negative integer, got ${typeof t}: ${t}`);return t===0?e:e.length<t?e.padStart(t,` `):e},h=e=>{let{minimumFractionDigits:t,maximumFractionDigits:n}=e;if(!(t===void 0&&n===void 0))return{...t!==void 0&&{minimumFractionDigits:t},...n!==void 0&&{maximumFractionDigits:n},roundingMode:`trunc`}};function g(e,t){if(typeof e!=`bigint`&&!Number.isFinite(e))throw TypeError(`Expected a finite number, got ${typeof e}: ${e}`);t={bits:!1,binary:!1,space:!0,nonBreakingSpace:!1,...t};let n=t.bits?t.binary?l:c:t.binary?s:o,r=t.space?t.nonBreakingSpace?`\xA0`:` `:``,i=typeof e==`number`?e===0:e===0n;if(t.signed&&i)return m(` 0${r}${n[0]}`,t.fixedWidth);let a=e<0,g=a?`-`:t.signed?`+`:``;a&&(e=-e);let _=h(t),v;if(e<1)v=g+u(e,t.locale,_)+r+n[0];else{let i=Math.min(Math.floor(t.binary?f(e)/Math.log(1024):d(e)/3),n.length-1);if(e=p(e,(t.binary?1024:1e3)**i),!_){let t=Math.max(3,Math.floor(e).toString().length);e=e.toPrecision(t)}let a=u(Number(e),t.locale,_),o=n[i];v=g+a+r+o}return m(v,t.fixedWidth)}function _(e){return g(e??0)}function v(e){if(!e)return`-`;try{let t=new Date(e);return isNaN(t.getTime())?`-`:new Intl.DateTimeFormat(`en-GB`,{day:`numeric`,month:`short`,year:`numeric`,hour:`2-digit`,minute:`2-digit`,second:`2-digit`,timeZone:`UTC`,timeZoneName:`short`}).format(t)}catch{return`-`}}export{_ as n,a as r,v as t};
|
||||
+42
File diff suppressed because one or more lines are too long
+2
File diff suppressed because one or more lines are too long
Generated
Vendored
+1
File diff suppressed because one or more lines are too long
Generated
Vendored
+1
@@ -0,0 +1 @@
|
||||
import{Dt as e,Fn as t,Gn as n,In as r,Wn as i,qn as a,wt as o}from"./index-BwGGYgiP.js";var s=a(i(),1),c=new Map([[`bold`,s.createElement(s.Fragment,null,s.createElement(`path`,{d:`M108,84a16,16,0,1,1,16,16A16,16,0,0,1,108,84Zm128,44A108,108,0,1,1,128,20,108.12,108.12,0,0,1,236,128Zm-24,0a84,84,0,1,0-84,84A84.09,84.09,0,0,0,212,128Zm-72,36.68V132a20,20,0,0,0-20-20,12,12,0,0,0-4,23.32V168a20,20,0,0,0,20,20,12,12,0,0,0,4-23.32Z`}))],[`duotone`,s.createElement(s.Fragment,null,s.createElement(`path`,{d:`M224,128a96,96,0,1,1-96-96A96,96,0,0,1,224,128Z`,opacity:`0.2`}),s.createElement(`path`,{d:`M144,176a8,8,0,0,1-8,8,16,16,0,0,1-16-16V128a8,8,0,0,1,0-16,16,16,0,0,1,16,16v40A8,8,0,0,1,144,176Zm88-48A104,104,0,1,1,128,24,104.11,104.11,0,0,1,232,128Zm-16,0a88,88,0,1,0-88,88A88.1,88.1,0,0,0,216,128ZM124,96a12,12,0,1,0-12-12A12,12,0,0,0,124,96Z`}))],[`fill`,s.createElement(s.Fragment,null,s.createElement(`path`,{d:`M128,24A104,104,0,1,0,232,128,104.11,104.11,0,0,0,128,24Zm-4,48a12,12,0,1,1-12,12A12,12,0,0,1,124,72Zm12,112a16,16,0,0,1-16-16V128a8,8,0,0,1,0-16,16,16,0,0,1,16,16v40a8,8,0,0,1,0,16Z`}))],[`light`,s.createElement(s.Fragment,null,s.createElement(`path`,{d:`M142,176a6,6,0,0,1-6,6,14,14,0,0,1-14-14V128a2,2,0,0,0-2-2,6,6,0,0,1,0-12,14,14,0,0,1,14,14v40a2,2,0,0,0,2,2A6,6,0,0,1,142,176ZM124,94a10,10,0,1,0-10-10A10,10,0,0,0,124,94Zm106,34A102,102,0,1,1,128,26,102.12,102.12,0,0,1,230,128Zm-12,0a90,90,0,1,0-90,90A90.1,90.1,0,0,0,218,128Z`}))],[`regular`,s.createElement(s.Fragment,null,s.createElement(`path`,{d:`M128,24A104,104,0,1,0,232,128,104.11,104.11,0,0,0,128,24Zm0,192a88,88,0,1,1,88-88A88.1,88.1,0,0,1,128,216Zm16-40a8,8,0,0,1-8,8,16,16,0,0,1-16-16V128a8,8,0,0,1,0-16,16,16,0,0,1,16,16v40A8,8,0,0,1,144,176ZM112,84a12,12,0,1,1,12,12A12,12,0,0,1,112,84Z`}))],[`thin`,s.createElement(s.Fragment,null,s.createElement(`path`,{d:`M140,176a4,4,0,0,1-4,4,12,12,0,0,1-12-12V128a4,4,0,0,0-4-4,4,4,0,0,1,0-8,12,12,0,0,1,12,12v40a4,4,0,0,0,4,4A4,4,0,0,1,140,176ZM124,92a8,8,0,1,0-8-8A8,8,0,0,0,124,92Zm104,36A100,100,0,1,1,128,28,100.11,100.11,0,0,1,228,128Zm-8,0a92,92,0,1,0-92,92A92.1,92.1,0,0,0,220,128Z`}))]]),l=s.forwardRef((e,n)=>s.createElement(t,{ref:n,...e,weights:c}));l.displayName=`InfoIcon`;var u=l,d=n();function f(e={}){return r(`m-0 text-base font-medium text-kumo-default`)}function p(){return r(`inline-flex items-center gap-1`)}function m({children:t,showOptional:n=!1,tooltip:i,className:a,htmlFor:s,asContent:c=!1}){let l=(0,d.jsxs)(d.Fragment,{children:[t,n&&(0,d.jsx)(`span`,{className:`font-normal text-kumo-strong`,children:`(optional)`}),i&&(0,d.jsx)(e,{content:i,asChild:!0,children:(0,d.jsx)(o,{variant:`ghost`,size:`xs`,shape:`square`,"aria-label":`More information`,children:(0,d.jsx)(u,{className:`size-4`})})})]});return c?(0,d.jsx)(`span`,{className:r(p(),a),children:l}):(0,d.jsx)(`label`,{htmlFor:s,className:r(f(),p(),a),children:l})}m.displayName=`Label`;export{m as t};
|
||||
+1
@@ -0,0 +1 @@
|
||||
import{t as e}from"./ResourceError-DwVOufwC.js";var t=e;export{t as errorComponent};
|
||||
+1
@@ -0,0 +1 @@
|
||||
import{st as e}from"./index-BwGGYgiP.js";var t=e;export{t as notFoundComponent};
|
||||
+1
File diff suppressed because one or more lines are too long
+1
@@ -0,0 +1 @@
|
||||
import{t as e}from"./Copy.es--li34FWs.js";import{$ as t,Ct as n,Gn as r,In as i,et as a,wt as o}from"./index-BwGGYgiP.js";var s=r();function c(e={}){return i(`flex w-full flex-col overflow-hidden rounded-lg bg-kumo-elevated text-base ring ring-kumo-line`)}function l({children:e,className:t}){return(0,s.jsx)(`div`,{className:i(c(),t),children:e})}function u({children:e,className:t}){return(0,s.jsx)(`div`,{className:i(`flex items-center gap-2 p-4 text-base font-medium text-kumo-strong -my-2 bg-kumo-elevated`,t),children:e})}function d({children:e,className:t}){return(0,s.jsx)(`div`,{className:i(`relative flex flex-col gap-2 overflow-hidden rounded-lg bg-kumo-base p-4 pr-3 text-inherit no-underline ring ring-kumo-fill`,t),children:e})}var f=Object.assign(l,{Primary:d,Secondary:u});function p({size:e=60,...t}){let n=Math.round(31/57*e);return(0,s.jsxs)(`div`,{...t,children:[(0,s.jsx)(`svg`,{className:`absolute h-0 w-0 overflow-hidden`,"aria-hidden":`true`,children:(0,s.jsxs)(`defs`,{children:[(0,s.jsx)(`path`,{id:`loader-cloud`,d:`M38.052 25.669a.3.3 0 0 1-.06.006h-.013l-37.25-.007a.39.39 0 0 1-.391-.339 9 9 0 0 1-.088-1.234c0-4.619 3.665-8.382 8.234-8.518a6 6 0 0 1-.155-2.096c.277-2.814 2.524-5.079 5.325-5.357a5.96 5.96 0 0 1 4.192 1.166C19.621 4.034 24.575.25 30.406.25c5.817 0 10.765 3.769 12.541 9.012q.003-.004.004-.002c.024.071.055.173.091.293q.1.32.184.645c.152.545.299 1.098.299 1.098l1.649-.004h.263c1.067 0 1.998.152 2.809.436a11.08 11.08 0 0 1 7.957 10.639c0 1.044-.142 2.048-.412 3.004a.42.42 0 0 1-.398.298z`}),(0,s.jsx)(`path`,{id:`loader-cutout`,d:`M45.328 7.581a70 70 0 0 1-1.038 3.978l-.797 2.754c-.344 1.18-.216 2.278.358 3.079.526.739 1.404 1.173 2.47 1.227l4.3.258a.38.38 0 0 1 .303.169.41.41 0 0 1 .048.367.54.54 0 0 1-.466.359l-4.468.258c-2.423.115-5.042 2.082-5.96 4.483l-.324.847c-.025.063-1.291 3.404-1.546 4.348l-.014.054a.455.455 0 0 1-.866-.27l.005-.018c.261-.828 1.06-4.058 1.084-4.142l.284-.997c.344-1.18.216-2.279-.358-3.079-.526-.739-1.404-1.173-2.47-1.227l-20.181-.258a.4.4 0 0 1-.317-.17.4.4 0 0 1-.04-.366.54.54 0 0 1 .465-.359l20.363-.258c2.416-.108 5.028-2.082 5.946-4.483l1.161-3.052c.404-1.345 1.021-3.042 1.176-3.716a.454.454 0 0 1 .882.214`})]})}),(0,s.jsx)(`div`,{className:`relative`,style:{width:e,height:n},children:(0,s.jsx)(`div`,{className:`absolute inset-0 origin-center animate-[animated-logo-container_1s_ease-out_forwards] overflow-visible motion-reduce:scale-100 motion-reduce:animate-none motion-reduce:opacity-100`,"aria-hidden":`true`,children:(0,s.jsxs)(`svg`,{viewBox:`0 0 57 31`,children:[(0,s.jsx)(`defs`,{children:(0,s.jsxs)(`mask`,{id:`animated-logo-mask`,children:[(0,s.jsx)(`rect`,{width:`100%`,height:`100%`,fill:`white`}),(0,s.jsx)(`use`,{href:`#loader-cutout`,className:`origin-[41.061px_19.219px] animate-[animated-logo-cutout_1s_ease-out_forwards] fill-black transform-view motion-reduce:scale-100 motion-reduce:animate-none`})]})}),(0,s.jsx)(`use`,{href:`#loader-cloud`,className:`animate-[animated-logo-cloud_1s_ease-out_forwards] fill-[#f38020] stroke-[#f38020] stroke-[0.5] [fill-opacity:0] [stroke-dasharray:145] [stroke-dashoffset:145] motion-reduce:animate-none motion-reduce:[fill-opacity:1] motion-reduce:[stroke-dashoffset:0]`,mask:`url(#animated-logo-mask)`})]})})})]})}function m(){let{prompt:r}=t.useLoaderData(),i=n();async function c(){try{await a(r),i.add({title:`Copied to clipboard`,variant:`success`})}catch{i.add({title:`Failed to copy to clipboard`,description:`Something went wrong when trying to copy the prompt.`,variant:`default`})}}return(0,s.jsx)(`div`,{className:`flex h-full flex-col items-center justify-center space-y-2 p-12 text-center`,children:(0,s.jsxs)(`div`,{className:`mx-auto max-w-sm space-y-6`,children:[(0,s.jsxs)(`div`,{className:`flex flex-col items-center gap-2`,children:[(0,s.jsx)(p,{size:96}),(0,s.jsx)(`h2`,{className:`text-3xl font-bold text-kumo-default`,children:`Welcome to Local Explorer`}),(0,s.jsx)(`p`,{className:`text-sm font-light text-kumo-subtle`,children:`Select a resource from the sidebar to view & manage it.`})]}),(0,s.jsxs)(f,{children:[(0,s.jsxs)(f.Secondary,{className:`flex items-center justify-between`,children:[(0,s.jsx)(`h4`,{children:`Copy prompt for agent`}),(0,s.jsx)(o,{icon:e,onClick:()=>{c()},size:`sm`,variant:`ghost`})]}),(0,s.jsx)(f.Primary,{className:`max-h-16 overflow-auto p-3 text-left`,children:(0,s.jsx)(`p`,{className:`font-mono text-kumo-inactive`,children:r})})]})]})})}export{m as component};
|
||||
Generated
Vendored
+1
@@ -0,0 +1 @@
|
||||
import{t as e}from"./checkbox-kt1uojk2f9e0d0h1-CLGaD9_Q.js";import{Gn as t,In as n,Wn as r,qn as i}from"./index-BwGGYgiP.js";var a=t(),o=i(r(),1),s={layout:{auto:{classes:``,description:`Auto table layout - columns resize based on content`},fixed:{classes:`table-fixed`,description:`Fixed table layout - columns have equal width, controlled via colgroup`}},variant:{default:{classes:``,description:`Default row variant`},selected:{classes:`bg-kumo-tint`,description:`Selected row variant`}},sticky:{left:{classes:`sticky left-0`,description:`Pin column to the left edge of the scroll container`},right:{classes:`sticky right-0`,description:`Pin column to the right edge of the scroll container`}}},c=(e,t)=>{let r=s.sticky[e].classes;return n(r,t===`head`?`z-2`:`z-1`,`bg-kumo-base`,e===`right`?`before:pointer-events-none before:absolute before:inset-y-0 before:-left-6 before:w-6 before:bg-gradient-to-r before:from-transparent before:to-kumo-base`:`before:pointer-events-none before:absolute before:inset-y-0 before:-right-6 before:w-6 before:bg-gradient-to-l before:from-transparent before:to-kumo-base`)},l={layout:`auto`,variant:`default`},u=(0,o.forwardRef)(({layout:e=`auto`,...t},r)=>{let i=n(`isolate w-full`,s.layout[e].classes,`[&_td]:border-b [&_td]:border-kumo-fill [&_tr:last-child_td]:border-b-0`,`[&_td]:p-3`,`[&_th]:border-b [&_th]:border-kumo-fill [&_th]:p-3 [&_th]:font-semibold [&_th]:text-base`,`[&_th]:bg-kumo-base`,`text-left text-kumo-default`,t.className);return(0,a.jsx)(`table`,{ref:r,...t,className:i})}),d=(0,o.forwardRef)(({variant:e=`default`,sticky:t,...r},i)=>{let o=n(e===`compact`&&`[&_th]:bg-kumo-elevated [&_th]:py-2 text-xs text-kumo-strong`,t&&`[&_th]:sticky [&_th]:top-0 [&_th]:z-1`,r.className);return(0,a.jsx)(`thead`,{ref:i,...r,className:o})}),f=(0,o.forwardRef)(({sticky:e,...t},r)=>{let i=n(`group relative`,e&&c(e,`head`),t.className);return(0,a.jsx)(`th`,{ref:r,...t,className:i})}),p=(0,o.forwardRef)(({variant:e=l.variant,...t},r)=>{let i=n(s.variant[e].classes,t.className);return(0,a.jsx)(`tr`,{ref:r,...t,className:i})}),m=(0,o.forwardRef)((e,t)=>(0,a.jsx)(`tbody`,{ref:t,...e})),h=(0,o.forwardRef)(({sticky:e,...t},r)=>{let i=n(e&&c(e,`cell`),t.className);return(0,a.jsx)(`td`,{ref:r,...t,className:i})}),g=(0,o.forwardRef)((e,t)=>(0,a.jsx)(`tfoot`,{ref:t,...e})),_=(0,o.forwardRef)((e,t)=>(0,a.jsx)(`button`,{ref:t,...e,type:`button`,"aria-label":`Resize column`,className:n(`invisible h-full group-hover:visible`,`w-[10px]`,`flex items-center justify-center`,`cursor-col-resize touch-none select-none`,`absolute top-0 right-0`,`m-0 bg-kumo-base p-0`),children:(0,a.jsx)(`span`,{className:`h-5 w-[2px] rounded bg-kumo-hairline`})})),v=(0,o.forwardRef)(({checked:t,indeterminate:r,onValueChange:i,label:o,disabled:s,...c},l)=>(0,a.jsx)(h,{ref:l,...c,className:n(`w-10 leading-none`,c.className),children:(0,a.jsx)(e,{checked:t,indeterminate:r,onCheckedChange:e=>{i?.(e)},"aria-label":o??`Select row`,disabled:s,className:`relative before:absolute before:-inset-3 before:content-['']`})})),y=(0,o.forwardRef)(({checked:t,indeterminate:r,onValueChange:i,label:o,disabled:s,...c},l)=>(0,a.jsx)(f,{ref:l,...c,className:n(`w-10 leading-none`,c.className),children:(0,a.jsx)(e,{checked:t,indeterminate:r,onCheckedChange:e=>{i?.(e)},"aria-label":o??`Select all rows`,disabled:s,className:`relative before:absolute before:-inset-3 before:content-['']`})}));u.displayName=`Table`,m.displayName=`Table.Body`,f.displayName=`Table.Head`,p.displayName=`Table.Row`,h.displayName=`Table.Cell`,g.displayName=`Table.Footer`,d.displayName=`Table.Header`,_.displayName=`Table.ResizeHandle`,v.displayName=`Table.CheckCell`,y.displayName=`Table.CheckHead`;var b=Object.assign(u,{Header:d,Head:f,Row:p,Body:m,Cell:h,CheckCell:v,CheckHead:y,Footer:g,ResizeHandle:_});export{b as t};
|
||||
Generated
Vendored
+1
@@ -0,0 +1 @@
|
||||
import{Gn as e,In as t,Wn as n,qn as r}from"./index-BwGGYgiP.js";var i=e(),a=r(n(),1),o={variant:{heading1:{classes:`text-3xl font-semibold`,description:`Large heading for page titles`},heading2:{classes:`text-2xl font-semibold`,description:`Medium heading for section titles`},heading3:{classes:`text-lg font-semibold`,description:`Small heading for subsections`},body:{classes:`text-kumo-default`,description:`Default body text`},secondary:{classes:`text-kumo-subtle`,description:`Muted text for secondary information`},success:{classes:`text-kumo-link`,description:`Success state text`},error:{classes:`text-kumo-danger`,description:`Error state text`},mono:{classes:`font-mono`,description:`Monospace text for code`},"mono-secondary":{classes:`font-mono text-kumo-subtle`,description:`Muted monospace text`}},size:{xs:{classes:`text-xs`,description:`Extra small text`},sm:{classes:`text-sm`,description:`Small text`},base:{classes:`text-base`,description:`Default text size`},lg:{classes:`text-lg`,description:`Large text`}}};function s({variant:e=`body`,bold:n=!1,size:r=`base`,truncate:s=!1,children:c,DANGEROUS_className:l,DANGEROUS_style:u,as:d,...f},p){let m=[`body`,`secondary`,`success`,`error`].includes(e),h=[`mono`,`mono-secondary`].includes(e);return(0,i.jsx)((0,a.useMemo)(()=>d||(e===`heading1`?`h1`:e===`heading2`?`h2`:e===`heading3`?`h3`:[`mono`,`mono-secondary`].includes(e)?`span`:`p`),[e,d]),{ref:p,className:t(`text-kumo-default`,o.variant[e].classes,m?o.size[r].classes:``,m&&n?`font-medium`:``,h&&(r===`lg`?o.size.base.classes:o.size.sm.classes),s&&`truncate min-w-0`,l),style:u,...f,children:c})}var c=(0,a.forwardRef)(s);export{c as t};
|
||||
+1
File diff suppressed because one or more lines are too long
+3
@@ -0,0 +1,3 @@
|
||||
<svg width="32" height="32" viewBox="0 0 66 30" stroke="#f6821f" stroke-width="3" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M52.688 13.028c-.22 0-.437.008-.654.015a.3.3 0 0 0-.102.024.37.37 0 0 0-.236.255l-.93 3.249c-.401 1.397-.252 2.687.422 3.634.618.876 1.646 1.39 2.894 1.45l5.045.306a.45.45 0 0 1 .435.41.5.5 0 0 1-.025.223.64.64 0 0 1-.547.426l-5.242.306c-2.848.132-5.912 2.456-6.987 5.29l-.378 1a.28.28 0 0 0 .248.382h18.054a.48.48 0 0 0 .464-.35c.32-1.153.482-2.344.48-3.54 0-7.22-5.79-13.072-12.933-13.072M44.807 29.578l.334-1.175c.402-1.397.253-2.687-.42-3.634-.62-.876-1.647-1.39-2.896-1.45l-23.665-.306a.47.47 0 0 1-.374-.199.5.5 0 0 1-.052-.434.64.64 0 0 1 .552-.426l23.886-.306c2.836-.131 5.9-2.456 6.975-5.29l1.362-3.6a.9.9 0 0 0 .04-.477C48.997 5.259 42.789 0 35.367 0c-6.842 0-12.647 4.462-14.73 10.665a6.92 6.92 0 0 0-4.911-1.374c-3.28.33-5.92 3.002-6.246 6.318a7.2 7.2 0 0 0 .18 2.472C4.3 18.241 0 22.679 0 28.133q0 .74.106 1.453a.46.46 0 0 0 .457.402h43.704a.57.57 0 0 0 .54-.418" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.0 KiB |
+14
@@ -0,0 +1,14 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<link rel="icon" type="image/svg+xml" href="/cdn-cgi/explorer/favicon.svg" />
|
||||
<title>Cloudflare Local Explorer</title>
|
||||
<script type="module" crossorigin src="/cdn-cgi/explorer/assets/index-BwGGYgiP.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/cdn-cgi/explorer/assets/index-CjrDtYhu.css">
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
</body>
|
||||
</html>
|
||||
+9465
File diff suppressed because it is too large
Load Diff
+92563
File diff suppressed because one or more lines are too long
+1
File diff suppressed because one or more lines are too long
Generated
Vendored
+16
@@ -0,0 +1,16 @@
|
||||
// src/workers/analytics-engine/analytics-engine.worker.ts
|
||||
var LocalAnalyticsEngineDataset = class {
|
||||
constructor(env) {
|
||||
this.env = env;
|
||||
}
|
||||
env;
|
||||
writeDataPoint(_event) {
|
||||
}
|
||||
};
|
||||
function analytics_engine_worker_default(env) {
|
||||
return new LocalAnalyticsEngineDataset(env);
|
||||
}
|
||||
export {
|
||||
analytics_engine_worker_default as default
|
||||
};
|
||||
//# sourceMappingURL=analytics-engine.worker.js.map
|
||||
Generated
Vendored
+7
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"version": 3,
|
||||
"sources": ["../../../../src/workers/analytics-engine/analytics-engine.worker.ts"],
|
||||
"sourcesContent": ["interface Env {\n\tdataset: string;\n}\nclass LocalAnalyticsEngineDataset implements AnalyticsEngineDataset {\n\tconstructor(private env: Env) {}\n\twriteDataPoint(_event?: AnalyticsEngineDataPoint): void {\n\t\t// no op in dev\n\t}\n}\n\nexport default function (env: Env) {\n\treturn new LocalAnalyticsEngineDataset(env);\n}\n"],
|
||||
"mappings": ";AAGA,IAAM,8BAAN,MAAoE;AAAA,EACnE,YAAoB,KAAU;AAAV;AAAA,EAAW;AAAA,EAAX;AAAA,EACpB,eAAe,QAAyC;AAAA,EAExD;AACD;AAEe,SAAR,gCAAkB,KAAU;AAClC,SAAO,IAAI,4BAA4B,GAAG;AAC3C;",
|
||||
"names": []
|
||||
}
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
// src/workers/assets/assets-kv.worker.ts
|
||||
import { SharedBindings } from "miniflare:shared";
|
||||
var assets_kv_worker_default = {
|
||||
async fetch(request, env) {
|
||||
if (request.method !== "GET") {
|
||||
let message = `Cannot ${request.method.toLowerCase()}() with Workers Assets namespace`;
|
||||
return new Response(message, { status: 405, statusText: message });
|
||||
}
|
||||
let pathHash = new URL(request.url).pathname.substring(1), entry = env.ASSETS_REVERSE_MAP[pathHash];
|
||||
if (entry === void 0)
|
||||
return new Response("Not Found", { status: 404 });
|
||||
let { filePath, contentType } = entry, response = await env[SharedBindings.MAYBE_SERVICE_BLOBS].fetch(
|
||||
new URL(
|
||||
// somewhere in blobservice I think this is being decoded again
|
||||
filePath.split("/").map((x) => encodeURIComponent(x)).join("/"),
|
||||
"http://placeholder"
|
||||
)
|
||||
), newResponse = new Response(response.body, response);
|
||||
return contentType !== null && newResponse.headers.append(
|
||||
"cf-kv-metadata",
|
||||
`{"contentType": "${contentType}"}`
|
||||
), newResponse;
|
||||
}
|
||||
};
|
||||
export {
|
||||
assets_kv_worker_default as default
|
||||
};
|
||||
//# sourceMappingURL=assets-kv.worker.js.map
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"version": 3,
|
||||
"sources": ["../../../../src/workers/assets/assets-kv.worker.ts"],
|
||||
"sourcesContent": ["import { SharedBindings } from \"miniflare:shared\";\n\ninterface Env {\n\t[SharedBindings.MAYBE_SERVICE_BLOBS]: Fetcher;\n\tASSETS_REVERSE_MAP: AssetReverseMap;\n}\n\ntype AssetReverseMap = {\n\t[pathHash: string]: { filePath: string; contentType: string };\n}; //map to actual filepath\n\nexport default <ExportedHandler<Env>>{\n\tasync fetch(request, env) {\n\t\t// Only permit reads\n\t\tif (request.method !== \"GET\") {\n\t\t\tconst message = `Cannot ${request.method.toLowerCase()}() with Workers Assets namespace`;\n\t\t\treturn new Response(message, { status: 405, statusText: message });\n\t\t}\n\n\t\tconst pathHash = new URL(request.url).pathname.substring(1);\n\t\tconst entry = env.ASSETS_REVERSE_MAP[pathHash];\n\t\tif (entry === undefined) {\n\t\t\treturn new Response(\"Not Found\", { status: 404 });\n\t\t}\n\n\t\tconst { filePath, contentType } = entry;\n\t\tconst blobsService = env[SharedBindings.MAYBE_SERVICE_BLOBS];\n\t\tconst response = await blobsService.fetch(\n\t\t\tnew URL(\n\t\t\t\t// somewhere in blobservice I think this is being decoded again\n\t\t\t\tfilePath\n\t\t\t\t\t.split(\"/\")\n\t\t\t\t\t.map((x) => encodeURIComponent(x))\n\t\t\t\t\t.join(\"/\"),\n\t\t\t\t\"http://placeholder\"\n\t\t\t)\n\t\t);\n\t\tconst newResponse = new Response(response.body, response);\n\t\t// ensure the runtime will return the metadata we need\n\t\tif (contentType !== null) {\n\t\t\tnewResponse.headers.append(\n\t\t\t\t\"cf-kv-metadata\",\n\t\t\t\t`{\"contentType\": \"${contentType}\"}`\n\t\t\t);\n\t\t}\n\t\treturn newResponse;\n\t},\n};\n"],
|
||||
"mappings": ";AAAA,SAAS,sBAAsB;AAW/B,IAAO,2BAA8B;AAAA,EACpC,MAAM,MAAM,SAAS,KAAK;AAEzB,QAAI,QAAQ,WAAW,OAAO;AAC7B,UAAM,UAAU,UAAU,QAAQ,OAAO,YAAY,CAAC;AACtD,aAAO,IAAI,SAAS,SAAS,EAAE,QAAQ,KAAK,YAAY,QAAQ,CAAC;AAAA,IAClE;AAEA,QAAM,WAAW,IAAI,IAAI,QAAQ,GAAG,EAAE,SAAS,UAAU,CAAC,GACpD,QAAQ,IAAI,mBAAmB,QAAQ;AAC7C,QAAI,UAAU;AACb,aAAO,IAAI,SAAS,aAAa,EAAE,QAAQ,IAAI,CAAC;AAGjD,QAAM,EAAE,UAAU,YAAY,IAAI,OAE5B,WAAW,MADI,IAAI,eAAe,mBAAmB,EACvB;AAAA,MACnC,IAAI;AAAA;AAAA,QAEH,SACE,MAAM,GAAG,EACT,IAAI,CAAC,MAAM,mBAAmB,CAAC,CAAC,EAChC,KAAK,GAAG;AAAA,QACV;AAAA,MACD;AAAA,IACD,GACM,cAAc,IAAI,SAAS,SAAS,MAAM,QAAQ;AAExD,WAAI,gBAAgB,QACnB,YAAY,QAAQ;AAAA,MACnB;AAAA,MACA,oBAAoB,WAAW;AAAA,IAChC,GAEM;AAAA,EACR;AACD;",
|
||||
"names": []
|
||||
}
|
||||
+9153
File diff suppressed because it is too large
Load Diff
+7
File diff suppressed because one or more lines are too long
+9669
File diff suppressed because it is too large
Load Diff
+7
File diff suppressed because one or more lines are too long
+56
@@ -0,0 +1,56 @@
|
||||
// src/workers/assets/rpc-proxy.worker.ts
|
||||
import { WorkerEntrypoint } from "cloudflare:workers";
|
||||
|
||||
// src/workers/core/dev-registry-proxy-shared.worker.ts
|
||||
import { DurableObject } from "cloudflare:workers";
|
||||
var SERIALIZED_DATE = "___serialized_date___", SERIALIZED_BIGINT = "___serialized_bigint___";
|
||||
function tailEventsReplacer(_, value) {
|
||||
return value instanceof Date ? { [SERIALIZED_DATE]: value.toISOString() } : typeof value == "bigint" ? { [SERIALIZED_BIGINT]: value.toString() } : value;
|
||||
}
|
||||
function tailEventsReviver(_, value) {
|
||||
if (value && typeof value == "object") {
|
||||
if (SERIALIZED_DATE in value)
|
||||
return new Date(value[SERIALIZED_DATE]);
|
||||
if (SERIALIZED_BIGINT in value)
|
||||
return BigInt(value[SERIALIZED_BIGINT]);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
// src/workers/assets/rpc-proxy.worker.ts
|
||||
var RPCProxyWorker = class extends WorkerEntrypoint {
|
||||
async fetch(request) {
|
||||
return this.env.ROUTER_WORKER.fetch(request);
|
||||
}
|
||||
// Forward scheduled events to the User Worker. The proxy itself doesn't run
|
||||
// any scheduled logic; it just dispatches a real scheduled event to the user
|
||||
// worker via the Fetcher built-in, then propagates the user worker's noRetry
|
||||
// decision back onto this controller so the outcome surfaces correctly to
|
||||
// the caller (e.g. the entry worker's `/cdn-cgi/handler/scheduled` handler).
|
||||
async scheduled(controller) {
|
||||
let result = await this.env.USER_WORKER.scheduled?.({
|
||||
cron: controller.cron,
|
||||
scheduledTime: new Date(controller.scheduledTime)
|
||||
});
|
||||
if (result?.noRetry && controller.noRetry(), result?.outcome !== "ok")
|
||||
throw new Error(
|
||||
`User Worker scheduled handler failed with outcome: ${result?.outcome}`
|
||||
);
|
||||
}
|
||||
tail(events) {
|
||||
return this.env.USER_WORKER.tail(
|
||||
JSON.parse(JSON.stringify(events, tailEventsReplacer), tailEventsReviver)
|
||||
);
|
||||
}
|
||||
constructor(ctx, env) {
|
||||
return super(ctx, env), new Proxy(this, {
|
||||
get(target, prop) {
|
||||
return Reflect.has(target, prop) ? Reflect.get(target, prop) : Reflect.get(target.env.USER_WORKER, prop);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
export {
|
||||
RPCProxyWorker as default
|
||||
};
|
||||
//# sourceMappingURL=rpc-proxy.worker.js.map
|
||||
+7
File diff suppressed because one or more lines are too long
+417
@@ -0,0 +1,417 @@
|
||||
var __defProp = Object.defineProperty;
|
||||
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
||||
var __decorateClass = (decorators, target, key, kind) => {
|
||||
for (var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target, i = decorators.length - 1, decorator; i >= 0; i--)
|
||||
(decorator = decorators[i]) && (result = (kind ? decorator(target, key, result) : decorator(result)) || result);
|
||||
return kind && result && __defProp(target, key, result), result;
|
||||
};
|
||||
|
||||
// src/workers/browser-rendering/binding.worker.ts
|
||||
import assert from "node:assert";
|
||||
import {
|
||||
DELETE,
|
||||
GET,
|
||||
HttpError,
|
||||
MiniflareDurableObject,
|
||||
POST,
|
||||
PUT,
|
||||
Router,
|
||||
SharedBindings
|
||||
} from "miniflare:shared";
|
||||
function isClosed(ws) {
|
||||
return !ws || ws.readyState === WebSocket.CLOSED;
|
||||
}
|
||||
function chromeBaseUrl(wsEndpoint) {
|
||||
return `http://${new URL(wsEndpoint.replace("ws://", "http://")).host}`;
|
||||
}
|
||||
var RETRYABLE_FETCH_ERROR_SUBSTRINGS = [
|
||||
// kj/async-io-win32.c++ ConnectEx (#1225) — the remote socket refused us.
|
||||
// Surfaces on Windows when Chrome announced the DevTools URL but isn't
|
||||
// quite accepting connections yet.
|
||||
"connection refused",
|
||||
"remote computer refused",
|
||||
// kj/async-io-win32.c++ WSARecv (#64) — the connection went away mid-read.
|
||||
"network name is no longer available",
|
||||
// Generic workerd disconnect classifications.
|
||||
"network connection lost",
|
||||
"disconnected"
|
||||
];
|
||||
function isRetryableFetchError(error) {
|
||||
let message = error?.message;
|
||||
if (typeof message != "string")
|
||||
return !1;
|
||||
let lower = message.toLowerCase();
|
||||
return RETRYABLE_FETCH_ERROR_SUBSTRINGS.some(
|
||||
(needle) => lower.includes(needle)
|
||||
);
|
||||
}
|
||||
var MAX_BODY_PREVIEW = 2e3;
|
||||
function truncateBody(text) {
|
||||
return text.length <= MAX_BODY_PREVIEW ? text : `${text.slice(0, MAX_BODY_PREVIEW)}... (truncated, ${text.length} bytes total)`;
|
||||
}
|
||||
async function parseJsonResponse(resp, context) {
|
||||
let text = await resp.text();
|
||||
if (!resp.ok)
|
||||
throw new Error(
|
||||
`${context}: upstream returned ${resp.status} ${resp.statusText}
|
||||
${truncateBody(text)}`
|
||||
);
|
||||
try {
|
||||
return JSON.parse(text);
|
||||
} catch (cause) {
|
||||
throw new Error(
|
||||
`${context}: expected JSON, got non-JSON response (${resp.status} ${resp.statusText})
|
||||
${truncateBody(text)}`,
|
||||
{ cause }
|
||||
);
|
||||
}
|
||||
}
|
||||
async function fetchWithConnectRetry(url, init, {
|
||||
maxAttempts = 5,
|
||||
baseDelayMs = 25,
|
||||
maxDelayMs = 250
|
||||
} = {}) {
|
||||
let lastError;
|
||||
for (let attempt = 0; attempt < maxAttempts; attempt++)
|
||||
try {
|
||||
return await fetch(url, init);
|
||||
} catch (e) {
|
||||
if (lastError = e, !isRetryableFetchError(e) || attempt === maxAttempts - 1)
|
||||
break;
|
||||
let delay = Math.min(maxDelayMs, baseDelayMs * 2 ** attempt);
|
||||
await new Promise((resolve) => setTimeout(resolve, delay));
|
||||
}
|
||||
throw lastError;
|
||||
}
|
||||
function forwardClose(target, e) {
|
||||
!target || target.readyState === WebSocket.CLOSED || (!e?.code || e?.code === 1005 || e?.code === 1006 ? target.close() : target.close(e.code, e.reason));
|
||||
}
|
||||
var BrowserSession = class extends MiniflareDurableObject {
|
||||
sessionInfo;
|
||||
chromeWs;
|
||||
legacyServerWs;
|
||||
wss = [];
|
||||
#statusTimeout;
|
||||
setSessionInfoRoute = async (req) => {
|
||||
this.sessionInfo = await req.json();
|
||||
let wsUrl = this.sessionInfo.wsEndpoint.replace("ws://", "http://"), resp = await fetchWithConnectRetry(wsUrl, {
|
||||
headers: { Upgrade: "websocket" }
|
||||
});
|
||||
return assert(resp.webSocket !== null, "Expected a WebSocket response"), this.chromeWs = resp.webSocket, this.chromeWs.accept(), this.chromeWs.addEventListener("message", (m) => {
|
||||
if (!this.legacyServerWs)
|
||||
return;
|
||||
let string = new TextEncoder().encode(m.data), data = new Uint8Array(string.length + 4);
|
||||
new DataView(data.buffer).setUint32(0, string.length, !0), data.set(string, 4), this.legacyServerWs.send(data);
|
||||
}), this.chromeWs.addEventListener("close", (e) => {
|
||||
this.closeSession(e);
|
||||
}), this.#scheduleStatusCheck(), new Response(null, { status: 204 });
|
||||
};
|
||||
getSessionInfoRoute = async () => (isClosed(this.chromeWs) && this.closeSession(), this.sessionInfo ? Response.json(this.sessionInfo) : new Response(null, { status: 204 }));
|
||||
connectDevtools = async () => {
|
||||
if (assert(
|
||||
this.sessionInfo !== void 0,
|
||||
"sessionInfo must be set before connecting"
|
||||
), assert(
|
||||
this.chromeWs !== void 0,
|
||||
"chromeWs must be established before connecting"
|
||||
), this.legacyServerWs !== void 0)
|
||||
throw new HttpError(409, "WebSocket already initialized");
|
||||
let webSocketPair = new WebSocketPair(), [client, server] = Object.values(webSocketPair);
|
||||
return server.accept(), server.addEventListener("message", (m) => {
|
||||
m.data !== "ping" && this.chromeWs?.send(
|
||||
new TextDecoder().decode(m.data.slice(4))
|
||||
);
|
||||
}), server.addEventListener("close", (e) => {
|
||||
this.closeWebSockets(e);
|
||||
}), this.legacyServerWs = server, this.sessionInfo.connectionId = crypto.randomUUID(), this.sessionInfo.connectionStartTime = Date.now(), new Response(null, {
|
||||
status: 101,
|
||||
webSocket: client,
|
||||
headers: { "cf-browser-session-id": this.name }
|
||||
});
|
||||
};
|
||||
jsonVersion = async () => this.#proxyJsonRequest("/json/version");
|
||||
jsonList = async () => this.#proxyJsonRequest("/json/list");
|
||||
jsonAlias = async () => this.#proxyJsonRequest("/json/list");
|
||||
jsonProtocol = async () => this.#proxyJsonRequest("/json/protocol");
|
||||
jsonNew = async (_req, _params, url) => this.#proxyJsonRequest(
|
||||
`/json/new?${new URLSearchParams({ url: url.searchParams.get("url") ?? "" })}`,
|
||||
"PUT"
|
||||
);
|
||||
jsonActivate = async (_req, params) => this.#proxyJsonRequest(`/json/activate/${params?.targetId}`);
|
||||
jsonClose = async (_req, params) => this.#proxyJsonRequest(`/json/close/${params?.targetId}`);
|
||||
pageWebSocket = async (_req, params) => this.sessionInfo ? this.#proxyRawWebSocket(
|
||||
`${chromeBaseUrl(this.sessionInfo.wsEndpoint).replace("http://", "ws://")}/devtools/page/${params?.pageId}`
|
||||
) : Response.json({ error: "Browser not found" }, { status: 404 });
|
||||
closeBrowser = async () => {
|
||||
if (this.sessionInfo) {
|
||||
let closeUrl = new URL("http://localhost/browser/close");
|
||||
closeUrl.searchParams.set("sessionId", this.sessionInfo.sessionId), this.env[SharedBindings.MAYBE_SERVICE_LOOPBACK].fetch(closeUrl, {
|
||||
method: "POST"
|
||||
});
|
||||
}
|
||||
return Response.json({ status: "closed" });
|
||||
};
|
||||
sessionDetail = async () => this.sessionInfo ? Response.json({
|
||||
sessionId: this.sessionInfo.sessionId,
|
||||
startTime: this.sessionInfo.startTime,
|
||||
connectionId: this.sessionInfo.connectionId,
|
||||
connectionStartTime: this.sessionInfo.connectionStartTime
|
||||
}) : Response.json({ error: "Session not found" }, { status: 404 });
|
||||
connect = async (_req) => {
|
||||
assert(
|
||||
this.sessionInfo !== void 0,
|
||||
"sessionInfo must be set before connecting"
|
||||
);
|
||||
let wsUrl = this.sessionInfo.wsEndpoint.replace("ws://", "http://"), resp = await this.#proxyRawWebSocket(wsUrl);
|
||||
return this.sessionInfo.connectionId = crypto.randomUUID(), this.sessionInfo.connectionStartTime = Date.now(), new Response(null, {
|
||||
status: resp.status,
|
||||
webSocket: resp.webSocket,
|
||||
headers: { "cf-browser-session-id": this.name }
|
||||
});
|
||||
};
|
||||
closeWebSockets(e) {
|
||||
forwardClose(this.legacyServerWs, e);
|
||||
for (let { chrome, server } of this.wss)
|
||||
forwardClose(chrome, e), forwardClose(server, e);
|
||||
this.legacyServerWs = void 0, this.wss = [], this.sessionInfo && (this.sessionInfo.connectionId = void 0, this.sessionInfo.connectionStartTime = void 0);
|
||||
}
|
||||
closeSession(e) {
|
||||
this.#statusTimeout !== void 0 && (this.timers.clearTimeout(this.#statusTimeout), this.#statusTimeout = void 0), this.closeWebSockets(e), forwardClose(this.chromeWs, e), this.chromeWs = void 0, this.sessionInfo = void 0;
|
||||
}
|
||||
async #proxyRawWebSocket(targetWsUrl) {
|
||||
let response = await fetchWithConnectRetry(
|
||||
targetWsUrl.replace("ws://", "http://"),
|
||||
{
|
||||
headers: { Upgrade: "websocket" }
|
||||
}
|
||||
);
|
||||
assert(response.webSocket !== null, "Expected a WebSocket response");
|
||||
let chrome = response.webSocket;
|
||||
chrome.accept();
|
||||
let webSocketPair = new WebSocketPair(), [client, server] = Object.values(webSocketPair);
|
||||
server.accept();
|
||||
let pair = { chrome, server };
|
||||
return this.wss.push(pair), chrome.addEventListener("message", (m) => server.send(m.data)), server.addEventListener("message", (m) => chrome.send(m.data)), server.addEventListener("close", (e) => {
|
||||
forwardClose(chrome, e), forwardClose(server, e), this.wss = this.wss.filter((p) => p !== pair);
|
||||
}), chrome.addEventListener("close", (e) => {
|
||||
forwardClose(server, e), forwardClose(chrome, e), this.wss = this.wss.filter((p) => p !== pair);
|
||||
}), new Response(null, { status: 101, webSocket: client });
|
||||
}
|
||||
async #proxyJsonRequest(chromePath, method = "GET") {
|
||||
if (!this.sessionInfo)
|
||||
return Response.json({ error: "Browser not found" }, { status: 404 });
|
||||
let resp = await fetchWithConnectRetry(
|
||||
`${chromeBaseUrl(this.sessionInfo.wsEndpoint)}${chromePath}`,
|
||||
{ method }
|
||||
);
|
||||
return new Response(await resp.text(), {
|
||||
status: resp.status,
|
||||
headers: { "Content-Type": "application/json" }
|
||||
});
|
||||
}
|
||||
async #checkStatus() {
|
||||
if (this.sessionInfo) {
|
||||
let url = new URL("http://localhost/browser/status");
|
||||
url.searchParams.set("sessionId", this.sessionInfo.sessionId), (await this.env[SharedBindings.MAYBE_SERVICE_LOOPBACK].fetch(url)).ok || this.closeSession();
|
||||
}
|
||||
}
|
||||
#scheduleStatusCheck() {
|
||||
this.#statusTimeout === void 0 && (this.#statusTimeout = this.timers.setTimeout(async () => {
|
||||
this.#statusTimeout = void 0, await this.#checkStatus(), this.chromeWs && this.#scheduleStatusCheck();
|
||||
}, 1e3));
|
||||
}
|
||||
};
|
||||
__decorateClass([
|
||||
POST("/session-info")
|
||||
], BrowserSession.prototype, "setSessionInfoRoute", 2), __decorateClass([
|
||||
GET("/session-info")
|
||||
], BrowserSession.prototype, "getSessionInfoRoute", 2), __decorateClass([
|
||||
GET("/v1/connectDevtools")
|
||||
], BrowserSession.prototype, "connectDevtools", 2), __decorateClass([
|
||||
GET("/v1/devtools/browser/:sessionId/json/version")
|
||||
], BrowserSession.prototype, "jsonVersion", 2), __decorateClass([
|
||||
GET("/v1/devtools/browser/:sessionId/json/list")
|
||||
], BrowserSession.prototype, "jsonList", 2), __decorateClass([
|
||||
GET("/v1/devtools/browser/:sessionId/json")
|
||||
], BrowserSession.prototype, "jsonAlias", 2), __decorateClass([
|
||||
GET("/v1/devtools/browser/:sessionId/json/protocol")
|
||||
], BrowserSession.prototype, "jsonProtocol", 2), __decorateClass([
|
||||
PUT("/v1/devtools/browser/:sessionId/json/new")
|
||||
], BrowserSession.prototype, "jsonNew", 2), __decorateClass([
|
||||
GET("/v1/devtools/browser/:sessionId/json/activate/:targetId")
|
||||
], BrowserSession.prototype, "jsonActivate", 2), __decorateClass([
|
||||
GET("/v1/devtools/browser/:sessionId/json/close/:targetId")
|
||||
], BrowserSession.prototype, "jsonClose", 2), __decorateClass([
|
||||
GET("/v1/devtools/browser/:sessionId/page/:pageId")
|
||||
], BrowserSession.prototype, "pageWebSocket", 2), __decorateClass([
|
||||
DELETE("/v1/devtools/browser/:sessionId")
|
||||
], BrowserSession.prototype, "closeBrowser", 2), __decorateClass([
|
||||
GET("/v1/devtools/session/:sessionId")
|
||||
], BrowserSession.prototype, "sessionDetail", 2), __decorateClass([
|
||||
GET("/v1/devtools/browser/:sessionId")
|
||||
], BrowserSession.prototype, "connect", 2);
|
||||
var BrowserRenderingRouter = class extends Router {
|
||||
constructor(env) {
|
||||
super();
|
||||
this.env = env;
|
||||
}
|
||||
env;
|
||||
#callSession(sessionId, request) {
|
||||
let cf = { miniflare: { name: sessionId } };
|
||||
return this.env.BrowserSession.get(
|
||||
this.env.BrowserSession.idFromName(sessionId)
|
||||
).fetch(request, {
|
||||
cf
|
||||
});
|
||||
}
|
||||
#fetchSession(sessionId, path, init) {
|
||||
let cf = { miniflare: { name: sessionId } };
|
||||
return this.env.BrowserSession.get(
|
||||
this.env.BrowserSession.idFromName(sessionId)
|
||||
).fetch(`http://placeholder${path}`, {
|
||||
...init,
|
||||
cf
|
||||
});
|
||||
}
|
||||
async #acquireSession() {
|
||||
let resp = await this.env[SharedBindings.MAYBE_SERVICE_LOOPBACK].fetch(
|
||||
"http://localhost/browser/launch"
|
||||
), sessionInfo = await parseJsonResponse(
|
||||
resp,
|
||||
"Failed to launch local browser via miniflare loopback (/browser/launch)"
|
||||
);
|
||||
return await this.#fetchSession(sessionInfo.sessionId, "/session-info", {
|
||||
method: "POST",
|
||||
body: JSON.stringify(sessionInfo)
|
||||
}), sessionInfo;
|
||||
}
|
||||
async #getActiveSessions() {
|
||||
let sessionIdsResp = await this.env[SharedBindings.MAYBE_SERVICE_LOOPBACK].fetch("http://localhost/browser/sessionIds"), sessionIds = await parseJsonResponse(
|
||||
sessionIdsResp,
|
||||
"Failed to list active browser sessions via miniflare loopback (/browser/sessionIds)"
|
||||
);
|
||||
return (await Promise.all(
|
||||
sessionIds.map(async (sessionId) => {
|
||||
let resp = await this.#fetchSession(sessionId, "/session-info");
|
||||
if (resp.status === 204)
|
||||
return null;
|
||||
let sessionInfo = await parseJsonResponse(
|
||||
resp,
|
||||
`Failed to read session-info for browser session ${sessionId}`
|
||||
);
|
||||
return {
|
||||
sessionId: sessionInfo.sessionId,
|
||||
startTime: sessionInfo.startTime,
|
||||
connectionId: sessionInfo.connectionId,
|
||||
connectionStartTime: sessionInfo.connectionStartTime
|
||||
};
|
||||
})
|
||||
)).filter(Boolean);
|
||||
}
|
||||
acquireRoute = async () => {
|
||||
let sessionInfo = await this.#acquireSession();
|
||||
return Response.json({ sessionId: sessionInfo.sessionId });
|
||||
};
|
||||
sessionsRoute = async () => Response.json({ sessions: await this.#getActiveSessions() });
|
||||
limitsRoute = async () => Response.json({
|
||||
maxConcurrentSessions: 6,
|
||||
allowedBrowserAcquisitions: 6,
|
||||
timeUntilNextAllowedBrowserAcquisition: 0
|
||||
});
|
||||
historyRoute = async () => Response.json([]);
|
||||
sessionListRoute = async () => Response.json(await this.#getActiveSessions());
|
||||
connectDevtoolsRoute = async (req, _params, url) => {
|
||||
let sessionId = url.searchParams.get("browser_session");
|
||||
return sessionId ? this.#callSession(sessionId, req) : new Response("browser_session must be set", { status: 400 });
|
||||
};
|
||||
acquireBrowserRoute = async () => {
|
||||
let sessionInfo = await this.#acquireSession();
|
||||
return Response.json({ sessionId: sessionInfo.sessionId });
|
||||
};
|
||||
connectBrowserRoute = async (req) => {
|
||||
let sessionInfo = await this.#acquireSession(), doUrl = new URL(req.url);
|
||||
return doUrl.pathname = `/v1/devtools/browser/${sessionInfo.sessionId}`, this.#callSession(
|
||||
sessionInfo.sessionId,
|
||||
new Request(doUrl, {
|
||||
method: req.method,
|
||||
headers: {
|
||||
...Object.fromEntries(req.headers),
|
||||
"x-session-id": sessionInfo.sessionId
|
||||
}
|
||||
})
|
||||
);
|
||||
};
|
||||
sessionDetailRoute = async (req, params) => this.#callSession(params.sessionId, req);
|
||||
closeBrowserRoute = async (req, params) => {
|
||||
let { sessionId } = params;
|
||||
await this.#callSession(sessionId, req);
|
||||
for (let i = 0; i < 50; i++) {
|
||||
let statusUrl = new URL("http://localhost/browser/status");
|
||||
if (statusUrl.searchParams.set("sessionId", sessionId), (await this.env[SharedBindings.MAYBE_SERVICE_LOOPBACK].fetch(statusUrl)).status === 410)
|
||||
break;
|
||||
await new Promise((r) => setTimeout(r, 100));
|
||||
}
|
||||
return Response.json({ status: "closed" });
|
||||
};
|
||||
connectBrowserSessionRoute = async (req, params, _url) => {
|
||||
let doUrl = new URL(req.url);
|
||||
return this.#callSession(params.sessionId, new Request(doUrl, req));
|
||||
};
|
||||
jsonVersionRoute = async (req, params) => this.#callSession(params.sessionId, req);
|
||||
jsonListRoute = async (req, params) => this.#callSession(params.sessionId, req);
|
||||
jsonAliasRoute = async (req, params) => this.#callSession(params.sessionId, req);
|
||||
jsonProtocolRoute = async (req, params) => this.#callSession(params.sessionId, req);
|
||||
jsonNewRoute = async (req, params) => this.#callSession(params.sessionId, req);
|
||||
jsonActivateRoute = async (req, params) => this.#callSession(params.sessionId, req);
|
||||
jsonCloseRoute = async (req, params) => this.#callSession(params.sessionId, req);
|
||||
pageWebSocketRoute = async (req, params) => this.#callSession(params.sessionId, req);
|
||||
};
|
||||
__decorateClass([
|
||||
GET("/v1/acquire")
|
||||
], BrowserRenderingRouter.prototype, "acquireRoute", 2), __decorateClass([
|
||||
GET("/v1/sessions")
|
||||
], BrowserRenderingRouter.prototype, "sessionsRoute", 2), __decorateClass([
|
||||
GET("/v1/limits")
|
||||
], BrowserRenderingRouter.prototype, "limitsRoute", 2), __decorateClass([
|
||||
GET("/v1/history")
|
||||
], BrowserRenderingRouter.prototype, "historyRoute", 2), __decorateClass([
|
||||
GET("/v1/devtools/session")
|
||||
], BrowserRenderingRouter.prototype, "sessionListRoute", 2), __decorateClass([
|
||||
GET("/v1/connectDevtools")
|
||||
], BrowserRenderingRouter.prototype, "connectDevtoolsRoute", 2), __decorateClass([
|
||||
POST("/v1/devtools/browser")
|
||||
], BrowserRenderingRouter.prototype, "acquireBrowserRoute", 2), __decorateClass([
|
||||
GET("/v1/devtools/browser")
|
||||
], BrowserRenderingRouter.prototype, "connectBrowserRoute", 2), __decorateClass([
|
||||
GET("/v1/devtools/session/:sessionId")
|
||||
], BrowserRenderingRouter.prototype, "sessionDetailRoute", 2), __decorateClass([
|
||||
DELETE("/v1/devtools/browser/:sessionId")
|
||||
], BrowserRenderingRouter.prototype, "closeBrowserRoute", 2), __decorateClass([
|
||||
GET("/v1/devtools/browser/:sessionId")
|
||||
], BrowserRenderingRouter.prototype, "connectBrowserSessionRoute", 2), __decorateClass([
|
||||
GET("/v1/devtools/browser/:sessionId/json/version")
|
||||
], BrowserRenderingRouter.prototype, "jsonVersionRoute", 2), __decorateClass([
|
||||
GET("/v1/devtools/browser/:sessionId/json/list")
|
||||
], BrowserRenderingRouter.prototype, "jsonListRoute", 2), __decorateClass([
|
||||
GET("/v1/devtools/browser/:sessionId/json")
|
||||
], BrowserRenderingRouter.prototype, "jsonAliasRoute", 2), __decorateClass([
|
||||
GET("/v1/devtools/browser/:sessionId/json/protocol")
|
||||
], BrowserRenderingRouter.prototype, "jsonProtocolRoute", 2), __decorateClass([
|
||||
PUT("/v1/devtools/browser/:sessionId/json/new")
|
||||
], BrowserRenderingRouter.prototype, "jsonNewRoute", 2), __decorateClass([
|
||||
GET("/v1/devtools/browser/:sessionId/json/activate/:targetId")
|
||||
], BrowserRenderingRouter.prototype, "jsonActivateRoute", 2), __decorateClass([
|
||||
GET("/v1/devtools/browser/:sessionId/json/close/:targetId")
|
||||
], BrowserRenderingRouter.prototype, "jsonCloseRoute", 2), __decorateClass([
|
||||
GET("/v1/devtools/browser/:sessionId/page/:pageId")
|
||||
], BrowserRenderingRouter.prototype, "pageWebSocketRoute", 2);
|
||||
var binding_worker_default = {
|
||||
fetch(request, env) {
|
||||
return new BrowserRenderingRouter(env).fetch(request);
|
||||
}
|
||||
};
|
||||
export {
|
||||
BrowserSession,
|
||||
binding_worker_default as default
|
||||
};
|
||||
//# sourceMappingURL=binding.worker.js.map
|
||||
+7
File diff suppressed because one or more lines are too long
+19
@@ -0,0 +1,19 @@
|
||||
// src/workers/cache/constants.ts
|
||||
var CacheHeaders = {
|
||||
NAMESPACE: "cf-cache-namespace",
|
||||
STATUS: "cf-cache-status"
|
||||
};
|
||||
|
||||
// src/workers/cache/cache-entry-noop.worker.ts
|
||||
var cache_entry_noop_worker_default = {
|
||||
async fetch(request) {
|
||||
return request.method === "GET" ? new Response(null, {
|
||||
status: 504,
|
||||
headers: { [CacheHeaders.STATUS]: "MISS" }
|
||||
}) : request.method === "PUT" ? (await request.body?.pipeTo(new WritableStream()), new Response(null, { status: 204 })) : request.method === "PURGE" ? new Response(null, { status: 404 }) : new Response(null, { status: 405 });
|
||||
}
|
||||
};
|
||||
export {
|
||||
cache_entry_noop_worker_default as default
|
||||
};
|
||||
//# sourceMappingURL=cache-entry-noop.worker.js.map
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"version": 3,
|
||||
"sources": ["../../../../src/workers/cache/constants.ts", "../../../../src/workers/cache/cache-entry-noop.worker.ts"],
|
||||
"sourcesContent": ["export const CacheHeaders = {\n\tNAMESPACE: \"cf-cache-namespace\",\n\tSTATUS: \"cf-cache-status\",\n} as const;\n\nexport const CacheBindings = {\n\tMAYBE_JSON_CACHE_WARN_USAGE: \"MINIFLARE_CACHE_WARN_USAGE\",\n} as const;\n\nexport interface CacheObjectCf {\n\tminiflare?: { cacheWarnUsage?: boolean };\n}\n", "import { CacheHeaders } from \"./constants\";\n\nexport default <ExportedHandler>{\n\tasync fetch(request) {\n\t\tif (request.method === \"GET\") {\n\t\t\treturn new Response(null, {\n\t\t\t\tstatus: 504,\n\t\t\t\theaders: { [CacheHeaders.STATUS]: \"MISS\" },\n\t\t\t});\n\t\t} else if (request.method === \"PUT\") {\n\t\t\t// Must consume request body, otherwise get \"disconnected: read end of pipe was aborted\" error from workerd\n\t\t\tawait request.body?.pipeTo(new WritableStream());\n\t\t\treturn new Response(null, { status: 204 });\n\t\t} else if (request.method === \"PURGE\") {\n\t\t\treturn new Response(null, { status: 404 });\n\t\t} else {\n\t\t\treturn new Response(null, { status: 405 });\n\t\t}\n\t},\n};\n"],
|
||||
"mappings": ";AAAO,IAAM,eAAe;AAAA,EAC3B,WAAW;AAAA,EACX,QAAQ;AACT;;;ACDA,IAAO,kCAAyB;AAAA,EAC/B,MAAM,MAAM,SAAS;AACpB,WAAI,QAAQ,WAAW,QACf,IAAI,SAAS,MAAM;AAAA,MACzB,QAAQ;AAAA,MACR,SAAS,EAAE,CAAC,aAAa,MAAM,GAAG,OAAO;AAAA,IAC1C,CAAC,IACS,QAAQ,WAAW,SAE7B,MAAM,QAAQ,MAAM,OAAO,IAAI,eAAe,CAAC,GACxC,IAAI,SAAS,MAAM,EAAE,QAAQ,IAAI,CAAC,KAC/B,QAAQ,WAAW,UACtB,IAAI,SAAS,MAAM,EAAE,QAAQ,IAAI,CAAC,IAElC,IAAI,SAAS,MAAM,EAAE,QAAQ,IAAI,CAAC;AAAA,EAE3C;AACD;",
|
||||
"names": []
|
||||
}
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
// src/workers/cache/cache-entry.worker.ts
|
||||
import { SharedBindings } from "miniflare:shared";
|
||||
|
||||
// src/workers/cache/constants.ts
|
||||
var CacheHeaders = {
|
||||
NAMESPACE: "cf-cache-namespace",
|
||||
STATUS: "cf-cache-status"
|
||||
}, CacheBindings = {
|
||||
MAYBE_JSON_CACHE_WARN_USAGE: "MINIFLARE_CACHE_WARN_USAGE"
|
||||
};
|
||||
|
||||
// src/workers/cache/cache-entry.worker.ts
|
||||
var cache_entry_worker_default = {
|
||||
async fetch(request, env) {
|
||||
let namespace = request.headers.get(CacheHeaders.NAMESPACE), name = namespace === null ? "default" : `named:${namespace}`, objectNamespace = env[SharedBindings.DURABLE_OBJECT_NAMESPACE_OBJECT], id = objectNamespace.idFromName(name), stub = objectNamespace.get(id), cf = {
|
||||
...request.cf,
|
||||
miniflare: {
|
||||
name,
|
||||
cacheWarnUsage: env[CacheBindings.MAYBE_JSON_CACHE_WARN_USAGE]
|
||||
}
|
||||
};
|
||||
return await stub.fetch(request, { cf });
|
||||
}
|
||||
};
|
||||
export {
|
||||
cache_entry_worker_default as default
|
||||
};
|
||||
//# sourceMappingURL=cache-entry.worker.js.map
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"version": 3,
|
||||
"sources": ["../../../../src/workers/cache/cache-entry.worker.ts", "../../../../src/workers/cache/constants.ts"],
|
||||
"sourcesContent": ["import { SharedBindings } from \"miniflare:shared\";\nimport { CacheBindings, CacheHeaders } from \"./constants\";\nimport type { CacheObjectCf } from \"./constants\";\nimport type { MiniflareDurableObjectCf } from \"miniflare:shared\";\n\ninterface Env {\n\t[SharedBindings.DURABLE_OBJECT_NAMESPACE_OBJECT]: DurableObjectNamespace;\n\t[CacheBindings.MAYBE_JSON_CACHE_WARN_USAGE]?: boolean;\n}\n\nexport default <ExportedHandler<Env>>{\n\tasync fetch(request, env) {\n\t\tconst namespace = request.headers.get(CacheHeaders.NAMESPACE);\n\t\tconst name = namespace === null ? \"default\" : `named:${namespace}`;\n\n\t\tconst objectNamespace = env[SharedBindings.DURABLE_OBJECT_NAMESPACE_OBJECT];\n\t\tconst id = objectNamespace.idFromName(name);\n\t\tconst stub = objectNamespace.get(id);\n\t\tconst cf: MiniflareDurableObjectCf & CacheObjectCf = {\n\t\t\t...request.cf,\n\t\t\tminiflare: {\n\t\t\t\tname,\n\t\t\t\tcacheWarnUsage: env[CacheBindings.MAYBE_JSON_CACHE_WARN_USAGE],\n\t\t\t},\n\t\t};\n\t\treturn await stub.fetch(request, { cf: cf as Record<string, unknown> });\n\t},\n};\n", "export const CacheHeaders = {\n\tNAMESPACE: \"cf-cache-namespace\",\n\tSTATUS: \"cf-cache-status\",\n} as const;\n\nexport const CacheBindings = {\n\tMAYBE_JSON_CACHE_WARN_USAGE: \"MINIFLARE_CACHE_WARN_USAGE\",\n} as const;\n\nexport interface CacheObjectCf {\n\tminiflare?: { cacheWarnUsage?: boolean };\n}\n"],
|
||||
"mappings": ";AAAA,SAAS,sBAAsB;;;ACAxB,IAAM,eAAe;AAAA,EAC3B,WAAW;AAAA,EACX,QAAQ;AACT,GAEa,gBAAgB;AAAA,EAC5B,6BAA6B;AAC9B;;;ADGA,IAAO,6BAA8B;AAAA,EACpC,MAAM,MAAM,SAAS,KAAK;AACzB,QAAM,YAAY,QAAQ,QAAQ,IAAI,aAAa,SAAS,GACtD,OAAO,cAAc,OAAO,YAAY,SAAS,SAAS,IAE1D,kBAAkB,IAAI,eAAe,+BAA+B,GACpE,KAAK,gBAAgB,WAAW,IAAI,GACpC,OAAO,gBAAgB,IAAI,EAAE,GAC7B,KAA+C;AAAA,MACpD,GAAG,QAAQ;AAAA,MACX,WAAW;AAAA,QACV;AAAA,QACA,gBAAgB,IAAI,cAAc,2BAA2B;AAAA,MAC9D;AAAA,IACD;AACA,WAAO,MAAM,KAAK,MAAM,SAAS,EAAE,GAAkC,CAAC;AAAA,EACvE;AACD;",
|
||||
"names": []
|
||||
}
|
||||
+658
@@ -0,0 +1,658 @@
|
||||
var __create = Object.create;
|
||||
var __defProp = Object.defineProperty;
|
||||
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
||||
var __getOwnPropNames = Object.getOwnPropertyNames;
|
||||
var __getProtoOf = Object.getPrototypeOf, __hasOwnProp = Object.prototype.hasOwnProperty;
|
||||
var __commonJS = (cb, mod) => function() {
|
||||
try {
|
||||
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
||||
} catch (e) {
|
||||
throw mod = 0, e;
|
||||
}
|
||||
};
|
||||
var __copyProps = (to, from, except, desc) => {
|
||||
if (from && typeof from == "object" || typeof from == "function")
|
||||
for (let key of __getOwnPropNames(from))
|
||||
!__hasOwnProp.call(to, key) && key !== except && __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
||||
return to;
|
||||
};
|
||||
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
||||
// If the importer is in node compatibility mode or this is not an ESM
|
||||
// file that has been converted to a CommonJS file using a Babel-
|
||||
// compatible transform (i.e. "__esModule" has not been set), then set
|
||||
// "default" to the CommonJS "module.exports" for node compatibility.
|
||||
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: !0 }) : target,
|
||||
mod
|
||||
));
|
||||
var __decorateClass = (decorators, target, key, kind) => {
|
||||
for (var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target, i = decorators.length - 1, decorator; i >= 0; i--)
|
||||
(decorator = decorators[i]) && (result = (kind ? decorator(target, key, result) : decorator(result)) || result);
|
||||
return kind && result && __defProp(target, key, result), result;
|
||||
};
|
||||
|
||||
// ../../node_modules/.pnpm/http-cache-semantics@4.1.1/node_modules/http-cache-semantics/index.js
|
||||
var require_http_cache_semantics = __commonJS({
|
||||
"../../node_modules/.pnpm/http-cache-semantics@4.1.1/node_modules/http-cache-semantics/index.js"(exports, module) {
|
||||
"use strict";
|
||||
var statusCodeCacheableByDefault = /* @__PURE__ */ new Set([
|
||||
200,
|
||||
203,
|
||||
204,
|
||||
206,
|
||||
300,
|
||||
301,
|
||||
308,
|
||||
404,
|
||||
405,
|
||||
410,
|
||||
414,
|
||||
501
|
||||
]), understoodStatuses = /* @__PURE__ */ new Set([
|
||||
200,
|
||||
203,
|
||||
204,
|
||||
300,
|
||||
301,
|
||||
302,
|
||||
303,
|
||||
307,
|
||||
308,
|
||||
404,
|
||||
405,
|
||||
410,
|
||||
414,
|
||||
501
|
||||
]), errorStatusCodes = /* @__PURE__ */ new Set([
|
||||
500,
|
||||
502,
|
||||
503,
|
||||
504
|
||||
]), hopByHopHeaders = {
|
||||
date: !0,
|
||||
// included, because we add Age update Date
|
||||
connection: !0,
|
||||
"keep-alive": !0,
|
||||
"proxy-authenticate": !0,
|
||||
"proxy-authorization": !0,
|
||||
te: !0,
|
||||
trailer: !0,
|
||||
"transfer-encoding": !0,
|
||||
upgrade: !0
|
||||
}, excludedFromRevalidationUpdate = {
|
||||
// Since the old body is reused, it doesn't make sense to change properties of the body
|
||||
"content-length": !0,
|
||||
"content-encoding": !0,
|
||||
"transfer-encoding": !0,
|
||||
"content-range": !0
|
||||
};
|
||||
function toNumberOrZero(s) {
|
||||
let n = parseInt(s, 10);
|
||||
return isFinite(n) ? n : 0;
|
||||
}
|
||||
function isErrorResponse(response) {
|
||||
return response ? errorStatusCodes.has(response.status) : !0;
|
||||
}
|
||||
function parseCacheControl(header) {
|
||||
let cc = {};
|
||||
if (!header) return cc;
|
||||
let parts = header.trim().split(/,/);
|
||||
for (let part of parts) {
|
||||
let [k, v] = part.split(/=/, 2);
|
||||
cc[k.trim()] = v === void 0 ? !0 : v.trim().replace(/^"|"$/g, "");
|
||||
}
|
||||
return cc;
|
||||
}
|
||||
function formatCacheControl(cc) {
|
||||
let parts = [];
|
||||
for (let k in cc) {
|
||||
let v = cc[k];
|
||||
parts.push(v === !0 ? k : k + "=" + v);
|
||||
}
|
||||
if (parts.length)
|
||||
return parts.join(", ");
|
||||
}
|
||||
module.exports = class {
|
||||
constructor(req, res, {
|
||||
shared,
|
||||
cacheHeuristic,
|
||||
immutableMinTimeToLive,
|
||||
ignoreCargoCult,
|
||||
_fromObject
|
||||
} = {}) {
|
||||
if (_fromObject) {
|
||||
this._fromObject(_fromObject);
|
||||
return;
|
||||
}
|
||||
if (!res || !res.headers)
|
||||
throw Error("Response headers missing");
|
||||
this._assertRequestHasHeaders(req), this._responseTime = this.now(), this._isShared = shared !== !1, this._cacheHeuristic = cacheHeuristic !== void 0 ? cacheHeuristic : 0.1, this._immutableMinTtl = immutableMinTimeToLive !== void 0 ? immutableMinTimeToLive : 24 * 3600 * 1e3, this._status = "status" in res ? res.status : 200, this._resHeaders = res.headers, this._rescc = parseCacheControl(res.headers["cache-control"]), this._method = "method" in req ? req.method : "GET", this._url = req.url, this._host = req.headers.host, this._noAuthorization = !req.headers.authorization, this._reqHeaders = res.headers.vary ? req.headers : null, this._reqcc = parseCacheControl(req.headers["cache-control"]), ignoreCargoCult && "pre-check" in this._rescc && "post-check" in this._rescc && (delete this._rescc["pre-check"], delete this._rescc["post-check"], delete this._rescc["no-cache"], delete this._rescc["no-store"], delete this._rescc["must-revalidate"], this._resHeaders = Object.assign({}, this._resHeaders, {
|
||||
"cache-control": formatCacheControl(this._rescc)
|
||||
}), delete this._resHeaders.expires, delete this._resHeaders.pragma), res.headers["cache-control"] == null && /no-cache/.test(res.headers.pragma) && (this._rescc["no-cache"] = !0);
|
||||
}
|
||||
now() {
|
||||
return Date.now();
|
||||
}
|
||||
storable() {
|
||||
return !!(!this._reqcc["no-store"] && // A cache MUST NOT store a response to any request, unless:
|
||||
// The request method is understood by the cache and defined as being cacheable, and
|
||||
(this._method === "GET" || this._method === "HEAD" || this._method === "POST" && this._hasExplicitExpiration()) && // the response status code is understood by the cache, and
|
||||
understoodStatuses.has(this._status) && // the "no-store" cache directive does not appear in request or response header fields, and
|
||||
!this._rescc["no-store"] && // the "private" response directive does not appear in the response, if the cache is shared, and
|
||||
(!this._isShared || !this._rescc.private) && // the Authorization header field does not appear in the request, if the cache is shared,
|
||||
(!this._isShared || this._noAuthorization || this._allowsStoringAuthenticated()) && // the response either:
|
||||
// contains an Expires header field, or
|
||||
(this._resHeaders.expires || // contains a max-age response directive, or
|
||||
// contains a s-maxage response directive and the cache is shared, or
|
||||
// contains a public response directive.
|
||||
this._rescc["max-age"] || this._isShared && this._rescc["s-maxage"] || this._rescc.public || // has a status code that is defined as cacheable by default
|
||||
statusCodeCacheableByDefault.has(this._status)));
|
||||
}
|
||||
_hasExplicitExpiration() {
|
||||
return this._isShared && this._rescc["s-maxage"] || this._rescc["max-age"] || this._resHeaders.expires;
|
||||
}
|
||||
_assertRequestHasHeaders(req) {
|
||||
if (!req || !req.headers)
|
||||
throw Error("Request headers missing");
|
||||
}
|
||||
satisfiesWithoutRevalidation(req) {
|
||||
this._assertRequestHasHeaders(req);
|
||||
let requestCC = parseCacheControl(req.headers["cache-control"]);
|
||||
return requestCC["no-cache"] || /no-cache/.test(req.headers.pragma) || requestCC["max-age"] && this.age() > requestCC["max-age"] || requestCC["min-fresh"] && this.timeToLive() < 1e3 * requestCC["min-fresh"] || this.stale() && !(requestCC["max-stale"] && !this._rescc["must-revalidate"] && (requestCC["max-stale"] === !0 || requestCC["max-stale"] > this.age() - this.maxAge())) ? !1 : this._requestMatches(req, !1);
|
||||
}
|
||||
_requestMatches(req, allowHeadMethod) {
|
||||
return (!this._url || this._url === req.url) && this._host === req.headers.host && // the request method associated with the stored response allows it to be used for the presented request, and
|
||||
(!req.method || this._method === req.method || allowHeadMethod && req.method === "HEAD") && // selecting header fields nominated by the stored response (if any) match those presented, and
|
||||
this._varyMatches(req);
|
||||
}
|
||||
_allowsStoringAuthenticated() {
|
||||
return this._rescc["must-revalidate"] || this._rescc.public || this._rescc["s-maxage"];
|
||||
}
|
||||
_varyMatches(req) {
|
||||
if (!this._resHeaders.vary)
|
||||
return !0;
|
||||
if (this._resHeaders.vary === "*")
|
||||
return !1;
|
||||
let fields = this._resHeaders.vary.trim().toLowerCase().split(/\s*,\s*/);
|
||||
for (let name of fields)
|
||||
if (req.headers[name] !== this._reqHeaders[name]) return !1;
|
||||
return !0;
|
||||
}
|
||||
_copyWithoutHopByHopHeaders(inHeaders) {
|
||||
let headers = {};
|
||||
for (let name in inHeaders)
|
||||
hopByHopHeaders[name] || (headers[name] = inHeaders[name]);
|
||||
if (inHeaders.connection) {
|
||||
let tokens = inHeaders.connection.trim().split(/\s*,\s*/);
|
||||
for (let name of tokens)
|
||||
delete headers[name];
|
||||
}
|
||||
if (headers.warning) {
|
||||
let warnings = headers.warning.split(/,/).filter((warning) => !/^\s*1[0-9][0-9]/.test(warning));
|
||||
warnings.length ? headers.warning = warnings.join(",").trim() : delete headers.warning;
|
||||
}
|
||||
return headers;
|
||||
}
|
||||
responseHeaders() {
|
||||
let headers = this._copyWithoutHopByHopHeaders(this._resHeaders), age = this.age();
|
||||
return age > 3600 * 24 && !this._hasExplicitExpiration() && this.maxAge() > 3600 * 24 && (headers.warning = (headers.warning ? `${headers.warning}, ` : "") + '113 - "rfc7234 5.5.4"'), headers.age = `${Math.round(age)}`, headers.date = new Date(this.now()).toUTCString(), headers;
|
||||
}
|
||||
/**
|
||||
* Value of the Date response header or current time if Date was invalid
|
||||
* @return timestamp
|
||||
*/
|
||||
date() {
|
||||
let serverDate = Date.parse(this._resHeaders.date);
|
||||
return isFinite(serverDate) ? serverDate : this._responseTime;
|
||||
}
|
||||
/**
|
||||
* Value of the Age header, in seconds, updated for the current time.
|
||||
* May be fractional.
|
||||
*
|
||||
* @return Number
|
||||
*/
|
||||
age() {
|
||||
let age = this._ageValue(), residentTime = (this.now() - this._responseTime) / 1e3;
|
||||
return age + residentTime;
|
||||
}
|
||||
_ageValue() {
|
||||
return toNumberOrZero(this._resHeaders.age);
|
||||
}
|
||||
/**
|
||||
* Value of applicable max-age (or heuristic equivalent) in seconds. This counts since response's `Date`.
|
||||
*
|
||||
* For an up-to-date value, see `timeToLive()`.
|
||||
*
|
||||
* @return Number
|
||||
*/
|
||||
maxAge() {
|
||||
if (!this.storable() || this._rescc["no-cache"] || this._isShared && this._resHeaders["set-cookie"] && !this._rescc.public && !this._rescc.immutable || this._resHeaders.vary === "*")
|
||||
return 0;
|
||||
if (this._isShared) {
|
||||
if (this._rescc["proxy-revalidate"])
|
||||
return 0;
|
||||
if (this._rescc["s-maxage"])
|
||||
return toNumberOrZero(this._rescc["s-maxage"]);
|
||||
}
|
||||
if (this._rescc["max-age"])
|
||||
return toNumberOrZero(this._rescc["max-age"]);
|
||||
let defaultMinTtl = this._rescc.immutable ? this._immutableMinTtl : 0, serverDate = this.date();
|
||||
if (this._resHeaders.expires) {
|
||||
let expires = Date.parse(this._resHeaders.expires);
|
||||
return Number.isNaN(expires) || expires < serverDate ? 0 : Math.max(defaultMinTtl, (expires - serverDate) / 1e3);
|
||||
}
|
||||
if (this._resHeaders["last-modified"]) {
|
||||
let lastModified = Date.parse(this._resHeaders["last-modified"]);
|
||||
if (isFinite(lastModified) && serverDate > lastModified)
|
||||
return Math.max(
|
||||
defaultMinTtl,
|
||||
(serverDate - lastModified) / 1e3 * this._cacheHeuristic
|
||||
);
|
||||
}
|
||||
return defaultMinTtl;
|
||||
}
|
||||
timeToLive() {
|
||||
let age = this.maxAge() - this.age(), staleIfErrorAge = age + toNumberOrZero(this._rescc["stale-if-error"]), staleWhileRevalidateAge = age + toNumberOrZero(this._rescc["stale-while-revalidate"]);
|
||||
return Math.max(0, age, staleIfErrorAge, staleWhileRevalidateAge) * 1e3;
|
||||
}
|
||||
stale() {
|
||||
return this.maxAge() <= this.age();
|
||||
}
|
||||
_useStaleIfError() {
|
||||
return this.maxAge() + toNumberOrZero(this._rescc["stale-if-error"]) > this.age();
|
||||
}
|
||||
useStaleWhileRevalidate() {
|
||||
return this.maxAge() + toNumberOrZero(this._rescc["stale-while-revalidate"]) > this.age();
|
||||
}
|
||||
static fromObject(obj) {
|
||||
return new this(void 0, void 0, { _fromObject: obj });
|
||||
}
|
||||
_fromObject(obj) {
|
||||
if (this._responseTime) throw Error("Reinitialized");
|
||||
if (!obj || obj.v !== 1) throw Error("Invalid serialization");
|
||||
this._responseTime = obj.t, this._isShared = obj.sh, this._cacheHeuristic = obj.ch, this._immutableMinTtl = obj.imm !== void 0 ? obj.imm : 24 * 3600 * 1e3, this._status = obj.st, this._resHeaders = obj.resh, this._rescc = obj.rescc, this._method = obj.m, this._url = obj.u, this._host = obj.h, this._noAuthorization = obj.a, this._reqHeaders = obj.reqh, this._reqcc = obj.reqcc;
|
||||
}
|
||||
toObject() {
|
||||
return {
|
||||
v: 1,
|
||||
t: this._responseTime,
|
||||
sh: this._isShared,
|
||||
ch: this._cacheHeuristic,
|
||||
imm: this._immutableMinTtl,
|
||||
st: this._status,
|
||||
resh: this._resHeaders,
|
||||
rescc: this._rescc,
|
||||
m: this._method,
|
||||
u: this._url,
|
||||
h: this._host,
|
||||
a: this._noAuthorization,
|
||||
reqh: this._reqHeaders,
|
||||
reqcc: this._reqcc
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Headers for sending to the origin server to revalidate stale response.
|
||||
* Allows server to return 304 to allow reuse of the previous response.
|
||||
*
|
||||
* Hop by hop headers are always stripped.
|
||||
* Revalidation headers may be added or removed, depending on request.
|
||||
*/
|
||||
revalidationHeaders(incomingReq) {
|
||||
this._assertRequestHasHeaders(incomingReq);
|
||||
let headers = this._copyWithoutHopByHopHeaders(incomingReq.headers);
|
||||
if (delete headers["if-range"], !this._requestMatches(incomingReq, !0) || !this.storable())
|
||||
return delete headers["if-none-match"], delete headers["if-modified-since"], headers;
|
||||
if (this._resHeaders.etag && (headers["if-none-match"] = headers["if-none-match"] ? `${headers["if-none-match"]}, ${this._resHeaders.etag}` : this._resHeaders.etag), headers["accept-ranges"] || headers["if-match"] || headers["if-unmodified-since"] || this._method && this._method != "GET") {
|
||||
if (delete headers["if-modified-since"], headers["if-none-match"]) {
|
||||
let etags = headers["if-none-match"].split(/,/).filter((etag) => !/^\s*W\//.test(etag));
|
||||
etags.length ? headers["if-none-match"] = etags.join(",").trim() : delete headers["if-none-match"];
|
||||
}
|
||||
} else this._resHeaders["last-modified"] && !headers["if-modified-since"] && (headers["if-modified-since"] = this._resHeaders["last-modified"]);
|
||||
return headers;
|
||||
}
|
||||
/**
|
||||
* Creates new CachePolicy with information combined from the previews response,
|
||||
* and the new revalidation response.
|
||||
*
|
||||
* Returns {policy, modified} where modified is a boolean indicating
|
||||
* whether the response body has been modified, and old cached body can't be used.
|
||||
*
|
||||
* @return {Object} {policy: CachePolicy, modified: Boolean}
|
||||
*/
|
||||
revalidatedPolicy(request, response) {
|
||||
if (this._assertRequestHasHeaders(request), this._useStaleIfError() && isErrorResponse(response))
|
||||
return {
|
||||
modified: !1,
|
||||
matches: !1,
|
||||
policy: this
|
||||
};
|
||||
if (!response || !response.headers)
|
||||
throw Error("Response headers missing");
|
||||
let matches = !1;
|
||||
if (response.status !== void 0 && response.status != 304 ? matches = !1 : response.headers.etag && !/^\s*W\//.test(response.headers.etag) ? matches = this._resHeaders.etag && this._resHeaders.etag.replace(/^\s*W\//, "") === response.headers.etag : this._resHeaders.etag && response.headers.etag ? matches = this._resHeaders.etag.replace(/^\s*W\//, "") === response.headers.etag.replace(/^\s*W\//, "") : this._resHeaders["last-modified"] ? matches = this._resHeaders["last-modified"] === response.headers["last-modified"] : !this._resHeaders.etag && !this._resHeaders["last-modified"] && !response.headers.etag && !response.headers["last-modified"] && (matches = !0), !matches)
|
||||
return {
|
||||
policy: new this.constructor(request, response),
|
||||
// Client receiving 304 without body, even if it's invalid/mismatched has no option
|
||||
// but to reuse a cached body. We don't have a good way to tell clients to do
|
||||
// error recovery in such case.
|
||||
modified: response.status != 304,
|
||||
matches: !1
|
||||
};
|
||||
let headers = {};
|
||||
for (let k in this._resHeaders)
|
||||
headers[k] = k in response.headers && !excludedFromRevalidationUpdate[k] ? response.headers[k] : this._resHeaders[k];
|
||||
let newResponse = Object.assign({}, response, {
|
||||
status: this._status,
|
||||
method: this._method,
|
||||
headers
|
||||
});
|
||||
return {
|
||||
policy: new this.constructor(request, newResponse, {
|
||||
shared: this._isShared,
|
||||
cacheHeuristic: this._cacheHeuristic,
|
||||
immutableMinTimeToLive: this._immutableMinTtl
|
||||
}),
|
||||
modified: !1,
|
||||
matches: !0
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
// src/workers/cache/cache.worker.ts
|
||||
var import_http_cache_semantics = __toESM(require_http_cache_semantics());
|
||||
import assert from "node:assert";
|
||||
import { Buffer as Buffer2 } from "node:buffer";
|
||||
import {
|
||||
DeferredPromise,
|
||||
DELETE,
|
||||
GET,
|
||||
KeyValueStorage,
|
||||
LogLevel,
|
||||
MiniflareDurableObject,
|
||||
parseRanges,
|
||||
PURGE,
|
||||
PUT
|
||||
} from "miniflare:shared";
|
||||
|
||||
// src/workers/kv/constants.ts
|
||||
import { testRegExps } from "miniflare:shared";
|
||||
var KVLimits = {
|
||||
MIN_CACHE_TTL_SECONDS: 30,
|
||||
MIN_EXPIRATION_TTL_SECONDS: 60,
|
||||
MAX_LIST_KEYS: 1e3,
|
||||
MAX_KEY_SIZE_BYTES: 512,
|
||||
MAX_VALUE_SIZE_BYTES: 25 * 1024 * 1024,
|
||||
MAX_VALUE_SIZE_TEST_BYTES: 1024,
|
||||
MAX_METADATA_SIZE_BYTES: 1024,
|
||||
MAX_BULK_SIZE_BYTES: 25 * 1024 * 1024
|
||||
};
|
||||
var SITES_NO_CACHE_PREFIX = "$__MINIFLARE_SITES__$/";
|
||||
function isSitesRequest(request) {
|
||||
return new URL(request.url).pathname.startsWith(`/${SITES_NO_CACHE_PREFIX}`);
|
||||
}
|
||||
|
||||
// src/workers/cache/errors.worker.ts
|
||||
import { HttpError } from "miniflare:shared";
|
||||
|
||||
// src/workers/cache/constants.ts
|
||||
var CacheHeaders = {
|
||||
NAMESPACE: "cf-cache-namespace",
|
||||
STATUS: "cf-cache-status"
|
||||
};
|
||||
|
||||
// src/workers/cache/errors.worker.ts
|
||||
var CacheError = class extends HttpError {
|
||||
constructor(code, message, headers = []) {
|
||||
super(code, message);
|
||||
this.headers = headers;
|
||||
}
|
||||
headers;
|
||||
toResponse() {
|
||||
return new Response(null, {
|
||||
status: this.code,
|
||||
headers: this.headers
|
||||
});
|
||||
}
|
||||
context(info) {
|
||||
return this.message += ` (${info})`, this;
|
||||
}
|
||||
}, StorageFailure = class extends CacheError {
|
||||
constructor() {
|
||||
super(413, "Cache storage failed");
|
||||
}
|
||||
}, PurgeFailure = class extends CacheError {
|
||||
constructor() {
|
||||
super(404, "Couldn't find asset to purge");
|
||||
}
|
||||
}, CacheMiss = class extends CacheError {
|
||||
constructor() {
|
||||
super(
|
||||
// workerd ignores this, but it's the correct status code
|
||||
504,
|
||||
"Asset not found in cache",
|
||||
[[CacheHeaders.STATUS, "MISS"]]
|
||||
);
|
||||
}
|
||||
}, RangeNotSatisfiable = class extends CacheError {
|
||||
constructor(size) {
|
||||
super(416, "Range not satisfiable", [
|
||||
["Content-Range", `bytes */${size}`],
|
||||
[CacheHeaders.STATUS, "HIT"]
|
||||
]);
|
||||
}
|
||||
};
|
||||
|
||||
// src/workers/cache/cache.worker.ts
|
||||
function getCacheKey(req) {
|
||||
return req.cf?.cacheKey ? String(req.cf?.cacheKey) : req.url;
|
||||
}
|
||||
function getExpiration(timers, req, res) {
|
||||
let reqHeaders = normaliseHeaders(req.headers);
|
||||
delete reqHeaders["cache-control"];
|
||||
let resHeaders = normaliseHeaders(res.headers);
|
||||
resHeaders["cache-control"]?.toLowerCase().includes("private=set-cookie") && (resHeaders["cache-control"] = resHeaders["cache-control"]?.toLowerCase().replace(/private=set-cookie;?/i, ""), delete resHeaders["set-cookie"]);
|
||||
let cacheReq = {
|
||||
url: req.url,
|
||||
// If a request gets to the Cache service, it's method will be GET. See README.md for details
|
||||
method: "GET",
|
||||
headers: reqHeaders
|
||||
}, cacheRes = {
|
||||
status: res.status,
|
||||
headers: resHeaders
|
||||
}, originalNow = import_http_cache_semantics.default.prototype.now;
|
||||
import_http_cache_semantics.default.prototype.now = timers.now;
|
||||
try {
|
||||
let policy = new import_http_cache_semantics.default(cacheReq, cacheRes, { shared: !0 });
|
||||
return {
|
||||
// Check if the request & response is cacheable
|
||||
storable: policy.storable() && !("set-cookie" in resHeaders),
|
||||
expiration: policy.timeToLive(),
|
||||
// Cache Policy Headers is typed as [header: string]: string | string[] | undefined
|
||||
// It's safe to ignore the undefined here, which is what casting to HeadersInit does
|
||||
headers: policy.responseHeaders()
|
||||
};
|
||||
} finally {
|
||||
import_http_cache_semantics.default.prototype.now = originalNow;
|
||||
}
|
||||
}
|
||||
function normaliseHeaders(headers) {
|
||||
let result = {};
|
||||
for (let [key, value] of headers) result[key.toLowerCase()] = value;
|
||||
return result;
|
||||
}
|
||||
var etagRegexp = /^(W\/)?"(.+)"$/;
|
||||
function parseETag(value) {
|
||||
return etagRegexp.exec(value.trim())?.[2] ?? void 0;
|
||||
}
|
||||
var utcDateRegexp = /^(Mon|Tue|Wed|Thu|Fri|Sat|Sun), \d\d (Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) \d\d\d\d \d\d:\d\d:\d\d GMT$/;
|
||||
function parseUTCDate(value) {
|
||||
return utcDateRegexp.test(value) ? Date.parse(value) : NaN;
|
||||
}
|
||||
function getMatchResponse(reqHeaders, res) {
|
||||
let reqIfNoneMatchHeader = reqHeaders.get("If-None-Match"), resETagHeader = res.headers.get("ETag");
|
||||
if (reqIfNoneMatchHeader !== null && resETagHeader !== null) {
|
||||
let resETag = parseETag(resETagHeader);
|
||||
if (resETag !== void 0) {
|
||||
if (reqIfNoneMatchHeader.trim() === "*")
|
||||
return new Response(null, { status: 304, headers: res.headers });
|
||||
for (let reqIfNoneMatch of reqIfNoneMatchHeader.split(","))
|
||||
if (resETag === parseETag(reqIfNoneMatch))
|
||||
return new Response(null, { status: 304, headers: res.headers });
|
||||
}
|
||||
}
|
||||
let reqIfModifiedSinceHeader = reqHeaders.get("If-Modified-Since"), resLastModifiedHeader = res.headers.get("Last-Modified");
|
||||
if (reqIfModifiedSinceHeader !== null && resLastModifiedHeader !== null) {
|
||||
let reqIfModifiedSince = parseUTCDate(reqIfModifiedSinceHeader);
|
||||
if (parseUTCDate(resLastModifiedHeader) <= reqIfModifiedSince)
|
||||
return new Response(null, { status: 304, headers: res.headers });
|
||||
}
|
||||
if (res.ranges.length > 0)
|
||||
if (res.status = 206, res.ranges.length > 1)
|
||||
assert(!(res.body instanceof ReadableStream)), res.headers.set("Content-Type", res.body.multipartContentType);
|
||||
else {
|
||||
let { start, end } = res.ranges[0];
|
||||
res.headers.set(
|
||||
"Content-Range",
|
||||
`bytes ${start}-${end}/${res.totalSize}`
|
||||
), res.headers.set("Content-Length", `${end - start + 1}`);
|
||||
}
|
||||
return res.body instanceof ReadableStream || (res.body = res.body.body), new Response(res.body, { status: res.status, headers: res.headers });
|
||||
}
|
||||
var CR = 13, LF = 10, STATUS_REGEXP = /^HTTP\/\d(?:\.\d)? (?<rawStatusCode>\d+) (?<statusText>.*)$/;
|
||||
async function parseHttpResponse(stream) {
|
||||
let buffer = Buffer2.alloc(0), blankLineIndex = -1;
|
||||
for await (let chunk of stream.values({ preventCancel: !0 }))
|
||||
if (buffer = Buffer2.concat([buffer, chunk]), blankLineIndex = buffer.findIndex(
|
||||
(_value, index) => buffer[index] === CR && buffer[index + 1] === LF && buffer[index + 2] === CR && buffer[index + 3] === LF
|
||||
), blankLineIndex !== -1) break;
|
||||
assert(blankLineIndex !== -1, "Expected to find blank line in HTTP message");
|
||||
let rawStatusHeaders = buffer.subarray(0, blankLineIndex).toString(), [rawStatus, ...rawHeaders] = rawStatusHeaders.split(`\r
|
||||
`), statusMatch = rawStatus.match(STATUS_REGEXP);
|
||||
assert(
|
||||
statusMatch?.groups != null,
|
||||
`Expected first line ${JSON.stringify(rawStatus)} to be HTTP status line`
|
||||
);
|
||||
let { rawStatusCode, statusText } = statusMatch.groups, statusCode = parseInt(rawStatusCode), headers = rawHeaders.map((rawHeader) => {
|
||||
let index = rawHeader.indexOf(":");
|
||||
return [
|
||||
rawHeader.substring(0, index),
|
||||
rawHeader.substring(index + 1).trim()
|
||||
];
|
||||
}), prefix = buffer.subarray(
|
||||
blankLineIndex + 4
|
||||
/* "\r\n\r\n" */
|
||||
), { readable, writable } = new IdentityTransformStream(), writer = writable.getWriter();
|
||||
return writer.write(prefix).then(() => (writer.releaseLock(), stream.pipeTo(writable))).catch((e) => console.error("Error writing HTTP body:", e)), new Response(readable, { status: statusCode, statusText, headers });
|
||||
}
|
||||
var SizingStream = class extends TransformStream {
|
||||
size;
|
||||
constructor() {
|
||||
let sizePromise = new DeferredPromise(), size = 0;
|
||||
super({
|
||||
transform(chunk, controller) {
|
||||
size += chunk.byteLength, controller.enqueue(chunk);
|
||||
},
|
||||
flush() {
|
||||
sizePromise.resolve(size);
|
||||
}
|
||||
}), this.size = sizePromise;
|
||||
}
|
||||
}, CacheObject = class extends MiniflareDurableObject {
|
||||
#warnedUsage = !1;
|
||||
async #maybeWarnUsage(request) {
|
||||
!this.#warnedUsage && request.cf?.miniflare?.cacheWarnUsage === !0 && (this.#warnedUsage = !0, await this.logWithLevel(
|
||||
LogLevel.WARN,
|
||||
"Cache operations will have no impact if you deploy to a workers.dev subdomain!"
|
||||
));
|
||||
}
|
||||
#storage;
|
||||
get storage() {
|
||||
return this.#storage ??= new KeyValueStorage(this);
|
||||
}
|
||||
match = async (req) => {
|
||||
await this.#maybeWarnUsage(req);
|
||||
let cacheKey = getCacheKey(req);
|
||||
if (isSitesRequest(req)) throw new CacheMiss();
|
||||
let resHeaders, resRanges, cached = await this.storage.get(cacheKey, ({ size, headers }) => {
|
||||
resHeaders = new Headers(headers);
|
||||
let contentType = resHeaders.get("Content-Type"), rangeHeader = req.headers.get("Range");
|
||||
if (rangeHeader !== null && (resRanges = parseRanges(rangeHeader, size), resRanges === void 0))
|
||||
throw new RangeNotSatisfiable(size);
|
||||
return {
|
||||
ranges: resRanges,
|
||||
contentLength: size,
|
||||
contentType: contentType ?? void 0
|
||||
};
|
||||
});
|
||||
if (cached?.metadata === void 0) throw new CacheMiss();
|
||||
return assert(resHeaders !== void 0), resHeaders.set("CF-Cache-Status", "HIT"), resRanges ??= [], getMatchResponse(req.headers, {
|
||||
status: cached.metadata.status,
|
||||
headers: resHeaders,
|
||||
ranges: resRanges,
|
||||
body: cached.value,
|
||||
totalSize: cached.metadata.size
|
||||
});
|
||||
};
|
||||
put = async (req) => {
|
||||
await this.#maybeWarnUsage(req);
|
||||
let cacheKey = getCacheKey(req);
|
||||
if (isSitesRequest(req)) throw new CacheMiss();
|
||||
assert(req.body !== null);
|
||||
let res = await parseHttpResponse(req.body), body = res.body;
|
||||
assert(body !== null);
|
||||
let { storable, expiration, headers } = getExpiration(
|
||||
this.timers,
|
||||
req,
|
||||
res
|
||||
);
|
||||
if (!storable) {
|
||||
try {
|
||||
await body.pipeTo(new WritableStream());
|
||||
} catch {
|
||||
}
|
||||
throw new StorageFailure();
|
||||
}
|
||||
let contentLength = parseInt(res.headers.get("Content-Length") ?? "NaN"), sizePromise;
|
||||
if (Number.isNaN(contentLength)) {
|
||||
let stream = new SizingStream();
|
||||
body = body.pipeThrough(stream), sizePromise = stream.size;
|
||||
} else
|
||||
sizePromise = Promise.resolve(contentLength);
|
||||
let metadata = sizePromise.then((size) => ({
|
||||
headers: Object.entries(headers),
|
||||
status: res.status,
|
||||
size
|
||||
}));
|
||||
return await this.storage.put({
|
||||
key: cacheKey,
|
||||
value: body,
|
||||
expiration: this.timers.now() + expiration,
|
||||
metadata
|
||||
}), new Response(null, { status: 204 });
|
||||
};
|
||||
delete = async (req) => {
|
||||
await this.#maybeWarnUsage(req);
|
||||
let cacheKey = getCacheKey(req);
|
||||
if (!await this.storage.delete(cacheKey)) throw new PurgeFailure();
|
||||
return new Response(null);
|
||||
};
|
||||
purgeAll = async () => {
|
||||
let deletedCount = this.storage.deleteAll();
|
||||
return Response.json({ deleted: deletedCount });
|
||||
};
|
||||
};
|
||||
__decorateClass([
|
||||
GET()
|
||||
], CacheObject.prototype, "match", 2), __decorateClass([
|
||||
PUT()
|
||||
], CacheObject.prototype, "put", 2), __decorateClass([
|
||||
PURGE()
|
||||
], CacheObject.prototype, "delete", 2), __decorateClass([
|
||||
DELETE("/purge-all")
|
||||
], CacheObject.prototype, "purgeAll", 2);
|
||||
export {
|
||||
CacheObject,
|
||||
parseHttpResponse
|
||||
};
|
||||
//# sourceMappingURL=cache.worker.js.map
|
||||
+7
File diff suppressed because one or more lines are too long
+204
@@ -0,0 +1,204 @@
|
||||
// src/workers/core/dev-registry-proxy.worker.ts
|
||||
import { WorkerEntrypoint } from "cloudflare:workers";
|
||||
|
||||
// src/workers/queues/constants.ts
|
||||
var HEADER_QUEUE_NAME = "MF-Queue-Name", SERVICE_QUEUE_PREFIX = "queues:queue";
|
||||
function getQueueServiceName(queueId) {
|
||||
return `${SERVICE_QUEUE_PREFIX}:${queueId}`;
|
||||
}
|
||||
|
||||
// src/workers/core/dev-registry-proxy-shared.worker.ts
|
||||
import { DurableObject } from "cloudflare:workers";
|
||||
var registry = /* @__PURE__ */ new Map();
|
||||
function setRegistry(data) {
|
||||
registry = new Map(Object.entries(data));
|
||||
}
|
||||
function resolveTarget(service) {
|
||||
let entry = registry.get(service);
|
||||
if (!(!entry || !("debugPortAddress" in entry)))
|
||||
return entry;
|
||||
}
|
||||
function findQueueConsumer(queueName) {
|
||||
for (let entry of registry.values())
|
||||
if (Array.isArray(entry.queueConsumers) && entry.queueConsumers.includes(queueName) && entry.debugPortAddress)
|
||||
return entry;
|
||||
}
|
||||
function hasRegistryEntry(service) {
|
||||
return registry.has(service);
|
||||
}
|
||||
function workerNotFoundMessage(service) {
|
||||
return hasRegistryEntry(service) ? `Worker "${service}" is not compatible with this version of the dev server. Please update all Worker instances to the same version.` : `Worker "${service}" not found. Make sure it is running locally.`;
|
||||
}
|
||||
function connectToActor(debugPort, scriptName, className, actorId) {
|
||||
let target = resolveTarget(scriptName);
|
||||
return !target || !target.debugPortAddress ? null : debugPort.connect(target.debugPortAddress).getActor(target.userWorkerService, className, actorId);
|
||||
}
|
||||
function createProxyDurableObjectClass({
|
||||
scriptName,
|
||||
className
|
||||
}) {
|
||||
return class extends DurableObject {
|
||||
_cachedFetcher;
|
||||
_cachedDebugPortAddress;
|
||||
// Lazily resolve and cache. Invalidates when debugPortAddress changes.
|
||||
_resolve() {
|
||||
let target = resolveTarget(scriptName);
|
||||
if (this._cachedFetcher && target?.debugPortAddress === this._cachedDebugPortAddress)
|
||||
return this._cachedFetcher;
|
||||
this._cachedFetcher = void 0, this._cachedDebugPortAddress = void 0;
|
||||
let fetcher = connectToActor(
|
||||
this.env.DEV_REGISTRY_DEBUG_PORT,
|
||||
scriptName,
|
||||
className,
|
||||
this.ctx.id.toString()
|
||||
);
|
||||
return fetcher && target && (this._cachedFetcher = fetcher, this._cachedDebugPortAddress = target.debugPortAddress), fetcher;
|
||||
}
|
||||
constructor(ctx, env) {
|
||||
return super(ctx, env), new Proxy(this, {
|
||||
get(target, prop) {
|
||||
if (Reflect.has(target, prop))
|
||||
return Reflect.get(target, prop);
|
||||
let fetcher = target._resolve();
|
||||
return fetcher ? Reflect.get(fetcher, prop) : () => {
|
||||
throw new Error(workerNotFoundMessage(scriptName));
|
||||
};
|
||||
}
|
||||
});
|
||||
}
|
||||
fetch(request) {
|
||||
let fetcher = this._resolve();
|
||||
return fetcher ? fetcher.fetch(request) : Promise.resolve(
|
||||
new Response(workerNotFoundMessage(scriptName), { status: 503 })
|
||||
);
|
||||
}
|
||||
};
|
||||
}
|
||||
var SERIALIZED_DATE = "___serialized_date___", SERIALIZED_BIGINT = "___serialized_bigint___";
|
||||
function tailEventsReplacer(_, value) {
|
||||
return value instanceof Date ? { [SERIALIZED_DATE]: value.toISOString() } : typeof value == "bigint" ? { [SERIALIZED_BIGINT]: value.toString() } : value;
|
||||
}
|
||||
function tailEventsReviver(_, value) {
|
||||
if (value && typeof value == "object") {
|
||||
if (SERIALIZED_DATE in value)
|
||||
return new Date(value[SERIALIZED_DATE]);
|
||||
if (SERIALIZED_BIGINT in value)
|
||||
return BigInt(value[SERIALIZED_BIGINT]);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
// src/workers/core/dev-registry-proxy.worker.ts
|
||||
var HANDLER_RESERVED_KEYS = /* @__PURE__ */ new Set([
|
||||
"alarm",
|
||||
"connect",
|
||||
"self",
|
||||
"tail",
|
||||
"tailStream",
|
||||
"test",
|
||||
"trace",
|
||||
"webSocketClose",
|
||||
"webSocketError",
|
||||
"webSocketMessage"
|
||||
]);
|
||||
function resolve(props, env) {
|
||||
let { service, entrypoint, userProps } = props, target = resolveTarget(service);
|
||||
if (!target || !target.debugPortAddress)
|
||||
return null;
|
||||
let serviceName = entrypoint === null || entrypoint === "default" ? target.defaultEntrypointService : target.userWorkerService;
|
||||
return env.DEV_REGISTRY_DEBUG_PORT.connect(target.debugPortAddress).getEntrypoint(serviceName, entrypoint ?? void 0, userProps);
|
||||
}
|
||||
var ExternalQueueProxy = class extends WorkerEntrypoint {
|
||||
fetch(request) {
|
||||
let queueName = request.headers.get(HEADER_QUEUE_NAME);
|
||||
if (queueName === null)
|
||||
return new Response(`Missing "${HEADER_QUEUE_NAME}" header`, {
|
||||
status: 400
|
||||
});
|
||||
let target = findQueueConsumer(queueName);
|
||||
if (target === void 0)
|
||||
return new Response(
|
||||
`No Worker consuming queue "${queueName}" found in the local dev registry. Make sure the consumer Worker is running locally.`,
|
||||
{ status: 503 }
|
||||
);
|
||||
let broker = this.env.DEV_REGISTRY_DEBUG_PORT.connect(
|
||||
target.debugPortAddress
|
||||
).getEntrypoint(getQueueServiceName(queueName)), headers = new Headers(request.headers);
|
||||
return headers.delete(HEADER_QUEUE_NAME), broker.fetch(new Request(request, { headers }));
|
||||
}
|
||||
}, ExternalServiceProxy = class extends WorkerEntrypoint {
|
||||
_fetcher = null;
|
||||
_entryFetcher = null;
|
||||
constructor(ctx, env) {
|
||||
super(ctx, env), this._fetcher = resolve(ctx.props, env);
|
||||
let target = resolveTarget(ctx.props.service);
|
||||
if (target && target.debugPortAddress) {
|
||||
let client = env.DEV_REGISTRY_DEBUG_PORT.connect(
|
||||
target.debugPortAddress
|
||||
);
|
||||
this._entryFetcher = client.getEntrypoint("core:entry");
|
||||
}
|
||||
return new Proxy(this, {
|
||||
get(target2, prop) {
|
||||
if (Reflect.has(target2, prop))
|
||||
return Reflect.get(target2, prop);
|
||||
if (!(typeof prop == "string" && HANDLER_RESERVED_KEYS.has(prop))) {
|
||||
if (!target2._fetcher)
|
||||
throw new Error(workerNotFoundMessage(ctx.props.service));
|
||||
return Reflect.get(target2._fetcher, prop);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
fetch(request) {
|
||||
return this._fetcher ? this._fetcher.fetch(request) : new Response(workerNotFoundMessage(this.ctx.props.service), {
|
||||
status: 503
|
||||
});
|
||||
}
|
||||
async scheduled(controller) {
|
||||
if (!this._entryFetcher)
|
||||
throw new Error(workerNotFoundMessage(this.ctx.props.service));
|
||||
let params = new URLSearchParams();
|
||||
controller.cron && params.set("cron", controller.cron), controller.scheduledTime && params.set("time", String(controller.scheduledTime));
|
||||
let response = await this._entryFetcher.fetch(
|
||||
new Request(`http://localhost/cdn-cgi/handler/scheduled?${params}`, {
|
||||
headers: { "MF-Route-Override": this.ctx.props.service }
|
||||
})
|
||||
);
|
||||
if (!response.ok) {
|
||||
let body = await response.text();
|
||||
throw new Error(
|
||||
`Scheduled handler returned HTTP ${response.status}: ${body}`
|
||||
);
|
||||
}
|
||||
}
|
||||
// Forward tail events to the remote worker via RPC.
|
||||
// Events with rpcMethod==="tail" are filtered out to prevent infinite
|
||||
// recursion (the remote tail() call would itself produce a tail event).
|
||||
tail(events) {
|
||||
if (!this._fetcher)
|
||||
return;
|
||||
let filtered = events.filter(
|
||||
(e) => e.event?.rpcMethod !== "tail"
|
||||
);
|
||||
if (filtered.length !== 0)
|
||||
try {
|
||||
let serializedEvents = JSON.parse(
|
||||
JSON.stringify(filtered, tailEventsReplacer),
|
||||
tailEventsReviver
|
||||
);
|
||||
return this._fetcher.tail(serializedEvents);
|
||||
} catch (e) {
|
||||
console.warn(
|
||||
`[dev-registry] Failed to forward tail events to "${this.ctx.props.service}": ${e instanceof Error ? e.message : String(e)}`
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
export {
|
||||
ExternalQueueProxy,
|
||||
ExternalServiceProxy,
|
||||
createProxyDurableObjectClass,
|
||||
setRegistry
|
||||
};
|
||||
//# sourceMappingURL=dev-registry-proxy.worker.js.map
|
||||
+7
File diff suppressed because one or more lines are too long
+67
@@ -0,0 +1,67 @@
|
||||
// src/plugins/core/constants.ts
|
||||
var CORE_PLUGIN_NAME = "core", SERVICE_ENTRY = `${CORE_PLUGIN_NAME}:entry`, SERVICE_LOCAL_EXPLORER = `${CORE_PLUGIN_NAME}:local-explorer`, LOCAL_EXPLORER_DISK = `${CORE_PLUGIN_NAME}:local-explorer-disk`, SERVICE_USER_PREFIX = `${CORE_PLUGIN_NAME}:user`, SERVICE_BUILTIN_PREFIX = `${CORE_PLUGIN_NAME}:builtin`, SERVICE_CUSTOM_FETCH_PREFIX = `${CORE_PLUGIN_NAME}:custom-fetch`, SERVICE_CUSTOM_NODE_PREFIX = `${CORE_PLUGIN_NAME}:custom-node`;
|
||||
var INTROSPECT_SQLITE_METHOD = "__miniflare_introspectSqlite", GET_DO_NAME_METHOD = "__miniflare_getDOName";
|
||||
|
||||
// src/workers/core/do-wrapper.worker.ts
|
||||
function createDurableObjectWrapper(UserClass) {
|
||||
class Wrapper extends UserClass {
|
||||
constructor(ctx, env) {
|
||||
super(ctx, env), ctx.id.name !== void 0 && ctx.blockConcurrencyWhile(async () => {
|
||||
let sql = ctx.storage.sql;
|
||||
sql && (sql.exec(
|
||||
"CREATE TABLE IF NOT EXISTS __miniflare_do_name (id INTEGER PRIMARY KEY, name TEXT)"
|
||||
), sql.exec(
|
||||
"INSERT OR REPLACE INTO __miniflare_do_name (id, name) VALUES (1, ?)",
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- guarded by outer if
|
||||
ctx.id.name
|
||||
));
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Returns the DO instance name from ctx.id.name if available:
|
||||
*/
|
||||
[GET_DO_NAME_METHOD]() {
|
||||
if (this.ctx.id.name !== void 0)
|
||||
return this.ctx.id.name;
|
||||
let sql = this.ctx.storage.sql;
|
||||
if (sql)
|
||||
try {
|
||||
let row = sql.exec("SELECT name FROM __miniflare_do_name WHERE id = 1").one();
|
||||
if (typeof row?.name == "string")
|
||||
return row.name;
|
||||
} catch {
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Execute SQL queries against the DO's SQLite storage.
|
||||
* If multiple queries are provided, they run in a transaction.
|
||||
*/
|
||||
[INTROSPECT_SQLITE_METHOD](queries) {
|
||||
let sql = this.ctx.storage.sql;
|
||||
if (!sql)
|
||||
throw new Error(
|
||||
"This Durable Object does not have SQLite storage enabled"
|
||||
);
|
||||
let executeQuery = (query) => {
|
||||
let cursor = sql.exec(query.sql, ...query.params ?? []);
|
||||
return {
|
||||
columns: cursor.columnNames,
|
||||
rows: Array.from(cursor.raw()),
|
||||
meta: {
|
||||
rows_read: cursor.rowsRead,
|
||||
rows_written: cursor.rowsWritten
|
||||
}
|
||||
};
|
||||
}, results = [];
|
||||
return queries.length > 1 ? this.ctx.storage.transactionSync(() => {
|
||||
for (let query of queries)
|
||||
results.push(executeQuery(query));
|
||||
}) : results.push(executeQuery(queries[0])), results;
|
||||
}
|
||||
}
|
||||
return Object.defineProperty(Wrapper, "name", { value: UserClass.name }), Wrapper;
|
||||
}
|
||||
export {
|
||||
createDurableObjectWrapper
|
||||
};
|
||||
//# sourceMappingURL=do-wrapper.worker.js.map
|
||||
+7
File diff suppressed because one or more lines are too long
+4698
File diff suppressed because it is too large
Load Diff
+7
File diff suppressed because one or more lines are too long
+122
@@ -0,0 +1,122 @@
|
||||
// src/workers/core/outbound.worker.ts
|
||||
import { LogLevel, SharedHeaders } from "miniflare:shared";
|
||||
|
||||
// src/workers/core/constants.ts
|
||||
var CoreHeaders = {
|
||||
CUSTOM_FETCH_SERVICE: "MF-Custom-Fetch-Service",
|
||||
CUSTOM_NODE_SERVICE: "MF-Custom-Node-Service",
|
||||
ORIGINAL_URL: "MF-Original-URL",
|
||||
/**
|
||||
* Stores the original hostname when using the `upstream` option.
|
||||
* When requests are proxied to an upstream, the `Host` header is rewritten
|
||||
* to match the upstream. This header preserves the original hostname
|
||||
* so Workers can access it if needed.
|
||||
*/
|
||||
ORIGINAL_HOSTNAME: "MF-Original-Hostname",
|
||||
PROXY_SHARED_SECRET: "MF-Proxy-Shared-Secret",
|
||||
DISABLE_PRETTY_ERROR: "MF-Disable-Pretty-Error",
|
||||
ERROR_STACK: "MF-Experimental-Error-Stack",
|
||||
ROUTE_OVERRIDE: "MF-Route-Override",
|
||||
CF_BLOB: "MF-CF-Blob",
|
||||
/** Used by the Vite plugin to pass through the original `sec-fetch-mode` header */
|
||||
SEC_FETCH_MODE: "MF-Sec-Fetch-Mode",
|
||||
// API Proxy
|
||||
OP_SECRET: "MF-Op-Secret",
|
||||
OP: "MF-Op",
|
||||
OP_TARGET: "MF-Op-Target",
|
||||
OP_KEY: "MF-Op-Key",
|
||||
OP_SYNC: "MF-Op-Sync",
|
||||
OP_STRINGIFIED_SIZE: "MF-Op-Stringified-Size",
|
||||
OP_RESULT_TYPE: "MF-Op-Result-Type",
|
||||
OP_ORIGINAL_URL: "MF-Op-Original-URL"
|
||||
}, CoreBindings = {
|
||||
SERVICE_LOOPBACK: "MINIFLARE_LOOPBACK",
|
||||
SERVICE_USER_ROUTE_PREFIX: "MINIFLARE_USER_ROUTE_",
|
||||
SERVICE_USER_FALLBACK: "MINIFLARE_USER_FALLBACK",
|
||||
TEXT_CUSTOM_SERVICE: "MINIFLARE_CUSTOM_SERVICE",
|
||||
// Backs the Images binding (`env.IMAGES`) — see imagesLocalFetcher.
|
||||
IMAGES_BINDING_SERVICE: "MINIFLARE_IMAGES_BINDING_SERVICE",
|
||||
// Backs `fetch(url, { cf: { image } })` transforms — see cfImageLocalFetcher.
|
||||
IMAGES_FETCH_SERVICE: "MINIFLARE_IMAGES_FETCH_SERVICE",
|
||||
TEXT_UPSTREAM_URL: "MINIFLARE_UPSTREAM_URL",
|
||||
JSON_CF_BLOB: "CF_BLOB",
|
||||
JSON_ROUTES: "MINIFLARE_ROUTES",
|
||||
JSON_LOG_LEVEL: "MINIFLARE_LOG_LEVEL",
|
||||
DATA_LIVE_RELOAD_SCRIPT: "MINIFLARE_LIVE_RELOAD_SCRIPT",
|
||||
DURABLE_OBJECT_NAMESPACE_PROXY: "MINIFLARE_PROXY",
|
||||
DATA_PROXY_SECRET: "MINIFLARE_PROXY_SECRET",
|
||||
DATA_PROXY_SHARED_SECRET: "MINIFLARE_PROXY_SHARED_SECRET",
|
||||
TRIGGER_HANDLERS: "TRIGGER_HANDLERS",
|
||||
LOG_REQUESTS: "LOG_REQUESTS",
|
||||
STRIP_DISABLE_PRETTY_ERROR: "STRIP_DISABLE_PRETTY_ERROR",
|
||||
SERVICE_LOCAL_EXPLORER: "MINIFLARE_LOCAL_EXPLORER",
|
||||
EXPLORER_DISK: "MINIFLARE_EXPLORER_DISK",
|
||||
JSON_LOCAL_EXPLORER_BINDING_MAP: "LOCAL_EXPLORER_BINDING_MAP",
|
||||
JSON_LOCAL_EXPLORER_WORKER_NAMES: "LOCAL_EXPLORER_WORKER_NAMES",
|
||||
JSON_EXPLORER_WORKER_OPTS: "MINIFLARE_EXPLORER_WORKER_OPTS",
|
||||
SERVICE_CACHE: "MINIFLARE_CACHE",
|
||||
SERVICE_DEV_REGISTRY_PROXY: "MINIFLARE_DEV_REGISTRY_PROXY",
|
||||
JSON_TELEMETRY_CONFIG: "MINIFLARE_TELEMETRY_CONFIG",
|
||||
DEV_REGISTRY_DEBUG_PORT: "DEV_REGISTRY_DEBUG_PORT",
|
||||
SERVICE_STREAM: "MINIFLARE_STREAM",
|
||||
SERVICE_IMAGES_DELIVERY: "MINIFLARE_IMAGES_DELIVERY",
|
||||
SERVICE_R2_PUBLIC: "MINIFLARE_R2_PUBLIC"
|
||||
};
|
||||
|
||||
// src/workers/core/outbound.worker.ts
|
||||
var RESIZING_VIA_TOKEN = "image-resizing", warnedLowFidelity = !1, outbound_worker_default = {
|
||||
async fetch(request, env) {
|
||||
let image = request.cf?.image;
|
||||
if (!(image != null && typeof image == "object" && Object.keys(image).length > 0)) {
|
||||
let headers = strippedHeaders(request, env);
|
||||
return headers ? fetch(request, { headers }) : fetch(request);
|
||||
}
|
||||
return resizeImage(request, env, image);
|
||||
}
|
||||
};
|
||||
function strippedHeaders(request, env) {
|
||||
if (!env.STRIP_CF_CONNECTING_IP)
|
||||
return;
|
||||
let headers = new Headers(request.headers);
|
||||
return headers.delete("CF-Connecting-IP"), headers.set("CF-Worker", env.CF_WORKER_ZONE), headers;
|
||||
}
|
||||
async function resizeImage(request, env, image) {
|
||||
let headers = strippedHeaders(request, env) ?? new Headers(request.headers), via = headers.get("via");
|
||||
headers.set(
|
||||
"via",
|
||||
via ? `${via}, ${RESIZING_VIA_TOKEN}` : RESIZING_VIA_TOKEN
|
||||
);
|
||||
let originResponse = await fetch(request, { headers });
|
||||
if (!originResponse.ok)
|
||||
return originResponse;
|
||||
let source = await originResponse.arrayBuffer(), form = new FormData();
|
||||
form.append("image", new Blob([source])), form.append("options", JSON.stringify(image));
|
||||
let transformRequest = new Request("http://localhost/cf-image", {
|
||||
method: "POST",
|
||||
body: form
|
||||
});
|
||||
transformRequest.headers.set(
|
||||
CoreHeaders.CUSTOM_FETCH_SERVICE,
|
||||
CoreBindings.IMAGES_FETCH_SERVICE
|
||||
);
|
||||
let transformed = await env[CoreBindings.SERVICE_LOOPBACK].fetch(transformRequest);
|
||||
if (!transformed.ok) {
|
||||
let headers2 = new Headers(originResponse.headers);
|
||||
return headers2.delete("content-encoding"), headers2.delete("content-length"), new Response(source, {
|
||||
status: originResponse.status,
|
||||
headers: headers2
|
||||
});
|
||||
}
|
||||
return await warnLowFidelityOnce(env), transformed;
|
||||
}
|
||||
async function warnLowFidelityOnce(env) {
|
||||
warnedLowFidelity || (warnedLowFidelity = !0, await env[CoreBindings.SERVICE_LOOPBACK].fetch("http://localhost/core/log", {
|
||||
method: "POST",
|
||||
headers: { [SharedHeaders.LOG_LEVEL]: LogLevel.WARN.toString() },
|
||||
body: "Local cf.image transforms are a low-fidelity mock; only resize, rotate and format conversion are applied. Deploy to preview the full transformation."
|
||||
}));
|
||||
}
|
||||
export {
|
||||
outbound_worker_default as default
|
||||
};
|
||||
//# sourceMappingURL=outbound.worker.js.map
|
||||
+7
File diff suppressed because one or more lines are too long
+224
@@ -0,0 +1,224 @@
|
||||
var __defProp = Object.defineProperty;
|
||||
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
||||
var __decorateClass = (decorators, target, key, kind) => {
|
||||
for (var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target, i = decorators.length - 1, decorator; i >= 0; i--)
|
||||
(decorator = decorators[i]) && (result = (kind ? decorator(target, key, result) : decorator(result)) || result);
|
||||
return kind && result && __defProp(target, key, result), result;
|
||||
};
|
||||
|
||||
// src/workers/d1/database.worker.ts
|
||||
import assert from "node:assert";
|
||||
import {
|
||||
get,
|
||||
HttpError,
|
||||
MiniflareDurableObject,
|
||||
POST,
|
||||
viewToBuffer
|
||||
} from "miniflare:shared";
|
||||
import { z } from "miniflare:zod";
|
||||
|
||||
// src/workers/d1/dumpSql.ts
|
||||
function* dumpSql(db, options, stats) {
|
||||
yield "PRAGMA defer_foreign_keys=TRUE;";
|
||||
let filterTables = new Set(options?.tables || []), { noData, noSchema } = options || {}, tables_cursor = db.prepare(`
|
||||
SELECT name, type, sql
|
||||
FROM sqlite_schema AS o
|
||||
WHERE (true) AND type=='table'
|
||||
AND sql NOT NULL
|
||||
ORDER BY tbl_name='sqlite_sequence', rowid;
|
||||
`)(), tables = Array.from(tables_cursor);
|
||||
stats && (stats.rows_read += tables_cursor.rowsRead, stats.rows_written += tables_cursor.rowsWritten);
|
||||
for (let { name: table, sql } of tables) {
|
||||
if (filterTables.size > 0 && !filterTables.has(table)) continue;
|
||||
if (table === "sqlite_sequence")
|
||||
noSchema || (yield "DELETE FROM sqlite_sequence;");
|
||||
else if (table.match(/^sqlite_stat./))
|
||||
noSchema || (yield "ANALYZE sqlite_schema;");
|
||||
else {
|
||||
if (sql.startsWith("CREATE VIRTUAL TABLE"))
|
||||
throw new Error(
|
||||
"D1 Export error: cannot export databases with Virtual Tables (fts5)"
|
||||
);
|
||||
if (table.startsWith("_cf_") || table.startsWith("sqlite_"))
|
||||
continue;
|
||||
sql.match(/CREATE TABLE ['"].*/) ? noSchema || (yield `CREATE TABLE IF NOT EXISTS ${sql.substring(13)};`) : noSchema || (yield `${sql};`);
|
||||
}
|
||||
if (noData) continue;
|
||||
let columns_cursor = db.exec(`PRAGMA table_info=${escapeId(table)}`), columns = Array.from(columns_cursor);
|
||||
stats && (stats.rows_read += columns_cursor.rowsRead, stats.rows_written += columns_cursor.rowsWritten);
|
||||
let select = `SELECT ${columns.map((c) => escapeId(c.name)).join(", ")} FROM ${escapeId(table)};`, rows_cursor = db.exec(select), columnNames = columns.map((c) => escapeId(c.name)).join(","), columnNamesOverhead = 3 + columnNames.length;
|
||||
for (let dataRow of rows_cursor.raw()) {
|
||||
let formattedCells = dataRow.map((cell, i) => {
|
||||
let colType = columns[i].type, cellType = typeof cell;
|
||||
return cell === null ? "NULL" : cellType === "number" ? cell : cellType === "string" ? outputQuotedEscapedString(cell) : cell instanceof ArrayBuffer ? `X'${Array.prototype.map.call(new Uint8Array(cell), (b) => b.toString(16).padStart(2, "0")).join("")}'` : (console.error({
|
||||
message: "dumpSql: unexpected cell type",
|
||||
colType,
|
||||
cellType,
|
||||
cell,
|
||||
column: columns[i]
|
||||
}), "ERROR");
|
||||
}), insertStmt = `INSERT INTO ${escapeId(table)} (${columnNames}) VALUES(${formattedCells.join(",")});`;
|
||||
if (stats) {
|
||||
let currentSize = insertStmt.length, sizeWithoutColumnNames = currentSize - columnNamesOverhead, LIMIT = 100 * 1024;
|
||||
stats.total_inserts++, sizeWithoutColumnNames > LIMIT && stats.inserts_already_over_100kb++, currentSize > LIMIT && stats.inserts_over_100kb_with_column_names++, sizeWithoutColumnNames > stats.max_insert_size && (stats.max_insert_size = sizeWithoutColumnNames), currentSize > stats.max_insert_size_with_column_names && (stats.max_insert_size_with_column_names = currentSize);
|
||||
}
|
||||
yield insertStmt;
|
||||
}
|
||||
stats && (stats.rows_read += rows_cursor.rowsRead, stats.rows_written += rows_cursor.rowsWritten);
|
||||
}
|
||||
if (!noSchema) {
|
||||
let rest_of_schema = db.exec(
|
||||
[
|
||||
"SELECT name, sql",
|
||||
"FROM sqlite_schema AS o",
|
||||
"WHERE (true) AND sql NOT NULL",
|
||||
" AND type IN ('index', 'trigger', 'view')",
|
||||
// 'DESC' appears in the code linked above but the observed behaviour of SQLite appears otherwise
|
||||
"ORDER BY type COLLATE NOCASE"
|
||||
].join(" ")
|
||||
);
|
||||
for (let { name, sql } of rest_of_schema)
|
||||
filterTables.size > 0 && !filterTables.has(name) || (yield `${sql};`);
|
||||
stats && (stats.rows_read += rest_of_schema.rowsRead, stats.rows_written += rest_of_schema.rowsWritten);
|
||||
}
|
||||
}
|
||||
function outputQuotedEscapedString(cell) {
|
||||
let lfs = !1, crs = !1, quotesOrNewlinesRegexp = /'|(\n)|(\r)/g, escapeQuotesDetectingNewlines = (_, lf, cr) => lf ? (lfs = !0, "\\n") : cr ? (crs = !0, "\\r") : "''", output_string = `'${cell.replace(
|
||||
quotesOrNewlinesRegexp,
|
||||
escapeQuotesDetectingNewlines
|
||||
)}'`;
|
||||
return crs && (output_string = `replace(${output_string},'\\r',char(13))`), lfs && (output_string = `replace(${output_string},'\\n',char(10))`), output_string;
|
||||
}
|
||||
function escapeId(id) {
|
||||
return `"${id.replace(/"/g, '""')}"`;
|
||||
}
|
||||
|
||||
// src/workers/d1/database.worker.ts
|
||||
var D1ValueSchema = z.union([
|
||||
z.number(),
|
||||
z.string(),
|
||||
z.null(),
|
||||
z.number().array()
|
||||
]), D1QuerySchema = z.object({
|
||||
sql: z.string(),
|
||||
params: z.array(D1ValueSchema).nullable().optional()
|
||||
}), D1QueriesSchema = z.union([D1QuerySchema, z.array(D1QuerySchema)]), D1_EXPORT_PRAGMA = "PRAGMA miniflare_d1_export(?,?,?);", D1ResultsFormatSchema = z.enum(["ARRAY_OF_OBJECTS", "ROWS_AND_COLUMNS", "NONE"]).catch("ARRAY_OF_OBJECTS"), served_by = "miniflare.db", D1_SESSION_COMMIT_TOKEN_HTTP_HEADER = "x-cf-d1-session-commit-token", D1Error = class extends HttpError {
|
||||
constructor(cause) {
|
||||
super(500);
|
||||
this.cause = cause;
|
||||
}
|
||||
cause;
|
||||
toResponse() {
|
||||
let response = { success: !1, error: typeof this.cause == "object" && this.cause !== null && "message" in this.cause && typeof this.cause.message == "string" ? this.cause.message : String(this.cause) };
|
||||
return Response.json(response);
|
||||
}
|
||||
};
|
||||
function convertParams(params) {
|
||||
return (params ?? []).map(
|
||||
(param) => (
|
||||
// If `param` is an array, assume it's a byte array
|
||||
Array.isArray(param) ? viewToBuffer(new Uint8Array(param)) : param
|
||||
)
|
||||
);
|
||||
}
|
||||
function convertRows(rows) {
|
||||
return rows.map(
|
||||
(row) => row.map((value) => {
|
||||
let normalised;
|
||||
return value instanceof ArrayBuffer ? normalised = Array.from(new Uint8Array(value)) : normalised = value, normalised;
|
||||
})
|
||||
);
|
||||
}
|
||||
function rowsToObjects(columns, rows) {
|
||||
return rows.map(
|
||||
(row) => Object.fromEntries(columns.map((name, i) => [name, row[i]]))
|
||||
);
|
||||
}
|
||||
function sqlStmts(db) {
|
||||
return {
|
||||
getChanges: db.prepare(
|
||||
"SELECT total_changes() AS totalChanges, last_insert_rowid() AS lastRowId"
|
||||
)
|
||||
};
|
||||
}
|
||||
var D1DatabaseObject = class extends MiniflareDurableObject {
|
||||
#stmts;
|
||||
constructor(state, env) {
|
||||
super(state, env), this.#stmts = sqlStmts(this.db);
|
||||
}
|
||||
#changes() {
|
||||
let changes = get(this.#stmts.getChanges());
|
||||
return assert(changes !== void 0), changes;
|
||||
}
|
||||
#query = (format, query) => {
|
||||
let beforeTime = performance.now(), beforeSize = this.state.storage.sql.databaseSize, beforeChanges = this.#changes(), params = convertParams(query.params ?? []), cursor = this.db.prepare(query.sql)(...params), columns = cursor.columnNames, rows = convertRows(Array.from(cursor.raw())), results;
|
||||
format === "ROWS_AND_COLUMNS" ? results = { columns, rows } : results = rowsToObjects(columns, rows);
|
||||
let afterTime = performance.now(), afterSize = this.state.storage.sql.databaseSize, afterChanges = this.#changes(), duration = afterTime - beforeTime, changes = afterChanges.totalChanges - beforeChanges.totalChanges, hasChanges = changes !== 0, lastRowChanged = afterChanges.lastRowId !== beforeChanges.lastRowId, changed = hasChanges || lastRowChanged || afterSize !== beforeSize;
|
||||
return {
|
||||
success: !0,
|
||||
results,
|
||||
meta: {
|
||||
served_by,
|
||||
duration,
|
||||
changes,
|
||||
last_row_id: afterChanges.lastRowId,
|
||||
changed_db: changed,
|
||||
size_after: afterSize,
|
||||
rows_read: cursor.rowsRead,
|
||||
rows_written: cursor.rowsWritten
|
||||
}
|
||||
};
|
||||
};
|
||||
#txn(queries, format) {
|
||||
if (queries = queries.filter(
|
||||
(query) => query.sql.replace(/^\s+--.*/gm, "").trim().length > 0
|
||||
), queries.length === 0) {
|
||||
let error = new Error("No SQL statements detected.");
|
||||
throw new D1Error(error);
|
||||
}
|
||||
try {
|
||||
return this.state.storage.transactionSync(
|
||||
() => queries.map(this.#query.bind(this, format))
|
||||
);
|
||||
} catch (e) {
|
||||
throw new D1Error(e);
|
||||
}
|
||||
}
|
||||
queryExecute = async (req) => {
|
||||
let queries = D1QueriesSchema.parse(await req.json());
|
||||
if (Array.isArray(queries) || (queries = [queries]), this.#isExportPragma(queries))
|
||||
return this.#doExportData(queries);
|
||||
let { searchParams } = new URL(req.url), resultsFormat = D1ResultsFormatSchema.parse(
|
||||
searchParams.get("resultsFormat")
|
||||
);
|
||||
return Response.json(this.#txn(queries, resultsFormat), {
|
||||
headers: {
|
||||
[D1_SESSION_COMMIT_TOKEN_HTTP_HEADER]: await this.state.storage.getCurrentBookmark()
|
||||
}
|
||||
});
|
||||
};
|
||||
#isExportPragma(queries) {
|
||||
return queries.length === 1 && queries[0].sql === D1_EXPORT_PRAGMA && (queries[0].params?.length || 0) >= 2;
|
||||
}
|
||||
#doExportData(queries) {
|
||||
let [noSchema, noData, ...tables] = queries[0].params, options = {
|
||||
noSchema: !!noSchema,
|
||||
noData: !!noData,
|
||||
tables
|
||||
};
|
||||
return Response.json({
|
||||
success: !0,
|
||||
results: [Array.from(dumpSql(this.state.storage.sql, options))],
|
||||
meta: {}
|
||||
});
|
||||
}
|
||||
};
|
||||
__decorateClass([
|
||||
POST("/query"),
|
||||
POST("/execute")
|
||||
], D1DatabaseObject.prototype, "queryExecute", 2);
|
||||
export {
|
||||
D1DatabaseObject,
|
||||
D1Error
|
||||
};
|
||||
//# sourceMappingURL=database.worker.js.map
|
||||
+7
File diff suppressed because one or more lines are too long
Generated
Vendored
+2332
File diff suppressed because it is too large
Load Diff
Generated
Vendored
+7
File diff suppressed because one or more lines are too long
Generated
Vendored
+12
@@ -0,0 +1,12 @@
|
||||
// src/workers/dispatch-namespace/dispatch-namespace.worker.ts
|
||||
function dispatch_namespace_worker_default(env) {
|
||||
return {
|
||||
get(name, args, options) {
|
||||
return env.proxyClient.get(name, args, options);
|
||||
}
|
||||
};
|
||||
}
|
||||
export {
|
||||
dispatch_namespace_worker_default as default
|
||||
};
|
||||
//# sourceMappingURL=dispatch-namespace.worker.js.map
|
||||
Generated
Vendored
+7
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"version": 3,
|
||||
"sources": ["../../../../src/workers/dispatch-namespace/dispatch-namespace.worker.ts"],
|
||||
"sourcesContent": ["/**\n * Wrapped binding extension for dispatch namespaces.\n *\n * Delegates to {@link DispatchNamespaceProxy} via a service binding.\n */\n\ninterface Env {\n\tproxyClient: DispatchNamespace;\n}\n\nexport default function (env: Env): DispatchNamespace {\n\treturn {\n\t\tget(\n\t\t\tname: string,\n\t\t\targs?: { [key: string]: unknown },\n\t\t\toptions?: DynamicDispatchOptions\n\t\t): Fetcher {\n\t\t\treturn env.proxyClient.get(name, args, options);\n\t\t},\n\t} satisfies DispatchNamespace;\n}\n"],
|
||||
"mappings": ";AAUe,SAAR,kCAAkB,KAA6B;AACrD,SAAO;AAAA,IACN,IACC,MACA,MACA,SACU;AACV,aAAO,IAAI,YAAY,IAAI,MAAM,MAAM,OAAO;AAAA,IAC/C;AAAA,EACD;AACD;",
|
||||
"names": []
|
||||
}
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
// src/workers/email/constants.ts
|
||||
var RAW_EMAIL = "EmailMessage::raw";
|
||||
|
||||
// src/workers/email/email.worker.ts
|
||||
var EmailMessage = class {
|
||||
constructor(from, to, raw) {
|
||||
this.from = from;
|
||||
this.to = to;
|
||||
this.raw = raw;
|
||||
return {
|
||||
from,
|
||||
to,
|
||||
// @ts-expect-error We need to be able to access the raw contents of an EmailMessage in entry.worker.ts
|
||||
[RAW_EMAIL]: raw
|
||||
};
|
||||
}
|
||||
from;
|
||||
to;
|
||||
raw;
|
||||
}, email_worker_default = {
|
||||
EmailMessage
|
||||
};
|
||||
export {
|
||||
email_worker_default as default
|
||||
};
|
||||
//# sourceMappingURL=email.worker.js.map
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"version": 3,
|
||||
"sources": ["../../../../src/workers/email/constants.ts", "../../../../src/workers/email/email.worker.ts"],
|
||||
"sourcesContent": ["export const RAW_EMAIL = \"EmailMessage::raw\";\n", "import { RAW_EMAIL } from \"./constants\";\nimport type { EmailMessage as EmailMessageType } from \"@cloudflare/workers-types/experimental\";\n\n// This type is the _actual_ type of an EmailMessage when running locally, which is different to production\n// Refer to the below constructor for more details about why\nexport type MiniflareEmailMessage = {\n\tfrom: string;\n\tto: string;\n\t[RAW_EMAIL]: ReadableStream<Uint8Array>;\n};\n\nclass EmailMessage implements EmailMessageType {\n\tpublic constructor(\n\t\tpublic readonly from: string,\n\t\tpublic readonly to: string,\n\t\tprivate raw: ReadableStream | string\n\t) {\n\t\t// @ts-expect-error This is a bit of hack! We need:\n\t\t// - EmailMessage to be constructable (to match production)\n\t\t// - EmailMessage to be able to be passed across JSRPC (to support e.g. message.reply(EmailMessage))\n\t\t// - EmailMessage properties to be synchronously available (to match production). This rules out `RpcStub`\n\t\t// The below is the only solution I could some up with that satisfies these constraints, but if the constraints change\n\t\t// this can and should be re-evaluated\n\t\treturn {\n\t\t\tfrom,\n\t\t\tto,\n\t\t\t// @ts-expect-error We need to be able to access the raw contents of an EmailMessage in entry.worker.ts\n\t\t\t[RAW_EMAIL]: raw,\n\t\t};\n\t}\n}\nexport default {\n\tEmailMessage,\n};\n"],
|
||||
"mappings": ";AAAO,IAAM,YAAY;;;ACWzB,IAAM,eAAN,MAA+C;AAAA,EACvC,YACU,MACA,IACR,KACP;AAHe;AACA;AACR;AAQR,WAAO;AAAA,MACN;AAAA,MACA;AAAA;AAAA,MAEA,CAAC,SAAS,GAAG;AAAA,IACd;AAAA,EACD;AAAA,EAhBiB;AAAA,EACA;AAAA,EACR;AAeV,GACO,uBAAQ;AAAA,EACd;AACD;",
|
||||
"names": []
|
||||
}
|
||||
+3269
File diff suppressed because it is too large
Load Diff
+7
File diff suppressed because one or more lines are too long
+19
@@ -0,0 +1,19 @@
|
||||
// src/workers/hello-world/binding.worker.ts
|
||||
import { WorkerEntrypoint } from "cloudflare:workers";
|
||||
var HelloWorldBinding = class extends WorkerEntrypoint {
|
||||
async get() {
|
||||
let objectNamespace = this.env.store, namespaceId = JSON.stringify(this.env.config), id = objectNamespace.idFromName(namespaceId);
|
||||
return {
|
||||
value: await objectNamespace.get(id).get() ?? "",
|
||||
ms: this.env.config.enable_timer ? 100 : void 0
|
||||
};
|
||||
}
|
||||
async set(value) {
|
||||
let objectNamespace = this.env.store, namespaceId = JSON.stringify(this.env.config), id = objectNamespace.idFromName(namespaceId);
|
||||
await objectNamespace.get(id).set(value);
|
||||
}
|
||||
};
|
||||
export {
|
||||
HelloWorldBinding
|
||||
};
|
||||
//# sourceMappingURL=binding.worker.js.map
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"version": 3,
|
||||
"sources": ["../../../../src/workers/hello-world/binding.worker.ts"],
|
||||
"sourcesContent": ["// Emulated Hello World Binding\n\nimport { WorkerEntrypoint } from \"cloudflare:workers\";\nimport type { HelloWorldObject } from \"./object.worker\";\n\n// ENV configuration\ninterface Env {\n\tconfig: { enable_timer?: boolean };\n\tstore: DurableObjectNamespace<HelloWorldObject>;\n}\n\nexport class HelloWorldBinding extends WorkerEntrypoint<Env> {\n\tasync get(): Promise<{ value: string; ms?: number }> {\n\t\tconst objectNamespace = this.env.store;\n\t\tconst namespaceId = JSON.stringify(this.env.config);\n\t\tconst id = objectNamespace.idFromName(namespaceId);\n\t\tconst stub = objectNamespace.get(id);\n\t\tconst value = await stub.get();\n\t\treturn {\n\t\t\tvalue: value ?? \"\",\n\t\t\tms: this.env.config.enable_timer ? 100 : undefined,\n\t\t};\n\t}\n\n\tasync set(value: string): Promise<void> {\n\t\tconst objectNamespace = this.env.store;\n\t\tconst namespaceId = JSON.stringify(this.env.config);\n\t\tconst id = objectNamespace.idFromName(namespaceId);\n\t\tconst stub = objectNamespace.get(id);\n\t\tawait stub.set(value);\n\t}\n}\n"],
|
||||
"mappings": ";AAEA,SAAS,wBAAwB;AAS1B,IAAM,oBAAN,cAAgC,iBAAsB;AAAA,EAC5D,MAAM,MAA+C;AACpD,QAAM,kBAAkB,KAAK,IAAI,OAC3B,cAAc,KAAK,UAAU,KAAK,IAAI,MAAM,GAC5C,KAAK,gBAAgB,WAAW,WAAW;AAGjD,WAAO;AAAA,MACN,OAFa,MADD,gBAAgB,IAAI,EAAE,EACV,IAAI,KAEZ;AAAA,MAChB,IAAI,KAAK,IAAI,OAAO,eAAe,MAAM;AAAA,IAC1C;AAAA,EACD;AAAA,EAEA,MAAM,IAAI,OAA8B;AACvC,QAAM,kBAAkB,KAAK,IAAI,OAC3B,cAAc,KAAK,UAAU,KAAK,IAAI,MAAM,GAC5C,KAAK,gBAAgB,WAAW,WAAW;AAEjD,UADa,gBAAgB,IAAI,EAAE,EACxB,IAAI,KAAK;AAAA,EACrB;AACD;",
|
||||
"names": []
|
||||
}
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
// src/workers/hello-world/object.worker.ts
|
||||
import { DurableObject } from "cloudflare:workers";
|
||||
var HelloWorldObject = class extends DurableObject {
|
||||
async get() {
|
||||
return await this.ctx.storage.get("value");
|
||||
}
|
||||
async set(value) {
|
||||
await this.ctx.storage.put("value", value);
|
||||
}
|
||||
};
|
||||
export {
|
||||
HelloWorldObject
|
||||
};
|
||||
//# sourceMappingURL=object.worker.js.map
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"version": 3,
|
||||
"sources": ["../../../../src/workers/hello-world/object.worker.ts"],
|
||||
"sourcesContent": ["import { DurableObject } from \"cloudflare:workers\";\n\nexport class HelloWorldObject extends DurableObject {\n\tasync get() {\n\t\treturn await this.ctx.storage.get<string>(\"value\");\n\t}\n\n\tasync set(value: string) {\n\t\tawait this.ctx.storage.put<string>(\"value\", value);\n\t}\n}\n"],
|
||||
"mappings": ";AAAA,SAAS,qBAAqB;AAEvB,IAAM,mBAAN,cAA+B,cAAc;AAAA,EACnD,MAAM,MAAM;AACX,WAAO,MAAM,KAAK,IAAI,QAAQ,IAAY,OAAO;AAAA,EAClD;AAAA,EAEA,MAAM,IAAI,OAAe;AACxB,UAAM,KAAK,IAAI,QAAQ,IAAY,SAAS,KAAK;AAAA,EAClD;AACD;",
|
||||
"names": []
|
||||
}
|
||||
+254
@@ -0,0 +1,254 @@
|
||||
// src/workers/images/images.worker.ts
|
||||
import { RpcTarget, WorkerEntrypoint } from "cloudflare:workers";
|
||||
import { getPublicUrl } from "miniflare:shared";
|
||||
|
||||
// src/workers/core/constants.ts
|
||||
var CorePaths = {
|
||||
/** Magic proxy used by getPlatformProxy */
|
||||
PLATFORM_PROXY: "/cdn-cgi/platform-proxy",
|
||||
/** Trigger scheduled event handlers */
|
||||
SCHEDULED: "/cdn-cgi/handler/scheduled",
|
||||
/** Trigger email event handlers */
|
||||
EMAIL: "/cdn-cgi/handler/email",
|
||||
/** Handler path prefix for validation */
|
||||
HANDLER_PREFIX: "/cdn-cgi/handler/",
|
||||
/** Live reload WebSocket endpoint */
|
||||
LIVE_RELOAD: "/cdn-cgi/mf/reload",
|
||||
/** Local explorer UI and API */
|
||||
EXPLORER: "/cdn-cgi/explorer",
|
||||
/** Legacy way to trigger scheduled event handlers */
|
||||
LEGACY_SCHEDULED: "/cdn-cgi/mf/scheduled",
|
||||
/** Stream video serving endpoint */
|
||||
STREAM_VIDEO: "/cdn-cgi/mf/stream",
|
||||
/** Local image delivery endpoint for serving hosted images */
|
||||
IMAGE_DELIVERY: "/cdn-cgi/mf/imagedelivery",
|
||||
/** Public R2 bucket object serving endpoint */
|
||||
R2_PUBLIC: "/cdn-cgi/local/r2/public"
|
||||
}, CoreHeaders = {
|
||||
CUSTOM_FETCH_SERVICE: "MF-Custom-Fetch-Service",
|
||||
CUSTOM_NODE_SERVICE: "MF-Custom-Node-Service",
|
||||
ORIGINAL_URL: "MF-Original-URL",
|
||||
/**
|
||||
* Stores the original hostname when using the `upstream` option.
|
||||
* When requests are proxied to an upstream, the `Host` header is rewritten
|
||||
* to match the upstream. This header preserves the original hostname
|
||||
* so Workers can access it if needed.
|
||||
*/
|
||||
ORIGINAL_HOSTNAME: "MF-Original-Hostname",
|
||||
PROXY_SHARED_SECRET: "MF-Proxy-Shared-Secret",
|
||||
DISABLE_PRETTY_ERROR: "MF-Disable-Pretty-Error",
|
||||
ERROR_STACK: "MF-Experimental-Error-Stack",
|
||||
ROUTE_OVERRIDE: "MF-Route-Override",
|
||||
CF_BLOB: "MF-CF-Blob",
|
||||
/** Used by the Vite plugin to pass through the original `sec-fetch-mode` header */
|
||||
SEC_FETCH_MODE: "MF-Sec-Fetch-Mode",
|
||||
// API Proxy
|
||||
OP_SECRET: "MF-Op-Secret",
|
||||
OP: "MF-Op",
|
||||
OP_TARGET: "MF-Op-Target",
|
||||
OP_KEY: "MF-Op-Key",
|
||||
OP_SYNC: "MF-Op-Sync",
|
||||
OP_STRINGIFIED_SIZE: "MF-Op-Stringified-Size",
|
||||
OP_RESULT_TYPE: "MF-Op-Result-Type",
|
||||
OP_ORIGINAL_URL: "MF-Op-Original-URL"
|
||||
}, CoreBindings = {
|
||||
SERVICE_LOOPBACK: "MINIFLARE_LOOPBACK",
|
||||
SERVICE_USER_ROUTE_PREFIX: "MINIFLARE_USER_ROUTE_",
|
||||
SERVICE_USER_FALLBACK: "MINIFLARE_USER_FALLBACK",
|
||||
TEXT_CUSTOM_SERVICE: "MINIFLARE_CUSTOM_SERVICE",
|
||||
// Backs the Images binding (`env.IMAGES`) — see imagesLocalFetcher.
|
||||
IMAGES_BINDING_SERVICE: "MINIFLARE_IMAGES_BINDING_SERVICE",
|
||||
// Backs `fetch(url, { cf: { image } })` transforms — see cfImageLocalFetcher.
|
||||
IMAGES_FETCH_SERVICE: "MINIFLARE_IMAGES_FETCH_SERVICE",
|
||||
TEXT_UPSTREAM_URL: "MINIFLARE_UPSTREAM_URL",
|
||||
JSON_CF_BLOB: "CF_BLOB",
|
||||
JSON_ROUTES: "MINIFLARE_ROUTES",
|
||||
JSON_LOG_LEVEL: "MINIFLARE_LOG_LEVEL",
|
||||
DATA_LIVE_RELOAD_SCRIPT: "MINIFLARE_LIVE_RELOAD_SCRIPT",
|
||||
DURABLE_OBJECT_NAMESPACE_PROXY: "MINIFLARE_PROXY",
|
||||
DATA_PROXY_SECRET: "MINIFLARE_PROXY_SECRET",
|
||||
DATA_PROXY_SHARED_SECRET: "MINIFLARE_PROXY_SHARED_SECRET",
|
||||
TRIGGER_HANDLERS: "TRIGGER_HANDLERS",
|
||||
LOG_REQUESTS: "LOG_REQUESTS",
|
||||
STRIP_DISABLE_PRETTY_ERROR: "STRIP_DISABLE_PRETTY_ERROR",
|
||||
SERVICE_LOCAL_EXPLORER: "MINIFLARE_LOCAL_EXPLORER",
|
||||
EXPLORER_DISK: "MINIFLARE_EXPLORER_DISK",
|
||||
JSON_LOCAL_EXPLORER_BINDING_MAP: "LOCAL_EXPLORER_BINDING_MAP",
|
||||
JSON_LOCAL_EXPLORER_WORKER_NAMES: "LOCAL_EXPLORER_WORKER_NAMES",
|
||||
JSON_EXPLORER_WORKER_OPTS: "MINIFLARE_EXPLORER_WORKER_OPTS",
|
||||
SERVICE_CACHE: "MINIFLARE_CACHE",
|
||||
SERVICE_DEV_REGISTRY_PROXY: "MINIFLARE_DEV_REGISTRY_PROXY",
|
||||
JSON_TELEMETRY_CONFIG: "MINIFLARE_TELEMETRY_CONFIG",
|
||||
DEV_REGISTRY_DEBUG_PORT: "DEV_REGISTRY_DEBUG_PORT",
|
||||
SERVICE_STREAM: "MINIFLARE_STREAM",
|
||||
SERVICE_IMAGES_DELIVERY: "MINIFLARE_IMAGES_DELIVERY",
|
||||
SERVICE_R2_PUBLIC: "MINIFLARE_R2_PUBLIC"
|
||||
};
|
||||
|
||||
// src/workers/images/images.worker.ts
|
||||
function buildVariantUrl(publicUrl, imageId, variant) {
|
||||
return new URL(
|
||||
`${CorePaths.IMAGE_DELIVERY}/${imageId}/${variant}`,
|
||||
publicUrl
|
||||
).toString();
|
||||
}
|
||||
async function withResolvedVariants(metadata, env) {
|
||||
let publicUrl = await getPublicUrl(env[CoreBindings.SERVICE_LOOPBACK]);
|
||||
return {
|
||||
...metadata,
|
||||
variants: metadata.variants.map(
|
||||
(variant) => buildVariantUrl(publicUrl, metadata.id, variant)
|
||||
)
|
||||
};
|
||||
}
|
||||
function base64DecodeArrayBuffer(buffer) {
|
||||
let base64String = new TextDecoder().decode(buffer), binaryString = atob(base64String.trim()), bytes = new Uint8Array(binaryString.length);
|
||||
for (let i = 0; i < binaryString.length; i++)
|
||||
bytes[i] = binaryString.charCodeAt(i);
|
||||
return bytes.buffer;
|
||||
}
|
||||
async function base64DecodeStream(stream) {
|
||||
let buffer = await new Response(stream).arrayBuffer();
|
||||
return base64DecodeArrayBuffer(buffer);
|
||||
}
|
||||
var ImageHandleImpl = class extends RpcTarget {
|
||||
#imageId;
|
||||
#env;
|
||||
constructor(imageId, env) {
|
||||
super(), this.#imageId = imageId, this.#env = env;
|
||||
}
|
||||
async details() {
|
||||
let result = await this.#env.IMAGES_STORE.getWithMetadata(
|
||||
this.#imageId,
|
||||
"arrayBuffer"
|
||||
);
|
||||
return result.metadata === null ? null : withResolvedVariants(result.metadata, this.#env);
|
||||
}
|
||||
async bytes() {
|
||||
let data = await this.#env.IMAGES_STORE.get(this.#imageId, "arrayBuffer");
|
||||
return data === null ? null : new Blob([data]).stream();
|
||||
}
|
||||
async update(options) {
|
||||
let existing = await this.#env.IMAGES_STORE.getWithMetadata(
|
||||
this.#imageId,
|
||||
"arrayBuffer"
|
||||
);
|
||||
if (existing.value === null || existing.metadata === null)
|
||||
throw new Error(`Image not found: ${this.#imageId}`);
|
||||
let updatedMetadata = {
|
||||
...existing.metadata,
|
||||
requireSignedURLs: options.requireSignedURLs ?? existing.metadata.requireSignedURLs,
|
||||
meta: options.metadata ?? existing.metadata.meta,
|
||||
creator: options.creator ?? existing.metadata.creator
|
||||
};
|
||||
return await this.#env.IMAGES_STORE.put(this.#imageId, existing.value, {
|
||||
metadata: updatedMetadata
|
||||
}), withResolvedVariants(updatedMetadata, this.#env);
|
||||
}
|
||||
async delete() {
|
||||
return await this.#env.IMAGES_STORE.get(
|
||||
this.#imageId,
|
||||
"arrayBuffer"
|
||||
) === null ? !1 : (await this.#env.IMAGES_STORE.delete(this.#imageId), !0);
|
||||
}
|
||||
}, ImagesService = class extends WorkerEntrypoint {
|
||||
image(imageId) {
|
||||
return new ImageHandleImpl(imageId, this.env);
|
||||
}
|
||||
async upload(image, options) {
|
||||
let imageData = image;
|
||||
options?.encoding === "base64" && (imageData = image instanceof ArrayBuffer ? base64DecodeArrayBuffer(image) : await base64DecodeStream(image));
|
||||
let buffer = imageData instanceof ArrayBuffer ? imageData : await new Response(imageData).arrayBuffer(), id = options?.id ?? crypto.randomUUID(), metadata = {
|
||||
id,
|
||||
filename: options?.filename ?? "uploaded.jpg",
|
||||
uploaded: (/* @__PURE__ */ new Date()).toISOString(),
|
||||
requireSignedURLs: options?.requireSignedURLs ?? !1,
|
||||
meta: options?.metadata ?? {},
|
||||
variants: ["public"],
|
||||
draft: !1,
|
||||
creator: options?.creator
|
||||
};
|
||||
return await this.env.IMAGES_STORE.put(id, buffer, { metadata }), withResolvedVariants(metadata, this.env);
|
||||
}
|
||||
async list(options) {
|
||||
let limit = options?.limit ?? 50, allImages = [], kvCursor;
|
||||
do {
|
||||
let kvResult = await this.env.IMAGES_STORE.list({
|
||||
cursor: kvCursor
|
||||
});
|
||||
for (let key of kvResult.keys)
|
||||
key.metadata && allImages.push(key.metadata);
|
||||
kvCursor = kvResult.list_complete ? void 0 : kvResult.cursor;
|
||||
} while (kvCursor);
|
||||
options?.creator && allImages.splice(
|
||||
0,
|
||||
allImages.length,
|
||||
...allImages.filter((i) => i.creator === options.creator)
|
||||
), allImages.sort((a, b) => {
|
||||
let dateA = a.uploaded ?? "", dateB = b.uploaded ?? "", cmp = dateA.localeCompare(dateB) || a.id.localeCompare(b.id);
|
||||
return options?.sortOrder === "desc" ? -cmp : cmp;
|
||||
});
|
||||
let startIndex = 0;
|
||||
if (options?.cursor) {
|
||||
let cursorIndex = allImages.findIndex((i) => i.id === options.cursor);
|
||||
cursorIndex >= 0 && (startIndex = cursorIndex + 1);
|
||||
}
|
||||
let page = allImages.slice(startIndex, startIndex + limit), hasMore = startIndex + limit < allImages.length, lastImage = page[page.length - 1], publicUrl = await getPublicUrl(
|
||||
this.env[CoreBindings.SERVICE_LOOPBACK]
|
||||
);
|
||||
return {
|
||||
images: page.map((metadata) => ({
|
||||
...metadata,
|
||||
variants: metadata.variants.map(
|
||||
(variant) => buildVariantUrl(publicUrl, metadata.id, variant)
|
||||
)
|
||||
})),
|
||||
cursor: hasMore && lastImage ? lastImage.id : void 0,
|
||||
listComplete: !hasMore
|
||||
};
|
||||
}
|
||||
async #detectContentType(data) {
|
||||
let formData = new FormData();
|
||||
formData.append("image", new Blob([data]));
|
||||
let infoRequest = new Request("http://placeholder/info", {
|
||||
method: "POST",
|
||||
body: formData
|
||||
});
|
||||
infoRequest.headers.set(
|
||||
CoreHeaders.CUSTOM_FETCH_SERVICE,
|
||||
CoreBindings.IMAGES_BINDING_SERVICE
|
||||
);
|
||||
let response = await this.env[CoreBindings.SERVICE_LOOPBACK].fetch(infoRequest);
|
||||
if (response.ok) {
|
||||
let info = await response.json();
|
||||
if (info.format)
|
||||
return info.format;
|
||||
}
|
||||
return "application/octet-stream";
|
||||
}
|
||||
// Handle HTTP requests for image delivery and transform operations
|
||||
async fetch(request) {
|
||||
let url = new URL(request.url);
|
||||
if (url.pathname.startsWith(`${CorePaths.IMAGE_DELIVERY}/`)) {
|
||||
let imageId = url.pathname.slice(CorePaths.IMAGE_DELIVERY.length + 1).split("/")[0];
|
||||
if (!imageId)
|
||||
return new Response("Missing image ID", { status: 400 });
|
||||
let data = await this.env.IMAGES_STORE.get(imageId, "arrayBuffer");
|
||||
if (data === null)
|
||||
return new Response("Image not found", { status: 404 });
|
||||
let contentType = await this.#detectContentType(data);
|
||||
return new Response(data, {
|
||||
headers: { "Content-Type": contentType }
|
||||
});
|
||||
}
|
||||
let forwardRequest = new Request(request);
|
||||
return forwardRequest.headers.set(
|
||||
CoreHeaders.CUSTOM_FETCH_SERVICE,
|
||||
CoreBindings.IMAGES_BINDING_SERVICE
|
||||
), forwardRequest.headers.set(CoreHeaders.ORIGINAL_URL, request.url), this.env[CoreBindings.SERVICE_LOOPBACK].fetch(forwardRequest);
|
||||
}
|
||||
};
|
||||
export {
|
||||
ImagesService as default
|
||||
};
|
||||
//# sourceMappingURL=images.worker.js.map
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user