@orangecheck/me-client 0.32.2 → 0.32.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @orangecheck/me-client
2
2
 
3
- > **Full reference:** [docs.ochk.io/sdk/me-client](https://docs.ochk.io/sdk/me-client) — auto-generated from the TypeScript source on every release.
3
+ > **Full reference:** [ochk.io/docs/sdk/me-client](https://ochk.io/docs/sdk/me-client) — auto-generated from the TypeScript source on every release.
4
4
  > Hand-written prose below is the high-level overview; the docs site is the source of truth for every export, type, and signature.
5
5
 
6
6
 
@@ -153,7 +153,7 @@ const unsubscribe = onTelemetry((event) => {
153
153
  });
154
154
  ```
155
155
 
156
- See [me.ochk.io/integrate](https://me.ochk.io/integrate) for the full price-band table, the "what you do not pay for" panel, and the live SDK reference.
156
+ See [ochk.app/pricing](https://ochk.app/pricing) for what each kind of event pays and what you never pay for, and [ochk.io/docs/me/sdk](https://ochk.io/docs/me/sdk) for the full SDK reference.
157
157
 
158
158
  ## Types
159
159
 
@@ -170,7 +170,7 @@ import type {
170
170
  } from '@orangecheck/me-client';
171
171
  ```
172
172
 
173
- The canonical source of truth lives at [oc-me-web/src/lib/events/types.ts](https://github.com/orangecheck/oc-me-web/blob/main/src/lib/events/types.ts). This package mirrors that shape — any change there ships here in the next minor.
173
+ These mirror what the me.ochk.io API accepts and returns. A change to the API ships here in the next minor.
174
174
 
175
175
  ## Server-side verification
176
176
 
@@ -13,7 +13,7 @@ interface ActivityAttestation {
13
13
  expires_at: string;
14
14
  }
15
15
  interface ActivityAttestationBundle {
16
- attestation: ActivityAttestation;
16
+ attestation?: ActivityAttestation;
17
17
  sig: string;
18
18
  kid: string;
19
19
  canonical_b64: string;
@@ -13,7 +13,7 @@ interface ActivityAttestation {
13
13
  expires_at: string;
14
14
  }
15
15
  interface ActivityAttestationBundle {
16
- attestation: ActivityAttestation;
16
+ attestation?: ActivityAttestation;
17
17
  sig: string;
18
18
  kid: string;
19
19
  canonical_b64: string;
package/dist/index.d.mts CHANGED
@@ -1,5 +1,5 @@
1
- import { v as verifyActivityAttestation, r as refreshEnvelopeJwks } from './identity-1VYMOhzV.mjs';
2
- export { A as ActivityAttestation, a as ActivityAttestationBundle, b as ActivityVerifyCheck, c as ActivityVerifyResult, V as VerifyActivityOptions, i as identity } from './identity-1VYMOhzV.mjs';
1
+ import { v as verifyActivityAttestation, r as refreshEnvelopeJwks } from './identity-6pjtyKYh.mjs';
2
+ export { A as ActivityAttestation, a as ActivityAttestationBundle, b as ActivityVerifyCheck, c as ActivityVerifyResult, V as VerifyActivityOptions, i as identity } from './identity-6pjtyKYh.mjs';
3
3
  import { B as BillableEvent, E as EventKey, I as IntegratorPriceConfig, T as TelemetryEvent, S as SignInOptions, a as Session, P as PaymentAuthorizeOptions, b as PaymentResult, V as ValidationResult, f as fromTemplate, g as getArchetypeTemplate, A as ArchetypeTemplate, F as Federation } from './integrator-C-enR55c.mjs';
4
4
  export { c as ALL_EVENT_SUBTYPES, d as ARCHETYPE_TEMPLATES, e as AgentClassOverride, h as AttestTier, C as ClassASubtype, i as ClassBSubtype, j as ClassCSubtype, k as ComputedFees, D as DropCadence, l as DropClosedWebhookPayload, m as DropResponseBlock, n as DropScheduleSummary, o as EVENT_SUBTYPES, p as EventClass, q as EventSubtype, r as EventSubtypeMetadata, s as FederationStatus, t as IntegratorArchetype, u as IntegratorEventConfig, M as MAX_DROP_WINDOW_DAYS, v as MIN_INTEGRATOR_PRICE_SATS, w as PLATFORM_FEE_POLICY, x as SessionPolicy, y as SigningMethod, z as SiteFeeShape, G as SystemWebhookPayload, W as WebhookHeaders, H as WebhookPayload, J as computeFees, K as subtypesForClass, L as validateIntegratorConfig } from './integrator-C-enR55c.mjs';
5
5
 
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { v as verifyActivityAttestation, r as refreshEnvelopeJwks } from './identity-1VYMOhzV.js';
2
- export { A as ActivityAttestation, a as ActivityAttestationBundle, b as ActivityVerifyCheck, c as ActivityVerifyResult, V as VerifyActivityOptions, i as identity } from './identity-1VYMOhzV.js';
1
+ import { v as verifyActivityAttestation, r as refreshEnvelopeJwks } from './identity-6pjtyKYh.js';
2
+ export { A as ActivityAttestation, a as ActivityAttestationBundle, b as ActivityVerifyCheck, c as ActivityVerifyResult, V as VerifyActivityOptions, i as identity } from './identity-6pjtyKYh.js';
3
3
  import { B as BillableEvent, E as EventKey, I as IntegratorPriceConfig, T as TelemetryEvent, S as SignInOptions, a as Session, P as PaymentAuthorizeOptions, b as PaymentResult, V as ValidationResult, f as fromTemplate, g as getArchetypeTemplate, A as ArchetypeTemplate, F as Federation } from './integrator-C-enR55c.js';
4
4
  export { c as ALL_EVENT_SUBTYPES, d as ARCHETYPE_TEMPLATES, e as AgentClassOverride, h as AttestTier, C as ClassASubtype, i as ClassBSubtype, j as ClassCSubtype, k as ComputedFees, D as DropCadence, l as DropClosedWebhookPayload, m as DropResponseBlock, n as DropScheduleSummary, o as EVENT_SUBTYPES, p as EventClass, q as EventSubtype, r as EventSubtypeMetadata, s as FederationStatus, t as IntegratorArchetype, u as IntegratorEventConfig, M as MAX_DROP_WINDOW_DAYS, v as MIN_INTEGRATOR_PRICE_SATS, w as PLATFORM_FEE_POLICY, x as SessionPolicy, y as SigningMethod, z as SiteFeeShape, G as SystemWebhookPayload, W as WebhookHeaders, H as WebhookPayload, J as computeFees, K as subtypesForClass, L as validateIntegratorConfig } from './integrator-C-enR55c.js';
5
5
 
package/dist/index.js CHANGED
@@ -1037,6 +1037,7 @@ async function defaultLive() {
1037
1037
  var federations = { list, live, get, defaultLive };
1038
1038
 
1039
1039
  // src/scope.ts
1040
+ var CONSENT_ORIGIN = "https://ochk.app";
1040
1041
  var VALID_SCOPES = [
1041
1042
  "bitcoin_address",
1042
1043
  "email",
@@ -1092,7 +1093,7 @@ function request(scopes2, options) {
1092
1093
  if (typeof window === "undefined") {
1093
1094
  throw new Error("oc.scope.request: must be called in a browser environment");
1094
1095
  }
1095
- const origin2 = options.origin ?? getOrigin();
1096
+ const origin2 = options.origin ?? CONSENT_ORIGIN;
1096
1097
  const url = new URL("/me/scope-grant", origin2);
1097
1098
  url.searchParams.set("project_key", options.project_key);
1098
1099
  url.searchParams.set("scopes", scopes2.join(","));
@@ -1234,33 +1235,85 @@ async function verifyEd255192(key, sig, msg) {
1234
1235
  return false;
1235
1236
  }
1236
1237
  }
1238
+ var SIGNED_FIELDS = [
1239
+ "v",
1240
+ "kind",
1241
+ "did_oc",
1242
+ "event_count",
1243
+ "human_event_count",
1244
+ "lifetime_sats",
1245
+ "distinct_integrator_count",
1246
+ "oldest_event_at",
1247
+ "active_days",
1248
+ "computed_at",
1249
+ "expires_at"
1250
+ ];
1251
+ var COUNTS = [
1252
+ "event_count",
1253
+ "human_event_count",
1254
+ "lifetime_sats",
1255
+ "distinct_integrator_count",
1256
+ "active_days"
1257
+ ];
1258
+ function readSignedAttestation(canonical, id) {
1259
+ const text = new TextDecoder().decode(canonical);
1260
+ let parsed;
1261
+ try {
1262
+ parsed = JSON.parse(text);
1263
+ } catch {
1264
+ return null;
1265
+ }
1266
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return null;
1267
+ const o = parsed;
1268
+ if (o.v !== 1 || o.kind !== "oc-me-activity" || typeof o.did_oc !== "string") return null;
1269
+ const countsOk = COUNTS.every((k) => {
1270
+ const n = o[k];
1271
+ return typeof n === "number" && Number.isSafeInteger(n) && n >= 0;
1272
+ });
1273
+ if (!countsOk) return null;
1274
+ if (o.oldest_event_at !== null && typeof o.oldest_event_at !== "string") return null;
1275
+ if (typeof o.computed_at !== "string" || typeof o.expires_at !== "string") return null;
1276
+ const ordered = Object.fromEntries(SIGNED_FIELDS.map((k) => [k, o[k]]));
1277
+ if (JSON.stringify(ordered) !== text) return null;
1278
+ return { id, ...ordered };
1279
+ }
1280
+ function sameAttestation(copy, signed) {
1281
+ const c = copy;
1282
+ const v = signed;
1283
+ return ["id", ...SIGNED_FIELDS].every((k) => c[k] === v[k]);
1284
+ }
1237
1285
  async function verifyActivityAttestation(bundle, options = {}) {
1238
1286
  const checks = [];
1239
- const shapeOk = !!bundle && typeof bundle === "object" && typeof bundle.sig === "string" && typeof bundle.kid === "string" && typeof bundle.canonical_b64 === "string" && !!bundle.attestation && typeof bundle.attestation.id === "string" && typeof bundle.attestation.expires_at === "string";
1287
+ const shapeOk = !!bundle && typeof bundle === "object" && typeof bundle.sig === "string" && typeof bundle.kid === "string" && typeof bundle.canonical_b64 === "string" && (bundle.attestation === void 0 || !!bundle.attestation && typeof bundle.attestation === "object");
1240
1288
  checks.push({
1241
1289
  ok: shapeOk,
1242
- label: "bundle shape \xB7 sig / kid / canonical_b64 / attestation"
1290
+ label: "bundle shape \xB7 sig / kid / canonical_b64"
1243
1291
  });
1244
1292
  if (!shapeOk) {
1245
1293
  return { ok: false, reason: "bundle shape invalid", checks };
1246
1294
  }
1247
- const a = bundle.attestation;
1248
1295
  const canonical = base64ToBytes(bundle.canonical_b64);
1249
1296
  checks.push({
1250
1297
  ok: canonical !== null,
1251
1298
  label: "canonical_b64 decodes",
1252
1299
  detail: canonical ? `${canonical.length} bytes` : "invalid base64"
1253
1300
  });
1254
- if (!canonical) return { ok: false, reason: "canonical_b64 invalid base64", checks, attestation: a };
1255
- const digest = await sha256(canonical);
1256
- const computedId = bytesToHex(digest);
1257
- const idOk = computedId === a.id;
1301
+ if (!canonical) return { ok: false, reason: "canonical_b64 invalid base64", checks };
1302
+ const computedId = bytesToHex(await sha256(canonical));
1303
+ const signed = readSignedAttestation(canonical, computedId);
1304
+ checks.push({
1305
+ ok: signed !== null,
1306
+ label: "canonical_bytes are an oc-me-activity attestation in canonical form"
1307
+ });
1308
+ if (!signed) return { ok: false, reason: "canonical bytes are not an activity attestation", checks };
1309
+ const copy = bundle.attestation;
1310
+ const copyOk = copy === void 0 || sameAttestation(copy, signed);
1258
1311
  checks.push({
1259
- ok: idOk,
1260
- label: "sha256(canonical_bytes) === id",
1261
- detail: idOk ? a.id : `expected ${a.id}, got ${computedId}`
1312
+ ok: copyOk,
1313
+ label: "attestation === the signed bytes, id = sha256(canonical_bytes)",
1314
+ detail: copyOk ? computedId : "the readable copy differs from what was signed"
1262
1315
  });
1263
- if (!idOk) return { ok: false, reason: "id does not match canonical-bytes hash", checks, attestation: a };
1316
+ if (!copyOk) return { ok: false, reason: "attestation does not match the signed bytes", checks };
1264
1317
  let key = null;
1265
1318
  if (options.jwk) {
1266
1319
  if (options.jwk.kid !== bundle.kid) {
@@ -1269,7 +1322,7 @@ async function verifyActivityAttestation(bundle, options = {}) {
1269
1322
  label: "JWK with matching kid present",
1270
1323
  detail: `provided jwk.kid=${options.jwk.kid} but bundle.kid=${bundle.kid}`
1271
1324
  });
1272
- return { ok: false, reason: "kid mismatch with provided jwk", checks, attestation: a };
1325
+ return { ok: false, reason: "kid mismatch with provided jwk", checks };
1273
1326
  }
1274
1327
  try {
1275
1328
  key = await importJWK(options.jwk, "EdDSA");
@@ -1280,7 +1333,7 @@ async function verifyActivityAttestation(bundle, options = {}) {
1280
1333
  label: "JWK with matching kid present",
1281
1334
  detail: `provided jwk failed import: ${err.message}`
1282
1335
  });
1283
- return { ok: false, reason: "provided jwk failed import", checks, attestation: a };
1336
+ return { ok: false, reason: "provided jwk failed import", checks };
1284
1337
  }
1285
1338
  } else {
1286
1339
  const issuer = options.issuer ?? DEFAULT_ISSUER2;
@@ -1299,7 +1352,7 @@ async function verifyActivityAttestation(bundle, options = {}) {
1299
1352
  detail: key ? `kid ${bundle.kid}` : `no JWK with kid ${bundle.kid} at ${issuer}${ENVELOPE_JWKS_PATH}`
1300
1353
  });
1301
1354
  if (!key) {
1302
- return { ok: false, reason: `kid ${bundle.kid} not in envelope JWKS`, checks, attestation: a };
1355
+ return { ok: false, reason: `kid ${bundle.kid} not in envelope JWKS`, checks };
1303
1356
  }
1304
1357
  } catch (err) {
1305
1358
  checks.push({
@@ -1310,8 +1363,7 @@ async function verifyActivityAttestation(bundle, options = {}) {
1310
1363
  return {
1311
1364
  ok: false,
1312
1365
  reason: `envelope JWKS unavailable: ${err.message}`,
1313
- checks,
1314
- attestation: a
1366
+ checks
1315
1367
  };
1316
1368
  }
1317
1369
  }
@@ -1322,7 +1374,7 @@ async function verifyActivityAttestation(bundle, options = {}) {
1322
1374
  label: "ed25519.verify(sig, canonical_bytes, jwk.public)",
1323
1375
  detail: "malformed sig (expected hex)"
1324
1376
  });
1325
- return { ok: false, reason: "malformed sig", checks, attestation: a };
1377
+ return { ok: false, reason: "malformed sig", checks };
1326
1378
  }
1327
1379
  const sigOk = await verifyEd255192(key, sigBytes, canonical);
1328
1380
  checks.push({
@@ -1330,17 +1382,17 @@ async function verifyActivityAttestation(bundle, options = {}) {
1330
1382
  label: "ed25519.verify(sig, canonical_bytes, jwk.public)",
1331
1383
  detail: sigOk ? "signature valid" : "signature does not match"
1332
1384
  });
1333
- if (!sigOk) return { ok: false, reason: "signature does not match", checks, attestation: a };
1385
+ if (!sigOk) return { ok: false, reason: "signature does not match", checks };
1334
1386
  const now = options.now ?? /* @__PURE__ */ new Date();
1335
- const expiresMs = Date.parse(a.expires_at);
1387
+ const expiresMs = Date.parse(signed.expires_at);
1336
1388
  const freshOk = Number.isFinite(expiresMs) && expiresMs > now.getTime();
1337
1389
  checks.push({
1338
1390
  ok: freshOk,
1339
1391
  label: "now < attestation.expires_at",
1340
1392
  detail: freshOk ? `expires ${new Date(expiresMs).toISOString()}` : "attestation has expired"
1341
1393
  });
1342
- if (!freshOk) return { ok: false, reason: "attestation has expired", checks, attestation: a };
1343
- return { ok: true, attestation: a, checks };
1394
+ if (!freshOk) return { ok: false, reason: "attestation has expired", checks };
1395
+ return { ok: true, attestation: signed, checks };
1344
1396
  }
1345
1397
  async function refreshEnvelopeJwks(issuer = DEFAULT_ISSUER2) {
1346
1398
  jwksCache2.delete(issuer);