@scrypted/server 0.29.0 → 0.31.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.

Potentially problematic release.


This version of @scrypted/server might be problematic. Click here for more details.

package/src/level.ts CHANGED
@@ -1,27 +1,4 @@
1
- // Type definitions for abstract-leveldown 5.0
2
- // Project: https://github.com/Level/abstract-leveldown
3
- // Definitions by: Meirion Hughes <https://github.com/MeirionHughes>
4
- // Daniel Byrne <https://github.com/danwbyrne>
5
- // Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
6
- // TypeScript Version: 2.3
7
-
8
- export interface AbstractOptions {
9
- // wtf is this?
10
- readonly [k: string]: any;
11
- }
12
-
13
- export type ErrorCallback = (err: Error | undefined) => void;
14
- export type ErrorValueCallback<V> = (err: Error | undefined, value: V) => void;
15
- export type ErrorKeyValueCallback<K, V> = (err: Error | undefined, key: K, value: V) => void;
16
-
17
- export interface AbstractOpenOptions extends AbstractOptions {
18
- createIfMissing?: boolean;
19
- errorIfExists?: boolean;
20
- }
21
-
22
- export interface AbstractGetOptions extends AbstractOptions {
23
- asBuffer?: boolean;
24
- }
1
+ import { GetOptions, Level, OpenOptions, PutOptions } from 'level';
25
2
 
