@myapihq/sdk 2.4.1 → 2.4.2

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/src/webhook.ts DELETED
@@ -1,88 +0,0 @@
1
- import { request } from './client';
2
- import { WEBHOOK_BASE as BASE_URL } from './config';
3
- import type { Exposes } from './exposes';
4
-
5
- export const EXPOSES: Exposes = [
6
- 'POST /webhook/orgs/{org_id}/endpoints',
7
- 'GET /webhook/orgs/{org_id}/endpoints',
8
- 'PATCH /webhook/orgs/{org_id}/endpoints/{endpoint_id}',
9
- 'DELETE /webhook/orgs/{org_id}/endpoints/{endpoint_id}',
10
- 'GET /webhook/orgs/{org_id}/deliveries/{delivery_id}',
11
- ];
12
-
13
- export interface WebhookEndpoint {
14
- id: string;
15
- org_id: string;
16
- name: string;
17
- description?: string;
18
- slug: string;
19
- url: string;
20
- // Dot-path into the webhook body whose value (an email) gets ingested
21
- // into CRM as a contact + webhook_received event on each delivery.
22
- // Default 'email' (top-level). Empty string disables CRM ingest.
23
- crm_email_path?: string;
24
- // URL every inbound delivery is forwarded to (POST, async, best-effort).
25
- // Empty/absent when forwarding is disabled. Backend webhook/endpoints.go.
26
- forward_url?: string;
27
- created_at: string;
28
- }
29
-
30
- export interface Delivery {
31
- id: string;
32
- endpoint_id: string;
33
- payload: unknown;
34
- received_at: string;
35
- // Forwarding outcome for this delivery, present only when the endpoint has
36
- // a forward_url configured (backend webhook/endpoints.go). forward_status
37
- // is the HTTP status of the forward POST; last_forward_error carries the
38
- // failure message when the forward attempt errored.
39
- forward_status?: number;
40
- last_forward_at?: string;
41
- last_forward_error?: string;
42
- }
43
-
44
- export interface CreateEndpointOptions {
45
- description?: string;
46
- // CRM auto-ingest config. Empty string disables; undefined defaults to
47
- // 'email' (top-level). For nested shapes pass the dot-path (e.g.
48
- // 'data.object.customer_email' for Stripe, 'sender.email' for GitHub).
49
- crm_email_path?: string;
50
- // Backend (2026-05-15): optional URL to forward every inbound delivery to
51
- // (POST, async, best-effort). Headers `X-MyAPI-Webhook-Endpoint-Id` and
52
- // `X-MyAPI-Webhook-Delivery-Id` are attached. Use http:// or https://.
53
- // Empty string disables forwarding.
54
- forward_url?: string;
55
- }
56
-
57
- // All fields optional — only those passed are mutated. Mirrors the backend
58
- // PATCH /webhook/orgs/{org_id}/endpoints/{id} contract (slug is immutable).
59
- export interface UpdateEndpointPayload {
60
- name?: string;
61
- description?: string;
62
- crm_email_path?: string;
63
- forward_url?: string;
64
- }
65
-
66
- export async function createEndpoint(apiKey: string, orgId: string, name: string, opts: CreateEndpointOptions = {}): Promise<WebhookEndpoint> {
67
- const body: Record<string, unknown> = { name };
68
- if (opts.description !== undefined) body.description = opts.description;
69
- if (opts.crm_email_path !== undefined) body.crm_email_path = opts.crm_email_path;
70
- if (opts.forward_url !== undefined) body.forward_url = opts.forward_url;
71
- return request('POST', `${BASE_URL}/webhook/orgs/${encodeURIComponent(orgId)}/endpoints`, apiKey, body);
72
- }
73
-
74
- export async function updateEndpoint(apiKey: string, orgId: string, endpointId: string, payload: UpdateEndpointPayload): Promise<WebhookEndpoint> {
75
- return request('PATCH', `${BASE_URL}/webhook/orgs/${encodeURIComponent(orgId)}/endpoints/${encodeURIComponent(endpointId)}`, apiKey, payload);
76
- }
77
-
78
- export async function listEndpoints(apiKey: string, orgId: string): Promise<WebhookEndpoint[]> {
79
- return request('GET', `${BASE_URL}/webhook/orgs/${encodeURIComponent(orgId)}/endpoints`, apiKey);
80
- }
81
-
82
- export async function deleteEndpoint(apiKey: string, orgId: string, endpointId: string): Promise<void> {
83
- return request('DELETE', `${BASE_URL}/webhook/orgs/${encodeURIComponent(orgId)}/endpoints/${encodeURIComponent(endpointId)}`, apiKey);
84
- }
85
-
86
- export async function getDelivery(apiKey: string, orgId: string, deliveryId: string): Promise<Delivery> {
87
- return request('GET', `${BASE_URL}/webhook/orgs/${encodeURIComponent(orgId)}/deliveries/${encodeURIComponent(deliveryId)}`, apiKey);
88
- }
package/src/workflow.ts DELETED
@@ -1,162 +0,0 @@
1
- import { request, requestPage } from './client';
2
- import { WORKFLOW_BASE as BASE_URL } from './config';
3
- import type { Exposes } from './exposes';
4
-
5
- export const EXPOSES: Exposes = [
6
- 'POST /workflow/orgs/{org_id}/workflows',
7
- 'GET /workflow/orgs/{org_id}/workflows',
8
- 'GET /workflow/orgs/{org_id}/workflows/{workflow_id}',
9
- 'PATCH /workflow/orgs/{org_id}/workflows/{workflow_id}',
10
- 'DELETE /workflow/orgs/{org_id}/workflows/{workflow_id}',
11
- 'POST /workflow/orgs/{org_id}/workflows/{workflow_id}/enable',
12
- 'POST /workflow/orgs/{org_id}/workflows/{workflow_id}/disable',
13
- 'GET /workflow/orgs/{org_id}/workflows/{workflow_id}/runs',
14
- 'GET /workflow/orgs/{org_id}/runs/{run_id}',
15
- ];
16
-
17
-
18
-
19
- /**
20
- * A single step in a workflow.
21
- *
22
- * `to`, `subject`, `text`, and `html` (or the resolved `template_id` body) all support
23
- * `{{payload.field}}` and `{{payload.nested.field}}` interpolation, evaluated at run time
24
- * against the inbound webhook body.
25
- *
26
- * For `send_email`, `from` must be an activated mailbox on a domain assigned to the account.
27
- * Each `send_email` execution is billed 1¢ and tracking pixels + click redirectors are
28
- * automatically injected into the HTML body.
29
- */
30
- export type WorkflowStep =
31
- | { type: 'send_email'; from: string; to: string; subject: string; template_id?: string; text?: string; html?: string }
32
- | { type: 'slack_message'; webhook_url: string; text: string }
33
- // Backend (2026-05-15): `http_request` step is now accepted (alias: `http`).
34
- // POSTs (or other method) to `url` with the inbound payload; supports
35
- // template substitution in url/body the same way email steps do.
36
- | { type: 'http_request' | 'http'; url: string; method?: 'GET' | 'POST' | 'PATCH' | 'PUT' | 'DELETE'; body?: string; headers?: Record<string, string> }
37
- // `enqueue_job` (alias: `enqueue`) hands durable work to my-queue-api —
38
- // the step enqueues a job on `queue` carrying `payload` (template
39
- // substitution supported, same as email/http steps). The workflow stays
40
- // the trigger layer; the queue owns retry/durability. Backend: pending —
41
- // see docs/cross-repo-prompts/backend-orchestration-composition.md.
42
- | { type: 'enqueue_job' | 'enqueue'; queue: string; payload?: string; dedup_key?: string; delay_seconds?: number };
43
-
44
- export interface Workflow {
45
- id: string;
46
- org_id: string;
47
- name: string;
48
- trigger_type: string;
49
- trigger_config: { endpoint_id: string };
50
- steps: WorkflowStep[];
51
- enabled: boolean;
52
- created_at: string;
53
- updated_at: string;
54
- }
55
- export interface WorkflowRun {
56
- id: string;
57
- workflow_id: string;
58
- trigger_payload: unknown;
59
- status: 'pending' | 'running' | 'completed' | 'failed';
60
- error?: string;
61
- attempt: number;
62
- started_at?: string;
63
- finished_at?: string;
64
- created_at: string;
65
- // Per-step output records, populated by GetRun only (backend crud.go:639
66
- // returns step_outputs; ListRuns omits them). Empty array when none.
67
- step_outputs?: unknown[];
68
- }
69
-
70
- export interface ListRunsOptions {
71
- limit?: number; // 1-500, default 100 server-side
72
- cursor?: string; // last run id from the prior page (keyset)
73
- }
74
-
75
- export interface WorkflowRunsPage {
76
- runs: WorkflowRun[];
77
- next_cursor?: string;
78
- has_more?: boolean;
79
- }
80
-
81
- // Local URL-shape check on http_request steps. Same shape as the SSRF
82
- // audit's scheme allowlist on webhook.forward_url and queue.consumer_url —
83
- // this is *UX defense*, not security: the backend MUST also validate
84
- // (which it does, via the same middleware) — see
85
- // docs/cross-repo-prompts/backend-workflow-step-validation.md.
86
- // Catches javascript:, file:, gopher:, data:, and whitespace/null-byte
87
- // hosts at agent typo-fix latency instead of at "why didn't my workflow
88
- // fire" investigation latency.
89
- function validateSteps(steps: WorkflowStep[]): void {
90
- for (let i = 0; i < steps.length; i++) {
91
- const s = steps[i];
92
- if (s.type === 'http_request' || s.type === 'http') {
93
- let parsed: URL;
94
- try { parsed = new URL(s.url); }
95
- catch {
96
- throw new Error(`step ${i} (${s.type}): "url" is not a valid URL — got ${JSON.stringify(s.url)}.`);
97
- }
98
- if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') {
99
- throw new Error(`step ${i} (${s.type}): "url" must use http:// or https:// scheme — got "${parsed.protocol}" in ${JSON.stringify(s.url)}.`);
100
- }
101
- }
102
- }
103
- }
104
-
105
- export async function createWorkflow(apiKey: string, orgId: string, payload: {
106
- name: string;
107
- trigger_config: { endpoint_id: string };
108
- steps: WorkflowStep[];
109
- }): Promise<Workflow> {
110
- validateSteps(payload.steps);
111
- return request('POST', `${BASE_URL}/workflow/orgs/${encodeURIComponent(orgId)}/workflows`, apiKey, payload);
112
- }
113
-
114
- export async function listWorkflows(apiKey: string, orgId: string): Promise<Workflow[]> {
115
- return request('GET', `${BASE_URL}/workflow/orgs/${encodeURIComponent(orgId)}/workflows`, apiKey);
116
- }
117
-
118
- export async function getWorkflow(apiKey: string, orgId: string, workflowId: string): Promise<Workflow> {
119
- return request('GET', `${BASE_URL}/workflow/orgs/${encodeURIComponent(orgId)}/workflows/${encodeURIComponent(workflowId)}`, apiKey);
120
- }
121
-
122
- export async function updateWorkflow(apiKey: string, orgId: string, workflowId: string, payload: { name?: string; trigger_config?: { endpoint_id: string }; steps?: WorkflowStep[] }): Promise<Workflow> {
123
- if (payload.steps) validateSteps(payload.steps);
124
- return request('PATCH', `${BASE_URL}/workflow/orgs/${encodeURIComponent(orgId)}/workflows/${encodeURIComponent(workflowId)}`, apiKey, payload);
125
- }
126
-
127
- export async function enableWorkflow(apiKey: string, orgId: string, workflowId: string): Promise<void> {
128
- return request('POST', `${BASE_URL}/workflow/orgs/${encodeURIComponent(orgId)}/workflows/${encodeURIComponent(workflowId)}/enable`, apiKey);
129
- }
130
-
131
- export async function disableWorkflow(apiKey: string, orgId: string, workflowId: string): Promise<void> {
132
- return request('POST', `${BASE_URL}/workflow/orgs/${encodeURIComponent(orgId)}/workflows/${encodeURIComponent(workflowId)}/disable`, apiKey);
133
- }
134
-
135
- export async function deleteWorkflow(apiKey: string, orgId: string, workflowId: string): Promise<void> {
136
- return request('DELETE', `${BASE_URL}/workflow/orgs/${encodeURIComponent(orgId)}/workflows/${encodeURIComponent(workflowId)}`, apiKey);
137
- }
138
-
139
- // listWorkflowRuns returns recent runs newest-first. The backend wraps this
140
- // in a keyset-pagination envelope (limit 1-500 + cursor), so we use
141
- // requestPage to preserve next_cursor — a plain `request` would drop it.
142
- export async function listWorkflowRuns(
143
- apiKey: string,
144
- orgId: string,
145
- workflowId: string,
146
- opts: ListRunsOptions = {},
147
- ): Promise<WorkflowRunsPage> {
148
- const qs = new URLSearchParams();
149
- if (opts.limit !== undefined) qs.set('limit', String(opts.limit));
150
- if (opts.cursor) qs.set('cursor', opts.cursor);
151
- const query = qs.toString() ? `?${qs.toString()}` : '';
152
- const page = await requestPage<WorkflowRun>(
153
- 'GET',
154
- `${BASE_URL}/workflow/orgs/${encodeURIComponent(orgId)}/workflows/${encodeURIComponent(workflowId)}/runs${query}`,
155
- apiKey,
156
- );
157
- return { runs: page.data, next_cursor: page.next_cursor, has_more: page.has_more };
158
- }
159
-
160
- export async function getWorkflowRun(apiKey: string, orgId: string, runId: string): Promise<WorkflowRun> {
161
- return request('GET', `${BASE_URL}/workflow/orgs/${encodeURIComponent(orgId)}/runs/${encodeURIComponent(runId)}`, apiKey);
162
- }
package/tsconfig.json DELETED
@@ -1,14 +0,0 @@
1
- {
2
- "compilerOptions": {
3
- "target": "ES2022",
4
- "module": "NodeNext",
5
- "moduleResolution": "NodeNext",
6
- "declaration": true,
7
- "outDir": "./dist",
8
- "strict": true,
9
- "esModuleInterop": true,
10
- "skipLibCheck": true,
11
- "forceConsistentCasingInFileNames": true
12
- },
13
- "include": ["src/**/*"]
14
- }