@enbox/dwn-sdk-js 0.4.17 → 0.4.18

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 (77) hide show
  1. package/dist/browser.mjs +1 -1
  2. package/dist/browser.mjs.map +4 -4
  3. package/dist/esm/generated/precompiled-validators.js +349 -198
  4. package/dist/esm/generated/precompiled-validators.js.map +1 -1
  5. package/dist/esm/src/handlers/records-collection.js +200 -0
  6. package/dist/esm/src/handlers/records-collection.js.map +1 -0
  7. package/dist/esm/src/handlers/records-count.js +19 -196
  8. package/dist/esm/src/handlers/records-count.js.map +1 -1
  9. package/dist/esm/src/handlers/records-query.js +19 -376
  10. package/dist/esm/src/handlers/records-query.js.map +1 -1
  11. package/dist/esm/src/handlers/records-subscribe.js +21 -341
  12. package/dist/esm/src/handlers/records-subscribe.js.map +1 -1
  13. package/dist/esm/src/interfaces/records-count.js +1 -1
  14. package/dist/esm/src/interfaces/records-count.js.map +1 -1
  15. package/dist/esm/src/interfaces/records-query.js +1 -1
  16. package/dist/esm/src/interfaces/records-query.js.map +1 -1
  17. package/dist/esm/src/interfaces/records-subscribe.js +3 -1
  18. package/dist/esm/src/interfaces/records-subscribe.js.map +1 -1
  19. package/dist/esm/src/store/index-level.js +84 -32
  20. package/dist/esm/src/store/index-level.js.map +1 -1
  21. package/dist/esm/src/store/message-store-level.js +45 -11
  22. package/dist/esm/src/store/message-store-level.js.map +1 -1
  23. package/dist/esm/src/utils/record-limit-occupancy.js +5 -2
  24. package/dist/esm/src/utils/record-limit-occupancy.js.map +1 -1
  25. package/dist/esm/src/utils/records.js +14 -47
  26. package/dist/esm/src/utils/records.js.map +1 -1
  27. package/dist/esm/tests/features/records-nested-query-scope.spec.js +15 -1
  28. package/dist/esm/tests/features/records-nested-query-scope.spec.js.map +1 -1
  29. package/dist/esm/tests/features/records-record-limit.spec.js +116 -0
  30. package/dist/esm/tests/features/records-record-limit.spec.js.map +1 -1
  31. package/dist/esm/tests/handlers/records-count.spec.js +52 -1
  32. package/dist/esm/tests/handlers/records-count.spec.js.map +1 -1
  33. package/dist/esm/tests/handlers/records-subscribe.spec.js +76 -1
  34. package/dist/esm/tests/handlers/records-subscribe.spec.js.map +1 -1
  35. package/dist/esm/tests/store/index-level.spec.js +95 -1
  36. package/dist/esm/tests/store/index-level.spec.js.map +1 -1
  37. package/dist/esm/tests/store/message-store-level.spec.js +70 -1
  38. package/dist/esm/tests/store/message-store-level.spec.js.map +1 -1
  39. package/dist/types/generated/precompiled-validators.d.ts.map +1 -1
  40. package/dist/types/src/handlers/records-collection.d.ts +32 -0
  41. package/dist/types/src/handlers/records-collection.d.ts.map +1 -0
  42. package/dist/types/src/handlers/records-count.d.ts +0 -35
  43. package/dist/types/src/handlers/records-count.d.ts.map +1 -1
  44. package/dist/types/src/handlers/records-query.d.ts +0 -61
  45. package/dist/types/src/handlers/records-query.d.ts.map +1 -1
  46. package/dist/types/src/handlers/records-subscribe.d.ts +1 -37
  47. package/dist/types/src/handlers/records-subscribe.d.ts.map +1 -1
  48. package/dist/types/src/interfaces/records-subscribe.d.ts.map +1 -1
  49. package/dist/types/src/store/index-level.d.ts +27 -3
  50. package/dist/types/src/store/index-level.d.ts.map +1 -1
  51. package/dist/types/src/store/message-store-level.d.ts +1 -0
  52. package/dist/types/src/store/message-store-level.d.ts.map +1 -1
  53. package/dist/types/src/types/message-store.d.ts +6 -1
  54. package/dist/types/src/types/message-store.d.ts.map +1 -1
  55. package/dist/types/src/types/records-types.d.ts +1 -1
  56. package/dist/types/src/types/records-types.d.ts.map +1 -1
  57. package/dist/types/src/utils/record-limit-occupancy.d.ts.map +1 -1
  58. package/dist/types/src/utils/records.d.ts +6 -25
  59. package/dist/types/src/utils/records.d.ts.map +1 -1
  60. package/dist/types/tests/features/records-nested-query-scope.spec.d.ts.map +1 -1
  61. package/dist/types/tests/features/records-record-limit.spec.d.ts.map +1 -1
  62. package/dist/types/tests/handlers/records-count.spec.d.ts.map +1 -1
  63. package/dist/types/tests/handlers/records-subscribe.spec.d.ts.map +1 -1
  64. package/package.json +1 -1
  65. package/src/handlers/records-collection.ts +269 -0
  66. package/src/handlers/records-count.ts +21 -236
  67. package/src/handlers/records-query.ts +22 -447
  68. package/src/handlers/records-subscribe.ts +26 -404
  69. package/src/interfaces/records-count.ts +1 -1
  70. package/src/interfaces/records-query.ts +1 -1
  71. package/src/interfaces/records-subscribe.ts +5 -2
  72. package/src/store/index-level.ts +145 -37
  73. package/src/store/message-store-level.ts +46 -11
  74. package/src/types/message-store.ts +6 -1
  75. package/src/types/records-types.ts +1 -1
  76. package/src/utils/record-limit-occupancy.ts +5 -2
  77. package/src/utils/records.ts +17 -52
