create-smoodly-app 0.0.29 → 0.0.31
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 +33 -2
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/templates/blank/AGENTS.md +6 -2
- package/templates/blank/package.json +1 -1
- package/templates/blank/smoodly/server.ts +4 -1
- package/templates/blank-intl/AGENTS.md +6 -2
- package/templates/blank-intl/package.json +1 -1
- package/templates/blank-intl/smoodly/server.ts +4 -1
- package/templates/lorem/AGENTS.md +6 -2
- package/templates/lorem/package.json +1 -1
- package/templates/lorem/scripts/seed.ts +3 -3
- package/templates/lorem/smoodly/server.ts +4 -1
- package/templates/lorem-intl/AGENTS.md +6 -2
- package/templates/lorem-intl/package.json +1 -1
- package/templates/lorem-intl/scripts/seed.ts +3 -3
- package/templates/lorem-intl/smoodly/server.ts +4 -1
package/README.md
CHANGED
|
@@ -15,8 +15,8 @@ sign in. Spec: `docs/superpowers/specs/2026-09-04-create-smoodly-app-design.md`.
|
|
|
15
15
|
`proxy.ts`, translated URLs per locale. Flag: `--locales en,fi`.
|
|
16
16
|
3. Where content lives: a **local Supabase stack** (`supabase init` +
|
|
17
17
|
`supabase start` inside the app, with the services Smoodly never uses
|
|
18
|
-
excluded — the image proxy, edge functions, analytics,
|
|
19
|
-
|
|
18
|
+
excluded — the image proxy, edge functions, analytics, the pooler —
|
|
19
|
+
so the stack stays small beside any other you run; needs
|
|
20
20
|
the Supabase CLI and Docker; when
|
|
21
21
|
another project holds the default `543xx` ports the new one moves to the
|
|
22
22
|
next free block, `553xx` and so on, and says so) or a
|
|
@@ -82,6 +82,37 @@ Posts and the Site item, a post with a Button element published and
|
|
|
82
82
|
served at `/posts/<slug>` in both locales; blank single-language
|
|
83
83
|
scaffolded in hosted mode against the repo stack and `next build` only.
|
|
84
84
|
|
|
85
|
+
## Follow-ups (logged 2026-09-28, fresh-install proof of 0.0.30)
|
|
86
|
+
|
|
87
|
+
Walked 2026-09-28: `npx create-smoodly-app@0.0.30 proof-0030 --supabase
|
|
88
|
+
local --yes --editor-email …` from the published package, in a scratch
|
|
89
|
+
directory beside three running stacks (the new one took the `563xx`
|
|
90
|
+
block). `smoodly` 0.0.30 installed, `tsc` and `next build` clean, `/`,
|
|
91
|
+
`/posts`, `/posts/<slug>`, `/company/about-us` and `/admin` 200, the
|
|
92
|
+
admin document's `<html lang="en">` present, the editor signed in, an
|
|
93
|
+
SEO title edit saved and published and served on `/`. Found:
|
|
94
|
+
|
|
95
|
+
- **Local mode left Realtime out (0.0.26–0.0.30).** `LOCAL_START_ARGS`
|
|
96
|
+
excluded `realtime` from before the concurrency spec, whose presence
|
|
97
|
+
channel and `saved` events ride it; the admin retried the WebSocket
|
|
98
|
+
forever (a console error per attempt) and a local install had no
|
|
99
|
+
presence or stale-page notice. CI's repo stack already kept Realtime.
|
|
100
|
+
Fixed 2026-09-28: the list no longer excludes it; restarted with the new
|
|
101
|
+
flags, a script signed in as the editor joined `space:<id>` and saw both
|
|
102
|
+
open admin tabs tracked on Home. The live job does not catch this
|
|
103
|
+
(it requests `/admin` once, no browser); an existing local install
|
|
104
|
+
restarts with `supabase stop && supabase start -x imgproxy,edge-runtime,logflare,vector,supavisor`.
|
|
105
|
+
- **The Lorem home's custom-section CTA linked `/articles`**, a 404 —
|
|
106
|
+
the articles collection lives at `/posts`. `examples/site/scripts/seed.ts`
|
|
107
|
+
hardcoded the href; fixed 2026-09-28 to `paths(locale).articles` like
|
|
108
|
+
every other starter link (Finnish gets its own segment too).
|
|
109
|
+
- **`--editor-email` without `SMOODLY_EDITOR_PASSWORD` fails late.** The
|
|
110
|
+
check lives in `askEditorWith`, which runs after the copy, install,
|
|
111
|
+
`git init` and `supabase start`, so the run stops at `ensureEditor`
|
|
112
|
+
with a half-made app. It has to be late for hosted mode (the email may
|
|
113
|
+
name an existing Auth user, no password needed), but a local stack is
|
|
114
|
+
always fresh, so local mode could refuse up front. Not fixed.
|
|
115
|
+
|
|
85
116
|
## Follow-ups (logged 2026-09-25, docs walk)
|
|
86
117
|
|
|
87
118
|
- **Single-language `/admin` had no root `<html>` (0.0.15–0.0.20).** The
|
package/dist/index.js
CHANGED
|
@@ -413,7 +413,7 @@ function parseStatusEnv(output) {
|
|
|
413
413
|
}
|
|
414
414
|
|
|
415
415
|
// src/run.ts
|
|
416
|
-
var LOCAL_START_ARGS = ["start", "-x", "imgproxy,edge-runtime,logflare,vector,
|
|
416
|
+
var LOCAL_START_ARGS = ["start", "-x", "imgproxy,edge-runtime,logflare,vector,supavisor"];
|
|
417
417
|
async function run(answers2, deps) {
|
|
418
418
|
if (answers2.supabase === "hosted" && !answers2.hosted) {
|
|
419
419
|
throw new Error("hosted answers need the project's keys");
|
package/package.json
CHANGED
|
@@ -22,8 +22,12 @@ where things are.
|
|
|
22
22
|
written through the page and entry stores, never raw SQL. It is
|
|
23
23
|
idempotent; run it with `npm run seed`.
|
|
24
24
|
- **Never import the admin into the site.** Nothing under `app/(site)`,
|
|
25
|
-
`app/[locale]` or `components
|
|
26
|
-
`smoodly/
|
|
25
|
+
`app/[locale]` or `components/`, and nothing they import
|
|
26
|
+
(`smoodly/server.ts` included), may import `@/smoodly/admin` or
|
|
27
|
+
`smoodly/admin/next`: Next ships every client module a route imports,
|
|
28
|
+
rendered or not, and the admin's chunk must not reach visitors. The
|
|
29
|
+
package's `smoodly/admin` entry has no client code; server-side
|
|
30
|
+
admin glue such as `supabaseAdminAuth` comes from there.
|
|
27
31
|
- **Two root layouts.** The site's layout lives in its route group or
|
|
28
32
|
locale segment and is never the admin's parent; `app/(smoodly)/admin`
|
|
29
33
|
is a second root layout. Do not add an `app/layout.tsx`.
|
|
@@ -11,7 +11,10 @@
|
|
|
11
11
|
import {
|
|
12
12
|
createSmoodlyClient, createSmoodlySite, publicContentConfig, smoodlyEnv, SupabaseAssetStore, SupabaseEntryStore, SupabaseMemberStore, SupabasePageStore, SupabasePathIndex, type ContentConfig, type SmoodlySite,
|
|
13
13
|
} from "smoodly";
|
|
14
|
-
|
|
14
|
+
// The admin gate from `smoodly/admin`, which holds no client code: the site
|
|
15
|
+
// routes import this file, and `smoodly/admin/next` would put the admin
|
|
16
|
+
// shell in every live page's JavaScript.
|
|
17
|
+
import { supabaseAdminAuth, type AdminAuth, type AuthConfig } from "smoodly/admin";
|
|
15
18
|
import { createPageRenderer, createSmoodlyQueries, type PageRegistration } from "smoodly/next";
|
|
16
19
|
import type { SupabaseClient } from "@supabase/supabase-js";
|
|
17
20
|
import { collections, config, elements, sections, globals } from "./config";
|
|
@@ -22,8 +22,12 @@ where things are.
|
|
|
22
22
|
written through the page and entry stores, never raw SQL. It is
|
|
23
23
|
idempotent; run it with `npm run seed`.
|
|
24
24
|
- **Never import the admin into the site.** Nothing under `app/(site)`,
|
|
25
|
-
`app/[locale]` or `components
|
|
26
|
-
`smoodly/
|
|
25
|
+
`app/[locale]` or `components/`, and nothing they import
|
|
26
|
+
(`smoodly/server.ts` included), may import `@/smoodly/admin` or
|
|
27
|
+
`smoodly/admin/next`: Next ships every client module a route imports,
|
|
28
|
+
rendered or not, and the admin's chunk must not reach visitors. The
|
|
29
|
+
package's `smoodly/admin` entry has no client code; server-side
|
|
30
|
+
admin glue such as `supabaseAdminAuth` comes from there.
|
|
27
31
|
- **Two root layouts.** The site's layout lives in its route group or
|
|
28
32
|
locale segment and is never the admin's parent; `app/(smoodly)/admin`
|
|
29
33
|
is a second root layout. Do not add an `app/layout.tsx`.
|
|
@@ -11,7 +11,10 @@
|
|
|
11
11
|
import {
|
|
12
12
|
createSmoodlyClient, createSmoodlySite, publicContentConfig, smoodlyEnv, SupabaseAssetStore, SupabaseEntryStore, SupabaseMemberStore, SupabasePageStore, SupabasePathIndex, type ContentConfig, type SmoodlySite,
|
|
13
13
|
} from "smoodly";
|
|
14
|
-
|
|
14
|
+
// The admin gate from `smoodly/admin`, which holds no client code: the site
|
|
15
|
+
// routes import this file, and `smoodly/admin/next` would put the admin
|
|
16
|
+
// shell in every live page's JavaScript.
|
|
17
|
+
import { supabaseAdminAuth, type AdminAuth, type AuthConfig } from "smoodly/admin";
|
|
15
18
|
import { createPageRenderer, createSmoodlyQueries, type PageRegistration } from "smoodly/next";
|
|
16
19
|
import type { SupabaseClient } from "@supabase/supabase-js";
|
|
17
20
|
import { getPathname } from "@/i18n/navigation";
|
|
@@ -22,8 +22,12 @@ where things are.
|
|
|
22
22
|
written through the page and entry stores, never raw SQL. It is
|
|
23
23
|
idempotent; run it with `npm run seed`.
|
|
24
24
|
- **Never import the admin into the site.** Nothing under `app/(site)`,
|
|
25
|
-
`app/[locale]` or `components
|
|
26
|
-
`smoodly/
|
|
25
|
+
`app/[locale]` or `components/`, and nothing they import
|
|
26
|
+
(`smoodly/server.ts` included), may import `@/smoodly/admin` or
|
|
27
|
+
`smoodly/admin/next`: Next ships every client module a route imports,
|
|
28
|
+
rendered or not, and the admin's chunk must not reach visitors. The
|
|
29
|
+
package's `smoodly/admin` entry has no client code; server-side
|
|
30
|
+
admin glue such as `supabaseAdminAuth` comes from there.
|
|
27
31
|
- **Two root layouts.** The site's layout lives in its route group or
|
|
28
32
|
locale segment and is never the admin's parent; `app/(smoodly)/admin`
|
|
29
33
|
is a second root layout. Do not add an `app/layout.tsx`.
|
|
@@ -255,7 +255,7 @@ const favourites = (heading: string): Node => ({
|
|
|
255
255
|
|
|
256
256
|
// The custom section (spec 2026-09-14 §6): the editor's own rows of
|
|
257
257
|
// richtext columns, widths in twelfths; Smoodly renders its layout CSS.
|
|
258
|
-
const customSection = (): Node => ({
|
|
258
|
+
const customSection = (locale: string): Node => ({
|
|
259
259
|
id: "node-custom",
|
|
260
260
|
type: "custom",
|
|
261
261
|
fields: { rows: [
|
|
@@ -263,7 +263,7 @@ const customSection = (): Node => ({
|
|
|
263
263
|
doc(h2("Sed ut perspiciatis"), p("Unde omnis iste natus error sit voluptatem accusantium doloremque laudantium.")),
|
|
264
264
|
doc(p("Totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo."), callout("Nemo enim", "Ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit.", "info")),
|
|
265
265
|
] },
|
|
266
|
-
{ spans: [12], gap: "md", align: "top", reverse: false, columns: [doc(cta("Neque porro quisquam", "Qui dolorem ipsum quia dolor sit amet.", "Read the articles",
|
|
266
|
+
{ spans: [12], gap: "md", align: "top", reverse: false, columns: [doc(cta("Neque porro quisquam", "Qui dolorem ipsum quia dolor sit amet.", "Read the articles", paths(locale).articles))] },
|
|
267
267
|
] },
|
|
268
268
|
styles: { spacingBottom: "lg" },
|
|
269
269
|
});
|
|
@@ -288,7 +288,7 @@ const homeTree = (locale: string, t: { kicker: string; buttons: [string, string]
|
|
|
288
288
|
image: img.hero,
|
|
289
289
|
},
|
|
290
290
|
}],
|
|
291
|
-
body: [imageText(locale, t.link), quote, points, customSection(), favourites(t.favourites)],
|
|
291
|
+
body: [imageText(locale, t.link), quote, points, customSection(locale), favourites(t.favourites)],
|
|
292
292
|
},
|
|
293
293
|
});
|
|
294
294
|
|
|
@@ -11,7 +11,10 @@
|
|
|
11
11
|
import {
|
|
12
12
|
createSmoodlyClient, createSmoodlySite, publicContentConfig, smoodlyEnv, SupabaseAssetStore, SupabaseEntryStore, SupabaseMemberStore, SupabasePageStore, SupabasePathIndex, type ContentConfig, type SmoodlySite,
|
|
13
13
|
} from "smoodly";
|
|
14
|
-
|
|
14
|
+
// The admin gate from `smoodly/admin`, which holds no client code: the site
|
|
15
|
+
// routes import this file, and `smoodly/admin/next` would put the admin
|
|
16
|
+
// shell in every live page's JavaScript.
|
|
17
|
+
import { supabaseAdminAuth, type AdminAuth, type AuthConfig } from "smoodly/admin";
|
|
15
18
|
import { createPageRenderer, createSmoodlyQueries, type PageRegistration } from "smoodly/next";
|
|
16
19
|
import type { SupabaseClient } from "@supabase/supabase-js";
|
|
17
20
|
import { collections, config, elements, sections, globals } from "./config";
|
|
@@ -22,8 +22,12 @@ where things are.
|
|
|
22
22
|
written through the page and entry stores, never raw SQL. It is
|
|
23
23
|
idempotent; run it with `npm run seed`.
|
|
24
24
|
- **Never import the admin into the site.** Nothing under `app/(site)`,
|
|
25
|
-
`app/[locale]` or `components
|
|
26
|
-
`smoodly/
|
|
25
|
+
`app/[locale]` or `components/`, and nothing they import
|
|
26
|
+
(`smoodly/server.ts` included), may import `@/smoodly/admin` or
|
|
27
|
+
`smoodly/admin/next`: Next ships every client module a route imports,
|
|
28
|
+
rendered or not, and the admin's chunk must not reach visitors. The
|
|
29
|
+
package's `smoodly/admin` entry has no client code; server-side
|
|
30
|
+
admin glue such as `supabaseAdminAuth` comes from there.
|
|
27
31
|
- **Two root layouts.** The site's layout lives in its route group or
|
|
28
32
|
locale segment and is never the admin's parent; `app/(smoodly)/admin`
|
|
29
33
|
is a second root layout. Do not add an `app/layout.tsx`.
|
|
@@ -255,7 +255,7 @@ const favourites = (heading: string): Node => ({
|
|
|
255
255
|
|
|
256
256
|
// The custom section (spec 2026-09-14 §6): the editor's own rows of
|
|
257
257
|
// richtext columns, widths in twelfths; Smoodly renders its layout CSS.
|
|
258
|
-
const customSection = (): Node => ({
|
|
258
|
+
const customSection = (locale: string): Node => ({
|
|
259
259
|
id: "node-custom",
|
|
260
260
|
type: "custom",
|
|
261
261
|
fields: { rows: [
|
|
@@ -263,7 +263,7 @@ const customSection = (): Node => ({
|
|
|
263
263
|
doc(h2("Sed ut perspiciatis"), p("Unde omnis iste natus error sit voluptatem accusantium doloremque laudantium.")),
|
|
264
264
|
doc(p("Totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo."), callout("Nemo enim", "Ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit.", "info")),
|
|
265
265
|
] },
|
|
266
|
-
{ spans: [12], gap: "md", align: "top", reverse: false, columns: [doc(cta("Neque porro quisquam", "Qui dolorem ipsum quia dolor sit amet.", "Read the articles",
|
|
266
|
+
{ spans: [12], gap: "md", align: "top", reverse: false, columns: [doc(cta("Neque porro quisquam", "Qui dolorem ipsum quia dolor sit amet.", "Read the articles", paths(locale).articles))] },
|
|
267
267
|
] },
|
|
268
268
|
styles: { spacingBottom: "lg" },
|
|
269
269
|
});
|
|
@@ -288,7 +288,7 @@ const homeTree = (locale: string, t: { kicker: string; buttons: [string, string]
|
|
|
288
288
|
image: img.hero,
|
|
289
289
|
},
|
|
290
290
|
}],
|
|
291
|
-
body: [imageText(locale, t.link), quote, points, customSection(), favourites(t.favourites)],
|
|
291
|
+
body: [imageText(locale, t.link), quote, points, customSection(locale), favourites(t.favourites)],
|
|
292
292
|
},
|
|
293
293
|
});
|
|
294
294
|
|
|
@@ -11,7 +11,10 @@
|
|
|
11
11
|
import {
|
|
12
12
|
createSmoodlyClient, createSmoodlySite, publicContentConfig, smoodlyEnv, SupabaseAssetStore, SupabaseEntryStore, SupabaseMemberStore, SupabasePageStore, SupabasePathIndex, type ContentConfig, type SmoodlySite,
|
|
13
13
|
} from "smoodly";
|
|
14
|
-
|
|
14
|
+
// The admin gate from `smoodly/admin`, which holds no client code: the site
|
|
15
|
+
// routes import this file, and `smoodly/admin/next` would put the admin
|
|
16
|
+
// shell in every live page's JavaScript.
|
|
17
|
+
import { supabaseAdminAuth, type AdminAuth, type AuthConfig } from "smoodly/admin";
|
|
15
18
|
import { createPageRenderer, createSmoodlyQueries, type PageRegistration } from "smoodly/next";
|
|
16
19
|
import type { SupabaseClient } from "@supabase/supabase-js";
|
|
17
20
|
import { getPathname } from "@/i18n/navigation";
|