@prampta/sdk 0.9.0 → 0.9.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
@@ -147,8 +147,11 @@ const decision = await pg.assertLicensed(subjectCode, {
147
147
  - asks fresh for **every subject in the output** and generates only if
148
148
  **all** of them return a licence-backed `allow`;
149
149
  - re-checks every allow **immediately before** your `generate` runs;
150
- - stores the output hash **before** sending receipts, and resends the
151
- byte-identical receipt after a failure;
150
+ - takes its own copy of the request before doing anything, so changing your
151
+ object afterwards cannot change the job;
152
+ - stores the output hash and the **exact receipts** (signed, if you sign)
153
+ before sending them, and after a failure resends those receipts byte for
154
+ byte — receipt options passed on a later call do not replace them;
152
155
  - a receipt counts as filed only when the registry accepted exactly it:
153
156
  `unreported` lists receipts to resend (call again with the same id and
154
157
  request), `conflicts` lists decisions for which the registry holds a
package/dist/index.d.mts CHANGED
@@ -398,8 +398,10 @@ interface GenerationJournalEntry {
398
398
  stage: "claimed" | "authorized" | "generated" | "reported" | "released";
399
399
  decisions: SignedDecision[];
400
400
  outputHash?: string;
401
- /** Kept so a resent receipt is byte-identical to the first. */
402
401
  generatedAt?: number;
402
+ /** The exact receipt bodies (signed, if a key was given), stored before the
403
+ * first send and resent unchanged. No private key is stored. */
404
+ receipts?: Record<string, Record<string, unknown>>;
403
405
  }
404
406
  interface GenerationJournal {
405
407
  /** ATOMIC across every worker: store `entry` if no entry exists for its
@@ -666,6 +668,8 @@ declare class Prampta {
666
668
  /** 32-byte Ed25519 private key, hex; keep server-side. Never sent to PRAMPTA. */
667
669
  providerSigningKeyHex?: string;
668
670
  }): Promise<Record<string, unknown>>;
671
+ /** The exact receipt body submitReceipt() would send, signed if a key is given. */
672
+ buildReceipt(decision: SignedDecision, result?: NonNullable<Parameters<Prampta["submitReceipt"]>[1]>): Promise<Record<string, unknown>>;
669
673
  /**
670
674
  * Get (issuing if needed) the signed `pg.assertion.v1` for a decision this
671
675
  * provider/licensee pair already submitted a receipt for — embed it in
package/dist/index.d.ts CHANGED
@@ -398,8 +398,10 @@ interface GenerationJournalEntry {
398
398
  stage: "claimed" | "authorized" | "generated" | "reported" | "released";
399
399
  decisions: SignedDecision[];
400
400
  outputHash?: string;
401
- /** Kept so a resent receipt is byte-identical to the first. */
402
401
  generatedAt?: number;
402
+ /** The exact receipt bodies (signed, if a key was given), stored before the
403
+ * first send and resent unchanged. No private key is stored. */
404
+ receipts?: Record<string, Record<string, unknown>>;
403
405
  }
404
406
  interface GenerationJournal {
405
407
  /** ATOMIC across every worker: store `entry` if no entry exists for its
@@ -666,6 +668,8 @@ declare class Prampta {
666
668
  /** 32-byte Ed25519 private key, hex; keep server-side. Never sent to PRAMPTA. */
667
669
  providerSigningKeyHex?: string;
668
670
  }): Promise<Record<string, unknown>>;
671
+ /** The exact receipt body submitReceipt() would send, signed if a key is given. */
672
+ buildReceipt(decision: SignedDecision, result?: NonNullable<Parameters<Prampta["submitReceipt"]>[1]>): Promise<Record<string, unknown>>;
669
673
  /**
670
674
  * Get (issuing if needed) the signed `pg.assertion.v1` for a decision this
671
675
  * provider/licensee pair already submitted a receipt for — embed it in
package/dist/index.js CHANGED
@@ -1143,6 +1143,7 @@ var Prampta = class _Prampta {
1143
1143
  * `generate` must throw only when nothing was produced.
1144
1144
  */
1145
1145
  async generateAuthorized(request, generate, options) {
1146
+ request = structuredClone(request);
1146
1147
  const id = request.generationId;
1147
1148
  if (!id) throw new PramptaSchemaError("generateAuthorized requires a generationId");
1148
1149
  if (!options?.journal) throw new PramptaSchemaError("generateAuthorized requires a journal (singleProcessJournal() for one process)");
@@ -1203,12 +1204,18 @@ var Prampta = class _Prampta {
1203
1204
  }
1204
1205
  const bytes = typeof result.outputBytes === "string" ? new TextEncoder().encode(result.outputBytes) : result.outputBytes;
1205
1206
  const outputHash = result.outputHash ?? (bytes ? await sha256Bytes(bytes) : "");
1206
- const generated = { ...entry, stage: "generated", outputHash, generatedAt: Math.floor(Date.now() / 1e3) };
1207
+ const generatedAt = Math.floor(Date.now() / 1e3);
1208
+ const receipts = {};
1209
+ for (const d of decisions) receipts[d.decisionId] = await this.buildReceipt(d, { ...receipt, outputHash, generatedAt });
1210
+ const generated = { ...entry, stage: "generated", outputHash, generatedAt, receipts };
1207
1211
  await journal.put(generated);
1208
1212
  return this.report(journal, generated, "generated", result.output, receipt);
1209
1213
  }
