@modainteract/moda-interact-shared 1.2.0 → 1.3.1

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.d.ts CHANGED
@@ -1,7 +1,8 @@
1
1
  import { z } from 'zod';
2
2
 
3
3
  declare const ARCH007_BILLING_CONTRACT_SCHEMA_VERSION: 1;
4
- declare const WHATSAPP_PROVIDER_STATUS_SCHEMA_VERSION: 2;
4
+ declare const WHATSAPP_PROVIDER_STATUS_V2_SCHEMA_VERSION: 2;
5
+ declare const WHATSAPP_PROVIDER_STATUS_SCHEMA_VERSION: 3;
5
6
  declare const BILLING_SUBSCRIPTION_RECONCILE_SCHEMA_VERSION: 1;
6
7
  declare const BILLING_SUBSCRIPTION_RECONCILE_QUEUE_NAME = "billing-subscription-reconcile";
7
8
  declare const BILLING_SUBSCRIPTION_RECONCILE_JOB_NAME = "reconcile-subscription";
@@ -96,8 +97,33 @@ declare const WhatsAppProviderPricingMetadataSchema: z.ZodObject<{
96
97
  model: z.ZodOptional<z.ZodString>;
97
98
  }, z.core.$strict>;
98
99
  type WhatsAppProviderPricingMetadata = z.infer<typeof WhatsAppProviderPricingMetadataSchema>;
