@407dev/cms-astro 1.0.2 → 1.1.0

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 CHANGED
@@ -66,4 +66,5 @@
66
66
  - When mutating the DOM during in-place toolbar saves, MutationObservers are paused to avoid triggering re-entrant rescan loops.
67
67
  - Preview bridge and dev status editor origins are configured via `CMS_EDITOR_ORIGINS` (comma-separated) or explicit `editorOrigins` integration options; defaults to allowing both `https://web.localhost` and `http://localhost:5173`.
68
68
  - The injected preview bridge automatically suppresses the Astro dev toolbar (`astro-dev-toolbar { display: none !important; }`) when loaded inside an `<iframe>` (editor preview).
69
+ - Rich-text image nodes render as a plain `<img loading="lazy">` by default, so an above-the-fold image needs a custom component. A `components.image` override receives `{ src, alt, title?, width?, height?, asset? }`: `src` is always a URL string, and `asset` is the `CmsAsset` that the stored UUID resolved to. Assets that aren't images are skipped. Pass `asset ?? src` to `<CmsImage>` to get focal point and srcset. See the `src` contract in [docs/api/content-api.md](../../docs/api/content-api.md).
69
70
  - Comment mode cursor and click interception takes precedence over visual edit mode and link navigation whenever `data-cms-comment-mode` is set on `document.documentElement`.
@@ -10,5 +10,5 @@ var DEFAULT_DEV_API_URL = "http://127.0.0.1:8787";
10
10
  var DEFAULT_DEV_CONTENT_URL = "http://127.0.0.1:8788";
11
11
 
12
12
  export { DEFAULT_DEV_API_URL, DEFAULT_DEV_CONTENT_URL, getJwtSecret };
13
- //# sourceMappingURL=chunk-B4YYLS7Y.js.map
14
- //# sourceMappingURL=chunk-B4YYLS7Y.js.map
13
+ //# sourceMappingURL=chunk-4KOHZWCL.js.map
14
+ //# sourceMappingURL=chunk-4KOHZWCL.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../config/src/index.ts"],"names":[],"mappings":";AAuBO,SAAS,aAAa,GAAA,EAA4B;AACvD,EAAA,MAAM,SAAS,GAAA,EAAK,UAAA,IAAe,OAAO,OAAA,KAAY,WAAA,IAAe,QAAQ,GAAA,EAAK,UAAA;AAClF,EAAA,IAAI,CAAC,MAAA,EAAQ;AACX,IAAA,MAAM,IAAI,MAAM,wBAAwB,CAAA;AAAA,EAC1C;AACA,EAAA,OAAO,MAAA;AACT;AA+BO,IAAM,mBAAA,GAAsB;AAC5B,IAAM,uBAAA,GAA0B","file":"chunk-4KOHZWCL.js","sourcesContent":["export const configVersion = '1.0.0';\n\nexport * from './collector.js';\nexport * from './preview-token.js';\n\nexport interface JwtSecretEnv {\n JWT_SECRET?: string;\n}\n\nexport interface PreviewTokenSecretEnv {\n PREVIEW_TOKEN_SECRET?: string;\n}\n\n// Local dev JWT secret used consistently across dev environments (.dev.vars, demo-site)\nexport const DEFAULT_DEV_JWT_SECRET =\n 'f44b0b9bf64e28c3b12e3c7ec5cec7b79f139d50f43655138caafe6b890565ce';\n\nexport const DEFAULT_DEV_ORCHESTRATOR_SECRET =\n 'dev-orchestrator-secret-f44b0b9bf64e28c3b12e3c7ec5cec7b79';\n\nexport const DEFAULT_DEV_ANALYTICS_QUERY_INTERNAL_SECRET =\n 'dev-analytics-query-internal-secret-b12e3c7ec5cec7b79f139d5';\n\nexport function getJwtSecret(env?: JwtSecretEnv): string {\n const secret = env?.JWT_SECRET || (typeof process !== 'undefined' && process.env?.JWT_SECRET);\n if (!secret) {\n throw new Error('JWT_SECRET is required');\n }\n return secret;\n}\n\nexport function getPreviewTokenSecret(env?: PreviewTokenSecretEnv): string {\n const secret =\n env?.PREVIEW_TOKEN_SECRET ||\n (typeof process !== 'undefined' && process.env?.PREVIEW_TOKEN_SECRET);\n if (!secret) {\n throw new Error('PREVIEW_TOKEN_SECRET is required');\n }\n return secret;\n}\n\n// Leading slash, no trailing slash (except root '/'), lowercase, duplicate slashes collapsed\nexport function normalizePath(rawPath?: string): string {\n if (!rawPath || rawPath.trim() === '') {\n return '/';\n }\n let p = rawPath.trim().toLowerCase();\n if (!p.startsWith('/')) {\n p = `/${p}`;\n }\n p = p.replace(/\\/{2,}/g, '/');\n if (p.length > 1 && p.endsWith('/')) {\n p = p.replace(/\\/+$/, '');\n }\n return p;\n}\n\n// Local Supabase URL fallback\nexport const DEFAULT_SUPABASE_URL = 'http://127.0.0.1:54321';\n\nexport const DEFAULT_DEV_API_URL = 'http://127.0.0.1:8787';\nexport const DEFAULT_DEV_CONTENT_URL = 'http://127.0.0.1:8788';\nexport const DEFAULT_DEV_ANALYTICS_QUERY_URL = 'http://127.0.0.1:8791';\nexport const DEFAULT_DEV_WEB_URL = 'https://web.localhost';\nexport const DEFAULT_DEV_FALLBACK_WEB_URL = 'http://localhost:5173';\nexport const DEFAULT_DEV_DEMO_SITE_URL = 'https://demo.localhost';\nexport const DEFAULT_DEV_FALLBACK_DEMO_SITE_URL = 'http://localhost:4321';\n\n// Canonical local development origins allowlist across both portless names and raw loopback ports\nexport const LOCAL_DEV_ORIGINS: string[] = [\n 'http://localhost:4321',\n 'http://localhost:3000',\n 'http://localhost:5173',\n 'http://localhost:8787',\n 'http://localhost:8788',\n 'http://localhost:8789',\n 'http://localhost:8790',\n 'http://localhost:8791',\n 'http://127.0.0.1:4321',\n 'http://127.0.0.1:3000',\n 'http://127.0.0.1:5173',\n 'http://127.0.0.1:8787',\n 'http://127.0.0.1:8788',\n 'http://127.0.0.1:8789',\n 'http://127.0.0.1:8790',\n 'http://127.0.0.1:8791',\n 'https://web.localhost',\n 'https://api.localhost',\n 'https://content.localhost',\n 'https://builds.localhost',\n 'https://analytics.localhost',\n 'https://analytics-query.localhost',\n 'https://demo.localhost',\n];\n\n// Local Supabase demo anon key, used only when SUPABASE_ANON_KEY is unset\nexport const DEFAULT_SUPABASE_ANON_KEY =\n 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZS1kZW1vIiwicm9sZSI6ImFub24iLCJleHAiOjE5ODM4MTI5OTZ9.CRXP1A7WOeoJeXxjNni43kdQwgnWNReilDMblYTn_I0';\n\nexport const DEFAULT_SUPABASE_SERVICE_ROLE_KEY =\n 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZS1kZW1vIiwicm9sZSI6InNlcnZpY2Vfcm9sZSIsImV4cCI6MTk4MzgxMjk5Nn0.EGIM96RAZx35lJzdJsyH-qQwv8Hdp7fsn3W0YpN81IU';\n\nexport function normalizeOrigin(raw?: string | null): string | null {\n if (!raw || typeof raw !== 'string') return null;\n const trimmed = raw.trim();\n if (!trimmed) return null;\n\n try {\n const withScheme = /^[a-zA-Z][a-zA-Z0-9+.-]*:\\/\\//.test(trimmed)\n ? trimmed\n : `https://${trimmed}`;\n const url = new URL(withScheme);\n if (!url.protocol || !url.host) return null;\n return `${url.protocol}//${url.host}`.toLowerCase();\n } catch {\n return null;\n }\n}\n\nconst LOOPBACK_HOSTS = new Set(['localhost', '127.0.0.1']);\n\n/** `normalizeOrigin`, restricted to origins a public site can serve from: https, or http on loopback. */\nexport function normalizeSiteOrigin(raw?: string | null): string | null {\n const origin = normalizeOrigin(raw);\n if (!origin) return null;\n const url = new URL(origin);\n const isLoopback = LOOPBACK_HOSTS.has(url.hostname);\n if (url.protocol !== 'https:' && !(url.protocol === 'http:' && isLoopback)) return null;\n if (!isLoopback && !url.hostname.includes('.')) return null;\n return origin;\n}\n\nexport function deriveSiteOrigins(\n domain?: string | null,\n customDomain?: string | null,\n opts?: { includeLocalhost?: boolean },\n): string[] {\n const origins = new Set<string>();\n\n const normDomain = normalizeOrigin(domain);\n if (normDomain) origins.add(normDomain);\n\n const normCustom = normalizeOrigin(customDomain);\n if (normCustom) origins.add(normCustom);\n\n if (opts?.includeLocalhost) {\n for (const origin of LOCAL_DEV_ORIGINS) {\n origins.add(origin);\n }\n }\n\n return Array.from(origins);\n}\n\nexport const PAGES_PROJECT_NAME_REGEX = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;\n// 58 = Cloudflare's project-name cap; reserve 8 for the `-preview` twin name.\nexport const PAGES_PROJECT_NAME_MAX = 50;\n\nexport function validatePagesProjectName(name: string): string | null {\n if (!name || typeof name !== 'string' || name.trim() === '') {\n return 'Project name cannot be empty';\n }\n if (name.length > PAGES_PROJECT_NAME_MAX) {\n return `Project name must be ${PAGES_PROJECT_NAME_MAX} characters or fewer`;\n }\n if (!PAGES_PROJECT_NAME_REGEX.test(name)) {\n return 'Project name can only contain lowercase letters, numbers, and hyphens, and cannot start or end with a hyphen';\n }\n return null;\n}\n\n// Cloudflare accounts that can host site Pages projects. Hardcoded on purpose: adding one means a\n// new entry here, its two worker secrets, and widening the `sites_cf_account_check` constraint.\n// Only site hosting (Pages projects, their env vars, deployments) is per-account; Stream, R2,\n// analytics and metering stay on the default account.\nexport const CF_ACCOUNTS = [\n {\n key: 'david',\n label: 'david@407.dev',\n accountIdVar: 'CF_ACCOUNT_ID',\n tokenVar: 'CF_API_TOKEN',\n },\n {\n key: 'lucas',\n label: 'lucas@407.dev',\n accountIdVar: 'CF_ACCOUNT_ID_LUCAS',\n tokenVar: 'CF_API_TOKEN_LUCAS',\n },\n] as const;\n\nexport type CfAccountKey = (typeof CF_ACCOUNTS)[number]['key'];\n\nexport const DEFAULT_CF_ACCOUNT: CfAccountKey = 'david';\n\nexport interface CfCredentials {\n accountId: string;\n token: string;\n}\n\nexport function isCfAccountKey(value: unknown): value is CfAccountKey {\n return CF_ACCOUNTS.some((a) => a.key === value);\n}\n\n/**\n * Credentials for a site's Cloudflare account, or null when that account's secrets are unset.\n * A null/undefined key means the default account (sites predating `sites.cf_account`).\n */\nexport function resolveCfCredentials(env: object, key?: string | null): CfCredentials | null {\n const account = CF_ACCOUNTS.find((a) => a.key === (key ?? DEFAULT_CF_ACCOUNT));\n if (!account) return null;\n const vars = env as Record<string, unknown>;\n const accountId = vars[account.accountIdVar];\n const token = vars[account.tokenVar];\n if (typeof accountId !== 'string' || !accountId || typeof token !== 'string' || !token) {\n return null;\n }\n return { accountId, token };\n}\n"]}
@@ -1,11 +1,11 @@
1
- import { DEFAULT_DEV_CONTENT_URL } from './chunk-B4YYLS7Y.js';
1
+ import { DEFAULT_DEV_CONTENT_URL } from './chunk-4KOHZWCL.js';
2
2
  import { isDraftMode, setActiveDraftBundle, runWithDraftBundle } from './chunk-DMLOBKYE.js';
3
3
  import { chromeTokens } from './chunk-AIUAT7FF.js';
4
4
  import { resolveEditorOrigins } from './chunk-XJPVYMZM.js';
5
5
 
6
6
  // package.json
7
7
  var package_default = {
8
- version: "1.0.2"};
8
+ version: "1.1.0"};
9
9
 
10
10
  // src/version.ts
11
11
  var CMS_ASTRO_VERSION = package_default.version;
@@ -1053,5 +1053,5 @@ function createPreviewMiddleware(options = {}) {
1053
1053
  }
1054
1054
 
1055
1055
  export { buildBridgeScript, createCmsClient, createPreviewMiddleware, getClient, initCmsClient, setClient };
