@orangecheck/sdk 1.17.1 → 1.18.1

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.
Files changed (45) hide show
  1. package/dist/attestation.d.mts +1 -1
  2. package/dist/attestation.d.ts +1 -1
  3. package/dist/attestation.js +8 -2
  4. package/dist/attestation.js.map +1 -1
  5. package/dist/attestation.mjs +8 -2
  6. package/dist/attestation.mjs.map +1 -1
  7. package/dist/canonical.d.mts +3 -2
  8. package/dist/canonical.d.ts +3 -2
  9. package/dist/canonical.js +9 -0
  10. package/dist/canonical.js.map +1 -1
  11. package/dist/canonical.mjs +9 -1
  12. package/dist/canonical.mjs.map +1 -1
  13. package/dist/challenge.d.mts +1 -1
  14. package/dist/challenge.d.ts +1 -1
  15. package/dist/challenge.js +29 -0
  16. package/dist/challenge.js.map +1 -1
  17. package/dist/challenge.mjs +29 -0
  18. package/dist/challenge.mjs.map +1 -1
  19. package/dist/identity.d.mts +1 -1
  20. package/dist/identity.d.ts +1 -1
  21. package/dist/index.d.mts +3 -3
  22. package/dist/index.d.ts +3 -3
  23. package/dist/index.js +48 -2
  24. package/dist/index.js.map +1 -1
  25. package/dist/index.mjs +48 -3
  26. package/dist/index.mjs.map +1 -1
  27. package/dist/nostr.d.mts +1 -1
  28. package/dist/nostr.d.ts +1 -1
  29. package/dist/nostr.js +8 -2
  30. package/dist/nostr.js.map +1 -1
  31. package/dist/nostr.mjs +8 -2
  32. package/dist/nostr.mjs.map +1 -1
  33. package/dist/scoring.js +22 -0
  34. package/dist/scoring.js.map +1 -1
  35. package/dist/scoring.mjs +22 -0
  36. package/dist/scoring.mjs.map +1 -1
  37. package/dist/{types-DsrYs3EB.d.mts → types-BdJoNWgs.d.mts} +1 -1
  38. package/dist/{types-DsrYs3EB.d.ts → types-BdJoNWgs.d.ts} +1 -1
  39. package/dist/verify.d.mts +2 -1
  40. package/dist/verify.d.ts +2 -1
  41. package/dist/verify.js +27 -2
  42. package/dist/verify.js.map +1 -1
  43. package/dist/verify.mjs +27 -2
  44. package/dist/verify.mjs.map +1 -1
  45. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -70,6 +70,11 @@ function parseIdentities(identitiesStr) {
70
70
  }
71
71
  return bindings;
72
72
  }
73
+ function readBondExtension(value) {
74
+ if (!/^[0-9]+$/.test(value)) return null;
75
+ const n = Number(value);
76
+ return Number.isSafeInteger(n) ? n : null;
77
+ }
73
78
  function buildCanonicalMessage({ address, identities }, extensions = {}, options = {}) {
74
79
  const nonce = options.nonce ?? randomNonce16BHexLower();
75
80
  if (!/^[0-9a-f]{32}$/.test(nonce)) {
@@ -92,6 +97,9 @@ function buildCanonicalMessage({ address, identities }, extensions = {}, options
92
97
  continue;
93
98
  }
94
99
  const key = k.toLowerCase();
100
+ if (key === "bond" && readBondExtension(String(v)) === null) {
101
+ throw new Error(`invalid bond: ${String(v)} is not a whole number of sats up to 2^53 - 1`);
102
+ }
95
103
  normExt[key] = String(v);
96
104
  }
97
105
  const extLines = Object.keys(normExt).sort().map((k) => `${k}: ${normExt[k]}`);
@@ -257,6 +265,10 @@ function refuseUnknown(where, opts, known) {
257
265
  `@orangecheck/sdk: ${where}: unknown option ${unknown.join(", ")}. It reads only ${[...known].join(", ")}.`
258
266
  );
259
267
  }
268
+ const inherited = [...known].filter((k) => k in opts && !Object.prototype.hasOwnProperty.call(opts, k));
269
+ if (inherited.length > 0) {
270
+ throw new TypeError(`@orangecheck/sdk: ${where}: option ${inherited.join(", ")} is inherited, not set by the caller`);
271
+ }
260
272
  }
