@graffiti-garden/api 1.1.0 → 1.1.1

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.
@@ -1 +1 @@
1
- {"version":3,"file":"crud.d.ts","sourceRoot":"","sources":["../../tests/crud.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,QAAQ,EACR,eAAe,EAEhB,MAAM,sBAAsB,CAAC;AAS9B,eAAO,MAAM,iBAAiB,GAC5B,aAAa,MAAM,IAAI,CAAC,QAAQ,EAAE,MAAM,GAAG,KAAK,GAAG,QAAQ,CAAC,EAC5D,aAAa,MAAM,eAAe,GAAG,OAAO,CAAC,eAAe,CAAC,EAC7D,aAAa,MAAM,eAAe,GAAG,OAAO,CAAC,eAAe,CAAC,SAwQ9D,CAAC"}
1
+ {"version":3,"file":"crud.d.ts","sourceRoot":"","sources":["../../tests/crud.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,QAAQ,EACR,eAAe,EAEhB,MAAM,sBAAsB,CAAC;AAU9B,eAAO,MAAM,iBAAiB,GAC5B,aAAa,MAAM,IAAI,CAAC,QAAQ,EAAE,MAAM,GAAG,KAAK,GAAG,QAAQ,CAAC,EAC5D,aAAa,MAAM,eAAe,GAAG,OAAO,CAAC,eAAe,CAAC,EAC7D,aAAa,MAAM,eAAe,GAAG,OAAO,CAAC,eAAe,CAAC,SAkS9D,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"discover.d.ts","sourceRoot":"","sources":["../../tests/discover.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,QAAQ,EACR,eAAe,EAEhB,MAAM,sBAAsB,CAAC;AAc9B,eAAO,MAAM,qBAAqB,GAChC,aAAa,MAAM,IAAI,CACrB,QAAQ,EACR,UAAU,GAAG,MAAM,GAAG,QAAQ,GAAG,kBAAkB,CACpD,EACD,aAAa,MAAM,eAAe,GAAG,OAAO,CAAC,eAAe,CAAC,EAC7D,aAAa,MAAM,eAAe,GAAG,OAAO,CAAC,eAAe,CAAC,SAgb9D,CAAC"}
1
+ {"version":3,"file":"discover.d.ts","sourceRoot":"","sources":["../../tests/discover.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,QAAQ,EACR,eAAe,EAEhB,MAAM,sBAAsB,CAAC;AAc9B,eAAO,MAAM,qBAAqB,GAChC,aAAa,MAAM,IAAI,CACrB,QAAQ,EACR,UAAU,GAAG,MAAM,GAAG,QAAQ,GAAG,kBAAkB,CACpD,EACD,aAAa,MAAM,eAAe,GAAG,OAAO,CAAC,eAAe,CAAC,EAC7D,aAAa,MAAM,eAAe,GAAG,OAAO,CAAC,eAAe,CAAC,SAyd9D,CAAC"}
package/dist/tests.mjs CHANGED
@@ -47,6 +47,7 @@ function continueStream(graffiti, streamReturn, type, session) {
47
47
  }
48
48
 
49
49
  // tests/crud.ts
50
+ import { randomPostObject as randomPostObject2 } from "@graffiti-garden/api/tests";
50
51
  var graffitiCRUDTests = (useGraffiti, useSession1, useSession2) => {
51
52
  describe.concurrent(
52
53
  "CRUD",
@@ -267,6 +268,24 @@ var graffitiCRUDTests = (useGraffiti, useSession1, useSession2) => {
267
268
  const gotten = await graffiti.get(output, {}, session1);
268
269
  expect(gotten).toEqual(output);
269
270
  });
271
+ it("multi 'device' get", async () => {
272
+ const graffiti1 = useGraffiti();
273
+ const graffiti2 = useGraffiti();
274
+ const prepost = randomPostObject2();
275
+ const posted = await graffiti1.post(prepost, session1);
276
+ const gotten1 = await graffiti1.get(posted, {}, session1);
277
+ const gotten2 = await graffiti2.get(posted, {}, session1);
278
+ expect(gotten1).toEqual(posted);
279
+ expect(gotten2).toEqual(posted);
280
+ await graffiti1.delete(posted, session1);
281
+ await expect(graffiti1.get(posted, {}, session1)).rejects.toThrow(
282
+ GraffitiErrorNotFound
283
+ );
284
+ await new Promise((resolve) => setTimeout(resolve, 1e3));
285
+ await expect(graffiti2.get(posted, {}, session1)).rejects.toThrow(
286
+ GraffitiErrorNotFound
287
+ );
288
+ });
270
289
  }
271
290
  );
272
291
  };
@@ -609,6 +628,38 @@ var graffitiDiscoverTests = (useGraffiti, useSession1, useSession2) => {
609
628
  expect2(counts.get("something")).toBe(2);
610
629
  expect2(counts.get("other")).toBe(1);
611
630
  });
631
+ it2("multi 'device' discover", async () => {
632
+ const graffiti1 = useGraffiti();
633
+ const graffiti2 = useGraffiti();
634
+ const prepost = randomPostObject();
635
+ const posted = await graffiti1.post(prepost, session1);
636
+ const iterator1 = graffiti1.discover(prepost.channels, {}, session1);
637
+ const iterator2 = graffiti2.discover(prepost.channels, {}, session1);
638
+ const next1 = await iterator1.next();
639
+ const next2 = await iterator2.next();
640
+ assert2(!next1.done && !next1.value.error);
641
+ assert2(!next2.done && !next2.value.error);
642
+ expect2(next1.value.object).toEqual(posted);
643
+ expect2(next2.value.object).toEqual(posted);
644
+ const next3 = await iterator1.next();
645
+ const next4 = await iterator2.next();
646
+ assert2(next3.done);
647
+ assert2(next4.done);
648
+ await graffiti1.delete(posted, session1);
649
+ const iterator3 = next3.value.continue(session1);
650
+ const next5 = await iterator3.next();
651
+ assert2(!next5.done && !next5.value.error);
652
+ expect2(next5.value.tombstone).toBe(true);
653
+ expect2(next5.value.object.url).toEqual(posted.url);
654
+ await expect2(iterator3.next()).resolves.toHaveProperty("done", true);
655
+ await new Promise((resolve) => setTimeout(resolve, 1e3));
656
+ const iterator4 = next4.value.continue(session1);
657
+ const next6 = await iterator4.next();
658
+ assert2(!next6.done && !next6.value.error);
659
+ expect2(next6.value.tombstone).toBe(true);
660
+ expect2(next6.value.object.url).toEqual(posted.url);
661
+ await expect2(iterator4.next()).resolves.toHaveProperty("done", true);
662
+ });
612
663
  for (const continueType of ["cursor", "continue"]) {
613
664
  describe2(`continue discover with ${continueType}`, () => {
614
665
  it2("discover for deleted content", async () => {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../tests/crud.ts", "../tests/utils.ts", "../tests/discover.ts", "../tests/media.ts"],
4
- "sourcesContent": ["import { it, expect, describe, beforeAll } from \"vitest\";\nimport type {\n Graffiti,\n GraffitiSession,\n JSONSchema,\n} from \"@graffiti-garden/api\";\nimport {\n GraffitiErrorNotFound,\n GraffitiErrorSchemaMismatch,\n GraffitiErrorInvalidSchema,\n GraffitiErrorForbidden,\n} from \"@graffiti-garden/api\";\nimport { randomString, randomUrl } from \"./utils.js\";\n\nexport const graffitiCRUDTests = (\n useGraffiti: () => Pick<Graffiti, \"post\" | \"get\" | \"delete\">,\n useSession1: () => GraffitiSession | Promise<GraffitiSession>,\n useSession2: () => GraffitiSession | Promise<GraffitiSession>,\n) => {\n describe.concurrent(\n \"CRUD\",\n {\n timeout: 20000,\n },\n () => {\n let graffiti: ReturnType<typeof useGraffiti>;\n let session: GraffitiSession;\n let session1: GraffitiSession;\n let session2: GraffitiSession;\n beforeAll(async () => {\n graffiti = useGraffiti();\n session1 = await useSession1();\n session = session1;\n session2 = await useSession2();\n });\n\n it(\"get nonexistant object\", async () => {\n await expect(graffiti.get(randomUrl(), {})).rejects.toThrow(\n GraffitiErrorNotFound,\n );\n });\n\n it(\"post, get, delete\", async () => {\n const value = {\n something: \"hello, world~ c:\",\n };\n const channels = [randomString(), randomString()];\n\n // Post the object\n const previous = await graffiti.post<{}>({ value, channels }, session);\n expect(previous.value).toEqual(value);\n expect(previous.channels).toEqual(channels);\n expect(previous.allowed).toEqual(undefined);\n expect(previous.actor).toEqual(session.actor);\n\n // Get it back\n const gotten = await graffiti.get(previous, {});\n expect(gotten.value).toEqual(value);\n expect(gotten.channels).toEqual([]);\n expect(gotten.allowed).toBeUndefined();\n expect(gotten.url).toEqual(previous.url);\n expect(gotten.actor).toEqual(previous.actor);\n\n // Delete it\n const deleted = await graffiti.delete(gotten, session);\n expect(deleted.value).toEqual(value);\n expect(deleted.channels).toEqual(channels);\n expect(deleted.allowed).toBeUndefined();\n expect(deleted.actor).toEqual(session.actor);\n expect(deleted.url).toEqual(previous.url);\n\n // Get is not found\n await expect(graffiti.get(gotten, {})).rejects.toBeInstanceOf(\n GraffitiErrorNotFound,\n );\n\n // Delete it again\n await expect(graffiti.delete(gotten, session)).rejects.toThrow(\n GraffitiErrorNotFound,\n );\n });\n\n it(\"post then delete with wrong actor\", async () => {\n const posted = await graffiti.post<{}>(\n { value: {}, channels: [] },\n session2,\n );\n\n await expect(graffiti.delete(posted, session1)).rejects.toThrow(\n GraffitiErrorForbidden,\n );\n });\n\n it(\"post and get with schema\", async () => {\n const schema = {\n properties: {\n value: {\n properties: {\n something: {\n type: \"string\",\n },\n another: {\n type: \"array\",\n items: {\n type: \"number\",\n },\n },\n deeper: {\n type: \"object\",\n properties: {\n deepProp: {\n type: \"string\",\n },\n },\n required: [\"deepProp\"],\n },\n },\n required: [\"another\", \"deeper\"],\n },\n },\n } as const satisfies JSONSchema;\n\n const goodValue = {\n something: \"hello\",\n another: [1, 2, 3],\n deeper: {\n deepProp: \"hello\",\n },\n };\n\n const posted = await graffiti.post<typeof schema>(\n {\n value: goodValue,\n channels: [],\n },\n session,\n );\n const gotten = await graffiti.get(posted, schema);\n\n expect(gotten.value.something).toEqual(goodValue.something);\n expect(gotten.value.another).toEqual(goodValue.another);\n expect(gotten.value.another[0]).toEqual(1);\n expect(gotten.value.deeper.deepProp).toEqual(goodValue.deeper.deepProp);\n });\n\n it(\"post and get with invalid schema\", async () => {\n const posted = await graffiti.post<{}>(\n { value: {}, channels: [] },\n session,\n );\n await expect(\n graffiti.get(posted, {\n properties: {\n value: {\n //@ts-ignore\n type: \"asdf\",\n },\n },\n }),\n ).rejects.toThrow(GraffitiErrorInvalidSchema);\n });\n\n it(\"post and get with wrong schema\", async () => {\n const posted = await graffiti.post<{}>(\n {\n value: {\n hello: \"world\",\n },\n channels: [],\n },\n session,\n );\n\n await expect(\n graffiti.get(posted, {\n properties: {\n value: {\n properties: {\n hello: {\n type: \"number\",\n },\n },\n },\n },\n }),\n ).rejects.toThrow(GraffitiErrorSchemaMismatch);\n });\n\n it(\"post and get with empty access control\", async () => {\n const value = {\n um: \"hi\",\n };\n const allowed = [randomUrl()];\n const channels = [randomString()];\n const posted = await graffiti.post<{}>(\n { value, allowed, channels },\n session1,\n );\n\n // Get it with authenticated session\n const gotten = await graffiti.get(posted, {}, session1);\n expect(gotten.url).toEqual(posted.url);\n expect(gotten.actor).toEqual(session1.actor);\n expect(gotten.value).toEqual(value);\n expect(gotten.allowed).toEqual(allowed);\n expect(gotten.channels).toEqual(channels);\n\n // But not without session\n await expect(graffiti.get(posted, {})).rejects.toBeInstanceOf(\n GraffitiErrorNotFound,\n );\n\n // Or the wrong session\n await expect(graffiti.get(posted, {}, session2)).rejects.toBeInstanceOf(\n GraffitiErrorNotFound,\n );\n });\n\n it(\"post and get with specific access control\", async () => {\n const value = {\n um: \"hi\",\n };\n const allowed = [randomUrl(), session2.actor, randomUrl()];\n const channels = [randomString()];\n const posted = await graffiti.post<{}>(\n {\n value,\n allowed,\n channels,\n },\n session1,\n );\n\n // Get it with authenticated session\n const gotten = await graffiti.get(posted, {}, session1);\n expect(gotten.url).toEqual(posted.url);\n expect(gotten.actor).toEqual(session1.actor);\n expect(gotten.value).toEqual(value);\n expect(gotten.allowed).toEqual(allowed);\n expect(gotten.channels).toEqual(channels);\n\n // But not without session\n await expect(graffiti.get(posted, {})).rejects.toBeInstanceOf(\n GraffitiErrorNotFound,\n );\n\n const gotten2 = await graffiti.get(posted, {}, session2);\n expect(gotten.url).toEqual(posted.url);\n expect(gotten.actor).toEqual(session1.actor);\n expect(gotten2.value).toEqual(value);\n // They should only see that is is private to them\n expect(gotten2.allowed).toEqual([session2.actor]);\n // And not see any channels\n expect(gotten2.channels).toEqual([]);\n });\n\n it(\"post and get with extra values\", async () => {\n const value = {\n something: \"hello, world~ c:\",\n };\n const channels = [randomString(), randomString()];\n\n const post = {\n value,\n channels,\n extra: \"extra value\",\n };\n\n // Post the object\n const output = await graffiti.post<{}>(post, session);\n expect(output.actor).toEqual(session1.actor);\n expect(output.value).toEqual(value);\n expect(output.allowed).toBeUndefined();\n expect(output.channels).toEqual(channels);\n expect(output).not.toHaveProperty(\"extra\");\n\n const gotten = await graffiti.get<{}>(output, {}, session1);\n expect(gotten).toEqual(output);\n });\n },\n );\n};\n", "import { assert } from \"vitest\";\nimport type {\n GraffitiPostObject,\n GraffitiObjectStream,\n JSONSchema,\n GraffitiObject,\n GraffitiObjectStreamReturn,\n Graffiti,\n GraffitiSession,\n} from \"@graffiti-garden/api\";\n\nexport function randomString(): string {\n const array = new Uint8Array(16);\n crypto.getRandomValues(array);\n const str = Array.from(array)\n .map((b) => b.toString(16).padStart(2, \"0\"))\n .join(\"\");\n\n // check for unicode support\n return str + \"\uD83D\uDC69\uD83C\uDFFD\u200D\u2764\uFE0F\u200D\uD83D\uDC8B\u200D\uD83D\uDC69\uD83C\uDFFB\uD83E\uDEF1\uD83C\uDFFC\u200D\uD83E\uDEF2\uD83C\uDFFF\";\n}\nexport function randomUrl(): string {\n return \"test:\" + randomString();\n}\n\nexport function randomValue() {\n return {\n [randomString()]: randomString(),\n };\n}\n\nexport function randomPostObject(): GraffitiPostObject<{}> {\n return {\n value: randomValue(),\n channels: [randomString(), randomString()],\n };\n}\n\nexport async function nextStreamValue<Schema extends JSONSchema>(\n iterator: GraffitiObjectStream<Schema>,\n): Promise<GraffitiObject<Schema>> {\n const result = await iterator.next();\n assert(!result.done && !result.value.error, \"result has no value\");\n assert(!result.value.tombstone, \"result has been deleted!\");\n return result.value.object;\n}\n\nexport function continueStream<Schema extends JSONSchema>(\n graffiti: Pick<Graffiti, \"continueDiscover\">,\n streamReturn: GraffitiObjectStreamReturn<Schema>,\n type: \"cursor\" | \"continue\",\n session?: GraffitiSession | null,\n): GraffitiObjectStream<Schema> {\n if (type === \"cursor\") {\n return graffiti.continueDiscover(\n streamReturn.cursor,\n session,\n ) as unknown as GraffitiObjectStream<Schema>;\n } else {\n return streamReturn.continue();\n }\n}\n", "import { it, expect, describe, assert, beforeAll } from \"vitest\";\nimport type {\n Graffiti,\n GraffitiSession,\n JSONSchema,\n} from \"@graffiti-garden/api\";\nimport {\n GraffitiErrorCursorExpired,\n GraffitiErrorForbidden,\n GraffitiErrorInvalidSchema,\n} from \"@graffiti-garden/api\";\nimport {\n randomString,\n nextStreamValue,\n randomPostObject,\n continueStream,\n randomUrl,\n} from \"./utils.js\";\n\nexport const graffitiDiscoverTests = (\n useGraffiti: () => Pick<\n Graffiti,\n \"discover\" | \"post\" | \"delete\" | \"continueDiscover\"\n >,\n useSession1: () => GraffitiSession | Promise<GraffitiSession>,\n useSession2: () => GraffitiSession | Promise<GraffitiSession>,\n) => {\n describe.concurrent(\"discover\", { timeout: 20000 }, () => {\n let graffiti: ReturnType<typeof useGraffiti>;\n let session: GraffitiSession;\n let session1: GraffitiSession;\n let session2: GraffitiSession;\n beforeAll(async () => {\n graffiti = useGraffiti();\n session1 = await useSession1();\n session = session1;\n session2 = await useSession2();\n });\n\n it(\"discover nothing\", async () => {\n const iterator = graffiti.discover([], {});\n expect(await iterator.next()).toHaveProperty(\"done\", true);\n });\n\n it(\"discover single\", async () => {\n const object = randomPostObject();\n\n const posted = await graffiti.post<{}>(object, session);\n\n const queryChannels = [randomString(), object.channels[0]];\n const iterator = graffiti.discover<{}>(queryChannels, {});\n const value = await nextStreamValue<{}>(iterator);\n expect(value.url).toEqual(posted.url);\n expect(value.value).toEqual(object.value);\n expect(value.channels).toEqual([object.channels[0]]);\n expect(value.allowed).toBeUndefined();\n expect(value.actor).toEqual(session.actor);\n const result2 = await iterator.next();\n expect(result2.done).toBe(true);\n });\n\n it(\"discover wrong channel\", async () => {\n const object = randomPostObject();\n await graffiti.post<{}>(object, session);\n const iterator = graffiti.discover([randomString()], {});\n await expect(iterator.next()).resolves.toHaveProperty(\"done\", true);\n });\n\n it(\"discover not allowed\", async () => {\n const object = randomPostObject();\n object.allowed = [randomUrl(), randomUrl()];\n const posted = await graffiti.post<{}>(object, session1);\n\n const iteratorSession1 = graffiti.discover<{}>(\n object.channels,\n {},\n session1,\n );\n const value = await nextStreamValue<{}>(iteratorSession1);\n expect(value.url).toEqual(posted.url);\n expect(value.value).toEqual(object.value);\n expect(value.channels).toEqual(object.channels);\n expect(value.allowed).toEqual(object.allowed);\n expect(value.actor).toEqual(session1.actor);\n\n const iteratorSession2 = graffiti.discover(object.channels, {}, session2);\n expect(await iteratorSession2.next()).toHaveProperty(\"done\", true);\n\n const iteratorNoSession = graffiti.discover(object.channels, {});\n expect(await iteratorNoSession.next()).toHaveProperty(\"done\", true);\n });\n\n it(\"discover allowed\", async () => {\n const object = randomPostObject();\n object.allowed = [randomUrl(), session2.actor, randomUrl()];\n const posted = await graffiti.post<{}>(object, session1);\n\n const iteratorSession2 = graffiti.discover<{}>(\n object.channels,\n {},\n session2,\n );\n const value = await nextStreamValue<{}>(iteratorSession2);\n expect(value.url).toEqual(posted.url);\n expect(value.value).toEqual(object.value);\n expect(value.allowed).toEqual([session2.actor]);\n expect(value.channels).toEqual(object.channels);\n expect(value.actor).toEqual(session1.actor);\n });\n\n it(\"discover bad schema\", async () => {\n const iterator = graffiti.discover([], {\n properties: {\n value: {\n //@ts-ignore\n type: \"asdf\",\n },\n },\n });\n\n await expect(iterator.next()).rejects.toThrow(GraffitiErrorInvalidSchema);\n });\n\n it(\"discover for actor\", async () => {\n const object1 = randomPostObject();\n const posted1 = await graffiti.post<{}>(object1, session1);\n\n const object2 = randomPostObject();\n object2.channels = object1.channels;\n const posted2 = await graffiti.post<{}>(object2, session2);\n\n const iterator = graffiti.discover<{}>(object1.channels, {\n properties: {\n actor: { const: posted1.actor },\n },\n });\n\n const value = await nextStreamValue<{}>(iterator);\n expect(value.url).toEqual(posted1.url);\n expect(value.url).not.toEqual(posted2.url);\n expect(value.value).toEqual(object1.value);\n await expect(iterator.next()).resolves.toHaveProperty(\"done\", true);\n });\n\n it(\"discover schema allowed, as and not as owner\", async () => {\n const object = randomPostObject();\n object.allowed = [randomUrl(), session2.actor, randomUrl()];\n await graffiti.post<{}>(object, session1);\n\n const iteratorSession1 = graffiti.discover<{}>(\n object.channels,\n {\n properties: {\n allowed: {\n minItems: 3,\n // Make sure session2.actor is in the allow list\n not: {\n items: {\n not: { const: session2.actor },\n },\n },\n },\n },\n },\n session1,\n );\n const value = await nextStreamValue<{}>(iteratorSession1);\n expect(value.value).toEqual(object.value);\n await expect(iteratorSession1.next()).resolves.toHaveProperty(\n \"done\",\n true,\n );\n\n const iteratorSession2BigAllow = graffiti.discover(\n object.channels,\n {\n properties: {\n allowed: {\n minItems: 3,\n },\n },\n },\n session2,\n );\n await expect(iteratorSession2BigAllow.next()).resolves.toHaveProperty(\n \"done\",\n true,\n );\n const iteratorSession2PeekOther = graffiti.discover(\n object.channels,\n {\n properties: {\n allowed: {\n not: {\n items: {\n not: { const: object.allowed[0] },\n },\n },\n },\n },\n },\n session2,\n );\n await expect(iteratorSession2PeekOther.next()).resolves.toHaveProperty(\n \"done\",\n true,\n );\n const iteratorSession2SmallAllowPeekSelf = graffiti.discover<{}>(\n object.channels,\n {\n properties: {\n allowed: {\n maxItems: 1,\n not: {\n items: {\n not: { const: session2.actor },\n },\n },\n },\n },\n },\n session2,\n );\n const value2 = await nextStreamValue<{}>(\n iteratorSession2SmallAllowPeekSelf,\n );\n expect(value2.value).toEqual(object.value);\n await expect(\n iteratorSession2SmallAllowPeekSelf.next(),\n ).resolves.toHaveProperty(\"done\", true);\n });\n\n it(\"discover schema channels, as and not as owner\", async () => {\n const object = randomPostObject();\n object.channels = [randomString(), randomString(), randomString()];\n await graffiti.post<{}>(object, session1);\n\n const iteratorSession1 = graffiti.discover<{}>(\n [object.channels[0], object.channels[2]],\n {\n properties: {\n channels: {\n minItems: 3,\n // Make sure channel 1 is in the allow list\n not: {\n items: {\n not: { const: object.channels[1] },\n },\n },\n },\n },\n },\n session1,\n );\n const value = await nextStreamValue<{}>(iteratorSession1);\n expect(value.value).toEqual(object.value);\n await expect(iteratorSession1.next()).resolves.toHaveProperty(\n \"done\",\n true,\n );\n\n const iteratorSession2BigAllow = graffiti.discover(\n [object.channels[0], object.channels[2]],\n {\n properties: {\n channels: {\n minItems: 3,\n },\n },\n },\n session2,\n );\n await expect(iteratorSession2BigAllow.next()).resolves.toHaveProperty(\n \"done\",\n true,\n );\n const iteratorSession2PeekOther = graffiti.discover(\n [object.channels[0], object.channels[2]],\n {\n properties: {\n channels: {\n not: {\n items: {\n not: { const: object.channels[1] },\n },\n },\n },\n },\n },\n session2,\n );\n await expect(iteratorSession2PeekOther.next()).resolves.toHaveProperty(\n \"done\",\n true,\n );\n const iteratorSession2SmallAllowPeekSelf = graffiti.discover<{}>(\n [object.channels[0], object.channels[2]],\n {\n properties: {\n allowed: {\n maxItems: 2,\n not: {\n items: {\n not: { const: object.channels[2] },\n },\n },\n },\n },\n },\n session2,\n );\n const value2 = await nextStreamValue<{}>(\n iteratorSession2SmallAllowPeekSelf,\n );\n expect(value2.value).toEqual(object.value);\n await expect(\n iteratorSession2SmallAllowPeekSelf.next(),\n ).resolves.toHaveProperty(\"done\", true);\n });\n\n it(\"discover query for empty allowed\", async () => {\n const publicO = randomPostObject();\n\n const publicSchema = {\n not: {\n required: [\"allowed\"],\n },\n } satisfies JSONSchema;\n\n await graffiti.post<{}>(publicO, session1);\n const iterator = graffiti.discover<{}>(\n publicO.channels,\n publicSchema,\n session1,\n );\n const value = await nextStreamValue<{}>(iterator);\n expect(value.value).toEqual(publicO.value);\n expect(value.allowed).toBeUndefined();\n await expect(iterator.next()).resolves.toHaveProperty(\"done\", true);\n\n const restricted = randomPostObject();\n restricted.allowed = [];\n await graffiti.post<{}>(restricted, session1);\n const iterator2 = graffiti.discover(\n restricted.channels,\n publicSchema,\n session1,\n );\n await expect(iterator2.next()).resolves.toHaveProperty(\"done\", true);\n });\n\n it(\"discover query for values\", async () => {\n const object1 = randomPostObject();\n object1.value = { test: randomString() };\n await graffiti.post<{}>(object1, session);\n\n const object2 = randomPostObject();\n object2.channels = object1.channels;\n object2.value = { test: randomString(), something: randomString() };\n await graffiti.post<{}>(object2, session);\n\n const object3 = randomPostObject();\n object3.channels = object1.channels;\n object3.value = { other: randomString(), something: randomString() };\n await graffiti.post<{}>(object3, session);\n\n const counts = new Map<string, number>();\n for (const property of [\"test\", \"something\", \"other\"] as const) {\n let count = 0;\n for await (const result of graffiti.discover(object1.channels, {\n properties: {\n value: {\n required: [property],\n },\n },\n })) {\n assert(!result.error, \"result has error\");\n assert(!result.tombstone, \"result is tombstone\");\n if (property in result.object.value) {\n count++;\n }\n }\n counts.set(property, count);\n }\n\n expect(counts.get(\"test\")).toBe(2);\n expect(counts.get(\"something\")).toBe(2);\n expect(counts.get(\"other\")).toBe(1);\n });\n\n for (const continueType of [\"cursor\", \"continue\"] as const) {\n describe(`continue discover with ${continueType}`, () => {\n it(\"discover for deleted content\", async () => {\n const object = randomPostObject();\n\n const posted = await graffiti.post<{}>(object, session);\n\n const iterator1 = graffiti.discover<{}>(object.channels, {});\n const value1 = await nextStreamValue<{}>(iterator1);\n expect(value1.value).toEqual(object.value);\n const returnValue = await iterator1.next();\n assert(returnValue.done, \"value2 is not done\");\n\n await graffiti.delete(posted, session);\n\n const tombIterator = continueStream<{}>(\n graffiti,\n returnValue.value,\n continueType,\n );\n const value = await tombIterator.next();\n assert(!value.done && !value.value.error, \"value is done\");\n assert(value.value.tombstone, \"value is not tombstone\");\n expect(value.value.object.url).toEqual(posted.url);\n const returnValue2 = await tombIterator.next();\n assert(returnValue2.done, \"value2 is not done\");\n\n // Post another object\n const posted2 = await graffiti.post<{}>(object, session);\n const doubleContinueIterator = continueStream<{}>(\n graffiti,\n returnValue2.value,\n continueType,\n );\n const value2 = await doubleContinueIterator.next();\n assert(!value2.done && !value2.value.error, \"value2 is done\");\n assert(!value2.value.tombstone, \"value2 is tombstone\");\n expect(value2.value.object.url).toEqual(posted2.url);\n await expect(doubleContinueIterator.next()).resolves.toHaveProperty(\n \"done\",\n true,\n );\n });\n\n it(\"continue with wrong actor\", async () => {\n const iterator = graffiti.discover<{}>([], {}, session1);\n const result = await iterator.next();\n assert(result.done, \"iterator is not done\");\n\n const continuation = continueStream<{}>(\n graffiti,\n result.value,\n continueType,\n session2,\n );\n await expect(continuation.next()).rejects.toThrow(\n GraffitiErrorForbidden,\n );\n });\n });\n }\n\n it(\"lookup non-existant cursor\", async () => {\n const iterator = graffiti.continueDiscover(randomString());\n await expect(iterator.next()).rejects.toThrow(GraffitiErrorCursorExpired);\n });\n });\n};\n", "import {\n GraffitiErrorNotAcceptable,\n GraffitiErrorNotFound,\n GraffitiErrorTooLarge,\n type Graffiti,\n type GraffitiSession,\n} from \"@graffiti-garden/api\";\nimport { it, expect, describe, beforeAll } from \"vitest\";\nimport { randomString, randomUrl } from \"./utils.js\";\n\nexport const graffitiMediaTests = (\n useGraffiti: () => Pick<Graffiti, \"postMedia\" | \"getMedia\" | \"deleteMedia\">,\n useSession1: () => GraffitiSession | Promise<GraffitiSession>,\n useSession2: () => GraffitiSession | Promise<GraffitiSession>,\n) => {\n describe.concurrent(\n \"media\",\n {\n timeout: 20000,\n },\n () => {\n let graffiti: ReturnType<typeof useGraffiti>;\n let session: GraffitiSession;\n let session1: GraffitiSession;\n let session2: GraffitiSession;\n beforeAll(async () => {\n graffiti = useGraffiti();\n session1 = await useSession1();\n session = session1;\n session2 = await useSession2();\n });\n\n it(\"post, get, delete media\", async () => {\n // Post media\n const text = randomString();\n const data = new Blob([text], { type: \"text/plain\" });\n const mediaUrl = await graffiti.postMedia({ data }, session);\n\n // Get the media back\n const media = await graffiti.getMedia(mediaUrl, {});\n expect(await media.data.text()).toEqual(text);\n expect(media.data.type).toEqual(\"text/plain\");\n expect(media.allowed).toBeUndefined();\n expect(media.actor).toBe(session.actor);\n\n // Delete the media\n await graffiti.deleteMedia(mediaUrl, session);\n\n // Try to get the media again\n await expect(graffiti.getMedia(mediaUrl, {})).rejects.toThrow(\n GraffitiErrorNotFound,\n );\n });\n\n it(\"acceptable type\", async () => {\n const text = randomString();\n const data = new Blob([text], { type: \"text/plain\" });\n const mediaUrl = await graffiti.postMedia({ data }, session);\n\n const media = await graffiti.getMedia(mediaUrl, {\n types: [\"application/json\", \"text/*\"],\n });\n expect(await media.data.text()).toEqual(text);\n expect(media.data.type).toEqual(\"text/plain\");\n expect(media.allowed).toBeUndefined();\n expect(media.actor).toBe(session.actor);\n });\n\n it(\"unacceptable type\", async () => {\n const text = randomString();\n const data = new Blob([text], { type: \"text/plain\" });\n const mediaUrl = await graffiti.postMedia({ data }, session);\n\n await expect(\n graffiti.getMedia(mediaUrl, {\n types: [\"image/*\"],\n }),\n ).rejects.toThrow(GraffitiErrorNotAcceptable);\n });\n\n it(\"acceptable size\", async () => {\n const text = randomString();\n const data = new Blob([text], { type: \"text/plain\" });\n const mediaUrl = await graffiti.postMedia({ data }, session);\n\n const media = await graffiti.getMedia(mediaUrl, {\n maxBytes: data.size,\n });\n expect(await media.data.text()).toEqual(text);\n expect(media.data.type).toEqual(\"text/plain\");\n expect(media.allowed).toBeUndefined();\n expect(media.actor).toBe(session.actor);\n });\n\n it(\"unacceptable size\", async () => {\n const text = randomString();\n const data = new Blob([text], { type: \"text/plain\" });\n const mediaUrl = await graffiti.postMedia({ data }, session);\n\n await expect(\n graffiti.getMedia(mediaUrl, {\n maxBytes: data.size - 1,\n }),\n ).rejects.toThrow(GraffitiErrorTooLarge);\n });\n\n it(\"empty allowed\", async () => {\n const text = randomString();\n const data = new Blob([text], { type: \"text/plain\" });\n const allowed: string[] = [];\n const mediaUrl = await graffiti.postMedia({ data, allowed }, session1);\n\n // Get it with the authorized user\n const media = await graffiti.getMedia(mediaUrl, {}, session1);\n expect(await media.data.text()).toEqual(text);\n expect(media.data.type).toEqual(\"text/plain\");\n expect(media.allowed).toEqual([]);\n expect(media.actor).toBe(session1.actor);\n\n // Get it with the unauthorized user\n await expect(graffiti.getMedia(mediaUrl, {}, session2)).rejects.toThrow(\n GraffitiErrorNotFound,\n );\n\n // Get it without authorization\n await expect(graffiti.getMedia(mediaUrl, {})).rejects.toThrow(\n GraffitiErrorNotFound,\n );\n });\n\n it(\"allowed\", async () => {\n const text = randomString();\n const data = new Blob([text], { type: \"text/plain\" });\n const allowed = [randomUrl(), session2.actor, randomUrl()];\n const mediaUrl = await graffiti.postMedia({ data, allowed }, session1);\n\n // Get it with the authorized user\n const media = await graffiti.getMedia(mediaUrl, {}, session1);\n expect(await media.data.text()).toEqual(text);\n expect(media.data.type).toEqual(\"text/plain\");\n expect(media.allowed).toEqual(allowed);\n expect(media.actor).toBe(session1.actor);\n\n // Get it with the allowed user\n const media2 = await graffiti.getMedia(mediaUrl, {}, session2);\n expect(await media2.data.text()).toEqual(text);\n expect(media2.data.type).toEqual(\"text/plain\");\n expect(media2.allowed).toEqual([session2.actor]);\n expect(media2.actor).toBe(session1.actor);\n\n // Get it without authorization\n await expect(graffiti.getMedia(mediaUrl, {})).rejects.toThrow(\n GraffitiErrorNotFound,\n );\n });\n },\n );\n};\n"],
5
- "mappings": "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",
6
- "names": ["it", "expect", "describe", "assert", "beforeAll", "GraffitiErrorForbidden", "GraffitiErrorInvalidSchema", "describe", "beforeAll", "it", "expect", "GraffitiErrorInvalidSchema", "assert", "GraffitiErrorForbidden", "GraffitiErrorNotFound", "it", "expect", "describe", "beforeAll", "describe", "beforeAll", "it", "expect", "GraffitiErrorNotFound"]
4
+ "sourcesContent": ["import { it, expect, describe, beforeAll } from \"vitest\";\nimport type {\n Graffiti,\n GraffitiSession,\n JSONSchema,\n} from \"@graffiti-garden/api\";\nimport {\n GraffitiErrorNotFound,\n GraffitiErrorSchemaMismatch,\n GraffitiErrorInvalidSchema,\n GraffitiErrorForbidden,\n} from \"@graffiti-garden/api\";\nimport { randomString, randomUrl } from \"./utils.js\";\nimport { randomPostObject } from \"@graffiti-garden/api/tests\";\n\nexport const graffitiCRUDTests = (\n useGraffiti: () => Pick<Graffiti, \"post\" | \"get\" | \"delete\">,\n useSession1: () => GraffitiSession | Promise<GraffitiSession>,\n useSession2: () => GraffitiSession | Promise<GraffitiSession>,\n) => {\n describe.concurrent(\n \"CRUD\",\n {\n timeout: 20000,\n },\n () => {\n let graffiti: ReturnType<typeof useGraffiti>;\n let session: GraffitiSession;\n let session1: GraffitiSession;\n let session2: GraffitiSession;\n beforeAll(async () => {\n graffiti = useGraffiti();\n session1 = await useSession1();\n session = session1;\n session2 = await useSession2();\n });\n\n it(\"get nonexistant object\", async () => {\n await expect(graffiti.get(randomUrl(), {})).rejects.toThrow(\n GraffitiErrorNotFound,\n );\n });\n\n it(\"post, get, delete\", async () => {\n const value = {\n something: \"hello, world~ c:\",\n };\n const channels = [randomString(), randomString()];\n\n // Post the object\n const previous = await graffiti.post<{}>({ value, channels }, session);\n expect(previous.value).toEqual(value);\n expect(previous.channels).toEqual(channels);\n expect(previous.allowed).toEqual(undefined);\n expect(previous.actor).toEqual(session.actor);\n\n // Get it back\n const gotten = await graffiti.get(previous, {});\n expect(gotten.value).toEqual(value);\n expect(gotten.channels).toEqual([]);\n expect(gotten.allowed).toBeUndefined();\n expect(gotten.url).toEqual(previous.url);\n expect(gotten.actor).toEqual(previous.actor);\n\n // Delete it\n const deleted = await graffiti.delete(gotten, session);\n expect(deleted.value).toEqual(value);\n expect(deleted.channels).toEqual(channels);\n expect(deleted.allowed).toBeUndefined();\n expect(deleted.actor).toEqual(session.actor);\n expect(deleted.url).toEqual(previous.url);\n\n // Get is not found\n await expect(graffiti.get(gotten, {})).rejects.toBeInstanceOf(\n GraffitiErrorNotFound,\n );\n\n // Delete it again\n await expect(graffiti.delete(gotten, session)).rejects.toThrow(\n GraffitiErrorNotFound,\n );\n });\n\n it(\"post then delete with wrong actor\", async () => {\n const posted = await graffiti.post<{}>(\n { value: {}, channels: [] },\n session2,\n );\n\n await expect(graffiti.delete(posted, session1)).rejects.toThrow(\n GraffitiErrorForbidden,\n );\n });\n\n it(\"post and get with schema\", async () => {\n const schema = {\n properties: {\n value: {\n properties: {\n something: {\n type: \"string\",\n },\n another: {\n type: \"array\",\n items: {\n type: \"number\",\n },\n },\n deeper: {\n type: \"object\",\n properties: {\n deepProp: {\n type: \"string\",\n },\n },\n required: [\"deepProp\"],\n },\n },\n required: [\"another\", \"deeper\"],\n },\n },\n } as const satisfies JSONSchema;\n\n const goodValue = {\n something: \"hello\",\n another: [1, 2, 3],\n deeper: {\n deepProp: \"hello\",\n },\n };\n\n const posted = await graffiti.post<typeof schema>(\n {\n value: goodValue,\n channels: [],\n },\n session,\n );\n const gotten = await graffiti.get(posted, schema);\n\n expect(gotten.value.something).toEqual(goodValue.something);\n expect(gotten.value.another).toEqual(goodValue.another);\n expect(gotten.value.another[0]).toEqual(1);\n expect(gotten.value.deeper.deepProp).toEqual(goodValue.deeper.deepProp);\n });\n\n it(\"post and get with invalid schema\", async () => {\n const posted = await graffiti.post<{}>(\n { value: {}, channels: [] },\n session,\n );\n await expect(\n graffiti.get(posted, {\n properties: {\n value: {\n //@ts-ignore\n type: \"asdf\",\n },\n },\n }),\n ).rejects.toThrow(GraffitiErrorInvalidSchema);\n });\n\n it(\"post and get with wrong schema\", async () => {\n const posted = await graffiti.post<{}>(\n {\n value: {\n hello: \"world\",\n },\n channels: [],\n },\n session,\n );\n\n await expect(\n graffiti.get(posted, {\n properties: {\n value: {\n properties: {\n hello: {\n type: \"number\",\n },\n },\n },\n },\n }),\n ).rejects.toThrow(GraffitiErrorSchemaMismatch);\n });\n\n it(\"post and get with empty access control\", async () => {\n const value = {\n um: \"hi\",\n };\n const allowed = [randomUrl()];\n const channels = [randomString()];\n const posted = await graffiti.post<{}>(\n { value, allowed, channels },\n session1,\n );\n\n // Get it with authenticated session\n const gotten = await graffiti.get(posted, {}, session1);\n expect(gotten.url).toEqual(posted.url);\n expect(gotten.actor).toEqual(session1.actor);\n expect(gotten.value).toEqual(value);\n expect(gotten.allowed).toEqual(allowed);\n expect(gotten.channels).toEqual(channels);\n\n // But not without session\n await expect(graffiti.get(posted, {})).rejects.toBeInstanceOf(\n GraffitiErrorNotFound,\n );\n\n // Or the wrong session\n await expect(graffiti.get(posted, {}, session2)).rejects.toBeInstanceOf(\n GraffitiErrorNotFound,\n );\n });\n\n it(\"post and get with specific access control\", async () => {\n const value = {\n um: \"hi\",\n };\n const allowed = [randomUrl(), session2.actor, randomUrl()];\n const channels = [randomString()];\n const posted = await graffiti.post<{}>(\n {\n value,\n allowed,\n channels,\n },\n session1,\n );\n\n // Get it with authenticated session\n const gotten = await graffiti.get(posted, {}, session1);\n expect(gotten.url).toEqual(posted.url);\n expect(gotten.actor).toEqual(session1.actor);\n expect(gotten.value).toEqual(value);\n expect(gotten.allowed).toEqual(allowed);\n expect(gotten.channels).toEqual(channels);\n\n // But not without session\n await expect(graffiti.get(posted, {})).rejects.toBeInstanceOf(\n GraffitiErrorNotFound,\n );\n\n const gotten2 = await graffiti.get(posted, {}, session2);\n expect(gotten.url).toEqual(posted.url);\n expect(gotten.actor).toEqual(session1.actor);\n expect(gotten2.value).toEqual(value);\n // They should only see that is is private to them\n expect(gotten2.allowed).toEqual([session2.actor]);\n // And not see any channels\n expect(gotten2.channels).toEqual([]);\n });\n\n it(\"post and get with extra values\", async () => {\n const value = {\n something: \"hello, world~ c:\",\n };\n const channels = [randomString(), randomString()];\n\n const post = {\n value,\n channels,\n extra: \"extra value\",\n };\n\n // Post the object\n const output = await graffiti.post<{}>(post, session);\n expect(output.actor).toEqual(session1.actor);\n expect(output.value).toEqual(value);\n expect(output.allowed).toBeUndefined();\n expect(output.channels).toEqual(channels);\n expect(output).not.toHaveProperty(\"extra\");\n\n const gotten = await graffiti.get<{}>(output, {}, session1);\n expect(gotten).toEqual(output);\n });\n\n it(\"multi 'device' get\", async () => {\n const graffiti1 = useGraffiti();\n const graffiti2 = useGraffiti();\n\n const prepost = randomPostObject();\n const posted = await graffiti1.post<{}>(prepost, session1);\n\n const gotten1 = await graffiti1.get(posted, {}, session1);\n const gotten2 = await graffiti2.get(posted, {}, session1);\n expect(gotten1).toEqual(posted);\n expect(gotten2).toEqual(posted);\n\n await graffiti1.delete(posted, session1);\n\n await expect(graffiti1.get(posted, {}, session1)).rejects.toThrow(\n GraffitiErrorNotFound,\n );\n\n // Wait for \"labels\" to propogate\n await new Promise((resolve) => setTimeout(resolve, 1000));\n\n await expect(graffiti2.get(posted, {}, session1)).rejects.toThrow(\n GraffitiErrorNotFound,\n );\n });\n },\n );\n};\n", "import { assert } from \"vitest\";\nimport type {\n GraffitiPostObject,\n GraffitiObjectStream,\n JSONSchema,\n GraffitiObject,\n GraffitiObjectStreamReturn,\n Graffiti,\n GraffitiSession,\n} from \"@graffiti-garden/api\";\n\nexport function randomString(): string {\n const array = new Uint8Array(16);\n crypto.getRandomValues(array);\n const str = Array.from(array)\n .map((b) => b.toString(16).padStart(2, \"0\"))\n .join(\"\");\n\n // check for unicode support\n return str + \"\uD83D\uDC69\uD83C\uDFFD\u200D\u2764\uFE0F\u200D\uD83D\uDC8B\u200D\uD83D\uDC69\uD83C\uDFFB\uD83E\uDEF1\uD83C\uDFFC\u200D\uD83E\uDEF2\uD83C\uDFFF\";\n}\nexport function randomUrl(): string {\n return \"test:\" + randomString();\n}\n\nexport function randomValue() {\n return {\n [randomString()]: randomString(),\n };\n}\n\nexport function randomPostObject(): GraffitiPostObject<{}> {\n return {\n value: randomValue(),\n channels: [randomString(), randomString()],\n };\n}\n\nexport async function nextStreamValue<Schema extends JSONSchema>(\n iterator: GraffitiObjectStream<Schema>,\n): Promise<GraffitiObject<Schema>> {\n const result = await iterator.next();\n assert(!result.done && !result.value.error, \"result has no value\");\n assert(!result.value.tombstone, \"result has been deleted!\");\n return result.value.object;\n}\n\nexport function continueStream<Schema extends JSONSchema>(\n graffiti: Pick<Graffiti, \"continueDiscover\">,\n streamReturn: GraffitiObjectStreamReturn<Schema>,\n type: \"cursor\" | \"continue\",\n session?: GraffitiSession | null,\n): GraffitiObjectStream<Schema> {\n if (type === \"cursor\") {\n return graffiti.continueDiscover(\n streamReturn.cursor,\n session,\n ) as unknown as GraffitiObjectStream<Schema>;\n } else {\n return streamReturn.continue();\n }\n}\n", "import { it, expect, describe, assert, beforeAll } from \"vitest\";\nimport type {\n Graffiti,\n GraffitiSession,\n JSONSchema,\n} from \"@graffiti-garden/api\";\nimport {\n GraffitiErrorCursorExpired,\n GraffitiErrorForbidden,\n GraffitiErrorInvalidSchema,\n} from \"@graffiti-garden/api\";\nimport {\n randomString,\n nextStreamValue,\n randomPostObject,\n continueStream,\n randomUrl,\n} from \"./utils.js\";\n\nexport const graffitiDiscoverTests = (\n useGraffiti: () => Pick<\n Graffiti,\n \"discover\" | \"post\" | \"delete\" | \"continueDiscover\"\n >,\n useSession1: () => GraffitiSession | Promise<GraffitiSession>,\n useSession2: () => GraffitiSession | Promise<GraffitiSession>,\n) => {\n describe.concurrent(\"discover\", { timeout: 20000 }, () => {\n let graffiti: ReturnType<typeof useGraffiti>;\n let session: GraffitiSession;\n let session1: GraffitiSession;\n let session2: GraffitiSession;\n beforeAll(async () => {\n graffiti = useGraffiti();\n session1 = await useSession1();\n session = session1;\n session2 = await useSession2();\n });\n\n it(\"discover nothing\", async () => {\n const iterator = graffiti.discover([], {});\n expect(await iterator.next()).toHaveProperty(\"done\", true);\n });\n\n it(\"discover single\", async () => {\n const object = randomPostObject();\n\n const posted = await graffiti.post<{}>(object, session);\n\n const queryChannels = [randomString(), object.channels[0]];\n const iterator = graffiti.discover<{}>(queryChannels, {});\n const value = await nextStreamValue<{}>(iterator);\n expect(value.url).toEqual(posted.url);\n expect(value.value).toEqual(object.value);\n expect(value.channels).toEqual([object.channels[0]]);\n expect(value.allowed).toBeUndefined();\n expect(value.actor).toEqual(session.actor);\n const result2 = await iterator.next();\n expect(result2.done).toBe(true);\n });\n\n it(\"discover wrong channel\", async () => {\n const object = randomPostObject();\n await graffiti.post<{}>(object, session);\n const iterator = graffiti.discover([randomString()], {});\n await expect(iterator.next()).resolves.toHaveProperty(\"done\", true);\n });\n\n it(\"discover not allowed\", async () => {\n const object = randomPostObject();\n object.allowed = [randomUrl(), randomUrl()];\n const posted = await graffiti.post<{}>(object, session1);\n\n const iteratorSession1 = graffiti.discover<{}>(\n object.channels,\n {},\n session1,\n );\n const value = await nextStreamValue<{}>(iteratorSession1);\n expect(value.url).toEqual(posted.url);\n expect(value.value).toEqual(object.value);\n expect(value.channels).toEqual(object.channels);\n expect(value.allowed).toEqual(object.allowed);\n expect(value.actor).toEqual(session1.actor);\n\n const iteratorSession2 = graffiti.discover(object.channels, {}, session2);\n expect(await iteratorSession2.next()).toHaveProperty(\"done\", true);\n\n const iteratorNoSession = graffiti.discover(object.channels, {});\n expect(await iteratorNoSession.next()).toHaveProperty(\"done\", true);\n });\n\n it(\"discover allowed\", async () => {\n const object = randomPostObject();\n object.allowed = [randomUrl(), session2.actor, randomUrl()];\n const posted = await graffiti.post<{}>(object, session1);\n\n const iteratorSession2 = graffiti.discover<{}>(\n object.channels,\n {},\n session2,\n );\n const value = await nextStreamValue<{}>(iteratorSession2);\n expect(value.url).toEqual(posted.url);\n expect(value.value).toEqual(object.value);\n expect(value.allowed).toEqual([session2.actor]);\n expect(value.channels).toEqual(object.channels);\n expect(value.actor).toEqual(session1.actor);\n });\n\n it(\"discover bad schema\", async () => {\n const iterator = graffiti.discover([], {\n properties: {\n value: {\n //@ts-ignore\n type: \"asdf\",\n },\n },\n });\n\n await expect(iterator.next()).rejects.toThrow(GraffitiErrorInvalidSchema);\n });\n\n it(\"discover for actor\", async () => {\n const object1 = randomPostObject();\n const posted1 = await graffiti.post<{}>(object1, session1);\n\n const object2 = randomPostObject();\n object2.channels = object1.channels;\n const posted2 = await graffiti.post<{}>(object2, session2);\n\n const iterator = graffiti.discover<{}>(object1.channels, {\n properties: {\n actor: { const: posted1.actor },\n },\n });\n\n const value = await nextStreamValue<{}>(iterator);\n expect(value.url).toEqual(posted1.url);\n expect(value.url).not.toEqual(posted2.url);\n expect(value.value).toEqual(object1.value);\n await expect(iterator.next()).resolves.toHaveProperty(\"done\", true);\n });\n\n it(\"discover schema allowed, as and not as owner\", async () => {\n const object = randomPostObject();\n object.allowed = [randomUrl(), session2.actor, randomUrl()];\n await graffiti.post<{}>(object, session1);\n\n const iteratorSession1 = graffiti.discover<{}>(\n object.channels,\n {\n properties: {\n allowed: {\n minItems: 3,\n // Make sure session2.actor is in the allow list\n not: {\n items: {\n not: { const: session2.actor },\n },\n },\n },\n },\n },\n session1,\n );\n const value = await nextStreamValue<{}>(iteratorSession1);\n expect(value.value).toEqual(object.value);\n await expect(iteratorSession1.next()).resolves.toHaveProperty(\n \"done\",\n true,\n );\n\n const iteratorSession2BigAllow = graffiti.discover(\n object.channels,\n {\n properties: {\n allowed: {\n minItems: 3,\n },\n },\n },\n session2,\n );\n await expect(iteratorSession2BigAllow.next()).resolves.toHaveProperty(\n \"done\",\n true,\n );\n const iteratorSession2PeekOther = graffiti.discover(\n object.channels,\n {\n properties: {\n allowed: {\n not: {\n items: {\n not: { const: object.allowed[0] },\n },\n },\n },\n },\n },\n session2,\n );\n await expect(iteratorSession2PeekOther.next()).resolves.toHaveProperty(\n \"done\",\n true,\n );\n const iteratorSession2SmallAllowPeekSelf = graffiti.discover<{}>(\n object.channels,\n {\n properties: {\n allowed: {\n maxItems: 1,\n not: {\n items: {\n not: { const: session2.actor },\n },\n },\n },\n },\n },\n session2,\n );\n const value2 = await nextStreamValue<{}>(\n iteratorSession2SmallAllowPeekSelf,\n );\n expect(value2.value).toEqual(object.value);\n await expect(\n iteratorSession2SmallAllowPeekSelf.next(),\n ).resolves.toHaveProperty(\"done\", true);\n });\n\n it(\"discover schema channels, as and not as owner\", async () => {\n const object = randomPostObject();\n object.channels = [randomString(), randomString(), randomString()];\n await graffiti.post<{}>(object, session1);\n\n const iteratorSession1 = graffiti.discover<{}>(\n [object.channels[0], object.channels[2]],\n {\n properties: {\n channels: {\n minItems: 3,\n // Make sure channel 1 is in the allow list\n not: {\n items: {\n not: { const: object.channels[1] },\n },\n },\n },\n },\n },\n session1,\n );\n const value = await nextStreamValue<{}>(iteratorSession1);\n expect(value.value).toEqual(object.value);\n await expect(iteratorSession1.next()).resolves.toHaveProperty(\n \"done\",\n true,\n );\n\n const iteratorSession2BigAllow = graffiti.discover(\n [object.channels[0], object.channels[2]],\n {\n properties: {\n channels: {\n minItems: 3,\n },\n },\n },\n session2,\n );\n await expect(iteratorSession2BigAllow.next()).resolves.toHaveProperty(\n \"done\",\n true,\n );\n const iteratorSession2PeekOther = graffiti.discover(\n [object.channels[0], object.channels[2]],\n {\n properties: {\n channels: {\n not: {\n items: {\n not: { const: object.channels[1] },\n },\n },\n },\n },\n },\n session2,\n );\n await expect(iteratorSession2PeekOther.next()).resolves.toHaveProperty(\n \"done\",\n true,\n );\n const iteratorSession2SmallAllowPeekSelf = graffiti.discover<{}>(\n [object.channels[0], object.channels[2]],\n {\n properties: {\n allowed: {\n maxItems: 2,\n not: {\n items: {\n not: { const: object.channels[2] },\n },\n },\n },\n },\n },\n session2,\n );\n const value2 = await nextStreamValue<{}>(\n iteratorSession2SmallAllowPeekSelf,\n );\n expect(value2.value).toEqual(object.value);\n await expect(\n iteratorSession2SmallAllowPeekSelf.next(),\n ).resolves.toHaveProperty(\"done\", true);\n });\n\n it(\"discover query for empty allowed\", async () => {\n const publicO = randomPostObject();\n\n const publicSchema = {\n not: {\n required: [\"allowed\"],\n },\n } satisfies JSONSchema;\n\n await graffiti.post<{}>(publicO, session1);\n const iterator = graffiti.discover<{}>(\n publicO.channels,\n publicSchema,\n session1,\n );\n const value = await nextStreamValue<{}>(iterator);\n expect(value.value).toEqual(publicO.value);\n expect(value.allowed).toBeUndefined();\n await expect(iterator.next()).resolves.toHaveProperty(\"done\", true);\n\n const restricted = randomPostObject();\n restricted.allowed = [];\n await graffiti.post<{}>(restricted, session1);\n const iterator2 = graffiti.discover(\n restricted.channels,\n publicSchema,\n session1,\n );\n await expect(iterator2.next()).resolves.toHaveProperty(\"done\", true);\n });\n\n it(\"discover query for values\", async () => {\n const object1 = randomPostObject();\n object1.value = { test: randomString() };\n await graffiti.post<{}>(object1, session);\n\n const object2 = randomPostObject();\n object2.channels = object1.channels;\n object2.value = { test: randomString(), something: randomString() };\n await graffiti.post<{}>(object2, session);\n\n const object3 = randomPostObject();\n object3.channels = object1.channels;\n object3.value = { other: randomString(), something: randomString() };\n await graffiti.post<{}>(object3, session);\n\n const counts = new Map<string, number>();\n for (const property of [\"test\", \"something\", \"other\"] as const) {\n let count = 0;\n for await (const result of graffiti.discover(object1.channels, {\n properties: {\n value: {\n required: [property],\n },\n },\n })) {\n assert(!result.error, \"result has error\");\n assert(!result.tombstone, \"result is tombstone\");\n if (property in result.object.value) {\n count++;\n }\n }\n counts.set(property, count);\n }\n\n expect(counts.get(\"test\")).toBe(2);\n expect(counts.get(\"something\")).toBe(2);\n expect(counts.get(\"other\")).toBe(1);\n });\n\n it(\"multi 'device' discover\", async () => {\n const graffiti1 = useGraffiti();\n const graffiti2 = useGraffiti();\n\n const prepost = randomPostObject();\n const posted = await graffiti1.post<{}>(prepost, session1);\n\n const iterator1 = graffiti1.discover(prepost.channels, {}, session1);\n const iterator2 = graffiti2.discover(prepost.channels, {}, session1);\n const next1 = await iterator1.next();\n const next2 = await iterator2.next();\n assert(!next1.done && !next1.value.error);\n assert(!next2.done && !next2.value.error);\n expect(next1.value.object).toEqual(posted);\n expect(next2.value.object).toEqual(posted);\n const next3 = await iterator1.next();\n const next4 = await iterator2.next();\n assert(next3.done);\n assert(next4.done);\n\n await graffiti1.delete(posted, session1);\n\n const iterator3 = next3.value.continue(session1);\n const next5 = await iterator3.next();\n assert(!next5.done && !next5.value.error);\n expect(next5.value.tombstone).toBe(true);\n expect(next5.value.object.url).toEqual(posted.url);\n await expect(iterator3.next()).resolves.toHaveProperty(\"done\", true);\n\n // Wait for \"labels\" to propogate\n // which could introduce a cache bug\n await new Promise((resolve) => setTimeout(resolve, 1000));\n\n const iterator4 = next4.value.continue(session1);\n const next6 = await iterator4.next();\n assert(!next6.done && !next6.value.error);\n expect(next6.value.tombstone).toBe(true);\n expect(next6.value.object.url).toEqual(posted.url);\n await expect(iterator4.next()).resolves.toHaveProperty(\"done\", true);\n });\n\n for (const continueType of [\"cursor\", \"continue\"] as const) {\n describe(`continue discover with ${continueType}`, () => {\n it(\"discover for deleted content\", async () => {\n const object = randomPostObject();\n\n const posted = await graffiti.post<{}>(object, session);\n\n const iterator1 = graffiti.discover<{}>(object.channels, {});\n const value1 = await nextStreamValue<{}>(iterator1);\n expect(value1.value).toEqual(object.value);\n const returnValue = await iterator1.next();\n assert(returnValue.done, \"value2 is not done\");\n\n await graffiti.delete(posted, session);\n\n const tombIterator = continueStream<{}>(\n graffiti,\n returnValue.value,\n continueType,\n );\n const value = await tombIterator.next();\n assert(!value.done && !value.value.error, \"value is done\");\n assert(value.value.tombstone, \"value is not tombstone\");\n expect(value.value.object.url).toEqual(posted.url);\n const returnValue2 = await tombIterator.next();\n assert(returnValue2.done, \"value2 is not done\");\n\n // Post another object\n const posted2 = await graffiti.post<{}>(object, session);\n const doubleContinueIterator = continueStream<{}>(\n graffiti,\n returnValue2.value,\n continueType,\n );\n const value2 = await doubleContinueIterator.next();\n assert(!value2.done && !value2.value.error, \"value2 is done\");\n assert(!value2.value.tombstone, \"value2 is tombstone\");\n expect(value2.value.object.url).toEqual(posted2.url);\n await expect(doubleContinueIterator.next()).resolves.toHaveProperty(\n \"done\",\n true,\n );\n });\n\n it(\"continue with wrong actor\", async () => {\n const iterator = graffiti.discover<{}>([], {}, session1);\n const result = await iterator.next();\n assert(result.done, \"iterator is not done\");\n\n const continuation = continueStream<{}>(\n graffiti,\n result.value,\n continueType,\n session2,\n );\n await expect(continuation.next()).rejects.toThrow(\n GraffitiErrorForbidden,\n );\n });\n });\n }\n\n it(\"lookup non-existant cursor\", async () => {\n const iterator = graffiti.continueDiscover(randomString());\n await expect(iterator.next()).rejects.toThrow(GraffitiErrorCursorExpired);\n });\n });\n};\n", "import {\n GraffitiErrorNotAcceptable,\n GraffitiErrorNotFound,\n GraffitiErrorTooLarge,\n type Graffiti,\n type GraffitiSession,\n} from \"@graffiti-garden/api\";\nimport { it, expect, describe, beforeAll } from \"vitest\";\nimport { randomString, randomUrl } from \"./utils.js\";\n\nexport const graffitiMediaTests = (\n useGraffiti: () => Pick<Graffiti, \"postMedia\" | \"getMedia\" | \"deleteMedia\">,\n useSession1: () => GraffitiSession | Promise<GraffitiSession>,\n useSession2: () => GraffitiSession | Promise<GraffitiSession>,\n) => {\n describe.concurrent(\n \"media\",\n {\n timeout: 20000,\n },\n () => {\n let graffiti: ReturnType<typeof useGraffiti>;\n let session: GraffitiSession;\n let session1: GraffitiSession;\n let session2: GraffitiSession;\n beforeAll(async () => {\n graffiti = useGraffiti();\n session1 = await useSession1();\n session = session1;\n session2 = await useSession2();\n });\n\n it(\"post, get, delete media\", async () => {\n // Post media\n const text = randomString();\n const data = new Blob([text], { type: \"text/plain\" });\n const mediaUrl = await graffiti.postMedia({ data }, session);\n\n // Get the media back\n const media = await graffiti.getMedia(mediaUrl, {});\n expect(await media.data.text()).toEqual(text);\n expect(media.data.type).toEqual(\"text/plain\");\n expect(media.allowed).toBeUndefined();\n expect(media.actor).toBe(session.actor);\n\n // Delete the media\n await graffiti.deleteMedia(mediaUrl, session);\n\n // Try to get the media again\n await expect(graffiti.getMedia(mediaUrl, {})).rejects.toThrow(\n GraffitiErrorNotFound,\n );\n });\n\n it(\"acceptable type\", async () => {\n const text = randomString();\n const data = new Blob([text], { type: \"text/plain\" });\n const mediaUrl = await graffiti.postMedia({ data }, session);\n\n const media = await graffiti.getMedia(mediaUrl, {\n types: [\"application/json\", \"text/*\"],\n });\n expect(await media.data.text()).toEqual(text);\n expect(media.data.type).toEqual(\"text/plain\");\n expect(media.allowed).toBeUndefined();\n expect(media.actor).toBe(session.actor);\n });\n\n it(\"unacceptable type\", async () => {\n const text = randomString();\n const data = new Blob([text], { type: \"text/plain\" });\n const mediaUrl = await graffiti.postMedia({ data }, session);\n\n await expect(\n graffiti.getMedia(mediaUrl, {\n types: [\"image/*\"],\n }),\n ).rejects.toThrow(GraffitiErrorNotAcceptable);\n });\n\n it(\"acceptable size\", async () => {\n const text = randomString();\n const data = new Blob([text], { type: \"text/plain\" });\n const mediaUrl = await graffiti.postMedia({ data }, session);\n\n const media = await graffiti.getMedia(mediaUrl, {\n maxBytes: data.size,\n });\n expect(await media.data.text()).toEqual(text);\n expect(media.data.type).toEqual(\"text/plain\");\n expect(media.allowed).toBeUndefined();\n expect(media.actor).toBe(session.actor);\n });\n\n it(\"unacceptable size\", async () => {\n const text = randomString();\n const data = new Blob([text], { type: \"text/plain\" });\n const mediaUrl = await graffiti.postMedia({ data }, session);\n\n await expect(\n graffiti.getMedia(mediaUrl, {\n maxBytes: data.size - 1,\n }),\n ).rejects.toThrow(GraffitiErrorTooLarge);\n });\n\n it(\"empty allowed\", async () => {\n const text = randomString();\n const data = new Blob([text], { type: \"text/plain\" });\n const allowed: string[] = [];\n const mediaUrl = await graffiti.postMedia({ data, allowed }, session1);\n\n // Get it with the authorized user\n const media = await graffiti.getMedia(mediaUrl, {}, session1);\n expect(await media.data.text()).toEqual(text);\n expect(media.data.type).toEqual(\"text/plain\");\n expect(media.allowed).toEqual([]);\n expect(media.actor).toBe(session1.actor);\n\n // Get it with the unauthorized user\n await expect(graffiti.getMedia(mediaUrl, {}, session2)).rejects.toThrow(\n GraffitiErrorNotFound,\n );\n\n // Get it without authorization\n await expect(graffiti.getMedia(mediaUrl, {})).rejects.toThrow(\n GraffitiErrorNotFound,\n );\n });\n\n it(\"allowed\", async () => {\n const text = randomString();\n const data = new Blob([text], { type: \"text/plain\" });\n const allowed = [randomUrl(), session2.actor, randomUrl()];\n const mediaUrl = await graffiti.postMedia({ data, allowed }, session1);\n\n // Get it with the authorized user\n const media = await graffiti.getMedia(mediaUrl, {}, session1);\n expect(await media.data.text()).toEqual(text);\n expect(media.data.type).toEqual(\"text/plain\");\n expect(media.allowed).toEqual(allowed);\n expect(media.actor).toBe(session1.actor);\n\n // Get it with the allowed user\n const media2 = await graffiti.getMedia(mediaUrl, {}, session2);\n expect(await media2.data.text()).toEqual(text);\n expect(media2.data.type).toEqual(\"text/plain\");\n expect(media2.allowed).toEqual([session2.actor]);\n expect(media2.actor).toBe(session1.actor);\n\n // Get it without authorization\n await expect(graffiti.getMedia(mediaUrl, {})).rejects.toThrow(\n GraffitiErrorNotFound,\n );\n });\n },\n );\n};\n"],
5
+ "mappings": "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",
6
+ "names": ["randomPostObject", "it", "expect", "describe", "assert", "beforeAll", "GraffitiErrorForbidden", "GraffitiErrorInvalidSchema", "describe", "beforeAll", "it", "expect", "GraffitiErrorInvalidSchema", "assert", "GraffitiErrorForbidden", "GraffitiErrorNotFound", "it", "expect", "describe", "beforeAll", "describe", "beforeAll", "it", "expect", "GraffitiErrorNotFound"]
7
7
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@graffiti-garden/api",
3
- "version": "1.1.0",
3
+ "version": "1.1.1",
4
4
  "description": "The heart of Graffiti",
5
5
  "types": "./dist/src/index.d.ts",
6
6
  "module": "./dist/esm/index.js",
package/tests/crud.ts CHANGED
@@ -11,6 +11,7 @@ import {
11
11
  GraffitiErrorForbidden,
12
12
  } from "@graffiti-garden/api";
13
13
  import { randomString, randomUrl } from "./utils.js";
14
+ import { randomPostObject } from "@graffiti-garden/api/tests";
14
15
 
15
16
  export const graffitiCRUDTests = (
16
17
  useGraffiti: () => Pick<Graffiti, "post" | "get" | "delete">,
@@ -277,6 +278,32 @@ export const graffitiCRUDTests = (
277
278
  const gotten = await graffiti.get<{}>(output, {}, session1);
278
279
  expect(gotten).toEqual(output);
279
280
  });
281
+
282
+ it("multi 'device' get", async () => {
283
+ const graffiti1 = useGraffiti();
284
+ const graffiti2 = useGraffiti();
285
+
286
+ const prepost = randomPostObject();
287
+ const posted = await graffiti1.post<{}>(prepost, session1);
288
+
289
+ const gotten1 = await graffiti1.get(posted, {}, session1);
290
+ const gotten2 = await graffiti2.get(posted, {}, session1);
291
+ expect(gotten1).toEqual(posted);
292
+ expect(gotten2).toEqual(posted);
293
+
294
+ await graffiti1.delete(posted, session1);
295
+
296
+ await expect(graffiti1.get(posted, {}, session1)).rejects.toThrow(
297
+ GraffitiErrorNotFound,
298
+ );
299
+
300
+ // Wait for "labels" to propogate
301
+ await new Promise((resolve) => setTimeout(resolve, 1000));
302
+
303
+ await expect(graffiti2.get(posted, {}, session1)).rejects.toThrow(
304
+ GraffitiErrorNotFound,
305
+ );
306
+ });
280
307
  },
281
308
  );
282
309
  };
package/tests/discover.ts CHANGED
@@ -388,6 +388,47 @@ export const graffitiDiscoverTests = (
388
388
  expect(counts.get("other")).toBe(1);
389
389
  });
390
390
 
391
+ it("multi 'device' discover", async () => {
392
+ const graffiti1 = useGraffiti();
393
+ const graffiti2 = useGraffiti();
394
+
395
+ const prepost = randomPostObject();
396
+ const posted = await graffiti1.post<{}>(prepost, session1);
397
+
398
+ const iterator1 = graffiti1.discover(prepost.channels, {}, session1);
399
+ const iterator2 = graffiti2.discover(prepost.channels, {}, session1);
400
+ const next1 = await iterator1.next();
401
+ const next2 = await iterator2.next();
402
+ assert(!next1.done && !next1.value.error);
403
+ assert(!next2.done && !next2.value.error);
404
+ expect(next1.value.object).toEqual(posted);
405
+ expect(next2.value.object).toEqual(posted);
406
+ const next3 = await iterator1.next();
407
+ const next4 = await iterator2.next();
408
+ assert(next3.done);
409
+ assert(next4.done);
410
+
411
+ await graffiti1.delete(posted, session1);
412
+
413
+ const iterator3 = next3.value.continue(session1);
414
+ const next5 = await iterator3.next();
415
+ assert(!next5.done && !next5.value.error);
416
+ expect(next5.value.tombstone).toBe(true);
417
+ expect(next5.value.object.url).toEqual(posted.url);
418
+ await expect(iterator3.next()).resolves.toHaveProperty("done", true);
419
+
420
+ // Wait for "labels" to propogate
421
+ // which could introduce a cache bug
422
+ await new Promise((resolve) => setTimeout(resolve, 1000));
423
+
424
+ const iterator4 = next4.value.continue(session1);
425
+ const next6 = await iterator4.next();
426
+ assert(!next6.done && !next6.value.error);
427
+ expect(next6.value.tombstone).toBe(true);
428
+ expect(next6.value.object.url).toEqual(posted.url);
429
+ await expect(iterator4.next()).resolves.toHaveProperty("done", true);
430
+ });
431
+
391
432
  for (const continueType of ["cursor", "continue"] as const) {
392
433
  describe(`continue discover with ${continueType}`, () => {
393
434
  it("discover for deleted content", async () => {