@smthrs/sync 0.0.0-stage → 1.0.0-rc.3
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/CHANGELOG.md +208 -0
- package/LICENSE +21 -0
- package/README.md +208 -2
- package/dist/cjs/BranchCommands.d.ts +228 -0
- package/dist/cjs/BranchCommands.d.ts.map +1 -0
- package/dist/cjs/BranchCommands.js +316 -0
- package/dist/cjs/BranchCommands.js.map +7 -0
- package/dist/cjs/BranchIds.d.ts +65 -0
- package/dist/cjs/BranchIds.d.ts.map +1 -0
- package/dist/cjs/BranchIds.js +53 -0
- package/dist/cjs/BranchIds.js.map +7 -0
- package/dist/cjs/BranchPresence.d.ts +195 -0
- package/dist/cjs/BranchPresence.d.ts.map +1 -0
- package/dist/cjs/BranchPresence.js +276 -0
- package/dist/cjs/BranchPresence.js.map +7 -0
- package/dist/cjs/BranchProjection.d.ts +179 -0
- package/dist/cjs/BranchProjection.d.ts.map +1 -0
- package/dist/cjs/BranchProjection.js +197 -0
- package/dist/cjs/BranchProjection.js.map +7 -0
- package/dist/cjs/BranchProtocol.d.ts +415 -0
- package/dist/cjs/BranchProtocol.d.ts.map +1 -0
- package/dist/cjs/BranchProtocol.js +172 -0
- package/dist/cjs/BranchProtocol.js.map +7 -0
- package/dist/cjs/BranchRpcs.d.ts +177 -0
- package/dist/cjs/BranchRpcs.d.ts.map +1 -0
- package/dist/cjs/BranchRpcs.js +85 -0
- package/dist/cjs/BranchRpcs.js.map +7 -0
- package/dist/cjs/BranchServer.d.ts +55 -0
- package/dist/cjs/BranchServer.d.ts.map +1 -0
- package/dist/cjs/BranchServer.js +147 -0
- package/dist/cjs/BranchServer.js.map +7 -0
- package/dist/cjs/BranchShare.d.ts +159 -0
- package/dist/cjs/BranchShare.d.ts.map +1 -0
- package/dist/cjs/BranchShare.js +147 -0
- package/dist/cjs/BranchShare.js.map +7 -0
- package/dist/cjs/RunCatalog.d.ts +207 -0
- package/dist/cjs/RunCatalog.d.ts.map +1 -0
- package/dist/cjs/RunCatalog.js +122 -0
- package/dist/cjs/RunCatalog.js.map +7 -0
- package/dist/cjs/SyncAuth.d.ts +70 -0
- package/dist/cjs/SyncAuth.d.ts.map +1 -0
- package/dist/cjs/SyncAuth.js +109 -0
- package/dist/cjs/SyncAuth.js.map +7 -0
- package/dist/cjs/SyncClient.d.ts +274 -0
- package/dist/cjs/SyncClient.d.ts.map +1 -0
- package/dist/cjs/SyncClient.js +474 -0
- package/dist/cjs/SyncClient.js.map +7 -0
- package/dist/cjs/SyncError.d.ts +107 -0
- package/dist/cjs/SyncError.d.ts.map +1 -0
- package/dist/cjs/SyncError.js +110 -0
- package/dist/cjs/SyncError.js.map +7 -0
- package/dist/cjs/SyncPrincipal.d.ts +100 -0
- package/dist/cjs/SyncPrincipal.d.ts.map +1 -0
- package/dist/cjs/SyncPrincipal.js +48 -0
- package/dist/cjs/SyncPrincipal.js.map +7 -0
- package/dist/cjs/SyncProtocol.d.ts +592 -0
- package/dist/cjs/SyncProtocol.d.ts.map +1 -0
- package/dist/cjs/SyncProtocol.js +165 -0
- package/dist/cjs/SyncProtocol.js.map +7 -0
- package/dist/cjs/SyncRpcs.d.ts +92 -0
- package/dist/cjs/SyncRpcs.d.ts.map +1 -0
- package/dist/cjs/SyncRpcs.js +35 -0
- package/dist/cjs/SyncRpcs.js.map +7 -0
- package/dist/cjs/SyncServer.d.ts +184 -0
- package/dist/cjs/SyncServer.d.ts.map +1 -0
- package/dist/cjs/SyncServer.js +513 -0
- package/dist/cjs/SyncServer.js.map +7 -0
- package/dist/cjs/WorkspaceShare.d.ts +174 -0
- package/dist/cjs/WorkspaceShare.d.ts.map +1 -0
- package/dist/cjs/WorkspaceShare.js +149 -0
- package/dist/cjs/WorkspaceShare.js.map +7 -0
- package/dist/cjs/index.d.ts +91 -0
- package/dist/cjs/index.d.ts.map +1 -0
- package/dist/cjs/index.js +67 -0
- package/dist/cjs/index.js.map +7 -0
- package/dist/cjs/internal/Admission.d.ts +43 -0
- package/dist/cjs/internal/Admission.d.ts.map +1 -0
- package/dist/cjs/internal/Admission.js +90 -0
- package/dist/cjs/internal/Admission.js.map +7 -0
- package/dist/cjs/internal/CauseText.d.ts +55 -0
- package/dist/cjs/internal/CauseText.d.ts.map +1 -0
- package/dist/cjs/internal/CauseText.js +38 -0
- package/dist/cjs/internal/CauseText.js.map +7 -0
- package/dist/cjs/internal/JournalErrorCode.d.ts +23 -0
- package/dist/cjs/internal/JournalErrorCode.d.ts.map +1 -0
- package/dist/cjs/internal/JournalErrorCode.js +34 -0
- package/dist/cjs/internal/JournalErrorCode.js.map +7 -0
- package/dist/cjs/internal/PolicyOptions.d.ts +57 -0
- package/dist/cjs/internal/PolicyOptions.d.ts.map +1 -0
- package/dist/cjs/internal/PolicyOptions.js +62 -0
- package/dist/cjs/internal/PolicyOptions.js.map +7 -0
- package/dist/cjs/internal/ProtocolVersion.d.ts +17 -0
- package/dist/cjs/internal/ProtocolVersion.d.ts.map +1 -0
- package/dist/cjs/internal/ProtocolVersion.js +44 -0
- package/dist/cjs/internal/ProtocolVersion.js.map +7 -0
- package/dist/cjs/internal/ShareSigner.d.ts +173 -0
- package/dist/cjs/internal/ShareSigner.d.ts.map +1 -0
- package/dist/cjs/internal/ShareSigner.js +150 -0
- package/dist/cjs/internal/ShareSigner.js.map +7 -0
- package/dist/cjs/internal/SnapshotBoundary.d.ts +17 -0
- package/dist/cjs/internal/SnapshotBoundary.d.ts.map +1 -0
- package/dist/cjs/internal/SnapshotBoundary.js +97 -0
- package/dist/cjs/internal/SnapshotBoundary.js.map +7 -0
- package/dist/cjs/package.json +1 -0
- package/dist/cjs/test/TestSocket.d.ts +55 -0
- package/dist/cjs/test/TestSocket.d.ts.map +1 -0
- package/dist/cjs/test/TestSocket.js +145 -0
- package/dist/cjs/test/TestSocket.js.map +7 -0
- package/dist/cjs/test/TestSync.d.ts +54 -0
- package/dist/cjs/test/TestSync.d.ts.map +1 -0
- package/dist/cjs/test/TestSync.js +96 -0
- package/dist/cjs/test/TestSync.js.map +7 -0
- package/dist/esm/BranchCommands.d.ts +228 -0
- package/dist/esm/BranchCommands.d.ts.map +1 -0
- package/dist/esm/BranchCommands.js +496 -0
- package/dist/esm/BranchCommands.js.map +1 -0
- package/dist/esm/BranchIds.d.ts +65 -0
- package/dist/esm/BranchIds.d.ts.map +1 -0
- package/dist/esm/BranchIds.js +61 -0
- package/dist/esm/BranchIds.js.map +1 -0
- package/dist/esm/BranchPresence.d.ts +195 -0
- package/dist/esm/BranchPresence.d.ts.map +1 -0
- package/dist/esm/BranchPresence.js +361 -0
- package/dist/esm/BranchPresence.js.map +1 -0
- package/dist/esm/BranchProjection.d.ts +179 -0
- package/dist/esm/BranchProjection.d.ts.map +1 -0
- package/dist/esm/BranchProjection.js +269 -0
- package/dist/esm/BranchProjection.js.map +1 -0
- package/dist/esm/BranchProtocol.d.ts +415 -0
- package/dist/esm/BranchProtocol.d.ts.map +1 -0
- package/dist/esm/BranchProtocol.js +323 -0
- package/dist/esm/BranchProtocol.js.map +1 -0
- package/dist/esm/BranchRpcs.d.ts +177 -0
- package/dist/esm/BranchRpcs.d.ts.map +1 -0
- package/dist/esm/BranchRpcs.js +103 -0
- package/dist/esm/BranchRpcs.js.map +1 -0
- package/dist/esm/BranchServer.d.ts +55 -0
- package/dist/esm/BranchServer.d.ts.map +1 -0
- package/dist/esm/BranchServer.js +168 -0
- package/dist/esm/BranchServer.js.map +1 -0
- package/dist/esm/BranchShare.d.ts +159 -0
- package/dist/esm/BranchShare.d.ts.map +1 -0
- package/dist/esm/BranchShare.js +213 -0
- package/dist/esm/BranchShare.js.map +1 -0
- package/dist/esm/RunCatalog.d.ts +207 -0
- package/dist/esm/RunCatalog.d.ts.map +1 -0
- package/dist/esm/RunCatalog.js +196 -0
- package/dist/esm/RunCatalog.js.map +1 -0
- package/dist/esm/SyncAuth.d.ts +70 -0
- package/dist/esm/SyncAuth.d.ts.map +1 -0
- package/dist/esm/SyncAuth.js +119 -0
- package/dist/esm/SyncAuth.js.map +1 -0
- package/dist/esm/SyncClient.d.ts +274 -0
- package/dist/esm/SyncClient.d.ts.map +1 -0
- package/dist/esm/SyncClient.js +586 -0
- package/dist/esm/SyncClient.js.map +1 -0
- package/dist/esm/SyncError.d.ts +107 -0
- package/dist/esm/SyncError.d.ts.map +1 -0
- package/dist/esm/SyncError.js +133 -0
- package/dist/esm/SyncError.js.map +1 -0
- package/dist/esm/SyncPrincipal.d.ts +100 -0
- package/dist/esm/SyncPrincipal.d.ts.map +1 -0
- package/dist/esm/SyncPrincipal.js +58 -0
- package/dist/esm/SyncPrincipal.js.map +1 -0
- package/dist/esm/SyncProtocol.d.ts +592 -0
- package/dist/esm/SyncProtocol.d.ts.map +1 -0
- package/dist/esm/SyncProtocol.js +434 -0
- package/dist/esm/SyncProtocol.js.map +1 -0
- package/dist/esm/SyncRpcs.d.ts +92 -0
- package/dist/esm/SyncRpcs.d.ts.map +1 -0
- package/dist/esm/SyncRpcs.js +35 -0
- package/dist/esm/SyncRpcs.js.map +1 -0
- package/dist/esm/SyncServer.d.ts +184 -0
- package/dist/esm/SyncServer.d.ts.map +1 -0
- package/dist/esm/SyncServer.js +897 -0
- package/dist/esm/SyncServer.js.map +1 -0
- package/dist/esm/WorkspaceShare.d.ts +174 -0
- package/dist/esm/WorkspaceShare.d.ts.map +1 -0
- package/dist/esm/WorkspaceShare.js +208 -0
- package/dist/esm/WorkspaceShare.js.map +1 -0
- package/dist/esm/index.d.ts +91 -0
- package/dist/esm/index.d.ts.map +1 -0
- package/dist/esm/index.js +91 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/internal/Admission.d.ts +43 -0
- package/dist/esm/internal/Admission.d.ts.map +1 -0
- package/dist/esm/internal/Admission.js +80 -0
- package/dist/esm/internal/Admission.js.map +1 -0
- package/dist/esm/internal/CauseText.d.ts +55 -0
- package/dist/esm/internal/CauseText.d.ts.map +1 -0
- package/dist/esm/internal/CauseText.js +67 -0
- package/dist/esm/internal/CauseText.js.map +1 -0
- package/dist/esm/internal/JournalErrorCode.d.ts +23 -0
- package/dist/esm/internal/JournalErrorCode.d.ts.map +1 -0
- package/dist/esm/internal/JournalErrorCode.js +44 -0
- package/dist/esm/internal/JournalErrorCode.js.map +1 -0
- package/dist/esm/internal/PolicyOptions.d.ts +57 -0
- package/dist/esm/internal/PolicyOptions.d.ts.map +1 -0
- package/dist/esm/internal/PolicyOptions.js +70 -0
- package/dist/esm/internal/PolicyOptions.js.map +1 -0
- package/dist/esm/internal/ProtocolVersion.d.ts +17 -0
- package/dist/esm/internal/ProtocolVersion.d.ts.map +1 -0
- package/dist/esm/internal/ProtocolVersion.js +24 -0
- package/dist/esm/internal/ProtocolVersion.js.map +1 -0
- package/dist/esm/internal/ShareSigner.d.ts +173 -0
- package/dist/esm/internal/ShareSigner.d.ts.map +1 -0
- package/dist/esm/internal/ShareSigner.js +219 -0
- package/dist/esm/internal/ShareSigner.js.map +1 -0
- package/dist/esm/internal/SnapshotBoundary.d.ts +17 -0
- package/dist/esm/internal/SnapshotBoundary.d.ts.map +1 -0
- package/dist/esm/internal/SnapshotBoundary.js +68 -0
- package/dist/esm/internal/SnapshotBoundary.js.map +1 -0
- package/dist/esm/test/TestSocket.d.ts +55 -0
- package/dist/esm/test/TestSocket.d.ts.map +1 -0
- package/dist/esm/test/TestSocket.js +128 -0
- package/dist/esm/test/TestSocket.js.map +1 -0
- package/dist/esm/test/TestSync.d.ts +54 -0
- package/dist/esm/test/TestSync.d.ts.map +1 -0
- package/dist/esm/test/TestSync.js +76 -0
- package/dist/esm/test/TestSync.js.map +1 -0
- package/docs/README.md +156 -0
- package/docs/api.md +328 -0
- package/docs/concepts/authorization.md +117 -0
- package/docs/concepts/branches.md +195 -0
- package/docs/concepts/compaction.md +144 -0
- package/docs/concepts/replay-then-follow.md +129 -0
- package/docs/concepts/scopes-and-cursors.md +135 -0
- package/docs/guides/authorize-a-connection.md +174 -0
- package/docs/guides/follow-a-run.md +174 -0
- package/docs/guides/handle-a-compacted-run.md +158 -0
- package/docs/guides/list-workspace-runs.md +120 -0
- package/docs/guides/run-a-long-soak.md +80 -0
- package/docs/guides/serve-the-read-path.md +146 -0
- package/docs/guides/test-a-follower.md +273 -0
- package/docs/installation.md +92 -0
- package/docs/protocol.md +183 -0
- package/docs/quickstart.md +159 -0
- package/docs/troubleshooting.md +234 -0
- package/package.json +304 -3
- package/src/BranchCommands.ts +684 -0
- package/src/BranchIds.ts +76 -0
- package/src/BranchPresence.ts +512 -0
- package/src/BranchProjection.ts +308 -0
- package/src/BranchProtocol.ts +411 -0
- package/src/BranchRpcs.ts +163 -0
- package/src/BranchServer.ts +202 -0
- package/src/BranchShare.ts +297 -0
- package/src/RunCatalog.ts +308 -0
- package/src/SyncAuth.ts +146 -0
- package/src/SyncClient.ts +902 -0
- package/src/SyncError.ts +147 -0
- package/src/SyncPrincipal.ts +115 -0
- package/src/SyncProtocol.ts +594 -0
- package/src/SyncRpcs.ts +40 -0
- package/src/SyncServer.ts +1184 -0
- package/src/WorkspaceShare.ts +292 -0
- package/src/index.ts +107 -0
- package/src/internal/Admission.ts +119 -0
- package/src/internal/CauseText.ts +74 -0
- package/src/internal/JournalErrorCode.ts +46 -0
- package/src/internal/PolicyOptions.ts +97 -0
- package/src/internal/ProtocolVersion.ts +28 -0
- package/src/internal/ShareSigner.ts +300 -0
- package/src/internal/SnapshotBoundary.ts +91 -0
- package/src/test/TestSocket.ts +192 -0
- package/src/test/TestSync.ts +113 -0
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The branch document projection: journal entries folded into what two people
|
|
3
|
+
* looking at the same branch must agree on.
|
|
4
|
+
*
|
|
5
|
+
* The fold is order-independent over the canonical entry set, which is what
|
|
6
|
+
* makes convergence a property rather than a hope: any two clients that have
|
|
7
|
+
* applied the same set of entries hold the same state, regardless of the
|
|
8
|
+
* order their transports delivered frames in or how many times a frame
|
|
9
|
+
* arrived.
|
|
10
|
+
*
|
|
11
|
+
* Three guards do all the work, and each is a production invariant:
|
|
12
|
+
*
|
|
13
|
+
* - entries from another branch's run are ignored, so a mis-routed frame can
|
|
14
|
+
* never leak into a projection;
|
|
15
|
+
* - an entry already folded — the cursor tip redelivered, or a command id
|
|
16
|
+
* already applied — is ignored, so an at-least-once transport cannot
|
|
17
|
+
* double-apply a user action and a reconnect replays no side effects;
|
|
18
|
+
* - an entry below the cursor whose command was never applied is folded into
|
|
19
|
+
* its canonical `seq` position, so out-of-order delivery converges on the
|
|
20
|
+
* same document instead of permanently dropping the late entry.
|
|
21
|
+
*
|
|
22
|
+
* @since 0.1.0
|
|
23
|
+
*/
|
|
24
|
+
import * as JournalEvent from "@smthrs/journal/JournalEvent";
|
|
25
|
+
import * as Schema from "effect/Schema";
|
|
26
|
+
import { BranchId } from "./BranchProtocol.ts";
|
|
27
|
+
/**
|
|
28
|
+
* One collaborative chat message in the branch timeline.
|
|
29
|
+
*
|
|
30
|
+
* @category models
|
|
31
|
+
* @since 0.1.0
|
|
32
|
+
*/
|
|
33
|
+
export declare const Message: Schema.Struct<{
|
|
34
|
+
readonly seq: Schema.brand<Schema.Int, "@smthrs/journal/JournalEvent/Seq">;
|
|
35
|
+
readonly commandId: Schema.brand<Schema.NonEmptyString, "@smthrs/sync/BranchProtocol/CommandId">;
|
|
36
|
+
readonly participantId: Schema.brand<Schema.NonEmptyString, "@smthrs/sync/BranchProtocol/ParticipantId">;
|
|
37
|
+
/** The verified share capability that submitted the message. */
|
|
38
|
+
readonly capabilityId: Schema.String;
|
|
39
|
+
readonly text: Schema.String;
|
|
40
|
+
}>;
|
|
41
|
+
/**
|
|
42
|
+
* The value form of {@link Message}.
|
|
43
|
+
*
|
|
44
|
+
* @category models
|
|
45
|
+
* @since 0.1.0
|
|
46
|
+
*/
|
|
47
|
+
export type Message = typeof Message.Type;
|
|
48
|
+
/**
|
|
49
|
+
* One command applied to the branch document.
|
|
50
|
+
*
|
|
51
|
+
* @category models
|
|
52
|
+
* @since 0.1.0
|
|
53
|
+
*/
|
|
54
|
+
export declare const AppliedCommand: Schema.Struct<{
|
|
55
|
+
readonly seq: Schema.brand<Schema.Int, "@smthrs/journal/JournalEvent/Seq">;
|
|
56
|
+
readonly commandId: Schema.brand<Schema.NonEmptyString, "@smthrs/sync/BranchProtocol/CommandId">;
|
|
57
|
+
readonly participantId: Schema.brand<Schema.NonEmptyString, "@smthrs/sync/BranchProtocol/ParticipantId">;
|
|
58
|
+
/** The verified share capability that submitted the command. */
|
|
59
|
+
readonly capabilityId: Schema.String;
|
|
60
|
+
readonly name: Schema.NonEmptyString;
|
|
61
|
+
readonly args: Schema.String;
|
|
62
|
+
readonly target: Schema.String;
|
|
63
|
+
}>;
|
|
64
|
+
/**
|
|
65
|
+
* The value form of {@link AppliedCommand}.
|
|
66
|
+
*
|
|
67
|
+
* @category models
|
|
68
|
+
* @since 0.1.0
|
|
69
|
+
*/
|
|
70
|
+
export type AppliedCommand = typeof AppliedCommand.Type;
|
|
71
|
+
/**
|
|
72
|
+
* The current winning value of one durably edited shared field.
|
|
73
|
+
*
|
|
74
|
+
* @category models
|
|
75
|
+
* @since 0.1.0
|
|
76
|
+
*/
|
|
77
|
+
export declare const Field: Schema.Struct<{
|
|
78
|
+
readonly target: Schema.NonEmptyString;
|
|
79
|
+
readonly value: Schema.String;
|
|
80
|
+
readonly seq: Schema.brand<Schema.Int, "@smthrs/journal/JournalEvent/Seq">;
|
|
81
|
+
readonly participantId: Schema.brand<Schema.NonEmptyString, "@smthrs/sync/BranchProtocol/ParticipantId">;
|
|
82
|
+
/** The verified share capability that wrote the winning value. */
|
|
83
|
+
readonly capabilityId: Schema.String;
|
|
84
|
+
}>;
|
|
85
|
+
/**
|
|
86
|
+
* The value form of {@link Field}.
|
|
87
|
+
*
|
|
88
|
+
* @category models
|
|
89
|
+
* @since 0.1.0
|
|
90
|
+
*/
|
|
91
|
+
export type Field = typeof Field.Type;
|
|
92
|
+
/**
|
|
93
|
+
* The projected state of one branch document.
|
|
94
|
+
*
|
|
95
|
+
* `seq` is the highest journal sequence folded in and is exactly the cursor a
|
|
96
|
+
* client resumes from.
|
|
97
|
+
*
|
|
98
|
+
* @category models
|
|
99
|
+
* @since 0.1.0
|
|
100
|
+
*/
|
|
101
|
+
export declare const State: Schema.Struct<{
|
|
102
|
+
readonly branchId: Schema.brand<Schema.NonEmptyString, "@smthrs/sync/BranchProtocol/BranchId">;
|
|
103
|
+
readonly seq: Schema.Int;
|
|
104
|
+
readonly messages: Schema.$Array<Schema.Struct<{
|
|
105
|
+
readonly seq: Schema.brand<Schema.Int, "@smthrs/journal/JournalEvent/Seq">;
|
|
106
|
+
readonly commandId: Schema.brand<Schema.NonEmptyString, "@smthrs/sync/BranchProtocol/CommandId">;
|
|
107
|
+
readonly participantId: Schema.brand<Schema.NonEmptyString, "@smthrs/sync/BranchProtocol/ParticipantId">;
|
|
108
|
+
/** The verified share capability that submitted the message. */
|
|
109
|
+
readonly capabilityId: Schema.String;
|
|
110
|
+
readonly text: Schema.String;
|
|
111
|
+
}>>;
|
|
112
|
+
readonly commands: Schema.$Array<Schema.Struct<{
|
|
113
|
+
readonly seq: Schema.brand<Schema.Int, "@smthrs/journal/JournalEvent/Seq">;
|
|
114
|
+
readonly commandId: Schema.brand<Schema.NonEmptyString, "@smthrs/sync/BranchProtocol/CommandId">;
|
|
115
|
+
readonly participantId: Schema.brand<Schema.NonEmptyString, "@smthrs/sync/BranchProtocol/ParticipantId">;
|
|
116
|
+
/** The verified share capability that submitted the command. */
|
|
117
|
+
readonly capabilityId: Schema.String;
|
|
118
|
+
readonly name: Schema.NonEmptyString;
|
|
119
|
+
readonly args: Schema.String;
|
|
120
|
+
readonly target: Schema.String;
|
|
121
|
+
}>>;
|
|
122
|
+
readonly fields: Schema.$Array<Schema.Struct<{
|
|
123
|
+
readonly target: Schema.NonEmptyString;
|
|
124
|
+
readonly value: Schema.String;
|
|
125
|
+
readonly seq: Schema.brand<Schema.Int, "@smthrs/journal/JournalEvent/Seq">;
|
|
126
|
+
readonly participantId: Schema.brand<Schema.NonEmptyString, "@smthrs/sync/BranchProtocol/ParticipantId">;
|
|
127
|
+
/** The verified share capability that wrote the winning value. */
|
|
128
|
+
readonly capabilityId: Schema.String;
|
|
129
|
+
}>>;
|
|
130
|
+
}>;
|
|
131
|
+
/**
|
|
132
|
+
* The value form of {@link State}.
|
|
133
|
+
*
|
|
134
|
+
* @category models
|
|
135
|
+
* @since 0.1.0
|
|
136
|
+
*/
|
|
137
|
+
export type State = typeof State.Type;
|
|
138
|
+
/**
|
|
139
|
+
* The empty projection of a branch, whose cursor is "nothing applied".
|
|
140
|
+
*
|
|
141
|
+
* @category constructors
|
|
142
|
+
* @since 0.1.0
|
|
143
|
+
*/
|
|
144
|
+
export declare const empty: (branchId: BranchId) => State;
|
|
145
|
+
/**
|
|
146
|
+
* The conflict policy for two durable edits of the same field.
|
|
147
|
+
*
|
|
148
|
+
* Highest canonical sequence wins. Within a branch the sequence is a total
|
|
149
|
+
* order assigned by the journal, so this is already decisive; the
|
|
150
|
+
* lexicographic `participantId` tie-break exists so the policy stays total if
|
|
151
|
+
* a future deployment ever merges two sequence domains. It is deliberately not
|
|
152
|
+
* wall-clock based — client clocks disagree, and a merge rule that depends on
|
|
153
|
+
* them is not deterministic.
|
|
154
|
+
*
|
|
155
|
+
* @category combinators
|
|
156
|
+
* @since 0.1.0
|
|
157
|
+
*/
|
|
158
|
+
export declare const resolveField: (existing: Field | undefined, candidate: Field) => Field;
|
|
159
|
+
/**
|
|
160
|
+
* Folds one journal entry into a branch projection.
|
|
161
|
+
*
|
|
162
|
+
* Redelivery and out-of-order delivery are told apart by identity, not by
|
|
163
|
+
* position: the cursor tip redelivered and a command id already applied are
|
|
164
|
+
* no-ops, while a below-cursor entry never applied is folded into canonical
|
|
165
|
+
* order. Non-command entries only raise the cursor, so re-applying one is
|
|
166
|
+
* idempotent by construction.
|
|
167
|
+
*
|
|
168
|
+
* @category combinators
|
|
169
|
+
* @since 0.1.0
|
|
170
|
+
*/
|
|
171
|
+
export declare const apply: (state: State, entry: JournalEvent.Entry) => State;
|
|
172
|
+
/**
|
|
173
|
+
* Folds a whole entry stream into a branch projection.
|
|
174
|
+
*
|
|
175
|
+
* @category combinators
|
|
176
|
+
* @since 0.1.0
|
|
177
|
+
*/
|
|
178
|
+
export declare const project: (branchId: BranchId, entries: Iterable<JournalEvent.Entry>) => State;
|
|
179
|
+
//# sourceMappingURL=BranchProjection.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BranchProjection.d.ts","sourceRoot":"","sources":["../../src/BranchProjection.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,KAAK,YAAY,MAAM,8BAA8B,CAAA;AAG5D,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AACvC,OAAO,EACL,QAAQ,EAOT,MAAM,qBAAqB,CAAA;AAE5B;;;;;GAKG;AACH,eAAO,MAAM,OAAO;;;;IAIlB,gEAAgE;;;EAGhE,CAAA;AACF;;;;;GAKG;AACH,MAAM,MAAM,OAAO,GAAG,OAAO,OAAO,CAAC,IAAI,CAAA;AAEzC;;;;;GAKG;AACH,eAAO,MAAM,cAAc;;;;IAIzB,gEAAgE;;;;;EAKhE,CAAA;AACF;;;;;GAKG;AACH,MAAM,MAAM,cAAc,GAAG,OAAO,cAAc,CAAC,IAAI,CAAA;AAEvD;;;;;GAKG;AACH,eAAO,MAAM,KAAK;;;;;IAKhB,kEAAkE;;EAElE,CAAA;AACF;;;;;GAKG;AACH,MAAM,MAAM,KAAK,GAAG,OAAO,KAAK,CAAC,IAAI,CAAA;AAErC;;;;;;;;GAQG;AACH,eAAO,MAAM,KAAK;;;;;;;QAnEhB,gEAAgE;;;;;;;;QAsBhE,gEAAgE;;;;;;;;;;;QAyBhE,kEAAkE;;;EA0BlE,CAAA;AACF;;;;;GAKG;AACH,MAAM,MAAM,KAAK,GAAG,OAAO,KAAK,CAAC,IAAI,CAAA;AAErC;;;;;GAKG;AACH,eAAO,MAAM,KAAK,GAAI,UAAU,QAAQ,KAAG,KAMzC,CAAA;AAEF;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,YAAY,GAAI,UAAU,KAAK,GAAG,SAAS,EAAE,WAAW,KAAK,KAAG,KAI5E,CAAA;AAwCD;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,KAAK,GAAI,OAAO,KAAK,EAAE,OAAO,YAAY,CAAC,KAAK,KAAG,KAuC/D,CAAA;AAED;;;;;GAKG;AACH,eAAO,MAAM,OAAO,GAAI,UAAU,QAAQ,EAAE,SAAS,QAAQ,CAAC,YAAY,CAAC,KAAK,CAAC,KAAG,KA+CnF,CAAA"}
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
var BranchProjection_exports = {};
|
|
30
|
+
__export(BranchProjection_exports, {
|
|
31
|
+
AppliedCommand: () => AppliedCommand,
|
|
32
|
+
Field: () => Field,
|
|
33
|
+
Message: () => Message,
|
|
34
|
+
State: () => State,
|
|
35
|
+
apply: () => apply,
|
|
36
|
+
empty: () => empty,
|
|
37
|
+
project: () => project,
|
|
38
|
+
resolveField: () => resolveField
|
|
39
|
+
});
|
|
40
|
+
module.exports = __toCommonJS(BranchProjection_exports);
|
|
41
|
+
var JournalEvent = __toESM(require("@smthrs/journal/JournalEvent"), 1);
|
|
42
|
+
var HashSet = __toESM(require("effect/HashSet"), 1);
|
|
43
|
+
var Option = __toESM(require("effect/Option"), 1);
|
|
44
|
+
var Schema = __toESM(require("effect/Schema"), 1);
|
|
45
|
+
var import_BranchProtocol = require("./BranchProtocol.js");
|
|
46
|
+
const Message = Schema.Struct({
|
|
47
|
+
seq: JournalEvent.Seq,
|
|
48
|
+
commandId: import_BranchProtocol.CommandId,
|
|
49
|
+
participantId: import_BranchProtocol.ParticipantId,
|
|
50
|
+
/** The verified share capability that submitted the message. */
|
|
51
|
+
capabilityId: Schema.String,
|
|
52
|
+
text: Schema.String
|
|
53
|
+
});
|
|
54
|
+
const AppliedCommand = Schema.Struct({
|
|
55
|
+
seq: JournalEvent.Seq,
|
|
56
|
+
commandId: import_BranchProtocol.CommandId,
|
|
57
|
+
participantId: import_BranchProtocol.ParticipantId,
|
|
58
|
+
/** The verified share capability that submitted the command. */
|
|
59
|
+
capabilityId: Schema.String,
|
|
60
|
+
name: Schema.NonEmptyString,
|
|
61
|
+
args: Schema.String,
|
|
62
|
+
target: Schema.String
|
|
63
|
+
});
|
|
64
|
+
const Field = Schema.Struct({
|
|
65
|
+
target: Schema.NonEmptyString,
|
|
66
|
+
value: Schema.String,
|
|
67
|
+
seq: JournalEvent.Seq,
|
|
68
|
+
participantId: import_BranchProtocol.ParticipantId,
|
|
69
|
+
/** The verified share capability that wrote the winning value. */
|
|
70
|
+
capabilityId: Schema.String
|
|
71
|
+
});
|
|
72
|
+
const State = Schema.Struct({
|
|
73
|
+
branchId: import_BranchProtocol.BranchId,
|
|
74
|
+
seq: Schema.Int.check(Schema.isGreaterThanOrEqualTo(-1)),
|
|
75
|
+
messages: Schema.Array(Message),
|
|
76
|
+
commands: Schema.Array(AppliedCommand),
|
|
77
|
+
fields: Schema.Array(Field)
|
|
78
|
+
});
|
|
79
|
+
const empty = (branchId) => ({
|
|
80
|
+
branchId,
|
|
81
|
+
seq: -1,
|
|
82
|
+
messages: [],
|
|
83
|
+
commands: [],
|
|
84
|
+
fields: []
|
|
85
|
+
});
|
|
86
|
+
const resolveField = (existing, candidate) => {
|
|
87
|
+
if (existing === void 0) return candidate;
|
|
88
|
+
if (candidate.seq !== existing.seq) return candidate.seq > existing.seq ? candidate : existing;
|
|
89
|
+
return candidate.participantId > existing.participantId ? candidate : existing;
|
|
90
|
+
};
|
|
91
|
+
const insertBySeq = (items, item) => {
|
|
92
|
+
const last = items[items.length - 1];
|
|
93
|
+
if (last === void 0 || last.seq <= item.seq) return [...items, item];
|
|
94
|
+
let low = 0;
|
|
95
|
+
let high = items.length;
|
|
96
|
+
while (low < high) {
|
|
97
|
+
const middle = Math.floor((low + high) / 2);
|
|
98
|
+
if (items[middle].seq <= item.seq) low = middle + 1;
|
|
99
|
+
else high = middle;
|
|
100
|
+
}
|
|
101
|
+
const result = items.slice();
|
|
102
|
+
result.splice(low, 0, item);
|
|
103
|
+
return result;
|
|
104
|
+
};
|
|
105
|
+
const commandIds = /* @__PURE__ */ new WeakMap();
|
|
106
|
+
const indexCommands = (commands) => {
|
|
107
|
+
const cached = commandIds.get(commands);
|
|
108
|
+
if (cached !== void 0) return cached;
|
|
109
|
+
const index = HashSet.fromIterable(commands.map((command) => command.commandId));
|
|
110
|
+
commandIds.set(commands, index);
|
|
111
|
+
return index;
|
|
112
|
+
};
|
|
113
|
+
const decodeCommand = Schema.decodeUnknownOption(import_BranchProtocol.CommandEventPayload);
|
|
114
|
+
const apply = (state, entry) => {
|
|
115
|
+
if (entry.runId !== (0, import_BranchProtocol.branchRunId)(state.branchId) || entry.seq === state.seq) return state;
|
|
116
|
+
const advanced = entry.seq < state.seq ? state : { ...state, seq: entry.seq };
|
|
117
|
+
if (entry.eventType !== import_BranchProtocol.CommandEvent) return advanced;
|
|
118
|
+
const decoded = decodeCommand(entry.payload);
|
|
119
|
+
if (Option.isNone(decoded)) return advanced;
|
|
120
|
+
const commandSubmission = decoded.value;
|
|
121
|
+
const ids = indexCommands(state.commands);
|
|
122
|
+
if (HashSet.has(ids, commandSubmission.commandId)) return advanced;
|
|
123
|
+
const command = { ...commandSubmission, seq: entry.seq };
|
|
124
|
+
const messages = commandSubmission.name === import_BranchProtocol.SayCommand ? insertBySeq(state.messages, {
|
|
125
|
+
seq: entry.seq,
|
|
126
|
+
commandId: commandSubmission.commandId,
|
|
127
|
+
participantId: commandSubmission.participantId,
|
|
128
|
+
capabilityId: commandSubmission.capabilityId,
|
|
129
|
+
text: commandSubmission.args
|
|
130
|
+
}) : state.messages;
|
|
131
|
+
const fields = commandSubmission.target === "" ? state.fields : (() => {
|
|
132
|
+
const candidate = {
|
|
133
|
+
target: commandSubmission.target,
|
|
134
|
+
value: commandSubmission.args,
|
|
135
|
+
seq: entry.seq,
|
|
136
|
+
participantId: commandSubmission.participantId,
|
|
137
|
+
capabilityId: commandSubmission.capabilityId
|
|
138
|
+
};
|
|
139
|
+
const winner = resolveField(
|
|
140
|
+
state.fields.find((field) => field.target === commandSubmission.target),
|
|
141
|
+
candidate
|
|
142
|
+
);
|
|
143
|
+
return [...state.fields.filter((field) => field.target !== commandSubmission.target), winner].sort((left, right) => left.target < right.target ? -1 : 1);
|
|
144
|
+
})();
|
|
145
|
+
const commands = insertBySeq(state.commands, command);
|
|
146
|
+
commandIds.set(commands, HashSet.add(ids, command.commandId));
|
|
147
|
+
return { ...advanced, messages, commands, fields };
|
|
148
|
+
};
|
|
149
|
+
const project = (branchId, entries) => {
|
|
150
|
+
const runId = (0, import_BranchProtocol.branchRunId)(branchId);
|
|
151
|
+
let seq = -1;
|
|
152
|
+
const ids = /* @__PURE__ */ new Set();
|
|
153
|
+
const commands = [];
|
|
154
|
+
const messages = [];
|
|
155
|
+
const fields = /* @__PURE__ */ new Map();
|
|
156
|
+
for (const entry of entries) {
|
|
157
|
+
if (entry.runId !== runId || entry.seq === seq) continue;
|
|
158
|
+
seq = Math.max(seq, entry.seq);
|
|
159
|
+
if (entry.eventType !== import_BranchProtocol.CommandEvent) continue;
|
|
160
|
+
const decoded = decodeCommand(entry.payload);
|
|
161
|
+
if (Option.isNone(decoded)) continue;
|
|
162
|
+
const submission = decoded.value;
|
|
163
|
+
if (ids.has(submission.commandId)) continue;
|
|
164
|
+
ids.add(submission.commandId);
|
|
165
|
+
commands.push({ ...submission, seq: entry.seq });
|
|
166
|
+
if (submission.name === import_BranchProtocol.SayCommand) {
|
|
167
|
+
messages.push({
|
|
168
|
+
seq: entry.seq,
|
|
169
|
+
commandId: submission.commandId,
|
|
170
|
+
participantId: submission.participantId,
|
|
171
|
+
capabilityId: submission.capabilityId,
|
|
172
|
+
text: submission.args
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
if (submission.target !== "") {
|
|
176
|
+
const candidate = {
|
|
177
|
+
target: submission.target,
|
|
178
|
+
value: submission.args,
|
|
179
|
+
seq: entry.seq,
|
|
180
|
+
participantId: submission.participantId,
|
|
181
|
+
capabilityId: submission.capabilityId
|
|
182
|
+
};
|
|
183
|
+
fields.set(submission.target, resolveField(fields.get(submission.target), candidate));
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
commands.sort((left, right) => left.seq - right.seq);
|
|
187
|
+
messages.sort((left, right) => left.seq - right.seq);
|
|
188
|
+
commandIds.set(commands, HashSet.fromIterable(ids));
|
|
189
|
+
return {
|
|
190
|
+
branchId,
|
|
191
|
+
seq,
|
|
192
|
+
commands,
|
|
193
|
+
messages,
|
|
194
|
+
fields: Array.from(fields.values()).sort((left, right) => left.target < right.target ? -1 : 1)
|
|
195
|
+
};
|
|
196
|
+
};
|
|
197
|
+
//# sourceMappingURL=BranchProjection.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/BranchProjection.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * The branch document projection: journal entries folded into what two people\n * looking at the same branch must agree on.\n *\n * The fold is order-independent over the canonical entry set, which is what\n * makes convergence a property rather than a hope: any two clients that have\n * applied the same set of entries hold the same state, regardless of the\n * order their transports delivered frames in or how many times a frame\n * arrived.\n *\n * Three guards do all the work, and each is a production invariant:\n *\n * - entries from another branch's run are ignored, so a mis-routed frame can\n * never leak into a projection;\n * - an entry already folded \u2014 the cursor tip redelivered, or a command id\n * already applied \u2014 is ignored, so an at-least-once transport cannot\n * double-apply a user action and a reconnect replays no side effects;\n * - an entry below the cursor whose command was never applied is folded into\n * its canonical `seq` position, so out-of-order delivery converges on the\n * same document instead of permanently dropping the late entry.\n *\n * @since 0.1.0\n */\n\nimport * as JournalEvent from \"@smthrs/journal/JournalEvent\"\nimport * as HashSet from \"effect/HashSet\"\nimport * as Option from \"effect/Option\"\nimport * as Schema from \"effect/Schema\"\nimport {\n BranchId,\n branchRunId,\n CommandEvent,\n CommandEventPayload,\n CommandId,\n ParticipantId,\n SayCommand\n} from \"./BranchProtocol.ts\"\n\n/**\n * One collaborative chat message in the branch timeline.\n *\n * @category models\n * @since 0.1.0\n */\nexport const Message = Schema.Struct({\n seq: JournalEvent.Seq,\n commandId: CommandId,\n participantId: ParticipantId,\n /** The verified share capability that submitted the message. */\n capabilityId: Schema.String,\n text: Schema.String\n})\n/**\n * The value form of {@link Message}.\n *\n * @category models\n * @since 0.1.0\n */\nexport type Message = typeof Message.Type\n\n/**\n * One command applied to the branch document.\n *\n * @category models\n * @since 0.1.0\n */\nexport const AppliedCommand = Schema.Struct({\n seq: JournalEvent.Seq,\n commandId: CommandId,\n participantId: ParticipantId,\n /** The verified share capability that submitted the command. */\n capabilityId: Schema.String,\n name: Schema.NonEmptyString,\n args: Schema.String,\n target: Schema.String\n})\n/**\n * The value form of {@link AppliedCommand}.\n *\n * @category models\n * @since 0.1.0\n */\nexport type AppliedCommand = typeof AppliedCommand.Type\n\n/**\n * The current winning value of one durably edited shared field.\n *\n * @category models\n * @since 0.1.0\n */\nexport const Field = Schema.Struct({\n target: Schema.NonEmptyString,\n value: Schema.String,\n seq: JournalEvent.Seq,\n participantId: ParticipantId,\n /** The verified share capability that wrote the winning value. */\n capabilityId: Schema.String\n})\n/**\n * The value form of {@link Field}.\n *\n * @category models\n * @since 0.1.0\n */\nexport type Field = typeof Field.Type\n\n/**\n * The projected state of one branch document.\n *\n * `seq` is the highest journal sequence folded in and is exactly the cursor a\n * client resumes from.\n *\n * @category models\n * @since 0.1.0\n */\nexport const State = Schema.Struct({\n branchId: BranchId,\n seq: Schema.Int.check(Schema.isGreaterThanOrEqualTo(-1)),\n messages: Schema.Array(Message),\n commands: Schema.Array(AppliedCommand),\n fields: Schema.Array(Field)\n})\n/**\n * The value form of {@link State}.\n *\n * @category models\n * @since 0.1.0\n */\nexport type State = typeof State.Type\n\n/**\n * The empty projection of a branch, whose cursor is \"nothing applied\".\n *\n * @category constructors\n * @since 0.1.0\n */\nexport const empty = (branchId: BranchId): State => ({\n branchId,\n seq: -1,\n messages: [],\n commands: [],\n fields: []\n})\n\n/**\n * The conflict policy for two durable edits of the same field.\n *\n * Highest canonical sequence wins. Within a branch the sequence is a total\n * order assigned by the journal, so this is already decisive; the\n * lexicographic `participantId` tie-break exists so the policy stays total if\n * a future deployment ever merges two sequence domains. It is deliberately not\n * wall-clock based \u2014 client clocks disagree, and a merge rule that depends on\n * them is not deterministic.\n *\n * @category combinators\n * @since 0.1.0\n */\nexport const resolveField = (existing: Field | undefined, candidate: Field): Field => {\n if (existing === undefined) return candidate\n if (candidate.seq !== existing.seq) return candidate.seq > existing.seq ? candidate : existing\n return candidate.participantId > existing.participantId ? candidate : existing\n}\n\n/**\n * Inserts one item into a sequence-ordered array at its canonical position.\n *\n * Canonical sequences are unique within a run, so an equal-sequence collision\n * is unrepresentable here: dedup happens before insertion.\n */\nconst insertBySeq = <Item extends { readonly seq: JournalEvent.Seq }>(\n items: ReadonlyArray<Item>,\n item: Item\n): Array<Item> => {\n const last = items[items.length - 1]\n if (last === undefined || last.seq <= item.seq) return [...items, item]\n let low = 0\n let high = items.length\n while (low < high) {\n const middle = Math.floor((low + high) / 2)\n if (items[middle]!.seq <= item.seq) low = middle + 1\n else high = middle\n }\n const result = items.slice()\n result.splice(low, 0, item)\n return result\n}\n\n// Cache by the immutable command array so cursor-only updates share the index.\n// Persistent sets let independent continuations share history without changing\n// an older state's deduplication. Restored states build their index on first use.\nconst commandIds = new WeakMap<ReadonlyArray<AppliedCommand>, HashSet.HashSet<CommandId>>()\nconst indexCommands = (commands: ReadonlyArray<AppliedCommand>): HashSet.HashSet<CommandId> => {\n const cached = commandIds.get(commands)\n if (cached !== undefined) return cached\n const index = HashSet.fromIterable(commands.map((command) => command.commandId))\n commandIds.set(commands, index)\n return index\n}\n\nconst decodeCommand = Schema.decodeUnknownOption(CommandEventPayload)\n\n/**\n * Folds one journal entry into a branch projection.\n *\n * Redelivery and out-of-order delivery are told apart by identity, not by\n * position: the cursor tip redelivered and a command id already applied are\n * no-ops, while a below-cursor entry never applied is folded into canonical\n * order. Non-command entries only raise the cursor, so re-applying one is\n * idempotent by construction.\n *\n * @category combinators\n * @since 0.1.0\n */\nexport const apply = (state: State, entry: JournalEvent.Entry): State => {\n if (entry.runId !== branchRunId(state.branchId) || entry.seq === state.seq) return state\n const advanced = entry.seq < state.seq ? state : { ...state, seq: entry.seq }\n if (entry.eventType !== CommandEvent) return advanced\n const decoded = decodeCommand(entry.payload)\n if (Option.isNone(decoded)) return advanced\n const commandSubmission = decoded.value\n const ids = indexCommands(state.commands)\n if (HashSet.has(ids, commandSubmission.commandId)) return advanced\n const command: AppliedCommand = { ...commandSubmission, seq: entry.seq }\n const messages = commandSubmission.name === SayCommand\n ? insertBySeq(state.messages, {\n seq: entry.seq,\n commandId: commandSubmission.commandId,\n participantId: commandSubmission.participantId,\n capabilityId: commandSubmission.capabilityId,\n text: commandSubmission.args\n })\n : state.messages\n const fields = commandSubmission.target === \"\"\n ? state.fields\n : (() => {\n const candidate: Field = {\n target: commandSubmission.target,\n value: commandSubmission.args,\n seq: entry.seq,\n participantId: commandSubmission.participantId,\n capabilityId: commandSubmission.capabilityId\n }\n const winner = resolveField(\n state.fields.find((field) => field.target === commandSubmission.target),\n candidate\n )\n return [...state.fields.filter((field) => field.target !== commandSubmission.target), winner]\n .sort((left, right) => left.target < right.target ? -1 : 1)\n })()\n const commands = insertBySeq(state.commands, command)\n commandIds.set(commands, HashSet.add(ids, command.commandId))\n return { ...advanced, messages, commands, fields }\n}\n\n/**\n * Folds a whole entry stream into a branch projection.\n *\n * @category combinators\n * @since 0.1.0\n */\nexport const project = (branchId: BranchId, entries: Iterable<JournalEvent.Entry>): State => {\n const runId = branchRunId(branchId)\n let seq = -1\n const ids = new Set<CommandId>()\n const commands: Array<AppliedCommand> = []\n const messages: Array<Message> = []\n const fields = new Map<string, Field>()\n for (const entry of entries) {\n if (entry.runId !== runId || entry.seq === seq) continue\n seq = Math.max(seq, entry.seq)\n if (entry.eventType !== CommandEvent) continue\n const decoded = decodeCommand(entry.payload)\n if (Option.isNone(decoded)) continue\n const submission = decoded.value\n if (ids.has(submission.commandId)) continue\n ids.add(submission.commandId)\n commands.push({ ...submission, seq: entry.seq })\n if (submission.name === SayCommand) {\n messages.push({\n seq: entry.seq,\n commandId: submission.commandId,\n participantId: submission.participantId,\n capabilityId: submission.capabilityId,\n text: submission.args\n })\n }\n if (submission.target !== \"\") {\n const candidate: Field = {\n target: submission.target,\n value: submission.args,\n seq: entry.seq,\n participantId: submission.participantId,\n capabilityId: submission.capabilityId\n }\n fields.set(submission.target, resolveField(fields.get(submission.target), candidate))\n }\n }\n commands.sort((left, right) => left.seq - right.seq)\n messages.sort((left, right) => left.seq - right.seq)\n commandIds.set(commands, HashSet.fromIterable(ids))\n return {\n branchId,\n seq,\n commands,\n messages,\n fields: Array.from(fields.values()).sort((left, right) => left.target < right.target ? -1 : 1)\n }\n}\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAwBA,mBAA8B;AAC9B,cAAyB;AACzB,aAAwB;AACxB,aAAwB;AACxB,4BAQO;AAQA,MAAM,UAAU,OAAO,OAAO;AAAA,EACnC,KAAK,aAAa;AAAA,EAClB,WAAW;AAAA,EACX,eAAe;AAAA;AAAA,EAEf,cAAc,OAAO;AAAA,EACrB,MAAM,OAAO;AACf,CAAC;AAeM,MAAM,iBAAiB,OAAO,OAAO;AAAA,EAC1C,KAAK,aAAa;AAAA,EAClB,WAAW;AAAA,EACX,eAAe;AAAA;AAAA,EAEf,cAAc,OAAO;AAAA,EACrB,MAAM,OAAO;AAAA,EACb,MAAM,OAAO;AAAA,EACb,QAAQ,OAAO;AACjB,CAAC;AAeM,MAAM,QAAQ,OAAO,OAAO;AAAA,EACjC,QAAQ,OAAO;AAAA,EACf,OAAO,OAAO;AAAA,EACd,KAAK,aAAa;AAAA,EAClB,eAAe;AAAA;AAAA,EAEf,cAAc,OAAO;AACvB,CAAC;AAkBM,MAAM,QAAQ,OAAO,OAAO;AAAA,EACjC,UAAU;AAAA,EACV,KAAK,OAAO,IAAI,MAAM,OAAO,uBAAuB,EAAE,CAAC;AAAA,EACvD,UAAU,OAAO,MAAM,OAAO;AAAA,EAC9B,UAAU,OAAO,MAAM,cAAc;AAAA,EACrC,QAAQ,OAAO,MAAM,KAAK;AAC5B,CAAC;AAeM,MAAM,QAAQ,CAAC,cAA+B;AAAA,EACnD;AAAA,EACA,KAAK;AAAA,EACL,UAAU,CAAC;AAAA,EACX,UAAU,CAAC;AAAA,EACX,QAAQ,CAAC;AACX;AAeO,MAAM,eAAe,CAAC,UAA6B,cAA4B;AACpF,MAAI,aAAa,OAAW,QAAO;AACnC,MAAI,UAAU,QAAQ,SAAS,IAAK,QAAO,UAAU,MAAM,SAAS,MAAM,YAAY;AACtF,SAAO,UAAU,gBAAgB,SAAS,gBAAgB,YAAY;AACxE;AAQA,MAAM,cAAc,CAClB,OACA,SACgB;AAChB,QAAM,OAAO,MAAM,MAAM,SAAS,CAAC;AACnC,MAAI,SAAS,UAAa,KAAK,OAAO,KAAK,IAAK,QAAO,CAAC,GAAG,OAAO,IAAI;AACtE,MAAI,MAAM;AACV,MAAI,OAAO,MAAM;AACjB,SAAO,MAAM,MAAM;AACjB,UAAM,SAAS,KAAK,OAAO,MAAM,QAAQ,CAAC;AAC1C,QAAI,MAAM,MAAM,EAAG,OAAO,KAAK,IAAK,OAAM,SAAS;AAAA,QAC9C,QAAO;AAAA,EACd;AACA,QAAM,SAAS,MAAM,MAAM;AAC3B,SAAO,OAAO,KAAK,GAAG,IAAI;AAC1B,SAAO;AACT;AAKA,MAAM,aAAa,oBAAI,QAAmE;AAC1F,MAAM,gBAAgB,CAAC,aAAwE;AAC7F,QAAM,SAAS,WAAW,IAAI,QAAQ;AACtC,MAAI,WAAW,OAAW,QAAO;AACjC,QAAM,QAAQ,QAAQ,aAAa,SAAS,IAAI,CAAC,YAAY,QAAQ,SAAS,CAAC;AAC/E,aAAW,IAAI,UAAU,KAAK;AAC9B,SAAO;AACT;AAEA,MAAM,gBAAgB,OAAO,oBAAoB,yCAAmB;AAc7D,MAAM,QAAQ,CAAC,OAAc,UAAqC;AACvE,MAAI,MAAM,cAAU,mCAAY,MAAM,QAAQ,KAAK,MAAM,QAAQ,MAAM,IAAK,QAAO;AACnF,QAAM,WAAW,MAAM,MAAM,MAAM,MAAM,QAAQ,EAAE,GAAG,OAAO,KAAK,MAAM,IAAI;AAC5E,MAAI,MAAM,cAAc,mCAAc,QAAO;AAC7C,QAAM,UAAU,cAAc,MAAM,OAAO;AAC3C,MAAI,OAAO,OAAO,OAAO,EAAG,QAAO;AACnC,QAAM,oBAAoB,QAAQ;AAClC,QAAM,MAAM,cAAc,MAAM,QAAQ;AACxC,MAAI,QAAQ,IAAI,KAAK,kBAAkB,SAAS,EAAG,QAAO;AAC1D,QAAM,UAA0B,EAAE,GAAG,mBAAmB,KAAK,MAAM,IAAI;AACvE,QAAM,WAAW,kBAAkB,SAAS,mCACxC,YAAY,MAAM,UAAU;AAAA,IAC5B,KAAK,MAAM;AAAA,IACX,WAAW,kBAAkB;AAAA,IAC7B,eAAe,kBAAkB;AAAA,IACjC,cAAc,kBAAkB;AAAA,IAChC,MAAM,kBAAkB;AAAA,EAC1B,CAAC,IACC,MAAM;AACV,QAAM,SAAS,kBAAkB,WAAW,KACxC,MAAM,UACL,MAAM;AACP,UAAM,YAAmB;AAAA,MACvB,QAAQ,kBAAkB;AAAA,MAC1B,OAAO,kBAAkB;AAAA,MACzB,KAAK,MAAM;AAAA,MACX,eAAe,kBAAkB;AAAA,MACjC,cAAc,kBAAkB;AAAA,IAClC;AACA,UAAM,SAAS;AAAA,MACb,MAAM,OAAO,KAAK,CAAC,UAAU,MAAM,WAAW,kBAAkB,MAAM;AAAA,MACtE;AAAA,IACF;AACA,WAAO,CAAC,GAAG,MAAM,OAAO,OAAO,CAAC,UAAU,MAAM,WAAW,kBAAkB,MAAM,GAAG,MAAM,EACzF,KAAK,CAAC,MAAM,UAAU,KAAK,SAAS,MAAM,SAAS,KAAK,CAAC;AAAA,EAC9D,GAAG;AACL,QAAM,WAAW,YAAY,MAAM,UAAU,OAAO;AACpD,aAAW,IAAI,UAAU,QAAQ,IAAI,KAAK,QAAQ,SAAS,CAAC;AAC5D,SAAO,EAAE,GAAG,UAAU,UAAU,UAAU,OAAO;AACnD;AAQO,MAAM,UAAU,CAAC,UAAoB,YAAiD;AAC3F,QAAM,YAAQ,mCAAY,QAAQ;AAClC,MAAI,MAAM;AACV,QAAM,MAAM,oBAAI,IAAe;AAC/B,QAAM,WAAkC,CAAC;AACzC,QAAM,WAA2B,CAAC;AAClC,QAAM,SAAS,oBAAI,IAAmB;AACtC,aAAW,SAAS,SAAS;AAC3B,QAAI,MAAM,UAAU,SAAS,MAAM,QAAQ,IAAK;AAChD,UAAM,KAAK,IAAI,KAAK,MAAM,GAAG;AAC7B,QAAI,MAAM,cAAc,mCAAc;AACtC,UAAM,UAAU,cAAc,MAAM,OAAO;AAC3C,QAAI,OAAO,OAAO,OAAO,EAAG;AAC5B,UAAM,aAAa,QAAQ;AAC3B,QAAI,IAAI,IAAI,WAAW,SAAS,EAAG;AACnC,QAAI,IAAI,WAAW,SAAS;AAC5B,aAAS,KAAK,EAAE,GAAG,YAAY,KAAK,MAAM,IAAI,CAAC;AAC/C,QAAI,WAAW,SAAS,kCAAY;AAClC,eAAS,KAAK;AAAA,QACZ,KAAK,MAAM;AAAA,QACX,WAAW,WAAW;AAAA,QACtB,eAAe,WAAW;AAAA,QAC1B,cAAc,WAAW;AAAA,QACzB,MAAM,WAAW;AAAA,MACnB,CAAC;AAAA,IACH;AACA,QAAI,WAAW,WAAW,IAAI;AAC5B,YAAM,YAAmB;AAAA,QACvB,QAAQ,WAAW;AAAA,QACnB,OAAO,WAAW;AAAA,QAClB,KAAK,MAAM;AAAA,QACX,eAAe,WAAW;AAAA,QAC1B,cAAc,WAAW;AAAA,MAC3B;AACA,aAAO,IAAI,WAAW,QAAQ,aAAa,OAAO,IAAI,WAAW,MAAM,GAAG,SAAS,CAAC;AAAA,IACtF;AAAA,EACF;AACA,WAAS,KAAK,CAAC,MAAM,UAAU,KAAK,MAAM,MAAM,GAAG;AACnD,WAAS,KAAK,CAAC,MAAM,UAAU,KAAK,MAAM,MAAM,GAAG;AACnD,aAAW,IAAI,UAAU,QAAQ,aAAa,GAAG,CAAC;AAClD,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,QAAQ,MAAM,KAAK,OAAO,OAAO,CAAC,EAAE,KAAK,CAAC,MAAM,UAAU,KAAK,SAAS,MAAM,SAAS,KAAK,CAAC;AAAA,EAC/F;AACF;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|