@wraps.dev/client 0.5.0 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -22,6 +22,163 @@ function createPlatformClient(config) {
22
22
  return client;
23
23
  }
24
24
 
25
+ // src/config.ts
26
+ function defineConfig(config) {
27
+ return config;
28
+ }
29
+ function defineBrand(brand) {
30
+ return brand;
31
+ }
32
+
33
+ // src/workflow.ts
34
+ function defineWorkflow(definition) {
35
+ return definition;
36
+ }
37
+
38
+ // src/workflow-steps.ts
39
+ function normalizeDuration(duration) {
40
+ if (duration.days !== void 0) {
41
+ return { amount: duration.days, unit: "days" };
42
+ }
43
+ if (duration.hours !== void 0) {
44
+ return { amount: duration.hours, unit: "hours" };
45
+ }
46
+ if (duration.minutes !== void 0) {
47
+ return { amount: duration.minutes, unit: "minutes" };
48
+ }
49
+ return { amount: 1, unit: "hours" };
50
+ }
51
+ function durationToSeconds(duration) {
52
+ if (!duration) return void 0;
53
+ let seconds = 0;
54
+ if (duration.days) seconds += duration.days * 24 * 60 * 60;
55
+ if (duration.hours) seconds += duration.hours * 60 * 60;
56
+ if (duration.minutes) seconds += duration.minutes * 60;
57
+ return seconds > 0 ? seconds : void 0;
58
+ }
59
+ function sendEmail(id, config) {
60
+ const { name, ...stepConfig } = config;
61
+ return {
62
+ id,
63
+ type: "send_email",
64
+ name: name ?? `Send email: ${config.template || "custom"}`,
65
+ config: { type: "send_email", ...stepConfig }
66
+ };
67
+ }
68
+ function sendSms(id, config) {
69
+ const { name, ...stepConfig } = config;
70
+ return {
71
+ id,
72
+ type: "send_sms",
73
+ name: name ?? `Send SMS: ${config.template || "custom"}`,
74
+ config: { type: "send_sms", ...stepConfig }
75
+ };
76
+ }
77
+ function delay(id, duration) {
78
+ const { name, ...durationConfig } = duration;
79
+ const normalized = normalizeDuration(durationConfig);
80
+ return {
81
+ id,
82
+ type: "delay",
83
+ name: name ?? `Wait ${normalized.amount} ${normalized.unit}`,
84
+ config: { type: "delay", ...normalized }
85
+ };
86
+ }
87
+ function condition(id, config) {
88
+ const { branches, name, ...conditionConfig } = config;
89
+ return {
90
+ id,
91
+ type: "condition",
92
+ name: name ?? `Check: ${config.field} ${config.operator}`,
93
+ config: { type: "condition", ...conditionConfig },
94
+ branches
95
+ };
96
+ }
97
+ function waitForEvent(id, config) {
98
+ const { name, timeout, ...eventConfig } = config;
99
+ return {
100
+ id,
101
+ type: "wait_for_event",
102
+ name: name ?? `Wait for: ${config.eventName}`,
103
+ config: {
104
+ type: "wait_for_event",
105
+ eventName: eventConfig.eventName,
106
+ timeoutSeconds: durationToSeconds(timeout)
107
+ }
108
+ };
109
+ }
110
+ function waitForEmailEngagement(id, config) {
111
+ const { name, timeout, emailStepId, engagementType } = config;
112
+ return {
113
+ id,
114
+ type: "wait_for_email_engagement",
115
+ name: name ?? `Wait for email ${engagementType}: ${emailStepId}`,
116
+ config: {
117
+ type: "wait_for_email_engagement",
118
+ timeoutSeconds: durationToSeconds(timeout)
119
+ }
120
+ };
121
+ }
122
+ function exit(id, config) {
123
+ const { name, ...exitConfig } = config ?? {};
124
+ return {
125
+ id,
126
+ type: "exit",
127
+ name: name ?? "Exit",
128
+ config: { type: "exit", ...exitConfig }
129
+ };
130
+ }
131
+ function updateContact(id, config) {
132
+ const { name, ...updateConfig } = config;
133
+ return {
134
+ id,
135
+ type: "update_contact",
136
+ name: name ?? "Update contact",
137
+ config: { type: "update_contact", ...updateConfig }
138
+ };
139
+ }
140
+ function subscribeTopic(id, config) {
141
+ const { name, ...topicConfig } = config;
142
+ return {
143
+ id,
144
+ type: "subscribe_topic",
145
+ name: name ?? `Subscribe to topic: ${config.topicId}`,
146
+ config: { type: "subscribe_topic", ...topicConfig }
147
+ };
148
+ }
149
+ function unsubscribeTopic(id, config) {
150
+ const { name, ...topicConfig } = config;
151
+ return {
152
+ id,
153
+ type: "unsubscribe_topic",
154
+ name: name ?? `Unsubscribe from topic: ${config.topicId}`,
155
+ config: { type: "unsubscribe_topic", ...topicConfig }
156
+ };
157
+ }
158
+ function webhook(id, config) {
159
+ const { name, ...webhookConfig } = config;
160
+ return {
161
+ id,
162
+ type: "webhook",
163
+ name: name ?? `Webhook: ${config.url}`,
164
+ config: { type: "webhook", method: "POST", ...webhookConfig }
165
+ };
166
+ }
167
+
168
+ exports.condition = condition;
25
169
  exports.createPlatformClient = createPlatformClient;
170
+ exports.defineBrand = defineBrand;
171
+ exports.defineConfig = defineConfig;
172
+ exports.defineWorkflow = defineWorkflow;
173
+ exports.delay = delay;
174
+ exports.exit = exit;
175
+ exports.sendEmail = sendEmail;
176
+ exports.sendSms = sendSms;
177
+ exports.subscribeTopic = subscribeTopic;
178
+ exports.unsubscribeTopic = unsubscribeTopic;
179
+ exports.updateContact = updateContact;
180
+ exports.waitForEmailEngagement = waitForEmailEngagement;
181
+ exports.waitForEvent = waitForEvent;
182
+ exports.webhook = webhook;
26
183
  //# sourceMappingURL=index.js.map
