@putiikkipalvelu/storefront-sdk 0.7.4 → 0.10.0

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.
package/dist/index.d.ts CHANGED
@@ -345,6 +345,8 @@ interface Product {
345
345
  saleStartDate: string | null;
346
346
  /** Sale end date (ISO 8601), null = no end */
347
347
  saleEndDate: string | null;
348
+ /** True if this product is delivered as a digital download (no shipping) */
349
+ isDigital?: boolean;
348
350
  /** Product variations (minimal fields for listing) */
349
351
  variations: ProductVariationListing[];
350
352
  }
@@ -382,6 +384,11 @@ interface ProductDetail extends Omit<Product, "variations"> {
382
384
  variations: ProductVariation[];
383
385
  /** Ticket info (present if product is a ticket, null otherwise) */
384
386
  ticketInfo: ProductTicketInfo | null;
387
+ /**
388
+ * HTML instructions shown to the buyer after a digital purchase.
389
+ * Only populated when isDigital=true; null otherwise.
390
+ */
391
+ digitalContent?: string | null;
385
392
  }
386
393
  /**
387
394
  * Response from /sorted-products
@@ -476,6 +483,8 @@ interface CartItem {
476
483
  variation?: ProductVariation;
477
484
  /** Whether this item is a ticket product (no shipping required) */
478
485
  isTicket?: boolean;
486
+ /** Whether this item is a digital product (no shipping required) */
487
+ isDigital?: boolean;
479
488
  }
480
489
  /**
481
490
  * Response from GET /cart, POST /cart, PATCH /cart, DELETE /cart
@@ -743,6 +752,11 @@ interface ConfirmationOrderLineItem {
743
752
  vatRate: number;
744
753
  /** Product images array */
745
754
  images: string[];
755
+ /**
756
+ * Snapshot of the product's digital instructions at purchase time.
757
+ * Populated for digital products; null otherwise.
758
+ */
759
+ digitalContent?: string | null;
746
760
  }
