@enbox/dwn-sdk-js 0.1.0 → 0.1.2

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 (139) hide show
  1. package/LICENSE +3 -2
  2. package/dist/browser.mjs +6 -6
  3. package/dist/browser.mjs.map +3 -3
  4. package/dist/esm/src/dwn.js +19 -5
  5. package/dist/esm/src/dwn.js.map +1 -1
  6. package/dist/esm/src/handlers/records-read.js +5 -1
  7. package/dist/esm/src/handlers/records-read.js.map +1 -1
  8. package/dist/esm/src/utils/protocols.js +2 -2
  9. package/dist/esm/src/utils/protocols.js.map +1 -1
  10. package/dist/esm/tests/fuzz/arbitraries/dwn-message.arbitrary.js +72 -0
  11. package/dist/esm/tests/fuzz/arbitraries/dwn-message.arbitrary.js.map +1 -0
  12. package/dist/esm/tests/fuzz/arbitraries/filter.arbitrary.js +53 -0
  13. package/dist/esm/tests/fuzz/arbitraries/filter.arbitrary.js.map +1 -0
  14. package/dist/esm/tests/fuzz/arbitraries/jws.arbitrary.js +55 -0
  15. package/dist/esm/tests/fuzz/arbitraries/jws.arbitrary.js.map +1 -0
  16. package/dist/esm/tests/fuzz/arbitraries/protocol-definition.arbitrary.js +106 -0
  17. package/dist/esm/tests/fuzz/arbitraries/protocol-definition.arbitrary.js.map +1 -0
  18. package/dist/esm/tests/fuzz/arbitraries/store.arbitrary.js +139 -0
  19. package/dist/esm/tests/fuzz/arbitraries/store.arbitrary.js.map +1 -0
  20. package/dist/esm/tests/fuzz/cid.fuzz.spec.js +74 -0
  21. package/dist/esm/tests/fuzz/cid.fuzz.spec.js.map +1 -0
  22. package/dist/esm/tests/fuzz/compound-index.fuzz.spec.js +203 -0
  23. package/dist/esm/tests/fuzz/compound-index.fuzz.spec.js.map +1 -0
  24. package/dist/esm/tests/fuzz/data-store.fuzz.spec.js +146 -0
  25. package/dist/esm/tests/fuzz/data-store.fuzz.spec.js.map +1 -0
  26. package/dist/esm/tests/fuzz/data-stream.fuzz.spec.js +44 -0
  27. package/dist/esm/tests/fuzz/data-stream.fuzz.spec.js.map +1 -0
  28. package/dist/esm/tests/fuzz/encoder.fuzz.spec.js +76 -0
  29. package/dist/esm/tests/fuzz/encoder.fuzz.spec.js.map +1 -0
  30. package/dist/esm/tests/fuzz/encryption.fuzz.spec.js +132 -0
  31. package/dist/esm/tests/fuzz/encryption.fuzz.spec.js.map +1 -0
  32. package/dist/esm/tests/fuzz/filter.fuzz.spec.js +149 -0
  33. package/dist/esm/tests/fuzz/filter.fuzz.spec.js.map +1 -0
  34. package/dist/esm/tests/fuzz/get-rule-set-at-path.fuzz.spec.js +82 -0
  35. package/dist/esm/tests/fuzz/get-rule-set-at-path.fuzz.spec.js.map +1 -0
  36. package/dist/esm/tests/fuzz/hd-key.fuzz.spec.js +77 -0
  37. package/dist/esm/tests/fuzz/hd-key.fuzz.spec.js.map +1 -0
  38. package/dist/esm/tests/fuzz/immutable-properties.fuzz.spec.js +86 -0
  39. package/dist/esm/tests/fuzz/immutable-properties.fuzz.spec.js.map +1 -0
  40. package/dist/esm/tests/fuzz/index-level.fuzz.spec.js +195 -0
  41. package/dist/esm/tests/fuzz/index-level.fuzz.spec.js.map +1 -0
  42. package/dist/esm/tests/fuzz/jws.fuzz.spec.js +100 -0
  43. package/dist/esm/tests/fuzz/jws.fuzz.spec.js.map +1 -0
  44. package/dist/esm/tests/fuzz/message-store.fuzz.spec.js +154 -0
  45. package/dist/esm/tests/fuzz/message-store.fuzz.spec.js.map +1 -0
  46. package/dist/esm/tests/fuzz/object.fuzz.spec.js +82 -0
  47. package/dist/esm/tests/fuzz/object.fuzz.spec.js.map +1 -0
  48. package/dist/esm/tests/fuzz/process-message.fuzz.spec.js +85 -0
  49. package/dist/esm/tests/fuzz/process-message.fuzz.spec.js.map +1 -0
  50. package/dist/esm/tests/fuzz/protocol-definition.fuzz.spec.js +145 -0
  51. package/dist/esm/tests/fuzz/protocol-definition.fuzz.spec.js.map +1 -0
  52. package/dist/esm/tests/fuzz/protocol-validation.fuzz.spec.js +146 -0
  53. package/dist/esm/tests/fuzz/protocol-validation.fuzz.spec.js.map +1 -0
  54. package/dist/esm/tests/fuzz/protocols-utils.fuzz.spec.js +41 -0
  55. package/dist/esm/tests/fuzz/protocols-utils.fuzz.spec.js.map +1 -0
  56. package/dist/esm/tests/fuzz/records-utils.fuzz.spec.js +81 -0
  57. package/dist/esm/tests/fuzz/records-utils.fuzz.spec.js.map +1 -0
  58. package/dist/esm/tests/fuzz/resumable-task-store.fuzz.spec.js +106 -0
  59. package/dist/esm/tests/fuzz/resumable-task-store.fuzz.spec.js.map +1 -0
  60. package/dist/esm/tests/fuzz/schema-validation.fuzz.spec.js +126 -0
  61. package/dist/esm/tests/fuzz/schema-validation.fuzz.spec.js.map +1 -0
  62. package/dist/esm/tests/fuzz/secp256k1.fuzz.spec.js +74 -0
  63. package/dist/esm/tests/fuzz/secp256k1.fuzz.spec.js.map +1 -0
  64. package/dist/esm/tests/fuzz/secp256r1.fuzz.spec.js +60 -0
  65. package/dist/esm/tests/fuzz/secp256r1.fuzz.spec.js.map +1 -0
  66. package/dist/esm/tests/fuzz/time.fuzz.spec.js +82 -0
  67. package/dist/esm/tests/fuzz/time.fuzz.spec.js.map +1 -0
  68. package/dist/esm/tests/fuzz/url.fuzz.spec.js +118 -0
  69. package/dist/esm/tests/fuzz/url.fuzz.spec.js.map +1 -0
  70. package/dist/esm/tests/handlers/records-read.spec.js +6 -2
  71. package/dist/esm/tests/handlers/records-read.spec.js.map +1 -1
  72. package/dist/types/src/dwn.d.ts +9 -0
  73. package/dist/types/src/dwn.d.ts.map +1 -1
  74. package/dist/types/src/handlers/records-read.d.ts.map +1 -1
  75. package/dist/types/tests/fuzz/arbitraries/dwn-message.arbitrary.d.ts +31 -0
  76. package/dist/types/tests/fuzz/arbitraries/dwn-message.arbitrary.d.ts.map +1 -0
  77. package/dist/types/tests/fuzz/arbitraries/filter.arbitrary.d.ts +27 -0
  78. package/dist/types/tests/fuzz/arbitraries/filter.arbitrary.d.ts.map +1 -0
  79. package/dist/types/tests/fuzz/arbitraries/jws.arbitrary.d.ts +26 -0
  80. package/dist/types/tests/fuzz/arbitraries/jws.arbitrary.d.ts.map +1 -0
  81. package/dist/types/tests/fuzz/arbitraries/protocol-definition.arbitrary.d.ts +31 -0
  82. package/dist/types/tests/fuzz/arbitraries/protocol-definition.arbitrary.d.ts.map +1 -0
  83. package/dist/types/tests/fuzz/arbitraries/store.arbitrary.d.ts +71 -0
  84. package/dist/types/tests/fuzz/arbitraries/store.arbitrary.d.ts.map +1 -0
  85. package/dist/types/tests/fuzz/cid.fuzz.spec.d.ts +2 -0
  86. package/dist/types/tests/fuzz/cid.fuzz.spec.d.ts.map +1 -0
  87. package/dist/types/tests/fuzz/compound-index.fuzz.spec.d.ts +2 -0
  88. package/dist/types/tests/fuzz/compound-index.fuzz.spec.d.ts.map +1 -0
  89. package/dist/types/tests/fuzz/data-store.fuzz.spec.d.ts +2 -0
  90. package/dist/types/tests/fuzz/data-store.fuzz.spec.d.ts.map +1 -0
  91. package/dist/types/tests/fuzz/data-stream.fuzz.spec.d.ts +2 -0
  92. package/dist/types/tests/fuzz/data-stream.fuzz.spec.d.ts.map +1 -0
  93. package/dist/types/tests/fuzz/encoder.fuzz.spec.d.ts +2 -0
  94. package/dist/types/tests/fuzz/encoder.fuzz.spec.d.ts.map +1 -0
  95. package/dist/types/tests/fuzz/encryption.fuzz.spec.d.ts +2 -0
  96. package/dist/types/tests/fuzz/encryption.fuzz.spec.d.ts.map +1 -0
  97. package/dist/types/tests/fuzz/filter.fuzz.spec.d.ts +2 -0
  98. package/dist/types/tests/fuzz/filter.fuzz.spec.d.ts.map +1 -0
  99. package/dist/types/tests/fuzz/get-rule-set-at-path.fuzz.spec.d.ts +2 -0
  100. package/dist/types/tests/fuzz/get-rule-set-at-path.fuzz.spec.d.ts.map +1 -0
  101. package/dist/types/tests/fuzz/hd-key.fuzz.spec.d.ts +2 -0
  102. package/dist/types/tests/fuzz/hd-key.fuzz.spec.d.ts.map +1 -0
  103. package/dist/types/tests/fuzz/immutable-properties.fuzz.spec.d.ts +2 -0
  104. package/dist/types/tests/fuzz/immutable-properties.fuzz.spec.d.ts.map +1 -0
  105. package/dist/types/tests/fuzz/index-level.fuzz.spec.d.ts +2 -0
  106. package/dist/types/tests/fuzz/index-level.fuzz.spec.d.ts.map +1 -0
  107. package/dist/types/tests/fuzz/jws.fuzz.spec.d.ts +2 -0
  108. package/dist/types/tests/fuzz/jws.fuzz.spec.d.ts.map +1 -0
  109. package/dist/types/tests/fuzz/message-store.fuzz.spec.d.ts +2 -0
  110. package/dist/types/tests/fuzz/message-store.fuzz.spec.d.ts.map +1 -0
  111. package/dist/types/tests/fuzz/object.fuzz.spec.d.ts +2 -0
  112. package/dist/types/tests/fuzz/object.fuzz.spec.d.ts.map +1 -0
  113. package/dist/types/tests/fuzz/process-message.fuzz.spec.d.ts +2 -0
  114. package/dist/types/tests/fuzz/process-message.fuzz.spec.d.ts.map +1 -0
  115. package/dist/types/tests/fuzz/protocol-definition.fuzz.spec.d.ts +2 -0
  116. package/dist/types/tests/fuzz/protocol-definition.fuzz.spec.d.ts.map +1 -0
  117. package/dist/types/tests/fuzz/protocol-validation.fuzz.spec.d.ts +2 -0
  118. package/dist/types/tests/fuzz/protocol-validation.fuzz.spec.d.ts.map +1 -0
  119. package/dist/types/tests/fuzz/protocols-utils.fuzz.spec.d.ts +2 -0
  120. package/dist/types/tests/fuzz/protocols-utils.fuzz.spec.d.ts.map +1 -0
  121. package/dist/types/tests/fuzz/records-utils.fuzz.spec.d.ts +2 -0
  122. package/dist/types/tests/fuzz/records-utils.fuzz.spec.d.ts.map +1 -0
  123. package/dist/types/tests/fuzz/resumable-task-store.fuzz.spec.d.ts +2 -0
  124. package/dist/types/tests/fuzz/resumable-task-store.fuzz.spec.d.ts.map +1 -0
  125. package/dist/types/tests/fuzz/schema-validation.fuzz.spec.d.ts +2 -0
  126. package/dist/types/tests/fuzz/schema-validation.fuzz.spec.d.ts.map +1 -0
  127. package/dist/types/tests/fuzz/secp256k1.fuzz.spec.d.ts +2 -0
  128. package/dist/types/tests/fuzz/secp256k1.fuzz.spec.d.ts.map +1 -0
  129. package/dist/types/tests/fuzz/secp256r1.fuzz.spec.d.ts +2 -0
  130. package/dist/types/tests/fuzz/secp256r1.fuzz.spec.d.ts.map +1 -0
  131. package/dist/types/tests/fuzz/time.fuzz.spec.d.ts +2 -0
  132. package/dist/types/tests/fuzz/time.fuzz.spec.d.ts.map +1 -0
  133. package/dist/types/tests/fuzz/url.fuzz.spec.d.ts +2 -0
  134. package/dist/types/tests/fuzz/url.fuzz.spec.d.ts.map +1 -0
  135. package/dist/types/tests/handlers/records-read.spec.d.ts.map +1 -1
  136. package/package.json +8 -5
  137. package/src/dwn.ts +30 -5
  138. package/src/handlers/records-read.ts +5 -1
  139. package/src/utils/protocols.ts +2 -2
