@graffiti-garden/api 1.0.0 → 1.0.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.
- package/dist/index.cjs +1 -1
- package/dist/index.cjs.map +4 -4
- package/dist/index.mjs +1 -1
- package/dist/index.mjs.map +4 -4
- package/dist/src/1-api.d.ts +66 -19
- package/dist/src/1-api.d.ts.map +1 -1
- package/dist/src/2-types.d.ts +3 -3
- package/dist/src/2-types.d.ts.map +1 -1
- package/dist/src/3-errors.d.ts +0 -9
- package/dist/src/3-errors.d.ts.map +1 -1
- package/dist/src/4-utilities.d.ts +8 -0
- package/dist/src/4-utilities.d.ts.map +1 -0
- package/dist/src/index.d.ts +1 -0
- package/dist/src/index.d.ts.map +1 -1
- package/dist/tests/crud.d.ts.map +1 -1
- package/dist/tests/index.d.ts +3 -0
- package/dist/tests/index.d.ts.map +1 -1
- package/dist/tests/media.d.ts +3 -0
- package/dist/tests/media.d.ts.map +1 -0
- package/dist/tests.mjs +683 -0
- package/dist/tests.mjs.map +4 -4
- package/package.json +3 -2
- package/src/1-api.ts +67 -17
- package/src/2-types.ts +4 -3
- package/src/3-errors.ts +0 -24
- package/src/4-utilities.ts +65 -0
- package/src/index.ts +1 -0
- package/tests/crud.ts +0 -15
- package/tests/index.ts +3 -2
- package/tests/media.ts +158 -0
package/dist/tests.mjs
CHANGED
|
@@ -1,3 +1,12 @@
|
|
|
1
|
+
// tests/crud.ts
|
|
2
|
+
import { it, expect, describe, beforeAll } from "vitest";
|
|
3
|
+
import {
|
|
4
|
+
GraffitiErrorNotFound,
|
|
5
|
+
GraffitiErrorSchemaMismatch,
|
|
6
|
+
GraffitiErrorInvalidSchema,
|
|
7
|
+
GraffitiErrorForbidden
|
|
8
|
+
} from "@graffiti-garden/api";
|
|
9
|
+
|
|
1
10
|
// tests/utils.ts
|
|
2
11
|
import { assert } from "vitest";
|
|
3
12
|
function randomString() {
|
|
@@ -33,8 +42,682 @@ function continueStream(graffiti, streamReturn, type, session) {
|
|
|
33
42
|
return streamReturn.continue();
|
|
34
43
|
}
|
|
35
44
|
}
|
|
45
|
+
|
|
46
|
+
// tests/crud.ts
|
|
47
|
+
var graffitiCRUDTests = (useGraffiti, useSession1, useSession2) => {
|
|
48
|
+
describe.concurrent(
|
|
49
|
+
"CRUD",
|
|
50
|
+
{
|
|
51
|
+
timeout: 2e4
|
|
52
|
+
},
|
|
53
|
+
() => {
|
|
54
|
+
let graffiti;
|
|
55
|
+
let session;
|
|
56
|
+
let session1;
|
|
57
|
+
let session2;
|
|
58
|
+
beforeAll(async () => {
|
|
59
|
+
graffiti = useGraffiti();
|
|
60
|
+
session1 = await useSession1();
|
|
61
|
+
session = session1;
|
|
62
|
+
session2 = await useSession2();
|
|
63
|
+
});
|
|
64
|
+
it("post, get, delete", async () => {
|
|
65
|
+
const value = {
|
|
66
|
+
something: "hello, world~ c:"
|
|
67
|
+
};
|
|
68
|
+
const channels = [randomString(), randomString()];
|
|
69
|
+
const previous = await graffiti.post({ value, channels }, session);
|
|
70
|
+
expect(previous.value).toEqual(value);
|
|
71
|
+
expect(previous.channels).toEqual(channels);
|
|
72
|
+
expect(previous.allowed).toEqual(void 0);
|
|
73
|
+
expect(previous.actor).toEqual(session.actor);
|
|
74
|
+
const gotten = await graffiti.get(previous, {});
|
|
75
|
+
expect(gotten.value).toEqual(value);
|
|
76
|
+
expect(gotten.channels).toEqual([]);
|
|
77
|
+
expect(gotten.allowed).toBeUndefined();
|
|
78
|
+
expect(gotten.url).toEqual(previous.url);
|
|
79
|
+
expect(gotten.actor).toEqual(previous.actor);
|
|
80
|
+
await graffiti.delete(gotten, session);
|
|
81
|
+
await expect(graffiti.get(gotten, {})).rejects.toBeInstanceOf(
|
|
82
|
+
GraffitiErrorNotFound
|
|
83
|
+
);
|
|
84
|
+
await expect(graffiti.delete(gotten, session)).rejects.toThrow(
|
|
85
|
+
GraffitiErrorNotFound
|
|
86
|
+
);
|
|
87
|
+
});
|
|
88
|
+
it("post then delete with wrong actor", async () => {
|
|
89
|
+
const posted = await graffiti.post(
|
|
90
|
+
{ value: {}, channels: [] },
|
|
91
|
+
session2
|
|
92
|
+
);
|
|
93
|
+
await expect(graffiti.delete(posted, session1)).rejects.toThrow(
|
|
94
|
+
GraffitiErrorForbidden
|
|
95
|
+
);
|
|
96
|
+
});
|
|
97
|
+
it("post and get with schema", async () => {
|
|
98
|
+
const schema = {
|
|
99
|
+
properties: {
|
|
100
|
+
value: {
|
|
101
|
+
properties: {
|
|
102
|
+
something: {
|
|
103
|
+
type: "string"
|
|
104
|
+
},
|
|
105
|
+
another: {
|
|
106
|
+
type: "array",
|
|
107
|
+
items: {
|
|
108
|
+
type: "number"
|
|
109
|
+
}
|
|
110
|
+
},
|
|
111
|
+
deeper: {
|
|
112
|
+
type: "object",
|
|
113
|
+
properties: {
|
|
114
|
+
deepProp: {
|
|
115
|
+
type: "string"
|
|
116
|
+
}
|
|
117
|
+
},
|
|
118
|
+
required: ["deepProp"]
|
|
119
|
+
}
|
|
120
|
+
},
|
|
121
|
+
required: ["another", "deeper"]
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
};
|
|
125
|
+
const goodValue = {
|
|
126
|
+
something: "hello",
|
|
127
|
+
another: [1, 2, 3],
|
|
128
|
+
deeper: {
|
|
129
|
+
deepProp: "hello"
|
|
130
|
+
}
|
|
131
|
+
};
|
|
132
|
+
const posted = await graffiti.post(
|
|
133
|
+
{
|
|
134
|
+
value: goodValue,
|
|
135
|
+
channels: []
|
|
136
|
+
},
|
|
137
|
+
session
|
|
138
|
+
);
|
|
139
|
+
const gotten = await graffiti.get(posted, schema);
|
|
140
|
+
expect(gotten.value.something).toEqual(goodValue.something);
|
|
141
|
+
expect(gotten.value.another).toEqual(goodValue.another);
|
|
142
|
+
expect(gotten.value.another[0]).toEqual(1);
|
|
143
|
+
expect(gotten.value.deeper.deepProp).toEqual(goodValue.deeper.deepProp);
|
|
144
|
+
});
|
|
145
|
+
it("post and get with invalid schema", async () => {
|
|
146
|
+
const posted = await graffiti.post(
|
|
147
|
+
{ value: {}, channels: [] },
|
|
148
|
+
session
|
|
149
|
+
);
|
|
150
|
+
await expect(
|
|
151
|
+
graffiti.get(posted, {
|
|
152
|
+
properties: {
|
|
153
|
+
value: {
|
|
154
|
+
//@ts-ignore
|
|
155
|
+
type: "asdf"
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
})
|
|
159
|
+
).rejects.toThrow(GraffitiErrorInvalidSchema);
|
|
160
|
+
});
|
|
161
|
+
it("post and get with wrong schema", async () => {
|
|
162
|
+
const posted = await graffiti.post(
|
|
163
|
+
{
|
|
164
|
+
value: {
|
|
165
|
+
hello: "world"
|
|
166
|
+
},
|
|
167
|
+
channels: []
|
|
168
|
+
},
|
|
169
|
+
session
|
|
170
|
+
);
|
|
171
|
+
await expect(
|
|
172
|
+
graffiti.get(posted, {
|
|
173
|
+
properties: {
|
|
174
|
+
value: {
|
|
175
|
+
properties: {
|
|
176
|
+
hello: {
|
|
177
|
+
type: "number"
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
})
|
|
183
|
+
).rejects.toThrow(GraffitiErrorSchemaMismatch);
|
|
184
|
+
});
|
|
185
|
+
it("post and get with empty access control", async () => {
|
|
186
|
+
const value = {
|
|
187
|
+
um: "hi"
|
|
188
|
+
};
|
|
189
|
+
const allowed = [randomString()];
|
|
190
|
+
const channels = [randomString()];
|
|
191
|
+
const posted = await graffiti.post(
|
|
192
|
+
{ value, allowed, channels },
|
|
193
|
+
session1
|
|
194
|
+
);
|
|
195
|
+
const gotten = await graffiti.get(posted, {}, session1);
|
|
196
|
+
expect(gotten.url).toEqual(posted.url);
|
|
197
|
+
expect(gotten.actor).toEqual(session1.actor);
|
|
198
|
+
expect(gotten.value).toEqual(value);
|
|
199
|
+
expect(gotten.allowed).toEqual(allowed);
|
|
200
|
+
expect(gotten.channels).toEqual(channels);
|
|
201
|
+
await expect(graffiti.get(posted, {})).rejects.toBeInstanceOf(
|
|
202
|
+
GraffitiErrorNotFound
|
|
203
|
+
);
|
|
204
|
+
await expect(graffiti.get(posted, {}, session2)).rejects.toBeInstanceOf(
|
|
205
|
+
GraffitiErrorNotFound
|
|
206
|
+
);
|
|
207
|
+
});
|
|
208
|
+
it("post and get with specific access control", async () => {
|
|
209
|
+
const value = {
|
|
210
|
+
um: "hi"
|
|
211
|
+
};
|
|
212
|
+
const allowed = [randomString(), session2.actor, randomString()];
|
|
213
|
+
const channels = [randomString()];
|
|
214
|
+
const posted = await graffiti.post(
|
|
215
|
+
{
|
|
216
|
+
value,
|
|
217
|
+
allowed,
|
|
218
|
+
channels
|
|
219
|
+
},
|
|
220
|
+
session1
|
|
221
|
+
);
|
|
222
|
+
const gotten = await graffiti.get(posted, {}, session1);
|
|
223
|
+
expect(gotten.url).toEqual(posted.url);
|
|
224
|
+
expect(gotten.actor).toEqual(session1.actor);
|
|
225
|
+
expect(gotten.value).toEqual(value);
|
|
226
|
+
expect(gotten.allowed).toEqual(allowed);
|
|
227
|
+
expect(gotten.channels).toEqual(channels);
|
|
228
|
+
await expect(graffiti.get(posted, {})).rejects.toBeInstanceOf(
|
|
229
|
+
GraffitiErrorNotFound
|
|
230
|
+
);
|
|
231
|
+
const gotten2 = await graffiti.get(posted, {}, session2);
|
|
232
|
+
expect(gotten.url).toEqual(posted.url);
|
|
233
|
+
expect(gotten.actor).toEqual(session1.actor);
|
|
234
|
+
expect(gotten2.value).toEqual(value);
|
|
235
|
+
expect(gotten2.allowed).toEqual([session2.actor]);
|
|
236
|
+
expect(gotten2.channels).toEqual([]);
|
|
237
|
+
});
|
|
238
|
+
}
|
|
239
|
+
);
|
|
240
|
+
};
|
|
241
|
+
|
|
242
|
+
// tests/discover.ts
|
|
243
|
+
import { it as it2, expect as expect2, describe as describe2, assert as assert2, beforeAll as beforeAll2 } from "vitest";
|
|
244
|
+
var graffitiDiscoverTests = (useGraffiti, useSession1, useSession2) => {
|
|
245
|
+
describe2.concurrent("discover", { timeout: 2e4 }, () => {
|
|
246
|
+
let graffiti;
|
|
247
|
+
let session;
|
|
248
|
+
let session1;
|
|
249
|
+
let session2;
|
|
250
|
+
beforeAll2(async () => {
|
|
251
|
+
graffiti = useGraffiti();
|
|
252
|
+
session1 = await useSession1();
|
|
253
|
+
session = session1;
|
|
254
|
+
session2 = await useSession2();
|
|
255
|
+
});
|
|
256
|
+
it2("discover nothing", async () => {
|
|
257
|
+
const iterator = graffiti.discover([], {});
|
|
258
|
+
expect2(await iterator.next()).toHaveProperty("done", true);
|
|
259
|
+
});
|
|
260
|
+
it2("discover single", async () => {
|
|
261
|
+
const object = randomPostObject();
|
|
262
|
+
const posted = await graffiti.post(object, session);
|
|
263
|
+
const queryChannels = [randomString(), object.channels[0]];
|
|
264
|
+
const iterator = graffiti.discover(queryChannels, {});
|
|
265
|
+
const value = await nextStreamValue(iterator);
|
|
266
|
+
expect2(value.url).toEqual(posted.url);
|
|
267
|
+
expect2(value.value).toEqual(object.value);
|
|
268
|
+
expect2(value.channels).toEqual([object.channels[0]]);
|
|
269
|
+
expect2(value.allowed).toBeUndefined();
|
|
270
|
+
expect2(value.actor).toEqual(session.actor);
|
|
271
|
+
const result2 = await iterator.next();
|
|
272
|
+
expect2(result2.done).toBe(true);
|
|
273
|
+
});
|
|
274
|
+
it2("discover wrong channel", async () => {
|
|
275
|
+
const object = randomPostObject();
|
|
276
|
+
await graffiti.post(object, session);
|
|
277
|
+
const iterator = graffiti.discover([randomString()], {});
|
|
278
|
+
await expect2(iterator.next()).resolves.toHaveProperty("done", true);
|
|
279
|
+
});
|
|
280
|
+
it2("discover not allowed", async () => {
|
|
281
|
+
const object = randomPostObject();
|
|
282
|
+
object.allowed = [randomString(), randomString()];
|
|
283
|
+
const posted = await graffiti.post(object, session1);
|
|
284
|
+
const iteratorSession1 = graffiti.discover(
|
|
285
|
+
object.channels,
|
|
286
|
+
{},
|
|
287
|
+
session1
|
|
288
|
+
);
|
|
289
|
+
const value = await nextStreamValue(iteratorSession1);
|
|
290
|
+
expect2(value.url).toEqual(posted.url);
|
|
291
|
+
expect2(value.value).toEqual(object.value);
|
|
292
|
+
expect2(value.channels).toEqual(object.channels);
|
|
293
|
+
expect2(value.allowed).toEqual(object.allowed);
|
|
294
|
+
expect2(value.actor).toEqual(session1.actor);
|
|
295
|
+
const iteratorSession2 = graffiti.discover(object.channels, {}, session2);
|
|
296
|
+
expect2(await iteratorSession2.next()).toHaveProperty("done", true);
|
|
297
|
+
const iteratorNoSession = graffiti.discover(object.channels, {});
|
|
298
|
+
expect2(await iteratorNoSession.next()).toHaveProperty("done", true);
|
|
299
|
+
});
|
|
300
|
+
it2("discover allowed", async () => {
|
|
301
|
+
const object = randomPostObject();
|
|
302
|
+
object.allowed = [randomString(), session2.actor, randomString()];
|
|
303
|
+
const posted = await graffiti.post(object, session1);
|
|
304
|
+
const iteratorSession2 = graffiti.discover(
|
|
305
|
+
object.channels,
|
|
306
|
+
{},
|
|
307
|
+
session2
|
|
308
|
+
);
|
|
309
|
+
const value = await nextStreamValue(iteratorSession2);
|
|
310
|
+
expect2(value.url).toEqual(posted.url);
|
|
311
|
+
expect2(value.value).toEqual(object.value);
|
|
312
|
+
expect2(value.allowed).toEqual([session2.actor]);
|
|
313
|
+
expect2(value.channels).toEqual(object.channels);
|
|
314
|
+
expect2(value.actor).toEqual(session1.actor);
|
|
315
|
+
});
|
|
316
|
+
it2("discover for actor", async () => {
|
|
317
|
+
const object1 = randomPostObject();
|
|
318
|
+
const posted1 = await graffiti.post(object1, session1);
|
|
319
|
+
const object2 = randomPostObject();
|
|
320
|
+
object2.channels = object1.channels;
|
|
321
|
+
const posted2 = await graffiti.post(object2, session2);
|
|
322
|
+
const iterator = graffiti.discover(object1.channels, {
|
|
323
|
+
properties: {
|
|
324
|
+
actor: { const: posted1.actor }
|
|
325
|
+
}
|
|
326
|
+
});
|
|
327
|
+
const value = await nextStreamValue(iterator);
|
|
328
|
+
expect2(value.url).toEqual(posted1.url);
|
|
329
|
+
expect2(value.url).not.toEqual(posted2.url);
|
|
330
|
+
expect2(value.value).toEqual(object1.value);
|
|
331
|
+
await expect2(iterator.next()).resolves.toHaveProperty("done", true);
|
|
332
|
+
});
|
|
333
|
+
it2("discover schema allowed, as and not as owner", async () => {
|
|
334
|
+
const object = randomPostObject();
|
|
335
|
+
object.allowed = [randomString(), session2.actor, randomString()];
|
|
336
|
+
await graffiti.post(object, session1);
|
|
337
|
+
const iteratorSession1 = graffiti.discover(
|
|
338
|
+
object.channels,
|
|
339
|
+
{
|
|
340
|
+
properties: {
|
|
341
|
+
allowed: {
|
|
342
|
+
minItems: 3,
|
|
343
|
+
// Make sure session2.actor is in the allow list
|
|
344
|
+
not: {
|
|
345
|
+
items: {
|
|
346
|
+
not: { const: session2.actor }
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
},
|
|
352
|
+
session1
|
|
353
|
+
);
|
|
354
|
+
const value = await nextStreamValue(iteratorSession1);
|
|
355
|
+
expect2(value.value).toEqual(object.value);
|
|
356
|
+
await expect2(iteratorSession1.next()).resolves.toHaveProperty(
|
|
357
|
+
"done",
|
|
358
|
+
true
|
|
359
|
+
);
|
|
360
|
+
const iteratorSession2BigAllow = graffiti.discover(
|
|
361
|
+
object.channels,
|
|
362
|
+
{
|
|
363
|
+
properties: {
|
|
364
|
+
allowed: {
|
|
365
|
+
minItems: 3
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
},
|
|
369
|
+
session2
|
|
370
|
+
);
|
|
371
|
+
await expect2(iteratorSession2BigAllow.next()).resolves.toHaveProperty(
|
|
372
|
+
"done",
|
|
373
|
+
true
|
|
374
|
+
);
|
|
375
|
+
const iteratorSession2PeekOther = graffiti.discover(
|
|
376
|
+
object.channels,
|
|
377
|
+
{
|
|
378
|
+
properties: {
|
|
379
|
+
allowed: {
|
|
380
|
+
not: {
|
|
381
|
+
items: {
|
|
382
|
+
not: { const: object.allowed[0] }
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
},
|
|
388
|
+
session2
|
|
389
|
+
);
|
|
390
|
+
await expect2(iteratorSession2PeekOther.next()).resolves.toHaveProperty(
|
|
391
|
+
"done",
|
|
392
|
+
true
|
|
393
|
+
);
|
|
394
|
+
const iteratorSession2SmallAllowPeekSelf = graffiti.discover(
|
|
395
|
+
object.channels,
|
|
396
|
+
{
|
|
397
|
+
properties: {
|
|
398
|
+
allowed: {
|
|
399
|
+
maxItems: 1,
|
|
400
|
+
not: {
|
|
401
|
+
items: {
|
|
402
|
+
not: { const: session2.actor }
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
},
|
|
408
|
+
session2
|
|
409
|
+
);
|
|
410
|
+
const value2 = await nextStreamValue(
|
|
411
|
+
iteratorSession2SmallAllowPeekSelf
|
|
412
|
+
);
|
|
413
|
+
expect2(value2.value).toEqual(object.value);
|
|
414
|
+
await expect2(
|
|
415
|
+
iteratorSession2SmallAllowPeekSelf.next()
|
|
416
|
+
).resolves.toHaveProperty("done", true);
|
|
417
|
+
});
|
|
418
|
+
it2("discover schema channels, as and not as owner", async () => {
|
|
419
|
+
const object = randomPostObject();
|
|
420
|
+
object.channels = [randomString(), randomString(), randomString()];
|
|
421
|
+
await graffiti.post(object, session1);
|
|
422
|
+
const iteratorSession1 = graffiti.discover(
|
|
423
|
+
[object.channels[0], object.channels[2]],
|
|
424
|
+
{
|
|
425
|
+
properties: {
|
|
426
|
+
channels: {
|
|
427
|
+
minItems: 3,
|
|
428
|
+
// Make sure channel 1 is in the allow list
|
|
429
|
+
not: {
|
|
430
|
+
items: {
|
|
431
|
+
not: { const: object.channels[1] }
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
},
|
|
437
|
+
session1
|
|
438
|
+
);
|
|
439
|
+
const value = await nextStreamValue(iteratorSession1);
|
|
440
|
+
expect2(value.value).toEqual(object.value);
|
|
441
|
+
await expect2(iteratorSession1.next()).resolves.toHaveProperty(
|
|
442
|
+
"done",
|
|
443
|
+
true
|
|
444
|
+
);
|
|
445
|
+
const iteratorSession2BigAllow = graffiti.discover(
|
|
446
|
+
[object.channels[0], object.channels[2]],
|
|
447
|
+
{
|
|
448
|
+
properties: {
|
|
449
|
+
channels: {
|
|
450
|
+
minItems: 3
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
},
|
|
454
|
+
session2
|
|
455
|
+
);
|
|
456
|
+
await expect2(iteratorSession2BigAllow.next()).resolves.toHaveProperty(
|
|
457
|
+
"done",
|
|
458
|
+
true
|
|
459
|
+
);
|
|
460
|
+
const iteratorSession2PeekOther = graffiti.discover(
|
|
461
|
+
[object.channels[0], object.channels[2]],
|
|
462
|
+
{
|
|
463
|
+
properties: {
|
|
464
|
+
channels: {
|
|
465
|
+
not: {
|
|
466
|
+
items: {
|
|
467
|
+
not: { const: object.channels[1] }
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
},
|
|
473
|
+
session2
|
|
474
|
+
);
|
|
475
|
+
await expect2(iteratorSession2PeekOther.next()).resolves.toHaveProperty(
|
|
476
|
+
"done",
|
|
477
|
+
true
|
|
478
|
+
);
|
|
479
|
+
const iteratorSession2SmallAllowPeekSelf = graffiti.discover(
|
|
480
|
+
[object.channels[0], object.channels[2]],
|
|
481
|
+
{
|
|
482
|
+
properties: {
|
|
483
|
+
allowed: {
|
|
484
|
+
maxItems: 2,
|
|
485
|
+
not: {
|
|
486
|
+
items: {
|
|
487
|
+
not: { const: object.channels[2] }
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
},
|
|
493
|
+
session2
|
|
494
|
+
);
|
|
495
|
+
const value2 = await nextStreamValue(
|
|
496
|
+
iteratorSession2SmallAllowPeekSelf
|
|
497
|
+
);
|
|
498
|
+
expect2(value2.value).toEqual(object.value);
|
|
499
|
+
await expect2(
|
|
500
|
+
iteratorSession2SmallAllowPeekSelf.next()
|
|
501
|
+
).resolves.toHaveProperty("done", true);
|
|
502
|
+
});
|
|
503
|
+
it2("discover query for empty allowed", async () => {
|
|
504
|
+
const publicO = randomPostObject();
|
|
505
|
+
const publicSchema = {
|
|
506
|
+
not: {
|
|
507
|
+
required: ["allowed"]
|
|
508
|
+
}
|
|
509
|
+
};
|
|
510
|
+
await graffiti.post(publicO, session1);
|
|
511
|
+
const iterator = graffiti.discover(
|
|
512
|
+
publicO.channels,
|
|
513
|
+
publicSchema,
|
|
514
|
+
session1
|
|
515
|
+
);
|
|
516
|
+
const value = await nextStreamValue(iterator);
|
|
517
|
+
expect2(value.value).toEqual(publicO.value);
|
|
518
|
+
expect2(value.allowed).toBeUndefined();
|
|
519
|
+
await expect2(iterator.next()).resolves.toHaveProperty("done", true);
|
|
520
|
+
const restricted = randomPostObject();
|
|
521
|
+
restricted.allowed = [];
|
|
522
|
+
await graffiti.post(restricted, session1);
|
|
523
|
+
const iterator2 = graffiti.discover(
|
|
524
|
+
restricted.channels,
|
|
525
|
+
publicSchema,
|
|
526
|
+
session1
|
|
527
|
+
);
|
|
528
|
+
await expect2(iterator2.next()).resolves.toHaveProperty("done", true);
|
|
529
|
+
});
|
|
530
|
+
it2("discover query for values", async () => {
|
|
531
|
+
const object1 = randomPostObject();
|
|
532
|
+
object1.value = { test: randomString() };
|
|
533
|
+
await graffiti.post(object1, session);
|
|
534
|
+
const object2 = randomPostObject();
|
|
535
|
+
object2.channels = object1.channels;
|
|
536
|
+
object2.value = { test: randomString(), something: randomString() };
|
|
537
|
+
await graffiti.post(object2, session);
|
|
538
|
+
const object3 = randomPostObject();
|
|
539
|
+
object3.channels = object1.channels;
|
|
540
|
+
object3.value = { other: randomString(), something: randomString() };
|
|
541
|
+
await graffiti.post(object3, session);
|
|
542
|
+
const counts = /* @__PURE__ */ new Map();
|
|
543
|
+
for (const property of ["test", "something", "other"]) {
|
|
544
|
+
let count = 0;
|
|
545
|
+
for await (const result of graffiti.discover(object1.channels, {
|
|
546
|
+
properties: {
|
|
547
|
+
value: {
|
|
548
|
+
required: [property]
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
})) {
|
|
552
|
+
assert2(!result.error, "result has error");
|
|
553
|
+
if (property in result.object.value) {
|
|
554
|
+
count++;
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
counts.set(property, count);
|
|
558
|
+
}
|
|
559
|
+
expect2(counts.get("test")).toBe(2);
|
|
560
|
+
expect2(counts.get("something")).toBe(2);
|
|
561
|
+
expect2(counts.get("other")).toBe(1);
|
|
562
|
+
});
|
|
563
|
+
for (const continueType of ["cursor", "continue"]) {
|
|
564
|
+
describe2(`continue discover with ${continueType}`, () => {
|
|
565
|
+
it2("discover for deleted content", async () => {
|
|
566
|
+
const object = randomPostObject();
|
|
567
|
+
const posted = await graffiti.post(object, session);
|
|
568
|
+
const iterator1 = graffiti.discover(object.channels, {});
|
|
569
|
+
const value1 = await nextStreamValue(iterator1);
|
|
570
|
+
expect2(value1.value).toEqual(object.value);
|
|
571
|
+
const returnValue = await iterator1.next();
|
|
572
|
+
assert2(returnValue.done, "value2 is not done");
|
|
573
|
+
await graffiti.delete(posted, session);
|
|
574
|
+
const iterator = graffiti.discover(object.channels, {});
|
|
575
|
+
await expect2(iterator.next()).resolves.toHaveProperty("done", true);
|
|
576
|
+
const tombIterator = continueStream(
|
|
577
|
+
graffiti,
|
|
578
|
+
returnValue.value,
|
|
579
|
+
continueType
|
|
580
|
+
);
|
|
581
|
+
const value = await tombIterator.next();
|
|
582
|
+
assert2(!value.done && !value.value.error, "value is done");
|
|
583
|
+
assert2(value.value.tombstone, "value is not tombstone");
|
|
584
|
+
expect2(value.value.object.url).toEqual(posted.url);
|
|
585
|
+
await expect2(tombIterator.next()).resolves.toHaveProperty(
|
|
586
|
+
"done",
|
|
587
|
+
true
|
|
588
|
+
);
|
|
589
|
+
});
|
|
590
|
+
});
|
|
591
|
+
}
|
|
592
|
+
});
|
|
593
|
+
};
|
|
594
|
+
|
|
595
|
+
// tests/media.ts
|
|
596
|
+
import {
|
|
597
|
+
GraffitiErrorNotAcceptable,
|
|
598
|
+
GraffitiErrorNotFound as GraffitiErrorNotFound2,
|
|
599
|
+
GraffitiErrorTooLarge
|
|
600
|
+
} from "@graffiti-garden/api";
|
|
601
|
+
import { it as it3, expect as expect3, describe as describe3, beforeAll as beforeAll3 } from "vitest";
|
|
602
|
+
var graffitiMediaTests = (useGraffiti, useSession1, useSession2) => {
|
|
603
|
+
describe3.concurrent(
|
|
604
|
+
"media",
|
|
605
|
+
{
|
|
606
|
+
timeout: 2e4
|
|
607
|
+
},
|
|
608
|
+
() => {
|
|
609
|
+
let graffiti;
|
|
610
|
+
let session;
|
|
611
|
+
let session1;
|
|
612
|
+
let session2;
|
|
613
|
+
beforeAll3(async () => {
|
|
614
|
+
graffiti = useGraffiti();
|
|
615
|
+
session1 = await useSession1();
|
|
616
|
+
session = session1;
|
|
617
|
+
session2 = await useSession2();
|
|
618
|
+
});
|
|
619
|
+
it3("post, get, delete media", async () => {
|
|
620
|
+
const text = randomString();
|
|
621
|
+
const data = new Blob([text], { type: "text/plain" });
|
|
622
|
+
const mediaUrl = await graffiti.postMedia({ data }, session);
|
|
623
|
+
const media = await graffiti.getMedia(mediaUrl, {});
|
|
624
|
+
expect3(await media.data.text()).toEqual(text);
|
|
625
|
+
expect3(media.data.type).toEqual("text/plain");
|
|
626
|
+
expect3(media.allowed).toBeUndefined();
|
|
627
|
+
expect3(media.actor).toBe(session.actor);
|
|
628
|
+
await graffiti.deleteMedia(mediaUrl, session);
|
|
629
|
+
await expect3(graffiti.getMedia(mediaUrl, {})).rejects.toThrow(
|
|
630
|
+
GraffitiErrorNotFound2
|
|
631
|
+
);
|
|
632
|
+
});
|
|
633
|
+
it3("acceptable type", async () => {
|
|
634
|
+
const text = randomString();
|
|
635
|
+
const data = new Blob([text], { type: "text/plain" });
|
|
636
|
+
const mediaUrl = await graffiti.postMedia({ data }, session);
|
|
637
|
+
const media = await graffiti.getMedia(mediaUrl, {
|
|
638
|
+
accept: "text/*"
|
|
639
|
+
});
|
|
640
|
+
expect3(await media.data.text()).toEqual(text);
|
|
641
|
+
expect3(media.data.type).toEqual("text/plain");
|
|
642
|
+
expect3(media.allowed).toBeUndefined();
|
|
643
|
+
expect3(media.actor).toBe(session.actor);
|
|
644
|
+
});
|
|
645
|
+
it3("unacceptable type", async () => {
|
|
646
|
+
const text = randomString();
|
|
647
|
+
const data = new Blob([text], { type: "text/plain" });
|
|
648
|
+
const mediaUrl = await graffiti.postMedia({ data }, session);
|
|
649
|
+
await expect3(
|
|
650
|
+
graffiti.getMedia(mediaUrl, {
|
|
651
|
+
accept: "image/*"
|
|
652
|
+
})
|
|
653
|
+
).rejects.toThrow(GraffitiErrorNotAcceptable);
|
|
654
|
+
});
|
|
655
|
+
it3("acceptable size", async () => {
|
|
656
|
+
const text = randomString();
|
|
657
|
+
const data = new Blob([text], { type: "text/plain" });
|
|
658
|
+
const mediaUrl = await graffiti.postMedia({ data }, session);
|
|
659
|
+
const media = await graffiti.getMedia(mediaUrl, {
|
|
660
|
+
maxBytes: data.size
|
|
661
|
+
});
|
|
662
|
+
expect3(await media.data.text()).toEqual(text);
|
|
663
|
+
expect3(media.data.type).toEqual("text/plain");
|
|
664
|
+
expect3(media.allowed).toBeUndefined();
|
|
665
|
+
expect3(media.actor).toBe(session.actor);
|
|
666
|
+
});
|
|
667
|
+
it3("unacceptable size", async () => {
|
|
668
|
+
const text = randomString();
|
|
669
|
+
const data = new Blob([text], { type: "text/plain" });
|
|
670
|
+
const mediaUrl = await graffiti.postMedia({ data }, session);
|
|
671
|
+
await expect3(
|
|
672
|
+
graffiti.getMedia(mediaUrl, {
|
|
673
|
+
maxBytes: data.size - 1
|
|
674
|
+
})
|
|
675
|
+
).rejects.toThrow(GraffitiErrorTooLarge);
|
|
676
|
+
});
|
|
677
|
+
it3("empty allowed", async () => {
|
|
678
|
+
const text = randomString();
|
|
679
|
+
const data = new Blob([text], { type: "text/plain" });
|
|
680
|
+
const allowed = [];
|
|
681
|
+
const mediaUrl = await graffiti.postMedia({ data, allowed }, session1);
|
|
682
|
+
const media = await graffiti.getMedia(mediaUrl, {}, session1);
|
|
683
|
+
expect3(await media.data.text()).toEqual(text);
|
|
684
|
+
expect3(media.data.type).toEqual("text/plain");
|
|
685
|
+
expect3(media.allowed).toEqual([]);
|
|
686
|
+
expect3(media.actor).toBe(session1.actor);
|
|
687
|
+
await expect3(graffiti.getMedia(mediaUrl, {}, session2)).rejects.toThrow(
|
|
688
|
+
GraffitiErrorNotFound2
|
|
689
|
+
);
|
|
690
|
+
await expect3(graffiti.getMedia(mediaUrl, {})).rejects.toThrow(
|
|
691
|
+
GraffitiErrorNotFound2
|
|
692
|
+
);
|
|
693
|
+
});
|
|
694
|
+
it3("allowed", async () => {
|
|
695
|
+
const text = randomString();
|
|
696
|
+
const data = new Blob([text], { type: "text/plain" });
|
|
697
|
+
const allowed = [randomString(), session2.actor, randomString()];
|
|
698
|
+
const mediaUrl = await graffiti.postMedia({ data, allowed }, session1);
|
|
699
|
+
const media = await graffiti.getMedia(mediaUrl, {}, session1);
|
|
700
|
+
expect3(await media.data.text()).toEqual(text);
|
|
701
|
+
expect3(media.data.type).toEqual("text/plain");
|
|
702
|
+
expect3(media.allowed).toEqual(allowed);
|
|
703
|
+
expect3(media.actor).toBe(session1.actor);
|
|
704
|
+
const media2 = await graffiti.getMedia(mediaUrl, {}, session2);
|
|
705
|
+
expect3(await media2.data.text()).toEqual(text);
|
|
706
|
+
expect3(media2.data.type).toEqual("text/plain");
|
|
707
|
+
expect3(media2.allowed).toEqual([session2.actor]);
|
|
708
|
+
expect3(media2.actor).toBe(session1.actor);
|
|
709
|
+
await expect3(graffiti.getMedia(mediaUrl, {})).rejects.toThrow(
|
|
710
|
+
GraffitiErrorNotFound2
|
|
711
|
+
);
|
|
712
|
+
});
|
|
713
|
+
}
|
|
714
|
+
);
|
|
715
|
+
};
|
|
36
716
|
export {
|
|
37
717
|
continueStream,
|
|
718
|
+
graffitiCRUDTests,
|
|
719
|
+
graffitiDiscoverTests,
|
|
720
|
+
graffitiMediaTests,
|
|
38
721
|
nextStreamValue,
|
|
39
722
|
randomPostObject,
|
|
40
723
|
randomString,
|