@enbox/agent 0.7.6 → 0.7.8

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.
Files changed (85) hide show
  1. package/dist/browser.mjs +9 -11
  2. package/dist/browser.mjs.map +4 -4
  3. package/dist/esm/dwn-api.js +3 -2
  4. package/dist/esm/dwn-api.js.map +1 -1
  5. package/dist/esm/enbox-connect-protocol.js +5 -5
  6. package/dist/esm/enbox-connect-protocol.js.map +1 -1
  7. package/dist/esm/hd-identity-vault.js +187 -177
  8. package/dist/esm/hd-identity-vault.js.map +1 -1
  9. package/dist/esm/index.js +1 -1
  10. package/dist/esm/index.js.map +1 -1
  11. package/dist/esm/permissions-api.js +7 -34
  12. package/dist/esm/permissions-api.js.map +1 -1
  13. package/dist/esm/sync-closure-resolver.js +229 -110
  14. package/dist/esm/sync-closure-resolver.js.map +1 -1
  15. package/dist/esm/sync-closure-types.js +24 -7
  16. package/dist/esm/sync-closure-types.js.map +1 -1
  17. package/dist/esm/sync-engine-level.js +1961 -764
  18. package/dist/esm/sync-engine-level.js.map +1 -1
  19. package/dist/esm/sync-link-id.js +4 -13
  20. package/dist/esm/sync-link-id.js.map +1 -1
  21. package/dist/esm/sync-link-reconciler.js +26 -8
  22. package/dist/esm/sync-link-reconciler.js.map +1 -1
  23. package/dist/esm/sync-messages.js +218 -154
  24. package/dist/esm/sync-messages.js.map +1 -1
  25. package/dist/esm/sync-permission-grants.js +208 -0
  26. package/dist/esm/sync-permission-grants.js.map +1 -0
  27. package/dist/esm/sync-replication-ledger.js +23 -40
  28. package/dist/esm/sync-replication-ledger.js.map +1 -1
  29. package/dist/esm/sync-scope-acceptance.js +126 -0
  30. package/dist/esm/sync-scope-acceptance.js.map +1 -0
  31. package/dist/esm/sync-topological-sort.js +57 -15
  32. package/dist/esm/sync-topological-sort.js.map +1 -1
  33. package/dist/esm/types/sync.js +130 -22
  34. package/dist/esm/types/sync.js.map +1 -1
  35. package/dist/types/dwn-api.d.ts.map +1 -1
  36. package/dist/types/hd-identity-vault.d.ts +25 -0
  37. package/dist/types/hd-identity-vault.d.ts.map +1 -1
  38. package/dist/types/index.d.ts +1 -1
  39. package/dist/types/index.d.ts.map +1 -1
  40. package/dist/types/permissions-api.d.ts +1 -2
  41. package/dist/types/permissions-api.d.ts.map +1 -1
  42. package/dist/types/sync-closure-resolver.d.ts.map +1 -1
  43. package/dist/types/sync-closure-types.d.ts +14 -3
  44. package/dist/types/sync-closure-types.d.ts.map +1 -1
  45. package/dist/types/sync-engine-level.d.ts +127 -25
  46. package/dist/types/sync-engine-level.d.ts.map +1 -1
  47. package/dist/types/sync-link-id.d.ts +3 -9
  48. package/dist/types/sync-link-id.d.ts.map +1 -1
  49. package/dist/types/sync-link-reconciler.d.ts +12 -2
  50. package/dist/types/sync-link-reconciler.d.ts.map +1 -1
  51. package/dist/types/sync-messages.d.ts +16 -13
  52. package/dist/types/sync-messages.d.ts.map +1 -1
  53. package/dist/types/sync-permission-grants.d.ts +52 -0
  54. package/dist/types/sync-permission-grants.d.ts.map +1 -0
  55. package/dist/types/sync-replication-ledger.d.ts +5 -13
  56. package/dist/types/sync-replication-ledger.d.ts.map +1 -1
  57. package/dist/types/sync-scope-acceptance.d.ts +28 -0
  58. package/dist/types/sync-scope-acceptance.d.ts.map +1 -0
  59. package/dist/types/sync-topological-sort.d.ts +2 -1
  60. package/dist/types/sync-topological-sort.d.ts.map +1 -1
  61. package/dist/types/types/identity-vault.d.ts +9 -0
  62. package/dist/types/types/identity-vault.d.ts.map +1 -1
  63. package/dist/types/types/permissions.d.ts +2 -0
  64. package/dist/types/types/permissions.d.ts.map +1 -1
  65. package/dist/types/types/sync.d.ts +137 -75
  66. package/dist/types/types/sync.d.ts.map +1 -1
  67. package/package.json +3 -3
  68. package/src/dwn-api.ts +3 -2
  69. package/src/enbox-connect-protocol.ts +5 -5
  70. package/src/hd-identity-vault.ts +244 -212
  71. package/src/index.ts +10 -1
  72. package/src/permissions-api.ts +11 -42
  73. package/src/sync-closure-resolver.ts +306 -126
  74. package/src/sync-closure-types.ts +38 -9
  75. package/src/sync-engine-level.ts +2560 -797
  76. package/src/sync-link-id.ts +9 -14
  77. package/src/sync-link-reconciler.ts +43 -10
  78. package/src/sync-messages.ts +263 -159
  79. package/src/sync-permission-grants.ts +297 -0
  80. package/src/sync-replication-ledger.ts +55 -50
  81. package/src/sync-scope-acceptance.ts +186 -0
  82. package/src/sync-topological-sort.ts +89 -21
  83. package/src/types/identity-vault.ts +8 -1
  84. package/src/types/permissions.ts +2 -0
  85. package/src/types/sync.ts +235 -62
