@enbox/dwn-sdk-js 0.3.6 → 0.3.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 (234) hide show
  1. package/dist/browser.mjs +8 -8
  2. package/dist/browser.mjs.map +4 -4
  3. package/dist/esm/generated/precompiled-validators.js +2591 -1435
  4. package/dist/esm/generated/precompiled-validators.js.map +1 -1
  5. package/dist/esm/src/core/constants.js +20 -0
  6. package/dist/esm/src/core/constants.js.map +1 -1
  7. package/dist/esm/src/core/dwn-error.js +24 -1
  8. package/dist/esm/src/core/dwn-error.js.map +1 -1
  9. package/dist/esm/src/core/grant-authorization.js +4 -4
  10. package/dist/esm/src/core/grant-authorization.js.map +1 -1
  11. package/dist/esm/src/core/message.js +89 -4
  12. package/dist/esm/src/core/message.js.map +1 -1
  13. package/dist/esm/src/core/messages-grant-authorization.js +147 -55
  14. package/dist/esm/src/core/messages-grant-authorization.js.map +1 -1
  15. package/dist/esm/src/core/protocol-authorization.js +76 -0
  16. package/dist/esm/src/core/protocol-authorization.js.map +1 -1
  17. package/dist/esm/src/core/records-grant-authorization.js +40 -15
  18. package/dist/esm/src/core/records-grant-authorization.js.map +1 -1
  19. package/dist/esm/src/handlers/messages-read.js +5 -5
  20. package/dist/esm/src/handlers/messages-read.js.map +1 -1
  21. package/dist/esm/src/handlers/messages-subscribe.js +109 -7
  22. package/dist/esm/src/handlers/messages-subscribe.js.map +1 -1
  23. package/dist/esm/src/handlers/messages-sync.js +341 -96
  24. package/dist/esm/src/handlers/messages-sync.js.map +1 -1
  25. package/dist/esm/src/handlers/protocols-configure.js +81 -2
  26. package/dist/esm/src/handlers/protocols-configure.js.map +1 -1
  27. package/dist/esm/src/handlers/records-count.js +30 -0
  28. package/dist/esm/src/handlers/records-count.js.map +1 -1
  29. package/dist/esm/src/handlers/records-delete.js +3 -2
  30. package/dist/esm/src/handlers/records-delete.js.map +1 -1
  31. package/dist/esm/src/handlers/records-query.js +30 -0
  32. package/dist/esm/src/handlers/records-query.js.map +1 -1
  33. package/dist/esm/src/handlers/records-read.js +3 -2
  34. package/dist/esm/src/handlers/records-read.js.map +1 -1
  35. package/dist/esm/src/handlers/records-subscribe.js +31 -0
  36. package/dist/esm/src/handlers/records-subscribe.js.map +1 -1
  37. package/dist/esm/src/handlers/records-write.js +36 -11
  38. package/dist/esm/src/handlers/records-write.js.map +1 -1
  39. package/dist/esm/src/index.js +2 -0
  40. package/dist/esm/src/index.js.map +1 -1
  41. package/dist/esm/src/interfaces/messages-read.js +6 -3
  42. package/dist/esm/src/interfaces/messages-read.js.map +1 -1
  43. package/dist/esm/src/interfaces/messages-subscribe.js +6 -3
  44. package/dist/esm/src/interfaces/messages-subscribe.js.map +1 -1
  45. package/dist/esm/src/interfaces/messages-sync.js +17 -3
  46. package/dist/esm/src/interfaces/messages-sync.js.map +1 -1
  47. package/dist/esm/src/interfaces/protocols-configure.js +5 -2
  48. package/dist/esm/src/interfaces/protocols-configure.js.map +1 -1
  49. package/dist/esm/src/interfaces/protocols-query.js +8 -4
  50. package/dist/esm/src/interfaces/protocols-query.js.map +1 -1
  51. package/dist/esm/src/interfaces/records-count.js +5 -0
  52. package/dist/esm/src/interfaces/records-count.js.map +1 -1
  53. package/dist/esm/src/interfaces/records-delete.js +6 -2
  54. package/dist/esm/src/interfaces/records-delete.js.map +1 -1
  55. package/dist/esm/src/interfaces/records-query.js +5 -0
  56. package/dist/esm/src/interfaces/records-query.js.map +1 -1
  57. package/dist/esm/src/interfaces/records-read.js +6 -3
  58. package/dist/esm/src/interfaces/records-read.js.map +1 -1
  59. package/dist/esm/src/interfaces/records-subscribe.js +5 -0
  60. package/dist/esm/src/interfaces/records-subscribe.js.map +1 -1
  61. package/dist/esm/src/interfaces/records-write.js +6 -3
  62. package/dist/esm/src/interfaces/records-write.js.map +1 -1
  63. package/dist/esm/src/protocols/permissions.js +28 -7
  64. package/dist/esm/src/protocols/permissions.js.map +1 -1
  65. package/dist/esm/src/sync/records-projection.js +228 -0
  66. package/dist/esm/src/sync/records-projection.js.map +1 -0
  67. package/dist/esm/src/types/message-types.js.map +1 -1
  68. package/dist/esm/src/types/permission-types.js.map +1 -1
  69. package/dist/esm/src/utils/permission-scope.js +37 -0
  70. package/dist/esm/src/utils/permission-scope.js.map +1 -0
  71. package/dist/esm/tests/core/grant-authorization.spec.js +26 -3
  72. package/dist/esm/tests/core/grant-authorization.spec.js.map +1 -1
  73. package/dist/esm/tests/core/records-grant-authorization.spec.js +117 -0
  74. package/dist/esm/tests/core/records-grant-authorization.spec.js.map +1 -0
  75. package/dist/esm/tests/features/permissions.spec.js +126 -0
  76. package/dist/esm/tests/features/permissions.spec.js.map +1 -1
  77. package/dist/esm/tests/handlers/messages-read.spec.js +345 -12
  78. package/dist/esm/tests/handlers/messages-read.spec.js.map +1 -1
  79. package/dist/esm/tests/handlers/messages-subscribe.spec.js +326 -9
  80. package/dist/esm/tests/handlers/messages-subscribe.spec.js.map +1 -1
  81. package/dist/esm/tests/handlers/messages-sync.spec.js +1053 -7
  82. package/dist/esm/tests/handlers/messages-sync.spec.js.map +1 -1
  83. package/dist/esm/tests/handlers/protocols-configure.spec.js +361 -0
  84. package/dist/esm/tests/handlers/protocols-configure.spec.js.map +1 -1
  85. package/dist/esm/tests/handlers/records-count.spec.js +75 -2
  86. package/dist/esm/tests/handlers/records-count.spec.js.map +1 -1
  87. package/dist/esm/tests/handlers/records-query.spec.js +73 -0
  88. package/dist/esm/tests/handlers/records-query.spec.js.map +1 -1
  89. package/dist/esm/tests/handlers/records-subscribe.spec.js +75 -1
  90. package/dist/esm/tests/handlers/records-subscribe.spec.js.map +1 -1
  91. package/dist/esm/tests/handlers/records-write.spec.js +15 -0
  92. package/dist/esm/tests/handlers/records-write.spec.js.map +1 -1
  93. package/dist/esm/tests/interfaces/messages-get.spec.js +107 -5
  94. package/dist/esm/tests/interfaces/messages-get.spec.js.map +1 -1
  95. package/dist/esm/tests/interfaces/protocols-configure.spec.js +13 -0
  96. package/dist/esm/tests/interfaces/protocols-configure.spec.js.map +1 -1
  97. package/dist/esm/tests/interfaces/records-delete.spec.js +12 -0
  98. package/dist/esm/tests/interfaces/records-delete.spec.js.map +1 -1
  99. package/dist/esm/tests/interfaces/records-query.spec.js +10 -0
  100. package/dist/esm/tests/interfaces/records-query.spec.js.map +1 -1
  101. package/dist/esm/tests/interfaces/records-subscribe.spec.js +10 -0
  102. package/dist/esm/tests/interfaces/records-subscribe.spec.js.map +1 -1
  103. package/dist/esm/tests/interfaces/records-write.spec.js +33 -0
  104. package/dist/esm/tests/interfaces/records-write.spec.js.map +1 -1
  105. package/dist/esm/tests/sync/records-projection.spec.js +245 -0
  106. package/dist/esm/tests/sync/records-projection.spec.js.map +1 -0
  107. package/dist/esm/tests/test-suite.js +2 -0
  108. package/dist/esm/tests/test-suite.js.map +1 -1
  109. package/dist/esm/tests/utils/permission-scope.spec.js +66 -0
  110. package/dist/esm/tests/utils/permission-scope.spec.js.map +1 -0
  111. package/dist/esm/tests/utils/test-data-generator.js +5 -2
  112. package/dist/esm/tests/utils/test-data-generator.js.map +1 -1
  113. package/dist/types/generated/precompiled-validators.d.ts.map +1 -1
  114. package/dist/types/src/core/constants.d.ts +13 -0
  115. package/dist/types/src/core/constants.d.ts.map +1 -1
  116. package/dist/types/src/core/dwn-error.d.ts +24 -1
  117. package/dist/types/src/core/dwn-error.d.ts.map +1 -1
  118. package/dist/types/src/core/grant-authorization.d.ts +1 -2
  119. package/dist/types/src/core/grant-authorization.d.ts.map +1 -1
  120. package/dist/types/src/core/message.d.ts +41 -1
  121. package/dist/types/src/core/message.d.ts.map +1 -1
  122. package/dist/types/src/core/messages-grant-authorization.d.ts +36 -4
  123. package/dist/types/src/core/messages-grant-authorization.d.ts.map +1 -1
  124. package/dist/types/src/core/protocol-authorization.d.ts +12 -0
  125. package/dist/types/src/core/protocol-authorization.d.ts.map +1 -1
  126. package/dist/types/src/core/records-grant-authorization.d.ts +6 -0
  127. package/dist/types/src/core/records-grant-authorization.d.ts.map +1 -1
  128. package/dist/types/src/handlers/messages-read.d.ts.map +1 -1
  129. package/dist/types/src/handlers/messages-subscribe.d.ts +2 -1
  130. package/dist/types/src/handlers/messages-subscribe.d.ts.map +1 -1
  131. package/dist/types/src/handlers/messages-sync.d.ts +31 -0
  132. package/dist/types/src/handlers/messages-sync.d.ts.map +1 -1
  133. package/dist/types/src/handlers/protocols-configure.d.ts +3 -0
  134. package/dist/types/src/handlers/protocols-configure.d.ts.map +1 -1
  135. package/dist/types/src/handlers/records-count.d.ts +4 -0
  136. package/dist/types/src/handlers/records-count.d.ts.map +1 -1
  137. package/dist/types/src/handlers/records-delete.d.ts.map +1 -1
  138. package/dist/types/src/handlers/records-query.d.ts +4 -0
  139. package/dist/types/src/handlers/records-query.d.ts.map +1 -1
  140. package/dist/types/src/handlers/records-read.d.ts.map +1 -1
  141. package/dist/types/src/handlers/records-subscribe.d.ts.map +1 -1
  142. package/dist/types/src/handlers/records-write.d.ts +1 -0
  143. package/dist/types/src/handlers/records-write.d.ts.map +1 -1
  144. package/dist/types/src/index.d.ts +6 -2
  145. package/dist/types/src/index.d.ts.map +1 -1
  146. package/dist/types/src/interfaces/messages-read.d.ts +1 -1
  147. package/dist/types/src/interfaces/messages-read.d.ts.map +1 -1
  148. package/dist/types/src/interfaces/messages-subscribe.d.ts +1 -1
  149. package/dist/types/src/interfaces/messages-subscribe.d.ts.map +1 -1
  150. package/dist/types/src/interfaces/messages-sync.d.ts +4 -1
  151. package/dist/types/src/interfaces/messages-sync.d.ts.map +1 -1
  152. package/dist/types/src/interfaces/protocols-configure.d.ts.map +1 -1
  153. package/dist/types/src/interfaces/protocols-query.d.ts.map +1 -1
  154. package/dist/types/src/interfaces/records-count.d.ts +1 -0
  155. package/dist/types/src/interfaces/records-count.d.ts.map +1 -1
  156. package/dist/types/src/interfaces/records-delete.d.ts.map +1 -1
  157. package/dist/types/src/interfaces/records-query.d.ts +1 -0
  158. package/dist/types/src/interfaces/records-query.d.ts.map +1 -1
  159. package/dist/types/src/interfaces/records-read.d.ts.map +1 -1
  160. package/dist/types/src/interfaces/records-subscribe.d.ts +1 -0
  161. package/dist/types/src/interfaces/records-subscribe.d.ts.map +1 -1
  162. package/dist/types/src/interfaces/records-write.d.ts.map +1 -1
  163. package/dist/types/src/protocols/permissions.d.ts +2 -0
  164. package/dist/types/src/protocols/permissions.d.ts.map +1 -1
  165. package/dist/types/src/sync/records-projection.d.ts +98 -0
  166. package/dist/types/src/sync/records-projection.d.ts.map +1 -0
  167. package/dist/types/src/types/message-types.d.ts +1 -0
  168. package/dist/types/src/types/message-types.d.ts.map +1 -1
  169. package/dist/types/src/types/messages-types.d.ts +21 -3
  170. package/dist/types/src/types/messages-types.d.ts.map +1 -1
  171. package/dist/types/src/types/permission-types.d.ts +4 -0
  172. package/dist/types/src/types/permission-types.d.ts.map +1 -1
  173. package/dist/types/src/types/records-types.d.ts +4 -0
  174. package/dist/types/src/types/records-types.d.ts.map +1 -1
  175. package/dist/types/src/types/subscriptions.d.ts +18 -3
  176. package/dist/types/src/types/subscriptions.d.ts.map +1 -1
  177. package/dist/types/src/utils/permission-scope.d.ts +29 -0
  178. package/dist/types/src/utils/permission-scope.d.ts.map +1 -0
  179. package/dist/types/tests/core/records-grant-authorization.spec.d.ts +2 -0
  180. package/dist/types/tests/core/records-grant-authorization.spec.d.ts.map +1 -0
  181. package/dist/types/tests/features/permissions.spec.d.ts.map +1 -1
  182. package/dist/types/tests/handlers/messages-read.spec.d.ts.map +1 -1
  183. package/dist/types/tests/handlers/messages-subscribe.spec.d.ts.map +1 -1
  184. package/dist/types/tests/handlers/messages-sync.spec.d.ts.map +1 -1
  185. package/dist/types/tests/handlers/protocols-configure.spec.d.ts.map +1 -1
  186. package/dist/types/tests/handlers/records-count.spec.d.ts.map +1 -1
  187. package/dist/types/tests/handlers/records-query.spec.d.ts.map +1 -1
  188. package/dist/types/tests/handlers/records-subscribe.spec.d.ts.map +1 -1
  189. package/dist/types/tests/handlers/records-write.spec.d.ts.map +1 -1
  190. package/dist/types/tests/sync/records-projection.spec.d.ts +2 -0
  191. package/dist/types/tests/sync/records-projection.spec.d.ts.map +1 -0
  192. package/dist/types/tests/test-suite.d.ts.map +1 -1
  193. package/dist/types/tests/utils/permission-scope.spec.d.ts +2 -0
  194. package/dist/types/tests/utils/permission-scope.spec.d.ts.map +1 -0
  195. package/dist/types/tests/utils/test-data-generator.d.ts +5 -2
  196. package/dist/types/tests/utils/test-data-generator.d.ts.map +1 -1
  197. package/package.json +1 -1
  198. package/src/core/constants.ts +24 -0
  199. package/src/core/dwn-error.ts +24 -1
  200. package/src/core/grant-authorization.ts +7 -5
  201. package/src/core/message.ts +153 -6
  202. package/src/core/messages-grant-authorization.ts +282 -70
  203. package/src/core/protocol-authorization.ts +130 -0
  204. package/src/core/records-grant-authorization.ts +64 -21
  205. package/src/handlers/messages-read.ts +7 -5
  206. package/src/handlers/messages-subscribe.ts +149 -9
  207. package/src/handlers/messages-sync.ts +593 -102
  208. package/src/handlers/protocols-configure.ts +103 -2
  209. package/src/handlers/records-count.ts +33 -0
  210. package/src/handlers/records-delete.ts +3 -2
  211. package/src/handlers/records-query.ts +33 -0
  212. package/src/handlers/records-read.ts +3 -2
  213. package/src/handlers/records-subscribe.ts +34 -0
  214. package/src/handlers/records-write.ts +62 -11
  215. package/src/index.ts +7 -3
  216. package/src/interfaces/messages-read.ts +8 -5
  217. package/src/interfaces/messages-subscribe.ts +12 -9
  218. package/src/interfaces/messages-sync.ts +33 -12
  219. package/src/interfaces/protocols-configure.ts +8 -4
  220. package/src/interfaces/protocols-query.ts +13 -9
  221. package/src/interfaces/records-count.ts +7 -0
  222. package/src/interfaces/records-delete.ts +9 -5
  223. package/src/interfaces/records-query.ts +7 -0
  224. package/src/interfaces/records-read.ts +6 -3
  225. package/src/interfaces/records-subscribe.ts +7 -0
  226. package/src/interfaces/records-write.ts +25 -17
  227. package/src/protocols/permissions.ts +47 -9
  228. package/src/sync/records-projection.ts +328 -0
  229. package/src/types/message-types.ts +1 -0
  230. package/src/types/messages-types.ts +23 -3
  231. package/src/types/permission-types.ts +5 -1
  232. package/src/types/records-types.ts +5 -1
  233. package/src/types/subscriptions.ts +19 -3
  234. package/src/utils/permission-scope.ts +55 -0
