@fairfox/polly 0.20.0 → 0.21.0
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 +11 -0
- package/dist/src/background/index.js +22 -12
- package/dist/src/background/index.js.map +8 -8
- package/dist/src/background/message-router.js +22 -12
- package/dist/src/background/message-router.js.map +8 -8
- package/dist/src/client/index.js +187 -154
- package/dist/src/client/index.js.map +4 -4
- package/dist/src/elysia/index.d.ts +2 -0
- package/dist/src/elysia/index.js +195 -25
- package/dist/src/elysia/index.js.map +8 -5
- package/dist/src/elysia/peer-repo-plugin.d.ts +79 -0
- package/dist/src/elysia/plugin.d.ts +3 -3
- package/dist/src/elysia/signaling-server-plugin.d.ts +121 -0
- package/dist/src/index.d.ts +36 -0
- package/dist/src/index.js +1752 -13
- package/dist/src/index.js.map +31 -13
- package/dist/src/shared/adapters/index.js +22 -12
- package/dist/src/shared/adapters/index.js.map +7 -7
- package/dist/src/shared/lib/_client-only.d.ts +38 -0
- package/dist/src/shared/lib/access.d.ts +124 -0
- package/dist/src/shared/lib/blob-ref.d.ts +72 -0
- package/dist/src/shared/lib/context-helpers.js +22 -12
- package/dist/src/shared/lib/context-helpers.js.map +8 -8
- package/dist/src/shared/lib/crdt-specialised.d.ts +129 -0
- package/dist/src/shared/lib/crdt-state.d.ts +86 -0
- package/dist/src/shared/lib/encryption.d.ts +117 -0
- package/dist/src/shared/lib/errors.js +19 -9
- package/dist/src/shared/lib/errors.js.map +2 -2
- package/dist/src/shared/lib/mesh-network-adapter.d.ts +130 -0
- package/dist/src/shared/lib/mesh-signaling-client.d.ts +85 -0
- package/dist/src/shared/lib/mesh-state.d.ts +102 -0
- package/dist/src/shared/lib/mesh-webrtc-adapter.d.ts +132 -0
- package/dist/src/shared/lib/message-bus.js +22 -12
- package/dist/src/shared/lib/message-bus.js.map +8 -8
- package/dist/src/shared/lib/migrate-primitive.d.ts +100 -0
- package/dist/src/shared/lib/pairing.d.ts +170 -0
- package/dist/src/shared/lib/peer-relay-adapter.d.ts +80 -0
- package/dist/src/shared/lib/peer-repo-server.d.ts +83 -0
- package/dist/src/shared/lib/peer-state.d.ts +117 -0
- package/dist/src/shared/lib/primitive-registry.d.ts +88 -0
- package/dist/src/shared/lib/resource.js +22 -12
- package/dist/src/shared/lib/resource.js.map +5 -5
- package/dist/src/shared/lib/revocation.d.ts +126 -0
- package/dist/src/shared/lib/schema-version.d.ts +129 -0
- package/dist/src/shared/lib/signing.d.ts +118 -0
- package/dist/src/shared/lib/state.js +22 -12
- package/dist/src/shared/lib/state.js.map +5 -5
- package/dist/src/shared/lib/test-helpers.js +19 -9
- package/dist/src/shared/lib/test-helpers.js.map +2 -2
- package/dist/src/shared/state/app-state.js +22 -12
- package/dist/src/shared/state/app-state.js.map +6 -6
- package/dist/src/shared/types/messages.js +19 -9
- package/dist/src/shared/types/messages.js.map +2 -2
- package/dist/tools/init/src/cli.js +6 -2
- package/dist/tools/init/src/cli.js.map +3 -3
- package/dist/tools/quality/src/index.js +177 -0
- package/dist/tools/quality/src/index.js.map +10 -0
- package/dist/tools/test/src/adapters/index.d.ts +2 -2
- package/dist/tools/test/src/adapters/index.js +19 -9
- package/dist/tools/test/src/adapters/index.js.map +5 -5
- package/dist/tools/test/src/browser/harness.d.ts +80 -0
- package/dist/tools/test/src/browser/index.d.ts +32 -0
- package/dist/tools/test/src/browser/index.js +243 -0
- package/dist/tools/test/src/browser/index.js.map +10 -0
- package/dist/tools/test/src/browser/run.d.ts +26 -0
- package/dist/tools/test/src/index.js +19 -9
- package/dist/tools/test/src/index.js.map +5 -5
- package/dist/tools/test/src/test-utils.js +19 -9
- package/dist/tools/test/src/test-utils.js.map +2 -2
- package/dist/tools/verify/specs/tla/MeshState.cfg +21 -0
- package/dist/tools/verify/specs/tla/MeshState.tla +247 -0
- package/dist/tools/verify/specs/tla/PeerState.cfg +27 -0
- package/dist/tools/verify/specs/tla/PeerState.tla +238 -0
- package/dist/tools/verify/specs/tla/README.md +27 -3
- package/dist/tools/verify/src/cli.js +10 -6
- package/dist/tools/verify/src/cli.js.map +10 -10
- package/dist/tools/verify/src/config.js +19 -9
- package/dist/tools/verify/src/config.js.map +2 -2
- package/dist/tools/visualize/src/cli.js +6 -2
- package/dist/tools/visualize/src/cli.js.map +8 -8
- package/package.json +52 -12
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* peerRepo — Elysia plugin that runs a Polly peer-relay server alongside an
|
|
3
|
+
* Elysia application and exposes the server's Repo on the Elysia context.
|
|
4
|
+
*
|
|
5
|
+
* The Phase 1 plan originally framed the relay server as an Elysia plugin
|
|
6
|
+
* that registers a WebSocket route on Elysia's native socket layer. That
|
|
7
|
+
* design does not work directly: Automerge's WebSocketServerAdapter requires
|
|
8
|
+
* an `isomorphic-ws` WebSocketServer instance, and Elysia's WebSocket layer
|
|
9
|
+
* is built on Bun's native WebSocket API, which is a different shape. The
|
|
10
|
+
* realistic Phase 1 cut is therefore a *lifecycle* plugin: it runs
|
|
11
|
+
* createPeerRepoServer on its own port during Elysia startup, decorates the
|
|
12
|
+
* Elysia context so route handlers can reach the resulting Repo, and tears
|
|
13
|
+
* the server down during Elysia shutdown. Authenticated WebSocket upgrades
|
|
14
|
+
* via Elysia's hook system are a Phase 1.1 follow-up that requires either
|
|
15
|
+
* a custom Bun-native NetworkAdapter or an upgrade-time auth bridge.
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* ```ts
|
|
19
|
+
* import { Elysia } from "elysia";
|
|
20
|
+
* import { peerRepo } from "@fairfox/polly/elysia";
|
|
21
|
+
*
|
|
22
|
+
* const app = new Elysia()
|
|
23
|
+
* .use(peerRepo({ port: 3030, storagePath: "./data/polly-peer" }))
|
|
24
|
+
* .get("/stats", ({ pollyPeerRepo }) => {
|
|
25
|
+
* return { peers: pollyPeerRepo.peers.length };
|
|
26
|
+
* })
|
|
27
|
+
* .listen(8080);
|
|
28
|
+
* ```
|
|
29
|
+
*/
|
|
30
|
+
import { Elysia } from "elysia";
|
|
31
|
+
import { type CreatePeerRepoServerOptions, type PeerRepoServer } from "../shared/lib/peer-repo-server";
|
|
32
|
+
export interface PeerRepoPluginOptions extends CreatePeerRepoServerOptions {
|
|
33
|
+
/** Optional path for a health endpoint that returns peer count and storage
|
|
34
|
+
* id. Set to false to skip the health route entirely. Defaults to
|
|
35
|
+
* "/polly/peer/health". */
|
|
36
|
+
healthPath?: string | false;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Elysia plugin that boots a Polly peer-relay server alongside the host app
|
|
40
|
+
* and decorates the context with `pollyPeerRepo` (the Repo) and
|
|
41
|
+
* `pollyPeerServer` (the full {@link PeerRepoServer} for advanced use).
|
|
42
|
+
*
|
|
43
|
+
* The plugin starts the relay server during Elysia's onStart lifecycle and
|
|
44
|
+
* shuts it down during onStop, so route handlers and cron jobs can use the
|
|
45
|
+
* decorated Repo throughout the request lifetime without managing the
|
|
46
|
+
* underlying transport themselves.
|
|
47
|
+
*/
|
|
48
|
+
export declare function peerRepo(options: PeerRepoPluginOptions): Elysia<"", {
|
|
49
|
+
decorator: {
|
|
50
|
+
pollyPeerRepo: import("@automerge/automerge-repo").Repo | null;
|
|
51
|
+
} & {
|
|
52
|
+
pollyPeerServer: PeerRepoServer | null;
|
|
53
|
+
};
|
|
54
|
+
store: {};
|
|
55
|
+
derive: {};
|
|
56
|
+
resolve: {};
|
|
57
|
+
}, {
|
|
58
|
+
typebox: {};
|
|
59
|
+
error: {};
|
|
60
|
+
}, {
|
|
61
|
+
schema: {};
|
|
62
|
+
standaloneSchema: {};
|
|
63
|
+
macro: {};
|
|
64
|
+
macroFn: {};
|
|
65
|
+
parser: {};
|
|
66
|
+
response: {};
|
|
67
|
+
}, {}, {
|
|
68
|
+
derive: {};
|
|
69
|
+
resolve: {};
|
|
70
|
+
schema: {};
|
|
71
|
+
standaloneSchema: {};
|
|
72
|
+
response: {};
|
|
73
|
+
}, {
|
|
74
|
+
derive: {};
|
|
75
|
+
resolve: {};
|
|
76
|
+
schema: {};
|
|
77
|
+
standaloneSchema: {};
|
|
78
|
+
response: {};
|
|
79
|
+
}>;
|
|
@@ -60,10 +60,10 @@ export declare function polly(config?: PollyConfig): Elysia<"", {
|
|
|
60
60
|
}, {
|
|
61
61
|
[x: string]: {
|
|
62
62
|
subscribe: {
|
|
63
|
-
body:
|
|
63
|
+
body: {};
|
|
64
64
|
params: {};
|
|
65
|
-
query:
|
|
66
|
-
headers:
|
|
65
|
+
query: {};
|
|
66
|
+
headers: {};
|
|
67
67
|
response: {};
|
|
68
68
|
};
|
|
69
69
|
};
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* signalingServer — Phase 2 Elysia plugin that exposes a stateless
|
|
3
|
+
* WebSocket route for SDP/ICE relay between $meshState peers.
|
|
4
|
+
*
|
|
5
|
+
* The mesh transport is a star-of-data-channels: peers establish direct
|
|
6
|
+
* WebRTC connections to each other and exchange document operations
|
|
7
|
+
* peer-to-peer once those channels are open. WebRTC connection setup
|
|
8
|
+
* needs an out-of-band channel for SDP offer/answer and ICE candidate
|
|
9
|
+
* exchange, and that channel is what this plugin provides. The plugin
|
|
10
|
+
* does not own any document state, does not hold any encryption keys,
|
|
11
|
+
* and never inspects the contents of the messages it relays. It is a
|
|
12
|
+
* pure pub-sub by peer id.
|
|
13
|
+
*
|
|
14
|
+
* Once two peers have completed the SDP exchange and opened a direct
|
|
15
|
+
* data channel, the signalling server is no longer on the critical
|
|
16
|
+
* path — the peers talk directly. The signalling server's role is
|
|
17
|
+
* therefore intermittent: peers connect to it only during the brief
|
|
18
|
+
* windows when they are establishing or re-establishing connections.
|
|
19
|
+
*
|
|
20
|
+
* Wire protocol:
|
|
21
|
+
*
|
|
22
|
+
* Client → server (join):
|
|
23
|
+
* { type: "join", peerId: "peer-alice" }
|
|
24
|
+
*
|
|
25
|
+
* Client → server (signal to another peer):
|
|
26
|
+
* { type: "signal", peerId: "peer-alice", targetPeerId: "peer-bob",
|
|
27
|
+
* payload: { ... } }
|
|
28
|
+
*
|
|
29
|
+
* Server → client (delivered signal):
|
|
30
|
+
* { type: "signal", peerId: "peer-alice", targetPeerId: "peer-bob",
|
|
31
|
+
* payload: { ... } }
|
|
32
|
+
*
|
|
33
|
+
* Server → client (notification of unknown target):
|
|
34
|
+
* { type: "error", reason: "unknown-target", targetPeerId: "..." }
|
|
35
|
+
*
|
|
36
|
+
* The `payload` is opaque to the signalling server — typically it
|
|
37
|
+
* carries an SDP offer, SDP answer, or ICE candidate. Applications can
|
|
38
|
+
* also use the relay for any other peer-to-peer message that needs an
|
|
39
|
+
* intermediary, such as the initial handshake of a pairing flow.
|
|
40
|
+
*
|
|
41
|
+
* @example
|
|
42
|
+
* ```ts
|
|
43
|
+
* import { Elysia } from "elysia";
|
|
44
|
+
* import { signalingServer } from "@fairfox/polly/elysia";
|
|
45
|
+
*
|
|
46
|
+
* const app = new Elysia()
|
|
47
|
+
* .use(signalingServer({ path: "/polly/signaling" }))
|
|
48
|
+
* .listen(8080);
|
|
49
|
+
* ```
|
|
50
|
+
*/
|
|
51
|
+
import { Elysia } from "elysia";
|
|
52
|
+
/** A signalling message. The `type` discriminates between join (peer
|
|
53
|
+
* registration), signal (relayed message), and error (server response). */
|
|
54
|
+
export type SignalingMessage = {
|
|
55
|
+
type: "join";
|
|
56
|
+
/** The peer registering itself with the signalling server. */
|
|
57
|
+
peerId: string;
|
|
58
|
+
} | {
|
|
59
|
+
type: "signal";
|
|
60
|
+
/** The peer sending the signal. */
|
|
61
|
+
peerId: string;
|
|
62
|
+
/** The peer the signal is being relayed to. */
|
|
63
|
+
targetPeerId: string;
|
|
64
|
+
/** Opaque payload, typically SDP or ICE. */
|
|
65
|
+
payload: unknown;
|
|
66
|
+
} | {
|
|
67
|
+
type: "error";
|
|
68
|
+
reason: "unknown-target" | "not-joined" | "malformed";
|
|
69
|
+
targetPeerId?: string;
|
|
70
|
+
};
|
|
71
|
+
export interface SignalingServerOptions {
|
|
72
|
+
/** WebSocket route path. Defaults to "/polly/signaling". */
|
|
73
|
+
path?: string;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Construct the signalling-server Elysia plugin. The plugin keeps a
|
|
77
|
+
* per-instance map of peer id → WebSocket connection so that incoming
|
|
78
|
+
* "signal" messages can be routed to the right target socket. The map
|
|
79
|
+
* is local to the plugin instance, not shared across processes; for
|
|
80
|
+
* multi-instance deployments behind a load balancer, applications need
|
|
81
|
+
* sticky connection routing or a shared backplane (Redis pub-sub or
|
|
82
|
+
* similar). That is a follow-up.
|
|
83
|
+
*/
|
|
84
|
+
export declare function signalingServer(options?: SignalingServerOptions): Elysia<"", {
|
|
85
|
+
decorator: {};
|
|
86
|
+
store: {};
|
|
87
|
+
derive: {};
|
|
88
|
+
resolve: {};
|
|
89
|
+
}, {
|
|
90
|
+
typebox: {};
|
|
91
|
+
error: {};
|
|
92
|
+
}, {
|
|
93
|
+
schema: {};
|
|
94
|
+
standaloneSchema: {};
|
|
95
|
+
macro: {};
|
|
96
|
+
macroFn: {};
|
|
97
|
+
parser: {};
|
|
98
|
+
response: {};
|
|
99
|
+
}, {
|
|
100
|
+
[x: string]: {
|
|
101
|
+
subscribe: {
|
|
102
|
+
body: {};
|
|
103
|
+
params: {};
|
|
104
|
+
query: {};
|
|
105
|
+
headers: {};
|
|
106
|
+
response: {};
|
|
107
|
+
};
|
|
108
|
+
};
|
|
109
|
+
}, {
|
|
110
|
+
derive: {};
|
|
111
|
+
resolve: {};
|
|
112
|
+
schema: {};
|
|
113
|
+
standaloneSchema: {};
|
|
114
|
+
response: {};
|
|
115
|
+
}, {
|
|
116
|
+
derive: {};
|
|
117
|
+
resolve: {};
|
|
118
|
+
schema: {};
|
|
119
|
+
standaloneSchema: {};
|
|
120
|
+
response: {};
|
|
121
|
+
}>;
|
package/dist/src/index.d.ts
CHANGED
|
@@ -6,14 +6,50 @@
|
|
|
6
6
|
*/
|
|
7
7
|
export type { ExtensionAdapters } from "./shared/adapters";
|
|
8
8
|
export { createChromeAdapters } from "./shared/adapters";
|
|
9
|
+
export type { Access, AccessPredicate, PeerIdentity } from "./shared/lib/access";
|
|
10
|
+
export { and, anyOfPeers, anyone, groupAccess, nobody, not, onlyPeer, or, ownerAccess, publicAccess, readOnlyExcept, } from "./shared/lib/access";
|
|
11
|
+
export type { BlobRef, CreateBlobRefArgs } from "./shared/lib/blob-ref";
|
|
12
|
+
export { computeBlobHash, createBlobRef, isBlobRef } from "./shared/lib/blob-ref";
|
|
9
13
|
export { checkPostconditions, checkPreconditions, clearConstraints, isRuntimeConstraintsEnabled, registerConstraint, registerConstraints, } from "./shared/lib/constraints";
|
|
10
14
|
export type { ContextConfig } from "./shared/lib/context-helpers";
|
|
11
15
|
export { createContext, runInContext } from "./shared/lib/context-helpers";
|
|
12
16
|
export type { BackgroundHelpers, ContentScriptHelpers, DevToolsHelpers, OptionsHelpers, PopupHelpers, SidePanelHelpers, } from "./shared/lib/context-specific-helpers";
|
|
17
|
+
export type { CounterDoc, CrdtCounterOptions, CrdtListOptions, CrdtTextOptions, ListDoc, SpecialisedPrimitive, TextDoc, } from "./shared/lib/crdt-specialised";
|
|
18
|
+
export { $crdtCounter, $crdtList, $crdtText } from "./shared/lib/crdt-specialised";
|
|
19
|
+
export type { CrdtPrimitive, CrdtStateOptions } from "./shared/lib/crdt-state";
|
|
20
|
+
export { $crdtState } from "./shared/lib/crdt-state";
|
|
21
|
+
export type { EncryptedEnvelope, SealedBytes, } from "./shared/lib/encryption";
|
|
22
|
+
export { decrypt, decryptOrThrow, EncryptionError, encrypt, generateDocumentKey, KEY_BYTES as ENCRYPTION_KEY_BYTES, NONCE_BYTES as ENCRYPTION_NONCE_BYTES, TAG_BYTES as ENCRYPTION_TAG_BYTES, } from "./shared/lib/encryption";
|
|
13
23
|
export { ConnectionError, ErrorHandler, ExtensionError, HandlerError, TimeoutError, } from "./shared/lib/errors";
|
|
24
|
+
export type { MeshKeyring, MeshNetworkAdapterOptions, } from "./shared/lib/mesh-network-adapter";
|
|
25
|
+
export { DEFAULT_MESH_KEY_ID, MeshNetworkAdapter, } from "./shared/lib/mesh-network-adapter";
|
|
26
|
+
export type { MeshSignalingClientOptions, SignalingMessage as MeshSignalingMessage, } from "./shared/lib/mesh-signaling-client";
|
|
27
|
+
export { MeshSignalingClient } from "./shared/lib/mesh-signaling-client";
|
|
28
|
+
export type { MeshStateOptions } from "./shared/lib/mesh-state";
|
|
29
|
+
export { $meshCounter, $meshList, $meshState, $meshText, configureMeshState, resetMeshState, } from "./shared/lib/mesh-state";
|
|
30
|
+
export type { MeshWebRTCAdapterOptions } from "./shared/lib/mesh-webrtc-adapter";
|
|
31
|
+
export { DEFAULT_ICE_SERVERS, MeshWebRTCAdapter } from "./shared/lib/mesh-webrtc-adapter";
|
|
14
32
|
export { getMessageBus, MessageBus } from "./shared/lib/message-bus";
|
|
33
|
+
export type { MigratableState } from "./shared/lib/migrate-primitive";
|
|
34
|
+
export { MigrationError, migratePrimitive } from "./shared/lib/migrate-primitive";
|
|
35
|
+
export type { CreatePairingTokenOptions, PairingToken, } from "./shared/lib/pairing";
|
|
36
|
+
export { applyPairingToken, createPairingToken, createPairingTokenWithFreshIdentity, DEFAULT_PAIRING_TTL_MS, decodePairingToken, encodePairingToken, isPairingTokenExpired, PAIRING_NONCE_BYTES, PAIRING_TOKEN_VERSION, PairingError, parsePairingToken, serialisePairingToken, } from "./shared/lib/pairing";
|
|
37
|
+
export type { CreatePeerStateClientOptions, PeerRelayConnectionState, PeerStateClient, } from "./shared/lib/peer-relay-adapter";
|
|
38
|
+
export { createPeerStateClient } from "./shared/lib/peer-relay-adapter";
|
|
39
|
+
export type { CreatePeerRepoServerOptions, PeerRepoServer, } from "./shared/lib/peer-repo-server";
|
|
40
|
+
export { createPeerRepoServer } from "./shared/lib/peer-repo-server";
|
|
41
|
+
export type { PeerCounterOptions, PeerListOptions, PeerStateOptions, PeerTextOptions, } from "./shared/lib/peer-state";
|
|
42
|
+
export { $peerCounter, $peerList, $peerState, $peerText, configurePeerState, resetPeerState, } from "./shared/lib/peer-state";
|
|
43
|
+
export type { PrimitiveKind } from "./shared/lib/primitive-registry";
|
|
44
|
+
export { PrimitiveCollisionError } from "./shared/lib/primitive-registry";
|
|
15
45
|
export type { Resource, ResourceOptions, ResourceStatus } from "./shared/lib/resource";
|
|
16
46
|
export { $resource } from "./shared/lib/resource";
|
|
47
|
+
export type { CreateRevocationOptions, RevocationRecord, } from "./shared/lib/revocation";
|
|
48
|
+
export { applyRevocation, createRevocation, decodeRevocation, encodeRevocation, REVOCATION_MAGIC, REVOCATION_RECORD_VERSION, RevocationError, revokePeerLocally, } from "./shared/lib/revocation";
|
|
49
|
+
export type { Migration, Migrations, OpVersionCheck, VersionedDoc, } from "./shared/lib/schema-version";
|
|
50
|
+
export { assertOpVersion, checkOpVersion, getDocVersion, SCHEMA_VERSION_FIELD, SchemaVersionError, } from "./shared/lib/schema-version";
|
|
51
|
+
export type { SignedEnvelope, SigningKeyPair } from "./shared/lib/signing";
|
|
52
|
+
export { generateSigningKeyPair, PUBLIC_KEY_BYTES as SIGNING_PUBLIC_KEY_BYTES, SECRET_KEY_BYTES as SIGNING_SECRET_KEY_BYTES, SIGNATURE_BYTES as SIGNING_SIGNATURE_BYTES, SigningError, sign, signingKeyPairFromSecret, verify, } from "./shared/lib/signing";
|
|
17
53
|
export { $persistedState, $sharedState, $state, $syncedState } from "./shared/lib/state";
|
|
18
54
|
export type { TestCase, TestSuite } from "./shared/lib/test-helpers";
|
|
19
55
|
export { createTestSuite, quickTest, TestRunner } from "./shared/lib/test-helpers";
|