@openwop/openwop 1.1.1 → 1.1.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.
Files changed (46) hide show
  1. package/README.md +4 -0
  2. package/dist/client.d.ts +80 -1
  3. package/dist/client.d.ts.map +1 -1
  4. package/dist/client.js +186 -0
  5. package/dist/client.js.map +1 -1
  6. package/dist/cost-attribution.d.ts +49 -0
  7. package/dist/cost-attribution.d.ts.map +1 -0
  8. package/dist/cost-attribution.js +65 -0
  9. package/dist/cost-attribution.js.map +1 -0
  10. package/dist/envelope-directive.d.ts +77 -0
  11. package/dist/envelope-directive.d.ts.map +1 -0
  12. package/dist/envelope-directive.js +89 -0
  13. package/dist/envelope-directive.js.map +1 -0
  14. package/dist/event-helpers.d.ts +95 -0
  15. package/dist/event-helpers.d.ts.map +1 -0
  16. package/dist/event-helpers.js +160 -0
  17. package/dist/event-helpers.js.map +1 -0
  18. package/dist/index.d.ts +14 -1
  19. package/dist/index.d.ts.map +1 -1
  20. package/dist/index.js +34 -0
  21. package/dist/index.js.map +1 -1
  22. package/dist/parse-refusal.d.ts +114 -0
  23. package/dist/parse-refusal.d.ts.map +1 -0
  24. package/dist/parse-refusal.js +216 -0
  25. package/dist/parse-refusal.js.map +1 -0
  26. package/dist/registry-helpers.d.ts +118 -0
  27. package/dist/registry-helpers.d.ts.map +1 -0
  28. package/dist/registry-helpers.js +82 -0
  29. package/dist/registry-helpers.js.map +1 -0
  30. package/dist/types.d.ts +376 -1
  31. package/dist/types.d.ts.map +1 -1
  32. package/dist/types.js.map +1 -1
  33. package/dist/webhook-helpers.d.ts +73 -0
  34. package/dist/webhook-helpers.d.ts.map +1 -0
  35. package/dist/webhook-helpers.js +97 -0
  36. package/dist/webhook-helpers.js.map +1 -0
  37. package/package.json +1 -1
  38. package/src/client.ts +218 -0
  39. package/src/cost-attribution.ts +72 -0
  40. package/src/envelope-directive.ts +110 -0
  41. package/src/event-helpers.ts +238 -0
  42. package/src/index.ts +117 -0
  43. package/src/parse-refusal.ts +311 -0
  44. package/src/registry-helpers.ts +173 -0
  45. package/src/types.ts +424 -0
  46. package/src/webhook-helpers.ts +131 -0