747
761
  /**
748
762
  * Customer delivery information attached to an order
@@ -1704,6 +1718,157 @@ interface TicketUseResponse {
1704
1718
  ticket: PurchasedTicket;
1705
1719
  }
1706
1720
 
1721
+ /**
1722
+ * Digital Downloads Types
1723
+ *
1724
+ * Types for digital product downloads (instructions + downloadable files).
1725
+ */
1726
+ /**
1727
+ * A single downloadable file within an order line item.
1728
+ * Snapshotted at purchase time — persists even if the merchant deletes the
1729
+ * original product or file.
1730
+ */
1731
+ interface OrderDownload {
1732
+ /** Unique download record ID (pass this to getDownloadUrl) */
1733
+ id: string;
1734
+ /** Merchant-editable file name shown to the customer */
1735
+ displayName: string;
1736
+ /** File size in bytes */
1737
+ sizeBytes: number;
1738
+ /** MIME type, e.g. "application/pdf" */
1739
+ mimeType: string;
1740
+ /** How many times this file has been downloaded on this order */
1741
+ downloadCount: number;
1742
+ /** Max downloads allowed on this order (null = unlimited) */
1743
+ maxDownloads: number | null;
1744
+ /** Downloads remaining (null = unlimited) */
1745
+ remaining: number | null;
1746
+ }
1747
+ /**
1748
+ * A line item in an order with digital content and/or downloadable files.
1749
+ * Only line items that either have instructions or files are returned by
1750
+ * the downloads list endpoint.
1751
+ */
1752
+ interface OrderDownloadLineItem {
1753
+ /** Order line item ID */
1754
+ id: string;
1755
+ /** Product/variation display name */
1756
+ name: string;
1757
+ /** Quantity ordered */
1758
+ quantity: number;
1759
+ /** Sanitized HTML instructions (from merchant's TipTap field). May be null. */
1760
+ digitalContent: string | null;
1761
+ /** Downloadable files attached to this line item. May be empty. */
1762
+ downloads: OrderDownload[];
1763
+ }
1764
+ /**
1765
+ * Response from GET /order/:id/downloads
1766
+ */
1767
+ interface OrderDownloadsResponse {
1768
+ /** Order ID the downloads belong to */
1769
+ orderId: string;
1770
+ /** Line items with digital content and/or downloads */
1771
+ items: OrderDownloadLineItem[];
1772
+ }
1773
+ /**
1774
+ * Response from POST /order/:id/downloads/:downloadId
1775
+ * Short-lived presigned URL for downloading the file directly from R2.
1776
+ */
1777
+ interface DownloadUrlResponse {
1778
+ /** Presigned download URL (typically valid ~5 minutes) */
1779
+ url: string;
1780
+ /** How long the URL stays valid, in seconds */
1781
+ expiresIn: number;
1782
+ }
1783
+ /**
1784
+ * Options for calling the downloads endpoints.
1785
+ * Authentication is granted via EITHER a token (from order confirmation email)
1786
+ * OR a valid customer session (logged-in customer who owns the order).
1787
+ */
1788
+ interface DownloadsAuthOptions {
1789
+ /** Download token from the confirmation email URL. Use this for guest access. */
1790
+ token?: string;
1791
+ /** Customer session token. Use this for logged-in customer access. */
1792
+ sessionId?: string;
1793
+ }
1794
+
1795
+ /**
1796
+ * Withdrawal Notice Types
1797
+ *
1798
+ * Types for the KKV peruutustoiminto / EU CRD Article 11a mandatory
1799
+ * withdrawal function (effective 19.6.2026).
1800
+ */
1801
+ /**
1802
+ * A single item being withdrawn (partial withdrawal).
1803
+ * Omit the items array entirely to indicate "whole order".
1804
+ */
1805
+ interface WithdrawalItem {
1806
+ /** Optional reference to a known line item id (matched orders only). */
1807
+ lineItemId?: string;
1808
+ /** Product name as the consumer sees it. */
1809
+ productName: string;
1810
+ /** Number of units being withdrawn. */
1811
+ quantity: number;
1812
+ }
1813
+ /**
1814
+ * Parameters for submitting a withdrawal notice.
1815
+ *
1816
+ * The function must accept the notice regardless of whether the order
1817
+ * can be resolved server-side (KKV requires the function to record any
1818
+ * submission as a legal record of intent).
1819
+ */
1820
+ interface WithdrawalNoticeParams {
1821
+ /** Consumer's name (KKV mandate). */
1822
+ name: string;
1823
+ /** Email where the confirmation will be sent (KKV mandate — consumer chooses). */
1824
+ email: string;
1825
+ /** Order number as the consumer types it. Optional — best-effort matched server-side. */
1826
+ orderNumber?: string;
1827
+ /**
1828
+ * Items being withdrawn for a partial withdrawal.
1829
+ * Omit / empty array = whole order.
1830
+ */
1831
+ items?: WithdrawalItem[];
1832
+ /** Optional free-text message from the consumer (max 2000 chars). */
1833
+ message?: string;
1834
+ /**
1835
+ * Pre-submit confirmation flag — MUST be `true`.
1836
+ * This represents the two-step UX step legally required by § 356a BGB
1837
+ * (and implied by KKV "selkeästi merkitty vahvistustoiminto").
1838
+ */
1839
+ confirmRead: true;
1840
+ /**
1841
+ * Honeypot field — leave empty. Submissions with a non-empty value are
1842
+ * silently dropped server-side as bot traffic.
1843
+ */
1844
+ honeypot?: string;
1845
+ }
1846
+ /**
1847
+ * Response from a successful withdrawal submission.
1848
+ */
1849
+ interface WithdrawalSubmitResponse {
1850
+ /** Human-readable per-store sequence (e.g. "PER-0042"). */
1851
+ noticeNumber: string;
1852
+ /** ISO timestamp of submission — printed on the confirmation email. */
1853
+ createdAt: string;
1854
+ }
1855
+ /**
1856
+ * Order details resolved from a withdrawal token (the signed link in the
1857
+ * order confirmation email). Used to pre-fill the withdrawal form.
1858
+ */
1859
+ interface WithdrawalResolveTokenResponse {
1860
+ /** Order number as a string ready to display. */
1861
+ orderNumber: string;
1862
+ /** Customer's full name from the order. */
1863
+ customerName: string;
1864
+ /** Customer's email from the order. */
1865
+ customerEmail: string;
1866
+ /** Line items eligible for partial withdrawal (excludes shipping rows). */
1867
+ items: WithdrawalItem[];
1868
+ /** ISO timestamp when the token expires. */
1869
+ expiresAt: string;
1870
+ }
1871
+
1707
1872
  /**
1708
1873
  * Putiikkipalvelu Storefront SDK Types
1709
1874
  *
@@ -2573,7 +2738,7 @@ declare function createCustomerResource(fetcher: Fetcher): {
2573
2738
  type CustomerResource = ReturnType<typeof createCustomerResource>;
2574
2739
 
2575
2740
  /**
2576
- * Order resource for fetching order details
2741
+ * Order resource for fetching order details and digital downloads
2577
2742
  *
2578
2743
  * Used for order confirmation pages and viewing order details.
2579
2744
  * For customer order history, use the customer.getOrders() method instead.
@@ -2596,36 +2761,54 @@ declare function createOrderResource(fetcher: Fetcher): {
2596
2761
  * console.log(`Order #${order.orderNumber} - ${order.status}`);
2597
2762
  * console.log(`Total: ${order.totalAmount / 100} EUR`);
2598
2763
  * ```
2764
+ */
2765
+ get(orderId: string, options?: FetchOptions): Promise<Order>;
2766
+ /**
2767
+ * List downloadable files for a paid order.
2599
2768
  *
2600
- * @example Next.js - with caching
2769
+ * Requires EITHER a download token (from the order confirmation email)
2770
+ * OR a valid customer session (for logged-in customers viewing their own
2771
+ * order history).
2772
+ *
2773
+ * Returns only line items that have digital content or downloadable files.
2774
+ * The order must be paid (status !== PENDING or FAILED).
2775
+ *
2776
+ * @param orderId - The order ID
2777
+ * @param auth - Token (guest) or sessionId (logged-in customer)
2778
+ * @param options - Fetch options
2779
+ *
2780
+ * @example Guest access via email token
2601
2781
  * ```typescript
2602
- * const order = await client.order.get(orderId, {
2603
- * next: { revalidate: 60, tags: ['order', orderId] }
2604
- * });
2782
+ * const token = new URLSearchParams(location.search).get("token");
2783
+ * const { items } = await client.order.listDownloads(orderId, { token });
2605
2784
  * ```
2606
2785
  *
2607
- * @example Display line items
2786
+ * @example Logged-in customer
2608
2787
  * ```typescript
2609
- * const order = await client.order.get(orderId);
2610
- * order.OrderLineItems.forEach(item => {
2611
- * if (item.itemType !== 'SHIPPING') {
2612
- * console.log(`${item.name} x${item.quantity} = ${item.totalAmount / 100} EUR`);
2613
- * }
2614
- * });
2788
+ * const { items } = await client.order.listDownloads(orderId, { sessionId });
2615
2789
  * ```
2790
+ */
2791
+ listDownloads(orderId: string, auth?: DownloadsAuthOptions, options?: FetchOptions): Promise<OrderDownloadsResponse>;
2792
+ /**
2793
+ * Issue a short-lived presigned URL to download a specific file from a
2794
+ * paid order. Increments the download counter and records a download
2795
+ * event (IP, user agent) on the server.
2796
+ *
2797
+ * The returned URL is typically valid for ~5 minutes — redirect the
2798
+ * browser to it or trigger a download immediately.
2799
+ *
2800
+ * @param orderId - The order ID
2801
+ * @param downloadId - The OrderDownload.id
2802
+ * @param auth - Token (guest) or sessionId (logged-in customer)
2803
+ * @param options - Fetch options
2616
2804
  *
2617
- * @example Show tracking info
2805
+ * @example
2618
2806
  * ```typescript
2619
- * const order = await client.order.get(orderId);
2620
- * if (order.orderShipmentMethod?.trackingNumber) {
2621
- * console.log(`Tracking: ${order.orderShipmentMethod.trackingNumber}`);
2622
- * order.orderShipmentMethod.trackingUrls?.forEach(url => {
2623
- * console.log(`Track at: ${url}`);
2624
- * });
2625
- * }
2807
+ * const { url } = await client.order.getDownloadUrl(orderId, downloadId, { token });
2808
+ * window.location.href = url;
2626
2809
  * ```
2627
2810
  */
