kernelcms 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.
package/README.md ADDED
@@ -0,0 +1,70 @@
1
+ # kernelcms
2
+
3
+ The TanStack-native, adapter-based, end-to-end type-safe **headless CMS** — config-as-code and fully self-hosted.
4
+
5
+ ```bash
6
+ npm install kernelcms
7
+ ```
8
+
9
+ > Requires **Node >= 22** and a **PostgreSQL** database (set `DATABASE_URL`).
10
+
11
+ ## Quickstart
12
+
13
+ ```ts
14
+ // kernel.config.ts
15
+ import { defineConfig } from 'kernelcms'
16
+ import { postgresAdapter } from 'kernelcms/postgres'
17
+
18
+ export default defineConfig({
19
+ secret: process.env.KERNEL_SECRET,
20
+ db: postgresAdapter(), // reads DATABASE_URL
21
+ collections: [
22
+ {
23
+ slug: 'posts',
24
+ access: { read: () => true },
25
+ fields: [
26
+ { name: 'title', type: 'text', required: true },
27
+ { name: 'body', type: 'richText' },
28
+ ],
29
+ },
30
+ ],
31
+ })
32
+ ```
33
+
34
+ ```bash
35
+ export DATABASE_URL="postgres://user:pass@localhost:5432/mydb"
36
+ ```
37
+
38
+ ```ts
39
+ import { initKernel } from 'kernelcms'
40
+ import config from './kernel.config'
41
+
42
+ const kernel = await initKernel(config, { autoMigrate: true })
43
+ const post = await kernel.create({ collection: 'posts', data: { title: 'Hello' }, overrideAccess: true })
44
+ ```
45
+
46
+ ## Entry points
47
+
48
+ | Import | What you get |
49
+ | --- | --- |
50
+ | `kernelcms` | Config, fields, the Local API (`initKernel`), auth, access, codegen, error types |
51
+ | `kernelcms/postgres` | `postgresAdapter` — the default PostgreSQL adapter (pooled, concurrent transactions) |
52
+ | `kernelcms/sqlite` | `sqliteAdapter` — an optional `node:sqlite` adapter, handy for local dev and tests |
53
+ | `kernelcms/server` | `createRequestHandler`, `serve` — the REST handler + Node http adapter |
54
+ | `kernelcms/client` | `createClient` — a tiny typed fetch client (browser/edge/Node) |
55
+
56
+ ## CLI
57
+
58
+ ```bash
59
+ npx kernel migrate # create/update tables from the config
60
+ npx kernel seed # run the exported seed()
61
+ npx kernel dev # migrate + start the REST API
62
+ npx kernel generate:types # emit TypeScript types for the content model
63
+ ```
64
+
65
+ The CLI imports your `kernel.config.ts` directly — run on Node ≥ 22.6 (type
66
+ stripping) or point `--config` at a compiled `.js`/`.mjs`.
67
+
68
+ ## License
69
+
70
+ MIT
package/dist/bin.d.ts ADDED
@@ -0,0 +1 @@
1
+ #!/usr/bin/env node
package/dist/bin.js ADDED
@@ -0,0 +1,133 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ serve
4
+ } from "./chunk-Z2RKB4LF.js";
5
+ import {
6
+ generateTypes,
7
+ initKernel
8
+ } from "./chunk-O5TO5JFA.js";
9
+
10
+ // ../cli/src/index.ts
11
+ import { writeFileSync } from "fs";
12
+ import { dirname, resolve } from "path";
13
+ import { pathToFileURL } from "url";
14
+ function parseArgs(argv) {
15
+ const positionals = [];
16
+ const flags = {};
17
+ for (let i = 0; i < argv.length; i++) {
18
+ const arg = argv[i];
19
+ if (arg.startsWith("--")) {
20
+ const key = arg.slice(2);
21
+ const next = argv[i + 1];
22
+ if (next !== void 0 && !next.startsWith("--")) {
23
+ flags[key] = next;
24
+ i++;
25
+ } else {
26
+ flags[key] = true;
27
+ }
28
+ } else {
29
+ positionals.push(arg);
30
+ }
31
+ }
32
+ return { command: positionals[0], positionals: positionals.slice(1), flags };
33
+ }
34
+ async function loadConfig(flags) {
35
+ const configPath = typeof flags.config === "string" ? flags.config : "kernel.config.ts";
36
+ const abs = resolve(process.cwd(), configPath);
37
+ const mod = await import(pathToFileURL(abs).href);
38
+ const config = mod.default ?? mod.config;
39
+ if (!config) throw new Error(`No config found. Export a default config from ${configPath}.`);
40
+ return { config, seed: mod.seed, path: abs };
41
+ }
42
+ var HELP = `KernelCMS CLI
43
+
44
+ Usage: kernel <command> [options]
45
+
46
+ Commands:
47
+ migrate Create/update database tables from the config schema
48
+ seed Run the exported seed() function
49
+ generate:types Write generated TypeScript types for the content model
50
+ dev Migrate, then start the REST API server
51
+
52
+ Options:
53
+ --config <path> Path to kernel.config.ts (default: ./kernel.config.ts)
54
+ --port <number> Port for "dev" (default: $PORT or 3000)
55
+ --out <path> Output file for "generate:types"
56
+ `;
57
+ async function run(argv) {
58
+ const { command, flags } = parseArgs(argv);
59
+ switch (command) {
60
+ case "migrate": {
61
+ const { config } = await loadConfig(flags);
62
+ const kernel = await initKernel(config);
63
+ const report = await kernel.db.migrate(kernel.schema);
64
+ console.log(
65
+ `\u2713 Migration complete \u2014 ${report.createdTables.length} table(s) created, ${report.addedColumns.length} column(s) added.`
66
+ );
67
+ if (report.createdTables.length) console.log(` Created: ${report.createdTables.join(", ")}`);
68
+ await kernel.destroy();
69
+ break;
70
+ }
71
+ case "seed": {
72
+ const { config, seed } = await loadConfig(flags);
73
+ if (!seed) throw new Error("No `seed` export found in the config module.");
74
+ const kernel = await initKernel(config, { autoMigrate: true });
75
+ await seed(kernel);
76
+ console.log("\u2713 Seed complete.");
77
+ await kernel.destroy();
78
+ break;
79
+ }
80
+ case "generate:types":
81
+ case "types": {
82
+ const { config, path } = await loadConfig(flags);
83
+ const output = generateTypes({ collections: config.collections, globals: config.globals ?? [] });
84
+ const out = typeof flags.out === "string" ? resolve(process.cwd(), flags.out) : resolve(dirname(path), "kernel-types.ts");
85
+ writeFileSync(out, output, "utf8");
86
+ console.log(`\u2713 Types written to ${out}`);
87
+ break;
88
+ }
89
+ case "dev": {
90
+ const { config } = await loadConfig(flags);
91
+ const kernel = await initKernel(config, { autoMigrate: true });
92
+ const port = typeof flags.port === "string" ? Number(flags.port) : Number(process.env.PORT) || 3e3;
93
+ const server = await serve(kernel, {
94
+ port,
95
+ apiKey: process.env.KERNEL_API_KEY,
96
+ cors: true
97
+ });
98
+ console.log(`
99
+ KernelCMS dev server`);
100
+ console.log(` \u279C API: ${server.url}${kernel.config.routes.api}`);
101
+ console.log(` \u279C Health: ${server.url}${kernel.config.routes.api}/health`);
102
+ console.log(` \u279C Collections: ${kernel.config.collections.map((c) => c.slug).join(", ") || "(none)"}`);
103
+ if (!process.env.KERNEL_API_KEY) {
104
+ console.log(` ! Set KERNEL_API_KEY to enable trusted writes over HTTP.`);
105
+ }
106
+ const shutdown = async () => {
107
+ await server.close();
108
+ await kernel.destroy();
109
+ process.exit(0);
110
+ };
111
+ process.on("SIGINT", shutdown);
112
+ process.on("SIGTERM", shutdown);
113
+ break;
114
+ }
115
+ case void 0:
116
+ case "help":
117
+ case "--help":
118
+ console.log(HELP);
119
+ break;
120
+ default:
121
+ console.error(`Unknown command "${command}".
122
+ `);
123
+ console.log(HELP);
124
+ process.exitCode = 1;
125
+ }
126
+ }
127
+
128
+ // src/bin.ts
129
+ run(process.argv.slice(2)).catch((err) => {
130
+ console.error(`
131
+ \u2717 ${err instanceof Error ? err.message : String(err)}`);
132
+ process.exit(1);
133
+ });