@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,18 @@
|
|
|
1
|
+
import type { NextConfig } from "next";
|
|
2
|
+
|
|
3
|
+
const nextConfig: NextConfig = {
|
|
4
|
+
// Add project-specific headers, redirects, or rewrites here.
|
|
5
|
+
|
|
6
|
+
// Allow `next/image` to load cover art hosted by Notion and the
|
|
7
|
+
// common placeholder hosts the scaffolder seeds into sample posts.
|
|
8
|
+
// Adjust this list if you self-host covers on R2 or another CDN.
|
|
9
|
+
images: {
|
|
10
|
+
remotePatterns: [
|
|
11
|
+
{ protocol: "https", hostname: "prod-files-secure.s3.us-west-2.amazonaws.com" },
|
|
12
|
+
{ protocol: "https", hostname: "www.notion.so" },
|
|
13
|
+
{ protocol: "https", hostname: "images.unsplash.com" },
|
|
14
|
+
],
|
|
15
|
+
},
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export default nextConfig;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "{{projectNameLower}}",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"private": true,
|
|
5
|
+
"type": "module",
|
|
6
|
+
"engines": {
|
|
7
|
+
"node": ">=22"
|
|
8
|
+
},
|
|
9
|
+
"scripts": {
|
|
10
|
+
"dev": "vinext dev --port 3001",
|
|
11
|
+
"build": "vinext build",
|
|
12
|
+
"start": "vinext start",
|
|
13
|
+
"test": "vitest run",
|
|
14
|
+
"typecheck": "tsc --noEmit",
|
|
15
|
+
"lint": "eslint .",
|
|
16
|
+
"deploy": "vinext deploy",
|
|
17
|
+
"migrate:remote": "wrangler d1 migrations apply {{projectNameLower}}-db --remote"
|
|
18
|
+
},
|
|
19
|
+
"dependencies": {
|
|
20
|
+
{{dependenciesBlock}}
|
|
21
|
+
},
|
|
22
|
+
"devDependencies": {
|
|
23
|
+
"@cloudflare/vite-plugin": "^1.40.0",
|
|
24
|
+
"@cloudflare/workers-types": "^4",
|
|
25
|
+
"@notionx/create-notionx-app": "{{createNotionxAppVersion}}",
|
|
26
|
+
"@tailwindcss/vite": "^4.0.0",
|
|
27
|
+
"@types/node": "^22",
|
|
28
|
+
"@types/react": "^19",
|
|
29
|
+
"@types/react-dom": "^19",
|
|
30
|
+
"@vinext/cloudflare": "^0.1.2",
|
|
31
|
+
"@vitejs/plugin-rsc": "^0.5.0",
|
|
32
|
+
"ntn": "^0.16.0",
|
|
33
|
+
"tailwindcss": "^4.0.0",
|
|
34
|
+
"typescript": "^5.5",
|
|
35
|
+
"vinext": "^0.1.4",
|
|
36
|
+
"vite": "^8",
|
|
37
|
+
"vitest": "^2",
|
|
38
|
+
"wrangler": "^4"
|
|
39
|
+
}
|
|
40
|
+
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
// Sanity test for the generated project. Verifies that
|
|
2
|
+
// `defineContentSource` registers the content source picked in the
|
|
3
|
+
// scaffolder prompt under the expected id and that the
|
|
4
|
+
// `@notionx/core` API surface is reachable from the generated
|
|
5
|
+
// project.
|
|
6
|
+
|
|
7
|
+
import { describe, it, expect } from "vitest";
|
|
8
|
+
import { {{contentSourceVarName}} } from "../lib/content/models.ts";
|
|
9
|
+
import { pageFields, pagesDataSourceEnv } from "../lib/pages/model.ts";
|
|
10
|
+
import {
|
|
11
|
+
defineContentSource,
|
|
12
|
+
getRegisteredSource,
|
|
13
|
+
getRegisteredSources,
|
|
14
|
+
type ContentSource,
|
|
15
|
+
} from "@notionx/core/content";
|
|
16
|
+
|
|
17
|
+
describe("content source registration", () => {
|
|
18
|
+
it("uses the id chosen in the scaffolder prompt", () => {
|
|
19
|
+
expect({{contentSourceVarName}}.id).toBe("{{contentSourceId}}");
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
it("is visible in notionx's registry", () => {
|
|
23
|
+
const ids = getRegisteredSources().map((s: ContentSource) => s.id);
|
|
24
|
+
expect(ids).toContain("{{contentSourceId}}");
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
it("returns the same instance from getRegisteredSource", () => {
|
|
28
|
+
expect(getRegisteredSource("{{contentSourceId}}")).toBe({{contentSourceVarName}});
|
|
29
|
+
});
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
describe("pages model", () => {
|
|
33
|
+
it("declares the Notion fields used for navigation and page rendering", () => {
|
|
34
|
+
expect(pagesDataSourceEnv).toBe("NOTION_PAGES_DATA_SOURCE_ID");
|
|
35
|
+
expect(pageFields.key).toBe("Key");
|
|
36
|
+
expect(pageFields.showInNav).toBe("Show in Nav");
|
|
37
|
+
expect(pageFields.footerOrder).toBe("Footer Order");
|
|
38
|
+
expect(pageFields.contentSource).toBe("Content Source");
|
|
39
|
+
});
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
describe("defineContentSource", () => {
|
|
43
|
+
it("is a re-registration-safe factory", () => {
|
|
44
|
+
const id = "smoke-{{contentSourceId}}";
|
|
45
|
+
const first = defineContentSource({
|
|
46
|
+
id,
|
|
47
|
+
kind: "article",
|
|
48
|
+
visibility: { public: true, admin: false },
|
|
49
|
+
source: {
|
|
50
|
+
type: "notion",
|
|
51
|
+
tokenEnv: "NOTION_TOKEN",
|
|
52
|
+
dataSourceEnv: "NOTION_DATA_SOURCE_ID",
|
|
53
|
+
fields: { title: "Title" },
|
|
54
|
+
query: { pageSize: 10 },
|
|
55
|
+
},
|
|
56
|
+
routes: {
|
|
57
|
+
listPath: "/smoke",
|
|
58
|
+
detailPath: "/smoke/[slug]",
|
|
59
|
+
detailParam: "slug",
|
|
60
|
+
},
|
|
61
|
+
ui: {
|
|
62
|
+
name: "Smoke",
|
|
63
|
+
pluralName: "Smokes",
|
|
64
|
+
navLabel: "Smoke",
|
|
65
|
+
listTitle: "Smoke",
|
|
66
|
+
listDescription: "Smoke",
|
|
67
|
+
emptyState: "empty",
|
|
68
|
+
},
|
|
69
|
+
capabilities: {
|
|
70
|
+
richBlocks: false,
|
|
71
|
+
coverImages: false,
|
|
72
|
+
gatedAssets: false,
|
|
73
|
+
},
|
|
74
|
+
});
|
|
75
|
+
expect(getRegisteredSource(id)).toBe(first);
|
|
76
|
+
const second = defineContentSource({
|
|
77
|
+
...first,
|
|
78
|
+
ui: { ...first.ui, listTitle: "Updated" },
|
|
79
|
+
});
|
|
80
|
+
expect(getRegisteredSource(id)).toBe(second);
|
|
81
|
+
expect(getRegisteredSource(id)?.ui.listTitle).toBe("Updated");
|
|
82
|
+
});
|
|
83
|
+
});
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"lib": ["dom", "dom.iterable", "esnext"],
|
|
5
|
+
"allowJs": true,
|
|
6
|
+
"skipLibCheck": true,
|
|
7
|
+
"strict": true,
|
|
8
|
+
"noEmit": true,
|
|
9
|
+
"esModuleInterop": true,
|
|
10
|
+
"module": "esnext",
|
|
11
|
+
"moduleResolution": "bundler",
|
|
12
|
+
"allowImportingTsExtensions": true,
|
|
13
|
+
"resolveJsonModule": true,
|
|
14
|
+
"isolatedModules": true,
|
|
15
|
+
"jsx": "preserve",
|
|
16
|
+
"incremental": true,
|
|
17
|
+
"plugins": [{ "name": "next" }],
|
|
18
|
+
"paths": {
|
|
19
|
+
"@/*": ["./*"]
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
"include": [
|
|
23
|
+
"next-env.d.ts",
|
|
24
|
+
"env.d.ts",
|
|
25
|
+
"**/*.ts",
|
|
26
|
+
"**/*.tsx",
|
|
27
|
+
".next/types/**/*.ts",
|
|
28
|
+
".next/dev/types/**/*.ts"
|
|
29
|
+
],
|
|
30
|
+
"exclude": ["node_modules", "dist", ".wrangler"]
|
|
31
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { defineConfig, type Plugin } from "vite";
|
|
2
|
+
import vinext from "vinext";
|
|
3
|
+
import { cloudflare } from "@cloudflare/vite-plugin";
|
|
4
|
+
import tailwindcss from "@tailwindcss/vite";
|
|
5
|
+
import { kvDataAdapter } from "@vinext/cloudflare/cache/kv-data-adapter";
|
|
6
|
+
import { fileURLToPath } from "node:url";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Provide empty shims for `cloudflare:workers` and `next/headers` in the
|
|
10
|
+
* client environment only. The cloudflare vite plugin resolves these
|
|
11
|
+
* virtual modules in the rsc/ssr environments, and workerd provides
|
|
12
|
+
* them at runtime. The client pre-bundle scan never executes the code;
|
|
13
|
+
* it just needs the import to resolve.
|
|
14
|
+
*/
|
|
15
|
+
function serverOnlyShimsForClient(): Plugin {
|
|
16
|
+
return {
|
|
17
|
+
name: "vinext:server-only-shims-for-client",
|
|
18
|
+
enforce: "pre",
|
|
19
|
+
resolveId(id) {
|
|
20
|
+
if (this.environment?.name !== "client") return null;
|
|
21
|
+
if (id === "cloudflare:workers") {
|
|
22
|
+
return fileURLToPath(
|
|
23
|
+
new URL("./shims/cloudflare-workers-empty.mjs", import.meta.url),
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
|
+
if (id === "next/headers") {
|
|
27
|
+
return fileURLToPath(
|
|
28
|
+
new URL("./shims/next-headers-empty.mjs", import.meta.url),
|
|
29
|
+
);
|
|
30
|
+
}
|
|
31
|
+
return null;
|
|
32
|
+
},
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export default defineConfig({
|
|
37
|
+
plugins: [
|
|
38
|
+
// `kvDataAdapter()` is a config-time builder: it just returns a
|
|
39
|
+
// serializable descriptor pointing at the runtime KV cache factory.
|
|
40
|
+
// The actual KV handler is instantiated lazily on the first request
|
|
41
|
+
// (it reads the `VINEXT_KV_CACHE` binding from `env`), so this is
|
|
42
|
+
// safe to call from `vite.config.ts` — it never touches workerd.
|
|
43
|
+
vinext({ cache: { data: kvDataAdapter() } }),
|
|
44
|
+
cloudflare({ viteEnvironment: { name: "rsc", childEnvironments: ["ssr"] } }),
|
|
45
|
+
tailwindcss(),
|
|
46
|
+
serverOnlyShimsForClient(),
|
|
47
|
+
],
|
|
48
|
+
resolve: {
|
|
49
|
+
alias: {
|
|
50
|
+
"@": fileURLToPath(new URL(".", import.meta.url)),
|
|
51
|
+
},
|
|
52
|
+
},
|
|
53
|
+
});
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
// Cloudflare Worker entry point. Notionx-routed requests (health,
|
|
2
|
+
// storage, notion media) are handled by `createNotionxWorker`
|
|
3
|
+
// before falling through to the vinext app router.
|
|
4
|
+
|
|
5
|
+
import handler from "vinext/server/app-router-entry";
|
|
6
|
+
import { createNotionxWorker } from "@notionx/core/worker";
|
|
7
|
+
import { authConfig } from "../lib/auth.config";
|
|
8
|
+
import { searchAdapter } from "../lib/search/config";
|
|
9
|
+
import { adminNav } from "../lib/admin/nav";
|
|
10
|
+
import { managedContentSources } from "../lib/content/models";
|
|
11
|
+
import { siteConfig } from "../lib/site/config";
|
|
12
|
+
import { runWithRequestEnv } from "../lib/site/request-env";
|
|
13
|
+
|
|
14
|
+
const notionx = createNotionxWorker({
|
|
15
|
+
sources: [...managedContentSources],
|
|
16
|
+
adminNav,
|
|
17
|
+
// `authConfig` is `undefined` when auth is disabled (scaffolded
|
|
18
|
+
// with `--no-auth` or after `notionx remove auth`). The worker
|
|
19
|
+
// bootstrap handles `undefined` by skipping session/admin gates.
|
|
20
|
+
...(authConfig ? { authConfig } : {}),
|
|
21
|
+
// `searchAdapter` is `undefined` when search is disabled
|
|
22
|
+
// (scaffolded with `--no-search` or after `notionx remove search`).
|
|
23
|
+
// The worker bootstrap handles `undefined` by not registering
|
|
24
|
+
// the `/api/search` route.
|
|
25
|
+
...(searchAdapter ? { searchAdapter } : {}),
|
|
26
|
+
siteConfig: {
|
|
27
|
+
name: siteConfig.name,
|
|
28
|
+
description: siteConfig.description,
|
|
29
|
+
defaultLocale: siteConfig.defaultLocale,
|
|
30
|
+
locales: [...siteConfig.locales],
|
|
31
|
+
navigation: siteConfig.navigation.main as unknown as unknown[],
|
|
32
|
+
},
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
export default {
|
|
36
|
+
async fetch(
|
|
37
|
+
request: Request,
|
|
38
|
+
env: Env,
|
|
39
|
+
ctx: ExecutionContext
|
|
40
|
+
): Promise<Response> {
|
|
41
|
+
// Make `env` reachable from any async code path (RSC server
|
|
42
|
+
// components, server actions, Notion content loaders, etc.) via
|
|
43
|
+
// `getRequestEnv()`. See `lib/site/request-env.ts` for the
|
|
44
|
+
// rationale — we cannot use `cloudflare:workers.getRequestContext`
|
|
45
|
+
// because that module does not export it.
|
|
46
|
+
return runWithRequestEnv(env, async () => {
|
|
47
|
+
const notionxResponse = await notionx.fetch(request, env, ctx);
|
|
48
|
+
if (notionxResponse) return notionxResponse;
|
|
49
|
+
return handler.fetch(request, env, ctx);
|
|
50
|
+
});
|
|
51
|
+
},
|
|
52
|
+
};
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "node_modules/wrangler/config-schema.json",
|
|
3
|
+
"name": "{{projectNameLower}}",
|
|
4
|
+
"compatibility_date": "2026-06-05",
|
|
5
|
+
"compatibility_flags": ["nodejs_compat"],
|
|
6
|
+
"main": "./worker/index.ts",
|
|
7
|
+
"assets": {
|
|
8
|
+
"directory": "dist/client",
|
|
9
|
+
"not_found_handling": "none",
|
|
10
|
+
"binding": "ASSETS"
|
|
11
|
+
},
|
|
12
|
+
"images": {
|
|
13
|
+
"binding": "IMAGES"
|
|
14
|
+
},
|
|
15
|
+
"d1_databases": [
|
|
16
|
+
{
|
|
17
|
+
"binding": "DB",
|
|
18
|
+
"database_name": "{{projectNameLower}}-db",
|
|
19
|
+
"database_id": "REPLACE_WITH_D1_DATABASE_ID",
|
|
20
|
+
"migrations_dir": "migrations"
|
|
21
|
+
}
|
|
22
|
+
],
|
|
23
|
+
"kv_namespaces": [
|
|
24
|
+
{
|
|
25
|
+
"binding": "CONTENT_CACHE",
|
|
26
|
+
"id": "REPLACE_WITH_KV_NAMESPACE_ID"
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
"binding": "VINEXT_KV_CACHE",
|
|
30
|
+
"id": "REPLACE_WITH_VINEXT_KV_NAMESPACE_ID"
|
|
31
|
+
}
|
|
32
|
+
],
|
|
33
|
+
"r2_buckets": [
|
|
34
|
+
{
|
|
35
|
+
"binding": "ASSETS_BUCKET",
|
|
36
|
+
"bucket_name": "{{projectNameLower}}-assets"
|
|
37
|
+
}
|
|
38
|
+
],
|
|
39
|
+
"vars": {
|
|
40
|
+
"SITE_URL": "https://{{projectNameLower}}.example.com",
|
|
41
|
+
"NOTION_BLOCKS_DATA_SOURCE_ID": "REPLACE_WITH_NOTION_BLOCKS_DATA_SOURCE_ID",
|
|
42
|
+
"NOTION_SITE_SETTINGS_DATA_SOURCE_ID": "REPLACE_WITH_NOTION_SITE_SETTINGS_DATA_SOURCE_ID"
|
|
43
|
+
}
|
|
44
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
// packages/create-notionx-app/src/ui-presets.ts
|
|
2
|
+
//
|
|
3
|
+
// Mirrors the component list from `presets.ts` for callers that
|
|
4
|
+
// need the raw array (e.g. the README's "What's included" section)
|
|
5
|
+
// plus dependency rendering helpers. The scaffolder only ships the
|
|
6
|
+
// "site" set, so there is no preset-selection layer here.
|
|
7
|
+
const SITE_PRESET_COMPONENTS = [
|
|
8
|
+
"accordion",
|
|
9
|
+
"alert",
|
|
10
|
+
"aspect-ratio",
|
|
11
|
+
"badge",
|
|
12
|
+
"button",
|
|
13
|
+
"card",
|
|
14
|
+
"dialog",
|
|
15
|
+
"dropdown-menu",
|
|
16
|
+
"input",
|
|
17
|
+
"label",
|
|
18
|
+
"separator",
|
|
19
|
+
"sheet",
|
|
20
|
+
"skeleton",
|
|
21
|
+
"table",
|
|
22
|
+
"tabs",
|
|
23
|
+
"tooltip",
|
|
24
|
+
];
|
|
25
|
+
const BASE_DEPENDENCIES = {
|
|
26
|
+
"@radix-ui/react-slot": "^1.2.0",
|
|
27
|
+
"class-variance-authority": "^0.7.1",
|
|
28
|
+
clsx: "^2.1.1",
|
|
29
|
+
"lucide-react": "^0.460.0",
|
|
30
|
+
"next-themes": "^0.4.4",
|
|
31
|
+
"tailwind-merge": "^2.5.5",
|
|
32
|
+
"tailwindcss-animate": "^1.0.7",
|
|
33
|
+
};
|
|
34
|
+
const COMPONENT_DEPENDENCIES = {
|
|
35
|
+
accordion: { "@radix-ui/react-accordion": "^1.2.1" },
|
|
36
|
+
"aspect-ratio": { "@radix-ui/react-aspect-ratio": "^1.1.0" },
|
|
37
|
+
dialog: { "@radix-ui/react-dialog": "^1.1.2" },
|
|
38
|
+
"dropdown-menu": { "@radix-ui/react-dropdown-menu": "^2.1.2" },
|
|
39
|
+
label: { "@radix-ui/react-label": "^2.1.0" },
|
|
40
|
+
separator: { "@radix-ui/react-separator": "^1.1.0" },
|
|
41
|
+
sheet: { "@radix-ui/react-dialog": "^1.1.2" },
|
|
42
|
+
tabs: { "@radix-ui/react-tabs": "^1.1.1" },
|
|
43
|
+
tooltip: { "@radix-ui/react-tooltip": "^1.1.4" },
|
|
44
|
+
};
|
|
45
|
+
export function uiComponents() {
|
|
46
|
+
return SITE_PRESET_COMPONENTS;
|
|
47
|
+
}
|
|
48
|
+
export function uiDependencies() {
|
|
49
|
+
const deps = { ...BASE_DEPENDENCIES };
|
|
50
|
+
for (const component of SITE_PRESET_COMPONENTS) {
|
|
51
|
+
Object.assign(deps, COMPONENT_DEPENDENCIES[component]);
|
|
52
|
+
}
|
|
53
|
+
return Object.fromEntries(Object.entries(deps).sort(([a], [b]) => a.localeCompare(b)));
|
|
54
|
+
}
|
|
55
|
+
export function renderDependencyLines(deps, indent = " ") {
|
|
56
|
+
return Object.entries(deps)
|
|
57
|
+
.map(([name, version]) => `${indent}${JSON.stringify(name)}: ${JSON.stringify(version)},`)
|
|
58
|
+
.join("\n");
|
|
59
|
+
}
|
|
60
|
+
//# sourceMappingURL=ui-presets.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ui-presets.js","sourceRoot":"","sources":["../src/ui-presets.ts"],"names":[],"mappings":"AAAA,gDAAgD;AAChD,EAAE;AACF,gEAAgE;AAChE,mEAAmE;AACnE,mEAAmE;AACnE,0DAA0D;AAE1D,MAAM,sBAAsB,GAAG;IAC7B,WAAW;IACX,OAAO;IACP,cAAc;IACd,OAAO;IACP,QAAQ;IACR,MAAM;IACN,QAAQ;IACR,eAAe;IACf,OAAO;IACP,OAAO;IACP,WAAW;IACX,OAAO;IACP,UAAU;IACV,OAAO;IACP,MAAM;IACN,SAAS;CACD,CAAC;AAEX,MAAM,iBAAiB,GAA2B;IAChD,sBAAsB,EAAE,QAAQ;IAChC,0BAA0B,EAAE,QAAQ;IACpC,IAAI,EAAE,QAAQ;IACd,cAAc,EAAE,UAAU;IAC1B,aAAa,EAAE,QAAQ;IACvB,gBAAgB,EAAE,QAAQ;IAC1B,qBAAqB,EAAE,QAAQ;CAChC,CAAC;AAEF,MAAM,sBAAsB,GAA2C;IACrE,SAAS,EAAE,EAAE,2BAA2B,EAAE,QAAQ,EAAE;IACpD,cAAc,EAAE,EAAE,8BAA8B,EAAE,QAAQ,EAAE;IAC5D,MAAM,EAAE,EAAE,wBAAwB,EAAE,QAAQ,EAAE;IAC9C,eAAe,EAAE,EAAE,+BAA+B,EAAE,QAAQ,EAAE;IAC9D,KAAK,EAAE,EAAE,uBAAuB,EAAE,QAAQ,EAAE;IAC5C,SAAS,EAAE,EAAE,2BAA2B,EAAE,QAAQ,EAAE;IACpD,KAAK,EAAE,EAAE,wBAAwB,EAAE,QAAQ,EAAE;IAC7C,IAAI,EAAE,EAAE,sBAAsB,EAAE,QAAQ,EAAE;IAC1C,OAAO,EAAE,EAAE,yBAAyB,EAAE,QAAQ,EAAE;CACjD,CAAC;AAEF,MAAM,UAAU,YAAY;IAC1B,OAAO,sBAAsB,CAAC;AAChC,CAAC;AAED,MAAM,UAAU,cAAc;IAC5B,MAAM,IAAI,GAA2B,EAAE,GAAG,iBAAiB,EAAE,CAAC;IAC9D,KAAK,MAAM,SAAS,IAAI,sBAAsB,EAAE,CAAC;QAC/C,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,sBAAsB,CAAC,SAAS,CAAC,CAAC,CAAC;IACzD,CAAC;IACD,OAAO,MAAM,CAAC,WAAW,CACvB,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAC5D,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,qBAAqB,CACnC,IAA4B,EAC5B,MAAM,GAAG,MAAM;IAEf,OAAO,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC;SACxB,GAAG,CACF,CAAC,CAAC,IAAI,EAAE,OAAO,CAAC,EAAE,EAAE,CAClB,GAAG,MAAM,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,KAAK,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,GAAG,CAClE;SACA,IAAI,CAAC,IAAI,CAAC,CAAC;AAChB,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@notionx/create-notionx-app",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Scaffold a new vinext (Next.js on Cloudflare Workers + D1 + R2) project backed by @notionx/core, with one-step provisioning of D1 / KV / R2 / Turnstile / Notion / Resend / Google OAuth.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"create-notionx-app": "./dist/index.js",
|
|
8
|
+
"notionx": "./dist/cli-notionx.js"
|
|
9
|
+
},
|
|
10
|
+
"files": [
|
|
11
|
+
"dist",
|
|
12
|
+
"README.md"
|
|
13
|
+
],
|
|
14
|
+
"keywords": [
|
|
15
|
+
"vinext",
|
|
16
|
+
"notionx",
|
|
17
|
+
"notionx",
|
|
18
|
+
"nextjs",
|
|
19
|
+
"cloudflare",
|
|
20
|
+
"workers",
|
|
21
|
+
"d1",
|
|
22
|
+
"r2",
|
|
23
|
+
"turnstile",
|
|
24
|
+
"notion",
|
|
25
|
+
"scaffold",
|
|
26
|
+
"create-notionx-app"
|
|
27
|
+
],
|
|
28
|
+
"license": "MIT",
|
|
29
|
+
"engines": {
|
|
30
|
+
"node": ">=22"
|
|
31
|
+
},
|
|
32
|
+
"dependencies": {
|
|
33
|
+
"@clack/prompts": "^0.7"
|
|
34
|
+
},
|
|
35
|
+
"devDependencies": {
|
|
36
|
+
"@types/node": "^22",
|
|
37
|
+
"tsx": "^4",
|
|
38
|
+
"typescript": "^5.5",
|
|
39
|
+
"vitest": "^3.2.4"
|
|
40
|
+
},
|
|
41
|
+
"publishConfig": {
|
|
42
|
+
"access": "public",
|
|
43
|
+
"registry": "https://registry.npmjs.org/"
|
|
44
|
+
},
|
|
45
|
+
"repository": {
|
|
46
|
+
"type": "git",
|
|
47
|
+
"url": "https://github.com/digwis/nextion.git",
|
|
48
|
+
"directory": "packages/create-notionx-app"
|
|
49
|
+
},
|
|
50
|
+
"author": "zhaofilms",
|
|
51
|
+
"homepage": "https://github.com/digwis/nextion#readme",
|
|
52
|
+
"bugs": {
|
|
53
|
+
"url": "https://github.com/digwis/nextion/issues"
|
|
54
|
+
},
|
|
55
|
+
"scripts": {
|
|
56
|
+
"build": "tsc -p tsconfig.json && node scripts/copy-templates.mjs",
|
|
57
|
+
"dev": "tsx src/index.ts",
|
|
58
|
+
"test": "vitest run"
|
|
59
|
+
}
|
|
60
|
+
}
|