@@ -0,0 +1,208 @@
1
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
+ return new (P || (P = Promise))(function (resolve, reject) {
4
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
8
+ });
9
+ };
10
+ import { Jws, Message, PermissionScopeMatcher } from '@enbox/dwn-sdk-js';
11
+ import { lexicographicalCompare, syncScopeFromRecordsProjectionScopes } from './types/sync.js';
12
+ /** Returns a sorted, duplicate-free grant ID set, or `undefined` for owner requests. */
13
+ export function toMessagesPermissionGrantIds(permissionGrantIds) {
14
+ if (permissionGrantIds === undefined || permissionGrantIds.length === 0) {
15
+ return undefined;
16
+ }
17
+ return [...new Set(permissionGrantIds)].sort(lexicographicalCompare);
18
+ }
19
+ /**
20
+ * Gets the active permission grant IDs that authorize a Messages operation.
21
+ *
22
+ * Owner-authored sync does not invoke grants. Delegate full sync requires at
23
+ * least one active unscoped Messages.Read grant. Delegate protocol-set sync
24
+ * requires each requested protocol to be covered by an active Messages.Read
25
+ * grant, then invokes every active grant that participates in the projection.
26
+ * This keeps the authorization epoch tied to grant churn without widening the
27
+ * CID projection being compared.
28
+ */
29
+ export function getMessagesPermissionGrantsForScope(_a) {
30
+ return __awaiter(this, arguments, void 0, function* ({ did, delegateDid, protocols, messageType, permissionsApi, }) {
31
+ const requestedScope = protocols === undefined
32
+ ? { kind: 'full' }
33
+ : { kind: 'protocolSet', protocols };
34
+ const resolutions = yield resolveMessagesSyncScopes({
35
+ did,
36
+ delegateDid,
37
+ requestedScope,
38
+ messageType,
39
+ permissionsApi,
40
+ });
41
+ return resolutions
42
+ .flatMap(resolution => resolution.permissionGrants)
43
+ .sort((a, b) => lexicographicalCompare(a.grant.id, b.grant.id));
44
+ });
45
+ }
46
+ /**
47
+ * Resolves active Messages.Read grants into one or more sync targets.
48
+ *
49
+ * Broad protocol coverage remains on StateIndex full/protocol roots. Exact
50
+ * protocolPath and contextId grants are grouped into a Records-primary
51
+ * projection target so a narrow grant never authorizes a broad protocol root.
52
+ */
53
+ export function resolveMessagesSyncScopes(_a) {
54
+ return __awaiter(this, arguments, void 0, function* ({ did, delegateDid, requestedScope, messageType, permissionsApi, }) {
55
+ if (!delegateDid) {
56
+ return [{ scope: requestedScope, permissionGrants: [] }];
57
+ }
58
+ const now = new Date().toISOString();
59
+ const permissionGrants = (yield permissionsApi.fetchGrants({
60
+ author: delegateDid,
61
+ target: delegateDid,
62
+ grantor: did,
63
+ grantee: delegateDid,
64
+ })).filter(entry => isActiveMessagesGrant(entry, did, delegateDid, now));
65
+ if (requestedScope.kind === 'full') {
66
+ return [resolveFullScope(permissionGrants, requestedScope, messageType)];
67
+ }
68
+ if (requestedScope.kind === 'protocolSet') {
69
+ return resolveProtocolSetScope(permissionGrants, requestedScope, messageType);
70
+ }
71
+ return [resolveRecordsProjectionScope(permissionGrants, requestedScope, messageType)];
72
+ });
73
+ }
74
+ function resolveFullScope(permissionGrants, requestedScope, messageType) {
75
+ const grants = permissionGrants
76
+ .filter(entry => grantMatchesProtocol(entry, undefined))
77
+ .sort((a, b) => lexicographicalCompare(a.grant.id, b.grant.id));
78
+ if (grants.length === 0) {
79
+ throw new Error(`SyncPermissions: No active Messages.Read permission found for ${messageType}: all protocols`);
80
+ }
81
+ return { scope: requestedScope, permissionGrants: grants };
82
+ }
83
+ function resolveProtocolSetScope(permissionGrants, requestedScope, messageType) {
84
+ const broadProtocols = [];
85
+ const narrowScopes = [];
86
+ for (const protocol of requestedScope.protocols) {
87
+ if (permissionGrants.some(entry => grantMatchesProtocol(entry, protocol))) {
88
+ broadProtocols.push(protocol);
89
+ continue;
90
+ }
91
+ const protocolNarrowScopes = permissionGrants
92
+ .map(entry => grantProjectionScopeForProtocol(entry, protocol))
93
+ .filter((scope) => scope !== undefined);
94
+ if (protocolNarrowScopes.length === 0) {
95
+ throw new Error(`SyncPermissions: No active Messages.Read permission found for ${messageType}: ${protocol}`);
96
+ }
97
+ narrowScopes.push(...protocolNarrowScopes);
98
+ }
99
+ return [
100
+ ...broadProtocolResolution(permissionGrants, broadProtocols),
101
+ ...recordsProjectionResolution(permissionGrants, narrowScopes, messageType),
102
+ ];
103
+ }
104
+ function resolveRecordsProjectionScope(permissionGrants, requestedScope, messageType) {
105
+ if (!requestedScope.scopes.every(scope => isProjectionScopeCovered(permissionGrants, scope))) {
106
+ throw new Error(`SyncPermissions: No active Messages.Read permission found for ${messageType}: projected Records scope`);
107
+ }
108
+ const grants = permissionGrants
109
+ .filter(entry => requestedScope.scopes.some(scope => PermissionScopeMatcher.matches(entry.grant.scope, scope)))
110
+ .sort((a, b) => lexicographicalCompare(a.grant.id, b.grant.id));
111
+ return { scope: requestedScope, permissionGrants: grants };
112
+ }
113
+ function isProjectionScopeCovered(permissionGrants, scope) {
114
+ return permissionGrants.some(entry => PermissionScopeMatcher.matches(entry.grant.scope, scope));
115
+ }
116
+ function broadProtocolResolution(permissionGrants, broadProtocols) {
117
+ if (broadProtocols.length === 0) {
118
+ return [];
119
+ }
120
+ const protocols = [...new Set(broadProtocols)].sort(lexicographicalCompare);
121
+ const grants = permissionGrants
122
+ .filter(entry => grantParticipatesInProtocolSet(entry, protocols))
123
+ .sort((a, b) => lexicographicalCompare(a.grant.id, b.grant.id));
124
+ return [{
125
+ scope: {
126
+ kind: 'protocolSet',
127
+ protocols,
128
+ },
129
+ permissionGrants: grants,
130
+ }];
131
+ }
132
+ function recordsProjectionResolution(permissionGrants, projectionScopes, messageType) {
133
+ const [firstScope, ...remainingScopes] = projectionScopes;
134
+ if (firstScope === undefined) {
135
+ return [];
136
+ }
137
+ const requestedScope = syncScopeFromRecordsProjectionScopes([firstScope, ...remainingScopes]);
138
+ return [resolveRecordsProjectionScope(permissionGrants, requestedScope, messageType)];
139
+ }
140
+ function grantProjectionScopeForProtocol(entry, protocol) {
141
+ const scope = entry.grant.scope;
142
+ if (!isMessagesReadScope(scope) || scope.protocol !== protocol) {
143
+ return undefined;
144
+ }
145
+ if (scope.protocolPath !== undefined) {
146
+ return { protocol, protocolPath: scope.protocolPath };
147
+ }
148
+ if (scope.contextId !== undefined) {
149
+ return { protocol, contextId: scope.contextId };
150
+ }
151
+ }
152
+ function isMessagesReadScope(scope) {
153
+ return scope.interface === 'Messages' &&
154
+ scope.method === 'Read';
155
+ }
156
+ function grantParticipatesInProtocolSet(entry, protocols) {
157
+ return protocols.some(protocol => grantMatchesProtocol(entry, protocol));
158
+ }
159
+ /** Converts permission grant entries into authorization epoch inputs. */
160
+ export function toSyncAuthorizationGrants(permissionGrants) {
161
+ if (permissionGrants.length === 0) {
162
+ throw new Error('SyncPermissions: delegate authorization requires at least one grant.');
163
+ }
164
+ return permissionGrants
165
+ .map(({ grant }) => ({
166
+ dateExpires: grant.dateExpires,
167
+ dateGranted: grant.dateGranted,
168
+ id: grant.id,
169
+ }))
170
+ .sort((a, b) => lexicographicalCompare(a.id, b.id));
171
+ }
172
+ function isActiveMessagesGrant(entry, grantor, grantee, now) {
173
+ const { grant } = entry;
174
+ if (grant.grantor !== grantor || grant.grantee !== grantee) {
175
+ return false;
176
+ }
177
+ if (grant.dateGranted > now || grant.dateExpires <= now) {
178
+ return false;
179
+ }
180
+ const scope = grant.scope;
181
+ return scope.interface === 'Messages' &&
182
+ scope.method === 'Read';
183
+ }
184
+ function grantMatchesProtocol(entry, protocol) {
185
+ return PermissionScopeMatcher.matches(entry.grant.scope, { protocol });
186
+ }
187
+ /** Returns sorted grant IDs from permission grant entries. */
188
+ export function permissionGrantIdsFromEntries(permissionGrants) {
189
+ return toMessagesPermissionGrantIds(permissionGrants.map(entry => entry.grant.id));
190
+ }
191
+ /**
192
+ * Returns the permission grant IDs invoked by a message.
193
+ *
194
+ * Real DWN messages use the author signature payload as the source of truth.
195
+ */
196
+ export function getInvokedPermissionGrantIds(message) {
197
+ if (message.authorization === undefined) {
198
+ return [];
199
+ }
200
+ try {
201
+ const signaturePayload = Jws.decodePlainObjectPayload(message.authorization.signature);
202
+ return Message.getPermissionGrantIds(signaturePayload);
203
+ }
204
+ catch (_a) {
205
+ return [];
206
+ }
207
+ }
208
+ //# sourceMappingURL=sync-permission-grants.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sync-permission-grants.js","sourceRoot":"","sources":["../../src/sync-permission-grants.ts"],"names":[],"mappings":"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"}
@@ -14,7 +14,7 @@ var __asyncValues = (this && this.__asyncValues) || function (o) {
14
14
  function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; }
