create-noy-db 0.1.0-pre.4

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.
Files changed (54) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +283 -0
  3. package/dist/bin/create.d.ts +1 -0
  4. package/dist/bin/create.js +815 -0
  5. package/dist/bin/create.js.map +1 -0
  6. package/dist/bin/noy-db.d.ts +1 -0
  7. package/dist/bin/noy-db.js +555 -0
  8. package/dist/bin/noy-db.js.map +1 -0
  9. package/dist/index.d.ts +697 -0
  10. package/dist/index.js +967 -0
  11. package/dist/index.js.map +1 -0
  12. package/package.json +74 -0
  13. package/templates/electron/README.md +85 -0
  14. package/templates/electron/_gitignore +31 -0
  15. package/templates/electron/electron/main.ts +51 -0
  16. package/templates/electron/index.html +12 -0
  17. package/templates/electron/package.json +32 -0
  18. package/templates/electron/src/App.vue +75 -0
  19. package/templates/electron/src/components/AddInvoiceForm.vue +39 -0
  20. package/templates/electron/src/components/InvoiceTable.vue +41 -0
  21. package/templates/electron/src/main.ts +48 -0
  22. package/templates/electron/src/stores/invoices.ts +35 -0
  23. package/templates/electron/src/style.css +119 -0
  24. package/templates/electron/tsconfig.json +19 -0
  25. package/templates/electron/vite.config.ts +21 -0
  26. package/templates/nuxt-default/README.md +38 -0
  27. package/templates/nuxt-default/_gitignore +32 -0
  28. package/templates/nuxt-default/app/app.vue +37 -0
  29. package/templates/nuxt-default/app/pages/index.vue +21 -0
  30. package/templates/nuxt-default/app/pages/invoices.vue +62 -0
  31. package/templates/nuxt-default/app/stores/invoices.ts +23 -0
  32. package/templates/nuxt-default/nuxt.config.ts +30 -0
  33. package/templates/nuxt-default/package.json +28 -0
  34. package/templates/nuxt-default/tsconfig.json +3 -0
  35. package/templates/vanilla/README.md +77 -0
  36. package/templates/vanilla/_gitignore +29 -0
  37. package/templates/vanilla/index.html +54 -0
  38. package/templates/vanilla/package.json +21 -0
  39. package/templates/vanilla/src/main.ts +153 -0
  40. package/templates/vanilla/src/style.css +127 -0
  41. package/templates/vanilla/tsconfig.json +17 -0
  42. package/templates/vanilla/vite.config.ts +10 -0
  43. package/templates/vite-vue/README.md +95 -0
  44. package/templates/vite-vue/_gitignore +29 -0
  45. package/templates/vite-vue/index.html +12 -0
  46. package/templates/vite-vue/package.json +28 -0
  47. package/templates/vite-vue/src/App.vue +75 -0
  48. package/templates/vite-vue/src/components/AddInvoiceForm.vue +39 -0
  49. package/templates/vite-vue/src/components/InvoiceTable.vue +41 -0
  50. package/templates/vite-vue/src/main.ts +55 -0
  51. package/templates/vite-vue/src/stores/invoices.ts +35 -0
  52. package/templates/vite-vue/src/style.css +119 -0
  53. package/templates/vite-vue/tsconfig.json +18 -0
  54. package/templates/vite-vue/vite.config.ts +12 -0
