@hartl-services/medusa-base 0.4.0 → 1.1.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/.medusa/server/src/admin/index.js +1657 -111
- package/.medusa/server/src/admin/index.mjs +1647 -101
- package/.medusa/server/src/api/admin/email/messages/[id]/resends/route.js +24 -0
- package/.medusa/server/src/api/admin/email/messages/[id]/route.js +12 -0
- package/.medusa/server/src/api/admin/email/messages/route.js +12 -0
- package/.medusa/server/src/api/admin/email/terms-versions/[id]/download/route.js +16 -0
- package/.medusa/server/src/api/admin/email/terms-versions/route.js +47 -0
- package/.medusa/server/src/api/admin/orders/[id]/documents/[document_id]/download/route.js +21 -0
- package/.medusa/server/src/api/admin/orders/[id]/documents/[document_id]/regenerate/route.js +38 -0
- package/.medusa/server/src/api/admin/orders/[id]/documents/regenerate/route.js +32 -0
- package/.medusa/server/src/api/admin/orders/[id]/documents/route.js +36 -0
- package/.medusa/server/src/api/admin/orders/[id]/packing-lists/[fulfillment_id]/download/route.js +24 -0
- package/.medusa/server/src/api/admin/orders/[id]/packing-lists/[fulfillment_id]/retry/route.js +44 -0
- package/.medusa/server/src/api/admin/orders/[id]/packing-lists/route.js +82 -0
- package/.medusa/server/src/api/document-download-response.js +16 -0
- package/.medusa/server/src/api/document-response.js +23 -0
- package/.medusa/server/src/api/files/[asset]/route.js +24 -0
- package/.medusa/server/src/api/files/file-response.js +43 -0
- package/.medusa/server/src/api/files/gateway-options.js +31 -0
- package/.medusa/server/src/api/files/private/[token]/route.js +29 -0
- package/.medusa/server/src/api/files/upload/[token]/route.js +66 -0
- package/.medusa/server/src/api/middlewares.js +168 -1
- package/.medusa/server/src/api/packing-list-response.js +22 -0
- package/.medusa/server/src/api/route.js +27 -0
- package/.medusa/server/src/api/store/documents/[id]/download/route.js +21 -0
- package/.medusa/server/src/api/store/documents/[id]/route.js +15 -0
- package/.medusa/server/src/api/store/documents/route.js +11 -0
- package/.medusa/server/src/api/terms-download-response.js +12 -0
- package/.medusa/server/src/documents/config/index.js +18 -0
- package/.medusa/server/src/documents/paths/documents.js +6 -0
- package/.medusa/server/src/documents/paths/index.js +18 -0
- package/.medusa/server/src/documents/plugin-features.js +38 -0
- package/.medusa/server/src/documents/schemas/documents.js +18 -0
- package/.medusa/server/src/documents/schemas/index.js +18 -0
- package/.medusa/server/src/documents/scripts/verify-documents-file-storage.js +55 -0
- package/.medusa/server/src/documents/templates/financial-document.js +160 -0
- package/.medusa/server/src/documents/templates/format.js +73 -0
- package/.medusa/server/src/documents/templates/html-factory.js +42 -0
- package/.medusa/server/src/documents/templates/html-utils.js +23 -0
- package/.medusa/server/src/documents/templates/layout.js +142 -0
- package/.medusa/server/src/documents/templates/packing-list.js +52 -0
- package/.medusa/server/src/documents/types/admin-api.js +3 -0
- package/.medusa/server/src/documents/types/document-summary.js +3 -0
- package/.medusa/server/src/documents/types/documents.js +3 -0
- package/.medusa/server/src/documents/types/html-factory.js +6 -0
- package/.medusa/server/src/documents/types/index.js +22 -0
- package/.medusa/server/src/documents/types/store-api.js +3 -0
- package/.medusa/server/src/documents/utils/document-merchant.js +22 -0
- package/.medusa/server/src/documents/utils/document-render-settings.js +59 -0
- package/.medusa/server/src/documents/utils/html-to-pdf.js +61 -0
- package/.medusa/server/src/documents/utils/private-file-storage.js +64 -0
- package/.medusa/server/src/documents/utils/resolve-services.js +7 -0
- package/.medusa/server/src/email/application/handle-invite-event.js +318 -0
- package/.medusa/server/src/email/application/handle-password-reset-event.js +366 -0
- package/.medusa/server/src/email/config/index.js +84 -0
- package/.medusa/server/src/email/config/notification-module.js +20 -0
- package/.medusa/server/src/email/domain/business-keys.js +50 -0
- package/.medusa/server/src/email/domain/documents-fact-fingerprint.js +7 -0
- package/.medusa/server/src/email/domain/event-schemas.js +36 -0
- package/.medusa/server/src/email/domain/failure-classification.js +53 -0
- package/.medusa/server/src/email/domain/order-summary.js +103 -0
- package/.medusa/server/src/email/domain/refund-summary.js +43 -0
- package/.medusa/server/src/email/domain/return-summary.js +118 -0
- package/.medusa/server/src/email/domain/shipment-summary.js +74 -0
- package/.medusa/server/src/email/plugin-features.js +39 -0
- package/.medusa/server/src/email/rendering/default-templates.js +719 -0
- package/.medusa/server/src/email/rendering/load-email-shop-details.js +36 -0
- package/.medusa/server/src/email/rendering/render-email.js +50 -0
- package/.medusa/server/src/email/rendering/resolve-shop-configuration.js +67 -0
- package/.medusa/server/src/email/types/email-kinds.js +18 -0
- package/.medusa/server/src/email/types/index.js +21 -0
- package/.medusa/server/src/email/types/shop-configuration.js +3 -0
- package/.medusa/server/src/email/types/smtp-configuration.js +3 -0
- package/.medusa/server/src/email/types/template-data.js +232 -0
- package/.medusa/server/src/files/config/index.js +256 -0
- package/.medusa/server/src/files/gateway/index.js +115 -0
- package/.medusa/server/src/files/types/index.js +6 -0
- package/.medusa/server/src/files/types/public.js +6 -0
- package/.medusa/server/src/jobs/document-fact-publication-reconciliation.js +18 -0
- package/.medusa/server/src/jobs/document-resolution-reconciliation.js +20 -0
- package/.medusa/server/src/jobs/packing-list-reconciliation.js +49 -0
- package/.medusa/server/src/jobs/reconcile-email-attempts.js +63 -0
- package/.medusa/server/src/jobs/reconcile-pending-email-messages.js +41 -0
- package/.medusa/server/src/jobs/retry-email-messages.js +27 -0
- package/.medusa/server/src/migration-scripts/dismiss-orphaned-cart-promotion-links.js +26 -0
- package/.medusa/server/src/modules/documents/domain/cancellation-snapshot.js +97 -0
- package/.medusa/server/src/modules/documents/domain/document-number.js +36 -0
- package/.medusa/server/src/modules/documents/domain/document-resolution.js +24 -0
- package/.medusa/server/src/modules/documents/domain/issuance-rules.js +37 -0
- package/.medusa/server/src/modules/documents/domain/merchant.js +86 -0
- package/.medusa/server/src/modules/documents/domain/options.js +40 -0
- package/.medusa/server/src/modules/documents/domain/packing-list.js +90 -0
- package/.medusa/server/src/modules/documents/domain/snapshot-normalization.js +17 -0
- package/.medusa/server/src/modules/documents/domain/tax-breakdown.js +66 -0
- package/.medusa/server/src/modules/documents/index.js +15 -0
- package/.medusa/server/src/modules/documents/loaders/assert-private-file-storage.js +20 -0
- package/.medusa/server/src/modules/documents/migrations/Migration20260827061749.js +75 -0
- package/.medusa/server/src/modules/documents/migrations/Migration20260830111207.js +28 -0
- package/.medusa/server/src/modules/documents/models/document-artifact.js +25 -0
- package/.medusa/server/src/modules/documents/models/document-number-sequence.js +29 -0
- package/.medusa/server/src/modules/documents/models/document.js +82 -0
- package/.medusa/server/src/modules/documents/models/order-cancellation-resolution.js +51 -0
- package/.medusa/server/src/modules/documents/models/packing-list-revision.js +36 -0
- package/.medusa/server/src/modules/documents/models/packing-list.js +27 -0
- package/.medusa/server/src/modules/documents/models/refund-document-resolution.js +66 -0
- package/.medusa/server/src/modules/documents/models/shipment-invoice-assignment.js +51 -0
- package/.medusa/server/src/modules/documents/models/shipment-invoice-coordinator.js +44 -0
- package/.medusa/server/src/modules/documents/service.js +1701 -0
- package/.medusa/server/src/modules/email/domain/attachment.js +25 -0
- package/.medusa/server/src/modules/email/domain/message-state.js +69 -0
- package/.medusa/server/src/modules/email/index.js +13 -0
- package/.medusa/server/src/modules/email/migrations/Migration20260826173422.js +32 -0
- package/.medusa/server/src/modules/email/migrations/Migration20260827172945.js +16 -0
- package/.medusa/server/src/modules/email/migrations/Migration20260827194804.js +22 -0
- package/.medusa/server/src/modules/email/migrations/Migration20260906195205.js +16 -0
- package/.medusa/server/src/modules/email/models/email-attempt.js +56 -0
- package/.medusa/server/src/modules/email/models/email-message.js +71 -0
- package/.medusa/server/src/modules/email/models/email-terms-version.js +37 -0
- package/.medusa/server/src/modules/email/service.js +1285 -0
- package/.medusa/server/src/modules/plugin-features/domain/plugin-settings.js +4 -3
- package/.medusa/server/src/providers/s3-cache/cache/atomic-write.js +25 -0
- package/.medusa/server/src/providers/s3-cache/cache/cache-manager.js +115 -0
- package/.medusa/server/src/providers/s3-cache/cache/keyed-lock.js +28 -0
- package/.medusa/server/src/providers/s3-cache/index.js +8 -0
- package/.medusa/server/src/providers/s3-cache/object-key.js +53 -0
- package/.medusa/server/src/providers/s3-cache/s3-cache-file.js +229 -0
- package/.medusa/server/src/providers/s3-cache/s3-object-store.js +86 -0
- package/.medusa/server/src/providers/smtp/index.js +8 -0
- package/.medusa/server/src/providers/smtp/service.js +236 -0
- package/.medusa/server/src/providers/smtp/types.js +11 -0
- package/.medusa/server/src/public/config.js +186 -0
- package/.medusa/server/src/public/descriptor.js +3 -1
- package/.medusa/server/src/public/gateway.js +19 -0
- package/.medusa/server/src/public/instrumentation.js +56 -0
- package/.medusa/server/src/public/shop-config.js +12 -0
- package/.medusa/server/src/public/shop-master-data.js +2 -2
- package/.medusa/server/src/public/shop-types.js +24 -0
- package/.medusa/server/src/shop-config/build-food-shop-config.js +252 -0
- package/.medusa/server/src/shop-config/options.js +75 -0
- package/.medusa/server/src/subscribers/affiliate-consignment-reminder-due.js +26 -0
- package/.medusa/server/src/subscribers/documents-order-canceled.js +24 -0
- package/.medusa/server/src/subscribers/documents-order-cancellation-ready.js +26 -0
- package/.medusa/server/src/subscribers/documents-refund-ready.js +24 -0
- package/.medusa/server/src/subscribers/documents-shipment-created.js +36 -0
- package/.medusa/server/src/subscribers/documents-shipment-invoice-assignment-decided.js +26 -0
- package/.medusa/server/src/subscribers/email-order-canceled.js +28 -0
- package/.medusa/server/src/subscribers/email-shipment-created.js +32 -0
- package/.medusa/server/src/subscribers/order-placed.js +27 -0
- package/.medusa/server/src/subscribers/packing-list-allocation-revised.js +32 -0
- package/.medusa/server/src/subscribers/packing-list-fulfillment-canceled.js +54 -0
- package/.medusa/server/src/subscribers/packing-list-fulfillment-created.js +31 -0
- package/.medusa/server/src/subscribers/password-reset.js +23 -0
- package/.medusa/server/src/subscribers/payment-refunded.js +38 -0
- package/.medusa/server/src/subscribers/return-received.js +27 -0
- package/.medusa/server/src/subscribers/return-requested.js +27 -0
- package/.medusa/server/src/subscribers/user-invite.js +23 -0
- package/.medusa/server/src/utils/cart-promotion-links.js +101 -0
- package/.medusa/server/src/workflows/documents/issue-cancellation-after-refund.js +246 -0
- package/.medusa/server/src/workflows/documents/issue-document.js +165 -0
- package/.medusa/server/src/workflows/documents/issue-invoice-after-shipment.js +521 -0
- package/.medusa/server/src/workflows/documents/issue-packing-list.js +390 -0
- package/.medusa/server/src/workflows/documents/publish-document-facts.js +53 -0
- package/.medusa/server/src/workflows/documents/reconcile-document-resolutions.js +48 -0
- package/.medusa/server/src/workflows/documents/reconcile-order-cancellation.js +92 -0
- package/.medusa/server/src/workflows/documents/regenerate-issued-document.js +61 -0
- package/.medusa/server/src/workflows/email/dispatch-email-message.js +301 -0
- package/.medusa/server/src/workflows/email/documents-required-facts.js +30 -0
- package/.medusa/server/src/workflows/email/prepare-affiliate-reminder-email.js +58 -0
- package/.medusa/server/src/workflows/email/prepare-order-canceled-email.js +102 -0
- package/.medusa/server/src/workflows/email/prepare-order-received-email.js +82 -0
- package/.medusa/server/src/workflows/email/prepare-refund-email.js +71 -0
- package/.medusa/server/src/workflows/email/prepare-return-email.js +136 -0
- package/.medusa/server/src/workflows/email/prepare-shipment-email.js +115 -0
- package/.medusa/server/src/workflows/email/retry-email-messages.js +31 -0
- package/.medusa/server/src/workflows/hooks/dismiss-deleted-promotion-cart-links.js +23 -0
- package/README.md +1777 -8
- package/dist/admin-components/features/plugin-features/components/ImageSettingInput.d.ts +15 -0
- package/dist/admin-components/features/plugin-features/components/ImageSettingInput.js +42 -0
- package/dist/admin-components/features/plugin-features/components/PluginSettingsForm.js +4 -2
- package/dist/admin-components/features/plugin-features/hooks/usePluginFeatureEnabled.d.ts +1 -1
- package/dist/admin-components/features/plugin-features/hooks/usePluginFeatures.d.ts +4 -4
- package/dist/admin-components/features/plugin-features/hooks/usePluginSettingsForm.d.ts +1 -1
- package/dist/admin-components/features/plugin-features/lib/image-upload.d.ts +6 -0
- package/dist/admin-components/features/plugin-features/lib/image-upload.js +17 -0
- package/dist/admin-components/features/plugin-features/lib/plugin-features-admin-client.d.ts +4 -4
- package/dist/admin-components/i18n/texts.d.ts +6 -0
- package/dist/admin-components/i18n/texts.js +6 -0
- package/dist/documents/config/index.d.ts +11 -0
- package/dist/documents/config/index.js +17 -0
- package/dist/documents/templates/financial-document.d.ts +3 -0
- package/dist/documents/templates/financial-document.js +159 -0
- package/dist/documents/templates/format.d.ts +30 -0
- package/dist/documents/templates/format.js +72 -0
- package/dist/documents/templates/html-factory.d.ts +15 -0
- package/dist/documents/templates/html-factory.js +41 -0
- package/dist/documents/templates/html-utils.d.ts +8 -0
- package/dist/documents/templates/html-utils.js +22 -0
- package/dist/documents/templates/layout.d.ts +35 -0
- package/dist/documents/templates/layout.js +141 -0
- package/dist/documents/templates/packing-list.d.ts +3 -0
- package/dist/documents/templates/packing-list.js +51 -0
- package/dist/documents/types/admin-api.d.ts +1 -0
- package/dist/documents/types/admin-api.js +2 -0
- package/dist/documents/types/document-summary.d.ts +1 -0
- package/dist/documents/types/document-summary.js +2 -0
- package/dist/documents/types/documents.d.ts +191 -0
- package/dist/documents/types/documents.js +2 -0
- package/dist/documents/types/html-factory.d.ts +8 -0
- package/dist/documents/types/html-factory.js +5 -0
- package/dist/documents/types/index.d.ts +5 -0
- package/dist/documents/types/index.js +21 -0
- package/dist/documents/types/store-api.d.ts +1 -0
- package/dist/documents/types/store-api.js +2 -0
- package/dist/email/config/index.d.ts +17 -0
- package/dist/email/config/index.js +83 -0
- package/dist/email/config/notification-module.d.ts +22 -0
- package/dist/email/config/notification-module.js +19 -0
- package/dist/email/types/email-kinds.d.ts +15 -0
- package/dist/email/types/email-kinds.js +17 -0
- package/dist/email/types/index.d.ts +4 -0
- package/dist/email/types/index.js +20 -0
- package/dist/email/types/shop-configuration.d.ts +68 -0
- package/dist/email/types/shop-configuration.js +2 -0
- package/dist/email/types/smtp-configuration.d.ts +9 -0
- package/dist/email/types/smtp-configuration.js +2 -0
- package/dist/email/types/template-data.d.ts +609 -0
- package/dist/email/types/template-data.js +231 -0
- package/dist/files/config/index.d.ts +32 -0
- package/dist/files/config/index.js +255 -0
- package/dist/files/gateway/index.d.ts +30 -0
- package/dist/files/gateway/index.js +114 -0
- package/dist/files/types/index.d.ts +2 -0
- package/dist/files/types/index.js +5 -0
- package/dist/files/types/public.d.ts +90 -0
- package/dist/files/types/public.js +5 -0
- package/dist/modules/documents/domain/merchant.d.ts +22 -0
- package/dist/modules/documents/domain/merchant.js +85 -0
- package/dist/modules/documents/domain/options.d.ts +34 -0
- package/dist/modules/documents/domain/options.js +39 -0
- package/dist/public/config.d.ts +59 -0
- package/dist/public/config.js +185 -0
- package/dist/public/descriptor.js +2 -0
- package/dist/public/gateway.d.ts +2 -0
- package/dist/public/gateway.js +18 -0
- package/dist/public/instrumentation.d.ts +12 -0
- package/dist/public/instrumentation.js +55 -0
- package/dist/public/shop-config.d.ts +8 -0
- package/dist/public/shop-config.js +11 -0
- package/dist/public/shop-master-data.d.ts +1 -1
- package/dist/public/shop-master-data.js +1 -1
- package/dist/public/shop-types.d.ts +7 -0
- package/dist/public/shop-types.js +23 -0
- package/dist/public/types.d.ts +19 -2
- package/dist/shop-config/build-food-shop-config.d.ts +44 -0
- package/dist/shop-config/build-food-shop-config.js +251 -0
- package/dist/shop-config/options.d.ts +48 -0
- package/dist/shop-config/options.js +74 -0
- package/package.json +48 -5
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.EmailRenderDataSchemas = exports.EmailPersistedDataSchemas = exports.RefundSummarySchema = exports.ReturnReceivedSummarySchema = exports.ReturnSummarySchema = exports.ShipmentSummarySchema = exports.OrderSummarySchema = void 0;
|
|
4
|
+
const zod_1 = require("@medusajs/framework/zod");
|
|
5
|
+
const affiliate_1 = require("@hartl-services/medusa-food-supplements-contracts/schemas/affiliate");
|
|
6
|
+
const NonEmptyStringSchema = zod_1.z.string().trim().min(1);
|
|
7
|
+
const NullableLocaleSchema = NonEmptyStringSchema.max(35).nullable();
|
|
8
|
+
const DocumentsFactFingerprintSchema = zod_1.z
|
|
9
|
+
.string()
|
|
10
|
+
.regex(/^[a-f0-9]{64}$/)
|
|
11
|
+
.optional();
|
|
12
|
+
const AmountSchema = zod_1.z.string().regex(/^-?\d+(\.\d+)?$/);
|
|
13
|
+
const OptionalTextSchema = zod_1.z.string().nullable();
|
|
14
|
+
const OrderSummaryAddressSchema = zod_1.z
|
|
15
|
+
.object({
|
|
16
|
+
first_name: OptionalTextSchema,
|
|
17
|
+
last_name: OptionalTextSchema,
|
|
18
|
+
company: OptionalTextSchema,
|
|
19
|
+
address_1: OptionalTextSchema,
|
|
20
|
+
address_2: OptionalTextSchema,
|
|
21
|
+
postal_code: OptionalTextSchema,
|
|
22
|
+
city: OptionalTextSchema,
|
|
23
|
+
country_code: OptionalTextSchema,
|
|
24
|
+
})
|
|
25
|
+
.strict();
|
|
26
|
+
/**
|
|
27
|
+
* Snapshot of an order when it was placed. Amounts are Medusa's gross
|
|
28
|
+
* decimal strings: item and shipping rows before discounts, so
|
|
29
|
+
* `original_item_total + original_shipping_total - discount_total` is the
|
|
30
|
+
* `total`, which already contains `tax_total`.
|
|
31
|
+
*/
|
|
32
|
+
exports.OrderSummarySchema = zod_1.z
|
|
33
|
+
.object({
|
|
34
|
+
display_id: zod_1.z.number().int().nullable(),
|
|
35
|
+
/** The order's e-mail address; `null` when the order has none. */
|
|
36
|
+
email: OptionalTextSchema,
|
|
37
|
+
/** When the order was placed (ISO 8601). */
|
|
38
|
+
placed_at: zod_1.z.string().datetime(),
|
|
39
|
+
currency_code: NonEmptyStringSchema,
|
|
40
|
+
items: zod_1.z.array(zod_1.z
|
|
41
|
+
.object({
|
|
42
|
+
title: NonEmptyStringSchema,
|
|
43
|
+
variant_title: OptionalTextSchema,
|
|
44
|
+
quantity: zod_1.z.number().positive(),
|
|
45
|
+
original_total: AmountSchema,
|
|
46
|
+
})
|
|
47
|
+
.strict()),
|
|
48
|
+
shipping_method_names: zod_1.z.array(NonEmptyStringSchema),
|
|
49
|
+
original_item_total: AmountSchema,
|
|
50
|
+
original_shipping_total: AmountSchema,
|
|
51
|
+
discount_total: AmountSchema,
|
|
52
|
+
tax_total: AmountSchema,
|
|
53
|
+
total: AmountSchema,
|
|
54
|
+
billing_address: OrderSummaryAddressSchema.nullable(),
|
|
55
|
+
shipping_address: OrderSummaryAddressSchema.nullable(),
|
|
56
|
+
})
|
|
57
|
+
.strict();
|
|
58
|
+
/**
|
|
59
|
+
* Snapshot of one shipment when it was shipped: the parcel's items (title
|
|
60
|
+
* of the order line, shipped quantity), tracking numbers and links as
|
|
61
|
+
* entered at shipping, and whether more of the order is still to be shipped.
|
|
62
|
+
*/
|
|
63
|
+
exports.ShipmentSummarySchema = zod_1.z
|
|
64
|
+
.object({
|
|
65
|
+
display_id: zod_1.z.number().int().nullable(),
|
|
66
|
+
shipping_method_name: OptionalTextSchema,
|
|
67
|
+
tracking: zod_1.z.array(zod_1.z
|
|
68
|
+
.object({
|
|
69
|
+
number: OptionalTextSchema,
|
|
70
|
+
url: OptionalTextSchema,
|
|
71
|
+
})
|
|
72
|
+
.strict()),
|
|
73
|
+
items: zod_1.z.array(zod_1.z
|
|
74
|
+
.object({
|
|
75
|
+
title: NonEmptyStringSchema,
|
|
76
|
+
variant_title: OptionalTextSchema,
|
|
77
|
+
quantity: zod_1.z.number().positive(),
|
|
78
|
+
})
|
|
79
|
+
.strict()),
|
|
80
|
+
delivery_address: OrderSummaryAddressSchema.nullable(),
|
|
81
|
+
more_to_follow: zod_1.z.boolean(),
|
|
82
|
+
})
|
|
83
|
+
.strict();
|
|
84
|
+
/**
|
|
85
|
+
* Snapshot of a return when it was requested: the return and order numbers,
|
|
86
|
+
* the items to send back (title of the order line, quantity, reason label),
|
|
87
|
+
* the return shipping option and where to send the parcel.
|
|
88
|
+
*/
|
|
89
|
+
exports.ReturnSummarySchema = zod_1.z
|
|
90
|
+
.object({
|
|
91
|
+
display_id: zod_1.z.number().int().nullable(),
|
|
92
|
+
order_display_id: zod_1.z.number().int().nullable(),
|
|
93
|
+
shipping_method_name: OptionalTextSchema,
|
|
94
|
+
items: zod_1.z.array(zod_1.z
|
|
95
|
+
.object({
|
|
96
|
+
title: NonEmptyStringSchema,
|
|
97
|
+
variant_title: OptionalTextSchema,
|
|
98
|
+
quantity: zod_1.z.number().positive(),
|
|
99
|
+
reason: OptionalTextSchema,
|
|
100
|
+
})
|
|
101
|
+
.strict()),
|
|
102
|
+
return_address: OrderSummaryAddressSchema.nullable(),
|
|
103
|
+
})
|
|
104
|
+
.strict();
|
|
105
|
+
/**
|
|
106
|
+
* Snapshot of a return when it was completely received: the return and
|
|
107
|
+
* order numbers, when it arrived and the received items (title of the order
|
|
108
|
+
* line, received quantity and how much of it arrived damaged).
|
|
109
|
+
*/
|
|
110
|
+
exports.ReturnReceivedSummarySchema = zod_1.z
|
|
111
|
+
.object({
|
|
112
|
+
display_id: zod_1.z.number().int().nullable(),
|
|
113
|
+
order_display_id: zod_1.z.number().int().nullable(),
|
|
114
|
+
received_at: zod_1.z.string().datetime().nullable(),
|
|
115
|
+
items: zod_1.z.array(zod_1.z
|
|
116
|
+
.object({
|
|
117
|
+
title: NonEmptyStringSchema,
|
|
118
|
+
variant_title: OptionalTextSchema,
|
|
119
|
+
quantity: zod_1.z.number().positive(),
|
|
120
|
+
damaged_quantity: zod_1.z.number().nonnegative(),
|
|
121
|
+
})
|
|
122
|
+
.strict()),
|
|
123
|
+
})
|
|
124
|
+
.strict();
|
|
125
|
+
/**
|
|
126
|
+
* Snapshot of one refund when its Documents fact arrived: the order number,
|
|
127
|
+
* the refunded gross amount, when it was refunded and the refund reason
|
|
128
|
+
* chosen in the Admin.
|
|
129
|
+
*/
|
|
130
|
+
exports.RefundSummarySchema = zod_1.z
|
|
131
|
+
.object({
|
|
132
|
+
order_display_id: zod_1.z.number().int().nullable(),
|
|
133
|
+
amount: AmountSchema,
|
|
134
|
+
currency_code: NonEmptyStringSchema,
|
|
135
|
+
refunded_at: zod_1.z.string().datetime().nullable(),
|
|
136
|
+
reason: OptionalTextSchema,
|
|
137
|
+
})
|
|
138
|
+
.strict();
|
|
139
|
+
exports.EmailPersistedDataSchemas = {
|
|
140
|
+
"order.received": zod_1.z
|
|
141
|
+
.object({
|
|
142
|
+
order_id: NonEmptyStringSchema,
|
|
143
|
+
// Optional: messages stored before the summary existed have none.
|
|
144
|
+
summary: exports.OrderSummarySchema.optional(),
|
|
145
|
+
})
|
|
146
|
+
.strict(),
|
|
147
|
+
"order.received.admin": zod_1.z
|
|
148
|
+
.object({
|
|
149
|
+
order_id: NonEmptyStringSchema,
|
|
150
|
+
// Optional: messages stored before the summary existed have none.
|
|
151
|
+
summary: exports.OrderSummarySchema.optional(),
|
|
152
|
+
})
|
|
153
|
+
.strict(),
|
|
154
|
+
"order.shipped": zod_1.z
|
|
155
|
+
.object({
|
|
156
|
+
order_id: NonEmptyStringSchema,
|
|
157
|
+
fulfillment_id: NonEmptyStringSchema,
|
|
158
|
+
documents_fact_fingerprint: DocumentsFactFingerprintSchema,
|
|
159
|
+
// Optional: messages stored before the snapshot existed have none.
|
|
160
|
+
shipment: exports.ShipmentSummarySchema.optional(),
|
|
161
|
+
/** The invoice PDF is attached (Documents chose this shipment). */
|
|
162
|
+
invoice_attached: zod_1.z.boolean().optional(),
|
|
163
|
+
})
|
|
164
|
+
.strict(),
|
|
165
|
+
"order.canceled": zod_1.z
|
|
166
|
+
.object({
|
|
167
|
+
order_id: NonEmptyStringSchema,
|
|
168
|
+
documents_fact_fingerprint: DocumentsFactFingerprintSchema,
|
|
169
|
+
// Optional: messages stored before the snapshot existed have none.
|
|
170
|
+
summary: exports.OrderSummarySchema.optional(),
|
|
171
|
+
/** When the order was canceled (ISO 8601). */
|
|
172
|
+
canceled_at: zod_1.z.string().datetime().optional(),
|
|
173
|
+
/** A cancellation document PDF is attached (from Documents). */
|
|
174
|
+
cancellation_attached: zod_1.z.boolean().optional(),
|
|
175
|
+
})
|
|
176
|
+
.strict(),
|
|
177
|
+
"order.return_requested": zod_1.z
|
|
178
|
+
.object({
|
|
179
|
+
order_id: NonEmptyStringSchema,
|
|
180
|
+
return_id: NonEmptyStringSchema,
|
|
181
|
+
// Optional: messages stored before the snapshot existed have none.
|
|
182
|
+
summary: exports.ReturnSummarySchema.optional(),
|
|
183
|
+
})
|
|
184
|
+
.strict(),
|
|
185
|
+
"order.return_received": zod_1.z
|
|
186
|
+
.object({
|
|
187
|
+
order_id: NonEmptyStringSchema,
|
|
188
|
+
return_id: NonEmptyStringSchema,
|
|
189
|
+
// Optional: messages stored before the snapshot existed have none.
|
|
190
|
+
summary: exports.ReturnReceivedSummarySchema.optional(),
|
|
191
|
+
})
|
|
192
|
+
.strict(),
|
|
193
|
+
"order.refunded": zod_1.z
|
|
194
|
+
.object({
|
|
195
|
+
order_id: NonEmptyStringSchema,
|
|
196
|
+
refund_id: NonEmptyStringSchema,
|
|
197
|
+
documents_fact_fingerprint: DocumentsFactFingerprintSchema,
|
|
198
|
+
// Optional: messages stored before the snapshot existed have none.
|
|
199
|
+
summary: exports.RefundSummarySchema.optional(),
|
|
200
|
+
/** A cancellation document PDF is attached (from Documents). */
|
|
201
|
+
cancellation_attached: zod_1.z.boolean().optional(),
|
|
202
|
+
})
|
|
203
|
+
.strict(),
|
|
204
|
+
"auth.password_reset": zod_1.z
|
|
205
|
+
.object({
|
|
206
|
+
locale: NullableLocaleSchema,
|
|
207
|
+
})
|
|
208
|
+
.strict(),
|
|
209
|
+
"affiliate.consignment_report_due": zod_1.z
|
|
210
|
+
.object({
|
|
211
|
+
affiliate_display_name: NonEmptyStringSchema,
|
|
212
|
+
period_start: affiliate_1.CalendarMonthSchema,
|
|
213
|
+
due_date: affiliate_1.CalendarDateSchema,
|
|
214
|
+
locale: NullableLocaleSchema,
|
|
215
|
+
})
|
|
216
|
+
.strict(),
|
|
217
|
+
"user.invite": zod_1.z.object({}).strict(),
|
|
218
|
+
};
|
|
219
|
+
exports.EmailRenderDataSchemas = {
|
|
220
|
+
...exports.EmailPersistedDataSchemas,
|
|
221
|
+
"auth.password_reset": exports.EmailPersistedDataSchemas["auth.password_reset"].extend({
|
|
222
|
+
reset_url: zod_1.z.string().url(),
|
|
223
|
+
/** How long the reset link is valid, from the token; `undefined` if unknown. */
|
|
224
|
+
valid_minutes: zod_1.z.number().int().positive().optional(),
|
|
225
|
+
}),
|
|
226
|
+
"user.invite": exports.EmailPersistedDataSchemas["user.invite"].extend({
|
|
227
|
+
invite_url: zod_1.z.string().url(),
|
|
228
|
+
/** When the invite expires (ISO 8601), from the current invite. */
|
|
229
|
+
expires_at: zod_1.z.string().datetime().optional(),
|
|
230
|
+
}),
|
|
231
|
+
};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { type FileGatewayOptions, type FileModuleConfiguration, type S3CacheFileModuleConfigOptions, type S3CacheOptions, type S3CacheOptionsCache, type S3CacheStorageConfiguration, type ValidatedS3CacheProviderOptions } from "../types";
|
|
2
|
+
export declare const validateS3CacheProviderOptions: (input: {
|
|
3
|
+
cache?: S3CacheOptionsCache;
|
|
4
|
+
gateway?: FileGatewayOptions;
|
|
5
|
+
s3?: S3CacheOptions;
|
|
6
|
+
}) => ValidatedS3CacheProviderOptions;
|
|
7
|
+
export declare const createS3CacheFileModuleConfig: (options?: S3CacheFileModuleConfigOptions) => FileModuleConfiguration;
|
|
8
|
+
/**
|
|
9
|
+
* Validates the options once and returns both parts S3 Cache Storage needs:
|
|
10
|
+
* the File Module with the S3 provider (under `modules`) and the `gateway`
|
|
11
|
+
* part of the base plugin's `files` option that serves its `/files` routes.
|
|
12
|
+
* Both carry the same signing secret, so every URL the provider signs is one
|
|
13
|
+
* the routes accept.
|
|
14
|
+
*/
|
|
15
|
+
export declare const createS3CacheStorageConfig: (options: Omit<S3CacheFileModuleConfigOptions, "enabled" | "local">) => S3CacheStorageConfiguration;
|
|
16
|
+
/**
|
|
17
|
+
* `medusa build` loads the configuration without deployment secrets. These
|
|
18
|
+
* placeholders only satisfy the required-variable checks of a build; they
|
|
19
|
+
* never reach a running server.
|
|
20
|
+
*/
|
|
21
|
+
export declare const S3_BUILD_PLACEHOLDERS: Readonly<Record<string, string>>;
|
|
22
|
+
/**
|
|
23
|
+
* Static S3 credentials are optional (the AWS credential chain applies
|
|
24
|
+
* otherwise) but must be complete when present. They are never read during
|
|
25
|
+
* a build.
|
|
26
|
+
*/
|
|
27
|
+
export declare const resolveS3Credentials: (environment: NodeJS.ProcessEnv, phase: "build" | "runtime") => {
|
|
28
|
+
readonly accessKeyId: string;
|
|
29
|
+
readonly secretAccessKey: string;
|
|
30
|
+
readonly sessionToken?: string;
|
|
31
|
+
} | undefined;
|
|
32
|
+
export declare const resolveExpirationStrategy: (environment: NodeJS.ProcessEnv, defaultValue: "absolute" | "sliding") => "absolute" | "sliding";
|
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.resolveExpirationStrategy = exports.resolveS3Credentials = exports.S3_BUILD_PLACEHOLDERS = exports.createS3CacheStorageConfig = exports.createS3CacheFileModuleConfig = exports.validateS3CacheProviderOptions = void 0;
|
|
4
|
+
const PACKAGE_NAME = "medusa-s3-cache-storage";
|
|
5
|
+
const DEFAULT_CACHE = {
|
|
6
|
+
cleanupIntervalMs: 900_000,
|
|
7
|
+
dir: "./.medusa-s3-cache",
|
|
8
|
+
expirationStrategy: "absolute",
|
|
9
|
+
ttlMs: 3_600_000,
|
|
10
|
+
};
|
|
11
|
+
const DEFAULT_PRIVATE_DOWNLOAD_DURATION_SECONDS = 3_600;
|
|
12
|
+
const invalid = (message) => {
|
|
13
|
+
throw new TypeError(`${PACKAGE_NAME}: ${message}`);
|
|
14
|
+
};
|
|
15
|
+
const requireNonBlankString = (value, field) => {
|
|
16
|
+
if (typeof value === "string") {
|
|
17
|
+
const trimmed = value.trim();
|
|
18
|
+
if (trimmed) {
|
|
19
|
+
return trimmed;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
return invalid(`${field} must be a non-blank string`);
|
|
23
|
+
};
|
|
24
|
+
const validateHttpUrl = (value, field) => {
|
|
25
|
+
const url = requireNonBlankString(value, field);
|
|
26
|
+
try {
|
|
27
|
+
const parsed = new URL(url);
|
|
28
|
+
if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
|
|
29
|
+
invalid(`${field} must be an HTTP(S) URL`);
|
|
30
|
+
}
|
|
31
|
+
if (parsed.username || parsed.password || parsed.search || parsed.hash) {
|
|
32
|
+
invalid(`${field} must not include credentials, a query, or a fragment`);
|
|
33
|
+
}
|
|
34
|
+
return parsed.toString().replace(/\/$/u, "");
|
|
35
|
+
}
|
|
36
|
+
catch (error) {
|
|
37
|
+
if (error instanceof TypeError && error.message.startsWith(PACKAGE_NAME)) {
|
|
38
|
+
throw error;
|
|
39
|
+
}
|
|
40
|
+
return invalid(`${field} must be an HTTP(S) URL`);
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
const validateSafePrefix = (value, field) => {
|
|
44
|
+
if (value === undefined) {
|
|
45
|
+
return "";
|
|
46
|
+
}
|
|
47
|
+
const prefix = requireNonBlankString(value, field).replaceAll("\\", "/");
|
|
48
|
+
const segments = prefix.split("/");
|
|
49
|
+
if (segments.some((segment) => !segment ||
|
|
50
|
+
segment === "." ||
|
|
51
|
+
segment === ".." ||
|
|
52
|
+
/[\u0000-\u001F\u007F]/u.test(segment))) {
|
|
53
|
+
invalid(`${field} must contain only safe path segments`);
|
|
54
|
+
}
|
|
55
|
+
return segments.join("/");
|
|
56
|
+
};
|
|
57
|
+
const validateFiniteNumber = (value, field, minimum, maximum, defaultValue) => {
|
|
58
|
+
if (value === undefined) {
|
|
59
|
+
return defaultValue;
|
|
60
|
+
}
|
|
61
|
+
if (typeof value !== "number") {
|
|
62
|
+
return invalid(`${field} must be an integer from ${minimum} through ${maximum}`);
|
|
63
|
+
}
|
|
64
|
+
if (!Number.isFinite(value) ||
|
|
65
|
+
!Number.isInteger(value) ||
|
|
66
|
+
value < minimum ||
|
|
67
|
+
value > maximum) {
|
|
68
|
+
return invalid(`${field} must be an integer from ${minimum} through ${maximum}`);
|
|
69
|
+
}
|
|
70
|
+
return value;
|
|
71
|
+
};
|
|
72
|
+
const validateCacheOptions = (cache) => {
|
|
73
|
+
const expirationStrategy = cache?.expirationStrategy ?? DEFAULT_CACHE.expirationStrategy;
|
|
74
|
+
if (expirationStrategy !== "absolute" && expirationStrategy !== "sliding") {
|
|
75
|
+
invalid("cache.expirationStrategy must be 'absolute' or 'sliding'");
|
|
76
|
+
}
|
|
77
|
+
return {
|
|
78
|
+
cleanupIntervalMs: validateFiniteNumber(cache?.cleanupIntervalMs, "cache.cleanupIntervalMs", 1, 86_400_000, DEFAULT_CACHE.cleanupIntervalMs),
|
|
79
|
+
dir: cache?.dir
|
|
80
|
+
? requireNonBlankString(cache.dir, "cache.dir")
|
|
81
|
+
: DEFAULT_CACHE.dir,
|
|
82
|
+
expirationStrategy,
|
|
83
|
+
ttlMs: validateFiniteNumber(cache?.ttlMs, "cache.ttlMs", 0, 604_800_000, DEFAULT_CACHE.ttlMs),
|
|
84
|
+
};
|
|
85
|
+
};
|
|
86
|
+
const validateCredentials = (credentials) => {
|
|
87
|
+
if (!credentials) {
|
|
88
|
+
return undefined;
|
|
89
|
+
}
|
|
90
|
+
const accessKeyId = credentials.accessKeyId;
|
|
91
|
+
const secretAccessKey = credentials.secretAccessKey;
|
|
92
|
+
if (!accessKeyId && !secretAccessKey && !credentials.sessionToken) {
|
|
93
|
+
invalid("s3.credentials must contain accessKeyId and secretAccessKey");
|
|
94
|
+
}
|
|
95
|
+
return {
|
|
96
|
+
accessKeyId: requireNonBlankString(accessKeyId, "s3.credentials.accessKeyId"),
|
|
97
|
+
secretAccessKey: requireNonBlankString(secretAccessKey, "s3.credentials.secretAccessKey"),
|
|
98
|
+
...(credentials.sessionToken
|
|
99
|
+
? {
|
|
100
|
+
sessionToken: requireNonBlankString(credentials.sessionToken, "s3.credentials.sessionToken"),
|
|
101
|
+
}
|
|
102
|
+
: {}),
|
|
103
|
+
};
|
|
104
|
+
};
|
|
105
|
+
const validateGatewayOptions = (gateway) => {
|
|
106
|
+
if (!gateway) {
|
|
107
|
+
return invalid("gateway options are required when enabled is true");
|
|
108
|
+
}
|
|
109
|
+
return {
|
|
110
|
+
baseUrl: validateHttpUrl(gateway.baseUrl, "gateway.baseUrl"),
|
|
111
|
+
privateDownloadDurationSeconds: validateFiniteNumber(gateway.privateDownloadDurationSeconds, "gateway.privateDownloadDurationSeconds", 1, 604_800, DEFAULT_PRIVATE_DOWNLOAD_DURATION_SECONDS),
|
|
112
|
+
signingSecret: requireNonBlankString(gateway.signingSecret, "gateway.signingSecret"),
|
|
113
|
+
};
|
|
114
|
+
};
|
|
115
|
+
const validateS3CacheProviderOptions = (input) => {
|
|
116
|
+
const s3 = input.s3;
|
|
117
|
+
if (!s3) {
|
|
118
|
+
return invalid("s3 options are required when enabled is true");
|
|
119
|
+
}
|
|
120
|
+
if (s3.forcePathStyle !== undefined &&
|
|
121
|
+
typeof s3.forcePathStyle !== "boolean") {
|
|
122
|
+
invalid("s3.forcePathStyle must be a boolean");
|
|
123
|
+
}
|
|
124
|
+
if (s3.endpoint !== undefined) {
|
|
125
|
+
validateHttpUrl(s3.endpoint, "s3.endpoint");
|
|
126
|
+
}
|
|
127
|
+
return {
|
|
128
|
+
cache: validateCacheOptions(input.cache),
|
|
129
|
+
gateway: validateGatewayOptions(input.gateway),
|
|
130
|
+
s3: {
|
|
131
|
+
bucket: requireNonBlankString(s3.bucket, "s3.bucket"),
|
|
132
|
+
credentials: validateCredentials(s3.credentials),
|
|
133
|
+
endpoint: s3.endpoint === undefined
|
|
134
|
+
? undefined
|
|
135
|
+
: validateHttpUrl(s3.endpoint, "s3.endpoint"),
|
|
136
|
+
forcePathStyle: s3.forcePathStyle ?? false,
|
|
137
|
+
region: requireNonBlankString(s3.region, "s3.region"),
|
|
138
|
+
storagePrefix: validateSafePrefix(s3.storagePrefix, "s3.storagePrefix"),
|
|
139
|
+
},
|
|
140
|
+
};
|
|
141
|
+
};
|
|
142
|
+
exports.validateS3CacheProviderOptions = validateS3CacheProviderOptions;
|
|
143
|
+
const buildLocalProviderOptions = (options) => ({
|
|
144
|
+
...(options?.backendUrl ? { backend_url: options.backendUrl } : {}),
|
|
145
|
+
...(options?.privateUploadDir
|
|
146
|
+
? { private_upload_dir: options.privateUploadDir }
|
|
147
|
+
: {}),
|
|
148
|
+
...(options?.uploadDir ? { upload_dir: options.uploadDir } : {}),
|
|
149
|
+
});
|
|
150
|
+
const createS3CacheFileModuleConfig = (options = {}) => {
|
|
151
|
+
if (options.enabled !== true) {
|
|
152
|
+
return {
|
|
153
|
+
options: {
|
|
154
|
+
providers: [
|
|
155
|
+
{
|
|
156
|
+
id: "local",
|
|
157
|
+
options: buildLocalProviderOptions(options.local),
|
|
158
|
+
resolve: "@medusajs/medusa/file-local",
|
|
159
|
+
},
|
|
160
|
+
],
|
|
161
|
+
},
|
|
162
|
+
resolve: "@medusajs/medusa/file",
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
return s3FileModule((0, exports.validateS3CacheProviderOptions)(options));
|
|
166
|
+
};
|
|
167
|
+
exports.createS3CacheFileModuleConfig = createS3CacheFileModuleConfig;
|
|
168
|
+
const s3FileModule = (validated) => ({
|
|
169
|
+
options: {
|
|
170
|
+
providers: [
|
|
171
|
+
{
|
|
172
|
+
id: "s3-cache",
|
|
173
|
+
options: {
|
|
174
|
+
cache: validated.cache,
|
|
175
|
+
gateway: validated.gateway,
|
|
176
|
+
s3: validated.s3,
|
|
177
|
+
},
|
|
178
|
+
resolve: "@hartl-services/medusa-base/providers/s3-cache",
|
|
179
|
+
},
|
|
180
|
+
],
|
|
181
|
+
},
|
|
182
|
+
resolve: "@medusajs/medusa/file",
|
|
183
|
+
});
|
|
184
|
+
/**
|
|
185
|
+
* Validates the options once and returns both parts S3 Cache Storage needs:
|
|
186
|
+
* the File Module with the S3 provider (under `modules`) and the `gateway`
|
|
187
|
+
* part of the base plugin's `files` option that serves its `/files` routes.
|
|
188
|
+
* Both carry the same signing secret, so every URL the provider signs is one
|
|
189
|
+
* the routes accept.
|
|
190
|
+
*/
|
|
191
|
+
const createS3CacheStorageConfig = (options) => {
|
|
192
|
+
const validated = (0, exports.validateS3CacheProviderOptions)(options);
|
|
193
|
+
return {
|
|
194
|
+
fileModule: s3FileModule(validated),
|
|
195
|
+
gateway: { signingSecret: validated.gateway.signingSecret },
|
|
196
|
+
};
|
|
197
|
+
};
|
|
198
|
+
exports.createS3CacheStorageConfig = createS3CacheStorageConfig;
|
|
199
|
+
/**
|
|
200
|
+
* `medusa build` loads the configuration without deployment secrets. These
|
|
201
|
+
* placeholders only satisfy the required-variable checks of a build; they
|
|
202
|
+
* never reach a running server.
|
|
203
|
+
*/
|
|
204
|
+
exports.S3_BUILD_PLACEHOLDERS = {
|
|
205
|
+
S3_CACHE_STORAGE_BUCKET: "build-bucket",
|
|
206
|
+
S3_CACHE_STORAGE_REGION: "build-placeholder",
|
|
207
|
+
};
|
|
208
|
+
const optionalEnvironment = (environment, name) => {
|
|
209
|
+
const value = environment[name]?.trim();
|
|
210
|
+
return value ? value : undefined;
|
|
211
|
+
};
|
|
212
|
+
/**
|
|
213
|
+
* Static S3 credentials are optional (the AWS credential chain applies
|
|
214
|
+
* otherwise) but must be complete when present. They are never read during
|
|
215
|
+
* a build.
|
|
216
|
+
*/
|
|
217
|
+
const resolveS3Credentials = (environment, phase) => {
|
|
218
|
+
if (phase === "build") {
|
|
219
|
+
return undefined;
|
|
220
|
+
}
|
|
221
|
+
const accessKeyId = optionalEnvironment(environment, "S3_CACHE_STORAGE_ACCESS_KEY_ID");
|
|
222
|
+
const secretAccessKey = optionalEnvironment(environment, "S3_CACHE_STORAGE_SECRET_ACCESS_KEY");
|
|
223
|
+
const sessionToken = optionalEnvironment(environment, "S3_CACHE_STORAGE_SESSION_TOKEN");
|
|
224
|
+
// A declared but blank key still counts: it signals intended static
|
|
225
|
+
// credentials, which must then be complete.
|
|
226
|
+
if (!("S3_CACHE_STORAGE_ACCESS_KEY_ID" in environment) &&
|
|
227
|
+
!("S3_CACHE_STORAGE_SECRET_ACCESS_KEY" in environment) &&
|
|
228
|
+
!sessionToken) {
|
|
229
|
+
return undefined;
|
|
230
|
+
}
|
|
231
|
+
const missing = [
|
|
232
|
+
accessKeyId ? undefined : "S3_CACHE_STORAGE_ACCESS_KEY_ID",
|
|
233
|
+
secretAccessKey ? undefined : "S3_CACHE_STORAGE_SECRET_ACCESS_KEY",
|
|
234
|
+
].filter((name) => name !== undefined);
|
|
235
|
+
if (missing.length > 0) {
|
|
236
|
+
throw new TypeError(`Missing required environment variables: ${missing.join(", ")}.`);
|
|
237
|
+
}
|
|
238
|
+
return {
|
|
239
|
+
accessKeyId: accessKeyId,
|
|
240
|
+
secretAccessKey: secretAccessKey,
|
|
241
|
+
...(sessionToken ? { sessionToken } : {}),
|
|
242
|
+
};
|
|
243
|
+
};
|
|
244
|
+
exports.resolveS3Credentials = resolveS3Credentials;
|
|
245
|
+
const resolveExpirationStrategy = (environment, defaultValue) => {
|
|
246
|
+
const value = optionalEnvironment(environment, "S3_CACHE_STORAGE_EXPIRATION_STRATEGY");
|
|
247
|
+
if (value === undefined) {
|
|
248
|
+
return defaultValue;
|
|
249
|
+
}
|
|
250
|
+
if (value !== "absolute" && value !== "sliding") {
|
|
251
|
+
throw new TypeError('S3_CACHE_STORAGE_EXPIRATION_STRATEGY must be either "absolute" or "sliding".');
|
|
252
|
+
}
|
|
253
|
+
return value;
|
|
254
|
+
};
|
|
255
|
+
exports.resolveExpirationStrategy = resolveExpirationStrategy;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export declare const toPublicFileGatewayUrl: (baseUrl: string, logicalFileKey: string) => string;
|
|
2
|
+
export declare const publicFileGatewayKey: (asset: string) => string;
|
|
3
|
+
export declare const createPrivateFileGatewayUrl: (input: {
|
|
4
|
+
baseUrl: string;
|
|
5
|
+
durationSeconds: number;
|
|
6
|
+
fileKey: string;
|
|
7
|
+
now?: number;
|
|
8
|
+
signingSecret: string;
|
|
9
|
+
}) => string;
|
|
10
|
+
export declare const createFileGatewayUploadUrl: (input: {
|
|
11
|
+
baseUrl: string;
|
|
12
|
+
durationSeconds: number;
|
|
13
|
+
fileKey: string;
|
|
14
|
+
now?: number;
|
|
15
|
+
signingSecret: string;
|
|
16
|
+
}) => string;
|
|
17
|
+
export declare const verifyPrivateFileGatewayToken: (input: {
|
|
18
|
+
expires: number;
|
|
19
|
+
now?: number;
|
|
20
|
+
signature: string;
|
|
21
|
+
signingSecret: string;
|
|
22
|
+
token: string;
|
|
23
|
+
}) => string | undefined;
|
|
24
|
+
export declare const verifyFileGatewayUploadToken: (input: {
|
|
25
|
+
expires: number;
|
|
26
|
+
now?: number;
|
|
27
|
+
signature: string;
|
|
28
|
+
signingSecret: string;
|
|
29
|
+
token: string;
|
|
30
|
+
}) => string | undefined;
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.verifyFileGatewayUploadToken = exports.verifyPrivateFileGatewayToken = exports.createFileGatewayUploadUrl = exports.createPrivateFileGatewayUrl = exports.publicFileGatewayKey = exports.toPublicFileGatewayUrl = void 0;
|
|
4
|
+
const node_crypto_1 = require("node:crypto");
|
|
5
|
+
const PRIVATE_SIGNATURE_VERSION = "v1";
|
|
6
|
+
const safeLogicalKey = (value) => {
|
|
7
|
+
if (!value ||
|
|
8
|
+
value.startsWith("/") ||
|
|
9
|
+
value.includes("\\") ||
|
|
10
|
+
value
|
|
11
|
+
.split("/")
|
|
12
|
+
.some((segment) => !segment ||
|
|
13
|
+
segment === "." ||
|
|
14
|
+
segment === ".." ||
|
|
15
|
+
/[\u0000-\u001F\u007F]/u.test(segment))) {
|
|
16
|
+
throw new TypeError("File gateway key must be a safe relative path");
|
|
17
|
+
}
|
|
18
|
+
return value;
|
|
19
|
+
};
|
|
20
|
+
const gatewayUrl = (baseUrl, path) => {
|
|
21
|
+
const url = new URL(`${baseUrl.replace(/\/$/u, "")}/`);
|
|
22
|
+
url.pathname = `${url.pathname.replace(/\/$/u, "")}/${path}`;
|
|
23
|
+
return url;
|
|
24
|
+
};
|
|
25
|
+
const signatureFor = (input) => (0, node_crypto_1.createHmac)("sha256", input.secret)
|
|
26
|
+
.update(`${PRIVATE_SIGNATURE_VERSION}\n${input.action}\n${input.token}\n${input.expires}`)
|
|
27
|
+
.digest("base64url");
|
|
28
|
+
const createPrivateCapabilityUrl = (input) => {
|
|
29
|
+
const fileKey = safeLogicalKey(input.fileKey);
|
|
30
|
+
if (input.action === "download" && fileKey.startsWith("public/")) {
|
|
31
|
+
throw new TypeError("Public files must not use private gateway URLs");
|
|
32
|
+
}
|
|
33
|
+
const token = Buffer.from(fileKey, "utf8").toString("base64url");
|
|
34
|
+
const expires = Math.floor((input.now ?? Date.now()) / 1_000) + input.durationSeconds;
|
|
35
|
+
const url = gatewayUrl(input.baseUrl, `${input.path}/${token}`);
|
|
36
|
+
url.searchParams.set("expires", String(expires));
|
|
37
|
+
url.searchParams.set("signature", signatureFor({
|
|
38
|
+
action: input.action,
|
|
39
|
+
expires,
|
|
40
|
+
secret: input.signingSecret,
|
|
41
|
+
token,
|
|
42
|
+
}));
|
|
43
|
+
return url.toString();
|
|
44
|
+
};
|
|
45
|
+
const verifyPrivateCapabilityToken = (input) => {
|
|
46
|
+
if (!Number.isSafeInteger(input.expires) ||
|
|
47
|
+
input.expires < Math.floor((input.now ?? Date.now()) / 1_000)) {
|
|
48
|
+
return undefined;
|
|
49
|
+
}
|
|
50
|
+
const expected = Buffer.from(signatureFor({
|
|
51
|
+
action: input.action,
|
|
52
|
+
expires: input.expires,
|
|
53
|
+
secret: input.signingSecret,
|
|
54
|
+
token: input.token,
|
|
55
|
+
}), "base64url");
|
|
56
|
+
const provided = Buffer.from(input.signature, "base64url");
|
|
57
|
+
if (provided.toString("base64url") !== input.signature ||
|
|
58
|
+
provided.length !== expected.length ||
|
|
59
|
+
!(0, node_crypto_1.timingSafeEqual)(provided, expected)) {
|
|
60
|
+
return undefined;
|
|
61
|
+
}
|
|
62
|
+
try {
|
|
63
|
+
const fileKeyBuffer = Buffer.from(input.token, "base64url");
|
|
64
|
+
if (fileKeyBuffer.toString("base64url") !== input.token) {
|
|
65
|
+
return undefined;
|
|
66
|
+
}
|
|
67
|
+
const fileKey = safeLogicalKey(fileKeyBuffer.toString("utf8"));
|
|
68
|
+
return input.action === "download" && fileKey.startsWith("public/")
|
|
69
|
+
? undefined
|
|
70
|
+
: fileKey;
|
|
71
|
+
}
|
|
72
|
+
catch {
|
|
73
|
+
return undefined;
|
|
74
|
+
}
|
|
75
|
+
};
|
|
76
|
+
const toPublicFileGatewayUrl = (baseUrl, logicalFileKey) => {
|
|
77
|
+
const key = safeLogicalKey(logicalFileKey);
|
|
78
|
+
if (!key.startsWith("public/")) {
|
|
79
|
+
throw new TypeError("Only public file keys can have public gateway URLs");
|
|
80
|
+
}
|
|
81
|
+
const asset = key.slice("public/".length);
|
|
82
|
+
if (!asset || asset.includes("/")) {
|
|
83
|
+
throw new TypeError("Public gateway files must have one opaque asset name");
|
|
84
|
+
}
|
|
85
|
+
return gatewayUrl(baseUrl, encodeURIComponent(asset)).toString();
|
|
86
|
+
};
|
|
87
|
+
exports.toPublicFileGatewayUrl = toPublicFileGatewayUrl;
|
|
88
|
+
const publicFileGatewayKey = (asset) => {
|
|
89
|
+
if (!asset || asset.includes("/") || asset.includes("\\")) {
|
|
90
|
+
throw new TypeError("Public gateway asset is invalid");
|
|
91
|
+
}
|
|
92
|
+
return safeLogicalKey(`public/${asset}`);
|
|
93
|
+
};
|
|
94
|
+
exports.publicFileGatewayKey = publicFileGatewayKey;
|
|
95
|
+
const createPrivateFileGatewayUrl = (input) => {
|
|
96
|
+
return createPrivateCapabilityUrl({
|
|
97
|
+
...input,
|
|
98
|
+
action: "download",
|
|
99
|
+
path: "private",
|
|
100
|
+
});
|
|
101
|
+
};
|
|
102
|
+
exports.createPrivateFileGatewayUrl = createPrivateFileGatewayUrl;
|
|
103
|
+
const createFileGatewayUploadUrl = (input) => createPrivateCapabilityUrl({
|
|
104
|
+
...input,
|
|
105
|
+
action: "upload",
|
|
106
|
+
path: "upload",
|
|
107
|
+
});
|
|
108
|
+
exports.createFileGatewayUploadUrl = createFileGatewayUploadUrl;
|
|
109
|
+
const verifyPrivateFileGatewayToken = (input) => {
|
|
110
|
+
return verifyPrivateCapabilityToken({ ...input, action: "download" });
|
|
111
|
+
};
|
|
112
|
+
exports.verifyPrivateFileGatewayToken = verifyPrivateFileGatewayToken;
|
|
113
|
+
const verifyFileGatewayUploadToken = (input) => verifyPrivateCapabilityToken({ ...input, action: "upload" });
|
|
114
|
+
exports.verifyFileGatewayUploadToken = verifyFileGatewayUploadToken;
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
export type { CacheExpirationStrategy, FileGatewayOptions, FilesPluginOptions, FileModuleConfiguration, FileModuleProviderConfiguration, LocalFileProviderOptions, S3CacheCredentials, S3CacheFileModuleConfigOptions, S3CacheOptions, S3CacheOptionsCache, S3CacheStorageConfiguration, ValidatedS3CacheCredentials, ValidatedFileGatewayOptions, ValidatedS3CacheOptions, ValidatedS3CacheProviderOptions, } from "./public";
|
|
2
|
+
export { BASE_PLUGIN_RESOLVE } from "./public";
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.BASE_PLUGIN_RESOLVE = void 0;
|
|
4
|
+
var public_1 = require("./public");
|
|
5
|
+
Object.defineProperty(exports, "BASE_PLUGIN_RESOLVE", { enumerable: true, get: function () { return public_1.BASE_PLUGIN_RESOLVE; } });
|