@dxos/credentials 0.8.3 → 0.8.4-main.05e74ebcff
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/LICENSE +102 -5
- package/README.md +1 -1
- package/dist/lib/{browser → neutral}/index.mjs +185 -379
- package/dist/lib/neutral/index.mjs.map +7 -0
- package/dist/lib/neutral/meta.json +1 -0
- package/dist/types/src/credentials/assertions.d.ts +1 -1
- package/dist/types/src/credentials/assertions.d.ts.map +1 -1
- package/dist/types/src/credentials/credential-factory.d.ts +4 -4
- package/dist/types/src/credentials/credential-factory.d.ts.map +1 -1
- package/dist/types/src/credentials/credential-generator.d.ts +3 -3
- package/dist/types/src/credentials/credential-generator.d.ts.map +1 -1
- package/dist/types/src/credentials/signing.d.ts.map +1 -1
- package/dist/types/src/credentials/verifier.d.ts.map +1 -1
- package/dist/types/src/did.d.ts +1 -1
- package/dist/types/src/did.d.ts.map +1 -1
- package/dist/types/src/graph/credential-graph.d.ts.map +1 -1
- package/dist/types/src/passcode.d.ts.map +1 -1
- package/dist/types/src/presentations/presentation.d.ts.map +1 -1
- package/dist/types/src/presentations/signing.d.ts.map +1 -1
- package/dist/types/src/presentations/verifier.d.ts.map +1 -1
- package/dist/types/src/processor/device-state-machine.d.ts +2 -2
- package/dist/types/src/processor/device-state-machine.d.ts.map +1 -1
- package/dist/types/src/processor/index.d.ts +1 -1
- package/dist/types/src/processor/index.d.ts.map +1 -1
- package/dist/types/src/processor/profile-state-machine.d.ts +2 -2
- package/dist/types/src/processor/profile-state-machine.d.ts.map +1 -1
- package/dist/types/src/seedphrase.d.ts.map +1 -1
- package/dist/types/src/state-machine/feed-state-machine.d.ts.map +1 -1
- package/dist/types/src/state-machine/invitation-state-machine.d.ts.map +1 -1
- package/dist/types/src/state-machine/member-state-machine.d.ts +1 -1
- package/dist/types/src/state-machine/member-state-machine.d.ts.map +1 -1
- package/dist/types/src/state-machine/space-state-machine.d.ts +8 -2
- package/dist/types/src/state-machine/space-state-machine.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/docs/README.md +17 -17
- package/moon.yml +12 -0
- package/package.json +21 -24
- package/src/credentials/assertions.ts +1 -1
- package/src/credentials/credential-factory.ts +5 -5
- package/src/credentials/credential-generator.ts +6 -1
- package/src/credentials/signing.ts +12 -0
- package/src/did.ts +2 -2
- package/src/presentations/json-encoding.test.ts +1 -1
- package/src/presentations/presentation.ts +1 -1
- package/src/presentations/verifier.test.ts +1 -1
- package/src/presentations/verifier.ts +1 -1
- package/src/processor/device-state-machine.ts +3 -3
- package/src/processor/index.ts +1 -1
- package/src/processor/profile-state-machine.ts +3 -3
- package/src/state-machine/invitation-state-machine.test.ts +2 -2
- package/src/state-machine/member-state-machine.test.ts +1 -1
- package/src/state-machine/member-state-machine.ts +1 -1
- package/src/state-machine/space-state-machine.test.ts +244 -2
- package/src/state-machine/space-state-machine.ts +33 -9
- package/vitest.config.ts +7 -3
- package/.eslintrc.cjs +0 -7
- package/dist/lib/browser/index.mjs.map +0 -7
- package/dist/lib/browser/meta.json +0 -1
- package/dist/lib/node/index.cjs +0 -1894
- package/dist/lib/node/index.cjs.map +0 -7
- package/dist/lib/node/meta.json +0 -1
- package/dist/lib/node-esm/index.mjs +0 -1870
- package/dist/lib/node-esm/index.mjs.map +0 -7
- package/dist/lib/node-esm/meta.json +0 -1
- package/project.json +0 -27
|
@@ -6,10 +6,10 @@ import { describe, expect, test } from 'vitest';
|
|
|
6
6
|
|
|
7
7
|
import { Keyring } from '@dxos/keyring';
|
|
8
8
|
import { type PublicKey } from '@dxos/keys';
|
|
9
|
-
import { AdmittedFeed, type Chain, SpaceMember } from '@dxos/protocols/proto/dxos/halo/credentials';
|
|
9
|
+
import { AdmittedFeed, type Chain, MembershipPolicy, SpaceMember } from '@dxos/protocols/proto/dxos/halo/credentials';
|
|
10
10
|
|
|
11
|
-
import { SpaceStateMachine } from './space-state-machine';
|
|
12
11
|
import { createCredential, verifyCredential } from '../credentials';
|
|
12
|
+
import { SpaceStateMachine } from './space-state-machine';
|
|
13
13
|
|
|
14
14
|
describe('SpaceStateMachine', () => {
|
|
15
15
|
test('basic space creation', async () => {
|
|
@@ -29,6 +29,7 @@ describe('SpaceStateMachine', () => {
|
|
|
29
29
|
assertion: {
|
|
30
30
|
'@type': 'dxos.halo.credentials.SpaceGenesis',
|
|
31
31
|
spaceKey: space,
|
|
32
|
+
membershipPolicy: MembershipPolicy.INVITE,
|
|
32
33
|
},
|
|
33
34
|
signer: keyring,
|
|
34
35
|
}),
|
|
@@ -129,6 +130,7 @@ describe('SpaceStateMachine', () => {
|
|
|
129
130
|
assertion: {
|
|
130
131
|
'@type': 'dxos.halo.credentials.SpaceGenesis',
|
|
131
132
|
spaceKey: space,
|
|
133
|
+
membershipPolicy: MembershipPolicy.INVITE,
|
|
132
134
|
},
|
|
133
135
|
signer: keyring,
|
|
134
136
|
}),
|
|
@@ -210,6 +212,60 @@ describe('SpaceStateMachine', () => {
|
|
|
210
212
|
expect(spaceState.credentials).toHaveLength(3);
|
|
211
213
|
});
|
|
212
214
|
|
|
215
|
+
test('space genesis with tags', async () => {
|
|
216
|
+
const keyring = new Keyring();
|
|
217
|
+
const space = await keyring.createKey();
|
|
218
|
+
const identity = await keyring.createKey();
|
|
219
|
+
const feed = await keyring.createKey();
|
|
220
|
+
|
|
221
|
+
const spaceState = new SpaceStateMachine(space);
|
|
222
|
+
|
|
223
|
+
expect(spaceState.tags).toEqual([]);
|
|
224
|
+
|
|
225
|
+
expect(
|
|
226
|
+
await spaceState.process(
|
|
227
|
+
await createCredential({
|
|
228
|
+
issuer: space,
|
|
229
|
+
subject: space,
|
|
230
|
+
assertion: {
|
|
231
|
+
'@type': 'dxos.halo.credentials.SpaceGenesis',
|
|
232
|
+
spaceKey: space,
|
|
233
|
+
tags: ['personal', 'test'],
|
|
234
|
+
membershipPolicy: MembershipPolicy.INVITE,
|
|
235
|
+
},
|
|
236
|
+
signer: keyring,
|
|
237
|
+
}),
|
|
238
|
+
{ sourceFeed: feed },
|
|
239
|
+
),
|
|
240
|
+
).toEqual(true);
|
|
241
|
+
|
|
242
|
+
expect(spaceState.tags).toEqual(['personal', 'test']);
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
test('space genesis without tags returns empty array', async () => {
|
|
246
|
+
const keyring = new Keyring();
|
|
247
|
+
const space = await keyring.createKey();
|
|
248
|
+
const feed = await keyring.createKey();
|
|
249
|
+
|
|
250
|
+
const spaceState = new SpaceStateMachine(space);
|
|
251
|
+
|
|
252
|
+
await spaceState.process(
|
|
253
|
+
await createCredential({
|
|
254
|
+
issuer: space,
|
|
255
|
+
subject: space,
|
|
256
|
+
assertion: {
|
|
257
|
+
'@type': 'dxos.halo.credentials.SpaceGenesis',
|
|
258
|
+
spaceKey: space,
|
|
259
|
+
membershipPolicy: MembershipPolicy.INVITE,
|
|
260
|
+
},
|
|
261
|
+
signer: keyring,
|
|
262
|
+
}),
|
|
263
|
+
{ sourceFeed: feed },
|
|
264
|
+
);
|
|
265
|
+
|
|
266
|
+
expect(spaceState.tags).toEqual([]);
|
|
267
|
+
});
|
|
268
|
+
|
|
213
269
|
test('storing device credentials and building a chain', async () => {
|
|
214
270
|
const keyring = new Keyring();
|
|
215
271
|
const haloSpace = await keyring.createKey();
|
|
@@ -229,6 +285,7 @@ describe('SpaceStateMachine', () => {
|
|
|
229
285
|
assertion: {
|
|
230
286
|
'@type': 'dxos.halo.credentials.SpaceGenesis',
|
|
231
287
|
spaceKey: haloSpace,
|
|
288
|
+
membershipPolicy: MembershipPolicy.INVITE,
|
|
232
289
|
},
|
|
233
290
|
signer: keyring,
|
|
234
291
|
}),
|
|
@@ -338,4 +395,189 @@ describe('SpaceStateMachine', () => {
|
|
|
338
395
|
|
|
339
396
|
expect(await verifyCredential(credential)).toEqual({ kind: 'pass' });
|
|
340
397
|
});
|
|
398
|
+
|
|
399
|
+
test('space genesis with membership policy', async () => {
|
|
400
|
+
const keyring = new Keyring();
|
|
401
|
+
const space = await keyring.createKey();
|
|
402
|
+
const feed = await keyring.createKey();
|
|
403
|
+
|
|
404
|
+
const spaceState = new SpaceStateMachine(space);
|
|
405
|
+
|
|
406
|
+
await spaceState.process(
|
|
407
|
+
await createCredential({
|
|
408
|
+
issuer: space,
|
|
409
|
+
subject: space,
|
|
410
|
+
assertion: {
|
|
411
|
+
'@type': 'dxos.halo.credentials.SpaceGenesis',
|
|
412
|
+
spaceKey: space,
|
|
413
|
+
membershipPolicy: MembershipPolicy.LOCKED,
|
|
414
|
+
},
|
|
415
|
+
signer: keyring,
|
|
416
|
+
}),
|
|
417
|
+
{ sourceFeed: feed },
|
|
418
|
+
);
|
|
419
|
+
|
|
420
|
+
expect(spaceState.membershipPolicy).toEqual(MembershipPolicy.LOCKED);
|
|
421
|
+
});
|
|
422
|
+
|
|
423
|
+
test('space genesis without membership policy defaults to INVITE', async () => {
|
|
424
|
+
const keyring = new Keyring();
|
|
425
|
+
const space = await keyring.createKey();
|
|
426
|
+
const feed = await keyring.createKey();
|
|
427
|
+
|
|
428
|
+
const spaceState = new SpaceStateMachine(space);
|
|
429
|
+
|
|
430
|
+
// MembershipPolicy.INVITE is the proto zero-value default.
|
|
431
|
+
// Existing spaces without the field will have this value.
|
|
432
|
+
await spaceState.process(
|
|
433
|
+
await createCredential({
|
|
434
|
+
issuer: space,
|
|
435
|
+
subject: space,
|
|
436
|
+
assertion: {
|
|
437
|
+
'@type': 'dxos.halo.credentials.SpaceGenesis',
|
|
438
|
+
spaceKey: space,
|
|
439
|
+
membershipPolicy: MembershipPolicy.INVITE,
|
|
440
|
+
},
|
|
441
|
+
signer: keyring,
|
|
442
|
+
}),
|
|
443
|
+
{ sourceFeed: feed },
|
|
444
|
+
);
|
|
445
|
+
|
|
446
|
+
expect(spaceState.membershipPolicy).toEqual(MembershipPolicy.INVITE);
|
|
447
|
+
});
|
|
448
|
+
|
|
449
|
+
test('locked space rejects new members', async ({ expect }) => {
|
|
450
|
+
const keyring = new Keyring();
|
|
451
|
+
const space = await keyring.createKey();
|
|
452
|
+
const identity = await keyring.createKey();
|
|
453
|
+
const identity2 = await keyring.createKey();
|
|
454
|
+
const feed = await keyring.createKey();
|
|
455
|
+
|
|
456
|
+
const spaceState = new SpaceStateMachine(space);
|
|
457
|
+
|
|
458
|
+
await spaceState.process(
|
|
459
|
+
await createCredential({
|
|
460
|
+
issuer: space,
|
|
461
|
+
subject: space,
|
|
462
|
+
assertion: {
|
|
463
|
+
'@type': 'dxos.halo.credentials.SpaceGenesis',
|
|
464
|
+
spaceKey: space,
|
|
465
|
+
membershipPolicy: MembershipPolicy.LOCKED,
|
|
466
|
+
},
|
|
467
|
+
signer: keyring,
|
|
468
|
+
}),
|
|
469
|
+
{ sourceFeed: feed },
|
|
470
|
+
);
|
|
471
|
+
|
|
472
|
+
await spaceState.process(
|
|
473
|
+
await createCredential({
|
|
474
|
+
issuer: space,
|
|
475
|
+
subject: identity,
|
|
476
|
+
assertion: {
|
|
477
|
+
'@type': 'dxos.halo.credentials.SpaceMember',
|
|
478
|
+
spaceKey: space,
|
|
479
|
+
role: SpaceMember.Role.OWNER,
|
|
480
|
+
genesisFeedKey: feed,
|
|
481
|
+
},
|
|
482
|
+
signer: keyring,
|
|
483
|
+
}),
|
|
484
|
+
{ sourceFeed: feed },
|
|
485
|
+
);
|
|
486
|
+
|
|
487
|
+
// Attempt to add a second member — should be rejected.
|
|
488
|
+
expect(
|
|
489
|
+
await spaceState.process(
|
|
490
|
+
await createCredential({
|
|
491
|
+
issuer: space,
|
|
492
|
+
subject: identity2,
|
|
493
|
+
assertion: {
|
|
494
|
+
'@type': 'dxos.halo.credentials.SpaceMember',
|
|
495
|
+
spaceKey: space,
|
|
496
|
+
role: SpaceMember.Role.EDITOR,
|
|
497
|
+
genesisFeedKey: feed,
|
|
498
|
+
},
|
|
499
|
+
signer: keyring,
|
|
500
|
+
}),
|
|
501
|
+
{ sourceFeed: feed },
|
|
502
|
+
),
|
|
503
|
+
).toEqual(false);
|
|
504
|
+
|
|
505
|
+
expect(spaceState.members.size).toEqual(1);
|
|
506
|
+
});
|
|
507
|
+
|
|
508
|
+
test('locked space allows admitted feeds for existing members', async ({ expect }) => {
|
|
509
|
+
const keyring = new Keyring();
|
|
510
|
+
const space = await keyring.createKey();
|
|
511
|
+
const identity = await keyring.createKey();
|
|
512
|
+
const device = await keyring.createKey();
|
|
513
|
+
const feed = await keyring.createKey();
|
|
514
|
+
const newFeed = await keyring.createKey();
|
|
515
|
+
|
|
516
|
+
const spaceState = new SpaceStateMachine(space);
|
|
517
|
+
|
|
518
|
+
await spaceState.process(
|
|
519
|
+
await createCredential({
|
|
520
|
+
issuer: space,
|
|
521
|
+
subject: space,
|
|
522
|
+
assertion: {
|
|
523
|
+
'@type': 'dxos.halo.credentials.SpaceGenesis',
|
|
524
|
+
spaceKey: space,
|
|
525
|
+
membershipPolicy: MembershipPolicy.LOCKED,
|
|
526
|
+
},
|
|
527
|
+
signer: keyring,
|
|
528
|
+
}),
|
|
529
|
+
{ sourceFeed: feed },
|
|
530
|
+
);
|
|
531
|
+
|
|
532
|
+
await spaceState.process(
|
|
533
|
+
await createCredential({
|
|
534
|
+
issuer: space,
|
|
535
|
+
subject: identity,
|
|
536
|
+
assertion: {
|
|
537
|
+
'@type': 'dxos.halo.credentials.SpaceMember',
|
|
538
|
+
spaceKey: space,
|
|
539
|
+
role: SpaceMember.Role.OWNER,
|
|
540
|
+
genesisFeedKey: feed,
|
|
541
|
+
},
|
|
542
|
+
signer: keyring,
|
|
543
|
+
}),
|
|
544
|
+
{ sourceFeed: feed },
|
|
545
|
+
);
|
|
546
|
+
|
|
547
|
+
const chain: Chain = {
|
|
548
|
+
credential: await createCredential({
|
|
549
|
+
assertion: {
|
|
550
|
+
'@type': 'dxos.halo.credentials.AuthorizedDevice',
|
|
551
|
+
deviceKey: device,
|
|
552
|
+
identityKey: identity,
|
|
553
|
+
},
|
|
554
|
+
subject: device,
|
|
555
|
+
issuer: identity,
|
|
556
|
+
signer: keyring,
|
|
557
|
+
}),
|
|
558
|
+
};
|
|
559
|
+
|
|
560
|
+
// AdmittedFeed should still work on locked space.
|
|
561
|
+
expect(
|
|
562
|
+
await spaceState.process(
|
|
563
|
+
await createCredential({
|
|
564
|
+
issuer: identity,
|
|
565
|
+
subject: newFeed,
|
|
566
|
+
assertion: {
|
|
567
|
+
'@type': 'dxos.halo.credentials.AdmittedFeed',
|
|
568
|
+
spaceKey: space,
|
|
569
|
+
identityKey: identity,
|
|
570
|
+
deviceKey: device,
|
|
571
|
+
designation: AdmittedFeed.Designation.CONTROL,
|
|
572
|
+
},
|
|
573
|
+
signer: keyring,
|
|
574
|
+
signingKey: device,
|
|
575
|
+
chain,
|
|
576
|
+
}),
|
|
577
|
+
{ sourceFeed: feed },
|
|
578
|
+
),
|
|
579
|
+
).toEqual(true);
|
|
580
|
+
|
|
581
|
+
expect(spaceState.feeds.size).toEqual(1);
|
|
582
|
+
});
|
|
341
583
|
});
|
|
@@ -7,15 +7,15 @@ import { Context } from '@dxos/context';
|
|
|
7
7
|
import { PublicKey } from '@dxos/keys';
|
|
8
8
|
import { log } from '@dxos/log';
|
|
9
9
|
import { type TypedMessage } from '@dxos/protocols/proto';
|
|
10
|
-
import { type Credential, SpaceMember } from '@dxos/protocols/proto/dxos/halo/credentials';
|
|
10
|
+
import { type Credential, MembershipPolicy, SpaceMember } from '@dxos/protocols/proto/dxos/halo/credentials';
|
|
11
11
|
import { type DelegateSpaceInvitation } from '@dxos/protocols/proto/dxos/halo/invitations';
|
|
12
12
|
import { type AsyncCallback, Callback, ComplexMap, ComplexSet } from '@dxos/util';
|
|
13
13
|
|
|
14
|
-
import { type FeedInfo, FeedStateMachine } from './feed-state-machine';
|
|
15
|
-
import { InvitationStateMachine } from './invitation-state-machine';
|
|
16
|
-
import { MemberStateMachine, type MemberInfo } from './member-state-machine';
|
|
17
14
|
import { getCredentialAssertion, verifyCredential } from '../credentials';
|
|
18
15
|
import { type CredentialProcessor } from '../processor/credential-processor';
|
|
16
|
+
import { type FeedInfo, FeedStateMachine } from './feed-state-machine';
|
|
17
|
+
import { InvitationStateMachine } from './invitation-state-machine';
|
|
18
|
+
import { type MemberInfo, MemberStateMachine } from './member-state-machine';
|
|
19
19
|
|
|
20
20
|
export interface SpaceState {
|
|
21
21
|
readonly members: ReadonlyMap<PublicKey, MemberInfo>;
|
|
@@ -23,6 +23,8 @@ export interface SpaceState {
|
|
|
23
23
|
readonly feeds: ReadonlyMap<PublicKey, FeedInfo>;
|
|
24
24
|
readonly credentials: Credential[];
|
|
25
25
|
readonly genesisCredential: Credential | undefined;
|
|
26
|
+
readonly tags: string[];
|
|
27
|
+
readonly membershipPolicy: MembershipPolicy;
|
|
26
28
|
readonly creator: MemberInfo | undefined;
|
|
27
29
|
readonly invitations: ReadonlyMap<PublicKey, DelegateSpaceInvitation>;
|
|
28
30
|
|
|
@@ -52,23 +54,30 @@ export type CredentialEntry = {
|
|
|
52
54
|
* Keeps and in-memory index of credentials and allows to query them.
|
|
53
55
|
*/
|
|
54
56
|
export class SpaceStateMachine implements SpaceState {
|
|
55
|
-
private readonly _members
|
|
56
|
-
private readonly _feeds
|
|
57
|
+
private readonly _members: MemberStateMachine;
|
|
58
|
+
private readonly _feeds: FeedStateMachine;
|
|
57
59
|
private readonly _invitations = new InvitationStateMachine();
|
|
58
60
|
private readonly _credentials: CredentialEntry[] = [];
|
|
59
61
|
private readonly _credentialsById = new ComplexMap<PublicKey, CredentialEntry>(PublicKey.hash);
|
|
60
62
|
private readonly _processedCredentials = new ComplexSet<PublicKey>(PublicKey.hash);
|
|
61
63
|
|
|
62
64
|
private _genesisCredential: Credential | undefined;
|
|
65
|
+
private _tags: string[] = [];
|
|
66
|
+
private _membershipPolicy: MembershipPolicy = MembershipPolicy.INVITE;
|
|
63
67
|
private _credentialProcessors: CredentialConsumer<any>[] = [];
|
|
64
68
|
|
|
65
69
|
readonly onCredentialProcessed = new Callback<AsyncCallback<Credential>>();
|
|
66
|
-
readonly onMemberRoleChanged
|
|
67
|
-
readonly onFeedAdmitted
|
|
70
|
+
readonly onMemberRoleChanged: Callback<AsyncCallback<MemberInfo[]>>;
|
|
71
|
+
readonly onFeedAdmitted: Callback<AsyncCallback<FeedInfo>>;
|
|
68
72
|
readonly onDelegatedInvitation = this._invitations.onDelegatedInvitation;
|
|
69
73
|
readonly onDelegatedInvitationRemoved = this._invitations.onDelegatedInvitationRemoved;
|
|
70
74
|
|
|
71
|
-
constructor(private readonly _spaceKey: PublicKey) {
|
|
75
|
+
constructor(private readonly _spaceKey: PublicKey) {
|
|
76
|
+
this._members = new MemberStateMachine(this._spaceKey);
|
|
77
|
+
this._feeds = new FeedStateMachine(this._spaceKey);
|
|
78
|
+
this.onMemberRoleChanged = this._members.onMemberRoleChanged;
|
|
79
|
+
this.onFeedAdmitted = this._feeds.onFeedAdmitted;
|
|
80
|
+
}
|
|
72
81
|
|
|
73
82
|
get creator(): MemberInfo | undefined {
|
|
74
83
|
return this._members.creator;
|
|
@@ -98,6 +107,14 @@ export class SpaceStateMachine implements SpaceState {
|
|
|
98
107
|
return this._genesisCredential;
|
|
99
108
|
}
|
|
100
109
|
|
|
110
|
+
get tags(): string[] {
|
|
111
|
+
return this._tags;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
get membershipPolicy(): MembershipPolicy {
|
|
115
|
+
return this._membershipPolicy;
|
|
116
|
+
}
|
|
117
|
+
|
|
101
118
|
get invitations(): ReadonlyMap<PublicKey, DelegateSpaceInvitation> {
|
|
102
119
|
return this._invitations.invitations;
|
|
103
120
|
}
|
|
@@ -174,6 +191,8 @@ export class SpaceStateMachine implements SpaceState {
|
|
|
174
191
|
return false;
|
|
175
192
|
}
|
|
176
193
|
this._genesisCredential = credential;
|
|
194
|
+
this._tags = assertion.tags ?? [];
|
|
195
|
+
this._membershipPolicy = assertion.membershipPolicy ?? MembershipPolicy.INVITE;
|
|
177
196
|
break;
|
|
178
197
|
}
|
|
179
198
|
|
|
@@ -254,6 +273,11 @@ export class SpaceStateMachine implements SpaceState {
|
|
|
254
273
|
}
|
|
255
274
|
|
|
256
275
|
private _canInviteNewMembers(key: PublicKey): boolean {
|
|
276
|
+
if (this._membershipPolicy === MembershipPolicy.LOCKED) {
|
|
277
|
+
// When locked, only the space key can add the initial owner during genesis.
|
|
278
|
+
// Once a member exists, no new members can be added.
|
|
279
|
+
return key.equals(this._spaceKey) && this._members.members.size === 0;
|
|
280
|
+
}
|
|
257
281
|
return (
|
|
258
282
|
key.equals(this._spaceKey) ||
|
|
259
283
|
this._members.getRole(key) === SpaceMember.Role.ADMIN ||
|
package/vitest.config.ts
CHANGED
|
@@ -2,8 +2,12 @@
|
|
|
2
2
|
// Copyright 2024 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import
|
|
5
|
+
import path from 'node:path';
|
|
6
|
+
import { fileURLToPath } from 'node:url';
|
|
6
7
|
|
|
7
|
-
import {
|
|
8
|
+
import { createConfig } from '../../../../vitest.base.config';
|
|
8
9
|
|
|
9
|
-
export default
|
|
10
|
+
export default createConfig({
|
|
11
|
+
dirname: typeof __dirname !== 'undefined' ? __dirname : path.dirname(fileURLToPath(import.meta.url)),
|
|
12
|
+
node: true,
|
|
13
|
+
});
|