@prampta/sdk 0.9.0 → 0.10.0
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 +86 -3
- package/dist/index.d.mts +159 -2
- package/dist/index.d.ts +159 -2
- package/dist/index.js +423 -30
- package/dist/index.mjs +417 -30
- package/package.json +3 -1
package/README.md
CHANGED
|
@@ -13,7 +13,7 @@ support is not claimed: CommonJS loads the ESM-only crypto dependency through
|
|
|
13
13
|
[`require(esm)`](https://nodejs.org/en/blog/release/v20.19.0). Local ESM/CommonJS
|
|
14
14
|
smoke tests run on Node 22.20; a wider runtime/browser matrix is still a release gate.
|
|
15
15
|
|
|
16
|
-
This README describes SDK 0.
|
|
16
|
+
This README describes SDK 0.10.0; sections name the version that added them.
|
|
17
17
|
In older 0.4.0, `assertAllowed` throws on
|
|
18
18
|
personal-use `not_blocked` and `PramptaReporter` is unavailable. Use `verify()`
|
|
19
19
|
and inspect `disposition` when supporting older installations;
|
|
@@ -36,6 +36,86 @@ production PRAMPTA deployment running the v1.0.0-default trust posture
|
|
|
36
36
|
refuses it with `PG_NO_PAIR`. Don't build a new integration against it; it
|
|
37
37
|
exists solely so an already-connected provider keeps working mid-migration.
|
|
38
38
|
|
|
39
|
+
## PRE-GEN v5: one setup, one call (0.10.0, `/v2`)
|
|
40
|
+
|
|
41
|
+
`createPregen` speaks the simplified PRE-GEN v5 formats at `/v2`: signed
|
|
42
|
+
answers bound to your request, signed reports, signed acknowledgements. Set it
|
|
43
|
+
up once; wrap each generation in one call.
|
|
44
|
+
|
|
45
|
+
```typescript
|
|
46
|
+
import pg from "pg";
|
|
47
|
+
import { createPregen, postgresStore } from "@prampta/sdk";
|
|
48
|
+
|
|
49
|
+
const pregen = createPregen({
|
|
50
|
+
baseUrl: "https://api2.prampta.com",
|
|
51
|
+
providerId: "my-ai",
|
|
52
|
+
token: process.env.PRAMPTA_TOKEN!, // your exchange_secret, server-side only
|
|
53
|
+
providerSigningKeyHex: process.env.PREGEN_SIGNING_KEY!, // your Ed25519 private key (32 bytes hex): signs your reports
|
|
54
|
+
operatorPublicKeyHex: process.env.PRAMPTA_OPERATOR_PUBLIC_KEY!, // obtained independently, not from the API
|
|
55
|
+
store: postgresStore(new pg.Pool()), // shared by all your workers; creates table pregen_jobs
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
await pregen.registerKey(); // once: registers your public key with the registry
|
|
59
|
+
setInterval(() => pregen.flush(), 60_000); // and at startup: resends reports still waiting
|
|
60
|
+
|
|
61
|
+
const result = await pregen.generate(
|
|
62
|
+
{ jobId: task.id, // YOUR stable task id: a retry reuses it, a new generation gets a new one
|
|
63
|
+
subjects: ["PGXX-..."], // everyone in the output
|
|
64
|
+
prompt, model: "my-model", modality: "image", use: { purpose: "commercial" },
|
|
65
|
+
licenseeId }, // the connected user, or omit for a provider-level request
|
|
66
|
+
async ({ obligations }) => {
|
|
67
|
+
const image = await render(prompt, obligations); // YOU apply the obligations (watermark, disclosure...)
|
|
68
|
+
return { output: image, outputBytes: image.bytes, obligationsApplied: obligations.map((o) => o.id) };
|
|
69
|
+
},
|
|
70
|
+
);
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
**What one call does.** Asks the registry about every subject under one job
|
|
74
|
+
hash; verifies every answer (your pinned key, bound to your request, times);
|
|
75
|
+
in `enforce` mode generates only when **all** subjects allow, re-checking
|
|
76
|
+
right before your function runs; stores the outcome and the signed reports
|
|
77
|
+
**before** sending them; counts a report as filed only when the registry's
|
|
78
|
+
signed acknowledgement of exactly it verifies. Refused, or your function
|
|
79
|
+
threw: nothing is generated and every allow is given back.
|
|
80
|
+
|
|
81
|
+
**The result tells you where the job stands:**
|
|
82
|
+
|
|
83
|
+
| `status` | Meaning | What you do |
|
|
84
|
+
|---|---|---|
|
|
85
|
+
| `confirmed` | Finished; every report acknowledged. `generated` says whether it generated. | Nothing. |
|
|
86
|
+
| `report_pending` | Finished; a report has not been acknowledged yet (network, outage). | Nothing: `flush()` resends it, byte for byte. |
|
|
87
|
+
| `needs_check` | The outcome is unknown: the job was interrupted after it may have started generating, or is running in another worker; or the registry refused a report for good. | Check your generator for this `jobId`, then `pregen.resolve(jobId, { generated: true, outputBytes })` or `{ generated: false }`. |
|
|
88
|
+
|
|
89
|
+
The same `jobId` never generates twice: calling again returns where the job
|
|
90
|
+
stands. The same `jobId` with a different generation is refused
|
|
91
|
+
(`PG_JOB_CONFLICT`). The SDK never guesses whether an interrupted generation
|
|
92
|
+
finished; only your generator knows, so it asks you.
|
|
93
|
+
|
|
94
|
+
**Obligations** are handed to your function and listed in the report as you
|
|
95
|
+
declare them in `obligationsApplied`; any you did not apply come back in
|
|
96
|
+
`unmetObligations`. How to apply a watermark or a disclosure depends on your
|
|
97
|
+
medium (image, video, audio) and is yours to implement.
|
|
98
|
+
|
|
99
|
+
**Which subjects.** You name them. Matching names in a prompt
|
|
100
|
+
(`matchSubjects`) only suggests candidates; faces, voices and uploaded
|
|
101
|
+
references are for your own pipeline to identify.
|
|
102
|
+
|
|
103
|
+
**`observe` mode** (`mode: "observe"`): generates whatever the answers say and
|
|
104
|
+
reports every generation. Nothing is blocked and nothing is granted: use it
|
|
105
|
+
to trial the integration, then switch to `enforce`; nothing else changes.
|
|
106
|
+
|
|
107
|
+
**Your signing key.** Reports must be signed. `registerKey()` sends a `first`
|
|
108
|
+
keyset signed by the key it names. After that, the registry also requires
|
|
109
|
+
your `/v1` receipts to be signed with the same key (`providerSigningKeyHex`
|
|
110
|
+
in `submitReceipt`). Rotation is not available yet.
|
|
111
|
+
|
|
112
|
+
**Stores.** `postgresStore(pool)` takes any node-postgres `Pool` or `Client`
|
|
113
|
+
(the `pg` package is yours; the SDK does not depend on it). `memoryStore()`
|
|
114
|
+
is for tests and a single process: it is lost on restart.
|
|
115
|
+
|
|
116
|
+
Not in this release: Python, other stores, several registries in one job,
|
|
117
|
+
key rotation.
|
|
118
|
+
|
|
39
119
|
## Quick Start: the safe setup (0.9.0)
|
|
40
120
|
|
|
41
121
|
One configuration turns on every check: the signed PRE-GEN directory, your
|
|
@@ -147,8 +227,11 @@ const decision = await pg.assertLicensed(subjectCode, {
|
|
|
147
227
|
- asks fresh for **every subject in the output** and generates only if
|
|
148
228
|
**all** of them return a licence-backed `allow`;
|
|
149
229
|
- re-checks every allow **immediately before** your `generate` runs;
|
|
150
|
-
-
|
|
151
|
-
|
|
230
|
+
- takes its own copy of the request before doing anything, so changing your
|
|
231
|
+
object afterwards cannot change the job;
|
|
232
|
+
- stores the output hash and the **exact receipts** (signed, if you sign)
|
|
233
|
+
before sending them, and after a failure resends those receipts byte for
|
|
234
|
+
byte — receipt options passed on a later call do not replace them;
|
|
152
235
|
- a receipt counts as filed only when the registry accepted exactly it:
|
|
153
236
|
`unreported` lists receipts to resend (call again with the same id and
|
|
154
237
|
request), `conflicts` lists decisions for which the registry holds a
|
package/dist/index.d.mts
CHANGED
|
@@ -122,6 +122,159 @@ declare class PramptaReporter {
|
|
|
122
122
|
deliver(event: Observation): Promise<DeliveryResult>;
|
|
123
123
|
}
|
|
124
124
|
|
|
125
|
+
type Envelope = {
|
|
126
|
+
type: string;
|
|
127
|
+
body: Record<string, any>;
|
|
128
|
+
signatures: string[];
|
|
129
|
+
};
|
|
130
|
+
type Purpose = "personal" | "educational" | "research" | "editorial" | "commercial";
|
|
131
|
+
interface Obligation {
|
|
132
|
+
subject: string;
|
|
133
|
+
id: string;
|
|
134
|
+
params: Record<string, unknown>;
|
|
135
|
+
}
|
|
136
|
+
interface PregenConfig {
|
|
137
|
+
baseUrl: string;
|
|
138
|
+
providerId: string;
|
|
139
|
+
/** Your runtime credential (`exchange_secret`). */
|
|
140
|
+
token: string;
|
|
141
|
+
/** Your Ed25519 private key, 32 bytes hex. Signs reports; register its public key once with `registerKey()`. */
|
|
142
|
+
providerSigningKeyHex: string;
|
|
143
|
+
/** The registry's public key(s), hex, obtained from its documentation, not from its API. */
|
|
144
|
+
operatorPublicKeyHex: string | string[];
|
|
145
|
+
store: PregenStore;
|
|
146
|
+
/** `enforce` (default): generate only when every subject allows. `observe`: generate anyway and report; nothing is blocked or granted. */
|
|
147
|
+
mode?: "enforce" | "observe";
|
|
148
|
+
timeoutMs?: number;
|
|
149
|
+
}
|
|
150
|
+
interface PregenJobInput {
|
|
151
|
+
/** Your own stable id for this generation, e.g. your task id. Calling again with the same id
|
|
152
|
+
* never generates twice; a new generation needs a new id. */
|
|
153
|
+
jobId: string;
|
|
154
|
+
/** PRE-GEN codes of everyone in the output. Name matching can suggest them; you decide. */
|
|
155
|
+
subjects: string[];
|
|
156
|
+
/** Hashed locally; never sent. */
|
|
157
|
+
prompt?: string;
|
|
158
|
+
promptHash?: string;
|
|
159
|
+
model: string;
|
|
160
|
+
modality: string;
|
|
161
|
+
use: {
|
|
162
|
+
purpose: Purpose;
|
|
163
|
+
rights?: string[];
|
|
164
|
+
territory?: string;
|
|
165
|
+
channel?: string;
|
|
166
|
+
};
|
|
167
|
+
/** The connected end user's licensee id; empty for a provider-level request. */
|
|
168
|
+
licenseeId?: string;
|
|
169
|
+
}
|
|
170
|
+
type GenerateFn<T> = (ctx: {
|
|
171
|
+
obligations: Obligation[];
|
|
172
|
+
}) => Promise<{
|
|
173
|
+
output: T;
|
|
174
|
+
/** One of these is required: the SHA-256 of the output, or the bytes to hash. */
|
|
175
|
+
outputHash?: string;
|
|
176
|
+
outputBytes?: Uint8Array | string;
|
|
177
|
+
/** Ids of the obligations you applied (watermark, disclosure...). */
|
|
178
|
+
obligationsApplied?: string[];
|
|
179
|
+
}>;
|
|
180
|
+
interface AskResult {
|
|
181
|
+
subject: string;
|
|
182
|
+
status: "allow" | "deny" | "review" | "not_blocked" | null;
|
|
183
|
+
reason?: string;
|
|
184
|
+
/** Why the answer is missing or unusable: PG_UNREACHABLE, PG_SIGNATURE, PG_TIME, PG_BINDING... */
|
|
185
|
+
error?: string;
|
|
186
|
+
}
|
|
187
|
+
interface PregenResult<T = unknown> {
|
|
188
|
+
jobId: string;
|
|
189
|
+
/** confirmed: finished, every report acknowledged. report_pending: finished, a report waits
|
|
190
|
+
* for acknowledgement; `flush()` resends it. needs_check: the outcome is unknown (interrupted,
|
|
191
|
+
* or running in another worker) or the registry holds a different report; check, then `resolve()`. */
|
|
192
|
+
status: "confirmed" | "report_pending" | "needs_check";
|
|
193
|
+
/** null while the outcome is unknown. */
|
|
194
|
+
generated: boolean | null;
|
|
195
|
+
/** Only from the call that generated. */
|
|
196
|
+
output?: T;
|
|
197
|
+
outputHash?: string;
|
|
198
|
+
answers: AskResult[];
|
|
199
|
+
/** Obligations the answers set that `obligationsApplied` did not list. */
|
|
200
|
+
unmetObligations: Obligation[];
|
|
201
|
+
detail?: string;
|
|
202
|
+
}
|
|
203
|
+
/** One job as the store keeps it. */
|
|
204
|
+
interface PregenJob {
|
|
205
|
+
providerId: string;
|
|
206
|
+
jobId: string;
|
|
207
|
+
/** SHA-256 of the manifest; the same job id with another manifest is refused. */
|
|
208
|
+
jobHash: string;
|
|
209
|
+
/** claimed: one worker owns it. asked: answers stored, generation may have started.
|
|
210
|
+
* finished: outcome and signed reports stored, some not acknowledged. done: nothing left to send. */
|
|
211
|
+
stage: "claimed" | "asked" | "finished" | "done";
|
|
212
|
+
asks: {
|
|
213
|
+
request: Record<string, any>;
|
|
214
|
+
answer: Envelope | null;
|
|
215
|
+
error?: string;
|
|
216
|
+
}[];
|
|
217
|
+
generated?: boolean;
|
|
218
|
+
outputHash?: string;
|
|
219
|
+
unmetObligations?: Obligation[];
|
|
220
|
+
/** `rejected`: the registry refused this report for good (it holds a different one, or found it malformed). */
|
|
221
|
+
reports: {
|
|
222
|
+
report: Envelope;
|
|
223
|
+
ack?: Envelope;
|
|
224
|
+
rejected?: boolean;
|
|
225
|
+
error?: string;
|
|
226
|
+
}[];
|
|
227
|
+
}
|
|
228
|
+
interface PregenStore {
|
|
229
|
+
/** ATOMIC across every worker: store `job` if none exists for (providerId, jobId) and return
|
|
230
|
+
* null; otherwise change nothing and return the existing job. */
|
|
231
|
+
claim(job: PregenJob): Promise<PregenJob | null>;
|
|
232
|
+
/** Replace the job. Resolve only after a durable write. */
|
|
233
|
+
put(job: PregenJob): Promise<void>;
|
|
234
|
+
get(providerId: string, jobId: string): Promise<PregenJob | null>;
|
|
235
|
+
/** Jobs in stage `finished`, oldest first. */
|
|
236
|
+
pending(providerId: string): Promise<PregenJob[]>;
|
|
237
|
+
}
|
|
238
|
+
declare class PregenError extends Error {
|
|
239
|
+
readonly code: string;
|
|
240
|
+
constructor(code: string, message: string);
|
|
241
|
+
}
|
|
242
|
+
declare function signingInput(type: string, body: Record<string, unknown>): Uint8Array;
|
|
243
|
+
/** The id of a message: covers type and body, not signatures. */
|
|
244
|
+
declare function messageId(type: string, body: Record<string, unknown>): Promise<string>;
|
|
245
|
+
declare function createPregen(config: PregenConfig): {
|
|
246
|
+
/** Ask, verify, generate (only when permitted), report. See the module comment. */
|
|
247
|
+
generate<T>(input: PregenJobInput, fn: GenerateFn<T>): Promise<PregenResult<T>>;
|
|
248
|
+
/** Resend every report still waiting (after a restart, an outage). Run at startup and every minute or so. */
|
|
249
|
+
flush(): Promise<PregenResult[]>;
|
|
250
|
+
/** Where a job stands, or null if this store never saw it. */
|
|
251
|
+
status(jobId: string): Promise<PregenResult | null>;
|
|
252
|
+
/** After `needs_check`: record what your generator actually did with this job. */
|
|
253
|
+
resolve(jobId: string, outcome: {
|
|
254
|
+
generated: false;
|
|
255
|
+
} | {
|
|
256
|
+
generated: true;
|
|
257
|
+
outputHash?: string;
|
|
258
|
+
outputBytes?: Uint8Array | string;
|
|
259
|
+
obligationsApplied?: string[];
|
|
260
|
+
}): Promise<PregenResult>;
|
|
261
|
+
/** Register this provider's signing key with the registry, once (a `first` keyset, §4.9). */
|
|
262
|
+
registerKey(): Promise<{
|
|
263
|
+
keyId: string;
|
|
264
|
+
}>;
|
|
265
|
+
};
|
|
266
|
+
type Pregen = ReturnType<typeof createPregen>;
|
|
267
|
+
/** In memory. Correct for ONE process only, and lost on restart: tests and trials. */
|
|
268
|
+
declare function memoryStore(): PregenStore;
|
|
269
|
+
/** Anything with node-postgres' `query(text, values)`: a `pg` Pool or Client. */
|
|
270
|
+
interface PgQueryable {
|
|
271
|
+
query(text: string, values?: unknown[]): Promise<{
|
|
272
|
+
rows: any[];
|
|
273
|
+
}>;
|
|
274
|
+
}
|
|
275
|
+
/** Postgres, shared by every worker. Creates its table `pregen_jobs` on first use. */
|
|
276
|
+
declare function postgresStore(pool: PgQueryable): PregenStore;
|
|
277
|
+
|
|
125
278
|
/**
|
|
126
279
|
* PRAMPTA SDK for TypeScript / Node.js
|
|
127
280
|
*
|
|
@@ -398,8 +551,10 @@ interface GenerationJournalEntry {
|
|
|
398
551
|
stage: "claimed" | "authorized" | "generated" | "reported" | "released";
|
|
399
552
|
decisions: SignedDecision[];
|
|
400
553
|
outputHash?: string;
|
|
401
|
-
/** Kept so a resent receipt is byte-identical to the first. */
|
|
402
554
|
generatedAt?: number;
|
|
555
|
+
/** The exact receipt bodies (signed, if a key was given), stored before the
|
|
556
|
+
* first send and resent unchanged. No private key is stored. */
|
|
557
|
+
receipts?: Record<string, Record<string, unknown>>;
|
|
403
558
|
}
|
|
404
559
|
interface GenerationJournal {
|
|
405
560
|
/** ATOMIC across every worker: store `entry` if no entry exists for its
|
|
@@ -666,6 +821,8 @@ declare class Prampta {
|
|
|
666
821
|
/** 32-byte Ed25519 private key, hex; keep server-side. Never sent to PRAMPTA. */
|
|
667
822
|
providerSigningKeyHex?: string;
|
|
668
823
|
}): Promise<Record<string, unknown>>;
|
|
824
|
+
/** The exact receipt body submitReceipt() would send, signed if a key is given. */
|
|
825
|
+
buildReceipt(decision: SignedDecision, result?: NonNullable<Parameters<Prampta["submitReceipt"]>[1]>): Promise<Record<string, unknown>>;
|
|
669
826
|
/**
|
|
670
827
|
* Get (issuing if needed) the signed `pg.assertion.v1` for a decision this
|
|
671
828
|
* provider/licensee pair already submitted a receipt for — embed it in
|
|
@@ -701,4 +858,4 @@ declare class Prampta {
|
|
|
701
858
|
private getOnce;
|
|
702
859
|
}
|
|
703
860
|
|
|
704
|
-
export { type AuthorizedGeneration, type AuthorizedRequest, type DeliveryResult, type GenerationJournal, type GenerationJournalEntry, HARD_REFUSAL_CODES, type LicenseRequestInput, type LicenseRequestResult, type LicenseSignatureInput, type Observation, type ObservationOutbox, type OutputMetadata, Prampta, PramptaApiError, type PramptaConfig, PramptaError, PramptaFailClosedError, PramptaJobConflictError, PramptaNetworkError, PramptaRefusalError, PramptaReporter, PramptaSchemaError, PramptaSignatureError, PramptaTimeoutError, REFUSAL_DESCRIPTIONS, type ReceiptOptions, RegistryDirectoryError, type RegistryDirectoryOptions, type ReportInput, SOFT_REFUSAL_CODES, type SignedDecision, type SubjectIndexEntry, type SubjectInfo, TrustedRegistryDirectory, type VerifyOptions, type VerifyRequest, canonicalJson, hashPrompt, matchSubjects, normalizeForMatch, singleProcessJournal, verifyLicenseSignatures, verifyMerkleProof };
|
|
861
|
+
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, 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, postgresStore, signingInput, singleProcessJournal, verifyLicenseSignatures, verifyMerkleProof };
|
package/dist/index.d.ts
CHANGED
|
@@ -122,6 +122,159 @@ declare class PramptaReporter {
|
|
|
122
122
|
deliver(event: Observation): Promise<DeliveryResult>;
|
|
123
123
|
}
|
|
124
124
|
|
|
125
|
+
type Envelope = {
|
|
126
|
+
type: string;
|
|
127
|
+
body: Record<string, any>;
|
|
128
|
+
signatures: string[];
|
|
129
|
+
};
|
|
130
|
+
type Purpose = "personal" | "educational" | "research" | "editorial" | "commercial";
|
|
131
|
+
interface Obligation {
|
|
132
|
+
subject: string;
|
|
133
|
+
id: string;
|
|
134
|
+
params: Record<string, unknown>;
|
|
135
|
+
}
|
|
136
|
+
interface PregenConfig {
|
|
137
|
+
baseUrl: string;
|
|
138
|
+
providerId: string;
|
|
139
|
+
/** Your runtime credential (`exchange_secret`). */
|
|
140
|
+
token: string;
|
|
141
|
+
/** Your Ed25519 private key, 32 bytes hex. Signs reports; register its public key once with `registerKey()`. */
|
|
142
|
+
providerSigningKeyHex: string;
|
|
143
|
+
/** The registry's public key(s), hex, obtained from its documentation, not from its API. */
|
|
144
|
+
operatorPublicKeyHex: string | string[];
|
|
145
|
+
store: PregenStore;
|
|
146
|
+
/** `enforce` (default): generate only when every subject allows. `observe`: generate anyway and report; nothing is blocked or granted. */
|
|
147
|
+
mode?: "enforce" | "observe";
|
|
148
|
+
timeoutMs?: number;
|
|
149
|
+
}
|
|
150
|
+
interface PregenJobInput {
|
|
151
|
+
/** Your own stable id for this generation, e.g. your task id. Calling again with the same id
|
|
152
|
+
* never generates twice; a new generation needs a new id. */
|
|
153
|
+
jobId: string;
|
|
154
|
+
/** PRE-GEN codes of everyone in the output. Name matching can suggest them; you decide. */
|
|
155
|
+
subjects: string[];
|
|
156
|
+
/** Hashed locally; never sent. */
|
|
157
|
+
prompt?: string;
|
|
158
|
+
promptHash?: string;
|
|
159
|
+
model: string;
|
|
160
|
+
modality: string;
|
|
161
|
+
use: {
|
|
162
|
+
purpose: Purpose;
|
|
163
|
+
rights?: string[];
|
|
164
|
+
territory?: string;
|
|
165
|
+
channel?: string;
|
|
166
|
+
};
|
|
167
|
+
/** The connected end user's licensee id; empty for a provider-level request. */
|
|
168
|
+
licenseeId?: string;
|
|
169
|
+
}
|
|
170
|
+
type GenerateFn<T> = (ctx: {
|
|
171
|
+
obligations: Obligation[];
|
|
172
|
+
}) => Promise<{
|
|
173
|
+
output: T;
|
|
174
|
+
/** One of these is required: the SHA-256 of the output, or the bytes to hash. */
|
|
175
|
+
outputHash?: string;
|
|
176
|
+
outputBytes?: Uint8Array | string;
|
|
177
|
+
/** Ids of the obligations you applied (watermark, disclosure...). */
|
|
178
|
+
obligationsApplied?: string[];
|
|
179
|
+
}>;
|
|
180
|
+
interface AskResult {
|
|
181
|
+
subject: string;
|
|
182
|
+
status: "allow" | "deny" | "review" | "not_blocked" | null;
|
|
183
|
+
reason?: string;
|
|
184
|
+
/** Why the answer is missing or unusable: PG_UNREACHABLE, PG_SIGNATURE, PG_TIME, PG_BINDING... */
|
|
185
|
+
error?: string;
|
|
186
|
+
}
|
|
187
|
+
interface PregenResult<T = unknown> {
|
|
188
|
+
jobId: string;
|
|
189
|
+
/** confirmed: finished, every report acknowledged. report_pending: finished, a report waits
|
|
190
|
+
* for acknowledgement; `flush()` resends it. needs_check: the outcome is unknown (interrupted,
|
|
191
|
+
* or running in another worker) or the registry holds a different report; check, then `resolve()`. */
|
|
192
|
+
status: "confirmed" | "report_pending" | "needs_check";
|
|
193
|
+
/** null while the outcome is unknown. */
|
|
194
|
+
generated: boolean | null;
|
|
195
|
+
/** Only from the call that generated. */
|
|
196
|
+
output?: T;
|
|
197
|
+
outputHash?: string;
|
|
198
|
+
answers: AskResult[];
|
|
199
|
+
/** Obligations the answers set that `obligationsApplied` did not list. */
|
|
200
|
+
unmetObligations: Obligation[];
|
|
201
|
+
detail?: string;
|
|
202
|
+
}
|
|
203
|
+
/** One job as the store keeps it. */
|
|
204
|
+
interface PregenJob {
|
|
205
|
+
providerId: string;
|
|
206
|
+
jobId: string;
|
|
207
|
+
/** SHA-256 of the manifest; the same job id with another manifest is refused. */
|
|
208
|
+
jobHash: string;
|
|
209
|
+
/** claimed: one worker owns it. asked: answers stored, generation may have started.
|
|
210
|
+
* finished: outcome and signed reports stored, some not acknowledged. done: nothing left to send. */
|
|
211
|
+
stage: "claimed" | "asked" | "finished" | "done";
|
|
212
|
+
asks: {
|
|
213
|
+
request: Record<string, any>;
|
|
214
|
+
answer: Envelope | null;
|
|
215
|
+
error?: string;
|
|
216
|
+
}[];
|
|
217
|
+
generated?: boolean;
|
|
218
|
+
outputHash?: string;
|
|
219
|
+
unmetObligations?: Obligation[];
|
|
220
|
+
/** `rejected`: the registry refused this report for good (it holds a different one, or found it malformed). */
|
|
221
|
+
reports: {
|
|
222
|
+
report: Envelope;
|
|
223
|
+
ack?: Envelope;
|
|
224
|
+
rejected?: boolean;
|
|
225
|
+
error?: string;
|
|
226
|
+
}[];
|
|
227
|
+
}
|
|
228
|
+
interface PregenStore {
|
|
229
|
+
/** ATOMIC across every worker: store `job` if none exists for (providerId, jobId) and return
|
|
230
|
+
* null; otherwise change nothing and return the existing job. */
|
|
231
|
+
claim(job: PregenJob): Promise<PregenJob | null>;
|
|
232
|
+
/** Replace the job. Resolve only after a durable write. */
|
|
233
|
+
put(job: PregenJob): Promise<void>;
|
|
234
|
+
get(providerId: string, jobId: string): Promise<PregenJob | null>;
|
|
235
|
+
/** Jobs in stage `finished`, oldest first. */
|
|
236
|
+
pending(providerId: string): Promise<PregenJob[]>;
|
|
237
|
+
}
|
|
238
|
+
declare class PregenError extends Error {
|
|
239
|
+
readonly code: string;
|
|
240
|
+
constructor(code: string, message: string);
|
|
241
|
+
}
|
|
242
|
+
declare function signingInput(type: string, body: Record<string, unknown>): Uint8Array;
|
|
243
|
+
/** The id of a message: covers type and body, not signatures. */
|
|
244
|
+
declare function messageId(type: string, body: Record<string, unknown>): Promise<string>;
|
|
245
|
+
declare function createPregen(config: PregenConfig): {
|
|
246
|
+
/** Ask, verify, generate (only when permitted), report. See the module comment. */
|
|
247
|
+
generate<T>(input: PregenJobInput, fn: GenerateFn<T>): Promise<PregenResult<T>>;
|
|
248
|
+
/** Resend every report still waiting (after a restart, an outage). Run at startup and every minute or so. */
|
|
249
|
+
flush(): Promise<PregenResult[]>;
|
|
250
|
+
/** Where a job stands, or null if this store never saw it. */
|
|
251
|
+
status(jobId: string): Promise<PregenResult | null>;
|
|
252
|
+
/** After `needs_check`: record what your generator actually did with this job. */
|
|
253
|
+
resolve(jobId: string, outcome: {
|
|
254
|
+
generated: false;
|
|
255
|
+
} | {
|
|
256
|
+
generated: true;
|
|
257
|
+
outputHash?: string;
|
|
258
|
+
outputBytes?: Uint8Array | string;
|
|
259
|
+
obligationsApplied?: string[];
|
|
260
|
+
}): Promise<PregenResult>;
|
|
261
|
+
/** Register this provider's signing key with the registry, once (a `first` keyset, §4.9). */
|
|
262
|
+
registerKey(): Promise<{
|
|
263
|
+
keyId: string;
|
|
264
|
+
}>;
|
|
265
|
+
};
|
|
266
|
+
type Pregen = ReturnType<typeof createPregen>;
|
|
267
|
+
/** In memory. Correct for ONE process only, and lost on restart: tests and trials. */
|
|
268
|
+
declare function memoryStore(): PregenStore;
|
|
269
|
+
/** Anything with node-postgres' `query(text, values)`: a `pg` Pool or Client. */
|
|
270
|
+
interface PgQueryable {
|
|
271
|
+
query(text: string, values?: unknown[]): Promise<{
|
|
272
|
+
rows: any[];
|
|
273
|
+
}>;
|
|
274
|
+
}
|
|
275
|
+
/** Postgres, shared by every worker. Creates its table `pregen_jobs` on first use. */
|
|
276
|
+
declare function postgresStore(pool: PgQueryable): PregenStore;
|
|
277
|
+
|
|
125
278
|
/**
|
|
126
279
|
* PRAMPTA SDK for TypeScript / Node.js
|
|
127
280
|
*
|
|
@@ -398,8 +551,10 @@ interface GenerationJournalEntry {
|
|
|
398
551
|
stage: "claimed" | "authorized" | "generated" | "reported" | "released";
|
|
399
552
|
decisions: SignedDecision[];
|
|
400
553
|
outputHash?: string;
|
|
401
|
-
/** Kept so a resent receipt is byte-identical to the first. */
|
|
402
554
|
generatedAt?: number;
|
|
555
|
+
/** The exact receipt bodies (signed, if a key was given), stored before the
|
|
556
|
+
* first send and resent unchanged. No private key is stored. */
|
|
557
|
+
receipts?: Record<string, Record<string, unknown>>;
|
|
403
558
|
}
|
|
404
559
|
interface GenerationJournal {
|
|
405
560
|
/** ATOMIC across every worker: store `entry` if no entry exists for its
|
|
@@ -666,6 +821,8 @@ declare class Prampta {
|
|
|
666
821
|
/** 32-byte Ed25519 private key, hex; keep server-side. Never sent to PRAMPTA. */
|
|
667
822
|
providerSigningKeyHex?: string;
|
|
668
823
|
}): Promise<Record<string, unknown>>;
|
|
824
|
+
/** The exact receipt body submitReceipt() would send, signed if a key is given. */
|
|
825
|
+
buildReceipt(decision: SignedDecision, result?: NonNullable<Parameters<Prampta["submitReceipt"]>[1]>): Promise<Record<string, unknown>>;
|
|
669
826
|
/**
|
|
670
827
|
* Get (issuing if needed) the signed `pg.assertion.v1` for a decision this
|
|
671
828
|
* provider/licensee pair already submitted a receipt for — embed it in
|
|
@@ -701,4 +858,4 @@ declare class Prampta {
|
|
|
701
858
|
private getOnce;
|
|
702
859
|
}
|
|
703
860
|
|
|
704
|
-
export { type AuthorizedGeneration, type AuthorizedRequest, type DeliveryResult, type GenerationJournal, type GenerationJournalEntry, HARD_REFUSAL_CODES, type LicenseRequestInput, type LicenseRequestResult, type LicenseSignatureInput, type Observation, type ObservationOutbox, type OutputMetadata, Prampta, PramptaApiError, type PramptaConfig, PramptaError, PramptaFailClosedError, PramptaJobConflictError, PramptaNetworkError, PramptaRefusalError, PramptaReporter, PramptaSchemaError, PramptaSignatureError, PramptaTimeoutError, REFUSAL_DESCRIPTIONS, type ReceiptOptions, RegistryDirectoryError, type RegistryDirectoryOptions, type ReportInput, SOFT_REFUSAL_CODES, type SignedDecision, type SubjectIndexEntry, type SubjectInfo, TrustedRegistryDirectory, type VerifyOptions, type VerifyRequest, canonicalJson, hashPrompt, matchSubjects, normalizeForMatch, singleProcessJournal, verifyLicenseSignatures, verifyMerkleProof };
|
|
861
|
+
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, 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, postgresStore, signingInput, singleProcessJournal, verifyLicenseSignatures, verifyMerkleProof };
|