diff --git a/README.md b/README.md
index 8ddaf00..af194fa 100644
--- a/README.md
+++ b/README.md
@@ -6,7 +6,7 @@ Sophisticated scheduler for durable tasks, built on Durable Object Alarms.
- schedule tasks by time, delay, or cron expression
- schedule multiple tasks on the same object
-- query tasks by name, id, or payload pattern
+- query tasks by description or id (or by time range?)
- cancel tasks
Bonus: This will be particularly useful when wired up with an LLM agent, so you'll be able to schedule tasks by describing them in natural language. Like "remind me to call my friend every monday at 10:00"
@@ -16,8 +16,7 @@ import { Scheduler } from "durable-scheduler";
type Task = {
id: string;
- name: string;
- payload: any;
+ description: string;
time: Date;
} & (
| {
@@ -25,7 +24,7 @@ type Task = {
type: "scheduled";
}
| {
- delay: number;
+ delayInSeconds: number;
type: "delayed";
}
| {
@@ -38,52 +37,38 @@ class MyClass extends Scheduler {
foo() {
// schedule at specific time
this.scheduler.scheduleTask({
- name: "my-task",
+ description: "my-task",
time: new Date(Date.now() + 1000),
- payload: {
- // ...
- },
});
// schedule after a certain amount of time
this.scheduler.scheduleTask({
- name: "my-task",
- delay: 1000, // in ms? s?
- payload: {
- // ...
- },
+ description: "my-task",
+ delayInSeconds: 1000, // in ms? s?
});
// schedule to run periodically
this.scheduler.scheduleTask({
- name: "my-task",
+ description: "my-task",
cron: "*/1 * * * *", // every minute
- payload: {
- // ...
- },
});
- // you can also use an id instead of a name
+ // you can also specify an id
this.scheduler.scheduleTask({
id: "my-task",
time: new Date(Date.now() + 1000),
- payload: {
- // ...
- },
});
// ids must be unique
- // names can be repeated
- // if you don't provide a name or id, it will default to a random uuid
+ // if you don't provide an id, it will default to a random uuid
// if you try to schedule a task with an id that already exists,
// it will overwrite the existing task
// query for tasks
const tasks = this.scheduler.query({
- // by name
+ // by description
// by id
- // by payload pattern matching (?)
// by time range
// some kind of sql syntax here? dunno..
});
diff --git a/eslint.config.mjs b/eslint.config.mjs
index 3f5c3a9..ab1c78c 100644
--- a/eslint.config.mjs
+++ b/eslint.config.mjs
@@ -48,7 +48,8 @@ export default [
"no-undef": "off",
"@typescript-eslint/explicit-module-boundary-types": "off",
"@typescript-eslint/no-unused-vars": ["warn", { argsIgnorePattern: "^_" }],
-
+ "@typescript-eslint/require-await": "off",
+ "@typescript-eslint/await-thenable": "off",
// React rules
...reactPlugin.configs.recommended.rules,
"react/react-in-jsx-scope": "off",
diff --git a/example/README.md b/example/README.md
new file mode 100644
index 0000000..9731e54
--- /dev/null
+++ b/example/README.md
@@ -0,0 +1,7 @@
+This is an example of how to use the `durable-scheduler` package.
+
+The example app is a TODO list app that can schedule tasks to be run at a future date. It is a client side rendered React app that uses tailwind for styling, built with Vite.
+
+We have one input at the top-middle of the page, where you can add a new task. This takes freeform natural language text input (eg: "Buy milk tomorrow at 10am", "Send me a report every friday evening", "Remind me to call my wife in 20 minutes"). We take the input from the user, which is then parsed into a task.
+
+Underneath the input, there is a list of all the tasks that have been scheduled. Each task has a description, a due date, and a status checkbox. We use the status checkbox to mark a task as complete. We can also delete a task altogether by clicking the delete button.
diff --git a/example/src/client/app.tsx b/example/src/client/app.tsx
index a745377..4b9ecbe 100644
--- a/example/src/client/app.tsx
+++ b/example/src/client/app.tsx
@@ -1,3 +1,124 @@
+import { useState } from "react";
+
+import { SqlTask } from "../../../src";
+
+interface ToDo {
+ id: string;
+ inputText: string;
+ parsedTask: SqlTask | undefined;
+ completed: boolean;
+}
+
+// eslint-disable-next-line @typescript-eslint/no-unused-vars
+const ROOM_ID = "username"; // TODO: this will read a username from auth later
+
export default function App() {
- return
Hello World ;
+ const [todos, setTodos] = useState([]);
+ const [inputText, setInputText] = useState("");
+
+ const handleAddToDo = async (e: React.FormEvent) => {
+ e.preventDefault();
+ if (!inputText.trim()) return;
+
+ try {
+ const newToDo: ToDo = {
+ id: crypto.randomUUID(),
+ inputText,
+ parsedTask: undefined,
+ completed: false,
+ };
+
+ setTodos((prev) => [...prev, newToDo]);
+ // TODO: Schedule the task and update the task with the parsedTask
+
+ // let's first convert it to the object that the scheduler expects
+ const result = await fetch("/api/string-to-schedule", {
+ method: "POST",
+ body: inputText,
+ });
+ const parsedTask = await result.json();
+ // eslint-disable-next-line no-console
+ console.log("parsedTask", parsedTask);
+ // ok now let's schedule it
+
+ // TODO: schedule the task
+ setInputText("");
+ } catch (error) {
+ console.error("Failed to parse todo:", error);
+ // You might want to show an error message to the user here
+ }
+ };
+
+ const handleToggleToDo = async (todoId: string) => {
+ setTodos((prev) =>
+ prev.map((todo) => (todo.id === todoId ? { ...todo, completed: !todo.completed } : todo))
+ );
+ };
+
+ const handleDeleteToDo = async (todoId: string) => {
+ // TODO: Cancel the scheduled task
+ setTodos((prev) => prev.filter((todo) => todo.id !== todoId));
+ };
+
+ return (
+
+
+
ToDo List
+
+
+
+
+ {todos.map((todo) => (
+
+
void handleToggleToDo(todo.id)}
+ className="h-5 w-5 rounded border-gray-300 text-blue-500 focus:ring-blue-500"
+ />
+
+
+ {todo.parsedTask?.description}
+
+
Due: {todo.parsedTask?.time}
+
+
void handleDeleteToDo(todo.id)}
+ className="p-2 text-red-500 hover:text-red-600 focus:outline-none"
+ >
+
+
+
+
+
+ ))}
+
+
+
+ );
}
diff --git a/example/src/server/index.ts b/example/src/server/index.ts
index eb2a31d..d8bcc9c 100644
--- a/example/src/server/index.ts
+++ b/example/src/server/index.ts
@@ -1,17 +1,42 @@
+import { createOpenAI } from "@ai-sdk/openai";
+import { generateObject } from "ai";
+import { Server, routePartykitRequest } from "partyserver";
import { z } from "zod";
import { Scheduler } from "../../../src";
+export { Scheduler };
+
type Env = {
+ OPENAI_API_KEY: string;
AI: Ai;
- SCHEDULER: DurableObjectNamespace;
+ Scheduler: DurableObjectNamespace>;
+ ToDos: DurableObjectNamespace;
};
const taskSchema = z
.object({
- id: z.string().default(() => crypto.randomUUID()),
- name: z.string().optional(),
- payload: z.record(z.any()).default({}),
+ id: z.string().default(() => {
+ return crypto.randomUUID();
+ }),
+ description: z.string().optional(),
+ // // we haven't implemented this yet
+ // payload: z.record(z.any()).optional(),
+ // // this isn't necessary, but it's here for reference
+ // callback: z
+ // .union([
+ // z.object({
+ // type: z.literal("webhook"),
+ // url: z.string(),
+ // }),
+ // z.object({
+ // type: z.literal("durable-object"),
+ // namespace: z.string(),
+ // id: z.string(),
+ // function: z.string(),
+ // }),
+ // ])
+ // .optional(),
})
.and(
z.discriminatedUnion("type", [
@@ -21,12 +46,15 @@ const taskSchema = z
}),
z.object({
type: z.literal("delayed"),
- delay: z.number(),
+ delayInSeconds: z.number(),
}),
z.object({
type: z.literal("cron"),
cron: z.string(),
}),
+ z.object({
+ type: z.literal("no-schedule"),
+ }),
])
);
@@ -34,67 +62,29 @@ const taskSchema = z
// if (!condition) throw new Error(message);
// }
-export class MyScheduler extends Scheduler {
+export class ToDos extends Server {
+ scheduler: DurableObjectStub>;
+ constructor(state: DurableObjectState, env: Env) {
+ super(state, env);
+ this.scheduler = env.Scheduler.get(state.id);
+ }
async fetch(request: Request) {
const url = new URL(request.url);
- if (!url.pathname.startsWith("/api/")) {
- return fetch(request.url.replace("http://localhost:8787", "http://localhost:5173"), request);
- }
-
const route = `${request.method} ${url.pathname}`;
switch (route) {
case "GET /api/":
return new Response("Hello, world!");
- case "GET /api/string-to-schedule": {
- const result = await this.env.AI.run("@cf/meta/llama-3.1-8b-instruct", {
- prompt: `
- You are a helpful assistant. Today is ${new Date().toUTCString()}.
- You are given a string that has to be input as an object into a scheduler.
- The string may be:
- - a delay like "in 10 minutes"
- - you need to convert this into an object with a delay property like
- {
- "type": "delayed",
- "delay": 600000
- }
- - a specific time like "next monday at 10:00"
- - you need to convert this into an object with a time property with a UTC timestamp like
- {
- "type": "scheduled",
- "time": "Mon, 02 Dec 2024 10:00:00 GMT"
- }
- - a cron expression like "every 10 minutes"
- - you need to convert this into an object with a cron property like
- {
- "type": "cron",
- "cron": "*/10 * * * *"
- }
-
- Here is the input string:
- ${url.searchParams.get("input")}
-
- Do not include any other text than the json object.
- `,
- });
-
- // @ts-expect-error - this is a string
- // eslint-disable-next-line no-console
- console.log(result.response);
- // @ts-expect-error - this is a string
- return new Response(result.response as string);
- }
-
case "GET /api/tasks": {
- const tasks = await this.query();
+ const tasks = await this.scheduler.query();
return new Response(JSON.stringify(tasks));
}
case "POST /api/tasks": {
const task = taskSchema.parse(await request.json());
- await this.scheduleTask(task);
+ await this.scheduler.scheduleTask(task);
return new Response(JSON.stringify(task));
}
@@ -112,8 +102,35 @@ export default {
return fetch(request.url.replace("http://localhost:8787", "http://localhost:5173"), request);
}
- const id = env.SCHEDULER.idFromName("example");
- const stub = env.SCHEDULER.get(id);
- return stub.fetch(request);
+ switch (`${request.method} ${url.pathname}`) {
+ case "POST /api/string-to-schedule": {
+ const openai = createOpenAI({
+ apiKey: env.OPENAI_API_KEY,
+ });
+
+ const result = await generateObject({
+ model: openai("gpt-4o"),
+ mode: "json",
+ schemaName: "task",
+ schemaDescription: "A task to be scheduled",
+ schema: taskSchema,
+ maxRetries: 5,
+ prompt: `
+Today is ${new Date().toUTCString()}.
+You are given a string that has to be input as an object into a scheduler.
+
+Here is the string:
+${await request.text()}
+`,
+ });
+
+ // eslint-disable-next-line no-console
+ console.log(result.object);
+
+ return new Response(JSON.stringify(result.object));
+ }
+ }
+
+ return (await routePartykitRequest(request, env)) || new Response("Not found", { status: 404 });
},
} satisfies ExportedHandler;
diff --git a/example/wrangler.toml b/example/wrangler.toml
index e90cb6e..36cbfd7 100644
--- a/example/wrangler.toml
+++ b/example/wrangler.toml
@@ -8,11 +8,16 @@ assets = { directory = "public" }
[[durable_objects.bindings]]
name = "SCHEDULER"
-class_name = "MyScheduler"
+class_name = "Scheduler"
+
+[[durable_objects.bindings]]
+name = "TODOS"
+class_name = "ToDos"
+
[[migrations]]
tag = "v1"
-new_sqlite_classes = [ "MyScheduler" ]
+new_sqlite_classes = [ "Scheduler", "ToDos" ]
[ai]
binding = "AI"
diff --git a/package-lock.json b/package-lock.json
index de12bbe..26313dc 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -12,41 +12,164 @@
"cron-parser": "^4.9.0"
},
"devDependencies": {
+ "@ai-sdk/openai": "^1.0.7",
"@changesets/changelog-github": "^0.5.0",
"@changesets/cli": "^2.27.10",
- "@cloudflare/vitest-pool-workers": "^0.5.32",
- "@cloudflare/workers-types": "^4.20241127.0",
- "@eslint/js": "^9.15.0",
+ "@cloudflare/vitest-pool-workers": "^0.5.34",
+ "@cloudflare/workers-types": "^4.20241205.0",
+ "@eslint/js": "^9.16.0",
"@tailwindcss/aspect-ratio": "^0.4.2",
"@tailwindcss/container-queries": "^0.1.1",
"@tailwindcss/forms": "^0.5.9",
"@tailwindcss/typography": "^0.5.15",
- "@tailwindcss/vite": "^4.0.0-beta.3",
+ "@tailwindcss/vite": "^4.0.0-beta.6",
"@types/bun": "^1.1.14",
- "@types/react": "^18.3.12",
- "@types/react-dom": "^18.3.1",
- "@typescript-eslint/eslint-plugin": "^8.16.0",
- "@typescript-eslint/parser": "^8.16.0",
+ "@types/react": "^19.0.1",
+ "@types/react-dom": "^19.0.1",
+ "@typescript-eslint/eslint-plugin": "^8.17.0",
+ "@typescript-eslint/parser": "^8.17.0",
"@vitejs/plugin-react": "^4.3.4",
+ "ai": "^4.0.13",
"concurrently": "^9.1.0",
- "eslint": "^9.15.0",
+ "eslint": "^9.16.0",
"eslint-config-prettier": "^9.1.0",
- "eslint-import-resolver-typescript": "^3.6.1",
+ "eslint-import-resolver-typescript": "^3.7.0",
"eslint-plugin-import": "^2.31.0",
"eslint-plugin-react": "^7.37.2",
- "eslint-plugin-react-hooks": "^5.0.0",
- "prettier": "^3.4.1",
- "react": "^18.3.1",
- "react-dom": "^18.3.1",
- "tailwindcss": "^4.0.0-beta.3",
+ "eslint-plugin-react-hooks": "^5.1.0",
+ "partyserver": "^0.0.57",
+ "partysocket": "^1.0.2",
+ "prettier": "^3.4.2",
+ "react": "^19.0.0",
+ "react-dom": "^19.0.0",
+ "tailwindcss": "^4.0.0-beta.6",
"tshy": "^3.0.2",
"typescript": "^5.7.2",
- "vite": "^6.0.1",
- "vitest": "2.1.6",
- "wrangler": "^3.91.0",
+ "vite": "^6.0.3",
+ "vitest": "2.1.8",
+ "wrangler": "^3.93.0",
"zod": "^3.23.8"
}
},
+ "node_modules/@ai-sdk/openai": {
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/@ai-sdk/openai/-/openai-1.0.7.tgz",
+ "integrity": "sha512-eXWERuUrMyH3k1GpmYHzTj7Xzxx5/0dENAkbxnj7t2Sn2Mgfb5Td/8QYfGSxuuPd8BrfGTyknArff6yqPkuvPA==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@ai-sdk/provider": "1.0.1",
+ "@ai-sdk/provider-utils": "2.0.3"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "peerDependencies": {
+ "zod": "^3.0.0"
+ }
+ },
+ "node_modules/@ai-sdk/provider": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/@ai-sdk/provider/-/provider-1.0.1.tgz",
+ "integrity": "sha512-mV+3iNDkzUsZ0pR2jG0sVzU6xtQY5DtSCBy3JFycLp6PwjyLw/iodfL3MwdmMCRJWgs3dadcHejRnMvF9nGTBg==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "json-schema": "^0.4.0"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@ai-sdk/provider-utils": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/@ai-sdk/provider-utils/-/provider-utils-2.0.3.tgz",
+ "integrity": "sha512-Cyk7GlFEse2jQ4I3FWYuZ1Zhr5w1mD9SHMJTYm/in1rd7r89nmEoQiOy3h8YV2ZvTa2/6aR10xZ4M0k4B3BluA==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@ai-sdk/provider": "1.0.1",
+ "eventsource-parser": "^3.0.0",
+ "nanoid": "^3.3.7",
+ "secure-json-parse": "^2.7.0"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "peerDependencies": {
+ "zod": "^3.0.0"
+ },
+ "peerDependenciesMeta": {
+ "zod": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@ai-sdk/react": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/@ai-sdk/react/-/react-1.0.5.tgz",
+ "integrity": "sha512-OPqYhltJE9dceWxw5pTXdYtAhs1Ca6Ly8xR7z/T+JZ0lrcgembFIMvnJ0dMBkba07P4GQBmuvd5DVTeAqPM9SQ==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@ai-sdk/provider-utils": "2.0.3",
+ "@ai-sdk/ui-utils": "1.0.4",
+ "swr": "^2.2.5",
+ "throttleit": "2.1.0"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "peerDependencies": {
+ "react": "^18 || ^19 || ^19.0.0-rc",
+ "zod": "^3.0.0"
+ },
+ "peerDependenciesMeta": {
+ "react": {
+ "optional": true
+ },
+ "zod": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@ai-sdk/react/node_modules/swr": {
+ "version": "2.2.5",
+ "resolved": "https://registry.npmjs.org/swr/-/swr-2.2.5.tgz",
+ "integrity": "sha512-QtxqyclFeAsxEUeZIYmsaQ0UjimSq1RZ9Un7I68/0ClKK/U3LoyQunwkQfJZr2fc22DfIXLNDc2wFyTEikCUpg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "client-only": "^0.0.1",
+ "use-sync-external-store": "^1.2.0"
+ },
+ "peerDependencies": {
+ "react": "^16.11.0 || ^17.0.0 || ^18.0.0"
+ }
+ },
+ "node_modules/@ai-sdk/ui-utils": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/@ai-sdk/ui-utils/-/ui-utils-1.0.4.tgz",
+ "integrity": "sha512-P2vDvASaGsD+lmbsQ5WYjELxJBQgse3CpxyLSA+usZiZxspwYbLFsSWiYz3zhIemcnS0T6/OwQdU6UlMB4N5BQ==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@ai-sdk/provider": "1.0.1",
+ "@ai-sdk/provider-utils": "2.0.3",
+ "zod-to-json-schema": "^3.23.5"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "peerDependencies": {
+ "zod": "^3.0.0"
+ },
+ "peerDependenciesMeta": {
+ "zod": {
+ "optional": true
+ }
+ }
+ },
"node_modules/@ampproject/remapping": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz",
@@ -700,9 +823,9 @@
}
},
"node_modules/@cloudflare/vitest-pool-workers": {
- "version": "0.5.32",
- "resolved": "https://registry.npmjs.org/@cloudflare/vitest-pool-workers/-/vitest-pool-workers-0.5.32.tgz",
- "integrity": "sha512-lJHwXq3VWKgzy7BzXs61O/QukT9QQ42hl27eRcqCV6P20OF4/bLH8rmUaYxdR8IxLlmNY7Q5h0wGN0nXBn8XKg==",
+ "version": "0.5.34",
+ "resolved": "https://registry.npmjs.org/@cloudflare/vitest-pool-workers/-/vitest-pool-workers-0.5.34.tgz",
+ "integrity": "sha512-OoC51MBgz0z/SNG5GnvE9VAyBB/xxJODb7OazoWyZlMWe8HIGjg/Dti1hyn18dugJeIL6WiT11E90CLVbNl48g==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -710,9 +833,9 @@
"cjs-module-lexer": "^1.2.3",
"devalue": "^4.3.0",
"esbuild": "0.17.19",
- "miniflare": "3.20241106.1",
+ "miniflare": "3.20241205.0",
"semver": "^7.5.1",
- "wrangler": "3.91.0",
+ "wrangler": "3.93.0",
"zod": "^3.22.3"
},
"peerDependencies": {
@@ -722,9 +845,9 @@
}
},
"node_modules/@cloudflare/workerd-darwin-64": {
- "version": "1.20241106.1",
- "resolved": "https://registry.npmjs.org/@cloudflare/workerd-darwin-64/-/workerd-darwin-64-1.20241106.1.tgz",
- "integrity": "sha512-zxvaToi1m0qzAScrxFt7UvFVqU8DxrCO2CinM1yQkv5no7pA1HolpIrwZ0xOhR3ny64Is2s/J6BrRjpO5dM9Zw==",
+ "version": "1.20241205.0",
+ "resolved": "https://registry.npmjs.org/@cloudflare/workerd-darwin-64/-/workerd-darwin-64-1.20241205.0.tgz",
+ "integrity": "sha512-TArEZkSZkHJyEwnlWWkSpCI99cF6lJ14OVeEoI9Um/+cD9CKZLM9vCmsLeKglKheJ0KcdCnkA+DbeD15t3VaWg==",
"cpu": [
"x64"
],
@@ -739,9 +862,9 @@
}
},
"node_modules/@cloudflare/workerd-darwin-arm64": {
- "version": "1.20241106.1",
- "resolved": "https://registry.npmjs.org/@cloudflare/workerd-darwin-arm64/-/workerd-darwin-arm64-1.20241106.1.tgz",
- "integrity": "sha512-j3dg/42D/bPgfNP3cRUBxF+4waCKO/5YKwXNj+lnVOwHxDu+ne5pFw9TIkKYcWTcwn0ZUkbNZNM5rhJqRn4xbg==",
+ "version": "1.20241205.0",
+ "resolved": "https://registry.npmjs.org/@cloudflare/workerd-darwin-arm64/-/workerd-darwin-arm64-1.20241205.0.tgz",
+ "integrity": "sha512-u5eqKa9QRdA8MugfgCoD+ADDjY6EpKbv3hSYJETmmUh17l7WXjWBzv4pUvOKIX67C0UzMUy4jZYwC53MymhX3w==",
"cpu": [
"arm64"
],
@@ -756,9 +879,9 @@
}
},
"node_modules/@cloudflare/workerd-linux-64": {
- "version": "1.20241106.1",
- "resolved": "https://registry.npmjs.org/@cloudflare/workerd-linux-64/-/workerd-linux-64-1.20241106.1.tgz",
- "integrity": "sha512-Ih+Ye8E1DMBXcKrJktGfGztFqHKaX1CeByqshmTbODnWKHt6O65ax3oTecUwyC0+abuyraOpAtdhHNpFMhUkmw==",
+ "version": "1.20241205.0",
+ "resolved": "https://registry.npmjs.org/@cloudflare/workerd-linux-64/-/workerd-linux-64-1.20241205.0.tgz",
+ "integrity": "sha512-OYA7S5zpumMamWEW+IhhBU6YojIEocyE5X/YFPiTOCrDE3dsfr9t6oqNE7hxGm1VAAu+Irtl+a/5LwmBOU681w==",
"cpu": [
"x64"
],
@@ -773,9 +896,9 @@
}
},
"node_modules/@cloudflare/workerd-linux-arm64": {
- "version": "1.20241106.1",
- "resolved": "https://registry.npmjs.org/@cloudflare/workerd-linux-arm64/-/workerd-linux-arm64-1.20241106.1.tgz",
- "integrity": "sha512-mdQFPk4+14Yywn7n1xIzI+6olWM8Ybz10R7H3h+rk0XulMumCWUCy1CzIDauOx6GyIcSgKIibYMssVHZR30ObA==",
+ "version": "1.20241205.0",
+ "resolved": "https://registry.npmjs.org/@cloudflare/workerd-linux-arm64/-/workerd-linux-arm64-1.20241205.0.tgz",
+ "integrity": "sha512-qAzecONjFJGIAVJZKExQ5dlbic0f3d4A+GdKa+H6SoUJtPaWiE3K6WuePo4JOT7W3/Zfh25McmX+MmpMUUcM5Q==",
"cpu": [
"arm64"
],
@@ -790,9 +913,9 @@
}
},
"node_modules/@cloudflare/workerd-windows-64": {
- "version": "1.20241106.1",
- "resolved": "https://registry.npmjs.org/@cloudflare/workerd-windows-64/-/workerd-windows-64-1.20241106.1.tgz",
- "integrity": "sha512-4rtcss31E/Rb/PeFocZfr+B9i1MdrkhsTBWizh8siNR4KMmkslU2xs2wPaH1z8+ErxkOsHrKRa5EPLh5rIiFeg==",
+ "version": "1.20241205.0",
+ "resolved": "https://registry.npmjs.org/@cloudflare/workerd-windows-64/-/workerd-windows-64-1.20241205.0.tgz",
+ "integrity": "sha512-BEab+HiUgCdl6GXAT7EI2yaRtDPiRJlB94XLvRvXi1ZcmQqsrq6awGo6apctFo4WUL29V7c09LxmN4HQ3X2Tvg==",
"cpu": [
"x64"
],
@@ -807,9 +930,9 @@
}
},
"node_modules/@cloudflare/workers-shared": {
- "version": "0.9.0",
- "resolved": "https://registry.npmjs.org/@cloudflare/workers-shared/-/workers-shared-0.9.0.tgz",
- "integrity": "sha512-eP6Ir45uPbKnpADVzUCtkRUYxYxjB1Ew6n/whTJvHu8H4m93USHAceCMm736VBZdlxuhXXUjEP3fCUxKPn+cfw==",
+ "version": "0.10.0",
+ "resolved": "https://registry.npmjs.org/@cloudflare/workers-shared/-/workers-shared-0.10.0.tgz",
+ "integrity": "sha512-j3EwZBc9ctavmFVOQT1gqztRO/Plx4ZR0LMEEOif+5YoCcuD1P7/NEjlODPMc5a1w+8+7A/H+Ci8Ihd55+x0Zw==",
"dev": true,
"license": "MIT OR Apache-2.0",
"dependencies": {
@@ -821,9 +944,9 @@
}
},
"node_modules/@cloudflare/workers-types": {
- "version": "4.20241127.0",
- "resolved": "https://registry.npmjs.org/@cloudflare/workers-types/-/workers-types-4.20241127.0.tgz",
- "integrity": "sha512-UqlvtqV8eI0CdPR7nxlbVlE52+lcjHvGdbYXEPwisy23+39RsFV7OOy0da0moJAhqnL2OhDmWTOaKdsVcPHiJQ==",
+ "version": "4.20241205.0",
+ "resolved": "https://registry.npmjs.org/@cloudflare/workers-types/-/workers-types-4.20241205.0.tgz",
+ "integrity": "sha512-pj1VKRHT/ScQbHOIMFODZaNAlJHQHdBSZXNIdr9ebJzwBff9Qz8VdqhbhggV7f+aUEh8WSbrsPIo4a+WtgjUvw==",
"dev": true,
"license": "MIT OR Apache-2.0"
},
@@ -1432,9 +1555,9 @@
}
},
"node_modules/@eslint/js": {
- "version": "9.15.0",
- "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.15.0.tgz",
- "integrity": "sha512-tMTqrY+EzbXmKJR5ToI8lxu7jaN5EdmrBFJpQk5JmSlyLsx6o4t27r883K5xsLuCYCpfKBCGswMSWXsM+jB7lg==",
+ "version": "9.16.0",
+ "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.16.0.tgz",
+ "integrity": "sha512-tw2HxzQkrbeuvyj1tG2Yqq+0H9wGoI2IMk4EOsQeX+vmd75FtJAzf+gTA69WF+baUKRYQ3x2kbLE08js5OsTVg==",
"dev": true,
"license": "MIT",
"engines": {
@@ -1827,6 +1950,16 @@
"node": ">=12.4.0"
}
},
+ "node_modules/@opentelemetry/api": {
+ "version": "1.9.0",
+ "resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.9.0.tgz",
+ "integrity": "sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": ">=8.0.0"
+ }
+ },
"node_modules/@rollup/rollup-android-arm-eabi": {
"version": "4.27.4",
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.27.4.tgz",
@@ -2120,44 +2253,44 @@
}
},
"node_modules/@tailwindcss/node": {
- "version": "4.0.0-beta.3",
- "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.0.0-beta.3.tgz",
- "integrity": "sha512-TPS/a/fsLwPU/p3VeSSKXfuhzKjvmMTJDIp8zVrcBmSk+GNbIrcjkc2p/KcvTSh7Zfw6xF/Z8cjA/JnTgMVjQA==",
+ "version": "4.0.0-beta.6",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.0.0-beta.6.tgz",
+ "integrity": "sha512-W07J19+05rRFKfk4sVtkNTb4iuGTI3BU6Ip/iEbb/w5NvaP+fSFK31OYFpJ+CXEWrbNgidUg46BQpw4Y1gophA==",
"dev": true,
"license": "MIT",
"dependencies": {
"enhanced-resolve": "^5.17.1",
"jiti": "^2.4.0",
- "tailwindcss": "4.0.0-beta.3"
+ "tailwindcss": "4.0.0-beta.6"
}
},
"node_modules/@tailwindcss/oxide": {
- "version": "4.0.0-beta.3",
- "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.0.0-beta.3.tgz",
- "integrity": "sha512-uN9ZlT8w4LlktqzS3aH2SztfxixzTYGZqEaRQgVuBPkFfTahInX1+GEGNZwmZ/hadR2jkCuCqxg8z1IuhWsSbw==",
+ "version": "4.0.0-beta.6",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.0.0-beta.6.tgz",
+ "integrity": "sha512-i/Fg/rXYwzV7OJEXbcwjNVkYPgnyfLdYXtduOX7Kvf686xn6jR/k6bhl9fVkQcDb/ujyKzNjD2POAjwhHAC8aw==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">= 10"
},
"optionalDependencies": {
- "@tailwindcss/oxide-android-arm64": "4.0.0-beta.3",
- "@tailwindcss/oxide-darwin-arm64": "4.0.0-beta.3",
- "@tailwindcss/oxide-darwin-x64": "4.0.0-beta.3",
- "@tailwindcss/oxide-freebsd-x64": "4.0.0-beta.3",
- "@tailwindcss/oxide-linux-arm-gnueabihf": "4.0.0-beta.3",
- "@tailwindcss/oxide-linux-arm64-gnu": "4.0.0-beta.3",
- "@tailwindcss/oxide-linux-arm64-musl": "4.0.0-beta.3",
- "@tailwindcss/oxide-linux-x64-gnu": "4.0.0-beta.3",
- "@tailwindcss/oxide-linux-x64-musl": "4.0.0-beta.3",
- "@tailwindcss/oxide-win32-arm64-msvc": "4.0.0-beta.3",
- "@tailwindcss/oxide-win32-x64-msvc": "4.0.0-beta.3"
+ "@tailwindcss/oxide-android-arm64": "4.0.0-beta.6",
+ "@tailwindcss/oxide-darwin-arm64": "4.0.0-beta.6",
+ "@tailwindcss/oxide-darwin-x64": "4.0.0-beta.6",
+ "@tailwindcss/oxide-freebsd-x64": "4.0.0-beta.6",
+ "@tailwindcss/oxide-linux-arm-gnueabihf": "4.0.0-beta.6",
+ "@tailwindcss/oxide-linux-arm64-gnu": "4.0.0-beta.6",
+ "@tailwindcss/oxide-linux-arm64-musl": "4.0.0-beta.6",
+ "@tailwindcss/oxide-linux-x64-gnu": "4.0.0-beta.6",
+ "@tailwindcss/oxide-linux-x64-musl": "4.0.0-beta.6",
+ "@tailwindcss/oxide-win32-arm64-msvc": "4.0.0-beta.6",
+ "@tailwindcss/oxide-win32-x64-msvc": "4.0.0-beta.6"
}
},
"node_modules/@tailwindcss/oxide-android-arm64": {
- "version": "4.0.0-beta.3",
- "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.0.0-beta.3.tgz",
- "integrity": "sha512-YXXoYFvzELo3YRzFIgJrcJCdw1p31xY2ONO1akZwajNjP+Ac8QdvjZejFJc4sLtnL5EXmYSOFv5w3Pa2gRzcAA==",
+ "version": "4.0.0-beta.6",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.0.0-beta.6.tgz",
+ "integrity": "sha512-yrUH/IfhkJWSYjF86UxpwrfaO866MjOhVQKG+wCgp0+YZGwirs8vX//a+8Y0SpEJrO0PVgmUU7xbsIM1EQWyTw==",
"cpu": [
"arm64"
],
@@ -2172,9 +2305,9 @@
}
},
"node_modules/@tailwindcss/oxide-darwin-arm64": {
- "version": "4.0.0-beta.3",
- "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.0.0-beta.3.tgz",
- "integrity": "sha512-ERDVLTEbjFOEnWEYQx8FWgAVl0gPhtoUJ8jXXhTcY4lIGQ/UNWg7amRwFF8jV2qOXUhMh1XppfsxemFMNl/XtQ==",
+ "version": "4.0.0-beta.6",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.0.0-beta.6.tgz",
+ "integrity": "sha512-WqFHSD/kocp8rH3KYJow8zTatTEMfdrkZu2KL8nnKfuAEk+juJuUnOQaXDmfsYNQSkGjtnGdcB/fueq4UtUSvw==",
"cpu": [
"arm64"
],
@@ -2189,9 +2322,9 @@
}
},
"node_modules/@tailwindcss/oxide-darwin-x64": {
- "version": "4.0.0-beta.3",
- "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.0.0-beta.3.tgz",
- "integrity": "sha512-FE5rWGNDNS6q0eSZiuD6M9VmBZgyEep+h4Oq7K6Ei+62sRTD0CRyLNhuot/w/C/IrkZqi2t/spHJa4mM3YKNiQ==",
+ "version": "4.0.0-beta.6",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.0.0-beta.6.tgz",
+ "integrity": "sha512-zFc/TTBkDNLOKl/G9i1JOpg0AgrUOgBcSgURT/E0RsF0ZcKdiIjcyNswNThmjQnj+JAA8QL1Rct+04dH5j7Xjw==",
"cpu": [
"x64"
],
@@ -2206,9 +2339,9 @@
}
},
"node_modules/@tailwindcss/oxide-freebsd-x64": {
- "version": "4.0.0-beta.3",
- "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.0.0-beta.3.tgz",
- "integrity": "sha512-CLmGpKpmtZpD/+9kvGmtDeY55OiwuePGsOpCrAZQ3PD40uNK2ghwWt+T/BmQJTI5RzsOPbMjzfzKmQthdtWZrg==",
+ "version": "4.0.0-beta.6",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.0.0-beta.6.tgz",
+ "integrity": "sha512-J3+uiPmKTeyefQBy4F0fz5sBQOj9eUTke6W/do/CplM5zXORQVCOKnrY2CPyDpN9bh4TYutldoiI0BP0Yo2ShA==",
"cpu": [
"x64"
],
@@ -2223,9 +2356,9 @@
}
},
"node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": {
- "version": "4.0.0-beta.3",
- "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.0.0-beta.3.tgz",
- "integrity": "sha512-szLw3+50bgAubvoFrynnt6ELbiLd9A/rYpchfA5AnWUakz29IxP7ZYruCkOnYnW9+KRTNv4kFSsRlPJAEJY5sw==",
+ "version": "4.0.0-beta.6",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.0.0-beta.6.tgz",
+ "integrity": "sha512-oWAwN6LjX2KH8ej0a/Uc1qnuy0ZSyAwOoJ1Fm2s38ipDmvxC8ARkNfWbYKN/D7dFhY7T3NMV4qjzamFKsrgchQ==",
"cpu": [
"arm"
],
@@ -2240,9 +2373,9 @@
}
},
"node_modules/@tailwindcss/oxide-linux-arm64-gnu": {
- "version": "4.0.0-beta.3",
- "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.0.0-beta.3.tgz",
- "integrity": "sha512-BpsBhwgW1V152GQ7FepJR1zqq17oyl3pVe2UyTCIPv92xCwJQ+eDm2vTvaNF9L6dznBVpppMPPfDfxk4KGvgTg==",
+ "version": "4.0.0-beta.6",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.0.0-beta.6.tgz",
+ "integrity": "sha512-p5jDtF6P3gOPl4eOH0YsN09yx/kXqLbgy4VMnOA9DB6Nlt+RVwM+JDa+RK/GAHL/qkAqO6YBEHeBURbWOeSuBw==",
"cpu": [
"arm64"
],
@@ -2257,9 +2390,9 @@
}
},
"node_modules/@tailwindcss/oxide-linux-arm64-musl": {
- "version": "4.0.0-beta.3",
- "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.0.0-beta.3.tgz",
- "integrity": "sha512-S4+PO+C10cG58sNb9qcjPN0A7q9UUxUFdGjetrNVN/t1JseFNOy1OhPp7oQCiXwCYye7vZzKNAUJK9nIGLAMEg==",
+ "version": "4.0.0-beta.6",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.0.0-beta.6.tgz",
+ "integrity": "sha512-ZI92S4LFuXx50gzkv98RXmybbRga183Y3NwBrQ+PfbRUOgDR0/tyT3Zh4CF/0eL9zzxa1mIE7cBbQjXNnejYqQ==",
"cpu": [
"arm64"
],
@@ -2274,9 +2407,9 @@
}
},
"node_modules/@tailwindcss/oxide-linux-x64-gnu": {
- "version": "4.0.0-beta.3",
- "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.0.0-beta.3.tgz",
- "integrity": "sha512-iAGIPAE26xNAbHSaTpu8N2+eG0csOpJ+ukOoKvoQWKArjIfquRw/7XNX1A6pTMvVteFvKPt4e305U7kdf3KtfA==",
+ "version": "4.0.0-beta.6",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.0.0-beta.6.tgz",
+ "integrity": "sha512-F0z48W0Yksrw+xg0GK54wUFa0KmFO9lpbKy2u/2yZtHs+ZwJ55PjdljjW1OJzEHpD81AT+8DT1PhNCkaqpOlqg==",
"cpu": [
"x64"
],
@@ -2291,9 +2424,9 @@
}
},
"node_modules/@tailwindcss/oxide-linux-x64-musl": {
- "version": "4.0.0-beta.3",
- "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.0.0-beta.3.tgz",
- "integrity": "sha512-dKeqjuK94YG+INIYpcfrynq9B5YkrBXEBsX26p1g0K6ai42nzO3Eg/fEadePSqGUBjL1CjtR4pChqaEUPNq1Xw==",
+ "version": "4.0.0-beta.6",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.0.0-beta.6.tgz",
+ "integrity": "sha512-GQx5f3qzLuAO7s1NTGY8PDhiEvrRTgYQhGN8HzH1LhP+URSbwgysyHKWFacejWrZS2azr6jlE84usxk8yn/7Xg==",
"cpu": [
"x64"
],
@@ -2308,9 +2441,9 @@
}
},
"node_modules/@tailwindcss/oxide-win32-arm64-msvc": {
- "version": "4.0.0-beta.3",
- "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.0.0-beta.3.tgz",
- "integrity": "sha512-AEHX9depJFa3GCxmV9s+abklPPo0OmL2uNpPBCumk6N4GLUpmXNpkDlEYeSgggHPRwoSyfvbs957Ahvf5E4v4w==",
+ "version": "4.0.0-beta.6",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.0.0-beta.6.tgz",
+ "integrity": "sha512-DUs1A5rVK1Da7XvY2FzVgS+5vinwVDOeXgOsL6dblL8ag70wlwzZjyB3YRbxKRekPynwKdILgIv8/TYE3cv7AQ==",
"cpu": [
"arm64"
],
@@ -2325,9 +2458,9 @@
}
},
"node_modules/@tailwindcss/oxide-win32-x64-msvc": {
- "version": "4.0.0-beta.3",
- "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.0.0-beta.3.tgz",
- "integrity": "sha512-hb24QffsW/9dM+6DgLv5VbTJKGLgfXMjIF47KLCqkhuZRvkQoSPHT6kXJSerEkO3rY3ptCxkPIhyfudACeHMSQ==",
+ "version": "4.0.0-beta.6",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.0.0-beta.6.tgz",
+ "integrity": "sha512-VRsHAs3QBZa88N2Bp+LOV1vxr6f82L3KtamLIhyNTYXnEQjJxazaGwVow0VzN9sru2MTvcXjVFwdd9hUbeBKbA==",
"cpu": [
"x64"
],
@@ -2358,20 +2491,19 @@
}
},
"node_modules/@tailwindcss/vite": {
- "version": "4.0.0-beta.3",
- "resolved": "https://registry.npmjs.org/@tailwindcss/vite/-/vite-4.0.0-beta.3.tgz",
- "integrity": "sha512-OEnRluaa3hvjnCQhY11YN8GiPoUbXQL5Qb/727q+3FBiGA1vIqrVbIJ01Z256bkaZLCl+AUyqCGasRd2jsSVLA==",
+ "version": "4.0.0-beta.6",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/vite/-/vite-4.0.0-beta.6.tgz",
+ "integrity": "sha512-SDlW8wrfhoGvEmNdbxdjPD0RJV5ErPegeJQFXNlS6CF815tzMMTekToIeMJphvwUO6w2TLSjvO9w3F9Z0ElMgQ==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@tailwindcss/node": "4.0.0-beta.3",
- "@tailwindcss/oxide": "4.0.0-beta.3",
+ "@tailwindcss/node": "4.0.0-beta.6",
+ "@tailwindcss/oxide": "4.0.0-beta.6",
"lightningcss": "^1.26.0",
- "svelte-preprocess": "^6.0.2",
- "tailwindcss": "4.0.0-beta.3"
+ "tailwindcss": "4.0.0-beta.6"
},
"peerDependencies": {
- "vite": "^5.2.0"
+ "vite": "^5.2.0 || ^6"
}
},
"node_modules/@types/babel__core": {
@@ -2429,6 +2561,13 @@
"bun-types": "1.1.37"
}
},
+ "node_modules/@types/diff-match-patch": {
+ "version": "1.0.36",
+ "resolved": "https://registry.npmjs.org/@types/diff-match-patch/-/diff-match-patch-1.0.36.tgz",
+ "integrity": "sha512-xFdR6tkm0MWvBfO8xXCSsinYxHcqkQUlcHeSpMC2ukzOb6lwQAfDmW+Qt0AvlGd8HpsS28qKsB+oPeJn9I39jg==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/@types/estree": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz",
@@ -2470,28 +2609,20 @@
"@types/node": "*"
}
},
- "node_modules/@types/prop-types": {
- "version": "15.7.13",
- "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.13.tgz",
- "integrity": "sha512-hCZTSvwbzWGvhqxp/RqVqwU999pBf2vp7hzIjiYOsl8wqOmUxkQ6ddw1cV3l8811+kdUFus/q4d1Y3E3SyEifA==",
- "dev": true,
- "license": "MIT"
- },
"node_modules/@types/react": {
- "version": "18.3.12",
- "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.12.tgz",
- "integrity": "sha512-D2wOSq/d6Agt28q7rSI3jhU7G6aiuzljDGZ2hTZHIkrTLUI+AF3WMeKkEZ9nN2fkBAlcktT6vcZjDFiIhMYEQw==",
+ "version": "19.0.1",
+ "resolved": "https://registry.npmjs.org/@types/react/-/react-19.0.1.tgz",
+ "integrity": "sha512-YW6614BDhqbpR5KtUYzTA+zlA7nayzJRA9ljz9CQoxthR0sDisYZLuvSMsil36t4EH/uAt8T52Xb4sVw17G+SQ==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@types/prop-types": "*",
"csstype": "^3.0.2"
}
},
"node_modules/@types/react-dom": {
- "version": "18.3.1",
- "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.1.tgz",
- "integrity": "sha512-qW1Mfv8taImTthu4KoXgDfLuk4bydU6Q/TkADnDWWHwi4NX4BR+LWfTp2sVmTqRrsHvyDDTelgelxJ+SsejKKQ==",
+ "version": "19.0.1",
+ "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.0.1.tgz",
+ "integrity": "sha512-hljHij7MpWPKF6u5vojuyfV0YA4YURsQG7KT6SzV0Zs2BXAtgdTxG6A229Ub/xiWV4w/7JL8fi6aAyjshH4meA==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -2509,17 +2640,17 @@
}
},
"node_modules/@typescript-eslint/eslint-plugin": {
- "version": "8.16.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.16.0.tgz",
- "integrity": "sha512-5YTHKV8MYlyMI6BaEG7crQ9BhSc8RxzshOReKwZwRWN0+XvvTOm+L/UYLCYxFpfwYuAAqhxiq4yae0CMFwbL7Q==",
+ "version": "8.17.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.17.0.tgz",
+ "integrity": "sha512-HU1KAdW3Tt8zQkdvNoIijfWDMvdSweFYm4hWh+KwhPstv+sCmWb89hCIP8msFm9N1R/ooh9honpSuvqKWlYy3w==",
"dev": true,
"license": "MIT",
"dependencies": {
"@eslint-community/regexpp": "^4.10.0",
- "@typescript-eslint/scope-manager": "8.16.0",
- "@typescript-eslint/type-utils": "8.16.0",
- "@typescript-eslint/utils": "8.16.0",
- "@typescript-eslint/visitor-keys": "8.16.0",
+ "@typescript-eslint/scope-manager": "8.17.0",
+ "@typescript-eslint/type-utils": "8.17.0",
+ "@typescript-eslint/utils": "8.17.0",
+ "@typescript-eslint/visitor-keys": "8.17.0",
"graphemer": "^1.4.0",
"ignore": "^5.3.1",
"natural-compare": "^1.4.0",
@@ -2543,16 +2674,16 @@
}
},
"node_modules/@typescript-eslint/parser": {
- "version": "8.16.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.16.0.tgz",
- "integrity": "sha512-D7DbgGFtsqIPIFMPJwCad9Gfi/hC0PWErRRHFnaCWoEDYi5tQUDiJCTmGUbBiLzjqAck4KcXt9Ayj0CNlIrF+w==",
+ "version": "8.17.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.17.0.tgz",
+ "integrity": "sha512-Drp39TXuUlD49F7ilHHCG7TTg8IkA+hxCuULdmzWYICxGXvDXmDmWEjJYZQYgf6l/TFfYNE167m7isnc3xlIEg==",
"dev": true,
"license": "BSD-2-Clause",
"dependencies": {
- "@typescript-eslint/scope-manager": "8.16.0",
- "@typescript-eslint/types": "8.16.0",
- "@typescript-eslint/typescript-estree": "8.16.0",
- "@typescript-eslint/visitor-keys": "8.16.0",
+ "@typescript-eslint/scope-manager": "8.17.0",
+ "@typescript-eslint/types": "8.17.0",
+ "@typescript-eslint/typescript-estree": "8.17.0",
+ "@typescript-eslint/visitor-keys": "8.17.0",
"debug": "^4.3.4"
},
"engines": {
@@ -2572,14 +2703,14 @@
}
},
"node_modules/@typescript-eslint/scope-manager": {
- "version": "8.16.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.16.0.tgz",
- "integrity": "sha512-mwsZWubQvBki2t5565uxF0EYvG+FwdFb8bMtDuGQLdCCnGPrDEDvm1gtfynuKlnpzeBRqdFCkMf9jg1fnAK8sg==",
+ "version": "8.17.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.17.0.tgz",
+ "integrity": "sha512-/ewp4XjvnxaREtqsZjF4Mfn078RD/9GmiEAtTeLQ7yFdKnqwTOgRMSvFz4et9U5RiJQ15WTGXPLj89zGusvxBg==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@typescript-eslint/types": "8.16.0",
- "@typescript-eslint/visitor-keys": "8.16.0"
+ "@typescript-eslint/types": "8.17.0",
+ "@typescript-eslint/visitor-keys": "8.17.0"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -2590,14 +2721,14 @@
}
},
"node_modules/@typescript-eslint/type-utils": {
- "version": "8.16.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.16.0.tgz",
- "integrity": "sha512-IqZHGG+g1XCWX9NyqnI/0CX5LL8/18awQqmkZSl2ynn8F76j579dByc0jhfVSnSnhf7zv76mKBQv9HQFKvDCgg==",
+ "version": "8.17.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.17.0.tgz",
+ "integrity": "sha512-q38llWJYPd63rRnJ6wY/ZQqIzPrBCkPdpIsaCfkR3Q4t3p6sb422zougfad4TFW9+ElIFLVDzWGiGAfbb/v2qw==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@typescript-eslint/typescript-estree": "8.16.0",
- "@typescript-eslint/utils": "8.16.0",
+ "@typescript-eslint/typescript-estree": "8.17.0",
+ "@typescript-eslint/utils": "8.17.0",
"debug": "^4.3.4",
"ts-api-utils": "^1.3.0"
},
@@ -2618,9 +2749,9 @@
}
},
"node_modules/@typescript-eslint/types": {
- "version": "8.16.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.16.0.tgz",
- "integrity": "sha512-NzrHj6thBAOSE4d9bsuRNMvk+BvaQvmY4dDglgkgGC0EW/tB3Kelnp3tAKH87GEwzoxgeQn9fNGRyFJM/xd+GQ==",
+ "version": "8.17.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.17.0.tgz",
+ "integrity": "sha512-gY2TVzeve3z6crqh2Ic7Cr+CAv6pfb0Egee7J5UAVWCpVvDI/F71wNfolIim4FE6hT15EbpZFVUj9j5i38jYXA==",
"dev": true,
"license": "MIT",
"engines": {
@@ -2632,14 +2763,14 @@
}
},
"node_modules/@typescript-eslint/typescript-estree": {
- "version": "8.16.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.16.0.tgz",
- "integrity": "sha512-E2+9IzzXMc1iaBy9zmo+UYvluE3TW7bCGWSF41hVWUE01o8nzr1rvOQYSxelxr6StUvRcTMe633eY8mXASMaNw==",
+ "version": "8.17.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.17.0.tgz",
+ "integrity": "sha512-JqkOopc1nRKZpX+opvKqnM3XUlM7LpFMD0lYxTqOTKQfCWAmxw45e3qlOCsEqEB2yuacujivudOFpCnqkBDNMw==",
"dev": true,
"license": "BSD-2-Clause",
"dependencies": {
- "@typescript-eslint/types": "8.16.0",
- "@typescript-eslint/visitor-keys": "8.16.0",
+ "@typescript-eslint/types": "8.17.0",
+ "@typescript-eslint/visitor-keys": "8.17.0",
"debug": "^4.3.4",
"fast-glob": "^3.3.2",
"is-glob": "^4.0.3",
@@ -2677,16 +2808,16 @@
}
},
"node_modules/@typescript-eslint/utils": {
- "version": "8.16.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.16.0.tgz",
- "integrity": "sha512-C1zRy/mOL8Pj157GiX4kaw7iyRLKfJXBR3L82hk5kS/GyHcOFmy4YUq/zfZti72I9wnuQtA/+xzft4wCC8PJdA==",
+ "version": "8.17.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.17.0.tgz",
+ "integrity": "sha512-bQC8BnEkxqG8HBGKwG9wXlZqg37RKSMY7v/X8VEWD8JG2JuTHuNK0VFvMPMUKQcbk6B+tf05k+4AShAEtCtJ/w==",
"dev": true,
"license": "MIT",
"dependencies": {
"@eslint-community/eslint-utils": "^4.4.0",
- "@typescript-eslint/scope-manager": "8.16.0",
- "@typescript-eslint/types": "8.16.0",
- "@typescript-eslint/typescript-estree": "8.16.0"
+ "@typescript-eslint/scope-manager": "8.17.0",
+ "@typescript-eslint/types": "8.17.0",
+ "@typescript-eslint/typescript-estree": "8.17.0"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -2705,13 +2836,13 @@
}
},
"node_modules/@typescript-eslint/visitor-keys": {
- "version": "8.16.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.16.0.tgz",
- "integrity": "sha512-pq19gbaMOmFE3CbL0ZB8J8BFCo2ckfHBfaIsaOZgBIF4EoISJIdLX5xRhd0FGB0LlHReNRuzoJoMGpTjq8F2CQ==",
+ "version": "8.17.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.17.0.tgz",
+ "integrity": "sha512-1Hm7THLpO6ww5QU6H/Qp+AusUUl+z/CAm3cNZZ0jQvon9yicgO7Rwd+/WWRpMKLYV6p2UvdbR27c86rzCPpreg==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@typescript-eslint/types": "8.16.0",
+ "@typescript-eslint/types": "8.17.0",
"eslint-visitor-keys": "^4.2.0"
},
"engines": {
@@ -2756,14 +2887,14 @@
}
},
"node_modules/@vitest/expect": {
- "version": "2.1.6",
- "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-2.1.6.tgz",
- "integrity": "sha512-9M1UR9CAmrhJOMoSwVnPh2rELPKhYo0m/CSgqw9PyStpxtkwhmdM6XYlXGKeYyERY1N6EIuzkQ7e3Lm1WKCoUg==",
+ "version": "2.1.8",
+ "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-2.1.8.tgz",
+ "integrity": "sha512-8ytZ/fFHq2g4PJVAtDX57mayemKgDR6X3Oa2Foro+EygiOJHUXhCqBAAKQYYajZpFoIfvBCF1j6R6IYRSIUFuw==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@vitest/spy": "2.1.6",
- "@vitest/utils": "2.1.6",
+ "@vitest/spy": "2.1.8",
+ "@vitest/utils": "2.1.8",
"chai": "^5.1.2",
"tinyrainbow": "^1.2.0"
},
@@ -2771,57 +2902,10 @@
"url": "https://opencollective.com/vitest"
}
},
- "node_modules/@vitest/mocker": {
- "version": "2.1.6",
- "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-2.1.6.tgz",
- "integrity": "sha512-MHZp2Z+Q/A3am5oD4WSH04f9B0T7UvwEb+v5W0kCYMhtXGYbdyl2NUk1wdSMqGthmhpiThPDp/hEoVwu16+u1A==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@vitest/spy": "2.1.6",
- "estree-walker": "^3.0.3",
- "magic-string": "^0.30.12"
- },
- "funding": {
- "url": "https://opencollective.com/vitest"
- },
- "peerDependencies": {
- "msw": "^2.4.9",
- "vite": "^5.0.0 || ^6.0.0"
- },
- "peerDependenciesMeta": {
- "msw": {
- "optional": true
- },
- "vite": {
- "optional": true
- }
- }
- },
- "node_modules/@vitest/mocker/node_modules/estree-walker": {
- "version": "3.0.3",
- "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz",
- "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@types/estree": "^1.0.0"
- }
- },
- "node_modules/@vitest/mocker/node_modules/magic-string": {
- "version": "0.30.14",
- "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.14.tgz",
- "integrity": "sha512-5c99P1WKTed11ZC0HMJOj6CDIue6F8ySu+bJL+85q1zBEIY8IklrJ1eiKC2NDRh3Ct3FcvmJPyQHb9erXMTJNw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@jridgewell/sourcemap-codec": "^1.5.0"
- }
- },
"node_modules/@vitest/pretty-format": {
- "version": "2.1.6",
- "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-2.1.6.tgz",
- "integrity": "sha512-exZyLcEnHgDMKc54TtHca4McV4sKT+NKAe9ix/yhd/qkYb/TP8HTyXRFDijV19qKqTZM0hPL4753zU/U8L/gAA==",
+ "version": "2.1.8",
+ "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-2.1.8.tgz",
+ "integrity": "sha512-9HiSZ9zpqNLKlbIDRWOnAWqgcA7xu+8YxXSekhr0Ykab7PAYFkhkwoqVArPOtJhPmYeE2YHgKZlj3CP36z2AJQ==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -2832,13 +2916,13 @@
}
},
"node_modules/@vitest/runner": {
- "version": "2.1.6",
- "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-2.1.6.tgz",
- "integrity": "sha512-SjkRGSFyrA82m5nz7To4CkRSEVWn/rwQISHoia/DB8c6IHIhaE/UNAo+7UfeaeJRE979XceGl00LNkIz09RFsA==",
+ "version": "2.1.8",
+ "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-2.1.8.tgz",
+ "integrity": "sha512-17ub8vQstRnRlIU5k50bG+QOMLHRhYPAna5tw8tYbj+jzjcspnwnwtPtiOlkuKC4+ixDPTuLZiqiWWQ2PSXHVg==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@vitest/utils": "2.1.6",
+ "@vitest/utils": "2.1.8",
"pathe": "^1.1.2"
},
"funding": {
@@ -2846,13 +2930,13 @@
}
},
"node_modules/@vitest/snapshot": {
- "version": "2.1.6",
- "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-2.1.6.tgz",
- "integrity": "sha512-5JTWHw8iS9l3v4/VSuthCndw1lN/hpPB+mlgn1BUhFbobeIUj1J1V/Bj2t2ovGEmkXLTckFjQddsxS5T6LuVWw==",
+ "version": "2.1.8",
+ "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-2.1.8.tgz",
+ "integrity": "sha512-20T7xRFbmnkfcmgVEz+z3AU/3b0cEzZOt/zmnvZEctg64/QZbSDJEVm9fLnnlSi74KibmRsO9/Qabi+t0vCRPg==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@vitest/pretty-format": "2.1.6",
+ "@vitest/pretty-format": "2.1.8",
"magic-string": "^0.30.12",
"pathe": "^1.1.2"
},
@@ -2871,9 +2955,9 @@
}
},
"node_modules/@vitest/spy": {
- "version": "2.1.6",
- "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-2.1.6.tgz",
- "integrity": "sha512-oTFObV8bd4SDdRka5O+mSh5w9irgx5IetrD5i+OsUUsk/shsBoHifwCzy45SAORzAhtNiprUVaK3hSCCzZh1jQ==",
+ "version": "2.1.8",
+ "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-2.1.8.tgz",
+ "integrity": "sha512-5swjf2q95gXeYPevtW0BLk6H8+bPlMb4Vw/9Em4hFxDcaOxS+e0LOX4yqNxoHzMR2akEB2xfpnWUzkZokmgWDg==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -2884,13 +2968,13 @@
}
},
"node_modules/@vitest/utils": {
- "version": "2.1.6",
- "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-2.1.6.tgz",
- "integrity": "sha512-ixNkFy3k4vokOUTU2blIUvOgKq/N2PW8vKIjZZYsGJCMX69MRa9J2sKqX5hY/k5O5Gty3YJChepkqZ3KM9LyIQ==",
+ "version": "2.1.8",
+ "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-2.1.8.tgz",
+ "integrity": "sha512-dwSoui6djdwbfFmIgbIjX2ZhIoG7Ex/+xpxyiEgIGzjliY8xGkcpITKTlp6B4MgtGkF2ilvm97cPM96XZaAgcA==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@vitest/pretty-format": "2.1.6",
+ "@vitest/pretty-format": "2.1.8",
"loupe": "^3.1.2",
"tinyrainbow": "^1.2.0"
},
@@ -2921,17 +3005,6 @@
"acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"
}
},
- "node_modules/acorn-typescript": {
- "version": "1.4.13",
- "resolved": "https://registry.npmjs.org/acorn-typescript/-/acorn-typescript-1.4.13.tgz",
- "integrity": "sha512-xsc9Xv0xlVfwp2o7sQ+GCQ1PgbkdcpWdTzrwXxO3xDMTAywVS3oXVOcOHuRjAPkS4P9b+yc/qNF15460v+jp4Q==",
- "dev": true,
- "license": "MIT",
- "peer": true,
- "peerDependencies": {
- "acorn": ">=8.9.0"
- }
- },
"node_modules/acorn-walk": {
"version": "8.3.4",
"resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz",
@@ -2945,6 +3018,37 @@
"node": ">=0.4.0"
}
},
+ "node_modules/ai": {
+ "version": "4.0.13",
+ "resolved": "https://registry.npmjs.org/ai/-/ai-4.0.13.tgz",
+ "integrity": "sha512-ic+qEVPQhfLpGPnZ2M55ErofeuKaD/TQebeh0qSPwv2PF+dQwsPr2Pw+JNYXahezAOaxFNdrDPz0EF1kKcSFSw==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@ai-sdk/provider": "1.0.1",
+ "@ai-sdk/provider-utils": "2.0.3",
+ "@ai-sdk/react": "1.0.5",
+ "@ai-sdk/ui-utils": "1.0.4",
+ "@opentelemetry/api": "1.9.0",
+ "jsondiffpatch": "0.6.0",
+ "zod-to-json-schema": "^3.23.5"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "peerDependencies": {
+ "react": "^18 || ^19 || ^19.0.0-rc",
+ "zod": "^3.0.0"
+ },
+ "peerDependenciesMeta": {
+ "react": {
+ "optional": true
+ },
+ "zod": {
+ "optional": true
+ }
+ }
+ },
"node_modules/ajv": {
"version": "6.12.6",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
@@ -3022,17 +3126,6 @@
"sprintf-js": "~1.0.2"
}
},
- "node_modules/aria-query": {
- "version": "5.3.2",
- "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.2.tgz",
- "integrity": "sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==",
- "dev": true,
- "license": "Apache-2.0",
- "peer": true,
- "engines": {
- "node": ">= 0.4"
- }
- },
"node_modules/array-buffer-byte-length": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.1.tgz",
@@ -3237,17 +3330,6 @@
"url": "https://github.com/sponsors/ljharb"
}
},
- "node_modules/axobject-query": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.1.0.tgz",
- "integrity": "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==",
- "dev": true,
- "license": "Apache-2.0",
- "peer": true,
- "engines": {
- "node": ">= 0.4"
- }
- },
"node_modules/balanced-match": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
@@ -3557,6 +3639,13 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/client-only": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz",
+ "integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/cliui": {
"version": "8.0.1",
"resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz",
@@ -3876,6 +3965,13 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/diff-match-patch": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/diff-match-patch/-/diff-match-patch-1.0.5.tgz",
+ "integrity": "sha512-IayShXAgj/QMXgB0IWmKx+rOPuGMhqm5w6jvFxmVenXKIzRqTAAsbBPT3kWQeGANj3jGgvcvv4yK6SxqYmikgw==",
+ "dev": true,
+ "license": "Apache-2.0"
+ },
"node_modules/dir-glob": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz",
@@ -4199,9 +4295,9 @@
}
},
"node_modules/eslint": {
- "version": "9.15.0",
- "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.15.0.tgz",
- "integrity": "sha512-7CrWySmIibCgT1Os28lUU6upBshZ+GxybLOrmRzi08kS8MBuO8QA7pXEgYgY5W8vK3e74xv0lpjo9DbaGU9Rkw==",
+ "version": "9.16.0",
+ "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.16.0.tgz",
+ "integrity": "sha512-whp8mSQI4C8VXd+fLgSM0lh3UlmcFtVwUQjyKCFfsp+2ItAIYhlq/hqGahGqHE6cv9unM41VlqKk2VtKYR2TaA==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -4210,7 +4306,7 @@
"@eslint/config-array": "^0.19.0",
"@eslint/core": "^0.9.0",
"@eslint/eslintrc": "^3.2.0",
- "@eslint/js": "9.15.0",
+ "@eslint/js": "9.16.0",
"@eslint/plugin-kit": "^0.2.3",
"@humanfs/node": "^0.16.6",
"@humanwhocodes/module-importer": "^1.0.1",
@@ -4294,20 +4390,20 @@
}
},
"node_modules/eslint-import-resolver-typescript": {
- "version": "3.6.3",
- "resolved": "https://registry.npmjs.org/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-3.6.3.tgz",
- "integrity": "sha512-ud9aw4szY9cCT1EWWdGv1L1XR6hh2PaRWif0j2QjQ0pgTY/69iw+W0Z4qZv5wHahOl8isEr+k/JnyAqNQkLkIA==",
+ "version": "3.7.0",
+ "resolved": "https://registry.npmjs.org/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-3.7.0.tgz",
+ "integrity": "sha512-Vrwyi8HHxY97K5ebydMtffsWAn1SCR9eol49eCd5fJS4O1WV7PaAjbcjmbfJJSMz/t4Mal212Uz/fQZrOB8mow==",
"dev": true,
"license": "ISC",
"dependencies": {
"@nolyfill/is-core-module": "1.0.39",
- "debug": "^4.3.5",
+ "debug": "^4.3.7",
"enhanced-resolve": "^5.15.0",
- "eslint-module-utils": "^2.8.1",
"fast-glob": "^3.3.2",
"get-tsconfig": "^4.7.5",
"is-bun-module": "^1.0.2",
- "is-glob": "^4.0.3"
+ "is-glob": "^4.0.3",
+ "stable-hash": "^0.0.4"
},
"engines": {
"node": "^14.18.0 || >=16.0.0"
@@ -4469,9 +4565,9 @@
}
},
"node_modules/eslint-plugin-react-hooks": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-5.0.0.tgz",
- "integrity": "sha512-hIOwI+5hYGpJEc4uPRmz2ulCjAGD/N13Lukkh8cLV0i2IRk/bdZDYjgLVHj+U9Z704kLIdIO6iueGvxNur0sgw==",
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-5.1.0.tgz",
+ "integrity": "sha512-mpJRtPgHN2tNAvZ35AMfqeB3Xqeo273QxrHJsbBEPWODRM4r0yB6jfoROqKEYrOn27UtRPpcpHc2UqyBSuUNTw==",
"dev": true,
"license": "MIT",
"engines": {
@@ -4678,14 +4774,6 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/esm-env": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/esm-env/-/esm-env-1.2.1.tgz",
- "integrity": "sha512-U9JedYYjCnadUlXk7e1Kr+aENQhtUaoaV9+gZm1T8LC/YBAPJx3NSPIAurFOC0U5vrdSevnUJS2/wUVxGwPhng==",
- "dev": true,
- "license": "MIT",
- "peer": true
- },
"node_modules/espree": {
"version": "10.3.0",
"resolved": "https://registry.npmjs.org/espree/-/espree-10.3.0.tgz",
@@ -4744,18 +4832,6 @@
"node": ">=0.10"
}
},
- "node_modules/esrap": {
- "version": "1.2.2",
- "resolved": "https://registry.npmjs.org/esrap/-/esrap-1.2.2.tgz",
- "integrity": "sha512-F2pSJklxx1BlQIQgooczXCPHmcWpn6EsP5oo73LQfonG9fIlIENQ8vMmfGXeojP9MrkzUNAfyU5vdFlR9shHAw==",
- "dev": true,
- "license": "MIT",
- "peer": true,
- "dependencies": {
- "@jridgewell/sourcemap-codec": "^1.4.15",
- "@types/estree": "^1.0.1"
- }
- },
"node_modules/esrecurse": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz",
@@ -4796,6 +4872,29 @@
"node": ">=0.10.0"
}
},
+ "node_modules/event-target-shim": {
+ "version": "6.0.2",
+ "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-6.0.2.tgz",
+ "integrity": "sha512-8q3LsZjRezbFZ2PN+uP+Q7pnHUMmAOziU2vA2OwoFaKIXxlxl38IylhSSgUorWu/rf4er67w0ikBqjBFk/pomA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=10.13.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/mysticatea"
+ }
+ },
+ "node_modules/eventsource-parser": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/eventsource-parser/-/eventsource-parser-3.0.0.tgz",
+ "integrity": "sha512-T1C0XCUimhxVQzW4zFipdx0SficT651NnkR0ZSH3yQwh+mFMdLfgjABVi4YtMTtaL4s168593DaoaRLMqryavA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18.0.0"
+ }
+ },
"node_modules/exit-hook": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/exit-hook/-/exit-hook-2.2.1.tgz",
@@ -5681,17 +5780,6 @@
"url": "https://github.com/sponsors/ljharb"
}
},
- "node_modules/is-reference": {
- "version": "3.0.3",
- "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-3.0.3.tgz",
- "integrity": "sha512-ixkJoqQvAP88E6wLydLGGqCJsrFUnqoH6HnaczB8XmDH1oaWU+xxdptvikTgaEhtZ53Ky6YXiBuUI2WXLMCwjw==",
- "dev": true,
- "license": "MIT",
- "peer": true,
- "dependencies": {
- "@types/estree": "^1.0.6"
- }
- },
"node_modules/is-regex": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz",
@@ -5957,6 +6045,13 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/json-schema": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz",
+ "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==",
+ "dev": true,
+ "license": "(AFL-2.1 OR BSD-3-Clause)"
+ },
"node_modules/json-schema-traverse": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
@@ -5984,6 +6079,37 @@
"node": ">=6"
}
},
+ "node_modules/jsondiffpatch": {
+ "version": "0.6.0",
+ "resolved": "https://registry.npmjs.org/jsondiffpatch/-/jsondiffpatch-0.6.0.tgz",
+ "integrity": "sha512-3QItJOXp2AP1uv7waBkao5nCvhEv+QmJAd38Ybq7wNI74Q+BBmnLn4EDKz6yI9xGAIQoUF87qHt+kc1IVxB4zQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/diff-match-patch": "^1.0.36",
+ "chalk": "^5.3.0",
+ "diff-match-patch": "^1.0.5"
+ },
+ "bin": {
+ "jsondiffpatch": "bin/jsondiffpatch.js"
+ },
+ "engines": {
+ "node": "^18.0.0 || >=20.0.0"
+ }
+ },
+ "node_modules/jsondiffpatch/node_modules/chalk": {
+ "version": "5.3.0",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz",
+ "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "^12.17.0 || ^14.13 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/chalk?sponsor=1"
+ }
+ },
"node_modules/jsonfile": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz",
@@ -6273,14 +6399,6 @@
"url": "https://opencollective.com/parcel"
}
},
- "node_modules/locate-character": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/locate-character/-/locate-character-3.0.0.tgz",
- "integrity": "sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA==",
- "dev": true,
- "license": "MIT",
- "peer": true
- },
"node_modules/locate-path": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
@@ -6426,9 +6544,9 @@
}
},
"node_modules/miniflare": {
- "version": "3.20241106.1",
- "resolved": "https://registry.npmjs.org/miniflare/-/miniflare-3.20241106.1.tgz",
- "integrity": "sha512-dM3RBlJE8rUFxnqlPCaFCq0E7qQqEQvKbYX7W/APGCK+rLcyLmEBzC4GQR/niXdNM/oV6gdg9AA50ghnn2ALuw==",
+ "version": "3.20241205.0",
+ "resolved": "https://registry.npmjs.org/miniflare/-/miniflare-3.20241205.0.tgz",
+ "integrity": "sha512-Z0cTtIf6ZrcAJ3SrOI9EUM3s4dkGhNeU6Ubl8sroYhsPVD+rtz3m5+p6McHFWCkcMff1o60X5XEKVTmkz0gbpA==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -6440,7 +6558,7 @@
"glob-to-regexp": "^0.4.1",
"stoppable": "^1.1.0",
"undici": "^5.28.4",
- "workerd": "1.20241106.1",
+ "workerd": "1.20241205.0",
"ws": "^8.18.0",
"youch": "^3.2.2",
"zod": "^3.22.3"
@@ -6855,6 +6973,48 @@
"node": ">=6"
}
},
+ "node_modules/partyserver": {
+ "version": "0.0.57",
+ "resolved": "https://registry.npmjs.org/partyserver/-/partyserver-0.0.57.tgz",
+ "integrity": "sha512-AVoNcslX+z8XjcESoNFC0WLYIH0WdxtnbaRKOHqHfzVOmEDvOlh/WUsWxeRY38f5v6aFH/gyUHNcxiW1KXlabw==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "nanoid": "^5.0.7"
+ },
+ "peerDependencies": {
+ "@cloudflare/workers-types": "^4.20240729.0"
+ }
+ },
+ "node_modules/partyserver/node_modules/nanoid": {
+ "version": "5.0.9",
+ "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-5.0.9.tgz",
+ "integrity": "sha512-Aooyr6MXU6HpvvWXKoVoXwKMs/KyVakWwg7xQfv5/S/RIgJMy0Ifa45H9qqYy7pTCszrHzP21Uk4PZq2HpEM8Q==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "license": "MIT",
+ "bin": {
+ "nanoid": "bin/nanoid.js"
+ },
+ "engines": {
+ "node": "^18 || >=20"
+ }
+ },
+ "node_modules/partysocket": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/partysocket/-/partysocket-1.0.2.tgz",
+ "integrity": "sha512-rAFOUKImaq+VBk2B+2RTBsWEvlnarEP53nchoUHzpVs8V6fG2/estihOTslTQUWHVuHEKDL5k8htG8K3TngyFA==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "event-target-shim": "^6.0.2"
+ }
+ },
"node_modules/path-exists": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
@@ -7050,9 +7210,9 @@
}
},
"node_modules/prettier": {
- "version": "3.4.1",
- "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.4.1.tgz",
- "integrity": "sha512-G+YdqtITVZmOJje6QkXQWzl3fSfMxFwm1tjTyo9exhkmWSqC4Yhd1+lug++IlR2mvRVAxEDDWYkQdeSztajqgg==",
+ "version": "3.4.2",
+ "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.4.2.tgz",
+ "integrity": "sha512-e9MewbtFo+Fevyuxn/4rrcDAaq0IYxPGLvObpQjiZBMAzB9IGmzlnG9RZy3FFas+eBMu2vA0CszMeduow5dIuQ==",
"dev": true,
"license": "MIT",
"bin": {
@@ -7116,30 +7276,26 @@
"license": "MIT"
},
"node_modules/react": {
- "version": "18.3.1",
- "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz",
- "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==",
+ "version": "19.0.0",
+ "resolved": "https://registry.npmjs.org/react/-/react-19.0.0.tgz",
+ "integrity": "sha512-V8AVnmPIICiWpGfm6GLzCR/W5FXLchHop40W4nXBmdlEceh16rCN8O8LNWm5bh5XUX91fh7KpA+W0TgMKmgTpQ==",
"dev": true,
"license": "MIT",
- "dependencies": {
- "loose-envify": "^1.1.0"
- },
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/react-dom": {
- "version": "18.3.1",
- "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz",
- "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==",
+ "version": "19.0.0",
+ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.0.0.tgz",
+ "integrity": "sha512-4GV5sHFG0e/0AD4X+ySy6UJd3jVl1iNsNHdpad0qhABJ11twS3TTBnseqsKurKcsNqCEFeGL3uLpVChpIO3QfQ==",
"dev": true,
"license": "MIT",
"dependencies": {
- "loose-envify": "^1.1.0",
- "scheduler": "^0.23.2"
+ "scheduler": "^0.25.0"
},
"peerDependencies": {
- "react": "^18.3.1"
+ "react": "^19.0.0"
}
},
"node_modules/react-is": {
@@ -7302,16 +7458,6 @@
"url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1"
}
},
- "node_modules/resolve.exports": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.2.tgz",
- "integrity": "sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=10"
- }
- },
"node_modules/reusify": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz",
@@ -7493,14 +7639,18 @@
"license": "MIT"
},
"node_modules/scheduler": {
- "version": "0.23.2",
- "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz",
- "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==",
+ "version": "0.25.0",
+ "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.25.0.tgz",
+ "integrity": "sha512-xFVuu11jh+xcO7JOAGJNOXld8/TcEHK/4CituBUeUb5hqxJLj9YuemAEuvm9gQ/+pgXYfbQuqAkiYu+u7YEsNA==",
"dev": true,
- "license": "MIT",
- "dependencies": {
- "loose-envify": "^1.1.0"
- }
+ "license": "MIT"
+ },
+ "node_modules/secure-json-parse": {
+ "version": "2.7.0",
+ "resolved": "https://registry.npmjs.org/secure-json-parse/-/secure-json-parse-2.7.0.tgz",
+ "integrity": "sha512-6aU+Rwsezw7VR8/nyvKTx8QpWH9FrcYiXXlqC4z5d5XQBDRqtbfsRjnwGyqbi3gddNtWHuEk9OANUotL26qKUw==",
+ "dev": true,
+ "license": "BSD-3-Clause"
},
"node_modules/selfsigned": {
"version": "2.4.1",
@@ -7694,6 +7844,13 @@
"dev": true,
"license": "BSD-3-Clause"
},
+ "node_modules/stable-hash": {
+ "version": "0.0.4",
+ "resolved": "https://registry.npmjs.org/stable-hash/-/stable-hash-0.0.4.tgz",
+ "integrity": "sha512-LjdcbuBeLcdETCrPn9i8AYAZ1eCtu4ECAWtP7UleOiZ9LzVxRzzUZEoZ8zB24nhkQnDWyET0I+3sWokSDS3E7g==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/stackback": {
"version": "0.0.2",
"resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz",
@@ -7930,99 +8087,6 @@
"url": "https://github.com/sponsors/ljharb"
}
},
- "node_modules/svelte": {
- "version": "5.2.10",
- "resolved": "https://registry.npmjs.org/svelte/-/svelte-5.2.10.tgz",
- "integrity": "sha512-ON0OyO7vOmSjTc9mLjusu3vf1I7BvjovbiRB7j84F1WZMXV6dR+Tj4btIzxQxMHfzbGskaFmRa7qjgmBSVBnhQ==",
- "dev": true,
- "license": "MIT",
- "peer": true,
- "dependencies": {
- "@ampproject/remapping": "^2.3.0",
- "@jridgewell/sourcemap-codec": "^1.5.0",
- "@types/estree": "^1.0.5",
- "acorn": "^8.12.1",
- "acorn-typescript": "^1.4.13",
- "aria-query": "^5.3.1",
- "axobject-query": "^4.1.0",
- "esm-env": "^1.2.0",
- "esrap": "^1.2.2",
- "is-reference": "^3.0.3",
- "locate-character": "^3.0.0",
- "magic-string": "^0.30.11",
- "zimmerframe": "^1.1.2"
- },
- "engines": {
- "node": ">=18"
- }
- },
- "node_modules/svelte-preprocess": {
- "version": "6.0.3",
- "resolved": "https://registry.npmjs.org/svelte-preprocess/-/svelte-preprocess-6.0.3.tgz",
- "integrity": "sha512-PLG2k05qHdhmRG7zR/dyo5qKvakhm8IJ+hD2eFRQmMLHp7X3eJnjeupUtvuRpbNiF31RjVw45W+abDwHEmP5OA==",
- "dev": true,
- "hasInstallScript": true,
- "license": "MIT",
- "engines": {
- "node": ">= 18.0.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.10.2",
- "coffeescript": "^2.5.1",
- "less": "^3.11.3 || ^4.0.0",
- "postcss": "^7 || ^8",
- "postcss-load-config": ">=3",
- "pug": "^3.0.0",
- "sass": "^1.26.8",
- "stylus": ">=0.55",
- "sugarss": "^2.0.0 || ^3.0.0 || ^4.0.0",
- "svelte": "^4.0.0 || ^5.0.0-next.100 || ^5.0.0",
- "typescript": "^5.0.0"
- },
- "peerDependenciesMeta": {
- "@babel/core": {
- "optional": true
- },
- "coffeescript": {
- "optional": true
- },
- "less": {
- "optional": true
- },
- "postcss": {
- "optional": true
- },
- "postcss-load-config": {
- "optional": true
- },
- "pug": {
- "optional": true
- },
- "sass": {
- "optional": true
- },
- "stylus": {
- "optional": true
- },
- "sugarss": {
- "optional": true
- },
- "typescript": {
- "optional": true
- }
- }
- },
- "node_modules/svelte/node_modules/magic-string": {
- "version": "0.30.14",
- "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.14.tgz",
- "integrity": "sha512-5c99P1WKTed11ZC0HMJOj6CDIue6F8ySu+bJL+85q1zBEIY8IklrJ1eiKC2NDRh3Ct3FcvmJPyQHb9erXMTJNw==",
- "dev": true,
- "license": "MIT",
- "peer": true,
- "dependencies": {
- "@jridgewell/sourcemap-codec": "^1.5.0"
- }
- },
"node_modules/sync-content": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/sync-content/-/sync-content-2.0.1.tgz",
@@ -8047,9 +8111,9 @@
}
},
"node_modules/tailwindcss": {
- "version": "4.0.0-beta.3",
- "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.0.0-beta.3.tgz",
- "integrity": "sha512-Cem7SF6OYcijYA1ZOGmuZHxk704iOxsRboFCXIpSJSR0XFft/NNz93Yoo0kHZIGNlqZmnQItI7JUSdR++Y9hZQ==",
+ "version": "4.0.0-beta.6",
+ "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.0.0-beta.6.tgz",
+ "integrity": "sha512-eCCuMk3H65w4J/QWkjxfeWoBSKbCD3E6Uj2LA6Xkkl4eMa1MXuwVpIU1RXcLIp+BVsXGEZMP7i7uJig7KxfAXQ==",
"dev": true,
"license": "MIT"
},
@@ -8076,6 +8140,19 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/throttleit": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/throttleit/-/throttleit-2.1.0.tgz",
+ "integrity": "sha512-nt6AMGKW1p/70DF/hGBdJB57B8Tspmbp5gfJ8ilhLnt7kkr2ye7hzD6NVG8GGErk2HWF34igrL2CXmNIkzKqKw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/tinybench": {
"version": "2.9.0",
"resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz",
@@ -8436,9 +8513,9 @@
},
"node_modules/unenv": {
"name": "unenv-nightly",
- "version": "2.0.0-20241121-161142-806b5c0",
- "resolved": "https://registry.npmjs.org/unenv-nightly/-/unenv-nightly-2.0.0-20241121-161142-806b5c0.tgz",
- "integrity": "sha512-RnFOasE/O0Q55gBkNB1b84OgKttgLEijGO0JCWpbn+O4XxpyCQg89NmcqQ5RGUiy4y+rMIrKzePTquQcLQF5pQ==",
+ "version": "2.0.0-20241204-140205-a5d5190",
+ "resolved": "https://registry.npmjs.org/unenv-nightly/-/unenv-nightly-2.0.0-20241204-140205-a5d5190.tgz",
+ "integrity": "sha512-jpmAytLeiiW01pl5bhVn9wYJ4vtiLdhGe10oXlJBuQEX8mxjxO8BlEXGHU4vr4yEikjFP1wsomTHt/CLU8kUwg==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -8499,6 +8576,16 @@
"punycode": "^2.1.0"
}
},
+ "node_modules/use-sync-external-store": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.4.0.tgz",
+ "integrity": "sha512-9WXSPC5fMv61vaupRkCKCxsPxBocVnwakBEkMIHHpkTTg6icbJtg6jzgtLDm4bl3cSHAca52rYWih0k4K3PfHw==",
+ "dev": true,
+ "license": "MIT",
+ "peerDependencies": {
+ "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
+ }
+ },
"node_modules/util-deprecate": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
@@ -8507,9 +8594,9 @@
"license": "MIT"
},
"node_modules/vite": {
- "version": "6.0.1",
- "resolved": "https://registry.npmjs.org/vite/-/vite-6.0.1.tgz",
- "integrity": "sha512-Ldn6gorLGr4mCdFnmeAOLweJxZ34HjKnDm4HGo6P66IEqTxQb36VEdFJQENKxWjupNfoIjvRUnswjn1hpYEpjQ==",
+ "version": "6.0.3",
+ "resolved": "https://registry.npmjs.org/vite/-/vite-6.0.3.tgz",
+ "integrity": "sha512-Cmuo5P0ENTN6HxLSo6IHsjCLn/81Vgrp81oaiFFMRa8gGDj5xEjIcEpf2ZymZtZR8oU0P2JX5WuUp/rlXcHkAw==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -8579,9 +8666,9 @@
}
},
"node_modules/vite-node": {
- "version": "2.1.6",
- "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-2.1.6.tgz",
- "integrity": "sha512-DBfJY0n9JUwnyLxPSSUmEePT21j8JZp/sR9n+/gBwQU6DcQOioPdb8/pibWfXForbirSagZCilseYIwaL3f95A==",
+ "version": "2.1.8",
+ "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-2.1.8.tgz",
+ "integrity": "sha512-uPAwSr57kYjAUux+8E2j0q0Fxpn8M9VoyfGiRI8Kfktz9NcYMCenwY5RnZxnF1WTu3TGiYipirIzacLL3VVGFg==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -8589,32 +8676,92 @@
"debug": "^4.3.7",
"es-module-lexer": "^1.5.4",
"pathe": "^1.1.2",
- "vite": "^5.0.0 || ^6.0.0"
+ "vite": "^5.0.0"
},
"bin": {
"vite-node": "vite-node.mjs"
},
"engines": {
- "node": "^18.0.0 || ^20.0.0 || >=22.0.0"
+ "node": "^18.0.0 || >=20.0.0"
},
"funding": {
"url": "https://opencollective.com/vitest"
}
},
+ "node_modules/vite-node/node_modules/vite": {
+ "version": "5.4.11",
+ "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.11.tgz",
+ "integrity": "sha512-c7jFQRklXua0mTzneGW9QVyxFjUgwcihC4bXEtujIo2ouWCe1Ajt/amn2PCxYnhYfd5k09JX3SB7OYWFKYqj8Q==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "esbuild": "^0.21.3",
+ "postcss": "^8.4.43",
+ "rollup": "^4.20.0"
+ },
+ "bin": {
+ "vite": "bin/vite.js"
+ },
+ "engines": {
+ "node": "^18.0.0 || >=20.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/vitejs/vite?sponsor=1"
+ },
+ "optionalDependencies": {
+ "fsevents": "~2.3.3"
+ },
+ "peerDependencies": {
+ "@types/node": "^18.0.0 || >=20.0.0",
+ "less": "*",
+ "lightningcss": "^1.21.0",
+ "sass": "*",
+ "sass-embedded": "*",
+ "stylus": "*",
+ "sugarss": "*",
+ "terser": "^5.4.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/node": {
+ "optional": true
+ },
+ "less": {
+ "optional": true
+ },
+ "lightningcss": {
+ "optional": true
+ },
+ "sass": {
+ "optional": true
+ },
+ "sass-embedded": {
+ "optional": true
+ },
+ "stylus": {
+ "optional": true
+ },
+ "sugarss": {
+ "optional": true
+ },
+ "terser": {
+ "optional": true
+ }
+ }
+ },
"node_modules/vitest": {
- "version": "2.1.6",
- "resolved": "https://registry.npmjs.org/vitest/-/vitest-2.1.6.tgz",
- "integrity": "sha512-isUCkvPL30J4c5O5hgONeFRsDmlw6kzFEdLQHLezmDdKQHy8Ke/B/dgdTMEgU0vm+iZ0TjW8GuK83DiahBoKWQ==",
+ "version": "2.1.8",
+ "resolved": "https://registry.npmjs.org/vitest/-/vitest-2.1.8.tgz",
+ "integrity": "sha512-1vBKTZskHw/aosXqQUlVWWlGUxSJR8YtiyZDJAFeW2kPAeX6S3Sool0mjspO+kXLuxVWlEDDowBAeqeAQefqLQ==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@vitest/expect": "2.1.6",
- "@vitest/mocker": "2.1.6",
- "@vitest/pretty-format": "^2.1.6",
- "@vitest/runner": "2.1.6",
- "@vitest/snapshot": "2.1.6",
- "@vitest/spy": "2.1.6",
- "@vitest/utils": "2.1.6",
+ "@vitest/expect": "2.1.8",
+ "@vitest/mocker": "2.1.8",
+ "@vitest/pretty-format": "^2.1.8",
+ "@vitest/runner": "2.1.8",
+ "@vitest/snapshot": "2.1.8",
+ "@vitest/spy": "2.1.8",
+ "@vitest/utils": "2.1.8",
"chai": "^5.1.2",
"debug": "^4.3.7",
"expect-type": "^1.1.0",
@@ -8625,24 +8772,24 @@
"tinyexec": "^0.3.1",
"tinypool": "^1.0.1",
"tinyrainbow": "^1.2.0",
- "vite": "^5.0.0 || ^6.0.0",
- "vite-node": "2.1.6",
+ "vite": "^5.0.0",
+ "vite-node": "2.1.8",
"why-is-node-running": "^2.3.0"
},
"bin": {
"vitest": "vitest.mjs"
},
"engines": {
- "node": "^18.0.0 || ^20.0.0 || >=22.0.0"
+ "node": "^18.0.0 || >=20.0.0"
},
"funding": {
"url": "https://opencollective.com/vitest"
},
"peerDependencies": {
"@edge-runtime/vm": "*",
- "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0",
- "@vitest/browser": "2.1.6",
- "@vitest/ui": "2.1.6",
+ "@types/node": "^18.0.0 || >=20.0.0",
+ "@vitest/browser": "2.1.8",
+ "@vitest/ui": "2.1.8",
"happy-dom": "*",
"jsdom": "*"
},
@@ -8667,6 +8814,43 @@
}
}
},
+ "node_modules/vitest/node_modules/@vitest/mocker": {
+ "version": "2.1.8",
+ "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-2.1.8.tgz",
+ "integrity": "sha512-7guJ/47I6uqfttp33mgo6ga5Gr1VnL58rcqYKyShoRK9ebu8T5Rs6HN3s1NABiBeVTdWNrwUMcHH54uXZBN4zA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@vitest/spy": "2.1.8",
+ "estree-walker": "^3.0.3",
+ "magic-string": "^0.30.12"
+ },
+ "funding": {
+ "url": "https://opencollective.com/vitest"
+ },
+ "peerDependencies": {
+ "msw": "^2.4.9",
+ "vite": "^5.0.0"
+ },
+ "peerDependenciesMeta": {
+ "msw": {
+ "optional": true
+ },
+ "vite": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/vitest/node_modules/estree-walker": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz",
+ "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/estree": "^1.0.0"
+ }
+ },
"node_modules/vitest/node_modules/magic-string": {
"version": "0.30.14",
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.14.tgz",
@@ -8677,6 +8861,66 @@
"@jridgewell/sourcemap-codec": "^1.5.0"
}
},
+ "node_modules/vitest/node_modules/vite": {
+ "version": "5.4.11",
+ "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.11.tgz",
+ "integrity": "sha512-c7jFQRklXua0mTzneGW9QVyxFjUgwcihC4bXEtujIo2ouWCe1Ajt/amn2PCxYnhYfd5k09JX3SB7OYWFKYqj8Q==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "esbuild": "^0.21.3",
+ "postcss": "^8.4.43",
+ "rollup": "^4.20.0"
+ },
+ "bin": {
+ "vite": "bin/vite.js"
+ },
+ "engines": {
+ "node": "^18.0.0 || >=20.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/vitejs/vite?sponsor=1"
+ },
+ "optionalDependencies": {
+ "fsevents": "~2.3.3"
+ },
+ "peerDependencies": {
+ "@types/node": "^18.0.0 || >=20.0.0",
+ "less": "*",
+ "lightningcss": "^1.21.0",
+ "sass": "*",
+ "sass-embedded": "*",
+ "stylus": "*",
+ "sugarss": "*",
+ "terser": "^5.4.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/node": {
+ "optional": true
+ },
+ "less": {
+ "optional": true
+ },
+ "lightningcss": {
+ "optional": true
+ },
+ "sass": {
+ "optional": true
+ },
+ "sass-embedded": {
+ "optional": true
+ },
+ "stylus": {
+ "optional": true
+ },
+ "sugarss": {
+ "optional": true
+ },
+ "terser": {
+ "optional": true
+ }
+ }
+ },
"node_modules/walk-up-path": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/walk-up-path/-/walk-up-path-4.0.0.tgz",
@@ -8833,9 +9077,9 @@
}
},
"node_modules/workerd": {
- "version": "1.20241106.1",
- "resolved": "https://registry.npmjs.org/workerd/-/workerd-1.20241106.1.tgz",
- "integrity": "sha512-1GdKl0kDw8rrirr/ThcK66Kbl4/jd4h8uHx5g7YHBrnenY5SX1UPuop2cnCzYUxlg55kPjzIqqYslz1muRFgFw==",
+ "version": "1.20241205.0",
+ "resolved": "https://registry.npmjs.org/workerd/-/workerd-1.20241205.0.tgz",
+ "integrity": "sha512-vso/2n0c5SdBDWiD+Sx5gM7unA6SiZXRVUHDqH1euoP/9mFVHZF8icoYsNLB87b/TX8zNgpae+I5N/xFpd9v0g==",
"dev": true,
"hasInstallScript": true,
"license": "Apache-2.0",
@@ -8846,22 +9090,22 @@
"node": ">=16"
},
"optionalDependencies": {
- "@cloudflare/workerd-darwin-64": "1.20241106.1",
- "@cloudflare/workerd-darwin-arm64": "1.20241106.1",
- "@cloudflare/workerd-linux-64": "1.20241106.1",
- "@cloudflare/workerd-linux-arm64": "1.20241106.1",
- "@cloudflare/workerd-windows-64": "1.20241106.1"
+ "@cloudflare/workerd-darwin-64": "1.20241205.0",
+ "@cloudflare/workerd-darwin-arm64": "1.20241205.0",
+ "@cloudflare/workerd-linux-64": "1.20241205.0",
+ "@cloudflare/workerd-linux-arm64": "1.20241205.0",
+ "@cloudflare/workerd-windows-64": "1.20241205.0"
}
},
"node_modules/wrangler": {
- "version": "3.91.0",
- "resolved": "https://registry.npmjs.org/wrangler/-/wrangler-3.91.0.tgz",
- "integrity": "sha512-Hdzn6wbY9cz5kL85ZUvWLwLIH7nPaEVRblfms40jhRf4qQO/Zf74aFlku8rQFbe8/2aVZFaxJVfBd6JQMeMSBQ==",
+ "version": "3.93.0",
+ "resolved": "https://registry.npmjs.org/wrangler/-/wrangler-3.93.0.tgz",
+ "integrity": "sha512-+wfxjOrtm6YgDS+NdJkB6aiBIS3ED97mNRQmfrEShRJW4pVo4sWY6oQ1FsGT+j4tGHplrTbWCE6U5yTgjNW/lw==",
"dev": true,
"license": "MIT OR Apache-2.0",
"dependencies": {
"@cloudflare/kv-asset-handler": "0.3.4",
- "@cloudflare/workers-shared": "0.9.0",
+ "@cloudflare/workers-shared": "0.10.0",
"@esbuild-plugins/node-globals-polyfill": "^0.2.3",
"@esbuild-plugins/node-modules-polyfill": "^0.2.2",
"blake3-wasm": "^2.1.5",
@@ -8869,15 +9113,14 @@
"date-fns": "^4.1.0",
"esbuild": "0.17.19",
"itty-time": "^1.0.6",
- "miniflare": "3.20241106.1",
+ "miniflare": "3.20241205.0",
"nanoid": "^3.3.3",
"path-to-regexp": "^6.3.0",
"resolve": "^1.22.8",
- "resolve.exports": "^2.0.2",
"selfsigned": "^2.0.1",
"source-map": "^0.6.1",
- "unenv": "npm:unenv-nightly@2.0.0-20241121-161142-806b5c0",
- "workerd": "1.20241106.1",
+ "unenv": "npm:unenv-nightly@2.0.0-20241204-140205-a5d5190",
+ "workerd": "1.20241205.0",
"xxhash-wasm": "^1.0.1"
},
"bin": {
@@ -8891,7 +9134,7 @@
"fsevents": "~2.3.2"
},
"peerDependencies": {
- "@cloudflare/workers-types": "^4.20241106.0"
+ "@cloudflare/workers-types": "^4.20241205.0"
},
"peerDependenciesMeta": {
"@cloudflare/workers-types": {
@@ -9036,14 +9279,6 @@
"stacktracey": "^2.1.8"
}
},
- "node_modules/zimmerframe": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/zimmerframe/-/zimmerframe-1.1.2.tgz",
- "integrity": "sha512-rAbqEGa8ovJy4pyBxZM70hg4pE6gDgaQ0Sl9M3enG3I0d6H4XSAM3GeNGLKnsBpuijUow064sf7ww1nutC5/3w==",
- "dev": true,
- "license": "MIT",
- "peer": true
- },
"node_modules/zod": {
"version": "3.23.8",
"resolved": "https://registry.npmjs.org/zod/-/zod-3.23.8.tgz",
@@ -9053,6 +9288,16 @@
"funding": {
"url": "https://github.com/sponsors/colinhacks"
}
+ },
+ "node_modules/zod-to-json-schema": {
+ "version": "3.23.5",
+ "resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.23.5.tgz",
+ "integrity": "sha512-5wlSS0bXfF/BrL4jPAbz9da5hDlDptdEppYfe+x4eIJ7jioqKG9uUxOwPzqof09u/XeVdrgFu29lZi+8XNDJtA==",
+ "dev": true,
+ "license": "ISC",
+ "peerDependencies": {
+ "zod": "^3.23.3"
+ }
}
}
}
diff --git a/package.json b/package.json
index 0e51c33..00a4193 100644
--- a/package.json
+++ b/package.json
@@ -32,39 +32,43 @@
"license": "MIT",
"description": "Sophisticated scheduler for durable tasks, built on Durable Object Alarms.",
"devDependencies": {
+ "@ai-sdk/openai": "^1.0.7",
"@changesets/changelog-github": "^0.5.0",
"@changesets/cli": "^2.27.10",
- "@cloudflare/vitest-pool-workers": "^0.5.32",
- "@cloudflare/workers-types": "^4.20241127.0",
+ "@cloudflare/vitest-pool-workers": "^0.5.34",
+ "@cloudflare/workers-types": "^4.20241205.0",
+ "@eslint/js": "^9.16.0",
"@tailwindcss/aspect-ratio": "^0.4.2",
"@tailwindcss/container-queries": "^0.1.1",
"@tailwindcss/forms": "^0.5.9",
"@tailwindcss/typography": "^0.5.15",
- "@tailwindcss/vite": "^4.0.0-beta.3",
+ "@tailwindcss/vite": "^4.0.0-beta.6",
"@types/bun": "^1.1.14",
- "@types/react": "^18.3.12",
- "@types/react-dom": "^18.3.1",
+ "@types/react": "^19.0.1",
+ "@types/react-dom": "^19.0.1",
+ "@typescript-eslint/eslint-plugin": "^8.17.0",
+ "@typescript-eslint/parser": "^8.17.0",
"@vitejs/plugin-react": "^4.3.4",
+ "ai": "^4.0.13",
"concurrently": "^9.1.0",
- "react": "^18.3.1",
- "react-dom": "^18.3.1",
- "tailwindcss": "^4.0.0-beta.3",
- "tshy": "^3.0.2",
- "typescript": "^5.7.2",
- "vite": "^6.0.1",
- "vitest": "2.1.6",
- "wrangler": "^3.91.0",
- "zod": "^3.23.8",
- "@typescript-eslint/eslint-plugin": "^8.16.0",
- "@typescript-eslint/parser": "^8.16.0",
- "eslint": "^9.15.0",
- "@eslint/js": "^9.15.0",
+ "eslint": "^9.16.0",
"eslint-config-prettier": "^9.1.0",
+ "eslint-import-resolver-typescript": "^3.7.0",
"eslint-plugin-import": "^2.31.0",
"eslint-plugin-react": "^7.37.2",
- "eslint-plugin-react-hooks": "^5.0.0",
- "prettier": "^3.4.1",
- "eslint-import-resolver-typescript": "^3.6.1"
+ "eslint-plugin-react-hooks": "^5.1.0",
+ "partyserver": "^0.0.57",
+ "partysocket": "^1.0.2",
+ "prettier": "^3.4.2",
+ "react": "^19.0.0",
+ "react-dom": "^19.0.0",
+ "tailwindcss": "^4.0.0-beta.6",
+ "tshy": "^3.0.2",
+ "typescript": "^5.7.2",
+ "vite": "^6.0.3",
+ "vitest": "2.1.8",
+ "wrangler": "^3.93.0",
+ "zod": "^3.23.8"
},
"overrides": {
"esbuild": "0.24.0"
diff --git a/src/index.ts b/src/index.ts
index 6b0bb8f..f756867 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -3,33 +3,50 @@ import cronParser from "cron-parser";
export type Task = {
id: string;
- name?: string | undefined;
- payload: Record;
+ description?: string | undefined;
+ payload?: Record | undefined;
+ callback?: Callback | undefined;
} & (
- | {
+ | {
time: Date;
type: "scheduled";
}
- | {
- delay: number;
+ | {
+ delayInSeconds: number;
type: "delayed";
}
- | {
+ | {
cron: string;
type: "cron";
}
- );
+ | {
+ type: "no-schedule";
+ }
+);
-type SqlTask = {
+export type SqlTask = {
id: string;
- name: string | null;
- type: string | null;
+ description: string | null;
payload: string | null;
+ callback: string | null;
+ type: string | null;
time: number | null;
- delay: number | null;
+ delayInSeconds: number | null;
cron: string | null;
created_at: number | null;
-}
+};
+
+type Callback =
+ | {
+ type: "webhook";
+ url: string;
+ }
+ | {
+ type: "durable-object";
+ namespace: string;
+ id: string;
+ function: string;
+ };
export class Scheduler extends DurableObject {
constructor(state: DurableObjectState, env: Env) {
@@ -40,11 +57,12 @@ export class Scheduler extends DurableObject {
`
CREATE TABLE IF NOT EXISTS tasks (
id TEXT PRIMARY KEY,
- name TEXT,
- type TEXT NOT NULL,
+ description TEXT,
payload TEXT,
+ callback TEXT,
+ type TEXT NOT NULL CHECK(type IN ('scheduled', 'delayed', 'cron', 'no-schedule')),
time INTEGER,
- delay INTEGER,
+ delayInSeconds INTEGER,
cron TEXT,
created_at INTEGER DEFAULT (unixepoch())
)
@@ -64,7 +82,6 @@ export class Scheduler extends DurableObject {
};
}
- // eslint-disable-next-line @typescript-eslint/require-await
async fetch(_request: Request): Promise {
return new Response("Hello World!");
}
@@ -82,7 +99,9 @@ export class Scheduler extends DurableObject {
ORDER BY time ASC
LIMIT 1
`;
- const { result } = this.querySql([{ sql: query, params: [Math.floor(Date.now() / 1000)] }])
+ const { result } = this.querySql([
+ { sql: query, params: [Math.floor(Date.now() / 1000)] },
+ ]);
if (!result) return;
if (result.length > 0 && "time" in result[0]) {
@@ -93,74 +112,135 @@ export class Scheduler extends DurableObject {
async scheduleTask(task: Task): Promise {
const { id } = task;
- const payload = JSON.stringify(task.payload);
if ("time" in task && task.time) {
const timestamp = Math.floor(task.time.getTime() / 1000);
const query = `
- INSERT OR REPLACE INTO tasks (id, name, type, payload, time)
- VALUES (?, ?, 'scheduled', ?, ?)
+ INSERT OR REPLACE INTO tasks (id, description, payload, callback, type, time)
+ VALUES (?, ?, ?, ?, 'scheduled', ?)
`;
- this.querySql([{ sql: query, params: [id, task.name || null, payload, timestamp] }])
+ this.querySql([
+ {
+ sql: query,
+ params: [
+ id,
+ task.description || null,
+ JSON.stringify(task.payload || null),
+ JSON.stringify(task.callback || null),
+ timestamp,
+ ],
+ },
+ ]);
await this.scheduleNextAlarm();
return {
id,
- name: task.name,
+ description: task.description,
payload: task.payload,
+ callback: task.callback,
time: task.time,
type: "scheduled",
};
- } else if ("delay" in task && task.delay) {
- const time = new Date(Date.now() + task.delay);
+ } else if ("delayInSeconds" in task && task.delayInSeconds) {
+ const time = new Date(Date.now() + task.delayInSeconds * 1000);
const timestamp = Math.floor(time.getTime() / 1000);
const query = `
- INSERT OR REPLACE INTO tasks (id, name, type, payload, delay, time)
- VALUES (?, ?, 'delayed', ?, ?, ?)
+ INSERT OR REPLACE INTO tasks (id, description, payload, callback, type, delayInSeconds, time)
+ VALUES (?, ?, ?, ?, 'delayed', ?, ?)
`;
- this.querySql([{ sql: query, params: [id, task.name || null, payload, task.delay, timestamp] }])
+ this.querySql([
+ {
+ sql: query,
+ params: [
+ id,
+ task.description || null,
+ JSON.stringify(task.payload || null),
+ JSON.stringify(task.callback || null),
+ task.delayInSeconds,
+ timestamp,
+ ],
+ },
+ ]);
await this.scheduleNextAlarm();
return {
id,
- name: task.name,
+ description: task.description,
payload: task.payload,
- delay: task.delay,
+ callback: task.callback,
+ delayInSeconds: task.delayInSeconds,
type: "delayed",
};
} else if ("cron" in task && task.cron) {
const nextExecutionTime = this.getNextCronTime(task.cron);
const timestamp = Math.floor(nextExecutionTime.getTime() / 1000);
const query = `
- INSERT OR REPLACE INTO tasks (id, name, type, payload, cron, time)
- VALUES (?, ?, 'cron', ?, ?, ?)
+ INSERT OR REPLACE INTO tasks (id, description, payload, callback, type, cron, time)
+ VALUES (?, ?, ?, ?, 'cron', ?, ?)
`;
- this.querySql([{ sql: query, params: [id, task.name || null, payload, task.cron, timestamp] }])
+ this.querySql([
+ {
+ sql: query,
+ params: [
+ id,
+ task.description || null,
+ JSON.stringify(task.payload || null),
+ JSON.stringify(task.callback || null),
+ task.cron,
+ timestamp,
+ ],
+ },
+ ]);
await this.scheduleNextAlarm();
return {
id,
- name: task.name,
+ description: task.description,
payload: task.payload,
+ callback: task.callback,
cron: task.cron,
type: "cron",
};
- }
+ } else {
+ const query = `
+ INSERT OR REPLACE INTO tasks (id, description, payload, callback, type)
+ VALUES (?, ?, ?, ?, 'no-schedule')
+ `;
+ this.querySql([
+ {
+ sql: query,
+ params: [
+ id,
+ task.description || null,
+ JSON.stringify(task.payload || null),
+ JSON.stringify(task.callback || null),
+ ],
+ },
+ ]);
- throw new Error("Invalid task configuration");
+ return {
+ id,
+ description: task.description,
+ payload: task.payload,
+ callback: task.callback,
+ type: "no-schedule",
+ };
+ }
}
async alarm(): Promise {
const now = Math.floor(Date.now() / 1000);
// Get all tasks that should be executed now
- const { result: tasks } = this.querySql([{ sql: "SELECT * FROM tasks WHERE time <= ?", params: [now] }])
+ const { result: tasks } = this.querySql([
+ { sql: "SELECT * FROM tasks WHERE time <= ?", params: [now] },
+ ]);
- for (const row of (tasks || [])) {
+ for (const row of tasks || []) {
const task = this.rowToTask(row);
await this.executeTask(task);
@@ -169,10 +249,12 @@ export class Scheduler extends DurableObject {
const nextExecutionTime = this.getNextCronTime(task.cron);
const nextTimestamp = Math.floor(nextExecutionTime.getTime() / 1000);
- this.querySql([{ sql: "UPDATE tasks SET time = ? WHERE id = ?", params: [nextTimestamp, task.id] }])
+ this.querySql([
+ { sql: "UPDATE tasks SET time = ? WHERE id = ?", params: [nextTimestamp, task.id] },
+ ]);
} else {
// Delete one-time tasks after execution
- this.querySql([{ sql: "DELETE FROM tasks WHERE id = ?", params: [task.id] }])
+ this.querySql([{ sql: "DELETE FROM tasks WHERE id = ?", params: [task.id] }]);
}
}
@@ -183,8 +265,9 @@ export class Scheduler extends DurableObject {
private rowToTask(row: SqlTask): Task {
const base = {
id: row.id,
- name: row.name,
- payload: JSON.parse(row.payload as string) as Record, // TODO: should probably parse/validate this
+ description: row.description,
+ payload: row.payload ? (JSON.parse(row.payload) as Record) : undefined,
+ callback: row.callback ? (JSON.parse(row.callback) as Callback) : undefined,
} as Task;
switch (row.type) {
@@ -197,7 +280,7 @@ export class Scheduler extends DurableObject {
case "delayed":
return {
...base,
- delay: row.delay as number,
+ delayInSeconds: row.delayInSeconds as number,
type: "delayed",
};
case "cron":
@@ -211,11 +294,29 @@ export class Scheduler extends DurableObject {
}
}
- // eslint-disable-next-line @typescript-eslint/require-await
private async executeTask(task: Task): Promise {
// This is where you would implement the actual task execution
// eslint-disable-next-line no-console
console.log(`Executing task ${task.id}:`, task);
+ if ("callback" in task && task.callback) {
+ const { type } = task.callback;
+ if (type === "webhook") {
+ await fetch(task.callback.url, {
+ method: "POST",
+ body: JSON.stringify(task.payload),
+ headers: {
+ "Content-Type": "application/json",
+ },
+ });
+ } else if (type === "durable-object") {
+ //@ts-expect-error yeah whatever
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access
+ const stub = this.env[task.callback.namespace].get(task.callback.id);
+
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access
+ await stub[task.callback.function](task.payload);
+ }
+ }
}
private getNextCronTime(cronExpression: string): Date {
@@ -223,10 +324,9 @@ export class Scheduler extends DurableObject {
return interval.next().toDate();
}
- // eslint-disable-next-line @typescript-eslint/require-await
async query(
criteria: {
- name?: string;
+ description?: string;
id?: string;
timeRange?: { start?: Date; end?: Date };
} = {}
@@ -239,9 +339,9 @@ export class Scheduler extends DurableObject {
params.push(criteria.id);
}
- if (criteria.name) {
- query += " AND name = ?";
- params.push(criteria.name);
+ if (criteria.description) {
+ query += " AND description = ?";
+ params.push(criteria.description);
}
if (criteria.timeRange) {
@@ -251,13 +351,13 @@ export class Scheduler extends DurableObject {
params.push(Math.floor(start.getTime() / 1000), Math.floor(end.getTime() / 1000));
}
- const { result } = this.querySql([{ sql: query, params }])
+ const { result } = this.querySql([{ sql: query, params }]);
return result?.map((row) => this.rowToTask(row)) || [];
}
async cancelTask(id: string): Promise {
const query = "DELETE FROM tasks WHERE id = ?";
- this.querySql([{ sql: query, params: [id] }])
+ this.querySql([{ sql: query, params: [id] }]);
await this.scheduleNextAlarm();
return true;
@@ -278,7 +378,6 @@ export class Scheduler extends DurableObject {
return { sql, params };
}) || [];
-
let result: QueryResponse | QueryResponse[];
if (queries.length > 1) {
@@ -292,73 +391,74 @@ export class Scheduler extends DurableObject {
error: null,
status: 200,
result: result as T[],
- }
+ };
} catch (error) {
return {
result: null,
error: (error as Error).message ?? "Operation failed.",
status: 500,
- }
+ };
}
}
- private executeTransaction(queries: { sql: string; params?: SqliteParams[] }[], isRaw: boolean): QueryResponse[] {
+ private executeTransaction(
+ queries: { sql: string; params?: SqliteParams[] }[],
+ isRaw: boolean
+ ): QueryResponse[] {
return this.ctx.storage.transactionSync(() => {
const results: QueryResponse[] = [];
- try {
- for (const queryObj of queries) {
- const { sql, params } = queryObj;
- const result = this.executeQuery(sql, params, isRaw);
- results.push(result);
- }
-
- return results;
- } catch (error) {
- throw error;
+ for (const queryObj of queries) {
+ const { sql, params } = queryObj;
+ const result = this.executeQuery(sql, params, isRaw);
+ results.push(result);
}
+
+ return results;
});
}
- executeQuery(sql: string, params: SqliteParams[] | undefined, isRaw: boolean): QueryResponse {
- try {
- const cursor = params?.length ? this.ctx.storage.sql.exec(sql, ...params) : this.ctx.storage.sql.exec(sql);
-
- let result: QueryResponse;
-
- if (isRaw) {
- result = {
- columns: cursor.columnNames,
- rows: (cursor.raw() as any).toArray() as T[],
- meta: {
- rows_read: cursor.rowsRead,
- rows_written: cursor.rowsWritten,
- },
- };
- } else {
- result = cursor.toArray() as T[];
- }
-
- return result;
- } catch (error) {
- throw error;
+ executeQuery(
+ sql: string,
+ params: SqliteParams[] | undefined,
+ isRaw: boolean
+ ): QueryResponse {
+ const cursor = params?.length
+ ? this.ctx.storage.sql.exec(sql, ...params)
+ : this.ctx.storage.sql.exec(sql);
+
+ let result: QueryResponse;
+
+ if (isRaw) {
+ result = {
+ columns: cursor.columnNames,
+ // @ts-expect-error TODO fix this!!!
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-call
+ rows: (cursor.raw() as unknown as T[]).toArray() as T[],
+ meta: {
+ rows_read: cursor.rowsRead,
+ rows_written: cursor.rowsWritten,
+ },
+ };
+ } else {
+ result = cursor.toArray() as T[];
}
- }
+ return result;
+ }
}
-
export type QueueResult =
| {
- result: T[];
- error: null;
- status: 200;
- }
+ result: T[];
+ error: null;
+ status: 200;
+ }
| {
- result: null;
- error: string;
- status: 500 | 408;
- };
+ result: null;
+ error: string;
+ status: 500 | 408;
+ };
export type RawSqliteResponse = {
columns: string[];
diff --git a/tests/index.test.ts b/tests/index.test.ts
index 44dcfe1..fc69b96 100644
--- a/tests/index.test.ts
+++ b/tests/index.test.ts
@@ -30,24 +30,33 @@ describe("Hello World worker", () => {
const stub = getStub(env);
const id = "scheduled-task-001";
const time = new Date(Date.now() + 10000);
- // eslint-disable-next-line @typescript-eslint/await-thenable
const task = await stub.scheduleTask({
id,
- name: "test",
+ description: "test",
+ payload: { test: "test" },
+ callback: {
+ type: "webhook",
+ url: "https://example.com",
+ },
type: "scheduled",
- payload: {},
time,
});
expect(task).toMatchInlineSnapshot(`
- {
- "id": "scheduled-task-001",
- "name": "test",
- "payload": {},
- "time": ${time.toISOString()},
- "type": "scheduled",
- }
- `);
+ {
+ "callback": {
+ "type": "webhook",
+ "url": "https://example.com",
+ },
+ "description": "test",
+ "id": "scheduled-task-001",
+ "payload": {
+ "test": "test",
+ },
+ "time": ${time.toISOString()},
+ "type": "scheduled",
+ }
+ `);
const timestamp = Math.floor(time.getTime() / 1000);
const debug = await stub.getAllTasks();
@@ -61,11 +70,12 @@ describe("Hello World worker", () => {
expect(rest).toMatchInlineSnapshot(`
{
+ "callback": "{"type":"webhook","url":"https://example.com"}",
"cron": null,
- "delay": null,
+ "delayInSeconds": null,
+ "description": "test",
"id": "scheduled-task-001",
- "name": "test",
- "payload": "{}",
+ "payload": "{"test":"test"}",
"time": ${timestamp},
"type": "scheduled",
}
@@ -75,30 +85,41 @@ describe("Hello World worker", () => {
it("can schedule a delayed task", async () => {
const stub = getStub(env);
const id = "delayed-task-001";
- const delay = 10000;
- const timestamp = new Date().getTime() + delay;
- // eslint-disable-next-line @typescript-eslint/await-thenable
+ const delayInSeconds = 10000;
+
const task = await stub.scheduleTask({
id,
- name: "test",
+ description: "test",
+ payload: { test: "test" },
+ callback: {
+ type: "webhook",
+ url: "https://example.com",
+ },
type: "delayed",
- payload: {},
- delay,
+ delayInSeconds,
});
expect(task).toMatchInlineSnapshot(`
- {
- "delay": 10000,
- "id": "delayed-task-001",
- "name": "test",
- "payload": {},
- "type": "delayed",
- }
- `);
+ {
+ "callback": {
+ "type": "webhook",
+ "url": "https://example.com",
+ },
+ "delayInSeconds": 10000,
+ "description": "test",
+ "id": "delayed-task-001",
+ "payload": {
+ "test": "test",
+ },
+ "type": "delayed",
+ }
+ `);
const debug = await stub.getAllTasks();
expect(debug.result).toHaveLength(1);
+ const timestamp = Math.floor((new Date().getTime() + delayInSeconds * 1000) / 1000);
+
const {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
created_at,
@@ -107,12 +128,13 @@ describe("Hello World worker", () => {
expect(rest).toMatchInlineSnapshot(`
{
+ "callback": "{"type":"webhook","url":"https://example.com"}",
"cron": null,
- "delay": 10000,
+ "delayInSeconds": 10000,
+ "description": "test",
"id": "delayed-task-001",
- "name": "test",
- "payload": "{}",
- "time": ${Math.floor(timestamp / 1000)},
+ "payload": "{"test":"test"}",
+ "time": ${timestamp},
"type": "delayed",
}
`);
@@ -125,24 +147,85 @@ describe("Hello World worker", () => {
const next = cronParser.parseExpression(cron).next();
const timestamp = Math.floor(next.toDate().getTime() / 1000);
- // eslint-disable-next-line @typescript-eslint/await-thenable
const task = await stub.scheduleTask({
id,
- name: "test",
+ description: "test",
+ payload: { test: "test" },
+ callback: {
+ type: "webhook",
+ url: "https://example.com",
+ },
type: "cron",
- payload: {},
cron,
});
expect(task).toMatchInlineSnapshot(`
{
+ "callback": {
+ "type": "webhook",
+ "url": "https://example.com",
+ },
+ "cron": "0 0 * * 2",
+ "description": "test",
+ "id": "cron-task-001",
+ "payload": {
+ "test": "test",
+ },
+ "type": "cron",
+ }
+ `);
+
+ const debug = await stub.getAllTasks();
+ expect(debug.result).toHaveLength(1);
+
+ const {
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
+ created_at,
+ ...rest
+ } = (debug.result || [])[0];
+
+ expect(rest).toMatchInlineSnapshot(`
+ {
+ "callback": "{"type":"webhook","url":"https://example.com"}",
"cron": "0 0 * * 2",
+ "delayInSeconds": null,
+ "description": "test",
"id": "cron-task-001",
- "name": "test",
- "payload": {},
+ "payload": "{"test":"test"}",
+ "time": ${timestamp},
"type": "cron",
}
`);
+ });
+
+ it("can schedule a no-schedule task", async () => {
+ const stub = getStub(env);
+ const id = "no-schedule-task-001";
+ const task = await stub.scheduleTask({
+ id,
+ description: "test",
+ payload: { test: "test" },
+ callback: {
+ type: "webhook",
+ url: "https://example.com",
+ },
+ type: "no-schedule",
+ });
+
+ expect(task).toMatchInlineSnapshot(`
+ {
+ "callback": {
+ "type": "webhook",
+ "url": "https://example.com",
+ },
+ "description": "test",
+ "id": "no-schedule-task-001",
+ "payload": {
+ "test": "test",
+ },
+ "type": "no-schedule",
+ }
+ `);
const debug = await stub.getAllTasks();
expect(debug.result).toHaveLength(1);
@@ -154,15 +237,16 @@ describe("Hello World worker", () => {
} = (debug.result || [])[0];
expect(rest).toMatchInlineSnapshot(`
- {
- "cron": "0 0 * * 2",
- "delay": null,
- "id": "cron-task-001",
- "name": "test",
- "payload": "{}",
- "time": ${timestamp},
- "type": "cron",
- }
- `);
+ {
+ "callback": "{"type":"webhook","url":"https://example.com"}",
+ "cron": null,
+ "delayInSeconds": null,
+ "description": "test",
+ "id": "no-schedule-task-001",
+ "payload": "{"test":"test"}",
+ "time": null,
+ "type": "no-schedule",
+ }
+ `);
});
});