@orangecheck/me-client 0.5.0 → 0.7.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.mjs CHANGED
@@ -1,24 +1,38 @@
1
1
  import * as React from 'react';
2
2
  import { jsxs, jsx } from 'react/jsx-runtime';
3
- export { OcSessionProvider, useOcSession, useOptionalOcSession } from '@orangecheck/auth-client';
4
- import { ed25519 } from '@noble/curves/ed25519';
5
- import { sha256 } from '@noble/hashes/sha256';
6
3
 
7
- // src/SignInButton.tsx
4
+ var __defProp = Object.defineProperty;
5
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
6
+ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
8
7
 
9
8
  // src/transport.ts
10
9
  var origin = "https://me.ochk.io";
10
+ var bearerToken = null;
11
11
  function setOrigin(url) {
12
12
  origin = url.replace(/\/$/, "");
13
13
  }
14
14
  function getOrigin() {
15
15
  return origin;
16
16
  }
17
+ function setBearerToken(token) {
18
+ bearerToken = token && token.length > 0 ? token : null;
19
+ }
20
+ function getBearerToken() {
21
+ return bearerToken;
22
+ }
23
+ function clearBearerToken() {
24
+ bearerToken = null;
25
+ }
17
26
  async function api(path, opts = {}) {
27
+ const headers = {
28
+ "content-type": "application/json",
29
+ accept: "application/json"
30
+ };
31
+ if (bearerToken) headers["authorization"] = `Bearer ${bearerToken}`;
18
32
  const res = await fetch(`${origin}${path}`, {
19
33
  method: opts.method ?? "GET",
20
34
  credentials: "include",
21
- headers: { "content-type": "application/json", accept: "application/json" },
35
+ headers,
22
36
  body: opts.body !== void 0 ? JSON.stringify(opts.body) : void 0,
23
37
  signal: opts.signal
24
38
  });
@@ -75,8 +89,7 @@ async function create(opts) {
75
89
  body: {
76
90
  scope: opts.scope,
77
91
  policy,
78
- return_to: opts.returnTo ?? (typeof window !== "undefined" ? window.location.href : void 0),
79
- ...opts.project_key ? { project_key: opts.project_key } : {}
92
+ return_to: opts.returnTo ?? (typeof window !== "undefined" ? window.location.href : void 0)
80
93
  }
81
94
  });
82
95
  }
@@ -177,13 +190,29 @@ async function authorize(opts) {
177
190
  }
178
191
  var payment = { authorize };
179
192
 
193
+ // src/event.ts
194
+ async function fire(options) {
195
+ if (!options.project_key) {
196
+ throw new Error("event.fire requires project_key");
197
+ }
198
+ if (!options.subtype) {
199
+ throw new Error("event.fire requires subtype");
200
+ }
201
+ return api("/api/integrator/event", {
202
+ method: "POST",
203
+ body: options
204
+ });
205
+ }
206
+ var event = { fire };
207
+
180
208
  // src/types.ts
181
209
  var PLATFORM_FEE_POLICY = {
182
210
  /** Fraction of every gross_fee that OC retains. */
183
211
  pct: 0.2,
184
212
  /** Absolute minimum platform fee, in sats. */
185
213
  min_floor_sats: 1,
186
- /** Date this policy was last ratified. Changes require an oc-me-protocol PR. */
214
+ /** Date this policy was last ratified. Changes require a versioned
215
+ * @orangecheck/me-client release. */
187
216
  ratified: "2026-04-30"
188
217
  };
189
218
  var MIN_INTEGRATOR_PRICE_SATS = 5;
@@ -246,149 +275,353 @@ function validateIntegratorConfig(cfg) {
246
275
  }
247
276
 
248
277
  // src/config.ts
249
- async function get() {
250
- return api("/api/developer/config", { method: "GET" });
251
- }
252
- async function update(cfg) {
253
- const result = validateIntegratorConfig(cfg);
254
- if (!result.ok) {
255
- const summary = result.errors.map((e) => e.subtype ? `${e.subtype}: ${e.message}` : e.message).join("; ");
256
- throw new Error(`IntegratorPriceConfig invalid \xB7 ${summary}`);
257
- }
258
- return api("/api/developer/config", {
259
- method: "POST",
260
- body: cfg
261
- });
262
- }
263
278
  function validate(cfg) {
264
279
  return validateIntegratorConfig(cfg);
265
280
  }
