@v3finance/core-sdk 0.1.0 → 0.2.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/CHANGELOG.md +397 -7
- package/README.md +215 -72
- package/dist/cjs/client.d.ts +67 -22
- package/dist/cjs/client.d.ts.map +1 -1
- package/dist/cjs/client.js +38 -2
- package/dist/cjs/client.js.map +1 -1
- package/dist/cjs/core/errors.d.ts +30 -10
- package/dist/cjs/core/errors.d.ts.map +1 -1
- package/dist/cjs/core/errors.js +47 -15
- package/dist/cjs/core/errors.js.map +1 -1
- package/dist/cjs/core/gated.d.ts +21 -3
- package/dist/cjs/core/gated.d.ts.map +1 -1
- package/dist/cjs/core/gated.js +12 -3
- package/dist/cjs/core/gated.js.map +1 -1
- package/dist/cjs/core/http.d.ts +12 -8
- package/dist/cjs/core/http.d.ts.map +1 -1
- package/dist/cjs/core/http.js +130 -40
- package/dist/cjs/core/http.js.map +1 -1
- package/dist/cjs/core/pagination.d.ts +28 -1
- package/dist/cjs/core/pagination.d.ts.map +1 -1
- package/dist/cjs/core/pagination.js +36 -1
- package/dist/cjs/core/pagination.js.map +1 -1
- package/dist/cjs/generated/operations.js +1 -1
- package/dist/cjs/generated/types.d.ts +948 -172
- package/dist/cjs/generated/types.d.ts.map +1 -1
- package/dist/cjs/index.d.ts +32 -8
- package/dist/cjs/index.d.ts.map +1 -1
- package/dist/cjs/index.js +12 -0
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/resources/addresses.d.ts +22 -8
- package/dist/cjs/resources/addresses.d.ts.map +1 -1
- package/dist/cjs/resources/addresses.js +7 -1
- package/dist/cjs/resources/addresses.js.map +1 -1
- package/dist/cjs/resources/admin.d.ts +150 -25
- package/dist/cjs/resources/admin.d.ts.map +1 -1
- package/dist/cjs/resources/admin.js +94 -23
- package/dist/cjs/resources/admin.js.map +1 -1
- package/dist/cjs/resources/approvals.d.ts +46 -5
- package/dist/cjs/resources/approvals.d.ts.map +1 -1
- package/dist/cjs/resources/approvals.js +27 -4
- package/dist/cjs/resources/approvals.js.map +1 -1
- package/dist/cjs/resources/balances.d.ts +152 -16
- package/dist/cjs/resources/balances.d.ts.map +1 -1
- package/dist/cjs/resources/balances.js +9 -5
- package/dist/cjs/resources/balances.js.map +1 -1
- package/dist/cjs/resources/categories.d.ts +93 -21
- package/dist/cjs/resources/categories.d.ts.map +1 -1
- package/dist/cjs/resources/categories.js +65 -18
- package/dist/cjs/resources/categories.js.map +1 -1
- package/dist/cjs/resources/counterparties.d.ts +26 -3
- package/dist/cjs/resources/counterparties.d.ts.map +1 -1
- package/dist/cjs/resources/counterparties.js +17 -0
- package/dist/cjs/resources/counterparties.js.map +1 -1
- package/dist/cjs/resources/folders.d.ts +51 -10
- package/dist/cjs/resources/folders.d.ts.map +1 -1
- package/dist/cjs/resources/folders.js +36 -5
- package/dist/cjs/resources/folders.js.map +1 -1
- package/dist/cjs/resources/history.d.ts +20 -2
- package/dist/cjs/resources/history.d.ts.map +1 -1
- package/dist/cjs/resources/history.js.map +1 -1
- package/dist/cjs/resources/me.d.ts +27 -4
- package/dist/cjs/resources/me.d.ts.map +1 -1
- package/dist/cjs/resources/me.js +22 -1
- package/dist/cjs/resources/me.js.map +1 -1
- package/dist/cjs/resources/members.d.ts +19 -4
- package/dist/cjs/resources/members.d.ts.map +1 -1
- package/dist/cjs/resources/members.js +15 -6
- package/dist/cjs/resources/members.js.map +1 -1
- package/dist/cjs/resources/operations.d.ts +64 -8
- package/dist/cjs/resources/operations.d.ts.map +1 -1
- package/dist/cjs/resources/operations.js +26 -2
- package/dist/cjs/resources/operations.js.map +1 -1
- package/dist/cjs/resources/registries.d.ts +87 -9
- package/dist/cjs/resources/registries.d.ts.map +1 -1
- package/dist/cjs/resources/registries.js +54 -11
- package/dist/cjs/resources/registries.js.map +1 -1
- package/dist/cjs/resources/reports.d.ts +300 -41
- package/dist/cjs/resources/reports.d.ts.map +1 -1
- package/dist/cjs/resources/reports.js +135 -7
- package/dist/cjs/resources/reports.js.map +1 -1
- package/dist/cjs/resources/sharing.d.ts +61 -10
- package/dist/cjs/resources/sharing.d.ts.map +1 -1
- package/dist/cjs/resources/sharing.js +51 -4
- package/dist/cjs/resources/sharing.js.map +1 -1
- package/dist/cjs/resources/transfers.d.ts +26 -4
- package/dist/cjs/resources/transfers.d.ts.map +1 -1
- package/dist/cjs/resources/transfers.js +23 -1
- package/dist/cjs/resources/transfers.js.map +1 -1
- package/dist/cjs/resources/types.d.ts +20 -0
- package/dist/cjs/resources/types.d.ts.map +1 -1
- package/dist/cjs/units.d.ts.map +1 -1
- package/dist/cjs/units.js +18 -2
- package/dist/cjs/units.js.map +1 -1
- package/dist/cjs/version.d.ts +1 -1
- package/dist/cjs/version.js +1 -1
- package/dist/esm/client.d.ts +67 -22
- package/dist/esm/client.d.ts.map +1 -1
- package/dist/esm/client.js +38 -2
- package/dist/esm/client.js.map +1 -1
- package/dist/esm/core/errors.d.ts +30 -10
- package/dist/esm/core/errors.d.ts.map +1 -1
- package/dist/esm/core/errors.js +47 -15
- package/dist/esm/core/errors.js.map +1 -1
- package/dist/esm/core/gated.d.ts +21 -3
- package/dist/esm/core/gated.d.ts.map +1 -1
- package/dist/esm/core/gated.js +12 -3
- package/dist/esm/core/gated.js.map +1 -1
- package/dist/esm/core/http.d.ts +12 -8
- package/dist/esm/core/http.d.ts.map +1 -1
- package/dist/esm/core/http.js +131 -41
- package/dist/esm/core/http.js.map +1 -1
- package/dist/esm/core/pagination.d.ts +28 -1
- package/dist/esm/core/pagination.d.ts.map +1 -1
- package/dist/esm/core/pagination.js +36 -1
- package/dist/esm/core/pagination.js.map +1 -1
- package/dist/esm/generated/operations.js +1 -1
- package/dist/esm/generated/types.d.ts +948 -172
- package/dist/esm/generated/types.d.ts.map +1 -1
- package/dist/esm/index.d.ts +32 -8
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js +17 -5
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/resources/addresses.d.ts +22 -8
- package/dist/esm/resources/addresses.d.ts.map +1 -1
- package/dist/esm/resources/addresses.js +7 -1
- package/dist/esm/resources/addresses.js.map +1 -1
- package/dist/esm/resources/admin.d.ts +150 -25
- package/dist/esm/resources/admin.d.ts.map +1 -1
- package/dist/esm/resources/admin.js +94 -23
- package/dist/esm/resources/admin.js.map +1 -1
- package/dist/esm/resources/approvals.d.ts +46 -5
- package/dist/esm/resources/approvals.d.ts.map +1 -1
- package/dist/esm/resources/approvals.js +27 -4
- package/dist/esm/resources/approvals.js.map +1 -1
- package/dist/esm/resources/balances.d.ts +152 -16
- package/dist/esm/resources/balances.d.ts.map +1 -1
- package/dist/esm/resources/balances.js +9 -5
- package/dist/esm/resources/balances.js.map +1 -1
- package/dist/esm/resources/categories.d.ts +93 -21
- package/dist/esm/resources/categories.d.ts.map +1 -1
- package/dist/esm/resources/categories.js +65 -18
- package/dist/esm/resources/categories.js.map +1 -1
- package/dist/esm/resources/counterparties.d.ts +26 -3
- package/dist/esm/resources/counterparties.d.ts.map +1 -1
- package/dist/esm/resources/counterparties.js +17 -0
- package/dist/esm/resources/counterparties.js.map +1 -1
- package/dist/esm/resources/folders.d.ts +51 -10
- package/dist/esm/resources/folders.d.ts.map +1 -1
- package/dist/esm/resources/folders.js +36 -5
- package/dist/esm/resources/folders.js.map +1 -1
- package/dist/esm/resources/history.d.ts +20 -2
- package/dist/esm/resources/history.d.ts.map +1 -1
- package/dist/esm/resources/history.js.map +1 -1
- package/dist/esm/resources/me.d.ts +27 -4
- package/dist/esm/resources/me.d.ts.map +1 -1
- package/dist/esm/resources/me.js +22 -1
- package/dist/esm/resources/me.js.map +1 -1
- package/dist/esm/resources/members.d.ts +19 -4
- package/dist/esm/resources/members.d.ts.map +1 -1
- package/dist/esm/resources/members.js +15 -6
- package/dist/esm/resources/members.js.map +1 -1
- package/dist/esm/resources/operations.d.ts +64 -8
- package/dist/esm/resources/operations.d.ts.map +1 -1
- package/dist/esm/resources/operations.js +26 -2
- package/dist/esm/resources/operations.js.map +1 -1
- package/dist/esm/resources/registries.d.ts +87 -9
- package/dist/esm/resources/registries.d.ts.map +1 -1
- package/dist/esm/resources/registries.js +54 -11
- package/dist/esm/resources/registries.js.map +1 -1
- package/dist/esm/resources/reports.d.ts +300 -41
- package/dist/esm/resources/reports.d.ts.map +1 -1
- package/dist/esm/resources/reports.js +135 -7
- package/dist/esm/resources/reports.js.map +1 -1
- package/dist/esm/resources/sharing.d.ts +61 -10
- package/dist/esm/resources/sharing.d.ts.map +1 -1
- package/dist/esm/resources/sharing.js +51 -4
- package/dist/esm/resources/sharing.js.map +1 -1
- package/dist/esm/resources/transfers.d.ts +26 -4
- package/dist/esm/resources/transfers.d.ts.map +1 -1
- package/dist/esm/resources/transfers.js +23 -1
- package/dist/esm/resources/transfers.js.map +1 -1
- package/dist/esm/resources/types.d.ts +20 -0
- package/dist/esm/resources/types.d.ts.map +1 -1
- package/dist/esm/units.d.ts.map +1 -1
- package/dist/esm/units.js +18 -2
- package/dist/esm/units.js.map +1 -1
- package/dist/esm/version.d.ts +1 -1
- package/dist/esm/version.js +1 -1
- package/docs/concepts.md +191 -0
- package/docs/errors.md +471 -0
- package/package.json +7 -6
- package/src/client.ts +89 -25
- package/src/core/errors.ts +49 -15
- package/src/core/gated.ts +22 -4
- package/src/core/http.ts +156 -46
- package/src/core/pagination.ts +38 -1
- package/src/generated/operations.ts +1 -1
- package/src/generated/types.ts +983 -173
- package/src/index.ts +64 -7
- package/src/resources/addresses.ts +23 -8
- package/src/resources/admin.ts +186 -33
- package/src/resources/approvals.ts +55 -9
- package/src/resources/balances.ts +186 -14
- package/src/resources/categories.ts +125 -30
- package/src/resources/counterparties.ts +23 -6
- package/src/resources/folders.ts +74 -18
- package/src/resources/history.ts +27 -2
- package/src/resources/me.ts +30 -5
- package/src/resources/members.ts +26 -7
- package/src/resources/operations.ts +73 -8
- package/src/resources/registries.ts +90 -11
- package/src/resources/reports.ts +348 -67
- package/src/resources/sharing.ts +71 -18
- package/src/resources/transfers.ts +33 -5
- package/src/resources/types.ts +20 -0
- package/src/units.ts +19 -2
- package/src/version.ts +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../../src/core/errors.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../../src/core/errors.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AAEH,6EAA6E;AAC7E,MAAM,MAAM,aAAa;AACvB,oFAAoF;AAClF,MAAM;AACR,uFAAuF;GACrF,SAAS;AACX,sFAAsF;GACpF,SAAS;AACX,gEAAgE;GAC9D,SAAS;AACX,yEAAyE;GACvE,OAAO,CAAA;AAEX,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,aAAa,CAAA;IACnB,OAAO,EAAE,MAAM,CAAA;IACf,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACtB,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,uEAAuE;IACvE,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,KAAK,CAAC,EAAE,OAAO,CAAA;CAChB;AAED,qBAAa,SAAU,SAAQ,KAAK;IAClC,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAA;IAC5B,yFAAyF;IACzF,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,wEAAwE;IACxE,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;IAC9B,sFAAsF;IACtF,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAA;IACzB,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,CAAA;IAErC,YAAY,IAAI,EAAE,aAAa,EAQ9B;CACF;AAED,wBAAgB,WAAW,CAAC,CAAC,EAAE,OAAO,GAAG,CAAC,IAAI,SAAS,CAEtD;AAED,0EAA0E;AAC1E,wBAAgB,OAAO,CAAC,CAAC,EAAE,OAAO,EAAE,GAAG,KAAK,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAExE;AAED;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CA6BrD;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAsD1F;AAsBD,eAAO,MAAM,YAAY,UAAW,OAAO,aAAa,MAAM,KAAG,SAQ7D,CAAA;AAEJ,eAAO,MAAM,YAAY,OAAQ,MAAM,aAAa,MAAM,KAAG,SAYzD,CAAA;AAEJ,eAAO,MAAM,YAAY,cAAe,MAAM,KAAG,SAO7C,CAAA;AAEJ,eAAO,MAAM,UAAU,UAAW,OAAO,aAAa,MAAM,KAAG,SAQ3D,CAAA"}
|
package/dist/cjs/core/errors.js
CHANGED
|
@@ -6,14 +6,30 @@
|
|
|
6
6
|
* wrapper has three gaps the client has to close itself — otherwise a precise
|
|
7
7
|
* error turns into "something went wrong":
|
|
8
8
|
*
|
|
9
|
-
* 1. Bodies without an `error` key pass through untouched
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
* item by item.
|
|
13
|
-
* 2.
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
9
|
+
* 1. Bodies without an `error` key pass through untouched — the wrapper
|
|
10
|
+
* keys off that one field. Batch sharing endpoints answer 400 with
|
|
11
|
+
* `{results:[…]}`, which is not a failure of the whole call but "some
|
|
12
|
+
* subjects were rejected", and has to be read item by item.
|
|
13
|
+
* 2. Non-JSON bodies have no wrapper at all: the layer leaves by
|
|
14
|
+
* content-type, and a thrown `HTTPException` carries its own response
|
|
15
|
+
* past it. So a 502 from the edge, a WAF 403 or a platform 429 arrive as
|
|
16
|
+
* text. `core/http.ts` reduces a short one to a flat `{error: "…"}`
|
|
17
|
+
* (dropping HTML pages) before it reaches this parser, which is why the
|
|
18
|
+
* flat string shape below is still read — and why the per-status
|
|
19
|
+
* fallback wording here is what a person ends up seeing.
|
|
20
|
+
* 3. `message` sometimes IS the code. Handlers answer `{error: "<CODE>",
|
|
21
|
+
* code: "<CODE>"}` and batch items carry `{code:"X", message:"X"}`; the
|
|
22
|
+
* wrapper copies the former into `message` faithfully. A code is not a
|
|
23
|
+
* sentence, so it must never be shown to a person as-is.
|
|
24
|
+
*
|
|
25
|
+
* What is NOT a gap any more: zod validation failures. The route hook does
|
|
26
|
+
* build a flat `{error: "amount: Required; …"}` (backend
|
|
27
|
+
* `openapi/common.ts`), but that is an intermediate form.
|
|
28
|
+
* `middleware/errorEnvelope` rewraps every JSON body carrying a string
|
|
29
|
+
* `error` into the canonical envelope, `code` derived from the status —
|
|
30
|
+
* `BAD_REQUEST` here, because the hook sets none of its own. The same layer
|
|
31
|
+
* answers an unmatched path and an uncaught throw. Reading `body.error` as a
|
|
32
|
+
* string against today's API therefore hands you an object.
|
|
17
33
|
*
|
|
18
34
|
* Because of that `code` is always present here: either the server sent one,
|
|
19
35
|
* or it is derived from the HTTP status. Branch on `code`, display `message`.
|
|
@@ -52,29 +68,37 @@ function hasCode(e, ...codes) {
|
|
|
52
68
|
return isCoreError(e) && codes.includes(e.code);
|
|
53
69
|
}
|
|
54
70
|
/**
|
|
55
|
-
* Status to code,
|
|
56
|
-
*
|
|
71
|
+
* Status to code, used only when a body carried no code of its own: a proxy's
|
|
72
|
+
* HTML 502, a platform 429, an empty body.
|
|
73
|
+
*
|
|
74
|
+
* The names are the API's own names for the same statuses, so that one
|
|
75
|
+
* condition has one name whichever side produced it. 502 and 504 are the
|
|
76
|
+
* exception — the API has no envelope for them, they arrive from the edge.
|
|
57
77
|
*/
|
|
58
78
|
function codeFromStatus(status) {
|
|
59
79
|
switch (status) {
|
|
60
80
|
case 400:
|
|
61
81
|
return 'BAD_REQUEST';
|
|
62
82
|
case 401:
|
|
63
|
-
return '
|
|
83
|
+
return 'UNAUTHENTICATED';
|
|
64
84
|
case 403:
|
|
65
85
|
return 'FORBIDDEN';
|
|
66
86
|
case 404:
|
|
67
87
|
return 'NOT_FOUND';
|
|
68
88
|
case 409:
|
|
69
89
|
return 'CONFLICT';
|
|
90
|
+
case 413:
|
|
91
|
+
return 'PAYLOAD_TOO_LARGE';
|
|
70
92
|
case 422:
|
|
71
|
-
return '
|
|
93
|
+
return 'UNPROCESSABLE_ENTITY';
|
|
72
94
|
case 429:
|
|
73
95
|
return 'RATE_LIMITED';
|
|
96
|
+
case 501:
|
|
97
|
+
return 'NOT_IMPLEMENTED';
|
|
74
98
|
case 502:
|
|
75
99
|
return 'BAD_GATEWAY';
|
|
76
100
|
case 503:
|
|
77
|
-
return '
|
|
101
|
+
return 'SERVICE_UNAVAILABLE';
|
|
78
102
|
case 504:
|
|
79
103
|
return 'GATEWAY_TIMEOUT';
|
|
80
104
|
default:
|
|
@@ -110,7 +134,12 @@ function parseErrorBody(status, body, endpoint) {
|
|
|
110
134
|
: fallbackMessage(status);
|
|
111
135
|
return make(message, code, o.details);
|
|
112
136
|
}
|
|
113
|
-
// Shape 2 — a
|
|
137
|
+
// Shape 2 — a flat string `error`. No longer how validation failures reach
|
|
138
|
+
// a client (the envelope rewraps those into Shape 1), so the live producer
|
|
139
|
+
// is `core/http.ts`, which folds a short non-JSON error body into this
|
|
140
|
+
// shape. The sibling `code` is still read: handlers do put one next to a
|
|
141
|
+
// string `error`, and an older deployment without the envelope layer would
|
|
142
|
+
// deliver exactly that.
|
|
114
143
|
if (typeof inner === 'string' && inner) {
|
|
115
144
|
const flat = body.code;
|
|
116
145
|
const code = typeof flat === 'string' && flat ? flat : fallbackCode;
|
|
@@ -156,7 +185,10 @@ const timeoutError = (ms, endpoint) => new CoreError({
|
|
|
156
185
|
kind: 'timeout',
|
|
157
186
|
code: 'TIMEOUT',
|
|
158
187
|
status: null,
|
|
159
|
-
|
|
188
|
+
// Sub-second timeouts rounded to `0s`, which reads as "no time was
|
|
189
|
+
// allowed" rather than "400ms was". Below a second the unit changes
|
|
190
|
+
// instead of the number; a whole second keeps the shorter wording.
|
|
191
|
+
message: `The server did not answer within ${ms < 1000 ? `${Math.round(ms)}ms` : `${Math.round(ms / 1000)}s`}`,
|
|
160
192
|
...(endpoint === undefined ? {} : { endpoint }),
|
|
161
193
|
});
|
|
162
194
|
exports.timeoutError = timeoutError;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../../../src/core/errors.ts"],"names":[],"mappings":";AAAA
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../../../src/core/errors.ts"],"names":[],"mappings":"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"}
|
package/dist/cjs/core/gated.d.ts
CHANGED
|
@@ -4,8 +4,10 @@
|
|
|
4
4
|
*
|
|
5
5
|
* 201 — applied immediately (policy allowed it without signatures);
|
|
6
6
|
* 202 — queued for approval, funds are reserved, nothing has moved yet;
|
|
7
|
-
* 200 — a replay of the same idempotency key
|
|
8
|
-
* existing operation came back (no second
|
|
7
|
+
* 200 — on a transfer: a replay of the same idempotency key, nothing
|
|
8
|
+
* happened now and the existing operation came back (no second
|
|
9
|
+
* broadcast). Everywhere else: an ordinary applied success, because
|
|
10
|
+
* an edit is not a creation and answers 200 (see `replayOn200`).
|
|
9
11
|
*
|
|
10
12
|
* The body can be identical: a transfer returns `{transaction}` in all three.
|
|
11
13
|
* A client that reads only the body will say "sent" where the truth is
|
|
@@ -17,9 +19,18 @@
|
|
|
17
19
|
* person should be told "already sent", not "sent" a second time.
|
|
18
20
|
*/
|
|
19
21
|
export type GatedOutcome = 'applied' | 'pending' | 'replayed';
|
|
22
|
+
/**
|
|
23
|
+
* `status` is the status the server ACTUALLY answered, which is why `applied`
|
|
24
|
+
* carries `200 | 201` rather than 201 alone: an ordinary 200 success is an
|
|
25
|
+
* applied operation too (updating a counterparty, editing a label — anything
|
|
26
|
+
* gated that is not a creation). The field used to be hard-coded to 201 for
|
|
27
|
+
* those, so every gated method except `transfers.send` reported a status the
|
|
28
|
+
* server never sent, into logs and error reports where it is the one thing
|
|
29
|
+
* worth trusting. Branch on `outcome`; read `status` when you need the fact.
|
|
30
|
+
*/
|
|
20
31
|
export type Gated<TApplied, TPending = TApplied> = {
|
|
21
32
|
readonly outcome: 'applied';
|
|
22
|
-
readonly status: 201;
|
|
33
|
+
readonly status: 200 | 201;
|
|
23
34
|
readonly data: TApplied;
|
|
24
35
|
} | {
|
|
25
36
|
readonly outcome: 'replayed';
|
|
@@ -39,6 +50,13 @@ export type Gated<TApplied, TPending = TApplied> = {
|
|
|
39
50
|
* success. Telling a person "already sent" after a plain edit would be as
|
|
40
51
|
* wrong as telling them "done" after a replay, so each caller states which
|
|
41
52
|
* of the two it is instead of the helper guessing.
|
|
53
|
+
*
|
|
54
|
+
* Which also means `outcome: 'replayed'` is UNREACHABLE for every gated
|
|
55
|
+
* method other than `transfers.send`: replay protection needs an idempotency
|
|
56
|
+
* key, and the transfer body is the only place the API takes one. The
|
|
57
|
+
* three-way `switch` in `docs/concepts.md` is right for a transfer; beside a
|
|
58
|
+
* counterparty edit its `case 'replayed'` is dead, and it is not evidence
|
|
59
|
+
* that such an edit can come back as a replay.
|
|
42
60
|
*/
|
|
43
61
|
export declare function toGated<TApplied, TPending>(status: number, data: unknown, options?: {
|
|
44
62
|
replayOn200?: boolean;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gated.d.ts","sourceRoot":"","sources":["../../../src/core/gated.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"gated.d.ts","sourceRoot":"","sources":["../../../src/core/gated.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,MAAM,MAAM,YAAY,GAAG,SAAS,GAAG,SAAS,GAAG,UAAU,CAAA;AAE7D;;;;;;;;GAQG;AACH,MAAM,MAAM,KAAK,CAAC,QAAQ,EAAE,QAAQ,GAAG,QAAQ,IAC3C;IAAE,QAAQ,CAAC,OAAO,EAAE,SAAS,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,GAAG,GAAG,GAAG,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAA;CAAE,GACpF;IAAE,QAAQ,CAAC,OAAO,EAAE,UAAU,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,GAAG,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAA;CAAE,GAC/E;IAAE,QAAQ,CAAC,OAAO,EAAE,SAAS,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,GAAG,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAA;CAAE,CAAA;AAElF;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,OAAO,CAAC,QAAQ,EAAE,QAAQ,EACxC,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,OAAO,EACb,OAAO,GAAE;IAAE,WAAW,CAAC,EAAE,OAAO,CAAA;CAAO,GACtC,KAAK,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAgB3B;AAED,qEAAqE;AACrE,wBAAgB,SAAS,CAAC,CAAC,EAAE,CAAC,EAC5B,CAAC,EAAE,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,GACb,CAAC,IAAI,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE;IAAE,OAAO,EAAE,SAAS,GAAG,UAAU,CAAA;CAAE,CAAC,CAEhE;AAED,yEAAyE;AACzE,wBAAgB,SAAS,CAAC,CAAC,EAAE,CAAC,EAC5B,CAAC,EAAE,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,GACb,CAAC,IAAI,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE;IAAE,OAAO,EAAE,SAAS,CAAA;CAAE,CAAC,CAEnD"}
|
package/dist/cjs/core/gated.js
CHANGED
|
@@ -5,8 +5,10 @@
|
|
|
5
5
|
*
|
|
6
6
|
* 201 — applied immediately (policy allowed it without signatures);
|
|
7
7
|
* 202 — queued for approval, funds are reserved, nothing has moved yet;
|
|
8
|
-
* 200 — a replay of the same idempotency key
|
|
9
|
-
* existing operation came back (no second
|
|
8
|
+
* 200 — on a transfer: a replay of the same idempotency key, nothing
|
|
9
|
+
* happened now and the existing operation came back (no second
|
|
10
|
+
* broadcast). Everywhere else: an ordinary applied success, because
|
|
11
|
+
* an edit is not a creation and answers 200 (see `replayOn200`).
|
|
10
12
|
*
|
|
11
13
|
* The body can be identical: a transfer returns `{transaction}` in all three.
|
|
12
14
|
* A client that reads only the body will say "sent" where the truth is
|
|
@@ -30,13 +32,20 @@ exports.isPending = isPending;
|
|
|
30
32
|
* success. Telling a person "already sent" after a plain edit would be as
|
|
31
33
|
* wrong as telling them "done" after a replay, so each caller states which
|
|
32
34
|
* of the two it is instead of the helper guessing.
|
|
35
|
+
*
|
|
36
|
+
* Which also means `outcome: 'replayed'` is UNREACHABLE for every gated
|
|
37
|
+
* method other than `transfers.send`: replay protection needs an idempotency
|
|
38
|
+
* key, and the transfer body is the only place the API takes one. The
|
|
39
|
+
* three-way `switch` in `docs/concepts.md` is right for a transfer; beside a
|
|
40
|
+
* counterparty edit its `case 'replayed'` is dead, and it is not evidence
|
|
41
|
+
* that such an edit can come back as a replay.
|
|
33
42
|
*/
|
|
34
43
|
function toGated(status, data, options = {}) {
|
|
35
44
|
switch (status) {
|
|
36
45
|
case 200:
|
|
37
46
|
return options.replayOn200
|
|
38
47
|
? { outcome: 'replayed', status: 200, data: data }
|
|
39
|
-
: { outcome: 'applied', status:
|
|
48
|
+
: { outcome: 'applied', status: 200, data: data };
|
|
40
49
|
case 201:
|
|
41
50
|
return { outcome: 'applied', status: 201, data: data };
|
|
42
51
|
case 202:
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gated.js","sourceRoot":"","sources":["../../../src/core/gated.ts"],"names":[],"mappings":";AAAA
|
|
1
|
+
{"version":3,"file":"gated.js","sourceRoot":"","sources":["../../../src/core/gated.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;GAmBG;;;;;AAkBH;;;;;;;;;;;;;;;;GAgBG;AACH,iBACE,MAAc,EACd,IAAa,EACb,OAAO,GAA8B,EAAE;IAEvC,QAAQ,MAAM,EAAE,CAAC;QACf,KAAK,GAAG;YACN,OAAO,OAAO,CAAC,WAAW;gBACxB,CAAC,CAAC,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,IAAgB,EAAE;gBAC9D,CAAC,CAAC,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,IAAgB,EAAE,CAAA;QACjE,KAAK,GAAG;YACN,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,IAAgB,EAAE,CAAA;QACpE,KAAK,GAAG;YACN,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,IAAgB,EAAE,CAAA;QACpE;YACE,MAAM,IAAI,KAAK,CACb,kDAAkD,MAAM,IAAI;gBAC1D,yDAAyD,CAC5D,CAAA;IACL,CAAC;AACH,CAAC;AAED,qEAAqE;AACrE,mBACE,CAAc;IAEd,OAAO,CAAC,CAAC,OAAO,KAAK,SAAS,IAAI,CAAC,CAAC,OAAO,KAAK,UAAU,CAAA;AAC5D,CAAC;AAED,yEAAyE;AACzE,mBACE,CAAc;IAEd,OAAO,CAAC,CAAC,OAAO,KAAK,SAAS,CAAA;AAChC,CAAC"}
|
package/dist/cjs/core/http.d.ts
CHANGED
|
@@ -39,15 +39,19 @@ export interface RequestOptions {
|
|
|
39
39
|
signal?: AbortSignal | undefined;
|
|
40
40
|
timeoutMs?: number | undefined;
|
|
41
41
|
/**
|
|
42
|
-
* Attempt key
|
|
42
|
+
* Attempt key. ACCEPTED AND IGNORED BY THE TRANSPORT — the working place
|
|
43
|
+
* for it is the request BODY, the way `transfers.send` passes it.
|
|
43
44
|
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
*
|
|
50
|
-
*
|
|
45
|
+
* It used to go out as an `idempotency-key` header. The server has never
|
|
46
|
+
* read that header, which by itself merely bought nothing; in a browser it
|
|
47
|
+
* cost the whole request. The API's CORS preflight allows exactly
|
|
48
|
+
* `Content-Type` and `Authorization` (`allowHeaders`, backend
|
|
49
|
+
* `src/index.ts`), so the extra header failed the preflight and the call
|
|
50
|
+
* was never sent at all — a money request that could not reach the server,
|
|
51
|
+
* and a "network error" that no retry explains. Replay protection is
|
|
52
|
+
* resolved from the `idempotencyKey` FIELD of the body and nowhere else.
|
|
53
|
+
*
|
|
54
|
+
* @deprecated The transport sends this nowhere. Put the key in the body.
|
|
51
55
|
*/
|
|
52
56
|
idempotencyKey?: string | undefined;
|
|
53
57
|
headers?: Record<string, string> | undefined;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../../../src/core/http.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../../../src/core/http.ts"],"names":[],"mappings":"AAAA,OAAO,EAOL,KAAK,SAAS,EACf,MAAM,aAAa,CAAA;AAwBpB,MAAM,MAAM,UAAU,GAClB,MAAM,GACN,MAAM,GACN,OAAO,GACP,IAAI,GACJ,SAAS,GACT,SAAS,CAAC,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,EAAE,CAAA;AAE1C,MAAM,MAAM,KAAK,GAAG,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAA;AAE9C,MAAM,WAAW,aAAa;IAC5B,8CAA8C;IAC9C,OAAO,CAAC,EAAE,MAAM,CAAA;IAEhB;;;;OAIG;IACH,cAAc,CAAC,EAAE,MACb,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GACtB,SAAS,GACT,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,SAAS,CAAC,CAAA;IAE/C;;;;;;OAMG;IACH,WAAW,CAAC,EAAE,kBAAkB,CAAA;IAEhC;;;;OAIG;IACH,cAAc,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAExD,8EAA8E;IAC9E,cAAc,CAAC,EAAE,CAAC,KAAK,EAAE,SAAS,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAE3D,4DAA4D;IAC5D,KAAK,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK,CAAA;IAE/B,+CAA+C;IAC/C,SAAS,CAAC,EAAE,MAAM,CAAA;IAElB,sCAAsC;IACtC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CACjC;AAED,MAAM,WAAW,cAAc;IAC7B,KAAK,CAAC,EAAE,KAAK,GAAG,SAAS,CAAA;IACzB,IAAI,CAAC,EAAE,OAAO,CAAA;IACd,MAAM,CAAC,EAAE,WAAW,GAAG,SAAS,CAAA;IAChC,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAC9B;;;;;;;;;;;;;;OAcG;IACH,cAAc,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IACnC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,SAAS,CAAA;CAC7C;AAED,MAAM,WAAW,WAAW,CAAC,CAAC;IAC5B,MAAM,EAAE,MAAM,CAAA;IACd,IAAI,EAAE,CAAC,CAAA;IACP,OAAO,EAAE,OAAO,CAAA;CACjB;AAED,sFAAsF;AACtF,eAAO,MAAM,GAAG,UAAW,MAAM,KAAG,MAAmC,CAAA;AAEvE;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,KAAK,GAAG,SAAS,GAAG,MAAM,CAa/D;AAED,qBAAa,UAAU;;IACrB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IAKxB,YAAY,OAAO,EAAE,aAAa,GAAG;QAAE,OAAO,EAAE,MAAM,CAAA;KAAE,EAWvD;IAED,yFAAyF;IACnF,OAAO,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,cAAmB,GAAG,OAAO,CAAC,CAAC,CAAC,CAEvF;IAED;;;;;OAKG;IACG,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,cAAmB,GAAG,OAAO,CAAC,QAAQ,CAAC,CAqB5F;IAED,qFAAqF;IAC/E,UAAU,CAAC,CAAC,EAChB,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,EACZ,OAAO,GAAE,cAAmB,GAC3B,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAYzB;CA8FF"}
|
package/dist/cjs/core/http.js
CHANGED
|
@@ -86,13 +86,18 @@ class HttpClient {
|
|
|
86
86
|
* time. Read it with `.blob()`, `.text()` or `.arrayBuffer()`.
|
|
87
87
|
*/
|
|
88
88
|
async fetchRaw(method, path, options = {}) {
|
|
89
|
-
|
|
89
|
+
// The body is touched only when the call FAILED — and then by the same
|
|
90
|
+
// reader a JSON call uses, so one 502 from the edge produces one message
|
|
91
|
+
// whichever method asked for it. The two used to disagree: this one fell
|
|
92
|
+
// back to neutral wording while `requestRaw` put the proxy's HTML page
|
|
93
|
+
// into `message`.
|
|
94
|
+
//
|
|
95
|
+
// On success the response is handed over unread, which also means the
|
|
96
|
+
// timeout ends at the headers here: the file body is the caller's to read
|
|
97
|
+
// and to bound, with their own signal.
|
|
98
|
+
const { response, endpoint, payload } = await this.#send(method, path, options, (r, ep) => r.ok ? Promise.resolve(undefined) : readJsonBody(r, ep));
|
|
90
99
|
if (!response.ok) {
|
|
91
|
-
const
|
|
92
|
-
.clone()
|
|
93
|
-
.json()
|
|
94
|
-
.catch(() => undefined);
|
|
95
|
-
const error = (0, errors_js_1.parseErrorBody)(response.status, body, endpoint);
|
|
100
|
+
const error = (0, errors_js_1.parseErrorBody)(response.status, payload, endpoint);
|
|
96
101
|
if (response.status === 401 && this.#options.onUnauthorized) {
|
|
97
102
|
await this.#options.onUnauthorized(error);
|
|
98
103
|
}
|
|
@@ -102,18 +107,28 @@ class HttpClient {
|
|
|
102
107
|
}
|
|
103
108
|
/** Same, but exposes the status — needed where 200 and 202 mean different things. */
|
|
104
109
|
async requestRaw(method, path, options = {}) {
|
|
105
|
-
const { response, endpoint } = await this.#send(method, path, options);
|
|
106
|
-
const data = await readBody(response, endpoint);
|
|
110
|
+
const { response, endpoint, payload } = await this.#send(method, path, options, readJsonBody);
|
|
107
111
|
if (!response.ok) {
|
|
108
|
-
const error = (0, errors_js_1.parseErrorBody)(response.status,
|
|
112
|
+
const error = (0, errors_js_1.parseErrorBody)(response.status, payload, endpoint);
|
|
109
113
|
if (response.status === 401 && this.#options.onUnauthorized) {
|
|
110
114
|
await this.#options.onUnauthorized(error);
|
|
111
115
|
}
|
|
112
116
|
throw error;
|
|
113
117
|
}
|
|
114
|
-
return { status: response.status, data:
|
|
118
|
+
return { status: response.status, data: payload, headers: response.headers };
|
|
115
119
|
}
|
|
116
|
-
|
|
120
|
+
/**
|
|
121
|
+
* One attempt: headers out, body in, cleanup.
|
|
122
|
+
*
|
|
123
|
+
* The body is read HERE, through `readPayload`, instead of by the caller
|
|
124
|
+
* afterwards — because the timeout and the caller's signal have to stay
|
|
125
|
+
* armed until the body is in hand. Headers arrive first and the body streams
|
|
126
|
+
* after; with the timer cleared at the headers, a server that answers and
|
|
127
|
+
* then stalls mid-body left a request hanging with nothing to end it. On a
|
|
128
|
+
* money path that is a transfer whose outcome is never learned, and no
|
|
129
|
+
* retry decision either.
|
|
130
|
+
*/
|
|
131
|
+
async #send(method, path, options, readPayload) {
|
|
117
132
|
const endpoint = `${method.toUpperCase()} ${path}`;
|
|
118
133
|
const url = `${this.baseUrl}${path}${serializeQuery(options.query)}`;
|
|
119
134
|
const timeoutMs = options.timeoutMs ?? this.#timeoutMs;
|
|
@@ -126,8 +141,14 @@ class HttpClient {
|
|
|
126
141
|
};
|
|
127
142
|
if (options.body !== undefined)
|
|
128
143
|
headers['content-type'] = 'application/json';
|
|
129
|
-
|
|
130
|
-
|
|
144
|
+
// NOTHING ELSE IS ADDED BY DEFAULT, and that is a browser constraint
|
|
145
|
+
// rather than minimalism: the API's CORS preflight allows exactly
|
|
146
|
+
// `Content-Type` and `Authorization`, so any further header of ours makes
|
|
147
|
+
// the preflight fail and the request is never sent. These three are safe —
|
|
148
|
+
// `accept` is CORS-safelisted, and `user-agent` is a forbidden header name
|
|
149
|
+
// the browser drops before it can be preflighted (it still reaches the API
|
|
150
|
+
// from Node and React Native, which is where it is useful). A header
|
|
151
|
+
// passed in through `headers` is the caller's own risk.
|
|
131
152
|
// A timer of our own on top of the caller's signal: `AbortSignal.timeout`
|
|
132
153
|
// is missing in some React Native runtimes, and "the caller cancelled" has
|
|
133
154
|
// to stay distinguishable from "time ran out" — on money paths those call
|
|
@@ -140,45 +161,89 @@ class HttpClient {
|
|
|
140
161
|
}, timeoutMs);
|
|
141
162
|
const onExternalAbort = () => controller.abort();
|
|
142
163
|
options.signal?.addEventListener('abort', onExternalAbort, { once: true });
|
|
143
|
-
|
|
164
|
+
const classify = (cause) => transportError(cause, { timedOut, timeoutMs, endpoint, signal: options.signal });
|
|
165
|
+
// The cleanup is an OUTER finally, so it also runs when `onTokenRotated`
|
|
166
|
+
// throws — a caller's storage failure should not leave our timer armed,
|
|
167
|
+
// ready to abort an unrelated stream seconds later.
|
|
144
168
|
try {
|
|
145
|
-
response
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
? {}
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
169
|
+
let response;
|
|
170
|
+
try {
|
|
171
|
+
response = await this.#fetch(url, {
|
|
172
|
+
method: method.toUpperCase(),
|
|
173
|
+
headers,
|
|
174
|
+
...(options.body === undefined ? {} : { body: JSON.stringify(options.body) }),
|
|
175
|
+
...(this.#options.credentials === undefined
|
|
176
|
+
? {}
|
|
177
|
+
: { credentials: this.#options.credentials }),
|
|
178
|
+
signal: controller.signal,
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
catch (cause) {
|
|
182
|
+
throw classify(cause);
|
|
183
|
+
}
|
|
184
|
+
// Rotation arrives on successful responses too, and is taken BEFORE the
|
|
185
|
+
// body: the token is valid whatever the body turns out to be, and a
|
|
186
|
+
// rotation we drop signs the client out at the next one.
|
|
187
|
+
const rotated = response.headers.get(ROTATED_TOKEN_HEADER);
|
|
188
|
+
if (rotated && this.#options.onTokenRotated)
|
|
189
|
+
await this.#options.onTokenRotated(rotated);
|
|
190
|
+
let payload;
|
|
191
|
+
try {
|
|
192
|
+
payload = await readPayload(response, endpoint);
|
|
193
|
+
}
|
|
194
|
+
catch (cause) {
|
|
195
|
+
throw classify(cause);
|
|
196
|
+
}
|
|
197
|
+
return { response, endpoint, payload };
|
|
161
198
|
}
|
|
162
199
|
finally {
|
|
163
200
|
clearTimeout(timer);
|
|
164
201
|
options.signal?.removeEventListener('abort', onExternalAbort);
|
|
165
202
|
}
|
|
166
|
-
// Rotation arrives on successful responses too.
|
|
167
|
-
const rotated = response.headers.get(ROTATED_TOKEN_HEADER);
|
|
168
|
-
if (rotated && this.#options.onTokenRotated)
|
|
169
|
-
await this.#options.onTokenRotated(rotated);
|
|
170
|
-
return { response, endpoint };
|
|
171
203
|
}
|
|
172
204
|
}
|
|
173
205
|
exports.HttpClient = HttpClient;
|
|
206
|
+
/**
|
|
207
|
+
* Names a transport failure, of the request or of the body behind it.
|
|
208
|
+
*
|
|
209
|
+
* The distinction is not cosmetic on a money path: a timeout may have been
|
|
210
|
+
* applied server-side (retry only with the same idempotency key), a cancel is
|
|
211
|
+
* the caller's own decision and must not be shown as a failure, and a network
|
|
212
|
+
* error never left the device. A `CoreError` arrives already named — the body
|
|
213
|
+
* reader raises one when a successful response is not the JSON the contract
|
|
214
|
+
* promises — and is passed through, so "the contract is wrong" is not reported
|
|
215
|
+
* as "the network is down".
|
|
216
|
+
*
|
|
217
|
+
* Our own timeout wins over the caller's signal, and both win over the cause:
|
|
218
|
+
* an abort mid-body surfaces as the abort that caused it, not as the opaque
|
|
219
|
+
* `AbortError` the stream rejects with.
|
|
220
|
+
*/
|
|
221
|
+
function transportError(cause, ctx) {
|
|
222
|
+
if (ctx.timedOut)
|
|
223
|
+
return (0, errors_js_1.timeoutError)(ctx.timeoutMs, ctx.endpoint);
|
|
224
|
+
if (ctx.signal?.aborted)
|
|
225
|
+
return (0, errors_js_1.abortedError)(ctx.endpoint);
|
|
226
|
+
if ((0, errors_js_1.isCoreError)(cause))
|
|
227
|
+
return cause;
|
|
228
|
+
return (0, errors_js_1.networkError)(cause, ctx.endpoint);
|
|
229
|
+
}
|
|
230
|
+
/** The longest fragment of a non-JSON error body worth carrying into a message. */
|
|
231
|
+
const MAX_PLAIN_ERROR_CHARS = 200;
|
|
174
232
|
/**
|
|
175
233
|
* An empty body (204, DELETE) is `undefined`, not a parse failure. Invalid
|
|
176
234
|
* JSON on a SUCCESSFUL status is a failure: the contract is not what we think
|
|
177
|
-
* it is, and returning `undefined` quietly is worse than throwing.
|
|
178
|
-
*
|
|
235
|
+
* it is, and returning `undefined` quietly is worse than throwing.
|
|
236
|
+
*
|
|
237
|
+
* A read that fails halfway is no longer swallowed. It used to be caught into
|
|
238
|
+
* an empty string, which turned a truncated response — a dropped connection,
|
|
239
|
+
* our own timeout firing while the body streamed — into `data: undefined`
|
|
240
|
+
* typed as the shape the caller asked for: a failure wearing the face of a
|
|
241
|
+
* successful empty answer, and on a balance or a transfer the worst possible
|
|
242
|
+
* disguise. The rejection now travels out to `transportError`, which names it
|
|
243
|
+
* a timeout, a cancel or a network failure.
|
|
179
244
|
*/
|
|
180
|
-
async function
|
|
181
|
-
const text = await response.text()
|
|
245
|
+
async function readJsonBody(response, endpoint) {
|
|
246
|
+
const text = await response.text();
|
|
182
247
|
if (!text)
|
|
183
248
|
return undefined;
|
|
184
249
|
try {
|
|
@@ -187,7 +252,32 @@ async function readBody(response, endpoint) {
|
|
|
187
252
|
catch (cause) {
|
|
188
253
|
if (response.ok)
|
|
189
254
|
throw (0, errors_js_1.parseError)(cause, endpoint);
|
|
190
|
-
return
|
|
255
|
+
return plainTextError(text);
|
|
191
256
|
}
|
|
192
257
|
}
|
|
258
|
+
/**
|
|
259
|
+
* A non-JSON error body reduced to something showable — or to nothing.
|
|
260
|
+
*
|
|
261
|
+
* Who sends these: everything in front of the API, never the API itself. A
|
|
262
|
+
* 502/504 while the worker is being replaced, a 403 from a WAF, a platform
|
|
263
|
+
* 429 — they answer with a whole HTML page (2318 bytes in one measured case).
|
|
264
|
+
* Passing that on as `{error: text}` put the page into `message`, which is the
|
|
265
|
+
* one field meant to be read by a person.
|
|
266
|
+
*
|
|
267
|
+
* Markup is therefore dropped and `parseErrorBody` falls back to its own
|
|
268
|
+
* wording for the status. A short line of plain text is kept instead of being
|
|
269
|
+
* dropped with it, because a proxy occasionally says something the status does
|
|
270
|
+
* not ("upstream connect error", "no healthy upstream").
|
|
271
|
+
*/
|
|
272
|
+
function plainTextError(text) {
|
|
273
|
+
// A leading `<` catches HTML and XML error documents alike; neither is ours.
|
|
274
|
+
const collapsed = text.trim().replace(/\s+/g, ' ');
|
|
275
|
+
if (!collapsed || collapsed.startsWith('<'))
|
|
276
|
+
return undefined;
|
|
277
|
+
return {
|
|
278
|
+
error: collapsed.length > MAX_PLAIN_ERROR_CHARS
|
|
279
|
+
? `${collapsed.slice(0, MAX_PLAIN_ERROR_CHARS)}…`
|
|
280
|
+
: collapsed,
|
|
281
|
+
};
|
|
282
|
+
}
|
|
193
283
|
//# sourceMappingURL=http.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"http.js","sourceRoot":"","sources":["../../../src/core/http.ts"],"names":[],"mappings":";;;;AAAA,
|
|
1
|
+
{"version":3,"file":"http.js","sourceRoot":"","sources":["../../../src/core/http.ts"],"names":[],"mappings":";;;;AAAA,2CAQoB;AACpB,8CAA2C;AAE3C;;;;;;;;;;;;;GAaG;AAEH,iDAAiD;AACjD,MAAM,oBAAoB,GAAG,gBAAgB,CAAA;AAE7C,2EAA2E;AAC3E,MAAM,kBAAkB,GAAG,MAAM,CAAA;AAqFjC,sFAAsF;AAC/E,MAAM,GAAG,GAAG,CAAC,KAAa,EAAU,EAAE,CAAC,kBAAkB,CAAC,KAAK,CAAC,CAAA;AAA1D,QAAA,GAAG,GAAH,GAAG,CAAuD;AAEvE;;;;;;;;;;;;;;;;GAgBG;AACH,wBAA+B,KAAwB;IACrD,IAAI,CAAC,KAAK;QAAE,OAAO,EAAE,CAAA;IACrB,MAAM,MAAM,GAAG,IAAI,eAAe,EAAE,CAAA;IACpC,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACjD,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,IAAI;YAAE,SAAQ;QACnD,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;YACzB,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC;gBAAE,MAAM,CAAC,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAA;QACvE,CAAC;aAAM,CAAC;YACN,MAAM,CAAC,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,CAAA;QACnC,CAAC;IACH,CAAC;IACD,MAAM,CAAC,GAAG,MAAM,CAAC,QAAQ,EAAE,CAAA;IAC3B,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAA;AACzB,CAAC;AAED;IACW,OAAO,CAAQ;IACf,QAAQ,CAAe;IACvB,MAAM,CAAyB;IAC/B,UAAU,CAAQ;IAE3B,YAAY,OAA4C;QACtD,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAA;QAClD,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAA;QACvB,MAAM,CAAC,GAAG,OAAO,CAAC,KAAK,IAAI,UAAU,CAAC,KAAK,CAAA;QAC3C,IAAI,OAAO,CAAC,KAAK,UAAU,EAAE,CAAC;YAC5B,MAAM,IAAI,KAAK,CACb,6FAA6F,CAC9F,CAAA;QACH,CAAC;QACD,IAAI,CAAC,MAAM,GAAG,CAAC,CAAA;QACf,IAAI,CAAC,UAAU,GAAG,OAAO,CAAC,SAAS,IAAI,kBAAkB,CAAA;IAC3D,CAAC;IAED,yFAAyF;IACzF,KAAK,CAAC,OAAO,CAAI,MAAc,EAAE,IAAY,EAAE,OAAO,GAAmB,EAAE;QACzE,OAAO,CAAC,MAAM,IAAI,CAAC,UAAU,CAAI,MAAM,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,IAAI,CAAA;IAC/D,CAAC;IAED;;;;;OAKG;IACH,KAAK,CAAC,QAAQ,CAAC,MAAc,EAAE,IAAY,EAAE,OAAO,GAAmB,EAAE;QACvE,uEAAuE;QACvE,yEAAyE;QACzE,yEAAyE;QACzE,uEAAuE;QACvE,kBAAkB;QAClB,EAAE;QACF,sEAAsE;QACtE,0EAA0E;QAC1E,uCAAuC;QACvC,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,EAAE,CACxF,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,EAAE,EAAE,CAAC,CACxD,CAAA;QACD,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YACjB,MAAM,KAAK,GAAG,IAAA,0BAAc,EAAC,QAAQ,CAAC,MAAM,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAA;YAChE,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG,IAAI,IAAI,CAAC,QAAQ,CAAC,cAAc,EAAE,CAAC;gBAC5D,MAAM,IAAI,CAAC,QAAQ,CAAC,cAAc,CAAC,KAAK,CAAC,CAAA;YAC3C,CAAC;YACD,MAAM,KAAK,CAAA;QACb,CAAC;QACD,OAAO,QAAQ,CAAA;IACjB,CAAC;IAED,qFAAqF;IACrF,KAAK,CAAC,UAAU,CACd,MAAc,EACd,IAAY,EACZ,OAAO,GAAmB,EAAE;QAE5B,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,YAAY,CAAC,CAAA;QAE7F,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YACjB,MAAM,KAAK,GAAG,IAAA,0BAAc,EAAC,QAAQ,CAAC,MAAM,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAA;YAChE,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG,IAAI,IAAI,CAAC,QAAQ,CAAC,cAAc,EAAE,CAAC;gBAC5D,MAAM,IAAI,CAAC,QAAQ,CAAC,cAAc,CAAC,KAAK,CAAC,CAAA;YAC3C,CAAC;YACD,MAAM,KAAK,CAAA;QACb,CAAC;QAED,OAAO,EAAE,MAAM,EAAE,QAAQ,CAAC,MAAM,EAAE,IAAI,EAAE,OAAY,EAAE,OAAO,EAAE,QAAQ,CAAC,OAAO,EAAE,CAAA;IACnF,CAAC;IAED;;;;;;;;;;OAUG;IACH,KAAK,CAAC,KAAK,CACT,MAAc,EACd,IAAY,EACZ,OAAuB,EACvB,WAAuE;QAEvE,MAAM,QAAQ,GAAG,GAAG,MAAM,CAAC,WAAW,EAAE,IAAI,IAAI,EAAE,CAAA;QAClD,MAAM,GAAG,GAAG,GAAG,IAAI,CAAC,OAAO,GAAG,IAAI,GAAG,cAAc,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAA;QACpE,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS,IAAI,IAAI,CAAC,UAAU,CAAA;QAEtD,MAAM,OAAO,GAA2B;YACtC,MAAM,EAAE,kBAAkB;YAC1B,YAAY,EAAE,uBAAuB,wBAAW,EAAE;YAClD,GAAG,IAAI,CAAC,QAAQ,CAAC,OAAO;YACxB,GAAG,CAAC,MAAM,IAAI,CAAC,QAAQ,CAAC,cAAc,EAAE,EAAE,CAAC;YAC3C,GAAG,OAAO,CAAC,OAAO;SACnB,CAAA;QACD,IAAI,OAAO,CAAC,IAAI,KAAK,SAAS;YAAE,OAAO,CAAC,cAAc,CAAC,GAAG,kBAAkB,CAAA;QAC5E,qEAAqE;QACrE,kEAAkE;QAClE,0EAA0E;QAC1E,2EAA2E;QAC3E,2EAA2E;QAC3E,2EAA2E;QAC3E,qEAAqE;QACrE,wDAAwD;QAExD,0EAA0E;QAC1E,2EAA2E;QAC3E,0EAA0E;QAC1E,2BAA2B;QAC3B,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAA;QACxC,IAAI,QAAQ,GAAG,KAAK,CAAA;QACpB,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE;YAC5B,QAAQ,GAAG,IAAI,CAAA;YACf,UAAU,CAAC,KAAK,EAAE,CAAA;QACpB,CAAC,EAAE,SAAS,CAAC,CAAA;QACb,MAAM,eAAe,GAAG,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,CAAA;QAChD,OAAO,CAAC,MAAM,EAAE,gBAAgB,CAAC,OAAO,EAAE,eAAe,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAA;QAE1E,MAAM,QAAQ,GAAG,CAAC,KAAc,EAAa,EAAE,CAC7C,cAAc,CAAC,KAAK,EAAE,EAAE,QAAQ,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC,CAAA;QAElF,yEAAyE;QACzE,wEAAwE;QACxE,oDAAoD;QACpD,IAAI,CAAC;YACH,IAAI,QAAkB,CAAA;YACtB,IAAI,CAAC;gBACH,QAAQ,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,GAAG,EAAE;oBAChC,MAAM,EAAE,MAAM,CAAC,WAAW,EAAE;oBAC5B,OAAO;oBACP,GAAG,CAAC,OAAO,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;oBAC7E,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,WAAW,KAAK,SAAS;wBACzC,CAAC,CAAC,EAAE;wBACJ,CAAC,CAAC,EAAE,WAAW,EAAE,IAAI,CAAC,QAAQ,CAAC,WAAW,EAAE,CAAC;oBAC/C,MAAM,EAAE,UAAU,CAAC,MAAM;iBAC1B,CAAC,CAAA;YACJ,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,MAAM,QAAQ,CAAC,KAAK,CAAC,CAAA;YACvB,CAAC;YAED,wEAAwE;YACxE,oEAAoE;YACpE,yDAAyD;YACzD,MAAM,OAAO,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC,CAAA;YAC1D,IAAI,OAAO,IAAI,IAAI,CAAC,QAAQ,CAAC,cAAc;gBAAE,MAAM,IAAI,CAAC,QAAQ,CAAC,cAAc,CAAC,OAAO,CAAC,CAAA;YAExF,IAAI,OAAgB,CAAA;YACpB,IAAI,CAAC;gBACH,OAAO,GAAG,MAAM,WAAW,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAA;YACjD,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,MAAM,QAAQ,CAAC,KAAK,CAAC,CAAA;YACvB,CAAC;YAED,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAA;QACxC,CAAC;gBAAS,CAAC;YACT,YAAY,CAAC,KAAK,CAAC,CAAA;YACnB,OAAO,CAAC,MAAM,EAAE,mBAAmB,CAAC,OAAO,EAAE,eAAe,CAAC,CAAA;QAC/D,CAAC;IACH,CAAC;CACF;;AAED;;;;;;;;;;;;;;GAcG;AACH,SAAS,cAAc,CACrB,KAAc,EACd,GAKC;IAED,IAAI,GAAG,CAAC,QAAQ;QAAE,OAAO,IAAA,wBAAY,EAAC,GAAG,CAAC,SAAS,EAAE,GAAG,CAAC,QAAQ,CAAC,CAAA;IAClE,IAAI,GAAG,CAAC,MAAM,EAAE,OAAO;QAAE,OAAO,IAAA,wBAAY,EAAC,GAAG,CAAC,QAAQ,CAAC,CAAA;IAC1D,IAAI,IAAA,uBAAW,EAAC,KAAK,CAAC;QAAE,OAAO,KAAK,CAAA;IACpC,OAAO,IAAA,wBAAY,EAAC,KAAK,EAAE,GAAG,CAAC,QAAQ,CAAC,CAAA;AAC1C,CAAC;AAED,mFAAmF;AACnF,MAAM,qBAAqB,GAAG,GAAG,CAAA;AAEjC;;;;;;;;;;;;GAYG;AACH,KAAK,UAAU,YAAY,CAAC,QAAkB,EAAE,QAAgB;IAC9D,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAA;IAClC,IAAI,CAAC,IAAI;QAAE,OAAO,SAAS,CAAA;IAC3B,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAY,CAAA;IACpC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,QAAQ,CAAC,EAAE;YAAE,MAAM,IAAA,sBAAU,EAAC,KAAK,EAAE,QAAQ,CAAC,CAAA;QAClD,OAAO,cAAc,CAAC,IAAI,CAAC,CAAA;IAC7B,CAAC;AACH,CAAC;AAED;;;;;;;;;;;;;GAaG;AACH,SAAS,cAAc,CAAC,IAAY;IAClC,6EAA6E;IAC7E,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;IAClD,IAAI,CAAC,SAAS,IAAI,SAAS,CAAC,UAAU,CAAC,GAAG,CAAC;QAAE,OAAO,SAAS,CAAA;IAC7D,OAAO;QACL,KAAK,EACH,SAAS,CAAC,MAAM,GAAG,qBAAqB;YACtC,CAAC,CAAC,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC,EAAE,qBAAqB,CAAC,GAAG;YACjD,CAAC,CAAC,SAAS;KAChB,CAAA;AACH,CAAC"}
|
|
@@ -1,5 +1,32 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Keyset pagination
|
|
2
|
+
* Keyset pagination — for the eleven endpoints that have it.
|
|
3
|
+
*
|
|
4
|
+
* "Every list returns `{items, nextCursor}`" is what this file used to claim,
|
|
5
|
+
* and it is not what the API does. Counted over the spec snapshot
|
|
6
|
+
* (`openapi/spec.json`), the reading endpoints fall into three shapes:
|
|
7
|
+
*
|
|
8
|
+
* • 11 GETs take `cursor`/`limit` and answer a `nextCursor` — addresses,
|
|
9
|
+
* history, approval requests, members, counterparties, counterparty
|
|
10
|
+
* groups, operation categories, operation relations, ledger entries, a
|
|
11
|
+
* vault's policies, balances. These are what `paginate` is for;
|
|
12
|
+
* • 18 answer `{items}` with NO cursor parameter at all — folders and their
|
|
13
|
+
* grants, address shares, shared-with-me / shared-by-me, visibility
|
|
14
|
+
* grants, category assignments and their versions, report templates and
|
|
15
|
+
* snapshots, user groups and their members, status history, the
|
|
16
|
+
* admin-level `/policies` list and one policy's versions (18 paths, two
|
|
17
|
+
* of them the older `/address-groups` prefix of the folder endpoints).
|
|
18
|
+
* What you get is everything there is; `paginate` over one of them yields
|
|
19
|
+
* that single page and stops, because an absent `nextCursor` is the
|
|
20
|
+
* end-of-list signal;
|
|
21
|
+
* • 8 answer a BARE ARRAY rather than an object: `/networks`, `/tokens`,
|
|
22
|
+
* `/vaults`, a vault's `/policy-groups` and `/invitations`, one
|
|
23
|
+
* operation's `/relations`, a policy group's `/policies`, a user's
|
|
24
|
+
* `/policy-groups`. There is no `items` to walk, so `paginate` refuses
|
|
25
|
+
* them by name instead of quietly yielding nothing.
|
|
26
|
+
*
|
|
27
|
+
* `/balances` is the one cursored endpoint `paginate` CANNOT walk: its page is
|
|
28
|
+
* `{vaultId, totals, accounts, nextCursor}` and the array is called
|
|
29
|
+
* `accounts`. Pass the cursor by hand there.
|
|
3
30
|
*
|
|
4
31
|
* The cursor is opaque: do not parse it, build it or compare it. A
|
|
5
32
|
* `nextCursor` of `null` is the only end-of-list signal — an empty page is
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pagination.d.ts","sourceRoot":"","sources":["../../../src/core/pagination.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"pagination.d.ts","sourceRoot":"","sources":["../../../src/core/pagination.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAEH,MAAM,WAAW,IAAI,CAAC,CAAC;IACrB,QAAQ,CAAC,KAAK,EAAE,CAAC,EAAE,CAAA;IACnB,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;CACnC;AAED,MAAM,WAAW,UAAU;IACzB,qCAAqC;IACrC,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAC1B,6DAA6D;IAC7D,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;CAC5B;AAED;;;;;;;;;GASG;AACH,wBAAuB,QAAQ,CAAC,CAAC,EAC/B,SAAS,EAAE,CAAC,MAAM,EAAE,UAAU,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EACnD,OAAO,GAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAO,GAClD,cAAc,CAAC,CAAC,EAAE,IAAI,EAAE,SAAS,CAAC,CAmCpC;AAED,uEAAuE;AACvE,wBAAsB,UAAU,CAAC,CAAC,EAChC,SAAS,EAAE,CAAC,MAAM,EAAE,UAAU,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EACnD,OAAO,GAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAO,GAClD,OAAO,CAAC,CAAC,EAAE,CAAC,CAId"}
|