@@ -0,0 +1,195 @@
1
+ import { afterAll, afterEach, beforeAll, describe, expect, it } from 'bun:test';
2
+ import fc from 'fast-check';
3
+ import { IndexLevel } from '../../src/store/index-level.js';
4
+ import { SortDirection } from '../../src/types/query-types.js';
5
+ import { indexedItemSet, indexKeyValues, messageCid } from './arbitraries/store.arbitrary.js';
6
+ const numRuns = Number(process.env.FAST_CHECK_NUM_RUNS) || 100;
7
+ describe('IndexLevel — fuzz', () => {
8
+ let indexLevel;
9
+ const testDataPath = '__TESTDATA__/fuzz-index-level';
10
+ const tenant = 'did:example:fuzz-tenant';
11
+ beforeAll(async () => {
12
+ indexLevel = new IndexLevel({ location: `${testDataPath}/index` });
13
+ await indexLevel.open();
14
+ });
15
+ afterEach(async () => {
16
+ await indexLevel.clear();
17
+ });
18
+ afterAll(async () => {
19
+ await indexLevel.close();
20
+ });
21
+ describe('encodeNumberValue — order preservation', () => {
22
+ it('should preserve order for any two integers: a < b implies encode(a) < encode(b)', () => {
23
+ fc.assert(fc.property(fc.integer({ min: Number.MIN_SAFE_INTEGER, max: Number.MAX_SAFE_INTEGER }), fc.integer({ min: Number.MIN_SAFE_INTEGER, max: Number.MAX_SAFE_INTEGER }), (a, b) => {
24
+ const encodedA = IndexLevel.encodeNumberValue(a);
25
+ const encodedB = IndexLevel.encodeNumberValue(b);
26
+ if (a < b) {
27
+ expect(encodedA < encodedB).toBe(true);
28
+ }
29
+ else if (a > b) {
30
+ expect(encodedA > encodedB).toBe(true);
31
+ }
32
+ else {
33
+ expect(encodedA).toBe(encodedB);
34
+ }
35
+ }), { numRuns });
36
+ });
37
+ it('should produce consistent results for the same input', () => {
38
+ fc.assert(fc.property(fc.integer({ min: Number.MIN_SAFE_INTEGER, max: Number.MAX_SAFE_INTEGER }), (n) => {
39
+ expect(IndexLevel.encodeNumberValue(n)).toBe(IndexLevel.encodeNumberValue(n));
40
+ }), { numRuns });
41
+ });
42
+ });
43
+ describe('encodeValue — type consistency', () => {
44
+ it('should return a string for any supported value type', () => {
45
+ fc.assert(fc.property(fc.oneof(fc.string({ minLength: 0, maxLength: 50 }), fc.integer({ min: -10000, max: 10000 }), fc.boolean()), (value) => {
46
+ const encoded = IndexLevel.encodeValue(value);
47
+ expect(typeof encoded).toBe('string');
48
+ expect(encoded.length).toBeGreaterThan(0);
49
+ }), { numRuns });
50
+ });
51
+ });
52
+ describe('put/query roundtrip', () => {
53
+ it('should find an item by any of its indexed properties after put', async () => {
54
+ await fc.assert(fc.asyncProperty(messageCid(), indexKeyValues(), async (cid, indexes) => {
55
+ await indexLevel.clear();
56
+ await indexLevel.put(tenant, cid, indexes);
57
+ // Query using the first string/number property as an equality filter
58
+ for (const [key, value] of Object.entries(indexes)) {
59
+ if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') {
60
+ const results = await indexLevel.query(tenant, [{ [key]: value }], {
61
+ sortProperty: 'messageTimestamp',
62
+ sortDirection: SortDirection.Ascending,
63
+ });
64
+ const foundCids = results.map((r) => r.messageCid);
65
+ expect(foundCids).toContain(cid);
66
+ break; // one property is enough to verify the roundtrip
67
+ }
68
+ }
69
+ }), { numRuns: Math.min(numRuns, 50) });
70
+ });
71
+ });
72
+ describe('put/delete roundtrip', () => {
73
+ it('should not find an item after deletion', async () => {
74
+ await fc.assert(fc.asyncProperty(messageCid(), indexKeyValues(), async (cid, indexes) => {
75
+ await indexLevel.clear();
76
+ await indexLevel.put(tenant, cid, indexes);
77
+ await indexLevel.delete(tenant, cid);
78
+ // Query with empty filter should return nothing
79
+ const results = await indexLevel.query(tenant, [{}], {
80
+ sortProperty: 'messageTimestamp',
81
+ sortDirection: SortDirection.Ascending,
82
+ });
83
+ const foundCids = results.map((r) => r.messageCid);
84
+ expect(foundCids).not.toContain(cid);
85
+ }), { numRuns: Math.min(numRuns, 50) });
86
+ });
87
+ });
88
+ describe('count equals query length', () => {
89
+ it('should return the same count as query results length for any filter', async () => {
90
+ await fc.assert(fc.asyncProperty(indexedItemSet({ minSize: 3, maxSize: 10 }), async (items) => {
91
+ await indexLevel.clear();
92
+ for (const item of items) {
93
+ await indexLevel.put(tenant, item.cid, item.indexes);
94
+ }
95
+ const queryOptions = {
96
+ sortProperty: 'messageTimestamp',
97
+ sortDirection: SortDirection.Ascending,
98
+ };
99
+ // Count with empty filter
100
+ const count = await indexLevel.count(tenant, [{}], queryOptions);
101
+ const results = await indexLevel.query(tenant, [{}], queryOptions);
102
+ expect(count).toBe(results.length);
103
+ }), { numRuns: Math.min(numRuns, 30) });
104
+ });
105
+ });
106
+ describe('sort ordering invariant', () => {
107
+ it('should return results sorted by messageTimestamp ascending', async () => {
108
+ await fc.assert(fc.asyncProperty(indexedItemSet({ minSize: 3, maxSize: 15 }), async (items) => {
109
+ await indexLevel.clear();
110
+ for (const item of items) {
111
+ await indexLevel.put(tenant, item.cid, item.indexes);
112
+ }
113
+ const results = await indexLevel.query(tenant, [{}], {
114
+ sortProperty: 'messageTimestamp',
115
+ sortDirection: SortDirection.Ascending,
116
+ });
117
+ for (let i = 1; i < results.length; i++) {
118
+ const prev = IndexLevel.encodeValue(results[i - 1].indexes.messageTimestamp);
119
+ const curr = IndexLevel.encodeValue(results[i].indexes.messageTimestamp);
120
+ // When timestamps are equal, the messageCid acts as tiebreaker
121
+ if (prev === curr) {
122
+ expect(results[i - 1].messageCid <= results[i].messageCid).toBe(true);
123
+ }
124
+ else {
125
+ expect(prev <= curr).toBe(true);
126
+ }
127
+ }
128
+ }), { numRuns: Math.min(numRuns, 30) });
129
+ });
130
+ it('should return results sorted by messageTimestamp descending', async () => {
131
+ await fc.assert(fc.asyncProperty(indexedItemSet({ minSize: 3, maxSize: 15 }), async (items) => {
132
+ await indexLevel.clear();
133
+ for (const item of items) {
134
+ await indexLevel.put(tenant, item.cid, item.indexes);
135
+ }
136
+ const results = await indexLevel.query(tenant, [{}], {
137
+ sortProperty: 'messageTimestamp',
138
+ sortDirection: SortDirection.Descending,
139
+ });
140
+ for (let i = 1; i < results.length; i++) {
141
+ const prev = IndexLevel.encodeValue(results[i - 1].indexes.messageTimestamp);
142
+ const curr = IndexLevel.encodeValue(results[i].indexes.messageTimestamp);
143
+ if (prev === curr) {
144
+ expect(results[i - 1].messageCid >= results[i].messageCid).toBe(true);
145
+ }
146
+ else {
147
+ expect(prev >= curr).toBe(true);
148
+ }
149
+ }
150
+ }), { numRuns: Math.min(numRuns, 30) });
151
+ });
152
+ });
153
+ describe('pagination completeness', () => {
154
+ it('should yield all items when paginating with any page size', async () => {
155
+ await fc.assert(fc.asyncProperty(indexedItemSet({ minSize: 3, maxSize: 12 }), fc.integer({ min: 1, max: 5 }), async (items, pageSize) => {
156
+ await indexLevel.clear();
157
+ for (const item of items) {
158
+ await indexLevel.put(tenant, item.cid, item.indexes);
159
+ }
160
+ const sortProperty = 'messageTimestamp';
161
+ const queryOptions = {
162
+ sortProperty,
163
+ sortDirection: SortDirection.Ascending,
164
+ limit: pageSize,
165
+ };
166
+ // Get all results without pagination for reference
167
+ const allResults = await indexLevel.query(tenant, [{}], {
168
+ sortProperty,
169
+ sortDirection: SortDirection.Ascending,
170
+ });
171
+ // Paginate through all results
172
+ const paginatedResults = [];
173
+ let cursor = undefined;
174
+ let iterations = 0;
175
+ const maxIterations = allResults.length + 5; // safety bound
176
+ while (iterations < maxIterations) {
177
+ const page = await indexLevel.query(tenant, [{}], { ...queryOptions, cursor });
178
+ if (page.length === 0) {
179
+ break;
180
+ }
181
+ paginatedResults.push(...page.map((r) => r.messageCid));
182
+ // Create cursor from last item for next page
183
+ if (page.length < pageSize) {
184
+ break; // last page
185
+ }
186
+ cursor = IndexLevel.createCursorFromLastArrayItem(page, sortProperty);
187
+ iterations++;
188
+ }
189
+ // All CIDs from pagination should match all CIDs from full query
190
+ expect(paginatedResults).toEqual(allResults.map((r) => r.messageCid));
191
+ }), { numRuns: Math.min(numRuns, 20) });
192
+ });
193
+ });
194
+ });
195
+ //# sourceMappingURL=index-level.fuzz.spec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index-level.fuzz.spec.js","sourceRoot":"","sources":["../../../../tests/fuzz/index-level.fuzz.spec.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,100 @@
1
+ import { describe, expect, it } from 'bun:test';
2
+ import fc from 'fast-check';
3
+ import { DwnError } from '../../src/core/dwn-error.js';
4
+ import { Encoder } from '../../src/utils/encoder.js';
5
+ import { Jws } from '../../src/utils/jws.js';
6
+ import { generalJws, malformedJws } from './arbitraries/jws.arbitrary.js';
7
+ const numRuns = Number(process.env.FAST_CHECK_NUM_RUNS) || 200;
8
+ describe('Jws — fuzz', () => {
9
+ describe('decodePlainObjectPayload — crash resistance with random JWS', () => {
10
+ it('should throw DwnError on malformed JWS payloads, never an unhandled error', () => {
11
+ fc.assert(fc.property(generalJws(), (jws) => {
12
+ try {
13
+ Jws.decodePlainObjectPayload(jws);
14
+ // If it succeeds, the decoded value should be a plain object
15
+ }
16
+ catch (error) {
17
+ expect(error).toBeInstanceOf(DwnError);
18
+ }
19
+ }), { numRuns });
20
+ });
21
+ });
22
+ describe('decodePlainObjectPayload — crash resistance with malformed JWS', () => {
23
+ it('should handle completely malformed JWS-like structures', () => {
24
+ fc.assert(fc.property(malformedJws(), (jws) => {
25
+ try {
26
+ Jws.decodePlainObjectPayload(jws);
27
+ }
28
+ catch (error) {
29
+ // Any error is acceptable — verify no unhandled crash
30
+ expect(error).toBeDefined();
31
+ }
32
+ }), { numRuns });
33
+ });
34
+ });
35
+ describe('decodePlainObjectPayload — roundtrip with valid encoded objects', () => {
36
+ it('should decode a payload that was properly base64url-encoded from a plain object', () => {
37
+ fc.assert(fc.property(fc.dictionary(fc.string({ minLength: 1, maxLength: 20 }), fc.oneof(fc.string(), fc.integer(), fc.boolean(), fc.constant(null)), { minKeys: 1, maxKeys: 5 }), (obj) => {
38
+ const payload = Encoder.stringToBase64Url(JSON.stringify(obj));
39
+ const jws = { payload, signatures: [] };
40
+ const decoded = Jws.decodePlainObjectPayload(jws);
41
+ expect(decoded).toEqual(obj);
42
+ }), { numRuns });
43
+ });
44
+ });
45
+ describe('decodePlainObjectPayload — rejects non-object payloads', () => {
46
+ it('should throw DwnError when the decoded payload is not a plain object', () => {
47
+ fc.assert(fc.property(fc.oneof(fc.string(), fc.integer(), fc.boolean(), fc.constant(null), fc.array(fc.integer())), (value) => {
48
+ const payload = Encoder.stringToBase64Url(JSON.stringify(value));
49
+ const jws = { payload, signatures: [] };
50
+ try {
51
+ Jws.decodePlainObjectPayload(jws);
52
+ // Arrays might pass isPlainObject, strings/numbers/booleans/null should not
53
+ if (typeof value !== 'object' || value === null || Array.isArray(value)) {
54
+ expect(true).toBe(false); // should have thrown
55
+ }
56
+ }
57
+ catch (error) {
58
+ expect(error).toBeInstanceOf(DwnError);
59
+ }
60
+ }), { numRuns });
61
+ });
62
+ });
63
+ describe('getKid — crash resistance', () => {
64
+ it('should handle signature entries with random protected headers', () => {
65
+ fc.assert(fc.property(fc.string({ minLength: 1, maxLength: 100 }), (protectedHeader) => {
66
+ try {
67
+ Jws.getKid({ protected: protectedHeader, signature: 'dummysig' });
68
+ }
69
+ catch {
70
+ // Any error is acceptable — we verify no unhandled crash
71
+ }
72
+ }), { numRuns });
73
+ });
74
+ });
75
+ describe('getKid — roundtrip with valid protected headers', () => {
76
+ it('should extract kid from a properly encoded protected header', () => {
77
+ fc.assert(fc.property(fc.string({ minLength: 1, maxLength: 50 }), (kid) => {
78
+ const protectedHeader = Encoder.stringToBase64Url(JSON.stringify({ kid }));
79
+ const extracted = Jws.getKid({ protected: protectedHeader, signature: 'dummysig' });
80
+ expect(extracted).toBe(kid);
81
+ }), { numRuns });
82
+ });
83
+ });
84
+ describe('extractDid — property', () => {
85
+ it('should extract the part before # from a kid string', () => {
86
+ fc.assert(fc.property(fc.string({ minLength: 1, maxLength: 50 }).filter((s) => !s.includes('#')), fc.string({ minLength: 1, maxLength: 20 }), (did, fragment) => {
87
+ const kid = `${did}#${fragment}`;
88
+ const extracted = Jws.extractDid(kid);
89
+ expect(extracted).toBe(did);
90
+ }), { numRuns });
91
+ });
92
+ it('should return the full string if there is no # separator', () => {
93
+ fc.assert(fc.property(fc.string({ minLength: 1, maxLength: 50 }).filter((s) => !s.includes('#')), (kid) => {
94
+ const extracted = Jws.extractDid(kid);
95
+ expect(extracted).toBe(kid);
96
+ }), { numRuns });
97
+ });
98
+ });
99
+ });
100
+ //# sourceMappingURL=jws.fuzz.spec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jws.fuzz.spec.js","sourceRoot":"","sources":["../../../../tests/fuzz/jws.fuzz.spec.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,154 @@
1
+ import { afterAll, afterEach, beforeAll, describe, expect, it } from 'bun:test';
2
+ import fc from 'fast-check';
3
+ import { Message } from '../../src/core/message.js';
4
+ import { MessageStoreLevel } from '../../src/store/message-store-level.js';
5
+ import { SortDirection } from '../../src/types/query-types.js';
6
+ import { genericMessage, genericMessageSet, indexKeyValues, tenantDid } from './arbitraries/store.arbitrary.js';
7
+ const numRuns = Number(process.env.FAST_CHECK_NUM_RUNS) || 100;
8
+ describe('MessageStoreLevel — fuzz', () => {
9
+ let messageStore;
10
+ const testDataPath = '__TESTDATA__/fuzz-message-store';
11
+ const tenant = 'did:example:fuzz-message-tenant';
12
+ beforeAll(async () => {
13
+ messageStore = new MessageStoreLevel({
14
+ blockstoreLocation: `${testDataPath}/blocks`,
15
+ indexLocation: `${testDataPath}/index`,
16
+ });
17
+ await messageStore.open();
18
+ });
19
+ afterEach(async () => {
20
+ await messageStore.clear();
21
+ });
22
+ afterAll(async () => {
23
+ await messageStore.close();
24
+ });
25
+ describe('put/get CID roundtrip', () => {
26
+ it('should store and retrieve any message by its computed CID', async () => {
27
+ await fc.assert(fc.asyncProperty(genericMessage(), indexKeyValues(), async (message, indexes) => {
28
+ await messageStore.clear();
29
+ // Ensure indexes include the message's own timestamp
30
+ indexes.messageTimestamp = message.descriptor.messageTimestamp;
31
+ await messageStore.put(tenant, message, indexes);
32
+ const cid = await Message.getCid(message);
33
+ const retrieved = await messageStore.get(tenant, cid);
34
+ expect(retrieved).toBeDefined();
35
+ expect(retrieved.descriptor.interface).toBe(message.descriptor.interface);
36
+ expect(retrieved.descriptor.method).toBe(message.descriptor.method);
37
+ expect(retrieved.descriptor.messageTimestamp).toBe(message.descriptor.messageTimestamp);
38
+ // The retrieved CID should match the original
39
+ const retrievedCid = await Message.getCid(retrieved);
40
+ expect(retrievedCid).toBe(cid);
41
+ }), { numRuns: Math.min(numRuns, 30) });
42
+ });
43
+ });
44
+ describe('get returns undefined for missing CID', () => {
45
+ it('should return undefined for a CID that was never stored', async () => {
46
+ await fc.assert(fc.asyncProperty(genericMessage(), async (message) => {
47
+ // Don't store the message — just compute its CID
48
+ const cid = await Message.getCid(message);
49
+ const retrieved = await messageStore.get(tenant, cid);
50
+ expect(retrieved).toBeUndefined();
51
+ }), { numRuns: Math.min(numRuns, 30) });
52
+ });
53
+ });
54
+ describe('put/delete roundtrip', () => {
55
+ it('should return undefined after deleting a message', async () => {
56
+ await fc.assert(fc.asyncProperty(genericMessage(), indexKeyValues(), async (message, indexes) => {
57
+ await messageStore.clear();
58
+ indexes.messageTimestamp = message.descriptor.messageTimestamp;
59
+ await messageStore.put(tenant, message, indexes);
60
+ const cid = await Message.getCid(message);
61
+ await messageStore.delete(tenant, cid);
62
+ const retrieved = await messageStore.get(tenant, cid);
63
+ expect(retrieved).toBeUndefined();
64
+ }), { numRuns: Math.min(numRuns, 30) });
65
+ });
66
+ });
67
+ describe('tenant isolation', () => {
68
+ it('should not allow one tenant to read another tenant\'s messages', async () => {
69
+ await fc.assert(fc.asyncProperty(tenantDid(), tenantDid(), genericMessage(), indexKeyValues(), async (tenant1, tenant2, message, indexes) => {
70
+ if (tenant1 === tenant2) {
71
+ return;
72
+ }
73
+ await messageStore.clear();
74
+ indexes.messageTimestamp = message.descriptor.messageTimestamp;
75
+ await messageStore.put(tenant1, message, indexes);
76
+ const cid = await Message.getCid(message);
77
+ const retrieved = await messageStore.get(tenant2, cid);
78
+ expect(retrieved).toBeUndefined();
79
+ }), { numRuns: Math.min(numRuns, 20) });
80
+ });
81
+ });
82
+ describe('count consistency', () => {
83
+ it('should return the same count as query results length', async () => {
84
+ await fc.assert(fc.asyncProperty(genericMessageSet({ minSize: 2, maxSize: 8 }), async (items) => {
85
+ await messageStore.clear();
86
+ for (const { message, indexes } of items) {
87
+ indexes.messageTimestamp = message.descriptor.messageTimestamp;
88
+ await messageStore.put(tenant, message, indexes);
89
+ }
90
+ const messageSort = { messageTimestamp: SortDirection.Ascending };
91
+ const count = await messageStore.count(tenant, [{}], messageSort);
92
+ const { messages } = await messageStore.query(tenant, [{}], messageSort);
93
+ expect(count).toBe(messages.length);
94
+ }), { numRuns: Math.min(numRuns, 15) });
95
+ });
96
+ });
97
+ describe('pagination completeness', () => {
98
+ it('should yield all messages when paginating with any page size', async () => {
99
+ await fc.assert(fc.asyncProperty(genericMessageSet({ minSize: 3, maxSize: 8 }), fc.integer({ min: 1, max: 4 }), async (items, pageSize) => {
100
+ await messageStore.clear();
101
+ for (const { message, indexes } of items) {
102
+ indexes.messageTimestamp = message.descriptor.messageTimestamp;
103
+ await messageStore.put(tenant, message, indexes);
104
+ }
105
+ const messageSort = { messageTimestamp: SortDirection.Ascending };
106
+ // Get all results without pagination for reference
107
+ const { messages: allMessages } = await messageStore.query(tenant, [{}], messageSort);
108
+ // Paginate through all results
109
+ const paginatedCids = [];
110
+ let cursor = undefined;
111
+ let iterations = 0;
112
+ const maxIterations = allMessages.length + 5; // safety bound
113
+ while (iterations < maxIterations) {
114
+ const { messages: page, cursor: nextCursor } = await messageStore.query(tenant, [{}], messageSort, { limit: pageSize, cursor });
115
+ if (page.length === 0) {
116
+ break;
117
+ }
118
+ for (const msg of page) {
119
+ paginatedCids.push(await Message.getCid(msg));
120
+ }
121
+ if (!nextCursor) {
122
+ break;
123
+ }
124
+ cursor = nextCursor;
125
+ iterations++;
126
+ }
127
+ // All CIDs from pagination should match all CIDs from full query
128
+ const allCids = [];
129
+ for (const msg of allMessages) {
130
+ allCids.push(await Message.getCid(msg));
131
+ }
132
+ expect(paginatedCids).toEqual(allCids);
133
+ }), { numRuns: Math.min(numRuns, 10) });
134
+ });
135
+ });
136
+ describe('idempotent put', () => {
137
+ it('should allow putting the same message twice without error', async () => {
138
+ await fc.assert(fc.asyncProperty(genericMessage(), indexKeyValues(), async (message, indexes) => {
139
+ await messageStore.clear();
140
+ indexes.messageTimestamp = message.descriptor.messageTimestamp;
141
+ // Put the same message twice
142
+ await messageStore.put(tenant, message, indexes);
143
+ await messageStore.put(tenant, message, indexes);
144
+ const cid = await Message.getCid(message);
145
+ const retrieved = await messageStore.get(tenant, cid);
146
+ expect(retrieved).toBeDefined();
147
+ // Should still only count as one message
148
+ const count = await messageStore.count(tenant, [{}], { messageTimestamp: SortDirection.Ascending });
149
+ expect(count).toBe(1);
150
+ }), { numRuns: Math.min(numRuns, 20) });
151
+ });
152
+ });
153
+ });
154
+ //# sourceMappingURL=message-store.fuzz.spec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"message-store.fuzz.spec.js","sourceRoot":"","sources":["../../../../tests/fuzz/message-store.fuzz.spec.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,82 @@
1
+ import { describe, expect, it } from 'bun:test';
2
+ import fc from 'fast-check';
3
+ import { isEmptyObject, removeEmptyObjects, removeUndefinedProperties } from '../../src/utils/object.js';
4
+ const numRuns = Number(process.env.FAST_CHECK_NUM_RUNS) || 100;
5
+ /**
6
+ * Generates nested objects with a mix of primitives, undefined values, and empty objects.
7
+ * Excludes null in nested positions — the production code's recursive helpers
8
+ * (`removeUndefinedProperties`, `removeEmptyObjects`) call `Object.keys()` on
9
+ * values where `typeof value === 'object'`, which includes `null` and would throw.
10
+ * Real DWN messages use `undefined` (not `null`) for absent properties.
11
+ */
12
+ function nestedObject() {
13
+ const leaf = fc.oneof(fc.string(), fc.integer(), fc.boolean(), fc.constant(undefined), fc.constant({}));
14
+ return fc.dictionary(fc.string({ minLength: 1, maxLength: 10 }), fc.oneof(leaf, fc.dictionary(fc.string({ minLength: 1, maxLength: 8 }), leaf, { minKeys: 0, maxKeys: 3 })), { minKeys: 0, maxKeys: 5 });
15
+ }
16
+ /** Check that no property in the (possibly nested) object is undefined. */
17
+ function hasNoUndefined(obj) {
18
+ for (const key of Object.keys(obj)) {
19
+ if (obj[key] === undefined) {
20
+ return false;
21
+ }
22
+ if (typeof obj[key] === 'object' && obj[key] !== null) {
23
+ if (!hasNoUndefined(obj[key])) {
24
+ return false;
25
+ }
26
+ }
27
+ }
28
+ return true;
29
+ }
30
+ describe('Object utilities — fuzz', () => {
31
+ describe('isEmptyObject', () => {
32
+ it('should return false for all primitives', () => {
33
+ fc.assert(fc.property(fc.oneof(fc.string(), fc.integer(), fc.float(), fc.boolean(), fc.constant(undefined)), (value) => {
34
+ expect(isEmptyObject(value)).toBe(false);
35
+ }), { numRuns });
36
+ });
37
+ });
38
+ describe('removeUndefinedProperties — idempotency', () => {
39
+ it('should produce the same result when applied twice', () => {
40
+ fc.assert(fc.property(nestedObject(), (obj) => {
41
+ const clone1 = structuredClone(obj);
42
+ const clone2 = structuredClone(obj);
43
+ removeUndefinedProperties(clone1);
44
+ removeUndefinedProperties(clone2);
45
+ removeUndefinedProperties(clone2); // second pass
46
+ expect(clone2).toEqual(clone1);
47
+ }), { numRuns });
48
+ });
49
+ it('should leave no undefined properties after one pass', () => {
50
+ fc.assert(fc.property(nestedObject(), (obj) => {
51
+ removeUndefinedProperties(obj);
52
+ expect(hasNoUndefined(obj)).toBe(true);
53
+ }), { numRuns });
54
+ });
55
+ });
56
+ describe('removeEmptyObjects — idempotency', () => {
57
+ it('should produce the same result when applied twice', () => {
58
+ fc.assert(fc.property(nestedObject(), (obj) => {
59
+ const clone1 = structuredClone(obj);
60
+ const clone2 = structuredClone(obj);
61
+ removeEmptyObjects(clone1);
62
+ removeEmptyObjects(clone2);
63
+ removeEmptyObjects(clone2); // second pass
64
+ expect(clone2).toEqual(clone1);
65
+ }), { numRuns });
66
+ });
67
+ });
68
+ describe('removeUndefinedProperties then removeEmptyObjects — clean result', () => {
69
+ it('should leave an object with no undefined properties and no empty objects', () => {
70
+ fc.assert(fc.property(nestedObject(), (obj) => {
71
+ removeUndefinedProperties(obj);
72
+ removeEmptyObjects(obj);
73
+ // After both passes: no undefined, no empty objects
74
+ expect(hasNoUndefined(obj)).toBe(true);
75
+ for (const key of Object.keys(obj)) {
76
+ expect(isEmptyObject(obj[key])).toBe(false);
77
+ }
78
+ }), { numRuns });
79
+ });
80
+ });
81
+ });
82
+ //# sourceMappingURL=object.fuzz.spec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"object.fuzz.spec.js","sourceRoot":"","sources":["../../../../tests/fuzz/object.fuzz.spec.ts"],"names":[],"mappings":"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"}