261
273
  function checkCheckParams(params) {
262
274
  refuseUnknown("check()", params, CHECK_OPTIONS);
@@ -265,6 +277,21 @@ function checkCheckParams(params) {
265
277
  function checkVerifyOptions(opts, where = "verify()") {
266
278
  refuseUnknown(where, opts, VERIFY_OPTIONS);
267
279
  }
280
+ var CHALLENGE_OPTIONS = /* @__PURE__ */ new Set([
281
+ "address",
282
+ "ttlSeconds",
283
+ "nonce",
284
+ "audience",
285
+ "purpose",
286
+ "now"
287
+ ]);
288
+ function checkChallengeOptions(opts) {
289
+ refuseUnknown("issueChallenge()", opts, CHALLENGE_OPTIONS);
290
+ }
291
+ var SCORING_OPTIONS = /* @__PURE__ */ new Set(["algorithm"]);
292
+ function checkScoringConfig(config) {
293
+ refuseUnknown("computeScore()", config, SCORING_OPTIONS);
294
+ }
268
295
 
269
296
  // src/scoring.ts
270
297
  function scoreV0(sats, days) {
@@ -279,6 +306,7 @@ function scoreTier(sats, days) {
279
306
  return "none";
280
307
  }
281
308
  function computeScore(sats, days, config) {
309
+ checkScoringConfig(config);
282
310
  switch (config.algorithm) {
283
311
  case "v0":
284
312
  return scoreV0(sats, days);
@@ -358,14 +386,15 @@ function parseCanonicalMessage(msg) {
358
386
  }
359
387
  const network = extensions["network"] || "mainnet";
360
388
  const bondStr = extensions["bond"];
361
- const bond = bondStr ? parseInt(bondStr, 10) : void 0;
389
+ const bond = bondStr ? readBondExtension(bondStr) : void 0;
362
390
  return {
363
391
  core: { address, identities, issued_at },
364
392
  expires,
365
393
  repeated,
366
394
  network,
367
395
  extensions,
368
- bond: bond !== void 0 && !isNaN(bond) && bond > 0 ? bond : void 0
396
+ bond: bond !== void 0 && bond !== null && bond > 0 ? bond : void 0,
397
+ bondMalformed: bond === null
369
398
  };
370
399
  }
371
400
  async function getAddressUtxos(address, network, opts) {
@@ -534,6 +563,16 @@ async function verify(input, opts = {}) {
534
563
  identities: parsed.core.identities
535
564
  };
536
565
  }
566
+ if (parsed.bondMalformed) {
567
+ codes.push("bond_malformed");
568
+ return {
569
+ ok: false,
570
+ codes,
571
+ network,
572
+ attestation_id,
573
+ identities: parsed.core.identities
574
+ };
575
+ }
537
576
  try {
538
577
  const utxos = await getAddressUtxos(input.addr, network, {
539
578
  esploraMainnetBase: opts.esploraMainnetBase,
@@ -1276,6 +1315,7 @@ function iso(date) {
1276
1315
  return date.toISOString().replace(/\.\d{3}Z$/, "Z");
1277
1316
  }
1278
1317
  function issueChallenge(opts) {
1318
+ checkChallengeOptions(opts);
1279
1319
  const now = opts.now ?? /* @__PURE__ */ new Date();
1280
1320
  const ttl = opts.ttlSeconds ?? 300;
1281
1321
  const expiresAt = new Date(now.getTime() + ttl * 1e3);
@@ -2318,6 +2358,11 @@ var STATUS_META = {
2318
2358
  detail: "The confirmed balance is less than the declared bond amount. The bond extension requires the address to hold at least the specified amount in confirmed UTXOs.",
2319
2359
  severity: "error"
2320
2360
  },
2361
+ bond_malformed: {
2362
+ label: "Bond amount not readable",
2363
+ detail: "The signed bond line is not a whole number of sats written in plain digits, so the attestation does not say how much it bonds.",
2364
+ severity: "error"
2365
+ },
2321
2366
  aud_mismatch: {
2322
2367
  label: "Audience mismatch",
2323
2368
  detail: "The message was signed for a different audience than expected. This may be intentional or indicate the signature is being used in the wrong context.",
@@ -2423,6 +2468,7 @@ exports.queryByAddress = queryByAddress;
2423
2468
  exports.queryByAttestationId = queryByAttestationId;
2424
2469
  exports.queryByIdentity = queryByIdentity;
2425
2470
  exports.queryRecent = queryRecent;
2471
+ exports.readBondExtension = readBondExtension;
2426
2472
  exports.requiresManualVerification = requiresManualVerification;
2427
2473
  exports.signNostrEvent = signNostrEvent;
2428
2474
  exports.signatureIsValid = signatureIsValid;