@calimero-network/mero-js 26.11.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.
Files changed (220) hide show
  1. package/README.md +73 -288
  2. package/dist/cloud-v2/attestation.d.ts +91 -0
  3. package/dist/cloud-v2/attestation.js +135 -0
  4. package/dist/cloud-v2/capabilities.d.ts +30 -0
  5. package/dist/cloud-v2/capabilities.js +31 -0
  6. package/dist/cloud-v2/client.d.ts +426 -0
  7. package/dist/cloud-v2/client.js +646 -0
  8. package/dist/cloud-v2/errors.d.ts +98 -0
  9. package/dist/cloud-v2/errors.js +165 -0
  10. package/dist/cloud-v2/index.d.ts +10 -0
  11. package/dist/cloud-v2/index.js +5 -0
  12. package/dist/cloud-v2/passkey.d.ts +27 -0
  13. package/dist/cloud-v2/passkey.js +73 -0
  14. package/dist/crypto/internal.d.ts +3 -37
  15. package/dist/crypto/internal.js +3 -72
  16. package/dist/index.browser.mjs +4 -2
  17. package/dist/index.browser.mjs.map +4 -4
  18. package/dist/index.cjs +1750 -12772
  19. package/dist/index.cjs.map +4 -4
  20. package/dist/index.d.ts +3 -56
  21. package/dist/index.js +14 -75
  22. package/dist/index.mjs +1750 -12772
  23. package/dist/index.mjs.map +4 -4
  24. package/dist/sealed/index.d.ts +4 -4
  25. package/dist/sealed/index.js +2 -2
  26. package/dist/sealed/release.d.ts +21 -76
  27. package/dist/sealed/release.js +24 -108
  28. package/dist/sealed/sealed.d.ts +8 -56
  29. package/dist/sealed/sealed.js +11 -89
  30. package/dist/sealed/verify.d.ts +7 -13
  31. package/dist/sealed/verify.js +3 -7
  32. package/package.json +8 -13
  33. package/dist/account/account-admin.d.ts +0 -80
  34. package/dist/account/account-admin.js +0 -346
  35. package/dist/account/account.d.ts +0 -196
  36. package/dist/account/account.js +0 -269
  37. package/dist/account/application-id.d.ts +0 -50
  38. package/dist/account/application-id.js +0 -83
  39. package/dist/account/bootstrap-from-invitation.d.ts +0 -110
  40. package/dist/account/bootstrap-from-invitation.js +0 -80
  41. package/dist/account/create-context.d.ts +0 -103
  42. package/dist/account/create-context.js +0 -267
  43. package/dist/account/govern.d.ts +0 -24
  44. package/dist/account/govern.js +0 -50
  45. package/dist/account/index.d.ts +0 -26
  46. package/dist/account/index.js +0 -15
  47. package/dist/account/join-as-account.d.ts +0 -23
  48. package/dist/account/join-as-account.js +0 -34
  49. package/dist/account/join-with-node.d.ts +0 -115
  50. package/dist/account/join-with-node.js +0 -161
  51. package/dist/account/node-admin.d.ts +0 -20
  52. package/dist/account/node-admin.js +0 -33
  53. package/dist/account/relay-from-invitation.d.ts +0 -137
  54. package/dist/account/relay-from-invitation.js +0 -180
  55. package/dist/account/relay-login-error.d.ts +0 -32
  56. package/dist/account/relay-login-error.js +0 -34
  57. package/dist/account/session.d.ts +0 -266
  58. package/dist/account/session.js +0 -915
  59. package/dist/account/wordlist.d.ts +0 -16
  60. package/dist/account/wordlist.js +0 -273
  61. package/dist/admin-api/admin-client.d.ts +0 -688
  62. package/dist/admin-api/admin-client.js +0 -1230
  63. package/dist/admin-api/admin-factory.d.ts +0 -14
  64. package/dist/admin-api/admin-factory.js +0 -22
  65. package/dist/admin-api/admin-types.d.ts +0 -2046
  66. package/dist/admin-api/admin-types.js +0 -12
  67. package/dist/admin-api/index.d.ts +0 -4
  68. package/dist/admin-api/index.js +0 -5
  69. package/dist/admin-api/redeem-invitation.d.ts +0 -101
  70. package/dist/admin-api/redeem-invitation.js +0 -200
  71. package/dist/auth/index.d.ts +0 -34
  72. package/dist/auth/index.js +0 -67
  73. package/dist/auth-api/auth-client.d.ts +0 -31
  74. package/dist/auth-api/auth-client.js +0 -117
  75. package/dist/auth-api/auth-factory.d.ts +0 -7
  76. package/dist/auth-api/auth-factory.js +0 -41
  77. package/dist/auth-api/auth-types.d.ts +0 -130
  78. package/dist/auth-api/auth-types.js +0 -2
  79. package/dist/auth-api/index.d.ts +0 -3
  80. package/dist/auth-api/index.js +0 -4
  81. package/dist/capabilities.d.ts +0 -84
  82. package/dist/capabilities.js +0 -117
  83. package/dist/cloud/account-ownership.d.ts +0 -63
  84. package/dist/cloud/account-ownership.js +0 -87
  85. package/dist/cloud/cloud-client.d.ts +0 -949
  86. package/dist/cloud/cloud-client.js +0 -1068
  87. package/dist/cloud/connect.d.ts +0 -213
  88. package/dist/cloud/connect.js +0 -260
  89. package/dist/cloud/enrol-redirect.d.ts +0 -181
  90. package/dist/cloud/enrol-redirect.js +0 -244
  91. package/dist/cloud/index.d.ts +0 -12
  92. package/dist/cloud/index.js +0 -10
  93. package/dist/cloud/link-redirect.d.ts +0 -95
  94. package/dist/cloud/link-redirect.js +0 -121
  95. package/dist/cloud/link-state.d.ts +0 -36
  96. package/dist/cloud/link-state.js +0 -104
  97. package/dist/cloud/routing-proof.d.ts +0 -113
  98. package/dist/cloud/routing-proof.js +0 -96
  99. package/dist/device-cert/device-cert.d.ts +0 -189
  100. package/dist/device-cert/device-cert.js +0 -239
  101. package/dist/device-cert/device-scope.d.ts +0 -58
  102. package/dist/device-cert/device-scope.js +0 -76
  103. package/dist/device-cert/index.d.ts +0 -4
  104. package/dist/device-cert/index.js +0 -3
  105. package/dist/ephemeral/codec.d.ts +0 -4
  106. package/dist/ephemeral/codec.js +0 -12
  107. package/dist/ephemeral/index.d.ts +0 -57
  108. package/dist/ephemeral/index.js +0 -101
  109. package/dist/ephemeral/types.d.ts +0 -27
  110. package/dist/ephemeral/types.js +0 -1
  111. package/dist/errors/classify.d.ts +0 -65
  112. package/dist/errors/classify.js +0 -117
  113. package/dist/errors/index.d.ts +0 -2
  114. package/dist/errors/index.js +0 -1
  115. package/dist/events/group.d.ts +0 -95
  116. package/dist/events/group.js +0 -10
  117. package/dist/events/index.d.ts +0 -5
  118. package/dist/events/index.js +0 -2
  119. package/dist/events/sse.d.ts +0 -127
  120. package/dist/events/sse.js +0 -469
  121. package/dist/events/ws.d.ts +0 -57
  122. package/dist/events/ws.js +0 -212
  123. package/dist/http-client/api-response.d.ts +0 -15
  124. package/dist/http-client/api-response.js +0 -1
  125. package/dist/http-client/http-factory.d.ts +0 -71
  126. package/dist/http-client/http-factory.js +0 -68
  127. package/dist/http-client/http-types.d.ts +0 -87
  128. package/dist/http-client/http-types.js +0 -1
  129. package/dist/http-client/index.d.ts +0 -7
  130. package/dist/http-client/index.js +0 -11
  131. package/dist/http-client/path-segment.d.ts +0 -1
  132. package/dist/http-client/path-segment.js +0 -8
  133. package/dist/http-client/retry.d.ts +0 -5
  134. package/dist/http-client/retry.js +0 -82
  135. package/dist/http-client/signal-utils.d.ts +0 -2
  136. package/dist/http-client/signal-utils.js +0 -41
  137. package/dist/http-client/web-client.d.ts +0 -80
  138. package/dist/http-client/web-client.js +0 -557
  139. package/dist/invitation/index.d.ts +0 -2
  140. package/dist/invitation/index.js +0 -2
  141. package/dist/invitation/invitation.d.ts +0 -106
  142. package/dist/invitation/invitation.js +0 -104
  143. package/dist/login/index.d.ts +0 -4
  144. package/dist/login/index.js +0 -3
  145. package/dist/login/login.d.ts +0 -111
  146. package/dist/login/login.js +0 -110
  147. package/dist/login/session.d.ts +0 -124
  148. package/dist/login/session.js +0 -141
  149. package/dist/mero-js.d.ts +0 -231
  150. package/dist/mero-js.js +0 -469
  151. package/dist/namespace-op/index.d.ts +0 -2
  152. package/dist/namespace-op/index.js +0 -3
  153. package/dist/namespace-op/namespace-op.d.ts +0 -150
  154. package/dist/namespace-op/namespace-op.js +0 -191
  155. package/dist/nodeDiscovery.d.ts +0 -47
  156. package/dist/nodeDiscovery.js +0 -101
  157. package/dist/owner-op/index.d.ts +0 -2
  158. package/dist/owner-op/index.js +0 -3
  159. package/dist/owner-op/owner-op.d.ts +0 -119
  160. package/dist/owner-op/owner-op.js +0 -214
  161. package/dist/presence/relay-presence.d.ts +0 -56
  162. package/dist/presence/relay-presence.js +0 -107
  163. package/dist/presence/statement.d.ts +0 -12
  164. package/dist/presence/statement.js +0 -17
  165. package/dist/relay/index.d.ts +0 -4
  166. package/dist/relay/index.js +0 -2
  167. package/dist/relay/nonce-source.d.ts +0 -72
  168. package/dist/relay/nonce-source.js +0 -111
  169. package/dist/relay/relay-client.d.ts +0 -472
  170. package/dist/relay/relay-client.js +0 -518
  171. package/dist/relay-attestation/attest-node-key.d.ts +0 -66
  172. package/dist/relay-attestation/attest-node-key.js +0 -110
  173. package/dist/relay-attestation/index.d.ts +0 -1
  174. package/dist/relay-attestation/index.js +0 -1
  175. package/dist/request/caller-proof.d.ts +0 -43
  176. package/dist/request/caller-proof.js +0 -36
  177. package/dist/request/index.d.ts +0 -3
  178. package/dist/request/index.js +0 -3
  179. package/dist/request/proof-signer.d.ts +0 -49
  180. package/dist/request/proof-signer.js +0 -59
  181. package/dist/request/request-sig.d.ts +0 -99
  182. package/dist/request/request-sig.js +0 -95
  183. package/dist/request-proof/authorizer.d.ts +0 -41
  184. package/dist/request-proof/authorizer.js +0 -60
  185. package/dist/request-proof/index.d.ts +0 -4
  186. package/dist/request-proof/index.js +0 -2
  187. package/dist/request-proof/request-proof.d.ts +0 -53
  188. package/dist/request-proof/request-proof.js +0 -95
  189. package/dist/rpc/index.d.ts +0 -64
  190. package/dist/rpc/index.js +0 -78
  191. package/dist/signer/index.d.ts +0 -2
  192. package/dist/signer/index.js +0 -3
  193. package/dist/signer/signer.d.ts +0 -92
  194. package/dist/signer/signer.js +0 -147
  195. package/dist/token-store/index.d.ts +0 -27
  196. package/dist/token-store/index.js +0 -62
  197. package/dist/transport/index.d.ts +0 -6
  198. package/dist/transport/index.js +0 -3
  199. package/dist/transport/mero-client.d.ts +0 -294
  200. package/dist/transport/mero-client.js +0 -386
  201. package/dist/transport/relay-observer.d.ts +0 -152
  202. package/dist/transport/relay-observer.js +0 -173
  203. package/dist/transport/relay-transport.d.ts +0 -73
  204. package/dist/transport/relay-transport.js +0 -94
  205. package/dist/transport/types.d.ts +0 -100
  206. package/dist/transport/types.js +0 -32
  207. package/dist/types/api-response.d.ts +0 -15
  208. package/dist/types/api-response.js +0 -1
  209. package/dist/types/index.d.ts +0 -1
  210. package/dist/types/index.js +0 -1
  211. package/dist/warrant/creation-warrant.d.ts +0 -163
  212. package/dist/warrant/creation-warrant.js +0 -194
  213. package/dist/warrant/governance-op.d.ts +0 -202
  214. package/dist/warrant/governance-op.js +0 -355
  215. package/dist/warrant/governance-warrant.d.ts +0 -124
  216. package/dist/warrant/governance-warrant.js +0 -164
  217. package/dist/warrant/index.d.ts +0 -8
  218. package/dist/warrant/index.js +0 -5
  219. package/dist/warrant/warrant.d.ts +0 -188
  220. 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,2 +0,0 @@
1
- export declare function combineSignals(signals: Array<AbortSignal | undefined>): AbortSignal | undefined;
2
- export declare function createTimeoutSignal(timeoutMs: number): AbortSignal;
@@ -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
- }