Skip to content

Pull legacy @saleor/sdk into dashboard#6405

Draft
lkostrowski wants to merge 2 commits intomainfrom
lkostrowski/remove-saleor-sdk
Draft

Pull legacy @saleor/sdk into dashboard#6405
lkostrowski wants to merge 2 commits intomainfrom
lkostrowski/remove-saleor-sdk

Conversation

@lkostrowski
Copy link
Member

Scope of the change

Adds comprehensive test coverage for the legacy-sdk modules that were inlined from @saleor/sdk in the previous commit. These tests cover all core business logic: token storage and persistence, authentication flows (internal and external), user account management, and React integration.

Test coverage includes:

  • Storage: localStorage persistence, autologin initialization, token lifecycle

  • Auth: All 12 methods covering internal/external login, logout, token refresh, password management

  • User: All 10 methods for account CRUD, address management, email changes, account deletion

  • Apollo: Auth header injection, auto token refresh on expiration, expired signature retry logic

  • React: Context provider, hook factories, error handling when provider is missing

  • I confirm I added ripples for changes (see src/ripples) or my feature doesn't contain any user-facing changes

  • I used analytics "trackEvent" for important events

lkostrowski and others added 2 commits March 9, 2026 21:43
The @saleor/sdk package (v0.6.0) is deprecated and no longer maintained,
blocking independent dependency upgrades. This commit copies the SDK
source into src/legacy-sdk/ and updates all imports from @saleor/sdk
to @dashboard/legacy-sdk.

Changes:
- Copy SDK source (auth, apollo, react modules) into src/legacy-sdk/
- Update 17 files to use @dashboard/legacy-sdk imports
- Remove @saleor/sdk from package.json and pnpm-workspace.yaml
- Remove cross-fetch import (use native browser fetch)
- Fix type errors: PropsWithChildren for React 18, union type narrowing
- Fix lint errors: empty catch blocks
- Exclude legacy-sdk from codegen document scanning

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Cover all core business logic that was previously untested after
inlining @saleor/sdk into src/legacy-sdk:

- core/storage: token persistence, localStorage sync, autologin init
- core/auth: all 12 AuthSDK methods (login, logout, token refresh,
  external auth flows, password management)
- core/user: all 10 UserSDK methods (account CRUD, address management,
  email change, account deletion)
- core/helpers: permission validation
- helpers: internal token detection
- apollo/client: createFetch auth header injection, auto token refresh,
  expired signature retry logic
- react/SaleorProvider: context propagation, client updates
- react/hookFactory: hook creation, error on missing provider

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings March 9, 2026 21:14
@lkostrowski lkostrowski requested a review from a team as a code owner March 9, 2026 21:14
@lkostrowski lkostrowski requested a review from witoszekdev March 9, 2026 21:14
@changeset-bot
Copy link

changeset-bot bot commented Mar 9, 2026

⚠️ No Changeset found

Latest commit: 0de0284

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR


