@zapier/zapier-sdk 0.68.1 → 0.69.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/CHANGELOG.md +15 -0
- package/README.md +17 -17
- package/dist/api/client.d.ts.map +1 -1
- package/dist/api/client.js +108 -3
- package/dist/api/error-classification.d.ts +12 -0
- package/dist/api/error-classification.d.ts.map +1 -0
- package/dist/api/error-classification.js +18 -0
- package/dist/api/index.d.ts +2 -0
- package/dist/api/index.d.ts.map +1 -1
- package/dist/api/index.js +3 -0
- package/dist/api/sse-parser.d.ts +17 -0
- package/dist/api/sse-parser.d.ts.map +1 -0
- package/dist/api/sse-parser.js +67 -0
- package/dist/api/types.d.ts +16 -0
- package/dist/api/types.d.ts.map +1 -1
- package/dist/experimental.cjs +365 -77
- package/dist/experimental.d.mts +2 -2
- package/dist/experimental.mjs +365 -77
- package/dist/{index-oRnHsPn5.d.mts → index-BWdR4HBe.d.mts} +30 -1
- package/dist/{index-oRnHsPn5.d.ts → index-BWdR4HBe.d.ts} +30 -1
- package/dist/index.cjs +140 -17
- package/dist/index.d.mts +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.mjs +140 -17
- package/dist/plugins/triggers/drainTriggerInbox/schemas.js +2 -2
- package/dist/plugins/triggers/watchTriggerInbox/index.d.ts +31 -6
- package/dist/plugins/triggers/watchTriggerInbox/index.d.ts.map +1 -1
- package/dist/plugins/triggers/watchTriggerInbox/index.js +272 -65
- package/dist/plugins/triggers/watchTriggerInbox/sse.d.ts +30 -0
- package/dist/plugins/triggers/watchTriggerInbox/sse.d.ts.map +1 -0
- package/dist/plugins/triggers/watchTriggerInbox/sse.js +38 -0
- package/package.json +2 -2
package/dist/experimental.cjs
CHANGED
|
@@ -655,21 +655,20 @@ function createPaginatedFunction(coreFn, options) {
|
|
|
655
655
|
});
|
|
656
656
|
});
|
|
657
657
|
}
|
|
658
|
+
const pageStream = async function* () {
|
|
659
|
+
yield await firstPagePromise;
|
|
660
|
+
for await (const page of iterator) {
|
|
661
|
+
yield page;
|
|
662
|
+
}
|
|
663
|
+
}();
|
|
658
664
|
return Object.assign(firstPagePromise, {
|
|
659
|
-
[Symbol.asyncIterator]
|
|
660
|
-
|
|
661
|
-
for await (const page of iterator) {
|
|
662
|
-
yield page;
|
|
663
|
-
}
|
|
665
|
+
[Symbol.asyncIterator]() {
|
|
666
|
+
return pageStream;
|
|
664
667
|
},
|
|
665
668
|
items: function() {
|
|
666
669
|
return {
|
|
667
670
|
[Symbol.asyncIterator]: async function* () {
|
|
668
|
-
const
|
|
669
|
-
for (const item of firstPage.data) {
|
|
670
|
-
yield item;
|
|
671
|
-
}
|
|
672
|
-
for await (const page of iterator) {
|
|
671
|
+
for await (const page of pageStream) {
|
|
673
672
|
for (const item of page.data) {
|
|
674
673
|
yield item;
|
|
675
674
|
}
|
|
@@ -3124,8 +3123,55 @@ async function invalidateCredentialsToken(options) {
|
|
|
3124
3123
|
}
|
|
3125
3124
|
}
|
|
3126
3125
|
|
|
3126
|
+
// src/api/sse-parser.ts
|
|
3127
|
+
function createSseParserStream() {
|
|
3128
|
+
let buffer = "";
|
|
3129
|
+
let data = "";
|
|
3130
|
+
let hasData = false;
|
|
3131
|
+
function processLine(line, controller) {
|
|
3132
|
+
if (line === "") {
|
|
3133
|
+
if (hasData) {
|
|
3134
|
+
controller.enqueue({
|
|
3135
|
+
data: data.endsWith("\n") ? data.slice(0, -1) : data
|
|
3136
|
+
});
|
|
3137
|
+
}
|
|
3138
|
+
data = "";
|
|
3139
|
+
hasData = false;
|
|
3140
|
+
return;
|
|
3141
|
+
}
|
|
3142
|
+
if (line.startsWith(":")) return;
|
|
3143
|
+
const colon = line.indexOf(":");
|
|
3144
|
+
const field = colon === -1 ? line : line.slice(0, colon);
|
|
3145
|
+
let value = colon === -1 ? "" : line.slice(colon + 1);
|
|
3146
|
+
if (value.startsWith(" ")) value = value.slice(1);
|
|
3147
|
+
if (field === "data") {
|
|
3148
|
+
data += value + "\n";
|
|
3149
|
+
hasData = true;
|
|
3150
|
+
}
|
|
3151
|
+
}
|
|
3152
|
+
return new TransformStream({
|
|
3153
|
+
transform(chunk, controller) {
|
|
3154
|
+
buffer += chunk;
|
|
3155
|
+
const newline = /\r\n|\r|\n/g;
|
|
3156
|
+
let start = 0;
|
|
3157
|
+
let match;
|
|
3158
|
+
while ((match = newline.exec(buffer)) !== null) {
|
|
3159
|
+
if (match[0] === "\r" && match.index === buffer.length - 1) break;
|
|
3160
|
+
processLine(buffer.slice(start, match.index), controller);
|
|
3161
|
+
start = match.index + match[0].length;
|
|
3162
|
+
}
|
|
3163
|
+
buffer = buffer.slice(start);
|
|
3164
|
+
},
|
|
3165
|
+
flush(controller) {
|
|
3166
|
+
if (buffer.endsWith("\r")) {
|
|
3167
|
+
processLine(buffer.slice(0, -1), controller);
|
|
3168
|
+
}
|
|
3169
|
+
}
|
|
3170
|
+
});
|
|
3171
|
+
}
|
|
3172
|
+
|
|
3127
3173
|
// src/sdk-version.ts
|
|
3128
|
-
var SDK_VERSION = (typeof process !== "undefined" && process.env ? "0.
|
|
3174
|
+
var SDK_VERSION = (typeof process !== "undefined" && process.env ? "0.69.1" : void 0) || "unknown";
|
|
3129
3175
|
|
|
3130
3176
|
// src/utils/open-url.ts
|
|
3131
3177
|
var nodePrefix = "node:";
|
|
@@ -3488,6 +3534,18 @@ var ZapierApiClient = class {
|
|
|
3488
3534
|
{ status: "max_retries_exceeded" }
|
|
3489
3535
|
);
|
|
3490
3536
|
};
|
|
3537
|
+
/**
|
|
3538
|
+
* Streaming counterpart to `fetch`. Opens a Server-Sent Events connection
|
|
3539
|
+
* through the same pipeline (auth, base URL, 429 retry, approval flow,
|
|
3540
|
+
* concurrency) and yields parsed `{ data }` frames. On a non-ok response it
|
|
3541
|
+
* throws the same `ZapierError` subclasses as the JSON path — callers
|
|
3542
|
+
* classify errors off `statusCode` instead of hand-rolling the mapping.
|
|
3543
|
+
*
|
|
3544
|
+
* The concurrency permit is released when the underlying `fetch` resolves
|
|
3545
|
+
* (headers received), not when the body finishes, so a long-lived stream
|
|
3546
|
+
* never pins a slot — see `withSemaphore`.
|
|
3547
|
+
*/
|
|
3548
|
+
this.fetchStream = (path, init) => this.streamSse(path, init);
|
|
3491
3549
|
this.get = async (path, options = {}) => {
|
|
3492
3550
|
return this.fetchJson("GET", path, void 0, options);
|
|
3493
3551
|
};
|
|
@@ -3562,17 +3620,30 @@ var ZapierApiClient = class {
|
|
|
3562
3620
|
}
|
|
3563
3621
|
// Helper to handle responses
|
|
3564
3622
|
async handleResponse(params) {
|
|
3623
|
+
const { data: responseData } = await this.parseResult(
|
|
3624
|
+
params.response
|
|
3625
|
+
);
|
|
3626
|
+
if (params.response.ok) {
|
|
3627
|
+
return responseData;
|
|
3628
|
+
}
|
|
3629
|
+
return this.throwForErrorResponse({ ...params, responseData });
|
|
3630
|
+
}
|
|
3631
|
+
/**
|
|
3632
|
+
* Maps a non-ok response to the appropriate ZapierError subclass and throws.
|
|
3633
|
+
* Takes the already-parsed body so a streaming caller (`fetchStream`) gets
|
|
3634
|
+
* the exact same status→error classification as the JSON path without
|
|
3635
|
+
* re-reading — or reading on the success path, which would consume the
|
|
3636
|
+
* stream — the response body.
|
|
3637
|
+
*/
|
|
3638
|
+
async throwForErrorResponse(params) {
|
|
3565
3639
|
const {
|
|
3566
3640
|
response,
|
|
3641
|
+
responseData,
|
|
3567
3642
|
customErrorHandler,
|
|
3568
3643
|
resource,
|
|
3569
3644
|
wasMissingAuthToken,
|
|
3570
3645
|
requiredScopes
|
|
3571
3646
|
} = params;
|
|
3572
|
-
const { data: responseData } = await this.parseResult(response);
|
|
3573
|
-
if (response.ok) {
|
|
3574
|
-
return responseData;
|
|
3575
|
-
}
|
|
3576
3647
|
const errorInfo = {
|
|
3577
3648
|
status: response.status,
|
|
3578
3649
|
statusText: response.statusText,
|
|
@@ -3809,6 +3880,58 @@ var ZapierApiClient = class {
|
|
|
3809
3880
|
}
|
|
3810
3881
|
return result;
|
|
3811
3882
|
}
|
|
3883
|
+
// The generator body for `fetchStream`. Kept as a prototype method (not an
|
|
3884
|
+
// arrow class field, which can't be a generator) and exposed through the
|
|
3885
|
+
// bound `fetchStream` arrow above for parity with the other client methods.
|
|
3886
|
+
async *streamSse(path, init) {
|
|
3887
|
+
const { onOpen, headers: initHeaders, ...fetchInit } = init ?? {};
|
|
3888
|
+
const signal = fetchInit.signal;
|
|
3889
|
+
if (signal?.aborted) return;
|
|
3890
|
+
const wasMissingAuthToken = fetchInit.authRequired === true && await this.getAuthToken({
|
|
3891
|
+
requiredScopes: fetchInit.requiredScopes
|
|
3892
|
+
}) == null;
|
|
3893
|
+
const headers = new Headers(initHeaders);
|
|
3894
|
+
if (!headers.has("Accept")) headers.set("Accept", "text/event-stream");
|
|
3895
|
+
let response;
|
|
3896
|
+
try {
|
|
3897
|
+
response = await this.fetch(path, {
|
|
3898
|
+
...fetchInit,
|
|
3899
|
+
method: fetchInit.method ?? "GET",
|
|
3900
|
+
headers
|
|
3901
|
+
});
|
|
3902
|
+
} catch (err) {
|
|
3903
|
+
if (signal?.aborted || isAbortError(err)) return;
|
|
3904
|
+
throw err;
|
|
3905
|
+
}
|
|
3906
|
+
if (!response.ok) {
|
|
3907
|
+
const { data } = await this.parseResult(response);
|
|
3908
|
+
await this.throwForErrorResponse({
|
|
3909
|
+
response,
|
|
3910
|
+
responseData: data,
|
|
3911
|
+
wasMissingAuthToken,
|
|
3912
|
+
requiredScopes: fetchInit.requiredScopes
|
|
3913
|
+
});
|
|
3914
|
+
}
|
|
3915
|
+
if (!response.body) return;
|
|
3916
|
+
const reader = response.body.pipeThrough(new TextDecoderStream()).pipeThrough(createSseParserStream()).getReader();
|
|
3917
|
+
const onAbort = () => {
|
|
3918
|
+
reader.cancel().catch(() => {
|
|
3919
|
+
});
|
|
3920
|
+
};
|
|
3921
|
+
try {
|
|
3922
|
+
onOpen?.();
|
|
3923
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
3924
|
+
while (!signal?.aborted) {
|
|
3925
|
+
const { done, value } = await reader.read();
|
|
3926
|
+
if (done || signal?.aborted) return;
|
|
3927
|
+
yield value;
|
|
3928
|
+
}
|
|
3929
|
+
} finally {
|
|
3930
|
+
signal?.removeEventListener("abort", onAbort);
|
|
3931
|
+
await reader.cancel().catch(() => {
|
|
3932
|
+
});
|
|
3933
|
+
}
|
|
3934
|
+
}
|
|
3812
3935
|
/**
|
|
3813
3936
|
* Run a single approval round: create the approval, open the URL (poll mode)
|
|
3814
3937
|
* or throw (throw mode), poll until resolved, and emit events. Throws on
|
|
@@ -3986,6 +4109,12 @@ var createZapierApi = (options) => {
|
|
|
3986
4109
|
});
|
|
3987
4110
|
};
|
|
3988
4111
|
|
|
4112
|
+
// src/api/error-classification.ts
|
|
4113
|
+
function isPermanentHttpError(err) {
|
|
4114
|
+
const statusCode = err instanceof ZapierError ? err.statusCode : void 0;
|
|
4115
|
+
return statusCode !== void 0 && statusCode >= 400 && statusCode < 500 && statusCode !== 429;
|
|
4116
|
+
}
|
|
4117
|
+
|
|
3989
4118
|
// src/api/index.ts
|
|
3990
4119
|
function getOrCreateApiClient(config) {
|
|
3991
4120
|
const {
|
|
@@ -10158,10 +10287,10 @@ var DrainTriggerInboxSchema = TriggerInboxCommandBaseSchema.extend({
|
|
|
10158
10287
|
);
|
|
10159
10288
|
var WatchTriggerInboxSchema = TriggerInboxCommandBaseSchema.extend({
|
|
10160
10289
|
maxDrainIntervalSeconds: zod.z.number().int().min(1).optional().describe(
|
|
10161
|
-
"Maximum seconds between
|
|
10290
|
+
"Maximum seconds between safety drain attempts (default: 300). The watcher subscribes to SSE notifications for near-real-time wake-ups; this interval is the backstop that guarantees forward progress if SSE events are missed or the connection drops undetected."
|
|
10162
10291
|
)
|
|
10163
10292
|
}).describe(
|
|
10164
|
-
"Continuously consume a trigger inbox: drain currently-available messages, then
|
|
10293
|
+
"Continuously consume a trigger inbox: drain currently-available messages, then subscribe to SSE notifications for new arrivals, until aborted. Stop via the `signal` AbortSignal or by throwing `ZapierAbortDrainSignal` from a handler. Resolves cleanly on abort; rejects on a fatal error or a fail-fast handler error."
|
|
10165
10294
|
);
|
|
10166
10295
|
|
|
10167
10296
|
// src/plugins/triggers/drainTriggerInbox/pipeline.ts
|
|
@@ -10516,36 +10645,170 @@ var drainTriggerInboxPlugin = definePlugin(
|
|
|
10516
10645
|
}
|
|
10517
10646
|
);
|
|
10518
10647
|
|
|
10648
|
+
// src/plugins/triggers/watchTriggerInbox/sse.ts
|
|
10649
|
+
async function* readInboxEvents({
|
|
10650
|
+
api,
|
|
10651
|
+
inboxId,
|
|
10652
|
+
signal,
|
|
10653
|
+
onOpen
|
|
10654
|
+
}) {
|
|
10655
|
+
for await (const message of api.fetchStream(
|
|
10656
|
+
`/trigger-inbox/api/v1/inboxes/${encodeURIComponent(inboxId)}/events`,
|
|
10657
|
+
{ method: "GET", signal, authRequired: true, onOpen }
|
|
10658
|
+
)) {
|
|
10659
|
+
let parsed;
|
|
10660
|
+
try {
|
|
10661
|
+
parsed = JSON.parse(message.data);
|
|
10662
|
+
} catch {
|
|
10663
|
+
continue;
|
|
10664
|
+
}
|
|
10665
|
+
if (typeof parsed === "object" && parsed !== null && typeof parsed.inbox_id === "string" && // Only wake on a frame for this inbox. Case-insensitive: the endpoint
|
|
10666
|
+
// echoes the canonical lowercase UUID, but resolveTriggerInboxId passes
|
|
10667
|
+
// a UUID-shaped `inbox` through unchanged, so its casing may differ.
|
|
10668
|
+
parsed.inbox_id.toLowerCase() === inboxId.toLowerCase()) {
|
|
10669
|
+
yield parsed;
|
|
10670
|
+
}
|
|
10671
|
+
}
|
|
10672
|
+
}
|
|
10673
|
+
|
|
10519
10674
|
// src/plugins/triggers/watchTriggerInbox/index.ts
|
|
10520
|
-
var
|
|
10521
|
-
|
|
10522
|
-
|
|
10523
|
-
|
|
10524
|
-
|
|
10525
|
-
|
|
10526
|
-
|
|
10527
|
-
|
|
10528
|
-
|
|
10529
|
-
|
|
10530
|
-
|
|
10531
|
-
|
|
10532
|
-
|
|
10533
|
-
return
|
|
10534
|
-
|
|
10535
|
-
|
|
10536
|
-
|
|
10537
|
-
|
|
10538
|
-
|
|
10539
|
-
|
|
10540
|
-
|
|
10541
|
-
|
|
10542
|
-
|
|
10543
|
-
|
|
10544
|
-
|
|
10545
|
-
|
|
10546
|
-
|
|
10547
|
-
|
|
10548
|
-
}
|
|
10675
|
+
var SSE_RECONNECT_BACKOFF_MS = [500, 1e3, 2e3, 5e3];
|
|
10676
|
+
var DEFAULT_SAFETY_DRAIN_INTERVAL_MS = 3e5;
|
|
10677
|
+
var SSE_HEALTHY_CONNECTION_MS = 5e3;
|
|
10678
|
+
function createDrainLatch() {
|
|
10679
|
+
let pending = false;
|
|
10680
|
+
const make = () => {
|
|
10681
|
+
let resolve2;
|
|
10682
|
+
const promise = new Promise((r) => {
|
|
10683
|
+
resolve2 = r;
|
|
10684
|
+
});
|
|
10685
|
+
return { promise, resolve: resolve2 };
|
|
10686
|
+
};
|
|
10687
|
+
let current = make();
|
|
10688
|
+
return {
|
|
10689
|
+
request() {
|
|
10690
|
+
pending = true;
|
|
10691
|
+
const prev = current;
|
|
10692
|
+
current = make();
|
|
10693
|
+
prev.resolve();
|
|
10694
|
+
},
|
|
10695
|
+
async waitForRequest() {
|
|
10696
|
+
if (pending) {
|
|
10697
|
+
pending = false;
|
|
10698
|
+
return;
|
|
10699
|
+
}
|
|
10700
|
+
await current.promise;
|
|
10701
|
+
pending = false;
|
|
10702
|
+
}
|
|
10703
|
+
};
|
|
10704
|
+
}
|
|
10705
|
+
async function drainRunner({
|
|
10706
|
+
drainOptions,
|
|
10707
|
+
drainRequest,
|
|
10708
|
+
signal
|
|
10709
|
+
}) {
|
|
10710
|
+
let firstFetch = true;
|
|
10711
|
+
while (!signal.aborted) {
|
|
10712
|
+
await drainRequest.waitForRequest();
|
|
10713
|
+
if (signal.aborted) return { kind: "aborted" };
|
|
10714
|
+
let abortedFromCallback = false;
|
|
10715
|
+
try {
|
|
10716
|
+
({ abortedFromCallback } = await runDrainPass({
|
|
10717
|
+
...drainOptions,
|
|
10718
|
+
firstFetch
|
|
10719
|
+
}));
|
|
10720
|
+
} catch (error) {
|
|
10721
|
+
return { kind: "error", error };
|
|
10722
|
+
}
|
|
10723
|
+
firstFetch = false;
|
|
10724
|
+
if (abortedFromCallback) return { kind: "abortedFromCallback" };
|
|
10725
|
+
}
|
|
10726
|
+
return { kind: "aborted" };
|
|
10727
|
+
}
|
|
10728
|
+
function sseErrorStatusCode(err) {
|
|
10729
|
+
return err instanceof ZapierError ? err.statusCode : void 0;
|
|
10730
|
+
}
|
|
10731
|
+
function sseErrorMessage(err) {
|
|
10732
|
+
return err instanceof Error ? err.message : String(err);
|
|
10733
|
+
}
|
|
10734
|
+
async function sseLoop({
|
|
10735
|
+
api,
|
|
10736
|
+
inboxId,
|
|
10737
|
+
drainRequest,
|
|
10738
|
+
safetyDrainMs,
|
|
10739
|
+
signal,
|
|
10740
|
+
debug
|
|
10741
|
+
}) {
|
|
10742
|
+
let attempt = 0;
|
|
10743
|
+
let degraded = false;
|
|
10744
|
+
while (!signal.aborted) {
|
|
10745
|
+
let connected = false;
|
|
10746
|
+
let connectedAt = 0;
|
|
10747
|
+
let transientError;
|
|
10748
|
+
try {
|
|
10749
|
+
for await (const _event of readInboxEvents({
|
|
10750
|
+
api,
|
|
10751
|
+
inboxId,
|
|
10752
|
+
signal,
|
|
10753
|
+
// SSE is edge-triggered with no replay, so draining on connect is the
|
|
10754
|
+
// only way to pick up messages that arrived before this connection —
|
|
10755
|
+
// including the window left by a prior disconnect.
|
|
10756
|
+
onOpen: () => {
|
|
10757
|
+
connected = true;
|
|
10758
|
+
connectedAt = Date.now();
|
|
10759
|
+
degraded = false;
|
|
10760
|
+
drainRequest.request();
|
|
10761
|
+
}
|
|
10762
|
+
})) {
|
|
10763
|
+
drainRequest.request();
|
|
10764
|
+
}
|
|
10765
|
+
if (connected && Date.now() - connectedAt >= SSE_HEALTHY_CONNECTION_MS) {
|
|
10766
|
+
attempt = 0;
|
|
10767
|
+
}
|
|
10768
|
+
} catch (err) {
|
|
10769
|
+
if (signal.aborted || isAbortError(err)) return;
|
|
10770
|
+
if (isPermanentHttpError(err)) {
|
|
10771
|
+
if (!degraded) {
|
|
10772
|
+
const statusCode = sseErrorStatusCode(err);
|
|
10773
|
+
const errorMsg = sseErrorMessage(err);
|
|
10774
|
+
const httpPart = statusCode !== void 0 ? ` (HTTP ${statusCode})` : "";
|
|
10775
|
+
console.warn(
|
|
10776
|
+
`[zapier-sdk] Real-time wake-ups for inbox ${inboxId}${httpPart} paused: ${errorMsg}. Falling back to the periodic safety drain.`
|
|
10777
|
+
);
|
|
10778
|
+
degraded = true;
|
|
10779
|
+
}
|
|
10780
|
+
attempt = 0;
|
|
10781
|
+
if (signal.aborted) return;
|
|
10782
|
+
await sleep(safetyDrainMs, signal);
|
|
10783
|
+
continue;
|
|
10784
|
+
}
|
|
10785
|
+
if (connected) attempt = 0;
|
|
10786
|
+
transientError = err;
|
|
10787
|
+
}
|
|
10788
|
+
if (signal.aborted) return;
|
|
10789
|
+
const delay = SSE_RECONNECT_BACKOFF_MS[Math.min(attempt, SSE_RECONNECT_BACKOFF_MS.length - 1)];
|
|
10790
|
+
attempt = Math.min(attempt + 1, SSE_RECONNECT_BACKOFF_MS.length - 1);
|
|
10791
|
+
if (transientError !== void 0 && debug) {
|
|
10792
|
+
const statusCode = sseErrorStatusCode(transientError);
|
|
10793
|
+
const errorMsg = sseErrorMessage(transientError);
|
|
10794
|
+
const httpPart = statusCode !== void 0 ? ` (HTTP ${statusCode})` : "";
|
|
10795
|
+
console.error(
|
|
10796
|
+
`[zapier-sdk] Reconnecting real-time wake-ups for inbox ${inboxId} (attempt ${attempt}, retry in ${delay}ms)${httpPart}: ${errorMsg}`
|
|
10797
|
+
);
|
|
10798
|
+
}
|
|
10799
|
+
await sleep(delay, signal);
|
|
10800
|
+
}
|
|
10801
|
+
}
|
|
10802
|
+
async function safetyTimerLoop({
|
|
10803
|
+
safetyDrainMs,
|
|
10804
|
+
drainRequest,
|
|
10805
|
+
signal
|
|
10806
|
+
}) {
|
|
10807
|
+
while (!signal.aborted) {
|
|
10808
|
+
await sleep(safetyDrainMs, signal);
|
|
10809
|
+
if (signal.aborted) return;
|
|
10810
|
+
drainRequest.request();
|
|
10811
|
+
}
|
|
10549
10812
|
}
|
|
10550
10813
|
var watchTriggerInboxPlugin = definePlugin(
|
|
10551
10814
|
(sdk) => {
|
|
@@ -10556,37 +10819,62 @@ var watchTriggerInboxPlugin = definePlugin(
|
|
|
10556
10819
|
api: sdk.context.api,
|
|
10557
10820
|
inbox: options.inbox
|
|
10558
10821
|
});
|
|
10559
|
-
|
|
10560
|
-
|
|
10561
|
-
|
|
10562
|
-
|
|
10563
|
-
|
|
10564
|
-
|
|
10565
|
-
|
|
10566
|
-
|
|
10567
|
-
|
|
10568
|
-
|
|
10569
|
-
|
|
10570
|
-
|
|
10571
|
-
|
|
10572
|
-
|
|
10573
|
-
|
|
10574
|
-
|
|
10575
|
-
|
|
10576
|
-
|
|
10577
|
-
|
|
10578
|
-
|
|
10579
|
-
|
|
10580
|
-
|
|
10581
|
-
|
|
10582
|
-
|
|
10583
|
-
|
|
10584
|
-
|
|
10585
|
-
|
|
10586
|
-
|
|
10587
|
-
|
|
10588
|
-
|
|
10822
|
+
if (options.signal?.aborted) return;
|
|
10823
|
+
const safetyDrainMs = options.maxDrainIntervalSeconds !== void 0 ? options.maxDrainIntervalSeconds * 1e3 : DEFAULT_SAFETY_DRAIN_INTERVAL_MS;
|
|
10824
|
+
const stop = new AbortController();
|
|
10825
|
+
const combined = combineAbortSignals({
|
|
10826
|
+
handles: [
|
|
10827
|
+
...options.signal ? [{ signal: options.signal, dispose: () => {
|
|
10828
|
+
} }] : [],
|
|
10829
|
+
{ signal: stop.signal, dispose: () => {
|
|
10830
|
+
} }
|
|
10831
|
+
]
|
|
10832
|
+
});
|
|
10833
|
+
const signal = combined?.signal ?? stop.signal;
|
|
10834
|
+
const drainRequest = createDrainLatch();
|
|
10835
|
+
signal.addEventListener("abort", () => drainRequest.request(), {
|
|
10836
|
+
once: true
|
|
10837
|
+
});
|
|
10838
|
+
const debug = sdk.context.options.debug === true;
|
|
10839
|
+
const drainOptions = {
|
|
10840
|
+
sdk,
|
|
10841
|
+
inboxId,
|
|
10842
|
+
onMessage,
|
|
10843
|
+
concurrency,
|
|
10844
|
+
leaseLimit,
|
|
10845
|
+
leaseSeconds: options.leaseSeconds,
|
|
10846
|
+
maxMessages: void 0,
|
|
10847
|
+
releaseOnError: options.releaseOnError ?? false,
|
|
10848
|
+
continueOnError: options.continueOnError ?? false,
|
|
10849
|
+
onError: options.onError,
|
|
10850
|
+
signal
|
|
10851
|
+
};
|
|
10852
|
+
drainRequest.request();
|
|
10853
|
+
const runnerDone = drainRunner({ drainOptions, drainRequest, signal });
|
|
10854
|
+
const sseDone = sseLoop({
|
|
10855
|
+
api: sdk.context.api,
|
|
10856
|
+
inboxId,
|
|
10857
|
+
drainRequest,
|
|
10858
|
+
safetyDrainMs,
|
|
10859
|
+
signal,
|
|
10860
|
+
debug
|
|
10861
|
+
}).catch(() => {
|
|
10862
|
+
});
|
|
10863
|
+
const safetyDone = safetyTimerLoop({
|
|
10864
|
+
safetyDrainMs,
|
|
10865
|
+
drainRequest,
|
|
10866
|
+
signal
|
|
10867
|
+
}).catch(() => {
|
|
10868
|
+
});
|
|
10869
|
+
let end;
|
|
10870
|
+
try {
|
|
10871
|
+
end = await runnerDone;
|
|
10872
|
+
} finally {
|
|
10873
|
+
stop.abort();
|
|
10874
|
+
await Promise.all([sseDone, safetyDone]);
|
|
10875
|
+
combined?.dispose();
|
|
10589
10876
|
}
|
|
10877
|
+
if (end.kind === "error") throw end.error;
|
|
10590
10878
|
}
|
|
10591
10879
|
return {
|
|
10592
10880
|
watchTriggerInbox,
|
|
@@ -10595,7 +10883,7 @@ var watchTriggerInboxPlugin = definePlugin(
|
|
|
10595
10883
|
watchTriggerInbox: {
|
|
10596
10884
|
...triggersDefaults,
|
|
10597
10885
|
type: "create",
|
|
10598
|
-
description: "Continuously consume a trigger inbox: drain currently-available messages via onMessage, then
|
|
10886
|
+
description: "Continuously consume a trigger inbox: drain currently-available messages via onMessage, then subscribe to SSE notifications for new arrivals until aborted. A periodic safety drain runs every maxDrainIntervalSeconds (default: 300) to guarantee forward progress if SSE events are missed. Resolves cleanly on signal abort or ZapierAbortDrainSignal from a handler; rejects on fatal SDK errors or fail-fast handler errors. Real-time wake-up health is reported on stderr: a warning when wake-ups pause and the watch falls back to the safety drain, plus (with debug) transient reconnect notices.",
|
|
10599
10887
|
itemType: "void",
|
|
10600
10888
|
// See drainTriggerInbox: override the doc generator's default
|
|
10601
10889
|
// suffix so the rendered return type is Promise<void>, not
|
package/dist/experimental.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { B as BaseSdkOptions, P as PluginStack, a as PluginMeta, M as MethodHooks, C as CoreOptions, Z as ZapierSdkOptions$1, E as EventEmissionContext, A as ApiClient, b as Manifest, R as ResolvedAppLocator, U as UpdateManifestEntryOptions, c as UpdateManifestEntryResult, d as AddActionEntryOptions, e as AddActionEntryResult, f as ActionEntry, g as findManifestEntry, r as readManifestFromFile, h as CapabilitiesContext, i as PaginatedSdkResult, F as FieldsetItem, j as PositionalMetadata, O as OutputFormatter, k as ZapierFetchInitOptions, D as DrainTriggerInboxOptions, l as DynamicResolver, W as WatchTriggerInboxOptions, m as ActionProxy, n as ZapierSdkApps, o as WithAddPlugin } from './index-
|
|
2
|
-
export { x as Action,
|
|
1
|
+
import { B as BaseSdkOptions, P as PluginStack, a as PluginMeta, M as MethodHooks, C as CoreOptions, Z as ZapierSdkOptions$1, E as EventEmissionContext, A as ApiClient, b as Manifest, R as ResolvedAppLocator, U as UpdateManifestEntryOptions, c as UpdateManifestEntryResult, d as AddActionEntryOptions, e as AddActionEntryResult, f as ActionEntry, g as findManifestEntry, r as readManifestFromFile, h as CapabilitiesContext, i as PaginatedSdkResult, F as FieldsetItem, j as PositionalMetadata, O as OutputFormatter, k as ZapierFetchInitOptions, D as DrainTriggerInboxOptions, l as DynamicResolver, W as WatchTriggerInboxOptions, m as ActionProxy, n as ZapierSdkApps, o as WithAddPlugin } from './index-BWdR4HBe.mjs';
|
|
2
|
+
export { x as Action, ca as ActionExecutionOptions, I as ActionExecutionResult, J as ActionField, K as ActionFieldChoice, aO as ActionItem, bo as ActionKeyProperty, aY as ActionKeyPropertySchema, bp as ActionProperty, aZ as ActionPropertySchema, aE as ActionResolverItem, bA as ActionTimeoutMsProperty, b8 as ActionTimeoutMsPropertySchema, aF as ActionTypeItem, bn as ActionTypeProperty, aX as ActionTypePropertySchema, c6 as ApiError, dA as ApiEvent, cU as ApiPluginOptions, cW as ApiPluginProvides, y as App, cb as AppFactoryInput, aM as AppItem, bl as AppKeyProperty, aV as AppKeyPropertySchema, bm as AppProperty, aW as AppPropertySchema, eJ as ApplicationLifecycleEventData, c2 as ApprovalStatus, c9 as AppsPluginProvides, bF as AppsProperty, bd as AppsPropertySchema, a5 as ArrayResolver, dz as AuthEvent, bt as AuthenticationIdProperty, b0 as AuthenticationIdPropertySchema, eR as BaseEvent, as as BaseSdkOptionsSchema, ag as BatchOptions, cH as CONTEXT_CACHE_MAX_SIZE, cG as CONTEXT_CACHE_TTL_MS, aw as CORE_ERROR_SYMBOL, H as Choice, dG as ClientCredentialsObject, dR as ClientCredentialsObjectSchema, V as Connection, dZ as ConnectionEntry, dY as ConnectionEntrySchema, br as ConnectionIdProperty, a$ as ConnectionIdPropertySchema, aN as ConnectionItem, bs as ConnectionProperty, b1 as ConnectionPropertySchema, d$ as ConnectionsMap, d_ as ConnectionsMapSchema, e1 as ConnectionsPluginProvides, bH as ConnectionsProperty, bf as ConnectionsPropertySchema, X as ConnectionsResponse, ax as CoreErrorCode, ct as CreateClientCredentialsPluginProvides, er as CreateTableFieldsPluginProvides, el as CreateTablePluginProvides, ez as CreateTableRecordsPluginProvides, dD as Credentials, dW as CredentialsFunction, dV as CredentialsFunctionSchema, dF as CredentialsObject, dT as CredentialsObjectSchema, dX as CredentialsSchema, e6 as DEFAULT_ACTION_TIMEOUT_MS, ee as DEFAULT_APPROVAL_TIMEOUT_MS, cQ as DEFAULT_CONFIG_PATH, ef as DEFAULT_MAX_APPROVAL_RETRIES, e5 as DEFAULT_PAGE_SIZE, by as DebugProperty, b6 as DebugPropertySchema, cv as DeleteClientCredentialsPluginProvides, et as DeleteTableFieldsPluginProvides, en as DeleteTablePluginProvides, eB as DeleteTableRecordsPluginProvides, s as DrainTriggerInboxCallback, t as DrainTriggerInboxErrorObserver, a8 as DynamicListResolver, a9 as DynamicSearchResolver, eK as EnhancedErrorEventData, bN as ErrorOptions, dC as EventCallback, eI as EventContext, eF as EventEmissionConfig, eH as EventEmissionProvides, cd as FetchPluginProvides, z as Field, bE as FieldsProperty, bc as FieldsPropertySchema, aa as FieldsResolver, v as FindFirstAuthenticationPluginProvides, cD as FindFirstConnectionPluginProvides, w as FindUniqueAuthenticationPluginProvides, cF as FindUniqueConnectionPluginProvides, a3 as FormattedItem, ar as FunctionDeprecation, aq as FunctionRegistryEntry, cn as GetActionInputFieldsSchemaPluginProvides, cz as GetActionPluginProvides, cx as GetAppPluginProvides, G as GetAuthenticationPluginProvides, cB as GetConnectionPluginProvides, cT as GetProfilePluginProvides, ej as GetTablePluginProvides, ev as GetTableRecordPluginProvides, aQ as InfoFieldItem, aP as InputFieldItem, bq as InputFieldProperty, a_ as InputFieldPropertySchema, bu as InputsProperty, b2 as InputsPropertySchema, bM as LeaseLimitProperty, bk as LeaseLimitPropertySchema, bK as LeaseProperty, bi as LeasePropertySchema, bL as LeaseSecondsProperty, bj as LeaseSecondsPropertySchema, L as LeasedTriggerMessageItem, bv as LimitProperty, b3 as LimitPropertySchema, cl as ListActionInputFieldChoicesPluginProvides, cj as ListActionInputFieldsPluginProvides, ch as ListActionsPluginProvides, cf as ListAppsPluginProvides, u as ListAuthenticationsPluginProvides, cr as ListClientCredentialsPluginProvides, cp as ListConnectionsPluginProvides, ep as ListTableFieldsPluginProvides, ex as ListTableRecordsPluginProvides, eh as ListTablesPluginProvides, dB as LoadingEvent, e9 as MAX_CONCURRENCY_LIMIT, e4 as MAX_PAGE_LIMIT, cR as ManifestEntry, cM as ManifestPluginOptions, cP as ManifestPluginProvides, eS as MethodCalledEvent, eL as MethodCalledEventData, N as Need, Q as NeedsRequest, S as NeedsResponse, bw as OffsetProperty, b4 as OffsetPropertySchema, bx as OutputProperty, b5 as OutputPropertySchema, aU as PaginatedSdkFunction, bz as ParamsProperty, b7 as ParamsPropertySchema, dH as PkceCredentialsObject, dS as PkceCredentialsObjectSchema, ay as Plugin, az as PluginProvides, aI as PollOptions, c0 as RateLimitInfo, bC as RecordProperty, ba as RecordPropertySchema, bD as RecordsProperty, bb as RecordsPropertySchema, al as RelayFetchSchema, ak as RelayRequestSchema, aH as RequestOptions, cL as RequestPluginProvides, dl as ResolveAuthTokenOptions, dM as ResolveCredentialsOptions, dE as ResolvedCredentials, dU as ResolvedCredentialsSchema, a4 as Resolver, a6 as ResolverMetadata, aR as RootFieldItem, cJ as RunActionPluginProvides, dy as SdkEvent, aT as SdkPage, aL as SseMessage, a7 as StaticResolver, bB as TableProperty, b9 as TablePropertySchema, bG as TablesProperty, be as TablesPropertySchema, bJ as TriggerInboxNameProperty, bh as TriggerInboxNamePropertySchema, bI as TriggerInboxProperty, bg as TriggerInboxPropertySchema, T as TriggerMessageStatus, eD as UpdateTableRecordsPluginProvides, Y as UserProfile, aS as UserProfileItem, e2 as ZAPIER_BASE_URL, eb as ZAPIER_MAX_CONCURRENT_REQUESTS, e7 as ZAPIER_MAX_NETWORK_RETRIES, e8 as ZAPIER_MAX_NETWORK_RETRY_DELAY_MS, p as ZapierAbortDrainSignal, b_ as ZapierActionError, bT as ZapierApiError, bU as ZapierAppNotFoundError, c3 as ZapierApprovalError, bR as ZapierAuthenticationError, bY as ZapierBundleError, du as ZapierCache, dv as ZapierCacheEntry, dw as ZapierCacheSetOptions, bX as ZapierConfigurationError, b$ as ZapierConflictError, bO as ZapierError, bV as ZapierNotFoundError, c1 as ZapierRateLimitError, c4 as ZapierRelayError, q as ZapierReleaseTriggerMessageSignal, bW as ZapierResourceNotFoundError, c7 as ZapierSignal, bZ as ZapierTimeoutError, bQ as ZapierUnknownError, bP as ZapierValidationError, cZ as actionKeyResolver, cY as actionTypeResolver, a2 as addPlugin, cV as apiPlugin, cX as appKeyResolver, c8 as appsPlugin, c$ as authenticationIdGenericResolver, c_ as authenticationIdResolver, af as batch, eM as buildApplicationLifecycleEvent, ah as buildCapabilityMessage, eO as buildErrorEvent, eN as buildErrorEventWithContext, eQ as buildMethodCalledEvent, eE as cleanupEventListeners, dm as clearTokenCache, d3 as clientCredentialsNameResolver, d4 as clientIdResolver, aD as composePlugins, c$ as connectionIdGenericResolver, c_ as connectionIdResolver, e0 as connectionsPlugin, eP as createBaseEvent, cs as createClientCredentialsPlugin, a1 as createCorePlugin, $ as createFunction, dx as createMemoryCache, ao as createOptionsPlugin, aC as createPaginatedPluginMethod, aB as createPluginMethod, a0 as createPluginStack, an as createSdk, eq as createTableFieldsPlugin, ek as createTablePlugin, ey as createTableRecordsPlugin, aJ as createZapierApi, ap as createZapierCoreStack, am as createZapierSdkWithoutRegistry, aA as definePlugin, cu as deleteClientCredentialsPlugin, es as deleteTableFieldsPlugin, em as deleteTablePlugin, eA as deleteTableRecordsPlugin, d8 as durableRunIdResolver, eG as eventEmissionPlugin, cc as fetchPlugin, cC as findFirstConnectionPlugin, cE as findUniqueConnectionPlugin, c5 as formatErrorMessage, eT as generateEventId, cm as getActionInputFieldsSchemaPlugin, cy as getActionPlugin, cw as getAppPlugin, dP as getBaseUrlFromCredentials, eZ as getCiPlatform, dQ as getClientIdFromCredentials, cA as getConnectionPlugin, av as getCoreErrorCause, au as getCoreErrorCode, e$ as getCpuTime, eU as getCurrentTimestamp, e_ as getMemoryUsage, aK as getOrCreateApiClient, eW as getOsInfo, eX as getPlatformVersions, cN as getPreferredManifestEntryKey, cS as getProfilePlugin, eV as getReleaseId, ei as getTablePlugin, eu as getTableRecordPlugin, dr as getTokenFromCliLogin, ec as getZapierApprovalMode, ed as getZapierDefaultApprovalMode, e3 as getZapierSdkService, dp as injectCliLogin, d2 as inputFieldKeyResolver, d1 as inputsAllOptionalResolver, d0 as inputsResolver, dn as invalidateCachedToken, dt as invalidateCredentialsToken, eY as isCi, dq as isCliLoginAvailable, dI as isClientCredentials, at as isCoreError, dL as isCredentialsFunction, dK as isCredentialsObject, dJ as isPkceCredentials, _ as isPositional, ck as listActionInputFieldChoicesPlugin, ci as listActionInputFieldsPlugin, cg as listActionsPlugin, ce as listAppsPlugin, cq as listClientCredentialsPlugin, co as listConnectionsPlugin, eo as listTableFieldsPlugin, ew as listTableRecordsPlugin, eg as listTablesPlugin, ai as logDeprecation, cO as manifestPlugin, ea as parseConcurrencyEnvVar, aG as registryPlugin, cK as requestPlugin, aj as resetDeprecationWarnings, ds as resolveAuthToken, dO as resolveCredentials, dN as resolveCredentialsFromEnv, cI as runActionPlugin, ab as runInMethodScope, ac as runWithTelemetryContext, de as tableFieldIdsResolver, dg as tableFieldsResolver, dj as tableFiltersResolver, d5 as tableIdResolver, df as tableNameResolver, dc as tableRecordIdResolver, dd as tableRecordIdsResolver, dh as tableRecordsResolver, dk as tableSortResolver, di as tableUpdateRecordsResolver, ad as toSnakeCase, ae as toTitleCase, d6 as triggerInboxResolver, db as triggerMessagesResolver, eC as updateTableRecordsPlugin, d7 as workflowIdResolver, da as workflowRunIdResolver, d9 as workflowVersionIdResolver, bS as zapierAdaptError } from './index-BWdR4HBe.mjs';
|
|
3
3
|
import * as zod_v4_core from 'zod/v4/core';
|
|
4
4
|
import * as zod from 'zod';
|
|
5
5
|
import '@zapier/zapier-sdk-core/v0/schemas/connections';
|