@automate.ax/integration-contracts 0.83.3 → 0.85.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@automate.ax/integration-contracts",
3
- "version": "0.83.3",
3
+ "version": "0.85.0",
4
4
  "description": "Shared integration payload contracts and provider primitives for Automate.ax.",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -31,10 +31,12 @@
31
31
  "./outlook": "./src/outlook/index.ts",
32
32
  "./resend": "./src/resend/index.ts",
33
33
  "./slack": "./src/slack/index.ts",
34
+ "./stripe": "./src/stripe/index.ts",
34
35
  "./teams": "./src/teams/index.ts",
35
36
  "./trello": "./src/trello/index.ts",
36
37
  "./triggers": "./src/triggers.ts",
37
38
  "./vercel": "./src/vercel/index.ts",
39
+ "./webflow": "./src/webflow/index.ts",
38
40
  "./whatsapp": "./src/whatsapp/index.ts"
39
41
  },
40
42
  "cjs": false,
@@ -43,7 +45,7 @@
43
45
  }
44
46
  },
45
47
  "dependencies": {
46
- "@automate.ax/codec": "0.83.3",
48
+ "@automate.ax/codec": "0.85.0",
47
49
  "@googleapis/calendar": "^15.0.0",
48
50
  "@googleapis/forms": "^6.0.1",
49
51
  "@googleapis/gmail": "^12.0.0",
@@ -54,11 +56,13 @@
54
56
  "html-to-text": "^10.0.0",
55
57
  "nodemailer": "^9.0.3",
56
58
  "postal-mime": "^2.7.5",
59
+ "stripe": "^22.1.0",
57
60
  "type-fest": "^5.6.0",
61
+ "webflow-api": "^3.3.4",
58
62
  "zod": "^4.3.6"
59
63
  },
60
64
  "devDependencies": {
61
- "@internal/config": "0.1.0",
65
+ "@internal/config": "0.2.0",
62
66
  "@types/bun": "latest",
63
67
  "@types/html-to-text": "^9.0.4",
64
68
  "@types/nodemailer": "^8.0.1",
@@ -153,6 +157,11 @@
153
157
  "types": "./dist/slack/index.d.ts",
154
158
  "default": "./dist/slack/index.js"
155
159
  },
160
+ "./stripe": {
161
+ "bun": "./src/stripe/index.ts",
162
+ "types": "./dist/stripe/index.d.ts",
163
+ "default": "./dist/stripe/index.js"
164
+ },
156
165
  "./teams": {
157
166
  "bun": "./src/teams/index.ts",
158
167
  "types": "./dist/teams/index.d.ts",
@@ -173,6 +182,11 @@
173
182
  "types": "./dist/vercel/index.d.ts",
174
183
  "default": "./dist/vercel/index.js"
175
184
  },