@@ -1,20 +1,25 @@
1
1
  import type { MessageSigner } from '../types/signer.js';
2
+ import type { RecordsProjectionScope } from '../sync/records-projection.js';
2
3
  import type { MessagesSyncAction, MessagesSyncDescriptor, MessagesSyncMessage } from '../types/messages-types.js';
3
4
 
4
5
  import { AbstractMessage } from '../core/abstract-message.js';
5
6
  import { Message } from '../core/message.js';
7
+ import { RECORDS_PROJECTION_ROOT_VERSION } from '../sync/records-projection.js';
6
8
  import { removeUndefinedProperties } from '@enbox/common';
7
9
  import { Time } from '../utils/time.js';
8
10
  import { validateProtocolUrlNormalized } from '../utils/url.js';
11
+ import { DwnError, DwnErrorCode } from '../core/dwn-error.js';
9
12
  import { DwnInterfaceName, DwnMethodName } from '../enums/dwn-interface-method.js';
10
13
 
11
14
  export type MessagesSyncOptions = {
12
15
  signer : MessageSigner;
13
16
  action : MessagesSyncAction;
14
17
  protocol? : string;
18
+ projectionRootVersion?: string;
19
+ projectionScopes?: RecordsProjectionScope[];
15
20
  prefix? : string;
16
21
  messageTimestamp? : string;
17
- permissionGrantId? : string;
22
+ permissionGrantIds? : string[];
18
23
  /** For `action: 'diff'`: client's subtree hashes at `depth`. */
19
24
  hashes? : Record<string, string>;
20
25
  /** For `action: 'diff'`: bit depth at which hashes were computed. */
@@ -30,30 +35,46 @@ export class MessagesSync extends AbstractMessage<MessagesSyncMessage> {
30
35
  if (message.descriptor.protocol !== undefined) {
31
36
  validateProtocolUrlNormalized(message.descriptor.protocol);
32
37
  }
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
+ }
33
48
 
34
49
  return new MessagesSync(message);
35
50
  }
