@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,119 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The sync read path's connection authentication: implementations of the
|
|
3
|
+
* `SyncRpcs.SyncAuth` RPC middleware.
|
|
4
|
+
*
|
|
5
|
+
* A connection presents a {@link WorkspaceShare.WorkspaceCapability} in the
|
|
6
|
+
* {@link capabilityHeader} request header. {@link layer} verifies it against
|
|
7
|
+
* the workspace's {@link WorkspaceShare.WorkspaceShare} authority and runs
|
|
8
|
+
* the handler as the workspace principal. A request with no header runs as
|
|
9
|
+
* the anonymous principal — branch share capabilities carried in request
|
|
10
|
+
* payloads still authorize branch reads — and the server refuses anonymous
|
|
11
|
+
* access to every non-branch run. A request whose header is present but
|
|
12
|
+
* malformed, forged, expired, or signed by an unknown key is refused
|
|
13
|
+
* outright: presence of a credential is a claim, and a false claim is never
|
|
14
|
+
* downgraded to anonymity.
|
|
15
|
+
*
|
|
16
|
+
* There is deliberately no trusted pass-through implementation here: the only
|
|
17
|
+
* sanctioned bypass is an in-process caller providing `SyncPrincipal` itself,
|
|
18
|
+
* never a transport.
|
|
19
|
+
*
|
|
20
|
+
* @since 0.1.0
|
|
21
|
+
*/
|
|
22
|
+
import * as Effect from "effect/Effect";
|
|
23
|
+
import * as Encoding from "effect/Encoding";
|
|
24
|
+
import * as Layer from "effect/Layer";
|
|
25
|
+
import * as Result from "effect/Result";
|
|
26
|
+
import * as Schema from "effect/Schema";
|
|
27
|
+
import * as Headers from "effect/unstable/http/Headers";
|
|
28
|
+
import * as RpcMiddleware from "effect/unstable/rpc/RpcMiddleware";
|
|
29
|
+
import { causeText } from "./internal/CauseText.js";
|
|
30
|
+
import * as shareSigner from "./internal/ShareSigner.js";
|
|
31
|
+
import { SyncError } from "./SyncError.js";
|
|
32
|
+
import * as SyncPrincipal from "./SyncPrincipal.js";
|
|
33
|
+
import { SyncAuth } from "./SyncRpcs.js";
|
|
34
|
+
import * as WorkspaceShare from "./WorkspaceShare.js";
|
|
35
|
+
/**
|
|
36
|
+
* The request header a connection presents its workspace capability in.
|
|
37
|
+
*
|
|
38
|
+
* @category constants
|
|
39
|
+
* @since 0.1.0
|
|
40
|
+
*/
|
|
41
|
+
export const capabilityHeader = "flows-sync-workspace";
|
|
42
|
+
const denied = shareSigner.unauthorized;
|
|
43
|
+
/**
|
|
44
|
+
* Renders a workspace capability as its header value: unpadded base64url of
|
|
45
|
+
* the schema-encoded capability JSON.
|
|
46
|
+
*
|
|
47
|
+
* @category encoding
|
|
48
|
+
* @since 0.1.0
|
|
49
|
+
*/
|
|
50
|
+
export const encodeCapability = (capability) => {
|
|
51
|
+
const encoded = Schema.encodeUnknownResult(WorkspaceShare.WorkspaceCapability)(capability);
|
|
52
|
+
return Result.isFailure(encoded)
|
|
53
|
+
? Effect.fail(new SyncError({
|
|
54
|
+
code: "invalid_request",
|
|
55
|
+
message: "The workspace capability does not encode",
|
|
56
|
+
// The rendering, never the parse failure itself: a schema issue
|
|
57
|
+
// carries the value it rejected, and the value here is a credential.
|
|
58
|
+
cause: causeText(encoded.failure)
|
|
59
|
+
}))
|
|
60
|
+
: Effect.succeed(Encoding.encodeBase64Url(JSON.stringify(encoded.success)));
|
|
61
|
+
};
|
|
62
|
+
/**
|
|
63
|
+
* Decodes a capability header value. Every malformation folds to the same
|
|
64
|
+
* `unauthorized` refusal so the header is not a parsing oracle.
|
|
65
|
+
*
|
|
66
|
+
* @category encoding
|
|
67
|
+
* @since 0.1.0
|
|
68
|
+
*/
|
|
69
|
+
export const decodeCapability = (value) => {
|
|
70
|
+
const text = Encoding.decodeBase64UrlString(value);
|
|
71
|
+
if (Result.isFailure(text)) {
|
|
72
|
+
return Effect.fail(denied("The workspace capability header is not a capability"));
|
|
73
|
+
}
|
|
74
|
+
let parsed;
|
|
75
|
+
try {
|
|
76
|
+
parsed = JSON.parse(text.success);
|
|
77
|
+
}
|
|
78
|
+
catch {
|
|
79
|
+
return Effect.fail(denied("The workspace capability header is not a capability"));
|
|
80
|
+
}
|
|
81
|
+
const decoded = Schema.decodeUnknownResult(WorkspaceShare.WorkspaceCapability)(parsed);
|
|
82
|
+
return Result.isFailure(decoded)
|
|
83
|
+
? Effect.fail(denied("The workspace capability header is not a capability"))
|
|
84
|
+
: Effect.succeed(decoded.success);
|
|
85
|
+
};
|
|
86
|
+
/**
|
|
87
|
+
* Provides the workspace-capability authentication middleware: no header
|
|
88
|
+
* runs the handler as anonymous, a verified header runs it as the workspace
|
|
89
|
+
* principal, and anything else refuses the request. Verification faults
|
|
90
|
+
* (Web Crypto failing) propagate as their own error rather than as a
|
|
91
|
+
* refusal.
|
|
92
|
+
*
|
|
93
|
+
* @category layers
|
|
94
|
+
* @since 0.1.0
|
|
95
|
+
*/
|
|
96
|
+
export const layer = Layer.effect(SyncAuth, Effect.gen(function* () {
|
|
97
|
+
const share = yield* WorkspaceShare.WorkspaceShare;
|
|
98
|
+
const middleware = (effect, options) => {
|
|
99
|
+
const header = Headers.get(options.headers, capabilityHeader);
|
|
100
|
+
if (header._tag === "None") {
|
|
101
|
+
return Effect.provideService(effect, SyncPrincipal.SyncPrincipal, SyncPrincipal.anonymous);
|
|
102
|
+
}
|
|
103
|
+
return decodeCapability(header.value).pipe(Effect.flatMap((capability) => share.verify(capability, { access: "read" })), Effect.flatMap((claims) => Effect.provideService(effect, SyncPrincipal.SyncPrincipal,
|
|
104
|
+
// The signed expiry travels WITH the identity. A handler that
|
|
105
|
+
// opens a stream authorizes once; reducing the verified claims to
|
|
106
|
+
// a capability id here left the stream with nothing to expire on.
|
|
107
|
+
SyncPrincipal.workspace(claims.capabilityId, claims.expiresAtMs))));
|
|
108
|
+
};
|
|
109
|
+
return middleware;
|
|
110
|
+
}));
|
|
111
|
+
/**
|
|
112
|
+
* Stamps every outgoing request from a generated RPC client with the given
|
|
113
|
+
* workspace capability.
|
|
114
|
+
*
|
|
115
|
+
* @category layers
|
|
116
|
+
* @since 0.1.0
|
|
117
|
+
*/
|
|
118
|
+
export const layerClient = (capability) => RpcMiddleware.layerClient(SyncAuth, Effect.map(encodeCapability(capability), (header) => ({ next, request }) => next({ ...request, headers: Headers.set(request.headers, capabilityHeader, header) })));
|
|
119
|
+
//# sourceMappingURL=SyncAuth.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SyncAuth.js","sourceRoot":"","sources":["../../src/SyncAuth.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The sync read path's connection authentication: implementations of the\n * `SyncRpcs.SyncAuth` RPC middleware.\n *\n * A connection presents a {@link WorkspaceShare.WorkspaceCapability} in the\n * {@link capabilityHeader} request header. {@link layer} verifies it against\n * the workspace's {@link WorkspaceShare.WorkspaceShare} authority and runs\n * the handler as the workspace principal. A request with no header runs as\n * the anonymous principal — branch share capabilities carried in request\n * payloads still authorize branch reads — and the server refuses anonymous\n * access to every non-branch run. A request whose header is present but\n * malformed, forged, expired, or signed by an unknown key is refused\n * outright: presence of a credential is a claim, and a false claim is never\n * downgraded to anonymity.\n *\n * There is deliberately no trusted pass-through implementation here: the only\n * sanctioned bypass is an in-process caller providing `SyncPrincipal` itself,\n * never a transport.\n *\n * @since 0.1.0\n */\n\nimport * as Effect from \"effect/Effect\"\nimport * as Encoding from \"effect/Encoding\"\nimport * as Layer from \"effect/Layer\"\nimport * as Result from \"effect/Result\"\nimport * as Schema from \"effect/Schema\"\nimport * as Headers from \"effect/unstable/http/Headers\"\nimport * as RpcMiddleware from \"effect/unstable/rpc/RpcMiddleware\"\nimport { causeText } from \"./internal/CauseText.ts\"\nimport * as shareSigner from \"./internal/ShareSigner.ts\"\nimport { SyncError } from \"./SyncError.ts\"\nimport * as SyncPrincipal from \"./SyncPrincipal.ts\"\nimport { SyncAuth } from \"./SyncRpcs.ts\"\nimport * as WorkspaceShare from \"./WorkspaceShare.ts\"\n\n/**\n * The request header a connection presents its workspace capability in.\n *\n * @category constants\n * @since 0.1.0\n */\nexport const capabilityHeader = \"flows-sync-workspace\"\n\nconst denied = shareSigner.unauthorized\n\n/**\n * Renders a workspace capability as its header value: unpadded base64url of\n * the schema-encoded capability JSON.\n *\n * @category encoding\n * @since 0.1.0\n */\nexport const encodeCapability = (\n capability: WorkspaceShare.WorkspaceCapability\n): Effect.Effect<string, SyncError> => {\n const encoded = Schema.encodeUnknownResult(WorkspaceShare.WorkspaceCapability)(capability)\n return Result.isFailure(encoded)\n ? Effect.fail(\n new SyncError({\n code: \"invalid_request\",\n message: \"The workspace capability does not encode\",\n // The rendering, never the parse failure itself: a schema issue\n // carries the value it rejected, and the value here is a credential.\n cause: causeText(encoded.failure)\n })\n )\n : Effect.succeed(Encoding.encodeBase64Url(JSON.stringify(encoded.success)))\n}\n\n/**\n * Decodes a capability header value. Every malformation folds to the same\n * `unauthorized` refusal so the header is not a parsing oracle.\n *\n * @category encoding\n * @since 0.1.0\n */\nexport const decodeCapability = (value: string): Effect.Effect<WorkspaceShare.WorkspaceCapability, SyncError> => {\n const text = Encoding.decodeBase64UrlString(value)\n if (Result.isFailure(text)) {\n return Effect.fail(denied(\"The workspace capability header is not a capability\"))\n }\n let parsed: unknown\n try {\n parsed = JSON.parse(text.success)\n } catch {\n return Effect.fail(denied(\"The workspace capability header is not a capability\"))\n }\n const decoded = Schema.decodeUnknownResult(WorkspaceShare.WorkspaceCapability)(parsed)\n return Result.isFailure(decoded)\n ? Effect.fail(denied(\"The workspace capability header is not a capability\"))\n : Effect.succeed(decoded.success)\n}\n\n/**\n * Provides the workspace-capability authentication middleware: no header\n * runs the handler as anonymous, a verified header runs it as the workspace\n * principal, and anything else refuses the request. Verification faults\n * (Web Crypto failing) propagate as their own error rather than as a\n * refusal.\n *\n * @category layers\n * @since 0.1.0\n */\nexport const layer: Layer.Layer<SyncAuth, never, WorkspaceShare.WorkspaceShare> = Layer.effect(\n SyncAuth,\n Effect.gen(function*() {\n const share = yield* WorkspaceShare.WorkspaceShare\n const middleware: RpcMiddleware.RpcMiddleware<never, SyncError, never> = (effect, options) => {\n const header = Headers.get(options.headers, capabilityHeader)\n if (header._tag === \"None\") {\n return Effect.provideService(effect, SyncPrincipal.SyncPrincipal, SyncPrincipal.anonymous)\n }\n return decodeCapability(header.value).pipe(\n Effect.flatMap((capability) => share.verify(capability, { access: \"read\" })),\n Effect.flatMap((claims) =>\n Effect.provideService(\n effect,\n SyncPrincipal.SyncPrincipal,\n // The signed expiry travels WITH the identity. A handler that\n // opens a stream authorizes once; reducing the verified claims to\n // a capability id here left the stream with nothing to expire on.\n SyncPrincipal.workspace(claims.capabilityId, claims.expiresAtMs)\n )\n )\n )\n }\n return middleware\n })\n)\n\n/**\n * Stamps every outgoing request from a generated RPC client with the given\n * workspace capability.\n *\n * @category layers\n * @since 0.1.0\n */\nexport const layerClient = (\n capability: WorkspaceShare.WorkspaceCapability\n): Layer.Layer<RpcMiddleware.ForClient<SyncAuth>, SyncError> =>\n RpcMiddleware.layerClient(\n SyncAuth,\n Effect.map(encodeCapability(capability), (header) => ({ next, request }) =>\n next({ ...request, headers: Headers.set(request.headers, capabilityHeader, header) }))\n )\n"]}
|
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Browser-safe client for replaying and following journal entries.
|
|
3
|
+
*
|
|
4
|
+
* @since 0.1.0
|
|
5
|
+
*/
|
|
6
|
+
import type * as JournalEvent from "@smthrs/journal/JournalEvent";
|
|
7
|
+
import * as Context from "effect/Context";
|
|
8
|
+
import * as Effect from "effect/Effect";
|
|
9
|
+
import * as Layer from "effect/Layer";
|
|
10
|
+
import * as Stream from "effect/Stream";
|
|
11
|
+
import * as RpcClient from "effect/unstable/rpc/RpcClient";
|
|
12
|
+
import * as RpcClientError from "effect/unstable/rpc/RpcClientError";
|
|
13
|
+
import type * as RpcGroup from "effect/unstable/rpc/RpcGroup";
|
|
14
|
+
import type { ShareCapability } from "./BranchProtocol.ts";
|
|
15
|
+
import { SyncError, SyncGapError } from "./SyncError.ts";
|
|
16
|
+
import { type Progress, type Resync, RunCursor, type Scope, type Snapshot, type SnapshotRequest, type WorkspaceCursor } from "./SyncProtocol.ts";
|
|
17
|
+
import { SyncRpcs } from "./SyncRpcs.ts";
|
|
18
|
+
/**
|
|
19
|
+
* Frames one subscription round may carry before the follow replenishes it.
|
|
20
|
+
*
|
|
21
|
+
* A subscription's `credit` is a hard frame limit the server enforces with
|
|
22
|
+
* `Stream.take`, so the number the client sends is the size of its window, not
|
|
23
|
+
* a hint. At `credit: 1` the window closed after every single entry and the
|
|
24
|
+
* follow resubscribed: following a run that emits a hundred entries cost a
|
|
25
|
+
* hundred subscribe round trips, each of them a fresh cursor snapshot and a
|
|
26
|
+
* fresh server-side fan-out. Replenishing 256 frames at a time makes the
|
|
27
|
+
* round-trip cost proportional to the window rather than to the traffic, and
|
|
28
|
+
* keeps it bounded — an unbounded window would hand the server one
|
|
29
|
+
* never-closing subscription per follower.
|
|
30
|
+
*
|
|
31
|
+
* @category constants
|
|
32
|
+
* @since 0.1.0
|
|
33
|
+
*/
|
|
34
|
+
export declare const defaultCredit = 256;
|
|
35
|
+
/**
|
|
36
|
+
* Entries one catch-up page asks for.
|
|
37
|
+
*
|
|
38
|
+
* Bootstrap is the replay half of replay-then-follow, so the page size is the
|
|
39
|
+
* memory one catch-up costs and the granularity at which its cursor advances.
|
|
40
|
+
* It matches {@link defaultCredit} and stays under
|
|
41
|
+
* `SyncProtocol.maxReadLimit`, which is the ceiling the server enforces.
|
|
42
|
+
*
|
|
43
|
+
* @category constants
|
|
44
|
+
* @since 1.0.0-rc.0
|
|
45
|
+
*/
|
|
46
|
+
export declare const defaultBootstrapLimit = 256;
|
|
47
|
+
/**
|
|
48
|
+
* The policy one sync client runs every operation under.
|
|
49
|
+
*
|
|
50
|
+
* Both fields are validated by {@link makeWith} and {@link layerWith}, so a
|
|
51
|
+
* value that is not a positive safe integer fails the constructor rather than
|
|
52
|
+
* disabling the bound it configures.
|
|
53
|
+
*
|
|
54
|
+
* @category models
|
|
55
|
+
* @since 1.0.0-rc.0
|
|
56
|
+
*/
|
|
57
|
+
export interface Options {
|
|
58
|
+
/**
|
|
59
|
+
* Largest summed encoded-entry size one frame or bootstrap page may carry,
|
|
60
|
+
* in bytes. Defaults to {@link defaultMaxFrameBytes}.
|
|
61
|
+
*/
|
|
62
|
+
readonly maxFrameBytes?: number | undefined;
|
|
63
|
+
/**
|
|
64
|
+
* Entries one catch-up page asks for. Defaults to
|
|
65
|
+
* {@link defaultBootstrapLimit}, and may not exceed
|
|
66
|
+
* `SyncProtocol.maxReadLimit`.
|
|
67
|
+
*/
|
|
68
|
+
readonly bootstrapLimit?: number | undefined;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Input accepted by a sync subscription.
|
|
72
|
+
*
|
|
73
|
+
* `capability` authorizes branch reads: following a shared branch's run
|
|
74
|
+
* requires a capability that verifies for that branch on the server.
|
|
75
|
+
*
|
|
76
|
+
* `EApply` and `EResync` are the consumer's own failure types for `apply` and
|
|
77
|
+
* `onResync`. The subscription fails with them unchanged, so an application
|
|
78
|
+
* failure is never dressed as a transport or protocol {@link SyncError}.
|
|
79
|
+
*
|
|
80
|
+
* @category models
|
|
81
|
+
* @since 0.1.0
|
|
82
|
+
*/
|
|
83
|
+
export interface SubscribeOptions<EApply = never, EResync = never> {
|
|
84
|
+
readonly scope: Scope;
|
|
85
|
+
/**
|
|
86
|
+
* Where this subscription starts, per run. The effective position is the
|
|
87
|
+
* LATER of this and the client's matching progress map (applied when an
|
|
88
|
+
* apply callback is present, delivered otherwise), so a caller
|
|
89
|
+
* ahead of the shared view keeps its place and a caller behind it is
|
|
90
|
+
* fast-forwarded. Rebuild from an earlier position with a fresh client.
|
|
91
|
+
*/
|
|
92
|
+
readonly cursors: WorkspaceCursor;
|
|
93
|
+
readonly capability?: ShareCapability;
|
|
94
|
+
/**
|
|
95
|
+
* Frames one subscription round may carry before the follow replenishes the
|
|
96
|
+
* window. Defaults to {@link defaultCredit}, and must be a positive integer
|
|
97
|
+
* no greater than `SyncProtocol.maxSubscribeCredit`.
|
|
98
|
+
*/
|
|
99
|
+
readonly credit?: number | undefined;
|
|
100
|
+
/**
|
|
101
|
+
* Applies one entry, and DEFINES what this subscription's cursor means.
|
|
102
|
+
*
|
|
103
|
+
* Without it the cursor advances as each entry is handed to the consumer,
|
|
104
|
+
* so a consumer whose own application then fails has a cursor naming an
|
|
105
|
+
* entry it never materialized. With it the cursor advances only after this
|
|
106
|
+
* effect succeeds, and records it in `Progress.applied`. A failure here
|
|
107
|
+
* fails the subscription with the entry unacknowledged, so the
|
|
108
|
+
* next applying subscription delivers it again; the effect must
|
|
109
|
+
* therefore be idempotent, because a redelivery is exactly what a retry is.
|
|
110
|
+
*/
|
|
111
|
+
readonly apply?: ((entry: JournalEvent.Entry) => Effect.Effect<void, EApply>) | undefined;
|
|
112
|
+
/**
|
|
113
|
+
* Restores state when the server refuses a cursor below a compaction floor.
|
|
114
|
+
* Return the exact run and sequence actually restored, after applying it.
|
|
115
|
+
*
|
|
116
|
+
* The entries under the floor are deleted. Fetch an explicitly public
|
|
117
|
+
* projection through `snapshot` or an authorized local source; a
|
|
118
|
+
* projection has a real hole to fill. The returned sequence must cover the
|
|
119
|
+
* requested floor; a newer snapshot resumes at its own sequence, not the
|
|
120
|
+
* older floor. Missing handlers, failures, interruption, and invalid receipts
|
|
121
|
+
* leave the cursor unmoved. There is no implicit skip of deleted history.
|
|
122
|
+
*
|
|
123
|
+
* Durable consumers must commit their restored state and durable cursor in
|
|
124
|
+
* their own transaction and seed a fresh client from that cursor on restart.
|
|
125
|
+
* This client's cursor is in memory, not an atomic cross-store transaction.
|
|
126
|
+
* Recovery must be idempotent, including when a newer compaction requires
|
|
127
|
+
* another restoration before the suffix can be read.
|
|
128
|
+
*/
|
|
129
|
+
readonly onResync?: ((resync: Resync) => Effect.Effect<RunCursor, EResync>) | undefined;
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Replicated journal subscription operations.
|
|
133
|
+
*
|
|
134
|
+
* @category models
|
|
135
|
+
* @since 0.1.0
|
|
136
|
+
*/
|
|
137
|
+
export interface Service {
|
|
138
|
+
/** Fetches a public snapshot without applying state or advancing a cursor. */
|
|
139
|
+
readonly snapshot: (request: SnapshotRequest) => Effect.Effect<Snapshot, SyncError>;
|
|
140
|
+
/** Replays then follows `options.scope`, also failing with the callbacks' own errors. */
|
|
141
|
+
readonly subscribe: <EApply = never, EResync = never>(options: SubscribeOptions<EApply, EResync>) => Stream.Stream<JournalEvent.Entry, SyncError | SyncGapError | EApply | EResync>;
|
|
142
|
+
/**
|
|
143
|
+
* Delivery and application positions. `delivered` is a transport bookmark
|
|
144
|
+
* only; `applied` is what the `apply` and `onResync` callbacks acknowledged.
|
|
145
|
+
*/
|
|
146
|
+
readonly progress: Effect.Effect<Progress>;
|
|
147
|
+
}
|
|
148
|
+
declare const SyncClient_base: Context.ServiceClass<SyncClient, "@smthrs/sync/SyncClient", Service>;
|
|
149
|
+
/**
|
|
150
|
+
* The browser-safe journal replication client.
|
|
151
|
+
*
|
|
152
|
+
* @category services
|
|
153
|
+
* @since 1.0.0-rc.0
|
|
154
|
+
*/
|
|
155
|
+
export declare class SyncClient extends SyncClient_base {
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* The client tag's former name, kept for one release.
|
|
159
|
+
*
|
|
160
|
+
* @deprecated Use {@link SyncClient}.
|
|
161
|
+
* @category services
|
|
162
|
+
* @since 0.1.0
|
|
163
|
+
*/
|
|
164
|
+
export declare const Sync: typeof SyncClient;
|
|
165
|
+
/**
|
|
166
|
+
* The client tag's former name, kept for one release.
|
|
167
|
+
*
|
|
168
|
+
* @deprecated Use {@link SyncClient}.
|
|
169
|
+
* @category services
|
|
170
|
+
* @since 0.1.0
|
|
171
|
+
*/
|
|
172
|
+
export type Sync = SyncClient;
|
|
173
|
+
/**
|
|
174
|
+
* Constructs a closed sync stub, optionally overriding individual operations.
|
|
175
|
+
*
|
|
176
|
+
* @category constructors
|
|
177
|
+
* @since 0.1.0
|
|
178
|
+
*/
|
|
179
|
+
export declare const makeNoop: (overrides?: Partial<Service>) => Service;
|
|
180
|
+
/**
|
|
181
|
+
* Provides a closed sync stub.
|
|
182
|
+
*
|
|
183
|
+
* @category layers
|
|
184
|
+
* @since 0.1.0
|
|
185
|
+
*/
|
|
186
|
+
export declare const layerNoop: (overrides?: Partial<Service>) => Layer.Layer<SyncClient>;
|
|
187
|
+
type Client = RpcClient.RpcClient<RpcGroup.Rpcs<typeof SyncRpcs>, RpcClientError.RpcClientError>;
|
|
188
|
+
/**
|
|
189
|
+
* Projects a Sync RPC client into the local replication service.
|
|
190
|
+
*
|
|
191
|
+
* Delivered and applied cursors are separate per-service `Ref` maps: concurrent
|
|
192
|
+
* subscriptions for one materialization share them, and each commit advances
|
|
193
|
+
* its matching map monotonically. A
|
|
194
|
+
* cursor advances in the same stream pull that admits each entry to the
|
|
195
|
+
* consumer, or — when the caller supplies `SubscribeOptions.apply` — only
|
|
196
|
+
* after that callback has applied the entry. Interrupted partial pages
|
|
197
|
+
* therefore retain the last admitted entry rather than incorrectly
|
|
198
|
+
* acknowledging the server's whole page.
|
|
199
|
+
*
|
|
200
|
+
* A frame or bootstrap page whose encoded entries exceed `maxFrameBytes` is
|
|
201
|
+
* refused with `frame_too_large`. Out-of-scope entries, repeated or reordered
|
|
202
|
+
* sequences, and missing response generations fail with `protocol_violation`
|
|
203
|
+
* before delivery. Each entry-bearing run in a Read page must have exactly one
|
|
204
|
+
* explicit generation cursor, and every entry must be above the requested
|
|
205
|
+
* cursor. Live frames instead drop already-covered entries and deliver only
|
|
206
|
+
* the suffix above the cursor. An incomplete bootstrap page with no entries
|
|
207
|
+
* or a completed subscription window with no frames fails with
|
|
208
|
+
* `protocol_violation` instead of reopening immediately.
|
|
209
|
+
*
|
|
210
|
+
* A live follow that loses its transport reconnects under
|
|
211
|
+
* {@link reconnectPolicy}, resuming from the acknowledged cursors; the failure
|
|
212
|
+
* cause is logged before the retry folds it. The follow spends a credit window
|
|
213
|
+
* of {@link defaultCredit} frames per subscription round and replenishes it by
|
|
214
|
+
* resubscribing from the cursors it has acknowledged. Already-covered entries
|
|
215
|
+
* are not delivered again; the round-trip cost scales with credit windows.
|
|
216
|
+
*
|
|
217
|
+
* A `compacted` refusal fails closed unless `SubscribeOptions.onResync`
|
|
218
|
+
* restores the missing prefix and returns its exact cursor. Snapshot fetching
|
|
219
|
+
* never applies state or advances cursors. Only a validated receipt for the requested run at or
|
|
220
|
+
* above its compaction floor advances the cursor before reading the suffix.
|
|
221
|
+
*
|
|
222
|
+
* A subscription's effective cursor per run is the LATER of the caller's and
|
|
223
|
+
* the matching progress map: a caller that restored its own progress is never
|
|
224
|
+
* regressed, and a caller asking for history this client already acknowledged
|
|
225
|
+
* is fast-forwarded. Rebuild a projection from an earlier position with a
|
|
226
|
+
* fresh client, whose acknowledged map is empty.
|
|
227
|
+
*
|
|
228
|
+
* This constructor carries the default policy, which is valid by
|
|
229
|
+
* construction and so cannot fail. {@link makeWith} takes an explicit
|
|
230
|
+
* {@link Options} and validates it.
|
|
231
|
+
*
|
|
232
|
+
* @category constructors
|
|
233
|
+
* @since 0.1.0
|
|
234
|
+
*/
|
|
235
|
+
export declare const make: ({ client }: {
|
|
236
|
+
readonly client: Client;
|
|
237
|
+
}) => Effect.Effect<Service>;
|
|
238
|
+
/**
|
|
239
|
+
* Constructs the sync client under an explicit policy.
|
|
240
|
+
*
|
|
241
|
+
* Every option is validated here, once, so a client either exists under a
|
|
242
|
+
* policy it can serve or never exists at all. Validating on each `subscribe`
|
|
243
|
+
* and each `snapshot` instead accepted a `maxFrameBytes` of `NaN` at
|
|
244
|
+
* construction and then refused every operation under it, which reported a
|
|
245
|
+
* composition's mistake as a run-time failure of the follow. This mirrors
|
|
246
|
+
* `SyncServer.makeLiveWith` and `BranchCommands.makeLiveWith`.
|
|
247
|
+
*
|
|
248
|
+
* `SubscribeOptions.credit` is a REQUEST count rather than a client policy, so
|
|
249
|
+
* it is still checked where the request is built.
|
|
250
|
+
*
|
|
251
|
+
* @category constructors
|
|
252
|
+
* @since 1.0.0-rc.0
|
|
253
|
+
*/
|
|
254
|
+
export declare const makeWith: ({ bootstrapLimit, client, maxFrameBytes }: Options & {
|
|
255
|
+
readonly client: Client;
|
|
256
|
+
}) => Effect.Effect<Service, SyncError>;
|
|
257
|
+
/**
|
|
258
|
+
* Provides the sync client from the active RPC protocol.
|
|
259
|
+
*
|
|
260
|
+
* @category layers
|
|
261
|
+
* @since 0.1.0
|
|
262
|
+
*/
|
|
263
|
+
export declare const layer: Layer.Layer<SyncClient, never, RpcClient.Protocol>;
|
|
264
|
+
/**
|
|
265
|
+
* Provides the sync client under an explicit policy. Fails with
|
|
266
|
+
* `invalid_request` when an option is not a positive safe integer, so a bad
|
|
267
|
+
* policy fails the composition rather than every operation under it.
|
|
268
|
+
*
|
|
269
|
+
* @category layers
|
|
270
|
+
* @since 1.0.0-rc.0
|
|
271
|
+
*/
|
|
272
|
+
export declare const layerWith: (options: Options) => Layer.Layer<SyncClient, SyncError, RpcClient.Protocol>;
|
|
273
|
+
export {};
|
|
274
|
+
//# sourceMappingURL=SyncClient.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SyncClient.d.ts","sourceRoot":"","sources":["../../src/SyncClient.ts"],"names":[],"mappings":"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"}
|