@graphorin/core 0.6.1 → 0.7.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.
Files changed (110) hide show
  1. package/CHANGELOG.md +82 -0
  2. package/README.md +8 -5
  3. package/dist/channels/index.d.ts +2 -2
  4. package/dist/channels/index.js +2 -2
  5. package/dist/channels/pause.d.ts +47 -2
  6. package/dist/channels/pause.d.ts.map +1 -1
  7. package/dist/channels/pause.js +62 -2
  8. package/dist/channels/pause.js.map +1 -1
  9. package/dist/contracts/checkpoint-store.d.ts +97 -1
  10. package/dist/contracts/checkpoint-store.d.ts.map +1 -1
  11. package/dist/contracts/checkpoint-store.js.map +1 -1
  12. package/dist/contracts/index.d.ts +5 -5
  13. package/dist/contracts/index.js +2 -1
  14. package/dist/contracts/memory-store.d.ts +59 -2
  15. package/dist/contracts/memory-store.d.ts.map +1 -1
  16. package/dist/contracts/provider.d.ts +20 -6
  17. package/dist/contracts/provider.d.ts.map +1 -1
  18. package/dist/contracts/session-store.d.ts +10 -2
  19. package/dist/contracts/session-store.d.ts.map +1 -1
  20. package/dist/contracts/tool.d.ts +75 -1
  21. package/dist/contracts/tool.d.ts.map +1 -1
  22. package/dist/contracts/tool.js +57 -0
  23. package/dist/contracts/tool.js.map +1 -0
  24. package/dist/contracts/tracer.d.ts +53 -5
  25. package/dist/contracts/tracer.d.ts.map +1 -1
  26. package/dist/contracts/tracer.js.map +1 -1
  27. package/dist/index.d.ts +9 -7
  28. package/dist/index.d.ts.map +1 -1
  29. package/dist/index.js +5 -5
  30. package/dist/package.js +1 -1
  31. package/dist/package.js.map +1 -1
  32. package/dist/types/agent-event-wire.d.ts +74 -0
  33. package/dist/types/agent-event-wire.d.ts.map +1 -0
  34. package/dist/types/agent-event-wire.js +130 -0
  35. package/dist/types/agent-event-wire.js.map +1 -0
  36. package/dist/types/agent-event.d.ts +48 -6
  37. package/dist/types/agent-event.d.ts.map +1 -1
  38. package/dist/types/index.d.ts +3 -2
  39. package/dist/types/index.js +2 -1
  40. package/dist/types/memory.d.ts +11 -0
  41. package/dist/types/memory.d.ts.map +1 -1
  42. package/dist/types/run.d.ts +86 -4
  43. package/dist/types/run.d.ts.map +1 -1
  44. package/dist/types/run.js.map +1 -1
  45. package/dist/types/tool.d.ts +10 -0
  46. package/dist/types/tool.d.ts.map +1 -1
  47. package/dist/types/usage.d.ts +11 -1
  48. package/dist/types/usage.d.ts.map +1 -1
  49. package/dist/types/usage.js.map +1 -1
  50. package/dist/utils/binary-json.d.ts +165 -0
  51. package/dist/utils/binary-json.d.ts.map +1 -0
  52. package/dist/utils/binary-json.js +240 -0
  53. package/dist/utils/binary-json.js.map +1 -0
  54. package/dist/utils/index.d.ts +2 -1
  55. package/dist/utils/index.js +2 -1
  56. package/dist/utils/validation.d.ts +10 -1
  57. package/dist/utils/validation.d.ts.map +1 -1
  58. package/dist/utils/validation.js +1 -1
  59. package/dist/utils/validation.js.map +1 -1
  60. package/package.json +9 -7
  61. package/src/channels/channels.ts +206 -0
  62. package/src/channels/directive.ts +41 -0
  63. package/src/channels/dispatch.ts +37 -0
  64. package/src/channels/durable.ts +151 -0
  65. package/src/channels/index.ts +62 -0
  66. package/src/channels/pause.ts +216 -0
  67. package/src/contracts/auth-token-store.ts +42 -0
  68. package/src/contracts/checkpoint-store.ts +256 -0
  69. package/src/contracts/embedder.ts +42 -0
  70. package/src/contracts/eval-scorer.ts +44 -0
  71. package/src/contracts/index.ts +112 -0
  72. package/src/contracts/local-provider-trust.ts +33 -0
  73. package/src/contracts/logger.ts +61 -0
  74. package/src/contracts/memory-store.ts +187 -0
  75. package/src/contracts/oauth-server-store.ts +78 -0
  76. package/src/contracts/preferred-model.ts +56 -0
  77. package/src/contracts/provider.ts +316 -0
  78. package/src/contracts/reasoning-retention.ts +52 -0
  79. package/src/contracts/redaction-validator.ts +56 -0
  80. package/src/contracts/sandbox.ts +70 -0
  81. package/src/contracts/secret-ref.ts +22 -0
  82. package/src/contracts/secret-value.ts +117 -0
  83. package/src/contracts/secrets-store.ts +90 -0
  84. package/src/contracts/session-store.ts +163 -0
  85. package/src/contracts/token-counter.ts +23 -0
  86. package/src/contracts/tool.ts +397 -0
  87. package/src/contracts/tracer.ts +219 -0
  88. package/src/contracts/trigger-store.ts +40 -0
  89. package/src/index.ts +23 -0
  90. package/src/types/agent-event-wire.ts +193 -0
  91. package/src/types/agent-event.ts +579 -0
  92. package/src/types/handoff.ts +111 -0
  93. package/src/types/index.ts +148 -0
  94. package/src/types/memory.ts +427 -0
  95. package/src/types/message.ts +174 -0
  96. package/src/types/run.ts +312 -0
  97. package/src/types/sensitivity.ts +35 -0
  98. package/src/types/session-scope.ts +18 -0
  99. package/src/types/stop-condition.ts +108 -0
  100. package/src/types/tool-call.ts +24 -0
  101. package/src/types/tool.ts +324 -0
  102. package/src/types/usage.ts +120 -0
  103. package/src/types/workflow-event.ts +132 -0
  104. package/src/utils/assert-never.ts +24 -0
  105. package/src/utils/async-context.ts +55 -0
  106. package/src/utils/binary-json.ts +425 -0
  107. package/src/utils/hash.ts +122 -0
  108. package/src/utils/index.ts +57 -0
  109. package/src/utils/streams.ts +233 -0
  110. package/src/utils/validation.ts +82 -0
