From f8cbec92009c25fd72c37887bb2bf37f5f5fc41f Mon Sep 17 00:00:00 2001 From: alistairsmith-tech Date: Mon, 10 Aug 2026 15:33:14 +0100 Subject: [PATCH 1/3] fix(PRO-349): support Next 16 and load the browser SDK from js.mcl.io Two independent bugs found while testing the PRO-323 AI install prompts against real apps. @spur.us/monocle-nextjs declared next@^13.5.7 || ^14.2.25 || ^15.2.3, so installing into a Next 16 project failed peer resolution outright. The SDK already worked on Next 16 once installed; the range was just stale. @spur.us/monocle-react loaded the script from mcl.spur.us, which does not match the https://*.mcl.io wildcard that docs.spur.us/monocle/security tells customers to allowlist. A CSP is checked against the host being requested, so anyone following those docs had the SDK silently blocked. Both hosts serve byte-identical payloads and mcl.spur.us already CNAMEs to v1.mcl.io, so this is a rename rather than an infrastructure change. monocle-backend keeps BASE_DOMAIN = mcl.spur.us deliberately: it builds https://decrypt.${baseDomain}, decrypt.mcl.io has no DNS record, and decrypt.mcl.spur.us is what the decryption docs reference. Moving that needs the host provisioned first. Co-Authored-By: Claude Fable 5 --- .changeset/monocle-loader-mcl-io.md | 9 +++++++++ .changeset/monocle-nextjs-next-16.md | 7 +++++++ packages/monocle-nextjs/package.json | 2 +- packages/monocle-react/src/constants.ts | 2 +- packages/monocle-react/src/types.ts | 2 +- pnpm-lock.yaml | 3 ++- 6 files changed, 21 insertions(+), 4 deletions(-) create mode 100644 .changeset/monocle-loader-mcl-io.md create mode 100644 .changeset/monocle-nextjs-next-16.md diff --git a/.changeset/monocle-loader-mcl-io.md b/.changeset/monocle-loader-mcl-io.md new file mode 100644 index 0000000..2e8faa1 --- /dev/null +++ b/.changeset/monocle-loader-mcl-io.md @@ -0,0 +1,9 @@ +--- +"@spur.us/monocle-react": minor +--- + +Load the Monocle script from `js.mcl.io` instead of `mcl.spur.us`. + +The two hosts serve identical payloads, but only `js.mcl.io` matches the Content Security Policy documented at https://docs.spur.us/monocle/security, which asks for `https://*.mcl.io` in `script-src`. Sites with a CSP that followed those docs were getting the SDK silently blocked, because the policy is checked against the host being requested and `mcl.spur.us` does not match the `*.mcl.io` wildcard. + +Pass the `domain` prop to `MonocleProvider` to override the default. diff --git a/.changeset/monocle-nextjs-next-16.md b/.changeset/monocle-nextjs-next-16.md new file mode 100644 index 0000000..89330c2 --- /dev/null +++ b/.changeset/monocle-nextjs-next-16.md @@ -0,0 +1,7 @@ +--- +"@spur.us/monocle-nextjs": minor +--- + +Accept Next.js 16 as a peer dependency. + +The declared range stopped at `^15.2.3`, so installing into a Next 16 project failed peer resolution and needed `--legacy-peer-deps`. The SDK already worked on Next 16 once installed; only the range was out of date. diff --git a/packages/monocle-nextjs/package.json b/packages/monocle-nextjs/package.json index dee0a6d..8a14fa3 100644 --- a/packages/monocle-nextjs/package.json +++ b/packages/monocle-nextjs/package.json @@ -48,7 +48,7 @@ "@spur.us/monocle-react": "workspace:^" }, "peerDependencies": { - "next": "^13.5.7 || ^14.2.25 || ^15.2.3", + "next": "^13.5.7 || ^14.2.25 || ^15.2.3 || ^16.0.0", "react": "catalog:peer-react", "react-dom": "catalog:peer-react" } diff --git a/packages/monocle-react/src/constants.ts b/packages/monocle-react/src/constants.ts index d8104ef..2acf103 100644 --- a/packages/monocle-react/src/constants.ts +++ b/packages/monocle-react/src/constants.ts @@ -1 +1 @@ -export const DOMAIN = 'mcl.spur.us'; +export const DOMAIN = 'js.mcl.io'; diff --git a/packages/monocle-react/src/types.ts b/packages/monocle-react/src/types.ts index b6d1645..2274f60 100644 --- a/packages/monocle-react/src/types.ts +++ b/packages/monocle-react/src/types.ts @@ -14,7 +14,7 @@ export interface MonocleProviderProps { */ publishableKey: string; /** - * Optional base domain for the Monocle API. Defaults to `mcl.spur.us` if not provided + * Optional base domain for the Monocle API. Defaults to `js.mcl.io` if not provided */ domain?: string; /** diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 72fb245..a78fcdd 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -143,7 +143,7 @@ importers: specifier: workspace:^ version: link:../monocle-react next: - specifier: ^13.5.7 || ^14.2.25 || ^15.2.3 + specifier: ^13.5.7 || ^14.2.25 || ^15.2.3 || ^16.0.0 version: 15.3.1(@babel/core@7.26.10)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) react: specifier: catalog:peer-react @@ -1950,6 +1950,7 @@ packages: next@15.3.1: resolution: {integrity: sha512-8+dDV0xNLOgHlyBxP1GwHGVaNXsmp+2NhZEYrXr24GWLHtt27YrBPbPuHvzlhi7kZNYjeJNR93IF5zfFu5UL0g==} engines: {node: ^18.18.0 || ^19.8.0 || >= 20.0.0} + deprecated: This version has a security vulnerability. Please upgrade to a patched version. See https://nextjs.org/blog/CVE-2025-66478 for more details. hasBin: true peerDependencies: '@opentelemetry/api': ^1.1.0 From 5fc8c618eb631cf020d00e256672f74c086a7b5d Mon Sep 17 00:00:00 2001 From: alistairsmith-tech Date: Mon, 10 Aug 2026 20:30:54 +0100 Subject: [PATCH 2/3] docs(PRO-349): lead the changeset with the CSP action for upgraders Anyone currently running the React SDK behind a CSP must have allowlisted mcl.spur.us to get it working, so the upgrade breaks them unless *.mcl.io is allowed too. That belongs at the top of the release note, not buried in the rationale. Co-Authored-By: Claude Fable 5 --- .changeset/monocle-loader-mcl-io.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.changeset/monocle-loader-mcl-io.md b/.changeset/monocle-loader-mcl-io.md index 2e8faa1..72b949a 100644 --- a/.changeset/monocle-loader-mcl-io.md +++ b/.changeset/monocle-loader-mcl-io.md @@ -4,6 +4,8 @@ Load the Monocle script from `js.mcl.io` instead of `mcl.spur.us`. -The two hosts serve identical payloads, but only `js.mcl.io` matches the Content Security Policy documented at https://docs.spur.us/monocle/security, which asks for `https://*.mcl.io` in `script-src`. Sites with a CSP that followed those docs were getting the SDK silently blocked, because the policy is checked against the host being requested and `mcl.spur.us` does not match the `*.mcl.io` wildcard. +**Before upgrading, if your site sets a Content Security Policy, make sure `https://*.mcl.io` is in your `script-src`.** Earlier versions requested `mcl.spur.us`, so a policy that allowlists only that host will block the SDK after this upgrade. The directives Monocle needs are listed at https://docs.spur.us/monocle/security. Sites without a CSP are unaffected and need no changes. -Pass the `domain` prop to `MonocleProvider` to override the default. +The two hosts serve identical payloads, but only `js.mcl.io` matches the `https://*.mcl.io` wildcard that the security docs have always asked for, so a site that followed those docs was previously getting the SDK silently blocked. A CSP is evaluated against the host being requested, and `mcl.spur.us` does not match that wildcard. + +Pass the `domain` prop to `MonocleProvider` to pin a different host. From 34feb43a09ca7270cb96bfd8232430733156fff3 Mon Sep 17 00:00:00 2001 From: alistairsmith-tech Date: Mon, 10 Aug 2026 20:33:56 +0100 Subject: [PATCH 3/3] revert(PRO-349): keep the browser loader on mcl.spur.us Drops the js.mcl.io rename. Every existing CSP user of this SDK must have allowlisted mcl.spur.us to get it working, so changing the requested host breaks them on update unless they also allow *.mcl.io first. Release notes cannot retroactively update a deployed policy, so no amount of documentation makes the upgrade risk-free. The CSP problem is fixed where it actually belongs: the security docs list only *.mcl.io while the SDK requests mcl.spur.us, so the docs get both hosts. That fixes new installs and breaks nobody. This PR is now the Next 16 peer range alone, which is purely additive. Co-Authored-By: Claude Fable 5 --- .changeset/monocle-loader-mcl-io.md | 11 ----------- packages/monocle-react/src/constants.ts | 2 +- packages/monocle-react/src/types.ts | 2 +- 3 files changed, 2 insertions(+), 13 deletions(-) delete mode 100644 .changeset/monocle-loader-mcl-io.md diff --git a/.changeset/monocle-loader-mcl-io.md b/.changeset/monocle-loader-mcl-io.md deleted file mode 100644 index 72b949a..0000000 --- a/.changeset/monocle-loader-mcl-io.md +++ /dev/null @@ -1,11 +0,0 @@ ---- -"@spur.us/monocle-react": minor ---- - -Load the Monocle script from `js.mcl.io` instead of `mcl.spur.us`. - -**Before upgrading, if your site sets a Content Security Policy, make sure `https://*.mcl.io` is in your `script-src`.** Earlier versions requested `mcl.spur.us`, so a policy that allowlists only that host will block the SDK after this upgrade. The directives Monocle needs are listed at https://docs.spur.us/monocle/security. Sites without a CSP are unaffected and need no changes. - -The two hosts serve identical payloads, but only `js.mcl.io` matches the `https://*.mcl.io` wildcard that the security docs have always asked for, so a site that followed those docs was previously getting the SDK silently blocked. A CSP is evaluated against the host being requested, and `mcl.spur.us` does not match that wildcard. - -Pass the `domain` prop to `MonocleProvider` to pin a different host. diff --git a/packages/monocle-react/src/constants.ts b/packages/monocle-react/src/constants.ts index 2acf103..d8104ef 100644 --- a/packages/monocle-react/src/constants.ts +++ b/packages/monocle-react/src/constants.ts @@ -1 +1 @@ -export const DOMAIN = 'js.mcl.io'; +export const DOMAIN = 'mcl.spur.us'; diff --git a/packages/monocle-react/src/types.ts b/packages/monocle-react/src/types.ts index 2274f60..b6d1645 100644 --- a/packages/monocle-react/src/types.ts +++ b/packages/monocle-react/src/types.ts @@ -14,7 +14,7 @@ export interface MonocleProviderProps { */ publishableKey: string; /** - * Optional base domain for the Monocle API. Defaults to `js.mcl.io` if not provided + * Optional base domain for the Monocle API. Defaults to `mcl.spur.us` if not provided */ domain?: string; /**