create-noy-db 0.9.0 → 0.10.0-pre.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 +34 -23
- package/dist/bin/create.js +41 -33
- package/dist/bin/create.js.map +1 -1
- package/dist/bin/noy-db.d.ts +57 -0
- package/dist/bin/noy-db.js +1725 -56
- package/dist/bin/noy-db.js.map +1 -1
- package/dist/index.d.ts +278 -4
- package/dist/index.js +1617 -131
- package/dist/index.js.map +1 -1
- package/package.json +20 -10
- package/templates/catalog.json +651 -0
- package/templates/electron/README.md +3 -3
- package/templates/minimal/README.md +35 -0
- package/templates/minimal/_gitignore +29 -0
- package/templates/minimal/index.html +20 -0
- package/templates/minimal/package.json +21 -0
- package/templates/minimal/src/main.ts +47 -0
- package/templates/minimal/tsconfig.json +17 -0
- package/templates/minimal/vite.config.ts +10 -0
- package/templates/nuxt-default/README.md +4 -5
- package/templates/vanilla/README.md +3 -4
- package/templates/vite-vue/README.md +3 -4
package/README.md
CHANGED
|
@@ -26,7 +26,7 @@ yarn create noy-db my-app
|
|
|
26
26
|
bun create noy-db my-app
|
|
27
27
|
```
|
|
28
28
|
|
|
29
|
-
The wizard asks at most
|
|
29
|
+
The wizard asks at most 4 questions — project name, adapter, sample data, and starter template — then writes a complete starter into `./my-app/`. Nothing is installed automatically: pick your package manager and run it yourself (the wizard closes by printing `cd <project>`, `pnpm install`, `pnpm dev`).
|
|
30
30
|
|
|
31
31
|
Four starter templates ship in the package:
|
|
32
32
|
|
|
@@ -34,7 +34,8 @@ Four starter templates ship in the package:
|
|
|
34
34
|
|---|---|---|
|
|
35
35
|
| `nuxt-default` | Nuxt 4 + Pinia | SSR + file-based routing — **the default** |
|
|
36
36
|
| `vite-vue` | Vite + Vue 3 + Pinia | Client-side SPA, shorter install graph |
|
|
37
|
-
| `
|
|
37
|
+
| `minimal` | Vite + TypeScript, one file | **Default.** hub + browser storage, put/get; add more with `noy-db add` |
|
|
38
|
+
| `vanilla` | Vite + TypeScript | No framework, an invoice-table UI |
|
|
38
39
|
| `electron` | Electron + Vue 3 | Desktop app with the `to-file` adapter — USB workflow |
|
|
39
40
|
|
|
40
41
|
Skip the prompts with `--yes`:
|
|
@@ -120,9 +121,9 @@ Validation errors and stack traces stay in English regardless of language so bug
|
|
|
120
121
|
|
|
121
122
|
---
|
|
122
123
|
|
|
123
|
-
## `noy-db` — the
|
|
124
|
+
## `noy-db` — the one command line
|
|
124
125
|
|
|
125
|
-
The `noy-db` bin ships inside the same `create-noy-db` package. Install it as a dev dependency and it's available via `pnpm exec` / `npx`:
|
|
126
|
+
The `noy-db` bin ships inside the same `create-noy-db` package; it is the only CLI you need after `npm create noy-db` (the former `@noy-db/cli` is a redirect to it). Install it as a dev dependency and it's available via `pnpm exec` / `npx`:
|
|
126
127
|
|
|
127
128
|
```bash
|
|
128
129
|
pnpm add -D create-noy-db
|
|
@@ -134,16 +135,26 @@ pnpm exec noy-db <command>
|
|
|
134
135
|
| Command | Purpose |
|
|
135
136
|
|---|---|
|
|
136
137
|
| `noy-db add <collection>` | Scaffold a new Pinia store + Vue page for a collection |
|
|
137
|
-
| `noy-db add
|
|
138
|
-
| `noy-db
|
|
139
|
-
| `noy-db
|
|
140
|
-
| `noy-db
|
|
141
|
-
|
|
142
|
-
|
|
138
|
+
| `noy-db user add <id> <role>` | Grant a new user access to a vault |
|
|
139
|
+
| `noy-db user rotate` | Rotate DEKs for one or more collections |
|
|
140
|
+
| `noy-db backup <target>` | Dump a vault to an encrypted file |
|
|
141
|
+
| `noy-db doctor crypto` | In-memory crypto round-trip check |
|
|
142
|
+
| `noy-db pod inspect <file.noydb>` | Print a pod's header — no secret needed |
|
|
143
|
+
| `noy-db pod verify <file.noydb>` | Verify a pod's integrity — no secret needed |
|
|
144
|
+
| `noy-db describe <file.noydb>` | YAML/JSON schema audit of a pod |
|
|
145
|
+
| `noy-db config validate <file>` | Sanity-check a `NoydbOptions` file |
|
|
146
|
+
| `noy-db config scaffold --profile=<id>` | Topology skeleton to stdout, `.env` template to stderr |
|
|
147
|
+
| `noy-db config profiles` | List the ten topology profiles |
|
|
148
|
+
| `noy-db monitor <file>` | Live store metrics (the config's store must be metered) |
|
|
149
|
+
| `noy-db inspect <file> --vault=<v>` | Terminal inspector — uses `@noy-db/in-devtools-tui` when installed |
|
|
150
|
+
|
|
151
|
+
The old spellings `add user`, `rotate` and `verify` still work and print the new one.
|
|
152
|
+
|
|
153
|
+
Commands that touch a real vault use the **file adapter** and take these flags:
|
|
143
154
|
|
|
144
155
|
- `--dir <path>` — the data directory. Defaults to `./data`.
|
|
145
|
-
- `--
|
|
146
|
-
- `--user <id>` — your own user id in the
|
|
156
|
+
- `--vault <name>` — the vault (tenant) name. Required.
|
|
157
|
+
- `--user <id>` — your own user id in the vault. Required.
|
|
147
158
|
|
|
148
159
|
You'll be prompted for your secret at runtime. Secrets are never echoed, never logged, never written to disk, and cleared from process memory when the command exits.
|
|
149
160
|
|
|
@@ -160,14 +171,14 @@ pnpm exec noy-db add clients
|
|
|
160
171
|
|
|
161
172
|
Refuses to overwrite existing files — if either target already exists, the command exits non-zero without touching anything. There's no `--force` flag; delete the old files manually if you want to regenerate.
|
|
162
173
|
|
|
163
|
-
### `noy-db add
|
|
174
|
+
### `noy-db user add <userId> <role> [options]`
|
|
164
175
|
|
|
165
|
-
Grants a new user access to a
|
|
176
|
+
Grants a new user access to a vault. Two secret prompts: yours (caller), then the new user's (with confirmation).
|
|
166
177
|
|
|
167
178
|
```bash
|
|
168
|
-
pnpm exec noy-db add
|
|
179
|
+
pnpm exec noy-db user add accountant-ann operator \
|
|
169
180
|
--dir ./data \
|
|
170
|
-
--
|
|
181
|
+
--vault demo-co \
|
|
171
182
|
--user owner-alice \
|
|
172
183
|
--collections invoices:rw,clients:ro
|
|
173
184
|
```
|
|
@@ -184,27 +195,27 @@ Roles:
|
|
|
184
195
|
|
|
185
196
|
For `operator` and `client`, the `--collections` flag is required. Format: `name1:rw,name2:ro,name3:rw`.
|
|
186
197
|
|
|
187
|
-
### `noy-db
|
|
198
|
+
### `noy-db doctor crypto`
|
|
188
199
|
|
|
189
200
|
Runs an end-to-end crypto round-trip against an in-memory adapter. No real data is touched; the command creates a throwaway compartment, writes a record, reads it back, and verifies it decrypts correctly. Useful as a sanity check that `@noy-db/hub` and your local Node version agree on Web Crypto.
|
|
190
201
|
|
|
191
202
|
```bash
|
|
192
|
-
pnpm exec noy-db
|
|
203
|
+
pnpm exec noy-db doctor crypto
|
|
193
204
|
# ✔ noy-db integrity check passed (126ms)
|
|
194
205
|
```
|
|
195
206
|
|
|
196
207
|
Exits non-zero if anything diverges.
|
|
197
208
|
|
|
198
|
-
### `noy-db rotate [options]`
|
|
209
|
+
### `noy-db user rotate [options]`
|
|
199
210
|
|
|
200
|
-
Rotate the DEKs for one or more collections in a
|
|
211
|
+
Rotate the DEKs for one or more collections in a vault. Generates fresh keys, re-encrypts every record with the new keys, and re-wraps the new keys into every user's keyring. Nobody is revoked — everyone keeps their current permissions with fresh key material.
|
|
201
212
|
|
|
202
213
|
```bash
|
|
203
214
|
# Rotate every collection in the compartment
|
|
204
|
-
pnpm exec noy-db rotate --dir ./data --
|
|
215
|
+
pnpm exec noy-db user rotate --dir ./data --vault demo-co --user owner-alice
|
|
205
216
|
|
|
206
217
|
# Rotate specific collections only
|
|
207
|
-
pnpm exec noy-db rotate --dir ./data --
|
|
218
|
+
pnpm exec noy-db user rotate --dir ./data --vault demo-co --user owner-alice \
|
|
208
219
|
--collections invoices,clients
|
|
209
220
|
```
|
|
210
221
|
|
|
@@ -221,7 +232,7 @@ Dump a compartment to a local file. The dump is a **verifiable backup**: it incl
|
|
|
221
232
|
|
|
222
233
|
```bash
|
|
223
234
|
pnpm exec noy-db backup ./backups/demo-2026-04-07.json \
|
|
224
|
-
--dir ./data --
|
|
235
|
+
--dir ./data --vault demo-co --user owner-alice
|
|
225
236
|
```
|
|
226
237
|
|
|
227
238
|
Target paths:
|
package/dist/bin/create.js
CHANGED
|
@@ -14,7 +14,12 @@ import pc from "picocolors";
|
|
|
14
14
|
import { promises as fs } from "fs";
|
|
15
15
|
import path from "path";
|
|
16
16
|
import { fileURLToPath } from "url";
|
|
17
|
-
var NOYDB_IN_VERSION = "0.
|
|
17
|
+
var NOYDB_IN_VERSION = "0.10.0-pre.1";
|
|
18
|
+
var ADAPTER_PACKAGES = {
|
|
19
|
+
browser: "@noy-db/to-browser-idb",
|
|
20
|
+
file: "@noy-db/to-file",
|
|
21
|
+
memory: "@noy-db/hub"
|
|
22
|
+
};
|
|
18
23
|
async function renderTemplate(src, dest, tokens) {
|
|
19
24
|
const written = [];
|
|
20
25
|
await walk(src, dest, "", tokens, written);
|
|
@@ -247,7 +252,7 @@ function isProxyArray(value) {
|
|
|
247
252
|
|
|
248
253
|
// src/wizard/i18n/en.ts
|
|
249
254
|
var en = {
|
|
250
|
-
wizardIntro: "A wizard for noy-db \u2014 None Of Your DataBase.\nGenerates a fresh
|
|
255
|
+
wizardIntro: "A wizard for noy-db \u2014 None Of Your DataBase.\nGenerates a fresh encrypted-store starter \u2014 minimal by default, Nuxt and more on request.",
|
|
251
256
|
promptProjectName: "Project name",
|
|
252
257
|
promptProjectNamePlaceholder: "my-noy-db-app",
|
|
253
258
|
promptAdapter: "Storage adapter",
|
|
@@ -255,6 +260,7 @@ var en = {
|
|
|
255
260
|
adapterFileLabel: "file \u2014 JSON files on disk (Electron / Tauri / USB workflows)",
|
|
256
261
|
adapterMemoryLabel: "memory \u2014 no persistence (ideal for tests and demos)",
|
|
257
262
|
promptSampleData: "Include sample invoice records?",
|
|
263
|
+
promptRecommended: "Use the recommended setup? (hub + browser storage, no framework \u2014 add more later with `noy-db add`)",
|
|
258
264
|
freshNextStepsTitle: "Next steps",
|
|
259
265
|
freshOutroDone: "\u2714 Done \u2014 happy encrypting!",
|
|
260
266
|
augmentModeTitle: "Augment mode",
|
|
@@ -285,6 +291,7 @@ var th = {
|
|
|
285
291
|
adapterFileLabel: "file \u2014 \u0E44\u0E1F\u0E25\u0E4C JSON \u0E1A\u0E19\u0E14\u0E34\u0E2A\u0E01\u0E4C (Electron / Tauri / USB)",
|
|
286
292
|
adapterMemoryLabel: "memory \u2014 \u0E44\u0E21\u0E48\u0E1A\u0E31\u0E19\u0E17\u0E36\u0E01\u0E02\u0E49\u0E2D\u0E21\u0E39\u0E25 (\u0E40\u0E2B\u0E21\u0E32\u0E30\u0E2A\u0E33\u0E2B\u0E23\u0E31\u0E1A\u0E01\u0E32\u0E23\u0E17\u0E14\u0E2A\u0E2D\u0E1A\u0E41\u0E25\u0E30\u0E15\u0E31\u0E27\u0E2D\u0E22\u0E48\u0E32\u0E07)",
|
|
287
293
|
promptSampleData: "\u0E40\u0E1E\u0E34\u0E48\u0E21\u0E02\u0E49\u0E2D\u0E21\u0E39\u0E25\u0E15\u0E31\u0E27\u0E2D\u0E22\u0E48\u0E32\u0E07\u0E43\u0E1A\u0E41\u0E08\u0E49\u0E07\u0E2B\u0E19\u0E35\u0E49\u0E2B\u0E23\u0E37\u0E2D\u0E44\u0E21\u0E48?",
|
|
294
|
+
promptRecommended: "\u0E43\u0E0A\u0E49\u0E01\u0E32\u0E23\u0E15\u0E31\u0E49\u0E07\u0E04\u0E48\u0E32\u0E17\u0E35\u0E48\u0E41\u0E19\u0E30\u0E19\u0E33\u0E44\u0E2B\u0E21? (hub + \u0E1E\u0E37\u0E49\u0E19\u0E17\u0E35\u0E48\u0E40\u0E01\u0E47\u0E1A\u0E02\u0E49\u0E2D\u0E21\u0E39\u0E25\u0E43\u0E19\u0E40\u0E1A\u0E23\u0E32\u0E27\u0E4C\u0E40\u0E0B\u0E2D\u0E23\u0E4C \u0E44\u0E21\u0E48\u0E21\u0E35\u0E40\u0E1F\u0E23\u0E21\u0E40\u0E27\u0E34\u0E23\u0E4C\u0E01 \u2014 \u0E40\u0E1E\u0E34\u0E48\u0E21\u0E17\u0E35\u0E2B\u0E25\u0E31\u0E07\u0E44\u0E14\u0E49\u0E14\u0E49\u0E27\u0E22 `noy-db add`)",
|
|
288
295
|
freshNextStepsTitle: "\u0E02\u0E31\u0E49\u0E19\u0E15\u0E2D\u0E19\u0E16\u0E31\u0E14\u0E44\u0E1B",
|
|
289
296
|
freshOutroDone: "\u2714 \u0E40\u0E2A\u0E23\u0E47\u0E08\u0E40\u0E23\u0E35\u0E22\u0E1A\u0E23\u0E49\u0E2D\u0E22 \u2014 \u0E02\u0E2D\u0E43\u0E2B\u0E49\u0E2A\u0E19\u0E38\u0E01\u0E01\u0E31\u0E1A\u0E01\u0E32\u0E23\u0E40\u0E02\u0E49\u0E32\u0E23\u0E2B\u0E31\u0E2A!",
|
|
290
297
|
augmentModeTitle: "\u0E42\u0E2B\u0E21\u0E14\u0E40\u0E2A\u0E23\u0E34\u0E21\u0E42\u0E1B\u0E23\u0E40\u0E08\u0E01\u0E15\u0E4C\u0E40\u0E14\u0E34\u0E21",
|
|
@@ -392,15 +399,18 @@ async function runWizard(options = {}) {
|
|
|
392
399
|
}
|
|
393
400
|
async function runFreshMode(options, cwd, yes, msg) {
|
|
394
401
|
const projectName = yes ? options.projectName ?? "my-noy-db-app" : await promptProjectName(options.projectName, msg);
|
|
395
|
-
const
|
|
396
|
-
const
|
|
397
|
-
const template = yes ? options.template ?? "
|
|
398
|
-
const
|
|
402
|
+
const explicit = options.template !== void 0 || options.adapter !== void 0 || options.sampleData !== void 0;
|
|
403
|
+
const recommended = yes || explicit ? false : await promptRecommended(msg);
|
|
404
|
+
const template = recommended ? "minimal" : yes ? options.template ?? "minimal" : await promptTemplate(options.template, msg);
|
|
405
|
+
const adapter = recommended ? "browser" : yes ? options.adapter ?? "browser" : await promptAdapter(options.adapter, msg);
|
|
406
|
+
const sampleData = recommended || template === "minimal" ? options.sampleData ?? false : yes ? options.sampleData ?? true : await promptSampleData(options.sampleData, msg);
|
|
407
|
+
const syncAdapter = options.syncAdapter ?? "none";
|
|
399
408
|
const projectPath = path3.resolve(cwd, projectName);
|
|
400
409
|
await assertWritableTarget(projectPath);
|
|
401
410
|
const tokens = {
|
|
402
411
|
PROJECT_NAME: projectName,
|
|
403
412
|
ADAPTER: adapter,
|
|
413
|
+
ADAPTER_PACKAGE: ADAPTER_PACKAGES[adapter],
|
|
404
414
|
DEVTOOLS: "true",
|
|
405
415
|
SEED_INVOICES: sampleData ? JSON.stringify(DEFAULT_SEED, null, 2).replace(/\n/g, "\n ") : "[]",
|
|
406
416
|
NOYDB_VERSION: await ownVersion(),
|
|
@@ -412,16 +422,20 @@ async function runFreshMode(options, cwd, yes, msg) {
|
|
|
412
422
|
projectPath,
|
|
413
423
|
tokens
|
|
414
424
|
);
|
|
425
|
+
const nextSteps = [
|
|
426
|
+
`${pc.bold("cd")} ${projectName}`,
|
|
427
|
+
`${pc.bold("pnpm install")} ${pc.dim("(or npm/yarn/bun)")}`,
|
|
428
|
+
`${pc.bold("pnpm dev")}`
|
|
429
|
+
].join("\n");
|
|
415
430
|
if (!yes) {
|
|
416
|
-
p.note(
|
|
417
|
-
[
|
|
418
|
-
`${pc.bold("cd")} ${projectName}`,
|
|
419
|
-
`${pc.bold("pnpm install")} ${pc.dim("(or npm/yarn/bun)")}`,
|
|
420
|
-
`${pc.bold("pnpm dev")}`
|
|
421
|
-
].join("\n"),
|
|
422
|
-
msg.freshNextStepsTitle
|
|
423
|
-
);
|
|
431
|
+
p.note(nextSteps, msg.freshNextStepsTitle);
|
|
424
432
|
p.outro(pc.green(msg.freshOutroDone));
|
|
433
|
+
} else {
|
|
434
|
+
process.stdout.write(`${msg.freshOutroDone}
|
|
435
|
+
|
|
436
|
+
${msg.freshNextStepsTitle}
|
|
437
|
+
${nextSteps}
|
|
438
|
+
`);
|
|
425
439
|
}
|
|
426
440
|
return {
|
|
427
441
|
kind: "fresh",
|
|
@@ -591,22 +605,8 @@ async function promptAdapter(initial, msg) {
|
|
|
591
605
|
}
|
|
592
606
|
return result;
|
|
593
607
|
}
|
|
594
|
-
async function
|
|
595
|
-
|
|
596
|
-
const choices = ["none", "memory", "file", "browser"].filter(
|
|
597
|
-
(x) => x !== primary
|
|
598
|
-
);
|
|
599
|
-
const labels = {
|
|
600
|
-
none: "No sync \u2014 local only",
|
|
601
|
-
memory: "In-memory (testing / CI)",
|
|
602
|
-
file: "JSON files (USB / shared drive)",
|
|
603
|
-
browser: "IndexedDB (other tabs / PWAs)"
|
|
604
|
-
};
|
|
605
|
-
const result = await p.select({
|
|
606
|
-
message: "Add a sync target?",
|
|
607
|
-
options: choices.map((value) => ({ value, label: labels[value] })),
|
|
608
|
-
initialValue: "none"
|
|
609
|
-
});
|
|
608
|
+
async function promptRecommended(msg) {
|
|
609
|
+
const result = await p.confirm({ message: msg.promptRecommended, initialValue: true });
|
|
610
610
|
if (p.isCancel(result)) {
|
|
611
611
|
process.exit(1);
|
|
612
612
|
}
|
|
@@ -617,10 +617,15 @@ async function promptTemplate(initial, _msg) {
|
|
|
617
617
|
const result = await p.select({
|
|
618
618
|
message: "Pick a starter template",
|
|
619
619
|
options: [
|
|
620
|
+
{
|
|
621
|
+
value: "minimal",
|
|
622
|
+
label: "Minimal \u2014 Vite + TypeScript, one file",
|
|
623
|
+
hint: "hub + browser storage, put/get (recommended)"
|
|
624
|
+
},
|
|
620
625
|
{
|
|
621
626
|
value: "nuxt-default",
|
|
622
627
|
label: "Nuxt 4 + Pinia",
|
|
623
|
-
hint: "SSR + file-based routing
|
|
628
|
+
hint: "SSR + file-based routing"
|
|
624
629
|
},
|
|
625
630
|
{
|
|
626
631
|
value: "vite-vue",
|
|
@@ -638,7 +643,7 @@ async function promptTemplate(initial, _msg) {
|
|
|
638
643
|
hint: "Desktop app with to-file adapter \u2014 USB workflow"
|
|
639
644
|
}
|
|
640
645
|
],
|
|
641
|
-
initialValue: "
|
|
646
|
+
initialValue: "minimal"
|
|
642
647
|
});
|
|
643
648
|
if (p.isCancel(result)) {
|
|
644
649
|
process.exit(1);
|
|
@@ -673,6 +678,7 @@ async function assertWritableTarget(target) {
|
|
|
673
678
|
|
|
674
679
|
// src/wizard/types.ts
|
|
675
680
|
var WIZARD_TEMPLATES = [
|
|
681
|
+
"minimal",
|
|
676
682
|
"nuxt-default",
|
|
677
683
|
"vanilla",
|
|
678
684
|
"vite-vue",
|
|
@@ -773,7 +779,7 @@ The wizard auto-detects whether cwd is an existing Nuxt 4 project:
|
|
|
773
779
|
Options:
|
|
774
780
|
-y, --yes Skip prompts; use defaults for missing values
|
|
775
781
|
--adapter <name> Adapter: browser (default) | file | memory
|
|
776
|
-
--template <name> Template:
|
|
782
|
+
--template <name> Template: minimal (default) | nuxt-default | vite-vue | vanilla | electron
|
|
777
783
|
--sync <name> Sync target (multi-backend):
|
|
778
784
|
none (default) | memory | file | browser
|
|
779
785
|
--no-sample-data (fresh mode) Skip the seed invoice records
|
|
@@ -788,6 +794,8 @@ Examples:
|
|
|
788
794
|
# Fresh project in a new directory
|
|
789
795
|
npm create noy-db my-app
|
|
790
796
|
npm create noy-db my-app --yes --adapter file
|
|
797
|
+
npm create noy-db my-app --yes # minimal: hub + browser storage
|
|
798
|
+
npm create noy-db my-app --yes --template nuxt-default
|
|
791
799
|
npm create noy-db my-app --yes --template vite-vue
|
|
792
800
|
npm create noy-db my-app --yes --template vanilla
|
|
793
801
|
|