@graffiti-garden/implementation-decentralized 0.0.10 → 0.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.
- package/LICENSE +4 -673
- package/dist/1-services/2-dids.d.ts +1 -0
- package/dist/1-services/2-dids.d.ts.map +1 -1
- package/dist/1-services/4-inboxes.d.ts +2 -1
- package/dist/1-services/4-inboxes.d.ts.map +1 -1
- package/dist/3-protocol/4-graffiti.d.ts.map +1 -1
- package/dist/browser/ajv-X6C4R6QN.js +9 -0
- package/dist/browser/ajv-X6C4R6QN.js.map +7 -0
- package/dist/browser/{build-DM3HADDZ.js → build-KAK33G4E.js} +1 -1
- package/dist/browser/{build-DM3HADDZ.js.map → build-KAK33G4E.js.map} +1 -1
- package/dist/browser/{graffiti-KV3G3O72-TAZN6KIP.js → graffiti-KV3G3O72-QD3APAKT.js} +1 -1
- package/dist/browser/{graffiti-KV3G3O72-TAZN6KIP.js.map → graffiti-KV3G3O72-QD3APAKT.js.map} +1 -1
- package/dist/browser/index.js +10 -10
- package/dist/browser/index.js.map +4 -4
- package/dist/browser/{rock-salt-LI7DAH66-TZP5ZWGV.js → rock-salt-LI7DAH66-M6W5PPFD.js} +1 -1
- package/dist/browser/{rock-salt-LI7DAH66-TZP5ZWGV.js.map → rock-salt-LI7DAH66-M6W5PPFD.js.map} +1 -1
- package/dist/browser/{style-BOBMBTYJ-GXWKT5M3.js → style-BOBMBTYJ-2YZTO5FX.js} +1 -1
- package/dist/browser/{style-BOBMBTYJ-GXWKT5M3.js.map → style-BOBMBTYJ-2YZTO5FX.js.map} +1 -1
- package/dist/cjs/1-services/2-dids-tests.js +53 -0
- package/dist/cjs/1-services/2-dids-tests.js.map +3 -3
- package/dist/cjs/1-services/2-dids.js +14 -4
- package/dist/cjs/1-services/2-dids.js.map +2 -2
- package/dist/cjs/1-services/4-inboxes.js +36 -17
- package/dist/cjs/1-services/4-inboxes.js.map +2 -2
- package/dist/cjs/3-protocol/4-graffiti.js +5 -2
- package/dist/cjs/3-protocol/4-graffiti.js.map +2 -2
- package/dist/cjs/index.js +2 -2
- package/dist/cjs/index.js.map +2 -2
- package/dist/cjs/index.spec.js +54 -41
- package/dist/cjs/index.spec.js.map +2 -2
- package/dist/esm/1-services/2-dids-tests.js +54 -1
- package/dist/esm/1-services/2-dids-tests.js.map +3 -3
- package/dist/esm/1-services/2-dids.js +14 -4
- package/dist/esm/1-services/2-dids.js.map +2 -2
- package/dist/esm/1-services/4-inboxes.js +36 -17
- package/dist/esm/1-services/4-inboxes.js.map +2 -2
- package/dist/esm/3-protocol/4-graffiti.js +5 -2
- package/dist/esm/3-protocol/4-graffiti.js.map +2 -2
- package/dist/esm/index.js +1 -1
- package/dist/esm/index.js.map +2 -2
- package/dist/esm/index.spec.js +59 -42
- package/dist/esm/index.spec.js.map +2 -2
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/package.json +15 -10
- package/src/1-services/2-dids-tests.ts +62 -1
- package/src/1-services/2-dids.ts +17 -5
- package/src/1-services/4-inboxes.ts +47 -19
- package/src/3-protocol/4-graffiti.ts +9 -2
- package/src/index.spec.ts +66 -48
- package/src/index.ts +2 -1
- package/dist/1-services/2-dids-tests.d.ts +0 -2
- package/dist/1-services/2-dids-tests.d.ts.map +0 -1
- package/dist/1-services/3-storage-buckets-tests.d.ts +0 -2
- package/dist/1-services/3-storage-buckets-tests.d.ts.map +0 -1
- package/dist/1-services/4-inboxes-tests.d.ts +0 -2
- package/dist/1-services/4-inboxes-tests.d.ts.map +0 -1
- package/dist/2-primitives/1-string-encoding-tests.d.ts +0 -2
- package/dist/2-primitives/1-string-encoding-tests.d.ts.map +0 -1
- package/dist/2-primitives/2-content-addresses-tests.d.ts +0 -2
- package/dist/2-primitives/2-content-addresses-tests.d.ts.map +0 -1
- package/dist/2-primitives/3-channel-attestations-tests.d.ts +0 -2
- package/dist/2-primitives/3-channel-attestations-tests.d.ts.map +0 -1
- package/dist/2-primitives/4-allowed-attestations-tests.d.ts +0 -2
- package/dist/2-primitives/4-allowed-attestations-tests.d.ts.map +0 -1
- package/dist/3-protocol/2-handles-tests.d.ts +0 -2
- package/dist/3-protocol/2-handles-tests.d.ts.map +0 -1
- package/dist/3-protocol/3-object-encoding-tests.d.ts +0 -2
- package/dist/3-protocol/3-object-encoding-tests.d.ts.map +0 -1
- package/dist/browser/ajv-LGNUXWV5.js +0 -9
- package/dist/browser/ajv-LGNUXWV5.js.map +0 -7
- package/dist/index.spec.d.ts +0 -2
- package/dist/index.spec.d.ts.map +0 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@graffiti-garden/implementation-decentralized",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"description": "A client for a decentralized implementation of the Graffiti API",
|
|
5
5
|
"types": "./dist/index.d.ts",
|
|
6
6
|
"module": "./dist/esm/index.js",
|
|
@@ -27,35 +27,40 @@
|
|
|
27
27
|
"author": "Theia Henderson",
|
|
28
28
|
"license": "GPL-3.0-or-later",
|
|
29
29
|
"scripts": {
|
|
30
|
-
"
|
|
31
|
-
"test
|
|
32
|
-
"test:
|
|
30
|
+
"check": "tsc --noEmit && tsc -p tsconfig.test.json",
|
|
31
|
+
"test": "vitest run",
|
|
32
|
+
"test:watch": "vitest --watch",
|
|
33
|
+
"test:coverage": "vitest --coverage",
|
|
33
34
|
"build:types": "tsc --declaration --emitDeclarationOnly",
|
|
34
35
|
"build:js": "tsx esbuild.config.mts",
|
|
35
36
|
"build": "rm -rf dist && npm run build:types && npm run build:js",
|
|
36
|
-
"prepublishOnly": "npm
|
|
37
|
+
"prepublishOnly": "npm test && npm run build"
|
|
37
38
|
},
|
|
38
39
|
"repository": {
|
|
39
40
|
"type": "git",
|
|
40
|
-
"url": "git+https://github.com/graffiti-garden/
|
|
41
|
+
"url": "git+https://github.com/graffiti-garden/graffiti.git",
|
|
42
|
+
"directory": "implementations/decentralized/client"
|
|
41
43
|
},
|
|
42
44
|
"bugs": {
|
|
43
|
-
"url": "https://github.com/graffiti-garden/
|
|
45
|
+
"url": "https://github.com/graffiti-garden/graffiti/issues"
|
|
44
46
|
},
|
|
45
47
|
"devDependencies": {
|
|
46
48
|
"@types/js-cookie": "^3.0.6",
|
|
47
49
|
"@types/node": "^26.1.1",
|
|
48
50
|
"@vitest/coverage-v8": "^4.0.18",
|
|
51
|
+
"esbuild": "^0.28.1",
|
|
52
|
+
"miniflare": "4.20260730.0",
|
|
49
53
|
"tsx": "^4.23.1",
|
|
50
54
|
"typescript": "^7.0.2",
|
|
51
55
|
"vitest": "^4.0.18"
|
|
52
56
|
},
|
|
53
57
|
"dependencies": {
|
|
54
|
-
"@graffiti-garden/api": "^1.
|
|
55
|
-
"@graffiti-garden/modal": "^1.0
|
|
58
|
+
"@graffiti-garden/api": "^1.3.0",
|
|
59
|
+
"@graffiti-garden/modal": "^1.1.0",
|
|
60
|
+
"@graffiti-garden/wrapper-runtime-types": "^0.1.0",
|
|
56
61
|
"@ipld/dag-cbor": "^10.0.1",
|
|
57
62
|
"@noble/ed25519": "^3.1.0",
|
|
58
|
-
"@noble/hashes": "2.
|
|
63
|
+
"@noble/hashes": "2.4",
|
|
59
64
|
"did-resolver": "^5.0.1",
|
|
60
65
|
"idb": "^8.0.3",
|
|
61
66
|
"js-cookie": "^3.0.8",
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { DIDResolutionResult, Resolver } from "did-resolver";
|
|
2
|
+
import { describe, expect, test, vi } from "vitest";
|
|
2
3
|
import { DecentralizedIdentifiers } from "./2-dids";
|
|
3
4
|
|
|
4
5
|
export function didTests() {
|
|
@@ -20,5 +21,65 @@ export function didTests() {
|
|
|
20
21
|
const result = await dids.resolve(did);
|
|
21
22
|
expect(result).toHaveProperty("id", did);
|
|
22
23
|
});
|
|
24
|
+
|
|
25
|
+
test("coalesces simultaneous resolutions", async () => {
|
|
26
|
+
const dids = new DecentralizedIdentifiers();
|
|
27
|
+
const did = "did:web:example.com";
|
|
28
|
+
const found: DIDResolutionResult = {
|
|
29
|
+
didDocument: { id: did },
|
|
30
|
+
didDocumentMetadata: {},
|
|
31
|
+
didResolutionMetadata: {},
|
|
32
|
+
};
|
|
33
|
+
let finish!: (result: DIDResolutionResult) => void;
|
|
34
|
+
const lookup = vi.fn<Resolver["resolve"]>().mockImplementation(
|
|
35
|
+
() => new Promise((resolve) => { finish = resolve; }),
|
|
36
|
+
);
|
|
37
|
+
Object.defineProperty(dids, "resolver", { value: { resolve: lookup } });
|
|
38
|
+
|
|
39
|
+
const first = dids.resolve(did);
|
|
40
|
+
const second = dids.resolve(did);
|
|
41
|
+
expect(lookup).toHaveBeenCalledTimes(1);
|
|
42
|
+
|
|
43
|
+
finish(found);
|
|
44
|
+
await expect(Promise.all([first, second])).resolves.toEqual([
|
|
45
|
+
found.didDocument,
|
|
46
|
+
found.didDocument,
|
|
47
|
+
]);
|
|
48
|
+
|
|
49
|
+
lookup.mockResolvedValue(found);
|
|
50
|
+
await expect(dids.resolve(did)).resolves.toEqual(found.didDocument);
|
|
51
|
+
expect(lookup).toHaveBeenCalledTimes(2);
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
test("retries a failed resolution", async () => {
|
|
55
|
+
const dids = new DecentralizedIdentifiers();
|
|
56
|
+
const did = "did:web:example.com";
|
|
57
|
+
const found: DIDResolutionResult = {
|
|
58
|
+
didDocument: { id: did },
|
|
59
|
+
didDocumentMetadata: {},
|
|
60
|
+
didResolutionMetadata: {},
|
|
61
|
+
};
|
|
62
|
+
const lookup = vi.fn<Resolver["resolve"]>()
|
|
63
|
+
.mockResolvedValueOnce({
|
|
64
|
+
didDocument: null,
|
|
65
|
+
didDocumentMetadata: {},
|
|
66
|
+
didResolutionMetadata: { error: "notFound" },
|
|
67
|
+
})
|
|
68
|
+
.mockResolvedValueOnce(found);
|
|
69
|
+
Object.defineProperty(dids, "resolver", { value: { resolve: lookup } });
|
|
70
|
+
|
|
71
|
+
const failed = await Promise.allSettled([
|
|
72
|
+
dids.resolve(did),
|
|
73
|
+
dids.resolve(did),
|
|
74
|
+
]);
|
|
75
|
+
expect(lookup).toHaveBeenCalledTimes(1);
|
|
76
|
+
expect(failed.map((result) => result.status)).toEqual([
|
|
77
|
+
"rejected",
|
|
78
|
+
"rejected",
|
|
79
|
+
]);
|
|
80
|
+
|
|
81
|
+
await expect(dids.resolve(did)).resolves.toEqual(found.didDocument);
|
|
82
|
+
expect(lookup).toHaveBeenCalledTimes(2);
|
|
83
|
+
});
|
|
23
84
|
});
|
|
24
85
|
}
|
package/src/1-services/2-dids.ts
CHANGED
|
@@ -14,6 +14,8 @@ export class DecentralizedIdentifiers {
|
|
|
14
14
|
{ cache: true },
|
|
15
15
|
);
|
|
16
16
|
|
|
17
|
+
protected readonly inFlight = new Map<string, Promise<DIDDocument>>();
|
|
18
|
+
|
|
17
19
|
async resolve(did: string): Promise<DIDDocument> {
|
|
18
20
|
if (
|
|
19
21
|
!Object.keys(this.methods).some((method) =>
|
|
@@ -23,11 +25,21 @@ export class DecentralizedIdentifiers {
|
|
|
23
25
|
throw new Error(`Unrecognized DID method: ${did}`);
|
|
24
26
|
}
|
|
25
27
|
|
|
26
|
-
const
|
|
27
|
-
if (
|
|
28
|
-
throw new GraffitiErrorNotFound(`DID not found: ${did}`);
|
|
29
|
-
}
|
|
28
|
+
const inFlight = this.inFlight.get(did);
|
|
29
|
+
if (inFlight) return inFlight;
|
|
30
30
|
|
|
31
|
-
|
|
31
|
+
const resolution = this.resolver.resolve(did).then(({ didDocument }) => {
|
|
32
|
+
if (!didDocument) {
|
|
33
|
+
throw new GraffitiErrorNotFound(`DID not found: ${did}`);
|
|
34
|
+
}
|
|
35
|
+
return didDocument;
|
|
36
|
+
});
|
|
37
|
+
this.inFlight.set(did, resolution);
|
|
38
|
+
|
|
39
|
+
try {
|
|
40
|
+
return await resolution;
|
|
41
|
+
} finally {
|
|
42
|
+
this.inFlight.delete(did);
|
|
43
|
+
}
|
|
32
44
|
}
|
|
33
45
|
}
|
|
@@ -138,6 +138,7 @@ export class Inboxes {
|
|
|
138
138
|
body: Uint8Array<ArrayBuffer> | undefined,
|
|
139
139
|
inboxToken?: string | null,
|
|
140
140
|
cursor?: string,
|
|
141
|
+
signal?: AbortSignal,
|
|
141
142
|
) {
|
|
142
143
|
const response = await fetchWithErrorHandling(
|
|
143
144
|
`${inboxUrl}/${type}${cursor ? `?cursor=${encodeURIComponent(cursor)}` : ""}`,
|
|
@@ -152,6 +153,7 @@ export class Inboxes {
|
|
|
152
153
|
: {}),
|
|
153
154
|
},
|
|
154
155
|
body,
|
|
156
|
+
signal,
|
|
155
157
|
},
|
|
156
158
|
);
|
|
157
159
|
const retryAfterHeader = response.headers.get("Retry-After");
|
|
@@ -414,13 +416,11 @@ export class Inboxes {
|
|
|
414
416
|
);
|
|
415
417
|
|
|
416
418
|
// First cache the messages with their labels
|
|
417
|
-
await
|
|
418
|
-
labeledMessages.map((m: LabeledMessageBase) =>
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
),
|
|
423
|
-
),
|
|
419
|
+
await cache.messages.setMany(
|
|
420
|
+
labeledMessages.map((m: LabeledMessageBase) => [
|
|
421
|
+
getMessageCacheKey(inboxUrl, m[LABELED_MESSAGE_ID_KEY]),
|
|
422
|
+
m,
|
|
423
|
+
]),
|
|
424
424
|
);
|
|
425
425
|
// Then store all the messageids
|
|
426
426
|
messageIds = [
|
|
@@ -439,22 +439,38 @@ export class Inboxes {
|
|
|
439
439
|
// Update how many we've seen
|
|
440
440
|
cacheNumSeen += labeledMessages.length;
|
|
441
441
|
|
|
442
|
+
// Fetch the next page while the caller processes the current page.
|
|
443
|
+
const prefetchController = new AbortController();
|
|
444
|
+
// Otherwise get another response (after waiting for rate-limit)
|
|
445
|
+
const nextPage = hasMore
|
|
446
|
+
? waitFor(waitTil)
|
|
447
|
+
.then(() => this.fetchMessageBatch(
|
|
448
|
+
inboxUrl,
|
|
449
|
+
type,
|
|
450
|
+
undefined, // Body is never past the first time
|
|
451
|
+
inboxToken,
|
|
452
|
+
cursor,
|
|
453
|
+
prefetchController.signal,
|
|
454
|
+
))
|
|
455
|
+
// A consumer may stop before awaiting this request.
|
|
456
|
+
.then((value) => ({ value }), (error) => ({ error }))
|
|
457
|
+
: null;
|
|
458
|
+
|
|
442
459
|
// Return the values
|
|
443
|
-
|
|
460
|
+
let consumedPage = false;
|
|
461
|
+
try {
|
|
462
|
+
for (const m of labeledMessages) yield m;
|
|
463
|
+
consumedPage = true;
|
|
464
|
+
} finally {
|
|
465
|
+
if (!consumedPage) prefetchController.abort();
|
|
466
|
+
}
|
|
444
467
|
|
|
445
468
|
if (!hasMore) break;
|
|
446
469
|
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
type,
|
|
452
|
-
undefined, // Body is never past the first time
|
|
453
|
-
inboxToken,
|
|
454
|
-
cursor,
|
|
455
|
-
);
|
|
456
|
-
response = out.response;
|
|
457
|
-
waitTil = out.waitTil;
|
|
470
|
+
const out = await nextPage!;
|
|
471
|
+
if ("error" in out) throw out.error;
|
|
472
|
+
response = out.value.response;
|
|
473
|
+
waitTil = out.value.waitTil;
|
|
458
474
|
}
|
|
459
475
|
|
|
460
476
|
const outputCursor: infer_<typeof CursorSchema> = {
|
|
@@ -619,6 +635,7 @@ type Cache = {
|
|
|
619
635
|
messages: {
|
|
620
636
|
get(k: string): Promise<LabeledMessageBase | null | undefined>;
|
|
621
637
|
set(k: string, value: LabeledMessageBase | null): Promise<void>;
|
|
638
|
+
setMany(entries: [string, LabeledMessageBase][]): Promise<void>;
|
|
622
639
|
del(k: string): Promise<void>;
|
|
623
640
|
};
|
|
624
641
|
messageIds: {
|
|
@@ -684,6 +701,14 @@ async function createCache(): Promise<Cache> {
|
|
|
684
701
|
set: async (k, v) => {
|
|
685
702
|
await db.put("m", v, k);
|
|
686
703
|
},
|
|
704
|
+
setMany: async (entries) => {
|
|
705
|
+
if (entries.length === 0) return;
|
|
706
|
+
const tx = db.transaction("m", "readwrite");
|
|
707
|
+
await Promise.all([
|
|
708
|
+
...entries.map(([k, v]) => tx.store.put(v, k)),
|
|
709
|
+
tx.done,
|
|
710
|
+
]);
|
|
711
|
+
},
|
|
687
712
|
del: (k) => db.delete("m", k),
|
|
688
713
|
},
|
|
689
714
|
messageIds: {
|
|
@@ -712,6 +737,9 @@ async function createCache(): Promise<Cache> {
|
|
|
712
737
|
messages: {
|
|
713
738
|
get: async (k) => m.get(k),
|
|
714
739
|
set: async (k, v) => void m.set(k, v),
|
|
740
|
+
setMany: async (entries) => {
|
|
741
|
+
for (const [k, v] of entries) m.set(k, v);
|
|
742
|
+
},
|
|
715
743
|
del: async (k) => void m.delete(k),
|
|
716
744
|
},
|
|
717
745
|
messageIds: {
|
|
@@ -133,7 +133,7 @@ export interface GraffitiDecentralizedOptions {
|
|
|
133
133
|
defaultInboxEndpoints?: string[];
|
|
134
134
|
}
|
|
135
135
|
|
|
136
|
-
const CONCURRENCY =
|
|
136
|
+
const CONCURRENCY = 128;
|
|
137
137
|
const LOCAL_STORAGE_REMEMBERED_HANDLE_KEY = "graffiti-login-remembered-handle";
|
|
138
138
|
|
|
139
139
|
export class GraffitiDecentralized implements Graffiti {
|
|
@@ -710,6 +710,13 @@ export class GraffitiDecentralized implements Graffiti {
|
|
|
710
710
|
getMedia: Graffiti["getMedia"] = async (...args) => {
|
|
711
711
|
const [mediaUrl, accept, session] = args;
|
|
712
712
|
|
|
713
|
+
if (
|
|
714
|
+
accept?.maxBytes !== undefined &&
|
|
715
|
+
(!Number.isSafeInteger(accept.maxBytes) || accept.maxBytes < 0)
|
|
716
|
+
) {
|
|
717
|
+
throw new TypeError("maxBytes must be a nonnegative safe integer");
|
|
718
|
+
}
|
|
719
|
+
|
|
713
720
|
const object = await this.get<typeof MEDIA_OBJECT_SCHEMA>(
|
|
714
721
|
mediaUrl,
|
|
715
722
|
MEDIA_OBJECT_SCHEMA,
|
|
@@ -718,7 +725,7 @@ export class GraffitiDecentralized implements Graffiti {
|
|
|
718
725
|
|
|
719
726
|
const { key, type, size } = object.value;
|
|
720
727
|
|
|
721
|
-
if (accept?.maxBytes && size > accept.maxBytes) {
|
|
728
|
+
if (accept?.maxBytes !== undefined && size > accept.maxBytes) {
|
|
722
729
|
throw new GraffitiErrorTooLarge("File size exceeds limit");
|
|
723
730
|
}
|
|
724
731
|
|
package/src/index.spec.ts
CHANGED
|
@@ -13,7 +13,7 @@ import { Authorization } from "./1-services/1-authorization";
|
|
|
13
13
|
import { StorageBuckets } from "./1-services/3-storage-buckets";
|
|
14
14
|
import { Inboxes } from "./1-services/4-inboxes";
|
|
15
15
|
import { Sessions } from "./3-protocol/1-sessions";
|
|
16
|
-
import { afterAll, describe } from "vitest";
|
|
16
|
+
import { afterAll, beforeAll, describe } from "vitest";
|
|
17
17
|
import { Handles } from "./3-protocol/2-handles";
|
|
18
18
|
import { didTests } from "./1-services/2-dids-tests";
|
|
19
19
|
import { storageBucketTests } from "./1-services/3-storage-buckets-tests";
|
|
@@ -25,48 +25,55 @@ import { allowedAttestationTests } from "./2-primitives/4-allowed-attestations-t
|
|
|
25
25
|
import { handleTests } from "./3-protocol/2-handles-tests";
|
|
26
26
|
import { objectEncodingTests } from "./3-protocol/3-object-encoding-tests";
|
|
27
27
|
import { GraffitiDecentralized } from "./3-protocol/4-graffiti";
|
|
28
|
+
import {
|
|
29
|
+
DecentralizedTestEnvironment,
|
|
30
|
+
decentralizedSharedInbox,
|
|
31
|
+
decentralizedTestUsers,
|
|
32
|
+
} from "../test/environment";
|
|
28
33
|
|
|
29
|
-
describe("GraffitiDecentralized Tests",
|
|
30
|
-
|
|
31
|
-
const
|
|
32
|
-
const sessionMethods = new Sessions({
|
|
33
|
-
dids,
|
|
34
|
-
authorization: new Authorization(),
|
|
35
|
-
inboxes: new Inboxes(),
|
|
36
|
-
storageBuckets: new StorageBuckets(),
|
|
37
|
-
});
|
|
38
|
-
const handleMethods = new Handles({ dids });
|
|
39
|
-
|
|
40
|
-
// Login
|
|
41
|
-
const handles = [
|
|
42
|
-
"localhost%3A5173:app:handles:handle:test1",
|
|
43
|
-
"localhost%3A5173:app:handles:handle:test2",
|
|
44
|
-
];
|
|
34
|
+
describe("GraffitiDecentralized Tests", () => {
|
|
35
|
+
const environment = new DecentralizedTestEnvironment();
|
|
36
|
+
const handles = decentralizedTestUsers.map((user) => user.handle);
|
|
45
37
|
let sessions: GraffitiSession[] = [];
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
38
|
+
let sessionMethods: Sessions;
|
|
39
|
+
let handleMethods: Handles;
|
|
40
|
+
|
|
41
|
+
beforeAll(async () => {
|
|
42
|
+
await environment.start();
|
|
43
|
+
|
|
44
|
+
const dids = new DecentralizedIdentifiers();
|
|
45
|
+
sessionMethods = new Sessions({
|
|
46
|
+
dids,
|
|
47
|
+
authorization: new Authorization(),
|
|
48
|
+
inboxes: new Inboxes(),
|
|
49
|
+
storageBuckets: new StorageBuckets(),
|
|
50
|
+
});
|
|
51
|
+
handleMethods = new Handles({ dids });
|
|
52
|
+
|
|
53
|
+
for (const handle of handles) {
|
|
54
|
+
sessions.push(await login(handle));
|
|
55
|
+
}
|
|
53
56
|
});
|
|
54
|
-
|
|
57
|
+
|
|
55
58
|
afterAll(async () => {
|
|
56
|
-
|
|
57
|
-
|
|
59
|
+
try {
|
|
60
|
+
for (const session of sessions) {
|
|
61
|
+
await logout(session.actor);
|
|
62
|
+
}
|
|
63
|
+
} finally {
|
|
64
|
+
await environment.stop();
|
|
58
65
|
}
|
|
59
66
|
});
|
|
60
67
|
|
|
61
68
|
// Service tests
|
|
62
69
|
didTests();
|
|
63
70
|
storageBucketTests(
|
|
64
|
-
|
|
65
|
-
|
|
71
|
+
decentralizedTestUsers[0].bucketEndpoint,
|
|
72
|
+
decentralizedTestUsers[0].token,
|
|
66
73
|
);
|
|
67
74
|
inboxTests(
|
|
68
|
-
|
|
69
|
-
|
|
75
|
+
decentralizedTestUsers[0].inboxEndpoint,
|
|
76
|
+
decentralizedTestUsers[0].token,
|
|
70
77
|
);
|
|
71
78
|
|
|
72
79
|
// Primitive tests
|
|
@@ -79,13 +86,10 @@ describe("GraffitiDecentralized Tests", async () => {
|
|
|
79
86
|
handleTests(handles[0]);
|
|
80
87
|
objectEncodingTests();
|
|
81
88
|
|
|
82
|
-
const useGraffiti = () =>
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
},
|
|
87
|
-
);
|
|
88
|
-
};
|
|
89
|
+
const useGraffiti = () =>
|
|
90
|
+
new GraffitiDecentralized({
|
|
91
|
+
defaultInboxEndpoints: [decentralizedSharedInbox],
|
|
92
|
+
});
|
|
89
93
|
graffitiCRUDTests(
|
|
90
94
|
useGraffiti,
|
|
91
95
|
() => sessions[0],
|
|
@@ -107,9 +111,16 @@ describe("GraffitiDecentralized Tests", async () => {
|
|
|
107
111
|
const actor = await handleMethods.handleToActor(handle);
|
|
108
112
|
|
|
109
113
|
return await new Promise<GraffitiSession>((resolve, reject) => {
|
|
114
|
+
let timeout: ReturnType<typeof setTimeout>;
|
|
115
|
+
const cleanup = () => {
|
|
116
|
+
clearTimeout(timeout);
|
|
117
|
+
sessionMethods.sessionEvents.removeEventListener("login", listener);
|
|
118
|
+
};
|
|
110
119
|
const listener = (e: unknown) => {
|
|
111
120
|
if (!(e instanceof CustomEvent)) return;
|
|
112
121
|
const detail = e.detail as GraffitiLoginEvent["detail"];
|
|
122
|
+
if (detail.session?.actor !== actor) return;
|
|
123
|
+
cleanup();
|
|
113
124
|
if (detail.error) {
|
|
114
125
|
reject(detail.error);
|
|
115
126
|
} else {
|
|
@@ -118,23 +129,30 @@ describe("GraffitiDecentralized Tests", async () => {
|
|
|
118
129
|
};
|
|
119
130
|
sessionMethods.sessionEvents.addEventListener("login", listener);
|
|
120
131
|
|
|
121
|
-
setTimeout(
|
|
132
|
+
timeout = setTimeout(
|
|
122
133
|
() => {
|
|
123
|
-
|
|
134
|
+
cleanup();
|
|
124
135
|
reject(new Error("Authorization timed out"));
|
|
125
136
|
},
|
|
126
|
-
|
|
127
|
-
);
|
|
137
|
+
30 * 1000,
|
|
138
|
+
);
|
|
128
139
|
|
|
129
|
-
sessionMethods.login(actor);
|
|
140
|
+
void sessionMethods.login(actor);
|
|
130
141
|
});
|
|
131
142
|
}
|
|
132
143
|
|
|
133
144
|
async function logout(actor: string) {
|
|
134
145
|
return await new Promise<void>((resolve, reject) => {
|
|
146
|
+
let timeout: ReturnType<typeof setTimeout>;
|
|
147
|
+
const cleanup = () => {
|
|
148
|
+
clearTimeout(timeout);
|
|
149
|
+
sessionMethods.sessionEvents.removeEventListener("logout", listener);
|
|
150
|
+
};
|
|
135
151
|
const listener = (e: unknown) => {
|
|
136
152
|
if (!(e instanceof CustomEvent)) return;
|
|
137
153
|
const detail = e.detail as GraffitiLogoutEvent["detail"];
|
|
154
|
+
if (detail.actor !== actor) return;
|
|
155
|
+
cleanup();
|
|
138
156
|
|
|
139
157
|
if (detail.error) {
|
|
140
158
|
reject(detail.error);
|
|
@@ -144,15 +162,15 @@ describe("GraffitiDecentralized Tests", async () => {
|
|
|
144
162
|
};
|
|
145
163
|
sessionMethods.sessionEvents.addEventListener("logout", listener);
|
|
146
164
|
|
|
147
|
-
setTimeout(
|
|
165
|
+
timeout = setTimeout(
|
|
148
166
|
() => {
|
|
149
|
-
|
|
167
|
+
cleanup();
|
|
150
168
|
reject(new Error("Logout timed out"));
|
|
151
169
|
},
|
|
152
|
-
|
|
153
|
-
);
|
|
170
|
+
30 * 1000,
|
|
171
|
+
);
|
|
154
172
|
|
|
155
|
-
sessionMethods.logout(actor);
|
|
173
|
+
void sessionMethods.logout(actor);
|
|
156
174
|
});
|
|
157
175
|
}
|
|
158
176
|
});
|
package/src/index.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { Graffiti
|
|
1
|
+
import type { Graffiti } from "@graffiti-garden/api";
|
|
2
|
+
import { GraffitiRuntimeTypes } from "@graffiti-garden/wrapper-runtime-types";
|
|
2
3
|
import {
|
|
3
4
|
GraffitiDecentralized as GraffitiDecentralized_,
|
|
4
5
|
type GraffitiDecentralizedOptions,
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"2-dids-tests.d.ts","sourceRoot":"","sources":["../../src/1-services/2-dids-tests.ts"],"names":[],"mappings":"AAGA,wBAAgB,QAAQ,4CAoBvB"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"3-storage-buckets-tests.d.ts","sourceRoot":"","sources":["../../src/1-services/3-storage-buckets-tests.ts"],"names":[],"mappings":"AAKA,wBAAgB,kBAAkB,CAChC,qBAAqB,EAAE,MAAM,EAC7B,kBAAkB,EAAE,MAAM,QAiH3B"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"4-inboxes-tests.d.ts","sourceRoot":"","sources":["../../src/1-services/4-inboxes-tests.ts"],"names":[],"mappings":"AAMA,wBAAgB,UAAU,CAAC,aAAa,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,QAqJnE"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"1-string-encoding-tests.d.ts","sourceRoot":"","sources":["../../src/2-primitives/1-string-encoding-tests.ts"],"names":[],"mappings":"AAOA,wBAAgB,mBAAmB,SAyBlC"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"2-content-addresses-tests.d.ts","sourceRoot":"","sources":["../../src/2-primitives/2-content-addresses-tests.ts"],"names":[],"mappings":"AAOA,wBAAgB,qBAAqB,SAsCpC"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"3-channel-attestations-tests.d.ts","sourceRoot":"","sources":["../../src/2-primitives/3-channel-attestations-tests.ts"],"names":[],"mappings":"AAWA,wBAAgB,uBAAuB,SAiHtC"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"4-allowed-attestations-tests.d.ts","sourceRoot":"","sources":["../../src/2-primitives/4-allowed-attestations-tests.ts"],"names":[],"mappings":"AAWA,wBAAgB,uBAAuB,SA0EtC"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"2-handles-tests.d.ts","sourceRoot":"","sources":["../../src/3-protocol/2-handles-tests.ts"],"names":[],"mappings":"AAIA,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,QAYzC"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"3-object-encoding-tests.d.ts","sourceRoot":"","sources":["../../src/3-protocol/3-object-encoding-tests.ts"],"names":[],"mappings":"AA2BA,wBAAgB,mBAAmB,SAiPlC"}
|