@sandboxsonny/ace-kit 0.12.0 → 0.12.1

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/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # @sandboxsonny/ace-kit
2
2
 
3
+ ## 0.12.1
4
+
5
+ ### Patch Changes
6
+
7
+ - ea4efe1: Fix the addresses in `sitemap.xml` and `robots.txt` on a site behind a proxy. They were built from the address the server was reached at, which behind a proxy such as Railway is the server's own internal address (`http://localhost:8080`). They now use the site's domain in the CMS (`ACE_SITE_DOMAIN`) over https, and fall back to the request's address only for a site on `localhost` or a `.test` domain. Also adds `client.siteDomain`.
8
+
3
9
  ## 0.12.0
4
10
 
5
11
  ### Minor Changes
package/dist/astro.d.ts CHANGED
@@ -147,6 +147,7 @@ type AcePage<Values = Record<string, unknown>> =
147
147
 
148
148
  /** The client for this site, made from the integration's settings. Most pages only need the functions below. */
149
149
  declare const ace: {
150
+ siteDomain: string;
150
151
  getEntry<Handle extends AceContentTypeHandle>(contentTypeHandle: Handle, handle: string, options?: {
151
152
  previewToken?: string | null;
152
153
  }): Promise<AceEntry<AceValuesOf<Handle>> | null>;
@@ -211,7 +212,7 @@ declare function getPage<Values = Record<string, unknown>>(astro: {
211
212
  * import { getSitemapResponse } from "@sandboxsonny/ace-kit/astro";
212
213
  * export const GET = ({ url }) => getSitemapResponse({ url });
213
214
  *
214
- * The addresses use https unless the site is on localhost; pass `{ origin: "https://example.com" }` to choose.
215
+ * The addresses are the site's domain (`ACE_SITE_DOMAIN`) over https, or the address of the request for a site on localhost; pass `{ origin: "https://example.com" }` to choose.
215
216
  */
216
217
  declare const getSitemapResponse: (astro: {
217
218
  url: URL;
package/dist/astro.js CHANGED
@@ -1,4 +1,4 @@
1
- import { createAceClient, loadMenuLinks, loadPage, sitemapResponse, robotsResponse } from './chunk-AJLQFATM.js';
1
+ import { createAceClient, loadMenuLinks, loadPage, sitemapResponse, robotsResponse } from './chunk-RW4CVLES.js';
2
2
  import './chunk-M5WR5TCR.js';
3
3
  import './chunk-YLO6IAXF.js';
4
4
  import { ACE_SITE_DOMAIN, ACE_API_URL } from 'astro:env/server';
@@ -22,6 +22,6 @@ async function getPage(astro) {
22
22
  return page;
23
23
  }
24
24
  var getSitemapResponse = (astro, options = {}) => sitemapResponse(ace, astro.url, options);
25
- var getRobotsResponse = (astro, options = {}) => robotsResponse(astro.url, options);
25
+ var getRobotsResponse = (astro, options = {}) => robotsResponse(astro.url, options, ace.siteDomain);
26
26
 
27
27
  export { ace, applyPage, getEntries, getEntry, getMenu, getMenuLinks, getPage, getRobotsResponse, getSite, getSitemapResponse };
@@ -67,6 +67,8 @@ function createAceClient({
67
67
  return value;
68
68
  }
69
69
  return {
70
+ /** The domain of the site this client reads, as the CMS knows it. */
71
+ siteDomain,
70
72
  /**
71
73
  * One live entry of a content type, by its handle; null if the site has no such entry. With a preview token the
72
74
  * entry the token was made for comes back with its draft applied (never cached); a token that has run out throws
@@ -175,9 +177,11 @@ async function notFoundOrRedirect(client, url, previewToken, headers) {
175
177
 
176
178
  // src/helpers/sitemap.ts
177
179
  var escapeXml = (text) => text.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&apos;");
178
- function publicOrigin(url) {
179
- const local = url.hostname === "localhost" || url.hostname.endsWith(".localhost") || /^[\d.]+$|:/.test(url.hostname);
180
- return local ? url.origin : `https://${url.host}`;
180
+ var isLocalHost = (host) => host === "localhost" || /\.(localhost|test|local)$/.test(host) || /^[\d.]+$|:/.test(host);
181
+ function publicOrigin(url, siteDomain) {
182
+ const domain = siteDomain?.trim().toLowerCase();
183
+ if (domain && !isLocalHost(domain)) return `https://${domain}`;
184
+ return isLocalHost(url.hostname) ? url.origin : `https://${url.host}`;
181
185
  }
182
186
  function sitemapXml(entries, origin) {
183
187
  const base = origin.replace(/\/+$/, "");
@@ -204,7 +208,7 @@ Sitemap: ${origin.replace(/\/+$/, "")}/sitemap.xml
204
208
  async function sitemapResponse(client, url, options = {}) {
205
209
  try {
206
210
  const entries = await client.getSitemap();
207
- return new Response(sitemapXml(entries, options.origin ?? publicOrigin(url)), {
211
+ return new Response(sitemapXml(entries, options.origin ?? publicOrigin(url, client.siteDomain)), {
208
212
  headers: { "Content-Type": "application/xml; charset=utf-8", "Cache-Control": "public, max-age=300" }
209
213
  });
210
214
  } catch (error) {
@@ -216,10 +220,13 @@ async function sitemapResponse(client, url, options = {}) {
216
220
  });
217
221
  }
218
222
  }
219
- function robotsResponse(url, options = {}) {
220
- return new Response(robotsTxt({ origin: options.origin ?? publicOrigin(url), disallowAll: options.disallowAll }), {
221
- headers: { "Content-Type": "text/plain; charset=utf-8", "Cache-Control": "public, max-age=3600" }
222
- });
223
+ function robotsResponse(url, options = {}, siteDomain) {
224
+ return new Response(
225
+ robotsTxt({ origin: options.origin ?? publicOrigin(url, siteDomain), disallowAll: options.disallowAll }),
226
+ {
227
+ headers: { "Content-Type": "text/plain; charset=utf-8", "Cache-Control": "public, max-age=3600" }
228
+ }
229
+ );
223
230
  }
224
231
 
225
232
  export { AcePreviewExpiredError, AceUnavailableError, createAceClient, isCurrentPage, linksFromMenu, loadMenuLinks, loadPage, publicOrigin, robotsResponse, robotsTxt, sitemapResponse, sitemapXml };
package/dist/cli.js CHANGED
@@ -9,8 +9,8 @@ if (major < 22 || major === 22 && minor < 12) {
9
9
  process.exit(1);
10
10
  }
11
11
  try {
12
- const { createRealEnvironment } = await import("./environment-4FBNWIHO.js");
13
- const { runCli } = await import("./main-4QMQF3L3.js");
12
+ const { createRealEnvironment } = await import("./environment-CXO6CVNR.js");
13
+ const { runCli } = await import("./main-4TEJQB6N.js");
14
14
  const environment = await createRealEnvironment();
15
15
  process.exit(await runCli(process.argv.slice(2), environment));
16
16
  } catch (error) {
@@ -145,7 +145,7 @@ function createLastApiUrl(path) {
145
145
  }
146
146
 
147
147
  // src/cli/version.ts
148
- var aceKitVersion = true ? "0.12.0" : "development";
148
+ var aceKitVersion = true ? "0.12.1" : "development";
149
149
 
150
150
  // src/cli/environment.ts
151
151
  var runCommand = (command, commandArguments, input) => new Promise((resolve, reject) => {
package/dist/index.d.ts CHANGED
@@ -147,6 +147,8 @@ type AceSitemapEntry = {
147
147
  * is sent too, for an API that predates the first (some platforms' proxies rewrite X-Forwarded-Host on the way in).
148
148
  */
149
149
  declare function createAceClient({ apiUrl, siteDomain, cacheSeconds, fetchImplementation, now, }: AceClientOptions): {
150
+ /** The domain of the site this client reads, as the CMS knows it. */
151
+ siteDomain: string;
150
152
  /**
151
153
  * One live entry of a content type, by its handle; null if the site has no such entry. With a preview token the
152
154
  * entry the token was made for comes back with its draft applied (never cached); a token that has run out throws
@@ -562,11 +564,12 @@ type AceSeoProperties = {
562
564
  declare function seoProperties(options: AceSeoOptions): AceSeoProperties;
563
565
 
564
566
  /**
565
- * The address a visitor reached the site at, for the full addresses in a sitemap. A site on a real domain is served
566
- * over https, but behind a proxy the server often sees plain http, so anything that isn't `localhost` or an IP address
567
- * is given https. Pass `origin` to the response helpers to choose it yourself.
567
+ * The address the site's pages are at, for the full addresses in a sitemap. It is the site's domain in the CMS
568
+ * (`ACE_SITE_DOMAIN`) over https, because behind a proxy the server only sees its own internal address
569
+ * (`localhost:8080` on Railway), so the request can't say. For a site on `localhost` (or a `.test` domain), which
570
+ * has no public address, it is the address the request came to. Pass `origin` to the response helpers to choose it.
568
571
  */
569
- declare function publicOrigin(url: URL): string;
572
+ declare function publicOrigin(url: URL, siteDomain?: string): string;
570
573
  /** The sitemap file for a site: one `<url>` per page, with when it last changed. `origin` is e.g. `https://example.com`. */
571
574
  declare function sitemapXml(entries: AceSitemapEntry[], origin: string): string;
572
575
  type RobotsOptions = {
@@ -588,7 +591,7 @@ declare function sitemapResponse(client: AceClient, url: URL, options?: {
588
591
  origin?: string;
589
592
  }): Promise<Response>;
590
593
  /** The response for `/robots.txt`. */
591
- declare function robotsResponse(url: URL, options?: RobotsOptions): Response;
594
+ declare function robotsResponse(url: URL, options?: RobotsOptions, siteDomain?: string): Response;
592
595
 
593
596
  /**
594
597
  * A text area field's text as HTML. With `multiline` (the default) blank lines start new paragraphs (`<p>`) and a
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  export { pageNotices } from './chunk-XPZY5R5A.js';
2
2
  export { headingLevel, imageAttributes, isInternalPath, linkAddress, linkAttributes, listStart, renderRichText, renderTextArea, richTextImageSizes } from './chunk-FVR55GIU.js';
3
3
  export { listenForPreviewRefresh, refreshPageContent } from './chunk-YN7LJWGI.js';
4
- export { AcePreviewExpiredError, AceUnavailableError, createAceClient, isCurrentPage, linksFromMenu, loadMenuLinks, loadPage, publicOrigin, robotsResponse, robotsTxt, sitemapResponse, sitemapXml } from './chunk-AJLQFATM.js';
4
+ export { AcePreviewExpiredError, AceUnavailableError, createAceClient, isCurrentPage, linksFromMenu, loadMenuLinks, loadPage, publicOrigin, robotsResponse, robotsTxt, sitemapResponse, sitemapXml } from './chunk-RW4CVLES.js';
5
5
  export { addressFromPath, homeAddress, isHomeAddress, pathOfAddress, visitablePath } from './chunk-M5WR5TCR.js';
6
6
  export { addFramingPolicy, framingPolicy, isRefreshRequest, originOf, previewHeaders, previewParameter, previewTokenFrom, refreshMessageType, swapPageContent } from './chunk-YLO6IAXF.js';
7
7
 
@@ -1345,6 +1345,8 @@ function createAceClient({
1345
1345
  return value;
1346
1346
  }
1347
1347
  return {
1348
+ /** The domain of the site this client reads, as the CMS knows it. */
1349
+ siteDomain,
1348
1350
  /**
1349
1351
  * One live entry of a content type, by its handle; null if the site has no such entry. With a preview token the
1350
1352
  * entry the token was made for comes back with its draft applied (never cached); a token that has run out throws
@@ -150,6 +150,8 @@ type AceSitemapEntry = {
150
150
  * is sent too, for an API that predates the first (some platforms' proxies rewrite X-Forwarded-Host on the way in).
151
151
  */
152
152
  declare function createAceClient({ apiUrl, siteDomain, cacheSeconds, fetchImplementation, now, }: AceClientOptions): {
153
+ /** The domain of the site this client reads, as the CMS knows it. */
154
+ siteDomain: string;
153
155
  /**
154
156
  * One live entry of a content type, by its handle; null if the site has no such entry. With a preview token the
155
157
  * entry the token was made for comes back with its draft applied (never cached); a token that has run out throws
@@ -252,7 +254,7 @@ declare function createPageLoader<Values = Record<string, unknown>>(): ({ reques
252
254
  *
253
255
  * export { sitemapLoader as loader } from "@sandboxsonny/ace-kit/react-router/server";
254
256
  *
255
- * It uses https unless the site is on localhost; for another address use `createSitemapLoader({ origin })`.
257
+ * It uses the site's domain (`ACE_SITE_DOMAIN`) over https, or the address of the request for a site on localhost; for another address use `createSitemapLoader({ origin })`.
256
258
  */
257
259
  declare const createSitemapLoader: (options?: {
258
260
  origin?: string;
@@ -1,4 +1,4 @@
1
- import { createAceClient, loadMenuLinks, loadPage, sitemapResponse, robotsResponse } from './chunk-AJLQFATM.js';
1
+ import { createAceClient, loadMenuLinks, loadPage, sitemapResponse, robotsResponse } from './chunk-RW4CVLES.js';
2
2
  import './chunk-M5WR5TCR.js';
3
3
  import { hostedAdminOrigin, hostedApiUrl } from './chunk-N5DIMG3X.js';
4
4
  import { previewTokenFrom, addFramingPolicy } from './chunk-YLO6IAXF.js';
@@ -48,7 +48,7 @@ var createSitemapLoader = (options = {}) => function loader2({ request }) {
48
48
  };
49
49
  var sitemapLoader = createSitemapLoader();
50
50
  var createRobotsLoader = (options = {}) => function loader2({ request }) {
51
- return robotsResponse(new URL(request.url), options);
51
+ return robotsResponse(new URL(request.url), options, getAceClient().siteDomain);
52
52
  };
53
53
  var robotsLoader = createRobotsLoader();
54
54
  var loader = createPageLoader();
package/docs/astro.md CHANGED
@@ -64,7 +64,7 @@ import { getRobotsResponse } from "@sandboxsonny/ace-kit/astro";
64
64
  export const GET = ({ url }) => getRobotsResponse({ url });
65
65
  ```
66
66
 
67
- Addresses in the sitemap use `https` unless the site is on `localhost`; pass `{ origin: "https://www.example.com" }` to either to choose. `getRobotsResponse({ url }, { disallowAll: true })` asks crawlers to stay away, for a site that isn't live yet. Delete any `robots.txt` in `public/`, which would take its place.
67
+ Addresses in the sitemap are your site's domain (`ACE_SITE_DOMAIN`) over `https`, or the address of the request when the site is on `localhost`; pass `{ origin: "https://www.example.com" }` to either to choose. `getRobotsResponse({ url }, { disallowAll: true })` asks crawlers to stay away, for a site that isn't live yet. Delete any `robots.txt` in `public/`, which would take its place.
68
68
 
69
69
  ## Reading content
70
70
 
@@ -116,7 +116,7 @@ export { sitemapLoader as loader } from "@sandboxsonny/ace-kit/react-router/serv
116
116
  export { robotsLoader as loader } from "@sandboxsonny/ace-kit/react-router/server";
117
117
  ```
118
118
 
119
- The sitemap lists the live pages from the CMS (only the content types that have "Entries have their own pages" ticked), with when each last changed. Addresses use `https` unless the site is on `localhost`. For another address, or to keep crawlers away from a site that isn't live yet, use `createSitemapLoader({ origin })` and `createRobotsLoader({ origin, disallowAll })`.
119
+ The sitemap lists the live pages from the CMS (only the content types that have "Entries have their own pages" ticked), with when each last changed. Addresses are your site's domain (`ACE_SITE_DOMAIN`) over `https`, or the address of the request when the site is on `localhost`. For another address, or to keep crawlers away from a site that isn't live yet, use `createSitemapLoader({ origin })` and `createRobotsLoader({ origin, disallowAll })`.
120
120
 
121
121
  ## Reading content in your own loaders
122
122
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sandboxsonny/ace-kit",
3
- "version": "0.12.0",
3
+ "version": "0.12.1",
4
4
  "description": "Everything a website needs to use CMS Ace: a typed client, addressing, images, menus, rich text, live preview, and Astro and React adapters.",
5
5
  "keywords": [
6
6
  "cms",