@graffiti-garden/wrapper-synchronize 0.2.3 → 1.0.2
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/README.md +1 -1
- package/dist/browser/ajv-UZKI6BMI.js +9 -0
- package/dist/browser/ajv-UZKI6BMI.js.map +7 -0
- package/dist/browser/chunk-YB7WCAZH.js +7 -0
- package/dist/browser/{chunk-POQWWD2G.js.map → chunk-YB7WCAZH.js.map} +1 -1
- package/dist/browser/index.js +1 -1
- package/dist/browser/index.js.map +4 -4
- package/dist/cjs/index.js +90 -135
- package/dist/cjs/index.js.map +2 -2
- package/dist/esm/index.js +91 -136
- package/dist/esm/index.js.map +2 -2
- package/dist/index.d.ts +39 -47
- package/dist/index.d.ts.map +1 -1
- package/package.json +12 -13
- package/src/index.spec.ts +110 -277
- package/src/index.ts +121 -165
- package/dist/browser/ajv-65NGXB2O.js +0 -9
- package/dist/browser/ajv-65NGXB2O.js.map +0 -7
- package/dist/browser/chunk-POQWWD2G.js +0 -7
- package/dist/browser/fast-json-patch-RVBYS6DB.js +0 -19
- package/dist/browser/fast-json-patch-RVBYS6DB.js.map +0 -7
package/src/index.ts
CHANGED
|
@@ -1,28 +1,26 @@
|
|
|
1
1
|
import type Ajv from "ajv";
|
|
2
|
-
import { Graffiti } from "@graffiti-garden/api";
|
|
3
2
|
import type {
|
|
3
|
+
Graffiti,
|
|
4
4
|
GraffitiSession,
|
|
5
5
|
JSONSchema,
|
|
6
|
+
GraffitiObjectBase,
|
|
6
7
|
GraffitiObjectStream,
|
|
7
8
|
GraffitiObjectStreamContinueEntry,
|
|
8
9
|
GraffitiObjectStreamContinue,
|
|
9
|
-
|
|
10
|
+
GraffitiObjectUrl,
|
|
10
11
|
} from "@graffiti-garden/api";
|
|
11
|
-
import type { GraffitiObjectBase } from "@graffiti-garden/api";
|
|
12
|
-
import { Repeater } from "@repeaterjs/repeater";
|
|
13
|
-
import type { applyPatch } from "fast-json-patch";
|
|
14
12
|
import {
|
|
15
|
-
|
|
13
|
+
GraffitiErrorNotFound,
|
|
16
14
|
compileGraffitiObjectSchema,
|
|
17
15
|
isActorAllowedGraffitiObject,
|
|
18
16
|
maskGraffitiObject,
|
|
19
17
|
unpackObjectUrl,
|
|
20
|
-
} from "@graffiti-garden/
|
|
18
|
+
} from "@graffiti-garden/api";
|
|
19
|
+
import { Repeater } from "@repeaterjs/repeater";
|
|
21
20
|
export type * from "@graffiti-garden/api";
|
|
22
21
|
|
|
23
22
|
export type GraffitiSynchronizeCallback = (
|
|
24
|
-
|
|
25
|
-
newObject?: GraffitiObjectStreamContinueEntry<{}>,
|
|
23
|
+
object: GraffitiObjectStreamContinueEntry<{}>,
|
|
26
24
|
) => void;
|
|
27
25
|
|
|
28
26
|
export interface GraffitiSynchronizeOptions {
|
|
@@ -48,23 +46,24 @@ export interface GraffitiSynchronizeOptions {
|
|
|
48
46
|
* the [Graffiti Vue Plugin](https://vue.graffiti.garden/variables/GraffitiPlugin.html)
|
|
49
47
|
* and possibly other front-end libraries in the future.
|
|
50
48
|
*
|
|
51
|
-
*
|
|
52
|
-
*
|
|
49
|
+
* [See a live example](/example).
|
|
50
|
+
*
|
|
51
|
+
* Specifically, this library provides the following *synchronize*
|
|
52
|
+
* methods to correspond with each of the following Graffiti API methods:
|
|
53
53
|
*
|
|
54
54
|
* | API Method | Synchronize Method |
|
|
55
55
|
* |------------|--------------------|
|
|
56
56
|
* | {@link get} | {@link synchronizeGet} |
|
|
57
57
|
* | {@link discover} | {@link synchronizeDiscover} |
|
|
58
|
-
* | {@link recoverOrphans} | {@link synchronizeRecoverOrphans} |
|
|
59
58
|
*
|
|
60
|
-
* Whenever a change is made via {@link
|
|
61
|
-
* received from {@link get}, {@link discover}, and {@link
|
|
59
|
+
* Whenever a change is made via {@link post} and {@link delete} or
|
|
60
|
+
* received from {@link get}, {@link discover}, and {@link continueDiscover},
|
|
62
61
|
* those changes are forwarded to the appropriate synchronize method.
|
|
63
62
|
* Each synchronize method returns an iterator that streams these changes
|
|
64
63
|
* continually until the user calls `return` on the iterator or `break`s out of the loop,
|
|
65
64
|
* allowing for live updates without additional polling.
|
|
66
65
|
*
|
|
67
|
-
* Example 1: Suppose a user publishes a post using {@link
|
|
66
|
+
* Example 1: Suppose a user publishes a post using {@link post}. If the feed
|
|
68
67
|
* displaying that user's posts is using {@link synchronizeDiscover} to listen for changes,
|
|
69
68
|
* then the user's new post will instantly appear in their feed, giving the UI a
|
|
70
69
|
* responsive feel.
|
|
@@ -75,25 +74,34 @@ export interface GraffitiSynchronizeOptions {
|
|
|
75
74
|
* all instance's of that friend's name in the user's application instantly,
|
|
76
75
|
* providing a consistent user experience.
|
|
77
76
|
*
|
|
78
|
-
* @
|
|
77
|
+
* Additionally, the library supplies a {@link synchronizeAll} method that can be used
|
|
78
|
+
* to stream all the Graffiti changes that an application is aware of, which can be used
|
|
79
|
+
* for caching or history building.
|
|
80
|
+
*
|
|
81
|
+
* The source code for this library is [available on GitHub](https://github.com/graffiti-garden/wrapper-synchronize/).
|
|
82
|
+
*
|
|
83
|
+
* @groupDescription 0 - Synchronize Methods
|
|
79
84
|
* This group contains methods that listen for changes made via
|
|
80
|
-
* {@link
|
|
81
|
-
* {@link get}, {@link discover},
|
|
85
|
+
* {@link post}, and {@link delete} or fetched from
|
|
86
|
+
* {@link get}, {@link discover}, or {@link continueDiscover} and then
|
|
82
87
|
* streams appropriate changes to provide a responsive and consistent user experience.
|
|
83
88
|
*/
|
|
84
|
-
export class GraffitiSynchronize
|
|
89
|
+
export class GraffitiSynchronize implements Graffiti {
|
|
85
90
|
protected ajv_: Promise<Ajv> | undefined;
|
|
86
|
-
protected applyPatch_: Promise<typeof applyPatch> | undefined;
|
|
87
91
|
protected readonly graffiti: Graffiti;
|
|
88
92
|
protected readonly callbacks = new Set<GraffitiSynchronizeCallback>();
|
|
89
93
|
protected readonly options: GraffitiSynchronizeOptions;
|
|
90
94
|
|
|
91
|
-
channelStats: Graffiti["channelStats"];
|
|
92
95
|
login: Graffiti["login"];
|
|
93
96
|
logout: Graffiti["logout"];
|
|
94
97
|
sessionEvents: Graffiti["sessionEvents"];
|
|
98
|
+
postMedia: Graffiti["postMedia"];
|
|
99
|
+
getMedia: Graffiti["getMedia"];
|
|
100
|
+
deleteMedia: Graffiti["deleteMedia"];
|
|
101
|
+
actorToHandle: Graffiti["actorToHandle"];
|
|
102
|
+
handleToActor: Graffiti["handleToActor"];
|
|
95
103
|
|
|
96
|
-
get ajv() {
|
|
104
|
+
protected get ajv() {
|
|
97
105
|
if (!this.ajv_) {
|
|
98
106
|
this.ajv_ = (async () => {
|
|
99
107
|
const { default: Ajv } = await import("ajv");
|
|
@@ -103,16 +111,6 @@ export class GraffitiSynchronize extends Graffiti {
|
|
|
103
111
|
return this.ajv_;
|
|
104
112
|
}
|
|
105
113
|
|
|
106
|
-
get applyPatch() {
|
|
107
|
-
if (!this.applyPatch_) {
|
|
108
|
-
this.applyPatch_ = (async () => {
|
|
109
|
-
const { applyPatch } = await import("fast-json-patch");
|
|
110
|
-
return applyPatch;
|
|
111
|
-
})();
|
|
112
|
-
}
|
|
113
|
-
return this.applyPatch_;
|
|
114
|
-
}
|
|
115
|
-
|
|
116
114
|
/**
|
|
117
115
|
* Wraps a Graffiti API instance to provide the synchronize methods.
|
|
118
116
|
* The GraffitiSyncrhonize class rather than the Graffiti class
|
|
@@ -126,13 +124,16 @@ export class GraffitiSynchronize extends Graffiti {
|
|
|
126
124
|
graffiti: Graffiti,
|
|
127
125
|
options?: GraffitiSynchronizeOptions,
|
|
128
126
|
) {
|
|
129
|
-
super();
|
|
130
127
|
this.options = options ?? {};
|
|
131
128
|
this.graffiti = graffiti;
|
|
132
|
-
this.channelStats = graffiti.channelStats.bind(graffiti);
|
|
133
129
|
this.login = graffiti.login.bind(graffiti);
|
|
134
130
|
this.logout = graffiti.logout.bind(graffiti);
|
|
135
131
|
this.sessionEvents = graffiti.sessionEvents;
|
|
132
|
+
this.postMedia = graffiti.postMedia.bind(graffiti);
|
|
133
|
+
this.getMedia = graffiti.getMedia.bind(graffiti);
|
|
134
|
+
this.deleteMedia = graffiti.deleteMedia.bind(graffiti);
|
|
135
|
+
this.actorToHandle = graffiti.actorToHandle.bind(graffiti);
|
|
136
|
+
this.handleToActor = graffiti.handleToActor.bind(graffiti);
|
|
136
137
|
}
|
|
137
138
|
|
|
138
139
|
protected synchronize<Schema extends JSONSchema>(
|
|
@@ -140,39 +141,32 @@ export class GraffitiSynchronize extends Graffiti {
|
|
|
140
141
|
channels: string[],
|
|
141
142
|
schema: Schema,
|
|
142
143
|
session?: GraffitiSession | null,
|
|
144
|
+
seenUrls: Set<string> = new Set<string>(),
|
|
143
145
|
): AsyncGenerator<GraffitiObjectStreamContinueEntry<Schema>> {
|
|
144
|
-
const seenUrls = new Set<string>();
|
|
145
|
-
|
|
146
146
|
const repeater = new Repeater<GraffitiObjectStreamContinueEntry<Schema>>(
|
|
147
147
|
async (push, stop) => {
|
|
148
148
|
const validate = compileGraffitiObjectSchema(await this.ajv, schema);
|
|
149
|
-
const callback: GraffitiSynchronizeCallback = (
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
)
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
}
|
|
171
|
-
if (validate(object)) {
|
|
172
|
-
push({ object });
|
|
173
|
-
seenUrls.add(object.url);
|
|
174
|
-
break;
|
|
175
|
-
}
|
|
149
|
+
const callback: GraffitiSynchronizeCallback = (objectUpdate) => {
|
|
150
|
+
if (objectUpdate?.tombstone) {
|
|
151
|
+
if (seenUrls.has(objectUpdate.object.url)) {
|
|
152
|
+
push(objectUpdate);
|
|
153
|
+
}
|
|
154
|
+
} else if (
|
|
155
|
+
objectUpdate &&
|
|
156
|
+
matchObject(objectUpdate.object) &&
|
|
157
|
+
(this.options.omniscient ||
|
|
158
|
+
isActorAllowedGraffitiObject(objectUpdate.object, session))
|
|
159
|
+
) {
|
|
160
|
+
// Deep clone the object to prevent mutation
|
|
161
|
+
const object = JSON.parse(
|
|
162
|
+
JSON.stringify(objectUpdate.object),
|
|
163
|
+
) as GraffitiObjectBase;
|
|
164
|
+
if (!this.options.omniscient) {
|
|
165
|
+
maskGraffitiObject(object, channels, session);
|
|
166
|
+
}
|
|
167
|
+
if (validate(object)) {
|
|
168
|
+
push({ object });
|
|
169
|
+
seenUrls.add(object.url);
|
|
176
170
|
}
|
|
177
171
|
}
|
|
178
172
|
};
|
|
@@ -183,13 +177,15 @@ export class GraffitiSynchronize extends Graffiti {
|
|
|
183
177
|
},
|
|
184
178
|
);
|
|
185
179
|
|
|
186
|
-
return
|
|
180
|
+
return (async function* () {
|
|
181
|
+
for await (const i of repeater) yield i;
|
|
182
|
+
})();
|
|
187
183
|
}
|
|
188
184
|
|
|
189
185
|
/**
|
|
190
186
|
* This method has the same signature as {@link discover} but listens for
|
|
191
|
-
* changes made via {@link
|
|
192
|
-
* fetched from {@link get}, {@link discover}, and {@link
|
|
187
|
+
* changes made via {@link post} and {@link delete} or
|
|
188
|
+
* fetched from {@link get}, {@link discover}, and {@link continueDiscover}
|
|
193
189
|
* and then streams appropriate changes to provide a responsive and
|
|
194
190
|
* consistent user experience.
|
|
195
191
|
*
|
|
@@ -197,12 +193,13 @@ export class GraffitiSynchronize extends Graffiti {
|
|
|
197
193
|
* and will not terminate unless the user calls the `return` method on the iterator
|
|
198
194
|
* or `break`s out of the loop.
|
|
199
195
|
*
|
|
200
|
-
* @group Synchronize Methods
|
|
196
|
+
* @group 0 - Synchronize Methods
|
|
201
197
|
*/
|
|
202
198
|
synchronizeDiscover<Schema extends JSONSchema>(
|
|
203
|
-
|
|
199
|
+
channels: string[],
|
|
200
|
+
schema: Schema,
|
|
201
|
+
session?: GraffitiSession | null,
|
|
204
202
|
): AsyncGenerator<GraffitiObjectStreamContinueEntry<Schema>> {
|
|
205
|
-
const [channels, schema, session] = args;
|
|
206
203
|
function matchObject(object: GraffitiObjectBase) {
|
|
207
204
|
return object.channels.some((channel) => channels.includes(channel));
|
|
208
205
|
}
|
|
@@ -211,48 +208,32 @@ export class GraffitiSynchronize extends Graffiti {
|
|
|
211
208
|
|
|
212
209
|
/**
|
|
213
210
|
* This method has the same signature as {@link get} but
|
|
214
|
-
* listens for changes made via {@link
|
|
215
|
-
* fetched from {@link get}, {@link discover}, and {@link
|
|
211
|
+
* listens for changes made via {@link post}, and {@link delete} or
|
|
212
|
+
* fetched from {@link get}, {@link discover}, and {@link continueDiscover} and then
|
|
216
213
|
* streams appropriate changes to provide a responsive and consistent user experience.
|
|
217
214
|
*
|
|
218
215
|
* Unlike {@link get}, which returns a single result, this method continuously
|
|
219
216
|
* listens for changes which are output as an asynchronous stream, similar
|
|
220
217
|
* to {@link discover}.
|
|
221
218
|
*
|
|
222
|
-
* @group Synchronize Methods
|
|
219
|
+
* @group 0 - Synchronize Methods
|
|
223
220
|
*/
|
|
224
221
|
synchronizeGet<Schema extends JSONSchema>(
|
|
225
|
-
|
|
222
|
+
objectUrl: string | GraffitiObjectUrl,
|
|
223
|
+
schema: Schema,
|
|
224
|
+
session?: GraffitiSession | null | undefined,
|
|
226
225
|
): AsyncGenerator<GraffitiObjectStreamContinueEntry<Schema>> {
|
|
227
|
-
const [objectUrl, schema, session] = args;
|
|
228
226
|
const url = unpackObjectUrl(objectUrl);
|
|
229
227
|
function matchObject(object: GraffitiObjectBase) {
|
|
230
228
|
return object.url === url;
|
|
231
229
|
}
|
|
232
|
-
return this.synchronize<Schema>(
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
* {@link get}, {@link discover}, and {@link recoverOrphans} and then
|
|
240
|
-
* streams appropriate changes to provide a responsive and consistent user experience.
|
|
241
|
-
*
|
|
242
|
-
* Unlike {@link recoverOrphans}, this method continuously listens for changes
|
|
243
|
-
* and will not terminate unless the user calls the `return` method on the iterator
|
|
244
|
-
* or `break`s out of the loop.
|
|
245
|
-
*
|
|
246
|
-
* @group Synchronize Methods
|
|
247
|
-
*/
|
|
248
|
-
synchronizeRecoverOrphans<Schema extends JSONSchema>(
|
|
249
|
-
...args: Parameters<typeof Graffiti.prototype.recoverOrphans<Schema>>
|
|
250
|
-
): AsyncGenerator<GraffitiObjectStreamContinueEntry<Schema>> {
|
|
251
|
-
const [schema, session] = args;
|
|
252
|
-
function matchObject(object: GraffitiObjectBase) {
|
|
253
|
-
return object.actor === session.actor && object.channels.length === 0;
|
|
254
|
-
}
|
|
255
|
-
return this.synchronize<Schema>(matchObject, [], schema, session);
|
|
230
|
+
return this.synchronize<Schema>(
|
|
231
|
+
matchObject,
|
|
232
|
+
[],
|
|
233
|
+
schema,
|
|
234
|
+
session,
|
|
235
|
+
new Set<string>([url]),
|
|
236
|
+
);
|
|
256
237
|
}
|
|
257
238
|
|
|
258
239
|
/**
|
|
@@ -264,6 +245,8 @@ export class GraffitiSynchronize extends Graffiti {
|
|
|
264
245
|
*
|
|
265
246
|
* Be careful using this method. Without additional filters it can
|
|
266
247
|
* expose the user to content out of context.
|
|
248
|
+
*
|
|
249
|
+
* @group 0 - Synchronize Methods
|
|
267
250
|
*/
|
|
268
251
|
synchronizeAll<Schema extends JSONSchema>(
|
|
269
252
|
schema: Schema,
|
|
@@ -273,12 +256,11 @@ export class GraffitiSynchronize extends Graffiti {
|
|
|
273
256
|
}
|
|
274
257
|
|
|
275
258
|
protected async synchronizeDispatch(
|
|
276
|
-
|
|
277
|
-
newObject?: GraffitiObjectStreamContinueEntry<{}>,
|
|
259
|
+
objectUpdate: GraffitiObjectStreamContinueEntry<{}>,
|
|
278
260
|
waitForListeners = false,
|
|
279
261
|
) {
|
|
280
262
|
for (const callback of this.callbacks) {
|
|
281
|
-
callback(
|
|
263
|
+
callback(objectUpdate);
|
|
282
264
|
}
|
|
283
265
|
if (waitForListeners) {
|
|
284
266
|
// Wait for the listeners to receive
|
|
@@ -306,63 +288,43 @@ export class GraffitiSynchronize extends Graffiti {
|
|
|
306
288
|
}
|
|
307
289
|
|
|
308
290
|
get: Graffiti["get"] = async (...args) => {
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
};
|
|
323
|
-
await this.synchronizeDispatch(
|
|
324
|
-
{
|
|
325
|
-
tombstone: true,
|
|
326
|
-
object: oldObject,
|
|
327
|
-
},
|
|
328
|
-
{
|
|
329
|
-
object: newObject,
|
|
330
|
-
},
|
|
331
|
-
true,
|
|
332
|
-
);
|
|
333
|
-
return oldObject;
|
|
291
|
+
try {
|
|
292
|
+
const object = await this.graffiti.get(...args);
|
|
293
|
+
this.synchronizeDispatch({ object });
|
|
294
|
+
return object;
|
|
295
|
+
} catch (error) {
|
|
296
|
+
if (error instanceof GraffitiErrorNotFound) {
|
|
297
|
+
this.synchronizeDispatch({
|
|
298
|
+
tombstone: true,
|
|
299
|
+
object: { url: unpackObjectUrl(args[0]) },
|
|
300
|
+
});
|
|
301
|
+
}
|
|
302
|
+
throw error;
|
|
303
|
+
}
|
|
334
304
|
};
|
|
335
305
|
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
const
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
}
|
|
342
|
-
await this.synchronizeDispatch(
|
|
343
|
-
{
|
|
344
|
-
tombstone: true,
|
|
345
|
-
object: oldObject,
|
|
346
|
-
},
|
|
347
|
-
{
|
|
348
|
-
object: newObject,
|
|
349
|
-
},
|
|
350
|
-
true,
|
|
351
|
-
);
|
|
352
|
-
return oldObject;
|
|
306
|
+
post: Graffiti["post"] = async (...args) => {
|
|
307
|
+
// @ts-ignore
|
|
308
|
+
const object = await this.graffiti.post(...args);
|
|
309
|
+
await this.synchronizeDispatch({ object }, true);
|
|
310
|
+
return object;
|
|
353
311
|
};
|
|
354
312
|
|
|
355
313
|
delete: Graffiti["delete"] = async (...args) => {
|
|
356
|
-
const
|
|
357
|
-
|
|
358
|
-
{
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
)
|
|
365
|
-
|
|
314
|
+
const update = {
|
|
315
|
+
tombstone: true,
|
|
316
|
+
object: { url: unpackObjectUrl(args[0]) },
|
|
317
|
+
} as const;
|
|
318
|
+
try {
|
|
319
|
+
const oldObject = await this.graffiti.delete(...args);
|
|
320
|
+
await this.synchronizeDispatch(update, true);
|
|
321
|
+
return oldObject;
|
|
322
|
+
} catch (error) {
|
|
323
|
+
if (error instanceof GraffitiErrorNotFound) {
|
|
324
|
+
await this.synchronizeDispatch(update, true);
|
|
325
|
+
}
|
|
326
|
+
throw error;
|
|
327
|
+
}
|
|
366
328
|
};
|
|
367
329
|
|
|
368
330
|
protected objectStreamContinue<Schema extends JSONSchema>(
|
|
@@ -375,14 +337,13 @@ export class GraffitiSynchronize extends Graffiti {
|
|
|
375
337
|
if (result.done) {
|
|
376
338
|
const { continue: continue_, cursor } = result.value;
|
|
377
339
|
return {
|
|
378
|
-
continue: () =>
|
|
340
|
+
continue: (session?: GraffitiSession | null) =>
|
|
341
|
+
this_.objectStreamContinue<Schema>(continue_(session)),
|
|
379
342
|
cursor,
|
|
380
343
|
};
|
|
381
344
|
}
|
|
382
345
|
if (!result.value.error) {
|
|
383
|
-
this_.synchronizeDispatch(
|
|
384
|
-
result.value as GraffitiObjectStreamContinueEntry<{}>,
|
|
385
|
-
);
|
|
346
|
+
this_.synchronizeDispatch(result.value);
|
|
386
347
|
}
|
|
387
348
|
yield result.value;
|
|
388
349
|
}
|
|
@@ -408,13 +369,8 @@ export class GraffitiSynchronize extends Graffiti {
|
|
|
408
369
|
return this.objectStream<(typeof args)[1]>(iterator);
|
|
409
370
|
};
|
|
410
371
|
|
|
411
|
-
|
|
412
|
-
const iterator = this.graffiti.
|
|
413
|
-
return this.
|
|
414
|
-
};
|
|
415
|
-
|
|
416
|
-
continueObjectStream: Graffiti["continueObjectStream"] = (...args) => {
|
|
417
|
-
// TODO!!
|
|
418
|
-
return this.graffiti.continueObjectStream(...args);
|
|
372
|
+
continueDiscover: Graffiti["continueDiscover"] = (...args) => {
|
|
373
|
+
const iterator = this.graffiti.continueDiscover(...args);
|
|
374
|
+
return this.objectStreamContinue<{}>(iterator);
|
|
419
375
|
};
|
|
420
376
|
}
|