mcard-js 2.1.39 → 2.1.40

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. package/dist/AbstractSqlEngine-BSfp8S_Y.d.cts +451 -0
  2. package/dist/AbstractSqlEngine-BSfp8S_Y.d.ts +451 -0
  3. package/dist/CardCollection-MXTUJV4J.js +9 -0
  4. package/dist/EventProducer-AWD6YMZR.js +47 -0
  5. package/dist/Handle-3N4QOA3U.js +13 -0
  6. package/dist/IndexedDBEngine-2G5KCISA.js +11 -0
  7. package/dist/LLMRuntime-LBWUJ7ON.js +16 -0
  8. package/dist/LambdaRuntime-B6D6IQKZ.js +18 -0
  9. package/dist/Loader-3LSJXJQG.js +11 -0
  10. package/dist/MCard-H56VOJLR.js +8 -0
  11. package/dist/NetworkRuntime-IAFHPQSX.js +1570 -0
  12. package/dist/OllamaProvider-QPX2JXL2.js +8 -0
  13. package/dist/chunk-2R4ESMZB.js +110 -0
  14. package/dist/chunk-3EIBJPNF.js +17 -0
  15. package/dist/chunk-3LPY36OG.js +355 -0
  16. package/dist/chunk-3MMMJ7NH.js +1068 -0
  17. package/dist/chunk-42VF42KH.js +273 -0
  18. package/dist/chunk-4PDYHPR6.js +297 -0
  19. package/dist/chunk-ADV52544.js +95 -0
  20. package/dist/chunk-FIE4LAJG.js +215 -0
  21. package/dist/chunk-PNKVD2UK.js +26 -0
  22. package/dist/chunk-RSTKX7WM.js +907 -0
  23. package/dist/chunk-VXV35I5J.js +2315 -0
  24. package/dist/index.browser.cjs +375 -276
  25. package/dist/index.browser.d.cts +4 -4
  26. package/dist/index.browser.d.ts +4 -4
  27. package/dist/index.browser.js +18 -13
  28. package/dist/index.cjs +382 -453
  29. package/dist/index.d.cts +2 -2
  30. package/dist/index.d.ts +2 -2
  31. package/dist/index.js +26 -21
  32. package/dist/storage/SqliteNodeEngine.cjs +395 -270
  33. package/dist/storage/SqliteNodeEngine.d.cts +9 -94
  34. package/dist/storage/SqliteNodeEngine.d.ts +9 -94
  35. package/dist/storage/SqliteNodeEngine.js +6 -5
  36. package/dist/storage/SqliteWasmEngine.cjs +382 -252
  37. package/dist/storage/SqliteWasmEngine.d.cts +8 -29
  38. package/dist/storage/SqliteWasmEngine.d.ts +8 -29
  39. package/dist/storage/SqliteWasmEngine.js +6 -5
  40. package/package.json +1 -1
