@orangecheck/me-client 0.4.0 → 0.6.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,8 +1,5 @@
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
4
  // src/SignInButton.tsx
8
5
 
@@ -182,7 +179,8 @@ var PLATFORM_FEE_POLICY = {
182
179
  pct: 0.2,
183
180
  /** Absolute minimum platform fee, in sats. */
184
181
  min_floor_sats: 1,
185
- /** Date this policy was last ratified. Changes require an oc-me-protocol PR. */
182
+ /** Date this policy was last ratified. Changes require a versioned
183
+ * @orangecheck/me-client release. */
186
184
  ratified: "2026-04-30"
187
185
  };
188
186
  var MIN_INTEGRATOR_PRICE_SATS = 5;
@@ -244,140 +242,9 @@ function validateIntegratorConfig(cfg) {
244
242
  return { ok: errors.length === 0, errors };
245
243
  }
246
244
 
247
- // src/config.ts
248
- async function get() {
249
- return api("/api/developer/config", { method: "GET" });
250
- }
251
- async function update(cfg) {
252
- const result = validateIntegratorConfig(cfg);
253
- if (!result.ok) {
254
- const summary = result.errors.map((e) => e.subtype ? `${e.subtype}: ${e.message}` : e.message).join("; ");
255
- throw new Error(`IntegratorPriceConfig invalid \xB7 ${summary}`);
256
- }
257
- return api("/api/developer/config", {
258
- method: "POST",
259
- body: cfg
260
- });
261
- }
262
- function validate(cfg) {
263
- return validateIntegratorConfig(cfg);
264
- }
265
- var config = { get, update, validate };
266
- var FAMILY_JWKS_URL = "https://ochk.io/.well-known/jwks.json";
267
- var cachedJwks = null;
268
- var JWKS_TTL_MS = 60 * 60 * 1e3;
269
- async function fetchJwks() {
270
- if (cachedJwks && Date.now() - cachedJwks.fetched_at < JWKS_TTL_MS) {
271
- return cachedJwks.keys;
272
- }
273
- const res = await fetch(FAMILY_JWKS_URL, {
274
- method: "GET",
275
- headers: { Accept: "application/json" }
276
- });
277
- if (!res.ok) {
278
- throw new Error(`failed to fetch JWKS: ${res.status} ${res.statusText}`);
279
- }
280
- const data = await res.json();
281
- cachedJwks = { fetched_at: Date.now(), keys: data.keys };
282
- return data.keys;
283
- }
284
- function base64urlDecode(input) {
285
- const padded = input.replace(/-/g, "+").replace(/_/g, "/").padEnd(
286
- Math.ceil(input.length / 4) * 4,
287
- "="
288
- );
289
- const bin = typeof atob === "function" ? atob(padded) : Buffer.from(padded, "base64").toString("binary");
290
- const out = new Uint8Array(bin.length);
291
- for (let i = 0; i < bin.length; i++) out[i] = bin.charCodeAt(i);
292
- return out;
293
- }
294
- function hexDecode(input) {
295
- const clean = input.toLowerCase().replace(/^0x/, "");
296
- if (clean.length % 2 !== 0) throw new Error("hex string has odd length");
297
- const out = new Uint8Array(clean.length / 2);
298
- for (let i = 0; i < out.length; i++) {
299
- out[i] = parseInt(clean.slice(i * 2, i * 2 + 2), 16);
300
- }
301
- return out;
302
- }
303
- async function verify(rawBody, sigHex, kid, jwk) {
304
- let key = jwk;
305
- if (!key || key.kid !== kid) {
306
- const keys = await fetchJwks();
307
- key = keys.find((k) => k.kid === kid);
308
- if (!key) {
309
- return { ok: false, reason: `no JWK with kid=${kid} in published JWKS`, key_id: kid };
310
- }
311
- }
312
- if (key.kty !== "OKP" || key.crv !== "Ed25519") {
313
- return { ok: false, reason: `JWK kid=${kid} is not Ed25519`, key_id: kid };
314
- }
315
- let pubKey;
316
- try {
317
- pubKey = base64urlDecode(key.x);
318
- } catch (err) {
319
- return {
320
- ok: false,
321
- reason: `failed to decode JWK x: ${err.message}`,
322
- key_id: kid
323
- };
324
- }
325
- if (pubKey.length !== 32) {
326
- return {
327
- ok: false,
328
- reason: `Ed25519 public key must be 32 bytes; got ${pubKey.length}`,
329
- key_id: kid
330
- };
331
- }
332
- let sig;
333
- try {
334
- sig = hexDecode(sigHex);
335
- } catch (err) {
336
- return {
337
- ok: false,
338
- reason: `failed to decode signature: ${err.message}`,
339
- key_id: kid
340
- };
341
- }
342
- if (sig.length !== 64) {
343
- return {
344
- ok: false,
345
- reason: `Ed25519 signature must be 64 bytes; got ${sig.length}`,
346
- key_id: kid
347
- };
348
- }
349
- const bodyBytes = typeof rawBody === "string" ? new TextEncoder().encode(rawBody) : rawBody;
350
- const hash = sha256(bodyBytes);
351
- try {
352
- const ok = ed25519.verify(sig, hash, pubKey);
353
- return ok ? { ok: true, key_id: kid } : { ok: false, reason: "signature does not match", key_id: kid };
354
- } catch (err) {
355
- return { ok: false, reason: err.message, key_id: kid };
356
- }
357
- }
358
- var webhook = { verify, fetchJwks };
359
-
360
- // src/delegation.ts
361
- async function issue(opts) {
362
- if (!opts.agent_id) throw new Error("agent_id is required");
363
- if (!opts.scope?.length) throw new Error("scope must contain at least one token");
364
- if (!opts.expires_at) throw new Error("expires_at is required");
365
- return api("/api/delegation/issue", {
366
- method: "POST",
367
- body: opts
368
- });
369
- }
370
- async function revoke(delegation_id) {
371
- return api("/api/delegation/revoke", {
372
- method: "POST",
373
- body: { delegation_id }
374
- });
375
- }
376
- var delegation = { issue, revoke };
377
-
378
245
  // src/index.ts
379
- var oc = { session, payment, config, webhook, delegation };
246
+ var oc = { session, payment };
380
247
 
381
- export { MIN_INTEGRATOR_PRICE_SATS, MeClientError, OcSignInButton, PLATFORM_FEE_POLICY, computeFees, config, delegation, getOrigin, oc, onTelemetry, payment, session, setOrigin, validateIntegratorConfig, webhook };
248
+ export { MIN_INTEGRATOR_PRICE_SATS, MeClientError, OcSignInButton, PLATFORM_FEE_POLICY, computeFees, getOrigin, oc, onTelemetry, payment, session, setOrigin, validateIntegratorConfig };
382
249
  //# sourceMappingURL=index.mjs.map
