@nestos/kanban 0.5.1 → 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 +73 -29
- package/dist/{activity-C6xDM-cg.d.cts → activity-BbC4sgKL.d.cts} +28 -2
- package/dist/{activity-Dw8DOw0L.d.ts → activity-Czlan5xW.d.ts} +28 -2
- 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 +10 -282
- package/dist/activity.cjs.map +1 -1
- package/dist/activity.d.cts +8 -30
- package/dist/activity.d.ts +8 -30
- package/dist/activity.js +9 -281
- package/dist/activity.js.map +1 -1
- package/dist/{chunk-O4OGAAV4.js → chunk-3JYLJPE5.js} +29 -5
- package/dist/chunk-3JYLJPE5.js.map +1 -0
- package/dist/{chunk-ATUFFNLV.js → chunk-3LEIHB7Y.js} +5 -5
- package/dist/chunk-4XF6LQSU.cjs.map +1 -1
- package/dist/chunk-5Q7WB63A.cjs +282 -0
- package/dist/chunk-5Q7WB63A.cjs.map +1 -0
- package/dist/{chunk-PSKQAFDF.cjs → chunk-7KDOTBRX.cjs} +1 -1
- package/dist/chunk-7KDOTBRX.cjs.map +1 -0
- package/dist/{chunk-5DLZWW5Y.js → chunk-AHHEGTUA.js} +3 -3
- package/dist/chunk-AOHQCX7K.cjs +95 -0
- package/dist/chunk-AOHQCX7K.cjs.map +1 -0
- package/dist/{chunk-IUI5CI2S.cjs → chunk-DINLR6E6.cjs} +96 -92
- package/dist/chunk-DINLR6E6.cjs.map +1 -0
- package/dist/{chunk-L44TM4EE.cjs → chunk-EYTVC2H5.cjs} +568 -454
- 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-DFTOTBGF.js → chunk-KH3WF3K4.js} +20 -16
- package/dist/chunk-KH3WF3K4.js.map +1 -0
- package/dist/{chunk-TB2RZGDV.js → chunk-M35X5PHO.js} +14 -1
- 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-4KF7KUAI.cjs → chunk-RBOER6EW.cjs} +6 -6
- package/dist/chunk-RBOER6EW.cjs.map +1 -0
- package/dist/{chunk-6MN3H3YF.cjs → chunk-RSH6QSEC.cjs} +16 -3
- package/dist/chunk-RSH6QSEC.cjs.map +1 -0
- package/dist/{chunk-T7P5EIC4.cjs → chunk-VMRDXOLX.cjs} +33 -33
- package/dist/chunk-VMRDXOLX.cjs.map +1 -0
- package/dist/{chunk-5XKOCKY2.js → chunk-X4UHZX6F.js} +1 -1
- package/dist/chunk-XBSGUVCY.cjs +382 -0
- package/dist/chunk-XBSGUVCY.cjs.map +1 -0
- package/dist/{chunk-OHQTKGQN.js → chunk-XKDZHAUE.js} +242 -128
- 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-CAIp1njn.d.cts → content-C5aJZFlw.d.cts} +1 -1
- package/dist/{content-CGMJdyH_.d.ts → content-hLH5BNud.d.ts} +1 -1
- package/dist/contracts/index.cjs +13 -3
- package/dist/contracts/index.cjs.map +1 -1
- package/dist/contracts/index.d.cts +5 -4
- package/dist/contracts/index.d.ts +5 -4
- package/dist/contracts/index.js +14 -4
- package/dist/{discovery-DxpirOz3.d.cts → discovery-9E-LfwIw.d.cts} +1 -1
- package/dist/{discovery-gSqWpuRm.d.ts → discovery-D60yrjej.d.ts} +1 -1
- package/dist/discovery.cjs +63 -65
- package/dist/discovery.cjs.map +1 -1
- package/dist/discovery.d.cts +4 -4
- package/dist/discovery.d.ts +4 -4
- package/dist/discovery.js +5 -7
- package/dist/discovery.js.map +1 -1
- package/dist/execution-bridge-fpCnH6z5.d.cts +52 -0
- package/dist/execution-bridge-rk0uVy_n.d.ts +52 -0
- package/dist/execution.cjs +6 -356
- package/dist/execution.cjs.map +1 -1
- package/dist/execution.d.cts +4 -51
- package/dist/execution.d.ts +4 -51
- package/dist/execution.js +9 -359
- package/dist/execution.js.map +1 -1
- package/dist/index.cjs +10 -12
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +9 -16
- package/dist/index.d.ts +9 -16
- package/dist/index.js +10 -12
- package/dist/index.js.map +1 -1
- package/dist/{module-CWNK2BMj.d.ts → module-CYfE7YhM.d.ts} +2 -2
- package/dist/{module-BbvwdCDF.d.cts → module-Ca9L3qCn.d.cts} +2 -2
- package/dist/{planning-CcFZYdIL.d.cts → planning-CHrOqQ6b.d.cts} +45 -10
- package/dist/{planning-CcFZYdIL.d.ts → planning-CHrOqQ6b.d.ts} +45 -10
- package/dist/{ports-Bn6ro2FB.d.ts → ports-B0McVg7B.d.ts} +4 -3
- package/dist/ports-BeGO1VRI.d.cts +49 -0
- package/dist/{ports-CaL6geqR.d.cts → ports-GQy0x-RI.d.cts} +4 -3
- 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 +9 -277
- package/dist/storage.cjs.map +1 -1
- package/dist/storage.d.cts +6 -6
- package/dist/storage.d.ts +6 -6
- package/dist/storage.js +11 -279
- package/dist/storage.js.map +1 -1
- package/dist/{store-q63eSMoT.d.cts → store-DPwHzGiz.d.cts} +2 -2
- package/dist/{store-Ct0gOAAg.d.ts → store-DgdrPCV9.d.ts} +2 -2
- 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 +117 -87
- package/dist/chunk-2YFPV5GF.cjs +0 -16
- package/dist/chunk-2YFPV5GF.cjs.map +0 -1
- package/dist/chunk-4KF7KUAI.cjs.map +0 -1
- package/dist/chunk-6MN3H3YF.cjs.map +0 -1
- package/dist/chunk-DFTOTBGF.js.map +0 -1
- package/dist/chunk-G6FCDLDF.js +0 -16
- package/dist/chunk-G6FCDLDF.js.map +0 -1
- package/dist/chunk-IUI5CI2S.cjs.map +0 -1
- package/dist/chunk-KYNYPKKH.cjs +0 -71
- package/dist/chunk-KYNYPKKH.cjs.map +0 -1
- package/dist/chunk-L44TM4EE.cjs.map +0 -1
- package/dist/chunk-LSE6JG5I.cjs +0 -20
- package/dist/chunk-LSE6JG5I.cjs.map +0 -1
- package/dist/chunk-O4OGAAV4.js.map +0 -1
- package/dist/chunk-OHQTKGQN.js.map +0 -1
- package/dist/chunk-PSKQAFDF.cjs.map +0 -1
- package/dist/chunk-QTMTBEBA.js +0 -20
- package/dist/chunk-QTMTBEBA.js.map +0 -1
- package/dist/chunk-T7P5EIC4.cjs.map +0 -1
- package/dist/chunk-TB2RZGDV.js.map +0 -1
- package/dist/ui/index.cjs +0 -1961
- package/dist/ui/index.cjs.map +0 -1
- package/dist/ui/index.d.cts +0 -209
- package/dist/ui/index.d.ts +0 -209
- package/dist/ui/index.js +0 -1961
- package/dist/ui/index.js.map +0 -1
- package/dist/ui/kanban.css +0 -194
- /package/dist/{chunk-ATUFFNLV.js.map → chunk-3LEIHB7Y.js.map} +0 -0
- /package/dist/{chunk-5DLZWW5Y.js.map → chunk-AHHEGTUA.js.map} +0 -0
- /package/dist/{chunk-5XKOCKY2.js.map → chunk-X4UHZX6F.js.map} +0 -0
package/dist/storage.cjs
CHANGED
|
@@ -1,289 +1,21 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports, "__esModule", {value: true});
|
|
1
|
+
"use strict";Object.defineProperty(exports, "__esModule", {value: true});
|
|
2
2
|
|
|
3
|
-
var _chunkT7P5EIC4cjs = require('./chunk-T7P5EIC4.cjs');
|
|
4
3
|
|
|
5
4
|
|
|
5
|
+
var _chunkZUZGAO6Gcjs = require('./chunk-ZUZGAO6G.cjs');
|
|
6
6
|
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
var _chunkL44TM4EEcjs = require('./chunk-L44TM4EE.cjs');
|
|
8
|
+
var _chunkVMRDXOLXcjs = require('./chunk-VMRDXOLX.cjs');
|
|
9
|
+
require('./chunk-EYTVC2H5.cjs');
|
|
27
10
|
require('./chunk-4XF6LQSU.cjs');
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
var _chunk4KF7KUAIcjs = require('./chunk-4KF7KUAI.cjs');
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
var _chunk2YFPV5GFcjs = require('./chunk-2YFPV5GF.cjs');
|
|
36
|
-
require('./chunk-KYNYPKKH.cjs');
|
|
37
|
-
require('./chunk-PSKQAFDF.cjs');
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
var _chunk6MN3H3YFcjs = require('./chunk-6MN3H3YF.cjs');
|
|
41
|
-
require('./chunk-LSE6JG5I.cjs');
|
|
42
|
-
|
|
43
|
-
// src/conditional-store.ts
|
|
44
|
-
var ConditionalKanbanStore = class {
|
|
45
|
-
constructor(client, prepareDirectory, path = "kanban/boards.seq", bodies) {
|
|
46
|
-
this.client = client;
|
|
47
|
-
this.prepareDirectory = prepareDirectory;
|
|
48
|
-
this.path = path;
|
|
49
|
-
this.bodies = bodies;
|
|
50
|
-
if (!bodies && client.readBody && client.writeBody) this.bodies = { read: async (hash) => {
|
|
51
|
-
try {
|
|
52
|
-
return await client.readBody(path, hash);
|
|
53
|
-
} catch (error) {
|
|
54
|
-
if (_optionalChain([error, 'optionalAccess', _2 => _2.remoteCode]) === "SEQ_BODY_INTEGRITY") throw new (0, _chunk2YFPV5GFcjs.KanbanError)("BODY_INTEGRITY");
|
|
55
|
-
throw error;
|
|
56
|
-
}
|
|
57
|
-
}, write: (hash, bytes) => client.writeBody(path, hash, bytes) };
|
|
58
|
-
}
|
|
59
|
-
async select(keys) {
|
|
60
|
-
return this.client.query(this.path, { keys });
|
|
61
|
-
}
|
|
62
|
-
async boardId(number) {
|
|
63
|
-
return entry(await this.select([_chunkL44TM4EEcjs.boardNumberKey.call(void 0, number)]), _chunkL44TM4EEcjs.boardNumberKey.call(void 0, number));
|
|
64
|
-
}
|
|
65
|
-
async ids() {
|
|
66
|
-
return JSON.parse(await _asyncNullishCoalesce(entry(await this.select(["index"]), "index"), async () => ( "[]")));
|
|
67
|
-
}
|
|
68
|
-
async view(id) {
|
|
69
|
-
const raw = entry(await this.select([_chunkL44TM4EEcjs.boardKey.call(void 0, id)]), _chunkL44TM4EEcjs.boardKey.call(void 0, id));
|
|
70
|
-
const indexed = _chunkL44TM4EEcjs.indexedView.call(void 0, raw);
|
|
71
|
-
if (indexed) return indexed;
|
|
72
|
-
const state = await this.read(id);
|
|
73
|
-
return state ? _chunkL44TM4EEcjs.viewFromState.call(void 0, state) : null;
|
|
74
|
-
}
|
|
75
|
-
async read(id) {
|
|
76
|
-
const snapshot = await this.select([_chunkL44TM4EEcjs.boardKey.call(void 0, id)]);
|
|
77
|
-
return _chunkL44TM4EEcjs.hydrate.call(void 0, await this.loadRows(entry(snapshot, _chunkL44TM4EEcjs.boardKey.call(void 0, id)), snapshot.revision), this.bodies);
|
|
78
|
-
}
|
|
79
|
-
async loadRows(raw, revision) {
|
|
80
|
-
const keys = _chunkL44TM4EEcjs.rowKeys.call(void 0, raw), rows = {};
|
|
81
|
-
for (let start = 0; start < keys.length; start += 256) {
|
|
82
|
-
_chunk4KF7KUAIcjs.requireValue.call(void 0, revision !== null, "INVALID_STORAGE");
|
|
83
|
-
const page = await this.queryRevision(keys.slice(start, start + 256), revision);
|
|
84
|
-
for (const row of page.entries) {
|
|
85
|
-
_chunk4KF7KUAIcjs.requireValue.call(void 0, typeof row.value === "string", "INVALID_STORAGE");
|
|
86
|
-
rows[row.key] = row.value;
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
return { raw, rows };
|
|
90
|
-
}
|
|
91
|
-
async queryRevision(keys, expectedRevision) {
|
|
92
|
-
try {
|
|
93
|
-
return await this.client.query(this.path, { keys, expectedRevision });
|
|
94
|
-
} catch (error) {
|
|
95
|
-
if (_optionalChain([error, 'optionalAccess', _3 => _3.code]) === "ECONFLICT") throw new (0, _chunk2YFPV5GFcjs.KanbanError)("REVISION_CONFLICT");
|
|
96
|
-
throw error;
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
async events(id, after, limit, through) {
|
|
100
|
-
const end = Math.min(through, after + limit);
|
|
101
|
-
const keys = Array.from({ length: Math.max(0, end - after) }, (_, index) => `event/${encodeURIComponent(id)}/${String(after + index + 1).padStart(16, "0")}`);
|
|
102
|
-
if (!keys.length) return [];
|
|
103
|
-
const events = [];
|
|
104
|
-
for (let start = 0; start < keys.length; start += 256) {
|
|
105
|
-
const rows = await this.select(keys.slice(start, start + 256));
|
|
106
|
-
events.push(...rows.entries.map((e) => JSON.parse(String(e.value))));
|
|
107
|
-
}
|
|
108
|
-
return events.sort((a, b) => a.sequence - b.sequence);
|
|
109
|
-
}
|
|
110
|
-
async archived(board, item) {
|
|
111
|
-
const raw = entry(await this.select([_chunkL44TM4EEcjs.archiveKey.call(void 0, board, item)]), _chunkL44TM4EEcjs.archiveKey.call(void 0, board, item));
|
|
112
|
-
if (!raw) return null;
|
|
113
|
-
const record = await _chunkL44TM4EEcjs.decodeRow.call(void 0, raw, this.bodies);
|
|
114
|
-
record.item.number ??= await _asyncOptionalChain([(await this.view(board)), 'optionalAccess', async _4 => _4.state, 'access', async _5 => _5.archiveIndex, 'optionalAccess', async _6 => _6.find, 'call', async _7 => _7((value) => value.id === item), 'optionalAccess', async _8 => _8.number]);
|
|
115
|
-
return record;
|
|
116
|
-
}
|
|
117
|
-
async numberBoard(snapshot, raw, id, state) {
|
|
118
|
-
const high = _chunkL44TM4EEcjs.counter.call(void 0, entry(snapshot, _chunkL44TM4EEcjs.boardCounterKey)), number = _chunkL44TM4EEcjs.allocateBoardNumber.call(void 0, raw, high);
|
|
119
|
-
state.board.number = number;
|
|
120
|
-
if (_chunkL44TM4EEcjs.storedBoardNumber.call(void 0, raw) !== void 0) return [];
|
|
121
|
-
if (snapshot.revision !== null) {
|
|
122
|
-
const lookup = await this.queryRevision([_chunkL44TM4EEcjs.boardNumberKey.call(void 0, number)], snapshot.revision), owner = entry(lookup, _chunkL44TM4EEcjs.boardNumberKey.call(void 0, number));
|
|
123
|
-
_chunk4KF7KUAIcjs.requireValue.call(void 0, owner === null || owner === id, "INVALID_NUMBERING");
|
|
124
|
-
}
|
|
125
|
-
return [{ action: "set", key: _chunkL44TM4EEcjs.boardCounterKey, value: String(Math.max(high, number)) }, { action: "set", key: _chunkL44TM4EEcjs.boardNumberKey.call(void 0, number), value: id }];
|
|
126
|
-
}
|
|
127
|
-
async update(id, operationId, fingerprint, change) {
|
|
128
|
-
await this.prepareDirectory();
|
|
129
|
-
const receiptKey = `receipt/${encodeURIComponent(id)}/${encodeURIComponent(operationId)}`;
|
|
130
|
-
const snapshot = await this.select([_chunkL44TM4EEcjs.boardKey.call(void 0, id), receiptKey, "index", _chunkL44TM4EEcjs.boardCounterKey]);
|
|
131
|
-
const raw = entry(snapshot, _chunkL44TM4EEcjs.boardKey.call(void 0, id)), receipt = entry(snapshot, receiptKey);
|
|
132
|
-
const before = await this.loadRows(raw, snapshot.revision), current = await _chunkL44TM4EEcjs.hydrate.call(void 0, before, this.bodies);
|
|
133
|
-
if (receipt) {
|
|
134
|
-
_chunkL44TM4EEcjs.verifyReceipt.call(void 0, receipt, fingerprint);
|
|
135
|
-
_chunk4KF7KUAIcjs.requireValue.call(void 0, current, "CORRUPT_RECEIPT");
|
|
136
|
-
return current;
|
|
137
|
-
}
|
|
138
|
-
const original = JSON.stringify(current), state = change(current);
|
|
139
|
-
_chunkL44TM4EEcjs.numberEntities.call(void 0, state);
|
|
140
|
-
if (JSON.stringify(state) === original) return state;
|
|
141
|
-
const numbering = await this.numberBoard(snapshot, raw, id, state);
|
|
142
|
-
const { changes, encoded } = await prepareChanges(id, before, state, this.bodies);
|
|
143
|
-
changes.push(...numbering);
|
|
144
|
-
changes.push({ action: "set", key: _chunkL44TM4EEcjs.boardKey.call(void 0, id), value: encoded.raw }, { action: "set", key: receiptKey, value: _chunkL44TM4EEcjs.receiptDigest.call(void 0, fingerprint) });
|
|
145
|
-
const ids = JSON.parse(_nullishCoalesce(entry(snapshot, "index"), () => ( "[]")));
|
|
146
|
-
if (!ids.includes(id)) changes.push({ action: "set", key: "index", value: JSON.stringify([...ids, id]) });
|
|
147
|
-
_chunk4KF7KUAIcjs.requireValue.call(void 0, changes.length <= 256, "REMOTE_TRANSACTION_LIMIT");
|
|
148
|
-
try {
|
|
149
|
-
await this.client.transaction(this.path, snapshot.revision, changes);
|
|
150
|
-
} catch (error) {
|
|
151
|
-
if (_optionalChain([error, 'optionalAccess', _9 => _9.outcome]) === "not-committed" && _optionalChain([error, 'optionalAccess', _10 => _10.code]) === "ECONFLICT") throw new (0, _chunk2YFPV5GFcjs.KanbanError)("REVISION_CONFLICT");
|
|
152
|
-
throw error;
|
|
153
|
-
}
|
|
154
|
-
return state;
|
|
155
|
-
}
|
|
156
|
-
};
|
|
157
|
-
function entry(snapshot, key) {
|
|
158
|
-
const value = _optionalChain([snapshot, 'access', _11 => _11.entries, 'access', _12 => _12.find, 'call', _13 => _13((e) => e.key === key), 'optionalAccess', _14 => _14.value]);
|
|
159
|
-
if (value === void 0) return null;
|
|
160
|
-
if (typeof value !== "string") throw new (0, _chunk2YFPV5GFcjs.KanbanError)("INVALID_STORAGE");
|
|
161
|
-
return value;
|
|
162
|
-
}
|
|
163
|
-
async function prepareChanges(id, before, state, bodies) {
|
|
164
|
-
const changes = state.events.map((event) => ({
|
|
165
|
-
action: "set",
|
|
166
|
-
key: `event/${encodeURIComponent(id)}/${String(event.sequence).padStart(16, "0")}`,
|
|
167
|
-
value: JSON.stringify(event)
|
|
168
|
-
}));
|
|
169
|
-
for (const write of _nullishCoalesce(state.archiveWrites, () => ( []))) changes.push(write.value ? { action: "set", key: _chunkL44TM4EEcjs.archiveKey.call(void 0, id, write.id), value: await _chunkL44TM4EEcjs.encodeRow.call(void 0, write.value, bodies) } : { action: "delete", key: _chunkL44TM4EEcjs.archiveKey.call(void 0, id, write.id) });
|
|
170
|
-
delete state.archiveWrites;
|
|
171
|
-
state.events = [];
|
|
172
|
-
const encoded = await _chunkL44TM4EEcjs.encodeBoard.call(void 0, state, bodies);
|
|
173
|
-
for (const row of _chunkL44TM4EEcjs.rowChanges.call(void 0, before, encoded)) changes.push(row.value === null ? { action: "delete", key: row.key } : { action: "set", key: row.key, value: row.value });
|
|
174
|
-
return { changes, encoded };
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
// src/content.ts
|
|
178
|
-
async function inspectKanbanContent(store, content) {
|
|
179
|
-
const state = await store.read(content.board.id);
|
|
180
|
-
const ids = new Set([..._nullishCoalesce(_optionalChain([state, 'optionalAccess', _15 => _15.board, 'access', _16 => _16.items]), () => ( [])), ..._nullishCoalesce(_optionalChain([state, 'optionalAccess', _17 => _17.archiveIndex]), () => ( []))].map((item) => item.id));
|
|
181
|
-
return {
|
|
182
|
-
version: _nullishCoalesce(_optionalChain([state, 'optionalAccess', _18 => _18.presetVersions, 'optionalAccess', _19 => _19[content.id]]), () => ( 0)),
|
|
183
|
-
complete: !!state && content.items.every((item) => ids.has(item.command.item.id)) && (_nullishCoalesce(content.records, () => ( []))).every((entry2) => _optionalChain([state, 'access', _20 => _20.records, 'optionalAccess', _21 => _21.some, 'call', _22 => _22((record) => record.id === entry2.record.id)]))
|
|
184
|
-
};
|
|
185
|
-
}
|
|
186
|
-
async function installKanbanContent(options) {
|
|
187
|
-
const started = (_nullishCoalesce(options.now, () => ( Date.now)))(), content = structuredClone(options.content);
|
|
188
|
-
try {
|
|
189
|
-
_chunk4KF7KUAIcjs.identity.call(void 0, content.id);
|
|
190
|
-
_chunk4KF7KUAIcjs.identity.call(void 0, options.operationId);
|
|
191
|
-
validateContent(content);
|
|
192
|
-
const actor = _chunk4KF7KUAIcjs.normalizeActor.call(void 0, options.actor), before = await options.store.read(content.board.id);
|
|
193
|
-
const initial = _nullishCoalesce(before, () => ( _chunkL44TM4EEcjs.createBoardState.call(void 0, content.board, actor, started)));
|
|
194
|
-
await options.authorize({ actor, board: structuredClone(initial.board), action: "install-content" });
|
|
195
|
-
const result = { changed: false, created: 0 };
|
|
196
|
-
if (before && !options.fillMissing && (_nullishCoalesce(_optionalChain([before, 'access', _23 => _23.presetVersions, 'optionalAccess', _24 => _24[content.id]]), () => ( 1))) >= content.version) {
|
|
197
|
-
report(options, started, "success");
|
|
198
|
-
return result;
|
|
199
|
-
}
|
|
200
|
-
await options.store.update(content.board.id, options.operationId, JSON.stringify({ content, actor, fillMissing: !!options.fillMissing, missingReferences: options.missingReferences }), (current) => {
|
|
201
|
-
_chunk4KF7KUAIcjs.requireValue.call(void 0, JSON.stringify(current) === JSON.stringify(before), "REVISION_CONFLICT");
|
|
202
|
-
if (_optionalChain([current, 'optionalAccess', _25 => _25.board, 'access', _26 => _26.deletedAt]) !== void 0) {
|
|
203
|
-
_chunk4KF7KUAIcjs.requireValue.call(void 0, !options.fillMissing, "BOARD_DELETED");
|
|
204
|
-
return current;
|
|
205
|
-
}
|
|
206
|
-
const installed = _nullishCoalesce(_optionalChain([current, 'optionalAccess', _27 => _27.presetVersions, 'optionalAccess', _28 => _28[content.id]]), () => ( (current ? 1 : 0)));
|
|
207
|
-
if (current && !options.fillMissing && installed >= content.version) return current;
|
|
208
|
-
const state = _nullishCoalesce(current, () => ( initial));
|
|
209
|
-
result.changed = !current;
|
|
210
|
-
applyContent(state, { ...options, content }, actor, installed, started, result);
|
|
211
|
-
(state.presetVersions ??= {})[content.id] = content.version;
|
|
212
|
-
return state;
|
|
213
|
-
});
|
|
214
|
-
report(options, started, "success");
|
|
215
|
-
return result;
|
|
216
|
-
} catch (error) {
|
|
217
|
-
const raw = _optionalChain([error, 'optionalAccess', _29 => _29.code]);
|
|
218
|
-
report(options, started, "failure", typeof raw === "string" && /^[A-Z][A-Z0-9_]{0,79}$/.test(raw) ? raw : "CONTENT_INSTALL_FAILED");
|
|
219
|
-
throw error;
|
|
220
|
-
}
|
|
221
|
-
}
|
|
222
|
-
function validateContent(content) {
|
|
223
|
-
_chunk4KF7KUAIcjs.requireValue.call(void 0, Number.isSafeInteger(content.version) && content.version > 0, "INVALID_CONTENT_VERSION");
|
|
224
|
-
_chunk4KF7KUAIcjs.requireValue.call(void 0, Array.isArray(content.items) && content.items.length <= 1e3, "CONTENT_ITEM_LIMIT");
|
|
225
|
-
for (const rows of [content.records, content.amendments]) _chunk4KF7KUAIcjs.requireValue.call(void 0, rows === void 0 || Array.isArray(rows) && rows.length <= 1e3, "CONTENT_RECORD_LIMIT");
|
|
226
|
-
for (const entry2 of [...content.items, ..._nullishCoalesce(content.records, () => ( [])), ..._nullishCoalesce(content.amendments, () => ( []))]) {
|
|
227
|
-
const version = _nullishCoalesce(entry2.introduced, () => ( 1));
|
|
228
|
-
_chunk4KF7KUAIcjs.requireValue.call(void 0, Number.isSafeInteger(version) && version > 0 && version <= content.version, "INVALID_CONTENT_VERSION");
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
|
-
function applyContent(state, options, actor, installed, now, result) {
|
|
232
|
-
const content = options.content, version = options.fillMissing ? 0 : installed;
|
|
233
|
-
const known = new Set([...state.board.items, ..._nullishCoalesce(state.archiveIndex, () => ( []))].map((item) => item.id));
|
|
234
|
-
const apply = (command) => _chunkL44TM4EEcjs.reduce.call(void 0, state, command, actor, options.operationId, now, (_nullishCoalesce(options.id, () => ( (0, _chunk6MN3H3YFcjs.randomUUID))))());
|
|
235
|
-
for (const entry2 of content.items) {
|
|
236
|
-
if (known.has(entry2.command.item.id) || (_nullishCoalesce(entry2.introduced, () => ( 1))) <= version) continue;
|
|
237
|
-
insertItem(state, entry2, options.missingReferences === "detach", apply);
|
|
238
|
-
known.add(entry2.command.item.id);
|
|
239
|
-
result.changed = true;
|
|
240
|
-
result.created++;
|
|
241
|
-
}
|
|
242
|
-
for (const entry2 of _nullishCoalesce(content.records, () => ( []))) {
|
|
243
|
-
if ((_nullishCoalesce(entry2.introduced, () => ( 1))) <= version || _optionalChain([state, 'access', _30 => _30.records, 'optionalAccess', _31 => _31.some, 'call', _32 => _32((record2) => record2.id === entry2.record.id)])) continue;
|
|
244
|
-
const record = structuredClone(entry2.record);
|
|
245
|
-
if (options.missingReferences === "detach") record.itemIds = record.itemIds.filter((id) => known.has(id));
|
|
246
|
-
apply({ type: "append-record", record });
|
|
247
|
-
if (entry2.confirmed) apply({ type: "review-record", recordId: record.id, accept: true });
|
|
248
|
-
result.changed = true;
|
|
249
|
-
}
|
|
250
|
-
for (const entry2 of _nullishCoalesce(content.amendments, () => ( []))) {
|
|
251
|
-
if ((_nullishCoalesce(entry2.introduced, () => ( 1))) <= version) continue;
|
|
252
|
-
const item = state.board.items.find((item2) => item2.id === entry2.itemId);
|
|
253
|
-
if (!item) continue;
|
|
254
|
-
const count = _nullishCoalesce(_optionalChain([item, 'access', _33 => _33.amendments, 'optionalAccess', _34 => _34.length]), () => ( 0));
|
|
255
|
-
_chunkL44TM4EEcjs.proposeAmendment.call(void 0, item, { action: "update", ...entry2, sources: [] }, entry2.proposedBy, now, entry2.runId);
|
|
256
|
-
if ((_nullishCoalesce(_optionalChain([item, 'access', _35 => _35.amendments, 'optionalAccess', _36 => _36.length]), () => ( 0))) > count) {
|
|
257
|
-
item.revision++;
|
|
258
|
-
state.board.revision++;
|
|
259
|
-
result.changed = true;
|
|
260
|
-
}
|
|
261
|
-
}
|
|
262
|
-
}
|
|
263
|
-
function insertItem(state, entry2, detach, apply) {
|
|
264
|
-
const command = structuredClone(entry2.command), parentId = _optionalChain([command, 'access', _37 => _37.planning, 'optionalAccess', _38 => _38.parentId]);
|
|
265
|
-
if (detach && parentId) {
|
|
266
|
-
const parent = state.board.items.find((item) => item.id === parentId);
|
|
267
|
-
if (!parent || ["completed", "cancelled"].includes(parent.status)) delete command.planning.parentId;
|
|
268
|
-
}
|
|
269
|
-
const itemId = command.item.id;
|
|
270
|
-
apply(command);
|
|
271
|
-
if (entry2.blocked) apply({ type: "block-item", itemId, reason: entry2.blocked });
|
|
272
|
-
if (entry2.completion) {
|
|
273
|
-
apply({ type: "close-plan", itemId, resultRef: entry2.completion.resultRef });
|
|
274
|
-
if (entry2.completion.archiveReason) apply({ type: "archive-items", itemIds: [itemId], reason: entry2.completion.archiveReason });
|
|
275
|
-
}
|
|
276
|
-
}
|
|
277
|
-
function report(options, start, result, code) {
|
|
278
|
-
try {
|
|
279
|
-
options.log({ operationId: options.operationId, boardId: options.content.board.id, stage: "content.install", result, code, durationMs: (_nullishCoalesce(options.now, () => ( Date.now)))() - start });
|
|
280
|
-
} catch (e2) {
|
|
281
|
-
}
|
|
282
|
-
}
|
|
11
|
+
require('./chunk-RBOER6EW.cjs');
|
|
12
|
+
require('./chunk-7KDOTBRX.cjs');
|
|
13
|
+
require('./chunk-RSH6QSEC.cjs');
|
|
14
|
+
require('./chunk-AOHQCX7K.cjs');
|
|
283
15
|
|
|
284
16
|
|
|
285
17
|
|
|
286
18
|
|
|
287
19
|
|
|
288
|
-
exports.ConditionalKanbanStore = ConditionalKanbanStore; exports.SeqKanbanStore =
|
|
20
|
+
exports.ConditionalKanbanStore = _chunkZUZGAO6Gcjs.ConditionalKanbanStore; exports.SeqKanbanStore = _chunkVMRDXOLXcjs.SeqKanbanStore; exports.inspectKanbanContent = _chunkZUZGAO6Gcjs.inspectKanbanContent; exports.installKanbanContent = _chunkZUZGAO6Gcjs.installKanbanContent;
|
|
289
21
|
//# sourceMappingURL=storage.cjs.map
|
package/dist/storage.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/home/li/share/prj/x1/release/local-libraries/work/1ca933a0-6fe7-4e9c-b13b-76d7f318e0fb/source/libraries/kanban/dist/storage.cjs","../src/conditional-store.ts","../src/content.ts"],"names":[],"mappings":"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","file":"/home/li/share/prj/x1/release/local-libraries/work/1ca933a0-6fe7-4e9c-b13b-76d7f318e0fb/source/libraries/kanban/dist/storage.cjs","sourcesContent":[null,"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"]}
|
|
1
|
+
{"version":3,"sources":["/home/li/share/prj/x1/libraries/kanban/dist/storage.cjs"],"names":[],"mappings":"AAAA;AACE;AACA;AACA;AACF,wDAA6B;AAC7B;AACE;AACF,wDAA6B;AAC7B,gCAA6B;AAC7B,gCAA6B;AAC7B,gCAA6B;AAC7B,gCAA6B;AAC7B,gCAA6B;AAC7B,gCAA6B;AAC7B;AACE;AACA;AACA;AACA;AACF,mRAAC","file":"/home/li/share/prj/x1/libraries/kanban/dist/storage.cjs"}
|
package/dist/storage.d.cts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { K as KanbanBodyStore } from './store-
|
|
2
|
-
export { S as SeqKanbanStore } from './store-
|
|
3
|
-
import {
|
|
4
|
-
import { t as KanbanEvent, c as KanbanArchivedItem } from './planning-
|
|
5
|
-
import { K as KanbanContent } from './content-
|
|
1
|
+
import { K as KanbanBodyStore } from './store-DPwHzGiz.cjs';
|
|
2
|
+
export { S as SeqKanbanStore } from './store-DPwHzGiz.cjs';
|
|
3
|
+
import { e as KanbanStore, b as KanbanReadView, d as KanbanState, K as KanbanModuleOptions } from './ports-GQy0x-RI.cjs';
|
|
4
|
+
import { t as KanbanEvent, c as KanbanArchivedItem } from './planning-CHrOqQ6b.cjs';
|
|
5
|
+
import { K as KanbanContent } from './content-C5aJZFlw.cjs';
|
|
6
6
|
import '@nestos/vfs-core';
|
|
7
|
-
import './discovery-
|
|
7
|
+
import './discovery-9E-LfwIw.cjs';
|
|
8
8
|
|
|
9
9
|
/** A transport snapshot is pinned to one revision; unknown writes must not be replayed. */
|
|
10
10
|
interface KanbanSeqSnapshot {
|
package/dist/storage.d.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { K as KanbanBodyStore } from './store-
|
|
2
|
-
export { S as SeqKanbanStore } from './store-
|
|
3
|
-
import {
|
|
4
|
-
import { t as KanbanEvent, c as KanbanArchivedItem } from './planning-
|
|
5
|
-
import { K as KanbanContent } from './content-
|
|
1
|
+
import { K as KanbanBodyStore } from './store-DgdrPCV9.js';
|
|
2
|
+
export { S as SeqKanbanStore } from './store-DgdrPCV9.js';
|
|
3
|
+
import { e as KanbanStore, b as KanbanReadView, d as KanbanState, K as KanbanModuleOptions } from './ports-B0McVg7B.js';
|
|
4
|
+
import { t as KanbanEvent, c as KanbanArchivedItem } from './planning-CHrOqQ6b.js';
|
|
5
|
+
import { K as KanbanContent } from './content-hLH5BNud.js';
|
|
6
6
|
import '@nestos/vfs-core';
|
|
7
|
-
import './discovery-
|
|
7
|
+
import './discovery-D60yrjej.js';
|
|
8
8
|
|
|
9
9
|
/** A transport snapshot is pinned to one revision; unknown writes must not be replayed. */
|
|
10
10
|
interface KanbanSeqSnapshot {
|