@notionx/create-notionx-app 1.0.0
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 +139 -0
- package/dist/answers.js +332 -0
- package/dist/answers.js.map +1 -0
- package/dist/cli-notionx.js +388 -0
- package/dist/cli-notionx.js.map +1 -0
- package/dist/cli-notionx.test.js +277 -0
- package/dist/cli-notionx.test.js.map +1 -0
- package/dist/diff.js +40 -0
- package/dist/diff.js.map +1 -0
- package/dist/diff.test.js +90 -0
- package/dist/diff.test.js.map +1 -0
- package/dist/index.js +99 -0
- package/dist/index.js.map +1 -0
- package/dist/locale-add/apply.js +39 -0
- package/dist/locale-add/apply.js.map +1 -0
- package/dist/locale-add/format.js +38 -0
- package/dist/locale-add/format.js.map +1 -0
- package/dist/locale-add/list.js +44 -0
- package/dist/locale-add/list.js.map +1 -0
- package/dist/locale-add/list.test.js +45 -0
- package/dist/locale-add/list.test.js.map +1 -0
- package/dist/locale-add/plan.js +128 -0
- package/dist/locale-add/plan.js.map +1 -0
- package/dist/locale-add/validate.js +46 -0
- package/dist/locale-add/validate.js.map +1 -0
- package/dist/metadata.js +41 -0
- package/dist/metadata.js.map +1 -0
- package/dist/notion-translation-sources/apply.js +61 -0
- package/dist/notion-translation-sources/apply.js.map +1 -0
- package/dist/notion-translation-sources/index.js +3 -0
- package/dist/notion-translation-sources/index.js.map +1 -0
- package/dist/notion-translation-sources/plan.js +33 -0
- package/dist/notion-translation-sources/plan.js.map +1 -0
- package/dist/notionx-source.js +142 -0
- package/dist/notionx-source.js.map +1 -0
- package/dist/notionx-source.test.js +144 -0
- package/dist/notionx-source.test.js.map +1 -0
- package/dist/password.js +18 -0
- package/dist/password.js.map +1 -0
- package/dist/presets.js +83 -0
- package/dist/presets.js.map +1 -0
- package/dist/presets.test.js +50 -0
- package/dist/presets.test.js.map +1 -0
- package/dist/prompt.js +218 -0
- package/dist/prompt.js.map +1 -0
- package/dist/provision/cloudflare.js +236 -0
- package/dist/provision/cloudflare.js.map +1 -0
- package/dist/provision/dependencies.js +219 -0
- package/dist/provision/dependencies.js.map +1 -0
- package/dist/provision/index.js +681 -0
- package/dist/provision/index.js.map +1 -0
- package/dist/provision/index.test.js +54 -0
- package/dist/provision/index.test.js.map +1 -0
- package/dist/provision/inspect.js +109 -0
- package/dist/provision/inspect.js.map +1 -0
- package/dist/provision/inspect.test.js +75 -0
- package/dist/provision/inspect.test.js.map +1 -0
- package/dist/provision/notion.js +1981 -0
- package/dist/provision/notion.js.map +1 -0
- package/dist/provision/notion.test.js +542 -0
- package/dist/provision/notion.test.js.map +1 -0
- package/dist/provision/ntn-credentials.js +198 -0
- package/dist/provision/ntn-credentials.js.map +1 -0
- package/dist/provision/options.js +15 -0
- package/dist/provision/options.js.map +1 -0
- package/dist/provision/password-hash.js +78 -0
- package/dist/provision/password-hash.js.map +1 -0
- package/dist/provision/prompts.js +115 -0
- package/dist/provision/prompts.js.map +1 -0
- package/dist/provision/repair.js +48 -0
- package/dist/provision/repair.js.map +1 -0
- package/dist/provision/repair.test.js +141 -0
- package/dist/provision/repair.test.js.map +1 -0
- package/dist/provision/shell.js +84 -0
- package/dist/provision/shell.js.map +1 -0
- package/dist/provision/wire.js +78 -0
- package/dist/provision/wire.js.map +1 -0
- package/dist/registry/doctor.js +181 -0
- package/dist/registry/doctor.js.map +1 -0
- package/dist/registry/doctor.test.js +180 -0
- package/dist/registry/doctor.test.js.map +1 -0
- package/dist/registry/install.js +217 -0
- package/dist/registry/install.js.map +1 -0
- package/dist/registry/install.test.js +168 -0
- package/dist/registry/install.test.js.map +1 -0
- package/dist/registry/load-registry.js +24 -0
- package/dist/registry/load-registry.js.map +1 -0
- package/dist/registry/load-registry.test.js +59 -0
- package/dist/registry/load-registry.test.js.map +1 -0
- package/dist/registry/migration-planner.js +204 -0
- package/dist/registry/migration-planner.js.map +1 -0
- package/dist/registry/migration-planner.test.js +340 -0
- package/dist/registry/migration-planner.test.js.map +1 -0
- package/dist/registry/migrations-store.js +125 -0
- package/dist/registry/migrations-store.js.map +1 -0
- package/dist/registry/migrations-store.test.js +163 -0
- package/dist/registry/migrations-store.test.js.map +1 -0
- package/dist/registry/migrations-types.js +25 -0
- package/dist/registry/migrations-types.js.map +1 -0
- package/dist/registry/project-meta.js +84 -0
- package/dist/registry/project-meta.js.map +1 -0
- package/dist/registry/registry-items.js +354 -0
- package/dist/registry/registry-items.js.map +1 -0
- package/dist/registry/registry-items.test.js +99 -0
- package/dist/registry/registry-items.test.js.map +1 -0
- package/dist/registry/registry-store.js +232 -0
- package/dist/registry/registry-store.js.map +1 -0
- package/dist/registry/registry-store.test.js +136 -0
- package/dist/registry/registry-store.test.js.map +1 -0
- package/dist/registry/registry-types.js +18 -0
- package/dist/registry/registry-types.js.map +1 -0
- package/dist/registry/registry-types.test.js +146 -0
- package/dist/registry/registry-types.test.js.map +1 -0
- package/dist/registry/render-content-source-files.js +158 -0
- package/dist/registry/render-content-source-files.js.map +1 -0
- package/dist/registry/render-multi-source.js +296 -0
- package/dist/registry/render-multi-source.js.map +1 -0
- package/dist/registry/render-multi-source.test.js +110 -0
- package/dist/registry/render-multi-source.test.js.map +1 -0
- package/dist/registry/text-utils.js +42 -0
- package/dist/registry/text-utils.js.map +1 -0
- package/dist/registry/uninstall.js +250 -0
- package/dist/registry/uninstall.js.map +1 -0
- package/dist/registry/uninstall.test.js +264 -0
- package/dist/registry/uninstall.test.js.map +1 -0
- package/dist/registry/update.js +280 -0
- package/dist/registry/update.js.map +1 -0
- package/dist/registry/update.test.js +229 -0
- package/dist/registry/update.test.js.map +1 -0
- package/dist/render.js +549 -0
- package/dist/render.js.map +1 -0
- package/dist/render.test.js +414 -0
- package/dist/render.test.js.map +1 -0
- package/dist/templates/.dev.vars.example.tmpl +32 -0
- package/dist/templates/.gitignore.tmpl +58 -0
- package/dist/templates/README.md.tmpl +417 -0
- package/dist/templates/app/[slug]/page.tsx.tmpl +55 -0
- package/dist/templates/app/admin/account/page.tsx.tmpl +18 -0
- package/dist/templates/app/admin/content-models/page.tsx.tmpl +6 -0
- package/dist/templates/app/admin/layout.tsx.tmpl +90 -0
- package/dist/templates/app/admin/loading.tsx.tmpl +6 -0
- package/dist/templates/app/admin/page.tsx.tmpl +17 -0
- package/dist/templates/app/api/auth/google/callback/route.ts.tmpl +3 -0
- package/dist/templates/app/api/auth/google/route.ts.tmpl +3 -0
- package/dist/templates/app/api/auth/verify-email/route.ts.tmpl +3 -0
- package/dist/templates/app/api/auth/viewer/route.ts.tmpl +3 -0
- package/dist/templates/app/api/health/route.ts.tmpl +3 -0
- package/dist/templates/app/api/{{contentSourceId}}/[slug]/route.ts.tmpl +27 -0
- package/dist/templates/app/api/{{contentSourceId}}/route.ts.tmpl +18 -0
- package/dist/templates/app/globals.css.tmpl +109 -0
- package/dist/templates/app/layout.tsx.tmpl +56 -0
- package/dist/templates/app/login/page.tsx.tmpl +154 -0
- package/dist/templates/app/page.fallback.tsx.tmpl +31 -0
- package/dist/templates/app/page.tsx.tmpl +42 -0
- package/dist/templates/app/register/page.tsx.tmpl +138 -0
- package/dist/templates/app/{{contentSourceListPath}}/[slug]/page.tsx.tmpl +113 -0
- package/dist/templates/app/{{contentSourceListPath}}/page.tsx.tmpl +74 -0
- package/dist/templates/components/content/post-card.tsx.tmpl +80 -0
- package/dist/templates/components/notion-blocks.tsx.tmpl +668 -0
- package/dist/templates/components/page-blocks/feature-grid-block.tsx.tmpl +68 -0
- package/dist/templates/components/page-blocks/hero-block.tsx.tmpl +73 -0
- package/dist/templates/components/page-blocks/latest-posts-block.tsx.tmpl +59 -0
- package/dist/templates/components/page-blocks/story-block.tsx.tmpl +70 -0
- package/dist/templates/components/page-blocks.fallback.tsx.tmpl +17 -0
- package/dist/templates/components/page-blocks.tsx.tmpl +32 -0
- package/dist/templates/components/search/search-dialog.tsx.tmpl +171 -0
- package/dist/templates/components/site/locale-switcher.tsx.tmpl +65 -0
- package/dist/templates/components/site/site-footer.tsx.tmpl +106 -0
- package/dist/templates/components/site/site-header.tsx.tmpl +80 -0
- package/dist/templates/components/site/site-shell.tsx.tmpl +20 -0
- package/dist/templates/components/site/theme-bootstrap.tsx.tmpl +51 -0
- package/dist/templates/components/theme-provider.tsx.tmpl +14 -0
- package/dist/templates/components/theme-toggle.tsx.tmpl +38 -0
- package/dist/templates/components/ui/accordion.tsx.tmpl +56 -0
- package/dist/templates/components/ui/alert.tsx.tmpl +59 -0
- package/dist/templates/components/ui/aspect-ratio.tsx.tmpl +8 -0
- package/dist/templates/components/ui/avatar.tsx.tmpl +44 -0
- package/dist/templates/components/ui/badge.tsx.tmpl +33 -0
- package/dist/templates/components/ui/button.tsx.tmpl +56 -0
- package/dist/templates/components/ui/card.tsx.tmpl +61 -0
- package/dist/templates/components/ui/checkbox.tsx.tmpl +28 -0
- package/dist/templates/components/ui/dialog.tsx.tmpl +104 -0
- package/dist/templates/components/ui/dropdown-menu.tsx.tmpl +183 -0
- package/dist/templates/components/ui/input.tsx.tmpl +21 -0
- package/dist/templates/components/ui/label.tsx.tmpl +25 -0
- package/dist/templates/components/ui/popover.tsx.tmpl +30 -0
- package/dist/templates/components/ui/radio-group.tsx.tmpl +44 -0
- package/dist/templates/components/ui/select.tsx.tmpl +150 -0
- package/dist/templates/components/ui/separator.tsx.tmpl +30 -0
- package/dist/templates/components/ui/sheet.tsx.tmpl +125 -0
- package/dist/templates/components/ui/skeleton.tsx.tmpl +15 -0
- package/dist/templates/components/ui/sonner.tsx.tmpl +30 -0
- package/dist/templates/components/ui/switch.tsx.tmpl +29 -0
- package/dist/templates/components/ui/table.tsx.tmpl +107 -0
- package/dist/templates/components/ui/tabs.tsx.tmpl +55 -0
- package/dist/templates/components/ui/textarea.tsx.tmpl +24 -0
- package/dist/templates/components/ui/tooltip.tsx.tmpl +30 -0
- package/dist/templates/components.json.tmpl +21 -0
- package/dist/templates/env.d.ts.tmpl +32 -0
- package/dist/templates/lib/admin/actions.ts.tmpl +43 -0
- package/dist/templates/lib/admin/context.tsx.tmpl +209 -0
- package/dist/templates/lib/admin/nav.ts.tmpl +23 -0
- package/dist/templates/lib/auth.config.fallback.ts.tmpl +10 -0
- package/dist/templates/lib/auth.config.ts.tmpl +45 -0
- package/dist/templates/lib/blocks/translations.ts.tmpl +44 -0
- package/dist/templates/lib/blog/translations.ts.tmpl +52 -0
- package/dist/templates/lib/content/models.ts.tmpl +53 -0
- package/dist/templates/lib/i18n/config.ts.tmpl +18 -0
- package/dist/templates/lib/i18n/index.ts.tmpl +1 -0
- package/dist/templates/lib/locale-contract/built-in.ts.tmpl +19 -0
- package/dist/templates/lib/locale-contract/index.ts.tmpl +3 -0
- package/dist/templates/lib/locale-contract/paths.ts.tmpl +29 -0
- package/dist/templates/lib/pages/model.ts.tmpl +16 -0
- package/dist/templates/lib/pages/source.ts.tmpl +566 -0
- package/dist/templates/lib/pages/translations.ts.tmpl +34 -0
- package/dist/templates/lib/search/config.fallback.ts.tmpl +11 -0
- package/dist/templates/lib/search/config.ts.tmpl +25 -0
- package/dist/templates/lib/site/config.ts.tmpl +120 -0
- package/dist/templates/lib/site/request-env.ts.tmpl +71 -0
- package/dist/templates/lib/site/settings.fallback.ts.tmpl +21 -0
- package/dist/templates/lib/site/settings.ts.tmpl +320 -0
- package/dist/templates/lib/site/translations.ts.tmpl +30 -0
- package/dist/templates/lib/utils.ts.tmpl +9 -0
- package/dist/templates/migrations/0001_init.sql.tmpl +57 -0
- package/dist/templates/migrations/0002_admin_seed.sql.tmpl +30 -0
- package/dist/templates/migrations/0003_search_index.sql.tmpl +29 -0
- package/dist/templates/next.config.ts.tmpl +18 -0
- package/dist/templates/package.json.tmpl +40 -0
- package/dist/templates/shims/cloudflare-workers-empty.mjs +4 -0
- package/dist/templates/shims/next-headers-empty.mjs +4 -0
- package/dist/templates/tests/smoke.test.ts.tmpl +83 -0
- package/dist/templates/tsconfig.json.tmpl +31 -0
- package/dist/templates/vite.config.ts.tmpl +53 -0
- package/dist/templates/vitest.config.ts.tmpl +13 -0
- package/dist/templates/worker/index.ts.tmpl +52 -0
- package/dist/templates/wrangler.jsonc.tmpl +44 -0
- package/dist/ui-presets.js +60 -0
- package/dist/ui-presets.js.map +1 -0
- package/package.json +60 -0
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
// packages/create-notionx-app/src/registry/migrations-store.ts
|
|
2
|
+
//
|
|
3
|
+
// Read / write `.notionx/migrations/`.
|
|
4
|
+
//
|
|
5
|
+
// Layout:
|
|
6
|
+
//
|
|
7
|
+
// .notionx/
|
|
8
|
+
// ├── registry.json
|
|
9
|
+
// └── migrations/
|
|
10
|
+
// ├── _meta.json
|
|
11
|
+
// ├── 0001_init.sql
|
|
12
|
+
// ├── 0002_add_blog_status.sql
|
|
13
|
+
// └── 0003_rename_eyebrow.notion-diff.json
|
|
14
|
+
//
|
|
15
|
+
// `_meta.json` is the **index**. The .sql / .notion-diff.json /
|
|
16
|
+
// .codemod.json files are the **payloads**. Both are append-only:
|
|
17
|
+
// once written, a file is never edited. To "undo" a migration, run
|
|
18
|
+
// another one that does the opposite.
|
|
19
|
+
import { mkdir, readFile, rename, writeFile } from "node:fs/promises";
|
|
20
|
+
import path from "node:path";
|
|
21
|
+
export const MIGRATIONS_DIR = ".notionx/migrations";
|
|
22
|
+
export const MIGRATIONS_META = "_meta.json";
|
|
23
|
+
export const MIGRATIONS_SCHEMA_V1 = "https://notionx.dev/schemas/migrations-meta.v1.json";
|
|
24
|
+
/**
|
|
25
|
+
* Empty `migrations/` directory shape. Used as the default when
|
|
26
|
+
* the directory doesn't exist yet.
|
|
27
|
+
*/
|
|
28
|
+
export function emptyMeta(nextSequence = 1) {
|
|
29
|
+
return {
|
|
30
|
+
$schema: MIGRATIONS_SCHEMA_V1,
|
|
31
|
+
nextSequence,
|
|
32
|
+
history: [],
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Read `_meta.json` from `<projectDir>/.notionx/migrations/`. Returns
|
|
37
|
+
* `null` when the directory doesn't exist (caller should treat as
|
|
38
|
+
* empty migrations history).
|
|
39
|
+
*/
|
|
40
|
+
export async function readMigrationsMeta(projectDir) {
|
|
41
|
+
const filePath = path.join(projectDir, MIGRATIONS_DIR, MIGRATIONS_META);
|
|
42
|
+
try {
|
|
43
|
+
const raw = await readFile(filePath, "utf8");
|
|
44
|
+
return JSON.parse(raw);
|
|
45
|
+
}
|
|
46
|
+
catch (err) {
|
|
47
|
+
if (isENOENT(err))
|
|
48
|
+
return null;
|
|
49
|
+
throw err;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Write `_meta.json` atomically (write to `.tmp`, then rename).
|
|
54
|
+
*/
|
|
55
|
+
export async function writeMigrationsMeta(projectDir, meta) {
|
|
56
|
+
const dir = path.join(projectDir, MIGRATIONS_DIR);
|
|
57
|
+
const target = path.join(dir, MIGRATIONS_META);
|
|
58
|
+
const tmp = `${target}.tmp`;
|
|
59
|
+
await mkdir(dir, { recursive: true });
|
|
60
|
+
await writeFile(tmp, `${JSON.stringify(meta, null, 2)}\n`, "utf8");
|
|
61
|
+
await rename(tmp, target);
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Append a single migration entry. Returns the new meta + the
|
|
65
|
+
* sequence number assigned to this entry.
|
|
66
|
+
*
|
|
67
|
+
* Sequence number is the **previous** `nextSequence` value, zero-
|
|
68
|
+
* padded to 4 digits. The meta's `nextSequence` is then
|
|
69
|
+
* incremented by 1.
|
|
70
|
+
*/
|
|
71
|
+
export async function appendMigration(projectDir, entry) {
|
|
72
|
+
const meta = (await readMigrationsMeta(projectDir)) ?? emptyMeta();
|
|
73
|
+
const seq = String(meta.nextSequence).padStart(4, "0");
|
|
74
|
+
const next = {
|
|
75
|
+
...meta,
|
|
76
|
+
nextSequence: meta.nextSequence + 1,
|
|
77
|
+
history: [
|
|
78
|
+
...meta.history,
|
|
79
|
+
{
|
|
80
|
+
...entry,
|
|
81
|
+
sequence: seq,
|
|
82
|
+
generatedAt: new Date().toISOString(),
|
|
83
|
+
},
|
|
84
|
+
],
|
|
85
|
+
};
|
|
86
|
+
await writeMigrationsMeta(projectDir, next);
|
|
87
|
+
return { meta: next, sequence: seq };
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Mark an existing migration as applied. Idempotent.
|
|
91
|
+
*/
|
|
92
|
+
export async function markMigrationApplied(projectDir, sequence) {
|
|
93
|
+
const meta = await readMigrationsMeta(projectDir);
|
|
94
|
+
if (!meta) {
|
|
95
|
+
throw new Error(`Cannot mark migration ${sequence} applied: .notionx/migrations/_meta.json does not exist.`);
|
|
96
|
+
}
|
|
97
|
+
const next = {
|
|
98
|
+
...meta,
|
|
99
|
+
history: meta.history.map((entry) => entry.sequence === sequence && !entry.applied
|
|
100
|
+
? { ...entry, applied: true, appliedAt: new Date().toISOString() }
|
|
101
|
+
: entry),
|
|
102
|
+
};
|
|
103
|
+
await writeMigrationsMeta(projectDir, next);
|
|
104
|
+
return next;
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Write a migration payload file (the .sql or .notion-diff.json
|
|
108
|
+
* next to `_meta.json`). Atomic. The filename is supplied by the
|
|
109
|
+
* caller; we don't try to derive it from the entry.
|
|
110
|
+
*/
|
|
111
|
+
export async function writeMigrationPayload(projectDir, filename, content) {
|
|
112
|
+
const dir = path.join(projectDir, MIGRATIONS_DIR);
|
|
113
|
+
const target = path.join(dir, filename);
|
|
114
|
+
const tmp = `${target}.tmp`;
|
|
115
|
+
await mkdir(dir, { recursive: true });
|
|
116
|
+
await writeFile(tmp, content, "utf8");
|
|
117
|
+
await rename(tmp, target);
|
|
118
|
+
}
|
|
119
|
+
function isENOENT(err) {
|
|
120
|
+
return (typeof err === "object" &&
|
|
121
|
+
err !== null &&
|
|
122
|
+
"code" in err &&
|
|
123
|
+
err.code === "ENOENT");
|
|
124
|
+
}
|
|
125
|
+
//# sourceMappingURL=migrations-store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"migrations-store.js","sourceRoot":"","sources":["../../src/registry/migrations-store.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
// packages/create-notionx-app/src/registry/migrations-store.test.ts
|
|
2
|
+
import { mkdtemp, readFile, rm } from "node:fs/promises";
|
|
3
|
+
import os from "node:os";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
import { afterEach, beforeEach, describe, expect, it } from "vitest";
|
|
6
|
+
import { MIGRATIONS_DIR, appendMigration, emptyMeta, markMigrationApplied, readMigrationsMeta, writeMigrationPayload, writeMigrationsMeta, } from "./migrations-store.js";
|
|
7
|
+
describe("migrations-store", () => {
|
|
8
|
+
let dir;
|
|
9
|
+
beforeEach(async () => {
|
|
10
|
+
dir = await mkdtemp(path.join(os.tmpdir(), "notionx-mig-"));
|
|
11
|
+
});
|
|
12
|
+
afterEach(async () => {
|
|
13
|
+
await rm(dir, { recursive: true, force: true });
|
|
14
|
+
});
|
|
15
|
+
it("exposes the canonical .notionx/migrations/ path", () => {
|
|
16
|
+
expect(MIGRATIONS_DIR).toBe(".notionx/migrations");
|
|
17
|
+
});
|
|
18
|
+
it("returns null when _meta.json does not exist", async () => {
|
|
19
|
+
const meta = await readMigrationsMeta(dir);
|
|
20
|
+
expect(meta).toBeNull();
|
|
21
|
+
});
|
|
22
|
+
it("emptyMeta() starts with nextSequence=1 and empty history", () => {
|
|
23
|
+
const m = emptyMeta();
|
|
24
|
+
expect(m.nextSequence).toBe(1);
|
|
25
|
+
expect(m.history).toEqual([]);
|
|
26
|
+
});
|
|
27
|
+
it("writeMigrationsMeta + read round-trips", async () => {
|
|
28
|
+
const m = emptyMeta();
|
|
29
|
+
await writeMigrationsMeta(dir, m);
|
|
30
|
+
const read = await readMigrationsMeta(dir);
|
|
31
|
+
expect(read).toEqual(m);
|
|
32
|
+
});
|
|
33
|
+
it("appendMigration assigns 4-digit sequence numbers and bumps nextSequence", async () => {
|
|
34
|
+
await writeMigrationsMeta(dir, emptyMeta());
|
|
35
|
+
const { sequence, meta } = await appendMigration(dir, {
|
|
36
|
+
itemId: "blog",
|
|
37
|
+
itemKind: "content-source",
|
|
38
|
+
file: { kind: "d1-sql", filename: "0001_init.sql" },
|
|
39
|
+
applied: false,
|
|
40
|
+
label: "init",
|
|
41
|
+
});
|
|
42
|
+
expect(sequence).toBe("0001");
|
|
43
|
+
expect(meta.nextSequence).toBe(2);
|
|
44
|
+
expect(meta.history).toHaveLength(1);
|
|
45
|
+
expect(meta.history[0]?.sequence).toBe("0001");
|
|
46
|
+
expect(meta.history[0]?.itemId).toBe("blog");
|
|
47
|
+
});
|
|
48
|
+
it("appendMigration is monotonic across many calls", async () => {
|
|
49
|
+
await writeMigrationsMeta(dir, emptyMeta());
|
|
50
|
+
for (let i = 1; i <= 5; i++) {
|
|
51
|
+
const { sequence } = await appendMigration(dir, {
|
|
52
|
+
itemId: "blog",
|
|
53
|
+
itemKind: "content-source",
|
|
54
|
+
file: { kind: "d1-sql", filename: `000${i}_x.sql` },
|
|
55
|
+
applied: false,
|
|
56
|
+
});
|
|
57
|
+
expect(sequence).toBe(`000${i}`);
|
|
58
|
+
}
|
|
59
|
+
const meta = await readMigrationsMeta(dir);
|
|
60
|
+
expect(meta?.nextSequence).toBe(6);
|
|
61
|
+
expect(meta?.history.map((e) => e.sequence)).toEqual([
|
|
62
|
+
"0001",
|
|
63
|
+
"0002",
|
|
64
|
+
"0003",
|
|
65
|
+
"0004",
|
|
66
|
+
"0005",
|
|
67
|
+
]);
|
|
68
|
+
});
|
|
69
|
+
it("markMigrationApplied is idempotent (only flips once)", async () => {
|
|
70
|
+
await writeMigrationsMeta(dir, emptyMeta());
|
|
71
|
+
await appendMigration(dir, {
|
|
72
|
+
itemId: "blog",
|
|
73
|
+
itemKind: "content-source",
|
|
74
|
+
file: { kind: "d1-sql", filename: "0001_x.sql" },
|
|
75
|
+
applied: false,
|
|
76
|
+
});
|
|
77
|
+
const first = await markMigrationApplied(dir, "0001");
|
|
78
|
+
expect(first.history[0]?.applied).toBe(true);
|
|
79
|
+
expect(first.history[0]?.appliedAt).toBeDefined();
|
|
80
|
+
// Wait a tick so the second call's `appliedAt` would differ if
|
|
81
|
+
// it actually re-wrote the timestamp. We assert the timestamp
|
|
82
|
+
// didn't change, proving idempotency.
|
|
83
|
+
const originalTimestamp = first.history[0]?.appliedAt;
|
|
84
|
+
await new Promise((resolve) => setTimeout(resolve, 5));
|
|
85
|
+
const second = await markMigrationApplied(dir, "0001");
|
|
86
|
+
expect(second.history[0]?.appliedAt).toBe(originalTimestamp);
|
|
87
|
+
});
|
|
88
|
+
it("markMigrationApplied throws when the directory is empty", async () => {
|
|
89
|
+
await expect(markMigrationApplied(dir, "0001")).rejects.toThrow(/does not exist/);
|
|
90
|
+
});
|
|
91
|
+
it("writeMigrationPayload writes the payload file alongside _meta.json", async () => {
|
|
92
|
+
await writeMigrationsMeta(dir, emptyMeta());
|
|
93
|
+
await writeMigrationPayload(dir, "0001_init.sql", "CREATE TABLE x (id INTEGER);");
|
|
94
|
+
const raw = await readFile(path.join(dir, MIGRATIONS_DIR, "0001_init.sql"), "utf8");
|
|
95
|
+
expect(raw).toContain("CREATE TABLE x");
|
|
96
|
+
});
|
|
97
|
+
it("migrations are append-only: re-writing the same sequence is not allowed by the store", async () => {
|
|
98
|
+
// We don't expose a "rewrite" API; ensure the public surface
|
|
99
|
+
// doesn't let us accidentally edit a previous migration. The
|
|
100
|
+
// only mutators are `writeMigrationsMeta` (whole-file) and
|
|
101
|
+
// `appendMigration` (always uses nextSequence). A test that
|
|
102
|
+
// calls writeMigrationsMeta with a "rewriting" intent has to
|
|
103
|
+
// opt out by writing the whole meta — and even then,
|
|
104
|
+
// `appendMigration` would never re-use a sequence.
|
|
105
|
+
await writeMigrationsMeta(dir, emptyMeta());
|
|
106
|
+
await appendMigration(dir, {
|
|
107
|
+
itemId: "blog",
|
|
108
|
+
itemKind: "content-source",
|
|
109
|
+
file: { kind: "d1-sql", filename: "0001_x.sql" },
|
|
110
|
+
applied: false,
|
|
111
|
+
});
|
|
112
|
+
const before = await readMigrationsMeta(dir);
|
|
113
|
+
const firstEntryBefore = before?.history[0];
|
|
114
|
+
// Second append must use sequence 0002, not 0001.
|
|
115
|
+
await appendMigration(dir, {
|
|
116
|
+
itemId: "blog",
|
|
117
|
+
itemKind: "content-source",
|
|
118
|
+
file: { kind: "d1-sql", filename: "0002_y.sql" },
|
|
119
|
+
applied: false,
|
|
120
|
+
});
|
|
121
|
+
const after = await readMigrationsMeta(dir);
|
|
122
|
+
const firstEntryAfter = after?.history[0];
|
|
123
|
+
// The first entry is byte-identical to its pre-second-append
|
|
124
|
+
// form (proving append-only for the first migration's record).
|
|
125
|
+
expect(firstEntryAfter).toEqual(firstEntryBefore);
|
|
126
|
+
expect(after?.history[1]?.sequence).toBe("0002");
|
|
127
|
+
});
|
|
128
|
+
});
|
|
129
|
+
describe("migrations-store: dir layout", () => {
|
|
130
|
+
let dir;
|
|
131
|
+
beforeEach(async () => {
|
|
132
|
+
dir = await mkdtemp(path.join(os.tmpdir(), "notionx-mig-dir-"));
|
|
133
|
+
});
|
|
134
|
+
afterEach(async () => {
|
|
135
|
+
await rm(dir, { recursive: true, force: true });
|
|
136
|
+
});
|
|
137
|
+
it("creates .notionx/migrations/ if missing", async () => {
|
|
138
|
+
await writeMigrationsMeta(dir, emptyMeta());
|
|
139
|
+
await writeMigrationPayload(dir, "0001_x.sql", "SELECT 1;");
|
|
140
|
+
const sub = path.join(dir, ".notionx/migrations");
|
|
141
|
+
const metaRaw = await readFile(path.join(sub, "_meta.json"), "utf8");
|
|
142
|
+
const payload = await readFile(path.join(sub, "0001_x.sql"), "utf8");
|
|
143
|
+
expect(metaRaw).toContain("nextSequence");
|
|
144
|
+
expect(payload).toBe("SELECT 1;");
|
|
145
|
+
});
|
|
146
|
+
it("rejects writing payload without prior dir creation when mkdir fails — actually the store creates it", async () => {
|
|
147
|
+
// Sanity: writeMigrationsMeta creates the dir, so a payload
|
|
148
|
+
// write that arrives first still works (the store calls
|
|
149
|
+
// mkdir({ recursive: true })).
|
|
150
|
+
await writeMigrationPayload(dir, "0001_x.sql", "SELECT 2;");
|
|
151
|
+
const raw = await readFile(path.join(dir, MIGRATIONS_DIR, "0001_x.sql"), "utf8");
|
|
152
|
+
expect(raw).toBe("SELECT 2;");
|
|
153
|
+
});
|
|
154
|
+
it("supports arbitrary filenames (the store does not enforce .sql extension)", async () => {
|
|
155
|
+
// The registry may ship a `.notion-diff.json` or `.codemod.json`
|
|
156
|
+
// payload. The store just writes whatever filename the caller
|
|
157
|
+
// gives.
|
|
158
|
+
await writeMigrationPayload(dir, "0001_add_author.notion-diff.json", JSON.stringify({ kind: "notion-field-add", property: "Author" }));
|
|
159
|
+
const raw = await readFile(path.join(dir, MIGRATIONS_DIR, "0001_add_author.notion-diff.json"), "utf8");
|
|
160
|
+
expect(raw).toContain("notion-field-add");
|
|
161
|
+
});
|
|
162
|
+
});
|
|
163
|
+
//# sourceMappingURL=migrations-store.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"migrations-store.test.js","sourceRoot":"","sources":["../../src/registry/migrations-store.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
// packages/create-notionx-app/src/registry/migrations-types.ts
|
|
2
|
+
//
|
|
3
|
+
// v2 Migration Protocol — the on-disk format for
|
|
4
|
+
// `.notionx/migrations/`.
|
|
5
|
+
//
|
|
6
|
+
// Modeled on Prisma's `migrations/` directory: every change to a
|
|
7
|
+
// project's schema (D1 or Notion) is an immutable, append-only
|
|
8
|
+
// file with a monotonically-increasing sequence number. Once a
|
|
9
|
+
// migration has been applied to a real environment, **it is
|
|
10
|
+
// never edited**. To reverse a change, the user runs
|
|
11
|
+
// `notionx update` to apply a *new* migration that undoes it.
|
|
12
|
+
//
|
|
13
|
+
// Three kinds of migration live alongside each other:
|
|
14
|
+
// - `.sql` — D1 schema change (run by `wrangler d1 migrations apply`)
|
|
15
|
+
// - `.notion.json`— Notion schema change (run by hand or via the
|
|
16
|
+
// Notion API in CI; PR 4 ships a *plan*, not the
|
|
17
|
+
// run)
|
|
18
|
+
// - `.codemod.json`— TypeScript code transformation (run by
|
|
19
|
+
// `notionx update` against the user's code)
|
|
20
|
+
//
|
|
21
|
+
// A single migration usually has exactly one file. We bundle
|
|
22
|
+
// them in `_meta.json` so the planner can apply them in order
|
|
23
|
+
// and the user can see what changed.
|
|
24
|
+
export {};
|
|
25
|
+
//# sourceMappingURL=migrations-types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"migrations-types.js","sourceRoot":"","sources":["../../src/registry/migrations-types.ts"],"names":[],"mappings":"AAAA,+DAA+D;AAC/D,EAAE;AACF,iDAAiD;AACjD,0BAA0B;AAC1B,EAAE;AACF,iEAAiE;AACjE,+DAA+D;AAC/D,+DAA+D;AAC/D,4DAA4D;AAC5D,qDAAqD;AACrD,8DAA8D;AAC9D,EAAE;AACF,sDAAsD;AACtD,8EAA8E;AAC9E,mEAAmE;AACnE,oEAAoE;AACpE,0BAA0B;AAC1B,8DAA8D;AAC9D,+DAA+D;AAC/D,EAAE;AACF,6DAA6D;AAC7D,8DAA8D;AAC9D,qCAAqC"}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
// packages/create-notionx-app/src/registry/project-meta.ts
|
|
2
|
+
//
|
|
3
|
+
// Shared helpers used by install / uninstall / update:
|
|
4
|
+
// - `readProjectMeta` reads `package.json` for the project name
|
|
5
|
+
// and assembles the `MultiSourceProject` shape the token
|
|
6
|
+
// builders need.
|
|
7
|
+
// - `rerenderModelsFile` re-renders `lib/content/models.ts` from
|
|
8
|
+
// its template using the current installed-item list.
|
|
9
|
+
//
|
|
10
|
+
// Both helpers lived as private duplicates in install.ts and
|
|
11
|
+
// update.ts (readProjectMeta) and in install.ts and uninstall.ts
|
|
12
|
+
// (rerenderModelsFile). They are collected here so there is one
|
|
13
|
+
// authoritative implementation.
|
|
14
|
+
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
15
|
+
import path from "node:path";
|
|
16
|
+
import { buildMultiSourceTokenMap } from "./render-multi-source.js";
|
|
17
|
+
/**
|
|
18
|
+
* Read `package.json` for the project name and assemble the
|
|
19
|
+
* `MultiSourceProject` shape. Falls back to the directory basename
|
|
20
|
+
* when `package.json` is missing or has no `name` field.
|
|
21
|
+
*/
|
|
22
|
+
export async function readProjectMeta(projectDir, manifest) {
|
|
23
|
+
const pkgPath = path.join(projectDir, "package.json");
|
|
24
|
+
let projectName = path.basename(projectDir);
|
|
25
|
+
try {
|
|
26
|
+
const raw = await readFile(pkgPath, "utf8");
|
|
27
|
+
const parsed = JSON.parse(raw);
|
|
28
|
+
if (typeof parsed.name === "string" && parsed.name.length > 0) {
|
|
29
|
+
projectName = parsed.name;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
// No package.json (or unreadable). Fall back to dir basename.
|
|
34
|
+
}
|
|
35
|
+
return {
|
|
36
|
+
projectName,
|
|
37
|
+
targetDir: projectDir,
|
|
38
|
+
defaultLocale: "en", // TODO: read from a future v2 i18n block
|
|
39
|
+
supportedLocales: ["en"],
|
|
40
|
+
notionxSource: manifest.notionxCore,
|
|
41
|
+
adminEmail: "admin@example.com", // placeholder; not used by add/remove/update
|
|
42
|
+
adminPassword: "", // placeholder; not used by add/remove/update
|
|
43
|
+
scaffoldVersion: manifest.scaffoldVersion,
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Re-render `lib/content/models.ts` from its template so the
|
|
48
|
+
* `contentSources` / `managedContentSources` arrays stay in sync
|
|
49
|
+
* with the installed-item list and the current internal-source
|
|
50
|
+
* flags (`enableSiteSettings` / `enableBlocks`).
|
|
51
|
+
*
|
|
52
|
+
* Returns `{ wrote: false }` when the template file is missing
|
|
53
|
+
* (e.g. a project that doesn't ship the models template).
|
|
54
|
+
*/
|
|
55
|
+
export async function rerenderModelsFile(input) {
|
|
56
|
+
const target = path.join(input.projectDir, "lib/content/models.ts");
|
|
57
|
+
const tplPath = path.join(input.templatesDir, "lib/content/models.ts.tmpl");
|
|
58
|
+
let tpl;
|
|
59
|
+
try {
|
|
60
|
+
tpl = await readFile(tplPath, "utf8");
|
|
61
|
+
}
|
|
62
|
+
catch {
|
|
63
|
+
return { wrote: false };
|
|
64
|
+
}
|
|
65
|
+
const tokens = buildMultiSourceTokenMap({
|
|
66
|
+
project: input.project,
|
|
67
|
+
installed: input.installed,
|
|
68
|
+
internalSources: input.internalSources,
|
|
69
|
+
});
|
|
70
|
+
const flat = {
|
|
71
|
+
contentSourceDeclarations: tokens.contentSourceDeclarations,
|
|
72
|
+
contentSourceSourcesVarNames: tokens.contentSourceSourcesVarNames,
|
|
73
|
+
internalSourceDeclarations: tokens.internalSourceDeclarations,
|
|
74
|
+
internalSourceVarNames: tokens.internalSourceVarNames,
|
|
75
|
+
};
|
|
76
|
+
const rendered = tpl.replace(/\{\{\s*([a-zA-Z][a-zA-Z0-9_]*)\s*\}\}/g, (full, key) => {
|
|
77
|
+
const v = flat[key];
|
|
78
|
+
return typeof v === "string" ? v : full;
|
|
79
|
+
});
|
|
80
|
+
await mkdir(path.dirname(target), { recursive: true });
|
|
81
|
+
await writeFile(target, rendered, "utf8");
|
|
82
|
+
return { wrote: true };
|
|
83
|
+
}
|
|
84
|
+
//# sourceMappingURL=project-meta.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"project-meta.js","sourceRoot":"","sources":["../../src/registry/project-meta.ts"],"names":[],"mappings":"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"}
|