@@ -0,0 +1,216 @@
1
+ /**
2
+ * parseRefusal — normalize per-provider LLM safety-stop signals to the
3
+ * canonical RFC 0032 §B.3 refusal shape.
4
+ *
5
+ * The three Tier-1 vendors (Anthropic / OpenAI / Google Gemini) surface
6
+ * refusals through different fields:
7
+ *
8
+ * - **Anthropic Messages API**: `stop_reason: "refusal"` (their 2025
9
+ * release) OR `stop_reason: "end_turn"` accompanied by safety-stop
10
+ * markers in the content. Refusal text MAY be inline in the
11
+ * `content[]` array's text blocks.
12
+ * - **OpenAI Chat Completions**: `choices[0].finish_reason:
13
+ * "content_filter"` OR `choices[0].message.refusal: <string>` (the
14
+ * refusal-text field added in their structured-output release).
15
+ * - **Google Gemini**: `candidates[0].finishReason: "SAFETY"` OR
16
+ * `promptFeedback.blockReason: "SAFETY"` (input-side block).
17
+ *
18
+ * Without normalization, every host re-implements this detection. This
19
+ * helper consolidates the per-vendor shape-detection and returns a
20
+ * canonical `RefusalSignal | null` — null when the response is a
21
+ * normal completion (no refusal detected).
22
+ *
23
+ * Per RFC 0032 §B.3 + RFC 0033 §D, hosts MUST NOT retry on refusal
24
+ * (circumvention concern). Callers route the non-null return through
25
+ * `envelope.refusal` emission + the `envelope_refusal` terminal error
26
+ * code (per RFC 0033 §F).
27
+ *
28
+ * Per SECURITY/invariants.yaml §envelope-refusal-no-prompt-leak,
29
+ * `refusalText` MUST be passed through the host's BYOK redaction
30
+ * harness BEFORE persistence — this helper does NOT redact; the
31
+ * caller is responsible for SR-1 carry-forward.
32
+ *
33
+ * @see RFCS/0032-envelope-reliability-events.md §B.3
34
+ * @see RFCS/0033-envelope-completion-contract.md §D + §F
35
+ * @see SECURITY/invariants.yaml §envelope-refusal-no-prompt-leak
36
+ */
37
+ /**
38
+ * Try to parse the response as OpenAI Chat Completions output.
39
+ *
40
+ * Detection: top-level `choices` array. Refusal signals:
41
+ * - `choices[0].finish_reason === "content_filter"`
42
+ * - `choices[0].message.refusal` is a non-empty string
43
+ */
44
+ function tryParseOpenAI(response) {
45
+ if (!response || typeof response !== 'object')
46
+ return null;
47
+ const r = response;
48
+ if (!Array.isArray(r.choices) || r.choices.length === 0)
49
+ return null;
50
+ const choice = r.choices[0];
51
+ if (!choice || typeof choice !== 'object')
52
+ return null;
53
+ const finishReason = choice.finish_reason;
54
+ const message = choice.message;
55
+ const refusalField = message && typeof message === 'object' ? message.refusal : undefined;
56
+ // Primary signal: explicit refusal-text field. OpenAI's structured-output
57
+ // release populates this when the safety filter intervenes.
58
+ if (typeof refusalField === 'string' && refusalField.length > 0) {
59
+ return { refusalText: refusalField, provider: 'openai' };
60
+ }
61
+ // Secondary signal: finish_reason. content_filter is the canonical
62
+ // safety-stop value.
63
+ if (finishReason === 'content_filter') {
64
+ const text = message && typeof message === 'object' && typeof message.content === 'string'
65
+ ? message.content
66
+ : null;
67
+ return { refusalText: text, safetyCategory: 'content_filter', provider: 'openai' };
68
+ }
69
+ return null;
70
+ }
71
+ /**
72
+ * Try to parse the response as Anthropic Messages API output.
73
+ *
74
+ * Detection: top-level `stop_reason` field (Anthropic's distinctive
75
+ * marker). Refusal signals:
76
+ * - `stop_reason === "refusal"` (their 2025 release)
77
+ *
78
+ * Anthropic does not surface a distinct safety-category field on
79
+ * refusals; the `refusal` stop_reason is the binary signal.
80
+ */
81
+ function tryParseAnthropic(response) {
82
+ if (!response || typeof response !== 'object')
83
+ return null;
84
+ const r = response;
85
+ if (typeof r.stop_reason !== 'string')
86
+ return null;
87
+ if (r.stop_reason === 'refusal') {
88
+ // Extract refusal text from the content array (Anthropic returns an
89
+ // array of typed blocks; refusal text appears in `text`-type blocks).
90
+ let refusalText = null;
91
+ if (Array.isArray(r.content)) {
92
+ const textBlocks = [];
93
+ for (const block of r.content) {
94
+ if (block && typeof block === 'object') {
95
+ const b = block;
96
+ if (b.type === 'text' && typeof b.text === 'string') {
97
+ textBlocks.push(b.text);
98
+ }
99
+ }
100
+ }
101
+ if (textBlocks.length > 0)
102
+ refusalText = textBlocks.join('\n');
103
+ }
104
+ return { refusalText, provider: 'anthropic' };
105
+ }
106
+ return null;
107
+ }
108
+ /**
109
+ * Try to parse the response as Google Gemini `generateContent` output.
110
+ *
111
+ * Detection: top-level `candidates` array OR top-level `promptFeedback`
112
+ * object. Refusal signals:
113
+ * - `candidates[0].finishReason === "SAFETY"` (output-side block)
114
+ * - `promptFeedback.blockReason === "SAFETY"` (input-side block)
115
+ *
116
+ * Gemini surfaces safety categories on `safetyRatings[]`; this helper
117
+ * picks the highest-probability HIGH/MEDIUM-tier category as
118
+ * `safetyCategory` when available.
119
+ */
120
+ function tryParseGemini(response) {
121
+ if (!response || typeof response !== 'object')
122
+ return null;
123
+ const r = response;
124
+ // Output-side safety block.
125
+ if (Array.isArray(r.candidates) && r.candidates.length > 0) {
126
+ const candidate = r.candidates[0];
127
+ if (candidate && typeof candidate === 'object' && candidate.finishReason === 'SAFETY') {
128
+ const safetyCategory = extractGeminiHighestRiskCategory(candidate.safetyRatings);
129
+ const result = { refusalText: null, provider: 'google' };
130
+ if (safetyCategory !== undefined)
131
+ result.safetyCategory = safetyCategory;
132
+ return result;
133
+ }
134
+ }
135
+ // Input-side safety block (Gemini rejected the prompt itself).
136
+ if (r.promptFeedback && typeof r.promptFeedback === 'object') {
137
+ const pf = r.promptFeedback;
138
+ if (typeof pf.blockReason === 'string' && pf.blockReason.toUpperCase().includes('SAFETY')) {
139
+ const safetyCategory = extractGeminiHighestRiskCategory(pf.safetyRatings);
140
+ const result = { refusalText: null, provider: 'google' };
141
+ if (safetyCategory !== undefined)
142
+ result.safetyCategory = safetyCategory;
143
+ return result;
144
+ }
145
+ }
146
+ return null;
147
+ }
148
+ /**
149
+ * From a Gemini `safetyRatings[]` array, return the highest-probability
150
+ * non-NEGLIGIBLE category identifier. Returns `undefined` when the
151
+ * array is absent or all ratings are NEGLIGIBLE.
152
+ */
153
+ function extractGeminiHighestRiskCategory(safetyRatings) {
154
+ if (!Array.isArray(safetyRatings))
155
+ return undefined;
156
+ const PROBABILITY_RANK = {
157
+ HIGH: 3,
158
+ MEDIUM: 2,
159
+ LOW: 1,
160
+ NEGLIGIBLE: 0,
161
+ };
162
+ let best = null;
163
+ for (const rating of safetyRatings) {
164
+ if (!rating || typeof rating !== 'object')
165
+ continue;
166
+ const r = rating;
167
+ if (typeof r.category !== 'string' || typeof r.probability !== 'string')
168
+ continue;
169
+ const rank = PROBABILITY_RANK[r.probability.toUpperCase()] ?? 0;
170
+ if (rank === 0)
171
+ continue;
172
+ if (best === null || rank > best.rank) {
173
+ best = { category: r.category, rank };
174
+ }
175
+ }
176
+ return best?.category;
177
+ }
178
+ /**
179
+ * Parse a provider response into a canonical refusal signal.
180
+ *
181
+ * Returns `null` when no refusal is detected (normal completion).
182
+ * Returns a `RefusalSignal` when the response matches one of the
183
+ * three Tier-1 vendors' safety-stop shapes.
184
+ *
185
+ * Detection order: OpenAI → Anthropic → Gemini. Each detector inspects
186
+ * a distinctive top-level field, so cross-vendor false-positives are
187
+ * unlikely. A response that doesn't match any vendor shape returns
188
+ * `null` (hosts that route through novel providers add their own
189
+ * detector + fall back to this for the three known ones).
190
+ *
191
+ * @example
192
+ * ```ts
193
+ * import { parseRefusal } from '@openwop/openwop';
194
+ *
195
+ * const response = await callOpenAI({...});
196
+ * const refusal = parseRefusal(response);
197
+ * if (refusal) {
198
+ * // Route through envelope.refusal emission + envelope_refusal error code.
199
+ * // REMEMBER to redact refusalText through the BYOK harness before
200
+ * // persistence (SECURITY invariant envelope-refusal-no-prompt-leak).
201
+ * await emitEnvelopeRefusal({
202
+ * refusalText: redactBYOK(refusal.refusalText),
203
+ * safetyCategory: refusal.safetyCategory,
204
+ * provider: refusal.provider,
205
+ * });
206
+ * throw new EnvelopeRefusalError(...);
207
+ * }
208
+ * // ...normal-completion handling...
209
+ * ```
210
+ */
211
+ export function parseRefusal(providerResponse) {
212
+ return (tryParseOpenAI(providerResponse) ??
213
+ tryParseAnthropic(providerResponse) ??
214
+ tryParseGemini(providerResponse));
215
+ }
216
+ //# sourceMappingURL=parse-refusal.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parse-refusal.js","sourceRoot":"","sources":["../src/parse-refusal.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,118 @@
1
+ /**
2
+ * Public-registry read helpers per
3
+ * `spec/v1/registry-operations.md`.
4
+ *
5
+ * The OpenWOP host SDK targets the host wire surface
6
+ * (`/.well-known/openwop` + `/v1/runs/*` + `/v1/interrupts/*` etc).
7
+ * The **public node-pack registry** at `packs.openwop.dev` is a
8
+ * separate wire surface with its own discovery payload and pack-
9
+ * versioned read endpoints. This module exposes a thin typed client
10
+ * for that surface so adopters fetching pack manifests, indices, or
11
+ * signature material don't roll their own HTTP plumbing.
12
+ *
13
+ * Read-only by design — the public registry uses pull-request-driven
14
+ * publishing per `spec/v1/registry-operations.md` §"Submission flow"
15
+ * + the `registry-publish.yml` GitHub workflow. There is no write API.
16
+ *
17
+ * No auth required for public reads.
18
+ *
19
+ * @module @openwop/openwop/registry-helpers
20
+ */
21
+ /** Public registry discovery payload per `registry-operations.md` §"Discovery". */
22
+ export interface RegistryDiscovery {
23
+ registryVersion: string;
24
+ protocolVersion: string;
25
+ name?: string;
26
+ operator?: string;
27
+ url?: string;
28
+ supportedNamespaces: readonly string[];
29
+ supportedSigningMethods: readonly string[];
30
+ supportedTrustModes?: readonly string[];
31
+ endpoints: {
32
+ registryIndex: string;
33
+ packMetadata: string;
34
+ versionManifest: string;
35
+ versionTarball: string;
36
+ versionSignature: string;
37
+ publicKey: string;
38
+ };
39
+ signingKeys?: ReadonlyArray<{
40
+ keyId: string;
41
+ algorithm: string;
42
+ publicKeyUrl?: string;
43
+ permittedNamespaces?: readonly string[];
44
+ operator?: string;
45
+ status?: string;
46
+ }>;
47
+ [key: string]: unknown;
48
+ }
49
+ /** Registry-wide index entry per `/v1/index.json` rows. */
50
+ export interface RegistryIndexEntry {
51
+ name: string;
52
+ latestVersion: string;
53
+ description?: string;
54
+ scope?: string;
55
+ [key: string]: unknown;
56
+ }
57
+ export interface RegistryIndex {
58
+ packs: ReadonlyArray<RegistryIndexEntry>;
59
+ generated?: string;
60
+ packCount?: number;
61
+ [key: string]: unknown;
62
+ }
63
+ /** Per-pack metadata document at `/v1/packs/{name}/index.json`. */
64
+ export interface RegistryPackMetadata {
65
+ name: string;
66
+ description?: string;
67
+ versions: ReadonlyArray<string>;
68
+ latestVersion?: string;
69
+ [key: string]: unknown;
70
+ }
71
+ /** Version manifest at `/v1/packs/{name}/-/{version}.json`. */
72
+ export interface RegistryVersionManifest {
73
+ name: string;
74
+ version: string;
75
+ description?: string;
76
+ /** SRI hash: `sha256-<43-char-b64>=`. */
77
+ integrity?: string;
78
+ signing?: {
79
+ method: 'ed25519' | 'manual' | string;
80
+ keyId: string;
81
+ publicKeyUrl?: string;
82
+ };
83
+ [key: string]: unknown;
84
+ }
85
+ export interface RegistryClientOptions {
86
+ /** Base URL for the registry. Defaults to `https://packs.openwop.dev`. */
87
+ baseUrl?: string;
88
+ /** Custom fetch implementation; defaults to `globalThis.fetch`. */
89
+ fetch?: typeof fetch;
90
+ }
91
+ /**
92
+ * Typed client for the public OpenWOP node-pack registry. Read-only;
93
+ * no auth required for the canonical public read surface.
94
+ *
95
+ * For host-side install-time verification (SRI + Ed25519 + lockfile),
96
+ * see `examples/hosts/postgres/src/pack-consumer.ts` — the registry
97
+ * client is the fetch surface; the consumer is the security surface.
98
+ */
99
+ export declare class RegistryClient {
100
+ #private;
101
+ readonly baseUrl: string;
102
+ constructor(options?: RegistryClientOptions);
103
+ /** `GET /.well-known/openwop-registry` — discovery + endpoint catalog. */
104
+ discovery(): Promise<RegistryDiscovery>;
105
+ /** `GET /v1/index.json` — registry-wide pack index. */
106
+ index(): Promise<RegistryIndex>;
107
+ /** `GET /v1/packs/{name}/index.json` — per-pack metadata. */
108
+ pack(name: string): Promise<RegistryPackMetadata>;
109
+ /** `GET /v1/packs/{name}/-/{version}.json` — version manifest. */
110
+ version(name: string, version: string): Promise<RegistryVersionManifest>;
111
+ /** Fetch raw tarball bytes. Caller MUST verify SRI + signature before trust. */
112
+ tarball(name: string, version: string): Promise<Buffer>;
113
+ /** Fetch raw 64-byte Ed25519 signature bytes. */
114
+ signature(name: string, version: string): Promise<Buffer>;
115
+ /** Fetch a publisher's public key as PEM text. */
116
+ publicKey(keyId: string): Promise<string>;
117
+ }
118
+ //# sourceMappingURL=registry-helpers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry-helpers.d.ts","sourceRoot":"","sources":["../src/registry-helpers.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,82 @@
1
+ /**
2
+ * Public-registry read helpers per
3
+ * `spec/v1/registry-operations.md`.
4
+ *
5
+ * The OpenWOP host SDK targets the host wire surface
6
+ * (`/.well-known/openwop` + `/v1/runs/*` + `/v1/interrupts/*` etc).
7
+ * The **public node-pack registry** at `packs.openwop.dev` is a
8
+ * separate wire surface with its own discovery payload and pack-
9
+ * versioned read endpoints. This module exposes a thin typed client
10
+ * for that surface so adopters fetching pack manifests, indices, or
11
+ * signature material don't roll their own HTTP plumbing.
12
+ *
13
+ * Read-only by design — the public registry uses pull-request-driven
14
+ * publishing per `spec/v1/registry-operations.md` §"Submission flow"
15
+ * + the `registry-publish.yml` GitHub workflow. There is no write API.
16
+ *
17
+ * No auth required for public reads.
18
+ *
19
+ * @module @openwop/openwop/registry-helpers
20
+ */
21
+ /**
22
+ * Typed client for the public OpenWOP node-pack registry. Read-only;
23
+ * no auth required for the canonical public read surface.
24
+ *
25
+ * For host-side install-time verification (SRI + Ed25519 + lockfile),
26
+ * see `examples/hosts/postgres/src/pack-consumer.ts` — the registry
27
+ * client is the fetch surface; the consumer is the security surface.
28
+ */
29
+ export class RegistryClient {
30
+ baseUrl;
31
+ #fetch;
32
+ constructor(options = {}) {
33
+ this.baseUrl = (options.baseUrl ?? 'https://packs.openwop.dev').replace(/\/$/, '');
34
+ this.#fetch = options.fetch ?? globalThis.fetch.bind(globalThis);
35
+ }
36
+ /** `GET /.well-known/openwop-registry` — discovery + endpoint catalog. */
37
+ async discovery() {
38
+ return this.#getJson('/.well-known/openwop-registry');
39
+ }
40
+ /** `GET /v1/index.json` — registry-wide pack index. */
41
+ async index() {
42
+ return this.#getJson('/v1/index.json');
43
+ }
44
+ /** `GET /v1/packs/{name}/index.json` — per-pack metadata. */
45
+ async pack(name) {
46
+ return this.#getJson(`/v1/packs/${encodeURIComponent(name)}/index.json`);
47
+ }
48
+ /** `GET /v1/packs/{name}/-/{version}.json` — version manifest. */
49
+ async version(name, version) {
50
+ return this.#getJson(`/v1/packs/${encodeURIComponent(name)}/-/${encodeURIComponent(version)}.json`);
51
+ }
52
+ /** Fetch raw tarball bytes. Caller MUST verify SRI + signature before trust. */
53
+ async tarball(name, version) {
54
+ return this.#getBinary(`/v1/packs/${encodeURIComponent(name)}/-/${encodeURIComponent(version)}.tgz`);
55
+ }
56
+ /** Fetch raw 64-byte Ed25519 signature bytes. */
57
+ async signature(name, version) {
58
+ return this.#getBinary(`/v1/packs/${encodeURIComponent(name)}/-/${encodeURIComponent(version)}.sig`);
59
+ }
60
+ /** Fetch a publisher's public key as PEM text. */
61
+ async publicKey(keyId) {
62
+ const res = await this.#fetch(`${this.baseUrl}/keys/${encodeURIComponent(keyId)}.pub`);
63
+ if (!res.ok)
64
+ throw new Error(`registry: GET /keys/${keyId}.pub returned ${res.status}`);
65
+ return res.text();
66
+ }
67
+ async #getJson(path) {
68
+ const res = await this.#fetch(`${this.baseUrl}${path}`, {
69
+ headers: { Accept: 'application/json' },
70
+ });
71
+ if (!res.ok)
72
+ throw new Error(`registry: GET ${path} returned ${res.status}`);
73
+ return (await res.json());
74
+ }
75
+ async #getBinary(path) {
76
+ const res = await this.#fetch(`${this.baseUrl}${path}`);
77
+ if (!res.ok)
78
+ throw new Error(`registry: GET ${path} returned ${res.status}`);
79
+ return Buffer.from(await res.arrayBuffer());
80
+ }
81
+ }
82
+ //# sourceMappingURL=registry-helpers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry-helpers.js","sourceRoot":"","sources":["../src/registry-helpers.ts"],"names":[],"mappings":"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"}