@noy-db/create
Wizard + CLI tool for noy-db — scaffold a fresh Nuxt 4 + Pinia encrypted store, augment an existing Nuxt project, or run operational commands (add user, rotate keys, backup) from the command line.
Two bins ship in this package:
create— invoked bynpm create @noy-db. Fresh-project wizard OR in-place augmenter for an existing Nuxt 4 project, depending on where you run it.noy-db— ongoing CLI tool. Invoked viapnpm exec noy-db <cmd>ornpx noy-db <cmd>from inside a project. Five subcommands:add,add user,verify,rotate,backup.
create @noy-db — the wizard
The wizard auto-detects whether your current directory is an existing Nuxt 4 project:
- If
nuxt.config.{ts,js,mjs}and apackage.jsonlistingnuxtare both present, the wizard enters augment mode (patches the existing config in-place) - Otherwise it enters fresh mode (creates a new subdirectory with a full Nuxt 4 starter)
Fresh mode — new project
# In an empty directory
npm create @noy-db my-app
pnpm create @noy-db my-app
yarn create @noy-db my-app
bun create @noy-db my-appThe wizard asks at most 3 questions (project name, adapter, include sample data) and writes a complete Nuxt 4 + Pinia + @noy-db/in-nuxt starter into ./my-app/. Nothing is installed automatically — pick your package manager and run it yourself.
Skip the prompts with --yes:
npm create @noy-db my-app --yes
npm create @noy-db my-app --yes --adapter file --no-sample-dataAugment mode — existing Nuxt 4 project
# From inside an existing Nuxt 4 project root
cd ~/my-existing-app
npm create @noy-dbThe wizard will:
- Detect the existing
nuxt.config.tsvia the detection rule above - Prompt for the adapter (
browser/file/memory) - Patch the config in-memory via magicast:
- Add
'@noy-db/in-nuxt'to themodulesarray (creating the array if missing) - Add
noydb: { adapter, pinia: true, devtools: true }(only if not already present)
- Add
- Show a colored unified diff of the proposed changes
- Ask for confirmation (
y/n) — your config is only written if you confirm - Print the
pnpm add …command for the packages the patched config now depends on
Safe behaviors
- Idempotent: re-running on an already-augmented project is a no-op. You'll see
Nothing to do — already configured. - Preserves custom config: a pre-existing
noydb:key in your config is left untouched. The wizard only fills in what's missing. - Preserves unrelated keys, comments, and formatting: magicast walks a real Babel AST, not a regex.
- Unsupported shapes are rejected cleanly: if your config uses an opaque export (
export default someVar) or a non-arraymodulesfield, the wizard bails with a clear error message telling you to edit manually.
Dry run
Preview the diff without writing anything:
npm create @noy-db --dry-runPrints the unified diff and exits. Useful in CI, code review, and "what would this do to my config?" exploration.
Force fresh mode inside an existing project
If you're inside a Nuxt workspace but want to create a new sub-project rather than augment the root, pass --force-fresh:
cd ~/my-monorepo-with-nuxt
npm create @noy-db my-sub-app --force-freshAll flags
| Flag | Effect |
|---|---|
<project-name> (positional) |
Target directory name (fresh mode only) |
-y, --yes |
Skip every prompt; use defaults |
--adapter <name> |
Pre-select adapter: browser (default) / file / memory |
--no-sample-data |
(fresh mode) Skip the seed invoice records |
--dry-run |
(augment mode) Show the diff without writing |
--force-fresh |
Force fresh-project mode even in an existing Nuxt dir |
--lang <code> |
UI language: en (default) / th. Auto-detected from LC_ALL / LANG when omitted |
-h, --help |
Show usage and exit |
Languages
The wizard's prompts and notes are available in English (default) and Thai (th). Pick a language explicitly with --lang:
npm create @noy-db my-app --lang thWhen --lang is omitted, the wizard reads the standard POSIX locale env vars (LC_ALL, LC_MESSAGES, LANG, LANGUAGE) and auto-selects Thai when they point to a Thai locale, e.g.:
LANG=th_TH.UTF-8 npm create @noy-db my-appValidation errors and stack traces stay in English regardless of language so bug reports look the same in any locale.
noy-db — the CLI tool
The noy-db bin ships inside the same @noy-db/create package. Install it as a dev dependency and it's available via pnpm exec / npx:
pnpm add -D @noy-db/create
pnpm exec noy-db <command>Commands at a glance
| Command | Purpose |
|---|---|
noy-db add <collection> |
Scaffold a new Pinia store + Vue page for a collection |
noy-db add user <id> <role> |
Grant a new user access to a compartment |
noy-db verify |
In-memory crypto round-trip integrity check |
noy-db rotate |
Rotate DEKs for one or more collections |
noy-db backup <target> |
Dump a compartment to an encrypted file |
All commands that touch real compartments use the file adapter and require these flags:
--dir <path>— the data directory. Defaults to./data.--compartment <name>— the compartment (tenant) name. Required.--user <id>— your own user id in the compartment. Required.
You'll be prompted for your passphrase at runtime. Passphrases are never echoed, never logged, never written to disk, and cleared from process memory when the command exits.
noy-db add <collection>
Scaffolds two new files in your project:
app/stores/<name>.ts— adefineNoydbStore<Name>()call with a placeholder interfaceapp/pages/<name>.vue— a minimal CRUD page that lists, adds, and deletes records
pnpm exec noy-db add clientsRefuses 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.
noy-db add user <userId> <role> [options]
Grants a new user access to a compartment. Two passphrase prompts: yours (caller), then the new user's (with confirmation).
pnpm exec noy-db add user accountant-ann operator \
--dir ./data \
--compartment demo-co \
--user owner-alice \
--collections invoices:rw,clients:roRoles:
| Role | Permissions | Requires --collections? |
|---|---|---|
owner |
All collections, all operations | No |
admin |
All collections, all operations (except grant owner) | No |
viewer |
All collections, read-only | No |
operator |
Per-collection rw or ro explicitly |
Yes |
client |
Per-collection ro explicitly |
Yes |
For operator and client, the --collections flag is required. Format: name1:rw,name2:ro,name3:rw.
noy-db verify
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, @noy-db/to-memory, and your local Node version all agree on Web Crypto.
pnpm exec noy-db verify
# ✔ noy-db integrity check passed (126ms)Exits non-zero if anything diverges.
noy-db rotate [options]
Rotate the DEKs for one or more collections in a compartment. 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.
# Rotate every collection in the compartment
pnpm exec noy-db rotate --dir ./data --compartment demo-co --user owner-alice
# Rotate specific collections only
pnpm exec noy-db rotate --dir ./data --compartment demo-co --user owner-alice \
--collections invoices,clientsUse cases:
- Suspected key leak: an operator lost a laptop, a developer accidentally pasted a passphrase into a Slack channel, a USB stick went missing. Rotating is cheap insurance.
- Scheduled rotation: some compliance regimes require periodic key rotation regardless of exposure. This command makes rotation scriptable from cron or a CI job.
Different from noydb.revoke({ rotateKeys: true }) in that it doesn't kick anyone out — it's the "just rotate" path.
noy-db backup <target> [options]
Dump a compartment to a local file. The dump is a verifiable backup: it includes the chain head and the full _ledger / _ledger_deltas snapshots, so compartment.load() on the receiving side will reject any tampering between dump and restore.
pnpm exec noy-db backup ./backups/demo-2026-04-07.json \
--dir ./data --compartment demo-co --user owner-aliceTarget paths:
- Plain filesystem path —
./backups/demo.jsonor/absolute/path.json file://URI —file:///absolute/path.jsonorfile://./relative.json
Parent directories are created on demand, so ./backups/2026/04/demo.json works even if ./backups/2026/04/ doesn't exist yet.
Unsupported schemes (s3://, https://, etc.) are rejected before the passphrase prompt so a typo doesn't waste a passphrase entry.
noy-db help
Prints the full usage message for all subcommands.
Security invariants
Every command that touches real compartments follows these rules:
- Passphrase via
@clack/promptspassword()— never echoes to the terminal, never logged. - Passphrase never leaves the local closure — no file writes, no error messages, no telemetry.
- Ctrl-C at the prompt aborts before any I/O happens — cancelling doesn't leave the system in a half-mutated state.
finally { db.close() }— KEK is cleared from process memory on exit, success or failure.- Unsupported backup schemes are rejected before the prompt — a typo doesn't waste a passphrase entry.
What's in the fresh-project template
my-app/
├── nuxt.config.ts ← @noy-db/in-nuxt wired up with your chosen adapter
├── package.json ← @noy-db/* deps at ^0.5.0
├── tsconfig.json
├── README.md
├── .gitignore
└── app/
├── app.vue
├── stores/
│ └── invoices.ts ← defineNoydbStore<Invoice>
└── pages/
├── index.vue
└── invoices.vue ← CRUD page with reactive query DSL
Everything stored is encrypted with AES-256-GCM before it touches the adapter. The adapter only ever sees ciphertext.
Deferred to a future release
These are explicit non-goals:
- Thai i18n of the wizard prompts (#36)
- Non-Nuxt templates — no Vite/Vue standalone, no Electron, no vanilla (#39)
noy-db seed— needs a design decision about how seed scripts authenticate- S3 backup targets — would bundle
@aws-sdkinto this package and break the zero-runtime-deps story; lives in a companion package instead noy-db restore <file>— paired with the existingcompartment.load()+ integrity check; deferred so it can be designed alongside future identity/session work
Open an issue if you need one of these sooner.
License
MIT