@prampta/sdk 0.11.0 → 0.11.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.
package/README.md CHANGED
@@ -40,8 +40,9 @@ exists solely so an already-connected provider keeps working mid-migration.
40
40
 
41
41
  `createPregen` speaks the simplified PRE-GEN v5 formats at `/v2`: signed
42
42
  answers bound to your request, signed reports, signed acknowledgements. Set it
43
- up once; wrap each generation in one call. Use 0.11.0 or later: 0.10.0 had
44
- defects found by an external review (see CHANGELOG).
43
+ up once; wrap each generation in one call. Use 0.11.1 or later: 0.10.0 and
44
+ 0.11.0 had defects found by external reviews (see CHANGELOG). A complete
45
+ program you can run as it stands: https://prampta.com/get-started-v2.md.
45
46
 
46
47
  ```typescript
47
48
  import pg from "pg";
@@ -52,7 +53,8 @@ const pregen = createPregen({
52
53
  providerId: "my-ai",
53
54
  token: process.env.PRAMPTA_TOKEN!, // your exchange_secret, server-side only
54
55
  providerSigningKeyHex: process.env.PREGEN_SIGNING_KEY!, // your Ed25519 private key (32 bytes hex): signs your reports
55
- pregenDirectory: await loadPregenDirectory({ previous: saved }), // PRAMPTA's keys, namespaces, revocations
56
+ pregenDirectory: await loadPregenDirectory({ previous: lastAccepted }), // PRAMPTA's keys, namespaces, revocations;
57
+ // lastAccepted: the directory you saved last time (toJSON()), or undefined
56
58
  store: postgresStore(new pg.Pool()), // shared by all your workers; table pregen_jobs
57
59
  });
58
60
 
package/dist/index.js CHANGED
@@ -494,11 +494,15 @@ async function verifyEnvelope(env, type, role, keyFor) {
494
494
  if (!ok) throw new PregenError("PG_SIGNATURE", `${type} signature does not verify`);
495
495
  return e.body;
496
496
  }
497
+ var GRANT_FORMATS = {
498
+ // The id is the SHA-256 of the bytes the licence's registry countersigned.
499
+ "pg.license.v2": (g) => keysWithin(g, ["format", "id", "license_id"]) && typeof g.id === "string" && HEX64.test(g.id) && (g.license_id === void 0 || str(g.license_id))
500
+ };
497
501
  function checkBasis(b) {
498
502
  if (!isObj(b)) return false;
499
503
  if (b.kind === "grant") {
500
504
  const g = b.grant;
501
- return keysWithin(b, ["kind", "grant"]) && isObj(g) && keysWithin(g, ["format", "id", "license_id"]) && str(g.format) && typeof g.id === "string" && Object.values(g).every((v) => typeof v === "string");
505
+ return keysWithin(b, ["kind", "grant"]) && isObj(g) && typeof g.format === "string" && !!GRANT_FORMATS[g.format]?.(g);
502
506
  }
503
507
  return b.kind === "policy" && keysWithin(b, ["kind", "rule"]) && str(b.rule);
504
508
  }
@@ -579,6 +583,7 @@ function createPregen(config) {
579
583
  };
580
584
  const listed = dir?.registries.find((r) => sameBase(r.api));
581
585
  if (dir && !listed) fail2(`${base} is not a registry listed in the PRE-GEN directory`);
586
+ const registryCode = listed ? listed.prefix ? `PG-${listed.prefix}-0` : "PG-0" : "";
582
587
  const ready = (async () => {
583
588
  const registry = /* @__PURE__ */ new Map();
584
589
  for (const p of pins) registry.set(await keyIdOf(unhex(p)), unhex(p));
@@ -589,10 +594,9 @@ function createPregen(config) {
589
594
  async function keyFor(keyId) {
590
595
  const { registry } = await ready;
591
596
  if (pins.length) return registry.get(keyId);
592
- const code = listed.prefix ? `PG-${listed.prefix}-0` : "PG-0";
593
597
  let p = fromDirectory.get(keyId);
594
598
  if (!p) {
595
- p = dir.publicKey(code, keyId).then(unhex, () => {
599
+ p = dir.publicKey(registryCode, keyId).then(unhex, () => {
596
600
  fromDirectory.delete(keyId);
597
601
  return void 0;
598
602
  });
@@ -600,7 +604,7 @@ function createPregen(config) {
600
604
  }
601
605
  return p;
602
606
  }
603
- const directoryVerdict = (subject, keyId) => !dir || !isPgCode(subject) ? "valid" : dir.checkSigner(subject, keyId);
607
+ const directoryVerdict = (subject, keyId) => !dir ? "valid" : dir.checkSigner(isPgCode(subject) ? subject : registryCode, keyId);
604
608
  async function post(path, payload) {
605
609
  const resp = await fetch(base + path, {
606
610
  method: "POST",
@@ -676,12 +680,11 @@ function createPregen(config) {
676
680
  return { subject: a.request.subject_ref, answerStatus: a.answer?.body.status ?? "none", report: await seal("pg.report.v1", body) };
677
681
  }
678
682
  async function checkAck(r, env) {
679
- const { keyId } = await ready;
680
683
  const ack = await verifyEnvelope(env, "pg.report_ack.v1", "registry", keyFor);
681
684
  const verdict = directoryVerdict(r.subject, ack.signers[0].key_id);
682
685
  if (verdict !== "valid") throw new PregenError(`PG_KEY_${verdict.toUpperCase()}`, "the directory does not list this key");
683
686
  if (Object.keys(ack).sort().join() !== [...ACK_FIELDS].sort().join()) throw malformed("acknowledgement fields");
684
- if (ack.report !== await messageId("pg.report.v1", r.report.body) || ack.answer !== r.report.body.answer || ack.answer_status !== r.answerStatus || ack.provider_key_id !== keyId) {
687
+ if (ack.report !== await messageId("pg.report.v1", r.report.body) || ack.answer !== r.report.body.answer || ack.answer_status !== r.answerStatus || ack.provider_key_id !== r.report.body.signers?.[0]?.key_id) {
685
688
  throw new PregenError("PG_BINDING", "the acknowledgement is not for this report");
686
689
  }
687
690
  if (!(ack.counted === null || HEX64.test(ack.counted)) || !Array.isArray(ack.released) || !ack.released.every((x) => typeof x === "string" && HEX64.test(x)) || !Number.isSafeInteger(ack.received_at)) {
package/dist/index.mjs CHANGED
@@ -429,11 +429,15 @@ async function verifyEnvelope(env, type, role, keyFor) {
429
429
  if (!ok) throw new PregenError("PG_SIGNATURE", `${type} signature does not verify`);
430
430
  return e.body;
431
431
  }
432
+ var GRANT_FORMATS = {
433
+ // The id is the SHA-256 of the bytes the licence's registry countersigned.
434
+ "pg.license.v2": (g) => keysWithin(g, ["format", "id", "license_id"]) && typeof g.id === "string" && HEX64.test(g.id) && (g.license_id === void 0 || str(g.license_id))
435
+ };
432
436
  function checkBasis(b) {
433
437
  if (!isObj(b)) return false;
434
438
  if (b.kind === "grant") {
435
439
  const g = b.grant;
436
- return keysWithin(b, ["kind", "grant"]) && isObj(g) && keysWithin(g, ["format", "id", "license_id"]) && str(g.format) && typeof g.id === "string" && Object.values(g).every((v) => typeof v === "string");
440
+ return keysWithin(b, ["kind", "grant"]) && isObj(g) && typeof g.format === "string" && !!GRANT_FORMATS[g.format]?.(g);
437
441
  }
438
442
  return b.kind === "policy" && keysWithin(b, ["kind", "rule"]) && str(b.rule);
439
443
  }
@@ -514,6 +518,7 @@ function createPregen(config) {
514
518
  };
515
519
  const listed = dir?.registries.find((r) => sameBase(r.api));
516
520
  if (dir && !listed) fail2(`${base} is not a registry listed in the PRE-GEN directory`);
521
+ const registryCode = listed ? listed.prefix ? `PG-${listed.prefix}-0` : "PG-0" : "";
517
522
  const ready = (async () => {
518
523
  const registry = /* @__PURE__ */ new Map();
519
524
  for (const p of pins) registry.set(await keyIdOf(unhex(p)), unhex(p));
@@ -524,10 +529,9 @@ function createPregen(config) {
524
529
  async function keyFor(keyId) {
525
530
  const { registry } = await ready;
526
531
  if (pins.length) return registry.get(keyId);
527
- const code = listed.prefix ? `PG-${listed.prefix}-0` : "PG-0";
528
532
  let p = fromDirectory.get(keyId);
529
533
  if (!p) {
530
- p = dir.publicKey(code, keyId).then(unhex, () => {
534
+ p = dir.publicKey(registryCode, keyId).then(unhex, () => {
531
535
  fromDirectory.delete(keyId);
532
536
  return void 0;
533
537
  });
@@ -535,7 +539,7 @@ function createPregen(config) {
535
539
  }
536
540
  return p;
537
541
  }
538
- const directoryVerdict = (subject, keyId) => !dir || !isPgCode(subject) ? "valid" : dir.checkSigner(subject, keyId);
542
+ const directoryVerdict = (subject, keyId) => !dir ? "valid" : dir.checkSigner(isPgCode(subject) ? subject : registryCode, keyId);
539
543
  async function post(path, payload) {
540
544
  const resp = await fetch(base + path, {
541
545
  method: "POST",
@@ -611,12 +615,11 @@ function createPregen(config) {
611
615
  return { subject: a.request.subject_ref, answerStatus: a.answer?.body.status ?? "none", report: await seal("pg.report.v1", body) };
612
616
  }
613
617
  async function checkAck(r, env) {
614
- const { keyId } = await ready;
615
618
  const ack = await verifyEnvelope(env, "pg.report_ack.v1", "registry", keyFor);
616
619
  const verdict = directoryVerdict(r.subject, ack.signers[0].key_id);
617
620
  if (verdict !== "valid") throw new PregenError(`PG_KEY_${verdict.toUpperCase()}`, "the directory does not list this key");
618
621
  if (Object.keys(ack).sort().join() !== [...ACK_FIELDS].sort().join()) throw malformed("acknowledgement fields");
619
- if (ack.report !== await messageId("pg.report.v1", r.report.body) || ack.answer !== r.report.body.answer || ack.answer_status !== r.answerStatus || ack.provider_key_id !== keyId) {
622
+ if (ack.report !== await messageId("pg.report.v1", r.report.body) || ack.answer !== r.report.body.answer || ack.answer_status !== r.answerStatus || ack.provider_key_id !== r.report.body.signers?.[0]?.key_id) {
620
623
  throw new PregenError("PG_BINDING", "the acknowledgement is not for this report");
621
624
  }
622
625
  if (!(ack.counted === null || HEX64.test(ack.counted)) || !Array.isArray(ack.released) || !ack.released.every((x) => typeof x === "string" && HEX64.test(x)) || !Number.isSafeInteger(ack.received_at)) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@prampta/sdk",
3
- "version": "0.11.0",
3
+ "version": "0.11.1",
4
4
  "description": "PRAMPTA SDK — authorization before generation",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",