create-prenta 1.3.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.
Files changed (49) hide show
  1. package/CHANGELOG.md +964 -0
  2. package/LICENSE +21 -0
  3. package/assets/prisma/migrations/0001_init/migration.sql +941 -0
  4. package/assets/prisma/migrations/0002_media_usage_field_path/migration.sql +11 -0
  5. package/assets/prisma/migrations/0003_ai_crawler_hits/migration.sql +21 -0
  6. package/assets/prisma/migrations/0004_drop_search_vector/migration.sql +4 -0
  7. package/assets/prisma/migrations/0005_script_tag_delivery_controls/migration.sql +8 -0
  8. package/assets/prisma/migrations/0006_totp_last_step/migration.sql +4 -0
  9. package/assets/prisma/migrations/0007_workflow_fk_drop_dead_enums/migration.sql +27 -0
  10. package/assets/prisma/migrations/0008_form_delivery_attempts/migration.sql +29 -0
  11. package/assets/prisma/migrations/0009_webhook_secret_rotation/migration.sql +6 -0
  12. package/assets/prisma/migrations/0010_media_is_decorative/migration.sql +3 -0
  13. package/assets/prisma/migrations/0011_media_content_hash/migration.sql +4 -0
  14. package/assets/prisma/migrations/0012_rename_to_prenta/migration.sql +89 -0
  15. package/assets/prisma/migrations/migration_lock.toml +3 -0
  16. package/assets/prisma/schema.prisma +989 -0
  17. package/dist/index.d.ts +3 -0
  18. package/dist/index.d.ts.map +1 -0
  19. package/dist/index.js +182 -0
  20. package/dist/index.js.map +1 -0
  21. package/dist/options.d.ts +160 -0
  22. package/dist/options.d.ts.map +1 -0
  23. package/dist/options.js +206 -0
  24. package/dist/options.js.map +1 -0
  25. package/dist/scaffold.d.ts +45 -0
  26. package/dist/scaffold.d.ts.map +1 -0
  27. package/dist/scaffold.js +2163 -0
  28. package/dist/scaffold.js.map +1 -0
  29. package/dist/templates/admin-page.ts.template.d.ts +24 -0
  30. package/dist/templates/admin-page.ts.template.d.ts.map +1 -0
  31. package/dist/templates/admin-page.ts.template.js +145 -0
  32. package/dist/templates/admin-page.ts.template.js.map +1 -0
  33. package/dist/templates/astro-site.d.ts +36 -0
  34. package/dist/templates/astro-site.d.ts.map +1 -0
  35. package/dist/templates/astro-site.js +918 -0
  36. package/dist/templates/astro-site.js.map +1 -0
  37. package/dist/templates/login-page.ts.template.d.ts +14 -0
  38. package/dist/templates/login-page.ts.template.d.ts.map +1 -0
  39. package/dist/templates/login-page.ts.template.js +143 -0
  40. package/dist/templates/login-page.ts.template.js.map +1 -0
  41. package/dist/templates/marketing-custom.d.ts +56 -0
  42. package/dist/templates/marketing-custom.d.ts.map +1 -0
  43. package/dist/templates/marketing-custom.js +814 -0
  44. package/dist/templates/marketing-custom.js.map +1 -0
  45. package/dist/templates/prenta.config.ts.template.d.ts +3 -0
  46. package/dist/templates/prenta.config.ts.template.d.ts.map +1 -0
  47. package/dist/templates/prenta.config.ts.template.js +253 -0
  48. package/dist/templates/prenta.config.ts.template.js.map +1 -0
  49. package/package.json +58 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"astro-site.js","sourceRoot":"","sources":["../../src/templates/astro-site.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ export interface LoginPageOptions {
2
+ /** Mount path of the login screens (e.g. '/securelogin'). */
3
+ loginPath: string;
4
+ /** Where the signed-in admin app lives (e.g. '/admin'). */
5
+ adminPath: string;
6
+ }
7
+ /**
8
+ * Split-login installs: a standalone page (mounted at `loginPath`) that
9
+ * renders `LoginRoot` — login + MFA, the first-run setup wizard, and the
10
+ * forgot/reset-password flows. After sign-in it hands off to the admin app
11
+ * at `adminPath` with a full-page navigation.
12
+ */
13
+ export declare function generateLoginPage(options: LoginPageOptions): string;
14
+ //# sourceMappingURL=login-page.ts.template.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"login-page.ts.template.d.ts","sourceRoot":"","sources":["../../src/templates/login-page.ts.template.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,gBAAgB;IAC/B,6DAA6D;IAC7D,SAAS,EAAE,MAAM,CAAA;IACjB,2DAA2D;IAC3D,SAAS,EAAE,MAAM,CAAA;CAClB;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,gBAAgB,GAAG,MAAM,CAuInE"}
@@ -0,0 +1,143 @@
1
+ /**
2
+ * Split-login installs: a standalone page (mounted at `loginPath`) that
3
+ * renders `LoginRoot` — login + MFA, the first-run setup wizard, and the
4
+ * forgot/reset-password flows. After sign-in it hands off to the admin app
5
+ * at `adminPath` with a full-page navigation.
6
+ */
7
+ export function generateLoginPage(options) {
8
+ return `'use client';
9
+
10
+ import { useState, useEffect } from 'react';
11
+ import { LoginRoot, cmsApi } from '@prenta/admin';
12
+ import type { CaptchaConfig } from '@prenta/admin';
13
+ import config from '../../../../prenta.config';
14
+
15
+ export default function LoginPage() {
16
+ const [session, setSession] = useState<any>(null);
17
+ const [setupRequired, setSetupRequired] = useState(false);
18
+ const [loading, setLoading] = useState(true);
19
+ const [statusError, setStatusError] = useState<string | null>(null);
20
+ const [captchaConfig, setCaptchaConfig] = useState<CaptchaConfig | undefined>(undefined);
21
+
22
+ useEffect(() => {
23
+ async function checkAuth() {
24
+ const [setupRes, captchaRes] = await Promise.all([
25
+ cmsApi<{ setupRequired: boolean; migrationsRequired?: boolean }>('/setup/status'),
26
+ cmsApi<{ provider: string; siteKey: string | null }>('/captcha/config'),
27
+ ]);
28
+
29
+ if (captchaRes.data) {
30
+ setCaptchaConfig(captchaRes.data as CaptchaConfig);
31
+ }
32
+
33
+ // Database is reachable but has no Prenta CMS tables yet — tell the
34
+ // operator to run migrations instead of dropping them on the login screen.
35
+ if (setupRes.data?.migrationsRequired) {
36
+ setStatusError('Your database has no Prenta CMS tables yet. Run \`npx prisma migrate deploy\` against your database, then reload this page.');
37
+ setLoading(false);
38
+ return;
39
+ }
40
+
41
+ // The status check itself failed (e.g. the database is unreachable).
42
+ if (setupRes.error) {
43
+ setStatusError('Could not reach the CMS backend: ' + setupRes.error);
44
+ setLoading(false);
45
+ return;
46
+ }
47
+
48
+ if (setupRes.data?.setupRequired) {
49
+ setSetupRequired(true);
50
+ setLoading(false);
51
+ return;
52
+ }
53
+ const meRes = await cmsApi<{ id: string; email: string; name: string; role: string }>('/auth/me');
54
+ if (meRes.data) {
55
+ setSession({ user: meRes.data });
56
+ }
57
+ setLoading(false);
58
+ }
59
+ checkAuth();
60
+ }, []);
61
+
62
+ const handleLogin = async (email: string, password: string, captchaToken?: string) => {
63
+ const res = await cmsApi<{
64
+ token?: string;
65
+ user?: any;
66
+ requiresTOTP?: boolean;
67
+ mfaPendingToken?: string;
68
+ }>('/auth/login', {
69
+ method: 'POST',
70
+ body: JSON.stringify({ email, password, captchaToken }),
71
+ });
72
+ if (res.error) return { success: false, error: res.error };
73
+ // Account has MFA enabled — password verified, advance to the TOTP step.
74
+ if (res.data?.requiresTOTP && res.data.mfaPendingToken) {
75
+ return { success: false, requiresTOTP: true, mfaPendingToken: res.data.mfaPendingToken };
76
+ }
77
+ if (res.data?.user) {
78
+ setSession({ user: res.data.user });
79
+ }
80
+ return { success: true };
81
+ };
82
+
83
+ const handleVerifyTotp = async (mfaPendingToken: string, code: string) => {
84
+ const res = await cmsApi<{ token: string; user: any }>('/auth/totp/login', {
85
+ method: 'POST',
86
+ body: JSON.stringify({ mfaPendingToken, code }),
87
+ });
88
+ if (res.error) return { success: false, error: res.error };
89
+ if (res.data?.user) {
90
+ setSession({ user: res.data.user });
91
+ }
92
+ return { success: true };
93
+ };
94
+
95
+ const handleSetupComplete = async (data: { name: string; email: string; password: string }) => {
96
+ const res = await cmsApi<any>('/setup/create-admin', {
97
+ method: 'POST',
98
+ body: JSON.stringify(data),
99
+ });
100
+ if (res.error) return { success: false, error: res.error };
101
+ setSetupRequired(false);
102
+ return handleLogin(data.email, data.password);
103
+ };
104
+
105
+ if (loading) {
106
+ return (
107
+ <div className="prenta-admin" style={{ minHeight: '100vh', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
108
+ <div style={{ width: 24, height: 24, border: '3px solid #e5e7eb', borderTopColor: '#2563eb', borderRadius: '50%', animation: 'spin 1s linear infinite' }} />
109
+ <style>{\`@keyframes spin { to { transform: rotate(360deg) } }\`}</style>
110
+ </div>
111
+ );
112
+ }
113
+
114
+ if (statusError) {
115
+ return (
116
+ <div className="prenta-admin" style={{ minHeight: '100vh', display: 'flex', alignItems: 'center', justifyContent: 'center', padding: 24 }}>
117
+ <div style={{ maxWidth: 520, width: '100%', border: '1px solid #e5e7eb', borderRadius: 12, padding: '28px 32px', background: '#fff', color: '#111827' }}>
118
+ <h1 style={{ fontSize: '1.25rem', fontWeight: 500, margin: '0 0 8px' }}>Setup can&apos;t continue yet</h1>
119
+ <p style={{ margin: 0, color: '#6b7280', lineHeight: 1.5 }}>{statusError}</p>
120
+ </div>
121
+ </div>
122
+ );
123
+ }
124
+
125
+ return (
126
+ <div className="prenta-admin">
127
+ <LoginRoot
128
+ config={config}
129
+ session={session}
130
+ basePath="${options.loginPath}"
131
+ adminPath="${options.adminPath}"
132
+ setupRequired={setupRequired}
133
+ onSetupComplete={handleSetupComplete}
134
+ onLogin={handleLogin}
135
+ onVerifyTotp={handleVerifyTotp}
136
+ captchaConfig={captchaConfig}
137
+ />
138
+ </div>
139
+ );
140
+ }
141
+ `;
142
+ }
143
+ //# sourceMappingURL=login-page.ts.template.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"login-page.ts.template.js","sourceRoot":"","sources":["../../src/templates/login-page.ts.template.ts"],"names":[],"mappings":"AAOA;;;;;GAKG;AACH,MAAM,UAAU,iBAAiB,CAAC,OAAyB;IACzD,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;oBA0HW,OAAO,CAAC,SAAS;qBAChB,OAAO,CAAC,SAAS;;;;;;;;;;CAUrC,CAAA;AACD,CAAC"}
@@ -0,0 +1,56 @@
1
+ /**
2
+ * `marketing-custom` starter template.
3
+ *
4
+ * Layers a "build a custom marketing site" workflow on top of the default
5
+ * scaffold:
6
+ * - `src/sections/types.ts` — custom section-type schema wired into
7
+ * `prenta.config.ts` (`sections.types`), so
8
+ * the admin editor can author them.
9
+ * - `src/sections/register.tsx` — ONE renderer map used for BOTH the public
10
+ * site (registered for `<Sections>`) and the
11
+ * admin editor canvas (`<AdminRoot
12
+ * sectionRenderers>`).
13
+ * - `src/blocks/Pricing.tsx` — a typed presentational component whose props
14
+ * `component-blocks` extracts into a manifest.
15
+ * - `scripts/verify-sections.mjs` — fast static check that every declared
16
+ * section type has a renderer (no dead types).
17
+ * - `.cursor/skills/prenta-add-section/SKILL.md` — an agent contract for
18
+ * turning a designed section into an editable
19
+ * one (schema + renderer + seed, in sync).
20
+ * - `npm run blocks:extract` / `blocks:diff` / `verify:sections` scripts.
21
+ *
22
+ * Everything else (config, layouts, Prisma, CI) comes from the default scaffold.
23
+ */
24
+ import type { ProjectOptions } from '../scaffold.js';
25
+ /** True when the project opted into the marketing-custom starter. */
26
+ export declare function isMarketingCustom(options: ProjectOptions): boolean;
27
+ /** Extra package.json scripts for the component-blocks workflow. */
28
+ export declare const MARKETING_CUSTOM_SCRIPTS: Record<string, string>;
29
+ /** Extra `.gitignore` entries (the throwaway manifest `blocks:diff` writes). */
30
+ export declare const MARKETING_CUSTOM_GITIGNORE: string[];
31
+ /**
32
+ * Files emitted for the marketing-custom template, keyed by project-relative
33
+ * POSIX path. The scaffolder creates parent dirs and writes each entry.
34
+ */
35
+ export declare function marketingCustomFiles(): Record<string, string>;
36
+ /**
37
+ * Files for the shared section kit in an astro-split **pnpm workspace**
38
+ * scaffold, keyed by project-root-relative POSIX path.
39
+ *
40
+ * The kit is the single source of truth for the three-layer section contract:
41
+ * 1. schema (`packages/sections/src/types.ts`) → `apps/cms/prenta.config.ts`
42
+ * 2. ONE renderer map (`packages/sections/src/register.tsx`) → admin canvas
43
+ * (`<AdminRoot sectionRenderers>`) **and** the Astro public site
44
+ * (side-effect import in `PageSections.tsx` → `<Sections>`)
45
+ * 3. `verify:sections` keeps schema ids and renderer keys in lockstep.
46
+ *
47
+ * The package ships raw TypeScript source: Next compiles it via
48
+ * `transpilePackages`, and Vite/Astro processes linked workspace deps natively.
49
+ */
50
+ export declare function workspaceSectionKitFiles(opts: {
51
+ /** Workspace package name for the kit, e.g. `@my-site/sections`. */
52
+ packageName: string;
53
+ /** Resolved `@prenta/*` version ranges (falls back per-entry). */
54
+ versions: Record<string, string>;
55
+ }): Record<string, string>;
56
+ //# sourceMappingURL=marketing-custom.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"marketing-custom.d.ts","sourceRoot":"","sources":["../../src/templates/marketing-custom.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAA;AAEpD,qEAAqE;AACrE,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAElE;AAED,oEAAoE;AACpE,eAAO,MAAM,wBAAwB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAM3D,CAAA;AAED,gFAAgF;AAChF,eAAO,MAAM,0BAA0B,EAAE,MAAM,EAAiC,CAAA;AAEhF;;;GAGG;AACH,wBAAgB,oBAAoB,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAU7D;AAUD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,wBAAwB,CAAC,IAAI,EAAE;IAC7C,oEAAoE;IACpE,WAAW,EAAE,MAAM,CAAA;IACnB,kEAAkE;IAClE,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CACjC,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAiFzB"}