@01.software/sdk 0.10.1 → 0.11.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.js CHANGED
@@ -564,6 +564,12 @@ var ProductApi = class extends BaseApi {
564
564
  stockCheck(params) {
565
565
  return this.request("/api/products/stock-check", params);
566
566
  }
567
+ listingGroups(params) {
568
+ return this.request(
569
+ "/api/products/listing-groups",
570
+ params
571
+ );
572
+ }
567
573
  };
568
574
 
569
575
  // src/utils/types.ts
@@ -908,6 +914,18 @@ var CollectionClient = class extends HttpClient {
908
914
  });
909
915
  return this.parseFindResponse(response);
910
916
  }
917
+ /**
918
+ * Find-like response from a custom endpoint
919
+ * POST /api/...custom-endpoint
920
+ */
921
+ async requestFindEndpoint(endpoint, data) {
922
+ const response = await httpFetch(endpoint, {
923
+ ...this.defaultOptions,
924
+ method: "POST",
925
+ body: data ? JSON.stringify(data) : void 0
926
+ });
927
+ return this.parseFindResponse(response);
928
+ }
911
929
  /**
912
930
  * Find document by ID
913
931
  * GET /api/{collection}/{id}
@@ -1056,7 +1074,6 @@ var COLLECTIONS = [
1056
1074
  "playlist-categories",
1057
1075
  "playlist-tags",
1058
1076
  "tracks",
1059
- "playlist-tracks",
1060
1077
  "track-categories",
1061
1078
  "track-tags",
1062
1079
  "galleries",
@@ -1555,6 +1572,14 @@ function getQueryClient() {
1555
1572
  return browserQueryClient;
1556
1573
  }
1557
1574
 
1575
+ // src/core/query/query-hooks.ts
1576
+ import {
1577
+ useInfiniteQuery as useInfiniteQueryOriginal2,
1578
+ useQuery as useQueryOriginal3,
1579
+ useSuspenseInfiniteQuery as useSuspenseInfiniteQueryOriginal2,
1580
+ useSuspenseQuery as useSuspenseQueryOriginal2
1581
+ } from "@tanstack/react-query";
1582
+
1558
1583
  // src/core/query/collection-hooks.ts
1559
1584
  import {
1560
1585
  useQuery as useQueryOriginal,
@@ -1580,6 +1605,10 @@ var customerKeys = {
1580
1605
  all: ["customer"],
1581
1606
  me: () => ["customer", "me"]
1582
1607
  };
1608
+ var productKeys = {
1609
+ listingGroups: (options) => ["products", "listing-groups", "list", options],
1610
+ listingGroupsInfinite: (options) => ["products", "listing-groups", "infinite", options]
1611
+ };
1583
1612
 
1584
1613
  // src/core/query/collection-hooks.ts
1585
1614
  var DEFAULT_PAGE_SIZE = 20;
@@ -1957,6 +1986,98 @@ var QueryHooks = class extends CollectionHooks {
1957
1986
  this.setCustomerData = (data) => this._customer.setCustomerData(data);
1958
1987
  this._customer = new CustomerHooks(queryClient, customerAuth);
1959
1988
  }
1989
+ useProductListingGroupsQuery(params, options) {
1990
+ const queryOptions = params.options;
1991
+ const { placeholderData, ...restOptions } = options ?? {};
1992
+ return useQueryOriginal3({
1993
+ queryKey: productKeys.listingGroups(queryOptions),
1994
+ queryFn: async () => this.collectionClient.requestFindEndpoint(
1995
+ "/api/products/listing-groups/query",
1996
+ { options: queryOptions }
1997
+ ),
1998
+ ...restOptions,
1999
+ ...placeholderData !== void 0 && {
2000
+ placeholderData
2001
+ }
2002
+ });
2003
+ }
2004
+ useSuspenseProductListingGroupsQuery(params, options) {
2005
+ const queryOptions = params.options;
2006
+ return useSuspenseQueryOriginal2({
2007
+ queryKey: productKeys.listingGroups(queryOptions),
2008
+ queryFn: async () => this.collectionClient.requestFindEndpoint(
2009
+ "/api/products/listing-groups/query",
2010
+ { options: queryOptions }
2011
+ ),
2012
+ ...options
2013
+ });
2014
+ }
2015
+ useInfiniteProductListingGroupsQuery(params, options) {
2016
+ const {
2017
+ options: queryOptions,
2018
+ pageSize = 20
2019
+ } = params;
2020
+ return useInfiniteQueryOriginal2({
2021
+ queryKey: productKeys.listingGroupsInfinite(queryOptions),
2022
+ queryFn: async ({ pageParam }) => this.collectionClient.requestFindEndpoint(
2023
+ "/api/products/listing-groups/query",
2024
+ {
2025
+ options: { ...queryOptions, page: pageParam, limit: pageSize }
2026
+ }
2027
+ ),
2028
+ initialPageParam: 1,
2029
+ getNextPageParam: (lastPage) => lastPage.hasNextPage ? lastPage.nextPage : void 0,
2030
+ ...options
2031
+ });
2032
+ }
2033
+ useSuspenseInfiniteProductListingGroupsQuery(params, options) {
2034
+ const {
2035
+ options: queryOptions,
2036
+ pageSize = 20
2037
+ } = params;
2038
+ return useSuspenseInfiniteQueryOriginal2({
2039
+ queryKey: productKeys.listingGroupsInfinite(queryOptions),
2040
+ queryFn: async ({ pageParam }) => this.collectionClient.requestFindEndpoint(
2041
+ "/api/products/listing-groups/query",
2042
+ {
2043
+ options: { ...queryOptions, page: pageParam, limit: pageSize }
2044
+ }
2045
+ ),
2046
+ initialPageParam: 1,
2047
+ getNextPageParam: (lastPage) => lastPage.hasNextPage ? lastPage.nextPage : void 0,
2048
+ ...options
2049
+ });
2050
+ }
2051
+ async prefetchProductListingGroupsQuery(params, options) {
2052
+ const queryOptions = params.options;
2053
+ return this.queryClient.prefetchQuery({
2054
+ queryKey: productKeys.listingGroups(queryOptions),
2055
+ queryFn: async () => this.collectionClient.requestFindEndpoint(
2056
+ "/api/products/listing-groups/query",
2057
+ { options: queryOptions }
2058
+ ),
2059
+ ...options
2060
+ });
2061
+ }
2062
+ async prefetchInfiniteProductListingGroupsQuery(params, options) {
2063
+ const {
2064
+ options: queryOptions,
2065
+ pageSize = 20
2066
+ } = params;
2067
+ return this.queryClient.prefetchInfiniteQuery({
2068
+ queryKey: productKeys.listingGroupsInfinite(queryOptions),
2069
+ queryFn: async ({ pageParam }) => this.collectionClient.requestFindEndpoint(
2070
+ "/api/products/listing-groups/query",
2071
+ {
2072
+ options: { ...queryOptions, page: pageParam, limit: pageSize }
2073
+ }
2074
+ ),
2075
+ initialPageParam: 1,
2076
+ getNextPageParam: (lastPage) => lastPage.hasNextPage ? lastPage.nextPage : void 0,
2077
+ pages: options?.pages ?? 1,
2078
+ staleTime: options?.staleTime
2079
+ });
2080
+ }
1960
2081
  };
1961
2082
 
1962
2083
  // src/core/client/client.ts
@@ -2297,6 +2418,242 @@ function createTypedWebhookHandler(collection, handler) {
2297
2418
  };
2298
2419
  }
2299
2420
 
2421
+ // src/utils/ecommerce.ts
2422
+ function getRelationID(value) {
2423
+ if (typeof value === "string") return value;
2424
+ if (typeof value === "number") return String(value);
2425
+ if (value && typeof value === "object" && "id" in value) {
2426
+ const id = value.id;
2427
+ if (typeof id === "string") return id;
2428
+ if (typeof id === "number") return String(id);
2429
+ }
2430
+ return void 0;
2431
+ }
2432
+ function compareOrder(left, right) {
2433
+ return (left ?? "").localeCompare(right ?? "");
2434
+ }
2435
+ function isProductOptionValueDoc(value) {
2436
+ return typeof value === "object" && value !== null && "id" in value && ("value" in value || "slug" in value);
2437
+ }
2438
+ function extractEntityId(value) {
2439
+ if (typeof value === "string") return value;
2440
+ if (typeof value === "number") return String(value);
2441
+ if (value && typeof value === "object" && "id" in value) {
2442
+ if (typeof value.id === "string") return value.id;
2443
+ if (typeof value.id === "number") return String(value.id);
2444
+ }
2445
+ return null;
2446
+ }
2447
+ function getFirstMediaId(values) {
2448
+ if (!Array.isArray(values)) return null;
2449
+ for (const value of values) {
2450
+ const id = extractEntityId(value);
2451
+ if (id != null) return id;
2452
+ }
2453
+ return null;
2454
+ }
2455
+ function getVariantPrimaryImage(variant) {
2456
+ if (!variant) return null;
2457
+ return extractEntityId(variant.thumbnail) ?? getFirstMediaId(variant.images);
2458
+ }
2459
+ function normalizeOptionValue(value, fallbackOptionId) {
2460
+ return {
2461
+ id: String(value.id),
2462
+ optionId: getRelationID(value.option) ?? fallbackOptionId,
2463
+ label: value.value || value.slug || String(value.id),
2464
+ slug: value.slug ?? null,
2465
+ order: value._order ?? value["_product-option-values_values_order"] ?? ""
2466
+ };
2467
+ }
2468
+ function normalizeVariantOptionValues(variant, valueToOptionId, optionIds) {
2469
+ const optionValueByOptionId = /* @__PURE__ */ new Map();
2470
+ for (const rawValue of Array.isArray(variant.optionValues) ? variant.optionValues : []) {
2471
+ const valueId = getRelationID(rawValue);
2472
+ if (!valueId) continue;
2473
+ const optionId = valueToOptionId.get(valueId) ?? (isProductOptionValueDoc(rawValue) ? getRelationID(rawValue.option) : void 0);
2474
+ if (!optionId || optionValueByOptionId.has(optionId)) continue;
2475
+ optionValueByOptionId.set(optionId, valueId);
2476
+ }
2477
+ const optionValueIds = optionIds.map((optionId) => optionValueByOptionId.get(optionId)).filter((valueId) => Boolean(valueId));
2478
+ return {
2479
+ id: String(variant.id),
2480
+ optionValueIds,
2481
+ optionValueByOptionId,
2482
+ source: variant
2483
+ };
2484
+ }
2485
+ function buildProductOptionMatrix({
2486
+ options,
2487
+ variants = []
2488
+ }) {
2489
+ const normalizedOptions = options.map((option) => {
2490
+ const valuesById = /* @__PURE__ */ new Map();
2491
+ for (const rawValue of option.values?.docs ?? []) {
2492
+ if (!isProductOptionValueDoc(rawValue)) continue;
2493
+ const normalizedValue = normalizeOptionValue(rawValue, String(option.id));
2494
+ valuesById.set(normalizedValue.id, normalizedValue);
2495
+ }
2496
+ return {
2497
+ id: String(option.id),
2498
+ title: option.title ?? String(option.id),
2499
+ order: option._order ?? option["_product-options_options_order"] ?? "",
2500
+ values: Array.from(valuesById.values()).sort(
2501
+ (left, right) => compareOrder(left.order, right.order)
2502
+ )
2503
+ };
2504
+ }).sort((left, right) => compareOrder(left.order, right.order));
2505
+ const optionById = new Map(normalizedOptions.map((option) => [option.id, option]));
2506
+ const valueById = /* @__PURE__ */ new Map();
2507
+ const valueToOptionId = /* @__PURE__ */ new Map();
2508
+ for (const option of normalizedOptions) {
2509
+ for (const value of option.values) {
2510
+ valueById.set(value.id, value);
2511
+ valueToOptionId.set(value.id, option.id);
2512
+ }
2513
+ }
2514
+ const optionIds = normalizedOptions.map((option) => option.id);
2515
+ const normalizedVariants = variants.map(
2516
+ (variant) => normalizeVariantOptionValues(variant, valueToOptionId, optionIds)
2517
+ );
2518
+ return {
2519
+ options: normalizedOptions,
2520
+ optionIds,
2521
+ optionById,
2522
+ valueById,
2523
+ valueToOptionId,
2524
+ variants: normalizedVariants
2525
+ };
2526
+ }
2527
+ function getSelectedValueByOptionId(matrix, selectedValueIds) {
2528
+ const selectedByOption = /* @__PURE__ */ new Map();
2529
+ for (const rawValue of selectedValueIds) {
2530
+ const valueId = getRelationID(rawValue);
2531
+ if (!valueId) continue;
2532
+ const optionId = matrix.valueToOptionId.get(valueId);
2533
+ if (!optionId || selectedByOption.has(optionId)) continue;
2534
+ selectedByOption.set(optionId, valueId);
2535
+ }
2536
+ return selectedByOption;
2537
+ }
2538
+ function normalizeSelectedValueIds(matrix, selectedValueIds) {
2539
+ const selectedByOption = getSelectedValueByOptionId(matrix, selectedValueIds);
2540
+ return matrix.optionIds.map((optionId) => selectedByOption.get(optionId)).filter((valueId) => Boolean(valueId));
2541
+ }
2542
+ function getAvailableOptionValues(matrix, optionId, selectedValueIds) {
2543
+ const option = matrix.optionById.get(optionId);
2544
+ if (!option) return [];
2545
+ if (matrix.variants.length === 0) {
2546
+ return option.values;
2547
+ }
2548
+ const selectedByOption = getSelectedValueByOptionId(matrix, selectedValueIds);
2549
+ selectedByOption.delete(optionId);
2550
+ const matchingVariants = matrix.variants.filter(
2551
+ (variant) => Array.from(selectedByOption.entries()).every(
2552
+ ([selectedOptionId, selectedValueId]) => variant.optionValueByOptionId.get(selectedOptionId) === selectedValueId
2553
+ )
2554
+ );
2555
+ const availableValueIds = new Set(
2556
+ matchingVariants.map((variant) => variant.optionValueByOptionId.get(optionId)).filter((valueId) => Boolean(valueId))
2557
+ );
2558
+ return option.values.filter((value) => availableValueIds.has(value.id));
2559
+ }
2560
+ function resolveVariantForSelection(matrix, selectedValueIds) {
2561
+ const selectedByOption = getSelectedValueByOptionId(matrix, selectedValueIds);
2562
+ if (selectedByOption.size !== matrix.optionIds.length) {
2563
+ return void 0;
2564
+ }
2565
+ return matrix.variants.find(
2566
+ (variant) => matrix.optionIds.every(
2567
+ (optionId) => variant.optionValueByOptionId.get(optionId) === selectedByOption.get(optionId)
2568
+ )
2569
+ );
2570
+ }
2571
+ function compareVariantOrder(a, b) {
2572
+ const aOrder = Number(a._order ?? Number.MAX_SAFE_INTEGER);
2573
+ const bOrder = Number(b._order ?? Number.MAX_SAFE_INTEGER);
2574
+ if (Number.isFinite(aOrder) && Number.isFinite(bOrder) && aOrder !== bOrder) {
2575
+ return aOrder - bOrder;
2576
+ }
2577
+ const aId = String(getRelationID(a.id) ?? "");
2578
+ const bId = String(getRelationID(b.id) ?? "");
2579
+ return aId.localeCompare(bId);
2580
+ }
2581
+ function isVariantAvailableForSale(variant) {
2582
+ if (variant.isActive === false) return false;
2583
+ if (variant.isUnlimited) return true;
2584
+ return (variant.stock ?? 0) > 0;
2585
+ }
2586
+ function getMinMax(values) {
2587
+ const numbers = values.filter((value) => typeof value === "number");
2588
+ if (numbers.length === 0) {
2589
+ return { min: null, max: null };
2590
+ }
2591
+ return {
2592
+ min: Math.min(...numbers),
2593
+ max: Math.max(...numbers)
2594
+ };
2595
+ }
2596
+ function buildProductListingProjection(product, variants) {
2597
+ const orderedVariants = [...variants].sort(compareVariantOrder);
2598
+ const activeVariants = orderedVariants.filter((variant) => variant.isActive !== false);
2599
+ const availableVariants = activeVariants.filter(isVariantAvailableForSale);
2600
+ const selectionHintVariant = availableVariants[0] ?? activeVariants[0] ?? null;
2601
+ const { min: minPrice, max: maxPrice } = getMinMax(
2602
+ activeVariants.map((variant) => variant.price)
2603
+ );
2604
+ const { min: minCompareAtPrice, max: maxCompareAtPrice } = getMinMax(
2605
+ activeVariants.map((variant) => variant.compareAtPrice)
2606
+ );
2607
+ const productPrimaryImage = extractEntityId(product?.thumbnail) ?? getFirstMediaId(product?.images);
2608
+ const variantPrimaryImage = getVariantPrimaryImage(selectionHintVariant) ?? getVariantPrimaryImage(activeVariants[0]) ?? getVariantPrimaryImage(orderedVariants[0]);
2609
+ return {
2610
+ selectionHintVariant: getRelationID(selectionHintVariant?.id) ?? null,
2611
+ primaryImage: productPrimaryImage ?? variantPrimaryImage,
2612
+ minPrice,
2613
+ maxPrice,
2614
+ minCompareAtPrice,
2615
+ maxCompareAtPrice,
2616
+ isPriceRange: minPrice !== null && maxPrice !== null ? minPrice !== maxPrice : false,
2617
+ availableForSale: availableVariants.length > 0
2618
+ };
2619
+ }
2620
+ function buildProductListingGroupsByOption(args) {
2621
+ const primaryOptionId = args.primaryOptionId ?? void 0;
2622
+ if (!primaryOptionId) return [];
2623
+ const matrix = buildProductOptionMatrix({
2624
+ options: args.options,
2625
+ variants: args.variants
2626
+ });
2627
+ const primaryOption = matrix.optionById.get(primaryOptionId);
2628
+ if (!primaryOption) return [];
2629
+ return primaryOption.values.flatMap((value) => {
2630
+ const variants = matrix.variants.filter(
2631
+ (variant) => variant.optionValueByOptionId.get(primaryOption.id) === value.id
2632
+ ).map((variant) => variant.source);
2633
+ if (variants.length === 0) {
2634
+ return [];
2635
+ }
2636
+ const listingBase = buildProductListingProjection(void 0, variants);
2637
+ const productFallbackImage = extractEntityId(args.product?.thumbnail) ?? getFirstMediaId(args.product?.images);
2638
+ return [
2639
+ {
2640
+ optionId: primaryOption.id,
2641
+ optionTitle: primaryOption.title,
2642
+ optionValueId: value.id,
2643
+ optionValueLabel: value.label,
2644
+ optionValueSlug: value.slug,
2645
+ variantIds: variants.map((variant) => String(variant.id)),
2646
+ variantCount: variants.length,
2647
+ variants,
2648
+ listing: {
2649
+ ...listingBase,
2650
+ primaryImage: listingBase.primaryImage ?? productFallbackImage
2651
+ }
2652
+ }
2653
+ ];
2654
+ });
2655
+ }
2656
+
2300
2657
  // src/utils/image.ts
