rwsdk 1.0.0-beta.4 → 1.0.0-beta.40

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 (139) hide show
  1. package/dist/lib/constants.d.mts +1 -0
  2. package/dist/lib/constants.mjs +7 -4
  3. package/dist/lib/e2e/browser.mjs +6 -2
  4. package/dist/lib/e2e/constants.d.mts +4 -0
  5. package/dist/lib/e2e/constants.mjs +49 -12
  6. package/dist/lib/e2e/dev.mjs +37 -49
  7. package/dist/lib/e2e/environment.d.mts +2 -0
  8. package/dist/lib/e2e/environment.mjs +201 -64
  9. package/dist/lib/e2e/index.d.mts +1 -0
  10. package/dist/lib/e2e/index.mjs +1 -0
  11. package/dist/lib/e2e/poll.d.mts +1 -1
  12. package/dist/lib/e2e/release.d.mts +1 -0
  13. package/dist/lib/e2e/release.mjs +16 -32
  14. package/dist/lib/e2e/tarball.mjs +2 -34
  15. package/dist/lib/e2e/testHarness.d.mts +34 -3
  16. package/dist/lib/e2e/testHarness.mjs +219 -90
  17. package/dist/lib/e2e/utils.d.mts +1 -0
  18. package/dist/lib/e2e/utils.mjs +15 -0
  19. package/dist/runtime/client/client.d.ts +35 -0
  20. package/dist/runtime/client/client.js +35 -0
  21. package/dist/runtime/client/navigation.d.ts +49 -0
  22. package/dist/runtime/client/navigation.js +80 -31
  23. package/dist/runtime/entries/clientSSR.d.ts +1 -0
  24. package/dist/runtime/entries/clientSSR.js +3 -0
  25. package/dist/runtime/entries/no-react-server-ssr-bridge.d.ts +0 -0
  26. package/dist/runtime/entries/no-react-server-ssr-bridge.js +2 -0
  27. package/dist/runtime/entries/router.d.ts +1 -0
  28. package/dist/runtime/entries/routerClient.d.ts +1 -0
  29. package/dist/runtime/entries/routerClient.js +1 -0
  30. package/dist/runtime/entries/worker.d.ts +2 -0
  31. package/dist/runtime/entries/worker.js +2 -0
  32. package/dist/runtime/imports/__mocks__/use-client-lookup.d.ts +6 -0
  33. package/dist/runtime/imports/__mocks__/use-client-lookup.js +6 -0
  34. package/dist/runtime/lib/db/SqliteDurableObject.d.ts +2 -2
  35. package/dist/runtime/lib/db/SqliteDurableObject.js +2 -2
  36. package/dist/runtime/lib/db/createDb.d.ts +1 -2
  37. package/dist/runtime/lib/db/createDb.js +4 -0
  38. package/dist/runtime/lib/db/typeInference/builders/alterTable.d.ts +13 -3
  39. package/dist/runtime/lib/db/typeInference/builders/columnDefinition.d.ts +35 -21
  40. package/dist/runtime/lib/db/typeInference/builders/createTable.d.ts +9 -2
  41. package/dist/runtime/lib/db/typeInference/database.d.ts +16 -2
  42. package/dist/runtime/lib/db/typeInference/typetests/alterTable.typetest.js +80 -5
  43. package/dist/runtime/lib/db/typeInference/typetests/createTable.typetest.js +104 -2
  44. package/dist/runtime/lib/db/typeInference/typetests/testUtils.d.ts +1 -0
  45. package/dist/runtime/lib/db/typeInference/utils.d.ts +59 -9
  46. package/dist/runtime/lib/links.d.ts +21 -7
  47. package/dist/runtime/lib/links.js +82 -24
  48. package/dist/runtime/lib/links.test.js +20 -0
  49. package/dist/runtime/lib/manifest.d.ts +1 -1
  50. package/dist/runtime/lib/manifest.js +7 -4
  51. package/dist/runtime/lib/realtime/client.js +8 -2
  52. package/dist/runtime/lib/realtime/worker.d.ts +1 -1
  53. package/dist/runtime/lib/router.d.ts +153 -36
  54. package/dist/runtime/lib/router.js +169 -20
  55. package/dist/runtime/lib/router.test.js +241 -0
  56. package/dist/runtime/lib/stitchDocumentAndAppStreams.d.ts +66 -0
  57. package/dist/runtime/lib/stitchDocumentAndAppStreams.js +302 -35
  58. package/dist/runtime/lib/stitchDocumentAndAppStreams.test.d.ts +1 -0
  59. package/dist/runtime/lib/stitchDocumentAndAppStreams.test.js +418 -0
  60. package/dist/runtime/lib/{rwContext.d.ts → types.d.ts} +1 -0
  61. package/dist/runtime/lib/types.js +1 -0
  62. package/dist/runtime/render/renderDocumentHtmlStream.d.ts +1 -1
  63. package/dist/runtime/render/renderToStream.d.ts +4 -2
  64. package/dist/runtime/render/renderToStream.js +53 -24
  65. package/dist/runtime/render/renderToString.d.ts +3 -6
  66. package/dist/runtime/requestInfo/types.d.ts +4 -1
  67. package/dist/runtime/requestInfo/utils.d.ts +9 -0
  68. package/dist/runtime/requestInfo/utils.js +44 -0
  69. package/dist/runtime/requestInfo/worker.d.ts +0 -1
  70. package/dist/runtime/requestInfo/worker.js +3 -10
  71. package/dist/runtime/script.d.ts +1 -3
  72. package/dist/runtime/script.js +1 -10
  73. package/dist/runtime/state.d.ts +3 -0
  74. package/dist/runtime/state.js +13 -0
  75. package/dist/runtime/worker.d.ts +3 -1
  76. package/dist/runtime/worker.js +32 -0
  77. package/dist/scripts/debug-sync.mjs +18 -20
  78. package/dist/scripts/worker-run.d.mts +1 -1
  79. package/dist/scripts/worker-run.mjs +59 -113
  80. package/dist/use-synced-state/SyncedStateServer.d.mts +21 -0
  81. package/dist/use-synced-state/SyncedStateServer.mjs +128 -0
  82. package/dist/use-synced-state/__tests__/SyncStateServer.test.d.mts +1 -0
  83. package/dist/use-synced-state/__tests__/SyncStateServer.test.mjs +109 -0
  84. package/dist/use-synced-state/__tests__/useSyncState.test.d.ts +1 -0
  85. package/dist/use-synced-state/__tests__/useSyncState.test.js +115 -0
  86. package/dist/use-synced-state/__tests__/useSyncedState.test.d.ts +1 -0
  87. package/dist/use-synced-state/__tests__/useSyncedState.test.js +115 -0
  88. package/dist/use-synced-state/__tests__/worker.test.d.mts +1 -0
  89. package/dist/use-synced-state/__tests__/worker.test.mjs +69 -0
  90. package/dist/use-synced-state/client-core.d.ts +26 -0
  91. package/dist/use-synced-state/client-core.js +39 -0
  92. package/dist/use-synced-state/client.d.ts +3 -0
  93. package/dist/use-synced-state/client.js +4 -0
  94. package/dist/use-synced-state/constants.d.mts +1 -0
  95. package/dist/use-synced-state/constants.mjs +1 -0
  96. package/dist/use-synced-state/useSyncedState.d.ts +20 -0
  97. package/dist/use-synced-state/useSyncedState.js +58 -0
  98. package/dist/use-synced-state/worker.d.mts +13 -0
  99. package/dist/use-synced-state/worker.mjs +69 -0
  100. package/dist/vite/buildApp.mjs +34 -2
  101. package/dist/vite/cloudflarePreInitPlugin.d.mts +11 -0
  102. package/dist/vite/cloudflarePreInitPlugin.mjs +40 -0
  103. package/dist/vite/configPlugin.mjs +9 -14
  104. package/dist/vite/constants.d.mts +1 -0
  105. package/dist/vite/constants.mjs +1 -0
  106. package/dist/vite/createDirectiveLookupPlugin.mjs +10 -7
  107. package/dist/vite/devServerTimingPlugin.mjs +4 -0
  108. package/dist/vite/diagnosticAssetGraphPlugin.d.mts +4 -0
  109. package/dist/vite/diagnosticAssetGraphPlugin.mjs +41 -0
  110. package/dist/vite/directiveModulesDevPlugin.mjs +9 -1
  111. package/dist/vite/directivesPlugin.mjs +4 -4
  112. package/dist/vite/envResolvers.d.mts +11 -0
  113. package/dist/vite/envResolvers.mjs +20 -0
  114. package/dist/vite/getViteEsbuild.mjs +2 -1
  115. package/dist/vite/hmrStabilityPlugin.d.mts +2 -0
  116. package/dist/vite/hmrStabilityPlugin.mjs +73 -0
  117. package/dist/vite/injectVitePreamblePlugin.mjs +0 -4
  118. package/dist/vite/knownDepsResolverPlugin.d.mts +0 -6
  119. package/dist/vite/knownDepsResolverPlugin.mjs +25 -17
  120. package/dist/vite/linkerPlugin.d.mts +2 -1
  121. package/dist/vite/linkerPlugin.mjs +11 -3
  122. package/dist/vite/linkerPlugin.test.mjs +15 -0
  123. package/dist/vite/miniflareHMRPlugin.mjs +6 -38
  124. package/dist/vite/moveStaticAssetsPlugin.mjs +35 -4
  125. package/dist/vite/redwoodPlugin.mjs +8 -10
  126. package/dist/vite/runDirectivesScan.mjs +72 -18
  127. package/dist/vite/ssrBridgePlugin.mjs +132 -40
  128. package/dist/vite/ssrBridgeWrapPlugin.d.mts +2 -0
  129. package/dist/vite/ssrBridgeWrapPlugin.mjs +85 -0
  130. package/dist/vite/staleDepRetryPlugin.d.mts +2 -0
  131. package/dist/vite/staleDepRetryPlugin.mjs +74 -0
  132. package/dist/vite/statePlugin.d.mts +4 -0
  133. package/dist/vite/statePlugin.mjs +62 -0
  134. package/dist/vite/transformJsxScriptTagsPlugin.mjs +0 -5
  135. package/dist/vite/virtualPlugin.mjs +6 -7
  136. package/package.json +27 -10
  137. package/dist/vite/manifestPlugin.d.mts +0 -4
  138. package/dist/vite/manifestPlugin.mjs +0 -63
  139. /package/dist/runtime/lib/{rwContext.js → links.test.d.ts} +0 -0
