@orangecheck/me-client 0.36.0 → 0.37.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 CHANGED
@@ -90,7 +90,7 @@ export default withOcAuth(handler, {
90
90
  });
91
91
  ```
92
92
 
93
- Or set it in code with `requireBond: { minSats: 100_000, minDays: 30, maxAgeSecs: 3600 }`. ochk.io re-checks the coin when its last check is over ten minutes old; `maxAgeSecs` refuses a claim checked longer ago than you accept. From 0.28.0, an account below the floor gets `403 { ok: false, reason: 'bond_required', need: { min_sats, min_days }, have: { sats_floor, days_floor } | null, back_url }`: link the person to `back_url` to back their account. If the project's setting can't be read and never has been, the request gets `503 { reason: 'bond_policy_unavailable' }` rather than being let through unchecked. `readBondClaim(session)` and `bondMeets(session, { minSats, minDays, maxAgeSecs })` are exported for your own checks.
93
+ Or set it in code with `requireBond: { minSats: 100_000, minDays: 30, maxAgeSecs: 3600 }`. ochk.io re-checks the coin when its last check is over ten minutes old; `maxAgeSecs` refuses a claim checked longer ago than you accept. From 0.28.0, an account below the floor gets `403 { ok: false, reason: 'bond_required', need: { min_sats, min_days }, have: { sats_floor, days_floor } | null, back_url }`: link the person to `back_url` to back their account. If the project's setting can't be read, the last one read stands for ten minutes; with none read in that time, a signed-in request gets `503 { reason: 'bond_policy_unavailable' }` rather than being let through unchecked. A request with no session is not held to the project's setting and never waits on it (0.37.0); pass `required: true` to answer it 401. `readBondClaim(session)` and `bondMeets(session, { minSats, minDays, maxAgeSecs })` are exported for your own checks.
94
94
 
95
95
  ## Pay your users, when you choose to
96
96
 
package/dist/server.d.mts CHANGED
@@ -5,6 +5,7 @@ export { A as ActivityAttestation, a as ActivityAttestationBundle, b as Activity
5
5
  interface OcSessionOptions extends VerifyOcOptions {
6
6
  method?: string;
7
7
  projectKey?: string;
8
+ meOrigin?: string;
8
9
  revocation?: RevocationCheck | false;
9
10
  }
10
11
  declare function _resetSessionChecksForTests(): void;
@@ -34,7 +35,6 @@ interface WithOcAuthOptions extends OcSessionOptions {
34
35
  maxAgeSecs?: number;
35
36
  };
36
37
  projectKey?: string;
37
- meOrigin?: string;
38
38
  }
39
39
  declare const BACK_ACCOUNT_URL = "https://ochk.app/me/account#backing";
40
40
  declare function withOcAuth<Req extends NextApiRequestLike = NextApiRequestLike, Res extends NextApiResponseLike = NextApiResponseLike>(handler: (req: WithOcSession<Req>, res: Res) => unknown, options?: WithOcAuthOptions): (req: Req, res: Res) => Promise<unknown>;
package/dist/server.d.ts CHANGED
@@ -5,6 +5,7 @@ export { A as ActivityAttestation, a as ActivityAttestationBundle, b as Activity
5
5
  interface OcSessionOptions extends VerifyOcOptions {
6
6
  method?: string;
7
7
  projectKey?: string;
8
+ meOrigin?: string;
8
9
  revocation?: RevocationCheck | false;
9
10
  }
10
11
  declare function _resetSessionChecksForTests(): void;
@@ -34,7 +35,6 @@ interface WithOcAuthOptions extends OcSessionOptions {
34
35
  maxAgeSecs?: number;
35
36
  };
36
37
  projectKey?: string;
37
- meOrigin?: string;
38
38
  }
39
39
  declare const BACK_ACCOUNT_URL = "https://ochk.app/me/account#backing";
40
40
  declare function withOcAuth<Req extends NextApiRequestLike = NextApiRequestLike, Res extends NextApiResponseLike = NextApiResponseLike>(handler: (req: WithOcSession<Req>, res: Res) => unknown, options?: WithOcAuthOptions): (req: Req, res: Res) => Promise<unknown>;
package/dist/server.js CHANGED
@@ -575,11 +575,14 @@ var warnedUnchecked = false;
575
575
  function revocationFor(options) {
576
576
  if (options.revocation === false) return null;
577
577
  if (options.revocation) return options.revocation;
578
- const key = options.projectKey ?? "";
578
+ const key = `${options.meOrigin ?? ""} ${options.projectKey ?? ""}`;
579
579
  if (!sessionChecks.has(key)) {
580
580
  sessionChecks.set(
581
581
  key,
582
- authCore.integratorRevocationCheck(options.projectKey ? { projectKey: options.projectKey } : {})
582
+ authCore.integratorRevocationCheck({
583
+ ...options.projectKey ? { projectKey: options.projectKey } : {},
584
+ ...options.meOrigin ? { meOrigin: options.meOrigin } : {}
585
+ })
583
586
  );
584
587
  }
585
588
  const check = sessionChecks.get(key);
@@ -636,38 +639,49 @@ var unknownKeys = /* @__PURE__ */ new Map();
636
639
  var UNKNOWN_PROJECT = /* @__PURE__ */ Symbol("unknown_project");
637
640
  var POLICY_TTL_MS = 6e4;
638
641
  var POLICY_RETRY_MS = 1e4;
642
+ var POLICY_MAX_STALE_MS = 6e5;
639
643
  var policies = /* @__PURE__ */ new Map();
644
+ var isFloor = (n) => Number.isSafeInteger(n) && n >= 0;
645
+ function readRequirement(body) {
646
+ const b = body;
647
+ if (!b || typeof b !== "object" || b.ok !== true || !("require_bond" in b)) return void 0;
648
+ if (b.require_bond === null) return null;
649
+ const r = b.require_bond;
650
+ if (!r || typeof r !== "object" || !isFloor(r.min_sats) || !isFloor(r.min_days)) return void 0;
651
+ return { minSats: r.min_sats, minDays: r.min_days };
652
+ }
640
653
  async function projectRequirement(options) {
654
+ const base = (options.meOrigin ?? "https://me.ochk.io").replace(/\/$/, "");
641
655
  const key = options.projectKey;
642
- const hit = policies.get(key);
656
+ const slot = `${base} ${key}`;
657
+ const hit = policies.get(slot);
643
658
  const now = Date.now();
644
- if (unknownKeys.has(key) && now - unknownKeys.get(key) < POLICY_TTL_MS) return UNKNOWN_PROJECT;
659
+ const standing = () => hit?.at && now - hit.at < POLICY_MAX_STALE_MS ? hit.need : void 0;
660
+ if (unknownKeys.has(slot) && now - unknownKeys.get(slot) < POLICY_TTL_MS) return UNKNOWN_PROJECT;
645
661
  if (hit && now - hit.at < POLICY_TTL_MS) return hit.need;
646
- if (hit?.failedAt && now - hit.failedAt < POLICY_RETRY_MS) return hit.at ? hit.need : void 0;
662
+ if (hit?.failedAt && now - hit.failedAt < POLICY_RETRY_MS) return standing();
647
663
  try {
648
- const base = options.meOrigin ?? "https://me.ochk.io";
649
664
  const r = await fetch(`${base}/api/integrator/${encodeURIComponent(key)}/sign-in`, {
650
665
  signal: AbortSignal.timeout(4e3)
651
666
  });
652
667
  if (r.status === 404) {
653
- if (!unknownKeys.has(key)) {
668
+ if (!unknownKeys.has(slot)) {
654
669
  console.error(
655
670
  `[@orangecheck/me-client] projectKey "${key}" is not a project. Copy yours from https://ochk.app/me/projects.`
