@hostwebhook/node 1.1.0 → 1.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +39 -0
- package/dist/index.d.mts +31 -8
- package/dist/index.d.ts +31 -8
- package/dist/index.js +76 -4
- package/dist/index.mjs +76 -4
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -102,6 +102,35 @@ const hw = new HostWebhook({ token: 'your_ingress_token' });
|
|
|
102
102
|
const { eventId } = await hw.send({ event: 'order.created', orderId: '123' });
|
|
103
103
|
```
|
|
104
104
|
|
|
105
|
+
### Wait for pipeline result (SSE streaming)
|
|
106
|
+
|
|
107
|
+
Use `waitForResult` to wait for the full pipeline to complete. The SDK opens an SSE stream behind the scenes and returns the result with all pipeline steps.
|
|
108
|
+
|
|
109
|
+
```ts
|
|
110
|
+
const result = await hw.send(
|
|
111
|
+
{ event: 'order.created', orderId: '123' },
|
|
112
|
+
{ waitForResult: true },
|
|
113
|
+
);
|
|
114
|
+
|
|
115
|
+
console.log(result.syncStatus); // 200 = delivered, 422 = validation failed, 502 = failed, 408 = timeout
|
|
116
|
+
console.log(result.steps); // array of pipeline steps with nodeType, status, durationMs
|
|
117
|
+
console.log(result.response); // response body from target URL
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
Works with any endpoint regardless of its response mode. Max wait: ~120 seconds.
|
|
121
|
+
|
|
122
|
+
### Deduplication detection
|
|
123
|
+
|
|
124
|
+
When an event is deduplicated, the response includes `deduplicated: true`:
|
|
125
|
+
|
|
126
|
+
```ts
|
|
127
|
+
const result = await hw.send({ event: 'order.created', orderId: '123' });
|
|
128
|
+
|
|
129
|
+
if (result.deduplicated) {
|
|
130
|
+
console.log('Duplicate! Original event:', result.originalEventId);
|
|
131
|
+
}
|
|
132
|
+
```
|
|
133
|
+
|
|
105
134
|
### Batch
|
|
106
135
|
|
|
107
136
|
```ts
|
|
@@ -129,9 +158,19 @@ const { eventId } = await send(
|
|
|
129
158
|
| `token` | `string` | *required* | Endpoint ingress token |
|
|
130
159
|
| `baseUrl` | `string` | `https://api.hostwebhook.com` | API base URL |
|
|
131
160
|
| `signingSecret` | `string` | — | Signs outgoing requests with HMAC-SHA256 |
|
|
161
|
+
| `signature` | `StaticSignature` | — | Static secret signature (alternative to HMAC) |
|
|
132
162
|
| `defaultHeaders` | `Record<string, string>` | — | Headers added to every request |
|
|
133
163
|
| `timeoutMs` | `number` | `10000` | Request timeout in ms |
|
|
134
164
|
|
|
165
|
+
### SendOptions
|
|
166
|
+
|
|
167
|
+
| Option | Type | Default | Description |
|
|
168
|
+
|--------|------|---------|-------------|
|
|
169
|
+
| `headers` | `Record<string, string>` | — | Per-request headers |
|
|
170
|
+
| `contentType` | `string` | `application/json` | Override content type |
|
|
171
|
+
| `rawBody` | `string \| Buffer` | — | Send raw body instead of JSON |
|
|
172
|
+
| `waitForResult` | `boolean` | `false` | Wait for pipeline result via SSE stream |
|
|
173
|
+
|
|
135
174
|
## Error Handling
|
|
136
175
|
|
|
137
176
|
```ts
|
package/dist/index.d.mts
CHANGED
|
@@ -184,6 +184,18 @@ interface HostWebhookConfig {
|
|
|
184
184
|
/** Request timeout in milliseconds. Default: 10000 (10s). */
|
|
185
185
|
timeoutMs?: number;
|
|
186
186
|
}
|
|
187
|
+
/** A single pipeline execution step received via SSE stream. */
|
|
188
|
+
interface PipelineStep {
|
|
189
|
+
eventId?: string;
|
|
190
|
+
nodeType: string;
|
|
191
|
+
nodeId: string;
|
|
192
|
+
nodeName?: string;
|
|
193
|
+
status: 'running' | 'success' | 'error' | 'blocked';
|
|
194
|
+
statusCode?: number;
|
|
195
|
+
durationMs?: number;
|
|
196
|
+
error?: string;
|
|
197
|
+
lastPayload?: Record<string, unknown>;
|
|
198
|
+
}
|
|
187
199
|
/** Options for a single send call. */
|
|
188
200
|
interface SendOptions {
|
|
189
201
|
/** Custom headers for this specific request (merged with defaultHeaders). */
|
|
@@ -195,25 +207,36 @@ interface SendOptions {
|
|
|
195
207
|
* When set, the `payload` parameter to `send()` is ignored.
|
|
196
208
|
*/
|
|
197
209
|
rawBody?: string | Buffer;
|
|
210
|
+
/**
|
|
211
|
+
* Wait for the full pipeline result via SSE streaming.
|
|
212
|
+
* The SDK will POST the payload, then open an SSE stream to receive
|
|
213
|
+
* pipeline steps and the final result. Returns when the pipeline completes.
|
|
214
|
+
* Timeout: ~125s (slightly above the server's 120s SSE timeout).
|
|
215
|
+
*/
|
|
216
|
+
waitForResult?: boolean;
|
|
198
217
|
}
|
|
199
218
|
/** Result returned after a successful send. */
|
|
200
219
|
interface SendResult {
|
|
201
220
|
/** The event ID assigned by HostWebhook. */
|
|
202
221
|
eventId: string;
|
|
203
|
-
/**
|
|
222
|
+
/** Short-lived token for SSE stream auth (returned by ingress, used internally by waitForResult). */
|
|
223
|
+
streamToken?: string;
|
|
224
|
+
/** Sync/stream: pipeline result status (200=delivered, 422=validation failed, 502=delivery failed, 408=timeout) */
|
|
204
225
|
syncStatus?: number;
|
|
205
|
-
/** Sync
|
|
226
|
+
/** Sync/stream: delivery status ('delivered') */
|
|
206
227
|
deliveryStatus?: string;
|
|
207
|
-
/** Sync
|
|
228
|
+
/** Sync/stream: HTTP status code from the target URL */
|
|
208
229
|
statusCode?: number;
|
|
209
|
-
/** Sync
|
|
230
|
+
/** Sync/stream: response body from the target URL (truncated to 4KB) */
|
|
210
231
|
response?: string;
|
|
211
|
-
/** Sync
|
|
232
|
+
/** Sync/stream: delivery latency in ms */
|
|
212
233
|
latencyMs?: number;
|
|
213
|
-
/** Sync
|
|
234
|
+
/** Sync/stream: error message if pipeline/delivery failed */
|
|
214
235
|
error?: string;
|
|
215
|
-
/** Sync
|
|
236
|
+
/** Sync/stream: validation error messages (schema validator) */
|
|
216
237
|
message?: string[];
|
|
238
|
+
/** SSE stream: pipeline execution steps (only when waitForResult is used) */
|
|
239
|
+
steps?: PipelineStep[];
|
|
217
240
|
/** Any additional fields from the sync response */
|
|
218
241
|
[key: string]: unknown;
|
|
219
242
|
}
|
|
@@ -269,4 +292,4 @@ declare class HostWebhook {
|
|
|
269
292
|
*/
|
|
270
293
|
declare function send(config: HostWebhookConfig, payload: Record<string, unknown>, options?: SendOptions): Promise<SendResult>;
|
|
271
294
|
|
|
272
|
-
export { HostWebhook, type HostWebhookConfig, SendError, type SendOptions, type SendResult, type StaticSignature, VerificationError, type VerifyOptions, type WebhookHeaders, createNestGuard, expressMiddleware, fastifyHook, parseHeaders, send, verify };
|
|
295
|
+
export { HostWebhook, type HostWebhookConfig, type PipelineStep, SendError, type SendOptions, type SendResult, type StaticSignature, VerificationError, type VerifyOptions, type WebhookHeaders, createNestGuard, expressMiddleware, fastifyHook, parseHeaders, send, verify };
|
package/dist/index.d.ts
CHANGED
|
@@ -184,6 +184,18 @@ interface HostWebhookConfig {
|
|
|
184
184
|
/** Request timeout in milliseconds. Default: 10000 (10s). */
|
|
185
185
|
timeoutMs?: number;
|
|
186
186
|
}
|
|
187
|
+
/** A single pipeline execution step received via SSE stream. */
|
|
188
|
+
interface PipelineStep {
|
|
189
|
+
eventId?: string;
|
|
190
|
+
nodeType: string;
|
|
191
|
+
nodeId: string;
|
|
192
|
+
nodeName?: string;
|
|
193
|
+
status: 'running' | 'success' | 'error' | 'blocked';
|
|
194
|
+
statusCode?: number;
|
|
195
|
+
durationMs?: number;
|
|
196
|
+
error?: string;
|
|
197
|
+
lastPayload?: Record<string, unknown>;
|
|
198
|
+
}
|
|
187
199
|
/** Options for a single send call. */
|
|
188
200
|
interface SendOptions {
|
|
189
201
|
/** Custom headers for this specific request (merged with defaultHeaders). */
|
|
@@ -195,25 +207,36 @@ interface SendOptions {
|
|
|
195
207
|
* When set, the `payload` parameter to `send()` is ignored.
|
|
196
208
|
*/
|
|
197
209
|
rawBody?: string | Buffer;
|
|
210
|
+
/**
|
|
211
|
+
* Wait for the full pipeline result via SSE streaming.
|
|
212
|
+
* The SDK will POST the payload, then open an SSE stream to receive
|
|
213
|
+
* pipeline steps and the final result. Returns when the pipeline completes.
|
|
214
|
+
* Timeout: ~125s (slightly above the server's 120s SSE timeout).
|
|
215
|
+
*/
|
|
216
|
+
waitForResult?: boolean;
|
|
198
217
|
}
|
|
199
218
|
/** Result returned after a successful send. */
|
|
200
219
|
interface SendResult {
|
|
201
220
|
/** The event ID assigned by HostWebhook. */
|
|
202
221
|
eventId: string;
|
|
203
|
-
/**
|
|
222
|
+
/** Short-lived token for SSE stream auth (returned by ingress, used internally by waitForResult). */
|
|
223
|
+
streamToken?: string;
|
|
224
|
+
/** Sync/stream: pipeline result status (200=delivered, 422=validation failed, 502=delivery failed, 408=timeout) */
|
|
204
225
|
syncStatus?: number;
|
|
205
|
-
/** Sync
|
|
226
|
+
/** Sync/stream: delivery status ('delivered') */
|
|
206
227
|
deliveryStatus?: string;
|
|
207
|
-
/** Sync
|
|
228
|
+
/** Sync/stream: HTTP status code from the target URL */
|
|
208
229
|
statusCode?: number;
|
|
209
|
-
/** Sync
|
|
230
|
+
/** Sync/stream: response body from the target URL (truncated to 4KB) */
|
|
210
231
|
response?: string;
|
|
211
|
-
/** Sync
|
|
232
|
+
/** Sync/stream: delivery latency in ms */
|
|
212
233
|
latencyMs?: number;
|
|
213
|
-
/** Sync
|
|
234
|
+
/** Sync/stream: error message if pipeline/delivery failed */
|
|
214
235
|
error?: string;
|
|
215
|
-
/** Sync
|
|
236
|
+
/** Sync/stream: validation error messages (schema validator) */
|
|
216
237
|
message?: string[];
|
|
238
|
+
/** SSE stream: pipeline execution steps (only when waitForResult is used) */
|
|
239
|
+
steps?: PipelineStep[];
|
|
217
240
|
/** Any additional fields from the sync response */
|
|
218
241
|
[key: string]: unknown;
|
|
219
242
|
}
|
|
@@ -269,4 +292,4 @@ declare class HostWebhook {
|
|
|
269
292
|
*/
|
|
270
293
|
declare function send(config: HostWebhookConfig, payload: Record<string, unknown>, options?: SendOptions): Promise<SendResult>;
|
|
271
294
|
|
|
272
|
-
export { HostWebhook, type HostWebhookConfig, SendError, type SendOptions, type SendResult, type StaticSignature, VerificationError, type VerifyOptions, type WebhookHeaders, createNestGuard, expressMiddleware, fastifyHook, parseHeaders, send, verify };
|
|
295
|
+
export { HostWebhook, type HostWebhookConfig, type PipelineStep, SendError, type SendOptions, type SendResult, type StaticSignature, VerificationError, type VerifyOptions, type WebhookHeaders, createNestGuard, expressMiddleware, fastifyHook, parseHeaders, send, verify };
|
package/dist/index.js
CHANGED
|
@@ -23,6 +23,7 @@ var __accessCheck = (obj, member, msg) => member.has(obj) || __typeError("Cannot
|
|
|
23
23
|
var __privateGet = (obj, member, getter) => (__accessCheck(obj, member, "read from private field"), getter ? getter.call(obj) : member.get(obj));
|
|
24
24
|
var __privateAdd = (obj, member, value) => member.has(obj) ? __typeError("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
|
|
25
25
|
var __privateSet = (obj, member, value, setter) => (__accessCheck(obj, member, "write to private field"), setter ? setter.call(obj, value) : member.set(obj, value), value);
|
|
26
|
+
var __privateMethod = (obj, member, method) => (__accessCheck(obj, member, "access private method"), method);
|
|
26
27
|
|
|
27
28
|
// src/index.ts
|
|
28
29
|
var index_exports = {};
|
|
@@ -206,9 +207,10 @@ var SendError = class extends Error {
|
|
|
206
207
|
// src/client.ts
|
|
207
208
|
var DEFAULT_BASE_URL = "https://api.hostwebhook.com";
|
|
208
209
|
var DEFAULT_TIMEOUT = 1e4;
|
|
209
|
-
var _token, _baseUrl, _signingSecret, _signature, _defaultHeaders, _timeoutMs;
|
|
210
|
+
var _token, _baseUrl, _signingSecret, _signature, _defaultHeaders, _timeoutMs, _HostWebhook_instances, waitForStream_fn;
|
|
210
211
|
var HostWebhook = class {
|
|
211
212
|
constructor(config) {
|
|
213
|
+
__privateAdd(this, _HostWebhook_instances);
|
|
212
214
|
__privateAdd(this, _token);
|
|
213
215
|
__privateAdd(this, _baseUrl);
|
|
214
216
|
__privateAdd(this, _signingSecret);
|
|
@@ -251,7 +253,7 @@ var HostWebhook = class {
|
|
|
251
253
|
}
|
|
252
254
|
const headers = {
|
|
253
255
|
"Content-Type": options?.contentType ?? "application/json",
|
|
254
|
-
"User-Agent": `HostWebhook-SDK/${"1.0
|
|
256
|
+
"User-Agent": `HostWebhook-SDK/${"1.1.0"}`,
|
|
255
257
|
"X-HostWebhook-Sent-At": (/* @__PURE__ */ new Date()).toISOString(),
|
|
256
258
|
...tz ? { "X-HostWebhook-Timezone": tz } : {},
|
|
257
259
|
...__privateGet(this, _defaultHeaders),
|
|
@@ -272,6 +274,7 @@ var HostWebhook = class {
|
|
|
272
274
|
const url = `${__privateGet(this, _baseUrl)}/api/in/${__privateGet(this, _token)}`;
|
|
273
275
|
const controller = new AbortController();
|
|
274
276
|
const timer = setTimeout(() => controller.abort(), __privateGet(this, _timeoutMs));
|
|
277
|
+
let ingressResult;
|
|
275
278
|
try {
|
|
276
279
|
const res = await fetch(url, {
|
|
277
280
|
method: "POST",
|
|
@@ -288,9 +291,9 @@ var HostWebhook = class {
|
|
|
288
291
|
);
|
|
289
292
|
}
|
|
290
293
|
try {
|
|
291
|
-
|
|
294
|
+
ingressResult = JSON.parse(text);
|
|
292
295
|
} catch {
|
|
293
|
-
|
|
296
|
+
ingressResult = { eventId: text };
|
|
294
297
|
}
|
|
295
298
|
} catch (err) {
|
|
296
299
|
if (err instanceof SendError) throw err;
|
|
@@ -305,6 +308,11 @@ var HostWebhook = class {
|
|
|
305
308
|
} finally {
|
|
306
309
|
clearTimeout(timer);
|
|
307
310
|
}
|
|
311
|
+
if (ingressResult.syncStatus !== void 0) return ingressResult;
|
|
312
|
+
if (options?.waitForResult && ingressResult.streamToken) {
|
|
313
|
+
return __privateMethod(this, _HostWebhook_instances, waitForStream_fn).call(this, ingressResult);
|
|
314
|
+
}
|
|
315
|
+
return ingressResult;
|
|
308
316
|
}
|
|
309
317
|
/**
|
|
310
318
|
* Convenience: send multiple payloads in parallel.
|
|
@@ -323,6 +331,70 @@ _signingSecret = new WeakMap();
|
|
|
323
331
|
_signature = new WeakMap();
|
|
324
332
|
_defaultHeaders = new WeakMap();
|
|
325
333
|
_timeoutMs = new WeakMap();
|
|
334
|
+
_HostWebhook_instances = new WeakSet();
|
|
335
|
+
waitForStream_fn = async function(ingressResult) {
|
|
336
|
+
const { eventId, streamToken } = ingressResult;
|
|
337
|
+
const streamUrl = `${__privateGet(this, _baseUrl)}/api/events/${eventId}/stream?token=${streamToken}`;
|
|
338
|
+
const controller = new AbortController();
|
|
339
|
+
const timer = setTimeout(() => controller.abort(), 125e3);
|
|
340
|
+
try {
|
|
341
|
+
const res = await fetch(streamUrl, { signal: controller.signal });
|
|
342
|
+
if (!res.ok) {
|
|
343
|
+
const text = await res.text();
|
|
344
|
+
throw new SendError(`SSE stream error (${res.status}): ${text}`, res.status, text);
|
|
345
|
+
}
|
|
346
|
+
const steps = [];
|
|
347
|
+
let doneResult = null;
|
|
348
|
+
const reader = res.body.getReader();
|
|
349
|
+
const decoder = new TextDecoder();
|
|
350
|
+
let buffer = "";
|
|
351
|
+
let currentEvent = "";
|
|
352
|
+
while (true) {
|
|
353
|
+
const { done, value } = await reader.read();
|
|
354
|
+
if (done) break;
|
|
355
|
+
buffer += decoder.decode(value, { stream: true });
|
|
356
|
+
const lines = buffer.split("\n");
|
|
357
|
+
buffer = lines.pop();
|
|
358
|
+
for (const line of lines) {
|
|
359
|
+
if (line.startsWith("event: ")) {
|
|
360
|
+
currentEvent = line.slice(7).trim();
|
|
361
|
+
} else if (line.startsWith("data: ")) {
|
|
362
|
+
const data = line.slice(6);
|
|
363
|
+
try {
|
|
364
|
+
const parsed = JSON.parse(data);
|
|
365
|
+
if (currentEvent === "step") {
|
|
366
|
+
steps.push(parsed);
|
|
367
|
+
} else if (currentEvent === "done") {
|
|
368
|
+
doneResult = parsed;
|
|
369
|
+
} else if (currentEvent === "timeout") {
|
|
370
|
+
return { ...ingressResult, steps, syncStatus: 408, error: "Pipeline timeout" };
|
|
371
|
+
}
|
|
372
|
+
} catch {
|
|
373
|
+
}
|
|
374
|
+
currentEvent = "";
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
if (doneResult) break;
|
|
378
|
+
}
|
|
379
|
+
if (doneResult) {
|
|
380
|
+
return {
|
|
381
|
+
...ingressResult,
|
|
382
|
+
steps,
|
|
383
|
+
syncStatus: doneResult.status ?? 200,
|
|
384
|
+
...doneResult.body ?? doneResult
|
|
385
|
+
};
|
|
386
|
+
}
|
|
387
|
+
return { ...ingressResult, steps, syncStatus: 408, error: "Stream ended without result" };
|
|
388
|
+
} catch (err) {
|
|
389
|
+
if (err instanceof SendError) throw err;
|
|
390
|
+
if (err instanceof DOMException && err.name === "AbortError") {
|
|
391
|
+
throw new SendError("Pipeline stream timed out after 125s", 0, "");
|
|
392
|
+
}
|
|
393
|
+
throw err;
|
|
394
|
+
} finally {
|
|
395
|
+
clearTimeout(timer);
|
|
396
|
+
}
|
|
397
|
+
};
|
|
326
398
|
async function send(config, payload, options) {
|
|
327
399
|
const client = new HostWebhook(config);
|
|
328
400
|
return client.send(payload, options);
|
package/dist/index.mjs
CHANGED
|
@@ -5,6 +5,7 @@ var __accessCheck = (obj, member, msg) => member.has(obj) || __typeError("Cannot
|
|
|
5
5
|
var __privateGet = (obj, member, getter) => (__accessCheck(obj, member, "read from private field"), getter ? getter.call(obj) : member.get(obj));
|
|
6
6
|
var __privateAdd = (obj, member, value) => member.has(obj) ? __typeError("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
|
|
7
7
|
var __privateSet = (obj, member, value, setter) => (__accessCheck(obj, member, "write to private field"), setter ? setter.call(obj, value) : member.set(obj, value), value);
|
|
8
|
+
var __privateMethod = (obj, member, method) => (__accessCheck(obj, member, "access private method"), method);
|
|
8
9
|
|
|
9
10
|
// src/verify.ts
|
|
10
11
|
import { createHmac, timingSafeEqual } from "crypto";
|
|
@@ -173,9 +174,10 @@ var SendError = class extends Error {
|
|
|
173
174
|
// src/client.ts
|
|
174
175
|
var DEFAULT_BASE_URL = "https://api.hostwebhook.com";
|
|
175
176
|
var DEFAULT_TIMEOUT = 1e4;
|
|
176
|
-
var _token, _baseUrl, _signingSecret, _signature, _defaultHeaders, _timeoutMs;
|
|
177
|
+
var _token, _baseUrl, _signingSecret, _signature, _defaultHeaders, _timeoutMs, _HostWebhook_instances, waitForStream_fn;
|
|
177
178
|
var HostWebhook = class {
|
|
178
179
|
constructor(config) {
|
|
180
|
+
__privateAdd(this, _HostWebhook_instances);
|
|
179
181
|
__privateAdd(this, _token);
|
|
180
182
|
__privateAdd(this, _baseUrl);
|
|
181
183
|
__privateAdd(this, _signingSecret);
|
|
@@ -218,7 +220,7 @@ var HostWebhook = class {
|
|
|
218
220
|
}
|
|
219
221
|
const headers = {
|
|
220
222
|
"Content-Type": options?.contentType ?? "application/json",
|
|
221
|
-
"User-Agent": `HostWebhook-SDK/${"1.0
|
|
223
|
+
"User-Agent": `HostWebhook-SDK/${"1.1.0"}`,
|
|
222
224
|
"X-HostWebhook-Sent-At": (/* @__PURE__ */ new Date()).toISOString(),
|
|
223
225
|
...tz ? { "X-HostWebhook-Timezone": tz } : {},
|
|
224
226
|
...__privateGet(this, _defaultHeaders),
|
|
@@ -239,6 +241,7 @@ var HostWebhook = class {
|
|
|
239
241
|
const url = `${__privateGet(this, _baseUrl)}/api/in/${__privateGet(this, _token)}`;
|
|
240
242
|
const controller = new AbortController();
|
|
241
243
|
const timer = setTimeout(() => controller.abort(), __privateGet(this, _timeoutMs));
|
|
244
|
+
let ingressResult;
|
|
242
245
|
try {
|
|
243
246
|
const res = await fetch(url, {
|
|
244
247
|
method: "POST",
|
|
@@ -255,9 +258,9 @@ var HostWebhook = class {
|
|
|
255
258
|
);
|
|
256
259
|
}
|
|
257
260
|
try {
|
|
258
|
-
|
|
261
|
+
ingressResult = JSON.parse(text);
|
|
259
262
|
} catch {
|
|
260
|
-
|
|
263
|
+
ingressResult = { eventId: text };
|
|
261
264
|
}
|
|
262
265
|
} catch (err) {
|
|
263
266
|
if (err instanceof SendError) throw err;
|
|
@@ -272,6 +275,11 @@ var HostWebhook = class {
|
|
|
272
275
|
} finally {
|
|
273
276
|
clearTimeout(timer);
|
|
274
277
|
}
|
|
278
|
+
if (ingressResult.syncStatus !== void 0) return ingressResult;
|
|
279
|
+
if (options?.waitForResult && ingressResult.streamToken) {
|
|
280
|
+
return __privateMethod(this, _HostWebhook_instances, waitForStream_fn).call(this, ingressResult);
|
|
281
|
+
}
|
|
282
|
+
return ingressResult;
|
|
275
283
|
}
|
|
276
284
|
/**
|
|
277
285
|
* Convenience: send multiple payloads in parallel.
|
|
@@ -290,6 +298,70 @@ _signingSecret = new WeakMap();
|
|
|
290
298
|
_signature = new WeakMap();
|
|
291
299
|
_defaultHeaders = new WeakMap();
|
|
292
300
|
_timeoutMs = new WeakMap();
|
|
301
|
+
_HostWebhook_instances = new WeakSet();
|
|
302
|
+
waitForStream_fn = async function(ingressResult) {
|
|
303
|
+
const { eventId, streamToken } = ingressResult;
|
|
304
|
+
const streamUrl = `${__privateGet(this, _baseUrl)}/api/events/${eventId}/stream?token=${streamToken}`;
|
|
305
|
+
const controller = new AbortController();
|
|
306
|
+
const timer = setTimeout(() => controller.abort(), 125e3);
|
|
307
|
+
try {
|
|
308
|
+
const res = await fetch(streamUrl, { signal: controller.signal });
|
|
309
|
+
if (!res.ok) {
|
|
310
|
+
const text = await res.text();
|
|
311
|
+
throw new SendError(`SSE stream error (${res.status}): ${text}`, res.status, text);
|
|
312
|
+
}
|
|
313
|
+
const steps = [];
|
|
314
|
+
let doneResult = null;
|
|
315
|
+
const reader = res.body.getReader();
|
|
316
|
+
const decoder = new TextDecoder();
|
|
317
|
+
let buffer = "";
|
|
318
|
+
let currentEvent = "";
|
|
319
|
+
while (true) {
|
|
320
|
+
const { done, value } = await reader.read();
|
|
321
|
+
if (done) break;
|
|
322
|
+
buffer += decoder.decode(value, { stream: true });
|
|
323
|
+
const lines = buffer.split("\n");
|
|
324
|
+
buffer = lines.pop();
|
|
325
|
+
for (const line of lines) {
|
|
326
|
+
if (line.startsWith("event: ")) {
|
|
327
|
+
currentEvent = line.slice(7).trim();
|
|
328
|
+
} else if (line.startsWith("data: ")) {
|
|
329
|
+
const data = line.slice(6);
|
|
330
|
+
try {
|
|
331
|
+
const parsed = JSON.parse(data);
|
|
332
|
+
if (currentEvent === "step") {
|
|
333
|
+
steps.push(parsed);
|
|
334
|
+
} else if (currentEvent === "done") {
|
|
335
|
+
doneResult = parsed;
|
|
336
|
+
} else if (currentEvent === "timeout") {
|
|
337
|
+
return { ...ingressResult, steps, syncStatus: 408, error: "Pipeline timeout" };
|
|
338
|
+
}
|
|
339
|
+
} catch {
|
|
340
|
+
}
|
|
341
|
+
currentEvent = "";
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
if (doneResult) break;
|
|
345
|
+
}
|
|
346
|
+
if (doneResult) {
|
|
347
|
+
return {
|
|
348
|
+
...ingressResult,
|
|
349
|
+
steps,
|
|
350
|
+
syncStatus: doneResult.status ?? 200,
|
|
351
|
+
...doneResult.body ?? doneResult
|
|
352
|
+
};
|
|
353
|
+
}
|
|
354
|
+
return { ...ingressResult, steps, syncStatus: 408, error: "Stream ended without result" };
|
|
355
|
+
} catch (err) {
|
|
356
|
+
if (err instanceof SendError) throw err;
|
|
357
|
+
if (err instanceof DOMException && err.name === "AbortError") {
|
|
358
|
+
throw new SendError("Pipeline stream timed out after 125s", 0, "");
|
|
359
|
+
}
|
|
360
|
+
throw err;
|
|
361
|
+
} finally {
|
|
362
|
+
clearTimeout(timer);
|
|
363
|
+
}
|
|
364
|
+
};
|
|
293
365
|
async function send(config, payload, options) {
|
|
294
366
|
const client = new HostWebhook(config);
|
|
295
367
|
return client.send(payload, options);
|