27
184
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/client.ts"],"names":["createClient"],"mappings":";;;;;;;;;AAmCO,SAAS,qBAAqB,MAAA,EAA6B;AAChE,EAAA,MAAM,EAAE,MAAA,EAAQ,OAAA,GAAU,uBAAA,EAAwB,GAAI,MAAA;AAEtD,EAAA,MAAM,cAAA,GAA6B;AAAA,IACjC,MAAM,SAAA,CAAU,EAAE,OAAA,EAAQ,EAAG;AAC3B,MAAA,OAAA,CAAQ,OAAA,CAAQ,GAAA,CAAI,eAAA,EAAiB,CAAA,OAAA,EAAU,MAAM,CAAA,CAAE,CAAA;AACvD,MAAA,OAAO,OAAA;AAAA,IACT;AAAA,GACF;AAEA,EAAA,MAAM,SAASA,6BAAA,CAAoB;AAAA,IACjC;AAAA,GACD,CAAA;AAED,EAAA,MAAA,CAAO,IAAI,cAAc,CAAA;AAEzB,EAAA,OAAO,MAAA;AACT","file":"index.js","sourcesContent":["import createClient, { type Middleware } from 'openapi-fetch';\nimport type { paths } from './schema.d.ts';\n\nexport interface WrapsPlatformConfig {\n /** API key for authentication */\n apiKey: string;\n /** Base URL for the API (defaults to https://api.wraps.dev) */\n baseUrl?: string;\n}\n\n/**\n * Creates a type-safe API client for the Wraps Platform.\n *\n * @example\n * ```ts\n * const client = createPlatformClient({\n * apiKey: 'your-api-key',\n * });\n *\n * // List contacts with type safety\n * const { data, error } = await client.GET('/v1/contacts/', {\n * params: {\n * query: { page: '1', pageSize: '10' },\n * },\n * });\n *\n * // Create a contact\n * const { data, error } = await client.POST('/v1/contacts/', {\n * body: {\n * email: 'user@example.com',\n * emailStatus: 'active',\n * },\n * });\n * ```\n */\nexport function createPlatformClient(config: WrapsPlatformConfig) {\n const { apiKey, baseUrl = 'https://api.wraps.dev' } = config;\n\n const authMiddleware: Middleware = {\n async onRequest({ request }) {\n request.headers.set('Authorization', `Bearer ${apiKey}`);\n return request;\n },\n };\n\n const client = createClient<paths>({\n baseUrl,\n });\n\n client.use(authMiddleware);\n\n return client;\n}\n\nexport type PlatformClient = ReturnType<typeof createPlatformClient>;\n"]}
1
+ {"version":3,"sources":["../src/client.ts","../src/config.ts","../src/workflow.ts","../src/workflow-steps.ts"],"names":["createClient"],"mappings":"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","file":"index.js","sourcesContent":["import createClient, { type Middleware } from 'openapi-fetch';\nimport type { paths } from './schema.d.ts';\n\nexport interface WrapsPlatformConfig {\n /** API key for authentication */\n apiKey: string;\n /** Base URL for the API (defaults to https://api.wraps.dev) */\n baseUrl?: string;\n}\n\n/**\n * Creates a type-safe API client for the Wraps Platform.\n *\n * @example\n * ```ts\n * const client = createPlatformClient({\n * apiKey: 'your-api-key',\n * });\n *\n * // List contacts with type safety\n * const { data, error } = await client.GET('/v1/contacts/', {\n * params: {\n * query: { page: '1', pageSize: '10' },\n * },\n * });\n *\n * // Create a contact\n * const { data, error } = await client.POST('/v1/contacts/', {\n * body: {\n * email: 'user@example.com',\n * emailStatus: 'active',\n * },\n * });\n * ```\n */\nexport function createPlatformClient(config: WrapsPlatformConfig) {\n const { apiKey, baseUrl = 'https://api.wraps.dev' } = config;\n\n const authMiddleware: Middleware = {\n async onRequest({ request }) {\n request.headers.set('Authorization', `Bearer ${apiKey}`);\n return request;\n },\n };\n\n const client = createClient<paths>({\n baseUrl,\n });\n\n client.use(authMiddleware);\n\n return client;\n}\n\nexport type PlatformClient = ReturnType<typeof createPlatformClient>;\n","/**\n * Wraps Project Configuration\n *\n * Identity functions for TypeScript intellisense when defining\n * wraps.config.ts and brand.ts files.\n */\n\nexport interface WrapsEnvironment {\n region?: string;\n from?: { email: string; name?: string };\n replyTo?: string;\n}\n\nexport interface WrapsProjectConfig {\n /** Organization slug from wraps.dev */\n org: string;\n\n /** Default sender address */\n from?: { email: string; name?: string };\n\n /** Default reply-to address */\n replyTo?: string;\n\n /** AWS region for SES */\n region?: string;\n\n /** Environment-specific overrides */\n environments?: Record<string, WrapsEnvironment>;\n\n /** Default environment name */\n defaultEnv?: string;\n\n /** Path to templates directory (default: \"./templates\") */\n templatesDir?: string;\n\n /** Path to workflows directory (default: \"./workflows\") */\n workflowsDir?: string;\n\n /** Path to brand file (default: \"./brand.ts\") */\n brandFile?: string;\n\n /** Preview server options */\n preview?: { port?: number; open?: boolean };\n}\n\nexport interface WrapsBrandKit {\n /** Primary brand color (hex) */\n primaryColor: string;\n\n /** Secondary brand color (hex) */\n secondaryColor?: string;\n\n /** Email background color (hex) */\n backgroundColor?: string;\n\n /** Text color (hex) */\n textColor?: string;\n\n /** Body font family */\n fontFamily?: string;\n\n /** Heading font family */\n headingFontFamily?: string;\n\n /** Button border radius (CSS value) */\n buttonRadius?: string;\n\n /** Button style preset */\n buttonStyle?: 'rounded' | 'square' | 'pill';\n\n /** Company name for footer */\n companyName?: string;\n\n /** Company address for CAN-SPAM compliance */\n companyAddress?: string;\n\n /** Logo URL */\n logoUrl?: string;\n\n /** Social media links */\n socialLinks?: Array<{ platform: string; url: string }>;\n}\n\n/**\n * Define your Wraps project configuration.\n * Use this in `wraps/wraps.config.ts` for full TypeScript intellisense.\n *\n * @example\n * ```ts\n * import { defineConfig } from '@wraps.dev/client';\n *\n * export default defineConfig({\n * org: 'my-company',\n * from: { email: 'hello@myapp.com', name: 'My App' },\n * region: 'us-east-1',\n * });\n * ```\n */\nexport function defineConfig(config: WrapsProjectConfig): WrapsProjectConfig {\n return config;\n}\n\n/**\n * Define your brand kit for consistent email styling.\n * Use this in `wraps/brand.ts` for full TypeScript intellisense.\n *\n * @example\n * ```ts\n * import { defineBrand } from '@wraps.dev/client';\n *\n * export default defineBrand({\n * primaryColor: '#5046e5',\n * companyName: 'My Company',\n * companyAddress: '123 Main St, City, ST 12345',\n * });\n * ```\n */\nexport function defineBrand(brand: WrapsBrandKit): WrapsBrandKit {\n return brand;\n}\n","/**\n * Workflow Definition Types\n *\n * Declarative TypeScript workflow definitions for email automation.\n * Use `defineWorkflow()` in `wraps/workflows/*.ts` for full TypeScript intellisense.\n *\n * @example\n * ```ts\n * import { defineWorkflow, sendEmail, delay, condition, exit } from '@wraps.dev/client';\n *\n * export default defineWorkflow({\n * name: 'User Onboarding',\n * description: 'Welcome sequence for new users',\n *\n * trigger: { type: 'contact_created' },\n *\n * steps: [\n * sendEmail('welcome', { template: 'welcome' }),\n * delay('wait-1-day', { days: 1 }),\n * condition('check-activation', {\n * field: 'contact.hasActivated',\n * operator: 'equals',\n * value: true,\n * branches: {\n * yes: [exit('activated')],\n * no: [sendEmail('tips', { template: 'getting-started-tips' })],\n * },\n * }),\n * ],\n * });\n * ```\n */\n\n// ═══════════════════════════════════════════════════════════════════════════\n// TRIGGER TYPES\n// ═══════════════════════════════════════════════════════════════════════════\n\n/**\n * Trigger types for workflow entry points\n */\nexport type WorkflowTriggerType =\n | 'event'\n | 'contact_created'\n | 'contact_updated'\n | 'segment_entry'\n | 'segment_exit'\n | 'schedule'\n | 'api'\n | 'topic_subscribed'\n | 'topic_unsubscribed';\n\n/**\n * Trigger configuration based on trigger type\n */\nexport interface TriggerDefinition {\n /** The type of trigger that starts this workflow */\n type: WorkflowTriggerType;\n\n /** For 'event' trigger: the event name to listen for */\n eventName?: string;\n\n /** For segment triggers: the segment ID to monitor */\n segmentId?: string;\n\n /** For 'schedule' trigger: cron expression */\n schedule?: string;\n\n /** For 'schedule' trigger: timezone (e.g., 'America/New_York') */\n timezone?: string;\n\n /** For topic triggers: the topic ID to monitor */\n topicId?: string;\n}\n\n// ═══════════════════════════════════════════════════════════════════════════\n// STEP TYPES\n// ═══════════════════════════════════════════════════════════════════════════\n\n/**\n * Workflow step types available in the builder\n */\nexport type WorkflowStepType =\n | 'trigger'\n | 'send_email'\n | 'send_sms'\n | 'delay'\n | 'exit'\n | 'condition'\n | 'webhook'\n | 'update_contact'\n | 'wait_for_event'\n | 'wait_for_email_engagement'\n | 'subscribe_topic'\n | 'unsubscribe_topic';\n\n/**\n * Duration configuration for delays and timeouts\n */\nexport interface DurationConfig {\n /** Number of days */\n days?: number;\n /** Number of hours */\n hours?: number;\n /** Number of minutes */\n minutes?: number;\n}\n\n/**\n * Condition operators for branching\n */\nexport type ConditionOperator =\n | 'equals'\n | 'not_equals'\n | 'contains'\n | 'not_contains'\n | 'starts_with'\n | 'ends_with'\n | 'greater_than'\n | 'less_than'\n | 'greater_than_or_equals'\n | 'less_than_or_equals'\n | 'is_set'\n | 'is_not_set'\n | 'is_true'\n | 'is_false';\n\n/**\n * Email template reference (by slug) or inline content\n */\nexport type EmailContent =\n | { template: string }\n | { subject: string; body: string };\n\n/**\n * SMS template reference or inline message\n */\nexport type SmsContent = { template: string } | { message: string };\n\n/**\n * Configuration for send_email step\n */\nexport interface SendEmailStepConfig {\n /** Template slug or inline content */\n template?: string;\n subject?: string;\n body?: string;\n /** Override sender address */\n from?: string;\n /** Override sender name */\n fromName?: string;\n /** Override reply-to address */\n replyTo?: string;\n}\n\n/**\n * Configuration for send_sms step\n */\nexport interface SendSmsStepConfig {\n /** Template slug or inline message */\n template?: string;\n message?: string;\n /** Override sender ID */\n senderId?: string;\n}\n\n/**\n * Configuration for delay step (user-facing)\n */\nexport interface DelayStepConfig extends DurationConfig {}\n\n/**\n * Configuration for delay step (internal/DB format)\n */\nexport interface DelayStepDbConfig {\n /** Delay amount */\n amount: number;\n /** Delay unit */\n unit: 'minutes' | 'hours' | 'days' | 'weeks';\n}\n\n/**\n * Configuration for condition step\n */\nexport interface ConditionStepConfig {\n /** Field to evaluate (e.g., 'contact.email', 'contact.hasActivated') */\n field: string;\n /** Comparison operator */\n operator: ConditionOperator;\n /** Value to compare against (not used for is_set, is_not_set, is_true, is_false) */\n value?: unknown;\n /** Branches for yes/no outcomes */\n branches: {\n yes?: StepDefinition[];\n no?: StepDefinition[];\n };\n}\n\n/**\n * Configuration for wait_for_event step (user-facing)\n */\nexport interface WaitForEventStepConfig {\n /** Event name to wait for */\n eventName: string;\n /** Timeout duration (optional) - will be converted to timeoutSeconds */\n timeout?: DurationConfig;\n}\n\n/**\n * Configuration for wait_for_event step (internal/DB format)\n */\nexport interface WaitForEventStepDbConfig {\n /** Event name to wait for */\n eventName: string;\n /** Timeout in seconds */\n timeoutSeconds?: number;\n}\n\n/**\n * Configuration for wait_for_email_engagement step (user-facing)\n */\nexport interface WaitForEmailEngagementStepConfig {\n /** ID of the email step to track */\n emailStepId: string;\n /** Type of engagement to wait for */\n engagementType: 'opened' | 'clicked';\n /** Timeout duration (optional) - will be converted to timeoutSeconds */\n timeout?: DurationConfig;\n}\n\n/**\n * Configuration for wait_for_email_engagement step (internal/DB format)\n */\nexport interface WaitForEmailEngagementStepDbConfig {\n /** Timeout in seconds */\n timeoutSeconds?: number;\n}\n\n/**\n * Configuration for update_contact step\n */\nexport interface UpdateContactStepConfig {\n /** Field updates to apply */\n updates: Array<{\n field: string;\n operation: 'set' | 'increment' | 'decrement' | 'append' | 'remove';\n value?: unknown;\n }>;\n}\n\n/**\n * Configuration for webhook step\n */\nexport interface WebhookStepConfig {\n /** Webhook URL */\n url: string;\n /** HTTP method (default: POST) */\n method?: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';\n /** HTTP headers */\n headers?: Record<string, string>;\n /** Request body (for POST/PUT/PATCH) */\n body?: Record<string, unknown>;\n}\n\n/**\n * Configuration for subscribe/unsubscribe_topic step\n */\nexport interface TopicStepConfig {\n /** Topic ID to subscribe to or unsubscribe from */\n topicId: string;\n /** Channel for the subscription */\n channel?: 'email' | 'sms';\n}\n\n/**\n * Configuration for exit step\n */\nexport interface ExitStepConfig {\n /** Optional reason for exiting */\n reason?: string;\n /** Mark execution as completed, cancelled, or failed */\n markAs?: 'completed' | 'cancelled' | 'failed';\n}\n\n/**\n * A step in the workflow definition\n */\nexport interface StepDefinition {\n /** Unique step identifier (used for transitions and references) */\n id: string;\n /** Step type */\n type: WorkflowStepType;\n /** Optional display name (defaults to type if not provided) */\n name?: string;\n /** Step-specific configuration */\n config: StepConfig;\n /** Branches for condition steps */\n branches?: {\n yes?: StepDefinition[];\n no?: StepDefinition[];\n };\n}\n\n/**\n * Union of all step configurations (internal/DB format)\n * This is the format stored in the database and used by the execution engine.\n */\nexport type StepConfig =\n | ({ type: 'send_email' } & SendEmailStepConfig)\n | ({ type: 'send_sms' } & SendSmsStepConfig)\n | ({ type: 'delay' } & DelayStepDbConfig)\n | ({ type: 'condition' } & Omit<ConditionStepConfig, 'branches'>)\n | ({ type: 'wait_for_event' } & WaitForEventStepDbConfig)\n | ({ type: 'wait_for_email_engagement' } & WaitForEmailEngagementStepDbConfig)\n | ({ type: 'update_contact' } & UpdateContactStepConfig)\n | ({ type: 'webhook' } & WebhookStepConfig)\n | ({ type: 'subscribe_topic' } & TopicStepConfig)\n | ({ type: 'unsubscribe_topic' } & TopicStepConfig)\n | ({ type: 'exit' } & ExitStepConfig);\n\n// ═══════════════════════════════════════════════════════════════════════════\n// WORKFLOW SETTINGS\n// ═══════════════════════════════════════════════════════════════════════════\n\n/**\n * Workflow execution settings\n */\nexport interface WorkflowSettings {\n /** Allow the same contact to re-enter the workflow if they trigger it again */\n allowReentry?: boolean;\n\n /** Minimum seconds between re-entries for the same contact (only used if allowReentry is true) */\n reentryDelaySeconds?: number;\n\n /** Maximum concurrent executions allowed for this workflow */\n maxConcurrentExecutions?: number;\n\n /** Cooldown period in seconds before a contact can trigger this workflow again */\n contactCooldownSeconds?: number;\n}\n\n// ═══════════════════════════════════════════════════════════════════════════\n// WORKFLOW DEFINITION\n// ═══════════════════════════════════════════════════════════════════════════\n\n/**\n * Complete workflow definition\n */\nexport interface WorkflowDefinition {\n /** Display name for the workflow */\n name: string;\n\n /** Optional description */\n description?: string;\n\n /** What triggers this workflow */\n trigger: TriggerDefinition;\n\n /** Steps in the workflow (executed sequentially unless branched) */\n steps: StepDefinition[];\n\n /** Execution settings */\n settings?: WorkflowSettings;\n\n /** Optional: associate workflow with a topic for subscription checks */\n topicId?: string;\n\n /** Default sender settings (can be overridden per step) */\n defaults?: {\n from?: string;\n fromName?: string;\n replyTo?: string;\n senderId?: string;\n };\n}\n\n// ═══════════════════════════════════════════════════════════════════════════\n// DEFINE WORKFLOW\n// ═══════════════════════════════════════════════════════════════════════════\n\n/**\n * Define an email automation workflow.\n * Use this in `wraps/workflows/*.ts` for full TypeScript intellisense.\n *\n * @example\n * ```ts\n * import { defineWorkflow, sendEmail, delay, exit } from '@wraps.dev/client';\n *\n * export default defineWorkflow({\n * name: 'Welcome Sequence',\n * trigger: { type: 'contact_created' },\n * steps: [\n * sendEmail('welcome', { template: 'welcome' }),\n * delay('wait-1-day', { days: 1 }),\n * sendEmail('tips', { template: 'getting-started-tips' }),\n * ],\n * });\n * ```\n */\nexport function defineWorkflow(\n definition: WorkflowDefinition\n): WorkflowDefinition {\n return definition;\n}\n","/**\n * Workflow Step Helper Functions\n *\n * Ergonomic helpers for defining workflow steps declaratively.\n * These functions return step definitions that can be used in `defineWorkflow()`.\n */\n\nimport type {\n ConditionOperator,\n ConditionStepConfig,\n DelayStepConfig,\n DurationConfig,\n ExitStepConfig,\n SendEmailStepConfig,\n SendSmsStepConfig,\n StepDefinition,\n TopicStepConfig,\n UpdateContactStepConfig,\n WaitForEmailEngagementStepConfig,\n WaitForEventStepConfig,\n WebhookStepConfig,\n} from './workflow';\n\n// ═══════════════════════════════════════════════════════════════════════════\n// INTERNAL HELPERS\n// ═══════════════════════════════════════════════════════════════════════════\n\n/**\n * Convert DurationConfig to delay step config (amount + unit)\n */\nfunction normalizeDuration(duration: DurationConfig): {\n amount: number;\n unit: 'minutes' | 'hours' | 'days' | 'weeks';\n} {\n if (duration.days !== undefined) {\n return { amount: duration.days, unit: 'days' };\n }\n if (duration.hours !== undefined) {\n return { amount: duration.hours, unit: 'hours' };\n }\n if (duration.minutes !== undefined) {\n return { amount: duration.minutes, unit: 'minutes' };\n }\n // Default to 1 hour if nothing specified\n return { amount: 1, unit: 'hours' };\n}\n\n/**\n * Convert DurationConfig to seconds for timeout values\n */\nfunction durationToSeconds(duration?: DurationConfig): number | undefined {\n if (!duration) return undefined;\n\n let seconds = 0;\n if (duration.days) seconds += duration.days * 24 * 60 * 60;\n if (duration.hours) seconds += duration.hours * 60 * 60;\n if (duration.minutes) seconds += duration.minutes * 60;\n\n return seconds > 0 ? seconds : undefined;\n}\n\n// ═══════════════════════════════════════════════════════════════════════════\n// CHANNEL STEPS\n// ═══════════════════════════════════════════════════════════════════════════\n\n/**\n * Send an email using a template or inline content.\n *\n * @example\n * ```ts\n * // Using a template\n * sendEmail('welcome', { template: 'welcome-email' })\n *\n * // With overrides\n * sendEmail('promo', {\n * template: 'promo-email',\n * from: 'marketing@example.com',\n * fromName: 'Marketing Team',\n * })\n * ```\n */\nexport function sendEmail(\n id: string,\n config: SendEmailStepConfig & { name?: string }\n): StepDefinition {\n const { name, ...stepConfig } = config;\n return {\n id,\n type: 'send_email',\n name: name ?? `Send email: ${config.template || 'custom'}`,\n config: { type: 'send_email', ...stepConfig },\n };\n}\n\n/**\n * Send an SMS using a template or inline message.\n *\n * @example\n * ```ts\n * // Using a template\n * sendSms('reminder', { template: 'appointment-reminder' })\n *\n * // Inline message\n * sendSms('otp', { message: 'Your code is {{otp}}' })\n * ```\n */\nexport function sendSms(\n id: string,\n config: SendSmsStepConfig & { name?: string }\n): StepDefinition {\n const { name, ...stepConfig } = config;\n return {\n id,\n type: 'send_sms',\n name: name ?? `Send SMS: ${config.template || 'custom'}`,\n config: { type: 'send_sms', ...stepConfig },\n };\n}\n\n// ═══════════════════════════════════════════════════════════════════════════\n// CONTROL FLOW STEPS\n// ═══════════════════════════════════════════════════════════════════════════\n\n/**\n * Wait for a specified duration before continuing.\n *\n * @example\n * ```ts\n * delay('wait-1-day', { days: 1 })\n * delay('wait-2-hours', { hours: 2 })\n * delay('wait-30-min', { minutes: 30 })\n * ```\n */\nexport function delay(\n id: string,\n duration: DurationConfig & { name?: string }\n): StepDefinition {\n const { name, ...durationConfig } = duration;\n const normalized = normalizeDuration(durationConfig);\n return {\n id,\n type: 'delay',\n name: name ?? `Wait ${normalized.amount} ${normalized.unit}`,\n config: { type: 'delay', ...normalized },\n };\n}\n\n/**\n * Branch the workflow based on a condition.\n *\n * @example\n * ```ts\n * condition('check-activated', {\n * field: 'contact.hasActivated',\n * operator: 'equals',\n * value: true,\n * branches: {\n * yes: [exit('already-active')],\n * no: [sendEmail('activation-reminder', { template: 'activate' })],\n * },\n * })\n * ```\n */\nexport function condition(\n id: string,\n config: ConditionStepConfig & { name?: string }\n): StepDefinition {\n const { branches, name, ...conditionConfig } = config;\n return {\n id,\n type: 'condition',\n name: name ?? `Check: ${config.field} ${config.operator}`,\n config: { type: 'condition', ...conditionConfig },\n branches,\n };\n}\n\n/**\n * Wait for a specific event before continuing.\n *\n * @example\n * ```ts\n * waitForEvent('wait-for-purchase', {\n * eventName: 'purchase_completed',\n * timeout: { days: 7 },\n * })\n * ```\n */\nexport function waitForEvent(\n id: string,\n config: WaitForEventStepConfig & { name?: string }\n): StepDefinition {\n const { name, timeout, ...eventConfig } = config;\n return {\n id,\n type: 'wait_for_event',\n name: name ?? `Wait for: ${config.eventName}`,\n config: {\n type: 'wait_for_event',\n eventName: eventConfig.eventName,\n timeoutSeconds: durationToSeconds(timeout),\n },\n };\n}\n\n/**\n * Wait for engagement with a previous email step.\n *\n * @example\n * ```ts\n * waitForEmailEngagement('wait-for-open', {\n * emailStepId: 'welcome',\n * engagementType: 'opened',\n * timeout: { days: 3 },\n * })\n * ```\n */\nexport function waitForEmailEngagement(\n id: string,\n config: WaitForEmailEngagementStepConfig & { name?: string }\n): StepDefinition {\n const { name, timeout, emailStepId, engagementType } = config;\n return {\n id,\n type: 'wait_for_email_engagement',\n name:\n name ?? `Wait for email ${engagementType}: ${emailStepId}`,\n config: {\n type: 'wait_for_email_engagement',\n timeoutSeconds: durationToSeconds(timeout),\n },\n };\n}\n\n/**\n * Exit the workflow.\n *\n * @example\n * ```ts\n * exit('completed')\n * exit('cancelled', { reason: 'User unsubscribed', markAs: 'cancelled' })\n * ```\n */\nexport function exit(\n id: string,\n config?: ExitStepConfig & { name?: string }\n): StepDefinition {\n const { name, ...exitConfig } = config ?? {};\n return {\n id,\n type: 'exit',\n name: name ?? 'Exit',\n config: { type: 'exit', ...exitConfig },\n };\n}\n\n// ═══════════════════════════════════════════════════════════════════════════\n// ACTION STEPS\n// ═══════════════════════════════════════════════════════════════════════════\n\n/**\n * Update contact fields.\n *\n * @example\n * ```ts\n * updateContact('mark-welcomed', {\n * updates: [\n * { field: 'welcomeEmailSent', operation: 'set', value: true },\n * { field: 'emailCount', operation: 'increment', value: 1 },\n * ],\n * })\n * ```\n */\nexport function updateContact(\n id: string,\n config: Omit<UpdateContactStepConfig, 'type'> & { name?: string }\n): StepDefinition {\n const { name, ...updateConfig } = config;\n return {\n id,\n type: 'update_contact',\n name: name ?? 'Update contact',\n config: { type: 'update_contact', ...updateConfig },\n };\n}\n\n/**\n * Subscribe a contact to a topic.\n *\n * @example\n * ```ts\n * subscribeTopic('subscribe-newsletter', {\n * topicId: 'newsletter',\n * channel: 'email',\n * })\n * ```\n */\nexport function subscribeTopic(\n id: string,\n config: Omit<TopicStepConfig, 'type'> & { name?: string }\n): StepDefinition {\n const { name, ...topicConfig } = config;\n return {\n id,\n type: 'subscribe_topic',\n name: name ?? `Subscribe to topic: ${config.topicId}`,\n config: { type: 'subscribe_topic', ...topicConfig },\n };\n}\n\n/**\n * Unsubscribe a contact from a topic.\n *\n * @example\n * ```ts\n * unsubscribeTopic('unsubscribe-promo', {\n * topicId: 'promotions',\n * channel: 'email',\n * })\n * ```\n */\nexport function unsubscribeTopic(\n id: string,\n config: Omit<TopicStepConfig, 'type'> & { name?: string }\n): StepDefinition {\n const { name, ...topicConfig } = config;\n return {\n id,\n type: 'unsubscribe_topic',\n name: name ?? `Unsubscribe from topic: ${config.topicId}`,\n config: { type: 'unsubscribe_topic', ...topicConfig },\n };\n}\n\n/**\n * Call an external webhook.\n *\n * @example\n * ```ts\n * webhook('notify-slack', {\n * url: 'https://hooks.slack.com/services/...',\n * method: 'POST',\n * body: { text: 'New user signed up!' },\n * })\n * ```\n */\nexport function webhook(\n id: string,\n config: Omit<WebhookStepConfig, 'type'> & { name?: string }\n): StepDefinition {\n const { name, ...webhookConfig } = config;\n return {\n id,\n type: 'webhook',\n name: name ?? `Webhook: ${config.url}`,\n config: { type: 'webhook', method: 'POST', ...webhookConfig },\n };\n}\n"]}
package/dist/index.mjs CHANGED
@@ -16,6 +16,149 @@ function createPlatformClient(config) {
16
16
  return client;
17
17
  }
