@enbox/dwn-sdk-js 0.3.4 → 0.3.5

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 (199) hide show
  1. package/dist/browser.mjs +8 -8
  2. package/dist/browser.mjs.map +3 -3
  3. package/dist/esm/generated/precompiled-validators.js +766 -1224
  4. package/dist/esm/generated/precompiled-validators.js.map +1 -1
  5. package/dist/esm/src/core/abstract-message.js +3 -3
  6. package/dist/esm/src/core/abstract-message.js.map +1 -1
  7. package/dist/esm/src/core/grant-authorization.js +6 -2
  8. package/dist/esm/src/core/grant-authorization.js.map +1 -1
  9. package/dist/esm/src/core/message.js +3 -3
  10. package/dist/esm/src/core/message.js.map +1 -1
  11. package/dist/esm/src/core/protocol-authorization-action.js +3 -3
  12. package/dist/esm/src/core/protocol-authorization-action.js.map +1 -1
  13. package/dist/esm/src/core/protocol-authorization-validation.js +1 -1
  14. package/dist/esm/src/core/protocol-authorization-validation.js.map +1 -1
  15. package/dist/esm/src/core/protocol-authorization.js +11 -11
  16. package/dist/esm/src/core/protocol-authorization.js.map +1 -1
  17. package/dist/esm/src/core/records-grant-authorization.js +1 -1
  18. package/dist/esm/src/core/records-grant-authorization.js.map +1 -1
  19. package/dist/esm/src/core/resumable-task-manager.js.map +1 -1
  20. package/dist/esm/src/dwn.js.map +1 -1
  21. package/dist/esm/src/event-stream/event-emitter-event-log.js +12 -12
  22. package/dist/esm/src/event-stream/event-emitter-event-log.js.map +1 -1
  23. package/dist/esm/src/handlers/messages-read.js +7 -7
  24. package/dist/esm/src/handlers/messages-read.js.map +1 -1
  25. package/dist/esm/src/handlers/messages-subscribe.js +1 -1
  26. package/dist/esm/src/handlers/messages-subscribe.js.map +1 -1
  27. package/dist/esm/src/handlers/messages-sync.js +18 -18
  28. package/dist/esm/src/handlers/messages-sync.js.map +1 -1
  29. package/dist/esm/src/handlers/protocols-configure.js +1 -1
  30. package/dist/esm/src/handlers/protocols-configure.js.map +1 -1
  31. package/dist/esm/src/handlers/protocols-query.js.map +1 -1
  32. package/dist/esm/src/handlers/records-count.js.map +1 -1
  33. package/dist/esm/src/handlers/records-delete.js.map +1 -1
  34. package/dist/esm/src/handlers/records-query.js.map +1 -1
  35. package/dist/esm/src/handlers/records-read.js +6 -6
  36. package/dist/esm/src/handlers/records-read.js.map +1 -1
  37. package/dist/esm/src/handlers/records-subscribe.js +1 -1
  38. package/dist/esm/src/handlers/records-subscribe.js.map +1 -1
  39. package/dist/esm/src/handlers/records-write.js +16 -16
  40. package/dist/esm/src/handlers/records-write.js.map +1 -1
  41. package/dist/esm/src/index.js +2 -2
  42. package/dist/esm/src/index.js.map +1 -1
  43. package/dist/esm/src/interfaces/protocols-configure.js +9 -9
  44. package/dist/esm/src/interfaces/protocols-configure.js.map +1 -1
  45. package/dist/esm/src/interfaces/records-delete.js.map +1 -1
  46. package/dist/esm/src/interfaces/records-write.js +8 -8
  47. package/dist/esm/src/interfaces/records-write.js.map +1 -1
  48. package/dist/esm/src/jose/jws/general/builder.js.map +1 -1
  49. package/dist/esm/src/jose/jws/general/verifier.js +30 -2
  50. package/dist/esm/src/jose/jws/general/verifier.js.map +1 -1
  51. package/dist/esm/src/protocols/permissions.js +1 -1
  52. package/dist/esm/src/protocols/permissions.js.map +1 -1
  53. package/dist/esm/src/smt/smt-store-level.js.map +1 -1
  54. package/dist/esm/src/smt/smt-store-memory.js.map +1 -1
  55. package/dist/esm/src/smt/sparse-merkle-tree.js +2 -2
  56. package/dist/esm/src/smt/sparse-merkle-tree.js.map +1 -1
  57. package/dist/esm/src/state-index/state-index-level.js.map +1 -1
  58. package/dist/esm/src/store/index-level-compound.js +10 -10
  59. package/dist/esm/src/store/index-level-compound.js.map +1 -1
  60. package/dist/esm/src/store/index-level.js +2 -2
  61. package/dist/esm/src/store/index-level.js.map +1 -1
  62. package/dist/esm/src/store/level-wrapper.js +1 -1
  63. package/dist/esm/src/store/level-wrapper.js.map +1 -1
  64. package/dist/esm/src/store/storage-controller.js +23 -10
  65. package/dist/esm/src/store/storage-controller.js.map +1 -1
  66. package/dist/esm/src/types/permission-types.js.map +1 -1
  67. package/dist/esm/src/utils/memory-cache.js.map +1 -1
  68. package/dist/esm/src/utils/messages.js +1 -1
  69. package/dist/esm/src/utils/messages.js.map +1 -1
  70. package/dist/esm/src/utils/object.js +1 -4
  71. package/dist/esm/src/utils/object.js.map +1 -1
  72. package/dist/esm/src/utils/private-key-signer.js.map +1 -1
  73. package/dist/esm/src/utils/records.js.map +1 -1
  74. package/dist/esm/tests/core/grant-authorization.spec.js +38 -0
  75. package/dist/esm/tests/core/grant-authorization.spec.js.map +1 -0
  76. package/dist/esm/tests/features/permissions.spec.js +1 -1
  77. package/dist/esm/tests/features/permissions.spec.js.map +1 -1
  78. package/dist/esm/tests/features/records-prune-cross-protocol.spec.js +422 -0
  79. package/dist/esm/tests/features/records-prune-cross-protocol.spec.js.map +1 -0
  80. package/dist/esm/tests/handlers/messages-subscribe.spec.js +3 -26
  81. package/dist/esm/tests/handlers/messages-subscribe.spec.js.map +1 -1
  82. package/dist/esm/tests/handlers/messages-sync.spec.js +3 -26
  83. package/dist/esm/tests/handlers/messages-sync.spec.js.map +1 -1
  84. package/dist/esm/tests/handlers/protocols-query.spec.js +4 -3
  85. package/dist/esm/tests/handlers/protocols-query.spec.js.map +1 -1
  86. package/dist/esm/tests/jose/jws/general.spec.js +115 -0
  87. package/dist/esm/tests/jose/jws/general.spec.js.map +1 -1
  88. package/dist/esm/tests/test-suite.js +2 -0
  89. package/dist/esm/tests/test-suite.js.map +1 -1
  90. package/dist/types/generated/precompiled-validators.d.ts.map +1 -1
  91. package/dist/types/src/core/abstract-message.d.ts +4 -4
  92. package/dist/types/src/core/abstract-message.d.ts.map +1 -1
  93. package/dist/types/src/core/grant-authorization.d.ts.map +1 -1
  94. package/dist/types/src/core/resumable-task-manager.d.ts +2 -2
  95. package/dist/types/src/core/resumable-task-manager.d.ts.map +1 -1
  96. package/dist/types/src/dwn.d.ts +12 -12
  97. package/dist/types/src/dwn.d.ts.map +1 -1
  98. package/dist/types/src/event-stream/event-emitter-event-log.d.ts +5 -5
  99. package/dist/types/src/event-stream/event-emitter-event-log.d.ts.map +1 -1
  100. package/dist/types/src/handlers/messages-read.d.ts +1 -1
  101. package/dist/types/src/handlers/messages-read.d.ts.map +1 -1
  102. package/dist/types/src/handlers/messages-subscribe.d.ts +1 -1
  103. package/dist/types/src/handlers/messages-subscribe.d.ts.map +1 -1
  104. package/dist/types/src/handlers/messages-sync.d.ts +1 -1
  105. package/dist/types/src/handlers/messages-sync.d.ts.map +1 -1
  106. package/dist/types/src/handlers/protocols-configure.d.ts +1 -1
  107. package/dist/types/src/handlers/protocols-configure.d.ts.map +1 -1
  108. package/dist/types/src/handlers/protocols-query.d.ts +1 -1
  109. package/dist/types/src/handlers/protocols-query.d.ts.map +1 -1
  110. package/dist/types/src/handlers/records-count.d.ts +1 -1
  111. package/dist/types/src/handlers/records-count.d.ts.map +1 -1
  112. package/dist/types/src/handlers/records-delete.d.ts +1 -1
  113. package/dist/types/src/handlers/records-delete.d.ts.map +1 -1
  114. package/dist/types/src/handlers/records-query.d.ts +1 -1
  115. package/dist/types/src/handlers/records-query.d.ts.map +1 -1
  116. package/dist/types/src/handlers/records-read.d.ts +1 -1
  117. package/dist/types/src/handlers/records-read.d.ts.map +1 -1
  118. package/dist/types/src/handlers/records-subscribe.d.ts +1 -1
  119. package/dist/types/src/handlers/records-subscribe.d.ts.map +1 -1
  120. package/dist/types/src/handlers/records-write.d.ts +1 -1
  121. package/dist/types/src/handlers/records-write.d.ts.map +1 -1
  122. package/dist/types/src/index.d.ts +5 -5
  123. package/dist/types/src/index.d.ts.map +1 -1
  124. package/dist/types/src/interfaces/records-write.d.ts +2 -2
  125. package/dist/types/src/interfaces/records-write.d.ts.map +1 -1
  126. package/dist/types/src/jose/jws/general/builder.d.ts +1 -1
  127. package/dist/types/src/jose/jws/general/builder.d.ts.map +1 -1
  128. package/dist/types/src/jose/jws/general/verifier.d.ts +13 -0
  129. package/dist/types/src/jose/jws/general/verifier.d.ts.map +1 -1
  130. package/dist/types/src/smt/smt-store-level.d.ts +1 -1
  131. package/dist/types/src/smt/smt-store-level.d.ts.map +1 -1
  132. package/dist/types/src/smt/smt-store-memory.d.ts +1 -1
  133. package/dist/types/src/smt/smt-store-memory.d.ts.map +1 -1
  134. package/dist/types/src/smt/sparse-merkle-tree.d.ts +1 -1
  135. package/dist/types/src/smt/sparse-merkle-tree.d.ts.map +1 -1
  136. package/dist/types/src/state-index/state-index-level.d.ts +3 -3
  137. package/dist/types/src/state-index/state-index-level.d.ts.map +1 -1
  138. package/dist/types/src/store/index-level.d.ts +2 -2
  139. package/dist/types/src/store/index-level.d.ts.map +1 -1
  140. package/dist/types/src/store/storage-controller.d.ts +19 -5
  141. package/dist/types/src/store/storage-controller.d.ts.map +1 -1
  142. package/dist/types/src/types/permission-types.d.ts +3 -4
  143. package/dist/types/src/types/permission-types.d.ts.map +1 -1
  144. package/dist/types/src/utils/memory-cache.d.ts +2 -2
  145. package/dist/types/src/utils/memory-cache.d.ts.map +1 -1
  146. package/dist/types/src/utils/object.d.ts.map +1 -1
  147. package/dist/types/src/utils/private-key-signer.d.ts +2 -2
  148. package/dist/types/src/utils/private-key-signer.d.ts.map +1 -1
  149. package/dist/types/tests/core/grant-authorization.spec.d.ts +2 -0
  150. package/dist/types/tests/core/grant-authorization.spec.d.ts.map +1 -0
  151. package/dist/types/tests/features/records-prune-cross-protocol.spec.d.ts +29 -0
  152. package/dist/types/tests/features/records-prune-cross-protocol.spec.d.ts.map +1 -0
  153. package/dist/types/tests/handlers/messages-subscribe.spec.d.ts.map +1 -1
  154. package/dist/types/tests/handlers/messages-sync.spec.d.ts.map +1 -1
  155. package/dist/types/tests/handlers/protocols-query.spec.d.ts.map +1 -1
  156. package/dist/types/tests/test-suite.d.ts.map +1 -1
  157. package/package.json +1 -1
  158. package/src/core/abstract-message.ts +8 -8
  159. package/src/core/grant-authorization.ts +9 -2
  160. package/src/core/message.ts +3 -3
  161. package/src/core/protocol-authorization-action.ts +3 -3
  162. package/src/core/protocol-authorization-validation.ts +9 -9
  163. package/src/core/protocol-authorization.ts +24 -24
  164. package/src/core/records-grant-authorization.ts +1 -1
  165. package/src/core/resumable-task-manager.ts +2 -2
  166. package/src/dwn.ts +13 -13
  167. package/src/event-stream/event-emitter-event-log.ts +15 -15
  168. package/src/handlers/messages-read.ts +7 -7
  169. package/src/handlers/messages-subscribe.ts +2 -2
  170. package/src/handlers/messages-sync.ts +19 -19
  171. package/src/handlers/protocols-configure.ts +2 -2
  172. package/src/handlers/protocols-query.ts +1 -1
  173. package/src/handlers/records-count.ts +1 -1
  174. package/src/handlers/records-delete.ts +1 -1
  175. package/src/handlers/records-query.ts +1 -1
  176. package/src/handlers/records-read.ts +6 -6
  177. package/src/handlers/records-subscribe.ts +2 -2
  178. package/src/handlers/records-write.ts +18 -18
  179. package/src/index.ts +5 -5
  180. package/src/interfaces/protocols-configure.ts +12 -12
  181. package/src/interfaces/records-delete.ts +1 -1
  182. package/src/interfaces/records-write.ts +11 -11
  183. package/src/jose/jws/general/builder.ts +1 -1
  184. package/src/jose/jws/general/verifier.ts +44 -3
  185. package/src/protocols/permissions.ts +1 -1
  186. package/src/smt/smt-store-level.ts +1 -1
  187. package/src/smt/smt-store-memory.ts +1 -1
  188. package/src/smt/sparse-merkle-tree.ts +10 -10
  189. package/src/state-index/state-index-level.ts +3 -3
  190. package/src/store/index-level-compound.ts +11 -11
  191. package/src/store/index-level.ts +4 -4
  192. package/src/store/level-wrapper.ts +1 -1
  193. package/src/store/storage-controller.ts +31 -16
  194. package/src/types/permission-types.ts +3 -4
  195. package/src/utils/memory-cache.ts +2 -2
  196. package/src/utils/messages.ts +2 -2
  197. package/src/utils/object.ts +1 -5
  198. package/src/utils/private-key-signer.ts +2 -2
  199. package/src/utils/records.ts +1 -1
