@modainteract/moda-interact-shared 0.11.1 → 0.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/billing.js +1 -1
- package/dist/{chunk-MBIECH3Y.js → chunk-ANBEH6NW.js} +2 -2
- package/dist/chunk-ANBEH6NW.js.map +1 -0
- package/dist/index.js +1 -1
- package/dist/whatsapp.d.ts +67 -0
- package/dist/whatsapp.js +52 -0
- package/dist/whatsapp.js.map +1 -0
- package/package.json +5 -1
- package/dist/chunk-MBIECH3Y.js.map +0 -1
package/dist/billing.js
CHANGED
|
@@ -27,7 +27,7 @@ import {
|
|
|
27
27
|
parseNormalizedWhatsAppStatus,
|
|
28
28
|
safeParseBillingSubscriptionReconcileJob,
|
|
29
29
|
safeParseNormalizedWhatsAppStatus
|
|
30
|
-
} from "./chunk-
|
|
30
|
+
} from "./chunk-ANBEH6NW.js";
|
|
31
31
|
export {
|
|
32
32
|
APP_PRICING_BILLING_PERIOD_DRAIN_WINDOW_MS,
|
|
33
33
|
ARCH007_BILLING_CONTRACT_SCHEMA_VERSION,
|
|
@@ -39,7 +39,7 @@ function isSameShopifyPurchaseProviderContext(purchase, current) {
|
|
|
39
39
|
[purchase.shopifyPlanHandleSnapshot, current.shopifyPlanHandle],
|
|
40
40
|
[purchase.billingPeriodId, current.billingPeriodId]
|
|
41
41
|
].every(
|
|
42
|
-
([purchaseValue, currentValue]) => typeof purchaseValue === "string" && typeof currentValue === "string" && purchaseValue.trim() === currentValue.trim()
|
|
42
|
+
([purchaseValue, currentValue]) => typeof purchaseValue === "string" && typeof currentValue === "string" && purchaseValue.trim().length > 0 && currentValue.trim().length > 0 && purchaseValue.trim() === currentValue.trim()
|
|
43
43
|
);
|
|
44
44
|
}
|
|
45
45
|
var BILLING_PLAN_KINDS = ["FREE", "PAID_METERED"];
|
|
@@ -203,4 +203,4 @@ export {
|
|
|
203
203
|
createRecoveryIdempotencyKey,
|
|
204
204
|
createShopifyUsageIdempotencyKey
|
|
205
205
|
};
|
|
206
|
-
//# sourceMappingURL=chunk-
|
|
206
|
+
//# sourceMappingURL=chunk-ANBEH6NW.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/billing.ts"],"sourcesContent":["import { z } from \"zod\";\n\nexport const ARCH007_BILLING_CONTRACT_SCHEMA_VERSION = 1 as const;\nexport const WHATSAPP_PROVIDER_STATUS_SCHEMA_VERSION = 2 as const;\nexport const BILLING_SUBSCRIPTION_RECONCILE_SCHEMA_VERSION = 1 as const;\nexport const BILLING_SUBSCRIPTION_RECONCILE_QUEUE_NAME = \"billing-subscription-reconcile\";\nexport const BILLING_SUBSCRIPTION_RECONCILE_JOB_NAME = \"reconcile-subscription\";\nexport const APP_PRICING_BILLING_PERIOD_DRAIN_WINDOW_MS = 300000 as const;\n\nconst SHOPIFY_PROVIDER_CONTEXT_INVALID_PREFIX = \"SHOPIFY_PROVIDER_CONTEXT_INVALID:\";\n\nexport type ShopifyProviderContextIdentityInput = Readonly<{\n providerSubscriptionId: string | null;\n planHandle: string;\n currentPeriodStart: Date | string | null;\n currentPeriodEnd: Date | string | null;\n}>;\n\nexport type ShopifyPurchaseProviderContext = Readonly<{\n providerContextIdentity: string;\n shopifyPlanHandleSnapshot: string;\n billingPeriodId: string;\n}>;\n\nexport type ShopifyCurrentProviderContext = Readonly<{\n providerContextIdentity: string;\n shopifyPlanHandle: string;\n billingPeriodId: string;\n}>;\n\nfunction invalidShopifyProviderContext(reason: string): never {\n throw new Error(`${SHOPIFY_PROVIDER_CONTEXT_INVALID_PREFIX}${reason}`);\n}\n\nfunction normalizeShopifyProviderContextDate(\n name: string,\n value: Date | string | null,\n): Date {\n if (value === null || (typeof value !== \"string\" && !(value instanceof Date))) {\n return invalidShopifyProviderContext(`${name} must be a valid date`);\n }\n\n const date = value instanceof Date ? new Date(value.getTime()) : new Date(value);\n if (Number.isNaN(date.getTime())) {\n return invalidShopifyProviderContext(`${name} must be a valid date`);\n }\n return date;\n}\n\nexport function deriveShopifyProviderContextIdentity(\n input: ShopifyProviderContextIdentityInput,\n): string {\n const providerSubscriptionId = typeof input.providerSubscriptionId === \"string\"\n ? input.providerSubscriptionId.trim()\n : \"\";\n if (providerSubscriptionId) return providerSubscriptionId;\n\n if (typeof input.planHandle !== \"string\" || input.planHandle.trim().length === 0) {\n return invalidShopifyProviderContext(\"planHandle must be a non-empty string\");\n }\n\n const start = normalizeShopifyProviderContextDate(\"currentPeriodStart\", input.currentPeriodStart);\n const end = normalizeShopifyProviderContextDate(\"currentPeriodEnd\", input.currentPeriodEnd);\n if (start >= end) {\n return invalidShopifyProviderContext(\"currentPeriodStart must be before currentPeriodEnd\");\n }\n\n return `app-pricing:v1:${encodeURIComponent(input.planHandle.trim())}:${start.toISOString()}:${end.toISOString()}`;\n}\n\nexport function isSameShopifyPurchaseProviderContext(\n purchase: ShopifyPurchaseProviderContext,\n current: ShopifyCurrentProviderContext,\n): boolean {\n return [\n [purchase.providerContextIdentity, current.providerContextIdentity],\n [purchase.shopifyPlanHandleSnapshot, current.shopifyPlanHandle],\n [purchase.billingPeriodId, current.billingPeriodId],\n ].every(([purchaseValue, currentValue]) =>\n typeof purchaseValue === \"string\"\n && typeof currentValue === \"string\"\n && purchaseValue.trim().length > 0\n && currentValue.trim().length > 0\n && purchaseValue.trim() === currentValue.trim(),\n );\n}\n\nexport const BILLING_PLAN_KINDS = [\"FREE\", \"PAID_METERED\"] as const;\nexport const BillingPlanKindSchema = z.enum(BILLING_PLAN_KINDS);\nexport type BillingPlanKind = z.infer<typeof BillingPlanKindSchema>;\n\nexport const BILLING_USAGE_METRICS = [\n \"RECOVERY_CONVERSATION\",\n \"OUTBOUND_AUTOMATED_MESSAGE\",\n \"DELIVERED_WHATSAPP_MESSAGE\",\n \"RECOVERY_CREDIT_PACK_PURCHASE\",\n] as const;\nexport const BillingUsageMetricSchema = z.enum(BILLING_USAGE_METRICS);\nexport type BillingUsageMetric = z.infer<typeof BillingUsageMetricSchema>;\n\nexport const BILLING_SYSTEM_MESSAGE_CODES = {\n FREE_ALLOWANCE_WARNING: \"BILLING_FREE_ALLOWANCE_WARNING\",\n RECOVERY_CAPACITY_EXHAUSTED: \"BILLING_RECOVERY_CAPACITY_EXHAUSTED\",\n PLAN_UPGRADED: \"BILLING_PLAN_UPGRADED\",\n PLAN_DOWNGRADE_SCHEDULED: \"BILLING_PLAN_DOWNGRADE_SCHEDULED\",\n SUBSCRIPTION_ENDED: \"BILLING_SUBSCRIPTION_ENDED\",\n SAFETY_LIMIT_REACHED: \"BILLING_SAFETY_LIMIT_REACHED\",\n REFUND_REQUEST_RECEIVED: \"BILLING_REFUND_REQUEST_RECEIVED\",\n REFUND_COMPLETED: \"BILLING_REFUND_COMPLETED\",\n REFUND_REJECTED: \"BILLING_REFUND_REJECTED\",\n} as const;\n\nconst BILLING_SYSTEM_MESSAGE_CODE_VALUES = [\n BILLING_SYSTEM_MESSAGE_CODES.FREE_ALLOWANCE_WARNING,\n BILLING_SYSTEM_MESSAGE_CODES.RECOVERY_CAPACITY_EXHAUSTED,\n BILLING_SYSTEM_MESSAGE_CODES.PLAN_UPGRADED,\n BILLING_SYSTEM_MESSAGE_CODES.PLAN_DOWNGRADE_SCHEDULED,\n BILLING_SYSTEM_MESSAGE_CODES.SUBSCRIPTION_ENDED,\n BILLING_SYSTEM_MESSAGE_CODES.SAFETY_LIMIT_REACHED,\n BILLING_SYSTEM_MESSAGE_CODES.REFUND_REQUEST_RECEIVED,\n BILLING_SYSTEM_MESSAGE_CODES.REFUND_COMPLETED,\n BILLING_SYSTEM_MESSAGE_CODES.REFUND_REJECTED,\n] as const;\n\nexport const BillingSystemMessageCodeSchema = z.enum(BILLING_SYSTEM_MESSAGE_CODE_VALUES);\nexport type BillingSystemMessageCode = z.infer<typeof BillingSystemMessageCodeSchema>;\n\nexport type PurchasedRecoveryCreditCounterSnapshot = Readonly<{\n grantedQuantity: number;\n committedQuantity: number;\n reservedQuantity: number;\n refundingQuantity: number;\n}>;\n\nexport function availablePurchasedRecoveryCredits(\n counter: PurchasedRecoveryCreditCounterSnapshot,\n): number {\n for (const [name, value] of Object.entries(counter)) {\n if (!Number.isInteger(value) || value < 0) {\n throw new Error(`${name} must be a non-negative integer`);\n }\n }\n\n return Math.max(\n counter.grantedQuantity\n - counter.committedQuantity\n - counter.reservedQuantity\n - counter.refundingQuantity,\n 0,\n );\n}\n\nexport const WHATSAPP_PROVIDER_STATUSES = [\n \"SENT\",\n \"DELIVERED\",\n \"READ\",\n \"FAILED\",\n] as const;\nexport const WhatsAppProviderStatusSchema = z.enum(WHATSAPP_PROVIDER_STATUSES);\nexport type WhatsAppProviderStatus = z.infer<typeof WhatsAppProviderStatusSchema>;\n\nconst MAX_ID_LENGTH = 128;\nconst MAX_SHORT_TEXT_LENGTH = 128;\n\nexport const BillingSubscriptionReconcileJobSchema = z\n .object({\n schemaVersion: z.literal(BILLING_SUBSCRIPTION_RECONCILE_SCHEMA_VERSION),\n shopId: z.string().trim().min(1).max(MAX_ID_LENGTH),\n subscriptionId: z.string().trim().min(1).max(MAX_ID_LENGTH),\n expectedNextReconcileAt: z.iso.datetime({ offset: true }),\n })\n .strict();\n\nexport type BillingSubscriptionReconcileJob = z.infer<\n typeof BillingSubscriptionReconcileJobSchema\n>;\n\nexport function parseBillingSubscriptionReconcileJob(\n input: unknown,\n): BillingSubscriptionReconcileJob {\n return BillingSubscriptionReconcileJobSchema.parse(input);\n}\n\nexport function safeParseBillingSubscriptionReconcileJob(input: unknown) {\n return BillingSubscriptionReconcileJobSchema.safeParse(input);\n}\n\nexport const WhatsAppProviderPricingMetadataSchema = z\n .object({\n billable: z.boolean().optional(),\n category: z.string().trim().min(1).max(MAX_SHORT_TEXT_LENGTH).optional(),\n model: z.string().trim().min(1).max(MAX_SHORT_TEXT_LENGTH).optional(),\n })\n .strict()\n .refine((value) => Object.keys(value).length > 0, \"pricing metadata must not be empty\");\n\nexport type WhatsAppProviderPricingMetadata = z.infer<\n typeof WhatsAppProviderPricingMetadataSchema\n>;\n\nexport const NormalizedWhatsAppStatusSchema = z\n .object({\n schemaVersion: z.literal(WHATSAPP_PROVIDER_STATUS_SCHEMA_VERSION),\n providerAccountId: z.string().trim().min(1).max(MAX_ID_LENGTH),\n providerPhoneNumberId: z.string().trim().min(1).max(MAX_ID_LENGTH),\n providerMessageId: z.string().trim().min(1).max(MAX_ID_LENGTH),\n status: WhatsAppProviderStatusSchema,\n occurredAt: z.iso.datetime({ offset: true }),\n pricing: WhatsAppProviderPricingMetadataSchema.optional(),\n })\n .strict();\n\nexport type NormalizedWhatsAppStatus = z.infer<typeof NormalizedWhatsAppStatusSchema>;\n\nexport function parseNormalizedWhatsAppStatus(input: unknown): NormalizedWhatsAppStatus {\n return NormalizedWhatsAppStatusSchema.parse(input);\n}\n\nexport function safeParseNormalizedWhatsAppStatus(input: unknown) {\n return NormalizedWhatsAppStatusSchema.safeParse(input);\n}\n\nfunction assertKeyPart(name: string, value: string): void {\n if (typeof value !== \"string\" || value.trim().length === 0) {\n throw new Error(`${name} must be a non-empty string`);\n }\n}\n\nfunction fnv1a64(value: string): string {\n let hash = 0xcbf29ce484222325n;\n for (const character of value) {\n hash ^= BigInt(character.codePointAt(0) ?? 0);\n hash = BigInt.asUintN(64, hash * 0x100000001b3n);\n }\n return hash.toString(16).padStart(16, \"0\");\n}\n\nexport function createBillingSubscriptionReconcileJobId(\n subscriptionId: string,\n expectedNextReconcileAt: string,\n): string {\n assertKeyPart(\"subscriptionId\", subscriptionId);\n if (subscriptionId.trim().length > MAX_ID_LENGTH) {\n throw new Error(`subscriptionId must be at most ${MAX_ID_LENGTH} characters`);\n }\n z.iso.datetime({ offset: true }).parse(expectedNextReconcileAt);\n return `billing-subscription-reconcile-${fnv1a64(`${subscriptionId.trim()}\\u0000${expectedNextReconcileAt}`)}`;\n}\n\nfunction boundedKey(prefix: string, parts: string[], maxLength: number): string {\n const canonical = parts.map((part) => part.trim()).join(\":\");\n const readable = `${prefix}:${canonical}`;\n if (readable.length <= maxLength) return readable;\n return `${prefix}:h${fnv1a64(canonical)}`;\n}\n\nexport function createMerchantBillingSystemSourceKey(\n shopId: string,\n code: BillingSystemMessageCode,\n eventIdentity: string,\n version = 1,\n): string {\n assertKeyPart(\"shopId\", shopId);\n assertKeyPart(\"code\", code);\n assertKeyPart(\"eventIdentity\", eventIdentity);\n if (!Number.isInteger(version) || version < 1) {\n throw new Error(\"version must be a positive integer\");\n }\n return boundedKey(\"billing-system\", [shopId, code, eventIdentity, String(version)], 255);\n}\n\nexport function createRecoveryIdempotencyKey(shopId: string, recoveryId: string): string {\n assertKeyPart(\"shopId\", shopId);\n assertKeyPart(\"recoveryId\", recoveryId);\n return boundedKey(\"recovery\", [shopId, recoveryId], 255);\n}\n\nexport function createShopifyUsageIdempotencyKey(\n shopId: string,\n usageEventId: string,\n): string {\n assertKeyPart(\"shopId\", shopId);\n assertKeyPart(\"usageEventId\", usageEventId);\n return boundedKey(\"shopify\", [shopId, usageEventId], 64);\n}"],"mappings":"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","names":[]}
|
package/dist/index.js
CHANGED
|
@@ -27,7 +27,7 @@ import {
|
|
|
27
27
|
parseNormalizedWhatsAppStatus,
|
|
28
28
|
safeParseBillingSubscriptionReconcileJob,
|
|
29
29
|
safeParseNormalizedWhatsAppStatus
|
|
30
|
-
} from "./chunk-
|
|
30
|
+
} from "./chunk-ANBEH6NW.js";
|
|
31
31
|
import {
|
|
32
32
|
AuthoredSupportBodySchema,
|
|
33
33
|
MERCHANT_COMMUNICATIONS_JOB_NAMES,
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
|
|
3
|
+
declare const WHATSAPP_INBOUND_MESSAGE_SCHEMA_VERSION: 1;
|
|
4
|
+
declare const WhatsAppInboundContentSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
5
|
+
type: z.ZodLiteral<"text">;
|
|
6
|
+
text: z.ZodString;
|
|
7
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
8
|
+
type: z.ZodLiteral<"audio">;
|
|
9
|
+
mediaId: z.ZodString;
|
|
10
|
+
mimeType: z.ZodNullable<z.ZodString>;
|
|
11
|
+
sha256: z.ZodNullable<z.ZodString>;
|
|
12
|
+
voice: z.ZodNullable<z.ZodBoolean>;
|
|
13
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
14
|
+
type: z.ZodLiteral<"unsupported">;
|
|
15
|
+
providerType: z.ZodString;
|
|
16
|
+
}, z.core.$strict>], "type">;
|
|
17
|
+
declare const NormalizedWhatsAppInboundMessageSchema: z.ZodObject<{
|
|
18
|
+
schemaVersion: z.ZodLiteral<1>;
|
|
19
|
+
provider: z.ZodLiteral<"whatsapp">;
|
|
20
|
+
providerAccountId: z.ZodString;
|
|
21
|
+
providerPhoneNumberId: z.ZodString;
|
|
22
|
+
providerMessageId: z.ZodString;
|
|
23
|
+
customerPhone: z.ZodString;
|
|
24
|
+
contextMessageId: z.ZodNullable<z.ZodString>;
|
|
25
|
+
occurredAt: z.ZodISODateTime;
|
|
26
|
+
content: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
27
|
+
type: z.ZodLiteral<"text">;
|
|
28
|
+
text: z.ZodString;
|
|
29
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
30
|
+
type: z.ZodLiteral<"audio">;
|
|
31
|
+
mediaId: z.ZodString;
|
|
32
|
+
mimeType: z.ZodNullable<z.ZodString>;
|
|
33
|
+
sha256: z.ZodNullable<z.ZodString>;
|
|
34
|
+
voice: z.ZodNullable<z.ZodBoolean>;
|
|
35
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
36
|
+
type: z.ZodLiteral<"unsupported">;
|
|
37
|
+
providerType: z.ZodString;
|
|
38
|
+
}, z.core.$strict>], "type">;
|
|
39
|
+
}, z.core.$strict>;
|
|
40
|
+
type WhatsAppInboundContent = z.infer<typeof WhatsAppInboundContentSchema>;
|
|
41
|
+
type NormalizedWhatsAppInboundMessage = z.infer<typeof NormalizedWhatsAppInboundMessageSchema>;
|
|
42
|
+
declare function parseNormalizedWhatsAppInboundMessage(input: unknown): NormalizedWhatsAppInboundMessage;
|
|
43
|
+
declare function safeParseNormalizedWhatsAppInboundMessage(input: unknown): z.ZodSafeParseResult<{
|
|
44
|
+
schemaVersion: 1;
|
|
45
|
+
provider: "whatsapp";
|
|
46
|
+
providerAccountId: string;
|
|
47
|
+
providerPhoneNumberId: string;
|
|
48
|
+
providerMessageId: string;
|
|
49
|
+
customerPhone: string;
|
|
50
|
+
contextMessageId: string | null;
|
|
51
|
+
occurredAt: string;
|
|
52
|
+
content: {
|
|
53
|
+
type: "text";
|
|
54
|
+
text: string;
|
|
55
|
+
} | {
|
|
56
|
+
type: "audio";
|
|
57
|
+
mediaId: string;
|
|
58
|
+
mimeType: string | null;
|
|
59
|
+
sha256: string | null;
|
|
60
|
+
voice: boolean | null;
|
|
61
|
+
} | {
|
|
62
|
+
type: "unsupported";
|
|
63
|
+
providerType: string;
|
|
64
|
+
};
|
|
65
|
+
}>;
|
|
66
|
+
|
|
67
|
+
export { type NormalizedWhatsAppInboundMessage, NormalizedWhatsAppInboundMessageSchema, WHATSAPP_INBOUND_MESSAGE_SCHEMA_VERSION, type WhatsAppInboundContent, WhatsAppInboundContentSchema, parseNormalizedWhatsAppInboundMessage, safeParseNormalizedWhatsAppInboundMessage };
|
package/dist/whatsapp.js
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
// src/whatsapp.ts
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
var WHATSAPP_INBOUND_MESSAGE_SCHEMA_VERSION = 1;
|
|
4
|
+
var MAX_IDENTIFIER_LENGTH = 256;
|
|
5
|
+
var MAX_CUSTOMER_PHONE_LENGTH = 64;
|
|
6
|
+
var MAX_TEXT_LENGTH = 4096;
|
|
7
|
+
var boundedIdentifier = (max = MAX_IDENTIFIER_LENGTH) => z.string().trim().min(1).max(max);
|
|
8
|
+
var textContentSchema = z.object({
|
|
9
|
+
type: z.literal("text"),
|
|
10
|
+
text: z.string().trim().min(1).max(MAX_TEXT_LENGTH)
|
|
11
|
+
}).strict();
|
|
12
|
+
var audioContentSchema = z.object({
|
|
13
|
+
type: z.literal("audio"),
|
|
14
|
+
mediaId: boundedIdentifier(),
|
|
15
|
+
mimeType: z.string().trim().min(1).max(MAX_IDENTIFIER_LENGTH).nullable(),
|
|
16
|
+
sha256: z.string().trim().min(1).max(MAX_IDENTIFIER_LENGTH).nullable(),
|
|
17
|
+
voice: z.boolean().nullable()
|
|
18
|
+
}).strict();
|
|
19
|
+
var unsupportedContentSchema = z.object({
|
|
20
|
+
type: z.literal("unsupported"),
|
|
21
|
+
providerType: boundedIdentifier()
|
|
22
|
+
}).strict();
|
|
23
|
+
var WhatsAppInboundContentSchema = z.discriminatedUnion("type", [
|
|
24
|
+
textContentSchema,
|
|
25
|
+
audioContentSchema,
|
|
26
|
+
unsupportedContentSchema
|
|
27
|
+
]);
|
|
28
|
+
var NormalizedWhatsAppInboundMessageSchema = z.object({
|
|
29
|
+
schemaVersion: z.literal(WHATSAPP_INBOUND_MESSAGE_SCHEMA_VERSION),
|
|
30
|
+
provider: z.literal("whatsapp"),
|
|
31
|
+
providerAccountId: boundedIdentifier(),
|
|
32
|
+
providerPhoneNumberId: boundedIdentifier(),
|
|
33
|
+
providerMessageId: boundedIdentifier(),
|
|
34
|
+
customerPhone: boundedIdentifier(MAX_CUSTOMER_PHONE_LENGTH),
|
|
35
|
+
contextMessageId: boundedIdentifier().nullable(),
|
|
36
|
+
occurredAt: z.iso.datetime({ offset: true }),
|
|
37
|
+
content: WhatsAppInboundContentSchema
|
|
38
|
+
}).strict();
|
|
39
|
+
function parseNormalizedWhatsAppInboundMessage(input) {
|
|
40
|
+
return NormalizedWhatsAppInboundMessageSchema.parse(input);
|
|
41
|
+
}
|
|
42
|
+
function safeParseNormalizedWhatsAppInboundMessage(input) {
|
|
43
|
+
return NormalizedWhatsAppInboundMessageSchema.safeParse(input);
|
|
44
|
+
}
|
|
45
|
+
export {
|
|
46
|
+
NormalizedWhatsAppInboundMessageSchema,
|
|
47
|
+
WHATSAPP_INBOUND_MESSAGE_SCHEMA_VERSION,
|
|
48
|
+
WhatsAppInboundContentSchema,
|
|
49
|
+
parseNormalizedWhatsAppInboundMessage,
|
|
50
|
+
safeParseNormalizedWhatsAppInboundMessage
|
|
51
|
+
};
|
|
52
|
+
//# sourceMappingURL=whatsapp.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/whatsapp.ts"],"sourcesContent":["import { z } from \"zod\";\n\nexport const WHATSAPP_INBOUND_MESSAGE_SCHEMA_VERSION = 1 as const;\n\nconst MAX_IDENTIFIER_LENGTH = 256;\nconst MAX_CUSTOMER_PHONE_LENGTH = 64;\nconst MAX_TEXT_LENGTH = 4096;\n\nconst boundedIdentifier = (max: number = MAX_IDENTIFIER_LENGTH) =>\n z.string().trim().min(1).max(max);\n\nconst textContentSchema = z\n .object({\n type: z.literal(\"text\"),\n text: z.string().trim().min(1).max(MAX_TEXT_LENGTH),\n })\n .strict();\n\nconst audioContentSchema = z\n .object({\n type: z.literal(\"audio\"),\n mediaId: boundedIdentifier(),\n mimeType: z.string().trim().min(1).max(MAX_IDENTIFIER_LENGTH).nullable(),\n sha256: z.string().trim().min(1).max(MAX_IDENTIFIER_LENGTH).nullable(),\n voice: z.boolean().nullable(),\n })\n .strict();\n\nconst unsupportedContentSchema = z\n .object({\n type: z.literal(\"unsupported\"),\n providerType: boundedIdentifier(),\n })\n .strict();\n\nexport const WhatsAppInboundContentSchema = z.discriminatedUnion(\"type\", [\n textContentSchema,\n audioContentSchema,\n unsupportedContentSchema,\n]);\n\nexport const NormalizedWhatsAppInboundMessageSchema = z\n .object({\n schemaVersion: z.literal(WHATSAPP_INBOUND_MESSAGE_SCHEMA_VERSION),\n provider: z.literal(\"whatsapp\"),\n providerAccountId: boundedIdentifier(),\n providerPhoneNumberId: boundedIdentifier(),\n providerMessageId: boundedIdentifier(),\n customerPhone: boundedIdentifier(MAX_CUSTOMER_PHONE_LENGTH),\n contextMessageId: boundedIdentifier().nullable(),\n occurredAt: z.iso.datetime({ offset: true }),\n content: WhatsAppInboundContentSchema,\n })\n .strict();\n\nexport type WhatsAppInboundContent = z.infer<typeof WhatsAppInboundContentSchema>;\nexport type NormalizedWhatsAppInboundMessage = z.infer<\n typeof NormalizedWhatsAppInboundMessageSchema\n>;\n\nexport function parseNormalizedWhatsAppInboundMessage(\n input: unknown,\n): NormalizedWhatsAppInboundMessage {\n return NormalizedWhatsAppInboundMessageSchema.parse(input);\n}\n\nexport function safeParseNormalizedWhatsAppInboundMessage(input: unknown) {\n return NormalizedWhatsAppInboundMessageSchema.safeParse(input);\n}"],"mappings":";AAAA,SAAS,SAAS;AAEX,IAAM,0CAA0C;AAEvD,IAAM,wBAAwB;AAC9B,IAAM,4BAA4B;AAClC,IAAM,kBAAkB;AAExB,IAAM,oBAAoB,CAAC,MAAc,0BACvC,EAAE,OAAO,EAAE,KAAK,EAAE,IAAI,CAAC,EAAE,IAAI,GAAG;AAElC,IAAM,oBAAoB,EACvB,OAAO;AAAA,EACN,MAAM,EAAE,QAAQ,MAAM;AAAA,EACtB,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,IAAI,CAAC,EAAE,IAAI,eAAe;AACpD,CAAC,EACA,OAAO;AAEV,IAAM,qBAAqB,EACxB,OAAO;AAAA,EACN,MAAM,EAAE,QAAQ,OAAO;AAAA,EACvB,SAAS,kBAAkB;AAAA,EAC3B,UAAU,EAAE,OAAO,EAAE,KAAK,EAAE,IAAI,CAAC,EAAE,IAAI,qBAAqB,EAAE,SAAS;AAAA,EACvE,QAAQ,EAAE,OAAO,EAAE,KAAK,EAAE,IAAI,CAAC,EAAE,IAAI,qBAAqB,EAAE,SAAS;AAAA,EACrE,OAAO,EAAE,QAAQ,EAAE,SAAS;AAC9B,CAAC,EACA,OAAO;AAEV,IAAM,2BAA2B,EAC9B,OAAO;AAAA,EACN,MAAM,EAAE,QAAQ,aAAa;AAAA,EAC7B,cAAc,kBAAkB;AAClC,CAAC,EACA,OAAO;AAEH,IAAM,+BAA+B,EAAE,mBAAmB,QAAQ;AAAA,EACvE;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAEM,IAAM,yCAAyC,EACnD,OAAO;AAAA,EACN,eAAe,EAAE,QAAQ,uCAAuC;AAAA,EAChE,UAAU,EAAE,QAAQ,UAAU;AAAA,EAC9B,mBAAmB,kBAAkB;AAAA,EACrC,uBAAuB,kBAAkB;AAAA,EACzC,mBAAmB,kBAAkB;AAAA,EACrC,eAAe,kBAAkB,yBAAyB;AAAA,EAC1D,kBAAkB,kBAAkB,EAAE,SAAS;AAAA,EAC/C,YAAY,EAAE,IAAI,SAAS,EAAE,QAAQ,KAAK,CAAC;AAAA,EAC3C,SAAS;AACX,CAAC,EACA,OAAO;AAOH,SAAS,sCACd,OACkC;AAClC,SAAO,uCAAuC,MAAM,KAAK;AAC3D;AAEO,SAAS,0CAA0C,OAAgB;AACxE,SAAO,uCAAuC,UAAU,KAAK;AAC/D;","names":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@modainteract/moda-interact-shared",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.12.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
@@ -20,6 +20,10 @@
|
|
|
20
20
|
"types": "./dist/billing.d.ts",
|
|
21
21
|
"import": "./dist/billing.js"
|
|
22
22
|
},
|
|
23
|
+
"./whatsapp": {
|
|
24
|
+
"types": "./dist/whatsapp.d.ts",
|
|
25
|
+
"import": "./dist/whatsapp.js"
|
|
26
|
+
},
|
|
23
27
|
"./merchant-communications": {
|
|
24
28
|
"types": "./dist/merchant-communications.d.ts",
|
|
25
29
|
"import": "./dist/merchant-communications.js"
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/billing.ts"],"sourcesContent":["import { z } from \"zod\";\n\nexport const ARCH007_BILLING_CONTRACT_SCHEMA_VERSION = 1 as const;\nexport const WHATSAPP_PROVIDER_STATUS_SCHEMA_VERSION = 2 as const;\nexport const BILLING_SUBSCRIPTION_RECONCILE_SCHEMA_VERSION = 1 as const;\nexport const BILLING_SUBSCRIPTION_RECONCILE_QUEUE_NAME = \"billing-subscription-reconcile\";\nexport const BILLING_SUBSCRIPTION_RECONCILE_JOB_NAME = \"reconcile-subscription\";\nexport const APP_PRICING_BILLING_PERIOD_DRAIN_WINDOW_MS = 300000 as const;\n\nconst SHOPIFY_PROVIDER_CONTEXT_INVALID_PREFIX = \"SHOPIFY_PROVIDER_CONTEXT_INVALID:\";\n\nexport type ShopifyProviderContextIdentityInput = Readonly<{\n providerSubscriptionId: string | null;\n planHandle: string;\n currentPeriodStart: Date | string | null;\n currentPeriodEnd: Date | string | null;\n}>;\n\nexport type ShopifyPurchaseProviderContext = Readonly<{\n providerContextIdentity: string;\n shopifyPlanHandleSnapshot: string;\n billingPeriodId: string;\n}>;\n\nexport type ShopifyCurrentProviderContext = Readonly<{\n providerContextIdentity: string;\n shopifyPlanHandle: string;\n billingPeriodId: string;\n}>;\n\nfunction invalidShopifyProviderContext(reason: string): never {\n throw new Error(`${SHOPIFY_PROVIDER_CONTEXT_INVALID_PREFIX}${reason}`);\n}\n\nfunction normalizeShopifyProviderContextDate(\n name: string,\n value: Date | string | null,\n): Date {\n if (value === null || (typeof value !== \"string\" && !(value instanceof Date))) {\n return invalidShopifyProviderContext(`${name} must be a valid date`);\n }\n\n const date = value instanceof Date ? new Date(value.getTime()) : new Date(value);\n if (Number.isNaN(date.getTime())) {\n return invalidShopifyProviderContext(`${name} must be a valid date`);\n }\n return date;\n}\n\nexport function deriveShopifyProviderContextIdentity(\n input: ShopifyProviderContextIdentityInput,\n): string {\n const providerSubscriptionId = typeof input.providerSubscriptionId === \"string\"\n ? input.providerSubscriptionId.trim()\n : \"\";\n if (providerSubscriptionId) return providerSubscriptionId;\n\n if (typeof input.planHandle !== \"string\" || input.planHandle.trim().length === 0) {\n return invalidShopifyProviderContext(\"planHandle must be a non-empty string\");\n }\n\n const start = normalizeShopifyProviderContextDate(\"currentPeriodStart\", input.currentPeriodStart);\n const end = normalizeShopifyProviderContextDate(\"currentPeriodEnd\", input.currentPeriodEnd);\n if (start >= end) {\n return invalidShopifyProviderContext(\"currentPeriodStart must be before currentPeriodEnd\");\n }\n\n return `app-pricing:v1:${encodeURIComponent(input.planHandle.trim())}:${start.toISOString()}:${end.toISOString()}`;\n}\n\nexport function isSameShopifyPurchaseProviderContext(\n purchase: ShopifyPurchaseProviderContext,\n current: ShopifyCurrentProviderContext,\n): boolean {\n return [\n [purchase.providerContextIdentity, current.providerContextIdentity],\n [purchase.shopifyPlanHandleSnapshot, current.shopifyPlanHandle],\n [purchase.billingPeriodId, current.billingPeriodId],\n ].every(([purchaseValue, currentValue]) =>\n typeof purchaseValue === \"string\"\n && typeof currentValue === \"string\"\n && purchaseValue.trim() === currentValue.trim(),\n );\n}\n\nexport const BILLING_PLAN_KINDS = [\"FREE\", \"PAID_METERED\"] as const;\nexport const BillingPlanKindSchema = z.enum(BILLING_PLAN_KINDS);\nexport type BillingPlanKind = z.infer<typeof BillingPlanKindSchema>;\n\nexport const BILLING_USAGE_METRICS = [\n \"RECOVERY_CONVERSATION\",\n \"OUTBOUND_AUTOMATED_MESSAGE\",\n \"DELIVERED_WHATSAPP_MESSAGE\",\n \"RECOVERY_CREDIT_PACK_PURCHASE\",\n] as const;\nexport const BillingUsageMetricSchema = z.enum(BILLING_USAGE_METRICS);\nexport type BillingUsageMetric = z.infer<typeof BillingUsageMetricSchema>;\n\nexport const BILLING_SYSTEM_MESSAGE_CODES = {\n FREE_ALLOWANCE_WARNING: \"BILLING_FREE_ALLOWANCE_WARNING\",\n RECOVERY_CAPACITY_EXHAUSTED: \"BILLING_RECOVERY_CAPACITY_EXHAUSTED\",\n PLAN_UPGRADED: \"BILLING_PLAN_UPGRADED\",\n PLAN_DOWNGRADE_SCHEDULED: \"BILLING_PLAN_DOWNGRADE_SCHEDULED\",\n SUBSCRIPTION_ENDED: \"BILLING_SUBSCRIPTION_ENDED\",\n SAFETY_LIMIT_REACHED: \"BILLING_SAFETY_LIMIT_REACHED\",\n REFUND_REQUEST_RECEIVED: \"BILLING_REFUND_REQUEST_RECEIVED\",\n REFUND_COMPLETED: \"BILLING_REFUND_COMPLETED\",\n REFUND_REJECTED: \"BILLING_REFUND_REJECTED\",\n} as const;\n\nconst BILLING_SYSTEM_MESSAGE_CODE_VALUES = [\n BILLING_SYSTEM_MESSAGE_CODES.FREE_ALLOWANCE_WARNING,\n BILLING_SYSTEM_MESSAGE_CODES.RECOVERY_CAPACITY_EXHAUSTED,\n BILLING_SYSTEM_MESSAGE_CODES.PLAN_UPGRADED,\n BILLING_SYSTEM_MESSAGE_CODES.PLAN_DOWNGRADE_SCHEDULED,\n BILLING_SYSTEM_MESSAGE_CODES.SUBSCRIPTION_ENDED,\n BILLING_SYSTEM_MESSAGE_CODES.SAFETY_LIMIT_REACHED,\n BILLING_SYSTEM_MESSAGE_CODES.REFUND_REQUEST_RECEIVED,\n BILLING_SYSTEM_MESSAGE_CODES.REFUND_COMPLETED,\n BILLING_SYSTEM_MESSAGE_CODES.REFUND_REJECTED,\n] as const;\n\nexport const BillingSystemMessageCodeSchema = z.enum(BILLING_SYSTEM_MESSAGE_CODE_VALUES);\nexport type BillingSystemMessageCode = z.infer<typeof BillingSystemMessageCodeSchema>;\n\nexport type PurchasedRecoveryCreditCounterSnapshot = Readonly<{\n grantedQuantity: number;\n committedQuantity: number;\n reservedQuantity: number;\n refundingQuantity: number;\n}>;\n\nexport function availablePurchasedRecoveryCredits(\n counter: PurchasedRecoveryCreditCounterSnapshot,\n): number {\n for (const [name, value] of Object.entries(counter)) {\n if (!Number.isInteger(value) || value < 0) {\n throw new Error(`${name} must be a non-negative integer`);\n }\n }\n\n return Math.max(\n counter.grantedQuantity\n - counter.committedQuantity\n - counter.reservedQuantity\n - counter.refundingQuantity,\n 0,\n );\n}\n\nexport const WHATSAPP_PROVIDER_STATUSES = [\n \"SENT\",\n \"DELIVERED\",\n \"READ\",\n \"FAILED\",\n] as const;\nexport const WhatsAppProviderStatusSchema = z.enum(WHATSAPP_PROVIDER_STATUSES);\nexport type WhatsAppProviderStatus = z.infer<typeof WhatsAppProviderStatusSchema>;\n\nconst MAX_ID_LENGTH = 128;\nconst MAX_SHORT_TEXT_LENGTH = 128;\n\nexport const BillingSubscriptionReconcileJobSchema = z\n .object({\n schemaVersion: z.literal(BILLING_SUBSCRIPTION_RECONCILE_SCHEMA_VERSION),\n shopId: z.string().trim().min(1).max(MAX_ID_LENGTH),\n subscriptionId: z.string().trim().min(1).max(MAX_ID_LENGTH),\n expectedNextReconcileAt: z.iso.datetime({ offset: true }),\n })\n .strict();\n\nexport type BillingSubscriptionReconcileJob = z.infer<\n typeof BillingSubscriptionReconcileJobSchema\n>;\n\nexport function parseBillingSubscriptionReconcileJob(\n input: unknown,\n): BillingSubscriptionReconcileJob {\n return BillingSubscriptionReconcileJobSchema.parse(input);\n}\n\nexport function safeParseBillingSubscriptionReconcileJob(input: unknown) {\n return BillingSubscriptionReconcileJobSchema.safeParse(input);\n}\n\nexport const WhatsAppProviderPricingMetadataSchema = z\n .object({\n billable: z.boolean().optional(),\n category: z.string().trim().min(1).max(MAX_SHORT_TEXT_LENGTH).optional(),\n model: z.string().trim().min(1).max(MAX_SHORT_TEXT_LENGTH).optional(),\n })\n .strict()\n .refine((value) => Object.keys(value).length > 0, \"pricing metadata must not be empty\");\n\nexport type WhatsAppProviderPricingMetadata = z.infer<\n typeof WhatsAppProviderPricingMetadataSchema\n>;\n\nexport const NormalizedWhatsAppStatusSchema = z\n .object({\n schemaVersion: z.literal(WHATSAPP_PROVIDER_STATUS_SCHEMA_VERSION),\n providerAccountId: z.string().trim().min(1).max(MAX_ID_LENGTH),\n providerPhoneNumberId: z.string().trim().min(1).max(MAX_ID_LENGTH),\n providerMessageId: z.string().trim().min(1).max(MAX_ID_LENGTH),\n status: WhatsAppProviderStatusSchema,\n occurredAt: z.iso.datetime({ offset: true }),\n pricing: WhatsAppProviderPricingMetadataSchema.optional(),\n })\n .strict();\n\nexport type NormalizedWhatsAppStatus = z.infer<typeof NormalizedWhatsAppStatusSchema>;\n\nexport function parseNormalizedWhatsAppStatus(input: unknown): NormalizedWhatsAppStatus {\n return NormalizedWhatsAppStatusSchema.parse(input);\n}\n\nexport function safeParseNormalizedWhatsAppStatus(input: unknown) {\n return NormalizedWhatsAppStatusSchema.safeParse(input);\n}\n\nfunction assertKeyPart(name: string, value: string): void {\n if (typeof value !== \"string\" || value.trim().length === 0) {\n throw new Error(`${name} must be a non-empty string`);\n }\n}\n\nfunction fnv1a64(value: string): string {\n let hash = 0xcbf29ce484222325n;\n for (const character of value) {\n hash ^= BigInt(character.codePointAt(0) ?? 0);\n hash = BigInt.asUintN(64, hash * 0x100000001b3n);\n }\n return hash.toString(16).padStart(16, \"0\");\n}\n\nexport function createBillingSubscriptionReconcileJobId(\n subscriptionId: string,\n expectedNextReconcileAt: string,\n): string {\n assertKeyPart(\"subscriptionId\", subscriptionId);\n if (subscriptionId.trim().length > MAX_ID_LENGTH) {\n throw new Error(`subscriptionId must be at most ${MAX_ID_LENGTH} characters`);\n }\n z.iso.datetime({ offset: true }).parse(expectedNextReconcileAt);\n return `billing-subscription-reconcile-${fnv1a64(`${subscriptionId.trim()}\\u0000${expectedNextReconcileAt}`)}`;\n}\n\nfunction boundedKey(prefix: string, parts: string[], maxLength: number): string {\n const canonical = parts.map((part) => part.trim()).join(\":\");\n const readable = `${prefix}:${canonical}`;\n if (readable.length <= maxLength) return readable;\n return `${prefix}:h${fnv1a64(canonical)}`;\n}\n\nexport function createMerchantBillingSystemSourceKey(\n shopId: string,\n code: BillingSystemMessageCode,\n eventIdentity: string,\n version = 1,\n): string {\n assertKeyPart(\"shopId\", shopId);\n assertKeyPart(\"code\", code);\n assertKeyPart(\"eventIdentity\", eventIdentity);\n if (!Number.isInteger(version) || version < 1) {\n throw new Error(\"version must be a positive integer\");\n }\n return boundedKey(\"billing-system\", [shopId, code, eventIdentity, String(version)], 255);\n}\n\nexport function createRecoveryIdempotencyKey(shopId: string, recoveryId: string): string {\n assertKeyPart(\"shopId\", shopId);\n assertKeyPart(\"recoveryId\", recoveryId);\n return boundedKey(\"recovery\", [shopId, recoveryId], 255);\n}\n\nexport function createShopifyUsageIdempotencyKey(\n shopId: string,\n usageEventId: string,\n): string {\n assertKeyPart(\"shopId\", shopId);\n assertKeyPart(\"usageEventId\", usageEventId);\n return boundedKey(\"shopify\", [shopId, usageEventId], 64);\n}"],"mappings":"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","names":[]}
|