@modainteract/moda-interact-shared 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +67 -0
- package/dist/chunk-NE5RMNXU.js +142 -0
- package/dist/chunk-NE5RMNXU.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +47 -0
- package/dist/index.js.map +1 -0
- package/dist/shopify/index.d.ts +331 -0
- package/dist/shopify/index.js +47 -0
- package/dist/shopify/index.js.map +1 -0
- package/dist/shopify/node.d.ts +7 -0
- package/dist/shopify/node.js +16 -0
- package/dist/shopify/node.js.map +1 -0
- package/package.json +42 -0
package/README.md
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# @modainteract/moda-interact-shared
|
|
2
|
+
|
|
3
|
+
Shared, runtime-validated TypeScript contracts used by more than one Moda
|
|
4
|
+
Interact service. This package is a library, not a service: it has no
|
|
5
|
+
transport, persistence, or framework code of its own.
|
|
6
|
+
|
|
7
|
+
## What this package owns
|
|
8
|
+
|
|
9
|
+
- Zod schemas for cross-service event contracts (currently: Shopify commerce
|
|
10
|
+
events).
|
|
11
|
+
- TypeScript types inferred from those schemas (`z.infer`), so producers and
|
|
12
|
+
consumers share one source of truth.
|
|
13
|
+
- Constants (queue/job names, schema version, event type strings).
|
|
14
|
+
- Parsing helpers and small pure utilities (ordering-key and job-id
|
|
15
|
+
derivation) needed to construct or validate those contracts.
|
|
16
|
+
|
|
17
|
+
This package does **not** define Prisma models, own migrations, or implement
|
|
18
|
+
any queue/transport client. PostgreSQL and Redis store the *serialized*
|
|
19
|
+
event envelope as JSON; the database layer does not enforce or duplicate its
|
|
20
|
+
shape. Producers must construct and validate an event with the schemas in
|
|
21
|
+
this package before persisting it. Consumers must parse the JSON read back
|
|
22
|
+
from PostgreSQL/Redis with the same schemas before acting on it — never trust
|
|
23
|
+
it as pre-validated.
|
|
24
|
+
|
|
25
|
+
## Ownership boundary
|
|
26
|
+
|
|
27
|
+
- **moda-interact** — authenticates Shopify webhooks, normalizes payloads,
|
|
28
|
+
constructs and validates a `ShopifyCommerceEvent`, and writes it to the
|
|
29
|
+
transactional outbox.
|
|
30
|
+
- **moda-interact-background** — parses `ShopifyCommerceEvent` (via
|
|
31
|
+
`parseShopifyCommerceEvent` / `safeParseShopifyCommerceEvent`) before
|
|
32
|
+
processing, dispatches by `eventType`, and applies tenant-safe, idempotent
|
|
33
|
+
domain transitions.
|
|
34
|
+
- **moda-interact-database** — stores receipt metadata and outbox JSON. It
|
|
35
|
+
does not own or duplicate the TypeScript event types defined here.
|
|
36
|
+
|
|
37
|
+
## Schema versioning
|
|
38
|
+
|
|
39
|
+
`schemaVersion` is embedded in every serialized event and is currently `1`.
|
|
40
|
+
|
|
41
|
+
- Any breaking change to the serialized shape (removing/renaming a field,
|
|
42
|
+
changing a type, tightening validation in a way that rejects previously
|
|
43
|
+
valid data) requires bumping `SHOPIFY_COMMERCE_EVENT_SCHEMA_VERSION` and
|
|
44
|
+
updating the schema to branch on it.
|
|
45
|
+
- Additive, optional-field changes do not require a version bump, but must
|
|
46
|
+
still be reviewed for old-consumer safety (an older consumer parsing a
|
|
47
|
+
newer envelope must not fail just because of a new optional field).
|
|
48
|
+
|
|
49
|
+
## Exports
|
|
50
|
+
|
|
51
|
+
- `@modainteract/moda-interact-shared` — re-exports everything from
|
|
52
|
+
`./shopify`.
|
|
53
|
+
- `@modainteract/moda-interact-shared/shopify` — schemas, types, constants,
|
|
54
|
+
and the pure `createShopifyCommerceOrderingKey` helper. Safe for browser
|
|
55
|
+
bundles (no Node built-ins).
|
|
56
|
+
- `@modainteract/moda-interact-shared/shopify/node` — `createShopifyWebhookJobId`,
|
|
57
|
+
which uses `node:crypto` and is therefore isolated in a Node-only subpath so
|
|
58
|
+
it isn't accidentally pulled into browser bundles that import the root or
|
|
59
|
+
`./shopify` entry points.
|
|
60
|
+
|
|
61
|
+
## Building and testing
|
|
62
|
+
|
|
63
|
+
```sh
|
|
64
|
+
npm run typecheck
|
|
65
|
+
npm run build
|
|
66
|
+
npm test
|
|
67
|
+
```
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
// src/shopify/constants.ts
|
|
2
|
+
var SHOPIFY_COMMERCE_EVENT_SCHEMA_VERSION = 1;
|
|
3
|
+
var SHOPIFY_COMMERCE_QUEUE = "commerce-events";
|
|
4
|
+
var SHOPIFY_COMMERCE_JOB = "shopify-commerce-event";
|
|
5
|
+
var SHOPIFY_COMMERCE_EVENT_TYPES = {
|
|
6
|
+
CHECKOUT_OBSERVED: "checkout.observed",
|
|
7
|
+
ORDER_COMPLETED: "order.completed"
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
// src/shopify/common.schema.ts
|
|
11
|
+
import { z } from "zod";
|
|
12
|
+
var MAX_ID_LENGTH = 100;
|
|
13
|
+
var MAX_SHORT_TEXT_LENGTH = 320;
|
|
14
|
+
var MAX_TITLE_LENGTH = 500;
|
|
15
|
+
var MAX_URL_LENGTH = 2048;
|
|
16
|
+
var MAX_LINE_ITEMS = 250;
|
|
17
|
+
var decimalStringPattern = /^-?\d+(\.\d+)?$/;
|
|
18
|
+
var DecimalStringSchema = z.string().min(1).max(32).regex(decimalStringPattern, 'must be a decimal string, e.g. "12.34"');
|
|
19
|
+
var ShopifyTenantSchema = z.object({
|
|
20
|
+
shopId: z.string().min(1).max(MAX_ID_LENGTH),
|
|
21
|
+
shopDomain: z.string().min(1).max(MAX_SHORT_TEXT_LENGTH).toLowerCase().trim()
|
|
22
|
+
}).strict();
|
|
23
|
+
var ShopifyCustomerReferenceSchema = z.object({
|
|
24
|
+
shopifyCustomerId: z.string().min(1).max(MAX_ID_LENGTH).nullable(),
|
|
25
|
+
email: z.string().email().max(MAX_SHORT_TEXT_LENGTH).nullable(),
|
|
26
|
+
phone: z.string().min(1).max(64).nullable(),
|
|
27
|
+
firstName: z.string().min(1).max(MAX_TITLE_LENGTH).nullable(),
|
|
28
|
+
lastName: z.string().min(1).max(MAX_TITLE_LENGTH).nullable()
|
|
29
|
+
}).strict();
|
|
30
|
+
var ShopifyMoneySchema = z.object({
|
|
31
|
+
amount: DecimalStringSchema,
|
|
32
|
+
currencyCode: z.string().regex(/^[A-Z]{3}$/, "must be an uppercase three-letter currency code")
|
|
33
|
+
}).strict();
|
|
34
|
+
var ShopifyCheckoutLineItemSchema = z.object({
|
|
35
|
+
lineItemId: z.string().min(1).max(MAX_ID_LENGTH).nullable(),
|
|
36
|
+
variantId: z.string().min(1).max(MAX_ID_LENGTH).nullable(),
|
|
37
|
+
productId: z.string().min(1).max(MAX_ID_LENGTH).nullable(),
|
|
38
|
+
title: z.string().min(1).max(MAX_TITLE_LENGTH),
|
|
39
|
+
variantTitle: z.string().min(1).max(MAX_TITLE_LENGTH).nullable(),
|
|
40
|
+
quantity: z.number().int().positive(),
|
|
41
|
+
unitPrice: DecimalStringSchema.nullable(),
|
|
42
|
+
sku: z.string().min(1).max(MAX_ID_LENGTH).nullable()
|
|
43
|
+
}).strict();
|
|
44
|
+
var ShopifyCheckoutLineItemsSchema = z.array(ShopifyCheckoutLineItemSchema).max(MAX_LINE_ITEMS);
|
|
45
|
+
|
|
46
|
+
// src/shopify/checkout-observed.schema.ts
|
|
47
|
+
import { z as z2 } from "zod";
|
|
48
|
+
var CheckoutObservedPayloadSchema = z2.object({
|
|
49
|
+
checkoutToken: z2.string().min(1),
|
|
50
|
+
cartToken: z2.string().min(1).nullable(),
|
|
51
|
+
checkoutUrl: z2.url().max(MAX_URL_LENGTH).nullable(),
|
|
52
|
+
customer: ShopifyCustomerReferenceSchema.nullable(),
|
|
53
|
+
total: ShopifyMoneySchema.nullable(),
|
|
54
|
+
lineItems: ShopifyCheckoutLineItemsSchema,
|
|
55
|
+
checkoutCreatedAt: z2.iso.datetime().nullable(),
|
|
56
|
+
checkoutUpdatedAt: z2.iso.datetime().nullable(),
|
|
57
|
+
completedAt: z2.iso.datetime().nullable()
|
|
58
|
+
}).strict();
|
|
59
|
+
|
|
60
|
+
// src/shopify/order-completed.schema.ts
|
|
61
|
+
import { z as z3 } from "zod";
|
|
62
|
+
var OrderCompletedPayloadSchema = z3.object({
|
|
63
|
+
orderId: z3.string().min(1),
|
|
64
|
+
checkoutToken: z3.string().min(1),
|
|
65
|
+
shopifyCustomerId: z3.string().min(1).nullable(),
|
|
66
|
+
total: ShopifyMoneySchema.nullable(),
|
|
67
|
+
completedAt: z3.iso.datetime()
|
|
68
|
+
}).strict();
|
|
69
|
+
|
|
70
|
+
// src/shopify/commerce-event.schema.ts
|
|
71
|
+
import { z as z4 } from "zod";
|
|
72
|
+
var ShopifyCommerceEventBaseSchema = z4.object({
|
|
73
|
+
schemaVersion: z4.literal(SHOPIFY_COMMERCE_EVENT_SCHEMA_VERSION),
|
|
74
|
+
receiptId: z4.string().min(1),
|
|
75
|
+
deliveryId: z4.string().min(1),
|
|
76
|
+
eventId: z4.string().min(1).nullable(),
|
|
77
|
+
source: z4.literal("shopify"),
|
|
78
|
+
providerTopic: z4.string().min(1),
|
|
79
|
+
tenant: ShopifyTenantSchema,
|
|
80
|
+
occurredAt: z4.iso.datetime().nullable(),
|
|
81
|
+
receivedAt: z4.iso.datetime(),
|
|
82
|
+
traceId: z4.string().min(1),
|
|
83
|
+
orderingKey: z4.string().min(1)
|
|
84
|
+
});
|
|
85
|
+
var ShopifyCheckoutObservedEventSchema = ShopifyCommerceEventBaseSchema.extend({
|
|
86
|
+
eventType: z4.literal(SHOPIFY_COMMERCE_EVENT_TYPES.CHECKOUT_OBSERVED),
|
|
87
|
+
payload: CheckoutObservedPayloadSchema
|
|
88
|
+
}).strict();
|
|
89
|
+
var ShopifyOrderCompletedEventSchema = ShopifyCommerceEventBaseSchema.extend({
|
|
90
|
+
eventType: z4.literal(SHOPIFY_COMMERCE_EVENT_TYPES.ORDER_COMPLETED),
|
|
91
|
+
payload: OrderCompletedPayloadSchema
|
|
92
|
+
}).strict();
|
|
93
|
+
var ShopifyCommerceEventSchema = z4.discriminatedUnion("eventType", [
|
|
94
|
+
ShopifyCheckoutObservedEventSchema,
|
|
95
|
+
ShopifyOrderCompletedEventSchema
|
|
96
|
+
]);
|
|
97
|
+
function parseShopifyCommerceEvent(input) {
|
|
98
|
+
return ShopifyCommerceEventSchema.parse(input);
|
|
99
|
+
}
|
|
100
|
+
function safeParseShopifyCommerceEvent(input) {
|
|
101
|
+
return ShopifyCommerceEventSchema.safeParse(input);
|
|
102
|
+
}
|
|
103
|
+
function isCheckoutObservedEvent(event) {
|
|
104
|
+
return event.eventType === SHOPIFY_COMMERCE_EVENT_TYPES.CHECKOUT_OBSERVED;
|
|
105
|
+
}
|
|
106
|
+
function isOrderCompletedEvent(event) {
|
|
107
|
+
return event.eventType === SHOPIFY_COMMERCE_EVENT_TYPES.ORDER_COMPLETED;
|
|
108
|
+
}
|
|
109
|
+
function createShopifyCommerceOrderingKey(shopId, checkoutToken) {
|
|
110
|
+
if (typeof shopId !== "string" || shopId.length === 0) {
|
|
111
|
+
throw new Error("createShopifyCommerceOrderingKey: shopId must be a non-empty string");
|
|
112
|
+
}
|
|
113
|
+
if (typeof checkoutToken !== "string" || checkoutToken.length === 0) {
|
|
114
|
+
throw new Error("createShopifyCommerceOrderingKey: checkoutToken must be a non-empty string");
|
|
115
|
+
}
|
|
116
|
+
return `shopify:${shopId.length}:${shopId}:${checkoutToken.length}:${checkoutToken}`;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
export {
|
|
120
|
+
SHOPIFY_COMMERCE_EVENT_SCHEMA_VERSION,
|
|
121
|
+
SHOPIFY_COMMERCE_QUEUE,
|
|
122
|
+
SHOPIFY_COMMERCE_JOB,
|
|
123
|
+
SHOPIFY_COMMERCE_EVENT_TYPES,
|
|
124
|
+
MAX_URL_LENGTH,
|
|
125
|
+
MAX_LINE_ITEMS,
|
|
126
|
+
ShopifyTenantSchema,
|
|
127
|
+
ShopifyCustomerReferenceSchema,
|
|
128
|
+
ShopifyMoneySchema,
|
|
129
|
+
ShopifyCheckoutLineItemSchema,
|
|
130
|
+
ShopifyCheckoutLineItemsSchema,
|
|
131
|
+
CheckoutObservedPayloadSchema,
|
|
132
|
+
OrderCompletedPayloadSchema,
|
|
133
|
+
ShopifyCheckoutObservedEventSchema,
|
|
134
|
+
ShopifyOrderCompletedEventSchema,
|
|
135
|
+
ShopifyCommerceEventSchema,
|
|
136
|
+
parseShopifyCommerceEvent,
|
|
137
|
+
safeParseShopifyCommerceEvent,
|
|
138
|
+
isCheckoutObservedEvent,
|
|
139
|
+
isOrderCompletedEvent,
|
|
140
|
+
createShopifyCommerceOrderingKey
|
|
141
|
+
};
|
|
142
|
+
//# sourceMappingURL=chunk-NE5RMNXU.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/shopify/constants.ts","../src/shopify/common.schema.ts","../src/shopify/checkout-observed.schema.ts","../src/shopify/order-completed.schema.ts","../src/shopify/commerce-event.schema.ts"],"sourcesContent":["export const SHOPIFY_COMMERCE_EVENT_SCHEMA_VERSION = 1 as const;\n\nexport const SHOPIFY_COMMERCE_QUEUE = \"commerce-events\" as const;\nexport const SHOPIFY_COMMERCE_JOB = \"shopify-commerce-event\" as const;\n\nexport const SHOPIFY_COMMERCE_EVENT_TYPES = {\n CHECKOUT_OBSERVED: \"checkout.observed\",\n ORDER_COMPLETED: \"order.completed\",\n} as const;\n","import { z } from \"zod\";\n\n/**\n * Reasonable upper bounds for externally controlled (Shopify-originated) strings.\n * These exist to keep queue messages small and predictable, not to validate business rules.\n */\nconst MAX_ID_LENGTH = 100;\nconst MAX_SHORT_TEXT_LENGTH = 320;\nconst MAX_TITLE_LENGTH = 500;\nconst MAX_URL_LENGTH = 2048;\nconst MAX_LINE_ITEMS = 250;\n\nconst decimalStringPattern = /^-?\\d+(\\.\\d+)?$/;\n\n/** Decimal amount encoded as a string; never a JS number to avoid float precision loss. */\nconst DecimalStringSchema = z\n .string()\n .min(1)\n .max(32)\n .regex(decimalStringPattern, \"must be a decimal string, e.g. \\\"12.34\\\"\");\n\nexport const ShopifyTenantSchema = z\n .object({\n shopId: z.string().min(1).max(MAX_ID_LENGTH),\n shopDomain: z\n .string()\n .min(1)\n .max(MAX_SHORT_TEXT_LENGTH)\n .toLowerCase()\n .trim(),\n })\n .strict();\n\nexport type ShopifyTenant = z.infer<typeof ShopifyTenantSchema>;\n\nexport const ShopifyCustomerReferenceSchema = z\n .object({\n shopifyCustomerId: z.string().min(1).max(MAX_ID_LENGTH).nullable(),\n email: z.string().email().max(MAX_SHORT_TEXT_LENGTH).nullable(),\n phone: z.string().min(1).max(64).nullable(),\n firstName: z.string().min(1).max(MAX_TITLE_LENGTH).nullable(),\n lastName: z.string().min(1).max(MAX_TITLE_LENGTH).nullable(),\n })\n .strict();\n\nexport type ShopifyCustomerReference = z.infer<typeof ShopifyCustomerReferenceSchema>;\n\nexport const ShopifyMoneySchema = z\n .object({\n amount: DecimalStringSchema,\n currencyCode: z\n .string()\n .regex(/^[A-Z]{3}$/, \"must be an uppercase three-letter currency code\"),\n })\n .strict();\n\nexport type ShopifyMoney = z.infer<typeof ShopifyMoneySchema>;\n\n/**\n * Fields limited to what checkout recovery and customer-facing basket context require.\n * Line-item arrays are bounded (see MAX_LINE_ITEMS) to prevent unexpectedly large queue messages.\n */\nexport const ShopifyCheckoutLineItemSchema = z\n .object({\n lineItemId: z.string().min(1).max(MAX_ID_LENGTH).nullable(),\n variantId: z.string().min(1).max(MAX_ID_LENGTH).nullable(),\n productId: z.string().min(1).max(MAX_ID_LENGTH).nullable(),\n title: z.string().min(1).max(MAX_TITLE_LENGTH),\n variantTitle: z.string().min(1).max(MAX_TITLE_LENGTH).nullable(),\n quantity: z.number().int().positive(),\n unitPrice: DecimalStringSchema.nullable(),\n sku: z.string().min(1).max(MAX_ID_LENGTH).nullable(),\n })\n .strict();\n\nexport type ShopifyCheckoutLineItem = z.infer<typeof ShopifyCheckoutLineItemSchema>;\n\nexport const ShopifyCheckoutLineItemsSchema = z\n .array(ShopifyCheckoutLineItemSchema)\n .max(MAX_LINE_ITEMS);\n\nexport { MAX_URL_LENGTH, MAX_LINE_ITEMS };\n","import { z } from \"zod\";\nimport {\n MAX_URL_LENGTH,\n ShopifyCheckoutLineItemsSchema,\n ShopifyCustomerReferenceSchema,\n ShopifyMoneySchema,\n} from \"./common.schema.js\";\n\nexport const CheckoutObservedPayloadSchema = z\n .object({\n checkoutToken: z.string().min(1),\n cartToken: z.string().min(1).nullable(),\n checkoutUrl: z.url().max(MAX_URL_LENGTH).nullable(),\n customer: ShopifyCustomerReferenceSchema.nullable(),\n total: ShopifyMoneySchema.nullable(),\n lineItems: ShopifyCheckoutLineItemsSchema,\n checkoutCreatedAt: z.iso.datetime().nullable(),\n checkoutUpdatedAt: z.iso.datetime().nullable(),\n completedAt: z.iso.datetime().nullable(),\n })\n .strict();\n\nexport type CheckoutObservedPayload = z.infer<typeof CheckoutObservedPayloadSchema>;\n","import { z } from \"zod\";\nimport { ShopifyMoneySchema } from \"./common.schema.js\";\n\nexport const OrderCompletedPayloadSchema = z\n .object({\n orderId: z.string().min(1),\n checkoutToken: z.string().min(1),\n shopifyCustomerId: z.string().min(1).nullable(),\n total: ShopifyMoneySchema.nullable(),\n completedAt: z.iso.datetime(),\n })\n .strict();\n\nexport type OrderCompletedPayload = z.infer<typeof OrderCompletedPayloadSchema>;\n","import { z } from \"zod\";\nimport { SHOPIFY_COMMERCE_EVENT_SCHEMA_VERSION, SHOPIFY_COMMERCE_EVENT_TYPES } from \"./constants.js\";\nimport { ShopifyTenantSchema } from \"./common.schema.js\";\nimport { CheckoutObservedPayloadSchema } from \"./checkout-observed.schema.js\";\nimport { OrderCompletedPayloadSchema } from \"./order-completed.schema.js\";\n\nconst ShopifyCommerceEventBaseSchema = z.object({\n schemaVersion: z.literal(SHOPIFY_COMMERCE_EVENT_SCHEMA_VERSION),\n receiptId: z.string().min(1),\n deliveryId: z.string().min(1),\n eventId: z.string().min(1).nullable(),\n source: z.literal(\"shopify\"),\n providerTopic: z.string().min(1),\n tenant: ShopifyTenantSchema,\n occurredAt: z.iso.datetime().nullable(),\n receivedAt: z.iso.datetime(),\n traceId: z.string().min(1),\n orderingKey: z.string().min(1),\n});\n\nexport const ShopifyCheckoutObservedEventSchema = ShopifyCommerceEventBaseSchema.extend({\n eventType: z.literal(SHOPIFY_COMMERCE_EVENT_TYPES.CHECKOUT_OBSERVED),\n payload: CheckoutObservedPayloadSchema,\n}).strict();\n\nexport type ShopifyCheckoutObservedEvent = z.infer<typeof ShopifyCheckoutObservedEventSchema>;\n\nexport const ShopifyOrderCompletedEventSchema = ShopifyCommerceEventBaseSchema.extend({\n eventType: z.literal(SHOPIFY_COMMERCE_EVENT_TYPES.ORDER_COMPLETED),\n payload: OrderCompletedPayloadSchema,\n}).strict();\n\nexport type ShopifyOrderCompletedEvent = z.infer<typeof ShopifyOrderCompletedEventSchema>;\n\nexport const ShopifyCommerceEventSchema = z.discriminatedUnion(\"eventType\", [\n ShopifyCheckoutObservedEventSchema,\n ShopifyOrderCompletedEventSchema,\n]);\n\nexport type ShopifyCommerceEvent = z.infer<typeof ShopifyCommerceEventSchema>;\nexport type ShopifyCommerceEventType = ShopifyCommerceEvent[\"eventType\"];\n\nexport function parseShopifyCommerceEvent(input: unknown): ShopifyCommerceEvent {\n return ShopifyCommerceEventSchema.parse(input);\n}\n\nexport function safeParseShopifyCommerceEvent(input: unknown) {\n return ShopifyCommerceEventSchema.safeParse(input);\n}\n\nexport function isCheckoutObservedEvent(\n event: ShopifyCommerceEvent,\n): event is ShopifyCheckoutObservedEvent {\n return event.eventType === SHOPIFY_COMMERCE_EVENT_TYPES.CHECKOUT_OBSERVED;\n}\n\nexport function isOrderCompletedEvent(\n event: ShopifyCommerceEvent,\n): event is ShopifyOrderCompletedEvent {\n return event.eventType === SHOPIFY_COMMERCE_EVENT_TYPES.ORDER_COMPLETED;\n}\n\n/**\n * Stable ordering key for a shop/checkout pair. Checkout and order events for the\n * same checkout must share this key, so deliveryId is intentionally excluded.\n * Values are length-prefixed to avoid ambiguous concatenation (e.g. \"1\" + \"23\" vs \"12\" + \"3\").\n */\nexport function createShopifyCommerceOrderingKey(shopId: string, checkoutToken: string): string {\n if (typeof shopId !== \"string\" || shopId.length === 0) {\n throw new Error(\"createShopifyCommerceOrderingKey: shopId must be a non-empty string\");\n }\n if (typeof checkoutToken !== \"string\" || checkoutToken.length === 0) {\n throw new Error(\"createShopifyCommerceOrderingKey: checkoutToken must be a non-empty string\");\n }\n\n return `shopify:${shopId.length}:${shopId}:${checkoutToken.length}:${checkoutToken}`;\n}\n"],"mappings":"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","names":["z","z","z","z","z","z"]}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
export { CheckoutObservedPayload, CheckoutObservedPayloadSchema, MAX_LINE_ITEMS, MAX_URL_LENGTH, OrderCompletedPayload, OrderCompletedPayloadSchema, SHOPIFY_COMMERCE_EVENT_SCHEMA_VERSION, SHOPIFY_COMMERCE_EVENT_TYPES, SHOPIFY_COMMERCE_JOB, SHOPIFY_COMMERCE_QUEUE, ShopifyCheckoutLineItem, ShopifyCheckoutLineItemSchema, ShopifyCheckoutLineItemsSchema, ShopifyCheckoutObservedEvent, ShopifyCheckoutObservedEventSchema, ShopifyCommerceEvent, ShopifyCommerceEventSchema, ShopifyCommerceEventType, ShopifyCustomerReference, ShopifyCustomerReferenceSchema, ShopifyMoney, ShopifyMoneySchema, ShopifyOrderCompletedEvent, ShopifyOrderCompletedEventSchema, ShopifyTenant, ShopifyTenantSchema, createShopifyCommerceOrderingKey, isCheckoutObservedEvent, isOrderCompletedEvent, parseShopifyCommerceEvent, safeParseShopifyCommerceEvent } from './shopify/index.js';
|
|
2
|
+
import 'zod';
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import {
|
|
2
|
+
CheckoutObservedPayloadSchema,
|
|
3
|
+
MAX_LINE_ITEMS,
|
|
4
|
+
MAX_URL_LENGTH,
|
|
5
|
+
OrderCompletedPayloadSchema,
|
|
6
|
+
SHOPIFY_COMMERCE_EVENT_SCHEMA_VERSION,
|
|
7
|
+
SHOPIFY_COMMERCE_EVENT_TYPES,
|
|
8
|
+
SHOPIFY_COMMERCE_JOB,
|
|
9
|
+
SHOPIFY_COMMERCE_QUEUE,
|
|
10
|
+
ShopifyCheckoutLineItemSchema,
|
|
11
|
+
ShopifyCheckoutLineItemsSchema,
|
|
12
|
+
ShopifyCheckoutObservedEventSchema,
|
|
13
|
+
ShopifyCommerceEventSchema,
|
|
14
|
+
ShopifyCustomerReferenceSchema,
|
|
15
|
+
ShopifyMoneySchema,
|
|
16
|
+
ShopifyOrderCompletedEventSchema,
|
|
17
|
+
ShopifyTenantSchema,
|
|
18
|
+
createShopifyCommerceOrderingKey,
|
|
19
|
+
isCheckoutObservedEvent,
|
|
20
|
+
isOrderCompletedEvent,
|
|
21
|
+
parseShopifyCommerceEvent,
|
|
22
|
+
safeParseShopifyCommerceEvent
|
|
23
|
+
} from "./chunk-NE5RMNXU.js";
|
|
24
|
+
export {
|
|
25
|
+
CheckoutObservedPayloadSchema,
|
|
26
|
+
MAX_LINE_ITEMS,
|
|
27
|
+
MAX_URL_LENGTH,
|
|
28
|
+
OrderCompletedPayloadSchema,
|
|
29
|
+
SHOPIFY_COMMERCE_EVENT_SCHEMA_VERSION,
|
|
30
|
+
SHOPIFY_COMMERCE_EVENT_TYPES,
|
|
31
|
+
SHOPIFY_COMMERCE_JOB,
|
|
32
|
+
SHOPIFY_COMMERCE_QUEUE,
|
|
33
|
+
ShopifyCheckoutLineItemSchema,
|
|
34
|
+
ShopifyCheckoutLineItemsSchema,
|
|
35
|
+
ShopifyCheckoutObservedEventSchema,
|
|
36
|
+
ShopifyCommerceEventSchema,
|
|
37
|
+
ShopifyCustomerReferenceSchema,
|
|
38
|
+
ShopifyMoneySchema,
|
|
39
|
+
ShopifyOrderCompletedEventSchema,
|
|
40
|
+
ShopifyTenantSchema,
|
|
41
|
+
createShopifyCommerceOrderingKey,
|
|
42
|
+
isCheckoutObservedEvent,
|
|
43
|
+
isOrderCompletedEvent,
|
|
44
|
+
parseShopifyCommerceEvent,
|
|
45
|
+
safeParseShopifyCommerceEvent
|
|
46
|
+
};
|
|
47
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
|
@@ -0,0 +1,331 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
|
|
3
|
+
declare const SHOPIFY_COMMERCE_EVENT_SCHEMA_VERSION: 1;
|
|
4
|
+
declare const SHOPIFY_COMMERCE_QUEUE: "commerce-events";
|
|
5
|
+
declare const SHOPIFY_COMMERCE_JOB: "shopify-commerce-event";
|
|
6
|
+
declare const SHOPIFY_COMMERCE_EVENT_TYPES: {
|
|
7
|
+
readonly CHECKOUT_OBSERVED: "checkout.observed";
|
|
8
|
+
readonly ORDER_COMPLETED: "order.completed";
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
declare const MAX_URL_LENGTH = 2048;
|
|
12
|
+
declare const MAX_LINE_ITEMS = 250;
|
|
13
|
+
declare const ShopifyTenantSchema: z.ZodObject<{
|
|
14
|
+
shopId: z.ZodString;
|
|
15
|
+
shopDomain: z.ZodString;
|
|
16
|
+
}, z.core.$strict>;
|
|
17
|
+
type ShopifyTenant = z.infer<typeof ShopifyTenantSchema>;
|
|
18
|
+
declare const ShopifyCustomerReferenceSchema: z.ZodObject<{
|
|
19
|
+
shopifyCustomerId: z.ZodNullable<z.ZodString>;
|
|
20
|
+
email: z.ZodNullable<z.ZodString>;
|
|
21
|
+
phone: z.ZodNullable<z.ZodString>;
|
|
22
|
+
firstName: z.ZodNullable<z.ZodString>;
|
|
23
|
+
lastName: z.ZodNullable<z.ZodString>;
|
|
24
|
+
}, z.core.$strict>;
|
|
25
|
+
type ShopifyCustomerReference = z.infer<typeof ShopifyCustomerReferenceSchema>;
|
|
26
|
+
declare const ShopifyMoneySchema: z.ZodObject<{
|
|
27
|
+
amount: z.ZodString;
|
|
28
|
+
currencyCode: z.ZodString;
|
|
29
|
+
}, z.core.$strict>;
|
|
30
|
+
type ShopifyMoney = z.infer<typeof ShopifyMoneySchema>;
|
|
31
|
+
/**
|
|
32
|
+
* Fields limited to what checkout recovery and customer-facing basket context require.
|
|
33
|
+
* Line-item arrays are bounded (see MAX_LINE_ITEMS) to prevent unexpectedly large queue messages.
|
|
34
|
+
*/
|
|
35
|
+
declare const ShopifyCheckoutLineItemSchema: z.ZodObject<{
|
|
36
|
+
lineItemId: z.ZodNullable<z.ZodString>;
|
|
37
|
+
variantId: z.ZodNullable<z.ZodString>;
|
|
38
|
+
productId: z.ZodNullable<z.ZodString>;
|
|
39
|
+
title: z.ZodString;
|
|
40
|
+
variantTitle: z.ZodNullable<z.ZodString>;
|
|
41
|
+
quantity: z.ZodNumber;
|
|
42
|
+
unitPrice: z.ZodNullable<z.ZodString>;
|
|
43
|
+
sku: z.ZodNullable<z.ZodString>;
|
|
44
|
+
}, z.core.$strict>;
|
|
45
|
+
type ShopifyCheckoutLineItem = z.infer<typeof ShopifyCheckoutLineItemSchema>;
|
|
46
|
+
declare const ShopifyCheckoutLineItemsSchema: z.ZodArray<z.ZodObject<{
|
|
47
|
+
lineItemId: z.ZodNullable<z.ZodString>;
|
|
48
|
+
variantId: z.ZodNullable<z.ZodString>;
|
|
49
|
+
productId: z.ZodNullable<z.ZodString>;
|
|
50
|
+
title: z.ZodString;
|
|
51
|
+
variantTitle: z.ZodNullable<z.ZodString>;
|
|
52
|
+
quantity: z.ZodNumber;
|
|
53
|
+
unitPrice: z.ZodNullable<z.ZodString>;
|
|
54
|
+
sku: z.ZodNullable<z.ZodString>;
|
|
55
|
+
}, z.core.$strict>>;
|
|
56
|
+
|
|
57
|
+
declare const CheckoutObservedPayloadSchema: z.ZodObject<{
|
|
58
|
+
checkoutToken: z.ZodString;
|
|
59
|
+
cartToken: z.ZodNullable<z.ZodString>;
|
|
60
|
+
checkoutUrl: z.ZodNullable<z.ZodURL>;
|
|
61
|
+
customer: z.ZodNullable<z.ZodObject<{
|
|
62
|
+
shopifyCustomerId: z.ZodNullable<z.ZodString>;
|
|
63
|
+
email: z.ZodNullable<z.ZodString>;
|
|
64
|
+
phone: z.ZodNullable<z.ZodString>;
|
|
65
|
+
firstName: z.ZodNullable<z.ZodString>;
|
|
66
|
+
lastName: z.ZodNullable<z.ZodString>;
|
|
67
|
+
}, z.core.$strict>>;
|
|
68
|
+
total: z.ZodNullable<z.ZodObject<{
|
|
69
|
+
amount: z.ZodString;
|
|
70
|
+
currencyCode: z.ZodString;
|
|
71
|
+
}, z.core.$strict>>;
|
|
72
|
+
lineItems: z.ZodArray<z.ZodObject<{
|
|
73
|
+
lineItemId: z.ZodNullable<z.ZodString>;
|
|
74
|
+
variantId: z.ZodNullable<z.ZodString>;
|
|
75
|
+
productId: z.ZodNullable<z.ZodString>;
|
|
76
|
+
title: z.ZodString;
|
|
77
|
+
variantTitle: z.ZodNullable<z.ZodString>;
|
|
78
|
+
quantity: z.ZodNumber;
|
|
79
|
+
unitPrice: z.ZodNullable<z.ZodString>;
|
|
80
|
+
sku: z.ZodNullable<z.ZodString>;
|
|
81
|
+
}, z.core.$strict>>;
|
|
82
|
+
checkoutCreatedAt: z.ZodNullable<z.ZodISODateTime>;
|
|
83
|
+
checkoutUpdatedAt: z.ZodNullable<z.ZodISODateTime>;
|
|
84
|
+
completedAt: z.ZodNullable<z.ZodISODateTime>;
|
|
85
|
+
}, z.core.$strict>;
|
|
86
|
+
type CheckoutObservedPayload = z.infer<typeof CheckoutObservedPayloadSchema>;
|
|
87
|
+
|
|
88
|
+
declare const OrderCompletedPayloadSchema: z.ZodObject<{
|
|
89
|
+
orderId: z.ZodString;
|
|
90
|
+
checkoutToken: z.ZodString;
|
|
91
|
+
shopifyCustomerId: z.ZodNullable<z.ZodString>;
|
|
92
|
+
total: z.ZodNullable<z.ZodObject<{
|
|
93
|
+
amount: z.ZodString;
|
|
94
|
+
currencyCode: z.ZodString;
|
|
95
|
+
}, z.core.$strict>>;
|
|
96
|
+
completedAt: z.ZodISODateTime;
|
|
97
|
+
}, z.core.$strict>;
|
|
98
|
+
type OrderCompletedPayload = z.infer<typeof OrderCompletedPayloadSchema>;
|
|
99
|
+
|
|
100
|
+
declare const ShopifyCheckoutObservedEventSchema: z.ZodObject<{
|
|
101
|
+
schemaVersion: z.ZodLiteral<1>;
|
|
102
|
+
receiptId: z.ZodString;
|
|
103
|
+
deliveryId: z.ZodString;
|
|
104
|
+
eventId: z.ZodNullable<z.ZodString>;
|
|
105
|
+
source: z.ZodLiteral<"shopify">;
|
|
106
|
+
providerTopic: z.ZodString;
|
|
107
|
+
tenant: z.ZodObject<{
|
|
108
|
+
shopId: z.ZodString;
|
|
109
|
+
shopDomain: z.ZodString;
|
|
110
|
+
}, z.core.$strict>;
|
|
111
|
+
occurredAt: z.ZodNullable<z.ZodISODateTime>;
|
|
112
|
+
receivedAt: z.ZodISODateTime;
|
|
113
|
+
traceId: z.ZodString;
|
|
114
|
+
orderingKey: z.ZodString;
|
|
115
|
+
eventType: z.ZodLiteral<"checkout.observed">;
|
|
116
|
+
payload: z.ZodObject<{
|
|
117
|
+
checkoutToken: z.ZodString;
|
|
118
|
+
cartToken: z.ZodNullable<z.ZodString>;
|
|
119
|
+
checkoutUrl: z.ZodNullable<z.ZodURL>;
|
|
120
|
+
customer: z.ZodNullable<z.ZodObject<{
|
|
121
|
+
shopifyCustomerId: z.ZodNullable<z.ZodString>;
|
|
122
|
+
email: z.ZodNullable<z.ZodString>;
|
|
123
|
+
phone: z.ZodNullable<z.ZodString>;
|
|
124
|
+
firstName: z.ZodNullable<z.ZodString>;
|
|
125
|
+
lastName: z.ZodNullable<z.ZodString>;
|
|
126
|
+
}, z.core.$strict>>;
|
|
127
|
+
total: z.ZodNullable<z.ZodObject<{
|
|
128
|
+
amount: z.ZodString;
|
|
129
|
+
currencyCode: z.ZodString;
|
|
130
|
+
}, z.core.$strict>>;
|
|
131
|
+
lineItems: z.ZodArray<z.ZodObject<{
|
|
132
|
+
lineItemId: z.ZodNullable<z.ZodString>;
|
|
133
|
+
variantId: z.ZodNullable<z.ZodString>;
|
|
134
|
+
productId: z.ZodNullable<z.ZodString>;
|
|
135
|
+
title: z.ZodString;
|
|
136
|
+
variantTitle: z.ZodNullable<z.ZodString>;
|
|
137
|
+
quantity: z.ZodNumber;
|
|
138
|
+
unitPrice: z.ZodNullable<z.ZodString>;
|
|
139
|
+
sku: z.ZodNullable<z.ZodString>;
|
|
140
|
+
}, z.core.$strict>>;
|
|
141
|
+
checkoutCreatedAt: z.ZodNullable<z.ZodISODateTime>;
|
|
142
|
+
checkoutUpdatedAt: z.ZodNullable<z.ZodISODateTime>;
|
|
143
|
+
completedAt: z.ZodNullable<z.ZodISODateTime>;
|
|
144
|
+
}, z.core.$strict>;
|
|
145
|
+
}, z.core.$strict>;
|
|
146
|
+
type ShopifyCheckoutObservedEvent = z.infer<typeof ShopifyCheckoutObservedEventSchema>;
|
|
147
|
+
declare const ShopifyOrderCompletedEventSchema: z.ZodObject<{
|
|
148
|
+
schemaVersion: z.ZodLiteral<1>;
|
|
149
|
+
receiptId: z.ZodString;
|
|
150
|
+
deliveryId: z.ZodString;
|
|
151
|
+
eventId: z.ZodNullable<z.ZodString>;
|
|
152
|
+
source: z.ZodLiteral<"shopify">;
|
|
153
|
+
providerTopic: z.ZodString;
|
|
154
|
+
tenant: z.ZodObject<{
|
|
155
|
+
shopId: z.ZodString;
|
|
156
|
+
shopDomain: z.ZodString;
|
|
157
|
+
}, z.core.$strict>;
|
|
158
|
+
occurredAt: z.ZodNullable<z.ZodISODateTime>;
|
|
159
|
+
receivedAt: z.ZodISODateTime;
|
|
160
|
+
traceId: z.ZodString;
|
|
161
|
+
orderingKey: z.ZodString;
|
|
162
|
+
eventType: z.ZodLiteral<"order.completed">;
|
|
163
|
+
payload: z.ZodObject<{
|
|
164
|
+
orderId: z.ZodString;
|
|
165
|
+
checkoutToken: z.ZodString;
|
|
166
|
+
shopifyCustomerId: z.ZodNullable<z.ZodString>;
|
|
167
|
+
total: z.ZodNullable<z.ZodObject<{
|
|
168
|
+
amount: z.ZodString;
|
|
169
|
+
currencyCode: z.ZodString;
|
|
170
|
+
}, z.core.$strict>>;
|
|
171
|
+
completedAt: z.ZodISODateTime;
|
|
172
|
+
}, z.core.$strict>;
|
|
173
|
+
}, z.core.$strict>;
|
|
174
|
+
type ShopifyOrderCompletedEvent = z.infer<typeof ShopifyOrderCompletedEventSchema>;
|
|
175
|
+
declare const ShopifyCommerceEventSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
176
|
+
schemaVersion: z.ZodLiteral<1>;
|
|
177
|
+
receiptId: z.ZodString;
|
|
178
|
+
deliveryId: z.ZodString;
|
|
179
|
+
eventId: z.ZodNullable<z.ZodString>;
|
|
180
|
+
source: z.ZodLiteral<"shopify">;
|
|
181
|
+
providerTopic: z.ZodString;
|
|
182
|
+
tenant: z.ZodObject<{
|
|
183
|
+
shopId: z.ZodString;
|
|
184
|
+
shopDomain: z.ZodString;
|
|
185
|
+
}, z.core.$strict>;
|
|
186
|
+
occurredAt: z.ZodNullable<z.ZodISODateTime>;
|
|
187
|
+
receivedAt: z.ZodISODateTime;
|
|
188
|
+
traceId: z.ZodString;
|
|
189
|
+
orderingKey: z.ZodString;
|
|
190
|
+
eventType: z.ZodLiteral<"checkout.observed">;
|
|
191
|
+
payload: z.ZodObject<{
|
|
192
|
+
checkoutToken: z.ZodString;
|
|
193
|
+
cartToken: z.ZodNullable<z.ZodString>;
|
|
194
|
+
checkoutUrl: z.ZodNullable<z.ZodURL>;
|
|
195
|
+
customer: z.ZodNullable<z.ZodObject<{
|
|
196
|
+
shopifyCustomerId: z.ZodNullable<z.ZodString>;
|
|
197
|
+
email: z.ZodNullable<z.ZodString>;
|
|
198
|
+
phone: z.ZodNullable<z.ZodString>;
|
|
199
|
+
firstName: z.ZodNullable<z.ZodString>;
|
|
200
|
+
lastName: z.ZodNullable<z.ZodString>;
|
|
201
|
+
}, z.core.$strict>>;
|
|
202
|
+
total: z.ZodNullable<z.ZodObject<{
|
|
203
|
+
amount: z.ZodString;
|
|
204
|
+
currencyCode: z.ZodString;
|
|
205
|
+
}, z.core.$strict>>;
|
|
206
|
+
lineItems: z.ZodArray<z.ZodObject<{
|
|
207
|
+
lineItemId: z.ZodNullable<z.ZodString>;
|
|
208
|
+
variantId: z.ZodNullable<z.ZodString>;
|
|
209
|
+
productId: z.ZodNullable<z.ZodString>;
|
|
210
|
+
title: z.ZodString;
|
|
211
|
+
variantTitle: z.ZodNullable<z.ZodString>;
|
|
212
|
+
quantity: z.ZodNumber;
|
|
213
|
+
unitPrice: z.ZodNullable<z.ZodString>;
|
|
214
|
+
sku: z.ZodNullable<z.ZodString>;
|
|
215
|
+
}, z.core.$strict>>;
|
|
216
|
+
checkoutCreatedAt: z.ZodNullable<z.ZodISODateTime>;
|
|
217
|
+
checkoutUpdatedAt: z.ZodNullable<z.ZodISODateTime>;
|
|
218
|
+
completedAt: z.ZodNullable<z.ZodISODateTime>;
|
|
219
|
+
}, z.core.$strict>;
|
|
220
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
221
|
+
schemaVersion: z.ZodLiteral<1>;
|
|
222
|
+
receiptId: z.ZodString;
|
|
223
|
+
deliveryId: z.ZodString;
|
|
224
|
+
eventId: z.ZodNullable<z.ZodString>;
|
|
225
|
+
source: z.ZodLiteral<"shopify">;
|
|
226
|
+
providerTopic: z.ZodString;
|
|
227
|
+
tenant: z.ZodObject<{
|
|
228
|
+
shopId: z.ZodString;
|
|
229
|
+
shopDomain: z.ZodString;
|
|
230
|
+
}, z.core.$strict>;
|
|
231
|
+
occurredAt: z.ZodNullable<z.ZodISODateTime>;
|
|
232
|
+
receivedAt: z.ZodISODateTime;
|
|
233
|
+
traceId: z.ZodString;
|
|
234
|
+
orderingKey: z.ZodString;
|
|
235
|
+
eventType: z.ZodLiteral<"order.completed">;
|
|
236
|
+
payload: z.ZodObject<{
|
|
237
|
+
orderId: z.ZodString;
|
|
238
|
+
checkoutToken: z.ZodString;
|
|
239
|
+
shopifyCustomerId: z.ZodNullable<z.ZodString>;
|
|
240
|
+
total: z.ZodNullable<z.ZodObject<{
|
|
241
|
+
amount: z.ZodString;
|
|
242
|
+
currencyCode: z.ZodString;
|
|
243
|
+
}, z.core.$strict>>;
|
|
244
|
+
completedAt: z.ZodISODateTime;
|
|
245
|
+
}, z.core.$strict>;
|
|
246
|
+
}, z.core.$strict>], "eventType">;
|
|
247
|
+
type ShopifyCommerceEvent = z.infer<typeof ShopifyCommerceEventSchema>;
|
|
248
|
+
type ShopifyCommerceEventType = ShopifyCommerceEvent["eventType"];
|
|
249
|
+
declare function parseShopifyCommerceEvent(input: unknown): ShopifyCommerceEvent;
|
|
250
|
+
declare function safeParseShopifyCommerceEvent(input: unknown): z.ZodSafeParseResult<{
|
|
251
|
+
schemaVersion: 1;
|
|
252
|
+
receiptId: string;
|
|
253
|
+
deliveryId: string;
|
|
254
|
+
eventId: string | null;
|
|
255
|
+
source: "shopify";
|
|
256
|
+
providerTopic: string;
|
|
257
|
+
tenant: {
|
|
258
|
+
shopId: string;
|
|
259
|
+
shopDomain: string;
|
|
260
|
+
};
|
|
261
|
+
occurredAt: string | null;
|
|
262
|
+
receivedAt: string;
|
|
263
|
+
traceId: string;
|
|
264
|
+
orderingKey: string;
|
|
265
|
+
eventType: "checkout.observed";
|
|
266
|
+
payload: {
|
|
267
|
+
checkoutToken: string;
|
|
268
|
+
cartToken: string | null;
|
|
269
|
+
checkoutUrl: string | null;
|
|
270
|
+
customer: {
|
|
271
|
+
shopifyCustomerId: string | null;
|
|
272
|
+
email: string | null;
|
|
273
|
+
phone: string | null;
|
|
274
|
+
firstName: string | null;
|
|
275
|
+
lastName: string | null;
|
|
276
|
+
} | null;
|
|
277
|
+
total: {
|
|
278
|
+
amount: string;
|
|
279
|
+
currencyCode: string;
|
|
280
|
+
} | null;
|
|
281
|
+
lineItems: {
|
|
282
|
+
lineItemId: string | null;
|
|
283
|
+
variantId: string | null;
|
|
284
|
+
productId: string | null;
|
|
285
|
+
title: string;
|
|
286
|
+
variantTitle: string | null;
|
|
287
|
+
quantity: number;
|
|
288
|
+
unitPrice: string | null;
|
|
289
|
+
sku: string | null;
|
|
290
|
+
}[];
|
|
291
|
+
checkoutCreatedAt: string | null;
|
|
292
|
+
checkoutUpdatedAt: string | null;
|
|
293
|
+
completedAt: string | null;
|
|
294
|
+
};
|
|
295
|
+
} | {
|
|
296
|
+
schemaVersion: 1;
|
|
297
|
+
receiptId: string;
|
|
298
|
+
deliveryId: string;
|
|
299
|
+
eventId: string | null;
|
|
300
|
+
source: "shopify";
|
|
301
|
+
providerTopic: string;
|
|
302
|
+
tenant: {
|
|
303
|
+
shopId: string;
|
|
304
|
+
shopDomain: string;
|
|
305
|
+
};
|
|
306
|
+
occurredAt: string | null;
|
|
307
|
+
receivedAt: string;
|
|
308
|
+
traceId: string;
|
|
309
|
+
orderingKey: string;
|
|
310
|
+
eventType: "order.completed";
|
|
311
|
+
payload: {
|
|
312
|
+
orderId: string;
|
|
313
|
+
checkoutToken: string;
|
|
314
|
+
shopifyCustomerId: string | null;
|
|
315
|
+
total: {
|
|
316
|
+
amount: string;
|
|
317
|
+
currencyCode: string;
|
|
318
|
+
} | null;
|
|
319
|
+
completedAt: string;
|
|
320
|
+
};
|
|
321
|
+
}>;
|
|
322
|
+
declare function isCheckoutObservedEvent(event: ShopifyCommerceEvent): event is ShopifyCheckoutObservedEvent;
|
|
323
|
+
declare function isOrderCompletedEvent(event: ShopifyCommerceEvent): event is ShopifyOrderCompletedEvent;
|
|
324
|
+
/**
|
|
325
|
+
* Stable ordering key for a shop/checkout pair. Checkout and order events for the
|
|
326
|
+
* same checkout must share this key, so deliveryId is intentionally excluded.
|
|
327
|
+
* Values are length-prefixed to avoid ambiguous concatenation (e.g. "1" + "23" vs "12" + "3").
|
|
328
|
+
*/
|
|
329
|
+
declare function createShopifyCommerceOrderingKey(shopId: string, checkoutToken: string): string;
|
|
330
|
+
|
|
331
|
+
export { type CheckoutObservedPayload, CheckoutObservedPayloadSchema, MAX_LINE_ITEMS, MAX_URL_LENGTH, type OrderCompletedPayload, OrderCompletedPayloadSchema, SHOPIFY_COMMERCE_EVENT_SCHEMA_VERSION, SHOPIFY_COMMERCE_EVENT_TYPES, SHOPIFY_COMMERCE_JOB, SHOPIFY_COMMERCE_QUEUE, type ShopifyCheckoutLineItem, ShopifyCheckoutLineItemSchema, ShopifyCheckoutLineItemsSchema, type ShopifyCheckoutObservedEvent, ShopifyCheckoutObservedEventSchema, type ShopifyCommerceEvent, ShopifyCommerceEventSchema, type ShopifyCommerceEventType, type ShopifyCustomerReference, ShopifyCustomerReferenceSchema, type ShopifyMoney, ShopifyMoneySchema, type ShopifyOrderCompletedEvent, ShopifyOrderCompletedEventSchema, type ShopifyTenant, ShopifyTenantSchema, createShopifyCommerceOrderingKey, isCheckoutObservedEvent, isOrderCompletedEvent, parseShopifyCommerceEvent, safeParseShopifyCommerceEvent };
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import {
|
|
2
|
+
CheckoutObservedPayloadSchema,
|
|
3
|
+
MAX_LINE_ITEMS,
|
|
4
|
+
MAX_URL_LENGTH,
|
|
5
|
+
OrderCompletedPayloadSchema,
|
|
6
|
+
SHOPIFY_COMMERCE_EVENT_SCHEMA_VERSION,
|
|
7
|
+
SHOPIFY_COMMERCE_EVENT_TYPES,
|
|
8
|
+
SHOPIFY_COMMERCE_JOB,
|
|
9
|
+
SHOPIFY_COMMERCE_QUEUE,
|
|
10
|
+
ShopifyCheckoutLineItemSchema,
|
|
11
|
+
ShopifyCheckoutLineItemsSchema,
|
|
12
|
+
ShopifyCheckoutObservedEventSchema,
|
|
13
|
+
ShopifyCommerceEventSchema,
|
|
14
|
+
ShopifyCustomerReferenceSchema,
|
|
15
|
+
ShopifyMoneySchema,
|
|
16
|
+
ShopifyOrderCompletedEventSchema,
|
|
17
|
+
ShopifyTenantSchema,
|
|
18
|
+
createShopifyCommerceOrderingKey,
|
|
19
|
+
isCheckoutObservedEvent,
|
|
20
|
+
isOrderCompletedEvent,
|
|
21
|
+
parseShopifyCommerceEvent,
|
|
22
|
+
safeParseShopifyCommerceEvent
|
|
23
|
+
} from "../chunk-NE5RMNXU.js";
|
|
24
|
+
export {
|
|
25
|
+
CheckoutObservedPayloadSchema,
|
|
26
|
+
MAX_LINE_ITEMS,
|
|
27
|
+
MAX_URL_LENGTH,
|
|
28
|
+
OrderCompletedPayloadSchema,
|
|
29
|
+
SHOPIFY_COMMERCE_EVENT_SCHEMA_VERSION,
|
|
30
|
+
SHOPIFY_COMMERCE_EVENT_TYPES,
|
|
31
|
+
SHOPIFY_COMMERCE_JOB,
|
|
32
|
+
SHOPIFY_COMMERCE_QUEUE,
|
|
33
|
+
ShopifyCheckoutLineItemSchema,
|
|
34
|
+
ShopifyCheckoutLineItemsSchema,
|
|
35
|
+
ShopifyCheckoutObservedEventSchema,
|
|
36
|
+
ShopifyCommerceEventSchema,
|
|
37
|
+
ShopifyCustomerReferenceSchema,
|
|
38
|
+
ShopifyMoneySchema,
|
|
39
|
+
ShopifyOrderCompletedEventSchema,
|
|
40
|
+
ShopifyTenantSchema,
|
|
41
|
+
createShopifyCommerceOrderingKey,
|
|
42
|
+
isCheckoutObservedEvent,
|
|
43
|
+
isOrderCompletedEvent,
|
|
44
|
+
parseShopifyCommerceEvent,
|
|
45
|
+
safeParseShopifyCommerceEvent
|
|
46
|
+
};
|
|
47
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Deterministic, BullMQ-safe job ID: "shopify-<sha256(appKey + ":" + deliveryId)>".
|
|
3
|
+
* The hex digest contains no colons and no secret material, only a one-way hash.
|
|
4
|
+
*/
|
|
5
|
+
declare function createShopifyWebhookJobId(appKey: string, deliveryId: string): string;
|
|
6
|
+
|
|
7
|
+
export { createShopifyWebhookJobId };
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
// src/shopify/node.ts
|
|
2
|
+
import { createHash } from "crypto";
|
|
3
|
+
function createShopifyWebhookJobId(appKey, deliveryId) {
|
|
4
|
+
if (typeof appKey !== "string" || appKey.length === 0) {
|
|
5
|
+
throw new Error("createShopifyWebhookJobId: appKey must be a non-empty string");
|
|
6
|
+
}
|
|
7
|
+
if (typeof deliveryId !== "string" || deliveryId.length === 0) {
|
|
8
|
+
throw new Error("createShopifyWebhookJobId: deliveryId must be a non-empty string");
|
|
9
|
+
}
|
|
10
|
+
const digest = createHash("sha256").update(`${appKey}:${deliveryId}`).digest("hex");
|
|
11
|
+
return `shopify-${digest}`;
|
|
12
|
+
}
|
|
13
|
+
export {
|
|
14
|
+
createShopifyWebhookJobId
|
|
15
|
+
};
|
|
16
|
+
//# sourceMappingURL=node.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/shopify/node.ts"],"sourcesContent":["import { createHash } from \"node:crypto\";\n\n/**\n * Deterministic, BullMQ-safe job ID: \"shopify-<sha256(appKey + \":\" + deliveryId)>\".\n * The hex digest contains no colons and no secret material, only a one-way hash.\n */\nexport function createShopifyWebhookJobId(appKey: string, deliveryId: string): string {\n if (typeof appKey !== \"string\" || appKey.length === 0) {\n throw new Error(\"createShopifyWebhookJobId: appKey must be a non-empty string\");\n }\n if (typeof deliveryId !== \"string\" || deliveryId.length === 0) {\n throw new Error(\"createShopifyWebhookJobId: deliveryId must be a non-empty string\");\n }\n\n const digest = createHash(\"sha256\").update(`${appKey}:${deliveryId}`).digest(\"hex\");\n return `shopify-${digest}`;\n}\n"],"mappings":";AAAA,SAAS,kBAAkB;AAMpB,SAAS,0BAA0B,QAAgB,YAA4B;AACpF,MAAI,OAAO,WAAW,YAAY,OAAO,WAAW,GAAG;AACrD,UAAM,IAAI,MAAM,8DAA8D;AAAA,EAChF;AACA,MAAI,OAAO,eAAe,YAAY,WAAW,WAAW,GAAG;AAC7D,UAAM,IAAI,MAAM,kEAAkE;AAAA,EACpF;AAEA,QAAM,SAAS,WAAW,QAAQ,EAAE,OAAO,GAAG,MAAM,IAAI,UAAU,EAAE,EAAE,OAAO,KAAK;AAClF,SAAO,WAAW,MAAM;AAC1B;","names":[]}
|
package/package.json
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@modainteract/moda-interact-shared",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"main": "./dist/index.js",
|
|
6
|
+
"types": "./dist/index.d.ts",
|
|
7
|
+
"publishConfig": {
|
|
8
|
+
"access": "public"
|
|
9
|
+
},
|
|
10
|
+
"exports": {
|
|
11
|
+
".": {
|
|
12
|
+
"types": "./dist/index.d.ts",
|
|
13
|
+
"import": "./dist/index.js"
|
|
14
|
+
},
|
|
15
|
+
"./shopify": {
|
|
16
|
+
"types": "./dist/shopify/index.d.ts",
|
|
17
|
+
"import": "./dist/shopify/index.js"
|
|
18
|
+
},
|
|
19
|
+
"./shopify/node": {
|
|
20
|
+
"types": "./dist/shopify/node.d.ts",
|
|
21
|
+
"import": "./dist/shopify/node.js"
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
"files": [
|
|
25
|
+
"dist"
|
|
26
|
+
],
|
|
27
|
+
"scripts": {
|
|
28
|
+
"build": "tsup",
|
|
29
|
+
"typecheck": "tsc --noEmit",
|
|
30
|
+
"test": "tsx --test src/**/*.test.ts",
|
|
31
|
+
"prepack": "npm run build"
|
|
32
|
+
},
|
|
33
|
+
"dependencies": {
|
|
34
|
+
"zod": "^4.0.0"
|
|
35
|
+
},
|
|
36
|
+
"devDependencies": {
|
|
37
|
+
"@types/node": "^26.4.0",
|
|
38
|
+
"tsup": "^8.0.0",
|
|
39
|
+
"tsx": "^4.23.12",
|
|
40
|
+
"typescript": "^5.0.0"
|
|
41
|
+
}
|
|
42
|
+
}
|