@@ -0,0 +1,273 @@
1
+ import {
2
+ createPage
3
+ } from "./chunk-3EIBJPNF.js";
4
+ import {
5
+ init_Handle,
6
+ validateHandle
7
+ } from "./chunk-ADV52544.js";
8
+ import {
9
+ DEFAULT_PAGE_SIZE,
10
+ INDEXEDDB_DEFAULT_DB_NAME,
11
+ INDEXEDDB_DEFAULT_DB_VERSION,
12
+ MCard
13
+ } from "./chunk-3MMMJ7NH.js";
14
+
15
+ // src/storage/engines/IndexedDBEngine.ts
16
+ import { openDB } from "idb";
17
+ init_Handle();
18
+ var IndexedDBEngine = class {
19
+ db = null;
20
+ dbName;
21
+ constructor(dbName = INDEXEDDB_DEFAULT_DB_NAME) {
22
+ this.dbName = dbName;
23
+ }
24
+ /**
25
+ * Initialize the database connection
26
+ */
27
+ async init() {
28
+ this.db = await openDB(this.dbName, INDEXEDDB_DEFAULT_DB_VERSION, {
29
+ upgrade(db) {
30
+ if (!db.objectStoreNames.contains("cards")) {
31
+ db.createObjectStore("cards", { keyPath: "hash" });
32
+ }
33
+ if (!db.objectStoreNames.contains("handles")) {
34
+ const handleStore = db.createObjectStore("handles", { keyPath: "handle" });
35
+ handleStore.createIndex("by-hash", "currentHash");
36
+ }
37
+ if (!db.objectStoreNames.contains("handleHistory")) {
38
+ const historyStore = db.createObjectStore("handleHistory", {
39
+ keyPath: "id",
40
+ autoIncrement: true
41
+ });
42
+ historyStore.createIndex("by-handle", "handle");
43
+ }
44
+ }
45
+ });
46
+ }
47
+ ensureDb() {
48
+ if (!this.db) {
49
+ throw new Error("Database not initialized. Call init() first.");
50
+ }
51
+ return this.db;
52
+ }
53
+ // =========== Card Operations ===========
54
+ async add(card) {
55
+ const db = this.ensureDb();
56
+ await db.put("cards", {
57
+ hash: card.hash,
58
+ content: card.content,
59
+ g_time: card.g_time
60
+ });
61
+ return card.hash;
62
+ }
63
+ async get(hash) {
64
+ const db = this.ensureDb();
65
+ const record = await db.get("cards", hash);
66
+ if (!record) return null;
67
+ return MCard.fromData(record.content, record.hash, record.g_time);
68
+ }
69
+ async delete(hash) {
70
+ const db = this.ensureDb();
71
+ await db.delete("cards", hash);
72
+ }
73
+ async getPage(pageNumber, pageSize = DEFAULT_PAGE_SIZE) {
74
+ const db = this.ensureDb();
75
+ const totalItems = await db.count("cards");
76
+ const allCards = await db.getAll("cards");
77
+ const start = (pageNumber - 1) * pageSize;
78
+ const pageRecords = allCards.slice(start, start + pageSize);
79
+ const items = pageRecords.map((r) => MCard.fromData(r.content, r.hash, r.g_time));
80
+ return createPage(items, totalItems, pageNumber, pageSize);
81
+ }
82
+ async count() {
83
+ const db = this.ensureDb();
84
+ return db.count("cards");
85
+ }
86
+ async searchByHash(hashPrefix) {
87
+ const db = this.ensureDb();
88
+ const start = hashPrefix;
89
+ const end = hashPrefix + "\uFFFF";
90
+ const range = IDBKeyRange.bound(start, end);
91
+ const records = await db.getAll("cards", range);
92
+ return records.map((r) => MCard.fromData(r.content, r.hash, r.g_time));
93
+ }
94
+ async search(query, pageNumber, pageSize = DEFAULT_PAGE_SIZE) {
95
+ const db = this.ensureDb();
96
+ const records = await db.getAll("cards");
97
+ const decoder = new TextDecoder();
98
+ const filtered = records.filter((r) => {
99
+ try {
100
+ const text = decoder.decode(r.content);
101
+ return text.includes(query);
102
+ } catch {
103
+ return false;
104
+ }
105
+ });
106
+ const totalItems = filtered.length;
107
+ const start = (pageNumber - 1) * pageSize;
108
+ const pageItems = filtered.slice(start, start + pageSize).map((r) => MCard.fromData(r.content, r.hash, r.g_time));
109
+ return createPage(pageItems, totalItems, pageNumber, pageSize);
110
+ }
111
+ async getAll() {
112
+ const db = this.ensureDb();
113
+ const records = await db.getAll("cards");
114
+ return records.map((r) => MCard.fromData(r.content, r.hash, r.g_time));
115
+ }
116
+ async clear() {
117
+ const db = this.ensureDb();
118
+ await db.clear("cards");
119
+ await db.clear("handles");
120
+ await db.clear("handleHistory");
121
+ }
122
+ // =========== Handle Operations ===========
123
+ async registerHandle(handle, hash) {
124
+ const db = this.ensureDb();
125
+ const normalized = validateHandle(handle);
126
+ const existing = await db.get("handles", normalized);
127
+ if (existing) {
128
+ throw new Error(`Handle '${handle}' already exists.`);
129
+ }
130
+ const now = (/* @__PURE__ */ new Date()).toISOString();
131
+ await db.put("handles", {
132
+ handle: normalized,
133
+ currentHash: hash,
134
+ createdAt: now,
135
+ updatedAt: now
136
+ });
137
+ }
138
+ async resolveHandle(handle) {
139
+ const db = this.ensureDb();
140
+ const normalized = validateHandle(handle);
141
+ const record = await db.get("handles", normalized);
142
+ return record?.currentHash ?? null;
143
+ }
144
+ async getByHandle(handle) {
145
+ const hash = await this.resolveHandle(handle);
146
+ if (!hash) return null;
147
+ return this.get(hash);
148
+ }
149
+ async updateHandle(handle, newHash) {
150
+ const db = this.ensureDb();
151
+ const normalized = validateHandle(handle);
152
+ const existing = await db.get("handles", normalized);
153
+ if (!existing) {
154
+ throw new Error(`Handle '${handle}' not found.`);
155
+ }
156
+ const previousHash = existing.currentHash;
157
+ const now = (/* @__PURE__ */ new Date()).toISOString();
158
+ await db.add("handleHistory", {
159
+ handle: normalized,
160
+ previousHash,
161
+ changedAt: now
162
+ });
163
+ await db.put("handles", {
164
+ ...existing,
165
+ currentHash: newHash,
166
+ updatedAt: now
167
+ });
168
+ return previousHash;
169
+ }
170
+ async getHandleHistory(handle) {
171
+ const db = this.ensureDb();
172
+ const normalized = validateHandle(handle);
173
+ const records = await db.getAllFromIndex("handleHistory", "by-handle", normalized);
174
+ return records.map((r) => ({ previousHash: r.previousHash, changedAt: r.changedAt })).reverse();
175
+ }
176
+ async pruneHandleHistory(handle, options = {}) {
177
+ const db = this.ensureDb();
178
+ const normalized = validateHandle(handle);
179
+ const records = await db.getAllFromIndex("handleHistory", "by-handle", normalized);
180
+ let toDelete;
181
+ if (options.deleteAll) {
182
+ toDelete = records;
183
+ } else if (options.olderThan) {
184
+ toDelete = records.filter((r) => r.changedAt < options.olderThan);
185
+ } else {
186
+ return 0;
187
+ }
188
+ const tx = db.transaction("handleHistory", "readwrite");
189
+ for (const record of toDelete) {
190
+ await tx.store.delete(record.id);
191
+ }
192
+ await tx.done;
193
+ return toDelete.length;
194
+ }
195
+ // =========== Handle Management Operations ===========
196
+ async getAllHandles() {
197
+ const db = this.ensureDb();
198
+ const records = await db.getAll("handles");
199
+ return records.map((r) => ({ handle: r.handle, hash: r.currentHash }));
200
+ }
201
+ async removeHandle(handle) {
202
+ const db = this.ensureDb();
203
+ const normalized = validateHandle(handle);
204
+ const keysToTry = normalized !== handle.trim() ? [normalized, handle.trim()] : [normalized];
205
+ const tx = db.transaction(["handles", "handleHistory"], "readwrite");
206
+ const handleStore = tx.objectStore("handles");
207
+ const historyStore = tx.objectStore("handleHistory");
208
+ for (const key of keysToTry) {
209
+ await handleStore.delete(key);
210
+ }
211
+ const historyIndex = historyStore.index("by-handle");
212
+ for (const key of keysToTry) {
213
+ let cursor = await historyIndex.openCursor(key);
214
+ while (cursor) {
215
+ await cursor.delete();
216
+ cursor = await cursor.continue();
217
+ }
218
+ }
219
+ await tx.done;
220
+ }
221
+ async renameHandle(oldHandle, newHandle) {
222
+ const db = this.ensureDb();
223
+ const normalizedOld = validateHandle(oldHandle);
224
+ const normalizedNew = validateHandle(newHandle);
225
+ if (normalizedOld === normalizedNew) return;
226
+ const oldEntry = await db.get("handles", normalizedOld);
227
+ if (!oldEntry) throw new Error(`Handle '${oldHandle}' not found.`);
228
+ const newEntry = await db.get("handles", normalizedNew);
229
+ if (newEntry) throw new Error(`Handle '${newHandle}' already exists.`);
230
+ const tx = db.transaction(["handles", "handleHistory"], "readwrite");
231
+ const handleStore = tx.objectStore("handles");
232
+ const historyStore = tx.objectStore("handleHistory");
233
+ const now = (/* @__PURE__ */ new Date()).toISOString();
234
+ await handleStore.put({
235
+ ...oldEntry,
236
+ handle: normalizedNew,
237
+ updatedAt: now
238
+ });
239
+ await handleStore.delete(normalizedOld);
240
+ const historyIndex = historyStore.index("by-handle");
241
+ let cursor = await historyIndex.openCursor(normalizedOld);
242
+ while (cursor) {
243
+ const record = cursor.value;
244
+ record.handle = normalizedNew;
245
+ await cursor.update(record);
246
+ cursor = await cursor.continue();
247
+ }
248
+ await tx.done;
249
+ }
250
+ async deleteHistoryEntry(handle, previousHash) {
251
+ const db = this.ensureDb();
252
+ const normalized = validateHandle(handle);
253
+ const records = await db.getAllFromIndex("handleHistory", "by-handle", normalized);
254
+ const entries = records.sort((a, b) => a.id - b.id);
255
+ const targetIdx = entries.findIndex((e) => e.previousHash === previousHash);
256
+ if (targetIdx === -1) return;
257
+ const target = entries[targetIdx];
258
+ const successor = entries[targetIdx + 1];
259
+ const tx = db.transaction("handleHistory", "readwrite");
260
+ const store = tx.objectStore("handleHistory");
261
+ if (successor && targetIdx > 0) {
262
+ const predecessor = entries[targetIdx - 1];
263
+ successor.previousHash = predecessor.previousHash;
264
+ await store.put(successor);
265
+ }
266
+ await store.delete(target.id);
267
+ await tx.done;
268
+ }
269
+ };
270
+
271
+ export {
272
+ IndexedDBEngine
273
+ };
@@ -0,0 +1,297 @@
1
+ import {
2
+ DEFAULT_PAGE_SIZE,
3
+ MCard
4
+ } from "./chunk-3MMMJ7NH.js";
5
+
6
+ // src/monads/Maybe.ts
7
+ var Maybe = class _Maybe {
8
+ constructor(_value, _isNothing) {
9
+ this._value = _value;
10
+ this._isNothing = _isNothing;
11
+ }
12
+ /**
13
+ * Create a Just (has value)
14
+ */
15
+ static just(value) {
16
+ return new _Maybe(value, false);
17
+ }
18
+ /**
19
+ * Create a Nothing (no value)
20
+ */
21
+ static nothing() {
22
+ return new _Maybe(null, true);
23
+ }
24
+ /**
25
+ * Check if this is Nothing
26
+ */
27
+ get isNothing() {
28
+ return this._isNothing;
29
+ }
30
+ /**
31
+ * Check if this is Just
32
+ */
33
+ get isJust() {
34
+ return !this._isNothing;
35
+ }
36
+ /**
37
+ * Get the value (throws if Nothing)
38
+ */
39
+ get value() {
40
+ if (this._isNothing) {
41
+ throw new Error("Cannot get value from Nothing");
42
+ }
43
+ return this._value;
44
+ }
45
+ /**
46
+ * Monadic bind - chain operations
47
+ * Short-circuits on Nothing
48
+ */
49
+ bind(fn) {
50
+ if (this._isNothing) {
51
+ return _Maybe.nothing();
52
+ }
53
+ return fn(this._value);
54
+ }
55
+ /**
56
+ * Map a function over the value
57
+ */
58
+ map(fn) {
59
+ if (this._isNothing) {
60
+ return _Maybe.nothing();
61
+ }
62
+ return _Maybe.just(fn(this._value));
63
+ }
64
+ /**
65
+ * Get value or default
66
+ */
67
+ getOrElse(defaultValue) {
68
+ return this._isNothing ? defaultValue : this._value;
69
+ }
70
+ };
71
+
72
+ // src/model/CardCollection.ts
73
+ var CardCollection = class {
74
+ engine;
75
+ constructor(engine) {
76
+ this.engine = engine;
77
+ }
78
+ // =========== Standard Operations ===========
79
+ /**
80
+ * Add a card to the collection
81
+ * Handles duplicates (same content, same hash) and collisions (diff content, same hash)
82
+ */
83
+ async add(card) {
84
+ const existingCard = await this.engine.get(card.hash);
85
+ if (existingCard) {
86
+ const isDuplicate = this.areContentsEqual(existingCard.content, card.content);
87
+ if (isDuplicate) {
88
+ const { generateDuplicationEvent } = await import("./EventProducer-AWD6YMZR.js");
89
+ const eventStr = generateDuplicationEvent(card);
90
+ const eventCard = await MCard.create(eventStr);
91
+ await this.engine.add(eventCard);
92
+ return card.hash;
93
+ } else {
94
+ const { generateCollisionEvent } = await import("./EventProducer-AWD6YMZR.js");
95
+ const eventStr = await generateCollisionEvent(card);
96
+ const eventCard = await MCard.create(eventStr);
97
+ await this.engine.add(eventCard);
98
+ const eventObj = JSON.parse(eventStr);
99
+ const nextAlgo = eventObj.upgraded_function;
100
+ if (!nextAlgo) {
101
+ throw new Error("Failed to determine next hash algorithm for collision");
102
+ }
103
+ const upgradedCard = await MCard.create(card.content, nextAlgo);
104
+ return this.engine.add(upgradedCard);
105
+ }
106
+ }
107
+ return this.engine.add(card);
108
+ }
109
+ areContentsEqual(a, b) {
110
+ if (a.length !== b.length) return false;
111
+ for (let i = 0; i < a.length; i++) {
112
+ if (a[i] !== b[i]) return false;
113
+ }
114
+ return true;
115
+ }
116
+ /**
117
+ * Get a card by hash
118
+ */
119
+ async get(hash) {
120
+ return this.engine.get(hash);
121
+ }
122
+ /**
123
+ * Delete a card by hash
124
+ */
125
+ async delete(hash) {
126
+ return this.engine.delete(hash);
127
+ }
128
+ /**
129
+ * Get a page of cards
130
+ */
131
+ async getPage(pageNumber = 1, pageSize = DEFAULT_PAGE_SIZE) {
132
+ return this.engine.getPage(pageNumber, pageSize);
133
+ }
134
+ /**
135
+ * Count total cards
136
+ */
137
+ async count() {
138
+ return this.engine.count();
139
+ }
140
+ // =========== Handle Operations ===========
141
+ /**
142
+ * Add a card and register a handle for it
143
+ */
144
+ async addWithHandle(card, handle) {
145
+ const hash = await this.add(card);
146
+ await this.engine.registerHandle(handle, hash);
147
+ return hash;
148
+ }
149
+ /**
150
+ * Get card by handle
151
+ */
152
+ async getByHandle(handle) {
153
+ return this.engine.getByHandle(handle);
154
+ }
155
+ /**
156
+ * Resolve handle to hash
157
+ */
158
+ async resolveHandle(handle) {
159
+ return this.engine.resolveHandle(handle);
160
+ }
161
+ /**
162
+ * Update handle to point to new card
163
+ */
164
+ async updateHandle(handle, newCard) {
165
+ const hash = await this.add(newCard);
166
+ await this.engine.updateHandle(handle, hash);
167
+ return hash;
168
+ }
169
+ /**
170
+ * Get version history for a handle
171
+ */
172
+ async getHandleHistory(handle) {
173
+ return this.engine.getHandleHistory(handle);
174
+ }
175
+ // =========== Monadic Operations ===========
176
+ /**
177
+ * Monadic get - returns Maybe<MCard>
178
+ */
179
+ async getM(hash) {
180
+ const card = await this.get(hash);
181
+ return card ? Maybe.just(card) : Maybe.nothing();
182
+ }
183
+ /**
184
+ * Monadic getByHandle - returns Maybe<MCard>
185
+ */
186
+ async getByHandleM(handle) {
187
+ const card = await this.getByHandle(handle);
188
+ return card ? Maybe.just(card) : Maybe.nothing();
189
+ }
190
+ /**
191
+ * Monadic resolveHandle - returns Maybe<string>
192
+ */
193
+ async resolveHandleM(handle) {
194
+ const hash = await this.resolveHandle(handle);
195
+ return hash ? Maybe.just(hash) : Maybe.nothing();
196
+ }
197
+ /**
198
+ * Resolve handle and get card in one monadic operation
199
+ */
200
+ async resolveAndGetM(handle) {
201
+ const maybeHash = await this.resolveHandleM(handle);
202
+ if (maybeHash.isNothing) return Maybe.nothing();
203
+ return this.getM(maybeHash.value);
204
+ }
205
+ /**
206
+ * Prune version history for a handle.
207
+ * @param handle The handle string.
208
+ * @param options Options for pruning (olderThan date, or deleteAll).
209
+ * @returns Number of deleted entries.
210
+ */
211
+ async pruneHandleHistory(handle, options = {}) {
212
+ if (this.engine.pruneHandleHistory) {
213
+ return this.engine.pruneHandleHistory(handle, options);
214
+ }
215
+ return 0;
216
+ }
217
+ // =========== Search & Bulk Operations ===========
218
+ async clear() {
219
+ return this.engine.clear();
220
+ }
221
+ async searchByString(query, pageNumber = 1, pageSize = DEFAULT_PAGE_SIZE) {
222
+ return this.engine.search(query, pageNumber, pageSize);
223
+ }
224
+ async searchByContent(query, pageNumber = 1, pageSize = DEFAULT_PAGE_SIZE) {
225
+ return this.engine.search(query, pageNumber, pageSize);
226
+ }
227
+ async searchByHash(hashPrefix) {
228
+ return this.engine.searchByHash(hashPrefix);
229
+ }
230
+ async getAllMCardsRaw() {
231
+ return this.engine.getAll();
232
+ }
233
+ async getAllCards(pageSize = DEFAULT_PAGE_SIZE, processCallback) {
234
+ const cards = [];
235
+ let pageNumber = 1;
236
+ let total = 0;
237
+ while (true) {
238
+ const page = await this.getPage(pageNumber, pageSize);
239
+ if (!page.items || page.items.length === 0) break;
240
+ for (const card of page.items) {
241
+ if (processCallback) {
242
+ processCallback(card);
243
+ }
244
+ cards.push(card);
245
+ }
246
+ total = page.totalItems;
247
+ if (!page.hasNext) break;
248
+ pageNumber++;
249
+ }
250
+ return { cards, total };
251
+ }
252
+ async printAllCards() {
253
+ const cards = await this.getAllMCardsRaw();
254
+ cards.forEach((card) => {
255
+ console.log(`Hash: ${card.hash}`);
256
+ try {
257
+ const text = new TextDecoder().decode(card.content);
258
+ const preview = text.slice(0, 100).replace(/\n/g, " ");
259
+ console.log(`Content: ${preview}${text.length > 100 ? "..." : ""}`);
260
+ } catch {
261
+ console.log(`Content (binary): ${card.content.length} bytes`);
262
+ }
263
+ console.log("---");
264
+ });
265
+ }
266
+ // =========== Handle Management Operations ===========
267
+ /**
268
+ * List all registered handles with their current hashes.
269
+ */
270
+ async getAllHandles() {
271
+ return this.engine.getAllHandles();
272
+ }
273
+ /**
274
+ * Remove a handle and all its history entries.
275
+ * Does NOT delete the underlying card(s).
276
+ */
277
+ async removeHandle(handle) {
278
+ return this.engine.removeHandle(handle);
279
+ }
280
+ /**
281
+ * Rename a handle atomically: updates handle registry and all history entries.
282
+ */
283
+ async renameHandle(oldHandle, newHandle) {
284
+ return this.engine.renameHandle(oldHandle, newHandle);
285
+ }
286
+ /**
287
+ * Delete a single history entry by handle + previousHash, stitching the chain.
288
+ */
289
+ async deleteHistoryEntry(handle, previousHash) {
290
+ return this.engine.deleteHistoryEntry(handle, previousHash);
291
+ }
292
+ };
293
+
294
+ export {
295
+ Maybe,
296
+ CardCollection
297
+ };
@@ -0,0 +1,95 @@
1
+ import {
2
+ __esm,
3
+ __export
4
+ } from "./chunk-PNKVD2UK.js";
5
+
6
+ // src/model/Handle.ts
7
+ var Handle_exports = {};
8
+ __export(Handle_exports, {
9
+ ContentHandle: () => ContentHandle,
10
+ HandleValidationError: () => HandleValidationError,
11
+ validateHandle: () => validateHandle
12
+ });
13
+ function isValidStartChar(char) {
14
+ return /^\p{L}$/u.test(char);
15
+ }
16
+ function isValidBodyChar(char) {
17
+ return /^[\p{L}\p{N}_./ -]$/u.test(char);
18
+ }
19
+ function validateHandle(handle) {
20
+ if (!handle) {
21
+ throw new HandleValidationError("Handle cannot be empty.");
22
+ }
23
+ const normalized = handle.trim().normalize("NFC");
24
+ if (normalized.length === 0) {
25
+ throw new HandleValidationError("Handle cannot be empty after normalization.");
26
+ }
27
+ if (normalized.length > MAX_HANDLE_LENGTH) {
28
+ throw new HandleValidationError(
29
+ `Handle '${handle}' is too long (${normalized.length} chars). Maximum is ${MAX_HANDLE_LENGTH}.`
30
+ );
31
+ }
32
+ if (!isValidStartChar(normalized[0])) {
33
+ throw new HandleValidationError(
34
+ `Invalid handle '${handle}'. Must start with a letter (any language).`
35
+ );
36
+ }
37
+ for (let i = 1; i < normalized.length; i++) {
38
+ if (!isValidBodyChar(normalized[i])) {
39
+ throw new HandleValidationError(
40
+ `Invalid character '${normalized[i]}' at position ${i} in handle '${handle}'.`
41
+ );
42
+ }
43
+ }
44
+ return normalized;
45
+ }
46
+ var MAX_HANDLE_LENGTH, HandleValidationError, ContentHandle;
47
+ var init_Handle = __esm({
48
+ "src/model/Handle.ts"() {
49
+ MAX_HANDLE_LENGTH = 255;
50
+ HandleValidationError = class extends Error {
51
+ constructor(message) {
52
+ super(message);
53
+ this.name = "HandleValidationError";
54
+ }
55
+ };
56
+ ContentHandle = class {
57
+ handle;
58
+ currentHash;
59
+ createdAt;
60
+ updatedAt;
61
+ constructor(handle, currentHash, createdAt, updatedAt) {
62
+ this.handle = validateHandle(handle);
63
+ this.currentHash = currentHash;
64
+ this.createdAt = createdAt ?? /* @__PURE__ */ new Date();
65
+ this.updatedAt = updatedAt ?? this.createdAt;
66
+ }
67
+ /**
68
+ * Update handle to point to new hash
69
+ * @returns Previous hash for history tracking
70
+ */
71
+ update(newHash) {
72
+ const previousHash = this.currentHash;
73
+ this.currentHash = newHash;
74
+ this.updatedAt = /* @__PURE__ */ new Date();
75
+ return previousHash;
76
+ }
77
+ toObject() {
78
+ return {
79
+ handle: this.handle,
80
+ currentHash: this.currentHash,
81
+ createdAt: this.createdAt.toISOString(),
82
+ updatedAt: this.updatedAt.toISOString()
83
+ };
84
+ }
85
+ };
86
+ }
87
+ });
88
+
89
+ export {
90
+ HandleValidationError,
91
+ validateHandle,
92
+ ContentHandle,
93
+ Handle_exports,
94
+ init_Handle
95
+ };