2628
- get(orderId: string, options?: FetchOptions): Promise<Order>;
2811
+ getDownloadUrl(orderId: string, downloadId: string, auth?: DownloadsAuthOptions, options?: FetchOptions): Promise<DownloadUrlResponse>;
2629
2812
  };
2630
2813
  /**
2631
2814
  * Type for the order resource
@@ -2931,6 +3114,59 @@ declare function createTicketsResource(fetcher: Fetcher): {
2931
3114
  */
2932
3115
  type TicketsResource = ReturnType<typeof createTicketsResource>;
2933
3116
 
3117
+ /**
3118
+ * Withdrawal Resource
3119
+ *
3120
+ * Submits consumer withdrawal notices (KKV peruutustoiminto / EU CRD Art. 11a).
3121
+ */
3122
+
3123
+ /**
3124
+ * Creates the withdrawal resource.
3125
+ */
3126
+ declare function createWithdrawalResource(fetcher: Fetcher): {
3127
+ /**
3128
+ * Submit a withdrawal notice (peruutusilmoitus).
3129
+ *
3130
+ * The notice is a legal record of intent. The server records it regardless
3131
+ * of whether the order number can be resolved, and the consumer receives a
3132
+ * confirmation email containing what was withdrawn plus exact submission
3133
+ * date/time.
3134
+ *
3135
+ * Refunds are handled separately by the merchant via the dashboard — this
3136
+ * endpoint never issues a refund.
3137
+ *
3138
+ * @param params - Notice payload (name, email, optional orderNumber + items + message)
3139
+ * @returns Notice number and creation timestamp
3140
+ *
3141
+ * @example
3142
+ * ```typescript
3143
+ * const { noticeNumber } = await client.withdrawal.submit({
3144
+ * name: "Matti Meikäläinen",
3145
+ * email: "matti@example.com",
3146
+ * orderNumber: "1024",
3147
+ * items: [{ productName: "Tuote A", quantity: 1 }],
3148
+ * message: "Haluan peruuttaa.",
3149
+ * confirmRead: true,
3150
+ * });
3151
+ * ```
3152
+ */
3153
+ submit(params: WithdrawalNoticeParams): Promise<WithdrawalSubmitResponse>;
3154
+ /**
3155
+ * Resolve a withdrawal token (from the order confirmation email link)
3156
+ * to the matching order's details. Used to pre-fill the withdrawal form.
3157
+ *
3158
+ * Throws `StorefrontError` with code `EXPIRED` / `INVALID` / `STORE_MISMATCH`
3159
+ * / `ORDER_NOT_FOUND` as appropriate.
3160
+ *
3161
+ * @param token - The signed token from the `?token=…` query param
3162
+ */
3163
+ resolveToken(token: string): Promise<WithdrawalResolveTokenResponse>;
3164
+ };
3165
+ /**
3166
+ * Type for the withdrawal resource.
3167
+ */
3168
+ type WithdrawalResource = ReturnType<typeof createWithdrawalResource>;
3169
+
2934
3170
  /**
2935
3171
  * The Storefront API client
2936
3172
  */