@@ -0,0 +1,41 @@
1
+ <script setup lang="ts">
2
+ import type { Invoice } from '../stores/invoices'
3
+
4
+ defineProps<{ invoices: Invoice[] }>()
5
+ const emit = defineEmits<{ (e: 'remove', id: string): void }>()
6
+ </script>
7
+
8
+ <template>
9
+ <section class="invoices">
10
+ <h2>Invoices</h2>
11
+ <table v-if="invoices.length > 0">
12
+ <thead>
13
+ <tr>
14
+ <th>ID</th>
15
+ <th>Client</th>
16
+ <th>Amount</th>
17
+ <th>Status</th>
18
+ <th>Issued</th>
19
+ <th></th>
20
+ </tr>
21
+ </thead>
22
+ <tbody>
23
+ <tr v-for="inv in invoices" :key="inv.id">
24
+ <td>{{ inv.id }}</td>
25
+ <td>{{ inv.client }}</td>
26
+ <td>{{ inv.amount.toLocaleString() }}</td>
27
+ <td>
28
+ <span :class="`status-pill status-${inv.status}`">{{ inv.status }}</span>
29
+ </td>
30
+ <td>{{ inv.issueDate }}</td>
31
+ <td>
32
+ <button class="danger" @click="emit('remove', inv.id)">×</button>
33
+ </td>
34
+ </tr>
35
+ </tbody>
36
+ </table>
37
+ <p v-else class="empty">
38
+ No invoices yet — add one above.
39
+ </p>
40
+ </section>
41
+ </template>
@@ -0,0 +1,48 @@
1
+ /**
2
+ * {{PROJECT_NAME}} — renderer bootstrap.
3
+ *
4
+ * Opens a Noydb vault backed by `@noy-db/to-file`, writing JSON to
5
+ * a directory under the user's data folder. Perfect for the
6
+ * USB-stick workflow: point the `dir` at an external mount and
7
+ * the vault travels with you.
8
+ */
9
+
10
+ import { createApp } from 'vue'
11
+ import { createPinia } from 'pinia'
12
+ import { createNoydb } from '@noy-db/hub'
13
+ import { jsonFile } from '@noy-db/to-file'
14
+ import { setActiveNoydb } from '@noy-db/in-pinia'
15
+ import path from 'node:path'
16
+ import App from './App.vue'
17
+ import './style.css'
18
+
19
+ async function bootstrap(): Promise<void> {
20
+ const pinia = createPinia()
21
+
22
+ // Default directory: `<userData>/{{PROJECT_NAME}}/vault`. For a
23
+ // USB-stick workflow, prompt the user for a path and use that
24
+ // instead (e.g. `/Volumes/USB/myapp`).
25
+ const baseDir = process.env.VITE_DEV_SERVER_URL
26
+ ? path.resolve('./.{{PROJECT_NAME}}-dev-vault')
27
+ : path.resolve(process.resourcesPath ?? '.', '{{PROJECT_NAME}}-vault')
28
+
29
+ const passphrase = prompt(
30
+ 'Enter passphrase for {{PROJECT_NAME}}\n\n' +
31
+ 'Master encryption key — lose it and the data is unrecoverable.',
32
+ ) ?? ''
33
+ if (passphrase.length === 0) {
34
+ document.body.textContent = 'Cancelled — reload to try again.'
35
+ return
36
+ }
37
+
38
+ const db = await createNoydb({
39
+ store: jsonFile({ dir: baseDir }),
40
+ user: 'owner',
41
+ secret: passphrase,
42
+ })
43
+ await db.openVault('demo')
44
+ setActiveNoydb(db)
45
+ createApp(App).use(pinia).mount('#app')
46
+ }
47
+
48
+ void bootstrap()
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Invoice store — reactive, encrypted, backed by a noy-db collection.
3
+ *
4
+ * `defineNoydbStore` wraps `defineStore` from Pinia and wires the
5
+ * store to a vault + collection. All writes encrypt before the
6
+ * IndexedDB adapter sees them; all reads decrypt into the reactive
7
+ * `items` array.
8
+ *
9
+ * Use from components:
10
+ * const invoices = useInvoices()
11
+ * await invoices.$ready
12
+ * await invoices.add(id, record)
13
+ * invoices.items // reactive array
14
+ * invoices.count // reactive getter
15
+ */
16
+ import { defineNoydbStore } from '@noy-db/in-pinia'
17
+
18
+ export interface Invoice {
19
+ id: string
20
+ client: string
21
+ amount: number
22
+ status: 'draft' | 'open' | 'paid' | 'overdue'
23
+ issueDate: string // ISO-8601
24
+ }
25
+
26
+ export const useInvoices = defineNoydbStore<Invoice>('invoices', {
27
+ vault: 'demo',
28
+ })
29
+
30
+ /** Optional seed set rendered on first load when the collection is empty. */
31
+ export const DEFAULT_INVOICES: Invoice[] = [
32
+ { id: 'inv-001', client: 'Acme Corp', amount: 1_200, status: 'paid', issueDate: '2026-01-15' },
33
+ { id: 'inv-002', client: 'Globex', amount: 2_400, status: 'open', issueDate: '2026-02-01' },
34
+ { id: 'inv-003', client: 'Initech', amount: 800, status: 'draft', issueDate: '2026-02-20' },
35
+ ]
@@ -0,0 +1,119 @@
1
+ :root {
2
+ color-scheme: light;
3
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
4
+ color: #1f2937;
5
+ background: #f9fafb;
6
+ }
7
+
8
+ * { box-sizing: border-box; }
9
+
10
+ body { margin: 0; padding: 1rem; }
11
+
12
+ .app { max-width: 900px; margin: 0 auto; }
13
+
14
+ header {
15
+ border-bottom: 1px solid #e5e7eb;
16
+ padding-bottom: 1rem;
17
+ margin-bottom: 1.5rem;
18
+ }
19
+
20
+ h1 { font-size: 1.5rem; margin: 0 0 0.5rem 0; }
21
+
22
+ .subtitle { color: #6b7280; font-size: 0.9rem; margin: 0; }
23
+
24
+ .loading {
25
+ background: white;
26
+ border: 1px solid #e5e7eb;
27
+ border-radius: 0.5rem;
28
+ padding: 1.5rem;
29
+ text-align: center;
30
+ color: #6b7280;
31
+ }
32
+
33
+ .summary {
34
+ display: flex;
35
+ gap: 1rem;
36
+ margin-bottom: 1.5rem;
37
+ }
38
+
39
+ .stat {
40
+ flex: 1;
41
+ background: white;
42
+ border: 1px solid #e5e7eb;
43
+ border-radius: 0.5rem;
44
+ padding: 1rem;
45
+ }
46
+ .stat .label { color: #6b7280; font-size: 0.75rem; text-transform: uppercase; }
47
+ .stat .value { font-size: 1.5rem; font-weight: 600; margin-top: 0.25rem; }
48
+
49
+ .add-form {
50
+ display: flex;
51
+ gap: 0.5rem;
52
+ margin-bottom: 1.5rem;
53
+ }
54
+ .add-form input, .add-form select {
55
+ padding: 0.5rem;
56
+ border: 1px solid #d1d5db;
57
+ border-radius: 0.25rem;
58
+ font-size: 0.875rem;
59
+ }
60
+ .add-form input[placeholder='Client name'] { flex: 2; }
61
+ .add-form input[type='number'] { flex: 1; }
62
+
63
+ button {
64
+ padding: 0.5rem 1rem;
65
+ border: 1px solid #2563eb;
66
+ background: #2563eb;
67
+ color: white;
68
+ border-radius: 0.25rem;
69
+ cursor: pointer;
70
+ font-size: 0.875rem;
71
+ }
72
+ button:hover { background: #1d4ed8; }
73
+ button.danger {
74
+ background: #dc2626;
75
+ border-color: #dc2626;
76
+ padding: 0.125rem 0.5rem;
77
+ }
78
+
79
+ .invoices h2 { font-size: 1.1rem; margin-top: 0; }
80
+
81
+ table {
82
+ width: 100%;
83
+ border-collapse: collapse;
84
+ background: white;
85
+ border: 1px solid #e5e7eb;
86
+ border-radius: 0.5rem;
87
+ overflow: hidden;
88
+ }
89
+ th, td {
90
+ padding: 0.5rem 0.75rem;
91
+ text-align: left;
92
+ border-bottom: 1px solid #e5e7eb;
93
+ font-size: 0.875rem;
94
+ }
95
+ th { background: #f3f4f6; font-weight: 600; }
96
+ tr:last-child td { border-bottom: 0; }
97
+
98
+ .empty { color: #6b7280; text-align: center; font-style: italic; padding: 1rem; }
99
+
100
+ .status-pill {
101
+ display: inline-block;
102
+ padding: 0.125rem 0.5rem;
103
+ border-radius: 0.25rem;
104
+ font-size: 0.75rem;
105
+ text-transform: uppercase;
106
+ font-weight: 600;
107
+ }
108
+ .status-draft { background: #f3f4f6; color: #4b5563; }
109
+ .status-open { background: #dbeafe; color: #1e40af; }
110
+ .status-paid { background: #d1fae5; color: #065f46; }
111
+ .status-overdue { background: #fee2e2; color: #b91c1c; }
112
+
113
+ footer {
114
+ margin-top: 3rem;
115
+ padding-top: 1rem;
116
+ border-top: 1px solid #e5e7eb;
117
+ color: #6b7280;
118
+ font-size: 0.85rem;
119
+ }
@@ -0,0 +1,19 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "module": "ESNext",
5
+ "moduleResolution": "Bundler",
6
+ "lib": ["ES2022", "DOM", "DOM.Iterable"],
7
+ "strict": true,
8
+ "noEmit": true,
9
+ "isolatedModules": true,
10
+ "resolveJsonModule": true,
11
+ "esModuleInterop": true,
12
+ "allowSyntheticDefaultImports": true,
13
+ "skipLibCheck": true,
14
+ "useDefineForClassFields": true,
15
+ "jsx": "preserve",
16
+ "types": ["node"]
17
+ },
18
+ "include": ["src/**/*.ts", "src/**/*.vue", "electron/**/*.ts"]
19
+ }
@@ -0,0 +1,21 @@
1
+ import { defineConfig } from 'vite'
2
+ import vue from '@vitejs/plugin-vue'
3
+ import electron from 'vite-plugin-electron'
4
+
5
+ export default defineConfig({
6
+ plugins: [
7
+ vue(),
8
+ electron({
9
+ entry: 'electron/main.ts',
10
+ vite: {
11
+ build: {
12
+ outDir: 'dist-electron',
13
+ target: 'es2022',
14
+ },
15
+ },
16
+ }),
17
+ ],
18
+ build: {
19
+ target: 'es2022',
20
+ },
21
+ })
@@ -0,0 +1,38 @@
1
+ # {{PROJECT_NAME}}
2
+
3
+ A Nuxt 4 + Pinia + [noy-db](https://github.com/vLannaAi/noy-db) starter, scaffolded by `create-noy-db`.
4
+
5
+ ## Stack
6
+
7
+ - **Nuxt 4** — fullstack Vue framework
8
+ - **Pinia** — reactive state management
9
+ - **@noy-db/in-nuxt** — Nuxt module for noy-db (auto-imports, SSR-safe runtime, devtools tab)
10
+ - **@noy-db/in-pinia** — `defineNoydbStore` — drop-in `defineStore` replacement that wires a Pinia store to an encrypted compartment + collection
11
+ - **@noy-db/{{ADAPTER}}** — storage adapter
12
+
13
+ Everything stored is encrypted with AES-256-GCM before it touches the adapter. The adapter only ever sees ciphertext.
14
+
15
+ ## Getting started
16
+
17
+ ```bash
18
+ pnpm install # or npm/yarn/bun
19
+ pnpm dev # nuxt dev on http://localhost:3000
20
+ pnpm build # production build
21
+ pnpm preview # preview the production build
22
+ pnpm verify # run the noy-db integrity check
23
+ ```
24
+
25
+ ## Adding a collection
26
+
27
+ ```bash
28
+ npx noy-db add clients
29
+ ```
30
+
31
+ This scaffolds `app/stores/clients.ts` and `app/pages/clients.vue`. Edit the generated `Client` interface to match your domain, then visit `/clients` in your dev server.
32
+
33
+ ## Documentation
34
+
35
+ - [noy-db getting started](https://github.com/vLannaAi/noy-db/blob/main/docs/quickstart.md)
36
+ - [End-user features](https://github.com/vLannaAi/noy-db/blob/main/docs/features.md)
37
+ - [Architecture](https://github.com/vLannaAi/noy-db/blob/main/docs/architecture.md)
38
+ - [Roadmap](https://github.com/vLannaAi/noy-db/blob/main/ROADMAP.md)
@@ -0,0 +1,32 @@
1
+ # Nuxt build outputs
2
+ .nuxt
3
+ .output
4
+ .data
5
+ .cache
6
+ .vite
7
+
8
+ # Node
9
+ node_modules
10
+ *.log
11
+ .npm
12
+
13
+ # Env files
14
+ .env
15
+ .env.local
16
+ .env.*.local
17
+
18
+ # OS
19
+ .DS_Store
20
+ Thumbs.db
21
+
22
+ # IDE
23
+ .vscode/*
24
+ !.vscode/extensions.json
25
+ .idea
26
+ *.suo
27
+ *.ntvs*
28
+ *.njsproj
29
+ *.sln
30
+
31
+ # Test coverage
32
+ coverage
@@ -0,0 +1,37 @@
1
+ <script setup lang="ts">
2
+ // Top-level layout. Add navigation here as you grow the app.
3
+ </script>
4
+
5
+ <template>
6
+ <div>
7
+ <header>
8
+ <nav>
9
+ <NuxtLink to="/">Home</NuxtLink>
10
+ <NuxtLink to="/invoices">Invoices</NuxtLink>
11
+ </nav>
12
+ </header>
13
+ <main>
14
+ <NuxtPage />
15
+ </main>
16
+ </div>
17
+ </template>
18
+
19
+ <style>
20
+ nav {
21
+ display: flex;
22
+ gap: 1rem;
23
+ padding: 1rem;
24
+ border-bottom: 1px solid #e5e5e5;
25
+ }
26
+ nav a {
27
+ text-decoration: none;
28
+ color: #0070f3;
29
+ }
30
+ nav a.router-link-active {
31
+ font-weight: bold;
32
+ }
33
+ main {
34
+ padding: 1rem;
35
+ font-family: system-ui, sans-serif;
36
+ }
37
+ </style>
@@ -0,0 +1,21 @@
1
+ <script setup lang="ts">
2
+ // Landing page for the generated noy-db app.
3
+ </script>
4
+
5
+ <template>
6
+ <section>
7
+ <h1>{{PROJECT_NAME}}</h1>
8
+ <p>
9
+ Encrypted, offline-first, zero-knowledge document store powered by
10
+ <a href="https://github.com/vLannaAi/noy-db">noy-db</a>.
11
+ </p>
12
+ <p>
13
+ Visit <NuxtLink to="/invoices">/invoices</NuxtLink> to see the demo
14
+ invoices store.
15
+ </p>
16
+ <p>
17
+ Run <code>noy-db verify</code> at any time to check the integrity of
18
+ your noy-db install.
19
+ </p>
20
+ </section>
21
+ </template>
@@ -0,0 +1,62 @@
1
+ <script setup lang="ts">
2
+ import { DEFAULT_INVOICES } from '~/stores/invoices'
3
+
4
+ const invoices = useInvoices()
5
+ await invoices.$ready
6
+
7
+ // Seed on first run: if the store is empty and there are defaults, populate.
8
+ // This runs once on component mount; later visits see whatever the user
9
+ // has edited.
10
+ if (invoices.items.length === 0 && DEFAULT_INVOICES.length > 0) {
11
+ for (const inv of DEFAULT_INVOICES) {
12
+ invoices.add(inv)
13
+ }
14
+ }
15
+
16
+ // Reactive query: re-runs whenever the underlying collection changes.
17
+ const open = invoices.query()
18
+ .where('status', '==', 'open')
19
+ .live()
20
+
21
+ function addDraft() {
22
+ invoices.add({
23
+ id: crypto.randomUUID(),
24
+ client: 'New Client',
25
+ amount: Math.round(Math.random() * 10000),
26
+ status: 'draft',
27
+ dueDate: new Date().toISOString().slice(0, 10),
28
+ })
29
+ }
30
+
31
+ function remove(id: string) {
32
+ invoices.remove(id)
33
+ }
34
+ </script>
35
+
36
+ <template>
37
+ <section>
38
+ <h1>Invoices</h1>
39
+ <button @click="addDraft">+ New draft</button>
40
+ <p><strong>{{ open.length }}</strong> open invoice(s)</p>
41
+ <ul>
42
+ <li v-for="inv in invoices.items" :key="inv.id">
43
+ <strong>{{ inv.client }}</strong> — {{ inv.amount }} ({{ inv.status }})
44
+ <button @click="remove(inv.id)">Delete</button>
45
+ </li>
46
+ </ul>
47
+ <p v-if="invoices.items.length === 0">
48
+ No invoices yet — click "New draft" to add one.
49
+ </p>
50
+ </section>
51
+ </template>
52
+
53
+ <style scoped>
54
+ button {
55
+ cursor: pointer;
56
+ padding: 0.25rem 0.75rem;
57
+ margin: 0.25rem;
58
+ }
59
+ li {
60
+ padding: 0.5rem 0;
61
+ }
62
+ </style>
@@ -0,0 +1,23 @@
1
+ // Generated by `create-noy-db`.
2
+ //
3
+ // `defineNoydbStore` is auto-imported by @noy-db/in-nuxt. The store wires
4
+ // a Pinia store to a noy-db compartment + collection. Encryption,
5
+ // keyring management, and adapter wiring are invisible to components.
6
+
7
+ export interface Invoice {
8
+ id: string
9
+ client: string
10
+ amount: number
11
+ status: 'draft' | 'open' | 'paid' | 'overdue'
12
+ dueDate: string
13
+ }
14
+
15
+ export const useInvoices = defineNoydbStore<Invoice>('invoices', {
16
+ vault: 'demo-co',
17
+ })
18
+
19
+ /**
20
+ * Default seed records rendered into the store on first mount (see
21
+ * `app/pages/invoices.vue`). An empty array means the page starts empty.
22
+ */
23
+ export const DEFAULT_INVOICES: Invoice[] = {{SEED_INVOICES}}
@@ -0,0 +1,30 @@
1
+ // Generated by `create-noy-db`.
2
+ //
3
+ // The `noydb:` key is fully typed via @noy-db/in-nuxt's module augmentation
4
+ // of @nuxt/schema. Hover any field for documentation.
5
+
6
+ export default defineNuxtConfig({
7
+ compatibilityDate: '2026-04-01',
8
+
9
+ modules: [
10
+ '@pinia/nuxt',
11
+ '@noy-db/in-nuxt',
12
+ ],
13
+
14
+ noydb: {
15
+ adapter: '{{ADAPTER}}',
16
+ pinia: true,
17
+ devtools: {{DEVTOOLS}},
18
+ },
19
+
20
+ devtools: {
21
+ enabled: process.env['NODE_ENV'] !== 'production',
22
+ },
23
+
24
+ telemetry: false,
25
+
26
+ typescript: {
27
+ strict: true,
28
+ typeCheck: false,
29
+ },
30
+ })
@@ -0,0 +1,28 @@
1
+ {
2
+ "name": "{{PROJECT_NAME}}",
3
+ "version": "0.0.1",
4
+ "private": true,
5
+ "type": "module",
6
+ "scripts": {
7
+ "dev": "nuxt dev",
8
+ "build": "nuxt build",
9
+ "preview": "nuxt preview",
10
+ "verify": "noy-db verify"
11
+ },
12
+ "dependencies": {
13
+ "@noy-db/to-browser-idb": "^0.11.0",
14
+ "@noy-db/hub": "^0.11.0",
15
+ "@noy-db/to-file": "^0.11.0",
16
+ "@noy-db/to-memory": "^0.11.0",
17
+ "@noy-db/in-nuxt": "^0.11.0",
18
+ "@noy-db/in-pinia": "^0.11.0",
19
+ "@noy-db/in-vue": "^0.11.0",
20
+ "@pinia/nuxt": "^0.11.0",
21
+ "nuxt": "^4.4.2",
22
+ "pinia": "^3.0.1",
23
+ "vue": "^3.5.32"
24
+ },
25
+ "devDependencies": {
26
+ "create-noy-db": "^0.5.0"
27
+ }
28
+ }
@@ -0,0 +1,3 @@
1
+ {
2
+ "extends": "./.nuxt/tsconfig.json"
3
+ }
@@ -0,0 +1,77 @@
1
+ # {{PROJECT_NAME}}
2
+
3
+ A Vite + TypeScript + [noy-db](https://github.com/vLannaAi/noy-db)
4
+ starter with **no framework** — just the browser, the hub, and the
5
+ IndexedDB store. Scaffolded by `create-noy-db`.
6
+
7
+ ## Stack
8
+
9
+ - **Vite** — dev server + build
10
+ - **@noy-db/hub** — zero-knowledge encrypted document store
11
+ - **@noy-db/to-browser-idb** — IndexedDB adapter (atomic CAS, larger
12
+ quota than localStorage)
13
+
14
+ Everything stored is encrypted with AES-256-GCM before it touches
15
+ IndexedDB. The adapter only ever sees ciphertext.
16
+
17
+ ## When to pick this template
18
+
19
+ - You want the **smallest possible** noy-db starting point.
20
+ - You're integrating noy-db into an existing non-framework app (hand-rolled
21
+ DOM, web components, a library).
22
+ - You want to learn the hub API without a framework abstraction layer in
23
+ the way.
24
+
25
+ If you want Vue, Pinia, or Nuxt, pick the `nuxt-default` template
26
+ instead (`npm create noy-db@latest -- --template nuxt-default`).
27
+
28
+ ## Getting started
29
+
30
+ ```bash
31
+ pnpm install # or npm/yarn/bun
32
+ pnpm dev # vite dev on http://localhost:5173
33
+ pnpm build # production build
34
+ pnpm preview # preview the production build
35
+ pnpm verify # run the noy-db integrity check
36
+ ```
37
+
38
+ First time the page loads it will prompt for a **passphrase** — that
39
+ passphrase derives the master key. Lose it and the data is
40
+ unrecoverable (by design: the library cannot help you).
41
+
42
+ ## What's in `src/main.ts`
43
+
44
+ The starter walks through the full lifecycle:
45
+
46
+ 1. `createNoydb({ store: browserIdbStore(), secret: passphrase })` —
47
+ open the encrypted store.
48
+ 2. `await db.openVault('demo')` — create or open a vault (tenant).
49
+ 3. `vault.collection<Invoice>('invoices')` — typed collection.
50
+ 4. CRUD operations — `.put()` / `.get()` / `.delete()` / `.list()`.
51
+ 5. `db.close()` — clears the master key from memory.
52
+
53
+ The UI is intentionally plain HTML — swap in your framework of choice
54
+ once you've understood the flow.
55
+
56
+ ## Verifying zero-knowledge
57
+
58
+ Open DevTools → Application → IndexedDB → your origin → `noydb_demo`
59
+ (or whatever vault name you used). Every record shows `{ _noydb: 1,
60
+ _v, _ts, _iv, _data }`. The `_data` blob is AES-GCM ciphertext — the
61
+ literal record contents never appear.
62
+
63
+ ## Adding a collection
64
+
65
+ ```bash
66
+ npx noy-db add clients
67
+ ```
68
+
69
+ This scaffolds `src/clients.ts` with a typed Client interface +
70
+ CRUD helpers. Edit the generated interface to match your domain.
71
+
72
+ ## Documentation
73
+
74
+ - [noy-db getting started](https://github.com/vLannaAi/noy-db/blob/main/docs/quickstart.md)
75
+ - [Topology matrix](https://github.com/vLannaAi/noy-db/blob/main/docs/topologies.md) — pick the right stack
76
+ - [Architecture](https://github.com/vLannaAi/noy-db/blob/main/docs/architecture.md)
77
+ - [Roadmap](https://github.com/vLannaAi/noy-db/blob/main/ROADMAP.md)
@@ -0,0 +1,29 @@
1
+ # Vite / build output
2
+ dist
3
+ .vite
4
+
5
+ # Node
6
+ node_modules
7
+ *.log
8
+ .npm
9
+
10
+ # Env files
11
+ .env
12
+ .env.local
13
+ .env.*.local
14
+
15
+ # OS
16
+ .DS_Store
17
+ Thumbs.db
18
+
19
+ # IDE
20
+ .vscode/*
21
+ !.vscode/extensions.json
22
+ .idea
23
+ *.suo
24
+ *.ntvs*
25
+ *.njsproj
26
+ *.sln
27
+
28
+ # Test coverage
29
+ coverage