create-monolayer-app 0.5.1 → 0.6.1

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 (85) hide show
  1. package/bin/index.js +91 -59
  2. package/package.json +19 -16
  3. package/template/.agents/skills/{monolayer-application-permissions → application-permissions}/SKILL.md +2 -2
  4. package/template/.agents/skills/application-permissions/agents/openai.yaml +4 -0
  5. package/template/.agents/skills/kysely/SKILL.md +48 -0
  6. package/template/.agents/skills/kysely/agents/openai.yaml +4 -0
  7. package/template/.agents/skills/kysely/references/execution-plugins-and-runtime.md +67 -0
  8. package/template/.agents/skills/kysely/references/expressions-and-helpers.md +102 -0
  9. package/template/.agents/skills/kysely/references/migrations.md +43 -0
  10. package/template/.agents/skills/kysely/references/official-docs-map.md +97 -0
  11. package/template/.agents/skills/kysely/references/query-building.md +119 -0
  12. package/template/.agents/skills/kysely/references/transactions.md +47 -0
  13. package/template/.agents/skills/kysely/references/troubleshooting-and-boundaries.md +67 -0
  14. package/template/.agents/skills/kysely/references/types.md +58 -0
  15. package/template/.agents/skills/persistent-app-data/SKILL.md +74 -0
  16. package/template/.agents/skills/persistent-app-data/agents/openai.yaml +4 -0
  17. package/template/.agents/skills/persistent-app-data/references/generated-types.md +23 -0
  18. package/template/.agents/skills/persistent-app-data/references/migrations.md +68 -0
  19. package/template/.agents/skills/vitest/GENERATION.md +25 -0
  20. package/template/.agents/skills/vitest/SKILL.md +59 -0
  21. package/template/.agents/skills/vitest/references/advanced-environments.md +26 -0
  22. package/template/.agents/skills/vitest/references/advanced-projects.md +31 -0
  23. package/template/.agents/skills/vitest/references/advanced-type-testing.md +30 -0
  24. package/template/.agents/skills/vitest/references/advanced-vi.md +23 -0
  25. package/template/.agents/skills/vitest/references/core-cli.md +23 -0
  26. package/template/.agents/skills/vitest/references/core-config.md +24 -0
  27. package/template/.agents/skills/vitest/references/core-describe.md +24 -0
  28. package/template/.agents/skills/vitest/references/core-expect.md +35 -0
  29. package/template/.agents/skills/vitest/references/core-hooks.md +26 -0
  30. package/template/.agents/skills/vitest/references/core-test-api.md +29 -0
  31. package/template/.agents/skills/vitest/references/features-benchmarking.md +25 -0
  32. package/template/.agents/skills/vitest/references/features-concurrency.md +20 -0
  33. package/template/.agents/skills/vitest/references/features-context.md +27 -0
  34. package/template/.agents/skills/vitest/references/features-coverage.md +17 -0
  35. package/template/.agents/skills/vitest/references/features-filtering.md +24 -0
  36. package/template/.agents/skills/vitest/references/features-mocking.md +32 -0
  37. package/template/.agents/skills/vitest/references/features-reporters.md +22 -0
  38. package/template/.agents/skills/vitest/references/features-snapshots.md +23 -0
  39. package/template/.agents/skills/vitest/references/features-test-tags.md +30 -0
  40. package/template/.agents/skills/vitest/references/version-compatibility.md +19 -0
  41. package/template/.claude/CLAUDE.md +2 -2
  42. package/template/.react-router/types/+routes.ts +41 -0
  43. package/template/.react-router/types/+server-build.d.ts +18 -0
  44. package/template/.react-router/types/app/+types/root.ts +68 -0
  45. package/template/.react-router/types/app/routes/+types/files.ts +71 -0
  46. package/template/.react-router/types/app/routes/+types/home.ts +71 -0
  47. package/template/AGENTS.md +6 -2
  48. package/template/app/routes/files.ts +3 -3
  49. package/template/build/client/assets/entry.client-Bc58m2-m.js +9 -0
  50. package/template/build/client/assets/errorBoundaries-CQxPIuVU.js +16 -0
  51. package/template/build/client/assets/files-BvRk9kiK.js +0 -0
  52. package/template/build/client/assets/home-CH2INc5e.js +1 -0
  53. package/template/build/client/assets/jsx-runtime-eLCqVKHJ.js +1 -0
  54. package/template/build/client/assets/logo-dark-pX2395Y0.svg +23 -0
  55. package/template/build/client/assets/logo-light-CVbx2LBR.svg +23 -0
  56. package/template/build/client/assets/manifest-2d65dd0f.js +1 -0
  57. package/template/build/client/assets/root-BeNS6njP.css +2 -0
  58. package/template/build/client/assets/root-C1tmjS9o.js +1 -0
  59. package/template/build/client/favicon.ico +0 -0
  60. package/template/build/server/index.js +1096 -0
  61. package/template/lib/db/client.ts +1 -27
  62. package/template/package-lock.json +8221 -0
  63. package/template/package.json +7 -3
  64. package/template/vendor/file-bucket/{client.ts → index.client.ts} +11 -9
  65. package/template/vendor/file-bucket/{server.ts → index.server.ts} +13 -8
  66. package/template/vendor/file-bucket/{index.ts → lib/file-bucket.ts} +2 -1
  67. package/template/vendor/file-bucket/{react-router.ts → react-router.server.ts} +15 -13
  68. package/template/vendor/kysely-dsql/dsql/dsql-kysely.ts +31 -3
  69. package/template/vendor/kysely-dsql/generator/migration-file.ts +3 -3
  70. package/template/vendor/kysely-dsql/plugins/index.ts +0 -2
  71. package/template/vendor/package-app/package-app.mjs +2 -2
  72. package/template/vite.config.ts +3 -1
  73. package/template/vitest.config.ts +1 -1
  74. package/template/.agents/skills/monolayer-application-permissions/agents/openai.yaml +0 -4
  75. package/template/vendor/kysely-dsql/plugins/soft-delete.plugin.ts +0 -217
  76. /package/template/.agents/skills/{monolayer-application-permissions → application-permissions}/references/development-and-verification.md +0 -0
  77. /package/template/.agents/skills/{monolayer-application-permissions → application-permissions}/references/interface-examples.md +0 -0
  78. /package/template/.agents/skills/{monolayer-application-permissions → application-permissions}/references/server-examples.md +0 -0
  79. /package/template/vendor/file-bucket/{errors.ts → lib/errors.server.ts} +0 -0
  80. /package/template/vendor/file-bucket/{multipart.ts → lib/multipart.ts} +0 -0
  81. /package/template/vendor/file-bucket/{protocol.ts → lib/protocol.ts} +0 -0
  82. /package/template/vendor/file-bucket/{transport.ts → lib/transport.client.ts} +0 -0
  83. /package/template/vendor/file-bucket/{types.ts → lib/types.ts} +0 -0
  84. /package/template/vendor/file-bucket/{transfers.ts → lib/upload-signed-url.ts} +0 -0
  85. /package/template/vendor/file-bucket/{xml.ts → lib/xml.ts} +0 -0