383
250
  //# sourceMappingURL=index.mjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/transport.ts","../src/session.ts","../src/SignInButton.tsx","../src/payment.ts","../src/types.ts","../src/config.ts","../src/webhook.ts","../src/delegation.ts","../src/index.ts"],"names":[],"mappings":"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","file":"index.mjs","sourcesContent":["/**\n * Tiny HTTP transport layer. The me.ochk.io origin is configurable so\n * staging deployments and self-hosted me-equivalents can swap it.\n */\n\nlet origin = 'https://me.ochk.io';\n\nexport function setOrigin(url: string): void {\n origin = url.replace(/\\/$/, '');\n}\n\nexport function getOrigin(): string {\n return origin;\n}\n\nexport interface FetchOptions {\n method?: 'GET' | 'POST' | 'PATCH' | 'DELETE';\n body?: unknown;\n signal?: AbortSignal;\n}\n\nexport async function api<T>(path: string, opts: FetchOptions = {}): Promise<T> {\n const res = await fetch(`${origin}${path}`, {\n method: opts.method ?? 'GET',\n credentials: 'include',\n headers: { 'content-type': 'application/json', accept: 'application/json' },\n body: opts.body !== undefined ? JSON.stringify(opts.body) : undefined,\n signal: opts.signal,\n });\n if (!res.ok) {\n let message = `me.ochk.io ${res.status}`;\n try {\n const data = (await res.json()) as { error?: string };\n if (data?.error) message = data.error;\n } catch {\n /* ignore */\n }\n throw new MeClientError(message, res.status);\n }\n return (await res.json()) as T;\n}\n\nexport class MeClientError extends Error {\n public readonly status: number;\n constructor(message: string, status: number) {\n super(message);\n this.name = 'MeClientError';\n this.status = status;\n }\n}\n","import type { Session, SessionPolicy, SignInOptions, TelemetryEvent } from './types';\n\nimport { api } from './transport';\n\nconst DEFAULT_POLICY: SessionPolicy = {\n duration_seconds: 7 * 24 * 60 * 60, // 7 days, standard SaaS shape\n refresh: 'sliding',\n sensitive_actions: 're-auth',\n};\n\nconst telemetrySubscribers = new Set<(e: TelemetryEvent) => void>();\n\n/** Subscribe to non-billable developer telemetry events. Call the returned\n * function to unsubscribe. */\nexport function onTelemetry(listener: (e: TelemetryEvent) => void): () => void {\n telemetrySubscribers.add(listener);\n return () => {\n telemetrySubscribers.delete(listener);\n };\n}\n\nfunction emitTelemetry(code: TelemetryEvent['code'], session_id?: string): void {\n const e: TelemetryEvent = {\n code,\n timestamp: new Date().toISOString(),\n ...(session_id ? { session_id } : {}),\n };\n for (const fn of telemetrySubscribers) {\n try {\n fn(e);\n } catch {\n /* listener errors must not break the session flow */\n }\n }\n}\n\n/**\n * Open a sign-in flow at me.ochk.io. Returns the resulting Session once\n * the user consents (Class C billable event for the integrating site,\n * cashback for the user). Internally this opens the OC consent UI in a\n * popup; v1 implementations may also redirect.\n */\nasync function create(opts: SignInOptions): Promise<Session> {\n const policy: SessionPolicy = { ...DEFAULT_POLICY, ...(opts.sessionPolicy ?? {}) };\n return api<Session>('/api/session/create', {\n method: 'POST',\n body: {\n scope: opts.scope,\n policy,\n return_to: opts.returnTo ?? (typeof window !== 'undefined' ? window.location.href : undefined),\n },\n });\n}\n\n/**\n * Refresh a still-valid session inside its policy window. Free for the\n * integrating site (does NOT instantiate a billable event); emits a\n * `session.token_refresh` telemetry record.\n */\nasync function refresh(sessionId: string): Promise<Session> {\n emitTelemetry('session.token_refresh', sessionId);\n return api<Session>('/api/session/refresh', {\n method: 'POST',\n body: { session_id: sessionId },\n });\n}\n\n/** Invalidate a session. Free, telemetry-only. */\nasync function invalidate(sessionId: string): Promise<void> {\n emitTelemetry('session.intra_signin', sessionId);\n await api<{ ok: true }>('/api/session/invalidate', {\n method: 'POST',\n body: { session_id: sessionId },\n });\n}\n\nexport const session = { create, refresh, invalidate };\n","import * as React from 'react';\n\nimport { session } from './session';\nimport type { Session, SessionPolicy } from './types';\n\nexport interface OcSignInButtonProps\n extends Omit<React.ButtonHTMLAttributes<HTMLButtonElement>, 'onError'> {\n scope: string[];\n sessionPolicy?: Partial<SessionPolicy>;\n returnTo?: string;\n onSignin?: (session: Session) => void;\n /** Called when the sign-in flow fails. Renamed from `onError` to avoid\n * shadowing the native button error handler. */\n onSignInError?: (error: Error) => void;\n /** Custom button text. Defaults to \"sign in with oc\". */\n label?: string;\n}\n\n/**\n * Drop-in Sign-in-with-OC button. Triggers the me.ochk.io consent flow\n * for the requested scope, opens (or refreshes) a session, and calls\n * onSignin(session) on success. Class C billable event for the\n * integrating site; cashback flows to the user.\n *\n * Mounting requires <OcSessionProvider> from @orangecheck/auth-client\n * somewhere up the React tree so the resulting session can be read by\n * useOcSession() across the rest of the app.\n */\nexport function OcSignInButton({\n scope,\n sessionPolicy,\n returnTo,\n onSignin,\n onSignInError,\n label = 'sign in with oc',\n children,\n onClick,\n style,\n ...rest\n}: OcSignInButtonProps) {\n const [pending, setPending] = React.useState(false);\n\n return (\n <button\n type=\"button\"\n onClick={async (event) => {\n onClick?.(event);\n if (event.defaultPrevented) return;\n setPending(true);\n try {\n const result = await session.create({ scope, sessionPolicy, returnTo });\n onSignin?.(result);\n } catch (err) {\n onSignInError?.(err instanceof Error ? err : new Error(String(err)));\n } finally {\n setPending(false);\n }\n }}\n style={{\n display: 'inline-flex',\n alignItems: 'center',\n gap: 8,\n padding: '10px 16px',\n fontSize: 13,\n fontWeight: 600,\n fontFamily: 'ui-monospace, \"JetBrains Mono\", \"SF Mono\", Menlo, monospace',\n letterSpacing: '0.18em',\n textTransform: 'uppercase',\n background: '#f97316',\n color: '#0b0909',\n border: '1px solid #f97316',\n borderRadius: 4,\n cursor: pending ? 'progress' : 'pointer',\n opacity: pending ? 0.7 : 1,\n ...(style ?? {}),\n }}\n disabled={pending || rest.disabled}\n data-oc-signin\n {...rest}\n >\n {/* compact OC mark */}\n <span\n aria-hidden\n style={{\n display: 'inline-block',\n width: 12,\n height: 12,\n background: '#0b0909',\n }}\n />\n {children ?? (pending ? 'opening…' : label)}\n </button>\n );\n}\n","import type { PaymentAuthorizeOptions, PaymentResult } from './types';\n\nimport { api } from './transport';\n\n/**\n * Authorize a payment through the user's OC identity. Class B billable\n * event for the integrating site (sub-Stripe rate, percentage-based);\n * cashback flows to the user as Lightning credit on /me/earn.\n *\n * The user is prompted by me.ochk.io to consent to the specific payment\n * before this resolves. If the user declines or cancels, the result has\n * status `'cancelled'`, a non-billable telemetry record is emitted, and\n * NO billable event is created.\n */\nasync function authorize(opts: PaymentAuthorizeOptions): Promise<PaymentResult> {\n if (opts.amount_sats == null && opts.usd_cents == null) {\n throw new Error('payment.authorize requires amount_sats or usd_cents');\n }\n return api<PaymentResult>('/api/payment/authorize', {\n method: 'POST',\n body: opts,\n });\n}\n\nexport const payment = { authorize };\n","/**\n * Canonical types for me.ochk.io integrators.\n *\n * Mirrors the source of truth at oc-me-web/src/lib/events/types.ts. Two\n * layers:\n * - Platform-level (PLATFORM_FEE_POLICY, MIN_INTEGRATOR_PRICE_SATS) —\n * fixed by OC, surfaced as constants here so integrators can validate\n * their config client-side before posting it.\n * - Integrator-level (IntegratorPriceConfig) — every integrator declares\n * their own per-event prices and user-share splits.\n *\n * Per Addendum 01: every chargeable event is in exactly one of three\n * classes. Sites pay for sessions and actions, not for clicks. Free\n * events never instantiate a BillableEvent.\n */\n\n// ── platform constants (fixed by OC) ──────────────────────────────────────\n\nexport const PLATFORM_FEE_POLICY = {\n /** Fraction of every gross_fee that OC retains. */\n pct: 0.2,\n /** Absolute minimum platform fee, in sats. */\n min_floor_sats: 1,\n /** Date this policy was last ratified. Changes require an oc-me-protocol PR. */\n ratified: '2026-04-30',\n} as const;\n\n/** Anti-spam price floor. No integrator can configure a per-event price\n * below this. */\nexport const MIN_INTEGRATOR_PRICE_SATS = 5;\n\n// ── event taxonomy ────────────────────────────────────────────────────────\n\nexport type EventClass = 'A' | 'B' | 'C';\n\nexport type ClassASubtype =\n | 'account_creation'\n | 'account_recovery'\n | 'kyc_tier_upgrade'\n | 'payment_method_connected'\n | 'agent_delegation_issued'\n | 'recovery_method_updated';\n\nexport type ClassBSubtype =\n | 'payment_authorization'\n | 'scoped_action_authorization'\n | 'attest_verification_at_gate'\n | 'stamp_signing'\n | 'pledge_resolution';\n\nexport type ClassCSubtype = 'session_creation';\n\nexport type EventSubtype = ClassASubtype | ClassBSubtype | ClassCSubtype;\n\nexport type AttestTier = 'anonymous' | 'bonded' | 'kyc_light' | 'kyc_strong';\n\n/** The shape of a per-event fee — either a fixed sats amount or a percent\n * of the underlying transaction amount (used for payments + pledges). */\nexport type SiteFeeShape =\n | { kind: 'fixed_sats'; sats: number }\n | { kind: 'percent_of_amount'; pct: number };\n\n/** What an integrator declares for a single event subtype. */\nexport interface IntegratorEventConfig {\n /** Whether this site bills this event subtype at all. */\n enabled: boolean;\n /** The per-event fee the site pays. */\n site_pays: SiteFeeShape;\n /** Fraction of post-platform-fee that flows to the user (0–0.8 since\n * platform_fee is 20%). The remainder is a rebate to the site's OC\n * project balance. */\n user_share_pct: number;\n}\n\n/** A complete integrator pricing config. Posted to me.ochk.io once at\n * integration time, mutable via the configurator UI or this SDK any time\n * after. */\nexport interface IntegratorPriceConfig {\n project_key: string;\n display_name: string;\n domain: string;\n /** ISO-8601 timestamp the config was last updated. */\n updated_at: string;\n /** Per-subtype configs. Subtypes not listed are disabled by default. */\n events: Partial<Record<EventSubtype, IntegratorEventConfig>>;\n}\n\n/** A computed fee breakdown for a single event. site_rebate_sats is what\n * flows back to the integrator's OC balance after OC's platform fee and\n * the user's cashback. */\nexport interface ComputedFees {\n gross_fee_sats: number;\n platform_fee_sats: number;\n user_earned_sats: number;\n site_rebate_sats: number;\n}\n\n/** Compute the four-way fee split for an event given an integrator's\n * config and (for percent_of_amount events) the underlying payment\n * amount.\n *\n * Invariants (verified by tests in oc-me-web/src/lib/events/types.test.ts):\n * 1. gross_fee_sats >= MIN_INTEGRATOR_PRICE_SATS\n * 2. platform_fee_sats >= PLATFORM_FEE_POLICY.min_floor_sats\n * 3. user_share_pct is clamped to [0, 0.8]\n * 4. site_rebate_sats >= 0\n * 5. gross == platform + user + rebate (exact, modulo rounding into rebate)\n */\nexport function computeFees(\n cfg: IntegratorEventConfig,\n payment_amount_sats?: number\n): ComputedFees {\n let gross = 0;\n if (cfg.site_pays.kind === 'fixed_sats') {\n gross = Math.max(MIN_INTEGRATOR_PRICE_SATS, Math.round(cfg.site_pays.sats));\n } else {\n if (payment_amount_sats == null) {\n throw new Error('percent_of_amount config requires payment_amount_sats');\n }\n gross = Math.max(\n MIN_INTEGRATOR_PRICE_SATS,\n Math.round(payment_amount_sats * cfg.site_pays.pct)\n );\n }\n const platform_fee_sats = Math.max(\n PLATFORM_FEE_POLICY.min_floor_sats,\n Math.round(gross * PLATFORM_FEE_POLICY.pct)\n );\n const user_share = Math.min(0.8, Math.max(0, cfg.user_share_pct));\n const user_earned_sats = Math.round(gross * user_share);\n const site_rebate_sats = Math.max(0, gross - platform_fee_sats - user_earned_sats);\n return { gross_fee_sats: gross, platform_fee_sats, user_earned_sats, site_rebate_sats };\n}\n\n/** Result of validating an IntegratorPriceConfig. */\nexport interface ValidationResult {\n ok: boolean;\n errors: { subtype?: EventSubtype; message: string }[];\n}\n\n/**\n * Validate an integrator's pricing config against the platform's\n * non-negotiable rules. Run client-side before posting; the server runs\n * the same checks and rejects anything that fails.\n */\nexport function validateIntegratorConfig(cfg: IntegratorPriceConfig): ValidationResult {\n const errors: ValidationResult['errors'] = [];\n\n if (!cfg.project_key) errors.push({ message: 'project_key is required' });\n if (!cfg.display_name) errors.push({ message: 'display_name is required' });\n if (!cfg.domain) errors.push({ message: 'domain is required' });\n\n for (const [key, eventCfg] of Object.entries(cfg.events)) {\n if (!eventCfg) continue;\n const subtype = key as EventSubtype;\n if (!eventCfg.enabled) continue;\n\n if (eventCfg.site_pays.kind === 'fixed_sats') {\n if (eventCfg.site_pays.sats < MIN_INTEGRATOR_PRICE_SATS) {\n errors.push({\n subtype,\n message: `site_pays.sats (${eventCfg.site_pays.sats}) is below MIN_INTEGRATOR_PRICE_SATS (${MIN_INTEGRATOR_PRICE_SATS})`,\n });\n }\n } else {\n const pct = eventCfg.site_pays.pct;\n if (!(pct > 0 && pct <= 1)) {\n errors.push({\n subtype,\n message: `site_pays.pct (${pct}) must be in (0, 1]`,\n });\n }\n }\n\n const u = eventCfg.user_share_pct;\n if (u < 0 || u > 0.8) {\n errors.push({\n subtype,\n message: `user_share_pct (${u}) must be in [0, 0.8]; max is 0.8 because platform_fee is ${PLATFORM_FEE_POLICY.pct}`,\n });\n }\n }\n\n return { ok: errors.length === 0, errors };\n}\n\n// ── canonical envelope ────────────────────────────────────────────────────\n\nexport interface BillableEvent {\n id: string;\n occurred_at: string;\n class: EventClass;\n subtype: EventSubtype;\n site: { domain: string; display_name: string };\n gross_fee_sats: number;\n platform_fee_sats: number;\n user_earned_sats: number;\n site_rebate_sats: number;\n verify_url: string;\n}\n\n// ── session lifecycle ────────────────────────────────────────────────────\n\nexport interface SessionPolicy {\n duration_seconds: number;\n refresh: 'sliding' | 'rolling' | 'none';\n sensitive_actions?: 're-auth' | 'none';\n}\n\nexport interface Session {\n id: string;\n identity: string;\n opens_at: string;\n expires_at: string;\n policy: SessionPolicy;\n scope: string[];\n}\n\nexport interface SignInOptions {\n scope: string[];\n sessionPolicy?: Partial<SessionPolicy>;\n returnTo?: string;\n}\n\nexport interface PaymentAuthorizeOptions {\n identity: string;\n amount_sats?: number;\n usd_cents?: number;\n description: string;\n external_ref?: string;\n}\n\nexport interface PaymentResult {\n id: string;\n status: 'authorized' | 'failed' | 'cancelled';\n sats_charged?: number;\n user_envelope_id?: string;\n verify_url?: string;\n}\n\nexport interface TelemetryEvent {\n code:\n | 'session.intra_signin'\n | 'session.token_refresh'\n | 'session.navigation'\n | 'auth.signin_failed'\n | 'auth.signin_cancelled'\n | 'auth.signin_rejected'\n | 'verify.passive_check';\n timestamp: string;\n session_id?: string;\n}\n","import type { IntegratorPriceConfig, ValidationResult } from './types';\n\nimport { validateIntegratorConfig } from './types';\nimport { api } from './transport';\n\n/**\n * Read the integrator's currently-stored IntegratorPriceConfig from\n * me.ochk.io. The endpoint reads from the federation index in production;\n * in v1 it returns the project's last-stored config from the in-memory\n * store keyed on the authenticated project_key.\n */\nasync function get(): Promise<IntegratorPriceConfig> {\n return api<IntegratorPriceConfig>('/api/developer/config', { method: 'GET' });\n}\n\n/**\n * Persist a new IntegratorPriceConfig. Validates client-side first so the\n * caller gets a structured error before a round trip; the server runs the\n * same validator and rejects with 422 + a list of offending subtypes if\n * anything slipped past.\n *\n * Throws an Error containing the validation report if the config is\n * invalid client-side. Throws MeClientError on server rejection.\n */\nasync function update(cfg: IntegratorPriceConfig): Promise<IntegratorPriceConfig> {\n const result = validateIntegratorConfig(cfg);\n if (!result.ok) {\n const summary = result.errors\n .map((e) => (e.subtype ? `${e.subtype}: ${e.message}` : e.message))\n .join('; ');\n throw new Error(`IntegratorPriceConfig invalid · ${summary}`);\n }\n return api<IntegratorPriceConfig>('/api/developer/config', {\n method: 'POST',\n body: cfg,\n });\n}\n\n/** Run the validator without making a network call. Useful for live\n * feedback in a dashboard form. */\nfunction validate(cfg: IntegratorPriceConfig): ValidationResult {\n return validateIntegratorConfig(cfg);\n}\n\nexport const config = { get, update, validate };\n","import { ed25519 } from '@noble/curves/ed25519';\nimport { sha256 } from '@noble/hashes/sha256';\n\n/**\n * Public Ed25519 JWK published at ochk.io/.well-known/jwks.json. Webhook\n * verification uses the key matching the OC-Key-Id header.\n */\nexport interface OcPublicJwk {\n kty: 'OKP';\n crv: 'Ed25519';\n x: string;\n kid: string;\n alg?: string;\n use?: string;\n}\n\nexport interface VerifyResult {\n ok: boolean;\n /** Reason verification failed. Undefined when ok is true. */\n reason?: string;\n /** kid that was matched (or attempted). */\n key_id?: string;\n}\n\nconst FAMILY_JWKS_URL = 'https://ochk.io/.well-known/jwks.json';\n\nlet cachedJwks: { fetched_at: number; keys: OcPublicJwk[] } | null = null;\nconst JWKS_TTL_MS = 60 * 60 * 1000;\n\n/** Fetch (and short-cache) the OC public JWKS. */\nasync function fetchJwks(): Promise<OcPublicJwk[]> {\n if (cachedJwks && Date.now() - cachedJwks.fetched_at < JWKS_TTL_MS) {\n return cachedJwks.keys;\n }\n const res = await fetch(FAMILY_JWKS_URL, {\n method: 'GET',\n headers: { Accept: 'application/json' },\n });\n if (!res.ok) {\n throw new Error(`failed to fetch JWKS: ${res.status} ${res.statusText}`);\n }\n const data = (await res.json()) as { keys: OcPublicJwk[] };\n cachedJwks = { fetched_at: Date.now(), keys: data.keys };\n return data.keys;\n}\n\nfunction base64urlDecode(input: string): Uint8Array {\n const padded = input.replace(/-/g, '+').replace(/_/g, '/').padEnd(\n Math.ceil(input.length / 4) * 4,\n '='\n );\n const bin =\n typeof atob === 'function'\n ? atob(padded)\n : Buffer.from(padded, 'base64').toString('binary');\n const out = new Uint8Array(bin.length);\n for (let i = 0; i < bin.length; i++) out[i] = bin.charCodeAt(i);\n return out;\n}\n\nfunction hexDecode(input: string): Uint8Array {\n const clean = input.toLowerCase().replace(/^0x/, '');\n if (clean.length % 2 !== 0) throw new Error('hex string has odd length');\n const out = new Uint8Array(clean.length / 2);\n for (let i = 0; i < out.length; i++) {\n out[i] = parseInt(clean.slice(i * 2, i * 2 + 2), 16);\n }\n return out;\n}\n\n/**\n * Verify a webhook signature against the raw request body. The signature\n * is hex-encoded in the OC-Signature header; the kid is in OC-Key-Id.\n *\n * NOTE: pass the *raw* body bytes (not the parsed JSON). Frameworks that\n * re-serialize before your handler runs produce a different byte sequence\n * and verification will fail. In Express set\n * app.use(express.text({ type: '*\\/*' }));\n * In Next.js Pages API routes set\n * export const config = { api: { bodyParser: false } };\n *\n * If `jwk` is omitted the function fetches and caches OC's published JWKS\n * for an hour. Pre-fetching once on boot and passing the matching JWK\n * here is the recommended hot path.\n */\nexport async function verify(\n rawBody: string | Uint8Array,\n sigHex: string,\n kid: string,\n jwk?: OcPublicJwk\n): Promise<VerifyResult> {\n let key = jwk;\n if (!key || key.kid !== kid) {\n const keys = await fetchJwks();\n key = keys.find((k) => k.kid === kid);\n if (!key) {\n return { ok: false, reason: `no JWK with kid=${kid} in published JWKS`, key_id: kid };\n }\n }\n if (key.kty !== 'OKP' || key.crv !== 'Ed25519') {\n return { ok: false, reason: `JWK kid=${kid} is not Ed25519`, key_id: kid };\n }\n\n let pubKey: Uint8Array;\n try {\n pubKey = base64urlDecode(key.x);\n } catch (err) {\n return {\n ok: false,\n reason: `failed to decode JWK x: ${(err as Error).message}`,\n key_id: kid,\n };\n }\n if (pubKey.length !== 32) {\n return {\n ok: false,\n reason: `Ed25519 public key must be 32 bytes; got ${pubKey.length}`,\n key_id: kid,\n };\n }\n\n let sig: Uint8Array;\n try {\n sig = hexDecode(sigHex);\n } catch (err) {\n return {\n ok: false,\n reason: `failed to decode signature: ${(err as Error).message}`,\n key_id: kid,\n };\n }\n if (sig.length !== 64) {\n return {\n ok: false,\n reason: `Ed25519 signature must be 64 bytes; got ${sig.length}`,\n key_id: kid,\n };\n }\n\n const bodyBytes =\n typeof rawBody === 'string' ? new TextEncoder().encode(rawBody) : rawBody;\n const hash = sha256(bodyBytes);\n\n try {\n const ok = ed25519.verify(sig, hash, pubKey);\n return ok\n ? { ok: true, key_id: kid }\n : { ok: false, reason: 'signature does not match', key_id: kid };\n } catch (err) {\n return { ok: false, reason: (err as Error).message, key_id: kid };\n }\n}\n\nexport const webhook = { verify, fetchJwks };\n","import { api } from './transport';\n\n/** A scope token an agent delegation can carry. */\nexport type DelegationScope =\n | 'identity.read'\n | 'inbox.read'\n | 'attest.verify'\n | 'stamp.sign'\n | 'payment.authorize';\n\nexport interface IssueDelegationOptions {\n /** Agent identifier — usually the agent's own pubkey or DID. */\n agent_id: string;\n /** Scopes the agent is allowed to act on. */\n scope: DelegationScope[];\n /** ISO-8601 expiration timestamp. Max 30 days in the future. */\n expires_at: string;\n /** Optional human-readable reason shown in /me/agents. */\n reason?: string;\n}\n\nexport interface DelegationEnvelope {\n /** Content-addressed envelope id. */\n id: string;\n /** Scope tokens the agent is allowed. */\n scope: DelegationScope[];\n /** ISO-8601 expiration. */\n expires_at: string;\n /** ISO-8601 issuance time. */\n issued_at: string;\n /** Public verifier URL. */\n verify_url: string;\n}\n\n/**\n * Issue an agent delegation. Class A billable event for the integrating\n * site that initiates it (the user authorizes from /me/agents).\n *\n * v1: returns a stub envelope until the federation signing service ships.\n * The shape is canonical and matches what production will return.\n */\nasync function issue(opts: IssueDelegationOptions): Promise<DelegationEnvelope> {\n if (!opts.agent_id) throw new Error('agent_id is required');\n if (!opts.scope?.length) throw new Error('scope must contain at least one token');\n if (!opts.expires_at) throw new Error('expires_at is required');\n return api<DelegationEnvelope>('/api/delegation/issue', {\n method: 'POST',\n body: opts,\n });\n}\n\n/** Revoke a previously-issued delegation by envelope id. Verifier rejects\n * any envelope signed under the delegation after revocation. */\nasync function revoke(delegation_id: string): Promise<{ ok: true }> {\n return api<{ ok: true }>('/api/delegation/revoke', {\n method: 'POST',\n body: { delegation_id },\n });\n}\n\nexport const delegation = { issue, revoke };\n","/**\n * @orangecheck/me-client\n *\n * Drop-in client for me.ochk.io. Exports the canonical billable-event\n * taxonomy as TypeScript types, session lifecycle hooks, payment\n * authorization, integrator-config CRUD, agent-delegation issue/revoke,\n * webhook signature verification, the developer telemetry stream, and\n * the React sign-in button + `useOcSession` hook.\n *\n * Sign-in-with-OC. You pay for sessions and actions, not for clicks.\n */\n\nexport { OcSignInButton } from './SignInButton';\nexport type { OcSignInButtonProps } from './SignInButton';\n\n// Re-export the React session primitives so integrators can pull every\n// auth surface from a single package.\nexport { OcSessionProvider, useOcSession, useOptionalOcSession } from '@orangecheck/auth-client';\nexport type {\n OcAccount,\n OcSessionState,\n OcSessionStatus,\n OcAuthConfig,\n} from '@orangecheck/auth-client';\n\nexport { session, onTelemetry } from './session';\nexport { payment } from './payment';\nexport { config } from './config';\nexport { webhook } from './webhook';\nexport type { OcPublicJwk, VerifyResult } from './webhook';\nexport { delegation } from './delegation';\nexport type { DelegationScope, DelegationEnvelope, IssueDelegationOptions } from './delegation';\nexport { setOrigin, getOrigin, MeClientError } from './transport';\n\nexport {\n PLATFORM_FEE_POLICY,\n MIN_INTEGRATOR_PRICE_SATS,\n computeFees,\n validateIntegratorConfig,\n} from './types';\n\nexport type {\n EventClass,\n EventSubtype,\n ClassASubtype,\n ClassBSubtype,\n ClassCSubtype,\n AttestTier,\n SiteFeeShape,\n IntegratorEventConfig,\n IntegratorPriceConfig,\n ComputedFees,\n ValidationResult,\n BillableEvent,\n Session,\n SessionPolicy,\n SignInOptions,\n PaymentAuthorizeOptions,\n PaymentResult,\n TelemetryEvent,\n} from './types';\n\nimport { session } from './session';\nimport { payment } from './payment';\nimport { config } from './config';\nimport { webhook } from './webhook';\nimport { delegation } from './delegation';\n\n/** Convenience namespace mirroring the public API surface in /integrate\n * code samples — `oc.session.create()`, `oc.payment.authorize()`,\n * `oc.config.update()`, `oc.webhook.verify()`, `oc.delegation.issue()`. */\nexport const oc = { session, payment, config, webhook, delegation };\n"]}
