rwsdk 0.1.0-alpha.9 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (87) hide show
  1. package/dist/runtime/client.d.ts +3 -1
  2. package/dist/runtime/client.js +15 -11
  3. package/dist/runtime/clientNavigation.d.ts +3 -0
  4. package/dist/runtime/clientNavigation.js +43 -0
  5. package/dist/runtime/entries/client.d.ts +1 -0
  6. package/dist/runtime/entries/client.js +1 -0
  7. package/dist/runtime/entries/worker.d.ts +2 -0
  8. package/dist/runtime/entries/worker.js +2 -0
  9. package/dist/runtime/imports/ClientOnly.d.ts +3 -0
  10. package/dist/runtime/imports/ClientOnly.js +8 -0
  11. package/dist/runtime/imports/NoSSRStub.d.ts +1 -0
  12. package/dist/runtime/imports/NoSSRStub.js +4 -0
  13. package/dist/runtime/imports/client.js +15 -2
  14. package/dist/runtime/imports/worker.d.ts +1 -1
  15. package/dist/runtime/imports/worker.js +7 -5
  16. package/dist/runtime/lib/db/DOWorkerDialect.d.ts +29 -0
  17. package/dist/runtime/lib/db/DOWorkerDialect.js +66 -0
  18. package/dist/runtime/lib/db/SqliteDurableObject.d.ts +14 -0
  19. package/dist/runtime/lib/db/SqliteDurableObject.js +42 -0
  20. package/dist/runtime/lib/db/create.d.ts +3 -0
  21. package/dist/runtime/lib/db/create.js +36 -0
  22. package/dist/runtime/lib/db/createDb.d.ts +2 -0
  23. package/dist/runtime/lib/db/createDb.js +27 -0
  24. package/dist/runtime/lib/db/index.d.ts +3 -0
  25. package/dist/runtime/lib/db/index.js +3 -0
  26. package/dist/runtime/lib/db/logger.d.ts +2 -0
  27. package/dist/runtime/lib/db/logger.js +41 -0
  28. package/dist/runtime/lib/db/migrations.d.ts +23 -0
  29. package/dist/runtime/lib/db/migrations.js +34 -0
  30. package/dist/runtime/lib/db/types.d.ts +0 -0
  31. package/dist/runtime/lib/db/types.js +1 -0
  32. package/dist/runtime/lib/debug.d.ts +2 -0
  33. package/dist/runtime/lib/debug.js +36 -0
  34. package/dist/runtime/lib/router.d.ts +6 -1
  35. package/dist/runtime/lib/router.js +9 -2
  36. package/dist/runtime/register/ssr.d.ts +2 -0
  37. package/dist/runtime/register/ssr.js +14 -1
  38. package/dist/runtime/register/worker.d.ts +1 -1
  39. package/dist/runtime/register/worker.js +5 -2
  40. package/dist/runtime/render/renderRscThenableToHtmlStream.d.ts +2 -1
  41. package/dist/runtime/render/renderRscThenableToHtmlStream.js +17 -3
  42. package/dist/runtime/render/renderToStream.d.ts +9 -0
  43. package/dist/runtime/render/renderToStream.js +26 -0
  44. package/dist/runtime/render/renderToString.d.ts +7 -0
  45. package/dist/runtime/render/renderToString.js +26 -0
  46. package/dist/runtime/render/transformRscToHtmlStream.js +1 -0
  47. package/dist/runtime/worker.js +17 -10
  48. package/dist/scripts/debug-sync.mjs +8 -6
  49. package/dist/scripts/worker-run.mjs +1 -0
  50. package/dist/vite/configPlugin.mjs +8 -17
  51. package/dist/vite/createDirectiveLookupPlugin.d.mts +1 -0
  52. package/dist/vite/createDirectiveLookupPlugin.mjs +88 -57
  53. package/dist/vite/devServerTimingPlugin.d.mts +2 -0
  54. package/dist/vite/devServerTimingPlugin.mjs +24 -0
  55. package/dist/vite/directivesPlugin.mjs +168 -70
  56. package/dist/vite/findImportSpecifiers.d.mts +16 -0
  57. package/dist/vite/findImportSpecifiers.mjs +152 -0
  58. package/dist/vite/findImportSpecifiers.test.d.mts +1 -0
  59. package/dist/vite/findImportSpecifiers.test.mjs +73 -0
  60. package/dist/vite/findSpecifiers.d.mts +31 -0
  61. package/dist/vite/findSpecifiers.mjs +230 -0
  62. package/dist/vite/hasDirective.d.mts +7 -0
  63. package/dist/vite/hasDirective.mjs +54 -0
  64. package/dist/vite/hasOwnCloudflareVitePlugin.d.mts +3 -0
  65. package/dist/vite/hasOwnCloudflareVitePlugin.mjs +14 -0
  66. package/dist/vite/invalidateModule.d.mts +2 -0
  67. package/dist/vite/invalidateModule.mjs +14 -0
  68. package/dist/vite/miniflareHMRPlugin.d.mts +8 -0
  69. package/dist/vite/miniflareHMRPlugin.mjs +133 -0
  70. package/dist/vite/normalizeModulePath.mjs +12 -1
  71. package/dist/vite/redwoodPlugin.d.mts +1 -0
  72. package/dist/vite/redwoodPlugin.mjs +19 -4
  73. package/dist/vite/resolveModuleId.d.mts +6 -0
  74. package/dist/vite/resolveModuleId.mjs +14 -0
  75. package/dist/vite/ssrBridgePlugin.d.mts +5 -1
  76. package/dist/vite/ssrBridgePlugin.mjs +4 -43
  77. package/dist/vite/transformClientComponents.d.mts +1 -0
  78. package/dist/vite/transformClientComponents.mjs +61 -125
  79. package/dist/vite/transformJsxScriptTagsPlugin.mjs +14 -3
  80. package/dist/vite/transformServerFunctions.d.mts +11 -3
  81. package/dist/vite/transformServerFunctions.mjs +256 -171
  82. package/dist/vite/transformServerFunctions.test.mjs +22 -3
  83. package/dist/vite/useClientLookupPlugin.mjs +1 -0
  84. package/dist/vite/useServerLookupPlugin.mjs +1 -0
  85. package/dist/vite/useServerPlugin.d.mts +1 -1
  86. package/dist/vite/useServerPlugin.mjs +1 -1
  87. package/package.json +14 -3
