Skip to content

feat(react): new react SDK - #665

Draft
dipankarmaikap wants to merge 49 commits into
mainfrom
feature/new-react-sdk
Draft

feat(react): new react SDK#665
dipankarmaikap wants to merge 49 commits into
mainfrom
feature/new-react-sdk

Conversation

@dipankarmaikap

Copy link
Copy Markdown
Contributor

No description provided.

- Remove rollupTypes which doesn't work with nested entry points
- Remove preserveModules which leaked internal workspace paths
- Add fixDtsExports plugin to remove erroneous 'export {}' from .d.ts files
dipankarmaikap and others added 3 commits July 2, 2026 19:13
## Summary

Updates Angular environment file handling in the `create` command to use
simple string replacement for placeholders instead of regex-based value
matching.

## Changes

- Add `updateAngularEnvironmentFiles` function for Angular-specific
environment file handling
- Pass `template` parameter to `handleEnvFileCreation` to detect Angular
projects
- Use `replaceAll` to replace `STORYBLOK_DELIVERY_API_TOKEN` and
`STORYBLOK_REGION` placeholders with actual values

## Before

The Angular environment files kept the placeholder names as literal
strings.

## After

```ts
// environment.ts
export const environment = {
  production: true,
  accessToken: 'actual-token-here', // Replace with your Storyblok Delivery API token
  region: 'eu', // Replace with your Storyblok region
};
```

## Related

Works with the Angular blueprint update:
storyblok/blueprint-core-angular#18
- Export v2 SDK as @storyblok/react/next, /next/rsc, /next/client
- Remove rollupTypes (incompatible with nested entries)
- Remove preserveModules (leaked workspace paths)
- Keep source in src/v2/, export as /next for experimentation
@pkg-pr-new

pkg-pr-new Bot commented Jul 2, 2026

Copy link
Copy Markdown

Open in StackBlitz

@storyblok/angular

npm i https://pkg.pr.new/@storyblok/angular@665

@storyblok/astro

npm i https://pkg.pr.new/@storyblok/astro@665

@storyblok/api-client

npm i https://pkg.pr.new/@storyblok/api-client@665

storyblok

npm i https://pkg.pr.new/storyblok@665

@storyblok/eslint-config

npm i https://pkg.pr.new/@storyblok/eslint-config@665

@storyblok/js

npm i https://pkg.pr.new/@storyblok/js@665

storyblok-js-client

npm i https://pkg.pr.new/storyblok-js-client@665

@storyblok/live-preview

npm i https://pkg.pr.new/@storyblok/live-preview@665

@storyblok/management-api-client

npm i https://pkg.pr.new/@storyblok/management-api-client@665

@storyblok/migrations

npm i https://pkg.pr.new/@storyblok/migrations@665

@storyblok/nuxt

npm i https://pkg.pr.new/@storyblok/nuxt@665

@storyblok/react

npm i https://pkg.pr.new/@storyblok/react@665

@storyblok/region-helper

npm i https://pkg.pr.new/@storyblok/region-helper@665

@storyblok/richtext

npm i https://pkg.pr.new/@storyblok/richtext@665

@storyblok/svelte

npm i https://pkg.pr.new/@storyblok/svelte@665

@storyblok/vue

npm i https://pkg.pr.new/@storyblok/vue@665

commit: caa59d9

maoberlehner and others added 2 commits July 6, 2026 08:37
…#672)

Assets migrated between spaces with `storyblok assets push` lost the
`<width>x<height>` dimensions folder in their CDN URL (e.g.
`.../f/SPACE/2048x1820/hash/image.jpg` became
`.../f/SPACE/hash/image.jpg`), even when the source asset had it.

Root cause: Storyblok's backend only appends the dimensions folder to
the S3 key when the sign request (`POST /v1/spaces/{id}/assets`)
includes a `size` field — it does not derive it from the actual image.
Two gaps combined to drop it:

- `@storyblok/management-api-client`'s `assets.create()` explicitly
whitelisted only `short_filename`, `asset_folder_id`, `is_private` when
calling `upload()`, silently discarding `size` (and `validate_upload`)
even though both are part of its declared input type.
- The CLI's `assets push` never derived a `size` for pushed assets in
the first place.

## Changes

- `packages/mapi-client/src/resources/assets.ts`: `create()` now
forwards `size`/`validate_upload` to the sign request.
- `packages/cli/src/commands/assets/streams.ts`: when creating a pushed
asset, reuse the dimensions already present in the source asset's
filename URL (parsed via a new `extractAssetSizeFromFilename` helper) so
pushed assets keep them.
- Added regression tests in both packages.

Fixes WDX-480
- Add ComponentEntry type for component config with fallback options
- Auto-detect React.lazy components and wrap in Suspense
- Add per-component fallback option for custom loading states
- Add global suspenseFallback config for default loading UI
- Add suspense option to force Suspense wrapping for async components
maoberlehner and others added 2 commits July 6, 2026 09:33
- project: @storyblok/api-client 0.4.0