@@ -0,0 +1,316 @@
1
+ import type { Message, ReasoningContentMeta } from '../types/message.js';
2
+ import type { Sensitivity } from '../types/sensitivity.js';
3
+ import type { ToolCall } from '../types/tool-call.js';
4
+ import type { Usage } from '../types/usage.js';
5
+ import type { ReasoningContract, ReasoningRetention } from './reasoning-retention.js';
6
+
7
+ /**
8
+ * Vendor-neutral LLM provider interface. Concrete adapters live in
9
+ * `@graphorin/provider` (and companion packages such as
10
+ * `@graphorin/provider-llamacpp-node`).
11
+ *
12
+ * Every provider exposes a `name` (used in spans / logs), the `modelId`
13
+ * it wraps, a static `capabilities` descriptor, and the two streaming /
14
+ * one-shot generation methods.
15
+ *
16
+ * @stable
17
+ */
18
+ export interface Provider {
19
+ readonly name: string;
20
+ readonly modelId: string;
21
+ readonly capabilities: ProviderCapabilities;
22
+
23
+ /** Returns an async stream of fine-grained provider events. */
24
+ stream(req: ProviderRequest): AsyncIterable<ProviderEvent>;
25
+
26
+ /** Convenience wrapper that consumes the stream into a single result. */
27
+ generate(req: ProviderRequest): Promise<ProviderResponse>;
28
+
29
+ /** Optional: provider-native input token counter. */
30
+ countTokens?(req: ProviderRequest): Promise<number>;
31
+
32
+ /**
33
+ * Sensitivity tiers this provider is allowed to receive. Used by the
34
+ * ContextEngine sensitivity filter (D2) and the outbound redaction
35
+ * middleware (D3) to decide what content is safe to forward.
36
+ */
37
+ readonly acceptsSensitivity?: ReadonlyArray<Sensitivity>;
38
+ }
39
+
40
+ /**
41
+ * Static capability descriptor returned by `Provider.capabilities`.
42
+ *
43
+ * @stable
44
+ */
45
+ export interface ProviderCapabilities {
46
+ readonly streaming: boolean;
47
+ readonly toolCalling: boolean;
48
+ readonly parallelToolCalls: boolean;
49
+ readonly multimodal: boolean;
50
+ readonly structuredOutput: boolean;
51
+ readonly reasoning: boolean;
52
+ /** Total context window in tokens. */
53
+ readonly contextWindow: number;
54
+ /** Maximum output tokens. */
55
+ readonly maxOutput: number;
56
+ /**
57
+ * How the provider treats reasoning content across consecutive
58
+ * `provider.stream(...)` calls. Drives the auto-detected default
59
+ * {@link ReasoningRetention} value when the caller does not pass
60
+ * an explicit override on the request.
61
+ *
62
+ * Adapters supplied with the framework declare this field; bespoke
63
+ * adapters that omit it are treated as `'optional'` (conservative
64
+ * `'strip'` default + WARN-once on first reasoning emission).
65
+ */
66
+ readonly reasoningContract?: ReasoningContract;
67
+ }
68
+
69
+ /**
70
+ * Opt-in prompt-cache breakpoint policy (core-provider-02).
71
+ *
72
+ * `breakpoints: 'auto'` asks the adapter to place provider-native cache
73
+ * anchors around the stable request prefix: the Anthropic path (via the
74
+ * vercel adapter) marks the first and last conversation messages with
75
+ * `cache_control: { type: 'ephemeral' }` so tools + system + the stable
76
+ * prefix are written once and read at ~0.1x input price on subsequent
77
+ * steps. Providers with automatic caching (OpenAI) or no cache concept
78
+ * ignore the policy. `ttl` maps to Anthropic's extended cache TTL.
79
+ *
80
+ * @stable
81
+ */
82
+ export interface ProviderCachePolicy {
83
+ readonly breakpoints: 'auto' | 'none';
84
+ readonly ttl?: '5m' | '1h';
85
+ }
86
+
87
+ /**
88
+ * Provider-call request payload.
89
+ *
90
+ * @stable
91
+ */
92
+ export interface ProviderRequest {
93
+ readonly messages: ReadonlyArray<Message>;
94
+ readonly tools?: ReadonlyArray<ToolDefinition>;
95
+ readonly toolChoice?: ToolChoice;
96
+ readonly outputType?: OutputSpec;
97
+ readonly systemMessage?: string;
98
+ readonly temperature?: number;
99
+ readonly maxTokens?: number;
100
+ readonly signal?: AbortSignal;
101
+ readonly providerOptions?: Readonly<Record<string, unknown>>;
102
+ readonly cachePolicy?: ProviderCachePolicy;
103
+ /**
104
+ * C7: live parent span for the provider call. Like `signal`, this is a
105
+ * runtime handle (never serialized): `withTracing` parents its
106
+ * provider.generate/stream span under it so a run's traces form one
107
+ * tree instead of disconnected fragments.
108
+ */
109
+ readonly parentSpan?: import('./tracer.js').AISpan;
110
+ readonly metadata?: ProviderRequestMetadata;
111
+ /**
112
+ * Per-request override of the provider's auto-detected
113
+ * {@link ReasoningRetention} default. Only honoured when the
114
+ * provider declares `reasoningContract` of `'round-trip-required'`
115
+ * or `'optional'`; hidden-chain-of-thought providers (e.g.
116
+ * `'hidden'`) always strip and emit one WARN per process when an
117
+ * incompatible override is supplied.
118
+ */
119
+ readonly reasoningRetention?: ReasoningRetention;
120
+ }
121
+
122
+ /**
123
+ * Per-request metadata used by tracing and auditing layers.
124
+ *
125
+ * @stable
126
+ */
127
+ export interface ProviderRequestMetadata {
128
+ readonly sessionId?: string;
129
+ readonly agentId?: string;
130
+ readonly userId?: string;
131
+ readonly runId?: string;
132
+ readonly stepNumber?: number;
133
+ }
134
+
135
+ /**
136
+ * One-shot response shape returned by `Provider.generate(...)`.
137
+ *
138
+ * @stable
139
+ */
140
+ export interface ProviderResponse {
141
+ readonly text?: string;
142
+ /**
143
+ * Tool invocations the model requested. W-127: reuses the canonical
144
+ * {@link ToolCall} (the inline shape here was structurally identical
145
+ * and only invited drift).
146
+ */
147
+ readonly toolCalls?: ReadonlyArray<ToolCall>;
148
+ readonly usage: Usage;
149
+ readonly finishReason: FinishReason;
150
+ readonly providerMetadata?: Readonly<Record<string, unknown>>;
151
+ }
152
+
153
+ /**
154
+ * Reason a provider call ended.
155
+ *
156
+ * @stable
157
+ */
158
+ export type FinishReason =
159
+ | 'stop'
160
+ | 'length'
161
+ | 'tool-calls'
162
+ | 'content-filter'
163
+ | 'error'
164
+ | 'aborted';
165
+
166
+ /**
167
+ * Streamed provider event. Shape matches the wire-stable subset of the
168
+ * provider event union - adapters hide vendor specifics.
169
+ *
170
+ * @stable
171
+ */
172
+ export type ProviderEvent =
173
+ | { readonly type: 'stream-start'; readonly metadata: ResponseMetadata }
174
+ | { readonly type: 'reasoning-delta'; readonly delta: string }
175
+ /**
176
+ * Closes the current reasoning block (W-024). Deltas stay textual;
177
+ * this terminator carries the provider's opaque round-trip metadata
178
+ * (e.g. the Anthropic thinking-block `signature`, or `data` for a
179
+ * redacted block) so multi-step tool use with extended thinking can
180
+ * replay the block byte-equal on the next request. Adapters without
181
+ * per-block structure simply never emit it - consumers fall back to
182
+ * collapsing the deltas.
183
+ */
184
+ | { readonly type: 'reasoning-end'; readonly meta?: ReasoningContentMeta }
185
+ | { readonly type: 'text-delta'; readonly delta: string }
186
+ | { readonly type: 'tool-call-start'; readonly toolCallId: string; readonly toolName: string }
187
+ | {
188
+ readonly type: 'tool-call-input-delta';
189
+ readonly toolCallId: string;
190
+ readonly argsDelta: string;
191
+ }
192
+ | { readonly type: 'tool-call-end'; readonly toolCallId: string; readonly finalArgs: unknown }
193
+ | { readonly type: 'file'; readonly mimeType: string; readonly data: Uint8Array }
194
+ | { readonly type: 'source'; readonly uri: string; readonly title?: string }
195
+ | { readonly type: 'finish'; readonly finishReason: FinishReason; readonly usage: Usage }
196
+ | { readonly type: 'error'; readonly error: ProviderError };
197
+
198
+ /**
199
+ * Metadata attached to the first `stream-start` event of a stream.
200
+ *
201
+ * @stable
202
+ */
203
+ export interface ResponseMetadata {
204
+ readonly providerName: string;
205
+ readonly modelId: string;
206
+ readonly responseId?: string;
207
+ readonly createdAt?: string;
208
+ }
209
+
210
+ /**
211
+ * Provider-side error shape carried by `provider-error` events.
212
+ *
213
+ * @stable
214
+ */
215
+ export interface ProviderError {
216
+ readonly kind: ProviderErrorKind;
217
+ readonly message: string;
218
+ readonly cause?: unknown;
219
+ }
220
+
221
+ /** @stable */
222
+ export type ProviderErrorKind =
223
+ | 'rate-limit'
224
+ | 'capacity'
225
+ | 'context-length'
226
+ | 'transient'
227
+ | 'invalid-request'
228
+ | 'unauthorized'
229
+ | 'content-filter'
230
+ | 'unknown';
231
+
232
+ /**
233
+ * Tool description shipped with a provider request. Implementations
234
+ * convert the user's Zod schema to a JSON Schema 7 fragment.
235
+ *
236
+ * @stable
237
+ */
238
+ export interface ToolDefinition {
239
+ readonly name: string;
240
+ readonly description?: string;
241
+ readonly inputSchema: Readonly<Record<string, unknown>>;
242
+ /**
243
+ * A5: the tool's output schema (JSON Schema), when declared. The agent runtime
244
+ * populates it from `Tool.outputSchema`; structured-output providers and typed
245
+ * code-mode use it to validate / type the tool's result. Absent when the tool
246
+ * declares no output schema.
247
+ */
248
+ readonly outputSchema?: Readonly<Record<string, unknown>>;
249
+ /**
250
+ * Worked examples surfaced to the provider alongside the schema. The
251
+ * agent runtime populates this from the tool's `examples` when they
252
+ * are eagerly rendered (see `Tool.examplesEagerlyRendered`); it is
253
+ * bounded to ≤5 and absent when the tool declares none or defers them.
254
+ * Implementations MAY fold these into the model-facing tool description.
255
+ */
256
+ readonly examples?: ReadonlyArray<ToolDefinitionExample>;
257
+ }
258
+
259
+ /**
260
+ * A single worked example as projected onto the provider wire contract -
261
+ * a serializable, schema-agnostic view of a `ToolExample`. `input` /
262
+ * `output` carry the example's already-parsed values; `comment` is the
263
+ * optional rationale shown to the model.
264
+ *
265
+ * @stable
266
+ */
267
+ export interface ToolDefinitionExample {
268
+ readonly input: unknown;
269
+ readonly output: unknown;
270
+ readonly comment?: string;
271
+ }
272
+
273
+ /**
274
+ * Tool selection strategy.
275
+ *
276
+ * @stable
277
+ */
278
+ export type ToolChoice = 'auto' | 'required' | 'none' | { readonly tool: string };
279
+
280
+ /**
281
+ * Output type specification for structured / typed responses. Concrete
282
+ * Zod-based variants live in the runtime packages.
283
+ *
284
+ * @stable
285
+ */
286
+ export interface OutputSpec {
287
+ readonly kind: 'text' | 'structured';
288
+ readonly description?: string;
289
+ readonly jsonSchema?: Readonly<Record<string, unknown>>;
290
+ }
291
+
292
+ /**
293
+ * Provider middleware: a function that wraps a `Provider` and returns a
294
+ * new `Provider` with extra behaviour (retry, fallback, redaction, …).
295
+ *
296
+ * Middleware ordering is enforced by the runtime per the documented
297
+ * inside-out chain (innermost adapter → ... → outermost retry / observer).
298
+ *
299
+ * @stable
300
+ */
301
+ export type ProviderMiddleware = (next: Provider) => Provider;
302
+
303
+ /**
304
+ * Type signature for the canonical middleware composer (the runtime
305
+ * implementation lives in `@graphorin/provider`).
306
+ *
307
+ * The concrete composer guarantees a deterministic ordering - order of
308
+ * arguments mirrors order of execution from outermost to innermost - and
309
+ * is the only blessed entry point for chaining middleware in
310
+ * `@graphorin/*` code (per the security-first ordering rule).
311
+ *
312
+ * @stable
313
+ */
314
+ export type ComposeProviderMiddleware = (
315
+ middlewares: ReadonlyArray<ProviderMiddleware>,
316
+ ) => ProviderMiddleware;
@@ -0,0 +1,52 @@
1
+ /**
2
+ * How a provider treats reasoning content across consecutive
3
+ * `provider.stream(...)` calls of the same agent + same model + same
4
+ * run.
5
+ *
6
+ * Three independent lifecycle operations exist for reasoning content
7
+ * in the provider layer:
8
+ *
9
+ * 1. **Intra-loop transmission** - controlled by this enum. Default is
10
+ * auto-detected per provider:
11
+ * - Hidden chain-of-thought providers (e.g. OpenAI o1/o3, Google
12
+ * Gemini reasoning): `'strip'`.
13
+ * - Round-trip-required providers (e.g. Anthropic Claude tool-use
14
+ * with thinking blocks): `'pass-through-claude'`.
15
+ * 2. **Sub-agent handoff transmission** - always strips reasoning
16
+ * regardless of this setting; lives in
17
+ * `@graphorin/sessions` handoff filters.
18
+ * 3. **Prompt-cache key calculation** - reasoning blocks are excluded
19
+ * from cache-key hashes but included in outbound transmission.
20
+ *
21
+ * @stable
22
+ */
23
+ export type ReasoningRetention =
24
+ /**
25
+ * Drop reasoning content from the next request body. Default for
26
+ * hidden-chain-of-thought providers and the conservative default
27
+ * for unknown providers.
28
+ */
29
+ | 'strip'
30
+ /**
31
+ * Round-trip Anthropic-shaped thinking blocks
32
+ * (`signature` / `data` / `text` fields) byte-equal to the previous
33
+ * assistant message.
34
+ */
35
+ | 'pass-through-claude'
36
+ /**
37
+ * Round-trip every reasoning content part the provider returns
38
+ * regardless of vendor shape. Useful for custom providers that
39
+ * declare `reasoningContract: 'optional'` and still benefit from
40
+ * preserving the chain.
41
+ */
42
+ | 'pass-through-all';
43
+
44
+ /**
45
+ * Capability declaration on `ProviderCapabilities` describing how the
46
+ * provider treats reasoning content. The field is auto-populated per
47
+ * provider family by the adapter; consumers use it to infer the
48
+ * default {@link ReasoningRetention} value for a request.
49
+ *
50
+ * @stable
51
+ */
52
+ export type ReasoningContract = 'hidden' | 'round-trip-required' | 'optional';
@@ -0,0 +1,56 @@
1
+ import type { Sensitivity } from '../types/sensitivity.js';
2
+
3
+ /**
4
+ * Wraps every observability exporter (OTLP, console, JSONL replay log,
5
+ * …) and refuses to forward attributes that exceed the configured
6
+ * sensitivity floor or that contain matched secret / PII patterns.
7
+ *
8
+ * Concrete patterns and the default policy live in
9
+ * `@graphorin/observability`; the interface lives here so every package
10
+ * (server, agent, workflow, …) can require a `RedactionValidator` in its
11
+ * config without taking an observability dependency.
12
+ *
13
+ * @stable
14
+ */
15
+ export interface RedactionValidator {
16
+ /** Identifier of the policy in use (`'default-deny-internal'`, …). */
17
+ readonly id: string;
18
+ /** Lowest tier that may pass through the validator. */
19
+ readonly minTier: Sensitivity;
20
+ /**
21
+ * Validate (and optionally rewrite) an attribute payload. Returns the
22
+ * sanitized value or `null` if the entire record must be dropped.
23
+ */
24
+ validate(input: RedactionInput): RedactionOutput | null;
25
+ }
26
+
27
+ /**
28
+ * Input handed to `RedactionValidator.validate(...)`.
29
+ *
30
+ * @stable
31
+ */
32
+ export interface RedactionInput {
33
+ readonly value: unknown;
34
+ /** Tier declared by the upstream caller for this value. */
35
+ readonly tier: Sensitivity;
36
+ /** Optional context describing where the value originated. */
37
+ readonly context?: {
38
+ readonly attribute?: string;
39
+ readonly spanType?: string;
40
+ readonly origin?: string;
41
+ };
42
+ }
43
+
44
+ /**
45
+ * Result of `RedactionValidator.validate(...)` - either the sanitized
46
+ * payload (possibly equal to the input) or `null` if the value must be
47
+ * dropped entirely.
48
+ *
49
+ * @stable
50
+ */
51
+ export interface RedactionOutput {
52
+ readonly value: unknown;
53
+ readonly tier: Sensitivity;
54
+ /** List of pattern names matched while validating. */
55
+ readonly matched?: ReadonlyArray<string>;
56
+ }
@@ -0,0 +1,70 @@
1
+ /**
2
+ * Pluggable sandbox interface for tool / skill execution. Concrete
3
+ * implementations live in `@graphorin/security` (worker-threads,
4
+ * isolated-vm, docker, none).
5
+ *
6
+ * @stable
7
+ */
8
+ export interface Sandbox {
9
+ /** Identifier of the sandbox flavor (`'worker-threads'`, `'isolated-vm'`, …). */
10
+ readonly id: string;
11
+ run<TInput, TOutput>(
12
+ code: SandboxCode,
13
+ opts: SandboxRunOptions<TInput>,
14
+ ): Promise<SandboxResult<TOutput>>;
15
+ }
16
+
17
+ /**
18
+ * Description of the code to run in the sandbox. Either a JS source
19
+ * string, a path to a JS file, or a fully-qualified handler reference
20
+ * resolved by the sandbox implementation.
21
+ *
22
+ * @stable
23
+ */
24
+ export type SandboxCode =
25
+ | { readonly kind: 'source'; readonly source: string; readonly filename?: string }
26
+ | { readonly kind: 'file'; readonly path: string }
27
+ | { readonly kind: 'handler'; readonly module: string; readonly export: string };
28
+
29
+ /**
30
+ * Per-call sandbox options.
31
+ *
32
+ * @stable
33
+ */
34
+ export interface SandboxRunOptions<TInput = unknown> {
35
+ readonly input: TInput;
36
+ readonly timeoutMs?: number;
37
+ readonly maxMemoryMb?: number;
38
+ /**
39
+ * Allowlist of environment variables visible inside the sandbox.
40
+ * Sandboxed code never inherits the host `process.env`; entries
41
+ * given here are the only ones defined.
42
+ */
43
+ readonly env?: Readonly<Record<string, string>>;
44
+ readonly allowNetwork?: boolean;
45
+ readonly allowFs?: boolean;
46
+ readonly signal?: AbortSignal;
47
+ }
48
+
49
+ /**
50
+ * Result of a sandboxed run. The shape mirrors the `ToolOutcome` union -
51
+ * the runtime maps `SandboxResult` to `ToolOutcome` after the call.
52
+ *
53
+ * @stable
54
+ */
55
+ export type SandboxResult<TOutput = unknown> =
56
+ | { readonly ok: true; readonly output: TOutput; readonly durationMs: number }
57
+ | {
58
+ readonly ok: false;
59
+ readonly error: {
60
+ readonly kind:
61
+ | 'timeout'
62
+ | 'memory-exceeded'
63
+ | 'sandbox-violation'
64
+ | 'aborted'
65
+ | 'execution-failed';
66
+ readonly message: string;
67
+ readonly cause?: unknown;
68
+ };
69
+ readonly durationMs: number;
70
+ };
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Parsed shape of a `SecretRef` URI (`scheme:[//authority]/path[?query][#fragment]`).
3
+ *
4
+ * The full grammar lives in `@graphorin/security`; the type lives here so
5
+ * downstream packages can carry parsed refs without a security dependency.
6
+ *
7
+ * @stable
8
+ */
9
+ export interface SecretRef {
10
+ /** Original URI string as supplied by the caller. */
11
+ readonly raw: string;
12
+ /** Lowercased scheme (`'env'`, `'keyring'`, `'file'`, …). */
13
+ readonly scheme: string;
14
+ /** Optional authority component (e.g. `host[:port]`). */
15
+ readonly authority?: string;
16
+ /** Path component (without the leading slash for opaque schemes). */
17
+ readonly path: string;
18
+ /** Parsed query parameters (already percent-decoded). */
19
+ readonly query: Readonly<Record<string, string>>;
20
+ /** Optional fragment (e.g. JSON-Pointer for nested fields). */
21
+ readonly fragment?: string;
22
+ }
@@ -0,0 +1,117 @@
1
+ /**
2
+ * Cross-realm symbol used to brand `SecretValue` instances. Implementations
3
+ * (e.g. the wrapper class shipped from `@graphorin/security`) attach this
4
+ * symbol so that `isSecretValue(...)` works across realms (Worker threads,
5
+ * sandboxes, etc.).
6
+ *
7
+ * @stable
8
+ */
9
+ export const SECRET_VALUE_BRAND: unique symbol = Symbol.for('graphorin.SecretValue');
10
+
11
+ /**
12
+ * Well-known symbol used by `node:util.inspect()` to format the wrapper.
13
+ * Re-exported here so downstream packages can reference it without taking
14
+ * an unconditional dependency on `node:util`.
15
+ *
16
+ * Equivalent to `Symbol.for('nodejs.util.inspect.custom')`.
17
+ *
18
+ * @stable
19
+ */
20
+ export const NODEJS_INSPECT_CUSTOM: unique symbol = Symbol.for('nodejs.util.inspect.custom');
21
+
22
+ /**
23
+ * Runtime-safe wrapper around an opaque secret (API key, token, password).
24
+ *
25
+ * The shape declared here is the **interface contract**: the concrete
26
+ * wrapper class lives in `@graphorin/security`. Downstream packages typing
27
+ * a parameter as `SecretValue` therefore avoid taking a security
28
+ * dependency.
29
+ *
30
+ * Note: `SecretValue` is **not** a TypeScript branded primitive - it is
31
+ * a full wrapper class with explicit leakage barriers
32
+ * (`Symbol.toPrimitive`, `toJSON`, `[nodejs.util.inspect.custom]`, …).
33
+ * Any conforming implementation must ensure that:
34
+ *
35
+ * - String coercion (`String(s)`, `` `${s}` ``, `s + ''`, …) yields a
36
+ * redacted placeholder, **not** the underlying value.
37
+ * - JSON serialization (`JSON.stringify({ apiKey: s })`) yields a
38
+ * redacted placeholder.
39
+ * - Inspector output (`util.inspect(s)`) yields
40
+ * `'SecretValue([REDACTED])'`.
41
+ * - The underlying value is only reachable through `.use(fn)`,
42
+ * `.useBuffer(fn)` or the audited `.reveal()` escape hatch.
43
+ *
44
+ * @stable
45
+ */
46
+ export interface SecretValue {
47
+ /** Number of bytes in the wrapped value. Safe to log. */
48
+ readonly length: number;
49
+
50
+ /**
51
+ * Run `fn` with the unwrapped string and return its result. Preferred
52
+ * over `.reveal()` because it scopes the unwrapped value to a single
53
+ * synchronous / asynchronous turn.
54
+ */
55
+ use<T>(fn: (raw: string) => T | Promise<T>): Promise<T>;
56
+
57
+ /**
58
+ * Run `fn` with the unwrapped value as a `Buffer`. Useful for binary
59
+ * secrets (encryption keys, HMAC keys) where round-tripping through a
60
+ * V8 string would defeat the wrapper's hygiene.
61
+ */
62
+ useBuffer<T>(fn: (buf: Buffer) => T | Promise<T>): Promise<T>;
63
+
64
+ /**
65
+ * One-shot reveal as a string. Audited by the implementation. Prefer
66
+ * `.use(fn)` whenever possible.
67
+ */
68
+ reveal(): string;
69
+
70
+ /**
71
+ * Best-effort zeroization of the underlying buffer. Does not affect
72
+ * derived V8 strings already created via `.use(fn)` / `.reveal()`.
73
+ */
74
+ dispose(): void;
75
+
76
+ /** Cross-realm brand. Implementations set this to `SECRET_VALUE_BRAND`. */
77
+ readonly [SECRET_VALUE_BRAND]: true;
78
+
79
+ /** Leakage barrier for ToPrimitive coercion. Returns the placeholder. */
80
+ [Symbol.toPrimitive](hint: string): string | number;
81
+
82
+ /** Leakage barrier for `JSON.stringify(...)`. Returns the placeholder. */
83
+ toJSON(): string;
84
+
85
+ /**
86
+ * Leakage barrier for `node:util.inspect(...)`. Returns the placeholder
87
+ * (`'SecretValue([REDACTED])'`) so that REPL / `console.log` /
88
+ * structured-logger output never reveals the underlying value.
89
+ */
90
+ [NODEJS_INSPECT_CUSTOM](depth?: number, opts?: unknown, inspect?: unknown): string;
91
+ }
92
+
93
+ /**
94
+ * Static helpers expected on every concrete `SecretValue` constructor.
95
+ *
96
+ * @stable
97
+ */
98
+ export interface SecretValueStatic {
99
+ /** Cross-realm safe type guard. */
100
+ isSecretValue(value: unknown): value is SecretValue;
101
+ /** Constant-time equality. */
102
+ timingSafeEquals(a: SecretValue, b: SecretValue): boolean;
103
+ /** Construct from a plain string. */
104
+ fromString(raw: string, opts?: SecretValueOptions): SecretValue;
105
+ /** Construct from a Node.js `Buffer`. */
106
+ fromBuffer(buf: Buffer, opts?: SecretValueOptions): SecretValue;
107
+ }
108
+
109
+ /**
110
+ * Optional metadata attached to a freshly constructed `SecretValue`.
111
+ *
112
+ * @stable
113
+ */
114
+ export interface SecretValueOptions {
115
+ /** Free-form provenance string for the audit log. */
116
+ readonly source?: { readonly resolver?: string; readonly ref?: string };
117
+ }