@@ -2983,6 +3219,10 @@ interface StorefrontClient {
2983
3219
  * Tickets resource for ticket scanning and validation
2984
3220
  */
2985
3221
  readonly tickets: TicketsResource;
3222
+ /**
3223
+ * Withdrawal resource for consumer withdrawal notices (KKV peruutustoiminto)
3224
+ */
3225
+ readonly withdrawal: WithdrawalResource;
2986
3226
  }
2987
3227
  /**
2988
3228
  * Create a new Storefront API client
@@ -3230,4 +3470,4 @@ declare class VerificationRequiredError extends StorefrontError {
3230
3470
  constructor(message: string, customerId: string);
3231
3471
  }
3232
3472
 
3233
- export { type AboutBlock, type AccordionBlock, type AccordionItem, type AddToCartParams, type AddToWishlistResponse, type AnalyticsConfig, type AppliedDiscount, type ApplyDiscountParams, type ApplyDiscountResponse, AuthError, type BuyXPayYCampaign, type CalculatedCartItem, type Campaign, type CampaignType, type CarouselContentBlock, type CarouselContentItem, type CartCalculationResult, type CartItem, type CartResponse, type CartSessionOptions, type CartValidationChanges, type CartValidationResponse, type Category, type CategoryReference, type CategoryResponse, type CheckoutCustomerData, type CheckoutErrorCode, type CheckoutErrorDetails, type CheckoutOptions, type CheckoutParams, type CheckoutShipmentMethod, type ConfirmationItemType, type ConfirmationOrderCustomerData, type ConfirmationOrderLineItem, type ConfirmationOrderShipmentMethod, type Customer, type CustomerOrder, type DeleteAccountResponse, type DiscountApplyErrorCode, type DiscountCodeError, type DiscountMessageLocale, type DiscountRemovalReason, type DiscountType, type FeatureFlags, type FetchOptions, type ForgotPasswordResponse, type FormatDiscountOptions, type GalleryBlock, type GalleryItem, type GetDiscountParams, type GetDiscountResponse, type GetOrdersResponse, type GetUserResponse, type HomeDeliveryOption, type ImageAspectRatio, type ImageGridBlock, type ImageGridItem, type LoginOptions, type LoginResponse, type LoginVerificationRequiredResponse, type LogoutResponse, type MarkdownBlock, type NavPage, NotFoundError, type OpeningHours, type OpeningHoursBlock, type OpeningHoursEntry, type Order, type OrderLineItem, type OrderProductInfo, type OrderShipmentMethod, type OrderStatus, type PageBlock, type PageSeo, type PaymentConfig, type PaytrailCheckoutResponse, type PaytrailGroup, type PaytrailProvider, type PickupPointOption, type PriceInfo, type Product, type ProductCountResponse, type ProductDetail, type ProductListParams, type ProductListResponse, type ProductSortOption, type ProductTicketInfo, type ProductVariation, type ProductVariationListing, type PurchasedTicket, RateLimitError, type RegisterData, type RegisterResponse, type RemoveDiscountParams, type RemoveDiscountResponse, type RemoveFromCartParams, type RemoveFromWishlistResponse, type ResendVerificationResponse, type ResetPasswordResponse, type ShipitShippingMethod, type ShipmentMethod, type ShipmentMethodsResponse, type ShowcaseBlock, type ShowcaseItem, type StoreConfig, type StoreInfo, type StorePage, type StoreSeo, type StorefrontClient, type StorefrontClientConfig, StorefrontError, type StripeCheckoutResponse, type TableBlock, type TextGridBlock, type TextGridItem, type TicketEvent, type TicketEventsResponse, type TicketGetResponse, type TicketHolderData, type TicketStatus, type TicketUseResponse, type TicketValidatePinResponse, type UpdateCartQuantityParams, type UpdateProfileData, type UpdateProfileResponse, ValidationError, type VariationOption, VerificationRequiredError, type VerifyEmailResponse, type WishlistItem, type WishlistProduct, type WishlistResponse, type WishlistVariation, type WishlistVariationOption, calculateCartWithCampaigns, calculateDiscountAmount, createStorefrontClient, formatDiscountValue, getDiscountApplyErrorMessage, getDiscountRemovalMessage, getPriceInfo, isSaleActive };
3473
+ export { type AboutBlock, type AccordionBlock, type AccordionItem, type AddToCartParams, type AddToWishlistResponse, type AnalyticsConfig, type AppliedDiscount, type ApplyDiscountParams, type ApplyDiscountResponse, AuthError, type BuyXPayYCampaign, type CalculatedCartItem, type Campaign, type CampaignType, type CarouselContentBlock, type CarouselContentItem, type CartCalculationResult, type CartItem, type CartResponse, type CartSessionOptions, type CartValidationChanges, type CartValidationResponse, type Category, type CategoryReference, type CategoryResponse, type CheckoutCustomerData, type CheckoutErrorCode, type CheckoutErrorDetails, type CheckoutOptions, type CheckoutParams, type CheckoutShipmentMethod, type ConfirmationItemType, type ConfirmationOrderCustomerData, type ConfirmationOrderLineItem, type ConfirmationOrderShipmentMethod, type Customer, type CustomerOrder, type DeleteAccountResponse, type DiscountApplyErrorCode, type DiscountCodeError, type DiscountMessageLocale, type DiscountRemovalReason, type DiscountType, type DownloadUrlResponse, type DownloadsAuthOptions, type FeatureFlags, type FetchOptions, type ForgotPasswordResponse, type FormatDiscountOptions, type GalleryBlock, type GalleryItem, type GetDiscountParams, type GetDiscountResponse, type GetOrdersResponse, type GetUserResponse, type HomeDeliveryOption, type ImageAspectRatio, type ImageGridBlock, type ImageGridItem, type LoginOptions, type LoginResponse, type LoginVerificationRequiredResponse, type LogoutResponse, type MarkdownBlock, type NavPage, NotFoundError, type OpeningHours, type OpeningHoursBlock, type OpeningHoursEntry, type Order, type OrderDownload, type OrderDownloadLineItem, type OrderDownloadsResponse, type OrderLineItem, type OrderProductInfo, type OrderShipmentMethod, type OrderStatus, type PageBlock, type PageSeo, type PaymentConfig, type PaytrailCheckoutResponse, type PaytrailGroup, type PaytrailProvider, type PickupPointOption, type PriceInfo, type Product, type ProductCountResponse, type ProductDetail, type ProductListParams, type ProductListResponse, type ProductSortOption, type ProductTicketInfo, type ProductVariation, type ProductVariationListing, type PurchasedTicket, RateLimitError, type RegisterData, type RegisterResponse, type RemoveDiscountParams, type RemoveDiscountResponse, type RemoveFromCartParams, type RemoveFromWishlistResponse, type ResendVerificationResponse, type ResetPasswordResponse, type ShipitShippingMethod, type ShipmentMethod, type ShipmentMethodsResponse, type ShowcaseBlock, type ShowcaseItem, type StoreConfig, type StoreInfo, type StorePage, type StoreSeo, type StorefrontClient, type StorefrontClientConfig, StorefrontError, type StripeCheckoutResponse, type TableBlock, type TextGridBlock, type TextGridItem, type TicketEvent, type TicketEventsResponse, type TicketGetResponse, type TicketHolderData, type TicketStatus, type TicketUseResponse, type TicketValidatePinResponse, type UpdateCartQuantityParams, type UpdateProfileData, type UpdateProfileResponse, ValidationError, type VariationOption, VerificationRequiredError, type VerifyEmailResponse, type WishlistItem, type WishlistProduct, type WishlistResponse, type WishlistVariation, type WishlistVariationOption, type WithdrawalItem, type WithdrawalNoticeParams, type WithdrawalResolveTokenResponse, type WithdrawalSubmitResponse, calculateCartWithCampaigns, calculateDiscountAmount, createStorefrontClient, formatDiscountValue, getDiscountApplyErrorMessage, getDiscountRemovalMessage, getPriceInfo, isSaleActive };
package/dist/index.js CHANGED
@@ -847,7 +847,7 @@ function createCustomerResource(fetcher) {
847
847
  */