26
3
  export interface LevelDocument {
27
4
  _id?: any;
@@ -32,265 +9,107 @@ export interface LevelDocumentConstructor<T extends LevelDocument> {
32
9
  new(): T;
33
10
  }
34
11
 
35
- export interface AbstractLevelDOWN<K = any, V = any> /* extends AbstractOptions */ {
36
- open(cb?: ErrorCallback): Promise<void>;
37
- open(options: AbstractOpenOptions, cb?: ErrorCallback): Promise<void>;
38
-
39
- close(cb?: ErrorCallback): void;
40
-
41
- get(key: K, cb?: ErrorValueCallback<V>): Promise<V>;
42
- get(key: K, options: AbstractGetOptions, cb?: ErrorValueCallback<V>): Promise<V>;
43
-
44
- put(key: K, value: V, cb?: ErrorCallback): Promise<void>;
45
- put(key: K, value: V, options: AbstractOptions, cb?: ErrorCallback): Promise<void>;
46
-
47
- del(key: K, cb?: ErrorCallback): Promise<void>;
48
- del(key: K, options: AbstractOptions, cb?: ErrorCallback): Promise<void>;
49
-
50
- batch(): AbstractChainedBatch<K, V>;
51
- batch(array: ReadonlyArray<AbstractBatch<K, V>>, cb?: ErrorCallback): AbstractChainedBatch<K, V>;
52
- batch(
53
- array: ReadonlyArray<AbstractBatch<K, V>>,
54
- options: AbstractOptions,
55
- cb?: ErrorCallback,
56
- ): AbstractChainedBatch<K, V>;
57
-
58
- iterator(options?: AbstractIteratorOptions<K>): AbstractIterator<K, V>;
59
-
60
- [Symbol.asyncIterator](): AsyncIterator<{ key: K, value: V }>;
61
- nextId(): number;
62
- tryGet<T extends LevelDocument>(documentConstructor: LevelDocumentConstructor<T>, _id: any, options?: AbstractGetOptions): Promise<T | undefined>;
63
- getAll<T extends LevelDocument>(documentConstructor: LevelDocumentConstructor<T>, options?: AbstractGetOptions): AsyncIterable<T>;
64
- upsert<T extends LevelDocument>(value: T, options?: AbstractOptions): Promise<T>;
65
- remove<T extends LevelDocument>(value: T): Promise<void>;
66
- removeId<T extends LevelDocument>(documentConstructor: LevelDocumentConstructor<T>, _id: any): Promise<void>;
67
- removeAll<T extends LevelDocument>(documentConstructor: LevelDocumentConstructor<T>): Promise<void>;
68
- getCount<T extends LevelDocument>(documentConstructor: LevelDocumentConstructor<T>, options?: AbstractGetOptions): Promise<number>;
69
- }
70
-
71
- export interface AbstractLevelDOWNConstructor {
72
- // tslint:disable-next-line no-unnecessary-generics
73
- new <K = any, V = any>(location: string): AbstractLevelDOWN<K, V>;
74
- // tslint:disable-next-line no-unnecessary-generics
75
- <K = any, V = any>(location: string): AbstractLevelDOWN<K, V>;
76
- }
77
-
78
- export interface AbstractIteratorOptions<K = any> extends AbstractOptions {
79
- gt?: K;
80
- gte?: K;
81
- lt?: K;
82
- lte?: K;
83
- reverse?: boolean;
84
- limit?: number;
85
- keys?: boolean;
86
- values?: boolean;
87
- keyAsBuffer?: boolean;
88
- valueAsBuffer?: boolean;
89
- }
90
-
91
- export type AbstractBatch<K = any, V = any> = PutBatch<K, V> | DelBatch<K, V>;
92
-
93
- export interface PutBatch<K = any, V = any> {
94
- readonly type: 'put';
95
- readonly key: K;
96
- readonly value: V;
97
- }
98
-
99
- export interface DelBatch<K = any, V = any> {
100
- readonly type: 'del';
101
- readonly key: K;
102
- }
103
-
104
- export interface AbstractChainedBatch<K = any, V = any> extends AbstractOptions {
105
- put: (key: K, value: V) => this;
106
- del: (key: K) => this;
107
- clear: () => this;
108
- write(cb?: ErrorCallback): any;
109
- write(options: any, cb?: ErrorCallback): any;
110
- }
111
-
112
- export interface AbstractChainedBatchConstructor {
113
- // tslint:disable-next-line no-unnecessary-generics
114
- new <K = any, V = any>(db: any): AbstractChainedBatch<K, V>;
115
- // tslint:disable-next-line no-unnecessary-generics
116
- <K = any, V = any>(db: any): AbstractChainedBatch<K, V>;
117
- }
118
-
119
- export interface AbstractIterator<K, V> extends AbstractOptions {
120
- db: AbstractLevelDOWN<K, V>;
121
- next(cb?: ErrorKeyValueCallback<K, V>): this;
122
- end(cb?: ErrorCallback): void;
123
- }
124
-
125
- export interface AbstractIteratorConstructor {
126
- // tslint:disable-next-line no-unnecessary-generics
127
- new <K = any, V = any>(db: any): AbstractIterator<K, V>;
128
- // tslint:disable-next-line no-unnecessary-generics
129
- <K = any, V = any>(db: any): AbstractIterator<K, V>;
130
- }
131
-
132
- export interface Level extends AbstractLevelDOWN {
133
- readonly location: string;
134
- readonly prefix: string;
135
- readonly version: string | number;
136
- destroy(location: string, cb?: (err: Error | undefined) => void): void;
137
- destroy(location: string, prefix: string, cb?: (err: Error | undefined) => void): void;
138
- }
139
-
140
- interface LevelOptions {
141
- readonly prefix?: string;
142
- readonly version?: string | number;
143
- }
144
-
145
-
146
- interface LevelConstructor {
147
- new(location: string, options?: LevelOptions, callback?: (err: Error) => void): Level;
148
- (location: string, options?: LevelOptions, callback?: (err: Error) => void): Level;
149
- }
150
-
151
- declare const Level: LevelConstructor;
152
-
153
- const level = require('level') as LevelConstructor;
154
-
155
12
  function createLevelDocument(documentConstructor: any, json: any) {
156
13
  const doc = new documentConstructor();
157
14
  Object.assign(doc, JSON.parse(json));
158
15
  return doc;
159
16
  }
160
17
 
161
- const wrapped = (location: string, options?: LevelOptions, callback?: (err: Error) => void) => {
162
- const ret = level(location, options, callback);
163
- ret.tryGet = async (documentConstructor: any, _id: any, options?: AbstractGetOptions): Promise<any> => {
18
+ export class WrappedLevel extends Level<string, string | number> {
19
+ curId: number;
20
+
21
+ async open(): Promise<void>;
22
+ async open(options?: OpenOptions): Promise<void> {
23
+ await super.open(options);
24
+ try {
25
+ this.curId = parseInt(await this.get('_id') as string);
26
+ }
27
+ catch (e) {
28
+ }
29
+ if (!this.curId)
30
+ this.curId = 0;
31
+ }
32
+
33
+ async tryGet(documentConstructor: any, _id: any, options?: GetOptions<string, string | number>) {
164
34
  try {
165
35
  const _documentType = documentConstructor.name;
166
36
  const key = `${_documentType}/${_id}`;
167
- const json = await ret.get(key, options);
37
+ const json = await this.get(key, options)
168
38
  return createLevelDocument(documentConstructor, json);
169
39
  }
170
40
  catch (e) {
171
41
  }
172
42
  }
173
43
 
174
- const iterable = {
175
- async*[Symbol.asyncIterator]() {
176
- const iterator = ret.iterator();
177
- try {
178
- while (true) {
179
- const { key, value } = await new Promise<{ key: any, value: any }>((resolve, reject) => {
180
- iterator.next((err, key, value) => {
181
- if (err) {
182
- reject(err);
183
- }
184
- else {
185
- resolve({ key, value });
186
- }
187
- })
188
- });
189
-
190
- if (key == null && value == null)
191
- break;
192
- yield {
193
- key,
194
- value,
195
- }
196
- }
197
- }
198
- finally {
199
- await new Promise(resolve => iterator.end(resolve));
200
- }
201
- }
202
- };
203
-
204
- ret[Symbol.asyncIterator] = iterable[Symbol.asyncIterator] as any;
205
- ret.getAll = (documentConstructor: any, options?: AbstractGetOptions): AsyncIterable<any> => {
44
+ async* getAll(documentConstructor: any): AsyncIterable<any> {
206
45
  const _documentType = documentConstructor.name;
207
46
  const prefix = `${_documentType}/`;
208
- return {
209
- async*[Symbol.asyncIterator]() {
210
- for await (const entry of ret) {
211
- if (entry.key.startsWith(prefix)) {
212
- const doc = createLevelDocument(documentConstructor, entry.value);
213
- if (doc._documentType === _documentType) {
214
- yield doc;
215
- }
216
- }
47
+ for await (const [key, value] of this.iterator()) {
48
+ if (key.startsWith(prefix)) {
49
+ const doc = createLevelDocument(documentConstructor, value);
50
+ if (doc._documentType === _documentType) {
51
+ yield doc;
217
52
  }
218
53
  }
219
54
  }
220
55
  }
221
56
 
222
- ret.getCount = async (documentConstructor: any, options?: AbstractGetOptions): Promise<any> => {
57
+ async getCount(documentConstructor: any) {
223
58
  let count = 0;
224
- for await (const doc of ret.getAll(documentConstructor)) {
59
+ for await (const doc of this.getAll(documentConstructor)) {
225
60
  count++;
226
61
  }
227
62
  return count;
228
63
  }
229
64
 
230
- let curId: number;
231
-
232
- const oldOpen = ret.open.bind(ret);
233
- (ret as any).open = async (...args: any) => {
234
- try {
235
- curId = parseInt(await ret.get('_id'));
236
- }
237
- catch (e) {
238
- }
239
- if (!curId)
240
- curId = 0;
241
- return oldOpen(...args);
242
- }
243
-
244
- ret.nextId = () => {
245
- if (typeof curId !== 'number')
65
+ nextId() {
66
+ if (typeof this.curId !== 'number')
246
67
  throw new Error('curId is not a number');
247
- return ++curId;
68
+ return ++this.curId;
248
69
  }
249
70
 
250
- const saveId = async () => {
251
- return ret.put("_id", curId);
71
+ async saveId() {
72
+ return this.put("_id", this.curId);
252
73
  }
253
74
 
254
- ret.upsert = async (value: LevelDocument, options?: AbstractOptions): Promise<any> => {
75
+ async upsert(value: LevelDocument, options?: PutOptions<string, string | number>): Promise<any> {
255
76
  const _documentType = value.constructor.name;
256
77
  if (!value._id)
257
- value._id = ret.nextId();
78
+ value._id = this.nextId();
258
79
 
259
- await saveId();
80
+ await this.saveId();
260
81
 
261
82
  value._documentType = _documentType;
262
83
  const key = `${_documentType}/${value._id}`;
263
- await ret.put(key, JSON.stringify(value), options);
84
+ await this.put(key, JSON.stringify(value), options);
264
85
  return value;
265
86
  };
266
87
 
267
- ret.remove = async (value: LevelDocument) => {
88
+ async remove(value: LevelDocument) {
268
89
  const _documentType = value.constructor.name;
269
90
  let { _id } = value;
270
91
  const key = `${_documentType}/${_id}`;
271
- await ret.del(key);
92
+ await this.del(key);
272
93
  }
273
94
 
274
- ret.removeId = async (documentConstructor: LevelDocumentConstructor<any>, _id: any) => {
95
+ async removeId(documentConstructor: LevelDocumentConstructor<any>, _id: any) {
275
96
  const _documentType = documentConstructor.name;
276
97
  const key = `${_documentType}/${_id}`;
277
- await ret.del(key);
98
+ await this.del(key);
278
99
  }
279
100
 
280
- ret.removeAll = async (documentConstructor: LevelDocumentConstructor<any>) => {
101
+ async removeAll(documentConstructor: LevelDocumentConstructor<any>) {
281
102
  const _documentType = documentConstructor.name;
282
103
  const prefix = `${_documentType}/`;
283
- for await (const entry of ret) {
284
- if (entry.key.startsWith(prefix)) {
285
- const doc = createLevelDocument(documentConstructor, entry.value);
104
+ for await (const [key, value] of this.iterator()) {
105
+ if (key.startsWith(prefix)) {
106
+ const doc = createLevelDocument(documentConstructor, value);
286
107
  if (doc._documentType === _documentType) {
287
- await ret.del(entry.key);
108
+ await this.del(key);
288
109
  }
289
110
  }
290
111
  }
291
112
  }
113
+ }
292
114
 
293
- return ret;
294
- };
295
-
296
- export default wrapped as LevelConstructor;
115
+ export default WrappedLevel;
@@ -4,13 +4,12 @@ import pathToFfmpeg from 'ffmpeg-static';
4
4
  import fs from 'fs';
5
5
  import https from 'https';
6
6
  import mimeType from 'mime';
7
- import mkdirp from "mkdirp";
8
7
  import Graph from 'node-dijkstra';
9
8
  import os from 'os';
10
9
  import path from 'path';
11
10
  import MimeType from 'whatwg-mimetype';
12
- import { MediaObjectRemote } from "./plugin-api";
13
11
  import { MediaObject } from "./mediaobject";
12
+ import { MediaObjectRemote } from "./plugin-api";
14
13
 
15
14
  function typeMatches(target: string, candidate: string): boolean {
16
15
  // candidate will accept anything
@@ -202,7 +201,9 @@ export abstract class MediaManagerBase implements MediaManager {
202
201
  if (!filesPath)
203
202
  throw new Error('SCRYPTED_PLUGIN_VOLUME env variable not set?');
204
203
  const ret = path.join(filesPath, 'files');
205
- mkdirp.sync(ret);
204
+ await fs.promises.mkdir(ret, {
205
+ recursive: true,
206
+ });
206
207
  return ret;
207
208
  }
208
209
 
@@ -1,11 +1,10 @@
1
- import os from 'os';
2
1
  import { Device, EngineIOHandler } from '@scrypted/types';
3
2
  import AdmZip from 'adm-zip';
4
3
  import crypto from 'crypto';
5
4
  import * as io from 'engine.io';
6
5
  import fs from 'fs';
7
- import mkdirp from 'mkdirp';
8
6
  import net from 'net';
7
+ import os from 'os';
9
8
  import path from 'path';
10
9
  import rimraf from 'rimraf';
11
10
  import { Duplex } from 'stream';
@@ -207,7 +206,9 @@ export class PluginHost {
207
206
  if (!fs.existsSync(zipFile)) {
208
207
  rimraf.sync(zipDirTmp);
209
208
  rimraf.sync(zipDir);
210
- mkdirp.sync(zipDirTmp);
209
+ fs.mkdirSync(zipDirTmp, {
210
+ recursive: true,
211
+ });
211
212
  fs.writeFileSync(path.join(zipDirTmp, zipFilename), zipBuffer);
212
213
  const admZip = new AdmZip(zipBuffer);
213
214
  admZip.extractAllTo(path.join(zipDirTmp, 'unzipped'), true);
@@ -1,7 +1,6 @@
1
1
  import child_process from 'child_process';
2
2
  import { once } from 'events';
3
3
  import fs from 'fs';
4
- import mkdirp from "mkdirp";
5
4
  import os from 'os';
6
5
  import path from 'path';
7
6
  import process from 'process';
@@ -66,7 +65,9 @@ export async function installOptionalDependencies(console: Console, packageJson:
66
65
  delete reduced.devDependencies;
67
66
  delete reduced.scripts;
68
67
 
69
- mkdirp.sync(nodePrefix);
68
+ await fs.promises.mkdir(nodePrefix, {
69
+ recursive: true,
70
+ })
70
71
  fs.writeFileSync(packageJsonPath, JSON.stringify(reduced));
71
72
 
72
73
  const cp = npmExecFunction(['--prefix', nodePrefix, 'install'], {
@@ -1,6 +1,6 @@
1
+ import fs from 'fs';
1
2
  import os from 'os';
2
3
  import path from 'path';
3
- import mkdirp from 'mkdirp';
4
4
 
5
5
  export function getScryptedVolume() {
6
6
  const volumeDir = process.env.SCRYPTED_VOLUME || path.join(os.homedir(), '.scrypted', 'volume');
@@ -16,7 +16,9 @@ export function getPluginVolume(pluginId: string) {
16
16
  export function ensurePluginVolume(pluginId: string) {
17
17
  const pluginVolume = getPluginVolume(pluginId);
18
18
  try {
19
- mkdirp.sync(pluginVolume);
19
+ fs.mkdirSync(pluginVolume, {
20
+ recursive: true,
21
+ })
20
22
  }
21
23
  catch (e) {
22
24
  }
package/src/runtime.ts CHANGED
@@ -20,7 +20,7 @@ import { Plugin, PluginDevice, ScryptedAlert, ScryptedUser } from './db-types';
20
20
  import { createResponseInterface } from './http-interfaces';
21
21
  import { getDisplayName, getDisplayRoom, getDisplayType, getProvidedNameOrDefault, getProvidedRoomOrDefault, getProvidedTypeOrDefault } from './infer-defaults';
22
22
  import { IOServer } from './io';
23
- import { Level } from './level';
23
+ import Level from './level';
24
24
  import { LogEntry, Logger, makeAlertId } from './logger';
25
25
  import { getMixins, hasMixinCycle } from './mixin/mixin-cycle';
26
26
  import { AccessControls } from './plugin/acl';
@@ -7,7 +7,6 @@ import fs from 'fs';
7
7
  import http from 'http';
8
8
  import httpAuth from 'http-auth';
9
9
  import https from 'https';
10
- import mkdirp from 'mkdirp';
11
10
  import net from 'net';
12
11
  import os from 'os';
13
12
  import path from 'path';
@@ -16,7 +15,7 @@ import semver from 'semver';
16
15
  import { install as installSourceMapSupport } from 'source-map-support';
17
16
  import { createSelfSignedCertificate, CURRENT_SELF_SIGNED_CERTIFICATE_VERSION } from './cert';
18
17
  import { Plugin, ScryptedUser, Settings } from './db-types';
19
- import level, { Level } from './level';
18
+ import Level from './level';
20
19
  import { PluginError } from './plugin/plugin-error';
21
20
  import { getScryptedVolume } from './plugin/plugin-volume';
22
21
  import { RPCResultError } from './rpc';
@@ -116,15 +115,11 @@ async function start(mainFilename: string, options?: {
116
115
  onRuntimeCreated?: (runtime: ScryptedRuntime) => Promise<void>,
117
116
  }) {
118
117
  const volumeDir = getScryptedVolume();
119
- mkdirp.sync(volumeDir);
118
+ await fs.promises.mkdir(volumeDir, {
119
+ recursive: true
120
+ });
120
121
  const dbPath = path.join(volumeDir, 'scrypted.db');
121
- const db = await new Promise<Level>((r, f) => {
122
- const db = level(dbPath, undefined, (e) => {
123
- if (e)
124
- return f(e);
125
- r(db);
126
- });
127
- })
122
+ const db = new Level(dbPath);
128
123
  await db.open();
129
124
 
130
125
  let certSetting = await db.tryGet(Settings, 'certificate') as Settings;
@@ -1,2 +0,0 @@
1
- export declare function asyncFilter<T>(asyncIterable: AsyncIterable<T>, predicate: (t: T) => Promise<boolean>): AsyncIterable<T>;
2
- export declare function asyncFind<T>(asyncIterable: AsyncIterable<T>, predicate: (t: T) => Promise<boolean>): Promise<T>;
@@ -1,24 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.asyncFind = exports.asyncFilter = void 0;
4
- function asyncFilter(asyncIterable, predicate) {
5
- return {
6
- async *[Symbol.asyncIterator]() {
7
- for await (const value of asyncIterable) {
8
- if (await predicate(value)) {
9
- yield value;
10
- }
11
- }
12
- }
13
- };
14
- }
15
- exports.asyncFilter = asyncFilter;
16
- async function asyncFind(asyncIterable, predicate) {
17
- for await (const value of asyncIterable) {
18
- if (await predicate(value)) {
19
- return value;
20
- }
21
- }
22
- }
23
- exports.asyncFind = asyncFind;
24
- //# sourceMappingURL=asynciterable-utils.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"asynciterable-utils.js","sourceRoot":"","sources":["../src/asynciterable-utils.ts"],"names":[],"mappings":";;;AAAA,SAAgB,WAAW,CAAI,aAA+B,EAAE,SAAqC;IACjG,OAAO;QACH,KAAK,CAAA,CAAE,CAAC,MAAM,CAAC,aAAa,CAAC;YACzB,IAAI,KAAK,EAAE,MAAM,KAAK,IAAI,aAAa,EAAE;gBACrC,IAAI,MAAM,SAAS,CAAC,KAAK,CAAC,EAAE;oBACxB,MAAM,KAAK,CAAC;iBACf;aACJ;QACL,CAAC;KACJ,CAAA;AACL,CAAC;AAVD,kCAUC;AAEM,KAAK,UAAU,SAAS,CAAI,aAA+B,EAAE,SAAqC;IACrG,IAAI,KAAK,EAAE,MAAM,KAAK,IAAI,aAAa,EAAE;QACrC,IAAI,MAAM,SAAS,CAAC,KAAK,CAAC,EAAE;YACxB,OAAO,KAAK,CAAC;SAChB;KACJ;AACL,CAAC;AAND,8BAMC"}
@@ -1 +0,0 @@
1
- export declare function hasSameElements<T>(a: T[], b: T[]): boolean;
@@ -1,16 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.hasSameElements = void 0;
4
- function hasSameElements(a, b) {
5
- const s1 = new Set(a);
6
- const s2 = new Set(b);
7
- if (s1.size != s2.size)
8
- return false;
9
- for (const e of s1) {
10
- if (!s2.has(e))
11
- return false;
12
- }
13
- return true;
14
- }
15
- exports.hasSameElements = hasSameElements;
16
- //# sourceMappingURL=collection.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"collection.js","sourceRoot":"","sources":["../src/collection.ts"],"names":[],"mappings":";;;AAAA,SAAgB,eAAe,CAAI,CAAM,EAAE,CAAM;IAC7C,MAAM,EAAE,GAAG,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC;IACtB,MAAM,EAAE,GAAG,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC;IACtB,IAAI,EAAE,CAAC,IAAI,IAAI,EAAE,CAAC,IAAI;QAClB,OAAO,KAAK,CAAC;IACjB,KAAK,MAAM,CAAC,IAAI,EAAE,EAAE;QAChB,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;YACV,OAAO,KAAK,CAAC;KACpB;IAED,OAAO,IAAI,CAAC;AAChB,CAAC;AAXD,0CAWC"}
@@ -1,19 +0,0 @@
1
- export function asyncFilter<T>(asyncIterable: AsyncIterable<T>, predicate: (t: T) => Promise<boolean>): AsyncIterable<T> {
2
- return {
3
- async* [Symbol.asyncIterator]() {
4
- for await (const value of asyncIterable) {
5
- if (await predicate(value)) {
6
- yield value;
7
- }
8
- }
9
- }
10
- }
11
- }
12
-
13
- export async function asyncFind<T>(asyncIterable: AsyncIterable<T>, predicate: (t: T) => Promise<boolean>): Promise<T> {
14
- for await (const value of asyncIterable) {
15
- if (await predicate(value)) {
16
- return value;
17
- }
18
- }
19
- }
package/src/collection.ts DELETED
@@ -1,12 +0,0 @@
1
- export function hasSameElements<T>(a: T[], b: T[]): boolean {
2
- const s1 = new Set(a);
3
- const s2 = new Set(b);
4
- if (s1.size != s2.size)
5
- return false;
6
- for (const e of s1) {
7
- if (!s2.has(e))
8
- return false;
9
- }
10
-
11
- return true;
12
- }