create-nextly-app 0.0.2-alpha.62 → 0.0.2-alpha.64

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/index.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  import { createRequire } from 'module';
2
- export { createNextly } from './chunk-CTBK76CF.mjs';
2
+ export { createNextly } from './chunk-I2U7KBH6.mjs';
3
3
 
4
4
  createRequire(import.meta.url);
5
5
  //# sourceMappingURL=index.mjs.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-nextly-app",
3
- "version": "0.0.2-alpha.62",
3
+ "version": "0.0.2-alpha.64",
4
4
  "description": "CLI to scaffold Nextly in your Next.js project",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -42,10 +42,10 @@
42
42
  "typescript": "^5.9.3",
43
43
  "vite-tsconfig-paths": "^5.1.4",
44
44
  "vitest": "^4.1.0",
45
- "@nextlyhq/eslint-config": "0.0.2-alpha.62",
46
- "@nextlyhq/eslint-plugin": "0.0.2-alpha.62",
47
- "@nextlyhq/telemetry": "0.0.2-alpha.62",
48
- "@nextlyhq/tsconfig": "0.0.2-alpha.62"
45
+ "@nextlyhq/eslint-config": "0.0.2-alpha.64",
46
+ "@nextlyhq/eslint-plugin": "0.0.2-alpha.64",
47
+ "@nextlyhq/telemetry": "0.0.2-alpha.64",
48
+ "@nextlyhq/tsconfig": "0.0.2-alpha.64"
49
49
  },