package/bin/index.js CHANGED
@@ -1,26 +1,30 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- import fs from 'node:fs';
4
- import path from 'node:path';
5
- import { fileURLToPath } from 'node:url';
6
- import { spawnSync } from 'node:child_process';
3
+ import { spawnSync } from "node:child_process";
4
+ import fs from "node:fs";
5
+ import path from "node:path";
6
+ import { fileURLToPath } from "node:url";
7
7
 
8
- const __filename = fileURLToPath(import.meta.url);
9
- const __dirname = path.dirname(__filename);
8
+ const __filename = import.meta.filename;
9
+ const __dirname = import.meta.dirname;
10
10
 
11
11
  // Terminal color helpers
12
- const reset = '\x1b[0m';
13
- const bold = (str) => `\x1b[1m${str}${reset}`;
14
- const cyan = (str) => `\x1b[36m${str}${reset}`;
15
- const green = (str) => `\x1b[32m${str}${reset}`;
16
- const red = (str) => `\x1b[31m${str}${reset}`;
17
- const dim = (str) => `\x1b[2m${str}${reset}`;
18
- const yellow = (str) => `\x1b[33m${str}${reset}`;
12
+ const reset = "\x1B[0m";
13
+ const bold = (str) => `\x1B[1m${str}${reset}`;
14
+ const cyan = (str) => `\x1B[36m${str}${reset}`;
15
+ const green = (str) => `\x1B[32m${str}${reset}`;
16
+ const red = (str) => `\x1B[31m${str}${reset}`;
17
+ const dim = (str) => `\x1B[2m${str}${reset}`;
18
+ const yellow = (str) => `\x1B[33m${str}${reset}`;
19
19
 
