@graffiti-garden/api 1.0.1 → 1.0.3

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/src/2-types.ts CHANGED
@@ -102,7 +102,7 @@ export interface GraffitiObjectBase {
102
102
  * Schema-aware objects are returned by {@link Graffiti.get} and {@link Graffiti.discover}.
103
103
  */
104
104
  export type GraffitiObject<Schema extends JSONSchema> = GraffitiObjectBase &
105
- FromSchema<Schema & typeof GraffitiObjectJSONSchema>;
105
+ FromSchema<Schema & typeof GraffitiPostObjectJSONSchema>;
106
106
 
107
107
  /**
108
108
  * A JSON Schema equivalent to the {@link GraffitiObjectBase} type.
@@ -145,7 +145,6 @@ export type GraffitiPostObject<Schema extends JSONSchema> = Pick<
145
145
  GraffitiObjectBase,
146
146
  "value" | "channels" | "allowed"
147
147
  > &
148
- Partial<GraffitiObjectBase> &
149
148
  FromSchema<Schema & typeof GraffitiPostObjectJSONSchema>;
150
149
 
151
150
  /**
@@ -397,3 +396,41 @@ export type GraffitiSessionInitializedEvent = CustomEvent<
397
396
  | null
398
397
  | undefined
399
398
  >;
399
+
400
+ export type GraffitiMedia = {
401
+ /**
402
+ * The binary data of the media to be uploaded,
403
+ * along with its [media type](https://www.iana.org/assignments/media-types/media-types.xhtml),
404
+ * formatted as a [Blob](https://developer.mozilla.org/en-US/docs/Web/API/Blob).
405
+ */
406
+ data: Blob;
407
+ /**
408
+ * The {@link GraffitiObjectBase.actor | `actor`} that
409
+ * {@link Graffiti.postMedia | `post`ed} the media.
410
+ */
411
+ actor: string;
412
+ /**
413
+ * An optional list, identical in function to an object's
414
+ * {@link GraffitiObjectBase.allowed | `allowed`} property,
415
+ * that specifies the {@link GraffitiObjectBase.actor | `actor`}s
416
+ * who are allowed to access the media. If the list is `undefined`
417
+ * or `null`, anyone with the URL can access the media. If the list
418
+ * is empty, only the {@link GraffitiObjectBase.actor | `actor`}
419
+ * who {@link Graffiti.postMedia | `post`ed} the media can access it.
420
+ */
421
+ allowed?: string[] | null;
422
+ };
423
+
424
+ export type GraffitiPostMedia = Pick<GraffitiMedia, "data" | "allowed">;
425
+
426
+ export type GraffitiMediaRequirements = {
427
+ /**
428
+ * A list of acceptable media types for the retrieved media,
429
+ * formatted as like an [HTTP Accept header](https://httpwg.org/specs/rfc9110.html#field.accept)
430
+ */
431
+ accept?: string;
432
+ /**
433
+ * The maximum acceptable size, in bytes, of the media.
434
+ */
435
+ maxBytes?: number;
436
+ };
package/src/3-errors.ts CHANGED
@@ -1,11 +1,3 @@
1
- export class GraffitiErrorUnauthorized extends Error {
2
- constructor(message?: string) {
3
- super(message);
4
- this.name = "GraffitiErrorUnauthorized";
5
- Object.setPrototypeOf(this, GraffitiErrorUnauthorized.prototype);
6
- }
7
- }
8
-
9
1
  export class GraffitiErrorForbidden extends Error {
10
2
  constructor(message?: string) {
11
3
  super(message);
package/tests/crud.ts CHANGED
@@ -34,6 +34,12 @@ export const graffitiCRUDTests = (
34
34
  session2 = await useSession2();
35
35
  });
36
36
 
37
+ it("get nonexistant object", async () => {
38
+ await expect(graffiti.get(randomString(), {})).rejects.toThrow(
39
+ GraffitiErrorNotFound,
40
+ );
41
+ });
42
+
37
43
  it("post, get, delete", async () => {
38
44
  const value = {
39
45
  something: "hello, world~ c:",
package/tests/discover.ts CHANGED
@@ -1,10 +1,14 @@
1
1
  import { it, expect, describe, assert, beforeAll } from "vitest";
2
2
  import type {
3
3
  Graffiti,
4
- GraffitiObjectBase,
5
4
  GraffitiSession,
6
5
  JSONSchema,
7
6
  } from "@graffiti-garden/api";
7
+ import {
8
+ GraffitiErrorForbidden,
9
+ GraffitiErrorInvalidSchema,
10
+ GraffitiErrorNotFound,
11
+ } from "@graffiti-garden/api";
8
12
  import {
9
13
  randomString,
10
14
  nextStreamValue,
@@ -103,6 +107,19 @@ export const graffitiDiscoverTests = (
103
107
  expect(value.actor).toEqual(session1.actor);
104
108
  });
105
109
 
110
+ it("discover bad schema", async () => {
111
+ const iterator = graffiti.discover([], {
112
+ properties: {
113
+ value: {
114
+ //@ts-ignore
115
+ type: "asdf",
116
+ },
117
+ },
118
+ });
119
+
120
+ await expect(iterator.next()).rejects.toThrow(GraffitiErrorInvalidSchema);
121
+ });
122
+
106
123
  it("discover for actor", async () => {
107
124
  const object1 = randomPostObject();
108
125
  const posted1 = await graffiti.post<{}>(object1, session1);
@@ -396,12 +413,47 @@ export const graffitiDiscoverTests = (
396
413
  assert(!value.done && !value.value.error, "value is done");
397
414
  assert(value.value.tombstone, "value is not tombstone");
398
415
  expect(value.value.object.url).toEqual(posted.url);
399
- await expect(tombIterator.next()).resolves.toHaveProperty(
416
+ const returnValue2 = await tombIterator.next();
417
+ assert(returnValue2.done, "value2 is not done");
418
+
419
+ // Post another object
420
+ const posted2 = await graffiti.post<{}>(object, session);
421
+ const doubleContinueIterator = continueStream<{}>(
422
+ graffiti,
423
+ returnValue2.value,
424
+ continueType,
425
+ );
426
+ const value2 = await doubleContinueIterator.next();
427
+ assert(!value2.done && !value2.value.error, "value2 is done");
428
+ assert(!value2.value.tombstone, "value2 is tombstone");
429
+ expect(value2.value.object.url).toEqual(posted2.url);
430
+ await expect(doubleContinueIterator.next()).resolves.toHaveProperty(
400
431
  "done",
401
432
  true,
402
433
  );
403
434
  });
435
+
436
+ it("continue with wrong actor", async () => {
437
+ const iterator = graffiti.discover<{}>([], {}, session1);
438
+ const result = await iterator.next();
439
+ assert(result.done, "iterator is not done");
440
+
441
+ const continuation = continueStream<{}>(
442
+ graffiti,
443
+ result.value,
444
+ continueType,
445
+ session2,
446
+ );
447
+ await expect(continuation.next()).rejects.toThrow(
448
+ GraffitiErrorForbidden,
449
+ );
450
+ });
404
451
  });
405
452
  }
453
+
454
+ it("lookup non-existant cursor", async () => {
455
+ const iterator = graffiti.continueDiscover(randomString());
456
+ await expect(iterator.next()).rejects.toThrow(GraffitiErrorNotFound);
457
+ });
406
458
  });
407
459
  };