- project: @storyblok/management-api-client 0.4.0

- project: @storyblok/migrations 0.1.17

- project: @storyblok/angular 1.0.2

- project: @storyblok/openapi 2.1.0

- project: storyblok 4.18.3
dipankarmaikap and others added 4 commits July 7, 2026 14:09
This PR fixes the TDZ (`ReferenceError`) caused by circular dependencies
when Storyblok components are imported directly and also render
`<StoryblokComponent />` internally.

It also adds both unit and Cypress tests to cover this scenario and help
prevent future regressions.

Fixes #547.
#630)

Teaches the `storyblok` CLI to push and pull assets to either a space or
the organization's shared libraries, so both kinds round-trip. A library
is a top-level shared asset folder with per-space read or write access.

## How

**mapi-client (`@storyblok/management-api-client`)**

- Adds three hand-written shared resources, mirroring the WDX-409
`convertToShared` pattern (these endpoints are not in the generated SDK,
since the WDX-407 overlay will not land): `sharedAssetFolders`,
`sharedAssets` (full sign → S3 → finish → get upload flow), and
`sharedInternalTags` (every call carries `asset_folder_id` = library
root).
- Exports the existing `uploadToS3` helper for reuse.
- Endpoint request/response shapes were verified against `../storyrails`
before wiring.

**CLI (`storyblok`)**

- `scope.ts`: a `Scope` discriminated union (`space` | `library`),
on-disk base-dir resolution, library listing and access helpers,
read-only failfast, and a library-root resolver. The existing
transport-injected pipelines are reused unchanged.
- `assets push`: `--target <space|shared|all>` and `--library` flags, a
scope loop, read-only-library failfast (no partial state), and library
tag remap (`internal_tag_ids` are mapped to the library's shared tags,
creating any that are missing). `meta_data` round-trips. Shared-asset
creates default the folder to the library root, and the library root
folder is skipped on bulk push (it is a shared root folder that cannot
be pushed from a space).
- `assets pull`: `--target <with-referenced|all|space|shared>` (default
`with-referenced`), which pulls space assets and then resolves
shared-library assets referenced by already-pulled local stories.
Classification is id-based, never URL-prefix-based.
- `--target` is constrained with Commander `.choices()`, so unknown
values fail fast with a non-zero exit.
- Shared `shared_*` API error actions; command READMEs updated.

## On-disk layout

Library assets live under `.storyblok/assets/shared/<library_id>/`,
parallel to the space subtree at `.storyblok/assets/<space_id>/`, each
with its own `manifest.jsonl`.

Fixes WDX-408
Rename the previous Linear ticket prefix `WDX` to the new `DX` prefix
across the repository.

## Changes

- Ticket references (`WDX-123` → `DX-123`) in agent skills
(`investigate`, `spec`, `triage`), `.claude/rules/artifact-naming.md`,
`AGENTS.md` (branch naming + commit footer conventions), and `adr/0004`.
- Linear team key in `linear-fetch.sh`: `DEFAULT_TEAM` and `--team`
references (`WDX` → `DX`). The ticket prefix is the Linear team key, so
leaving the default would break the `triage` command.

## Left untouched (intentional)

