@graffiti-garden/api 0.4.4 → 0.5.0
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/index.cjs +1 -1
- package/dist/index.cjs.map +3 -3
- package/dist/index.mjs +1 -1
- package/dist/index.mjs.map +3 -3
- package/dist/src/1-api.d.ts +21 -50
- package/dist/src/1-api.d.ts.map +1 -1
- package/dist/src/2-types.d.ts +36 -47
- package/dist/src/2-types.d.ts.map +1 -1
- package/dist/src/3-errors.d.ts +3 -0
- package/dist/src/3-errors.d.ts.map +1 -1
- package/dist/tests/crud.d.ts.map +1 -1
- package/dist/tests/discover.d.ts.map +1 -1
- package/dist/tests/index.d.ts +0 -1
- package/dist/tests/index.d.ts.map +1 -1
- package/dist/tests/orphans.d.ts.map +1 -1
- package/dist/tests.mjs +275 -277
- package/dist/tests.mjs.map +4 -4
- package/package.json +1 -1
- package/src/1-api.ts +21 -55
- package/src/2-types.ts +33 -51
- package/src/3-errors.ts +8 -0
- package/tests/crud.ts +54 -20
- package/tests/discover.ts +22 -12
- package/tests/index.ts +0 -1
- package/tests/orphans.ts +4 -5
- package/dist/tests/location.d.ts +0 -3
- package/dist/tests/location.d.ts.map +0 -1
- package/tests/location.ts +0 -42
package/src/2-types.ts
CHANGED
|
@@ -12,9 +12,7 @@ import type { Operation as JSONPatchOperation } from "fast-json-patch";
|
|
|
12
12
|
* or properties that emerge in the Graffiti [folksonomy](https://en.wikipedia.org/wiki/Folksonomy)
|
|
13
13
|
* to promote interoperability.
|
|
14
14
|
*
|
|
15
|
-
* The
|
|
16
|
-
* properties together uniquely describe the {@link GraffitiLocation | object's location}
|
|
17
|
-
* and can be {@link Graffiti.locationToUri | converted to a globally unique URI}.
|
|
15
|
+
* The object is globally addressable via its {@link uri | `uri`}.
|
|
18
16
|
*
|
|
19
17
|
* The {@link channels | `channels`} and {@link allowed | `allowed`} properties
|
|
20
18
|
* enable the object's creator to shape the visibility of and access to their object.
|
|
@@ -78,21 +76,23 @@ export interface GraffitiObjectBase {
|
|
|
78
76
|
actor: string;
|
|
79
77
|
|
|
80
78
|
/**
|
|
81
|
-
* A
|
|
82
|
-
*
|
|
83
|
-
*
|
|
84
|
-
*
|
|
85
|
-
*
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
*
|
|
91
|
-
*
|
|
92
|
-
*
|
|
93
|
-
*
|
|
79
|
+
* A globally unique identifier for the object. It can be used to point to
|
|
80
|
+
* an object or to retrieve the object directly with {@link Graffiti.get}.
|
|
81
|
+
* If an object is {@link Graffiti.put | put} with the same URI
|
|
82
|
+
* as an existing object, the existing object will be replaced with the new object.
|
|
83
|
+
*
|
|
84
|
+
* The URI is generated on creation and include sufficient randomness to prevent collisions
|
|
85
|
+
* and guessing. The URI starts with "scheme", just like web URLs start with `http` or `https`, to indicate
|
|
86
|
+
* to indicate the particular Graffiti implementation. This allows for applications
|
|
87
|
+
* to pull from multiple coexisting Graffiti implementations without collision.
|
|
88
|
+
* Existing schemes include `graffiti:local:` for objects stored locally
|
|
89
|
+
* (see the [local implementation](https://github.com/graffiti-garden/implementation-local))
|
|
90
|
+
* and `graffiti:remote:` for objects stored on Graffiti-specific web servers (see the
|
|
91
|
+
* [remote implementation](https://github.com/graffiti-garden/implementation-remote)).
|
|
92
|
+
* Options available in the future might include `graffiti:solid:` for objects stored on Solid servers
|
|
93
|
+
* or `graffiti:p2p:` for objects stored on a peer-to-peer network.
|
|
94
94
|
*/
|
|
95
|
-
|
|
95
|
+
uri: string;
|
|
96
96
|
|
|
97
97
|
/**
|
|
98
98
|
* The time the object was last modified, measured in milliseconds since January 1, 1970.
|
|
@@ -135,38 +135,23 @@ export const GraffitiObjectJSONSchema = {
|
|
|
135
135
|
value: { type: "object" },
|
|
136
136
|
channels: { type: "array", items: { type: "string" } },
|
|
137
137
|
allowed: { type: "array", items: { type: "string" }, nullable: true },
|
|
138
|
+
uri: { type: "string" },
|
|
138
139
|
actor: { type: "string" },
|
|
139
|
-
name: { type: "string" },
|
|
140
|
-
source: { type: "string" },
|
|
141
140
|
lastModified: { type: "number" },
|
|
142
141
|
tombstone: { type: "boolean" },
|
|
143
142
|
},
|
|
144
143
|
additionalProperties: false,
|
|
145
|
-
required: [
|
|
146
|
-
"value",
|
|
147
|
-
"channels",
|
|
148
|
-
"actor",
|
|
149
|
-
"name",
|
|
150
|
-
"source",
|
|
151
|
-
"lastModified",
|
|
152
|
-
"tombstone",
|
|
153
|
-
],
|
|
144
|
+
required: ["value", "channels", "actor", "uri", "lastModified", "tombstone"],
|
|
154
145
|
} as const satisfies JSONSchema;
|
|
155
146
|
|
|
156
147
|
/**
|
|
157
|
-
* This is
|
|
158
|
-
*
|
|
159
|
-
*
|
|
160
|
-
*
|
|
161
|
-
*
|
|
162
|
-
*
|
|
163
|
-
* This location can be converted to
|
|
164
|
-
* a globally unique URI using {@link Graffiti.locationToUri}.
|
|
148
|
+
* This is an object containing only the {@link GraffitiObjectBase.uri | `uri`}
|
|
149
|
+
* property of a {@link GraffitiObjectBase | GraffitiObject}.
|
|
150
|
+
* It is used as a utility type so that users can call {@link Graffiti.get},
|
|
151
|
+
* {@link Graffiti.patch}, or {@link Graffiti.delete} directly on an object
|
|
152
|
+
* rather than on `object.uri`.
|
|
165
153
|
*/
|
|
166
|
-
export type GraffitiLocation = Pick<
|
|
167
|
-
GraffitiObjectBase,
|
|
168
|
-
"actor" | "name" | "source"
|
|
169
|
-
>;
|
|
154
|
+
export type GraffitiLocation = Pick<GraffitiObjectBase, "uri">;
|
|
170
155
|
|
|
171
156
|
/**
|
|
172
157
|
* This object is a subset of {@link GraffitiObjectBase} that a user must construct locally before calling {@link Graffiti.put}.
|
|
@@ -176,12 +161,8 @@ export type GraffitiLocation = Pick<
|
|
|
176
161
|
* This local object must have a {@link GraffitiObjectBase.value | `value`} and {@link GraffitiObjectBase.channels | `channels`}
|
|
177
162
|
* and may optionally have an {@link GraffitiObjectBase.allowed | `allowed`} property.
|
|
178
163
|
*
|
|
179
|
-
* It may also
|
|
180
|
-
*
|
|
181
|
-
* If the location provided exactly matches an existing object, the existing object will be replaced.
|
|
182
|
-
* If no `name` is provided, one will be randomly generated.
|
|
183
|
-
* If no `actor` is provided, the `actor` from the supplied {@link GraffitiSession | `session` } will be used.
|
|
184
|
-
* If no `source` is provided, one may be inferred by the depending on implementation.
|
|
164
|
+
* It may also include a {@link GraffitiObjectBase.uri | `uri`} property to specify the
|
|
165
|
+
* URI of an existing object to replace. If no `uri` is provided, one will be generated during object creation.
|
|
185
166
|
*
|
|
186
167
|
* This object does not need a {@link GraffitiObjectBase.lastModified | `lastModified`} or {@link GraffitiObjectBase.tombstone | `tombstone`}
|
|
187
168
|
* property since these are automatically generated by the Graffiti system.
|
|
@@ -204,8 +185,7 @@ export const GraffitiPutObjectJSONSchema = {
|
|
|
204
185
|
} as const satisfies JSONSchema;
|
|
205
186
|
|
|
206
187
|
/**
|
|
207
|
-
* This object contains information that
|
|
208
|
-
* {@link GraffitiObjectBase.source | `source`}s can
|
|
188
|
+
* This object contains information that the underlying implementation can
|
|
209
189
|
* use to verify that a user has permission to operate a
|
|
210
190
|
* particular {@link GraffitiObjectBase.actor | `actor`}.
|
|
211
191
|
* This object is required of all {@link Graffiti} methods
|
|
@@ -289,10 +269,12 @@ export interface GraffitiPatch {
|
|
|
289
269
|
*
|
|
290
270
|
* Errors are returned within the stream rather than as
|
|
291
271
|
* exceptions that would halt the entire stream. This is because
|
|
292
|
-
* some implementations may pull data from multiple
|
|
293
|
-
* {@link GraffitiObjectBase.source | `source`}s
|
|
272
|
+
* some implementations may pull data from multiple sources
|
|
294
273
|
* including some that may be unreliable. In many cases,
|
|
295
274
|
* these errors can be safely ignored.
|
|
275
|
+
* The `origin` property of the error object indicates the
|
|
276
|
+
* source of the error including its scheme and other
|
|
277
|
+
* implementation-specific details (e.g. domain name).
|
|
296
278
|
*
|
|
297
279
|
* The stream is an [`AsyncGenerator`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function)
|
|
298
280
|
* that can be iterated over using `for await` loops or calling `next` on the generator.
|
|
@@ -305,7 +287,7 @@ export type GraffitiStream<TValue, TReturn = void> = AsyncGenerator<
|
|
|
305
287
|
}
|
|
306
288
|
| {
|
|
307
289
|
error: Error;
|
|
308
|
-
|
|
290
|
+
origin: string;
|
|
309
291
|
},
|
|
310
292
|
TReturn
|
|
311
293
|
>;
|
package/src/3-errors.ts
CHANGED
|
@@ -61,3 +61,11 @@ export class GraffitiErrorInvalidUri extends Error {
|
|
|
61
61
|
Object.setPrototypeOf(this, GraffitiErrorInvalidUri.prototype);
|
|
62
62
|
}
|
|
63
63
|
}
|
|
64
|
+
|
|
65
|
+
export class GraffitiErrorUnrecognizedUriScheme extends Error {
|
|
66
|
+
constructor(message?: string) {
|
|
67
|
+
super(message);
|
|
68
|
+
this.name = "GraffitiErrorUnrecognizedUriScheme";
|
|
69
|
+
Object.setPrototypeOf(this, GraffitiErrorUnrecognizedUriScheme.prototype);
|
|
70
|
+
}
|
|
71
|
+
}
|
package/tests/crud.ts
CHANGED
|
@@ -5,7 +5,6 @@ import type {
|
|
|
5
5
|
GraffitiPatch,
|
|
6
6
|
JSONSchema,
|
|
7
7
|
} from "@graffiti-garden/api";
|
|
8
|
-
import type { FromSchema } from "json-schema-to-ts";
|
|
9
8
|
import {
|
|
10
9
|
GraffitiErrorNotFound,
|
|
11
10
|
GraffitiErrorSchemaMismatch,
|
|
@@ -48,7 +47,7 @@ export const graffitiCRUDTests = (
|
|
|
48
47
|
const previous = await graffiti.put<{}>({ value, channels }, session);
|
|
49
48
|
expect(previous.value).toEqual({});
|
|
50
49
|
expect(previous.channels).toEqual([]);
|
|
51
|
-
expect(previous.allowed).
|
|
50
|
+
expect(previous.allowed).toEqual([]);
|
|
52
51
|
expect(previous.actor).toEqual(session.actor);
|
|
53
52
|
|
|
54
53
|
// Get it back
|
|
@@ -56,9 +55,8 @@ export const graffitiCRUDTests = (
|
|
|
56
55
|
expect(gotten.value).toEqual(value);
|
|
57
56
|
expect(gotten.channels).toEqual([]);
|
|
58
57
|
expect(gotten.allowed).toBeUndefined();
|
|
59
|
-
expect(gotten.
|
|
58
|
+
expect(gotten.uri).toEqual(previous.uri);
|
|
60
59
|
expect(gotten.actor).toEqual(previous.actor);
|
|
61
|
-
expect(gotten.source).toEqual(previous.source);
|
|
62
60
|
expect(gotten.lastModified).toEqual(previous.lastModified);
|
|
63
61
|
|
|
64
62
|
// Replace it
|
|
@@ -66,14 +64,17 @@ export const graffitiCRUDTests = (
|
|
|
66
64
|
something: "goodbye, world~ :c",
|
|
67
65
|
};
|
|
68
66
|
const beforeReplaced = await graffiti.put<{}>(
|
|
69
|
-
{
|
|
67
|
+
{
|
|
68
|
+
uri: previous.uri,
|
|
69
|
+
value: newValue,
|
|
70
|
+
channels: [],
|
|
71
|
+
},
|
|
70
72
|
session,
|
|
71
73
|
);
|
|
72
74
|
expect(beforeReplaced.value).toEqual(value);
|
|
73
75
|
expect(beforeReplaced.tombstone).toEqual(true);
|
|
74
|
-
expect(beforeReplaced.
|
|
76
|
+
expect(beforeReplaced.uri).toEqual(previous.uri);
|
|
75
77
|
expect(beforeReplaced.actor).toEqual(previous.actor);
|
|
76
|
-
expect(beforeReplaced.source).toEqual(previous.source);
|
|
77
78
|
expect(beforeReplaced.lastModified).toBeGreaterThanOrEqual(
|
|
78
79
|
gotten.lastModified,
|
|
79
80
|
);
|
|
@@ -95,22 +96,14 @@ export const graffitiCRUDTests = (
|
|
|
95
96
|
// Get a tombstone
|
|
96
97
|
const final = await graffiti.get(afterReplaced, {});
|
|
97
98
|
expect(final).toEqual(beforeDeleted);
|
|
98
|
-
});
|
|
99
99
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
{
|
|
105
|
-
...putted,
|
|
106
|
-
name: randomString(),
|
|
107
|
-
},
|
|
108
|
-
{},
|
|
109
|
-
),
|
|
110
|
-
).rejects.toBeInstanceOf(GraffitiErrorNotFound);
|
|
100
|
+
// Delete it again
|
|
101
|
+
await expect(graffiti.delete(final, session)).rejects.toThrow(
|
|
102
|
+
GraffitiErrorNotFound,
|
|
103
|
+
);
|
|
111
104
|
});
|
|
112
105
|
|
|
113
|
-
it("put,
|
|
106
|
+
it("put, delete, patch with wrong actor", async () => {
|
|
114
107
|
await expect(
|
|
115
108
|
graffiti.put<{}>(
|
|
116
109
|
{ value: {}, channels: [], actor: session2.actor },
|
|
@@ -123,6 +116,17 @@ export const graffitiCRUDTests = (
|
|
|
123
116
|
session2,
|
|
124
117
|
);
|
|
125
118
|
|
|
119
|
+
await expect(
|
|
120
|
+
graffiti.put<{}>(
|
|
121
|
+
{
|
|
122
|
+
uri: putted.uri,
|
|
123
|
+
value: {},
|
|
124
|
+
channels: [],
|
|
125
|
+
},
|
|
126
|
+
session1,
|
|
127
|
+
),
|
|
128
|
+
).rejects.toThrow(GraffitiErrorForbidden);
|
|
129
|
+
|
|
126
130
|
await expect(graffiti.delete(putted, session1)).rejects.toThrow(
|
|
127
131
|
GraffitiErrorForbidden,
|
|
128
132
|
);
|
|
@@ -132,6 +136,36 @@ export const graffitiCRUDTests = (
|
|
|
132
136
|
);
|
|
133
137
|
});
|
|
134
138
|
|
|
139
|
+
it("put, patch, delete object that is not allowed", async () => {
|
|
140
|
+
const putted = await graffiti.put<{}>(
|
|
141
|
+
{
|
|
142
|
+
value: {},
|
|
143
|
+
channels: [],
|
|
144
|
+
allowed: [],
|
|
145
|
+
},
|
|
146
|
+
session1,
|
|
147
|
+
);
|
|
148
|
+
|
|
149
|
+
await expect(
|
|
150
|
+
graffiti.put(
|
|
151
|
+
{
|
|
152
|
+
uri: putted.uri,
|
|
153
|
+
value: {},
|
|
154
|
+
channels: [],
|
|
155
|
+
},
|
|
156
|
+
session2,
|
|
157
|
+
),
|
|
158
|
+
).rejects.toThrow(GraffitiErrorNotFound);
|
|
159
|
+
|
|
160
|
+
await expect(graffiti.patch({}, putted, session2)).rejects.toThrow(
|
|
161
|
+
GraffitiErrorNotFound,
|
|
162
|
+
);
|
|
163
|
+
|
|
164
|
+
await expect(graffiti.delete(putted, session2)).rejects.toThrow(
|
|
165
|
+
GraffitiErrorNotFound,
|
|
166
|
+
);
|
|
167
|
+
});
|
|
168
|
+
|
|
135
169
|
it("put and get with schema", async () => {
|
|
136
170
|
const schema = {
|
|
137
171
|
properties: {
|
package/tests/discover.ts
CHANGED
|
@@ -89,7 +89,7 @@ export const graffitiDiscoverTests = (
|
|
|
89
89
|
expect(value.lastModified).toEqual(putted.lastModified);
|
|
90
90
|
});
|
|
91
91
|
|
|
92
|
-
for (const prop of ["
|
|
92
|
+
for (const prop of ["actor", "lastModified"] as const) {
|
|
93
93
|
it(`discover for ${prop}`, async () => {
|
|
94
94
|
const object1 = randomPutObject();
|
|
95
95
|
const putted1 = await graffiti.put<{}>(object1, session1);
|
|
@@ -109,8 +109,8 @@ export const graffitiDiscoverTests = (
|
|
|
109
109
|
});
|
|
110
110
|
|
|
111
111
|
const value = await nextStreamValue(iterator);
|
|
112
|
-
expect(value.
|
|
113
|
-
expect(value.
|
|
112
|
+
expect(value.uri).toEqual(putted1.uri);
|
|
113
|
+
expect(value.uri).not.toEqual(putted2.uri);
|
|
114
114
|
expect(value.value).toEqual(object1.value);
|
|
115
115
|
await expect(iterator.next()).resolves.toHaveProperty("done", true);
|
|
116
116
|
});
|
|
@@ -123,7 +123,7 @@ export const graffitiDiscoverTests = (
|
|
|
123
123
|
await new Promise((r) => setTimeout(r, 20));
|
|
124
124
|
const putted2 = await graffiti.put<{}>(object, session);
|
|
125
125
|
|
|
126
|
-
expect(putted1.
|
|
126
|
+
expect(putted1.uri).not.toEqual(putted2.uri);
|
|
127
127
|
expect(putted1.lastModified).toBeLessThan(putted2.lastModified);
|
|
128
128
|
|
|
129
129
|
const gtIterator = graffiti.discover([object.channels[0]], {
|
|
@@ -142,7 +142,7 @@ export const graffitiDiscoverTests = (
|
|
|
142
142
|
},
|
|
143
143
|
});
|
|
144
144
|
const value1 = await nextStreamValue(gtIteratorEpsilon);
|
|
145
|
-
expect(value1.
|
|
145
|
+
expect(value1.uri).toEqual(putted2.uri);
|
|
146
146
|
expect(await gtIteratorEpsilon.next()).toHaveProperty("done", true);
|
|
147
147
|
const gteIterator = graffiti.discover(object.channels, {
|
|
148
148
|
properties: {
|
|
@@ -153,7 +153,7 @@ export const graffitiDiscoverTests = (
|
|
|
153
153
|
},
|
|
154
154
|
});
|
|
155
155
|
const value = await nextStreamValue(gteIterator);
|
|
156
|
-
expect(value.
|
|
156
|
+
expect(value.uri).toEqual(putted2.uri);
|
|
157
157
|
expect(await gteIterator.next()).toHaveProperty("done", true);
|
|
158
158
|
const gteIteratorEpsilon = graffiti.discover(object.channels, {
|
|
159
159
|
properties: {
|
|
@@ -181,7 +181,7 @@ export const graffitiDiscoverTests = (
|
|
|
181
181
|
},
|
|
182
182
|
});
|
|
183
183
|
const value3 = await nextStreamValue(ltIteratorEpsilon);
|
|
184
|
-
expect(value3.
|
|
184
|
+
expect(value3.uri).toEqual(putted1.uri);
|
|
185
185
|
expect(await ltIteratorEpsilon.next()).toHaveProperty("done", true);
|
|
186
186
|
|
|
187
187
|
const lteIterator = graffiti.discover(object.channels, {
|
|
@@ -192,7 +192,7 @@ export const graffitiDiscoverTests = (
|
|
|
192
192
|
},
|
|
193
193
|
});
|
|
194
194
|
const value2 = await nextStreamValue(lteIterator);
|
|
195
|
-
expect(value2.
|
|
195
|
+
expect(value2.uri).toEqual(putted1.uri);
|
|
196
196
|
expect(await lteIterator.next()).toHaveProperty("done", true);
|
|
197
197
|
|
|
198
198
|
const lteIteratorEpsilon = graffiti.discover(object.channels, {
|
|
@@ -481,8 +481,8 @@ export const graffitiDiscoverTests = (
|
|
|
481
481
|
const object2 = randomPutObject();
|
|
482
482
|
const replaced = await graffiti.put<{}>(
|
|
483
483
|
{
|
|
484
|
-
...putted,
|
|
485
484
|
...object2,
|
|
485
|
+
uri: putted.uri,
|
|
486
486
|
},
|
|
487
487
|
session,
|
|
488
488
|
);
|
|
@@ -535,11 +535,21 @@ export const graffitiDiscoverTests = (
|
|
|
535
535
|
|
|
536
536
|
it("put concurrently and discover one", async () => {
|
|
537
537
|
const object = randomPutObject();
|
|
538
|
-
object.name = randomString();
|
|
539
538
|
|
|
540
|
-
|
|
539
|
+
// Put a first one to get a URI
|
|
540
|
+
const putted = await graffiti.put<{}>(object, session);
|
|
541
|
+
|
|
542
|
+
const putPromises = Array(99)
|
|
541
543
|
.fill(0)
|
|
542
|
-
.map(() =>
|
|
544
|
+
.map(() =>
|
|
545
|
+
graffiti.put<{}>(
|
|
546
|
+
{
|
|
547
|
+
...object,
|
|
548
|
+
uri: putted.uri,
|
|
549
|
+
},
|
|
550
|
+
session,
|
|
551
|
+
),
|
|
552
|
+
);
|
|
543
553
|
await Promise.all(putPromises);
|
|
544
554
|
|
|
545
555
|
const iterator = graffiti.discover(object.channels, {});
|
package/tests/index.ts
CHANGED
package/tests/orphans.ts
CHANGED
|
@@ -27,7 +27,7 @@ export const graffitiOrphanTests = (
|
|
|
27
27
|
const orphanIterator1 = graffiti.recoverOrphans({}, session);
|
|
28
28
|
for await (const orphan of orphanIterator1) {
|
|
29
29
|
if (orphan.error) continue;
|
|
30
|
-
existingOrphans.push(orphan.value.
|
|
30
|
+
existingOrphans.push(orphan.value.uri);
|
|
31
31
|
}
|
|
32
32
|
|
|
33
33
|
const object = randomPutObject();
|
|
@@ -37,9 +37,8 @@ export const graffitiOrphanTests = (
|
|
|
37
37
|
let numResults = 0;
|
|
38
38
|
for await (const orphan of orphanIterator2) {
|
|
39
39
|
if (orphan.error) continue;
|
|
40
|
-
if (orphan.value.
|
|
40
|
+
if (orphan.value.uri === putted.uri) {
|
|
41
41
|
numResults++;
|
|
42
|
-
expect(orphan.value.source).toBe(putted.source);
|
|
43
42
|
expect(orphan.value.lastModified).toBe(putted.lastModified);
|
|
44
43
|
}
|
|
45
44
|
}
|
|
@@ -62,14 +61,14 @@ export const graffitiOrphanTests = (
|
|
|
62
61
|
},
|
|
63
62
|
session,
|
|
64
63
|
);
|
|
65
|
-
expect(putNotOrphan.
|
|
64
|
+
expect(putNotOrphan.uri).toBe(putOrphan.uri);
|
|
66
65
|
expect(putNotOrphan.lastModified).toBeGreaterThan(putOrphan.lastModified);
|
|
67
66
|
|
|
68
67
|
const orphanIterator = graffiti.recoverOrphans({}, session);
|
|
69
68
|
let numResults = 0;
|
|
70
69
|
for await (const orphan of orphanIterator) {
|
|
71
70
|
if (orphan.error) continue;
|
|
72
|
-
if (orphan.value.
|
|
71
|
+
if (orphan.value.uri === putOrphan.uri) {
|
|
73
72
|
numResults++;
|
|
74
73
|
expect(orphan.value.tombstone).toBe(true);
|
|
75
74
|
expect(orphan.value.lastModified).toBe(putNotOrphan.lastModified);
|
package/dist/tests/location.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"location.d.ts","sourceRoot":"","sources":["../../tests/location.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAIrD,eAAO,MAAM,qBAAqB,GAChC,aAAa,MAAM,IAAI,CAAC,QAAQ,EAAE,eAAe,GAAG,eAAe,CAAC,SAmCrE,CAAC"}
|
package/tests/location.ts
DELETED
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
import { it, expect, describe } from "vitest";
|
|
2
|
-
import type { Graffiti } from "@graffiti-garden/api";
|
|
3
|
-
import { GraffitiErrorInvalidUri } from "@graffiti-garden/api";
|
|
4
|
-
import { randomString } from "./utils";
|
|
5
|
-
|
|
6
|
-
export const graffitiLocationTests = (
|
|
7
|
-
useGraffiti: () => Pick<Graffiti, "locationToUri" | "uriToLocation">,
|
|
8
|
-
) => {
|
|
9
|
-
describe.concurrent("URI and location conversion", () => {
|
|
10
|
-
it("location to uri and back", async () => {
|
|
11
|
-
const graffiti = useGraffiti();
|
|
12
|
-
const location = {
|
|
13
|
-
name: randomString(),
|
|
14
|
-
actor: randomString(),
|
|
15
|
-
source: randomString(),
|
|
16
|
-
};
|
|
17
|
-
const uri = graffiti.locationToUri(location);
|
|
18
|
-
const location2 = graffiti.uriToLocation(uri);
|
|
19
|
-
expect(location).toEqual(location2);
|
|
20
|
-
});
|
|
21
|
-
|
|
22
|
-
it("collision resistance", async () => {
|
|
23
|
-
const graffiti = useGraffiti();
|
|
24
|
-
const location1 = {
|
|
25
|
-
name: randomString(),
|
|
26
|
-
actor: randomString(),
|
|
27
|
-
source: randomString(),
|
|
28
|
-
};
|
|
29
|
-
for (const prop of ["name", "actor", "source"] as const) {
|
|
30
|
-
const location2 = { ...location1, [prop]: randomString() };
|
|
31
|
-
const uri1 = graffiti.locationToUri(location1);
|
|
32
|
-
const uri2 = graffiti.locationToUri(location2);
|
|
33
|
-
expect(uri1).not.toEqual(uri2);
|
|
34
|
-
}
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
it("random URI should not be a valid location", async () => {
|
|
38
|
-
const graffiti = useGraffiti();
|
|
39
|
-
expect(() => graffiti.uriToLocation("")).toThrow(GraffitiErrorInvalidUri);
|
|
40
|
-
});
|
|
41
|
-
});
|
|
42
|
-
};
|