@dabble/patches 0.5.4 → 0.5.6
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/dist/algorithms/server/createVersion.js +4 -4
- package/dist/algorithms/server/getSnapshotAtRevision.js +2 -2
- package/dist/algorithms/server/handleOfflineSessionsAndBatches.js +2 -2
- package/dist/json-patch/utils/log.d.ts +1 -1
- package/dist/json-patch/utils/log.js +1 -1
- package/dist/server/PatchesBranchManager.js +9 -9
- package/dist/server/types.d.ts +8 -2
- package/dist/types.d.ts +10 -10
- package/package.json +1 -1
|
@@ -3,8 +3,8 @@ import { createVersionMetadata } from "../../data/version.js";
|
|
|
3
3
|
import { getISO } from "../../utils/dates.js";
|
|
4
4
|
async function createVersion(store, docId, state, changes, metadata) {
|
|
5
5
|
if (changes.length === 0) return;
|
|
6
|
-
const
|
|
7
|
-
if (
|
|
6
|
+
const startRev = changes[0].baseRev;
|
|
7
|
+
if (startRev === void 0) {
|
|
8
8
|
throw new Error(`Client changes must include baseRev for doc ${docId}.`);
|
|
9
9
|
}
|
|
10
10
|
const sessionMetadata = createVersionMetadata({
|
|
@@ -12,8 +12,8 @@ async function createVersion(store, docId, state, changes, metadata) {
|
|
|
12
12
|
// Convert client timestamps to UTC for version metadata (enables lexicographic sorting)
|
|
13
13
|
startedAt: getISO(changes[0].createdAt),
|
|
14
14
|
endedAt: getISO(changes[changes.length - 1].createdAt),
|
|
15
|
-
|
|
16
|
-
|
|
15
|
+
endRev: changes[changes.length - 1].rev,
|
|
16
|
+
startRev,
|
|
17
17
|
...metadata
|
|
18
18
|
});
|
|
19
19
|
await store.createVersion(docId, sessionMetadata, state, changes);
|
|
@@ -5,11 +5,11 @@ async function getSnapshotAtRevision(store, docId, rev) {
|
|
|
5
5
|
reverse: true,
|
|
6
6
|
startAfter: rev ? rev + 1 : void 0,
|
|
7
7
|
origin: "main",
|
|
8
|
-
orderBy: "
|
|
8
|
+
orderBy: "endRev"
|
|
9
9
|
});
|
|
10
10
|
const latestMainVersion = versions[0];
|
|
11
11
|
const versionState = latestMainVersion && await store.loadVersionState(docId, latestMainVersion.id) || null;
|
|
12
|
-
const versionRev = latestMainVersion?.
|
|
12
|
+
const versionRev = latestMainVersion?.endRev ?? 0;
|
|
13
13
|
const changesSinceVersion = await store.listChanges(docId, {
|
|
14
14
|
startAfter: versionRev,
|
|
15
15
|
endBefore: rev ? rev + 1 : void 0
|
|
@@ -46,8 +46,8 @@ async function handleOfflineSessionsAndBatches(store, sessionTimeoutMillis, docI
|
|
|
46
46
|
// Convert client timestamps to UTC for version metadata (enables lexicographic sorting)
|
|
47
47
|
startedAt: getISO(sessionChanges[0].createdAt),
|
|
48
48
|
endedAt: getISO(sessionChanges[sessionChanges.length - 1].createdAt),
|
|
49
|
-
|
|
50
|
-
baseRev
|
|
49
|
+
endRev: sessionChanges[sessionChanges.length - 1].rev,
|
|
50
|
+
startRev: baseRev
|
|
51
51
|
});
|
|
52
52
|
await store.createVersion(docId, sessionMetadata, offlineBaseState, sessionChanges);
|
|
53
53
|
parentId = sessionMetadata.id;
|
|
@@ -32,15 +32,15 @@ class PatchesBranchManager {
|
|
|
32
32
|
throw new Error("Cannot create a branch from another branch.");
|
|
33
33
|
}
|
|
34
34
|
const stateAtRev = (await this.patchesServer.getStateAtRevision(docId, rev)).state;
|
|
35
|
-
const branchDocId = createId();
|
|
35
|
+
const branchDocId = this.store.createBranchId ? await Promise.resolve(this.store.createBranchId(docId)) : createId(22);
|
|
36
36
|
const now = getISO();
|
|
37
37
|
const initialVersionMetadata = createVersionMetadata({
|
|
38
38
|
origin: "main",
|
|
39
39
|
// Branch doc versions are 'main' until merged
|
|
40
40
|
startedAt: now,
|
|
41
41
|
endedAt: now,
|
|
42
|
-
rev,
|
|
43
|
-
|
|
42
|
+
endRev: rev,
|
|
43
|
+
startRev: rev,
|
|
44
44
|
name: metadata?.name,
|
|
45
45
|
groupId: branchDocId,
|
|
46
46
|
branchName: metadata?.name
|
|
@@ -49,8 +49,8 @@ class PatchesBranchManager {
|
|
|
49
49
|
const branch = {
|
|
50
50
|
...metadata,
|
|
51
51
|
id: branchDocId,
|
|
52
|
-
|
|
53
|
-
|
|
52
|
+
docId,
|
|
53
|
+
branchedAtRev: rev,
|
|
54
54
|
createdAt: now,
|
|
55
55
|
status: "open"
|
|
56
56
|
};
|
|
@@ -88,8 +88,8 @@ class PatchesBranchManager {
|
|
|
88
88
|
if (branch.status !== "open") {
|
|
89
89
|
throw new Error(`Branch ${branchId} is not open (status: ${branch.status}). Cannot merge.`);
|
|
90
90
|
}
|
|
91
|
-
const sourceDocId = branch.
|
|
92
|
-
const branchStartRevOnSource = branch.
|
|
91
|
+
const sourceDocId = branch.docId;
|
|
92
|
+
const branchStartRevOnSource = branch.branchedAtRev;
|
|
93
93
|
const branchChanges = await this.store.listChanges(branchId, {});
|
|
94
94
|
if (branchChanges.length === 0) {
|
|
95
95
|
console.log(`Branch ${branchId} has no changes to merge.`);
|
|
@@ -107,7 +107,7 @@ class PatchesBranchManager {
|
|
|
107
107
|
const newVersionMetadata = createVersionMetadata({
|
|
108
108
|
...v,
|
|
109
109
|
origin: versionOrigin,
|
|
110
|
-
|
|
110
|
+
startRev: branchStartRevOnSource,
|
|
111
111
|
groupId: branchId,
|
|
112
112
|
branchName: branch.name,
|
|
113
113
|
// Keep branchName for traceability
|
|
@@ -149,7 +149,7 @@ class PatchesBranchManager {
|
|
|
149
149
|
return committedMergeChanges;
|
|
150
150
|
}
|
|
151
151
|
}
|
|
152
|
-
const nonModifiableMetadataFields = /* @__PURE__ */ new Set(["id", "
|
|
152
|
+
const nonModifiableMetadataFields = /* @__PURE__ */ new Set(["id", "docId", "branchedAtRev", "createdAt", "status"]);
|
|
153
153
|
function assertBranchMetadata(metadata) {
|
|
154
154
|
if (!metadata) return;
|
|
155
155
|
for (const key in metadata) {
|
package/dist/server/types.d.ts
CHANGED
|
@@ -24,10 +24,10 @@ interface PatchesStoreBackend {
|
|
|
24
24
|
/** Update a version's metadata. */
|
|
25
25
|
updateVersion(docId: string, versionId: string, metadata: EditableVersionMetadata): Promise<void>;
|
|
26
26
|
/**
|
|
27
|
-
* Appends changes to an existing version, updating its state snapshot, endedAt, and
|
|
27
|
+
* Appends changes to an existing version, updating its state snapshot, endedAt, and endRev.
|
|
28
28
|
* Used when a session spans multiple batch submissions.
|
|
29
29
|
*/
|
|
30
|
-
appendVersionChanges(docId: string, versionId: string, changes: Change[], newEndedAt: string,
|
|
30
|
+
appendVersionChanges(docId: string, versionId: string, changes: Change[], newEndedAt: string, newEndRev: number, newState: any): Promise<void>;
|
|
31
31
|
/** Lists version metadata based on filtering/sorting options. */
|
|
32
32
|
listVersions(docId: string, options: ListVersionsOptions): Promise<VersionMetadata[]>;
|
|
33
33
|
/** Loads the state snapshot for a specific version ID. */
|
|
@@ -41,6 +41,12 @@ interface PatchesStoreBackend {
|
|
|
41
41
|
* Extends PatchesStoreBackend with methods specifically for managing branches.
|
|
42
42
|
*/
|
|
43
43
|
interface BranchingStoreBackend extends PatchesStoreBackend {
|
|
44
|
+
/**
|
|
45
|
+
* Generates a unique ID for a new branch document.
|
|
46
|
+
* If not provided, a random 22-character ID is generated using createId().
|
|
47
|
+
* @param docId - The source document ID being branched from
|
|
48
|
+
*/
|
|
49
|
+
createBranchId?(docId: string): Promise<string> | string;
|
|
44
50
|
/** Lists metadata records for branches originating from a document. */
|
|
45
51
|
listBranches(docId: string): Promise<Branch[]>;
|
|
46
52
|
/** Loads the metadata record for a specific branch ID. */
|
package/dist/types.d.ts
CHANGED
|
@@ -68,9 +68,9 @@ interface Branch {
|
|
|
68
68
|
/** The ID of the branch document. */
|
|
69
69
|
id: string;
|
|
70
70
|
/** The ID of the document this document was branched from. */
|
|
71
|
-
|
|
71
|
+
docId: string;
|
|
72
72
|
/** The revision number on the source document where the branch occurred. */
|
|
73
|
-
|
|
73
|
+
branchedAtRev: number;
|
|
74
74
|
/** Server-side ISO timestamp when the branch was created (UTC with Z). */
|
|
75
75
|
createdAt: string;
|
|
76
76
|
/** Optional user-friendly name for the branch. */
|
|
@@ -80,7 +80,7 @@ interface Branch {
|
|
|
80
80
|
/** Optional arbitrary metadata associated with the branch record. */
|
|
81
81
|
[metadata: string]: any;
|
|
82
82
|
}
|
|
83
|
-
type EditableBranchMetadata = Disallowed<Branch, 'id' | '
|
|
83
|
+
type EditableBranchMetadata = Disallowed<Branch, 'id' | 'docId' | 'branchedAtRev' | 'createdAt' | 'status'>;
|
|
84
84
|
/**
|
|
85
85
|
* Metadata, state snapshot, and included changes for a specific version.
|
|
86
86
|
*/
|
|
@@ -102,17 +102,17 @@ interface VersionMetadata {
|
|
|
102
102
|
startedAt: string;
|
|
103
103
|
/** Server-side ISO timestamp of version end (UTC with Z). */
|
|
104
104
|
endedAt: string;
|
|
105
|
-
/** The revision number this version
|
|
106
|
-
|
|
107
|
-
/** The revision number
|
|
108
|
-
|
|
105
|
+
/** The ending revision number of this version (the last change's rev). */
|
|
106
|
+
endRev: number;
|
|
107
|
+
/** The starting revision number of this version (the first change's baseRev). If this is an offline/branch version, this is the revision number of the source document where the branch was created. */
|
|
108
|
+
startRev: number;
|
|
109
109
|
/** Optional arbitrary metadata associated with the version. */
|
|
110
110
|
[metadata: string]: any;
|
|
111
111
|
}
|
|
112
112
|
type Disallowed<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>> & {
|
|
113
113
|
[P in K]?: never;
|
|
114
114
|
};
|
|
115
|
-
type EditableVersionMetadata = Disallowed<VersionMetadata, 'id' | 'parentId' | 'groupId' | 'origin' | 'branchName' | 'startedAt' | 'endedAt' | '
|
|
115
|
+
type EditableVersionMetadata = Disallowed<VersionMetadata, 'id' | 'parentId' | 'groupId' | 'origin' | 'branchName' | 'startedAt' | 'endedAt' | 'endRev' | 'startRev'>;
|
|
116
116
|
/**
|
|
117
117
|
* Options for committing changes.
|
|
118
118
|
*/
|
|
@@ -155,8 +155,8 @@ interface ListVersionsOptions {
|
|
|
155
155
|
endBefore?: number | string;
|
|
156
156
|
/** Maximum number of versions to return. */
|
|
157
157
|
limit?: number;
|
|
158
|
-
/** Sort by startedAt,
|
|
159
|
-
orderBy?: 'startedAt' | '
|
|
158
|
+
/** Sort by startedAt, endRev, or startRev. Defaults to 'endRev'. */
|
|
159
|
+
orderBy?: 'startedAt' | 'endRev' | 'startRev';
|
|
160
160
|
/** Return versions in descending order. Defaults to false (ascending). When reversed, startAfter and endBefore apply to the *reversed* list. */
|
|
161
161
|
reverse?: boolean;
|
|
162
162
|
/** Filter by the origin type. */
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dabble/patches",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.6",
|
|
4
4
|
"description": "Immutable JSON Patch implementation based on RFC 6902 supporting operational transformation and last-writer-wins",
|
|
5
5
|
"author": "Jacob Wright <jacwright@gmail.com>",
|
|
6
6
|
"bugs": {
|