oasis-std
Advanced tools
Comparing version 0.1.0-rc.29-non-c10l to 0.1.0
@@ -277,7 +277,14 @@ "use strict"; | ||
const decoder = bytes instanceof Decoder ? bytes : new Decoder(bytes); | ||
const obj = doAbiDecode(schema, decoder); | ||
const remainder = decoder.remainder(); | ||
if (remainder.length !== 0 && !(bytes instanceof Decoder)) { | ||
throw new Error(`failed to decode ${remainder.length} trailing bytes.`); | ||
let obj; | ||
try { | ||
obj = doAbiDecode(schema, decoder); | ||
const remainder = decoder.remainder(); | ||
if (remainder.length !== 0 && !(bytes instanceof Decoder)) { | ||
throw new Error(`failed to decode ${remainder.length} trailing bytes.`); | ||
} | ||
} | ||
catch (e) { | ||
const inputHex = utils_1.encodeHex(new Uint8Array(bytes instanceof Decoder ? [...bytes.buf] : [...bytes])); | ||
throw new Error(`abiDecode failed to interpret "${inputHex}" as ${stringifySchema(schema)}: ${e}`); | ||
} | ||
return obj; | ||
@@ -284,0 +291,0 @@ } |
@@ -11,6 +11,8 @@ import EventEmitter from 'eventemitter3'; | ||
private inner; | ||
private keyStore; | ||
private subscriptionId; | ||
private log; | ||
constructor(url: string, apiToken: string, headers?: Map<string, string>); | ||
/** | ||
* Deploy a new service. | ||
* Deploy a new confidential service. | ||
* `payload` should be the service bytecode followed by the constructor stdin. | ||
@@ -22,3 +24,3 @@ * @returns a promise that resolves to the address of the newly-created service. | ||
/** | ||
* Calls a service deployed at `address` with `payload` as stdin. | ||
* Calls a confidential service deployed at `address` with `payload` as stdin. | ||
* Optional `headers` override those passed to the `Gateway` constructor. | ||
@@ -36,6 +38,6 @@ * @returns a promise that resolves to the service stdout or rejects with an `RpcError`. | ||
/** | ||
* Subscribes to events emitted by the service at `address` that contains | ||
* all of the provided `topics`. | ||
* Subscribes to events emitted by the service at `address` that contain | ||
* all of the provided `topics` and for which `filter` returns true. | ||
*/ | ||
subscribe<T>(address: Address | null, topics: string[], decoder: (payload: Uint8Array) => Promise<T>): Promise<Subscription<T>>; | ||
subscribe<T>(address: Address | null, topics: string[], decoder: (payload: Uint8Array) => Promise<T>, filter?: (event: T) => boolean): Promise<Subscription<T>>; | ||
/** | ||
@@ -73,14 +75,23 @@ * Cancels a previous subscription named `subscriptionName`. | ||
}; | ||
/** | ||
* A class that represents an event-emiting object (with `.on(...)` API) | ||
* as an async iterable (with `for await (... of ...)` API). | ||
* It also provides hooks for event transformation (e.g. ABI decoding) and filtering. | ||
*/ | ||
export declare class Subscription<T> implements AsyncIterable<T> { | ||
private name; | ||
private emitter; | ||
private decoder; | ||
private gateway; | ||
private events; | ||
private postResults; | ||
private postError; | ||
private hasResults; | ||
constructor(name: string, emitter: EventEmitter, decoder: (payload: Uint8Array) => Promise<T>, gateway: Gateway); | ||
/** | ||
* @param name The event to listen to from `emitter`. | ||
* @param emitter Events from this object will be exposed. | ||
* @param decoder Each event will be deserialized with this function before being exposed. | ||
* @param filter Only events for which the filter returns true (after deserialization) will be exposed. | ||
* @param gateway Once the output iterator terminates, we'll unsubscribe from events from this gateway. | ||
* The assumption is that `emitter` generates events from `gateway`. | ||
*/ | ||
constructor(name: string, emitter: EventEmitter, decoder: (payload: Uint8Array) => Promise<T>, filter: (event: T) => boolean, gateway: Gateway); | ||
[Symbol.asyncIterator](): AsyncIterator<T>; | ||
first(): Promise<T>; | ||
} |
@@ -36,4 +36,7 @@ "use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const common_1 = require("@oasislabs/common"); | ||
const confidential_1 = require("@oasislabs/confidential"); | ||
const gateway_1 = require("@oasislabs/gateway"); | ||
const service_1 = require("@oasislabs/service"); | ||
const logging_1 = require("./logging"); | ||
const types_1 = require("./types"); | ||
@@ -51,5 +54,7 @@ const utils_1 = require("./utils"); | ||
this.inner = new gateway_1.HttpGateway(url, apiToken, { headers }); | ||
this.keyStore = new confidential_1.KeyStore(new common_1.LocalStorage(), this.inner); | ||
this.log = logging_1.oasisLogger('oasis-std-gateway-client'); | ||
} | ||
/** | ||
* Deploy a new service. | ||
* Deploy a new confidential service. | ||
* `payload` should be the service bytecode followed by the constructor stdin. | ||
@@ -67,3 +72,11 @@ * @returns a promise that resolves to the address of the newly-created service. | ||
catch (e) { | ||
throw yield Gateway.convertError(e); | ||
let parsedErr; | ||
try { | ||
parsedErr = yield Gateway.convertError(e); | ||
} | ||
catch (eParse) { | ||
parsedErr = new types_1.RpcError.Gateway(`(Failed to parse error; parsing error: ${JSON.stringify(eParse)}; unparsed error: ${JSON.stringify(e)})`); | ||
} | ||
this.log.error({ err: parsedErr, rawErr: e }, 'Failed to deploy service'); | ||
throw parsedErr; | ||
} | ||
@@ -73,6 +86,6 @@ }); | ||
static makeDeployCode(payload, options) { | ||
return service_1.DeployHeader.deployCode({ confidential: false, expiry: options === null || options === void 0 ? void 0 : options.expiry }, payload); | ||
return service_1.DeployHeader.deployCode({ confidential: true, expiry: options === null || options === void 0 ? void 0 : options.expiry }, payload); | ||
} | ||
/** | ||
* Calls a service deployed at `address` with `payload` as stdin. | ||
* Calls a confidential service deployed at `address` with `payload` as stdin. | ||
* Optional `headers` override those passed to the `Gateway` constructor. | ||
@@ -82,14 +95,38 @@ * @returns a promise that resolves to the service stdout or rejects with an `RpcError`. | ||
rpc(address, payload, options, headers = new Map()) { | ||
var _a; | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const servicePublicKey = yield this.keyStore.publicKey(new common_1.Address(address.bytes)); | ||
const clientKeys = this.keyStore.localKeys(); | ||
const data = yield confidential_1.encrypt(confidential_1.nonce(), payload, servicePublicKey, clientKeys.publicKey, clientKeys.privateKey, (_a = options === null || options === void 0 ? void 0 : options.aad) !== null && _a !== void 0 ? _a : new Uint8Array()); | ||
const decryptToBuffer = (bytes) => __awaiter(this, void 0, void 0, function* () { | ||
return utils_1.typedArrayToBuffer((yield confidential_1.decrypt(bytes, clientKeys.privateKey)).plaintext); | ||
}); | ||
try { | ||
const res = this.withHeaders(headers, () => { | ||
const res = yield this.withHeaders(headers, () => { | ||
return this.inner.rpc({ | ||
address: address.bytes, | ||
data: payload, | ||
data, | ||
}); | ||
}); | ||
return utils_1.decodeHex((yield res).output); | ||
if (res.error) { | ||
// Should never happen; in case of errors, `this.inner.rpc()` should | ||
// throw an Error, not return a result with `error` field filled out. | ||
throw new types_1.RpcError.Gateway('Delegated inner RPC failed: ' + JSON.stringify(res.error)); | ||
} | ||
return decryptToBuffer(utils_1.decodeHex(res.output)); | ||
} | ||
catch (e) { | ||
throw yield Gateway.convertError(e); | ||
let parsedErr; | ||
try { | ||
parsedErr = yield Gateway.convertError(e, decryptToBuffer); | ||
} | ||
catch (eParse) { | ||
parsedErr = new types_1.RpcError.Gateway(`(Failed to parse error; parsing error: ${JSON.stringify(eParse)}; unparsed error: ${JSON.stringify(e)})`); | ||
} | ||
this.log.error({ | ||
err: parsedErr, | ||
rawErr: e, | ||
stack: logging_1.stackTrace(), | ||
}, 'Failed to make RPC'); | ||
throw parsedErr; | ||
} | ||
@@ -128,9 +165,10 @@ }); | ||
/** | ||
* Subscribes to events emitted by the service at `address` that contains | ||
* all of the provided `topics`. | ||
* Subscribes to events emitted by the service at `address` that contain | ||
* all of the provided `topics` and for which `filter` returns true. | ||
*/ | ||
subscribe(address, topics, decoder) { | ||
subscribe(address, topics, decoder, filter = (_) => true) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
this.subscriptionId += 1; | ||
const sub = new Subscription(this.subscriptionId.toString(), yield this.inner.subscribe({ | ||
const sub = new Subscription(this.subscriptionId.toString(), yield this.inner | ||
.subscribe({ | ||
event: this.subscriptionId.toString(), | ||
@@ -141,3 +179,4 @@ filter: { | ||
}, | ||
}), decoder, this); | ||
}) | ||
.catch(wrapError), decoder, filter, this); | ||
return sub; | ||
@@ -151,3 +190,5 @@ }); | ||
return __awaiter(this, void 0, void 0, function* () { | ||
yield this.inner.unsubscribe({ event: subscriptionName }); | ||
yield this.inner | ||
.unsubscribe({ event: subscriptionName }) | ||
.catch(wrapError); | ||
}); | ||
@@ -162,7 +203,9 @@ } | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const { code: deploycode } = yield this.inner.getCode({ | ||
const { code: deploycode } = yield this.inner | ||
.getCode({ | ||
address: address.bytes, | ||
}); | ||
}) | ||
.catch(wrapError); | ||
if (deploycode === null || deploycode.length === 0) { | ||
throw new Error(`no bytecode for service at ${address.hex}`); | ||
throw new types_1.RpcError.Gateway(`no bytecode for service at ${address.hex}`); | ||
} | ||
@@ -178,8 +221,10 @@ return service_1.DeployHeaderReader.initcode(deploycode); | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const { publicKey } = yield this.inner.publicKey({ | ||
const { publicKey } = yield this.inner | ||
.publicKey({ | ||
address: address.bytes, | ||
}); | ||
}) | ||
.catch(wrapError); | ||
if (typeof publicKey === 'undefined') { | ||
/* istanbul ignore next */ // pubkey is derived from addr, so always exists | ||
throw new Error(`could not get public key of service at ${address.hex}`); | ||
throw new types_1.RpcError.Gateway(`could not get public key of service at ${address.hex}`); | ||
} | ||
@@ -194,3 +239,5 @@ return publicKey; | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const { expiry } = yield this.inner.expiry({ address: address.bytes }); | ||
const { expiry } = yield this.inner | ||
.expiry({ address: address.bytes }) | ||
.catch(wrapError); | ||
return expiry; | ||
@@ -204,3 +251,3 @@ }); | ||
return __awaiter(this, void 0, void 0, function* () { | ||
return this.inner.disconnect(); | ||
return this.inner.disconnect().catch(wrapError); | ||
}); | ||
@@ -210,24 +257,49 @@ } | ||
exports.Gateway = Gateway; | ||
/** | ||
* Wrapper around a Promise that exposes its `resolve`/`reject` methods. | ||
* Intended for async signaling: If this object is shared between two | ||
* sections of code, one section can signal the other section by calling | ||
* `resolve()` on the object, while the other section `await`s the `promise`. | ||
*/ | ||
class ExternallySettledPromise { | ||
constructor() { | ||
this.promise = new Promise((resolve_, reject_) => { | ||
this.resolve = resolve_; | ||
this.reject = reject_; | ||
}); | ||
} | ||
} | ||
/** | ||
* A class that represents an event-emiting object (with `.on(...)` API) | ||
* as an async iterable (with `for await (... of ...)` API). | ||
* It also provides hooks for event transformation (e.g. ABI decoding) and filtering. | ||
*/ | ||
class Subscription { | ||
constructor(name, emitter, decoder, gateway) { | ||
/** | ||
* @param name The event to listen to from `emitter`. | ||
* @param emitter Events from this object will be exposed. | ||
* @param decoder Each event will be deserialized with this function before being exposed. | ||
* @param filter Only events for which the filter returns true (after deserialization) will be exposed. | ||
* @param gateway Once the output iterator terminates, we'll unsubscribe from events from this gateway. | ||
* The assumption is that `emitter` generates events from `gateway`. | ||
*/ | ||
constructor(name, emitter, decoder, filter, gateway) { | ||
this.name = name; | ||
this.emitter = emitter; | ||
this.decoder = decoder; | ||
this.gateway = gateway; | ||
// Events that have accumulated between successive calls to `[Symbol.asyncIterator]` | ||
this.events = []; | ||
this.hasResults = new Promise((resolve, reject) => { | ||
this.postResults = resolve; | ||
this.postError = reject; | ||
}); | ||
// Signalling mechanism between event-ingesting part and iterator interface. | ||
this.hasResults = new ExternallySettledPromise(); | ||
emitter | ||
.on(name, ({ data }) => __awaiter(this, void 0, void 0, function* () { | ||
this.events.push(yield decoder(utils_1.decodeHex(data))); | ||
this.postResults(); | ||
this.hasResults = new Promise((resolve, reject) => { | ||
this.postResults = resolve; | ||
this.postError = reject; | ||
}); | ||
const decodedData = yield decoder(utils_1.decodeHex(data)); | ||
if (!filter(decodedData)) | ||
return; | ||
this.events.push(decodedData); | ||
this.hasResults.resolve(); | ||
this.hasResults = new ExternallySettledPromise(); | ||
})) | ||
.on('error', (e) => { | ||
this.postError(e); | ||
this.hasResults.reject(new types_1.RpcError.Gateway(e)); | ||
this.hasResults = new ExternallySettledPromise(); | ||
}); | ||
@@ -243,3 +315,3 @@ } | ||
} | ||
yield __await(this.hasResults); | ||
yield __await(this.hasResults.promise); | ||
yield __await(yield* __asyncDelegator(__asyncValues(this.events))); | ||
@@ -254,2 +326,4 @@ this.events = []; | ||
} | ||
// Returns a Promise that resolves to the first event. After that, the | ||
// subscription automatically ends. | ||
first() { | ||
@@ -277,2 +351,5 @@ var e_1, _a; | ||
exports.Subscription = Subscription; | ||
function wrapError(e) { | ||
return Promise.reject(new types_1.RpcError.Gateway(e)); | ||
} | ||
//# sourceMappingURL=gateway.js.map |
export { AbiDecodable, AbiEncodable, Decoder, Encoder, Schema, abiDecode, abiEncode, encodeEventTopic, } from './abi'; | ||
export * from './gateway'; | ||
export { Address, Balance, RpcError, OasisMap as Map, OasisSet as Set, Result, } from './types'; | ||
export { oasisLogger, OasisLogger, stackTrace } from './logging'; | ||
export { decodeHex, encodeHex, fetchBytecode } from './utils'; |
@@ -20,2 +20,5 @@ "use strict"; | ||
exports.Result = types_1.Result; | ||
var logging_1 = require("./logging"); | ||
exports.oasisLogger = logging_1.oasisLogger; | ||
exports.stackTrace = logging_1.stackTrace; | ||
var utils_1 = require("./utils"); | ||
@@ -22,0 +25,0 @@ exports.decodeHex = utils_1.decodeHex; |
{ | ||
"name": "oasis-std", | ||
"version": "0.1.0-rc.29-non-c10l", | ||
"version": "0.1.0", | ||
"description": "Oasis platform standard library", | ||
@@ -18,11 +18,14 @@ "license": "Apache-2.0", | ||
"dependencies": { | ||
"@oasislabs/common": "=1.0.0-rc.17", | ||
"@oasislabs/confidential": "=1.0.0-rc.20", | ||
"@oasislabs/gateway": "=1.0.0-rc.36", | ||
"@oasislabs/service": "=1.0.0-rc.31", | ||
"@oasislabs/common": "=1.0.0-rc.19", | ||
"@oasislabs/confidential": "=1.0.0-rc.25", | ||
"@oasislabs/gateway": "=1.0.0-rc.45", | ||
"@oasislabs/service": "=1.0.0-rc.36", | ||
"@types/pino": "^6.2.1", | ||
"buffer": "^5.4.3", | ||
"eventemitter3": "^4.0.0", | ||
"js-sha3": "^0.8.0", | ||
"node-fetch": "^2.6.0" | ||
} | ||
"node-fetch": "^2.6.0", | ||
"pino": "^6.2.1" | ||
}, | ||
"gitHead": "f6f0431a1546493faa4bd9064b3184a76e248550" | ||
} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
300944
21
1996
10
3
+ Added@types/pino@^6.2.1
+ Addedpino@^6.2.1
+ Added@types/node@22.9.3(transitive)
+ Added@types/pino@6.3.12(transitive)
+ Added@types/pino-pretty@5.0.0(transitive)
+ Added@types/pino-std-serializers@4.0.0(transitive)
+ Addedatomic-sleep@1.0.0(transitive)
+ Addedcolorette@2.0.20(transitive)
+ Addeddateformat@4.6.3(transitive)
+ Addedend-of-stream@1.4.4(transitive)
+ Addedfast-copy@3.0.2(transitive)
+ Addedfast-redact@3.5.0(transitive)
+ Addedfast-safe-stringify@2.1.1(transitive)
+ Addedflatstr@1.0.12(transitive)
+ Addedhelp-me@5.0.0(transitive)
+ Addedjoycon@3.1.1(transitive)
+ Addedminimist@1.2.8(transitive)
+ Addedon-exit-leak-free@2.1.2(transitive)
+ Addedonce@1.4.0(transitive)
+ Addedpino@6.14.0(transitive)
+ Addedpino-abstract-transport@2.0.0(transitive)
+ Addedpino-pretty@13.0.0(transitive)
+ Addedpino-std-serializers@3.2.07.0.0(transitive)
+ Addedprocess-warning@1.0.0(transitive)
+ Addedpump@3.0.2(transitive)
+ Addedquick-format-unescaped@4.0.4(transitive)
+ Addedsecure-json-parse@2.7.0(transitive)
+ Addedsonic-boom@1.4.12.8.04.2.0(transitive)
+ Addedsplit2@4.2.0(transitive)
+ Addedstrip-json-comments@3.1.1(transitive)
+ Addedundici-types@6.19.8(transitive)
+ Addedwrappy@1.0.2(transitive)