Loading workspace insights... Statistics interval
7 days30 daysLatest CI Pipeline Executions
d85e8816 📦 Publish SDKs (#4725)
This PR was opened by the [Changesets
release](https://github.com/changesets/action) GitHub action. When
you're ready to do a release, you can merge this and the packages will
be published to npm automatically. If you're not ready to do a release
yet, that's fine, whenever you add more changesets to main, this PR will
be updated.
# Releases
## @builder.io/sdk@6.3.1
### Patch Changes
- 95c6a94: Validate visual editor message origins with exact trusted
hostnames and reject malformed or non-HTTP origins.
## @builder.io/react@9.4.1
### Patch Changes
- 95c6a94: Validate visual editor message origins with exact trusted
hostnames and reject malformed or non-HTTP origins.
- Updated dependencies [95c6a94]
- @builder.io/sdk@6.3.1
## @builder.io/sdk-angular@0.25.6
### Patch Changes
- 95c6a94: Validate visual editor message origins with exact trusted
hostnames and reject malformed or non-HTTP origins.
## @builder.io/sdk-react-nextjs@0.25.6
### Patch Changes
- 95c6a94: Validate visual editor message origins with exact trusted
hostnames and reject malformed or non-HTTP origins.
## @builder.io/sdk-qwik@0.25.6
### Patch Changes
- 95c6a94: Validate visual editor message origins with exact trusted
hostnames and reject malformed or non-HTTP origins.
## @builder.io/sdk-react@5.2.5
### Patch Changes
- 95c6a94: Validate visual editor message origins with exact trusted
hostnames and reject malformed or non-HTTP origins.
## @builder.io/sdk-react-native@5.2.5
### Patch Changes
- 95c6a94: Validate visual editor message origins with exact trusted
hostnames and reject malformed or non-HTTP origins.
## @builder.io/sdk-solid@5.2.5
### Patch Changes
- 95c6a94: Validate visual editor message origins with exact trusted
hostnames and reject malformed or non-HTTP origins.
## @builder.io/sdk-svelte@5.2.5
### Patch Changes
- 95c6a94: Validate visual editor message origins with exact trusted
hostnames and reject malformed or non-HTTP origins.
## @builder.io/sdk-vue@5.2.5
### Patch Changes
- 95c6a94: Validate visual editor message origins with exact trusted
hostnames and reject malformed or non-HTTP origins.
<!-- CURSOR_SUMMARY -->
---
> [!NOTE]
> **Medium Risk**
> Tightens postMessage origin handling in visual editing, which is
security-sensitive; unlikely to break legitimate Builder hosts but could
affect custom `trustedHosts` or unusual preview URLs.
>
> **Overview**
> This is an automated **Changesets release** that publishes patch
versions across Gen1 and Gen2 Builder SDKs. It removes the pending
changeset file and bumps `package.json` versions plus `CHANGELOG.md`
entries for each affected package.
>
> The release ships commit **95c6a94**: **stricter validation of
`postMessage` origins** between hosted sites and the visual editor. SDKs
now require origins to parse as **HTTP/HTTPS**, match **exact trusted
hostnames** (not loose substring checks), and reject malformed or
dangerous schemes (e.g. `javascript:`). Gen1 `@builder.io/sdk` **6.3.1**
and `@builder.io/react` **9.4.1** are included; Gen2 packages (Angular,
Next.js, Qwik, React, React Native, Solid, Svelte, Vue) receive aligned
patch bumps with the same changelog note.
>
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
bbb25adc5137303d207c76805778942a42cfefdb. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> bfaef841 📦 Publish SDKs (#4725)
This PR was opened by the [Changesets
release](https://github.com/changesets/action) GitHub action. When
you're ready to do a release, you can merge this and the packages will
be published to npm automatically. If you're not ready to do a release
yet, that's fine, whenever you add more changesets to main, this PR will
be updated.
# Releases
## @builder.io/sdk@6.3.1
### Patch Changes
- 95c6a94: Validate visual editor message origins with exact trusted
hostnames and reject malformed or non-HTTP origins.
## @builder.io/react@9.4.1
### Patch Changes
- 95c6a94: Validate visual editor message origins with exact trusted
hostnames and reject malformed or non-HTTP origins.
- Updated dependencies [95c6a94]
- @builder.io/sdk@6.3.1
## @builder.io/sdk-angular@0.25.6
### Patch Changes
- 95c6a94: Validate visual editor message origins with exact trusted
hostnames and reject malformed or non-HTTP origins.
## @builder.io/sdk-react-nextjs@0.25.6
### Patch Changes
- 95c6a94: Validate visual editor message origins with exact trusted
hostnames and reject malformed or non-HTTP origins.
## @builder.io/sdk-qwik@0.25.6
### Patch Changes
- 95c6a94: Validate visual editor message origins with exact trusted
hostnames and reject malformed or non-HTTP origins.
## @builder.io/sdk-react@5.2.5
### Patch Changes
- 95c6a94: Validate visual editor message origins with exact trusted
hostnames and reject malformed or non-HTTP origins.
## @builder.io/sdk-react-native@5.2.5
### Patch Changes
- 95c6a94: Validate visual editor message origins with exact trusted
hostnames and reject malformed or non-HTTP origins.
## @builder.io/sdk-solid@5.2.5
### Patch Changes
- 95c6a94: Validate visual editor message origins with exact trusted
hostnames and reject malformed or non-HTTP origins.
## @builder.io/sdk-svelte@5.2.5
### Patch Changes
- 95c6a94: Validate visual editor message origins with exact trusted
hostnames and reject malformed or non-HTTP origins.
## @builder.io/sdk-vue@5.2.5
### Patch Changes
- 95c6a94: Validate visual editor message origins with exact trusted
hostnames and reject malformed or non-HTTP origins.
<!-- CURSOR_SUMMARY -->
---
> [!NOTE]
> **Medium Risk**
> Tightens postMessage origin handling in visual editing, which is
security-sensitive; unlikely to break legitimate Builder hosts but could
affect custom `trustedHosts` or unusual preview URLs.
>
> **Overview**
> This is an automated **Changesets release** that publishes patch
versions across Gen1 and Gen2 Builder SDKs. It removes the pending
changeset file and bumps `package.json` versions plus `CHANGELOG.md`
entries for each affected package.
>
> The release ships commit **95c6a94**: **stricter validation of
`postMessage` origins** between hosted sites and the visual editor. SDKs
now require origins to parse as **HTTP/HTTPS**, match **exact trusted
hostnames** (not loose substring checks), and reject malformed or
dangerous schemes (e.g. `javascript:`). Gen1 `@builder.io/sdk` **6.3.1**
and `@builder.io/react` **9.4.1** are included; Gen2 packages (Angular,
Next.js, Qwik, React, React Native, Solid, Svelte, Vue) receive aligned
patch bumps with the same changelog note.
>
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
bbb25adc5137303d207c76805778942a42cfefdb. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> d85e8816 📦 Publish SDKs (#4725)
This PR was opened by the [Changesets
release](https://github.com/changesets/action) GitHub action. When
you're ready to do a release, you can merge this and the packages will
be published to npm automatically. If you're not ready to do a release
yet, that's fine, whenever you add more changesets to main, this PR will
be updated.
# Releases
## @builder.io/sdk@6.3.1
### Patch Changes
- 95c6a94: Validate visual editor message origins with exact trusted
hostnames and reject malformed or non-HTTP origins.
## @builder.io/react@9.4.1
### Patch Changes
- 95c6a94: Validate visual editor message origins with exact trusted
hostnames and reject malformed or non-HTTP origins.
- Updated dependencies [95c6a94]
- @builder.io/sdk@6.3.1
## @builder.io/sdk-angular@0.25.6
### Patch Changes
- 95c6a94: Validate visual editor message origins with exact trusted
hostnames and reject malformed or non-HTTP origins.
## @builder.io/sdk-react-nextjs@0.25.6
### Patch Changes
- 95c6a94: Validate visual editor message origins with exact trusted
hostnames and reject malformed or non-HTTP origins.
## @builder.io/sdk-qwik@0.25.6
### Patch Changes
- 95c6a94: Validate visual editor message origins with exact trusted
hostnames and reject malformed or non-HTTP origins.
## @builder.io/sdk-react@5.2.5
### Patch Changes
- 95c6a94: Validate visual editor message origins with exact trusted
hostnames and reject malformed or non-HTTP origins.
## @builder.io/sdk-react-native@5.2.5
### Patch Changes
- 95c6a94: Validate visual editor message origins with exact trusted
hostnames and reject malformed or non-HTTP origins.
## @builder.io/sdk-solid@5.2.5
### Patch Changes
- 95c6a94: Validate visual editor message origins with exact trusted
hostnames and reject malformed or non-HTTP origins.
## @builder.io/sdk-svelte@5.2.5
### Patch Changes
- 95c6a94: Validate visual editor message origins with exact trusted
hostnames and reject malformed or non-HTTP origins.
## @builder.io/sdk-vue@5.2.5
### Patch Changes
- 95c6a94: Validate visual editor message origins with exact trusted
hostnames and reject malformed or non-HTTP origins.
<!-- CURSOR_SUMMARY -->
---
> [!NOTE]
> **Medium Risk**
> Tightens postMessage origin handling in visual editing, which is
security-sensitive; unlikely to break legitimate Builder hosts but could
affect custom `trustedHosts` or unusual preview URLs.
>
> **Overview**
> This is an automated **Changesets release** that publishes patch
versions across Gen1 and Gen2 Builder SDKs. It removes the pending
changeset file and bumps `package.json` versions plus `CHANGELOG.md`
entries for each affected package.
>
> The release ships commit **95c6a94**: **stricter validation of
`postMessage` origins** between hosted sites and the visual editor. SDKs
now require origins to parse as **HTTP/HTTPS**, match **exact trusted
hostnames** (not loose substring checks), and reject malformed or
dangerous schemes (e.g. `javascript:`). Gen1 `@builder.io/sdk` **6.3.1**
and `@builder.io/react` **9.4.1** are included; Gen2 packages (Angular,
Next.js, Qwik, React, React Native, Solid, Svelte, Vue) receive aligned
patch bumps with the same changelog note.
>
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
bbb25adc5137303d207c76805778942a42cfefdb. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> d85e8816 📦 Publish SDKs (#4725)
This PR was opened by the [Changesets
release](https://github.com/changesets/action) GitHub action. When
you're ready to do a release, you can merge this and the packages will
be published to npm automatically. If you're not ready to do a release
yet, that's fine, whenever you add more changesets to main, this PR will
be updated.
# Releases
## @builder.io/sdk@6.3.1
### Patch Changes
- 95c6a94: Validate visual editor message origins with exact trusted
hostnames and reject malformed or non-HTTP origins.
## @builder.io/react@9.4.1
### Patch Changes
- 95c6a94: Validate visual editor message origins with exact trusted
hostnames and reject malformed or non-HTTP origins.
- Updated dependencies [95c6a94]
- @builder.io/sdk@6.3.1
## @builder.io/sdk-angular@0.25.6
### Patch Changes
- 95c6a94: Validate visual editor message origins with exact trusted
hostnames and reject malformed or non-HTTP origins.
## @builder.io/sdk-react-nextjs@0.25.6
### Patch Changes
- 95c6a94: Validate visual editor message origins with exact trusted
hostnames and reject malformed or non-HTTP origins.
## @builder.io/sdk-qwik@0.25.6
### Patch Changes
- 95c6a94: Validate visual editor message origins with exact trusted
hostnames and reject malformed or non-HTTP origins.
## @builder.io/sdk-react@5.2.5
### Patch Changes
- 95c6a94: Validate visual editor message origins with exact trusted
hostnames and reject malformed or non-HTTP origins.
## @builder.io/sdk-react-native@5.2.5
### Patch Changes
- 95c6a94: Validate visual editor message origins with exact trusted
hostnames and reject malformed or non-HTTP origins.
## @builder.io/sdk-solid@5.2.5
### Patch Changes
- 95c6a94: Validate visual editor message origins with exact trusted
hostnames and reject malformed or non-HTTP origins.
## @builder.io/sdk-svelte@5.2.5
### Patch Changes
- 95c6a94: Validate visual editor message origins with exact trusted
hostnames and reject malformed or non-HTTP origins.
## @builder.io/sdk-vue@5.2.5
### Patch Changes
- 95c6a94: Validate visual editor message origins with exact trusted
hostnames and reject malformed or non-HTTP origins.
<!-- CURSOR_SUMMARY -->
---
> [!NOTE]
> **Medium Risk**
> Tightens postMessage origin handling in visual editing, which is
security-sensitive; unlikely to break legitimate Builder hosts but could
affect custom `trustedHosts` or unusual preview URLs.
>
> **Overview**
> This is an automated **Changesets release** that publishes patch
versions across Gen1 and Gen2 Builder SDKs. It removes the pending
changeset file and bumps `package.json` versions plus `CHANGELOG.md`
entries for each affected package.
>
> The release ships commit **95c6a94**: **stricter validation of
`postMessage` origins** between hosted sites and the visual editor. SDKs
now require origins to parse as **HTTP/HTTPS**, match **exact trusted
hostnames** (not loose substring checks), and reject malformed or
dangerous schemes (e.g. `javascript:`). Gen1 `@builder.io/sdk` **6.3.1**
and `@builder.io/react` **9.4.1** are included; Gen2 packages (Angular,
Next.js, Qwik, React, React Native, Solid, Svelte, Vue) receive aligned
patch bumps with the same changelog note.
>
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
bbb25adc5137303d207c76805778942a42cfefdb. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> d85e8816 📦 Publish SDKs (#4725)
This PR was opened by the [Changesets
release](https://github.com/changesets/action) GitHub action. When
you're ready to do a release, you can merge this and the packages will
be published to npm automatically. If you're not ready to do a release
yet, that's fine, whenever you add more changesets to main, this PR will
be updated.
# Releases
## @builder.io/sdk@6.3.1
### Patch Changes
- 95c6a94: Validate visual editor message origins with exact trusted
hostnames and reject malformed or non-HTTP origins.
## @builder.io/react@9.4.1
### Patch Changes
- 95c6a94: Validate visual editor message origins with exact trusted
hostnames and reject malformed or non-HTTP origins.
- Updated dependencies [95c6a94]
- @builder.io/sdk@6.3.1
## @builder.io/sdk-angular@0.25.6
### Patch Changes
- 95c6a94: Validate visual editor message origins with exact trusted
hostnames and reject malformed or non-HTTP origins.
## @builder.io/sdk-react-nextjs@0.25.6
### Patch Changes
- 95c6a94: Validate visual editor message origins with exact trusted
hostnames and reject malformed or non-HTTP origins.
## @builder.io/sdk-qwik@0.25.6
### Patch Changes
- 95c6a94: Validate visual editor message origins with exact trusted
hostnames and reject malformed or non-HTTP origins.
## @builder.io/sdk-react@5.2.5
### Patch Changes
- 95c6a94: Validate visual editor message origins with exact trusted
hostnames and reject malformed or non-HTTP origins.
## @builder.io/sdk-react-native@5.2.5
### Patch Changes
- 95c6a94: Validate visual editor message origins with exact trusted
hostnames and reject malformed or non-HTTP origins.
## @builder.io/sdk-solid@5.2.5
### Patch Changes
- 95c6a94: Validate visual editor message origins with exact trusted
hostnames and reject malformed or non-HTTP origins.
## @builder.io/sdk-svelte@5.2.5
### Patch Changes
- 95c6a94: Validate visual editor message origins with exact trusted
hostnames and reject malformed or non-HTTP origins.
## @builder.io/sdk-vue@5.2.5
### Patch Changes
- 95c6a94: Validate visual editor message origins with exact trusted
hostnames and reject malformed or non-HTTP origins.
<!-- CURSOR_SUMMARY -->
---
> [!NOTE]
> **Medium Risk**
> Tightens postMessage origin handling in visual editing, which is
security-sensitive; unlikely to break legitimate Builder hosts but could
affect custom `trustedHosts` or unusual preview URLs.
>
> **Overview**
> This is an automated **Changesets release** that publishes patch
versions across Gen1 and Gen2 Builder SDKs. It removes the pending
changeset file and bumps `package.json` versions plus `CHANGELOG.md`
entries for each affected package.
>
> The release ships commit **95c6a94**: **stricter validation of
`postMessage` origins** between hosted sites and the visual editor. SDKs
now require origins to parse as **HTTP/HTTPS**, match **exact trusted
hostnames** (not loose substring checks), and reject malformed or
dangerous schemes (e.g. `javascript:`). Gen1 `@builder.io/sdk` **6.3.1**
and `@builder.io/react` **9.4.1** are included; Gen2 packages (Angular,
Next.js, Qwik, React, React Native, Solid, Svelte, Vue) receive aligned
patch bumps with the same changelog note.
>
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
bbb25adc5137303d207c76805778942a42cfefdb. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> 95c6a948 Fix origin validation bypass in postMessage trust checks (#4724)
## Description
Fixes a security issue reported by a customer where `postMessage`
origin/referrer validation could be bypassed using spoofed or lookalike
hostnames, potentially allowing untrusted windows to send messages
(including block bindings that get executed as code) to Builder-rendered
pages.
Specifically:
- **`packages/core/src/builder.class.ts`**:
`Builder.isTrustedHostForEvent` previously parsed the origin without
strictly validating the protocol/format, and `Builder.isEditing` used an
unanchored regex (`/builder\.io|localhost:1234/`) against
`document.referrer`, which would match spoofed hostnames like
`evil-builder.io.attacker.com` or `notlocalhost:1234x`. This has been
fixed by:
- Requiring the origin to match `^https?:\/\//i` before parsing.
- Validating the parsed protocol is `http:`/`https:` and the hostname is
trusted via `Builder.isTrustedHost`.
- Replacing the unanchored regex check in `isEditing` with a call to
`Builder.isTrustedHostForEvent`, reusing the same validated logic.
- **`packages/react/src/components/builder-block.component.tsx`**:
`BuilderBlock.onWindowMessage` did not validate the message origin at
all, unlike `BuilderContent.onWindowMessage`. Added an origin check
using `Builder.isTrustedHostForEvent(event)` at the top of the handler,
returning early if the origin isn't trusted, matching the existing
pattern used by `BuilderContent`.
- **`packages/sdks/src/functions/is-from-trusted-host.ts`**:
`isFromTrustedHost` used `startsWith('http')`/`startsWith('https')`
checks and did not guard against malformed URLs throwing during `new
URL(...)`. Updated to safely parse the URL in a try/catch, return
`false` on parse failure, and explicitly validate the protocol is
`http:` or `https:` before checking the hostname against the trusted
hosts list. This applies the same fix to the Gen2 SDKs.
### Tests
- Added/updated tests in `packages/core/src/builder.class.test.ts`,
`packages/react/test/builder-block.test.tsx` (new), and
`packages/sdks/src/functions/is-from-trusted-host.test.ts` covering
spoofed hostnames (e.g. `evil-builder.io.attacker.com`,
`notlocalhost:1234x`), non-HTTP origins (e.g.
`javascript://builder.io`), the literal string `"null"`, and non-URL
strings — asserting these are all correctly rejected as untrusted.
**JIRA**
https://builder-io.atlassian.net/browse/ENG-13357
---
<a
href="https://builder.io/app/projects/b29d4bc79bfe480fb3f0/classic-seed-fvi4jqvb"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://cdn.builder.io/api/v1/image/assets%2FYJIGb4i01jvw0SRdL5Bt%2F226fa21c49ce4f95a5aba53aa594fe7a"><img
src="https://cdn.builder.io/api/v1/image/assets%2FYJIGb4i01jvw0SRdL5Bt%2F949e3db6dedf4252bf6ae0258f4a37de"
alt="Edit in Builder"></picture></a> <a
href="https://b29d4bc79bfe480fb3f0-classic-seed-fvi4jqvb.projects.builder.my/"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://cdn.builder.io/api/v1/image/assets%2FYJIGb4i01jvw0SRdL5Bt%2Fe530b1333b5b4cedac9c41b8573c8268"><img
src="https://cdn.builder.io/api/v1/image/assets%2FYJIGb4i01jvw0SRdL5Bt%2Fbf5aebbec0b448779c805d58bacf6278"
alt="Preview"></picture></a>
---
To clone this PR locally use the [Github CLI](https://cli.github.com/)
with command `gh pr checkout 4724`
You can tag me at @builderio for anything you want me to fix or change
<!-- DO NOT EDIT THE CONTENT BELOW: -->
<!--<projectId>b29d4bc79bfe480fb3f0</projectId>-->
<!--<branchName>classic-seed-fvi4jqvb</branchName>-->
<!-- CURSOR_SUMMARY -->
---
> [!NOTE]
> **High Risk**
> Security fix for editor postMessage handling and code-binding updates;
incorrect validation could break legitimate editing or leave XSS vectors
open.
>
> **Overview**
> Closes a **postMessage origin bypass** where spoofed hostnames or
malformed origins could be treated as trusted, allowing untrusted pages
to send editor messages (including `builder.patchUpdates` that apply
bindings executed as code).
>
> **`Builder.isTrustedHostForEvent`** now requires `^https?://`, parses
the origin in a try/catch, enforces `http:`/`https:` protocol, and
checks the hostname with **`Builder.isTrustedHost`** (exact match, not
substring). **`Builder.isEditing`** drops the unanchored
`/builder\.io|localhost:1234/` referrer regex in favor of the same
helper.
>
> **`BuilderBlock.onWindowMessage`** adds an early
**`isTrustedHostForEvent`** guard (aligned with other editor listeners).
Gen2 **`isFromTrustedHost`** mirrors the same parse/protocol/hostname
rules.
>
> Tests cover lookalike domains, non-HTTP schemes, and invalid origins;
a changeset patches all affected SDK packages.
>
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
e7f5de7509ad1c674bbb0279c1e95257d2cf64d9. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
---------
Co-authored-by: Builder.io <builder-bot@builder.io> 1830e03c feat: ENG-12261 add OAuth 2.0 support and settings UI for Phrase integration (#4699)
## Description
Adds OAuth 2.0 support and settings UI for Phrase integration
<!-- CURSOR_SUMMARY -->
---
> [!NOTE]
> **Medium Risk**
> Changes authentication and how Phrase API calls are authorized (OAuth
popup, session state, 401 refresh), which can break translation
workflows if server OAuth endpoints or token refresh behave differently
than password auth.
>
> **Overview**
> Adds **SSO / OAuth 2.0** as an alternative to username/password for
the Phrase connector, aimed at orgs that block password login. Settings
gain an **Authentication** dropdown, per-org **OAuth Client ID**, US
data-center flag, and a custom **Connect / Disconnect** panel that runs
the Builder API OAuth popup flow (`prepare` → `start` → `postMessage`);
tokens stay server-side and the browser only sees connection metadata.
>
> Translation actions now go through a new **`PhraseApi`** wrapper that
checks credentials (`ensureAuthenticated`), retries on **401** via
**`oauth/refresh`** in OAuth mode, and handles org switches and stale
in-memory OAuth state with **apiKey-scoped session markers**.
Username/password fields are shown only when not in OAuth mode; both
credential types can coexist when switching modes.
>
> The README documents OAuth setup (Phrase registered app, redirect URI,
admin connect steps) and a sequence diagram. Plugin version bumps to
**0.0.17**. The stub **Request an updated translation** content action
is removed; pending-job **outdated source** warnings are refactored into
`checkTranslationFreshness`.
>
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
5e0c959ba6cf03cb165653deb827b7723332a959. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY --> 270f73a7 feat: ENG-12261 add OAuth 2.0 support and settings UI for Phrase integration (#4699)
## Description
Adds OAuth 2.0 support and settings UI for Phrase integration
<!-- CURSOR_SUMMARY -->
---
> [!NOTE]
> **Medium Risk**
> Changes authentication and how Phrase API calls are authorized (OAuth
popup, session state, 401 refresh), which can break translation
workflows if server OAuth endpoints or token refresh behave differently
than password auth.
>
> **Overview**
> Adds **SSO / OAuth 2.0** as an alternative to username/password for
the Phrase connector, aimed at orgs that block password login. Settings
gain an **Authentication** dropdown, per-org **OAuth Client ID**, US
data-center flag, and a custom **Connect / Disconnect** panel that runs
the Builder API OAuth popup flow (`prepare` → `start` → `postMessage`);
tokens stay server-side and the browser only sees connection metadata.
>
> Translation actions now go through a new **`PhraseApi`** wrapper that
checks credentials (`ensureAuthenticated`), retries on **401** via
**`oauth/refresh`** in OAuth mode, and handles org switches and stale
in-memory OAuth state with **apiKey-scoped session markers**.
Username/password fields are shown only when not in OAuth mode; both
credential types can coexist when switching modes.
>
> The README documents OAuth setup (Phrase registered app, redirect URI,
admin connect steps) and a sequence diagram. Plugin version bumps to
**0.0.17**. The stub **Request an updated translation** content action
is removed; pending-job **outdated source** warnings are refactored into
`checkTranslationFreshness`.
>
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
5e0c959ba6cf03cb165653deb827b7723332a959. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY --> 1830e03c feat: ENG-12261 add OAuth 2.0 support and settings UI for Phrase integration (#4699)
## Description
Adds OAuth 2.0 support and settings UI for Phrase integration
<!-- CURSOR_SUMMARY -->
---
> [!NOTE]
> **Medium Risk**
> Changes authentication and how Phrase API calls are authorized (OAuth
popup, session state, 401 refresh), which can break translation
workflows if server OAuth endpoints or token refresh behave differently
than password auth.
>
> **Overview**
> Adds **SSO / OAuth 2.0** as an alternative to username/password for
the Phrase connector, aimed at orgs that block password login. Settings
gain an **Authentication** dropdown, per-org **OAuth Client ID**, US
data-center flag, and a custom **Connect / Disconnect** panel that runs
the Builder API OAuth popup flow (`prepare` → `start` → `postMessage`);
tokens stay server-side and the browser only sees connection metadata.
>
> Translation actions now go through a new **`PhraseApi`** wrapper that
checks credentials (`ensureAuthenticated`), retries on **401** via
**`oauth/refresh`** in OAuth mode, and handles org switches and stale
in-memory OAuth state with **apiKey-scoped session markers**.
Username/password fields are shown only when not in OAuth mode; both
credential types can coexist when switching modes.
>
> The README documents OAuth setup (Phrase registered app, redirect URI,
admin connect steps) and a sequence diagram. Plugin version bumps to
**0.0.17**. The stub **Request an updated translation** content action
is removed; pending-job **outdated source** warnings are refactored into
`checkTranslationFreshness`.
>
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
5e0c959ba6cf03cb165653deb827b7723332a959. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY --> 661064a3 feat: ENG-12261 add OAuth 2.0 support and settings UI for Phrase integration (#4699)
## Description
Adds OAuth 2.0 support and settings UI for Phrase integration
<!-- CURSOR_SUMMARY -->
---
> [!NOTE]
> **Medium Risk**
> Changes authentication and how Phrase API calls are authorized (OAuth
popup, session state, 401 refresh), which can break translation
workflows if server OAuth endpoints or token refresh behave differently
than password auth.
>
> **Overview**
> Adds **SSO / OAuth 2.0** as an alternative to username/password for
the Phrase connector, aimed at orgs that block password login. Settings
gain an **Authentication** dropdown, per-org **OAuth Client ID**, US
data-center flag, and a custom **Connect / Disconnect** panel that runs
the Builder API OAuth popup flow (`prepare` → `start` → `postMessage`);
tokens stay server-side and the browser only sees connection metadata.
>
> Translation actions now go through a new **`PhraseApi`** wrapper that
checks credentials (`ensureAuthenticated`), retries on **401** via
**`oauth/refresh`** in OAuth mode, and handles org switches and stale
in-memory OAuth state with **apiKey-scoped session markers**.
Username/password fields are shown only when not in OAuth mode; both
credential types can coexist when switching modes.
>
> The README documents OAuth setup (Phrase registered app, redirect URI,
admin connect steps) and a sequence diagram. Plugin version bumps to
**0.0.17**. The stub **Request an updated translation** content action
is removed; pending-job **outdated source** warnings are refactored into
`checkTranslationFreshness`.
>
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
5e0c959ba6cf03cb165653deb827b7723332a959. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY --> 1830e03c feat: ENG-12261 add OAuth 2.0 support and settings UI for Phrase integration (#4699)
## Description
Adds OAuth 2.0 support and settings UI for Phrase integration
<!-- CURSOR_SUMMARY -->
---
> [!NOTE]
> **Medium Risk**
> Changes authentication and how Phrase API calls are authorized (OAuth
popup, session state, 401 refresh), which can break translation
workflows if server OAuth endpoints or token refresh behave differently
than password auth.
>
> **Overview**
> Adds **SSO / OAuth 2.0** as an alternative to username/password for
the Phrase connector, aimed at orgs that block password login. Settings
gain an **Authentication** dropdown, per-org **OAuth Client ID**, US
data-center flag, and a custom **Connect / Disconnect** panel that runs
the Builder API OAuth popup flow (`prepare` → `start` → `postMessage`);
tokens stay server-side and the browser only sees connection metadata.
>
> Translation actions now go through a new **`PhraseApi`** wrapper that
checks credentials (`ensureAuthenticated`), retries on **401** via
**`oauth/refresh`** in OAuth mode, and handles org switches and stale
in-memory OAuth state with **apiKey-scoped session markers**.
Username/password fields are shown only when not in OAuth mode; both
credential types can coexist when switching modes.
>
> The README documents OAuth setup (Phrase registered app, redirect URI,
admin connect steps) and a sequence diagram. Plugin version bumps to
**0.0.17**. The stub **Request an updated translation** content action
is removed; pending-job **outdated source** warnings are refactored into
`checkTranslationFreshness`.
>
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
5e0c959ba6cf03cb165653deb827b7723332a959. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY --> 6f9b2253 fix[smartling]: ENG-12342 fix 'Clear translation metadata' button not working (#4544)
## Problem
The **Clear translation metadata** content action in the Smartling
plugin was silently broken. Clicking the button and confirming the
dialog appeared to succeed (snackbar showed \"Translation metadata
cleared.\"), but the translation fields (`translationStatus`,
`translationJobId`, etc.) were never actually removed from the content.
## Root Cause
`content.meta` is a **MobX observable Map**. The button's `onClick`
handler cloned it using `fastClone`:
```ts
const updatedMeta = fastClone(content.meta);
// fastClone = (obj) => JSON.parse(JSON.stringify(obj))
```
`JSON.stringify` on a MobX observable Map serialises it as `{}` (an
empty plain object) — Map entries are not picked up by the default JSON
serialiser. As a result:
- `updatedMeta` was always `{}`
- The subsequent `delete updatedMeta.translationStatus` (etc.) calls
were no-ops on a field that didn't exist
- `updateLatestDraft` was called with `meta: {}`, either leaving the
translation fields untouched (if the API merges) or wiping *all*
metadata (if the API replaces)
## Fix
Replace `fastClone(content.meta)` with `{ ...content.meta?.toJS() }`.
`.toJS()` is the correct MobX API for converting an observable Map to a
plain JS object. The spread then creates a regular mutable copy, and the
`delete` operations work as intended.
```ts
// Before
const updatedMeta = fastClone(content.meta);
// After
const updatedMeta = { ...content.meta?.toJS() };
```
This is exactly the same pattern already used in the backend's
`cleanupOrphanedTranslationMetadata` helper
([`smartling.ts:465`](../blob/main/plugins/smartling/src/smartling.ts#L465)),
confirming it's the correct approach.
## Test Plan
- [ ] Open a content entry that has stale translation metadata (e.g.
`translationStatus` = `completed` or `translationJobId` set, not in
`pending`/`local`)
- [ ] Open the content actions menu — confirm **Clear translation
metadata** is visible
- [ ] Click it and confirm the dialog
- [ ] Verify the snackbar shows \"Translation metadata cleared.\"
- [ ] Reload the content entry and confirm all 7 translation fields
(`translationStatus`, `translationJobId`, `translationBy`,
`translationRevision`, `translationRevisionLatest`, `translationBatch`,
`translationRequested`) are gone from the meta
- [ ] Confirm the **Clear translation metadata** button no longer
appears for that entry
🤖 Generated with [Claude Code](https://claude.com/claude-code)
<!-- CURSOR_SUMMARY -->
---
> [!NOTE]
> **Low Risk**
> Scoped UI fix for one content action and a patch version bump; no auth
or broad meta-write path changes beyond correcting this handler.
>
> **Overview**
> Fixes the **Clear translation metadata** content action so it actually
removes Smartling fields instead of showing success while leaving
metadata unchanged.
>
> The handler no longer clones `content.meta` with `fastClone` /
`JSON.stringify`, which produced `{}` for MobX observable Maps. It now
builds a plain object via `content.meta.toJS()` (with a fallback),
deletes the seven translation keys, and persists with
`updateLatestDraft`. The confirm dialog call matches the updated API
shape.
>
> Plugin version is bumped to **0.1.2** in `package.json` and the
lockfile.
>
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
035fad6056df312bf5ec4df7663dcfb53422c307. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
---------
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: Sanyam Kamat <1625114+sanyamkamat@users.noreply.github.com> 57a307ee fix[smartling]: ENG-12342 fix 'Clear translation metadata' button not working (#4544)
## Problem
The **Clear translation metadata** content action in the Smartling
plugin was silently broken. Clicking the button and confirming the
dialog appeared to succeed (snackbar showed \"Translation metadata
cleared.\"), but the translation fields (`translationStatus`,
`translationJobId`, etc.) were never actually removed from the content.
## Root Cause
`content.meta` is a **MobX observable Map**. The button's `onClick`
handler cloned it using `fastClone`:
```ts
const updatedMeta = fastClone(content.meta);
// fastClone = (obj) => JSON.parse(JSON.stringify(obj))
```
`JSON.stringify` on a MobX observable Map serialises it as `{}` (an
empty plain object) — Map entries are not picked up by the default JSON
serialiser. As a result:
- `updatedMeta` was always `{}`
- The subsequent `delete updatedMeta.translationStatus` (etc.) calls
were no-ops on a field that didn't exist
- `updateLatestDraft` was called with `meta: {}`, either leaving the
translation fields untouched (if the API merges) or wiping *all*
metadata (if the API replaces)
## Fix
Replace `fastClone(content.meta)` with `{ ...content.meta?.toJS() }`.
`.toJS()` is the correct MobX API for converting an observable Map to a
plain JS object. The spread then creates a regular mutable copy, and the
`delete` operations work as intended.
```ts
// Before
const updatedMeta = fastClone(content.meta);
// After
const updatedMeta = { ...content.meta?.toJS() };
```
This is exactly the same pattern already used in the backend's
`cleanupOrphanedTranslationMetadata` helper
([`smartling.ts:465`](../blob/main/plugins/smartling/src/smartling.ts#L465)),
confirming it's the correct approach.
## Test Plan
- [ ] Open a content entry that has stale translation metadata (e.g.
`translationStatus` = `completed` or `translationJobId` set, not in
`pending`/`local`)
- [ ] Open the content actions menu — confirm **Clear translation
metadata** is visible
- [ ] Click it and confirm the dialog
- [ ] Verify the snackbar shows \"Translation metadata cleared.\"
- [ ] Reload the content entry and confirm all 7 translation fields
(`translationStatus`, `translationJobId`, `translationBy`,
`translationRevision`, `translationRevisionLatest`, `translationBatch`,
`translationRequested`) are gone from the meta
- [ ] Confirm the **Clear translation metadata** button no longer
appears for that entry
🤖 Generated with [Claude Code](https://claude.com/claude-code)
<!-- CURSOR_SUMMARY -->
---
> [!NOTE]
> **Low Risk**
> Scoped UI fix for one content action and a patch version bump; no auth
or broad meta-write path changes beyond correcting this handler.
>
> **Overview**
> Fixes the **Clear translation metadata** content action so it actually
removes Smartling fields instead of showing success while leaving
metadata unchanged.
>
> The handler no longer clones `content.meta` with `fastClone` /
`JSON.stringify`, which produced `{}` for MobX observable Maps. It now
builds a plain object via `content.meta.toJS()` (with a fallback),
deletes the seven translation keys, and persists with
`updateLatestDraft`. The confirm dialog call matches the updated API
shape.
>
> Plugin version is bumped to **0.1.2** in `package.json` and the
lockfile.
>
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
035fad6056df312bf5ec4df7663dcfb53422c307. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
---------
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: Sanyam Kamat <1625114+sanyamkamat@users.noreply.github.com> 6f9b2253 fix[smartling]: ENG-12342 fix 'Clear translation metadata' button not working (#4544)
## Problem
The **Clear translation metadata** content action in the Smartling
plugin was silently broken. Clicking the button and confirming the
dialog appeared to succeed (snackbar showed \"Translation metadata
cleared.\"), but the translation fields (`translationStatus`,
`translationJobId`, etc.) were never actually removed from the content.
## Root Cause
`content.meta` is a **MobX observable Map**. The button's `onClick`
handler cloned it using `fastClone`:
```ts
const updatedMeta = fastClone(content.meta);
// fastClone = (obj) => JSON.parse(JSON.stringify(obj))
```
`JSON.stringify` on a MobX observable Map serialises it as `{}` (an
empty plain object) — Map entries are not picked up by the default JSON
serialiser. As a result:
- `updatedMeta` was always `{}`
- The subsequent `delete updatedMeta.translationStatus` (etc.) calls
were no-ops on a field that didn't exist
- `updateLatestDraft` was called with `meta: {}`, either leaving the
translation fields untouched (if the API merges) or wiping *all*
metadata (if the API replaces)
## Fix
Replace `fastClone(content.meta)` with `{ ...content.meta?.toJS() }`.
`.toJS()` is the correct MobX API for converting an observable Map to a
plain JS object. The spread then creates a regular mutable copy, and the
`delete` operations work as intended.
```ts
// Before
const updatedMeta = fastClone(content.meta);
// After
const updatedMeta = { ...content.meta?.toJS() };
```
This is exactly the same pattern already used in the backend's
`cleanupOrphanedTranslationMetadata` helper
([`smartling.ts:465`](../blob/main/plugins/smartling/src/smartling.ts#L465)),
confirming it's the correct approach.
## Test Plan
- [ ] Open a content entry that has stale translation metadata (e.g.
`translationStatus` = `completed` or `translationJobId` set, not in
`pending`/`local`)
- [ ] Open the content actions menu — confirm **Clear translation
metadata** is visible
- [ ] Click it and confirm the dialog
- [ ] Verify the snackbar shows \"Translation metadata cleared.\"
- [ ] Reload the content entry and confirm all 7 translation fields
(`translationStatus`, `translationJobId`, `translationBy`,
`translationRevision`, `translationRevisionLatest`, `translationBatch`,
`translationRequested`) are gone from the meta
- [ ] Confirm the **Clear translation metadata** button no longer
appears for that entry
🤖 Generated with [Claude Code](https://claude.com/claude-code)
<!-- CURSOR_SUMMARY -->
---
> [!NOTE]
> **Low Risk**
> Scoped UI fix for one content action and a patch version bump; no auth
or broad meta-write path changes beyond correcting this handler.
>
> **Overview**
> Fixes the **Clear translation metadata** content action so it actually
removes Smartling fields instead of showing success while leaving
metadata unchanged.
>
> The handler no longer clones `content.meta` with `fastClone` /
`JSON.stringify`, which produced `{}` for MobX observable Maps. It now
builds a plain object via `content.meta.toJS()` (with a fallback),
deletes the seven translation keys, and persists with
`updateLatestDraft`. The confirm dialog call matches the updated API
shape.
>
> Plugin version is bumped to **0.1.2** in `package.json` and the
lockfile.
>
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
035fad6056df312bf5ec4df7663dcfb53422c307. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
---------
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: Sanyam Kamat <1625114+sanyamkamat@users.noreply.github.com> d905293c fix[smartling]: ENG-12342 fix 'Clear translation metadata' button not working (#4544)
## Problem
The **Clear translation metadata** content action in the Smartling
plugin was silently broken. Clicking the button and confirming the
dialog appeared to succeed (snackbar showed \"Translation metadata
cleared.\"), but the translation fields (`translationStatus`,
`translationJobId`, etc.) were never actually removed from the content.
## Root Cause
`content.meta` is a **MobX observable Map**. The button's `onClick`
handler cloned it using `fastClone`:
```ts
const updatedMeta = fastClone(content.meta);
// fastClone = (obj) => JSON.parse(JSON.stringify(obj))
```
`JSON.stringify` on a MobX observable Map serialises it as `{}` (an
empty plain object) — Map entries are not picked up by the default JSON
serialiser. As a result:
- `updatedMeta` was always `{}`
- The subsequent `delete updatedMeta.translationStatus` (etc.) calls
were no-ops on a field that didn't exist
- `updateLatestDraft` was called with `meta: {}`, either leaving the
translation fields untouched (if the API merges) or wiping *all*
metadata (if the API replaces)
## Fix
Replace `fastClone(content.meta)` with `{ ...content.meta?.toJS() }`.
`.toJS()` is the correct MobX API for converting an observable Map to a
plain JS object. The spread then creates a regular mutable copy, and the
`delete` operations work as intended.
```ts
// Before
const updatedMeta = fastClone(content.meta);
// After
const updatedMeta = { ...content.meta?.toJS() };
```
This is exactly the same pattern already used in the backend's
`cleanupOrphanedTranslationMetadata` helper
([`smartling.ts:465`](../blob/main/plugins/smartling/src/smartling.ts#L465)),
confirming it's the correct approach.
## Test Plan
- [ ] Open a content entry that has stale translation metadata (e.g.
`translationStatus` = `completed` or `translationJobId` set, not in
`pending`/`local`)
- [ ] Open the content actions menu — confirm **Clear translation
metadata** is visible
- [ ] Click it and confirm the dialog
- [ ] Verify the snackbar shows \"Translation metadata cleared.\"
- [ ] Reload the content entry and confirm all 7 translation fields
(`translationStatus`, `translationJobId`, `translationBy`,
`translationRevision`, `translationRevisionLatest`, `translationBatch`,
`translationRequested`) are gone from the meta
- [ ] Confirm the **Clear translation metadata** button no longer
appears for that entry
🤖 Generated with [Claude Code](https://claude.com/claude-code)
<!-- CURSOR_SUMMARY -->
---
> [!NOTE]
> **Low Risk**
> Scoped UI fix for one content action and a patch version bump; no auth
or broad meta-write path changes beyond correcting this handler.
>
> **Overview**
> Fixes the **Clear translation metadata** content action so it actually
removes Smartling fields instead of showing success while leaving
metadata unchanged.
>
> The handler no longer clones `content.meta` with `fastClone` /
`JSON.stringify`, which produced `{}` for MobX observable Maps. It now
builds a plain object via `content.meta.toJS()` (with a fallback),
deletes the seven translation keys, and persists with
`updateLatestDraft`. The confirm dialog call matches the updated API
shape.
>
> Plugin version is bumped to **0.1.2** in `package.json` and the
lockfile.
>
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
035fad6056df312bf5ec4df7663dcfb53422c307. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
---------
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: Sanyam Kamat <1625114+sanyamkamat@users.noreply.github.com> 6f9b2253 fix[smartling]: ENG-12342 fix 'Clear translation metadata' button not working (#4544)
## Problem
The **Clear translation metadata** content action in the Smartling
plugin was silently broken. Clicking the button and confirming the
dialog appeared to succeed (snackbar showed \"Translation metadata
cleared.\"), but the translation fields (`translationStatus`,
`translationJobId`, etc.) were never actually removed from the content.
## Root Cause
`content.meta` is a **MobX observable Map**. The button's `onClick`
handler cloned it using `fastClone`:
```ts
const updatedMeta = fastClone(content.meta);
// fastClone = (obj) => JSON.parse(JSON.stringify(obj))
```
`JSON.stringify` on a MobX observable Map serialises it as `{}` (an
empty plain object) — Map entries are not picked up by the default JSON
serialiser. As a result:
- `updatedMeta` was always `{}`
- The subsequent `delete updatedMeta.translationStatus` (etc.) calls
were no-ops on a field that didn't exist
- `updateLatestDraft` was called with `meta: {}`, either leaving the
translation fields untouched (if the API merges) or wiping *all*
metadata (if the API replaces)
## Fix
Replace `fastClone(content.meta)` with `{ ...content.meta?.toJS() }`.
`.toJS()` is the correct MobX API for converting an observable Map to a
plain JS object. The spread then creates a regular mutable copy, and the
`delete` operations work as intended.
```ts
// Before
const updatedMeta = fastClone(content.meta);
// After
const updatedMeta = { ...content.meta?.toJS() };
```
This is exactly the same pattern already used in the backend's
`cleanupOrphanedTranslationMetadata` helper
([`smartling.ts:465`](../blob/main/plugins/smartling/src/smartling.ts#L465)),
confirming it's the correct approach.
## Test Plan
- [ ] Open a content entry that has stale translation metadata (e.g.
`translationStatus` = `completed` or `translationJobId` set, not in
`pending`/`local`)
- [ ] Open the content actions menu — confirm **Clear translation
metadata** is visible
- [ ] Click it and confirm the dialog
- [ ] Verify the snackbar shows \"Translation metadata cleared.\"
- [ ] Reload the content entry and confirm all 7 translation fields
(`translationStatus`, `translationJobId`, `translationBy`,
`translationRevision`, `translationRevisionLatest`, `translationBatch`,
`translationRequested`) are gone from the meta
- [ ] Confirm the **Clear translation metadata** button no longer
appears for that entry
🤖 Generated with [Claude Code](https://claude.com/claude-code)
<!-- CURSOR_SUMMARY -->
---
> [!NOTE]
> **Low Risk**
> Scoped UI fix for one content action and a patch version bump; no auth
or broad meta-write path changes beyond correcting this handler.
>
> **Overview**
> Fixes the **Clear translation metadata** content action so it actually
removes Smartling fields instead of showing success while leaving
metadata unchanged.
>
> The handler no longer clones `content.meta` with `fastClone` /
`JSON.stringify`, which produced `{}` for MobX observable Maps. It now
builds a plain object via `content.meta.toJS()` (with a fallback),
deletes the seven translation keys, and persists with
`updateLatestDraft`. The confirm dialog call matches the updated API
shape.
>
> Plugin version is bumped to **0.1.2** in `package.json` and the
lockfile.
>
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
035fad6056df312bf5ec4df7663dcfb53422c307. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
---------
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: Sanyam Kamat <1625114+sanyamkamat@users.noreply.github.com> 27e443e1 📦 Publish SDKs (#4691)
This PR was opened by the [Changesets
release](https://github.com/changesets/action) GitHub action. When
you're ready to do a release, you can merge this and the packages will
be published to npm automatically. If you're not ready to do a release
yet, that's fine, whenever you add more changesets to main, this PR will
be updated.
# Releases
## @builder.io/sdk-angular@0.25.5
### Patch Changes
- 071f939: Stop injecting duplicate inline A/B test scripts on pages
with multiple Content components. The `window.builderIoAbTest` /
`window.builderIoRenderContent` init script is now only emitted when a
Content actually renders A/B variants, and the definition is idempotent
and self-removing on hydration targets. This avoids the duplication
without the client-side DOM mutation that caused the previous hydration
regression.
## @builder.io/sdk-react-nextjs@0.25.5
### Patch Changes
- 071f939: Stop injecting duplicate inline A/B test scripts on pages
with multiple Content components. The `window.builderIoAbTest` /
`window.builderIoRenderContent` init script is now only emitted when a
Content actually renders A/B variants, and the definition is idempotent
and self-removing on hydration targets. This avoids the duplication
without the client-side DOM mutation that caused the previous hydration
regression.
- 10b6707: Bump `next` peer dependency to `>=13.5.9` to address
authorization bypass in Next.js middleware (CVE-2025-29927)
## @builder.io/sdk-qwik@0.25.5
### Patch Changes
- 071f939: Stop injecting duplicate inline A/B test scripts on pages
with multiple Content components. The `window.builderIoAbTest` /
`window.builderIoRenderContent` init script is now only emitted when a
Content actually renders A/B variants, and the definition is idempotent
and self-removing on hydration targets. This avoids the duplication
without the client-side DOM mutation that caused the previous hydration
regression.
## @builder.io/sdk-react@5.2.4
### Patch Changes
- 071f939: Stop injecting duplicate inline A/B test scripts on pages
with multiple Content components. The `window.builderIoAbTest` /
`window.builderIoRenderContent` init script is now only emitted when a
Content actually renders A/B variants, and the definition is idempotent
and self-removing on hydration targets. This avoids the duplication
without the client-side DOM mutation that caused the previous hydration
regression.
## @builder.io/sdk-react-native@5.2.4
### Patch Changes
- 071f939: Stop injecting duplicate inline A/B test scripts on pages
with multiple Content components. The `window.builderIoAbTest` /
`window.builderIoRenderContent` init script is now only emitted when a
Content actually renders A/B variants, and the definition is idempotent
and self-removing on hydration targets. This avoids the duplication
without the client-side DOM mutation that caused the previous hydration
regression.
## @builder.io/sdk-solid@5.2.4
### Patch Changes
- 071f939: Stop injecting duplicate inline A/B test scripts on pages
with multiple Content components. The `window.builderIoAbTest` /
`window.builderIoRenderContent` init script is now only emitted when a
Content actually renders A/B variants, and the definition is idempotent
and self-removing on hydration targets. This avoids the duplication
without the client-side DOM mutation that caused the previous hydration
regression.
## @builder.io/sdk-svelte@5.2.4
### Patch Changes
- 071f939: Stop injecting duplicate inline A/B test scripts on pages
with multiple Content components. The `window.builderIoAbTest` /
`window.builderIoRenderContent` init script is now only emitted when a
Content actually renders A/B variants, and the definition is idempotent
and self-removing on hydration targets. This avoids the duplication
without the client-side DOM mutation that caused the previous hydration
regression.
## @builder.io/sdk-vue@5.2.4
### Patch Changes
- 071f939: Stop injecting duplicate inline A/B test scripts on pages
with multiple Content components. The `window.builderIoAbTest` /
`window.builderIoRenderContent` init script is now only emitted when a
Content actually renders A/B variants, and the definition is idempotent
and self-removing on hydration targets. This avoids the duplication
without the client-side DOM mutation that caused the previous hydration
regression.
<!-- CURSOR_SUMMARY -->
---
> [!NOTE]
> **Medium Risk**
> A/B and SSR/hydration script behavior affects all framework SDK
consumers; the Next peer bump may block installs on vulnerable Next
versions until upgraded.
>
> **Overview**
> This **Changesets release PR** bumps published Gen2 SDK versions and
records patch notes; merging triggers npm publish.
>
> **A/B test inline script (all listed SDKs):** Re-applies the dedupe
fix after a prior revert—`window.builderIoAbTest` /
`window.builderIoRenderContent` init scripts are emitted only when
`Content` actually renders A/B variants, with idempotent definitions
that self-remove on hydration targets, avoiding duplicate scripts on
multi-`Content` pages without client-side DOM mutation that caused
hydration regressions.
>
> **Next.js SDK only (`@builder.io/sdk-react-nextjs@0.25.5`):** Raises
the `next` peer dependency to `>=13.5.9` for CVE-2025-29927 (middleware
authorization bypass).
>
> Version bumps: Angular `0.25.5`; Next/Qwik `0.25.5`; React, React
Native, Solid, Svelte, Vue `5.2.4`. Pending changeset files under
`.changeset/` are removed as part of the release workflow.
>
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
a8b9547d52d1bfb9aca388bde43a726f46db540d. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> 26eae805 📦 Publish SDKs (#4691)
This PR was opened by the [Changesets
release](https://github.com/changesets/action) GitHub action. When
you're ready to do a release, you can merge this and the packages will
be published to npm automatically. If you're not ready to do a release
yet, that's fine, whenever you add more changesets to main, this PR will
be updated.
# Releases
## @builder.io/sdk-angular@0.25.5
### Patch Changes
- 071f939: Stop injecting duplicate inline A/B test scripts on pages
with multiple Content components. The `window.builderIoAbTest` /
`window.builderIoRenderContent` init script is now only emitted when a
Content actually renders A/B variants, and the definition is idempotent
and self-removing on hydration targets. This avoids the duplication
without the client-side DOM mutation that caused the previous hydration
regression.
## @builder.io/sdk-react-nextjs@0.25.5
### Patch Changes
- 071f939: Stop injecting duplicate inline A/B test scripts on pages
with multiple Content components. The `window.builderIoAbTest` /
`window.builderIoRenderContent` init script is now only emitted when a
Content actually renders A/B variants, and the definition is idempotent
and self-removing on hydration targets. This avoids the duplication
without the client-side DOM mutation that caused the previous hydration
regression.
- 10b6707: Bump `next` peer dependency to `>=13.5.9` to address
authorization bypass in Next.js middleware (CVE-2025-29927)
## @builder.io/sdk-qwik@0.25.5
### Patch Changes
- 071f939: Stop injecting duplicate inline A/B test scripts on pages
with multiple Content components. The `window.builderIoAbTest` /
`window.builderIoRenderContent` init script is now only emitted when a
Content actually renders A/B variants, and the definition is idempotent
and self-removing on hydration targets. This avoids the duplication
without the client-side DOM mutation that caused the previous hydration
regression.
## @builder.io/sdk-react@5.2.4
### Patch Changes
- 071f939: Stop injecting duplicate inline A/B test scripts on pages
with multiple Content components. The `window.builderIoAbTest` /
`window.builderIoRenderContent` init script is now only emitted when a
Content actually renders A/B variants, and the definition is idempotent
and self-removing on hydration targets. This avoids the duplication
without the client-side DOM mutation that caused the previous hydration
regression.
## @builder.io/sdk-react-native@5.2.4
### Patch Changes
- 071f939: Stop injecting duplicate inline A/B test scripts on pages
with multiple Content components. The `window.builderIoAbTest` /
`window.builderIoRenderContent` init script is now only emitted when a
Content actually renders A/B variants, and the definition is idempotent
and self-removing on hydration targets. This avoids the duplication
without the client-side DOM mutation that caused the previous hydration
regression.
## @builder.io/sdk-solid@5.2.4
### Patch Changes
- 071f939: Stop injecting duplicate inline A/B test scripts on pages
with multiple Content components. The `window.builderIoAbTest` /
`window.builderIoRenderContent` init script is now only emitted when a
Content actually renders A/B variants, and the definition is idempotent
and self-removing on hydration targets. This avoids the duplication
without the client-side DOM mutation that caused the previous hydration
regression.
## @builder.io/sdk-svelte@5.2.4
### Patch Changes
- 071f939: Stop injecting duplicate inline A/B test scripts on pages
with multiple Content components. The `window.builderIoAbTest` /
`window.builderIoRenderContent` init script is now only emitted when a
Content actually renders A/B variants, and the definition is idempotent
and self-removing on hydration targets. This avoids the duplication
without the client-side DOM mutation that caused the previous hydration
regression.
## @builder.io/sdk-vue@5.2.4
### Patch Changes
- 071f939: Stop injecting duplicate inline A/B test scripts on pages
with multiple Content components. The `window.builderIoAbTest` /
`window.builderIoRenderContent` init script is now only emitted when a
Content actually renders A/B variants, and the definition is idempotent
and self-removing on hydration targets. This avoids the duplication
without the client-side DOM mutation that caused the previous hydration
regression.
<!-- CURSOR_SUMMARY -->
---
> [!NOTE]
> **Medium Risk**
> A/B and SSR/hydration script behavior affects all framework SDK
consumers; the Next peer bump may block installs on vulnerable Next
versions until upgraded.
>
> **Overview**
> This **Changesets release PR** bumps published Gen2 SDK versions and
records patch notes; merging triggers npm publish.
>
> **A/B test inline script (all listed SDKs):** Re-applies the dedupe
fix after a prior revert—`window.builderIoAbTest` /
`window.builderIoRenderContent` init scripts are emitted only when
`Content` actually renders A/B variants, with idempotent definitions
that self-remove on hydration targets, avoiding duplicate scripts on
multi-`Content` pages without client-side DOM mutation that caused
hydration regressions.
>
> **Next.js SDK only (`@builder.io/sdk-react-nextjs@0.25.5`):** Raises
the `next` peer dependency to `>=13.5.9` for CVE-2025-29927 (middleware
authorization bypass).
>
> Version bumps: Angular `0.25.5`; Next/Qwik `0.25.5`; React, React
Native, Solid, Svelte, Vue `5.2.4`. Pending changeset files under
`.changeset/` are removed as part of the release workflow.
>
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
a8b9547d52d1bfb9aca388bde43a726f46db540d. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> 27e443e1 📦 Publish SDKs (#4691)
This PR was opened by the [Changesets
release](https://github.com/changesets/action) GitHub action. When
you're ready to do a release, you can merge this and the packages will
be published to npm automatically. If you're not ready to do a release
yet, that's fine, whenever you add more changesets to main, this PR will
be updated.
# Releases
## @builder.io/sdk-angular@0.25.5
### Patch Changes
- 071f939: Stop injecting duplicate inline A/B test scripts on pages
with multiple Content components. The `window.builderIoAbTest` /
`window.builderIoRenderContent` init script is now only emitted when a
Content actually renders A/B variants, and the definition is idempotent
and self-removing on hydration targets. This avoids the duplication
without the client-side DOM mutation that caused the previous hydration
regression.
## @builder.io/sdk-react-nextjs@0.25.5
### Patch Changes
- 071f939: Stop injecting duplicate inline A/B test scripts on pages
with multiple Content components. The `window.builderIoAbTest` /
`window.builderIoRenderContent` init script is now only emitted when a
Content actually renders A/B variants, and the definition is idempotent
and self-removing on hydration targets. This avoids the duplication
without the client-side DOM mutation that caused the previous hydration
regression.
- 10b6707: Bump `next` peer dependency to `>=13.5.9` to address
authorization bypass in Next.js middleware (CVE-2025-29927)
## @builder.io/sdk-qwik@0.25.5
### Patch Changes
- 071f939: Stop injecting duplicate inline A/B test scripts on pages
with multiple Content components. The `window.builderIoAbTest` /
`window.builderIoRenderContent` init script is now only emitted when a
Content actually renders A/B variants, and the definition is idempotent
and self-removing on hydration targets. This avoids the duplication
without the client-side DOM mutation that caused the previous hydration
regression.
## @builder.io/sdk-react@5.2.4
### Patch Changes
- 071f939: Stop injecting duplicate inline A/B test scripts on pages
with multiple Content components. The `window.builderIoAbTest` /
`window.builderIoRenderContent` init script is now only emitted when a
Content actually renders A/B variants, and the definition is idempotent
and self-removing on hydration targets. This avoids the duplication
without the client-side DOM mutation that caused the previous hydration
regression.
## @builder.io/sdk-react-native@5.2.4
### Patch Changes
- 071f939: Stop injecting duplicate inline A/B test scripts on pages
with multiple Content components. The `window.builderIoAbTest` /
`window.builderIoRenderContent` init script is now only emitted when a
Content actually renders A/B variants, and the definition is idempotent
and self-removing on hydration targets. This avoids the duplication
without the client-side DOM mutation that caused the previous hydration
regression.
## @builder.io/sdk-solid@5.2.4
### Patch Changes
- 071f939: Stop injecting duplicate inline A/B test scripts on pages
with multiple Content components. The `window.builderIoAbTest` /
`window.builderIoRenderContent` init script is now only emitted when a
Content actually renders A/B variants, and the definition is idempotent
and self-removing on hydration targets. This avoids the duplication
without the client-side DOM mutation that caused the previous hydration
regression.
## @builder.io/sdk-svelte@5.2.4
### Patch Changes
- 071f939: Stop injecting duplicate inline A/B test scripts on pages
with multiple Content components. The `window.builderIoAbTest` /
`window.builderIoRenderContent` init script is now only emitted when a
Content actually renders A/B variants, and the definition is idempotent
and self-removing on hydration targets. This avoids the duplication
without the client-side DOM mutation that caused the previous hydration
regression.
## @builder.io/sdk-vue@5.2.4
### Patch Changes
- 071f939: Stop injecting duplicate inline A/B test scripts on pages
with multiple Content components. The `window.builderIoAbTest` /
`window.builderIoRenderContent` init script is now only emitted when a
Content actually renders A/B variants, and the definition is idempotent
and self-removing on hydration targets. This avoids the duplication
without the client-side DOM mutation that caused the previous hydration
regression.
<!-- CURSOR_SUMMARY -->
---
> [!NOTE]
> **Medium Risk**
> A/B and SSR/hydration script behavior affects all framework SDK
consumers; the Next peer bump may block installs on vulnerable Next
versions until upgraded.
>
> **Overview**
> This **Changesets release PR** bumps published Gen2 SDK versions and
records patch notes; merging triggers npm publish.
>
> **A/B test inline script (all listed SDKs):** Re-applies the dedupe
fix after a prior revert—`window.builderIoAbTest` /
`window.builderIoRenderContent` init scripts are emitted only when
`Content` actually renders A/B variants, with idempotent definitions
that self-remove on hydration targets, avoiding duplicate scripts on
multi-`Content` pages without client-side DOM mutation that caused
hydration regressions.
>
> **Next.js SDK only (`@builder.io/sdk-react-nextjs@0.25.5`):** Raises
the `next` peer dependency to `>=13.5.9` for CVE-2025-29927 (middleware
authorization bypass).
>
> Version bumps: Angular `0.25.5`; Next/Qwik `0.25.5`; React, React
Native, Solid, Svelte, Vue `5.2.4`. Pending changeset files under
`.changeset/` are removed as part of the release workflow.
>
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
a8b9547d52d1bfb9aca388bde43a726f46db540d. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>