18
18
 
19
- export { createPlatformClient };
19
+ // src/config.ts
20
+ function defineConfig(config) {
21
+ return config;
22
+ }
23
+ function defineBrand(brand) {
24
+ return brand;
25
+ }
26
+
27
+ // src/workflow.ts
28
+ function defineWorkflow(definition) {
29
+ return definition;
30
+ }
31
+
32
+ // src/workflow-steps.ts
33
+ function normalizeDuration(duration) {
34
+ if (duration.days !== void 0) {
35
+ return { amount: duration.days, unit: "days" };
36
+ }
37
+ if (duration.hours !== void 0) {
38
+ return { amount: duration.hours, unit: "hours" };
39
+ }
40
+ if (duration.minutes !== void 0) {
41
+ return { amount: duration.minutes, unit: "minutes" };
42
+ }
43
+ return { amount: 1, unit: "hours" };
44
+ }
45
+ function durationToSeconds(duration) {
46
+ if (!duration) return void 0;
47
+ let seconds = 0;
48
+ if (duration.days) seconds += duration.days * 24 * 60 * 60;
49
+ if (duration.hours) seconds += duration.hours * 60 * 60;
50
+ if (duration.minutes) seconds += duration.minutes * 60;
51
+ return seconds > 0 ? seconds : void 0;
52
+ }
53
+ function sendEmail(id, config) {
54
+ const { name, ...stepConfig } = config;
55
+ return {
56
+ id,
57
+ type: "send_email",
58
+ name: name ?? `Send email: ${config.template || "custom"}`,
59
+ config: { type: "send_email", ...stepConfig }
60
+ };
61
+ }
62
+ function sendSms(id, config) {
63
+ const { name, ...stepConfig } = config;
64
+ return {
65
+ id,
66
+ type: "send_sms",
67
+ name: name ?? `Send SMS: ${config.template || "custom"}`,
68
+ config: { type: "send_sms", ...stepConfig }
69
+ };
70
+ }
71
+ function delay(id, duration) {
72
+ const { name, ...durationConfig } = duration;
73
+ const normalized = normalizeDuration(durationConfig);
74
+ return {
75
+ id,
76
+ type: "delay",
77
+ name: name ?? `Wait ${normalized.amount} ${normalized.unit}`,
78
+ config: { type: "delay", ...normalized }
79
+ };
80
+ }
81
+ function condition(id, config) {
82
+ const { branches, name, ...conditionConfig } = config;
83
+ return {
84
+ id,
85
+ type: "condition",
86
+ name: name ?? `Check: ${config.field} ${config.operator}`,
87
+ config: { type: "condition", ...conditionConfig },
88
+ branches
89
+ };
90
+ }
91
+ function waitForEvent(id, config) {
92
+ const { name, timeout, ...eventConfig } = config;
93
+ return {
94
+ id,
95
+ type: "wait_for_event",
96
+ name: name ?? `Wait for: ${config.eventName}`,
97
+ config: {
98
+ type: "wait_for_event",
99
+ eventName: eventConfig.eventName,
100
+ timeoutSeconds: durationToSeconds(timeout)
101
+ }
102
+ };
103
+ }
104
+ function waitForEmailEngagement(id, config) {
105
+ const { name, timeout, emailStepId, engagementType } = config;
106
+ return {
107
+ id,
108
+ type: "wait_for_email_engagement",
109
+ name: name ?? `Wait for email ${engagementType}: ${emailStepId}`,
110
+ config: {
111
+ type: "wait_for_email_engagement",
112
+ timeoutSeconds: durationToSeconds(timeout)
113
+ }
114
+ };
115
+ }
116
+ function exit(id, config) {
117
+ const { name, ...exitConfig } = config ?? {};
118
+ return {
119
+ id,
120
+ type: "exit",
121
+ name: name ?? "Exit",
122
+ config: { type: "exit", ...exitConfig }
123
+ };
124
+ }
125
+ function updateContact(id, config) {
126
+ const { name, ...updateConfig } = config;
127
+ return {
128
+ id,
129
+ type: "update_contact",
130
+ name: name ?? "Update contact",
131
+ config: { type: "update_contact", ...updateConfig }
132
+ };
133
+ }
134
+ function subscribeTopic(id, config) {
135
+ const { name, ...topicConfig } = config;
136
+ return {
137
+ id,
138
+ type: "subscribe_topic",
139
+ name: name ?? `Subscribe to topic: ${config.topicId}`,
140
+ config: { type: "subscribe_topic", ...topicConfig }
141
+ };
142
+ }
143
+ function unsubscribeTopic(id, config) {
144
+ const { name, ...topicConfig } = config;
145
+ return {
146
+ id,
147
+ type: "unsubscribe_topic",
148
+ name: name ?? `Unsubscribe from topic: ${config.topicId}`,
149
+ config: { type: "unsubscribe_topic", ...topicConfig }
150
+ };
151
+ }
152
+ function webhook(id, config) {
153
+ const { name, ...webhookConfig } = config;
154
+ return {
155
+ id,
156
+ type: "webhook",
157
+ name: name ?? `Webhook: ${config.url}`,
158
+ config: { type: "webhook", method: "POST", ...webhookConfig }
159
+ };
160
+ }
161
+
162
+ export { condition, createPlatformClient, defineBrand, defineConfig, defineWorkflow, delay, exit, sendEmail, sendSms, subscribeTopic, unsubscribeTopic, updateContact, waitForEmailEngagement, waitForEvent, webhook };
20
163
  //# sourceMappingURL=index.mjs.map
