nomi-relay-cli 0.0.0-stage → 0.1.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.
package/README.md CHANGED
@@ -1,3 +1,40 @@
1
- # Temporary Holding Version
1
+ # nomi-relay-cli
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ The command line for Nomi Relay. It installs a `nomi-relay` command.
4
+
5
+ ```sh
6
+ npx nomi-relay-cli --help
7
+ # or
8
+ npm install -D nomi-relay-cli && npx nomi-relay --help
9
+ ```
10
+
11
+ ## Commands
12
+
13
+ | Command | What it does |
14
+ |---|---|
15
+ | `nomi-relay init` | Creates `nomi/backend.json`, `nomi/migrations/0001_init.sql` and `nomi/functions/` |
16
+ | `nomi-relay migrate new <name>` | Writes the next numbered migration, e.g. `0003_add_orders.sql` |
17
+ | `nomi-relay migrate lint` | Checks migrations before they're applied (exits 1 on problems, so it fits CI) |
18
+ | `nomi-relay migrate status` | Lists local migrations with their checksums |
19
+ | `nomi-relay functions new <name>` | Writes `nomi/functions/<name>.ts` from a starter |
20
+
21
+ `--dir <path>` points any command at another project folder.
22
+
23
+ ## What `migrate lint` checks
24
+
25
+ - **Row-level security.** Every `create table` needs `alter table … enable row level security`
26
+ in some migration, unless it's marked `-- nomi: public` on the line above.
27
+ - **Drops that lose data.** `drop table` and `alter table … drop column` need
28
+ `-- nomi: destructive` on the line above.
29
+ - **Staying inside the project.** No objects in other schemas (such as `nomi.*`), no schema,
30
+ role or database changes, no `set role` or `search_path`.
31
+
32
+ Relay runs the same checks, authoritatively, when it applies migrations; the CLI gives you
33
+ the answer before that.
34
+
35
+ ## Coming with the hosted Relay
36
+
37
+ `login`, `link`, `migrate apply`, `types`, `functions serve`, `functions deploy` and
38
+ `secrets set` are reserved and say so when called.
39
+
40
+ The app-side client is [`nomi-relay`](https://www.npmjs.com/package/nomi-relay).
package/dist/cli.js ADDED
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env node
2
+ import { EXIT_PROBLEMS, run } from './run.js';
3
+ run(process.argv.slice(2), { cwd: process.cwd(), out: console.log, err: console.error }).then((code) => process.exit(code), (error) => {
4
+ console.error(error);
5
+ process.exit(EXIT_PROBLEMS);
6
+ });
7
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,aAAa,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AAE9C,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE,EAAE,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE,GAAG,EAAE,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC,IAAI,CAC3F,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAC5B,CAAC,KAAK,EAAE,EAAE;IACR,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IACrB,OAAO,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;AAC9B,CAAC,CACF,CAAC"}
package/dist/lint.js ADDED
@@ -0,0 +1,83 @@
1
+ import { splitStatements, unquote } from './sql.js';
2
+ /** Marks a table that's meant to be readable without row-level security. */
3
+ export const PUBLIC_MARKER = 'nomi: public';
4
+ /** Marks a drop that's meant to lose data. */
5
+ export const DESTRUCTIVE_MARKER = 'nomi: destructive';
6
+ /** The only schema a project's migrations may create things in by name; unqualified names land there too. */
7
+ const OWN_SCHEMA = 'public';
8
+ const IDENT = String.raw `(?:"[^"]+"|[a-z_][a-z0-9_$]*)`;
9
+ const QUALIFIED = String.raw `(?:(${IDENT})\.)?(${IDENT})`;
10
+ const CREATE_TABLE = new RegExp(String.raw `^create (?:unlogged )?table (?:if not exists )?${QUALIFIED}`);
11
+ const ENABLE_RLS = new RegExp(String.raw `^alter table (?:if exists )?(?:only )?${QUALIFIED} enable row level security`);
12
+ const DROP_TABLE = /^drop table /;
13
+ const DROP_COLUMN = /^alter table .* drop (?:column )?(?!constraint\b|default\b|not null\b|identity\b|expression\b)/;
14
+ const QUALIFIED_DDL = new RegExp(String.raw `^(?:create|alter|drop) (?:or replace )?(?:unique )?(?:unlogged )?(?:materialized )?` +
15
+ String.raw `(?:table|view|function|procedure|index|type|trigger|sequence|domain|aggregate) ` +
16
+ String.raw `(?:if (?:not )?exists )?(?:concurrently )?(?:only )?(${IDENT})\.`);
17
+ const QUALIFIED_ON = new RegExp(String.raw `^create (?:policy|trigger|(?:unique )?index) .*? on (?:only )?(${IDENT})\.${IDENT}`);
18
+ const FORBIDDEN = [
19
+ { pattern: /^(?:create|alter|drop) schema\b/, what: 'creating, changing or dropping a schema' },
20
+ { pattern: /^(?:create|alter|drop) (?:role|user|group)\b/, what: 'managing database roles' },
21
+ { pattern: /^(?:create|alter|drop) database\b/, what: 'managing databases' },
22
+ { pattern: /^(?:set|reset) (?:local )?(?:role|session authorization|search_path)\b/, what: 'switching role or search_path' },
23
+ { pattern: /^alter system\b/, what: 'changing server settings' },
24
+ { pattern: /^(?:create|alter|drop) event trigger\b/, what: 'event triggers' },
25
+ { pattern: /^copy .* (?:from|to) program\b/, what: 'running programs on the server' }
26
+ ];
27
+ function hasMarker(statement, marker) {
28
+ return statement.comments.toLowerCase().includes(marker);
29
+ }
30
+ /**
31
+ * Checks migrations the way Relay does before applying them. This is an early check for the
32
+ * editor and CI; Relay runs the authoritative one.
33
+ */
34
+ export function lintMigrations(files) {
35
+ const issues = [];
36
+ const parsed = files.map((file) => ({ file, statements: splitStatements(file.sql) }));
37
+ const rlsEnabled = new Set();
38
+ for (const { statements } of parsed) {
39
+ for (const statement of statements) {
40
+ const match = ENABLE_RLS.exec(statement.code);
41
+ if (match)
42
+ rlsEnabled.add(unquote(match[2]));
43
+ }
44
+ }
45
+ for (const { file, statements } of parsed) {
46
+ for (const statement of statements) {
47
+ const at = { file: file.name, line: statement.line };
48
+ const table = CREATE_TABLE.exec(statement.code);
49
+ if (table) {
50
+ const name = unquote(table[2]);
51
+ if (!rlsEnabled.has(name) && !hasMarker(statement, PUBLIC_MARKER)) {
52
+ issues.push({
53
+ ...at,
54
+ rule: 'row-level-security',
55
+ message: `table "${name}" has no row-level security: add "alter table ${name} enable row level security;" and policies, or mark it "-- ${PUBLIC_MARKER}"`
56
+ });
57
+ }
58
+ }
59
+ if ((DROP_TABLE.test(statement.code) || DROP_COLUMN.test(statement.code)) && !hasMarker(statement, DESTRUCTIVE_MARKER)) {
60
+ issues.push({
61
+ ...at,
62
+ rule: 'destructive',
63
+ message: `this drops data: mark it "-- ${DESTRUCTIVE_MARKER}" if that's intended`
64
+ });
65
+ }
66
+ const schema = QUALIFIED_DDL.exec(statement.code)?.[1] ?? QUALIFIED_ON.exec(statement.code)?.[1];
67
+ if (schema && unquote(schema) !== OWN_SCHEMA) {
68
+ issues.push({
69
+ ...at,
70
+ rule: 'outside-project',
71
+ message: `migrations may only define things in the project's own schema, not "${unquote(schema)}"`
72
+ });
73
+ }
74
+ for (const { pattern, what } of FORBIDDEN) {
75
+ if (pattern.test(statement.code)) {
76
+ issues.push({ ...at, rule: 'outside-project', message: `migrations can't do ${what}` });
77
+ }
78
+ }
79
+ }
80
+ }
81
+ return issues;
82
+ }
83
+ //# sourceMappingURL=lint.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lint.js","sourceRoot":"","sources":["../src/lint.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,53 @@
1
+ import { createHash } from 'node:crypto';
2
+ import { readdir, readFile } from 'node:fs/promises';
3
+ import { join } from 'node:path';
4
+ /** Migrations are `0001_init.sql`, `0002_orders.sql`…: a zero-padded number, then a name. */
5
+ export const MIGRATION_NAME = /^(\d{4,})_([a-z0-9_]+)\.sql$/;
6
+ const NUMBER_WIDTH = 4;
7
+ export function checksum(sql) {
8
+ return createHash('sha256').update(sql).digest('hex');
9
+ }
10
+ export async function readMigrations(dir) {
11
+ let entries;
12
+ try {
13
+ entries = await readdir(dir);
14
+ }
15
+ catch (error) {
16
+ if (error.code === 'ENOENT')
17
+ return { migrations: [], problems: [] };
18
+ throw error;
19
+ }
20
+ const migrations = [];
21
+ const problems = [];
22
+ for (const file of entries.sort()) {
23
+ if (file.startsWith('.'))
24
+ continue;
25
+ const match = MIGRATION_NAME.exec(file);
26
+ if (!match) {
27
+ problems.push({ file, message: 'not a migration name: use 0001_name.sql (lowercase letters, digits, underscores)' });
28
+ continue;
29
+ }
30
+ const sql = await readFile(join(dir, file), 'utf8');
31
+ migrations.push({ number: Number(match[1]), name: match[2], file, sql, checksum: checksum(sql) });
32
+ }
33
+ migrations.sort((a, b) => a.number - b.number);
34
+ for (let i = 1; i < migrations.length; i++) {
35
+ if (migrations[i].number === migrations[i - 1].number) {
36
+ problems.push({ file: migrations[i].file, message: `has the same number as ${migrations[i - 1].file}` });
37
+ }
38
+ }
39
+ return { migrations, problems };
40
+ }
41
+ /** `Add Orders!` → `add_orders`. */
42
+ export function slug(name) {
43
+ return name
44
+ .trim()
45
+ .toLowerCase()
46
+ .replace(/[^a-z0-9]+/g, '_')
47
+ .replace(/^_+|_+$/g, '');
48
+ }
49
+ export function nextMigrationFile(existing, name) {
50
+ const number = (existing.at(-1)?.number ?? 0) + 1;
51
+ return `${String(number).padStart(NUMBER_WIDTH, '0')}_${slug(name)}.sql`;
52
+ }
53
+ //# sourceMappingURL=migrations.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"migrations.js","sourceRoot":"","sources":["../src/migrations.ts"],"names":[],"mappings":"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"}
package/dist/run.js ADDED
@@ -0,0 +1,164 @@
1
+ import { access, mkdir, readFile, writeFile } from 'node:fs/promises';
2
+ import { dirname, join, relative, resolve } from 'node:path';
3
+ import { fileURLToPath } from 'node:url';
4
+ import { parseArgs } from 'node:util';
5
+ import { lintMigrations } from './lint.js';
6
+ import { nextMigrationFile, readMigrations, slug } from './migrations.js';
7
+ const EXIT_OK = 0;
8
+ export const EXIT_PROBLEMS = 1;
9
+ const EXIT_USAGE = 2;
10
+ /** Shown checksums are cut to this many characters; the full one is what Relay compares. */
11
+ const SHORT_CHECKSUM_LENGTH = 12;
12
+ const HELP = `nomi-relay: command line for Nomi Relay
13
+
14
+ Usage: nomi-relay <command> [options]
15
+
16
+ Commands
17
+ init Create nomi/backend.json, nomi/migrations and nomi/functions
18
+ migrate new <name> Write the next numbered migration, e.g. 0003_add_orders.sql
19
+ migrate lint Check migrations for missing row-level security, unmarked drops
20
+ and statements that reach outside the project
21
+ migrate status List local migrations with their checksums
22
+ functions new <name> Write nomi/functions/<name>.ts from a starter
23
+
24
+ Coming with the hosted Relay
25
+ login, link, migrate apply, types, functions serve, functions deploy, secrets set
26
+
27
+ Options
28
+ --dir <path> Project folder (default: the current folder)
29
+ -h, --help Show this help
30
+ -v, --version Show the version`;
31
+ const COMING_SOON = new Set(['login', 'link', 'types', 'secrets', 'migrate apply', 'functions serve', 'functions deploy']);
32
+ const BACKEND_JSON = {
33
+ auth: { methods: ['email_code'], redirect_urls: [] },
34
+ storage: { buckets: [] },
35
+ realtime: [],
36
+ functions: {}
37
+ };
38
+ const FIRST_MIGRATION = `-- Plain SQL, applied once, in order. Never edit a migration after it's applied: add a new one.
39
+ -- Every table needs row-level security (or a "-- nomi: public" marker).
40
+ `;
41
+ function functionStarter(name) {
42
+ return `import { defineFunction } from 'nomi-relay/functions';
43
+
44
+ // Called at /functions/${name}, or nomi.functions.invoke('${name}', { body }).
45
+ export default defineFunction(async (req, ctx) => {
46
+ if (!ctx.user) return new Response('sign in first', { status: 401 });
47
+ const body = req.method === 'GET' ? null : await req.json();
48
+ return Response.json({ ok: true, user: ctx.user.id, body });
49
+ });
50
+ `;
51
+ }
52
+ async function exists(path) {
53
+ try {
54
+ await access(path);
55
+ return true;
56
+ }
57
+ catch {
58
+ return false;
59
+ }
60
+ }
61
+ async function writeNew(path, content, io) {
62
+ if (await exists(path)) {
63
+ io.err(`${relative(io.cwd, path)} already exists; leaving it as it is`);
64
+ return false;
65
+ }
66
+ await mkdir(dirname(path), { recursive: true });
67
+ await writeFile(path, content);
68
+ io.out(`created ${relative(io.cwd, path)}`);
69
+ return true;
70
+ }
71
+ async function version() {
72
+ const pkg = JSON.parse(await readFile(join(dirname(fileURLToPath(import.meta.url)), '..', 'package.json'), 'utf8'));
73
+ return String(pkg.version);
74
+ }
75
+ export async function run(argv, io) {
76
+ let parsed;
77
+ try {
78
+ parsed = parseArgs({
79
+ args: argv,
80
+ allowPositionals: true,
81
+ options: {
82
+ dir: { type: 'string' },
83
+ help: { type: 'boolean', short: 'h' },
84
+ version: { type: 'boolean', short: 'v' }
85
+ }
86
+ });
87
+ }
88
+ catch (error) {
89
+ io.err(error.message);
90
+ return EXIT_USAGE;
91
+ }
92
+ const { values, positionals } = parsed;
93
+ if (values.version) {
94
+ io.out(await version());
95
+ return EXIT_OK;
96
+ }
97
+ const [command, sub, ...rest] = positionals;
98
+ if (values.help || !command || command === 'help') {
99
+ io.out(HELP);
100
+ return command || values.help ? EXIT_OK : EXIT_USAGE;
101
+ }
102
+ const root = resolve(io.cwd, values.dir ?? '.');
103
+ const nomiDir = join(root, 'nomi');
104
+ const migrationsDir = join(nomiDir, 'migrations');
105
+ const functionsDir = join(nomiDir, 'functions');
106
+ if (COMING_SOON.has(command) || COMING_SOON.has(`${command} ${sub}`)) {
107
+ io.err(`"${[command, sub].filter(Boolean).join(' ')}" needs the hosted Nomi Relay and isn't available in this release yet.`);
108
+ return EXIT_USAGE;
109
+ }
110
+ switch (`${command} ${sub ?? ''}`.trim()) {
111
+ case 'init': {
112
+ await writeNew(join(nomiDir, 'backend.json'), JSON.stringify(BACKEND_JSON, null, 2) + '\n', io);
113
+ const { migrations } = await readMigrations(migrationsDir);
114
+ if (migrations.length === 0)
115
+ await writeNew(join(migrationsDir, '0001_init.sql'), FIRST_MIGRATION, io);
116
+ await mkdir(functionsDir, { recursive: true });
117
+ return EXIT_OK;
118
+ }
119
+ case 'migrate new': {
120
+ const name = rest.join(' ');
121
+ if (!slug(name)) {
122
+ io.err('Usage: nomi-relay migrate new <name>');
123
+ return EXIT_USAGE;
124
+ }
125
+ const { migrations } = await readMigrations(migrationsDir);
126
+ await writeNew(join(migrationsDir, nextMigrationFile(migrations, name)), '', io);
127
+ return EXIT_OK;
128
+ }
129
+ case 'migrate lint': {
130
+ const { migrations, problems } = await readMigrations(migrationsDir);
131
+ for (const problem of problems)
132
+ io.err(`${problem.file}: ${problem.message}`);
133
+ const issues = lintMigrations(migrations.map((migration) => ({ name: migration.file, sql: migration.sql })));
134
+ for (const issue of issues)
135
+ io.err(`${issue.file}:${issue.line} ${issue.rule} ${issue.message}`);
136
+ const count = problems.length + issues.length;
137
+ io.out(count === 0 ? `${migrations.length} migration(s) look good` : `${count} problem(s) found`);
138
+ return count === 0 ? EXIT_OK : EXIT_PROBLEMS;
139
+ }
140
+ case 'migrate status': {
141
+ const { migrations, problems } = await readMigrations(migrationsDir);
142
+ if (migrations.length === 0)
143
+ io.out('no migrations yet: run "nomi-relay migrate new <name>"');
144
+ for (const migration of migrations)
145
+ io.out(`${migration.file} ${migration.checksum.slice(0, SHORT_CHECKSUM_LENGTH)}`);
146
+ for (const problem of problems)
147
+ io.err(`${problem.file}: ${problem.message}`);
148
+ return problems.length === 0 ? EXIT_OK : EXIT_PROBLEMS;
149
+ }
150
+ case 'functions new': {
151
+ const name = slug(rest.join(' ')).replace(/_/g, '-');
152
+ if (!name) {
153
+ io.err('Usage: nomi-relay functions new <name>');
154
+ return EXIT_USAGE;
155
+ }
156
+ const created = await writeNew(join(functionsDir, `${name}.ts`), functionStarter(name), io);
157
+ return created ? EXIT_OK : EXIT_PROBLEMS;
158
+ }
159
+ default:
160
+ io.err(`Unknown command "${positionals.join(' ')}". Run "nomi-relay --help".`);
161
+ return EXIT_USAGE;
162
+ }
163
+ }
164
+ //# sourceMappingURL=run.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run.js","sourceRoot":"","sources":["../src/run.ts"],"names":[],"mappings":"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"}
package/dist/sql.js ADDED
@@ -0,0 +1,92 @@
1
+ /**
2
+ * Splits SQL into statements on `;`, skipping semicolons inside strings, quoted identifiers,
3
+ * dollar-quoted bodies (`$$ … $$`, `$fn$ … $fn$`) and comments.
4
+ */
5
+ export function splitStatements(sql) {
6
+ const statements = [];
7
+ let code = '';
8
+ let comments = '';
9
+ let line = 1;
10
+ let startLine = 0;
11
+ let i = 0;
12
+ const flush = () => {
13
+ const normalized = code.replace(/\s+/g, ' ').trim().toLowerCase();
14
+ if (normalized)
15
+ statements.push({ code: normalized, comments, line: startLine || line });
16
+ code = '';
17
+ comments = '';
18
+ startLine = 0;
19
+ };
20
+ const markStart = () => {
21
+ if (!startLine)
22
+ startLine = line;
23
+ };
24
+ while (i < sql.length) {
25
+ const char = sql[i];
26
+ const next = sql[i + 1];
27
+ if (char === '\n')
28
+ line += 1;
29
+ if (char === '-' && next === '-') {
30
+ const end = sql.indexOf('\n', i);
31
+ const stop = end === -1 ? sql.length : end;
32
+ comments += sql.slice(i, stop) + '\n';
33
+ i = stop;
34
+ continue;
35
+ }
36
+ if (char === '/' && next === '*') {
37
+ const end = sql.indexOf('*/', i + 2);
38
+ const stop = end === -1 ? sql.length : end + 2;
39
+ const block = sql.slice(i, stop);
40
+ comments += block + '\n';
41
+ line += block.split('\n').length - 1;
42
+ i = stop;
43
+ code += ' ';
44
+ continue;
45
+ }
46
+ if (char === "'" || char === '"') {
47
+ markStart();
48
+ let j = i + 1;
49
+ while (j < sql.length) {
50
+ if (sql[j] === char && sql[j + 1] === char)
51
+ j += 2;
52
+ else if (sql[j] === char)
53
+ break;
54
+ else
55
+ j += 1;
56
+ }
57
+ const quoted = sql.slice(i, j + 1);
58
+ line += quoted.split('\n').length - 1;
59
+ // Keep quoted identifiers (they matter for names); blank out string contents.
60
+ code += char === '"' ? quoted : "''";
61
+ i = j + 1;
62
+ continue;
63
+ }
64
+ if (char === '$') {
65
+ const tag = /^\$[A-Za-z_]*\$/.exec(sql.slice(i))?.[0];
66
+ if (tag) {
67
+ markStart();
68
+ const end = sql.indexOf(tag, i + tag.length);
69
+ const stop = end === -1 ? sql.length : end + tag.length;
70
+ line += sql.slice(i, stop).split('\n').length - 1;
71
+ code += ' $body$ ';
72
+ i = stop;
73
+ continue;
74
+ }
75
+ }
76
+ if (char === ';') {
77
+ flush();
78
+ i += 1;
79
+ continue;
80
+ }
81
+ if (!/\s/.test(char))
82
+ markStart();
83
+ code += char;
84
+ i += 1;
85
+ }
86
+ flush();
87
+ return statements;
88
+ }
89
+ export function unquote(identifier) {
90
+ return identifier.replace(/^"|"$/g, '').toLowerCase();
91
+ }
92
+ //# sourceMappingURL=sql.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sql.js","sourceRoot":"","sources":["../src/sql.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,36 @@
1
1
  {
2
2
  "name": "nomi-relay-cli",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "0.1.1",
4
+ "description": "Command line for Nomi Relay: migrations, linting and functions.",
5
+ "type": "module",
6
+ "license": "MIT",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/triandamai/nomi-v2.git",
10
+ "directory": "relay/cli"
11
+ },
12
+ "keywords": [
13
+ "nomi",
14
+ "baas",
15
+ "migrations",
16
+ "cli"
17
+ ],
18
+ "bin": {
19
+ "nomi-relay": "dist/cli.js"
20
+ },
21
+ "files": [
22
+ "dist",
23
+ "README.md"
24
+ ],
25
+ "scripts": {
26
+ "build": "rm -rf dist && tsc -p tsconfig.build.json && chmod +x dist/cli.js",
27
+ "check": "tsc -p tsconfig.json --noEmit",
28
+ "test": "vitest run"
29
+ },
30
+ "engines": {
31
+ "node": ">=20"
32
+ },
33
+ "publishConfig": {
34
+ "access": "public"
35
+ }
36
+ }