@@ -4,6 +4,55 @@ export interface ClientNavigationOptions {
4
4
  scrollBehavior?: "auto" | "smooth" | "instant";
5
5
  }
6
6
  export declare function validateClickEvent(event: MouseEvent, target: HTMLElement): boolean;
7
+ export interface NavigateOptions {
8
+ history?: "push" | "replace";
9
+ info?: {
10
+ scrollToTop?: boolean;
11
+ scrollBehavior?: "auto" | "smooth" | "instant";
12
+ };
13
+ }
14
+ export declare function navigate(href: string, options?: NavigateOptions): Promise<void>;
15
+ /**
16
+ * Initializes client-side navigation for Single Page App (SPA) behavior.
17
+ *
18
+ * Intercepts clicks on internal links and fetches page content without full-page reloads.
19
+ * Returns a handleResponse function to pass to initClient.
20
+ *
21
+ * @param opts.scrollToTop - Scroll to top after navigation (default: true)
22
+ * @param opts.scrollBehavior - How to scroll: 'instant', 'smooth', or 'auto' (default: 'instant')
23
+ * @param opts.onNavigate - Callback executed after history push but before RSC fetch
24
+ *
25
+ * @example
26
+ * // Basic usage
27
+ * import { initClient, initClientNavigation } from "rwsdk/client";
28
+ *
29
+ * const { handleResponse } = initClientNavigation();
30
+ * initClient({ handleResponse });
31
+ *
32
+ * @example
33
+ * // With custom scroll behavior
34
+ * const { handleResponse } = initClientNavigation({
35
+ * scrollBehavior: "smooth",
36
+ * scrollToTop: true,
37
+ * });
38
+ * initClient({ handleResponse });
39
+ *
40
+ * @example
41
+ * // Preserve scroll position (e.g., for infinite scroll)
42
+ * const { handleResponse } = initClientNavigation({
43
+ * scrollToTop: false,
44
+ * });
45
+ * initClient({ handleResponse });
46
+ *
47
+ * @example
48
+ * // With navigation callback
49
+ * const { handleResponse } = initClientNavigation({
50
+ * onNavigate: () => {
51
+ * console.log("Navigating to:", window.location.href);
52
+ * },
53
+ * });
54
+ * initClient({ handleResponse });
55
+ */
7
56
  export declare function initClientNavigation(opts?: ClientNavigationOptions): {
8
57
  handleResponse: (response: Response) => boolean;
9
58
  };
