@nanokajs/core 0.1.1 → 0.1.3
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 +53 -4
- package/dist/cli.js +24 -14
- package/dist/cli.js.map +1 -1
- package/dist/config.d.ts +2 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -21,11 +21,44 @@ Phase 1 (MVP). Experimental. Expect breaking changes until v1.0.
|
|
|
21
21
|
|
|
22
22
|
## Install
|
|
23
23
|
|
|
24
|
+
Nanoka assumes a Hono + Cloudflare Workers project. The standard starting point is `pnpm create hono@latest` (Cloudflare Workers template), which scaffolds `wrangler` and `hono` but **not** TypeScript, `@cloudflare/workers-types`, or `drizzle-kit`. From a fresh scaffold, add Nanoka and the missing pieces:
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
pnpm add @nanokajs/core drizzle-orm zod@^3.23.0
|
|
28
|
+
pnpm add -D typescript drizzle-kit @cloudflare/workers-types
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
Then add a `types` entry to `tsconfig.json` so `D1Database`, `Request`, `ExecutionContext`, and `crypto` resolve as ambient globals (no per-file imports needed):
|
|
32
|
+
|
|
33
|
+
```jsonc
|
|
34
|
+
{
|
|
35
|
+
"compilerOptions": {
|
|
36
|
+
// ... existing options from create-hono ...
|
|
37
|
+
"types": ["@cloudflare/workers-types"]
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Without `types`, you would have to `import { D1Database, Request, ... } from '@cloudflare/workers-types'` in every file — which works for types but is misleading because the package has no runtime exports, and importing `Request` shadows the global `Request` constructor.
|
|
43
|
+
|
|
44
|
+
After this, the [Minimal example](#minimal-example-model--1-route) below works as written.
|
|
45
|
+
|
|
46
|
+
> **Zod 4 is not yet supported.** Zod 4 reorders the `ZodType` generics, which collapses Nanoka's field type inference (`RowType`, `CreateInput`) to `never`. Pin `zod@^3.23.0` until Phase 2 ships Zod 4 support. Without the pin, `pnpm add zod` will install the latest 4.x and `User.create({...})` will fail to type-check.
|
|
47
|
+
|
|
48
|
+
`drizzle-kit` is required at install time (not a peer dep) because `npx drizzle-kit generate` is the supported migration step — see Quickstart step 3.
|
|
49
|
+
|
|
50
|
+
### Adding to a project that wasn't scaffolded by create-hono
|
|
51
|
+
|
|
52
|
+
If you're integrating into an existing TypeScript project (no `create hono`), `hono` itself is also a peer dep — add it to the runtime install:
|
|
53
|
+
|
|
24
54
|
```bash
|
|
25
|
-
pnpm add @nanokajs/core hono drizzle-orm zod
|
|
55
|
+
pnpm add @nanokajs/core hono drizzle-orm zod@^3.23.0
|
|
56
|
+
pnpm add -D typescript drizzle-kit @cloudflare/workers-types
|
|
26
57
|
```
|
|
27
58
|
|
|
28
|
-
|
|
59
|
+
The tsconfig `types` entry above still applies if you're targeting Cloudflare Workers.
|
|
60
|
+
|
|
61
|
+
Peer dependency ranges: `hono ^4.0.0`, `drizzle-orm ^0.45.0`, `zod ^3.23.0`, `@cloudflare/workers-types ^4.20240925.0`.
|
|
29
62
|
|
|
30
63
|
## Quickstart
|
|
31
64
|
|
|
@@ -69,8 +102,21 @@ Peer dependencies: `hono ^4.0.0`, `drizzle-orm ^0.45.0`, `zod ^3.23.0`, `@cloudf
|
|
|
69
102
|
|
|
70
103
|
✓ Creates `drizzle/schema.ts` from your models.
|
|
71
104
|
|
|
72
|
-
3. **
|
|
105
|
+
3. **Generate SQL migrations and apply them**
|
|
106
|
+
|
|
107
|
+
Create `drizzle.config.ts` in your project root (this is read by `drizzle-kit`, not by Nanoka):
|
|
108
|
+
```ts
|
|
109
|
+
import { defineConfig } from 'drizzle-kit'
|
|
110
|
+
|
|
111
|
+
export default defineConfig({
|
|
112
|
+
schema: './drizzle/schema.ts',
|
|
113
|
+
out: './drizzle/migrations',
|
|
114
|
+
dialect: 'sqlite',
|
|
115
|
+
driver: 'd1-http',
|
|
116
|
+
})
|
|
117
|
+
```
|
|
73
118
|
|
|
119
|
+
Then:
|
|
74
120
|
```bash
|
|
75
121
|
npx drizzle-kit generate
|
|
76
122
|
npx wrangler d1 migrations apply <DATABASE> --local
|
|
@@ -78,12 +124,14 @@ Peer dependencies: `hono ^4.0.0`, `drizzle-orm ^0.45.0`, `zod ^3.23.0`, `@cloudf
|
|
|
78
124
|
|
|
79
125
|
✓ SQL migrations generated from Drizzle schema. Ready to deploy.
|
|
80
126
|
|
|
127
|
+
The `nanoka.config.ts` (step 2) and `drizzle.config.ts` (step 3) are deliberately separate: Nanoka generates Drizzle schema code, then `drizzle-kit` diffs and emits SQL. Nanoka does not generate SQL or apply migrations — see [How it fits with drizzle-kit and wrangler](#how-it-fits-with-drizzle-kit-and-wrangler) below.
|
|
128
|
+
|
|
81
129
|
### Minimal example (model + 1 route)
|
|
82
130
|
|
|
83
131
|
`src/index.ts`:
|
|
84
132
|
```ts
|
|
85
133
|
import { d1Adapter, nanoka } from '@nanokajs/core'
|
|
86
|
-
import { userFields, userTableName } from './
|
|
134
|
+
import { userFields, userTableName } from './models/user'
|
|
87
135
|
|
|
88
136
|
export interface Env {
|
|
89
137
|
DB: D1Database
|
|
@@ -335,6 +383,7 @@ Nanoka Phase 1 is intentionally minimal. These features are Phase 2 or later:
|
|
|
335
383
|
|
|
336
384
|
- **Relations** (`hasMany()`, `belongsTo()`, lazy loading) — Phase 2. Use raw Drizzle for joins.
|
|
337
385
|
- **Field accessor API** (`User.schema({ pick: f => [f.name, f.email] })`, `User.where(f => eq(f.email, x))`) — Phase 2. Phase 1 uses string arrays and object-form `where`. When Phase 2 lands, the `f` object will be `as const`, with zero runtime cost.
|
|
386
|
+
- **Zod 4 support** — Phase 2. Zod 4 changed `ZodType<Output, Def, Input>` (v3) to `ZodType<Output, Input, Internals>` (v4); Nanoka's field type derivation depends on the v3 generic order, so installing Zod 4 collapses `InferFieldType` to `never`. Pin `zod@^3.23.0` for now.
|
|
338
387
|
- **OpenAPI generation** — Phase 2 or 3.
|
|
339
388
|
- **Turso / libSQL adapters** — Phase 2. Nanoka is designed adapter-first; additional adapters will follow.
|
|
340
389
|
- **CLI scaffolder** (`create-nanoka-app`) — Phase 3.
|
package/dist/cli.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { promises } from 'fs';
|
|
2
|
+
import { realpathSync, promises } from 'fs';
|
|
3
3
|
import { resolve, dirname } from 'path';
|
|
4
|
+
import { pathToFileURL } from 'url';
|
|
4
5
|
import { createJiti } from 'jiti';
|
|
5
6
|
|
|
6
7
|
// src/cli/index.ts
|
|
@@ -106,7 +107,7 @@ function generateDrizzleSchema(models) {
|
|
|
106
107
|
${fieldsStr}
|
|
107
108
|
}` : "{}";
|
|
108
109
|
lines.push(
|
|
109
|
-
`export const ${model.
|
|
110
|
+
`export const ${model.name} = sqliteTable('${model.name}', ${tableContent})`
|
|
110
111
|
);
|
|
111
112
|
lines.push("");
|
|
112
113
|
}
|
|
@@ -125,27 +126,27 @@ async function loadConfig(configPath) {
|
|
|
125
126
|
async function main(args) {
|
|
126
127
|
try {
|
|
127
128
|
if (args.length === 0 || args[0] === "help" || args[0] === "--help" || args[0] === "-h") {
|
|
128
|
-
console.log("Usage: nanoka generate [--config <path>] [--
|
|
129
|
+
console.log("Usage: nanoka generate [--config <path>] [--output <path>]");
|
|
129
130
|
console.log("");
|
|
130
131
|
console.log("Options:");
|
|
131
132
|
console.log(" --config <path> Path to nanoka.config.ts (default: ./nanoka.config.ts)");
|
|
132
|
-
console.log(" --
|
|
133
|
+
console.log(" --output <path> Output file path (overrides config.output)");
|
|
133
134
|
return 0;
|
|
134
135
|
}
|
|
135
136
|
if (args[0] !== "generate") {
|
|
136
137
|
console.error(`Error: unknown command '${args[0]}'`);
|
|
137
|
-
console.error("Usage: nanoka generate [--config <path>] [--
|
|
138
|
+
console.error("Usage: nanoka generate [--config <path>] [--output <path>]");
|
|
138
139
|
return 1;
|
|
139
140
|
}
|
|
140
141
|
let configPath = "./nanoka.config.ts";
|
|
141
|
-
let
|
|
142
|
+
let outputPath;
|
|
142
143
|
let i = 1;
|
|
143
144
|
while (i < args.length) {
|
|
144
145
|
if (args[i] === "--config" && i + 1 < args.length) {
|
|
145
146
|
configPath = args[i + 1];
|
|
146
147
|
i += 2;
|
|
147
|
-
} else if (args[i] === "--
|
|
148
|
-
|
|
148
|
+
} else if (args[i] === "--output" && i + 1 < args.length) {
|
|
149
|
+
outputPath = args[i + 1];
|
|
149
150
|
i += 2;
|
|
150
151
|
} else {
|
|
151
152
|
console.error(`Error: unknown option '${args[i]}'`);
|
|
@@ -154,12 +155,12 @@ async function main(args) {
|
|
|
154
155
|
}
|
|
155
156
|
const absoluteConfigPath = resolve(process.cwd(), configPath);
|
|
156
157
|
const config = await loadConfig(absoluteConfigPath);
|
|
157
|
-
const
|
|
158
|
-
const
|
|
158
|
+
const finalOutputPath = outputPath ?? config.output ?? "./drizzle/schema.ts";
|
|
159
|
+
const absoluteOutputPath = resolve(process.cwd(), finalOutputPath);
|
|
159
160
|
const schema = generateDrizzleSchema(config.models);
|
|
160
|
-
await promises.mkdir(dirname(
|
|
161
|
-
await promises.writeFile(
|
|
162
|
-
console.log(`\u2713 Generated ${
|
|
161
|
+
await promises.mkdir(dirname(absoluteOutputPath), { recursive: true });
|
|
162
|
+
await promises.writeFile(absoluteOutputPath, schema, "utf-8");
|
|
163
|
+
console.log(`\u2713 Generated ${absoluteOutputPath}`);
|
|
163
164
|
return 0;
|
|
164
165
|
} catch (error) {
|
|
165
166
|
if (error instanceof Error) {
|
|
@@ -170,7 +171,16 @@ async function main(args) {
|
|
|
170
171
|
return 1;
|
|
171
172
|
}
|
|
172
173
|
}
|
|
173
|
-
|
|
174
|
+
function isCliEntrypoint() {
|
|
175
|
+
const argv1 = process.argv[1];
|
|
176
|
+
if (!argv1) return false;
|
|
177
|
+
try {
|
|
178
|
+
return pathToFileURL(realpathSync(argv1)).href === import.meta.url;
|
|
179
|
+
} catch {
|
|
180
|
+
return false;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
if (isCliEntrypoint()) {
|
|
174
184
|
main(process.argv.slice(2)).then((code) => {
|
|
175
185
|
process.exit(code);
|
|
176
186
|
});
|
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/codegen/render-field.ts","../src/codegen/generate.ts","../src/cli/load-config.ts","../src/cli/index.ts"],"names":["fs"],"mappings":"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","file":"cli.js","sourcesContent":["import type { Field } from '../field'\n\nexport function renderField(fieldName: string, field: Field<any, any, any>): string {\n const lines: string[] = []\n\n const kind = field.kind\n let colType: string\n\n if (kind === 'string' || kind === 'uuid') {\n colType = `text('${fieldName}')`\n } else if (kind === 'number') {\n colType = `real('${fieldName}')`\n } else if (kind === 'integer') {\n colType = `integer('${fieldName}')`\n } else if (kind === 'boolean') {\n colType = `integer('${fieldName}', { mode: 'boolean' })`\n } else if (kind === 'timestamp') {\n colType = `integer('${fieldName}', { mode: 'timestamp_ms' })`\n } else if (kind === 'json') {\n colType = `text('${fieldName}', { mode: 'json' }).$type<unknown>()`\n } else {\n throw new Error(`Unknown field kind: ${kind}`)\n }\n\n let column = colType\n\n if (field.modifiers.primary) {\n column += '.primaryKey()'\n }\n\n if (!field.modifiers.optional) {\n column += '.notNull()'\n }\n\n if (field.modifiers.unique) {\n column += '.unique()'\n }\n\n if (field.modifiers.hasDefault) {\n const defaultValue = field.modifiers.defaultValue\n if (typeof defaultValue === 'function') {\n console.warn(\n `[nanoka] Warning: field \"${fieldName}\" has a function default. Default clause will be omitted. ` +\n `Use Drizzle's $defaultFn() or .onUpdateCurrent() in your custom schema if needed.`,\n )\n } else {\n const serializedValue = JSON.stringify(defaultValue)\n column += `.default(${serializedValue})`\n }\n }\n\n lines.push(` ${fieldName}: ${column},`)\n return lines.join('\\n')\n}\n","import { renderField } from './render-field'\nimport type { ModelDef } from './types'\n\nconst USED_DRIZZLE_IMPORTS = {\n text: false,\n integer: false,\n real: false,\n sqliteTable: false,\n}\n\nfunction detectImports(\n models: readonly ModelDef[],\n): Record<keyof typeof USED_DRIZZLE_IMPORTS, boolean> {\n const imports = { ...USED_DRIZZLE_IMPORTS }\n\n for (const model of models) {\n for (const field of Object.values(model.fields)) {\n const kind = field.kind\n\n if (kind === 'string' || kind === 'uuid' || kind === 'json') {\n imports.text = true\n } else if (kind === 'number') {\n imports.real = true\n } else if (kind === 'integer' || kind === 'boolean' || kind === 'timestamp') {\n imports.integer = true\n }\n }\n\n if (Object.values(model.fields).length > 0) {\n imports.sqliteTable = true\n }\n }\n\n return imports\n}\n\nfunction buildImportStatement(imports: Record<keyof typeof USED_DRIZZLE_IMPORTS, boolean>): string {\n const used: string[] = []\n\n if (imports.integer) used.push('integer')\n if (imports.real) used.push('real')\n if (imports.sqliteTable) used.push('sqliteTable')\n if (imports.text) used.push('text')\n\n if (used.length === 0) {\n return \"import { sqliteTable } from 'drizzle-orm/sqlite-core'\"\n }\n\n return `import { ${used.join(', ')} } from 'drizzle-orm/sqlite-core'`\n}\n\nexport function generateDrizzleSchema(models: readonly ModelDef[]): string {\n const imports = detectImports(models)\n const importStatement = buildImportStatement(imports)\n\n const lines: string[] = [\n '// AUTO-GENERATED by `nanoka generate`. DO NOT EDIT BY HAND.',\n '// To regenerate: `npx nanoka generate`',\n importStatement,\n '',\n ]\n\n for (const model of models) {\n const fieldLines: string[] = []\n\n for (const [fieldName, field] of Object.entries(model.fields)) {\n fieldLines.push(renderField(fieldName, field))\n }\n\n const fieldsStr = fieldLines.length > 0 ? fieldLines.join('\\n') : ''\n const tableContent = fieldsStr ? `{\\n${fieldsStr}\\n}` : '{}'\n\n lines.push(\n `export const ${model.tableName} = sqliteTable('${model.tableName}', ${tableContent})`,\n )\n lines.push('')\n }\n\n // Remove trailing empty line and add single newline at EOF\n while (lines.length > 0 && lines[lines.length - 1] === '') {\n lines.pop()\n }\n\n return lines.join('\\n') + '\\n'\n}\n","import { createJiti } from 'jiti'\nimport type { NanokaConfig } from '../codegen/types'\n\nexport async function loadConfig(configPath: string): Promise<NanokaConfig> {\n const jiti = createJiti(import.meta.url, { interopDefault: true })\n const mod = await jiti.import<{ default: NanokaConfig }>(configPath)\n return mod.default\n}\n","import { promises as fs } from 'fs'\nimport { dirname, resolve } from 'path'\nimport { generateDrizzleSchema } from '../codegen/generate'\nimport { loadConfig } from './load-config'\n\nasync function main(args: string[]): Promise<number> {\n try {\n if (args.length === 0 || args[0] === 'help' || args[0] === '--help' || args[0] === '-h') {\n console.log('Usage: nanoka generate [--config <path>] [--out <path>]')\n console.log('')\n console.log('Options:')\n console.log(' --config <path> Path to nanoka.config.ts (default: ./nanoka.config.ts)')\n console.log(' --out <path> Output file path (overrides config.out)')\n return 0\n }\n\n if (args[0] !== 'generate') {\n console.error(`Error: unknown command '${args[0]}'`)\n console.error('Usage: nanoka generate [--config <path>] [--out <path>]')\n return 1\n }\n\n let configPath: string = './nanoka.config.ts'\n let outPath: string | undefined\n\n let i = 1\n while (i < args.length) {\n if (args[i] === '--config' && i + 1 < args.length) {\n configPath = args[i + 1]!\n i += 2\n } else if (args[i] === '--out' && i + 1 < args.length) {\n outPath = args[i + 1]!\n i += 2\n } else {\n console.error(`Error: unknown option '${args[i]}'`)\n return 1\n }\n }\n\n const absoluteConfigPath = resolve(process.cwd(), configPath)\n const config = await loadConfig(absoluteConfigPath)\n\n const finalOutPath = outPath ?? config.out ?? './drizzle/schema.ts'\n const absoluteOutPath = resolve(process.cwd(), finalOutPath)\n\n const schema = generateDrizzleSchema(config.models)\n\n await fs.mkdir(dirname(absoluteOutPath), { recursive: true })\n await fs.writeFile(absoluteOutPath, schema, 'utf-8')\n\n console.log(`✓ Generated ${absoluteOutPath}`)\n return 0\n } catch (error) {\n if (error instanceof Error) {\n console.error(`Error: ${error.message}`)\n } else {\n console.error('Unknown error:', error)\n }\n return 1\n }\n}\n\nif (import.meta.url === `file://${process.argv[1]}`) {\n main(process.argv.slice(2)).then((code) => {\n process.exit(code)\n })\n}\n\nexport { main }\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/codegen/render-field.ts","../src/codegen/generate.ts","../src/cli/load-config.ts","../src/cli/index.ts"],"names":["fs"],"mappings":"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","file":"cli.js","sourcesContent":["import type { Field } from '../field'\n\nexport function renderField(fieldName: string, field: Field<any, any, any>): string {\n const lines: string[] = []\n\n const kind = field.kind\n let colType: string\n\n if (kind === 'string' || kind === 'uuid') {\n colType = `text('${fieldName}')`\n } else if (kind === 'number') {\n colType = `real('${fieldName}')`\n } else if (kind === 'integer') {\n colType = `integer('${fieldName}')`\n } else if (kind === 'boolean') {\n colType = `integer('${fieldName}', { mode: 'boolean' })`\n } else if (kind === 'timestamp') {\n colType = `integer('${fieldName}', { mode: 'timestamp_ms' })`\n } else if (kind === 'json') {\n colType = `text('${fieldName}', { mode: 'json' }).$type<unknown>()`\n } else {\n throw new Error(`Unknown field kind: ${kind}`)\n }\n\n let column = colType\n\n if (field.modifiers.primary) {\n column += '.primaryKey()'\n }\n\n if (!field.modifiers.optional) {\n column += '.notNull()'\n }\n\n if (field.modifiers.unique) {\n column += '.unique()'\n }\n\n if (field.modifiers.hasDefault) {\n const defaultValue = field.modifiers.defaultValue\n if (typeof defaultValue === 'function') {\n console.warn(\n `[nanoka] Warning: field \"${fieldName}\" has a function default. Default clause will be omitted. ` +\n `Use Drizzle's $defaultFn() or .onUpdateCurrent() in your custom schema if needed.`,\n )\n } else {\n const serializedValue = JSON.stringify(defaultValue)\n column += `.default(${serializedValue})`\n }\n }\n\n lines.push(` ${fieldName}: ${column},`)\n return lines.join('\\n')\n}\n","import { renderField } from './render-field'\nimport type { ModelDef } from './types'\n\nconst USED_DRIZZLE_IMPORTS = {\n text: false,\n integer: false,\n real: false,\n sqliteTable: false,\n}\n\nfunction detectImports(\n models: readonly ModelDef[],\n): Record<keyof typeof USED_DRIZZLE_IMPORTS, boolean> {\n const imports = { ...USED_DRIZZLE_IMPORTS }\n\n for (const model of models) {\n for (const field of Object.values(model.fields)) {\n const kind = field.kind\n\n if (kind === 'string' || kind === 'uuid' || kind === 'json') {\n imports.text = true\n } else if (kind === 'number') {\n imports.real = true\n } else if (kind === 'integer' || kind === 'boolean' || kind === 'timestamp') {\n imports.integer = true\n }\n }\n\n if (Object.values(model.fields).length > 0) {\n imports.sqliteTable = true\n }\n }\n\n return imports\n}\n\nfunction buildImportStatement(imports: Record<keyof typeof USED_DRIZZLE_IMPORTS, boolean>): string {\n const used: string[] = []\n\n if (imports.integer) used.push('integer')\n if (imports.real) used.push('real')\n if (imports.sqliteTable) used.push('sqliteTable')\n if (imports.text) used.push('text')\n\n if (used.length === 0) {\n return \"import { sqliteTable } from 'drizzle-orm/sqlite-core'\"\n }\n\n return `import { ${used.join(', ')} } from 'drizzle-orm/sqlite-core'`\n}\n\nexport function generateDrizzleSchema(models: readonly ModelDef[]): string {\n const imports = detectImports(models)\n const importStatement = buildImportStatement(imports)\n\n const lines: string[] = [\n '// AUTO-GENERATED by `nanoka generate`. DO NOT EDIT BY HAND.',\n '// To regenerate: `npx nanoka generate`',\n importStatement,\n '',\n ]\n\n for (const model of models) {\n const fieldLines: string[] = []\n\n for (const [fieldName, field] of Object.entries(model.fields)) {\n fieldLines.push(renderField(fieldName, field))\n }\n\n const fieldsStr = fieldLines.length > 0 ? fieldLines.join('\\n') : ''\n const tableContent = fieldsStr ? `{\\n${fieldsStr}\\n}` : '{}'\n\n lines.push(\n `export const ${model.name} = sqliteTable('${model.name}', ${tableContent})`,\n )\n lines.push('')\n }\n\n // Remove trailing empty line and add single newline at EOF\n while (lines.length > 0 && lines[lines.length - 1] === '') {\n lines.pop()\n }\n\n return lines.join('\\n') + '\\n'\n}\n","import { createJiti } from 'jiti'\nimport type { NanokaConfig } from '../codegen/types'\n\nexport async function loadConfig(configPath: string): Promise<NanokaConfig> {\n const jiti = createJiti(import.meta.url, { interopDefault: true })\n const mod = await jiti.import<{ default: NanokaConfig }>(configPath)\n return mod.default\n}\n","import { promises as fs, realpathSync } from 'node:fs'\nimport { dirname, resolve } from 'node:path'\nimport { pathToFileURL } from 'node:url'\nimport { generateDrizzleSchema } from '../codegen/generate'\nimport { loadConfig } from './load-config'\n\nasync function main(args: string[]): Promise<number> {\n try {\n if (args.length === 0 || args[0] === 'help' || args[0] === '--help' || args[0] === '-h') {\n console.log('Usage: nanoka generate [--config <path>] [--output <path>]')\n console.log('')\n console.log('Options:')\n console.log(' --config <path> Path to nanoka.config.ts (default: ./nanoka.config.ts)')\n console.log(' --output <path> Output file path (overrides config.output)')\n return 0\n }\n\n if (args[0] !== 'generate') {\n console.error(`Error: unknown command '${args[0]}'`)\n console.error('Usage: nanoka generate [--config <path>] [--output <path>]')\n return 1\n }\n\n let configPath: string = './nanoka.config.ts'\n let outputPath: string | undefined\n\n let i = 1\n while (i < args.length) {\n if (args[i] === '--config' && i + 1 < args.length) {\n configPath = args[i + 1]!\n i += 2\n } else if (args[i] === '--output' && i + 1 < args.length) {\n outputPath = args[i + 1]!\n i += 2\n } else {\n console.error(`Error: unknown option '${args[i]}'`)\n return 1\n }\n }\n\n const absoluteConfigPath = resolve(process.cwd(), configPath)\n const config = await loadConfig(absoluteConfigPath)\n\n const finalOutputPath = outputPath ?? config.output ?? './drizzle/schema.ts'\n const absoluteOutputPath = resolve(process.cwd(), finalOutputPath)\n\n const schema = generateDrizzleSchema(config.models)\n\n await fs.mkdir(dirname(absoluteOutputPath), { recursive: true })\n await fs.writeFile(absoluteOutputPath, schema, 'utf-8')\n\n console.log(`✓ Generated ${absoluteOutputPath}`)\n return 0\n } catch (error) {\n if (error instanceof Error) {\n console.error(`Error: ${error.message}`)\n } else {\n console.error('Unknown error:', error)\n }\n return 1\n }\n}\n\n// Entry-point detection: compare realpath-resolved argv[1] (which may be a\n// symlink under pnpm/npm bin shims) with this module's URL. A naive\n// `file://${argv[1]}` comparison fails whenever the package is installed via\n// pnpm because node_modules entries are symlinks into the .pnpm store while\n// import.meta.url is always the resolved path.\nfunction isCliEntrypoint(): boolean {\n const argv1 = process.argv[1]\n if (!argv1) return false\n try {\n return pathToFileURL(realpathSync(argv1)).href === import.meta.url\n } catch {\n return false\n }\n}\n\nif (isCliEntrypoint()) {\n main(process.argv.slice(2)).then((code) => {\n process.exit(code)\n })\n}\n\nexport { main }\n"]}
|
package/dist/config.d.ts
CHANGED
|
@@ -4,11 +4,11 @@ import 'drizzle-orm/sqlite-core';
|
|
|
4
4
|
import 'zod';
|
|
5
5
|
|
|
6
6
|
interface ModelDef {
|
|
7
|
-
readonly
|
|
7
|
+
readonly name: string;
|
|
8
8
|
readonly fields: Record<string, Field<any, any, any>>;
|
|
9
9
|
}
|
|
10
10
|
interface NanokaConfig {
|
|
11
|
-
readonly
|
|
11
|
+
readonly output?: string | undefined;
|
|
12
12
|
readonly models: readonly ModelDef[];
|
|
13
13
|
}
|
|
14
14
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nanokajs/core",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Thin wrapper over Hono + Drizzle + Zod for Cloudflare Workers + D1. 80% automatic, 20% explicit.",
|
|
6
6
|
"author": "Eiichiro Iriguchi <eiichiro_iriguchi@a-1ro.dev>",
|