@calimero-network/mero-js 26.10.0 → 27.0.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 +73 -288
- package/dist/cloud-v2/attestation.d.ts +91 -0
- package/dist/cloud-v2/attestation.js +135 -0
- package/dist/cloud-v2/capabilities.d.ts +30 -0
- package/dist/cloud-v2/capabilities.js +31 -0
- package/dist/cloud-v2/client.d.ts +426 -0
- package/dist/cloud-v2/client.js +646 -0
- package/dist/cloud-v2/errors.d.ts +98 -0
- package/dist/cloud-v2/errors.js +165 -0
- package/dist/cloud-v2/index.d.ts +10 -0
- package/dist/cloud-v2/index.js +5 -0
- package/dist/cloud-v2/passkey.d.ts +27 -0
- package/dist/cloud-v2/passkey.js +73 -0
- package/dist/crypto/internal.d.ts +3 -37
- package/dist/crypto/internal.js +3 -72
- package/dist/index.browser.mjs +4 -2
- package/dist/index.browser.mjs.map +4 -4
- package/dist/index.cjs +1750 -12767
- package/dist/index.cjs.map +4 -4
- package/dist/index.d.ts +3 -56
- package/dist/index.js +14 -75
- package/dist/index.mjs +1750 -12767
- package/dist/index.mjs.map +4 -4
- package/dist/sealed/index.d.ts +4 -4
- package/dist/sealed/index.js +2 -2
- package/dist/sealed/release.d.ts +21 -76
- package/dist/sealed/release.js +24 -108
- package/dist/sealed/sealed.d.ts +8 -56
- package/dist/sealed/sealed.js +11 -89
- package/dist/sealed/verify.d.ts +7 -13
- package/dist/sealed/verify.js +3 -7
- package/package.json +8 -13
- package/dist/account/account-admin.d.ts +0 -80
- package/dist/account/account-admin.js +0 -346
- package/dist/account/account.d.ts +0 -196
- package/dist/account/account.js +0 -269
- package/dist/account/application-id.d.ts +0 -50
- package/dist/account/application-id.js +0 -83
- package/dist/account/bootstrap-from-invitation.d.ts +0 -110
- package/dist/account/bootstrap-from-invitation.js +0 -80
- package/dist/account/create-context.d.ts +0 -103
- package/dist/account/create-context.js +0 -267
- package/dist/account/govern.d.ts +0 -24
- package/dist/account/govern.js +0 -50
- package/dist/account/index.d.ts +0 -26
- package/dist/account/index.js +0 -15
- package/dist/account/join-as-account.d.ts +0 -23
- package/dist/account/join-as-account.js +0 -34
- package/dist/account/join-with-node.d.ts +0 -115
- package/dist/account/join-with-node.js +0 -161
- package/dist/account/node-admin.d.ts +0 -20
- package/dist/account/node-admin.js +0 -33
- package/dist/account/relay-from-invitation.d.ts +0 -137
- package/dist/account/relay-from-invitation.js +0 -180
- package/dist/account/relay-login-error.d.ts +0 -32
- package/dist/account/relay-login-error.js +0 -34
- package/dist/account/session.d.ts +0 -266
- package/dist/account/session.js +0 -915
- package/dist/account/wordlist.d.ts +0 -16
- package/dist/account/wordlist.js +0 -273
- package/dist/admin-api/admin-client.d.ts +0 -686
- package/dist/admin-api/admin-client.js +0 -1225
- package/dist/admin-api/admin-factory.d.ts +0 -14
- package/dist/admin-api/admin-factory.js +0 -22
- package/dist/admin-api/admin-types.d.ts +0 -2041
- package/dist/admin-api/admin-types.js +0 -12
- package/dist/admin-api/index.d.ts +0 -4
- package/dist/admin-api/index.js +0 -5
- package/dist/admin-api/redeem-invitation.d.ts +0 -101
- package/dist/admin-api/redeem-invitation.js +0 -200
- package/dist/auth/index.d.ts +0 -34
- package/dist/auth/index.js +0 -67
- package/dist/auth-api/auth-client.d.ts +0 -31
- package/dist/auth-api/auth-client.js +0 -117
- package/dist/auth-api/auth-factory.d.ts +0 -7
- package/dist/auth-api/auth-factory.js +0 -41
- package/dist/auth-api/auth-types.d.ts +0 -130
- package/dist/auth-api/auth-types.js +0 -2
- package/dist/auth-api/index.d.ts +0 -3
- package/dist/auth-api/index.js +0 -4
- package/dist/capabilities.d.ts +0 -84
- package/dist/capabilities.js +0 -117
- package/dist/cloud/account-ownership.d.ts +0 -63
- package/dist/cloud/account-ownership.js +0 -87
- package/dist/cloud/cloud-client.d.ts +0 -949
- package/dist/cloud/cloud-client.js +0 -1068
- package/dist/cloud/connect.d.ts +0 -213
- package/dist/cloud/connect.js +0 -260
- package/dist/cloud/enrol-redirect.d.ts +0 -181
- package/dist/cloud/enrol-redirect.js +0 -244
- package/dist/cloud/index.d.ts +0 -12
- package/dist/cloud/index.js +0 -10
- package/dist/cloud/link-redirect.d.ts +0 -95
- package/dist/cloud/link-redirect.js +0 -121
- package/dist/cloud/link-state.d.ts +0 -36
- package/dist/cloud/link-state.js +0 -104
- package/dist/cloud/routing-proof.d.ts +0 -113
- package/dist/cloud/routing-proof.js +0 -96
- package/dist/device-cert/device-cert.d.ts +0 -189
- package/dist/device-cert/device-cert.js +0 -239
- package/dist/device-cert/device-scope.d.ts +0 -58
- package/dist/device-cert/device-scope.js +0 -76
- package/dist/device-cert/index.d.ts +0 -4
- package/dist/device-cert/index.js +0 -3
- package/dist/ephemeral/codec.d.ts +0 -4
- package/dist/ephemeral/codec.js +0 -12
- package/dist/ephemeral/index.d.ts +0 -57
- package/dist/ephemeral/index.js +0 -101
- package/dist/ephemeral/types.d.ts +0 -27
- package/dist/ephemeral/types.js +0 -1
- package/dist/errors/classify.d.ts +0 -65
- package/dist/errors/classify.js +0 -117
- package/dist/errors/index.d.ts +0 -2
- package/dist/errors/index.js +0 -1
- package/dist/events/group.d.ts +0 -95
- package/dist/events/group.js +0 -10
- package/dist/events/index.d.ts +0 -5
- package/dist/events/index.js +0 -2
- package/dist/events/sse.d.ts +0 -127
- package/dist/events/sse.js +0 -469
- package/dist/events/ws.d.ts +0 -57
- package/dist/events/ws.js +0 -212
- package/dist/http-client/api-response.d.ts +0 -15
- package/dist/http-client/api-response.js +0 -1
- package/dist/http-client/http-factory.d.ts +0 -71
- package/dist/http-client/http-factory.js +0 -68
- package/dist/http-client/http-types.d.ts +0 -87
- package/dist/http-client/http-types.js +0 -1
- package/dist/http-client/index.d.ts +0 -7
- package/dist/http-client/index.js +0 -11
- package/dist/http-client/path-segment.d.ts +0 -1
- package/dist/http-client/path-segment.js +0 -8
- package/dist/http-client/retry.d.ts +0 -5
- package/dist/http-client/retry.js +0 -82
- package/dist/http-client/signal-utils.d.ts +0 -2
- package/dist/http-client/signal-utils.js +0 -41
- package/dist/http-client/web-client.d.ts +0 -80
- package/dist/http-client/web-client.js +0 -557
- package/dist/invitation/index.d.ts +0 -2
- package/dist/invitation/index.js +0 -2
- package/dist/invitation/invitation.d.ts +0 -106
- package/dist/invitation/invitation.js +0 -104
- package/dist/login/index.d.ts +0 -4
- package/dist/login/index.js +0 -3
- package/dist/login/login.d.ts +0 -111
- package/dist/login/login.js +0 -110
- package/dist/login/session.d.ts +0 -124
- package/dist/login/session.js +0 -141
- package/dist/mero-js.d.ts +0 -231
- package/dist/mero-js.js +0 -469
- package/dist/namespace-op/index.d.ts +0 -2
- package/dist/namespace-op/index.js +0 -3
- package/dist/namespace-op/namespace-op.d.ts +0 -150
- package/dist/namespace-op/namespace-op.js +0 -191
- package/dist/nodeDiscovery.d.ts +0 -47
- package/dist/nodeDiscovery.js +0 -101
- package/dist/owner-op/index.d.ts +0 -2
- package/dist/owner-op/index.js +0 -3
- package/dist/owner-op/owner-op.d.ts +0 -119
- package/dist/owner-op/owner-op.js +0 -214
- package/dist/presence/relay-presence.d.ts +0 -56
- package/dist/presence/relay-presence.js +0 -107
- package/dist/presence/statement.d.ts +0 -12
- package/dist/presence/statement.js +0 -17
- package/dist/relay/index.d.ts +0 -4
- package/dist/relay/index.js +0 -2
- package/dist/relay/nonce-source.d.ts +0 -72
- package/dist/relay/nonce-source.js +0 -111
- package/dist/relay/relay-client.d.ts +0 -472
- package/dist/relay/relay-client.js +0 -518
- package/dist/relay-attestation/attest-node-key.d.ts +0 -66
- package/dist/relay-attestation/attest-node-key.js +0 -110
- package/dist/relay-attestation/index.d.ts +0 -1
- package/dist/relay-attestation/index.js +0 -1
- package/dist/request/caller-proof.d.ts +0 -43
- package/dist/request/caller-proof.js +0 -36
- package/dist/request/index.d.ts +0 -3
- package/dist/request/index.js +0 -3
- package/dist/request/proof-signer.d.ts +0 -49
- package/dist/request/proof-signer.js +0 -59
- package/dist/request/request-sig.d.ts +0 -99
- package/dist/request/request-sig.js +0 -95
- package/dist/request-proof/authorizer.d.ts +0 -41
- package/dist/request-proof/authorizer.js +0 -60
- package/dist/request-proof/index.d.ts +0 -4
- package/dist/request-proof/index.js +0 -2
- package/dist/request-proof/request-proof.d.ts +0 -53
- package/dist/request-proof/request-proof.js +0 -95
- package/dist/rpc/index.d.ts +0 -64
- package/dist/rpc/index.js +0 -78
- package/dist/signer/index.d.ts +0 -2
- package/dist/signer/index.js +0 -3
- package/dist/signer/signer.d.ts +0 -92
- package/dist/signer/signer.js +0 -147
- package/dist/token-store/index.d.ts +0 -27
- package/dist/token-store/index.js +0 -62
- package/dist/transport/index.d.ts +0 -6
- package/dist/transport/index.js +0 -3
- package/dist/transport/mero-client.d.ts +0 -294
- package/dist/transport/mero-client.js +0 -386
- package/dist/transport/relay-observer.d.ts +0 -152
- package/dist/transport/relay-observer.js +0 -173
- package/dist/transport/relay-transport.d.ts +0 -73
- package/dist/transport/relay-transport.js +0 -94
- package/dist/transport/types.d.ts +0 -100
- package/dist/transport/types.js +0 -32
- package/dist/types/api-response.d.ts +0 -15
- package/dist/types/api-response.js +0 -1
- package/dist/types/index.d.ts +0 -1
- package/dist/types/index.js +0 -1
- package/dist/warrant/creation-warrant.d.ts +0 -163
- package/dist/warrant/creation-warrant.js +0 -194
- package/dist/warrant/governance-op.d.ts +0 -202
- package/dist/warrant/governance-op.js +0 -355
- package/dist/warrant/governance-warrant.d.ts +0 -124
- package/dist/warrant/governance-warrant.js +0 -164
- package/dist/warrant/index.d.ts +0 -8
- package/dist/warrant/index.js +0 -5
- package/dist/warrant/warrant.d.ts +0 -188
- package/dist/warrant/warrant.js +0 -202
package/dist/events/ws.js
DELETED
|
@@ -1,212 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @experimental WebSocket event client. The SSE client (`SseClient`) is the
|
|
3
|
-
* recommended transport for production — use `MeroJs.events` instead of `MeroJs.ws`.
|
|
4
|
-
*/
|
|
5
|
-
export class WsClient {
|
|
6
|
-
constructor(opts) {
|
|
7
|
-
this.ws = null;
|
|
8
|
-
this.closed = false;
|
|
9
|
-
this.reconnectAttempt = 0;
|
|
10
|
-
this.reconnectTimer = null;
|
|
11
|
-
this.subscribedContextIds = new Set();
|
|
12
|
-
this.subscribedGroupIds = new Set();
|
|
13
|
-
this.listeners = { connect: [], event: [], error: [] };
|
|
14
|
-
this.baseUrl = opts.baseUrl.replace(/\/+$/, '');
|
|
15
|
-
this.getAuthToken = opts.getAuthToken;
|
|
16
|
-
}
|
|
17
|
-
on(event, handler) {
|
|
18
|
-
const key = event;
|
|
19
|
-
if (key in this.listeners) {
|
|
20
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
21
|
-
const arr = this.listeners[key];
|
|
22
|
-
if (!arr.includes(handler))
|
|
23
|
-
arr.push(handler);
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
off(event, handler) {
|
|
27
|
-
const key = event;
|
|
28
|
-
if (key in this.listeners) {
|
|
29
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
30
|
-
const arr = this.listeners[key];
|
|
31
|
-
const idx = arr.indexOf(handler);
|
|
32
|
-
if (idx !== -1)
|
|
33
|
-
arr.splice(idx, 1);
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
emit(event, arg) {
|
|
37
|
-
const key = event;
|
|
38
|
-
if (key in this.listeners) {
|
|
39
|
-
for (const handler of this.listeners[key]) {
|
|
40
|
-
try {
|
|
41
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
42
|
-
handler(arg);
|
|
43
|
-
}
|
|
44
|
-
catch {
|
|
45
|
-
// Swallow handler errors
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
async connect() {
|
|
51
|
-
if (this.ws && (this.ws.readyState === 0 /* CONNECTING */ || this.ws.readyState === 1 /* OPEN */)) {
|
|
52
|
-
return;
|
|
53
|
-
}
|
|
54
|
-
this.closed = false;
|
|
55
|
-
try {
|
|
56
|
-
const token = await this.getAuthToken();
|
|
57
|
-
if (!token) {
|
|
58
|
-
throw new Error('No authentication token available for WebSocket connection');
|
|
59
|
-
}
|
|
60
|
-
// Browser WebSocket API can't set headers, use query param
|
|
61
|
-
const wsUrl = this.baseUrl.replace(/^http/, 'ws');
|
|
62
|
-
this.ws = new WebSocket(`${wsUrl}/ws?token=${encodeURIComponent(token)}`);
|
|
63
|
-
this.ws.onopen = () => {
|
|
64
|
-
this.reconnectAttempt = 0;
|
|
65
|
-
this.emit('connect');
|
|
66
|
-
this.resubscribeAfterReconnect();
|
|
67
|
-
};
|
|
68
|
-
this.ws.onmessage = (event) => {
|
|
69
|
-
this.handleMessage(event.data);
|
|
70
|
-
};
|
|
71
|
-
this.ws.onerror = () => {
|
|
72
|
-
this.emit('error', new Error('WebSocket error'));
|
|
73
|
-
};
|
|
74
|
-
this.ws.onclose = () => {
|
|
75
|
-
if (!this.closed) {
|
|
76
|
-
this.scheduleReconnect();
|
|
77
|
-
}
|
|
78
|
-
};
|
|
79
|
-
}
|
|
80
|
-
catch (err) {
|
|
81
|
-
if (this.closed)
|
|
82
|
-
return;
|
|
83
|
-
const error = err instanceof Error ? err : new Error(String(err));
|
|
84
|
-
this.emit('error', error);
|
|
85
|
-
this.scheduleReconnect();
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
handleMessage(raw) {
|
|
89
|
-
if (typeof raw !== 'string')
|
|
90
|
-
return;
|
|
91
|
-
try {
|
|
92
|
-
const msg = JSON.parse(raw);
|
|
93
|
-
if (!msg.result)
|
|
94
|
-
return;
|
|
95
|
-
let eventData = msg.result.data;
|
|
96
|
-
if (Array.isArray(eventData)) {
|
|
97
|
-
try {
|
|
98
|
-
const bytes = new Uint8Array(eventData);
|
|
99
|
-
const text = new TextDecoder().decode(bytes);
|
|
100
|
-
eventData = JSON.parse(text);
|
|
101
|
-
}
|
|
102
|
-
catch {
|
|
103
|
-
// Keep raw data
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
if (msg.result.contextId) {
|
|
107
|
-
this.emit('event', {
|
|
108
|
-
contextId: msg.result.contextId,
|
|
109
|
-
// Forward the event tag (sibling of `data` in core's flattened
|
|
110
|
-
// payload) so consumers can discriminate, matching `SseClient`.
|
|
111
|
-
type: msg.result.type,
|
|
112
|
-
data: eventData,
|
|
113
|
-
});
|
|
114
|
-
return;
|
|
115
|
-
}
|
|
116
|
-
// Group-keyed event message (untagged NodeEvent's membership and
|
|
117
|
-
// migration variants; the `type` tag tells them apart).
|
|
118
|
-
if (msg.result.groupId) {
|
|
119
|
-
this.emit('event', {
|
|
120
|
-
groupId: msg.result.groupId,
|
|
121
|
-
type: msg.result.type,
|
|
122
|
-
data: eventData,
|
|
123
|
-
});
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
catch {
|
|
127
|
-
// Invalid JSON, ignore
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
subscribe(idsOrOpts) {
|
|
131
|
-
const opts = Array.isArray(idsOrOpts) ? { contextIds: idsOrOpts } : idsOrOpts;
|
|
132
|
-
for (const id of opts.contextIds ?? []) {
|
|
133
|
-
this.subscribedContextIds.add(id);
|
|
134
|
-
}
|
|
135
|
-
for (const id of opts.groupIds ?? []) {
|
|
136
|
-
this.subscribedGroupIds.add(id);
|
|
137
|
-
}
|
|
138
|
-
if (this.ws && this.ws.readyState === 1 /* OPEN */) {
|
|
139
|
-
this.sendMessage({
|
|
140
|
-
id: null,
|
|
141
|
-
method: 'subscribe',
|
|
142
|
-
params: this.buildSubscriptionParams(opts.contextIds ?? [], opts.groupIds ?? []),
|
|
143
|
-
});
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
unsubscribe(idsOrOpts) {
|
|
147
|
-
const opts = Array.isArray(idsOrOpts) ? { contextIds: idsOrOpts } : idsOrOpts;
|
|
148
|
-
for (const id of opts.contextIds ?? []) {
|
|
149
|
-
this.subscribedContextIds.delete(id);
|
|
150
|
-
}
|
|
151
|
-
for (const id of opts.groupIds ?? []) {
|
|
152
|
-
this.subscribedGroupIds.delete(id);
|
|
153
|
-
}
|
|
154
|
-
if (this.ws && this.ws.readyState === 1 /* OPEN */) {
|
|
155
|
-
this.sendMessage({
|
|
156
|
-
id: null,
|
|
157
|
-
method: 'unsubscribe',
|
|
158
|
-
params: this.buildSubscriptionParams(opts.contextIds ?? [], opts.groupIds ?? []),
|
|
159
|
-
});
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
resubscribeAfterReconnect() {
|
|
163
|
-
if (this.subscribedContextIds.size === 0 && this.subscribedGroupIds.size === 0)
|
|
164
|
-
return;
|
|
165
|
-
this.sendMessage({
|
|
166
|
-
id: null,
|
|
167
|
-
method: 'subscribe',
|
|
168
|
-
params: this.buildSubscriptionParams([...this.subscribedContextIds], [...this.subscribedGroupIds]),
|
|
169
|
-
});
|
|
170
|
-
}
|
|
171
|
-
buildSubscriptionParams(contextIds, groupIds) {
|
|
172
|
-
const params = {};
|
|
173
|
-
if (contextIds.length > 0)
|
|
174
|
-
params.contextIds = contextIds;
|
|
175
|
-
if (groupIds.length > 0)
|
|
176
|
-
params.groupIds = groupIds;
|
|
177
|
-
return params;
|
|
178
|
-
}
|
|
179
|
-
sendMessage(msg) {
|
|
180
|
-
if (this.ws && this.ws.readyState === 1 /* OPEN */) {
|
|
181
|
-
this.ws.send(JSON.stringify(msg));
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
scheduleReconnect() {
|
|
185
|
-
if (this.closed)
|
|
186
|
-
return;
|
|
187
|
-
if (this.reconnectTimer) {
|
|
188
|
-
clearTimeout(this.reconnectTimer);
|
|
189
|
-
}
|
|
190
|
-
const delay = Math.min(1000 * Math.pow(2, this.reconnectAttempt), WsClient.MAX_BACKOFF_MS);
|
|
191
|
-
this.reconnectAttempt++;
|
|
192
|
-
this.reconnectTimer = setTimeout(() => {
|
|
193
|
-
this.reconnectTimer = null;
|
|
194
|
-
this.connect();
|
|
195
|
-
}, delay);
|
|
196
|
-
}
|
|
197
|
-
close() {
|
|
198
|
-
this.closed = true;
|
|
199
|
-
if (this.reconnectTimer) {
|
|
200
|
-
clearTimeout(this.reconnectTimer);
|
|
201
|
-
this.reconnectTimer = null;
|
|
202
|
-
}
|
|
203
|
-
if (this.ws) {
|
|
204
|
-
this.ws.onclose = null;
|
|
205
|
-
this.ws.close();
|
|
206
|
-
this.ws = null;
|
|
207
|
-
}
|
|
208
|
-
this.subscribedContextIds.clear();
|
|
209
|
-
this.subscribedGroupIds.clear();
|
|
210
|
-
}
|
|
211
|
-
}
|
|
212
|
-
WsClient.MAX_BACKOFF_MS = 30000;
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
export type ErrorResponse = {
|
|
2
|
-
code?: number;
|
|
3
|
-
message: string;
|
|
4
|
-
};
|
|
5
|
-
export type ResponseData<D = unknown> = {
|
|
6
|
-
data: D;
|
|
7
|
-
error: null;
|
|
8
|
-
} | {
|
|
9
|
-
data: null;
|
|
10
|
-
error: ErrorResponse;
|
|
11
|
-
};
|
|
12
|
-
export type ApiResponse<D = unknown> = Promise<ResponseData<D>>;
|
|
13
|
-
export interface SuccessResponse {
|
|
14
|
-
success: boolean;
|
|
15
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
import { Transport, HttpClient } from './http-types.js';
|
|
2
|
-
export declare function createHttpClient(transport: Transport): HttpClient;
|
|
3
|
-
export declare function createBrowserHttpClient(options: {
|
|
4
|
-
baseUrl: string;
|
|
5
|
-
fetch?: typeof fetch;
|
|
6
|
-
getAuthToken?: () => Promise<string | undefined>;
|
|
7
|
-
getProof?: Transport['getProof'];
|
|
8
|
-
onTokenRefresh?: (newToken: string) => Promise<void>;
|
|
9
|
-
/**
|
|
10
|
-
* Callback to refresh the access token when a 401 error with 'token_expired' is detected.
|
|
11
|
-
* Should return the new access token, or throw an error if refresh fails.
|
|
12
|
-
* If provided, the client will automatically retry the request after a successful refresh.
|
|
13
|
-
*/
|
|
14
|
-
refreshToken?: () => Promise<string>;
|
|
15
|
-
/**
|
|
16
|
-
* Callback invoked when the server reports a revoked token family
|
|
17
|
-
* (`x-auth-error: token_reuse` / `token_revoked`). Terminal — the request is
|
|
18
|
-
* never retried; clear stored tokens and force a re-login.
|
|
19
|
-
*/
|
|
20
|
-
onAuthRevoked?: () => Promise<void> | void;
|
|
21
|
-
defaultHeaders?: Record<string, string>;
|
|
22
|
-
timeoutMs?: number;
|
|
23
|
-
credentials?: RequestCredentials;
|
|
24
|
-
defaultAbortSignal?: AbortSignal;
|
|
25
|
-
}): HttpClient;
|
|
26
|
-
export declare function createNodeHttpClient(options: {
|
|
27
|
-
baseUrl: string;
|
|
28
|
-
fetch?: typeof fetch;
|
|
29
|
-
getAuthToken?: () => Promise<string | undefined>;
|
|
30
|
-
getProof?: Transport['getProof'];
|
|
31
|
-
onTokenRefresh?: (newToken: string) => Promise<void>;
|
|
32
|
-
/**
|
|
33
|
-
* Callback to refresh the access token when a 401 error with 'token_expired' is detected.
|
|
34
|
-
* Should return the new access token, or throw an error if refresh fails.
|
|
35
|
-
* If provided, the client will automatically retry the request after a successful refresh.
|
|
36
|
-
*/
|
|
37
|
-
refreshToken?: () => Promise<string>;
|
|
38
|
-
/**
|
|
39
|
-
* Callback invoked when the server reports a revoked token family
|
|
40
|
-
* (`x-auth-error: token_reuse` / `token_revoked`). Terminal — the request is
|
|
41
|
-
* never retried; clear stored tokens and force a re-login.
|
|
42
|
-
*/
|
|
43
|
-
onAuthRevoked?: () => Promise<void> | void;
|
|
44
|
-
defaultHeaders?: Record<string, string>;
|
|
45
|
-
timeoutMs?: number;
|
|
46
|
-
credentials?: RequestCredentials;
|
|
47
|
-
defaultAbortSignal?: AbortSignal;
|
|
48
|
-
}): HttpClient;
|
|
49
|
-
export declare function createUniversalHttpClient(options: {
|
|
50
|
-
baseUrl: string;
|
|
51
|
-
fetch?: typeof fetch;
|
|
52
|
-
getAuthToken?: () => Promise<string | undefined>;
|
|
53
|
-
getProof?: Transport['getProof'];
|
|
54
|
-
onTokenRefresh?: (newToken: string) => Promise<void>;
|
|
55
|
-
/**
|
|
56
|
-
* Callback to refresh the access token when a 401 error with 'token_expired' is detected.
|
|
57
|
-
* Should return the new access token, or throw an error if refresh fails.
|
|
58
|
-
* If provided, the client will automatically retry the request after a successful refresh.
|
|
59
|
-
*/
|
|
60
|
-
refreshToken?: () => Promise<string>;
|
|
61
|
-
/**
|
|
62
|
-
* Callback invoked when the server reports a revoked token family
|
|
63
|
-
* (`x-auth-error: token_reuse` / `token_revoked`). Terminal — the request is
|
|
64
|
-
* never retried; clear stored tokens and force a re-login.
|
|
65
|
-
*/
|
|
66
|
-
onAuthRevoked?: () => Promise<void> | void;
|
|
67
|
-
defaultHeaders?: Record<string, string>;
|
|
68
|
-
timeoutMs?: number;
|
|
69
|
-
credentials?: RequestCredentials;
|
|
70
|
-
defaultAbortSignal?: AbortSignal;
|
|
71
|
-
}): HttpClient;
|
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
import { WebHttpClient } from './web-client.js';
|
|
2
|
-
// Factory function to create HTTP client with sensible defaults
|
|
3
|
-
export function createHttpClient(transport) {
|
|
4
|
-
return new WebHttpClient(transport);
|
|
5
|
-
}
|
|
6
|
-
// Factory function for browser environments
|
|
7
|
-
export function createBrowserHttpClient(options) {
|
|
8
|
-
const transport = {
|
|
9
|
-
// globalThis.fetch must be called as a method on globalThis, not through a
|
|
10
|
-
// variable, or browsers throw "Illegal invocation".
|
|
11
|
-
fetch: (url, init) => options.fetch ? options.fetch(url, init) : globalThis.fetch(url, init),
|
|
12
|
-
baseUrl: options.baseUrl,
|
|
13
|
-
getAuthToken: options.getAuthToken,
|
|
14
|
-
getProof: options.getProof,
|
|
15
|
-
onTokenRefresh: options.onTokenRefresh,
|
|
16
|
-
refreshToken: options.refreshToken,
|
|
17
|
-
onAuthRevoked: options.onAuthRevoked,
|
|
18
|
-
defaultHeaders: options.defaultHeaders,
|
|
19
|
-
timeoutMs: options.timeoutMs,
|
|
20
|
-
credentials: options.credentials,
|
|
21
|
-
defaultAbortSignal: options.defaultAbortSignal,
|
|
22
|
-
};
|
|
23
|
-
return createHttpClient(transport);
|
|
24
|
-
}
|
|
25
|
-
// Factory function for Node.js environments
|
|
26
|
-
export function createNodeHttpClient(options) {
|
|
27
|
-
// Use provided fetch or try to use global fetch (Node 18+)
|
|
28
|
-
const fetchImpl = options.fetch ?? globalThis.fetch;
|
|
29
|
-
if (!fetchImpl) {
|
|
30
|
-
throw new Error('No fetch implementation available. Please provide a fetch implementation ' +
|
|
31
|
-
'(e.g., undici.fetch) or use Node.js 18+ which has native fetch support.');
|
|
32
|
-
}
|
|
33
|
-
// Check if we're using the default globalThis.fetch to preserve context
|
|
34
|
-
// When fetchImpl is globalThis.fetch, we must call it directly, not through a variable
|
|
35
|
-
// Custom fetch implementations (like undici.fetch) can be called through the variable
|
|
36
|
-
const isDefaultFetch = fetchImpl === globalThis.fetch;
|
|
37
|
-
const transport = {
|
|
38
|
-
// Wrap fetch in arrow function to prevent "Illegal invocation" error
|
|
39
|
-
// For globalThis.fetch, call it directly to preserve 'this' context
|
|
40
|
-
// For custom implementations, calling through the variable is safe
|
|
41
|
-
fetch: isDefaultFetch
|
|
42
|
-
? (url, init) => globalThis.fetch(url, init)
|
|
43
|
-
: (url, init) => fetchImpl(url, init),
|
|
44
|
-
baseUrl: options.baseUrl,
|
|
45
|
-
getAuthToken: options.getAuthToken,
|
|
46
|
-
getProof: options.getProof,
|
|
47
|
-
onTokenRefresh: options.onTokenRefresh,
|
|
48
|
-
refreshToken: options.refreshToken,
|
|
49
|
-
onAuthRevoked: options.onAuthRevoked,
|
|
50
|
-
defaultHeaders: options.defaultHeaders,
|
|
51
|
-
timeoutMs: options.timeoutMs,
|
|
52
|
-
credentials: options.credentials,
|
|
53
|
-
defaultAbortSignal: options.defaultAbortSignal,
|
|
54
|
-
};
|
|
55
|
-
return createHttpClient(transport);
|
|
56
|
-
}
|
|
57
|
-
// Universal factory that works in both environments
|
|
58
|
-
export function createUniversalHttpClient(options) {
|
|
59
|
-
// Try to detect environment and use appropriate factory
|
|
60
|
-
if (typeof window !== 'undefined') {
|
|
61
|
-
// Browser environment
|
|
62
|
-
return createBrowserHttpClient(options);
|
|
63
|
-
}
|
|
64
|
-
else {
|
|
65
|
-
// Node.js environment
|
|
66
|
-
return createNodeHttpClient(options);
|
|
67
|
-
}
|
|
68
|
-
}
|
|
@@ -1,87 +0,0 @@
|
|
|
1
|
-
export type FetchLike = (input: RequestInfo, init?: RequestInit) => Promise<Response>;
|
|
2
|
-
export interface Transport {
|
|
3
|
-
fetch: FetchLike;
|
|
4
|
-
baseUrl: string;
|
|
5
|
-
defaultHeaders?: Record<string, string>;
|
|
6
|
-
getAuthToken?: () => Promise<string | undefined>;
|
|
7
|
-
/**
|
|
8
|
-
* Per-request authorization, for a credential that commits to the request.
|
|
9
|
-
*
|
|
10
|
-
* `getAuthToken` returns one value reused across requests; a request proof
|
|
11
|
-
* signs the method, the path and the body, so it can only be produced where
|
|
12
|
-
* those are known. This is called with exactly that, and whatever it returns
|
|
13
|
-
* is merged into the headers.
|
|
14
|
-
*
|
|
15
|
-
* It runs AFTER `getAuthToken`, so a transport holding both sends both and
|
|
16
|
-
* lets the node decide — which it does by answering a request carrying a token
|
|
17
|
-
* by that token, and consulting a proof only when there is none.
|
|
18
|
-
*/
|
|
19
|
-
authorizeRequest?: (request: {
|
|
20
|
-
method: string;
|
|
21
|
-
/** The path and query the node will see, as `signedPath` reads them. */
|
|
22
|
-
path: string;
|
|
23
|
-
body?: string | Uint8Array;
|
|
24
|
-
}) => Promise<Record<string, string>>;
|
|
25
|
-
/**
|
|
26
|
-
* Sign each request instead of, or alongside, presenting a session.
|
|
27
|
-
*
|
|
28
|
-
* Called per call with the method, the path the node will see, and the exact
|
|
29
|
-
* body — a proof commits to all three, so unlike `getAuthToken` it cannot be
|
|
30
|
-
* resolved once and reused. Returning `undefined` sends no proof header,
|
|
31
|
-
* which is how a client that only sometimes has a key stays usable.
|
|
32
|
-
*
|
|
33
|
-
* `createProofSigner` builds one of these from a credential and a key.
|
|
34
|
-
*/
|
|
35
|
-
getProof?: (request: {
|
|
36
|
-
method: string;
|
|
37
|
-
path: string;
|
|
38
|
-
body?: unknown;
|
|
39
|
-
}) => Promise<string | undefined>;
|
|
40
|
-
onTokenRefresh?: (newToken: string) => Promise<void>;
|
|
41
|
-
/**
|
|
42
|
-
* Callback to refresh the access token when a 401 error with 'token_expired' is detected.
|
|
43
|
-
* Should return the new access token, or throw an error if refresh fails.
|
|
44
|
-
* If provided, the client will automatically retry the request after a successful refresh.
|
|
45
|
-
*/
|
|
46
|
-
refreshToken?: () => Promise<string>;
|
|
47
|
-
/**
|
|
48
|
-
* Callback invoked when the server reports that the token family is gone
|
|
49
|
-
* (`x-auth-error: token_reuse` on 401, or `token_revoked`). Refresh tokens are
|
|
50
|
-
* single-use, so this is terminal: the stored tokens must be dropped and the
|
|
51
|
-
* user re-authenticated. The client never retries such a request.
|
|
52
|
-
*/
|
|
53
|
-
onAuthRevoked?: () => Promise<void> | void;
|
|
54
|
-
timeoutMs?: number;
|
|
55
|
-
credentials?: RequestCredentials;
|
|
56
|
-
defaultAbortSignal?: AbortSignal;
|
|
57
|
-
}
|
|
58
|
-
export type ResponseParser = 'json' | 'text' | 'blob' | 'arrayBuffer' | 'response';
|
|
59
|
-
export interface RequestOptions extends RequestInit {
|
|
60
|
-
parse?: ResponseParser;
|
|
61
|
-
timeoutMs?: number;
|
|
62
|
-
}
|
|
63
|
-
export interface HttpClient {
|
|
64
|
-
get<T>(path: string, init?: RequestOptions): Promise<T>;
|
|
65
|
-
post<T>(path: string, body?: unknown, init?: RequestOptions): Promise<T>;
|
|
66
|
-
put<T>(path: string, body?: unknown, init?: RequestOptions): Promise<T>;
|
|
67
|
-
delete<T>(path: string, init?: RequestOptions): Promise<T>;
|
|
68
|
-
patch<T>(path: string, body?: unknown, init?: RequestOptions): Promise<T>;
|
|
69
|
-
head(path: string, init?: RequestOptions): Promise<{
|
|
70
|
-
headers: Record<string, string>;
|
|
71
|
-
status: number;
|
|
72
|
-
}>;
|
|
73
|
-
request<T>(path: string, init?: RequestOptions): Promise<T>;
|
|
74
|
-
}
|
|
75
|
-
export interface Header {
|
|
76
|
-
[key: string]: string;
|
|
77
|
-
}
|
|
78
|
-
export interface ProgressCallback {
|
|
79
|
-
(progress: number): void;
|
|
80
|
-
}
|
|
81
|
-
export interface HeadResponse {
|
|
82
|
-
headers: Record<string, string>;
|
|
83
|
-
status: number;
|
|
84
|
-
}
|
|
85
|
-
export interface LegacyRequestOptions {
|
|
86
|
-
responseType?: 'arraybuffer' | 'blob' | 'json';
|
|
87
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
export * from './http-types.js';
|
|
2
|
-
export * from './api-response.js';
|
|
3
|
-
export { WebHttpClient, HTTPError, AuthRevokedError, RequestAuthError } from './web-client.js';
|
|
4
|
-
export { createHttpClient, createBrowserHttpClient, createNodeHttpClient, createUniversalHttpClient, } from './http-factory.js';
|
|
5
|
-
export { withRetry, createRetryableMethod } from './retry.js';
|
|
6
|
-
export type { RetryOptions } from './retry.js';
|
|
7
|
-
export { combineSignals, createTimeoutSignal } from './signal-utils.js';
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
// HTTP client types and interfaces
|
|
2
|
-
export * from './http-types.js';
|
|
3
|
-
export * from './api-response.js';
|
|
4
|
-
// Web Standards HTTP client implementation
|
|
5
|
-
export { WebHttpClient, HTTPError, AuthRevokedError, RequestAuthError } from './web-client.js';
|
|
6
|
-
// Factory functions for easy client creation
|
|
7
|
-
export { createHttpClient, createBrowserHttpClient, createNodeHttpClient, createUniversalHttpClient, } from './http-factory.js';
|
|
8
|
-
// Retry functionality
|
|
9
|
-
export { withRetry, createRetryableMethod } from './retry.js';
|
|
10
|
-
// Signal utilities
|
|
11
|
-
export { combineSignals, createTimeoutSignal } from './signal-utils.js';
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare function pathSegment(id: string): string;
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
// encodeURIComponent leaves "." and ".." intact and URL parsers collapse them,
|
|
2
|
-
// so those (and the empty id, which names the collection route) are refused.
|
|
3
|
-
export function pathSegment(id) {
|
|
4
|
-
if (id === '' || id === '.' || id === '..') {
|
|
5
|
-
throw new TypeError(`invalid request path segment: ${JSON.stringify(id)}`);
|
|
6
|
-
}
|
|
7
|
-
return encodeURIComponent(id);
|
|
8
|
-
}
|
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
export interface RetryOptions {
|
|
2
|
-
attempts?: number;
|
|
3
|
-
}
|
|
4
|
-
export declare function withRetry<T>(fn: (attempt: number) => Promise<T>, options?: RetryOptions): Promise<T>;
|
|
5
|
-
export declare function createRetryableMethod<T extends unknown[], R>(method: (...args: T) => Promise<R>, retryOptions?: RetryOptions): (...args: T) => Promise<R>;
|
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
// Default retry condition - retry on network errors and 5xx status codes
|
|
2
|
-
function defaultRetryCondition(error, attempt) {
|
|
3
|
-
// Don't retry on the last attempt
|
|
4
|
-
if (attempt <= 0)
|
|
5
|
-
return false;
|
|
6
|
-
// Distinguish timeout vs. user abort:
|
|
7
|
-
// - Timeout: name === 'TimeoutError' (per spec/platforms)
|
|
8
|
-
// - User abort: name === 'AbortError'
|
|
9
|
-
const errorWithName = error;
|
|
10
|
-
const name = errorWithName?.name;
|
|
11
|
-
if (name === 'TimeoutError')
|
|
12
|
-
return true;
|
|
13
|
-
if (name === 'AbortError')
|
|
14
|
-
return false;
|
|
15
|
-
// HTTP 5xx and 429 (including HTTPError from web-client)
|
|
16
|
-
const errorWithStatus = error;
|
|
17
|
-
if ('status' in errorWithStatus &&
|
|
18
|
-
typeof errorWithStatus.status === 'number') {
|
|
19
|
-
const status = errorWithStatus.status;
|
|
20
|
-
return status >= 500 || status === 429;
|
|
21
|
-
}
|
|
22
|
-
// Network TypeError (DNS/reset) is reasonably retryable
|
|
23
|
-
if (name === 'TypeError')
|
|
24
|
-
return true;
|
|
25
|
-
return false;
|
|
26
|
-
}
|
|
27
|
-
// Calculate delay with exponential backoff and jitter
|
|
28
|
-
function calculateDelay(attempt) {
|
|
29
|
-
const baseDelayMs = 250; // Base 250ms as per spec
|
|
30
|
-
const delay = baseDelayMs * Math.pow(2, attempt - 1);
|
|
31
|
-
// Add ±20% jitter to reduce stampedes
|
|
32
|
-
const jitter = (Math.random() - 0.5) * 0.4 * delay;
|
|
33
|
-
return Math.max(0, delay + jitter);
|
|
34
|
-
}
|
|
35
|
-
// Retry helper function with new signature
|
|
36
|
-
export async function withRetry(fn, options = {}) {
|
|
37
|
-
const { attempts = 3 } = options;
|
|
38
|
-
let lastError;
|
|
39
|
-
for (let attempt = 1; attempt <= attempts; attempt++) {
|
|
40
|
-
try {
|
|
41
|
-
return await fn(attempt);
|
|
42
|
-
}
|
|
43
|
-
catch (error) {
|
|
44
|
-
lastError = error;
|
|
45
|
-
// Check if we should retry (this handles the last attempt check)
|
|
46
|
-
if (!defaultRetryCondition(lastError, attempts - attempt)) {
|
|
47
|
-
throw lastError;
|
|
48
|
-
}
|
|
49
|
-
// Calculate delay
|
|
50
|
-
let delayMs = calculateDelay(attempt);
|
|
51
|
-
// Check for Retry-After header if it's an HTTP error
|
|
52
|
-
const errorWithHeaders = lastError;
|
|
53
|
-
const hdrs = errorWithHeaders.headers;
|
|
54
|
-
const retryAfter = hdrs?.get?.('Retry-After');
|
|
55
|
-
if (retryAfter) {
|
|
56
|
-
// If it's a number, treat as seconds
|
|
57
|
-
const seconds = parseInt(retryAfter, 10);
|
|
58
|
-
if (!isNaN(seconds)) {
|
|
59
|
-
delayMs = Math.max(delayMs, seconds * 1000);
|
|
60
|
-
}
|
|
61
|
-
else {
|
|
62
|
-
// If it's a date, calculate the difference
|
|
63
|
-
const date = new Date(retryAfter);
|
|
64
|
-
if (!isNaN(date.getTime())) {
|
|
65
|
-
const waitTime = Math.max(0, date.getTime() - Date.now());
|
|
66
|
-
// Cap wait at 60s per attempt as per spec
|
|
67
|
-
delayMs = Math.max(delayMs, Math.min(waitTime, 60000));
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
// Wait before retrying
|
|
72
|
-
await new Promise((resolve) => setTimeout(resolve, delayMs));
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
throw lastError || new Error('Retry failed without error');
|
|
76
|
-
}
|
|
77
|
-
// Helper to create a retry-enabled HTTP client method
|
|
78
|
-
export function createRetryableMethod(method, retryOptions = {}) {
|
|
79
|
-
return async (...args) => {
|
|
80
|
-
return withRetry(() => method(...args), retryOptions);
|
|
81
|
-
};
|
|
82
|
-
}
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
// Utility for combining multiple AbortSignals
|
|
2
|
-
export function combineSignals(signals) {
|
|
3
|
-
const list = signals.filter(Boolean);
|
|
4
|
-
if (list.length === 0)
|
|
5
|
-
return undefined;
|
|
6
|
-
// Prefer native any(), but fall back if unavailable or it throws
|
|
7
|
-
const AbortSignalAny = AbortSignal;
|
|
8
|
-
if (typeof AbortSignalAny.any === 'function') {
|
|
9
|
-
try {
|
|
10
|
-
return AbortSignalAny.any(list);
|
|
11
|
-
}
|
|
12
|
-
catch {
|
|
13
|
-
// Fall through to manual implementation
|
|
14
|
-
}
|
|
15
|
-
}
|
|
16
|
-
const controller = new AbortController();
|
|
17
|
-
const onAbort = (evt) => {
|
|
18
|
-
controller.abort(evt.target.reason);
|
|
19
|
-
for (const s of list)
|
|
20
|
-
s.removeEventListener('abort', onAbort);
|
|
21
|
-
};
|
|
22
|
-
for (const s of list) {
|
|
23
|
-
if (s.aborted)
|
|
24
|
-
return AbortSignal.abort(s.reason);
|
|
25
|
-
s.addEventListener('abort', onAbort, { once: true });
|
|
26
|
-
}
|
|
27
|
-
return controller.signal;
|
|
28
|
-
}
|
|
29
|
-
// Helper to create a timeout signal
|
|
30
|
-
export function createTimeoutSignal(timeoutMs) {
|
|
31
|
-
// Use AbortSignal.timeout if available (Node 18.17+, modern browsers)
|
|
32
|
-
if (typeof AbortSignal.timeout === 'function') {
|
|
33
|
-
return AbortSignal.timeout(timeoutMs);
|
|
34
|
-
}
|
|
35
|
-
// Fallback for older environments
|
|
36
|
-
const controller = new AbortController();
|
|
37
|
-
setTimeout(() => {
|
|
38
|
-
controller.abort(new DOMException('Timeout', 'TimeoutError'));
|
|
39
|
-
}, timeoutMs);
|
|
40
|
-
return controller.signal;
|
|
41
|
-
}
|