@holochain/client
Advanced tools
Comparing version 0.12.6 to 0.12.7
@@ -1,2 +0,1 @@ | ||
/// <reference types="node" /> | ||
import { Action, DhtOp, Entry, ZomeCallCapGrant } from "../../hdk/index.js"; | ||
@@ -10,3 +9,3 @@ import { ActionHash, AgentPubKey, CellId, DnaHash, DnaProperties, Duration, HoloHash, HoloHashB64, InstalledAppId, KitsuneAgent, KitsuneSpace, RoleName, Signature, Timestamp, WasmHash } from "../../types.js"; | ||
export type AttachAppInterfaceRequest = { | ||
port: number; | ||
port?: number; | ||
}; | ||
@@ -131,3 +130,3 @@ /** | ||
*/ | ||
export type MembraneProof = Buffer; | ||
export type MembraneProof = Uint8Array; | ||
/** | ||
@@ -168,3 +167,3 @@ * @public | ||
cell_id: CellId; | ||
dht_ops_cursor: number | undefined; | ||
dht_ops_cursor?: number; | ||
}; | ||
@@ -201,3 +200,3 @@ /** | ||
network_seed: NetworkSeed; | ||
properties: DnaProperties; | ||
properties: Uint8Array; | ||
origin_time: Timestamp; | ||
@@ -262,2 +261,12 @@ quantum_time: Duration; | ||
*/ | ||
export type UpdateCoordinatorsRequest = { | ||
dna_hash: DnaHash; | ||
} & CoordinatorSource; | ||
/** | ||
* @public | ||
*/ | ||
export type UpdateCoordinatorsResponse = void; | ||
/** | ||
* @public | ||
*/ | ||
export type ResourceBytes = Uint8Array; | ||
@@ -381,8 +390,29 @@ /** | ||
export type InstallAppRequest = { | ||
/** | ||
* The agent to use when creating Cells for this App. | ||
*/ | ||
agent_key: AgentPubKey; | ||
/** | ||
* The unique identifier for an installed app in this conductor. | ||
* If not specified, it will be derived from the app name in the bundle manifest. | ||
*/ | ||
installed_app_id?: InstalledAppId; | ||
/** | ||
* Include proof-of-membrane-membership data for cells that require it, | ||
* keyed by the CellNick specified in the app bundle manifest. | ||
*/ | ||
membrane_proofs: { | ||
[key: string]: MembraneProof; | ||
}; | ||
/** | ||
* Optional global network seed override. If set will override the network seed value for all | ||
* DNAs in the bundle. | ||
*/ | ||
network_seed?: NetworkSeed; | ||
/** | ||
* Optional: If app installation fails due to genesis failure, normally the app will be immediately uninstalled. | ||
* When this flag is set, the app is left installed with empty cells intact. This can be useful for | ||
* using graft_records_onto_source_chain, or for diagnostics. | ||
*/ | ||
ignore_genesis_failure?: boolean; | ||
} & AppBundleSource; | ||
@@ -512,5 +542,12 @@ /** | ||
*/ | ||
export interface ZomeDependency { | ||
name: ZomeName; | ||
} | ||
/** | ||
* @public | ||
*/ | ||
export type ZomeManifest = { | ||
name: string; | ||
hash?: string; | ||
dependencies?: ZomeDependency[]; | ||
} & ZomeLocation; | ||
@@ -520,2 +557,23 @@ /** | ||
*/ | ||
export interface CoordinatorManifest { | ||
zomes: Array<ZomeManifest>; | ||
} | ||
/** | ||
* @public | ||
*/ | ||
export interface CoordinatorBundle { | ||
manifest: CoordinatorManifest; | ||
resources: ResourceMap; | ||
} | ||
/** | ||
* @public | ||
*/ | ||
export type CoordinatorSource = { | ||
path: string; | ||
} | { | ||
bundle: CoordinatorBundle; | ||
}; | ||
/** | ||
* @public | ||
*/ | ||
export type DnaManifest = { | ||
@@ -638,2 +696,42 @@ /** | ||
*/ | ||
export interface DnaStorageInfo { | ||
authored_data_size: number; | ||
authored_data_size_on_disk: number; | ||
dht_data_size: number; | ||
dht_data_size_on_disk: number; | ||
cache_data_size: number; | ||
cache_data_size_on_disk: number; | ||
used_by: Array<InstalledAppId>; | ||
} | ||
/** | ||
* @public | ||
*/ | ||
export interface DnaStorageBlob { | ||
dna: DnaStorageInfo; | ||
} | ||
/** | ||
* @public | ||
*/ | ||
export interface StorageInfo { | ||
blobs: Array<DnaStorageBlob>; | ||
} | ||
/** | ||
* @public | ||
*/ | ||
export type StorageInfoRequest = void; | ||
/** | ||
* @public | ||
*/ | ||
export type StorageInfoResponse = StorageInfo; | ||
/** | ||
* @public | ||
*/ | ||
export type DumpNetworkStatsRequest = void; | ||
/** | ||
* @public | ||
*/ | ||
export type DumpNetworkStatsResponse = string; | ||
/** | ||
* @public | ||
*/ | ||
export interface AdminApi { | ||
@@ -658,2 +756,4 @@ attachAppInterface: Requester<AttachAppInterfaceRequest, AttachAppInterfaceResponse>; | ||
grantZomeCallCapability: Requester<GrantZomeCallCapabilityRequest, GrantZomeCallCapabilityResponse>; | ||
storageInfo: Requester<StorageInfoRequest, StorageInfoResponse>; | ||
dumpNetworkStats: Requester<DumpNetworkStatsRequest, DumpNetworkStatsResponse>; | ||
} |
@@ -5,3 +5,3 @@ import { CapSecret, GrantedFunctions } from "../../hdk/capabilities.js"; | ||
import { Requester, Transformer } from "../common.js"; | ||
import { AddAgentInfoRequest, AddAgentInfoResponse, AdminApi, AgentInfoRequest, AgentInfoResponse, AttachAppInterfaceRequest, AttachAppInterfaceResponse, DeleteCloneCellRequest, DeleteCloneCellResponse, DisableAppRequest, DisableAppResponse, DumpFullStateRequest, DumpFullStateResponse, DumpStateRequest, DumpStateResponse, EnableAppRequest, EnableAppResponse, GenerateAgentPubKeyRequest, GenerateAgentPubKeyResponse, GetDnaDefinitionRequest, GetDnaDefinitionResponse, GrantZomeCallCapabilityRequest, GrantZomeCallCapabilityResponse, InstallAppRequest, InstallAppResponse, ListAppInterfacesRequest, ListAppInterfacesResponse, ListAppsRequest, ListAppsResponse, ListCellIdsRequest, ListCellIdsResponse, ListDnasRequest, ListDnasResponse, RegisterDnaRequest, RegisterDnaResponse, UninstallAppRequest, UninstallAppResponse } from "./types.js"; | ||
import { AddAgentInfoRequest, AddAgentInfoResponse, AdminApi, AgentInfoRequest, AgentInfoResponse, AttachAppInterfaceRequest, AttachAppInterfaceResponse, DeleteCloneCellRequest, DeleteCloneCellResponse, DisableAppRequest, DisableAppResponse, DumpFullStateRequest, DumpFullStateResponse, DumpNetworkStatsRequest, DumpNetworkStatsResponse, DumpStateRequest, DumpStateResponse, EnableAppRequest, EnableAppResponse, GenerateAgentPubKeyRequest, GenerateAgentPubKeyResponse, GetDnaDefinitionRequest, GetDnaDefinitionResponse, GrantZomeCallCapabilityRequest, GrantZomeCallCapabilityResponse, InstallAppRequest, InstallAppResponse, ListAppInterfacesRequest, ListAppInterfacesResponse, ListAppsRequest, ListAppsResponse, ListCellIdsRequest, ListCellIdsResponse, ListDnasRequest, ListDnasResponse, RegisterDnaRequest, RegisterDnaResponse, StorageInfoRequest, StorageInfoResponse, UninstallAppRequest, UninstallAppResponse, UpdateCoordinatorsRequest, UpdateCoordinatorsResponse } from "./types.js"; | ||
/** | ||
@@ -29,3 +29,3 @@ * A class for interacting with a conductor's Admin API. | ||
*/ | ||
static connect(url: string, defaultTimeout?: number): Promise<AdminWebsocket>; | ||
static connect(url: URL, defaultTimeout?: number): Promise<AdminWebsocket>; | ||
_requester<ReqI, ReqO, ResI, ResO>(tag: string, transformer?: Transformer<ReqI, ReqO, ResI, ResO>): (req: ReqI, timeout?: number | undefined) => Promise<ResO>; | ||
@@ -76,2 +76,6 @@ /** | ||
/** | ||
* Update coordinators for an installed app. | ||
*/ | ||
updateCoordinators: Requester<UpdateCoordinatorsRequest, UpdateCoordinatorsResponse>; | ||
/** | ||
* List all registered DNAs. | ||
@@ -109,2 +113,4 @@ */ | ||
grantZomeCallCapability: Requester<GrantZomeCallCapabilityRequest, GrantZomeCallCapabilityResponse>; | ||
storageInfo: Requester<StorageInfoRequest, StorageInfoResponse>; | ||
dumpNetworkStats: Requester<DumpNetworkStatsRequest, DumpNetworkStatsResponse>; | ||
/** | ||
@@ -111,0 +117,0 @@ * Grant a capability for signing zome calls. |
@@ -37,3 +37,3 @@ import { getLauncherEnvironment } from "../../environments/launcher.js"; | ||
if (env?.ADMIN_INTERFACE_PORT) { | ||
url = `ws://127.0.0.1:${env.ADMIN_INTERFACE_PORT}`; | ||
url = new URL(`ws://127.0.0.1:${env.ADMIN_INTERFACE_PORT}`); | ||
} | ||
@@ -90,2 +90,6 @@ const wsClient = await WsClient.connect(url); | ||
/** | ||
* Update coordinators for an installed app. | ||
*/ | ||
updateCoordinators = this._requester("update_coordinators"); | ||
/** | ||
* List all registered DNAs. | ||
@@ -123,2 +127,4 @@ */ | ||
grantZomeCallCapability = this._requester("grant_zome_call_capability"); | ||
storageInfo = this._requester("storage_info"); | ||
dumpNetworkStats = this._requester("dump_network_stats"); | ||
// zome call signing related methods | ||
@@ -159,3 +165,3 @@ /** | ||
authorizeSigningCredentials = async (cellId, functions) => { | ||
const [keyPair, signingKey] = generateSigningKeyPair(); | ||
const [keyPair, signingKey] = await generateSigningKeyPair(); | ||
const capSecret = await this.grantSigningKey(cellId, functions || { [GrantedFunctionsType.All]: null }, signingKey); | ||
@@ -162,0 +168,0 @@ setSigningCredentials(cellId, { capSecret, keyPair, signingKey }); |
import { UnsubscribeFunction } from "emittery"; | ||
import { AgentPubKey, RoleName } from "../../index.js"; | ||
import { AppInfoResponse, AppSignal, AppSignalCb, CallZomeRequest, CallZomeRequestSigned, DisableCloneCellRequest, EnableCloneCellRequest, EnableCloneCellResponse } from "../app/index.js"; | ||
import { AppInfoResponse, AppSignal, AppSignalCb, CallZomeRequest, CallZomeRequestSigned, DisableCloneCellRequest, EnableCloneCellRequest, EnableCloneCellResponse, NetworkInfoRequest, NetworkInfoResponse } from "../app/index.js"; | ||
import { CreateCloneCellRequest, CreateCloneCellResponse, DisableCloneCellResponse } from "../index.js"; | ||
@@ -40,2 +40,6 @@ /** | ||
*/ | ||
export type AppAgentNetworkInfoRequest = Omit<NetworkInfoRequest, "agent_pub_key">; | ||
/** | ||
* @public | ||
*/ | ||
export interface AppAgentEvents { | ||
@@ -55,2 +59,3 @@ signal: AppSignal; | ||
disableCloneCell(args: AppDisableCloneCellRequest): Promise<DisableCloneCellResponse>; | ||
networkInfo(args: AppAgentNetworkInfoRequest): Promise<NetworkInfoResponse>; | ||
} |
import Emittery, { UnsubscribeFunction } from "emittery"; | ||
import { AgentPubKey, CellId, InstalledAppId, RoleName } from "../../types.js"; | ||
import { AppInfo, AppSignalCb, AppWebsocket, CallZomeResponse, CreateCloneCellResponse, DisableCloneCellResponse, EnableCloneCellResponse } from "../index.js"; | ||
import { AppAgentCallZomeRequest, AppAgentClient, AppAgentEvents, AppCreateCloneCellRequest, AppDisableCloneCellRequest, AppEnableCloneCellRequest } from "./types.js"; | ||
import { AppInfo } from "../admin/types.js"; | ||
import { AppSignalCb, CallZomeResponse, CreateCloneCellResponse, DisableCloneCellResponse, EnableCloneCellResponse, NetworkInfoResponse } from "../app/types.js"; | ||
import { AppWebsocket } from "../app/websocket.js"; | ||
import { AppAgentCallZomeRequest, AppAgentClient, AppAgentEvents, AppAgentNetworkInfoRequest, AppCreateCloneCellRequest, AppDisableCloneCellRequest, AppEnableCloneCellRequest } from "./types.js"; | ||
/** | ||
@@ -32,3 +34,3 @@ * A class to establish a websocket connection to an App interface, for a | ||
*/ | ||
static connect(url: string, installed_app_id: InstalledAppId, defaultTimeout?: number): Promise<AppAgentWebsocket>; | ||
static connect(url: URL, installed_app_id: InstalledAppId, defaultTimeout?: number): Promise<AppAgentWebsocket>; | ||
/** | ||
@@ -71,2 +73,8 @@ * Get a cell id by its role name or clone id. | ||
/** | ||
* Request network info about gossip status. | ||
* @param args - Specify the DNAs for which you want network info | ||
* @returns Network info for the specified DNAs | ||
*/ | ||
networkInfo(args: AppAgentNetworkInfoRequest): Promise<NetworkInfoResponse>; | ||
/** | ||
* Register an event listener for signals. | ||
@@ -73,0 +81,0 @@ * |
import Emittery from "emittery"; | ||
import { omit } from "lodash-es"; | ||
import { getLauncherEnvironment } from "../../environments/launcher.js"; | ||
import { CellType } from "../admin/types.js"; | ||
import { AppWebsocket } from "../app/websocket.js"; | ||
import { getBaseRoleNameFromCloneId, isCloneId } from "../common.js"; | ||
import { AppWebsocket, CellType, } from "../index.js"; | ||
/** | ||
@@ -21,2 +22,11 @@ * A class to establish a websocket connection to an App interface, for a | ||
this.emitter = new Emittery(); | ||
// Ensure all super methods are bound to this instance because Emittery relies on `this` being the instance. | ||
// Please retain until the upstream is fixed https://github.com/sindresorhus/emittery/issues/86. | ||
Object.getOwnPropertyNames(Emittery.prototype).forEach((name) => { | ||
const to_bind = this.emitter[name]; | ||
if (typeof to_bind === "function") { | ||
this.emitter[name] = | ||
to_bind.bind(this.emitter); | ||
} | ||
}); | ||
const env = getLauncherEnvironment(); | ||
@@ -96,8 +106,3 @@ this.installedAppId = env?.INSTALLED_APP_ID || installedAppId; | ||
async callZome(request, timeout) { | ||
if ("provenance" in request) { | ||
if ("role_name" in request && request.role_name) { | ||
throw new Error("Cannot find other agent's cells based on role name. Use cell id when providing a provenance."); | ||
} | ||
} | ||
else { | ||
if (!("provenance" in request)) { | ||
request = { | ||
@@ -161,2 +166,13 @@ ...request, | ||
/** | ||
* Request network info about gossip status. | ||
* @param args - Specify the DNAs for which you want network info | ||
* @returns Network info for the specified DNAs | ||
*/ | ||
async networkInfo(args) { | ||
return this.appWebsocket.networkInfo({ | ||
...args, | ||
agent_pub_key: this.myPubKey, | ||
}); | ||
} | ||
/** | ||
* Register an event listener for signals. | ||
@@ -163,0 +179,0 @@ * |
import { AgentPubKey, CellId, DnaHash, DnaProperties, InstalledAppId, NetworkInfo, RoleName, Timestamp } from "../../types.js"; | ||
import { AppInfo, ClonedCell, FunctionName, MembraneProof, NetworkSeed, ZomeName } from "../admin/index.js"; | ||
import { AppInfo, ClonedCell, FunctionName, MembraneProof, NetworkSeed, ZomeName } from "../admin/types.js"; | ||
import { Requester } from "../common.js"; | ||
@@ -117,5 +117,13 @@ /** | ||
/** | ||
* The DNAs for which to get network info | ||
* The calling agent | ||
*/ | ||
agent_pub_key: AgentPubKey; | ||
/** | ||
* Get network info for these DNAs | ||
*/ | ||
dnas: DnaHash[]; | ||
/** | ||
* Timestamp in ms since which received amount of bytes from peers will be returned. Defaults to UNIX_EPOCH. | ||
*/ | ||
last_time_queried?: number; | ||
} | ||
@@ -122,0 +130,0 @@ /** |
@@ -26,4 +26,4 @@ import Emittery from "emittery"; | ||
*/ | ||
static connect(url: string, defaultTimeout?: number): Promise<AppWebsocket>; | ||
_requester: <ReqI, ReqO, ResI, ResO>(tag: string, transformer?: Transformer<ReqI, ReqO, ResI, ResO> | undefined) => (req: ReqI, timeout?: number | undefined) => Promise<ResO>; | ||
static connect(url: URL, defaultTimeout?: number): Promise<AppWebsocket>; | ||
_requester<ReqI, ReqO, ResI, ResO>(tag: string, transformer?: Transformer<ReqI, ReqO, ResI, ResO>): (req: ReqI, timeout?: number | undefined) => Promise<ResO>; | ||
/** | ||
@@ -30,0 +30,0 @@ * Request the app's info, including all cell infos. |
import { hashZomeCall } from "@holochain/serialization"; | ||
import { decode, encode } from "@msgpack/msgpack"; | ||
import _sodium from "libsodium-wrappers"; | ||
import Emittery from "emittery"; | ||
import nacl from "tweetnacl"; | ||
import { getHostZomeCallSigner, getLauncherEnvironment, isLauncher, signZomeCallTauri, } from "../../environments/launcher.js"; | ||
import { getLauncherEnvironment, signZomeCallTauri, signZomeCallElectron, getHostZomeCallSigner, } from "../../environments/launcher.js"; | ||
import { encodeHashToBase64 } from "../../utils/base64.js"; | ||
import { WsClient } from "../client.js"; | ||
import { catchError, DEFAULT_TIMEOUT, promiseTimeout, requesterTransformer, } from "../common.js"; | ||
import { DEFAULT_TIMEOUT, catchError, promiseTimeout, requesterTransformer, } from "../common.js"; | ||
import { getNonceExpiration, getSigningCredentials, randomNonce, } from "../zome-call-signing.js"; | ||
@@ -22,2 +22,11 @@ /** | ||
super(); | ||
// Ensure all super methods are bound to this instance because Emittery relies on `this` being the instance. | ||
// Please retain until the upstream is fixed https://github.com/sindresorhus/emittery/issues/86. | ||
Object.getOwnPropertyNames(Emittery.prototype).forEach((name) => { | ||
const to_bind = this[name]; | ||
if (typeof to_bind === "function") { | ||
this[name] = | ||
to_bind.bind(this); | ||
} | ||
}); | ||
this.client = client; | ||
@@ -39,3 +48,3 @@ this.defaultTimeout = | ||
if (env?.APP_INTERFACE_PORT) { | ||
url = `ws://127.0.0.1:${env.APP_INTERFACE_PORT}`; | ||
url = new URL(`ws://127.0.0.1:${env.APP_INTERFACE_PORT}`); | ||
} | ||
@@ -47,3 +56,5 @@ const wsClient = await WsClient.connect(url); | ||
} | ||
_requester = (tag, transformer) => requesterTransformer((req, timeout) => promiseTimeout(this.client.request(req), tag, timeout || this.defaultTimeout).then(catchError), tag, transformer); | ||
_requester(tag, transformer) { | ||
return requesterTransformer((req, timeout) => promiseTimeout(this.client.request(req), tag, timeout || this.defaultTimeout).then(catchError), tag, transformer); | ||
} | ||
/** | ||
@@ -97,6 +108,12 @@ * Request the app's info, including all cell infos. | ||
} | ||
else if (isLauncher) { | ||
else { | ||
const env = getLauncherEnvironment(); | ||
if (!env) { | ||
return signZomeCall(request); | ||
} | ||
if (env.FRAMEWORK === "electron") { | ||
return signZomeCallElectron(request); | ||
} | ||
return signZomeCallTauri(request); | ||
} | ||
return signZomeCall(request); | ||
}, | ||
@@ -135,5 +152,7 @@ output: (response) => decode(response), | ||
const hashedZomeCall = await hashZomeCall(unsignedZomeCallPayload); | ||
const signature = nacl | ||
.sign(hashedZomeCall, signingCredentialsForCell.keyPair.secretKey) | ||
.subarray(0, nacl.sign.signatureLength); | ||
await _sodium.ready; | ||
const sodium = _sodium; | ||
const signature = sodium | ||
.crypto_sign(hashedZomeCall, signingCredentialsForCell.keyPair.privateKey) | ||
.subarray(0, sodium.crypto_sign_BYTES); | ||
const signedZomeCall = { | ||
@@ -140,0 +159,0 @@ ...unsignedZomeCallPayload, |
/// <reference types="ws" /> | ||
import { decode } from "@msgpack/msgpack"; | ||
import Emittery from "emittery"; | ||
import Websocket from "isomorphic-ws"; | ||
import IsoWebSocket from "isomorphic-ws"; | ||
/** | ||
* A Websocket client which can make requests and receive responses, | ||
* A WebSocket client which can make requests and receive responses, | ||
* as well as send and receive signals. | ||
* | ||
* Uses Holochain's websocket WireMessage for communication. | ||
* Uses Holochain's WireMessage for communication. | ||
* | ||
@@ -14,16 +13,15 @@ * @public | ||
export declare class WsClient extends Emittery { | ||
socket: Websocket; | ||
pendingRequests: Record<number, { | ||
resolve: (msg: unknown) => ReturnType<typeof decode>; | ||
reject: (error: Error) => void; | ||
}>; | ||
index: number; | ||
constructor(socket: Websocket); | ||
socket: IsoWebSocket; | ||
url: URL | undefined; | ||
private pendingRequests; | ||
private index; | ||
constructor(socket: IsoWebSocket, url: URL); | ||
private setupSocket; | ||
/** | ||
* Instance factory for creating WsClients. | ||
* | ||
* @param url - The `ws://` URL to connect to. | ||
* @param url - The WebSocket URL to connect to. | ||
* @returns An new instance of the WsClient. | ||
*/ | ||
static connect(url: string): Promise<WsClient>; | ||
static connect(url: URL): Promise<WsClient>; | ||
/** | ||
@@ -41,3 +39,4 @@ * Sends data as a signal. | ||
*/ | ||
request<Req, Res>(request: Req): Promise<Res>; | ||
request<Response>(request: unknown): Promise<Response>; | ||
private sendMessage; | ||
private handleResponse; | ||
@@ -47,3 +46,4 @@ /** | ||
*/ | ||
close(code?: number): Promise<void>; | ||
close(code?: number): Promise<CloseEvent>; | ||
} | ||
export { IsoWebSocket }; |
import { decode, encode } from "@msgpack/msgpack"; | ||
import Emittery from "emittery"; | ||
import Websocket from "isomorphic-ws"; | ||
import IsoWebSocket from "isomorphic-ws"; | ||
import { SignalType } from "./app/types.js"; | ||
/** | ||
* A Websocket client which can make requests and receive responses, | ||
* A WebSocket client which can make requests and receive responses, | ||
* as well as send and receive signals. | ||
* | ||
* Uses Holochain's websocket WireMessage for communication. | ||
* Uses Holochain's WireMessage for communication. | ||
* | ||
@@ -15,14 +15,19 @@ * @public | ||
socket; | ||
url; | ||
pendingRequests; | ||
index; | ||
constructor(socket) { | ||
constructor(socket, url) { | ||
super(); | ||
this.socket = socket; | ||
this.url = url; | ||
this.pendingRequests = {}; | ||
this.index = 0; | ||
socket.onmessage = async (serializedMessage) => { | ||
this.setupSocket(); | ||
} | ||
setupSocket() { | ||
this.socket.onmessage = async (serializedMessage) => { | ||
// If data is not a buffer (nodejs), it will be a blob (browser) | ||
let deserializedData; | ||
if (typeof window === "object" && | ||
serializedMessage.data instanceof window.Blob) { | ||
if (globalThis.window && | ||
serializedMessage.data instanceof globalThis.window.Blob) { | ||
deserializedData = await serializedMessage.data.arrayBuffer(); | ||
@@ -68,3 +73,3 @@ } | ||
}; | ||
socket.onclose = (event) => { | ||
this.socket.onclose = (event) => { | ||
const pendingRequestIds = Object.keys(this.pendingRequests).map((id) => parseInt(id)); | ||
@@ -83,3 +88,3 @@ if (pendingRequestIds.length) { | ||
* | ||
* @param url - The `ws://` URL to connect to. | ||
* @param url - The WebSocket URL to connect to. | ||
* @returns An new instance of the WsClient. | ||
@@ -89,6 +94,3 @@ */ | ||
return new Promise((resolve, reject) => { | ||
const socket = new Websocket(url); | ||
// make sure that there are no uncaught connection | ||
// errors because that causes nodejs thread to crash | ||
// with uncaught exception | ||
const socket = new IsoWebSocket(url); | ||
socket.onerror = () => { | ||
@@ -98,3 +100,3 @@ reject(new Error(`could not connect to holochain conductor, please check that a conductor service is running and available at ${url}`)); | ||
socket.onopen = () => { | ||
const client = new WsClient(socket); | ||
const client = new WsClient(socket, url); | ||
resolve(client); | ||
@@ -122,17 +124,24 @@ }; | ||
*/ | ||
request(request) { | ||
async request(request) { | ||
if (this.socket.readyState === this.socket.OPEN) { | ||
const id = this.index; | ||
const encodedMsg = encode({ | ||
id, | ||
type: "request", | ||
data: encode(request), | ||
}); | ||
const promise = new Promise((resolve, reject) => { | ||
this.pendingRequests[id] = { resolve, reject }; | ||
this.sendMessage(request, resolve, reject); | ||
}); | ||
this.socket.send(encodedMsg); | ||
this.index += 1; | ||
return promise; | ||
} | ||
else if (this.url) { | ||
const response = new Promise((resolve, reject) => { | ||
// typescript forgets in this promise scope that this.url is not undefined | ||
const socket = new IsoWebSocket(this.url); | ||
this.socket = socket; | ||
socket.onerror = () => { | ||
reject(new Error(`could not connect to Holochain conductor, please check that a conductor service is running and available at ${this.url}`)); | ||
}; | ||
socket.onopen = () => { | ||
this.sendMessage(request, resolve, reject); | ||
}; | ||
this.setupSocket(); | ||
}); | ||
return response; | ||
} | ||
else { | ||
@@ -142,2 +151,13 @@ return Promise.reject(new Error("Socket is not open")); | ||
} | ||
sendMessage(request, resolve, reject) { | ||
const id = this.index; | ||
const encodedMsg = encode({ | ||
id, | ||
type: "request", | ||
data: encode(request), | ||
}); | ||
this.socket.send(encodedMsg); | ||
this.pendingRequests[id] = { resolve, reject }; | ||
this.index += 1; | ||
} | ||
handleResponse(msg) { | ||
@@ -161,4 +181,10 @@ const id = msg.id; | ||
*/ | ||
close(code) { | ||
const closedPromise = new Promise((resolve) => this.socket.on("close", resolve)); | ||
close(code = 1000) { | ||
const closedPromise = new Promise((resolve) => | ||
// for an unknown reason "addEventListener" is seen as a non-callable | ||
// property and gives a ts2349 error | ||
// type assertion as workaround | ||
this.socket.addEventListener("close", (event) => resolve(event)) | ||
// } | ||
); | ||
this.socket.close(code); | ||
@@ -185,1 +211,2 @@ return closedPromise; | ||
} | ||
export { IsoWebSocket }; |
import { RoleName } from "../types.js"; | ||
export declare const DEFAULT_TIMEOUT = 15000; | ||
export declare const DEFAULT_TIMEOUT = 60000; | ||
/** | ||
@@ -33,2 +33,10 @@ * @public | ||
export declare const requesterTransformer: <ReqI, ReqO, ResI, ResO>(requester: Requester<Tagged<ReqO>, Tagged<ResI>>, tag: string, transform?: Transformer<ReqI, ReqO, ResI, ResO>) => (req: ReqI, timeout?: number) => Promise<ResO>; | ||
/** | ||
* Error thrown when response from Holochain is an error. | ||
* | ||
* @public | ||
*/ | ||
export declare class HolochainError extends Error { | ||
constructor(name: string, message: string); | ||
} | ||
export declare const catchError: (res: any) => Promise<any>; | ||
@@ -35,0 +43,0 @@ export declare const promiseTimeout: (promise: Promise<unknown>, tag: string, ms: number) => Promise<unknown>; |
const ERROR_TYPE = "error"; | ||
export const DEFAULT_TIMEOUT = 15000; | ||
export const DEFAULT_TIMEOUT = 60000; | ||
/** | ||
@@ -22,4 +22,23 @@ * Take a Requester function which deals with tagged requests and responses, | ||
}; | ||
/** | ||
* Error thrown when response from Holochain is an error. | ||
* | ||
* @public | ||
*/ | ||
export class HolochainError extends Error { | ||
constructor(name, message) { | ||
super(); | ||
this.name = name; | ||
this.message = message; | ||
} | ||
} | ||
// this determines the error format of all error responses | ||
export const catchError = (res) => { | ||
return res.type === ERROR_TYPE ? Promise.reject(res) : Promise.resolve(res); | ||
if (res.type === ERROR_TYPE) { | ||
const error = new HolochainError(res.data.type, res.data.data); | ||
return Promise.reject(error); | ||
} | ||
else { | ||
return Promise.resolve(res); | ||
} | ||
}; | ||
@@ -29,6 +48,3 @@ export const promiseTimeout = (promise, tag, ms) => { | ||
const timeout = new Promise((_, reject) => { | ||
id = setTimeout(() => { | ||
clearTimeout(id); | ||
reject(new Error(`Timed out in ${ms}ms: ${tag}`)); | ||
}, ms); | ||
id = setTimeout(() => reject(new Error(`Timed out in ${ms}ms: ${tag}`)), ms); | ||
}); | ||
@@ -35,0 +51,0 @@ return new Promise((res, rej) => { |
@@ -5,4 +5,4 @@ export { hashZomeCall } from "@holochain/serialization"; | ||
export * from "./app/index.js"; | ||
export { CloneId, Requester, Transformer } from "./common.js"; | ||
export { WsClient } from "./client.js"; | ||
export { IsoWebSocket, WsClient } from "./client.js"; | ||
export { CloneId, HolochainError, Requester, Transformer, getBaseRoleNameFromCloneId, isCloneId, } from "./common.js"; | ||
export * from "./zome-call-signing.js"; |
@@ -5,4 +5,4 @@ export { hashZomeCall } from "@holochain/serialization"; | ||
export * from "./app/index.js"; | ||
export { CloneId } from "./common.js"; | ||
export { WsClient } from "./client.js"; | ||
export { IsoWebSocket, WsClient } from "./client.js"; | ||
export { CloneId, HolochainError, getBaseRoleNameFromCloneId, isCloneId, } from "./common.js"; | ||
export * from "./zome-call-signing.js"; |
@@ -1,4 +0,4 @@ | ||
import nacl from "tweetnacl"; | ||
import { CapSecret } from "../hdk/capabilities.js"; | ||
import { AgentPubKey, CellId } from "../types.js"; | ||
import { type KeyPair } from "libsodium-wrappers"; | ||
import type { CapSecret } from "../hdk/capabilities.js"; | ||
import type { AgentPubKey, CellId } from "../types.js"; | ||
/** | ||
@@ -13,3 +13,3 @@ * @public | ||
capSecret: CapSecret; | ||
keyPair: nacl.SignKeyPair; | ||
keyPair: KeyPair; | ||
signingKey: AgentPubKey; | ||
@@ -37,2 +37,4 @@ } | ||
* | ||
* @param agentPubKey - The agent pub key to take 4 last bytes (= DHT location) | ||
* from (optional). | ||
* @returns The signing key pair and an agent pub key based on the public key. | ||
@@ -42,6 +44,3 @@ * | ||
*/ | ||
export declare const generateSigningKeyPair: () => [ | ||
nacl.SignKeyPair, | ||
AgentPubKey | ||
]; | ||
export declare const generateSigningKeyPair: (agentPubKey?: AgentPubKey) => Promise<[KeyPair, AgentPubKey]>; | ||
/** | ||
@@ -48,0 +47,0 @@ * @public |
@@ -1,2 +0,2 @@ | ||
import nacl from "tweetnacl"; | ||
import _sodium from "libsodium-wrappers"; | ||
import { encodeHashToBase64 } from "../utils/base64.js"; | ||
@@ -30,2 +30,4 @@ const signingCredentials = new Map(); | ||
* | ||
* @param agentPubKey - The agent pub key to take 4 last bytes (= DHT location) | ||
* from (optional). | ||
* @returns The signing key pair and an agent pub key based on the public key. | ||
@@ -35,5 +37,8 @@ * | ||
*/ | ||
export const generateSigningKeyPair = () => { | ||
const keyPair = nacl.sign.keyPair(); | ||
const signingKey = new Uint8Array([132, 32, 36].concat(...keyPair.publicKey).concat(...[0, 0, 0, 0])); | ||
export const generateSigningKeyPair = async (agentPubKey) => { | ||
await _sodium.ready; | ||
const sodium = _sodium; | ||
const keyPair = sodium.crypto_sign_keypair(); | ||
const locationBytes = agentPubKey ? agentPubKey.subarray(35) : [0, 0, 0, 0]; | ||
const signingKey = new Uint8Array([132, 32, 36].concat(...keyPair.publicKey).concat(...locationBytes)); | ||
return [keyPair, signingKey]; | ||
@@ -44,3 +49,3 @@ }; | ||
*/ | ||
export const randomCapSecret = () => randomByteArray(64); | ||
export const randomCapSecret = async () => randomByteArray(64); | ||
/** | ||
@@ -54,11 +59,8 @@ * @public | ||
export const randomByteArray = async (length) => { | ||
if (typeof window !== "undefined" && | ||
"crypto" in window && | ||
"getRandomValues" in window.crypto) { | ||
return window.crypto.getRandomValues(new Uint8Array(length)); | ||
if (globalThis.crypto && "getRandomValues" in globalThis.crypto) { | ||
return globalThis.crypto.getRandomValues(new Uint8Array(length)); | ||
} | ||
else { | ||
const crypto = await import("crypto"); | ||
return new Uint8Array(crypto.randomBytes(length)); | ||
} | ||
await _sodium.ready; | ||
const sodium = _sodium; | ||
return sodium.randombytes_buf(length); | ||
}; | ||
@@ -65,0 +67,0 @@ /** |
@@ -0,3 +1,4 @@ | ||
import { CallZomeRequest } from "../api/app/types.js"; | ||
import { CallZomeRequestSigned, CallZomeRequestUnsigned } from "../api/app/websocket.js"; | ||
import { InstalledAppId } from "../types.js"; | ||
import { CallZomeRequest, CallZomeRequestSigned } from "../api/index.js"; | ||
export interface LauncherEnvironment { | ||
@@ -7,2 +8,3 @@ APP_INTERFACE_PORT?: number; | ||
INSTALLED_APP_ID?: InstalledAppId; | ||
FRAMEWORK?: "tauri" | "electron"; | ||
} | ||
@@ -14,3 +16,3 @@ export interface HostZomeCallSigner { | ||
declare const __HC_ZOME_CALL_SIGNER__ = "__HC_ZOME_CALL_SIGNER__"; | ||
export declare const isLauncher: boolean; | ||
export declare const isLauncher: () => boolean; | ||
export declare const getLauncherEnvironment: () => LauncherEnvironment | undefined; | ||
@@ -20,7 +22,27 @@ export declare const getHostZomeCallSigner: () => HostZomeCallSigner | undefined; | ||
interface Window { | ||
[__HC_LAUNCHER_ENV__]: LauncherEnvironment | undefined; | ||
[__HC_LAUNCHER_ENV__]?: LauncherEnvironment; | ||
[__HC_ZOME_CALL_SIGNER__]?: HostZomeCallSigner; | ||
electronAPI?: { | ||
signZomeCall: (data: CallZomeRequestUnsignedElectron) => CallZomeRequestSignedElectron; | ||
}; | ||
} | ||
} | ||
interface CallZomeRequestSignedElectron extends Omit<CallZomeRequestSigned, "cap_secret" | "cell_id" | "provenance" | "nonce" | "zome_name" | "fn_name" | "expires_at"> { | ||
cellId: [Array<number>, Array<number>]; | ||
provenance: Array<number>; | ||
zomeName: string; | ||
fnName: string; | ||
nonce: Array<number>; | ||
expiresAt: number; | ||
} | ||
interface CallZomeRequestUnsignedElectron extends Omit<CallZomeRequestUnsigned, "cap_secret" | "cell_id" | "provenance" | "nonce" | "zome_name" | "fn_name" | "expires_at"> { | ||
cellId: [Array<number>, Array<number>]; | ||
provenance: Array<number>; | ||
zomeName: string; | ||
fnName: string; | ||
nonce: Array<number>; | ||
expiresAt: number; | ||
} | ||
export declare const signZomeCallTauri: (request: CallZomeRequest) => Promise<CallZomeRequestSigned>; | ||
export declare const signZomeCallElectron: (request: CallZomeRequest) => Promise<CallZomeRequestSigned>; | ||
export {}; |
@@ -0,8 +1,8 @@ | ||
import { encode } from "@msgpack/msgpack"; | ||
import { invoke } from "@tauri-apps/api/tauri"; | ||
import { getNonceExpiration, randomNonce, } from "../api/index.js"; | ||
import { encode } from "@msgpack/msgpack"; | ||
import { getNonceExpiration, randomNonce } from "../api/zome-call-signing.js"; | ||
const __HC_LAUNCHER_ENV__ = "__HC_LAUNCHER_ENV__"; | ||
const __HC_ZOME_CALL_SIGNER__ = "__HC_ZOME_CALL_SIGNER__"; | ||
export const isLauncher = typeof window === "object" && __HC_LAUNCHER_ENV__ in window; | ||
export const getLauncherEnvironment = () => isLauncher ? window[__HC_LAUNCHER_ENV__] : undefined; | ||
export const isLauncher = () => globalThis.window && __HC_LAUNCHER_ENV__ in globalThis.window; | ||
export const getLauncherEnvironment = () => isLauncher() ? globalThis.window[__HC_LAUNCHER_ENV__] : undefined; | ||
export const getHostZomeCallSigner = () => globalThis.window && globalThis.window[__HC_ZOME_CALL_SIGNER__]; | ||
@@ -36,1 +36,31 @@ export const signZomeCallTauri = async (request) => { | ||
}; | ||
export const signZomeCallElectron = async (request) => { | ||
if (!window.electronAPI) { | ||
throw Error("Unable to signZomeCallElectron. window.electronAPI not defined"); | ||
} | ||
const zomeCallUnsignedElectron = { | ||
provenance: Array.from(request.provenance), | ||
cellId: [Array.from(request.cell_id[0]), Array.from(request.cell_id[1])], | ||
zomeName: request.zome_name, | ||
fnName: request.fn_name, | ||
payload: Array.from(encode(request.payload)), | ||
nonce: Array.from(await randomNonce()), | ||
expiresAt: getNonceExpiration(), | ||
}; | ||
const zomeCallSignedElectron = await window.electronAPI.signZomeCall(zomeCallUnsignedElectron); | ||
const zomeCallSigned = { | ||
provenance: Uint8Array.from(zomeCallSignedElectron.provenance), | ||
cap_secret: null, | ||
cell_id: [ | ||
Uint8Array.from(zomeCallSignedElectron.cellId[0]), | ||
Uint8Array.from(zomeCallSignedElectron.cellId[1]), | ||
], | ||
zome_name: zomeCallSignedElectron.zomeName, | ||
fn_name: zomeCallSignedElectron.fnName, | ||
payload: Uint8Array.from(zomeCallSignedElectron.payload), | ||
signature: Uint8Array.from(zomeCallSignedElectron.signature), | ||
expires_at: zomeCallSignedElectron.expiresAt, | ||
nonce: Uint8Array.from(zomeCallSignedElectron.nonce), | ||
}; | ||
return zomeCallSigned; | ||
}; |
import { AgentPubKey, DnaHash, EntryHash, ActionHash, HoloHashed, Signature, Timestamp } from "../types.js"; | ||
import { EntryType } from "./entry.js"; | ||
import { Entry, EntryType } from "./entry.js"; | ||
import { LinkTag, LinkType, RateWeight } from "./link.js"; | ||
/** | ||
@@ -13,2 +14,9 @@ * @public | ||
*/ | ||
export interface RegisterAgentActivity { | ||
action: SignedActionHashed; | ||
cached_entry?: Entry; | ||
} | ||
/** | ||
* @public | ||
*/ | ||
export type ActionHashed = HoloHashed<Action>; | ||
@@ -79,4 +87,6 @@ /** | ||
target_address: EntryHash; | ||
zome_id: number; | ||
tag: any; | ||
zome_index: number; | ||
link_type: LinkType; | ||
tag: LinkTag; | ||
weight: RateWeight; | ||
} | ||
@@ -83,0 +93,0 @@ /** |
@@ -1,2 +0,2 @@ | ||
import { FunctionName, ZomeName } from "../api/index.js"; | ||
import { FunctionName, ZomeName } from "../api/admin/types.js"; | ||
import { AgentPubKey } from "../types.js"; | ||
@@ -41,8 +41,18 @@ /** | ||
*/ | ||
export type CapAccess = "Unrestricted" | { | ||
Transferable: { | ||
export declare enum CapAccessType { | ||
Unrestricted = "Unrestricted", | ||
Transferable = "Transferable", | ||
Assigned = "Assigned" | ||
} | ||
/** | ||
* @public | ||
*/ | ||
export type CapAccess = { | ||
[CapAccessType.Unrestricted]: null; | ||
} | { | ||
[CapAccessType.Transferable]: { | ||
secret: CapSecret; | ||
}; | ||
} | { | ||
Assigned: { | ||
[CapAccessType.Assigned]: { | ||
secret: CapSecret; | ||
@@ -49,0 +59,0 @@ assignees: AgentPubKey[]; |
@@ -9,1 +9,10 @@ /** | ||
})(GrantedFunctionsType || (GrantedFunctionsType = {})); | ||
/** | ||
* @public | ||
*/ | ||
export var CapAccessType; | ||
(function (CapAccessType) { | ||
CapAccessType["Unrestricted"] = "Unrestricted"; | ||
CapAccessType["Transferable"] = "Transferable"; | ||
CapAccessType["Assigned"] = "Assigned"; | ||
})(CapAccessType || (CapAccessType = {})); |
@@ -6,2 +6,3 @@ export * from "./action.js"; | ||
export * from "./entry.js"; | ||
export * from "./link.js"; | ||
export * from "./record.js"; |
@@ -6,2 +6,3 @@ export * from "./action.js"; | ||
export * from "./entry.js"; | ||
export * from "./link.js"; | ||
export * from "./record.js"; |
@@ -8,5 +8,5 @@ // This file is read by tools that parse documentation comments conforming to the TSDoc standard. | ||
"packageName": "@microsoft/api-extractor", | ||
"packageVersion": "7.39.4" | ||
"packageVersion": "7.34.4" | ||
} | ||
] | ||
} |
@@ -32,2 +32,6 @@ /** | ||
*/ | ||
export type ExternalHash = HoloHash; | ||
/** | ||
* @public | ||
*/ | ||
export type KitsuneAgent = Uint8Array; | ||
@@ -82,3 +86,3 @@ /** | ||
*/ | ||
export type DnaProperties = any; | ||
export type DnaProperties = unknown; | ||
/** | ||
@@ -118,2 +122,7 @@ * @public | ||
fetch_pool_info: FetchPoolInfo; | ||
current_number_of_peers: number; | ||
arc_size: number; | ||
total_network_peers: number; | ||
bytes_since_last_time_queried: number; | ||
completed_rounds_since_last_time_queried: number; | ||
} | ||
@@ -120,0 +129,0 @@ /** |
@@ -7,2 +7,3 @@ import { DnaHash, ActionHash, AgentPubKey, EntryHash } from "../types.js"; | ||
* | ||
* @param coreByte - Optionally specify a byte to repeat for all core 32 bytes. If undefined will generate random core 32 bytes. | ||
* @returns An {@link EntryHash}. | ||
@@ -12,6 +13,7 @@ * | ||
*/ | ||
export declare function fakeEntryHash(): Promise<EntryHash>; | ||
export declare function fakeEntryHash(coreByte?: number | undefined): Promise<EntryHash>; | ||
/** | ||
* Generate a valid agent key of a non-existing agent. | ||
* | ||
* @param coreByte - Optionally specify a byte to repeat for all core 32 bytes. If undefined will generate random core 32 bytes. | ||
* @returns An {@link AgentPubKey}. | ||
@@ -21,6 +23,7 @@ * | ||
*/ | ||
export declare function fakeAgentPubKey(): Promise<AgentPubKey>; | ||
export declare function fakeAgentPubKey(coreByte?: number | undefined): Promise<AgentPubKey>; | ||
/** | ||
* Generate a valid hash of a non-existing action. | ||
* | ||
* @param coreByte - Optionally specify a byte to repeat for all core 32 bytes. If undefined will generate random core 32 bytes. | ||
* @returns An {@link ActionHash}. | ||
@@ -30,6 +33,7 @@ * | ||
*/ | ||
export declare function fakeActionHash(): Promise<ActionHash>; | ||
export declare function fakeActionHash(coreByte?: number | undefined): Promise<ActionHash>; | ||
/** | ||
* Generate a valid hash of a non-existing DNA. | ||
* | ||
* @param coreByte - Optionally specify a byte to repeat for all core 32 bytes. If undefined will generate random core 32 bytes. | ||
* @returns A {@link DnaHash}. | ||
@@ -39,2 +43,2 @@ * | ||
*/ | ||
export declare function fakeDnaHash(): Promise<DnaHash>; | ||
export declare function fakeDnaHash(coreByte?: number | undefined): Promise<DnaHash>; |
@@ -0,2 +1,15 @@ | ||
import { range } from "lodash-es"; | ||
import { randomByteArray } from "../api/zome-call-signing.js"; | ||
import { dhtLocationFrom32 } from "./hash-parts.js"; | ||
async function fakeValidHash(prefix, coreByte) { | ||
let core; | ||
if (coreByte === undefined) { | ||
core = await randomByteArray(32); | ||
} | ||
else { | ||
core = Uint8Array.from(range(0, 32).map(() => coreByte)); | ||
} | ||
const checksum = dhtLocationFrom32(core); | ||
return new Uint8Array([...prefix, ...core, ...Array.from(checksum)]); | ||
} | ||
/** | ||
@@ -7,2 +20,3 @@ * Generate a valid hash of a non-existing entry. | ||
* | ||
* @param coreByte - Optionally specify a byte to repeat for all core 32 bytes. If undefined will generate random core 32 bytes. | ||
* @returns An {@link EntryHash}. | ||
@@ -12,5 +26,4 @@ * | ||
*/ | ||
export async function fakeEntryHash() { | ||
const randomBytes = await randomByteArray(36); | ||
return new Uint8Array([0x84, 0x21, 0x24, ...randomBytes]); | ||
export async function fakeEntryHash(coreByte = undefined) { | ||
return fakeValidHash([0x84, 0x21, 0x24], coreByte); | ||
} | ||
@@ -20,2 +33,3 @@ /** | ||
* | ||
* @param coreByte - Optionally specify a byte to repeat for all core 32 bytes. If undefined will generate random core 32 bytes. | ||
* @returns An {@link AgentPubKey}. | ||
@@ -25,5 +39,4 @@ * | ||
*/ | ||
export async function fakeAgentPubKey() { | ||
const randomBytes = await randomByteArray(36); | ||
return new Uint8Array([0x84, 0x20, 0x24, ...randomBytes]); | ||
export async function fakeAgentPubKey(coreByte = undefined) { | ||
return fakeValidHash([0x84, 0x20, 0x24], coreByte); | ||
} | ||
@@ -33,2 +46,3 @@ /** | ||
* | ||
* @param coreByte - Optionally specify a byte to repeat for all core 32 bytes. If undefined will generate random core 32 bytes. | ||
* @returns An {@link ActionHash}. | ||
@@ -38,5 +52,4 @@ * | ||
*/ | ||
export async function fakeActionHash() { | ||
const randomBytes = await randomByteArray(36); | ||
return new Uint8Array([0x84, 0x29, 0x24, ...randomBytes]); | ||
export async function fakeActionHash(coreByte = undefined) { | ||
return fakeValidHash([0x84, 0x29, 0x24], coreByte); | ||
} | ||
@@ -46,2 +59,3 @@ /** | ||
* | ||
* @param coreByte - Optionally specify a byte to repeat for all core 32 bytes. If undefined will generate random core 32 bytes. | ||
* @returns A {@link DnaHash}. | ||
@@ -51,5 +65,4 @@ * | ||
*/ | ||
export async function fakeDnaHash() { | ||
const randomBytes = await randomByteArray(36); | ||
return new Uint8Array([0x84, 0x2d, 0x24, ...randomBytes]); | ||
export async function fakeDnaHash(coreByte = undefined) { | ||
return fakeValidHash([0x84, 0x2d, 0x24], coreByte); | ||
} |
export * from "./base64.js"; | ||
export * from "./fake-hash.js"; | ||
export * from "./hash-parts.js"; |
export * from "./base64.js"; | ||
export * from "./fake-hash.js"; | ||
export * from "./hash-parts.js"; |
{ | ||
"name": "@holochain/client", | ||
"version": "0.12.6", | ||
"version": "0.12.7", | ||
"description": "A JavaScript client for the Holochain Conductor API", | ||
@@ -5,0 +5,0 @@ "author": "Holochain Foundation <info@holochain.org> (http://holochain.org)", |
114799
59
3661