create-astroid 0.3.0 → 0.3.2
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/index.mjs +44 -16
- package/package.json +3 -3
- package/template/README.md +14 -0
- package/template/_github/workflows/ci.yml +54 -0
- package/template/package.json +2 -1
package/index.mjs
CHANGED
|
@@ -34,9 +34,15 @@ import {
|
|
|
34
34
|
|
|
35
35
|
const TEMPLATE_DIR = join(dirname(fileURLToPath(import.meta.url)), "template");
|
|
36
36
|
|
|
37
|
-
// Files whose leading `_` is stripped on copy (npm strips real
|
|
38
|
-
// published package, so they ship as `_gitignore` /
|
|
39
|
-
|
|
37
|
+
// Files (and dirs) whose leading `_` is stripped on copy (npm strips real
|
|
38
|
+
// dotfiles from a published package, so they ship as `_gitignore` /
|
|
39
|
+
// `_env.example` / `_github/…`). Applied per entry in `copyTemplate`, so a
|
|
40
|
+
// directory renames too — `_github` becomes `.github` and its contents follow.
|
|
41
|
+
const DOTFILE_RENAMES = {
|
|
42
|
+
_gitignore: ".gitignore",
|
|
43
|
+
"_env.example": ".env.example",
|
|
44
|
+
_github: ".github",
|
|
45
|
+
};
|
|
40
46
|
|
|
41
47
|
// Archetype → default editable home sections. Imported from astroidjs rather
|
|
42
48
|
// than duplicated here: as a literal in this file it could name a section that
|
|
@@ -173,8 +179,23 @@ function astroidConfigSource(config) {
|
|
|
173
179
|
...(config.modules?.length ? [` modules: ${JSON.stringify(config.modules)},`] : []),
|
|
174
180
|
// Must be emitted: `astroid generate` rebuilds the middleware from THIS
|
|
175
181
|
// file, so a config that omitted the portal would regenerate a middleware
|
|
176
|
-
// with no guard while src/portal-auth.ts sat there unused.
|
|
177
|
-
|
|
182
|
+
// with no guard while src/portal-auth.ts sat there unused. And the FULL shape
|
|
183
|
+
// (tablePrefix, signUp) — not a bare `{ enabled: true }` — so a regenerate
|
|
184
|
+
// reproduces the SAME unprefixed `user`/`session` seam the 0002_portal_auth
|
|
185
|
+
// migration created, rather than defaulting the prefix back to `portal_`.
|
|
186
|
+
...(config.portal?.enabled
|
|
187
|
+
? [
|
|
188
|
+
" portal: {",
|
|
189
|
+
" enabled: true,",
|
|
190
|
+
...(config.portal.tablePrefix !== undefined
|
|
191
|
+
? [` tablePrefix: ${JSON.stringify(config.portal.tablePrefix)},`]
|
|
192
|
+
: []),
|
|
193
|
+
...(config.portal.signUp !== undefined
|
|
194
|
+
? [` signUp: ${JSON.stringify(config.portal.signUp)},`]
|
|
195
|
+
: []),
|
|
196
|
+
" },",
|
|
197
|
+
]
|
|
198
|
+
: []),
|
|
178
199
|
' deploy: { platform: "cloudflare" },',
|
|
179
200
|
"});",
|
|
180
201
|
"",
|
|
@@ -243,9 +264,11 @@ async function main() {
|
|
|
243
264
|
const archetype = ARCHETYPES.includes(archetypeRaw) ? archetypeRaw : "marketing";
|
|
244
265
|
const color = flags.color || (await prompt("Brand color (hex)", "#5b4bff"));
|
|
245
266
|
const host = flags.host && flags.host !== true ? flags.host : undefined;
|
|
246
|
-
//
|
|
247
|
-
//
|
|
248
|
-
|
|
267
|
+
// The customer PORTAL is opt-in via --portal, but a storefront IMPLIES one — a
|
|
268
|
+
// shop has customers who sign in, reorder, and track orders — so enable it there
|
|
269
|
+
// by default. (Commerce below stays opt-in: infra a marketing site shouldn't carry.)
|
|
270
|
+
const portal =
|
|
271
|
+
flags.portal === true || flags.portal === "true" || archetype === "storefront";
|
|
249
272
|
// The map module is opt-in and pulls real weight (maplibre-gl is ~1 MB), so
|
|
250
273
|
// it is never on by default.
|
|
251
274
|
const map = flags.map === true || flags.map === "true";
|
|
@@ -284,7 +307,10 @@ async function main() {
|
|
|
284
307
|
theme: { name, colors: { brand: color } },
|
|
285
308
|
sections: ARCHETYPE_SECTIONS[archetype],
|
|
286
309
|
...(commerce ? { commerce: { provider: commerce } } : {}),
|
|
287
|
-
|
|
310
|
+
// Unprefixed `user`/`session` (customers — email + password), so the studio's
|
|
311
|
+
// `louise_`-prefixed tables and the portal's never collide (mirrors the
|
|
312
|
+
// reference storefront). `signUp: true` because a shop lets customers register.
|
|
313
|
+
...(portal ? { portal: { enabled: true, tablePrefix: "", signUp: true } } : {}),
|
|
288
314
|
// ONE array, built from every enabled flag. Two separate `...(x ? {modules}
|
|
289
315
|
// : {})` spreads would let the later one overwrite the earlier, silently
|
|
290
316
|
// dropping a module whenever both were passed.
|
|
@@ -394,15 +420,17 @@ async function main() {
|
|
|
394
420
|
// instance. Must match the `tablePrefix` in src/auth.ts and the `louise_user`
|
|
395
421
|
// table the generated `editorsRoute` reads.
|
|
396
422
|
write(dir, "migrations/0001_auth.sql", generateAuthSchemaSql({ tablePrefix: "louise_" }));
|
|
397
|
-
// The portal's own auth tables
|
|
398
|
-
//
|
|
399
|
-
//
|
|
400
|
-
// the
|
|
423
|
+
// The portal's own auth tables — a SECOND Better Auth instance sharing one D1
|
|
424
|
+
// but never a row, so a portal account can't sign into the studio and an
|
|
425
|
+
// editor doesn't appear in the portal. `customers: true` (email + password)
|
|
426
|
+
// and the config's tablePrefix, so this schema matches the scaffolded
|
|
427
|
+
// portal-auth.ts exactly. Without this migration the portal builds fine and
|
|
428
|
+
// fails on the first sign-in with a missing table.
|
|
401
429
|
if (config.portal?.enabled) {
|
|
402
430
|
write(
|
|
403
431
|
dir,
|
|
404
432
|
"migrations/0002_portal_auth.sql",
|
|
405
|
-
generateAuthSchemaSql({ tablePrefix: "
|
|
433
|
+
generateAuthSchemaSql({ customers: true, tablePrefix: config.portal.tablePrefix ?? "" }),
|
|
406
434
|
);
|
|
407
435
|
}
|
|
408
436
|
authMigrationOk = true;
|
|
@@ -419,8 +447,8 @@ async function main() {
|
|
|
419
447
|
write(
|
|
420
448
|
dir,
|
|
421
449
|
"migrations/0002_portal_auth.sql",
|
|
422
|
-
"-- Portal Better Auth tables (
|
|
423
|
-
"-- pnpm exec louise gen-auth-schema --
|
|
450
|
+
"-- Portal Better Auth tables (customers, unprefixed) — generate after install:\n" +
|
|
451
|
+
"-- pnpm exec louise gen-auth-schema --out migrations/0002_portal_auth.sql\n",
|
|
424
452
|
);
|
|
425
453
|
}
|
|
426
454
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-astroid",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.2",
|
|
4
4
|
"description": "Scaffold a new Astroid site — an editable, multi-editor Astro app on Cloudflare Workers — in one command.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"astro",
|
|
@@ -32,8 +32,8 @@
|
|
|
32
32
|
"dependencies": {
|
|
33
33
|
"@better-auth/passkey": "^1.6.23",
|
|
34
34
|
"better-auth": "^1.6.23",
|
|
35
|
-
"louise-toolkit": "0.
|
|
36
|
-
"astroidjs": "0.3.
|
|
35
|
+
"louise-toolkit": "0.18.0",
|
|
36
|
+
"astroidjs": "0.3.2"
|
|
37
37
|
},
|
|
38
38
|
"engines": {
|
|
39
39
|
"node": ">=24.0.0"
|
package/template/README.md
CHANGED
|
@@ -103,6 +103,20 @@ pnpm doctor # validate config, bindings, and generated-file freshness
|
|
|
103
103
|
wrangler deploy # or: pnpm astroid deploy
|
|
104
104
|
```
|
|
105
105
|
|
|
106
|
+
## Taking payments
|
|
107
|
+
|
|
108
|
+
Storefront sites (`--commerce square`) are scaffolded with a server-authoritative
|
|
109
|
+
payment route at `src/pages/api/checkout.ts` and a `<SquareCard>` input. **Keep
|
|
110
|
+
its sequence** — extend it (shipping, tax, an order row, a receipt), don't replace
|
|
111
|
+
it. It re-prices every line from the D1 catalog mirror (the client's price is a
|
|
112
|
+
_staleness check_, never an input to the charge — accept a `unitPrice` from the
|
|
113
|
+
request body and anyone buys anything for a penny) and derives the Square
|
|
114
|
+
idempotency key from the verified cart **and** the cart id. Hand-rolling
|
|
115
|
+
`createPayment` without a stable, cart-scoped idempotency key is the failure this
|
|
116
|
+
route exists to prevent: a double-clicked Pay button charges twice, and a
|
|
117
|
+
constant (or omitted) key lets two customers' identical carts collide into a
|
|
118
|
+
single charge.
|
|
119
|
+
|
|
106
120
|
## Layout
|
|
107
121
|
|
|
108
122
|
| Path | What |
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
|
|
8
|
+
# Cancel superseded runs on the same ref (a force-push mid-run).
|
|
9
|
+
concurrency:
|
|
10
|
+
group: ci-${{ github.ref }}
|
|
11
|
+
cancel-in-progress: true
|
|
12
|
+
|
|
13
|
+
jobs:
|
|
14
|
+
build:
|
|
15
|
+
runs-on: ubuntu-latest
|
|
16
|
+
env:
|
|
17
|
+
# corepack pins pnpm from `packageManager` in package.json; in CI it must
|
|
18
|
+
# fetch that version without an interactive prompt.
|
|
19
|
+
COREPACK_ENABLE_DOWNLOAD_PROMPT: 0
|
|
20
|
+
steps:
|
|
21
|
+
- uses: actions/checkout@v4
|
|
22
|
+
|
|
23
|
+
- uses: actions/setup-node@v4
|
|
24
|
+
with:
|
|
25
|
+
node-version: 24
|
|
26
|
+
|
|
27
|
+
# pnpm via corepack, pinned by `packageManager` — the same version you
|
|
28
|
+
# develop with, so `--frozen-lockfile` below always matches the committed
|
|
29
|
+
# pnpm-lock.yaml. (Commit that lockfile; this step relies on it.)
|
|
30
|
+
- name: Enable pnpm (corepack)
|
|
31
|
+
run: corepack enable
|
|
32
|
+
|
|
33
|
+
- name: Install
|
|
34
|
+
run: pnpm install --frozen-lockfile
|
|
35
|
+
|
|
36
|
+
# Validate the config, bindings, and that the generated
|
|
37
|
+
# src/schema.ts · src/worker.ts · src/middleware.ts trio is still in sync
|
|
38
|
+
# with astroid.config.ts. A fast fail before the heavier steps.
|
|
39
|
+
- name: Doctor
|
|
40
|
+
run: pnpm doctor
|
|
41
|
+
|
|
42
|
+
# No-ops on a fresh scaffold; runs automatically once you add a `lint`
|
|
43
|
+
# script (oxlint/biome) — same for `test` (vitest) further down.
|
|
44
|
+
- name: Lint
|
|
45
|
+
run: pnpm run --if-present lint
|
|
46
|
+
|
|
47
|
+
- name: Type-check
|
|
48
|
+
run: pnpm check
|
|
49
|
+
|
|
50
|
+
- name: Test
|
|
51
|
+
run: pnpm run --if-present test
|
|
52
|
+
|
|
53
|
+
- name: Build
|
|
54
|
+
run: pnpm build
|