@exaudeus/workrail 0.11.0 → 0.13.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/dist/application/services/enhanced-loop-validator.js +3 -3
- package/dist/application/services/step-output-decoder.d.ts +6 -0
- package/dist/application/services/step-output-decoder.js +49 -0
- package/dist/application/services/validation-engine.d.ts +9 -0
- package/dist/application/services/validation-engine.js +142 -18
- package/dist/application/services/workflow-interpreter.d.ts +1 -1
- package/dist/application/services/workflow-interpreter.js +147 -81
- package/dist/application/services/workflow-service.d.ts +2 -0
- package/dist/application/services/workflow-service.js +3 -3
- package/dist/application/use-cases/validate-step-output.d.ts +2 -0
- package/dist/config/feature-flags.js +1 -1
- package/dist/di/container.js +88 -0
- package/dist/di/tokens.d.ts +16 -0
- package/dist/di/tokens.js +16 -0
- package/dist/domain/execution/state.d.ts +6 -6
- package/dist/domain/workflow-id-policy.d.ts +17 -0
- package/dist/domain/workflow-id-policy.js +57 -0
- package/dist/infrastructure/storage/enhanced-multi-source-workflow-storage.js +33 -6
- package/dist/infrastructure/storage/file-workflow-storage.js +3 -1
- package/dist/infrastructure/storage/schema-validating-workflow-storage.js +13 -8
- package/dist/manifest.json +329 -161
- package/dist/mcp/error-mapper.d.ts +3 -8
- package/dist/mcp/error-mapper.js +41 -19
- package/dist/mcp/handlers/session.js +25 -11
- package/dist/mcp/handlers/v2-execution-helpers.d.ts +99 -0
- package/dist/mcp/handlers/v2-execution-helpers.js +249 -0
- package/dist/mcp/handlers/v2-execution.d.ts +4 -0
- package/dist/mcp/handlers/v2-execution.js +1044 -0
- package/dist/mcp/handlers/v2-workflow.js +21 -16
- package/dist/mcp/handlers/workflow.js +21 -12
- package/dist/mcp/index.d.ts +1 -1
- package/dist/mcp/index.js +4 -1
- package/dist/mcp/output-schemas.d.ts +411 -4
- package/dist/mcp/output-schemas.js +57 -1
- package/dist/mcp/server.d.ts +1 -1
- package/dist/mcp/server.js +96 -65
- package/dist/mcp/tool-descriptions.js +32 -15
- package/dist/mcp/tools.js +26 -14
- package/dist/mcp/types/tool-description-types.d.ts +1 -1
- package/dist/mcp/types/tool-description-types.js +7 -5
- package/dist/mcp/types.d.ts +40 -3
- package/dist/mcp/types.js +32 -3
- package/dist/mcp/v2/tool-registry.js +16 -1
- package/dist/mcp/v2/tools.d.ts +45 -0
- package/dist/mcp/v2/tools.js +21 -1
- package/dist/mcp/validation/workflow-next-prevalidate.d.ts +2 -3
- package/dist/mcp/validation/workflow-next-prevalidate.js +38 -27
- package/dist/v2/durable-core/constants.d.ts +15 -0
- package/dist/v2/durable-core/constants.js +18 -0
- package/dist/v2/durable-core/domain/ack-advance-append-plan.d.ts +32 -0
- package/dist/v2/durable-core/domain/ack-advance-append-plan.js +95 -0
- package/dist/v2/durable-core/domain/loop-runtime.d.ts +50 -0
- package/dist/v2/durable-core/domain/loop-runtime.js +95 -0
- package/dist/v2/durable-core/domain/notes-markdown.d.ts +4 -0
- package/dist/v2/durable-core/domain/notes-markdown.js +46 -0
- package/dist/v2/durable-core/domain/outputs.d.ts +12 -0
- package/dist/v2/durable-core/domain/outputs.js +18 -0
- package/dist/v2/durable-core/ids/index.d.ts +2 -0
- package/dist/v2/durable-core/ids/index.js +4 -0
- package/dist/v2/durable-core/schemas/compiled-workflow/index.d.ts +100 -6
- package/dist/v2/durable-core/schemas/compiled-workflow/index.js +18 -3
- package/dist/v2/durable-core/schemas/execution-snapshot/execution-snapshot.v1.d.ts +113 -113
- package/dist/v2/durable-core/schemas/execution-snapshot/execution-snapshot.v1.js +11 -10
- package/dist/v2/durable-core/schemas/export-bundle/index.d.ts +7129 -0
- package/dist/v2/durable-core/schemas/export-bundle/index.js +82 -0
- package/dist/v2/durable-core/schemas/lib/decision-trace-ref.d.ts +80 -0
- package/dist/v2/durable-core/schemas/lib/decision-trace-ref.js +38 -0
- package/dist/v2/durable-core/schemas/lib/dedupe-key.d.ts +8 -0
- package/dist/v2/durable-core/schemas/lib/dedupe-key.js +28 -0
- package/dist/v2/durable-core/schemas/lib/utf8-bounded-string.d.ts +6 -0
- package/dist/v2/durable-core/schemas/lib/utf8-bounded-string.js +12 -0
- package/dist/v2/durable-core/schemas/session/events.d.ts +238 -62
- package/dist/v2/durable-core/schemas/session/events.js +74 -29
- package/dist/v2/durable-core/schemas/session/manifest.d.ts +3 -3
- package/dist/v2/durable-core/schemas/session/manifest.js +6 -1
- package/dist/v2/durable-core/schemas/session/preferences.d.ts +5 -0
- package/dist/v2/durable-core/schemas/session/preferences.js +6 -0
- package/dist/v2/durable-core/schemas/session/session-health.d.ts +3 -0
- package/dist/v2/durable-core/tokens/index.d.ts +2 -1
- package/dist/v2/durable-core/tokens/index.js +4 -4
- package/dist/v2/durable-core/tokens/payloads.d.ts +4 -4
- package/dist/v2/durable-core/tokens/token-codec.d.ts +3 -2
- package/dist/v2/durable-core/tokens/token-codec.js +12 -6
- package/dist/v2/durable-core/tokens/token-signer.d.ts +3 -2
- package/dist/v2/durable-core/tokens/token-signer.js +8 -9
- package/dist/v2/infra/local/base64url/index.d.ts +5 -0
- package/dist/v2/infra/local/base64url/index.js +48 -0
- package/dist/v2/infra/local/fs/index.js +8 -4
- package/dist/v2/infra/local/keyring/index.d.ts +5 -1
- package/dist/v2/infra/local/keyring/index.js +41 -32
- package/dist/v2/infra/local/pinned-workflow-store/index.d.ts +6 -4
- package/dist/v2/infra/local/pinned-workflow-store/index.js +50 -62
- package/dist/v2/infra/local/random-entropy/index.d.ts +4 -0
- package/dist/v2/infra/local/random-entropy/index.js +10 -0
- package/dist/v2/infra/local/session-lock/index.d.ts +3 -1
- package/dist/v2/infra/local/session-lock/index.js +5 -4
- package/dist/v2/infra/local/session-store/index.d.ts +0 -1
- package/dist/v2/infra/local/session-store/index.js +372 -282
- package/dist/v2/infra/local/snapshot-store/index.js +20 -25
- package/dist/v2/infra/local/time-clock/index.d.ts +5 -0
- package/dist/v2/infra/local/time-clock/index.js +12 -0
- package/dist/v2/infra/local/utf8/index.d.ts +5 -0
- package/dist/v2/infra/local/utf8/index.js +12 -0
- package/dist/v2/ports/base64url.port.d.ts +12 -0
- package/dist/v2/ports/base64url.port.js +2 -0
- package/dist/v2/ports/pinned-workflow-store.port.d.ts +3 -3
- package/dist/v2/ports/random-entropy.port.d.ts +3 -0
- package/dist/v2/ports/random-entropy.port.js +2 -0
- package/dist/v2/ports/session-event-log-store.port.d.ts +1 -1
- package/dist/v2/ports/session-lock.port.d.ts +1 -1
- package/dist/v2/ports/time-clock.port.d.ts +4 -0
- package/dist/v2/ports/time-clock.port.js +2 -0
- package/dist/v2/ports/utf8.port.d.ts +3 -0
- package/dist/v2/ports/utf8.port.js +2 -0
- package/dist/v2/projections/node-outputs.js +28 -11
- package/dist/v2/projections/preferences.d.ts +1 -2
- package/dist/v2/projections/preferences.js +11 -4
- package/dist/v2/projections/run-dag.js +40 -28
- package/dist/v2/projections/run-status-signals.d.ts +1 -2
- package/dist/v2/read-only/v1-to-v2-shim.d.ts +6 -1
- package/dist/v2/read-only/v1-to-v2-shim.js +16 -4
- package/dist/v2/usecases/execution-session-gate.d.ts +3 -2
- package/dist/v2/usecases/execution-session-gate.js +81 -85
- package/package.json +4 -1
- package/spec/workflow.schema.json +2 -2
- package/workflows/coding-task-workflow-agentic.json +498 -78
- package/workflows/design-thinking-workflow-autonomous.agentic.json +1 -1
- package/workflows/design-thinking-workflow.json +1 -1
- package/workflows/relocation-workflow-us.json +430 -0
- package/dist/v2/durable-core/tokens/base64url.d.ts +0 -7
- package/dist/v2/durable-core/tokens/base64url.js +0 -16
|
@@ -4,10 +4,21 @@ exports.DomainEventV1Schema = exports.DomainEventEnvelopeV1Schema = void 0;
|
|
|
4
4
|
const zod_1 = require("zod");
|
|
5
5
|
const json_zod_js_1 = require("../../canonical/json-zod.js");
|
|
6
6
|
const index_js_1 = require("../../ids/index.js");
|
|
7
|
+
const preferences_js_1 = require("./preferences.js");
|
|
8
|
+
const constants_js_1 = require("../../constants.js");
|
|
9
|
+
const decision_trace_ref_js_1 = require("../lib/decision-trace-ref.js");
|
|
10
|
+
const dedupe_key_js_1 = require("../lib/dedupe-key.js");
|
|
11
|
+
const utf8_bounded_string_js_1 = require("../lib/utf8-bounded-string.js");
|
|
12
|
+
function utf8ByteLength(s) {
|
|
13
|
+
return new TextEncoder().encode(s).length;
|
|
14
|
+
}
|
|
7
15
|
const sha256DigestSchema = zod_1.z
|
|
8
16
|
.string()
|
|
9
|
-
.regex(
|
|
17
|
+
.regex(constants_js_1.SHA256_DIGEST_PATTERN, 'Expected sha256:<64 hex chars>')
|
|
10
18
|
.describe('sha256 digest in WorkRail v2 format');
|
|
19
|
+
const workflowHashSchema = sha256DigestSchema
|
|
20
|
+
.transform((v) => (0, index_js_1.asWorkflowHash)((0, index_js_1.asSha256Digest)(v)))
|
|
21
|
+
.describe('WorkflowHash (sha256 digest of workflow definition)');
|
|
11
22
|
const snapshotRefSchema = sha256DigestSchema
|
|
12
23
|
.transform((v) => (0, index_js_1.asSnapshotRef)((0, index_js_1.asSha256Digest)(v)))
|
|
13
24
|
.describe('SnapshotRef (content-addressed sha256 ref)');
|
|
@@ -17,7 +28,7 @@ exports.DomainEventEnvelopeV1Schema = zod_1.z.object({
|
|
|
17
28
|
eventIndex: zod_1.z.number().int().nonnegative(),
|
|
18
29
|
sessionId: zod_1.z.string().min(1),
|
|
19
30
|
kind: zod_1.z.string().min(1),
|
|
20
|
-
dedupeKey:
|
|
31
|
+
dedupeKey: dedupe_key_js_1.DedupeKeyV1Schema,
|
|
21
32
|
scope: zod_1.z
|
|
22
33
|
.object({
|
|
23
34
|
runId: zod_1.z.string().min(1).optional(),
|
|
@@ -29,7 +40,7 @@ exports.DomainEventEnvelopeV1Schema = zod_1.z.object({
|
|
|
29
40
|
const WorkflowSourceKindSchema = zod_1.z.enum(['bundled', 'user', 'project', 'remote', 'plugin']);
|
|
30
41
|
const RunStartedDataV1Schema = zod_1.z.object({
|
|
31
42
|
workflowId: zod_1.z.string().min(1),
|
|
32
|
-
workflowHash:
|
|
43
|
+
workflowHash: workflowHashSchema,
|
|
33
44
|
workflowSourceKind: WorkflowSourceKindSchema,
|
|
34
45
|
workflowSourceRef: zod_1.z.string().min(1),
|
|
35
46
|
});
|
|
@@ -37,7 +48,7 @@ const NodeKindSchema = zod_1.z.enum(['step', 'checkpoint']);
|
|
|
37
48
|
const NodeCreatedDataV1Schema = zod_1.z.object({
|
|
38
49
|
nodeKind: NodeKindSchema,
|
|
39
50
|
parentNodeId: zod_1.z.string().min(1).nullable(),
|
|
40
|
-
workflowHash:
|
|
51
|
+
workflowHash: workflowHashSchema,
|
|
41
52
|
snapshotRef: snapshotRefSchema,
|
|
42
53
|
});
|
|
43
54
|
const EdgeKindSchema = zod_1.z.enum(['acked_step', 'checkpoint']);
|
|
@@ -65,7 +76,12 @@ const EdgeCreatedDataV1Schema = zod_1.z
|
|
|
65
76
|
const OutputChannelSchema = zod_1.z.enum(['recap', 'artifact']);
|
|
66
77
|
const NotesPayloadV1Schema = zod_1.z.object({
|
|
67
78
|
payloadKind: zod_1.z.literal('notes'),
|
|
68
|
-
notesMarkdown: zod_1.z
|
|
79
|
+
notesMarkdown: zod_1.z
|
|
80
|
+
.string()
|
|
81
|
+
.min(1)
|
|
82
|
+
.refine((s) => utf8ByteLength(s) <= constants_js_1.MAX_OUTPUT_NOTES_MARKDOWN_BYTES, {
|
|
83
|
+
message: `notesMarkdown exceeds max ${constants_js_1.MAX_OUTPUT_NOTES_MARKDOWN_BYTES} UTF-8 bytes`,
|
|
84
|
+
}),
|
|
69
85
|
});
|
|
70
86
|
const ArtifactRefPayloadV1Schema = zod_1.z.object({
|
|
71
87
|
payloadKind: zod_1.z.literal('artifact_ref'),
|
|
@@ -100,31 +116,57 @@ const BlockerCodeSchema = zod_1.z.enum([
|
|
|
100
116
|
'STORAGE_CORRUPTION_DETECTED',
|
|
101
117
|
]);
|
|
102
118
|
const BlockerPointerSchema = zod_1.z.discriminatedUnion('kind', [
|
|
103
|
-
zod_1.z.object({ kind: zod_1.z.literal('context_key'), key: zod_1.z.string().min(1) }),
|
|
119
|
+
zod_1.z.object({ kind: zod_1.z.literal('context_key'), key: zod_1.z.string().min(1).regex(constants_js_1.DELIMITER_SAFE_ID_PATTERN, 'context_key must be delimiter-safe: [a-z0-9_-]+') }),
|
|
120
|
+
zod_1.z.object({ kind: zod_1.z.literal('context_budget') }),
|
|
104
121
|
zod_1.z.object({ kind: zod_1.z.literal('output_contract'), contractRef: zod_1.z.string().min(1) }),
|
|
105
122
|
zod_1.z.object({ kind: zod_1.z.literal('capability'), capability: zod_1.z.enum(['delegation', 'web_browsing']) }),
|
|
106
|
-
zod_1.z.object({ kind: zod_1.z.literal('workflow_step'), stepId: zod_1.z.string().min(1) }),
|
|
123
|
+
zod_1.z.object({ kind: zod_1.z.literal('workflow_step'), stepId: zod_1.z.string().min(1).regex(constants_js_1.DELIMITER_SAFE_ID_PATTERN, 'stepId must be delimiter-safe: [a-z0-9_-]+') }),
|
|
107
124
|
]);
|
|
108
125
|
const BlockerSchema = zod_1.z.object({
|
|
109
126
|
code: BlockerCodeSchema,
|
|
110
127
|
pointer: BlockerPointerSchema,
|
|
111
|
-
message: zod_1.z
|
|
112
|
-
|
|
128
|
+
message: zod_1.z
|
|
129
|
+
.string()
|
|
130
|
+
.min(1)
|
|
131
|
+
.refine((s) => utf8ByteLength(s) <= constants_js_1.MAX_BLOCKER_MESSAGE_BYTES, {
|
|
132
|
+
message: `Blocker message exceeds ${constants_js_1.MAX_BLOCKER_MESSAGE_BYTES} bytes (UTF-8)`,
|
|
133
|
+
}),
|
|
134
|
+
suggestedFix: zod_1.z
|
|
135
|
+
.string()
|
|
136
|
+
.min(1)
|
|
137
|
+
.refine((s) => utf8ByteLength(s) <= constants_js_1.MAX_BLOCKER_SUGGESTED_FIX_BYTES, {
|
|
138
|
+
message: `Blocker suggestedFix exceeds ${constants_js_1.MAX_BLOCKER_SUGGESTED_FIX_BYTES} bytes (UTF-8)`,
|
|
139
|
+
})
|
|
140
|
+
.optional(),
|
|
113
141
|
});
|
|
114
142
|
const BlockerReportV1Schema = zod_1.z
|
|
115
143
|
.object({
|
|
116
|
-
blockers: zod_1.z.array(BlockerSchema).min(1).max(
|
|
144
|
+
blockers: zod_1.z.array(BlockerSchema).min(1).max(constants_js_1.MAX_BLOCKERS),
|
|
117
145
|
})
|
|
118
146
|
.superRefine((v, ctx) => {
|
|
119
147
|
const keyFor = (b) => {
|
|
120
148
|
const p = b.pointer;
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
149
|
+
let ptrStable;
|
|
150
|
+
switch (p.kind) {
|
|
151
|
+
case 'context_key':
|
|
152
|
+
ptrStable = p.key;
|
|
153
|
+
break;
|
|
154
|
+
case 'output_contract':
|
|
155
|
+
ptrStable = p.contractRef;
|
|
156
|
+
break;
|
|
157
|
+
case 'capability':
|
|
158
|
+
ptrStable = p.capability;
|
|
159
|
+
break;
|
|
160
|
+
case 'workflow_step':
|
|
161
|
+
ptrStable = p.stepId;
|
|
162
|
+
break;
|
|
163
|
+
case 'context_budget':
|
|
164
|
+
ptrStable = '';
|
|
165
|
+
break;
|
|
166
|
+
default:
|
|
167
|
+
const _exhaustive = p;
|
|
168
|
+
ptrStable = _exhaustive;
|
|
169
|
+
}
|
|
128
170
|
return `${b.code}|${p.kind}|${String(ptrStable)}`;
|
|
129
171
|
};
|
|
130
172
|
for (let i = 1; i < v.blockers.length; i++) {
|
|
@@ -147,21 +189,19 @@ const AdvanceRecordedDataV1Schema = zod_1.z.object({
|
|
|
147
189
|
intent: zod_1.z.literal('ack_pending'),
|
|
148
190
|
outcome: AdvanceRecordedOutcomeV1Schema,
|
|
149
191
|
});
|
|
150
|
-
const AutonomySchema = zod_1.z.enum(['guided', 'full_auto_stop_on_user_deps', 'full_auto_never_stop']);
|
|
151
|
-
const RiskPolicySchema = zod_1.z.enum(['conservative', 'balanced', 'aggressive']);
|
|
152
192
|
const PreferencesChangedDataV1Schema = zod_1.z
|
|
153
193
|
.object({
|
|
154
194
|
changeId: zod_1.z.string().min(1),
|
|
155
195
|
source: zod_1.z.enum(['user', 'workflow_recommendation', 'system']),
|
|
156
196
|
delta: zod_1.z
|
|
157
197
|
.array(zod_1.z.discriminatedUnion('key', [
|
|
158
|
-
zod_1.z.object({ key: zod_1.z.literal('autonomy'), value:
|
|
159
|
-
zod_1.z.object({ key: zod_1.z.literal('riskPolicy'), value:
|
|
198
|
+
zod_1.z.object({ key: zod_1.z.literal('autonomy'), value: preferences_js_1.AutonomyV2Schema }),
|
|
199
|
+
zod_1.z.object({ key: zod_1.z.literal('riskPolicy'), value: preferences_js_1.RiskPolicyV2Schema }),
|
|
160
200
|
]))
|
|
161
201
|
.min(1),
|
|
162
202
|
effective: zod_1.z.object({
|
|
163
|
-
autonomy:
|
|
164
|
-
riskPolicy:
|
|
203
|
+
autonomy: preferences_js_1.AutonomyV2Schema,
|
|
204
|
+
riskPolicy: preferences_js_1.RiskPolicyV2Schema,
|
|
165
205
|
}),
|
|
166
206
|
})
|
|
167
207
|
.superRefine((v, ctx) => {
|
|
@@ -212,7 +252,7 @@ exports.DomainEventV1Schema = zod_1.z.discriminatedUnion('kind', [
|
|
|
212
252
|
data: zod_1.z.object({
|
|
213
253
|
key: zod_1.z.enum(['git_branch', 'git_head_sha', 'repo_root_hash']),
|
|
214
254
|
value: zod_1.z.discriminatedUnion('type', [
|
|
215
|
-
zod_1.z.object({ type: zod_1.z.literal('short_string'), value: zod_1.z.string().min(1).max(
|
|
255
|
+
zod_1.z.object({ type: zod_1.z.literal('short_string'), value: zod_1.z.string().min(1).max(constants_js_1.MAX_OBSERVATION_SHORT_STRING_LENGTH) }),
|
|
216
256
|
zod_1.z.object({ type: zod_1.z.literal('git_sha1'), value: zod_1.z.string().regex(/^[0-9a-f]{40}$/) }),
|
|
217
257
|
zod_1.z.object({ type: zod_1.z.literal('sha256'), value: sha256DigestSchema }),
|
|
218
258
|
]),
|
|
@@ -317,16 +357,21 @@ exports.DomainEventV1Schema = zod_1.z.discriminatedUnion('kind', [
|
|
|
317
357
|
exports.DomainEventEnvelopeV1Schema.extend({
|
|
318
358
|
kind: zod_1.z.literal('decision_trace_appended'),
|
|
319
359
|
scope: zod_1.z.object({ runId: zod_1.z.string().min(1), nodeId: zod_1.z.string().min(1) }),
|
|
320
|
-
data: zod_1.z
|
|
360
|
+
data: zod_1.z
|
|
361
|
+
.object({
|
|
321
362
|
traceId: zod_1.z.string().min(1),
|
|
322
363
|
entries: zod_1.z
|
|
323
364
|
.array(zod_1.z.object({
|
|
324
365
|
kind: zod_1.z.enum(['selected_next_step', 'evaluated_condition', 'entered_loop', 'exited_loop', 'detected_non_tip_advance']),
|
|
325
|
-
summary:
|
|
326
|
-
refs:
|
|
366
|
+
summary: (0, utf8_bounded_string_js_1.utf8BoundedString)({ maxBytes: constants_js_1.MAX_DECISION_TRACE_ENTRY_SUMMARY_BYTES, label: 'decision trace entry summary', minLength: 1 }),
|
|
367
|
+
refs: decision_trace_ref_js_1.DecisionTraceRefsV1Schema,
|
|
327
368
|
}))
|
|
328
369
|
.min(1)
|
|
329
|
-
.max(
|
|
330
|
-
})
|
|
370
|
+
.max(constants_js_1.MAX_DECISION_TRACE_ENTRIES),
|
|
371
|
+
})
|
|
372
|
+
.refine((data) => {
|
|
373
|
+
const totalBytes = data.entries.reduce((sum, entry) => sum + utf8ByteLength(entry.summary), 0);
|
|
374
|
+
return totalBytes <= constants_js_1.MAX_DECISION_TRACE_TOTAL_BYTES;
|
|
375
|
+
}, { message: `Decision trace total bytes exceeds ${constants_js_1.MAX_DECISION_TRACE_TOTAL_BYTES}` }),
|
|
331
376
|
}),
|
|
332
377
|
]);
|
|
@@ -6,7 +6,7 @@ export declare const ManifestRecordV1Schema: z.ZodDiscriminatedUnion<"kind", [z.
|
|
|
6
6
|
kind: z.ZodLiteral<"segment_closed">;
|
|
7
7
|
firstEventIndex: z.ZodNumber;
|
|
8
8
|
lastEventIndex: z.ZodNumber;
|
|
9
|
-
segmentRelPath: z.ZodString
|
|
9
|
+
segmentRelPath: z.ZodEffects<z.ZodEffects<z.ZodString, string, string>, string, string>;
|
|
10
10
|
sha256: z.ZodString;
|
|
11
11
|
bytes: z.ZodNumber;
|
|
12
12
|
}, "strip", z.ZodTypeAny, {
|
|
@@ -41,17 +41,17 @@ export declare const ManifestRecordV1Schema: z.ZodDiscriminatedUnion<"kind", [z.
|
|
|
41
41
|
kind: "snapshot_pinned";
|
|
42
42
|
sessionId: string;
|
|
43
43
|
v: 1;
|
|
44
|
+
manifestIndex: number;
|
|
44
45
|
eventIndex: number;
|
|
45
46
|
snapshotRef: string;
|
|
46
|
-
manifestIndex: number;
|
|
47
47
|
createdByEventId: string;
|
|
48
48
|
}, {
|
|
49
49
|
kind: "snapshot_pinned";
|
|
50
50
|
sessionId: string;
|
|
51
51
|
v: 1;
|
|
52
|
+
manifestIndex: number;
|
|
52
53
|
eventIndex: number;
|
|
53
54
|
snapshotRef: string;
|
|
54
|
-
manifestIndex: number;
|
|
55
55
|
createdByEventId: string;
|
|
56
56
|
}>]>;
|
|
57
57
|
export type ManifestRecordV1 = z.infer<typeof ManifestRecordV1Schema>;
|
|
@@ -6,6 +6,11 @@ const sha256DigestSchema = zod_1.z
|
|
|
6
6
|
.string()
|
|
7
7
|
.regex(/^sha256:[0-9a-f]{64}$/, 'Expected sha256:<64 hex chars>')
|
|
8
8
|
.describe('sha256 digest in WorkRail v2 format');
|
|
9
|
+
const relativePathSchema = zod_1.z
|
|
10
|
+
.string()
|
|
11
|
+
.min(1)
|
|
12
|
+
.refine((path) => !path.startsWith('/') && !path.startsWith('\\'), 'Path must be relative (no absolute paths)')
|
|
13
|
+
.refine((path) => !path.includes('../') && !path.includes('..\\'), 'Path must not contain path traversal (..)');
|
|
9
14
|
exports.ManifestRecordV1Schema = zod_1.z.discriminatedUnion('kind', [
|
|
10
15
|
zod_1.z.object({
|
|
11
16
|
v: zod_1.z.literal(1),
|
|
@@ -14,7 +19,7 @@ exports.ManifestRecordV1Schema = zod_1.z.discriminatedUnion('kind', [
|
|
|
14
19
|
kind: zod_1.z.literal('segment_closed'),
|
|
15
20
|
firstEventIndex: zod_1.z.number().int().nonnegative(),
|
|
16
21
|
lastEventIndex: zod_1.z.number().int().nonnegative(),
|
|
17
|
-
segmentRelPath:
|
|
22
|
+
segmentRelPath: relativePathSchema,
|
|
18
23
|
sha256: sha256DigestSchema,
|
|
19
24
|
bytes: zod_1.z.number().int().nonnegative(),
|
|
20
25
|
}),
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export type AutonomyV2 = 'guided' | 'full_auto_stop_on_user_deps' | 'full_auto_never_stop';
|
|
3
|
+
export type RiskPolicyV2 = 'conservative' | 'balanced' | 'aggressive';
|
|
4
|
+
export declare const AutonomyV2Schema: z.ZodEnum<["guided", "full_auto_stop_on_user_deps", "full_auto_never_stop"]>;
|
|
5
|
+
export declare const RiskPolicyV2Schema: z.ZodEnum<["conservative", "balanced", "aggressive"]>;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.RiskPolicyV2Schema = exports.AutonomyV2Schema = void 0;
|
|
4
|
+
const zod_1 = require("zod");
|
|
5
|
+
exports.AutonomyV2Schema = zod_1.z.enum(['guided', 'full_auto_stop_on_user_deps', 'full_auto_never_stop']);
|
|
6
|
+
exports.RiskPolicyV2Schema = zod_1.z.enum(['conservative', 'balanced', 'aggressive']);
|
|
@@ -10,6 +10,9 @@ export type CorruptionReasonV2 = {
|
|
|
10
10
|
} | {
|
|
11
11
|
readonly code: 'unknown_schema_version';
|
|
12
12
|
readonly message: string;
|
|
13
|
+
} | {
|
|
14
|
+
readonly code: 'schema_validation_failed';
|
|
15
|
+
readonly message: string;
|
|
13
16
|
};
|
|
14
17
|
export type SessionHealthV2 = {
|
|
15
18
|
readonly kind: 'healthy';
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
export { encodeBase64Url, decodeBase64Url } from './base64url.js';
|
|
2
1
|
export { TokenPayloadV1Schema, StateTokenPayloadV1Schema, AckTokenPayloadV1Schema, CheckpointTokenPayloadV1Schema, expectedPrefixForTokenKind, } from './payloads.js';
|
|
3
2
|
export type { TokenPayloadV1, StateTokenPayloadV1, AckTokenPayloadV1, CheckpointTokenPayloadV1 } from './payloads.js';
|
|
4
3
|
export { encodeTokenPayloadV1, encodeUnsignedTokenV1, parseTokenV1 } from './token-codec.js';
|
|
5
4
|
export type { TokenDecodeErrorV2, ParsedTokenV1 } from './token-codec.js';
|
|
6
5
|
export { signTokenV1, verifyTokenSignatureV1, assertTokenScopeMatchesState } from './token-signer.js';
|
|
7
6
|
export type { TokenVerifyErrorV2 } from './token-signer.js';
|
|
7
|
+
export type { AttemptId, OutputId } from '../ids/index.js';
|
|
8
|
+
export { asAttemptId, asOutputId } from '../ids/index.js';
|
|
@@ -1,9 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.assertTokenScopeMatchesState = exports.verifyTokenSignatureV1 = exports.signTokenV1 = exports.parseTokenV1 = exports.encodeUnsignedTokenV1 = exports.encodeTokenPayloadV1 = exports.expectedPrefixForTokenKind = exports.CheckpointTokenPayloadV1Schema = exports.AckTokenPayloadV1Schema = exports.StateTokenPayloadV1Schema = exports.TokenPayloadV1Schema =
|
|
4
|
-
var base64url_js_1 = require("./base64url.js");
|
|
5
|
-
Object.defineProperty(exports, "encodeBase64Url", { enumerable: true, get: function () { return base64url_js_1.encodeBase64Url; } });
|
|
6
|
-
Object.defineProperty(exports, "decodeBase64Url", { enumerable: true, get: function () { return base64url_js_1.decodeBase64Url; } });
|
|
3
|
+
exports.asOutputId = exports.asAttemptId = exports.assertTokenScopeMatchesState = exports.verifyTokenSignatureV1 = exports.signTokenV1 = exports.parseTokenV1 = exports.encodeUnsignedTokenV1 = exports.encodeTokenPayloadV1 = exports.expectedPrefixForTokenKind = exports.CheckpointTokenPayloadV1Schema = exports.AckTokenPayloadV1Schema = exports.StateTokenPayloadV1Schema = exports.TokenPayloadV1Schema = void 0;
|
|
7
4
|
var payloads_js_1 = require("./payloads.js");
|
|
8
5
|
Object.defineProperty(exports, "TokenPayloadV1Schema", { enumerable: true, get: function () { return payloads_js_1.TokenPayloadV1Schema; } });
|
|
9
6
|
Object.defineProperty(exports, "StateTokenPayloadV1Schema", { enumerable: true, get: function () { return payloads_js_1.StateTokenPayloadV1Schema; } });
|
|
@@ -18,3 +15,6 @@ var token_signer_js_1 = require("./token-signer.js");
|
|
|
18
15
|
Object.defineProperty(exports, "signTokenV1", { enumerable: true, get: function () { return token_signer_js_1.signTokenV1; } });
|
|
19
16
|
Object.defineProperty(exports, "verifyTokenSignatureV1", { enumerable: true, get: function () { return token_signer_js_1.verifyTokenSignatureV1; } });
|
|
20
17
|
Object.defineProperty(exports, "assertTokenScopeMatchesState", { enumerable: true, get: function () { return token_signer_js_1.assertTokenScopeMatchesState; } });
|
|
18
|
+
var index_js_1 = require("../ids/index.js");
|
|
19
|
+
Object.defineProperty(exports, "asAttemptId", { enumerable: true, get: function () { return index_js_1.asAttemptId; } });
|
|
20
|
+
Object.defineProperty(exports, "asOutputId", { enumerable: true, get: function () { return index_js_1.asOutputId; } });
|
|
@@ -17,20 +17,20 @@ export declare const StateTokenPayloadV1Schema: z.ZodObject<{
|
|
|
17
17
|
sessionId: string & {
|
|
18
18
|
readonly __brand: "v2.SessionId";
|
|
19
19
|
};
|
|
20
|
-
workflowHash: never;
|
|
21
20
|
runId: string & {
|
|
22
21
|
readonly __brand: "v2.RunId";
|
|
23
22
|
};
|
|
24
23
|
nodeId: string & {
|
|
25
24
|
readonly __brand: "v2.NodeId";
|
|
26
25
|
};
|
|
26
|
+
workflowHash: never;
|
|
27
27
|
tokenVersion: 1;
|
|
28
28
|
tokenKind: "state";
|
|
29
29
|
}, {
|
|
30
30
|
sessionId: string;
|
|
31
|
-
workflowHash: string;
|
|
32
31
|
runId: string;
|
|
33
32
|
nodeId: string;
|
|
33
|
+
workflowHash: string;
|
|
34
34
|
tokenVersion: 1;
|
|
35
35
|
tokenKind: "state";
|
|
36
36
|
}>;
|
|
@@ -129,20 +129,20 @@ export declare const TokenPayloadV1Schema: z.ZodDiscriminatedUnion<"tokenKind",
|
|
|
129
129
|
sessionId: string & {
|
|
130
130
|
readonly __brand: "v2.SessionId";
|
|
131
131
|
};
|
|
132
|
-
workflowHash: never;
|
|
133
132
|
runId: string & {
|
|
134
133
|
readonly __brand: "v2.RunId";
|
|
135
134
|
};
|
|
136
135
|
nodeId: string & {
|
|
137
136
|
readonly __brand: "v2.NodeId";
|
|
138
137
|
};
|
|
138
|
+
workflowHash: never;
|
|
139
139
|
tokenVersion: 1;
|
|
140
140
|
tokenKind: "state";
|
|
141
141
|
}, {
|
|
142
142
|
sessionId: string;
|
|
143
|
-
workflowHash: string;
|
|
144
143
|
runId: string;
|
|
145
144
|
nodeId: string;
|
|
145
|
+
workflowHash: string;
|
|
146
146
|
tokenVersion: 1;
|
|
147
147
|
tokenKind: "state";
|
|
148
148
|
}>, z.ZodObject<{
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { Result } from 'neverthrow';
|
|
2
2
|
import type { CanonicalBytes } from '../ids/index.js';
|
|
3
3
|
import type { TokenStringV1 } from '../ids/index.js';
|
|
4
|
+
import type { Base64UrlPortV2 } from '../../ports/base64url.port.js';
|
|
4
5
|
import { type TokenPayloadV1, type TokenPrefixV1 } from './payloads.js';
|
|
5
6
|
export type TokenDecodeErrorV2 = {
|
|
6
7
|
readonly code: 'TOKEN_INVALID_FORMAT';
|
|
@@ -24,8 +25,8 @@ export interface ParsedTokenV1 {
|
|
|
24
25
|
readonly payload: TokenPayloadV1;
|
|
25
26
|
}
|
|
26
27
|
export declare function encodeTokenPayloadV1(payload: TokenPayloadV1): Result<CanonicalBytes, TokenDecodeErrorV2>;
|
|
27
|
-
export declare function encodeUnsignedTokenV1(payload: TokenPayloadV1): Result<{
|
|
28
|
+
export declare function encodeUnsignedTokenV1(payload: TokenPayloadV1, base64url: Base64UrlPortV2): Result<{
|
|
28
29
|
readonly token: TokenStringV1;
|
|
29
30
|
readonly payloadBytes: CanonicalBytes;
|
|
30
31
|
}, TokenDecodeErrorV2>;
|
|
31
|
-
export declare function parseTokenV1(token: string): Result<ParsedTokenV1, TokenDecodeErrorV2>;
|
|
32
|
+
export declare function parseTokenV1(token: string, base64url: Base64UrlPortV2): Result<ParsedTokenV1, TokenDecodeErrorV2>;
|
|
@@ -6,7 +6,6 @@ exports.parseTokenV1 = parseTokenV1;
|
|
|
6
6
|
const neverthrow_1 = require("neverthrow");
|
|
7
7
|
const jcs_js_1 = require("../canonical/jcs.js");
|
|
8
8
|
const index_js_1 = require("../ids/index.js");
|
|
9
|
-
const base64url_js_1 = require("./base64url.js");
|
|
10
9
|
const payloads_js_1 = require("./payloads.js");
|
|
11
10
|
function encodeTokenPayloadV1(payload) {
|
|
12
11
|
return (0, jcs_js_1.toCanonicalBytes)(payload).mapErr((e) => ({
|
|
@@ -14,15 +13,15 @@ function encodeTokenPayloadV1(payload) {
|
|
|
14
13
|
message: e.message,
|
|
15
14
|
}));
|
|
16
15
|
}
|
|
17
|
-
function encodeUnsignedTokenV1(payload) {
|
|
16
|
+
function encodeUnsignedTokenV1(payload, base64url) {
|
|
18
17
|
const bytes = encodeTokenPayloadV1(payload);
|
|
19
18
|
if (bytes.isErr())
|
|
20
19
|
return (0, neverthrow_1.err)(bytes.error);
|
|
21
20
|
const prefix = (0, payloads_js_1.expectedPrefixForTokenKind)(payload.tokenKind);
|
|
22
|
-
const token = `${prefix}.v1.${
|
|
21
|
+
const token = `${prefix}.v1.${base64url.encodeBase64Url(bytes.value)}.`;
|
|
23
22
|
return (0, neverthrow_1.ok)({ token: (0, index_js_1.asTokenStringV1)(token), payloadBytes: bytes.value });
|
|
24
23
|
}
|
|
25
|
-
function parseTokenV1(token) {
|
|
24
|
+
function parseTokenV1(token, base64url) {
|
|
26
25
|
const parts = token.split('.');
|
|
27
26
|
if (parts.length !== 4)
|
|
28
27
|
return (0, neverthrow_1.err)({ code: 'TOKEN_INVALID_FORMAT', message: 'Expected 4 dot-separated segments' });
|
|
@@ -35,13 +34,20 @@ function parseTokenV1(token) {
|
|
|
35
34
|
if (payloadB64.trim() === '' || sigB64.trim() === '') {
|
|
36
35
|
return (0, neverthrow_1.err)({ code: 'TOKEN_INVALID_FORMAT', message: 'Missing payload or signature segment' });
|
|
37
36
|
}
|
|
38
|
-
const decoded =
|
|
37
|
+
const decoded = base64url.decodeBase64Url(payloadB64);
|
|
39
38
|
if (decoded.isErr())
|
|
40
39
|
return (0, neverthrow_1.err)({ code: 'TOKEN_INVALID_FORMAT', message: decoded.error.message });
|
|
41
40
|
const payloadBytes = (0, index_js_1.asCanonicalBytes)(decoded.value);
|
|
41
|
+
let payloadText;
|
|
42
|
+
try {
|
|
43
|
+
payloadText = new TextDecoder('utf-8', { fatal: true }).decode(payloadBytes);
|
|
44
|
+
}
|
|
45
|
+
catch {
|
|
46
|
+
return (0, neverthrow_1.err)({ code: 'TOKEN_INVALID_FORMAT', message: 'Payload is not valid UTF-8' });
|
|
47
|
+
}
|
|
42
48
|
let payloadJson;
|
|
43
49
|
try {
|
|
44
|
-
payloadJson = JSON.parse(
|
|
50
|
+
payloadJson = JSON.parse(payloadText);
|
|
45
51
|
}
|
|
46
52
|
catch {
|
|
47
53
|
return (0, neverthrow_1.err)({ code: 'TOKEN_INVALID_FORMAT', message: 'Payload is not valid JSON' });
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { Result } from 'neverthrow';
|
|
2
2
|
import type { HmacSha256PortV2 } from '../../ports/hmac-sha256.port.js';
|
|
3
3
|
import type { KeyringV1 } from '../../ports/keyring.port.js';
|
|
4
|
+
import type { Base64UrlPortV2 } from '../../ports/base64url.port.js';
|
|
4
5
|
import type { CanonicalBytes, TokenStringV1 } from '../ids/index.js';
|
|
5
6
|
import type { ParsedTokenV1, TokenDecodeErrorV2 } from './token-codec.js';
|
|
6
7
|
export type TokenVerifyErrorV2 = {
|
|
@@ -10,6 +11,6 @@ export type TokenVerifyErrorV2 = {
|
|
|
10
11
|
readonly code: 'TOKEN_INVALID_FORMAT';
|
|
11
12
|
readonly message: string;
|
|
12
13
|
};
|
|
13
|
-
export declare function signTokenV1(unsignedTokenPrefix: 'st.v1.' | 'ack.v1.' | 'chk.v1.', payloadBytes: CanonicalBytes, keyring: KeyringV1, hmac: HmacSha256PortV2): Result<TokenStringV1, TokenVerifyErrorV2>;
|
|
14
|
-
export declare function verifyTokenSignatureV1(parsed: ParsedTokenV1, keyring: KeyringV1, hmac: HmacSha256PortV2): Result<void, TokenVerifyErrorV2>;
|
|
14
|
+
export declare function signTokenV1(unsignedTokenPrefix: 'st.v1.' | 'ack.v1.' | 'chk.v1.', payloadBytes: CanonicalBytes, keyring: KeyringV1, hmac: HmacSha256PortV2, base64url: Base64UrlPortV2): Result<TokenStringV1, TokenVerifyErrorV2>;
|
|
15
|
+
export declare function verifyTokenSignatureV1(parsed: ParsedTokenV1, keyring: KeyringV1, hmac: HmacSha256PortV2, base64url: Base64UrlPortV2): Result<void, TokenVerifyErrorV2>;
|
|
15
16
|
export declare function assertTokenScopeMatchesState(state: ParsedTokenV1, other: ParsedTokenV1): Result<void, TokenDecodeErrorV2>;
|
|
@@ -4,26 +4,25 @@ exports.signTokenV1 = signTokenV1;
|
|
|
4
4
|
exports.verifyTokenSignatureV1 = verifyTokenSignatureV1;
|
|
5
5
|
exports.assertTokenScopeMatchesState = assertTokenScopeMatchesState;
|
|
6
6
|
const neverthrow_1 = require("neverthrow");
|
|
7
|
-
const base64url_js_1 = require("./base64url.js");
|
|
8
7
|
const index_js_1 = require("../ids/index.js");
|
|
9
|
-
function decodeKeyBytes(keyBase64Url) {
|
|
10
|
-
const decoded =
|
|
8
|
+
function decodeKeyBytes(keyBase64Url, base64url) {
|
|
9
|
+
const decoded = base64url.decodeBase64Url(keyBase64Url);
|
|
11
10
|
if (decoded.isErr())
|
|
12
11
|
return (0, neverthrow_1.err)({ code: 'TOKEN_INVALID_FORMAT', message: 'Invalid key encoding' });
|
|
13
12
|
if (decoded.value.length !== 32)
|
|
14
13
|
return (0, neverthrow_1.err)({ code: 'TOKEN_INVALID_FORMAT', message: 'Invalid key length' });
|
|
15
14
|
return (0, neverthrow_1.ok)(decoded.value);
|
|
16
15
|
}
|
|
17
|
-
function signTokenV1(unsignedTokenPrefix, payloadBytes, keyring, hmac) {
|
|
18
|
-
const key = decodeKeyBytes(keyring.current.keyBase64Url);
|
|
16
|
+
function signTokenV1(unsignedTokenPrefix, payloadBytes, keyring, hmac, base64url) {
|
|
17
|
+
const key = decodeKeyBytes(keyring.current.keyBase64Url, base64url);
|
|
19
18
|
if (key.isErr())
|
|
20
19
|
return (0, neverthrow_1.err)(key.error);
|
|
21
20
|
const sig = hmac.hmacSha256(key.value, payloadBytes);
|
|
22
|
-
const token = `${unsignedTokenPrefix}${
|
|
21
|
+
const token = `${unsignedTokenPrefix}${base64url.encodeBase64Url(payloadBytes)}.${base64url.encodeBase64Url(sig)}`;
|
|
23
22
|
return (0, neverthrow_1.ok)((0, index_js_1.asTokenStringV1)(token));
|
|
24
23
|
}
|
|
25
|
-
function verifyTokenSignatureV1(parsed, keyring, hmac) {
|
|
26
|
-
const sigBytes =
|
|
24
|
+
function verifyTokenSignatureV1(parsed, keyring, hmac, base64url) {
|
|
25
|
+
const sigBytes = base64url.decodeBase64Url(parsed.sigBase64Url);
|
|
27
26
|
if (sigBytes.isErr())
|
|
28
27
|
return (0, neverthrow_1.err)({ code: 'TOKEN_INVALID_FORMAT', message: 'Invalid signature encoding' });
|
|
29
28
|
if (sigBytes.value.length !== 32)
|
|
@@ -32,7 +31,7 @@ function verifyTokenSignatureV1(parsed, keyring, hmac) {
|
|
|
32
31
|
if (keyring.previous)
|
|
33
32
|
keys.push(keyring.previous.keyBase64Url);
|
|
34
33
|
for (const k of keys) {
|
|
35
|
-
const key = decodeKeyBytes(k);
|
|
34
|
+
const key = decodeKeyBytes(k, base64url);
|
|
36
35
|
if (key.isErr())
|
|
37
36
|
continue;
|
|
38
37
|
const expected = hmac.hmacSha256(key.value, parsed.payloadBytes);
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { Base64UrlPortV2 } from '../../../ports/base64url.port.js';
|
|
2
|
+
export declare class NodeBase64UrlV2 implements Base64UrlPortV2 {
|
|
3
|
+
encodeBase64Url(bytes: Uint8Array): string;
|
|
4
|
+
decodeBase64Url(input: string): ReturnType<Base64UrlPortV2['decodeBase64Url']>;
|
|
5
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.NodeBase64UrlV2 = void 0;
|
|
4
|
+
const neverthrow_1 = require("neverthrow");
|
|
5
|
+
const node_buffer_1 = require("node:buffer");
|
|
6
|
+
class NodeBase64UrlV2 {
|
|
7
|
+
encodeBase64Url(bytes) {
|
|
8
|
+
return node_buffer_1.Buffer.from(bytes).toString('base64url');
|
|
9
|
+
}
|
|
10
|
+
decodeBase64Url(input) {
|
|
11
|
+
if (input.trim() === '') {
|
|
12
|
+
return (0, neverthrow_1.err)({
|
|
13
|
+
code: 'INVALID_BASE64URL_CHARACTERS',
|
|
14
|
+
message: 'Invalid base64url: empty input',
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
if (input.includes('=')) {
|
|
18
|
+
return (0, neverthrow_1.err)({
|
|
19
|
+
code: 'INVALID_BASE64URL_PADDING',
|
|
20
|
+
message: 'Invalid base64url: padding is not allowed',
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
const base64UrlRe = /^[A-Za-z0-9_-]+$/;
|
|
24
|
+
if (!base64UrlRe.test(input)) {
|
|
25
|
+
return (0, neverthrow_1.err)({
|
|
26
|
+
code: 'INVALID_BASE64URL_CHARACTERS',
|
|
27
|
+
message: 'Invalid base64url: invalid characters',
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
try {
|
|
31
|
+
const decoded = node_buffer_1.Buffer.from(input, 'base64url');
|
|
32
|
+
if (decoded.toString('base64url') !== input) {
|
|
33
|
+
return (0, neverthrow_1.err)({
|
|
34
|
+
code: 'INVALID_BASE64URL_CHARACTERS',
|
|
35
|
+
message: 'Invalid base64url: non-canonical encoding',
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
return (0, neverthrow_1.ok)(new Uint8Array(decoded));
|
|
39
|
+
}
|
|
40
|
+
catch (e) {
|
|
41
|
+
return (0, neverthrow_1.err)({
|
|
42
|
+
code: 'INVALID_BASE64URL_CHARACTERS',
|
|
43
|
+
message: `Invalid base64url: ${e instanceof Error ? e.message : String(e)}`,
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
exports.NodeBase64UrlV2 = NodeBase64UrlV2;
|
|
@@ -38,9 +38,14 @@ const fs = __importStar(require("fs/promises"));
|
|
|
38
38
|
const fsCb = __importStar(require("fs"));
|
|
39
39
|
const fs_1 = require("fs");
|
|
40
40
|
const neverthrow_1 = require("neverthrow");
|
|
41
|
+
function nodeErrorCode(e) {
|
|
42
|
+
if (typeof e !== 'object' || e === null)
|
|
43
|
+
return undefined;
|
|
44
|
+
const code = e.code;
|
|
45
|
+
return typeof code === 'string' ? code : undefined;
|
|
46
|
+
}
|
|
41
47
|
function mapFsError(e, filePath) {
|
|
42
|
-
const
|
|
43
|
-
const code = any?.code;
|
|
48
|
+
const code = nodeErrorCode(e);
|
|
44
49
|
if (code === 'ENOENT')
|
|
45
50
|
return { code: 'FS_NOT_FOUND', message: `Not found: ${filePath}` };
|
|
46
51
|
if (code === 'EEXIST')
|
|
@@ -130,8 +135,7 @@ class NodeFileSystemV2 {
|
|
|
130
135
|
await dirHandle.close();
|
|
131
136
|
}
|
|
132
137
|
})(), (e) => {
|
|
133
|
-
const
|
|
134
|
-
const code = any?.code;
|
|
138
|
+
const code = nodeErrorCode(e);
|
|
135
139
|
if (code === 'EINVAL' || code === 'ENOTSUP') {
|
|
136
140
|
return { code: 'FS_UNSUPPORTED', message: `Directory fsync unsupported for: ${dirPath}` };
|
|
137
141
|
}
|
|
@@ -2,10 +2,14 @@ import type { ResultAsync } from 'neverthrow';
|
|
|
2
2
|
import type { DataDirPortV2 } from '../../../ports/data-dir.port.js';
|
|
3
3
|
import type { FileSystemPortV2 } from '../../../ports/fs.port.js';
|
|
4
4
|
import type { KeyringError, KeyringPortV2, KeyringV1 } from '../../../ports/keyring.port.js';
|
|
5
|
+
import type { Base64UrlPortV2 } from '../../../ports/base64url.port.js';
|
|
6
|
+
import type { RandomEntropyPortV2 } from '../../../ports/random-entropy.port.js';
|
|
5
7
|
export declare class LocalKeyringV2 implements KeyringPortV2 {
|
|
6
8
|
private readonly dataDir;
|
|
7
9
|
private readonly fs;
|
|
8
|
-
|
|
10
|
+
private readonly base64url;
|
|
11
|
+
private readonly entropy;
|
|
12
|
+
constructor(dataDir: DataDirPortV2, fs: FileSystemPortV2, base64url: Base64UrlPortV2, entropy: RandomEntropyPortV2);
|
|
9
13
|
loadOrCreate(): ResultAsync<KeyringV1, KeyringError>;
|
|
10
14
|
rotate(): ResultAsync<KeyringV1, KeyringError>;
|
|
11
15
|
private createAndPersistFresh;
|