create-nextly-app 0.0.2-alpha.70 → 0.0.2-alpha.72

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
- const require_create_nextly = require("./create-nextly-BbKGDrEC.cjs");
3
+ const require_create_nextly = require("./create-nextly-BGu1tXYs.cjs");
4
4
  // ../../node_modules/.pnpm/commander@14.0.2/node_modules/commander/lib/error.js
5
5
  var require_error = /* @__PURE__ */ require_create_nextly.__commonJSMin(((exports) => {
6
6
  /**
package/dist/cli.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { a as getAvailableTemplateNames, c as init, d as __require, f as __toESM, i as validateTemplateName, l as shutdown, n as resolveProjectArg, o as packageVersion, r as validateProjectName, s as capture, t as createNextly, u as __commonJSMin } from "./create-nextly-5wiGMVI6.mjs";
2
+ import { a as getAvailableTemplateNames, c as init, d as __require, f as __toESM, i as validateTemplateName, l as shutdown, n as resolveProjectArg, o as packageVersion, r as validateProjectName, s as capture, t as createNextly, u as __commonJSMin } from "./create-nextly-CyI8XgVc.mjs";
3
3
  // ../../node_modules/.pnpm/commander@14.0.2/node_modules/commander/lib/error.js
4
4
  var require_error = /* @__PURE__ */ __commonJSMin(((exports) => {
5
5
  /**
@@ -8066,6 +8066,38 @@ var require_utils$3 = /* @__PURE__ */ __commonJSMin(((exports, module) => {
8066
8066
  return output.join("");
8067
8067
  }
8068
8068
  /**
8069
+ * Removes dot segments from the path of a relative reference (a path that does
8070
+ * not start with "/") without changing what it resolves to against any base.
8071
+ * Unlike `removeDotSegments`, leading ".." segments that cannot be collapsed
8072
+ * are kept, the result never becomes root-relative, and a result that would be
8073
+ * empty or start with an empty segment is prefixed with "." (an empty path
8074
+ * means "same document" and a leading "//" would introduce an authority).
8075
+ *
8076
+ * @param {string} path
8077
+ * @returns {string}
8078
+ */
8079
+ function removeDotSegmentsRelative(path) {
8080
+ if (path === "" || path[0] === "/") return removeDotSegments(path);
8081
+ const segments = path.split("/");
8082
+ const last = segments.length - 1;
8083
+ /** @type {string[]} */
8084
+ const output = [];
8085
+ let trailingDirectory = false;
8086
+ for (let i = 0; i <= last; i++) {
8087
+ const segment = segments[i];
8088
+ if (segment === "." || segment === "..") {
8089
+ if (segment === "..") {
8090
+ if (output.length !== 0 && output[output.length - 1] !== "..") output.pop();
8091
+ else output.push("..");
8092
+ }
8093
+ trailingDirectory = i === last;
8094
+ } else output.push(segment);
8095
+ }
8096
+ if (trailingDirectory && output[output.length - 1] !== "..") output.push("");
8097
+ if (output.length === 0 || output[0] === "" || output[0].includes(":")) output.unshift(".");
8098
+ return output.join("/");
8099
+ }
8100
+ /**
8069
8101
  * Re-escape RFC 3986 gen-delims that must not appear literally in the host.
8070
8102
  * After the URI regex parses, these characters cannot be literal in the host
8071
8103
  * field, so any that appear after decoding came from percent-encoding and
@@ -8369,6 +8401,7 @@ var require_utils$3 = /* @__PURE__ */ __commonJSMin(((exports, module) => {
8369
8401
  encodeFragment,
8370
8402
  escapePreservingEscapes,
8371
8403
  removeDotSegments,
8404
+ removeDotSegmentsRelative,
8372
8405
  isIPv4,
8373
8406
  isUUID,
8374
8407
  normalizeIPv6,
@@ -8558,18 +8591,24 @@ var require_schemes = /* @__PURE__ */ __commonJSMin(((exports, module) => {
8558
8591
  };
8559
8592
  }));
8560
8593
  var require_fast_uri = /* @__PURE__ */ __commonJSMin(((exports, module) => {
8561
- const { normalizeIPv6, removeDotSegments, recomposeAuthority, normalizePercentEncoding, normalizePathEncoding, serializePathEncoding, normalizeQueryFragmentEncoding, encodeQuery, encodeFragment, reescapeHostDelimiters, isIPv4, nonSimpleDomain } = require_utils$3();
8594
+ const { normalizeIPv6, removeDotSegments, removeDotSegmentsRelative, recomposeAuthority, normalizePercentEncoding, normalizePathEncoding, serializePathEncoding, normalizeQueryFragmentEncoding, encodeQuery, encodeFragment, reescapeHostDelimiters, isIPv4, nonSimpleDomain } = require_utils$3();
8562
8595
  const { SCHEMES, getSchemeHandler } = require_schemes();
8563
8596
  const VALID_SCHEME = /^[A-Za-z][A-Za-z0-9+.-]*$/u;
8564
8597
  const MALFORMED_SCHEME_ERROR = "URI scheme is malformed.";
8598
+ const MALFORMED_HOST_ERROR = "URI host is malformed.";
8599
+ const FORBIDDEN_DOMAIN_HOST_CHARACTER = /[\0-\x20"#/:<>?@[\\\]^`{|}\x7F]/u;
8565
8600
  /**
8601
+ * RFC 3986 section 3.1 does not allow percent-encoding in a scheme, so the
8602
+ * scheme is validated as-is and never decoded. Decoding would let inert input
8603
+ * such as `%6Aavascript:` become a live `javascript:` scheme.
8604
+ *
8566
8605
  * @param {string} scheme
8567
8606
  * @returns {string}
8568
8607
  */
8569
- function decodeValidScheme(scheme) {
8570
- const decodedScheme = unescape(String(scheme));
8571
- if (!VALID_SCHEME.test(decodedScheme)) throw new TypeError(MALFORMED_SCHEME_ERROR);
8572
- return decodedScheme;
8608
+ function validateScheme(scheme) {
8609
+ const stringScheme = String(scheme);
8610
+ if (!VALID_SCHEME.test(stringScheme)) throw new TypeError(MALFORMED_SCHEME_ERROR);
8611
+ return stringScheme;
8573
8612
  }
8574
8613
  /**
8575
8614
  * @template {import('./types/index').URIComponent|string} T
@@ -8597,6 +8636,7 @@ var require_fast_uri = /* @__PURE__ */ __commonJSMin(((exports, module) => {
8597
8636
  const resolvedSchemeHandler = getSchemeHandler(options && options.scheme || resolved.scheme);
8598
8637
  const resolvedHost = resolved.host;
8599
8638
  const resolvedHostIsIP = resolvedHost !== void 0 && resolvedHost !== "" && (isIPv4(resolvedHost) || normalizeIPv6(resolvedHost).isIPV6);
8639
+ if (hasForbiddenDomainHost(resolved, options || {}, resolvedSchemeHandler, resolvedHostIsIP)) throw new Error(MALFORMED_HOST_ERROR);
8600
8640
  canonicalizeHost(resolved, options || {}, resolvedSchemeHandler, resolvedHostIsIP);
8601
8641
  const encodedASCIIHost = resolvedHost && resolvedHost.indexOf("%") !== -1 && !/\P{ASCII}/u.test(resolvedHost);
8602
8642
  if (resolved.error && !encodedASCIIHost) throw new Error(resolved.error);
@@ -8640,10 +8680,11 @@ var require_fast_uri = /* @__PURE__ */ __commonJSMin(((exports, module) => {
8640
8680
  } else {
8641
8681
  if (relative.path[0] === "/") target.path = removeDotSegments(relative.path);
8642
8682
  else {
8643
- if ((base.userinfo !== void 0 || base.host !== void 0 || base.port !== void 0) && !base.path) target.path = "/" + relative.path;
8683
+ const baseHasAuthority = base.userinfo !== void 0 || base.host !== void 0 || base.port !== void 0;
8684
+ if (baseHasAuthority && !base.path) target.path = "/" + relative.path;
8644
8685
  else if (!base.path) target.path = relative.path;
8645
8686
  else target.path = base.path.slice(0, base.path.lastIndexOf("/") + 1) + relative.path;
8646
- target.path = removeDotSegments(target.path);
8687
+ target.path = base.scheme === void 0 && !baseHasAuthority && target.path[0] !== "/" ? removeDotSegmentsRelative(target.path) : removeDotSegments(target.path);
8647
8688
  }
8648
8689
  target.query = relative.query;
8649
8690
  }
@@ -8691,17 +8732,18 @@ var require_fast_uri = /* @__PURE__ */ __commonJSMin(((exports, module) => {
8691
8732
  };
8692
8733
  const options = Object.assign({}, opts);
8693
8734
  const uriTokens = [];
8694
- if (component.scheme) component.scheme = decodeValidScheme(component.scheme);
8735
+ if (component.scheme) component.scheme = validateScheme(component.scheme);
8695
8736
  const schemeHandler = getSchemeHandler(options.scheme || component.scheme);
8696
8737
  if (schemeHandler && schemeHandler.serialize) schemeHandler.serialize(component, options);
8697
8738
  const hasAuthority = component.userinfo !== void 0 || component.host !== void 0 || component.port !== void 0;
8698
- const pathNoScheme = !options.skipEscape && component.scheme === void 0 && !hasAuthority;
8739
+ const schemelessReference = (component.scheme === void 0 || options.reference === "suffix") && !hasAuthority;
8740
+ const pathNoScheme = !options.skipEscape && schemelessReference;
8699
8741
  if (component.path !== void 0) {
8700
8742
  if (!options.skipEscape) component.path = serializePathEncoding(component.path, pathNoScheme);
8701
8743
  else component.path = normalizePercentEncoding(component.path);
8702
8744
  }
8703
8745
  if (options.reference !== "suffix" && component.scheme) {
8704
- component.scheme = decodeValidScheme(component.scheme);
8746
+ component.scheme = validateScheme(component.scheme);
8705
8747
  uriTokens.push(component.scheme, ":");
8706
8748
  }
8707
8749
  const authority = recomposeAuthority(component);
@@ -8712,8 +8754,8 @@ var require_fast_uri = /* @__PURE__ */ __commonJSMin(((exports, module) => {
8712
8754
  }
8713
8755
  if (component.path !== void 0) {
8714
8756
  let s = component.path;
8715
- if (!options.absolutePath && (!schemeHandler || !schemeHandler.absolutePath)) s = removeDotSegments(s);
8716
- if (pathNoScheme) s = serializePathEncoding(s, true);
8757
+ if (!options.absolutePath && (!schemeHandler || !schemeHandler.absolutePath)) s = schemelessReference && s[0] !== "/" ? removeDotSegmentsRelative(s) : removeDotSegments(s);
8758
+ if (schemelessReference) s = serializePathEncoding(s, true);
8717
8759
  if (authority === void 0 && s[0] === "/" && s[1] === "/") s = "/%2F" + s.slice(2);
8718
8760
  uriTokens.push(s);
8719
8761
  }
@@ -8777,15 +8819,50 @@ var require_fast_uri = /* @__PURE__ */ __commonJSMin(((exports, module) => {
8777
8819
  * @returns {boolean} whether host conversion failed
8778
8820
  */
8779
8821
  function canonicalizeHost(parsed, options, schemeHandler, isIP) {
8780
- if (!options.unicodeSupport && (!schemeHandler || !schemeHandler.unicodeSupport) && parsed.host && !isIPLiteral(parsed.host) && (options.domainHost || schemeHandler && schemeHandler.domainHost) && isIP === false && nonSimpleDomain(parsed.host)) try {
8781
- parsed.host = new URL("http://" + parsed.host).hostname;
8782
- } catch (e) {
8783
- parsed.error = parsed.error || "Host's domain name can not be converted to ASCII: " + e;
8822
+ if (hasForbiddenDomainHost(parsed, options, schemeHandler, isIP)) {
8823
+ parsed.error = parsed.error || MALFORMED_HOST_ERROR;
8784
8824
  return true;
8785
8825
  }
8826
+ if (!options.unicodeSupport && (!schemeHandler || !schemeHandler.unicodeSupport) && parsed.host && !isIPLiteral(parsed.host) && (options.domainHost || schemeHandler && schemeHandler.domainHost) && isIP === false && nonSimpleDomain(parsed.host)) {
8827
+ let url;
8828
+ try {
8829
+ url = new URL("http://" + parsed.host);
8830
+ } catch (e) {
8831
+ parsed.error = parsed.error || "Host's domain name can not be converted to ASCII: " + e;
8832
+ return true;
8833
+ }
8834
+ if (!isHostOnlyURL(url)) {
8835
+ parsed.error = parsed.error || MALFORMED_HOST_ERROR;
8836
+ return true;
8837
+ }
8838
+ parsed.host = url.hostname;
8839
+ }
8786
8840
  return false;
8787
8841
  }
8788
8842
  /**
8843
+ * Whether a domain host contains an ASCII character that RFC 3986 does not
8844
+ * allow in a reg-name (unreserved, sub-delims, or pct-encoded). Such a host is
8845
+ * rejected instead of being handed to the WHATWG URL parser, which would treat
8846
+ * "@" as a userinfo delimiter (silently dropping the data before it) and strip
8847
+ * TAB, LF, and CR. Non-ASCII characters remain allowed for IDNs.
8848
+ *
8849
+ * @param {import('./types/index').URIComponent} parsed
8850
+ * @param {import('./types/index').Options} options
8851
+ * @param {{ domainHost?: boolean }|undefined} schemeHandler
8852
+ * @param {boolean} isIP
8853
+ * @returns {boolean}
8854
+ */
8855
+ function hasForbiddenDomainHost(parsed, options, schemeHandler, isIP) {
8856
+ return Boolean(parsed.host && isIP === false && !isIPLiteral(parsed.host) && (options.domainHost || schemeHandler && schemeHandler.domainHost) && FORBIDDEN_DOMAIN_HOST_CHARACTER.test(parsed.host));
8857
+ }
8858
+ /**
8859
+ * @param {URL} url
8860
+ * @returns {boolean}
8861
+ */
8862
+ function isHostOnlyURL(url) {
8863
+ return url.username === "" && url.password === "" && url.port === "" && url.pathname === "/" && url.search === "" && url.hash === "" && url.hostname !== "";
8864
+ }
8865
+ /**
8789
8866
  * @param {string} uri
8790
8867
  * @param {import('./types/index').Options} [opts]
8791
8868
  * @returns {{ parsed: import('./types/index').URIComponent, malformedAuthorityOrPort: boolean, malformedPercentEncoding: boolean, malformedSchemeSpecific: boolean, malformedHost: boolean, malformedScheme: boolean }}
@@ -8842,8 +8919,7 @@ var require_fast_uri = /* @__PURE__ */ __commonJSMin(((exports, module) => {
8842
8919
  parsed.query = matches[7];
8843
8920
  parsed.fragment = matches[8];
8844
8921
  if (parsed.scheme !== void 0) {
8845
- const decodedScheme = unescape(parsed.scheme);
8846
- if (VALID_SCHEME.test(decodedScheme)) parsed.scheme = decodedScheme.toLowerCase();
8922
+ if (VALID_SCHEME.test(parsed.scheme)) parsed.scheme = parsed.scheme.toLowerCase();
8847
8923
  else {
8848
8924
  parsed.error = parsed.error || MALFORMED_SCHEME_ERROR;
8849
8925
  malformedScheme = true;
@@ -8866,7 +8942,7 @@ var require_fast_uri = /* @__PURE__ */ __commonJSMin(((exports, module) => {
8866
8942
  malformedIPLiteral = hasIPLiteralBracket && (!bracketedIPLiteral || ipv6result.error === true);
8867
8943
  parsed.host = isIP ? ipv6result.host : ipv6result.host.toLowerCase();
8868
8944
  if (malformedIPLiteral) {
8869
- parsed.error = parsed.error || "URI host is malformed.";
8945
+ parsed.error = parsed.error || MALFORMED_HOST_ERROR;
8870
8946
  malformedAuthorityOrPort = true;
8871
8947
  }
8872
8948
  } else isIP = true;
@@ -8878,13 +8954,12 @@ var require_fast_uri = /* @__PURE__ */ __commonJSMin(((exports, module) => {
8878
8954
  if (options.reference && options.reference !== "suffix" && options.reference !== parsed.reference) parsed.error = parsed.error || "URI is not a " + options.reference + " reference.";
8879
8955
  const schemeHandler = getSchemeHandler(options.scheme || parsed.scheme);
8880
8956
  if (!malformedIPLiteral) malformedHost = canonicalizeHost(parsed, options, schemeHandler, isIP);
8957
+ if (uri.indexOf("%") !== -1 && parsed.host !== void 0 && !malformedIPLiteral) {
8958
+ let host = isIP ? parsed.host : normalizePercentEncoding(parsed.host, true);
8959
+ if (!isIP) host = normalizePercentEncoding(host.toLowerCase());
8960
+ parsed.host = isIP || options.scheme !== "null" ? reescapeHostDelimiters(host, isIP) : host;
8961
+ }
8881
8962
  if (!schemeHandler || schemeHandler && !schemeHandler.skipNormalize) {
8882
- if (uri.indexOf("%") !== -1) {
8883
- if (parsed.host !== void 0 && !malformedIPLiteral) {
8884
- const host = isIP ? parsed.host : normalizePercentEncoding(parsed.host, true);
8885
- parsed.host = reescapeHostDelimiters(host, isIP);
8886
- }
8887
- }
8888
8963
  if (parsed.path) parsed.path = normalizePathEncoding(parsed.path);
8889
8964
  if (parsed.query) parsed.query = normalizeQueryFragmentEncoding(parsed.query);
8890
8965
  if (parsed.fragment) parsed.fragment = normalizeQueryFragmentEncoding(parsed.fragment);
@@ -46930,17 +47005,22 @@ async function generateRoutes(cwd, projectInfo) {
46930
47005
  * lists and deletes media, every request checked against the signed-in
46931
47006
  * caller's media permissions (`requireAuth: true` in the template);
46932
47007
  * - the public media route, `api/media/...`, which serves reads only;
47008
+ * - the uploads route, `uploads/...`, which serves files stored on local disk
47009
+ * that `next start` has no static file for, those uploaded since it started;
46933
47010
  * - the health check.
46934
47011
  *
46935
47012
  * `segment` is the URL each route answers. A handler already answering it
46936
47013
  * means the app has its own route there, which is left alone. Next.js leaves
46937
47014
  * route groups `(name)` and slots `@name` out of the URL wherever they sit,
46938
47015
  * and never routes a private folder `_name`, so the folders that answer a URL
46939
- * are found by that rule rather than by name. `catchAll` marks the optional
47016
+ * are found by that rule rather than by name. `catchAll` marks the
46940
47017
  * catch-alls, which serve everything below their URL too: a child folder
46941
- * holding a handler is weighed by {@link childFinding}.
47018
+ * holding a handler is weighed by {@link childFinding}. The uploads route is
47019
+ * a required catch-all rather than an optional one, and is weighed the same
47020
+ * way: a handler at `/uploads` itself, or any route below it, is the app's
47021
+ * own and leaves it unwritten.
46942
47022
  *
46943
- * `role` says what Nextly's route does there, for a media route the app
47023
+ * `role` says what Nextly's route does there, for a media or uploads route the app
46944
47024
  * already has something in place of; the report then carries the route to
46945
47025
  * add by hand.
46946
47026
  */
@@ -46968,6 +47048,20 @@ const ROUTES = [
46968
47048
  }
46969
47049
  ];
46970
47050
  /**
47051
+ * The uploads route, written by {@link generateUploadsRoute} beside the media
47052
+ * routes. Apart from them because it is a different concern: it serves the
47053
+ * files local storage keeps, where they serve the media library's records.
47054
+ */
47055
+ const UPLOADS_ROUTE = {
47056
+ path: "uploads/[...path]/route.ts",
47057
+ segment: "uploads",
47058
+ catchAll: true,
47059
+ importsConfig: true,
47060
+ role: (file) => `Nextly's uploads route at ${file} serves files stored on local disk at /uploads, which a production server otherwise answers 404 for until it restarts`
47061
+ };
47062
+ /** Every route the existing-app path writes, read from the templates together. */
47063
+ const ALL_ROUTES = [...ROUTES, UPLOADS_ROUTE];
47064
+ /**
46971
47065
  * The import that brings in the Nextly config: the template spells it through
46972
47066
  * the `@nextly-config` alias or a path relative to its own layout, neither of
46973
47067
  * which an existing app is guaranteed to resolve.
@@ -47054,7 +47148,7 @@ var UnreadableFolder = class extends Error {
47054
47148
  */
47055
47149
  async function readMediaRouteTemplates(templatesDir = resolveTemplatePath()) {
47056
47150
  const texts = /* @__PURE__ */ new Map();
47057
- for (const route of ROUTES) {
47151
+ for (const route of ALL_ROUTES) {
47058
47152
  const relative = `base/src/app/${route.path}`;
47059
47153
  let text;
47060
47154
  try {
@@ -47084,7 +47178,20 @@ async function readMediaRouteTemplates(templatesDir = resolveTemplatePath()) {
47084
47178
  * is for such an app.
47085
47179
  */
47086
47180
  async function generateMediaRoutes(cwd, projectInfo, templates) {
47087
- const prepared = ROUTES.map((route) => prepareRoute(cwd, projectInfo, templates, route));
47181
+ return writeRoutes(cwd, projectInfo, templates, ROUTES);
47182
+ }
47183
+ /**
47184
+ * Write the uploads route into an existing app, by the same rules as
47185
+ * {@link generateMediaRoutes}: never where the app already answers
47186
+ * `/uploads`, never through a link, and under `pageExtensions` reported with
47187
+ * its content rather than written.
47188
+ */
47189
+ async function generateUploadsRoute(cwd, projectInfo, templates) {
47190
+ return writeRoutes(cwd, projectInfo, templates, [UPLOADS_ROUTE]);
47191
+ }
47192
+ /** Write each of `routes` where nothing answers its URL, reporting the rest. */
47193
+ async function writeRoutes(cwd, projectInfo, templates, routes) {
47194
+ const prepared = routes.map((route) => prepareRoute(cwd, projectInfo, templates, route));
47088
47195
  const pages = await appPageExtensions(cwd);
47089
47196
  if (pages.extensions !== "absent") {
47090
47197
  const { configName, extensions } = pages;
@@ -47888,6 +47995,7 @@ async function generateIntoExistingApp(cwd, projectType, projectInfo, database,
47888
47995
  await generateRoutes(cwd, projectInfo),
47889
47996
  await generateAdminPage(cwd, projectInfo),
47890
47997
  await generateMediaRoutes(cwd, projectInfo, templates),
47998
+ await generateUploadsRoute(cwd, projectInfo, templates),
47891
47999
  await generateInstrumentation(cwd, projectInfo),
47892
48000
  await generateTypesDirectory(cwd, projectInfo),
47893
48001
  nextConfigFiles(await patchNextConfig(cwd, database)),
@@ -52625,4 +52733,4 @@ Object.defineProperty(exports, "validateTemplateName", {
52625
52733
  }
52626
52734
  });
52627
52735
 
52628
- //# sourceMappingURL=create-nextly-BbKGDrEC.cjs.map
52736
+ //# sourceMappingURL=create-nextly-BGu1tXYs.cjs.map