@@ -65,11 +65,13 @@ export declare class Records {
65
65
  */
66
66
  static normalizeFilter(filter: RecordsFilter): RecordsFilter;
67
67
  /**
68
- * Nested protocol-path queries must select the target path itself or one of
69
- * its ancestor contexts. An omitted, malformed, or deeper context cannot
70
- * identify a bounded subtree of the selected protocol path.
68
+ * Nested protocol-path collection requests must select one or more direct
69
+ * parents, the target path itself, or one of its ancestor contexts. A
70
+ * bounded path-wide subscription may omit that scope because its initial
71
+ * page is explicitly capped; record-limited results still project each
72
+ * direct-parent population independently.
71
73
  */
72
- static validateNestedProtocolPathQueryScope(filter: RecordsFilter, errorCode: DwnErrorCode, operationName: string): void;
74
+ static validateNestedProtocolPathScope(filter: RecordsFilter, errorCode: DwnErrorCode, operationName: string, allowBoundedPathWideSelection?: boolean): void;
73
75
  static isStartsWithFilter(filter: RecordsWriteTagsFilter): filter is StartsWithFilter;
74
76
  /**
75
77
  * This will create individual keys for each of the tags that look like `tag.tag_property`
@@ -88,7 +90,6 @@ export declare class Records {
88
90
  * @returns {Filter} a generic Filter able to be used with MessageStore.
89
91
  */
90
92
  static convertFilter(filter: RecordsFilter, dateSort?: DateSort): Filter;
91
- static buildUnpublishedControlRecordsFilter(filter: RecordsFilter, dateSort?: DateSort): Filter;
92
93
  static buildControlRecordsFilters(filters: Filter[]): Filter[];
93
94
  /**
94
95
  * Validates the referential integrity of both author-delegated grant and owner-delegated grant.
@@ -116,10 +117,6 @@ export declare class Records {
116
117
  * @returns a `MessageSort` for `MessageStore` sorting.
117
118
  */
118
119
  static convertDateSort(dateSort?: DateSort): MessageSort;
119
- /**
120
- * Determines if signature payload contains a protocolRole and should be authorized as such.
121
- */
122
- static shouldProtocolAuthorize(signaturePayload: GenericSignaturePayload): boolean;
123
120
  /**
124
121
  * Checks if the filter supports returning published records.
125
122
  */
@@ -140,21 +137,5 @@ export declare class Records {
140
137
  * replay, and replay must never admit a delete that admission would now reject.
141
138
  */
142
139
  static isDeleteBeatenByExistingTombstone(deleteToBePerformed: RecordsDeleteMessage, newestExistingMessage: GenericMessage): Promise<boolean>;
143
- /**
144
- * Checks whether or not the incoming records query filter should build an unpublished recipient MessageStore filter.
145
- *
146
- * @param filter The incoming RecordsFilter to evaluate against.
147
- * @param recipient The recipient to check against the filter, typically the query/subscribe message author.
148
- * @returns {boolean} True if the filter contains the recipient, or if the recipient filter is undefined/empty.
149
- */
150
- static shouldBuildUnpublishedRecipientFilter(filter: RecordsFilter, recipient: string): boolean;
151
- /**
152
- * Checks whether or not the incoming records query filter should build an unpublished author MessageStore filter.
153
- *
154
- * @param filter The incoming RecordsFilter to evaluate against.
155
- * @param author The author to check against the filter, typically the query/subscribe message author.
156
- * @returns {boolean} True if the filter contains the author, or if the author filter is undefined/empty.
157
- */
158
- static shouldBuildUnpublishedAuthorFilter(filter: RecordsFilter, author: string): boolean;
159
140
  }
160
141
  //# sourceMappingURL=records.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"records.d.ts","sourceRoot":"","sources":["../../../../src/utils/records.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"records.d.ts","sourceRoot":"","sources":["../../../../src/utils/records.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"records-nested-query-scope.spec.d.ts","sourceRoot":"","sources":["../../../../tests/features/records-nested-query-scope.spec.ts"],"names":[],"mappings":"AAmBA,wBAAgB,2BAA2B,IAAI,IAAI,CAsZlD"}
1
+ {"version":3,"file":"records-nested-query-scope.spec.d.ts","sourceRoot":"","sources":["../../../../tests/features/records-nested-query-scope.spec.ts"],"names":[],"mappings":"AAmBA,wBAAgB,2BAA2B,IAAI,IAAI,CAwalD"}
@@ -1 +1 @@
1
- {"version":3,"file":"records-record-limit.spec.d.ts","sourceRoot":"","sources":["../../../../tests/features/records-record-limit.spec.ts"],"names":[],"mappings":"AA4BA,wBAAgB,sBAAsB,IAAI,IAAI,CAoiC7C"}
1
+ {"version":3,"file":"records-record-limit.spec.d.ts","sourceRoot":"","sources":["../../../../tests/features/records-record-limit.spec.ts"],"names":[],"mappings":"AA4BA,wBAAgB,sBAAsB,IAAI,IAAI,CAoqC7C"}
@@ -1 +1 @@
1
- {"version":3,"file":"records-count.spec.d.ts","sourceRoot":"","sources":["../../../../tests/handlers/records-count.spec.ts"],"names":[],"mappings":"AAyBA,wBAAgB,uBAAuB,IAAI,IAAI,CA2zB9C"}
1
+ {"version":3,"file":"records-count.spec.d.ts","sourceRoot":"","sources":["../../../../tests/handlers/records-count.spec.ts"],"names":[],"mappings":"AA0BA,wBAAgB,uBAAuB,IAAI,IAAI,CAy3B9C"}
@@ -1 +1 @@
1
- {"version":3,"file":"records-subscribe.spec.d.ts","sourceRoot":"","sources":["../../../../tests/handlers/records-subscribe.spec.ts"],"names":[],"mappings":"AAkCA,wBAAgB,2BAA2B,IAAI,IAAI,CAupDlD"}
1
+ {"version":3,"file":"records-subscribe.spec.d.ts","sourceRoot":"","sources":["../../../../tests/handlers/records-subscribe.spec.ts"],"names":[],"mappings":"AAkCA,wBAAgB,2BAA2B,IAAI,IAAI,CAwvDlD"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@enbox/dwn-sdk-js",
3
- "version": "0.4.17",
3
+ "version": "0.4.18",
4
4
  "description": "A reference implementation of https://identity.foundation/decentralized-web-node/spec/",
5
5
  "repository": {
6
6
  "type": "git",
@@ -0,0 +1,269 @@
1
+ import type { HandlerDependencies } from '../types/method-handler.js';
2
+ import type { RecordsCount } from '../interfaces/records-count.js';
3
+ import type { RecordsQuery } from '../interfaces/records-query.js';
4
+ import type { RecordsSubscribe } from '../interfaces/records-subscribe.js';
5
+ import type { Filter, PaginationCursor } from '../types/query-types.js';
6
+ import type { RecordsFilter, RecordsQueryReplyEntry } from '../types/records-types.js';
7
+
8
+ import { authenticate } from '../core/auth.js';
9
+ import { DateSort } from '../types/records-types.js';
10
+ import { EncryptionControl } from '../core/encryption-control.js';
11
+ import { Message } from '../core/message.js';
12
+ import { ProtocolAuthorization } from '../core/protocol-authorization.js';
13
+ import { Records } from '../utils/records.js';
14
+ import { RecordsGrantAuthorization } from '../core/records-grant-authorization.js';
15
+ import { DwnInterfaceName, DwnMethodName } from '../enums/dwn-interface-method.js';
16
+ import { queryRecordsWithRecordLimitOccupancy, resolveRecordLimitOccupancy } from '../utils/record-limit-occupancy.js';
17
+
18
+ type RecordsCollectionRequest = RecordsCount | RecordsQuery | RecordsSubscribe;
19
+
20
+ export type RecordsCollectionVisibility = 'nonOwner' | 'owner' | 'published';
21
+
22
+ /**
23
+ * Resolves the visible population for a Records collection request, authenticating and
24
+ * authorizing every request that is not an anonymous published-records read.
25
+ */
26
+ export async function resolveRecordsCollectionVisibility(
27
+ tenant: string,
28
+ request: RecordsCollectionRequest,
29
+ deps: HandlerDependencies,
30
+ ): Promise<RecordsCollectionVisibility> {
31
+ const recordsFilter = request.message.descriptor.filter;
32
+ if (Records.filterIncludesPublishedRecords(recordsFilter) && request.author === undefined) {
33
+ return 'published';
34
+ }
35
+
36
+ await authenticate(request.message.authorization!, deps.didResolver);
37
+
38
+ if (Message.isSignedByAuthorDelegate(request.message) && !EncryptionControl.filterTargetsOnlyControlRecords(recordsFilter)) {
39
+ await request.authorizeDelegate(deps.validationStateReader);
40
+ } else if (EncryptionControl.filterTargetsOnlyControlRecords(recordsFilter)) {
41
+ await EncryptionControl.authorizeControlReadRequest({
42
+ tenant,
43
+ incomingMessage : request.message,
44
+ requester : Message.getRequester(request.message),
45
+ validationStateReader : deps.validationStateReader,
46
+ });
47
+ }
48
+
49
+ const permissionGrantId = Message.getPermissionGrantId(request.signaturePayload!);
50
+ if (permissionGrantId !== undefined) {
51
+ const permissionGrant = await deps.validationStateReader.fetchGrant(tenant, permissionGrantId);
52
+ await RecordsGrantAuthorization.authorizeQueryOrSubscribe({
53
+ incomingMessage : request.message,
54
+ expectedGrantor : tenant,
55
+ expectedGrantee : request.author!,
56
+ permissionGrant,
57
+ validationStateReader : deps.validationStateReader,
58
+ });
59
+ } else if (invokesProtocolRole(request)) {
60
+ // A protocol filter alone does not require protocol authorization because unauthorized
61
+ // records are removed by the visibility filters. An invoked protocol role does.
62
+ await ProtocolAuthorization.authorizeQueryOrSubscribe(tenant, request, deps.validationStateReader);
63
+ }
64
+
65
+ return request.author === tenant ? 'owner' : 'nonOwner';
66
+ }
67
+
68
+ /** Builds latest-write filters shared by Records Query, Count, and Subscribe snapshots. */
69
+ export function buildRecordsSnapshotFilters(
70
+ request: RecordsCollectionRequest,
71
+ visibility: RecordsCollectionVisibility,
72
+ ): Filter[] {
73
+ const descriptor = request.message.descriptor;
74
+ const dateSort = 'dateSort' in descriptor ? descriptor.dateSort : undefined;
75
+ return buildRecordsVisibilityFilters({
76
+ request,
77
+ visibility,
78
+ filter : descriptor.filter,
79
+ purpose : 'snapshot',
80
+ dateSort,
81
+ });
82
+ }
83
+
84
+ /** Builds Write-and-Delete filters for Records Subscribe event delivery. */
85
+ export function buildRecordsEventFilters(
86
+ request: RecordsSubscribe,
87
+ visibility: RecordsCollectionVisibility,
88
+ ): Filter[] {
89
+ return buildRecordsVisibilityFilters({
90
+ request,
91
+ visibility,
92
+ filter : request.message.descriptor.filter,
93
+ purpose : 'event',
94
+ });
95
+ }
96
+
97
+ /**
98
+ * Queries one visible Records page after applying record-limit occupancy, current-audience
99
+ * projection, and encryption-control authorization in their required order.
100
+ */
101
+ export async function queryVisibleRecordsPage(input: {
102
+ deps: HandlerDependencies;
103
+ request: RecordsQuery | RecordsSubscribe;
104
+ tenant: string;
105
+ visibility: RecordsCollectionVisibility;
106
+ }): Promise<{ messages: RecordsQueryReplyEntry[]; cursor?: PaginationCursor }> {
107
+ const { deps, request, tenant, visibility } = input;
108
+ const { dateSort, filter, messageTimestamp, pagination } = request.message.descriptor;
109
+ const filters = buildRecordsSnapshotFilters(request, visibility);
110
+ const recordLimit = await resolveRecordLimitOccupancy({
111
+ validationStateReader : deps.validationStateReader,
112
+ tenant,
113
+ recordsFilter : filter,
114
+ messageTimestamp,
115
+ });
116
+ const controlFilters = Records.buildControlRecordsFilters(filters);
117
+ const currentAudienceRecordIdCache = new Map<string, string | undefined>();
118
+ const requester = Message.getRequester(request.message);
119
+ const messageSort = Records.convertDateSort(dateSort ?? DateSort.CreatedAscending);
120
+
121
+ const queryProjectedPage = async (page = pagination): Promise<{
122
+ messages: RecordsQueryReplyEntry[];
123
+ cursor?: PaginationCursor;
124
+ }> => {
125
+ const result = await queryRecordsWithRecordLimitOccupancy({
126
+ messageStore : deps.messageStore,
127
+ tenant,
128
+ filters,
129
+ recordLimit,
130
+ messageSort,
131
+ pagination : page,
132
+ });
133
+ return EncryptionControl.projectCurrentAudienceRecordPage({
134
+ messageStore: deps.messageStore,
135
+ tenant,
136
+ filters,
137
+ currentAudienceRecordIdCache,
138
+ result,
139
+ });
140
+ };
141
+
142
+ const filterVisibleControlRecords = (messages: RecordsQueryReplyEntry[]): Promise<RecordsQueryReplyEntry[]> =>
143
+ EncryptionControl.filterVisibleControlRecords({
144
+ tenant,
145
+ incomingMessage : request.message,
146
+ requester,
147
+ recordsWriteMessages : messages,
148
+ validationStateReader : deps.validationStateReader,
149
+ });
150
+
151
+ if (controlFilters.length === 0) {
152
+ return queryProjectedPage();
153
+ }
154
+
155
+ if (pagination?.limit === undefined || pagination.limit <= 0) {
156
+ const result = await queryProjectedPage();
157
+ return {
158
+ messages : await filterVisibleControlRecords(result.messages),
159
+ cursor : result.cursor,
160
+ };
161
+ }
162
+
163
+ const visibleMessages: RecordsQueryReplyEntry[] = [];
164
+ let cursor = pagination.cursor;
165
+ let nextCursor: PaginationCursor | undefined;
166
+ // Keeps visible-page pagination stable until #1100 moves control visibility into indexed store filters.
167
+ do {
168
+ const remainingLimit = pagination.limit - visibleMessages.length;
169
+ const result = await queryProjectedPage({ ...pagination, cursor, limit: remainingLimit });
170
+ visibleMessages.push(...await filterVisibleControlRecords(result.messages));
171
+ nextCursor = result.cursor;
172
+ cursor = result.cursor;
173
+ } while (visibleMessages.length < pagination.limit && cursor !== undefined);
174
+
175
+ return { messages: visibleMessages, cursor: nextCursor };
176
+ }
177
+
178
+ function buildRecordsVisibilityFilters(input: {
179
+ dateSort?: DateSort;
180
+ filter: RecordsFilter;
181
+ purpose: 'event' | 'snapshot';
182
+ request: RecordsCollectionRequest;
183
+ visibility: RecordsCollectionVisibility;
184
+ }): Filter[] {
185
+ const { dateSort, filter, purpose, request, visibility } = input;
186
+ if (visibility === 'owner') {
187
+ return [buildRecordsFilter({ dateSort, filter, purpose })];
188
+ }
189
+
190
+ if (visibility === 'published') {
191
+ return [buildRecordsFilter({ dateSort, filter, purpose, published: true })];
192
+ }
193
+
194
+ const filters: Filter[] = [];
195
+ if (Records.filterIncludesPublishedRecords(filter)) {
196
+ filters.push(buildRecordsFilter({ dateSort, filter, purpose, published: true }));
197
+ }
198
+
199
+ if (!Records.filterIncludesUnpublishedRecords(filter)) {
200
+ return filters;
201
+ }
202
+
203
+ if (EncryptionControl.isExactAudienceFilter(filter)) {
204
+ filters.push(buildRecordsFilter({ dateSort, filter, purpose, published: false }));
205
+ }
206
+
207
+ if (shouldBuildUnpublishedAuthorFilter(filter, request.author!)) {
208
+ filters.push(buildRecordsFilter({ author: request.author, dateSort, filter, purpose, published: false }));
209
+ }
210
+
211
+ if (invokesProtocolRole(request) || Message.getPermissionGrantId(request.signaturePayload!) !== undefined) {
212
+ filters.push(buildRecordsFilter({ dateSort, filter, purpose, published: false }));
213
+ }
214
+
215
+ if (shouldBuildUnpublishedRecipientFilter(filter, request.author!)) {
216
+ filters.push(buildRecordsFilter({ dateSort, filter, purpose, published: false, recipient: request.author }));
217
+ }
218
+
219
+ return filters;
220
+ }
221
+
222
+ function buildRecordsFilter(input: {
223
+ author?: string;
224
+ dateSort?: DateSort;
225
+ filter: RecordsFilter;
226
+ purpose: 'event' | 'snapshot';
227
+ published?: boolean;
228
+ recipient?: string;
229
+ }): Filter {
230
+ const { author, dateSort, filter, purpose, published, recipient } = input;
231
+ const result: Filter = {
232
+ ...Records.convertFilter(filter, purpose === 'snapshot' ? dateSort : undefined),
233
+ interface : DwnInterfaceName.Records,
234
+ method : purpose === 'snapshot' ? DwnMethodName.Write : [DwnMethodName.Write, DwnMethodName.Delete],
235
+ };
236
+
237
+ if (purpose === 'snapshot') {
238
+ result.isLatestBaseState = true;
239
+ }
240
+ if (author !== undefined) {
241
+ result.author = author;
242
+ }
243
+ if (published !== undefined) {
244
+ result.published = published;
245
+ }
246
+ if (recipient !== undefined) {
247
+ result.recipient = recipient;
248
+ }
249
+
250
+ return result;
251
+ }
252
+
253
+ function invokesProtocolRole(request: RecordsCollectionRequest): boolean {
254
+ return request.signaturePayload?.protocolRole !== undefined;
255
+ }
256
+
257
+ function shouldBuildUnpublishedRecipientFilter(filter: RecordsFilter, recipient: string): boolean {
258
+ const { recipient: recipientFilter } = filter;
259
+ return Array.isArray(recipientFilter)
260
+ ? recipientFilter.length === 0 || recipientFilter.includes(recipient)
261
+ : recipientFilter === undefined || recipientFilter === recipient;
262
+ }
263
+
264
+ function shouldBuildUnpublishedAuthorFilter(filter: RecordsFilter, author: string): boolean {
265
+ const { author: authorFilter } = filter;
266
+ return Array.isArray(authorFilter)
267
+ ? authorFilter.length === 0 || authorFilter.includes(author)
268
+ : authorFilter === undefined || authorFilter === author;
269
+ }
@@ -1,22 +1,20 @@
1
1
  import type { Filter } from '../types/query-types.js';
2
2
  import type { RecordLimitOccupancy } from '../types/message-store.js';
3
+ import type { RecordsCollectionVisibility } from './records-collection.js';
3
4
  import type { HandlerDependencies, MethodHandler } from '../types/method-handler.js';
4
5
  import type { RecordsCountMessage, RecordsCountReply } from '../types/records-types.js';
5
6
 
6
- import { authenticate } from '../core/auth.js';
7
7
  import { EncryptionControl } from '../core/encryption-control.js';
8
8
  import { Message } from '../core/message.js';
9
9
  import { messageReplyFromError } from '../core/message-reply.js';
10
- import { ProtocolAuthorization } from '../core/protocol-authorization.js';
11
10
  import { Records } from '../utils/records.js';
12
11
  import { RecordsCount } from '../interfaces/records-count.js';
13
- import { RecordsGrantAuthorization } from '../core/records-grant-authorization.js';
12
+ import { buildRecordsSnapshotFilters, resolveRecordsCollectionVisibility } from './records-collection.js';
14
13
  import {
15
14
  countRecordsWithRecordLimitOccupancy,
16
15
  queryRecordsWithRecordLimitOccupancy,
17
16
  resolveRecordLimitOccupancy,
18
17
  } from '../utils/record-limit-occupancy.js';
19
- import { DwnInterfaceName, DwnMethodName } from '../enums/dwn-interface-method.js';
20
18
 
21
19
  export class RecordsCountHandler implements MethodHandler {
22
20
 
@@ -29,34 +27,29 @@ export class RecordsCountHandler implements MethodHandler {
29
27
  let recordsCount: RecordsCount;
30
28
  try {
31
29
  recordsCount = await RecordsCount.parse(message);
32
- } catch (e) {
33
- return messageReplyFromError(e, 400);
30
+ } catch (error) {
31
+ return messageReplyFromError(error, 400);
34
32
  }
35
33
 
36
- let count: number;
37
34
  const requester = Message.getRequester(recordsCount.message);
35
+ let visibility: RecordsCollectionVisibility;
36
+ try {
37
+ visibility = await resolveRecordsCollectionVisibility(tenant, recordsCount, this.deps);
38
+ } catch (error) {
39
+ return messageReplyFromError(error, 401);
40
+ }
38
41
 
39
- // if this is an anonymous count and the filter supports published records, count only published records
40
- if (Records.filterIncludesPublishedRecords(recordsCount.message.descriptor.filter) && recordsCount.author === undefined) {
41
- count = await this.countPublishedRecords(tenant, recordsCount, requester);
42
- } else {
43
- // authentication and authorization
44
- try {
45
- await authenticate(message.authorization!, this.deps.didResolver);
46
-
47
- await RecordsCountHandler.authorizeRecordsCount(tenant, recordsCount, this.deps);
48
- } catch (e) {
49
- return messageReplyFromError(e, 401);
50
- }
42
+ const filters = buildRecordsSnapshotFilters(recordsCount, visibility);
43
+ const recordLimit = await resolveRecordLimitOccupancy({
44
+ validationStateReader : this.deps.validationStateReader,
45
+ tenant,
46
+ recordsFilter : recordsCount.message.descriptor.filter,
47
+ messageTimestamp : recordsCount.message.descriptor.messageTimestamp,
48
+ });
51
49
 
52
- if (recordsCount.author === tenant && requester === tenant) {
53
- count = await this.countRecordsAsOwner(tenant, recordsCount);
54
- } else if (recordsCount.author === tenant) {
55
- count = await this.countRecordsAsOwnerDelegate(tenant, recordsCount, requester);
56
- } else {
57
- count = await this.countRecordsAsNonOwner(tenant, recordsCount, requester);
58
- }
59
- }
50
+ const count = recordsCount.author === tenant && requester === tenant
51
+ ? await this.countProjectedRecords(tenant, filters, recordLimit)
52
+ : await this.countProjectedRecordsForRequester(tenant, recordsCount, requester, filters, recordLimit);
60
53
 
61
54
  return {
62
55
  status: { code: 200, detail: 'OK' },
@@ -64,90 +57,6 @@ export class RecordsCountHandler implements MethodHandler {
64
57
  };
65
58
  }
66
59
 
67
- /**
68
- * Counts records as the owner of the DWN with no additional filtering.
69
- */
70
- private async countRecordsAsOwner(tenant: string, recordsCount: RecordsCount): Promise<number> {
71
- const { filter } = recordsCount.message.descriptor;
72
- const countFilter = {
73
- ...Records.convertFilter(filter),
74
- interface : DwnInterfaceName.Records,
75
- method : DwnMethodName.Write,
76
- isLatestBaseState : true
77
- };
78
-
79
- const recordLimit = await this.resolveRecordLimit(tenant, recordsCount);
80
- return this.countProjectedRecords(tenant, [countFilter], recordLimit);
81
- }
82
-
83
- private async countRecordsAsOwnerDelegate(
84
- tenant: string,
85
- recordsCount: RecordsCount,
86
- requester: string | undefined,
87
- ): Promise<number> {
88
- const { filter } = recordsCount.message.descriptor;
89
- const countFilter = {
90
- ...Records.convertFilter(filter),
91
- interface : DwnInterfaceName.Records,
92
- method : DwnMethodName.Write,
93
- isLatestBaseState : true
94
- };
95
-
96
- return this.countProjectedRecordsForRequester(tenant, recordsCount, requester, [countFilter]);
97
- }
98
-
99
- /**
100
- * Counts records as a non-owner, applying the same filter logic as RecordsQuery.
101
- */
102
- private async countRecordsAsNonOwner(
103
- tenant: string,
104
- recordsCount: RecordsCount,
105
- requester: string | undefined,
106
- ): Promise<number> {
107
- const { filter } = recordsCount.message.descriptor;
108
- const filters: Filter[] = [];
109
-
110
- if (Records.filterIncludesPublishedRecords(filter)) {
111
- filters.push(RecordsCountHandler.buildPublishedRecordsFilter(recordsCount));
112
- }
113
-
114
- if (Records.filterIncludesUnpublishedRecords(filter)) {
115
- if (EncryptionControl.isExactAudienceFilter(filter)) {
116
- filters.push(Records.buildUnpublishedControlRecordsFilter(filter));
117
- }
118
-
119
- if (Records.shouldBuildUnpublishedAuthorFilter(filter, recordsCount.author!)) {
120
- filters.push(RecordsCountHandler.buildUnpublishedRecordsByCountAuthorFilter(recordsCount));
121
- }
122
-
123
- if (Records.shouldProtocolAuthorize(recordsCount.signaturePayload!)) {
124
- filters.push(RecordsCountHandler.buildUnpublishedProtocolAuthorizedRecordsFilter(recordsCount));
125
- }
126
-
127
- if (Message.getPermissionGrantId(recordsCount.signaturePayload!) !== undefined) {
128
- filters.push(RecordsCountHandler.buildUnpublishedPermissionGrantAuthorizedRecordsFilter(recordsCount));
129
- }
130
-
131
- if (Records.shouldBuildUnpublishedRecipientFilter(filter, recordsCount.author!)) {
132
- filters.push(RecordsCountHandler.buildUnpublishedRecordsForCountAuthorFilter(recordsCount));
133
- }
134
- }
135
-
136
- return this.countProjectedRecordsForRequester(tenant, recordsCount, requester, filters);
137
- }
138
-
139
- /**
140
- * Counts only published records.
141
- */
142
- private async countPublishedRecords(
143
- tenant: string,
144
- recordsCount: RecordsCount,
145
- requester: string | undefined,
146
- ): Promise<number> {
147
- const filter = RecordsCountHandler.buildPublishedRecordsFilter(recordsCount);
148
- return this.countProjectedRecordsForRequester(tenant, recordsCount, requester, [filter]);
149
- }
150
-
151
60
  private async countProjectedRecords(
152
61
  tenant: string,
153
62
  filters: Filter[],
@@ -186,8 +95,8 @@ export class RecordsCountHandler implements MethodHandler {
186
95
  recordsCount: RecordsCount,
187
96
  requester: string | undefined,
188
97
  filters: Filter[],
98
+ recordLimit: RecordLimitOccupancy | undefined,
189
99
  ): Promise<number> {
190
- const recordLimit = await this.resolveRecordLimit(tenant, recordsCount);
191
100
  const controlFilters = Records.buildControlRecordsFilters(filters);
192
101
  if (controlFilters.length === 0) {
193
102
  return this.countProjectedRecords(tenant, filters, recordLimit);
@@ -220,128 +129,4 @@ export class RecordsCountHandler implements MethodHandler {
220
129
  });
221
130
  return totalCount - controlCount + visibleMessages.length;
222
131
  }
223
-
224
- private async resolveRecordLimit(
225
- tenant: string,
226
- recordsCount: RecordsCount,
227
- ): Promise<RecordLimitOccupancy | undefined> {
228
- return resolveRecordLimitOccupancy({
229
- validationStateReader : this.deps.validationStateReader,
230
- tenant,
231
- recordsFilter : recordsCount.message.descriptor.filter,
232
- messageTimestamp : recordsCount.message.descriptor.messageTimestamp,
233
- });
234
- }
235
-
236
- private static buildPublishedRecordsFilter(recordsCount: RecordsCount): Filter {
237
- const { filter } = recordsCount.message.descriptor;
238
- return {
239
- ...Records.convertFilter(filter),
240
- interface : DwnInterfaceName.Records,
241
- method : DwnMethodName.Write,
242
- published : true,
243
- isLatestBaseState : true
244
- };
245
- }
246
-
247
- /**
248
- * Creates a filter for unpublished records that are intended for the count author (where `recipient` is the author).
249
- */
250
- private static buildUnpublishedRecordsForCountAuthorFilter(recordsCount: RecordsCount): Filter {
251
- const { filter } = recordsCount.message.descriptor;
252
- return {
253
- ...Records.convertFilter(filter),
254
- interface : DwnInterfaceName.Records,
255
- method : DwnMethodName.Write,
256
- recipient : recordsCount.author!,
257
- isLatestBaseState : true,
258
- published : false
259
- };
260
- }
261
-
262
- /**
263
- * Creates a filter for unpublished records that are within the specified protocol.
264
- */
265
- private static buildUnpublishedProtocolAuthorizedRecordsFilter(recordsCount: RecordsCount): Filter {
266
- const { filter } = recordsCount.message.descriptor;
267
- return {
268
- ...Records.convertFilter(filter),
269
- interface : DwnInterfaceName.Records,
270
- method : DwnMethodName.Write,
271
- isLatestBaseState : true,
272
- published : false
273
- };
274
- }
275
-
276
- /**
277
- * Creates a filter for unpublished records authorized by a permission grant.
278
- */
279
- private static buildUnpublishedPermissionGrantAuthorizedRecordsFilter(recordsCount: RecordsCount): Filter {
280
- const { filter } = recordsCount.message.descriptor;
281
- return {
282
- ...Records.convertFilter(filter),
283
- interface : DwnInterfaceName.Records,
284
- method : DwnMethodName.Write,
285
- isLatestBaseState : true,
286
- published : false
287
- };
288
- }
289
-
290
- /**
291
- * Creates a filter for only unpublished records where the author is the same as the count author.
292
- */
293
- private static buildUnpublishedRecordsByCountAuthorFilter(recordsCount: RecordsCount): Filter {
294
- const { filter } = recordsCount.message.descriptor;
295
- return {
296
- ...Records.convertFilter(filter),
297
- author : recordsCount.author!,
298
- interface : DwnInterfaceName.Records,
299
- method : DwnMethodName.Write,
300
- isLatestBaseState : true,
301
- published : false
302
- };
303
- }
304
-
305
- /**
306
- * @param messageStore Used to check if the grant has been revoked.
307
- */
308
- private static async authorizeRecordsCount(
309
- tenant: string,
310
- recordsCount: RecordsCount,
311
- deps: HandlerDependencies,
312
- ): Promise<void> {
313
-
314
- if (Message.isSignedByAuthorDelegate(recordsCount.message) &&
315
- !EncryptionControl.filterTargetsOnlyControlRecords(recordsCount.message.descriptor.filter)) {
316
- await recordsCount.authorizeDelegate(deps.validationStateReader);
317
- } else if (EncryptionControl.filterTargetsOnlyControlRecords(recordsCount.message.descriptor.filter)) {
318
- await EncryptionControl.authorizeControlReadRequest({
319
- tenant,
320
- incomingMessage : recordsCount.message,
321
- requester : Message.getRequester(recordsCount.message),
322
- validationStateReader : deps.validationStateReader,
323
- });
324
- }
325
-
326
- const permissionGrantId = Message.getPermissionGrantId(recordsCount.signaturePayload!);
327
- if (permissionGrantId !== undefined) {
328
- const permissionGrant = await deps.validationStateReader.fetchGrant(tenant, permissionGrantId);
329
- await RecordsGrantAuthorization.authorizeQueryOrSubscribe({
330
- incomingMessage : recordsCount.message,
331
- expectedGrantor : tenant,
332
- expectedGrantee : recordsCount.author!,
333
- permissionGrant,
334
- validationStateReader : deps.validationStateReader,
335
- });
336
- return;
337
- }
338
-
339
- // NOTE: not all RecordsCount messages require protocol authorization even if the filter includes protocol-related fields,
340
- // this is because we dynamically filter out records that the caller is not authorized to see.
341
- // Currently only run protocol authorization if message deliberately invokes a protocol role.
342
- if (Records.shouldProtocolAuthorize(recordsCount.signaturePayload!)) {
343
- await ProtocolAuthorization.authorizeQueryOrSubscribe(tenant, recordsCount, deps.validationStateReader);
344
- }
345
- }
346
-
347
132
  }