@comapeo/core 2.3.2 → 3.0.0-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/dist/blob-store/live-download.d.ts +107 -0
- package/dist/blob-store/live-download.d.ts.map +1 -0
- package/dist/capabilities.d.ts +121 -0
- package/dist/capabilities.d.ts.map +1 -0
- package/dist/core-manager/compat.d.ts +4 -0
- package/dist/core-manager/compat.d.ts.map +1 -0
- package/dist/discovery/dns-sd.d.ts +54 -0
- package/dist/discovery/dns-sd.d.ts.map +1 -0
- package/dist/errors.d.ts +16 -0
- package/dist/errors.d.ts.map +1 -1
- package/dist/fastify-plugins/maps/index.d.ts +11 -0
- package/dist/fastify-plugins/maps/index.d.ts.map +1 -0
- package/dist/fastify-plugins/maps/offline-fallback-map.d.ts +12 -0
- package/dist/fastify-plugins/maps/offline-fallback-map.d.ts.map +1 -0
- package/dist/fastify-plugins/maps/static-maps.d.ts +11 -0
- package/dist/fastify-plugins/maps/static-maps.d.ts.map +1 -0
- package/dist/invite/invite-api.d.ts +112 -0
- package/dist/invite/invite-api.d.ts.map +1 -0
- package/dist/invite/invite-state-machine.d.ts +510 -0
- package/dist/invite/invite-state-machine.d.ts.map +1 -0
- package/dist/lib/timing-safe-equal.d.ts +15 -0
- package/dist/lib/timing-safe-equal.d.ts.map +1 -0
- package/dist/local-peers.d.ts.map +1 -1
- package/dist/mapeo-manager.d.ts +1 -1
- package/dist/mapeo-manager.d.ts.map +1 -1
- package/dist/media-server.d.ts +36 -0
- package/dist/media-server.d.ts.map +1 -0
- package/dist/member-api.d.ts.map +1 -1
- package/dist/server/ws-core-replicator.d.ts +6 -0
- package/dist/server/ws-core-replicator.d.ts.map +1 -0
- package/dist/sync/sync-api.d.ts.map +1 -1
- package/dist/types.d.ts +5 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/utils.d.ts +2 -2
- package/dist/utils.d.ts.map +1 -1
- package/package.json +2 -1
- package/src/errors.js +33 -0
- package/src/invite/StateDiagram.md +47 -0
- package/src/invite/invite-api.js +387 -0
- package/src/invite/invite-state-machine.js +208 -0
- package/src/local-peers.js +12 -9
- package/src/mapeo-manager.js +1 -1
- package/src/member-api.js +5 -4
- package/src/types.ts +6 -0
- package/src/utils.js +8 -3
- package/src/invite-api.js +0 -450
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/dist/utils.d.ts
CHANGED
|
@@ -10,10 +10,10 @@ export function keyToId(key: Buffer | string): string;
|
|
|
10
10
|
export function noop(): void;
|
|
11
11
|
/**
|
|
12
12
|
* @param {unknown} condition
|
|
13
|
-
* @param {string}
|
|
13
|
+
* @param {string | Error} messageOrError
|
|
14
14
|
* @returns {asserts condition}
|
|
15
15
|
*/
|
|
16
|
-
export function assert(condition: unknown,
|
|
16
|
+
export function assert(condition: unknown, messageOrError: string | Error): asserts condition;
|
|
17
17
|
/**
|
|
18
18
|
* Return a function that itself returns whether a value is part of the set.
|
|
19
19
|
*
|
package/dist/utils.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.js"],"names":[],"mappings":"AAQA;;;;GAIG;AACH,6BAHW,MAAM,SAAO,UASvB;AAUD;;GAEG;AACH,wBAFa,IAAI,CAEQ;AAEzB;;;;GAIG;AACH,kCAJW,OAAO,
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.js"],"names":[],"mappings":"AAQA;;;;GAIG;AACH,6BAHW,MAAM,SAAO,UASvB;AAUD;;GAEG;AACH,wBAFa,IAAI,CAEQ;AAEzB;;;;GAIG;AACH,kCAJW,OAAO,kBACP,MAAM,GAAG,KAAK,GACZ,QAAQ,SAAS,CAS7B;AAED;;;;;;;;;;;;;GAaG;AACH,uBATa,CAAC,OACH,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,WAUd,OAAO,KACL,KAAK,IAAI,CAAC,CAGxB;AAED;;;;GAIG;AACH,0BAJa,CAAC,SACH,SAAS,GAAG,CAAC,GACX,KAAK,IAAI,CAAC,CAItB;AAED;;;;;;;GAOG;AAEH,0BALkB,CAAC,SAAN,EAAI,OACN,CAAC,GACC,OAAO,YAAY,EAAE,kBAAkB,CAAC,CAAC,CAAC,CAUtD;AAED;;;;GAIG;AACH,wBAJyE,CAAC,SAA5D,OAAO,iBAAiB,EAAE,QAAQ,GAAG;IAAE,KAAK,CAAC,EAAE,MAAM,EAAE,CAAA;CAAG,OAC7D,CAAC,GACC,IAAI,CAAC,CAAC,EAAE,OAAO,GAAG,WAAW,GAAG,mBAAmB,GAAG,OAAO,GAAG,OAAO,GAAG,WAAW,GAAG,WAAW,GAAG,SAAS,CAAC,CAa5H;AAED;;;;GAIG;AACH,2CAHW,MAAM,GACJ,MAAM,CAIlB;AAED;;;;GAIG;AACH,iDAHW,MAAM,GACJ,MAAM,CAIlB;AAED;;;;GAIG;AACH,wDAHW,QAAQ,CAAC,MAAM,CAAC,GACd,MAAM,CAMlB;AAED;;;GAGG;AACH,4CAHW,MAAM,GACJ,MAAM,CAIlB;AAED;;;GAGG;AACH,wCAHW,2CAAkC,GAChC,MAAM,CAIlB;AAED;;;;;;;2DAO2D;AAC3D,0BALsB,CAAC,SAAV,MAAQ,EACF,CAAC,wBACT,aAAa,CAAC,CAAC,CAAC,SAChB,CAAC,GACC,MAAM,CAAC,CAAC,EAAE,CAAC,SAAS,MAAM,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAOtD;AAED;;;;GAIG;AACH,gCAHW,MAAM,UAQhB;AArKD;IACE,2BAA2B;IAC3B,mBADY,KAAK,EAIhB;CACF"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@comapeo/core",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.0.0-0",
|
|
4
4
|
"description": "Offline p2p mapping library",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -209,6 +209,7 @@
|
|
|
209
209
|
"unix-path-resolve": "^1.0.2",
|
|
210
210
|
"varint": "^6.0.0",
|
|
211
211
|
"ws": "^8.18.0",
|
|
212
|
+
"xstate": "^5.19.2",
|
|
212
213
|
"yauzl-promise": "^4.0.0"
|
|
213
214
|
}
|
|
214
215
|
}
|
package/src/errors.js
CHANGED
|
@@ -1,6 +1,39 @@
|
|
|
1
1
|
export class NotFoundError extends Error {
|
|
2
2
|
constructor(message = 'Not found') {
|
|
3
3
|
super(message)
|
|
4
|
+
this.name = 'NotFoundError'
|
|
5
|
+
}
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export class AlreadyJoinedError extends Error {
|
|
9
|
+
/** @param {string} [message] */
|
|
10
|
+
constructor(message = 'AlreadyJoinedError') {
|
|
11
|
+
super(message)
|
|
12
|
+
this.name = 'AlreadyJoinedError'
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export class InviteSendError extends Error {
|
|
17
|
+
/** @param {string} [message] */
|
|
18
|
+
constructor(message = 'Invite Send Error') {
|
|
19
|
+
super(message)
|
|
20
|
+
this.name = 'InviteSendError'
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export class InviteAbortedError extends Error {
|
|
25
|
+
/** @param {string} [message] */
|
|
26
|
+
constructor(message = 'Invite Aborted') {
|
|
27
|
+
super(message)
|
|
28
|
+
this.name = 'InviteAbortedError'
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export class TimeoutError extends Error {
|
|
33
|
+
/** @param {string} [message] */
|
|
34
|
+
constructor(message = 'TimeoutError') {
|
|
35
|
+
super(message)
|
|
36
|
+
this.name = 'TimeoutError'
|
|
4
37
|
}
|
|
5
38
|
}
|
|
6
39
|
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
```mermaid
|
|
2
|
+
---
|
|
3
|
+
title: Invite Receive State Diagram
|
|
4
|
+
---
|
|
5
|
+
stateDiagram-v2
|
|
6
|
+
state "invite" as invite {
|
|
7
|
+
[*] --> invite.pending
|
|
8
|
+
invite.pending --> invite.canceled : CANCEL_INVITE
|
|
9
|
+
invite.pending --> invite.responding.accept : ACCEPT_INVITE
|
|
10
|
+
invite.pending --> invite.responding.already : ALREADY_IN_PROJECT
|
|
11
|
+
invite.pending --> invite.responding.reject : REJECT_INVITE
|
|
12
|
+
invite.responding.default --> invite.error
|
|
13
|
+
invite.responding.accept --> invite.joining.addingProject : RECEIVE_PROJECT_DETAILS
|
|
14
|
+
invite.responding.accept --> invite.joining : Responded Accept
|
|
15
|
+
invite.responding.accept --> invite.error : Error responding
|
|
16
|
+
invite.responding.reject --> invite.rejected : Responded Reject
|
|
17
|
+
invite.responding.reject --> invite.error : Error responding
|
|
18
|
+
invite.responding.already --> invite.respondedAlready : Responded Already
|
|
19
|
+
invite.responding.already --> invite.error : Error responding
|
|
20
|
+
invite.responding --> invite.canceled : CANCEL_INVITE
|
|
21
|
+
invite.joining.awaitingDetails --> invite.canceled : CANCEL_INVITE
|
|
22
|
+
invite.joining.awaitingDetails --> invite.error : projectDetailsTimeout
|
|
23
|
+
invite.joining.addingProject --> invite.error : addProject Timeout
|
|
24
|
+
invite.joining.addingProject --> invite.joined : Project Added
|
|
25
|
+
invite.joining.addingProject --> invite.error : addProject Error
|
|
26
|
+
state "Pending invite awaiting response" as invite.pending
|
|
27
|
+
state "Responding to invite" as invite.responding {
|
|
28
|
+
[*] --> invite.responding.default
|
|
29
|
+
state "default" as invite.responding.default
|
|
30
|
+
state "accept" as invite.responding.accept
|
|
31
|
+
state "reject" as invite.responding.reject
|
|
32
|
+
state "already" as invite.responding.already
|
|
33
|
+
}
|
|
34
|
+
state "Joining project from invite" as invite.joining {
|
|
35
|
+
[*] --> invite.joining.awaitingDetails
|
|
36
|
+
invite.joining.awaitingDetails --> invite.joining.addingProject : RECEIVE_PROJECT_DETAILS
|
|
37
|
+
state "Awaiting project details" as invite.joining.awaitingDetails
|
|
38
|
+
state "Adding project" as invite.joining.addingProject
|
|
39
|
+
}
|
|
40
|
+
state "Invite Canceled" as invite.canceled
|
|
41
|
+
state "Invite Rejected" as invite.rejected
|
|
42
|
+
state "Responded already in project" as invite.respondedAlready
|
|
43
|
+
state "Joined project" as invite.joined
|
|
44
|
+
state "Invite Error" as invite.error
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
```
|
|
@@ -0,0 +1,387 @@
|
|
|
1
|
+
import { TypedEmitter } from 'tiny-typed-emitter'
|
|
2
|
+
import { InviteResponse_Decision } from '../generated/rpc.js'
|
|
3
|
+
import { assert, keyToId, noop } from '../utils.js'
|
|
4
|
+
import HashMap from '../lib/hashmap.js'
|
|
5
|
+
import timingSafeEqual from 'string-timing-safe-equal'
|
|
6
|
+
import { Logger } from '../logger.js'
|
|
7
|
+
import { createActor, fromPromise, toPromise } from 'xstate'
|
|
8
|
+
import { inviteStateMachine } from './invite-state-machine.js'
|
|
9
|
+
import {
|
|
10
|
+
NotFoundError,
|
|
11
|
+
AlreadyJoinedError,
|
|
12
|
+
InviteSendError,
|
|
13
|
+
} from '../errors.js'
|
|
14
|
+
|
|
15
|
+
/** @import { MapBuffers } from '../types.js' */
|
|
16
|
+
/**
|
|
17
|
+
* @import {
|
|
18
|
+
* Invite as InviteRpcMessage,
|
|
19
|
+
* InviteCancel,
|
|
20
|
+
* ProjectJoinDetails
|
|
21
|
+
* } from '../generated/rpc.js'
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
// There are three slightly different invite types:
|
|
25
|
+
//
|
|
26
|
+
// - InviteRpcMessage comes from the protobuf.
|
|
27
|
+
// - InviteInternal adds a locally-generated receive timestamp.
|
|
28
|
+
// - Invite is the externally-facing type.
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* @internal
|
|
32
|
+
* @typedef {InviteRpcMessage & { receivedAt: number }} InviteInternal
|
|
33
|
+
*/
|
|
34
|
+
/** @typedef {ExtractStateString<import('xstate').StateValueFrom<typeof inviteStateMachine>>} InviteState */
|
|
35
|
+
/** @typedef {import('type-fest').Simplify<MapBuffers<InviteInternal> & { invitorDeviceId: string } & ({ state: Exclude<InviteState, 'error'> } | { state: 'error', error: Error })>} Invite */
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* @typedef {import('xstate').ActorRefFrom<typeof inviteStateMachine>} invite.actor
|
|
39
|
+
*/
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* @typedef {Object} InviteApiEvents
|
|
43
|
+
* @property {(invite: Invite) => void} invite-received
|
|
44
|
+
* @property {(invite: Invite) => void} invite-updated
|
|
45
|
+
*/
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* @typedef {(projectDetails: Pick<ProjectJoinDetails, 'projectKey' | 'encryptionKeys'> & { projectName: string }) => Promise<string>} AddProjectQuery
|
|
49
|
+
*/
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* @extends {TypedEmitter<InviteApiEvents>}
|
|
53
|
+
*/
|
|
54
|
+
export class InviteApi extends TypedEmitter {
|
|
55
|
+
#getProjectByInviteId
|
|
56
|
+
#addProject
|
|
57
|
+
/** @type {HashMap<string | Buffer, { value: InviteInternal, actor: invite.actor, peerId: string }>} */
|
|
58
|
+
#invites = new HashMap(keyToId)
|
|
59
|
+
#l
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* @param {Object} options
|
|
63
|
+
* @param {import('../local-peers.js').LocalPeers} options.rpc
|
|
64
|
+
* @param {object} options.queries
|
|
65
|
+
* @param {(projectInviteId: Readonly<Buffer>) => undefined | { projectPublicId: string }} options.queries.getProjectByInviteId
|
|
66
|
+
* @param {AddProjectQuery} options.queries.addProject
|
|
67
|
+
* @param {Logger} [options.logger]
|
|
68
|
+
*/
|
|
69
|
+
constructor({ rpc, queries, logger }) {
|
|
70
|
+
super()
|
|
71
|
+
|
|
72
|
+
this.#l = Logger.create('InviteApi', logger)
|
|
73
|
+
|
|
74
|
+
this.rpc = rpc
|
|
75
|
+
this.#getProjectByInviteId = queries.getProjectByInviteId
|
|
76
|
+
this.#addProject = queries.addProject
|
|
77
|
+
|
|
78
|
+
this.rpc.on('invite', (...args) => {
|
|
79
|
+
try {
|
|
80
|
+
this.#handleNewInvite(...args)
|
|
81
|
+
} catch (err) {
|
|
82
|
+
console.error('Error handling invite', err)
|
|
83
|
+
}
|
|
84
|
+
})
|
|
85
|
+
|
|
86
|
+
this.rpc.on('invite-cancel', (_peerId, inviteCancel) => {
|
|
87
|
+
try {
|
|
88
|
+
this.#handleInviteCancel(inviteCancel)
|
|
89
|
+
} catch (err) {
|
|
90
|
+
console.error('Error handling invite cancel', err)
|
|
91
|
+
}
|
|
92
|
+
})
|
|
93
|
+
|
|
94
|
+
this.rpc.on('got-project-details', (peerId, projectJoinDetails) => {
|
|
95
|
+
try {
|
|
96
|
+
this.#handleGotProjectDetails(peerId, projectJoinDetails)
|
|
97
|
+
} catch (err) {
|
|
98
|
+
console.error('Error handling got-project-details', err)
|
|
99
|
+
}
|
|
100
|
+
})
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/** @param {Buffer} projectInviteId */
|
|
104
|
+
#isJoiningProject(projectInviteId) {
|
|
105
|
+
for (const { value, actor } of this.#invites.values()) {
|
|
106
|
+
const state = actor.getSnapshot()
|
|
107
|
+
if (
|
|
108
|
+
state.matches('joining') &&
|
|
109
|
+
value.projectInviteId.equals(projectInviteId)
|
|
110
|
+
) {
|
|
111
|
+
return true
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
return false
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* @param {string} peerId
|
|
119
|
+
* @param {InviteRpcMessage} inviteRpcMessage
|
|
120
|
+
*/
|
|
121
|
+
#handleNewInvite(peerId, inviteRpcMessage) {
|
|
122
|
+
const { inviteId, projectInviteId, projectName } = inviteRpcMessage
|
|
123
|
+
const invite = { ...inviteRpcMessage, receivedAt: Date.now() }
|
|
124
|
+
|
|
125
|
+
this.#l.log('Received invite %h from %S', inviteId, peerId)
|
|
126
|
+
|
|
127
|
+
const hasAlreadyReceivedThisInvite = this.#invites.has(inviteId)
|
|
128
|
+
if (hasAlreadyReceivedThisInvite) {
|
|
129
|
+
this.#l.log('Invite %h: already received this invite', inviteId)
|
|
130
|
+
return
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
const isAlreadyMember = Boolean(this.#getProjectByInviteId(projectInviteId))
|
|
134
|
+
if (isAlreadyMember) {
|
|
135
|
+
this.#l.log('Invite %h: already in project', inviteId)
|
|
136
|
+
this.rpc
|
|
137
|
+
.sendInviteResponse(peerId, {
|
|
138
|
+
decision: InviteResponse_Decision.ALREADY,
|
|
139
|
+
inviteId,
|
|
140
|
+
})
|
|
141
|
+
.catch(noop)
|
|
142
|
+
return
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
const actor = createActor(
|
|
146
|
+
inviteStateMachine.provide({
|
|
147
|
+
actors: {
|
|
148
|
+
sendInviteResponse: fromPromise(async ({ input: { decision } }) => {
|
|
149
|
+
return this.rpc.sendInviteResponse(peerId, { decision, inviteId })
|
|
150
|
+
}),
|
|
151
|
+
addProject: fromPromise(async ({ input: projectDetails }) => {
|
|
152
|
+
return this.#addProject({ ...projectDetails, projectName })
|
|
153
|
+
}),
|
|
154
|
+
},
|
|
155
|
+
guards: {
|
|
156
|
+
isNotAlreadyJoiningOrInProject: () => {
|
|
157
|
+
const isJoining = this.#isJoiningProject(projectInviteId)
|
|
158
|
+
const isAlreadyMember = Boolean(
|
|
159
|
+
this.#getProjectByInviteId(projectInviteId)
|
|
160
|
+
)
|
|
161
|
+
return !isJoining && !isAlreadyMember
|
|
162
|
+
},
|
|
163
|
+
},
|
|
164
|
+
})
|
|
165
|
+
)
|
|
166
|
+
|
|
167
|
+
this.#invites.set(inviteId, { value: invite, actor, peerId })
|
|
168
|
+
|
|
169
|
+
this.emit('invite-received', toInvite(invite, actor.getSnapshot(), peerId))
|
|
170
|
+
actor.start()
|
|
171
|
+
// Subscribe after start so that initial state (invite-received) is not emitted twice
|
|
172
|
+
actor.subscribe((snapshot) => {
|
|
173
|
+
this.emit('invite-updated', toInvite(invite, snapshot, peerId))
|
|
174
|
+
})
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* @param {InviteCancel} inviteCancel
|
|
179
|
+
*/
|
|
180
|
+
#handleInviteCancel(inviteCancel) {
|
|
181
|
+
const { inviteId } = inviteCancel
|
|
182
|
+
|
|
183
|
+
this.#l.log('Received invite cancel for invite ID %h', inviteId)
|
|
184
|
+
|
|
185
|
+
const invite = this.#invites.get(inviteId)
|
|
186
|
+
assert(!!invite, `Cannot find invite ${inviteId.toString('hex')}`)
|
|
187
|
+
|
|
188
|
+
// TODO: Move this logging to the state machine
|
|
189
|
+
const state = invite.actor.getSnapshot()
|
|
190
|
+
if (!state.can({ type: 'CANCEL_INVITE' })) {
|
|
191
|
+
this.#l.log(
|
|
192
|
+
'Received invite cancel for %h but invite is already in state %o',
|
|
193
|
+
inviteId,
|
|
194
|
+
state.value
|
|
195
|
+
)
|
|
196
|
+
return
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
invite.actor.send({ type: 'CANCEL_INVITE' })
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* @param {string} peerId
|
|
204
|
+
* @param {ProjectJoinDetails} projectJoinDetails
|
|
205
|
+
*/
|
|
206
|
+
#handleGotProjectDetails(peerId, projectJoinDetails) {
|
|
207
|
+
const invite = this.#invites.get(projectJoinDetails.inviteId)
|
|
208
|
+
if (!invite) {
|
|
209
|
+
this.#l.log(
|
|
210
|
+
'Received project details for %h but invite is not found',
|
|
211
|
+
projectJoinDetails.inviteId
|
|
212
|
+
)
|
|
213
|
+
return
|
|
214
|
+
}
|
|
215
|
+
if (!timingSafeEqual(peerId, invite.peerId)) {
|
|
216
|
+
this.#l.log(
|
|
217
|
+
'Received project details for %h but peer ID does not match',
|
|
218
|
+
projectJoinDetails.inviteId
|
|
219
|
+
)
|
|
220
|
+
return
|
|
221
|
+
}
|
|
222
|
+
invite.actor.send({
|
|
223
|
+
type: 'RECEIVE_PROJECT_DETAILS',
|
|
224
|
+
...projectJoinDetails,
|
|
225
|
+
})
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* Get all invites (in all)
|
|
230
|
+
*
|
|
231
|
+
* @returns {Array<Invite>}
|
|
232
|
+
*/
|
|
233
|
+
getMany() {
|
|
234
|
+
/** @type {Array<Invite>} */
|
|
235
|
+
const invites = []
|
|
236
|
+
for (const { value, actor, peerId } of this.#invites.values()) {
|
|
237
|
+
const snapshot = actor.getSnapshot()
|
|
238
|
+
invites.push(toInvite(value, snapshot, peerId))
|
|
239
|
+
}
|
|
240
|
+
return invites
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
/**
|
|
244
|
+
* Get an invite by inviteId
|
|
245
|
+
*
|
|
246
|
+
* @param {string} inviteIdString
|
|
247
|
+
* @returns {Invite}
|
|
248
|
+
*/
|
|
249
|
+
getById(inviteIdString) {
|
|
250
|
+
const inviteId = Buffer.from(inviteIdString, 'hex')
|
|
251
|
+
const invite = this.#invites.get(inviteId)
|
|
252
|
+
if (!invite) {
|
|
253
|
+
throw new NotFoundError(`Cannot find invite ${inviteIdString}`)
|
|
254
|
+
}
|
|
255
|
+
return toInvite(invite.value, invite.actor.getSnapshot(), invite.peerId)
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
/**
|
|
259
|
+
* Attempt to accept the invite.
|
|
260
|
+
*
|
|
261
|
+
* This can fail if the invitor has canceled the invite or if you cannot
|
|
262
|
+
* connect to the invitor's device.
|
|
263
|
+
*
|
|
264
|
+
* If the invite is accepted and you had other invites to the same project,
|
|
265
|
+
* those invites are removed, and the invitors are told that you're already
|
|
266
|
+
* part of this project.
|
|
267
|
+
*
|
|
268
|
+
* @param {Pick<Invite, 'inviteId'>} invite
|
|
269
|
+
* @returns {Promise<string>}
|
|
270
|
+
*/
|
|
271
|
+
async accept({ inviteId: inviteIdString }) {
|
|
272
|
+
const inviteId = Buffer.from(inviteIdString, 'hex')
|
|
273
|
+
|
|
274
|
+
const invite = this.#invites.get(inviteId)
|
|
275
|
+
assert(!!invite, new NotFoundError(`Cannot find invite ${inviteIdString}`))
|
|
276
|
+
assertCanSend(invite.actor, { type: 'ACCEPT_INVITE' })
|
|
277
|
+
|
|
278
|
+
this.#l.log('Accepting invite %h', inviteId)
|
|
279
|
+
invite.actor.send({ type: 'ACCEPT_INVITE' })
|
|
280
|
+
|
|
281
|
+
for (const { value, actor } of this.#invites.values()) {
|
|
282
|
+
if (value.inviteId.equals(inviteId)) continue
|
|
283
|
+
const inviteIsForSameProject = value.projectInviteId.equals(
|
|
284
|
+
invite.value.projectInviteId
|
|
285
|
+
)
|
|
286
|
+
if (inviteIsForSameProject) {
|
|
287
|
+
actor.send({ type: 'ALREADY_IN_PROJECT' })
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
const { projectPublicId } = await toPromise(invite.actor)
|
|
292
|
+
|
|
293
|
+
if (!projectPublicId) {
|
|
294
|
+
const { context, value } = invite.actor.getSnapshot()
|
|
295
|
+
throw value === 'respondedAlready'
|
|
296
|
+
? new AlreadyJoinedError('Already joining or in project')
|
|
297
|
+
: context.error || new Error('Unknown error')
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
return projectPublicId
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
/**
|
|
304
|
+
* @param {Pick<Invite, 'inviteId'>} invite
|
|
305
|
+
* @returns {void}
|
|
306
|
+
*/
|
|
307
|
+
reject({ inviteId: inviteIdString }) {
|
|
308
|
+
const inviteId = Buffer.from(inviteIdString, 'hex')
|
|
309
|
+
|
|
310
|
+
const invite = this.#invites.get(inviteId)
|
|
311
|
+
assert(!!invite, `Cannot find invite ${inviteIdString}`)
|
|
312
|
+
assertCanSend(invite.actor, { type: 'REJECT_INVITE' })
|
|
313
|
+
|
|
314
|
+
this.#l.log('Rejecting invite %h', inviteId)
|
|
315
|
+
invite.actor.send({ type: 'REJECT_INVITE' })
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
/**
|
|
320
|
+
* @param {InviteInternal} internal
|
|
321
|
+
* @param {import('xstate').SnapshotFrom<invite.actor>} snapshot
|
|
322
|
+
* @param {string} invitorDeviceId
|
|
323
|
+
* @returns {Invite}
|
|
324
|
+
*/
|
|
325
|
+
function toInvite(internal, snapshot, invitorDeviceId) {
|
|
326
|
+
const state = toStateString(snapshot.value)
|
|
327
|
+
if (state === 'error') {
|
|
328
|
+
return {
|
|
329
|
+
...internal,
|
|
330
|
+
invitorDeviceId,
|
|
331
|
+
inviteId: internal.inviteId.toString('hex'),
|
|
332
|
+
projectInviteId: internal.projectInviteId.toString('hex'),
|
|
333
|
+
state,
|
|
334
|
+
error: snapshot.context.error || new Error('Unknown error'),
|
|
335
|
+
}
|
|
336
|
+
} else {
|
|
337
|
+
return {
|
|
338
|
+
...internal,
|
|
339
|
+
invitorDeviceId,
|
|
340
|
+
inviteId: internal.inviteId.toString('hex'),
|
|
341
|
+
projectInviteId: internal.projectInviteId.toString('hex'),
|
|
342
|
+
state,
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
/**
|
|
348
|
+
* Assert that a given event type can be sent to the state machine (will throw
|
|
349
|
+
* if there is no transition defined for this event type for the current state
|
|
350
|
+
* of the machine)
|
|
351
|
+
*
|
|
352
|
+
* @param {invite.actor} actor
|
|
353
|
+
* @param {import('xstate').EventFrom<invite.actor>} eventType
|
|
354
|
+
*/
|
|
355
|
+
function assertCanSend(actor, eventType) {
|
|
356
|
+
const state = actor.getSnapshot()
|
|
357
|
+
assert(
|
|
358
|
+
state.can(eventType),
|
|
359
|
+
new InviteSendError(
|
|
360
|
+
`Cannot send ${JSON.stringify(eventType)} in state ${toStateString(
|
|
361
|
+
state.value
|
|
362
|
+
)}`
|
|
363
|
+
)
|
|
364
|
+
)
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
/**
|
|
368
|
+
* @template {import('xstate').StateValue} T
|
|
369
|
+
* @typedef {T extends string ? T : T extends import('xstate').StateValueMap ? keyof T : never} ExtractStateString
|
|
370
|
+
*/
|
|
371
|
+
|
|
372
|
+
/**
|
|
373
|
+
* "Flatten" nested states into a top-level string, e.g. in our case the state
|
|
374
|
+
* `{ joining: 'awaitingDetails' }` will be flattened to `'joining'`.
|
|
375
|
+
*
|
|
376
|
+
* @template {import('xstate').StateValue} T
|
|
377
|
+
* @param {T} stateValue
|
|
378
|
+
* @returns {ExtractStateString<T>}
|
|
379
|
+
*/
|
|
380
|
+
function toStateString(stateValue) {
|
|
381
|
+
if (typeof stateValue === 'string') {
|
|
382
|
+
// @ts-expect-error - typescript limitation
|
|
383
|
+
return stateValue
|
|
384
|
+
}
|
|
385
|
+
// @ts-expect-error - typescript limitation
|
|
386
|
+
return Object.keys(stateValue)[0]
|
|
387
|
+
}
|