2301
2658
  var IMAGE_SIZES = [384, 768, 1536];
2302
2659
  function getImageUrl(image, displayWidth, dpr = 1) {
@@ -2435,6 +2792,9 @@ export {
2435
2792
  TimeoutError,
2436
2793
  UsageLimitError,
2437
2794
  ValidationError,
2795
+ buildProductListingGroupsByOption,
2796
+ buildProductListingProjection,
2797
+ buildProductOptionMatrix,
2438
2798
  collectionKeys,
2439
2799
  createClient,
2440
2800
  createServerClient,
@@ -2442,12 +2802,14 @@ export {
2442
2802
  customerKeys,
2443
2803
  formatOrderName,
2444
2804
  generateOrderNumber,
2805
+ getAvailableOptionValues,
2445
2806
  getImageLqip,
2446
2807
  getImagePalette,
2447
2808
  getImagePlaceholderStyle,
2448
2809
  getImageSrcSet,
2449
2810
  getImageUrl,
2450
2811
  getQueryClient,
2812
+ getSelectedValueByOptionId,
2451
2813
  getVideoGif,
2452
2814
  getVideoMp4Url,
2453
2815
  getVideoStoryboard,
@@ -2464,6 +2826,9 @@ export {
2464
2826
  isUsageLimitError,
2465
2827
  isValidWebhookEvent,
2466
2828
  isValidationError,
2467
- resolveRelation
2829
+ normalizeSelectedValueIds,
2830
+ productKeys,
2831
+ resolveRelation,
2832
+ resolveVariantForSelection
2468
2833
  };
2469
2834
  //# sourceMappingURL=index.js.map