656
671
  );
657
672
  }
658
- unknownKeys.set(key, Date.now());
673
+ unknownKeys.set(slot, Date.now());
659
674
  return UNKNOWN_PROJECT;
660
675
  }
661
- unknownKeys.delete(key);
676
+ unknownKeys.delete(slot);
662
677
  if (!r.ok) throw new Error(`HTTP ${r.status}`);
663
- const j = await r.json();
664
- const req = j.require_bond ?? null;
665
- const need = req ? { minSats: req.min_sats, minDays: req.min_days } : null;
666
- policies.set(key, { at: Date.now(), need });
678
+ const need = readRequirement(await r.json());
679
+ if (need === void 0) throw new Error("unexpected body");
680
+ policies.set(slot, { at: Date.now(), need });
667
681
  return need;
668
682
  } catch {
669
- policies.set(key, { at: hit?.at ?? 0, need: hit?.need ?? null, failedAt: Date.now() });
670
- return hit?.at ? hit.need : void 0;
683
+ policies.set(slot, { at: hit?.at ?? 0, need: hit?.need ?? null, failedAt: Date.now() });
684
+ return standing();
671
685
  }
672
686
  }
673
687
  async function bondNeed(options) {
@@ -676,10 +690,11 @@ async function bondNeed(options) {
676
690
  return null;
677
691
  }
678
692
  async function refusal(session, options) {
679
- const need = await bondNeed(options);
680
693
  if (!session && options.required) {
681
694
  return { status: 401, body: { ok: false, reason: "unauthenticated" } };
682
695
  }
696
+ if (!session && !options.requireBond) return null;
697
+ const need = await bondNeed(options);
683
698
  if (need === UNKNOWN_PROJECT) {
684
699
  return { status: 500, body: { ok: false, reason: "unknown_project_key" } };
685
700
  }