- `storyblok/openapi-wdx` repository name and the `openapi-wdx-`
temp-dir prefix in `tools/openapi-codegen/` — a real GitHub repo name,
not a ticket reference.
…DX-273) (#675)

Adds selective sync to `components pull` and `components push` so teams
sharing a single space can sync only their own components.

- `components pull` gains `--filter <glob>`, `--group <name|Parent/Child
path>` (repeatable, includes descendant groups), and `--tag <name>`
(repeatable, comma-separated).
- `components push` gains `--group` and `--tag` with the same semantics.
- Selectors combine with AND across types and OR within a repeatable
selector. `--filter` is a `minimatch` glob applied on top.

Fixes DX-273
maoberlehner and others added 10 commits July 13, 2026 11:05
…ck (#691)

Adds `packages/js-client/vitest.config.ts` enabling Vitest `typecheck`
so `vitest run` collects and type-checks `src/**/*.test-d.ts`.

## Why

Follow-up to #677 (DX-472). That PR added `src/index.test-d.ts` with
`expectTypeOf` assertions pinning the write methods
(`post`/`put`/`patch`/`delete`) to `ISbResponse`, and described them as
enforced by both `test:types` (tsc) and `vitest --typecheck`.

In reality only `test:types` enforced them:
- There was no `vitest.config.ts`, and `test:unit` is a plain `vitest
run` with no `--typecheck` flag.
- Vitest's default `include` matches `*.{test,spec}.ts` — it never
matches `*.test-d.ts`, so the file wasn't even collected by `vitest
run`.

Fixes DX-472
- Remove rollupTypes which doesn't work with nested entry points
- Remove preserveModules which leaked internal workspace paths
- Add fixDtsExports plugin to remove erroneous 'export {}' from .d.ts files
- Export v2 SDK as @storyblok/react/next, /next/rsc, /next/client
- Remove rollupTypes (incompatible with nested entries)
- Remove preserveModules (leaked workspace paths)
- Keep source in src/v2/, export as /next for experimentation
- Add ComponentEntry type for component config with fallback options
- Auto-detect React.lazy components and wrap in Suspense
- Add per-component fallback option for custom loading states
- Add global suspenseFallback config for default loading UI
- Add suspense option to force Suspense wrapping for async components
@github-actions

Copy link
Copy Markdown
Contributor

⚠️ Cross-package changes detected

This PR is titled as a feat(react) commit but modifies files across 9 packages:

  • packages/angular/
  • packages/astro/
  • packages/capi-client/
  • packages/cli/
  • packages/eslint-config/
  • packages/js/
  • packages/js-client/
  • packages/live-preview/
  • packages/mapi-client/

When this PR is squash-merged, all changes become a single feat(react) commit.
Nx release uses file changes (not the commit scope) to determine which packages to bump,
so every package listed above will get a version bump on the next release.

If the changes to other packages are cosmetic (README fixes, dependency bumps, config cleanup),
please split them into a separate PR with a chore: title. chore commits don't trigger version bumps.

…mponent types

- Add `StoryblokComponentProps<T>` helper interface to simplify typing blok components
- Introduce `AnyBlokComponent` internal type to avoid contravariance errors when registering components with specific blok shapes
- Export `ComponentEntry`, `RegistryConfig`, and `RegistryResult` types from v2 index
…reaming

Passing async Server Component output as initialContent prop + useState
forced the RSC serializer to fully await all async components before
sending the payload, bypassing Suspense boundaries and blocking the
initial page response (TTFB) for the full duration of any slow
async component.

Using children keeps the RSC subtree in the server stream where
Suspense works correctly. The component now tracks editor updates in
a separate updatedContent state (null until the first editor event),
rendering updatedContent ?? children.

Also fix pre-existing lint errors in guide.md (one-liner if statements,
Unicode ellipsis in code block, missing braces).
Without debouncing, every editor keystroke fires a Server Action call.
If the component tree contains a slow async Server Component (e.g. an
external API fetch), each keystroke can trigger a redundant 10-second
request — and if the user edits a field that is part of the cache key
(e.g. a location name), each intermediate value starts its own fetch.

Add a debounceMs prop (default 300 ms) that cancels the pending re-
render timer on each new editor event and only fires the Server Action
after the user pauses. The timer is cleared on unmount so no stale
updates can arrive after the component is removed.
- Bump install snippet to fc8fac6 (latest)
- Section 2: update page.tsx example to use children syntax
- Section 4: full rewrite documenting children prop, debounceMs prop,
  and the reasoning behind each — why children preserves RSC streaming
  (named prop + useState forces the serialiser to await all async
  components, bypassing Suspense) and why debounce avoids firing a
  Server Action on every keystroke
- Section 5: expand caching table from 3 to 4 layers (add LRUCache and
  inFlightDraftFetches rows); update code example to reflect the
  lru-cache implementation with TTL + max-size cap
…yblokPreview

Previously the Suspense fallback was always `children` (the original SSR
snapshot). After a first renderContent call resolved and the user made a
second edit, the page would jump back to stale content while the new render
was in flight.

Fix: add `fallback` state (starts as `children`) and advance it via an
onCommit callback in LiveContent each time use(promise) resolves. Subsequent
editor updates now show the most-recently committed content as the fallback
instead of reverting to the original SSR tree.
… RSC streaming

Storing `children` in useState forces the RSC serialiser to fully await
every async component in the subtree before committing the initial state
value. With a component like WeatherWidget (10 s fetch) in the tree this
blocked the entire initial HTML response, causing a blank page for the full
duration of the slowest component — exactly what useState<ReactNode> does
according to the guide.

Fix: initialise committedContent to null instead of children.

The Suspense fallback now uses `committedContent ?? children`:
- Before the first renderContent resolves: children is read directly from
  the prop (never from state), keeping it inside React's RSC streaming
  channel so Suspense boundaries fire normally.
- After the first renderContent resolves: committedContent holds the
  server-rendered output (fully resolved, safe in state). Subsequent
  editor updates show the latest committed state as the fallback instead
  of reverting to the original SSR snapshot.
…d playground link

- Bump install URL to pkg.pr.new/@storyblok/reacta76b1c7
- Add playground repo link (dipankarmaikap/nextjs-storyblok-react-sdk-v2)
- Replace draftMode() cookie approach with two-deployment isPreview strategy
  (STORYBLOK_ENV=preview env var; network-first cache on preview deployment)
- Rewrite page rendering section: catch-all [[...slug]] route, Next.js 16
  async params pattern, StoryContent single-source-of-truth component
- Simplify WeatherWidget caching: remove LRU + inFlightDraftFetches draft
  path; use unstable_cache on both deployments (weather is external/independent)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants