@vtex/faststore 0.0.6 → 0.0.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (132) hide show
  1. package/CHANGELOG.md +56 -0
  2. package/dist/catalog.json +161 -20
  3. package/dist/cli/UnreachableCaseError-Crd168Vu.js +10 -0
  4. package/dist/cli/UnreachableCaseError-Crd168Vu.js.map +1 -0
  5. package/dist/cli/cacheControl-CEojH_TM.js +158 -0
  6. package/dist/cli/cacheControl-CEojH_TM.js.map +1 -0
  7. package/dist/cli/cachePolicy-m2vASMRW.js +26 -0
  8. package/dist/cli/cachePolicy-m2vASMRW.js.map +1 -0
  9. package/dist/cli/computeCoreSchemaHash-DPJZj-qJ.js +10 -0
  10. package/dist/cli/computeCoreSchemaHash-DPJZj-qJ.js.map +1 -0
  11. package/dist/cli/default-BCQHcwbL.js +253 -0
  12. package/dist/cli/default-BCQHcwbL.js.map +1 -0
  13. package/dist/cli/disableSuggestions-yO9UqiWn.js +21 -0
  14. package/dist/cli/disableSuggestions-yO9UqiWn.js.map +1 -0
  15. package/dist/cli/dist-C1JhdHfo.js +2001 -0
  16. package/dist/cli/dist-C1JhdHfo.js.map +1 -0
  17. package/dist/cli/graphql-DG9thCDG.js +14589 -0
  18. package/dist/cli/graphql-DG9thCDG.js.map +1 -0
  19. package/dist/cli/index.d.ts +350 -0
  20. package/dist/cli/index.js +35047 -0
  21. package/dist/cli/index.js.map +1 -0
  22. package/dist/cli/index.min-BsIHDfFK.js +613 -0
  23. package/dist/cli/index.min-BsIHDfFK.js.map +1 -0
  24. package/dist/cli/inlineTrace-uLgOJ3TH.js +52 -0
  25. package/dist/cli/inlineTrace-uLgOJ3TH.js.map +1 -0
  26. package/dist/cli/internalPlugin-DnuwN4_4.js +11 -0
  27. package/dist/cli/internalPlugin-DnuwN4_4.js.map +1 -0
  28. package/dist/cli/packageVersion-DQAnIEil.js +6 -0
  29. package/dist/cli/packageVersion-DQAnIEil.js.map +1 -0
  30. package/dist/cli/rolldown-runtime-BMI-E3GI.js +44 -0
  31. package/dist/cli/schemaIsSubgraph-DoGh3OYj.js +17 -0
  32. package/dist/cli/schemaIsSubgraph-DoGh3OYj.js.map +1 -0
  33. package/dist/cli/schemaReporting-K-me-3-v.js +199 -0
  34. package/dist/cli/schemaReporting-K-me-3-v.js.map +1 -0
  35. package/dist/cli/server-runtime.js +49859 -0
  36. package/dist/cli/server-runtime.js.map +1 -0
  37. package/dist/cli/traceTreeBuilder-BIcV2U7b.js +9118 -0
  38. package/dist/cli/traceTreeBuilder-BIcV2U7b.js.map +1 -0
  39. package/dist/cli/usageReporting-Bpl8vSZX.js +10201 -0
  40. package/dist/cli/usageReporting-Bpl8vSZX.js.map +1 -0
  41. package/dist/cli/v4-CBhFvC49.js +42 -0
  42. package/dist/cli/v4-CBhFvC49.js.map +1 -0
  43. package/dist/components.d.ts +5 -3
  44. package/dist/components.js +5 -3
  45. package/dist/content-types.json +93 -0
  46. package/dist/core/dist/define-component.d.ts +37 -0
  47. package/dist/core/dist/index.d.ts +2 -2
  48. package/dist/docs/account-entry-point.md +1 -1
  49. package/dist/docs/account-menu-identity.md +160 -0
  50. package/dist/docs/account-menu.md +106 -23
  51. package/dist/docs/avatar.md +103 -0
  52. package/dist/docs/my-account-profile.md +1 -1
  53. package/dist/docs/product-shelf.md +20 -13
  54. package/dist/index.d.ts +2 -2
  55. package/dist/internal/client.js +1 -1
  56. package/dist/internal/content.d.ts +2 -2
  57. package/dist/internal/server.d.ts +4 -1
  58. package/dist/internal/server.js +4 -1
  59. package/dist/matter/account-access-gate/account-access-gate.js.map +1 -1
  60. package/dist/matter/account-entry-point/account-entry-point.js +1 -1
  61. package/dist/matter/account-entry-point/account-entry-point.js.map +1 -1
  62. package/dist/matter/account-menu/account-menu.d.ts +70 -0
  63. package/dist/matter/account-menu/account-menu.js +201 -9
  64. package/dist/matter/account-menu/account-menu.js.map +1 -1
  65. package/dist/matter/account-menu/sign-out-failure.js +50 -0
  66. package/dist/matter/account-menu/sign-out-failure.js.map +1 -0
  67. package/dist/matter/account-menu-identity/account-menu-identity.d.ts +21 -0
  68. package/dist/matter/account-menu-identity/account-menu-identity.js +88 -0
  69. package/dist/matter/account-menu-identity/account-menu-identity.js.map +1 -0
  70. package/dist/matter/card-entry/card-entry.js +1 -0
  71. package/dist/matter/card-entry/card-entry.js.map +1 -1
  72. package/dist/matter/cart/cart.js +1 -1
  73. package/dist/matter/client-preferences/client-preferences-fieldset.js +2 -2
  74. package/dist/matter/client-profile-form/client-profile-fieldset.js +2 -2
  75. package/dist/matter/identity-summary/identity-summary.js +2 -1
  76. package/dist/matter/identity-summary/identity-summary.js.map +1 -1
  77. package/dist/matter/my-account-profile/my-account-profile.d.ts +3 -0
  78. package/dist/matter/my-account-profile/my-account-profile.js +2 -1
  79. package/dist/matter/my-account-profile/my-account-profile.js.map +1 -1
  80. package/dist/matter/payment/payment-controller.js +1 -0
  81. package/dist/matter/payment/payment-controller.js.map +1 -1
  82. package/dist/matter/payment/payment.js +1 -0
  83. package/dist/matter/payment/payment.js.map +1 -1
  84. package/dist/matter/product-shelf/product-shelf.d.ts +61 -31
  85. package/dist/matter/product-shelf/product-shelf.js +157 -57
  86. package/dist/matter/product-shelf/product-shelf.js.map +1 -1
  87. package/dist/matter/saved-cards/saved-cards.js +1 -0
  88. package/dist/matter/saved-cards/saved-cards.js.map +1 -1
  89. package/dist/matter/shipping-address/shipping-address.js +2 -2
  90. package/dist/particles/avatar/avatar.d.ts +17 -0
  91. package/dist/particles/avatar/avatar.js +65 -0
  92. package/dist/particles/avatar/avatar.js.map +1 -0
  93. package/dist/schema.graphql +65 -26
  94. package/dist/sdk/analytics/use-analytics-actions.js +2 -1
  95. package/dist/sdk/analytics/use-analytics-actions.js.map +1 -1
  96. package/dist/sdk/cart/use-cart-actions.js +9 -8
  97. package/dist/sdk/cart/use-cart-actions.js.map +1 -1
  98. package/dist/sdk/cart/use-cart-validate-on-open.js +2 -1
  99. package/dist/sdk/cart/use-cart-validate-on-open.js.map +1 -1
  100. package/dist/sdk/content/create-content-runtime.d.ts +22 -1
  101. package/dist/sdk/content/create-content-runtime.js +89 -1
  102. package/dist/sdk/content/create-content-runtime.js.map +1 -1
  103. package/dist/sdk/data/empty-content-value.js +16 -0
  104. package/dist/sdk/data/empty-content-value.js.map +1 -0
  105. package/dist/sdk/data/hot-data-provider.js +2 -1
  106. package/dist/sdk/data/hot-data-provider.js.map +1 -1
  107. package/dist/sdk/data/index.js +2 -2
  108. package/dist/sdk/data/reactive-list-item-data-provider.js +2 -2
  109. package/dist/sdk/data/variables-from-content.d.ts +43 -0
  110. package/dist/sdk/data/variables-from-content.js +57 -0
  111. package/dist/sdk/data/variables-from-content.js.map +1 -0
  112. package/dist/sdk/generated/gql.js +2 -1
  113. package/dist/sdk/generated/gql.js.map +1 -1
  114. package/dist/sdk/generated/graphql.js +85 -1
  115. package/dist/sdk/generated/graphql.js.map +1 -1
  116. package/dist/sdk/identity/use-identity-actions.js +5 -4
  117. package/dist/sdk/identity/use-identity-actions.js.map +1 -1
  118. package/dist/sdk/payment/use-payment-actions.js +1 -1
  119. package/dist/sdk/payment/use-place-order.js +1 -1
  120. package/dist/sdk/region/use-region-actions.js +2 -1
  121. package/dist/sdk/region/use-region-actions.js.map +1 -1
  122. package/dist/sdk/session/read-server-session.d.ts +21 -0
  123. package/dist/sdk/session/read-server-session.js +61 -0
  124. package/dist/sdk/session/read-server-session.js.map +1 -0
  125. package/dist/sdk/session/use-session-actions.js +5 -4
  126. package/dist/sdk/session/use-session-actions.js.map +1 -1
  127. package/dist/sdk/session/use-session-revalidation.js +2 -1
  128. package/dist/sdk/session/use-session-revalidation.js.map +1 -1
  129. package/dist/sdk/shipping/use-shipping-actions.js +3 -2
  130. package/dist/sdk/shipping/use-shipping-actions.js.map +1 -1
  131. package/dist/utils/safe-href.d.ts +11 -0
  132. package/package.json +13 -2
@@ -24,9 +24,10 @@ const UNAUTHORIZED_CUSTOMER_PROFILE_ERROR = {
24
24
  message: "Your session has expired. Please sign in again."
25
25
  };
26
26
  /**
27
- * The profile module answers an anonymous or expired session with a top-level `UNAUTHORIZED`, never
28
- * a `userError`. Collapsing it into `NETWORK_ERROR` would offer a retry that cannot succeed, so it
29
- * gets its own code and the caller can send the shopper back to sign-in.
27
+ * The profile write answers an anonymous or expired session with a top-level `UNAUTHORIZED`, never
28
+ * a `userError` (the read answers an anonymous one with a null profile instead). Collapsing it into
29
+ * `NETWORK_ERROR` would offer a retry that cannot succeed, so it gets its own code and the caller can
30
+ * send the shopper back to sign-in.
30
31
  */
31
32
  function toCustomerProfileError(error) {
32
33
  if (CombinedGraphQLErrors.is(error)) {
@@ -63,7 +64,7 @@ function useIdentityActions() {
63
64
  try {
64
65
  return (await customerProfileMutation({ variables: { input: payload } })).data?.customerProfileUpdate?.userErrors ?? [];
65
66
  } catch (error) {
66
- console.error("[identity.customerProfileUpdate] customerProfileUpdate failed", error instanceof Error ? error.name : "UnknownError");
67
+ console.error("[identity.customerProfileUpdate] customerProfileUpdate failed", loggableErrorName(error));
67
68
  return [toCustomerProfileError(error)];
68
69
  }
69
70
  }, [customerProfileMutation]);
@@ -1 +1 @@
1
- {"version":3,"file":"use-identity-actions.js","names":[],"sources":["../../../src/sdk/identity/use-identity-actions.ts"],"sourcesContent":["'use client';\n\nimport { CombinedGraphQLErrors } from '@apollo/client/errors';\nimport { useMutation } from '@apollo/client/react';\nimport { defineActions } from '@vtex/fs-core';\nimport { useCallback, useMemo } from 'react';\nimport { loggableErrorName } from '../../utils/loggable-error-name.js';\nimport {\n CLIENT_PREFERENCES_UPDATE,\n CLIENT_PROFILE_UPDATE,\n type ClientPreferenceKey,\n type ClientProfileUserError,\n CUSTOMER_PROFILE_UPDATE,\n type CustomerProfileUpdateInput,\n type CustomerProfileUserError,\n} from './operations.js';\n\n/**\n * The `identity` action namespace — the context-free owner of the shopper-profile,\n * consent-preference, and persistent-profile writes\n * (specs/fspg-859-email-field.md, specs/consent-opt-in-component.md,\n * docs/storefront-core/reference-free-particle-model.md § Write side — actions,\n * docs/storefront-core/adr-0010-actions-own-the-write-side.md).\n *\n * It mirrors `useCartActions`: a component anywhere in the tree dispatches the write through the\n * compiler-injected `$actions.identity.*` prop, and the handler calls the corresponding mutation.\n * Every write is **async / pessimistic** (Decision 1): the caller awaits the persisted result. Each\n * call returns its `userErrors` (empty on success) so the caller can surface server-side failures\n * inline; the returned entity self-updates the normalized cache and every reactive subscriber.\n *\n * The first two writes target the cart's sibling identity entities; `customerProfileUpdate` targets\n * the shopper's account profile, which needs no cart at all.\n */\n\n/**\n * Payload for the profile write. Callers persist only the fields they own; other fields are\n * untouched. The payload is passed through to `ClientProfileUpdateInput` unmapped, so this type\n * mirrors that input verbatim — a stacked field only needs a field to already exist here to reach\n * the wire.\n */\nexport type ClientProfileUpdatePayload = Readonly<{\n email?: string;\n firstName?: string;\n lastName?: string;\n phone?: string;\n document?: string;\n}>;\n\n/** Payload for the preferences write — one opt-in flag; the other flag is left untouched. */\nexport type ClientPreferencesUpdatePayload = Readonly<Partial<Record<ClientPreferenceKey, boolean>>>;\n\n/**\n * Payload for the persistent-profile write. Mirrors `CustomerProfileUpdateInput` verbatim and is\n * forwarded unmapped, so an omitted field stays untouched upstream and an empty string erases.\n */\nexport type CustomerProfileUpdatePayload = CustomerProfileUpdateInput;\n\nexport type IdentityActions = Readonly<{\n /**\n * Persist the provided profile fields (partial) to the active cart's `clientProfileData`.\n * Async — awaits the mutation before resolving. Returns the resulting `userErrors` (empty on\n * success).\n */\n clientProfileUpdate: (payload: ClientProfileUpdatePayload) => Promise<readonly ClientProfileUserError[]>;\n /**\n * Persist the provided consent opt-in flag(s) (partial) to the shopper's `ClientPreferences`\n * entity (order-form-backed). Async — awaits the mutation before resolving. Writes ONLY the\n * requested field. Returns the resulting `userErrors` (empty on success).\n */\n clientPreferencesUpdate: (payload: ClientPreferencesUpdatePayload) => Promise<readonly ClientProfileUserError[]>;\n /**\n * Persist the provided profile fields (partial) to the shopper's persistent, cart-independent\n * account profile. Async — awaits the mutation before resolving. Sends exactly the fields it is\n * given: an omitted field is left untouched, an empty string erases. Returns the resulting\n * `userErrors` (empty on success).\n */\n customerProfileUpdate: (payload: CustomerProfileUpdatePayload) => Promise<readonly CustomerProfileUserError[]>;\n}>;\n\nconst NETWORK_PROFILE_ERROR: ClientProfileUserError = {\n code: 'NETWORK_ERROR',\n message: 'Unable to save your details. Please try again.',\n};\n\nconst NETWORK_PREFERENCE_ERROR: ClientProfileUserError = {\n code: 'NETWORK_ERROR',\n message: 'Unable to save your preference. Please try again.',\n};\n\nconst NETWORK_CUSTOMER_PROFILE_ERROR: CustomerProfileUserError = {\n code: 'NETWORK_ERROR',\n message: 'Unable to save your profile. Please try again.',\n};\n\nconst UNAUTHORIZED_CUSTOMER_PROFILE_ERROR: CustomerProfileUserError = {\n code: 'UNAUTHORIZED',\n message: 'Your session has expired. Please sign in again.',\n};\n\n/**\n * The profile module answers an anonymous or expired session with a top-level `UNAUTHORIZED`, never\n * a `userError`. Collapsing it into `NETWORK_ERROR` would offer a retry that cannot succeed, so it\n * gets its own code and the caller can send the shopper back to sign-in.\n */\nfunction toCustomerProfileError(error: unknown): CustomerProfileUserError {\n if (CombinedGraphQLErrors.is(error)) {\n const unauthorized = error.errors.some(({ extensions }) => extensions?.code === 'UNAUTHORIZED');\n if (unauthorized) return UNAUTHORIZED_CUSTOMER_PROFILE_ERROR;\n }\n return NETWORK_CUSTOMER_PROFILE_ERROR;\n}\n\n/**\n * The `identity` namespace hook. Registered with the first-party action registry via `identityActions`\n * below; the compiler-emitted `IdentityActionProvider` calls it and threads the narrowed methods into\n * each consumer's `$actions.identity`.\n */\nexport function useIdentityActions(): IdentityActions {\n const [profileMutation] = useMutation(CLIENT_PROFILE_UPDATE);\n const [preferencesMutation] = useMutation(CLIENT_PREFERENCES_UPDATE);\n const [customerProfileMutation] = useMutation(CUSTOMER_PROFILE_UPDATE);\n\n const clientProfileUpdate = useCallback<IdentityActions['clientProfileUpdate']>(\n async (payload) => {\n try {\n const result = await profileMutation({ variables: { input: payload } });\n return result.data?.clientProfileUpdate?.userErrors ?? [];\n } catch (error) {\n // Log only the error name — the message can echo the submitted email (PII).\n console.error('[identity.clientProfileUpdate] clientProfileUpdate failed', loggableErrorName(error));\n return [NETWORK_PROFILE_ERROR];\n }\n },\n [profileMutation],\n );\n\n const clientPreferencesUpdate = useCallback<IdentityActions['clientPreferencesUpdate']>(\n async (payload) => {\n try {\n const result = await preferencesMutation({ variables: { input: payload } });\n return result.data?.clientPreferencesUpdate?.userErrors ?? [];\n } catch (error) {\n // Log only the error name — mirrors the profile write's PII-safe logging.\n console.error('[identity.clientPreferencesUpdate] clientPreferencesUpdate failed', loggableErrorName(error));\n return [NETWORK_PREFERENCE_ERROR];\n }\n },\n [preferencesMutation],\n );\n\n const customerProfileUpdate = useCallback<IdentityActions['customerProfileUpdate']>(\n async (payload) => {\n try {\n // Forwarded unmapped: an empty string is an explicit erase and must survive to the wire.\n const result = await customerProfileMutation({ variables: { input: payload } });\n return result.data?.customerProfileUpdate?.userErrors ?? [];\n } catch (error) {\n // Log only the error name — the message can echo a submitted profile value (PII).\n console.error(\n '[identity.customerProfileUpdate] customerProfileUpdate failed',\n error instanceof Error ? error.name : 'UnknownError',\n );\n return [toCustomerProfileError(error)];\n }\n },\n [customerProfileMutation],\n );\n\n return useMemo(\n () => ({ clientProfileUpdate, clientPreferencesUpdate, customerProfileUpdate }),\n [clientProfileUpdate, clientPreferencesUpdate, customerProfileUpdate],\n );\n}\n\n/**\n * Declares the `identity` action namespace — the single source of truth for its method/payload\n * metadata, runtime provider, and `use` hook (mirrors `cartActions`). The native catalog builder\n * (`scripts/build-catalog.mjs`) statically reads this call to emit `actions.json`; at runtime\n * `IdentityActionProvider` calls `useIdentityActions` directly.\n */\nexport const identityActions = defineActions({\n namespace: 'identity',\n description:\n 'Mutation-backed writes against the shopper identity entities (client profile, consent preferences, account profile).',\n provider: { name: 'IdentityActionProvider', importPath: '@vtex/faststore/internal/client' },\n methods: {\n clientProfileUpdate: {\n description:\n 'Persist profile fields (partial) to the active cart (async strategy). Sending email flips Session.isIdentified.',\n payload: [\n { name: 'email', type: 'string', optional: true },\n { name: 'firstName', type: 'string', optional: true },\n { name: 'lastName', type: 'string', optional: true },\n { name: 'phone', type: 'string', optional: true },\n { name: 'document', type: 'string', optional: true },\n ],\n },\n clientPreferencesUpdate: {\n description:\n 'Persist consent opt-in flags (partial) to the active cart (async strategy). Writes only the provided flag(s).',\n payload: [\n { name: 'optinNewsLetter', type: 'boolean', optional: true },\n { name: 'savePersonalData', type: 'boolean', optional: true },\n ],\n },\n customerProfileUpdate: {\n description:\n 'Persist profile fields (partial) to the persistent account profile, not the cart (async strategy). Omitted fields are untouched; an empty string erases.',\n payload: [\n { name: 'firstName', type: 'string', optional: true },\n { name: 'lastName', type: 'string', optional: true },\n { name: 'homePhone', type: 'string', optional: true },\n { name: 'mobilePhone', type: 'string', optional: true },\n { name: 'document', type: 'string', optional: true },\n { name: 'documentType', type: 'string', optional: true },\n { name: 'birthDate', type: 'string', optional: true },\n { name: 'gender', type: 'string', optional: true },\n ],\n },\n },\n use: useIdentityActions,\n});\n"],"mappings":"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"}
1
+ {"version":3,"file":"use-identity-actions.js","names":[],"sources":["../../../src/sdk/identity/use-identity-actions.ts"],"sourcesContent":["'use client';\n\nimport { CombinedGraphQLErrors } from '@apollo/client/errors';\nimport { useMutation } from '@apollo/client/react';\nimport { defineActions } from '@vtex/fs-core';\nimport { useCallback, useMemo } from 'react';\nimport { loggableErrorName } from '../../utils/loggable-error-name.js';\nimport {\n CLIENT_PREFERENCES_UPDATE,\n CLIENT_PROFILE_UPDATE,\n type ClientPreferenceKey,\n type ClientProfileUserError,\n CUSTOMER_PROFILE_UPDATE,\n type CustomerProfileUpdateInput,\n type CustomerProfileUserError,\n} from './operations.js';\n\n/**\n * The `identity` action namespace — the context-free owner of the shopper-profile,\n * consent-preference, and persistent-profile writes\n * (specs/fspg-859-email-field.md, specs/consent-opt-in-component.md,\n * docs/storefront-core/reference-free-particle-model.md § Write side — actions,\n * docs/storefront-core/adr-0010-actions-own-the-write-side.md).\n *\n * It mirrors `useCartActions`: a component anywhere in the tree dispatches the write through the\n * compiler-injected `$actions.identity.*` prop, and the handler calls the corresponding mutation.\n * Every write is **async / pessimistic** (Decision 1): the caller awaits the persisted result. Each\n * call returns its `userErrors` (empty on success) so the caller can surface server-side failures\n * inline; the returned entity self-updates the normalized cache and every reactive subscriber.\n *\n * The first two writes target the cart's sibling identity entities; `customerProfileUpdate` targets\n * the shopper's account profile, which needs no cart at all.\n */\n\n/**\n * Payload for the profile write. Callers persist only the fields they own; other fields are\n * untouched. The payload is passed through to `ClientProfileUpdateInput` unmapped, so this type\n * mirrors that input verbatim — a stacked field only needs a field to already exist here to reach\n * the wire.\n */\nexport type ClientProfileUpdatePayload = Readonly<{\n email?: string;\n firstName?: string;\n lastName?: string;\n phone?: string;\n document?: string;\n}>;\n\n/** Payload for the preferences write — one opt-in flag; the other flag is left untouched. */\nexport type ClientPreferencesUpdatePayload = Readonly<Partial<Record<ClientPreferenceKey, boolean>>>;\n\n/**\n * Payload for the persistent-profile write. Mirrors `CustomerProfileUpdateInput` verbatim and is\n * forwarded unmapped, so an omitted field stays untouched upstream and an empty string erases.\n */\nexport type CustomerProfileUpdatePayload = CustomerProfileUpdateInput;\n\nexport type IdentityActions = Readonly<{\n /**\n * Persist the provided profile fields (partial) to the active cart's `clientProfileData`.\n * Async — awaits the mutation before resolving. Returns the resulting `userErrors` (empty on\n * success).\n */\n clientProfileUpdate: (payload: ClientProfileUpdatePayload) => Promise<readonly ClientProfileUserError[]>;\n /**\n * Persist the provided consent opt-in flag(s) (partial) to the shopper's `ClientPreferences`\n * entity (order-form-backed). Async — awaits the mutation before resolving. Writes ONLY the\n * requested field. Returns the resulting `userErrors` (empty on success).\n */\n clientPreferencesUpdate: (payload: ClientPreferencesUpdatePayload) => Promise<readonly ClientProfileUserError[]>;\n /**\n * Persist the provided profile fields (partial) to the shopper's persistent, cart-independent\n * account profile. Async — awaits the mutation before resolving. Sends exactly the fields it is\n * given: an omitted field is left untouched, an empty string erases. Returns the resulting\n * `userErrors` (empty on success).\n */\n customerProfileUpdate: (payload: CustomerProfileUpdatePayload) => Promise<readonly CustomerProfileUserError[]>;\n}>;\n\nconst NETWORK_PROFILE_ERROR: ClientProfileUserError = {\n code: 'NETWORK_ERROR',\n message: 'Unable to save your details. Please try again.',\n};\n\nconst NETWORK_PREFERENCE_ERROR: ClientProfileUserError = {\n code: 'NETWORK_ERROR',\n message: 'Unable to save your preference. Please try again.',\n};\n\nconst NETWORK_CUSTOMER_PROFILE_ERROR: CustomerProfileUserError = {\n code: 'NETWORK_ERROR',\n message: 'Unable to save your profile. Please try again.',\n};\n\nconst UNAUTHORIZED_CUSTOMER_PROFILE_ERROR: CustomerProfileUserError = {\n code: 'UNAUTHORIZED',\n message: 'Your session has expired. Please sign in again.',\n};\n\n/**\n * The profile write answers an anonymous or expired session with a top-level `UNAUTHORIZED`, never\n * a `userError` (the read answers an anonymous one with a null profile instead). Collapsing it into\n * `NETWORK_ERROR` would offer a retry that cannot succeed, so it gets its own code and the caller can\n * send the shopper back to sign-in.\n */\nfunction toCustomerProfileError(error: unknown): CustomerProfileUserError {\n if (CombinedGraphQLErrors.is(error)) {\n const unauthorized = error.errors.some(({ extensions }) => extensions?.code === 'UNAUTHORIZED');\n if (unauthorized) return UNAUTHORIZED_CUSTOMER_PROFILE_ERROR;\n }\n return NETWORK_CUSTOMER_PROFILE_ERROR;\n}\n\n/**\n * The `identity` namespace hook. Registered with the first-party action registry via `identityActions`\n * below; the compiler-emitted `IdentityActionProvider` calls it and threads the narrowed methods into\n * each consumer's `$actions.identity`.\n */\nexport function useIdentityActions(): IdentityActions {\n const [profileMutation] = useMutation(CLIENT_PROFILE_UPDATE);\n const [preferencesMutation] = useMutation(CLIENT_PREFERENCES_UPDATE);\n const [customerProfileMutation] = useMutation(CUSTOMER_PROFILE_UPDATE);\n\n const clientProfileUpdate = useCallback<IdentityActions['clientProfileUpdate']>(\n async (payload) => {\n try {\n const result = await profileMutation({ variables: { input: payload } });\n return result.data?.clientProfileUpdate?.userErrors ?? [];\n } catch (error) {\n // Log only the error name — the message can echo the submitted email (PII).\n console.error('[identity.clientProfileUpdate] clientProfileUpdate failed', loggableErrorName(error));\n return [NETWORK_PROFILE_ERROR];\n }\n },\n [profileMutation],\n );\n\n const clientPreferencesUpdate = useCallback<IdentityActions['clientPreferencesUpdate']>(\n async (payload) => {\n try {\n const result = await preferencesMutation({ variables: { input: payload } });\n return result.data?.clientPreferencesUpdate?.userErrors ?? [];\n } catch (error) {\n // Log only the error name — mirrors the profile write's PII-safe logging.\n console.error('[identity.clientPreferencesUpdate] clientPreferencesUpdate failed', loggableErrorName(error));\n return [NETWORK_PREFERENCE_ERROR];\n }\n },\n [preferencesMutation],\n );\n\n const customerProfileUpdate = useCallback<IdentityActions['customerProfileUpdate']>(\n async (payload) => {\n try {\n // Forwarded unmapped: an empty string is an explicit erase and must survive to the wire.\n const result = await customerProfileMutation({ variables: { input: payload } });\n return result.data?.customerProfileUpdate?.userErrors ?? [];\n } catch (error) {\n // Log only the error name — the message can echo a submitted profile value (PII).\n console.error('[identity.customerProfileUpdate] customerProfileUpdate failed', loggableErrorName(error));\n return [toCustomerProfileError(error)];\n }\n },\n [customerProfileMutation],\n );\n\n return useMemo(\n () => ({ clientProfileUpdate, clientPreferencesUpdate, customerProfileUpdate }),\n [clientProfileUpdate, clientPreferencesUpdate, customerProfileUpdate],\n );\n}\n\n/**\n * Declares the `identity` action namespace — the single source of truth for its method/payload\n * metadata, runtime provider, and `use` hook (mirrors `cartActions`). The native catalog builder\n * (`scripts/build-catalog.mjs`) statically reads this call to emit `actions.json`; at runtime\n * `IdentityActionProvider` calls `useIdentityActions` directly.\n */\nexport const identityActions = defineActions({\n namespace: 'identity',\n description:\n 'Mutation-backed writes against the shopper identity entities (client profile, consent preferences, account profile).',\n provider: { name: 'IdentityActionProvider', importPath: '@vtex/faststore/internal/client' },\n methods: {\n clientProfileUpdate: {\n description:\n 'Persist profile fields (partial) to the active cart (async strategy). Sending email flips Session.isIdentified.',\n payload: [\n { name: 'email', type: 'string', optional: true },\n { name: 'firstName', type: 'string', optional: true },\n { name: 'lastName', type: 'string', optional: true },\n { name: 'phone', type: 'string', optional: true },\n { name: 'document', type: 'string', optional: true },\n ],\n },\n clientPreferencesUpdate: {\n description:\n 'Persist consent opt-in flags (partial) to the active cart (async strategy). Writes only the provided flag(s).',\n payload: [\n { name: 'optinNewsLetter', type: 'boolean', optional: true },\n { name: 'savePersonalData', type: 'boolean', optional: true },\n ],\n },\n customerProfileUpdate: {\n description:\n 'Persist profile fields (partial) to the persistent account profile, not the cart (async strategy). Omitted fields are untouched; an empty string erases.',\n payload: [\n { name: 'firstName', type: 'string', optional: true },\n { name: 'lastName', type: 'string', optional: true },\n { name: 'homePhone', type: 'string', optional: true },\n { name: 'mobilePhone', type: 'string', optional: true },\n { name: 'document', type: 'string', optional: true },\n { name: 'documentType', type: 'string', optional: true },\n { name: 'birthDate', type: 'string', optional: true },\n { name: 'gender', type: 'string', optional: true },\n ],\n },\n },\n use: useIdentityActions,\n});\n"],"mappings":"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"}
@@ -1,8 +1,8 @@
1
1
  "use client";
2
2
  import { defineActions } from "../../core/dist/actions/registry.js";
3
3
  import "../../core/dist/index.js";
4
- import { PAYMENT_BILLING_ADDRESS_UPDATE, PAYMENT_GATEWAY_CALLBACK, PAYMENT_INSTALLMENT_SELECT, PAYMENT_METHOD_SELECT, PAYMENT_NETWORK_ERROR_CODE, PAYMENT_START_TRANSACTION } from "./operations.js";
5
4
  import { loggableErrorName } from "../../utils/loggable-error-name.js";
5
+ import { PAYMENT_BILLING_ADDRESS_UPDATE, PAYMENT_GATEWAY_CALLBACK, PAYMENT_INSTALLMENT_SELECT, PAYMENT_METHOD_SELECT, PAYMENT_NETWORK_ERROR_CODE, PAYMENT_START_TRANSACTION } from "./operations.js";
6
6
  import { CLIENT_PREFERENCES_UPDATE } from "../identity/operations.js";
7
7
  import { PAYMENT_GATEWAY_USER_ERROR, postPaymentsToGateway } from "./gateway.js";
8
8
  import { useMutation } from "@apollo/client/react";
@@ -1,7 +1,7 @@
1
1
  "use client";
2
+ import { loggableErrorName } from "../../utils/loggable-error-name.js";
2
3
  import { usePaymentSubmission } from "./submission-registry.js";
3
4
  import { PAYMENT_NETWORK_ERROR_CODE } from "./operations.js";
4
- import { loggableErrorName } from "../../utils/loggable-error-name.js";
5
5
  import { isTrustedGatewayOrigin } from "./gateway-origin.js";
6
6
  import { useCallback, useMemo, useRef, useState } from "react";
7
7
  //#region src/sdk/payment/use-place-order.ts
@@ -1,6 +1,7 @@
1
1
  "use client";
2
2
  import { defineActions } from "../../core/dist/actions/registry.js";
3
3
  import "../../core/dist/index.js";
4
+ import { loggableErrorName } from "../../utils/loggable-error-name.js";
4
5
  import { REGION_UPDATE } from "./region-operations.js";
5
6
  import { useMutation } from "@apollo/client/react";
6
7
  import { useCallback, useMemo } from "react";
@@ -38,7 +39,7 @@ function useRegionActions() {
38
39
  try {
39
40
  return (await updateMutation({ variables: { postalCode } })).data?.regionUpdate.errors ?? [];
40
41
  } catch (error) {
41
- console.error("[region.setPostalCode] regionUpdate failed", error);
42
+ console.error("[region.setPostalCode] regionUpdate failed", loggableErrorName(error));
42
43
  return [NETWORK_USER_ERROR];
43
44
  }
44
45
  }, [updateMutation]);
@@ -1 +1 @@
1
- {"version":3,"file":"use-region-actions.js","names":[],"sources":["../../../src/sdk/region/use-region-actions.ts"],"sourcesContent":["'use client';\n\nimport { useMutation } from '@apollo/client/react';\nimport { defineActions } from '@vtex/fs-core';\nimport { useCallback, useMemo } from 'react';\nimport { REGION_UPDATE, type RegionUserError } from './region-operations.js';\n\nexport type { RegionUserError } from './region-operations.js';\n\n/**\n * The `region` action namespace — the one sanctioned client write surface for the shopper's active\n * region (docs/storefront-core/adr-0010-actions-own-the-write-side.md).\n *\n * The single action is async/pessimistic: the handler awaits the mutation and only the\n * server-confirmed payload changes the cache. A region cannot be guessed client-side, because the\n * server owns both the postal-code format and the city it resolves to. The handler is stateless — no\n * reactive vars, no module state — since the active value lives in the normalized cache and its\n * persistence is the server's business.\n *\n * `setPostalCode` resolves the payload `errors` (empty on success) and never throws for an expected\n * outcome; infrastructure failures resolve as the synthetic `NETWORK_ERROR`, matching `session` and\n * `identity`.\n */\nexport type RegionActions = Readonly<{\n /** Submits a postal code as the shopper typed it (masked). Resolves to [] on success. Never throws. */\n setPostalCode: (postalCode: string) => Promise<readonly RegionUserError[]>;\n}>;\n\nconst NETWORK_USER_ERROR: RegionUserError = {\n code: 'NETWORK_ERROR',\n message: 'Unable to set your region. Please try again.',\n};\n\n/**\n * The `region` namespace hook. Registered with the first-party action registry via `regionActions`\n * below; the compiler-emitted `RegionActionProvider` calls it and threads the narrowed method into\n * each consumer's `$actions.region`.\n *\n * A successful write merges the payload into the normalized cache — it selects the full `Region`\n * field set including `id`, so Apollo identifies the entity and every `RegionFragment` subscriber\n * re-renders with no refetch. The merge alone is not enough on the *first* write of a session,\n * though: `Query.region` is nullable, so a shopper who arrives with no region has `null` stored at\n * that root field, and merging an entity never repoints a root field that holds null. The reactive\n * read resolves the entity *through* `Query.region`, so it would keep reading null until a reload.\n * Hence the `update` below, which points the root field at the entity. It is idempotent, so writes\n * after the first cost nothing.\n *\n * The masked value is passed through untouched: the server strips the mask and echoes back a\n * formatted `postalCode`, which keeps one authority on format instead of two that can diverge.\n */\nexport function useRegionActions(): RegionActions {\n const [updateMutation] = useMutation(REGION_UPDATE, {\n update(cache, { data }) {\n const region = data?.regionUpdate.region;\n if (!region) return;\n const id = cache.identify(region);\n if (!id) return;\n cache.modify({\n fields: {\n region: (_existing, { toReference }) => toReference(id),\n },\n });\n },\n });\n\n const setPostalCode = useCallback<RegionActions['setPostalCode']>(\n async (postalCode) => {\n try {\n const result = await updateMutation({ variables: { postalCode } });\n return result.data?.regionUpdate.errors ?? [];\n } catch (error) {\n console.error('[region.setPostalCode] regionUpdate failed', error);\n return [NETWORK_USER_ERROR];\n }\n },\n [updateMutation],\n );\n\n return useMemo(() => ({ setPostalCode }), [setPostalCode]);\n}\n\n/**\n * Declares the `region` action namespace — the single source of truth for its method/payload\n * metadata, runtime provider, and `use` hook (mirrors `sessionActions`). The native catalog builder\n * (`scripts/build-catalog.mjs`) statically reads this call to emit `actions.json`; at runtime\n * `RegionActionProvider` calls `useRegionActions` directly.\n */\nexport const regionActions = defineActions({\n namespace: 'region',\n description: \"Mutation-backed writes against the shopper's active region (postal code).\",\n provider: { name: 'RegionActionProvider', importPath: '@vtex/faststore/internal/client' },\n methods: {\n setPostalCode: {\n description:\n 'Set the active region from a postal code, masked or bare (async/pessimistic). Resolves the payload errors.',\n payload: [{ name: 'postalCode', type: 'string' }],\n },\n },\n use: useRegionActions,\n});\n"],"mappings":";;;;;;;AA4BA,MAAM,qBAAsC;CAC1C,MAAM;CACN,SAAS;AACX;;;;;;;;;;;;;;;;;;AAmBA,SAAgB,mBAAkC;CAChD,MAAM,CAAC,kBAAkB,YAAY,eAAe,EAClD,OAAO,OAAO,EAAE,QAAQ;EACtB,MAAM,SAAS,MAAM,aAAa;EAClC,IAAI,CAAC,QAAQ;EACb,MAAM,KAAK,MAAM,SAAS,MAAM;EAChC,IAAI,CAAC,IAAI;EACT,MAAM,OAAO,EACX,QAAQ,EACN,SAAS,WAAW,EAAE,kBAAkB,YAAY,EAAE,EACxD,EACF,CAAC;CACH,EACF,CAAC;CAED,MAAM,gBAAgB,YACpB,OAAO,eAAe;EACpB,IAAI;GAEF,QAAO,MADc,eAAe,EAAE,WAAW,EAAE,WAAW,EAAE,CAAC,EAAA,CACnD,MAAM,aAAa,UAAU,CAAC;EAC9C,SAAS,OAAO;GACd,QAAQ,MAAM,8CAA8C,KAAK;GACjE,OAAO,CAAC,kBAAkB;EAC5B;CACF,GACA,CAAC,cAAc,CACjB;CAEA,OAAO,eAAe,EAAE,cAAc,IAAI,CAAC,aAAa,CAAC;AAC3D;AAQ6B,cAAc;CACzC,WAAW;CACX,aAAa;CACb,UAAU;EAAE,MAAM;EAAwB,YAAY;CAAkC;CACxF,SAAS,EACP,eAAe;EACb,aACE;EACF,SAAS,CAAC;GAAE,MAAM;GAAc,MAAM;EAAS,CAAC;CAClD,EACF;CACA,KAAK;AACP,CAAC"}
1
+ {"version":3,"file":"use-region-actions.js","names":[],"sources":["../../../src/sdk/region/use-region-actions.ts"],"sourcesContent":["'use client';\n\nimport { useMutation } from '@apollo/client/react';\nimport { defineActions } from '@vtex/fs-core';\nimport { useCallback, useMemo } from 'react';\nimport { loggableErrorName } from '../../utils/loggable-error-name.js';\nimport { REGION_UPDATE, type RegionUserError } from './region-operations.js';\n\nexport type { RegionUserError } from './region-operations.js';\n\n/**\n * The `region` action namespace — the one sanctioned client write surface for the shopper's active\n * region (docs/storefront-core/adr-0010-actions-own-the-write-side.md).\n *\n * The single action is async/pessimistic: the handler awaits the mutation and only the\n * server-confirmed payload changes the cache. A region cannot be guessed client-side, because the\n * server owns both the postal-code format and the city it resolves to. The handler is stateless — no\n * reactive vars, no module state — since the active value lives in the normalized cache and its\n * persistence is the server's business.\n *\n * `setPostalCode` resolves the payload `errors` (empty on success) and never throws for an expected\n * outcome; infrastructure failures resolve as the synthetic `NETWORK_ERROR`, matching `session` and\n * `identity`.\n */\nexport type RegionActions = Readonly<{\n /** Submits a postal code as the shopper typed it (masked). Resolves to [] on success. Never throws. */\n setPostalCode: (postalCode: string) => Promise<readonly RegionUserError[]>;\n}>;\n\nconst NETWORK_USER_ERROR: RegionUserError = {\n code: 'NETWORK_ERROR',\n message: 'Unable to set your region. Please try again.',\n};\n\n/**\n * The `region` namespace hook. Registered with the first-party action registry via `regionActions`\n * below; the compiler-emitted `RegionActionProvider` calls it and threads the narrowed method into\n * each consumer's `$actions.region`.\n *\n * A successful write merges the payload into the normalized cache — it selects the full `Region`\n * field set including `id`, so Apollo identifies the entity and every `RegionFragment` subscriber\n * re-renders with no refetch. The merge alone is not enough on the *first* write of a session,\n * though: `Query.region` is nullable, so a shopper who arrives with no region has `null` stored at\n * that root field, and merging an entity never repoints a root field that holds null. The reactive\n * read resolves the entity *through* `Query.region`, so it would keep reading null until a reload.\n * Hence the `update` below, which points the root field at the entity. It is idempotent, so writes\n * after the first cost nothing.\n *\n * The masked value is passed through untouched: the server strips the mask and echoes back a\n * formatted `postalCode`, which keeps one authority on format instead of two that can diverge.\n */\nexport function useRegionActions(): RegionActions {\n const [updateMutation] = useMutation(REGION_UPDATE, {\n update(cache, { data }) {\n const region = data?.regionUpdate.region;\n if (!region) return;\n const id = cache.identify(region);\n if (!id) return;\n cache.modify({\n fields: {\n region: (_existing, { toReference }) => toReference(id),\n },\n });\n },\n });\n\n const setPostalCode = useCallback<RegionActions['setPostalCode']>(\n async (postalCode) => {\n try {\n const result = await updateMutation({ variables: { postalCode } });\n return result.data?.regionUpdate.errors ?? [];\n } catch (error) {\n console.error('[region.setPostalCode] regionUpdate failed', loggableErrorName(error));\n return [NETWORK_USER_ERROR];\n }\n },\n [updateMutation],\n );\n\n return useMemo(() => ({ setPostalCode }), [setPostalCode]);\n}\n\n/**\n * Declares the `region` action namespace — the single source of truth for its method/payload\n * metadata, runtime provider, and `use` hook (mirrors `sessionActions`). The native catalog builder\n * (`scripts/build-catalog.mjs`) statically reads this call to emit `actions.json`; at runtime\n * `RegionActionProvider` calls `useRegionActions` directly.\n */\nexport const regionActions = defineActions({\n namespace: 'region',\n description: \"Mutation-backed writes against the shopper's active region (postal code).\",\n provider: { name: 'RegionActionProvider', importPath: '@vtex/faststore/internal/client' },\n methods: {\n setPostalCode: {\n description:\n 'Set the active region from a postal code, masked or bare (async/pessimistic). Resolves the payload errors.',\n payload: [{ name: 'postalCode', type: 'string' }],\n },\n },\n use: useRegionActions,\n});\n"],"mappings":";;;;;;;;AA6BA,MAAM,qBAAsC;CAC1C,MAAM;CACN,SAAS;AACX;;;;;;;;;;;;;;;;;;AAmBA,SAAgB,mBAAkC;CAChD,MAAM,CAAC,kBAAkB,YAAY,eAAe,EAClD,OAAO,OAAO,EAAE,QAAQ;EACtB,MAAM,SAAS,MAAM,aAAa;EAClC,IAAI,CAAC,QAAQ;EACb,MAAM,KAAK,MAAM,SAAS,MAAM;EAChC,IAAI,CAAC,IAAI;EACT,MAAM,OAAO,EACX,QAAQ,EACN,SAAS,WAAW,EAAE,kBAAkB,YAAY,EAAE,EACxD,EACF,CAAC;CACH,EACF,CAAC;CAED,MAAM,gBAAgB,YACpB,OAAO,eAAe;EACpB,IAAI;GAEF,QAAO,MADc,eAAe,EAAE,WAAW,EAAE,WAAW,EAAE,CAAC,EAAA,CACnD,MAAM,aAAa,UAAU,CAAC;EAC9C,SAAS,OAAO;GACd,QAAQ,MAAM,8CAA8C,kBAAkB,KAAK,CAAC;GACpF,OAAO,CAAC,kBAAkB;EAC5B;CACF,GACA,CAAC,cAAc,CACjB;CAEA,OAAO,eAAe,EAAE,cAAc,IAAI,CAAC,aAAa,CAAC;AAC3D;AAQ6B,cAAc;CACzC,WAAW;CACX,aAAa;CACb,UAAU;EAAE,MAAM;EAAwB,YAAY;CAAkC;CACxF,SAAS,EACP,eAAe;EACb,aACE;EACF,SAAS,CAAC;GAAE,MAAM;GAAc,MAAM;EAAS,CAAC;CAClD,EACF;CACA,KAAK;AACP,CAAC"}
@@ -0,0 +1,21 @@
1
+ import { CreateClientOptions } from "../client/create-client.js";
2
+ //#region src/sdk/session/read-server-session.d.ts
3
+ /**
4
+ * Classifies `Query.session` for a server caller.
5
+ *
6
+ * Always resolves. `signed-in` is `loggedIn === true`. An identified guest is `anonymous`. A
7
+ * throw, a GraphQL error, a missing `session`, or a timeout is `failed`, including a partial
8
+ * payload that says `loggedIn: true`. The result carries no session payload. No `Cookie` header
9
+ * is set here, so `createClient` keeps forwarding `cookies()`.
10
+ */
11
+ export type ServerSessionRead = {
12
+ status: 'signed-in';
13
+ } | {
14
+ status: 'anonymous';
15
+ } | {
16
+ status: 'failed';
17
+ reason: string;
18
+ };
19
+ export declare function readServerSession(options?: CreateClientOptions): Promise<ServerSessionRead>;
20
+ //#endregion
21
+ //# sourceMappingURL=read-server-session.d.ts.map
@@ -0,0 +1,61 @@
1
+ import { ServerSessionReadDocument } from "../generated/graphql.js";
2
+ import { createClient } from "../client/create-client.js";
3
+ import { CombinedGraphQLErrors } from "@apollo/client/errors";
4
+ //#region src/sdk/session/read-server-session.ts
5
+ /**
6
+ * Local bound for the session read. Not the content runtime's request timeout: that module must
7
+ * stay off the server barrel.
8
+ */
9
+ const SERVER_SESSION_READ_TIMEOUT_MS = 5e3;
10
+ async function readServerSession(options) {
11
+ try {
12
+ const result = await createClient(options).query({
13
+ query: ServerSessionReadDocument,
14
+ errorPolicy: "all",
15
+ fetchPolicy: "no-cache",
16
+ context: { fetchOptions: { signal: AbortSignal.timeout(SERVER_SESSION_READ_TIMEOUT_MS) } }
17
+ });
18
+ if (isTimeoutError(result.error)) return {
19
+ status: "failed",
20
+ reason: "timeout"
21
+ };
22
+ if (result.error || result.data?.session == null) return {
23
+ status: "failed",
24
+ reason: graphqlFailureReason(result.error)
25
+ };
26
+ if (result.data.session.loggedIn === true) return { status: "signed-in" };
27
+ return { status: "anonymous" };
28
+ } catch (error) {
29
+ if (isTimeoutError(error)) return {
30
+ status: "failed",
31
+ reason: "timeout"
32
+ };
33
+ if (error instanceof Error && error.message.length > 0) return {
34
+ status: "failed",
35
+ reason: error.message
36
+ };
37
+ return {
38
+ status: "failed",
39
+ reason: "network error"
40
+ };
41
+ }
42
+ }
43
+ function graphqlFailureReason(error) {
44
+ if (CombinedGraphQLErrors.is(error)) {
45
+ const message = error.errors[0]?.message;
46
+ if (typeof message === "string" && message.length > 0) return message;
47
+ }
48
+ return "graphql error";
49
+ }
50
+ function isTimeoutError(error) {
51
+ if (hasAbortName(error)) return true;
52
+ if (typeof error === "object" && error !== null && "cause" in error) return hasAbortName(error.cause);
53
+ return false;
54
+ }
55
+ function hasAbortName(error) {
56
+ return typeof error === "object" && error !== null && "name" in error && (error.name === "TimeoutError" || error.name === "AbortError");
57
+ }
58
+ //#endregion
59
+ export { readServerSession };
60
+
61
+ //# sourceMappingURL=read-server-session.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"read-server-session.js","names":[],"sources":["../../../src/sdk/session/read-server-session.ts"],"sourcesContent":["import { CombinedGraphQLErrors } from '@apollo/client/errors';\nimport type { CreateClientOptions } from '../client/create-client.js';\nimport { createClient } from '../client/create-client.js';\nimport { ServerSessionReadDocument } from '../generated/graphql.js';\n\n/**\n * Local bound for the session read. Not the content runtime's request timeout: that module must\n * stay off the server barrel.\n */\nconst SERVER_SESSION_READ_TIMEOUT_MS = 5_000;\n\n/**\n * Classifies `Query.session` for a server caller.\n *\n * Always resolves. `signed-in` is `loggedIn === true`. An identified guest is `anonymous`. A\n * throw, a GraphQL error, a missing `session`, or a timeout is `failed`, including a partial\n * payload that says `loggedIn: true`. The result carries no session payload. No `Cookie` header\n * is set here, so `createClient` keeps forwarding `cookies()`.\n */\nexport type ServerSessionRead =\n | { status: 'signed-in' }\n | { status: 'anonymous' }\n | { status: 'failed'; reason: string };\n\nexport async function readServerSession(options?: CreateClientOptions): Promise<ServerSessionRead> {\n try {\n const client = createClient(options);\n const result = await client.query({\n query: ServerSessionReadDocument,\n errorPolicy: 'all',\n fetchPolicy: 'no-cache',\n context: { fetchOptions: { signal: AbortSignal.timeout(SERVER_SESSION_READ_TIMEOUT_MS) } },\n });\n\n // A timeout lands on `result.error` under `errorPolicy: 'all'` rather than rejecting.\n if (isTimeoutError(result.error)) {\n return { status: 'failed', reason: 'timeout' };\n }\n\n if (result.error || result.data?.session == null) {\n return { status: 'failed', reason: graphqlFailureReason(result.error) };\n }\n\n if (result.data.session.loggedIn === true) {\n return { status: 'signed-in' };\n }\n\n return { status: 'anonymous' };\n } catch (error) {\n if (isTimeoutError(error)) {\n return { status: 'failed', reason: 'timeout' };\n }\n if (error instanceof Error && error.message.length > 0) {\n return { status: 'failed', reason: error.message };\n }\n return { status: 'failed', reason: 'network error' };\n }\n}\n\nfunction graphqlFailureReason(error: unknown): string {\n if (CombinedGraphQLErrors.is(error)) {\n const message = error.errors[0]?.message;\n if (typeof message === 'string' && message.length > 0) return message;\n }\n return 'graphql error';\n}\n\nfunction isTimeoutError(error: unknown): boolean {\n if (hasAbortName(error)) return true;\n if (typeof error === 'object' && error !== null && 'cause' in error) {\n return hasAbortName(error.cause);\n }\n return false;\n}\n\nfunction hasAbortName(error: unknown): boolean {\n return (\n typeof error === 'object' &&\n error !== null &&\n 'name' in error &&\n (error.name === 'TimeoutError' || error.name === 'AbortError')\n );\n}\n"],"mappings":";;;;;;;;AASA,MAAM,iCAAiC;AAevC,eAAsB,kBAAkB,SAA2D;CACjG,IAAI;EAEF,MAAM,SAAS,MADA,aAAa,OACF,CAAC,CAAC,MAAM;GAChC,OAAO;GACP,aAAa;GACb,aAAa;GACb,SAAS,EAAE,cAAc,EAAE,QAAQ,YAAY,QAAQ,8BAA8B,EAAE,EAAE;EAC3F,CAAC;EAGD,IAAI,eAAe,OAAO,KAAK,GAC7B,OAAO;GAAE,QAAQ;GAAU,QAAQ;EAAU;EAG/C,IAAI,OAAO,SAAS,OAAO,MAAM,WAAW,MAC1C,OAAO;GAAE,QAAQ;GAAU,QAAQ,qBAAqB,OAAO,KAAK;EAAE;EAGxE,IAAI,OAAO,KAAK,QAAQ,aAAa,MACnC,OAAO,EAAE,QAAQ,YAAY;EAG/B,OAAO,EAAE,QAAQ,YAAY;CAC/B,SAAS,OAAO;EACd,IAAI,eAAe,KAAK,GACtB,OAAO;GAAE,QAAQ;GAAU,QAAQ;EAAU;EAE/C,IAAI,iBAAiB,SAAS,MAAM,QAAQ,SAAS,GACnD,OAAO;GAAE,QAAQ;GAAU,QAAQ,MAAM;EAAQ;EAEnD,OAAO;GAAE,QAAQ;GAAU,QAAQ;EAAgB;CACrD;AACF;AAEA,SAAS,qBAAqB,OAAwB;CACpD,IAAI,sBAAsB,GAAG,KAAK,GAAG;EACnC,MAAM,UAAU,MAAM,OAAO,EAAE,EAAE;EACjC,IAAI,OAAO,YAAY,YAAY,QAAQ,SAAS,GAAG,OAAO;CAChE;CACA,OAAO;AACT;AAEA,SAAS,eAAe,OAAyB;CAC/C,IAAI,aAAa,KAAK,GAAG,OAAO;CAChC,IAAI,OAAO,UAAU,YAAY,UAAU,QAAQ,WAAW,OAC5D,OAAO,aAAa,MAAM,KAAK;CAEjC,OAAO;AACT;AAEA,SAAS,aAAa,OAAyB;CAC7C,OACE,OAAO,UAAU,YACjB,UAAU,QACV,UAAU,UACT,MAAM,SAAS,kBAAkB,MAAM,SAAS;AAErD"}
@@ -1,6 +1,7 @@
1
1
  "use client";
2
2
  import { defineActions } from "../../core/dist/actions/registry.js";
3
3
  import "../../core/dist/index.js";
4
+ import { loggableErrorName } from "../../utils/loggable-error-name.js";
4
5
  import { SESSION_LOGIN_WITH_PASSWORD, SESSION_LOGOUT, SESSION_REQUEST_ACCESS_CODE, SESSION_VALIDATE_ACCESS_CODE } from "./auth-operations.js";
5
6
  import { useMutation } from "@apollo/client/react";
6
7
  import { useCallback, useMemo } from "react";
@@ -24,7 +25,7 @@ function useSessionActions() {
24
25
  try {
25
26
  return (await loginMutation({ variables: { input: payload } })).data?.sessionLoginWithPassword.userErrors ?? [];
26
27
  } catch (error) {
27
- console.error("[session.loginWithPassword] sessionLoginWithPassword failed", error);
28
+ console.error("[session.loginWithPassword] sessionLoginWithPassword failed", loggableErrorName(error));
28
29
  return [NETWORK_USER_ERROR];
29
30
  }
30
31
  }, [loginMutation]);
@@ -36,7 +37,7 @@ function useSessionActions() {
36
37
  userErrors: data?.userErrors ?? []
37
38
  };
38
39
  } catch (error) {
39
- console.error("[session.requestAccessCode] sessionRequestAccessCode failed", error);
40
+ console.error("[session.requestAccessCode] sessionRequestAccessCode failed", loggableErrorName(error));
40
41
  return {
41
42
  authenticationToken: null,
42
43
  userErrors: [NETWORK_USER_ERROR]
@@ -47,7 +48,7 @@ function useSessionActions() {
47
48
  try {
48
49
  return (await validateMutation({ variables: { input: payload } })).data?.sessionValidateAccessCode.userErrors ?? [];
49
50
  } catch (error) {
50
- console.error("[session.validateAccessCode] sessionValidateAccessCode failed", error);
51
+ console.error("[session.validateAccessCode] sessionValidateAccessCode failed", loggableErrorName(error));
51
52
  return [NETWORK_USER_ERROR];
52
53
  }
53
54
  }, [validateMutation]);
@@ -55,7 +56,7 @@ function useSessionActions() {
55
56
  try {
56
57
  return (await logoutMutation()).data?.sessionLogout.userErrors ?? [];
57
58
  } catch (error) {
58
- console.error("[session.logout] sessionLogout failed", error);
59
+ console.error("[session.logout] sessionLogout failed", loggableErrorName(error));
59
60
  return [NETWORK_USER_ERROR];
60
61
  }
61
62
  }, [logoutMutation]);
@@ -1 +1 @@
1
- {"version":3,"file":"use-session-actions.js","names":[],"sources":["../../../src/sdk/session/use-session-actions.ts"],"sourcesContent":["'use client';\n\nimport { useMutation } from '@apollo/client/react';\nimport { defineActions } from '@vtex/fs-core';\nimport { useCallback, useMemo } from 'react';\nimport {\n SESSION_LOGIN_WITH_PASSWORD,\n SESSION_LOGOUT,\n SESSION_REQUEST_ACCESS_CODE,\n SESSION_VALIDATE_ACCESS_CODE,\n type SessionAccessCodeRequestResult,\n type SessionPasswordLoginPayload,\n type SessionRequestAccessCodePayload,\n type SessionUserError,\n type SessionValidateAccessCodePayload,\n} from './auth-operations.js';\n\n/**\n * The `session` action namespace — the one sanctioned client write surface for authentication\n * (docs/storefront-core/reference-free-particle-model.md § Write side — actions, docs/storefront-core/adr-0010-actions-own-the-write-side.md).\n *\n * Every action is async/pessimistic (Decision 1): the handler awaits the mutation and only the\n * server-confirmed payload changes the cache — authentication cannot be guessed client-side. The\n * handlers are stateless: no reactive vars, no module state; the access-code `authenticationToken`\n * is returned to the caller, which owns it as UI flow state (Decision 4). Each action resolves its\n * payload `userErrors` (empty on success) and never throws for expected outcomes; infrastructure\n * failures resolve as the synthetic `NETWORK_ERROR` (Decision 5). The credentials pass through\n * mutation variables only — never logged, never stored.\n */\nexport type SessionActions = Readonly<{\n /** Password sign-in. Async/pessimistic; resolves the payload userErrors (empty on success). */\n loginWithPassword: (payload: SessionPasswordLoginPayload) => Promise<readonly SessionUserError[]>;\n /** Email an access code; resolves the opaque authenticationToken to round-trip into validate. */\n requestAccessCode: (payload: SessionRequestAccessCodePayload) => Promise<SessionAccessCodeRequestResult>;\n /** Validate an access code + token; logs the shopper in exactly as a password login would. */\n validateAccessCode: (payload: SessionValidateAccessCodePayload) => Promise<readonly SessionUserError[]>;\n /** Sign out. Idempotent for guests. */\n logout: () => Promise<readonly SessionUserError[]>;\n}>;\n\nconst NETWORK_USER_ERROR: SessionUserError = {\n code: 'NETWORK_ERROR',\n message: 'Unable to complete the request. Please try again.',\n};\n\n/**\n * The `session` namespace hook. Registered with the first-party action registry via `sessionActions`\n * below; the compiler-emitted `SessionActionProvider` calls it and threads the narrowed methods into\n * each consumer's `$actions.session`. Login/validate/logout refresh the session purely through the\n * normalized-cache merge of the mutation response (Decision 2) — no refetch, no imperative write.\n */\nexport function useSessionActions(): SessionActions {\n const [loginMutation] = useMutation(SESSION_LOGIN_WITH_PASSWORD);\n const [requestMutation] = useMutation(SESSION_REQUEST_ACCESS_CODE);\n const [validateMutation] = useMutation(SESSION_VALIDATE_ACCESS_CODE);\n const [logoutMutation] = useMutation(SESSION_LOGOUT);\n\n const loginWithPassword = useCallback<SessionActions['loginWithPassword']>(\n async (payload) => {\n try {\n const result = await loginMutation({ variables: { input: payload } });\n return result.data?.sessionLoginWithPassword.userErrors ?? [];\n } catch (error) {\n console.error('[session.loginWithPassword] sessionLoginWithPassword failed', error);\n return [NETWORK_USER_ERROR];\n }\n },\n [loginMutation],\n );\n\n const requestAccessCode = useCallback<SessionActions['requestAccessCode']>(\n async (payload) => {\n try {\n const result = await requestMutation({ variables: { input: payload } });\n const data = result.data?.sessionRequestAccessCode;\n return { authenticationToken: data?.authenticationToken ?? null, userErrors: data?.userErrors ?? [] };\n } catch (error) {\n console.error('[session.requestAccessCode] sessionRequestAccessCode failed', error);\n return { authenticationToken: null, userErrors: [NETWORK_USER_ERROR] };\n }\n },\n [requestMutation],\n );\n\n const validateAccessCode = useCallback<SessionActions['validateAccessCode']>(\n async (payload) => {\n try {\n const result = await validateMutation({ variables: { input: payload } });\n return result.data?.sessionValidateAccessCode.userErrors ?? [];\n } catch (error) {\n console.error('[session.validateAccessCode] sessionValidateAccessCode failed', error);\n return [NETWORK_USER_ERROR];\n }\n },\n [validateMutation],\n );\n\n const logout = useCallback<SessionActions['logout']>(async () => {\n try {\n const result = await logoutMutation();\n return result.data?.sessionLogout.userErrors ?? [];\n } catch (error) {\n console.error('[session.logout] sessionLogout failed', error);\n return [NETWORK_USER_ERROR];\n }\n }, [logoutMutation]);\n\n return useMemo(\n () => ({ loginWithPassword, requestAccessCode, validateAccessCode, logout }),\n [loginWithPassword, requestAccessCode, validateAccessCode, logout],\n );\n}\n\n/**\n * Declares the `session` action namespace — the single source of truth for its method/payload\n * metadata, runtime provider, and `use` hook (mirrors `cartActions`). The native catalog builder\n * (`scripts/build-catalog.mjs`) statically reads this call to emit `actions.json`; at runtime\n * `SessionActionProvider` calls `useSessionActions` directly.\n */\nexport const sessionActions = defineActions({\n namespace: 'session',\n description: 'Mutation-backed authentication writes against the VTEX ID session (login, access code, logout).',\n provider: { name: 'SessionActionProvider', importPath: '@vtex/faststore/internal/client' },\n methods: {\n loginWithPassword: {\n description: 'Sign in with email and password (async/pessimistic). Resolves the payload userErrors.',\n payload: [\n { name: 'email', type: 'string' },\n { name: 'password', type: 'string' },\n ],\n },\n requestAccessCode: {\n description: 'Email the shopper an access code; resolves the opaque authenticationToken to round-trip.',\n payload: [{ name: 'email', type: 'string' }],\n },\n validateAccessCode: {\n description: 'Validate an access code with its authenticationToken (async/pessimistic); logs the shopper in.',\n payload: [\n { name: 'email', type: 'string' },\n { name: 'accessCode', type: 'string' },\n { name: 'authenticationToken', type: 'string' },\n ],\n },\n logout: {\n description: 'Sign out, clearing the auth cookies (async/pessimistic). Idempotent for guests.',\n payload: [],\n },\n },\n use: useSessionActions,\n});\n"],"mappings":";;;;;;;AAwCA,MAAM,qBAAuC;CAC3C,MAAM;CACN,SAAS;AACX;;;;;;;AAQA,SAAgB,oBAAoC;CAClD,MAAM,CAAC,iBAAiB,YAAY,2BAA2B;CAC/D,MAAM,CAAC,mBAAmB,YAAY,2BAA2B;CACjE,MAAM,CAAC,oBAAoB,YAAY,4BAA4B;CACnE,MAAM,CAAC,kBAAkB,YAAY,cAAc;CAEnD,MAAM,oBAAoB,YACxB,OAAO,YAAY;EACjB,IAAI;GAEF,QAAO,MADc,cAAc,EAAE,WAAW,EAAE,OAAO,QAAQ,EAAE,CAAC,EAAA,CACtD,MAAM,yBAAyB,cAAc,CAAC;EAC9D,SAAS,OAAO;GACd,QAAQ,MAAM,+DAA+D,KAAK;GAClF,OAAO,CAAC,kBAAkB;EAC5B;CACF,GACA,CAAC,aAAa,CAChB;CAEA,MAAM,oBAAoB,YACxB,OAAO,YAAY;EACjB,IAAI;GAEF,MAAM,QAAO,MADQ,gBAAgB,EAAE,WAAW,EAAE,OAAO,QAAQ,EAAE,CAAC,EAAA,CAClD,MAAM;GAC1B,OAAO;IAAE,qBAAqB,MAAM,uBAAuB;IAAM,YAAY,MAAM,cAAc,CAAC;GAAE;EACtG,SAAS,OAAO;GACd,QAAQ,MAAM,+DAA+D,KAAK;GAClF,OAAO;IAAE,qBAAqB;IAAM,YAAY,CAAC,kBAAkB;GAAE;EACvE;CACF,GACA,CAAC,eAAe,CAClB;CAEA,MAAM,qBAAqB,YACzB,OAAO,YAAY;EACjB,IAAI;GAEF,QAAO,MADc,iBAAiB,EAAE,WAAW,EAAE,OAAO,QAAQ,EAAE,CAAC,EAAA,CACzD,MAAM,0BAA0B,cAAc,CAAC;EAC/D,SAAS,OAAO;GACd,QAAQ,MAAM,iEAAiE,KAAK;GACpF,OAAO,CAAC,kBAAkB;EAC5B;CACF,GACA,CAAC,gBAAgB,CACnB;CAEA,MAAM,SAAS,YAAsC,YAAY;EAC/D,IAAI;GAEF,QAAO,MADc,eAAe,EAAA,CACtB,MAAM,cAAc,cAAc,CAAC;EACnD,SAAS,OAAO;GACd,QAAQ,MAAM,yCAAyC,KAAK;GAC5D,OAAO,CAAC,kBAAkB;EAC5B;CACF,GAAG,CAAC,cAAc,CAAC;CAEnB,OAAO,eACE;EAAE;EAAmB;EAAmB;EAAoB;CAAO,IAC1E;EAAC;EAAmB;EAAmB;EAAoB;CAAM,CACnE;AACF;AAQ8B,cAAc;CAC1C,WAAW;CACX,aAAa;CACb,UAAU;EAAE,MAAM;EAAyB,YAAY;CAAkC;CACzF,SAAS;EACP,mBAAmB;GACjB,aAAa;GACb,SAAS,CACP;IAAE,MAAM;IAAS,MAAM;GAAS,GAChC;IAAE,MAAM;IAAY,MAAM;GAAS,CACrC;EACF;EACA,mBAAmB;GACjB,aAAa;GACb,SAAS,CAAC;IAAE,MAAM;IAAS,MAAM;GAAS,CAAC;EAC7C;EACA,oBAAoB;GAClB,aAAa;GACb,SAAS;IACP;KAAE,MAAM;KAAS,MAAM;IAAS;IAChC;KAAE,MAAM;KAAc,MAAM;IAAS;IACrC;KAAE,MAAM;KAAuB,MAAM;IAAS;GAChD;EACF;EACA,QAAQ;GACN,aAAa;GACb,SAAS,CAAC;EACZ;CACF;CACA,KAAK;AACP,CAAC"}
1
+ {"version":3,"file":"use-session-actions.js","names":[],"sources":["../../../src/sdk/session/use-session-actions.ts"],"sourcesContent":["'use client';\n\nimport { useMutation } from '@apollo/client/react';\nimport { defineActions } from '@vtex/fs-core';\nimport { useCallback, useMemo } from 'react';\nimport { loggableErrorName } from '../../utils/loggable-error-name.js';\nimport {\n SESSION_LOGIN_WITH_PASSWORD,\n SESSION_LOGOUT,\n SESSION_REQUEST_ACCESS_CODE,\n SESSION_VALIDATE_ACCESS_CODE,\n type SessionAccessCodeRequestResult,\n type SessionPasswordLoginPayload,\n type SessionRequestAccessCodePayload,\n type SessionUserError,\n type SessionValidateAccessCodePayload,\n} from './auth-operations.js';\n\n/**\n * The `session` action namespace — the one sanctioned client write surface for authentication\n * (docs/storefront-core/reference-free-particle-model.md § Write side — actions, docs/storefront-core/adr-0010-actions-own-the-write-side.md).\n *\n * Every action is async/pessimistic (Decision 1): the handler awaits the mutation and only the\n * server-confirmed payload changes the cache — authentication cannot be guessed client-side. The\n * handlers are stateless: no reactive vars, no module state; the access-code `authenticationToken`\n * is returned to the caller, which owns it as UI flow state (Decision 4). Each action resolves its\n * payload `userErrors` (empty on success) and never throws for expected outcomes; infrastructure\n * failures resolve as the synthetic `NETWORK_ERROR` (Decision 5). The credentials pass through\n * mutation variables only — never logged, never stored.\n */\nexport type SessionActions = Readonly<{\n /** Password sign-in. Async/pessimistic; resolves the payload userErrors (empty on success). */\n loginWithPassword: (payload: SessionPasswordLoginPayload) => Promise<readonly SessionUserError[]>;\n /** Email an access code; resolves the opaque authenticationToken to round-trip into validate. */\n requestAccessCode: (payload: SessionRequestAccessCodePayload) => Promise<SessionAccessCodeRequestResult>;\n /** Validate an access code + token; logs the shopper in exactly as a password login would. */\n validateAccessCode: (payload: SessionValidateAccessCodePayload) => Promise<readonly SessionUserError[]>;\n /** Sign out. Idempotent for guests. */\n logout: () => Promise<readonly SessionUserError[]>;\n}>;\n\nconst NETWORK_USER_ERROR: SessionUserError = {\n code: 'NETWORK_ERROR',\n message: 'Unable to complete the request. Please try again.',\n};\n\n/**\n * The `session` namespace hook. Registered with the first-party action registry via `sessionActions`\n * below; the compiler-emitted `SessionActionProvider` calls it and threads the narrowed methods into\n * each consumer's `$actions.session`. Login/validate/logout refresh the session purely through the\n * normalized-cache merge of the mutation response (Decision 2) — no refetch, no imperative write.\n */\nexport function useSessionActions(): SessionActions {\n const [loginMutation] = useMutation(SESSION_LOGIN_WITH_PASSWORD);\n const [requestMutation] = useMutation(SESSION_REQUEST_ACCESS_CODE);\n const [validateMutation] = useMutation(SESSION_VALIDATE_ACCESS_CODE);\n const [logoutMutation] = useMutation(SESSION_LOGOUT);\n\n const loginWithPassword = useCallback<SessionActions['loginWithPassword']>(\n async (payload) => {\n try {\n const result = await loginMutation({ variables: { input: payload } });\n return result.data?.sessionLoginWithPassword.userErrors ?? [];\n } catch (error) {\n console.error('[session.loginWithPassword] sessionLoginWithPassword failed', loggableErrorName(error));\n return [NETWORK_USER_ERROR];\n }\n },\n [loginMutation],\n );\n\n const requestAccessCode = useCallback<SessionActions['requestAccessCode']>(\n async (payload) => {\n try {\n const result = await requestMutation({ variables: { input: payload } });\n const data = result.data?.sessionRequestAccessCode;\n return { authenticationToken: data?.authenticationToken ?? null, userErrors: data?.userErrors ?? [] };\n } catch (error) {\n console.error('[session.requestAccessCode] sessionRequestAccessCode failed', loggableErrorName(error));\n return { authenticationToken: null, userErrors: [NETWORK_USER_ERROR] };\n }\n },\n [requestMutation],\n );\n\n const validateAccessCode = useCallback<SessionActions['validateAccessCode']>(\n async (payload) => {\n try {\n const result = await validateMutation({ variables: { input: payload } });\n return result.data?.sessionValidateAccessCode.userErrors ?? [];\n } catch (error) {\n console.error('[session.validateAccessCode] sessionValidateAccessCode failed', loggableErrorName(error));\n return [NETWORK_USER_ERROR];\n }\n },\n [validateMutation],\n );\n\n const logout = useCallback<SessionActions['logout']>(async () => {\n try {\n const result = await logoutMutation();\n return result.data?.sessionLogout.userErrors ?? [];\n } catch (error) {\n console.error('[session.logout] sessionLogout failed', loggableErrorName(error));\n return [NETWORK_USER_ERROR];\n }\n }, [logoutMutation]);\n\n return useMemo(\n () => ({ loginWithPassword, requestAccessCode, validateAccessCode, logout }),\n [loginWithPassword, requestAccessCode, validateAccessCode, logout],\n );\n}\n\n/**\n * Declares the `session` action namespace — the single source of truth for its method/payload\n * metadata, runtime provider, and `use` hook (mirrors `cartActions`). The native catalog builder\n * (`scripts/build-catalog.mjs`) statically reads this call to emit `actions.json`; at runtime\n * `SessionActionProvider` calls `useSessionActions` directly.\n */\nexport const sessionActions = defineActions({\n namespace: 'session',\n description: 'Mutation-backed authentication writes against the VTEX ID session (login, access code, logout).',\n provider: { name: 'SessionActionProvider', importPath: '@vtex/faststore/internal/client' },\n methods: {\n loginWithPassword: {\n description: 'Sign in with email and password (async/pessimistic). Resolves the payload userErrors.',\n payload: [\n { name: 'email', type: 'string' },\n { name: 'password', type: 'string' },\n ],\n },\n requestAccessCode: {\n description: 'Email the shopper an access code; resolves the opaque authenticationToken to round-trip.',\n payload: [{ name: 'email', type: 'string' }],\n },\n validateAccessCode: {\n description: 'Validate an access code with its authenticationToken (async/pessimistic); logs the shopper in.',\n payload: [\n { name: 'email', type: 'string' },\n { name: 'accessCode', type: 'string' },\n { name: 'authenticationToken', type: 'string' },\n ],\n },\n logout: {\n description: 'Sign out, clearing the auth cookies (async/pessimistic). Idempotent for guests.',\n payload: [],\n },\n },\n use: useSessionActions,\n});\n"],"mappings":";;;;;;;;AAyCA,MAAM,qBAAuC;CAC3C,MAAM;CACN,SAAS;AACX;;;;;;;AAQA,SAAgB,oBAAoC;CAClD,MAAM,CAAC,iBAAiB,YAAY,2BAA2B;CAC/D,MAAM,CAAC,mBAAmB,YAAY,2BAA2B;CACjE,MAAM,CAAC,oBAAoB,YAAY,4BAA4B;CACnE,MAAM,CAAC,kBAAkB,YAAY,cAAc;CAEnD,MAAM,oBAAoB,YACxB,OAAO,YAAY;EACjB,IAAI;GAEF,QAAO,MADc,cAAc,EAAE,WAAW,EAAE,OAAO,QAAQ,EAAE,CAAC,EAAA,CACtD,MAAM,yBAAyB,cAAc,CAAC;EAC9D,SAAS,OAAO;GACd,QAAQ,MAAM,+DAA+D,kBAAkB,KAAK,CAAC;GACrG,OAAO,CAAC,kBAAkB;EAC5B;CACF,GACA,CAAC,aAAa,CAChB;CAEA,MAAM,oBAAoB,YACxB,OAAO,YAAY;EACjB,IAAI;GAEF,MAAM,QAAO,MADQ,gBAAgB,EAAE,WAAW,EAAE,OAAO,QAAQ,EAAE,CAAC,EAAA,CAClD,MAAM;GAC1B,OAAO;IAAE,qBAAqB,MAAM,uBAAuB;IAAM,YAAY,MAAM,cAAc,CAAC;GAAE;EACtG,SAAS,OAAO;GACd,QAAQ,MAAM,+DAA+D,kBAAkB,KAAK,CAAC;GACrG,OAAO;IAAE,qBAAqB;IAAM,YAAY,CAAC,kBAAkB;GAAE;EACvE;CACF,GACA,CAAC,eAAe,CAClB;CAEA,MAAM,qBAAqB,YACzB,OAAO,YAAY;EACjB,IAAI;GAEF,QAAO,MADc,iBAAiB,EAAE,WAAW,EAAE,OAAO,QAAQ,EAAE,CAAC,EAAA,CACzD,MAAM,0BAA0B,cAAc,CAAC;EAC/D,SAAS,OAAO;GACd,QAAQ,MAAM,iEAAiE,kBAAkB,KAAK,CAAC;GACvG,OAAO,CAAC,kBAAkB;EAC5B;CACF,GACA,CAAC,gBAAgB,CACnB;CAEA,MAAM,SAAS,YAAsC,YAAY;EAC/D,IAAI;GAEF,QAAO,MADc,eAAe,EAAA,CACtB,MAAM,cAAc,cAAc,CAAC;EACnD,SAAS,OAAO;GACd,QAAQ,MAAM,yCAAyC,kBAAkB,KAAK,CAAC;GAC/E,OAAO,CAAC,kBAAkB;EAC5B;CACF,GAAG,CAAC,cAAc,CAAC;CAEnB,OAAO,eACE;EAAE;EAAmB;EAAmB;EAAoB;CAAO,IAC1E;EAAC;EAAmB;EAAmB;EAAoB;CAAM,CACnE;AACF;AAQ8B,cAAc;CAC1C,WAAW;CACX,aAAa;CACb,UAAU;EAAE,MAAM;EAAyB,YAAY;CAAkC;CACzF,SAAS;EACP,mBAAmB;GACjB,aAAa;GACb,SAAS,CACP;IAAE,MAAM;IAAS,MAAM;GAAS,GAChC;IAAE,MAAM;IAAY,MAAM;GAAS,CACrC;EACF;EACA,mBAAmB;GACjB,aAAa;GACb,SAAS,CAAC;IAAE,MAAM;IAAS,MAAM;GAAS,CAAC;EAC7C;EACA,oBAAoB;GAClB,aAAa;GACb,SAAS;IACP;KAAE,MAAM;KAAS,MAAM;IAAS;IAChC;KAAE,MAAM;KAAc,MAAM;IAAS;IACrC;KAAE,MAAM;KAAuB,MAAM;IAAS;GAChD;EACF;EACA,QAAQ;GACN,aAAa;GACb,SAAS,CAAC;EACZ;CACF;CACA,KAAK;AACP,CAAC"}
@@ -1,5 +1,6 @@
1
1
  "use client";
2
2
  import { graphql } from "../generated/gql.js";
3
+ import { loggableErrorName } from "../../utils/loggable-error-name.js";
3
4
  import { getApolloContext } from "@apollo/client/react";
4
5
  import { useCallback, useContext } from "react";
5
6
  //#region src/sdk/session/use-session-revalidation.ts
@@ -54,7 +55,7 @@ function useSessionRevalidation() {
54
55
  });
55
56
  return "revalidated";
56
57
  } catch (error) {
57
- console.error("[useSessionRevalidation] session re-read failed", error);
58
+ console.error("[useSessionRevalidation] session re-read failed", loggableErrorName(error));
58
59
  return "failed";
59
60
  }
60
61
  }, [client]);
@@ -1 +1 @@
1
- {"version":3,"file":"use-session-revalidation.js","names":[],"sources":["../../../src/sdk/session/use-session-revalidation.ts"],"sourcesContent":["'use client';\n\nimport { getApolloContext } from '@apollo/client/react';\nimport { useCallback, useContext } from 'react';\nimport { graphql } from '../generated/gql.js';\n\n/**\n * The imperative re-read of the session, for the one case the reactive path cannot serve: a document\n * the browser restored from its back-forward cache. A restored document resumes its heap without\n * remounting, so `PageReactiveDataRoot` never re-runs its `cache-first` query and\n * `useReactiveEntity` never issues a request — the session comes back exactly as stale as the frame\n * around it.\n *\n * Selects the same field set as `SessionFragment`, so the response writes over the entity the layout\n * query already references and every `SessionRoot` below it reacts.\n */\nexport const ACCOUNT_SESSION_REVALIDATE = graphql(`\n query AccountSessionRevalidate {\n session {\n ...SessionFragment\n }\n }\n`);\n\n/**\n * What a revalidation is able to say about the session afterwards.\n *\n * `unavailable` is not a failure. With no Apollo client there is no cache to hold a stale session and\n * nothing to re-read: the session in the tree came from a `$data` prop, and a prop cannot go stale\n * behind the caller's back. A caller that treats it as a failure is distrusting an answer that was\n * never checkable — which is every story and test composed without a provider.\n */\nexport type SessionRevalidation = 'revalidated' | 'failed' | 'unavailable';\n\n/**\n * Discards the cached session and re-reads it from the network, resolving what it was able to find\n * out. Only `failed` means the caller is holding an answer it has reason to distrust: the session was\n * discarded and the query that should have replaced it rejected.\n *\n * **The discard comes first, and that ordering is the contract.** For the whole of the re-read there\n * must be no session in the cache for anything to read: a re-read that merely overwrote would leave\n * the restored `loggedIn` answering every consumer in the tree until the network replied. What has to\n * go is the normalized entity, not the root field that points at it — the reactive read subscribes to\n * `Session:<id>` through `useFragment`, so a root field cleared from under a live entity leaves that\n * read complete and the consumer resolved.\n *\n * The consumers follow asynchronously, once the watched query has re-read: a component that must\n * withhold something in the same frame the discard happens has to hold that state itself, and\n * `AccountAccessGate` does.\n *\n * The client is resolved through Apollo's context rather than `useApolloClient()`, which throws when\n * there is none: every session-aware story and test in this package renders `SessionRoot` bare, and a\n * revalidation that cannot run is not a reason for a component to fail to render.\n */\nexport function useSessionRevalidation(): () => Promise<SessionRevalidation> {\n const { client } = useContext(getApolloContext());\n\n return useCallback(async (): Promise<SessionRevalidation> => {\n if (!client) {\n return 'unavailable';\n }\n\n try {\n // The document about to be re-read is also what names the entity to discard: it selects the\n // same field, so it resolves whichever Session the cache is currently holding. An incomplete\n // read means there is nothing cached to discard, and the re-read below is all that is needed.\n const cached = client.cache.readQuery({ query: ACCOUNT_SESSION_REVALIDATE });\n const entity = cached?.session ? client.cache.identify(cached.session) : undefined;\n if (entity) {\n client.cache.evict({ id: entity });\n }\n\n await client.query({ query: ACCOUNT_SESSION_REVALIDATE, fetchPolicy: 'network-only' });\n return 'revalidated';\n } catch (error) {\n // The discard is inside this guard along with the re-read, so a cache that refused either one\n // resolves rather than rejecting. A caller left awaiting a promise that never settles would\n // hold its shopper in the wait forever, which is the one outcome worse than saying no.\n console.error('[useSessionRevalidation] session re-read failed', error);\n return 'failed';\n }\n }, [client]);\n}\n"],"mappings":";;;;;;;;;;;;;;;AAgBA,MAAa,6BAA6B,QAAQ;;;;;;CAMjD;;;;;;;;;;;;;;;;;;;;;AAgCD,SAAgB,yBAA6D;CAC3E,MAAM,EAAE,WAAW,WAAW,iBAAiB,CAAC;CAEhD,OAAO,YAAY,YAA0C;EAC3D,IAAI,CAAC,QACH,OAAO;EAGT,IAAI;GAIF,MAAM,SAAS,OAAO,MAAM,UAAU,EAAE,OAAO,2BAA2B,CAAC;GAC3E,MAAM,SAAS,QAAQ,UAAU,OAAO,MAAM,SAAS,OAAO,OAAO,IAAI,KAAA;GACzE,IAAI,QACF,OAAO,MAAM,MAAM,EAAE,IAAI,OAAO,CAAC;GAGnC,MAAM,OAAO,MAAM;IAAE,OAAO;IAA4B,aAAa;GAAe,CAAC;GACrF,OAAO;EACT,SAAS,OAAO;GAId,QAAQ,MAAM,mDAAmD,KAAK;GACtE,OAAO;EACT;CACF,GAAG,CAAC,MAAM,CAAC;AACb"}
1
+ {"version":3,"file":"use-session-revalidation.js","names":[],"sources":["../../../src/sdk/session/use-session-revalidation.ts"],"sourcesContent":["'use client';\n\nimport { getApolloContext } from '@apollo/client/react';\nimport { useCallback, useContext } from 'react';\nimport { loggableErrorName } from '../../utils/loggable-error-name.js';\nimport { graphql } from '../generated/gql.js';\n\n/**\n * The imperative re-read of the session, for the one case the reactive path cannot serve: a document\n * the browser restored from its back-forward cache. A restored document resumes its heap without\n * remounting, so `PageReactiveDataRoot` never re-runs its `cache-first` query and\n * `useReactiveEntity` never issues a request — the session comes back exactly as stale as the frame\n * around it.\n *\n * Selects the same field set as `SessionFragment`, so the response writes over the entity the layout\n * query already references and every `SessionRoot` below it reacts.\n */\nexport const ACCOUNT_SESSION_REVALIDATE = graphql(`\n query AccountSessionRevalidate {\n session {\n ...SessionFragment\n }\n }\n`);\n\n/**\n * What a revalidation is able to say about the session afterwards.\n *\n * `unavailable` is not a failure. With no Apollo client there is no cache to hold a stale session and\n * nothing to re-read: the session in the tree came from a `$data` prop, and a prop cannot go stale\n * behind the caller's back. A caller that treats it as a failure is distrusting an answer that was\n * never checkable — which is every story and test composed without a provider.\n */\nexport type SessionRevalidation = 'revalidated' | 'failed' | 'unavailable';\n\n/**\n * Discards the cached session and re-reads it from the network, resolving what it was able to find\n * out. Only `failed` means the caller is holding an answer it has reason to distrust: the session was\n * discarded and the query that should have replaced it rejected.\n *\n * **The discard comes first, and that ordering is the contract.** For the whole of the re-read there\n * must be no session in the cache for anything to read: a re-read that merely overwrote would leave\n * the restored `loggedIn` answering every consumer in the tree until the network replied. What has to\n * go is the normalized entity, not the root field that points at it — the reactive read subscribes to\n * `Session:<id>` through `useFragment`, so a root field cleared from under a live entity leaves that\n * read complete and the consumer resolved.\n *\n * The consumers follow asynchronously, once the watched query has re-read: a component that must\n * withhold something in the same frame the discard happens has to hold that state itself, and\n * `AccountAccessGate` does.\n *\n * The client is resolved through Apollo's context rather than `useApolloClient()`, which throws when\n * there is none: every session-aware story and test in this package renders `SessionRoot` bare, and a\n * revalidation that cannot run is not a reason for a component to fail to render.\n */\nexport function useSessionRevalidation(): () => Promise<SessionRevalidation> {\n const { client } = useContext(getApolloContext());\n\n return useCallback(async (): Promise<SessionRevalidation> => {\n if (!client) {\n return 'unavailable';\n }\n\n try {\n // The document about to be re-read is also what names the entity to discard: it selects the\n // same field, so it resolves whichever Session the cache is currently holding. An incomplete\n // read means there is nothing cached to discard, and the re-read below is all that is needed.\n const cached = client.cache.readQuery({ query: ACCOUNT_SESSION_REVALIDATE });\n const entity = cached?.session ? client.cache.identify(cached.session) : undefined;\n if (entity) {\n client.cache.evict({ id: entity });\n }\n\n await client.query({ query: ACCOUNT_SESSION_REVALIDATE, fetchPolicy: 'network-only' });\n return 'revalidated';\n } catch (error) {\n // The discard is inside this guard along with the re-read, so a cache that refused either one\n // resolves rather than rejecting. A caller left awaiting a promise that never settles would\n // hold its shopper in the wait forever, which is the one outcome worse than saying no.\n console.error('[useSessionRevalidation] session re-read failed', loggableErrorName(error));\n return 'failed';\n }\n }, [client]);\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAiBA,MAAa,6BAA6B,QAAQ;;;;;;CAMjD;;;;;;;;;;;;;;;;;;;;;AAgCD,SAAgB,yBAA6D;CAC3E,MAAM,EAAE,WAAW,WAAW,iBAAiB,CAAC;CAEhD,OAAO,YAAY,YAA0C;EAC3D,IAAI,CAAC,QACH,OAAO;EAGT,IAAI;GAIF,MAAM,SAAS,OAAO,MAAM,UAAU,EAAE,OAAO,2BAA2B,CAAC;GAC3E,MAAM,SAAS,QAAQ,UAAU,OAAO,MAAM,SAAS,OAAO,OAAO,IAAI,KAAA;GACzE,IAAI,QACF,OAAO,MAAM,MAAM,EAAE,IAAI,OAAO,CAAC;GAGnC,MAAM,OAAO,MAAM;IAAE,OAAO;IAA4B,aAAa;GAAe,CAAC;GACrF,OAAO;EACT,SAAS,OAAO;GAId,QAAQ,MAAM,mDAAmD,kBAAkB,KAAK,CAAC;GACzF,OAAO;EACT;CACF,GAAG,CAAC,MAAM,CAAC;AACb"}
@@ -1,6 +1,7 @@
1
1
  "use client";
2
2
  import { defineActions } from "../../core/dist/actions/registry.js";
3
3
  import "../../core/dist/index.js";
4
+ import { loggableErrorName } from "../../utils/loggable-error-name.js";
4
5
  import { SHIPPING_OPTION_SELECT } from "./option-select-operations.js";
5
6
  import { SHIPPING_ADDRESS_UPDATE, SHIPPING_NETWORK_ERROR_CODE } from "./shipping-operations.js";
6
7
  import { useMutation } from "@apollo/client/react";
@@ -27,7 +28,7 @@ function useShippingActions() {
27
28
  try {
28
29
  return (await addressMutation({ variables: { input: address } })).data?.shippingAddressUpdate.userErrors ?? [];
29
30
  } catch (error) {
30
- console.error("[shipping.setAddress] shippingAddressUpdate failed", error);
31
+ console.error("[shipping.setAddress] shippingAddressUpdate failed", loggableErrorName(error));
31
32
  return [SET_ADDRESS_NETWORK_ERROR];
32
33
  }
33
34
  }, [addressMutation]);
@@ -35,7 +36,7 @@ function useShippingActions() {
35
36
  try {
36
37
  return (await selectOptionMutation({ variables: { input: { optionId } } })).data?.shippingOptionSelect.userErrors ?? [];
37
38
  } catch (error) {
38
- console.error("[shipping.selectOption] shippingOptionSelect failed", error);
39
+ console.error("[shipping.selectOption] shippingOptionSelect failed", loggableErrorName(error));
39
40
  return [SELECT_OPTION_NETWORK_ERROR];
40
41
  }
41
42
  }, [selectOptionMutation]);
@@ -1 +1 @@
1
- {"version":3,"file":"use-shipping-actions.js","names":[],"sources":["../../../src/sdk/shipping/use-shipping-actions.ts"],"sourcesContent":["'use client';\n\nimport { useMutation } from '@apollo/client/react';\nimport { defineActions } from '@vtex/fs-core';\nimport { useCallback, useMemo } from 'react';\nimport { SHIPPING_OPTION_SELECT, type ShippingOptionSelectUserError } from './option-select-operations.js';\nimport {\n SHIPPING_ADDRESS_UPDATE,\n SHIPPING_NETWORK_ERROR_CODE,\n type ShippingAddressInput,\n type ShippingAddressUpdateErrorEntity,\n} from './shipping-operations.js';\n\n/**\n * The `shipping` action namespace — the sanctioned client write surface against the VTEX orderForm\n * shippingData: delivery-address updates (docs/storefront-core/reference-free-particle-model.md § The cart write contract;\n * docs/storefront-core/adr-0010-actions-own-the-write-side.md) and cart-scoped delivery-option\n * selection (docs/storefront-core/reference-free-particle-model.md § The cart write contract). Per Decision 4 the two tasks share this one\n * namespace — T2 (`setAddress`) merged first and owns the registration, T3 extends it with\n * `selectOption` here.\n *\n * Both actions are async/pessimistic (Decision 1 of the address spec): the handler awaits the\n * mutation and only the server-confirmed payload changes the cache. Each is stateless (no reactive\n * vars, no module state), resolves its payload `userErrors` (empty on success), and never throws for\n * expected outcomes; an infrastructure failure (network or an upstream GraphQLError) is caught and\n * collapsed to one synthetic network `userError` — no per-code branching (US-4, FR-5). Inputs pass\n * through mutation variables only — never logged, never stored beyond the cache.\n */\nexport type ShippingActions = Readonly<{\n /** Persist the single delivery address (async/pessimistic). Resolves the payload userErrors. */\n setAddress: (address: ShippingAddressInput) => Promise<readonly ShippingAddressUpdateErrorEntity[]>;\n /** Select a delivery option for the whole cart. Resolves the payload userErrors (empty on success). */\n selectOption: (optionId: string) => Promise<readonly ShippingOptionSelectUserError[]>;\n}>;\n\nconst SET_ADDRESS_NETWORK_ERROR: ShippingAddressUpdateErrorEntity = {\n code: SHIPPING_NETWORK_ERROR_CODE,\n message: 'Unable to complete the request. Please try again.',\n};\n\nconst SELECT_OPTION_NETWORK_ERROR: ShippingOptionSelectUserError = {\n code: 'NETWORK_ERROR',\n message: 'Unable to update the delivery option. Please try again.',\n};\n\n/**\n * The `shipping` namespace hook. Registered with the first-party action registry via `shippingActions`\n * below; the compiler-emitted `ShippingActionProvider` calls it and threads the narrowed methods into\n * each consumer's `$actions.shipping`. Writes persist purely through the normalized-cache merge of\n * each mutation response (Decision 2 of the address spec) — no refetch, no imperative write.\n */\nexport function useShippingActions(): ShippingActions {\n const [addressMutation] = useMutation(SHIPPING_ADDRESS_UPDATE);\n const [selectOptionMutation] = useMutation(SHIPPING_OPTION_SELECT);\n\n const setAddress = useCallback<ShippingActions['setAddress']>(\n async (address) => {\n try {\n const result = await addressMutation({ variables: { input: address } });\n return result.data?.shippingAddressUpdate.userErrors ?? [];\n } catch (error) {\n console.error('[shipping.setAddress] shippingAddressUpdate failed', error);\n return [SET_ADDRESS_NETWORK_ERROR];\n }\n },\n [addressMutation],\n );\n\n const selectOption = useCallback<ShippingActions['selectOption']>(\n async (optionId) => {\n try {\n const result = await selectOptionMutation({ variables: { input: { optionId } } });\n return result.data?.shippingOptionSelect.userErrors ?? [];\n } catch (error) {\n console.error('[shipping.selectOption] shippingOptionSelect failed', error);\n return [SELECT_OPTION_NETWORK_ERROR];\n }\n },\n [selectOptionMutation],\n );\n\n return useMemo(() => ({ setAddress, selectOption }), [setAddress, selectOption]);\n}\n\n/**\n * Declares the `shipping` action namespace — the single source of truth for its method/payload\n * metadata, runtime provider, and `use` hook (mirrors `cartActions`, `sessionActions`). The native\n * catalog builder (`scripts/build-catalog.mjs`) statically reads this call to emit `actions.json`;\n * at runtime `ShippingActionProvider` calls `useShippingActions` directly.\n */\nexport const shippingActions = defineActions({\n namespace: 'shipping',\n description: 'Mutation-backed delivery writes against the VTEX orderForm shippingData (address in T2; option in T3).',\n provider: { name: 'ShippingActionProvider', importPath: '@vtex/faststore/internal/client' },\n methods: {\n setAddress: {\n description:\n 'Persist the single delivery address in one submit (async/pessimistic). Resolves the payload userErrors.',\n payload: [\n { name: 'savedAddressId', type: 'string' },\n { name: 'recipientName', type: 'string' },\n { name: 'postalCode', type: 'string' },\n { name: 'country', type: 'string' },\n { name: 'street', type: 'string' },\n { name: 'number', type: 'string' },\n { name: 'complement', type: 'string' },\n { name: 'neighborhood', type: 'string' },\n { name: 'city', type: 'string' },\n { name: 'state', type: 'string' },\n ],\n },\n selectOption: {\n description: 'Select a delivery option for the whole cart (async/pessimistic). Resolves the payload userErrors.',\n payload: [{ name: 'optionId', type: 'string' }],\n },\n },\n use: useShippingActions,\n});\n"],"mappings":";;;;;;;;AAmCA,MAAM,4BAA8D;CAClE,MAAM;CACN,SAAS;AACX;AAEA,MAAM,8BAA6D;CACjE,MAAM;CACN,SAAS;AACX;;;;;;;AAQA,SAAgB,qBAAsC;CACpD,MAAM,CAAC,mBAAmB,YAAY,uBAAuB;CAC7D,MAAM,CAAC,wBAAwB,YAAY,sBAAsB;CAEjE,MAAM,aAAa,YACjB,OAAO,YAAY;EACjB,IAAI;GAEF,QAAO,MADc,gBAAgB,EAAE,WAAW,EAAE,OAAO,QAAQ,EAAE,CAAC,EAAA,CACxD,MAAM,sBAAsB,cAAc,CAAC;EAC3D,SAAS,OAAO;GACd,QAAQ,MAAM,sDAAsD,KAAK;GACzE,OAAO,CAAC,yBAAyB;EACnC;CACF,GACA,CAAC,eAAe,CAClB;CAEA,MAAM,eAAe,YACnB,OAAO,aAAa;EAClB,IAAI;GAEF,QAAO,MADc,qBAAqB,EAAE,WAAW,EAAE,OAAO,EAAE,SAAS,EAAE,EAAE,CAAC,EAAA,CAClE,MAAM,qBAAqB,cAAc,CAAC;EAC1D,SAAS,OAAO;GACd,QAAQ,MAAM,uDAAuD,KAAK;GAC1E,OAAO,CAAC,2BAA2B;EACrC;CACF,GACA,CAAC,oBAAoB,CACvB;CAEA,OAAO,eAAe;EAAE;EAAY;CAAa,IAAI,CAAC,YAAY,YAAY,CAAC;AACjF;AAQ+B,cAAc;CAC3C,WAAW;CACX,aAAa;CACb,UAAU;EAAE,MAAM;EAA0B,YAAY;CAAkC;CAC1F,SAAS;EACP,YAAY;GACV,aACE;GACF,SAAS;IACP;KAAE,MAAM;KAAkB,MAAM;IAAS;IACzC;KAAE,MAAM;KAAiB,MAAM;IAAS;IACxC;KAAE,MAAM;KAAc,MAAM;IAAS;IACrC;KAAE,MAAM;KAAW,MAAM;IAAS;IAClC;KAAE,MAAM;KAAU,MAAM;IAAS;IACjC;KAAE,MAAM;KAAU,MAAM;IAAS;IACjC;KAAE,MAAM;KAAc,MAAM;IAAS;IACrC;KAAE,MAAM;KAAgB,MAAM;IAAS;IACvC;KAAE,MAAM;KAAQ,MAAM;IAAS;IAC/B;KAAE,MAAM;KAAS,MAAM;IAAS;GAClC;EACF;EACA,cAAc;GACZ,aAAa;GACb,SAAS,CAAC;IAAE,MAAM;IAAY,MAAM;GAAS,CAAC;EAChD;CACF;CACA,KAAK;AACP,CAAC"}
1
+ {"version":3,"file":"use-shipping-actions.js","names":[],"sources":["../../../src/sdk/shipping/use-shipping-actions.ts"],"sourcesContent":["'use client';\n\nimport { useMutation } from '@apollo/client/react';\nimport { defineActions } from '@vtex/fs-core';\nimport { useCallback, useMemo } from 'react';\nimport { loggableErrorName } from '../../utils/loggable-error-name.js';\nimport { SHIPPING_OPTION_SELECT, type ShippingOptionSelectUserError } from './option-select-operations.js';\nimport {\n SHIPPING_ADDRESS_UPDATE,\n SHIPPING_NETWORK_ERROR_CODE,\n type ShippingAddressInput,\n type ShippingAddressUpdateErrorEntity,\n} from './shipping-operations.js';\n\n/**\n * The `shipping` action namespace — the sanctioned client write surface against the VTEX orderForm\n * shippingData: delivery-address updates (docs/storefront-core/reference-free-particle-model.md § The cart write contract;\n * docs/storefront-core/adr-0010-actions-own-the-write-side.md) and cart-scoped delivery-option\n * selection (docs/storefront-core/reference-free-particle-model.md § The cart write contract). Per Decision 4 the two tasks share this one\n * namespace — T2 (`setAddress`) merged first and owns the registration, T3 extends it with\n * `selectOption` here.\n *\n * Both actions are async/pessimistic (Decision 1 of the address spec): the handler awaits the\n * mutation and only the server-confirmed payload changes the cache. Each is stateless (no reactive\n * vars, no module state), resolves its payload `userErrors` (empty on success), and never throws for\n * expected outcomes; an infrastructure failure (network or an upstream GraphQLError) is caught and\n * collapsed to one synthetic network `userError` — no per-code branching (US-4, FR-5). Inputs pass\n * through mutation variables only — never logged, never stored beyond the cache.\n */\nexport type ShippingActions = Readonly<{\n /** Persist the single delivery address (async/pessimistic). Resolves the payload userErrors. */\n setAddress: (address: ShippingAddressInput) => Promise<readonly ShippingAddressUpdateErrorEntity[]>;\n /** Select a delivery option for the whole cart. Resolves the payload userErrors (empty on success). */\n selectOption: (optionId: string) => Promise<readonly ShippingOptionSelectUserError[]>;\n}>;\n\nconst SET_ADDRESS_NETWORK_ERROR: ShippingAddressUpdateErrorEntity = {\n code: SHIPPING_NETWORK_ERROR_CODE,\n message: 'Unable to complete the request. Please try again.',\n};\n\nconst SELECT_OPTION_NETWORK_ERROR: ShippingOptionSelectUserError = {\n code: 'NETWORK_ERROR',\n message: 'Unable to update the delivery option. Please try again.',\n};\n\n/**\n * The `shipping` namespace hook. Registered with the first-party action registry via `shippingActions`\n * below; the compiler-emitted `ShippingActionProvider` calls it and threads the narrowed methods into\n * each consumer's `$actions.shipping`. Writes persist purely through the normalized-cache merge of\n * each mutation response (Decision 2 of the address spec) — no refetch, no imperative write.\n */\nexport function useShippingActions(): ShippingActions {\n const [addressMutation] = useMutation(SHIPPING_ADDRESS_UPDATE);\n const [selectOptionMutation] = useMutation(SHIPPING_OPTION_SELECT);\n\n const setAddress = useCallback<ShippingActions['setAddress']>(\n async (address) => {\n try {\n const result = await addressMutation({ variables: { input: address } });\n return result.data?.shippingAddressUpdate.userErrors ?? [];\n } catch (error) {\n console.error('[shipping.setAddress] shippingAddressUpdate failed', loggableErrorName(error));\n return [SET_ADDRESS_NETWORK_ERROR];\n }\n },\n [addressMutation],\n );\n\n const selectOption = useCallback<ShippingActions['selectOption']>(\n async (optionId) => {\n try {\n const result = await selectOptionMutation({ variables: { input: { optionId } } });\n return result.data?.shippingOptionSelect.userErrors ?? [];\n } catch (error) {\n console.error('[shipping.selectOption] shippingOptionSelect failed', loggableErrorName(error));\n return [SELECT_OPTION_NETWORK_ERROR];\n }\n },\n [selectOptionMutation],\n );\n\n return useMemo(() => ({ setAddress, selectOption }), [setAddress, selectOption]);\n}\n\n/**\n * Declares the `shipping` action namespace — the single source of truth for its method/payload\n * metadata, runtime provider, and `use` hook (mirrors `cartActions`, `sessionActions`). The native\n * catalog builder (`scripts/build-catalog.mjs`) statically reads this call to emit `actions.json`;\n * at runtime `ShippingActionProvider` calls `useShippingActions` directly.\n */\nexport const shippingActions = defineActions({\n namespace: 'shipping',\n description: 'Mutation-backed delivery writes against the VTEX orderForm shippingData (address in T2; option in T3).',\n provider: { name: 'ShippingActionProvider', importPath: '@vtex/faststore/internal/client' },\n methods: {\n setAddress: {\n description:\n 'Persist the single delivery address in one submit (async/pessimistic). Resolves the payload userErrors.',\n payload: [\n { name: 'savedAddressId', type: 'string' },\n { name: 'recipientName', type: 'string' },\n { name: 'postalCode', type: 'string' },\n { name: 'country', type: 'string' },\n { name: 'street', type: 'string' },\n { name: 'number', type: 'string' },\n { name: 'complement', type: 'string' },\n { name: 'neighborhood', type: 'string' },\n { name: 'city', type: 'string' },\n { name: 'state', type: 'string' },\n ],\n },\n selectOption: {\n description: 'Select a delivery option for the whole cart (async/pessimistic). Resolves the payload userErrors.',\n payload: [{ name: 'optionId', type: 'string' }],\n },\n },\n use: useShippingActions,\n});\n"],"mappings":";;;;;;;;;AAoCA,MAAM,4BAA8D;CAClE,MAAM;CACN,SAAS;AACX;AAEA,MAAM,8BAA6D;CACjE,MAAM;CACN,SAAS;AACX;;;;;;;AAQA,SAAgB,qBAAsC;CACpD,MAAM,CAAC,mBAAmB,YAAY,uBAAuB;CAC7D,MAAM,CAAC,wBAAwB,YAAY,sBAAsB;CAEjE,MAAM,aAAa,YACjB,OAAO,YAAY;EACjB,IAAI;GAEF,QAAO,MADc,gBAAgB,EAAE,WAAW,EAAE,OAAO,QAAQ,EAAE,CAAC,EAAA,CACxD,MAAM,sBAAsB,cAAc,CAAC;EAC3D,SAAS,OAAO;GACd,QAAQ,MAAM,sDAAsD,kBAAkB,KAAK,CAAC;GAC5F,OAAO,CAAC,yBAAyB;EACnC;CACF,GACA,CAAC,eAAe,CAClB;CAEA,MAAM,eAAe,YACnB,OAAO,aAAa;EAClB,IAAI;GAEF,QAAO,MADc,qBAAqB,EAAE,WAAW,EAAE,OAAO,EAAE,SAAS,EAAE,EAAE,CAAC,EAAA,CAClE,MAAM,qBAAqB,cAAc,CAAC;EAC1D,SAAS,OAAO;GACd,QAAQ,MAAM,uDAAuD,kBAAkB,KAAK,CAAC;GAC7F,OAAO,CAAC,2BAA2B;EACrC;CACF,GACA,CAAC,oBAAoB,CACvB;CAEA,OAAO,eAAe;EAAE;EAAY;CAAa,IAAI,CAAC,YAAY,YAAY,CAAC;AACjF;AAQ+B,cAAc;CAC3C,WAAW;CACX,aAAa;CACb,UAAU;EAAE,MAAM;EAA0B,YAAY;CAAkC;CAC1F,SAAS;EACP,YAAY;GACV,aACE;GACF,SAAS;IACP;KAAE,MAAM;KAAkB,MAAM;IAAS;IACzC;KAAE,MAAM;KAAiB,MAAM;IAAS;IACxC;KAAE,MAAM;KAAc,MAAM;IAAS;IACrC;KAAE,MAAM;KAAW,MAAM;IAAS;IAClC;KAAE,MAAM;KAAU,MAAM;IAAS;IACjC;KAAE,MAAM;KAAU,MAAM;IAAS;IACjC;KAAE,MAAM;KAAc,MAAM;IAAS;IACrC;KAAE,MAAM;KAAgB,MAAM;IAAS;IACvC;KAAE,MAAM;KAAQ,MAAM;IAAS;IAC/B;KAAE,MAAM;KAAS,MAAM;IAAS;GAClC;EACF;EACA,cAAc;GACZ,aAAa;GACb,SAAS,CAAC;IAAE,MAAM;IAAY,MAAM;GAAS,CAAC;EAChD;CACF;CACA,KAAK;AACP,CAAC"}
@@ -0,0 +1,11 @@
1
+ //#region src/utils/safe-href.d.ts
2
+ /**
3
+ * Builds the sign-in destination, carrying the current path so the shopper can be returned where they
4
+ * started. The sender's half only: nothing stops a hand-crafted link, so the sign-in route is to narrow
5
+ * the parameter again on arrival. A path the narrowing refuses drops the parameter instead of
6
+ * travelling encoded, and so does a router reporting no path — `usePathname()`'s type is why this takes
7
+ * a nullable one.
8
+ */
9
+ export declare function resolveSignInHref(pathname: string | null): string;
10
+ //#endregion
11
+ //# sourceMappingURL=safe-href.d.ts.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vtex/faststore",
3
- "version": "0.0.6",
3
+ "version": "0.0.7",
4
4
  "description": "FastStore AI Native component library built on Base UI with AI-editable styles",
5
5
  "license": "MIT",
6
6
  "homepage": "https://developers.vtex.com/docs/guides/faststore",
@@ -25,6 +25,11 @@
25
25
  "import": "./dist/graphql.js",
26
26
  "default": "./dist/graphql.js"
27
27
  },
28
+ "./cli": {
29
+ "types": "./dist/cli/index.d.ts",
30
+ "import": "./dist/cli/index.js",
31
+ "default": "./dist/cli/index.js"
32
+ },
28
33
  "./internal/client": {
29
34
  "types": "./dist/internal/client.d.ts",
30
35
  "import": "./dist/internal/client.js"
@@ -63,6 +68,12 @@
63
68
  "@apollo/client-integration-nextjs": "^0.14.5",
64
69
  "next": ">=16",
65
70
  "react": "^19.0.0",
66
- "react-dom": "^19.0.0"
71
+ "react-dom": "^19.0.0",
72
+ "typescript": "^5.9.3"
73
+ },
74
+ "peerDependenciesMeta": {
75
+ "typescript": {
76
+ "optional": true
77
+ }
67
78
  }
68
79
  }