99
- declare const NormalizedWhatsAppStatusSchema: z.ZodObject<{
100
+ declare const WhatsAppProviderFailureEvidenceSchema: z.ZodObject<{
101
+ providerCode: z.ZodString;
102
+ }, z.core.$strict>;
103
+ type WhatsAppProviderFailureEvidence = z.infer<typeof WhatsAppProviderFailureEvidenceSchema>;
104
+ declare const NormalizedWhatsAppStatusV2Schema: z.ZodObject<{
105
+ providerAccountId: z.ZodString;
106
+ providerPhoneNumberId: z.ZodString;
107
+ providerMessageId: z.ZodString;
108
+ status: z.ZodEnum<{
109
+ SENT: "SENT";
110
+ DELIVERED: "DELIVERED";
111
+ READ: "READ";
112
+ FAILED: "FAILED";
113
+ }>;
114
+ occurredAt: z.ZodISODateTime;
115
+ pricing: z.ZodOptional<z.ZodObject<{
116
+ billable: z.ZodOptional<z.ZodBoolean>;
117
+ category: z.ZodOptional<z.ZodString>;
118
+ model: z.ZodOptional<z.ZodString>;
119
+ }, z.core.$strict>>;
100
120
  schemaVersion: z.ZodLiteral<2>;
121
+ }, z.core.$strict>;
122
+ type NormalizedWhatsAppStatusV2 = z.infer<typeof NormalizedWhatsAppStatusV2Schema>;
123
+ declare const NormalizedWhatsAppStatusV3Schema: z.ZodObject<{
124
+ failure: z.ZodOptional<z.ZodObject<{
125
+ providerCode: z.ZodString;
126
+ }, z.core.$strict>>;
101
127
  providerAccountId: z.ZodString;
102
128
  providerPhoneNumberId: z.ZodString;
103
129
  providerMessageId: z.ZodString;
@@ -113,16 +139,71 @@ declare const NormalizedWhatsAppStatusSchema: z.ZodObject<{
113
139
  category: z.ZodOptional<z.ZodString>;
114
140
  model: z.ZodOptional<z.ZodString>;
115
141
  }, z.core.$strict>>;
142
+ schemaVersion: z.ZodLiteral<3>;
116
143
  }, z.core.$strict>;
144
+ type NormalizedWhatsAppStatusV3 = z.infer<typeof NormalizedWhatsAppStatusV3Schema>;
145
+ declare const NormalizedWhatsAppStatusSchema: z.ZodUnion<readonly [z.ZodObject<{
146
+ providerAccountId: z.ZodString;
147
+ providerPhoneNumberId: z.ZodString;
148
+ providerMessageId: z.ZodString;
149
+ status: z.ZodEnum<{
150
+ SENT: "SENT";
151
+ DELIVERED: "DELIVERED";
152
+ READ: "READ";
153
+ FAILED: "FAILED";
154
+ }>;
155
+ occurredAt: z.ZodISODateTime;
156
+ pricing: z.ZodOptional<z.ZodObject<{
157
+ billable: z.ZodOptional<z.ZodBoolean>;
158
+ category: z.ZodOptional<z.ZodString>;
159
+ model: z.ZodOptional<z.ZodString>;
160
+ }, z.core.$strict>>;
161
+ schemaVersion: z.ZodLiteral<2>;
162
+ }, z.core.$strict>, z.ZodObject<{
163
+ failure: z.ZodOptional<z.ZodObject<{
164
+ providerCode: z.ZodString;
165
+ }, z.core.$strict>>;
166
+ providerAccountId: z.ZodString;
167
+ providerPhoneNumberId: z.ZodString;
168
+ providerMessageId: z.ZodString;
169
+ status: z.ZodEnum<{
170
+ SENT: "SENT";
171
+ DELIVERED: "DELIVERED";
172
+ READ: "READ";
173
+ FAILED: "FAILED";
174
+ }>;
175
+ occurredAt: z.ZodISODateTime;
176
+ pricing: z.ZodOptional<z.ZodObject<{
177
+ billable: z.ZodOptional<z.ZodBoolean>;
178
+ category: z.ZodOptional<z.ZodString>;
179
+ model: z.ZodOptional<z.ZodString>;
180
+ }, z.core.$strict>>;
181
+ schemaVersion: z.ZodLiteral<3>;
182
+ }, z.core.$strict>]>;
117
183
  type NormalizedWhatsAppStatus = z.infer<typeof NormalizedWhatsAppStatusSchema>;
118
184
  declare function parseNormalizedWhatsAppStatus(input: unknown): NormalizedWhatsAppStatus;
119
185
  declare function safeParseNormalizedWhatsAppStatus(input: unknown): z.ZodSafeParseResult<{
186
+ providerAccountId: string;
187
+ providerPhoneNumberId: string;
188
+ providerMessageId: string;
189
+ status: "SENT" | "DELIVERED" | "READ" | "FAILED";
190
+ occurredAt: string;
120
191
  schemaVersion: 2;
192
+ pricing?: {
193
+ billable?: boolean | undefined;
194
+ category?: string | undefined;
195
+ model?: string | undefined;
196
+ } | undefined;
197
+ } | {
121
198
  providerAccountId: string;
122
199
  providerPhoneNumberId: string;
123
200
  providerMessageId: string;
124
201
  status: "SENT" | "DELIVERED" | "READ" | "FAILED";
125
202
  occurredAt: string;
203
+ schemaVersion: 3;
204
+ failure?: {
205
+ providerCode: string;
206
+ } | undefined;
126
207
  pricing?: {
127
208
  billable?: boolean | undefined;
128
209
  category?: string | undefined;
@@ -134,4 +215,4 @@ declare function createMerchantBillingSystemSourceKey(shopId: string, code: Bill
134
215
  declare function createRecoveryIdempotencyKey(shopId: string, recoveryId: string): string;
135
216
  declare function createShopifyUsageIdempotencyKey(shopId: string, usageEventId: string): string;
136
217
 
137
- export { APP_PRICING_BILLING_PERIOD_DRAIN_WINDOW_MS, ARCH007_BILLING_CONTRACT_SCHEMA_VERSION, BILLING_PLAN_KINDS, BILLING_SUBSCRIPTION_RECONCILE_JOB_NAME, BILLING_SUBSCRIPTION_RECONCILE_QUEUE_NAME, BILLING_SUBSCRIPTION_RECONCILE_SCHEMA_VERSION, BILLING_SYSTEM_MESSAGE_CODES, BILLING_USAGE_METRICS, type BillingPlanKind, BillingPlanKindSchema, type BillingSubscriptionReconcileJob, BillingSubscriptionReconcileJobSchema, type BillingSystemMessageCode, BillingSystemMessageCodeSchema, type BillingUsageMetric, BillingUsageMetricSchema, type NormalizedWhatsAppStatus, NormalizedWhatsAppStatusSchema, type PurchasedRecoveryCreditCounterSnapshot, type ShopifyCurrentProviderContext, type ShopifyProviderContextIdentityInput, type ShopifyPurchaseProviderContext, WHATSAPP_PROVIDER_STATUSES, WHATSAPP_PROVIDER_STATUS_SCHEMA_VERSION, type WhatsAppProviderPricingMetadata, WhatsAppProviderPricingMetadataSchema, type WhatsAppProviderStatus, WhatsAppProviderStatusSchema, availablePurchasedRecoveryCredits, createBillingSubscriptionReconcileJobId, createMerchantBillingSystemSourceKey, createRecoveryIdempotencyKey, createShopifyUsageIdempotencyKey, deriveShopifyProviderContextIdentity, isSameShopifyPurchaseProviderContext, parseBillingSubscriptionReconcileJob, parseNormalizedWhatsAppStatus, safeParseBillingSubscriptionReconcileJob, safeParseNormalizedWhatsAppStatus };
218
+ export { APP_PRICING_BILLING_PERIOD_DRAIN_WINDOW_MS, ARCH007_BILLING_CONTRACT_SCHEMA_VERSION, BILLING_PLAN_KINDS, BILLING_SUBSCRIPTION_RECONCILE_JOB_NAME, BILLING_SUBSCRIPTION_RECONCILE_QUEUE_NAME, BILLING_SUBSCRIPTION_RECONCILE_SCHEMA_VERSION, BILLING_SYSTEM_MESSAGE_CODES, BILLING_USAGE_METRICS, type BillingPlanKind, BillingPlanKindSchema, type BillingSubscriptionReconcileJob, BillingSubscriptionReconcileJobSchema, type BillingSystemMessageCode, BillingSystemMessageCodeSchema, type BillingUsageMetric, BillingUsageMetricSchema, type NormalizedWhatsAppStatus, NormalizedWhatsAppStatusSchema, type NormalizedWhatsAppStatusV2, NormalizedWhatsAppStatusV2Schema, type NormalizedWhatsAppStatusV3, NormalizedWhatsAppStatusV3Schema, type PurchasedRecoveryCreditCounterSnapshot, type ShopifyCurrentProviderContext, type ShopifyProviderContextIdentityInput, type ShopifyPurchaseProviderContext, WHATSAPP_PROVIDER_STATUSES, WHATSAPP_PROVIDER_STATUS_SCHEMA_VERSION, WHATSAPP_PROVIDER_STATUS_V2_SCHEMA_VERSION, type WhatsAppProviderFailureEvidence, WhatsAppProviderFailureEvidenceSchema, type WhatsAppProviderPricingMetadata, WhatsAppProviderPricingMetadataSchema, type WhatsAppProviderStatus, WhatsAppProviderStatusSchema, availablePurchasedRecoveryCredits, createBillingSubscriptionReconcileJobId, createMerchantBillingSystemSourceKey, createRecoveryIdempotencyKey, createShopifyUsageIdempotencyKey, deriveShopifyProviderContextIdentity, isSameShopifyPurchaseProviderContext, parseBillingSubscriptionReconcileJob, parseNormalizedWhatsAppStatus, safeParseBillingSubscriptionReconcileJob, safeParseNormalizedWhatsAppStatus };
package/dist/billing.js CHANGED
@@ -12,8 +12,12 @@ import {
12
12
  BillingSystemMessageCodeSchema,
13
13
  BillingUsageMetricSchema,
14
14
  NormalizedWhatsAppStatusSchema,
15
+ NormalizedWhatsAppStatusV2Schema,
16
+ NormalizedWhatsAppStatusV3Schema,
15
17
  WHATSAPP_PROVIDER_STATUSES,
16
18
  WHATSAPP_PROVIDER_STATUS_SCHEMA_VERSION,
19
+ WHATSAPP_PROVIDER_STATUS_V2_SCHEMA_VERSION,
20
+ WhatsAppProviderFailureEvidenceSchema,
17
21
  WhatsAppProviderPricingMetadataSchema,
18
22
  WhatsAppProviderStatusSchema,
19
23
  availablePurchasedRecoveryCredits,
@@ -27,7 +31,7 @@ import {
27
31
  parseNormalizedWhatsAppStatus,
28
32
  safeParseBillingSubscriptionReconcileJob,
29
33
  safeParseNormalizedWhatsAppStatus
30
- } from "./chunk-ANBEH6NW.js";
34
+ } from "./chunk-HIHWRUZH.js";
31
35
  export {
32
36
  APP_PRICING_BILLING_PERIOD_DRAIN_WINDOW_MS,
33
37
  ARCH007_BILLING_CONTRACT_SCHEMA_VERSION,
@@ -42,8 +46,12 @@ export {
42
46
  BillingSystemMessageCodeSchema,
43
47
  BillingUsageMetricSchema,
44
48
  NormalizedWhatsAppStatusSchema,
49
+ NormalizedWhatsAppStatusV2Schema,
50
+ NormalizedWhatsAppStatusV3Schema,
45
51
  WHATSAPP_PROVIDER_STATUSES,
46
52
  WHATSAPP_PROVIDER_STATUS_SCHEMA_VERSION,
53
+ WHATSAPP_PROVIDER_STATUS_V2_SCHEMA_VERSION,
54
+ WhatsAppProviderFailureEvidenceSchema,
47
55
  WhatsAppProviderPricingMetadataSchema,
48
56
  WhatsAppProviderStatusSchema,
49
57
  availablePurchasedRecoveryCredits,
@@ -1,7 +1,8 @@
1
1
  // src/billing.ts
2
2
  import { z } from "zod";
3
3
  var ARCH007_BILLING_CONTRACT_SCHEMA_VERSION = 1;
4
- var WHATSAPP_PROVIDER_STATUS_SCHEMA_VERSION = 2;
4
+ var WHATSAPP_PROVIDER_STATUS_V2_SCHEMA_VERSION = 2;
5
+ var WHATSAPP_PROVIDER_STATUS_SCHEMA_VERSION = 3;
5
6
  var BILLING_SUBSCRIPTION_RECONCILE_SCHEMA_VERSION = 1;
6
7
  var BILLING_SUBSCRIPTION_RECONCILE_QUEUE_NAME = "billing-subscription-reconcile";
7
8
  var BILLING_SUBSCRIPTION_RECONCILE_JOB_NAME = "reconcile-subscription";
@@ -111,15 +112,33 @@ var WhatsAppProviderPricingMetadataSchema = z.object({
111
112
  category: z.string().trim().min(1).max(MAX_SHORT_TEXT_LENGTH).optional(),
112
113
  model: z.string().trim().min(1).max(MAX_SHORT_TEXT_LENGTH).optional()
113
114
  }).strict().refine((value) => Object.keys(value).length > 0, "pricing metadata must not be empty");
114
- var NormalizedWhatsAppStatusSchema = z.object({
115
- schemaVersion: z.literal(WHATSAPP_PROVIDER_STATUS_SCHEMA_VERSION),
115
+ var WhatsAppProviderFailureEvidenceSchema = z.object({
116
+ providerCode: z.string().trim().min(1).max(64)
117
+ }).strict();
118
+ var NORMALIZED_WHATSAPP_STATUS_FIELDS = {
116
119
  providerAccountId: z.string().trim().min(1).max(MAX_ID_LENGTH),
117
120
  providerPhoneNumberId: z.string().trim().min(1).max(MAX_ID_LENGTH),
118
121
  providerMessageId: z.string().trim().min(1).max(MAX_ID_LENGTH),
119
122
  status: WhatsAppProviderStatusSchema,
120
123
  occurredAt: z.iso.datetime({ offset: true }),
121
124
  pricing: WhatsAppProviderPricingMetadataSchema.optional()
125
+ };
126
+ var NormalizedWhatsAppStatusV2Schema = z.object({
127
+ schemaVersion: z.literal(WHATSAPP_PROVIDER_STATUS_V2_SCHEMA_VERSION),
128
+ ...NORMALIZED_WHATSAPP_STATUS_FIELDS
122
129
  }).strict();
130
+ var NormalizedWhatsAppStatusV3Schema = z.object({
131
+ schemaVersion: z.literal(WHATSAPP_PROVIDER_STATUS_SCHEMA_VERSION),
132
+ ...NORMALIZED_WHATSAPP_STATUS_FIELDS,
133
+ failure: WhatsAppProviderFailureEvidenceSchema.optional()
134
+ }).strict().refine((value) => value.status === "FAILED" || value.failure === void 0, {
135
+ message: "failure evidence is only valid for FAILED statuses",
136
+ path: ["failure"]
137
+ });
138
+ var NormalizedWhatsAppStatusSchema = z.union([
139
+ NormalizedWhatsAppStatusV2Schema,
140
+ NormalizedWhatsAppStatusV3Schema
141
+ ]);
123
142
  function parseNormalizedWhatsAppStatus(input) {
124
143
  return NormalizedWhatsAppStatusSchema.parse(input);
125
144
  }
@@ -175,6 +194,7 @@ function createShopifyUsageIdempotencyKey(shopId, usageEventId) {
175
194
 
176
195
  export {
177
196
  ARCH007_BILLING_CONTRACT_SCHEMA_VERSION,
197
+ WHATSAPP_PROVIDER_STATUS_V2_SCHEMA_VERSION,
178
198
  WHATSAPP_PROVIDER_STATUS_SCHEMA_VERSION,
179
199
  BILLING_SUBSCRIPTION_RECONCILE_SCHEMA_VERSION,
180
200
  BILLING_SUBSCRIPTION_RECONCILE_QUEUE_NAME,
@@ -195,6 +215,9 @@ export {
195
215
  parseBillingSubscriptionReconcileJob,
196
216
  safeParseBillingSubscriptionReconcileJob,
197
217
  WhatsAppProviderPricingMetadataSchema,
218
+ WhatsAppProviderFailureEvidenceSchema,
219
+ NormalizedWhatsAppStatusV2Schema,
220
+ NormalizedWhatsAppStatusV3Schema,
198
221
  NormalizedWhatsAppStatusSchema,
199
222
  parseNormalizedWhatsAppStatus,
200
223
  safeParseNormalizedWhatsAppStatus,
@@ -203,4 +226,4 @@ export {
203
226
  createRecoveryIdempotencyKey,
204
227
  createShopifyUsageIdempotencyKey
205
228
  };
206
- //# sourceMappingURL=chunk-ANBEH6NW.js.map
229
+ //# sourceMappingURL=chunk-HIHWRUZH.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_V2_SCHEMA_VERSION = 2 as const;\nexport const WHATSAPP_PROVIDER_STATUS_SCHEMA_VERSION = 3 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 WhatsAppProviderFailureEvidenceSchema = z\n .object({\n providerCode: z.string().trim().min(1).max(64),\n })\n .strict();\n\nexport type WhatsAppProviderFailureEvidence = z.infer<\n typeof WhatsAppProviderFailureEvidenceSchema\n>;\n\nconst NORMALIZED_WHATSAPP_STATUS_FIELDS = {\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\nexport const NormalizedWhatsAppStatusV2Schema = z\n .object({\n schemaVersion: z.literal(WHATSAPP_PROVIDER_STATUS_V2_SCHEMA_VERSION),\n ...NORMALIZED_WHATSAPP_STATUS_FIELDS,\n })\n .strict();\n\nexport type NormalizedWhatsAppStatusV2 = z.infer<typeof NormalizedWhatsAppStatusV2Schema>;\n\nexport const NormalizedWhatsAppStatusV3Schema = z\n .object({\n schemaVersion: z.literal(WHATSAPP_PROVIDER_STATUS_SCHEMA_VERSION),\n ...NORMALIZED_WHATSAPP_STATUS_FIELDS,\n failure: WhatsAppProviderFailureEvidenceSchema.optional(),\n })\n .strict()\n .refine((value) => value.status === \"FAILED\" || value.failure === undefined, {\n message: \"failure evidence is only valid for FAILED statuses\",\n path: [\"failure\"],\n });\n\nexport type NormalizedWhatsAppStatusV3 = z.infer<typeof NormalizedWhatsAppStatusV3Schema>;\n\nexport const NormalizedWhatsAppStatusSchema = z.union([\n NormalizedWhatsAppStatusV2Schema,\n NormalizedWhatsAppStatusV3Schema,\n]);\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":[]}
@@ -380,6 +380,48 @@ type CodeResponseProcessorResult = {
380
380
  };
381
381
  };
382
382
 
383
+ declare const STORE_CATEGORY_PROMPT_RUNTIME_VERSION: "store-category-prompt.v1";
384
+ declare const MAX_STORE_CATEGORY_PROMPT_SOURCE_CHARS = 100000;
385
+ declare const MAX_STORE_CATEGORY_PROMPT_RENDERED_CHARS = 100000;
386
+ declare const MAX_STORE_CATEGORY_PROMPT_CONDITIONS = 256;
387
+ declare const StoreCategoryPromptConditionKeySchema: z.ZodString;
388
+ type StoreCategoryPromptConditionKey = z.infer<typeof StoreCategoryPromptConditionKeySchema>;
389
+ declare const StoreCategoryPromptContextSchema: z.ZodObject<{
390
+ mappings: z.ZodRecord<z.ZodString, z.ZodBoolean>;
391
+ }, z.core.$strict>;
392
+ type StoreCategoryPromptContext = z.infer<typeof StoreCategoryPromptContextSchema>;
393
+ type StoreCategoryPromptTemplateIssue = {
394
+ path: "/promptText";
395
+ code: "invalid_prompt_source" | "unsupported_template_construct" | "invalid_template_structure" | "invalid_template_expression" | "invalid_mapping_condition" | "unknown_mapping_condition" | "template_too_complex" | "rendered_prompt_too_large";
396
+ message: string;
397
+ };
398
+ type StoreCategoryPromptTemplateValidation = {
399
+ valid: boolean;
400
+ issues: StoreCategoryPromptTemplateIssue[];
401
+ referencedConditionKeys: string[];
402
+ };
403
+ type StoreCategoryPromptRenderResult = {
404
+ ok: true;
405
+ promptText: string;
406
+ referencedConditionKeys: string[];
407
+ } | {
408
+ ok: false;
409
+ issues: StoreCategoryPromptTemplateIssue[];
410
+ };
411
+ declare function validateStoreCategoryPromptTemplate(input: {
412
+ source: string;
413
+ availableConditionKeys: readonly string[];
414
+ }): StoreCategoryPromptTemplateValidation;
415
+ declare function createStoreCategoryPromptConditionBlock(conditionKey: string): string;
416
+ declare function createStoreCategoryPromptContext(input: {
417
+ availableConditionKeys: readonly string[];
418
+ selectedConditionKeys: readonly string[];
419
+ }): StoreCategoryPromptContext;
420
+ declare function renderStoreCategoryPromptTemplate(input: {
421
+ source: string;
422
+ context: StoreCategoryPromptContext;
423
+ }): StoreCategoryPromptRenderResult;
424
+
383
425
  /** Synthetic examples; no provider identity, schema artifact or publication claim. */
384
426
 
385
427
  declare const exampleTool: ToolDescriptor;
@@ -389,4 +431,4 @@ declare function exampleManifest(digest: Digest, withTool?: boolean): CommerceMa
389
431
  declare function exampleGrant(manifest: CommerceManifest): CommerceConversationGrant;
390
432
  declare const exampleFinal: CommerceFinalResponse;
391
433
 
392
- export { type CodeResponseProcessorInput, type CodeResponseProcessorResult, CommerceConversationGrant, CommerceFinalResponse, CommerceManifest, CommerceToolDefinition, CommerceTurnIdentity, type ConnectionCommand, ConnectionCommandSchema, ConnectionIssueSchema, type ConnectionResult, ConnectionResultSchema, type ConnectionRevisionView, ConnectionRevisionViewSchema, type ConnectionView, ConnectionViewSchema, ContractVersionSchema, type CredentialStatus, CredentialStatusSchema, CurrencySchema, DateSchema, Digest, type ExternalHttpResultData, ExternalHttpResultDataSchema, ExternalPathSchema, ExternalQueryMappingSchema, ExternalQueryMappingsSchema, ExternalQueryValueSchema, type ExternalResponseFormat, ExternalResponseFormatSchema, type FeatureFacts, type FieldProjection, FieldProjectionSchema, GrantedTool, HashSchema, IdSchema, LanguageSchema, MoneySchema, type ResponseFilter, ResponseFilterSchema, type ResponseProcessing, ResponseProcessingSchema, type RevisionInput, RevisionInputSchema, SemverSchema, SubsetSchema, ToolDescriptor, type TransformResponse, TransformResponseSchema, type TransformSample, TransformSampleSchema, type VisualResponseProcessing, VisualResponseProcessingSchema, type VisualResponseProcessorInput, type VisualResponseProcessorResult, boundedJson, currentlyGrantedTools, deduplicateTools, distinct, exampleDefinition, exampleFinal, exampleGrant, exampleManifest, exampleTool, exampleTurn, manifestMatchesGrant, parseCommerceManifest, selectCapabilities };
434
+ export { type CodeResponseProcessorInput, type CodeResponseProcessorResult, CommerceConversationGrant, CommerceFinalResponse, CommerceManifest, CommerceToolDefinition, CommerceTurnIdentity, type ConnectionCommand, ConnectionCommandSchema, ConnectionIssueSchema, type ConnectionResult, ConnectionResultSchema, type ConnectionRevisionView, ConnectionRevisionViewSchema, type ConnectionView, ConnectionViewSchema, ContractVersionSchema, type CredentialStatus, CredentialStatusSchema, CurrencySchema, DateSchema, Digest, type ExternalHttpResultData, ExternalHttpResultDataSchema, ExternalPathSchema, ExternalQueryMappingSchema, ExternalQueryMappingsSchema, ExternalQueryValueSchema, type ExternalResponseFormat, ExternalResponseFormatSchema, type FeatureFacts, type FieldProjection, FieldProjectionSchema, GrantedTool, HashSchema, IdSchema, LanguageSchema, MAX_STORE_CATEGORY_PROMPT_CONDITIONS, MAX_STORE_CATEGORY_PROMPT_RENDERED_CHARS, MAX_STORE_CATEGORY_PROMPT_SOURCE_CHARS, MoneySchema, type ResponseFilter, ResponseFilterSchema, type ResponseProcessing, ResponseProcessingSchema, type RevisionInput, RevisionInputSchema, STORE_CATEGORY_PROMPT_RUNTIME_VERSION, SemverSchema, type StoreCategoryPromptConditionKey, StoreCategoryPromptConditionKeySchema, type StoreCategoryPromptContext, StoreCategoryPromptContextSchema, type StoreCategoryPromptRenderResult, type StoreCategoryPromptTemplateIssue, type StoreCategoryPromptTemplateValidation, SubsetSchema, ToolDescriptor, type TransformResponse, TransformResponseSchema, type TransformSample, TransformSampleSchema, type VisualResponseProcessing, VisualResponseProcessingSchema, type VisualResponseProcessorInput, type VisualResponseProcessorResult, boundedJson, createStoreCategoryPromptConditionBlock, createStoreCategoryPromptContext, currentlyGrantedTools, deduplicateTools, distinct, exampleDefinition, exampleFinal, exampleGrant, exampleManifest, exampleTool, exampleTurn, manifestMatchesGrant, parseCommerceManifest, renderStoreCategoryPromptTemplate, selectCapabilities, validateStoreCategoryPromptTemplate };
@@ -95,6 +95,384 @@ import {
95
95
  } from "../chunk-AUS3WQIW.js";
96
96
  import "../chunk-4KSODB2R.js";
97
97
 
98
+ // src/commerce/store-category-prompt.ts
99
+ import { z } from "zod";
100
+ var STORE_CATEGORY_PROMPT_RUNTIME_VERSION = "store-category-prompt.v1";
101
+ var MAX_STORE_CATEGORY_PROMPT_SOURCE_CHARS = 1e5;
102
+ var MAX_STORE_CATEGORY_PROMPT_RENDERED_CHARS = 1e5;
103
+ var MAX_STORE_CATEGORY_PROMPT_CONDITIONS = 256;
104
+ var MAX_CONTROL_TAGS = 512;
105
+ var MAX_CONTROL_DEPTH = 8;
106
+ var MAX_EXPRESSION_CHARS = 1024;
107
+ var forbiddenConditionKeys = /* @__PURE__ */ new Set(["__proto__", "prototype", "constructor"]);
108
+ var conditionKeyPattern = /^[a-z][a-z0-9_]{0,127}$/;
109
+ var StoreCategoryPromptConditionKeySchema = z.string().regex(conditionKeyPattern).refine((value) => !forbiddenConditionKeys.has(value));
110
+ var StoreCategoryPromptContextSchema = z.strictObject({
111
+ mappings: z.record(StoreCategoryPromptConditionKeySchema, z.boolean()).refine((value) => Object.keys(value).length <= MAX_STORE_CATEGORY_PROMPT_CONDITIONS)
112
+ });
113
+ function issue(code, message) {
114
+ return { path: "/promptText", code, message };
115
+ }
116
+ function boundedIssues(issues) {
117
+ return issues.slice(0, 32).map((entry) => ({
118
+ path: entry.path,
119
+ code: entry.code,
120
+ message: entry.message.slice(0, 512)
121
+ }));
122
+ }
123
+ function sourceLength(value) {
124
+ return Array.from(value).length;
125
+ }
126
+ function findNextMarker(source, start) {
127
+ let best = null;
128
+ for (const marker of ["{%", "{{", "{#"]) {
129
+ const index = source.indexOf(marker, start);
130
+ if (index >= 0 && (!best || index < best.index)) best = { index, marker };
131
+ }
132
+ return best;
133
+ }
134
+ function tokenizeTemplate(source, issues) {
135
+ const tokens = [];
136
+ let cursor = 0;
137
+ while (cursor < source.length) {
138
+ const next = findNextMarker(source, cursor);
139
+ if (!next) {
140
+ tokens.push({ kind: "text", text: source.slice(cursor) });
141
+ break;
142
+ }
143
+ if (next.index > cursor) tokens.push({ kind: "text", text: source.slice(cursor, next.index) });
144
+ const closeMarker = next.marker === "{%" ? "%}" : next.marker === "{{" ? "}}" : "#}";
145
+ const close = source.indexOf(closeMarker, next.index + 2);
146
+ if (close < 0) {
147
+ issues.push(issue("invalid_template_structure", `Unclosed ${next.marker} template construct.`));
148
+ tokens.push({ kind: "text", text: source.slice(next.index) });
149
+ break;
150
+ }
151
+ const raw = source.slice(next.index + 2, close).trim();
152
+ if (next.marker === "{%") tokens.push({ kind: "control", source: raw });
153
+ else tokens.push({ kind: "unsupported", source: raw, marker: next.marker === "{{" ? "interpolation" : "comment" });
154
+ cursor = close + 2;
155
+ }
156
+ if (source.length === 0) tokens.push({ kind: "text", text: "" });
157
+ return tokens;
158
+ }
159
+ function lexExpression(source, issues) {
160
+ if (sourceLength(source) > MAX_EXPRESSION_CHARS) {
161
+ issues.push(issue("template_too_complex", `Conditional expressions must not exceed ${MAX_EXPRESSION_CHARS} characters.`));
162
+ return null;
163
+ }
164
+ const tokens = [];
165
+ let cursor = 0;
166
+ while (cursor < source.length) {
167
+ const char = source[cursor];
168
+ if (/\s/.test(char)) {
169
+ cursor += 1;
170
+ continue;
171
+ }
172
+ if (char === ".") {
173
+ tokens.push({ kind: "dot" });
174
+ cursor += 1;
175
+ continue;
176
+ }
177
+ if (char === "(") {
178
+ tokens.push({ kind: "lparen" });
179
+ cursor += 1;
180
+ continue;
181
+ }
182
+ if (char === ")") {
183
+ tokens.push({ kind: "rparen" });
184
+ cursor += 1;
185
+ continue;
186
+ }
187
+ const match = /^[A-Za-z_][A-Za-z0-9_]*/.exec(source.slice(cursor));
188
+ if (!match) {
189
+ issues.push(issue("invalid_template_expression", "Conditional expressions may only use mappings.<conditionKey>, not, and, or, and parentheses."));
190
+ return null;
191
+ }
192
+ tokens.push({ kind: "word", value: match[0] });
193
+ cursor += match[0].length;
194
+ }
195
+ return tokens;
196
+ }
197
+ function parseExpression(source, issues, referenced) {
198
+ const tokens = lexExpression(source, issues);
199
+ if (!tokens || tokens.length === 0) {
200
+ if (tokens?.length === 0) issues.push(issue("invalid_template_expression", "A conditional expression is required."));
201
+ return null;
202
+ }
203
+ let index = 0;
204
+ const peekWord = (word) => {
205
+ const token = tokens[index];
206
+ return token?.kind === "word" && token.value === word;
207
+ };
208
+ const parsePrimary = () => {
209
+ const token = tokens[index];
210
+ if (token?.kind === "lparen") {
211
+ index += 1;
212
+ const inner = parseOr();
213
+ if (tokens[index]?.kind !== "rparen") {
214
+ issues.push(issue("invalid_template_expression", "Conditional expression parentheses are unbalanced."));
215
+ return null;
216
+ }
217
+ index += 1;
218
+ return inner;
219
+ }
220
+ if (!peekWord("mappings")) {
221
+ issues.push(issue("invalid_template_expression", "Conditional expressions must reference mappings.<conditionKey>."));
222
+ return null;
223
+ }
224
+ index += 1;
225
+ if (tokens[index]?.kind !== "dot") {
226
+ issues.push(issue("invalid_template_expression", "Mapping conditions must use mappings.<conditionKey>."));
227
+ return null;
228
+ }
229
+ index += 1;
230
+ const keyToken = tokens[index];
231
+ if (keyToken?.kind !== "word") {
232
+ issues.push(issue("invalid_mapping_condition", "A valid mapping condition key is required after mappings."));
233
+ return null;
234
+ }
235
+ index += 1;
236
+ if (!StoreCategoryPromptConditionKeySchema.safeParse(keyToken.value).success) {
237
+ issues.push(issue("invalid_mapping_condition", `Invalid mapping condition key: ${keyToken.value}.`));
238
+ return null;
239
+ }
240
+ if (!referenced.includes(keyToken.value)) referenced.push(keyToken.value);
241
+ return { kind: "condition", key: keyToken.value };
242
+ };
243
+ const parseNot = () => {
244
+ if (peekWord("not")) {
245
+ index += 1;
246
+ const operand = parseNot();
247
+ return operand ? { kind: "not", operand } : null;
248
+ }
249
+ return parsePrimary();
250
+ };
251
+ const parseAnd = () => {
252
+ let left = parseNot();
253
+ while (left && peekWord("and")) {
254
+ index += 1;
255
+ const right = parseNot();
256
+ if (!right) return null;
257
+ left = { kind: "and", left, right };
258
+ }
259
+ return left;
260
+ };
261
+ const parseOr = () => {
262
+ let left = parseAnd();
263
+ while (left && peekWord("or")) {
264
+ index += 1;
265
+ const right = parseAnd();
266
+ if (!right) return null;
267
+ left = { kind: "or", left, right };
268
+ }
269
+ return left;
270
+ };
271
+ const expression = parseOr();
272
+ if (expression && index !== tokens.length) {
273
+ issues.push(issue("invalid_template_expression", "Conditional expression contains unsupported syntax."));
274
+ return null;
275
+ }
276
+ return expression;
277
+ }
278
+ function compileStoreCategoryPromptTemplate(source) {
279
+ const issues = [];
280
+ const referencedConditionKeys = [];
281
+ const nodes = [];
282
+ if (source.trim().length === 0) issues.push(issue("invalid_prompt_source", "Prompt template must not be blank."));
283
+ if (sourceLength(source) > MAX_STORE_CATEGORY_PROMPT_SOURCE_CHARS) {
284
+ issues.push(issue("invalid_prompt_source", `Prompt template must not exceed ${MAX_STORE_CATEGORY_PROMPT_SOURCE_CHARS.toLocaleString()} characters.`));
285
+ }
286
+ const tokens = tokenizeTemplate(source, issues);
287
+ const stack = [];
288
+ let currentBody = nodes;
289
+ let controlCount = 0;
290
+ for (const token of tokens) {
291
+ if (token.kind === "text") {
292
+ if (token.text) currentBody.push({ kind: "text", text: token.text });
293
+ continue;
294
+ }
295
+ if (token.kind === "unsupported") {
296
+ issues.push(issue(
297
+ "unsupported_template_construct",
298
+ token.marker === "interpolation" ? "Variable interpolation is not supported in Store Category prompt templates." : "Template comments are not supported in Store Category prompt templates."
299
+ ));
300
+ continue;
301
+ }
302
+ controlCount += 1;
303
+ if (controlCount > MAX_CONTROL_TAGS) {
304
+ issues.push(issue("template_too_complex", `Prompt template must not contain more than ${MAX_CONTROL_TAGS} control tags.`));
305
+ break;
306
+ }
307
+ const ifMatch = /^if\s+([\s\S]+)$/.exec(token.source);
308
+ if (ifMatch) {
309
+ if (stack.length >= MAX_CONTROL_DEPTH) {
310
+ issues.push(issue("template_too_complex", `Conditional nesting must not exceed ${MAX_CONTROL_DEPTH} levels.`));
311
+ continue;
312
+ }
313
+ const expression = parseExpression(ifMatch[1].trim(), issues, referencedConditionKeys);
314
+ if (!expression) continue;
315
+ const branchBody = [];
316
+ const node = {
317
+ kind: "if",
318
+ branches: [{ expression, body: branchBody }],
319
+ elseBody: null
320
+ };
321
+ currentBody.push(node);
322
+ const frame = { node, parentBody: currentBody, currentBody: branchBody, sawElse: false };
323
+ stack.push(frame);
324
+ currentBody = branchBody;
325
+ continue;
326
+ }
327
+ const elifMatch = /^elif\s+([\s\S]+)$/.exec(token.source);
328
+ if (elifMatch) {
329
+ const frame = stack.at(-1);
330
+ if (!frame || frame.sawElse) {
331
+ issues.push(issue("invalid_template_structure", "elif must appear inside an if block and before else."));
332
+ continue;
333
+ }
334
+ const expression = parseExpression(elifMatch[1].trim(), issues, referencedConditionKeys);
335
+ if (!expression) continue;
336
+ const branchBody = [];
337
+ frame.node.branches.push({ expression, body: branchBody });
338
+ frame.currentBody = branchBody;
339
+ currentBody = branchBody;
340
+ continue;
341
+ }
342
+ if (token.source === "else") {
343
+ const frame = stack.at(-1);
344
+ if (!frame || frame.sawElse) {
345
+ issues.push(issue("invalid_template_structure", "else must appear once inside an if block."));
346
+ continue;
347
+ }
348
+ const elseBody = [];
349
+ frame.node.elseBody = elseBody;
350
+ frame.currentBody = elseBody;
351
+ frame.sawElse = true;
352
+ currentBody = elseBody;
353
+ continue;
354
+ }
355
+ if (token.source === "endif") {
356
+ const frame = stack.pop();
357
+ if (!frame) {
358
+ issues.push(issue("invalid_template_structure", "endif does not have a matching if block."));
359
+ continue;
360
+ }
361
+ currentBody = frame.parentBody;
362
+ continue;
363
+ }
364
+ issues.push(issue(
365
+ "unsupported_template_construct",
366
+ "Only if, elif, else, and endif control tags are supported in Store Category prompt templates."
367
+ ));
368
+ }
369
+ if (stack.length) issues.push(issue("invalid_template_structure", "Every if block must end with endif."));
370
+ return { issues: boundedIssues(issues), nodes, referencedConditionKeys };
371
+ }
372
+ function validateAvailableConditionKeys(values, issues) {
373
+ if (values.length > MAX_STORE_CATEGORY_PROMPT_CONDITIONS) {
374
+ issues.push(issue("template_too_complex", `At most ${MAX_STORE_CATEGORY_PROMPT_CONDITIONS} mapping conditions are supported.`));
375
+ }
376
+ const keys = /* @__PURE__ */ new Set();
377
+ for (const value of values.slice(0, MAX_STORE_CATEGORY_PROMPT_CONDITIONS + 1)) {
378
+ if (!StoreCategoryPromptConditionKeySchema.safeParse(value).success) {
379
+ issues.push(issue("invalid_mapping_condition", `Invalid mapping condition key: ${value}.`));
380
+ continue;
381
+ }
382
+ if (keys.has(value)) {
383
+ issues.push(issue("invalid_mapping_condition", `Duplicate mapping condition key: ${value}.`));
384
+ continue;
385
+ }
386
+ keys.add(value);
387
+ }
388
+ return keys;
389
+ }
390
+ function validateStoreCategoryPromptTemplate(input) {
391
+ const compiled = compileStoreCategoryPromptTemplate(input.source);
392
+ const issues = [...compiled.issues];
393
+ const available = validateAvailableConditionKeys(input.availableConditionKeys, issues);
394
+ for (const key of compiled.referencedConditionKeys) {
395
+ if (!available.has(key)) issues.push(issue("unknown_mapping_condition", `Prompt template references unavailable mapping condition: mappings.${key}.`));
396
+ }
397
+ const bounded = boundedIssues(issues);
398
+ return { valid: bounded.length === 0, issues: bounded, referencedConditionKeys: compiled.referencedConditionKeys };
399
+ }
400
+ function createStoreCategoryPromptConditionBlock(conditionKey) {
401
+ const parsed = StoreCategoryPromptConditionKeySchema.safeParse(conditionKey);
402
+ if (!parsed.success) throw new TypeError(`Invalid mapping condition key: ${conditionKey}.`);
403
+ return `{% if mappings.${conditionKey} %}
404
+
405
+ {% endif %}`;
406
+ }
407
+ function createStoreCategoryPromptContext(input) {
408
+ const issues = [];
409
+ const available = validateAvailableConditionKeys(input.availableConditionKeys, issues);
410
+ const selected = validateAvailableConditionKeys(input.selectedConditionKeys, issues);
411
+ for (const key of selected) {
412
+ if (!available.has(key)) issues.push(issue("unknown_mapping_condition", `Selected mapping condition is unavailable: ${key}.`));
413
+ }
414
+ if (issues.length) throw new TypeError(issues[0].message);
415
+ const mappings = /* @__PURE__ */ Object.create(null);
416
+ for (const key of available) mappings[key] = selected.has(key);
417
+ return { mappings };
418
+ }
419
+ function evaluateExpression(expression, mappings) {
420
+ switch (expression.kind) {
421
+ case "condition":
422
+ return mappings[expression.key] === true;
423
+ case "not":
424
+ return !evaluateExpression(expression.operand, mappings);
425
+ case "and":
426
+ return evaluateExpression(expression.left, mappings) && evaluateExpression(expression.right, mappings);
427
+ case "or":
428
+ return evaluateExpression(expression.left, mappings) || evaluateExpression(expression.right, mappings);
429
+ }
430
+ }
431
+ function renderNodes(nodes, mappings, append) {
432
+ for (const node of nodes) {
433
+ if (node.kind === "text") {
434
+ if (!append(node.text)) return false;
435
+ continue;
436
+ }
437
+ let renderedBranch = false;
438
+ for (const branch of node.branches) {
439
+ if (evaluateExpression(branch.expression, mappings)) {
440
+ if (!renderNodes(branch.body, mappings, append)) return false;
441
+ renderedBranch = true;
442
+ break;
443
+ }
444
+ }
445
+ if (!renderedBranch && node.elseBody && !renderNodes(node.elseBody, mappings, append)) return false;
446
+ }
447
+ return true;
448
+ }
449
+ function renderStoreCategoryPromptTemplate(input) {
450
+ const contextResult = StoreCategoryPromptContextSchema.safeParse(input.context);
451
+ if (!contextResult.success) {
452
+ return { ok: false, issues: [issue("invalid_mapping_condition", "Store Category prompt context contains invalid mapping conditions.")] };
453
+ }
454
+ const availableConditionKeys = Object.keys(contextResult.data.mappings);
455
+ const validation = validateStoreCategoryPromptTemplate({ source: input.source, availableConditionKeys });
456
+ if (!validation.valid) return { ok: false, issues: validation.issues };
457
+ const compiled = compileStoreCategoryPromptTemplate(input.source);
458
+ let output = "";
459
+ let outputChars = 0;
460
+ const append = (text) => {
461
+ outputChars += sourceLength(text);
462
+ if (outputChars > MAX_STORE_CATEGORY_PROMPT_RENDERED_CHARS) return false;
463
+ output += text;
464
+ return true;
465
+ };
466
+ const rendered = renderNodes(compiled.nodes, contextResult.data.mappings, append);
467
+ if (!rendered) {
468
+ return {
469
+ ok: false,
470
+ issues: [issue("rendered_prompt_too_large", `Rendered prompt must not exceed ${MAX_STORE_CATEGORY_PROMPT_RENDERED_CHARS.toLocaleString()} characters.`)]
471
+ };
472
+ }
473
+ return { ok: true, promptText: output, referencedConditionKeys: validation.referencedConditionKeys };
474
+ }
475
+
98
476
  // src/commerce/fixtures.ts
99
477
  var exampleTool = {
100
478
  toolId: "tool-fixture",
@@ -240,6 +618,9 @@ export {
240
618
  IdSchema,
241
619
  InputSchemaSchema,
242
620
  LanguageSchema,
621
+ MAX_STORE_CATEGORY_PROMPT_CONDITIONS,
622
+ MAX_STORE_CATEGORY_PROMPT_RENDERED_CHARS,
623
+ MAX_STORE_CATEGORY_PROMPT_SOURCE_CHARS,
243
624
  MONEY_PATTERN,
244
625
  MoneySchema,
245
626
  POLICY_OPERATIONS,
@@ -249,7 +630,10 @@ export {
249
630
  ResponseProcessingSchema,
250
631
  ResponseTemplateSchema,
251
632
  RevisionInputSchema,
633
+ STORE_CATEGORY_PROMPT_RUNTIME_VERSION,
252
634
  SemverSchema,
635
+ StoreCategoryPromptConditionKeySchema,
636
+ StoreCategoryPromptContextSchema,
253
637
  ToolDescriptorSchema,
254
638
  ToolNameSchema,
255
639
  TransformResponseSchema,
@@ -259,6 +643,8 @@ export {
259
643
  canonicalJson,
260
644
  commerceToolResultSchema,
261
645
  compileSubset,
646
+ createStoreCategoryPromptConditionBlock,
647
+ createStoreCategoryPromptContext,
262
648
  currentlyGrantedTools,
263
649
  deduplicateTools,
264
650
  definitionToMcpDescriptor,
@@ -277,6 +663,7 @@ export {
277
663
  matchesSubset,
278
664
  parseCommerceManifest,
279
665
  productBelongsToDomain,
666
+ renderStoreCategoryPromptTemplate,
280
667
  responseContractCanonicalJson,
281
668
  safeName,
282
669
  safePath,
@@ -284,6 +671,7 @@ export {
284
671
  toolHashInput,
285
672
  validateDefinitionForPublication,
286
673
  validateDefinitionVersion,
674
+ validateStoreCategoryPromptTemplate,
287
675
  validateSubset,
288
676
  verifyResponseContract
289
677
  };
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/commerce/fixtures.ts"],"sourcesContent":["/** Synthetic examples; no provider identity, schema artifact or publication claim. */\nimport type {\n CommerceManifest,\n CommerceConversationGrant,\n CommerceTurnIdentity,\n} from \"./schemas\";\nimport {\n EMPTY_RESPONSE_CONTRACT,\n type CommerceFinalResponse,\n} from \"./response\";\nimport type { Digest } from \"./canonical-json\";\nimport { responseContractCanonicalJson } from \"./canonical-json\";\nimport type { ToolDescriptor, CommerceToolDefinition } from \"./definitions\";\nexport const exampleTool: ToolDescriptor = {\n toolId: \"tool-fixture\",\n toolRevisionId: \"revision-fixture\",\n name: \"never_seeded_catalogue_facts\",\n definitionVersion: \"1.0.0\",\n description: \"Read synthetic catalogue facts.\",\n inputSchema: {\n type: \"object\",\n properties: { handle: { type: \"string\", minLength: 1, maxLength: 255 } },\n required: [\"handle\"],\n additionalProperties: false,\n },\n};\nexport const exampleDefinition: CommerceToolDefinition = {\n name: exampleTool.name,\n definitionVersion: \"1.0.0\",\n description: exampleTool.description,\n inputSchema: exampleTool.inputSchema,\n execution: {\n kind: \"SHOPIFY_STOREFRONT_QUERY\",\n executorVersion: \"1.0.0\",\n apiVersion: \"2026-07\",\n schemaHash: \"a\".repeat(64),\n document:\n \"query ProductDetails($handle: String!) { product(handle: $handle) { title description } }\",\n operationName: \"ProductDetails\",\n variables: { handle: { input: \"handle\" } },\n resultPath: \"product\",\n },\n responseTemplate: {\n kind: \"text\",\n text: \"{{result.values.title}}: {{result.values.description}}\",\n unavailable: \"Product details could not be verified.\",\n },\n};\nexport const exampleTurn: CommerceTurnIdentity = {\n contractVersion: \"commerce.v1\",\n shopId: \"shop-fixture\",\n checkoutRecoveryId: \"recovery-fixture\",\n conversationId: \"conversation-fixture\",\n inboundVersion: 1,\n};\nexport function exampleManifest(\n digest: Digest,\n withTool = false,\n): CommerceManifest {\n const capabilities = withTool\n ? [{\n capabilityId: \"capability-fixture\",\n key: \"feature_product_read\",\n featureId: \"feature-fixture\",\n position: 0,\n toolDescriptor: structuredClone(exampleTool),\n }]\n : [];\n return {\n contractVersion: \"commerce.v1\",\n releaseId: \"release-fixture\",\n runnerCompatibility: \"^1.0.0\",\n capabilities,\n featureBehaviours: withTool\n ? [{ featureId: \"feature-fixture\", behaviourPrompt: \"Synthetic Feature behavior.\" }]\n : [],\n selectedCapabilityKeys: capabilities.map((capability) => capability.key),\n grantedTools: withTool\n ? [\n {\n toolId: exampleTool.toolId,\n toolRevisionId: exampleTool.toolRevisionId,\n toolName: exampleTool.name,\n definitionVersion: \"1.0.0\",\n capabilityKeys: [\"feature_product_read\"],\n },\n ]\n : [],\n responseContract: structuredClone(EMPTY_RESPONSE_CONTRACT),\n responseContractHash: digest(\n responseContractCanonicalJson(EMPTY_RESPONSE_CONTRACT),\n ),\n };\n}\nexport function exampleGrant(\n manifest: CommerceManifest,\n): CommerceConversationGrant {\n return {\n id: \"grant-fixture\",\n shopId: exampleTurn.shopId,\n conversationId: exampleTurn.conversationId,\n initialInboundVersion: 1,\n releaseId: manifest.releaseId,\n selectedCapabilityKeys: [...manifest.selectedCapabilityKeys],\n grantedTools: structuredClone(manifest.grantedTools),\n runnerVersion: \"1.0.0\",\n createdAt: \"2026-09-20T00:00:00.000Z\",\n expiresAt: null,\n };\n}\nexport const exampleFinal: CommerceFinalResponse = {\n answerKind: \"REFER_TO_STORE\",\n replyText:\n \"I cannot verify that information. Please contact the store directly.\",\n referralReason: \"INSUFFICIENT_TOOLS\",\n detectedLanguageTag: null,\n detectedLanguageConfidence: null,\n evidenceIds: [],\n details: {},\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAaO,IAAM,cAA8B;AAAA,EACzC,QAAQ;AAAA,EACR,gBAAgB;AAAA,EAChB,MAAM;AAAA,EACN,mBAAmB;AAAA,EACnB,aAAa;AAAA,EACb,aAAa;AAAA,IACX,MAAM;AAAA,IACN,YAAY,EAAE,QAAQ,EAAE,MAAM,UAAU,WAAW,GAAG,WAAW,IAAI,EAAE;AAAA,IACvE,UAAU,CAAC,QAAQ;AAAA,IACnB,sBAAsB;AAAA,EACxB;AACF;AACO,IAAM,oBAA4C;AAAA,EACvD,MAAM,YAAY;AAAA,EAClB,mBAAmB;AAAA,EACnB,aAAa,YAAY;AAAA,EACzB,aAAa,YAAY;AAAA,EACzB,WAAW;AAAA,IACT,MAAM;AAAA,IACN,iBAAiB;AAAA,IACjB,YAAY;AAAA,IACZ,YAAY,IAAI,OAAO,EAAE;AAAA,IACzB,UACE;AAAA,IACF,eAAe;AAAA,IACf,WAAW,EAAE,QAAQ,EAAE,OAAO,SAAS,EAAE;AAAA,IACzC,YAAY;AAAA,EACd;AAAA,EACA,kBAAkB;AAAA,IAChB,MAAM;AAAA,IACN,MAAM;AAAA,IACN,aAAa;AAAA,EACf;AACF;AACO,IAAM,cAAoC;AAAA,EAC/C,iBAAiB;AAAA,EACjB,QAAQ;AAAA,EACR,oBAAoB;AAAA,EACpB,gBAAgB;AAAA,EAChB,gBAAgB;AAClB;AACO,SAAS,gBACd,QACA,WAAW,OACO;AAClB,QAAM,eAAe,WACjB,CAAC;AAAA,IACC,cAAc;AAAA,IACd,KAAK;AAAA,IACL,WAAW;AAAA,IACX,UAAU;AAAA,IACV,gBAAgB,gBAAgB,WAAW;AAAA,EAC7C,CAAC,IACD,CAAC;AACL,SAAO;AAAA,IACL,iBAAiB;AAAA,IACjB,WAAW;AAAA,IACX,qBAAqB;AAAA,IACrB;AAAA,IACA,mBAAmB,WACf,CAAC,EAAE,WAAW,mBAAmB,iBAAiB,8BAA8B,CAAC,IACjF,CAAC;AAAA,IACL,wBAAwB,aAAa,IAAI,CAAC,eAAe,WAAW,GAAG;AAAA,IACvE,cAAc,WACV;AAAA,MACE;AAAA,QACE,QAAQ,YAAY;AAAA,QACpB,gBAAgB,YAAY;AAAA,QAC5B,UAAU,YAAY;AAAA,QACtB,mBAAmB;AAAA,QACnB,gBAAgB,CAAC,sBAAsB;AAAA,MACzC;AAAA,IACF,IACA,CAAC;AAAA,IACL,kBAAkB,gBAAgB,uBAAuB;AAAA,IACzD,sBAAsB;AAAA,MACpB,8BAA8B,uBAAuB;AAAA,IACvD;AAAA,EACF;AACF;AACO,SAAS,aACd,UAC2B;AAC3B,SAAO;AAAA,IACL,IAAI;AAAA,IACJ,QAAQ,YAAY;AAAA,IACpB,gBAAgB,YAAY;AAAA,IAC5B,uBAAuB;AAAA,IACvB,WAAW,SAAS;AAAA,IACpB,wBAAwB,CAAC,GAAG,SAAS,sBAAsB;AAAA,IAC3D,cAAc,gBAAgB,SAAS,YAAY;AAAA,IACnD,eAAe;AAAA,IACf,WAAW;AAAA,IACX,WAAW;AAAA,EACb;AACF;AACO,IAAM,eAAsC;AAAA,EACjD,YAAY;AAAA,EACZ,WACE;AAAA,EACF,gBAAgB;AAAA,EAChB,qBAAqB;AAAA,EACrB,4BAA4B;AAAA,EAC5B,aAAa,CAAC;AAAA,EACd,SAAS,CAAC;AACZ;","names":[]}
1
+ {"version":3,"sources":["../../src/commerce/store-category-prompt.ts","../../src/commerce/fixtures.ts"],"sourcesContent":["import { z } from \"zod\";\n\nexport const STORE_CATEGORY_PROMPT_RUNTIME_VERSION = \"store-category-prompt.v1\" as const;\nexport const MAX_STORE_CATEGORY_PROMPT_SOURCE_CHARS = 100_000;\nexport const MAX_STORE_CATEGORY_PROMPT_RENDERED_CHARS = 100_000;\nexport const MAX_STORE_CATEGORY_PROMPT_CONDITIONS = 256;\nconst MAX_CONTROL_TAGS = 512;\nconst MAX_CONTROL_DEPTH = 8;\nconst MAX_EXPRESSION_CHARS = 1_024;\n\nconst forbiddenConditionKeys = new Set([\"__proto__\", \"prototype\", \"constructor\"]);\nconst conditionKeyPattern = /^[a-z][a-z0-9_]{0,127}$/;\n\nexport const StoreCategoryPromptConditionKeySchema = z\n .string()\n .regex(conditionKeyPattern)\n .refine((value) => !forbiddenConditionKeys.has(value));\n\nexport type StoreCategoryPromptConditionKey = z.infer<typeof StoreCategoryPromptConditionKeySchema>;\n\nexport const StoreCategoryPromptContextSchema = z.strictObject({\n mappings: z\n .record(StoreCategoryPromptConditionKeySchema, z.boolean())\n .refine((value) => Object.keys(value).length <= MAX_STORE_CATEGORY_PROMPT_CONDITIONS),\n});\n\nexport type StoreCategoryPromptContext = z.infer<typeof StoreCategoryPromptContextSchema>;\n\nexport type StoreCategoryPromptTemplateIssue = {\n path: \"/promptText\";\n code:\n | \"invalid_prompt_source\"\n | \"unsupported_template_construct\"\n | \"invalid_template_structure\"\n | \"invalid_template_expression\"\n | \"invalid_mapping_condition\"\n | \"unknown_mapping_condition\"\n | \"template_too_complex\"\n | \"rendered_prompt_too_large\";\n message: string;\n};\n\nexport type StoreCategoryPromptTemplateValidation = {\n valid: boolean;\n issues: StoreCategoryPromptTemplateIssue[];\n referencedConditionKeys: string[];\n};\n\nexport type StoreCategoryPromptRenderResult =\n | { ok: true; promptText: string; referencedConditionKeys: string[] }\n | { ok: false; issues: StoreCategoryPromptTemplateIssue[] };\n\ntype ExpressionNode =\n | { kind: \"condition\"; key: string }\n | { kind: \"not\"; operand: ExpressionNode }\n | { kind: \"and\"; left: ExpressionNode; right: ExpressionNode }\n | { kind: \"or\"; left: ExpressionNode; right: ExpressionNode };\n\ntype TemplateNode =\n | { kind: \"text\"; text: string }\n | {\n kind: \"if\";\n branches: Array<{ expression: ExpressionNode; body: TemplateNode[] }>;\n elseBody: TemplateNode[] | null;\n };\n\ntype TemplateToken =\n | { kind: \"text\"; text: string }\n | { kind: \"control\"; source: string }\n | { kind: \"unsupported\"; source: string; marker: \"interpolation\" | \"comment\" };\n\ntype CompileResult = {\n issues: StoreCategoryPromptTemplateIssue[];\n nodes: TemplateNode[];\n referencedConditionKeys: string[];\n};\n\nfunction issue(code: StoreCategoryPromptTemplateIssue[\"code\"], message: string): StoreCategoryPromptTemplateIssue {\n return { path: \"/promptText\", code, message };\n}\n\nfunction boundedIssues(issues: StoreCategoryPromptTemplateIssue[]): StoreCategoryPromptTemplateIssue[] {\n return issues.slice(0, 32).map((entry) => ({\n path: entry.path,\n code: entry.code,\n message: entry.message.slice(0, 512),\n }));\n}\n\nfunction sourceLength(value: string): number {\n return Array.from(value).length;\n}\n\nfunction findNextMarker(source: string, start: number): { index: number; marker: \"{%\" | \"{{\" | \"{#\" } | null {\n let best: { index: number; marker: \"{%\" | \"{{\" | \"{#\" } | null = null;\n for (const marker of [\"{%\", \"{{\", \"{#\"] as const) {\n const index = source.indexOf(marker, start);\n if (index >= 0 && (!best || index < best.index)) best = { index, marker };\n }\n return best;\n}\n\nfunction tokenizeTemplate(source: string, issues: StoreCategoryPromptTemplateIssue[]): TemplateToken[] {\n const tokens: TemplateToken[] = [];\n let cursor = 0;\n while (cursor < source.length) {\n const next = findNextMarker(source, cursor);\n if (!next) {\n tokens.push({ kind: \"text\", text: source.slice(cursor) });\n break;\n }\n if (next.index > cursor) tokens.push({ kind: \"text\", text: source.slice(cursor, next.index) });\n const closeMarker = next.marker === \"{%\" ? \"%}\" : next.marker === \"{{\" ? \"}}\" : \"#}\";\n const close = source.indexOf(closeMarker, next.index + 2);\n if (close < 0) {\n issues.push(issue(\"invalid_template_structure\", `Unclosed ${next.marker} template construct.`));\n tokens.push({ kind: \"text\", text: source.slice(next.index) });\n break;\n }\n const raw = source.slice(next.index + 2, close).trim();\n if (next.marker === \"{%\") tokens.push({ kind: \"control\", source: raw });\n else tokens.push({ kind: \"unsupported\", source: raw, marker: next.marker === \"{{\" ? \"interpolation\" : \"comment\" });\n cursor = close + 2;\n }\n if (source.length === 0) tokens.push({ kind: \"text\", text: \"\" });\n return tokens;\n}\n\ntype ExprToken = { kind: \"word\"; value: string } | { kind: \"dot\" } | { kind: \"lparen\" } | { kind: \"rparen\" };\n\nfunction lexExpression(source: string, issues: StoreCategoryPromptTemplateIssue[]): ExprToken[] | null {\n if (sourceLength(source) > MAX_EXPRESSION_CHARS) {\n issues.push(issue(\"template_too_complex\", `Conditional expressions must not exceed ${MAX_EXPRESSION_CHARS} characters.`));\n return null;\n }\n const tokens: ExprToken[] = [];\n let cursor = 0;\n while (cursor < source.length) {\n const char = source[cursor];\n if (/\\s/.test(char)) {\n cursor += 1;\n continue;\n }\n if (char === \".\") {\n tokens.push({ kind: \"dot\" });\n cursor += 1;\n continue;\n }\n if (char === \"(\") {\n tokens.push({ kind: \"lparen\" });\n cursor += 1;\n continue;\n }\n if (char === \")\") {\n tokens.push({ kind: \"rparen\" });\n cursor += 1;\n continue;\n }\n const match = /^[A-Za-z_][A-Za-z0-9_]*/.exec(source.slice(cursor));\n if (!match) {\n issues.push(issue(\"invalid_template_expression\", \"Conditional expressions may only use mappings.<conditionKey>, not, and, or, and parentheses.\"));\n return null;\n }\n tokens.push({ kind: \"word\", value: match[0] });\n cursor += match[0].length;\n }\n return tokens;\n}\n\nfunction parseExpression(source: string, issues: StoreCategoryPromptTemplateIssue[], referenced: string[]): ExpressionNode | null {\n const tokens = lexExpression(source, issues);\n if (!tokens || tokens.length === 0) {\n if (tokens?.length === 0) issues.push(issue(\"invalid_template_expression\", \"A conditional expression is required.\"));\n return null;\n }\n let index = 0;\n const peekWord = (word: string) => {\n const token = tokens[index];\n return token?.kind === \"word\" && token.value === word;\n };\n\n const parsePrimary = (): ExpressionNode | null => {\n const token = tokens[index];\n if (token?.kind === \"lparen\") {\n index += 1;\n const inner = parseOr();\n if (tokens[index]?.kind !== \"rparen\") {\n issues.push(issue(\"invalid_template_expression\", \"Conditional expression parentheses are unbalanced.\"));\n return null;\n }\n index += 1;\n return inner;\n }\n if (!peekWord(\"mappings\")) {\n issues.push(issue(\"invalid_template_expression\", \"Conditional expressions must reference mappings.<conditionKey>.\"));\n return null;\n }\n index += 1;\n if (tokens[index]?.kind !== \"dot\") {\n issues.push(issue(\"invalid_template_expression\", \"Mapping conditions must use mappings.<conditionKey>.\"));\n return null;\n }\n index += 1;\n const keyToken = tokens[index];\n if (keyToken?.kind !== \"word\") {\n issues.push(issue(\"invalid_mapping_condition\", \"A valid mapping condition key is required after mappings.\"));\n return null;\n }\n index += 1;\n if (!StoreCategoryPromptConditionKeySchema.safeParse(keyToken.value).success) {\n issues.push(issue(\"invalid_mapping_condition\", `Invalid mapping condition key: ${keyToken.value}.`));\n return null;\n }\n if (!referenced.includes(keyToken.value)) referenced.push(keyToken.value);\n return { kind: \"condition\", key: keyToken.value };\n };\n\n const parseNot = (): ExpressionNode | null => {\n if (peekWord(\"not\")) {\n index += 1;\n const operand = parseNot();\n return operand ? { kind: \"not\", operand } : null;\n }\n return parsePrimary();\n };\n\n const parseAnd = (): ExpressionNode | null => {\n let left = parseNot();\n while (left && peekWord(\"and\")) {\n index += 1;\n const right = parseNot();\n if (!right) return null;\n left = { kind: \"and\", left, right };\n }\n return left;\n };\n\n const parseOr = (): ExpressionNode | null => {\n let left = parseAnd();\n while (left && peekWord(\"or\")) {\n index += 1;\n const right = parseAnd();\n if (!right) return null;\n left = { kind: \"or\", left, right };\n }\n return left;\n };\n\n const expression = parseOr();\n if (expression && index !== tokens.length) {\n issues.push(issue(\"invalid_template_expression\", \"Conditional expression contains unsupported syntax.\"));\n return null;\n }\n return expression;\n}\n\nfunction compileStoreCategoryPromptTemplate(source: string): CompileResult {\n const issues: StoreCategoryPromptTemplateIssue[] = [];\n const referencedConditionKeys: string[] = [];\n const nodes: TemplateNode[] = [];\n\n if (source.trim().length === 0) issues.push(issue(\"invalid_prompt_source\", \"Prompt template must not be blank.\"));\n if (sourceLength(source) > MAX_STORE_CATEGORY_PROMPT_SOURCE_CHARS) {\n issues.push(issue(\"invalid_prompt_source\", `Prompt template must not exceed ${MAX_STORE_CATEGORY_PROMPT_SOURCE_CHARS.toLocaleString()} characters.`));\n }\n\n const tokens = tokenizeTemplate(source, issues);\n type Frame = {\n node: Extract<TemplateNode, { kind: \"if\" }>;\n parentBody: TemplateNode[];\n currentBody: TemplateNode[];\n sawElse: boolean;\n };\n const stack: Frame[] = [];\n let currentBody = nodes;\n let controlCount = 0;\n\n for (const token of tokens) {\n if (token.kind === \"text\") {\n if (token.text) currentBody.push({ kind: \"text\", text: token.text });\n continue;\n }\n if (token.kind === \"unsupported\") {\n issues.push(issue(\n \"unsupported_template_construct\",\n token.marker === \"interpolation\"\n ? \"Variable interpolation is not supported in Store Category prompt templates.\"\n : \"Template comments are not supported in Store Category prompt templates.\",\n ));\n continue;\n }\n\n controlCount += 1;\n if (controlCount > MAX_CONTROL_TAGS) {\n issues.push(issue(\"template_too_complex\", `Prompt template must not contain more than ${MAX_CONTROL_TAGS} control tags.`));\n break;\n }\n\n const ifMatch = /^if\\s+([\\s\\S]+)$/.exec(token.source);\n if (ifMatch) {\n if (stack.length >= MAX_CONTROL_DEPTH) {\n issues.push(issue(\"template_too_complex\", `Conditional nesting must not exceed ${MAX_CONTROL_DEPTH} levels.`));\n continue;\n }\n const expression = parseExpression(ifMatch[1].trim(), issues, referencedConditionKeys);\n if (!expression) continue;\n const branchBody: TemplateNode[] = [];\n const node: Extract<TemplateNode, { kind: \"if\" }> = {\n kind: \"if\",\n branches: [{ expression, body: branchBody }],\n elseBody: null,\n };\n currentBody.push(node);\n const frame: Frame = { node, parentBody: currentBody, currentBody: branchBody, sawElse: false };\n stack.push(frame);\n currentBody = branchBody;\n continue;\n }\n\n const elifMatch = /^elif\\s+([\\s\\S]+)$/.exec(token.source);\n if (elifMatch) {\n const frame = stack.at(-1);\n if (!frame || frame.sawElse) {\n issues.push(issue(\"invalid_template_structure\", \"elif must appear inside an if block and before else.\"));\n continue;\n }\n const expression = parseExpression(elifMatch[1].trim(), issues, referencedConditionKeys);\n if (!expression) continue;\n const branchBody: TemplateNode[] = [];\n frame.node.branches.push({ expression, body: branchBody });\n frame.currentBody = branchBody;\n currentBody = branchBody;\n continue;\n }\n\n if (token.source === \"else\") {\n const frame = stack.at(-1);\n if (!frame || frame.sawElse) {\n issues.push(issue(\"invalid_template_structure\", \"else must appear once inside an if block.\"));\n continue;\n }\n const elseBody: TemplateNode[] = [];\n frame.node.elseBody = elseBody;\n frame.currentBody = elseBody;\n frame.sawElse = true;\n currentBody = elseBody;\n continue;\n }\n\n if (token.source === \"endif\") {\n const frame = stack.pop();\n if (!frame) {\n issues.push(issue(\"invalid_template_structure\", \"endif does not have a matching if block.\"));\n continue;\n }\n currentBody = frame.parentBody;\n continue;\n }\n\n issues.push(issue(\n \"unsupported_template_construct\",\n \"Only if, elif, else, and endif control tags are supported in Store Category prompt templates.\",\n ));\n }\n\n if (stack.length) issues.push(issue(\"invalid_template_structure\", \"Every if block must end with endif.\"));\n return { issues: boundedIssues(issues), nodes, referencedConditionKeys };\n}\n\nfunction validateAvailableConditionKeys(values: readonly string[], issues: StoreCategoryPromptTemplateIssue[]): Set<string> {\n if (values.length > MAX_STORE_CATEGORY_PROMPT_CONDITIONS) {\n issues.push(issue(\"template_too_complex\", `At most ${MAX_STORE_CATEGORY_PROMPT_CONDITIONS} mapping conditions are supported.`));\n }\n const keys = new Set<string>();\n for (const value of values.slice(0, MAX_STORE_CATEGORY_PROMPT_CONDITIONS + 1)) {\n if (!StoreCategoryPromptConditionKeySchema.safeParse(value).success) {\n issues.push(issue(\"invalid_mapping_condition\", `Invalid mapping condition key: ${value}.`));\n continue;\n }\n if (keys.has(value)) {\n issues.push(issue(\"invalid_mapping_condition\", `Duplicate mapping condition key: ${value}.`));\n continue;\n }\n keys.add(value);\n }\n return keys;\n}\n\nexport function validateStoreCategoryPromptTemplate(input: {\n source: string;\n availableConditionKeys: readonly string[];\n}): StoreCategoryPromptTemplateValidation {\n const compiled = compileStoreCategoryPromptTemplate(input.source);\n const issues = [...compiled.issues];\n const available = validateAvailableConditionKeys(input.availableConditionKeys, issues);\n for (const key of compiled.referencedConditionKeys) {\n if (!available.has(key)) issues.push(issue(\"unknown_mapping_condition\", `Prompt template references unavailable mapping condition: mappings.${key}.`));\n }\n const bounded = boundedIssues(issues);\n return { valid: bounded.length === 0, issues: bounded, referencedConditionKeys: compiled.referencedConditionKeys };\n}\n\n\nexport function createStoreCategoryPromptConditionBlock(conditionKey: string): string {\n const parsed = StoreCategoryPromptConditionKeySchema.safeParse(conditionKey);\n if (!parsed.success) throw new TypeError(`Invalid mapping condition key: ${conditionKey}.`);\n return `{% if mappings.${conditionKey} %}\\n\\n{% endif %}`;\n}\n\nexport function createStoreCategoryPromptContext(input: {\n availableConditionKeys: readonly string[];\n selectedConditionKeys: readonly string[];\n}): StoreCategoryPromptContext {\n const issues: StoreCategoryPromptTemplateIssue[] = [];\n const available = validateAvailableConditionKeys(input.availableConditionKeys, issues);\n const selected = validateAvailableConditionKeys(input.selectedConditionKeys, issues);\n for (const key of selected) {\n if (!available.has(key)) issues.push(issue(\"unknown_mapping_condition\", `Selected mapping condition is unavailable: ${key}.`));\n }\n if (issues.length) throw new TypeError(issues[0].message);\n const mappings = Object.create(null) as Record<string, boolean>;\n for (const key of available) mappings[key] = selected.has(key);\n return { mappings };\n}\n\nfunction evaluateExpression(expression: ExpressionNode, mappings: Record<string, boolean>): boolean {\n switch (expression.kind) {\n case \"condition\":\n return mappings[expression.key] === true;\n case \"not\":\n return !evaluateExpression(expression.operand, mappings);\n case \"and\":\n return evaluateExpression(expression.left, mappings) && evaluateExpression(expression.right, mappings);\n case \"or\":\n return evaluateExpression(expression.left, mappings) || evaluateExpression(expression.right, mappings);\n }\n}\n\nfunction renderNodes(nodes: TemplateNode[], mappings: Record<string, boolean>, append: (text: string) => boolean): boolean {\n for (const node of nodes) {\n if (node.kind === \"text\") {\n if (!append(node.text)) return false;\n continue;\n }\n let renderedBranch = false;\n for (const branch of node.branches) {\n if (evaluateExpression(branch.expression, mappings)) {\n if (!renderNodes(branch.body, mappings, append)) return false;\n renderedBranch = true;\n break;\n }\n }\n if (!renderedBranch && node.elseBody && !renderNodes(node.elseBody, mappings, append)) return false;\n }\n return true;\n}\n\nexport function renderStoreCategoryPromptTemplate(input: {\n source: string;\n context: StoreCategoryPromptContext;\n}): StoreCategoryPromptRenderResult {\n const contextResult = StoreCategoryPromptContextSchema.safeParse(input.context);\n if (!contextResult.success) {\n return { ok: false, issues: [issue(\"invalid_mapping_condition\", \"Store Category prompt context contains invalid mapping conditions.\")] };\n }\n const availableConditionKeys = Object.keys(contextResult.data.mappings);\n const validation = validateStoreCategoryPromptTemplate({ source: input.source, availableConditionKeys });\n if (!validation.valid) return { ok: false, issues: validation.issues };\n\n const compiled = compileStoreCategoryPromptTemplate(input.source);\n let output = \"\";\n let outputChars = 0;\n const append = (text: string) => {\n outputChars += sourceLength(text);\n if (outputChars > MAX_STORE_CATEGORY_PROMPT_RENDERED_CHARS) return false;\n output += text;\n return true;\n };\n const rendered = renderNodes(compiled.nodes, contextResult.data.mappings, append);\n if (!rendered) {\n return {\n ok: false,\n issues: [issue(\"rendered_prompt_too_large\", `Rendered prompt must not exceed ${MAX_STORE_CATEGORY_PROMPT_RENDERED_CHARS.toLocaleString()} characters.`)],\n };\n }\n return { ok: true, promptText: output, referencedConditionKeys: validation.referencedConditionKeys };\n}\n","/** Synthetic examples; no provider identity, schema artifact or publication claim. */\nimport type {\n CommerceManifest,\n CommerceConversationGrant,\n CommerceTurnIdentity,\n} from \"./schemas\";\nimport {\n EMPTY_RESPONSE_CONTRACT,\n type CommerceFinalResponse,\n} from \"./response\";\nimport type { Digest } from \"./canonical-json\";\nimport { responseContractCanonicalJson } from \"./canonical-json\";\nimport type { ToolDescriptor, CommerceToolDefinition } from \"./definitions\";\nexport const exampleTool: ToolDescriptor = {\n toolId: \"tool-fixture\",\n toolRevisionId: \"revision-fixture\",\n name: \"never_seeded_catalogue_facts\",\n definitionVersion: \"1.0.0\",\n description: \"Read synthetic catalogue facts.\",\n inputSchema: {\n type: \"object\",\n properties: { handle: { type: \"string\", minLength: 1, maxLength: 255 } },\n required: [\"handle\"],\n additionalProperties: false,\n },\n};\nexport const exampleDefinition: CommerceToolDefinition = {\n name: exampleTool.name,\n definitionVersion: \"1.0.0\",\n description: exampleTool.description,\n inputSchema: exampleTool.inputSchema,\n execution: {\n kind: \"SHOPIFY_STOREFRONT_QUERY\",\n executorVersion: \"1.0.0\",\n apiVersion: \"2026-07\",\n schemaHash: \"a\".repeat(64),\n document:\n \"query ProductDetails($handle: String!) { product(handle: $handle) { title description } }\",\n operationName: \"ProductDetails\",\n variables: { handle: { input: \"handle\" } },\n resultPath: \"product\",\n },\n responseTemplate: {\n kind: \"text\",\n text: \"{{result.values.title}}: {{result.values.description}}\",\n unavailable: \"Product details could not be verified.\",\n },\n};\nexport const exampleTurn: CommerceTurnIdentity = {\n contractVersion: \"commerce.v1\",\n shopId: \"shop-fixture\",\n checkoutRecoveryId: \"recovery-fixture\",\n conversationId: \"conversation-fixture\",\n inboundVersion: 1,\n};\nexport function exampleManifest(\n digest: Digest,\n withTool = false,\n): CommerceManifest {\n const capabilities = withTool\n ? [{\n capabilityId: \"capability-fixture\",\n key: \"feature_product_read\",\n featureId: \"feature-fixture\",\n position: 0,\n toolDescriptor: structuredClone(exampleTool),\n }]\n : [];\n return {\n contractVersion: \"commerce.v1\",\n releaseId: \"release-fixture\",\n runnerCompatibility: \"^1.0.0\",\n capabilities,\n featureBehaviours: withTool\n ? [{ featureId: \"feature-fixture\", behaviourPrompt: \"Synthetic Feature behavior.\" }]\n : [],\n selectedCapabilityKeys: capabilities.map((capability) => capability.key),\n grantedTools: withTool\n ? [\n {\n toolId: exampleTool.toolId,\n toolRevisionId: exampleTool.toolRevisionId,\n toolName: exampleTool.name,\n definitionVersion: \"1.0.0\",\n capabilityKeys: [\"feature_product_read\"],\n },\n ]\n : [],\n responseContract: structuredClone(EMPTY_RESPONSE_CONTRACT),\n responseContractHash: digest(\n responseContractCanonicalJson(EMPTY_RESPONSE_CONTRACT),\n ),\n };\n}\nexport function exampleGrant(\n manifest: CommerceManifest,\n): CommerceConversationGrant {\n return {\n id: \"grant-fixture\",\n shopId: exampleTurn.shopId,\n conversationId: exampleTurn.conversationId,\n initialInboundVersion: 1,\n releaseId: manifest.releaseId,\n selectedCapabilityKeys: [...manifest.selectedCapabilityKeys],\n grantedTools: structuredClone(manifest.grantedTools),\n runnerVersion: \"1.0.0\",\n createdAt: \"2026-09-20T00:00:00.000Z\",\n expiresAt: null,\n };\n}\nexport const exampleFinal: CommerceFinalResponse = {\n answerKind: \"REFER_TO_STORE\",\n replyText:\n \"I cannot verify that information. Please contact the store directly.\",\n referralReason: \"INSUFFICIENT_TOOLS\",\n detectedLanguageTag: null,\n detectedLanguageConfidence: null,\n evidenceIds: [],\n details: {},\n};\n"],"mappings":"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","names":[]}
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  export { CatalogueValidationOptions, CountryCode, CountryCodeSchema, CurrencyCode, CurrencyCodeSchema, IcuMessageCatalogue, IcuMessageValues, InternationalContext, InternationalContextSchema, InternationalizationRuntime, InternationalizationRuntimeOptions, LanguageSource, LanguageSourceSchema, LanguageTag, LanguageTagSchema, MODA_SUPPORTED_LANGUAGE_TAGS, ModaSupportedLanguageTag, ModaSupportedLanguageTagSchema, TimeZoneId, TimeZoneIdSchema, canonicaliseLanguageTag, createInternationalizationRuntime, mergeInternationalContext, normalizeCountryCode, normalizeCurrencyCode, normalizeTimeZone, resolveLocaleDirection, resolveModaConfigurationLocale, validateIcuCatalogue } from './internationalization.js';
2
- export { APP_PRICING_BILLING_PERIOD_DRAIN_WINDOW_MS, ARCH007_BILLING_CONTRACT_SCHEMA_VERSION, BILLING_PLAN_KINDS, BILLING_SUBSCRIPTION_RECONCILE_JOB_NAME, BILLING_SUBSCRIPTION_RECONCILE_QUEUE_NAME, BILLING_SUBSCRIPTION_RECONCILE_SCHEMA_VERSION, BILLING_SYSTEM_MESSAGE_CODES, BILLING_USAGE_METRICS, BillingPlanKind, BillingPlanKindSchema, BillingSubscriptionReconcileJob, BillingSubscriptionReconcileJobSchema, BillingSystemMessageCode, BillingSystemMessageCodeSchema, BillingUsageMetric, BillingUsageMetricSchema, NormalizedWhatsAppStatus, NormalizedWhatsAppStatusSchema, PurchasedRecoveryCreditCounterSnapshot, ShopifyCurrentProviderContext, ShopifyProviderContextIdentityInput, ShopifyPurchaseProviderContext, WHATSAPP_PROVIDER_STATUSES, WHATSAPP_PROVIDER_STATUS_SCHEMA_VERSION, WhatsAppProviderPricingMetadata, WhatsAppProviderPricingMetadataSchema, WhatsAppProviderStatus, WhatsAppProviderStatusSchema, availablePurchasedRecoveryCredits, createBillingSubscriptionReconcileJobId, createMerchantBillingSystemSourceKey, createRecoveryIdempotencyKey, createShopifyUsageIdempotencyKey, deriveShopifyProviderContextIdentity, isSameShopifyPurchaseProviderContext, parseBillingSubscriptionReconcileJob, parseNormalizedWhatsAppStatus, safeParseBillingSubscriptionReconcileJob, safeParseNormalizedWhatsAppStatus } from './billing.js';
2
+ export { APP_PRICING_BILLING_PERIOD_DRAIN_WINDOW_MS, ARCH007_BILLING_CONTRACT_SCHEMA_VERSION, BILLING_PLAN_KINDS, BILLING_SUBSCRIPTION_RECONCILE_JOB_NAME, BILLING_SUBSCRIPTION_RECONCILE_QUEUE_NAME, BILLING_SUBSCRIPTION_RECONCILE_SCHEMA_VERSION, BILLING_SYSTEM_MESSAGE_CODES, BILLING_USAGE_METRICS, BillingPlanKind, BillingPlanKindSchema, BillingSubscriptionReconcileJob, BillingSubscriptionReconcileJobSchema, BillingSystemMessageCode, BillingSystemMessageCodeSchema, BillingUsageMetric, BillingUsageMetricSchema, NormalizedWhatsAppStatus, NormalizedWhatsAppStatusSchema, NormalizedWhatsAppStatusV2, NormalizedWhatsAppStatusV2Schema, NormalizedWhatsAppStatusV3, NormalizedWhatsAppStatusV3Schema, PurchasedRecoveryCreditCounterSnapshot, ShopifyCurrentProviderContext, ShopifyProviderContextIdentityInput, ShopifyPurchaseProviderContext, WHATSAPP_PROVIDER_STATUSES, WHATSAPP_PROVIDER_STATUS_SCHEMA_VERSION, WHATSAPP_PROVIDER_STATUS_V2_SCHEMA_VERSION, WhatsAppProviderFailureEvidence, WhatsAppProviderFailureEvidenceSchema, WhatsAppProviderPricingMetadata, WhatsAppProviderPricingMetadataSchema, WhatsAppProviderStatus, WhatsAppProviderStatusSchema, availablePurchasedRecoveryCredits, createBillingSubscriptionReconcileJobId, createMerchantBillingSystemSourceKey, createRecoveryIdempotencyKey, createShopifyUsageIdempotencyKey, deriveShopifyProviderContextIdentity, isSameShopifyPurchaseProviderContext, parseBillingSubscriptionReconcileJob, parseNormalizedWhatsAppStatus, safeParseBillingSubscriptionReconcileJob, safeParseNormalizedWhatsAppStatus } from './billing.js';
3
3
  export { AuthoredSupportBodySchema, MERCHANT_COMMUNICATIONS_JOB_NAMES, MERCHANT_COMMUNICATIONS_QUEUE_NAME, MERCHANT_COMMUNICATIONS_SCHEMA_VERSION, MerchantMessageTranslationContract, MerchantMessageTranslationContractSchema, MerchantMessageTranslationStatus, MerchantMessageTranslationStatusSchema, MerchantSupportMessageContract, MerchantSupportMessageContractSchema, MerchantSupportMessageKind, MerchantSupportMessageKindSchema, MerchantSupportMessageState, MerchantSupportMessageStateSchema, MerchantTranslationBatchContract, MerchantTranslationBatchContractSchema, MerchantTranslationBatchStatus, MerchantTranslationBatchStatusSchema, MerchantTranslationDirection, MerchantTranslationDirectionSchema, MerchantTranslationReconciliationRequestContract, MerchantTranslationReconciliationRequestContractSchema, MerchantTranslationReconciliationScope, MerchantTranslationReconciliationScopeSchema, MerchantTranslationReconciliationStatus, MerchantTranslationReconciliationStatusSchema, PLATFORM_SUPPORT_LANGUAGE_TAG, TranslatedSupportBodySchema, TranslationBatchPollJob, TranslationBatchPollJobSchema, TranslationBatchResultsJob, TranslationBatchResultsJobSchema, TranslationBatchSubmitJob, TranslationBatchSubmitJobSchema, TranslationDispatchJob, TranslationDispatchJobSchema, TranslationReconcileJob, TranslationReconcileJobSchema, countUnicodeGraphemes, requiresMerchantTranslation } from './merchant-communications.js';
4
4
  export { EffectiveRecoveryPolicy, EffectiveRecoveryPolicySchema, RECOVERY_OFFER_MODES, RecoveryOfferMode, RecoveryOfferModeSchema, parseEffectiveRecoveryPolicy, safeParseEffectiveRecoveryPolicy } from './recovery-policy.js';
5
5
  export { CheckoutCreatedPayloadV2, CheckoutCreatedPayloadV2Schema, CheckoutObservedPayload, CheckoutObservedPayloadSchema, CheckoutUpdatedPayloadV2, CheckoutUpdatedPayloadV2Schema, MAX_LINE_ITEMS, MAX_URL_LENGTH, OrderCompletedPayload, OrderCompletedPayloadSchema, OrderCompletedPayloadV2, OrderCompletedPayloadV2Schema, SHOPIFY_COMMERCE_EVENT_SCHEMA_VERSION, SHOPIFY_COMMERCE_EVENT_SCHEMA_VERSION_V1, SHOPIFY_COMMERCE_EVENT_SCHEMA_VERSION_V2, SHOPIFY_COMMERCE_EVENT_TYPES, SHOPIFY_DISCOUNT_SYNC_REASONS, SHOPIFY_DISCOUNT_SYNC_WEBHOOK_TOPICS, SHOPIFY_RECOVERY_EVENT_TYPES_V2, SHOPIFY_WEBHOOK_OUTBOX_DESTINATIONS, SHOPIFY_WEBHOOK_QUEUE_CONTRACTS, ShopifyCartActivityEventV2, ShopifyCartActivityEventV2Schema, ShopifyCartActivityPayloadV2, ShopifyCartActivityPayloadV2Schema, ShopifyCheckoutCreatedEventV2, ShopifyCheckoutCreatedEventV2Schema, ShopifyCheckoutLineItem, ShopifyCheckoutLineItemSchema, ShopifyCheckoutLineItemsSchema, ShopifyCheckoutObservedEvent, ShopifyCheckoutObservedEventSchema, ShopifyCheckoutUpdatedEventV2, ShopifyCheckoutUpdatedEventV2Schema, ShopifyCommerceEvent, ShopifyCommerceEventSchema, ShopifyCommerceEventType, ShopifyCustomerReference, ShopifyCustomerReferenceSchema, ShopifyDiscountSyncJob, ShopifyDiscountSyncJobSchema, ShopifyDiscountSyncReasonSchema, ShopifyDiscountSyncWebhookTopicSchema, ShopifyMoney, ShopifyMoneySchema, ShopifyOrderCompletedEvent, ShopifyOrderCompletedEventSchema, ShopifyOrderCompletedEventV2, ShopifyOrderCompletedEventV2Schema, ShopifyRecoveryEventTypeV2, ShopifyRecoveryEventV2, ShopifyRecoveryEventV2Schema, ShopifyTenant, ShopifyTenantSchema, createShopifyCartActivityOrderingKey, createShopifyCommerceOrderingKey, createShopifyOrderCorrelationOrderingKey, createShopifyOrderOrderingKey, createShopifyPendingRecoveryOrderingKey, isCartActivityEventV2, isCheckoutCreatedEventV2, isCheckoutObservedEvent, isCheckoutUpdatedEventV2, isOrderCompletedEvent, isOrderCompletedEventV2, parseShopifyCommerceEvent, parseShopifyDiscountSyncJob, parseShopifyRecoveryEventV2, safeParseShopifyCommerceEvent, safeParseShopifyDiscountSyncJob, safeParseShopifyRecoveryEventV2 } from './shopify/index.js';
package/dist/index.js CHANGED
@@ -12,8 +12,12 @@ import {
12
12
  BillingSystemMessageCodeSchema,
13
13
  BillingUsageMetricSchema,
14
14
  NormalizedWhatsAppStatusSchema,
15
+ NormalizedWhatsAppStatusV2Schema,
16
+ NormalizedWhatsAppStatusV3Schema,
15
17
  WHATSAPP_PROVIDER_STATUSES,
16
18
  WHATSAPP_PROVIDER_STATUS_SCHEMA_VERSION,
19
+ WHATSAPP_PROVIDER_STATUS_V2_SCHEMA_VERSION,
20
+ WhatsAppProviderFailureEvidenceSchema,
17
21
  WhatsAppProviderPricingMetadataSchema,
18
22
  WhatsAppProviderStatusSchema,
19
23
  availablePurchasedRecoveryCredits,
@@ -27,7 +31,7 @@ import {
27
31
  parseNormalizedWhatsAppStatus,
28
32
  safeParseBillingSubscriptionReconcileJob,
29
33
  safeParseNormalizedWhatsAppStatus
30
- } from "./chunk-ANBEH6NW.js";
34
+ } from "./chunk-HIHWRUZH.js";
31
35
  import {
32
36
  EffectiveRecoveryPolicySchema,
33
37
  RECOVERY_OFFER_MODES,
@@ -174,6 +178,8 @@ export {
174
178
  MerchantTranslationReconciliationStatusSchema,
175
179
  ModaSupportedLanguageTagSchema,
176
180
  NormalizedWhatsAppStatusSchema,
181
+ NormalizedWhatsAppStatusV2Schema,
182
+ NormalizedWhatsAppStatusV3Schema,
177
183
  OrderCompletedPayloadSchema,
178
184
  OrderCompletedPayloadV2Schema,
179
185
  PLATFORM_SUPPORT_LANGUAGE_TAG,
@@ -214,6 +220,8 @@ export {
214
220
  TranslationReconcileJobSchema,
215
221
  WHATSAPP_PROVIDER_STATUSES,
216
222
  WHATSAPP_PROVIDER_STATUS_SCHEMA_VERSION,
223
+ WHATSAPP_PROVIDER_STATUS_V2_SCHEMA_VERSION,
224
+ WhatsAppProviderFailureEvidenceSchema,
217
225
  WhatsAppProviderPricingMetadataSchema,
218
226
  WhatsAppProviderStatusSchema,
219
227
  availablePurchasedRecoveryCredits,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@modainteract/moda-interact-shared",
3
- "version": "1.2.0",
3
+ "version": "1.3.1",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
@@ -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().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":[]}