266
- var config = { get, update, validate };
267
- var FAMILY_JWKS_URL = "https://ochk.io/.well-known/jwks.json";
268
- var cachedJwks = null;
269
- var JWKS_TTL_MS = 60 * 60 * 1e3;
270
- async function fetchJwks() {
271
- if (cachedJwks && Date.now() - cachedJwks.fetched_at < JWKS_TTL_MS) {
272
- return cachedJwks.keys;
273
- }
274
- const res = await fetch(FAMILY_JWKS_URL, {
275
- method: "GET",
276
- headers: { Accept: "application/json" }
277
- });
278
- if (!res.ok) {
279
- throw new Error(`failed to fetch JWKS: ${res.status} ${res.statusText}`);
281
+ var config = { validate };
282
+
283
+ // node_modules/jose/dist/webapi/lib/buffer_utils.js
284
+ new TextEncoder();
285
+ var decoder = new TextDecoder();
286
+
287
+ // node_modules/jose/dist/webapi/lib/base64.js
288
+ function decodeBase64(encoded) {
289
+ if (Uint8Array.fromBase64) {
290
+ return Uint8Array.fromBase64(encoded);
280
291
  }
281
- const data = await res.json();
282
- cachedJwks = { fetched_at: Date.now(), keys: data.keys };
283
- return data.keys;
284
- }
285
- function base64urlDecode(input) {
286
- const padded = input.replace(/-/g, "+").replace(/_/g, "/").padEnd(
287
- Math.ceil(input.length / 4) * 4,
288
- "="
289
- );
290
- const bin = typeof atob === "function" ? atob(padded) : Buffer.from(padded, "base64").toString("binary");
291
- const out = new Uint8Array(bin.length);
292
- for (let i = 0; i < bin.length; i++) out[i] = bin.charCodeAt(i);
293
- return out;
294
- }
295
- function hexDecode(input) {
296
- const clean = input.toLowerCase().replace(/^0x/, "");
297
- if (clean.length % 2 !== 0) throw new Error("hex string has odd length");
298
- const out = new Uint8Array(clean.length / 2);
299
- for (let i = 0; i < out.length; i++) {
300
- out[i] = parseInt(clean.slice(i * 2, i * 2 + 2), 16);
292
+ const binary = atob(encoded);
293
+ const bytes = new Uint8Array(binary.length);
294
+ for (let i = 0; i < binary.length; i++) {
295
+ bytes[i] = binary.charCodeAt(i);
301
296
  }
302
- return out;
297
+ return bytes;
303
298
  }
304
- async function verify(rawBody, sigHex, kid, jwk) {
305
- let key = jwk;
306
- if (!key || key.kid !== kid) {
307
- const keys = await fetchJwks();
308
- key = keys.find((k) => k.kid === kid);
309
- if (!key) {
310
- return { ok: false, reason: `no JWK with kid=${kid} in published JWKS`, key_id: kid };
311
- }
299
+
300
+ // node_modules/jose/dist/webapi/util/base64url.js
301
+ function decode(input) {
302
+ if (Uint8Array.fromBase64) {
303
+ return Uint8Array.fromBase64(typeof input === "string" ? input : decoder.decode(input), {
304
+ alphabet: "base64url"
305
+ });
312
306
  }
313
- if (key.kty !== "OKP" || key.crv !== "Ed25519") {
314
- return { ok: false, reason: `JWK kid=${kid} is not Ed25519`, key_id: kid };
307
+ let encoded = input;
308
+ if (encoded instanceof Uint8Array) {
309
+ encoded = decoder.decode(encoded);
315
310
  }
316
- let pubKey;
311
+ encoded = encoded.replace(/-/g, "+").replace(/_/g, "/");
317
312
  try {
318
- pubKey = base64urlDecode(key.x);
319
- } catch (err) {
320
- return {
321
- ok: false,
322
- reason: `failed to decode JWK x: ${err.message}`,
323
- key_id: kid
324
- };
313
+ return decodeBase64(encoded);
314
+ } catch {
315
+ throw new TypeError("The input to be decoded is not correctly encoded.");
325
316
  }
326
- if (pubKey.length !== 32) {
327
- return {
328
- ok: false,
329
- reason: `Ed25519 public key must be 32 bytes; got ${pubKey.length}`,
330
- key_id: kid
331
- };
317
+ }
318
+
319
+ // node_modules/jose/dist/webapi/util/errors.js
320
+ var JOSEError = class extends Error {
321
+ constructor(message, options) {
322
+ super(message, options);
323
+ __publicField(this, "code", "ERR_JOSE_GENERIC");
324
+ this.name = this.constructor.name;
325
+ Error.captureStackTrace?.(this, this.constructor);
332
326
  }
333
- let sig;
334
- try {
335
- sig = hexDecode(sigHex);
336
- } catch (err) {
337
- return {
338
- ok: false,
339
- reason: `failed to decode signature: ${err.message}`,
340
- key_id: kid
341
- };
327
+ };
328
+ __publicField(JOSEError, "code", "ERR_JOSE_GENERIC");
329
+ var JOSENotSupported = class extends JOSEError {
330
+ constructor() {
331
+ super(...arguments);
332
+ __publicField(this, "code", "ERR_JOSE_NOT_SUPPORTED");
342
333
  }
343
- if (sig.length !== 64) {
344
- return {
345
- ok: false,
346
- reason: `Ed25519 signature must be 64 bytes; got ${sig.length}`,
347
- key_id: kid
348
- };
334
+ };
335
+ __publicField(JOSENotSupported, "code", "ERR_JOSE_NOT_SUPPORTED");
336
+ var _a, _b;
337
+ var JWKSMultipleMatchingKeys = class extends (_b = JOSEError, _a = Symbol.asyncIterator, _b) {
338
+ constructor(message = "multiple matching keys found in the JSON Web Key Set", options) {
339
+ super(message, options);
340
+ __publicField(this, _a);
341
+ __publicField(this, "code", "ERR_JWKS_MULTIPLE_MATCHING_KEYS");
349
342
  }
350
- const bodyBytes = typeof rawBody === "string" ? new TextEncoder().encode(rawBody) : rawBody;
351
- const hash = sha256(bodyBytes);
352
- try {
353
- const ok = ed25519.verify(sig, hash, pubKey);
354
- return ok ? { ok: true, key_id: kid } : { ok: false, reason: "signature does not match", key_id: kid };
355
- } catch (err) {
356
- return { ok: false, reason: err.message, key_id: kid };
343
+ };
344
+ __publicField(JWKSMultipleMatchingKeys, "code", "ERR_JWKS_MULTIPLE_MATCHING_KEYS");
345
+
346
+ // node_modules/jose/dist/webapi/lib/type_checks.js
347
+ var isObjectLike = (value) => typeof value === "object" && value !== null;
348
+ function isObject(input) {
349
+ if (!isObjectLike(input) || Object.prototype.toString.call(input) !== "[object Object]") {
350
+ return false;
351
+ }
352
+ if (Object.getPrototypeOf(input) === null) {
353
+ return true;
357
354
  }
355
+ let proto = input;
356
+ while (Object.getPrototypeOf(proto) !== null) {
357
+ proto = Object.getPrototypeOf(proto);
358
+ }
359
+ return Object.getPrototypeOf(input) === proto;
358
360
  }
359
- var webhook = { verify, fetchJwks };
360
361
 
361
- // src/delegation.ts
362
- async function issue(opts) {
363
- if (!opts.agent_id) throw new Error("agent_id is required");
364
- if (!opts.scope?.length) throw new Error("scope must contain at least one token");
365
- if (!opts.expires_at) throw new Error("expires_at is required");
366
- return api("/api/delegation/issue", {
367
- method: "POST",
368
- body: opts
369
- });
362
+ // node_modules/jose/dist/webapi/lib/jwk_to_key.js
363
+ var unsupportedAlg = 'Invalid or unsupported JWK "alg" (Algorithm) Parameter value';
364
+ function subtleMapping(jwk) {
365
+ let algorithm;
366
+ let keyUsages;
367
+ switch (jwk.kty) {
368
+ case "AKP": {
369
+ switch (jwk.alg) {
370
+ case "ML-DSA-44":
371
+ case "ML-DSA-65":
372
+ case "ML-DSA-87":
373
+ algorithm = { name: jwk.alg };
374
+ keyUsages = jwk.priv ? ["sign"] : ["verify"];
375
+ break;
376
+ default:
377
+ throw new JOSENotSupported(unsupportedAlg);
378
+ }
379
+ break;
380
+ }
381
+ case "RSA": {
382
+ switch (jwk.alg) {
383
+ case "PS256":
384
+ case "PS384":
385
+ case "PS512":
386
+ algorithm = { name: "RSA-PSS", hash: `SHA-${jwk.alg.slice(-3)}` };
387
+ keyUsages = jwk.d ? ["sign"] : ["verify"];
388
+ break;
389
+ case "RS256":
390
+ case "RS384":
391
+ case "RS512":
392
+ algorithm = { name: "RSASSA-PKCS1-v1_5", hash: `SHA-${jwk.alg.slice(-3)}` };
393
+ keyUsages = jwk.d ? ["sign"] : ["verify"];
394
+ break;
395
+ case "RSA-OAEP":
396
+ case "RSA-OAEP-256":
397
+ case "RSA-OAEP-384":
398
+ case "RSA-OAEP-512":
399
+ algorithm = {
400
+ name: "RSA-OAEP",
401
+ hash: `SHA-${parseInt(jwk.alg.slice(-3), 10) || 1}`
402
+ };
403
+ keyUsages = jwk.d ? ["decrypt", "unwrapKey"] : ["encrypt", "wrapKey"];
404
+ break;
405
+ default:
406
+ throw new JOSENotSupported(unsupportedAlg);
407
+ }
408
+ break;
409
+ }
410
+ case "EC": {
411
+ switch (jwk.alg) {
412
+ case "ES256":
413
+ case "ES384":
414
+ case "ES512":
415
+ algorithm = {
416
+ name: "ECDSA",
417
+ namedCurve: { ES256: "P-256", ES384: "P-384", ES512: "P-521" }[jwk.alg]
418
+ };
419
+ keyUsages = jwk.d ? ["sign"] : ["verify"];
420
+ break;
421
+ case "ECDH-ES":
422
+ case "ECDH-ES+A128KW":
423
+ case "ECDH-ES+A192KW":
424
+ case "ECDH-ES+A256KW":
425
+ algorithm = { name: "ECDH", namedCurve: jwk.crv };
426
+ keyUsages = jwk.d ? ["deriveBits"] : [];
427
+ break;
428
+ default:
429
+ throw new JOSENotSupported(unsupportedAlg);
430
+ }
431
+ break;
432
+ }
433
+ case "OKP": {
434
+ switch (jwk.alg) {
435
+ case "Ed25519":
436
+ case "EdDSA":
437
+ algorithm = { name: "Ed25519" };
438
+ keyUsages = jwk.d ? ["sign"] : ["verify"];
439
+ break;
440
+ case "ECDH-ES":
441
+ case "ECDH-ES+A128KW":
442
+ case "ECDH-ES+A192KW":
443
+ case "ECDH-ES+A256KW":
444
+ algorithm = { name: jwk.crv };
445
+ keyUsages = jwk.d ? ["deriveBits"] : [];
446
+ break;
447
+ default:
448
+ throw new JOSENotSupported(unsupportedAlg);
449
+ }
450
+ break;
451
+ }
452
+ default:
453
+ throw new JOSENotSupported('Invalid or unsupported JWK "kty" (Key Type) Parameter value');
454
+ }
455
+ return { algorithm, keyUsages };
370
456
  }
371
- async function revoke(delegation_id) {
372
- return api("/api/delegation/revoke", {
373
- method: "POST",
374
- body: { delegation_id }
375
- });
457
+ async function jwkToKey(jwk) {
458
+ if (!jwk.alg) {
459
+ throw new TypeError('"alg" argument is required when "jwk.alg" is not present');
460
+ }
461
+ const { algorithm, keyUsages } = subtleMapping(jwk);
462
+ const keyData = { ...jwk };
463
+ if (keyData.kty !== "AKP") {
464
+ delete keyData.alg;
465
+ }
466
+ delete keyData.use;
467
+ return crypto.subtle.importKey("jwk", keyData, algorithm, jwk.ext ?? (jwk.d || jwk.priv ? false : true), jwk.key_ops ?? keyUsages);
376
468
  }
377
- var delegation = { issue, revoke };
378
469
 
379
- // src/event.ts
380
- async function fire(opts) {
381
- const result = await api("/api/integrator/event", {
382
- method: "POST",
383
- body: opts
470
+ // node_modules/jose/dist/webapi/key/import.js
471
+ async function importJWK(jwk, alg, options) {
472
+ if (!isObject(jwk)) {
473
+ throw new TypeError("JWK must be an object");
474
+ }
475
+ let ext;
476
+ ext ?? (ext = jwk.ext);
477
+ switch (jwk.kty) {
478
+ case "oct":
479
+ if (typeof jwk.k !== "string" || !jwk.k) {
480
+ throw new TypeError('missing "k" (Key Value) Parameter value');
481
+ }
482
+ return decode(jwk.k);
483
+ case "RSA":
484
+ if ("oth" in jwk && jwk.oth !== void 0) {
485
+ throw new JOSENotSupported('RSA JWK "oth" (Other Primes Info) Parameter value is not supported');
486
+ }
487
+ return jwkToKey({ ...jwk, alg, ext });
488
+ case "AKP": {
489
+ if (typeof jwk.alg !== "string" || !jwk.alg) {
490
+ throw new TypeError('missing "alg" (Algorithm) Parameter value');
491
+ }
492
+ if (alg !== jwk.alg) {
493
+ throw new TypeError("JWK alg and alg option value mismatch");
494
+ }
495
+ return jwkToKey({ ...jwk, ext });
496
+ }
497
+ case "EC":
498
+ case "OKP":
499
+ return jwkToKey({ ...jwk, alg, ext });
500
+ default:
501
+ throw new JOSENotSupported('Unsupported "kty" (Key Type) Parameter value');
502
+ }
503
+ }
504
+
505
+ // src/webhook.ts
506
+ var DEFAULT_ISSUER = "https://ochk.io";
507
+ var DEFAULT_TTL_MS = 60 * 60 * 1e3;
508
+ var jwksCache = /* @__PURE__ */ new Map();
509
+ var inflight = /* @__PURE__ */ new Map();
510
+ async function fetchJwks(issuer, ttlMs) {
511
+ const cached = jwksCache.get(issuer);
512
+ if (cached && Date.now() - cached.fetchedAt < ttlMs) return cached;
513
+ const existing = inflight.get(issuer);
514
+ if (existing) return existing;
515
+ const p = (async () => {
516
+ try {
517
+ const url = `${issuer.replace(/\/$/, "")}/.well-known/jwks.json`;
518
+ const res = await fetch(url, { headers: { Accept: "application/json" } });
519
+ if (!res.ok) throw new Error(`JWKS fetch ${url} returned ${res.status}`);
520
+ const json = await res.json();
521
+ if (!json || !Array.isArray(json.keys)) {
522
+ throw new Error(`JWKS at ${url} did not return {keys:[\u2026]}`);
523
+ }
524
+ const keys = {};
525
+ for (const k of json.keys) {
526
+ if (typeof k.kid !== "string") continue;
527
+ try {
528
+ keys[k.kid] = await importJWK(k, "EdDSA");
529
+ } catch {
530
+ }
531
+ }
532
+ const entry = { keys, fetchedAt: Date.now() };
533
+ jwksCache.set(issuer, entry);
534
+ return entry;
535
+ } catch (err) {
536
+ const stale = jwksCache.get(issuer);
537
+ if (stale) return stale;
538
+ throw err;
539
+ }
540
+ })().finally(() => {
541
+ inflight.delete(issuer);
384
542
  });
385
- return result.event;
543
+ inflight.set(issuer, p);
544
+ return p;
386
545
  }
387
- var event = { fire };
546
+ function hexToBytes(hex) {
547
+ if (typeof hex !== "string") return null;
548
+ const s = hex.trim();
549
+ if (s.length === 0 || s.length % 2 !== 0) return null;
550
+ const out = new Uint8Array(s.length / 2);
551
+ for (let i = 0; i < out.length; i++) {
552
+ const b = parseInt(s.slice(i * 2, i * 2 + 2), 16);
553
+ if (Number.isNaN(b)) return null;
554
+ out[i] = b;
555
+ }
556
+ return out;
557
+ }
558
+ function toBytes(input) {
559
+ if (typeof input === "string") return new TextEncoder().encode(input);
560
+ return input;
561
+ }
562
+ function toArrayBuffer(view) {
563
+ const buf = new ArrayBuffer(view.byteLength);
564
+ new Uint8Array(buf).set(view);
565
+ return buf;
566
+ }
567
+ async function verifyEd25519(key, sig, msg) {
568
+ const subtle = typeof globalThis.crypto !== "undefined" && globalThis.crypto.subtle ? globalThis.crypto.subtle : null;
569
+ if (!subtle) return false;
570
+ try {
571
+ return await subtle.verify(
572
+ "Ed25519",
573
+ key,
574
+ toArrayBuffer(sig),
575
+ toArrayBuffer(msg)
576
+ );
577
+ } catch {
578
+ return false;
579
+ }
580
+ }
581
+ async function verify(rawBody, sigHex, kid, options = {}) {
582
+ if (!sigHex) return { ok: false, reason: "missing signature" };
583
+ if (!kid) return { ok: false, reason: "missing kid" };
584
+ const sig = hexToBytes(sigHex);
585
+ if (!sig) return { ok: false, reason: "malformed signature (expected hex)" };
586
+ const msg = toBytes(rawBody);
587
+ let key;
588
+ if (options.jwk) {
589
+ if (options.jwk.kid !== kid) {
590
+ return { ok: false, reason: `kid mismatch (header=${kid}, jwk=${options.jwk.kid})` };
591
+ }
592
+ try {
593
+ key = await importJWK(options.jwk, "EdDSA");
594
+ } catch {
595
+ return { ok: false, reason: "could not import provided jwk" };
596
+ }
597
+ } else {
598
+ const issuer = options.issuer ?? DEFAULT_ISSUER;
599
+ const ttl = options.jwksCacheTtlMs ?? DEFAULT_TTL_MS;
600
+ try {
601
+ let entry = await fetchJwks(issuer, ttl);
602
+ key = entry.keys[kid];
603
+ if (!key) {
604
+ jwksCache.delete(issuer);
605
+ entry = await fetchJwks(issuer, ttl);
606
+ key = entry.keys[kid];
607
+ }
608
+ } catch (err) {
609
+ return { ok: false, reason: `jwks unavailable: ${err.message}` };
610
+ }
611
+ if (!key) return { ok: false, reason: `kid ${kid} not in JWKS` };
612
+ }
613
+ const ok = await verifyEd25519(key, sig, msg);
614
+ return ok ? { ok: true } : { ok: false, reason: "signature does not match" };
615
+ }
616
+ async function fetchJwksForce(issuer = DEFAULT_ISSUER) {
617
+ jwksCache.delete(issuer);
618
+ await fetchJwks(issuer, DEFAULT_TTL_MS);
619
+ }
620
+ var webhook = { verify, fetchJwks: fetchJwksForce };
388
621
 
389
622
  // src/index.ts
390
- var oc = { session, payment, config, webhook, delegation, event };
623
+ var oc = { session, payment, event, config, webhook };
391
624
 
392
- export { MIN_INTEGRATOR_PRICE_SATS, MeClientError, OcSignInButton, PLATFORM_FEE_POLICY, computeFees, config, delegation, event, getOrigin, oc, onTelemetry, payment, session, setOrigin, validateIntegratorConfig, webhook };
625
+ export { MIN_INTEGRATOR_PRICE_SATS, MeClientError, OcSignInButton, PLATFORM_FEE_POLICY, clearBearerToken, computeFees, config, event, getBearerToken, getOrigin, oc, onTelemetry, payment, session, setBearerToken, setOrigin, validateIntegratorConfig, webhook };
393
626
  //# sourceMappingURL=index.mjs.map
394
627
  //# sourceMappingURL=index.mjs.map