1
+ {"version":3,"sources":["../src/transport.ts","../src/session.ts","../src/SignInButton.tsx","../src/payment.ts","../src/types.ts","../src/index.ts"],"names":[],"mappings":"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","file":"index.mjs","sourcesContent":["/**\n * Tiny HTTP transport layer. The me.ochk.io origin is configurable so\n * staging deployments and self-hosted me-equivalents can swap it.\n */\n\nlet origin = 'https://me.ochk.io';\n\nexport function setOrigin(url: string): void {\n origin = url.replace(/\\/$/, '');\n}\n\nexport function getOrigin(): string {\n return origin;\n}\n\nexport interface FetchOptions {\n method?: 'GET' | 'POST' | 'PATCH' | 'DELETE';\n body?: unknown;\n signal?: AbortSignal;\n}\n\nexport async function api<T>(path: string, opts: FetchOptions = {}): Promise<T> {\n const res = await fetch(`${origin}${path}`, {\n method: opts.method ?? 'GET',\n credentials: 'include',\n headers: { 'content-type': 'application/json', accept: 'application/json' },\n body: opts.body !== undefined ? JSON.stringify(opts.body) : undefined,\n signal: opts.signal,\n });\n if (!res.ok) {\n let message = `me.ochk.io ${res.status}`;\n try {\n const data = (await res.json()) as { error?: string };\n if (data?.error) message = data.error;\n } catch {\n /* ignore */\n }\n throw new MeClientError(message, res.status);\n }\n return (await res.json()) as T;\n}\n\nexport class MeClientError extends Error {\n public readonly status: number;\n constructor(message: string, status: number) {\n super(message);\n this.name = 'MeClientError';\n this.status = status;\n }\n}\n","import type { Session, SessionPolicy, SignInOptions, TelemetryEvent } from './types';\n\nimport { api } from './transport';\n\nconst DEFAULT_POLICY: SessionPolicy = {\n duration_seconds: 7 * 24 * 60 * 60, // 7 days, standard SaaS shape\n refresh: 'sliding',\n sensitive_actions: 're-auth',\n};\n\nconst telemetrySubscribers = new Set<(e: TelemetryEvent) => void>();\n\n/** Subscribe to non-billable developer telemetry events. Call the returned\n * function to unsubscribe. */\nexport function onTelemetry(listener: (e: TelemetryEvent) => void): () => void {\n telemetrySubscribers.add(listener);\n return () => {\n telemetrySubscribers.delete(listener);\n };\n}\n\nfunction emitTelemetry(code: TelemetryEvent['code'], session_id?: string): void {\n const e: TelemetryEvent = {\n code,\n timestamp: new Date().toISOString(),\n ...(session_id ? { session_id } : {}),\n };\n for (const fn of telemetrySubscribers) {\n try {\n fn(e);\n } catch {\n /* listener errors must not break the session flow */\n }\n }\n}\n\n/**\n * Open a sign-in flow at me.ochk.io. Returns the resulting Session once\n * the user consents (Class C billable event for the integrating site,\n * cashback for the user). Internally this opens the OC consent UI in a\n * popup; v1 implementations may also redirect.\n */\nasync function create(opts: SignInOptions): Promise<Session> {\n const policy: SessionPolicy = { ...DEFAULT_POLICY, ...(opts.sessionPolicy ?? {}) };\n return api<Session>('/api/session/create', {\n method: 'POST',\n body: {\n scope: opts.scope,\n policy,\n return_to: opts.returnTo ?? (typeof window !== 'undefined' ? window.location.href : undefined),\n },\n });\n}\n\n/**\n * Refresh a still-valid session inside its policy window. Free for the\n * integrating site (does NOT instantiate a billable event); emits a\n * `session.token_refresh` telemetry record.\n */\nasync function refresh(sessionId: string): Promise<Session> {\n emitTelemetry('session.token_refresh', sessionId);\n return api<Session>('/api/session/refresh', {\n method: 'POST',\n body: { session_id: sessionId },\n });\n}\n\n/** Invalidate a session. Free, telemetry-only. */\nasync function invalidate(sessionId: string): Promise<void> {\n emitTelemetry('session.intra_signin', sessionId);\n await api<{ ok: true }>('/api/session/invalidate', {\n method: 'POST',\n body: { session_id: sessionId },\n });\n}\n\nexport const session = { create, refresh, invalidate };\n","import * as React from 'react';\n\nimport { session } from './session';\nimport type { Session, SessionPolicy } from './types';\n\nexport interface OcSignInButtonProps\n extends Omit<React.ButtonHTMLAttributes<HTMLButtonElement>, 'onError'> {\n scope: string[];\n sessionPolicy?: Partial<SessionPolicy>;\n returnTo?: string;\n onSignin?: (session: Session) => void;\n /** Called when the sign-in flow fails. Renamed from `onError` to avoid\n * shadowing the native button error handler. */\n onSignInError?: (error: Error) => void;\n /** Custom button text. Defaults to \"sign in with oc\". */\n label?: string;\n}\n\n/**\n * Drop-in Sign-in-with-OC button. Triggers the me.ochk.io consent flow\n * for the requested scope, opens (or refreshes) a session, and calls\n * onSignin(session) on success. Class C billable event for the\n * integrating site; cashback flows to the user.\n *\n * Mounting requires <OcSessionProvider> from @orangecheck/auth-client\n * somewhere up the React tree so the resulting session can be read by\n * useOcSession() across the rest of the app.\n */\nexport function OcSignInButton({\n scope,\n sessionPolicy,\n returnTo,\n onSignin,\n onSignInError,\n label = 'sign in with oc',\n children,\n onClick,\n style,\n ...rest\n}: OcSignInButtonProps) {\n const [pending, setPending] = React.useState(false);\n\n return (\n <button\n type=\"button\"\n onClick={async (event) => {\n onClick?.(event);\n if (event.defaultPrevented) return;\n setPending(true);\n try {\n const result = await session.create({ scope, sessionPolicy, returnTo });\n onSignin?.(result);\n } catch (err) {\n onSignInError?.(err instanceof Error ? err : new Error(String(err)));\n } finally {\n setPending(false);\n }\n }}\n style={{\n display: 'inline-flex',\n alignItems: 'center',\n gap: 8,\n padding: '10px 16px',\n fontSize: 13,\n fontWeight: 600,\n fontFamily: 'ui-monospace, \"JetBrains Mono\", \"SF Mono\", Menlo, monospace',\n letterSpacing: '0.18em',\n textTransform: 'uppercase',\n background: '#f97316',\n color: '#0b0909',\n border: '1px solid #f97316',\n borderRadius: 4,\n cursor: pending ? 'progress' : 'pointer',\n opacity: pending ? 0.7 : 1,\n ...(style ?? {}),\n }}\n disabled={pending || rest.disabled}\n data-oc-signin\n {...rest}\n >\n {/* compact OC mark */}\n <span\n aria-hidden\n style={{\n display: 'inline-block',\n width: 12,\n height: 12,\n background: '#0b0909',\n }}\n />\n {children ?? (pending ? 'opening…' : label)}\n </button>\n );\n}\n","import type { PaymentAuthorizeOptions, PaymentResult } from './types';\n\nimport { api } from './transport';\n\n/**\n * Authorize a payment through the user's OC identity. Class B billable\n * event for the integrating site (sub-Stripe rate, percentage-based);\n * cashback flows to the user as Lightning credit on /me/earn.\n *\n * The user is prompted by me.ochk.io to consent to the specific payment\n * before this resolves. If the user declines or cancels, the result has\n * status `'cancelled'`, a non-billable telemetry record is emitted, and\n * NO billable event is created.\n */\nasync function authorize(opts: PaymentAuthorizeOptions): Promise<PaymentResult> {\n if (opts.amount_sats == null && opts.usd_cents == null) {\n throw new Error('payment.authorize requires amount_sats or usd_cents');\n }\n return api<PaymentResult>('/api/payment/authorize', {\n method: 'POST',\n body: opts,\n });\n}\n\nexport const payment = { authorize };\n","/**\n * Canonical types for me.ochk.io integrators.\n *\n * Mirrors the source of truth at oc-me-web/src/lib/events/types.ts. Two\n * layers:\n * - Platform-level (PLATFORM_FEE_POLICY, MIN_INTEGRATOR_PRICE_SATS) —\n * fixed by OC, surfaced as constants here so integrators can validate\n * their config client-side before posting it.\n * - Integrator-level (IntegratorPriceConfig) — every integrator declares\n * their own per-event prices and user-share splits.\n *\n * Per Addendum 01: every chargeable event is in exactly one of three\n * classes. Sites pay for sessions and actions, not for clicks. Free\n * events never instantiate a BillableEvent.\n */\n\n// ── platform constants (fixed by OC) ──────────────────────────────────────\n\nexport const PLATFORM_FEE_POLICY = {\n /** Fraction of every gross_fee that OC retains. */\n pct: 0.2,\n /** Absolute minimum platform fee, in sats. */\n min_floor_sats: 1,\n /** Date this policy was last ratified. Changes require a versioned\n * @orangecheck/me-client release. */\n ratified: '2026-04-30',\n} as const;\n\n/** Anti-spam price floor. No integrator can configure a per-event price\n * below this. */\nexport const MIN_INTEGRATOR_PRICE_SATS = 5;\n\n// ── event taxonomy ────────────────────────────────────────────────────────\n\nexport type EventClass = 'A' | 'B' | 'C';\n\nexport type ClassASubtype =\n | 'account_creation'\n | 'account_recovery'\n | 'kyc_tier_upgrade'\n | 'payment_method_connected'\n | 'agent_delegation_issued'\n | 'recovery_method_updated';\n\nexport type ClassBSubtype =\n | 'payment_authorization'\n | 'scoped_action_authorization'\n | 'attest_verification_at_gate'\n | 'stamp_signing'\n | 'pledge_resolution';\n\nexport type ClassCSubtype = 'session_creation';\n\nexport type EventSubtype = ClassASubtype | ClassBSubtype | ClassCSubtype;\n\nexport type AttestTier = 'anonymous' | 'bonded' | 'kyc_light' | 'kyc_strong';\n\n/** The shape of a per-event fee — either a fixed sats amount or a percent\n * of the underlying transaction amount (used for payments + pledges). */\nexport type SiteFeeShape =\n | { kind: 'fixed_sats'; sats: number }\n | { kind: 'percent_of_amount'; pct: number };\n\n/** What an integrator declares for a single event subtype. */\nexport interface IntegratorEventConfig {\n /** Whether this site bills this event subtype at all. */\n enabled: boolean;\n /** The per-event fee the site pays. */\n site_pays: SiteFeeShape;\n /** Fraction of post-platform-fee that flows to the user (0–0.8 since\n * platform_fee is 20%). The remainder is a rebate to the site's OC\n * project balance. */\n user_share_pct: number;\n}\n\n/** A complete integrator pricing config. Posted to me.ochk.io once at\n * integration time, mutable via the configurator UI or this SDK any time\n * after. */\nexport interface IntegratorPriceConfig {\n project_key: string;\n display_name: string;\n domain: string;\n /** ISO-8601 timestamp the config was last updated. */\n updated_at: string;\n /** Per-subtype configs. Subtypes not listed are disabled by default. */\n events: Partial<Record<EventSubtype, IntegratorEventConfig>>;\n}\n\n/** A computed fee breakdown for a single event. site_rebate_sats is what\n * flows back to the integrator's OC balance after OC's platform fee and\n * the user's cashback. */\nexport interface ComputedFees {\n gross_fee_sats: number;\n platform_fee_sats: number;\n user_earned_sats: number;\n site_rebate_sats: number;\n}\n\n/** Compute the four-way fee split for an event given an integrator's\n * config and (for percent_of_amount events) the underlying payment\n * amount.\n *\n * Invariants (verified by tests in oc-me-web/src/lib/events/types.test.ts):\n * 1. gross_fee_sats >= MIN_INTEGRATOR_PRICE_SATS\n * 2. platform_fee_sats >= PLATFORM_FEE_POLICY.min_floor_sats\n * 3. user_share_pct is clamped to [0, 0.8]\n * 4. site_rebate_sats >= 0\n * 5. gross == platform + user + rebate (exact, modulo rounding into rebate)\n */\nexport function computeFees(\n cfg: IntegratorEventConfig,\n payment_amount_sats?: number\n): ComputedFees {\n let gross = 0;\n if (cfg.site_pays.kind === 'fixed_sats') {\n gross = Math.max(MIN_INTEGRATOR_PRICE_SATS, Math.round(cfg.site_pays.sats));\n } else {\n if (payment_amount_sats == null) {\n throw new Error('percent_of_amount config requires payment_amount_sats');\n }\n gross = Math.max(\n MIN_INTEGRATOR_PRICE_SATS,\n Math.round(payment_amount_sats * cfg.site_pays.pct)\n );\n }\n const platform_fee_sats = Math.max(\n PLATFORM_FEE_POLICY.min_floor_sats,\n Math.round(gross * PLATFORM_FEE_POLICY.pct)\n );\n const user_share = Math.min(0.8, Math.max(0, cfg.user_share_pct));\n const user_earned_sats = Math.round(gross * user_share);\n const site_rebate_sats = Math.max(0, gross - platform_fee_sats - user_earned_sats);\n return { gross_fee_sats: gross, platform_fee_sats, user_earned_sats, site_rebate_sats };\n}\n\n/** Result of validating an IntegratorPriceConfig. */\nexport interface ValidationResult {\n ok: boolean;\n errors: { subtype?: EventSubtype; message: string }[];\n}\n\n/**\n * Validate an integrator's pricing config against the platform's\n * non-negotiable rules. Run client-side before posting; the server runs\n * the same checks and rejects anything that fails.\n */\nexport function validateIntegratorConfig(cfg: IntegratorPriceConfig): ValidationResult {\n const errors: ValidationResult['errors'] = [];\n\n if (!cfg.project_key) errors.push({ message: 'project_key is required' });\n if (!cfg.display_name) errors.push({ message: 'display_name is required' });\n if (!cfg.domain) errors.push({ message: 'domain is required' });\n\n for (const [key, eventCfg] of Object.entries(cfg.events)) {\n if (!eventCfg) continue;\n const subtype = key as EventSubtype;\n if (!eventCfg.enabled) continue;\n\n if (eventCfg.site_pays.kind === 'fixed_sats') {\n if (eventCfg.site_pays.sats < MIN_INTEGRATOR_PRICE_SATS) {\n errors.push({\n subtype,\n message: `site_pays.sats (${eventCfg.site_pays.sats}) is below MIN_INTEGRATOR_PRICE_SATS (${MIN_INTEGRATOR_PRICE_SATS})`,\n });\n }\n } else {\n const pct = eventCfg.site_pays.pct;\n if (!(pct > 0 && pct <= 1)) {\n errors.push({\n subtype,\n message: `site_pays.pct (${pct}) must be in (0, 1]`,\n });\n }\n }\n\n const u = eventCfg.user_share_pct;\n if (u < 0 || u > 0.8) {\n errors.push({\n subtype,\n message: `user_share_pct (${u}) must be in [0, 0.8]; max is 0.8 because platform_fee is ${PLATFORM_FEE_POLICY.pct}`,\n });\n }\n }\n\n return { ok: errors.length === 0, errors };\n}\n\n// ── canonical envelope ────────────────────────────────────────────────────\n\nexport interface BillableEvent {\n id: string;\n occurred_at: string;\n class: EventClass;\n subtype: EventSubtype;\n site: { domain: string; display_name: string };\n gross_fee_sats: number;\n platform_fee_sats: number;\n user_earned_sats: number;\n site_rebate_sats: number;\n verify_url: string;\n}\n\n// ── session lifecycle ────────────────────────────────────────────────────\n\nexport interface SessionPolicy {\n duration_seconds: number;\n refresh: 'sliding' | 'rolling' | 'none';\n sensitive_actions?: 're-auth' | 'none';\n}\n\nexport interface Session {\n id: string;\n identity: string;\n opens_at: string;\n expires_at: string;\n policy: SessionPolicy;\n scope: string[];\n}\n\nexport interface SignInOptions {\n scope: string[];\n sessionPolicy?: Partial<SessionPolicy>;\n returnTo?: string;\n}\n\nexport interface PaymentAuthorizeOptions {\n identity: string;\n amount_sats?: number;\n usd_cents?: number;\n description: string;\n external_ref?: string;\n}\n\nexport interface PaymentResult {\n id: string;\n status: 'authorized' | 'failed' | 'cancelled';\n sats_charged?: number;\n user_envelope_id?: string;\n verify_url?: string;\n}\n\nexport interface TelemetryEvent {\n code:\n | 'session.intra_signin'\n | 'session.token_refresh'\n | 'session.navigation'\n | 'auth.signin_failed'\n | 'auth.signin_cancelled'\n | 'auth.signin_rejected'\n | 'verify.passive_check';\n timestamp: string;\n session_id?: string;\n}\n","/**\n * @orangecheck/me-client\n *\n * Drop-in client for me.ochk.io. Sign-in-with-OC. You pay for sessions\n * and actions, not for clicks.\n *\n * Three entry points for three audiences:\n *\n * import { ... } from '@orangecheck/me-client' // React surface\n * import { ... } from '@orangecheck/me-client/server' // server-side\n * verification\n * (Next.js, Express,\n * Hono — all without\n * env vars or JWK\n * handling)\n * import { signInWithOc } from '@orangecheck/me-client/popup'\n * // browser-only popup\n * orchestrator\n *\n * Server-side verification example:\n *\n * // pages/api/me.ts\n * import { withOcAuth } from '@orangecheck/me-client/server';\n *\n * export default withOcAuth(async (req, res) => {\n * if (!req.ocSession) return res.status(401).json({ ok: false });\n * res.status(200).json({ address: req.ocSession.addr });\n * });\n *\n * Popup signin example:\n *\n * import { signInWithOc } from '@orangecheck/me-client/popup';\n *\n * button.addEventListener('click', async () => {\n * const result = await signInWithOc();\n * if (!result) return; // user cancelled\n * localStorage.setItem('oc-token', result.token);\n * location.assign('/dashboard');\n * });\n */\n\nexport { OcSignInButton } from './SignInButton';\nexport type { OcSignInButtonProps } from './SignInButton';\n\nexport { session, onTelemetry } from './session';\nexport { payment } from './payment';\nexport { setOrigin, getOrigin, MeClientError } from './transport';\n\nexport {\n PLATFORM_FEE_POLICY,\n MIN_INTEGRATOR_PRICE_SATS,\n computeFees,\n validateIntegratorConfig,\n} from './types';\n\nexport type {\n EventClass,\n EventSubtype,\n ClassASubtype,\n ClassBSubtype,\n ClassCSubtype,\n AttestTier,\n SiteFeeShape,\n IntegratorEventConfig,\n IntegratorPriceConfig,\n ComputedFees,\n ValidationResult,\n BillableEvent,\n Session,\n SessionPolicy,\n SignInOptions,\n PaymentAuthorizeOptions,\n PaymentResult,\n TelemetryEvent,\n} from './types';\n\nimport { session } from './session';\nimport { payment } from './payment';\n\n/** Convenience namespace mirroring the public API surface in /integrate\n * code samples — `oc.session.create()`, `oc.payment.authorize()`. */\nexport const oc = { session, payment };\n"]}
@@ -0,0 +1,22 @@
1
+ interface OcPopupAccount {
2
+ id?: string;
3
+ address?: string;
4
+ btc_address?: string;
5
+ display_name?: string | null;
6
+ nostr_npub?: string | null;
7
+ wallet_provisioned?: boolean;
8
+ email?: string;
9
+ }
10
+ interface OcPopupResult {
11
+ account: OcPopupAccount;
12
+ token: string;
13
+ }
14
+ interface SignInWithOcOptions {
15
+ popupOrigin?: string;
16
+ popupPath?: string;
17
+ features?: string;
18
+ signal?: AbortSignal;
19
+ }
20
+ declare function signInWithOc(options?: SignInWithOcOptions): Promise<OcPopupResult | null>;
21
+
22
+ export { type OcPopupAccount, type OcPopupResult, type SignInWithOcOptions, signInWithOc };
@@ -0,0 +1,22 @@
1
+ interface OcPopupAccount {
2
+ id?: string;
3
+ address?: string;
4
+ btc_address?: string;
5
+ display_name?: string | null;
6
+ nostr_npub?: string | null;
7
+ wallet_provisioned?: boolean;
8
+ email?: string;
9
+ }
10
+ interface OcPopupResult {
11
+ account: OcPopupAccount;
12
+ token: string;
13
+ }
14
+ interface SignInWithOcOptions {
15
+ popupOrigin?: string;
16
+ popupPath?: string;
17
+ features?: string;
18
+ signal?: AbortSignal;
19
+ }
20
+ declare function signInWithOc(options?: SignInWithOcOptions): Promise<OcPopupResult | null>;
21
+
22
+ export { type OcPopupAccount, type OcPopupResult, type SignInWithOcOptions, signInWithOc };
package/dist/popup.js ADDED
@@ -0,0 +1,69 @@
1
+ 'use strict';
2
+
3
+ // src/popup.ts
4
+ var DEFAULT_POPUP_ORIGIN = "https://me.ochk.io";
5
+ var DEFAULT_POPUP_PATH = "/popup/signin";
6
+ var DEFAULT_FEATURES = "width=480,height=720,resizable=yes,scrollbars=yes";
7
+ function signInWithOc(options = {}) {
8
+ const popupOrigin = options.popupOrigin ?? DEFAULT_POPUP_ORIGIN;
9
+ const popupPath = options.popupPath ?? DEFAULT_POPUP_PATH;
10
+ const features = options.features ?? DEFAULT_FEATURES;
11
+ return new Promise((resolve) => {
12
+ if (typeof window === "undefined") {
13
+ resolve(null);
14
+ return;
15
+ }
16
+ const url = new URL(popupPath, popupOrigin);
17
+ url.searchParams.set("opener_origin", window.location.origin);
18
+ const popup = window.open(url.toString(), "oc-signin", features);
19
+ if (!popup) {
20
+ resolve(null);
21
+ return;
22
+ }
23
+ popup.focus();
24
+ let settled = false;
25
+ const cleanup = () => {
26
+ window.removeEventListener("message", onMessage);
27
+ clearInterval(closedTimer);
28
+ if (options.signal) options.signal.removeEventListener("abort", onAbort);
29
+ };
30
+ function settle(value) {
31
+ if (settled) return;
32
+ settled = true;
33
+ cleanup();
34
+ try {
35
+ if (popup && !popup.closed) popup.close();
36
+ } catch {
37
+ }
38
+ resolve(value);
39
+ }
40
+ function onMessage(event) {
41
+ if (event.origin !== popupOrigin) return;
42
+ const data = event.data;
43
+ if (!data || data.type !== "oc-signin-success") return;
44
+ if (!data.account || !data.token) {
45
+ settle(null);
46
+ return;
47
+ }
48
+ settle({ account: data.account, token: data.token });
49
+ }
50
+ function onAbort() {
51
+ settle(null);
52
+ }
53
+ window.addEventListener("message", onMessage);
54
+ if (options.signal) {
55
+ if (options.signal.aborted) {
56
+ settle(null);
57
+ return;
58
+ }
59
+ options.signal.addEventListener("abort", onAbort);
60
+ }
61
+ const closedTimer = setInterval(() => {
62
+ if (popup && popup.closed) settle(null);
63
+ }, 500);
64
+ });
65
+ }
66
+
67
+ exports.signInWithOc = signInWithOc;
68
+ //# sourceMappingURL=popup.js.map
69
+ //# sourceMappingURL=popup.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/popup.ts"],"names":[],"mappings":"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","file":"popup.js","sourcesContent":["/**\n * @orangecheck/me-client/popup\n *\n * Browser-side helper that opens the OC sign-in popup, listens for the\n * postMessage from me.ochk.io, and resolves with the verified session.\n *\n * import { signInWithOc } from '@orangecheck/me-client/popup';\n *\n * document.querySelector('#oc-signin')!.addEventListener('click', async () => {\n * const result = await signInWithOc();\n * if (result) {\n * localStorage.setItem('oc-session-token', result.token);\n * location.assign('/app');\n * }\n * });\n *\n * Why this lives in a separate entry point: it's browser-only (uses\n * window.open / addEventListener) and integrators that only need the\n * server-side verifier shouldn't pull popup orchestration into their\n * server bundle.\n */\n\nconst DEFAULT_POPUP_ORIGIN = 'https://me.ochk.io';\nconst DEFAULT_POPUP_PATH = '/popup/signin';\nconst DEFAULT_FEATURES = 'width=480,height=720,resizable=yes,scrollbars=yes';\n\nexport interface OcPopupAccount {\n id?: string;\n address?: string;\n btc_address?: string;\n display_name?: string | null;\n nostr_npub?: string | null;\n wallet_provisioned?: boolean;\n email?: string;\n}\n\nexport interface OcPopupResult {\n /** Account payload from the auth host. `address` is the canonical\n * identifier (Bitcoin address for BIP-322 users, did:email:<hash>\n * for email-OTP users). */\n account: OcPopupAccount;\n /** The session JWT. Cross-domain integrators store this and send\n * it as `Authorization: Bearer <token>` on subsequent calls.\n * Family integrators (*.ochk.io) can ignore it — the cookie set\n * Domain=.ochk.io rides home automatically. */\n token: string;\n}\n\nexport interface SignInWithOcOptions {\n /** Origin of the OC popup page. Defaults to https://me.ochk.io.\n * Override only for staging / preview environments. */\n popupOrigin?: string;\n /** Path on the popup origin. Defaults to /popup/signin. */\n popupPath?: string;\n /** window.open features string. Defaults to a 480x720 resizable\n * popup with scrollbars. */\n features?: string;\n /** AbortSignal that cancels the wait and closes the popup. */\n signal?: AbortSignal;\n}\n\n/**\n * Open the OC signin popup and resolve with the session result. Returns\n * `null` if the user closed the popup without completing signin, or if\n * the AbortSignal fired.\n *\n * MUST be called inside a user-gesture handler (e.g. a button onClick).\n * Browsers block `window.open` outside of user gestures.\n */\nexport function signInWithOc(options: SignInWithOcOptions = {}): Promise<OcPopupResult | null> {\n const popupOrigin = options.popupOrigin ?? DEFAULT_POPUP_ORIGIN;\n const popupPath = options.popupPath ?? DEFAULT_POPUP_PATH;\n const features = options.features ?? DEFAULT_FEATURES;\n\n return new Promise((resolve) => {\n if (typeof window === 'undefined') {\n resolve(null);\n return;\n }\n\n const url = new URL(popupPath, popupOrigin);\n url.searchParams.set('opener_origin', window.location.origin);\n const popup = window.open(url.toString(), 'oc-signin', features);\n if (!popup) {\n // Popup blocked. Caller can detect a null result and fall\n // back to a full-page redirect if desired.\n resolve(null);\n return;\n }\n popup.focus();\n\n let settled = false;\n const cleanup = () => {\n window.removeEventListener('message', onMessage);\n clearInterval(closedTimer);\n if (options.signal) options.signal.removeEventListener('abort', onAbort);\n };\n\n function settle(value: OcPopupResult | null) {\n if (settled) return;\n settled = true;\n cleanup();\n try {\n if (popup && !popup.closed) popup.close();\n } catch {\n /* popup may have closed itself first */\n }\n resolve(value);\n }\n\n function onMessage(event: MessageEvent) {\n if (event.origin !== popupOrigin) return;\n const data = event.data as\n | { type?: string; account?: OcPopupAccount; token?: string }\n | null;\n if (!data || data.type !== 'oc-signin-success') return;\n if (!data.account || !data.token) {\n // Malformed payload — treat as not-signed-in.\n settle(null);\n return;\n }\n settle({ account: data.account, token: data.token });\n }\n\n function onAbort() {\n settle(null);\n }\n\n window.addEventListener('message', onMessage);\n if (options.signal) {\n if (options.signal.aborted) {\n settle(null);\n return;\n }\n options.signal.addEventListener('abort', onAbort);\n }\n\n // Detect the user closing the popup without completing signin.\n const closedTimer = setInterval(() => {\n if (popup && popup.closed) settle(null);\n }, 500);\n });\n}\n"]}
package/dist/popup.mjs ADDED
@@ -0,0 +1,67 @@
1
+ // src/popup.ts
2
+ var DEFAULT_POPUP_ORIGIN = "https://me.ochk.io";
3
+ var DEFAULT_POPUP_PATH = "/popup/signin";
4
+ var DEFAULT_FEATURES = "width=480,height=720,resizable=yes,scrollbars=yes";
5
+ function signInWithOc(options = {}) {
6
+ const popupOrigin = options.popupOrigin ?? DEFAULT_POPUP_ORIGIN;
7
+ const popupPath = options.popupPath ?? DEFAULT_POPUP_PATH;
8
+ const features = options.features ?? DEFAULT_FEATURES;
9
+ return new Promise((resolve) => {
10
+ if (typeof window === "undefined") {
11
+ resolve(null);
12
+ return;
13
+ }
14
+ const url = new URL(popupPath, popupOrigin);
15
+ url.searchParams.set("opener_origin", window.location.origin);
16
+ const popup = window.open(url.toString(), "oc-signin", features);
17
+ if (!popup) {
18
+ resolve(null);
19
+ return;
20
+ }
21
+ popup.focus();
22
+ let settled = false;
23
+ const cleanup = () => {
24
+ window.removeEventListener("message", onMessage);
25
+ clearInterval(closedTimer);
26
+ if (options.signal) options.signal.removeEventListener("abort", onAbort);
27
+ };
28
+ function settle(value) {
29
+ if (settled) return;
30
+ settled = true;
31
+ cleanup();
32
+ try {
33
+ if (popup && !popup.closed) popup.close();
34
+ } catch {
35
+ }
36
+ resolve(value);
37
+ }
38
+ function onMessage(event) {
39
+ if (event.origin !== popupOrigin) return;
40
+ const data = event.data;
41
+ if (!data || data.type !== "oc-signin-success") return;
42
+ if (!data.account || !data.token) {
43
+ settle(null);
44
+ return;
45
+ }
46
+ settle({ account: data.account, token: data.token });
47
+ }
48
+ function onAbort() {
49
+ settle(null);
50
+ }
51
+ window.addEventListener("message", onMessage);
52
+ if (options.signal) {
53
+ if (options.signal.aborted) {
54
+ settle(null);
55
+ return;
56
+ }
57
+ options.signal.addEventListener("abort", onAbort);
58
+ }
59
+ const closedTimer = setInterval(() => {
60
+ if (popup && popup.closed) settle(null);
61
+ }, 500);
62
+ });
63
+ }
64
+
65
+ export { signInWithOc };
66
+ //# sourceMappingURL=popup.mjs.map
67
+ //# sourceMappingURL=popup.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/popup.ts"],"names":[],"mappings":"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","file":"popup.mjs","sourcesContent":["/**\n * @orangecheck/me-client/popup\n *\n * Browser-side helper that opens the OC sign-in popup, listens for the\n * postMessage from me.ochk.io, and resolves with the verified session.\n *\n * import { signInWithOc } from '@orangecheck/me-client/popup';\n *\n * document.querySelector('#oc-signin')!.addEventListener('click', async () => {\n * const result = await signInWithOc();\n * if (result) {\n * localStorage.setItem('oc-session-token', result.token);\n * location.assign('/app');\n * }\n * });\n *\n * Why this lives in a separate entry point: it's browser-only (uses\n * window.open / addEventListener) and integrators that only need the\n * server-side verifier shouldn't pull popup orchestration into their\n * server bundle.\n */\n\nconst DEFAULT_POPUP_ORIGIN = 'https://me.ochk.io';\nconst DEFAULT_POPUP_PATH = '/popup/signin';\nconst DEFAULT_FEATURES = 'width=480,height=720,resizable=yes,scrollbars=yes';\n\nexport interface OcPopupAccount {\n id?: string;\n address?: string;\n btc_address?: string;\n display_name?: string | null;\n nostr_npub?: string | null;\n wallet_provisioned?: boolean;\n email?: string;\n}\n\nexport interface OcPopupResult {\n /** Account payload from the auth host. `address` is the canonical\n * identifier (Bitcoin address for BIP-322 users, did:email:<hash>\n * for email-OTP users). */\n account: OcPopupAccount;\n /** The session JWT. Cross-domain integrators store this and send\n * it as `Authorization: Bearer <token>` on subsequent calls.\n * Family integrators (*.ochk.io) can ignore it — the cookie set\n * Domain=.ochk.io rides home automatically. */\n token: string;\n}\n\nexport interface SignInWithOcOptions {\n /** Origin of the OC popup page. Defaults to https://me.ochk.io.\n * Override only for staging / preview environments. */\n popupOrigin?: string;\n /** Path on the popup origin. Defaults to /popup/signin. */\n popupPath?: string;\n /** window.open features string. Defaults to a 480x720 resizable\n * popup with scrollbars. */\n features?: string;\n /** AbortSignal that cancels the wait and closes the popup. */\n signal?: AbortSignal;\n}\n\n/**\n * Open the OC signin popup and resolve with the session result. Returns\n * `null` if the user closed the popup without completing signin, or if\n * the AbortSignal fired.\n *\n * MUST be called inside a user-gesture handler (e.g. a button onClick).\n * Browsers block `window.open` outside of user gestures.\n */\nexport function signInWithOc(options: SignInWithOcOptions = {}): Promise<OcPopupResult | null> {\n const popupOrigin = options.popupOrigin ?? DEFAULT_POPUP_ORIGIN;\n const popupPath = options.popupPath ?? DEFAULT_POPUP_PATH;\n const features = options.features ?? DEFAULT_FEATURES;\n\n return new Promise((resolve) => {\n if (typeof window === 'undefined') {\n resolve(null);\n return;\n }\n\n const url = new URL(popupPath, popupOrigin);\n url.searchParams.set('opener_origin', window.location.origin);\n const popup = window.open(url.toString(), 'oc-signin', features);\n if (!popup) {\n // Popup blocked. Caller can detect a null result and fall\n // back to a full-page redirect if desired.\n resolve(null);\n return;\n }\n popup.focus();\n\n let settled = false;\n const cleanup = () => {\n window.removeEventListener('message', onMessage);\n clearInterval(closedTimer);\n if (options.signal) options.signal.removeEventListener('abort', onAbort);\n };\n\n function settle(value: OcPopupResult | null) {\n if (settled) return;\n settled = true;\n cleanup();\n try {\n if (popup && !popup.closed) popup.close();\n } catch {\n /* popup may have closed itself first */\n }\n resolve(value);\n }\n\n function onMessage(event: MessageEvent) {\n if (event.origin !== popupOrigin) return;\n const data = event.data as\n | { type?: string; account?: OcPopupAccount; token?: string }\n | null;\n if (!data || data.type !== 'oc-signin-success') return;\n if (!data.account || !data.token) {\n // Malformed payload — treat as not-signed-in.\n settle(null);\n return;\n }\n settle({ account: data.account, token: data.token });\n }\n\n function onAbort() {\n settle(null);\n }\n\n window.addEventListener('message', onMessage);\n if (options.signal) {\n if (options.signal.aborted) {\n settle(null);\n return;\n }\n options.signal.addEventListener('abort', onAbort);\n }\n\n // Detect the user closing the popup without completing signin.\n const closedTimer = setInterval(() => {\n if (popup && popup.closed) settle(null);\n }, 500);\n });\n}\n"]}
@@ -0,0 +1,51 @@
1
+ import { VerifyOcOptions, SessionRequestHeaders, SessionPayload } from '@orangecheck/auth-core';
2
+ export { SessionPayload, VerifyOcOptions, verifyOcToken } from '@orangecheck/auth-core';
3
+
4
+ declare function getOcSession(headers: SessionRequestHeaders | Headers, options?: VerifyOcOptions): Promise<SessionPayload | null>;
5
+ interface NextApiRequestLike {
6
+ headers: {
7
+ cookie?: string;
8
+ authorization?: string;
9
+ [k: string]: unknown;
10
+ };
11
+ ocSession?: SessionPayload | null;
12
+ }
13
+ interface NextApiResponseLike {
14
+ status(code: number): NextApiResponseLike;
15
+ json(body: unknown): unknown;
16
+ setHeader(name: string, value: string | number | readonly string[]): unknown;
17
+ }
18
+ type NextApiHandlerLike = (req: NextApiRequestLike, res: NextApiResponseLike) => unknown | Promise<unknown>;
19
+ interface WithOcAuthOptions extends VerifyOcOptions {
20
+ required?: boolean;
21
+ }
22
+ declare function withOcAuth<T extends NextApiHandlerLike>(handler: T, options?: WithOcAuthOptions): T;
23
+ interface ExpressRequestLike {
24
+ headers: {
25
+ cookie?: string;
26
+ authorization?: string;
27
+ [k: string]: unknown;
28
+ };
29
+ ocSession?: SessionPayload | null;
30
+ }
31
+ interface ExpressResponseLike {
32
+ status(code: number): ExpressResponseLike;
33
+ json(body: unknown): unknown;
34
+ setHeader(name: string, value: string | number | readonly string[]): unknown;
35
+ }
36
+ type ExpressNextLike = (err?: unknown) => void;
37
+ declare function ocAuthExpress(options?: WithOcAuthOptions): (req: ExpressRequestLike, res: ExpressResponseLike, next: ExpressNextLike) => Promise<void>;
38
+ interface HonoContextLike {
39
+ req: {
40
+ raw: {
41
+ headers: Headers;
42
+ };
43
+ };
44
+ set(key: string, value: unknown): void;
45
+ json(body: unknown, status?: number): unknown;
46
+ header(name: string, value: string): void;
47
+ }
48
+ type HonoNextLike = () => Promise<void>;
49
+ declare function ocAuthHono(options?: WithOcAuthOptions): (c: HonoContextLike, next: HonoNextLike) => Promise<unknown>;
50
+
51
+ export { type WithOcAuthOptions, getOcSession, ocAuthExpress, ocAuthHono, withOcAuth };