@graffiti-garden/implementation-local 1.0.3 → 1.0.7
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/browser/index.js +1 -12
- package/dist/browser/index.js.map +4 -4
- package/dist/cjs/index.js +7 -1
- package/dist/cjs/index.js.map +2 -2
- package/dist/cjs/media.js +10 -27
- package/dist/cjs/media.js.map +3 -3
- package/dist/cjs/objects.js +22 -20
- package/dist/cjs/objects.js.map +2 -2
- package/dist/cjs/tests.spec.js +2 -2
- package/dist/cjs/tests.spec.js.map +2 -2
- package/dist/cjs/utilities.js +13 -12
- package/dist/cjs/utilities.js.map +2 -2
- package/dist/esm/index.js +8 -2
- package/dist/esm/index.js.map +2 -2
- package/dist/esm/media.js +13 -26
- package/dist/esm/media.js.map +2 -2
- package/dist/esm/objects.js +24 -21
- package/dist/esm/objects.js.map +2 -2
- package/dist/esm/tests.spec.js +2 -2
- package/dist/esm/tests.spec.js.map +2 -2
- package/dist/esm/utilities.js +13 -12
- package/dist/esm/utilities.js.map +2 -2
- package/dist/index.d.ts +3 -21
- package/dist/index.d.ts.map +1 -1
- package/dist/media.d.ts.map +1 -1
- package/dist/objects.d.ts +0 -3
- package/dist/objects.d.ts.map +1 -1
- package/dist/utilities.d.ts +2 -5
- package/dist/utilities.d.ts.map +1 -1
- package/package.json +5 -7
- package/src/index.ts +9 -2
- package/src/media.ts +12 -25
- package/src/objects.ts +24 -22
- package/src/tests.spec.ts +3 -2
- package/src/utilities.ts +11 -10
package/src/objects.ts
CHANGED
|
@@ -14,9 +14,9 @@ import {
|
|
|
14
14
|
maskGraffitiObject,
|
|
15
15
|
isActorAllowedGraffitiObject,
|
|
16
16
|
compileGraffitiObjectSchema,
|
|
17
|
+
GraffitiErrorCursorExpired,
|
|
17
18
|
} from "@graffiti-garden/api";
|
|
18
19
|
import { randomBase64, decodeObjectUrl, encodeObjectUrl } from "./utilities.js";
|
|
19
|
-
import type Ajv from "ajv";
|
|
20
20
|
|
|
21
21
|
/**
|
|
22
22
|
* Constructor options for the GraffitiPoubchDB class.
|
|
@@ -56,7 +56,6 @@ type ContinueDiscoverParams = {
|
|
|
56
56
|
*/
|
|
57
57
|
export class GraffitiLocalObjects {
|
|
58
58
|
protected db_: Promise<PouchDB.Database<GraffitiObjectData>> | undefined;
|
|
59
|
-
protected ajv_: Promise<Ajv> | undefined;
|
|
60
59
|
protected readonly options: GraffitiLocalOptions;
|
|
61
60
|
|
|
62
61
|
get db() {
|
|
@@ -111,16 +110,6 @@ export class GraffitiLocalObjects {
|
|
|
111
110
|
return this.db_;
|
|
112
111
|
}
|
|
113
112
|
|
|
114
|
-
protected get ajv() {
|
|
115
|
-
if (!this.ajv_) {
|
|
116
|
-
this.ajv_ = (async () => {
|
|
117
|
-
const { default: Ajv } = await import("ajv");
|
|
118
|
-
return new Ajv({ strict: false });
|
|
119
|
-
})();
|
|
120
|
-
}
|
|
121
|
-
return this.ajv_;
|
|
122
|
-
}
|
|
123
|
-
|
|
124
113
|
protected async getOperationClock() {
|
|
125
114
|
return Number((await (await this.db).info()).update_seq);
|
|
126
115
|
}
|
|
@@ -166,13 +155,13 @@ export class GraffitiLocalObjects {
|
|
|
166
155
|
|
|
167
156
|
// Mask out the allowed list and channels
|
|
168
157
|
// if the user is not the owner
|
|
169
|
-
maskGraffitiObject(object, [], session);
|
|
158
|
+
const masked = maskGraffitiObject(object, [], session?.actor);
|
|
170
159
|
|
|
171
|
-
const validate = compileGraffitiObjectSchema(
|
|
172
|
-
if (!validate(
|
|
160
|
+
const validate = await compileGraffitiObjectSchema(schema);
|
|
161
|
+
if (!validate(masked)) {
|
|
173
162
|
throw new GraffitiErrorSchemaMismatch();
|
|
174
163
|
}
|
|
175
|
-
return
|
|
164
|
+
return masked;
|
|
176
165
|
};
|
|
177
166
|
|
|
178
167
|
delete: Graffiti["delete"] = async (...args) => {
|
|
@@ -206,7 +195,16 @@ export class GraffitiLocalObjects {
|
|
|
206
195
|
throw new GraffitiErrorNotFound("Object not found.");
|
|
207
196
|
}
|
|
208
197
|
|
|
209
|
-
|
|
198
|
+
// Return the output
|
|
199
|
+
const { value, channels, allowed } = doc;
|
|
200
|
+
const object: GraffitiObjectBase = {
|
|
201
|
+
value,
|
|
202
|
+
channels,
|
|
203
|
+
allowed,
|
|
204
|
+
url,
|
|
205
|
+
actor,
|
|
206
|
+
};
|
|
207
|
+
return object;
|
|
210
208
|
};
|
|
211
209
|
|
|
212
210
|
post: Graffiti["post"] = async (...args) => {
|
|
@@ -265,7 +263,7 @@ export class GraffitiLocalObjects {
|
|
|
265
263
|
}
|
|
266
264
|
|
|
267
265
|
const [discoverChannels, schema, session] = args;
|
|
268
|
-
const validate = compileGraffitiObjectSchema(
|
|
266
|
+
const validate = await compileGraffitiObjectSchema(schema);
|
|
269
267
|
const startKeySuffix = continueParams
|
|
270
268
|
? continueParams.ifModifiedSince.toString().padStart(15, "0")
|
|
271
269
|
: "";
|
|
@@ -313,16 +311,20 @@ export class GraffitiLocalObjects {
|
|
|
313
311
|
|
|
314
312
|
if (!isActorAllowedGraffitiObject(object, session)) continue;
|
|
315
313
|
|
|
316
|
-
maskGraffitiObject(
|
|
314
|
+
const masked = maskGraffitiObject(
|
|
315
|
+
object,
|
|
316
|
+
discoverChannels,
|
|
317
|
+
session?.actor,
|
|
318
|
+
);
|
|
317
319
|
|
|
318
|
-
if (!validate(
|
|
320
|
+
if (!validate(masked)) continue;
|
|
319
321
|
|
|
320
322
|
yield tombstone
|
|
321
323
|
? {
|
|
322
324
|
tombstone: true,
|
|
323
325
|
object: { url },
|
|
324
326
|
}
|
|
325
|
-
: { object };
|
|
327
|
+
: { object: masked };
|
|
326
328
|
}
|
|
327
329
|
}
|
|
328
330
|
|
|
@@ -429,7 +431,7 @@ export class GraffitiLocalObjects {
|
|
|
429
431
|
);
|
|
430
432
|
} else {
|
|
431
433
|
return (async function* () {
|
|
432
|
-
throw new
|
|
434
|
+
throw new GraffitiErrorCursorExpired("Cursor not found");
|
|
433
435
|
})();
|
|
434
436
|
}
|
|
435
437
|
};
|
package/src/tests.spec.ts
CHANGED
|
@@ -6,9 +6,10 @@ import {
|
|
|
6
6
|
import { GraffitiLocal } from "./index";
|
|
7
7
|
|
|
8
8
|
const useGraffiti = () => new GraffitiLocal();
|
|
9
|
-
const useSession1 = () => ({ actor: "someone" });
|
|
10
|
-
const useSession2 = () => ({ actor: "someoneelse" });
|
|
9
|
+
const useSession1 = () => ({ actor: "did:example:someone" });
|
|
10
|
+
const useSession2 = () => ({ actor: "did:example:someoneelse" });
|
|
11
11
|
|
|
12
|
+
// @ts-ignore
|
|
12
13
|
graffitiCRUDTests(useGraffiti, useSession1, useSession2);
|
|
13
14
|
graffitiDiscoverTests(useGraffiti, useSession1, useSession2);
|
|
14
15
|
graffitiMediaTests(useGraffiti, useSession1, useSession2);
|
package/src/utilities.ts
CHANGED
|
@@ -23,18 +23,22 @@ export function randomBase64(numBytes: number = 32): string {
|
|
|
23
23
|
return encodeBase64(bytes);
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
-
const OBJECT_URL_PREFIX = "graffiti:
|
|
27
|
-
const MEDIA_URL_PREFIX = "graffiti:media:";
|
|
26
|
+
const OBJECT_URL_PREFIX = "graffiti:";
|
|
28
27
|
|
|
28
|
+
export function encodeObjectUrlComponent(value: string) {
|
|
29
|
+
const replaced = value.replace(/:/g, "!").replace(/\//g, "~");
|
|
30
|
+
return encodeURIComponent(replaced);
|
|
31
|
+
}
|
|
32
|
+
export function decodeObjectUrlComponent(value: string) {
|
|
33
|
+
const decoded = decodeURIComponent(value);
|
|
34
|
+
return decoded.replace(/!/g, ":").replace(/~/g, "/");
|
|
35
|
+
}
|
|
29
36
|
export function encodeGraffitiUrl(actor: string, id: string, prefix: string) {
|
|
30
|
-
return `${prefix}${
|
|
37
|
+
return `${prefix}${encodeObjectUrlComponent(actor)}:${encodeObjectUrlComponent(id)}`;
|
|
31
38
|
}
|
|
32
39
|
export function encodeObjectUrl(actor: string, id: string) {
|
|
33
40
|
return encodeGraffitiUrl(actor, id, OBJECT_URL_PREFIX);
|
|
34
41
|
}
|
|
35
|
-
export function encodeMediaUrl(actor: string, id: string) {
|
|
36
|
-
return encodeGraffitiUrl(actor, id, MEDIA_URL_PREFIX);
|
|
37
|
-
}
|
|
38
42
|
|
|
39
43
|
export function decodeGraffitiUrl(url: string, prefix: string) {
|
|
40
44
|
if (!url.startsWith(prefix)) {
|
|
@@ -44,15 +48,12 @@ export function decodeGraffitiUrl(url: string, prefix: string) {
|
|
|
44
48
|
if (slices.length !== 2) {
|
|
45
49
|
throw new GraffitiErrorNotFound("URL has too many colon-seperated parts");
|
|
46
50
|
}
|
|
47
|
-
const [actor, id] = slices.map(
|
|
51
|
+
const [actor, id] = slices.map(decodeObjectUrlComponent);
|
|
48
52
|
return { actor, id };
|
|
49
53
|
}
|
|
50
54
|
export function decodeObjectUrl(url: string) {
|
|
51
55
|
return decodeGraffitiUrl(url, OBJECT_URL_PREFIX);
|
|
52
56
|
}
|
|
53
|
-
export function decodeMediaUrl(url: string) {
|
|
54
|
-
return decodeGraffitiUrl(url, MEDIA_URL_PREFIX);
|
|
55
|
-
}
|
|
56
57
|
|
|
57
58
|
export async function blobToBase64(blob: Blob): Promise<string> {
|
|
58
59
|
if (typeof FileReader !== "undefined") {
|