@nestos/kanban 0.0.0-stage → 0.5.2
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/LICENSE +674 -0
- package/README.md +165 -2
- package/dist/activity-BbC4sgKL.d.cts +258 -0
- package/dist/activity-Czlan5xW.d.ts +258 -0
- package/dist/activity-module-DaO1Rry0.d.cts +22 -0
- package/dist/activity-module-T22wliZu.d.ts +22 -0
- package/dist/activity-ports-Dqxa86zT.d.cts +12 -0
- package/dist/activity-ports-cxfrelaL.d.ts +12 -0
- package/dist/activity.cjs +16 -0
- package/dist/activity.cjs.map +1 -0
- package/dist/activity.d.cts +12 -0
- package/dist/activity.d.ts +12 -0
- package/dist/activity.js +16 -0
- package/dist/activity.js.map +1 -0
- package/dist/chunk-3JYLJPE5.js +95 -0
- package/dist/chunk-3JYLJPE5.js.map +1 -0
- package/dist/chunk-3LEIHB7Y.js +221 -0
- package/dist/chunk-3LEIHB7Y.js.map +1 -0
- package/dist/chunk-4XF6LQSU.cjs +9 -0
- package/dist/chunk-4XF6LQSU.cjs.map +1 -0
- package/dist/chunk-5Q7WB63A.cjs +282 -0
- package/dist/chunk-5Q7WB63A.cjs.map +1 -0
- package/dist/chunk-7KDOTBRX.cjs +58 -0
- package/dist/chunk-7KDOTBRX.cjs.map +1 -0
- package/dist/chunk-AHHEGTUA.js +148 -0
- package/dist/chunk-AHHEGTUA.js.map +1 -0
- package/dist/chunk-AOHQCX7K.cjs +95 -0
- package/dist/chunk-AOHQCX7K.cjs.map +1 -0
- package/dist/chunk-DINLR6E6.cjs +443 -0
- package/dist/chunk-DINLR6E6.cjs.map +1 -0
- package/dist/chunk-EYTVC2H5.cjs +1612 -0
- package/dist/chunk-EYTVC2H5.cjs.map +1 -0
- package/dist/chunk-FEE2YBZ7.js +1972 -0
- package/dist/chunk-FEE2YBZ7.js.map +1 -0
- package/dist/chunk-FNO5K3A7.js +282 -0
- package/dist/chunk-FNO5K3A7.js.map +1 -0
- package/dist/chunk-IHHDXZPZ.js +382 -0
- package/dist/chunk-IHHDXZPZ.js.map +1 -0
- package/dist/chunk-J3EAIVA3.js +280 -0
- package/dist/chunk-J3EAIVA3.js.map +1 -0
- package/dist/chunk-KH3WF3K4.js +443 -0
- package/dist/chunk-KH3WF3K4.js.map +1 -0
- package/dist/chunk-M35X5PHO.js +196 -0
- package/dist/chunk-M35X5PHO.js.map +1 -0
- package/dist/chunk-QRGZD2JU.cjs +1972 -0
- package/dist/chunk-QRGZD2JU.cjs.map +1 -0
- package/dist/chunk-RBOER6EW.cjs +221 -0
- package/dist/chunk-RBOER6EW.cjs.map +1 -0
- package/dist/chunk-RQP77ZTY.js +9 -0
- package/dist/chunk-RQP77ZTY.js.map +1 -0
- package/dist/chunk-RSH6QSEC.cjs +196 -0
- package/dist/chunk-RSH6QSEC.cjs.map +1 -0
- package/dist/chunk-VMRDXOLX.cjs +148 -0
- package/dist/chunk-VMRDXOLX.cjs.map +1 -0
- package/dist/chunk-X4UHZX6F.js +58 -0
- package/dist/chunk-X4UHZX6F.js.map +1 -0
- package/dist/chunk-XBSGUVCY.cjs +382 -0
- package/dist/chunk-XBSGUVCY.cjs.map +1 -0
- package/dist/chunk-XKDZHAUE.js +1612 -0
- package/dist/chunk-XKDZHAUE.js.map +1 -0
- package/dist/chunk-ZUZGAO6G.cjs +280 -0
- package/dist/chunk-ZUZGAO6G.cjs.map +1 -0
- package/dist/content-C5aJZFlw.d.cts +35 -0
- package/dist/content-hLH5BNud.d.ts +35 -0
- package/dist/contracts/index.cjs +31 -0
- package/dist/contracts/index.cjs.map +1 -0
- package/dist/contracts/index.d.cts +5 -0
- package/dist/contracts/index.d.ts +5 -0
- package/dist/contracts/index.js +31 -0
- package/dist/contracts/index.js.map +1 -0
- package/dist/discovery-9E-LfwIw.d.cts +61 -0
- package/dist/discovery-D60yrjej.d.ts +61 -0
- package/dist/discovery.cjs +377 -0
- package/dist/discovery.cjs.map +1 -0
- package/dist/discovery.d.cts +22 -0
- package/dist/discovery.d.ts +22 -0
- package/dist/discovery.js +377 -0
- package/dist/discovery.js.map +1 -0
- package/dist/execution-bridge-fpCnH6z5.d.cts +52 -0
- package/dist/execution-bridge-rk0uVy_n.d.ts +52 -0
- package/dist/execution.cjs +18 -0
- package/dist/execution.cjs.map +1 -0
- package/dist/execution.d.cts +42 -0
- package/dist/execution.d.ts +42 -0
- package/dist/execution.js +18 -0
- package/dist/execution.js.map +1 -0
- package/dist/index.cjs +74 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +54 -0
- package/dist/index.d.ts +54 -0
- package/dist/index.js +74 -0
- package/dist/index.js.map +1 -0
- package/dist/module-CYfE7YhM.d.ts +11 -0
- package/dist/module-Ca9L3qCn.d.cts +11 -0
- package/dist/planning-CHrOqQ6b.d.cts +879 -0
- package/dist/planning-CHrOqQ6b.d.ts +879 -0
- package/dist/ports-B0McVg7B.d.ts +143 -0
- package/dist/ports-BeGO1VRI.d.cts +49 -0
- package/dist/ports-GQy0x-RI.d.cts +143 -0
- package/dist/ports-ykGiNUSx.d.ts +49 -0
- package/dist/runtime/index.cjs +205 -0
- package/dist/runtime/index.cjs.map +1 -0
- package/dist/runtime/index.d.cts +75 -0
- package/dist/runtime/index.d.ts +75 -0
- package/dist/runtime/index.js +205 -0
- package/dist/runtime/index.js.map +1 -0
- package/dist/runtime/integration.cjs +423 -0
- package/dist/runtime/integration.cjs.map +1 -0
- package/dist/runtime/integration.d.cts +658 -0
- package/dist/runtime/integration.d.ts +658 -0
- package/dist/runtime/integration.js +423 -0
- package/dist/runtime/integration.js.map +1 -0
- package/dist/storage.cjs +21 -0
- package/dist/storage.cjs.map +1 -0
- package/dist/storage.d.cts +71 -0
- package/dist/storage.d.ts +71 -0
- package/dist/storage.js +21 -0
- package/dist/storage.js.map +1 -0
- package/dist/store-DPwHzGiz.d.cts +28 -0
- package/dist/store-DgdrPCV9.d.ts +28 -0
- package/dist/task-projection-CSorlMws.d.ts +11 -0
- package/dist/task-projection-DKKB_ueb.d.cts +11 -0
- package/examples/standalone.ts +22 -0
- package/package.json +143 -4
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
import {
|
|
2
|
+
allocateBoardNumber,
|
|
3
|
+
archiveKey,
|
|
4
|
+
boardCounterKey,
|
|
5
|
+
boardKey,
|
|
6
|
+
boardNumberKey,
|
|
7
|
+
counter,
|
|
8
|
+
createBoardState,
|
|
9
|
+
decodeRow,
|
|
10
|
+
encodeBoard,
|
|
11
|
+
encodeRow,
|
|
12
|
+
hydrate,
|
|
13
|
+
indexedView,
|
|
14
|
+
numberEntities,
|
|
15
|
+
proposeAmendment,
|
|
16
|
+
receiptDigest,
|
|
17
|
+
reduce,
|
|
18
|
+
rowChanges,
|
|
19
|
+
rowKeys,
|
|
20
|
+
storedBoardNumber,
|
|
21
|
+
verifyReceipt,
|
|
22
|
+
viewFromState
|
|
23
|
+
} from "./chunk-XKDZHAUE.js";
|
|
24
|
+
import {
|
|
25
|
+
identity,
|
|
26
|
+
normalizeActor,
|
|
27
|
+
requireValue
|
|
28
|
+
} from "./chunk-3LEIHB7Y.js";
|
|
29
|
+
import {
|
|
30
|
+
KanbanError,
|
|
31
|
+
randomUUID
|
|
32
|
+
} from "./chunk-M35X5PHO.js";
|
|
33
|
+
|
|
34
|
+
// src/conditional-store.ts
|
|
35
|
+
var ConditionalKanbanStore = class {
|
|
36
|
+
constructor(client, prepareDirectory, path = "kanban/boards.seq", bodies) {
|
|
37
|
+
this.client = client;
|
|
38
|
+
this.prepareDirectory = prepareDirectory;
|
|
39
|
+
this.path = path;
|
|
40
|
+
this.bodies = bodies;
|
|
41
|
+
if (!bodies && client.readBody && client.writeBody) this.bodies = { read: async (hash) => {
|
|
42
|
+
try {
|
|
43
|
+
return await client.readBody(path, hash);
|
|
44
|
+
} catch (error) {
|
|
45
|
+
if (error?.remoteCode === "SEQ_BODY_INTEGRITY") throw new KanbanError("BODY_INTEGRITY");
|
|
46
|
+
throw error;
|
|
47
|
+
}
|
|
48
|
+
}, write: (hash, bytes) => client.writeBody(path, hash, bytes) };
|
|
49
|
+
}
|
|
50
|
+
async select(keys) {
|
|
51
|
+
return this.client.query(this.path, { keys });
|
|
52
|
+
}
|
|
53
|
+
async boardId(number) {
|
|
54
|
+
return entry(await this.select([boardNumberKey(number)]), boardNumberKey(number));
|
|
55
|
+
}
|
|
56
|
+
async ids() {
|
|
57
|
+
return JSON.parse(entry(await this.select(["index"]), "index") ?? "[]");
|
|
58
|
+
}
|
|
59
|
+
async view(id) {
|
|
60
|
+
const raw = entry(await this.select([boardKey(id)]), boardKey(id));
|
|
61
|
+
const indexed = indexedView(raw);
|
|
62
|
+
if (indexed) return indexed;
|
|
63
|
+
const state = await this.read(id);
|
|
64
|
+
return state ? viewFromState(state) : null;
|
|
65
|
+
}
|
|
66
|
+
async read(id) {
|
|
67
|
+
const snapshot = await this.select([boardKey(id)]);
|
|
68
|
+
return hydrate(await this.loadRows(entry(snapshot, boardKey(id)), snapshot.revision), this.bodies);
|
|
69
|
+
}
|
|
70
|
+
async loadRows(raw, revision) {
|
|
71
|
+
const keys = rowKeys(raw), rows = {};
|
|
72
|
+
for (let start = 0; start < keys.length; start += 256) {
|
|
73
|
+
requireValue(revision !== null, "INVALID_STORAGE");
|
|
74
|
+
const page = await this.queryRevision(keys.slice(start, start + 256), revision);
|
|
75
|
+
for (const row of page.entries) {
|
|
76
|
+
requireValue(typeof row.value === "string", "INVALID_STORAGE");
|
|
77
|
+
rows[row.key] = row.value;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
return { raw, rows };
|
|
81
|
+
}
|
|
82
|
+
async queryRevision(keys, expectedRevision) {
|
|
83
|
+
try {
|
|
84
|
+
return await this.client.query(this.path, { keys, expectedRevision });
|
|
85
|
+
} catch (error) {
|
|
86
|
+
if (error?.code === "ECONFLICT") throw new KanbanError("REVISION_CONFLICT");
|
|
87
|
+
throw error;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
async events(id, after, limit, through) {
|
|
91
|
+
const end = Math.min(through, after + limit);
|
|
92
|
+
const keys = Array.from({ length: Math.max(0, end - after) }, (_, index) => `event/${encodeURIComponent(id)}/${String(after + index + 1).padStart(16, "0")}`);
|
|
93
|
+
if (!keys.length) return [];
|
|
94
|
+
const events = [];
|
|
95
|
+
for (let start = 0; start < keys.length; start += 256) {
|
|
96
|
+
const rows = await this.select(keys.slice(start, start + 256));
|
|
97
|
+
events.push(...rows.entries.map((e) => JSON.parse(String(e.value))));
|
|
98
|
+
}
|
|
99
|
+
return events.sort((a, b) => a.sequence - b.sequence);
|
|
100
|
+
}
|
|
101
|
+
async archived(board, item) {
|
|
102
|
+
const raw = entry(await this.select([archiveKey(board, item)]), archiveKey(board, item));
|
|
103
|
+
if (!raw) return null;
|
|
104
|
+
const record = await decodeRow(raw, this.bodies);
|
|
105
|
+
record.item.number ??= (await this.view(board))?.state.archiveIndex?.find((value) => value.id === item)?.number;
|
|
106
|
+
return record;
|
|
107
|
+
}
|
|
108
|
+
async numberBoard(snapshot, raw, id, state) {
|
|
109
|
+
const high = counter(entry(snapshot, boardCounterKey)), number = allocateBoardNumber(raw, high);
|
|
110
|
+
state.board.number = number;
|
|
111
|
+
if (storedBoardNumber(raw) !== void 0) return [];
|
|
112
|
+
if (snapshot.revision !== null) {
|
|
113
|
+
const lookup = await this.queryRevision([boardNumberKey(number)], snapshot.revision), owner = entry(lookup, boardNumberKey(number));
|
|
114
|
+
requireValue(owner === null || owner === id, "INVALID_NUMBERING");
|
|
115
|
+
}
|
|
116
|
+
return [{ action: "set", key: boardCounterKey, value: String(Math.max(high, number)) }, { action: "set", key: boardNumberKey(number), value: id }];
|
|
117
|
+
}
|
|
118
|
+
async update(id, operationId, fingerprint, change) {
|
|
119
|
+
await this.prepareDirectory();
|
|
120
|
+
const receiptKey = `receipt/${encodeURIComponent(id)}/${encodeURIComponent(operationId)}`;
|
|
121
|
+
const snapshot = await this.select([boardKey(id), receiptKey, "index", boardCounterKey]);
|
|
122
|
+
const raw = entry(snapshot, boardKey(id)), receipt = entry(snapshot, receiptKey);
|
|
123
|
+
const before = await this.loadRows(raw, snapshot.revision), current = await hydrate(before, this.bodies);
|
|
124
|
+
if (receipt) {
|
|
125
|
+
verifyReceipt(receipt, fingerprint);
|
|
126
|
+
requireValue(current, "CORRUPT_RECEIPT");
|
|
127
|
+
return current;
|
|
128
|
+
}
|
|
129
|
+
const original = JSON.stringify(current), state = change(current);
|
|
130
|
+
numberEntities(state);
|
|
131
|
+
if (JSON.stringify(state) === original) return state;
|
|
132
|
+
const numbering = await this.numberBoard(snapshot, raw, id, state);
|
|
133
|
+
const { changes, encoded } = await prepareChanges(id, before, state, this.bodies);
|
|
134
|
+
changes.push(...numbering);
|
|
135
|
+
changes.push({ action: "set", key: boardKey(id), value: encoded.raw }, { action: "set", key: receiptKey, value: receiptDigest(fingerprint) });
|
|
136
|
+
const ids = JSON.parse(entry(snapshot, "index") ?? "[]");
|
|
137
|
+
if (!ids.includes(id)) changes.push({ action: "set", key: "index", value: JSON.stringify([...ids, id]) });
|
|
138
|
+
requireValue(changes.length <= 256, "REMOTE_TRANSACTION_LIMIT");
|
|
139
|
+
try {
|
|
140
|
+
await this.client.transaction(this.path, snapshot.revision, changes);
|
|
141
|
+
} catch (error) {
|
|
142
|
+
if (error?.outcome === "not-committed" && error?.code === "ECONFLICT") throw new KanbanError("REVISION_CONFLICT");
|
|
143
|
+
throw error;
|
|
144
|
+
}
|
|
145
|
+
return state;
|
|
146
|
+
}
|
|
147
|
+
};
|
|
148
|
+
function entry(snapshot, key) {
|
|
149
|
+
const value = snapshot.entries.find((e) => e.key === key)?.value;
|
|
150
|
+
if (value === void 0) return null;
|
|
151
|
+
if (typeof value !== "string") throw new KanbanError("INVALID_STORAGE");
|
|
152
|
+
return value;
|
|
153
|
+
}
|
|
154
|
+
async function prepareChanges(id, before, state, bodies) {
|
|
155
|
+
const changes = state.events.map((event) => ({
|
|
156
|
+
action: "set",
|
|
157
|
+
key: `event/${encodeURIComponent(id)}/${String(event.sequence).padStart(16, "0")}`,
|
|
158
|
+
value: JSON.stringify(event)
|
|
159
|
+
}));
|
|
160
|
+
for (const write of state.archiveWrites ?? []) changes.push(write.value ? { action: "set", key: archiveKey(id, write.id), value: await encodeRow(write.value, bodies) } : { action: "delete", key: archiveKey(id, write.id) });
|
|
161
|
+
delete state.archiveWrites;
|
|
162
|
+
state.events = [];
|
|
163
|
+
const encoded = await encodeBoard(state, bodies);
|
|
164
|
+
for (const row of rowChanges(before, encoded)) changes.push(row.value === null ? { action: "delete", key: row.key } : { action: "set", key: row.key, value: row.value });
|
|
165
|
+
return { changes, encoded };
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// src/content.ts
|
|
169
|
+
async function inspectKanbanContent(store, content) {
|
|
170
|
+
const state = await store.read(content.board.id);
|
|
171
|
+
const ids = new Set([...state?.board.items ?? [], ...state?.archiveIndex ?? []].map((item) => item.id));
|
|
172
|
+
return {
|
|
173
|
+
version: state?.presetVersions?.[content.id] ?? 0,
|
|
174
|
+
complete: !!state && content.items.every((item) => ids.has(item.command.item.id)) && (content.records ?? []).every((entry2) => state.records?.some((record) => record.id === entry2.record.id))
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
async function installKanbanContent(options) {
|
|
178
|
+
const started = (options.now ?? Date.now)(), content = structuredClone(options.content);
|
|
179
|
+
try {
|
|
180
|
+
identity(content.id);
|
|
181
|
+
identity(options.operationId);
|
|
182
|
+
validateContent(content);
|
|
183
|
+
const actor = normalizeActor(options.actor), before = await options.store.read(content.board.id);
|
|
184
|
+
const initial = before ?? createBoardState(content.board, actor, started);
|
|
185
|
+
await options.authorize({ actor, board: structuredClone(initial.board), action: "install-content" });
|
|
186
|
+
const result = { changed: false, created: 0 };
|
|
187
|
+
if (before && !options.fillMissing && (before.presetVersions?.[content.id] ?? 1) >= content.version) {
|
|
188
|
+
report(options, started, "success");
|
|
189
|
+
return result;
|
|
190
|
+
}
|
|
191
|
+
await options.store.update(content.board.id, options.operationId, JSON.stringify({ content, actor, fillMissing: !!options.fillMissing, missingReferences: options.missingReferences }), (current) => {
|
|
192
|
+
requireValue(JSON.stringify(current) === JSON.stringify(before), "REVISION_CONFLICT");
|
|
193
|
+
if (current?.board.deletedAt !== void 0) {
|
|
194
|
+
requireValue(!options.fillMissing, "BOARD_DELETED");
|
|
195
|
+
return current;
|
|
196
|
+
}
|
|
197
|
+
const installed = current?.presetVersions?.[content.id] ?? (current ? 1 : 0);
|
|
198
|
+
if (current && !options.fillMissing && installed >= content.version) return current;
|
|
199
|
+
const state = current ?? initial;
|
|
200
|
+
result.changed = !current;
|
|
201
|
+
applyContent(state, { ...options, content }, actor, installed, started, result);
|
|
202
|
+
(state.presetVersions ??= {})[content.id] = content.version;
|
|
203
|
+
return state;
|
|
204
|
+
});
|
|
205
|
+
report(options, started, "success");
|
|
206
|
+
return result;
|
|
207
|
+
} catch (error) {
|
|
208
|
+
const raw = error?.code;
|
|
209
|
+
report(options, started, "failure", typeof raw === "string" && /^[A-Z][A-Z0-9_]{0,79}$/.test(raw) ? raw : "CONTENT_INSTALL_FAILED");
|
|
210
|
+
throw error;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
function validateContent(content) {
|
|
214
|
+
requireValue(Number.isSafeInteger(content.version) && content.version > 0, "INVALID_CONTENT_VERSION");
|
|
215
|
+
requireValue(Array.isArray(content.items) && content.items.length <= 1e3, "CONTENT_ITEM_LIMIT");
|
|
216
|
+
for (const rows of [content.records, content.amendments]) requireValue(rows === void 0 || Array.isArray(rows) && rows.length <= 1e3, "CONTENT_RECORD_LIMIT");
|
|
217
|
+
for (const entry2 of [...content.items, ...content.records ?? [], ...content.amendments ?? []]) {
|
|
218
|
+
const version = entry2.introduced ?? 1;
|
|
219
|
+
requireValue(Number.isSafeInteger(version) && version > 0 && version <= content.version, "INVALID_CONTENT_VERSION");
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
function applyContent(state, options, actor, installed, now, result) {
|
|
223
|
+
const content = options.content, version = options.fillMissing ? 0 : installed;
|
|
224
|
+
const known = new Set([...state.board.items, ...state.archiveIndex ?? []].map((item) => item.id));
|
|
225
|
+
const apply = (command) => reduce(state, command, actor, options.operationId, now, (options.id ?? randomUUID)());
|
|
226
|
+
for (const entry2 of content.items) {
|
|
227
|
+
if (known.has(entry2.command.item.id) || (entry2.introduced ?? 1) <= version) continue;
|
|
228
|
+
insertItem(state, entry2, options.missingReferences === "detach", apply);
|
|
229
|
+
known.add(entry2.command.item.id);
|
|
230
|
+
result.changed = true;
|
|
231
|
+
result.created++;
|
|
232
|
+
}
|
|
233
|
+
for (const entry2 of content.records ?? []) {
|
|
234
|
+
if ((entry2.introduced ?? 1) <= version || state.records?.some((record2) => record2.id === entry2.record.id)) continue;
|
|
235
|
+
const record = structuredClone(entry2.record);
|
|
236
|
+
if (options.missingReferences === "detach") record.itemIds = record.itemIds.filter((id) => known.has(id));
|
|
237
|
+
apply({ type: "append-record", record });
|
|
238
|
+
if (entry2.confirmed) apply({ type: "review-record", recordId: record.id, accept: true });
|
|
239
|
+
result.changed = true;
|
|
240
|
+
}
|
|
241
|
+
for (const entry2 of content.amendments ?? []) {
|
|
242
|
+
if ((entry2.introduced ?? 1) <= version) continue;
|
|
243
|
+
const item = state.board.items.find((item2) => item2.id === entry2.itemId);
|
|
244
|
+
if (!item) continue;
|
|
245
|
+
const count = item.amendments?.length ?? 0;
|
|
246
|
+
proposeAmendment(item, { action: "update", ...entry2, sources: [] }, entry2.proposedBy, now, entry2.runId);
|
|
247
|
+
if ((item.amendments?.length ?? 0) > count) {
|
|
248
|
+
item.revision++;
|
|
249
|
+
state.board.revision++;
|
|
250
|
+
result.changed = true;
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
function insertItem(state, entry2, detach, apply) {
|
|
255
|
+
const command = structuredClone(entry2.command), parentId = command.planning?.parentId;
|
|
256
|
+
if (detach && parentId) {
|
|
257
|
+
const parent = state.board.items.find((item) => item.id === parentId);
|
|
258
|
+
if (!parent || ["completed", "cancelled"].includes(parent.status)) delete command.planning.parentId;
|
|
259
|
+
}
|
|
260
|
+
const itemId = command.item.id;
|
|
261
|
+
apply(command);
|
|
262
|
+
if (entry2.blocked) apply({ type: "block-item", itemId, reason: entry2.blocked });
|
|
263
|
+
if (entry2.completion) {
|
|
264
|
+
apply({ type: "close-plan", itemId, resultRef: entry2.completion.resultRef });
|
|
265
|
+
if (entry2.completion.archiveReason) apply({ type: "archive-items", itemIds: [itemId], reason: entry2.completion.archiveReason });
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
function report(options, start, result, code) {
|
|
269
|
+
try {
|
|
270
|
+
options.log({ operationId: options.operationId, boardId: options.content.board.id, stage: "content.install", result, code, durationMs: (options.now ?? Date.now)() - start });
|
|
271
|
+
} catch {
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
export {
|
|
276
|
+
ConditionalKanbanStore,
|
|
277
|
+
inspectKanbanContent,
|
|
278
|
+
installKanbanContent
|
|
279
|
+
};
|
|
280
|
+
//# sourceMappingURL=chunk-J3EAIVA3.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/conditional-store.ts","../src/content.ts"],"sourcesContent":["import {numberEntities, boardCounterKey, boardNumberKey, counter, allocateBoardNumber, storedBoardNumber} from './numbering';\nimport type {KanbanSeqClient, KanbanSeqChange, KanbanSeqSnapshot} from './storage-ports';\nimport type {KanbanEvent, KanbanArchivedItem} from './contracts';\nimport {KanbanError, type KanbanState, type KanbanStore} from './ports';\nimport {requireValue} from './rules';\nimport {indexedView, viewFromState, archiveKey, boardKey as key, rowKeys, hydrate, encodeBoard, rowChanges, encodeRow, decodeRow, receiptDigest, verifyReceipt, type StoredBoard, type KanbanBodyStore} from './storage-codec';\n\n/** The project export and its authorization are frozen in the injected HTTP client. */\nexport class ConditionalKanbanStore implements KanbanStore {\n constructor(private readonly client: Pick<KanbanSeqClient, 'query' | 'transaction'> & Partial<Pick<KanbanSeqClient, 'readBody' | 'writeBody'>>,\n private readonly prepareDirectory: () => Promise<void>, private readonly path = 'kanban/boards.seq', private readonly bodies?: KanbanBodyStore) {\n if (!bodies && client.readBody && client.writeBody) this.bodies = {read: async hash => {\n try {return await client.readBody!(path, hash);}\n catch (error) {if ((error as {remoteCode?: string})?.remoteCode === 'SEQ_BODY_INTEGRITY') throw new KanbanError('BODY_INTEGRITY'); throw error;}\n }, write: (hash, bytes) => client.writeBody!(path, hash, bytes)};\n }\n private async select(keys: string[]): Promise<KanbanSeqSnapshot> {return this.client.query(this.path, {keys});}\n async boardId(number: number): Promise<string | null> {return entry(await this.select([boardNumberKey(number)]), boardNumberKey(number));}\n async ids(): Promise<string[]> {return JSON.parse(entry(await this.select(['index']), 'index') ?? '[]');}\n async view(id: string) {\n const raw = entry(await this.select([key(id)]), key(id));\n const indexed = indexedView(raw); if (indexed) return indexed;\n const state = await this.read(id); return state ? viewFromState(state) : null;\n }\n async read(id: string): Promise<KanbanState | null> {\n const snapshot = await this.select([key(id)]);\n return hydrate(await this.loadRows(entry(snapshot, key(id)), snapshot.revision), this.bodies);\n }\n private async loadRows(raw: string | null, revision: string | null): Promise<StoredBoard> {\n const keys = rowKeys(raw), rows: Record<string, string> = {};\n for (let start = 0; start < keys.length; start += 256) {\n requireValue(revision !== null, 'INVALID_STORAGE');\n const page = await this.queryRevision(keys.slice(start, start + 256), revision);\n for (const row of page.entries) {requireValue(typeof row.value === 'string', 'INVALID_STORAGE'); rows[row.key] = row.value;}\n }\n return {raw, rows};\n }\n private async queryRevision(keys: string[], expectedRevision: string) {\n try {return await this.client.query(this.path, {keys, expectedRevision});}\n catch (error) {\n if ((error as {code?: string})?.code === 'ECONFLICT') throw new KanbanError('REVISION_CONFLICT');\n throw error;\n }\n }\n async events(id: string, after: number, limit: number, through: number): Promise<KanbanEvent[]> {\n const end = Math.min(through, after + limit);\n const keys = Array.from({length: Math.max(0, end - after)}, (_, index) =>\n `event/${encodeURIComponent(id)}/${String(after + index + 1).padStart(16, '0')}`);\n if (!keys.length) return [];\n const events: KanbanEvent[] = [];\n // Event keys below through are immutable; concurrent appends cannot change this prefix.\n for (let start = 0; start < keys.length; start += 256) {\n const rows = await this.select(keys.slice(start, start + 256));\n events.push(...rows.entries.map(e => JSON.parse(String(e.value)) as KanbanEvent));\n }\n return events.sort((a, b) => a.sequence - b.sequence);\n }\n async archived(board: string, item: string): Promise<KanbanArchivedItem | null> {\n const raw = entry(await this.select([archiveKey(board, item)]), archiveKey(board, item));\n if (!raw) return null; const record = await decodeRow<KanbanArchivedItem>(raw, this.bodies);\n record.item.number ??= (await this.view(board))?.state.archiveIndex?.find(value => value.id === item)?.number; return record;\n }\n private async numberBoard(snapshot: KanbanSeqSnapshot, raw: string | null, id: string, state: KanbanState): Promise<KanbanSeqChange[]> {\n const high = counter(entry(snapshot, boardCounterKey)), number = allocateBoardNumber(raw, high);\n state.board.number = number;\n if (storedBoardNumber(raw) !== undefined) return [];\n if (snapshot.revision !== null) {\n const lookup = await this.queryRevision([boardNumberKey(number)], snapshot.revision), owner = entry(lookup, boardNumberKey(number));\n requireValue(owner === null || owner === id, 'INVALID_NUMBERING');\n }\n return [{action:'set',key:boardCounterKey,value:String(Math.max(high,number))}, {action:'set',key:boardNumberKey(number),value:id}];\n }\n async update(id: string, operationId: string, fingerprint: string,\n change: (state: KanbanState | null) => KanbanState): Promise<KanbanState> {\n await this.prepareDirectory();\n const receiptKey = `receipt/${encodeURIComponent(id)}/${encodeURIComponent(operationId)}`;\n const snapshot = await this.select([key(id), receiptKey, 'index', boardCounterKey]);\n const raw = entry(snapshot, key(id)), receipt = entry(snapshot, receiptKey);\n const before = await this.loadRows(raw, snapshot.revision), current = await hydrate(before, this.bodies);\n if (receipt) {verifyReceipt(receipt, fingerprint); requireValue(current, 'CORRUPT_RECEIPT'); return current;}\n const original = JSON.stringify(current), state = change(current); numberEntities(state); if (JSON.stringify(state) === original) return state;\n const numbering = await this.numberBoard(snapshot, raw, id, state);\n const {changes, encoded} = await prepareChanges(id, before, state, this.bodies);\n changes.push(...numbering);\n changes.push({action: 'set', key: key(id), value: encoded.raw!}, {action: 'set', key: receiptKey, value: receiptDigest(fingerprint)});\n const ids: string[] = JSON.parse(entry(snapshot, 'index') ?? '[]');\n if (!ids.includes(id)) changes.push({action: 'set', key: 'index', value: JSON.stringify([...ids, id])});\n requireValue(changes.length <= 256, 'REMOTE_TRANSACTION_LIMIT');\n // The transport owns unknown-write reconciliation. Never retry a mutation here.\n try {await this.client.transaction(this.path, snapshot.revision, changes);}\n catch (error) {\n if ((error as {outcome?: string})?.outcome === 'not-committed' && (error as {code?: string})?.code === 'ECONFLICT') throw new KanbanError('REVISION_CONFLICT');\n throw error;\n }\n return state;\n }\n}\nfunction entry(snapshot: KanbanSeqSnapshot, key: string): string | null {\n const value = snapshot.entries.find(e => e.key === key)?.value;\n if (value === undefined) return null;\n if (typeof value !== 'string') throw new KanbanError('INVALID_STORAGE'); return value;\n}\n\nasync function prepareChanges(id: string, before: StoredBoard, state: KanbanState, bodies?: KanbanBodyStore) {\n const changes: KanbanSeqChange[] = state.events.map(event => ({action: 'set',\n key: `event/${encodeURIComponent(id)}/${String(event.sequence).padStart(16, '0')}`, value: JSON.stringify(event)}));\n for (const write of state.archiveWrites ?? []) changes.push(write.value\n ? {action: 'set', key: archiveKey(id, write.id), value: await encodeRow(write.value, bodies)}\n : {action: 'delete', key: archiveKey(id, write.id)});\n delete state.archiveWrites; state.events = [];\n const encoded = await encodeBoard(state, bodies);\n for (const row of rowChanges(before, encoded)) changes.push(row.value === null ? {action: 'delete', key: row.key} : {action: 'set', key: row.key, value: row.value});\n return {changes, encoded};\n}\n","import type {KanbanActor, KanbanCommand, KanbanContent, KanbanContentItem} from './contracts';\nimport type {KanbanModuleOptions, KanbanState, KanbanStore} from './ports';\nimport {createBoardState} from './board';\nimport {normalizeActor} from './identity';\nimport {identity, requireValue} from './rules';\nimport {reduce} from './reducer';\nimport {proposeAmendment} from './amendments';\nimport {randomUUID} from './utils';\n\nexport interface KanbanContentOptions extends KanbanModuleOptions {\n content: KanbanContent;\n operationId: string;\n fillMissing?: boolean;\n missingReferences?: 'reject' | 'detach';\n}\nexport async function inspectKanbanContent(store: KanbanStore, content: KanbanContent) {\n const state = await store.read(content.board.id);\n const ids = new Set([...state?.board.items ?? [], ...state?.archiveIndex ?? []].map(item => item.id));\n return {version: state?.presetVersions?.[content.id] ?? 0,\n complete: !!state && content.items.every(item => ids.has(item.command.item.id)) && (content.records ?? []).every(entry => state.records?.some(record => record.id === entry.record.id))};\n}\n\n/** Authorized bootstrap/import: domain changes and the installed version commit together. */\nexport async function installKanbanContent(options: KanbanContentOptions): Promise<{changed: boolean; created: number}> {\n const started = (options.now ?? Date.now)(), content = structuredClone(options.content);\n try {\n identity(content.id); identity(options.operationId);\n validateContent(content);\n const actor = normalizeActor(options.actor), before = await options.store.read(content.board.id);\n const initial = before ?? createBoardState(content.board, actor, started);\n await options.authorize({actor, board: structuredClone(initial.board), action: 'install-content'});\n const result = {changed: false, created: 0};\n if (before && !options.fillMissing && (before.presetVersions?.[content.id] ?? 1) >= content.version) {report(options, started, 'success'); return result;}\n await options.store.update(content.board.id, options.operationId, JSON.stringify({content, actor, fillMissing: !!options.fillMissing, missingReferences: options.missingReferences}), current => {\n requireValue(JSON.stringify(current) === JSON.stringify(before), 'REVISION_CONFLICT');\n if (current?.board.deletedAt !== undefined) {requireValue(!options.fillMissing, 'BOARD_DELETED'); return current;}\n const installed = current?.presetVersions?.[content.id] ?? (current ? 1 : 0);\n if (current && !options.fillMissing && installed >= content.version) return current;\n const state = current ?? initial; result.changed = !current;\n applyContent(state, {...options, content}, actor, installed, started, result);\n (state.presetVersions ??= {})[content.id] = content.version;\n return state;\n });\n report(options, started, 'success'); return result;\n } catch (error) {\n const raw = (error as {code?: unknown})?.code;\n report(options, started, 'failure', typeof raw === 'string' && /^[A-Z][A-Z0-9_]{0,79}$/.test(raw) ? raw : 'CONTENT_INSTALL_FAILED');\n throw error;\n }\n}\nfunction validateContent(content: KanbanContent): void {\n requireValue(Number.isSafeInteger(content.version) && content.version > 0, 'INVALID_CONTENT_VERSION');\n requireValue(Array.isArray(content.items) && content.items.length <= 1000, 'CONTENT_ITEM_LIMIT');\n for (const rows of [content.records, content.amendments]) requireValue(rows === undefined || Array.isArray(rows) && rows.length <= 1000, 'CONTENT_RECORD_LIMIT');\n for (const entry of [...content.items, ...content.records ?? [], ...content.amendments ?? []]) {\n const version = entry.introduced ?? 1;\n requireValue(Number.isSafeInteger(version) && version > 0 && version <= content.version, 'INVALID_CONTENT_VERSION');\n }\n}\nfunction applyContent(state: KanbanState, options: KanbanContentOptions, actor: KanbanActor, installed: number, now: number, result: {changed: boolean; created: number}): void {\n const content = options.content, version = options.fillMissing ? 0 : installed;\n const known = new Set([...state.board.items, ...state.archiveIndex ?? []].map(item => item.id));\n const apply = (command: KanbanCommand) => reduce(state, command, actor, options.operationId, now, (options.id ?? randomUUID)());\n for (const entry of content.items) {\n if (known.has(entry.command.item.id) || (entry.introduced ?? 1) <= version) continue;\n insertItem(state, entry, options.missingReferences === 'detach', apply);\n known.add(entry.command.item.id); result.changed = true; result.created++;\n }\n for (const entry of content.records ?? []) {\n if ((entry.introduced ?? 1) <= version || state.records?.some(record => record.id === entry.record.id)) continue;\n const record = structuredClone(entry.record);\n if (options.missingReferences === 'detach') record.itemIds = record.itemIds.filter(id => known.has(id));\n apply({type: 'append-record', record});\n if (entry.confirmed) apply({type: 'review-record', recordId: record.id, accept: true});\n result.changed = true;\n }\n for (const entry of content.amendments ?? []) {\n if ((entry.introduced ?? 1) <= version) continue;\n const item = state.board.items.find(item => item.id === entry.itemId); if (!item) continue;\n const count = item.amendments?.length ?? 0;\n // Imported attribution grants no authority to execute or review work.\n proposeAmendment(item, {action: 'update', ...entry, sources: []}, entry.proposedBy, now, entry.runId);\n if ((item.amendments?.length ?? 0) > count) {item.revision++; state.board.revision++; result.changed = true;}\n }\n}\nfunction insertItem(state: KanbanState, entry: KanbanContentItem, detach: boolean, apply: (command: KanbanCommand) => void): void {\n const command = structuredClone(entry.command), parentId = command.planning?.parentId;\n if (detach && parentId) {\n const parent = state.board.items.find(item => item.id === parentId);\n if (!parent || ['completed', 'cancelled'].includes(parent.status)) delete command.planning!.parentId;\n }\n const itemId = command.item.id;\n apply(command);\n if (entry.blocked) apply({type: 'block-item', itemId, reason: entry.blocked});\n if (entry.completion) {\n apply({type: 'close-plan', itemId, resultRef: entry.completion.resultRef});\n if (entry.completion.archiveReason) apply({type: 'archive-items', itemIds: [itemId], reason: entry.completion.archiveReason});\n }\n}\nfunction report(options: KanbanContentOptions, start: number, result: 'success' | 'failure', code?: string): void {\n try {options.log({operationId: options.operationId, boardId: options.content.board.id, stage: 'content.install', result, code, durationMs: (options.now ?? Date.now)() - start});}\n catch { /* Diagnostics cannot undo content installation. */ }\n}\n"],"mappings":"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","names":["entry","record","item"]}
|