20
20
  // Helper to validate slug
21
21
  function isValidSlug(name) {
22
- if (!name || typeof name !== 'string') return false;
23
- if (/\s/.test(name)) return false;
22
+ if (!name || typeof name !== "string") {
23
+ return false;
24
+ }
25
+ if (/\s/.test(name)) {
26
+ return false;
27
+ }
24
28
  // Slug should consist of letters, numbers, hyphens, and underscores
25
29
  return /^[a-zA-Z0-9_-]+$/.test(name);
26
30
  }
@@ -31,14 +35,16 @@ function copyDir(src, dest) {
31
35
  const entries = fs.readdirSync(src, { withFileTypes: true });
32
36
 
33
37
  for (const entry of entries) {
34
- if (entry.name === '.DS_Store') continue;
38
+ if (entry.name === ".DS_Store") {
39
+ continue;
40
+ }
35
41
 
36
42
  const srcPath = path.join(src, entry.name);
37
43
  let destName = entry.name;
38
44
 
39
45
  // npm ignores or modifies .gitignore during publishing, so we use _gitignore in template
40
- if (destName === '_gitignore') {
41
- destName = '.gitignore';
46
+ if (destName === "_gitignore") {
47
+ destName = ".gitignore";
42
48
  }
43
49
 
44
50
  const destPath = path.join(dest, destName);
@@ -53,20 +59,20 @@ function copyDir(src, dest) {
53
59
 
54
60
  function printUsage() {
55
61
  console.log(`
56
- ${bold('create-monolayer-app')} - Scaffold a new Monolayer application
62
+ ${bold("create-monolayer-app")} - Scaffold a new Monolayer application
57
63
 
58
- ${bold('Usage:')}
59
- npx create-monolayer-app ${green('<app-name>')}
64
+ ${bold("Usage:")}
65
+ npx create-monolayer-app ${green("<app-name>")}
60
66
 
61
- ${bold('Arguments:')}
62
- ${green('<app-name>')} Required. The name of the app (slug, no spaces). A directory
67
+ ${bold("Arguments:")}
68
+ ${green("<app-name>")} Required. The name of the app (slug, no spaces). A directory
63
69
  with this name will be created in the current working directory.
64
70
 
65
- ${bold('Options:')}
71
+ ${bold("Options:")}
66
72
  -h, --help Show this help message
67
73
  -v, --version Show version number
68
74
 
69
- ${bold('Example:')}
75
+ ${bold("Example:")}
70
76
  npx create-monolayer-app my-monolayer-app
71
77
  `);
72
78
  }
@@ -74,22 +80,22 @@ ${bold('Example:')}
74
80
  function main() {
75
81
  const args = process.argv.slice(2);
76
82
 
77
- if (args.includes('--help') || args.includes('-h')) {
83
+ if (args.includes("--help") || args.includes("-h")) {
78
84
  printUsage();
79
85
  process.exit(0);
80
86
  }
81
87
 
82
- if (args.includes('--version') || args.includes('-v')) {
83
- const pkgPath = path.join(__dirname, '../package.json');
84
- const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
88
+ if (args.includes("--version") || args.includes("-v")) {
89
+ const pkgPath = path.join(__dirname, "../package.json");
90
+ const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf-8"));
85
91
  console.log(pkg.version);
86
92
  process.exit(0);
87
93
  }
88
94
 
89
- const rawArg = args.find((arg) => !arg.startsWith('-'));
95
+ const rawArg = args.find((arg) => !arg.startsWith("-"));
90
96
 
91
97
  if (!rawArg) {
92
- console.error(red('Error: <app-name> is required.'));
98
+ console.error(red("Error: <app-name> is required."));
93
99
  printUsage();
94
100
  process.exit(1);
95
101
  }
@@ -97,24 +103,30 @@ function main() {
97
103
  const appName = rawArg.trim();
98
104
 
99
105
  if (appName.length === 0) {
100
- console.error(red('Error: App name cannot be empty.'));
106
+ console.error(red("Error: App name cannot be empty."));
101
107
  process.exit(1);
102
108
  }
103
109
 
104
110
  if (/\s/.test(appName)) {
105
111
  console.error(red(`Error: App name "${appName}" contains spaces.`));
106
- console.error(yellow('App name must be a slug without spaces (e.g. my-app or my_app).'));
112
+ console.error(
113
+ yellow("App name must be a slug without spaces (e.g. my-app or my_app)."),
114
+ );
107
115
  process.exit(1);
108
116
  }
109
117
 
110
118
  if (!isValidSlug(appName)) {
111
119
  console.error(red(`Error: App name "${appName}" is not a valid slug.`));
112
- console.error(yellow('Only alphanumeric characters, hyphens (-), and underscores (_) are allowed.'));
120
+ console.error(
121
+ yellow(
122
+ "Only alphanumeric characters, hyphens (-), and underscores (_) are allowed.",
123
+ ),
124
+ );
113
125
  process.exit(1);
114
126
  }
115
127
 
116
128
  const targetDir = path.resolve(process.cwd(), appName);
117
- const templateDir = path.resolve(__dirname, '../template');
129
+ const templateDir = path.resolve(__dirname, "../template");
118
130
 
119
131
  if (!fs.existsSync(templateDir)) {
120
132
  console.error(red(`Error: Template directory not found at ${templateDir}`));
@@ -124,56 +136,76 @@ function main() {
124
136
  if (fs.existsSync(targetDir)) {
125
137
  const existingFiles = fs.readdirSync(targetDir);
126
138
  if (existingFiles.length > 0) {
127
- console.error(red(`Error: Directory "${appName}" already exists and is not empty.`));
139
+ console.error(
140
+ red(`Error: Directory "${appName}" already exists and is not empty.`),
141
+ );
128
142
  process.exit(1);
129
143
  }
130
144
  }
131
145
 
132
- console.log(`\nCreating a new Monolayer app in ${green(targetDir)}...\n`);
146
+ console.log(`\nCreating a new monolayer app in ${green(targetDir)}...\n`);
133
147
 
134
148
  // 1. Copy template files
135
149
  copyDir(templateDir, targetDir);
136
150
 
137
151
  // 2. Update package.json name
138
- const targetPkgPath = path.join(targetDir, 'package.json');
152
+ const targetPkgPath = path.join(targetDir, "package.json");
139
153
  if (fs.existsSync(targetPkgPath)) {
140
- const pkg = JSON.parse(fs.readFileSync(targetPkgPath, 'utf8'));
154
+ const pkg = JSON.parse(fs.readFileSync(targetPkgPath, "utf-8"));
141
155
  pkg.name = appName.toLowerCase();
142
- fs.writeFileSync(targetPkgPath, `${JSON.stringify(pkg, null, 2)}\n`, 'utf8');
156
+ fs.writeFileSync(
157
+ targetPkgPath,
158
+ `${JSON.stringify(pkg, null, 2)}\n`,
159
+ "utf-8",
160
+ );
143
161
  }
144
162
 
145
163
  // 3. Install dependencies with npm
146
- console.log(cyan('Installing dependencies with npm...'));
164
+ console.log(cyan("Installing dependencies with npm..."));
147
165
  console.log(dim(`Running npm install in ${targetDir}\n`));
148
166
 
149
- const npmCmd = process.platform === 'win32' ? 'npm.cmd' : 'npm';
150
- const installResult = spawnSync(npmCmd, ['install', '--no-audit', '--no-fund'], {
151
- cwd: targetDir,
152
- stdio: 'inherit',
153
- });
167
+ const npmCmd = process.platform === "win32" ? "npm.cmd" : "npm";
168
+ const installResult = spawnSync(
169
+ npmCmd,
170
+ ["install", "--no-audit", "--no-fund"],
171
+ {
172
+ cwd: targetDir,
173
+ stdio: "inherit",
174
+ },
175
+ );
154
176
 
155
177
  if (installResult.status !== 0) {
156
- console.error(red('\nFailed to install dependencies with npm.'));
178
+ console.error(red("\nFailed to install dependencies with npm."));
157
179
  process.exit(installResult.status ?? 1);
158
180
  }
159
181
 
160
182
  // 4. Success message
161
- console.log(`\n${green('✔')} Successfully created ${bold(appName)} at ${dim(targetDir)}\n`);
162
- console.log('Inside that directory, you can run:');
183
+ console.log(
184
+ `\n${green("✔")} Successfully created ${bold(appName)} at ${dim(targetDir)}\n`,
185
+ );
186
+ console.log("Inside that directory, you can run:");
163
187
  console.log(`\n ${cyan(`cd ${appName}`)}`);
164
- console.log(` ${cyan('npm run dev')}\n`);
165
- console.log('Available scripts:');
166
- console.log(` ${cyan('npm run dev')} - Start the development server with HMR`);
167
- console.log(` ${cyan('npm run build')} - Build the application for production`);
168
- console.log(` ${cyan('npm run start')} - Start the production server`);
169
- console.log(` ${cyan('npm run check')} - Run typegen, TypeScript, and Ultracite checks`);
170
- console.log(` ${cyan('npm run fix')} - Automatically fix lint and format issues\n`);
171
- console.log(bold('Happy coding!'));
188
+ console.log(` ${cyan("npm run dev")}\n`);
189
+ console.log("Available scripts:");
190
+ console.log(
191
+ ` ${cyan("npm run dev")} - Start the development server with HMR`,
192
+ );
193
+ console.log(
194
+ ` ${cyan("npm run build")} - Build the application for production`,
195
+ );
196
+ console.log(` ${cyan("npm run start")} - Start the production server`);
197
+ console.log(
198
+ ` ${cyan("npm run check")} - Run typegen, TypeScript, and Ultracite checks`,
199
+ );
200
+ console.log(
201
+ ` ${cyan("npm run fix")} - Automatically fix lint and format issues\n`,
202
+ );
203
+ console.log(bold("Happy coding!"));
172
204
  }
173
205
 
174
206
  try {
175
207
  main();
176
- } catch (err) {
177
- console.error(red('\nAn unexpected error occurred:'), err);
208
+ } catch (error) {
209
+ console.error(red("\nAn unexpected error occurred:"), error);
178
210
  process.exit(1);
179
211
  }
package/package.json CHANGED
@@ -1,29 +1,32 @@
1
1
  {
2
2
  "name": "create-monolayer-app",
3
- "version": "0.5.1",
3
+ "version": "0.6.1",
4
4
  "description": "CLI to scaffold a new monolayer application",
5
- "type": "module",
5
+ "keywords": [
6
+ "create-app",
7
+ "create-monolayer-app",
8
+ "monolayer",
9
+ "react-router",
10
+ "scaffold",
11
+ "template"
12
+ ],
13
+ "license": "MIT",
6
14
  "bin": {
7
15
  "create-monolayer-app": "./bin/index.js"
8
16
  },
9
- "scripts": {
10
- "publish:local": "npm publish --registry http://localhost:4873",
11
- "unpublish:local": "npm unpublish --registry http://localhost:4873 create-monolayer-app -f"
12
- },
13
17
  "files": [
14
18
  "bin",
15
19
  "template"
16
20
  ],
21
+ "type": "module",
22
+ "scripts": {
23
+ "release": "npm publish",
24
+ "prerelease": "rm -rf template && cp -r ./../../apps/monolayer-app-template . && mv monolayer-app-template template && rm -rf template/node_modules template/.gitignore template/.pglite* template/.turbo template/vendor/kysely-dsql/scripts/.pglite*",
25
+ "publish:local": "npm publish --registry http://localhost:4873",
26
+ "prepublish:local": "rm -rf template && cp -r ./../../apps/monolayer-app-template . && mv monolayer-app-template template && rm -rf template/node_modules template/.gitignore template/.pglite* template/.turbo template/vendor/kysely-dsql/scripts/.pglite*",
27
+ "unpublish:local": "npm unpublish --registry http://localhost:4873 create-monolayer-app -f"
28
+ },
17
29
  "engines": {
18
30
  "node": ">=22.0.0"
19
- },
20
- "keywords": [
21
- "create-monolayer-app",
22
- "create-app",
23
- "monolayer",
24
- "react-router",
25
- "scaffold",
26
- "template"
27
- ],
28
- "license": "MIT"
31
+ }
29
32
  }
@@ -1,12 +1,12 @@
1
1
  ---
2
- name: monolayer-application-permissions
2
+ name: application-permissions
3
3
  description: >
4
4
  Apply viewer, editor, and owner permissions in monolayer React Router apps.
5
5
  Use for application content access, editing interactions, or changes to
6
6
  authentication and user context, including demos with sample or temporary data.
7
7
  ---
8
8
 
9
- # Monolayer Application Permissions
9
+ # Application Permissions
10
10
 
11
11
  Build application features using the existing user context. The application is the sharing boundary: authorized users see the same content, subject to explicit product rules.
12
12
 
@@ -0,0 +1,4 @@
1
+ interface:
2
+ display_name: "Application Permissions"
3
+ short_description: "Use shared application roles in React Router"
4
+ default_prompt: "Use $application-permissions to apply shared read and write permissions with the existing user middleware."
@@ -0,0 +1,48 @@
1
+ ---
2
+ name: kysely
3
+ description: Build, debug, review, and explain type-safe PostgreSQL with Kysely. Use for schema types, queries, expressions, transactions, migrations, plugins, compiled queries, or Kysely errors.
4
+ ---
5
+
6
+ # Kysely
7
+
8
+ Use Kysely as a type-safe PostgreSQL query builder. Keep SQL behavior, PostgreSQL behavior, and TypeScript types aligned.
9
+
10
+ ## Workflow
11
+
12
+ 1. Inspect the Kysely version, PostgreSQL version, `pg` settings, `Database` type, migrations, and local query patterns.
13
+ 2. Select the smallest applicable reference from the section map below.
14
+ 3. Build the query from typed Kysely expressions and PostgreSQL behavior.
15
+ 4. Check generated SQL when PostgreSQL behavior, parameters, plugins, or query shape can change the result.
16
+ 5. Run the focused type checks and tests that cover the changed query behavior.
17
+
18
+ The work is complete when strict TypeScript checks pass and focused tests prove the required database behavior.
19
+
20
+ ## Core Rules
21
+
22
+ - Treat Kysely as a query builder. Model relations and loading behavior explicitly with SQL.
23
+ - Treat PostgreSQL and `pg` as the source for runtime value types.
24
+ - Keep the `Database` type aligned with the deployed schema.
25
+ - Reassign immutable query builders when conditional calls add filters, grouping, or ordering.
26
+ - Use `$if` when a runtime condition changes the selected or returned row shape.
27
+ - Use expression-builder callbacks when visible tables and columns must control type inference.
28
+ - Use the `sql` template tag for missing SQL features. Interpolated values become query parameters.
29
+ - Use trusted identifiers with identifier helpers. Keep untrusted text out of `sql.raw`.
30
+ - Use PostgreSQL behavior for `returning`, JSON helpers, merge queries, DDL, and database functions.
31
+ - Keep migrations independent from current application types and current application functions.
32
+
33
+ ## Section Map
34
+
35
+ - Read [types.md](references/types.md) for PostgreSQL schema types, operation types, generated types, and `pg` runtime values.
36
+ - Read [query-building.md](references/query-building.md) for selects, filters, joins, writes, CTEs, merge queries, and execution methods.
37
+ - Read [expressions-and-helpers.md](references/expressions-and-helpers.md) for expressions, raw SQL, conditional queries, dynamic references, and reusable helpers.
38
+ - Read [transactions.md](references/transactions.md) for callback transactions, controlled transactions, and savepoints.
39
+ - Read [migrations.md](references/migrations.md) for migration files, schema changes, migration order, and execution.
40
+ - Read [execution-plugins-and-runtime.md](references/execution-plugins-and-runtime.md) for execution flow, plugins, logging, introspection, and compiled PostgreSQL queries.
41
+ - Read [troubleshooting-and-boundaries.md](references/troubleshooting-and-boundaries.md) for runtime type errors, nullable results, deep types, joins, schemas, and relation loading.
42
+ - Read [official-docs-map.md](references/official-docs-map.md) when an exact API detail needs its official Kysely source page.
43
+
44
+ ## Source Policy
45
+
46
+ These references summarize the PostgreSQL sections in the official Kysely `llms-full.txt` document retrieved on 2026-08-22.
47
+
48
+ Inspect local package types first when the installed version differs from the source. Use the official API documentation for exact signatures.
@@ -0,0 +1,4 @@
1
+ interface:
2
+ display_name: "Kysely"
3
+ short_description: "Build type-safe PostgreSQL with Kysely"
4
+ default_prompt: "Use $kysely to implement a type-safe PostgreSQL query for this application."
@@ -0,0 +1,67 @@
1
+ # Execution, plugins, and runtime
2
+
3
+ Use this reference for query execution, plugins, diagnostics, compiled queries, and compile-only environments.
4
+
5
+ ## Execution flow
6
+
7
+ Kysely query building is immutable. Each query-builder call returns a new abstract syntax tree.
8
+
9
+ Execution follows this sequence:
10
+
11
+ 1. The query executor calls each plugin `transformQuery` method.
12
+ 2. The PostgreSQL compiler creates SQL text and parameters.
13
+ 3. The Kysely driver gets a `pg` connection.
14
+ 4. The database connection executes the compiled query.
15
+ 5. `pg` returns values through a standard Kysely query result.
16
+ 6. The query executor calls each plugin `transformResult` method.
17
+
18
+ This sequence explains why plugins can change identifiers, SQL structure, and returned data.
19
+
20
+ ## Plugins
21
+
22
+ Register global plugins in the Kysely configuration. Use `withPlugin` for one query chain.
23
+
24
+ Built-in plugins include these plugins:
25
+
26
+ - `CamelCasePlugin` maps database snake-case names to JavaScript camel-case names.
27
+ - `DeduplicateJoinsPlugin` removes duplicate joins when its structural comparison succeeds.
28
+ - `HandleEmptyInListsPlugin` selects behavior for empty `IN` and `NOT IN` lists.
29
+ - `SafeNullComparisonPlugin` maps null equality operators to `IS` and `IS NOT`.
30
+
31
+ Check plugin order because each transformation receives the prior transformed query or result.
32
+
33
+ ## Logging
34
+
35
+ The Kysely `log` setting accepts log levels or a logging function. Use a function for structured application events.
36
+
37
+ Query events include compiled SQL, parameters, duration, and query results. Error events include the database error.
38
+
39
+ Apply the repository redaction rules before logs record parameters or database errors.
40
+
41
+ ## Compile and execute separately
42
+
43
+ Call `.compile()` to get a `CompiledQuery` with SQL, parameters, and the Kysely query tree.
44
+
45
+ Use `InferResult<typeof query>` or `InferResult<typeof compiledQuery>` to keep the inferred row type.
46
+
47
+ Execute a compiled query with a connected Kysely instance:
48
+
49
+ ```typescript
50
+ const query = db
51
+ .selectFrom("person")
52
+ .select("first_name")
53
+ .where("id", "=", personId)
54
+
55
+ const compiled = query.compile()
56
+ const result = await db.executeQuery(compiled)
57
+ ```
58
+
59
+ A `DummyDriver` creates a compile-only Kysely instance. Use `PostgresAdapter`, `PostgresIntrospector`, and `PostgresQueryCompiler` with it.
60
+
61
+ Compile-only mode creates PostgreSQL SQL without a database connection. Executing through `DummyDriver` does not contact PostgreSQL.
62
+
63
+ ## Runtime checks
64
+
65
+ Check the `pg` documentation when a value has an unexpected runtime type. Kysely returns `pg` values without conversion by default.
66
+
67
+ Configure `pg` type parsers when the application requires different PostgreSQL runtime values.
@@ -0,0 +1,102 @@
1
+ # Expressions and helpers
2
+
3
+ Use this reference for complex expressions, raw SQL, conditional output, and reusable query parts.
4
+
5
+ ## Expression builder
6
+
7
+ `Expression<T>` is the common Kysely query part. `T` is the expression output type.
8
+
9
+ Use callback expression builders when the visible tables must control available references.
10
+
11
+ ```typescript
12
+ const row = await db
13
+ .selectFrom("person")
14
+ .select(({ fn, ref, val }) => [
15
+ fn<string>("upper", ["first_name"]).as("upper_first_name"),
16
+ ref("last_name").as("family_name"),
17
+ val("person").as("kind"),
18
+ ])
19
+ .executeTakeFirstOrThrow()
20
+ ```
21
+
22
+ Expression-builder callbacks infer the query context. A global `expressionBuilder<DB>()` has no visible tables by default.
23
+
24
+ Use `Expression<SqlBool>` for reusable predicates. Use `Expression<T>` parameters for reusable value helpers.
25
+
26
+ ## Conditional queries
27
+
28
+ Kysely query builders are immutable. A reassigned builder keeps its original static variable type.
29
+
30
+ Conditional filters, groups, and ordering usually keep the row type unchanged. Reassign those builders directly.
31
+
32
+ Conditional selects, returning clauses, and joins change the row type. Use `$if` for optional output properties.
33
+
34
+ ```typescript
35
+ const row = await db
36
+ .selectFrom("person")
37
+ .select("first_name")
38
+ .$if(includeLastName, (query) => query.select("last_name"))
39
+ .where("id", "=", personId)
40
+ .executeTakeFirstOrThrow()
41
+ ```
42
+
43
+ The `last_name` result property is optional. Use explicit branches when the function needs a discriminated result union.
44
+
45
+ ## Raw SQL
46
+
47
+ Use the `sql` template tag when Kysely has no suitable typed method.
48
+
49
+ ```typescript
50
+ import { sql } from "kysely"
51
+
52
+ const rows = await db
53
+ .selectFrom("person")
54
+ .select(sql<string>`upper(${sql.ref("first_name")})`.as("name"))
55
+ .where("id", "=", personId)
56
+ .execute()
57
+ ```
58
+
59
+ Normal interpolated values become query parameters. Expressions inside interpolation remain SQL expressions.
60
+
61
+ Choose identifier helpers by purpose:
62
+
63
+ - `sql.ref` creates a column reference.
64
+ - `sql.table` creates a table reference.
65
+ - `sql.id` creates a general identifier.
66
+ - `sql.join` joins expressions with a SQL separator.
67
+ - `sql.val` creates a parameterized value.
68
+ - `sql.lit` creates a literal.
69
+ - `sql.raw` inserts trusted SQL text unchanged.
70
+
71
+ Validate runtime identifiers against an application allowlist. Raw identifier helpers do not make untrusted names safe.
72
+
73
+ Use a generic type on `sql<T>` because Kysely cannot infer raw SQL output types.
74
+
75
+ ## Dynamic references
76
+
77
+ Use `db.dynamic.ref` when a validated runtime value selects a column. The result type can become a union of optional properties.
78
+
79
+ Prefer ordinary typed references when the column name is known during compilation.
80
+
81
+ ## Reusable helpers
82
+
83
+ Accept expressions instead of raw values when callers can pass columns, values, functions, or subqueries.
84
+
85
+ ```typescript
86
+ import type { Expression } from "kysely"
87
+ import { sql } from "kysely"
88
+
89
+ function upper(value: Expression<string>) {
90
+ return sql<string>`upper(${value})`
91
+ }
92
+ ```
93
+
94
+ Add `as` when a helper appears in a select list. Use `$asScalar()` when a one-column subquery must act as a scalar expression.
95
+
96
+ Use conditional generic types when a helper must preserve nullable input behavior. Use `$notNull()` only with a proven SQL invariant.
97
+
98
+ ## Extension choices
99
+
100
+ Prefer a small helper that returns `Expression<T>` or `AliasedExpression<T, A>`. This choice keeps the public API small.
101
+
102
+ Implement Kysely interfaces directly only when raw builders cannot express the required operation. Preserve operation-node immutability in custom implementations.
@@ -0,0 +1,43 @@
1
+ # Migrations
2
+
3
+ Use this reference for migration files, schema changes, migration order, and execution.
4
+
5
+ ## Migration files
6
+
7
+ Migration modules export `up` and `down` functions.
8
+
9
+ ```typescript
10
+ import type { Kysely } from "kysely"
11
+
12
+ export async function up(db: Kysely<any>): Promise<void> {
13
+ await db.schema
14
+ .createTable("person")
15
+ .addColumn("id", "serial", (column) => column.primaryKey())
16
+ .addColumn("name", "varchar", (column) => column.notNull())
17
+ .execute()
18
+ }
19
+
20
+ export async function down(db: Kysely<any>): Promise<void> {
21
+ await db.schema.dropTable("person").execute()
22
+ }
23
+ ```
24
+
25
+ The official guidance uses `Kysely<any>` in migrations. A migration represents its historical schema, not the current application schema.
26
+
27
+ Keep migration behavior frozen in time. Put required data changes and SQL inside the migration boundary.
28
+
29
+ ## Order and execution
30
+
31
+ Kysely sorts migration names with alphanumeric order. Prefix names with an ISO 8601 date or another sortable identifier.
32
+
33
+ The default migrator verifies that file order matches the prior database execution order. `allowUnorderedMigrations` relaxes this check for parallel teams.
34
+
35
+ Pending unordered migrations still run in alphanumeric order. Down migrations run in reverse execution order.
36
+
37
+ `Migrator.migrateToLatest()` uses a database lock. Concurrent application instances execute each migration once.
38
+
39
+ Always inspect the returned `error` and `results`. Destroy the migration Kysely instance after the runner finishes.
40
+
41
+ ## Schema operations
42
+
43
+ Use PostgreSQL data types, defaults, constraints, and index behavior. Check the generated SQL before production use.