@dabble/patches 0.9.2 → 0.9.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/README.md +20 -0
- package/dist/{BaseDoc-rCKMFV6B.d.ts → BaseDoc-CXHXcW18.d.ts} +1 -1
- package/dist/algorithms/ot/server/createVersion.d.ts +1 -1
- package/dist/client/BaseDoc.d.ts +1 -1
- package/dist/client/ClientAlgorithm.d.ts +1 -1
- package/dist/client/LWWAlgorithm.d.ts +1 -1
- package/dist/client/LWWDoc.d.ts +1 -1
- package/dist/client/OTAlgorithm.d.ts +1 -1
- package/dist/client/OTDoc.d.ts +1 -1
- package/dist/client/Patches.d.ts +1 -1
- package/dist/client/PatchesBranchClient.d.ts +1 -1
- package/dist/client/PatchesDoc.d.ts +1 -1
- package/dist/client/factories.d.ts +1 -1
- package/dist/client/index.d.ts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/json-patch/JSONPatch.d.ts +3 -0
- package/dist/json-patch/JSONPatch.js +7 -8
- package/dist/json-patch/ops/text.d.ts +11 -1
- package/dist/json-patch/ops/text.js +20 -9
- package/dist/net/PatchesSync.d.ts +1 -37
- package/dist/net/PatchesSync.js +1 -53
- package/dist/net/error.d.ts +9 -9
- package/dist/net/error.js +4 -9
- package/dist/net/index.d.ts +1 -2
- package/dist/net/index.js +0 -1
- package/dist/net/protocol/JSONRPCServer.js +1 -1
- package/dist/net/rest/PatchesREST.d.ts +0 -23
- package/dist/net/rest/PatchesREST.js +0 -46
- package/dist/net/rest/PatchesRESTSignalingTransport.d.ts +0 -1
- package/dist/net/rest/index.d.ts +0 -1
- package/dist/net/signaling/SignalingService.js +4 -3
- package/dist/net/webrtc/WebRTCTransport.js +2 -2
- package/dist/server/branchUtils.d.ts +1 -1
- package/dist/shared/doc-manager.d.ts +1 -1
- package/dist/solid/context.d.ts +1 -1
- package/dist/solid/doc-manager.d.ts +1 -1
- package/dist/solid/index.d.ts +1 -1
- package/dist/solid/primitives.d.ts +1 -1
- package/dist/vue/composables.d.ts +2 -2
- package/dist/vue/doc-manager.d.ts +1 -1
- package/dist/vue/index.d.ts +1 -1
- package/dist/vue/managed-docs.d.ts +2 -2
- package/dist/vue/provider.d.ts +1 -1
- package/package.json +1 -1
- package/dist/net/invite.d.ts +0 -55
- package/dist/net/invite.js +0 -0
package/README.md
CHANGED
|
@@ -16,6 +16,26 @@ doc.change(state => (state.title = 'New Title'));
|
|
|
16
16
|
|
|
17
17
|
Changes apply immediately for snappy UIs, then sync to the server in the background. Offline? No problem. Changes queue up and sync when you're back online.
|
|
18
18
|
|
|
19
|
+
## Scope: what Patches is and is not
|
|
20
|
+
|
|
21
|
+
Patches is a **generic primitives library**. It provides the building blocks (OT, LWW, sync transport, doc-store interfaces) for realtime systems. Compose it into your own backend and frontend.
|
|
22
|
+
|
|
23
|
+
Patches knows about:
|
|
24
|
+
|
|
25
|
+
- JSON documents, JSON Patch operations, and snapshots
|
|
26
|
+
- Operational Transformation and Last-Write-Wins conflict resolution
|
|
27
|
+
- A transport surface (WebSocket, SSE+REST, WebRTC) that moves changes between clients and a server
|
|
28
|
+
- HTTP status codes propagated as `StatusError` (401, 403, 404, 410) — so consuming apps can branch on the response
|
|
29
|
+
|
|
30
|
+
Patches does **not** know about:
|
|
31
|
+
|
|
32
|
+
- Users, roles, invites, memberships, or any access-control model
|
|
33
|
+
- Apps, projects, books, documents-as-products, or any app-specific terminology
|
|
34
|
+
- Email sending, name/email lookups, or any identity service
|
|
35
|
+
- UX policy for what to do when access is lost (consuming apps decide whether a 403 means "show a banner", "kick out of the doc", or anything else)
|
|
36
|
+
|
|
37
|
+
If a feature feels like it belongs in Patches but mentions an app concept (e.g. "an invite for a project"), it doesn't belong here — it belongs one level up, in the app's own client SDK or in the consuming app itself. The Patches surface should stay generic enough to back any realtime system.
|
|
38
|
+
|
|
19
39
|
## Two Sync Strategies
|
|
20
40
|
|
|
21
41
|
Patches gives you two conflict resolution approaches. Pick the right tool for the job.
|
|
@@ -246,4 +246,4 @@ declare abstract class BaseDoc<T extends object = object> extends ReadonlyStoreC
|
|
|
246
246
|
abstract import(snapshot: PatchesSnapshot<T>): void;
|
|
247
247
|
}
|
|
248
248
|
|
|
249
|
-
export { BaseDoc as B, OTDoc as O, type
|
|
249
|
+
export { BaseDoc as B, OTDoc as O, type PatchesDocOptions as P, type PatchesDoc as a };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { OTStoreBackend } from '../../../server/types.js';
|
|
2
|
-
import { EditableVersionMetadata,
|
|
2
|
+
import { EditableVersionMetadata, VersionMetadata, Change } from '../../../types.js';
|
|
3
3
|
import '../../../json-patch/types.js';
|
|
4
4
|
import '../../../json-patch/JSONPatch.js';
|
|
5
5
|
import '@dabble/delta';
|
package/dist/client/BaseDoc.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { JSONPatchOp } from '../json-patch/types.js';
|
|
2
2
|
import { PatchesSnapshot, Change } from '../types.js';
|
|
3
|
-
import {
|
|
3
|
+
import { a as PatchesDoc } from '../BaseDoc-CXHXcW18.js';
|
|
4
4
|
import { PatchesStore, TrackedDoc } from './PatchesStore.js';
|
|
5
5
|
import '../json-patch/JSONPatch.js';
|
|
6
6
|
import '@dabble/delta';
|
|
@@ -2,7 +2,7 @@ import { JSONPatchOp } from '../json-patch/types.js';
|
|
|
2
2
|
import { PatchesSnapshot, Change } from '../types.js';
|
|
3
3
|
import { ClientAlgorithm } from './ClientAlgorithm.js';
|
|
4
4
|
import { LWWClientStore } from './LWWClientStore.js';
|
|
5
|
-
import {
|
|
5
|
+
import { a as PatchesDoc } from '../BaseDoc-CXHXcW18.js';
|
|
6
6
|
import { TrackedDoc } from './PatchesStore.js';
|
|
7
7
|
import '../json-patch/JSONPatch.js';
|
|
8
8
|
import '@dabble/delta';
|
package/dist/client/LWWDoc.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { JSONPatchOp } from '../json-patch/types.js';
|
|
2
2
|
import { PatchesSnapshot, Change } from '../types.js';
|
|
3
|
-
import { B as BaseDoc } from '../BaseDoc-
|
|
3
|
+
import { B as BaseDoc } from '../BaseDoc-CXHXcW18.js';
|
|
4
4
|
import '../json-patch/JSONPatch.js';
|
|
5
5
|
import '@dabble/delta';
|
|
6
6
|
import 'easy-signal';
|
|
@@ -2,7 +2,7 @@ import { JSONPatchOp } from '../json-patch/types.js';
|
|
|
2
2
|
import { PatchesSnapshot, Change } from '../types.js';
|
|
3
3
|
import { ClientAlgorithm } from './ClientAlgorithm.js';
|
|
4
4
|
import { OTClientStore } from './OTClientStore.js';
|
|
5
|
-
import {
|
|
5
|
+
import { P as PatchesDocOptions, a as PatchesDoc } from '../BaseDoc-CXHXcW18.js';
|
|
6
6
|
import { TrackedDoc } from './PatchesStore.js';
|
|
7
7
|
import '../json-patch/JSONPatch.js';
|
|
8
8
|
import '@dabble/delta';
|
package/dist/client/OTDoc.d.ts
CHANGED
package/dist/client/Patches.d.ts
CHANGED
|
@@ -3,7 +3,7 @@ import { Unsubscriber } from 'easy-signal';
|
|
|
3
3
|
import { JSONPatchOp } from '../json-patch/types.js';
|
|
4
4
|
import { Change } from '../types.js';
|
|
5
5
|
import { ClientAlgorithm } from './ClientAlgorithm.js';
|
|
6
|
-
import {
|
|
6
|
+
import { P as PatchesDocOptions, a as PatchesDoc } from '../BaseDoc-CXHXcW18.js';
|
|
7
7
|
import { AlgorithmName } from './PatchesStore.js';
|
|
8
8
|
import '../json-patch/JSONPatch.js';
|
|
9
9
|
import '@dabble/delta';
|
|
@@ -8,7 +8,7 @@ import '../json-patch/JSONPatch.js';
|
|
|
8
8
|
import '@dabble/delta';
|
|
9
9
|
import '../json-patch/types.js';
|
|
10
10
|
import './ClientAlgorithm.js';
|
|
11
|
-
import '../BaseDoc-
|
|
11
|
+
import '../BaseDoc-CXHXcW18.js';
|
|
12
12
|
|
|
13
13
|
interface PatchesBranchClientOptions {
|
|
14
14
|
/** Algorithm to use for the branch document (defaults to the Patches instance default). */
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import 'easy-signal';
|
|
2
2
|
import '../json-patch/types.js';
|
|
3
3
|
import '../types.js';
|
|
4
|
-
export { O as OTDoc,
|
|
4
|
+
export { O as OTDoc, a as PatchesDoc, P as PatchesDocOptions } from '../BaseDoc-CXHXcW18.js';
|
|
5
5
|
import '../json-patch/JSONPatch.js';
|
|
6
6
|
import '@dabble/delta';
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { AlgorithmName } from './PatchesStore.js';
|
|
2
2
|
import { Patches } from './Patches.js';
|
|
3
|
-
import {
|
|
3
|
+
import { P as PatchesDocOptions } from '../BaseDoc-CXHXcW18.js';
|
|
4
4
|
import '../types.js';
|
|
5
5
|
import '../json-patch/JSONPatch.js';
|
|
6
6
|
import '@dabble/delta';
|
package/dist/client/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { B as BaseDoc, O as OTDoc,
|
|
1
|
+
export { B as BaseDoc, O as OTDoc, a as PatchesDoc, P as PatchesDocOptions } from '../BaseDoc-CXHXcW18.js';
|
|
2
2
|
export { IndexedDBFactoryOptions, MultiAlgorithmFactoryOptions, MultiAlgorithmIndexedDBFactoryOptions, PatchesFactoryOptions, createLWWIndexedDBPatches, createLWWPatches, createMultiAlgorithmExternalDBPatches, createMultiAlgorithmIndexedDBPatches, createMultiAlgorithmPatches, createOTIndexedDBPatches, createOTPatches, upgradePatchesDB } from './factories.js';
|
|
3
3
|
export { IDBStoreWrapper, IDBTransactionWrapper, IndexedDBStore } from './IndexedDBStore.js';
|
|
4
4
|
export { OTIndexedDBStore } from './OTIndexedDBStore.js';
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { Delta } from '@dabble/delta';
|
|
2
|
-
export { B as BaseDoc, O as OTDoc,
|
|
2
|
+
export { B as BaseDoc, O as OTDoc, a as PatchesDoc, P as PatchesDocOptions } from './BaseDoc-CXHXcW18.js';
|
|
3
3
|
export { IndexedDBFactoryOptions, MultiAlgorithmFactoryOptions, MultiAlgorithmIndexedDBFactoryOptions, PatchesFactoryOptions, createLWWIndexedDBPatches, createLWWPatches, createMultiAlgorithmExternalDBPatches, createMultiAlgorithmIndexedDBPatches, createMultiAlgorithmPatches, createOTIndexedDBPatches, createOTPatches, upgradePatchesDB } from './client/factories.js';
|
|
4
4
|
export { IDBStoreWrapper, IDBTransactionWrapper, IndexedDBStore } from './client/IndexedDBStore.js';
|
|
5
5
|
export { OTIndexedDBStore } from './client/OTIndexedDBStore.js';
|
|
@@ -86,6 +86,9 @@ declare class JSONPatch {
|
|
|
86
86
|
bit(path: PathLike, index: number, on: boolean): this;
|
|
87
87
|
/**
|
|
88
88
|
* Applies a delta to a text document.
|
|
89
|
+
*
|
|
90
|
+
* `value` is stored as a bare `Op[]` array (the canonical `@txt` shape).
|
|
91
|
+
* Accepts a `Delta` instance, a serialized `{ ops }` form, or the array directly.
|
|
89
92
|
*/
|
|
90
93
|
text(path: PathLike, value: Delta | Delta['ops']): this;
|
|
91
94
|
/**
|
|
@@ -22,6 +22,7 @@ import { applyPatch } from "./applyPatch.js";
|
|
|
22
22
|
import { composePatch } from "./composePatch.js";
|
|
23
23
|
import { invertPatch } from "./invertPatch.js";
|
|
24
24
|
import { bitmask } from "./ops/bitmask.js";
|
|
25
|
+
import { toOps } from "./ops/text.js";
|
|
25
26
|
import { transformPatch } from "./transformPatch.js";
|
|
26
27
|
class JSONPatch {
|
|
27
28
|
ops;
|
|
@@ -120,16 +121,14 @@ class JSONPatch {
|
|
|
120
121
|
}
|
|
121
122
|
/**
|
|
122
123
|
* Applies a delta to a text document.
|
|
124
|
+
*
|
|
125
|
+
* `value` is stored as a bare `Op[]` array (the canonical `@txt` shape).
|
|
126
|
+
* Accepts a `Delta` instance, a serialized `{ ops }` form, or the array directly.
|
|
123
127
|
*/
|
|
124
128
|
text(path, value) {
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
value = new Delta(value.ops);
|
|
129
|
-
} else if (!(value instanceof Delta)) {
|
|
130
|
-
throw new Error("Invalid Delta");
|
|
131
|
-
}
|
|
132
|
-
return this.op("@txt", path, value);
|
|
129
|
+
const ops = toOps(value);
|
|
130
|
+
if (!ops) throw new Error("Invalid Delta");
|
|
131
|
+
return this.op("@txt", path, ops);
|
|
133
132
|
}
|
|
134
133
|
/**
|
|
135
134
|
* Creates a patch from an object partial, updating each field. Set a field to undefined to delete it.
|
|
@@ -1,5 +1,15 @@
|
|
|
1
|
+
import { Op } from '@dabble/delta';
|
|
1
2
|
import { JSONPatchOpHandler } from '../types.js';
|
|
2
3
|
|
|
4
|
+
/**
|
|
5
|
+
* Normalize a `@txt` op's `value` to a bare `Op[]` array.
|
|
6
|
+
*
|
|
7
|
+
* The canonical form is an array of Delta ops, but historically `JSONPatch.text()`,
|
|
8
|
+
* `text.compose()`, and `text.invert()` produced `Delta` instances. Those serialize
|
|
9
|
+
* via `JSON.stringify` to `{ ops: [...] }`, so any rehydrated op may land in either
|
|
10
|
+
* shape. Accept all three; return `null` if the input isn't a recognizable Delta.
|
|
11
|
+
*/
|
|
12
|
+
declare function toOps(value: unknown): Op[] | null;
|
|
3
13
|
declare const text: JSONPatchOpHandler;
|
|
4
14
|
|
|
5
|
-
export { text };
|
|
15
|
+
export { text, toOps };
|
|
@@ -4,13 +4,21 @@ import { replace } from "../ops/replace.js";
|
|
|
4
4
|
import { get } from "../utils/get.js";
|
|
5
5
|
import { log } from "../utils/log.js";
|
|
6
6
|
import { updateRemovedOps } from "../utils/ops.js";
|
|
7
|
+
function toOps(value) {
|
|
8
|
+
if (Array.isArray(value)) return value;
|
|
9
|
+
if (value && typeof value === "object" && Array.isArray(value.ops)) {
|
|
10
|
+
return value.ops;
|
|
11
|
+
}
|
|
12
|
+
return null;
|
|
13
|
+
}
|
|
7
14
|
const text = {
|
|
8
15
|
like: "replace",
|
|
9
16
|
apply(state, path, value) {
|
|
10
|
-
const
|
|
11
|
-
if (!
|
|
17
|
+
const ops = toOps(value);
|
|
18
|
+
if (!ops) {
|
|
12
19
|
return "Invalid delta";
|
|
13
20
|
}
|
|
21
|
+
const delta = new Delta(ops);
|
|
14
22
|
const existingData = get(state, path);
|
|
15
23
|
let doc;
|
|
16
24
|
if (Array.isArray(existingData)) {
|
|
@@ -29,22 +37,24 @@ const text = {
|
|
|
29
37
|
},
|
|
30
38
|
transform(state, thisOp, otherOps) {
|
|
31
39
|
log("Transforming ", otherOps, ' against "@txt"', thisOp);
|
|
40
|
+
const thisOps = toOps(thisOp.value);
|
|
32
41
|
return updateRemovedOps(state, thisOp.path, otherOps, false, true, thisOp.op, (op) => {
|
|
33
42
|
if (op.path !== thisOp.path) return null;
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
43
|
+
const otherOpsArr = toOps(op.value);
|
|
44
|
+
if (!thisOps || !otherOpsArr) return null;
|
|
45
|
+
const thisDelta = new Delta(thisOps);
|
|
46
|
+
let otherDelta = new Delta(otherOpsArr);
|
|
37
47
|
otherDelta = thisDelta.transform(otherDelta, true);
|
|
38
48
|
return { ...op, value: otherDelta.ops };
|
|
39
49
|
});
|
|
40
50
|
},
|
|
41
51
|
invert(state, { path, value }, oldValue, changedObj) {
|
|
42
52
|
if (path.endsWith("/-")) path = path.replace("-", changedObj.length);
|
|
43
|
-
const delta = new Delta(value);
|
|
44
|
-
return oldValue === void 0 ? { op: "remove", path } : { op: "@txt", path, value: delta.invert(oldValue) };
|
|
53
|
+
const delta = new Delta(toOps(value) ?? []);
|
|
54
|
+
return oldValue === void 0 ? { op: "remove", path } : { op: "@txt", path, value: delta.invert(oldValue).ops };
|
|
45
55
|
},
|
|
46
56
|
compose(state, delta1, delta2) {
|
|
47
|
-
return new Delta(delta1).compose(new Delta(delta2));
|
|
57
|
+
return new Delta(toOps(delta1) ?? []).compose(new Delta(toOps(delta2) ?? [])).ops;
|
|
48
58
|
}
|
|
49
59
|
};
|
|
50
60
|
function fixBadDeltaDoc(delta) {
|
|
@@ -72,5 +82,6 @@ function fixBadDeltaDoc(delta) {
|
|
|
72
82
|
return newDelta;
|
|
73
83
|
}
|
|
74
84
|
export {
|
|
75
|
-
text
|
|
85
|
+
text,
|
|
86
|
+
toOps
|
|
76
87
|
};
|
|
@@ -13,7 +13,7 @@ import { WebSocketOptions } from './websocket/WebSocketTransport.js';
|
|
|
13
13
|
import '../json-patch/JSONPatch.js';
|
|
14
14
|
import '@dabble/delta';
|
|
15
15
|
import '../json-patch/types.js';
|
|
16
|
-
import '../BaseDoc-
|
|
16
|
+
import '../BaseDoc-CXHXcW18.js';
|
|
17
17
|
import '../utils/deferred.js';
|
|
18
18
|
|
|
19
19
|
interface PatchesSyncState {
|
|
@@ -84,19 +84,6 @@ declare class PatchesSync extends ReadonlyStoreClass<PatchesSyncState> {
|
|
|
84
84
|
* Provides the pending changes that were discarded so the application can handle them.
|
|
85
85
|
*/
|
|
86
86
|
readonly onRemoteDocDeleted: easy_signal.Signal<(docId: string, pendingChanges: Change[]) => void>;
|
|
87
|
-
/**
|
|
88
|
-
* Signal emitted when the server reports the caller is no longer authorised
|
|
89
|
-
* to read/write a tracked document (e.g. a co-author was revoked, removed
|
|
90
|
-
* from a shared collection, or never had access in the first place).
|
|
91
|
-
*
|
|
92
|
-
* Local cleanup mirrors `onRemoteDocDeleted` — untrack, drop the local
|
|
93
|
-
* cache, return any pending changes that were lost — but the doc itself
|
|
94
|
-
* still exists server-side. Consumers that maintain a workspace listing
|
|
95
|
-
* (e.g. a "Shared with Me" dashboard) should remove the doc from their
|
|
96
|
-
* own state when this fires; otherwise it would resurface on next start
|
|
97
|
-
* and immediately re-fail with the same 403.
|
|
98
|
-
*/
|
|
99
|
-
readonly onRemoteDocAccessRevoked: easy_signal.Signal<(docId: string, pendingChanges: Change[]) => void>;
|
|
100
87
|
/**
|
|
101
88
|
* Signal emitted after pending branch metas have been synced to the server.
|
|
102
89
|
* Consumers should use this to refresh in-memory branch state (e.g. call `loadCached()`
|
|
@@ -196,21 +183,6 @@ declare class PatchesSync extends ReadonlyStoreClass<PatchesSyncState> {
|
|
|
196
183
|
* Cleans up local state and notifies the application with any pending changes that were lost.
|
|
197
184
|
*/
|
|
198
185
|
protected _handleRemoteDocDeleted(docId: string): Promise<void>;
|
|
199
|
-
/**
|
|
200
|
-
* Sibling of `_handleRemoteDocDeleted` for the access-revoked path.
|
|
201
|
-
* Same local cleanup (close, untrack, drop cache, clear sync state) but
|
|
202
|
-
* the doc is not tombstoned server-side — it just isn't ours anymore.
|
|
203
|
-
* Emitted as a distinct signal so consumers can show different UX
|
|
204
|
-
* ("Your access was revoked" vs. "Project was deleted") without having
|
|
205
|
-
* to inspect error codes themselves.
|
|
206
|
-
*/
|
|
207
|
-
protected _handleRemoteDocAccessRevoked(docId: string): Promise<void>;
|
|
208
|
-
/**
|
|
209
|
-
* Local cleanup shared by `_handleRemoteDocDeleted` and
|
|
210
|
-
* `_handleRemoteDocAccessRevoked`. Returns pending changes that were
|
|
211
|
-
* lost so the caller can include them in the application-facing signal.
|
|
212
|
-
*/
|
|
213
|
-
protected _cleanupAfterAccessLoss(docId: string): Promise<Change[]>;
|
|
214
186
|
/**
|
|
215
187
|
* Adds, updates, or removes a doc state entry immutably and notifies via store.
|
|
216
188
|
* - Pass a full DocSyncState to add a new entry or overwrite an existing one.
|
|
@@ -239,14 +211,6 @@ declare class PatchesSync extends ReadonlyStoreClass<PatchesSyncState> {
|
|
|
239
211
|
* Helper to detect DOC_DELETED (410) errors from the server.
|
|
240
212
|
*/
|
|
241
213
|
protected _isDocDeletedError(err: unknown): boolean;
|
|
242
|
-
/**
|
|
243
|
-
* Helper to detect ACCESS_REVOKED (403) errors from the server. Used by
|
|
244
|
-
* the sync/flush catch blocks to short-circuit straight into the
|
|
245
|
-
* `_handleRemoteDocAccessRevoked` cleanup path rather than latching the
|
|
246
|
-
* error onto `docStates[docId].syncError` (which would surface as a
|
|
247
|
-
* permanent "Unable to Sync" pill in the UI).
|
|
248
|
-
*/
|
|
249
|
-
protected _isAccessRevokedError(err: unknown): boolean;
|
|
250
214
|
}
|
|
251
215
|
|
|
252
216
|
export { PatchesSync, type PatchesSyncOptions, type PatchesSyncState };
|
package/dist/net/PatchesSync.js
CHANGED
|
@@ -52,19 +52,6 @@ class PatchesSync extends (_a = ReadonlyStoreClass, _syncDoc_dec = [serialGate],
|
|
|
52
52
|
* Provides the pending changes that were discarded so the application can handle them.
|
|
53
53
|
*/
|
|
54
54
|
__publicField(this, "onRemoteDocDeleted", signal());
|
|
55
|
-
/**
|
|
56
|
-
* Signal emitted when the server reports the caller is no longer authorised
|
|
57
|
-
* to read/write a tracked document (e.g. a co-author was revoked, removed
|
|
58
|
-
* from a shared collection, or never had access in the first place).
|
|
59
|
-
*
|
|
60
|
-
* Local cleanup mirrors `onRemoteDocDeleted` — untrack, drop the local
|
|
61
|
-
* cache, return any pending changes that were lost — but the doc itself
|
|
62
|
-
* still exists server-side. Consumers that maintain a workspace listing
|
|
63
|
-
* (e.g. a "Shared with Me" dashboard) should remove the doc from their
|
|
64
|
-
* own state when this fires; otherwise it would resurface on next start
|
|
65
|
-
* and immediately re-fail with the same 403.
|
|
66
|
-
*/
|
|
67
|
-
__publicField(this, "onRemoteDocAccessRevoked", signal());
|
|
68
55
|
/**
|
|
69
56
|
* Signal emitted after pending branch metas have been synced to the server.
|
|
70
57
|
* Consumers should use this to refresh in-memory branch state (e.g. call `loadCached()`
|
|
@@ -373,10 +360,6 @@ class PatchesSync extends (_a = ReadonlyStoreClass, _syncDoc_dec = [serialGate],
|
|
|
373
360
|
await this._handleRemoteDocDeleted(docId);
|
|
374
361
|
return;
|
|
375
362
|
}
|
|
376
|
-
if (this._isAccessRevokedError(err)) {
|
|
377
|
-
await this._handleRemoteDocAccessRevoked(docId);
|
|
378
|
-
return;
|
|
379
|
-
}
|
|
380
363
|
const syncError = err instanceof Error ? err : new Error(String(err));
|
|
381
364
|
this._updateDocSyncState(docId, { syncStatus: "error", syncError });
|
|
382
365
|
console.error(`Error syncing doc ${docId}:`, err);
|
|
@@ -438,10 +421,6 @@ class PatchesSync extends (_a = ReadonlyStoreClass, _syncDoc_dec = [serialGate],
|
|
|
438
421
|
await this._handleRemoteDocDeleted(docId);
|
|
439
422
|
return;
|
|
440
423
|
}
|
|
441
|
-
if (this._isAccessRevokedError(err)) {
|
|
442
|
-
await this._handleRemoteDocAccessRevoked(docId);
|
|
443
|
-
return;
|
|
444
|
-
}
|
|
445
424
|
const flushError = err instanceof Error ? err : new Error(String(err));
|
|
446
425
|
this._updateDocSyncState(docId, { syncStatus: "error", syncError: flushError });
|
|
447
426
|
console.error(`Flush failed for doc ${docId}:`, err);
|
|
@@ -583,27 +562,6 @@ class PatchesSync extends (_a = ReadonlyStoreClass, _syncDoc_dec = [serialGate],
|
|
|
583
562
|
* Cleans up local state and notifies the application with any pending changes that were lost.
|
|
584
563
|
*/
|
|
585
564
|
async _handleRemoteDocDeleted(docId) {
|
|
586
|
-
const pendingChanges = await this._cleanupAfterAccessLoss(docId);
|
|
587
|
-
await this.onRemoteDocDeleted.emit(docId, pendingChanges);
|
|
588
|
-
}
|
|
589
|
-
/**
|
|
590
|
-
* Sibling of `_handleRemoteDocDeleted` for the access-revoked path.
|
|
591
|
-
* Same local cleanup (close, untrack, drop cache, clear sync state) but
|
|
592
|
-
* the doc is not tombstoned server-side — it just isn't ours anymore.
|
|
593
|
-
* Emitted as a distinct signal so consumers can show different UX
|
|
594
|
-
* ("Your access was revoked" vs. "Project was deleted") without having
|
|
595
|
-
* to inspect error codes themselves.
|
|
596
|
-
*/
|
|
597
|
-
async _handleRemoteDocAccessRevoked(docId) {
|
|
598
|
-
const pendingChanges = await this._cleanupAfterAccessLoss(docId);
|
|
599
|
-
await this.onRemoteDocAccessRevoked.emit(docId, pendingChanges);
|
|
600
|
-
}
|
|
601
|
-
/**
|
|
602
|
-
* Local cleanup shared by `_handleRemoteDocDeleted` and
|
|
603
|
-
* `_handleRemoteDocAccessRevoked`. Returns pending changes that were
|
|
604
|
-
* lost so the caller can include them in the application-facing signal.
|
|
605
|
-
*/
|
|
606
|
-
async _cleanupAfterAccessLoss(docId) {
|
|
607
565
|
const algorithm = this._getAlgorithm(docId);
|
|
608
566
|
const pendingChanges = await algorithm.getPendingToSend(docId) ?? [];
|
|
609
567
|
const doc = this.patches.getOpenDoc(docId);
|
|
@@ -613,7 +571,7 @@ class PatchesSync extends (_a = ReadonlyStoreClass, _syncDoc_dec = [serialGate],
|
|
|
613
571
|
this.trackedDocs.delete(docId);
|
|
614
572
|
this._updateDocSyncState(docId, void 0);
|
|
615
573
|
await algorithm.confirmDeleteDoc(docId);
|
|
616
|
-
|
|
574
|
+
await this.onRemoteDocDeleted.emit(docId, pendingChanges);
|
|
617
575
|
}
|
|
618
576
|
/**
|
|
619
577
|
* Adds, updates, or removes a doc state entry immutably and notifies via store.
|
|
@@ -676,16 +634,6 @@ class PatchesSync extends (_a = ReadonlyStoreClass, _syncDoc_dec = [serialGate],
|
|
|
676
634
|
_isDocDeletedError(err) {
|
|
677
635
|
return err instanceof StatusError && err.code === ErrorCodes.DOC_DELETED;
|
|
678
636
|
}
|
|
679
|
-
/**
|
|
680
|
-
* Helper to detect ACCESS_REVOKED (403) errors from the server. Used by
|
|
681
|
-
* the sync/flush catch blocks to short-circuit straight into the
|
|
682
|
-
* `_handleRemoteDocAccessRevoked` cleanup path rather than latching the
|
|
683
|
-
* error onto `docStates[docId].syncError` (which would surface as a
|
|
684
|
-
* permanent "Unable to Sync" pill in the UI).
|
|
685
|
-
*/
|
|
686
|
-
_isAccessRevokedError(err) {
|
|
687
|
-
return err instanceof StatusError && err.code === ErrorCodes.ACCESS_REVOKED;
|
|
688
|
-
}
|
|
689
637
|
}
|
|
690
638
|
_init = __decoratorStart(_a);
|
|
691
639
|
__decorateElement(_init, 1, "syncDoc", _syncDoc_dec, PatchesSync);
|
package/dist/net/error.d.ts
CHANGED
|
@@ -5,21 +5,21 @@ declare class StatusError extends Error {
|
|
|
5
5
|
}
|
|
6
6
|
/**
|
|
7
7
|
* Standard error codes for Patches operations.
|
|
8
|
+
*
|
|
9
|
+
* Patches is permission-agnostic; these codes are surfaced verbatim from
|
|
10
|
+
* `StatusError.code` so consuming apps can branch on the HTTP status without
|
|
11
|
+
* reaching for string matching. Permission *policy* (what to do with a 403)
|
|
12
|
+
* lives in the consuming app.
|
|
8
13
|
*/
|
|
9
14
|
declare const ErrorCodes: {
|
|
10
15
|
/** Document was deleted (tombstone exists). */
|
|
11
16
|
readonly DOC_DELETED: 410;
|
|
12
17
|
/** Document not found (never existed). */
|
|
13
18
|
readonly DOC_NOT_FOUND: 404;
|
|
14
|
-
/**
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
* loop treats it like a soft delete: untrack, drop local cache, emit
|
|
19
|
-
* `onRemoteDocAccessRevoked` so the application can remove the doc from
|
|
20
|
-
* its own workspace state.
|
|
21
|
-
*/
|
|
22
|
-
readonly ACCESS_REVOKED: 403;
|
|
19
|
+
/** Caller is not authenticated (no/invalid credentials). */
|
|
20
|
+
readonly DOC_UNAUTHORIZED: 401;
|
|
21
|
+
/** Caller is authenticated but not authorized for this doc. */
|
|
22
|
+
readonly DOC_FORBIDDEN: 403;
|
|
23
23
|
};
|
|
24
24
|
/**
|
|
25
25
|
* Error thrown when the JSON-RPC client receives a message that cannot be parsed as JSON.
|
package/dist/net/error.js
CHANGED
|
@@ -11,15 +11,10 @@ const ErrorCodes = {
|
|
|
11
11
|
DOC_DELETED: 410,
|
|
12
12
|
/** Document not found (never existed). */
|
|
13
13
|
DOC_NOT_FOUND: 404,
|
|
14
|
-
/**
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
* loop treats it like a soft delete: untrack, drop local cache, emit
|
|
19
|
-
* `onRemoteDocAccessRevoked` so the application can remove the doc from
|
|
20
|
-
* its own workspace state.
|
|
21
|
-
*/
|
|
22
|
-
ACCESS_REVOKED: 403
|
|
14
|
+
/** Caller is not authenticated (no/invalid credentials). */
|
|
15
|
+
DOC_UNAUTHORIZED: 401,
|
|
16
|
+
/** Caller is authenticated but not authorized for this doc. */
|
|
17
|
+
DOC_FORBIDDEN: 403
|
|
23
18
|
};
|
|
24
19
|
class JSONRPCParseError extends Error {
|
|
25
20
|
rawMessage;
|
package/dist/net/index.d.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
export { Invite, InviteProjectBookMeta, InviteProjectMetaSnapshot, InviteRole, InviteTo } from './invite.js';
|
|
2
1
|
export { FetchTransport } from './http/FetchTransport.js';
|
|
3
2
|
export { PatchesClient } from './PatchesClient.js';
|
|
4
3
|
export { PatchesConnection } from './PatchesConnection.js';
|
|
@@ -25,7 +24,7 @@ import '../algorithms/ot/shared/changeBatching.js';
|
|
|
25
24
|
import '../client/BranchClientStore.js';
|
|
26
25
|
import '../client/ClientAlgorithm.js';
|
|
27
26
|
import '../json-patch/types.js';
|
|
28
|
-
import '../BaseDoc-
|
|
27
|
+
import '../BaseDoc-CXHXcW18.js';
|
|
29
28
|
import '../client/PatchesStore.js';
|
|
30
29
|
import '../client/Patches.js';
|
|
31
30
|
import '../server/types.js';
|
package/dist/net/index.js
CHANGED
|
@@ -162,7 +162,7 @@ class JSONRPCServer {
|
|
|
162
162
|
}
|
|
163
163
|
const ok = await this.auth.canAccess(ctx, docId, access, method);
|
|
164
164
|
if (!ok) {
|
|
165
|
-
throw new StatusError(
|
|
165
|
+
throw new StatusError(403, `${access.toUpperCase()}_FORBIDDEN:${docId}`);
|
|
166
166
|
}
|
|
167
167
|
}
|
|
168
168
|
/**
|
|
@@ -2,7 +2,6 @@ import * as easy_signal from 'easy-signal';
|
|
|
2
2
|
import { Change, CommitChangesOptions, PatchesState, ChangeInput, DeleteDocOptions, EditableVersionMetadata, ListVersionsOptions, VersionMetadata, PatchesSnapshot, Branch, CreateBranchMetadata, EditableBranchMetadata } from '../../types.js';
|
|
3
3
|
import { PatchesConnection } from '../PatchesConnection.js';
|
|
4
4
|
import { ConnectionState } from '../protocol/types.js';
|
|
5
|
-
import { Invite } from '../invite.js';
|
|
6
5
|
import '../../json-patch/JSONPatch.js';
|
|
7
6
|
import '@dabble/delta';
|
|
8
7
|
import '../../json-patch/types.js';
|
|
@@ -76,28 +75,6 @@ declare class PatchesREST implements PatchesConnection {
|
|
|
76
75
|
updateBranch(docId: string, branchId: string, metadata: EditableBranchMetadata): Promise<void>;
|
|
77
76
|
deleteBranch(docId: string, branchId: string): Promise<void>;
|
|
78
77
|
mergeBranch(docId: string, branchId: string): Promise<void>;
|
|
79
|
-
/**
|
|
80
|
-
* Fetch a single invite addressed to the authenticated user.
|
|
81
|
-
* `GET /docs/:docId/_invites/:inviteId`
|
|
82
|
-
*/
|
|
83
|
-
getInvite(docId: string, inviteId: string): Promise<Invite>;
|
|
84
|
-
/**
|
|
85
|
-
* Accept or decline an invite. Returns whether the server applied a role
|
|
86
|
-
* change (`ok` from `{ ok: boolean }`).
|
|
87
|
-
* `POST /docs/:docId/_invites/:inviteId` body `{ accept: boolean }`
|
|
88
|
-
*/
|
|
89
|
-
acceptInvite(docId: string, inviteId: string, accept: boolean): Promise<boolean>;
|
|
90
|
-
/**
|
|
91
|
-
* Remove the authenticated user from `roles.users` (non-owners only).
|
|
92
|
-
* `POST /docs/:docId/_self/leave`
|
|
93
|
-
*/
|
|
94
|
-
leaveProject(docId: string): Promise<boolean>;
|
|
95
|
-
/**
|
|
96
|
-
* Owner/co-author revokes another member. `targetUid` is removed from
|
|
97
|
-
* `roles.users` and tombstoned under `roles.formerUsers.revokedAt`.
|
|
98
|
-
* `POST /docs/:docId/_members/:uid/revoke`
|
|
99
|
-
*/
|
|
100
|
-
revokeMember(docId: string, targetUid: string): Promise<boolean>;
|
|
101
78
|
/**
|
|
102
79
|
* POSTs a raw JSON-RPC string to `/signal/:clientId`. Used as the upstream
|
|
103
80
|
* half of the multiplexed signaling channel: receive happens via the `signal`
|
|
@@ -202,52 +202,6 @@ class PatchesREST {
|
|
|
202
202
|
async mergeBranch(docId, branchId) {
|
|
203
203
|
await this._fetch(`/docs/${docId}/_branches/${encodeURIComponent(branchId)}/_merge`, { method: "POST" });
|
|
204
204
|
}
|
|
205
|
-
// --- Invites & membership (pup REST) ---
|
|
206
|
-
/**
|
|
207
|
-
* Fetch a single invite addressed to the authenticated user.
|
|
208
|
-
* `GET /docs/:docId/_invites/:inviteId`
|
|
209
|
-
*/
|
|
210
|
-
async getInvite(docId, inviteId) {
|
|
211
|
-
return this._fetch(`/docs/${docId}/_invites/${encodeURIComponent(inviteId)}`);
|
|
212
|
-
}
|
|
213
|
-
/**
|
|
214
|
-
* Accept or decline an invite. Returns whether the server applied a role
|
|
215
|
-
* change (`ok` from `{ ok: boolean }`).
|
|
216
|
-
* `POST /docs/:docId/_invites/:inviteId` body `{ accept: boolean }`
|
|
217
|
-
*/
|
|
218
|
-
async acceptInvite(docId, inviteId, accept) {
|
|
219
|
-
const result = await this._fetch(`/docs/${docId}/_invites/${encodeURIComponent(inviteId)}`, {
|
|
220
|
-
method: "POST",
|
|
221
|
-
body: { accept }
|
|
222
|
-
});
|
|
223
|
-
return Boolean(result?.ok);
|
|
224
|
-
}
|
|
225
|
-
/**
|
|
226
|
-
* Remove the authenticated user from `roles.users` (non-owners only).
|
|
227
|
-
* `POST /docs/:docId/_self/leave`
|
|
228
|
-
*/
|
|
229
|
-
async leaveProject(docId) {
|
|
230
|
-
const result = await this._fetch(`/docs/${docId}/_self/leave`, {
|
|
231
|
-
method: "POST",
|
|
232
|
-
body: {}
|
|
233
|
-
});
|
|
234
|
-
return Boolean(result?.ok);
|
|
235
|
-
}
|
|
236
|
-
/**
|
|
237
|
-
* Owner/co-author revokes another member. `targetUid` is removed from
|
|
238
|
-
* `roles.users` and tombstoned under `roles.formerUsers.revokedAt`.
|
|
239
|
-
* `POST /docs/:docId/_members/:uid/revoke`
|
|
240
|
-
*/
|
|
241
|
-
async revokeMember(docId, targetUid) {
|
|
242
|
-
const result = await this._fetch(
|
|
243
|
-
`/docs/${docId}/_members/${encodeURIComponent(targetUid)}/revoke`,
|
|
244
|
-
{
|
|
245
|
-
method: "POST",
|
|
246
|
-
body: {}
|
|
247
|
-
}
|
|
248
|
-
);
|
|
249
|
-
return Boolean(result?.ok);
|
|
250
|
-
}
|
|
251
205
|
// --- WebRTC Signaling ---
|
|
252
206
|
/**
|
|
253
207
|
* POSTs a raw JSON-RPC string to `/signal/:clientId`. Used as the upstream
|
package/dist/net/rest/index.d.ts
CHANGED
|
@@ -10,7 +10,6 @@ import '@dabble/delta';
|
|
|
10
10
|
import '../../json-patch/types.js';
|
|
11
11
|
import '../PatchesConnection.js';
|
|
12
12
|
import '../protocol/types.js';
|
|
13
|
-
import '../invite.js';
|
|
14
13
|
import '../websocket/AuthorizationProvider.js';
|
|
15
14
|
import '../../server/types.js';
|
|
16
15
|
import '../signaling/SignalingService.js';
|
|
@@ -70,9 +70,10 @@ class SignalingService {
|
|
|
70
70
|
} catch {
|
|
71
71
|
return false;
|
|
72
72
|
}
|
|
73
|
-
if (parsed.jsonrpc !== "2.0" || parsed.method !== "peer-signal" || !parsed.params
|
|
74
|
-
const {
|
|
75
|
-
const
|
|
73
|
+
if (parsed.jsonrpc !== "2.0" || parsed.method !== "peer-signal" || !Array.isArray(parsed.params)) return false;
|
|
74
|
+
const { id } = parsed;
|
|
75
|
+
const [to, data] = parsed.params;
|
|
76
|
+
if (typeof to !== "string" || !to) return false;
|
|
76
77
|
const clients = await this.getClients();
|
|
77
78
|
if (!clients.has(to)) {
|
|
78
79
|
this.respondError(fromId, id, "Target not connected");
|
|
@@ -20,7 +20,7 @@ class WebRTCTransport {
|
|
|
20
20
|
this.rpc.on("peer-disconnected", ({ id }) => {
|
|
21
21
|
this._removePeer(id);
|
|
22
22
|
}),
|
|
23
|
-
this.rpc.on("
|
|
23
|
+
this.rpc.on("signal", ({ from, data }) => {
|
|
24
24
|
if (!this.peers.has(from)) {
|
|
25
25
|
this._connectToPeer(from, false);
|
|
26
26
|
}
|
|
@@ -113,7 +113,7 @@ class WebRTCTransport {
|
|
|
113
113
|
_connectToPeer(peerId, initiator) {
|
|
114
114
|
const peer = new Peer({ initiator, trickle: false });
|
|
115
115
|
peer.on("signal", (data) => {
|
|
116
|
-
this.rpc.
|
|
116
|
+
this.rpc.notify("peer-signal", peerId, data);
|
|
117
117
|
});
|
|
118
118
|
peer.on("connect", () => {
|
|
119
119
|
this.peers.set(peerId, { id: peerId, peer, connected: true });
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ApiDefinition } from '../net/protocol/JSONRPCServer.js';
|
|
2
|
-
import { EditableBranchMetadata,
|
|
2
|
+
import { EditableBranchMetadata, CreateBranchMetadata, Branch } from '../types.js';
|
|
3
3
|
import 'easy-signal';
|
|
4
4
|
import '../net/websocket/AuthorizationProvider.js';
|
|
5
5
|
import './types.js';
|
package/dist/solid/context.d.ts
CHANGED
|
@@ -7,7 +7,7 @@ import '../types.js';
|
|
|
7
7
|
import '../json-patch/JSONPatch.js';
|
|
8
8
|
import '@dabble/delta';
|
|
9
9
|
import '../client/ClientAlgorithm.js';
|
|
10
|
-
import '../BaseDoc-
|
|
10
|
+
import '../BaseDoc-CXHXcW18.js';
|
|
11
11
|
import '../client/PatchesStore.js';
|
|
12
12
|
import '../algorithms/ot/shared/changeBatching.js';
|
|
13
13
|
import '../client/BranchClientStore.js';
|
package/dist/solid/index.d.ts
CHANGED
|
@@ -11,7 +11,7 @@ import '../types.js';
|
|
|
11
11
|
import '../json-patch/JSONPatch.js';
|
|
12
12
|
import '@dabble/delta';
|
|
13
13
|
import '../client/ClientAlgorithm.js';
|
|
14
|
-
import '../BaseDoc-
|
|
14
|
+
import '../BaseDoc-CXHXcW18.js';
|
|
15
15
|
import '../client/PatchesStore.js';
|
|
16
16
|
import '../net/PatchesSync.js';
|
|
17
17
|
import '../algorithms/ot/shared/changeBatching.js';
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Accessor } from 'solid-js';
|
|
2
2
|
import { OpenDocOptions } from '../client/Patches.js';
|
|
3
|
-
import {
|
|
3
|
+
import { a as PatchesDoc } from '../BaseDoc-CXHXcW18.js';
|
|
4
4
|
import { ChangeMutator } from '../types.js';
|
|
5
5
|
import 'easy-signal';
|
|
6
6
|
import '../json-patch/types.js';
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { ShallowRef, Ref,
|
|
1
|
+
import { ShallowRef, Ref, MaybeRefOrGetter, MaybeRef } from 'vue';
|
|
2
2
|
import { OpenDocOptions } from '../client/Patches.js';
|
|
3
|
-
import {
|
|
3
|
+
import { a as PatchesDoc } from '../BaseDoc-CXHXcW18.js';
|
|
4
4
|
import { ChangeMutator } from '../types.js';
|
|
5
5
|
import 'easy-signal';
|
|
6
6
|
import '../json-patch/types.js';
|
package/dist/vue/index.d.ts
CHANGED
|
@@ -11,7 +11,7 @@ import '../types.js';
|
|
|
11
11
|
import '../json-patch/JSONPatch.js';
|
|
12
12
|
import '@dabble/delta';
|
|
13
13
|
import '../client/ClientAlgorithm.js';
|
|
14
|
-
import '../BaseDoc-
|
|
14
|
+
import '../BaseDoc-CXHXcW18.js';
|
|
15
15
|
import '../client/PatchesStore.js';
|
|
16
16
|
import '../net/PatchesSync.js';
|
|
17
17
|
import '../algorithms/ot/shared/changeBatching.js';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Ref, ShallowRef } from 'vue';
|
|
2
2
|
import { OpenDocOptions } from '../client/Patches.js';
|
|
3
3
|
import 'easy-signal';
|
|
4
4
|
import '../json-patch/types.js';
|
|
@@ -6,7 +6,7 @@ import '../types.js';
|
|
|
6
6
|
import '../json-patch/JSONPatch.js';
|
|
7
7
|
import '@dabble/delta';
|
|
8
8
|
import '../client/ClientAlgorithm.js';
|
|
9
|
-
import '../BaseDoc-
|
|
9
|
+
import '../BaseDoc-CXHXcW18.js';
|
|
10
10
|
import '../client/PatchesStore.js';
|
|
11
11
|
|
|
12
12
|
/**
|
package/dist/vue/provider.d.ts
CHANGED
|
@@ -7,7 +7,7 @@ import '../types.js';
|
|
|
7
7
|
import '../json-patch/JSONPatch.js';
|
|
8
8
|
import '@dabble/delta';
|
|
9
9
|
import '../client/ClientAlgorithm.js';
|
|
10
|
-
import '../BaseDoc-
|
|
10
|
+
import '../BaseDoc-CXHXcW18.js';
|
|
11
11
|
import '../client/PatchesStore.js';
|
|
12
12
|
import '../algorithms/ot/shared/changeBatching.js';
|
|
13
13
|
import '../client/BranchClientStore.js';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dabble/patches",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.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": {
|
package/dist/net/invite.d.ts
DELETED
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Shapes returned by pup's invite endpoints (`GET /docs/:docId/_invites/:inviteId`)
|
|
3
|
-
* and embedded in roles documents. Kept in sync with pup's `Invite` / `UserAccess`
|
|
4
|
-
* surface so clients deserialize with correct field names.
|
|
5
|
-
*/
|
|
6
|
-
type InviteRole = 'owner' | 'write' | 'edit' | 'comment' | 'view';
|
|
7
|
-
/** Invite addressee payload (`invite.to`). */
|
|
8
|
-
interface InviteTo {
|
|
9
|
-
role: InviteRole;
|
|
10
|
-
private?: boolean;
|
|
11
|
-
doc?: string;
|
|
12
|
-
/** Optional client-side id echoed from legacy creation paths; stripped on accept server-side. */
|
|
13
|
-
id?: string;
|
|
14
|
-
name?: string;
|
|
15
|
-
email: string;
|
|
16
|
-
}
|
|
17
|
-
/**
|
|
18
|
-
* Minimal book-row shape stored on invites for dashboard-style previews.
|
|
19
|
-
* Mirrors writer `NovelBookMeta` / pup-embedded JSON (extra keys are ignored).
|
|
20
|
-
*/
|
|
21
|
-
interface InviteProjectBookMeta {
|
|
22
|
-
id?: string;
|
|
23
|
-
title?: string;
|
|
24
|
-
subtitle?: string;
|
|
25
|
-
author?: string;
|
|
26
|
-
coverArt?: string;
|
|
27
|
-
coverArtRatio?: unknown;
|
|
28
|
-
pattern?: number;
|
|
29
|
-
backgroundColor?: unknown;
|
|
30
|
-
}
|
|
31
|
-
/** Novel project meta snapshot on an invite (writer `InviteProjectMetaSnapshot`). */
|
|
32
|
-
interface InviteProjectMetaSnapshot {
|
|
33
|
-
title?: string;
|
|
34
|
-
modifiedAt?: string;
|
|
35
|
-
books: InviteProjectBookMeta[];
|
|
36
|
-
isTemplate?: boolean;
|
|
37
|
-
templateCount?: number;
|
|
38
|
-
type?: string;
|
|
39
|
-
}
|
|
40
|
-
interface Invite {
|
|
41
|
-
from: string;
|
|
42
|
-
to: InviteTo;
|
|
43
|
-
createdAt: number;
|
|
44
|
-
expiresAt: number;
|
|
45
|
-
/** Cached project title at invite creation (writer/pup roles doc). */
|
|
46
|
-
projectName?: string;
|
|
47
|
-
/** @deprecated Prefer `projectMetaSnapshot.books`. */
|
|
48
|
-
projectBooks?: InviteProjectBookMeta[];
|
|
49
|
-
/** @deprecated Prefer `projectMetaSnapshot.modifiedAt`. */
|
|
50
|
-
projectModifiedAt?: string;
|
|
51
|
-
/** Full project meta snapshot for accept-modal preview. */
|
|
52
|
-
projectMetaSnapshot?: InviteProjectMetaSnapshot;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
export type { Invite, InviteProjectBookMeta, InviteProjectMetaSnapshot, InviteRole, InviteTo };
|
package/dist/net/invite.js
DELETED
|
File without changes
|