@astrosheep/keiyaku 2.9.8 → 2.9.10
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 +50 -182
- package/build/.tsbuildinfo +1 -1
- package/build/agents/harness/control-types.js +18 -1
- package/build/agents/harness/index.js +2 -0
- package/build/agents/harness/outcome-error.js +81 -0
- package/build/agents/harness/projection.js +10 -7
- package/build/agents/harness/router.js +5 -1
- package/build/agents/providers/claude-agent-sdk/adapter.js +18 -4
- package/build/agents/providers/claude-agent-sdk/registration.js +11 -1
- package/build/agents/providers/claude-agent-sdk/session.js +19 -5
- package/build/agents/providers/codex-app-server/adapter.js +11 -6
- package/build/agents/providers/codex-app-server/events.js +67 -6
- package/build/agents/providers/codex-app-server/registration.js +11 -1
- package/build/agents/providers/opencode-sdk/adapter.js +8 -1
- package/build/agents/providers/opencode-sdk/events.js +24 -2
- package/build/agents/providers/opencode-sdk/registration.js +11 -1
- package/build/agents/providers/pi/checkpoint.js +9 -1
- package/build/agents/providers/pi/events.js +2 -0
- package/build/agents/providers/pi/registration.js +14 -1
- package/build/cli/commands/akuma/akuma/handler.js +1 -1
- package/build/cli/commands/akuma/akuma/meta.js +3 -3
- package/build/cli/commands/akuma/catalog.js +2 -2
- package/build/cli/commands/akuma/{view → show}/handler.js +5 -5
- package/build/cli/commands/akuma/{view → show}/meta.js +3 -3
- package/build/cli/commands/akuma.js +1 -1
- package/build/cli/commands/contract/amend/handler.js +5 -4
- package/build/cli/commands/contract/arc/handler.js +5 -4
- package/build/cli/commands/contract/audit/handler.js +2 -2
- package/build/cli/commands/contract/bind/handler.js +12 -3
- package/build/cli/commands/contract/bind/meta.js +45 -15
- package/build/cli/commands/contract/forfeit/handler.js +9 -5
- package/build/cli/commands/contract/log/handler.js +2 -2
- package/build/cli/commands/contract/petition/handler.js +34 -7
- package/build/cli/commands/contract/renew/handler.js +7 -7
- package/build/cli/commands/contract/renew/meta.js +3 -3
- package/build/cli/commands/metadata.js +10 -6
- package/build/cli/commands/projection/call/meta.js +1 -1
- package/build/cli/commands/projection/catalog.js +2 -0
- package/build/cli/commands/projection/history/handler.js +21 -0
- package/build/cli/commands/projection/history/meta.js +9 -0
- package/build/cli/commands/projection/shared.js +3 -4
- package/build/cli/commands/projection/status/handler.js +3 -3
- package/build/cli/commands/projection/wait/handler.js +20 -11
- package/build/cli/commands/task/add/handler.js +14 -5
- package/build/cli/commands/task/add/meta.js +2 -2
- package/build/cli/commands/task/catalog.js +4 -0
- package/build/cli/commands/task/done/handler.js +1 -4
- package/build/cli/commands/task/done/meta.js +1 -1
- package/build/cli/commands/task/drop/meta.js +1 -1
- package/build/cli/commands/task/hold/handler.js +3 -0
- package/build/cli/commands/task/hold/meta.js +8 -0
- package/build/cli/commands/task/log/handler.js +1 -1
- package/build/cli/commands/task/log/meta.js +2 -2
- package/build/cli/commands/task/resume/handler.js +3 -0
- package/build/cli/commands/task/resume/meta.js +8 -0
- package/build/cli/commands/task/shared.js +39 -14
- package/build/cli/commands/task/show/handler.js +1 -1
- package/build/cli/commands/task/show/meta.js +1 -1
- package/build/cli/commands/task/start/meta.js +1 -1
- package/build/cli/commands/task/stop/handler.js +1 -4
- package/build/cli/commands/task/stop/meta.js +1 -1
- package/build/cli/commands/task/update/handler.js +11 -3
- package/build/cli/commands/task/update/meta.js +3 -3
- package/build/cli/completion.js +3 -2
- package/build/cli/flags.js +51 -14
- package/build/cli/help.js +4 -1
- package/build/cli/index.js +40 -25
- package/build/cli/parse-flags.js +40 -7
- package/build/cli/parse-metadata.js +5 -2
- package/build/cli/parse-selectors.js +2 -3
- package/build/cli/parse.js +40 -6
- package/build/cli/projection-address.js +12 -10
- package/build/cli/render/amendment-warning.js +8 -0
- package/build/cli/render/arc.js +6 -2
- package/build/cli/render/audit.js +400 -81
- package/build/cli/render/kanshi.js +242 -79
- package/build/cli/render/lifecycle.js +56 -0
- package/build/cli/render/misc.js +24 -28
- package/build/cli/render/petition.js +5 -0
- package/build/cli/render/projection-activity.js +65 -29
- package/build/cli/render/projection-history.js +64 -0
- package/build/cli/render/shared.js +23 -9
- package/build/cli/render/status.js +13 -35
- package/build/cli/render/task.js +51 -26
- package/build/cli/render/terminal-failure.js +3 -1
- package/build/cli/render/wait.js +45 -69
- package/build/cli/subagent-guard.js +1 -1
- package/build/cli/types.js +1 -1
- package/build/config/env-keys.js +3 -1
- package/build/config/env.js +24 -1
- package/build/config/settings/schema.js +3 -1
- package/build/core/address-carrier.js +89 -0
- package/build/core/addressing.js +255 -196
- package/build/core/amend.js +115 -38
- package/build/core/amendment-criteria.js +17 -0
- package/build/core/amendment-warning.js +10 -0
- package/build/core/arc.js +184 -83
- package/build/core/audit/candidate.js +110 -9
- package/build/core/audit/coordinates.js +120 -65
- package/build/core/audit/evidence.js +19 -23
- package/build/core/audit/facade.js +34 -11
- package/build/core/audit/report.js +5 -5
- package/build/core/bind-reconciliation.js +390 -0
- package/build/core/bind-workspace.js +12 -20
- package/build/core/bind.js +242 -273
- package/build/core/call/call.js +1 -0
- package/build/core/call/context.js +46 -71
- package/build/core/call/prompt.js +6 -3
- package/build/core/context.js +49 -35
- package/build/core/contract-carrier-runtime.js +408 -0
- package/build/core/contract-carrier.js +270 -0
- package/build/core/contract-view.js +33 -27
- package/build/core/contract.js +5 -1
- package/build/core/derived-replay.js +207 -0
- package/build/core/draft.js +125 -57
- package/build/core/forfeit.js +113 -56
- package/build/core/identifier-slug.js +63 -13
- package/build/core/ids.js +4 -4
- package/build/core/lifecycle-history.js +35 -0
- package/build/core/lifecycle-recovery.js +117 -0
- package/build/core/lifecycle-runner.js +377 -0
- package/build/core/log.js +37 -11
- package/build/core/outcome-base.js +181 -0
- package/build/core/process-group.js +139 -0
- package/build/core/projection/generation/database.js +82 -7
- package/build/core/projection/generation/model.js +9 -36
- package/build/core/projection/generation/projection-generation-continuation.js +10 -22
- package/build/core/projection/generation/projection-generation-execution.js +13 -6
- package/build/core/projection/index.js +5 -4
- package/build/core/projection/projection-activity.js +29 -8
- package/build/core/projection/projection-alias.js +23 -10
- package/build/core/projection/projection-core.js +21 -7
- package/build/core/projection/projection-execution-observer.js +91 -39
- package/build/core/projection/projection-history.js +474 -0
- package/build/core/projection/projection-runner-lock.js +12 -0
- package/build/core/projection/projection-status-observation.js +365 -0
- package/build/core/projection/projection-status.js +35 -337
- package/build/core/projection/projection-terminal-failure.js +13 -8
- package/build/core/projection/projection-wait.js +7 -2
- package/build/core/projection/tell/launch-store.js +244 -0
- package/build/core/projection/tell/model.js +3 -3
- package/build/core/projection/tell/store.js +70 -118
- package/build/core/registry.js +22 -87
- package/build/core/renew-build.js +424 -0
- package/build/core/renew-plan.js +239 -0
- package/build/core/renew-rewrite.js +77 -0
- package/build/core/renew.js +295 -520
- package/build/core/repository-ledger/accepted-fold-read.js +19 -0
- package/build/core/repository-ledger/accepted-tail.js +116 -0
- package/build/core/repository-ledger/admission.js +38 -0
- package/build/core/repository-ledger/authoritative-transaction.js +1 -0
- package/build/core/repository-ledger/claim-evidence.js +147 -0
- package/build/core/repository-ledger/codec.js +297 -0
- package/build/core/repository-ledger/current-state-store.js +853 -0
- package/build/core/repository-ledger/fold-repository.js +375 -0
- package/build/core/repository-ledger/fold.js +248 -0
- package/build/core/repository-ledger/git-object-store.js +243 -0
- package/build/core/repository-ledger/history-read.js +15 -0
- package/build/core/repository-ledger/incremental-read.js +153 -0
- package/build/core/repository-ledger/index.js +15 -0
- package/build/core/repository-ledger/inventory-plan.js +75 -0
- package/build/core/repository-ledger/inventory.js +310 -0
- package/build/core/repository-ledger/publication-admission.js +125 -0
- package/build/core/repository-ledger/publication.js +353 -0
- package/build/core/repository-ledger/read-model.js +469 -0
- package/build/core/repository-ledger/transaction-membership.js +78 -0
- package/build/core/repository-ledger/traversal.js +404 -0
- package/build/core/repository-ledger/write-transaction.js +339 -0
- package/build/core/seal.js +168 -161
- package/build/core/settlement/claim-delivery.js +42 -215
- package/build/core/settlement/claim.js +235 -153
- package/build/core/settlement/index.js +4 -4
- package/build/core/settlement/petition-claim-gates.js +52 -33
- package/build/core/settlement/petition-forfeit.js +12 -5
- package/build/core/settlement/petition-head-guard.js +8 -5
- package/build/core/settlement/petition-preview.js +68 -56
- package/build/core/settlement/petition-window.js +50 -0
- package/build/core/settlement/petition.js +252 -131
- package/build/core/settlement/queue-read-model.js +72 -95
- package/build/core/settlement/queue-seat-allocation.js +35 -126
- package/build/core/settlement/queue.js +1 -1
- package/build/core/settlement/settlement.js +172 -80
- package/build/core/settlement/verdict.js +112 -66
- package/build/core/settlement/verification-coordination.js +305 -0
- package/build/core/settlement/verification-supervisor.js +275 -0
- package/build/core/settlement/verification.js +398 -31
- package/build/core/status/board.js +125 -127
- package/build/core/status/lifecycle.js +7 -80
- package/build/core/structured-query.js +23 -0
- package/build/core/target-ref.js +1 -1
- package/build/core/task/board.js +59 -24
- package/build/core/task/commands.js +181 -33
- package/build/core/task/coordinate.js +56 -0
- package/build/core/task/document.js +25 -9
- package/build/core/task/index.js +7 -4
- package/build/core/task/query.js +17 -27
- package/build/core/task/settlement-git.js +164 -179
- package/build/core/task/settlement-policy.js +15 -11
- package/build/core/task/source-board.js +31 -13
- package/build/core/task/task-bind-preparation.js +193 -0
- package/build/core/task/task-contract.js +102 -193
- package/build/core/task/task-file-transaction.js +171 -0
- package/build/core/task/task-git-runtime.js +76 -14
- package/build/core/task/task-git-store.js +68 -169
- package/build/core/task/task-store-repository.js +13 -6
- package/build/core/task/task-worktree.js +6 -33
- package/build/core/task/task.js +1 -1
- package/build/core/task/tree.js +3 -3
- package/build/core/task/validation.js +4 -3
- package/build/core/transcripts.js +93 -1
- package/build/core/worktree-bootstrap.js +44 -36
- package/build/core/worktree-path.js +210 -77
- package/build/flow-error.js +7 -7
- package/build/generated/version.js +2 -2
- package/build/git/core.js +76 -13
- package/build/git/refs.js +168 -46
- package/build/git/streaming-batch.js +73 -13
- package/package.json +1 -1
- package/skills/keiyaku/SKILL.md +1 -1
- package/skills/keiyaku-akuma/SKILL.md +3 -3
- package/skills/keiyaku-task/SKILL.md +4 -2
- package/skills/keiyaku-workflow/SKILL.md +88 -203
- package/build/core/entry.js +0 -305
- package/build/core/ledger-batch.js +0 -194
- package/build/core/ledger.js +0 -84
- package/build/core/projection/leash.js +0 -87
- package/build/core/ref-log.js +0 -119
- package/build/core/renew-session.js +0 -128
- package/build/core/status/ledger-batch.js +0 -1
- package/build/core/status/reconciliation.js +0 -137
package/build/core/entry.js
DELETED
|
@@ -1,305 +0,0 @@
|
|
|
1
|
-
import { z } from "zod";
|
|
2
|
-
const SHA_RE = /^[0-9a-f]{7,40}$/i;
|
|
3
|
-
const ISO_UTC_RE = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d{3})?Z$/;
|
|
4
|
-
const CONTRACT_ID_RE = /^\S+$/;
|
|
5
|
-
const SUBJECT_RE = /^keiyaku: (bind|arc|seal|amend|renew|petition|verdict|claim|forfeit|bootstrap) ([^\s]+)$/;
|
|
6
|
-
const shaSchema = z.string().regex(SHA_RE, "expected git sha");
|
|
7
|
-
const isoUtcSchema = z.string().regex(ISO_UTC_RE, "expected ISO 8601 UTC timestamp");
|
|
8
|
-
const nonEmptyString = z.string().trim().min(1);
|
|
9
|
-
const nonBlankString = z.string().refine((value) => value.trim().length > 0, "expected non-empty string");
|
|
10
|
-
// Scope patterns are gitignore text: do not trim, or escaped trailing spaces (`foo\ `) are destroyed.
|
|
11
|
-
const scopePatternString = z
|
|
12
|
-
.string()
|
|
13
|
-
.refine((value) => value.trim().length > 0, "expected non-empty scope pattern");
|
|
14
|
-
// Catalog base (2-13 lowercase letters) or generation overflow base2, base3, ...
|
|
15
|
-
const placeSchema = z.string().regex(/^[a-z]{2,13}(?:[2-9]|[1-9][0-9]+)?$/);
|
|
16
|
-
export const entryKindSchema = z.enum([
|
|
17
|
-
"bind",
|
|
18
|
-
"arc",
|
|
19
|
-
"seal",
|
|
20
|
-
"amend",
|
|
21
|
-
"renew",
|
|
22
|
-
"petition",
|
|
23
|
-
"verdict",
|
|
24
|
-
"claim",
|
|
25
|
-
"forfeit",
|
|
26
|
-
"bootstrap",
|
|
27
|
-
]);
|
|
28
|
-
const diffstatSchema = z
|
|
29
|
-
.object({
|
|
30
|
-
files: z.number().int().nonnegative(),
|
|
31
|
-
insertions: z.number().int().nonnegative(),
|
|
32
|
-
deletions: z.number().int().nonnegative(),
|
|
33
|
-
})
|
|
34
|
-
.strict();
|
|
35
|
-
const scopeAuditSchema = z
|
|
36
|
-
.object({
|
|
37
|
-
violations: z.array(nonEmptyString),
|
|
38
|
-
})
|
|
39
|
-
.strict();
|
|
40
|
-
export const fullBranchRefSchema = z
|
|
41
|
-
.string()
|
|
42
|
-
.regex(/^refs\/heads\/\S+$/, "expected full branch ref");
|
|
43
|
-
export const bindBootstrapPlanSchema = z
|
|
44
|
-
.object({
|
|
45
|
-
command: z.array(nonEmptyString).min(1),
|
|
46
|
-
timeoutMs: z.number().int().min(1).max(3_600_000),
|
|
47
|
-
})
|
|
48
|
-
.strict();
|
|
49
|
-
export const bindEntryDataSchema = z
|
|
50
|
-
.object({
|
|
51
|
-
name: nonEmptyString,
|
|
52
|
-
objective: nonEmptyString,
|
|
53
|
-
scope: z.array(scopePatternString).min(1),
|
|
54
|
-
checks: z.array(nonBlankString).min(1),
|
|
55
|
-
extensions: z
|
|
56
|
-
.array(z
|
|
57
|
-
.object({
|
|
58
|
-
title: nonBlankString,
|
|
59
|
-
content: z.string(),
|
|
60
|
-
})
|
|
61
|
-
.strict()),
|
|
62
|
-
base: shaSchema,
|
|
63
|
-
target: fullBranchRefSchema,
|
|
64
|
-
workspace: z.enum(["worktree", "here"]),
|
|
65
|
-
after: z.array(nonEmptyString).optional(),
|
|
66
|
-
place: placeSchema.nullable().optional(),
|
|
67
|
-
bootstrap: bindBootstrapPlanSchema.optional(),
|
|
68
|
-
})
|
|
69
|
-
.strict();
|
|
70
|
-
const bootstrapExitResultSchema = z
|
|
71
|
-
.object({
|
|
72
|
-
kind: z.literal("exit"),
|
|
73
|
-
code: z.number().int().min(0).max(255),
|
|
74
|
-
})
|
|
75
|
-
.strict();
|
|
76
|
-
const bootstrapSignalResultSchema = z
|
|
77
|
-
.object({
|
|
78
|
-
kind: z.literal("signal"),
|
|
79
|
-
signal: z.string().min(1),
|
|
80
|
-
})
|
|
81
|
-
.strict();
|
|
82
|
-
const bootstrapTimeoutResultSchema = z
|
|
83
|
-
.object({
|
|
84
|
-
kind: z.literal("timeout"),
|
|
85
|
-
})
|
|
86
|
-
.strict();
|
|
87
|
-
const bootstrapSpawnResultSchema = z
|
|
88
|
-
.object({
|
|
89
|
-
kind: z.literal("spawn"),
|
|
90
|
-
message: z.string(),
|
|
91
|
-
})
|
|
92
|
-
.strict();
|
|
93
|
-
export const bootstrapResultSchema = z.discriminatedUnion("kind", [
|
|
94
|
-
bootstrapExitResultSchema,
|
|
95
|
-
bootstrapSignalResultSchema,
|
|
96
|
-
bootstrapTimeoutResultSchema,
|
|
97
|
-
bootstrapSpawnResultSchema,
|
|
98
|
-
]);
|
|
99
|
-
export const bootstrapEntryDataSchema = z
|
|
100
|
-
.object({
|
|
101
|
-
result: bootstrapResultSchema,
|
|
102
|
-
durationMs: z
|
|
103
|
-
.number()
|
|
104
|
-
.int()
|
|
105
|
-
.nonnegative()
|
|
106
|
-
.refine((value) => Number.isSafeInteger(value), "durationMs must be a safe integer"),
|
|
107
|
-
stderrTail: z.string().optional(),
|
|
108
|
-
stderrTruncated: z.boolean().optional(),
|
|
109
|
-
})
|
|
110
|
-
.strict();
|
|
111
|
-
export const arcEntryDataSchema = z
|
|
112
|
-
.object({
|
|
113
|
-
arc: z.number().int().positive(),
|
|
114
|
-
title: nonEmptyString,
|
|
115
|
-
objective: nonEmptyString,
|
|
116
|
-
brief: nonEmptyString,
|
|
117
|
-
})
|
|
118
|
-
.strict();
|
|
119
|
-
export const sealEntryDataSchema = z
|
|
120
|
-
.object({
|
|
121
|
-
arc: z.number().int().nonnegative(),
|
|
122
|
-
sealedBy: z.enum(["arc", "renew", "petition"]),
|
|
123
|
-
oldFence: shaSchema,
|
|
124
|
-
newFence: shaSchema,
|
|
125
|
-
receipts: z.array(shaSchema),
|
|
126
|
-
diffstat: diffstatSchema,
|
|
127
|
-
scopeAudit: scopeAuditSchema,
|
|
128
|
-
})
|
|
129
|
-
.strict();
|
|
130
|
-
export const amendEntryDataSchema = z
|
|
131
|
-
.object({
|
|
132
|
-
amendment: nonBlankString,
|
|
133
|
-
scopeDelta: z
|
|
134
|
-
.object({
|
|
135
|
-
add: z.array(scopePatternString),
|
|
136
|
-
})
|
|
137
|
-
.strict()
|
|
138
|
-
.optional(),
|
|
139
|
-
})
|
|
140
|
-
.strict();
|
|
141
|
-
export const renewEntryDataSchema = z
|
|
142
|
-
.object({
|
|
143
|
-
oldBase: shaSchema,
|
|
144
|
-
newBase: shaSchema,
|
|
145
|
-
oldHead: shaSchema,
|
|
146
|
-
newHead: shaSchema,
|
|
147
|
-
})
|
|
148
|
-
.strict();
|
|
149
|
-
const positiveSafeSeatSchema = z
|
|
150
|
-
.number()
|
|
151
|
-
.int()
|
|
152
|
-
.positive()
|
|
153
|
-
.refine((value) => Number.isSafeInteger(value), "seat must be a positive safe integer");
|
|
154
|
-
// Current petitions always carry target + seat. Legacy residuals omit both and
|
|
155
|
-
// exist only for diagnostic/rejection paths — never for production writers.
|
|
156
|
-
export const petitionEntryDataSchema = z.union([
|
|
157
|
-
z
|
|
158
|
-
.object({
|
|
159
|
-
intent: z.literal("claim"),
|
|
160
|
-
oath: nonEmptyString,
|
|
161
|
-
target: fullBranchRefSchema,
|
|
162
|
-
seat: positiveSafeSeatSchema,
|
|
163
|
-
})
|
|
164
|
-
.strict(),
|
|
165
|
-
z
|
|
166
|
-
.object({
|
|
167
|
-
intent: z.literal("forfeit"),
|
|
168
|
-
target: fullBranchRefSchema,
|
|
169
|
-
seat: positiveSafeSeatSchema,
|
|
170
|
-
})
|
|
171
|
-
.strict(),
|
|
172
|
-
z
|
|
173
|
-
.object({
|
|
174
|
-
intent: z.literal("claim"),
|
|
175
|
-
oath: nonEmptyString,
|
|
176
|
-
})
|
|
177
|
-
.strict(),
|
|
178
|
-
z
|
|
179
|
-
.object({
|
|
180
|
-
intent: z.literal("forfeit"),
|
|
181
|
-
})
|
|
182
|
-
.strict(),
|
|
183
|
-
]);
|
|
184
|
-
export const verdictEntryDataSchema = z
|
|
185
|
-
.object({
|
|
186
|
-
result: z.enum(["approved", "rejected"]),
|
|
187
|
-
summary: nonEmptyString,
|
|
188
|
-
})
|
|
189
|
-
.strict();
|
|
190
|
-
export const claimEntryDataSchema = z
|
|
191
|
-
.object({
|
|
192
|
-
mergeCommit: shaSchema,
|
|
193
|
-
})
|
|
194
|
-
.strict();
|
|
195
|
-
export const forfeitEntryDataSchema = z
|
|
196
|
-
.object({
|
|
197
|
-
reason: z.enum(["manual", "bind-failed"]),
|
|
198
|
-
by: nonEmptyString,
|
|
199
|
-
note: nonEmptyString.optional(),
|
|
200
|
-
})
|
|
201
|
-
.strict();
|
|
202
|
-
function makeEntrySchema(kind, data, version = 1) {
|
|
203
|
-
return z
|
|
204
|
-
.object({
|
|
205
|
-
v: z.literal(version),
|
|
206
|
-
kind: z.literal(kind),
|
|
207
|
-
contract: z.string().trim().regex(CONTRACT_ID_RE, "contract id cannot contain whitespace"),
|
|
208
|
-
at: isoUtcSchema,
|
|
209
|
-
actor: nonEmptyString,
|
|
210
|
-
data,
|
|
211
|
-
})
|
|
212
|
-
.strict();
|
|
213
|
-
}
|
|
214
|
-
export const bindEntrySchema = makeEntrySchema("bind", bindEntryDataSchema);
|
|
215
|
-
export const arcEntrySchema = makeEntrySchema("arc", arcEntryDataSchema);
|
|
216
|
-
export const sealEntrySchema = makeEntrySchema("seal", sealEntryDataSchema, 2);
|
|
217
|
-
export const amendEntrySchema = makeEntrySchema("amend", amendEntryDataSchema);
|
|
218
|
-
export const renewEntrySchema = makeEntrySchema("renew", renewEntryDataSchema);
|
|
219
|
-
export const petitionEntrySchema = makeEntrySchema("petition", petitionEntryDataSchema);
|
|
220
|
-
export const verdictEntrySchema = makeEntrySchema("verdict", verdictEntryDataSchema);
|
|
221
|
-
export const claimEntrySchema = makeEntrySchema("claim", claimEntryDataSchema);
|
|
222
|
-
export const forfeitEntrySchema = makeEntrySchema("forfeit", forfeitEntryDataSchema);
|
|
223
|
-
export const bootstrapEntrySchema = makeEntrySchema("bootstrap", bootstrapEntryDataSchema);
|
|
224
|
-
export const ledgerEntrySchema = z.discriminatedUnion("kind", [
|
|
225
|
-
bindEntrySchema,
|
|
226
|
-
arcEntrySchema,
|
|
227
|
-
sealEntrySchema,
|
|
228
|
-
amendEntrySchema,
|
|
229
|
-
renewEntrySchema,
|
|
230
|
-
petitionEntrySchema,
|
|
231
|
-
verdictEntrySchema,
|
|
232
|
-
claimEntrySchema,
|
|
233
|
-
forfeitEntrySchema,
|
|
234
|
-
bootstrapEntrySchema,
|
|
235
|
-
]);
|
|
236
|
-
export class LedgerEntryFormatError extends Error {
|
|
237
|
-
code = "INVALID_LEDGER_ENTRY_FORMAT";
|
|
238
|
-
constructor(message, options) {
|
|
239
|
-
super(message, options);
|
|
240
|
-
this.name = "LedgerEntryFormatError";
|
|
241
|
-
}
|
|
242
|
-
}
|
|
243
|
-
export class LedgerEntrySchemaError extends Error {
|
|
244
|
-
code = "INVALID_LEDGER_ENTRY_SCHEMA";
|
|
245
|
-
constructor(message, options) {
|
|
246
|
-
super(message, options);
|
|
247
|
-
this.name = "LedgerEntrySchemaError";
|
|
248
|
-
}
|
|
249
|
-
}
|
|
250
|
-
export function formatLedgerEntrySubject(entry) {
|
|
251
|
-
return `keiyaku: ${entry.kind} ${entry.contract}`;
|
|
252
|
-
}
|
|
253
|
-
export function formatLedgerEntryCommitMessage(entry) {
|
|
254
|
-
const result = ledgerEntrySchema.safeParse(entry);
|
|
255
|
-
if (!result.success) {
|
|
256
|
-
throw new LedgerEntrySchemaError(`ledger entry schema validation failed: ${result.error.message}`, {
|
|
257
|
-
cause: result.error,
|
|
258
|
-
});
|
|
259
|
-
}
|
|
260
|
-
return `${formatLedgerEntrySubject(result.data)}\n\n${JSON.stringify(result.data, null, 2)}\n`;
|
|
261
|
-
}
|
|
262
|
-
export function parseLedgerEntryCommitMessage(message) {
|
|
263
|
-
const normalized = message.replace(/\r\n/g, "\n");
|
|
264
|
-
const separatorIndex = normalized.indexOf("\n\n");
|
|
265
|
-
if (separatorIndex < 0) {
|
|
266
|
-
throw new LedgerEntryFormatError("ledger entry commit message must contain a blank line before the JSON body");
|
|
267
|
-
}
|
|
268
|
-
const subject = normalized.slice(0, separatorIndex).trim();
|
|
269
|
-
const subjectMatch = SUBJECT_RE.exec(subject);
|
|
270
|
-
if (!subjectMatch) {
|
|
271
|
-
throw new LedgerEntryFormatError("ledger entry subject must match 'keiyaku: <kind> <contract>'");
|
|
272
|
-
}
|
|
273
|
-
const body = normalized.slice(separatorIndex + 2).trim();
|
|
274
|
-
let parsed;
|
|
275
|
-
try {
|
|
276
|
-
parsed = JSON.parse(body);
|
|
277
|
-
}
|
|
278
|
-
catch (error) {
|
|
279
|
-
throw new LedgerEntryFormatError("ledger entry JSON body is not valid JSON", { cause: error });
|
|
280
|
-
}
|
|
281
|
-
if (typeof parsed === "object" && parsed !== null && Object.hasOwn(parsed, "repoId")) {
|
|
282
|
-
const { repoId: _legacyRepoId, ...current } = parsed;
|
|
283
|
-
parsed = current;
|
|
284
|
-
}
|
|
285
|
-
if (typeof parsed === "object" && parsed !== null &&
|
|
286
|
-
parsed.kind === "amend") {
|
|
287
|
-
const data = parsed.data;
|
|
288
|
-
const scopeDelta = typeof data === "object" && data !== null
|
|
289
|
-
? data.scopeDelta
|
|
290
|
-
: undefined;
|
|
291
|
-
if (typeof scopeDelta === "object" && scopeDelta !== null && Object.hasOwn(scopeDelta, "remove")) {
|
|
292
|
-
throw new LedgerEntrySchemaError("ledger entry schema validation failed: scopeDelta.remove is obsolete; ledger row is corrupt");
|
|
293
|
-
}
|
|
294
|
-
}
|
|
295
|
-
const result = ledgerEntrySchema.safeParse(parsed);
|
|
296
|
-
if (!result.success) {
|
|
297
|
-
throw new LedgerEntrySchemaError(`ledger entry schema validation failed: ${result.error.message}`, {
|
|
298
|
-
cause: result.error,
|
|
299
|
-
});
|
|
300
|
-
}
|
|
301
|
-
if (result.data.kind !== subjectMatch[1] || result.data.contract !== subjectMatch[2]) {
|
|
302
|
-
throw new LedgerEntryFormatError("ledger entry subject does not match the JSON body");
|
|
303
|
-
}
|
|
304
|
-
return result.data;
|
|
305
|
-
}
|
|
@@ -1,194 +0,0 @@
|
|
|
1
|
-
import { wrapGitError, runGitProcess } from "../git/core.js";
|
|
2
|
-
import { GitStreamingBatchFramingError, GitStreamingBatchResponseEndedError, openGitStreamingBatch, } from "../git/streaming-batch.js";
|
|
3
|
-
import { parseLedgerEntryCommitMessage } from "./entry.js";
|
|
4
|
-
import { ACTIVE_LEDGER_REF_PREFIX, activeLedgerRef, } from "./ledger.js";
|
|
5
|
-
const MAX_LEDGER_COMMIT_BYTES = 1024 * 1024;
|
|
6
|
-
async function runLedgerGit(cwd, args) {
|
|
7
|
-
const result = await runGitProcess(cwd, args);
|
|
8
|
-
if (result.error || result.status !== 0) {
|
|
9
|
-
throw wrapGitError(args.join(" "), {
|
|
10
|
-
message: result.error?.message
|
|
11
|
-
?? `git exited with status ${result.status ?? "unknown"}`,
|
|
12
|
-
stderr: result.stderr,
|
|
13
|
-
stdout: result.stdout,
|
|
14
|
-
}, cwd);
|
|
15
|
-
}
|
|
16
|
-
return Buffer.from(result.stdout, "utf8");
|
|
17
|
-
}
|
|
18
|
-
async function queryBatchObject(batch, expression) {
|
|
19
|
-
const record = await batch.request(expression, {
|
|
20
|
-
maxContentBytes: MAX_LEDGER_COMMIT_BYTES,
|
|
21
|
-
});
|
|
22
|
-
if (record.kind === "missing")
|
|
23
|
-
return null;
|
|
24
|
-
if (record.kind === "ambiguous") {
|
|
25
|
-
throw new Error(`[git cat-file ${expression}] object is ambiguous`);
|
|
26
|
-
}
|
|
27
|
-
return {
|
|
28
|
-
oid: record.record.oid,
|
|
29
|
-
type: record.record.type,
|
|
30
|
-
content: record.record.content,
|
|
31
|
-
};
|
|
32
|
-
}
|
|
33
|
-
function parseCommitObject(object) {
|
|
34
|
-
if (object.type !== "commit") {
|
|
35
|
-
throw new Error(`git cat-file expected commit ${object.oid}, received ${object.type}`);
|
|
36
|
-
}
|
|
37
|
-
const content = object.content.toString("utf8");
|
|
38
|
-
const messageStart = content.indexOf("\n\n");
|
|
39
|
-
if (messageStart < 0)
|
|
40
|
-
throw new Error(`git commit ${object.oid} has no message separator`);
|
|
41
|
-
const parents = [];
|
|
42
|
-
for (const line of content.slice(0, messageStart).split("\n")) {
|
|
43
|
-
if (!line.startsWith("parent "))
|
|
44
|
-
continue;
|
|
45
|
-
const parent = line.slice("parent ".length);
|
|
46
|
-
if (!/^[0-9a-f]{40,64}$/.test(parent)) {
|
|
47
|
-
throw new Error(`git commit ${object.oid} has an invalid parent header`);
|
|
48
|
-
}
|
|
49
|
-
parents.push(parent);
|
|
50
|
-
}
|
|
51
|
-
return { oid: object.oid, parents, message: content.slice(messageStart + 2) };
|
|
52
|
-
}
|
|
53
|
-
function parseLedgerRefs(output) {
|
|
54
|
-
return output
|
|
55
|
-
.toString("utf8")
|
|
56
|
-
.split(/\r?\n/)
|
|
57
|
-
.filter((ref) => ref.startsWith(ACTIVE_LEDGER_REF_PREFIX))
|
|
58
|
-
.map((ref) => ({ contractId: ref.slice(ACTIVE_LEDGER_REF_PREFIX.length), ref }));
|
|
59
|
-
}
|
|
60
|
-
async function readLedgerFromBatch(batch, ref, commits) {
|
|
61
|
-
const headObject = await queryBatchObject(batch, `${ref.ref}^{commit}`);
|
|
62
|
-
if (!headObject)
|
|
63
|
-
return null;
|
|
64
|
-
const head = parseCommitObject(headObject);
|
|
65
|
-
commits.set(head.oid, Promise.resolve(head));
|
|
66
|
-
const ordered = [];
|
|
67
|
-
const visited = new Set();
|
|
68
|
-
const visiting = new Set();
|
|
69
|
-
const visit = async (oid) => {
|
|
70
|
-
if (visited.has(oid))
|
|
71
|
-
return;
|
|
72
|
-
if (visiting.has(oid))
|
|
73
|
-
throw new Error(`git ledger ancestry contains a cycle at ${oid}`);
|
|
74
|
-
visiting.add(oid);
|
|
75
|
-
let pending = commits.get(oid);
|
|
76
|
-
if (!pending) {
|
|
77
|
-
pending = queryBatchObject(batch, oid).then((object) => {
|
|
78
|
-
if (!object)
|
|
79
|
-
throw new Error(`[git cat-file ${oid}] object is missing`);
|
|
80
|
-
return parseCommitObject(object);
|
|
81
|
-
});
|
|
82
|
-
commits.set(oid, pending);
|
|
83
|
-
}
|
|
84
|
-
const commit = await pending;
|
|
85
|
-
for (const parent of commit.parents)
|
|
86
|
-
await visit(parent);
|
|
87
|
-
visiting.delete(oid);
|
|
88
|
-
visited.add(oid);
|
|
89
|
-
ordered.push(commit);
|
|
90
|
-
};
|
|
91
|
-
await visit(head.oid);
|
|
92
|
-
return {
|
|
93
|
-
contractId: ref.contractId,
|
|
94
|
-
ref: ref.ref,
|
|
95
|
-
head: head.oid,
|
|
96
|
-
entries: ordered.map((commit) => parseLedgerEntryCommitMessage(commit.message)),
|
|
97
|
-
};
|
|
98
|
-
}
|
|
99
|
-
async function closeBatch(cwd, batch) {
|
|
100
|
-
const close = await batch.close();
|
|
101
|
-
if (!close.aborted && (close.timedOut || close.signal || close.code !== 0)) {
|
|
102
|
-
throw wrapGitError("cat-file --batch", {
|
|
103
|
-
message: close.timedOut
|
|
104
|
-
? "git timed out"
|
|
105
|
-
: close.signal
|
|
106
|
-
? `git exited from signal ${close.signal}`
|
|
107
|
-
: `git exited with status ${close.code ?? "unknown"}`,
|
|
108
|
-
stderr: close.stderr.toString("utf8"),
|
|
109
|
-
}, cwd);
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
async function readLedgerRefs(cwd, refs) {
|
|
113
|
-
if (refs.length === 0)
|
|
114
|
-
return [];
|
|
115
|
-
const batch = openGitStreamingBatch(cwd);
|
|
116
|
-
const commits = new Map();
|
|
117
|
-
const results = [];
|
|
118
|
-
let readError;
|
|
119
|
-
try {
|
|
120
|
-
for (let index = 0; index < refs.length; index += 1) {
|
|
121
|
-
const ref = refs[index];
|
|
122
|
-
try {
|
|
123
|
-
const ledger = await readLedgerFromBatch(batch, ref, commits);
|
|
124
|
-
if (ledger)
|
|
125
|
-
results.push(ledger);
|
|
126
|
-
else
|
|
127
|
-
results.push({ id: ref.contractId, error: new Error(`ledger ref disappeared: ${ref.ref}`) });
|
|
128
|
-
}
|
|
129
|
-
catch (error) {
|
|
130
|
-
const diagnostic = error instanceof Error ? error : new Error(String(error));
|
|
131
|
-
results.push({ id: ref.contractId, error: diagnostic });
|
|
132
|
-
if (error instanceof GitStreamingBatchFramingError
|
|
133
|
-
|| error instanceof GitStreamingBatchResponseEndedError) {
|
|
134
|
-
const isolationReason = error instanceof GitStreamingBatchResponseEndedError
|
|
135
|
-
? "response ended"
|
|
136
|
-
: "malformed frame";
|
|
137
|
-
for (const pending of refs.slice(index + 1)) {
|
|
138
|
-
results.push({
|
|
139
|
-
id: pending.contractId,
|
|
140
|
-
error: new Error(`git cat-file batch terminated after ${isolationReason}: ${diagnostic.message}`),
|
|
141
|
-
});
|
|
142
|
-
}
|
|
143
|
-
break;
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
catch (error) {
|
|
149
|
-
readError = error;
|
|
150
|
-
}
|
|
151
|
-
try {
|
|
152
|
-
await closeBatch(cwd, batch);
|
|
153
|
-
}
|
|
154
|
-
catch (error) {
|
|
155
|
-
if (!readError)
|
|
156
|
-
readError = error;
|
|
157
|
-
}
|
|
158
|
-
if (readError)
|
|
159
|
-
throw readError;
|
|
160
|
-
return results;
|
|
161
|
-
}
|
|
162
|
-
/** Read every ledger with two Git processes regardless of ledger or entry count. */
|
|
163
|
-
export async function readAllLedgerSnapshots(cwd) {
|
|
164
|
-
const refOutput = await runLedgerGit(cwd, [
|
|
165
|
-
"for-each-ref",
|
|
166
|
-
"--sort=refname",
|
|
167
|
-
"--format=%(refname)",
|
|
168
|
-
ACTIVE_LEDGER_REF_PREFIX,
|
|
169
|
-
]);
|
|
170
|
-
return readLedgerRefs(cwd, parseLedgerRefs(refOutput));
|
|
171
|
-
}
|
|
172
|
-
/** Read one exact ledger with one Git process and without enumerating other refs. */
|
|
173
|
-
export async function readLedgerSnapshot(cwd, contractId) {
|
|
174
|
-
const ref = activeLedgerRef(contractId);
|
|
175
|
-
const batch = openGitStreamingBatch(cwd);
|
|
176
|
-
let ledger = null;
|
|
177
|
-
let readError;
|
|
178
|
-
try {
|
|
179
|
-
ledger = await readLedgerFromBatch(batch, { contractId, ref }, new Map());
|
|
180
|
-
}
|
|
181
|
-
catch (error) {
|
|
182
|
-
readError = error;
|
|
183
|
-
}
|
|
184
|
-
try {
|
|
185
|
-
await closeBatch(cwd, batch);
|
|
186
|
-
}
|
|
187
|
-
catch (error) {
|
|
188
|
-
if (!readError)
|
|
189
|
-
readError = error;
|
|
190
|
-
}
|
|
191
|
-
if (readError)
|
|
192
|
-
throw readError;
|
|
193
|
-
return ledger;
|
|
194
|
-
}
|
package/build/core/ledger.js
DELETED
|
@@ -1,84 +0,0 @@
|
|
|
1
|
-
import { createGit, wrapGitError, } from "../git/core.js";
|
|
2
|
-
import { formatLedgerEntryCommitMessage, parseLedgerEntryCommitMessage, } from "./entry.js";
|
|
3
|
-
import { casUpdateRefLog, createRefLogCommit, listRefLogCommits, readRefLogCommitMessage, resolveRefLogHead, } from "./ref-log.js";
|
|
4
|
-
export const ACTIVE_LEDGER_REF_PREFIX = "refs/keiyaku/active/";
|
|
5
|
-
export function activeLedgerRef(contractId) {
|
|
6
|
-
return `${ACTIVE_LEDGER_REF_PREFIX}${contractId}`;
|
|
7
|
-
}
|
|
8
|
-
export async function appendEntry(cwd, ref, entry, expectedHead) {
|
|
9
|
-
const message = formatLedgerEntryCommitMessage(entry);
|
|
10
|
-
const separator = message.indexOf("\n\n");
|
|
11
|
-
const subject = message.slice(0, separator);
|
|
12
|
-
const body = message.slice(separator + 2).trimEnd();
|
|
13
|
-
const newHead = await createRefLogCommit(cwd, {
|
|
14
|
-
subject,
|
|
15
|
-
body,
|
|
16
|
-
parentHead: expectedHead,
|
|
17
|
-
errorLabel: `ledger ${entry.kind} ${entry.contract}`,
|
|
18
|
-
});
|
|
19
|
-
const casOk = await casUpdateRefLog(cwd, ref, newHead, expectedHead);
|
|
20
|
-
if (casOk)
|
|
21
|
-
return { ok: true, head: newHead };
|
|
22
|
-
// Intentional: CAS loss re-resolves and surfaces conflict/missing-ref without throw.
|
|
23
|
-
const currentHead = await resolveRefLogHead(cwd, ref);
|
|
24
|
-
if (currentHead === null) {
|
|
25
|
-
return { ok: false, reason: "missing-ref" };
|
|
26
|
-
}
|
|
27
|
-
return { ok: false, reason: "conflict", currentHead };
|
|
28
|
-
}
|
|
29
|
-
export async function appendWithRetry(cwd, ref, build, options = {}) {
|
|
30
|
-
const maxRetries = options.maxRetries ?? 3;
|
|
31
|
-
let currentHead = await resolveRefLogHead(cwd, ref);
|
|
32
|
-
const startedMissing = currentHead === null;
|
|
33
|
-
for (let attempt = 0; attempt <= maxRetries; attempt += 1) {
|
|
34
|
-
const currentEntries = currentHead ? (await readLedgerRef(cwd, ref, currentHead)).entries : [];
|
|
35
|
-
const nextEntry = await build(currentHead, currentEntries);
|
|
36
|
-
if (nextEntry === null) {
|
|
37
|
-
return { ok: false, reason: "aborted", currentHead };
|
|
38
|
-
}
|
|
39
|
-
const result = await appendEntry(cwd, ref, nextEntry, currentHead);
|
|
40
|
-
if (result.ok)
|
|
41
|
-
return result;
|
|
42
|
-
if (result.reason === "missing-ref") {
|
|
43
|
-
if (!startedMissing) {
|
|
44
|
-
return result;
|
|
45
|
-
}
|
|
46
|
-
currentHead = null;
|
|
47
|
-
continue;
|
|
48
|
-
}
|
|
49
|
-
currentHead = result.currentHead;
|
|
50
|
-
}
|
|
51
|
-
if (currentHead === null) {
|
|
52
|
-
return { ok: false, reason: "missing-ref" };
|
|
53
|
-
}
|
|
54
|
-
return { ok: false, reason: "conflict", currentHead };
|
|
55
|
-
}
|
|
56
|
-
async function readLedgerRef(cwd, ref, head) {
|
|
57
|
-
const commits = await listRefLogCommits(cwd, head, ref);
|
|
58
|
-
const entries = [];
|
|
59
|
-
for (const commit of commits) {
|
|
60
|
-
entries.push(parseLedgerEntryCommitMessage(await readRefLogCommitMessage(cwd, commit)));
|
|
61
|
-
}
|
|
62
|
-
return { ref, head, entries };
|
|
63
|
-
}
|
|
64
|
-
export async function readLedger(cwd, contractId) {
|
|
65
|
-
const ref = activeLedgerRef(contractId);
|
|
66
|
-
const head = await resolveRefLogHead(cwd, ref);
|
|
67
|
-
if (!head)
|
|
68
|
-
return null;
|
|
69
|
-
return { contractId, ...(await readLedgerRef(cwd, ref, head)) };
|
|
70
|
-
}
|
|
71
|
-
export async function listContractIds(cwd) {
|
|
72
|
-
const git = createGit(cwd);
|
|
73
|
-
try {
|
|
74
|
-
const output = await git.raw(["for-each-ref", "--format=%(refname)", ACTIVE_LEDGER_REF_PREFIX]);
|
|
75
|
-
return output
|
|
76
|
-
.split(/\r?\n/)
|
|
77
|
-
.map((line) => line.trim())
|
|
78
|
-
.filter((line) => line.startsWith(ACTIVE_LEDGER_REF_PREFIX))
|
|
79
|
-
.map((ref) => ref.slice(ACTIVE_LEDGER_REF_PREFIX.length));
|
|
80
|
-
}
|
|
81
|
-
catch (error) {
|
|
82
|
-
throw wrapGitError(`for-each-ref ${ACTIVE_LEDGER_REF_PREFIX}`, error, cwd);
|
|
83
|
-
}
|
|
84
|
-
}
|
|
@@ -1,87 +0,0 @@
|
|
|
1
|
-
import * as fs from "node:fs";
|
|
2
|
-
import * as path from "node:path";
|
|
3
|
-
import { DatabaseSync } from "node:sqlite";
|
|
4
|
-
import { isErrnoException } from "../../errno.js";
|
|
5
|
-
export const LEASH_FILE = "leash";
|
|
6
|
-
export class ProjectionLeashError extends Error {
|
|
7
|
-
code = "PROJECTION_LEASH_ERROR";
|
|
8
|
-
constructor(message, options) {
|
|
9
|
-
super(message, options);
|
|
10
|
-
this.name = "ProjectionLeashError";
|
|
11
|
-
}
|
|
12
|
-
}
|
|
13
|
-
export function leashPath(projectionDirectory) {
|
|
14
|
-
return path.join(projectionDirectory, LEASH_FILE);
|
|
15
|
-
}
|
|
16
|
-
function errorDetail(error) {
|
|
17
|
-
return error instanceof Error ? error.message : String(error);
|
|
18
|
-
}
|
|
19
|
-
function readJournalMode(database) {
|
|
20
|
-
const row = database.prepare("PRAGMA journal_mode").get();
|
|
21
|
-
return typeof row?.journal_mode === "string" ? row.journal_mode.toLowerCase() : undefined;
|
|
22
|
-
}
|
|
23
|
-
/**
|
|
24
|
-
* Birth-time initialization for the projection leash file.
|
|
25
|
-
* Creates a brand-new extensionless rollback-journal SQLite database with the
|
|
26
|
-
* minimal kernel-lock anchor schema, then closes all handles before return.
|
|
27
|
-
* Fails if the target already exists. Stores zero product facts.
|
|
28
|
-
*/
|
|
29
|
-
export function initializeProjectionLeash(projectionDirectory) {
|
|
30
|
-
let parent;
|
|
31
|
-
try {
|
|
32
|
-
parent = fs.statSync(projectionDirectory);
|
|
33
|
-
}
|
|
34
|
-
catch (error) {
|
|
35
|
-
throw new ProjectionLeashError(`projection leash parent directory does not exist at ${projectionDirectory}`, { cause: error });
|
|
36
|
-
}
|
|
37
|
-
if (!parent.isDirectory()) {
|
|
38
|
-
throw new ProjectionLeashError("projection leash parent must be a directory");
|
|
39
|
-
}
|
|
40
|
-
const target = leashPath(projectionDirectory);
|
|
41
|
-
let reserved = false;
|
|
42
|
-
try {
|
|
43
|
-
const fd = fs.openSync(target, "wx");
|
|
44
|
-
fs.closeSync(fd);
|
|
45
|
-
reserved = true;
|
|
46
|
-
}
|
|
47
|
-
catch (error) {
|
|
48
|
-
if (isErrnoException(error) && error.code === "EEXIST") {
|
|
49
|
-
throw new ProjectionLeashError(`projection leash already exists at ${target}`, { cause: error });
|
|
50
|
-
}
|
|
51
|
-
throw new ProjectionLeashError(`projection leash could not be initialized: ${errorDetail(error)}`, { cause: error });
|
|
52
|
-
}
|
|
53
|
-
let database;
|
|
54
|
-
try {
|
|
55
|
-
database = new DatabaseSync(target, {
|
|
56
|
-
enableDoubleQuotedStringLiterals: false,
|
|
57
|
-
allowExtension: false,
|
|
58
|
-
});
|
|
59
|
-
database.exec("PRAGMA busy_timeout = 0");
|
|
60
|
-
database.exec("PRAGMA journal_mode = DELETE");
|
|
61
|
-
database.exec("CREATE TABLE lock_anchor (id INTEGER PRIMARY KEY CHECK (id = 1))");
|
|
62
|
-
if (readJournalMode(database) !== "delete") {
|
|
63
|
-
throw new ProjectionLeashError("projection leash does not use rollback-journal mode");
|
|
64
|
-
}
|
|
65
|
-
database.prepare("SELECT id FROM lock_anchor LIMIT 1").get();
|
|
66
|
-
database.close();
|
|
67
|
-
database = undefined;
|
|
68
|
-
return target;
|
|
69
|
-
}
|
|
70
|
-
catch (error) {
|
|
71
|
-
try {
|
|
72
|
-
database?.close();
|
|
73
|
-
}
|
|
74
|
-
catch { /* preserve the causal initialization failure */ }
|
|
75
|
-
if (reserved) {
|
|
76
|
-
try {
|
|
77
|
-
fs.unlinkSync(target);
|
|
78
|
-
}
|
|
79
|
-
catch {
|
|
80
|
-
// Leave a partial file only if unlink itself fails.
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
if (error instanceof ProjectionLeashError)
|
|
84
|
-
throw error;
|
|
85
|
-
throw new ProjectionLeashError(`projection leash could not be initialized: ${errorDetail(error)}`, { cause: error });
|
|
86
|
-
}
|
|
87
|
-
}
|