@orangecheck/me-client 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +9 -1
- package/dist/index.d.ts +9 -1
- package/dist/index.js +38 -3
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +38 -4
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -39,6 +39,14 @@ interface ComputedFees {
|
|
|
39
39
|
site_rebate_sats: number;
|
|
40
40
|
}
|
|
41
41
|
declare function computeFees(cfg: IntegratorEventConfig, payment_amount_sats?: number): ComputedFees;
|
|
42
|
+
interface ValidationResult {
|
|
43
|
+
ok: boolean;
|
|
44
|
+
errors: {
|
|
45
|
+
subtype?: EventSubtype;
|
|
46
|
+
message: string;
|
|
47
|
+
}[];
|
|
48
|
+
}
|
|
49
|
+
declare function validateIntegratorConfig(cfg: IntegratorPriceConfig): ValidationResult;
|
|
42
50
|
interface BillableEvent {
|
|
43
51
|
id: string;
|
|
44
52
|
occurred_at: string;
|
|
@@ -135,4 +143,4 @@ declare const oc: {
|
|
|
135
143
|
};
|
|
136
144
|
};
|
|
137
145
|
|
|
138
|
-
export { type AttestTier, type BillableEvent, type ClassASubtype, type ClassBSubtype, type ClassCSubtype, type ComputedFees, type EventClass, type EventSubtype, type IntegratorEventConfig, type IntegratorPriceConfig, MIN_INTEGRATOR_PRICE_SATS, MeClientError, OcSignInButton, type OcSignInButtonProps, PLATFORM_FEE_POLICY, type PaymentAuthorizeOptions, type PaymentResult, type Session, type SessionPolicy, type SignInOptions, type SiteFeeShape, type TelemetryEvent, computeFees, getOrigin, oc, onTelemetry, payment, session, setOrigin };
|
|
146
|
+
export { type AttestTier, type BillableEvent, type ClassASubtype, type ClassBSubtype, type ClassCSubtype, type ComputedFees, type EventClass, type EventSubtype, type IntegratorEventConfig, type IntegratorPriceConfig, MIN_INTEGRATOR_PRICE_SATS, MeClientError, OcSignInButton, type OcSignInButtonProps, PLATFORM_FEE_POLICY, type PaymentAuthorizeOptions, type PaymentResult, type Session, type SessionPolicy, type SignInOptions, type SiteFeeShape, type TelemetryEvent, type ValidationResult, computeFees, getOrigin, oc, onTelemetry, payment, session, setOrigin, validateIntegratorConfig };
|
package/dist/index.d.ts
CHANGED
|
@@ -39,6 +39,14 @@ interface ComputedFees {
|
|
|
39
39
|
site_rebate_sats: number;
|
|
40
40
|
}
|
|
41
41
|
declare function computeFees(cfg: IntegratorEventConfig, payment_amount_sats?: number): ComputedFees;
|
|
42
|
+
interface ValidationResult {
|
|
43
|
+
ok: boolean;
|
|
44
|
+
errors: {
|
|
45
|
+
subtype?: EventSubtype;
|
|
46
|
+
message: string;
|
|
47
|
+
}[];
|
|
48
|
+
}
|
|
49
|
+
declare function validateIntegratorConfig(cfg: IntegratorPriceConfig): ValidationResult;
|
|
42
50
|
interface BillableEvent {
|
|
43
51
|
id: string;
|
|
44
52
|
occurred_at: string;
|
|
@@ -135,4 +143,4 @@ declare const oc: {
|
|
|
135
143
|
};
|
|
136
144
|
};
|
|
137
145
|
|
|
138
|
-
export { type AttestTier, type BillableEvent, type ClassASubtype, type ClassBSubtype, type ClassCSubtype, type ComputedFees, type EventClass, type EventSubtype, type IntegratorEventConfig, type IntegratorPriceConfig, MIN_INTEGRATOR_PRICE_SATS, MeClientError, OcSignInButton, type OcSignInButtonProps, PLATFORM_FEE_POLICY, type PaymentAuthorizeOptions, type PaymentResult, type Session, type SessionPolicy, type SignInOptions, type SiteFeeShape, type TelemetryEvent, computeFees, getOrigin, oc, onTelemetry, payment, session, setOrigin };
|
|
146
|
+
export { type AttestTier, type BillableEvent, type ClassASubtype, type ClassBSubtype, type ClassCSubtype, type ComputedFees, type EventClass, type EventSubtype, type IntegratorEventConfig, type IntegratorPriceConfig, MIN_INTEGRATOR_PRICE_SATS, MeClientError, OcSignInButton, type OcSignInButtonProps, PLATFORM_FEE_POLICY, type PaymentAuthorizeOptions, type PaymentResult, type Session, type SessionPolicy, type SignInOptions, type SiteFeeShape, type TelemetryEvent, type ValidationResult, computeFees, getOrigin, oc, onTelemetry, payment, session, setOrigin, validateIntegratorConfig };
|
package/dist/index.js
CHANGED
|
@@ -222,12 +222,46 @@ function computeFees(cfg, payment_amount_sats) {
|
|
|
222
222
|
PLATFORM_FEE_POLICY.min_floor_sats,
|
|
223
223
|
Math.round(gross * PLATFORM_FEE_POLICY.pct)
|
|
224
224
|
);
|
|
225
|
-
const post_platform = Math.max(0, gross - platform_fee_sats);
|
|
226
225
|
const user_share = Math.min(0.8, Math.max(0, cfg.user_share_pct));
|
|
227
|
-
const user_earned_sats = Math.round(
|
|
228
|
-
const site_rebate_sats = Math.max(0,
|
|
226
|
+
const user_earned_sats = Math.round(gross * user_share);
|
|
227
|
+
const site_rebate_sats = Math.max(0, gross - platform_fee_sats - user_earned_sats);
|
|
229
228
|
return { gross_fee_sats: gross, platform_fee_sats, user_earned_sats, site_rebate_sats };
|
|
230
229
|
}
|
|
230
|
+
function validateIntegratorConfig(cfg) {
|
|
231
|
+
const errors = [];
|
|
232
|
+
if (!cfg.project_key) errors.push({ message: "project_key is required" });
|
|
233
|
+
if (!cfg.display_name) errors.push({ message: "display_name is required" });
|
|
234
|
+
if (!cfg.domain) errors.push({ message: "domain is required" });
|
|
235
|
+
for (const [key, eventCfg] of Object.entries(cfg.events)) {
|
|
236
|
+
if (!eventCfg) continue;
|
|
237
|
+
const subtype = key;
|
|
238
|
+
if (!eventCfg.enabled) continue;
|
|
239
|
+
if (eventCfg.site_pays.kind === "fixed_sats") {
|
|
240
|
+
if (eventCfg.site_pays.sats < MIN_INTEGRATOR_PRICE_SATS) {
|
|
241
|
+
errors.push({
|
|
242
|
+
subtype,
|
|
243
|
+
message: `site_pays.sats (${eventCfg.site_pays.sats}) is below MIN_INTEGRATOR_PRICE_SATS (${MIN_INTEGRATOR_PRICE_SATS})`
|
|
244
|
+
});
|
|
245
|
+
}
|
|
246
|
+
} else {
|
|
247
|
+
const pct = eventCfg.site_pays.pct;
|
|
248
|
+
if (!(pct > 0 && pct <= 1)) {
|
|
249
|
+
errors.push({
|
|
250
|
+
subtype,
|
|
251
|
+
message: `site_pays.pct (${pct}) must be in (0, 1]`
|
|
252
|
+
});
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
const u = eventCfg.user_share_pct;
|
|
256
|
+
if (u < 0 || u > 0.8) {
|
|
257
|
+
errors.push({
|
|
258
|
+
subtype,
|
|
259
|
+
message: `user_share_pct (${u}) must be in [0, 0.8]; max is 0.8 because platform_fee is ${PLATFORM_FEE_POLICY.pct}`
|
|
260
|
+
});
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
return { ok: errors.length === 0, errors };
|
|
264
|
+
}
|
|
231
265
|
|
|
232
266
|
// src/index.ts
|
|
233
267
|
var oc = { session, payment };
|
|
@@ -243,5 +277,6 @@ exports.onTelemetry = onTelemetry;
|
|
|
243
277
|
exports.payment = payment;
|
|
244
278
|
exports.session = session;
|
|
245
279
|
exports.setOrigin = setOrigin;
|
|
280
|
+
exports.validateIntegratorConfig = validateIntegratorConfig;
|
|
246
281
|
//# sourceMappingURL=index.js.map
|
|
247
282
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/transport.ts","../src/session.ts","../src/SignInButton.tsx","../src/payment.ts","../src/types.ts","../src/index.ts"],"names":["React","jsxs","jsx"],"mappings":"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","file":"index.js","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. Mirrors the canonical computeFees in oc-me-web. */\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 post_platform = Math.max(0, gross - platform_fee_sats);\n const user_share = Math.min(0.8, Math.max(0, cfg.user_share_pct));\n const user_earned_sats = Math.round(post_platform * (user_share / 0.8));\n const site_rebate_sats = Math.max(0, post_platform - user_earned_sats);\n return { gross_fee_sats: gross, platform_fee_sats, user_earned_sats, site_rebate_sats };\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. Exports the canonical billable-event\n * taxonomy as TypeScript types, session lifecycle hooks, payment\n * authorization, the developer telemetry stream, and the React sign-in\n * button.\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\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} 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 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"]}
|
|
1
|
+
{"version":3,"sources":["../src/transport.ts","../src/session.ts","../src/SignInButton.tsx","../src/payment.ts","../src/types.ts","../src/index.ts"],"names":["React","jsxs","jsx"],"mappings":"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","file":"index.js","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","/**\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, the developer telemetry stream, and the React sign-in\n * button.\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\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"]}
|
package/dist/index.mjs
CHANGED
|
@@ -200,16 +200,50 @@ function computeFees(cfg, payment_amount_sats) {
|
|
|
200
200
|
PLATFORM_FEE_POLICY.min_floor_sats,
|
|
201
201
|
Math.round(gross * PLATFORM_FEE_POLICY.pct)
|
|
202
202
|
);
|
|
203
|
-
const post_platform = Math.max(0, gross - platform_fee_sats);
|
|
204
203
|
const user_share = Math.min(0.8, Math.max(0, cfg.user_share_pct));
|
|
205
|
-
const user_earned_sats = Math.round(
|
|
206
|
-
const site_rebate_sats = Math.max(0,
|
|
204
|
+
const user_earned_sats = Math.round(gross * user_share);
|
|
205
|
+
const site_rebate_sats = Math.max(0, gross - platform_fee_sats - user_earned_sats);
|
|
207
206
|
return { gross_fee_sats: gross, platform_fee_sats, user_earned_sats, site_rebate_sats };
|
|
208
207
|
}
|
|
208
|
+
function validateIntegratorConfig(cfg) {
|
|
209
|
+
const errors = [];
|
|
210
|
+
if (!cfg.project_key) errors.push({ message: "project_key is required" });
|
|
211
|
+
if (!cfg.display_name) errors.push({ message: "display_name is required" });
|
|
212
|
+
if (!cfg.domain) errors.push({ message: "domain is required" });
|
|
213
|
+
for (const [key, eventCfg] of Object.entries(cfg.events)) {
|
|
214
|
+
if (!eventCfg) continue;
|
|
215
|
+
const subtype = key;
|
|
216
|
+
if (!eventCfg.enabled) continue;
|
|
217
|
+
if (eventCfg.site_pays.kind === "fixed_sats") {
|
|
218
|
+
if (eventCfg.site_pays.sats < MIN_INTEGRATOR_PRICE_SATS) {
|
|
219
|
+
errors.push({
|
|
220
|
+
subtype,
|
|
221
|
+
message: `site_pays.sats (${eventCfg.site_pays.sats}) is below MIN_INTEGRATOR_PRICE_SATS (${MIN_INTEGRATOR_PRICE_SATS})`
|
|
222
|
+
});
|
|
223
|
+
}
|
|
224
|
+
} else {
|
|
225
|
+
const pct = eventCfg.site_pays.pct;
|
|
226
|
+
if (!(pct > 0 && pct <= 1)) {
|
|
227
|
+
errors.push({
|
|
228
|
+
subtype,
|
|
229
|
+
message: `site_pays.pct (${pct}) must be in (0, 1]`
|
|
230
|
+
});
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
const u = eventCfg.user_share_pct;
|
|
234
|
+
if (u < 0 || u > 0.8) {
|
|
235
|
+
errors.push({
|
|
236
|
+
subtype,
|
|
237
|
+
message: `user_share_pct (${u}) must be in [0, 0.8]; max is 0.8 because platform_fee is ${PLATFORM_FEE_POLICY.pct}`
|
|
238
|
+
});
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
return { ok: errors.length === 0, errors };
|
|
242
|
+
}
|
|
209
243
|
|
|
210
244
|
// src/index.ts
|
|
211
245
|
var oc = { session, payment };
|
|
212
246
|
|
|
213
|
-
export { MIN_INTEGRATOR_PRICE_SATS, MeClientError, OcSignInButton, PLATFORM_FEE_POLICY, computeFees, getOrigin, oc, onTelemetry, payment, session, setOrigin };
|
|
247
|
+
export { MIN_INTEGRATOR_PRICE_SATS, MeClientError, OcSignInButton, PLATFORM_FEE_POLICY, computeFees, getOrigin, oc, onTelemetry, payment, session, setOrigin, validateIntegratorConfig };
|
|
214
248
|
//# sourceMappingURL=index.mjs.map
|
|
215
249
|
//# sourceMappingURL=index.mjs.map
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
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 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. Mirrors the canonical computeFees in oc-me-web. */\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 post_platform = Math.max(0, gross - platform_fee_sats);\n const user_share = Math.min(0.8, Math.max(0, cfg.user_share_pct));\n const user_earned_sats = Math.round(post_platform * (user_share / 0.8));\n const site_rebate_sats = Math.max(0, post_platform - user_earned_sats);\n return { gross_fee_sats: gross, platform_fee_sats, user_earned_sats, site_rebate_sats };\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. Exports the canonical billable-event\n * taxonomy as TypeScript types, session lifecycle hooks, payment\n * authorization, the developer telemetry stream, and the React sign-in\n * button.\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\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} 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 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"]}
|
|
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 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","/**\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, the developer telemetry stream, and the React sign-in\n * button.\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\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"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@orangecheck/me-client",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Drop-in client for me.ochk.io. Sign-in-with-OC button, session lifecycle hooks (oc.session.create / refresh / invalidate), payment authorization, and the canonical billable-event taxonomy as types.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"orangecheck",
|