@orangecheck/me-client 0.9.0 → 0.12.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/dist/index.d.mts +73 -2
- package/dist/index.d.ts +73 -2
- package/dist/index.js +124 -7
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +123 -8
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -38,22 +38,69 @@ async function api(path, opts = {}) {
|
|
|
38
38
|
});
|
|
39
39
|
if (!res.ok) {
|
|
40
40
|
let message = `me.ochk.io ${res.status}`;
|
|
41
|
+
let errorCode;
|
|
42
|
+
let body;
|
|
41
43
|
try {
|
|
42
44
|
const data = await res.json();
|
|
43
|
-
|
|
45
|
+
body = data;
|
|
46
|
+
if (data?.error) {
|
|
47
|
+
errorCode = data.error;
|
|
48
|
+
message = data.reason ?? data.error;
|
|
49
|
+
}
|
|
44
50
|
} catch {
|
|
45
51
|
}
|
|
46
|
-
|
|
52
|
+
let retryAfterSeconds;
|
|
53
|
+
if (res.status === 429) {
|
|
54
|
+
const headerValue = res.headers.get("retry-after");
|
|
55
|
+
if (headerValue) {
|
|
56
|
+
const parsed = Number.parseInt(headerValue, 10);
|
|
57
|
+
if (Number.isFinite(parsed) && parsed >= 0) retryAfterSeconds = parsed;
|
|
58
|
+
}
|
|
59
|
+
if (retryAfterSeconds == null && typeof body?.retry_after_seconds === "number") {
|
|
60
|
+
retryAfterSeconds = body.retry_after_seconds;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
throw new MeClientError(message, res.status, { errorCode, retryAfterSeconds });
|
|
47
64
|
}
|
|
48
65
|
return await res.json();
|
|
49
66
|
}
|
|
50
67
|
var MeClientError = class extends Error {
|
|
51
|
-
constructor(message, status) {
|
|
68
|
+
constructor(message, status, opts) {
|
|
52
69
|
super(message);
|
|
53
70
|
this.name = "MeClientError";
|
|
54
71
|
this.status = status;
|
|
72
|
+
this.errorCode = opts?.errorCode;
|
|
73
|
+
this.retryAfterSeconds = opts?.retryAfterSeconds;
|
|
74
|
+
}
|
|
75
|
+
/** True for the 429 surface · convenience boolean so callers don't
|
|
76
|
+
* have to compare status === 429 every time. */
|
|
77
|
+
get isRateLimited() {
|
|
78
|
+
return this.status === 429;
|
|
55
79
|
}
|
|
56
80
|
};
|
|
81
|
+
async function withRateLimitRetry(fn, opts = {}) {
|
|
82
|
+
const maxRetries = opts.maxRetries ?? 2;
|
|
83
|
+
const maxRetryAfter = opts.maxRetryAfterSeconds ?? 30;
|
|
84
|
+
const baseBackoff = opts.baseBackoffMs ?? 250;
|
|
85
|
+
let attempt = 0;
|
|
86
|
+
while (true) {
|
|
87
|
+
try {
|
|
88
|
+
return await fn();
|
|
89
|
+
} catch (err) {
|
|
90
|
+
if (!(err instanceof MeClientError) || !err.isRateLimited) throw err;
|
|
91
|
+
if (attempt >= maxRetries) throw err;
|
|
92
|
+
let waitMs;
|
|
93
|
+
if (err.retryAfterSeconds != null) {
|
|
94
|
+
if (err.retryAfterSeconds > maxRetryAfter) throw err;
|
|
95
|
+
waitMs = err.retryAfterSeconds * 1e3;
|
|
96
|
+
} else {
|
|
97
|
+
waitMs = baseBackoff * 2 ** attempt;
|
|
98
|
+
}
|
|
99
|
+
await new Promise((resolve) => setTimeout(resolve, waitMs));
|
|
100
|
+
attempt++;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
57
104
|
|
|
58
105
|
// src/session.ts
|
|
59
106
|
var DEFAULT_POLICY = {
|
|
@@ -109,7 +156,7 @@ async function invalidate(sessionId) {
|
|
|
109
156
|
}
|
|
110
157
|
var session = { create, refresh, invalidate };
|
|
111
158
|
function OcSignInButton({
|
|
112
|
-
scope,
|
|
159
|
+
scope: scope2,
|
|
113
160
|
sessionPolicy,
|
|
114
161
|
returnTo,
|
|
115
162
|
onSignin,
|
|
@@ -130,7 +177,7 @@ function OcSignInButton({
|
|
|
130
177
|
if (event2.defaultPrevented) return;
|
|
131
178
|
setPending(true);
|
|
132
179
|
try {
|
|
133
|
-
const result = await session.create({ scope, sessionPolicy, returnTo });
|
|
180
|
+
const result = await session.create({ scope: scope2, sessionPolicy, returnTo });
|
|
134
181
|
onSignin?.(result);
|
|
135
182
|
} catch (err) {
|
|
136
183
|
onSignInError?.(err instanceof Error ? err : new Error(String(err)));
|
|
@@ -272,6 +319,23 @@ async function fire(options) {
|
|
|
272
319
|
body: options
|
|
273
320
|
});
|
|
274
321
|
}
|
|
322
|
+
async function fireBatch(options) {
|
|
323
|
+
if (!options.project_key) {
|
|
324
|
+
throw new Error("event.fireBatch requires project_key");
|
|
325
|
+
}
|
|
326
|
+
if (!Array.isArray(options.events) || options.events.length === 0) {
|
|
327
|
+
throw new Error("event.fireBatch requires at least one event");
|
|
328
|
+
}
|
|
329
|
+
if (options.events.length > 100) {
|
|
330
|
+
throw new Error(
|
|
331
|
+
`event.fireBatch \xB7 max 100 events per call (got ${options.events.length}). Split client-side.`
|
|
332
|
+
);
|
|
333
|
+
}
|
|
334
|
+
return api("/api/integrator/event/batch", {
|
|
335
|
+
method: "POST",
|
|
336
|
+
body: options
|
|
337
|
+
});
|
|
338
|
+
}
|
|
275
339
|
function verify(envelope, config2, payment_amount_sats) {
|
|
276
340
|
const issues = [];
|
|
277
341
|
const eventCfg = config2.events[envelope.subtype];
|
|
@@ -356,7 +420,7 @@ function verify(envelope, config2, payment_amount_sats) {
|
|
|
356
420
|
issues
|
|
357
421
|
};
|
|
358
422
|
}
|
|
359
|
-
var event = { fire, verify };
|
|
423
|
+
var event = { fire, fireBatch, verify };
|
|
360
424
|
|
|
361
425
|
// src/config.ts
|
|
362
426
|
function validate(cfg) {
|
|
@@ -722,9 +786,60 @@ async function defaultLive() {
|
|
|
722
786
|
}
|
|
723
787
|
var federations = { list, live, get, defaultLive };
|
|
724
788
|
|
|
789
|
+
// src/scope.ts
|
|
790
|
+
var VALID_SCOPES = [
|
|
791
|
+
"bitcoin_address",
|
|
792
|
+
"email",
|
|
793
|
+
"attest_tier",
|
|
794
|
+
"display_name"
|
|
795
|
+
];
|
|
796
|
+
async function granted(options) {
|
|
797
|
+
if (!options.project_key) {
|
|
798
|
+
throw new Error("oc.scope.granted: project_key is required");
|
|
799
|
+
}
|
|
800
|
+
const r = await api(
|
|
801
|
+
`/api/integrator/scopes/${encodeURIComponent(options.project_key)}`,
|
|
802
|
+
{ method: "GET", signal: options.signal }
|
|
803
|
+
);
|
|
804
|
+
return {
|
|
805
|
+
sub: r.sub,
|
|
806
|
+
scopes_granted: r.scopes_granted,
|
|
807
|
+
scopes: r.scopes
|
|
808
|
+
};
|
|
809
|
+
}
|
|
810
|
+
function request(scopes, options) {
|
|
811
|
+
if (!options.project_key) {
|
|
812
|
+
throw new Error("oc.scope.request: project_key is required");
|
|
813
|
+
}
|
|
814
|
+
if (!options.return_to) {
|
|
815
|
+
throw new Error("oc.scope.request: return_to is required");
|
|
816
|
+
}
|
|
817
|
+
if (!Array.isArray(scopes) || scopes.length === 0) {
|
|
818
|
+
throw new Error("oc.scope.request: scopes must be a non-empty array");
|
|
819
|
+
}
|
|
820
|
+
for (const s of scopes) {
|
|
821
|
+
if (!VALID_SCOPES.includes(s)) {
|
|
822
|
+
throw new Error(
|
|
823
|
+
`oc.scope.request: unknown scope "${s}" \xB7 valid: ${VALID_SCOPES.join(", ")}`
|
|
824
|
+
);
|
|
825
|
+
}
|
|
826
|
+
}
|
|
827
|
+
if (typeof window === "undefined") {
|
|
828
|
+
throw new Error("oc.scope.request: must be called in a browser environment");
|
|
829
|
+
}
|
|
830
|
+
const origin2 = options.origin ?? getOrigin();
|
|
831
|
+
const url = new URL("/me/scope-grant", origin2);
|
|
832
|
+
url.searchParams.set("project_key", options.project_key);
|
|
833
|
+
url.searchParams.set("scopes", scopes.join(","));
|
|
834
|
+
url.searchParams.set("return_to", options.return_to);
|
|
835
|
+
window.location.assign(url.toString());
|
|
836
|
+
throw new Error("oc.scope.request: redirected to consent prompt");
|
|
837
|
+
}
|
|
838
|
+
var scope = { granted, request };
|
|
839
|
+
|
|
725
840
|
// src/index.ts
|
|
726
|
-
var oc = { session, payment, event, config, webhook, federations };
|
|
841
|
+
var oc = { session, payment, event, config, webhook, federations, scope };
|
|
727
842
|
|
|
728
|
-
export { MIN_INTEGRATOR_PRICE_SATS, MeClientError, OcSignInButton, PLATFORM_FEE_POLICY, clearBearerToken, computeFees, config, event, federations, getBearerToken, getOrigin, oc, onTelemetry, payment, session, setBearerToken, setOrigin, validateIntegratorConfig, webhook };
|
|
843
|
+
export { MIN_INTEGRATOR_PRICE_SATS, MeClientError, OcSignInButton, PLATFORM_FEE_POLICY, clearBearerToken, computeFees, config, event, federations, getBearerToken, getOrigin, oc, onTelemetry, payment, scope, session, setBearerToken, setOrigin, validateIntegratorConfig, webhook, withRateLimitRetry };
|
|
729
844
|
//# sourceMappingURL=index.mjs.map
|
|
730
845
|
//# sourceMappingURL=index.mjs.map
|