15
15
  function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); }
16
16
  };
17
- import { computeScopeId } from './types/sync.js';
17
+ import { canonicalizeSyncScope, computeProjectionId } from './types/sync.js';
18
18
  /** Separator used in compound LevelDB keys. */
19
19
  const KEY_SEP = '^';
20
20
  /**
@@ -22,7 +22,7 @@ const KEY_SEP = '^';
22
22
  * sync link in a LevelDB sublevel. Provides CRUD operations and replication
23
23
  * checkpoint helpers.
24
24
  *
25
- * Key format: `{tenantDid}^{remoteEndpoint}^{scopeId}`
25
+ * Key format: `{tenantDid}^{remoteEndpoint}^{projectionId}^{authorizationEpoch}`
26
26
  *
27
27
  * Each link tracks independent pull and push {@link DirectionCheckpoint}s.
28
28
  * The ledger does not own subscriptions or timers — it is a passive state
@@ -37,12 +37,13 @@ export class ReplicationLedger {
37
37
  // Key helpers
38
38
  // ---------------------------------------------------------------------------
39
39
  /** Build the compound key for a link. */
40
- static buildKey(tenantDid, remoteEndpoint, scopeId) {
41
- return `${tenantDid}${KEY_SEP}${remoteEndpoint}${KEY_SEP}${scopeId}`;
40
+ static buildKey(tenantDid, remoteEndpoint, projectionId, authorizationEpoch) {
41
+ return `${tenantDid}${KEY_SEP}${remoteEndpoint}${KEY_SEP}${projectionId}${KEY_SEP}${authorizationEpoch}`;
42
42
  }
43
43
  // Note: compound keys use raw '^' separator. This is safe because tenantDid
44
- // (DID URI), remoteEndpoint (URL), and scopeId (base64url hash) cannot
45
- // contain '^'. If future fields can contain '^', keys must be escaped.
44
+ // (DID URI), remoteEndpoint (URL), projectionId (base64url hash), and
45
+ // authorizationEpoch (base64url hash) cannot contain '^'. If future fields
46
+ // can contain '^', keys must be escaped.
46
47
  // ---------------------------------------------------------------------------
47
48
  // CRUD
48
49
  // ---------------------------------------------------------------------------
@@ -52,12 +53,12 @@ export class ReplicationLedger {
52
53
  */
53
54
  getOrCreateLink(params) {
54
55
  return __awaiter(this, void 0, void 0, function* () {
55
- const scopeId = yield computeScopeId(params.scope);
56
- const key = ReplicationLedger.buildKey(params.tenantDid, params.remoteEndpoint, scopeId);
56
+ const scope = canonicalizeSyncScope(params.scope);
57
+ const projectionId = yield computeProjectionId(params.tenantDid, scope);
58
+ const key = ReplicationLedger.buildKey(params.tenantDid, params.remoteEndpoint, projectionId, params.authorizationEpoch);
57
59
  try {
58
60
  const raw = yield this.sublevel.get(key);
59
61
  const link = JSON.parse(raw);
60
- delete link.push; // strip legacy push field from old persisted links
61
62
  // connectivity is runtime state — always reset to 'unknown' on load
62
63
  // so stale 'online' from a previous session doesn't give false positives.
63
64
  link.connectivity = 'unknown';
@@ -73,14 +74,15 @@ export class ReplicationLedger {
73
74
  const link = {
74
75
  tenantDid: params.tenantDid,
75
76
  remoteEndpoint: params.remoteEndpoint,
76
- scopeId,
77
- scope: params.scope,
77
+ projectionId,
78
+ authorizationEpoch: params.authorizationEpoch,
79
+ scope,
80
+ authorization: params.authorization,
78
81
  status: 'initializing',
79
82
  connectivity: 'unknown',
80
83
  pull: {},
81
84
  needsReconcile: false,
82
85
  delegateDid: params.delegateDid,
83
- protocol: params.protocol,
84
86
  };
85
87
  yield this.sublevel.put(key, JSON.stringify(link));
86
88
  return link;
@@ -89,15 +91,15 @@ export class ReplicationLedger {
89
91
  /** Persist the current state of a link. */
90
92
  saveLink(link) {
91
93
  return __awaiter(this, void 0, void 0, function* () {
92
- const key = ReplicationLedger.buildKey(link.tenantDid, link.remoteEndpoint, link.scopeId);
94
+ const key = ReplicationLedger.buildKey(link.tenantDid, link.remoteEndpoint, link.projectionId, link.authorizationEpoch);
93
95
  link.lastActivityAt = new Date().toISOString();
94
96
  yield this.sublevel.put(key, JSON.stringify(link));
95
97
  });
96
98
  }
97
99
  /** Delete a link. */
98
- deleteLink(tenantDid, remoteEndpoint, scopeId) {
100
+ deleteLink(tenantDid, remoteEndpoint, projectionId, authorizationEpoch) {
99
101
  return __awaiter(this, void 0, void 0, function* () {
100
- const key = ReplicationLedger.buildKey(tenantDid, remoteEndpoint, scopeId);
102
+ const key = ReplicationLedger.buildKey(tenantDid, remoteEndpoint, projectionId, authorizationEpoch);
101
103
  yield this.sublevel.del(key);
102
104
  });
103
105
  }
@@ -151,31 +153,6 @@ export class ReplicationLedger {
151
153
  });
152
154
  }
153
155
  // ---------------------------------------------------------------------------
154
- // Delegate updates
155
- // ---------------------------------------------------------------------------
156
- /**
157
- * Update the `delegateDid` on all persisted links for a tenant and persist.
158
- * This ensures that repair and reconcile paths — which read `delegateDid`
159
- * from the durable {@link ReplicationLinkState} — use the current delegate
160
- * after a hot-swap via `updateIdentityOptions()`.
161
- *
162
- * @returns the links that were updated.
163
- */
164
- updateDelegateDid(tenantDid, delegateDid) {
165
- return __awaiter(this, void 0, void 0, function* () {
166
- const links = yield this.getLinksForTenant(tenantDid);
167
- const updated = [];
168
- for (const link of links) {
169
- if (link.delegateDid !== delegateDid) {
170
- link.delegateDid = delegateDid;
171
- yield this.saveLink(link);
172
- updated.push(link);
173
- }
174
- }
175
- return updated;
176
- });
177
- }
178
- // ---------------------------------------------------------------------------
179
156
  // Status transitions
180
157
  // ---------------------------------------------------------------------------
181
158
  /** Transition a link to a new status and persist. */
@@ -232,6 +209,12 @@ export class ReplicationLedger {
232
209
  * are durably committed before calling this.
233
210
  */
234
211
  static commitContiguousToken(checkpoint, token) {
212
+ if (checkpoint.contiguousAppliedToken !== undefined &&
213
+ token.streamId === checkpoint.contiguousAppliedToken.streamId &&
214
+ token.epoch === checkpoint.contiguousAppliedToken.epoch &&
215
+ ReplicationLedger.comparePosition(token, checkpoint.contiguousAppliedToken) <= 0) {
216
+ return;
217
+ }
235
218
  checkpoint.contiguousAppliedToken = token;
236
219
  }
237
220
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"sync-replication-ledger.js","sourceRoot":"","sources":["../../src/sync-replication-ledger.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"sync-replication-ledger.js","sourceRoot":"","sources":["../../src/sync-replication-ledger.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,126 @@
1
+ import { DwnInterfaceName, DwnMethodName, PermissionScopeMatcher, PermissionsProtocol } from '@enbox/dwn-sdk-js';
2
+ /**
3
+ * Classifies whether a live event belongs to the link's current sync scope.
4
+ *
5
+ * Full links accept every message. Protocol-set links accept records for a
6
+ * covered protocol, ProtocolsConfigure messages that install a covered
7
+ * protocol, and permission records tagged for a covered protocol. RecordsDelete
8
+ * messages carry no protocol in their descriptor, so they must be classified
9
+ * from the event's initial write metadata.
10
+ */
11
+ export function classifySyncEventScope(event, scope) {
12
+ return classifySyncMessageScope({
13
+ message: event.message,
14
+ initialWrite: event.initialWrite,
15
+ scope,
16
+ });
17
+ }
18
+ /**
19
+ * Classifies whether a DWN message belongs to a sync scope before local apply.
20
+ *
21
+ * If a RecordsDelete cannot be tied to its initial write, the result is
22
+ * `unknown` so callers fail closed instead of applying an unclassified delete.
23
+ */
24
+ export function classifySyncMessageScope({ message, initialWrite, scope, }) {
25
+ if (scope.kind === 'full') {
26
+ return 'in-scope';
27
+ }
28
+ if (scope.kind === 'recordsProjection') {
29
+ return classifyRecordsProjectionScope(message, initialWrite, scope);
30
+ }
31
+ return classifyProtocolSetScope(message, initialWrite, scope);
32
+ }
33
+ function classifyProtocolSetScope(message, initialWrite, scope) {
34
+ const descriptor = message.descriptor;
35
+ const scopedDescriptor = getScopedMessageDescriptor(message, initialWrite);
36
+ if (scopedDescriptor === undefined) {
37
+ return 'unknown';
38
+ }
39
+ const permissionRecordClassification = classifyTaggedPermissionRecord(scopedDescriptor, scope.protocols);
40
+ if (permissionRecordClassification !== undefined) {
41
+ return permissionRecordClassification;
42
+ }
43
+ const protocolClassification = classifyProtocolField(scopedDescriptor.protocol, scope.protocols);
44
+ if (protocolClassification !== undefined) {
45
+ return protocolClassification;
46
+ }
47
+ return classifyProtocolsConfigureDescriptor(descriptor, scope.protocols);
48
+ }
49
+ function classifyTaggedPermissionRecord(descriptor, protocols) {
50
+ if (descriptor.protocol !== PermissionsProtocol.uri || !isRecordObject(descriptor.tags)) {
51
+ return undefined;
52
+ }
53
+ const taggedProtocol = descriptor.tags.protocol;
54
+ return typeof taggedProtocol === 'string' && protocols.includes(taggedProtocol)
55
+ ? 'in-scope'
56
+ : 'out-of-scope';
57
+ }
58
+ function classifyProtocolField(protocol, protocols) {
59
+ if (typeof protocol !== 'string') {
60
+ return undefined;
61
+ }
62
+ return protocols.includes(protocol) ? 'in-scope' : 'out-of-scope';
63
+ }
64
+ function classifyProtocolsConfigureDescriptor(descriptor, protocols) {
65
+ if (descriptor.interface === DwnInterfaceName.Protocols &&
66
+ descriptor.method === DwnMethodName.Configure &&
67
+ isRecordObject(descriptor.definition)) {
68
+ const definitionProtocol = descriptor.definition.protocol;
69
+ return typeof definitionProtocol === 'string' && protocols.includes(definitionProtocol)
70
+ ? 'in-scope'
71
+ : 'out-of-scope';
72
+ }
73
+ return 'out-of-scope';
74
+ }
75
+ function getScopedMessageDescriptor(message, initialWrite) {
76
+ const descriptor = message.descriptor;
77
+ if (descriptor.interface === DwnInterfaceName.Records &&
78
+ descriptor.method === DwnMethodName.Delete) {
79
+ return initialWrite === null || initialWrite === void 0 ? void 0 : initialWrite.descriptor;
80
+ }
81
+ return descriptor;
82
+ }
83
+ function classifyRecordsProjectionScope(message, initialWrite, scope) {
84
+ const target = getRecordsProjectionTarget(message, initialWrite);
85
+ if (target === undefined) {
86
+ return isRecordsDelete(message) ? 'unknown' : 'out-of-scope';
87
+ }
88
+ return scope.scopes.some(projectionScope => PermissionScopeMatcher.matches(projectionScope, target))
89
+ ? 'in-scope'
90
+ : 'out-of-scope';
91
+ }
92
+ function getRecordsProjectionTarget(message, initialWrite) {
93
+ const descriptor = message.descriptor;
94
+ if (descriptor.interface !== DwnInterfaceName.Records) {
95
+ return undefined;
96
+ }
97
+ if (descriptor.method === DwnMethodName.Write) {
98
+ return {
99
+ protocol: stringField(descriptor.protocol),
100
+ protocolPath: stringField(descriptor.protocolPath),
101
+ contextId: message.contextId,
102
+ };
103
+ }
104
+ if (descriptor.method === DwnMethodName.Delete) {
105
+ if (initialWrite === undefined) {
106
+ return undefined;
107
+ }
108
+ return {
109
+ protocol: initialWrite.descriptor.protocol,
110
+ protocolPath: initialWrite.descriptor.protocolPath,
111
+ contextId: initialWrite.contextId,
112
+ };
113
+ }
114
+ }
115
+ function isRecordsDelete(message) {
116
+ const descriptor = message.descriptor;
117
+ return descriptor.interface === DwnInterfaceName.Records &&
118
+ descriptor.method === DwnMethodName.Delete;
119
+ }
120
+ function isRecordObject(value) {
121
+ return typeof value === 'object' && value !== null;
122
+ }
123
+ function stringField(value) {
124
+ return typeof value === 'string' ? value : undefined;
125
+ }
126
+ //# sourceMappingURL=sync-scope-acceptance.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sync-scope-acceptance.js","sourceRoot":"","sources":["../../src/sync-scope-acceptance.ts"],"names":[],"mappings":"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"}
@@ -1,11 +1,44 @@
1
+ import { getInvokedPermissionGrantIds } from './sync-permission-grants.js';
1
2
  import { DwnInterfaceName, DwnMethodName, PermissionsProtocol } from '@enbox/dwn-sdk-js';
3
+ function isRecordsDescriptor(descriptor) {
4
+ return descriptor.interface === DwnInterfaceName.Records;
5
+ }
6
+ function isRecordsWriteDescriptor(descriptor) {
7
+ return descriptor.interface === DwnInterfaceName.Records && descriptor.method === DwnMethodName.Write;
8
+ }
9
+ function isRecordsDeleteDescriptor(descriptor) {
10
+ return descriptor.interface === DwnInterfaceName.Records && descriptor.method === DwnMethodName.Delete;
11
+ }
12
+ function isProtocolsConfigureDescriptor(descriptor) {
13
+ return descriptor.interface === DwnInterfaceName.Protocols && descriptor.method === DwnMethodName.Configure;
14
+ }
15
+ function getRecordId(message) {
16
+ return message.recordId;
17
+ }
18
+ function getProtocolDefinition(message) {
19
+ const { descriptor } = message;
20
+ return isProtocolsConfigureDescriptor(descriptor) ? descriptor.definition : undefined;
21
+ }
22
+ function getConfiguredProtocol(message) {
23
+ var _a;
24
+ const protocol = (_a = getProtocolDefinition(message)) === null || _a === void 0 ? void 0 : _a.protocol;
25
+ return typeof protocol === 'string' ? protocol : undefined;
26
+ }
27
+ function getComposedProtocolDependencies(message) {
28
+ var _a;
29
+ const uses = (_a = getProtocolDefinition(message)) === null || _a === void 0 ? void 0 : _a.uses;
30
+ if (!uses) {
31
+ return [];
32
+ }
33
+ return Object.values(uses).filter((protocol) => typeof protocol === 'string');
34
+ }
2
35
  /**
3
36
  * Checks whether a message is an initial RecordsWrite (not an update).
4
37
  * An initial write has dateCreated === messageTimestamp (first write for this recordId).
5
38
  */
6
39
  function isInitialWrite(message) {
7
40
  const desc = message.descriptor;
8
- if (desc.interface !== DwnInterfaceName.Records || desc.method !== DwnMethodName.Write) {
41
+ if (!isRecordsWriteDescriptor(desc)) {
9
42
  return false;
10
43
  }
11
44
  // A RecordsWrite is initial if dateCreated === messageTimestamp (first write for this recordId).
@@ -17,12 +50,12 @@ function isInitialWrite(message) {
17
50
  *
18
51
  * Dependencies:
19
52
  * - ProtocolsConfigure must come before any RecordsWrite using that protocol
53
+ * - Composed ProtocolsConfigure must come after ProtocolsConfigure messages for protocols in `uses`
20
54
  * - Parent record must come before child record (via parentId)
21
55
  * - Initial write must come before update writes (same recordId, not initial)
22
- * - Permission grant must come before records using that permissionGrantId
56
+ * - Permission grants must come before messages that invoke them
23
57
  */
24
58
  export function topologicalSort(messages) {
25
- var _a;
26
59
  if (messages.length <= 1) {
27
60
  return messages;
28
61
  }
@@ -36,13 +69,13 @@ export function topologicalSort(messages) {
36
69
  byIndex.set(i, entry);
37
70
  const desc = entry.message.descriptor;
38
71
  if (desc.interface === DwnInterfaceName.Protocols && desc.method === DwnMethodName.Configure) {
39
- const protocolUrl = (_a = desc.definition) === null || _a === void 0 ? void 0 : _a.protocol;
72
+ const protocolUrl = getConfiguredProtocol(entry.message);
40
73
  if (protocolUrl) {
41
74
  protocolConfigureIndex.set(protocolUrl, i);
42
75
  }
43
76
  }
44
- if (desc.interface === DwnInterfaceName.Records && desc.method === DwnMethodName.Write) {
45
- const recordId = entry.message.recordId;
77
+ if (isRecordsWriteDescriptor(desc)) {
78
+ const recordId = getRecordId(entry.message);
46
79
  const initial = isInitialWrite(entry.message);
47
80
  if (initial && recordId) {
48
81
  initialWriteIndex.set(recordId, i);
@@ -73,38 +106,47 @@ export function topologicalSort(messages) {
73
106
  };
74
107
  for (let i = 0; i < messages.length; i++) {
75
108
  const desc = messages[i].message.descriptor;
109
+ // Composition dependency: a composed protocol depends on its referenced protocol definitions.
110
+ if (isProtocolsConfigureDescriptor(desc)) {
111
+ for (const protocol of getComposedProtocolDependencies(messages[i].message)) {
112
+ if (protocolConfigureIndex.has(protocol)) {
113
+ addEdge(protocolConfigureIndex.get(protocol), i);
114
+ }
115
+ }
116
+ }
76
117
  // Protocol dependency: RecordsWrite depends on ProtocolsConfigure for its protocol.
77
- if (desc.interface === DwnInterfaceName.Records) {
118
+ if (isRecordsDescriptor(desc)) {
78
119
  const protocol = desc.protocol;
79
120
  if (protocol && protocolConfigureIndex.has(protocol)) {
80
121
  addEdge(protocolConfigureIndex.get(protocol), i);
81
122
  }
82
123
  }
83
124
  // Parent dependency: child record depends on parent record.
84
- if (desc.interface === DwnInterfaceName.Records && desc.parentId) {
125
+ if (isRecordsDescriptor(desc) && desc.parentId) {
85
126
  const parentId = desc.parentId;
86
127
  if (initialWriteIndex.has(parentId)) {
87
128
  addEdge(initialWriteIndex.get(parentId), i);
88
129
  }
89
130
  }
90
131
  // Initial write dependency: update depends on initial write.
91
- if (desc.interface === DwnInterfaceName.Records && desc.method === DwnMethodName.Write) {
92
- const recordId = messages[i].message.recordId;
132
+ if (isRecordsWriteDescriptor(desc)) {
133
+ const recordId = getRecordId(messages[i].message);
93
134
  if (recordId && !isInitialWrite(messages[i].message) && initialWriteIndex.has(recordId)) {
94
135
  addEdge(initialWriteIndex.get(recordId), i);
95
136
  }
96
137
  }
97
138
  // Delete depends on initial write.
98
- if (desc.interface === DwnInterfaceName.Records && desc.method === DwnMethodName.Delete) {
139
+ if (isRecordsDeleteDescriptor(desc)) {
99
140
  const recordId = desc.recordId;
100
141
  if (recordId && initialWriteIndex.has(recordId)) {
101
142
  addEdge(initialWriteIndex.get(recordId), i);
102
143
  }
103
144
  }
104
- // Permission grant dependency: message depends on the grant it references.
105
- const permissionGrantId = desc.permissionGrantId;
106
- if (permissionGrantId && grantIndex.has(permissionGrantId)) {
107
- addEdge(grantIndex.get(permissionGrantId), i);
145
+ // Permission grant dependency: message depends on each grant it references.
146
+ for (const permissionGrantId of getInvokedPermissionGrantIds(messages[i].message)) {
147
+ if (grantIndex.has(permissionGrantId)) {
148
+ addEdge(grantIndex.get(permissionGrantId), i);
149
+ }
108
150
  }
109
151
  }
110
152
  // Kahn's algorithm for topological sort.