mirror of
https://github.com/fluencelabs/fluence-js.git
synced 2024-12-04 18:00:18 +00:00
Builtin methods, update aquamarine (#960)
This commit is contained in:
parent
2792dcfc93
commit
83c3a172e8
@ -4,10 +4,9 @@ node_modules
|
||||
types
|
||||
|
||||
src/
|
||||
aqua/
|
||||
|
||||
tsconfig.json
|
||||
webpack.config.js
|
||||
|
||||
bundle
|
||||
pkg
|
||||
pkg
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "fluence",
|
||||
"version": "0.7.38",
|
||||
"version": "0.7.53",
|
||||
"description": "the browser js-libp2p client for the Fluence network",
|
||||
"main": "./dist/fluence.js",
|
||||
"typings": "./dist/fluence.d.ts",
|
||||
@ -8,7 +8,7 @@
|
||||
"test": "mocha -r ts-node/register src/**/*.spec.ts",
|
||||
"test-ts": "ts-mocha -p tsconfig.json src/**/*.spec.ts",
|
||||
"package:build": "NODE_ENV=production webpack && npm run package",
|
||||
"package": "tsc && cp -r aqua dist",
|
||||
"package": "tsc && cp -r src/aqua dist",
|
||||
"compile": "tsc",
|
||||
"start": "webpack-dev-server -p",
|
||||
"build": "webpack"
|
||||
|
3
aqua/index.d.ts → src/aqua/index.d.ts
vendored
3
aqua/index.d.ts → src/aqua/index.d.ts
vendored
@ -4,10 +4,11 @@
|
||||
* @param wasm
|
||||
* @param {string} init_user_id
|
||||
* @param {string} aqua
|
||||
* @param {string} prev_data
|
||||
* @param {string} data
|
||||
* @returns {string}
|
||||
*/
|
||||
export function invoke(wasm: any, init_user_id: string, aqua: string, data: string): string;
|
||||
export function invoke(wasm: any, init_user_id: string, aqua: string, prev_data: string, data: string): string;
|
||||
export function getStringFromWasm0(wasm: any, arg1: any, arg2: any): string
|
||||
export function getInt32Memory0(wasm: any): number[]
|
||||
export function passStringToWasm0(wasm: any, arg: any, malloc: any, realloc: any): number
|
@ -90,10 +90,11 @@ export function getStringFromWasm0(wasm, ptr, len) {
|
||||
* @param {any} wasm
|
||||
* @param {string} init_user_id
|
||||
* @param {string} aqua
|
||||
* @param {string} prev_data
|
||||
* @param {string} data
|
||||
* @returns {string}
|
||||
*/
|
||||
export function invoke(wasm, init_user_id, aqua, data) {
|
||||
export function invoke(wasm, init_user_id, aqua, prev_data, data) {
|
||||
try {
|
||||
const retptr = wasm.__wbindgen_export_0.value - 16;
|
||||
wasm.__wbindgen_export_0.value = retptr;
|
||||
@ -101,9 +102,11 @@ export function invoke(wasm, init_user_id, aqua, data) {
|
||||
var len0 = WASM_VECTOR_LEN;
|
||||
var ptr1 = passStringToWasm0(wasm, aqua, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
||||
var len1 = WASM_VECTOR_LEN;
|
||||
var ptr2 = passStringToWasm0(wasm, data, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
||||
var ptr2 = passStringToWasm0(wasm, prev_data, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
||||
var len2 = WASM_VECTOR_LEN;
|
||||
wasm.invoke(retptr, ptr0, len0, ptr1, len1, ptr2, len2);
|
||||
var ptr3 = passStringToWasm0(wasm, data, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
||||
var len3 = WASM_VECTOR_LEN;
|
||||
wasm.invoke(retptr, ptr0, len0, ptr1, len1, ptr2, len2, ptr3, len3);
|
||||
var r0 = getInt32Memory0(wasm)[retptr / 4 + 0];
|
||||
var r1 = getInt32Memory0(wasm)[retptr / 4 + 1];
|
||||
return getStringFromWasm0(wasm, r0, r1);
|
1
src/aqua/wasmBs64.ts
Normal file
1
src/aqua/wasmBs64.ts
Normal file
File diff suppressed because one or more lines are too long
@ -15,15 +15,31 @@
|
||||
*/
|
||||
|
||||
|
||||
import {Particle} from "./particle";
|
||||
import {build, genUUID, Particle} from "./particle";
|
||||
import {StepperOutcome} from "./stepperOutcome";
|
||||
import * as PeerId from "peer-id";
|
||||
import Multiaddr from "multiaddr"
|
||||
import {FluenceConnection} from "./fluenceConnection";
|
||||
import {Subscriptions} from "./subscriptions";
|
||||
import {addParticle, getCurrentParticleId, popParticle, setCurrentParticleId} from "./globalState";
|
||||
import {
|
||||
addParticle,
|
||||
deleteService,
|
||||
getCurrentParticleId,
|
||||
popParticle,
|
||||
registerService,
|
||||
setCurrentParticleId
|
||||
} from "./globalState";
|
||||
import {instantiateStepper, Stepper} from "./stepper";
|
||||
import log from "loglevel";
|
||||
import {Service} from "./callService";
|
||||
import {delay} from "./utils";
|
||||
|
||||
const bs58 = require('bs58')
|
||||
|
||||
interface NamedPromise<T> {
|
||||
promise: Promise<T>,
|
||||
name: string
|
||||
}
|
||||
|
||||
export class FluenceClient {
|
||||
readonly selfPeerId: PeerId;
|
||||
@ -43,7 +59,7 @@ export class FluenceClient {
|
||||
/**
|
||||
* Pass a particle to a stepper and send a result to other services.
|
||||
*/
|
||||
private handleParticle(particle: Particle): void {
|
||||
private async handleParticle(particle: Particle): Promise<void> {
|
||||
|
||||
// if a current particle is processing, add new particle to the queue
|
||||
if (getCurrentParticleId() !== undefined) {
|
||||
@ -54,20 +70,38 @@ export class FluenceClient {
|
||||
}
|
||||
// start particle processing if queue is empty
|
||||
try {
|
||||
let stepperOutcomeStr = this.stepper(particle.init_peer_id, particle.script, JSON.stringify(particle.data))
|
||||
let stepperOutcome: StepperOutcome = JSON.parse(stepperOutcomeStr);
|
||||
// check if a particle is relevant
|
||||
let now = Date.now();
|
||||
let actualTtl = particle.timestamp + particle.ttl - now;
|
||||
if (actualTtl <= 0) {
|
||||
log.info(`Particle expired. Now: ${now}, ttl: ${particle.ttl}, ts: ${particle.timestamp}`)
|
||||
} else {
|
||||
// if there is no subscription yet, previous data is empty
|
||||
let prevData = {};
|
||||
let prevParticle = this.subscriptions.get(particle.id);
|
||||
if (prevParticle) {
|
||||
prevData = prevParticle.data;
|
||||
// update a particle in a subscription
|
||||
this.subscriptions.update(particle)
|
||||
} else {
|
||||
// set a particle with actual ttl
|
||||
this.subscriptions.subscribe(particle, actualTtl)
|
||||
}
|
||||
let stepperOutcomeStr = this.stepper(particle.init_peer_id, particle.script, JSON.stringify(prevData), JSON.stringify(particle.data))
|
||||
let stepperOutcome: StepperOutcome = JSON.parse(stepperOutcomeStr);
|
||||
|
||||
log.info("inner stepper outcome:");
|
||||
log.info(stepperOutcome);
|
||||
log.info("inner stepper outcome:");
|
||||
log.info(stepperOutcome);
|
||||
|
||||
// do nothing if there is no `next_peer_pks`
|
||||
if (stepperOutcome.next_peer_pks.length > 0) {
|
||||
let newParticle: Particle = {...particle};
|
||||
newParticle.data = JSON.parse(stepperOutcome.data);
|
||||
// do nothing if there is no `next_peer_pks`
|
||||
if (stepperOutcome.next_peer_pks.length > 0) {
|
||||
let newParticle: Particle = {...particle};
|
||||
newParticle.data = JSON.parse(stepperOutcome.data);
|
||||
|
||||
this.connection.sendParticle(newParticle).catch((reason) => {
|
||||
console.error(`Error on sending particle with id ${particle.id}: ${reason}`)
|
||||
});
|
||||
await this.connection.sendParticle(newParticle).catch((reason) => {
|
||||
console.error(`Error on sending particle with id ${particle.id}: ${reason}`)
|
||||
});
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
// get last particle from the queue
|
||||
@ -76,7 +110,7 @@ export class FluenceClient {
|
||||
if (nextParticle) {
|
||||
// update current particle
|
||||
setCurrentParticleId(nextParticle.id);
|
||||
this.handleParticle(nextParticle)
|
||||
await this.handleParticle(nextParticle)
|
||||
} else {
|
||||
// wait for a new call (do nothing) if there is no new particle in a queue
|
||||
setCurrentParticleId(undefined);
|
||||
@ -88,16 +122,20 @@ export class FluenceClient {
|
||||
/**
|
||||
* Handle incoming particle from a relay.
|
||||
*/
|
||||
private handleExternalParticle(): (particle: Particle) => void {
|
||||
private handleExternalParticle(): (particle: Particle) => Promise<void> {
|
||||
|
||||
let _this = this;
|
||||
|
||||
return (particle: Particle) => {
|
||||
let now = Date.now();
|
||||
if (particle.timestamp + particle.ttl > now) {
|
||||
_this.handleParticle(particle);
|
||||
return async (particle: Particle) => {
|
||||
let data = particle.data;
|
||||
let error: any = data["protocol!error"]
|
||||
if (error !== undefined) {
|
||||
log.error("error in external particle: ")
|
||||
log.error(error)
|
||||
} else {
|
||||
console.log(`Particle expired. Now: ${now}, ttl: ${particle.ttl}, ts: ${particle.timestamp}`)
|
||||
log.info("handle external particle: ")
|
||||
log.info(particle)
|
||||
await _this.handleParticle(particle);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -139,9 +177,190 @@ export class FluenceClient {
|
||||
this.connection = connection;
|
||||
}
|
||||
|
||||
sendParticle(particle: Particle): string {
|
||||
this.handleParticle(particle);
|
||||
this.subscriptions.subscribe(particle.id, particle.ttl);
|
||||
async sendParticle(particle: Particle): Promise<string> {
|
||||
await this.handleParticle(particle);
|
||||
return particle.id
|
||||
}
|
||||
|
||||
nodeIdentityCall(): string {
|
||||
return `(call ("${this.nodePeerIdStr}" ("identity" "") () void[]))`
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates service that will wait for a response from external peers.
|
||||
*/
|
||||
private waitService<T>(functionName: string, func: (args: any[]) => T, ttl: number): NamedPromise<T> {
|
||||
let serviceName = `${functionName}-${genUUID()}`;
|
||||
log.info(`Create waiting service '${serviceName}'`)
|
||||
let service = new Service(serviceName)
|
||||
registerService(service)
|
||||
|
||||
let promise: Promise<T> = new Promise(function(resolve){
|
||||
service.registerFunction("", (args: any[]) => {
|
||||
resolve(func(args))
|
||||
return {}
|
||||
})
|
||||
})
|
||||
|
||||
let timeout = delay<T>(ttl, "Timeout on waiting " + serviceName)
|
||||
|
||||
return {
|
||||
name: serviceName,
|
||||
promise: Promise.race([promise, timeout]).finally(() => {
|
||||
deleteService(serviceName)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
async requestResponse<T>(name: string, call: (nodeId: string) => string, returnValue: string, data: any, handleResponse: (args: any[]) => T, nodeId?: string, ttl?: number): Promise<T> {
|
||||
if (!ttl) {
|
||||
ttl = 10000
|
||||
}
|
||||
|
||||
if (!nodeId) {
|
||||
nodeId = this.nodePeerIdStr
|
||||
}
|
||||
|
||||
let serviceCall = call(nodeId)
|
||||
|
||||
let namedPromise = this.waitService(name, handleResponse, ttl)
|
||||
|
||||
let script = `(seq (
|
||||
${this.nodeIdentityCall()}
|
||||
(seq (
|
||||
(seq (
|
||||
${serviceCall}
|
||||
${this.nodeIdentityCall()}
|
||||
))
|
||||
(call ("${this.selfPeerIdStr}" ("${namedPromise.name}" "") (${returnValue}) void[]))
|
||||
))
|
||||
))
|
||||
`
|
||||
|
||||
let particle = await build(this.selfPeerId, script, data, ttl)
|
||||
await this.sendParticle(particle);
|
||||
|
||||
return namedPromise.promise
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a script to add module to a relay. Waiting for a response from a relay.
|
||||
*/
|
||||
async addModule(name: string, moduleBase64: string, nodeId?: string, ttl?: number): Promise<void> {
|
||||
let config = {
|
||||
name: name,
|
||||
mem_pages_count: 100,
|
||||
logger_enabled: true,
|
||||
wasi: {
|
||||
envs: {},
|
||||
preopened_files: ["/tmp"],
|
||||
mapped_dirs: {},
|
||||
}
|
||||
}
|
||||
|
||||
let data = {
|
||||
module_bytes: moduleBase64,
|
||||
module_config: config
|
||||
}
|
||||
|
||||
let call = (nodeId: string) => `(call ("${nodeId}" ("add_module" "") (module_bytes module_config) void[]))`
|
||||
|
||||
return this.requestResponse("addModule", call, "", data, () => {}, nodeId, ttl)
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a script to add module to a relay. Waiting for a response from a relay.
|
||||
*/
|
||||
async addBlueprint(name: string, dependencies: string[], nodeId?: string, ttl?: number): Promise<string> {
|
||||
let returnValue = "blueprint_id";
|
||||
let call = (nodeId: string) => `(call ("${nodeId}" ("add_blueprint" "") (blueprint) ${returnValue}))`
|
||||
|
||||
let data = {
|
||||
blueprint: { name: name, dependencies: dependencies }
|
||||
}
|
||||
|
||||
return this.requestResponse("addBlueprint", call, returnValue, data, (args: any[]) => args[0] as string, nodeId, ttl)
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a script to create a service to a relay. Waiting for a response from a relay.
|
||||
*/
|
||||
async createService(blueprintId: string, nodeId?: string, ttl?: number): Promise<string> {
|
||||
let returnValue = "service_id";
|
||||
let call = (nodeId: string) => `(call ("${nodeId}" ("create" "") (blueprint_id) ${returnValue}))`
|
||||
|
||||
let data = {
|
||||
blueprint_id: blueprintId
|
||||
}
|
||||
|
||||
return this.requestResponse("createService", call, returnValue, data, (args: any[]) => args[0] as string, nodeId, ttl)
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all available modules hosted on a connected relay.
|
||||
*/
|
||||
async getAvailableModules(nodeId?: string, ttl?: number): Promise<string[]> {
|
||||
let returnValue = "modules";
|
||||
let call = (nodeId: string) => `(call ("${nodeId}" ("get_available_modules" "") () ${returnValue}))`
|
||||
|
||||
return this.requestResponse("getAvailableModules", call, returnValue, {}, (args: any[]) => args[0] as string[], nodeId, ttl)
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all available blueprints hosted on a connected relay.
|
||||
*/
|
||||
async getBlueprints(nodeId: string, ttl?: number): Promise<string[]> {
|
||||
let returnValue = "blueprints";
|
||||
let call = (nodeId: string) => `(call ("${nodeId}" ("get_available_modules" "") () ${returnValue}))`
|
||||
|
||||
return this.requestResponse("getBlueprints", call, returnValue, {}, (args: any[]) => args[0] as string[], nodeId, ttl)
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a provider to DHT network to neighborhood around a key.
|
||||
*/
|
||||
async addProvider(key: Buffer, providerPeer: string, providerServiceId?: string, nodeId?: string, ttl?: number): Promise<void> {
|
||||
let call = (nodeId: string) => `(call ("${nodeId}" ("add_provider" "") (key provider) void[]))`
|
||||
|
||||
key = bs58.encode(key)
|
||||
|
||||
let provider = {
|
||||
peer: providerPeer,
|
||||
service_id: providerServiceId
|
||||
}
|
||||
|
||||
return this.requestResponse("addProvider", call, "", {key, provider}, () => {}, nodeId, ttl)
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a provider from DHT network from neighborhood around a key..
|
||||
*/
|
||||
async getProviders(key: Buffer, nodeId?: string, ttl?: number): Promise<any> {
|
||||
key = bs58.encode(key)
|
||||
|
||||
let returnValue = "providers"
|
||||
let call = (nodeId: string) => `(call ("${nodeId}" ("get_providers" "") (key) providers[]))`
|
||||
|
||||
return this.requestResponse("getProviders", call, returnValue, {key}, (args) => args[0], nodeId, ttl)
|
||||
}
|
||||
|
||||
/**
|
||||
* Get relays neighborhood
|
||||
*/
|
||||
async neighborhood(node: string, ttl?: number): Promise<string[]> {
|
||||
let returnValue = "neighborhood"
|
||||
let call = (nodeId: string) => `(call ("${nodeId}" ("neighborhood" "") (node) ${returnValue}))`
|
||||
|
||||
return this.requestResponse("neighborhood", call, returnValue, {node}, (args) => args[0] as string[], node, ttl)
|
||||
}
|
||||
|
||||
/**
|
||||
* Call relays 'identity' method. It should return passed 'fields'
|
||||
*/
|
||||
async relayIdentity(fields: string[], data: any, nodeId?: string, ttl?: number): Promise<any> {
|
||||
let returnValue = "id";
|
||||
let call = (nodeId: string) => `(call ("${nodeId}" ("identity" "") (${fields.join(" ")}) ${returnValue}))`
|
||||
|
||||
return this.requestResponse("getIdentity", call, returnValue, data, (args: any[]) => args[0], nodeId, ttl)
|
||||
}
|
||||
}
|
||||
|
@ -42,6 +42,10 @@ export function registerService(service: Service) {
|
||||
services.set(service.serviceId, service)
|
||||
}
|
||||
|
||||
export function deleteService(serviceId: string): boolean {
|
||||
return services.delete(serviceId)
|
||||
}
|
||||
|
||||
export function getService(serviceId: string): Service | undefined {
|
||||
return services.get(serviceId)
|
||||
}
|
||||
|
@ -28,7 +28,7 @@ export interface Particle {
|
||||
script: string,
|
||||
// sign upper fields
|
||||
signature: string,
|
||||
data: object
|
||||
data: any
|
||||
}
|
||||
|
||||
export async function build(peerId: PeerId, script: string, data: object, ttl?: number): Promise<Particle> {
|
||||
|
@ -14,16 +14,16 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import {wasmBs64} from "../wasmBs64";
|
||||
import {wasmBs64} from "./aqua/wasmBs64";
|
||||
import {toByteArray} from "base64-js";
|
||||
import * as aqua from "../aqua"
|
||||
import * as aqua from "./aqua"
|
||||
|
||||
import {callService} from "./callService";
|
||||
import {getInt32Memory0, getStringFromWasm0, passStringToWasm0, WASM_VECTOR_LEN} from "../aqua";
|
||||
import {getInt32Memory0, getStringFromWasm0, passStringToWasm0, WASM_VECTOR_LEN} from "./aqua";
|
||||
import PeerId from "peer-id";
|
||||
import log from "loglevel";
|
||||
|
||||
export type Stepper = (init_user_id: string, script: string, data: string) => string
|
||||
export type Stepper = (init_user_id: string, script: string, prev_data: string, data: string) => string
|
||||
|
||||
export async function instantiateStepper(pid: PeerId): Promise<Stepper> {
|
||||
// Fetch our Wasm File
|
||||
@ -34,7 +34,7 @@ export async function instantiateStepper(pid: PeerId): Promise<Stepper> {
|
||||
const importObject = {
|
||||
// __wbg_callserviceimpl_c0ca292e3c8c0c97 this is a function generated by bindgen. Could be changed.
|
||||
// If so, an error with a new name will be occurred after wasm initialization.
|
||||
"./index_bg.js": { __wbg_callserviceimpl_c0ca292e3c8c0c97: (arg0: any, arg1: any, arg2: any, arg3: any, arg4: any, arg5: any, arg6: any) => {
|
||||
"./index_bg.js": { __wbg_callserviceimpl_a0e7e7457d0787ac: (arg0: any, arg1: any, arg2: any, arg3: any, arg4: any, arg5: any, arg6: any) => {
|
||||
try {
|
||||
let serviceId = getStringFromWasm0(wasm, arg1, arg2)
|
||||
let fnName = getStringFromWasm0(wasm, arg3, arg4)
|
||||
@ -51,7 +51,7 @@ export async function instantiateStepper(pid: PeerId): Promise<Stepper> {
|
||||
wasm.__wbindgen_free(arg5, arg6);
|
||||
}
|
||||
},
|
||||
__wbg_getcurrentpeeridimpl_a04b7c07e1108952: (arg0: any) => {
|
||||
__wbg_getcurrentpeeridimpl_b463298bc6aec9ec: (arg0: any) => {
|
||||
var ret = pid.toB58String();
|
||||
var ptr0 = passStringToWasm0(wasm, ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
||||
var len0 = WASM_VECTOR_LEN;
|
||||
@ -78,8 +78,8 @@ export async function instantiateStepper(pid: PeerId): Promise<Stepper> {
|
||||
|
||||
wasm.main();
|
||||
|
||||
let func = (init_user_id: string, script: string, data: string) => {
|
||||
return aqua.invoke(wasm, init_user_id, script, data)
|
||||
let func = (init_user_id: string, script: string, prev_data: string, data: string) => {
|
||||
return aqua.invoke(wasm, init_user_id, script, prev_data, data)
|
||||
}
|
||||
|
||||
return func
|
||||
|
@ -18,23 +18,36 @@ import {Particle} from "./particle";
|
||||
import log from "loglevel";
|
||||
|
||||
export class Subscriptions {
|
||||
private subscriptions: Set<string> = new Set();
|
||||
private subscriptions: Map<string, Particle> = new Map();
|
||||
|
||||
constructor() {}
|
||||
|
||||
/**
|
||||
* Subscriptions will be applied by outside message if id will be the same.
|
||||
*
|
||||
* @param id message identificator
|
||||
* @param particle
|
||||
* @param ttl time to live, subscription will be deleted after this time
|
||||
*/
|
||||
subscribe(id: string, ttl: number) {
|
||||
subscribe(particle: Particle, ttl: number) {
|
||||
let _this = this;
|
||||
setTimeout(() => {
|
||||
_this.subscriptions.delete(id)
|
||||
log.info(`Particle with id ${id} deleted by timeout`)
|
||||
_this.subscriptions.delete(particle.id)
|
||||
log.info(`Particle with id ${particle.id} deleted by timeout`)
|
||||
}, ttl)
|
||||
this.subscriptions.add(id);
|
||||
this.subscriptions.set(particle.id, particle);
|
||||
}
|
||||
|
||||
update(particle: Particle): boolean {
|
||||
if (this.subscriptions.has(particle.id)) {
|
||||
this.subscriptions.set(particle.id, particle);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
get(id: string): Particle | undefined {
|
||||
return this.subscriptions.get(id)
|
||||
}
|
||||
|
||||
hasSubscription(particle: Particle): boolean {
|
||||
|
21
src/utils.ts
Normal file
21
src/utils.ts
Normal file
@ -0,0 +1,21 @@
|
||||
/*
|
||||
* Copyright 2020 Fluence Labs Limited
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
export function delay<T>(ms: number, error: string): Promise<T> {
|
||||
return new Promise((resolve, reject) => {
|
||||
setTimeout(() => reject(new Error(error)), ms);
|
||||
});
|
||||
}
|
@ -26,7 +26,8 @@
|
||||
"exclude": [
|
||||
"node_modules",
|
||||
"dist",
|
||||
"bundle"
|
||||
"bundle",
|
||||
"src/test"
|
||||
],
|
||||
"include": ["src/**/*"]
|
||||
}
|
||||
}
|
||||
|
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue
Block a user