@@ -1,4 +1,5 @@
1
1
  import { type CallServerCallback } from "react-server-dom-webpack/client.browser";
2
+ import { type HydrationOptions } from "react-dom/client";
2
3
  export type ActionResponse<Result> = {
3
4
  node: React.ReactNode;
4
5
  actionResult: Result;
@@ -9,7 +10,8 @@ type TransportContext = {
9
10
  export type Transport = (context: TransportContext) => CallServerCallback;
10
11
  export type CreateCallServer = (context: TransportContext) => <Result>(id: null | string, args: null | unknown[]) => Promise<Result>;
11
12
  export declare const fetchTransport: Transport;
12
- export declare const initClient: ({ transport, }?: {
13
+ export declare const initClient: ({ transport, hydrateRootOptions, }?: {
13
14
  transport?: Transport;
15
+ hydrateRootOptions?: HydrationOptions;
14
16
  }) => Promise<void>;
15
17
  export {};
@@ -21,7 +21,9 @@ export const fetchTransport = (transportContext) => {
21
21
  };
22
22
  return fetchCallServer;
23
23
  };
24
- export const initClient = async ({ transport = fetchTransport, } = {}) => {
24
+ export const initClient = async ({ transport = fetchTransport, hydrateRootOptions, } = {}) => {
25
+ const React = await import("react");
26
+ const { hydrateRoot } = await import("react-dom/client");
25
27
  const transportContext = {
26
28
  setRscPayload: () => { },
27
29
  };
@@ -37,25 +39,27 @@ export const initClient = async ({ transport = fetchTransport, } = {}) => {
37
39
  callServer,
38
40
  upgradeToRealtime,
39
41
  };
40
- const rootEl = document.getElementById("root");
42
+ const rootEl = document.getElementById("hydrate-root");
41
43
  if (!rootEl) {
42
- throw new Error('no element with id "root"');
44
+ throw new Error('no element with id "hydrate-root"');
43
45
  }
44
- const React = await import("react");
45
- const { hydrateRoot } = await import("react-dom/client");
46
- const { createFromReadableStream } = await import("react-server-dom-webpack/client.browser");
47
- const { rscStream } = await import("rsc-html-stream/client");
48
46
  let rscPayload;
49
- rscPayload ??= createFromReadableStream(rscStream, {
50
- callServer,
51
- });
47
+ // context(justinvdm, 18 Jun 2025): We inject the RSC payload
48
+ // unless render(Document, [...], { rscPayload: false }) was used.
49
+ if (globalThis.__FLIGHT_DATA) {
50
+ const { createFromReadableStream } = await import("react-server-dom-webpack/client.browser");
51
+ const { rscStream } = await import("rsc-html-stream/client");
52
+ rscPayload = createFromReadableStream(rscStream, {
53
+ callServer,
54
+ });
55
+ }
52
56
  function Content() {
53
57
  const [streamData, setStreamData] = React.useState(rscPayload);
54
58
  const [_isPending, startTransition] = React.useTransition();
55
59
  transportContext.setRscPayload = (v) => startTransition(() => setStreamData(v));
56
60
  return _jsx(_Fragment, { children: React.use(streamData).node });
57
61
  }
58
- hydrateRoot(rootEl, _jsx(Content, {}));
62
+ hydrateRoot(rootEl, _jsx(Content, {}), hydrateRootOptions);
59
63
  if (import.meta.hot) {
60
64
  import.meta.hot.on("rsc:update", (e) => {
61
65
  console.log("[rwsdk] hot update", e.file);
@@ -0,0 +1,3 @@
1
+ export declare function initClientNavigation(opts?: {
2
+ onNavigate: () => void;
3
+ }): void;
@@ -0,0 +1,43 @@
1
+ export function initClientNavigation(opts = {
2
+ onNavigate: async function onNavigate() {
3
+ // @ts-expect-error
4
+ await globalThis.__rsc_callServer();
5
+ },
6
+ }) {
7
+ // Intercept all anchor tag clicks
8
+ document.addEventListener("click", async function handleClickEvent(event) {
9
+ // should this only work for left click?
10
+ if (event.button !== 0) {
11
+ return;
12
+ }
13
+ if (event.ctrlKey || event.metaKey || event.shiftKey || event.altKey) {
14
+ return;
15
+ }
16
+ const target = event.target;
17
+ const link = target.closest("a");
18
+ if (!link) {
19
+ return;
20
+ }
21
+ const href = link.getAttribute("href");
22
+ if (!href) {
23
+ return;
24
+ }
25
+ // Skip if target="_blank" or similar
26
+ if (link.target && link.target !== "_self") {
27
+ return;
28
+ }
29
+ // Skip if download attribute
30
+ if (link.hasAttribute("download")) {
31
+ return;
32
+ }
33
+ // Prevent default navigation
34
+ event.preventDefault();
35
+ // push this to the history stack.
36
+ window.history.pushState({ path: href }, "", window.location.origin + href);
37
+ await opts.onNavigate();
38
+ }, true);
39
+ // Handle browser back/forward buttons
40
+ window.addEventListener("popstate", async function handlePopState() {
41
+ await opts.onNavigate();
42
+ });
43
+ }
@@ -1,3 +1,4 @@
1
1
  export * from "../client";
2
2
  export * from "../register/client";
3
3
  export * from "../lib/streams/consumeEventStream";
4
+ export * from "../clientNavigation";
@@ -1,3 +1,4 @@
1
1
  export * from "../client";
2
2
  export * from "../register/client";
3
3
  export * from "../lib/streams/consumeEventStream";
4
+ export * from "../clientNavigation";
@@ -5,3 +5,5 @@ export * from "../script";
5
5
  export * from "../lib/utils";
6
6
  export * from "../requestInfo/types";
7
7
  export * from "../requestInfo/worker";
8
+ export * from "../render/renderToString";
9
+ export * from "../render/renderToStream";
@@ -5,3 +5,5 @@ export * from "../script";
5
5
  export * from "../lib/utils";
6
6
  export * from "../requestInfo/types";
7
7
  export * from "../requestInfo/worker";
8
+ export * from "../render/renderToString";
9
+ export * from "../render/renderToStream";
@@ -0,0 +1,3 @@
1
+ export declare const ClientOnly: ({ children }: {
2
+ children: React.ReactNode;
3
+ }) => import("react").ReactNode;
@@ -0,0 +1,8 @@
1
+ import { useEffect, useState } from "react";
2
+ export const ClientOnly = ({ children }) => {
3
+ const [didUpdate, setDidUpdate] = useState(false);
4
+ useEffect(() => {
5
+ setDidUpdate(true);
6
+ }, []);
7
+ return didUpdate ? children : null;
8
+ };
@@ -0,0 +1 @@
1
+ export declare const NoSSRStub: () => import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,4 @@
1
+ "use client";
2
+ import { jsx as _jsx } from "react/jsx-runtime";
3
+ import { ClientOnly } from "./ClientOnly";
4
+ export const NoSSRStub = () => _jsx(ClientOnly, { children: null });
@@ -1,3 +1,4 @@
1
+ import React from "react";
1
2
  import memoize from "lodash/memoize";
2
3
  export const loadModule = memoize(async (id) => {
3
4
  if (import.meta.env.DEV && !process.env.PREVIEW) {
@@ -15,6 +16,18 @@ export const loadModule = memoize(async (id) => {
15
16
  // context(justinvdm, 2 Dec 2024): re memoize(): React relies on the same promise instance being returned for the same id
16
17
  export const clientWebpackRequire = memoize(async (id) => {
17
18
  const [file, name] = id.split("#");
18
- const module = await loadModule(file);
19
- return { [id]: module[name] };
19
+ const promisedModule = loadModule(file);
20
+ const promisedComponent = promisedModule.then((module) => module[name]);
21
+ const didSSR = globalThis.__RWSDK_CONTEXT?.rw?.ssr;
22
+ if (didSSR) {
23
+ const awaitedComponent = await promisedComponent;
24
+ return { [id]: awaitedComponent };
25
+ }
26
+ const { ClientOnly } = await import("./ClientOnly");
27
+ const promisedDefault = promisedComponent.then((Component) => ({
28
+ default: Component,
29
+ }));
30
+ const Lazy = React.lazy(() => promisedDefault);
31
+ const Wrapped = () => React.createElement(ClientOnly, null, React.createElement(Lazy));
32
+ return { [id]: Wrapped };
20
33
  });
@@ -1,5 +1,5 @@
1
1
  export declare const loadServerModule: ((id: string) => Promise<any>) & import("lodash").MemoizedFunction;
2
2
  export declare const getServerModuleExport: (id: string) => Promise<any>;
3
- export declare const serverWebpackRequire: ((id: string) => Promise<{
3
+ export declare const ssrWebpackRequire: ((id: string) => Promise<{
4
4
  [x: string]: any;
5
5
  }>) & import("lodash").MemoizedFunction;
@@ -1,4 +1,6 @@
1
1
  import memoize from "lodash/memoize";
2
+ import { requestInfo } from "../requestInfo/worker";
3
+ import { ssrWebpackRequire as baseSsrWebpackRequire } from "rwsdk/__ssr_bridge";
2
4
  export const loadServerModule = memoize(async (id) => {
3
5
  const { useServerLookup } = await import("virtual:use-server-lookup");
4
6
  const moduleFn = useServerLookup[id];
@@ -12,9 +14,9 @@ export const getServerModuleExport = async (id) => {
12
14
  const module = await loadServerModule(file);
13
15
  return module[name];
14
16
  };
15
- // context(justinvdm, 2 Dec 2024): re memoize(): React relies on the same promise instance being returned for the same id
16
- export const serverWebpackRequire = memoize(async (id) => {
17
- const [file, name] = id.split("#");
18
- const module = await loadServerModule(file);
19
- return { [id]: module[name] };
17
+ export const ssrWebpackRequire = memoize(async (id) => {
18
+ if (!requestInfo.rw.ssr) {
19
+ return { [id]: () => null };
20
+ }
21
+ return baseSsrWebpackRequire(id);
20
22
  });
@@ -0,0 +1,29 @@
1
+ import { SqliteAdapter, SqliteIntrospector, SqliteQueryCompiler, Driver, DatabaseConnection } from "kysely";
2
+ export declare class DOWorkerDialect {
3
+ config: {
4
+ stub: any;
5
+ };
6
+ constructor(config: {
7
+ stub: any;
8
+ });
9
+ createAdapter(): SqliteAdapter;
10
+ createDriver(): DOWorkerDriver;
11
+ createQueryCompiler(): SqliteQueryCompiler;
12
+ createIntrospector(db: any): SqliteIntrospector;
13
+ }
14
+ declare class DOWorkerDriver implements Driver {
15
+ config: {
16
+ stub: any;
17
+ };
18
+ constructor(config: {
19
+ stub: any;
20
+ });
21
+ init(): Promise<void>;
22
+ acquireConnection(): Promise<DatabaseConnection>;
23
+ beginTransaction(conn: any): Promise<any>;
24
+ commitTransaction(conn: any): Promise<any>;
25
+ rollbackTransaction(conn: any): Promise<any>;
26
+ releaseConnection(_conn: any): Promise<void>;
27
+ destroy(): Promise<void>;
28
+ }
29
+ export {};
@@ -0,0 +1,66 @@
1
+ import debug from "../debug";
2
+ import { SqliteAdapter, SqliteIntrospector, SqliteQueryCompiler, } from "kysely";
3
+ const log = debug("sdk:db:do-worker-dialect");
4
+ export class DOWorkerDialect {
5
+ constructor(config) {
6
+ this.config = config;
7
+ }
8
+ createAdapter() {
9
+ return new SqliteAdapter();
10
+ }
11
+ createDriver() {
12
+ return new DOWorkerDriver(this.config);
13
+ }
14
+ createQueryCompiler() {
15
+ return new SqliteQueryCompiler();
16
+ }
17
+ createIntrospector(db) {
18
+ return new SqliteIntrospector(db);
19
+ }
20
+ }
21
+ class DOWorkerDriver {
22
+ constructor(config) {
23
+ this.config = config;
24
+ }
25
+ async init() { }
26
+ async acquireConnection() {
27
+ return new DOWorkerConnection(this.config.stub.kyselyExecuteQuery);
28
+ }
29
+ async beginTransaction(conn) {
30
+ return await conn.beginTransaction();
31
+ }
32
+ async commitTransaction(conn) {
33
+ return await conn.commitTransaction();
34
+ }
35
+ async rollbackTransaction(conn) {
36
+ return await conn.rollbackTransaction();
37
+ }
38
+ async releaseConnection(_conn) { }
39
+ async destroy() { }
40
+ }
41
+ class DOWorkerConnection {
42
+ constructor(executeQuery) {
43
+ this._executeQuery = executeQuery;
44
+ }
45
+ async executeQuery(compiledQuery) {
46
+ log("Forwarding query to Durable Object: %s", compiledQuery.sql);
47
+ // Call the DO's kyselyExecuteQuery method
48
+ const result = await this._executeQuery({
49
+ sql: compiledQuery.sql,
50
+ parameters: compiledQuery.parameters,
51
+ });
52
+ return result;
53
+ }
54
+ async beginTransaction() {
55
+ throw new Error("Transactions are not supported yet.");
56
+ }
57
+ async commitTransaction() {
58
+ throw new Error("Transactions are not supported yet.");
59
+ }
60
+ async rollbackTransaction() {
61
+ throw new Error("Transactions are not supported yet.");
62
+ }
63
+ async *streamQuery(_compiledQuery, _chunkSize) {
64
+ throw new Error("DO Driver does not support streaming");
65
+ }
66
+ }
@@ -0,0 +1,14 @@
1
+ import { DurableObject } from "cloudflare:workers";
2
+ import { Kysely, QueryResult } from "kysely";
3
+ export declare class SqliteDurableObject<T = any> extends DurableObject {
4
+ migrations: Record<string, any>;
5
+ kysely: Kysely<T>;
6
+ private initialized;
7
+ private migrationTableName;
8
+ constructor(ctx: DurableObjectState, env: any, migrations: Record<string, any>, migrationTableName?: string);
9
+ private initialize;
10
+ kyselyExecuteQuery<R>(compiledQuery: {
11
+ sql: string;
12
+ parameters: readonly unknown[];
13
+ }): Promise<QueryResult<R>>;
14
+ }
@@ -0,0 +1,42 @@
1
+ import { DODialect } from "kysely-do";
2
+ import { DurableObject } from "cloudflare:workers";
3
+ import { Kysely } from "kysely";
4
+ import { createMigrator } from "./index.js";
5
+ import debug from "../debug.js";
6
+ const log = debug("sdk:do-db");
7
+ // Base class for Durable Objects that need Kysely database access
8
+ export class SqliteDurableObject extends DurableObject {
9
+ constructor(ctx, env, migrations, migrationTableName = "__migrations") {
10
+ super(ctx, env);
11
+ this.initialized = false;
12
+ this.migrations = migrations;
13
+ this.migrationTableName = migrationTableName;
14
+ this.kysely = new Kysely({
15
+ dialect: new DODialect({ ctx }),
16
+ });
17
+ }
18
+ async initialize() {
19
+ if (this.initialized) {
20
+ log("Database already initialized, skipping");
21
+ return;
22
+ }
23
+ log("Initializing Durable Object database");
24
+ const migrator = createMigrator(this.kysely, this.migrations, this.migrationTableName);
25
+ await migrator.migrateToLatest();
26
+ this.initialized = true;
27
+ log("Database initialization complete");
28
+ }
29
+ // RPC method for executing queries - must be on prototype for RPC to work
30
+ async kyselyExecuteQuery(compiledQuery) {
31
+ await this.initialize();
32
+ log("Executing SQL: %s with params: %o", compiledQuery.sql, compiledQuery.parameters);
33
+ // Forward to the internal Kysely database
34
+ const result = await this.kysely.executeQuery({
35
+ sql: compiledQuery.sql,
36
+ parameters: compiledQuery.parameters,
37
+ query: {},
38
+ queryId: {},
39
+ });
40
+ return result;
41
+ }
42
+ }
@@ -0,0 +1,3 @@
1
+ import { Kysely } from "kysely";
2
+ export declare function createDurableObjectDb<T>(durableObjectBinding: any, name?: string): Kysely<T>;
3
+ export declare function createDb<T>(durableObjectBinding: any, name?: string): Kysely<T>;
@@ -0,0 +1,36 @@
1
+ import { Kysely } from "kysely";
2
+ import { requestInfo } from "../../requestInfo/worker.js";
3
+ import { DOWorkerDialect } from "./SqliteDurableObject.js";
4
+ export function createDurableObjectDb(durableObjectBinding, name = "main") {
5
+ const durableObjectId = durableObjectBinding.idFromName(name);
6
+ const stub = durableObjectBinding.get(durableObjectId);
7
+ return new Kysely({
8
+ dialect: new DOWorkerDialect({ stub }),
9
+ });
10
+ }
11
+ export function createDb(durableObjectBinding, name = "main") {
12
+ // Create a cache key from the binding and name
13
+ const cacheKey = `${durableObjectBinding}_${name}`;
14
+ // Return a proxy that lazily creates and caches the database instance
15
+ return new Proxy({}, {
16
+ get(target, prop, receiver) {
17
+ if (!requestInfo.rw.databases) {
18
+ requestInfo.rw.databases = new Map();
19
+ }
20
+ // Check if we have a cached instance
21
+ let db = requestInfo.rw.databases.get(cacheKey);
22
+ if (!db) {
23
+ // Create the database instance and cache it
24
+ db = createDurableObjectDb(durableObjectBinding, name);
25
+ requestInfo.rw.databases.set(cacheKey, db);
26
+ }
27
+ // Forward the property access to the actual database instance
28
+ const value = db[prop];
29
+ // If it's a function, bind it to the database instance
30
+ if (typeof value === "function") {
31
+ return value.bind(db);
32
+ }
33
+ return value;
34
+ },
35
+ });
36
+ }
@@ -0,0 +1,2 @@
1
+ import { Kysely } from "kysely";
2
+ export declare function createDb<T>(durableObjectBinding: any, name?: string): Kysely<T>;
@@ -0,0 +1,27 @@
1
+ import { Kysely } from "kysely";
2
+ import { requestInfo } from "../../requestInfo/worker.js";
3
+ import { DOWorkerDialect } from "./DOWorkerDialect.js";
4
+ const createDurableObjectDb = (durableObjectBinding, name = "main") => {
5
+ const durableObjectId = durableObjectBinding.idFromName(name);
6
+ const stub = durableObjectBinding.get(durableObjectId);
7
+ return new Kysely({
8
+ dialect: new DOWorkerDialect({ stub }),
9
+ });
10
+ };
11
+ export function createDb(durableObjectBinding, name = "main") {
12
+ const cacheKey = `${durableObjectBinding}_${name}`;
13
+ return new Proxy({}, {
14
+ get(target, prop, receiver) {
15
+ let db = requestInfo.rw.databases.get(cacheKey);
16
+ if (!db) {
17
+ db = createDurableObjectDb(durableObjectBinding, name);
18
+ requestInfo.rw.databases.set(cacheKey, db);
19
+ }
20
+ const value = db[prop];
21
+ if (typeof value === "function") {
22
+ return value.bind(db);
23
+ }
24
+ return value;
25
+ },
26
+ });
27
+ }
@@ -0,0 +1,3 @@
1
+ export * from "./migrations.js";
2
+ export * from "./SqliteDurableObject.js";
3
+ export * from "./createDb.js";
@@ -0,0 +1,3 @@
1
+ export * from "./migrations.js";
2
+ export * from "./SqliteDurableObject.js";
3
+ export * from "./createDb.js";
@@ -0,0 +1,2 @@
1
+ declare const debug: (namespace: string) => (...args: any[]) => void;
2
+ export default debug;
@@ -0,0 +1,41 @@
1
+ // Simple debug function with DEBUG environment variable filtering
2
+ // Supports patterns like: DEBUG=passkey:* or DEBUG=passkey:database,passkey:functions
3
+ function isEnabled(namespace) {
4
+ const debug = process.env.DEBUG;
5
+ if (!debug)
6
+ return false;
7
+ // Split by comma and check each pattern
8
+ const patterns = debug.split(",").map((p) => p.trim());
9
+ for (const pattern of patterns) {
10
+ // Handle exclusions (patterns starting with -)
11
+ if (pattern.startsWith("-")) {
12
+ const excludePattern = pattern.slice(1);
13
+ if (matchesPattern(namespace, excludePattern)) {
14
+ return false;
15
+ }
16
+ continue;
17
+ }
18
+ // Check if namespace matches this pattern
19
+ if (matchesPattern(namespace, pattern)) {
20
+ return true;
21
+ }
22
+ }
23
+ return false;
24
+ }
25
+ function matchesPattern(namespace, pattern) {
26
+ // Convert pattern to regex (handle * wildcards)
27
+ const regex = pattern
28
+ .replace(/\*/g, ".*") // * becomes .*
29
+ .replace(/:/g, "\\:"); // escape colons
30
+ return new RegExp(`^${regex}$`).test(namespace);
31
+ }
32
+ // Factory function that creates a debugger for a given namespace
33
+ const debug = (namespace) => {
34
+ return (...args) => {
35
+ if (isEnabled(namespace)) {
36
+ console.log(`[${namespace}]`, ...args);
37
+ }
38
+ };
39
+ };
40
+ // Export the factory function as default (like the real debug package)
41
+ export default debug;
@@ -0,0 +1,23 @@
1
+ import { Kysely, Migration, Migrator, MigrationProvider } from "kysely";
2
+ /**
3
+ * A custom MigrationProvider that works with in-memory migrations
4
+ * rather than reading from files.
5
+ */
6
+ export declare class InMemoryMigrationProvider implements MigrationProvider {
7
+ private migrations;
8
+ constructor(migrations: Record<string, Migration>);
9
+ getMigrations(): Promise<Record<string, Migration>>;
10
+ }
11
+ /**
12
+ * Helper function to create a migrator using Kysely's built-in Migrator.
13
+ *
14
+ * @example
15
+ * ```typescript
16
+ * const migrator = createMigrator(db, migrations, "__my_migrations");
17
+ * const result = await migrator.migrateToLatest();
18
+ * if (result.error) {
19
+ * throw new Error(`Migration failed: ${result.error}`);
20
+ * }
21
+ * ```
22
+ */
23
+ export declare function createMigrator(db: Kysely<any>, migrations: Record<string, Migration>, migrationTableName?: string): Migrator;
@@ -0,0 +1,34 @@
1
+ import { Migrator } from "kysely";
2
+ /**
3
+ * A custom MigrationProvider that works with in-memory migrations
4
+ * rather than reading from files.
5
+ */
6
+ export class InMemoryMigrationProvider {
7
+ constructor(migrations) {
8
+ this.migrations = migrations;
9
+ }
10
+ async getMigrations() {
11
+ return this.migrations;
12
+ }
13
+ }
14
+ /**
15
+ * Helper function to create a migrator using Kysely's built-in Migrator.
16
+ *
17
+ * @example
18
+ * ```typescript
19
+ * const migrator = createMigrator(db, migrations, "__my_migrations");
20
+ * const result = await migrator.migrateToLatest();
21
+ * if (result.error) {
22
+ * throw new Error(`Migration failed: ${result.error}`);
23
+ * }
24
+ * ```
25
+ */
26
+ export function createMigrator(db, migrations, migrationTableName = "__rwsdk_migrations") {
27
+ return new Migrator({
28
+ db,
29
+ provider: new InMemoryMigrationProvider(migrations),
30
+ migrationTableName,
31
+ // Use a custom lock table name based on the migration table name
32
+ migrationLockTableName: `${migrationTableName}_lock`,
33
+ });
34
+ }
File without changes
@@ -0,0 +1 @@
1
+ "use strict";
@@ -0,0 +1,2 @@
1
+ declare const debug: (namespace: string) => (...args: any[]) => void;
2
+ export default debug;
@@ -0,0 +1,36 @@
1
+ // Simple debug function with DEBUG environment variable filtering
2
+ // Supports patterns like: DEBUG=passkey:* or DEBUG=passkey:database,passkey:functions
3
+ function isEnabled(namespace) {
4
+ const debug = process.env.DEBUG;
5
+ if (!debug)
6
+ return false;
7
+ const patterns = debug.split(",").map((p) => p.trim());
8
+ for (const pattern of patterns) {
9
+ if (pattern.startsWith("-")) {
10
+ const excludePattern = pattern.slice(1);
11
+ if (matchesPattern(namespace, excludePattern)) {
12
+ return false;
13
+ }
14
+ continue;
15
+ }
16
+ if (matchesPattern(namespace, pattern)) {
17
+ return true;
18
+ }
19
+ }
20
+ return false;
21
+ }
22
+ function matchesPattern(namespace, pattern) {
23
+ // Convert pattern to regex (handle * wildcards)
24
+ const regex = pattern
25
+ .replace(/\*/g, ".*") // * becomes .*
26
+ .replace(/:/g, "\\:"); // escape colons
27
+ return new RegExp(`^${regex}$`).test(namespace);
28
+ }
29
+ const debug = (namespace) => {
30
+ return (...args) => {
31
+ if (isEnabled(namespace)) {
32
+ console.log(`[${namespace}]`, ...args);
33
+ }
34
+ };
35
+ };
36
+ export default debug;
@@ -1,5 +1,6 @@
1
1
  import React from "react";
2
2
  import { RequestInfo } from "../requestInfo/types";
3
+ import type { Kysely } from "kysely";
3
4
  export type DocumentProps<T extends RequestInfo = RequestInfo> = T & {
4
5
  children: React.ReactNode;
5
6
  };
@@ -11,7 +12,9 @@ export type RwContext = {
11
12
  nonce: string;
12
13
  Document: React.FC<DocumentProps<any>>;
13
14
  rscPayload: boolean;
15
+ ssr: boolean;
14
16
  layouts?: React.FC<LayoutProps<any>>[];
17
+ databases: Map<string, Kysely<any>>;
15
18
  };
16
19
  export type RouteMiddleware<T extends RequestInfo = RequestInfo> = (requestInfo: T) => Response | Promise<Response> | void | Promise<void> | Promise<Response | void>;
17
20
  type RouteFunction<T extends RequestInfo = RequestInfo> = (requestInfo: T) => Response | Promise<Response>;
@@ -43,9 +46,11 @@ export declare function render<T extends RequestInfo = RequestInfo>(Document: Re
43
46
  /**
44
47
  * @param options - Configuration options for rendering.
45
48
  * @param options.rscPayload - Toggle the RSC payload that's appended to the Document. Disabling this will mean that interactivity no longer works.
49
+ * @param options.ssr - Disable sever side rendering for all these routes. This only allow client side rendering`, which requires `rscPayload` to be enabled.
46
50
  */
47
51
  options?: {
48
- rscPayload: boolean;
52
+ rscPayload?: boolean;
53
+ ssr?: boolean;
49
54
  }): Route<T>[];
50
55
  export declare const isClientReference: (Component: React.FC<any>) => boolean;
51
56
  export {};