Adds Redux and React-Intl to storybook (#35094)

This commit is contained in:
Echo 2025-06-24 11:31:27 +02:00 committed by GitHub
parent c4128d89c9
commit 8ee8231a43
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 876 additions and 53 deletions

View File

@ -11,6 +11,7 @@ const config: StorybookConfig = {
name: '@storybook/react-vite', name: '@storybook/react-vite',
options: {}, options: {},
}, },
staticDirs: ['./static'],
}; };
export default config; export default config;

View File

@ -1,29 +0,0 @@
import type { Preview } from '@storybook/react-vite';
// If you want to run the dark theme during development,
// you can change the below to `/application.scss`
import '../app/javascript/styles/mastodon-light.scss';
const preview: Preview = {
// Auto-generate docs: https://storybook.js.org/docs/writing-docs/autodocs
tags: ['autodocs'],
parameters: {
layout: 'centered',
controls: {
matchers: {
color: /(background|color)$/i,
date: /Date$/i,
},
},
a11y: {
// 'todo' - show a11y violations in the test UI only
// 'error' - fail CI on a11y violations
// 'off' - skip a11y checks entirely
test: 'todo',
},
},
};
export default preview;

136
.storybook/preview.tsx Normal file
View File

@ -0,0 +1,136 @@
import { useEffect, useState } from 'react';
import { IntlProvider } from 'react-intl';
import { configureStore } from '@reduxjs/toolkit';
import { Provider } from 'react-redux';
import type { Preview } from '@storybook/react-vite';
import { http, passthrough } from 'msw';
import { initialize, mswLoader } from 'msw-storybook-addon';
import type { LocaleData } from '@/mastodon/locales';
import { reducerWithInitialState, rootReducer } from '@/mastodon/reducers';
import { defaultMiddleware } from '@/mastodon/store/store';
// If you want to run the dark theme during development,
// you can change the below to `/application.scss`
import '../app/javascript/styles/mastodon-light.scss';
const localeFiles = import.meta.glob('@/mastodon/locales/*.json', {
query: { as: 'json' },
});
// Initialize MSW
initialize();
const preview: Preview = {
// Auto-generate docs: https://storybook.js.org/docs/writing-docs/autodocs
tags: ['autodocs'],
globalTypes: {
locale: {
description: 'Locale for the story',
toolbar: {
title: 'Locale',
icon: 'globe',
items: Object.keys(localeFiles).map((path) =>
path.replace('/mastodon/locales/', '').replace('.json', ''),
),
dynamicTitle: true,
},
},
},
initialGlobals: {
locale: 'en',
},
decorators: [
(Story, { parameters }) => {
const { state = {} } = parameters;
let reducer = rootReducer;
if (typeof state === 'object' && state) {
reducer = reducerWithInitialState(state as Record<string, unknown>);
}
const store = configureStore({
reducer,
middleware(getDefaultMiddleware) {
return getDefaultMiddleware(defaultMiddleware);
},
});
return (
<Provider store={store}>
<Story />
</Provider>
);
},
(Story, { globals }) => {
const currentLocale = (globals.locale as string) || 'en';
const [messages, setMessages] = useState<
Record<string, Record<string, string>>
>({});
const currentLocaleData = messages[currentLocale];
useEffect(() => {
async function loadLocaleData() {
const { default: localeFile } = (await import(
`@/mastodon/locales/${currentLocale}.json`
)) as { default: LocaleData['messages'] };
setMessages((prevLocales) => ({
...prevLocales,
[currentLocale]: localeFile,
}));
}
if (!currentLocaleData) {
void loadLocaleData();
}
}, [currentLocale, currentLocaleData]);
return (
<IntlProvider
locale={currentLocale}
messages={currentLocaleData}
textComponent='span'
>
<Story />
</IntlProvider>
);
},
],
loaders: [mswLoader],
parameters: {
layout: 'centered',
controls: {
matchers: {
color: /(background|color)$/i,
date: /Date$/i,
},
},
a11y: {
// 'todo' - show a11y violations in the test UI only
// 'error' - fail CI on a11y violations
// 'off' - skip a11y checks entirely
test: 'todo',
},
state: {},
// Force docs to use an iframe as it breaks MSW handlers.
// See: https://github.com/mswjs/msw-storybook-addon/issues/83
docs: {
story: {
inline: false,
},
},
msw: {
handlers: [
http.get('/index.json', passthrough),
http.get('/packs-dev/*', passthrough),
http.get('/sounds/*', passthrough),
],
},
},
};
export default preview;

View File