@@ -1,10 +1,3 @@
1
- function saveScrollPosition(x, y) {
2
- window.history.replaceState({
3
- ...window.history.state,
4
- scrollX: x,
5
- scrollY: y,
6
- }, "", window.location.href);
7
- }
8
1
  export function validateClickEvent(event, target) {
9
2
  // should this only work for left click?
10
3
  if (event.button !== 0) {
@@ -37,19 +30,85 @@ export function validateClickEvent(event, target) {
37
30
  }
38
31
  return true;
39
32
  }
33
+ let IS_CLIENT_NAVIGATION = false;
34
+ export async function navigate(href, options = { history: "push" }) {
35
+ if (!IS_CLIENT_NAVIGATION) {
36
+ window.location.href = href;
37
+ return;
38
+ }
39
+ saveScrollPosition(window.scrollX, window.scrollY);
40
+ const url = window.location.origin + href;
41
+ if (options.history === "push") {
42
+ window.history.pushState({ path: href }, "", url);
43
+ }
44
+ else {
45
+ window.history.replaceState({ path: href }, "", url);
46
+ }
47
+ // @ts-expect-error
48
+ await globalThis.__rsc_callServer();
49
+ const scrollToTop = options.info?.scrollToTop ?? true;
50
+ const scrollBehavior = options.info?.scrollBehavior ?? "instant";
51
+ if (scrollToTop && history.scrollRestoration === "auto") {
52
+ window.scrollTo({
53
+ top: 0,
54
+ left: 0,
55
+ behavior: scrollBehavior,
56
+ });
57
+ saveScrollPosition(0, 0);
58
+ }
59
+ }
60
+ function saveScrollPosition(x, y) {
61
+ window.history.replaceState({
62
+ ...window.history.state,
63
+ scrollX: x,
64
+ scrollY: y,
65
+ }, "", window.location.href);
66
+ }
67
+ /**
68
+ * Initializes client-side navigation for Single Page App (SPA) behavior.
69
+ *
70
+ * Intercepts clicks on internal links and fetches page content without full-page reloads.
71
+ * Returns a handleResponse function to pass to initClient.
72
+ *
73
+ * @param opts.scrollToTop - Scroll to top after navigation (default: true)
74
+ * @param opts.scrollBehavior - How to scroll: 'instant', 'smooth', or 'auto' (default: 'instant')
75
+ * @param opts.onNavigate - Callback executed after history push but before RSC fetch
76
+ *
77
+ * @example
78
+ * // Basic usage
79
+ * import { initClient, initClientNavigation } from "rwsdk/client";
80
+ *
81
+ * const { handleResponse } = initClientNavigation();
82
+ * initClient({ handleResponse });
83
+ *
84
+ * @example
85
+ * // With custom scroll behavior
86
+ * const { handleResponse } = initClientNavigation({
87
+ * scrollBehavior: "smooth",
88
+ * scrollToTop: true,
89
+ * });
90
+ * initClient({ handleResponse });
91
+ *
92
+ * @example
93
+ * // Preserve scroll position (e.g., for infinite scroll)
94
+ * const { handleResponse } = initClientNavigation({
95
+ * scrollToTop: false,
96
+ * });
97
+ * initClient({ handleResponse });
98
+ *
99
+ * @example
100
+ * // With navigation callback
101
+ * const { handleResponse } = initClientNavigation({
102
+ * onNavigate: () => {
103
+ * console.log("Navigating to:", window.location.href);
104
+ * },
105
+ * });
106
+ * initClient({ handleResponse });
107
+ */
40
108
  export function initClientNavigation(opts = {}) {
41
- const options = {
42
- onNavigate: async function onNavigate() {
43
- // @ts-expect-error
44
- await globalThis.__rsc_callServer();
45
- },
46
- scrollToTop: true,
47
- scrollBehavior: "instant",
48
- ...opts,
49
- };
109
+ IS_CLIENT_NAVIGATION = true;
50
110
  history.scrollRestoration = "auto";
51
111
  document.addEventListener("click", async function handleClickEvent(event) {
52
- // Prevent default navigation
53
112
  if (!validateClickEvent(event, event.target)) {
54
113
  return;
55
114
  }
@@ -57,28 +116,18 @@ export function initClientNavigation(opts = {}) {
57
116
  const el = event.target;
58
117
  const a = el.closest("a");
59
118
  const href = a?.getAttribute("href");
60
- saveScrollPosition(window.scrollX, window.scrollY);
61
- window.history.pushState({ path: href }, "", window.location.origin + href);
62
- await options.onNavigate();
63
- if (options.scrollToTop && history.scrollRestoration === "auto") {
64
- window.scrollTo({
65
- top: 0,
66
- left: 0,
67
- behavior: options.scrollBehavior,
68
- });
69
- saveScrollPosition(0, 0);
70
- }
71
- history.scrollRestoration = "auto";
119
+ navigate(href);
72
120
  }, true);
73
121
  window.addEventListener("popstate", async function handlePopState() {
74
- saveScrollPosition(window.scrollX, window.scrollY);
75
- await options.onNavigate();
122
+ // @ts-expect-error
123
+ await globalThis.__rsc_callServer();
76
124
  });
77
125
  // Return a handleResponse function for use with initClient
78
126
  return {
79
127
  handleResponse: function handleResponse(response) {
80
128
  if (!response.ok) {
81
129
  // Redirect to the current page (window.location) to show the error
130
+ // This means the page that produced the error is called twice.
82
131
  window.location.href = window.location.href;
83
132
  return false;
84
133
  }
@@ -1,2 +1,3 @@
1
1
  import "./types/ssr";
2
2
  export * from "../lib/streams/consumeEventStream";
3
+ export declare const navigate: () => void;
@@ -1,2 +1,5 @@
1
1
  import "./types/ssr";
2
2
  export * from "../lib/streams/consumeEventStream";
3
+ export const navigate = () => {
4
+ /* stub */
5
+ };
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ throw new Error("rwsdk: SSR bridge was resolved with 'react-server' condition. This is a bug - the SSR bridge should be intercepted by the esbuild plugin before reaching package.json exports. Please report this issue.");
@@ -1,3 +1,4 @@
1
1
  import "./types/shared";
2
2
  export * from "../lib/links";
3
3
  export * from "../lib/router";
4
+ export type { DocumentProps, LayoutProps } from "../lib/types";
@@ -0,0 +1 @@
1
+ export { defineLinks, linkFor } from "../lib/links.js";
@@ -0,0 +1 @@
1
+ export { defineLinks, linkFor } from "../lib/links.js";
@@ -1,10 +1,12 @@
1
1
  import "./types/worker";
2
2
  export * from "../error";
3
+ export * from "../lib/types";
3
4
  export * from "../lib/utils";
4
5
  export * from "../register/worker";
5
6
  export * from "../render/renderToStream";
6
7
  export * from "../render/renderToString";
7
8
  export * from "../requestInfo/types";
9
+ export * from "../requestInfo/utils";
8
10
  export * from "../requestInfo/worker";
9
11
  export * from "../script";
10
12
  export * from "../worker";
@@ -1,10 +1,12 @@
1
1
  import "./types/worker";
2
2
  export * from "../error";
3
+ export * from "../lib/types";
3
4
  export * from "../lib/utils";
4
5
  export * from "../register/worker";
5
6
  export * from "../render/renderToStream";
6
7
  export * from "../render/renderToString";
7
8
  export * from "../requestInfo/types";
9
+ export * from "../requestInfo/utils";
8
10
  export * from "../requestInfo/worker";
9
11
  export * from "../script";
10
12
  export * from "../worker";
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Mock implementation of the virtual:use-client-lookup.js module for tests.
3
+ * This provides an empty lookup object since tests don't need to actually
4
+ * load client modules - they use dependency injection for React hooks.
5
+ */
6
+ export declare const useClientLookup: Record<string, () => Promise<any>>;
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Mock implementation of the virtual:use-client-lookup.js module for tests.
3
+ * This provides an empty lookup object since tests don't need to actually
4
+ * load client modules - they use dependency injection for React hooks.
5
+ */
6
+ export const useClientLookup = {};
@@ -1,11 +1,11 @@
1
1
  import { DurableObject } from "cloudflare:workers";
2
- import { Kysely, QueryResult } from "kysely";
2
+ import { Kysely, KyselyPlugin, QueryResult } from "kysely";
3
3
  export declare class SqliteDurableObject<T = any> extends DurableObject {
4
4
  migrations: Record<string, any>;
5
5
  kysely: Kysely<T>;
6
6
  private initialized;
7
7
  private migrationTableName;
8
- constructor(ctx: DurableObjectState, env: any, migrations: Record<string, any>, migrationTableName?: string);
8
+ constructor(ctx: DurableObjectState, env: any, migrations: Record<string, any>, migrationTableName?: string, plugins?: KyselyPlugin[]);
9
9
  initialize(): Promise<void>;
10
10
  kyselyExecuteQuery<R>(compiledQuery: {
11
11
  sql: string;
@@ -6,14 +6,14 @@ import { createMigrator } from "./index.js";
6
6
  const log = debug("sdk:do-db");
7
7
  // Base class for Durable Objects that need Kysely database access
8
8
  export class SqliteDurableObject extends DurableObject {
9
- constructor(ctx, env, migrations, migrationTableName = "__migrations") {
9
+ constructor(ctx, env, migrations, migrationTableName = "__migrations", plugins = [new ParseJSONResultsPlugin()]) {
10
10
  super(ctx, env);
11
11
  this.initialized = false;
12
12
  this.migrations = migrations;
13
13
  this.migrationTableName = migrationTableName;
14
14
  this.kysely = new Kysely({
15
15
  dialect: new DODialect({ ctx }),
16
- plugins: [new ParseJSONResultsPlugin()],
16
+ plugins: plugins,
17
17
  });
18
18
  }
19
19
  async initialize() {
@@ -1,3 +1,2 @@
1
1
  import { Kysely } from "kysely";
2
- import { type SqliteDurableObject } from "./index.js";
3
- export declare function createDb<T>(durableObjectBinding: DurableObjectNamespace<SqliteDurableObject>, name?: string): Kysely<T>;
2
+ export declare function createDb<DatabaseType>(durableObjectBinding: DurableObjectNamespace<any>, name?: string): Kysely<DatabaseType>;
@@ -5,6 +5,10 @@ export function createDb(durableObjectBinding, name = "main") {
5
5
  dialect: new DOWorkerDialect({
6
6
  kyselyExecuteQuery: (...args) => {
7
7
  const durableObjectId = durableObjectBinding.idFromName(name);
8
+ // context(justinvdm, 2 Oct 2025): First prize would be a type parameter
9
+ // for the durable object and then use it for `durableObjectBinding`'s
10
+ // type, rather than casting like this. However, that would prevent
11
+ // users from being able to do createDb<InferredDbType> then though.
8
12
  const stub = durableObjectBinding.get(durableObjectId);
9
13
  stub.initialize();
10
14
  return stub.kyselyExecuteQuery(...args);
@@ -1,8 +1,14 @@
1
1
  import { CheckConstraintNode, Expression, ForeignKeyConstraintBuilder, PrimaryKeyConstraintNode, sql, UniqueConstraintNode } from "kysely";
2
2
  import { AddColumnOp, AlterColumnOp, AlterOperation, DropColumnOp, ExecutedBuilder, ModifyColumnOp, RenameColumnOp, SqlToTsType } from "../utils";
3
3
  import { AlterColumnBuilderCallback } from "./alterColumn";
4
- import { ColumnDefinitionBuilder } from "./columnDefinition";
4
+ import { ColumnDefinitionBuilder, ColumnDescriptor } from "./columnDefinition";
5
5
  type DataTypeExpression = string | typeof sql;
6
+ type InitialDescriptor<TType> = {
7
+ tsType: TType;
8
+ isNullable: true;
9
+ hasDefault: false;
10
+ isAutoIncrement: false;
11
+ };
6
12
  interface CheckConstraintBuilder {
7
13
  $call<T>(func: (qb: this) => T): T;
8
14
  toOperationNode(): CheckConstraintNode;
@@ -31,14 +37,18 @@ export interface AlterTableBuilder<TName extends string, TOps extends AlterOpera
31
37
  readonly __renamedFrom: TName;
32
38
  };
33
39
  setSchema(newSchema: string): AlterTableBuilder<TName, TOps>;
34
- addColumn<K extends string, T extends DataTypeExpression>(name: K, type: T, build?: (col: ColumnDefinitionBuilder<SqlToTsType<T>>) => ColumnDefinitionBuilder<SqlToTsType<T>>): AlterTableBuilder<TName, [...TOps, AddColumnOp<K, T>]>;
40
+ addColumn<K extends string, T extends DataTypeExpression>(name: K, type: T): AlterTableBuilder<TName, [
41
+ ...TOps,
42
+ AddColumnOp<K, T, InitialDescriptor<SqlToTsType<T>>>
43
+ ]>;
44
+ addColumn<K extends string, T extends DataTypeExpression, TDescriptor extends ColumnDescriptor>(name: K, type: T, build: (col: ColumnDefinitionBuilder<InitialDescriptor<SqlToTsType<T>>>) => ColumnDefinitionBuilder<TDescriptor>): AlterTableBuilder<TName, [...TOps, AddColumnOp<K, T, TDescriptor>]>;
35
45
  dropColumn<K extends string>(name: K): AlterTableBuilder<TName, [...TOps, DropColumnOp<K>]>;
36
46
  renameColumn<KFrom extends string, KTo extends string>(from: KFrom, to: KTo): AlterTableBuilder<TName, [...TOps, RenameColumnOp<KFrom, KTo>]>;
37
47
  alterColumn<K extends string, const TCallback extends AlterColumnBuilderCallback>(column: K, alteration: TCallback): AlterTableBuilder<TName, [
38
48
  ...TOps,
39
49
  AlterColumnOp<K, ReturnType<TCallback>["__alteration"]>
40
50
  ]>;
41
- modifyColumn<K extends string, T extends DataTypeExpression>(column: K, type: T, build?: (col: ColumnDefinitionBuilder<SqlToTsType<T>>) => ColumnDefinitionBuilder<SqlToTsType<T>>): AlterTableBuilder<TName, [...TOps, ModifyColumnOp<K, T>]>;
51
+ modifyColumn<K extends string, T extends DataTypeExpression, TDescriptor extends ColumnDescriptor>(column: K, type: T, build?: (col: ColumnDefinitionBuilder<InitialDescriptor<SqlToTsType<T>>>) => ColumnDefinitionBuilder<TDescriptor>): AlterTableBuilder<TName, [...TOps, ModifyColumnOp<K, T, TDescriptor>]>;
42
52
  addUniqueConstraint(constraintName: string, columns: string[], build?: (builder: UniqueConstraintBuilder) => UniqueConstraintBuilder): AlterTableBuilder<TName, TOps>;
43
53
  addPrimaryKeyConstraint(constraintName: string, columns: string[], build?: (builder: PrimaryKeyConstraintBuilder) => PrimaryKeyConstraintBuilder): AlterTableBuilder<TName, TOps>;
44
54
  addCheckConstraint(constraintName: string, checkExpression: Expression<any>, build?: (builder: CheckConstraintBuilder) => CheckConstraintBuilder): AlterTableBuilder<TName, TOps>;
@@ -1,25 +1,39 @@
1
1
  import { ColumnDefinitionNode, Expression, sql } from "kysely";
2
- type DefaultValueExpression = string | number | boolean | null | typeof sql;
3
- export interface ColumnDefinitionBuilder<TType> {
4
- autoIncrement(): ColumnDefinitionBuilder<TType>;
5
- identity(): ColumnDefinitionBuilder<TType>;
6
- primaryKey(): ColumnDefinitionBuilder<TType>;
7
- references(ref: string): ColumnDefinitionBuilder<TType>;
8
- onDelete(onDelete: "no action" | "restrict" | "cascade" | "set null" | "set default"): ColumnDefinitionBuilder<TType>;
9
- onUpdate(onUpdate: "no action" | "restrict" | "cascade" | "set null" | "set default"): ColumnDefinitionBuilder<TType>;
10
- unique(): ColumnDefinitionBuilder<TType>;
11
- notNull(): ColumnDefinitionBuilder<TType>;
12
- unsigned(): ColumnDefinitionBuilder<TType>;
13
- defaultTo(value: DefaultValueExpression): ColumnDefinitionBuilder<TType>;
14
- check(expression: Expression<any>): ColumnDefinitionBuilder<TType>;
15
- generatedAlwaysAs(expression: Expression<any>): ColumnDefinitionBuilder<TType>;
16
- generatedAlwaysAsIdentity(): ColumnDefinitionBuilder<TType>;
17
- generatedByDefaultAsIdentity(): ColumnDefinitionBuilder<TType>;
18
- stored(): ColumnDefinitionBuilder<TType>;
19
- modifyFront(modifier: Expression<any>): ColumnDefinitionBuilder<TType>;
20
- nullsNotDistinct(): ColumnDefinitionBuilder<TType>;
21
- ifNotExists(): ColumnDefinitionBuilder<TType>;
22
- modifyEnd(modifier: Expression<any>): ColumnDefinitionBuilder<TType>;
2
+ type DefaultValueExpression = string | number | boolean | null | ReturnType<typeof sql>;
3
+ export type ColumnDescriptor = {
4
+ tsType: any;
5
+ isNullable: boolean;
6
+ hasDefault: boolean;
7
+ isAutoIncrement: boolean;
8
+ };
9
+ export interface ColumnDefinitionBuilder<TDescriptor extends ColumnDescriptor> {
10
+ autoIncrement(): ColumnDefinitionBuilder<{
11
+ [K in keyof TDescriptor]: K extends "isAutoIncrement" ? true : TDescriptor[K];
12
+ }>;
13
+ identity(): ColumnDefinitionBuilder<TDescriptor>;
14
+ primaryKey(): ColumnDefinitionBuilder<{
15
+ [K in keyof TDescriptor]: K extends "isNullable" ? false : TDescriptor[K];
16
+ }>;
17
+ references(ref: string): ColumnDefinitionBuilder<TDescriptor>;
18
+ onDelete(onDelete: "no action" | "restrict" | "cascade" | "set null" | "set default"): ColumnDefinitionBuilder<TDescriptor>;
19
+ onUpdate(onUpdate: "no action" | "restrict" | "cascade" | "set null" | "set default"): ColumnDefinitionBuilder<TDescriptor>;
20
+ unique(): ColumnDefinitionBuilder<TDescriptor>;
21
+ notNull(): ColumnDefinitionBuilder<{
22
+ [K in keyof TDescriptor]: K extends "isNullable" ? false : TDescriptor[K];
23
+ }>;
24
+ unsigned(): ColumnDefinitionBuilder<TDescriptor>;
25
+ defaultTo(value: DefaultValueExpression): ColumnDefinitionBuilder<{
26
+ [K in keyof TDescriptor]: K extends "isNullable" ? false : K extends "hasDefault" ? true : TDescriptor[K];
27
+ }>;
28
+ check(expression: Expression<any>): ColumnDefinitionBuilder<TDescriptor>;
29
+ generatedAlwaysAs(expression: Expression<any>): ColumnDefinitionBuilder<TDescriptor>;
30
+ generatedAlwaysAsIdentity(): ColumnDefinitionBuilder<TDescriptor>;
31
+ generatedByDefaultAsIdentity(): ColumnDefinitionBuilder<TDescriptor>;
32
+ stored(): ColumnDefinitionBuilder<TDescriptor>;
33
+ modifyFront(modifier: Expression<any>): ColumnDefinitionBuilder<TDescriptor>;
34
+ nullsNotDistinct(): ColumnDefinitionBuilder<TDescriptor>;
35
+ ifNotExists(): ColumnDefinitionBuilder<TDescriptor>;
36
+ modifyEnd(modifier: Expression<any>): ColumnDefinitionBuilder<TDescriptor>;
23
37
  $call<T>(func: (qb: this) => T): T;
24
38
  toOperationNode(): ColumnDefinitionNode;
25
39
  }
@@ -1,6 +1,6 @@
1
1
  import { CheckConstraintNode, CompiledQuery, CreateTableNode, Expression, ForeignKeyConstraintBuilder, PrimaryKeyConstraintNode, UniqueConstraintNode } from "kysely";
2
2
  import { ExecutedBuilder, Prettify, SqlToTsType } from "../utils";
3
- import { ColumnDefinitionBuilder } from "./columnDefinition";
3
+ import { ColumnDefinitionBuilder, ColumnDescriptor } from "./columnDefinition";
4
4
  interface CheckConstraintBuilder {
5
5
  $call<T>(func: (qb: this) => T): T;
6
6
  toOperationNode(): CheckConstraintNode;
@@ -22,13 +22,20 @@ interface PrimaryKeyConstraintBuilder {
22
22
  $call<T>(func: (qb: this) => T): T;
23
23
  toOperationNode(): PrimaryKeyConstraintNode;
24
24
  }
25
+ type InitialDescriptor<TType> = {
26
+ tsType: TType;
27
+ isNullable: true;
28
+ hasDefault: false;
29
+ isAutoIncrement: false;
30
+ };
25
31
  export interface CreateTableBuilder<TName extends string, TSchema extends Record<string, any> = {}> {
26
32
  readonly __tableName: TName;
27
33
  readonly __addedColumns: TSchema;
28
34
  temporary(): CreateTableBuilder<TName, TSchema>;
29
35
  onCommit(onCommit: "preserve rows" | "delete rows" | "drop"): CreateTableBuilder<TName, TSchema>;
30
36
  ifNotExists(): CreateTableBuilder<TName, TSchema>;
31
- addColumn<K extends string, T extends string>(name: K, type: T, build?: (col: ColumnDefinitionBuilder<SqlToTsType<T>>) => ColumnDefinitionBuilder<SqlToTsType<T>>): CreateTableBuilder<TName, Prettify<(TSchema extends Record<string, any> ? TSchema : {}) & Record<K, SqlToTsType<T>>>>;
37
+ addColumn<K extends string, T extends string>(name: K, type: T): CreateTableBuilder<TName, Prettify<(TSchema extends Record<string, any> ? TSchema : {}) & Record<K, InitialDescriptor<SqlToTsType<T>>>>>;
38
+ addColumn<K extends string, T extends string, TDescriptor extends ColumnDescriptor>(name: K, type: T, build: (col: ColumnDefinitionBuilder<InitialDescriptor<SqlToTsType<T>>>) => ColumnDefinitionBuilder<TDescriptor>): CreateTableBuilder<TName, Prettify<(TSchema extends Record<string, any> ? TSchema : {}) & Record<K, TDescriptor>>>;
32
39
  addUniqueConstraint(constraintName: string, columns: (keyof TSchema)[], build?: (builder: UniqueConstraintBuilder) => UniqueConstraintBuilder): CreateTableBuilder<TName, TSchema>;
33
40
  addPrimaryKeyConstraint(constraintName: string, columns: (keyof TSchema)[], build?: (builder: PrimaryKeyConstraintBuilder) => PrimaryKeyConstraintBuilder): CreateTableBuilder<TName, TSchema>;
34
41
  addCheckConstraint(constraintName: string, checkExpression: Expression<any>, build?: (builder: CheckConstraintBuilder) => CheckConstraintBuilder): CreateTableBuilder<TName, TSchema>;
@@ -1,9 +1,10 @@
1
- import { Kysely } from "kysely";
1
+ import { Generated, Kysely } from "kysely";
2
2
  import { AlterTableBuilder } from "./builders/alterTable";
3
3
  import { CreateTableBuilder } from "./builders/createTable";
4
4
  import { DropTableBuilder } from "./builders/dropTable";
5
5
  import { SchemaBuilder } from "./builders/schema";
6
6
  import { ExecutedBuilder, Prettify, ProcessAlteredTable, UnionToTuple } from "./utils";
7
+ import { ColumnDescriptor } from "./builders/columnDefinition";
7
8
  export interface InferenceBuilder {
8
9
  schema: SchemaBuilder;
9
10
  }
@@ -23,5 +24,18 @@ type ApplyBuilders<TSchema, TBuildersTuple> = TBuildersTuple extends [
23
24
  ...infer TRest
24
25
  ] ? ApplyBuilders<ApplyBuilder<TSchema, THead>, TRest> : TSchema;
25
26
  type ProcessMigrations<TMigrations extends Migrations, TKeys, TSchema = {}> = TKeys extends [infer THeadKey, ...infer TRestKeys] ? THeadKey extends keyof TMigrations ? ProcessMigrations<TMigrations, TRestKeys, ApplyBuilders<TSchema, UnionToTuple<BuildersFromMigration<TMigrations[THeadKey]>>>> : TSchema : TSchema;
26
- export type Database<TMigrations extends Migrations = Migrations> = ProcessMigrations<TMigrations, UnionToTuple<keyof TMigrations>>;
27
+ type TableToSelectType<TTable> = Prettify<{
28
+ [K in keyof TTable]: TTable[K] extends ColumnDescriptor ? TTable[K]["isNullable"] extends true ? TTable[K]["tsType"] | null : TTable[K]["tsType"] : TTable[K];
29
+ }>;
30
+ type TableToKyselySchema<TTable> = Prettify<{
31
+ [K in keyof TTable]: TTable[K] extends ColumnDescriptor ? TTable[K]["hasDefault"] extends true ? Generated<TTable[K]["isNullable"] extends true ? TTable[K]["tsType"] | null : TTable[K]["tsType"]> : TTable[K]["isAutoIncrement"] extends true ? Generated<TTable[K]["tsType"]> : TTable[K]["isNullable"] extends true ? TTable[K]["tsType"] | null : TTable[K]["tsType"] : TTable[K];
32
+ }>;
33
+ type DatabaseWithDescriptors<TMigrations extends Migrations = Migrations> = ProcessMigrations<TMigrations, UnionToTuple<keyof TMigrations>>;
34
+ export type Database<TMigrations extends Migrations = Migrations> = Prettify<{
35
+ [K in keyof DatabaseWithDescriptors<TMigrations>]: TableToSelectType<DatabaseWithDescriptors<TMigrations>[K]>;
36
+ } & {
37
+ __kyselySchema: {
38
+ [K in keyof DatabaseWithDescriptors<TMigrations>]: TableToKyselySchema<DatabaseWithDescriptors<TMigrations>[K]>;
39
+ };
40
+ }>;
27
41
  export {};
@@ -97,7 +97,7 @@
97
97
  },
98
98
  },
99
99
  };
100
- //(_test: Expect<Equal<Actual, Expected>>) => {};
100
+ //(_test: ExpectDb<Actual, Expected>) => {};
101
101
  };
102
102
  (_it = "alterTable addUniqueConstraint") => {
103
103
  const migrations = {
@@ -123,7 +123,7 @@
123
123
  },
124
124
  },
125
125
  };
126
- //(_test: Expect<Equal<Actual, Expected>>) => {};
126
+ //(_test: ExpectDb<Actual, Expected>) => {};
127
127
  };
128
128
  (_it = "alterTable drop column") => {
129
129
  const migrations = {
@@ -153,7 +153,7 @@
153
153
  up: async (db) => [
154
154
  await db.schema
155
155
  .createTable("users")
156
- .addColumn("id", "integer")
156
+ .addColumn("id", "integer", (c) => c.primaryKey().autoIncrement())
157
157
  .execute(),
158
158
  ],
159
159
  },
@@ -242,7 +242,7 @@
242
242
  return [
243
243
  await db.schema
244
244
  .createTable("users")
245
- .addColumn("id", "integer")
245
+ .addColumn("id", "integer", (col) => col.notNull())
246
246
  .execute(),
247
247
  ];
248
248
  },
@@ -271,7 +271,7 @@
271
271
  return [
272
272
  await db.schema
273
273
  .createTable("users")
274
- .addColumn("id", "integer")
274
+ .addColumn("id", "integer", (col) => col.primaryKey().autoIncrement())
275
275
  .execute(),
276
276
  ];
277
277
  },
@@ -357,4 +357,79 @@
357
357
  };
358
358
  (_test) => { };
359
359
  };
360
+ (_it = "alterTable addColumn with notNull") => {
361
+ const migrations = {
362
+ "0": {
363
+ async up(db) {
364
+ return [
365
+ await db.schema
366
+ .createTable("users")
367
+ .addColumn("id", "integer", (col) => col.primaryKey())
368
+ .execute(),
369
+ ];
370
+ },
371
+ },
372
+ "1": {
373
+ async up(db) {
374
+ return [
375
+ await db.schema
376
+ .alterTable("users")
377
+ .addColumn("email", "text", (col) => col.notNull())
378
+ .execute(),
379
+ ];
380
+ },
381
+ },
382
+ };
383
+ (_test) => { };
384
+ };
385
+ (_it = "alterTable modifyColumn with notNull") => {
386
+ const migrations = {
387
+ "0": {
388
+ async up(db) {
389
+ return [
390
+ await db.schema
391
+ .createTable("products")
392
+ .addColumn("price", "real")
393
+ .execute(),
394
+ ];
395
+ },
396
+ },
397
+ "1": {
398
+ async up(db) {
399
+ return [
400
+ await db.schema
401
+ .alterTable("products")
402
+ .modifyColumn("price", "real", (col) => col.notNull())
403
+ .execute(),
404
+ ];
405
+ },
406
+ },
407
+ };
408
+ (_test) => { };
409
+ };
410
+ (_it = "alterTable modifyColumn nullable to non-nullable") => {
411
+ const migrations = {
412
+ "0": {
413
+ async up(db) {
414
+ return [
415
+ await db.schema
416
+ .createTable("orders")
417
+ .addColumn("status", "text")
418
+ .execute(),
419
+ ];
420
+ },
421
+ },
422
+ "1": {
423
+ async up(db) {
424
+ return [
425
+ await db.schema
426
+ .alterTable("orders")
427
+ .modifyColumn("status", "text", (col) => col.notNull().defaultTo("pending"))
428
+ .execute(),
429
+ ];
430
+ },
431
+ },
432
+ };
433
+ (_test) => { };
434
+ };
360
435
  export {};