@enbox/dwn-sdk-js 0.3.8 → 0.4.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/browser.mjs +11 -11
- package/dist/browser.mjs.map +4 -4
- package/dist/esm/generated/precompiled-validators.js +175 -512
- package/dist/esm/generated/precompiled-validators.js.map +1 -1
- package/dist/esm/src/core/dwn-error.js +1 -3
- package/dist/esm/src/core/dwn-error.js.map +1 -1
- package/dist/esm/src/core/messages-grant-authorization.js +1 -17
- package/dist/esm/src/core/messages-grant-authorization.js.map +1 -1
- package/dist/esm/src/core/protocol-authorization-validation.js +1 -1
- package/dist/esm/src/core/protocol-authorization-validation.js.map +1 -1
- package/dist/esm/src/core/replication-apply.js +200 -0
- package/dist/esm/src/core/replication-apply.js.map +1 -0
- package/dist/esm/src/dwn.js +212 -0
- package/dist/esm/src/dwn.js.map +1 -1
- package/dist/esm/src/handlers/messages-sync.js +66 -369
- package/dist/esm/src/handlers/messages-sync.js.map +1 -1
- package/dist/esm/src/handlers/records-write.js +18 -12
- package/dist/esm/src/handlers/records-write.js.map +1 -1
- package/dist/esm/src/index.js +1 -1
- package/dist/esm/src/index.js.map +1 -1
- package/dist/esm/src/interfaces/messages-sync.js +0 -11
- package/dist/esm/src/interfaces/messages-sync.js.map +1 -1
- package/dist/esm/tests/core/replication-apply.spec.js +220 -0
- package/dist/esm/tests/core/replication-apply.spec.js.map +1 -0
- package/dist/esm/tests/dwn.spec.js +139 -2
- package/dist/esm/tests/dwn.spec.js.map +1 -1
- package/dist/esm/tests/features/records-record-limit.spec.js +14 -0
- package/dist/esm/tests/features/records-record-limit.spec.js.map +1 -1
- package/dist/esm/tests/handlers/messages-sync.spec.js +1 -684
- package/dist/esm/tests/handlers/messages-sync.spec.js.map +1 -1
- package/dist/esm/tests/handlers/records-write.spec.js +43 -2
- package/dist/esm/tests/handlers/records-write.spec.js.map +1 -1
- package/dist/esm/tests/test-suite.js +0 -2
- package/dist/esm/tests/test-suite.js.map +1 -1
- package/dist/types/generated/precompiled-validators.d.ts.map +1 -1
- package/dist/types/src/core/dwn-error.d.ts +1 -3
- package/dist/types/src/core/dwn-error.d.ts.map +1 -1
- package/dist/types/src/core/messages-grant-authorization.d.ts +0 -1
- package/dist/types/src/core/messages-grant-authorization.d.ts.map +1 -1
- package/dist/types/src/core/replication-apply.d.ts +93 -0
- package/dist/types/src/core/replication-apply.d.ts.map +1 -0
- package/dist/types/src/dwn.d.ts +22 -1
- package/dist/types/src/dwn.d.ts.map +1 -1
- package/dist/types/src/handlers/messages-sync.d.ts +10 -54
- package/dist/types/src/handlers/messages-sync.d.ts.map +1 -1
- package/dist/types/src/handlers/records-write.d.ts.map +1 -1
- package/dist/types/src/index.d.ts +3 -3
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/src/interfaces/messages-sync.d.ts +0 -3
- package/dist/types/src/interfaces/messages-sync.d.ts.map +1 -1
- package/dist/types/src/types/messages-types.d.ts +0 -18
- package/dist/types/src/types/messages-types.d.ts.map +1 -1
- package/dist/types/tests/core/replication-apply.spec.d.ts +2 -0
- package/dist/types/tests/core/replication-apply.spec.d.ts.map +1 -0
- package/dist/types/tests/dwn.spec.d.ts.map +1 -1
- package/dist/types/tests/features/records-record-limit.spec.d.ts.map +1 -1
- package/dist/types/tests/handlers/messages-sync.spec.d.ts.map +1 -1
- package/dist/types/tests/handlers/records-write.spec.d.ts.map +1 -1
- package/dist/types/tests/test-suite.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/core/dwn-error.ts +1 -3
- package/src/core/messages-grant-authorization.ts +1 -31
- package/src/core/protocol-authorization-validation.ts +2 -2
- package/src/core/replication-apply.ts +272 -0
- package/src/dwn.ts +296 -2
- package/src/handlers/messages-sync.ts +92 -585
- package/src/handlers/records-write.ts +18 -13
- package/src/index.ts +3 -4
- package/src/interfaces/messages-sync.ts +8 -25
- package/src/types/messages-types.ts +0 -20
- package/dist/esm/src/sync/records-projection.js +0 -228
- package/dist/esm/src/sync/records-projection.js.map +0 -1
- package/dist/esm/tests/sync/records-projection.spec.js +0 -245
- package/dist/esm/tests/sync/records-projection.spec.js.map +0 -1
- package/dist/types/src/sync/records-projection.d.ts +0 -98
- package/dist/types/src/sync/records-projection.d.ts.map +0 -1
- package/dist/types/tests/sync/records-projection.spec.d.ts +0 -2
- package/dist/types/tests/sync/records-projection.spec.d.ts.map +0 -1
- package/src/sync/records-projection.ts +0 -328
|
@@ -37,20 +37,10 @@ export class RecordsWriteHandler implements MethodHandler {
|
|
|
37
37
|
let recordsWrite: RecordsWrite;
|
|
38
38
|
try {
|
|
39
39
|
recordsWrite = await RecordsWrite.parse(message);
|
|
40
|
-
|
|
41
|
-
await ProtocolAuthorization.validateReferentialIntegrity(tenant, recordsWrite, this.deps.messageStore, this.deps.coreProtocols);
|
|
42
40
|
} catch (e) {
|
|
43
41
|
return messageReplyFromError(e, 400);
|
|
44
42
|
}
|
|
45
43
|
|
|
46
|
-
// authentication & authorization
|
|
47
|
-
try {
|
|
48
|
-
await authenticate(message.authorization, this.deps.didResolver, message.attestation);
|
|
49
|
-
await this.authorizeRecordsWrite(tenant, recordsWrite, this.deps.messageStore);
|
|
50
|
-
} catch (e) {
|
|
51
|
-
return messageReplyFromError(e, 401);
|
|
52
|
-
}
|
|
53
|
-
|
|
54
44
|
// get existing messages matching the `recordId`
|
|
55
45
|
const query = {
|
|
56
46
|
interface : DwnInterfaceName.Records,
|
|
@@ -58,9 +48,10 @@ export class RecordsWriteHandler implements MethodHandler {
|
|
|
58
48
|
};
|
|
59
49
|
const { messages: existingMessages } = await this.deps.messageStore.query(tenant, [ query ]);
|
|
60
50
|
|
|
61
|
-
// If the exact same message already exists, return 409
|
|
62
|
-
//
|
|
63
|
-
//
|
|
51
|
+
// If the exact same message already exists, return 409 before re-running
|
|
52
|
+
// mutable validation. An already-stored message has already passed
|
|
53
|
+
// admission; replay should not be reinterpreted against current protocol,
|
|
54
|
+
// parent, role, grant, or record-limit state.
|
|
64
55
|
//
|
|
65
56
|
// Exception: an initial write may have been stored earlier without data
|
|
66
57
|
// (204). A later delivery of the same message with data must be allowed
|
|
@@ -83,6 +74,20 @@ export class RecordsWriteHandler implements MethodHandler {
|
|
|
83
74
|
}
|
|
84
75
|
}
|
|
85
76
|
|
|
77
|
+
try {
|
|
78
|
+
await ProtocolAuthorization.validateReferentialIntegrity(tenant, recordsWrite, this.deps.messageStore, this.deps.coreProtocols);
|
|
79
|
+
} catch (e) {
|
|
80
|
+
return messageReplyFromError(e, 400);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// authentication & authorization
|
|
84
|
+
try {
|
|
85
|
+
await authenticate(message.authorization, this.deps.didResolver, message.attestation);
|
|
86
|
+
await this.authorizeRecordsWrite(tenant, recordsWrite, this.deps.messageStore);
|
|
87
|
+
} catch (e) {
|
|
88
|
+
return messageReplyFromError(e, 401);
|
|
89
|
+
}
|
|
90
|
+
|
|
86
91
|
// if the incoming write is not the initial write, then it must not modify any immutable properties defined by the initial write
|
|
87
92
|
const newMessageIsInitialWrite = await recordsWrite.isInitialWrite();
|
|
88
93
|
let initialWrite: RecordsWriteMessage | undefined;
|
package/src/index.ts
CHANGED
|
@@ -2,7 +2,9 @@
|
|
|
2
2
|
export type { DwnConfig } from './dwn.js';
|
|
3
3
|
export type { EventListener, EventLog, EventLogEntry, EventLogReadOptions, EventLogReadResult, EventLogSubscribeOptions, EventSubscription, MessageEvent, ProgressGapInfo, ProgressGapReason, ProgressToken, SubscriptionEose, SubscriptionError, SubscriptionEvent, SubscriptionListener, SubscriptionMessage, SubscriptionReply } from './types/subscriptions.js';
|
|
4
4
|
export type { AuthorizationModel, Descriptor, DelegatedGrantRecordsWriteMessage, GenericMessage, GenericMessageReply, GenericSignaturePayload, MessageSort, MessageSubscription, Pagination, QueryResultEntry, Status } from './types/message-types.js';
|
|
5
|
-
export type {
|
|
5
|
+
export type { DependencyRef, ReplicationApplyOptions, ReplicationApplyResult, ReplicationApplyResultContext } from './core/replication-apply.js';
|
|
6
|
+
export { replicationApplyResultFromReply } from './core/replication-apply.js';
|
|
7
|
+
export type { MessagesFilter, MessagesReadMessage, MessagesReadReply, MessagesReadReplyEntry, MessagesReadDescriptor, MessagesSubscribeDescriptor, MessagesSubscribeMessage, MessagesSubscribeReply, MessagesSubscribeMessageOptions, MessagesSyncAction, MessagesSyncDescriptor, MessagesSyncDiffEntry, MessagesSyncMessage, MessagesSyncReply } from './types/messages-types.js';
|
|
6
8
|
export type { GT, LT, Filter, FilterValue, KeyValues, EqualFilter, OneOfFilter, RangeFilter, RangeCriterion, PaginationCursor, QueryOptions, RangeValue, StartsWithFilter } from './types/query-types.js';
|
|
7
9
|
export type { ProtocolsConfigureDescriptor, ProtocolDefinition, ProtocolTypes, ProtocolRuleSet, ProtocolsQueryFilter, ProtocolsConfigureMessage, ProtocolsQueryMessage, ProtocolsQueryReply, ProtocolActionRule, ProtocolDeliveryStrategy, ProtocolPathEncryption, ProtocolsQueryDescriptor, ProtocolRecordLimitDefinition, ProtocolSizeDefinition, ProtocolTagsDefinition, ProtocolTagSchema, ProtocolType, ProtocolUses } from './types/protocols-types.js';
|
|
8
10
|
export { ProtocolRecordLimitStrategy } from './types/protocols-types.js';
|
|
@@ -103,9 +105,6 @@ export { SMTStoreLevel } from './smt/smt-store-level.js';
|
|
|
103
105
|
export { SMTStoreMemory } from './smt/smt-store-memory.js';
|
|
104
106
|
export type { Hash, SMTNode, SMTInternalNode, SMTLeafNode, SMTProof, SMTDiffResult, SMTNodeStore } from './types/smt-types.js';
|
|
105
107
|
export { hashChildren, hashEquals, hashKey, hashLeaf, hashToHex, hexToHash, getBit, initDefaultHashes, getDefaultHashes, SMT_DEPTH, ZERO_HASH } from './smt/smt-utils.js';
|
|
106
|
-
export { RECORDS_PROJECTION_ROOT_VERSION, RecordsProjection } from './sync/records-projection.js';
|
|
107
|
-
export type { NormalizedRecordsProjectionScope, RecordsProjectionInput, RecordsProjectionScope, RecordsProjectionSnapshot, RecordsProjectionTreeInput } from './sync/records-projection.js';
|
|
108
|
-
|
|
109
108
|
// test library exports
|
|
110
109
|
export type { GenerateFromRecordsWriteInput, GenerateFromRecordsWriteOut, GenerateGrantCreateInput, GenerateGrantCreateOutput, GenerateMessagesReadInput, GenerateMessagesReadOutput, GenerateMessagesSubscribeInput, GenerateMessagesSubscribeOutput, GenerateProtocolsConfigureInput, GenerateProtocolsConfigureOutput, GenerateProtocolsQueryInput, GenerateProtocolsQueryOutput, GenerateRecordsCountInput, GenerateRecordsCountOutput, GenerateRecordsDeleteInput, GenerateRecordsDeleteOutput, GenerateRecordsQueryInput, GenerateRecordsQueryOutput, GenerateRecordsSubscribeInput, GenerateRecordsSubscribeOutput, GenerateRecordsWriteInput, GenerateRecordsWriteOutput, Persona } from '../tests/utils/test-data-generator.js';
|
|
111
110
|
export { TestDataGenerator } from '../tests/utils/test-data-generator.js';
|
|
@@ -1,22 +1,17 @@
|
|
|
1
1
|
import type { MessageSigner } from '../types/signer.js';
|
|
2
|
-
import type { RecordsProjectionScope } from '../sync/records-projection.js';
|
|
3
2
|
import type { MessagesSyncAction, MessagesSyncDescriptor, MessagesSyncMessage } from '../types/messages-types.js';
|
|
4
3
|
|
|
5
4
|
import { AbstractMessage } from '../core/abstract-message.js';
|
|
6
5
|
import { Message } from '../core/message.js';
|
|
7
|
-
import { RECORDS_PROJECTION_ROOT_VERSION } from '../sync/records-projection.js';
|
|
8
6
|
import { removeUndefinedProperties } from '@enbox/common';
|
|
9
7
|
import { Time } from '../utils/time.js';
|
|
10
8
|
import { validateProtocolUrlNormalized } from '../utils/url.js';
|
|
11
|
-
import { DwnError, DwnErrorCode } from '../core/dwn-error.js';
|
|
12
9
|
import { DwnInterfaceName, DwnMethodName } from '../enums/dwn-interface-method.js';
|
|
13
10
|
|
|
14
11
|
export type MessagesSyncOptions = {
|
|
15
12
|
signer : MessageSigner;
|
|
16
13
|
action : MessagesSyncAction;
|
|
17
14
|
protocol? : string;
|
|
18
|
-
projectionRootVersion?: string;
|
|
19
|
-
projectionScopes?: RecordsProjectionScope[];
|
|
20
15
|
prefix? : string;
|
|
21
16
|
messageTimestamp? : string;
|
|
22
17
|
permissionGrantIds? : string[];
|
|
@@ -35,16 +30,6 @@ export class MessagesSync extends AbstractMessage<MessagesSyncMessage> {
|
|
|
35
30
|
if (message.descriptor.protocol !== undefined) {
|
|
36
31
|
validateProtocolUrlNormalized(message.descriptor.protocol);
|
|
37
32
|
}
|
|
38
|
-
if (message.descriptor.projectionRootVersion !== undefined &&
|
|
39
|
-
message.descriptor.projectionRootVersion !== RECORDS_PROJECTION_ROOT_VERSION) {
|
|
40
|
-
throw new DwnError(
|
|
41
|
-
DwnErrorCode.MessagesSyncUnsupportedProjectionRootVersion,
|
|
42
|
-
`Unsupported projection root version ${message.descriptor.projectionRootVersion}`
|
|
43
|
-
);
|
|
44
|
-
}
|
|
45
|
-
for (const scope of message.descriptor.projectionScopes ?? []) {
|
|
46
|
-
validateProtocolUrlNormalized(scope.protocol);
|
|
47
|
-
}
|
|
48
33
|
|
|
49
34
|
return new MessagesSync(message);
|
|
50
35
|
}
|
|
@@ -55,16 +40,14 @@ export class MessagesSync extends AbstractMessage<MessagesSyncMessage> {
|
|
|
55
40
|
});
|
|
56
41
|
|
|
57
42
|
const descriptor: MessagesSyncDescriptor = {
|
|
58
|
-
interface
|
|
59
|
-
method
|
|
60
|
-
messageTimestamp
|
|
61
|
-
action
|
|
62
|
-
protocol
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
hashes : options.hashes,
|
|
67
|
-
depth : options.depth,
|
|
43
|
+
interface : DwnInterfaceName.Messages,
|
|
44
|
+
method : DwnMethodName.Sync,
|
|
45
|
+
messageTimestamp : options.messageTimestamp ?? Time.getCurrentTimestamp(),
|
|
46
|
+
action : options.action,
|
|
47
|
+
protocol : options.protocol,
|
|
48
|
+
prefix : options.prefix,
|
|
49
|
+
hashes : options.hashes,
|
|
50
|
+
depth : options.depth,
|
|
68
51
|
...permissionGrantInvocation,
|
|
69
52
|
};
|
|
70
53
|
|
|
@@ -50,12 +50,6 @@ export type MessagesSyncDescriptor = {
|
|
|
50
50
|
messageTimestamp : string;
|
|
51
51
|
action : MessagesSyncAction;
|
|
52
52
|
protocol? : string; // optional protocol scope
|
|
53
|
-
projectionRootVersion?: string;
|
|
54
|
-
projectionScopes?: {
|
|
55
|
-
protocol: string;
|
|
56
|
-
protocolPath?: string;
|
|
57
|
-
contextId?: string;
|
|
58
|
-
}[];
|
|
59
53
|
prefix? : string; // bit path for subtree/leaves (e.g. "0110101...")
|
|
60
54
|
permissionGrantIds? : string[];
|
|
61
55
|
/**
|
|
@@ -91,18 +85,6 @@ export type MessagesSyncDiffEntry = {
|
|
|
91
85
|
encodedData? : string;
|
|
92
86
|
};
|
|
93
87
|
|
|
94
|
-
export type MessagesSyncDependencyClass = 'protocolsConfigure' | 'recordsInitialWrite';
|
|
95
|
-
|
|
96
|
-
/**
|
|
97
|
-
* Advisory dependency hint returned with projected diff responses. Dependency
|
|
98
|
-
* entries are not part of the projected root; clients must rederive that the
|
|
99
|
-
* dependency is required by the referenced primary before applying it.
|
|
100
|
-
*/
|
|
101
|
-
export type MessagesSyncDependencyEntry = MessagesSyncDiffEntry & {
|
|
102
|
-
dependencyClass: MessagesSyncDependencyClass;
|
|
103
|
-
rootMessageCid: string;
|
|
104
|
-
};
|
|
105
|
-
|
|
106
88
|
export type MessagesSyncReply = GenericMessageReply & {
|
|
107
89
|
root? : string; // hex-encoded root hash (for 'root' action)
|
|
108
90
|
hash? : string; // hex-encoded subtree hash (for 'subtree' action)
|
|
@@ -111,8 +93,6 @@ export type MessagesSyncReply = GenericMessageReply & {
|
|
|
111
93
|
onlyRemote? : MessagesSyncDiffEntry[];
|
|
112
94
|
/** For 'diff' action: bit prefixes where the client has entries the server doesn't. */
|
|
113
95
|
onlyLocal? : string[];
|
|
114
|
-
/** Advisory dependency messages needed to apply projected `onlyRemote` primary entries. */
|
|
115
|
-
dependencies? : MessagesSyncDependencyEntry[];
|
|
116
96
|
};
|
|
117
97
|
|
|
118
98
|
export type MessagesSubscribeMessageOptions = {
|
|
@@ -1,228 +0,0 @@
|
|
|
1
|
-
import { DwnInterfaceName } from '../enums/dwn-interface-method.js';
|
|
2
|
-
import { FilterUtility } from '../utils/filter.js';
|
|
3
|
-
import { hashToHex } from '../smt/smt-utils.js';
|
|
4
|
-
import { isRecordsPrimaryProjectionExcludedProtocol } from '../core/constants.js';
|
|
5
|
-
import { lexicographicalCompare } from '../utils/string.js';
|
|
6
|
-
import { Message } from '../core/message.js';
|
|
7
|
-
import { SMTStoreMemory } from '../smt/smt-store-memory.js';
|
|
8
|
-
import { SparseMerkleTree } from '../smt/sparse-merkle-tree.js';
|
|
9
|
-
/**
|
|
10
|
-
* Projection-root algorithm for record-primary scoped subsets.
|
|
11
|
-
*
|
|
12
|
-
* This version builds an on-demand SMT over latest Records primary message CIDs
|
|
13
|
-
* selected by protocol plus optional exact protocolPath or context subtree.
|
|
14
|
-
* Dependency records, protocol configs, and record data payloads are not part
|
|
15
|
-
* of this root.
|
|
16
|
-
*/
|
|
17
|
-
export const RECORDS_PROJECTION_ROOT_VERSION = 'records-primary-scope-root-v1';
|
|
18
|
-
/**
|
|
19
|
-
* Computes deterministic on-demand roots for Records projections.
|
|
20
|
-
*
|
|
21
|
-
* The snapshot API performs one store enumeration and serves tree operations
|
|
22
|
-
* from that in-memory view. A future store-level snapshot/high-watermark can be
|
|
23
|
-
* threaded through the `options` input without changing the projection shape.
|
|
24
|
-
*/
|
|
25
|
-
export class RecordsProjection {
|
|
26
|
-
/**
|
|
27
|
-
* Returns the sorted latest Records primary message CIDs covered by a scope union.
|
|
28
|
-
*/
|
|
29
|
-
static async getPrimaryMessageCids({ tenant, messageStore, scopes, options, }) {
|
|
30
|
-
const filters = RecordsProjection.normalizeScopes(scopes)
|
|
31
|
-
.filter(scope => !isRecordsPrimaryProjectionExcludedProtocol(scope.protocol))
|
|
32
|
-
.flatMap(scope => RecordsProjection.constructFilters(scope));
|
|
33
|
-
if (filters.length === 0) {
|
|
34
|
-
return [];
|
|
35
|
-
}
|
|
36
|
-
const { messages } = await messageStore.query(tenant, filters, undefined, undefined, options);
|
|
37
|
-
const messageCids = await Promise.all(messages.map(message => Message.getCid(message)));
|
|
38
|
-
return [...new Set(messageCids)].sort(lexicographicalCompare); // NOSONAR — projection IDs require locale-independent bytewise ordering.
|
|
39
|
-
}
|
|
40
|
-
/**
|
|
41
|
-
* Returns the projection root hash.
|
|
42
|
-
*/
|
|
43
|
-
static async getRoot(input) {
|
|
44
|
-
return RecordsProjection.withTree(input, tree => tree.getRoot());
|
|
45
|
-
}
|
|
46
|
-
/**
|
|
47
|
-
* Returns the projection root hash encoded as lowercase hex.
|
|
48
|
-
*/
|
|
49
|
-
static async getRootHex(input) {
|
|
50
|
-
return hashToHex(await RecordsProjection.getRoot(input));
|
|
51
|
-
}
|
|
52
|
-
/**
|
|
53
|
-
* Returns the subtree hash for a bit prefix within this projection.
|
|
54
|
-
*/
|
|
55
|
-
static async getSubtreeHash(input) {
|
|
56
|
-
return RecordsProjection.withTree(input, tree => tree.getSubtreeHash(input.prefix));
|
|
57
|
-
}
|
|
58
|
-
/**
|
|
59
|
-
* Returns the message CIDs under a bit prefix within this projection.
|
|
60
|
-
*/
|
|
61
|
-
static async getLeaves(input) {
|
|
62
|
-
return RecordsProjection.withTree(input, tree => tree.getLeaves(input.prefix));
|
|
63
|
-
}
|
|
64
|
-
/**
|
|
65
|
-
* Builds an in-memory projection tree from one primary-CID enumeration.
|
|
66
|
-
*/
|
|
67
|
-
static async createSnapshot(input) {
|
|
68
|
-
const tree = await RecordsProjection.createTree(input);
|
|
69
|
-
return {
|
|
70
|
-
close: () => tree.close(),
|
|
71
|
-
getLeaves: (prefix) => tree.getLeaves(prefix),
|
|
72
|
-
getRoot: () => tree.getRoot(),
|
|
73
|
-
getRootHex: async () => hashToHex(await tree.getRoot()),
|
|
74
|
-
getSubtreeHash: (prefix) => tree.getSubtreeHash(prefix),
|
|
75
|
-
};
|
|
76
|
-
}
|
|
77
|
-
/**
|
|
78
|
-
* Normalizes a scope union into sorted, duplicate-free, subsumption-reduced entries.
|
|
79
|
-
*/
|
|
80
|
-
static normalizeScopes(scopes) {
|
|
81
|
-
if (scopes.length === 0) {
|
|
82
|
-
throw new Error('RecordsProjection: scopes must contain at least one scope.');
|
|
83
|
-
}
|
|
84
|
-
const normalized = scopes.map(scope => RecordsProjection.normalizeScope(scope));
|
|
85
|
-
const deduped = new Map();
|
|
86
|
-
for (const scope of normalized) {
|
|
87
|
-
deduped.set(RecordsProjection.scopeKey(scope), scope);
|
|
88
|
-
}
|
|
89
|
-
const uniqueScopes = [...deduped.values()];
|
|
90
|
-
const protocolWide = new Set(uniqueScopes
|
|
91
|
-
.filter(scope => RecordsProjection.isProtocolWideScope(scope))
|
|
92
|
-
.map(scope => scope.protocol));
|
|
93
|
-
const reduced = uniqueScopes.filter(scope => {
|
|
94
|
-
if (protocolWide.has(scope.protocol)) {
|
|
95
|
-
return RecordsProjection.isProtocolWideScope(scope);
|
|
96
|
-
}
|
|
97
|
-
if (RecordsProjection.isContextScope(scope)) {
|
|
98
|
-
return !uniqueScopes.some(candidate => candidate !== scope &&
|
|
99
|
-
RecordsProjection.isContextScope(candidate) &&
|
|
100
|
-
candidate.protocol === scope.protocol &&
|
|
101
|
-
RecordsProjection.contextIdSubsumes(candidate.contextId, scope.contextId));
|
|
102
|
-
}
|
|
103
|
-
return true;
|
|
104
|
-
});
|
|
105
|
-
const result = reduced.sort(RecordsProjection.compareScopes);
|
|
106
|
-
return result;
|
|
107
|
-
}
|
|
108
|
-
static async withTree(input, fn) {
|
|
109
|
-
const tree = await RecordsProjection.createTree(input);
|
|
110
|
-
try {
|
|
111
|
-
return await fn(tree);
|
|
112
|
-
}
|
|
113
|
-
finally {
|
|
114
|
-
await tree.close();
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
static async createTree(input) {
|
|
118
|
-
const tree = new SparseMerkleTree(new SMTStoreMemory());
|
|
119
|
-
await tree.initialize();
|
|
120
|
-
try {
|
|
121
|
-
const messageCids = await RecordsProjection.getPrimaryMessageCids(input);
|
|
122
|
-
for (const messageCid of messageCids) {
|
|
123
|
-
await tree.insert(messageCid);
|
|
124
|
-
}
|
|
125
|
-
return tree;
|
|
126
|
-
}
|
|
127
|
-
catch (error) {
|
|
128
|
-
await tree.close();
|
|
129
|
-
throw error;
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
static normalizeScope(scope) {
|
|
133
|
-
const protocol = RecordsProjection.requireNonEmptyString(scope.protocol, 'protocol');
|
|
134
|
-
if (scope.protocolPath !== undefined && scope.contextId !== undefined) {
|
|
135
|
-
throw new Error('RecordsProjection: protocolPath and contextId scopes are mutually exclusive.');
|
|
136
|
-
}
|
|
137
|
-
if (scope.protocolPath !== undefined) {
|
|
138
|
-
return {
|
|
139
|
-
protocol,
|
|
140
|
-
protocolPath: RecordsProjection.requireNonEmptyString(scope.protocolPath, 'protocolPath'),
|
|
141
|
-
};
|
|
142
|
-
}
|
|
143
|
-
if (scope.contextId !== undefined) {
|
|
144
|
-
return {
|
|
145
|
-
protocol,
|
|
146
|
-
contextId: RecordsProjection.requireNonEmptyString(scope.contextId, 'contextId'),
|
|
147
|
-
};
|
|
148
|
-
}
|
|
149
|
-
return { protocol };
|
|
150
|
-
}
|
|
151
|
-
static constructFilters(scope) {
|
|
152
|
-
const baseFilter = {
|
|
153
|
-
interface: DwnInterfaceName.Records,
|
|
154
|
-
isLatestBaseState: true,
|
|
155
|
-
protocol: scope.protocol,
|
|
156
|
-
};
|
|
157
|
-
if ('protocolPath' in scope) {
|
|
158
|
-
return [{ ...baseFilter, protocolPath: scope.protocolPath }];
|
|
159
|
-
}
|
|
160
|
-
if ('contextId' in scope) {
|
|
161
|
-
const childContextPrefix = `${scope.contextId}/`;
|
|
162
|
-
return [
|
|
163
|
-
{ ...baseFilter, contextId: scope.contextId },
|
|
164
|
-
{
|
|
165
|
-
...baseFilter,
|
|
166
|
-
contextId: FilterUtility.constructPrefixFilterAsRangeFilter(childContextPrefix),
|
|
167
|
-
},
|
|
168
|
-
];
|
|
169
|
-
}
|
|
170
|
-
return [baseFilter];
|
|
171
|
-
}
|
|
172
|
-
static requireNonEmptyString(value, field) {
|
|
173
|
-
if (typeof value !== 'string' || value.length === 0) {
|
|
174
|
-
throw new Error(`RecordsProjection: ${field} must be a non-empty string.`);
|
|
175
|
-
}
|
|
176
|
-
return value;
|
|
177
|
-
}
|
|
178
|
-
static scopeKey(scope) {
|
|
179
|
-
if ('protocolPath' in scope) {
|
|
180
|
-
return `${scope.protocol}\u001fprotocolPath\u001f${scope.protocolPath}`;
|
|
181
|
-
}
|
|
182
|
-
if ('contextId' in scope) {
|
|
183
|
-
return `${scope.protocol}\u001fcontextId\u001f${scope.contextId}`;
|
|
184
|
-
}
|
|
185
|
-
return `${scope.protocol}\u001fprotocol`;
|
|
186
|
-
}
|
|
187
|
-
static isProtocolWideScope(scope) {
|
|
188
|
-
return !('protocolPath' in scope) && !('contextId' in scope);
|
|
189
|
-
}
|
|
190
|
-
static isContextScope(scope) {
|
|
191
|
-
return 'contextId' in scope;
|
|
192
|
-
}
|
|
193
|
-
static contextIdSubsumes(parentContextId, childContextId) {
|
|
194
|
-
return childContextId === parentContextId ||
|
|
195
|
-
childContextId.startsWith(`${parentContextId}/`);
|
|
196
|
-
}
|
|
197
|
-
static compareScopes(a, b) {
|
|
198
|
-
const protocolCompare = lexicographicalCompare(a.protocol, b.protocol);
|
|
199
|
-
if (protocolCompare !== 0) {
|
|
200
|
-
return protocolCompare;
|
|
201
|
-
}
|
|
202
|
-
const aRank = RecordsProjection.scopeRank(a);
|
|
203
|
-
const bRank = RecordsProjection.scopeRank(b);
|
|
204
|
-
if (aRank !== bRank) {
|
|
205
|
-
return aRank - bRank;
|
|
206
|
-
}
|
|
207
|
-
return lexicographicalCompare(RecordsProjection.scopeValue(a), RecordsProjection.scopeValue(b));
|
|
208
|
-
}
|
|
209
|
-
static scopeRank(scope) {
|
|
210
|
-
if ('protocolPath' in scope) {
|
|
211
|
-
return 1;
|
|
212
|
-
}
|
|
213
|
-
if ('contextId' in scope) {
|
|
214
|
-
return 2;
|
|
215
|
-
}
|
|
216
|
-
return 0;
|
|
217
|
-
}
|
|
218
|
-
static scopeValue(scope) {
|
|
219
|
-
if ('protocolPath' in scope) {
|
|
220
|
-
return scope.protocolPath;
|
|
221
|
-
}
|
|
222
|
-
if ('contextId' in scope) {
|
|
223
|
-
return scope.contextId;
|
|
224
|
-
}
|
|
225
|
-
return '';
|
|
226
|
-
}
|
|
227
|
-
}
|
|
228
|
-
//# sourceMappingURL=records-projection.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"records-projection.js","sourceRoot":"","sources":["../../../../src/sync/records-projection.ts"],"names":[],"mappings":"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"}
|