@ -0,0 +1,344 @@
/* eslint-disable */
/* tslint:disable */
/**
* Mock Service Worker.
* @see https://github.com/mswjs/msw
* - Please do NOT modify this file.
*/
const PACKAGE_VERSION = '2.10.2'
const INTEGRITY_CHECKSUM = 'f5825c521429caf22a4dd13b66e243af'
const IS_MOCKED_RESPONSE = Symbol('isMockedResponse')
const activeClientIds = new Set()
addEventListener('install', function () {
self.skipWaiting()
})
addEventListener('activate', function (event) {
event.waitUntil(self.clients.claim())
})
addEventListener('message', async function (event) {
const clientId = Reflect.get(event.source || {}, 'id')
if (!clientId || !self.clients) {
return
}
const client = await self.clients.get(clientId)
if (!client) {
return
}
const allClients = await self.clients.matchAll({
type: 'window',
})
switch (event.data) {
case 'KEEPALIVE_REQUEST': {
sendToClient(client, {
type: 'KEEPALIVE_RESPONSE',
})
break
}
case 'INTEGRITY_CHECK_REQUEST': {
sendToClient(client, {
type: 'INTEGRITY_CHECK_RESPONSE',
payload: {
packageVersion: PACKAGE_VERSION,
checksum: INTEGRITY_CHECKSUM,
},
})
break
}
case 'MOCK_ACTIVATE': {
activeClientIds.add(clientId)
sendToClient(client, {
type: 'MOCKING_ENABLED',
payload: {
client: {
id: client.id,
frameType: client.frameType,
},
},
})
break
}
case 'MOCK_DEACTIVATE': {
activeClientIds.delete(clientId)
break
}
case 'CLIENT_CLOSED': {
activeClientIds.delete(clientId)
const remainingClients = allClients.filter((client) => {
return client.id !== clientId
})
// Unregister itself when there are no more clients
if (remainingClients.length === 0) {
self.registration.unregister()
}
break
}
}
})
addEventListener('fetch', function (event) {
// Bypass navigation requests.
if (event.request.mode === 'navigate') {
return
}
// Opening the DevTools triggers the "only-if-cached" request
// that cannot be handled by the worker. Bypass such requests.
if (
event.request.cache === 'only-if-cached' &&
event.request.mode !== 'same-origin'
) {
return
}
// Bypass all requests when there are no active clients.
// Prevents the self-unregistered worked from handling requests
// after it's been deleted (still remains active until the next reload).
if (activeClientIds.size === 0) {
return
}
const requestId = crypto.randomUUID()
event.respondWith(handleRequest(event, requestId))
})
/**
* @param {FetchEvent} event
* @param {string} requestId
*/
async function handleRequest(event, requestId) {
const client = await resolveMainClient(event)
const requestCloneForEvents = event.request.clone()
const response = await getResponse(event, client, requestId)
// Send back the response clone for the "response:*" life-cycle events.
// Ensure MSW is active and ready to handle the message, otherwise
// this message will pend indefinitely.
if (client && activeClientIds.has(client.id)) {
const serializedRequest = await serializeRequest(requestCloneForEvents)
// Clone the response so both the client and the library could consume it.
const responseClone = response.clone()
sendToClient(
client,
{
type: 'RESPONSE',
payload: {
isMockedResponse: IS_MOCKED_RESPONSE in response,
request: {
id: requestId,
...serializedRequest,
},
response: {
type: responseClone.type,
status: responseClone.status,
statusText: responseClone.statusText,
headers: Object.fromEntries(responseClone.headers.entries()),
body: responseClone.body,
},
},
},
responseClone.body ? [serializedRequest.body, responseClone.body] : [],
)
}
return response
}
/**
* Resolve the main client for the given event.
* Client that issues a request doesn't necessarily equal the client
* that registered the worker. It's with the latter the worker should
* communicate with during the response resolving phase.
* @param {FetchEvent} event
* @returns {Promise<Client | undefined>}
*/
async function resolveMainClient(event) {
const client = await self.clients.get(event.clientId)
if (activeClientIds.has(event.clientId)) {
return client
}
if (client?.frameType === 'top-level') {
return client
}
const allClients = await self.clients.matchAll({
type: 'window',
})
return allClients
.filter((client) => {
// Get only those clients that are currently visible.
return client.visibilityState === 'visible'
})
.find((client) => {
// Find the client ID that's recorded in the
// set of clients that have registered the worker.
return activeClientIds.has(client.id)
})
}
/**
* @param {FetchEvent} event
* @param {Client | undefined} client
* @param {string} requestId
* @returns {Promise<Response>}
*/
async function getResponse(event, client, requestId) {
// Clone the request because it might've been already used
// (i.e. its body has been read and sent to the client).
const requestClone = event.request.clone()
function passthrough() {
// Cast the request headers to a new Headers instance
// so the headers can be manipulated with.
const headers = new Headers(requestClone.headers)
// Remove the "accept" header value that marked this request as passthrough.
// This prevents request alteration and also keeps it compliant with the
// user-defined CORS policies.
const acceptHeader = headers.get('accept')
if (acceptHeader) {
const values = acceptHeader.split(',').map((value) => value.trim())
const filteredValues = values.filter(
(value) => value !== 'msw/passthrough',
)
if (filteredValues.length > 0) {
headers.set('accept', filteredValues.join(', '))
} else {
headers.delete('accept')
}
}
return fetch(requestClone, { headers })
}
// Bypass mocking when the client is not active.
if (!client) {
return passthrough()
}
// Bypass initial page load requests (i.e. static assets).
// The absence of the immediate/parent client in the map of the active clients
// means that MSW hasn't dispatched the "MOCK_ACTIVATE" event yet
// and is not ready to handle requests.
if (!activeClientIds.has(client.id)) {
return passthrough()
}
// Notify the client that a request has been intercepted.
const serializedRequest = await serializeRequest(event.request)
const clientMessage = await sendToClient(
client,
{
type: 'REQUEST',
payload: {
id: requestId,
...serializedRequest,
},
},
[serializedRequest.body],
)
switch (clientMessage.type) {
case 'MOCK_RESPONSE': {
return respondWithMock(clientMessage.data)
}
case 'PASSTHROUGH': {
return passthrough()
}
}
return passthrough()
}
/**
* @param {Client} client
* @param {any} message
* @param {Array<Transferable>} transferrables
* @returns {Promise<any>}
*/
function sendToClient(client, message, transferrables = []) {
return new Promise((resolve, reject) => {
const channel = new MessageChannel()
channel.port1.onmessage = (event) => {
if (event.data && event.data.error) {
return reject(event.data.error)
}
resolve(event.data)
}
client.postMessage(message, [
channel.port2,
...transferrables.filter(Boolean),
])
})
}
/**
* @param {Response} response
* @returns {Response}
*/
function respondWithMock(response) {
// Setting response status code to 0 is a no-op.
// However, when responding with a "Response.error()", the produced Response
// instance will have status code set to 0. Since it's not possible to create
// a Response instance with status code 0, handle that use-case separately.
if (response.status === 0) {
return Response.error()
}
const mockedResponse = new Response(response.body, response)
Reflect.defineProperty(mockedResponse, IS_MOCKED_RESPONSE, {
value: true,
enumerable: true,
})
return mockedResponse
}
/**
* @param {Request} request
*/
async function serializeRequest(request) {
return {
url: request.url,
mode: request.mode,
method: request.method,
headers: Object.fromEntries(request.headers.entries()),
cache: request.cache,
credentials: request.credentials,
destination: request.destination,
integrity: request.integrity,
redirect: request.redirect,
referrer: request.referrer,
referrerPolicy: request.referrerPolicy,
body: await request.arrayBuffer(),
keepalive: request.keepalive,
}
}

