create-nextly-app 0.0.2-alpha.73 → 0.0.2-alpha.75
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-Q62KZJib.cjs → create-nextly-DdIL2e9E.cjs} +170 -77
- package/dist/{create-nextly-Q62KZJib.cjs.map → create-nextly-DdIL2e9E.cjs.map} +1 -1
- package/dist/{create-nextly-CuWn_ITx.mjs → create-nextly-N_COehCu.mjs} +170 -77
- package/dist/{create-nextly-CuWn_ITx.mjs.map → create-nextly-N_COehCu.mjs.map} +1 -1
- 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 +1 -1
- package/skills/nextly-deploy/SKILL.md +1 -1
- package/skills/nextly-install/SKILL.md +1 -1
- package/templates/base/src/app/admin/[[...params]]/layout.tsx +60 -8
- package/templates/base/src/app/layout.tsx +5 -0
- package/templates/base/src/nextly/cached-read.ts +52 -0
- package/templates/base/src/types/generated/plugin-admin-imports.generated.ts +2 -0
- package/templates/blank/src/app/layout.tsx +5 -0
- package/templates/blank/src/instrumentation.ts +4 -1
- package/templates/plugin/AGENTS.md.template +2 -2
- package/templates/plugin/dev/src/app/layout.tsx +6 -0
- package/templates/plugin/dev/src/instrumentation.ts +4 -1
- package/templates/plugin/dev/src/nextly/cached-read.ts +52 -0
- package/templates/plugin/dev/src/types/generated/plugin-admin-imports.generated.ts +2 -2
- package/templates/plugin/src/admin/index.ts +4 -14
- package/templates/plugin/dev/src/app/admin/[[...params]]/layout.tsx +0 -24
|
@@ -42566,15 +42566,27 @@ const REQUIRE_IMPORT = "import { createRequire } from \"node:module\";";
|
|
|
42566
42566
|
const requireDeclaration = (createRequireName) => `// Resolves Nextly's cache handlers from this app's node_modules.
|
|
42567
42567
|
const require = ${createRequireName}(import.meta.url);`;
|
|
42568
42568
|
const REQUIRE_DECLARATION = requireDeclaration("createRequire");
|
|
42569
|
+
/** Where a new app's config takes the crawlers that wait for the whole head. */
|
|
42570
|
+
const HTML_LIMITED_BOTS_IMPORT = "import { nextlyHtmlLimitedBots } from \"nextly/next\";";
|
|
42571
|
+
/**
|
|
42572
|
+
* The crawlers answered with each page's whole head in the first HTML rather
|
|
42573
|
+
* than streamed it: Next.js's own list, the main Googlebot and the AI
|
|
42574
|
+
* crawlers (`nextlyHtmlLimitedBots`).
|
|
42575
|
+
*/
|
|
42576
|
+
const HTML_LIMITED_BOTS_LINE = ` // Search engines and AI crawlers read each page's whole head in the first
|
|
42577
|
+
// HTML, rather than metadata streamed in after it.
|
|
42578
|
+
htmlLimitedBots: nextlyHtmlLimitedBots,`;
|
|
42569
42579
|
/**
|
|
42570
42580
|
* Render a complete next.config.ts file for the selected database.
|
|
42571
42581
|
*/
|
|
42572
42582
|
function buildNextConfigTemplate(database) {
|
|
42573
42583
|
return `import type { NextConfig } from "next";
|
|
42584
|
+
${HTML_LIMITED_BOTS_IMPORT}
|
|
42574
42585
|
|
|
42575
42586
|
const nextConfig: NextConfig = {
|
|
42576
42587
|
${CACHE_COMPONENTS_ON}
|
|
42577
42588
|
serverExternalPackages: ${packageListLiteral(database)},
|
|
42589
|
+
${HTML_LIMITED_BOTS_LINE}
|
|
42578
42590
|
};
|
|
42579
42591
|
|
|
42580
42592
|
export default nextConfig;
|
|
@@ -42583,6 +42595,7 @@ export default nextConfig;
|
|
|
42583
42595
|
/** The same config as a JavaScript module, for an app without TypeScript. */
|
|
42584
42596
|
function buildNextConfigModule(database) {
|
|
42585
42597
|
return `${REQUIRE_IMPORT}
|
|
42598
|
+
${HTML_LIMITED_BOTS_IMPORT}
|
|
42586
42599
|
|
|
42587
42600
|
${REQUIRE_DECLARATION}
|
|
42588
42601
|
|
|
@@ -42590,6 +42603,7 @@ ${REQUIRE_DECLARATION}
|
|
|
42590
42603
|
const nextConfig = {
|
|
42591
42604
|
${CACHE_COMPONENTS_ON}
|
|
42592
42605
|
serverExternalPackages: ${packageListLiteral(database)},
|
|
42606
|
+
${HTML_LIMITED_BOTS_LINE}
|
|
42593
42607
|
};
|
|
42594
42608
|
|
|
42595
42609
|
export default nextConfig;
|
|
@@ -45973,41 +45987,56 @@ const SEARCH_INDEX_SCRIPT = path.join("scripts", "build-search-index.mjs");
|
|
|
45973
45987
|
async function projectHasSearchIndexScript(targetDir) {
|
|
45974
45988
|
return import_lib$1.default.pathExists(path.join(targetDir, SEARCH_INDEX_SCRIPT));
|
|
45975
45989
|
}
|
|
45976
|
-
/**
|
|
45977
|
-
|
|
45978
|
-
* imports from a `@nextlyhq/plugin-*` package (the SDK aside) that a
|
|
45979
|
-
* `plugins: [...]` list in it names, however deep in an element. Read with
|
|
45980
|
-
* the parser the Next config step uses, so nested brackets, either quote and
|
|
45981
|
-
* default or aliased imports are read as the compiler reads them. First-party
|
|
45982
|
-
* plugins register under their package name, which is what
|
|
45983
|
-
* `nextly plugins install` takes. Throws for a config that does not parse,
|
|
45984
|
-
* since every template's must.
|
|
45985
|
-
*
|
|
45986
|
-
* Exported for the test that holds every template's config to its build.
|
|
45987
|
-
*/
|
|
45988
|
-
function configuredPlugins(configText, file = "nextly.config.ts") {
|
|
45989
|
-
let program;
|
|
45990
|
+
/** Parses a config, naming the file when it does not parse. */
|
|
45991
|
+
function parseConfigProgram(configText, file) {
|
|
45990
45992
|
try {
|
|
45991
|
-
|
|
45993
|
+
return (0, import_lib.parse)(configText, {
|
|
45992
45994
|
sourceType: "module",
|
|
45993
45995
|
plugins: ["typescript", "jsx"]
|
|
45994
45996
|
}).program;
|
|
45995
45997
|
} catch (error) {
|
|
45996
45998
|
throw new Error(`${file} cannot be parsed (${error.message}), so the plugins its build must install cannot be read.`);
|
|
45997
45999
|
}
|
|
45998
|
-
|
|
46000
|
+
}
|
|
46001
|
+
/** Each binding imported from a module `matches` accepts, to that module's name. */
|
|
46002
|
+
function bindingsImportedFrom(program, matches) {
|
|
46003
|
+
const bindings = /* @__PURE__ */ new Map();
|
|
45999
46004
|
for (const statement of program.body) {
|
|
46000
46005
|
if (statement.type !== "ImportDeclaration") continue;
|
|
46001
|
-
|
|
46002
|
-
|
|
46003
|
-
for (const specifier of statement.specifiers) fromPackage.set(specifier.local.name, pkg);
|
|
46006
|
+
if (!matches(statement.source.value)) continue;
|
|
46007
|
+
for (const specifier of statement.specifiers) bindings.set(specifier.local.name, statement.source.value);
|
|
46004
46008
|
}
|
|
46005
|
-
|
|
46009
|
+
return bindings;
|
|
46010
|
+
}
|
|
46011
|
+
const isPluginPackage = (source) => source.startsWith("@nextlyhq/plugin-") && source !== "@nextlyhq/plugin-sdk";
|
|
46012
|
+
/** What a config's `plugins` lists hold: the packages, and whether a binding from its own source is among them. */
|
|
46013
|
+
function readPluginLists(configText, file) {
|
|
46014
|
+
const program = parseConfigProgram(configText, file);
|
|
46015
|
+
const fromPackage = bindingsImportedFrom(program, isPluginPackage);
|
|
46016
|
+
const packages = /* @__PURE__ */ new Set();
|
|
46006
46017
|
for (const name of identifiersInPluginLists(program, file)) {
|
|
46007
46018
|
const pkg = fromPackage.get(name);
|
|
46008
|
-
if (pkg !== void 0
|
|
46019
|
+
if (pkg !== void 0) packages.add(pkg);
|
|
46009
46020
|
}
|
|
46010
|
-
|
|
46021
|
+
const local = bindingsImportedFrom(program, (source) => source.startsWith("."));
|
|
46022
|
+
const ownPlugin = namesInPluginEntries(program, file).some((name) => local.has(name) && !fromPackage.has(name));
|
|
46023
|
+
return {
|
|
46024
|
+
packages: [...packages],
|
|
46025
|
+
ownPlugin
|
|
46026
|
+
};
|
|
46027
|
+
}
|
|
46028
|
+
/**
|
|
46029
|
+
* The `nextly plugins install` steps a project's build runs, read from its
|
|
46030
|
+
* config. A plugin package is installed by name, and the build says which. A
|
|
46031
|
+
* plugin the site wrote itself has no package name to give, and a production
|
|
46032
|
+
* boot refuses it like any other when nothing has installed it, so a config
|
|
46033
|
+
* that lists one installs with `--all`, which reads the names from the config.
|
|
46034
|
+
* Exported for the test that holds every template's config to its build.
|
|
46035
|
+
*/
|
|
46036
|
+
function pluginInstallSteps(configText, file = "nextly.config.ts") {
|
|
46037
|
+
const { packages, ownPlugin } = readPluginLists(configText, file);
|
|
46038
|
+
if (ownPlugin) return ["nextly plugins install --all"];
|
|
46039
|
+
return packages.map((pkg) => `nextly plugins install ${pkg}`);
|
|
46011
46040
|
}
|
|
46012
46041
|
/** Every identifier inside the value of each `plugins: [...]` property, in source order. */
|
|
46013
46042
|
function identifiersInPluginLists(program, file) {
|
|
@@ -46021,6 +46050,20 @@ function identifiersInPluginLists(program, file) {
|
|
|
46021
46050
|
return names;
|
|
46022
46051
|
}
|
|
46023
46052
|
/**
|
|
46053
|
+
* The binding each entry of a `plugins: [...]` list is, as written: `seo` for
|
|
46054
|
+
* `seo` or `seo({ ... })`. Narrower than {@link identifiersInPluginLists},
|
|
46055
|
+
* which also sees the identifiers inside an entry's options.
|
|
46056
|
+
*/
|
|
46057
|
+
function namesInPluginEntries(program, file) {
|
|
46058
|
+
const names = [];
|
|
46059
|
+
walkNodes(program, (node) => {
|
|
46060
|
+
if (!isPluginList(node, file) || node.value.type !== "ArrayExpression") return;
|
|
46061
|
+
for (const element of node.value.elements) if (element?.type === "Identifier") names.push(element.name);
|
|
46062
|
+
else if (element?.type === "CallExpression" && element.callee.type === "Identifier") names.push(element.callee.name);
|
|
46063
|
+
});
|
|
46064
|
+
return names;
|
|
46065
|
+
}
|
|
46066
|
+
/**
|
|
46024
46067
|
* A `plugins: [...]` property, by an identifier or a string key. A `plugins`
|
|
46025
46068
|
* property written any other way, such as a variable holding the list, a call
|
|
46026
46069
|
* or a spread inside it, is
|
|
@@ -46052,16 +46095,15 @@ function isNode(value) {
|
|
|
46052
46095
|
return typeof value === "object" && value !== null && typeof value.type === "string";
|
|
46053
46096
|
}
|
|
46054
46097
|
/**
|
|
46055
|
-
* The
|
|
46056
|
-
* finished project as {@link projectHasSearchIndexScript} is: a template
|
|
46057
|
-
* offers more than one config
|
|
46058
|
-
*
|
|
46059
|
-
* no project on disk to ask.
|
|
46098
|
+
* The plugin install steps the scaffolded PROJECT's build needs, read from
|
|
46099
|
+
* the finished project as {@link projectHasSearchIndexScript} is: a template
|
|
46100
|
+
* offers more than one config, so only the file the copy wrote can say. None
|
|
46101
|
+
* when there is no config, or no project on disk to ask.
|
|
46060
46102
|
*/
|
|
46061
|
-
async function
|
|
46103
|
+
async function projectPluginInstalls(targetDir) {
|
|
46062
46104
|
if (targetDir === void 0) return [];
|
|
46063
46105
|
const config = path.join(targetDir, "nextly.config.ts");
|
|
46064
|
-
return await import_lib$1.default.pathExists(config) ?
|
|
46106
|
+
return await import_lib$1.default.pathExists(config) ? pluginInstallSteps(await import_lib$1.default.readFile(config, "utf-8"), config) : [];
|
|
46065
46107
|
}
|
|
46066
46108
|
/**
|
|
46067
46109
|
* Every file under `root` that could carry an import specifier.
|
|
@@ -46654,7 +46696,7 @@ async function generatePackageJson(projectName, database, source = nextlySource(
|
|
|
46654
46696
|
esbuild: PINNED_VERSIONS.esbuild
|
|
46655
46697
|
};
|
|
46656
46698
|
const shipsSearchIndex = targetDir ? await projectHasSearchIndexScript(targetDir) : false;
|
|
46657
|
-
const
|
|
46699
|
+
const pluginInstalls = await projectPluginInstalls(targetDir);
|
|
46658
46700
|
if (shipsSearchIndex) devDependencies.pagefind = "^1.1.0";
|
|
46659
46701
|
const pkg = {
|
|
46660
46702
|
name: projectName,
|
|
@@ -46664,7 +46706,7 @@ async function generatePackageJson(projectName, database, source = nextlySource(
|
|
|
46664
46706
|
dev: "next dev --turbopack",
|
|
46665
46707
|
build: [
|
|
46666
46708
|
"nextly migrate",
|
|
46667
|
-
...
|
|
46709
|
+
...pluginInstalls,
|
|
46668
46710
|
"next build",
|
|
46669
46711
|
...shipsSearchIndex ? ["node scripts/build-search-index.mjs"] : []
|
|
46670
46712
|
].join(" && "),
|
|
@@ -47320,6 +47362,15 @@ const ADMIN_LAYOUT = {
|
|
|
47320
47362
|
path: "admin/[[...params]]/layout.tsx",
|
|
47321
47363
|
importsConfig: true
|
|
47322
47364
|
};
|
|
47365
|
+
/**
|
|
47366
|
+
* The admin component map's two generated files, under the app's source root,
|
|
47367
|
+
* as the base template commits them: the admin layout imports the list, and
|
|
47368
|
+
* the admin page imports the map that registers the components. Read with the
|
|
47369
|
+
* routes, so an app Nextly is added to starts from the template's own empty
|
|
47370
|
+
* map rather than a second one written out here, and `next dev` rewrites them
|
|
47371
|
+
* as plugins are added.
|
|
47372
|
+
*/
|
|
47373
|
+
const ADMIN_COMPONENT_MAP_FILES = ["types/generated/plugin-admin-components.generated.ts", "types/generated/plugin-admin-imports.generated.ts"];
|
|
47323
47374
|
/** Every file the existing-app path writes from the templates, read together. */
|
|
47324
47375
|
const ALL_ROUTES = [
|
|
47325
47376
|
...ROUTES,
|
|
@@ -47425,6 +47476,15 @@ async function readMediaRouteTemplates(templatesDir = resolveTemplatePath()) {
|
|
|
47425
47476
|
if (route.importsConfig && !CONFIG_IMPORT.test(text)) throw new Error(`The template's ${route.path} does not import the Nextly config, so no route that finds it can be written. Nothing was installed or written.`);
|
|
47426
47477
|
texts.set(route.path, text);
|
|
47427
47478
|
}
|
|
47479
|
+
for (const file of ADMIN_COMPONENT_MAP_FILES) {
|
|
47480
|
+
const relative = `base/src/${file}`;
|
|
47481
|
+
try {
|
|
47482
|
+
texts.set(file, await import_lib$1.default.readFile(path.join(templatesDir, relative), "utf-8"));
|
|
47483
|
+
} catch (error) {
|
|
47484
|
+
const code = error.code ?? "unreadable";
|
|
47485
|
+
throw new Error(`The templates at ${templatesDir} have no readable ${relative} (${code}), so Nextly's admin component map cannot be added. Nothing was installed or written; check the --local-template path if one was given.`);
|
|
47486
|
+
}
|
|
47487
|
+
}
|
|
47428
47488
|
return texts;
|
|
47429
47489
|
}
|
|
47430
47490
|
/**
|
|
@@ -47875,10 +47935,71 @@ function skipped(cwd, left, target, text, role, reason) {
|
|
|
47875
47935
|
function toPosix(p) {
|
|
47876
47936
|
return p.split(path.sep).join("/");
|
|
47877
47937
|
}
|
|
47938
|
+
// src/generators/types.ts
|
|
47939
|
+
/**
|
|
47940
|
+
* Where the generated types file goes, relative to the project root: under
|
|
47941
|
+
* src/ when the app keeps its code there, at the root when it does not. The
|
|
47942
|
+
* config names this path and the types step creates it, so both read it here.
|
|
47943
|
+
*/
|
|
47944
|
+
function typesOutputFile(projectInfo) {
|
|
47945
|
+
return `${projectInfo.srcDir ? "./src" : "."}/types/generated/nextly-types.ts`;
|
|
47946
|
+
}
|
|
47947
|
+
/**
|
|
47948
|
+
* The folder the generated files go in, relative to the project root, as
|
|
47949
|
+
* {@link typesOutputFile} names it: the admin layout and page import the
|
|
47950
|
+
* component map from here.
|
|
47951
|
+
*/
|
|
47952
|
+
function typesOutputFolder(projectInfo) {
|
|
47953
|
+
return path.posix.dirname(path.posix.normalize(typesOutputFile(projectInfo)));
|
|
47954
|
+
}
|
|
47955
|
+
/**
|
|
47956
|
+
* Create the types directory structure for generated TypeScript types.
|
|
47957
|
+
* This mirrors what `nextly init` does - creates the directory and a placeholder file.
|
|
47958
|
+
* The actual types are generated when running `next dev` (which boots Nextly
|
|
47959
|
+
* and emits types lazily) or `npx nextly generate:types`.
|
|
47960
|
+
*/
|
|
47961
|
+
async function generateTypesDirectory(cwd, projectInfo, templates) {
|
|
47962
|
+
const files = nothingYet();
|
|
47963
|
+
const typesFile = path.posix.normalize(typesOutputFile(projectInfo));
|
|
47964
|
+
const typesDir = typesOutputFolder(projectInfo);
|
|
47965
|
+
await writeNew(cwd, `${typesDir}/.gitkeep`, "", files, { why: "it is already there" });
|
|
47966
|
+
await writeNew(cwd, typesFile, `/**
|
|
47967
|
+
* Nextly Generated Types
|
|
47968
|
+
*
|
|
47969
|
+
* This file will be auto-generated when you run:
|
|
47970
|
+
* next dev (Nextly emits types on first boot)
|
|
47971
|
+
* npx nextly generate:types
|
|
47972
|
+
*
|
|
47973
|
+
* Do not edit this file manually - it will be overwritten.
|
|
47974
|
+
*/
|
|
47975
|
+
|
|
47976
|
+
// Types will be generated here after running next dev
|
|
47977
|
+
export {};
|
|
47978
|
+
`, files, { why: "it is already there; Nextly writes the types into it when they are generated" });
|
|
47979
|
+
for (const file of ADMIN_COMPONENT_MAP_FILES) {
|
|
47980
|
+
const text = templates.get(file);
|
|
47981
|
+
if (text === void 0) throw new Error(`The templates read for this app hold no ${file}, so Nextly's admin component map cannot be written.`);
|
|
47982
|
+
await writeNew(cwd, `${typesDir}/${path.posix.basename(file)}`, text, files, { why: "it is already there; `next dev` and `nextly generate:types` keep it current" });
|
|
47983
|
+
}
|
|
47984
|
+
return files;
|
|
47985
|
+
}
|
|
47878
47986
|
// src/generators/admin.ts
|
|
47879
|
-
|
|
47987
|
+
/**
|
|
47988
|
+
* The generated component map's two files, by the name a module imports them
|
|
47989
|
+
* as: the list the layout reads, and the map the page loads to register the
|
|
47990
|
+
* components.
|
|
47991
|
+
*/
|
|
47992
|
+
const COMPONENT_LIST = "plugin-admin-components.generated";
|
|
47993
|
+
const COMPONENT_MAP = "plugin-admin-imports.generated";
|
|
47994
|
+
/** How the file at `target` imports `name` from the app's generated types folder. */
|
|
47995
|
+
function generatedImport(cwd, target, projectInfo, name) {
|
|
47996
|
+
const relative = path.relative(path.dirname(target), path.join(cwd, typesOutputFolder(projectInfo), name)).split(path.sep).join("/");
|
|
47997
|
+
return relative.startsWith(".") ? relative : `./${relative}`;
|
|
47998
|
+
}
|
|
47999
|
+
const adminPageTemplate = (componentMap) => `"use client";
|
|
47880
48000
|
|
|
47881
48001
|
import "@nextlyhq/admin/style.css";
|
|
48002
|
+
import "${componentMap}";
|
|
47882
48003
|
import { RootLayout, QueryProvider, ErrorBoundary } from "@nextlyhq/admin";
|
|
47883
48004
|
|
|
47884
48005
|
export default function AdminPage() {
|
|
@@ -47897,14 +48018,16 @@ export default function AdminPage() {
|
|
|
47897
48018
|
`;
|
|
47898
48019
|
/**
|
|
47899
48020
|
* The admin layout, as the base template holds it, with its config import
|
|
47900
|
-
* pointing at the project's `nextly.config
|
|
47901
|
-
*
|
|
47902
|
-
*
|
|
48021
|
+
* pointing at the project's `nextly.config`, and its component-list import at
|
|
48022
|
+
* the app's generated types folder, from where the layout is written. One
|
|
48023
|
+
* source with a new project's layout, so an app Nextly is added to gets the
|
|
48024
|
+
* same per-request admin.
|
|
47903
48025
|
*/
|
|
47904
|
-
function adminLayout(cwd, adminDir, templates) {
|
|
48026
|
+
function adminLayout(cwd, adminDir, projectInfo, templates) {
|
|
47905
48027
|
const text = templates.get(ADMIN_LAYOUT.path);
|
|
47906
48028
|
if (text === void 0) throw new Error(`The templates read for this app hold no ${ADMIN_LAYOUT.path}, so Nextly's admin layout cannot be written.`);
|
|
47907
|
-
|
|
48029
|
+
const target = path.join(cwd, adminDir, "layout.tsx");
|
|
48030
|
+
return withRelativeConfigImport(text, cwd, target, ADMIN_LAYOUT.path).replace(new RegExp(`"[^"]*/${COMPONENT_LIST.replaceAll(".", "\\.")}"`), `"${generatedImport(cwd, target, projectInfo, COMPONENT_LIST)}"`);
|
|
47908
48031
|
}
|
|
47909
48032
|
/**
|
|
47910
48033
|
* Generate the admin panel page and layout.
|
|
@@ -47913,56 +48036,23 @@ function adminLayout(cwd, adminDir, templates) {
|
|
|
47913
48036
|
async function generateAdminPage(cwd, projectInfo, templates) {
|
|
47914
48037
|
const files = nothingYet();
|
|
47915
48038
|
const adminDir = `${projectInfo.appDir}/admin/[[...params]]`;
|
|
47916
|
-
const layout = adminLayout(cwd, adminDir, templates);
|
|
48039
|
+
const layout = adminLayout(cwd, adminDir, projectInfo, templates);
|
|
48040
|
+
const page = adminPageTemplate(generatedImport(cwd, path.join(cwd, adminDir, "page.tsx"), projectInfo, COMPONENT_MAP));
|
|
47917
48041
|
const pages = await appPageExtensions(cwd);
|
|
47918
48042
|
if (pages.extensions !== "absent") {
|
|
47919
48043
|
const { configName, extensions } = pages;
|
|
47920
|
-
for (const [name, text] of [["page",
|
|
48044
|
+
for (const [name, text] of [["page", page], ["layout", layout]]) files.skipped.push(pageExtensionsSkip(`${adminDir}/${name}`, text, {
|
|
47921
48045
|
configName,
|
|
47922
48046
|
extensions
|
|
47923
48047
|
}, TSX_FILE));
|
|
47924
48048
|
return files;
|
|
47925
48049
|
}
|
|
47926
|
-
for (const [name, text] of [["page.tsx",
|
|
48050
|
+
for (const [name, text] of [["page.tsx", page], ["layout.tsx", layout]]) await writeNew(cwd, `${adminDir}/${name}`, text, files, {
|
|
47927
48051
|
why: `the app already has one; Nextly's admin needs its own ${name}, which is`,
|
|
47928
48052
|
toAdd: text
|
|
47929
48053
|
});
|
|
47930
48054
|
return files;
|
|
47931
48055
|
}
|
|
47932
|
-
// src/generators/types.ts
|
|
47933
|
-
/**
|
|
47934
|
-
* Where the generated types file goes, relative to the project root: under
|
|
47935
|
-
* src/ when the app keeps its code there, at the root when it does not. The
|
|
47936
|
-
* config names this path and the types step creates it, so both read it here.
|
|
47937
|
-
*/
|
|
47938
|
-
function typesOutputFile(projectInfo) {
|
|
47939
|
-
return `${projectInfo.srcDir ? "./src" : "."}/types/generated/nextly-types.ts`;
|
|
47940
|
-
}
|
|
47941
|
-
/**
|
|
47942
|
-
* Create the types directory structure for generated TypeScript types.
|
|
47943
|
-
* This mirrors what `nextly init` does - creates the directory and a placeholder file.
|
|
47944
|
-
* The actual types are generated when running `next dev` (which boots Nextly
|
|
47945
|
-
* and emits types lazily) or `npx nextly generate:types`.
|
|
47946
|
-
*/
|
|
47947
|
-
async function generateTypesDirectory(cwd, projectInfo) {
|
|
47948
|
-
const files = nothingYet();
|
|
47949
|
-
const typesFile = path.posix.normalize(typesOutputFile(projectInfo));
|
|
47950
|
-
await writeNew(cwd, `${path.posix.dirname(typesFile)}/.gitkeep`, "", files, { why: "it is already there" });
|
|
47951
|
-
await writeNew(cwd, typesFile, `/**
|
|
47952
|
-
* Nextly Generated Types
|
|
47953
|
-
*
|
|
47954
|
-
* This file will be auto-generated when you run:
|
|
47955
|
-
* next dev (Nextly emits types on first boot)
|
|
47956
|
-
* npx nextly generate:types
|
|
47957
|
-
*
|
|
47958
|
-
* Do not edit this file manually - it will be overwritten.
|
|
47959
|
-
*/
|
|
47960
|
-
|
|
47961
|
-
// Types will be generated here after running next dev
|
|
47962
|
-
export {};
|
|
47963
|
-
`, files, { why: "it is already there; Nextly writes the types into it when they are generated" });
|
|
47964
|
-
return files;
|
|
47965
|
-
}
|
|
47966
48056
|
// src/generators/config.ts
|
|
47967
48057
|
/**
|
|
47968
48058
|
* Base templates for project types that use inline config generation.
|
|
@@ -48045,9 +48135,12 @@ function startNextly(configImport) {
|
|
|
48045
48135
|
// Next.js writes its Cache Components setting into this file as it builds
|
|
48046
48136
|
// it. Nextly, loaded from node_modules, cannot read that for itself. With
|
|
48047
48137
|
// it off, Nextly warns at start; with it on, a cached read that finds no
|
|
48048
|
-
// "use cache" read function says so.
|
|
48138
|
+
// "use cache" read function says so. The same holds for the build's newest
|
|
48139
|
+
// migration, which withNextly sets: a production start compares it with
|
|
48140
|
+
// the database's schema version and warns when the database is behind.
|
|
48049
48141
|
await createRegister(config, {
|
|
48050
48142
|
cacheComponents: process.env.__NEXT_CACHE_COMPONENTS,
|
|
48143
|
+
buildSchemaVersion: process.env.NEXTLY_BUILD_SCHEMA_VERSION,
|
|
48051
48144
|
})();`;
|
|
48052
48145
|
}
|
|
48053
48146
|
/** The whole hook, as the blank template ships it. */
|
|
@@ -48195,7 +48288,7 @@ async function generateIntoExistingApp(cwd, projectType, projectInfo, database,
|
|
|
48195
48288
|
await generateMediaRoutes(cwd, projectInfo, templates),
|
|
48196
48289
|
await generateUploadsRoute(cwd, projectInfo, templates),
|
|
48197
48290
|
await generateInstrumentation(cwd, projectInfo),
|
|
48198
|
-
await generateTypesDirectory(cwd, projectInfo),
|
|
48291
|
+
await generateTypesDirectory(cwd, projectInfo, templates),
|
|
48199
48292
|
nextConfigFiles(await patchNextConfig(cwd, database)),
|
|
48200
48293
|
cacheComponentsFiles(await turnOnCacheComponents(cwd))
|
|
48201
48294
|
];
|
|
@@ -52996,4 +53089,4 @@ async function createNextly(options = {}) {
|
|
|
52996
53089
|
}
|
|
52997
53090
|
export { getAvailableTemplateNames as a, init as c, __require as d, __toESM$1 as f, validateTemplateName as i, shutdown as l, resolveProjectArg as n, packageVersion as o, validateProjectName as r, capture as s, createNextly as t, __commonJSMin$1 as u };
|
|
52998
53091
|
|
|
52999
|
-
//# sourceMappingURL=create-nextly-
|
|
53092
|
+
//# sourceMappingURL=create-nextly-N_COehCu.mjs.map
|