50
50
  "engines": {
51
51
  "node": "^20.19.0 || ^22.12.0 || >=24.0.0"
@@ -9,9 +9,15 @@ DATABASE_URL={{databaseUrl}}
9
9
  # Generate with: openssl rand -base64 32
10
10
  NEXTLY_SECRET=change-me-generate-a-secure-secret
11
11
 
12
- # Application URL
12
+ # Where the Nextly app itself lives: the admin, the API, and the origin its
13
+ # emails and preview links point at.
13
14
  NEXT_PUBLIC_APP_URL=http://localhost:3000
14
15
 
16
+ # Where READERS find the public site. Used for canonical links, Open Graph
17
+ # tags, the sitemap and RSS. Set it when the public site is served from a
18
+ # different origin than the app above; otherwise the app's origin is used.
19
+ # NEXT_PUBLIC_SITE_URL=https://example.com
20
+
15
21
  # Development diagnostics (opt-in)
16
22
  # Uncomment to add a _devDiagnostics field to error responses, carrying the
17
23
  # error's log context and the underlying cause, so a failure names itself while
@@ -2,6 +2,7 @@ import type { Metadata } from "next";
2
2
  import "@fontsource-variable/geist";
3
3
  import "@fontsource-variable/geist-mono";
4
4
  import "./globals.css";
5
+ import { SITE_URL } from "@/lib/site-url";
5
6
 
6
7
  /**
7
8
  * The faces are imported as STYLESHEETS from packages in `node_modules`, rather
@@ -34,9 +35,7 @@ import "./globals.css";
34
35
  * `https://yourblog.com`). The localhost fallback keeps dev working.
35
36
  */
36
37
  export const metadata: Metadata = {
37
- metadataBase: new URL(
38
- process.env.NEXT_PUBLIC_SITE_URL ?? "http://localhost:3000"
39
- ),
38
+ metadataBase: new URL(SITE_URL),
40
39
  title: { default: "Nextly", template: "%s — Nextly" },
41
40
  description: "A site built with Nextly.",
42
41
  };
@@ -0,0 +1,55 @@
1
+ /**
2
+ * The origin this site's absolute URLs are built from.
3
+ *
4
+ * Absolute URLs are needed in places that leave the browser's context —
5
+ * `metadataBase`, canonical links, Open Graph tags, the sitemap, RSS and
6
+ * JSON-LD. A relative path is meaningless in all of them, so something has to
7
+ * name the origin.
8
+ *
9
+ * ## Why two variables, in this order
10
+ *
11
+ * `NEXT_PUBLIC_SITE_URL` is where READERS find the site. `NEXT_PUBLIC_APP_URL`
12
+ * is where the Nextly app itself lives — the admin, the API, the origin its
13
+ * emails and preview links point at. They are usually the same host and are
14
+ * not the same question: a headless setup serves its public pages from one
15
+ * origin and runs the admin on another.
16
+ *
17
+ * So the public one wins when it is set, and the app's own origin is used when
18
+ * it is not. That second step matters more than it looks: the generated `.env`
19
+ * sets `NEXT_PUBLIC_APP_URL`, so without it a project that configured the only
20
+ * URL it was given would still publish `localhost` canonicals and OG tags to
21
+ * production — silently, because nothing about a wrong absolute URL fails at
22
+ * build time.
23
+ *
24
+ * ## The development fallback reads the port it is actually served on
25
+ *
26
+ * Not a hardcoded 3000. Next assigns `process.env.PORT` to the port it ends up
27
+ * listening on — after its own "port in use, using available port instead"
28
+ * fallback — so this follows `next dev -p 4000`, and follows Next onto a
29
+ * different port when 3000 is taken. A literal cannot do either, and the
30
+ * failure is quiet: pages render while every absolute URL points somewhere
31
+ * nothing is listening.
32
+ *
33
+ * `PORT` is a server-side value and is not inlined into client bundles, so a
34
+ * client component importing this reads the plain default. That is the same
35
+ * answer it would have had anyway, and client code should prefer
36
+ * `window.location.origin`, which is exact.
37
+ */
38
+ const DEV_PORT = process.env.PORT ?? "3000";
39
+
40
+ export const SITE_URL =
41
+ process.env.NEXT_PUBLIC_SITE_URL ??
42
+ process.env.NEXT_PUBLIC_APP_URL ??
43
+ `http://localhost:${DEV_PORT}`;
44
+
45
+ /**
46
+ * Join a path onto {@link SITE_URL} without duplicating slashes.
47
+ *
48
+ * @param path - A root-relative path; a leading slash is optional
49
+ * @returns The absolute URL
50
+ */
51
+ export function absoluteUrl(path = "/"): string {
52
+ const base = SITE_URL.replace(/\/$/, "");
53
+ const p = path.startsWith("/") ? path : `/${path}`;
54
+ return `${base}${p}`;
55
+ }
@@ -1,6 +1,7 @@
1
1
  import Link from "next/link";
2
2
 
3
3
  import { ThemeToggle } from "@/components/ThemeToggle";
4
+ import { SITE_URL } from "@/lib/site-url";
4
5
 
5
6
  /**
6
7
  * Blank-template landing page (public route via the (frontend) route group).
@@ -26,8 +27,7 @@ interface SetupStatus {
26
27
 
27
28
  async function fetchSetupStatus(): Promise<SetupStatus | null> {
28
29
  try {
29
- const baseUrl = process.env.NEXT_PUBLIC_SITE_URL ?? "http://localhost:3000";
30
- const res = await fetch(`${baseUrl}/api/auth/setup-status`, {
30
+ const res = await fetch(`${SITE_URL}/api/auth/setup-status`, {
31
31
  cache: "no-store",
32
32
  });
33
33
  if (!res.ok) return null;
@@ -3,6 +3,7 @@ import "@fontsource-variable/inter";
3
3
  import "@fontsource-variable/jetbrains-mono";
4
4
 
5
5
  import "./globals.css";
6
+ import { SITE_URL } from "@/lib/site-url";
6
7
 
7
8
  /**
8
9
  * The faces are imported as STYLESHEETS from packages in `node_modules`, rather
@@ -37,9 +38,7 @@ import "./globals.css";
37
38
  * blank-template pages can use relative OG image URLs without breaking.
38
39
  */
39
40
  export const metadata: Metadata = {
40
- metadataBase: new URL(
41
- process.env.NEXT_PUBLIC_SITE_URL ?? "http://localhost:3000"
42
- ),
41
+ metadataBase: new URL(SITE_URL),
43
42
  title: { default: "Nextly", template: "%s — Nextly" },
44
43
  description: "A Nextly project.",
45
44
  };