View File

@ -36,7 +36,8 @@ export default meta;
type Story = StoryObj<typeof meta>; type Story = StoryObj<typeof meta>;
const buttonTest: Story['play'] = async ({ args, canvas, userEvent }) => { const buttonTest: Story['play'] = async ({ args, canvas, userEvent }) => {
await userEvent.click(canvas.getByRole('button')); const button = await canvas.findByRole('button');
await userEvent.click(button);
await expect(args.onClick).toHaveBeenCalled(); await expect(args.onClick).toHaveBeenCalled();
}; };
@ -45,7 +46,8 @@ const disabledButtonTest: Story['play'] = async ({
canvas, canvas,
userEvent, userEvent,
}) => { }) => {
await userEvent.click(canvas.getByRole('button')); const button = await canvas.findByRole('button');
await userEvent.click(button);
await expect(args.onClick).not.toHaveBeenCalled(); await expect(args.onClick).not.toHaveBeenCalled();
}; };

View File

@ -1,4 +1,4 @@
import { Record as ImmutableRecord } from 'immutable'; import { Record as ImmutableRecord, mergeDeep } from 'immutable';
import { loadingBarReducer } from 'react-redux-loading-bar'; import { loadingBarReducer } from 'react-redux-loading-bar';
import { combineReducers } from 'redux-immutable'; import { combineReducers } from 'redux-immutable';
@ -98,6 +98,15 @@ const initialRootState = Object.fromEntries(
const RootStateRecord = ImmutableRecord(initialRootState, 'RootState'); const RootStateRecord = ImmutableRecord(initialRootState, 'RootState');
const rootReducer = combineReducers(reducers, RootStateRecord); export const rootReducer = combineReducers(reducers, RootStateRecord);
export { rootReducer }; export function reducerWithInitialState(
stateOverrides: Record<string, unknown> = {},
) {
const initialStateRecord = mergeDeep(initialRootState, stateOverrides);
const PatchedRootStateRecord = ImmutableRecord(
initialStateRecord,
'RootState',
);
return combineReducers(reducers, PatchedRootStateRecord);
}

View File

@ -6,24 +6,26 @@ import { errorsMiddleware } from './middlewares/errors';
import { loadingBarMiddleware } from './middlewares/loading_bar'; import { loadingBarMiddleware } from './middlewares/loading_bar';
import { soundsMiddleware } from './middlewares/sounds'; import { soundsMiddleware } from './middlewares/sounds';
export const defaultMiddleware = {
// In development, Redux Toolkit enables 2 default middlewares to detect
// common issues with states. Unfortunately, our use of ImmutableJS for state
// triggers both, so lets disable them until our state is fully refactored
// https://redux-toolkit.js.org/api/serializabilityMiddleware
// This checks recursively that every values in the state are serializable in JSON
// Which is not the case, as we use ImmutableJS structures, but also File objects
serializableCheck: false,
// https://redux-toolkit.js.org/api/immutabilityMiddleware
// This checks recursively if every value in the state is immutable (ie, a JS primitive type)
// But this is not the case, as our Root State is an ImmutableJS map, which is an object
immutableCheck: false,
} as const;
export const store = configureStore({ export const store = configureStore({
reducer: rootReducer, reducer: rootReducer,
middleware: (getDefaultMiddleware) => middleware: (getDefaultMiddleware) =>
getDefaultMiddleware({ getDefaultMiddleware(defaultMiddleware)
// In development, Redux Toolkit enables 2 default middlewares to detect
// common issues with states. Unfortunately, our use of ImmutableJS for state
// triggers both, so lets disable them until our state is fully refactored
// https://redux-toolkit.js.org/api/serializabilityMiddleware
// This checks recursively that every values in the state are serializable in JSON
// Which is not the case, as we use ImmutableJS structures, but also File objects
serializableCheck: false,
// https://redux-toolkit.js.org/api/immutabilityMiddleware
// This checks recursively if every value in the state is immutable (ie, a JS primitive type)
// But this is not the case, as our Root State is an ImmutableJS map, which is an object
immutableCheck: false,
})
.concat( .concat(
loadingBarMiddleware({ loadingBarMiddleware({
promiseTypeSuffixes: ['REQUEST', 'SUCCESS', 'FAIL'], promiseTypeSuffixes: ['REQUEST', 'SUCCESS', 'FAIL'],

View File

@ -258,7 +258,7 @@ export default tseslint.config([
'app/javascript/**/*.stories.tsx', 'app/javascript/**/*.stories.tsx',
'app/javascript/**/*.test.ts', 'app/javascript/**/*.test.ts',
'app/javascript/**/*.test.tsx', 'app/javascript/**/*.test.tsx',
'.storybook/**/*.ts', '.storybook/**/*',
], ],
}, },
], ],
@ -406,7 +406,7 @@ export default tseslint.config([
}, },
}, },
{ {
files: ['**/*.stories.ts', '**/*.stories.tsx', '.storybook/**/*.ts'], files: ['**/*.stories.ts', '**/*.stories.tsx', '.storybook/*'],
rules: { rules: {
'import/no-default-export': 'off', 'import/no-default-export': 'off',
}, },

View File

@ -172,6 +172,8 @@
"globals": "^16.0.0", "globals": "^16.0.0",
"husky": "^9.0.11", "husky": "^9.0.11",
"lint-staged": "^16.0.0", "lint-staged": "^16.0.0",
"msw": "^2.10.2",
"msw-storybook-addon": "^2.0.5",
"playwright": "^1.52.0", "playwright": "^1.52.0",
"prettier": "^3.3.3", "prettier": "^3.3.3",
"react-test-renderer": "^18.2.0", "react-test-renderer": "^18.2.0",
@ -202,5 +204,10 @@
"react-router-dom": { "react-router-dom": {
"optional": true "optional": true
} }
},
"msw": {
"workerDirectory": [
".storybook/static"
]
} }
} }

355
yarn.lock
View File

@ -1189,6 +1189,34 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"@bundled-es-modules/cookie@npm:^2.0.1":
version: 2.0.1
resolution: "@bundled-es-modules/cookie@npm:2.0.1"
dependencies:
cookie: "npm:^0.7.2"
checksum: 10c0/dfac5e36127e827c5557b8577f17a8aa94c057baff6d38555917927b99da0ecf0b1357e7fedadc8853ecdbd4a8a7fa1f5e64111b2a656612f4a36376f5bdbe8d
languageName: node
linkType: hard
"@bundled-es-modules/statuses@npm:^1.0.1":
version: 1.0.1
resolution: "@bundled-es-modules/statuses@npm:1.0.1"
dependencies:
statuses: "npm:^2.0.1"
checksum: 10c0/c1a8ede3efa8da61ccda4b98e773582a9733edfbeeee569d4630785f8e018766202edb190a754a3ec7a7f6bd738e857829affc2fdb676b6dab4db1bb44e62785
languageName: node
linkType: hard
"@bundled-es-modules/tough-cookie@npm:^0.1.6":
version: 0.1.6
resolution: "@bundled-es-modules/tough-cookie@npm:0.1.6"
dependencies:
"@types/tough-cookie": "npm:^4.0.5"
tough-cookie: "npm:^4.1.4"
checksum: 10c0/28bcac878bff6b34719ba3aa8341e9924772ee55de5487680ebe784981ec9fccb70ed5d46f563e2404855a04de606f9e56aa4202842d4f5835bc04a4fe820571
languageName: node
linkType: hard
"@csstools/cascade-layer-name-parser@npm:^2.0.5": "@csstools/cascade-layer-name-parser@npm:^2.0.5":
version: 2.0.5 version: 2.0.5
resolution: "@csstools/cascade-layer-name-parser@npm:2.0.5" resolution: "@csstools/cascade-layer-name-parser@npm:2.0.5"
@ -2412,6 +2440,61 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"@inquirer/confirm@npm:^5.0.0":
version: 5.1.12
resolution: "@inquirer/confirm@npm:5.1.12"
dependencies:
"@inquirer/core": "npm:^10.1.13"
"@inquirer/type": "npm:^3.0.7"
peerDependencies:
"@types/node": ">=18"
peerDependenciesMeta:
"@types/node":
optional: true
checksum: 10c0/581aedfe8ce45e177fb4470a12f874f5162a4396636bf4140edc5812ffc8ed0d1fa7e9bbc3a7af618203089a084f489e0b32112947eedc6930a766fad992449e
languageName: node
linkType: hard
"@inquirer/core@npm:^10.1.13":
version: 10.1.13
resolution: "@inquirer/core@npm:10.1.13"
dependencies:
"@inquirer/figures": "npm:^1.0.12"
"@inquirer/type": "npm:^3.0.7"
ansi-escapes: "npm:^4.3.2"
cli-width: "npm:^4.1.0"
mute-stream: "npm:^2.0.0"
signal-exit: "npm:^4.1.0"
wrap-ansi: "npm:^6.2.0"
yoctocolors-cjs: "npm:^2.1.2"
peerDependencies:
"@types/node": ">=18"
peerDependenciesMeta:
"@types/node":
optional: true
checksum: 10c0/919208a31307297d5a07a44b9ebe69a999ce1470b31a2e1b5a04538bc36624d2053808cd6c677637a61690af09bdbdd635bd7031b64e3dd86c5b18df3ca7c3f9
languageName: node
linkType: hard
"@inquirer/figures@npm:^1.0.12":
version: 1.0.12
resolution: "@inquirer/figures@npm:1.0.12"
checksum: 10c0/08694288bdf9aa474571ca94272113a5ac443229519ce71447eba9eb7d5a2007901bdc3e92216d929a69746dcbac29683886c20e67b7864a7c7f6c59b99d3269
languageName: node
linkType: hard
"@inquirer/type@npm:^3.0.7":
version: 3.0.7
resolution: "@inquirer/type@npm:3.0.7"
peerDependencies:
"@types/node": ">=18"
peerDependenciesMeta:
"@types/node":
optional: true
checksum: 10c0/bbaa33c274a10f70d3a587264e1db6dbfcd8c1458d595c54870d1d5b3fc113ab5063203ec12a098485bb9e2fcef1a87d8c6ecd2a6d44ddc575f5c4715379be5e
languageName: node
linkType: hard
"@ioredis/commands@npm:^1.1.1": "@ioredis/commands@npm:^1.1.1":
version: 1.2.0 version: 1.2.0
resolution: "@ioredis/commands@npm:1.2.0" resolution: "@ioredis/commands@npm:1.2.0"
@ -2608,6 +2691,8 @@ __metadata:
lint-staged: "npm:^16.0.0" lint-staged: "npm:^16.0.0"
lodash: "npm:^4.17.21" lodash: "npm:^4.17.21"
marky: "npm:^1.2.5" marky: "npm:^1.2.5"
msw: "npm:^2.10.2"
msw-storybook-addon: "npm:^2.0.5"
path-complete-extname: "npm:^1.0.0" path-complete-extname: "npm:^1.0.0"
playwright: "npm:^1.52.0" playwright: "npm:^1.52.0"
postcss-preset-env: "npm:^10.1.5" postcss-preset-env: "npm:^10.1.5"
@ -2721,6 +2806,20 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"@mswjs/interceptors@npm:^0.39.1":
version: 0.39.2
resolution: "@mswjs/interceptors@npm:0.39.2"
dependencies:
"@open-draft/deferred-promise": "npm:^2.2.0"
"@open-draft/logger": "npm:^0.3.0"
"@open-draft/until": "npm:^2.0.0"
is-node-process: "npm:^1.2.0"
outvariant: "npm:^1.4.3"
strict-event-emitter: "npm:^0.5.1"
checksum: 10c0/5698e33930a6b6e7cc78cf762291be60c91c6348faa22750acc41ef41528e7891e74541ccfb668ba470d964233fd2121c44d0224a2917eedeba2459cf0b78ca2
languageName: node
linkType: hard
"@napi-rs/wasm-runtime@npm:^0.2.7": "@napi-rs/wasm-runtime@npm:^0.2.7":
version: 0.2.7 version: 0.2.7
resolution: "@napi-rs/wasm-runtime@npm:0.2.7" resolution: "@napi-rs/wasm-runtime@npm:0.2.7"
@ -2781,6 +2880,30 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"@open-draft/deferred-promise@npm:^2.2.0":
version: 2.2.0
resolution: "@open-draft/deferred-promise@npm:2.2.0"
checksum: 10c0/eafc1b1d0fc8edb5e1c753c5e0f3293410b40dde2f92688211a54806d4136887051f39b98c1950370be258483deac9dfd17cf8b96557553765198ef2547e4549
languageName: node
linkType: hard
"@open-draft/logger@npm:^0.3.0":
version: 0.3.0
resolution: "@open-draft/logger@npm:0.3.0"
dependencies:
is-node-process: "npm:^1.2.0"
outvariant: "npm:^1.4.0"
checksum: 10c0/90010647b22e9693c16258f4f9adb034824d1771d3baa313057b9a37797f571181005bc50415a934eaf7c891d90ff71dcd7a9d5048b0b6bb438f31bef2c7c5c1
languageName: node
linkType: hard
"@open-draft/until@npm:^2.0.0, @open-draft/until@npm:^2.1.0":
version: 2.1.0
resolution: "@open-draft/until@npm:2.1.0"
checksum: 10c0/61d3f99718dd86bb393fee2d7a785f961dcaf12f2055f0c693b27f4d0cd5f7a03d498a6d9289773b117590d794a43cd129366fd8e99222e4832f67b1653d54cf
languageName: node
linkType: hard
"@opentelemetry/api@npm:^1.4.0": "@opentelemetry/api@npm:^1.4.0":
version: 1.6.0 version: 1.6.0
resolution: "@opentelemetry/api@npm:1.6.0" resolution: "@opentelemetry/api@npm:1.6.0"
@ -3786,6 +3909,13 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"@types/cookie@npm:^0.6.0":
version: 0.6.0
resolution: "@types/cookie@npm:0.6.0"
checksum: 10c0/5b326bd0188120fb32c0be086b141b1481fec9941b76ad537f9110e10d61ee2636beac145463319c71e4be67a17e85b81ca9e13ceb6e3bb63b93d16824d6c149
languageName: node
linkType: hard
"@types/cors@npm:^2.8.16": "@types/cors@npm:^2.8.16":
version: 2.8.18 version: 2.8.18
resolution: "@types/cors@npm:2.8.18" resolution: "@types/cors@npm:2.8.18"
@ -4201,6 +4331,20 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"@types/statuses@npm:^2.0.4":
version: 2.0.6
resolution: "@types/statuses@npm:2.0.6"
checksum: 10c0/dd88c220b0e2c6315686289525fd61472d2204d2e4bef4941acfb76bda01d3066f749ac74782aab5b537a45314fcd7d6261eefa40b6ec872691f5803adaa608d
languageName: node
linkType: hard
"@types/tough-cookie@npm:^4.0.5":
version: 4.0.5
resolution: "@types/tough-cookie@npm:4.0.5"
checksum: 10c0/68c6921721a3dcb40451543db2174a145ef915bc8bcbe7ad4e59194a0238e776e782b896c7a59f4b93ac6acefca9161fccb31d1ce3b3445cb6faa467297fb473
languageName: node
linkType: hard
"@types/trusted-types@npm:^2.0.2": "@types/trusted-types@npm:^2.0.2":
version: 2.0.3 version: 2.0.3
resolution: "@types/trusted-types@npm:2.0.3" resolution: "@types/trusted-types@npm:2.0.3"
@ -4882,6 +5026,15 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"ansi-escapes@npm:^4.3.2":
version: 4.3.2
resolution: "ansi-escapes@npm:4.3.2"
dependencies:
type-fest: "npm:^0.21.3"
checksum: 10c0/da917be01871525a3dfcf925ae2977bc59e8c513d4423368645634bf5d4ceba5401574eb705c1e92b79f7292af5a656f78c5725a4b0e1cec97c4b413705c1d50
languageName: node
linkType: hard
"ansi-escapes@npm:^7.0.0": "ansi-escapes@npm:^7.0.0":
version: 7.0.0 version: 7.0.0
resolution: "ansi-escapes@npm:7.0.0" resolution: "ansi-escapes@npm:7.0.0"
@ -5658,6 +5811,13 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"cli-width@npm:^4.1.0":
version: 4.1.0
resolution: "cli-width@npm:4.1.0"
checksum: 10c0/1fbd56413578f6117abcaf858903ba1f4ad78370a4032f916745fa2c7e390183a9d9029cf837df320b0fdce8137668e522f60a30a5f3d6529ff3872d265a955f
languageName: node
linkType: hard
"cliui@npm:^8.0.1": "cliui@npm:^8.0.1":
version: 8.0.1 version: 8.0.1
resolution: "cliui@npm:8.0.1" resolution: "cliui@npm:8.0.1"
@ -5808,6 +5968,13 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"cookie@npm:^0.7.2":
version: 0.7.2
resolution: "cookie@npm:0.7.2"
checksum: 10c0/9596e8ccdbf1a3a88ae02cf5ee80c1c50959423e1022e4e60b91dd87c622af1da309253d8abdb258fb5e3eacb4f08e579dc58b4897b8087574eee0fd35dfa5d2
languageName: node
linkType: hard
"core-js-compat@npm:^3.40.0": "core-js-compat@npm:^3.40.0":
version: 3.41.0 version: 3.41.0
resolution: "core-js-compat@npm:3.41.0" resolution: "core-js-compat@npm:3.41.0"
@ -7712,6 +7879,13 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"graphql@npm:^16.8.1":
version: 16.11.0
resolution: "graphql@npm:16.11.0"
checksum: 10c0/124da7860a2292e9acf2fed0c71fc0f6a9b9ca865d390d112bdd563c1f474357141501c12891f4164fe984315764736ad67f705219c62f7580681d431a85db88
languageName: node
linkType: hard
"has-bigints@npm:^1.0.2": "has-bigints@npm:^1.0.2":
version: 1.0.2 version: 1.0.2
resolution: "has-bigints@npm:1.0.2" resolution: "has-bigints@npm:1.0.2"
@ -7769,6 +7943,13 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"headers-polyfill@npm:^4.0.2":
version: 4.0.3
resolution: "headers-polyfill@npm:4.0.3"
checksum: 10c0/53e85b2c6385f8d411945fb890c5369f1469ce8aa32a6e8d28196df38568148de640c81cf88cbc7c67767103dd9acba48f4f891982da63178fc6e34560022afe
languageName: node
linkType: hard
"help-me@npm:^5.0.0": "help-me@npm:^5.0.0":
version: 5.0.0 version: 5.0.0
resolution: "help-me@npm:5.0.0" resolution: "help-me@npm:5.0.0"
@ -8263,6 +8444,13 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"is-node-process@npm:^1.0.1, is-node-process@npm:^1.2.0":
version: 1.2.0
resolution: "is-node-process@npm:1.2.0"
checksum: 10c0/5b24fda6776d00e42431d7bcd86bce81cb0b6cabeb944142fe7b077a54ada2e155066ad06dbe790abdb397884bdc3151e04a9707b8cd185099efbc79780573ed
languageName: node
linkType: hard
"is-number-object@npm:^1.1.1": "is-number-object@npm:^1.1.1":
version: 1.1.1 version: 1.1.1
resolution: "is-number-object@npm:1.1.1" resolution: "is-number-object@npm:1.1.1"
@ -9343,6 +9531,57 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"msw-storybook-addon@npm:^2.0.5":
version: 2.0.5
resolution: "msw-storybook-addon@npm:2.0.5"
dependencies:
is-node-process: "npm:^1.0.1"
peerDependencies:
msw: ^2.0.0
checksum: 10c0/3f26fd4a8a6b1b4da165a8940eca4da2e175a69036a1c85c07ec1952fbb595252db689c4380d8f88ec1cfaa66a6696e90ef0c26b2d1bf17c30092b81247d1d40
languageName: node
linkType: hard
"msw@npm:^2.10.2":
version: 2.10.2
resolution: "msw@npm:2.10.2"
dependencies:
"@bundled-es-modules/cookie": "npm:^2.0.1"
"@bundled-es-modules/statuses": "npm:^1.0.1"
"@bundled-es-modules/tough-cookie": "npm:^0.1.6"
"@inquirer/confirm": "npm:^5.0.0"
"@mswjs/interceptors": "npm:^0.39.1"
"@open-draft/deferred-promise": "npm:^2.2.0"
"@open-draft/until": "npm:^2.1.0"
"@types/cookie": "npm:^0.6.0"
"@types/statuses": "npm:^2.0.4"
graphql: "npm:^16.8.1"
headers-polyfill: "npm:^4.0.2"
is-node-process: "npm:^1.2.0"
outvariant: "npm:^1.4.3"
path-to-regexp: "npm:^6.3.0"
picocolors: "npm:^1.1.1"
strict-event-emitter: "npm:^0.5.1"
type-fest: "npm:^4.26.1"
yargs: "npm:^17.7.2"
peerDependencies:
typescript: ">= 4.8.x"
peerDependenciesMeta:
typescript:
optional: true
bin:
msw: cli/index.js
checksum: 10c0/fb44961e17e12864b4764b4c015f6ce7c907081f8dcd237ecd635eab00b787847406fbd36a2bcf2ef4c21114a3610ac03c7f93f3080f509a69b0c1c5285fd683
languageName: node
linkType: hard
"mute-stream@npm:^2.0.0":
version: 2.0.0
resolution: "mute-stream@npm:2.0.0"
checksum: 10c0/2cf48a2087175c60c8dcdbc619908b49c07f7adcfc37d29236b0c5c612d6204f789104c98cc44d38acab7b3c96f4a3ec2cfdc4934d0738d876dbefa2a12c69f4
languageName: node
linkType: hard
"nano-spawn@npm:^1.0.0": "nano-spawn@npm:^1.0.0":
version: 1.0.1 version: 1.0.1
resolution: "nano-spawn@npm:1.0.1" resolution: "nano-spawn@npm:1.0.1"
@ -9625,6 +9864,13 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"outvariant@npm:^1.4.0, outvariant@npm:^1.4.3":
version: 1.4.3
resolution: "outvariant@npm:1.4.3"
checksum: 10c0/5976ca7740349cb8c71bd3382e2a762b1aeca6f33dc984d9d896acdf3c61f78c3afcf1bfe9cc633a7b3c4b295ec94d292048f83ea2b2594fae4496656eba992c
languageName: node
linkType: hard
"own-keys@npm:^1.0.1": "own-keys@npm:^1.0.1":
version: 1.0.1 version: 1.0.1
resolution: "own-keys@npm:1.0.1" resolution: "own-keys@npm:1.0.1"
@ -9778,6 +10024,13 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"path-to-regexp@npm:^6.3.0":
version: 6.3.0
resolution: "path-to-regexp@npm:6.3.0"
checksum: 10c0/73b67f4638b41cde56254e6354e46ae3a2ebc08279583f6af3d96fe4664fc75788f74ed0d18ca44fa4a98491b69434f9eee73b97bb5314bd1b5adb700f5c18d6
languageName: node
linkType: hard
"path-type@npm:^4.0.0": "path-type@npm:^4.0.0":
version: 4.0.0 version: 4.0.0
resolution: "path-type@npm:4.0.0" resolution: "path-type@npm:4.0.0"
@ -10580,6 +10833,15 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"psl@npm:^1.1.33":
version: 1.15.0
resolution: "psl@npm:1.15.0"
dependencies:
punycode: "npm:^2.3.1"
checksum: 10c0/d8d45a99e4ca62ca12ac3c373e63d80d2368d38892daa40cfddaa1eb908be98cd549ac059783ef3a56cfd96d57ae8e2fd9ae53d1378d90d42bc661ff924e102a
languageName: node
linkType: hard
"pump@npm:^3.0.0": "pump@npm:^3.0.0":
version: 3.0.0 version: 3.0.0
resolution: "pump@npm:3.0.0" resolution: "pump@npm:3.0.0"
@ -10597,7 +10859,7 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"punycode@npm:^2.1.0, punycode@npm:^2.3.0, punycode@npm:^2.3.1": "punycode@npm:^2.1.0, punycode@npm:^2.1.1, punycode@npm:^2.3.0, punycode@npm:^2.3.1":
version: 2.3.1 version: 2.3.1
resolution: "punycode@npm:2.3.1" resolution: "punycode@npm:2.3.1"
checksum: 10c0/14f76a8206bc3464f794fb2e3d3cc665ae416c01893ad7a02b23766eb07159144ee612ad67af5e84fa4479ccfe67678c4feb126b0485651b302babf66f04f9e9 checksum: 10c0/14f76a8206bc3464f794fb2e3d3cc665ae416c01893ad7a02b23766eb07159144ee612ad67af5e84fa4479ccfe67678c4feb126b0485651b302babf66f04f9e9
@ -10613,6 +10875,13 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"querystringify@npm:^2.1.1":
version: 2.2.0
resolution: "querystringify@npm:2.2.0"
checksum: 10c0/3258bc3dbdf322ff2663619afe5947c7926a6ef5fb78ad7d384602974c467fadfc8272af44f5eb8cddd0d011aae8fabf3a929a8eee4b86edcc0a21e6bd10f9aa
languageName: node
linkType: hard
"queue-microtask@npm:^1.2.2": "queue-microtask@npm:^1.2.2":
version: 1.2.3 version: 1.2.3
resolution: "queue-microtask@npm:1.2.3" resolution: "queue-microtask@npm:1.2.3"
@ -11307,6 +11576,13 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"requires-port@npm:^1.0.0":
version: 1.0.0
resolution: "requires-port@npm:1.0.0"
checksum: 10c0/b2bfdd09db16c082c4326e573a82c0771daaf7b53b9ce8ad60ea46aa6e30aaf475fe9b164800b89f93b748d2c234d8abff945d2551ba47bf5698e04cd7713267
languageName: node
linkType: hard
"reselect@npm:^5.1.0": "reselect@npm:^5.1.0":
version: 5.1.0 version: 5.1.0
resolution: "reselect@npm:5.1.0" resolution: "reselect@npm:5.1.0"
@ -12147,6 +12423,13 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"statuses@npm:^2.0.1":
version: 2.0.2
resolution: "statuses@npm:2.0.2"
checksum: 10c0/a9947d98ad60d01f6b26727570f3bcceb6c8fa789da64fe6889908fe2e294d57503b14bf2b5af7605c2d36647259e856635cd4c49eab41667658ec9d0080ec3f
languageName: node
linkType: hard
"std-env@npm:^3.9.0": "std-env@npm:^3.9.0":
version: 3.9.0 version: 3.9.0
resolution: "std-env@npm:3.9.0" resolution: "std-env@npm:3.9.0"
@ -12187,6 +12470,13 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"strict-event-emitter@npm:^0.5.1":
version: 0.5.1
resolution: "strict-event-emitter@npm:0.5.1"
checksum: 10c0/f5228a6e6b6393c57f52f62e673cfe3be3294b35d6f7842fc24b172ae0a6e6c209fa83241d0e433fc267c503bc2f4ffdbe41a9990ff8ffd5ac425ec0489417f7
languageName: node
linkType: hard
"string-argv@npm:^0.3.2": "string-argv@npm:^0.3.2":
version: 0.3.2 version: 0.3.2
resolution: "string-argv@npm:0.3.2" resolution: "string-argv@npm:0.3.2"
@ -12820,6 +13110,18 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"tough-cookie@npm:^4.1.4":
version: 4.1.4
resolution: "tough-cookie@npm:4.1.4"
dependencies:
psl: "npm:^1.1.33"
punycode: "npm:^2.1.1"
universalify: "npm:^0.2.0"
url-parse: "npm:^1.5.3"
checksum: 10c0/aca7ff96054f367d53d1e813e62ceb7dd2eda25d7752058a74d64b7266fd07be75908f3753a32ccf866a2f997604b414cfb1916d6e7f69bc64d9d9939b0d6c45
languageName: node
linkType: hard
"tough-cookie@npm:^5.1.1": "tough-cookie@npm:^5.1.1":
version: 5.1.2 version: 5.1.2
resolution: "tough-cookie@npm:5.1.2" resolution: "tough-cookie@npm:5.1.2"
@ -12956,6 +13258,20 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"type-fest@npm:^0.21.3":
version: 0.21.3
resolution: "type-fest@npm:0.21.3"
checksum: 10c0/902bd57bfa30d51d4779b641c2bc403cdf1371fb9c91d3c058b0133694fcfdb817aef07a47f40faf79039eecbaa39ee9d3c532deff244f3a19ce68cea71a61e8
languageName: node
linkType: hard
"type-fest@npm:^4.26.1":
version: 4.41.0
resolution: "type-fest@npm:4.41.0"
checksum: 10c0/f5ca697797ed5e88d33ac8f1fec21921839871f808dc59345c9cf67345bfb958ce41bd821165dbf3ae591cedec2bf6fe8882098dfdd8dc54320b859711a2c1e4
languageName: node
linkType: hard
"type-is@npm:~1.6.18": "type-is@npm:~1.6.18":
version: 1.6.18 version: 1.6.18
resolution: "type-is@npm:1.6.18" resolution: "type-is@npm:1.6.18"
@ -13173,6 +13489,13 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"universalify@npm:^0.2.0":
version: 0.2.0
resolution: "universalify@npm:0.2.0"
checksum: 10c0/cedbe4d4ca3967edf24c0800cfc161c5a15e240dac28e3ce575c689abc11f2c81ccc6532c8752af3b40f9120fb5e454abecd359e164f4f6aa44c29cd37e194fe
languageName: node
linkType: hard
"universalify@npm:^2.0.0": "universalify@npm:^2.0.0":
version: 2.0.1 version: 2.0.1
resolution: "universalify@npm:2.0.1" resolution: "universalify@npm:2.0.1"
@ -13281,6 +13604,16 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"url-parse@npm:^1.5.3":
version: 1.5.10
resolution: "url-parse@npm:1.5.10"
dependencies:
querystringify: "npm:^2.1.1"
requires-port: "npm:^1.0.0"
checksum: 10c0/bd5aa9389f896974beb851c112f63b466505a04b4807cea2e5a3b7092f6fbb75316f0491ea84e44f66fed55f1b440df5195d7e3a8203f64fcefa19d182f5be87
languageName: node
linkType: hard
"use-composed-ref@npm:^1.3.0": "use-composed-ref@npm:^1.3.0":
version: 1.3.0 version: 1.3.0
resolution: "use-composed-ref@npm:1.3.0" resolution: "use-composed-ref@npm:1.3.0"
@ -14043,6 +14376,17 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"wrap-ansi@npm:^6.2.0":
version: 6.2.0
resolution: "wrap-ansi@npm:6.2.0"
dependencies:
ansi-styles: "npm:^4.0.0"
string-width: "npm:^4.1.0"
strip-ansi: "npm:^6.0.0"
checksum: 10c0/baad244e6e33335ea24e86e51868fe6823626e3a3c88d9a6674642afff1d34d9a154c917e74af8d845fd25d170c4ea9cf69a47133c3f3656e1252b3d462d9f6c
languageName: node
linkType: hard
"wrap-ansi@npm:^8.1.0": "wrap-ansi@npm:^8.1.0":
version: 8.1.0 version: 8.1.0
resolution: "wrap-ansi@npm:8.1.0" resolution: "wrap-ansi@npm:8.1.0"
@ -14162,7 +14506,7 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"yargs@npm:^17.5.1": "yargs@npm:^17.5.1, yargs@npm:^17.7.2":
version: 17.7.2 version: 17.7.2
resolution: "yargs@npm:17.7.2" resolution: "yargs@npm:17.7.2"
dependencies: dependencies:
@ -14184,6 +14528,13 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"yoctocolors-cjs@npm:^2.1.2":
version: 2.1.2
resolution: "yoctocolors-cjs@npm:2.1.2"
checksum: 10c0/a0e36eb88fea2c7981eab22d1ba45e15d8d268626e6c4143305e2c1628fa17ebfaa40cd306161a8ce04c0a60ee0262058eab12567493d5eb1409780853454c6f
languageName: node
linkType: hard
"zlibjs@npm:^0.3.1": "zlibjs@npm:^0.3.1":
version: 0.3.1 version: 0.3.1
resolution: "zlibjs@npm:0.3.1" resolution: "zlibjs@npm:0.3.1"