@djangocfg/nextjs 2.1.541 → 2.1.543
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 +3 -2
- package/dist/config/index.d.mts +32 -16
- package/dist/config/index.mjs +58 -45
- package/dist/config/index.mjs.map +1 -1
- package/dist/health/index.d.mts +1 -1
- package/dist/health/index.mjs +5 -2
- package/dist/health/index.mjs.map +1 -1
- package/dist/i18n/routing.d.mts +20 -20
- package/dist/i18n/server.d.mts +2 -2
- package/dist/index.d.mts +1 -1
- package/dist/index.mjs +63 -47
- package/dist/index.mjs.map +1 -1
- package/dist/pwa/index.mjs +6 -5
- package/dist/pwa/index.mjs.map +1 -1
- package/dist/pwa/manifest.d.mts +1 -1
- package/dist/pwa/manifest.mjs +6 -5
- package/dist/pwa/manifest.mjs.map +1 -1
- package/dist/pwa/worker/index.mjs.map +1 -1
- package/dist/sitemap/index.d.mts +1 -1
- package/dist/{types-l9x1Rkmf.d.mts → types-CMxSgWnS.d.mts} +2 -0
- package/package.json +9 -9
- package/src/config/constants.ts +21 -4
- package/src/config/createNextConfig.ts +51 -28
- package/src/config/csp.ts +8 -5
- package/src/config/packages/installer.ts +11 -7
- package/src/config/packages/updater.ts +6 -6
- package/src/config/plugins/compression.ts +1 -1
- package/src/config/utils/deepMerge.ts +25 -21
- package/src/config/utils/version.ts +3 -3
- package/src/health/route.ts +5 -2
- package/src/pwa/manifest.ts +11 -8
- package/src/pwa/worker/index.ts +9 -7
- package/src/types.ts +2 -0
package/README.md
CHANGED
|
@@ -122,8 +122,9 @@ the box — no setup required:
|
|
|
122
122
|
- `Content-Security-Policy` — a pragmatic baseline that blocks the high-value
|
|
123
123
|
injection vectors (`object-src 'none'`, `base-uri 'self'`, `form-action 'self'`,
|
|
124
124
|
`frame-ancestors`) while keeping the inline/eval scripts a Next.js app needs.
|
|
125
|
-
**Dev-aware:** `connect-src`/`img-src` allow `http:`/`ws:` in development (
|
|
126
|
-
Django
|
|
125
|
+
**Dev-aware:** `connect-src`/`img-src` allow `http:`/`ws:` in development (a
|
|
126
|
+
local Django, plus any WebSocket transport the app brings itself) and tighten
|
|
127
|
+
to `https:`/`wss:` only in production.
|
|
127
128
|
- `X-Content-Type-Options: nosniff`, `Referrer-Policy: strict-origin-when-cross-origin`
|
|
128
129
|
- `X-Frame-Options: DENY` (or `SAMEORIGIN` when `allowIframeFrom` is set)
|
|
129
130
|
|
package/dist/config/index.d.mts
CHANGED
|
@@ -128,11 +128,14 @@ type CspVendor = keyof typeof CSP_VENDOR_PRESETS;
|
|
|
128
128
|
* (Observed 2026-07-23: cmdop `apps/web` blocked on
|
|
129
129
|
* `googletagmanager.com/gtag/js?id=G-YJ0F48S83F`.)
|
|
130
130
|
*
|
|
131
|
-
* - `youtube` / `vimeo` — `VideoPlayer`
|
|
132
|
-
* iframes AT RUNTIME from a URL
|
|
133
|
-
*
|
|
134
|
-
*
|
|
135
|
-
*
|
|
131
|
+
* - `youtube` / `vimeo` — these existed for `VideoPlayer`
|
|
132
|
+
* (`@djangocfg/ui-tools`), which mounted the iframes AT RUNTIME from a URL
|
|
133
|
+
* inside a chat message. That player was retired with `ui-tools`;
|
|
134
|
+
* `@djangocfg/widget-player` embeds no third-party frames, so **nothing in
|
|
135
|
+
* this repo needs these presets today**. They are kept because the shape of
|
|
136
|
+
* the problem outlives the component: an app author enables a chat, and
|
|
137
|
+
* whether a user ever pastes a YouTube link is not knowable at build time,
|
|
138
|
+
* so no `next.config.ts` can declare it honestly.
|
|
136
139
|
*
|
|
137
140
|
* Note what these have in common: the script/frame is turned on by the RUNTIME
|
|
138
141
|
* (the edge, a package, or an end user), never by the app author editing the
|
|
@@ -179,7 +182,17 @@ declare function resolveCspVendors(vendors: readonly string[] | undefined, warnU
|
|
|
179
182
|
* ```
|
|
180
183
|
*/
|
|
181
184
|
|
|
182
|
-
|
|
185
|
+
/**
|
|
186
|
+
* Second argument Next.js passes to the `webpack` hook. Derived from Next's own
|
|
187
|
+
* signature rather than re-declared, so it tracks upstream.
|
|
188
|
+
*/
|
|
189
|
+
type WebpackContext = Parameters<NonNullable<NextConfig['webpack']>>[1];
|
|
190
|
+
/**
|
|
191
|
+
* DjangoCFG-specific options. Every other Next.js option passes through via the
|
|
192
|
+
* `NextConfig` half of `BaseNextConfigOptions`; the keys redeclared here are
|
|
193
|
+
* omitted from it because this package narrows or re-purposes them.
|
|
194
|
+
*/
|
|
195
|
+
interface DjangoCfgNextOptions {
|
|
183
196
|
/** Static build path (used when NEXT_PUBLIC_STATIC_BUILD=true) */
|
|
184
197
|
isDefaultCfgAdmin?: boolean;
|
|
185
198
|
/** Additional transpile packages (merged with defaults) */
|
|
@@ -311,11 +324,7 @@ interface BaseNextConfigOptions {
|
|
|
311
324
|
/** Turbopack configuration (Next.js 16+ default bundler) */
|
|
312
325
|
turbopack?: NextConfig['turbopack'];
|
|
313
326
|
/** Custom webpack configuration function (called after base webpack logic) */
|
|
314
|
-
webpack?: (config: Configuration, options:
|
|
315
|
-
isServer: boolean;
|
|
316
|
-
dev: boolean;
|
|
317
|
-
[key: string]: any;
|
|
318
|
-
}) => Configuration | void;
|
|
327
|
+
webpack?: (config: Configuration, options: WebpackContext) => Configuration | void;
|
|
319
328
|
/** Custom experimental options (merged with defaults) */
|
|
320
329
|
experimental?: NextConfig['experimental'];
|
|
321
330
|
/** Custom env variables (merged with defaults) */
|
|
@@ -326,9 +335,11 @@ interface BaseNextConfigOptions {
|
|
|
326
335
|
headers?: NextConfig['headers'];
|
|
327
336
|
/** Additional rewrites */
|
|
328
337
|
rewrites?: NextConfig['rewrites'];
|
|
329
|
-
/** Override any Next.js config option */
|
|
330
|
-
[key: string]: any;
|
|
331
338
|
}
|
|
339
|
+
/**
|
|
340
|
+
* DjangoCFG options plus every remaining Next.js config option.
|
|
341
|
+
*/
|
|
342
|
+
type BaseNextConfigOptions = DjangoCfgNextOptions & Omit<NextConfig, keyof DjangoCfgNextOptions>;
|
|
332
343
|
/**
|
|
333
344
|
* Create base Next.js configuration with standard DjangoCFG settings
|
|
334
345
|
*
|
|
@@ -342,8 +353,8 @@ declare function createBaseNextConfig(options?: BaseNextConfigOptions): NextConf
|
|
|
342
353
|
*/
|
|
343
354
|
declare const PACKAGE_NAME = "@djangocfg/nextjs";
|
|
344
355
|
declare const DJANGO_CFG_BANNER = "\n\u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2557 \u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557\n\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557 \u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D \u2588\u2588\u2554\u2550\u2550\u2550\u2588\u2588\u2557 \u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D\n\u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2551\u2588\u2588\u2554\u2588\u2588\u2557 \u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2588\u2557\u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2551 \u2588\u2588\u2588\u2557\n\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588 \u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2551\u2588\u2588\u2551\u255A\u2588\u2588\u2557\u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2554\u2550\u2550\u255D \u2588\u2588\u2551 \u2588\u2588\u2551\n\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u255A\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551 \u255A\u2588\u2588\u2588\u2588\u2551\u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D \u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2551 \u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\n\u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D\n";
|
|
345
|
-
declare const DJANGOCFG_PACKAGES: readonly ["@djangocfg/ui-core", "@djangocfg/layouts", "@djangocfg/nextjs", "@djangocfg/api", "@djangocfg/
|
|
346
|
-
declare const DEFAULT_TRANSPILE_PACKAGES: readonly ["@djangocfg/i18n", "@djangocfg/ui-core", "@djangocfg/layouts", "@djangocfg/
|
|
356
|
+
declare const DJANGOCFG_PACKAGES: readonly ["@djangocfg/ui-core", "@djangocfg/layouts", "@djangocfg/nextjs", "@djangocfg/api", "@djangocfg/eslint-config", "@djangocfg/typescript-config"];
|
|
357
|
+
declare const DEFAULT_TRANSPILE_PACKAGES: readonly ["@djangocfg/i18n", "@djangocfg/ui-core", "@djangocfg/layouts", "@djangocfg/api", "@djangocfg/analytics", "@djangocfg/devtools", "@djangocfg/payments", "@djangocfg/widget-agent", "@djangocfg/widget-avatar", "@djangocfg/widget-charts", "@djangocfg/widget-chat", "@djangocfg/widget-code", "@djangocfg/widget-data", "@djangocfg/widget-diagram", "@djangocfg/widget-editor", "@djangocfg/widget-forms", "@djangocfg/widget-kit", "@djangocfg/widget-map", "@djangocfg/widget-media", "@djangocfg/widget-ogimage", "@djangocfg/widget-overlay", "@djangocfg/widget-player", "@djangocfg/widget-visual"];
|
|
347
358
|
declare const DEFAULT_OPTIMIZE_PACKAGES: readonly ["@djangocfg/ui-core", "@djangocfg/layouts", "lucide-react", "recharts"];
|
|
348
359
|
|
|
349
360
|
/**
|
|
@@ -351,7 +362,12 @@ declare const DEFAULT_OPTIMIZE_PACKAGES: readonly ["@djangocfg/ui-core", "@djang
|
|
|
351
362
|
*
|
|
352
363
|
* Recursively merges objects, replacing arrays instead of merging them.
|
|
353
364
|
*/
|
|
354
|
-
|
|
365
|
+
/**
|
|
366
|
+
* `T extends object` rather than `Record<string, unknown>`: call sites pass
|
|
367
|
+
* Next.js config interfaces, which have declared keys and no index signature —
|
|
368
|
+
* they are not assignable to `Record<string, unknown>`.
|
|
369
|
+
*/
|
|
370
|
+
declare function deepMerge<T extends object>(target: T, source: Partial<T>): T;
|
|
355
371
|
|
|
356
372
|
/**
|
|
357
373
|
* Environment Variable Utilities
|
package/dist/config/index.mjs
CHANGED
|
@@ -38,7 +38,6 @@ var DJANGOCFG_PACKAGES = [
|
|
|
38
38
|
"@djangocfg/layouts",
|
|
39
39
|
"@djangocfg/nextjs",
|
|
40
40
|
"@djangocfg/api",
|
|
41
|
-
"@djangocfg/centrifugo",
|
|
42
41
|
"@djangocfg/eslint-config",
|
|
43
42
|
"@djangocfg/typescript-config"
|
|
44
43
|
];
|
|
@@ -46,12 +45,26 @@ var DEFAULT_TRANSPILE_PACKAGES = [
|
|
|
46
45
|
"@djangocfg/i18n",
|
|
47
46
|
"@djangocfg/ui-core",
|
|
48
47
|
"@djangocfg/layouts",
|
|
49
|
-
"@djangocfg/ui-tools",
|
|
50
48
|
"@djangocfg/api",
|
|
51
49
|
"@djangocfg/analytics",
|
|
52
|
-
"@djangocfg/centrifugo",
|
|
53
50
|
"@djangocfg/devtools",
|
|
54
|
-
"@djangocfg/payments"
|
|
51
|
+
"@djangocfg/payments",
|
|
52
|
+
"@djangocfg/widget-agent",
|
|
53
|
+
"@djangocfg/widget-avatar",
|
|
54
|
+
"@djangocfg/widget-charts",
|
|
55
|
+
"@djangocfg/widget-chat",
|
|
56
|
+
"@djangocfg/widget-code",
|
|
57
|
+
"@djangocfg/widget-data",
|
|
58
|
+
"@djangocfg/widget-diagram",
|
|
59
|
+
"@djangocfg/widget-editor",
|
|
60
|
+
"@djangocfg/widget-forms",
|
|
61
|
+
"@djangocfg/widget-kit",
|
|
62
|
+
"@djangocfg/widget-map",
|
|
63
|
+
"@djangocfg/widget-media",
|
|
64
|
+
"@djangocfg/widget-ogimage",
|
|
65
|
+
"@djangocfg/widget-overlay",
|
|
66
|
+
"@djangocfg/widget-player",
|
|
67
|
+
"@djangocfg/widget-visual"
|
|
55
68
|
];
|
|
56
69
|
var DEFAULT_OPTIMIZE_PACKAGES = [
|
|
57
70
|
"@djangocfg/ui-core",
|
|
@@ -336,7 +349,7 @@ function addCompressionPlugins(config, options = {}) {
|
|
|
336
349
|
);
|
|
337
350
|
}
|
|
338
351
|
return true;
|
|
339
|
-
} catch
|
|
352
|
+
} catch {
|
|
340
353
|
return false;
|
|
341
354
|
}
|
|
342
355
|
}
|
|
@@ -544,7 +557,7 @@ async function installSinglePackage(pkg, pm, index, total) {
|
|
|
544
557
|
const spinner = createSpinner(`${chalk.dim(progress)} Installing ${chalk.cyan(pkg.name)}...`);
|
|
545
558
|
spinner.start();
|
|
546
559
|
return new Promise((resolve) => {
|
|
547
|
-
const [cmd, ...args] = command.split(" ");
|
|
560
|
+
const [cmd = pm, ...args] = command.split(" ");
|
|
548
561
|
const proc = spawn(cmd, args, {
|
|
549
562
|
shell: true,
|
|
550
563
|
cwd: process.cwd(),
|
|
@@ -580,13 +593,13 @@ async function installPackagesWithProgress(packages) {
|
|
|
580
593
|
console.log(chalk.bold(` Installing ${total} package${total > 1 ? "s" : ""}...`));
|
|
581
594
|
console.log("");
|
|
582
595
|
let successCount = 0;
|
|
583
|
-
|
|
584
|
-
for (
|
|
585
|
-
const success = await installSinglePackage(
|
|
596
|
+
const failedPackages = [];
|
|
597
|
+
for (const [i, pkg] of packages.entries()) {
|
|
598
|
+
const success = await installSinglePackage(pkg, pm, i, total);
|
|
586
599
|
if (success) {
|
|
587
600
|
successCount++;
|
|
588
601
|
} else {
|
|
589
|
-
failedPackages.push(
|
|
602
|
+
failedPackages.push(pkg.name);
|
|
590
603
|
}
|
|
591
604
|
}
|
|
592
605
|
console.log("");
|
|
@@ -951,12 +964,12 @@ async function updatePackagesWithProgress(packages) {
|
|
|
951
964
|
console.log("");
|
|
952
965
|
let successCount = 0;
|
|
953
966
|
const failedPackages = [];
|
|
954
|
-
for (
|
|
955
|
-
const success = await updateSinglePackage(
|
|
967
|
+
for (const [i, pkg] of packages.entries()) {
|
|
968
|
+
const success = await updateSinglePackage(pkg, pm, i, total);
|
|
956
969
|
if (success) {
|
|
957
970
|
successCount++;
|
|
958
971
|
} else {
|
|
959
|
-
failedPackages.push(
|
|
972
|
+
failedPackages.push(pkg.name);
|
|
960
973
|
}
|
|
961
974
|
}
|
|
962
975
|
console.log("");
|
|
@@ -1212,22 +1225,17 @@ function resetDevStartupState() {
|
|
|
1212
1225
|
}
|
|
1213
1226
|
|
|
1214
1227
|
// src/config/utils/deepMerge.ts
|
|
1228
|
+
function isPlainObject(value) {
|
|
1229
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1230
|
+
}
|
|
1215
1231
|
function deepMerge(target, source) {
|
|
1216
1232
|
const output = { ...target };
|
|
1217
|
-
for (const key
|
|
1218
|
-
|
|
1219
|
-
if (
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
if (targetValue && typeof targetValue === "object" && !Array.isArray(targetValue)) {
|
|
1224
|
-
output[key] = deepMerge(targetValue, source[key]);
|
|
1225
|
-
} else {
|
|
1226
|
-
output[key] = source[key];
|
|
1227
|
-
}
|
|
1228
|
-
} else {
|
|
1229
|
-
output[key] = source[key];
|
|
1230
|
-
}
|
|
1233
|
+
for (const key of Object.keys(source)) {
|
|
1234
|
+
const sourceValue = source[key];
|
|
1235
|
+
if (sourceValue === void 0) continue;
|
|
1236
|
+
const targetValue = output[key];
|
|
1237
|
+
const merged = isPlainObject(sourceValue) && isPlainObject(targetValue) ? deepMerge(targetValue, sourceValue) : sourceValue;
|
|
1238
|
+
output[key] = merged;
|
|
1231
1239
|
}
|
|
1232
1240
|
return output;
|
|
1233
1241
|
}
|
|
@@ -1316,7 +1324,7 @@ function createBaseNextConfig(options = {}) {
|
|
|
1316
1324
|
"style-src 'self' 'unsafe-inline'",
|
|
1317
1325
|
imgSrc,
|
|
1318
1326
|
`font-src 'self' data:${extraFont}`,
|
|
1319
|
-
// API
|
|
1327
|
+
// API calls go cross-origin to Django.
|
|
1320
1328
|
connectSrc,
|
|
1321
1329
|
// Declared vendors (Stripe Elements/Checkout, video embeds…) and any
|
|
1322
1330
|
// app-declared trusted origins mount iframes; add their hosts here.
|
|
@@ -1437,23 +1445,28 @@ function createBaseNextConfig(options = {}) {
|
|
|
1437
1445
|
return config;
|
|
1438
1446
|
}
|
|
1439
1447
|
};
|
|
1440
|
-
const {
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1448
|
+
const { i18n: i18nOptions, pwa: pwaOptions } = options;
|
|
1449
|
+
const DJANGOCFG_ONLY_KEYS = [
|
|
1450
|
+
"i18n",
|
|
1451
|
+
"pwa",
|
|
1452
|
+
"transpilePackages",
|
|
1453
|
+
"optimizePackageImports",
|
|
1454
|
+
"isDefaultCfgAdmin",
|
|
1455
|
+
"checkUpdates",
|
|
1456
|
+
"autoUpdate",
|
|
1457
|
+
"forceCheckWorkspace",
|
|
1458
|
+
"checkPackages",
|
|
1459
|
+
"autoInstall",
|
|
1460
|
+
"allowIframeFrom",
|
|
1461
|
+
"dpop",
|
|
1462
|
+
"stripe",
|
|
1463
|
+
"csp"
|
|
1464
|
+
];
|
|
1465
|
+
const nextConfigOptions = Object.fromEntries(
|
|
1466
|
+
Object.entries(options).filter(
|
|
1467
|
+
([key]) => !DJANGOCFG_ONLY_KEYS.includes(key)
|
|
1468
|
+
)
|
|
1469
|
+
);
|
|
1457
1470
|
let finalConfig = deepMerge(baseConfig, nextConfigOptions);
|
|
1458
1471
|
if (pwaOptions) {
|
|
1459
1472
|
finalConfig = withPWA(finalConfig, pwaOptions);
|