1210
1214
  async report(journal, entry, status, output, receipt) {
1211
- const results = await Promise.allSettled(entry.decisions.map((d) => this.submitReceipt(d, { ...receipt, outputHash: entry.outputHash ?? "", generatedAt: entry.generatedAt })));
1215
+ const results = await Promise.allSettled(entry.decisions.map(async (d) => this.post(
1216
+ "/v1/receipts/",
1217
+ entry.receipts?.[d.decisionId] ?? await this.buildReceipt(d, { ...receipt, outputHash: entry.outputHash ?? "", generatedAt: entry.generatedAt })
1218
+ )));
1212
1219
  const unreported = [], conflicts = [];
1213
1220
  results.forEach((r, i) => {
1214
1221
  if (r.status === "fulfilled") return;
@@ -1275,6 +1282,10 @@ var Prampta = class _Prampta {
1275
1282
  * provider attestation, not proof of complete reporting or actual execution.
1276
1283
  */
1277
1284
  async submitReceipt(decision, result = {}) {
1285
+ return this.post("/v1/receipts/", await this.buildReceipt(decision, result));
1286
+ }
1287
+ /** The exact receipt body submitReceipt() would send, signed if a key is given. */
1288
+ async buildReceipt(decision, result = {}) {
1278
1289
  const payload = {
1279
1290
  decision_id: decision.decisionId,
1280
1291
  prompt_hash: decision.promptHash,
@@ -1317,7 +1328,7 @@ var Prampta = class _Prampta {
1317
1328
  } else if (result.eventType && result.eventType !== "output_accepted") {
1318
1329
  throw new PramptaError("A non-default eventType requires a provider signing key and pg.receipt.v3");
1319
1330
  }
1320
- return this.post("/v1/receipts/", payload);
1331
+ return payload;
1321
1332
  }
1322
1333
  // ── C2PA bridge (PRE-GEN v1.1 addendum §11) ─────────────────────────────
1323
1334
  /**
package/dist/index.mjs CHANGED
@@ -1086,6 +1086,7 @@ var Prampta = class _Prampta {
1086
1086
  * `generate` must throw only when nothing was produced.
1087
1087
  */
1088
1088
  async generateAuthorized(request, generate, options) {
1089
+ request = structuredClone(request);
1089
1090
  const id = request.generationId;
1090
1091
  if (!id) throw new PramptaSchemaError("generateAuthorized requires a generationId");
1091
1092
  if (!options?.journal) throw new PramptaSchemaError("generateAuthorized requires a journal (singleProcessJournal() for one process)");
@@ -1146,12 +1147,18 @@ var Prampta = class _Prampta {
1146
1147
  }
1147
1148
  const bytes = typeof result.outputBytes === "string" ? new TextEncoder().encode(result.outputBytes) : result.outputBytes;
1148
1149
  const outputHash = result.outputHash ?? (bytes ? await sha256Bytes(bytes) : "");
1149
- const generated = { ...entry, stage: "generated", outputHash, generatedAt: Math.floor(Date.now() / 1e3) };
1150
+ const generatedAt = Math.floor(Date.now() / 1e3);
1151
+ const receipts = {};
1152
+ for (const d of decisions) receipts[d.decisionId] = await this.buildReceipt(d, { ...receipt, outputHash, generatedAt });
1153
+ const generated = { ...entry, stage: "generated", outputHash, generatedAt, receipts };
1150
1154
  await journal.put(generated);
1151
1155
  return this.report(journal, generated, "generated", result.output, receipt);
1152
1156
  }
1153
1157
  async report(journal, entry, status, output, receipt) {
1154
- const results = await Promise.allSettled(entry.decisions.map((d) => this.submitReceipt(d, { ...receipt, outputHash: entry.outputHash ?? "", generatedAt: entry.generatedAt })));
1158
+ const results = await Promise.allSettled(entry.decisions.map(async (d) => this.post(
1159
+ "/v1/receipts/",
1160
+ entry.receipts?.[d.decisionId] ?? await this.buildReceipt(d, { ...receipt, outputHash: entry.outputHash ?? "", generatedAt: entry.generatedAt })
1161
+ )));
1155
1162
  const unreported = [], conflicts = [];
1156
1163
  results.forEach((r, i) => {
1157
1164
  if (r.status === "fulfilled") return;
@@ -1218,6 +1225,10 @@ var Prampta = class _Prampta {
1218
1225
  * provider attestation, not proof of complete reporting or actual execution.
1219
1226
  */
1220
1227
  async submitReceipt(decision, result = {}) {
1228
+ return this.post("/v1/receipts/", await this.buildReceipt(decision, result));
1229
+ }
1230
+ /** The exact receipt body submitReceipt() would send, signed if a key is given. */
1231
+ async buildReceipt(decision, result = {}) {
1221
1232
  const payload = {
1222
1233
  decision_id: decision.decisionId,
1223
1234
  prompt_hash: decision.promptHash,
@@ -1260,7 +1271,7 @@ var Prampta = class _Prampta {
1260
1271
  } else if (result.eventType && result.eventType !== "output_accepted") {
1261
1272
  throw new PramptaError("A non-default eventType requires a provider signing key and pg.receipt.v3");
1262
1273
  }
1263
- return this.post("/v1/receipts/", payload);
1274
+ return payload;
1264
1275
  }
1265
1276
  // ── C2PA bridge (PRE-GEN v1.1 addendum §11) ─────────────────────────────
1266
1277
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@prampta/sdk",
3
- "version": "0.9.0",
3
+ "version": "0.9.1",
4
4
  "description": "PRAMPTA SDK — authorization before generation",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",