21
164
  //# sourceMappingURL=index.mjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/client.ts"],"names":[],"mappings":";;;AAmCO,SAAS,qBAAqB,MAAA,EAA6B;AAChE,EAAA,MAAM,EAAE,MAAA,EAAQ,OAAA,GAAU,uBAAA,EAAwB,GAAI,MAAA;AAEtD,EAAA,MAAM,cAAA,GAA6B;AAAA,IACjC,MAAM,SAAA,CAAU,EAAE,OAAA,EAAQ,EAAG;AAC3B,MAAA,OAAA,CAAQ,OAAA,CAAQ,GAAA,CAAI,eAAA,EAAiB,CAAA,OAAA,EAAU,MAAM,CAAA,CAAE,CAAA;AACvD,MAAA,OAAO,OAAA;AAAA,IACT;AAAA,GACF;AAEA,EAAA,MAAM,SAAS,YAAA,CAAoB;AAAA,IACjC;AAAA,GACD,CAAA;AAED,EAAA,MAAA,CAAO,IAAI,cAAc,CAAA;AAEzB,EAAA,OAAO,MAAA;AACT","file":"index.mjs","sourcesContent":["import createClient, { type Middleware } from 'openapi-fetch';\nimport type { paths } from './schema.d.ts';\n\nexport interface WrapsPlatformConfig {\n /** API key for authentication */\n apiKey: string;\n /** Base URL for the API (defaults to https://api.wraps.dev) */\n baseUrl?: string;\n}\n\n/**\n * Creates a type-safe API client for the Wraps Platform.\n *\n * @example\n * ```ts\n * const client = createPlatformClient({\n * apiKey: 'your-api-key',\n * });\n *\n * // List contacts with type safety\n * const { data, error } = await client.GET('/v1/contacts/', {\n * params: {\n * query: { page: '1', pageSize: '10' },\n * },\n * });\n *\n * // Create a contact\n * const { data, error } = await client.POST('/v1/contacts/', {\n * body: {\n * email: 'user@example.com',\n * emailStatus: 'active',\n * },\n * });\n * ```\n */\nexport function createPlatformClient(config: WrapsPlatformConfig) {\n const { apiKey, baseUrl = 'https://api.wraps.dev' } = config;\n\n const authMiddleware: Middleware = {\n async onRequest({ request }) {\n request.headers.set('Authorization', `Bearer ${apiKey}`);\n return request;\n },\n };\n\n const client = createClient<paths>({\n baseUrl,\n });\n\n client.use(authMiddleware);\n\n return client;\n}\n\nexport type PlatformClient = ReturnType<typeof createPlatformClient>;\n"]}
