diff --git a/.gitignore b/.gitignore index 8ac600a..2b2fa13 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,6 @@ workerd-tests workerd-tests.capnp .cache .vercel +kv.db +kv.db-shm +kv.db-wal diff --git a/package.json b/package.json index 27433bc..2120445 100644 --- a/package.json +++ b/package.json @@ -240,20 +240,20 @@ "generate": "yarn build && node esnext/generate.js", "test": "yarn build && yarn test:node", "test:all": "yarn build && yarn test:node && yarn test:bun", - "test:node": "NODE_ENV=test TESTING=1 OTEL_SERVICE_NAME=logistics-tests node --env-file=.env.test --enable-source-maps esnext/tests/index.js", - "test:node:inspect": "yarn build && NODE_ENV=test TESTING=1 OTEL_SERVICE_NAME=logistics-tests node --env-file=.env.test --enable-source-maps --inspect-brk esnext/tests/index.js", + "test:node": "NODE_ENV=test TESTING=1 OTEL_SERVICE_NAME=logistics-tests node --no-warnings=DEP0040 --env-file=.env.test --enable-source-maps esnext/tests/index.js", + "test:node:inspect": "yarn build && NODE_ENV=test TESTING=1 OTEL_SERVICE_NAME=logistics-tests node --no-warnings=DEP0040 --env-file=.env.test --enable-source-maps --inspect-brk esnext/tests/index.js", "test:bun": "NODE_ENV=test TESTING=1 OTEL_SERVICE_NAME=logistics-tests bun esnext/tests/index.js", "coverage": "NODE_ENV=test TESTING=1 OTEL_SERVICE_NAME=logistics-tests c8 node --env-file=.env.test esnext/tests/index.js && yarn postbuild", - "start": "node --enable-source-maps --env-file=.env esnext/listen/main.js", + "start": "node --no-warnings=DEP0040 --enable-source-maps --env-file=.env esnext/listen/main.js", "start:bun": "bun esnext/listen/main.js", - "start:nodemon": "nodemon --enable-source-maps --env-file=.env esnext/listen/main.js", + "start:nodemon": "nodemon --enable-source-maps --no-warnings=DEP0040 --env-file=.env esnext/listen/main.js", "quick": "yarn build && yarn start", "local": "yarn build && yarn seed && yarn start", - "seed": "node --enable-source-maps esnext/data/seed/main.js", + "seed": "node --enable-source-maps --no-warnings=DEP0040 esnext/data/seed/main.js", "watch": "yarn build && concurrently --raw \"yarn start:nodemon\" \"yarn build:watch\" ", "prettier:check": "prettier --check .", "prettier": "prettier --write .", - "vork": "node ./esnext/worker/service-worker/configure/main.js", + "vork": "node --no-warnings=DEP0040 ./esnext/worker/service-worker/configure/main.js", "bork": "bun ./esnext/worker/service-worker/configure/main.js" }, "importmap": { diff --git a/src/events/dispatch/index.ts b/src/events/dispatch/index.ts index 527a310..5faa2c5 100644 --- a/src/events/dispatch/index.ts +++ b/src/events/dispatch/index.ts @@ -2,6 +2,7 @@ import {on, dispatchEvent} from "../schedule"; import type {DurableEventData, UnknownEvent} from "../../data"; import {isLike, ok} from "../../is"; import {getServiceWorkerModuleExports} from "../../worker/service-worker/worker-exports"; +import {getDispatcherFunction} from "../schedule/schedule"; const DISPATCH = "dispatch" as const; type DispatchEventType = typeof DISPATCH; @@ -36,26 +37,42 @@ export async function onDispatchEvent(event: UnknownEvent) { }))); return; } - if (event.dispatch.type === "dispatch") { + let dispatching: DurableEventData; + + if (typeof event.dispatch === "string") { + dispatching = { + type: event.dispatch + }; + } else { + dispatching = { + ...event.dispatch + }; + } + + if (dispatching.type === "dispatch") { // This is to prevent infinite loops console.warn("dispatch cannot be used to dispatch additional events"); return; } - let dispatching: DurableEventData = { - ...event.dispatch - }; const entrypointArguments = event.entrypointArguments; async function dispatchEntrypointEvent(entrypoint: unknown) { - ok(typeof entrypoint === "function", "Expected entrypoint to be a function"); - if (entrypointArguments) { - const dispatchArguments = entrypointArguments.map( - key => key === "$event" ? dispatching : dispatching[key] - ); - return entrypoint(...dispatchArguments); - } else { - ok(entrypoint); - return entrypoint(dispatching); + const dispatcher = getDispatcherFunction({ + event: dispatching + }); + dispatcher.handler(dispatching, dispatch); + + function dispatch(dispatching: DurableEventData) { + ok(typeof entrypoint === "function", "Expected entrypoint to be a function"); + if (entrypointArguments) { + const dispatchArguments = entrypointArguments.map( + key => key === "$event" ? dispatching : dispatching[key] + ); + return entrypoint(...dispatchArguments); + } else { + ok(entrypoint); + return entrypoint(dispatching); + } } } diff --git a/src/fetch/dispatch.ts b/src/fetch/dispatch.ts index 3fb51d1..ec46018 100644 --- a/src/fetch/dispatch.ts +++ b/src/fetch/dispatch.ts @@ -8,7 +8,7 @@ import { fromRequestResponse, setDurableRequestForEvent } from "../data"; -import {dispatcher} from "../events/schedule/schedule"; +import {dispatcher, getDispatcherFunction} from "../events/schedule/schedule"; import {v4} from "uuid"; import {caches} from "./cache"; import {dispatchEvent} from "../events/schedule/event"; @@ -236,35 +236,41 @@ export const removeFetchDispatcherFunction = dispatcher("fetch", async (event, d const entrypointArguments = event.entrypointArguments; async function dispatchServiceWorkerFnRequest(fn: unknown, fnError = "Expected entrypoint to be a function") { - ok(typeof fn === "function", fnError); - - let returned; - if (entrypointArguments) { - const requestArguments = entrypointArguments.map( - key => key === "$event" ? requestEvent : requestEvent[key] - ); - returned = fn(...requestArguments); - } else { - ok(fn, fnError); - returned = fn(request, requestEvent); - } - if (isLike>(returned) && typeof returned === "object" && "then" in returned) { - waitUntil(returned); - returned = await returned; - } - if (returned instanceof Response) { - respondWith(returned); + const dispatcher = getDispatcherFunction({ + event: requestEvent + }); + dispatcher.handler(requestEvent, dispatch); + + async function dispatch(requestEvent: DurableEventData) { + ok(typeof fn === "function", fnError); + let returned; + if (entrypointArguments) { + const requestArguments = entrypointArguments.map( + key => key === "$event" ? requestEvent : requestEvent[key] + ); + returned = fn(...requestArguments); + } else { + ok(fn, fnError); + returned = fn(request, requestEvent); + } + if (isLike>(returned) && typeof returned === "object" && "then" in returned) { + waitUntil(returned); + returned = await returned; + } + if (returned instanceof Response) { + respondWith(returned); + } } } const serviceWorker = getServiceWorkerModuleExports(); if (event.entrypoint) { const entrypoint = serviceWorker[event.entrypoint]; - if (!entrypoint) { - const names = Object.keys(serviceWorker); - throw new Error(`Unknown entrypoint ${event.entrypoint}, expected one of ${names.join(", ")}`); + if (entrypoint) { + await dispatchServiceWorkerFnRequest(entrypoint); + } else { + await dispatch(requestEvent); } - await dispatchServiceWorkerFnRequest(entrypoint); } else if (typeof serviceWorker.fetch === "function") { await dispatchServiceWorkerFnRequest(serviceWorker.fetch); } else if (typeof serviceWorker.default === "function") { diff --git a/src/tests/worker/service-worker/index.ts b/src/tests/worker/service-worker/index.ts index 10e1c22..008311f 100644 --- a/src/tests/worker/service-worker/index.ts +++ b/src/tests/worker/service-worker/index.ts @@ -54,9 +54,11 @@ const worker = join(dirname(pathname), "./worker.js"); { const registration = await serviceWorker.register(worker); + ok(registration.active, "Expected registration to be active"); + const routes = await listRoutes(registration.durable.serviceWorkerId); - ok(routes.length); + ok(routes.length, "Expected routes to be initiated"); const fetch = await createRouter([ registration diff --git a/src/tests/worker/service-worker/worker.ts b/src/tests/worker/service-worker/worker.ts index 61dd80f..2421d56 100644 --- a/src/tests/worker/service-worker/worker.ts +++ b/src/tests/worker/service-worker/worker.ts @@ -7,6 +7,7 @@ declare var self: DurableServiceWorkerScope; console.log("in test service worker"); self.addEventListener("install", event => { + console.log("Ran install", event); event.addRoutes([ { condition: { @@ -36,7 +37,7 @@ self.addEventListener("activate", event => { }) self.addEventListener("fetch", event => { - console.log("In fetch handler!", event.tag || "untagged"); + console.log("In fetch handler!", event.tag || "untagged", event.respondWith); event.respondWith(onFetchEvent(event)); }); diff --git a/src/worker/service-worker/configure/import.ts b/src/worker/service-worker/configure/import.ts index c4f3d4c..e092870 100644 --- a/src/worker/service-worker/configure/import.ts +++ b/src/worker/service-worker/configure/import.ts @@ -169,17 +169,7 @@ export async function importConfiguration(source: string | URL | Config, { virtu // This saves us from creating these values multiple times... // ... is okay to use parse/stringify... isn't the best but that is okay if (!noStringifyConfig) { - config = JSON.parse( - JSON.stringify( - config, - (key, value) => { - if (key === "url" && typeof value === "function") { - return getMaybeFunctionURL(value); - } - return value; - } - ) - ); + replaceFunctions(config); } const getService = await initialiseServices(config); @@ -342,4 +332,20 @@ async function initialiseSocket(config: Config, socket: Socket, getService: Serv hostname, }, }, variableDispatch); +} + +function replaceFunctions(value: unknown): void { + if (!value) return; + if (Array.isArray(value)) { + return value.forEach(replaceFunctions); + } + if (typeof value !== "object") return; + for (const [key, nextValue] of Object.entries(value)) { + if (key === "url" && typeof nextValue === "function") { + Object.assign(value, { [key]: getMaybeFunctionURL(nextValue) }) + } else { + replaceFunctions(nextValue); + } + } + } \ No newline at end of file diff --git a/src/worker/service-worker/dispatchers/index.ts b/src/worker/service-worker/dispatchers/index.ts index b10f9df..ce4153d 100644 --- a/src/worker/service-worker/dispatchers/index.ts +++ b/src/worker/service-worker/dispatchers/index.ts @@ -1,2 +1,3 @@ +import "../../../dispatch"; export * from "./activate"; export * from "./install"; \ No newline at end of file diff --git a/src/worker/service-worker/worker.ts b/src/worker/service-worker/worker.ts index f30b07d..dbe1a0e 100644 --- a/src/worker/service-worker/worker.ts +++ b/src/worker/service-worker/worker.ts @@ -76,12 +76,12 @@ export async function onServiceWorkerWorkerData(data: ServiceWorkerWorkerData, i Object.assign(globalThis, scope); await import("./dispatchers"); - await importWorkerExtensions(data.config, data.config.extensions, scope); + await importWorkerExtensions(data.config, data.config?.extensions, scope); const url = new URL(registration.durable.url, registration.durable.baseURL); url.searchParams.set("importCacheBust", Date.now().toString()); imported = await import(url.toString()); - if (Array.isArray(data.service?.url)) { + if (data.config && Array.isArray(data.service?.url)) { const rest = data.service.url.slice(1); await importWorkerExtensions(data.config, rest, scope); }