36
51
 
37
52
  public static async create(options: MessagesSyncOptions): Promise<MessagesSync> {
53
+ const permissionGrantInvocation = Message.normalizePermissionGrantInvocation({
54
+ permissionGrantIds: options.permissionGrantIds
55
+ });
56
+
38
57
  const descriptor: MessagesSyncDescriptor = {
39
- interface : DwnInterfaceName.Messages,
40
- method : DwnMethodName.Sync,
41
- messageTimestamp : options.messageTimestamp ?? Time.getCurrentTimestamp(),
42
- action : options.action,
43
- protocol : options.protocol,
44
- prefix : options.prefix,
45
- permissionGrantId : options.permissionGrantId,
46
- hashes : options.hashes,
47
- depth : options.depth,
58
+ interface : DwnInterfaceName.Messages,
59
+ method : DwnMethodName.Sync,
60
+ messageTimestamp : options.messageTimestamp ?? Time.getCurrentTimestamp(),
61
+ action : options.action,
62
+ protocol : options.protocol,
63
+ projectionRootVersion : options.projectionRootVersion,
64
+ projectionScopes : options.projectionScopes,
65
+ prefix : options.prefix,
66
+ hashes : options.hashes,
67
+ depth : options.depth,
68
+ ...permissionGrantInvocation,
48
69
  };
49
70
 
50
71
  removeUndefinedProperties(descriptor);
51
72
 
52
- const { permissionGrantId, signer } = options;
73
+ const { signer } = options;
53
74
  const authorization = await Message.createAuthorization({
54
75
  descriptor,
55
76
  signer,
56
- permissionGrantId
77
+ ...permissionGrantInvocation
57
78
  });
58
79
 
59
80
  const message = { descriptor, authorization };
@@ -40,19 +40,23 @@ export class ProtocolsConfigure extends AbstractMessage<ProtocolsConfigureMessag
40
40
  }
