📄 src/models/versioning.ts
D-OPEN SOVEREIGN
Documentation & Insights
Tracks the edit history of each object in the in-memory database.
ObjectTypeId => ObjectId => { properties, relations }1/*
2 * Copyright (c) 2026 DataPond D-Library Pty Ltd. ("The Sanctuary")
3 * Non-Profit Public Library — The World Library
4 *
5 * D-SAFE Certification issued by POND Enterprise.
6 * Published under the D-Open Code Sovereign Licence v1.0 framework
7 * DataPond D-Library All exclusive Right reserved on modifiying the code - CC Attribution to data pond, Non modifiable, Non Commercial.
8 * https://registry.world.bibliotech.com/licence
9 * Source code donated to DataPond D-Library by it's author: data pond.
10 *
11 * Technical Guardian ("The Shield"): Pond Enterprise Pty Ltd. (ACN 694 747 987)
12 * All liability claims about D-SAFE certification issues coming from the published D-Safe direction must be addressed with Pond Enterprise Pty Ltd.
13 * Code Modification automatically voids the certified liability protection provided by Pond Enterprise.
14 */
15import {
16 PatchOperation, PatchAction,
17 type AnyPatch,
18 type EditPropertyStringObj, type EditPropertyNumberObj,
19 type EditRelationObj,
20} from "./binary.ts";
21import { Patches } from "./patcher.ts";
22
23/**
24 * Tracks the edit history of each object in the in-memory database.
25 * ObjectTypeId => ObjectId => { properties, relations }
26 */
27type IVersioning = Map<number, {
28 createdBy: string,
29 // propId => values over time
30 properties: Map<number, Array<{ username: string, value: string | number, langId: number }>>,
31 // relationId => ['+' | '-', targetId]
32 relations: Map<number, Array<{ username: string, value: ['+' | '-', number] }>>
33}>
34
35const versioning: Map<number, IVersioning> = new Map()
36
37let currentUsername = "mine"
38
39export const LockUsername = (username: string) => {
40 currentUsername = username
41}
42export const UnlockUsername = () => {
43 currentUsername = "mine"
44}
45
46const collectionFor = (objectType: number, objectId: number) => {
47 if (!versioning.has(objectType)) {
48 versioning.set(objectType, new Map())
49 }
50 const collection = versioning.get(objectType)!
51 if (!collection.has(objectId)) {
52 collection.set(objectId, {
53 createdBy: currentUsername,
54 properties: new Map(),
55 relations: new Map()
56 })
57 }
58 return collection.get(objectId)!
59}
60
61export const track = (patch: AnyPatch) => {
62 if (Patches._replaying) {
63 return
64 }
65 switch (patch.operation) {
66 case PatchOperation.EditPropertyString:
67 case PatchOperation.EditPropertyNumber: {
68 const op = patch as EditPropertyStringObj | EditPropertyNumberObj
69 const entry = collectionFor(op.objectType, op.objectId)
70 if (!entry.properties.has(op.propertyId)) {
71 entry.properties.set(op.propertyId, [])
72 }
73 entry.properties.get(op.propertyId)!.push({
74 username: currentUsername,
75 value: op.value,
76 langId: op.langId
77 })
78 break
79 }
80 case PatchOperation.EditRelation: {
81 const op = patch as EditRelationObj
82 const entry = collectionFor(op.objectType, op.objectId)
83 if (!entry.relations.has(op.relationId)) {
84 entry.relations.set(op.relationId, [])
85 }
86 entry.relations.get(op.relationId)!.push({
87 username: currentUsername,
88 value: [op.action === PatchAction.Add ? '+' : '-', op.targetId]
89 })
90 break
91 }
92 default:
93 // EditInstanceField* and SetAlias are not tracked in the history view
94 break
95 }
96}
97
98export const getHistory = (objectType: number, objectId: number) => {
99 return versioning.get(objectType)?.get(objectId)
100}
101
102export const clearHistory = () => {
103 versioning.clear()
104}
105