1
+ {"version":3,"sources":["../src/client.ts","../src/config.ts","../src/workflow.ts","../src/workflow-steps.ts"],"names":[],"mappings":"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","file":"index.mjs","sourcesContent":["import createClient, { type Middleware } from 'openapi-fetch';\nimport type { paths } from './schema.d.ts';\n\nexport interface WrapsPlatformConfig {\n /** API key for authentication */\n apiKey: string;\n /** Base URL for the API (defaults to https://api.wraps.dev) */\n baseUrl?: string;\n}\n\n/**\n * Creates a type-safe API client for the Wraps Platform.\n *\n * @example\n * ```ts\n * const client = createPlatformClient({\n * apiKey: 'your-api-key',\n * });\n *\n * // List contacts with type safety\n * const { data, error } = await client.GET('/v1/contacts/', {\n * params: {\n * query: { page: '1', pageSize: '10' },\n * },\n * });\n *\n * // Create a contact\n * const { data, error } = await client.POST('/v1/contacts/', {\n * body: {\n * email: 'user@example.com',\n * emailStatus: 'active',\n * },\n * });\n * ```\n */\nexport function createPlatformClient(config: WrapsPlatformConfig) {\n const { apiKey, baseUrl = 'https://api.wraps.dev' } = config;\n\n const authMiddleware: Middleware = {\n async onRequest({ request }) {\n request.headers.set('Authorization', `Bearer ${apiKey}`);\n return request;\n },\n };\n\n const client = createClient<paths>({\n baseUrl,\n });\n\n client.use(authMiddleware);\n\n return client;\n}\n\nexport type PlatformClient = ReturnType<typeof createPlatformClient>;\n","/**\n * Wraps Project Configuration\n *\n * Identity functions for TypeScript intellisense when defining\n * wraps.config.ts and brand.ts files.\n */\n\nexport interface WrapsEnvironment {\n region?: string;\n from?: { email: string; name?: string };\n replyTo?: string;\n}\n\nexport interface WrapsProjectConfig {\n /** Organization slug from wraps.dev */\n org: string;\n\n /** Default sender address */\n from?: { email: string; name?: string };\n\n /** Default reply-to address */\n replyTo?: string;\n\n /** AWS region for SES */\n region?: string;\n\n /** Environment-specific overrides */\n environments?: Record<string, WrapsEnvironment>;\n\n /** Default environment name */\n defaultEnv?: string;\n\n /** Path to templates directory (default: \"./templates\") */\n templatesDir?: string;\n\n /** Path to workflows directory (default: \"./workflows\") */\n workflowsDir?: string;\n\n /** Path to brand file (default: \"./brand.ts\") */\n brandFile?: string;\n\n /** Preview server options */\n preview?: { port?: number; open?: boolean };\n}\n\nexport interface WrapsBrandKit {\n /** Primary brand color (hex) */\n primaryColor: string;\n\n /** Secondary brand color (hex) */\n secondaryColor?: string;\n\n /** Email background color (hex) */\n backgroundColor?: string;\n\n /** Text color (hex) */\n textColor?: string;\n\n /** Body font family */\n fontFamily?: string;\n\n /** Heading font family */\n headingFontFamily?: string;\n\n /** Button border radius (CSS value) */\n buttonRadius?: string;\n\n /** Button style preset */\n buttonStyle?: 'rounded' | 'square' | 'pill';\n\n /** Company name for footer */\n companyName?: string;\n\n /** Company address for CAN-SPAM compliance */\n companyAddress?: string;\n\n /** Logo URL */\n logoUrl?: string;\n\n /** Social media links */\n socialLinks?: Array<{ platform: string; url: string }>;\n}\n\n/**\n * Define your Wraps project configuration.\n * Use this in `wraps/wraps.config.ts` for full TypeScript intellisense.\n *\n * @example\n * ```ts\n * import { defineConfig } from '@wraps.dev/client';\n *\n * export default defineConfig({\n * org: 'my-company',\n * from: { email: 'hello@myapp.com', name: 'My App' },\n * region: 'us-east-1',\n * });\n * ```\n */\nexport function defineConfig(config: WrapsProjectConfig): WrapsProjectConfig {\n return config;\n}\n\n/**\n * Define your brand kit for consistent email styling.\n * Use this in `wraps/brand.ts` for full TypeScript intellisense.\n *\n * @example\n * ```ts\n * import { defineBrand } from '@wraps.dev/client';\n *\n * export default defineBrand({\n * primaryColor: '#5046e5',\n * companyName: 'My Company',\n * companyAddress: '123 Main St, City, ST 12345',\n * });\n * ```\n */\nexport function defineBrand(brand: WrapsBrandKit): WrapsBrandKit {\n return brand;\n}\n","/**\n * Workflow Definition Types\n *\n * Declarative TypeScript workflow definitions for email automation.\n * Use `defineWorkflow()` in `wraps/workflows/*.ts` for full TypeScript intellisense.\n *\n * @example\n * ```ts\n * import { defineWorkflow, sendEmail, delay, condition, exit } from '@wraps.dev/client';\n *\n * export default defineWorkflow({\n * name: 'User Onboarding',\n * description: 'Welcome sequence for new users',\n *\n * trigger: { type: 'contact_created' },\n *\n * steps: [\n * sendEmail('welcome', { template: 'welcome' }),\n * delay('wait-1-day', { days: 1 }),\n * condition('check-activation', {\n * field: 'contact.hasActivated',\n * operator: 'equals',\n * value: true,\n * branches: {\n * yes: [exit('activated')],\n * no: [sendEmail('tips', { template: 'getting-started-tips' })],\n * },\n * }),\n * ],\n * });\n * ```\n */\n\n// ═══════════════════════════════════════════════════════════════════════════\n// TRIGGER TYPES\n// ═══════════════════════════════════════════════════════════════════════════\n\n/**\n * Trigger types for workflow entry points\n */\nexport type WorkflowTriggerType =\n | 'event'\n | 'contact_created'\n | 'contact_updated'\n | 'segment_entry'\n | 'segment_exit'\n | 'schedule'\n | 'api'\n | 'topic_subscribed'\n | 'topic_unsubscribed';\n\n/**\n * Trigger configuration based on trigger type\n */\nexport interface TriggerDefinition {\n /** The type of trigger that starts this workflow */\n type: WorkflowTriggerType;\n\n /** For 'event' trigger: the event name to listen for */\n eventName?: string;\n\n /** For segment triggers: the segment ID to monitor */\n segmentId?: string;\n\n /** For 'schedule' trigger: cron expression */\n schedule?: string;\n\n /** For 'schedule' trigger: timezone (e.g., 'America/New_York') */\n timezone?: string;\n\n /** For topic triggers: the topic ID to monitor */\n topicId?: string;\n}\n\n// ═══════════════════════════════════════════════════════════════════════════\n// STEP TYPES\n// ═══════════════════════════════════════════════════════════════════════════\n\n/**\n * Workflow step types available in the builder\n */\nexport type WorkflowStepType =\n | 'trigger'\n | 'send_email'\n | 'send_sms'\n | 'delay'\n | 'exit'\n | 'condition'\n | 'webhook'\n | 'update_contact'\n | 'wait_for_event'\n | 'wait_for_email_engagement'\n | 'subscribe_topic'\n | 'unsubscribe_topic';\n\n/**\n * Duration configuration for delays and timeouts\n */\nexport interface DurationConfig {\n /** Number of days */\n days?: number;\n /** Number of hours */\n hours?: number;\n /** Number of minutes */\n minutes?: number;\n}\n\n/**\n * Condition operators for branching\n */\nexport type ConditionOperator =\n | 'equals'\n | 'not_equals'\n | 'contains'\n | 'not_contains'\n | 'starts_with'\n | 'ends_with'\n | 'greater_than'\n | 'less_than'\n | 'greater_than_or_equals'\n | 'less_than_or_equals'\n | 'is_set'\n | 'is_not_set'\n | 'is_true'\n | 'is_false';\n\n/**\n * Email template reference (by slug) or inline content\n */\nexport type EmailContent =\n | { template: string }\n | { subject: string; body: string };\n\n/**\n * SMS template reference or inline message\n */\nexport type SmsContent = { template: string } | { message: string };\n\n/**\n * Configuration for send_email step\n */\nexport interface SendEmailStepConfig {\n /** Template slug or inline content */\n template?: string;\n subject?: string;\n body?: string;\n /** Override sender address */\n from?: string;\n /** Override sender name */\n fromName?: string;\n /** Override reply-to address */\n replyTo?: string;\n}\n\n/**\n * Configuration for send_sms step\n */\nexport interface SendSmsStepConfig {\n /** Template slug or inline message */\n template?: string;\n message?: string;\n /** Override sender ID */\n senderId?: string;\n}\n\n/**\n * Configuration for delay step (user-facing)\n */\nexport interface DelayStepConfig extends DurationConfig {}\n\n/**\n * Configuration for delay step (internal/DB format)\n */\nexport interface DelayStepDbConfig {\n /** Delay amount */\n amount: number;\n /** Delay unit */\n unit: 'minutes' | 'hours' | 'days' | 'weeks';\n}\n\n/**\n * Configuration for condition step\n */\nexport interface ConditionStepConfig {\n /** Field to evaluate (e.g., 'contact.email', 'contact.hasActivated') */\n field: string;\n /** Comparison operator */\n operator: ConditionOperator;\n /** Value to compare against (not used for is_set, is_not_set, is_true, is_false) */\n value?: unknown;\n /** Branches for yes/no outcomes */\n branches: {\n yes?: StepDefinition[];\n no?: StepDefinition[];\n };\n}\n\n/**\n * Configuration for wait_for_event step (user-facing)\n */\nexport interface WaitForEventStepConfig {\n /** Event name to wait for */\n eventName: string;\n /** Timeout duration (optional) - will be converted to timeoutSeconds */\n timeout?: DurationConfig;\n}\n\n/**\n * Configuration for wait_for_event step (internal/DB format)\n */\nexport interface WaitForEventStepDbConfig {\n /** Event name to wait for */\n eventName: string;\n /** Timeout in seconds */\n timeoutSeconds?: number;\n}\n\n/**\n * Configuration for wait_for_email_engagement step (user-facing)\n */\nexport interface WaitForEmailEngagementStepConfig {\n /** ID of the email step to track */\n emailStepId: string;\n /** Type of engagement to wait for */\n engagementType: 'opened' | 'clicked';\n /** Timeout duration (optional) - will be converted to timeoutSeconds */\n timeout?: DurationConfig;\n}\n\n/**\n * Configuration for wait_for_email_engagement step (internal/DB format)\n */\nexport interface WaitForEmailEngagementStepDbConfig {\n /** Timeout in seconds */\n timeoutSeconds?: number;\n}\n\n/**\n * Configuration for update_contact step\n */\nexport interface UpdateContactStepConfig {\n /** Field updates to apply */\n updates: Array<{\n field: string;\n operation: 'set' | 'increment' | 'decrement' | 'append' | 'remove';\n value?: unknown;\n }>;\n}\n\n/**\n * Configuration for webhook step\n */\nexport interface WebhookStepConfig {\n /** Webhook URL */\n url: string;\n /** HTTP method (default: POST) */\n method?: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';\n /** HTTP headers */\n headers?: Record<string, string>;\n /** Request body (for POST/PUT/PATCH) */\n body?: Record<string, unknown>;\n}\n\n/**\n * Configuration for subscribe/unsubscribe_topic step\n */\nexport interface TopicStepConfig {\n /** Topic ID to subscribe to or unsubscribe from */\n topicId: string;\n /** Channel for the subscription */\n channel?: 'email' | 'sms';\n}\n\n/**\n * Configuration for exit step\n */\nexport interface ExitStepConfig {\n /** Optional reason for exiting */\n reason?: string;\n /** Mark execution as completed, cancelled, or failed */\n markAs?: 'completed' | 'cancelled' | 'failed';\n}\n\n/**\n * A step in the workflow definition\n */\nexport interface StepDefinition {\n /** Unique step identifier (used for transitions and references) */\n id: string;\n /** Step type */\n type: WorkflowStepType;\n /** Optional display name (defaults to type if not provided) */\n name?: string;\n /** Step-specific configuration */\n config: StepConfig;\n /** Branches for condition steps */\n branches?: {\n yes?: StepDefinition[];\n no?: StepDefinition[];\n };\n}\n\n/**\n * Union of all step configurations (internal/DB format)\n * This is the format stored in the database and used by the execution engine.\n */\nexport type StepConfig =\n | ({ type: 'send_email' } & SendEmailStepConfig)\n | ({ type: 'send_sms' } & SendSmsStepConfig)\n | ({ type: 'delay' } & DelayStepDbConfig)\n | ({ type: 'condition' } & Omit<ConditionStepConfig, 'branches'>)\n | ({ type: 'wait_for_event' } & WaitForEventStepDbConfig)\n | ({ type: 'wait_for_email_engagement' } & WaitForEmailEngagementStepDbConfig)\n | ({ type: 'update_contact' } & UpdateContactStepConfig)\n | ({ type: 'webhook' } & WebhookStepConfig)\n | ({ type: 'subscribe_topic' } & TopicStepConfig)\n | ({ type: 'unsubscribe_topic' } & TopicStepConfig)\n | ({ type: 'exit' } & ExitStepConfig);\n\n// ═══════════════════════════════════════════════════════════════════════════\n// WORKFLOW SETTINGS\n// ═══════════════════════════════════════════════════════════════════════════\n\n/**\n * Workflow execution settings\n */\nexport interface WorkflowSettings {\n /** Allow the same contact to re-enter the workflow if they trigger it again */\n allowReentry?: boolean;\n\n /** Minimum seconds between re-entries for the same contact (only used if allowReentry is true) */\n reentryDelaySeconds?: number;\n\n /** Maximum concurrent executions allowed for this workflow */\n maxConcurrentExecutions?: number;\n\n /** Cooldown period in seconds before a contact can trigger this workflow again */\n contactCooldownSeconds?: number;\n}\n\n// ═══════════════════════════════════════════════════════════════════════════\n// WORKFLOW DEFINITION\n// ═══════════════════════════════════════════════════════════════════════════\n\n/**\n * Complete workflow definition\n */\nexport interface WorkflowDefinition {\n /** Display name for the workflow */\n name: string;\n\n /** Optional description */\n description?: string;\n\n /** What triggers this workflow */\n trigger: TriggerDefinition;\n\n /** Steps in the workflow (executed sequentially unless branched) */\n steps: StepDefinition[];\n\n /** Execution settings */\n settings?: WorkflowSettings;\n\n /** Optional: associate workflow with a topic for subscription checks */\n topicId?: string;\n\n /** Default sender settings (can be overridden per step) */\n defaults?: {\n from?: string;\n fromName?: string;\n replyTo?: string;\n senderId?: string;\n };\n}\n\n// ═══════════════════════════════════════════════════════════════════════════\n// DEFINE WORKFLOW\n// ═══════════════════════════════════════════════════════════════════════════\n\n/**\n * Define an email automation workflow.\n * Use this in `wraps/workflows/*.ts` for full TypeScript intellisense.\n *\n * @example\n * ```ts\n * import { defineWorkflow, sendEmail, delay, exit } from '@wraps.dev/client';\n *\n * export default defineWorkflow({\n * name: 'Welcome Sequence',\n * trigger: { type: 'contact_created' },\n * steps: [\n * sendEmail('welcome', { template: 'welcome' }),\n * delay('wait-1-day', { days: 1 }),\n * sendEmail('tips', { template: 'getting-started-tips' }),\n * ],\n * });\n * ```\n */\nexport function defineWorkflow(\n definition: WorkflowDefinition\n): WorkflowDefinition {\n return definition;\n}\n","/**\n * Workflow Step Helper Functions\n *\n * Ergonomic helpers for defining workflow steps declaratively.\n * These functions return step definitions that can be used in `defineWorkflow()`.\n */\n\nimport type {\n ConditionOperator,\n ConditionStepConfig,\n DelayStepConfig,\n DurationConfig,\n ExitStepConfig,\n SendEmailStepConfig,\n SendSmsStepConfig,\n StepDefinition,\n TopicStepConfig,\n UpdateContactStepConfig,\n WaitForEmailEngagementStepConfig,\n WaitForEventStepConfig,\n WebhookStepConfig,\n} from './workflow';\n\n// ═══════════════════════════════════════════════════════════════════════════\n// INTERNAL HELPERS\n// ═══════════════════════════════════════════════════════════════════════════\n\n/**\n * Convert DurationConfig to delay step config (amount + unit)\n */\nfunction normalizeDuration(duration: DurationConfig): {\n amount: number;\n unit: 'minutes' | 'hours' | 'days' | 'weeks';\n} {\n if (duration.days !== undefined) {\n return { amount: duration.days, unit: 'days' };\n }\n if (duration.hours !== undefined) {\n return { amount: duration.hours, unit: 'hours' };\n }\n if (duration.minutes !== undefined) {\n return { amount: duration.minutes, unit: 'minutes' };\n }\n // Default to 1 hour if nothing specified\n return { amount: 1, unit: 'hours' };\n}\n\n/**\n * Convert DurationConfig to seconds for timeout values\n */\nfunction durationToSeconds(duration?: DurationConfig): number | undefined {\n if (!duration) return undefined;\n\n let seconds = 0;\n if (duration.days) seconds += duration.days * 24 * 60 * 60;\n if (duration.hours) seconds += duration.hours * 60 * 60;\n if (duration.minutes) seconds += duration.minutes * 60;\n\n return seconds > 0 ? seconds : undefined;\n}\n\n// ═══════════════════════════════════════════════════════════════════════════\n// CHANNEL STEPS\n// ═══════════════════════════════════════════════════════════════════════════\n\n/**\n * Send an email using a template or inline content.\n *\n * @example\n * ```ts\n * // Using a template\n * sendEmail('welcome', { template: 'welcome-email' })\n *\n * // With overrides\n * sendEmail('promo', {\n * template: 'promo-email',\n * from: 'marketing@example.com',\n * fromName: 'Marketing Team',\n * })\n * ```\n */\nexport function sendEmail(\n id: string,\n config: SendEmailStepConfig & { name?: string }\n): StepDefinition {\n const { name, ...stepConfig } = config;\n return {\n id,\n type: 'send_email',\n name: name ?? `Send email: ${config.template || 'custom'}`,\n config: { type: 'send_email', ...stepConfig },\n };\n}\n\n/**\n * Send an SMS using a template or inline message.\n *\n * @example\n * ```ts\n * // Using a template\n * sendSms('reminder', { template: 'appointment-reminder' })\n *\n * // Inline message\n * sendSms('otp', { message: 'Your code is {{otp}}' })\n * ```\n */\nexport function sendSms(\n id: string,\n config: SendSmsStepConfig & { name?: string }\n): StepDefinition {\n const { name, ...stepConfig } = config;\n return {\n id,\n type: 'send_sms',\n name: name ?? `Send SMS: ${config.template || 'custom'}`,\n config: { type: 'send_sms', ...stepConfig },\n };\n}\n\n// ═══════════════════════════════════════════════════════════════════════════\n// CONTROL FLOW STEPS\n// ═══════════════════════════════════════════════════════════════════════════\n\n/**\n * Wait for a specified duration before continuing.\n *\n * @example\n * ```ts\n * delay('wait-1-day', { days: 1 })\n * delay('wait-2-hours', { hours: 2 })\n * delay('wait-30-min', { minutes: 30 })\n * ```\n */\nexport function delay(\n id: string,\n duration: DurationConfig & { name?: string }\n): StepDefinition {\n const { name, ...durationConfig } = duration;\n const normalized = normalizeDuration(durationConfig);\n return {\n id,\n type: 'delay',\n name: name ?? `Wait ${normalized.amount} ${normalized.unit}`,\n config: { type: 'delay', ...normalized },\n };\n}\n\n/**\n * Branch the workflow based on a condition.\n *\n * @example\n * ```ts\n * condition('check-activated', {\n * field: 'contact.hasActivated',\n * operator: 'equals',\n * value: true,\n * branches: {\n * yes: [exit('already-active')],\n * no: [sendEmail('activation-reminder', { template: 'activate' })],\n * },\n * })\n * ```\n */\nexport function condition(\n id: string,\n config: ConditionStepConfig & { name?: string }\n): StepDefinition {\n const { branches, name, ...conditionConfig } = config;\n return {\n id,\n type: 'condition',\n name: name ?? `Check: ${config.field} ${config.operator}`,\n config: { type: 'condition', ...conditionConfig },\n branches,\n };\n}\n\n/**\n * Wait for a specific event before continuing.\n *\n * @example\n * ```ts\n * waitForEvent('wait-for-purchase', {\n * eventName: 'purchase_completed',\n * timeout: { days: 7 },\n * })\n * ```\n */\nexport function waitForEvent(\n id: string,\n config: WaitForEventStepConfig & { name?: string }\n): StepDefinition {\n const { name, timeout, ...eventConfig } = config;\n return {\n id,\n type: 'wait_for_event',\n name: name ?? `Wait for: ${config.eventName}`,\n config: {\n type: 'wait_for_event',\n eventName: eventConfig.eventName,\n timeoutSeconds: durationToSeconds(timeout),\n },\n };\n}\n\n/**\n * Wait for engagement with a previous email step.\n *\n * @example\n * ```ts\n * waitForEmailEngagement('wait-for-open', {\n * emailStepId: 'welcome',\n * engagementType: 'opened',\n * timeout: { days: 3 },\n * })\n * ```\n */\nexport function waitForEmailEngagement(\n id: string,\n config: WaitForEmailEngagementStepConfig & { name?: string }\n): StepDefinition {\n const { name, timeout, emailStepId, engagementType } = config;\n return {\n id,\n type: 'wait_for_email_engagement',\n name:\n name ?? `Wait for email ${engagementType}: ${emailStepId}`,\n config: {\n type: 'wait_for_email_engagement',\n timeoutSeconds: durationToSeconds(timeout),\n },\n };\n}\n\n/**\n * Exit the workflow.\n *\n * @example\n * ```ts\n * exit('completed')\n * exit('cancelled', { reason: 'User unsubscribed', markAs: 'cancelled' })\n * ```\n */\nexport function exit(\n id: string,\n config?: ExitStepConfig & { name?: string }\n): StepDefinition {\n const { name, ...exitConfig } = config ?? {};\n return {\n id,\n type: 'exit',\n name: name ?? 'Exit',\n config: { type: 'exit', ...exitConfig },\n };\n}\n\n// ═══════════════════════════════════════════════════════════════════════════\n// ACTION STEPS\n// ═══════════════════════════════════════════════════════════════════════════\n\n/**\n * Update contact fields.\n *\n * @example\n * ```ts\n * updateContact('mark-welcomed', {\n * updates: [\n * { field: 'welcomeEmailSent', operation: 'set', value: true },\n * { field: 'emailCount', operation: 'increment', value: 1 },\n * ],\n * })\n * ```\n */\nexport function updateContact(\n id: string,\n config: Omit<UpdateContactStepConfig, 'type'> & { name?: string }\n): StepDefinition {\n const { name, ...updateConfig } = config;\n return {\n id,\n type: 'update_contact',\n name: name ?? 'Update contact',\n config: { type: 'update_contact', ...updateConfig },\n };\n}\n\n/**\n * Subscribe a contact to a topic.\n *\n * @example\n * ```ts\n * subscribeTopic('subscribe-newsletter', {\n * topicId: 'newsletter',\n * channel: 'email',\n * })\n * ```\n */\nexport function subscribeTopic(\n id: string,\n config: Omit<TopicStepConfig, 'type'> & { name?: string }\n): StepDefinition {\n const { name, ...topicConfig } = config;\n return {\n id,\n type: 'subscribe_topic',\n name: name ?? `Subscribe to topic: ${config.topicId}`,\n config: { type: 'subscribe_topic', ...topicConfig },\n };\n}\n\n/**\n * Unsubscribe a contact from a topic.\n *\n * @example\n * ```ts\n * unsubscribeTopic('unsubscribe-promo', {\n * topicId: 'promotions',\n * channel: 'email',\n * })\n * ```\n */\nexport function unsubscribeTopic(\n id: string,\n config: Omit<TopicStepConfig, 'type'> & { name?: string }\n): StepDefinition {\n const { name, ...topicConfig } = config;\n return {\n id,\n type: 'unsubscribe_topic',\n name: name ?? `Unsubscribe from topic: ${config.topicId}`,\n config: { type: 'unsubscribe_topic', ...topicConfig },\n };\n}\n\n/**\n * Call an external webhook.\n *\n * @example\n * ```ts\n * webhook('notify-slack', {\n * url: 'https://hooks.slack.com/services/...',\n * method: 'POST',\n * body: { text: 'New user signed up!' },\n * })\n * ```\n */\nexport function webhook(\n id: string,\n config: Omit<WebhookStepConfig, 'type'> & { name?: string }\n): StepDefinition {\n const { name, ...webhookConfig } = config;\n return {\n id,\n type: 'webhook',\n name: name ?? `Webhook: ${config.url}`,\n config: { type: 'webhook', method: 'POST', ...webhookConfig },\n };\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wraps.dev/client",
3
- "version": "0.5.0",
3
+ "version": "0.6.0",
4
4
  "description": "Type-safe API client for Wraps Platform",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",