create-nextly-app 0.0.2-alpha.72 → 0.0.2-alpha.73
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/dist/cli.cjs +1 -1
- package/dist/cli.mjs +1 -1
- package/dist/{create-nextly-CyI8XgVc.mjs → create-nextly-CuWn_ITx.mjs} +807 -466
- package/dist/create-nextly-CuWn_ITx.mjs.map +1 -0
- package/dist/{create-nextly-BGu1tXYs.cjs → create-nextly-Q62KZJib.cjs} +807 -466
- package/dist/create-nextly-Q62KZJib.cjs.map +1 -0
- package/dist/index.cjs +1 -1
- package/dist/index.mjs +1 -1
- package/package.json +5 -5
- package/skills/nextly-authentication/SKILL.md +1 -1
- package/skills/nextly-collections/SKILL.md +10 -4
- package/skills/nextly-deploy/SKILL.md +5 -3
- package/skills/nextly-install/SKILL.md +5 -4
- package/templates/base/src/app/admin/[[...params]]/layout.tsx +15 -1
- package/templates/base/src/app/globals.css +13 -2
- package/templates/blank/src/app/(frontend)/page.tsx +43 -21
- package/templates/blank/src/instrumentation.ts +3 -2
- package/templates/plugin/dev/next.config.ts +8 -2
- package/templates/plugin/dev/src/app/admin/[[...params]]/layout.tsx +24 -0
- package/templates/plugin/dev/src/instrumentation.ts +3 -2
- package/dist/create-nextly-BGu1tXYs.cjs.map +0 -1
- package/dist/create-nextly-CyI8XgVc.mjs.map +0 -1
package/dist/index.cjs
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
const require_create_nextly = require("./create-nextly-
|
|
2
|
+
const require_create_nextly = require("./create-nextly-Q62KZJib.cjs");
|
|
3
3
|
exports.createNextly = require_create_nextly.createNextly;
|
package/dist/index.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export { t as createNextly } from "./create-nextly-
|
|
1
|
+
export { t as createNextly } from "./create-nextly-CuWn_ITx.mjs";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-nextly-app",
|
|
3
|
-
"version": "0.0.2-alpha.
|
|
3
|
+
"version": "0.0.2-alpha.73",
|
|
4
4
|
"description": "CLI to scaffold Nextly in your Next.js project",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -37,10 +37,10 @@
|
|
|
37
37
|
},
|
|
38
38
|
"devDependencies": {
|
|
39
39
|
"@babel/types": "^7.29.7",
|
|
40
|
-
"@nextlyhq/eslint-plugin": "0.0.2-alpha.
|
|
41
|
-
"@nextlyhq/module-specifiers": "0.0.2-alpha.
|
|
42
|
-
"@nextlyhq/telemetry": "0.0.2-alpha.
|
|
43
|
-
"@nextlyhq/tsconfig": "0.0.2-alpha.
|
|
40
|
+
"@nextlyhq/eslint-plugin": "0.0.2-alpha.73",
|
|
41
|
+
"@nextlyhq/module-specifiers": "0.0.2-alpha.73",
|
|
42
|
+
"@nextlyhq/telemetry": "0.0.2-alpha.73",
|
|
43
|
+
"@nextlyhq/tsconfig": "0.0.2-alpha.73",
|
|
44
44
|
"@testing-library/react": "^16.3.0",
|
|
45
45
|
"@types/fs-extra": "^11.0.4",
|
|
46
46
|
"@types/node": "^22.20.5",
|
|
@@ -7,7 +7,7 @@ description: >-
|
|
|
7
7
|
code, and extra fields on users. Also use when asked to add login or
|
|
8
8
|
sign-up to a Nextly site, so the answer matches what Nextly provides.
|
|
9
9
|
metadata:
|
|
10
|
-
nextly-version: 0.0.2-alpha.
|
|
10
|
+
nextly-version: 0.0.2-alpha.73
|
|
11
11
|
---
|
|
12
12
|
|
|
13
13
|
# Authentication and access in Nextly
|
|
@@ -9,7 +9,7 @@ description: >-
|
|
|
9
9
|
not appear in the admin, a field change does not reach the database, or a
|
|
10
10
|
page reading content fails to build.
|
|
11
11
|
metadata:
|
|
12
|
-
nextly-version: 0.0.2-alpha.
|
|
12
|
+
nextly-version: 0.0.2-alpha.73
|
|
13
13
|
---
|
|
14
14
|
|
|
15
15
|
# Define a collection in Nextly
|
|
@@ -176,9 +176,15 @@ export default async function PostsPage() {
|
|
|
176
176
|
- `status: "published"` keeps drafts off the page. Without it a trusted
|
|
177
177
|
server read returns drafts too.
|
|
178
178
|
- `cachedFind` with `nextlyTags("posts")` caches the result and clears it when
|
|
179
|
-
a post is saved, so the page updates on publish. It also lets the page
|
|
180
|
-
|
|
181
|
-
outside `<Suspense>` fails `next build`.
|
|
179
|
+
a post is saved, so the page updates on publish. It also lets the page
|
|
180
|
+
build: a Nextly app runs with `cacheComponents: true`, where an uncached
|
|
181
|
+
database read outside `<Suspense>` fails `next build`. There the read goes
|
|
182
|
+
through the app's own `"use cache"` function, `src/nextly/cached-read.ts`
|
|
183
|
+
(`nextly/cached-read.ts` without a `src/` folder): import it in the module
|
|
184
|
+
that reads, `import "@/nextly/cached-read";` with `src/`, or by a relative
|
|
185
|
+
path without one. A blog ships it; for another app, copy it from the caching
|
|
186
|
+
guide
|
|
187
|
+
(<https://nextlyhq.com/docs/guides/isr-caching#cache-components>).
|
|
182
188
|
- `keyParts` names the cache entry, and everyone whose read uses the same key
|
|
183
189
|
gets the same rows. Cache only reads that are the same for every reader:
|
|
184
190
|
published content of a collection with no read rule, on the collection or
|
|
@@ -8,7 +8,7 @@ description: >-
|
|
|
8
8
|
Also use when a deployed Nextly app has missing tables, refuses to start,
|
|
9
9
|
or loses uploaded files.
|
|
10
10
|
metadata:
|
|
11
|
-
nextly-version: 0.0.2-alpha.
|
|
11
|
+
nextly-version: 0.0.2-alpha.73
|
|
12
12
|
---
|
|
13
13
|
|
|
14
14
|
# Deploy a Nextly project
|
|
@@ -244,5 +244,7 @@ could then pick their own address.
|
|
|
244
244
|
- **Sign-in fails with `CSRF_FAILED` behind a proxy:** add the public origin
|
|
245
245
|
to `NEXTLY_ALLOWED_ORIGINS`.
|
|
246
246
|
- **`next build` fails on a page reading content:** in an app with
|
|
247
|
-
`cacheComponents: true`, wrap the read in `cachedFind`
|
|
248
|
-
`nextly-collections` skill) or render it inside `<Suspense>`.
|
|
247
|
+
`cacheComponents: true`, the Nextly default, wrap the read in `cachedFind`
|
|
248
|
+
(the `nextly-collections` skill) or render it inside `<Suspense>`. An app
|
|
249
|
+
made by an earlier release may have it off: check `next.config` first, and
|
|
250
|
+
turn it on as the installation guide describes.
|
|
@@ -8,7 +8,7 @@ description: >-
|
|
|
8
8
|
Nextly install shows no collections, fails to load nextly.config.ts, or its
|
|
9
9
|
admin panel misbehaves after setup.
|
|
10
10
|
metadata:
|
|
11
|
-
nextly-version: 0.0.2-alpha.
|
|
11
|
+
nextly-version: 0.0.2-alpha.73
|
|
12
12
|
---
|
|
13
13
|
|
|
14
14
|
# Install Nextly into an existing Next.js app
|
|
@@ -23,9 +23,10 @@ Checked against `nextly` 0.0.2-alpha.67 with Next.js 16.4. Run
|
|
|
23
23
|
|
|
24
24
|
## Before you start
|
|
25
25
|
|
|
26
|
-
- Next.js 16.4.1
|
|
27
|
-
Router (`app/` or `src/app/`).
|
|
28
|
-
|
|
26
|
+
- Next.js `^16.4.1` and React `^19.3.0` (16.4.1 or later within 16.x, 19.3.0
|
|
27
|
+
or later within 19.x), with the App Router (`app/` or `src/app/`). The
|
|
28
|
+
[supported versions](https://nextlyhq.com/docs/getting-started/installation#requirements)
|
|
29
|
+
are kept current there.
|
|
29
30
|
- Node.js `^22.12.0 || >=24.0.0`. Node 20 and Node 23 are not supported.
|
|
30
31
|
- A clean git working tree, so every change below is visible in one diff.
|
|
31
32
|
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { connection } from "next/server";
|
|
2
|
+
import { Suspense } from "react";
|
|
1
3
|
import { getBrandingCss } from "nextly/config";
|
|
2
4
|
|
|
3
5
|
import config from "../../../../nextly.config";
|
|
@@ -14,7 +16,19 @@ export default function AdminLayout({
|
|
|
14
16
|
{brandingCss && (
|
|
15
17
|
<style dangerouslySetInnerHTML={{ __html: brandingCss }} />
|
|
16
18
|
)}
|
|
17
|
-
{
|
|
19
|
+
<Suspense fallback={null}>
|
|
20
|
+
<ForThisRequest>{children}</ForThisRequest>
|
|
21
|
+
</Suspense>
|
|
18
22
|
</>
|
|
19
23
|
);
|
|
20
24
|
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* The admin renders for each request, never from a cache another user's
|
|
28
|
+
* request filled. Beneath the layout's Suspense boundary, so under Cache
|
|
29
|
+
* Components the shell above it still prerenders.
|
|
30
|
+
*/
|
|
31
|
+
async function ForThisRequest({ children }: { children: React.ReactNode }) {
|
|
32
|
+
await connection();
|
|
33
|
+
return children;
|
|
34
|
+
}
|
|
@@ -47,8 +47,19 @@ body {
|
|
|
47
47
|
|
|
48
48
|
/* Visible focus ring for keyboard users. `:focus-visible` only fires
|
|
49
49
|
on keyboard / programmatic focus, so clicking a button doesn't
|
|
50
|
-
show the ring but tabbing to it does.
|
|
51
|
-
|
|
50
|
+
show the ring but tabbing to it does.
|
|
51
|
+
|
|
52
|
+
Weighed as two element names, the pseudo-class inside `:where()` counting
|
|
53
|
+
for nothing. That is enough to keep the ring over a reset added later, such
|
|
54
|
+
as `button { outline: none }`, and on this site's pages it draws as
|
|
55
|
+
`*:focus-visible` did, since no other rule here sets these properties on a
|
|
56
|
+
focused element. The admin at /admin renders in this same document and
|
|
57
|
+
reverts a site's rules made of element names only; with the pseudo-class
|
|
58
|
+
counted, this rule would outweigh that and redraw every focused control in
|
|
59
|
+
the admin with this ring and corner. The trade: a class-based reset, such as
|
|
60
|
+
`.btn { outline: none }`, outweighs this ring wherever it is written; give
|
|
61
|
+
such a rule a `:focus-visible` style of its own. */
|
|
62
|
+
html body :where(:focus-visible) {
|
|
52
63
|
outline: 2px solid currentColor;
|
|
53
64
|
outline-offset: 2px;
|
|
54
65
|
border-radius: 2px;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import Link from "next/link";
|
|
2
|
+
import { Suspense } from "react";
|
|
2
3
|
|
|
3
4
|
import { ThemeToggle } from "@/components/ThemeToggle";
|
|
4
5
|
import { SITE_URL } from "@/lib/site-url";
|
|
@@ -12,6 +13,10 @@ import { SITE_URL } from "@/lib/site-url";
|
|
|
12
13
|
* primary button label flips between "Set up admin" (no super-admin
|
|
13
14
|
* yet) and "Open admin" (super-admin exists).
|
|
14
15
|
*
|
|
16
|
+
* The app runs with Cache Components on, so the page is prerendered as a
|
|
17
|
+
* static shell and the setup-status read, made per request, sits inside a
|
|
18
|
+
* `<Suspense>` boundary: the shell shows "Open admin" until it resolves.
|
|
19
|
+
*
|
|
15
20
|
* If the auth API fails for any reason (DB not migrated, network),
|
|
16
21
|
* the button defaults to "Open admin" / /admin since /admin already
|
|
17
22
|
* redirects to /admin/setup when no super-admin exists — the link
|
|
@@ -37,12 +42,42 @@ async function fetchSetupStatus(): Promise<SetupStatus | null> {
|
|
|
37
42
|
}
|
|
38
43
|
}
|
|
39
44
|
|
|
40
|
-
|
|
45
|
+
/** The primary button, linking to the admin with the label and target it needs. */
|
|
46
|
+
function AdminButton({ label, href }: { label: string; href: string }) {
|
|
47
|
+
return (
|
|
48
|
+
<Link href={href} className="btn-primary">
|
|
49
|
+
<span>{label}</span>
|
|
50
|
+
<svg
|
|
51
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
52
|
+
width="18"
|
|
53
|
+
height="18"
|
|
54
|
+
viewBox="0 0 24 24"
|
|
55
|
+
fill="none"
|
|
56
|
+
stroke="currentColor"
|
|
57
|
+
strokeWidth="2"
|
|
58
|
+
strokeLinecap="round"
|
|
59
|
+
strokeLinejoin="round"
|
|
60
|
+
className="lucide lucide-arrow-right"
|
|
61
|
+
>
|
|
62
|
+
<path d="M5 12h14" />
|
|
63
|
+
<path d="m12 5 7 7-7 7" />
|
|
64
|
+
</svg>
|
|
65
|
+
</Link>
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/** The button once setup-status answers: "Set up admin" while there is no super-admin. */
|
|
70
|
+
async function SetupAwareAdminButton() {
|
|
41
71
|
const status = await fetchSetupStatus();
|
|
42
72
|
const needsSetup = status?.requiresInitialUser ?? false;
|
|
43
|
-
|
|
44
|
-
|
|
73
|
+
return needsSetup ? (
|
|
74
|
+
<AdminButton label="Set up admin" href="/admin/setup" />
|
|
75
|
+
) : (
|
|
76
|
+
<AdminButton label="Open admin" href="/admin" />
|
|
77
|
+
);
|
|
78
|
+
}
|
|
45
79
|
|
|
80
|
+
export default function HomePage() {
|
|
46
81
|
return (
|
|
47
82
|
<main className="relative min-h-screen flex flex-col items-center justify-center p-6 bg-background text-foreground font-display selection:bg-foreground/10">
|
|
48
83
|
<ThemeToggle />
|
|
@@ -85,24 +120,11 @@ export default async function HomePage() {
|
|
|
85
120
|
</p>
|
|
86
121
|
|
|
87
122
|
<div className="mt-10 flex flex-wrap items-center justify-center gap-4">
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
height="18"
|
|
94
|
-
viewBox="0 0 24 24"
|
|
95
|
-
fill="none"
|
|
96
|
-
stroke="currentColor"
|
|
97
|
-
strokeWidth="2"
|
|
98
|
-
strokeLinecap="round"
|
|
99
|
-
strokeLinejoin="round"
|
|
100
|
-
className="lucide lucide-arrow-right"
|
|
101
|
-
>
|
|
102
|
-
<path d="M5 12h14" />
|
|
103
|
-
<path d="m12 5 7 7-7 7" />
|
|
104
|
-
</svg>
|
|
105
|
-
</Link>
|
|
123
|
+
{/* "/admin" redirects to setup while there is no super-admin, so the
|
|
124
|
+
fallback link works before the read answers. */}
|
|
125
|
+
<Suspense fallback={<AdminButton label="Open admin" href="/admin" />}>
|
|
126
|
+
<SetupAwareAdminButton />
|
|
127
|
+
</Suspense>
|
|
106
128
|
<Link href="https://nextlyhq.com/docs" className="btn-secondary">
|
|
107
129
|
<span>Read documentation</span>
|
|
108
130
|
<svg
|
|
@@ -24,8 +24,9 @@ export async function register(): Promise<void> {
|
|
|
24
24
|
const { createRegister } = await import("nextly");
|
|
25
25
|
const { default: config } = await import("../nextly.config");
|
|
26
26
|
// Next.js writes its Cache Components setting into this file as it builds
|
|
27
|
-
// it. Nextly, loaded from node_modules, cannot read that for itself
|
|
28
|
-
// warns
|
|
27
|
+
// it. Nextly, loaded from node_modules, cannot read that for itself. With
|
|
28
|
+
// it off, Nextly warns at start; with it on, a cached read that finds no
|
|
29
|
+
// "use cache" read function says so.
|
|
29
30
|
await createRegister(config, {
|
|
30
31
|
cacheComponents: process.env.__NEXT_CACHE_COMPONENTS,
|
|
31
32
|
})();
|
|
@@ -6,8 +6,14 @@ import type { NextConfig } from "next";
|
|
|
6
6
|
// external (Turbopack can't bundle them).
|
|
7
7
|
const nextConfig: NextConfig = {
|
|
8
8
|
typescript: { ignoreBuildErrors: true },
|
|
9
|
-
// Nextly
|
|
10
|
-
|
|
9
|
+
// Nextly runs with Cache Components and Partial Prefetching on. Its cache
|
|
10
|
+
// handlers make the first read after a write show the new version:
|
|
11
|
+
// https://nextlyhq.com/docs/getting-started/installation#cache-components
|
|
12
|
+
cacheComponents: true,
|
|
13
|
+
partialPrefetching: true,
|
|
14
|
+
cacheHandler: require.resolve("nextly/cache-handler"),
|
|
15
|
+
cacheMaxMemorySize: 0,
|
|
16
|
+
cacheHandlers: { default: require.resolve("nextly/cache-handlers") },
|
|
11
17
|
// Transpile the aliased plugin source so HMR fires on src/ edits.
|
|
12
18
|
transpilePackages: ["{{pluginName}}"],
|
|
13
19
|
serverExternalPackages: [
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { connection } from "next/server";
|
|
2
|
+
import { Suspense } from "react";
|
|
3
|
+
|
|
4
|
+
export default function AdminLayout({
|
|
5
|
+
children,
|
|
6
|
+
}: {
|
|
7
|
+
children: React.ReactNode;
|
|
8
|
+
}) {
|
|
9
|
+
return (
|
|
10
|
+
<Suspense fallback={null}>
|
|
11
|
+
<ForThisRequest>{children}</ForThisRequest>
|
|
12
|
+
</Suspense>
|
|
13
|
+
);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* The admin renders for each request, never from a cache another user's
|
|
18
|
+
* request filled. Beneath the layout's Suspense boundary, so under Cache
|
|
19
|
+
* Components the rest of the page still prerenders.
|
|
20
|
+
*/
|
|
21
|
+
async function ForThisRequest({ children }: { children: React.ReactNode }) {
|
|
22
|
+
await connection();
|
|
23
|
+
return children;
|
|
24
|
+
}
|
|
@@ -8,8 +8,9 @@ export async function register(): Promise<void> {
|
|
|
8
8
|
const { createRegister, getService } = await import("nextly");
|
|
9
9
|
const { default: config } = await import("../nextly.config");
|
|
10
10
|
// Next.js writes its Cache Components setting into this file as it builds
|
|
11
|
-
// it. Nextly, loaded from node_modules, cannot read that for itself
|
|
12
|
-
// warns
|
|
11
|
+
// it. Nextly, loaded from node_modules, cannot read that for itself. With
|
|
12
|
+
// it off, Nextly warns at start; with it on, a cached read that finds no
|
|
13
|
+
// "use cache" read function says so.
|
|
13
14
|
await createRegister(config, {
|
|
14
15
|
cacheComponents: process.env.__NEXT_CACHE_COMPONENTS,
|
|
15
16
|
})();
|