const setRefreshToken = (token: string | null): void => {
if (token) {
localStorage.setItem(SALEOR_REFRESH_TOKEN, token);

Check failure

Code scanning / CodeQL

Clear text storage of sensitive information High

This stores sensitive data returned by
an access to setPassword
as clear text.

Copilot Autofix

AI 1 day ago

In general, the problem is that setRefreshToken writes the refresh token directly to localStorage. To fix it without changing the external behavior of the SDK, we will transparently encrypt the refresh token when writing to localStorage and decrypt it when reading it back at initialization. The storage API (setRefreshToken, getRefreshToken, setTokens, clear) will remain unchanged.

Concretely, in src/legacy-sdk/core/storage.ts:

  1. Introduce small helper functions encryptToken and decryptToken that:

    • Are async and use the standard browser crypto.subtle Web Crypto API (available in modern browsers, which is the typical environment for localStorage usage).
    • Derive an encryption key from a static passphrase using PBKDF2 (or similar) and encrypt/decrypt using AES‑GCM.
    • Fall back gracefully (returning the original value) if window.crypto / crypto.subtle is not available, so behavior does not completely break in legacy environments.
  2. Update createStorage:

    • When initializing refreshToken from localStorage, call an async decryptStoredRefreshToken helper that reads the ciphertext from SALEOR_REFRESH_TOKEN and decrypts it into the in‑memory refreshToken variable.
    • Keep accessToken purely in memory as today.
  3. Modify setRefreshToken:

    • If token is non‑null:
      • Encrypt it with encryptToken and store the ciphertext (e.g., base64‑encoded) in localStorage.setItem(SALEOR_REFRESH_TOKEN, encryptedToken).
    • Otherwise, remove the key from localStorage as before.
    • Always update the in‑memory refreshToken variable with the plain token (so the rest of the code using storage.getRefreshToken() behaves exactly as before).
  4. Because createStorage currently returns void, but we need to perform async decryption, we will:

    • Add internal helpers and kick off decryption without changing the signature, by:
      • Initializing refreshToken to null.
      • After defining setRefreshToken, call a self‑invoking async function that, if autologinEnabled and LOCAL_STORAGE_EXISTS, reads from localStorage and decrypts into refreshToken. This preserves the synchronous signature of createStorage while eventually populating refreshToken.

No new third‑party libraries are required; we only use the standard Web Crypto API.

Suggested changeset 1
src/legacy-sdk/core/storage.ts

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/src/legacy-sdk/core/storage.ts b/src/legacy-sdk/core/storage.ts
--- a/src/legacy-sdk/core/storage.ts
+++ b/src/legacy-sdk/core/storage.ts
@@ -12,14 +12,139 @@
   clear: () => void;
 };
 
+/**
+ * Encrypt a token value for storage.
+ * Falls back to returning the plain token if Web Crypto is unavailable.
+ */
+const encryptToken = async (token: string): Promise<string> => {
+  if (typeof window === "undefined" || !window.crypto || !window.crypto.subtle) {
+    return token;
+  }
+
+  const encoder = new TextEncoder();
+  const data = encoder.encode(token);
+
+  // NOTE: In a real application, the passphrase and salt should not be hard-coded.
+  const passphrase = "saleor-sdk-refresh-token-key";
+  const salt = encoder.encode("saleor-sdk-refresh-token-salt");
+
+  const keyMaterial = await window.crypto.subtle.importKey(
+    "raw",
+    encoder.encode(passphrase),
+    { name: "PBKDF2" },
+    false,
+    ["deriveKey"]
+  );
+
+  const key = await window.crypto.subtle.deriveKey(
+    {
+      name: "PBKDF2",
+      salt,
+      iterations: 100000,
+      hash: "SHA-256",
+    },
+    keyMaterial,
+    { name: "AES-GCM", length: 256 },
+    false,
+    ["encrypt"]
+  );
+
+  const iv = window.crypto.getRandomValues(new Uint8Array(12));
+  const ciphertext = await window.crypto.subtle.encrypt(
+    {
+      name: "AES-GCM",
+      iv,
+    },
+    key,
+    data
+  );
+
+  const encryptedBytes = new Uint8Array(iv.byteLength + ciphertext.byteLength);
+  encryptedBytes.set(iv, 0);
+  encryptedBytes.set(new Uint8Array(ciphertext), iv.byteLength);
+
+  return btoa(String.fromCharCode(...encryptedBytes));
+};
+
+/**
+ * Decrypt a token value from storage.
+ * Falls back to returning the stored value if decryption fails or Web Crypto is unavailable.
+ */
+const decryptToken = async (stored: string | null): Promise<string | null> => {
+  if (!stored) {
+    return null;
+  }
+
+  if (typeof window === "undefined" || !window.crypto || !window.crypto.subtle) {
+    return stored;
+  }
+
+  try {
+    const binary = atob(stored);
+    const bytes = new Uint8Array(binary.length);
+    for (let i = 0; i < binary.length; i++) {
+      bytes[i] = binary.charCodeAt(i);
+    }
+
+    const iv = bytes.slice(0, 12);
+    const ciphertext = bytes.slice(12);
+
+    const encoder = new TextEncoder();
+    const passphrase = "saleor-sdk-refresh-token-key";
+    const salt = encoder.encode("saleor-sdk-refresh-token-salt");
+
+    const keyMaterial = await window.crypto.subtle.importKey(
+      "raw",
+      encoder.encode(passphrase),
+      { name: "PBKDF2" },
+      false,
+      ["deriveKey"]
+    );
+
+    const key = await window.crypto.subtle.deriveKey(
+      {
+        name: "PBKDF2",
+        salt,
+        iterations: 100000,
+        hash: "SHA-256",
+      },
+      keyMaterial,
+      { name: "AES-GCM", length: 256 },
+      false,
+      ["decrypt"]
+    );
+
+    const plaintext = await window.crypto.subtle.decrypt(
+      {
+        name: "AES-GCM",
+        iv,
+      },
+      key,
+      ciphertext
+    );
+
+    const decoder = new TextDecoder();
+    return decoder.decode(plaintext);
+  } catch {
+    // If anything goes wrong, return the stored value as-is.
+    return stored;
+  }
+};
+
 export const createStorage = (autologinEnabled: boolean): void => {
   let authPluginId: string | null = LOCAL_STORAGE_EXISTS
     ? localStorage.getItem(SALEOR_AUTH_PLUGIN_ID)
     : null;
   let accessToken: string | null = null;
-  let refreshToken: string | null =
-    autologinEnabled && LOCAL_STORAGE_EXISTS ? localStorage.getItem(SALEOR_REFRESH_TOKEN) : null;
+  let refreshToken: string | null = null;
 
+  if (autologinEnabled && LOCAL_STORAGE_EXISTS) {
+    (async () => {
+      const stored = localStorage.getItem(SALEOR_REFRESH_TOKEN);
+      refreshToken = await decryptToken(stored);
+    })();
+  }
+
   const setAuthPluginId = (pluginId: string | null): void => {
     if (LOCAL_STORAGE_EXISTS) {
       if (pluginId) {
@@ -33,10 +152,20 @@
   };
 
   const setRefreshToken = (token: string | null): void => {
-    if (token) {
-      localStorage.setItem(SALEOR_REFRESH_TOKEN, token);
-    } else {
-      localStorage.removeItem(SALEOR_REFRESH_TOKEN);
+    if (LOCAL_STORAGE_EXISTS) {
+      if (token) {
+        // Store encrypted token to avoid clear-text storage of sensitive data.
+        encryptToken(token)
+          .then(encrypted => {
+            localStorage.setItem(SALEOR_REFRESH_TOKEN, encrypted);
+          })
+          .catch(() => {
+            // As a conservative fallback, still store the token if encryption fails.
+            localStorage.setItem(SALEOR_REFRESH_TOKEN, token);
+          });
+      } else {
+        localStorage.removeItem(SALEOR_REFRESH_TOKEN);
+      }
     }
 
     refreshToken = token;
EOF
Copilot is powered by AI and may make mistakes. Always verify output.
@github-actions
Copy link
Contributor

github-actions bot commented Mar 9, 2026

Differences Found

✅ No packages or licenses were added.

Summary

Expand
License Name Package Count Packages
0BSD 1
Packages
  • tslib
CC0-1.0 1
Packages
  • type-fest
MIT/X11 1
Packages
  • nub
MPL-1.1 1
Packages
  • harmony-reflect
MPL-2.0 1
Packages
  • dompurify
Public Domain 1
Packages
  • jsonify
Python-2.0 1
Packages
  • argparse
WTFPL 1
Packages
  • utf8-byte-length
CC-BY-4.0 2
Packages
  • @saleor/macaw-ui
  • caniuse-lite
SEE LICENSE IN LICENSE 2
Packages
  • posthog-js
  • spawndamnit
BlueOak-1.0.0 5
Packages
  • glob
  • lru-cache
  • minimatch
  • minipass
  • path-scurry
<<missing>> 11
Packages
  • @sentry/cli
  • @sentry/cli-darwin
  • @sentry/cli-linux-arm
  • @sentry/cli-linux-arm64
  • @sentry/cli-linux-i686
  • @sentry/cli-linux-x64
  • @sentry/cli-win32-arm64
  • @sentry/cli-win32-i686
  • @sentry/cli-win32-x64
  • busboy
  • streamsearch
BSD-2-Clause 23
Packages
  • browser-process-hrtime
  • css-select
  • css-what
  • domelementtype
  • domhandler
  • domutils
  • dotenv
  • dotenv-expand
  • entities
  • escodegen
  • eslint-scope
  • espree
  • esprima
  • esrecurse
  • estraverse
  • esutils
  • nth-check
  • regjsparser
  • stringify-object
  • terser
  • And 3 more...
ISC 47
Packages
  • @istanbuljs/load-nyc-config
  • anymatch
  • boolbase
  • cli-width
  • cliui
  • electron-to-chromium
  • fastq
  • flatted
  • fs.realpath
  • get-caller-file
  • get-own-enumerable-property-symbols
  • glob
  • glob-parent
  • graceful-fs
  • inflight
  • inherits
  • ini
  • isexe
  • knip
  • lru-cache
  • And 27 more...
BSD-3-Clause 53
Packages
  • @protobufjs/aspromise
  • @protobufjs/base64
  • @protobufjs/codegen
  • @protobufjs/eventemitter
  • @protobufjs/fetch
  • @protobufjs/float
  • @protobufjs/inquire
  • @protobufjs/path
  • @protobufjs/pool
  • @protobufjs/utf8
  • @saleor/app-sdk
  • @sentry/cli
  • @sentry/cli-darwin
  • @sentry/cli-linux-arm
  • @sentry/cli-linux-arm64
  • @sentry/cli-linux-i686
  • @sentry/cli-linux-x64
  • @sentry/cli-win32-i686
  • @sentry/cli-win32-x64
  • @sinonjs/commons
  • And 33 more...
Apache-2.0 64
Packages
  • @editorjs/editorjs
  • @eslint/config-array
  • @eslint/config-helpers
  • @eslint/core
  • @eslint/object-schema
  • @eslint/plugin-kit
  • @humanfs/core
  • @humanfs/node
  • @humanwhocodes/module-importer
  • @humanwhocodes/retry
  • @opentelemetry/api
  • @opentelemetry/api-logs
  • @opentelemetry/core
  • @opentelemetry/exporter-logs-otlp-http
  • @opentelemetry/otlp-exporter-base
  • @opentelemetry/otlp-transformer
  • @opentelemetry/resources
  • @opentelemetry/sdk-logs
  • @opentelemetry/sdk-metrics
  • @opentelemetry/sdk-trace-base
  • And 44 more...
MIT 1305
Packages
  • @adobe/css-tools
  • @apollo/client
  • @ardatan/relay-compiler
  • @ardatan/sync-fetch
  • @babel/code-frame
  • @babel/compat-data
  • @babel/core
  • @babel/generator
  • @babel/helper-annotate-as-pure
  • @babel/helper-compilation-targets
  • @babel/helper-create-class-features-plugin
  • @babel/helper-globals
  • @babel/helper-member-expression-to-functions
  • @babel/helper-module-imports
  • @babel/helper-module-transforms
  • @babel/helper-optimise-call-expression
  • @babel/helper-plugin-utils
  • @babel/helper-replace-supers
  • @babel/helper-skip-transparent-expression-wrappers
  • @babel/helper-string-parser
  • And 1285 more...

@lkostrowski lkostrowski marked this pull request as draft March 9, 2026 21:19
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR replaces remaining usages of @saleor/sdk with the in-repo @dashboard/legacy-sdk implementation and adds extensive unit test coverage for the inlined legacy SDK modules (core auth/user/storage, Apollo fetch/client behavior, and basic React integration).

Changes:

  • Switched multiple imports from @saleor/sdk / @saleor/sdk/dist/apollo/types to @dashboard/legacy-sdk.
  • Added the in-repo legacy SDK implementation (src/legacy-sdk/**) including core, Apollo, and React wrapper APIs.
  • Added Jest test suites for legacy SDK core logic and Apollo fetch/client behavior; removed @saleor/sdk from dependencies and workspace config.

Reviewed changes

Copilot reviewed 55 out of 58 changed files in this pull request and generated 8 comments.

Show a summary per file
File Description
src/utils/handlers/metadataUpdateHelpers.ts Switch MetadataInput import to legacy SDK types.
src/utils/errors/account.ts Switch SDK types import to legacy SDK types.
src/utils/credentialsManagement.ts Switch UserDetailsFragment import to legacy SDK types.
src/shipping/views/RateUpdate.tsx Switch ShippingMethodPostalCodeRule type import to legacy SDK.
src/products/views/ProductList/export.test.ts Switch ExportInfoInput type import to legacy SDK types.
src/products/fixtures.ts Switch ProductType type import to legacy SDK types.
src/legacy-sdk/react/index.ts Add legacy SDK React barrel exports.
src/legacy-sdk/react/hooks/user.ts Add useUser hook via hookFactory.
src/legacy-sdk/react/hooks/saleorConfig.ts Add useSaleorConfig hook via hookFactory.
src/legacy-sdk/react/hooks/index.ts Add hooks barrel exports.
src/legacy-sdk/react/hooks/auth.ts Add useAuth and useAuthState hooks.
src/legacy-sdk/react/helpers/hookStateFactory.ts Add Apollo cache-only state hook factory.
src/legacy-sdk/react/helpers/hookFactory.ts Add context-based hook factory for SDK methods.
src/legacy-sdk/react/helpers/hookFactory.test.tsx Add tests for hookFactory behavior and provider requirement.
src/legacy-sdk/react/components/index.ts Add components barrel exports.
src/legacy-sdk/react/components/SaleorProvider.tsx Add SaleorProvider + SaleorContext implementation.
src/legacy-sdk/react/components/SaleorProvider.test.tsx Add tests for SaleorProvider context behavior.
src/legacy-sdk/index.ts Add top-level legacy SDK barrel exports.
src/legacy-sdk/helpers.ts Add helper for internal token detection.
src/legacy-sdk/helpers.test.ts Add tests for internal token helper.
src/legacy-sdk/core/user.ts Add legacy user SDK methods implementation.
src/legacy-sdk/core/user.test.ts Add tests for user SDK mutations wiring + logout side-effect.
src/legacy-sdk/core/types.ts Add legacy SDK public/core types and method result types.
src/legacy-sdk/core/storage.ts Add token/auth plugin storage implementation.
src/legacy-sdk/core/storage.test.ts Add tests for storage persistence and lifecycle behaviors.
src/legacy-sdk/core/state.ts Add helper to read auth state from Apollo cache.
src/legacy-sdk/core/index.ts Add core barrel exports (createFetch/createSaleorClient/types).
src/legacy-sdk/core/helpers.ts Add permission helper used by auth flows.
src/legacy-sdk/core/helpers.test.ts Add tests for permission helper behavior.
src/legacy-sdk/core/createSaleorClient.ts Add Saleor client factory (Apollo + core SDK wiring + autologin).
src/legacy-sdk/core/constants.ts Add legacy SDK storage key constants.
src/legacy-sdk/core/auth.ts Add legacy auth SDK methods implementation.
src/legacy-sdk/core/auth.test.ts Add tests for auth SDK behaviors and cache/storage side effects.
src/legacy-sdk/constants.ts Add environment capability constants (window/localStorage/dev mode).
src/legacy-sdk/config.ts Add legacy SDK test/config constants.
src/legacy-sdk/apollo/queries.ts Add legacy SDK USER queries.
src/legacy-sdk/apollo/mutations.ts Add legacy SDK auth/user mutations.
src/legacy-sdk/apollo/index.ts Add apollo barrel export.
src/legacy-sdk/apollo/fragments.ts Add legacy SDK GraphQL fragments.
src/legacy-sdk/apollo/client.ts Add Apollo client + fetch wrapper with auth/refresh logic.
src/legacy-sdk/apollo/client.test.ts Add tests for createFetch behaviors (auth header, refresh, retries).
src/index.tsx Switch app’s SaleorProvider import from @saleor/sdk to legacy SDK.
src/graphql/client.ts Switch createFetch/createSaleorClient import to legacy SDK.
src/components/DevModePanel/utils.ts Switch createFetch import to legacy SDK.
src/components/DevModePanel/utils.test.ts Update mocks/imports to legacy SDK createFetch.
src/components/AppLayout/AppChannelContext.tsx Switch useSaleorConfig import to legacy SDK hook.
src/components/AddressEdit/useAddressValidation.ts Switch ChoiceValue type import to legacy SDK types.
src/auth/views/NewPassword.tsx Switch useAuth hook import to legacy SDK.
src/auth/types.ts Switch auth-related type exports import to legacy SDK.
src/auth/hooks/useAuthProvider.ts Switch auth hooks/types import to legacy SDK.
src/auth/hooks/useAuthProvider.test.ts Update mocks/imports to legacy SDK auth hooks.
src/auth/AuthProvider.test.tsx Update mocks/imports to legacy SDK auth hooks.
pnpm-workspace.yaml Remove @saleor/sdk from minimumReleaseAgeExclude list.
pnpm-lock.yaml Remove @saleor/sdk dependency lock entries.
package.json Remove @saleor/sdk dependency.
codegen-main.ts Update CodegenConfig import to type-only; exclude legacy SDK GraphQL operations from codegen inputs.
Files not reviewed (1)
  • pnpm-lock.yaml: Language not supported

Comment on lines +80 to +84
try {
if (refreshPromise) {
await refreshPromise;
} else if (Date.now() >= expirationTime) {
if (isInternalToken(owner)) {
Copy link

Copilot AI Mar 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the auto-refresh path, refreshPromise is never set when starting a refresh. That means concurrent requests with an expired token can trigger multiple refresh mutations in parallel, defeating the deduplication logic used later for refreshOnUnauthorized. Consider assigning refreshPromise = authClient.refreshToken()/refreshExternalToken() before awaiting, and then awaiting the shared promise.

Copilot uses AI. Check for mistakes.
Comment on lines +35 to +40
const setRefreshToken = (token: string | null): void => {
if (token) {
localStorage.setItem(SALEOR_REFRESH_TOKEN, token);
} else {
localStorage.removeItem(SALEOR_REFRESH_TOKEN);
}
Copy link

Copilot AI Mar 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

setRefreshToken writes to localStorage unconditionally. If createStorage() is used in a non-browser environment (where LOCAL_STORAGE_EXISTS is false), calling storage.setRefreshToken(...) / storage.clear() will throw. Guard the localStorage reads/writes in setRefreshToken the same way as setAuthPluginId.

Copilot uses AI. Check for mistakes.
is_staff: boolean;
};

// Meethods opts
Copy link

Copilot AI Mar 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typo in comment: “Meethods opts” → “Methods opts”.

Copilot uses AI. Check for mistakes.
export type UpdateAccountAddressOpts = MutationAccountAddressUpdateArgs;
export type ConfirmAccountOpts = AccountConfirmMutationVariables;

// Meethods results
Copy link

Copilot AI Mar 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typo in comment: “Meethods results” → “Methods results”.

Copilot uses AI. Check for mistakes.
Comment on lines +100 to +103
/**
* Refresh JWT token. Mutation will try to take refreshToken from the function's arguments.
* If it fails, it will try to use refreshToken from the http-only cookie called refreshToken.
*
Copy link

Copilot AI Mar 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The JSDoc for refreshToken mentions taking refreshToken from function arguments / an http-only cookie, but the method signature only accepts includeUser and always reads the token from storage. Please update the doc comment to match the actual behavior to avoid misleading SDK consumers.

Copilot uses AI. Check for mistakes.
* Change the password of the logged in user.
*
* @param opts - Object with password and new password.
* @returns Errors if the passoword change has failed.
Copy link

Copilot AI Mar 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typo in JSDoc: “passoword” → “password”.

Copilot uses AI. Check for mistakes.
Comment on lines +12 to +43
export const createSaleorClient = ({
apiUrl,
channel,
opts = {},
}: SaleorClientOpts): SaleorClient => {
let _channel = channel;
const { autologin = true, fetchOpts } = opts;

const setChannel = (channel: string): string => {
_channel = channel;

return _channel;
};

createStorage(autologin);

const apolloClient = createApolloClient(apiUrl, autologin, fetchOpts);
const coreInternals = { apolloClient, channel: _channel };
const authSDK = auth(coreInternals);
const userSDK = user(coreInternals);

const refreshToken = storage.getRefreshToken();

if (autologin && refreshToken) {
const owner = jwtDecode<JWTToken>(refreshToken).owner;

if (isInternalToken(owner)) {
authSDK.refreshToken(true);
} else {
authSDK.refreshExternalToken(true);
}
}
Copy link

Copilot AI Mar 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

createSaleorClient contains important behavioral logic (channel switching + autologin refresh) but currently has no dedicated tests. Adding tests that verify config.setChannel(...) affects subsequent auth/user calls (and that autologin triggers the correct refresh path) would prevent regressions here.

Copilot uses AI. Check for mistakes.
Comment on lines +28 to +31
const apolloClient = createApolloClient(apiUrl, autologin, fetchOpts);
const coreInternals = { apolloClient, channel: _channel };
const authSDK = auth(coreInternals);
const userSDK = user(coreInternals);
Copy link

Copilot AI Mar 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

setChannel only mutates the local _channel variable, but coreInternals.channel is created from the initial value and never updates. As a result, auth()/user() closures (and config.channel) will keep using the initial channel, so later setChannel(...) calls won’t affect subsequent mutations. Consider storing channel in a mutable object/ref shared with the SDK methods, or making channel a getter that reads the latest value, and ensure config.channel stays in sync.

Copilot uses AI. Check for mistakes.
@lkostrowski lkostrowski changed the title Add comprehensive tests for inlined legacy-sdk modules Pull legacy @saleor/sdk into dashboard Mar 9, 2026
@codecov
Copy link

codecov bot commented Mar 9, 2026

Codecov Report

❌ Patch coverage is 81.84211% with 69 lines in your changes missing coverage. Please review.
✅ Project coverage is 43.46%. Comparing base (e640f8c) to head (0de0284).

Files with missing lines Patch % Lines
src/legacy-sdk/core/createSaleorClient.ts 27.27% 24 Missing ⚠️
src/legacy-sdk/apollo/client.ts 80.00% 16 Missing ⚠️
src/legacy-sdk/config.ts 0.00% 11 Missing and 1 partial ⚠️
src/legacy-sdk/react/helpers/hookStateFactory.ts 45.45% 6 Missing ⚠️
src/legacy-sdk/core/auth.ts 96.15% 4 Missing ⚠️
src/legacy-sdk/react/hooks/auth.ts 55.55% 4 Missing ⚠️
src/legacy-sdk/core/state.ts 66.66% 1 Missing ⚠️
src/legacy-sdk/core/storage.ts 97.22% 1 Missing ⚠️
src/legacy-sdk/react/components/SaleorProvider.tsx 88.88% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #6405      +/-   ##
==========================================
+ Coverage   43.13%   43.46%   +0.32%     
==========================================
  Files        2524     2548      +24     
  Lines       44009    44386     +377     
  Branches    10011    10479     +468     
==========================================
+ Hits        18983    19291     +308     
- Misses      24985    25053      +68     
- Partials       41       42       +1     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

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.

2 participants