@@ -146,8 +146,15 @@ export class GrantAuthorization {
146
146
  );
147
147
  }
148
148
 
149
- // For the Messages interface, a `Read` scope is a unified scope that also covers `Subscribe` and `Sync`.
150
- if (dwnInterface === DwnInterfaceName.Messages && permissionGrant.scope.method === DwnMethodName.Read) {
149
+ // Messages.Read is the only valid Messages scope and covers Read, Subscribe, and Sync operations.
150
+ // Reject any Messages grant with method !== Read (malformed or legacy stored data).
151
+ if (dwnInterface === DwnInterfaceName.Messages) {
152
+ if (permissionGrant.scope.method !== DwnMethodName.Read) {
153
+ throw new DwnError(
154
+ DwnErrorCode.GrantAuthorizationMethodMismatch,
155
+ `messages permission grant must have method 'Read', got '${permissionGrant.scope.method}' for grant ${permissionGrant.id}`
156
+ );
157
+ }
151
158
  const allowedMethods = [DwnMethodName.Read, DwnMethodName.Subscribe, DwnMethodName.Sync];
152
159
  if (!allowedMethods.includes(dwnMethod as DwnMethodName)) {
153
160
  throw new DwnError(
@@ -26,10 +26,10 @@ export class Message {
26
26
  }
27
27
 
28
28
  let author;
29
- if (message.authorization.authorDelegatedGrant !== undefined) {
30
- author = Message.getSigner(message.authorization.authorDelegatedGrant);
31
- } else {
29
+ if (message.authorization.authorDelegatedGrant === undefined) {
32
30
  author = Message.getSigner(message);
31
+ } else {
32
+ author = Message.getSigner(message.authorization.authorDelegatedGrant);
33
33
  }
34
34
 
35
35
  return author;
@@ -53,7 +53,7 @@ export async function verifyInvokedRole(
53
53
  );
54
54
  }
55
55
 
56
- if (protocolDefinition.uses === undefined || protocolDefinition.uses[parsed.alias] === undefined) {
56
+ if (protocolDefinition.uses?.[parsed.alias] === undefined) {
57
57
  throw new DwnError(
58
58
  DwnErrorCode.ProtocolAuthorizationNotARole,
59
59
  `Cross-protocol role alias '${parsed.alias}' in '${protocolRole}' does not exist in the protocol's 'uses' map.`
@@ -68,7 +68,7 @@ export async function verifyInvokedRole(
68
68
  tenant, roleProtocolUri, messageStore, governingTimestamp
69
69
  );
70
70
  const roleRuleSet = getRuleSetAtPath(roleProtocolPath, refDefinition.structure);
71
- if (roleRuleSet === undefined || !roleRuleSet.$role) {
71
+ if (!roleRuleSet?.$role) {
72
72
  throw new DwnError(
73
73
  DwnErrorCode.ProtocolAuthorizationNotARole,
74
74
  `Cross-protocol role path ${protocolRole} does not match role record type.`
@@ -77,7 +77,7 @@ export async function verifyInvokedRole(
77
77
  } else {
78
78
  // Local role: validate in the composing protocol's definition
79
79
  const roleRuleSet = getRuleSetAtPath(protocolRole, protocolDefinition.structure);
80
- if (roleRuleSet === undefined || !roleRuleSet.$role) {
80
+ if (!roleRuleSet?.$role) {
81
81
  throw new DwnError(
82
82
  DwnErrorCode.ProtocolAuthorizationNotARole,
83
83
  `Protocol path ${protocolRole} does not match role record type.`
@@ -28,7 +28,7 @@ export async function verifyProtocolPathAndContextId(
28
28
  fetchProtocolDefinition: FetchProtocolDefinitionFn,
29
29
  governingTimestamp?: string,
30
30
  ): Promise<void> {
31
- const declaredProtocolPath = inboundMessage.message.descriptor.protocolPath!;
31
+ const declaredProtocolPath = inboundMessage.message.descriptor.protocolPath;
32
32
  const declaredTypeName = getTypeName(declaredProtocolPath);
33
33
 
34
34
  const parentId = inboundMessage.message.descriptor.parentId;
@@ -47,7 +47,7 @@ export async function verifyProtocolPathAndContextId(
47
47
 
48
48
  // Determine the protocol URI for the parent query.
49
49
  // If the parent path segment has a `$ref` in the composing protocol, the parent lives in a different protocol.
50
- const childProtocol = inboundMessage.message.descriptor.protocol!;
50
+ const childProtocol = inboundMessage.message.descriptor.protocol;
51
51
  const parentProtocolUri = await resolveParentProtocolUri(
52
52
  tenant, childProtocol, declaredProtocolPath, messageStore, fetchProtocolDefinition, governingTimestamp
53
53
  );
@@ -174,7 +174,7 @@ export async function verifyTypeWithComposition(
174
174
  fetchProtocolDefinition: FetchProtocolDefinitionFn,
175
175
  governingTimestamp?: string,
176
176
  ): Promise<void> {
177
- const declaredProtocolPath = inboundMessage.descriptor.protocolPath!;
177
+ const declaredProtocolPath = inboundMessage.descriptor.protocolPath;
178
178
  const declaredTypeName = getTypeName(declaredProtocolPath);
179
179
 
180
180
  // Resolve which protocol types map to use.
@@ -231,7 +231,7 @@ export function verifyType(
231
231
  protocolTypes: ProtocolTypes,
232
232
  typeName?: string,
233
233
  ): void {
234
- const declaredTypeName = typeName ?? getTypeName(inboundMessage.descriptor.protocolPath!);
234
+ const declaredTypeName = typeName ?? getTypeName(inboundMessage.descriptor.protocolPath);
235
235
  const typeNames = Object.keys(protocolTypes);
236
236
 
237
237
  if (!typeNames.includes(declaredTypeName)) {
@@ -361,12 +361,12 @@ export async function verifyAsRoleRecordIfNeeded(
361
361
  );
362
362
  }
363
363
 
364
- const protocolPath = incomingRecordsWrite.message.descriptor.protocolPath!;
364
+ const protocolPath = incomingRecordsWrite.message.descriptor.protocolPath;
365
365
  const filter: Filter = {
366
366
  interface : DwnInterfaceName.Records,
367
367
  method : DwnMethodName.Write,
368
368
  isLatestBaseState : true,
369
- protocol : incomingRecordsWrite.message.descriptor.protocol!,
369
+ protocol : incomingRecordsWrite.message.descriptor.protocol,
370
370
  protocolPath,
371
371
  recipient,
372
372
  };
@@ -422,12 +422,12 @@ export async function verifyRecordLimit(
422
422
  const { max, strategy } = ruleSet.$recordLimit;
423
423
 
424
424
  // Build a filter to count existing records at the same protocol path and parent context.
425
- const protocolPath = incomingMessage.message.descriptor.protocolPath!;
425
+ const protocolPath = incomingMessage.message.descriptor.protocolPath;
426
426
  const filter: Filter = {
427
427
  interface : DwnInterfaceName.Records,
428
428
  method : DwnMethodName.Write,
429
429
  isLatestBaseState : true,
430
- protocol : incomingMessage.message.descriptor.protocol!,
430
+ protocol : incomingMessage.message.descriptor.protocol,
431
431
  protocolPath,
432
432
  };
433
433
 
@@ -445,7 +445,7 @@ export async function verifyRecordLimit(
445
445
  throw new DwnError(
446
446
  DwnErrorCode.ProtocolAuthorizationRecordLimitExceeded,
447
447
  `record limit of ${max} reached at protocol path '${protocolPath}'` +
448
- `${parentContextId !== '' ? ` under parent context '${parentContextId}'` : ''}` +
448
+ `${parentContextId === '' ? '' : ` under parent context '${parentContextId}'`}` +
449
449
  `: new records are rejected until existing records are deleted.`
450
450
  );
451
451
  }
@@ -61,7 +61,7 @@ export class ProtocolAuthorization {
61
61
  // fetch the protocol definition that was active at the governing timestamp
62
62
  const protocolDefinition = await ProtocolAuthorization.fetchProtocolDefinition(
63
63
  tenant,
64
- incomingMessage.message.descriptor.protocol!,
64
+ incomingMessage.message.descriptor.protocol,
65
65
  messageStore,
66
66
  governingTimestamp,
67
67
  coreProtocols,
@@ -85,7 +85,7 @@ export class ProtocolAuthorization {
85
85
 
86
86
  // get the rule set for the inbound message
87
87
  const ruleSet = ProtocolAuthorization.getRuleSet(
88
- incomingMessage.message.descriptor.protocolPath!,
88
+ incomingMessage.message.descriptor.protocolPath,
89
89
  protocolDefinition,
90
90
  );
91
91
 
@@ -143,7 +143,7 @@ export class ProtocolAuthorization {
143
143
  // fetch the protocol definition that was active at the governing timestamp
144
144
  const protocolDefinition = await ProtocolAuthorization.fetchProtocolDefinition(
145
145
  tenant,
146
- incomingMessage.message.descriptor.protocol!,
146
+ incomingMessage.message.descriptor.protocol,
147
147
  messageStore,
148
148
  governingTimestamp,
149
149
  coreProtocols,
@@ -151,7 +151,7 @@ export class ProtocolAuthorization {
151
151
 
152
152
  // get the rule set for the inbound message
153
153
  const ruleSet = ProtocolAuthorization.getRuleSet(
154
- incomingMessage.message.descriptor.protocolPath!,
154
+ incomingMessage.message.descriptor.protocolPath,
155
155
  protocolDefinition,
156
156
  );
157
157
 
@@ -161,8 +161,8 @@ export class ProtocolAuthorization {
161
161
  await verifyInvokedRole(
162
162
  tenant,
163
163
  incomingMessage,
164
- incomingMessage.message.descriptor.protocol!,
165
- incomingMessage.message.contextId!,
164
+ incomingMessage.message.descriptor.protocol,
165
+ incomingMessage.message.contextId,
166
166
  protocolDefinition,
167
167
  messageStore,
168
168
  boundFetchDefinition,
@@ -201,14 +201,14 @@ export class ProtocolAuthorization {
201
201
  const initialWrite = await fetchInitialWrite(
202
202
  tenant, newestRecordsWrite.message.recordId, messageStore
203
203
  );
204
- const governingTimestamp = initialWrite !== undefined
205
- ? initialWrite.descriptor.messageTimestamp
206
- : newestRecordsWrite.message.descriptor.messageTimestamp;
204
+ const governingTimestamp = initialWrite === undefined
205
+ ? newestRecordsWrite.message.descriptor.messageTimestamp
206
+ : initialWrite.descriptor.messageTimestamp;
207
207
 
208
208
  // fetch the protocol definition that was active when the record was created
209
209
  const protocolDefinition = await ProtocolAuthorization.fetchProtocolDefinition(
210
210
  tenant,
211
- newestRecordsWrite.message.descriptor.protocol!,
211
+ newestRecordsWrite.message.descriptor.protocol,
212
212
  messageStore,
213
213
  governingTimestamp,
214
214
  coreProtocols,
@@ -216,7 +216,7 @@ export class ProtocolAuthorization {
216
216
 
217
217
  // get the rule set for the inbound message
218
218
  const ruleSet = ProtocolAuthorization.getRuleSet(
219
- newestRecordsWrite.message.descriptor.protocolPath!,
219
+ newestRecordsWrite.message.descriptor.protocolPath,
220
220
  protocolDefinition,
221
221
  );
222
222
 
@@ -226,8 +226,8 @@ export class ProtocolAuthorization {
226
226
  await verifyInvokedRole(
227
227
  tenant,
228
228
  incomingMessage,
229
- newestRecordsWrite.message.descriptor.protocol!,
230
- newestRecordsWrite.message.contextId!,
229
+ newestRecordsWrite.message.descriptor.protocol,
230
+ newestRecordsWrite.message.contextId,
231
231
  protocolDefinition,
232
232
  messageStore,
233
233
  boundFetchDefinition,
@@ -312,14 +312,14 @@ export class ProtocolAuthorization {
312
312
  const initialWrite = await fetchInitialWrite(
313
313
  tenant, incomingMessage.message.descriptor.recordId, messageStore
314
314
  );
315
- const governingTimestamp = initialWrite !== undefined
316
- ? initialWrite.descriptor.messageTimestamp
317
- : recordsWrite.message.descriptor.messageTimestamp;
315
+ const governingTimestamp = initialWrite === undefined
316
+ ? recordsWrite.message.descriptor.messageTimestamp
317
+ : initialWrite.descriptor.messageTimestamp;
318
318
 
319
319
  // fetch the protocol definition that was active when the record was created
320
320
  const protocolDefinition = await ProtocolAuthorization.fetchProtocolDefinition(
321
321
  tenant,
322
- recordsWrite.message.descriptor.protocol!,
322
+ recordsWrite.message.descriptor.protocol,
323
323
  messageStore,
324
324
  governingTimestamp,
325
325
  coreProtocols,
@@ -327,7 +327,7 @@ export class ProtocolAuthorization {
327
327
 
328
328
  // get the rule set for the inbound message
329
329
  const ruleSet = ProtocolAuthorization.getRuleSet(
330
- recordsWrite.message.descriptor.protocolPath!,
330
+ recordsWrite.message.descriptor.protocolPath,
331
331
  protocolDefinition,
332
332
  );
333
333
 
@@ -337,8 +337,8 @@ export class ProtocolAuthorization {
337
337
  await verifyInvokedRole(
338
338
  tenant,
339
339
  incomingMessage,
340
- recordsWrite.message.descriptor.protocol!,
341
- recordsWrite.message.contextId!,
340
+ recordsWrite.message.descriptor.protocol,
341
+ recordsWrite.message.contextId,
342
342
  protocolDefinition,
343
343
  messageStore,
344
344
  boundFetchDefinition,
@@ -389,12 +389,12 @@ export class ProtocolAuthorization {
389
389
  protocol : protocolUri,
390
390
  };
391
391
 
392
- if (messageTimestamp !== undefined) {
393
- // temporal lookup: find the protocol definition active at the given timestamp
394
- query.messageTimestamp = { lte: messageTimestamp };
395
- } else {
392
+ if (messageTimestamp === undefined) {
396
393
  // default: return only the latest protocol definition
397
394
  query.isLatestBaseState = true;
395
+ } else {
396
+ // temporal lookup: find the protocol definition active at the given timestamp
397
+ query.messageTimestamp = { lte: messageTimestamp };
398
398
  }
399
399
 
400
400
  const { messages: protocols } = await messageStore.query(
@@ -153,7 +153,7 @@ export class RecordsGrantAuthorization {
153
153
 
154
154
  // If grant specifies a contextId, check that record falls under that contextId
155
155
  if (grantScope.contextId !== undefined) {
156
- if (recordsWriteMessage.contextId === undefined || !recordsWriteMessage.contextId.startsWith(grantScope.contextId)) {
156
+ if (!recordsWriteMessage.contextId?.startsWith(grantScope.contextId)) {
157
157
  throw new DwnError(
158
158
  DwnErrorCode.RecordsGrantAuthorizationScopeContextIdMismatch,
159
159
  `Grant scope specifies different contextId than what appears in the record`
@@ -20,9 +20,9 @@ export class ResumableTaskManager {
20
20
  public static readonly timeoutExtensionFrequencyInSeconds = 30;
21
21
 
22
22
  private resumableTaskBatchSize = 100;
23
- private resumableTaskHandlers: { [key:string]: (taskData: any) => Promise<void> };
23
+ private readonly resumableTaskHandlers: { [key:string]: (taskData: any) => Promise<void> };
24
24
 
25
- public constructor(private resumableTaskStore: ResumableTaskStore, storageController: StorageController) {
25
+ public constructor(private readonly resumableTaskStore: ResumableTaskStore, storageController: StorageController) {
26
26
  // assign resumable task handlers
27
27
  this.resumableTaskHandlers = {
28
28
  // NOTE: The arrow function is IMPORTANT here, else the `this` context will be lost within the invoked method.
package/src/dwn.ts CHANGED
@@ -34,20 +34,20 @@ import { DidDht, DidJwk, DidKey, DidResolverCacheMemory, DidWeb, UniversalResolv
34
34
  import { DwnInterfaceName, DwnMethodName } from './enums/dwn-interface-method.js';
35
35
 
36
36
  export class Dwn {
37
- private methodHandlers: { [key:string]: MethodHandler };
38
- private didResolver: DidResolver;
39
- private messageStore: MessageStore;
40
- private dataStore: DataStore;
41
- private resumableTaskStore: ResumableTaskStore;
42
- private stateIndex: StateIndex;
43
- private tenantGate: TenantGate;
44
- private eventLog?: EventLog;
45
- private storageController: StorageController;
46
- private resumableTaskManager: ResumableTaskManager;
47
- private _coreProtocols: CoreProtocolRegistry;
37
+ private readonly methodHandlers: { [key:string]: MethodHandler };
38
+ private readonly didResolver: DidResolver;
39
+ private readonly messageStore: MessageStore;
40
+ private readonly dataStore: DataStore;
41
+ private readonly resumableTaskStore: ResumableTaskStore;
42
+ private readonly stateIndex: StateIndex;
43
+ private readonly tenantGate: TenantGate;
44
+ private readonly eventLog?: EventLog;
45
+ private readonly storageController: StorageController;
46
+ private readonly resumableTaskManager: ResumableTaskManager;
47
+ private readonly _coreProtocols: CoreProtocolRegistry;
48
48
 
49
49
  /** Whether the DWN owns the resolver's lifecycle (i.e., created it via defaults). */
50
- private ownsResolver: boolean;
50
+ private readonly ownsResolver: boolean;
51
51
 
52
52
  private constructor(config: DwnConfig) {
53
53
  this.didResolver = config.didResolver!;
@@ -204,7 +204,7 @@ export class Dwn {
204
204
  const handlerKey = rawMessage.descriptor.interface + rawMessage.descriptor.method;
205
205
  const methodHandlerReply = await this.methodHandlers[handlerKey].handle({
206
206
  tenant,
207
- message: rawMessage as GenericMessage,
207
+ message: rawMessage,
208
208
  dataStream,
209
209
  subscriptionHandler
210
210
  });
@@ -65,21 +65,21 @@ export interface EventEmitterEventLogConfig {
65
65
  * For multi-node deployments, use a distributed implementation (NATS, Redis, etc.).
66
66
  */
67
67
  export class EventEmitterEventLog implements EventLog {
68
- private emitter = mitt<EmitterEvents>();
68
+ private readonly emitter = mitt<EmitterEvents>();
69
69
  private isOpen: boolean = false;
70
- private errorHandler: (error: any) => void = (error): void => { console.error('event log error', error); };
71
- private maxEventsPerTenant: number;
70
+ private readonly errorHandler: (error: any) => void = (error): void => { console.error('event log error', error); };
71
+ private readonly maxEventsPerTenant: number;
72
72
 
73
73
  /**
74
74
  * Per-tenant ordered event storage.
75
75
  * Key: tenant DID → Map of seq → StoredEntry.
76
76
  */
77
- private tenantLogs: Map<string, Map<number, StoredEntry>> = new Map();
77
+ private readonly tenantLogs: Map<string, Map<number, StoredEntry>> = new Map();
78
78
 
79
79
  /**
80
80
  * Per-tenant monotonic sequence counter.
81
81
  */
82
- private tenantSeqs: Map<string, number> = new Map();
82
+ private readonly tenantSeqs: Map<string, number> = new Map();
83
83
 
84
84
  /**
85
85
  * Epoch for this EventLog instance. Generated once at construction as a
@@ -131,9 +131,7 @@ export class EventEmitterEventLog implements EventLog {
131
131
  let reason: ProgressGapReason;
132
132
  if (cursor.streamId !== expectedStreamId) {
133
133
  reason = 'stream_mismatch';
134
- } else if (cursor.epoch !== this.epoch) {
135
- reason = 'epoch_mismatch';
136
- } else {
134
+ } else if (cursor.epoch === this.epoch) {
137
135
  // Check if position is still within replay bounds.
138
136
  const log = this.tenantLogs.get(tenant);
139
137
  if (log !== undefined && log.size > 0) {
@@ -148,6 +146,8 @@ export class EventEmitterEventLog implements EventLog {
148
146
  } else {
149
147
  return; // No events for tenant — cursor is vacuously valid (will get empty catch-up + EOSE).
150
148
  }
149
+ } else {
150
+ reason = 'epoch_mismatch';
151
151
  }
152
152
 
153
153
  // Build gap metadata.
@@ -226,7 +226,7 @@ export class EventEmitterEventLog implements EventLog {
226
226
  await this.validateCursor(tenant, cursor);
227
227
  }
228
228
 
229
- const cursorSeq = cursor !== undefined ? EventEmitterEventLog.parsePosition(cursor.position) : undefined;
229
+ const cursorSeq = cursor === undefined ? undefined : EventEmitterEventLog.parsePosition(cursor.position);
230
230
  const log = this.tenantLogs.get(tenant);
231
231
 
232
232
  if (log === undefined || log.size === 0) {
@@ -319,12 +319,12 @@ export class EventEmitterEventLog implements EventLog {
319
319
  if (filters !== undefined && filters.length > 0) {
320
320
  if (!FilterUtility.matchAnyFilter(payload.indexes, filters)) { return; }
321
321
  }
322
- if (!catchUpComplete) {
323
- pendingLiveEvents.push({ event: payload.event, seq: payload.seq, messageCid: payload.messageCid });
324
- } else {
322
+ if (catchUpComplete) {
325
323
  void tokenFromPayload(payload).then((token) => {
326
324
  listener({ type: 'event', cursor: token, event: payload.event });
327
325
  });
326
+ } else {
327
+ pendingLiveEvents.push({ event: payload.event, seq: payload.seq, messageCid: payload.messageCid });
328
328
  }
329
329
  };
330
330
 
@@ -334,9 +334,9 @@ export class EventEmitterEventLog implements EventLog {
334
334
  const readResult = await this.read(tenant, { cursor, filters });
335
335
  // The read cursor is the token of the last read event, or the input cursor if nothing new.
336
336
  const eoseCursor = readResult.cursor ?? cursor;
337
- const lastCatchUpSeq = readResult.cursor !== undefined
338
- ? EventEmitterEventLog.parsePosition(readResult.cursor.position)
339
- : cursorSeq;
337
+ const lastCatchUpSeq = readResult.cursor === undefined
338
+ ? cursorSeq
339
+ : EventEmitterEventLog.parsePosition(readResult.cursor.position);
340
340
 
341
341
  // Use the messageCid captured by read() during its synchronous iteration.
342
342
  // This eliminates re-lookup races: read() populates entry.messageCid before
@@ -18,7 +18,7 @@ type HandleArgs = { tenant: string, message: MessagesReadMessage };
18
18
 
19
19
  export class MessagesReadHandler implements MethodHandler {
20
20
 
21
- constructor(private deps: HandlerDependencies) {}
21
+ constructor(private readonly deps: HandlerDependencies) {}
22
22
 
23
23
  public async handle({ tenant, message }: HandleArgs): Promise<MessagesReadReply> {
24
24
  let messagesRead: MessagesRead;
@@ -52,16 +52,16 @@ export class MessagesReadHandler implements MethodHandler {
52
52
  const recordsWrite = entry.message as RecordsQueryReplyEntry;
53
53
  // RecordsWrite specific handling, if MessageStore has embedded `encodedData` return it with the entry.
54
54
  // we store `encodedData` along with the message if the data is below a certain threshold.
55
- if (recordsWrite.encodedData !== undefined) {
56
- const dataBytes = Encoder.base64UrlToBytes(recordsWrite.encodedData);
57
- entry.data = DataStream.fromBytes(dataBytes);
58
- delete recordsWrite.encodedData;
59
- } else {
60
- // otherwise check the data store for the associated data
55
+ if (recordsWrite.encodedData === undefined) {
56
+ // check the data store for the associated data
61
57
  const result = await this.deps.dataStore!.get(tenant, recordsWrite.recordId, recordsWrite.descriptor.dataCid);
62
58
  if (result?.dataStream !== undefined) {
63
59
  entry.data = result.dataStream;
64
60
  }
61
+ } else {
62
+ const dataBytes = Encoder.base64UrlToBytes(recordsWrite.encodedData);
63
+ entry.data = DataStream.fromBytes(dataBytes);
64
+ delete recordsWrite.encodedData;
65
65
  }
66
66
  }
67
67
 
@@ -14,7 +14,7 @@ import { DwnError, DwnErrorCode } from '../core/dwn-error.js';
14
14
 
15
15
  export class MessagesSubscribeHandler implements MethodHandler {
16
16
 
17
- constructor(private deps: HandlerDependencies) {}
17
+ constructor(private readonly deps: HandlerDependencies) {}
18
18
 
19
19
  public async handle({
20
20
  tenant,
@@ -65,7 +65,7 @@ export class MessagesSubscribeHandler implements MethodHandler {
65
65
  const gapInfo = (error as any).gapInfo as ProgressGapInfo | undefined;
66
66
  return {
67
67
  status : { code: 410, detail: 'Progress token gap' },
68
- error : gapInfo !== undefined ? { code: 'ProgressGap' as const, ...gapInfo } : undefined,
68
+ error : gapInfo === undefined ? undefined : { code: 'ProgressGap' as const, ...gapInfo },
69
69
  };
70
70
  }
71
71
  return messageReplyFromError(error, 500);
@@ -25,7 +25,7 @@ const DEFAULT_MAX_INLINE_DATA_SIZE = DwnConstant.maxDataSizeAllowedToBeEncoded;
25
25
 
26
26
  export class MessagesSyncHandler implements MethodHandler {
27
27
 
28
- constructor(private deps: HandlerDependencies) { }
28
+ constructor(private readonly deps: HandlerDependencies) { }
29
29
 
30
30
  public async handle({
31
31
  tenant,
@@ -51,9 +51,9 @@ export class MessagesSyncHandler implements MethodHandler {
51
51
  try {
52
52
  switch (action) {
53
53
  case 'root': {
54
- const rootHash = protocol !== undefined
55
- ? await this.deps.stateIndex!.getProtocolRoot(tenant, protocol)
56
- : await this.deps.stateIndex!.getRoot(tenant);
54
+ const rootHash = protocol === undefined
55
+ ? await this.deps.stateIndex!.getRoot(tenant)
56
+ : await this.deps.stateIndex!.getProtocolRoot(tenant, protocol);
57
57
  return {
58
58
  status : { code: 200, detail: 'OK' },
59
59
  root : hashToHex(rootHash),
@@ -62,9 +62,9 @@ export class MessagesSyncHandler implements MethodHandler {
62
62
 
63
63
  case 'subtree': {
64
64
  const bitPath = MessagesSyncHandler.parseBitPrefix(prefix!);
65
- const hash = protocol !== undefined
66
- ? await this.deps.stateIndex!.getProtocolSubtreeHash(tenant, protocol, bitPath)
67
- : await this.deps.stateIndex!.getSubtreeHash(tenant, bitPath);
65
+ const hash = protocol === undefined
66
+ ? await this.deps.stateIndex!.getSubtreeHash(tenant, bitPath)
67
+ : await this.deps.stateIndex!.getProtocolSubtreeHash(tenant, protocol, bitPath);
68
68
  return {
69
69
  status : { code: 200, detail: 'OK' },
70
70
  hash : hashToHex(hash),
@@ -73,9 +73,9 @@ export class MessagesSyncHandler implements MethodHandler {
73
73
 
74
74
  case 'leaves': {
75
75
  const bitPath = MessagesSyncHandler.parseBitPrefix(prefix!);
76
- const leaves = protocol !== undefined
77
- ? await this.deps.stateIndex!.getProtocolLeaves(tenant, protocol, bitPath)
78
- : await this.deps.stateIndex!.getLeaves(tenant, bitPath);
76
+ const leaves = protocol === undefined
77
+ ? await this.deps.stateIndex!.getLeaves(tenant, bitPath)
78
+ : await this.deps.stateIndex!.getProtocolLeaves(tenant, protocol, bitPath);
79
79
  return {
80
80
  status : { code: 200, detail: 'OK' },
81
81
  entries : leaves,
@@ -165,18 +165,18 @@ export class MessagesSyncHandler implements MethodHandler {
165
165
  if (clientHash === undefined) {
166
166
  // Server has entries the client doesn't — enumerate server leaves.
167
167
  const bitPath = MessagesSyncHandler.parseBitPrefix(pfx);
168
- const leaves = protocol !== undefined
169
- ? await stateIndex.getProtocolLeaves(tenant, protocol, bitPath)
170
- : await stateIndex.getLeaves(tenant, bitPath);
168
+ const leaves = protocol === undefined
169
+ ? await stateIndex.getLeaves(tenant, bitPath)
170
+ : await stateIndex.getProtocolLeaves(tenant, protocol, bitPath);
171
171
  onlyRemoteCids.push(...leaves);
172
172
  continue;
173
173
  }
174
174
 
175
175
  // Both sides have entries but they differ — enumerate both and set-diff.
176
176
  const bitPath = MessagesSyncHandler.parseBitPrefix(pfx);
177
- const serverLeaves = protocol !== undefined
178
- ? await stateIndex.getProtocolLeaves(tenant, protocol, bitPath)
179
- : await stateIndex.getLeaves(tenant, bitPath);
177
+ const serverLeaves = protocol === undefined
178
+ ? await stateIndex.getLeaves(tenant, bitPath)
179
+ : await stateIndex.getProtocolLeaves(tenant, protocol, bitPath);
180
180
 
181
181
  // We don't have the client's leaves, so we report all server leaves
182
182
  // as onlyRemote (the client will de-duplicate locally). We also
@@ -210,9 +210,9 @@ export class MessagesSyncHandler implements MethodHandler {
210
210
 
211
211
  const walk = async (prefix: string, currentDepth: number): Promise<void> => {
212
212
  const bitPath = MessagesSyncHandler.parseBitPrefix(prefix);
213
- const hash = protocol !== undefined
214
- ? await stateIndex.getProtocolSubtreeHash(tenant, protocol, bitPath)
215
- : await stateIndex.getSubtreeHash(tenant, bitPath);
213
+ const hash = protocol === undefined
214
+ ? await stateIndex.getSubtreeHash(tenant, bitPath)
215
+ : await stateIndex.getProtocolSubtreeHash(tenant, protocol, bitPath);
216
216
  const hexHash = hashToHex(hash);
217
217
 
218
218
  if (hexHash === defaultHashHex) {
@@ -15,7 +15,7 @@ import { getRuleSetAtPath, parseCrossProtocolRef } from '../utils/protocols.js';
15
15
 
16
16
  export class ProtocolsConfigureHandler implements MethodHandler {
17
17
 
18
- constructor(private deps: HandlerDependencies) { }
18
+ constructor(private readonly deps: HandlerDependencies) { }
19
19
 
20
20
  public async handle({
21
21
  tenant,
@@ -298,7 +298,7 @@ export class ProtocolsConfigureHandler implements MethodHandler {
298
298
 
299
299
  // Check that the role path exists and is marked $role: true in the referenced protocol
300
300
  const roleRuleSet = getRuleSetAtPath(parsed.protocolPath, refDefinition.structure);
301
- if (roleRuleSet === undefined || !roleRuleSet.$role) {
301
+ if (!roleRuleSet?.$role) {
302
302
  throw new DwnError(
303
303
  DwnErrorCode.ProtocolsConfigureInvalidCrossProtocolRole,
304
304
  `cross-protocol role '${actionRule.role}' at protocol path '${childProtocolPath}' ` +
@@ -11,7 +11,7 @@ import { DwnInterfaceName, DwnMethodName } from '../enums/dwn-interface-method.j
11
11
 
12
12
  export class ProtocolsQueryHandler implements MethodHandler {
13
13
 
14
- constructor(private deps: HandlerDependencies) { }
14
+ constructor(private readonly deps: HandlerDependencies) { }
15
15
 
16
16
  public async handle({
17
17
  tenant,
@@ -14,7 +14,7 @@ import { DwnInterfaceName, DwnMethodName } from '../enums/dwn-interface-method.j
14
14
 
15
15
  export class RecordsCountHandler implements MethodHandler {
16
16
 
17
- constructor(private deps: HandlerDependencies) { }
17
+ constructor(private readonly deps: HandlerDependencies) { }
18
18
 
19
19
  public async handle({
20
20
  tenant,
@@ -18,7 +18,7 @@ import { ResumableTaskName } from '../core/resumable-task-manager.js';
18
18
 
19
19
  export class RecordsDeleteHandler implements MethodHandler {
20
20
 
21
- constructor(private deps: HandlerDependencies) { }
21
+ constructor(private readonly deps: HandlerDependencies) { }
22
22
 
23
23
  public async handle({
24
24
  tenant,
@@ -18,7 +18,7 @@ import { DwnInterfaceName, DwnMethodName } from '../enums/dwn-interface-method.j
18
18
 
19
19
  export class RecordsQueryHandler implements MethodHandler {
20
20
 
21
- constructor(private deps: HandlerDependencies) { }
21
+ constructor(private readonly deps: HandlerDependencies) { }
22
22
 
23
23
  public async handle({
24
24
  tenant,
@@ -20,7 +20,7 @@ import { DwnInterfaceName, DwnMethodName } from '../enums/dwn-interface-method.j
20
20
 
21
21
  export class RecordsReadHandler implements MethodHandler {
22
22
 
23
- constructor(private deps: HandlerDependencies) { }
23
+ constructor(private readonly deps: HandlerDependencies) { }
24
24
 
25
25
  public async handle({
26
26
  tenant,
@@ -115,11 +115,7 @@ export class RecordsReadHandler implements MethodHandler {
115
115
  }
116
116
 
117
117
  let data;
118
- if (matchedRecordsWrite.encodedData !== undefined) {
119
- const dataBytes = Encoder.base64UrlToBytes(matchedRecordsWrite.encodedData);
120
- data = DataStream.fromBytes(dataBytes);
121
- delete matchedRecordsWrite.encodedData;
122
- } else {
118
+ if (matchedRecordsWrite.encodedData === undefined) {
123
119
  const result = await this.deps.dataStore!.get(tenant, matchedRecordsWrite.recordId, matchedRecordsWrite.descriptor.dataCid);
124
120
  if (result?.dataStream === undefined) {
125
121
  // The message envelope exists but the record data is unavailable (e.g., evicted
@@ -131,6 +127,10 @@ export class RecordsReadHandler implements MethodHandler {
131
127
  };
132
128
  }
133
129
  data = result.dataStream;
130
+ } else {
131
+ const dataBytes = Encoder.base64UrlToBytes(matchedRecordsWrite.encodedData);
132
+ data = DataStream.fromBytes(dataBytes);
133
+ delete matchedRecordsWrite.encodedData;
134
134
  }
135
135
 
136
136
  const recordsReadReply: RecordsReadReply = {