185
+ "./webflow": {
186
+ "bun": "./src/webflow/index.ts",
187
+ "types": "./dist/webflow/index.d.ts",
188
+ "default": "./dist/webflow/index.js"
189
+ },
176
190
  "./whatsapp": {
177
191
  "bun": "./src/whatsapp/index.ts",
178
192
  "types": "./dist/whatsapp/index.d.ts",
@@ -0,0 +1,165 @@
1
+ import * as z from "zod"
2
+ import type { StripeEvent, StripeSemanticEvent } from "./schemas"
3
+ import { STRIPE_EVENT_SCHEMA, stripeSemanticEventSchema } from "./schemas"
4
+
5
+ export * from "./schemas"
6
+
7
+ export const STRIPE_TRIGGER_CONFIG_SCHEMA = z.object({})
8
+
9
+ type StripeTriggerContract<TEvent> = {
10
+ readonly configSchema: typeof STRIPE_TRIGGER_CONFIG_SCHEMA
11
+ readonly eventSchema: z.ZodType<TEvent>
12
+ }
13
+
14
+ type StripeSemanticTriggerEventTypes = {
15
+ readonly "stripe.charge.dispute.closed": "charge.dispute.closed"
16
+ readonly "stripe.charge.dispute.created": "charge.dispute.created"
17
+ readonly "stripe.checkout.session.asyncPaymentFailed": "checkout.session.async_payment_failed"
18
+ readonly "stripe.checkout.session.asyncPaymentSucceeded": "checkout.session.async_payment_succeeded"
19
+ readonly "stripe.checkout.session.completed": "checkout.session.completed"
20
+ readonly "stripe.checkout.session.expired": "checkout.session.expired"
21
+ readonly "stripe.customer.created": "customer.created"
22
+ readonly "stripe.customer.deleted": "customer.deleted"
23
+ readonly "stripe.customer.subscription.created": "customer.subscription.created"
24
+ readonly "stripe.customer.subscription.deleted": "customer.subscription.deleted"
25
+ readonly "stripe.customer.subscription.trialWillEnd": "customer.subscription.trial_will_end"
26
+ readonly "stripe.customer.subscription.updated": "customer.subscription.updated"
27
+ readonly "stripe.customer.updated": "customer.updated"
28
+ readonly "stripe.invoice.finalized": "invoice.finalized"
29
+ readonly "stripe.invoice.overdue": "invoice.overdue"
30
+ readonly "stripe.invoice.paid": "invoice.paid"
31
+ readonly "stripe.invoice.paymentFailed": "invoice.payment_failed"
32
+ readonly "stripe.invoice.voided": "invoice.voided"
33
+ readonly "stripe.paymentIntent.canceled": "payment_intent.canceled"
34
+ readonly "stripe.paymentIntent.paymentFailed": "payment_intent.payment_failed"
35
+ readonly "stripe.paymentIntent.succeeded": "payment_intent.succeeded"
36
+ readonly "stripe.payout.failed": "payout.failed"
37
+ readonly "stripe.payout.paid": "payout.paid"
38
+ readonly "stripe.refund.created": "refund.created"
39
+ readonly "stripe.refund.failed": "refund.failed"
40
+ }
41
+
42
+ /**
43
+ * Named registry shape keeps declaration emit independent of Stripe's private
44
+ * resource modules.
45
+ */
46
+ type StripeTriggerContracts = {
47
+ readonly [TTrigger in keyof StripeSemanticTriggerEventTypes]: StripeTriggerContract<
48
+ StripeSemanticEvent<StripeSemanticTriggerEventTypes[TTrigger]>
49
+ >
50
+ } & {
51
+ readonly "stripe.event": StripeTriggerContract<StripeEvent>
52
+ }
53
+
54
+ export const stripeTriggerContracts: StripeTriggerContracts = {
55
+ "stripe.charge.dispute.closed": {
56
+ configSchema: STRIPE_TRIGGER_CONFIG_SCHEMA,
57
+ eventSchema: stripeSemanticEventSchema("charge.dispute.closed"),
58
+ },
59
+ "stripe.charge.dispute.created": {
60
+ configSchema: STRIPE_TRIGGER_CONFIG_SCHEMA,
61
+ eventSchema: stripeSemanticEventSchema("charge.dispute.created"),
62
+ },
63
+ "stripe.checkout.session.completed": {
64
+ configSchema: STRIPE_TRIGGER_CONFIG_SCHEMA,
65
+ eventSchema: stripeSemanticEventSchema("checkout.session.completed"),
66
+ },
67
+ "stripe.checkout.session.asyncPaymentFailed": {
68
+ configSchema: STRIPE_TRIGGER_CONFIG_SCHEMA,
69
+ eventSchema: stripeSemanticEventSchema(
70
+ "checkout.session.async_payment_failed",
71
+ ),
72
+ },
73
+ "stripe.checkout.session.asyncPaymentSucceeded": {
74
+ configSchema: STRIPE_TRIGGER_CONFIG_SCHEMA,
75
+ eventSchema: stripeSemanticEventSchema(
76
+ "checkout.session.async_payment_succeeded",
77
+ ),
78
+ },
79
+ "stripe.checkout.session.expired": {
80
+ configSchema: STRIPE_TRIGGER_CONFIG_SCHEMA,
81
+ eventSchema: stripeSemanticEventSchema("checkout.session.expired"),
82
+ },
83
+ "stripe.customer.created": {
84
+ configSchema: STRIPE_TRIGGER_CONFIG_SCHEMA,
85
+ eventSchema: stripeSemanticEventSchema("customer.created"),
86
+ },
87
+ "stripe.customer.deleted": {
88
+ configSchema: STRIPE_TRIGGER_CONFIG_SCHEMA,
89
+ eventSchema: stripeSemanticEventSchema("customer.deleted"),
90
+ },
91
+ "stripe.customer.subscription.created": {
92
+ configSchema: STRIPE_TRIGGER_CONFIG_SCHEMA,
93
+ eventSchema: stripeSemanticEventSchema("customer.subscription.created"),
94
+ },
95
+ "stripe.customer.subscription.deleted": {
96
+ configSchema: STRIPE_TRIGGER_CONFIG_SCHEMA,
97
+ eventSchema: stripeSemanticEventSchema("customer.subscription.deleted"),
98
+ },
99
+ "stripe.customer.subscription.trialWillEnd": {
100
+ configSchema: STRIPE_TRIGGER_CONFIG_SCHEMA,
101
+ eventSchema: stripeSemanticEventSchema(
102
+ "customer.subscription.trial_will_end",
103
+ ),
104
+ },
105
+ "stripe.customer.subscription.updated": {
106
+ configSchema: STRIPE_TRIGGER_CONFIG_SCHEMA,
107
+ eventSchema: stripeSemanticEventSchema("customer.subscription.updated"),
108
+ },
109
+ "stripe.customer.updated": {
110
+ configSchema: STRIPE_TRIGGER_CONFIG_SCHEMA,
111
+ eventSchema: stripeSemanticEventSchema("customer.updated"),
112
+ },
113
+ "stripe.event": {
114
+ configSchema: STRIPE_TRIGGER_CONFIG_SCHEMA,
115
+ eventSchema: STRIPE_EVENT_SCHEMA,
116
+ },
117
+ "stripe.invoice.finalized": {
118
+ configSchema: STRIPE_TRIGGER_CONFIG_SCHEMA,
119
+ eventSchema: stripeSemanticEventSchema("invoice.finalized"),
120
+ },
121
+ "stripe.invoice.overdue": {
122
+ configSchema: STRIPE_TRIGGER_CONFIG_SCHEMA,
123
+ eventSchema: stripeSemanticEventSchema("invoice.overdue"),
124
+ },
125
+ "stripe.invoice.paid": {
126
+ configSchema: STRIPE_TRIGGER_CONFIG_SCHEMA,
127
+ eventSchema: stripeSemanticEventSchema("invoice.paid"),
128
+ },
129
+ "stripe.invoice.paymentFailed": {
130
+ configSchema: STRIPE_TRIGGER_CONFIG_SCHEMA,
131
+ eventSchema: stripeSemanticEventSchema("invoice.payment_failed"),
132
+ },
133
+ "stripe.invoice.voided": {
134
+ configSchema: STRIPE_TRIGGER_CONFIG_SCHEMA,
135
+ eventSchema: stripeSemanticEventSchema("invoice.voided"),
136
+ },
137
+ "stripe.paymentIntent.canceled": {
138
+ configSchema: STRIPE_TRIGGER_CONFIG_SCHEMA,
139
+ eventSchema: stripeSemanticEventSchema("payment_intent.canceled"),
140
+ },
141
+ "stripe.paymentIntent.paymentFailed": {
142
+ configSchema: STRIPE_TRIGGER_CONFIG_SCHEMA,
143
+ eventSchema: stripeSemanticEventSchema("payment_intent.payment_failed"),
144
+ },
145
+ "stripe.paymentIntent.succeeded": {
146
+ configSchema: STRIPE_TRIGGER_CONFIG_SCHEMA,
147
+ eventSchema: stripeSemanticEventSchema("payment_intent.succeeded"),
148
+ },
149
+ "stripe.payout.failed": {
150
+ configSchema: STRIPE_TRIGGER_CONFIG_SCHEMA,
151
+ eventSchema: stripeSemanticEventSchema("payout.failed"),
152
+ },
153
+ "stripe.payout.paid": {
154
+ configSchema: STRIPE_TRIGGER_CONFIG_SCHEMA,
155
+ eventSchema: stripeSemanticEventSchema("payout.paid"),
156
+ },
157
+ "stripe.refund.created": {
158
+ configSchema: STRIPE_TRIGGER_CONFIG_SCHEMA,
159
+ eventSchema: stripeSemanticEventSchema("refund.created"),
160
+ },
161
+ "stripe.refund.failed": {
162
+ configSchema: STRIPE_TRIGGER_CONFIG_SCHEMA,
163
+ eventSchema: stripeSemanticEventSchema("refund.failed"),
164
+ },
165
+ }
@@ -0,0 +1,120 @@
1
+ import type { Encodable } from "@automate.ax/codec"
2
+ import type Stripe from "stripe"
3
+ import type { CamelCasedPropertiesDeep } from "type-fest"
4
+ import * as z from "zod"
5
+
6
+ export const STRIPE_SEMANTIC_EVENT_TYPES = [
7
+ "charge.dispute.closed",
8
+ "charge.dispute.created",
9
+ "checkout.session.async_payment_failed",
10
+ "checkout.session.async_payment_succeeded",
11
+ "checkout.session.completed",
12
+ "checkout.session.expired",
13
+ "customer.created",
14
+ "customer.deleted",
15
+ "customer.subscription.created",
16
+ "customer.subscription.deleted",
17
+ "customer.subscription.trial_will_end",
18
+ "customer.subscription.updated",
19
+ "customer.updated",
20
+ "invoice.finalized",
21
+ "invoice.overdue",
22
+ "invoice.paid",
23
+ "invoice.payment_failed",
24
+ "invoice.voided",
25
+ "payment_intent.canceled",
26
+ "payment_intent.payment_failed",
27
+ "payment_intent.succeeded",
28
+ "payout.failed",
29
+ "payout.paid",
30
+ "refund.created",
31
+ "refund.failed",
32
+ ] as const satisfies readonly Stripe.Event.Type[]
33
+
34
+ const STRIPE_EVENT_BASE_SCHEMA = z.looseObject({
35
+ apiVersion: z.string().nullable(),
36
+ created: z.number().int().nonnegative(),
37
+ data: z.looseObject({ object: z.looseObject({ object: z.string() }) }),
38
+ id: z.string().startsWith("evt_"),
39
+ livemode: z.boolean(),
40
+ object: z.literal("event"),
41
+ pendingWebhooks: z.number().int().nonnegative(),
42
+ request: z
43
+ .looseObject({
44
+ id: z.string().nullable(),
45
+ idempotencyKey: z.string().nullable(),
46
+ })
47
+ .nullable(),
48
+ type: z.string().min(1),
49
+ })
50
+
51
+ /** Public camelCase representation of an official Stripe event type. */
52
+ export type StripeEvent<TEvent extends Stripe.Event = Stripe.Event> =
53
+ CamelCasedPropertiesDeep<TEvent> & Encodable
54
+
55
+ /** Public event type for one exact Stripe event name. */
56
+ export type StripeSemanticEvent<TType extends Stripe.Event.Type> = StripeEvent<
57
+ Extract<Stripe.Event, { type: TType }>
58
+ >
59
+
60
+ export const STRIPE_EVENT_SCHEMA: z.ZodType<StripeEvent> =
61
+ z.custom<StripeEvent>(
62
+ (value) => STRIPE_EVENT_BASE_SCHEMA.safeParse(value).success,
63
+ )
64
+
65
+ /**
66
+ * Converts a verified provider event to its public camelCase representation.
67
+ *
68
+ * @param event - Verified provider event.
69
+ * @returns Validated public Stripe event.
70
+ */
71
+ export function normalizeStripeEvent(event: unknown): StripeEvent {
72
+ return STRIPE_EVENT_SCHEMA.parse(camelizeStripeValue(event))
73
+ }
74
+
75
+ /**
76
+ * Builds a schema that narrows a verified broad event to one Stripe type.
77
+ *
78
+ * @param type - Exact Stripe event name.
79
+ * @returns Runtime schema for the semantic event.
80
+ */
81
+ export function stripeSemanticEventSchema<
82
+ TType extends (typeof STRIPE_SEMANTIC_EVENT_TYPES)[number],
83
+ >(type: TType): z.ZodType<StripeSemanticEvent<TType>> {
84
+ return z.custom<StripeSemanticEvent<TType>>((value) => {
85
+ const event = STRIPE_EVENT_SCHEMA.safeParse(value)
86
+ return event.success && event.data.type === type
87
+ })
88
+ }
89
+
90
+ /**
91
+ * Converts provider object keys recursively while preserving metadata keys.
92
+ *
93
+ * @param value - Provider value to normalize.
94
+ * @returns Public value with camel-cased object keys.
95
+ */
96
+ function camelizeStripeValue(value: unknown): unknown {
97
+ if (Array.isArray(value)) return value.map(camelizeStripeValue)
98
+ if (!isPlainRecord(value)) return value
99
+
100
+ return Object.fromEntries(
101
+ Object.entries(value).map(([key, item]) => [
102
+ key.replace(/_([a-z0-9])/g, (_match, character: string) =>
103
+ character.toUpperCase(),
104
+ ),
105
+ key === "metadata" ? item : camelizeStripeValue(item),
106
+ ]),
107
+ )
108
+ }
109
+
110
+ /**
111
+ * Checks whether a value is a plain record safe for key conversion.
112
+ *
113
+ * @param value - Value to inspect.
114
+ * @returns Whether the value is a plain record.
115
+ */
116
+ function isPlainRecord(value: unknown): value is Record<string, unknown> {
117
+ if (value === null || typeof value !== "object") return false
118
+ const prototype = Object.getPrototypeOf(value)
119
+ return prototype === null || prototype === Object.prototype
120
+ }
package/src/triggers.ts CHANGED
@@ -11,9 +11,11 @@ import type { linearTriggerContracts } from "./linear"
11
11
  import type { outlookTriggerContracts } from "./outlook"
12
12
  import type { resendTriggerContracts } from "./resend"
13
13
  import type { slackTriggerContracts } from "./slack"
14
+ import type { stripeTriggerContracts } from "./stripe"
14
15
  import type { teamsTriggerContracts } from "./teams"
15
16
  import type { trelloTriggerContracts } from "./trello"
16
17
  import type { vercelTriggerContracts } from "./vercel"
18
+ import type { webflowTriggerContracts } from "./webflow"
17
19
  import type { whatsappTriggerContracts } from "./whatsapp"
18
20
  import type { z } from "zod"
19
21
 
@@ -30,9 +32,11 @@ export type TriggerContractMap = typeof airtableTriggerContracts &
30
32
  typeof outlookTriggerContracts &
31
33
  typeof resendTriggerContracts &
32
34
  typeof slackTriggerContracts &
35
+ typeof stripeTriggerContracts &
33
36
  typeof teamsTriggerContracts &
34
37
  typeof trelloTriggerContracts &
35
38
  typeof vercelTriggerContracts &
39
+ typeof webflowTriggerContracts &
36
40
  typeof whatsappTriggerContracts
37
41
  export type IntegrationTriggerType = keyof TriggerContractMap
38
42
 
@@ -0,0 +1,98 @@
1
+ import * as z from "zod"
2
+ import type {
3
+ WebflowEvent,
4
+ WebflowEventType,
5
+ WebflowSemanticEvent,
6
+ } from "./schemas"
7
+ import { WEBFLOW_EVENT_SCHEMA, webflowSemanticEventSchema } from "./schemas"
8
+
9
+ export * from "./schemas"
10
+
11
+ /** Site selected for one Webflow webhook subscription. */
12
+ export const WEBFLOW_TRIGGER_CONFIG_SCHEMA = z.object({
13
+ siteId: z.string().trim().min(1),
14
+ })
15
+
16
+ type WebflowTriggerContract<TEvent> = {
17
+ readonly configSchema: typeof WEBFLOW_TRIGGER_CONFIG_SCHEMA
18
+ readonly eventSchema: z.ZodType<TEvent>
19
+ }
20
+
21
+ type WebflowSemanticTriggerTypes = {
22
+ readonly "webflow.collectionItem.changed": "collection_item_changed"
23
+ readonly "webflow.collectionItem.created": "collection_item_created"
24
+ readonly "webflow.collectionItem.deleted": "collection_item_deleted"
25
+ readonly "webflow.collectionItem.published": "collection_item_published"
26
+ readonly "webflow.collectionItem.unpublished": "collection_item_unpublished"
27
+ readonly "webflow.comment.created": "comment_created"
28
+ readonly "webflow.form.submitted": "form_submission"
29
+ readonly "webflow.inventory.changed": "ecomm_inventory_changed"
30
+ readonly "webflow.order.changed": "ecomm_order_changed"
31
+ readonly "webflow.order.created": "ecomm_new_order"
32
+ readonly "webflow.page.created": "page_created"
33
+ readonly "webflow.page.deleted": "page_deleted"
34
+ readonly "webflow.page.metadataUpdated": "page_metadata_updated"
35
+ readonly "webflow.site.published": "site_publish"
36
+ }
37
+
38
+ type WebflowTriggerContracts = {
39
+ readonly [TTrigger in keyof WebflowSemanticTriggerTypes]: WebflowTriggerContract<
40
+ WebflowSemanticEvent<WebflowSemanticTriggerTypes[TTrigger]>
41
+ >
42
+ } & {
43
+ readonly "webflow.event": WebflowTriggerContract<WebflowEvent>
44
+ }
45
+
46
+ export const webflowTriggerContracts: WebflowTriggerContracts = {
47
+ "webflow.collectionItem.changed": semanticContract("collection_item_changed"),
48
+ "webflow.collectionItem.created": semanticContract("collection_item_created"),
49
+ "webflow.collectionItem.deleted": semanticContract("collection_item_deleted"),
50
+ "webflow.collectionItem.published": semanticContract(
51
+ "collection_item_published",
52
+ ),
53
+ "webflow.collectionItem.unpublished": semanticContract(
54
+ "collection_item_unpublished",
55
+ ),
56
+ "webflow.comment.created": semanticContract("comment_created"),
57
+ "webflow.event": {
58
+ configSchema: WEBFLOW_TRIGGER_CONFIG_SCHEMA,
59
+ eventSchema: WEBFLOW_EVENT_SCHEMA,
60
+ },
61
+ "webflow.form.submitted": semanticContract("form_submission"),
62
+ "webflow.inventory.changed": semanticContract("ecomm_inventory_changed"),
63
+ "webflow.order.changed": semanticContract("ecomm_order_changed"),
64
+ "webflow.order.created": semanticContract("ecomm_new_order"),
65
+ "webflow.page.created": semanticContract("page_created"),
66
+ "webflow.page.deleted": semanticContract("page_deleted"),
67
+ "webflow.page.metadataUpdated": semanticContract("page_metadata_updated"),
68
+ "webflow.site.published": semanticContract("site_publish"),
69
+ }
70
+
71
+ export const webflowEventTypeMap = {
72
+ collection_item_changed: "webflow.collectionItem.changed",
73
+ collection_item_created: "webflow.collectionItem.created",
74
+ collection_item_deleted: "webflow.collectionItem.deleted",
75
+ collection_item_published: "webflow.collectionItem.published",
76
+ collection_item_unpublished: "webflow.collectionItem.unpublished",
77
+ comment_created: "webflow.comment.created",
78
+ ecomm_inventory_changed: "webflow.inventory.changed",
79
+ ecomm_new_order: "webflow.order.created",
80
+ ecomm_order_changed: "webflow.order.changed",
81
+ form_submission: "webflow.form.submitted",
82
+ page_created: "webflow.page.created",
83
+ page_deleted: "webflow.page.deleted",
84
+ page_metadata_updated: "webflow.page.metadataUpdated",
85
+ site_publish: "webflow.site.published",
86
+ } as const satisfies Record<WebflowEventType, keyof WebflowTriggerContracts>
87
+
88
+ /**
89
+ * Builds a contract for one semantic Webflow webhook event.
90
+ *
91
+ * @param type - Webflow webhook event type exposed by the contract.
92
+ */
93
+ function semanticContract<TType extends WebflowEventType>(type: TType) {
94
+ return {
95
+ configSchema: WEBFLOW_TRIGGER_CONFIG_SCHEMA,
96
+ eventSchema: webflowSemanticEventSchema(type),
97
+ }
98
+ }