848
848
  async register(data, fetchOptions) {
849
849
  return fetcher.request(
850
- "/api/storefront/v1/customer/(auth)/register",
850
+ "/api/storefront/v1/customer/register",
851
851
  {
852
852
  method: "POST",
853
853
  body: data,
@@ -894,7 +894,7 @@ function createCustomerResource(fetcher) {
894
894
  headers["x-cart-id"] = options.cartId;
895
895
  }
896
896
  return fetcher.request(
897
- "/api/storefront/v1/customer/(auth)/login",
897
+ "/api/storefront/v1/customer/login",
898
898
  {
899
899
  method: "POST",
900
900
  body: { email, password },
@@ -926,7 +926,7 @@ function createCustomerResource(fetcher) {
926
926
  */
927
927
  async logout(sessionId, fetchOptions) {
928
928
  return fetcher.request(
929
- "/api/storefront/v1/customer/(auth)/logout",
929
+ "/api/storefront/v1/customer/logout",
930
930
  {
931
931
  method: "POST",
932
932
  headers: buildSessionHeaders(sessionId),
@@ -953,7 +953,7 @@ function createCustomerResource(fetcher) {
953
953
  */
954
954
  async getUser(sessionId, fetchOptions) {
955
955
  return fetcher.request(
956
- "/api/storefront/v1/customer/(auth)/get-user",
956
+ "/api/storefront/v1/customer/get-user",
957
957
  {
958
958
  method: "GET",
959
959
  headers: buildSessionHeaders(sessionId),
@@ -980,7 +980,7 @@ function createCustomerResource(fetcher) {
980
980
  */
981
981
  async verifyEmail(token, fetchOptions) {
982
982
  return fetcher.request(
983
- "/api/storefront/v1/customer/(auth)/verify-email",
983
+ "/api/storefront/v1/customer/verify-email",
984
984
  {
985
985
  method: "GET",
986
986
  params: { token },
@@ -1008,7 +1008,7 @@ function createCustomerResource(fetcher) {
1008
1008
  */
1009
1009
  async resendVerification(customerId, fetchOptions) {
1010
1010
  return fetcher.request(
1011
- "/api/storefront/v1/customer/(auth)/resend-verification",
1011
+ "/api/storefront/v1/customer/resend-verification",
1012
1012
  {
1013
1013
  method: "POST",
1014
1014
  body: { customerId },
@@ -1039,7 +1039,7 @@ function createCustomerResource(fetcher) {
1039
1039
  */
1040
1040
  async forgotPassword(email, fetchOptions) {
1041
1041
  return fetcher.request(
1042
- "/api/storefront/v1/customer/(auth)/forgot-password",
1042
+ "/api/storefront/v1/customer/forgot-password",
1043
1043
  {
1044
1044
  method: "POST",
1045
1045
  body: { email },
@@ -1079,7 +1079,7 @@ function createCustomerResource(fetcher) {
1079
1079
  */
1080
1080
  async resetPassword(token, password, fetchOptions) {
1081
1081
  return fetcher.request(
1082
- "/api/storefront/v1/customer/(auth)/reset-password",
1082
+ "/api/storefront/v1/customer/reset-password",
1083
1083
  {
1084
1084
  method: "POST",
1085
1085
  body: { token, password },
@@ -1296,6 +1296,11 @@ function createCustomerResource(fetcher) {
1296
1296
  }
1297
1297
 
1298
1298
  // src/resources/order.ts
1299
+ function buildDownloadAuthHeaders(auth) {
1300
+ const headers = {};
1301
+ if (auth?.sessionId) headers["x-session-id"] = auth.sessionId;
1302
+ return headers;
1303
+ }
1299
1304
  function createOrderResource(fetcher) {
1300
1305
  return {
1301
1306
  /**
@@ -1315,40 +1320,87 @@ function createOrderResource(fetcher) {
1315
1320
  * console.log(`Order #${order.orderNumber} - ${order.status}`);
1316
1321
  * console.log(`Total: ${order.totalAmount / 100} EUR`);
1317
1322
  * ```
1323
+ */
1324
+ async get(orderId, options) {
1325
+ return fetcher.request(
1326
+ `/api/storefront/v1/order/${encodeURIComponent(orderId)}`,
1327
+ {
1328
+ ...options
1329
+ }
1330
+ );
1331
+ },
1332
+ /**
1333
+ * List downloadable files for a paid order.
1318
1334
  *
1319
- * @example Next.js - with caching
1335
+ * Requires EITHER a download token (from the order confirmation email)
1336
+ * OR a valid customer session (for logged-in customers viewing their own
1337
+ * order history).
1338
+ *
1339
+ * Returns only line items that have digital content or downloadable files.
1340
+ * The order must be paid (status !== PENDING or FAILED).
1341
+ *
1342
+ * @param orderId - The order ID
1343
+ * @param auth - Token (guest) or sessionId (logged-in customer)
1344
+ * @param options - Fetch options
1345
+ *
1346
+ * @example Guest access via email token
1320
1347
  * ```typescript
1321
- * const order = await client.order.get(orderId, {
1322
- * next: { revalidate: 60, tags: ['order', orderId] }
1323
- * });
1348
+ * const token = new URLSearchParams(location.search).get("token");
1349
+ * const { items } = await client.order.listDownloads(orderId, { token });
1324
1350
  * ```
1325
1351
  *
1326
- * @example Display line items
1352
+ * @example Logged-in customer
1327
1353
  * ```typescript
1328
- * const order = await client.order.get(orderId);
1329
- * order.OrderLineItems.forEach(item => {
1330
- * if (item.itemType !== 'SHIPPING') {
1331
- * console.log(`${item.name} x${item.quantity} = ${item.totalAmount / 100} EUR`);
1332
- * }
1333
- * });
1354
+ * const { items } = await client.order.listDownloads(orderId, { sessionId });
1334
1355
  * ```
1356
+ */
1357
+ async listDownloads(orderId, auth, options) {
1358
+ const { headers: extraHeaders, ...restOptions } = options ?? {};
1359
+ return fetcher.request(
1360
+ `/api/storefront/v1/order/${encodeURIComponent(orderId)}/downloads`,
1361
+ {
1362
+ ...restOptions,
1363
+ params: auth?.token ? { token: auth.token } : void 0,
1364
+ headers: {
1365
+ ...buildDownloadAuthHeaders(auth),
1366
+ ...extraHeaders ?? {}
1367
+ }
1368
+ }
1369
+ );
1370
+ },
1371
+ /**
1372
+ * Issue a short-lived presigned URL to download a specific file from a
1373
+ * paid order. Increments the download counter and records a download
1374
+ * event (IP, user agent) on the server.
1375
+ *
1376
+ * The returned URL is typically valid for ~5 minutes — redirect the
1377
+ * browser to it or trigger a download immediately.
1378
+ *
1379
+ * @param orderId - The order ID
1380
+ * @param downloadId - The OrderDownload.id
1381
+ * @param auth - Token (guest) or sessionId (logged-in customer)
1382
+ * @param options - Fetch options
1335
1383
  *
1336
- * @example Show tracking info
1384
+ * @example
1337
1385
  * ```typescript
1338
- * const order = await client.order.get(orderId);
1339
- * if (order.orderShipmentMethod?.trackingNumber) {
1340
- * console.log(`Tracking: ${order.orderShipmentMethod.trackingNumber}`);
1341
- * order.orderShipmentMethod.trackingUrls?.forEach(url => {
1342
- * console.log(`Track at: ${url}`);
1343
- * });
1344
- * }
1386
+ * const { url } = await client.order.getDownloadUrl(orderId, downloadId, { token });
1387
+ * window.location.href = url;
1345
1388
  * ```
1346
1389
  */
1347
- async get(orderId, options) {
1390
+ async getDownloadUrl(orderId, downloadId, auth, options) {
1391
+ const { headers: extraHeaders, ...restOptions } = options ?? {};
1348
1392
  return fetcher.request(
1349
- `/api/storefront/v1/order/${encodeURIComponent(orderId)}`,
1393
+ `/api/storefront/v1/order/${encodeURIComponent(
1394
+ orderId
1395
+ )}/downloads/${encodeURIComponent(downloadId)}`,
1350
1396
  {
1351
- ...options
1397
+ ...restOptions,
1398
+ method: "POST",
1399
+ params: auth?.token ? { token: auth.token } : void 0,
1400
+ headers: {
1401
+ ...buildDownloadAuthHeaders(auth),
1402
+ ...extraHeaders ?? {}
1403
+ }
1352
1404
  }
1353
1405
  );
1354
1406
  }
@@ -1738,6 +1790,65 @@ function createTicketsResource(fetcher) {
1738
1790
  };
1739
1791
  }
1740
1792
 
1793
+ // src/resources/withdrawal.ts
1794
+ function createWithdrawalResource(fetcher) {
1795
+ return {
1796
+ /**
1797
+ * Submit a withdrawal notice (peruutusilmoitus).
1798
+ *
1799
+ * The notice is a legal record of intent. The server records it regardless
1800
+ * of whether the order number can be resolved, and the consumer receives a
1801
+ * confirmation email containing what was withdrawn plus exact submission
1802
+ * date/time.
1803
+ *
1804
+ * Refunds are handled separately by the merchant via the dashboard — this
1805
+ * endpoint never issues a refund.
1806
+ *
1807
+ * @param params - Notice payload (name, email, optional orderNumber + items + message)
1808
+ * @returns Notice number and creation timestamp
1809
+ *
1810
+ * @example
1811
+ * ```typescript
1812
+ * const { noticeNumber } = await client.withdrawal.submit({
1813
+ * name: "Matti Meikäläinen",
1814
+ * email: "matti@example.com",
1815
+ * orderNumber: "1024",
1816
+ * items: [{ productName: "Tuote A", quantity: 1 }],
1817
+ * message: "Haluan peruuttaa.",
1818
+ * confirmRead: true,
1819
+ * });
1820
+ * ```
1821
+ */
1822
+ async submit(params) {
1823
+ return fetcher.request(
1824
+ "/api/storefront/v1/withdrawal",
1825
+ {
1826
+ method: "POST",
1827
+ body: params
1828
+ }
1829
+ );
1830
+ },
1831
+ /**
1832
+ * Resolve a withdrawal token (from the order confirmation email link)
1833
+ * to the matching order's details. Used to pre-fill the withdrawal form.
1834
+ *
1835
+ * Throws `StorefrontError` with code `EXPIRED` / `INVALID` / `STORE_MISMATCH`
1836
+ * / `ORDER_NOT_FOUND` as appropriate.
1837
+ *
1838
+ * @param token - The signed token from the `?token=…` query param
1839
+ */
1840
+ async resolveToken(token) {
1841
+ return fetcher.request(
1842
+ "/api/storefront/v1/withdrawal/resolve-token",
1843
+ {
1844
+ method: "GET",
1845
+ params: { token }
1846
+ }
1847
+ );
1848
+ }
1849
+ };
1850
+ }
1851
+
1741
1852
  // src/client.ts
1742
1853
  function createStorefrontClient(config) {
1743
1854
  if (!config.apiKey) {
@@ -1764,7 +1875,8 @@ function createStorefrontClient(config) {
1764
1875
  checkout: createCheckoutResource(fetcher),
1765
1876
  discountCode: createDiscountCodeResource(fetcher),
1766
1877
  pages: createPagesResource(fetcher),
1767
- tickets: createTicketsResource(fetcher)
1878
+ tickets: createTicketsResource(fetcher),
1879
+ withdrawal: createWithdrawalResource(fetcher)
1768
1880
  };
1769
1881
  }
1770
1882