@graffiti-garden/implementation-local 1.0.3 → 1.0.4
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/media.js +7 -19
- package/dist/cjs/media.js.map +3 -3
- package/dist/cjs/objects.js +21 -9
- package/dist/cjs/objects.js.map +2 -2
- package/dist/cjs/utilities.js +10 -0
- package/dist/cjs/utilities.js.map +2 -2
- package/dist/esm/media.js +9 -10
- package/dist/esm/media.js.map +2 -2
- package/dist/esm/objects.js +26 -10
- package/dist/esm/objects.js.map +2 -2
- package/dist/esm/utilities.js +14 -1
- package/dist/esm/utilities.js.map +2 -2
- package/dist/media.d.ts.map +1 -1
- package/dist/objects.d.ts.map +1 -1
- package/dist/utilities.d.ts +3 -0
- package/dist/utilities.d.ts.map +1 -1
- package/package.json +5 -6
- package/src/media.ts +8 -9
- package/src/objects.ts +26 -9
- package/src/utilities.ts +27 -1
package/dist/media.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"media.d.ts","sourceRoot":"","sources":["../src/media.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"media.d.ts","sourceRoot":"","sources":["../src/media.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,QAAQ,EAEd,MAAM,sBAAsB,CAAC;AAuB9B,qBAAa,kBAAkB;IAC7B,SAAS,CAAC,EAAE,EAAE,IAAI,CAAC,QAAQ,EAAE,MAAM,GAAG,KAAK,GAAG,QAAQ,CAAC,CAAC;gBAE5C,EAAE,EAAE,IAAI,CAAC,QAAQ,EAAE,MAAM,GAAG,KAAK,GAAG,QAAQ,CAAC;IAIzD,SAAS,EAAE,QAAQ,CAAC,WAAW,CAAC,CAqB9B;IAEF,QAAQ,EAAE,QAAQ,CAAC,UAAU,CAAC,CAoC5B;IAEF,WAAW,EAAE,QAAQ,CAAC,aAAa,CAAC,CAMlC;CACH"}
|
package/dist/objects.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"objects.d.ts","sourceRoot":"","sources":["../src/objects.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,QAAQ,EAER,UAAU,EACV,eAAe,EACf,4BAA4B,EAC5B,iCAAiC,EAClC,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"objects.d.ts","sourceRoot":"","sources":["../src/objects.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,QAAQ,EAER,UAAU,EACV,eAAe,EACf,4BAA4B,EAC5B,iCAAiC,EAClC,MAAM,sBAAsB,CAAC;AAe9B,OAAO,KAAK,GAAG,MAAM,KAAK,CAAC;AAE3B;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC;;;;;;OAMG;IACH,cAAc,CAAC,EAAE,OAAO,CAAC,aAAa,CAAC,qBAAqB,CAAC;IAC7D;;;OAGG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,KAAK,kBAAkB,GAAG;IACxB,SAAS,EAAE,OAAO,CAAC;IACnB,KAAK,EAAE,EAAE,CAAC;IACV,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;IAC1B,YAAY,EAAE,MAAM,CAAC;CACtB,CAAC;AAEF,KAAK,sBAAsB,GAAG;IAC5B,cAAc,EAAE,MAAM,CAAC;IACvB,eAAe,EAAE,MAAM,CAAC;CACzB,CAAC;AAEF;;;GAGG;AACH,qBAAa,oBAAoB;IAC/B,SAAS,CAAC,GAAG,EAAE,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAC,CAAC,GAAG,SAAS,CAAC;IACzE,SAAS,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC,GAAG,SAAS,CAAC;IACzC,SAAS,CAAC,QAAQ,CAAC,OAAO,EAAE,oBAAoB,CAAC;IAEjD,IAAI,EAAE,kDAkDL;IAED,SAAS,KAAK,GAAG,iBAQhB;cAEe,iBAAiB;gBAIrB,OAAO,CAAC,EAAE,oBAAoB;IAI1C,GAAG,EAAE,QAAQ,CAAC,KAAK,CAAC,CA4ClB;IAEF,MAAM,EAAE,QAAQ,CAAC,QAAQ,CAAC,CAyCxB;IAEF,IAAI,EAAE,QAAQ,CAAC,MAAM,CAAC,CA4BpB;cAEe,YAAY,CAAC,MAAM,SAAS,UAAU,EACrD,IAAI,EAAE,UAAU,CAAC,OAAO,QAAQ,CAAC,SAAS,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,EAC5D,cAAc,CAAC,EAAE;QACf,cAAc,EAAE,MAAM,CAAC;QACvB,eAAe,EAAE,MAAM,CAAC;KACzB,GACA,cAAc,CACf,iCAAiC,CAAC,MAAM,CAAC,EACzC,sBAAsB,CACvB;IAwFD,SAAS,CAAC,cAAc,CACtB,IAAI,EAAE,UAAU,CAAC,OAAO,QAAQ,CAAC,SAAS,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,EACxD,cAAc,EAAE;QACd,cAAc,EAAE,MAAM,CAAC;QACvB,eAAe,EAAE,MAAM,CAAC;KACzB,GACA,MAAM;cAaQ,gBAAgB,CAAC,MAAM,SAAS,UAAU,EACzD,IAAI,EAAE,UAAU,CAAC,OAAO,QAAQ,CAAC,SAAS,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,EAC5D,cAAc,EAAE;QACd,cAAc,EAAE,MAAM,CAAC;QACvB,eAAe,EAAE,MAAM,CAAC;KACzB,EACD,OAAO,CAAC,EAAE,eAAe,GAAG,IAAI,GAC/B,4BAA4B,CAAC,MAAM,CAAC;IAqBvC,QAAQ,EAAE,QAAQ,CAAC,UAAU,CAAC,CA4B5B;IAEF,gBAAgB,EAAE,QAAQ,CAAC,kBAAkB,CAAC,CAuB5C;CACH"}
|
package/dist/utilities.d.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { type GraffitiObject, type GraffitiObjectBase, type JSONSchema } from "@graffiti-garden/api";
|
|
2
|
+
import type Ajv from "ajv";
|
|
1
3
|
export declare function encodeBase64(bytes: Uint8Array): string;
|
|
2
4
|
export declare function decodeBase64(base64Url: string): Uint8Array;
|
|
3
5
|
export declare function randomBase64(numBytes?: number): string;
|
|
@@ -18,4 +20,5 @@ export declare function decodeMediaUrl(url: string): {
|
|
|
18
20
|
};
|
|
19
21
|
export declare function blobToBase64(blob: Blob): Promise<string>;
|
|
20
22
|
export declare function base64ToBlob(dataUrl: string): Promise<Blob>;
|
|
23
|
+
export declare function compileGraffitiObjectSchema<Schema extends JSONSchema>(ajv: Ajv, schema: Schema): (data: GraffitiObjectBase) => data is GraffitiObject<Schema>;
|
|
21
24
|
//# sourceMappingURL=utilities.d.ts.map
|
package/dist/utilities.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utilities.d.ts","sourceRoot":"","sources":["../src/utilities.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"utilities.d.ts","sourceRoot":"","sources":["../src/utilities.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,cAAc,EACnB,KAAK,kBAAkB,EACvB,KAAK,UAAU,EAChB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,KAAK,GAAG,MAAM,KAAK,CAAC;AAE3B,wBAAgB,YAAY,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,CAKtD;AAED,wBAAgB,YAAY,CAAC,SAAS,EAAE,MAAM,GAAG,UAAU,CAO1D;AAED,wBAAgB,YAAY,CAAC,QAAQ,GAAE,MAAW,GAAG,MAAM,CAK1D;AAKD,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,UAE1E;AACD,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,UAExD;AACD,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,UAEvD;AAED,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;;;EAU5D;AACD,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM;;;EAE1C;AACD,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM;;;EAEzC;AAED,wBAAsB,YAAY,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,MAAM,CAAC,CAsB9D;AAED,wBAAsB,YAAY,CAAC,OAAO,EAAE,MAAM,iBAGjD;AAED,wBAAgB,2BAA2B,CAAC,MAAM,SAAS,UAAU,EACnE,GAAG,EAAE,GAAG,EACR,MAAM,EAAE,MAAM,UAQJ,kBAAkB,KACrB,IAAI,IAAI,cAAc,CAAC,MAAM,CAAC,CAMtC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@graffiti-garden/implementation-local",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.4",
|
|
4
4
|
"description": "A local implementation of the Graffiti API using PouchDB",
|
|
5
5
|
"types": "./dist/index.d.ts",
|
|
6
6
|
"module": "./dist/esm/index.js",
|
|
@@ -84,19 +84,18 @@
|
|
|
84
84
|
},
|
|
85
85
|
"devDependencies": {
|
|
86
86
|
"@types/negotiator": "^0.6.4",
|
|
87
|
-
"@types/node": "^25.0.
|
|
87
|
+
"@types/node": "^25.0.6",
|
|
88
88
|
"@types/pouchdb": "^6.4.2",
|
|
89
|
-
"@vitest/coverage-v8": "^4.0.
|
|
89
|
+
"@vitest/coverage-v8": "^4.0.17",
|
|
90
90
|
"esbuild": "^0.27.2",
|
|
91
91
|
"esbuild-plugin-polyfill-node": "^0.3.0",
|
|
92
92
|
"tsx": "^4.19.2",
|
|
93
93
|
"typescript": "^5.7.3",
|
|
94
|
-
"vitest": "^4.0.
|
|
94
|
+
"vitest": "^4.0.17"
|
|
95
95
|
},
|
|
96
96
|
"dependencies": {
|
|
97
|
-
"@graffiti-garden/api": "^1.0.
|
|
97
|
+
"@graffiti-garden/api": "^1.0.4",
|
|
98
98
|
"ajv": "^8.17.1",
|
|
99
|
-
"negotiator": "^1.0.0",
|
|
100
99
|
"pouchdb": "^9.0.0"
|
|
101
100
|
}
|
|
102
101
|
}
|
package/src/media.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
GraffitiErrorNotAcceptable,
|
|
3
3
|
GraffitiErrorTooLarge,
|
|
4
|
+
isMediaAcceptable,
|
|
4
5
|
type Graffiti,
|
|
5
6
|
type JSONSchema,
|
|
6
7
|
} from "@graffiti-garden/api";
|
|
@@ -12,7 +13,6 @@ import {
|
|
|
12
13
|
blobToBase64,
|
|
13
14
|
base64ToBlob,
|
|
14
15
|
} from "./utilities";
|
|
15
|
-
import Negotiator from "negotiator";
|
|
16
16
|
|
|
17
17
|
const MEDIA_OBJECT_SCHEMA = {
|
|
18
18
|
properties: {
|
|
@@ -58,7 +58,7 @@ export class GraffitiLocalMedia {
|
|
|
58
58
|
};
|
|
59
59
|
|
|
60
60
|
getMedia: Graffiti["getMedia"] = async (...args) => {
|
|
61
|
-
const [mediaUrl,
|
|
61
|
+
const [mediaUrl, accept, session] = args;
|
|
62
62
|
const { actor, id } = decodeMediaUrl(mediaUrl);
|
|
63
63
|
const objectUrl = encodeObjectUrl(actor, id);
|
|
64
64
|
|
|
@@ -70,17 +70,16 @@ export class GraffitiLocalMedia {
|
|
|
70
70
|
|
|
71
71
|
const { dataBase64, type, size } = object.value;
|
|
72
72
|
|
|
73
|
-
if (
|
|
73
|
+
if (accept?.maxBytes && size > accept.maxBytes) {
|
|
74
74
|
throw new GraffitiErrorTooLarge("File size exceeds limit");
|
|
75
75
|
}
|
|
76
76
|
|
|
77
77
|
// Make sure it adheres to requirements.accept
|
|
78
|
-
if (
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
throw new GraffitiErrorNotAcceptable(`Unsupported media type, ${type}`);
|
|
78
|
+
if (accept?.types) {
|
|
79
|
+
if (!isMediaAcceptable(type, accept.types)) {
|
|
80
|
+
throw new GraffitiErrorNotAcceptable(
|
|
81
|
+
`Unacceptable media type, ${type}`,
|
|
82
|
+
);
|
|
84
83
|
}
|
|
85
84
|
}
|
|
86
85
|
|
package/src/objects.ts
CHANGED
|
@@ -13,9 +13,13 @@ import {
|
|
|
13
13
|
unpackObjectUrl,
|
|
14
14
|
maskGraffitiObject,
|
|
15
15
|
isActorAllowedGraffitiObject,
|
|
16
|
-
compileGraffitiObjectSchema,
|
|
17
16
|
} from "@graffiti-garden/api";
|
|
18
|
-
import {
|
|
17
|
+
import {
|
|
18
|
+
randomBase64,
|
|
19
|
+
decodeObjectUrl,
|
|
20
|
+
encodeObjectUrl,
|
|
21
|
+
compileGraffitiObjectSchema,
|
|
22
|
+
} from "./utilities.js";
|
|
19
23
|
import type Ajv from "ajv";
|
|
20
24
|
|
|
21
25
|
/**
|
|
@@ -166,13 +170,13 @@ export class GraffitiLocalObjects {
|
|
|
166
170
|
|
|
167
171
|
// Mask out the allowed list and channels
|
|
168
172
|
// if the user is not the owner
|
|
169
|
-
maskGraffitiObject(object, [], session);
|
|
173
|
+
const masked = maskGraffitiObject(object, [], session?.actor);
|
|
170
174
|
|
|
171
175
|
const validate = compileGraffitiObjectSchema(await this.ajv, schema);
|
|
172
|
-
if (!validate(
|
|
176
|
+
if (!validate(masked)) {
|
|
173
177
|
throw new GraffitiErrorSchemaMismatch();
|
|
174
178
|
}
|
|
175
|
-
return
|
|
179
|
+
return masked;
|
|
176
180
|
};
|
|
177
181
|
|
|
178
182
|
delete: Graffiti["delete"] = async (...args) => {
|
|
@@ -206,7 +210,16 @@ export class GraffitiLocalObjects {
|
|
|
206
210
|
throw new GraffitiErrorNotFound("Object not found.");
|
|
207
211
|
}
|
|
208
212
|
|
|
209
|
-
|
|
213
|
+
// Return the output
|
|
214
|
+
const { value, channels, allowed } = doc;
|
|
215
|
+
const object: GraffitiObjectBase = {
|
|
216
|
+
value,
|
|
217
|
+
channels,
|
|
218
|
+
allowed,
|
|
219
|
+
url,
|
|
220
|
+
actor,
|
|
221
|
+
};
|
|
222
|
+
return object;
|
|
210
223
|
};
|
|
211
224
|
|
|
212
225
|
post: Graffiti["post"] = async (...args) => {
|
|
@@ -313,16 +326,20 @@ export class GraffitiLocalObjects {
|
|
|
313
326
|
|
|
314
327
|
if (!isActorAllowedGraffitiObject(object, session)) continue;
|
|
315
328
|
|
|
316
|
-
maskGraffitiObject(
|
|
329
|
+
const masked = maskGraffitiObject(
|
|
330
|
+
object,
|
|
331
|
+
discoverChannels,
|
|
332
|
+
session?.actor,
|
|
333
|
+
);
|
|
317
334
|
|
|
318
|
-
if (!validate(
|
|
335
|
+
if (!validate(masked)) continue;
|
|
319
336
|
|
|
320
337
|
yield tombstone
|
|
321
338
|
? {
|
|
322
339
|
tombstone: true,
|
|
323
340
|
object: { url },
|
|
324
341
|
}
|
|
325
|
-
: { object };
|
|
342
|
+
: { object: masked };
|
|
326
343
|
}
|
|
327
344
|
}
|
|
328
345
|
|
package/src/utilities.ts
CHANGED
|
@@ -1,4 +1,11 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
GraffitiErrorInvalidSchema,
|
|
3
|
+
GraffitiErrorNotFound,
|
|
4
|
+
type GraffitiObject,
|
|
5
|
+
type GraffitiObjectBase,
|
|
6
|
+
type JSONSchema,
|
|
7
|
+
} from "@graffiti-garden/api";
|
|
8
|
+
import type Ajv from "ajv";
|
|
2
9
|
|
|
3
10
|
export function encodeBase64(bytes: Uint8Array): string {
|
|
4
11
|
// Convert it to base64
|
|
@@ -82,3 +89,22 @@ export async function base64ToBlob(dataUrl: string) {
|
|
|
82
89
|
const response = await fetch(dataUrl);
|
|
83
90
|
return await response.blob();
|
|
84
91
|
}
|
|
92
|
+
|
|
93
|
+
export function compileGraffitiObjectSchema<Schema extends JSONSchema>(
|
|
94
|
+
ajv: Ajv,
|
|
95
|
+
schema: Schema,
|
|
96
|
+
) {
|
|
97
|
+
try {
|
|
98
|
+
// Force the validation guard because
|
|
99
|
+
// it is too big for the type checker.
|
|
100
|
+
// Fortunately json-schema-to-ts is
|
|
101
|
+
// well tested against ajv.
|
|
102
|
+
return ajv.compile(schema) as (
|
|
103
|
+
data: GraffitiObjectBase,
|
|
104
|
+
) => data is GraffitiObject<Schema>;
|
|
105
|
+
} catch (error) {
|
|
106
|
+
throw new GraffitiErrorInvalidSchema(
|
|
107
|
+
error instanceof Error ? error.message : undefined,
|
|
108
|
+
);
|
|
109
|
+
}
|
|
110
|
+
}
|