@pingroom/sdk 0.7.1 → 0.9.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/README.md +288 -44
- package/dist/client.d.ts +27 -312
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +33 -1154
- package/dist/client.js.map +1 -1
- package/dist/errors.d.ts +40 -6
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +56 -4
- package/dist/errors.js.map +1 -1
- package/dist/http.d.ts +12 -1
- package/dist/http.d.ts.map +1 -1
- package/dist/http.js +47 -18
- package/dist/http.js.map +1 -1
- package/dist/index.d.ts +3 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -2
- package/dist/index.js.map +1 -1
- package/dist/internal/async.d.ts +2 -0
- package/dist/internal/async.d.ts.map +1 -1
- package/dist/internal/async.js +6 -0
- package/dist/internal/async.js.map +1 -1
- package/dist/internal/guards.d.ts +16 -0
- package/dist/internal/guards.d.ts.map +1 -1
- package/dist/internal/guards.js +22 -1
- package/dist/internal/guards.js.map +1 -1
- package/dist/internal/request.d.ts +41 -0
- package/dist/internal/request.d.ts.map +1 -0
- package/dist/internal/request.js +78 -0
- package/dist/internal/request.js.map +1 -0
- package/dist/internal/retry.d.ts +65 -0
- package/dist/internal/retry.d.ts.map +1 -0
- package/dist/internal/retry.js +126 -0
- package/dist/internal/retry.js.map +1 -0
- package/dist/internal/url.d.ts +9 -0
- package/dist/internal/url.d.ts.map +1 -1
- package/dist/internal/url.js +25 -0
- package/dist/internal/url.js.map +1 -1
- package/dist/internal/validate.d.ts +13 -0
- package/dist/internal/validate.d.ts.map +1 -0
- package/dist/internal/validate.js +36 -0
- package/dist/internal/validate.js.map +1 -0
- package/dist/linkPing.d.ts.map +1 -1
- package/dist/linkPing.js +6 -2
- package/dist/linkPing.js.map +1 -1
- package/dist/liveStatus.d.ts +106 -11
- package/dist/liveStatus.d.ts.map +1 -1
- package/dist/liveStatus.js +20 -3
- package/dist/liveStatus.js.map +1 -1
- package/dist/mcp.d.ts.map +1 -1
- package/dist/mcp.js +40 -10
- package/dist/mcp.js.map +1 -1
- package/dist/namespaces/actions.d.ts +50 -0
- package/dist/namespaces/actions.d.ts.map +1 -0
- package/dist/namespaces/actions.js +219 -0
- package/dist/namespaces/actions.js.map +1 -0
- package/dist/namespaces/approvals.d.ts +23 -0
- package/dist/namespaces/approvals.d.ts.map +1 -0
- package/dist/namespaces/approvals.js +78 -0
- package/dist/namespaces/approvals.js.map +1 -0
- package/dist/namespaces/attachments.d.ts +37 -0
- package/dist/namespaces/attachments.d.ts.map +1 -0
- package/dist/namespaces/attachments.js +91 -0
- package/dist/namespaces/attachments.js.map +1 -0
- package/dist/namespaces/auth.d.ts +58 -0
- package/dist/namespaces/auth.d.ts.map +1 -0
- package/dist/namespaces/auth.js +242 -0
- package/dist/namespaces/auth.js.map +1 -0
- package/dist/namespaces/directory.d.ts +10 -0
- package/dist/namespaces/directory.d.ts.map +1 -0
- package/dist/namespaces/directory.js +19 -0
- package/dist/namespaces/directory.js.map +1 -0
- package/dist/namespaces/handoffs.d.ts +47 -0
- package/dist/namespaces/handoffs.d.ts.map +1 -0
- package/dist/namespaces/handoffs.js +126 -0
- package/dist/namespaces/handoffs.js.map +1 -0
- package/dist/namespaces/inbox.d.ts +17 -0
- package/dist/namespaces/inbox.d.ts.map +1 -0
- package/dist/namespaces/inbox.js +192 -0
- package/dist/namespaces/inbox.js.map +1 -0
- package/dist/namespaces/live.d.ts +57 -0
- package/dist/namespaces/live.d.ts.map +1 -0
- package/dist/namespaces/live.js +116 -0
- package/dist/namespaces/live.js.map +1 -0
- package/dist/namespaces/notifications.d.ts +25 -0
- package/dist/namespaces/notifications.d.ts.map +1 -0
- package/dist/namespaces/notifications.js +128 -0
- package/dist/namespaces/notifications.js.map +1 -0
- package/dist/namespaces/profile.d.ts +19 -0
- package/dist/namespaces/profile.d.ts.map +1 -0
- package/dist/namespaces/profile.js +22 -0
- package/dist/namespaces/profile.js.map +1 -0
- package/dist/namespaces/questions.d.ts +41 -0
- package/dist/namespaces/questions.d.ts.map +1 -0
- package/dist/namespaces/questions.js +107 -0
- package/dist/namespaces/questions.js.map +1 -0
- package/dist/namespaces/rooms.d.ts +13 -0
- package/dist/namespaces/rooms.d.ts.map +1 -0
- package/dist/namespaces/rooms.js +41 -0
- package/dist/namespaces/rooms.js.map +1 -0
- package/dist/namespaces/webhooks.d.ts +11 -0
- package/dist/namespaces/webhooks.d.ts.map +1 -0
- package/dist/namespaces/webhooks.js +32 -0
- package/dist/namespaces/webhooks.js.map +1 -0
- package/dist/types/approvals.d.ts +62 -0
- package/dist/types/approvals.d.ts.map +1 -0
- package/dist/types/approvals.js +2 -0
- package/dist/types/approvals.js.map +1 -0
- package/dist/types/auth.d.ts +185 -0
- package/dist/types/auth.d.ts.map +1 -0
- package/dist/types/auth.js +2 -0
- package/dist/types/auth.js.map +1 -0
- package/dist/types/common.d.ts +43 -0
- package/dist/types/common.d.ts.map +1 -0
- package/dist/types/common.js +2 -0
- package/dist/types/common.js.map +1 -0
- package/dist/types/handoffs.d.ts +121 -0
- package/dist/types/handoffs.d.ts.map +1 -0
- package/dist/types/handoffs.js +2 -0
- package/dist/types/handoffs.js.map +1 -0
- package/dist/types/inbox.d.ts +51 -0
- package/dist/types/inbox.d.ts.map +1 -0
- package/dist/types/inbox.js +2 -0
- package/dist/types/inbox.js.map +1 -0
- package/dist/types/notifications.d.ts +376 -0
- package/dist/types/notifications.d.ts.map +1 -0
- package/dist/types/notifications.js +2 -0
- package/dist/types/notifications.js.map +1 -0
- package/dist/types/profile.d.ts +30 -0
- package/dist/types/profile.d.ts.map +1 -0
- package/dist/types/profile.js +3 -0
- package/dist/types/profile.js.map +1 -0
- package/dist/types/questions.d.ts +210 -0
- package/dist/types/questions.d.ts.map +1 -0
- package/dist/types/questions.js +2 -0
- package/dist/types/questions.js.map +1 -0
- package/dist/types/rooms.d.ts +163 -0
- package/dist/types/rooms.d.ts.map +1 -0
- package/dist/types/rooms.js +3 -0
- package/dist/types/rooms.js.map +1 -0
- package/dist/types.d.ts +9 -1035
- package/dist/types.d.ts.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/webhooks.d.ts +32 -5
- package/dist/webhooks.d.ts.map +1 -1
- package/dist/webhooks.js +44 -14
- package/dist/webhooks.js.map +1 -1
- package/package.json +4 -2
- package/src/client.ts +115 -0
- package/src/errors.ts +291 -0
- package/src/http.ts +225 -0
- package/src/index.ts +97 -0
- package/src/internal/async.ts +54 -0
- package/src/internal/guards.ts +129 -0
- package/src/internal/request.ts +97 -0
- package/src/internal/retry.ts +157 -0
- package/src/internal/url.ts +78 -0
- package/src/internal/validate.ts +42 -0
- package/src/linkPing.ts +56 -0
- package/src/liveStatus.ts +337 -0
- package/src/locationPing.ts +101 -0
- package/src/mcp.ts +161 -0
- package/src/namespaces/actions.ts +234 -0
- package/src/namespaces/approvals.ts +104 -0
- package/src/namespaces/attachments.ts +106 -0
- package/src/namespaces/auth.ts +284 -0
- package/src/namespaces/directory.ts +21 -0
- package/src/namespaces/handoffs.ts +160 -0
- package/src/namespaces/inbox.ts +253 -0
- package/src/namespaces/live.ts +134 -0
- package/src/namespaces/notifications.ts +152 -0
- package/src/namespaces/profile.ts +24 -0
- package/src/namespaces/questions.ts +133 -0
- package/src/namespaces/rooms.ts +53 -0
- package/src/namespaces/webhooks.ts +38 -0
- package/src/types/approvals.ts +67 -0
- package/src/types/auth.ts +202 -0
- package/src/types/common.ts +74 -0
- package/src/types/handoffs.ts +148 -0
- package/src/types/inbox.ts +64 -0
- package/src/types/notifications.ts +393 -0
- package/src/types/profile.ts +37 -0
- package/src/types/questions.ts +226 -0
- package/src/types/rooms.ts +169 -0
- package/src/types.ts +17 -0
- package/src/version.ts +2 -0
- package/src/webhooks.ts +373 -0
- package/dist/liveActivity.d.ts +0 -101
- package/dist/liveActivity.d.ts.map +0 -1
- package/dist/liveActivity.js +0 -83
- package/dist/liveActivity.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"async.js","sourceRoot":"","sources":["../../src/internal/async.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,MAAM,UAAU,cAAc,CAAC,OAAoB,EAAE,KAAmB;IACtE,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,OAAO,OAAO,CAAC;IACjB,CAAC;IACD,MAAM,KAAK,GAAI,WAA4E,CAAC,GAAG,CAAC;IAChG,IAAI,OAAO,KAAK,KAAK,UAAU,EAAE,CAAC;QAChC,OAAO,KAAK,CAAC,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC,CAAC;IACjC,CAAC;IACD,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAC;IACzC,MAAM,OAAO,GAAG,CAAC,CAAc,EAAQ,EAAE;QACvC,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;YAC/B,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;QAC7B,CAAC;IACH,CAAC,CAAC;IACF,KAAK,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,KAAK,CAAC,EAAE,CAAC;QACjC,IAAI,CAAC,CAAC,OAAO,EAAE,CAAC;YACd,OAAO,CAAC,CAAC,CAAC,CAAC;YACX,MAAM;QACR,CAAC;QACD,CAAC,CAAC,gBAAgB,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;IAChE,CAAC;IACD,OAAO,UAAU,CAAC,MAAM,CAAC;AAC3B,CAAC;AAED,2EAA2E;AAC3E,MAAM,UAAU,KAAK,CAAC,EAAU,EAAE,MAAoB;IACpD,OAAO,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,EAAE;QACnC,IAAI,MAAM,EAAE,OAAO,EAAE,CAAC;YACpB,OAAO,EAAE,CAAC;YACV,OAAO;QACT,CAAC;QACD,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE;YAC5B,OAAO,EAAE,CAAC;YACV,OAAO,EAAE,CAAC;QACZ,CAAC,EAAE,EAAE,CAAC,CAAC;QACP,MAAM,OAAO,GAAG,GAAS,EAAE;YACzB,OAAO,EAAE,CAAC;YACV,OAAO,EAAE,CAAC;QACZ,CAAC,CAAC;QACF,MAAM,OAAO,GAAG,GAAS,EAAE;YACzB,YAAY,CAAC,KAAK,CAAC,CAAC;YACpB,MAAM,EAAE,mBAAmB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QAChD,CAAC,CAAC;QACF,MAAM,EAAE,gBAAgB,CAAC,OAAO,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;IAC7D,CAAC,CAAC,CAAC;AACL,CAAC"}
|
|
1
|
+
{"version":3,"file":"async.js","sourceRoot":"","sources":["../../src/internal/async.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,MAAM,UAAU,cAAc,CAAC,OAAoB,EAAE,KAAmB;IACtE,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,OAAO,OAAO,CAAC;IACjB,CAAC;IACD,MAAM,KAAK,GAAI,WAA4E,CAAC,GAAG,CAAC;IAChG,IAAI,OAAO,KAAK,KAAK,UAAU,EAAE,CAAC;QAChC,OAAO,KAAK,CAAC,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC,CAAC;IACjC,CAAC;IACD,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAC;IACzC,MAAM,OAAO,GAAG,CAAC,CAAc,EAAQ,EAAE;QACvC,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;YAC/B,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;QAC7B,CAAC;IACH,CAAC,CAAC;IACF,KAAK,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,KAAK,CAAC,EAAE,CAAC;QACjC,IAAI,CAAC,CAAC,OAAO,EAAE,CAAC;YACd,OAAO,CAAC,CAAC,CAAC,CAAC;YACX,MAAM;QACR,CAAC;QACD,CAAC,CAAC,gBAAgB,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;IAChE,CAAC;IACD,OAAO,UAAU,CAAC,MAAM,CAAC;AAC3B,CAAC;AAED,2EAA2E;AAC3E,MAAM,UAAU,KAAK,CAAC,EAAU,EAAE,MAAoB;IACpD,OAAO,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,EAAE;QACnC,IAAI,MAAM,EAAE,OAAO,EAAE,CAAC;YACpB,OAAO,EAAE,CAAC;YACV,OAAO;QACT,CAAC;QACD,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE;YAC5B,OAAO,EAAE,CAAC;YACV,OAAO,EAAE,CAAC;QACZ,CAAC,EAAE,EAAE,CAAC,CAAC;QACP,MAAM,OAAO,GAAG,GAAS,EAAE;YACzB,OAAO,EAAE,CAAC;YACV,OAAO,EAAE,CAAC;QACZ,CAAC,CAAC;QACF,MAAM,OAAO,GAAG,GAAS,EAAE;YACzB,YAAY,CAAC,KAAK,CAAC,CAAC;YACpB,MAAM,EAAE,mBAAmB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QAChD,CAAC,CAAC;QACF,MAAM,EAAE,gBAAgB,CAAC,OAAO,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;IAC7D,CAAC,CAAC,CAAC;AACL,CAAC;AAED,oFAAoF;AACpF,MAAM,UAAU,cAAc,CAAC,MAAoB;IACjD,IAAI,MAAM,EAAE,OAAO,EAAE,CAAC;QACpB,MAAM,MAAM,CAAC,MAAM,IAAI,IAAI,KAAK,CAAC,SAAS,CAAC,CAAC;IAC9C,CAAC;AACH,CAAC"}
|
|
@@ -5,8 +5,24 @@ export declare const MAX_PRIVATE_PING_MESSAGE_LENGTH = 120;
|
|
|
5
5
|
export declare const MAX_PUBLIC_PING_MESSAGE_LENGTH = 160;
|
|
6
6
|
export declare const MAX_PING_TITLE_LENGTH = 40;
|
|
7
7
|
export declare function assertMaxLength(value: unknown, max: number, field: string): void;
|
|
8
|
+
/**
|
|
9
|
+
* Bytes a JSON string takes as PHP's default json_encode() writes it, which is
|
|
10
|
+
* what the server's 8 KB cap measures: every non-ASCII UTF-16 unit becomes a
|
|
11
|
+
* six-byte `\uXXXX` escape and `/` becomes `\/`. Non-Latin text is several
|
|
12
|
+
* times larger there than its UTF-8 size.
|
|
13
|
+
*/
|
|
14
|
+
export declare function serverJsonByteLength(json: string): number;
|
|
8
15
|
export declare function assertStructuredData(data: unknown): void;
|
|
9
16
|
export declare function assertActionNumber(n: unknown): void;
|
|
17
|
+
/**
|
|
18
|
+
* Normalize an idempotency key the way the server reads it
|
|
19
|
+
* (`RequestIdempotency::keyFrom`): trimmed, then 1–255 characters. It travels
|
|
20
|
+
* as the `Idempotency-Key` header, so it must also be printable ASCII (space
|
|
21
|
+
* included): fetch throws on a character outside Latin-1, which surfaced as a
|
|
22
|
+
* retryable `network_error` that every retry repeated, and a Latin-1 byte above
|
|
23
|
+
* 0x7E reaches the server as invalid UTF-8.
|
|
24
|
+
*/
|
|
25
|
+
export declare function normalizeIdempotencyKey(value: unknown, field?: string): string;
|
|
10
26
|
export declare function requireNonEmpty(value: unknown, field: string): void;
|
|
11
27
|
/** Validate before uppercasing so Unicode case expansion cannot become a code. */
|
|
12
28
|
export declare function normalizeRedeemCode(value: unknown): string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"guards.d.ts","sourceRoot":"","sources":["../../src/internal/guards.ts"],"names":[],"mappings":"AAEA,8FAA8F;AAC9F,eAAO,MAAM,cAAc,QAAW,CAAC;AACvC,eAAO,MAAM,aAAa,KAAK,CAAC;AAChC,eAAO,MAAM,+BAA+B,MAAM,CAAC;AACnD,eAAO,MAAM,8BAA8B,MAAM,CAAC;AAClD,eAAO,MAAM,qBAAqB,KAAK,CAAC;AAOxC,wBAAgB,eAAe,CAAC,KAAK,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAchF;
|
|
1
|
+
{"version":3,"file":"guards.d.ts","sourceRoot":"","sources":["../../src/internal/guards.ts"],"names":[],"mappings":"AAEA,8FAA8F;AAC9F,eAAO,MAAM,cAAc,QAAW,CAAC;AACvC,eAAO,MAAM,aAAa,KAAK,CAAC;AAChC,eAAO,MAAM,+BAA+B,MAAM,CAAC;AACnD,eAAO,MAAM,8BAA8B,MAAM,CAAC;AAClD,eAAO,MAAM,qBAAqB,KAAK,CAAC;AAOxC,wBAAgB,eAAe,CAAC,KAAK,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAchF;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CASzD;AAED,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,CAqBxD;AAED,wBAAgB,kBAAkB,CAAC,CAAC,EAAE,OAAO,GAAG,IAAI,CAOnD;AAMD;;;;;;;GAOG;AACH,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,OAAO,EAAE,KAAK,SAAmB,GAAG,MAAM,CAYxF;AAED,wBAAgB,eAAe,CAAC,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAInE;AAED,kFAAkF;AAClF,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAK1D;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAIxE"}
|
package/dist/internal/guards.js
CHANGED
|
@@ -27,7 +27,7 @@ export function assertMaxLength(value, max, field) {
|
|
|
27
27
|
* six-byte `\uXXXX` escape and `/` becomes `\/`. Non-Latin text is several
|
|
28
28
|
* times larger there than its UTF-8 size.
|
|
29
29
|
*/
|
|
30
|
-
function serverJsonByteLength(json) {
|
|
30
|
+
export function serverJsonByteLength(json) {
|
|
31
31
|
let bytes = 0;
|
|
32
32
|
for (let index = 0; index < json.length; index += 1) {
|
|
33
33
|
const code = json.charCodeAt(index);
|
|
@@ -71,6 +71,27 @@ export function assertActionNumber(n) {
|
|
|
71
71
|
throw new PingRoomError('action_number must be an integer 1–16.', { code: 'invalid_request' });
|
|
72
72
|
}
|
|
73
73
|
}
|
|
74
|
+
const MAX_IDEMPOTENCY_KEY_LENGTH = 255;
|
|
75
|
+
/** PHP trim()'s default set: what the server strips from both ends of a key. */
|
|
76
|
+
const SERVER_TRIM = /^[ \t\n\r\0\x0B]+|[ \t\n\r\0\x0B]+$/g;
|
|
77
|
+
/**
|
|
78
|
+
* Normalize an idempotency key the way the server reads it
|
|
79
|
+
* (`RequestIdempotency::keyFrom`): trimmed, then 1–255 characters. It travels
|
|
80
|
+
* as the `Idempotency-Key` header, so it must also be printable ASCII (space
|
|
81
|
+
* included): fetch throws on a character outside Latin-1, which surfaced as a
|
|
82
|
+
* retryable `network_error` that every retry repeated, and a Latin-1 byte above
|
|
83
|
+
* 0x7E reaches the server as invalid UTF-8.
|
|
84
|
+
*/
|
|
85
|
+
export function normalizeIdempotencyKey(value, field = 'idempotencyKey') {
|
|
86
|
+
if (typeof value !== 'string') {
|
|
87
|
+
throw new PingRoomError(`\`${field}\` must be a string.`, { code: 'invalid_request' });
|
|
88
|
+
}
|
|
89
|
+
const key = value.replace(SERVER_TRIM, '');
|
|
90
|
+
if (key.length < 1 || key.length > MAX_IDEMPOTENCY_KEY_LENGTH || !/^[\x20-\x7E]+$/.test(key)) {
|
|
91
|
+
throw new PingRoomError(`\`${field}\` must be 1–${MAX_IDEMPOTENCY_KEY_LENGTH} printable ASCII characters (letters, digits, punctuation or spaces).`, { code: 'invalid_request' });
|
|
92
|
+
}
|
|
93
|
+
return key;
|
|
94
|
+
}
|
|
74
95
|
export function requireNonEmpty(value, field) {
|
|
75
96
|
if (typeof value !== 'string' || value.trim() === '') {
|
|
76
97
|
throw new PingRoomError(`\`${field}\` is required.`, { code: 'invalid_request' });
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"guards.js","sourceRoot":"","sources":["../../src/internal/guards.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAE7C,8FAA8F;AAC9F,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,GAAG,IAAI,CAAC;AACvC,MAAM,CAAC,MAAM,aAAa,GAAG,EAAE,CAAC;AAChC,MAAM,CAAC,MAAM,+BAA+B,GAAG,GAAG,CAAC;AACnD,MAAM,CAAC,MAAM,8BAA8B,GAAG,GAAG,CAAC;AAClD,MAAM,CAAC,MAAM,qBAAqB,GAAG,EAAE,CAAC;AAExC,iFAAiF;AACjF,SAAS,eAAe,CAAC,KAAa;IACpC,OAAO,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC;AAClC,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,KAAc,EAAE,GAAW,EAAE,KAAa;IACxE,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;QAC1C,OAAO;IACT,CAAC;IACD,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC9B,MAAM,IAAI,aAAa,CAAC,KAAK,KAAK,sBAAsB,EAAE,EAAE,IAAI,EAAE,iBAAiB,EAAE,CAAC,CAAC;IACzF,CAAC;IACD,MAAM,MAAM,GAAG,eAAe,CAAC,KAAK,CAAC,CAAC;IACtC,IAAI,MAAM,GAAG,GAAG,EAAE,CAAC;QACjB,MAAM,IAAI,aAAa,CACrB,KAAK,KAAK,uBAAuB,GAAG,oBAAoB,MAAM,IAAI,EAClE,EAAE,IAAI,EAAE,iBAAiB,EAAE,CAC5B,CAAC;IACJ,CAAC;AACH,CAAC;AAED;;;;;GAKG;AACH,
|
|
1
|
+
{"version":3,"file":"guards.js","sourceRoot":"","sources":["../../src/internal/guards.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { PingInput } from '../types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Minimum spacing between the starts of two handoff-wait polls. The route is
|
|
4
|
+
* throttled at 30 requests a minute per human; a short or zero `timeout`
|
|
5
|
+
* would otherwise let one loop exhaust it.
|
|
6
|
+
*/
|
|
7
|
+
export declare const MIN_HANDOFF_POLL_INTERVAL_MS = 2100;
|
|
8
|
+
/**
|
|
9
|
+
* Minimum spacing between the starts of two `listen()` polls after an empty
|
|
10
|
+
* answer. `notifications/wait` is throttled at 30 requests a minute per human,
|
|
11
|
+
* shared with every other listener on the account (the CLI, other agents); a
|
|
12
|
+
* zero hold or a proxy that answers early would otherwise spin the loop and
|
|
13
|
+
* keep that bucket exhausted. Same floor as the handoff wait.
|
|
14
|
+
*/
|
|
15
|
+
export declare const MIN_LISTEN_POLL_INTERVAL_MS = 2100;
|
|
16
|
+
/**
|
|
17
|
+
* Minimum spacing between the starts of two approval or question wait polls.
|
|
18
|
+
* The server normally holds each one, but a proxy or a zero hold that answers
|
|
19
|
+
* `pending` at once would otherwise spin the loop and keep that route's
|
|
20
|
+
* 30-per-minute bucket for the human exhausted. Same floor as the handoff wait and the
|
|
21
|
+
* CLI (2100 ms keeps one loop under 30 a minute).
|
|
22
|
+
*/
|
|
23
|
+
export declare const MIN_WAIT_POLL_INTERVAL_MS = 2100;
|
|
24
|
+
export declare function enc(segment: string): string;
|
|
25
|
+
/**
|
|
26
|
+
* Lift the SDK-only `idempotencyKey` out of an input and into the
|
|
27
|
+
* `Idempotency-Key` header the server reads. The server trims the key and
|
|
28
|
+
* accepts 1–255 characters; as a header it must also be printable ASCII.
|
|
29
|
+
*/
|
|
30
|
+
export declare function splitIdempotencyKey<T extends {
|
|
31
|
+
idempotencyKey?: string;
|
|
32
|
+
}>(input: T): {
|
|
33
|
+
body: Omit<T, 'idempotencyKey'>;
|
|
34
|
+
headers?: Record<string, string>;
|
|
35
|
+
};
|
|
36
|
+
/** `onRetry`, when given, must be callable: a TypeError mid-outage would hide the real failure. */
|
|
37
|
+
export declare function assertOnRetry(onRetry: unknown): void;
|
|
38
|
+
export declare function dropUndefined<T extends Record<string, unknown>>(obj: T): Partial<T>;
|
|
39
|
+
export declare function assertPing(ping: PingInput): void;
|
|
40
|
+
export declare function waitTimeoutMs(seconds: number | undefined): number;
|
|
41
|
+
//# sourceMappingURL=request.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"request.d.ts","sourceRoot":"","sources":["../../src/internal/request.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAM7C;;;;GAIG;AACH,eAAO,MAAM,4BAA4B,OAAO,CAAC;AACjD;;;;;;GAMG;AACH,eAAO,MAAM,2BAA2B,OAA+B,CAAC;AACxE;;;;;;GAMG;AACH,eAAO,MAAM,yBAAyB,OAA+B,CAAC;AAEtE,wBAAgB,GAAG,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAQ3C;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,CAAC,SAAS;IAAE,cAAc,CAAC,EAAE,MAAM,CAAA;CAAE,EACvE,KAAK,EAAE,CAAC,GACP;IAAE,IAAI,EAAE,IAAI,CAAC,CAAC,EAAE,gBAAgB,CAAC,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAAE,CAMvE;AAED,mGAAmG;AACnG,wBAAgB,aAAa,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAIpD;AAED,wBAAgB,aAAa,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,GAAG,EAAE,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAQnF;AAED,wBAAgB,UAAU,CAAC,IAAI,EAAE,SAAS,GAAG,IAAI,CAQhD;AAED,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAEjE"}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
// Request building shared by the PingRoom namespaces: path segments, bodies,
|
|
2
|
+
// the Idempotency-Key header, ping input checks and long-poll timing.
|
|
3
|
+
import { PingRoomError } from '../errors.js';
|
|
4
|
+
import { assertActionNumber, assertMaxLength, assertStructuredData, MAX_PING_TITLE_LENGTH, MAX_PUBLIC_PING_MESSAGE_LENGTH, normalizeIdempotencyKey, requireNonEmpty, } from './guards.js';
|
|
5
|
+
/** Extra wall-clock allowance over the server's hold window for long-poll calls. */
|
|
6
|
+
const LONG_POLL_BUFFER_MS = 10_000;
|
|
7
|
+
const DEFAULT_WAIT_SECONDS = 20;
|
|
8
|
+
/**
|
|
9
|
+
* Minimum spacing between the starts of two handoff-wait polls. The route is
|
|
10
|
+
* throttled at 30 requests a minute per human; a short or zero `timeout`
|
|
11
|
+
* would otherwise let one loop exhaust it.
|
|
12
|
+
*/
|
|
13
|
+
export const MIN_HANDOFF_POLL_INTERVAL_MS = 2100;
|
|
14
|
+
/**
|
|
15
|
+
* Minimum spacing between the starts of two `listen()` polls after an empty
|
|
16
|
+
* answer. `notifications/wait` is throttled at 30 requests a minute per human,
|
|
17
|
+
* shared with every other listener on the account (the CLI, other agents); a
|
|
18
|
+
* zero hold or a proxy that answers early would otherwise spin the loop and
|
|
19
|
+
* keep that bucket exhausted. Same floor as the handoff wait.
|
|
20
|
+
*/
|
|
21
|
+
export const MIN_LISTEN_POLL_INTERVAL_MS = MIN_HANDOFF_POLL_INTERVAL_MS;
|
|
22
|
+
/**
|
|
23
|
+
* Minimum spacing between the starts of two approval or question wait polls.
|
|
24
|
+
* The server normally holds each one, but a proxy or a zero hold that answers
|
|
25
|
+
* `pending` at once would otherwise spin the loop and keep that route's
|
|
26
|
+
* 30-per-minute bucket for the human exhausted. Same floor as the handoff wait and the
|
|
27
|
+
* CLI (2100 ms keeps one loop under 30 a minute).
|
|
28
|
+
*/
|
|
29
|
+
export const MIN_WAIT_POLL_INTERVAL_MS = MIN_HANDOFF_POLL_INTERVAL_MS;
|
|
30
|
+
export function enc(segment) {
|
|
31
|
+
// encodeURIComponent leaves `.` and `..` alone, and URL parsing then
|
|
32
|
+
// resolves them as dot segments: `live.get('AB12', '..')` would request the
|
|
33
|
+
// room itself. No id is empty or a dot segment, so refuse them.
|
|
34
|
+
if (segment === '' || segment === '.' || segment === '..') {
|
|
35
|
+
throw new PingRoomError('A path parameter may not be empty, `.` or `..`.', { code: 'invalid_request' });
|
|
36
|
+
}
|
|
37
|
+
return encodeURIComponent(segment);
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Lift the SDK-only `idempotencyKey` out of an input and into the
|
|
41
|
+
* `Idempotency-Key` header the server reads. The server trims the key and
|
|
42
|
+
* accepts 1–255 characters; as a header it must also be printable ASCII.
|
|
43
|
+
*/
|
|
44
|
+
export function splitIdempotencyKey(input) {
|
|
45
|
+
const { idempotencyKey, ...body } = input;
|
|
46
|
+
if (idempotencyKey === undefined) {
|
|
47
|
+
return { body };
|
|
48
|
+
}
|
|
49
|
+
return { body, headers: { 'Idempotency-Key': normalizeIdempotencyKey(idempotencyKey) } };
|
|
50
|
+
}
|
|
51
|
+
/** `onRetry`, when given, must be callable: a TypeError mid-outage would hide the real failure. */
|
|
52
|
+
export function assertOnRetry(onRetry) {
|
|
53
|
+
if (onRetry !== undefined && typeof onRetry !== 'function') {
|
|
54
|
+
throw new PingRoomError('`onRetry` must be a function.', { code: 'invalid_request' });
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
export function dropUndefined(obj) {
|
|
58
|
+
const out = {};
|
|
59
|
+
for (const [k, v] of Object.entries(obj)) {
|
|
60
|
+
if (v !== undefined) {
|
|
61
|
+
out[k] = v;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
return out;
|
|
65
|
+
}
|
|
66
|
+
export function assertPing(ping) {
|
|
67
|
+
requireNonEmpty(ping.message, 'message');
|
|
68
|
+
// The invite code does not expose room visibility. Permit the public-room
|
|
69
|
+
// ceiling locally; Laravel applies 120 for private and 160 for public rooms.
|
|
70
|
+
assertMaxLength(ping.message, MAX_PUBLIC_PING_MESSAGE_LENGTH, 'message');
|
|
71
|
+
assertMaxLength(ping.title, MAX_PING_TITLE_LENGTH, 'title');
|
|
72
|
+
assertActionNumber(ping.action_number);
|
|
73
|
+
assertStructuredData(ping.data);
|
|
74
|
+
}
|
|
75
|
+
export function waitTimeoutMs(seconds) {
|
|
76
|
+
return (seconds ?? DEFAULT_WAIT_SECONDS) * 1000 + LONG_POLL_BUFFER_MS;
|
|
77
|
+
}
|
|
78
|
+
//# sourceMappingURL=request.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"request.js","sourceRoot":"","sources":["../../src/internal/request.ts"],"names":[],"mappings":"AAAA,6EAA6E;AAC7E,sEAAsE;AAEtE,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC7C,OAAO,EACL,kBAAkB,EAClB,eAAe,EACf,oBAAoB,EACpB,qBAAqB,EACrB,8BAA8B,EAC9B,uBAAuB,EACvB,eAAe,GAChB,MAAM,aAAa,CAAC;AAGrB,oFAAoF;AACpF,MAAM,mBAAmB,GAAG,MAAM,CAAC;AACnC,MAAM,oBAAoB,GAAG,EAAE,CAAC;AAEhC;;;;GAIG;AACH,MAAM,CAAC,MAAM,4BAA4B,GAAG,IAAI,CAAC;AACjD;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,2BAA2B,GAAG,4BAA4B,CAAC;AACxE;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,yBAAyB,GAAG,4BAA4B,CAAC;AAEtE,MAAM,UAAU,GAAG,CAAC,OAAe;IACjC,qEAAqE;IACrE,4EAA4E;IAC5E,gEAAgE;IAChE,IAAI,OAAO,KAAK,EAAE,IAAI,OAAO,KAAK,GAAG,IAAI,OAAO,KAAK,IAAI,EAAE,CAAC;QAC1D,MAAM,IAAI,aAAa,CAAC,iDAAiD,EAAE,EAAE,IAAI,EAAE,iBAAiB,EAAE,CAAC,CAAC;IAC1G,CAAC;IACD,OAAO,kBAAkB,CAAC,OAAO,CAAC,CAAC;AACrC,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,mBAAmB,CACjC,KAAQ;IAER,MAAM,EAAE,cAAc,EAAE,GAAG,IAAI,EAAE,GAAG,KAAK,CAAC;IAC1C,IAAI,cAAc,KAAK,SAAS,EAAE,CAAC;QACjC,OAAO,EAAE,IAAI,EAAE,CAAC;IAClB,CAAC;IACD,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,iBAAiB,EAAE,uBAAuB,CAAC,cAAc,CAAC,EAAE,EAAE,CAAC;AAC3F,CAAC;AAED,mGAAmG;AACnG,MAAM,UAAU,aAAa,CAAC,OAAgB;IAC5C,IAAI,OAAO,KAAK,SAAS,IAAI,OAAO,OAAO,KAAK,UAAU,EAAE,CAAC;QAC3D,MAAM,IAAI,aAAa,CAAC,+BAA+B,EAAE,EAAE,IAAI,EAAE,iBAAiB,EAAE,CAAC,CAAC;IACxF,CAAC;AACH,CAAC;AAED,MAAM,UAAU,aAAa,CAAoC,GAAM;IACrE,MAAM,GAAG,GAA4B,EAAE,CAAC;IACxC,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;QACzC,IAAI,CAAC,KAAK,SAAS,EAAE,CAAC;YACpB,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;QACb,CAAC;IACH,CAAC;IACD,OAAO,GAAiB,CAAC;AAC3B,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,IAAe;IACxC,eAAe,CAAC,IAAI,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;IACzC,0EAA0E;IAC1E,6EAA6E;IAC7E,eAAe,CAAC,IAAI,CAAC,OAAO,EAAE,8BAA8B,EAAE,SAAS,CAAC,CAAC;IACzE,eAAe,CAAC,IAAI,CAAC,KAAK,EAAE,qBAAqB,EAAE,OAAO,CAAC,CAAC;IAC5D,kBAAkB,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;IACvC,oBAAoB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAClC,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,OAA2B;IACvD,OAAO,CAAC,OAAO,IAAI,oBAAoB,CAAC,GAAG,IAAI,GAAG,mBAAmB,CAAC;AACxE,CAAC"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { PingRoomError } from '../errors.js';
|
|
2
|
+
/** First retry delay after a transient failure, in ms. */
|
|
3
|
+
export declare const TRANSIENT_BACKOFF_BASE_MS = 1000;
|
|
4
|
+
/**
|
|
5
|
+
* The smallest backoff base, whatever a caller asks for. A persistent failure
|
|
6
|
+
* would otherwise retry in a tight loop (a base of 0 never grows at all)
|
|
7
|
+
* against wait routes limited to 30 requests a minute each.
|
|
8
|
+
*/
|
|
9
|
+
export declare const MIN_TRANSIENT_BACKOFF_MS = 250;
|
|
10
|
+
/** Ceiling on the exponential backoff (a server Retry-After may ask for longer). */
|
|
11
|
+
export declare const TRANSIENT_BACKOFF_CAP_MS = 30000;
|
|
12
|
+
/**
|
|
13
|
+
* How long past the last-seen `expires_at` a wait keeps retrying an
|
|
14
|
+
* unreachable API. The server reports `expired` once expires_at passes, so
|
|
15
|
+
* after this the only outcome left is one that cannot be read. Covers clock
|
|
16
|
+
* skew. Same bound as the CLI.
|
|
17
|
+
*/
|
|
18
|
+
export declare const WAIT_EXPIRY_GRACE_MS: number;
|
|
19
|
+
/** The bound on an unbroken outage while no response has carried `expires_at`. */
|
|
20
|
+
export declare const WAIT_UNKNOWN_EXPIRY_OUTAGE_MS: number;
|
|
21
|
+
/**
|
|
22
|
+
* A failure a read loop may retry: a dropped connection, a request deadline,
|
|
23
|
+
* a 429 (each wait route has its own 30/min bucket per human), or a 5xx.
|
|
24
|
+
* Everything else — 401/403/404/422, a refused redirect, a malformed response —
|
|
25
|
+
* is permanent and must surface to the caller.
|
|
26
|
+
*/
|
|
27
|
+
export declare function isTransientError(error: unknown): error is PingRoomError;
|
|
28
|
+
/**
|
|
29
|
+
* Delay before retrying after the `failures`-th consecutive transient failure:
|
|
30
|
+
* exponential from `baseMs`, capped at 30 s. A server `retryAfter` replaces the
|
|
31
|
+
* exponential step, but is never waited for less than `baseMs`. A `baseMs`
|
|
32
|
+
* below {@link MIN_TRANSIENT_BACKOFF_MS} is raised to it.
|
|
33
|
+
*/
|
|
34
|
+
export declare function transientDelayMs(error: PingRoomError, failures: number, baseMs?: number): number;
|
|
35
|
+
export interface PollUntilSettledOptions<T> {
|
|
36
|
+
/** One bounded long-poll. Its errors are retried only when transient. */
|
|
37
|
+
poll: () => Promise<unknown>;
|
|
38
|
+
/** Check the response's minimal shape; throw `invalid_response` otherwise. */
|
|
39
|
+
validate: (value: unknown) => T;
|
|
40
|
+
/** True once the validated value is terminal. */
|
|
41
|
+
settled: (value: T) => boolean;
|
|
42
|
+
signal?: AbortSignal;
|
|
43
|
+
/** Minimum time between the starts of two polls, in ms. Default 0. */
|
|
44
|
+
minIntervalMs?: number;
|
|
45
|
+
/** Read `expires_at` (an ISO time) from a validated response; it bounds an outage. */
|
|
46
|
+
expiresAt?: (value: T) => unknown;
|
|
47
|
+
/** Names what is waited on in the give-up message, e.g. `approval a1`. */
|
|
48
|
+
what: string;
|
|
49
|
+
/** Called before each retry of a transient failure; `attempt` counts consecutive failures from 1. */
|
|
50
|
+
onRetry?: (error: PingRoomError, attempt: number) => void;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* The shared human-in-the-loop wait loop. Polls until a validated response is
|
|
54
|
+
* terminal; retries transient failures with backoff; rejects with the
|
|
55
|
+
* signal's reason once it aborts. A response that fails validation is never
|
|
56
|
+
* returned as an outcome.
|
|
57
|
+
*
|
|
58
|
+
* The retries are bounded even without a signal. Once only failures have come
|
|
59
|
+
* back since the last valid response, and the last-seen `expires_at` plus
|
|
60
|
+
* {@link WAIT_EXPIRY_GRACE_MS} has passed (or, before any `expires_at` was
|
|
61
|
+
* seen, after {@link WAIT_UNKNOWN_EXPIRY_OUTAGE_MS} of unbroken failures), the
|
|
62
|
+
* wait rejects with `unavailable`, the last failure as its `cause`.
|
|
63
|
+
*/
|
|
64
|
+
export declare function pollUntilSettled<T>(options: PollUntilSettledOptions<T>): Promise<T>;
|
|
65
|
+
//# sourceMappingURL=retry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"retry.d.ts","sourceRoot":"","sources":["../../src/internal/retry.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAG7C,0DAA0D;AAC1D,eAAO,MAAM,yBAAyB,OAAO,CAAC;AAC9C;;;;GAIG;AACH,eAAO,MAAM,wBAAwB,MAAM,CAAC;AAC5C,oFAAoF;AACpF,eAAO,MAAM,wBAAwB,QAAS,CAAC;AAG/C;;;;;GAKG;AACH,eAAO,MAAM,oBAAoB,QAAa,CAAC;AAC/C,kFAAkF;AAClF,eAAO,MAAM,6BAA6B,QAAc,CAAC;AAEzD;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,aAAa,CAQvE;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,aAAa,EACpB,QAAQ,EAAE,MAAM,EAChB,MAAM,GAAE,MAAkC,GACzC,MAAM,CAUR;AAED,MAAM,WAAW,uBAAuB,CAAC,CAAC;IACxC,yEAAyE;IACzE,IAAI,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,CAAC;IAC7B,8EAA8E;IAC9E,QAAQ,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,CAAC,CAAC;IAChC,iDAAiD;IACjD,OAAO,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,OAAO,CAAC;IAC/B,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,sEAAsE;IACtE,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,sFAAsF;IACtF,SAAS,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,OAAO,CAAC;IAClC,0EAA0E;IAC1E,IAAI,EAAE,MAAM,CAAC;IACb,qGAAqG;IACrG,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,aAAa,EAAE,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;CAC3D;AAeD;;;;;;;;;;;GAWG;AACH,wBAAsB,gBAAgB,CAAC,CAAC,EAAE,OAAO,EAAE,uBAAuB,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAkDzF"}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { PingRoomError } from '../errors.js';
|
|
2
|
+
import { sleep, throwIfAborted } from './async.js';
|
|
3
|
+
/** First retry delay after a transient failure, in ms. */
|
|
4
|
+
export const TRANSIENT_BACKOFF_BASE_MS = 1000;
|
|
5
|
+
/**
|
|
6
|
+
* The smallest backoff base, whatever a caller asks for. A persistent failure
|
|
7
|
+
* would otherwise retry in a tight loop (a base of 0 never grows at all)
|
|
8
|
+
* against wait routes limited to 30 requests a minute each.
|
|
9
|
+
*/
|
|
10
|
+
export const MIN_TRANSIENT_BACKOFF_MS = 250;
|
|
11
|
+
/** Ceiling on the exponential backoff (a server Retry-After may ask for longer). */
|
|
12
|
+
export const TRANSIENT_BACKOFF_CAP_MS = 30_000;
|
|
13
|
+
/** setTimeout fires immediately above this, so no delay may exceed it. */
|
|
14
|
+
const MAX_TIMER_MS = 2_147_483_647;
|
|
15
|
+
/**
|
|
16
|
+
* How long past the last-seen `expires_at` a wait keeps retrying an
|
|
17
|
+
* unreachable API. The server reports `expired` once expires_at passes, so
|
|
18
|
+
* after this the only outcome left is one that cannot be read. Covers clock
|
|
19
|
+
* skew. Same bound as the CLI.
|
|
20
|
+
*/
|
|
21
|
+
export const WAIT_EXPIRY_GRACE_MS = 5 * 60_000;
|
|
22
|
+
/** The bound on an unbroken outage while no response has carried `expires_at`. */
|
|
23
|
+
export const WAIT_UNKNOWN_EXPIRY_OUTAGE_MS = 15 * 60_000;
|
|
24
|
+
/**
|
|
25
|
+
* A failure a read loop may retry: a dropped connection, a request deadline,
|
|
26
|
+
* a 429 (each wait route has its own 30/min bucket per human), or a 5xx.
|
|
27
|
+
* Everything else — 401/403/404/422, a refused redirect, a malformed response —
|
|
28
|
+
* is permanent and must surface to the caller.
|
|
29
|
+
*/
|
|
30
|
+
export function isTransientError(error) {
|
|
31
|
+
return (error instanceof PingRoomError
|
|
32
|
+
&& (error.code === 'network_error'
|
|
33
|
+
|| error.code === 'timeout'
|
|
34
|
+
|| error.status === 429
|
|
35
|
+
|| error.status >= 500));
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Delay before retrying after the `failures`-th consecutive transient failure:
|
|
39
|
+
* exponential from `baseMs`, capped at 30 s. A server `retryAfter` replaces the
|
|
40
|
+
* exponential step, but is never waited for less than `baseMs`. A `baseMs`
|
|
41
|
+
* below {@link MIN_TRANSIENT_BACKOFF_MS} is raised to it.
|
|
42
|
+
*/
|
|
43
|
+
export function transientDelayMs(error, failures, baseMs = TRANSIENT_BACKOFF_BASE_MS) {
|
|
44
|
+
const requested = Number.isFinite(baseMs) && baseMs >= 0 ? baseMs : TRANSIENT_BACKOFF_BASE_MS;
|
|
45
|
+
const base = Math.max(MIN_TRANSIENT_BACKOFF_MS, requested);
|
|
46
|
+
const retryAfter = error.retryAfter;
|
|
47
|
+
if (typeof retryAfter === 'number' && Number.isFinite(retryAfter) && retryAfter >= 0) {
|
|
48
|
+
return Math.min(MAX_TIMER_MS, Math.max(retryAfter * 1000, base));
|
|
49
|
+
}
|
|
50
|
+
// Enough doublings to pass the cap from any base; also keeps 2 ** step finite.
|
|
51
|
+
const step = Math.min(Math.max(0, failures - 1), 30);
|
|
52
|
+
return Math.min(MAX_TIMER_MS, Math.max(base, TRANSIENT_BACKOFF_CAP_MS), base * 2 ** step);
|
|
53
|
+
}
|
|
54
|
+
function timeOf(value) {
|
|
55
|
+
const at = typeof value === 'string' ? Date.parse(value) : NaN;
|
|
56
|
+
return Number.isFinite(at) ? at : null;
|
|
57
|
+
}
|
|
58
|
+
function unavailable(last, since, what) {
|
|
59
|
+
const reason = last.status > 0 ? `HTTP ${last.status}` : (last.code ?? 'network error');
|
|
60
|
+
return new PingRoomError(`PingRoom unavailable since ${new Date(since).toISOString()} (${reason}); stopped waiting for ${what}.`, { code: 'unavailable', cause: last });
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* The shared human-in-the-loop wait loop. Polls until a validated response is
|
|
64
|
+
* terminal; retries transient failures with backoff; rejects with the
|
|
65
|
+
* signal's reason once it aborts. A response that fails validation is never
|
|
66
|
+
* returned as an outcome.
|
|
67
|
+
*
|
|
68
|
+
* The retries are bounded even without a signal. Once only failures have come
|
|
69
|
+
* back since the last valid response, and the last-seen `expires_at` plus
|
|
70
|
+
* {@link WAIT_EXPIRY_GRACE_MS} has passed (or, before any `expires_at` was
|
|
71
|
+
* seen, after {@link WAIT_UNKNOWN_EXPIRY_OUTAGE_MS} of unbroken failures), the
|
|
72
|
+
* wait rejects with `unavailable`, the last failure as its `cause`.
|
|
73
|
+
*/
|
|
74
|
+
export async function pollUntilSettled(options) {
|
|
75
|
+
const { poll, validate, settled, signal, minIntervalMs = 0, expiresAt, what, onRetry } = options;
|
|
76
|
+
let failures = 0;
|
|
77
|
+
let failingSince = null;
|
|
78
|
+
// expires_at plus grace, from the last valid response that carried one.
|
|
79
|
+
let deadline = null;
|
|
80
|
+
for (;;) {
|
|
81
|
+
throwIfAborted(signal);
|
|
82
|
+
const startedAt = Date.now();
|
|
83
|
+
let value;
|
|
84
|
+
try {
|
|
85
|
+
value = validate(await poll());
|
|
86
|
+
}
|
|
87
|
+
catch (error) {
|
|
88
|
+
throwIfAborted(signal);
|
|
89
|
+
if (!isTransientError(error)) {
|
|
90
|
+
throw error;
|
|
91
|
+
}
|
|
92
|
+
failures += 1;
|
|
93
|
+
failingSince ??= Date.now();
|
|
94
|
+
const remaining = (deadline ?? failingSince + WAIT_UNKNOWN_EXPIRY_OUTAGE_MS) - Date.now();
|
|
95
|
+
if (remaining <= 0) {
|
|
96
|
+
throw unavailable(error, failingSince, what);
|
|
97
|
+
}
|
|
98
|
+
onRetry?.(error, failures);
|
|
99
|
+
// A fast failure still consumes a poll. Keep retries spaced even when a
|
|
100
|
+
// pending response between failures resets the exponential backoff.
|
|
101
|
+
const delay = Math.max(transientDelayMs(error, failures), minIntervalMs - (Date.now() - startedAt));
|
|
102
|
+
// Do not retry earlier than the interval or Retry-After just to fit the
|
|
103
|
+
// outage bound. Wait out the budget, then stop without another request.
|
|
104
|
+
if (delay > remaining) {
|
|
105
|
+
await sleep(remaining, signal);
|
|
106
|
+
throwIfAborted(signal);
|
|
107
|
+
throw unavailable(error, failingSince, what);
|
|
108
|
+
}
|
|
109
|
+
await sleep(delay, signal);
|
|
110
|
+
continue;
|
|
111
|
+
}
|
|
112
|
+
failures = 0;
|
|
113
|
+
failingSince = null;
|
|
114
|
+
const expiry = expiresAt ? timeOf(expiresAt(value)) : null;
|
|
115
|
+
if (expiry !== null) {
|
|
116
|
+
deadline = expiry + WAIT_EXPIRY_GRACE_MS;
|
|
117
|
+
}
|
|
118
|
+
if (settled(value)) {
|
|
119
|
+
return value;
|
|
120
|
+
}
|
|
121
|
+
// An injected transport can resolve pending polls immediately. Yield
|
|
122
|
+
// between them so timer-driven cancellation and deadlines can run.
|
|
123
|
+
await sleep(Math.max(0, minIntervalMs - (Date.now() - startedAt)), signal);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
//# sourceMappingURL=retry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"retry.js","sourceRoot":"","sources":["../../src/internal/retry.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC7C,OAAO,EAAE,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAEnD,0DAA0D;AAC1D,MAAM,CAAC,MAAM,yBAAyB,GAAG,IAAI,CAAC;AAC9C;;;;GAIG;AACH,MAAM,CAAC,MAAM,wBAAwB,GAAG,GAAG,CAAC;AAC5C,oFAAoF;AACpF,MAAM,CAAC,MAAM,wBAAwB,GAAG,MAAM,CAAC;AAC/C,0EAA0E;AAC1E,MAAM,YAAY,GAAG,aAAa,CAAC;AACnC;;;;;GAKG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAAC,GAAG,MAAM,CAAC;AAC/C,kFAAkF;AAClF,MAAM,CAAC,MAAM,6BAA6B,GAAG,EAAE,GAAG,MAAM,CAAC;AAEzD;;;;;GAKG;AACH,MAAM,UAAU,gBAAgB,CAAC,KAAc;IAC7C,OAAO,CACL,KAAK,YAAY,aAAa;WAC3B,CAAC,KAAK,CAAC,IAAI,KAAK,eAAe;eAC7B,KAAK,CAAC,IAAI,KAAK,SAAS;eACxB,KAAK,CAAC,MAAM,KAAK,GAAG;eACpB,KAAK,CAAC,MAAM,IAAI,GAAG,CAAC,CAC1B,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,gBAAgB,CAC9B,KAAoB,EACpB,QAAgB,EAChB,SAAiB,yBAAyB;IAE1C,MAAM,SAAS,GAAG,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,MAAM,IAAI,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,yBAAyB,CAAC;IAC9F,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,wBAAwB,EAAE,SAAS,CAAC,CAAC;IAC3D,MAAM,UAAU,GAAG,KAAK,CAAC,UAAU,CAAC;IACpC,IAAI,OAAO,UAAU,KAAK,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC,UAAU,CAAC,IAAI,UAAU,IAAI,CAAC,EAAE,CAAC;QACrF,OAAO,IAAI,CAAC,GAAG,CAAC,YAAY,EAAE,IAAI,CAAC,GAAG,CAAC,UAAU,GAAG,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC;IACnE,CAAC;IACD,+EAA+E;IAC/E,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,QAAQ,GAAG,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IACrD,OAAO,IAAI,CAAC,GAAG,CAAC,YAAY,EAAE,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,wBAAwB,CAAC,EAAE,IAAI,GAAG,CAAC,IAAI,IAAI,CAAC,CAAC;AAC5F,CAAC;AAoBD,SAAS,MAAM,CAAC,KAAc;IAC5B,MAAM,EAAE,GAAG,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC;IAC/D,OAAO,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;AACzC,CAAC;AAED,SAAS,WAAW,CAAC,IAAmB,EAAE,KAAa,EAAE,IAAY;IACnE,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,IAAI,eAAe,CAAC,CAAC;IACxF,OAAO,IAAI,aAAa,CACtB,8BAA8B,IAAI,IAAI,CAAC,KAAK,CAAC,CAAC,WAAW,EAAE,KAAK,MAAM,0BAA0B,IAAI,GAAG,EACvG,EAAE,IAAI,EAAE,aAAa,EAAE,KAAK,EAAE,IAAI,EAAE,CACrC,CAAC;AACJ,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAI,OAAmC;IAC3E,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,EAAE,aAAa,GAAG,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC;IACjG,IAAI,QAAQ,GAAG,CAAC,CAAC;IACjB,IAAI,YAAY,GAAkB,IAAI,CAAC;IACvC,wEAAwE;IACxE,IAAI,QAAQ,GAAkB,IAAI,CAAC;IACnC,SAAS,CAAC;QACR,cAAc,CAAC,MAAM,CAAC,CAAC;QACvB,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAC7B,IAAI,KAAQ,CAAC;QACb,IAAI,CAAC;YACH,KAAK,GAAG,QAAQ,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC;QACjC,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,cAAc,CAAC,MAAM,CAAC,CAAC;YACvB,IAAI,CAAC,gBAAgB,CAAC,KAAK,CAAC,EAAE,CAAC;gBAC7B,MAAM,KAAK,CAAC;YACd,CAAC;YACD,QAAQ,IAAI,CAAC,CAAC;YACd,YAAY,KAAK,IAAI,CAAC,GAAG,EAAE,CAAC;YAC5B,MAAM,SAAS,GAAG,CAAC,QAAQ,IAAI,YAAY,GAAG,6BAA6B,CAAC,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;YAC1F,IAAI,SAAS,IAAI,CAAC,EAAE,CAAC;gBACnB,MAAM,WAAW,CAAC,KAAK,EAAE,YAAY,EAAE,IAAI,CAAC,CAAC;YAC/C,CAAC;YACD,OAAO,EAAE,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;YAC3B,wEAAwE;YACxE,oEAAoE;YACpE,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,gBAAgB,CAAC,KAAK,EAAE,QAAQ,CAAC,EAAE,aAAa,GAAG,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,CAAC,CAAC,CAAC;YACpG,wEAAwE;YACxE,wEAAwE;YACxE,IAAI,KAAK,GAAG,SAAS,EAAE,CAAC;gBACtB,MAAM,KAAK,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;gBAC/B,cAAc,CAAC,MAAM,CAAC,CAAC;gBACvB,MAAM,WAAW,CAAC,KAAK,EAAE,YAAY,EAAE,IAAI,CAAC,CAAC;YAC/C,CAAC;YACD,MAAM,KAAK,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;YAC3B,SAAS;QACX,CAAC;QACD,QAAQ,GAAG,CAAC,CAAC;QACb,YAAY,GAAG,IAAI,CAAC;QACpB,MAAM,MAAM,GAAG,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;QAC3D,IAAI,MAAM,KAAK,IAAI,EAAE,CAAC;YACpB,QAAQ,GAAG,MAAM,GAAG,oBAAoB,CAAC;QAC3C,CAAC;QACD,IAAI,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;YACnB,OAAO,KAAK,CAAC;QACf,CAAC;QACD,qEAAqE;QACrE,mEAAmE;QACnE,MAAM,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,aAAa,GAAG,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;IAC7E,CAAC;AACH,CAAC"}
|
package/dist/internal/url.d.ts
CHANGED
|
@@ -12,4 +12,13 @@ export declare function assertSecureUrl(rawUrl: string, allowInsecure: boolean):
|
|
|
12
12
|
* errors, so a message copied from one must not reach a caller's logs as-is.
|
|
13
13
|
*/
|
|
14
14
|
export declare function redactUrlInMessage(message: string, url: URL, rawUrl: string): string;
|
|
15
|
+
/**
|
|
16
|
+
* Every request goes out with `redirect: 'manual'` (Cloudflare Workers throw
|
|
17
|
+
* on `'error'`), so a redirect comes back as a response instead of being
|
|
18
|
+
* followed. Refuse it: a 307/308 would replay pairing secrets, uploaded bytes
|
|
19
|
+
* or a webhook body to whatever origin `Location` names. Browsers report a
|
|
20
|
+
* manual redirect as an `opaqueredirect` with status 0; other runtimes return
|
|
21
|
+
* the 3xx itself.
|
|
22
|
+
*/
|
|
23
|
+
export declare function refuseRedirect(res: Response): void;
|
|
15
24
|
//# sourceMappingURL=url.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"url.d.ts","sourceRoot":"","sources":["../../src/internal/url.ts"],"names":[],"mappings":"AAEA,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAGxD;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,EAAE,aAAa,EAAE,OAAO,GAAG,GAAG,CAsB3E;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAUpF"}
|
|
1
|
+
{"version":3,"file":"url.d.ts","sourceRoot":"","sources":["../../src/internal/url.ts"],"names":[],"mappings":"AAEA,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAGxD;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,EAAE,aAAa,EAAE,OAAO,GAAG,GAAG,CAsB3E;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAUpF;AAED;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,QAAQ,GAAG,IAAI,CAelD"}
|
package/dist/internal/url.js
CHANGED
|
@@ -48,4 +48,29 @@ export function redactUrlInMessage(message, url, rawUrl) {
|
|
|
48
48
|
}
|
|
49
49
|
return out;
|
|
50
50
|
}
|
|
51
|
+
/**
|
|
52
|
+
* Every request goes out with `redirect: 'manual'` (Cloudflare Workers throw
|
|
53
|
+
* on `'error'`), so a redirect comes back as a response instead of being
|
|
54
|
+
* followed. Refuse it: a 307/308 would replay pairing secrets, uploaded bytes
|
|
55
|
+
* or a webhook body to whatever origin `Location` names. Browsers report a
|
|
56
|
+
* manual redirect as an `opaqueredirect` with status 0; other runtimes return
|
|
57
|
+
* the 3xx itself.
|
|
58
|
+
*/
|
|
59
|
+
export function refuseRedirect(res) {
|
|
60
|
+
if (res.type === 'opaqueredirect' || (res.status >= 300 && res.status < 400)) {
|
|
61
|
+
// Release the body, best effort. A custom `fetch` such as node-fetch hands
|
|
62
|
+
// back a Node Readable with no cancel(); calling it threw a TypeError that
|
|
63
|
+
// surfaced as a retryable network_error instead of this refusal.
|
|
64
|
+
try {
|
|
65
|
+
res.body?.cancel?.()?.catch?.(() => { });
|
|
66
|
+
}
|
|
67
|
+
catch {
|
|
68
|
+
// Ignored: the refusal below is what matters.
|
|
69
|
+
}
|
|
70
|
+
throw new PingRoomError('Refusing to follow a redirect; credentials and request bodies are never forwarded.', {
|
|
71
|
+
code: 'redirect_refused',
|
|
72
|
+
status: res.status,
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
}
|
|
51
76
|
//# sourceMappingURL=url.js.map
|
package/dist/internal/url.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"url.js","sourceRoot":"","sources":["../../src/internal/url.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAE7C,MAAM,UAAU,cAAc,CAAC,QAAgB;IAC7C,MAAM,CAAC,GAAG,QAAQ,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;IACvE,OAAO,CAAC,KAAK,WAAW,IAAI,CAAC,KAAK,WAAW,IAAI,CAAC,KAAK,KAAK,IAAI,CAAC,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC;AAC3F,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,eAAe,CAAC,MAAc,EAAE,aAAsB;IACpE,IAAI,GAAQ,CAAC;IACb,IAAI,CAAC;QACH,GAAG,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,CAAC;IACxB,CAAC;IAAC,MAAM,CAAC;QACP,0EAA0E;QAC1E,2CAA2C;QAC3C,MAAM,IAAI,aAAa,CAAC,+DAA+D,EAAE;YACvF,IAAI,EAAE,aAAa;SACpB,CAAC,CAAC;IACL,CAAC;IACD,IAAI,GAAG,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;QAC9B,OAAO,GAAG,CAAC;IACb,CAAC;IACD,IAAI,GAAG,CAAC,QAAQ,KAAK,OAAO,IAAI,CAAC,aAAa,IAAI,cAAc,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC;QAChF,OAAO,GAAG,CAAC;IACb,CAAC;IACD,MAAM,IAAI,aAAa,CACrB,sDAAsD,GAAG,CAAC,QAAQ,KAAK,GAAG,CAAC,IAAI,KAAK;QAClF,sEAAsE,EACxE,EAAE,IAAI,EAAE,cAAc,EAAE,CACzB,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,kBAAkB,CAAC,OAAe,EAAE,GAAQ,EAAE,MAAc;IAC1E,MAAM,QAAQ,GAAG,GAAG,GAAG,CAAC,MAAM,aAAa,CAAC;IAC5C,IAAI,GAAG,GAAG,OAAO,CAAC;IAClB,KAAK,MAAM,IAAI,IAAI,CAAC,MAAM,EAAE,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;QACtC,IAAI,IAAI;YAAE,GAAG,GAAG,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IACjD,CAAC;IACD,KAAK,MAAM,IAAI,IAAI,CAAC,GAAG,GAAG,CAAC,QAAQ,GAAG,GAAG,CAAC,MAAM,GAAG,GAAG,CAAC,IAAI,EAAE,EAAE,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC7E,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC;YAAE,GAAG,GAAG,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;IACjE,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC"}
|
|
1
|
+
{"version":3,"file":"url.js","sourceRoot":"","sources":["../../src/internal/url.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { PingRoomError } from '../errors.js';
|
|
2
|
+
export declare function isRecord(value: unknown): value is Record<string, unknown>;
|
|
3
|
+
export declare function isNonEmptyString(value: unknown): value is string;
|
|
4
|
+
export declare function isNullableString(value: unknown): value is string | null;
|
|
5
|
+
/** UUIDs are case-insensitive; a caller may hold an id in either case. */
|
|
6
|
+
export declare function sameId(received: unknown, expected: string): boolean;
|
|
7
|
+
export declare function invalidWaitResponse(subject: string, expectedId: string, value: unknown, stateField: string): never;
|
|
8
|
+
/**
|
|
9
|
+
* A 2xx the PingRoom API never sends: a gateway's or captive portal's page, or
|
|
10
|
+
* a URL that is not PingRoom's. The body is kept short, for inspection only.
|
|
11
|
+
*/
|
|
12
|
+
export declare function invalidSuccessResponse(status: number, expected: string, body: unknown): PingRoomError;
|
|
13
|
+
//# sourceMappingURL=validate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../../src/internal/validate.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAE7C,wBAAgB,QAAQ,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAEzE;AAED,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,MAAM,CAEhE;AAED,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,MAAM,GAAG,IAAI,CAEvE;AAED,0EAA0E;AAC1E,wBAAgB,MAAM,CAAC,QAAQ,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAEnE;AAED,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,GAAG,KAAK,CASlH;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,aAAa,CAKrG"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
// Shape checks for server responses the wait loops and Agent Inbox trust.
|
|
2
|
+
import { PingRoomError } from '../errors.js';
|
|
3
|
+
export function isRecord(value) {
|
|
4
|
+
return value !== null && typeof value === 'object' && !Array.isArray(value);
|
|
5
|
+
}
|
|
6
|
+
export function isNonEmptyString(value) {
|
|
7
|
+
return typeof value === 'string' && value.trim() !== '';
|
|
8
|
+
}
|
|
9
|
+
export function isNullableString(value) {
|
|
10
|
+
return value === null || typeof value === 'string';
|
|
11
|
+
}
|
|
12
|
+
/** UUIDs are case-insensitive; a caller may hold an id in either case. */
|
|
13
|
+
export function sameId(received, expected) {
|
|
14
|
+
return typeof received === 'string' && received.toLowerCase() === expected.toLowerCase();
|
|
15
|
+
}
|
|
16
|
+
export function invalidWaitResponse(subject, expectedId, value, stateField) {
|
|
17
|
+
throw new PingRoomError(`PingRoom returned an invalid ${subject} wait response.`, {
|
|
18
|
+
code: 'invalid_response',
|
|
19
|
+
body: {
|
|
20
|
+
expected_id: expectedId,
|
|
21
|
+
received_id: isRecord(value) && typeof value['id'] === 'string' ? value['id'] : null,
|
|
22
|
+
[stateField]: isRecord(value) && typeof value[stateField] === 'string' ? value[stateField] : null,
|
|
23
|
+
},
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* A 2xx the PingRoom API never sends: a gateway's or captive portal's page, or
|
|
28
|
+
* a URL that is not PingRoom's. The body is kept short, for inspection only.
|
|
29
|
+
*/
|
|
30
|
+
export function invalidSuccessResponse(status, expected, body) {
|
|
31
|
+
return new PingRoomError(`PingRoom returned an invalid response (HTTP ${status}): expected ${expected}.`, {
|
|
32
|
+
code: 'invalid_response',
|
|
33
|
+
body: typeof body === 'string' ? body.slice(0, 512) : body,
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=validate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validate.js","sourceRoot":"","sources":["../../src/internal/validate.ts"],"names":[],"mappings":"AAAA,0EAA0E;AAE1E,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAE7C,MAAM,UAAU,QAAQ,CAAC,KAAc;IACrC,OAAO,KAAK,KAAK,IAAI,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;AAC9E,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,KAAc;IAC7C,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC;AAC1D,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,KAAc;IAC7C,OAAO,KAAK,KAAK,IAAI,IAAI,OAAO,KAAK,KAAK,QAAQ,CAAC;AACrD,CAAC;AAED,0EAA0E;AAC1E,MAAM,UAAU,MAAM,CAAC,QAAiB,EAAE,QAAgB;IACxD,OAAO,OAAO,QAAQ,KAAK,QAAQ,IAAI,QAAQ,CAAC,WAAW,EAAE,KAAK,QAAQ,CAAC,WAAW,EAAE,CAAC;AAC3F,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,OAAe,EAAE,UAAkB,EAAE,KAAc,EAAE,UAAkB;IACzG,MAAM,IAAI,aAAa,CAAC,gCAAgC,OAAO,iBAAiB,EAAE;QAChF,IAAI,EAAE,kBAAkB;QACxB,IAAI,EAAE;YACJ,WAAW,EAAE,UAAU;YACvB,WAAW,EAAE,QAAQ,CAAC,KAAK,CAAC,IAAI,OAAO,KAAK,CAAC,IAAI,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI;YACpF,CAAC,UAAU,CAAC,EAAE,QAAQ,CAAC,KAAK,CAAC,IAAI,OAAO,KAAK,CAAC,UAAU,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,IAAI;SAClG;KACF,CAAC,CAAC;AACL,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,sBAAsB,CAAC,MAAc,EAAE,QAAgB,EAAE,IAAa;IACpF,OAAO,IAAI,aAAa,CAAC,+CAA+C,MAAM,eAAe,QAAQ,GAAG,EAAE;QACxG,IAAI,EAAE,kBAAkB;QACxB,IAAI,EAAE,OAAO,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI;KAC3D,CAAC,CAAC;AACL,CAAC"}
|
package/dist/linkPing.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"linkPing.d.ts","sourceRoot":"","sources":["../src/linkPing.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,MAAM,WAAW,aAAa;IAC5B,2FAA2F;IAC3F,GAAG,EAAE,MAAM,CAAC;IACZ,oFAAoF;IACpF,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,YAAY;IAC3B,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;
|
|
1
|
+
{"version":3,"file":"linkPing.d.ts","sourceRoot":"","sources":["../src/linkPing.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,MAAM,WAAW,aAAa;IAC5B,2FAA2F;IAC3F,GAAG,EAAE,MAAM,CAAC;IACZ,oFAAoF;IACpF,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,YAAY;IAC3B,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAUD,wFAAwF;AACxF,wBAAgB,QAAQ,CAAC,KAAK,EAAE,aAAa,GAAG,YAAY,CAmB3D"}
|
package/dist/linkPing.js
CHANGED
|
@@ -13,6 +13,10 @@
|
|
|
13
13
|
*/
|
|
14
14
|
const URL_MAX = 2048;
|
|
15
15
|
const LABEL_MAX = 26;
|
|
16
|
+
/** Count code points, as the server's mb_strlen does — an emoji is one character, not two. */
|
|
17
|
+
function characterLength(value) {
|
|
18
|
+
return Array.from(value).length;
|
|
19
|
+
}
|
|
16
20
|
/** Build the `data` fragment for a link ping. Spread it into a ping's `data` object. */
|
|
17
21
|
export function linkPing(input) {
|
|
18
22
|
let parsed;
|
|
@@ -25,10 +29,10 @@ export function linkPing(input) {
|
|
|
25
29
|
if (parsed.protocol !== 'https:' && parsed.protocol !== 'http:') {
|
|
26
30
|
throw new TypeError('linkPing: url must be an absolute http(s) URL');
|
|
27
31
|
}
|
|
28
|
-
if (input.url
|
|
32
|
+
if (characterLength(input.url) > URL_MAX) {
|
|
29
33
|
throw new TypeError(`linkPing: url must be at most ${URL_MAX} characters`);
|
|
30
34
|
}
|
|
31
|
-
if (input.buttonLabel !== undefined && input.buttonLabel
|
|
35
|
+
if (input.buttonLabel !== undefined && characterLength(input.buttonLabel) > LABEL_MAX) {
|
|
32
36
|
throw new TypeError(`linkPing: buttonLabel must be at most ${LABEL_MAX} characters`);
|
|
33
37
|
}
|
|
34
38
|
const out = { url: input.url };
|
package/dist/linkPing.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"linkPing.js","sourceRoot":"","sources":["../src/linkPing.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAeH,MAAM,OAAO,GAAG,IAAI,CAAC;AACrB,MAAM,SAAS,GAAG,EAAE,CAAC;AAErB,wFAAwF;AACxF,MAAM,UAAU,QAAQ,CAAC,KAAoB;IAC3C,IAAI,MAAW,CAAC;IAChB,IAAI,CAAC;QACH,MAAM,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC9B,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,SAAS,CAAC,kCAAkC,CAAC,CAAC;IAC1D,CAAC;IACD,IAAI,MAAM,CAAC,QAAQ,KAAK,QAAQ,IAAI,MAAM,CAAC,QAAQ,KAAK,OAAO,EAAE,CAAC;QAChE,MAAM,IAAI,SAAS,CAAC,+CAA+C,CAAC,CAAC;IACvE,CAAC;IACD,IAAI,KAAK,CAAC,GAAG,CAAC,
|
|
1
|
+
{"version":3,"file":"linkPing.js","sourceRoot":"","sources":["../src/linkPing.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAeH,MAAM,OAAO,GAAG,IAAI,CAAC;AACrB,MAAM,SAAS,GAAG,EAAE,CAAC;AAErB,8FAA8F;AAC9F,SAAS,eAAe,CAAC,KAAa;IACpC,OAAO,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC;AAClC,CAAC;AAED,wFAAwF;AACxF,MAAM,UAAU,QAAQ,CAAC,KAAoB;IAC3C,IAAI,MAAW,CAAC;IAChB,IAAI,CAAC;QACH,MAAM,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC9B,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,SAAS,CAAC,kCAAkC,CAAC,CAAC;IAC1D,CAAC;IACD,IAAI,MAAM,CAAC,QAAQ,KAAK,QAAQ,IAAI,MAAM,CAAC,QAAQ,KAAK,OAAO,EAAE,CAAC;QAChE,MAAM,IAAI,SAAS,CAAC,+CAA+C,CAAC,CAAC;IACvE,CAAC;IACD,IAAI,eAAe,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,OAAO,EAAE,CAAC;QACzC,MAAM,IAAI,SAAS,CAAC,iCAAiC,OAAO,aAAa,CAAC,CAAC;IAC7E,CAAC;IACD,IAAI,KAAK,CAAC,WAAW,KAAK,SAAS,IAAI,eAAe,CAAC,KAAK,CAAC,WAAW,CAAC,GAAG,SAAS,EAAE,CAAC;QACtF,MAAM,IAAI,SAAS,CAAC,yCAAyC,SAAS,aAAa,CAAC,CAAC;IACvF,CAAC;IACD,MAAM,GAAG,GAAiB,EAAE,GAAG,EAAE,KAAK,CAAC,GAAG,EAAE,CAAC;IAC7C,IAAI,KAAK,CAAC,WAAW,KAAK,SAAS;QAAE,GAAG,CAAC,YAAY,GAAG,KAAK,CAAC,WAAW,CAAC;IAC1E,OAAO,GAAG,CAAC;AACb,CAAC"}
|