41
41
 
42
42
  public static async create(options: ProtocolsConfigureOptions): Promise<ProtocolsConfigure> {
43
+ const permissionGrantInvocation = Message.normalizePermissionGrantInvocation({
44
+ permissionGrantId: options.permissionGrantId,
45
+ });
46
+
43
47
  const descriptor: ProtocolsConfigureDescriptor = {
44
48
  interface : DwnInterfaceName.Protocols,
45
49
  method : DwnMethodName.Configure,
46
50
  messageTimestamp : options.messageTimestamp ?? Time.getCurrentTimestamp(),
47
51
  definition : ProtocolsConfigure.normalizeDefinition(options.definition),
48
- ...(options.permissionGrantId !== undefined && { permissionGrantId: options.permissionGrantId }),
52
+ ...permissionGrantInvocation,
49
53
  };
50
54
 
51
55
  const authorization = await Message.createAuthorization({
52
56
  descriptor,
53
- signer : options.signer,
54
- delegatedGrant : options.delegatedGrant,
55
- permissionGrantId : options.permissionGrantId
57
+ signer : options.signer,
58
+ delegatedGrant : options.delegatedGrant,
59
+ ...permissionGrantInvocation
56
60
  });
57
61
  const message = { descriptor, authorization };
58
62
 
@@ -36,13 +36,16 @@ export class ProtocolsQuery extends AbstractMessage<ProtocolsQueryMessage> {
36
36
  }
37
37
 
38
38
  public static async create(options: ProtocolsQueryOptions): Promise<ProtocolsQuery> {
39
+ const permissionGrantInvocation = Message.normalizePermissionGrantInvocation({
40
+ permissionGrantId: options.permissionGrantId,
41
+ });
39
42
 
40
43
  const descriptor: ProtocolsQueryDescriptor = {
41
- interface : DwnInterfaceName.Protocols,
42
- method : DwnMethodName.Query,
43
- messageTimestamp : options.messageTimestamp ?? Time.getCurrentTimestamp(),
44
- filter : options.filter ? ProtocolsQuery.normalizeFilter(options.filter) : undefined,
45
- permissionGrantId : options.permissionGrantId,
44
+ interface : DwnInterfaceName.Protocols,
45
+ method : DwnMethodName.Query,
46
+ messageTimestamp : options.messageTimestamp ?? Time.getCurrentTimestamp(),
47
+ filter : options.filter ? ProtocolsQuery.normalizeFilter(options.filter) : undefined,
48
+ ...permissionGrantInvocation,
46
49
  };
47
50
 
48
51
  // delete all descriptor properties that are `undefined` else the code will encounter the following IPLD issue when attempting to generate CID:
@@ -54,8 +57,8 @@ export class ProtocolsQuery extends AbstractMessage<ProtocolsQueryMessage> {
54
57
  if (options.signer !== undefined) {
55
58
  authorization = await Message.createAuthorization({
56
59
  descriptor,
57
- signer : options.signer,
58
- permissionGrantId : options.permissionGrantId
60
+ signer: options.signer,
61
+ ...permissionGrantInvocation
59
62
  });
60
63
  }
61
64
 
@@ -78,8 +81,9 @@ export class ProtocolsQuery extends AbstractMessage<ProtocolsQueryMessage> {
78
81
  // if author is the same as the target tenant, we can directly grant access
79
82
  if (this.author === tenant) {
80
83
  return;
81
- } else if (this.author !== undefined && this.signaturePayload!.permissionGrantId) {
82
- const permissionGrant = await PermissionsProtocol.fetchGrant(tenant, messageStore, this.signaturePayload!.permissionGrantId);
84
+ } else if (this.author !== undefined && Message.getPermissionGrantId(this.signaturePayload!) !== undefined) {
85
+ const permissionGrantId = Message.getPermissionGrantId(this.signaturePayload!)!;
86
+ const permissionGrant = await PermissionsProtocol.fetchGrant(tenant, messageStore, permissionGrantId);
83
87
  await ProtocolsGrantAuthorization.authorizeQuery({
84
88
  expectedGrantor : tenant,
85
89
  expectedGrantee : this.author,
@@ -17,6 +17,7 @@ export type RecordsCountOptions = {
17
17
  messageTimestamp?: string;
18
18
  filter: RecordsFilter;
19
19
  signer?: MessageSigner;
20
+ permissionGrantId?: string;
20
21
  protocolRole?: string;
21
22
 
22
23
  /**
@@ -60,11 +61,16 @@ export class RecordsCount extends AbstractMessage<RecordsCountMessage> {
60
61
  }
61
62
 
62
63
  public static async create(options: RecordsCountOptions): Promise<RecordsCount> {
64
+ const permissionGrantInvocation = Message.normalizePermissionGrantInvocation({
65
+ permissionGrantId: options.permissionGrantId,
66
+ });
67
+
63
68
  const descriptor: RecordsCountDescriptor = {
64
69
  interface : DwnInterfaceName.Records,
65
70
  method : DwnMethodName.Count,
66
71
  messageTimestamp : options.messageTimestamp ?? Time.getCurrentTimestamp(),
67
72
  filter : Records.normalizeFilter(options.filter),
73
+ ...permissionGrantInvocation,
68
74
  };
69
75
 
70
76
  // delete all descriptor properties that are `undefined` else the code will encounter the following IPLD issue when attempting to generate CID:
@@ -78,6 +84,7 @@ export class RecordsCount extends AbstractMessage<RecordsCountMessage> {
78
84
  authorization = await Message.createAuthorization({
79
85
  descriptor,
80
86
  signer,
87
+ ...permissionGrantInvocation,
81
88
  protocolRole : options.protocolRole,
82
89
  delegatedGrant : options.delegatedGrant
83
90
  });
@@ -58,21 +58,25 @@ export class RecordsDelete extends AbstractMessage<RecordsDeleteMessage> {
58
58
  public static async create(options: RecordsDeleteOptions): Promise<RecordsDelete> {
59
59
  const recordId = options.recordId;
60
60
  const currentTime = Time.getCurrentTimestamp();
61
+ const permissionGrantInvocation = Message.normalizePermissionGrantInvocation({
62
+ permissionGrantId: options.permissionGrantId,
63
+ });
61
64
 
62
65
  const descriptor: RecordsDeleteDescriptor = {
63
66
  interface : DwnInterfaceName.Records,
64
67
  method : DwnMethodName.Delete,
65
68
  messageTimestamp : options.messageTimestamp ?? currentTime,
66
69
  recordId,
67
- prune : options.prune ?? false
70
+ prune : options.prune ?? false,
71
+ ...permissionGrantInvocation,
68
72
  };
69
73
 
70
74
  const authorization = await Message.createAuthorization({
71
75
  descriptor,
72
- signer : options.signer,
73
- protocolRole : options.protocolRole,
74
- permissionGrantId : options.permissionGrantId,
75
- delegatedGrant : options.delegatedGrant
76
+ signer : options.signer,
77
+ protocolRole : options.protocolRole,
78
+ ...permissionGrantInvocation,
79
+ delegatedGrant : options.delegatedGrant
76
80
  });
77
81
  const message: RecordsDeleteMessage = { descriptor, authorization };
78
82
 
@@ -21,6 +21,7 @@ export type RecordsQueryOptions = {
21
21
  dateSort?: DateSort;
22
22
  pagination?: Pagination;
23
23
  signer?: MessageSigner;
24
+ permissionGrantId?: string;
24
25
  protocolRole?: string;
25
26
 
26
27
  /**
@@ -74,11 +75,16 @@ export class RecordsQuery extends AbstractMessage<RecordsQueryMessage> {
74
75
  }
75
76
 
76
77
  public static async create(options: RecordsQueryOptions): Promise<RecordsQuery> {
78
+ const permissionGrantInvocation = Message.normalizePermissionGrantInvocation({
79
+ permissionGrantId: options.permissionGrantId,
80
+ });
81
+
77
82
  const descriptor: RecordsQueryDescriptor = {
78
83
  interface : DwnInterfaceName.Records,
79
84
  method : DwnMethodName.Query,
80
85
  messageTimestamp : options.messageTimestamp ?? Time.getCurrentTimestamp(),
81
86
  filter : Records.normalizeFilter(options.filter),
87
+ ...permissionGrantInvocation,
82
88
  dateSort : options.dateSort,
83
89
  pagination : options.pagination,
84
90
  };
@@ -103,6 +109,7 @@ export class RecordsQuery extends AbstractMessage<RecordsQueryMessage> {
103
109
  authorization = await Message.createAuthorization({
104
110
  descriptor,
105
111
  signer,
112
+ ...permissionGrantInvocation,
106
113
  protocolRole : options.protocolRole,
107
114
  delegatedGrant : options.delegatedGrant
108
115
  });
@@ -64,8 +64,11 @@ export class RecordsRead extends AbstractMessage<RecordsReadMessage> {
64
64
  * @throws {DwnError} when a combination of required RecordsReadOptions are missing
65
65
  */
66
66
  public static async create(options: RecordsReadOptions): Promise<RecordsRead> {
67
- const { filter, signer, permissionGrantId, protocolRole, dateSort } = options;
67
+ const { filter, signer, protocolRole, dateSort } = options;
68
68
  const currentTime = Time.getCurrentTimestamp();
69
+ const permissionGrantInvocation = Message.normalizePermissionGrantInvocation({
70
+ permissionGrantId: options.permissionGrantId
71
+ });
69
72
 
70
73
  if (options.filter.published === false) {
71
74
  if (dateSort === DateSort.PublishedAscending || dateSort === DateSort.PublishedDescending) {
@@ -81,8 +84,8 @@ export class RecordsRead extends AbstractMessage<RecordsReadMessage> {
81
84
  method : DwnMethodName.Read,
82
85
  filter : Records.normalizeFilter(filter),
83
86
  messageTimestamp : options.messageTimestamp ?? currentTime,
84
- permissionGrantId,
85
87
  dateSort,
88
+ ...permissionGrantInvocation,
86
89
  };
87
90
 
88
91
  removeUndefinedProperties(descriptor);
@@ -93,7 +96,7 @@ export class RecordsRead extends AbstractMessage<RecordsReadMessage> {
93
96
  authorization = await Message.createAuthorization({
94
97
  descriptor,
95
98
  signer,
96
- permissionGrantId,
99
+ ...permissionGrantInvocation,
97
100
  protocolRole,
98
101
  delegatedGrant: options.delegatedGrant
99
102
  });
@@ -21,6 +21,7 @@ export type RecordsSubscribeOptions = {
21
21
  dateSort?: DateSort;
22
22
  pagination?: Pagination;
23
23
  signer?: MessageSigner;
24
+ permissionGrantId?: string;
24
25
  protocolRole?: string;
25
26
 
26
27
  /**
@@ -68,11 +69,16 @@ export class RecordsSubscribe extends AbstractMessage<RecordsSubscribeMessage> {
68
69
  }
69
70
 
70
71
  public static async create(options: RecordsSubscribeOptions): Promise<RecordsSubscribe> {
72
+ const permissionGrantInvocation = Message.normalizePermissionGrantInvocation({
73
+ permissionGrantId: options.permissionGrantId,
74
+ });
75
+
71
76
  const descriptor: RecordsSubscribeDescriptor = {
72
77
  interface : DwnInterfaceName.Records,
73
78
  method : DwnMethodName.Subscribe,
74
79
  messageTimestamp : options.messageTimestamp ?? Time.getCurrentTimestamp(),
75
80
  filter : Records.normalizeFilter(options.filter),
81
+ ...permissionGrantInvocation,
76
82
  dateSort : options.dateSort,
77
83
  pagination : options.pagination,
78
84
  cursor : options.cursor,
@@ -89,6 +95,7 @@ export class RecordsSubscribe extends AbstractMessage<RecordsSubscribeMessage> {
89
95
  authorization = await Message.createAuthorization({
90
96
  descriptor,
91
97
  signer,
98
+ ...permissionGrantInvocation,
92
99
  protocolRole : options.protocolRole,
93
100
  delegatedGrant : options.delegatedGrant
94
101
  });
@@ -267,7 +267,12 @@ export class RecordsWrite implements MessageInterface<RecordsWriteMessage> {
267
267
  await Message.validateSignatureStructure(message.authorization.signature, message.descriptor, 'RecordsWriteSignaturePayload');
268
268
 
269
269
  if (message.authorization.ownerSignature !== undefined) {
270
- await Message.validateSignatureStructure(message.authorization.ownerSignature, message.descriptor);
270
+ await Message.validateSignatureStructure(
271
+ message.authorization.ownerSignature,
272
+ message.descriptor,
273
+ 'GenericSignaturePayload',
274
+ { validatePermissionGrantInvocation: false }
275
+ );
271
276
  }
272
277
 
273
278
  await validateAttestationIntegrity(message);
@@ -314,25 +319,28 @@ export class RecordsWrite implements MessageInterface<RecordsWriteMessage> {
314
319
  const dataSize = options.dataSize ?? options.data!.length;
315
320
 
316
321
  const currentTime = Time.getCurrentTimestamp();
322
+ const permissionGrantInvocation = Message.normalizePermissionGrantInvocation({
323
+ permissionGrantId: options.permissionGrantId,
324
+ });
317
325
 
318
326
  const descriptor: RecordsWriteDescriptor = {
319
- interface : DwnInterfaceName.Records,
320
- method : DwnMethodName.Write,
321
- protocol : normalizeProtocolUrl(options.protocol),
322
- protocolPath : options.protocolPath,
323
- recipient : options.recipient,
324
- schema : options.schema === undefined ? undefined : normalizeSchemaUrl(options.schema),
325
- tags : options.tags,
326
- parentId : RecordsWrite.getRecordIdFromContextId(options.parentContextId),
327
+ interface : DwnInterfaceName.Records,
328
+ method : DwnMethodName.Write,
329
+ protocol : normalizeProtocolUrl(options.protocol),
330
+ protocolPath : options.protocolPath,
331
+ recipient : options.recipient,
332
+ schema : options.schema === undefined ? undefined : normalizeSchemaUrl(options.schema),
333
+ tags : options.tags,
334
+ parentId : RecordsWrite.getRecordIdFromContextId(options.parentContextId),
327
335
  dataCid,
328
336
  dataSize,
329
- dateCreated : options.dateCreated ?? currentTime,
330
- messageTimestamp : options.messageTimestamp ?? currentTime,
331
- published : options.published,
332
- datePublished : options.datePublished,
333
- dataFormat : options.dataFormat,
334
- permissionGrantId : options.permissionGrantId,
335
- squash : options.squash,
337
+ dateCreated : options.dateCreated ?? currentTime,
338
+ messageTimestamp : options.messageTimestamp ?? currentTime,
339
+ published : options.published,
340
+ datePublished : options.datePublished,
341
+ dataFormat : options.dataFormat,
342
+ squash : options.squash,
343
+ ...permissionGrantInvocation,
336
344
  };
337
345
 
338
346
  // generate `datePublished` if the message is to be published but `datePublished` is not given
@@ -370,7 +378,7 @@ export class RecordsWrite implements MessageInterface<RecordsWriteMessage> {
370
378
  await recordsWrite.sign({
371
379
  signer : options.signer,
372
380
  delegatedGrant : options.delegatedGrant,
373
- permissionGrantId : options.permissionGrantId,
381
+ ...permissionGrantInvocation,
374
382
  protocolRole : options.protocolRole,
375
383
  authorKeyDeliveryPublicKey : options.authorKeyDeliveryPublicKey,
376
384
  });
@@ -14,6 +14,7 @@ import { FilterUtility } from '../utils/filter.js';
14
14
  import { Message } from '../core/message.js';
15
15
  import { PermissionGrant } from './permission-grant.js';
16
16
  import { PermissionRequest } from './permission-request.js';
17
+ import { PERMISSIONS_PROTOCOL_URI } from '../core/constants.js';
17
18
  import { Records } from '../utils/records.js';
18
19
  import { RecordsWrite } from '../interfaces/records-write.js';
19
20
  import { Time } from '../utils/time.js';
@@ -95,7 +96,7 @@ export class PermissionsProtocol implements CoreProtocol {
95
96
  /**
96
97
  * The URI of the DWN Permissions protocol.
97
98
  */
98
- public static readonly uri = 'https://identity.foundation/dwn/permissions';
99
+ public static readonly uri = PERMISSIONS_PROTOCOL_URI;
99
100
 
100
101
  /**
101
102
  * The protocol path of the `request` record.
@@ -312,12 +313,24 @@ export class PermissionsProtocol implements CoreProtocol {
312
313
  dataEncodedMessage: DataEncodedRecordsWriteMessage,
313
314
  }> {
314
315
 
316
+ if (this.hasConflictingSubtreeScope(options.scope)) {
317
+ throw new DwnError(
318
+ DwnErrorCode.PermissionsProtocolCreateRequestScopeContextIdProtocolPathConflict,
319
+ 'Permission request scopes cannot have both `contextId` and `protocolPath` present'
320
+ );
321
+ }
315
322
  if (this.isRecordPermissionScope(options.scope) && options.scope.protocol === undefined) {
316
323
  throw new DwnError(
317
324
  DwnErrorCode.PermissionsProtocolCreateRequestRecordsScopeMissingProtocol,
318
325
  'Permission request for Records must have a scope with a `protocol` property'
319
326
  );
320
327
  }
328
+ if (this.hasSubtreeScope(options.scope) && !this.hasProtocolScope(options.scope)) {
329
+ throw new DwnError(
330
+ DwnErrorCode.PermissionsProtocolCreateRequestSubtreeScopeMissingProtocol,
331
+ 'Permission request subtree scopes must have a `protocol` property'
332
+ );
333
+ }
321
334
 
322
335
  const scope = PermissionsProtocol.normalizePermissionScope(options.scope);
323
336
 
@@ -371,12 +384,24 @@ export class PermissionsProtocol implements CoreProtocol {
371
384
  dataEncodedMessage: DataEncodedRecordsWriteMessage,
372
385
  }> {
373
386
 
387
+ if (this.hasConflictingSubtreeScope(options.scope)) {
388
+ throw new DwnError(
389
+ DwnErrorCode.PermissionsProtocolCreateGrantScopeContextIdProtocolPathConflict,
390
+ 'Permission grant scopes cannot have both `contextId` and `protocolPath` present'
391
+ );
392
+ }
374
393
  if (this.isRecordPermissionScope(options.scope) && options.scope.protocol === undefined) {
375
394
  throw new DwnError(
376
395
  DwnErrorCode.PermissionsProtocolCreateGrantRecordsScopeMissingProtocol,
377
396
  'Permission grants for Records must have a scope with a `protocol` property'
378
397
  );
379
398
  }
399
+ if (this.hasSubtreeScope(options.scope) && !this.hasProtocolScope(options.scope)) {
400
+ throw new DwnError(
401
+ DwnErrorCode.PermissionsProtocolCreateGrantSubtreeScopeMissingProtocol,
402
+ 'Permission grant subtree scopes must have a `protocol` property'
403
+ );
404
+ }
380
405
 
381
406
  const scope = PermissionsProtocol.normalizePermissionScope(options.scope);
382
407
 
@@ -600,6 +625,16 @@ export class PermissionsProtocol implements CoreProtocol {
600
625
  return 'protocol' in scope && scope.protocol !== undefined;
601
626
  }
602
627
 
628
+ private static hasSubtreeScope(scope: PermissionScope): scope is PermissionScope & ({ contextId: string } | { protocolPath: string }) {
629
+ return ('contextId' in scope && scope.contextId !== undefined)
630
+ || ('protocolPath' in scope && scope.protocolPath !== undefined);
631
+ }
632
+
633
+ private static hasConflictingSubtreeScope(scope: PermissionScope): boolean {
634
+ return ('contextId' in scope && scope.contextId !== undefined)
635
+ && ('protocolPath' in scope && scope.protocolPath !== undefined);
636
+ }
637
+
603
638
  /**
604
639
  * Validates that tags must include a protocol tag that matches the scoped protocol.
605
640
  */
@@ -633,18 +668,21 @@ export class PermissionsProtocol implements CoreProtocol {
633
668
  this.validateTags(requestOrGrant, scope.protocol);
634
669
  }
635
670
 
636
- // if the scope is not a record permission scope, no additional validation is required
637
- if (!this.isRecordPermissionScope(scope)) {
638
- return;
639
- }
640
- // otherwise this is a record permission scope, more validation needed below
641
-
642
671
  // `contextId` and `protocolPath` are mutually exclusive
643
- if (scope.contextId !== undefined && scope.protocolPath !== undefined) {
672
+ const hasContextId = 'contextId' in scope && scope.contextId !== undefined;
673
+ const hasProtocolPath = 'protocolPath' in scope && scope.protocolPath !== undefined;
674
+ if (hasContextId && hasProtocolPath) {
644
675
  throw new DwnError(
645
676
  DwnErrorCode.PermissionsProtocolValidateScopeContextIdProhibitedProperties,
646
677
  'Permission grants cannot have both `contextId` and `protocolPath` present'
647
678
  );
648
679
  }
680
+ if ((hasContextId || hasProtocolPath) && !this.hasProtocolScope(scope)) {
681
+ throw new DwnError(
682
+ DwnErrorCode.PermissionsProtocolValidateScopeSubtreeScopeMissingProtocol,
683
+ 'Permission grant subtree scopes must have a `protocol` property'
684
+ );
685
+ }
686
+
649
687
  }
650
- };
688
+ };