@ecomiq/core 0.1.8 → 1.0.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/LICENSE +21 -0
- package/README.md +39 -2
- package/dist/_virtual/_rolldown/runtime-C6LprzCP.cjs +22 -0
- package/dist/api.cjs +117 -102
- package/dist/api.d.cts +33 -37
- package/dist/api.d.ts +33 -37
- package/dist/api.js +116 -100
- package/dist/client.cjs +499 -1681
- package/dist/client.d.cts +156 -15
- package/dist/client.d.ts +156 -15
- package/dist/client.js +500 -1680
- package/dist/index.cjs +333 -2108
- package/dist/index.d.cts +53 -1117
- package/dist/index.d.ts +53 -1117
- package/dist/index.js +52 -1910
- package/dist/libs/bounded-read-cache-Abmb5VnJ.js +41 -0
- package/dist/libs/bounded-read-cache-D4644LJo.cjs +41 -0
- package/dist/libs/catalog-link-key-B7l5KZsF.js +9 -0
- package/dist/libs/catalog-link-key-CZTHJBGD.cjs +9 -0
- package/dist/libs/catalog-link-key.d.cts +2 -0
- package/dist/libs/catalog-link-key.d.ts +2 -0
- package/dist/libs/graphql-_6Y8lR_Q.js +49 -0
- package/dist/libs/graphql-selection-Cj51WkJn.cjs +21 -0
- package/dist/libs/graphql-selection-H1RMh6VD.js +21 -0
- package/dist/libs/graphql-selection.d.cts +3 -0
- package/dist/libs/graphql-selection.d.ts +3 -0
- package/dist/libs/graphql-wJH7HaQU.cjs +50 -0
- package/dist/libs/graphql.d.cts +24 -0
- package/dist/libs/graphql.d.ts +24 -0
- package/dist/models/amounts-cKBCecl7.js +5 -0
- package/dist/models/amounts-lmg89eJQ.cjs +4 -0
- package/dist/models/articles-C-4JvT2Z.js +27 -0
- package/dist/models/articles-xHCXLKDK.cjs +30 -0
- package/dist/models/articles.d.cts +46 -0
- package/dist/models/articles.d.ts +46 -0
- package/dist/models/catalog-links-BzJeyBy4.js +80 -0
- package/dist/models/catalog-links-c4LADGf_.cjs +88 -0
- package/dist/models/catalog-links.d.cts +39 -0
- package/dist/models/catalog-links.d.ts +39 -0
- package/dist/models/categories-CKkJY8_P.js +42 -0
- package/dist/models/categories-DZ5i5kwi.cjs +45 -0
- package/dist/models/categories.d.cts +54 -0
- package/dist/models/categories.d.ts +54 -0
- package/dist/models/collections.cjs +13 -24
- package/dist/models/collections.d.cts +23 -56
- package/dist/models/collections.d.ts +23 -56
- package/dist/models/collections.js +12 -22
- package/dist/models/complaint-book-D5INpuI2.cjs +64 -0
- package/dist/models/complaint-book-QpQZe7Xl.js +58 -0
- package/dist/models/complaint-book.d.cts +71 -0
- package/dist/models/complaint-book.d.ts +71 -0
- package/dist/models/customer-address.cjs +39 -32
- package/dist/models/customer-address.d.cts +59 -158
- package/dist/models/customer-address.d.ts +59 -158
- package/dist/models/customer-address.js +38 -30
- package/dist/models/customer-order.cjs +181 -136
- package/dist/models/customer-order.d.cts +430 -862
- package/dist/models/customer-order.d.ts +430 -862
- package/dist/models/customer-order.js +178 -135
- package/dist/models/customer-profile.cjs +121 -112
- package/dist/models/customer-profile.d.cts +90 -175
- package/dist/models/customer-profile.d.ts +90 -175
- package/dist/models/customer-profile.js +121 -110
- package/dist/models/customer-registration-C13knqyv.js +28 -0
- package/dist/models/customer-registration-EZ0yZgGr.cjs +31 -0
- package/dist/models/customer-registration.d.cts +66 -0
- package/dist/models/customer-registration.d.ts +66 -0
- package/dist/models/customer-session-BiX0TXhO.js +41 -0
- package/dist/models/customer-session-JeQiC8Yx.cjs +45 -0
- package/dist/models/customer-session.d.cts +61 -0
- package/dist/models/customer-session.d.ts +61 -0
- package/dist/models/geo.cjs +52 -51
- package/dist/models/geo.d.cts +141 -270
- package/dist/models/geo.d.ts +141 -270
- package/dist/models/geo.js +51 -49
- package/dist/models/ids.cjs +9 -13
- package/dist/models/ids.d.cts +9 -12
- package/dist/models/ids.d.ts +9 -12
- package/dist/models/ids.js +8 -12
- package/dist/models/order-draft-CnHJ0btL.js +37 -0
- package/dist/models/order-draft-PFBZfRRR.cjs +39 -0
- package/dist/models/order-draft.d.cts +51 -0
- package/dist/models/order-draft.d.ts +51 -0
- package/dist/models/order-review--xGlZKtS.cjs +18 -0
- package/dist/models/order-review-egGeCaqB.js +17 -0
- package/dist/models/order-review.d.cts +22 -0
- package/dist/models/order-review.d.ts +22 -0
- package/dist/models/order-status-CS_OeSPY.cjs +66 -0
- package/dist/models/order-status-CgaLkU0M.js +60 -0
- package/dist/models/order-status.d.cts +298 -0
- package/dist/models/order-status.d.ts +298 -0
- package/dist/models/payment-methods--VUUZpMz.js +17 -0
- package/dist/models/payment-methods-CmK08zBM.cjs +19 -0
- package/dist/models/payment-methods.d.cts +28 -0
- package/dist/models/payment-methods.d.ts +28 -0
- package/dist/models/products.cjs +214 -200
- package/dist/models/products.d.cts +616 -1359
- package/dist/models/products.d.ts +616 -1359
- package/dist/models/products.js +210 -192
- package/dist/models/search.cjs +15 -202
- package/dist/models/search.d.cts +21 -51
- package/dist/models/search.d.ts +21 -51
- package/dist/models/search.js +14 -200
- package/dist/models/sellers.cjs +44 -0
- package/dist/models/sellers.d.cts +82 -0
- package/dist/models/sellers.d.ts +82 -0
- package/dist/models/sellers.js +38 -0
- package/dist/models/settings.cjs +205 -238
- package/dist/models/settings.d.cts +862 -6949
- package/dist/models/settings.d.ts +862 -6949
- package/dist/models/settings.js +213 -241
- package/dist/models/storefront-cart.cjs +143 -129
- package/dist/models/storefront-cart.d.cts +255 -713
- package/dist/models/storefront-cart.d.ts +255 -713
- package/dist/models/storefront-cart.js +140 -127
- package/dist/models/storefront-checkout.cjs +212 -298
- package/dist/models/storefront-checkout.d.cts +656 -2441
- package/dist/models/storefront-checkout.d.ts +656 -2441
- package/dist/models/storefront-checkout.js +208 -298
- package/dist/models/storefront-reviews.cjs +62 -226
- package/dist/models/storefront-reviews.d.cts +73 -141
- package/dist/models/storefront-reviews.d.ts +73 -141
- package/dist/models/storefront-reviews.js +59 -225
- package/dist/models/tracking-CiIAhQW0.js +33 -0
- package/dist/models/tracking-wNyzQ6Bp.cjs +36 -0
- package/dist/models/tracking.d.cts +26 -0
- package/dist/models/tracking.d.ts +26 -0
- package/dist/models/urls-B0ZODOwH.cjs +35 -0
- package/dist/models/urls-Dt_dTt4Q.js +33 -0
- package/dist/models/urls.d.cts +201 -0
- package/dist/models/urls.d.ts +201 -0
- package/dist/redirects.cjs +113 -0
- package/dist/redirects.d.cts +11 -0
- package/dist/redirects.d.ts +11 -0
- package/dist/redirects.js +108 -0
- package/dist/services/article.service-DBsOvflH.js +10 -0
- package/dist/services/article.service-zmTkbbPV.cjs +11 -0
- package/dist/services/article.service.d.cts +4 -0
- package/dist/services/article.service.d.ts +4 -0
- package/dist/services/cart.service-B0D8s6jI.cjs +37 -0
- package/dist/services/cart.service-yMCz9oQP.js +33 -0
- package/dist/services/cart.service.d.cts +527 -0
- package/dist/services/cart.service.d.ts +527 -0
- package/dist/services/catalog-link.service-BQ2d-EPX.js +8 -0
- package/dist/services/catalog-link.service-DiB-OVjn.cjs +8 -0
- package/dist/services/category.service-8tieYX2r.js +6 -0
- package/dist/services/category.service-BsSJZV2B.cjs +6 -0
- package/dist/services/checkout.service-CC-3tm2y.js +60 -0
- package/dist/services/checkout.service-CG8KrDNY.cjs +69 -0
- package/dist/services/checkout.service.d.cts +439 -0
- package/dist/services/checkout.service.d.ts +439 -0
- package/dist/services/collection.service-C4QETpuI.js +11 -0
- package/dist/services/collection.service-DHGN3rhs.cjs +12 -0
- package/dist/services/complaint-book.service-C7TxltQe.cjs +13 -0
- package/dist/services/complaint-book.service-DXiVyKdD.js +12 -0
- package/dist/services/complaint-book.service.d.cts +4 -0
- package/dist/services/complaint-book.service.d.ts +4 -0
- package/dist/services/customer-address.service-Ca4qla_R.cjs +51 -0
- package/dist/services/customer-address.service-xEThx7cQ.js +47 -0
- package/dist/services/customer-address.service.d.cts +19 -0
- package/dist/services/customer-address.service.d.ts +19 -0
- package/dist/services/customer-order.service-DLGgT0xa.cjs +54 -0
- package/dist/services/customer-order.service-qHoRBuyX.js +51 -0
- package/dist/services/customer-order.service.d.cts +34 -0
- package/dist/services/customer-order.service.d.ts +34 -0
- package/dist/services/customer-registration.service-C3BNyCHP.cjs +10 -0
- package/dist/services/customer-registration.service-CxcWD2hf.js +9 -0
- package/dist/services/customer-registration.service.d.cts +5 -0
- package/dist/services/customer-registration.service.d.ts +5 -0
- package/dist/services/customer-session.service-4YgfbWRB.js +16 -0
- package/dist/services/customer-session.service-Bd8pLC2v.cjs +19 -0
- package/dist/services/customer.service-BM0NrOxP.cjs +26 -0
- package/dist/services/customer.service-BoU6l2-R.js +25 -0
- package/dist/services/customer.service.d.cts +10 -0
- package/dist/services/customer.service.d.ts +10 -0
- package/dist/services/geo.service-C32R7N8W.js +39 -0
- package/dist/services/geo.service-JeTT3Wun.cjs +42 -0
- package/dist/services/geo.service.d.cts +10 -0
- package/dist/services/geo.service.d.ts +10 -0
- package/dist/services/layout.service-BkvLzl1g.cjs +50 -0
- package/dist/services/layout.service-DmbeMOkK.js +50 -0
- package/dist/services/layout.service.d.cts +9 -0
- package/dist/services/layout.service.d.ts +9 -0
- package/dist/services/order-draft.service-D9gy-OPr.cjs +14 -0
- package/dist/services/order-draft.service-DYPR_pcV.js +13 -0
- package/dist/services/order-draft.service.d.cts +4 -0
- package/dist/services/order-draft.service.d.ts +4 -0
- package/dist/services/order-review.service-BEr-FB6_.cjs +11 -0
- package/dist/services/order-review.service-PdBPUsxE.js +11 -0
- package/dist/services/order-review.service.d.cts +7 -0
- package/dist/services/order-review.service.d.ts +7 -0
- package/dist/services/order-status.service-Cn7dsaJo.cjs +26 -0
- package/dist/services/order-status.service-MC9hVpP-.js +23 -0
- package/dist/services/order-status.service.d.cts +16 -0
- package/dist/services/order-status.service.d.ts +16 -0
- package/dist/services/page.service-CWhWCjMQ.js +7 -0
- package/dist/services/page.service-DmCSeMiR.cjs +7 -0
- package/dist/services/page.service.d.cts +4 -0
- package/dist/services/page.service.d.ts +4 -0
- package/dist/services/payment-method.service-CEt_nB4R.cjs +7 -0
- package/dist/services/payment-method.service-CjKbAsOh.js +7 -0
- package/dist/services/payment-method.service.d.cts +4 -0
- package/dist/services/payment-method.service.d.ts +4 -0
- package/dist/services/product.service-B05Qmbuh.js +35 -0
- package/dist/services/product.service-B7OFZWB1.cjs +37 -0
- package/dist/services/product.service.d.cts +231 -0
- package/dist/services/product.service.d.ts +231 -0
- package/dist/services/review.service-CO2icjpu.cjs +46 -0
- package/dist/services/review.service-De1YkhFp.js +43 -0
- package/dist/services/review.service.d.cts +28 -0
- package/dist/services/review.service.d.ts +28 -0
- package/dist/services/search.service-Bx1zbTHJ.cjs +10 -0
- package/dist/services/search.service-DSBMhaSY.js +10 -0
- package/dist/services/search.service.d.cts +9 -0
- package/dist/services/search.service.d.ts +9 -0
- package/dist/services/seller.service-D11WHhbC.cjs +10 -0
- package/dist/services/seller.service-DUptDTv4.js +9 -0
- package/dist/services/seller.service.d.cts +42 -0
- package/dist/services/seller.service.d.ts +42 -0
- package/dist/services/tracking.service-CPK1B69N.js +11 -0
- package/dist/services/tracking.service-DqOoi8qr.cjs +11 -0
- package/dist/services/tracking.service.d.cts +7 -0
- package/dist/services/tracking.service.d.ts +7 -0
- package/dist/services/url.service-B-nC14Ue.cjs +19 -0
- package/dist/services/url.service-CLW0Tc7S.js +18 -0
- package/dist/storefront-cache-revision.cjs +23 -0
- package/dist/storefront-cache-revision.d.cts +16 -0
- package/dist/storefront-cache-revision.d.ts +16 -0
- package/dist/storefront-cache-revision.js +17 -0
- package/dist/storefront-routes.cjs +14 -0
- package/dist/storefront-routes.d.cts +11 -0
- package/dist/storefront-routes.d.ts +11 -0
- package/dist/storefront-routes.js +12 -0
- package/dist/utils-CDEC5xcY.cjs +139 -0
- package/dist/utils-DK7qa54o.js +136 -0
- package/dist/utils.d.cts +3 -0
- package/dist/utils.d.ts +3 -0
- package/dist/video-links-CbRO0m8V.js +47 -0
- package/dist/video-links-ClryQjPH.cjs +47 -0
- package/dist/video-links.d.cts +7 -0
- package/dist/video-links.d.ts +7 -0
- package/package.json +28 -11
- package/dist/api.cjs.map +0 -1
- package/dist/api.js.map +0 -1
- package/dist/client-4ZTG2RZ3.d.ts +0 -195
- package/dist/client-BpX4yR6S.d.cts +0 -195
- package/dist/client.cjs.map +0 -1
- package/dist/client.js.map +0 -1
- package/dist/index.cjs.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/models/collections.cjs.map +0 -1
- package/dist/models/collections.js.map +0 -1
- package/dist/models/customer-address.cjs.map +0 -1
- package/dist/models/customer-address.js.map +0 -1
- package/dist/models/customer-order.cjs.map +0 -1
- package/dist/models/customer-order.js.map +0 -1
- package/dist/models/customer-profile.cjs.map +0 -1
- package/dist/models/customer-profile.js.map +0 -1
- package/dist/models/geo.cjs.map +0 -1
- package/dist/models/geo.js.map +0 -1
- package/dist/models/ids.cjs.map +0 -1
- package/dist/models/ids.js.map +0 -1
- package/dist/models/products.cjs.map +0 -1
- package/dist/models/products.js.map +0 -1
- package/dist/models/search.cjs.map +0 -1
- package/dist/models/search.js.map +0 -1
- package/dist/models/settings.cjs.map +0 -1
- package/dist/models/settings.js.map +0 -1
- package/dist/models/storefront-cart.cjs.map +0 -1
- package/dist/models/storefront-cart.js.map +0 -1
- package/dist/models/storefront-checkout.cjs.map +0 -1
- package/dist/models/storefront-checkout.js.map +0 -1
- package/dist/models/storefront-reviews.cjs.map +0 -1
- package/dist/models/storefront-reviews.js.map +0 -1
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
// src/storefront-cache-revision.ts
|
|
3
|
+
const STOREFRONT_CACHE_REVISION_HEADER = "x-ecomiq-cache-revision";
|
|
4
|
+
const STOREFRONT_CACHE_TTL_SECONDS = 30;
|
|
5
|
+
const StorefrontCacheRevisionSchema = z.string().regex(/^[1-9]\d{0,18}$/);
|
|
6
|
+
const StorefrontCacheRevisionDocumentSchema = z.object({
|
|
7
|
+
schemaVersion: z.literal(1),
|
|
8
|
+
storeId: z.string().regex(/^[1-9]\d{0,18}$/),
|
|
9
|
+
revision: StorefrontCacheRevisionSchema
|
|
10
|
+
}).strict();
|
|
11
|
+
const StorefrontCacheTokenSchema = z.string().regex(/^[1-9]\d{0,18}\.(?:0|[1-9]\d{0,11})$/);
|
|
12
|
+
function storefrontCacheToken({ storeId, revision, now }) {
|
|
13
|
+
const windowMs = 3e4;
|
|
14
|
+
const offsetMs = Number(BigInt(storeId) % BigInt(windowMs));
|
|
15
|
+
return `${revision}.${Math.floor((now + offsetMs) / windowMs)}`;
|
|
16
|
+
}
|
|
17
|
+
export { STOREFRONT_CACHE_REVISION_HEADER, STOREFRONT_CACHE_TTL_SECONDS, StorefrontCacheRevisionDocumentSchema, StorefrontCacheRevisionSchema, StorefrontCacheTokenSchema, storefrontCacheToken };
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
let zod = require("zod");
|
|
3
|
+
// src/storefront-routes.ts
|
|
4
|
+
const StorefrontHostnameSchema = zod.z.string().transform((value) => value.trim().toLowerCase().replace(/\.$/, "")).pipe(zod.z.string().max(253).regex(/^[a-z0-9](?:[a-z0-9.-]*[a-z0-9])?$/).refine((value) => !value.includes("..")));
|
|
5
|
+
/** Published domain mapping consumed by the dispatcher and storefront tools. */
|
|
6
|
+
const StorefrontRouteDocumentSchema = zod.z.object({
|
|
7
|
+
schemaVersion: zod.z.literal(1),
|
|
8
|
+
slug: zod.z.string().min(2).max(100).regex(/^[a-z0-9]+(?:-[a-z0-9]+)*$/),
|
|
9
|
+
hostname: StorefrontHostnameSchema,
|
|
10
|
+
primaryHostname: StorefrontHostnameSchema,
|
|
11
|
+
storeId: zod.z.string().regex(/^[1-9]\d{0,19}$/)
|
|
12
|
+
});
|
|
13
|
+
exports.StorefrontHostnameSchema = StorefrontHostnameSchema;
|
|
14
|
+
exports.StorefrontRouteDocumentSchema = StorefrontRouteDocumentSchema;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export declare const StorefrontHostnameSchema: z.ZodPipe<z.ZodPipe<z.ZodString, z.ZodTransform<string, string>>, z.ZodString>;
|
|
3
|
+
/** Published domain mapping consumed by the dispatcher and storefront tools. */
|
|
4
|
+
export declare const StorefrontRouteDocumentSchema: z.ZodObject<{
|
|
5
|
+
schemaVersion: z.ZodLiteral<1>;
|
|
6
|
+
slug: z.ZodString;
|
|
7
|
+
hostname: z.ZodPipe<z.ZodPipe<z.ZodString, z.ZodTransform<string, string>>, z.ZodString>;
|
|
8
|
+
primaryHostname: z.ZodPipe<z.ZodPipe<z.ZodString, z.ZodTransform<string, string>>, z.ZodString>;
|
|
9
|
+
storeId: z.ZodString;
|
|
10
|
+
}, z.core.$strip>;
|
|
11
|
+
export type StorefrontRouteDocument = z.infer<typeof StorefrontRouteDocumentSchema>;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export declare const StorefrontHostnameSchema: z.ZodPipe<z.ZodPipe<z.ZodString, z.ZodTransform<string, string>>, z.ZodString>;
|
|
3
|
+
/** Published domain mapping consumed by the dispatcher and storefront tools. */
|
|
4
|
+
export declare const StorefrontRouteDocumentSchema: z.ZodObject<{
|
|
5
|
+
schemaVersion: z.ZodLiteral<1>;
|
|
6
|
+
slug: z.ZodString;
|
|
7
|
+
hostname: z.ZodPipe<z.ZodPipe<z.ZodString, z.ZodTransform<string, string>>, z.ZodString>;
|
|
8
|
+
primaryHostname: z.ZodPipe<z.ZodPipe<z.ZodString, z.ZodTransform<string, string>>, z.ZodString>;
|
|
9
|
+
storeId: z.ZodString;
|
|
10
|
+
}, z.core.$strip>;
|
|
11
|
+
export type StorefrontRouteDocument = z.infer<typeof StorefrontRouteDocumentSchema>;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
// src/storefront-routes.ts
|
|
3
|
+
const StorefrontHostnameSchema = z.string().transform((value) => value.trim().toLowerCase().replace(/\.$/, "")).pipe(z.string().max(253).regex(/^[a-z0-9](?:[a-z0-9.-]*[a-z0-9])?$/).refine((value) => !value.includes("..")));
|
|
4
|
+
/** Published domain mapping consumed by the dispatcher and storefront tools. */
|
|
5
|
+
const StorefrontRouteDocumentSchema = z.object({
|
|
6
|
+
schemaVersion: z.literal(1),
|
|
7
|
+
slug: z.string().min(2).max(100).regex(/^[a-z0-9]+(?:-[a-z0-9]+)*$/),
|
|
8
|
+
hostname: StorefrontHostnameSchema,
|
|
9
|
+
primaryHostname: StorefrontHostnameSchema,
|
|
10
|
+
storeId: z.string().regex(/^[1-9]\d{0,19}$/)
|
|
11
|
+
});
|
|
12
|
+
export { StorefrontHostnameSchema, StorefrontRouteDocumentSchema };
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
const require_runtime = require("./_virtual/_rolldown/runtime-C6LprzCP.cjs");
|
|
2
|
+
let sanitize_html = require("sanitize-html");
|
|
3
|
+
sanitize_html = require_runtime.__toESM(sanitize_html, 1);
|
|
4
|
+
// src/utils.ts
|
|
5
|
+
const STOREFRONT_HTML_ALLOWLIST = {
|
|
6
|
+
allowedTags: [
|
|
7
|
+
"a",
|
|
8
|
+
"b",
|
|
9
|
+
"blockquote",
|
|
10
|
+
"br",
|
|
11
|
+
"code",
|
|
12
|
+
"col",
|
|
13
|
+
"colgroup",
|
|
14
|
+
"div",
|
|
15
|
+
"em",
|
|
16
|
+
"figcaption",
|
|
17
|
+
"figure",
|
|
18
|
+
"h1",
|
|
19
|
+
"h2",
|
|
20
|
+
"h3",
|
|
21
|
+
"h4",
|
|
22
|
+
"h5",
|
|
23
|
+
"h6",
|
|
24
|
+
"hr",
|
|
25
|
+
"i",
|
|
26
|
+
"img",
|
|
27
|
+
"li",
|
|
28
|
+
"ol",
|
|
29
|
+
"p",
|
|
30
|
+
"pre",
|
|
31
|
+
"s",
|
|
32
|
+
"small",
|
|
33
|
+
"span",
|
|
34
|
+
"strong",
|
|
35
|
+
"sub",
|
|
36
|
+
"sup",
|
|
37
|
+
"table",
|
|
38
|
+
"tbody",
|
|
39
|
+
"td",
|
|
40
|
+
"tfoot",
|
|
41
|
+
"th",
|
|
42
|
+
"thead",
|
|
43
|
+
"tr",
|
|
44
|
+
"u",
|
|
45
|
+
"ul",
|
|
46
|
+
"video",
|
|
47
|
+
"iframe"
|
|
48
|
+
],
|
|
49
|
+
allowedAttributes: {
|
|
50
|
+
a: [
|
|
51
|
+
"href",
|
|
52
|
+
"rel",
|
|
53
|
+
"target",
|
|
54
|
+
"title"
|
|
55
|
+
],
|
|
56
|
+
video: [
|
|
57
|
+
"controls",
|
|
58
|
+
"height",
|
|
59
|
+
"loop",
|
|
60
|
+
"muted",
|
|
61
|
+
"playsinline",
|
|
62
|
+
"poster",
|
|
63
|
+
"preload",
|
|
64
|
+
"src",
|
|
65
|
+
"title",
|
|
66
|
+
"width"
|
|
67
|
+
],
|
|
68
|
+
iframe: [
|
|
69
|
+
"allow",
|
|
70
|
+
"allowfullscreen",
|
|
71
|
+
"height",
|
|
72
|
+
"loading",
|
|
73
|
+
"src",
|
|
74
|
+
"title",
|
|
75
|
+
"width"
|
|
76
|
+
],
|
|
77
|
+
col: ["span"],
|
|
78
|
+
img: [
|
|
79
|
+
"alt",
|
|
80
|
+
"height",
|
|
81
|
+
"loading",
|
|
82
|
+
"src",
|
|
83
|
+
"title",
|
|
84
|
+
"width"
|
|
85
|
+
],
|
|
86
|
+
td: ["colspan", "rowspan"],
|
|
87
|
+
th: [
|
|
88
|
+
"colspan",
|
|
89
|
+
"rowspan",
|
|
90
|
+
"scope"
|
|
91
|
+
]
|
|
92
|
+
},
|
|
93
|
+
allowedIframeHostnames: [
|
|
94
|
+
"www.youtube.com",
|
|
95
|
+
"www.youtube-nocookie.com",
|
|
96
|
+
"player.vimeo.com"
|
|
97
|
+
],
|
|
98
|
+
allowedSchemes: [
|
|
99
|
+
"http",
|
|
100
|
+
"https",
|
|
101
|
+
"mailto",
|
|
102
|
+
"tel"
|
|
103
|
+
],
|
|
104
|
+
allowedSchemesAppliedToAttributes: [
|
|
105
|
+
"href",
|
|
106
|
+
"src",
|
|
107
|
+
"poster"
|
|
108
|
+
],
|
|
109
|
+
allowProtocolRelative: false,
|
|
110
|
+
disallowedTagsMode: "discard",
|
|
111
|
+
enforceHtmlBoundary: true,
|
|
112
|
+
parseStyleAttributes: false,
|
|
113
|
+
exclusiveFilter: (frame) => frame.tag === "iframe" && frame.attribs.src === void 0,
|
|
114
|
+
transformTags: {
|
|
115
|
+
a: (tagName, attributes) => {
|
|
116
|
+
if (attributes.target !== "_blank") return {
|
|
117
|
+
tagName,
|
|
118
|
+
attribs: attributes
|
|
119
|
+
};
|
|
120
|
+
return {
|
|
121
|
+
tagName,
|
|
122
|
+
attribs: {
|
|
123
|
+
...attributes,
|
|
124
|
+
rel: "noopener noreferrer"
|
|
125
|
+
}
|
|
126
|
+
};
|
|
127
|
+
},
|
|
128
|
+
h1: "h2"
|
|
129
|
+
}
|
|
130
|
+
};
|
|
131
|
+
function sanitizeHtml(html) {
|
|
132
|
+
return (0, sanitize_html.default)(html, STOREFRONT_HTML_ALLOWLIST);
|
|
133
|
+
}
|
|
134
|
+
/** Convierte HTML en texto plano (metadata, JSON-LD). */
|
|
135
|
+
function stripHtml(html) {
|
|
136
|
+
return html.replace(/<br\s*\/?>/gi, " ").replace(/<[^>]+>/g, " ").replace(/\s+/g, " ").trim();
|
|
137
|
+
}
|
|
138
|
+
exports.sanitizeHtml = sanitizeHtml;
|
|
139
|
+
exports.stripHtml = stripHtml;
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import sanitize from "sanitize-html";
|
|
2
|
+
// src/utils.ts
|
|
3
|
+
const STOREFRONT_HTML_ALLOWLIST = {
|
|
4
|
+
allowedTags: [
|
|
5
|
+
"a",
|
|
6
|
+
"b",
|
|
7
|
+
"blockquote",
|
|
8
|
+
"br",
|
|
9
|
+
"code",
|
|
10
|
+
"col",
|
|
11
|
+
"colgroup",
|
|
12
|
+
"div",
|
|
13
|
+
"em",
|
|
14
|
+
"figcaption",
|
|
15
|
+
"figure",
|
|
16
|
+
"h1",
|
|
17
|
+
"h2",
|
|
18
|
+
"h3",
|
|
19
|
+
"h4",
|
|
20
|
+
"h5",
|
|
21
|
+
"h6",
|
|
22
|
+
"hr",
|
|
23
|
+
"i",
|
|
24
|
+
"img",
|
|
25
|
+
"li",
|
|
26
|
+
"ol",
|
|
27
|
+
"p",
|
|
28
|
+
"pre",
|
|
29
|
+
"s",
|
|
30
|
+
"small",
|
|
31
|
+
"span",
|
|
32
|
+
"strong",
|
|
33
|
+
"sub",
|
|
34
|
+
"sup",
|
|
35
|
+
"table",
|
|
36
|
+
"tbody",
|
|
37
|
+
"td",
|
|
38
|
+
"tfoot",
|
|
39
|
+
"th",
|
|
40
|
+
"thead",
|
|
41
|
+
"tr",
|
|
42
|
+
"u",
|
|
43
|
+
"ul",
|
|
44
|
+
"video",
|
|
45
|
+
"iframe"
|
|
46
|
+
],
|
|
47
|
+
allowedAttributes: {
|
|
48
|
+
a: [
|
|
49
|
+
"href",
|
|
50
|
+
"rel",
|
|
51
|
+
"target",
|
|
52
|
+
"title"
|
|
53
|
+
],
|
|
54
|
+
video: [
|
|
55
|
+
"controls",
|
|
56
|
+
"height",
|
|
57
|
+
"loop",
|
|
58
|
+
"muted",
|
|
59
|
+
"playsinline",
|
|
60
|
+
"poster",
|
|
61
|
+
"preload",
|
|
62
|
+
"src",
|
|
63
|
+
"title",
|
|
64
|
+
"width"
|
|
65
|
+
],
|
|
66
|
+
iframe: [
|
|
67
|
+
"allow",
|
|
68
|
+
"allowfullscreen",
|
|
69
|
+
"height",
|
|
70
|
+
"loading",
|
|
71
|
+
"src",
|
|
72
|
+
"title",
|
|
73
|
+
"width"
|
|
74
|
+
],
|
|
75
|
+
col: ["span"],
|
|
76
|
+
img: [
|
|
77
|
+
"alt",
|
|
78
|
+
"height",
|
|
79
|
+
"loading",
|
|
80
|
+
"src",
|
|
81
|
+
"title",
|
|
82
|
+
"width"
|
|
83
|
+
],
|
|
84
|
+
td: ["colspan", "rowspan"],
|
|
85
|
+
th: [
|
|
86
|
+
"colspan",
|
|
87
|
+
"rowspan",
|
|
88
|
+
"scope"
|
|
89
|
+
]
|
|
90
|
+
},
|
|
91
|
+
allowedIframeHostnames: [
|
|
92
|
+
"www.youtube.com",
|
|
93
|
+
"www.youtube-nocookie.com",
|
|
94
|
+
"player.vimeo.com"
|
|
95
|
+
],
|
|
96
|
+
allowedSchemes: [
|
|
97
|
+
"http",
|
|
98
|
+
"https",
|
|
99
|
+
"mailto",
|
|
100
|
+
"tel"
|
|
101
|
+
],
|
|
102
|
+
allowedSchemesAppliedToAttributes: [
|
|
103
|
+
"href",
|
|
104
|
+
"src",
|
|
105
|
+
"poster"
|
|
106
|
+
],
|
|
107
|
+
allowProtocolRelative: false,
|
|
108
|
+
disallowedTagsMode: "discard",
|
|
109
|
+
enforceHtmlBoundary: true,
|
|
110
|
+
parseStyleAttributes: false,
|
|
111
|
+
exclusiveFilter: (frame) => frame.tag === "iframe" && frame.attribs.src === void 0,
|
|
112
|
+
transformTags: {
|
|
113
|
+
a: (tagName, attributes) => {
|
|
114
|
+
if (attributes.target !== "_blank") return {
|
|
115
|
+
tagName,
|
|
116
|
+
attribs: attributes
|
|
117
|
+
};
|
|
118
|
+
return {
|
|
119
|
+
tagName,
|
|
120
|
+
attribs: {
|
|
121
|
+
...attributes,
|
|
122
|
+
rel: "noopener noreferrer"
|
|
123
|
+
}
|
|
124
|
+
};
|
|
125
|
+
},
|
|
126
|
+
h1: "h2"
|
|
127
|
+
}
|
|
128
|
+
};
|
|
129
|
+
function sanitizeHtml(html) {
|
|
130
|
+
return sanitize(html, STOREFRONT_HTML_ALLOWLIST);
|
|
131
|
+
}
|
|
132
|
+
/** Convierte HTML en texto plano (metadata, JSON-LD). */
|
|
133
|
+
function stripHtml(html) {
|
|
134
|
+
return html.replace(/<br\s*\/?>/gi, " ").replace(/<[^>]+>/g, " ").replace(/\s+/g, " ").trim();
|
|
135
|
+
}
|
|
136
|
+
export { sanitizeHtml, stripHtml };
|
package/dist/utils.d.cts
ADDED
package/dist/utils.d.ts
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
// src/video-links.ts
|
|
2
|
+
const YOUTUBE_HOSTS = /* @__PURE__ */ new Set([
|
|
3
|
+
"youtube.com",
|
|
4
|
+
"www.youtube.com",
|
|
5
|
+
"m.youtube.com",
|
|
6
|
+
"youtu.be",
|
|
7
|
+
"youtube-nocookie.com",
|
|
8
|
+
"www.youtube-nocookie.com"
|
|
9
|
+
]);
|
|
10
|
+
const VIMEO_HOSTS = /* @__PURE__ */ new Set([
|
|
11
|
+
"vimeo.com",
|
|
12
|
+
"www.vimeo.com",
|
|
13
|
+
"player.vimeo.com"
|
|
14
|
+
]);
|
|
15
|
+
/** Enlaces de YouTube o Vimeo que se muestran como iframe en vez de <video>. */
|
|
16
|
+
function embeddedVideo(url) {
|
|
17
|
+
let parsed;
|
|
18
|
+
try {
|
|
19
|
+
parsed = new URL(url);
|
|
20
|
+
} catch {
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
const host = parsed.hostname.toLowerCase();
|
|
24
|
+
if (YOUTUBE_HOSTS.has(host)) {
|
|
25
|
+
let id = "";
|
|
26
|
+
if (host === "youtu.be") id = parsed.pathname.slice(1).split("/")[0] ?? "";
|
|
27
|
+
else if (parsed.pathname.startsWith("/watch")) id = parsed.searchParams.get("v") ?? "";
|
|
28
|
+
else id = parsed.pathname.match(/^\/(?:embed|shorts|live|v)\/([^/?]+)/)?.[1] ?? "";
|
|
29
|
+
if (!/^[A-Za-z0-9_-]{6,}$/.test(id)) return null;
|
|
30
|
+
return {
|
|
31
|
+
provider: "youtube",
|
|
32
|
+
embedUrl: `https://www.youtube-nocookie.com/embed/${id}`,
|
|
33
|
+
thumbnailUrl: `https://img.youtube.com/vi/${id}/hqdefault.jpg`
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
if (VIMEO_HOSTS.has(host)) {
|
|
37
|
+
const id = parsed.pathname.match(/(\d{5,})/)?.[1];
|
|
38
|
+
if (!id) return null;
|
|
39
|
+
return {
|
|
40
|
+
provider: "vimeo",
|
|
41
|
+
embedUrl: `https://player.vimeo.com/video/${id}`,
|
|
42
|
+
thumbnailUrl: null
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
return null;
|
|
46
|
+
}
|
|
47
|
+
export { embeddedVideo };
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
// src/video-links.ts
|
|
2
|
+
const YOUTUBE_HOSTS = /* @__PURE__ */ new Set([
|
|
3
|
+
"youtube.com",
|
|
4
|
+
"www.youtube.com",
|
|
5
|
+
"m.youtube.com",
|
|
6
|
+
"youtu.be",
|
|
7
|
+
"youtube-nocookie.com",
|
|
8
|
+
"www.youtube-nocookie.com"
|
|
9
|
+
]);
|
|
10
|
+
const VIMEO_HOSTS = /* @__PURE__ */ new Set([
|
|
11
|
+
"vimeo.com",
|
|
12
|
+
"www.vimeo.com",
|
|
13
|
+
"player.vimeo.com"
|
|
14
|
+
]);
|
|
15
|
+
/** Enlaces de YouTube o Vimeo que se muestran como iframe en vez de <video>. */
|
|
16
|
+
function embeddedVideo(url) {
|
|
17
|
+
let parsed;
|
|
18
|
+
try {
|
|
19
|
+
parsed = new URL(url);
|
|
20
|
+
} catch {
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
const host = parsed.hostname.toLowerCase();
|
|
24
|
+
if (YOUTUBE_HOSTS.has(host)) {
|
|
25
|
+
let id = "";
|
|
26
|
+
if (host === "youtu.be") id = parsed.pathname.slice(1).split("/")[0] ?? "";
|
|
27
|
+
else if (parsed.pathname.startsWith("/watch")) id = parsed.searchParams.get("v") ?? "";
|
|
28
|
+
else id = parsed.pathname.match(/^\/(?:embed|shorts|live|v)\/([^/?]+)/)?.[1] ?? "";
|
|
29
|
+
if (!/^[A-Za-z0-9_-]{6,}$/.test(id)) return null;
|
|
30
|
+
return {
|
|
31
|
+
provider: "youtube",
|
|
32
|
+
embedUrl: `https://www.youtube-nocookie.com/embed/${id}`,
|
|
33
|
+
thumbnailUrl: `https://img.youtube.com/vi/${id}/hqdefault.jpg`
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
if (VIMEO_HOSTS.has(host)) {
|
|
37
|
+
const id = parsed.pathname.match(/(\d{5,})/)?.[1];
|
|
38
|
+
if (!id) return null;
|
|
39
|
+
return {
|
|
40
|
+
provider: "vimeo",
|
|
41
|
+
embedUrl: `https://player.vimeo.com/video/${id}`,
|
|
42
|
+
thumbnailUrl: null
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
return null;
|
|
46
|
+
}
|
|
47
|
+
exports.embeddedVideo = embeddedVideo;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export type EmbeddedVideo = {
|
|
2
|
+
provider: 'youtube' | 'vimeo';
|
|
3
|
+
embedUrl: string;
|
|
4
|
+
thumbnailUrl: string | null;
|
|
5
|
+
};
|
|
6
|
+
/** Enlaces de YouTube o Vimeo que se muestran como iframe en vez de <video>. */
|
|
7
|
+
export declare function embeddedVideo(url: string): EmbeddedVideo | null;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export type EmbeddedVideo = {
|
|
2
|
+
provider: 'youtube' | 'vimeo';
|
|
3
|
+
embedUrl: string;
|
|
4
|
+
thumbnailUrl: string | null;
|
|
5
|
+
};
|
|
6
|
+
/** Enlaces de YouTube o Vimeo que se muestran como iframe en vez de <video>. */
|
|
7
|
+
export declare function embeddedVideo(url: string): EmbeddedVideo | null;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ecomiq/core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "1.0.0",
|
|
4
4
|
"description": "Modelos, API client y schemas compartidos de Ecomiq",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -10,10 +10,7 @@
|
|
|
10
10
|
"url": "git+https://github.com/ecomiq/ecomiq-storefront.git",
|
|
11
11
|
"directory": "packages/ecomiq-core"
|
|
12
12
|
},
|
|
13
|
-
"homepage": "https://
|
|
14
|
-
"bugs": {
|
|
15
|
-
"url": "https://github.com/ecomiq/ecomiq-storefront/issues"
|
|
16
|
-
},
|
|
13
|
+
"homepage": "https://docs.ecomiq.pe/es/docs/storefront",
|
|
17
14
|
"keywords": [
|
|
18
15
|
"ecomiq",
|
|
19
16
|
"storefront",
|
|
@@ -26,6 +23,21 @@
|
|
|
26
23
|
"module": "./dist/index.js",
|
|
27
24
|
"types": "./dist/index.d.ts",
|
|
28
25
|
"exports": {
|
|
26
|
+
"./storefront-cache-revision": {
|
|
27
|
+
"types": "./dist/storefront-cache-revision.d.ts",
|
|
28
|
+
"import": "./dist/storefront-cache-revision.js",
|
|
29
|
+
"require": "./dist/storefront-cache-revision.cjs"
|
|
30
|
+
},
|
|
31
|
+
"./storefront-routes": {
|
|
32
|
+
"types": "./dist/storefront-routes.d.ts",
|
|
33
|
+
"import": "./dist/storefront-routes.js",
|
|
34
|
+
"require": "./dist/storefront-routes.cjs"
|
|
35
|
+
},
|
|
36
|
+
"./redirects": {
|
|
37
|
+
"types": "./dist/redirects.d.ts",
|
|
38
|
+
"import": "./dist/redirects.js",
|
|
39
|
+
"require": "./dist/redirects.cjs"
|
|
40
|
+
},
|
|
29
41
|
".": {
|
|
30
42
|
"types": "./dist/index.d.ts",
|
|
31
43
|
"import": "./dist/index.js",
|
|
@@ -86,6 +98,11 @@
|
|
|
86
98
|
"import": "./dist/models/geo.js",
|
|
87
99
|
"require": "./dist/models/geo.cjs"
|
|
88
100
|
},
|
|
101
|
+
"./models/sellers": {
|
|
102
|
+
"types": "./dist/models/sellers.d.ts",
|
|
103
|
+
"import": "./dist/models/sellers.js",
|
|
104
|
+
"require": "./dist/models/sellers.cjs"
|
|
105
|
+
},
|
|
89
106
|
"./models/customer-address": {
|
|
90
107
|
"types": "./dist/models/customer-address.d.ts",
|
|
91
108
|
"import": "./dist/models/customer-address.js",
|
|
@@ -112,17 +129,17 @@
|
|
|
112
129
|
"registry": "https://registry.npmjs.org/"
|
|
113
130
|
},
|
|
114
131
|
"dependencies": {
|
|
115
|
-
"sanitize-html": "^2.
|
|
116
|
-
"zod": "^
|
|
132
|
+
"sanitize-html": "^2.18.1",
|
|
133
|
+
"zod": "^4.6.6"
|
|
117
134
|
},
|
|
118
135
|
"devDependencies": {
|
|
119
136
|
"@types/sanitize-html": "^2.16.1",
|
|
120
|
-
"
|
|
121
|
-
"typescript": "^
|
|
137
|
+
"tsdown": "^0.23.0",
|
|
138
|
+
"typescript": "^7.0.2"
|
|
122
139
|
},
|
|
123
140
|
"scripts": {
|
|
124
|
-
"build": "
|
|
125
|
-
"dev": "
|
|
141
|
+
"build": "tsdown",
|
|
142
|
+
"dev": "tsdown --watch",
|
|
126
143
|
"typecheck": "tsc --noEmit -p tsconfig.json"
|
|
127
144
|
}
|
|
128
145
|
}
|
package/dist/api.cjs.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/libs/api.ts"],"names":["bodyText"],"mappings":"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","file":"api.cjs","sourcesContent":["/**\n * Cliente HTTP de Ecomiq para servicios externos.\n * fetch nativo (funciona en Node, navegador y Cloudflare Workers)\n * + validación de respuestas con Zod.\n */\nimport type { z } from 'zod'\n\nexport const DEFAULT_API_BASE_URL = 'https://storefront.ecomiq.pe'\nexport const DEFAULT_API_VERSION = 'v1'\n\nexport class ApiError extends Error {\n constructor(\n message: string,\n public readonly status: number,\n public readonly url: string,\n public readonly body?: unknown,\n ) {\n super(message)\n this.name = 'ApiError'\n }\n}\n\nexport interface CreateApiOptions {\n /** Default: https://storefront.ecomiq.pe */\n baseUrl?: string\n /** Segmento de path, default 'v1' → {baseUrl}/v1/... */\n version?: string\n headers?: Record<string, string>\n timeoutMs?: number\n}\n\ninterface RequestOptions {\n query?: Record<string, string | number | boolean | undefined>\n headers?: Record<string, string>\n signal?: AbortSignal\n}\n\nexport interface Api {\n get<S extends z.ZodTypeAny>(\n path: string,\n schema: S,\n options?: RequestOptions,\n ): Promise<z.output<S>>\n post<S extends z.ZodTypeAny>(\n path: string,\n body: unknown,\n schema: S,\n options?: RequestOptions,\n ): Promise<z.output<S>>\n /** POST multipart; no fuerza `content-type: application/json`. */\n postForm<S extends z.ZodTypeAny>(\n path: string,\n body: FormData,\n schema: S,\n options?: RequestOptions,\n ): Promise<z.output<S>>\n request<S extends z.ZodTypeAny>(\n method: string,\n path: string,\n schema: S,\n options?: RequestOptions & { body?: unknown },\n ): Promise<z.output<S>>\n}\n\n/** Une baseUrl + version en la base efectiva del cliente, ej. https://storefront.ecomiq.pe/v1/ */\nexport function resolveApiBaseUrl(\n baseUrl: string = DEFAULT_API_BASE_URL,\n version: string = DEFAULT_API_VERSION,\n): string {\n const root = baseUrl.endsWith('/') ? baseUrl : `${baseUrl}/`\n const segment = version.replace(/^\\/+|\\/+$/g, '')\n // Sin segmento: conservar la base tal cual (p. ej. BFF `/api/` same-origin).\n // `new URL('/', root)` reemplazaría el pathname entero.\n if (!segment) return root\n return new URL(`${segment}/`, root).toString()\n}\n\n/**\n * Crea un cliente HTTP tipado con Zod.\n *\n * ```ts\n * const api = createApi()\n * const data = await api.get('settings', schema)\n * // → GET https://storefront.ecomiq.pe/v1/settings\n * ```\n */\nexport function createApi(options: CreateApiOptions = {}): Api {\n const {\n baseUrl = DEFAULT_API_BASE_URL,\n version = DEFAULT_API_VERSION,\n headers: baseHeaders = {},\n timeoutMs = 10_000,\n } = options\n\n const effectiveBaseUrl = resolveApiBaseUrl(baseUrl, version)\n\n async function request<S extends z.ZodTypeAny>(\n method: string,\n path: string,\n schema: S,\n opts: RequestOptions & { body?: unknown } = {},\n ): Promise<z.output<S>> {\n const url = new URL(path.replace(/^\\//, ''), effectiveBaseUrl)\n for (const [key, value] of Object.entries(opts.query ?? {})) {\n if (value !== undefined) url.searchParams.set(key, String(value))\n }\n\n const controller = new AbortController()\n const timeout = setTimeout(() => controller.abort(), timeoutMs)\n if (opts.signal) opts.signal.addEventListener('abort', () => controller.abort(), { once: true })\n\n const isFormData =\n typeof FormData !== 'undefined' && opts.body instanceof FormData\n\n let response: Response\n try {\n response = await fetch(url.toString(), {\n method,\n headers: {\n accept: 'application/json',\n ...(opts.body !== undefined && !isFormData\n ? { 'content-type': 'application/json' }\n : {}),\n ...baseHeaders,\n ...opts.headers,\n },\n body:\n opts.body === undefined\n ? undefined\n : isFormData\n ? (opts.body as FormData)\n : JSON.stringify(opts.body),\n signal: controller.signal,\n })\n } catch (err) {\n throw new ApiError(\n err instanceof DOMException && err.name === 'AbortError'\n ? `Timeout tras ${timeoutMs}ms: ${url}`\n : `No se pudo conectar con ${url}`,\n 0,\n url.toString(),\n )\n } finally {\n clearTimeout(timeout)\n }\n\n if (!response.ok) {\n const bodyText = await response.text().catch(() => undefined)\n let body: unknown = bodyText\n if (bodyText) {\n try {\n body = JSON.parse(bodyText)\n } catch {}\n }\n throw new ApiError(`${method} ${url} → ${response.status}`, response.status, url.toString(), body)\n }\n\n const bodyText = await response.text()\n let json: unknown = null\n if (bodyText.trim()) {\n try {\n json = JSON.parse(bodyText)\n } catch {\n throw new ApiError(\n `Respuesta no JSON de ${url}`,\n response.status,\n url.toString(),\n bodyText,\n )\n }\n }\n\n const parsed = schema.safeParse(json)\n if (!parsed.success) {\n throw new ApiError(\n `Respuesta inesperada de ${url}: ${parsed.error.issues[0]?.path.join('.')} ${parsed.error.issues[0]?.message}`,\n response.status,\n url.toString(),\n json,\n )\n }\n return parsed.data as z.output<S>\n }\n\n return {\n request,\n get: (path, schema, opts) => request('GET', path, schema, opts),\n post: (path, body, schema, opts) => request('POST', path, schema, { ...opts, body }),\n postForm: (path, body, schema, opts) =>\n request('POST', path, schema, { ...opts, body }),\n }\n}\n"]}
|
package/dist/api.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/libs/api.ts"],"names":["bodyText"],"mappings":"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","file":"api.js","sourcesContent":["/**\n * Cliente HTTP de Ecomiq para servicios externos.\n * fetch nativo (funciona en Node, navegador y Cloudflare Workers)\n * + validación de respuestas con Zod.\n */\nimport type { z } from 'zod'\n\nexport const DEFAULT_API_BASE_URL = 'https://storefront.ecomiq.pe'\nexport const DEFAULT_API_VERSION = 'v1'\n\nexport class ApiError extends Error {\n constructor(\n message: string,\n public readonly status: number,\n public readonly url: string,\n public readonly body?: unknown,\n ) {\n super(message)\n this.name = 'ApiError'\n }\n}\n\nexport interface CreateApiOptions {\n /** Default: https://storefront.ecomiq.pe */\n baseUrl?: string\n /** Segmento de path, default 'v1' → {baseUrl}/v1/... */\n version?: string\n headers?: Record<string, string>\n timeoutMs?: number\n}\n\ninterface RequestOptions {\n query?: Record<string, string | number | boolean | undefined>\n headers?: Record<string, string>\n signal?: AbortSignal\n}\n\nexport interface Api {\n get<S extends z.ZodTypeAny>(\n path: string,\n schema: S,\n options?: RequestOptions,\n ): Promise<z.output<S>>\n post<S extends z.ZodTypeAny>(\n path: string,\n body: unknown,\n schema: S,\n options?: RequestOptions,\n ): Promise<z.output<S>>\n /** POST multipart; no fuerza `content-type: application/json`. */\n postForm<S extends z.ZodTypeAny>(\n path: string,\n body: FormData,\n schema: S,\n options?: RequestOptions,\n ): Promise<z.output<S>>\n request<S extends z.ZodTypeAny>(\n method: string,\n path: string,\n schema: S,\n options?: RequestOptions & { body?: unknown },\n ): Promise<z.output<S>>\n}\n\n/** Une baseUrl + version en la base efectiva del cliente, ej. https://storefront.ecomiq.pe/v1/ */\nexport function resolveApiBaseUrl(\n baseUrl: string = DEFAULT_API_BASE_URL,\n version: string = DEFAULT_API_VERSION,\n): string {\n const root = baseUrl.endsWith('/') ? baseUrl : `${baseUrl}/`\n const segment = version.replace(/^\\/+|\\/+$/g, '')\n // Sin segmento: conservar la base tal cual (p. ej. BFF `/api/` same-origin).\n // `new URL('/', root)` reemplazaría el pathname entero.\n if (!segment) return root\n return new URL(`${segment}/`, root).toString()\n}\n\n/**\n * Crea un cliente HTTP tipado con Zod.\n *\n * ```ts\n * const api = createApi()\n * const data = await api.get('settings', schema)\n * // → GET https://storefront.ecomiq.pe/v1/settings\n * ```\n */\nexport function createApi(options: CreateApiOptions = {}): Api {\n const {\n baseUrl = DEFAULT_API_BASE_URL,\n version = DEFAULT_API_VERSION,\n headers: baseHeaders = {},\n timeoutMs = 10_000,\n } = options\n\n const effectiveBaseUrl = resolveApiBaseUrl(baseUrl, version)\n\n async function request<S extends z.ZodTypeAny>(\n method: string,\n path: string,\n schema: S,\n opts: RequestOptions & { body?: unknown } = {},\n ): Promise<z.output<S>> {\n const url = new URL(path.replace(/^\\//, ''), effectiveBaseUrl)\n for (const [key, value] of Object.entries(opts.query ?? {})) {\n if (value !== undefined) url.searchParams.set(key, String(value))\n }\n\n const controller = new AbortController()\n const timeout = setTimeout(() => controller.abort(), timeoutMs)\n if (opts.signal) opts.signal.addEventListener('abort', () => controller.abort(), { once: true })\n\n const isFormData =\n typeof FormData !== 'undefined' && opts.body instanceof FormData\n\n let response: Response\n try {\n response = await fetch(url.toString(), {\n method,\n headers: {\n accept: 'application/json',\n ...(opts.body !== undefined && !isFormData\n ? { 'content-type': 'application/json' }\n : {}),\n ...baseHeaders,\n ...opts.headers,\n },\n body:\n opts.body === undefined\n ? undefined\n : isFormData\n ? (opts.body as FormData)\n : JSON.stringify(opts.body),\n signal: controller.signal,\n })\n } catch (err) {\n throw new ApiError(\n err instanceof DOMException && err.name === 'AbortError'\n ? `Timeout tras ${timeoutMs}ms: ${url}`\n : `No se pudo conectar con ${url}`,\n 0,\n url.toString(),\n )\n } finally {\n clearTimeout(timeout)\n }\n\n if (!response.ok) {\n const bodyText = await response.text().catch(() => undefined)\n let body: unknown = bodyText\n if (bodyText) {\n try {\n body = JSON.parse(bodyText)\n } catch {}\n }\n throw new ApiError(`${method} ${url} → ${response.status}`, response.status, url.toString(), body)\n }\n\n const bodyText = await response.text()\n let json: unknown = null\n if (bodyText.trim()) {\n try {\n json = JSON.parse(bodyText)\n } catch {\n throw new ApiError(\n `Respuesta no JSON de ${url}`,\n response.status,\n url.toString(),\n bodyText,\n )\n }\n }\n\n const parsed = schema.safeParse(json)\n if (!parsed.success) {\n throw new ApiError(\n `Respuesta inesperada de ${url}: ${parsed.error.issues[0]?.path.join('.')} ${parsed.error.issues[0]?.message}`,\n response.status,\n url.toString(),\n json,\n )\n }\n return parsed.data as z.output<S>\n }\n\n return {\n request,\n get: (path, schema, opts) => request('GET', path, schema, opts),\n post: (path, body, schema, opts) => request('POST', path, schema, { ...opts, body }),\n postForm: (path, body, schema, opts) =>\n request('POST', path, schema, { ...opts, body }),\n }\n}\n"]}
|