@dxos/echo-db 2.33.4-dev.faf06c70 → 2.33.5-dev.1fc05a51
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/src/api/selection/queries.d.ts.map +1 -1
- package/dist/src/api/selection/queries.js +13 -17
- package/dist/src/api/selection/queries.js.map +1 -1
- package/dist/src/api/selection/selection.d.ts.map +1 -1
- package/dist/src/api/selection/selection.js +1 -3
- package/dist/src/api/selection/selection.js.map +1 -1
- package/dist/src/api/selection/selection.test.js +4 -12
- package/dist/src/api/selection/selection.test.js.map +1 -1
- package/dist/src/database/item-demuxer.d.ts +1 -1
- package/dist/src/database/item-demuxer.d.ts.map +1 -1
- package/dist/src/database/item-demuxer.js +3 -5
- package/dist/src/database/item-demuxer.js.map +1 -1
- package/dist/src/database/item-manager.js +2 -2
- package/dist/src/database/item-manager.js.map +1 -1
- package/dist/src/database/testing.js +1 -1
- package/dist/src/database/testing.js.map +1 -1
- package/dist/src/echo.d.ts +5 -12
- package/dist/src/echo.d.ts.map +1 -1
- package/dist/src/echo.js +9 -20
- package/dist/src/echo.js.map +1 -1
- package/dist/src/halo/halo-factory.d.ts.map +1 -1
- package/dist/src/halo/halo-factory.js +5 -11
- package/dist/src/halo/halo-factory.js.map +1 -1
- package/dist/src/halo/halo-party.d.ts +3 -3
- package/dist/src/halo/halo-party.d.ts.map +1 -1
- package/dist/src/halo/halo-party.js +6 -4
- package/dist/src/halo/halo-party.js.map +1 -1
- package/dist/src/halo/halo.test.js +5 -4
- package/dist/src/halo/halo.test.js.map +1 -1
- package/dist/src/halo/identity.js +2 -2
- package/dist/src/halo/identity.js.map +1 -1
- package/dist/src/halo/party-opener.d.ts +1 -1
- package/dist/src/halo/party-opener.d.ts.map +1 -1
- package/dist/src/halo/party-opener.js +2 -2
- package/dist/src/halo/party-opener.js.map +1 -1
- package/dist/src/halo/preferences.d.ts.map +1 -1
- package/dist/src/halo/preferences.js +7 -10
- package/dist/src/halo/preferences.js.map +1 -1
- package/dist/src/index.d.ts +0 -1
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +0 -1
- package/dist/src/index.js.map +1 -1
- package/dist/src/invitations/greeting-protocol-provider.d.ts.map +1 -1
- package/dist/src/invitations/greeting-protocol-provider.js +5 -9
- package/dist/src/invitations/greeting-protocol-provider.js.map +1 -1
- package/dist/src/invitations/greeting-responder.d.ts +2 -2
- package/dist/src/invitations/greeting-responder.d.ts.map +1 -1
- package/dist/src/invitations/greeting-responder.js +8 -12
- package/dist/src/invitations/greeting-responder.js.map +1 -1
- package/dist/src/invitations/invitation-factory.d.ts +2 -2
- package/dist/src/invitations/invitation-factory.d.ts.map +1 -1
- package/dist/src/invitations/invitation-factory.js.map +1 -1
- package/dist/src/invitations/offline-invitation-claimer.d.ts.map +1 -1
- package/dist/src/invitations/offline-invitation-claimer.js +5 -7
- package/dist/src/invitations/offline-invitation-claimer.js.map +1 -1
- package/dist/src/parties/data-party.d.ts +7 -5
- package/dist/src/parties/data-party.d.ts.map +1 -1
- package/dist/src/parties/data-party.js +12 -9
- package/dist/src/parties/data-party.js.map +1 -1
- package/dist/src/parties/data-party.test.js +16 -16
- package/dist/src/parties/data-party.test.js.map +1 -1
- package/dist/src/parties/party-factory.d.ts +0 -6
- package/dist/src/parties/party-factory.d.ts.map +1 -1
- package/dist/src/parties/party-factory.js +17 -45
- package/dist/src/parties/party-factory.js.map +1 -1
- package/dist/src/parties/party-manager.d.ts.map +1 -1
- package/dist/src/parties/party-manager.js +2 -1
- package/dist/src/parties/party-manager.js.map +1 -1
- package/dist/src/parties/party-manager.test.js +7 -7
- package/dist/src/parties/party-manager.test.js.map +1 -1
- package/dist/src/pipeline/message-selector.d.ts +2 -2
- package/dist/src/pipeline/message-selector.d.ts.map +1 -1
- package/dist/src/pipeline/message-selector.js +29 -39
- package/dist/src/pipeline/message-selector.js.map +1 -1
- package/dist/src/pipeline/metadata-store.d.ts +3 -3
- package/dist/src/pipeline/metadata-store.d.ts.map +1 -1
- package/dist/src/pipeline/metadata-store.js +5 -5
- package/dist/src/pipeline/metadata-store.js.map +1 -1
- package/dist/src/pipeline/metadata-store.test.js +9 -5
- package/dist/src/pipeline/metadata-store.test.js.map +1 -1
- package/dist/src/pipeline/party-core.d.ts +3 -2
- package/dist/src/pipeline/party-core.d.ts.map +1 -1
- package/dist/src/pipeline/party-core.js +5 -0
- package/dist/src/pipeline/party-core.js.map +1 -1
- package/dist/src/pipeline/party-core.test.js +17 -43
- package/dist/src/pipeline/party-core.test.js.map +1 -1
- package/dist/src/pipeline/party-processor.d.ts +23 -5
- package/dist/src/pipeline/party-processor.d.ts.map +1 -1
- package/dist/src/pipeline/party-processor.js.map +1 -1
- package/dist/src/pipeline/pipeline.d.ts +2 -4
- package/dist/src/pipeline/pipeline.d.ts.map +1 -1
- package/dist/src/pipeline/pipeline.js +0 -3
- package/dist/src/pipeline/pipeline.js.map +1 -1
- package/dist/src/pipeline/pipeline.test.js +2 -2
- package/dist/src/pipeline/pipeline.test.js.map +1 -1
- package/dist/src/protocol/auth-plugin.d.ts +1 -1
- package/dist/src/protocol/auth-plugin.d.ts.map +1 -1
- package/dist/src/protocol/auth-plugin.js +1 -3
- package/dist/src/protocol/auth-plugin.js.map +1 -1
- package/dist/src/protocol/authenticator.d.ts +2 -2
- package/dist/src/protocol/authenticator.d.ts.map +1 -1
- package/dist/src/protocol/authenticator.js +12 -16
- package/dist/src/protocol/authenticator.js.map +1 -1
- package/dist/src/protocol/halo-recovery-plugin.d.ts +1 -1
- package/dist/src/protocol/halo-recovery-plugin.d.ts.map +1 -1
- package/dist/src/protocol/halo-recovery-plugin.js +1 -3
- package/dist/src/protocol/halo-recovery-plugin.js.map +1 -1
- package/dist/src/protocol/identity-credentials.d.ts +2 -2
- package/dist/src/protocol/identity-credentials.d.ts.map +1 -1
- package/dist/src/protocol/identity-credentials.js +4 -4
- package/dist/src/protocol/identity-credentials.js.map +1 -1
- package/dist/src/protocol/offline-invitation-plugin.d.ts +1 -1
- package/dist/src/protocol/offline-invitation-plugin.d.ts.map +1 -1
- package/dist/src/protocol/offline-invitation-plugin.js +1 -3
- package/dist/src/protocol/offline-invitation-plugin.js.map +1 -1
- package/dist/src/protocol/party-protocol-factory.d.ts +1 -14
- package/dist/src/protocol/party-protocol-factory.d.ts.map +1 -1
- package/dist/src/protocol/party-protocol-factory.js +2 -55
- package/dist/src/protocol/party-protocol-factory.js.map +1 -1
- package/dist/src/protocol/replicator-plugin.d.ts +7 -0
- package/dist/src/protocol/replicator-plugin.d.ts.map +1 -0
- package/dist/src/protocol/replicator-plugin.js +36 -0
- package/dist/src/protocol/replicator-plugin.js.map +1 -0
- package/dist/src/snapshots/snapshot-generator.d.ts +1 -1
- package/dist/src/snapshots/snapshot-generator.d.ts.map +1 -1
- package/dist/src/snapshots/snapshot-generator.js +13 -15
- package/dist/src/snapshots/snapshot-generator.js.map +1 -1
- package/dist/src/snapshots/snapshot-store.d.ts +3 -3
- package/dist/src/snapshots/snapshot-store.d.ts.map +1 -1
- package/dist/src/snapshots/snapshot-store.js +5 -5
- package/dist/src/snapshots/snapshot-store.js.map +1 -1
- package/dist/src/snapshots/snapshot-store.test.js +2 -2
- package/dist/src/snapshots/snapshot-store.test.js.map +1 -1
- package/dist/src/testing/benchmark.test.d.ts +2 -0
- package/dist/src/testing/benchmark.test.d.ts.map +1 -0
- package/dist/src/testing/benchmark.test.js +25 -0
- package/dist/src/testing/benchmark.test.js.map +1 -0
- package/dist/src/testing/testing-factories.js +2 -2
- package/dist/src/testing/testing-factories.js.map +1 -1
- package/dist/src/testing/testing.d.ts +3 -4
- package/dist/src/testing/testing.d.ts.map +1 -1
- package/dist/src/testing/testing.js +3 -4
- package/dist/src/testing/testing.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +21 -21
- package/src/api/selection/queries.ts +14 -18
- package/src/api/selection/selection.test.ts +4 -12
- package/src/api/selection/selection.ts +1 -7
- package/src/database/item-demuxer.ts +2 -4
- package/src/database/item-manager.ts +2 -2
- package/src/database/testing.ts +1 -1
- package/src/echo.ts +13 -35
- package/src/halo/halo-factory.ts +6 -18
- package/src/halo/halo-party.ts +8 -7
- package/src/halo/halo.test.ts +5 -4
- package/src/halo/identity.ts +2 -2
- package/src/halo/party-opener.ts +2 -2
- package/src/halo/preferences.ts +7 -10
- package/src/index.ts +0 -1
- package/src/invitations/greeting-protocol-provider.ts +5 -9
- package/src/invitations/greeting-responder.ts +10 -14
- package/src/invitations/invitation-factory.ts +2 -2
- package/src/invitations/offline-invitation-claimer.ts +5 -7
- package/src/parties/data-party.test.ts +17 -16
- package/src/parties/data-party.ts +17 -13
- package/src/parties/party-factory.ts +23 -69
- package/src/parties/party-manager.test.ts +9 -7
- package/src/parties/party-manager.ts +2 -1
- package/src/pipeline/message-selector.ts +31 -44
- package/src/pipeline/metadata-store.test.ts +9 -5
- package/src/pipeline/metadata-store.ts +5 -5
- package/src/pipeline/party-core.test.ts +19 -60
- package/src/pipeline/party-core.ts +7 -2
- package/src/pipeline/party-processor.ts +26 -2
- package/src/pipeline/pipeline.test.ts +2 -2
- package/src/pipeline/pipeline.ts +2 -6
- package/src/protocol/auth-plugin.ts +1 -3
- package/src/protocol/authenticator.ts +27 -31
- package/src/protocol/halo-recovery-plugin.ts +4 -6
- package/src/protocol/identity-credentials.ts +4 -4
- package/src/protocol/offline-invitation-plugin.ts +4 -6
- package/src/protocol/party-protocol-factory.ts +3 -56
- package/src/protocol/replicator-plugin.ts +37 -0
- package/src/snapshots/snapshot-generator.ts +12 -16
- package/src/snapshots/snapshot-store.test.ts +2 -2
- package/src/snapshots/snapshot-store.ts +5 -6
- package/src/testing/benchmark.test.ts +30 -0
- package/src/testing/testing-factories.ts +2 -2
- package/src/testing/testing.ts +4 -8
- package/dist/src/util/index.d.ts +0 -2
- package/dist/src/util/index.d.ts.map +0 -1
- package/dist/src/util/index.js +0 -17
- package/dist/src/util/index.js.map +0 -1
- package/dist/src/util/persistant-ram-storage.d.ts +0 -6
- package/dist/src/util/persistant-ram-storage.d.ts.map +0 -1
- package/dist/src/util/persistant-ram-storage.js +0 -32
- package/dist/src/util/persistant-ram-storage.js.map +0 -1
- package/src/util/index.ts +0 -5
- package/src/util/persistant-ram-storage.ts +0 -33
|
@@ -5,10 +5,10 @@
|
|
|
5
5
|
import assert from 'assert';
|
|
6
6
|
|
|
7
7
|
import { synchronized } from '@dxos/async';
|
|
8
|
-
import { KeyHint, KeyType } from '@dxos/credentials';
|
|
8
|
+
import { KeyHint, KeyType, Message as HaloMessage } from '@dxos/credentials';
|
|
9
9
|
import { PublicKey } from '@dxos/crypto';
|
|
10
10
|
import { timed } from '@dxos/debug';
|
|
11
|
-
import { createFeedWriter, DatabaseSnapshot, PartyKey, PartySnapshot, Timeframe } from '@dxos/echo-protocol';
|
|
11
|
+
import { createFeedWriter, DatabaseSnapshot, PartyKey, PartySnapshot, Timeframe, WriteReceipt } from '@dxos/echo-protocol';
|
|
12
12
|
import { ModelFactory } from '@dxos/model-factory';
|
|
13
13
|
import { SubscriptionGroup } from '@dxos/util';
|
|
14
14
|
|
|
@@ -202,6 +202,11 @@ export class PartyCore {
|
|
|
202
202
|
return this;
|
|
203
203
|
}
|
|
204
204
|
|
|
205
|
+
writeCredentialsMessage (message: HaloMessage): Promise<WriteReceipt> {
|
|
206
|
+
assert(this._partyProcessor, 'Party not open');
|
|
207
|
+
return this._partyProcessor?.writeHaloMessage(message);
|
|
208
|
+
}
|
|
209
|
+
|
|
205
210
|
/**
|
|
206
211
|
* Create a snapshot of the current state.
|
|
207
212
|
*/
|
|
@@ -12,7 +12,8 @@ import {
|
|
|
12
12
|
PartyState,
|
|
13
13
|
Message as HaloMessage,
|
|
14
14
|
IdentityEventType,
|
|
15
|
-
PartyEventType
|
|
15
|
+
PartyEventType,
|
|
16
|
+
SignedMessage
|
|
16
17
|
} from '@dxos/credentials';
|
|
17
18
|
import { PublicKey } from '@dxos/crypto';
|
|
18
19
|
import { FeedKey, FeedWriter, IHaloStream, PartyKey, HaloStateSnapshot, WriteReceipt } from '@dxos/echo-protocol';
|
|
@@ -20,10 +21,33 @@ import { jsonReplacer } from '@dxos/util';
|
|
|
20
21
|
|
|
21
22
|
const log = debug('dxos:echo-db:party-processor');
|
|
22
23
|
|
|
24
|
+
export interface CredentialWriter {
|
|
25
|
+
writeHaloMessage (message: HaloMessage): Promise<WriteReceipt>
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export interface CredentialProcessor {
|
|
29
|
+
processMessage (message: IHaloStream): Promise<void>
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export interface PartyStateProvider {
|
|
33
|
+
partyKey: PublicKey
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Whether PartyGenesis was already processed.
|
|
37
|
+
*/
|
|
38
|
+
genesisRequired: boolean
|
|
39
|
+
memberKeys: PublicKey[]
|
|
40
|
+
feedKeys: PublicKey[]
|
|
41
|
+
getFeedOwningMember (feedKey: FeedKey): PublicKey | undefined
|
|
42
|
+
isFeedAdmitted (feedKey: FeedKey): boolean
|
|
43
|
+
|
|
44
|
+
getOfflineInvitation (invitationID: Buffer): SignedMessage | undefined
|
|
45
|
+
}
|
|
46
|
+
|
|
23
47
|
/**
|
|
24
48
|
* TODO(burdon): Wrapper/Bridge between HALO APIs.
|
|
25
49
|
*/
|
|
26
|
-
export class PartyProcessor {
|
|
50
|
+
export class PartyProcessor implements CredentialWriter, CredentialProcessor, PartyStateProvider {
|
|
27
51
|
private readonly _state: PartyState;
|
|
28
52
|
|
|
29
53
|
private _outboundHaloStream: FeedWriter<HaloMessage> | undefined;
|
|
@@ -25,7 +25,7 @@ const log = debug('dxos:echo:pipeline:test');
|
|
|
25
25
|
describe('pipeline', () => {
|
|
26
26
|
test('streams', async () => {
|
|
27
27
|
const storage = createStorage('', StorageType.RAM);
|
|
28
|
-
const feedStore = new FeedStore(storage, { valueEncoding: codec });
|
|
28
|
+
const feedStore = new FeedStore(storage.directory('feed'), { valueEncoding: codec });
|
|
29
29
|
const feedKeys: Uint8Array[] = [];
|
|
30
30
|
const feedSelector: FeedSelector = descriptor => !!feedKeys.find(key => descriptor.key.equals(key));
|
|
31
31
|
const feedReadStream = new FeedStoreIterator(feedSelector, () => 0, new Timeframe());
|
|
@@ -87,7 +87,7 @@ describe('pipeline', () => {
|
|
|
87
87
|
|
|
88
88
|
test('writing', async () => {
|
|
89
89
|
const storage = createStorage('', StorageType.RAM);
|
|
90
|
-
const feedStore = new FeedStore(storage, { valueEncoding: codec });
|
|
90
|
+
const feedStore = new FeedStore(storage.directory('feed'), { valueEncoding: codec });
|
|
91
91
|
const feedReadStream = new FeedStoreIterator(() => true, () => 0, new Timeframe());
|
|
92
92
|
|
|
93
93
|
const { publicKey, secretKey } = createKeyPair();
|
package/src/pipeline/pipeline.ts
CHANGED
|
@@ -17,7 +17,7 @@ import { createReadable } from '@dxos/feed-store';
|
|
|
17
17
|
import { jsonReplacer } from '@dxos/util';
|
|
18
18
|
|
|
19
19
|
import { TimeframeClock } from '../database';
|
|
20
|
-
import {
|
|
20
|
+
import { CredentialProcessor, PartyStateProvider } from './party-processor';
|
|
21
21
|
|
|
22
22
|
interface Options {
|
|
23
23
|
readLogger?: (msg: any) => void
|
|
@@ -55,17 +55,13 @@ export class Pipeline {
|
|
|
55
55
|
* @param _options
|
|
56
56
|
*/
|
|
57
57
|
constructor (
|
|
58
|
-
private readonly _partyProcessor:
|
|
58
|
+
private readonly _partyProcessor: CredentialProcessor & PartyStateProvider,
|
|
59
59
|
private readonly _feedStorIterator: FeedStoreIterator,
|
|
60
60
|
private readonly _timeframeClock: TimeframeClock,
|
|
61
61
|
private readonly _feedWriter?: FeedWriter<FeedMessage>,
|
|
62
62
|
private readonly _options: Options = {}
|
|
63
63
|
) {}
|
|
64
64
|
|
|
65
|
-
get partyKey () {
|
|
66
|
-
return this._partyProcessor.partyKey;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
65
|
get isOpen () {
|
|
70
66
|
return this._inboundEchoStream !== undefined;
|
|
71
67
|
}
|
|
@@ -9,6 +9,4 @@ import { Replicator } from '@dxos/protocol-plugin-replicator';
|
|
|
9
9
|
/**
|
|
10
10
|
* Creates authenticator network-protocol plugin that guards access to the replicator.
|
|
11
11
|
*/
|
|
12
|
-
export
|
|
13
|
-
return new AuthPlugin(peerId.asBuffer(), authenticator, [Replicator.extension]);
|
|
14
|
-
}
|
|
12
|
+
export const createAuthPlugin = (authenticator: Authenticator, peerId: PublicKey) => new AuthPlugin(peerId.asBuffer(), authenticator, [Replicator.extension]);
|
|
@@ -12,19 +12,17 @@ import { CredentialsSigner } from './credentials-signer';
|
|
|
12
12
|
|
|
13
13
|
const log = debug('dxos:echo-db:authenticator');
|
|
14
14
|
|
|
15
|
-
export
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
});
|
|
27
|
-
}
|
|
15
|
+
export const createAuthenticator = (partyProcessor: PartyProcessor, credentialsSigner: CredentialsSigner): Authenticator => new PartyAuthenticator(partyProcessor.state, async auth => {
|
|
16
|
+
if (auth.feedAdmit && auth.feedKey && !partyProcessor.isFeedAdmitted(auth.feedKey)) {
|
|
17
|
+
log(`Admitting feed of authenticated member: ${auth.feedKey}`);
|
|
18
|
+
await partyProcessor.writeHaloMessage(createEnvelopeMessage(
|
|
19
|
+
credentialsSigner.signer,
|
|
20
|
+
partyProcessor.partyKey,
|
|
21
|
+
auth.feedAdmit,
|
|
22
|
+
[credentialsSigner.getDeviceSigningKeys()]
|
|
23
|
+
));
|
|
24
|
+
}
|
|
25
|
+
});
|
|
28
26
|
|
|
29
27
|
export interface CredentialsProvider {
|
|
30
28
|
/**
|
|
@@ -33,24 +31,22 @@ export interface CredentialsProvider {
|
|
|
33
31
|
get (): Buffer
|
|
34
32
|
}
|
|
35
33
|
|
|
36
|
-
export
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
34
|
+
export const createCredentialsProvider = (credentialsSigner: CredentialsSigner, partyKey: PartyKey, feedKey: FeedKey): CredentialsProvider => ({
|
|
35
|
+
get: () => {
|
|
36
|
+
const authMessage = createAuthMessage(
|
|
37
|
+
credentialsSigner.signer,
|
|
38
|
+
partyKey,
|
|
39
|
+
credentialsSigner.getIdentityKey(),
|
|
40
|
+
credentialsSigner.getDeviceSigningKeys(),
|
|
41
|
+
feedKey,
|
|
42
|
+
undefined,
|
|
43
|
+
createFeedAdmitMessage(
|
|
40
44
|
credentialsSigner.signer,
|
|
41
45
|
partyKey,
|
|
42
|
-
credentialsSigner.getIdentityKey(),
|
|
43
|
-
credentialsSigner.getDeviceSigningKeys(),
|
|
44
46
|
feedKey,
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
)
|
|
52
|
-
);
|
|
53
|
-
return Buffer.from(codec.encode(authMessage));
|
|
54
|
-
}
|
|
55
|
-
};
|
|
56
|
-
}
|
|
47
|
+
[feedKey, credentialsSigner.getDeviceSigningKeys()]
|
|
48
|
+
)
|
|
49
|
+
);
|
|
50
|
+
return Buffer.from(codec.encode(authMessage));
|
|
51
|
+
}
|
|
52
|
+
});
|
|
@@ -12,9 +12,7 @@ import { HaloRecoveryInitiator, InvitationFactory } from '../invitations';
|
|
|
12
12
|
* Plugin is intended to be used in HALO party swarm.
|
|
13
13
|
*
|
|
14
14
|
*/
|
|
15
|
-
export
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
);
|
|
20
|
-
}
|
|
15
|
+
export const createHaloRecoveryPlugin = (identityKey: PublicKey, invitationFactory: InvitationFactory, peerId: PublicKey) => new GreetingCommandPlugin(
|
|
16
|
+
peerId.asBuffer(),
|
|
17
|
+
HaloRecoveryInitiator.createHaloInvitationClaimHandler(identityKey, invitationFactory)
|
|
18
|
+
);
|
|
@@ -25,7 +25,7 @@ export interface IdentityCredentials {
|
|
|
25
25
|
|
|
26
26
|
export type IdentityCredentialsProvider = () => IdentityCredentials | undefined
|
|
27
27
|
|
|
28
|
-
export
|
|
28
|
+
export const createTestIdentityCredentials = async (keyring: Keyring): Promise<IdentityCredentials> => {
|
|
29
29
|
const identityKey = await keyring.createKeyRecord({ type: KeyType.IDENTITY });
|
|
30
30
|
const deviceKey = await keyring.createKeyRecord({ type: KeyType.DEVICE });
|
|
31
31
|
const feedKey = await keyring.createKeyRecord({ type: KeyType.FEED });
|
|
@@ -53,9 +53,9 @@ export async function createTestIdentityCredentials (keyring: Keyring): Promise<
|
|
|
53
53
|
preferences: undefined,
|
|
54
54
|
contacts: undefined
|
|
55
55
|
};
|
|
56
|
-
}
|
|
56
|
+
};
|
|
57
57
|
|
|
58
|
-
export
|
|
58
|
+
export const deriveTestDeviceCredentials = async (identity: IdentityCredentials): Promise<IdentityCredentials> => {
|
|
59
59
|
const deviceKey = await identity.keyring.createKeyRecord({ type: KeyType.DEVICE });
|
|
60
60
|
const keyAdmit = createKeyAdmitMessage(identity.keyring, identity.identityKey.publicKey, deviceKey, [identity.identityKey]);
|
|
61
61
|
|
|
@@ -75,4 +75,4 @@ export async function deriveTestDeviceCredentials (identity: IdentityCredentials
|
|
|
75
75
|
deviceKeyChain
|
|
76
76
|
)
|
|
77
77
|
};
|
|
78
|
-
}
|
|
78
|
+
};
|
|
@@ -11,9 +11,7 @@ import { InvitationFactory, OfflineInvitationClaimer } from '../invitations';
|
|
|
11
11
|
* Creates network protocol plugin that allows peers to claim offline invitations.
|
|
12
12
|
* Plugin is intended to be used in data-party swarms.
|
|
13
13
|
*/
|
|
14
|
-
export
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
);
|
|
19
|
-
}
|
|
14
|
+
export const createOfflineInvitationPlugin = (invitationFactory: InvitationFactory, peerId: PublicKey) => new GreetingCommandPlugin(
|
|
15
|
+
peerId.asBuffer(),
|
|
16
|
+
OfflineInvitationClaimer.createOfflineInvitationClaimHandler(invitationFactory)
|
|
17
|
+
);
|
|
@@ -4,17 +4,13 @@
|
|
|
4
4
|
|
|
5
5
|
import debug from 'debug';
|
|
6
6
|
|
|
7
|
-
import { synchronized } from '@dxos/async';
|
|
8
7
|
import { discoveryKey, keyToString, PublicKey } from '@dxos/crypto';
|
|
9
|
-
import {
|
|
10
|
-
import type { HypercoreFeed } from '@dxos/feed-store';
|
|
8
|
+
import { PartyKey } from '@dxos/echo-protocol';
|
|
11
9
|
import { Protocol } from '@dxos/mesh-protocol';
|
|
12
10
|
import { MMSTTopology, NetworkManager, Plugin } from '@dxos/network-manager';
|
|
13
11
|
import { PresencePlugin } from '@dxos/protocol-plugin-presence';
|
|
14
|
-
import { Replicator } from '@dxos/protocol-plugin-replicator';
|
|
15
12
|
|
|
16
13
|
import { CredentialsProvider } from '.';
|
|
17
|
-
import { PartyFeedProvider } from '../pipeline/party-feed-provider';
|
|
18
14
|
|
|
19
15
|
const log = debug('dxos:echo-db:party-protocol-factory');
|
|
20
16
|
|
|
@@ -23,21 +19,15 @@ const log = debug('dxos:echo-db:party-protocol-factory');
|
|
|
23
19
|
*/
|
|
24
20
|
export class PartyProtocolFactory {
|
|
25
21
|
private readonly _presencePlugin = new PresencePlugin(this._peerId.asBuffer());
|
|
26
|
-
private readonly _replicatorProtocolPluginFactory: ReplicatorProtocolPluginFactory;
|
|
27
22
|
|
|
28
23
|
private _started = false;
|
|
29
24
|
|
|
30
25
|
constructor (
|
|
31
26
|
private readonly _partyKey: PartyKey,
|
|
32
27
|
private readonly _networkManager: NetworkManager,
|
|
33
|
-
private readonly _feedProvider: PartyFeedProvider,
|
|
34
28
|
private readonly _peerId: PublicKey,
|
|
35
29
|
private readonly _credentials: CredentialsProvider
|
|
36
|
-
) {
|
|
37
|
-
// Replication.
|
|
38
|
-
this._replicatorProtocolPluginFactory =
|
|
39
|
-
new ReplicatorProtocolPluginFactory(this._feedProvider);
|
|
40
|
-
}
|
|
30
|
+
) {}
|
|
41
31
|
|
|
42
32
|
async start (plugins: Plugin[]) {
|
|
43
33
|
if (this._started) {
|
|
@@ -73,9 +63,8 @@ export class PartyProtocolFactory {
|
|
|
73
63
|
await this._networkManager.leaveProtocolSwarm(this._partyKey);
|
|
74
64
|
}
|
|
75
65
|
|
|
76
|
-
private _createProtocol (channel: any, opts: {initiator: boolean}, extraPlugins: Plugin[]) {
|
|
66
|
+
private _createProtocol (channel: any, opts: { initiator: boolean }, extraPlugins: Plugin[]) {
|
|
77
67
|
const plugins: Plugin[] = [
|
|
78
|
-
...this._replicatorProtocolPluginFactory.createPlugins(),
|
|
79
68
|
...extraPlugins,
|
|
80
69
|
this._presencePlugin
|
|
81
70
|
];
|
|
@@ -118,45 +107,3 @@ export class PartyProtocolFactory {
|
|
|
118
107
|
return protocol;
|
|
119
108
|
}
|
|
120
109
|
}
|
|
121
|
-
|
|
122
|
-
/**
|
|
123
|
-
* Creates the protocol plugin for feed replication.
|
|
124
|
-
*/
|
|
125
|
-
export class ReplicatorProtocolPluginFactory {
|
|
126
|
-
constructor (
|
|
127
|
-
private readonly _feedProvider: PartyFeedProvider
|
|
128
|
-
) {}
|
|
129
|
-
|
|
130
|
-
createPlugins () {
|
|
131
|
-
return [
|
|
132
|
-
new Replicator({
|
|
133
|
-
load: async () => {
|
|
134
|
-
const feeds = this._feedProvider.getFeeds();
|
|
135
|
-
log(`Loading feeds: ${feeds.map(feed => keyToString(feed.key))}`);
|
|
136
|
-
return feeds.map((feed) => ({ discoveryKey: feed.feed.discoveryKey }));
|
|
137
|
-
},
|
|
138
|
-
|
|
139
|
-
subscribe: (addFeedToReplicatedSet: (feed: any) => void) => {
|
|
140
|
-
return this._feedProvider.feedOpened.on(async (feed) => {
|
|
141
|
-
log(`Adding feed: ${feed.key.toHex()}`);
|
|
142
|
-
addFeedToReplicatedSet({ discoveryKey: feed.feed.discoveryKey });
|
|
143
|
-
});
|
|
144
|
-
},
|
|
145
|
-
|
|
146
|
-
replicate: async (remoteFeeds, info) => {
|
|
147
|
-
// We can ignore remoteFeeds entirely, since the set of feeds we want to replicate is dictated by the Party.
|
|
148
|
-
// TODO(telackey): Why are we opening feeds? Necessary or belt/braces thinking, or because open party does it?
|
|
149
|
-
const feeds = this._feedProvider.getFeeds();
|
|
150
|
-
log(`Replicating: peerId=${info.session}; feeds=${feeds.map(feed => feed.key.toHex())}`);
|
|
151
|
-
return feeds.map(feed => feed.feed);
|
|
152
|
-
}
|
|
153
|
-
})
|
|
154
|
-
];
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
@synchronized
|
|
158
|
-
private async _openFeed (key: FeedKey): Promise<HypercoreFeed> {
|
|
159
|
-
const descriptor = await this._feedProvider.createOrOpenReadOnlyFeed(key);
|
|
160
|
-
return descriptor.feed;
|
|
161
|
-
}
|
|
162
|
-
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2022 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import debug from 'debug';
|
|
6
|
+
|
|
7
|
+
import { keyToString } from '@dxos/crypto';
|
|
8
|
+
import { Replicator } from '@dxos/protocol-plugin-replicator';
|
|
9
|
+
|
|
10
|
+
import { PartyFeedProvider } from '../pipeline';
|
|
11
|
+
|
|
12
|
+
const log = debug('dxos:echo-db:protocol:replicator');
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Creates the protocol plugin for feed replication.
|
|
16
|
+
*/
|
|
17
|
+
export const createReplicatorPlugin = (feedProvider: PartyFeedProvider) =>
|
|
18
|
+
new Replicator({
|
|
19
|
+
load: async () => {
|
|
20
|
+
const feeds = feedProvider.getFeeds();
|
|
21
|
+
log(`Loading feeds: ${feeds.map(feed => keyToString(feed.key))}`);
|
|
22
|
+
return feeds.map((feed) => ({ discoveryKey: feed.feed.discoveryKey }));
|
|
23
|
+
},
|
|
24
|
+
|
|
25
|
+
subscribe: (addFeedToReplicatedSet: (feed: any) => void) => feedProvider.feedOpened.on(async (feed) => {
|
|
26
|
+
log(`Adding feed: ${feed.key.toHex()}`);
|
|
27
|
+
addFeedToReplicatedSet({ discoveryKey: feed.feed.discoveryKey });
|
|
28
|
+
}),
|
|
29
|
+
|
|
30
|
+
replicate: async (remoteFeeds, info) => {
|
|
31
|
+
// We can ignore remoteFeeds entirely, since the set of feeds we want to replicate is dictated by the Party.
|
|
32
|
+
// TODO(telackey): Why are we opening feeds? Necessary or belt/braces thinking, or because open party does it?
|
|
33
|
+
const feeds = feedProvider.getFeeds();
|
|
34
|
+
log(`Replicating: peerId=${info.session}; feeds=${feeds.map(feed => feed.key.toHex())}`);
|
|
35
|
+
return feeds.map(feed => feed.feed);
|
|
36
|
+
}
|
|
37
|
+
});
|
|
@@ -10,20 +10,16 @@ import { SnapshotStore } from './snapshot-store';
|
|
|
10
10
|
|
|
11
11
|
const log = debug('dxos:snapshot-generator');
|
|
12
12
|
|
|
13
|
-
export
|
|
14
|
-
|
|
15
|
-
) {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
} catch (err: any) {
|
|
24
|
-
console.error('Failed to save snapshot');
|
|
25
|
-
console.error(err);
|
|
26
|
-
}
|
|
13
|
+
export const createAutomaticSnapshots = (party: PartyCore, clock: TimeframeClock, store: SnapshotStore, interval: number) => clock.update.on(async timeframe => {
|
|
14
|
+
const totalMessages = timeframe.totalMessages();
|
|
15
|
+
if (totalMessages > 0 && totalMessages % interval === 0) {
|
|
16
|
+
log(`Saving snapshot of ${party.key.humanize()}...`);
|
|
17
|
+
try {
|
|
18
|
+
const snapshot = party.createSnapshot();
|
|
19
|
+
await store.save(snapshot);
|
|
20
|
+
} catch (err: any) {
|
|
21
|
+
console.error('Failed to save snapshot');
|
|
22
|
+
console.error(err);
|
|
27
23
|
}
|
|
28
|
-
}
|
|
29
|
-
}
|
|
24
|
+
}
|
|
25
|
+
});
|
|
@@ -7,15 +7,15 @@ import { it as test } from 'mocha';
|
|
|
7
7
|
|
|
8
8
|
import { createId, createKeyPair, PublicKey } from '@dxos/crypto';
|
|
9
9
|
import { PartySnapshot } from '@dxos/echo-protocol';
|
|
10
|
+
import { createStorage, StorageType } from '@dxos/random-access-multi-storage';
|
|
10
11
|
|
|
11
|
-
import { createRamStorage } from '../util';
|
|
12
12
|
import { SnapshotStore } from './snapshot-store';
|
|
13
13
|
|
|
14
14
|
const createPublicKey = () => PublicKey.from(createKeyPair().publicKey);
|
|
15
15
|
|
|
16
16
|
describe('SnapshotStore', () => {
|
|
17
17
|
test('in-memory', async () => {
|
|
18
|
-
const store = new SnapshotStore(
|
|
18
|
+
const store = new SnapshotStore(createStorage('', StorageType.RAM).directory('snapshots'));
|
|
19
19
|
|
|
20
20
|
const key1 = createPublicKey();
|
|
21
21
|
const key2 = createPublicKey();
|
|
@@ -7,10 +7,9 @@ import debug from 'debug';
|
|
|
7
7
|
|
|
8
8
|
import { keyToString } from '@dxos/crypto';
|
|
9
9
|
import { schema, PartyKey, PartySnapshot } from '@dxos/echo-protocol';
|
|
10
|
-
import {
|
|
10
|
+
import { Directory } from '@dxos/random-access-multi-storage';
|
|
11
11
|
|
|
12
12
|
const log = debug('dxos:snapshot-store');
|
|
13
|
-
|
|
14
13
|
/**
|
|
15
14
|
* Stores party snapshots. Takes any `random-access-storage` compatible backend.
|
|
16
15
|
*
|
|
@@ -18,11 +17,11 @@ const log = debug('dxos:snapshot-store');
|
|
|
18
17
|
*/
|
|
19
18
|
export class SnapshotStore {
|
|
20
19
|
constructor (
|
|
21
|
-
private readonly
|
|
20
|
+
private readonly _directory: Directory
|
|
22
21
|
) {}
|
|
23
22
|
|
|
24
23
|
async load (partyKey: PartyKey): Promise<PartySnapshot | undefined> {
|
|
25
|
-
const file = this.
|
|
24
|
+
const file = this._directory.createOrOpen(partyKey.toHex());
|
|
26
25
|
|
|
27
26
|
try {
|
|
28
27
|
const { size } = await file.stat();
|
|
@@ -45,7 +44,7 @@ export class SnapshotStore {
|
|
|
45
44
|
|
|
46
45
|
async save (snapshot: PartySnapshot) {
|
|
47
46
|
assert(snapshot.partyKey);
|
|
48
|
-
const file = this.
|
|
47
|
+
const file = this._directory.createOrOpen(keyToString(snapshot.partyKey), { truncate: true, size: 0 });
|
|
49
48
|
|
|
50
49
|
try {
|
|
51
50
|
const data = schema.getCodecForType('dxos.echo.snapshot.PartySnapshot').encode(snapshot);
|
|
@@ -60,6 +59,6 @@ export class SnapshotStore {
|
|
|
60
59
|
*/
|
|
61
60
|
async clear () {
|
|
62
61
|
log('Clearing all snapshots..');
|
|
63
|
-
await this.
|
|
62
|
+
await this._directory.destroy();
|
|
64
63
|
}
|
|
65
64
|
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2022 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { ObjectModel } from '@dxos/object-model';
|
|
6
|
+
|
|
7
|
+
import { ECHO } from '../echo';
|
|
8
|
+
|
|
9
|
+
const ITEMS = 100;
|
|
10
|
+
const MUTATIONS = 1000;
|
|
11
|
+
|
|
12
|
+
it.skip('Database benchmark', async () => {
|
|
13
|
+
const echo = new ECHO({ snapshots: false });
|
|
14
|
+
await echo.open();
|
|
15
|
+
await echo.halo.createProfile();
|
|
16
|
+
const party = await echo.createParty();
|
|
17
|
+
|
|
18
|
+
const start = Date.now();
|
|
19
|
+
for (let i = 0; i < ITEMS; i++) {
|
|
20
|
+
const item = await party.database.createItem({ model: ObjectModel, type: 'test:item' });
|
|
21
|
+
|
|
22
|
+
for (let j = 0; j < MUTATIONS; j++) {
|
|
23
|
+
await item.model.set(`key${j % 100}`, `value-${j}`);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
console.log(`${i * MUTATIONS}/${ITEMS * MUTATIONS} ${((Date.now() - start) / ((i + 1) * MUTATIONS / 1000)).toFixed(1)} µs/mut ${((i + 1) * MUTATIONS / (Date.now() - start) * 1000).toFixed(1)} mut/s`);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
await echo.close();
|
|
30
|
+
});
|
|
@@ -22,10 +22,10 @@ export type TestPeer = Awaited<ReturnType<typeof createTestInstance>>;
|
|
|
22
22
|
|
|
23
23
|
export type WithTestMeta<T> = T & { testMeta: TestPeer }
|
|
24
24
|
|
|
25
|
-
|
|
25
|
+
const addTestMeta = <T>(obj: T, meta: TestPeer): WithTestMeta<T> => {
|
|
26
26
|
(obj as any).testMeta = meta;
|
|
27
27
|
return obj as any;
|
|
28
|
-
}
|
|
28
|
+
};
|
|
29
29
|
|
|
30
30
|
/**
|
|
31
31
|
* Creates a number of test ECHO instances and a party that's shared between all of them.
|
package/src/testing/testing.ts
CHANGED
|
@@ -5,12 +5,11 @@
|
|
|
5
5
|
import debug from 'debug';
|
|
6
6
|
|
|
7
7
|
import { NetworkManagerOptions } from '@dxos/network-manager';
|
|
8
|
-
import {
|
|
8
|
+
import { Storage, createStorage, StorageType } from '@dxos/random-access-multi-storage';
|
|
9
9
|
import { jsonReplacer } from '@dxos/util';
|
|
10
10
|
|
|
11
11
|
import { ECHO } from '../echo';
|
|
12
12
|
import { DataParty } from '../parties';
|
|
13
|
-
import { createRamStorage } from '../util';
|
|
14
13
|
|
|
15
14
|
export const log = debug('dxos:echo-db:testing');
|
|
16
15
|
|
|
@@ -21,13 +20,12 @@ export const messageLogger = (tag: string) => (message: any) => {
|
|
|
21
20
|
export interface TestOptions {
|
|
22
21
|
verboseLogging?: boolean
|
|
23
22
|
initialize?: boolean
|
|
24
|
-
storage?:
|
|
23
|
+
storage?: Storage
|
|
25
24
|
keyStorage?: any
|
|
26
25
|
networkManagerOptions?: NetworkManagerOptions
|
|
27
26
|
// TODO(burdon): Group properties by hierarchical object.
|
|
28
27
|
snapshots?: boolean
|
|
29
28
|
snapshotInterval?: number
|
|
30
|
-
snapshotStorage?: IStorage
|
|
31
29
|
}
|
|
32
30
|
|
|
33
31
|
/**
|
|
@@ -36,17 +34,15 @@ export interface TestOptions {
|
|
|
36
34
|
export const createTestInstance = async ({
|
|
37
35
|
verboseLogging = false,
|
|
38
36
|
initialize = false,
|
|
39
|
-
storage =
|
|
37
|
+
storage = createStorage('', StorageType.RAM),
|
|
40
38
|
keyStorage = undefined,
|
|
41
39
|
networkManagerOptions,
|
|
42
|
-
snapshotStorage = createRamStorage(),
|
|
43
40
|
snapshots = true,
|
|
44
41
|
snapshotInterval
|
|
45
42
|
}: TestOptions = {}) => {
|
|
46
43
|
const echo = new ECHO({
|
|
47
|
-
|
|
44
|
+
storage,
|
|
48
45
|
keyStorage,
|
|
49
|
-
snapshotStorage,
|
|
50
46
|
snapshotInterval,
|
|
51
47
|
snapshots,
|
|
52
48
|
networkManagerOptions,
|
package/dist/src/util/index.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/util/index.ts"],"names":[],"mappings":"AAIA,cAAc,0BAA0B,CAAC"}
|
package/dist/src/util/index.js
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
//
|
|
3
|
-
// Copyright 2020 DXOS.org
|
|
4
|
-
//
|
|
5
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
6
|
-
if (k2 === undefined) k2 = k;
|
|
7
|
-
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
|
|
8
|
-
}) : (function(o, m, k, k2) {
|
|
9
|
-
if (k2 === undefined) k2 = k;
|
|
10
|
-
o[k2] = m[k];
|
|
11
|
-
}));
|
|
12
|
-
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
13
|
-
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
14
|
-
};
|
|
15
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
16
|
-
__exportStar(require("./persistant-ram-storage"), exports);
|
|
17
|
-
//# sourceMappingURL=index.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/util/index.ts"],"names":[],"mappings":";AAAA,EAAE;AACF,0BAA0B;AAC1B,EAAE;;;;;;;;;;;;AAEF,2DAAyC"}
|
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
import { IStorage } from '@dxos/random-access-multi-storage';
|
|
2
|
-
/**
|
|
3
|
-
* A wrapper around RAM storage that preserves file data when closing and re-opening files.
|
|
4
|
-
*/
|
|
5
|
-
export declare function createRamStorage(): IStorage;
|
|
6
|
-
//# sourceMappingURL=persistant-ram-storage.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"persistant-ram-storage.d.ts","sourceRoot":"","sources":["../../../src/util/persistant-ram-storage.ts"],"names":[],"mappings":"AAIA,OAAO,EAAoC,QAAQ,EAAE,MAAM,mCAAmC,CAAC;AAE/F;;GAEG;AAEH,wBAAgB,gBAAgB,IAAK,QAAQ,CAsB5C"}
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
//
|
|
3
|
-
// Copyright 2020 DXOS.org
|
|
4
|
-
//
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.createRamStorage = void 0;
|
|
7
|
-
const random_access_multi_storage_1 = require("@dxos/random-access-multi-storage");
|
|
8
|
-
/**
|
|
9
|
-
* A wrapper around RAM storage that preserves file data when closing and re-opening files.
|
|
10
|
-
*/
|
|
11
|
-
// TODO(burdon): Factor out?
|
|
12
|
-
function createRamStorage() {
|
|
13
|
-
const root = 'snapshots';
|
|
14
|
-
const storage = (0, random_access_multi_storage_1.createStorage)(root, random_access_multi_storage_1.StorageType.RAM);
|
|
15
|
-
const files = new Map();
|
|
16
|
-
const fn = {};
|
|
17
|
-
fn.createOrOpen = (name) => {
|
|
18
|
-
if (files.has(name)) {
|
|
19
|
-
return files.get(name);
|
|
20
|
-
}
|
|
21
|
-
const file = storage.createOrOpen(name);
|
|
22
|
-
file.close = (cb) => cb === null || cb === void 0 ? void 0 : cb(null); // Fix.
|
|
23
|
-
files.set(name, file);
|
|
24
|
-
return file;
|
|
25
|
-
};
|
|
26
|
-
fn.root = root;
|
|
27
|
-
fn.type = storage.type;
|
|
28
|
-
fn.destroy = storage.destroy.bind(storage);
|
|
29
|
-
return fn;
|
|
30
|
-
}
|
|
31
|
-
exports.createRamStorage = createRamStorage;
|
|
32
|
-
//# sourceMappingURL=persistant-ram-storage.js.map
|