1056
- //# sourceMappingURL=chunk-ZAAWLJPU.js.map
1057
- //# sourceMappingURL=chunk-ZAAWLJPU.js.map
1056
+ //# sourceMappingURL=chunk-4PBDIQNL.js.map
1057
+ //# sourceMappingURL=chunk-4PBDIQNL.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../package.json","../src/version.ts","../src/client.ts","../src/preview/bridge-script.ts","../src/middleware/preview.ts"],"names":["globalWithCms"],"mappings":";;;;;;AAAA,IAAA,eAAA,GAAA;AAAA,EAEE,OAAA,EAAW,OA6Fb,CAAA;;;AC7FO,IAAM,oBAA4B,eAAA,CAAI,OAAA;;;ACQtC,SAAS,gBAAgB,MAAA,EAAoC;AAClE,EAAA,MAAM,SAAS,MAAA,CAAO,MAAA;AACtB,EAAA,MAAM,UAAA,GAAa,MAAA,CAAO,UAAA,CAAW,OAAA,CAAQ,QAAQ,EAAE,CAAA;AACvD,EAAA,MAAM,OAAA,GAAU,OAAO,KAAA,IAAS,KAAA;AAGhC,EAAA,IAAI,qBAAA,GAA8C,IAAA;AAElD,EAAA,MAAM,MAAA,GAAoB;AAAA,IACxB,MAAA;AAAA,IACA,UAAA;AAAA,IACA,eAAe,MAAA,CAAO,aAAA;AAAA,IAEtB,MAAM,UAAU,OAAA,EAAoD;AAClE,MAAA,MAAM,OAAA,GAAU,OAAA,CAAQ,OAAA,EAAS,YAAY,CAAA;AAE7C,MAAA,IAAI,CAAC,WAAW,qBAAA,EAAuB;AACrC,QAAA,OAAO,qBAAA;AAAA,MACT;AAEA,MAAA,MAAM,GAAA,GAAM,OAAA,GACR,CAAA,EAAG,UAAU,CAAA,OAAA,EAAU,MAAM,CAAA,OAAA,CAAA,GAC7B,CAAA,EAAG,UAAU,CAAA,SAAA,EAAY,MAAM,CAAA,OAAA,CAAA;AAEnC,MAAA,MAAM,OAAA,GAAkC;AAAA,QACtC,WAAA,EAAa,aAAa,iBAAiB,CAAA;AAAA,OAC7C;AACA,MAAA,IAAI,SAAS,YAAA,EAAc;AACzB,QAAA,OAAA,CAAQ,iBAAiB,IAAI,OAAA,CAAQ,YAAA;AAAA,MACvC;AAEA,MAAA,MAAM,GAAA,GAAM,MAAM,OAAA,CAAQ,GAAA,EAAK;AAAA,QAC7B;AAAA,OACD,CAAA;AACD,MAAA,IAAI,CAAC,IAAI,EAAA,EAAI;AACX,QAAA,MAAM,QAAQ,IAAI,KAAA;AAAA,UAChB,2CAA2C,GAAG,CAAA,SAAA,EAAY,IAAI,MAAM,CAAA,GAAA,EAAM,IAAI,UAAU,CAAA;AAAA,SAC1F;AACA,QAAC,KAAA,CAAyC,SAAS,GAAA,CAAI,MAAA;AACvD,QAAA,MAAM,KAAA;AAAA,MACR;AAEA,MAAA,MAAM,MAAA,GAAU,MAAM,GAAA,CAAI,IAAA,EAAK;AAE/B,MAAA,IAAI,CAAC,OAAA,EAAS;AACZ,QAAA,qBAAA,GAAwB,MAAA;AAAA,MAC1B;AAEA,MAAA,OAAO,MAAA;AAAA,IACT,CAAA;AAAA,IAEA,MAAM,UAAU,OAAA,EAA8D;AAC5E,MAAA,MAAM,MAAA,GAAS,MAAM,IAAA,CAAK,SAAA,CAAU,OAAO,CAAA;AAC3C,MAAA,OAAO,MAAA,CAAO,UAAU,EAAC;AAAA,IAC3B,CAAA;AAAA,IAEA,MAAM,QAAA,CAAsB,GAAA,EAAa,OAAA,EAA+C;AACtF,MAAA,MAAM,MAAA,GAAS,MAAM,IAAA,CAAK,SAAA,CAAU,OAAO,CAAA;AAC3C,MAAA,OAAQ,MAAA,CAAO,GAAG,CAAA,IAAW,IAAA;AAAA,IAC/B,CAAA;AAAA,IAEA,MAAM,eAAe,OAAA,EAAmE;AACtF,MAAA,MAAM,MAAA,GAAS,MAAM,IAAA,CAAK,SAAA,CAAU,OAAO,CAAA;AAC3C,MAAA,OAAO,MAAA,CAAO,eAAe,EAAC;AAAA,IAChC,CAAA;AAAA,IAEA,MAAM,UAAA,CACJ,aAAA,EACA,OAAA,EAC2C;AAC3C,MAAA,MAAM,MAAA,GAAS,MAAM,IAAA,CAAK,SAAA,CAAU,OAAO,CAAA;AAC3C,MAAA,OAAO,MAAA,CAAO,OAAA,GAAU,aAAa,CAAA,IAAK,EAAC;AAAA,IAC7C,CAAA;AAAA,IAEA,MAAM,QAAA,CACJ,aAAA,EACA,IAAA,EACA,OAAA,EAC0D;AAC1D,MAAA,MAAM,OAAA,GAAU,MAAM,IAAA,CAAK,UAAA,CAAW,eAAe,OAAO,CAAA;AAC5D,MAAA,OAAO,QAAQ,IAAA,CAAK,CAAC,MAAM,CAAA,CAAE,IAAA,KAAS,IAAI,CAAA,IAAK,IAAA;AAAA,IACjD,CAAA;AAAA,IAEA,MAAM,UAAU,OAAA,EAA8D;AAC5E,MAAA,MAAM,MAAA,GAAS,MAAM,IAAA,CAAK,SAAA,CAAU,OAAO,CAAA;AAC3C,MAAA,OAAO,MAAA,CAAO,UAAU,EAAC;AAAA,IAC3B,CAAA;AAAA,IAEA,MAAM,cAAc,OAAA,EAAoD;AACtE,MAAA,MAAM,MAAA,GAAS,MAAM,IAAA,CAAK,SAAA,CAAU,OAAO,CAAA;AAC3C,MAAA,OAAO;AAAA,QACL,SAAS,MAAA,CAAO,OAAA;AAAA,QAChB,SAAA,EAAW,MAAA,CAAO,SAAA,IAAa,EAAC;AAAA,QAChC,MAAA,EAAQ,MAAA,CAAO,QAAA,EAAU,MAAA,IAAU,EAAC;AAAA,QACpC,WAAA,EAAa,MAAA,CAAO,QAAA,EAAU,WAAA,IAAe,EAAC;AAAA,QAC9C,OAAA,EAAS,MAAA,CAAO,QAAA,EAAU,OAAA,IAAW,EAAC;AAAA,QACtC,cAAA,EAAgB,MAAA,CAAO,QAAA,EAAU,cAAA,IAAkB;AAAA,OACrD;AAAA,IACF,CAAA;AAAA,IAEA,UAAA,GAAmB;AACjB,MAAA,qBAAA,GAAwB,IAAA;AAAA,IAC1B;AAAA,GACF;AAEA,EAAA,OAAO,MAAA;AACT;AAEA,IAAM,aAAA,GAAgB,UAAA;AAItB,IAAI,YAAA,GACD,OAAO,UAAA,KAAe,WAAA,IAAe,cAAc,cAAA,IAAmB,IAAA;AAElE,SAAS,cAAc,OAAA,EAKhB;AACZ,EAAA,IAAI,QAAQ,MAAA,EAAQ;AAClB,IAAA,YAAA,GAAe,OAAA,CAAQ,MAAA;AACvB,IAAA,IAAI,OAAO,eAAe,WAAA,EAAa;AACrC,MAAA,aAAA,CAAc,iBAAiB,OAAA,CAAQ,MAAA;AAAA,IACzC;AACA,IAAA,OAAO,YAAA;AAAA,EACT;AAEA,EAAA,YAAA,GAAe,eAAA,CAAgB;AAAA,IAC7B,MAAA,EAAQ,OAAA,CAAQ,MAAA,IAAU,OAAA,CAAQ,IAAI,WAAA,IAAe,EAAA;AAAA,IACrD,UAAA,EAAY,OAAA,CAAQ,UAAA,IAAc,OAAA,CAAQ,IAAI,eAAA,IAAmB,uBAAA;AAAA,IACjE,aAAA,EAAe,OAAA,CAAQ,aAAA,IAAiB,OAAA,CAAQ,GAAA,CAAI;AAAA,GACrD,CAAA;AACD,EAAA,IAAI,OAAO,eAAe,WAAA,EAAa;AACrC,IAAA,aAAA,CAAc,cAAA,GAAiB,YAAA;AAAA,EACjC;AAEA,EAAA,OAAO,YAAA;AACT;AAEO,SAAS,SAAA,GAA8B;AAC5C,EAAA,OACE,YAAA,IAAiB,OAAO,UAAA,KAAe,WAAA,IAAe,cAAc,cAAA,IAAmB,IAAA;AAE3F;AAEO,SAAS,UAAU,MAAA,EAAgC;AACxD,EAAA,YAAA,GAAe,MAAA;AACf,EAAA,IAAI,OAAO,eAAe,WAAA,EAAa;AACrC,IAAA,aAAA,CAAc,cAAA,GAAiB,MAAA;AAAA,EACjC;AACF;;;AC/JO,IAAM,uBAAA,GAA0B,CAAA;AAMhC,SAAS,iBAAA,CAAkB,OAAA,GAA+B,EAAC,EAAW;AAC3E,EAAA,MAAM,cAAA,GAAiB,oBAAA,CAAqB,OAAA,CAAQ,aAAa,CAAA;AACjE,EAAA,MAAM,kBAAA,GAAqB,IAAA,CAAK,SAAA,CAAU,cAAc,CAAA;AAExD,EAAA,OAAO,CAAA;AAAA;AAAA;AAAA;;AAAA,yBAAA,EAKkB,uBAAuB,CAAA;AAAA,uBAAA,EACzB,kBAAkB,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,4BAAA,EAsEb,aAAa,OAAO,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,4BAAA,EAQpB,aAAa,OAAO,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,4BAAA,EAUpB,aAAa,OAAO,CAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,KAAA,CAAA;AA+qBlD;;;AC/vBO,SAAS,uBAAA,CAAwB,OAAA,GAAoC,EAAC,EAAG;AAC9E,EAAA,IAAI,SAAS,OAAA,CAAQ,MAAA;AAErB,EAAA,OAAO,OACL,SACA,IAAA,KACsB;AACtB,IAAA,MAAMA,cAAAA,GAAgB,UAAA;AAKtB,IAAA,IACG,OAAO,eAAe,WAAA,IAAeA,cAAAA,CAAc,wBACpD,WAAA,EAAY,IACZ,OAAA,CAAQ,MAAA,EAAQ,cAAA,EAChB;AACA,MAAA,OAAO,IAAA,EAAK;AAAA,IACd;AAEA,IAAA,MAAM,SAAS,OAAA,CAAQ,GAAA;AACvB,IAAA,MAAM,GAAA,GACJ,UAAU,OAAO,MAAA,CAAO,SAAS,QAAA,GAC7B,IAAI,GAAA,CAAI,MAAA,CAAO,IAAI,CAAA,GACnB,UAAU,OAAQ,MAAA,CAA4C,QAAA,KAAa,QAAA,GACzE,MAAA,GACA,IAAI,IAAI,OAAA,CAAQ,OAAA,EAAS,GAAA,IAAO,GAAA,EAAK,kBAAkB,CAAA;AAC/D,IAAA,MAAM,QAAA,GAAW,IAAI,QAAA,IAAY,GAAA;AACjC,IAAA,MAAM,cAAA,GAAiB,QAAA,KAAa,WAAA,IAAe,QAAA,CAAS,WAAW,YAAY,CAAA;AAEnF,IAAA,MAAM,YAAA,GAAA,CACH,MAAA,EAAQ,YAAA,EAAc,GAAA,GAAM,MAAA,CAAO,YAAA,CAAa,GAAA,CAAI,eAAe,CAAA,GAAI,IAAA,MACvE,GAAA,EAAK,YAAA,EAAc,GAAA,GAAM,GAAA,CAAI,YAAA,CAAa,GAAA,CAAI,eAAe,CAAA,GAAI,IAAA,CAAA,KACjE,OAAA,CAAQ,OAAA,EAAS,OAAA,EAAS,GAAA,GAAM,OAAA,CAAQ,OAAA,CAAQ,OAAA,CAAQ,GAAA,CAAI,iBAAiB,CAAA,GAAI,IAAA,CAAA;AAEpF,IAAA,IAAI,CAAC,cAAA,IAAkB,CAAC,YAAA,EAAc;AACpC,MAAA,OAAO,IAAA,EAAK;AAAA,IACd;AAEA,IAAA,IAAI,CAAC,MAAA,EAAQ;AACX,MAAA,MAAA,GAAS,WAAU,IAAK,MAAA;AAAA,IAC1B;AAEA,IAAA,IAAI,CAAC,MAAA,EAAQ;AACX,MAAA,MAAM,UAAW,MAAA,CAAA,IAAA,CAAwE,GAAA;AACzF,MAAA,MAAM,MAAA,GACJ,OAAA,CAAQ,MAAA,IACP,OAAO,OAAA,KAAY,WAAA,IAAe,OAAA,CAAQ,GAAA,EAAK,WAAA,IAC/C,OAAO,MAAA,CAAA,IAAA,KAAgB,WAAA,IAAe,SAAS,WAAA,IAChD,EAAA;AACF,MAAA,MAAM,UAAA,GACJ,OAAA,CAAQ,UAAA,IACP,OAAO,OAAA,KAAY,WAAA,IAAe,OAAA,CAAQ,GAAA,EAAK,eAAA,IAC/C,OAAO,MAAA,CAAA,IAAA,KAAgB,WAAA,IAAe,SAAS,eAAA,IAChD,EAAA;AACF,MAAA,IAAI,UAAU,UAAA,EAAY;AACxB,QAAA,MAAA,GAAS,eAAA,CAAgB;AAAA,UACvB,MAAA;AAAA,UACA;AAAA,SACD,CAAA;AAAA,MACH;AAAA,IACF;AAEA,IAAA,IAAI,CAAC,YAAA,EAAc;AACjB,MAAA,OAAO,IAAI,SAAS,0BAAA,EAA4B;AAAA,QAC9C,MAAA,EAAQ,GAAA;AAAA,QACR,OAAA,EAAS;AAAA,UACP,eAAA,EAAiB,mBAAA;AAAA,UACjB,cAAA,EAAgB;AAAA;AAClB,OACD,CAAA;AAAA,IACH;AAEA,IAAA,IAAI,CAAC,MAAA,EAAQ;AACX,MAAA,OAAO,IAAI,SAAS,yCAAA,EAA2C;AAAA,QAC7D,MAAA,EAAQ,GAAA;AAAA,QACR,OAAA,EAAS;AAAA,UACP,eAAA,EAAiB,mBAAA;AAAA,UACjB,cAAA,EAAgB;AAAA;AAClB,OACD,CAAA;AAAA,IACH;AAEA,IAAA,IAAI,WAAA;AACJ,IAAA,IAAI;AACF,MAAA,WAAA,GAAc,MAAM,MAAA,CAAO,SAAA,CAAU,EAAE,cAAc,CAAA;AAAA,IACvD,SAAS,GAAA,EAAK;AACZ,MAAA,MAAM,SAAU,GAAA,EAA6B,MAAA;AAC7C,MAAA,IAAI,MAAA,KAAW,GAAA,IAAO,MAAA,KAAW,GAAA,IAAO,WAAW,GAAA,EAAK;AACtD,QAAA,OAAO,IAAI,SAAS,0CAAA,EAA4C;AAAA,UAC9D,MAAA,EAAQ,GAAA;AAAA,UACR,OAAA,EAAS;AAAA,YACP,eAAA,EAAiB,mBAAA;AAAA,YACjB,cAAA,EAAgB;AAAA;AAClB,SACD,CAAA;AAAA,MACH;AAEA,MAAA,OAAA,CAAQ,MAAM,GAAG,CAAA;AACjB,MAAA,OAAO,IAAI,SAAS,gCAAA,EAAkC;AAAA,QACpD,MAAA,EAAQ,GAAA;AAAA,QACR,OAAA,EAAS;AAAA,UACP,eAAA,EAAiB,mBAAA;AAAA,UACjB,cAAA,EAAgB;AAAA;AAClB,OACD,CAAA;AAAA,IACH;AAGA,IAAA,IAAI,QAAQ,MAAA,EAAQ;AAClB,MAAA,OAAA,CAAQ,OAAO,cAAA,GAAiB,IAAA;AAChC,MAAA,OAAA,CAAQ,OAAO,kBAAA,GAAqB,WAAA;AAAA,IACtC;AAEA,IAAA,IAAI,aAAA;AACJ,IAAA,oBAAA,CAAqB,WAAW,CAAA;AAChC,IAAA,IAAI;AACF,MAAA,aAAA,GAAgB,MAAM,kBAAA,CAAmB,WAAA,EAAa,YAAY;AAChE,QAAA,IAAI,QAAA;AACJ,QAAA,IAAI,cAAA,EAAgB;AAClB,UAAA,MAAM,QAAA,GAAW,QAAA,CAAS,OAAA,CAAQ,aAAA,EAAe,EAAE,CAAA,IAAK,GAAA;AACxD,UAAA,IAAI,OAAO,OAAA,CAAQ,OAAA,KAAY,UAAA,EAAY;AACzC,YAAA,IAAI,OAAO,eAAe,WAAA,EAAa;AACrC,cAAAA,eAAc,oBAAA,GAAuB,IAAA;AAAA,YACvC;AACA,YAAA,IAAI;AACF,cAAA,MAAM,SAAA,GAAY,MAAM,OAAA,CAAQ,OAAA,CAAQ,QAAQ,CAAA;AAChD,cAAA,IAAI,SAAA,EAAW;AACb,gBAAA,QAAA,GAAW,SAAA;AAAA,cACb,CAAA,MAAO;AACL,gBAAA,QAAA,GAAW,MAAM,IAAA,EAAK;AAAA,cACxB;AAAA,YACF,CAAA,SAAE;AACA,cAAA,IAAI,OAAO,eAAe,WAAA,EAAa;AACrC,gBAAAA,eAAc,oBAAA,GAAuB,KAAA;AAAA,cACvC;AAAA,YACF;AAAA,UACF,CAAA,MAAO;AACL,YAAA,QAAA,GAAW,MAAM,IAAA,EAAK;AAAA,UACxB;AAAA,QACF,CAAA,MAAO;AACL,UAAA,QAAA,GAAW,MAAM,IAAA,EAAK;AAAA,QACxB;AAEA,QAAA,MAAM,WAAA,GAAc,UAAU,OAAA,EAAS,GAAA,GAAM,SAAS,OAAA,CAAQ,GAAA,CAAI,cAAc,CAAA,GAAI,EAAA;AACpF,QAAA,MAAM,aAAA,GAAgB,OAAA;AAAA,UACpB,QAAA,CAAS,MAAM,oEAAoE;AAAA,SACrF;AACA,QAAA,MAAM,MAAA,GACH,OAAO,WAAA,KAAgB,QAAA,IAAY,WAAA,CAAY,SAAS,WAAW,CAAA,IACnE,CAAC,WAAA,IAAe,CAAC,aAAA;AAEpB,QAAA,IAAI,MAAA,EAAQ;AACV,UAAA,MAAM,IAAA,GAAO,MAAM,QAAA,CAAS,IAAA,EAAK;AACjC,UAAA,MAAM,eAAe,iBAAA,CAAkB;AAAA,YACrC,eAAe,OAAA,CAAQ;AAAA,WACxB,CAAA;AACD,UAAA,MAAM,SAAA,GAAY,WAAW,YAAY,CAAA,SAAA,CAAA;AACzC,UAAA,MAAM,YAAA,GAAe,IAAA,CAAK,QAAA,CAAS,SAAS,IACxC,IAAA,CAAK,OAAA,CAAQ,SAAA,EAAW,CAAA,EAAG,SAAS,CAAA,OAAA,CAAS,CAAA,GAC7C,CAAA,EAAG,IAAI,GAAG,SAAS,CAAA,CAAA;AAEvB,UAAA,MAAM,UAAA,GAAa,IAAI,OAAA,CAAQ,QAAA,CAAS,OAAO,CAAA;AAC/C,UAAA,IAAI,CAAC,UAAA,CAAW,GAAA,CAAI,cAAc,CAAA,EAAG;AACnC,YAAA,UAAA,CAAW,GAAA,CAAI,gBAAgB,0BAA0B,CAAA;AAAA,UAC3D;AACA,UAAA,UAAA,CAAW,OAAO,gBAAgB,CAAA;AAClC,UAAA,UAAA,CAAW,GAAA,CAAI,iBAAiB,8CAA8C,CAAA;AAC9E,UAAA,UAAA,CAAW,GAAA,CAAI,gBAAgB,mBAAmB,CAAA;AAElD,UAAA,OAAO,IAAI,SAAS,YAAA,EAAc;AAAA,YAChC,QAAQ,QAAA,CAAS,MAAA;AAAA,YACjB,YAAY,QAAA,CAAS,UAAA;AAAA,YACrB,OAAA,EAAS;AAAA,WACV,CAAA;AAAA,QACH;AAEA,QAAA,MAAM,cAAA,GAAiB,IAAI,OAAA,CAAQ,QAAA,CAAS,OAAO,CAAA;AACnD,QAAA,cAAA,CAAe,GAAA,CAAI,iBAAiB,8CAA8C,CAAA;AAClF,QAAA,cAAA,CAAe,GAAA,CAAI,gBAAgB,mBAAmB,CAAA;AACtD,QAAA,OAAO,IAAI,QAAA,CAAS,QAAA,CAAS,IAAA,EAAM;AAAA,UACjC,QAAQ,QAAA,CAAS,MAAA;AAAA,UACjB,YAAY,QAAA,CAAS,UAAA;AAAA,UACrB,OAAA,EAAS;AAAA,SACV,CAAA;AAAA,MACH,CAAC,CAAA;AAAA,IACH,CAAA,SAAE;AACA,MAAA,oBAAA,CAAqB,IAAI,CAAA;AAAA,IAC3B;AAEA,IAAA,OAAO,aAAA;AAAA,EACT,CAAA;AACF","file":"chunk-ZAAWLJPU.js","sourcesContent":["{\n \"name\": \"@407dev/cms-astro\",\n \"version\": \"1.0.2\",\n \"type\": \"module\",\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"git+https://github.com/407dev/cms.git\",\n \"directory\": \"packages/astro\"\n },\n \"main\": \"./dist/index.js\",\n \"types\": \"./dist/index.d.ts\",\n \"exports\": {\n \".\": {\n \"source\": \"./src/index.ts\",\n \"types\": \"./dist/index.d.ts\",\n \"import\": \"./dist/index.js\",\n \"default\": \"./dist/index.js\"\n },\n \"./collections\": {\n \"source\": \"./src/fields/collections.ts\",\n \"types\": \"./dist/fields/collections.d.ts\",\n \"import\": \"./dist/fields/collections.js\"\n },\n \"./image\": {\n \"source\": \"./src/image.ts\",\n \"types\": \"./dist/image.d.ts\",\n \"import\": \"./dist/image.js\",\n \"default\": \"./dist/image.js\"\n },\n \"./CmsImage.astro\": \"./src/CmsImage.astro\",\n \"./CmsVideo.astro\": \"./src/CmsVideo.astro\",\n \"./CmsHead.astro\": \"./src/CmsHead.astro\",\n \"./RichText.astro\": \"./src/RichText.astro\",\n \"./middleware\": {\n \"source\": \"./src/middleware/index.ts\",\n \"types\": \"./dist/middleware/index.d.ts\",\n \"import\": \"./dist/middleware/index.js\",\n \"default\": \"./dist/middleware/index.js\"\n },\n \"./toolbar\": {\n \"source\": \"./src/toolbar/app.ts\",\n \"types\": \"./dist/toolbar/app.d.ts\",\n \"import\": \"./dist/toolbar/app.js\",\n \"default\": \"./dist/toolbar/app.js\"\n },\n \"./dev\": {\n \"source\": \"./src/dev/index.ts\",\n \"types\": \"./dist/dev/index.d.ts\",\n \"import\": \"./dist/dev/index.js\",\n \"default\": \"./dist/dev/index.js\"\n }\n },\n \"publishConfig\": {\n \"access\": \"public\"\n },\n \"files\": [\n \"dist\",\n \"src\"\n ],\n \"scripts\": {\n \"build\": \"tsup\",\n \"dev\": \"tsup --watch\",\n \"lint\": \"biome check src\",\n \"typecheck\": \"tsc --noEmit\",\n \"test\": \"vitest run\"\n },\n \"dependencies\": {\n \"@407dev/blocks\": \"workspace:*\",\n \"@407dev/field-types\": \"workspace:*\",\n \"zod\": \"^4.4.3\"\n },\n \"peerDependencies\": {\n \"@407dev/cli\": \"workspace:*\",\n \"astro\": \"^5.0.0\"\n },\n \"peerDependenciesMeta\": {\n \"@407dev/cli\": {\n \"optional\": true\n },\n \"astro\": {\n \"optional\": true\n }\n },\n \"devDependencies\": {\n \"@407dev/api-client\": \"workspace:*\",\n \"@407dev/cli\": \"workspace:*\",\n \"@407dev/config\": \"workspace:*\",\n \"@407dev/design-tokens\": \"workspace:*\",\n \"astro\": \"^5.3.0\",\n \"expect-type\": \"^0.20.0\",\n \"tsup\": \"^8.4.0\",\n \"typescript\": \"^5.7.3\",\n \"vite\": \"^6.1.0\",\n \"vitest\": \"3.0.7\"\n }\n}\n","import pkg from '../package.json';\n\nexport const CMS_ASTRO_VERSION: string = pkg.version;\n","import { DEFAULT_DEV_CONTENT_URL } from '@407dev/config';\nimport type {\n CmsClient,\n CmsClientConfig,\n CmsSiteConfig,\n ContentBundle,\n GetBundleOptions,\n} from './types';\nimport { CMS_ASTRO_VERSION } from './version.js';\n\nexport function createCmsClient(config: CmsClientConfig): CmsClient {\n const siteId = config.siteId;\n const contentUrl = config.contentUrl.replace(/\\/+$/, '');\n const fetchFn = config.fetch || fetch;\n\n // In-memory cache for published bundle to ensure build determinism\n let cachedPublishedBundle: ContentBundle | null = null;\n\n const client: CmsClient = {\n siteId,\n contentUrl,\n previewSecret: config.previewSecret,\n\n async getBundle(options?: GetBundleOptions): Promise<ContentBundle> {\n const isDraft = Boolean(options?.previewToken);\n\n if (!isDraft && cachedPublishedBundle) {\n return cachedPublishedBundle;\n }\n\n const url = isDraft\n ? `${contentUrl}/draft/${siteId}/bundle`\n : `${contentUrl}/content/${siteId}/bundle`;\n\n const headers: Record<string, string> = {\n 'x-cms-sdk': `cms-astro@${CMS_ASTRO_VERSION}`,\n };\n if (options?.previewToken) {\n headers['x-preview-token'] = options.previewToken;\n }\n\n const res = await fetchFn(url, {\n headers,\n });\n if (!res.ok) {\n const error = new Error(\n `CMS Client: Failed to fetch bundle from ${url} (status ${res.status}): ${res.statusText}`,\n );\n (error as unknown as { status?: number }).status = res.status;\n throw error;\n }\n\n const bundle = (await res.json()) as ContentBundle;\n\n if (!isDraft) {\n cachedPublishedBundle = bundle;\n }\n\n return bundle;\n },\n\n async getFields(options?: GetBundleOptions): Promise<ContentBundle['fields']> {\n const bundle = await this.getBundle(options);\n return bundle.fields || {};\n },\n\n async getField<T = unknown>(key: string, options?: GetBundleOptions): Promise<T | null> {\n const fields = await this.getFields(options);\n return (fields[key] as T) ?? null;\n },\n\n async getCollections(options?: GetBundleOptions): Promise<ContentBundle['collections']> {\n const bundle = await this.getBundle(options);\n return bundle.collections || {};\n },\n\n async getEntries(\n collectionKey: string,\n options?: GetBundleOptions,\n ): Promise<ContentBundle['entries'][string]> {\n const bundle = await this.getBundle(options);\n return bundle.entries?.[collectionKey] || [];\n },\n\n async getEntry(\n collectionKey: string,\n slug: string,\n options?: GetBundleOptions,\n ): Promise<ContentBundle['entries'][string][number] | null> {\n const entries = await this.getEntries(collectionKey, options);\n return entries.find((e) => e.slug === slug) || null;\n },\n\n async getRoutes(options?: GetBundleOptions): Promise<ContentBundle['routes']> {\n const bundle = await this.getBundle(options);\n return bundle.routes || [];\n },\n\n async getSiteConfig(options?: GetBundleOptions): Promise<CmsSiteConfig> {\n const bundle = await this.getBundle(options);\n return {\n site_id: bundle.site_id,\n redirects: bundle.redirects || [],\n robots: bundle.settings?.robots || {},\n default_seo: bundle.settings?.default_seo || {},\n sitemap: bundle.settings?.sitemap || {},\n not_found_path: bundle.settings?.not_found_path || null,\n };\n },\n\n clearCache(): void {\n cachedPublishedBundle = null;\n },\n };\n\n return client;\n}\n\nconst globalWithCms = globalThis as typeof globalThis & {\n __CMS_CLIENT__?: CmsClient | null;\n};\n\nlet globalClient: CmsClient | null =\n (typeof globalThis !== 'undefined' && globalWithCms.__CMS_CLIENT__) || null;\n\nexport function initCmsClient(options: {\n siteId?: string;\n contentUrl?: string;\n previewSecret?: string;\n client?: CmsClient;\n}): CmsClient {\n if (options.client) {\n globalClient = options.client;\n if (typeof globalThis !== 'undefined') {\n globalWithCms.__CMS_CLIENT__ = options.client;\n }\n return globalClient;\n }\n\n globalClient = createCmsClient({\n siteId: options.siteId || process.env.CMS_SITE_ID || '',\n contentUrl: options.contentUrl || process.env.CMS_CONTENT_URL || DEFAULT_DEV_CONTENT_URL,\n previewSecret: options.previewSecret || process.env.CMS_PREVIEW_SECRET,\n });\n if (typeof globalThis !== 'undefined') {\n globalWithCms.__CMS_CLIENT__ = globalClient;\n }\n\n return globalClient;\n}\n\nexport function getClient(): CmsClient | null {\n return (\n globalClient || (typeof globalThis !== 'undefined' && globalWithCms.__CMS_CLIENT__) || null\n );\n}\n\nexport function setClient(client: CmsClient | null): void {\n globalClient = client;\n if (typeof globalThis !== 'undefined') {\n globalWithCms.__CMS_CLIENT__ = client;\n }\n}\n","import { chromeTokens } from '@407dev/design-tokens/tokens';\nimport { resolveEditorOrigins } from './origins';\n\nexport const BRIDGE_PROTOCOL_VERSION = 1;\n\nexport interface BridgeScriptOptions {\n editorOrigins?: string[];\n}\n\nexport function buildBridgeScript(options: BridgeScriptOptions = {}): string {\n const allowedOrigins = resolveEditorOrigins(options.editorOrigins);\n const allowedOriginsJson = JSON.stringify(allowedOrigins);\n\n return `(function() {\n if (typeof window === 'undefined') return;\n if (window.__CMS_BRIDGE_INITIALIZED__) return;\n window.__CMS_BRIDGE_INITIALIZED__ = true;\n\n var PROTOCOL_VERSION = ${BRIDGE_PROTOCOL_VERSION};\n var allowedOrigins = ${allowedOriginsJson};\n var connectedOrigin = null;\n var connectedSource = null;\n var activeKey = null;\n var watchedAnchors = [];\n var rafScheduled = false;\n var isPatchingDom = false;\n var debounceRescanTimer = null;\n\n function normalizeOrigin(raw) {\n if (!raw || typeof raw !== 'string') return null;\n var trimmed = raw.trim();\n if (!trimmed) return null;\n try {\n var withScheme = /^[a-zA-Z][a-zA-Z0-9+.-]*:\\\\/\\\\//.test(trimmed) ? trimmed : 'https://' + trimmed;\n var url = new URL(withScheme);\n if (!url.protocol || !url.host) return null;\n return (url.protocol + '//' + url.host).toLowerCase();\n } catch (e) {\n return null;\n }\n }\n\n var normalizedAllowed = allowedOrigins.map(normalizeOrigin).filter(Boolean);\n\n function isOriginAllowed(origin) {\n var norm = normalizeOrigin(origin);\n if (!norm) return false;\n return normalizedAllowed.indexOf(norm) !== -1;\n }\n\n function postToEditor(msg) {\n if (!connectedSource || !connectedOrigin) return;\n try {\n connectedSource.postMessage(msg, connectedOrigin);\n } catch (err) {\n // Failed to post\n }\n }\n\n // Inject Bridge Styles\n var isEmbedded = false;\n try {\n isEmbedded = window.self !== window.top || window.parent !== window;\n } catch (_e) {\n isEmbedded = true;\n }\n\n var toolbarTag = 'astro-' + 'dev-toolbar';\n\n function ensureBridgeStyles() {\n if (typeof document === 'undefined' || !document || typeof document.getElementById !== 'function') return;\n if (document.getElementById('cms-bridge-styles')) return;\n var style = document.createElement('style');\n style.id = 'cms-bridge-styles';\n style.textContent = [\n isEmbedded ? toolbarTag + ' { display: none !important; }' : '',\n 'html[data-cms-comment-mode],',\n 'html[data-cms-comment-mode] * {',\n ' cursor: crosshair !important;',\n '}',\n 'html[data-cms-edit-mode] [data-cms-field],',\n 'html[data-cms-edit-mode] [data-cms-entry-field] {',\n ' cursor: pointer !important;',\n ' outline: 1px dashed rgba(99, 102, 241, 0.5) !important;',\n ' outline-offset: 2px !important;',\n ' transition: outline 0.15s ease-in-out !important;',\n '}',\n 'html[data-cms-edit-mode] [data-cms-field]:hover,',\n 'html[data-cms-edit-mode] [data-cms-entry-field]:hover {',\n ' outline: 2px solid ${chromeTokens.primary} !important;',\n ' outline-offset: 2px !important;',\n '}',\n 'html[data-cms-edit-mode] [data-cms-group] {',\n ' outline: 1px dashed rgba(16, 185, 129, 0.4) !important;',\n ' outline-offset: 3px !important;',\n '}',\n 'html[data-cms-edit-mode] [data-cms-group]:hover {',\n ' outline: 2px solid ${chromeTokens.success} !important;',\n ' outline-offset: 3px !important;',\n '}',\n 'html[data-cms-edit-mode] [data-cms-collection] {',\n ' cursor: pointer !important;',\n ' outline: 1px dashed rgba(251, 191, 36, 0.4) !important;',\n ' outline-offset: 4px !important;',\n ' transition: outline 0.15s ease-in-out !important;',\n '}',\n 'html[data-cms-edit-mode] [data-cms-collection]:hover {',\n ' outline: 2px solid ${chromeTokens.warning} !important;',\n ' outline-offset: 4px !important;',\n '}'\n ].filter(Boolean).join('\\\\n');\n\n var target = document.head || document.documentElement;\n if (target) {\n target.appendChild(style);\n }\n }\n\n function hideDevToolbar() {\n if (!isEmbedded) return;\n ensureBridgeStyles();\n if (typeof document === 'undefined' || !document || typeof document.querySelector !== 'function') return;\n try {\n var tb = document.querySelector(toolbarTag);\n if (tb && tb instanceof HTMLElement) {\n tb.style.setProperty('display', 'none', 'important');\n }\n } catch (_e) {}\n }\n\n ensureBridgeStyles();\n hideDevToolbar();\n\n function inferFieldKind(el) {\n if (!el) return 'unknown';\n var tag = el.tagName ? el.tagName.toLowerCase() : '';\n if (tag === 'img') return 'image';\n if (tag === 'video') return 'video';\n var explicitKind = el.getAttribute('data-cms-kind');\n if (explicitKind) return explicitKind;\n if (el.classList.contains('rich-body') || el.classList.contains('cms-richtext') || el.getAttribute('data-cms-richtext') === 'true') {\n return 'richtext';\n }\n return 'text';\n }\n\n function getElementRect(el) {\n var r = el.getBoundingClientRect();\n return {\n top: r.top,\n left: r.left,\n width: r.width,\n height: r.height\n };\n }\n\n function parseGroupAttr(raw) {\n if (!raw) return undefined;\n var idx = raw.indexOf(':');\n if (idx === -1) return { group: raw, scope: '' };\n return {\n group: raw.slice(0, idx),\n scope: raw.slice(idx + 1)\n };\n }\n\n function scanRenderedFields() {\n var fieldEls = document.querySelectorAll('[data-cms-field], [data-cms-entry-field]');\n var fieldMap = {};\n\n for (var i = 0; i < fieldEls.length; i++) {\n var el = fieldEls[i];\n var key = el.getAttribute('data-cms-field') || el.getAttribute('data-cms-entry-field') || '';\n if (!key) continue;\n\n var isEntry = el.hasAttribute('data-cms-entry-field');\n var groupEl = el.closest('[data-cms-group]');\n var collectionEl = el.closest('[data-cms-collection]');\n var groupName = undefined;\n if (groupEl) {\n var g = parseGroupAttr(groupEl.getAttribute('data-cms-group'));\n if (g) groupName = g.group;\n }\n\n var entryRef = undefined;\n if (isEntry || collectionEl) {\n entryRef = {\n collection: collectionEl ? collectionEl.getAttribute('data-cms-collection') || '' : '',\n slug: collectionEl ? collectionEl.getAttribute('data-cms-entry') || '' : '',\n path: isEntry ? key : key\n };\n }\n\n var uniqueId = (isEntry && entryRef ? entryRef.collection + ':' + entryRef.slug + ':' : '') + key;\n\n if (!fieldMap[uniqueId]) {\n fieldMap[uniqueId] = {\n key: key,\n kind: inferFieldKind(el),\n group: groupName,\n entryRef: entryRef,\n instances: 1\n };\n } else {\n fieldMap[uniqueId].instances++;\n }\n }\n\n var fields = [];\n for (var k in fieldMap) {\n if (Object.prototype.hasOwnProperty.call(fieldMap, k)) {\n fields.push(fieldMap[k]);\n }\n }\n\n window.__CMS_FIELDS__ = fields;\n window.__CMS_RESCAN__ = scanRenderedFields;\n\n try {\n document.dispatchEvent(new CustomEvent('cms:fields-updated', { detail: fields }));\n } catch (_e) {}\n\n postToEditor({\n source: 'cms-preview',\n v: PROTOCOL_VERSION,\n type: 'rendered-fields',\n fields: fields\n });\n }\n\n function debouncedRescan() {\n if (isPatchingDom) return;\n if (debounceRescanTimer) clearTimeout(debounceRescanTimer);\n debounceRescanTimer = setTimeout(function() {\n scanRenderedFields();\n scheduleRectsUpdate();\n }, 150);\n }\n\n var currentObserver = null;\n function setupMutationObserver() {\n if (typeof MutationObserver === 'undefined' || !document.body) return;\n if (currentObserver) {\n try {\n currentObserver.disconnect();\n } catch (_e) {}\n }\n currentObserver = new MutationObserver(function(mutations) {\n if (isPatchingDom) return;\n hideDevToolbar();\n debouncedRescan();\n });\n currentObserver.observe(document.body, {\n childList: true,\n subtree: true,\n attributeFilter: ['data-cms-field', 'data-cms-entry-field', 'data-cms-group', 'data-cms-collection', 'data-cms-entry']\n });\n }\n\n function buildStableSelector(target) {\n if (!target || !target.tagName) return '';\n if (target === document.documentElement) return 'html';\n if (target === document.body) return 'body';\n\n var parts = [];\n var curr = target;\n var maxLevels = 8;\n\n while (curr && curr !== document.documentElement && parts.length < maxLevels) {\n if (curr === document.body) {\n parts.unshift('body');\n break;\n }\n var id = curr.getAttribute('id');\n if (id && id.trim()) {\n var escapedId = (typeof CSS !== 'undefined' && CSS.escape) ? CSS.escape(id.trim()) : id.trim();\n parts.unshift('#' + escapedId);\n break;\n }\n var tag = curr.tagName ? curr.tagName.toLowerCase() : '';\n if (!tag) break;\n var count = 1;\n var sib = curr.previousElementSibling;\n while (sib) {\n if (sib.tagName && sib.tagName.toLowerCase() === tag) {\n count++;\n }\n sib = sib.previousElementSibling;\n }\n parts.unshift(tag + ':nth-of-type(' + count + ')');\n curr = curr.parentElement;\n }\n\n return parts.join(' > ');\n }\n\n function buildElementLabel(el) {\n if (!el || !el.tagName) return 'element';\n\n var ariaLabel = el.getAttribute('aria-label');\n if (ariaLabel && ariaLabel.trim()) {\n return ariaLabel.trim();\n }\n\n var id = el.getAttribute('id');\n if (id && id.trim()) {\n return '#' + id.trim();\n }\n\n var tag = el.tagName.toLowerCase();\n\n if (tag === 'nav') return 'Navigation';\n if (tag === 'header') return 'Header';\n if (tag === 'footer') return 'Footer';\n if (tag === 'aside') return 'Sidebar';\n if (tag === 'form') return 'Form';\n\n if (tag === 'img') {\n var alt = el.getAttribute('alt');\n if (alt && alt.trim()) return alt.trim();\n return 'img';\n }\n\n if (tag === 'a' || tag === 'button') {\n var text = (el.textContent || '').trim().replace(/\\\\s+/g, ' ');\n if (text) {\n return text.length > 40 ? text.slice(0, 37) + '...' : text;\n }\n return tag;\n }\n\n return tag || 'element';\n }\n\n function buildCandidateEntry(targetEl, clientX, clientY) {\n if (!targetEl || !targetEl.tagName) return null;\n var selector = buildStableSelector(targetEl);\n if (!selector) return null;\n var all = Array.prototype.slice.call(document.querySelectorAll(selector));\n var instance = Math.max(0, all.indexOf(targetEl));\n var hitRect = targetEl.getBoundingClientRect();\n var offsetX = typeof clientX === 'number' ? Math.round(clientX - hitRect.left) : 0;\n var offsetY = typeof clientY === 'number' ? Math.round(clientY - hitRect.top) : 0;\n return {\n selector: selector,\n instance: instance,\n kind: 'element',\n label: buildElementLabel(targetEl),\n offsetX: offsetX,\n offsetY: offsetY,\n rect: getElementRect(targetEl)\n };\n }\n\n function buildAnchorChain(el, clientX, clientY) {\n var chain = [];\n var curr = el;\n while (curr && curr !== document.documentElement && curr !== document.body) {\n var hit = curr.closest('[data-cms-field], [data-cms-entry-field], [data-cms-group], [data-cms-collection][data-cms-entry]');\n if (!hit) break;\n\n var selector = '';\n var kind = 'unknown';\n var label = '';\n\n if (hit.hasAttribute('data-cms-field')) {\n var fieldKey = hit.getAttribute('data-cms-field') || '';\n selector = '[data-cms-field=\"' + fieldKey + '\"]';\n kind = inferFieldKind(hit);\n label = fieldKey;\n } else if (hit.hasAttribute('data-cms-entry-field')) {\n var entryFieldKey = hit.getAttribute('data-cms-entry-field') || '';\n selector = '[data-cms-entry-field=\"' + entryFieldKey + '\"]';\n kind = inferFieldKind(hit);\n label = entryFieldKey;\n } else if (hit.hasAttribute('data-cms-group')) {\n var groupAttr = hit.getAttribute('data-cms-group') || '';\n selector = '[data-cms-group=\"' + groupAttr + '\"]';\n kind = 'group';\n var parsed = parseGroupAttr(groupAttr);\n label = parsed ? parsed.group : groupAttr;\n } else if (hit.hasAttribute('data-cms-collection') && hit.hasAttribute('data-cms-entry')) {\n var col = hit.getAttribute('data-cms-collection') || '';\n var ent = hit.getAttribute('data-cms-entry') || '';\n selector = '[data-cms-collection=\"' + col + '\"][data-cms-entry=\"' + ent + '\"]';\n kind = 'entry';\n label = col + '/' + ent;\n }\n\n if (selector) {\n var all = Array.prototype.slice.call(document.querySelectorAll(selector));\n var instance = Math.max(0, all.indexOf(hit));\n var hitRect = hit.getBoundingClientRect();\n var offsetX = typeof clientX === 'number' ? Math.round(clientX - hitRect.left) : 0;\n var offsetY = typeof clientY === 'number' ? Math.round(clientY - hitRect.top) : 0;\n chain.push({\n selector: selector,\n instance: instance,\n kind: kind,\n label: label,\n offsetX: offsetX,\n offsetY: offsetY,\n rect: getElementRect(hit)\n });\n }\n\n curr = hit.parentElement;\n }\n\n if (chain.length > 0) {\n return chain;\n }\n\n if (!el || !el.tagName) return chain;\n\n var interactiveEl = el.closest ? el.closest('a, button') : null;\n var selfEl = interactiveEl || (el.closest ? el.closest('a, button, nav, header, footer, aside, main, section, article, form, img, svg, [role]') : null) || el;\n var landmarkEl = selfEl.closest ? selfEl.closest('nav, header, footer, aside, main, section, article, form, [role=\"navigation\"], [role=\"banner\"], [role=\"contentinfo\"]') : null;\n\n var selfEntry = buildCandidateEntry(selfEl, clientX, clientY);\n if (selfEntry) {\n chain.push(selfEntry);\n }\n\n if (landmarkEl && landmarkEl !== selfEl) {\n var landmarkEntry = buildCandidateEntry(landmarkEl, clientX, clientY);\n if (landmarkEntry) {\n chain.push(landmarkEntry);\n }\n }\n\n return chain;\n }\n\n function resolveAnchorEl(anchor) {\n if (!anchor || !anchor.selector) return null;\n try {\n var els = document.querySelectorAll(anchor.selector);\n if (!els || els.length === 0) return null;\n var inst = typeof anchor.instance === 'number' ? anchor.instance : 0;\n if (inst >= 0 && inst < els.length) return els[inst];\n return els[0];\n } catch (_e) {\n return null;\n }\n }\n\n function scheduleRectsUpdate() {\n if (rafScheduled) return;\n rafScheduled = true;\n requestAnimationFrame(function() {\n rafScheduled = false;\n var rects = {};\n if (activeKey) {\n var el = document.querySelector('[data-cms-field=\"' + activeKey + '\"], [data-cms-entry-field=\"' + activeKey + '\"]');\n if (el) {\n rects[activeKey] = getElementRect(el);\n }\n }\n postToEditor({\n source: 'cms-preview',\n v: PROTOCOL_VERSION,\n type: 'rects-update',\n rects: rects,\n scrollY: window.scrollY || window.pageYOffset || 0\n });\n\n if (watchedAnchors && watchedAnchors.length > 0) {\n var anchorRects = {};\n for (var a = 0; a < watchedAnchors.length; a++) {\n var wAnchor = watchedAnchors[a];\n var resolvedEl = resolveAnchorEl(wAnchor);\n if (resolvedEl) {\n anchorRects[wAnchor.id] = getElementRect(resolvedEl);\n } else {\n anchorRects[wAnchor.id] = null;\n }\n }\n postToEditor({\n source: 'cms-preview',\n v: PROTOCOL_VERSION,\n type: 'anchor-rects',\n rects: anchorRects\n });\n }\n });\n }\n\n // Click handler\n document.addEventListener('click', function(e) {\n if (document.documentElement.hasAttribute('data-cms-comment-mode')) {\n e.preventDefault();\n e.stopPropagation();\n var target = e.target;\n if (!target || !(target instanceof Element)) return;\n\n var docWidth = Math.max(\n document.documentElement.scrollWidth || 0,\n document.body ? document.body.scrollWidth : 0,\n window.innerWidth || 0\n );\n var docHeight = Math.max(\n document.documentElement.scrollHeight || 0,\n document.body ? document.body.scrollHeight : 0,\n window.innerHeight || 0\n );\n var pageX = e.pageX !== undefined ? e.pageX : (e.clientX + (window.scrollX || window.pageXOffset || 0));\n var pageY = e.pageY !== undefined ? e.pageY : (e.clientY + (window.scrollY || window.pageYOffset || 0));\n var pageXPct = docWidth > 0 ? Math.round((pageX / docWidth) * 10000) / 100 : 0;\n var pageYPct = docHeight > 0 ? Math.round((pageY / docHeight) * 10000) / 100 : 0;\n\n var chain = buildAnchorChain(target, e.clientX, e.clientY);\n var clickRect = chain.length > 0 ? chain[0].rect : {\n top: e.clientY,\n left: e.clientX,\n width: 0,\n height: 0\n };\n\n postToEditor({\n source: 'cms-preview',\n v: PROTOCOL_VERSION,\n type: 'comment-click',\n chain: chain,\n point: { pageXPct: pageXPct, pageYPct: pageYPct },\n rect: clickRect\n });\n return;\n }\n\n if (!document.documentElement.hasAttribute('data-cms-edit-mode')) return;\n var target = e.target;\n if (!target || !(target instanceof Element)) return;\n\n var fieldEl = target.closest('[data-cms-field], [data-cms-entry-field]');\n var groupEl = target.closest('[data-cms-group]');\n\n if (fieldEl) {\n e.preventDefault();\n e.stopPropagation();\n\n var isEntry = fieldEl.hasAttribute('data-cms-entry-field');\n var key = fieldEl.getAttribute('data-cms-field') || fieldEl.getAttribute('data-cms-entry-field') || '';\n var kind = inferFieldKind(fieldEl);\n var rect = getElementRect(fieldEl);\n activeKey = key;\n\n var selector = isEntry ? '[data-cms-entry-field=\"' + key + '\"]' : '[data-cms-field=\"' + key + '\"]';\n var all = Array.prototype.slice.call(document.querySelectorAll(selector));\n var instance = Math.max(0, all.indexOf(fieldEl));\n\n var collectionEl = fieldEl.closest('[data-cms-collection]');\n var entryRef = (isEntry || collectionEl) ? {\n collection: collectionEl ? collectionEl.getAttribute('data-cms-collection') || '' : '',\n slug: collectionEl ? collectionEl.getAttribute('data-cms-entry') || '' : '',\n path: isEntry ? key : key\n } : undefined;\n\n var groupPath = groupEl ? parseGroupAttr(groupEl.getAttribute('data-cms-group')) : undefined;\n\n try {\n document.dispatchEvent(new CustomEvent('cms:field-selected', {\n detail: {\n key: key,\n kind: kind,\n entryRef: entryRef,\n groupPath: groupPath\n }\n }));\n } catch (_e) {}\n\n postToEditor({\n source: 'cms-preview',\n v: PROTOCOL_VERSION,\n type: 'field-click',\n key: key,\n kind: kind,\n rect: rect,\n instance: instance,\n entryRef: entryRef,\n groupPath: groupPath\n });\n return;\n }\n\n if (groupEl) {\n e.preventDefault();\n e.stopPropagation();\n\n var g = parseGroupAttr(groupEl.getAttribute('data-cms-group'));\n if (g) {\n var gRect = getElementRect(groupEl);\n postToEditor({\n source: 'cms-preview',\n v: PROTOCOL_VERSION,\n type: 'group-click',\n group: g.group,\n scope: g.scope,\n rect: gRect\n });\n }\n return;\n }\n\n var collectionEl = target.closest('[data-cms-collection]');\n if (collectionEl) {\n e.preventDefault();\n e.stopPropagation();\n\n var collKey = collectionEl.getAttribute('data-cms-collection') || '';\n var entryEl = target.closest('[data-cms-entry]');\n var slug = collectionEl.getAttribute('data-cms-entry') || (entryEl ? entryEl.getAttribute('data-cms-entry') : null) || undefined;\n var cRect = getElementRect(collectionEl);\n\n postToEditor({\n source: 'cms-preview',\n v: PROTOCOL_VERSION,\n type: 'collection-click',\n collection: collKey,\n slug: slug,\n rect: cRect\n });\n return;\n }\n }, true);\n\n // Message handler\n window.addEventListener('message', function(e) {\n var data = e.data;\n if (!data || typeof data !== 'object') return;\n if (data.source !== 'cms-editor') return;\n\n if (data.type === 'hello') {\n if (!isOriginAllowed(e.origin)) return;\n connectedOrigin = e.origin;\n connectedSource = e.source;\n\n postToEditor({\n source: 'cms-preview',\n v: PROTOCOL_VERSION,\n type: 'ready',\n protocolVersion: PROTOCOL_VERSION,\n capabilities: ['comments', 'collection-click']\n });\n\n scanRenderedFields();\n return;\n }\n\n if (!connectedOrigin || e.origin !== connectedOrigin) return;\n\n if (data.type === 'highlight-mode') {\n if (data.on) {\n document.documentElement.setAttribute('data-cms-edit-mode', 'true');\n } else {\n document.documentElement.removeAttribute('data-cms-edit-mode');\n }\n return;\n }\n\n if (data.type === 'comment-mode') {\n if (data.on) {\n document.documentElement.setAttribute('data-cms-comment-mode', 'true');\n } else {\n document.documentElement.removeAttribute('data-cms-comment-mode');\n }\n return;\n }\n\n if (data.type === 'watch-anchors') {\n watchedAnchors = Array.isArray(data.anchors) ? data.anchors : [];\n scheduleRectsUpdate();\n return;\n }\n\n if (data.type === 'scroll-to-anchor') {\n var sId = data.id;\n var targetItem = null;\n for (var si = 0; si < watchedAnchors.length; si++) {\n if (watchedAnchors[si].id === sId) {\n targetItem = watchedAnchors[si];\n break;\n }\n }\n if (targetItem) {\n var elToScroll = resolveAnchorEl(targetItem);\n if (elToScroll) {\n elToScroll.scrollIntoView({ behavior: 'smooth', block: 'center' });\n scheduleRectsUpdate();\n }\n }\n return;\n }\n\n if (data.type === 'patch') {\n isPatchingDom = true;\n var patchKey = data.key;\n var patchKind = data.kind;\n var patchVal = data.value;\n var patchEntry = data.entryRef;\n\n var patchSelector;\n var fPath = patchEntry && patchEntry.path ? patchEntry.path : patchKey;\n if (patchEntry && (patchEntry.collection || patchEntry.slug)) {\n var colAttr = patchEntry.collection ? '[data-cms-collection=\"' + patchEntry.collection + '\"]' : '';\n var entryAttr = patchEntry.slug ? '[data-cms-entry=\"' + patchEntry.slug + '\"]' : '';\n var scopeSel = colAttr + entryAttr;\n patchSelector = scopeSel + ' [data-cms-entry-field=\"' + fPath + '\"], ' +\n scopeSel + '[data-cms-entry-field=\"' + fPath + '\"]';\n } else if (patchEntry) {\n patchSelector = '[data-cms-entry-field=\"' + fPath + '\"]';\n } else {\n patchSelector = '[data-cms-field=\"' + patchKey + '\"]';\n }\n\n var matchingEls = document.querySelectorAll(patchSelector);\n for (var j = 0; j < matchingEls.length; j++) {\n var mEl = matchingEls[j];\n var isStructured = patchKind === 'geo.area' || patchKind === 'geoArea' ||\n patchKind === 'address' || patchKind === 'address.list' ||\n patchKind === 'media.videoList' || patchKind === 'videoList' ||\n mEl.getAttribute('data-cms-kind') === 'geo.area' ||\n mEl.getAttribute('data-cms-kind') === 'address.list' ||\n mEl.getAttribute('data-cms-kind') === 'media.videoList';\n\n if (patchKind === 'image' || mEl.tagName.toLowerCase() === 'img') {\n if (patchVal && typeof patchVal === 'object') {\n if (patchVal.url) mEl.setAttribute('src', patchVal.url);\n if (patchVal.alt !== undefined) mEl.setAttribute('alt', patchVal.alt);\n } else if (typeof patchVal === 'string') {\n mEl.setAttribute('src', patchVal);\n }\n } else if (patchKind === 'video' || mEl.tagName.toLowerCase() === 'video') {\n if (patchVal && typeof patchVal === 'object') {\n if (patchVal.url) mEl.setAttribute('src', patchVal.url);\n if (patchVal.poster !== undefined) mEl.setAttribute('poster', patchVal.poster);\n } else if (typeof patchVal === 'string') {\n mEl.setAttribute('src', patchVal);\n }\n if (typeof mEl.load === 'function') mEl.load();\n } else if (isStructured || (patchVal && typeof patchVal === 'object')) {\n // Structured non-image field values (e.g. videoList, geoArea, address) cannot be rendered\n // via simple textContent replacement without producing [object Object].\n // Skip the text write and leave server-rendered markup intact; structured fields refresh via reload.\n } else {\n mEl.textContent = patchVal !== null && patchVal !== undefined ? String(patchVal) : '';\n }\n }\n\n isPatchingDom = false;\n scanRenderedFields();\n scheduleRectsUpdate();\n return;\n }\n\n if (data.type === 'scroll-to') {\n var scrollKey = data.key;\n var scrollInstance = typeof data.instance === 'number' ? data.instance : 0;\n var scrollEls = document.querySelectorAll('[data-cms-field=\"' + scrollKey + '\"], [data-cms-entry-field=\"' + scrollKey + '\"]');\n if (scrollEls.length > scrollInstance) {\n scrollEls[scrollInstance].scrollIntoView({ behavior: 'smooth', block: 'center' });\n activeKey = scrollKey;\n scheduleRectsUpdate();\n }\n return;\n }\n\n if (data.type === 'reload') {\n window.location.reload();\n return;\n }\n });\n\n function handlePageTransition() {\n hideDevToolbar();\n scanRenderedFields();\n setupMutationObserver();\n }\n\n window.addEventListener('scroll', scheduleRectsUpdate, { passive: true });\n window.addEventListener('resize', scheduleRectsUpdate, { passive: true });\n\n document.addEventListener('astro:page-load', handlePageTransition);\n document.addEventListener('astro:after-swap', handlePageTransition);\n window.addEventListener('popstate', handlePageTransition);\n\n if (document.readyState === 'loading') {\n document.addEventListener('DOMContentLoaded', function() {\n handlePageTransition();\n });\n } else {\n handlePageTransition();\n }\n})();`;\n}\n","import { createCmsClient, getClient } from '../client';\nimport { buildBridgeScript } from '../preview/bridge-script';\nimport { isDraftMode, runWithDraftBundle, setActiveDraftBundle } from '../runtime/store';\nimport type { CmsClient, ContentBundle } from '../types';\n\nexport interface PreviewMiddlewareOptions {\n client?: CmsClient;\n siteId?: string;\n contentUrl?: string;\n /** @deprecated Site hosts no longer verify preview tokens. Ignored outside astro dev. */\n previewSecret?: string;\n editorOrigins?: string[];\n}\n\ninterface PreviewContextLocals {\n __cms_is_draft?: boolean;\n __cms_draft_bundle?: ContentBundle;\n [key: string]: unknown;\n}\n\nexport interface PreviewMiddlewareContext {\n request: Request;\n url?: URL;\n locals?: PreviewContextLocals;\n rewrite?: (path: string) => Promise<Response> | undefined;\n}\n\nexport function createPreviewMiddleware(options: PreviewMiddlewareOptions = {}) {\n let client = options.client;\n\n return async (\n context: PreviewMiddlewareContext,\n next: () => Promise<Response>,\n ): Promise<Response> => {\n const globalWithCms = globalThis as typeof globalThis & {\n __CMS_IS_REWRITING__?: boolean;\n };\n\n // If already running within an active draft bundle context or internal rewrite, pass through\n if (\n (typeof globalThis !== 'undefined' && globalWithCms.__CMS_IS_REWRITING__) ||\n isDraftMode() ||\n context.locals?.__cms_is_draft\n ) {\n return next();\n }\n\n const rawUrl = context.url;\n const url =\n rawUrl && typeof rawUrl.href === 'string'\n ? new URL(rawUrl.href)\n : rawUrl && typeof (rawUrl as unknown as { pathname?: string }).pathname === 'string'\n ? rawUrl\n : new URL(context.request?.url || '/', 'http://localhost');\n const pathname = url.pathname || '/';\n const isPreviewRoute = pathname === '/_preview' || pathname.startsWith('/_preview/');\n\n const previewToken =\n (rawUrl?.searchParams?.get ? rawUrl.searchParams.get('preview_token') : null) ||\n (url?.searchParams?.get ? url.searchParams.get('preview_token') : null) ||\n (context.request?.headers?.get ? context.request.headers.get('x-preview-token') : null);\n\n if (!isPreviewRoute && !previewToken) {\n return next();\n }\n\n if (!client) {\n client = getClient() || undefined;\n }\n\n if (!client) {\n const metaEnv = (import.meta as unknown as { env?: Record<string, string | undefined> }).env;\n const siteId =\n options.siteId ||\n (typeof process !== 'undefined' && process.env?.CMS_SITE_ID) ||\n (typeof import.meta !== 'undefined' && metaEnv?.CMS_SITE_ID) ||\n '';\n const contentUrl =\n options.contentUrl ||\n (typeof process !== 'undefined' && process.env?.CMS_CONTENT_URL) ||\n (typeof import.meta !== 'undefined' && metaEnv?.CMS_CONTENT_URL) ||\n '';\n if (siteId && contentUrl) {\n client = createCmsClient({\n siteId,\n contentUrl,\n });\n }\n }\n\n if (!previewToken) {\n return new Response('Preview token is missing', {\n status: 400,\n headers: {\n 'Cache-Control': 'private, no-store',\n 'X-Robots-Tag': 'noindex, nofollow',\n },\n });\n }\n\n if (!client) {\n return new Response('CMS client is missing or not configured', {\n status: 500,\n headers: {\n 'Cache-Control': 'private, no-store',\n 'X-Robots-Tag': 'noindex, nofollow',\n },\n });\n }\n\n let draftBundle: ContentBundle;\n try {\n draftBundle = await client.getBundle({ previewToken });\n } catch (err) {\n const status = (err as { status?: number })?.status;\n if (status === 401 || status === 403 || status === 404) {\n return new Response('Preview token is not valid for this site', {\n status: 404,\n headers: {\n 'Cache-Control': 'private, no-store',\n 'X-Robots-Tag': 'noindex, nofollow',\n },\n });\n }\n\n console.error(err);\n return new Response('Failed to load preview content', {\n status: 502,\n headers: {\n 'Cache-Control': 'private, no-store',\n 'X-Robots-Tag': 'noindex, nofollow',\n },\n });\n }\n\n // Run downstream request within the draft bundle context\n if (context.locals) {\n context.locals.__cms_is_draft = true;\n context.locals.__cms_draft_bundle = draftBundle;\n }\n\n let finalResponse: Response;\n setActiveDraftBundle(draftBundle);\n try {\n finalResponse = await runWithDraftBundle(draftBundle, async () => {\n let response: Response;\n if (isPreviewRoute) {\n const basePath = pathname.replace(/^\\/_preview/, '') || '/';\n if (typeof context.rewrite === 'function') {\n if (typeof globalThis !== 'undefined') {\n globalWithCms.__CMS_IS_REWRITING__ = true;\n }\n try {\n const rewritten = await context.rewrite(basePath);\n if (rewritten) {\n response = rewritten as Response;\n } else {\n response = await next();\n }\n } finally {\n if (typeof globalThis !== 'undefined') {\n globalWithCms.__CMS_IS_REWRITING__ = false;\n }\n }\n } else {\n response = await next();\n }\n } else {\n response = await next();\n }\n\n const contentType = response?.headers?.get ? response.headers.get('content-type') : '';\n const isStaticAsset = Boolean(\n pathname.match(/\\.(js|css|png|jpg|jpeg|gif|svg|ico|webp|woff|woff2|ttf|json|map)$/i),\n );\n const isHtml =\n (typeof contentType === 'string' && contentType.includes('text/html')) ||\n (!contentType && !isStaticAsset);\n\n if (isHtml) {\n const html = await response.text();\n const bridgeScript = buildBridgeScript({\n editorOrigins: options.editorOrigins,\n });\n const scriptTag = `<script>${bridgeScript}</script>`;\n const modifiedHtml = html.includes('</body>')\n ? html.replace('</body>', `${scriptTag}</body>`)\n : `${html}${scriptTag}`;\n\n const newHeaders = new Headers(response.headers);\n if (!newHeaders.has('content-type')) {\n newHeaders.set('content-type', 'text/html; charset=utf-8');\n }\n newHeaders.delete('content-length');\n newHeaders.set('Cache-Control', 'private, no-store, no-cache, must-revalidate');\n newHeaders.set('X-Robots-Tag', 'noindex, nofollow');\n\n return new Response(modifiedHtml, {\n status: response.status,\n statusText: response.statusText,\n headers: newHeaders,\n });\n }\n\n const nonHtmlHeaders = new Headers(response.headers);\n nonHtmlHeaders.set('Cache-Control', 'private, no-store, no-cache, must-revalidate');\n nonHtmlHeaders.set('X-Robots-Tag', 'noindex, nofollow');\n return new Response(response.body, {\n status: response.status,\n statusText: response.statusText,\n headers: nonHtmlHeaders,\n });\n });\n } finally {\n setActiveDraftBundle(null);\n }\n\n return finalResponse;\n };\n}\n"]}
1
+ {"version":3,"sources":["../package.json","../src/version.ts","../src/client.ts","../src/preview/bridge-script.ts","../src/middleware/preview.ts"],"names":["globalWithCms"],"mappings":"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;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AA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","file":"chunk-4PBDIQNL.js","sourcesContent":["{\n \"name\": \"@407dev/cms-astro\",\n \"version\": \"1.1.0\",\n \"type\": \"module\",\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"git+https://github.com/407dev/cms.git\",\n \"directory\": \"packages/astro\"\n },\n \"main\": \"./dist/index.js\",\n \"types\": \"./dist/index.d.ts\",\n \"exports\": {\n \".\": {\n \"source\": \"./src/index.ts\",\n \"types\": \"./dist/index.d.ts\",\n \"import\": \"./dist/index.js\",\n \"default\": \"./dist/index.js\"\n },\n \"./collections\": {\n \"source\": \"./src/fields/collections.ts\",\n \"types\": \"./dist/fields/collections.d.ts\",\n \"import\": \"./dist/fields/collections.js\"\n },\n \"./image\": {\n \"source\": \"./src/image.ts\",\n \"types\": \"./dist/image.d.ts\",\n \"import\": \"./dist/image.js\",\n \"default\": \"./dist/image.js\"\n },\n \"./CmsImage.astro\": \"./src/CmsImage.astro\",\n \"./CmsVideo.astro\": \"./src/CmsVideo.astro\",\n \"./CmsHead.astro\": \"./src/CmsHead.astro\",\n \"./RichText.astro\": \"./src/RichText.astro\",\n \"./middleware\": {\n \"source\": \"./src/middleware/index.ts\",\n \"types\": \"./dist/middleware/index.d.ts\",\n \"import\": \"./dist/middleware/index.js\",\n \"default\": \"./dist/middleware/index.js\"\n },\n \"./toolbar\": {\n \"source\": \"./src/toolbar/app.ts\",\n \"types\": \"./dist/toolbar/app.d.ts\",\n \"import\": \"./dist/toolbar/app.js\",\n \"default\": \"./dist/toolbar/app.js\"\n },\n \"./dev\": {\n \"source\": \"./src/dev/index.ts\",\n \"types\": \"./dist/dev/index.d.ts\",\n \"import\": \"./dist/dev/index.js\",\n \"default\": \"./dist/dev/index.js\"\n }\n },\n \"publishConfig\": {\n \"access\": \"public\"\n },\n \"files\": [\n \"dist\",\n \"src\"\n ],\n \"scripts\": {\n \"build\": \"tsup\",\n \"dev\": \"tsup --watch\",\n \"lint\": \"biome check src\",\n \"typecheck\": \"tsc --noEmit\",\n \"test\": \"vitest run\"\n },\n \"dependencies\": {\n \"@407dev/blocks\": \"workspace:*\",\n \"@407dev/field-types\": \"workspace:*\",\n \"zod\": \"^4.4.3\"\n },\n \"peerDependencies\": {\n \"@407dev/cli\": \"workspace:*\",\n \"astro\": \"^5.0.0\"\n },\n \"peerDependenciesMeta\": {\n \"@407dev/cli\": {\n \"optional\": true\n },\n \"astro\": {\n \"optional\": true\n }\n },\n \"devDependencies\": {\n \"@407dev/api-client\": \"workspace:*\",\n \"@407dev/cli\": \"workspace:*\",\n \"@407dev/config\": \"workspace:*\",\n \"@407dev/design-tokens\": \"workspace:*\",\n \"astro\": \"^5.3.0\",\n \"expect-type\": \"^0.20.0\",\n \"tsup\": \"^8.4.0\",\n \"typescript\": \"^5.7.3\",\n \"vite\": \"^6.1.0\",\n \"vitest\": \"3.0.7\"\n }\n}\n","import pkg from '../package.json';\n\nexport const CMS_ASTRO_VERSION: string = pkg.version;\n","import { DEFAULT_DEV_CONTENT_URL } from '@407dev/config';\nimport type {\n CmsClient,\n CmsClientConfig,\n CmsSiteConfig,\n ContentBundle,\n GetBundleOptions,\n} from './types';\nimport { CMS_ASTRO_VERSION } from './version.js';\n\nexport function createCmsClient(config: CmsClientConfig): CmsClient {\n const siteId = config.siteId;\n const contentUrl = config.contentUrl.replace(/\\/+$/, '');\n const fetchFn = config.fetch || fetch;\n\n // In-memory cache for published bundle to ensure build determinism\n let cachedPublishedBundle: ContentBundle | null = null;\n\n const client: CmsClient = {\n siteId,\n contentUrl,\n previewSecret: config.previewSecret,\n\n async getBundle(options?: GetBundleOptions): Promise<ContentBundle> {\n const isDraft = Boolean(options?.previewToken);\n\n if (!isDraft && cachedPublishedBundle) {\n return cachedPublishedBundle;\n }\n\n const url = isDraft\n ? `${contentUrl}/draft/${siteId}/bundle`\n : `${contentUrl}/content/${siteId}/bundle`;\n\n const headers: Record<string, string> = {\n 'x-cms-sdk': `cms-astro@${CMS_ASTRO_VERSION}`,\n };\n if (options?.previewToken) {\n headers['x-preview-token'] = options.previewToken;\n }\n\n const res = await fetchFn(url, {\n headers,\n });\n if (!res.ok) {\n const error = new Error(\n `CMS Client: Failed to fetch bundle from ${url} (status ${res.status}): ${res.statusText}`,\n );\n (error as unknown as { status?: number }).status = res.status;\n throw error;\n }\n\n const bundle = (await res.json()) as ContentBundle;\n\n if (!isDraft) {\n cachedPublishedBundle = bundle;\n }\n\n return bundle;\n },\n\n async getFields(options?: GetBundleOptions): Promise<ContentBundle['fields']> {\n const bundle = await this.getBundle(options);\n return bundle.fields || {};\n },\n\n async getField<T = unknown>(key: string, options?: GetBundleOptions): Promise<T | null> {\n const fields = await this.getFields(options);\n return (fields[key] as T) ?? null;\n },\n\n async getCollections(options?: GetBundleOptions): Promise<ContentBundle['collections']> {\n const bundle = await this.getBundle(options);\n return bundle.collections || {};\n },\n\n async getEntries(\n collectionKey: string,\n options?: GetBundleOptions,\n ): Promise<ContentBundle['entries'][string]> {\n const bundle = await this.getBundle(options);\n return bundle.entries?.[collectionKey] || [];\n },\n\n async getEntry(\n collectionKey: string,\n slug: string,\n options?: GetBundleOptions,\n ): Promise<ContentBundle['entries'][string][number] | null> {\n const entries = await this.getEntries(collectionKey, options);\n return entries.find((e) => e.slug === slug) || null;\n },\n\n async getRoutes(options?: GetBundleOptions): Promise<ContentBundle['routes']> {\n const bundle = await this.getBundle(options);\n return bundle.routes || [];\n },\n\n async getSiteConfig(options?: GetBundleOptions): Promise<CmsSiteConfig> {\n const bundle = await this.getBundle(options);\n return {\n site_id: bundle.site_id,\n redirects: bundle.redirects || [],\n robots: bundle.settings?.robots || {},\n default_seo: bundle.settings?.default_seo || {},\n sitemap: bundle.settings?.sitemap || {},\n not_found_path: bundle.settings?.not_found_path || null,\n };\n },\n\n clearCache(): void {\n cachedPublishedBundle = null;\n },\n };\n\n return client;\n}\n\nconst globalWithCms = globalThis as typeof globalThis & {\n __CMS_CLIENT__?: CmsClient | null;\n};\n\nlet globalClient: CmsClient | null =\n (typeof globalThis !== 'undefined' && globalWithCms.__CMS_CLIENT__) || null;\n\nexport function initCmsClient(options: {\n siteId?: string;\n contentUrl?: string;\n previewSecret?: string;\n client?: CmsClient;\n}): CmsClient {\n if (options.client) {\n globalClient = options.client;\n if (typeof globalThis !== 'undefined') {\n globalWithCms.__CMS_CLIENT__ = options.client;\n }\n return globalClient;\n }\n\n globalClient = createCmsClient({\n siteId: options.siteId || process.env.CMS_SITE_ID || '',\n contentUrl: options.contentUrl || process.env.CMS_CONTENT_URL || DEFAULT_DEV_CONTENT_URL,\n previewSecret: options.previewSecret || process.env.CMS_PREVIEW_SECRET,\n });\n if (typeof globalThis !== 'undefined') {\n globalWithCms.__CMS_CLIENT__ = globalClient;\n }\n\n return globalClient;\n}\n\nexport function getClient(): CmsClient | null {\n return (\n globalClient || (typeof globalThis !== 'undefined' && globalWithCms.__CMS_CLIENT__) || null\n );\n}\n\nexport function setClient(client: CmsClient | null): void {\n globalClient = client;\n if (typeof globalThis !== 'undefined') {\n globalWithCms.__CMS_CLIENT__ = client;\n }\n}\n","import { chromeTokens } from '@407dev/design-tokens/tokens';\nimport { resolveEditorOrigins } from './origins';\n\nexport const BRIDGE_PROTOCOL_VERSION = 1;\n\nexport interface BridgeScriptOptions {\n editorOrigins?: string[];\n}\n\nexport function buildBridgeScript(options: BridgeScriptOptions = {}): string {\n const allowedOrigins = resolveEditorOrigins(options.editorOrigins);\n const allowedOriginsJson = JSON.stringify(allowedOrigins);\n\n return `(function() {\n if (typeof window === 'undefined') return;\n if (window.__CMS_BRIDGE_INITIALIZED__) return;\n window.__CMS_BRIDGE_INITIALIZED__ = true;\n\n var PROTOCOL_VERSION = ${BRIDGE_PROTOCOL_VERSION};\n var allowedOrigins = ${allowedOriginsJson};\n var connectedOrigin = null;\n var connectedSource = null;\n var activeKey = null;\n var watchedAnchors = [];\n var rafScheduled = false;\n var isPatchingDom = false;\n var debounceRescanTimer = null;\n\n function normalizeOrigin(raw) {\n if (!raw || typeof raw !== 'string') return null;\n var trimmed = raw.trim();\n if (!trimmed) return null;\n try {\n var withScheme = /^[a-zA-Z][a-zA-Z0-9+.-]*:\\\\/\\\\//.test(trimmed) ? trimmed : 'https://' + trimmed;\n var url = new URL(withScheme);\n if (!url.protocol || !url.host) return null;\n return (url.protocol + '//' + url.host).toLowerCase();\n } catch (e) {\n return null;\n }\n }\n\n var normalizedAllowed = allowedOrigins.map(normalizeOrigin).filter(Boolean);\n\n function isOriginAllowed(origin) {\n var norm = normalizeOrigin(origin);\n if (!norm) return false;\n return normalizedAllowed.indexOf(norm) !== -1;\n }\n\n function postToEditor(msg) {\n if (!connectedSource || !connectedOrigin) return;\n try {\n connectedSource.postMessage(msg, connectedOrigin);\n } catch (err) {\n // Failed to post\n }\n }\n\n // Inject Bridge Styles\n var isEmbedded = false;\n try {\n isEmbedded = window.self !== window.top || window.parent !== window;\n } catch (_e) {\n isEmbedded = true;\n }\n\n var toolbarTag = 'astro-' + 'dev-toolbar';\n\n function ensureBridgeStyles() {\n if (typeof document === 'undefined' || !document || typeof document.getElementById !== 'function') return;\n if (document.getElementById('cms-bridge-styles')) return;\n var style = document.createElement('style');\n style.id = 'cms-bridge-styles';\n style.textContent = [\n isEmbedded ? toolbarTag + ' { display: none !important; }' : '',\n 'html[data-cms-comment-mode],',\n 'html[data-cms-comment-mode] * {',\n ' cursor: crosshair !important;',\n '}',\n 'html[data-cms-edit-mode] [data-cms-field],',\n 'html[data-cms-edit-mode] [data-cms-entry-field] {',\n ' cursor: pointer !important;',\n ' outline: 1px dashed rgba(99, 102, 241, 0.5) !important;',\n ' outline-offset: 2px !important;',\n ' transition: outline 0.15s ease-in-out !important;',\n '}',\n 'html[data-cms-edit-mode] [data-cms-field]:hover,',\n 'html[data-cms-edit-mode] [data-cms-entry-field]:hover {',\n ' outline: 2px solid ${chromeTokens.primary} !important;',\n ' outline-offset: 2px !important;',\n '}',\n 'html[data-cms-edit-mode] [data-cms-group] {',\n ' outline: 1px dashed rgba(16, 185, 129, 0.4) !important;',\n ' outline-offset: 3px !important;',\n '}',\n 'html[data-cms-edit-mode] [data-cms-group]:hover {',\n ' outline: 2px solid ${chromeTokens.success} !important;',\n ' outline-offset: 3px !important;',\n '}',\n 'html[data-cms-edit-mode] [data-cms-collection] {',\n ' cursor: pointer !important;',\n ' outline: 1px dashed rgba(251, 191, 36, 0.4) !important;',\n ' outline-offset: 4px !important;',\n ' transition: outline 0.15s ease-in-out !important;',\n '}',\n 'html[data-cms-edit-mode] [data-cms-collection]:hover {',\n ' outline: 2px solid ${chromeTokens.warning} !important;',\n ' outline-offset: 4px !important;',\n '}'\n ].filter(Boolean).join('\\\\n');\n\n var target = document.head || document.documentElement;\n if (target) {\n target.appendChild(style);\n }\n }\n\n function hideDevToolbar() {\n if (!isEmbedded) return;\n ensureBridgeStyles();\n if (typeof document === 'undefined' || !document || typeof document.querySelector !== 'function') return;\n try {\n var tb = document.querySelector(toolbarTag);\n if (tb && tb instanceof HTMLElement) {\n tb.style.setProperty('display', 'none', 'important');\n }\n } catch (_e) {}\n }\n\n ensureBridgeStyles();\n hideDevToolbar();\n\n function inferFieldKind(el) {\n if (!el) return 'unknown';\n var tag = el.tagName ? el.tagName.toLowerCase() : '';\n if (tag === 'img') return 'image';\n if (tag === 'video') return 'video';\n var explicitKind = el.getAttribute('data-cms-kind');\n if (explicitKind) return explicitKind;\n if (el.classList.contains('rich-body') || el.classList.contains('cms-richtext') || el.getAttribute('data-cms-richtext') === 'true') {\n return 'richtext';\n }\n return 'text';\n }\n\n function getElementRect(el) {\n var r = el.getBoundingClientRect();\n return {\n top: r.top,\n left: r.left,\n width: r.width,\n height: r.height\n };\n }\n\n function parseGroupAttr(raw) {\n if (!raw) return undefined;\n var idx = raw.indexOf(':');\n if (idx === -1) return { group: raw, scope: '' };\n return {\n group: raw.slice(0, idx),\n scope: raw.slice(idx + 1)\n };\n }\n\n function scanRenderedFields() {\n var fieldEls = document.querySelectorAll('[data-cms-field], [data-cms-entry-field]');\n var fieldMap = {};\n\n for (var i = 0; i < fieldEls.length; i++) {\n var el = fieldEls[i];\n var key = el.getAttribute('data-cms-field') || el.getAttribute('data-cms-entry-field') || '';\n if (!key) continue;\n\n var isEntry = el.hasAttribute('data-cms-entry-field');\n var groupEl = el.closest('[data-cms-group]');\n var collectionEl = el.closest('[data-cms-collection]');\n var groupName = undefined;\n if (groupEl) {\n var g = parseGroupAttr(groupEl.getAttribute('data-cms-group'));\n if (g) groupName = g.group;\n }\n\n var entryRef = undefined;\n if (isEntry || collectionEl) {\n entryRef = {\n collection: collectionEl ? collectionEl.getAttribute('data-cms-collection') || '' : '',\n slug: collectionEl ? collectionEl.getAttribute('data-cms-entry') || '' : '',\n path: isEntry ? key : key\n };\n }\n\n var uniqueId = (isEntry && entryRef ? entryRef.collection + ':' + entryRef.slug + ':' : '') + key;\n\n if (!fieldMap[uniqueId]) {\n fieldMap[uniqueId] = {\n key: key,\n kind: inferFieldKind(el),\n group: groupName,\n entryRef: entryRef,\n instances: 1\n };\n } else {\n fieldMap[uniqueId].instances++;\n }\n }\n\n var fields = [];\n for (var k in fieldMap) {\n if (Object.prototype.hasOwnProperty.call(fieldMap, k)) {\n fields.push(fieldMap[k]);\n }\n }\n\n window.__CMS_FIELDS__ = fields;\n window.__CMS_RESCAN__ = scanRenderedFields;\n\n try {\n document.dispatchEvent(new CustomEvent('cms:fields-updated', { detail: fields }));\n } catch (_e) {}\n\n postToEditor({\n source: 'cms-preview',\n v: PROTOCOL_VERSION,\n type: 'rendered-fields',\n fields: fields\n });\n }\n\n function debouncedRescan() {\n if (isPatchingDom) return;\n if (debounceRescanTimer) clearTimeout(debounceRescanTimer);\n debounceRescanTimer = setTimeout(function() {\n scanRenderedFields();\n scheduleRectsUpdate();\n }, 150);\n }\n\n var currentObserver = null;\n function setupMutationObserver() {\n if (typeof MutationObserver === 'undefined' || !document.body) return;\n if (currentObserver) {\n try {\n currentObserver.disconnect();\n } catch (_e) {}\n }\n currentObserver = new MutationObserver(function(mutations) {\n if (isPatchingDom) return;\n hideDevToolbar();\n debouncedRescan();\n });\n currentObserver.observe(document.body, {\n childList: true,\n subtree: true,\n attributeFilter: ['data-cms-field', 'data-cms-entry-field', 'data-cms-group', 'data-cms-collection', 'data-cms-entry']\n });\n }\n\n function buildStableSelector(target) {\n if (!target || !target.tagName) return '';\n if (target === document.documentElement) return 'html';\n if (target === document.body) return 'body';\n\n var parts = [];\n var curr = target;\n var maxLevels = 8;\n\n while (curr && curr !== document.documentElement && parts.length < maxLevels) {\n if (curr === document.body) {\n parts.unshift('body');\n break;\n }\n var id = curr.getAttribute('id');\n if (id && id.trim()) {\n var escapedId = (typeof CSS !== 'undefined' && CSS.escape) ? CSS.escape(id.trim()) : id.trim();\n parts.unshift('#' + escapedId);\n break;\n }\n var tag = curr.tagName ? curr.tagName.toLowerCase() : '';\n if (!tag) break;\n var count = 1;\n var sib = curr.previousElementSibling;\n while (sib) {\n if (sib.tagName && sib.tagName.toLowerCase() === tag) {\n count++;\n }\n sib = sib.previousElementSibling;\n }\n parts.unshift(tag + ':nth-of-type(' + count + ')');\n curr = curr.parentElement;\n }\n\n return parts.join(' > ');\n }\n\n function buildElementLabel(el) {\n if (!el || !el.tagName) return 'element';\n\n var ariaLabel = el.getAttribute('aria-label');\n if (ariaLabel && ariaLabel.trim()) {\n return ariaLabel.trim();\n }\n\n var id = el.getAttribute('id');\n if (id && id.trim()) {\n return '#' + id.trim();\n }\n\n var tag = el.tagName.toLowerCase();\n\n if (tag === 'nav') return 'Navigation';\n if (tag === 'header') return 'Header';\n if (tag === 'footer') return 'Footer';\n if (tag === 'aside') return 'Sidebar';\n if (tag === 'form') return 'Form';\n\n if (tag === 'img') {\n var alt = el.getAttribute('alt');\n if (alt && alt.trim()) return alt.trim();\n return 'img';\n }\n\n if (tag === 'a' || tag === 'button') {\n var text = (el.textContent || '').trim().replace(/\\\\s+/g, ' ');\n if (text) {\n return text.length > 40 ? text.slice(0, 37) + '...' : text;\n }\n return tag;\n }\n\n return tag || 'element';\n }\n\n function buildCandidateEntry(targetEl, clientX, clientY) {\n if (!targetEl || !targetEl.tagName) return null;\n var selector = buildStableSelector(targetEl);\n if (!selector) return null;\n var all = Array.prototype.slice.call(document.querySelectorAll(selector));\n var instance = Math.max(0, all.indexOf(targetEl));\n var hitRect = targetEl.getBoundingClientRect();\n var offsetX = typeof clientX === 'number' ? Math.round(clientX - hitRect.left) : 0;\n var offsetY = typeof clientY === 'number' ? Math.round(clientY - hitRect.top) : 0;\n return {\n selector: selector,\n instance: instance,\n kind: 'element',\n label: buildElementLabel(targetEl),\n offsetX: offsetX,\n offsetY: offsetY,\n rect: getElementRect(targetEl)\n };\n }\n\n function buildAnchorChain(el, clientX, clientY) {\n var chain = [];\n var curr = el;\n while (curr && curr !== document.documentElement && curr !== document.body) {\n var hit = curr.closest('[data-cms-field], [data-cms-entry-field], [data-cms-group], [data-cms-collection][data-cms-entry]');\n if (!hit) break;\n\n var selector = '';\n var kind = 'unknown';\n var label = '';\n\n if (hit.hasAttribute('data-cms-field')) {\n var fieldKey = hit.getAttribute('data-cms-field') || '';\n selector = '[data-cms-field=\"' + fieldKey + '\"]';\n kind = inferFieldKind(hit);\n label = fieldKey;\n } else if (hit.hasAttribute('data-cms-entry-field')) {\n var entryFieldKey = hit.getAttribute('data-cms-entry-field') || '';\n selector = '[data-cms-entry-field=\"' + entryFieldKey + '\"]';\n kind = inferFieldKind(hit);\n label = entryFieldKey;\n } else if (hit.hasAttribute('data-cms-group')) {\n var groupAttr = hit.getAttribute('data-cms-group') || '';\n selector = '[data-cms-group=\"' + groupAttr + '\"]';\n kind = 'group';\n var parsed = parseGroupAttr(groupAttr);\n label = parsed ? parsed.group : groupAttr;\n } else if (hit.hasAttribute('data-cms-collection') && hit.hasAttribute('data-cms-entry')) {\n var col = hit.getAttribute('data-cms-collection') || '';\n var ent = hit.getAttribute('data-cms-entry') || '';\n selector = '[data-cms-collection=\"' + col + '\"][data-cms-entry=\"' + ent + '\"]';\n kind = 'entry';\n label = col + '/' + ent;\n }\n\n if (selector) {\n var all = Array.prototype.slice.call(document.querySelectorAll(selector));\n var instance = Math.max(0, all.indexOf(hit));\n var hitRect = hit.getBoundingClientRect();\n var offsetX = typeof clientX === 'number' ? Math.round(clientX - hitRect.left) : 0;\n var offsetY = typeof clientY === 'number' ? Math.round(clientY - hitRect.top) : 0;\n chain.push({\n selector: selector,\n instance: instance,\n kind: kind,\n label: label,\n offsetX: offsetX,\n offsetY: offsetY,\n rect: getElementRect(hit)\n });\n }\n\n curr = hit.parentElement;\n }\n\n if (chain.length > 0) {\n return chain;\n }\n\n if (!el || !el.tagName) return chain;\n\n var interactiveEl = el.closest ? el.closest('a, button') : null;\n var selfEl = interactiveEl || (el.closest ? el.closest('a, button, nav, header, footer, aside, main, section, article, form, img, svg, [role]') : null) || el;\n var landmarkEl = selfEl.closest ? selfEl.closest('nav, header, footer, aside, main, section, article, form, [role=\"navigation\"], [role=\"banner\"], [role=\"contentinfo\"]') : null;\n\n var selfEntry = buildCandidateEntry(selfEl, clientX, clientY);\n if (selfEntry) {\n chain.push(selfEntry);\n }\n\n if (landmarkEl && landmarkEl !== selfEl) {\n var landmarkEntry = buildCandidateEntry(landmarkEl, clientX, clientY);\n if (landmarkEntry) {\n chain.push(landmarkEntry);\n }\n }\n\n return chain;\n }\n\n function resolveAnchorEl(anchor) {\n if (!anchor || !anchor.selector) return null;\n try {\n var els = document.querySelectorAll(anchor.selector);\n if (!els || els.length === 0) return null;\n var inst = typeof anchor.instance === 'number' ? anchor.instance : 0;\n if (inst >= 0 && inst < els.length) return els[inst];\n return els[0];\n } catch (_e) {\n return null;\n }\n }\n\n function scheduleRectsUpdate() {\n if (rafScheduled) return;\n rafScheduled = true;\n requestAnimationFrame(function() {\n rafScheduled = false;\n var rects = {};\n if (activeKey) {\n var el = document.querySelector('[data-cms-field=\"' + activeKey + '\"], [data-cms-entry-field=\"' + activeKey + '\"]');\n if (el) {\n rects[activeKey] = getElementRect(el);\n }\n }\n postToEditor({\n source: 'cms-preview',\n v: PROTOCOL_VERSION,\n type: 'rects-update',\n rects: rects,\n scrollY: window.scrollY || window.pageYOffset || 0\n });\n\n if (watchedAnchors && watchedAnchors.length > 0) {\n var anchorRects = {};\n for (var a = 0; a < watchedAnchors.length; a++) {\n var wAnchor = watchedAnchors[a];\n var resolvedEl = resolveAnchorEl(wAnchor);\n if (resolvedEl) {\n anchorRects[wAnchor.id] = getElementRect(resolvedEl);\n } else {\n anchorRects[wAnchor.id] = null;\n }\n }\n postToEditor({\n source: 'cms-preview',\n v: PROTOCOL_VERSION,\n type: 'anchor-rects',\n rects: anchorRects\n });\n }\n });\n }\n\n // Click handler\n document.addEventListener('click', function(e) {\n if (document.documentElement.hasAttribute('data-cms-comment-mode')) {\n e.preventDefault();\n e.stopPropagation();\n var target = e.target;\n if (!target || !(target instanceof Element)) return;\n\n var docWidth = Math.max(\n document.documentElement.scrollWidth || 0,\n document.body ? document.body.scrollWidth : 0,\n window.innerWidth || 0\n );\n var docHeight = Math.max(\n document.documentElement.scrollHeight || 0,\n document.body ? document.body.scrollHeight : 0,\n window.innerHeight || 0\n );\n var pageX = e.pageX !== undefined ? e.pageX : (e.clientX + (window.scrollX || window.pageXOffset || 0));\n var pageY = e.pageY !== undefined ? e.pageY : (e.clientY + (window.scrollY || window.pageYOffset || 0));\n var pageXPct = docWidth > 0 ? Math.round((pageX / docWidth) * 10000) / 100 : 0;\n var pageYPct = docHeight > 0 ? Math.round((pageY / docHeight) * 10000) / 100 : 0;\n\n var chain = buildAnchorChain(target, e.clientX, e.clientY);\n var clickRect = chain.length > 0 ? chain[0].rect : {\n top: e.clientY,\n left: e.clientX,\n width: 0,\n height: 0\n };\n\n postToEditor({\n source: 'cms-preview',\n v: PROTOCOL_VERSION,\n type: 'comment-click',\n chain: chain,\n point: { pageXPct: pageXPct, pageYPct: pageYPct },\n rect: clickRect\n });\n return;\n }\n\n if (!document.documentElement.hasAttribute('data-cms-edit-mode')) return;\n var target = e.target;\n if (!target || !(target instanceof Element)) return;\n\n var fieldEl = target.closest('[data-cms-field], [data-cms-entry-field]');\n var groupEl = target.closest('[data-cms-group]');\n\n if (fieldEl) {\n e.preventDefault();\n e.stopPropagation();\n\n var isEntry = fieldEl.hasAttribute('data-cms-entry-field');\n var key = fieldEl.getAttribute('data-cms-field') || fieldEl.getAttribute('data-cms-entry-field') || '';\n var kind = inferFieldKind(fieldEl);\n var rect = getElementRect(fieldEl);\n activeKey = key;\n\n var selector = isEntry ? '[data-cms-entry-field=\"' + key + '\"]' : '[data-cms-field=\"' + key + '\"]';\n var all = Array.prototype.slice.call(document.querySelectorAll(selector));\n var instance = Math.max(0, all.indexOf(fieldEl));\n\n var collectionEl = fieldEl.closest('[data-cms-collection]');\n var entryRef = (isEntry || collectionEl) ? {\n collection: collectionEl ? collectionEl.getAttribute('data-cms-collection') || '' : '',\n slug: collectionEl ? collectionEl.getAttribute('data-cms-entry') || '' : '',\n path: isEntry ? key : key\n } : undefined;\n\n var groupPath = groupEl ? parseGroupAttr(groupEl.getAttribute('data-cms-group')) : undefined;\n\n try {\n document.dispatchEvent(new CustomEvent('cms:field-selected', {\n detail: {\n key: key,\n kind: kind,\n entryRef: entryRef,\n groupPath: groupPath\n }\n }));\n } catch (_e) {}\n\n postToEditor({\n source: 'cms-preview',\n v: PROTOCOL_VERSION,\n type: 'field-click',\n key: key,\n kind: kind,\n rect: rect,\n instance: instance,\n entryRef: entryRef,\n groupPath: groupPath\n });\n return;\n }\n\n if (groupEl) {\n e.preventDefault();\n e.stopPropagation();\n\n var g = parseGroupAttr(groupEl.getAttribute('data-cms-group'));\n if (g) {\n var gRect = getElementRect(groupEl);\n postToEditor({\n source: 'cms-preview',\n v: PROTOCOL_VERSION,\n type: 'group-click',\n group: g.group,\n scope: g.scope,\n rect: gRect\n });\n }\n return;\n }\n\n var collectionEl = target.closest('[data-cms-collection]');\n if (collectionEl) {\n e.preventDefault();\n e.stopPropagation();\n\n var collKey = collectionEl.getAttribute('data-cms-collection') || '';\n var entryEl = target.closest('[data-cms-entry]');\n var slug = collectionEl.getAttribute('data-cms-entry') || (entryEl ? entryEl.getAttribute('data-cms-entry') : null) || undefined;\n var cRect = getElementRect(collectionEl);\n\n postToEditor({\n source: 'cms-preview',\n v: PROTOCOL_VERSION,\n type: 'collection-click',\n collection: collKey,\n slug: slug,\n rect: cRect\n });\n return;\n }\n }, true);\n\n // Message handler\n window.addEventListener('message', function(e) {\n var data = e.data;\n if (!data || typeof data !== 'object') return;\n if (data.source !== 'cms-editor') return;\n\n if (data.type === 'hello') {\n if (!isOriginAllowed(e.origin)) return;\n connectedOrigin = e.origin;\n connectedSource = e.source;\n\n postToEditor({\n source: 'cms-preview',\n v: PROTOCOL_VERSION,\n type: 'ready',\n protocolVersion: PROTOCOL_VERSION,\n capabilities: ['comments', 'collection-click']\n });\n\n scanRenderedFields();\n return;\n }\n\n if (!connectedOrigin || e.origin !== connectedOrigin) return;\n\n if (data.type === 'highlight-mode') {\n if (data.on) {\n document.documentElement.setAttribute('data-cms-edit-mode', 'true');\n } else {\n document.documentElement.removeAttribute('data-cms-edit-mode');\n }\n return;\n }\n\n if (data.type === 'comment-mode') {\n if (data.on) {\n document.documentElement.setAttribute('data-cms-comment-mode', 'true');\n } else {\n document.documentElement.removeAttribute('data-cms-comment-mode');\n }\n return;\n }\n\n if (data.type === 'watch-anchors') {\n watchedAnchors = Array.isArray(data.anchors) ? data.anchors : [];\n scheduleRectsUpdate();\n return;\n }\n\n if (data.type === 'scroll-to-anchor') {\n var sId = data.id;\n var targetItem = null;\n for (var si = 0; si < watchedAnchors.length; si++) {\n if (watchedAnchors[si].id === sId) {\n targetItem = watchedAnchors[si];\n break;\n }\n }\n if (targetItem) {\n var elToScroll = resolveAnchorEl(targetItem);\n if (elToScroll) {\n elToScroll.scrollIntoView({ behavior: 'smooth', block: 'center' });\n scheduleRectsUpdate();\n }\n }\n return;\n }\n\n if (data.type === 'patch') {\n isPatchingDom = true;\n var patchKey = data.key;\n var patchKind = data.kind;\n var patchVal = data.value;\n var patchEntry = data.entryRef;\n\n var patchSelector;\n var fPath = patchEntry && patchEntry.path ? patchEntry.path : patchKey;\n if (patchEntry && (patchEntry.collection || patchEntry.slug)) {\n var colAttr = patchEntry.collection ? '[data-cms-collection=\"' + patchEntry.collection + '\"]' : '';\n var entryAttr = patchEntry.slug ? '[data-cms-entry=\"' + patchEntry.slug + '\"]' : '';\n var scopeSel = colAttr + entryAttr;\n patchSelector = scopeSel + ' [data-cms-entry-field=\"' + fPath + '\"], ' +\n scopeSel + '[data-cms-entry-field=\"' + fPath + '\"]';\n } else if (patchEntry) {\n patchSelector = '[data-cms-entry-field=\"' + fPath + '\"]';\n } else {\n patchSelector = '[data-cms-field=\"' + patchKey + '\"]';\n }\n\n var matchingEls = document.querySelectorAll(patchSelector);\n for (var j = 0; j < matchingEls.length; j++) {\n var mEl = matchingEls[j];\n var isStructured = patchKind === 'geo.area' || patchKind === 'geoArea' ||\n patchKind === 'address' || patchKind === 'address.list' ||\n patchKind === 'media.videoList' || patchKind === 'videoList' ||\n mEl.getAttribute('data-cms-kind') === 'geo.area' ||\n mEl.getAttribute('data-cms-kind') === 'address.list' ||\n mEl.getAttribute('data-cms-kind') === 'media.videoList';\n\n if (patchKind === 'image' || mEl.tagName.toLowerCase() === 'img') {\n if (patchVal && typeof patchVal === 'object') {\n if (patchVal.url) mEl.setAttribute('src', patchVal.url);\n if (patchVal.alt !== undefined) mEl.setAttribute('alt', patchVal.alt);\n } else if (typeof patchVal === 'string') {\n mEl.setAttribute('src', patchVal);\n }\n } else if (patchKind === 'video' || mEl.tagName.toLowerCase() === 'video') {\n if (patchVal && typeof patchVal === 'object') {\n if (patchVal.url) mEl.setAttribute('src', patchVal.url);\n if (patchVal.poster !== undefined) mEl.setAttribute('poster', patchVal.poster);\n } else if (typeof patchVal === 'string') {\n mEl.setAttribute('src', patchVal);\n }\n if (typeof mEl.load === 'function') mEl.load();\n } else if (isStructured || (patchVal && typeof patchVal === 'object')) {\n // Structured non-image field values (e.g. videoList, geoArea, address) cannot be rendered\n // via simple textContent replacement without producing [object Object].\n // Skip the text write and leave server-rendered markup intact; structured fields refresh via reload.\n } else {\n mEl.textContent = patchVal !== null && patchVal !== undefined ? String(patchVal) : '';\n }\n }\n\n isPatchingDom = false;\n scanRenderedFields();\n scheduleRectsUpdate();\n return;\n }\n\n if (data.type === 'scroll-to') {\n var scrollKey = data.key;\n var scrollInstance = typeof data.instance === 'number' ? data.instance : 0;\n var scrollEls = document.querySelectorAll('[data-cms-field=\"' + scrollKey + '\"], [data-cms-entry-field=\"' + scrollKey + '\"]');\n if (scrollEls.length > scrollInstance) {\n scrollEls[scrollInstance].scrollIntoView({ behavior: 'smooth', block: 'center' });\n activeKey = scrollKey;\n scheduleRectsUpdate();\n }\n return;\n }\n\n if (data.type === 'reload') {\n window.location.reload();\n return;\n }\n });\n\n function handlePageTransition() {\n hideDevToolbar();\n scanRenderedFields();\n setupMutationObserver();\n }\n\n window.addEventListener('scroll', scheduleRectsUpdate, { passive: true });\n window.addEventListener('resize', scheduleRectsUpdate, { passive: true });\n\n document.addEventListener('astro:page-load', handlePageTransition);\n document.addEventListener('astro:after-swap', handlePageTransition);\n window.addEventListener('popstate', handlePageTransition);\n\n if (document.readyState === 'loading') {\n document.addEventListener('DOMContentLoaded', function() {\n handlePageTransition();\n });\n } else {\n handlePageTransition();\n }\n})();`;\n}\n","import { createCmsClient, getClient } from '../client';\nimport { buildBridgeScript } from '../preview/bridge-script';\nimport { isDraftMode, runWithDraftBundle, setActiveDraftBundle } from '../runtime/store';\nimport type { CmsClient, ContentBundle } from '../types';\n\nexport interface PreviewMiddlewareOptions {\n client?: CmsClient;\n siteId?: string;\n contentUrl?: string;\n /** @deprecated Site hosts no longer verify preview tokens. Ignored outside astro dev. */\n previewSecret?: string;\n editorOrigins?: string[];\n}\n\ninterface PreviewContextLocals {\n __cms_is_draft?: boolean;\n __cms_draft_bundle?: ContentBundle;\n [key: string]: unknown;\n}\n\nexport interface PreviewMiddlewareContext {\n request: Request;\n url?: URL;\n locals?: PreviewContextLocals;\n rewrite?: (path: string) => Promise<Response> | undefined;\n}\n\nexport function createPreviewMiddleware(options: PreviewMiddlewareOptions = {}) {\n let client = options.client;\n\n return async (\n context: PreviewMiddlewareContext,\n next: () => Promise<Response>,\n ): Promise<Response> => {\n const globalWithCms = globalThis as typeof globalThis & {\n __CMS_IS_REWRITING__?: boolean;\n };\n\n // If already running within an active draft bundle context or internal rewrite, pass through\n if (\n (typeof globalThis !== 'undefined' && globalWithCms.__CMS_IS_REWRITING__) ||\n isDraftMode() ||\n context.locals?.__cms_is_draft\n ) {\n return next();\n }\n\n const rawUrl = context.url;\n const url =\n rawUrl && typeof rawUrl.href === 'string'\n ? new URL(rawUrl.href)\n : rawUrl && typeof (rawUrl as unknown as { pathname?: string }).pathname === 'string'\n ? rawUrl\n : new URL(context.request?.url || '/', 'http://localhost');\n const pathname = url.pathname || '/';\n const isPreviewRoute = pathname === '/_preview' || pathname.startsWith('/_preview/');\n\n const previewToken =\n (rawUrl?.searchParams?.get ? rawUrl.searchParams.get('preview_token') : null) ||\n (url?.searchParams?.get ? url.searchParams.get('preview_token') : null) ||\n (context.request?.headers?.get ? context.request.headers.get('x-preview-token') : null);\n\n if (!isPreviewRoute && !previewToken) {\n return next();\n }\n\n if (!client) {\n client = getClient() || undefined;\n }\n\n if (!client) {\n const metaEnv = (import.meta as unknown as { env?: Record<string, string | undefined> }).env;\n const siteId =\n options.siteId ||\n (typeof process !== 'undefined' && process.env?.CMS_SITE_ID) ||\n (typeof import.meta !== 'undefined' && metaEnv?.CMS_SITE_ID) ||\n '';\n const contentUrl =\n options.contentUrl ||\n (typeof process !== 'undefined' && process.env?.CMS_CONTENT_URL) ||\n (typeof import.meta !== 'undefined' && metaEnv?.CMS_CONTENT_URL) ||\n '';\n if (siteId && contentUrl) {\n client = createCmsClient({\n siteId,\n contentUrl,\n });\n }\n }\n\n if (!previewToken) {\n return new Response('Preview token is missing', {\n status: 400,\n headers: {\n 'Cache-Control': 'private, no-store',\n 'X-Robots-Tag': 'noindex, nofollow',\n },\n });\n }\n\n if (!client) {\n return new Response('CMS client is missing or not configured', {\n status: 500,\n headers: {\n 'Cache-Control': 'private, no-store',\n 'X-Robots-Tag': 'noindex, nofollow',\n },\n });\n }\n\n let draftBundle: ContentBundle;\n try {\n draftBundle = await client.getBundle({ previewToken });\n } catch (err) {\n const status = (err as { status?: number })?.status;\n if (status === 401 || status === 403 || status === 404) {\n return new Response('Preview token is not valid for this site', {\n status: 404,\n headers: {\n 'Cache-Control': 'private, no-store',\n 'X-Robots-Tag': 'noindex, nofollow',\n },\n });\n }\n\n console.error(err);\n return new Response('Failed to load preview content', {\n status: 502,\n headers: {\n 'Cache-Control': 'private, no-store',\n 'X-Robots-Tag': 'noindex, nofollow',\n },\n });\n }\n\n // Run downstream request within the draft bundle context\n if (context.locals) {\n context.locals.__cms_is_draft = true;\n context.locals.__cms_draft_bundle = draftBundle;\n }\n\n let finalResponse: Response;\n setActiveDraftBundle(draftBundle);\n try {\n finalResponse = await runWithDraftBundle(draftBundle, async () => {\n let response: Response;\n if (isPreviewRoute) {\n const basePath = pathname.replace(/^\\/_preview/, '') || '/';\n if (typeof context.rewrite === 'function') {\n if (typeof globalThis !== 'undefined') {\n globalWithCms.__CMS_IS_REWRITING__ = true;\n }\n try {\n const rewritten = await context.rewrite(basePath);\n if (rewritten) {\n response = rewritten as Response;\n } else {\n response = await next();\n }\n } finally {\n if (typeof globalThis !== 'undefined') {\n globalWithCms.__CMS_IS_REWRITING__ = false;\n }\n }\n } else {\n response = await next();\n }\n } else {\n response = await next();\n }\n\n const contentType = response?.headers?.get ? response.headers.get('content-type') : '';\n const isStaticAsset = Boolean(\n pathname.match(/\\.(js|css|png|jpg|jpeg|gif|svg|ico|webp|woff|woff2|ttf|json|map)$/i),\n );\n const isHtml =\n (typeof contentType === 'string' && contentType.includes('text/html')) ||\n (!contentType && !isStaticAsset);\n\n if (isHtml) {\n const html = await response.text();\n const bridgeScript = buildBridgeScript({\n editorOrigins: options.editorOrigins,\n });\n const scriptTag = `<script>${bridgeScript}</script>`;\n const modifiedHtml = html.includes('</body>')\n ? html.replace('</body>', `${scriptTag}</body>`)\n : `${html}${scriptTag}`;\n\n const newHeaders = new Headers(response.headers);\n if (!newHeaders.has('content-type')) {\n newHeaders.set('content-type', 'text/html; charset=utf-8');\n }\n newHeaders.delete('content-length');\n newHeaders.set('Cache-Control', 'private, no-store, no-cache, must-revalidate');\n newHeaders.set('X-Robots-Tag', 'noindex, nofollow');\n\n return new Response(modifiedHtml, {\n status: response.status,\n statusText: response.statusText,\n headers: newHeaders,\n });\n }\n\n const nonHtmlHeaders = new Headers(response.headers);\n nonHtmlHeaders.set('Cache-Control', 'private, no-store, no-cache, must-revalidate');\n nonHtmlHeaders.set('X-Robots-Tag', 'noindex, nofollow');\n return new Response(response.body, {\n status: response.status,\n statusText: response.statusText,\n headers: nonHtmlHeaders,\n });\n });\n } finally {\n setActiveDraftBundle(null);\n }\n\n return finalResponse;\n };\n}\n"]}
@@ -1,4 +1,4 @@
1
- import { getJwtSecret } from './chunk-B4YYLS7Y.js';
1
+ import { getJwtSecret } from './chunk-4KOHZWCL.js';
2
2
 
3
3
  // src/jwt.ts
4
4
  function base64UrlEncode(data) {
@@ -122,5 +122,5 @@ async function mintDevPreviewToken(siteId, previewSecret) {
122
122
  }
123
123
 
124
124
  export { DEV_PREVIEW_TOKEN_TTL_SECONDS, mintDevPreviewToken, signPreviewToken, verifyPreviewToken };
125
- //# sourceMappingURL=chunk-7LMUFCWX.js.map
126
- //# sourceMappingURL=chunk-7LMUFCWX.js.map
125
+ //# sourceMappingURL=chunk-AUGWPP5U.js.map
126
+ //# sourceMappingURL=chunk-AUGWPP5U.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/jwt.ts","../src/dev/preview-token.ts"],"names":[],"mappings":"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","file":"chunk-7LMUFCWX.js","sourcesContent":["import type { PreviewTokenPayload, VerifyTokenResult } from './types';\n\n// Base64url encoding and decoding helpers using standard Web APIs\nfunction base64UrlEncode(data: Uint8Array | string): string {\n let bytes: Uint8Array;\n if (typeof data === 'string') {\n bytes = new TextEncoder().encode(data);\n } else {\n bytes = data;\n }\n\n let binary = '';\n for (let i = 0; i < bytes.byteLength; i++) {\n binary += String.fromCharCode(bytes[i]);\n }\n const base64 = btoa(binary);\n return base64.replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=+$/, '');\n}\n\nfunction base64UrlDecode(str: string): Uint8Array {\n let base64 = str.replace(/-/g, '+').replace(/_/g, '/');\n while (base64.length % 4 !== 0) {\n base64 += '=';\n }\n const binary = atob(base64);\n const bytes = new Uint8Array(binary.length);\n for (let i = 0; i < binary.length; i++) {\n bytes[i] = binary.charCodeAt(i);\n }\n return bytes;\n}\n\nfunction base64UrlDecodeToString(str: string): string {\n const bytes = base64UrlDecode(str);\n return new TextDecoder().decode(bytes);\n}\n\nasync function getHmacKey(secret: string, usage: 'sign' | 'verify'): Promise<CryptoKey> {\n const enc = new TextEncoder();\n return crypto.subtle.importKey(\n 'raw',\n enc.encode(secret),\n { name: 'HMAC', hash: 'SHA-256' },\n false,\n [usage],\n );\n}\n\n/**\n * Signs a payload with HS256 using standard Web Crypto API.\n */\nexport async function signPreviewToken(\n payload: Record<string, unknown>,\n secret: string,\n): Promise<string> {\n const header = { alg: 'HS256', typ: 'JWT' };\n const encodedHeader = base64UrlEncode(JSON.stringify(header));\n const encodedPayload = base64UrlEncode(JSON.stringify(payload));\n const data = new TextEncoder().encode(`${encodedHeader}.${encodedPayload}`);\n\n const key = await getHmacKey(secret, 'sign');\n const signature = await crypto.subtle.sign('HMAC', key, data);\n const encodedSignature = base64UrlEncode(new Uint8Array(signature));\n\n return `${encodedHeader}.${encodedPayload}.${encodedSignature}`;\n}\n\n/**\n * Locally verifies a signed JWT token against a shared secret using standard Web Crypto API.\n * Never performs network requests.\n */\nexport async function verifyPreviewToken(\n token: string | null | undefined,\n secret: string | undefined,\n expectedSiteId?: string,\n): Promise<VerifyTokenResult> {\n if (!token || typeof token !== 'string') {\n return { valid: false, error: 'Preview token is missing or empty' };\n }\n\n if (!secret || typeof secret !== 'string') {\n return { valid: false, error: 'Preview token secret is not configured' };\n }\n\n const parts = token.trim().split('.');\n if (parts.length !== 3) {\n return { valid: false, error: 'Invalid JWT structure' };\n }\n\n const [encodedHeader, encodedPayload, encodedSignature] = parts;\n\n try {\n // 1. Verify signature with SubtleCrypto\n const key = await getHmacKey(secret, 'verify');\n const data = new TextEncoder().encode(`${encodedHeader}.${encodedPayload}`);\n const signatureBytes = base64UrlDecode(encodedSignature);\n\n const isSigValid = await crypto.subtle.verify(\n 'HMAC',\n key,\n signatureBytes as unknown as BufferSource,\n data as unknown as BufferSource,\n );\n if (!isSigValid) {\n return { valid: false, error: 'Invalid token signature' };\n }\n\n // 2. Decode and parse payload\n const payloadJson = base64UrlDecodeToString(encodedPayload);\n const payload = JSON.parse(payloadJson) as PreviewTokenPayload;\n\n // 3. Verify expiration\n const now = Math.floor(Date.now() / 1000);\n if (typeof payload.exp === 'number' && payload.exp < now) {\n return { valid: false, error: 'Preview token has expired' };\n }\n\n // 4. Verify site scope if specified; fail closed when the payload has no site_id\n if (expectedSiteId && payload.site_id !== expectedSiteId) {\n return {\n valid: false,\n error: `Preview token site_id (${payload.site_id}) does not match expected site_id (${expectedSiteId})`,\n };\n }\n\n return { valid: true, payload };\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n return { valid: false, error: `Failed to verify preview token: ${msg}` };\n }\n}\n","import { getJwtSecret } from '@407dev/config';\nimport { signPreviewToken } from '../jwt';\n\nexport const DEV_PREVIEW_TOKEN_TTL_SECONDS = 60 * 60 * 12;\n\n/** Self-mints a preview token for dev-mode draft reads using the shared preview secret. */\nexport async function mintDevPreviewToken(\n siteId: string,\n previewSecret: string | undefined,\n): Promise<string | null> {\n const secret =\n previewSecret ||\n (typeof process !== 'undefined'\n ? process.env?.CMS_PREVIEW_SECRET || process.env?.JWT_SECRET\n : undefined) ||\n (() => {\n try {\n return getJwtSecret();\n } catch {\n return undefined;\n }\n })();\n\n if (!secret || !siteId) {\n return null;\n }\n\n const now = Math.floor(Date.now() / 1000);\n return signPreviewToken(\n {\n site_id: siteId,\n sub: 'astro-dev',\n scope: 'cms:preview',\n iat: now,\n exp: now + DEV_PREVIEW_TOKEN_TTL_SECONDS,\n },\n secret,\n );\n}\n"]}
1
+ {"version":3,"sources":["../src/jwt.ts","../src/dev/preview-token.ts"],"names":[],"mappings":"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","file":"chunk-AUGWPP5U.js","sourcesContent":["import type { PreviewTokenPayload, VerifyTokenResult } from './types';\n\n// Base64url encoding and decoding helpers using standard Web APIs\nfunction base64UrlEncode(data: Uint8Array | string): string {\n let bytes: Uint8Array;\n if (typeof data === 'string') {\n bytes = new TextEncoder().encode(data);\n } else {\n bytes = data;\n }\n\n let binary = '';\n for (let i = 0; i < bytes.byteLength; i++) {\n binary += String.fromCharCode(bytes[i]);\n }\n const base64 = btoa(binary);\n return base64.replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=+$/, '');\n}\n\nfunction base64UrlDecode(str: string): Uint8Array {\n let base64 = str.replace(/-/g, '+').replace(/_/g, '/');\n while (base64.length % 4 !== 0) {\n base64 += '=';\n }\n const binary = atob(base64);\n const bytes = new Uint8Array(binary.length);\n for (let i = 0; i < binary.length; i++) {\n bytes[i] = binary.charCodeAt(i);\n }\n return bytes;\n}\n\nfunction base64UrlDecodeToString(str: string): string {\n const bytes = base64UrlDecode(str);\n return new TextDecoder().decode(bytes);\n}\n\nasync function getHmacKey(secret: string, usage: 'sign' | 'verify'): Promise<CryptoKey> {\n const enc = new TextEncoder();\n return crypto.subtle.importKey(\n 'raw',\n enc.encode(secret),\n { name: 'HMAC', hash: 'SHA-256' },\n false,\n [usage],\n );\n}\n\n/**\n * Signs a payload with HS256 using standard Web Crypto API.\n */\nexport async function signPreviewToken(\n payload: Record<string, unknown>,\n secret: string,\n): Promise<string> {\n const header = { alg: 'HS256', typ: 'JWT' };\n const encodedHeader = base64UrlEncode(JSON.stringify(header));\n const encodedPayload = base64UrlEncode(JSON.stringify(payload));\n const data = new TextEncoder().encode(`${encodedHeader}.${encodedPayload}`);\n\n const key = await getHmacKey(secret, 'sign');\n const signature = await crypto.subtle.sign('HMAC', key, data);\n const encodedSignature = base64UrlEncode(new Uint8Array(signature));\n\n return `${encodedHeader}.${encodedPayload}.${encodedSignature}`;\n}\n\n/**\n * Locally verifies a signed JWT token against a shared secret using standard Web Crypto API.\n * Never performs network requests.\n */\nexport async function verifyPreviewToken(\n token: string | null | undefined,\n secret: string | undefined,\n expectedSiteId?: string,\n): Promise<VerifyTokenResult> {\n if (!token || typeof token !== 'string') {\n return { valid: false, error: 'Preview token is missing or empty' };\n }\n\n if (!secret || typeof secret !== 'string') {\n return { valid: false, error: 'Preview token secret is not configured' };\n }\n\n const parts = token.trim().split('.');\n if (parts.length !== 3) {\n return { valid: false, error: 'Invalid JWT structure' };\n }\n\n const [encodedHeader, encodedPayload, encodedSignature] = parts;\n\n try {\n // 1. Verify signature with SubtleCrypto\n const key = await getHmacKey(secret, 'verify');\n const data = new TextEncoder().encode(`${encodedHeader}.${encodedPayload}`);\n const signatureBytes = base64UrlDecode(encodedSignature);\n\n const isSigValid = await crypto.subtle.verify(\n 'HMAC',\n key,\n signatureBytes as unknown as BufferSource,\n data as unknown as BufferSource,\n );\n if (!isSigValid) {\n return { valid: false, error: 'Invalid token signature' };\n }\n\n // 2. Decode and parse payload\n const payloadJson = base64UrlDecodeToString(encodedPayload);\n const payload = JSON.parse(payloadJson) as PreviewTokenPayload;\n\n // 3. Verify expiration\n const now = Math.floor(Date.now() / 1000);\n if (typeof payload.exp === 'number' && payload.exp < now) {\n return { valid: false, error: 'Preview token has expired' };\n }\n\n // 4. Verify site scope if specified; fail closed when the payload has no site_id\n if (expectedSiteId && payload.site_id !== expectedSiteId) {\n return {\n valid: false,\n error: `Preview token site_id (${payload.site_id}) does not match expected site_id (${expectedSiteId})`,\n };\n }\n\n return { valid: true, payload };\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n return { valid: false, error: `Failed to verify preview token: ${msg}` };\n }\n}\n","import { getJwtSecret } from '@407dev/config';\nimport { signPreviewToken } from '../jwt';\n\nexport const DEV_PREVIEW_TOKEN_TTL_SECONDS = 60 * 60 * 12;\n\n/** Self-mints a preview token for dev-mode draft reads using the shared preview secret. */\nexport async function mintDevPreviewToken(\n siteId: string,\n previewSecret: string | undefined,\n): Promise<string | null> {\n const secret =\n previewSecret ||\n (typeof process !== 'undefined'\n ? process.env?.CMS_PREVIEW_SECRET || process.env?.JWT_SECRET\n : undefined) ||\n (() => {\n try {\n return getJwtSecret();\n } catch {\n return undefined;\n }\n })();\n\n if (!secret || !siteId) {\n return null;\n }\n\n const now = Math.floor(Date.now() / 1000);\n return signPreviewToken(\n {\n site_id: siteId,\n sub: 'astro-dev',\n scope: 'cms:preview',\n iat: now,\n exp: now + DEV_PREVIEW_TOKEN_TTL_SECONDS,\n },\n secret,\n );\n}\n"]}
package/dist/dev/index.js CHANGED
@@ -1,6 +1,6 @@
1
- import { mintDevPreviewToken } from '../chunk-7LMUFCWX.js';
2
- export { DEV_PREVIEW_TOKEN_TTL_SECONDS, mintDevPreviewToken } from '../chunk-7LMUFCWX.js';
3
- import { DEFAULT_DEV_API_URL } from '../chunk-B4YYLS7Y.js';
1
+ import { mintDevPreviewToken } from '../chunk-AUGWPP5U.js';
2
+ export { DEV_PREVIEW_TOKEN_TTL_SECONDS, mintDevPreviewToken } from '../chunk-AUGWPP5U.js';
3
+ import { DEFAULT_DEV_API_URL } from '../chunk-4KOHZWCL.js';
4
4
  import { updateBundleFieldValue } from '../chunk-DMLOBKYE.js';
5
5
  import { resolveEditorOrigins } from '../chunk-XJPVYMZM.js';
6
6
  import fs from 'fs';
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { a as CmsClientConfig, C as CmsClient, R as RouteSeo, b as CmsSiteConfig, c as CmsAstroOptions, V as VerifyTokenResult, d as ContentBundle, e as CmsRedirect } from './types-NaKJe6Pg.js';
2
2
  export { f as CmsIntegrationOptions, G as GetBundleOptions, P as PreviewTokenPayload } from './types-NaKJe6Pg.js';
3
- import { z } from '@407dev/blocks';
3
+ import { z, CmsAsset } from '@407dev/blocks';
4
4
  export { CmsAsset, z } from '@407dev/blocks';
5
5
  import { C as CollectionHandle, a as CollectionEntry, I as InferEntryContent, D as DefineCollectionOptions, b as CollectionStaticPath, c as DualCallableHelper, G as GroupDefinition, F as FieldScope, d as FieldHelpersMap } from './types-CEYS5Fzc.js';
6
6
  export { B as BoundGroupAccessor, e as FieldComponentProps, f as FieldReadOptions, g as GroupAccessor } from './types-CEYS5Fzc.js';
@@ -157,6 +157,21 @@ interface LinkMarkAttrs {
157
157
  rel?: string;
158
158
  title?: string;
159
159
  }
160
+ /**
161
+ * Props for an image node. `src` is always a renderable URL string; `asset` is set when the stored
162
+ * asset UUID was resolved into a CmsAsset (published snapshots and draft previews), so components
163
+ * can use focal point and dimensions, e.g. `<CmsImage src={asset ?? src} alt={alt} />`.
164
+ */
165
+ interface RichTextImageProps {
166
+ src: string;
167
+ alt: string;
168
+ title?: string;
169
+ width?: number;
170
+ height?: number;
171
+ asset?: CmsAsset;
172
+ }
173
+ /** Normalizes an image node's `src` (URL string or resolved CmsAsset), or null if it has no safe URL. */
174
+ declare function getImageNodeProps(attrs: Record<string, unknown> | undefined): RichTextImageProps | null;
160
175
  /** Parses a richtext value (doc object or JSON string) into a doc root, or null if invalid/empty. */
161
176
  declare function parseRichTextDoc(value: unknown): {
162
177
  type?: string;
@@ -218,4 +233,4 @@ interface SitemapRouteItem {
218
233
  */
219
234
  declare function renderSitemapXml(routes: SitemapRouteItem[], options: RenderSitemapOptions): string;
220
235
 
221
- export { type BuildHeadTagsOptions, CmsAstroOptions, CmsClient, CmsClientConfig, type CmsF, CmsRedirect, CmsSiteConfig, CollectionEntry, CollectionHandle, CollectionStaticPath, ContentBundle, DEFAULT_EDITOR_ORIGINS, DefineCollectionOptions, DualCallableHelper, type EntryScopeAccessor, FieldHelpersMap, FieldScope, type GetPreviewDataOptions, GroupDefinition, type HeadRouteInput, type HeadTag, InferEntryContent, KNOWN_NODES, type LinkMarkAttrs, type PreviewBundleResult, type RenderRobotsOptions, type RenderSitemapOptions, type RichTextNodeShape, type RichTextRenderOptions, RouteSeo, type SitemapRouteItem, VerifyTokenResult, buildHeadTags, bundleReady, clearMissingFieldWarnings, cms, cmsAstro, cmsCollectionAttr, cmsEntryAttr, cmsEntryFieldAttr, cmsFieldAttr, cmsGroupAttr, collectionAttrs, collectionPaths, createCmsClient, createEntryDualCallableHelper, createEntryScope, createScope, defineCollection, defineGroup, entryScope, escapeHtml, f, getActiveBundle, getBuildBundle, getClient, getEntries, getEntry, getLinkMarkAttrs, getMissingFieldWarnings, getPreviewData, initCmsClient, isBundleReady, isDraftMode, markBundleReady, parseRichTextDoc, recordMissingField, renderMarksOnly, renderRedirectsFile, renderRichTextHtml, renderRobotsTxt, renderSitemapXml, resolveEditorOrigins, runWithDraftBundle, setActiveDraftBundle, setBuildBundle, setClient, signPreviewToken, updateBundleFieldValue, verifyPreviewToken };
236
+ export { type BuildHeadTagsOptions, CmsAstroOptions, CmsClient, CmsClientConfig, type CmsF, CmsRedirect, CmsSiteConfig, CollectionEntry, CollectionHandle, CollectionStaticPath, ContentBundle, DEFAULT_EDITOR_ORIGINS, DefineCollectionOptions, DualCallableHelper, type EntryScopeAccessor, FieldHelpersMap, FieldScope, type GetPreviewDataOptions, GroupDefinition, type HeadRouteInput, type HeadTag, InferEntryContent, KNOWN_NODES, type LinkMarkAttrs, type PreviewBundleResult, type RenderRobotsOptions, type RenderSitemapOptions, type RichTextImageProps, type RichTextNodeShape, type RichTextRenderOptions, RouteSeo, type SitemapRouteItem, VerifyTokenResult, buildHeadTags, bundleReady, clearMissingFieldWarnings, cms, cmsAstro, cmsCollectionAttr, cmsEntryAttr, cmsEntryFieldAttr, cmsFieldAttr, cmsGroupAttr, collectionAttrs, collectionPaths, createCmsClient, createEntryDualCallableHelper, createEntryScope, createScope, defineCollection, defineGroup, entryScope, escapeHtml, f, getActiveBundle, getBuildBundle, getClient, getEntries, getEntry, getImageNodeProps, getLinkMarkAttrs, getMissingFieldWarnings, getPreviewData, initCmsClient, isBundleReady, isDraftMode, markBundleReady, parseRichTextDoc, recordMissingField, renderMarksOnly, renderRedirectsFile, renderRichTextHtml, renderRobotsTxt, renderSitemapXml, resolveEditorOrigins, runWithDraftBundle, setActiveDraftBundle, setBuildBundle, setClient, signPreviewToken, updateBundleFieldValue, verifyPreviewToken };
package/dist/index.js CHANGED
@@ -1,16 +1,16 @@
1
1
  export { ALLOWED_IMAGE_FITS, ALLOWED_IMAGE_QUALITIES, CDN_IMAGE_WIDTHS, buildCdnImageUrl, buildSrcSet, isCdnTransformableUrl, snapToAllowedQuality, snapToAllowedWidth } from './chunk-6FH3C4FF.js';
2
- import { mintDevPreviewToken } from './chunk-7LMUFCWX.js';
3
- export { signPreviewToken, verifyPreviewToken } from './chunk-7LMUFCWX.js';
2
+ import { mintDevPreviewToken } from './chunk-AUGWPP5U.js';
3
+ export { signPreviewToken, verifyPreviewToken } from './chunk-AUGWPP5U.js';
4
4
  import { collectionAttrs, collectionPaths, defineCollection, getEntry, getEntries, markBundleReady, cmsEntryAttr, cmsGroupAttr } from './chunk-SGHAANOW.js';
5
5
  export { bundleReady, cmsCollectionAttr, cmsEntryAttr, cmsEntryFieldAttr, cmsFieldAttr, cmsGroupAttr, collectionAttrs, collectionPaths, defineCollection, getEntries, getEntry, isBundleReady, markBundleReady } from './chunk-SGHAANOW.js';
6
- import { initCmsClient, buildBridgeScript, getClient } from './chunk-ZAAWLJPU.js';
7
- export { createCmsClient, createPreviewMiddleware, getClient, initCmsClient, setClient } from './chunk-ZAAWLJPU.js';
8
- import './chunk-B4YYLS7Y.js';
6
+ import { initCmsClient, buildBridgeScript, getClient } from './chunk-4PBDIQNL.js';
7
+ export { createCmsClient, createPreviewMiddleware, getClient, initCmsClient, setClient } from './chunk-4PBDIQNL.js';
8
+ import './chunk-4KOHZWCL.js';
9
9
  import { getActiveBundle, recordMissingField, getMissingFieldWarnings, clearMissingFieldWarnings } from './chunk-DMLOBKYE.js';
10
10
  export { clearMissingFieldWarnings, getActiveBundle, getBuildBundle, getMissingFieldWarnings, isDraftMode, recordMissingField, runWithDraftBundle, setActiveDraftBundle, setBuildBundle, updateBundleFieldValue } from './chunk-DMLOBKYE.js';
11
11
  import './chunk-AIUAT7FF.js';
12
12
  export { DEFAULT_EDITOR_ORIGINS, resolveEditorOrigins } from './chunk-XJPVYMZM.js';
13
- import { listFieldTypes, getFieldType, isValidLinkHref } from '@407dev/field-types';
13
+ import { listFieldTypes, getFieldType, isValidLinkHref, stripUrlControlChars, isAssetUuid, isSafeMediaSrc } from '@407dev/field-types';
14
14
  import { createComponent, spreadAttributes, renderTemplate, markHTMLString } from 'astro/runtime/server/index.js';
15
15
  export { z } from '@407dev/blocks';
16
16
  import fs from 'fs';
@@ -36,6 +36,38 @@ var KNOWN_NODES = /* @__PURE__ */ new Set([
36
36
  "image"
37
37
  ]);
38
38
  var KNOWN_MARKS = /* @__PURE__ */ new Set(["bold", "italic", "underline", "strike", "code", "link"]);
39
+ function toImageUrl(raw) {
40
+ if (typeof raw !== "string") return null;
41
+ const cleaned = stripUrlControlChars(raw);
42
+ if (isAssetUuid(cleaned) || cleaned.startsWith("#")) return null;
43
+ return isSafeMediaSrc(cleaned) ? cleaned : null;
44
+ }
45
+ function isImageAsset(obj) {
46
+ if (typeof obj.id !== "string" || typeof obj.url !== "string") return false;
47
+ if (typeof obj.kind === "string") return obj.kind === "image";
48
+ return typeof obj.mime_type === "string" && obj.mime_type.startsWith("image/");
49
+ }
50
+ function getImageNodeProps(attrs) {
51
+ let rawSrc = attrs?.src;
52
+ let asset;
53
+ if (rawSrc && typeof rawSrc === "object" && !Array.isArray(rawSrc)) {
54
+ const obj = rawSrc;
55
+ if (obj.kind === "url") rawSrc = obj.src;
56
+ else if (obj.kind === "asset") return null;
57
+ else {
58
+ if (!isImageAsset(obj)) return null;
59
+ asset = rawSrc;
60
+ rawSrc = asset.url;
61
+ }
62
+ }
63
+ const src = toImageUrl(rawSrc);
64
+ if (!src) return null;
65
+ const alt = typeof attrs?.alt === "string" && attrs.alt ? attrs.alt : asset?.alt ?? "";
66
+ const title = typeof attrs?.title === "string" && attrs.title ? attrs.title : void 0;
67
+ const width = typeof attrs?.width === "number" ? attrs.width : asset?.width ?? void 0;
68
+ const height = typeof attrs?.height === "number" ? attrs.height : asset?.height ?? void 0;
69
+ return { src, alt, title, width, height, asset };
70
+ }
39
71
  function parseRichTextDoc(value) {
40
72
  if (!value) return null;
41
73
  let parsed = value;
@@ -173,12 +205,12 @@ function renderRichTextHtml(doc, options = {}) {
173
205
  case "horizontalRule":
174
206
  return "<hr />";
175
207
  case "image": {
176
- if (options.components?.image) {
177
- const src = typeof n.attrs?.src === "string" ? escapeHtml(n.attrs.src) : "";
178
- const alt = typeof n.attrs?.alt === "string" ? escapeHtml(n.attrs.alt) : "";
179
- return `<img src="${src}" alt="${alt}" />`;
180
- }
181
- return "";
208
+ const img = getImageNodeProps(n.attrs);
209
+ if (!img) return "";
210
+ const title = img.title ? ` title="${escapeHtml(img.title)}"` : "";
211
+ const width = img.width ? ` width="${img.width}"` : "";
212
+ const height = img.height ? ` height="${img.height}"` : "";
213
+ return `<img src="${escapeHtml(img.src)}" alt="${escapeHtml(img.alt)}"${title}${width}${height} loading="lazy" />`;
182
214
  }
183
215
  default:
184
216
  return children;
@@ -917,6 +949,6 @@ ${urlEntries.join("\n")}
917
949
  `;
918
950
  }
919
951
 
920
- export { KNOWN_NODES, buildHeadTags, cms, cmsAstro, createEntryDualCallableHelper, createEntryScope, createScope, defineGroup, entryScope, escapeHtml, f, getLinkMarkAttrs, getPreviewData, parseRichTextDoc, renderMarksOnly, renderRedirectsFile, renderRichTextHtml, renderRobotsTxt, renderSitemapXml };
952
+ export { KNOWN_NODES, buildHeadTags, cms, cmsAstro, createEntryDualCallableHelper, createEntryScope, createScope, defineGroup, entryScope, escapeHtml, f, getImageNodeProps, getLinkMarkAttrs, getPreviewData, parseRichTextDoc, renderMarksOnly, renderRedirectsFile, renderRichTextHtml, renderRobotsTxt, renderSitemapXml };
921
953
  //# sourceMappingURL=index.js.map
922
954
  //# sourceMappingURL=index.js.map