@scayle/storefront-nuxt 8.12.3 → 8.14.4
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/CHANGELOG.md +92 -76
- package/dist/module.json +1 -1
- package/dist/module.mjs +1 -1
- package/dist/runtime/api/rpcHandler.d.ts +1 -33
- package/package.json +5 -5
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,21 @@
|
|
|
1
1
|
# @scayle/storefront-nuxt
|
|
2
2
|
|
|
3
|
+
## 8.14.4
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
**@scayle/storefront-core v8.14.4**
|
|
8
|
+
|
|
9
|
+
**Dependencies**
|
|
10
|
+
|
|
11
|
+
## 8.12.4
|
|
12
|
+
|
|
13
|
+
### Patch Changes
|
|
14
|
+
|
|
15
|
+
**Dependencies**
|
|
16
|
+
|
|
17
|
+
- Updated dependency to @scayle/storefront-core@8.14.3
|
|
18
|
+
|
|
3
19
|
## 8.12.3
|
|
4
20
|
|
|
5
21
|
### Patch Changes
|
|
@@ -398,28 +414,28 @@
|
|
|
398
414
|
**rpc-methods.ts**
|
|
399
415
|
|
|
400
416
|
```typescript
|
|
401
|
-
import type { RpcContext, RpcHandler } from
|
|
417
|
+
import type { RpcContext, RpcHandler } from "@scayle/storefront-nuxt";
|
|
402
418
|
|
|
403
419
|
export const foo: RpcHandler<string, number> = function testing(
|
|
404
420
|
param: string,
|
|
405
|
-
_: RpcContext
|
|
421
|
+
_: RpcContext
|
|
406
422
|
) {
|
|
407
|
-
return param.length
|
|
408
|
-
}
|
|
423
|
+
return param.length;
|
|
424
|
+
};
|
|
409
425
|
```
|
|
410
426
|
|
|
411
427
|
**module.ts**
|
|
412
428
|
|
|
413
429
|
```typescript
|
|
414
430
|
function setup() {
|
|
415
|
-
const resolver = createResolver(import.meta.url)
|
|
431
|
+
const resolver = createResolver(import.meta.url);
|
|
416
432
|
|
|
417
|
-
nuxt.hook(
|
|
433
|
+
nuxt.hook("storefront:custom-rpc:extend", (customRpcImports) => {
|
|
418
434
|
customRpcImports.push({
|
|
419
|
-
source: resolver.resolve(
|
|
420
|
-
names: [
|
|
421
|
-
})
|
|
422
|
-
})
|
|
435
|
+
source: resolver.resolve("./rpc-methods.ts"),
|
|
436
|
+
names: ["foo"],
|
|
437
|
+
});
|
|
438
|
+
});
|
|
423
439
|
}
|
|
424
440
|
```
|
|
425
441
|
|
|
@@ -641,23 +657,23 @@
|
|
|
641
657
|
storefront: {
|
|
642
658
|
// ...
|
|
643
659
|
redis: {
|
|
644
|
-
host:
|
|
660
|
+
host: "localhost",
|
|
645
661
|
port: 6379,
|
|
646
|
-
prefix:
|
|
647
|
-
user:
|
|
648
|
-
password:
|
|
662
|
+
prefix: "",
|
|
663
|
+
user: "",
|
|
664
|
+
password: "",
|
|
649
665
|
sslTransit: false,
|
|
650
666
|
},
|
|
651
667
|
// ...
|
|
652
668
|
session: {
|
|
653
669
|
// ...
|
|
654
|
-
provider:
|
|
670
|
+
provider: "redis",
|
|
655
671
|
},
|
|
656
672
|
},
|
|
657
673
|
// ...
|
|
658
674
|
},
|
|
659
675
|
// ...
|
|
660
|
-
})
|
|
676
|
+
});
|
|
661
677
|
```
|
|
662
678
|
|
|
663
679
|
- _Current Unified Storage Approach (`nuxt.config.ts`):_
|
|
@@ -671,13 +687,13 @@
|
|
|
671
687
|
// ...
|
|
672
688
|
storage: {
|
|
673
689
|
cache: {
|
|
674
|
-
driver:
|
|
675
|
-
host:
|
|
690
|
+
driver: "redis",
|
|
691
|
+
host: "localhost",
|
|
676
692
|
port: 6379,
|
|
677
693
|
},
|
|
678
694
|
session: {
|
|
679
|
-
driver:
|
|
680
|
-
host:
|
|
695
|
+
driver: "redis",
|
|
696
|
+
host: "localhost",
|
|
681
697
|
port: 6379,
|
|
682
698
|
},
|
|
683
699
|
// ...
|
|
@@ -687,7 +703,7 @@
|
|
|
687
703
|
// ...
|
|
688
704
|
},
|
|
689
705
|
// ...
|
|
690
|
-
})
|
|
706
|
+
});
|
|
691
707
|
```
|
|
692
708
|
|
|
693
709
|
- **\[💥 BREAKING\]** The composable `useSearch` has been replaced by `useStorefrontSearch`, consolidating and transitioning to SCAYLE Search v2.
|
|
@@ -754,9 +770,9 @@
|
|
|
754
770
|
|
|
755
771
|
```ts
|
|
756
772
|
const { activeFilters, applyFilters, resetFilterUrl, productConditions } =
|
|
757
|
-
useQueryFilterState()
|
|
773
|
+
useQueryFilterState();
|
|
758
774
|
|
|
759
|
-
applyFilters({ brand: 23, sale: true, maxPrice: 100, minPrice: 0 })
|
|
775
|
+
applyFilters({ brand: 23, sale: true, maxPrice: 100, minPrice: 0 });
|
|
760
776
|
```
|
|
761
777
|
|
|
762
778
|
- _Current Usage of `useFilter` and `useAppliedFilters`:_
|
|
@@ -769,20 +785,20 @@
|
|
|
769
785
|
resetFilters,
|
|
770
786
|
resetPriceFilter,
|
|
771
787
|
resetFilter,
|
|
772
|
-
} = useFilter()
|
|
788
|
+
} = useFilter();
|
|
773
789
|
|
|
774
|
-
applyPriceFilter([0, 100])
|
|
775
|
-
applyBooleanFilter(
|
|
776
|
-
applyAttributeFilter(
|
|
790
|
+
applyPriceFilter([0, 100]);
|
|
791
|
+
applyBooleanFilter("sale", true);
|
|
792
|
+
applyAttributeFilter("brand", 23);
|
|
777
793
|
|
|
778
|
-
const route = useRoute()
|
|
794
|
+
const route = useRoute();
|
|
779
795
|
const {
|
|
780
796
|
appliedFilter,
|
|
781
797
|
appliedFiltersCount,
|
|
782
798
|
appliedAttributeValues,
|
|
783
799
|
appliedBooleanValues,
|
|
784
800
|
areFiltersApplied,
|
|
785
|
-
} = useAppliedFilters(route)
|
|
801
|
+
} = useAppliedFilters(route);
|
|
786
802
|
```
|
|
787
803
|
|
|
788
804
|
- **\[💥 BREAKING\]** The `getBadgeLabel` helper function has been removed, giving you more control over badge label display.
|
|
@@ -792,43 +808,43 @@
|
|
|
792
808
|
|
|
793
809
|
```ts
|
|
794
810
|
const BadgeLabel = {
|
|
795
|
-
NEW:
|
|
796
|
-
SOLD_OUT:
|
|
797
|
-
ONLINE_EXCLUSIVE:
|
|
798
|
-
SUSTAINABLE:
|
|
799
|
-
PREMIUM:
|
|
800
|
-
DEFAULT:
|
|
801
|
-
} as const
|
|
811
|
+
NEW: "new",
|
|
812
|
+
SOLD_OUT: "sold_out",
|
|
813
|
+
ONLINE_EXCLUSIVE: "online_exclusive",
|
|
814
|
+
SUSTAINABLE: "sustainable",
|
|
815
|
+
PREMIUM: "premium",
|
|
816
|
+
DEFAULT: "",
|
|
817
|
+
} as const;
|
|
802
818
|
|
|
803
819
|
type BadgeLabelParamsKeys =
|
|
804
|
-
|
|
|
805
|
-
|
|
|
806
|
-
|
|
|
807
|
-
|
|
|
808
|
-
|
|
|
809
|
-
type BadgeLabelParams = Partial<Record<BadgeLabelParamsKeys, boolean
|
|
820
|
+
| "isNew"
|
|
821
|
+
| "isSoldOut"
|
|
822
|
+
| "isOnlineOnly"
|
|
823
|
+
| "isSustainable"
|
|
824
|
+
| "isPremium";
|
|
825
|
+
type BadgeLabelParams = Partial<Record<BadgeLabelParamsKeys, boolean>>;
|
|
810
826
|
|
|
811
827
|
const getBadgeLabel = (params: BadgeLabelParams = {}): string => {
|
|
812
828
|
if (!params) {
|
|
813
|
-
return BadgeLabel.DEFAULT
|
|
829
|
+
return BadgeLabel.DEFAULT;
|
|
814
830
|
}
|
|
815
831
|
const { isNew, isSoldOut, isOnlineOnly, isSustainable, isPremium } =
|
|
816
|
-
params
|
|
832
|
+
params;
|
|
817
833
|
|
|
818
834
|
if (isNew) {
|
|
819
|
-
return BadgeLabel.NEW
|
|
835
|
+
return BadgeLabel.NEW;
|
|
820
836
|
} else if (isSoldOut) {
|
|
821
|
-
return BadgeLabel.SOLD_OUT
|
|
837
|
+
return BadgeLabel.SOLD_OUT;
|
|
822
838
|
} else if (isOnlineOnly) {
|
|
823
|
-
return BadgeLabel.ONLINE_EXCLUSIVE
|
|
839
|
+
return BadgeLabel.ONLINE_EXCLUSIVE;
|
|
824
840
|
} else if (isSustainable) {
|
|
825
|
-
return BadgeLabel.SUSTAINABLE
|
|
841
|
+
return BadgeLabel.SUSTAINABLE;
|
|
826
842
|
} else if (isPremium) {
|
|
827
|
-
return BadgeLabel.PREMIUM
|
|
843
|
+
return BadgeLabel.PREMIUM;
|
|
828
844
|
} else {
|
|
829
|
-
return BadgeLabel.DEFAULT
|
|
845
|
+
return BadgeLabel.DEFAULT;
|
|
830
846
|
}
|
|
831
|
-
}
|
|
847
|
+
};
|
|
832
848
|
```
|
|
833
849
|
|
|
834
850
|
- **\[💥 BREAKING\]** The `store` option in the module configuration has been removed. `œscayle/storefront-nuxt@7.84.0` introduced the `shops` option as a replacement, but maintained backward compatibility with the `store` option. Going forward, configuring shops must be done using the `shops` keyword.
|
|
@@ -852,7 +868,7 @@
|
|
|
852
868
|
// ...
|
|
853
869
|
},
|
|
854
870
|
// ...
|
|
855
|
-
})
|
|
871
|
+
});
|
|
856
872
|
```
|
|
857
873
|
|
|
858
874
|
- _Previous Environment Variables for Store Configuration:_
|
|
@@ -881,7 +897,7 @@
|
|
|
881
897
|
// ...
|
|
882
898
|
},
|
|
883
899
|
// ...
|
|
884
|
-
})
|
|
900
|
+
});
|
|
885
901
|
```
|
|
886
902
|
|
|
887
903
|
- _Current Environment Variables for Shops Configuration:_
|
|
@@ -901,8 +917,8 @@
|
|
|
901
917
|
```ts
|
|
902
918
|
useProduct({
|
|
903
919
|
// ...
|
|
904
|
-
key:
|
|
905
|
-
})
|
|
920
|
+
key: "productKey",
|
|
921
|
+
});
|
|
906
922
|
```
|
|
907
923
|
|
|
908
924
|
- _Current `key` as dedicated composables argument:_
|
|
@@ -912,8 +928,8 @@
|
|
|
912
928
|
{
|
|
913
929
|
// ...
|
|
914
930
|
},
|
|
915
|
-
|
|
916
|
-
)
|
|
931
|
+
"productKey"
|
|
932
|
+
);
|
|
917
933
|
```
|
|
918
934
|
|
|
919
935
|
- **\[💥 BREAKING\]** Introducing a new feature flag `storefront.legacy.enableSessionMigration` to control the automatic migration of legacy session data, set to `false` by default. Starting with `@scayle/storefront-nuxt@7.68.0` Storefront uses unique session cookie names for each shop, simplifying implementation and enhancing stability.
|
|
@@ -930,27 +946,27 @@
|
|
|
930
946
|
- _Previous Usage of `handleIDPLoginCallback`:_
|
|
931
947
|
|
|
932
948
|
```ts
|
|
933
|
-
const { handleIDPLoginCallback } = await useIDP()
|
|
949
|
+
const { handleIDPLoginCallback } = await useIDP();
|
|
934
950
|
|
|
935
951
|
watch(
|
|
936
952
|
() => route.query,
|
|
937
953
|
async (query) => {
|
|
938
954
|
if (query.code && isString(query.code)) {
|
|
939
|
-
await handleIDPLoginCallback(query.code)
|
|
955
|
+
await handleIDPLoginCallback(query.code);
|
|
940
956
|
}
|
|
941
957
|
},
|
|
942
|
-
{ immediate: true }
|
|
943
|
-
)
|
|
958
|
+
{ immediate: true }
|
|
959
|
+
);
|
|
944
960
|
```
|
|
945
961
|
|
|
946
962
|
- _Current Usage of `loginIDP`:_
|
|
947
963
|
|
|
948
964
|
```ts
|
|
949
|
-
const { loginIDP } = useAuthentication(
|
|
965
|
+
const { loginIDP } = useAuthentication("login");
|
|
950
966
|
|
|
951
967
|
onMounted(async () => {
|
|
952
|
-
await loginIDP(props.code)
|
|
953
|
-
})
|
|
968
|
+
await loginIDP(props.code);
|
|
969
|
+
});
|
|
954
970
|
```
|
|
955
971
|
|
|
956
972
|
- **\[🧹 NON-BREAKING\]** Addressed various type resolution errors that were present when using the `@scayle/storefront-nuxt` package with different Node.js versions and module systems. These errors manifested as internal resolution errors or ESM dynamic import only warnings. With this fix, the package now more consistently resolves types correctly across Node.js 16 (CJS and ESM), and bundlers, ensuring a smoother developer experience.
|
|
@@ -960,17 +976,17 @@
|
|
|
960
976
|
- _Previous `useRpc` with `autoFetch`:_
|
|
961
977
|
|
|
962
978
|
```ts
|
|
963
|
-
useRpc(
|
|
979
|
+
useRpc("rpcMethod", key, params, { autoFetch: true });
|
|
964
980
|
|
|
965
|
-
useUser({ autoFetch: true })
|
|
981
|
+
useUser({ autoFetch: true });
|
|
966
982
|
```
|
|
967
983
|
|
|
968
984
|
- _Current `useRpc` with `immediate`:_
|
|
969
985
|
|
|
970
986
|
```ts
|
|
971
|
-
useRpc(
|
|
987
|
+
useRpc("rpcMethod", key, params, { immediate: true });
|
|
972
988
|
|
|
973
|
-
useUser({ immediate: true })
|
|
989
|
+
useUser({ immediate: true });
|
|
974
990
|
```
|
|
975
991
|
|
|
976
992
|
- **\[💥 BREAKING\]** The attribute `isCmsPreview` has been removed from `RpcContext`.
|
|
@@ -990,18 +1006,18 @@
|
|
|
990
1006
|
getSearchSuggestions,
|
|
991
1007
|
fetching,
|
|
992
1008
|
...searchData
|
|
993
|
-
} = useStorefrontSearch(searchQuery, { key })
|
|
1009
|
+
} = useStorefrontSearch(searchQuery, { key });
|
|
994
1010
|
|
|
995
|
-
fetching.value // true or false
|
|
1011
|
+
fetching.value; // true or false
|
|
996
1012
|
```
|
|
997
1013
|
|
|
998
1014
|
- _Current `useStorefrontSearch` returning `status`:_
|
|
999
1015
|
|
|
1000
1016
|
```ts
|
|
1001
1017
|
const { data, resolveSearch, getSearchSuggestions, status, ...searchData } =
|
|
1002
|
-
useStorefrontSearch(searchQuery, {}, key)
|
|
1018
|
+
useStorefrontSearch(searchQuery, {}, key);
|
|
1003
1019
|
|
|
1004
|
-
status.value // 'idle', 'pending', 'error' or 'success'
|
|
1020
|
+
status.value; // 'idle', 'pending', 'error' or 'success'
|
|
1005
1021
|
```
|
|
1006
1022
|
|
|
1007
1023
|
- **\[💥 BREAKING\]** We've simplified composable caching and clarified the control you have over shared state behavior. The configuration option `disableDefaultGetCachedDataOverride` has been replaced with `legacy.enableDefaultGetCachedDataOverride`, and its logic has been reversed. Now, when `legacy.enableDefaultGetCachedDataOverride` is not set or set to `false`, the default behavior maintains the shared state functionality of `useRpc`, where multiple calls with the same key use the same cached data. Setting the option to `true` bypasses this shared caching, providing data isolation between calls. To maintain your existing caching behavior, simply change the value of `disableDefaultGetCachedDataOverride` to its opposite in your `nuxt.config.ts` file.
|
|
@@ -1026,7 +1042,7 @@
|
|
|
1026
1042
|
// ...
|
|
1027
1043
|
},
|
|
1028
1044
|
// ...
|
|
1029
|
-
})
|
|
1045
|
+
});
|
|
1030
1046
|
```
|
|
1031
1047
|
|
|
1032
1048
|
- _Current `enableDefaultGetCachedDataOverride`in `nuxt.config.ts`:_
|
|
@@ -1051,7 +1067,7 @@
|
|
|
1051
1067
|
// ...
|
|
1052
1068
|
},
|
|
1053
1069
|
// ...
|
|
1054
|
-
})
|
|
1070
|
+
});
|
|
1055
1071
|
```
|
|
1056
1072
|
|
|
1057
1073
|
- **\[💥 BREAKING\]** The `useRpc` composable has been updated to provide a more modern and robust data fetching experience, aligning its interface with the current and underlying [Nuxt 3 `useAsyncData`.](https://nuxt.com/docs/api/composables/use-async-data#return-values).
|
|
@@ -1073,7 +1089,7 @@
|
|
|
1073
1089
|
function myCustomRpc() {
|
|
1074
1090
|
// ...
|
|
1075
1091
|
|
|
1076
|
-
throw new BaseError(404)
|
|
1092
|
+
throw new BaseError(404);
|
|
1077
1093
|
}
|
|
1078
1094
|
```
|
|
1079
1095
|
|
|
@@ -1083,7 +1099,7 @@
|
|
|
1083
1099
|
function myCustomRpc() {
|
|
1084
1100
|
// ...
|
|
1085
1101
|
|
|
1086
|
-
return new Response(null, { status: 404 })
|
|
1102
|
+
return new Response(null, { status: 404 });
|
|
1087
1103
|
}
|
|
1088
1104
|
```
|
|
1089
1105
|
|
package/dist/module.json
CHANGED
package/dist/module.mjs
CHANGED
|
@@ -10,37 +10,5 @@
|
|
|
10
10
|
*
|
|
11
11
|
* @returns The result of the RPC call or a `Response` object with an error status.
|
|
12
12
|
*/
|
|
13
|
-
declare const _default: import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<
|
|
14
|
-
accessToken: string;
|
|
15
|
-
checkoutJwt: string;
|
|
16
|
-
} | import("@scayle/storefront-api").VariantDetail[] | {
|
|
17
|
-
basket: import("@scayle/storefront-api").BasketResponseData<import("@scayle/storefront-api").Product, import("@scayle/storefront-api").Variant>;
|
|
18
|
-
} | {
|
|
19
|
-
readonly type: "success";
|
|
20
|
-
readonly basket: import("@scayle/storefront-api").BasketResponseData<import("@scayle/storefront-api").Product, import("@scayle/storefront-api").Variant>;
|
|
21
|
-
} | {
|
|
22
|
-
readonly type: "failure";
|
|
23
|
-
readonly basket: import("@scayle/storefront-api").BasketResponseData<import("@scayle/storefront-api").Product, import("@scayle/storefront-api").Variant>;
|
|
24
|
-
readonly errors: import("@scayle/storefront-api").AddOrUpdateItemError[];
|
|
25
|
-
} | import("@scayle/storefront-api").BrandsEndpointResponseData | import("@scayle/storefront-api").Brand | {
|
|
26
|
-
categories: import("@scayle/storefront-api").Category[];
|
|
27
|
-
activeNode: undefined;
|
|
28
|
-
} | import("@scayle/storefront-api").Category | {
|
|
29
|
-
categories: import("@scayle/storefront-api").Category;
|
|
30
|
-
activeNode: import("@scayle/storefront-api").Category;
|
|
31
|
-
} | import("@scayle/storefront-core").Order<Record<string, unknown>, Record<string, unknown>> | import("@scayle/storefront-api").SearchV2SuggestionsEndpointResponseData | import("@scayle/storefront-api").SearchEntity | import("@scayle/storefront-api").ShopConfiguration | {
|
|
32
|
-
user: import("@scayle/storefront-core").ShopUser | undefined;
|
|
33
|
-
} | import("@scayle/storefront-core").ShopUserAddress[] | import("@scayle/storefront-api").NavigationAllEndpointResponseData | import("@scayle/storefront-api").NavigationTree | {
|
|
34
|
-
success: true;
|
|
35
|
-
} | {
|
|
36
|
-
success: false;
|
|
37
|
-
} | {
|
|
38
|
-
result: true;
|
|
39
|
-
} | {
|
|
40
|
-
result: false;
|
|
41
|
-
} | import("@scayle/storefront-api").PromotionsEndpointResponseData | {
|
|
42
|
-
[k: string]: string;
|
|
43
|
-
} | {
|
|
44
|
-
message: string;
|
|
45
|
-
} | null | undefined>>;
|
|
13
|
+
declare const _default: import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<any>>;
|
|
46
14
|
export default _default;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@scayle/storefront-nuxt",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "8.
|
|
4
|
+
"version": "8.14.4",
|
|
5
5
|
"description": "Nuxt integration for the SCAYLE Commerce Engine and Storefront API",
|
|
6
6
|
"author": "SCAYLE Commerce Engine",
|
|
7
7
|
"license": "MIT",
|
|
@@ -81,7 +81,7 @@
|
|
|
81
81
|
"dependencies": {
|
|
82
82
|
"@opentelemetry/api": "^1.9.0",
|
|
83
83
|
"@scayle/h3-session": "0.6.0",
|
|
84
|
-
"@scayle/storefront-core": "8.14.
|
|
84
|
+
"@scayle/storefront-core": "8.14.4",
|
|
85
85
|
"@scayle/unstorage-compression-driver": "^0.2.4",
|
|
86
86
|
"@vercel/nft": "0.29.2",
|
|
87
87
|
"@vueuse/core": "13.0.0",
|
|
@@ -101,15 +101,15 @@
|
|
|
101
101
|
},
|
|
102
102
|
"devDependencies": {
|
|
103
103
|
"@eslint/eslintrc": "3.3.1",
|
|
104
|
-
"@nuxt/eslint": "1.
|
|
104
|
+
"@nuxt/eslint": "1.3.0",
|
|
105
105
|
"@nuxt/kit": "3.15.4",
|
|
106
106
|
"@nuxt/module-builder": "0.8.4",
|
|
107
107
|
"@nuxt/schema": "3.15.4",
|
|
108
108
|
"@nuxt/test-utils": "3.17.2",
|
|
109
|
-
"@scayle/eslint-config-storefront": "4.
|
|
109
|
+
"@scayle/eslint-config-storefront": "4.5.0",
|
|
110
110
|
"@scayle/eslint-plugin-vue-composable": "0.2.1",
|
|
111
111
|
"@scayle/unstorage-scayle-kv-driver": "0.1.1",
|
|
112
|
-
"@types/node": "22.13.
|
|
112
|
+
"@types/node": "22.13.14",
|
|
113
113
|
"dprint": "0.49.1",
|
|
114
114
|
"eslint-formatter-gitlab": "5.1.0",
|
|
115
115
|
"eslint": "9.23.0",
|