@prampta/sdk 0.11.1 → 0.11.3
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 +15 -7
- package/dist/index.d.mts +17 -6
- package/dist/index.d.ts +17 -6
- package/dist/index.js +39 -8
- package/dist/index.mjs +39 -8
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -40,8 +40,8 @@ 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.
|
|
44
|
-
|
|
43
|
+
up once; wrap each generation in one call. Use 0.11.3 or later: earlier versions
|
|
44
|
+
had defects found by external reviews (see CHANGELOG). A complete
|
|
45
45
|
program you can run as it stands: https://prampta.com/get-started-v2.md.
|
|
46
46
|
|
|
47
47
|
```typescript
|
|
@@ -180,8 +180,9 @@ const result = await pg.generateAuthorized(
|
|
|
180
180
|
{ subjectIds: [subjectCode], generationId: jobId, promptHash, model, modality: "image",
|
|
181
181
|
intendedUse: { useCase: "commercial" } },
|
|
182
182
|
async (decisions) => {
|
|
183
|
-
const image = await render(prompt);
|
|
184
|
-
return { output: image, outputBytes: image.bytes
|
|
183
|
+
const image = await render(prompt, decisions.map((d) => d.obligations)); // apply the obligations yourself
|
|
184
|
+
return { output: image, outputBytes: image.bytes,
|
|
185
|
+
obligationsApplied: { attribution: true } }; // only what you actually did (0.11.3: nothing is assumed)
|
|
185
186
|
},
|
|
186
187
|
{ journal },
|
|
187
188
|
);
|
|
@@ -267,10 +268,17 @@ const decision = await pg.assertLicensed(subjectCode, {
|
|
|
267
268
|
- stores the output hash and the **exact receipts** (signed, if you sign)
|
|
268
269
|
before sending them, and after a failure resends those receipts byte for
|
|
269
270
|
byte — receipt options passed on a later call do not replace them;
|
|
270
|
-
- a receipt counts as filed only when the registry
|
|
271
|
-
`
|
|
272
|
-
|
|
271
|
+
- a receipt counts as filed only when the registry's answer is about exactly
|
|
272
|
+
it (0.11.3): `recorded` or `already_recorded`, this decision, and the
|
|
273
|
+
`receipt_hash` of these bytes (`checkReceiptAck`; `submitReceipt` checks
|
|
274
|
+
it too); `unreported` lists receipts to resend (call again with the same
|
|
275
|
+
id and request), `conflicts` lists decisions for which the registry holds a
|
|
273
276
|
different receipt;
|
|
277
|
+
- claims only the obligations your `generate` returns in
|
|
278
|
+
`obligationsApplied` (and `watermarkEmbedded`); with none, the receipt
|
|
279
|
+
says none were applied and PRAMPTA records it as not compliant. Before
|
|
280
|
+
0.11.3 the SDK copied the decision's obligations into the receipt, a claim
|
|
281
|
+
of work nobody had confirmed;
|
|
274
282
|
- gives the allows back (`releaseDecision`) when a subject refuses or your
|
|
275
283
|
`generate` throws; that job is then closed, use a new `generationId`;
|
|
276
284
|
- never reruns a job that may have started generating.
|
package/dist/index.d.mts
CHANGED
|
@@ -619,6 +619,17 @@ interface AuthorizedGeneration<T> {
|
|
|
619
619
|
* Resending will not help; find out why. */
|
|
620
620
|
conflicts: SignedDecision[];
|
|
621
621
|
}
|
|
622
|
+
/** What your `generate` returns to `generateAuthorized`. Report only obligations you carried out: the receipt is a
|
|
623
|
+
* signed statement, and nothing is claimed on your behalf. */
|
|
624
|
+
interface GeneratedOutput<T> {
|
|
625
|
+
output: T;
|
|
626
|
+
outputHash?: string;
|
|
627
|
+
outputBytes?: Uint8Array | string;
|
|
628
|
+
/** The obligations you applied, by name (e.g. `{ attribution: true }`). Default: none. */
|
|
629
|
+
obligationsApplied?: Record<string, unknown>;
|
|
630
|
+
/** Whether you embedded the watermark an obligation asked for. Default: false. */
|
|
631
|
+
watermarkEmbedded?: boolean;
|
|
632
|
+
}
|
|
622
633
|
interface OutputMetadata {
|
|
623
634
|
prampta_decision_id: string;
|
|
624
635
|
prampta_license_id: string | null;
|
|
@@ -819,11 +830,7 @@ declare class Prampta {
|
|
|
819
830
|
* If a subject refuses or `generate` throws, the allows are given back.
|
|
820
831
|
* `generate` must throw only when nothing was produced.
|
|
821
832
|
*/
|
|
822
|
-
generateAuthorized<T>(request: AuthorizedRequest, generate: (decisions: SignedDecision[]) => Promise<{
|
|
823
|
-
output: T;
|
|
824
|
-
outputHash?: string;
|
|
825
|
-
outputBytes?: Uint8Array | string;
|
|
826
|
-
}>, options: {
|
|
833
|
+
generateAuthorized<T>(request: AuthorizedRequest, generate: (decisions: SignedDecision[]) => Promise<GeneratedOutput<T>>, options: {
|
|
827
834
|
journal: GenerationJournal;
|
|
828
835
|
receipt?: ReceiptOptions;
|
|
829
836
|
}): Promise<AuthorizedGeneration<T>>;
|
|
@@ -855,6 +862,10 @@ declare class Prampta {
|
|
|
855
862
|
/** 32-byte Ed25519 private key, hex; keep server-side. Never sent to PRAMPTA. */
|
|
856
863
|
providerSigningKeyHex?: string;
|
|
857
864
|
}): Promise<Record<string, unknown>>;
|
|
865
|
+
/** A receipt counts as filed only when PRAMPTA's answer is about exactly it: `recorded` or `already_recorded`
|
|
866
|
+
* (the identical receipt again), this decision, and the receipt_hash of the body the registry built from these
|
|
867
|
+
* bytes (app/core/receipt_body.py). A success status alone proves nothing about which receipt was accepted. */
|
|
868
|
+
checkReceiptAck(decision: SignedDecision, payload: Record<string, unknown>, ack: unknown): Promise<Record<string, unknown>>;
|
|
858
869
|
/** The exact receipt body submitReceipt() would send, signed if a key is given. */
|
|
859
870
|
buildReceipt(decision: SignedDecision, result?: NonNullable<Parameters<Prampta["submitReceipt"]>[1]>): Promise<Record<string, unknown>>;
|
|
860
871
|
/**
|
|
@@ -892,4 +903,4 @@ declare class Prampta {
|
|
|
892
903
|
private getOnce;
|
|
893
904
|
}
|
|
894
905
|
|
|
895
|
-
export { type AskResult, type AuthorizedGeneration, type AuthorizedRequest, type DeliveryResult, type Envelope, type GenerateFn, type GenerationJournal, type GenerationJournalEntry, HARD_REFUSAL_CODES, type LicenseRequestInput, type LicenseRequestResult, type LicenseSignatureInput, NotGeneratedError, type Obligation, type Observation, type ObservationOutbox, type OutputMetadata, type PgQueryable, Prampta, PramptaApiError, type PramptaConfig, PramptaError, PramptaFailClosedError, PramptaJobConflictError, PramptaNetworkError, PramptaRefusalError, PramptaReporter, PramptaSchemaError, PramptaSignatureError, PramptaTimeoutError, type Pregen, type PregenConfig, PregenError, type PregenJob, type PregenJobInput, type PregenResult, type PregenStore, type Purpose, REFUSAL_DESCRIPTIONS, type ReceiptOptions, RegistryDirectoryError, type RegistryDirectoryOptions, type ReportInput, SOFT_REFUSAL_CODES, type SignedDecision, type SubjectIndexEntry, type SubjectInfo, TrustedRegistryDirectory, type VerifyOptions, type VerifyRequest, canonicalJson, createPregen, hashPrompt, matchSubjects, memoryStore, messageId, normalizeForMatch, postgresSchema, postgresStore, signingInput, singleProcessJournal, verifyLicenseSignatures, verifyMerkleProof };
|
|
906
|
+
export { type AskResult, type AuthorizedGeneration, type AuthorizedRequest, type DeliveryResult, type Envelope, type GenerateFn, type GeneratedOutput, type GenerationJournal, type GenerationJournalEntry, HARD_REFUSAL_CODES, type LicenseRequestInput, type LicenseRequestResult, type LicenseSignatureInput, NotGeneratedError, type Obligation, type Observation, type ObservationOutbox, type OutputMetadata, type PgQueryable, Prampta, PramptaApiError, type PramptaConfig, PramptaError, PramptaFailClosedError, PramptaJobConflictError, PramptaNetworkError, PramptaRefusalError, PramptaReporter, PramptaSchemaError, PramptaSignatureError, PramptaTimeoutError, type Pregen, type PregenConfig, PregenError, type PregenJob, type PregenJobInput, type PregenResult, type PregenStore, type Purpose, REFUSAL_DESCRIPTIONS, type ReceiptOptions, RegistryDirectoryError, type RegistryDirectoryOptions, type ReportInput, SOFT_REFUSAL_CODES, type SignedDecision, type SubjectIndexEntry, type SubjectInfo, TrustedRegistryDirectory, type VerifyOptions, type VerifyRequest, canonicalJson, createPregen, hashPrompt, matchSubjects, memoryStore, messageId, normalizeForMatch, postgresSchema, postgresStore, signingInput, singleProcessJournal, verifyLicenseSignatures, verifyMerkleProof };
|
package/dist/index.d.ts
CHANGED
|
@@ -619,6 +619,17 @@ interface AuthorizedGeneration<T> {
|
|
|
619
619
|
* Resending will not help; find out why. */
|
|
620
620
|
conflicts: SignedDecision[];
|
|
621
621
|
}
|
|
622
|
+
/** What your `generate` returns to `generateAuthorized`. Report only obligations you carried out: the receipt is a
|
|
623
|
+
* signed statement, and nothing is claimed on your behalf. */
|
|
624
|
+
interface GeneratedOutput<T> {
|
|
625
|
+
output: T;
|
|
626
|
+
outputHash?: string;
|
|
627
|
+
outputBytes?: Uint8Array | string;
|
|
628
|
+
/** The obligations you applied, by name (e.g. `{ attribution: true }`). Default: none. */
|
|
629
|
+
obligationsApplied?: Record<string, unknown>;
|
|
630
|
+
/** Whether you embedded the watermark an obligation asked for. Default: false. */
|
|
631
|
+
watermarkEmbedded?: boolean;
|
|
632
|
+
}
|
|
622
633
|
interface OutputMetadata {
|
|
623
634
|
prampta_decision_id: string;
|
|
624
635
|
prampta_license_id: string | null;
|
|
@@ -819,11 +830,7 @@ declare class Prampta {
|
|
|
819
830
|
* If a subject refuses or `generate` throws, the allows are given back.
|
|
820
831
|
* `generate` must throw only when nothing was produced.
|
|
821
832
|
*/
|
|
822
|
-
generateAuthorized<T>(request: AuthorizedRequest, generate: (decisions: SignedDecision[]) => Promise<{
|
|
823
|
-
output: T;
|
|
824
|
-
outputHash?: string;
|
|
825
|
-
outputBytes?: Uint8Array | string;
|
|
826
|
-
}>, options: {
|
|
833
|
+
generateAuthorized<T>(request: AuthorizedRequest, generate: (decisions: SignedDecision[]) => Promise<GeneratedOutput<T>>, options: {
|
|
827
834
|
journal: GenerationJournal;
|
|
828
835
|
receipt?: ReceiptOptions;
|
|
829
836
|
}): Promise<AuthorizedGeneration<T>>;
|
|
@@ -855,6 +862,10 @@ declare class Prampta {
|
|
|
855
862
|
/** 32-byte Ed25519 private key, hex; keep server-side. Never sent to PRAMPTA. */
|
|
856
863
|
providerSigningKeyHex?: string;
|
|
857
864
|
}): Promise<Record<string, unknown>>;
|
|
865
|
+
/** A receipt counts as filed only when PRAMPTA's answer is about exactly it: `recorded` or `already_recorded`
|
|
866
|
+
* (the identical receipt again), this decision, and the receipt_hash of the body the registry built from these
|
|
867
|
+
* bytes (app/core/receipt_body.py). A success status alone proves nothing about which receipt was accepted. */
|
|
868
|
+
checkReceiptAck(decision: SignedDecision, payload: Record<string, unknown>, ack: unknown): Promise<Record<string, unknown>>;
|
|
858
869
|
/** The exact receipt body submitReceipt() would send, signed if a key is given. */
|
|
859
870
|
buildReceipt(decision: SignedDecision, result?: NonNullable<Parameters<Prampta["submitReceipt"]>[1]>): Promise<Record<string, unknown>>;
|
|
860
871
|
/**
|
|
@@ -892,4 +903,4 @@ declare class Prampta {
|
|
|
892
903
|
private getOnce;
|
|
893
904
|
}
|
|
894
905
|
|
|
895
|
-
export { type AskResult, type AuthorizedGeneration, type AuthorizedRequest, type DeliveryResult, type Envelope, type GenerateFn, type GenerationJournal, type GenerationJournalEntry, HARD_REFUSAL_CODES, type LicenseRequestInput, type LicenseRequestResult, type LicenseSignatureInput, NotGeneratedError, type Obligation, type Observation, type ObservationOutbox, type OutputMetadata, type PgQueryable, Prampta, PramptaApiError, type PramptaConfig, PramptaError, PramptaFailClosedError, PramptaJobConflictError, PramptaNetworkError, PramptaRefusalError, PramptaReporter, PramptaSchemaError, PramptaSignatureError, PramptaTimeoutError, type Pregen, type PregenConfig, PregenError, type PregenJob, type PregenJobInput, type PregenResult, type PregenStore, type Purpose, REFUSAL_DESCRIPTIONS, type ReceiptOptions, RegistryDirectoryError, type RegistryDirectoryOptions, type ReportInput, SOFT_REFUSAL_CODES, type SignedDecision, type SubjectIndexEntry, type SubjectInfo, TrustedRegistryDirectory, type VerifyOptions, type VerifyRequest, canonicalJson, createPregen, hashPrompt, matchSubjects, memoryStore, messageId, normalizeForMatch, postgresSchema, postgresStore, signingInput, singleProcessJournal, verifyLicenseSignatures, verifyMerkleProof };
|
|
906
|
+
export { type AskResult, type AuthorizedGeneration, type AuthorizedRequest, type DeliveryResult, type Envelope, type GenerateFn, type GeneratedOutput, type GenerationJournal, type GenerationJournalEntry, HARD_REFUSAL_CODES, type LicenseRequestInput, type LicenseRequestResult, type LicenseSignatureInput, NotGeneratedError, type Obligation, type Observation, type ObservationOutbox, type OutputMetadata, type PgQueryable, Prampta, PramptaApiError, type PramptaConfig, PramptaError, PramptaFailClosedError, PramptaJobConflictError, PramptaNetworkError, PramptaRefusalError, PramptaReporter, PramptaSchemaError, PramptaSignatureError, PramptaTimeoutError, type Pregen, type PregenConfig, PregenError, type PregenJob, type PregenJobInput, type PregenResult, type PregenStore, type Purpose, REFUSAL_DESCRIPTIONS, type ReceiptOptions, RegistryDirectoryError, type RegistryDirectoryOptions, type ReportInput, SOFT_REFUSAL_CODES, type SignedDecision, type SubjectIndexEntry, type SubjectInfo, TrustedRegistryDirectory, type VerifyOptions, type VerifyRequest, canonicalJson, createPregen, hashPrompt, matchSubjects, memoryStore, messageId, normalizeForMatch, postgresSchema, postgresStore, signingInput, singleProcessJournal, verifyLicenseSignatures, verifyMerkleProof };
|
package/dist/index.js
CHANGED
|
@@ -502,7 +502,7 @@ function checkBasis(b) {
|
|
|
502
502
|
if (!isObj(b)) return false;
|
|
503
503
|
if (b.kind === "grant") {
|
|
504
504
|
const g = b.grant;
|
|
505
|
-
return keysWithin(b, ["kind", "grant"]) && isObj(g) && typeof g.format === "string" &&
|
|
505
|
+
return keysWithin(b, ["kind", "grant"]) && isObj(g) && typeof g.format === "string" && Object.hasOwn(GRANT_FORMATS, g.format) && GRANT_FORMATS[g.format](g) === true;
|
|
506
506
|
}
|
|
507
507
|
return b.kind === "policy" && keysWithin(b, ["kind", "rule"]) && str(b.rule);
|
|
508
508
|
}
|
|
@@ -1787,16 +1787,20 @@ var Prampta = class _Prampta {
|
|
|
1787
1787
|
const outputHash = result.outputHash ?? (bytes ? await sha256Bytes(bytes) : "");
|
|
1788
1788
|
const generatedAt = Math.floor(Date.now() / 1e3);
|
|
1789
1789
|
const receipts = {};
|
|
1790
|
-
|
|
1790
|
+
const done = {
|
|
1791
|
+
...result.obligationsApplied !== void 0 ? { obligationsApplied: result.obligationsApplied } : {},
|
|
1792
|
+
...result.watermarkEmbedded !== void 0 ? { watermarkEmbedded: result.watermarkEmbedded } : {}
|
|
1793
|
+
};
|
|
1794
|
+
for (const d of decisions) receipts[d.decisionId] = await this.buildReceipt(d, { ...receipt, ...done, outputHash, generatedAt });
|
|
1791
1795
|
const generated = { ...entry, stage: "generated", outputHash, generatedAt, receipts };
|
|
1792
1796
|
await journal.put(generated);
|
|
1793
1797
|
return this.report(journal, generated, "generated", result.output, receipt);
|
|
1794
1798
|
}
|
|
1795
1799
|
async report(journal, entry, status, output, receipt) {
|
|
1796
|
-
const results = await Promise.allSettled(entry.decisions.map(async (d) =>
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
))
|
|
1800
|
+
const results = await Promise.allSettled(entry.decisions.map(async (d) => {
|
|
1801
|
+
const payload = entry.receipts?.[d.decisionId] ?? await this.buildReceipt(d, { ...receipt, outputHash: entry.outputHash ?? "", generatedAt: entry.generatedAt });
|
|
1802
|
+
return this.checkReceiptAck(d, payload, await this.post("/v1/receipts/", payload));
|
|
1803
|
+
}));
|
|
1800
1804
|
const unreported = [], conflicts = [];
|
|
1801
1805
|
results.forEach((r, i) => {
|
|
1802
1806
|
if (r.status === "fulfilled") return;
|
|
@@ -1863,7 +1867,33 @@ var Prampta = class _Prampta {
|
|
|
1863
1867
|
* provider attestation, not proof of complete reporting or actual execution.
|
|
1864
1868
|
*/
|
|
1865
1869
|
async submitReceipt(decision, result = {}) {
|
|
1866
|
-
|
|
1870
|
+
const payload = await this.buildReceipt(decision, result);
|
|
1871
|
+
return this.checkReceiptAck(decision, payload, await this.post("/v1/receipts/", payload));
|
|
1872
|
+
}
|
|
1873
|
+
/** A receipt counts as filed only when PRAMPTA's answer is about exactly it: `recorded` or `already_recorded`
|
|
1874
|
+
* (the identical receipt again), this decision, and the receipt_hash of the body the registry built from these
|
|
1875
|
+
* bytes (app/core/receipt_body.py). A success status alone proves nothing about which receipt was accepted. */
|
|
1876
|
+
async checkReceiptAck(decision, payload, ack) {
|
|
1877
|
+
const a = ack;
|
|
1878
|
+
const v = String(payload.schema_version ?? "pg.receipt.v2");
|
|
1879
|
+
const body = {
|
|
1880
|
+
v,
|
|
1881
|
+
decision_id: payload.decision_id,
|
|
1882
|
+
subject_id: decision.subjectId,
|
|
1883
|
+
licensee_id: this.licenseeId,
|
|
1884
|
+
provider_id: this.providerId,
|
|
1885
|
+
prompt_hash: payload.prompt_hash,
|
|
1886
|
+
output_hash: payload.output_hash,
|
|
1887
|
+
model: payload.model,
|
|
1888
|
+
obligations_applied: payload.obligations_applied,
|
|
1889
|
+
watermark_embedded: payload.watermark_embedded,
|
|
1890
|
+
generated_at: payload.generated_at,
|
|
1891
|
+
...v === "pg.receipt.v3" ? { event_type: payload.event_type } : {}
|
|
1892
|
+
};
|
|
1893
|
+
if (!a || typeof a !== "object" || a.status !== "recorded" && a.status !== "already_recorded" || a.decision_id !== decision.decisionId || a.receipt_hash !== await sha2563(canonicalJson(body))) {
|
|
1894
|
+
throw new PramptaSchemaError("The registry's receipt answer is not about this receipt");
|
|
1895
|
+
}
|
|
1896
|
+
return a;
|
|
1867
1897
|
}
|
|
1868
1898
|
/** The exact receipt body submitReceipt() would send, signed if a key is given. */
|
|
1869
1899
|
async buildReceipt(decision, result = {}) {
|
|
@@ -1873,7 +1903,8 @@ var Prampta = class _Prampta {
|
|
|
1873
1903
|
output_hash: result.outputHash ?? "",
|
|
1874
1904
|
model: result.model ?? decision.model,
|
|
1875
1905
|
watermark_embedded: result.watermarkEmbedded ?? false,
|
|
1876
|
-
|
|
1906
|
+
// Only what the caller says it did: copying the decision's obligations here claimed work never done.
|
|
1907
|
+
obligations_applied: result.obligationsApplied ?? {},
|
|
1877
1908
|
generated_at: result.generatedAt ?? Math.floor(Date.now() / 1e3)
|
|
1878
1909
|
};
|
|
1879
1910
|
if (result.providerSigningKeyHex !== void 0) {
|
package/dist/index.mjs
CHANGED
|
@@ -437,7 +437,7 @@ function checkBasis(b) {
|
|
|
437
437
|
if (!isObj(b)) return false;
|
|
438
438
|
if (b.kind === "grant") {
|
|
439
439
|
const g = b.grant;
|
|
440
|
-
return keysWithin(b, ["kind", "grant"]) && isObj(g) && typeof g.format === "string" &&
|
|
440
|
+
return keysWithin(b, ["kind", "grant"]) && isObj(g) && typeof g.format === "string" && Object.hasOwn(GRANT_FORMATS, g.format) && GRANT_FORMATS[g.format](g) === true;
|
|
441
441
|
}
|
|
442
442
|
return b.kind === "policy" && keysWithin(b, ["kind", "rule"]) && str(b.rule);
|
|
443
443
|
}
|
|
@@ -1722,16 +1722,20 @@ var Prampta = class _Prampta {
|
|
|
1722
1722
|
const outputHash = result.outputHash ?? (bytes ? await sha256Bytes(bytes) : "");
|
|
1723
1723
|
const generatedAt = Math.floor(Date.now() / 1e3);
|
|
1724
1724
|
const receipts = {};
|
|
1725
|
-
|
|
1725
|
+
const done = {
|
|
1726
|
+
...result.obligationsApplied !== void 0 ? { obligationsApplied: result.obligationsApplied } : {},
|
|
1727
|
+
...result.watermarkEmbedded !== void 0 ? { watermarkEmbedded: result.watermarkEmbedded } : {}
|
|
1728
|
+
};
|
|
1729
|
+
for (const d of decisions) receipts[d.decisionId] = await this.buildReceipt(d, { ...receipt, ...done, outputHash, generatedAt });
|
|
1726
1730
|
const generated = { ...entry, stage: "generated", outputHash, generatedAt, receipts };
|
|
1727
1731
|
await journal.put(generated);
|
|
1728
1732
|
return this.report(journal, generated, "generated", result.output, receipt);
|
|
1729
1733
|
}
|
|
1730
1734
|
async report(journal, entry, status, output, receipt) {
|
|
1731
|
-
const results = await Promise.allSettled(entry.decisions.map(async (d) =>
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
))
|
|
1735
|
+
const results = await Promise.allSettled(entry.decisions.map(async (d) => {
|
|
1736
|
+
const payload = entry.receipts?.[d.decisionId] ?? await this.buildReceipt(d, { ...receipt, outputHash: entry.outputHash ?? "", generatedAt: entry.generatedAt });
|
|
1737
|
+
return this.checkReceiptAck(d, payload, await this.post("/v1/receipts/", payload));
|
|
1738
|
+
}));
|
|
1735
1739
|
const unreported = [], conflicts = [];
|
|
1736
1740
|
results.forEach((r, i) => {
|
|
1737
1741
|
if (r.status === "fulfilled") return;
|
|
@@ -1798,7 +1802,33 @@ var Prampta = class _Prampta {
|
|
|
1798
1802
|
* provider attestation, not proof of complete reporting or actual execution.
|
|
1799
1803
|
*/
|
|
1800
1804
|
async submitReceipt(decision, result = {}) {
|
|
1801
|
-
|
|
1805
|
+
const payload = await this.buildReceipt(decision, result);
|
|
1806
|
+
return this.checkReceiptAck(decision, payload, await this.post("/v1/receipts/", payload));
|
|
1807
|
+
}
|
|
1808
|
+
/** A receipt counts as filed only when PRAMPTA's answer is about exactly it: `recorded` or `already_recorded`
|
|
1809
|
+
* (the identical receipt again), this decision, and the receipt_hash of the body the registry built from these
|
|
1810
|
+
* bytes (app/core/receipt_body.py). A success status alone proves nothing about which receipt was accepted. */
|
|
1811
|
+
async checkReceiptAck(decision, payload, ack) {
|
|
1812
|
+
const a = ack;
|
|
1813
|
+
const v = String(payload.schema_version ?? "pg.receipt.v2");
|
|
1814
|
+
const body = {
|
|
1815
|
+
v,
|
|
1816
|
+
decision_id: payload.decision_id,
|
|
1817
|
+
subject_id: decision.subjectId,
|
|
1818
|
+
licensee_id: this.licenseeId,
|
|
1819
|
+
provider_id: this.providerId,
|
|
1820
|
+
prompt_hash: payload.prompt_hash,
|
|
1821
|
+
output_hash: payload.output_hash,
|
|
1822
|
+
model: payload.model,
|
|
1823
|
+
obligations_applied: payload.obligations_applied,
|
|
1824
|
+
watermark_embedded: payload.watermark_embedded,
|
|
1825
|
+
generated_at: payload.generated_at,
|
|
1826
|
+
...v === "pg.receipt.v3" ? { event_type: payload.event_type } : {}
|
|
1827
|
+
};
|
|
1828
|
+
if (!a || typeof a !== "object" || a.status !== "recorded" && a.status !== "already_recorded" || a.decision_id !== decision.decisionId || a.receipt_hash !== await sha2563(canonicalJson(body))) {
|
|
1829
|
+
throw new PramptaSchemaError("The registry's receipt answer is not about this receipt");
|
|
1830
|
+
}
|
|
1831
|
+
return a;
|
|
1802
1832
|
}
|
|
1803
1833
|
/** The exact receipt body submitReceipt() would send, signed if a key is given. */
|
|
1804
1834
|
async buildReceipt(decision, result = {}) {
|
|
@@ -1808,7 +1838,8 @@ var Prampta = class _Prampta {
|
|
|
1808
1838
|
output_hash: result.outputHash ?? "",
|
|
1809
1839
|
model: result.model ?? decision.model,
|
|
1810
1840
|
watermark_embedded: result.watermarkEmbedded ?? false,
|
|
1811
|
-
|
|
1841
|
+
// Only what the caller says it did: copying the decision's obligations here claimed work never done.
|
|
1842
|
+
obligations_applied: result.obligationsApplied ?? {},
|
|
1812
1843
|
generated_at: result.generatedAt ?? Math.floor(Date.now() / 1e3)
|
|
1813
1844
|
};
|
|
1814
1845
|
if (result.providerSigningKeyHex !== void 0) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@prampta/sdk",
|
|
3
|
-
"version": "0.11.
|
|
3
|
+
"version": "0.11.3",
|
|
4
4
|
"description": "PRAMPTA SDK — authorization before generation",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.mjs",
|
|
@@ -49,7 +49,7 @@
|
|
|
49
49
|
},
|
|
50
50
|
"dependencies": {
|
|
51
51
|
"@noble/ed25519": "^3.1.0",
|
|
52
|
-
"@pregen/verify": "^0.
|
|
52
|
+
"@pregen/verify": "^0.8.0"
|
|
53
53
|
},
|
|
54
54
|
"repository": {
|
|
55
55
|
"type": "git",
|