diff --git a/.envrc b/.envrc new file mode 100644 index 000000000..c862386a5 --- /dev/null +++ b/.envrc @@ -0,0 +1 @@ +export FABRIC_NETWORK=playnet diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index acfa2881a..4061b0f14 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -1,35 +1,47 @@ -name: Test - +name: npm test on: pull_request: branches: - #- master # To be enabled once swaps-develop is merged - - feature/node-16 # To be removed once it is ready and merged - + - '**' + push: + branches: + - master jobs: test: - name: Test + name: Run tests runs-on: ${{ matrix.os }} - strategy: matrix: os: - macos-latest - ubuntu-latest - steps: - - name: checkout branch + - name: Checkout branch uses: actions/checkout@v3 - - - name: setup node.js on ${{ matrix.os }} - uses: actions/setup-node@v2 + - name: Install Node.js on ${{ matrix.os }} + uses: actions/setup-node@v4 with: node-version-file: '.nvmrc' cache: 'npm' cache-dependency-path: package-lock.json - - - name: install dependencies - run: npm ci - - - name: run tests with coverage - run: npm run coverage + - name: Set up Python + uses: actions/setup-python@v2 + with: + python-version: '3.8' + - name: Install dependencies + run: npm run report:install + - name: Download and install bitcoind + run: | + if [ "${{ matrix.os }}" = "ubuntu-latest" ]; then + wget https://bitcoin.org/bin/bitcoin-core-28.0/bitcoin-28.0-x86_64-linux-gnu.tar.gz + tar -xzf bitcoin-28.0-x86_64-linux-gnu.tar.gz + sudo mv bitcoin-28.0/bin/bitcoind /usr/local/bin/ + else + brew install bitcoin + fi + - name: Generate coverage report + run: npm run report:coverage + - name: Send coverage report + uses: codecov/codecov-action@v3.1.1 + with: + directory: ./reports/ diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index e69de29bb..000000000 diff --git a/.nix/node-env.nix b/.nix/node-env.nix index 2590dd267..af3f738e1 100644 --- a/.nix/node-env.nix +++ b/.nix/node-env.nix @@ -186,7 +186,7 @@ let ''} ''; - # Recursively traverses all dependencies of a package and pinpoints all + # Recursively traverses all package dependencies and pinpoints all # dependencies in the package.json file to the versions that are actually # being used. @@ -362,7 +362,7 @@ let ${lib.optionalString reconstructLock '' if [ -f package-lock.json ] then - echo "WARNING: Reconstruct lock option enabled, but a lock file already exists!" + echo "WARNING: The reconstruct lock option is enabled, but a lock file already exists!" echo "This will most likely result in version mismatches! We will remove the lock file and regenerate it!" rm package-lock.json else diff --git a/.nvmrc b/.nvmrc index 7fd023741..517f38666 100644 --- a/.nvmrc +++ b/.nvmrc @@ -1 +1 @@ -v16.15.0 +v22.14.0 diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 68db82272..000000000 --- a/.travis.yml +++ /dev/null @@ -1,9 +0,0 @@ -dist: focal -language: node_js -node_js: - - 16.17.1 -before_install: - - npm install -g codecov -after_success: - - npm run report:coverage - - codecov diff --git a/API.md b/API.md index b53a11791..d501547ae 100644 --- a/API.md +++ b/API.md @@ -1,15 +1,29 @@ ## Classes
-
Actor
-

Generic Fabric Actor.

+
BitcoinService
+

Manages interaction with the Bitcoin network.

+
+
Lightning
+

Manage a Lightning node.

+
+
Redis
+

Connect and subscribe to Redis servers.

+
+
ZMQ
+

Connect and subscribe to ZeroMQ publishers.

+
+
HTTPServer
+

Deprecated 2021-10-16.

+
+
Scribe
+

Deprecated 2021-11-06.

-
Aggregator
-

Aggregates a set of balances (inputs).

+
Stash
+

Deprecated 2021-11-06.

-
AppService
-

Web-friendly application framework for building single-page applications with -Fabric-based networking and storage.

+
Actor
+

Generic Fabric Actor.

Chain

Chain.

@@ -26,7 +40,7 @@ service to the network.

The Circuit is the mechanism through which Fabric operates, a computable directed graph describing a network of Peer components and their interactions (side effects). -See also Swarm for deeper *inspection of Machine +See also Swarm for deeper inspection of Machine mechanics.

CLI
@@ -36,15 +50,6 @@ the Fabric network using a terminal emulator.

Collection

The Collection type maintains an ordered list of State items.

-
Compiler : Actor
-

Compilers build interfaces for users of Fabric applications.

-
-
Consensus
-

Provides various network-specific rules.

-
-
Entity : Object
-

Live instance of an ARC in Fabric.

-
Environment

Interact with the user's Environment.

@@ -73,9 +78,6 @@ RFC 5869. Defaults to 32 byte output, matching Bitcoin's implementaton.

Key

Represents a cryptographic key.

-
Keystore
-

Provides an encrypted datastore for generic object storage.

-
LedgerScribe

An ordered stack of pages.

@@ -85,25 +87,11 @@ RFC 5869. Defaults to 32 byte output, matching Bitcoin's implementaton.

Machine

General-purpose state machine with Vector-based instructions.

-
Mempool
-

Stores a list of Transaction elements.

-
Message : Object

The Message type defines the Application Messaging Protocol, or AMP. Each Actor in the network receives and broadcasts messages, selectively disclosing new routes to peers which may have open circuits.

-
Node
-

Full definition of a Fabric node.

-
-
OracleStore
-

An Oracle manages one or more collections, using a mempool for -transitive state.

-
-
Path
-

A Path is a Fabric-native link to a Document -within the network.

-
Peer

An in-memory representation of a node in our network.

@@ -118,12 +106,6 @@ be moved to @fabric/http before final release!

Resource

Generic interface for collections of digital objects.

-
RouterScribe
-

Process incoming messages.

-
-
ScribeState
-

Simple tag-based recordkeeper.

-
Script
Service
@@ -139,9 +121,6 @@ familiar semantics.

The Session type describes a connection between Peer objects, and includes its own lifecycle.

-
SignerActor
-

Generic Fabric Signer.

-
Snapshot

A type of message to be expected from a Service.

@@ -156,17 +135,11 @@ committing to the outcome. This workflow keeps app design quite simple!

Store

Long-term storage.

-
Swap : Object
-

The Swap contract executes a set of transactions on two distinct -Chain components, utilizing a secret-reveal mechanism to atomically -execute either the full set or none.

-
Swarm : String

Orchestrates a network of peers.

-
Transition
-

The Transition type reflects a change from one finite -State to another.

+
Token
+

Implements a capability-based security token.

Tree

Class implementing a Merkle Tree.

@@ -186,515 +159,298 @@ execute either the full set or none.

almost like "threads", as they run asynchronously over the duration of a contract's lifetime as "fulfillment conditions" for its closure.

-
BitcoinService
-

Manages interaction with the Bitcoin network.

-
-
Exchange
-

Implements a basic Exchange.

-
-
Lightning
-

Manage a Lightning node.

-
-
Redis
-

Connect and subscribe to ZeroMQ servers.

-
-
ZMQ
-

Connect and subscribe to ZeroMQ publishers.

-
-
HTTPServer
-

Deprecated 2021-10-16.

-
-
Scribe
-

Deprecated 2021-11-06.

-
-
Stash
-

Deprecated 2021-11-06.

-
- + -## Actor -Generic Fabric Actor. +## Bitcoin ⇐ [Service](#Service) +Manages interaction with the Bitcoin network. **Kind**: global class -**Emits**: event:message Fabric {@link Message} objects. -**Access**: protected -**Properties** +**Extends**: [Service](#Service) -| Name | Type | Description | +* [Bitcoin](#Bitcoin) ⇐ [Service](#Service) + * [new Bitcoin([settings])](#new_Bitcoin_new) + * [.UAString](#Bitcoin+UAString) + * [.tip](#Bitcoin+tip) + * [.height](#Bitcoin+height) + * [.broadcast(tx)](#Bitcoin+broadcast) + * [._processSpendMessage(message)](#Bitcoin+_processSpendMessage) ⇒ BitcoinTransactionID + * [._prepareTransaction(obj)](#Bitcoin+_prepareTransaction) + * [._handleCommittedBlock(block)](#Bitcoin+_handleCommittedBlock) + * [._handlePeerPacket(msg)](#Bitcoin+_handlePeerPacket) + * [._handleBlockFromSPV(msg)](#Bitcoin+_handleBlockFromSPV) + * [._handleTransactionFromSPV(tx)](#Bitcoin+_handleTransactionFromSPV) + * [._subscribeToShard(shard)](#Bitcoin+_subscribeToShard) + * [._connectSPV()](#Bitcoin+_connectSPV) + * [.connect(addr)](#Bitcoin+connect) + * [._requestBlockAtHeight(height)](#Bitcoin+_requestBlockAtHeight) ⇒ Object + * [._createContractProposal(options)](#Bitcoin+_createContractProposal) ⇒ ContractProposal + * [._buildPSBT(options)](#Bitcoin+_buildPSBT) ⇒ PSBT + * [.start()](#Bitcoin+start) + * [.stop()](#Bitcoin+stop) + * [.init()](#Service+init) + * [.tick()](#Service+tick) ⇒ Number + * [.beat()](#Service+beat) ⇒ [Service](#Service) + * [.get(path)](#Service+get) ⇒ Mixed + * [.set(path)](#Service+set) ⇒ Mixed + * [.trust(source)](#Service+trust) ⇒ [Service](#Service) + * [.handler(message)](#Service+handler) ⇒ [Service](#Service) + * [.lock([duration])](#Service+lock) ⇒ Boolean + * [.when(event, method)](#Service+when) ⇒ EventEmitter + * [.route(msg)](#Service+route) ⇒ Promise + * [._GET(path)](#Service+_GET) ⇒ Promise + * [._PUT(path, value, [commit])](#Service+_PUT) ⇒ Promise + * [.send(channel, message)](#Service+send) ⇒ [Service](#Service) + * [._registerActor(actor)](#Service+_registerActor) ⇒ Promise + * [._send(message)](#Service+_send) + + + +### new Bitcoin([settings]) +Creates an instance of the Bitcoin service. + + +| Param | Type | Description | | --- | --- | --- | -| id | String | Unique identifier for this Actor (id === SHA256(preimage)). | -| preimage | String | Input hash for the `id` property (preimage === SHA256(ActorState)). | +| [settings] | Object | Map of configuration options for the Bitcoin service. | +| [settings.network] | String | One of `regtest`, `testnet`, or `mainnet`. | +| [settings.nodes] | Array | List of address:port pairs to trust. | +| [settings.seeds] | Array | Bitcoin peers to request chain from (address:port). | +| [settings.fullnode] | Boolean | Run a full node. | + -* [Actor](#Actor) - * [new Actor([actor])](#new_Actor_new) - * _instance_ - * [.adopt(changes)](#Actor+adopt) ⇒ [Actor](#Actor) - * [.commit()](#Actor+commit) ⇒ String - * [.export()](#Actor+export) ⇒ Object - * [.get(path)](#Actor+get) ⇒ Object - * [.set(path, value)](#Actor+set) ⇒ Object - * [.toBuffer()](#Actor+toBuffer) ⇒ Buffer - * [.toGenericMessage()](#Actor+toGenericMessage) ⇒ Object - * [.toObject()](#Actor+toObject) ⇒ Object - * [.pause()](#Actor+pause) ⇒ [Actor](#Actor) - * [.serialize()](#Actor+serialize) ⇒ String - * [.sign()](#Actor+sign) ⇒ [Actor](#Actor) - * [.unpause()](#Actor+unpause) ⇒ [Actor](#Actor) - * [.value([format])](#Actor+value) ⇒ Object - * [._readObject(input)](#Actor+_readObject) ⇒ Object - * _static_ - * [.fromAny(input)](#Actor.fromAny) ⇒ [Actor](#Actor) - * [.randomBytes([count])](#Actor.randomBytes) ⇒ Buffer +### bitcoin.UAString +User Agent string for the Bitcoin P2P network. - +**Kind**: instance property of [Bitcoin](#Bitcoin) + -### new Actor([actor]) -Creates an [Actor](#Actor), which emits messages for other -Actors to subscribe to. You can supply certain parameters -for the actor, including key material [!!!] — be mindful of -what you share with others! +### bitcoin.tip +Chain tip (block hash of the chain with the most Proof of Work) -**Returns**: [Actor](#Actor) - Instance of the Actor. Call [sign](#Actor+sign) to emit a [Signature](Signature). +**Kind**: instance property of [Bitcoin](#Bitcoin) + -| Param | Type | Description | -| --- | --- | --- | -| [actor] | Object | Object to use as the actor. | -| [actor.seed] | String | BIP24 Mnemonic to use as a seed phrase. | -| [actor.public] | Buffer | Public key. | -| [actor.private] | Buffer | Private key. | +### bitcoin.height +Chain height (`=== length - 1`) - +**Kind**: instance property of [Bitcoin](#Bitcoin) + -### actor.adopt(changes) ⇒ [Actor](#Actor) -Explicitly adopt a set of [JSONPatch](JSONPatch)-encoded changes. +### bitcoin.broadcast(tx) +Broadcast a transaction to the Bitcoin network. -**Kind**: instance method of [Actor](#Actor) -**Returns**: [Actor](#Actor) - Instance of the Actor. +**Kind**: instance method of [Bitcoin](#Bitcoin) +**Unstable**: | Param | Type | Description | | --- | --- | --- | -| changes | Array | List of [JSONPatch](JSONPatch) operations to apply. | +| tx | TX | Bitcoin transaction | - + -### actor.commit() ⇒ String -Resolve the current state to a commitment. +### bitcoin.\_processSpendMessage(message) ⇒ BitcoinTransactionID +Process a spend message. -**Kind**: instance method of [Actor](#Actor) -**Returns**: String - 32-byte ID - +**Kind**: instance method of [Bitcoin](#Bitcoin) +**Returns**: BitcoinTransactionID - Hex-encoded representation of the transaction ID. -### actor.export() ⇒ Object -Export the Actor's state to a standard [Object](Object). +| Param | Type | Description | +| --- | --- | --- | +| message | SpendMessage | Generic-level message for spending. | +| message.amount | String | Amount (in BTC) to spend. | +| message.destination | String | Destination for funds. | -**Kind**: instance method of [Actor](#Actor) -**Returns**: Object - Standard object. - + -### actor.get(path) ⇒ Object -Retrieve a value from the Actor's state by [JSONPointer](JSONPointer) path. +### bitcoin.\_prepareTransaction(obj) +Prepares a [Transaction](Transaction) for storage. -**Kind**: instance method of [Actor](#Actor) -**Returns**: Object - Value of the path in the Actor's state. +**Kind**: instance method of [Bitcoin](#Bitcoin) | Param | Type | Description | | --- | --- | --- | -| path | String | Path to retrieve using [JSONPointer](JSONPointer). | +| obj | Transaction | Transaction to prepare. | - + -### actor.set(path, value) ⇒ Object -Set a value in the Actor's state by [JSONPointer](JSONPointer) path. +### bitcoin.\_handleCommittedBlock(block) +Receive a committed block. -**Kind**: instance method of [Actor](#Actor) -**Returns**: Object - Value of the path in the Actor's state. +**Kind**: instance method of [Bitcoin](#Bitcoin) | Param | Type | Description | | --- | --- | --- | -| path | String | Path to set using [JSONPointer](JSONPointer). | -| value | Object | Value to set. | +| block | Block | Block to handle. | - + -### actor.toBuffer() ⇒ Buffer -Casts the Actor to a normalized Buffer. +### bitcoin.\_handlePeerPacket(msg) +Process a message from a peer in the Bitcoin network. -**Kind**: instance method of [Actor](#Actor) - +**Kind**: instance method of [Bitcoin](#Bitcoin) -### actor.toGenericMessage() ⇒ Object -Casts the Actor to a generic message. +| Param | Type | Description | +| --- | --- | --- | +| msg | PeerPacket | Message from peer. | -**Kind**: instance method of [Actor](#Actor) -**Returns**: Object - Generic message object. - + -### actor.toObject() ⇒ Object -Returns the Actor's current state as an [Object](Object). +### bitcoin.\_handleBlockFromSPV(msg) +Hand a [Block](Block) message as supplied by an [SPV](SPV) client. -**Kind**: instance method of [Actor](#Actor) - +**Kind**: instance method of [Bitcoin](#Bitcoin) -### actor.pause() ⇒ [Actor](#Actor) -Toggles `status` property to paused. +| Param | Type | Description | +| --- | --- | --- | +| msg | BlockMessage | A [Message](#Message) as passed by the [SPV](SPV) source. | -**Kind**: instance method of [Actor](#Actor) -**Returns**: [Actor](#Actor) - Instance of the Actor. - + -### actor.serialize() ⇒ String -Serialize the Actor's current state into a JSON-formatted string. +### bitcoin.\_handleTransactionFromSPV(tx) +Verify and interpret a [BitcoinTransaction](BitcoinTransaction), as received from an +[SPVSource](SPVSource). -**Kind**: instance method of [Actor](#Actor) - +**Kind**: instance method of [Bitcoin](#Bitcoin) -### actor.sign() ⇒ [Actor](#Actor) -Signs the Actor. +| Param | Type | Description | +| --- | --- | --- | +| tx | BitcoinTransaction | Incoming transaction from the SPV source. | -**Kind**: instance method of [Actor](#Actor) - + -### actor.unpause() ⇒ [Actor](#Actor) -Toggles `status` property to unpaused. +### bitcoin.\_subscribeToShard(shard) +Attach event handlers for a supplied list of addresses. -**Kind**: instance method of [Actor](#Actor) -**Returns**: [Actor](#Actor) - Instance of the Actor. - - -### actor.value([format]) ⇒ Object -Get the inner value of the Actor with an optional cast type. - -**Kind**: instance method of [Actor](#Actor) -**Returns**: Object - Inner value of the Actor as an [Object](Object), or cast to the requested `format`. - -| Param | Type | Default | Description | -| --- | --- | --- | --- | -| [format] | String | object | Cast the value to one of: `buffer, hex, json, string` | - - - -### actor.\_readObject(input) ⇒ Object -Parse an Object into a corresponding Fabric state. - -**Kind**: instance method of [Actor](#Actor) -**Returns**: Object - Fabric state. +**Kind**: instance method of [Bitcoin](#Bitcoin) | Param | Type | Description | | --- | --- | --- | -| input | Object | Object to read as input. | - - - -### Actor.fromAny(input) ⇒ [Actor](#Actor) -Create an [Actor](#Actor) from a variety of formats. - -**Kind**: static method of [Actor](#Actor) -**Returns**: [Actor](#Actor) - Instance of the [Actor](#Actor). - -| Param | Type | Description | -| --- | --- | --- | -| input | Object | Target [Object](Object) to create. | - - - -### Actor.randomBytes([count]) ⇒ Buffer -Get a number of random bytes from the runtime environment. - -**Kind**: static method of [Actor](#Actor) -**Returns**: Buffer - The random bytes. - -| Param | Type | Default | Description | -| --- | --- | --- | --- | -| [count] | Number | 32 | Number of random bytes to retrieve. | - - - -## Aggregator -Aggregates a set of balances (inputs). +| shard | Shard | List of addresses to monitor. | -**Kind**: global class + -* [Aggregator](#Aggregator) - * [new Aggregator([settings])](#new_Aggregator_new) - * [._importBalances(list)](#Aggregator+_importBalances) ⇒ AnchorBalance - * [._computeBalances()](#Aggregator+_computeBalances) ⇒ AnchorBalance - * [.commit()](#Aggregator+commit) ⇒ AggregatorCommit - * ["commit"](#Aggregator+event_commit) +### bitcoin.\_connectSPV() +Initiate outbound connections to configured SPV nodes. - +**Kind**: instance method of [Bitcoin](#Bitcoin) + -### new Aggregator([settings]) -Create a new Aggregator. +### bitcoin.connect(addr) +Connect to a Fabric [Peer](#Peer). -**Returns**: [Aggregator](#Aggregator) - Instance of the [Aggregator](#Aggregator). +**Kind**: instance method of [Bitcoin](#Bitcoin) +**Overrides**: [connect](#Service+connect) | Param | Type | Description | | --- | --- | --- | -| [settings] | Object | Map of configuration values. | -| [settings.inputs] | Array | Array of [AnchorBalance](AnchorBalance) instances. | +| addr | String | Address to connect to. | - + -### aggregator.\_importBalances(list) ⇒ AnchorBalance -Import a list of [AnchorBalance](AnchorBalance) instances. +### bitcoin.\_requestBlockAtHeight(height) ⇒ Object +Retrieve the equivalent to `getblockhash` from Bitcoin Core. -**Kind**: instance method of [Aggregator](#Aggregator) -**Returns**: AnchorBalance - Summary of resulting balances. +**Kind**: instance method of [Bitcoin](#Bitcoin) +**Returns**: Object - The block hash. | Param | Type | Description | | --- | --- | --- | -| list | Array | List of inputs to add. | - - - -### aggregator.\_computeBalances() ⇒ AnchorBalance -Updates the state to reflect balances from current inputs. - -**Kind**: instance method of [Aggregator](#Aggregator) -**Returns**: AnchorBalance - Summary of balances. - - -### aggregator.commit() ⇒ AggregatorCommit -Commits the balance of all input. - -**Kind**: instance method of [Aggregator](#Aggregator) -**Returns**: AggregatorCommit - Commit instance. -**Emits**: [commit](#Aggregator+event_commit) - - -### "commit" -Commit event. - -**Kind**: event emitted by [Aggregator](#Aggregator) -**Properties** - -| Name | Type | Description | -| --- | --- | --- | -| root | Uint8Array | Root of the [Tree](#Tree). | -| leaves | Array | Leaves of the [Tree](#Tree). | +| height | Number | Height of block to retrieve. | - + -## App ⇐ [Service](#Service) -Web-friendly application framework for building single-page applications with -Fabric-based networking and storage. +### bitcoin.\_createContractProposal(options) ⇒ ContractProposal +Creates an unsigned Bitcoin transaction. -**Kind**: global class -**Extends**: [Service](#Service) -**Properties** +**Kind**: instance method of [Bitcoin](#Bitcoin) +**Returns**: ContractProposal - Instance of the proposal. -| Name | Type | Description | -| --- | --- | --- | -| components | [Collection](#Collection) | Interface elements. | -| stash | [Store](#Store) | Routable [Datastore](Datastore). | - - -* [App](#App) ⇐ [Service](#Service) - * [new App(definition)](#new_App_new) - * [.start()](#App+start) ⇒ Promise - * [.stop()](#App+stop) ⇒ Promise - * [.define(name, structure)](#App+define) ⇒ Object - * [.defer(authority)](#App+defer) ⇒ [App](#App) - * [.attach(element)](#App+attach) ⇒ [App](#App) - * [.consume(resources)](#App+consume) ⇒ [App](#App) - * [.envelop(selector)](#App+envelop) ⇒ [App](#App) - * [.use(name, definition)](#App+use) ⇒ [App](#App) - * [.render()](#App+render) ⇒ String - * [._registerService(name, Service)](#App+_registerService) ⇒ [Service](#Service) - * [.init()](#Service+init) - * [.tick()](#Service+tick) ⇒ Number - * [.beat()](#Service+beat) ⇒ [Service](#Service) - * [.get(path)](#Service+get) ⇒ Mixed - * [.set(path)](#Service+set) ⇒ Mixed - * [.trust(source)](#Service+trust) ⇒ [Service](#Service) - * [.handler(message)](#Service+handler) ⇒ [Service](#Service) - * [.lock([duration])](#Service+lock) ⇒ Boolean - * [.route(msg)](#Service+route) ⇒ Promise - * [._GET(path)](#Service+_GET) ⇒ Promise - * [._PUT(path, value, [commit])](#Service+_PUT) ⇒ Promise - * [.connect(notify)](#Service+connect) ⇒ Promise - * [.send(channel, message)](#Service+send) ⇒ [Service](#Service) - * [._registerActor(actor)](#Service+_registerActor) ⇒ Promise - * [._send(message)](#Service+_send) +| Param | Type | +| --- | --- | +| options | Object | - + -### new App(definition) -Generic bundle for building Fabric applications. +### bitcoin.\_buildPSBT(options) ⇒ PSBT +Create a Partially-Signed Bitcoin Transaction (PSBT). -**Returns**: [App](#App) - Returns an instance of `App`. +**Kind**: instance method of [Bitcoin](#Bitcoin) +**Returns**: PSBT - Instance of the PSBT. | Param | Type | Description | | --- | --- | --- | -| definition | Object | Application definition. See `config` for examples. | +| options | Object | Parameters for the PSBT. | - + -### app.start() ⇒ Promise -Start the program. +### bitcoin.start() +Start the Bitcoin service, including the initiation of outbound requests. -**Kind**: instance method of [App](#App) +**Kind**: instance method of [Bitcoin](#Bitcoin) **Overrides**: [start](#Service+start) - - -### app.stop() ⇒ Promise -Stop the program. - -**Kind**: instance method of [App](#App) - - -### app.define(name, structure) ⇒ Object -Define a Resource, or "Type", used by the application. - -**Kind**: instance method of [App](#App) -**Returns**: Object - [description] - -| Param | Type | Description | -| --- | --- | --- | -| name | String | Human-friendly name for the Resource. | -| structure | Object | Map of attribute names -> definitions. | - - - -### app.defer(authority) ⇒ [App](#App) -Defer control of this application to an outside authority. - -**Kind**: instance method of [App](#App) -**Returns**: [App](#App) - The configured application as deferred to `authority`. - -| Param | Type | Description | -| --- | --- | --- | -| authority | String | Hostname to trust. | - - - -### app.attach(element) ⇒ [App](#App) -Configure the Application to use a specific element. - -**Kind**: instance method of [App](#App) -**Returns**: [App](#App) - Configured instance of the Application. - -| Param | Type | Description | -| --- | --- | --- | -| element | DOMElement | DOM element to bind to. | - - - -### app.consume(resources) ⇒ [App](#App) -Define the Application's resources from an existing resource map. - -**Kind**: instance method of [App](#App) -**Returns**: [App](#App) - Configured instance of the Application. - -| Param | Type | Description | -| --- | --- | --- | -| resources | Object | Map of resource definitions by name. | - - - -### app.envelop(selector) ⇒ [App](#App) -Use a CSS selector to find an element in the current document's tree and -bind to it as the render target. - -**Kind**: instance method of [App](#App) -**Returns**: [App](#App) - Instance of app with bound element. - -| Param | Type | Description | -| --- | --- | --- | -| selector | String | CSS selector. | - - - -### app.use(name, definition) ⇒ [App](#App) -Define a named [Resource](#Resource). - -**Kind**: instance method of [App](#App) -**Returns**: [App](#App) - Configurated instance of the [App](#App). - -| Param | Type | Description | -| --- | --- | --- | -| name | String | Human-friendly name for this resource. | -| definition | Object | Map of configuration values. | - - - -### app.render() ⇒ String -Get the output of our program. - -**Kind**: instance method of [App](#App) -**Returns**: String - Output of the program. - - -### app.\_registerService(name, Service) ⇒ [Service](#Service) -Registers a named [Service](#Service) with the application. Services are -standardized interfaces for Fabric contracts, emitting [Message](#Message) -events with a predictable lifecycle. - -**Kind**: instance method of [App](#App) -**Returns**: [Service](#Service) - The registered service instance. -**Internal**: + -| Param | Type | Description | -| --- | --- | --- | -| name | String | Internal name of the service. | -| Service | Class | The ES6 class definition implementing [Service](#Service). | +### bitcoin.stop() +Stop the Bitcoin service. +**Kind**: instance method of [Bitcoin](#Bitcoin) -### app.init() +### bitcoin.init() Called by Web Components. TODO: move to @fabric/http/types/spa -**Kind**: instance method of [App](#App) +**Kind**: instance method of [Bitcoin](#Bitcoin) **Overrides**: [init](#Service+init) -### app.tick() ⇒ Number +### bitcoin.tick() ⇒ Number Move forward one clock cycle. -**Kind**: instance method of [App](#App) +**Kind**: instance method of [Bitcoin](#Bitcoin) **Overrides**: [tick](#Service+tick) -### app.beat() ⇒ [Service](#Service) +### bitcoin.beat() ⇒ [Service](#Service) Compute latest state. -**Kind**: instance method of [App](#App) +**Kind**: instance method of [Bitcoin](#Bitcoin) **Overrides**: [beat](#Service+beat) **Emits**: Message#event:beat -### app.get(path) ⇒ Mixed +### bitcoin.get(path) ⇒ Mixed Retrieve a key from the [State](#State). -**Kind**: instance method of [App](#App) +**Kind**: instance method of [Bitcoin](#Bitcoin) **Overrides**: [get](#Service+get) +**Returns**: Mixed - Returns the target value if found, otherwise null. | Param | Type | Description | | --- | --- | --- | -| path | [Path](#Path) | Key to retrieve. | +| path | Path | Key to retrieve. | -### app.set(path) ⇒ Mixed +### bitcoin.set(path) ⇒ Mixed Set a key in the [State](#State) to a particular value. -**Kind**: instance method of [App](#App) +**Kind**: instance method of [Bitcoin](#Bitcoin) **Overrides**: [set](#Service+set) | Param | Type | Description | | --- | --- | --- | -| path | [Path](#Path) | Key to retrieve. | +| path | Path | Key to retrieve. | -### app.trust(source) ⇒ [Service](#Service) +### bitcoin.trust(source) ⇒ [Service](#Service) Explicitly trust all events from a known source. -**Kind**: instance method of [App](#App) +**Kind**: instance method of [Bitcoin](#Bitcoin) **Overrides**: [trust](#Service+trust) **Returns**: [Service](#Service) - Instance of Service after binding events. @@ -704,11 +460,11 @@ Explicitly trust all events from a known source. -### app.handler(message) ⇒ [Service](#Service) +### bitcoin.handler(message) ⇒ [Service](#Service) Default route handler for an incoming message. Follows the Activity Streams 2.0 spec: https://www.w3.org/TR/activitystreams-core/ -**Kind**: instance method of [App](#App) +**Kind**: instance method of [Bitcoin](#Bitcoin) **Overrides**: [handler](#Service+handler) **Returns**: [Service](#Service) - Chainable method. @@ -718,10 +474,10 @@ Streams 2.0 spec: https://www.w3.org/TR/activitystreams-core/ -### app.lock([duration]) ⇒ Boolean +### bitcoin.lock([duration]) ⇒ Boolean Attempt to acquire a lock for `duration` seconds. -**Kind**: instance method of [App](#App) +**Kind**: instance method of [Bitcoin](#Bitcoin) **Overrides**: [lock](#Service+lock) **Returns**: Boolean - true if locked, false if unable to lock. @@ -729,12 +485,26 @@ Attempt to acquire a lock for `duration` seconds. | --- | --- | --- | --- | | [duration] | Number | 1000 | Number of milliseconds to hold lock. | + + +### bitcoin.when(event, method) ⇒ EventEmitter +Bind a method to an event, with current state as the immutable context. + +**Kind**: instance method of [Bitcoin](#Bitcoin) +**Overrides**: [when](#Service+when) +**Returns**: EventEmitter - Instance of EventEmitter. + +| Param | Type | Description | +| --- | --- | --- | +| event | String | Name of the event upon which to execute `method` as a function. | +| method | function | Function to execute when named [Event](Event) `event` is encountered. | + -### app.route(msg) ⇒ Promise +### bitcoin.route(msg) ⇒ Promise Resolve a [State](#State) from a particular [Message](#Message) object. -**Kind**: instance method of [App](#App) +**Kind**: instance method of [Bitcoin](#Bitcoin) **Overrides**: [route](#Service+route) **Returns**: Promise - Resolves with resulting [State](#State). @@ -744,10 +514,10 @@ Resolve a [State](#State) from a particular [Message](#Message) object. -### app.\_GET(path) ⇒ Promise +### bitcoin.\_GET(path) ⇒ Promise Retrieve a value from the Service's state. -**Kind**: instance method of [App](#App) +**Kind**: instance method of [Bitcoin](#Bitcoin) **Overrides**: [\_GET](#Service+_GET) **Returns**: Promise - Resolves with the result. @@ -757,10 +527,10 @@ Retrieve a value from the Service's state. -### app.\_PUT(path, value, [commit]) ⇒ Promise +### bitcoin.\_PUT(path, value, [commit]) ⇒ Promise Store a value in the Service's state. -**Kind**: instance method of [App](#App) +**Kind**: instance method of [Bitcoin](#Bitcoin) **Overrides**: [\_PUT](#Service+_PUT) **Returns**: Promise - Resolves with with stored document. @@ -770,25 +540,12 @@ Store a value in the Service's state. | value | Object | | Document to store. | | [commit] | Boolean | false | Sign the resulting state. | - - -### app.connect(notify) ⇒ Promise -Attach to network. - -**Kind**: instance method of [App](#App) -**Overrides**: [connect](#Service+connect) -**Returns**: Promise - Resolves to [Fabric](#Fabric). - -| Param | Type | Default | Description | -| --- | --- | --- | --- | -| notify | Boolean | true | Commit to changes. | - -### app.send(channel, message) ⇒ [Service](#Service) +### bitcoin.send(channel, message) ⇒ [Service](#Service) Send a message to a channel. -**Kind**: instance method of [App](#App) +**Kind**: instance method of [Bitcoin](#Bitcoin) **Overrides**: [send](#Service+send) **Returns**: [Service](#Service) - Chainable method. @@ -799,10 +556,10 @@ Send a message to a channel. -### app.\_registerActor(actor) ⇒ Promise +### bitcoin.\_registerActor(actor) ⇒ Promise Register an [Actor](#Actor) with the [Service](#Service). -**Kind**: instance method of [App](#App) +**Kind**: instance method of [Bitcoin](#Bitcoin) **Overrides**: [\_registerActor](#Service+_registerActor) **Returns**: Promise - Resolves upon successful registration. @@ -812,1024 +569,163 @@ Register an [Actor](#Actor) with the [Service](#Service). -### app.\_send(message) +### bitcoin.\_send(message) Sends a message. -**Kind**: instance method of [App](#App) +**Kind**: instance method of [Bitcoin](#Bitcoin) **Overrides**: [\_send](#Service+_send) | Param | Type | Description | | --- | --- | --- | | message | Mixed | Message to send. | - + -## Chain -Chain. +## Lightning +Manage a Lightning node. **Kind**: global class -**Properties** -| Name | Type | Description | -| --- | --- | --- | -| name | String | Current name. | -| indices | Map | | -| storage | Storage | | +* [Lightning](#Lightning) + * [new Lightning([settings])](#new_Lightning_new) + * [._makeRPCRequest(method, [params])](#Lightning+_makeRPCRequest) ⇒ Object \| String - + -### new Chain(genesis) -Holds an immutable chain of events. +### new Lightning([settings]) +Create an instance of the Lightning [Service](#Service). | Param | Type | Description | | --- | --- | --- | -| genesis | [Vector](#Vector) | Initial state for the chain of events. | +| [settings] | Object | Settings. | - + -## Channel -The [Channel](#Channel) is a encrypted connection with a member of your -[Peer](#Peer) group, with some amount of $BTC bonded and paid for each -correctly-validated message. +### lightning.\_makeRPCRequest(method, [params]) ⇒ Object \| String +Make an RPC request through the Lightning UNIX socket. -Channels in Fabric are powerful tools for application development, as they -can empower users with income opportunities in exchange for delivering -service to the network. +**Kind**: instance method of [Lightning](#Lightning) +**Returns**: Object \| String - Respond from the Lightning node. -**Kind**: global class +| Param | Type | Description | +| --- | --- | --- | +| method | String | Name of method to call. | +| [params] | Array | Array of parameters. | -* [Channel](#Channel) - * [new Channel([settings])](#new_Channel_new) - * [.add(amount)](#Channel+add) - * [.fund(input)](#Channel+fund) - * [.open(channel)](#Channel+open) + - +## Redis +Connect and subscribe to Redis servers. -### new Channel([settings]) -Creates a channel between two peers. -of many transactions over time, to be settled on-chain later. - - -| Param | Type | Description | -| --- | --- | --- | -| [settings] | Object | Configuration for the channel. | - - - -### channel.add(amount) -Add an amount to the channel's balance. - -**Kind**: instance method of [Channel](#Channel) - -| Param | Type | Description | -| --- | --- | --- | -| amount | Number | Amount value to add to current outgoing balance. | - - - -### channel.fund(input) -Fund the channel. - -**Kind**: instance method of [Channel](#Channel) - -| Param | Type | Description | -| --- | --- | --- | -| input | Mixed | Instance of a [Transaction](Transaction). | - - - -### channel.open(channel) -Opens a [Channel](#Channel) with a [Peer](#Peer). - -**Kind**: instance method of [Channel](#Channel) - -| Param | Type | Description | -| --- | --- | --- | -| channel | Object | Channel settings. | - - - -## Circuit -The [Circuit](#Circuit) is the mechanism through which [Fabric](#Fabric) -operates, a computable directed graph describing a network of -[Peer](#Peer) components and their interactions (side effects). -See also [Swarm](#Swarm) for deeper *inspection of [Machine](#Machine) -mechanics. - -**Kind**: global class - - -## CLI -Provides a Command Line Interface (CLI) for interacting with -the Fabric network using a terminal emulator. - -**Kind**: global class - -* [CLI](#CLI) - * [new CLI([settings])](#new_CLI_new) - * [.start()](#CLI+start) - * [.stop()](#CLI+stop) - - - -### new CLI([settings]) -Create a terminal-based interface for a [User](User). - - -| Param | Type | Description | -| --- | --- | --- | -| [settings] | Object | Configuration values. | -| [settings.currencies] | Array | List of currencies to support. | - - - -### clI.start() -Starts (and renders) the CLI. - -**Kind**: instance method of [CLI](#CLI) - - -### clI.stop() -Disconnect all interfaces and exit the process. - -**Kind**: instance method of [CLI](#CLI) - - -## Collection -The [Collection](#Collection) type maintains an ordered list of [State](#State) items. - -**Kind**: global class -**Properties** - -| Name | Type | Description | -| --- | --- | --- | -| @entity | Object | Fabric-bound entity object. | - - -* [Collection](#Collection) - * [new Collection([configuration])](#new_Collection_new) - * [.asMerkleTree()](#Collection+asMerkleTree) ⇒ MerkleTree - * [._setKey(name)](#Collection+_setKey) - * [.getByID(id)](#Collection+getByID) - * [.getLatest()](#Collection+getLatest) - * [.findByField(name, value)](#Collection+findByField) - * [.findByName(name)](#Collection+findByName) - * [.findBySymbol(symbol)](#Collection+findBySymbol) - * [._patchTarget(path, patches)](#Collection+_patchTarget) - * [.push(data)](#Collection+push) ⇒ Number - * [.get(path)](#Collection+get) ⇒ Mixed - * [.set(path)](#Collection+set) ⇒ Mixed - * ~~[.list()](#Collection+list) ⇒ Array~~ - * [.toTypedArray()](#Collection+toTypedArray) - * [.map()](#Collection+map) ⇒ Array - * [.create(entity)](#Collection+create) ⇒ Promise - * [.import(state, commit)](#Collection+import) - - - -### new Collection([configuration]) -Create a list of [Entity](#Entity)-like objects for later retrieval. - -**Returns**: [Collection](#Collection) - Configured instance of the the [Collection](#Collection). - -| Param | Type | Default | Description | -| --- | --- | --- | --- | -| [configuration] | Object | {} | Configuration object. | - - - -### collection.asMerkleTree() ⇒ MerkleTree -Current elements of the collection as a [MerkleTree](MerkleTree). - -**Kind**: instance method of [Collection](#Collection) - - -### collection.\_setKey(name) -Sets the `key` property of collection settings. - -**Kind**: instance method of [Collection](#Collection) - -| Param | Type | Description | -| --- | --- | --- | -| name | String | Value to set the `key` setting to. | - - - -### collection.getByID(id) -Retrieve an element from the collection by ID. - -**Kind**: instance method of [Collection](#Collection) - -| Param | Type | Description | -| --- | --- | --- | -| id | String | Document identifier. | - - - -### collection.getLatest() -Retrieve the most recent element in the collection. - -**Kind**: instance method of [Collection](#Collection) - - -### collection.findByField(name, value) -Find a document by specific field. - -**Kind**: instance method of [Collection](#Collection) - -| Param | Type | Description | -| --- | --- | --- | -| name | String | Name of field to search. | -| value | String | Value to match. | - - - -### collection.findByName(name) -Find a document by the "name" field. - -**Kind**: instance method of [Collection](#Collection) - -| Param | Type | Description | -| --- | --- | --- | -| name | String | Name to search for. | - - - -### collection.findBySymbol(symbol) -Find a document by the "symbol" field. - -**Kind**: instance method of [Collection](#Collection) - -| Param | Type | Description | -| --- | --- | --- | -| symbol | String | Value to search for. | - - - -### collection.\_patchTarget(path, patches) -Modify a target document using an array of atomic updates. - -**Kind**: instance method of [Collection](#Collection) - -| Param | Type | Description | -| --- | --- | --- | -| path | String | Path to the document to modify. | -| patches | Array | List of operations to apply. | - - - -### collection.push(data) ⇒ Number -Adds an [Entity](#Entity) to the [Collection](#Collection). - -**Kind**: instance method of [Collection](#Collection) -**Returns**: Number - Length of the collection. - -| Param | Type | Description | -| --- | --- | --- | -| data | Mixed | [Entity](#Entity) to add. | - - - -### collection.get(path) ⇒ Mixed -Retrieve a key from the [State](#State). - -**Kind**: instance method of [Collection](#Collection) - -| Param | Type | Description | -| --- | --- | --- | -| path | [Path](#Path) | Key to retrieve. | - - - -### collection.set(path) ⇒ Mixed -Set a key in the [State](#State) to a particular value. - -**Kind**: instance method of [Collection](#Collection) - -| Param | Type | Description | -| --- | --- | --- | -| path | [Path](#Path) | Key to retrieve. | - - - -### ~~collection.list() ⇒ Array~~ -***Deprecated*** - -Generate a list of elements in the collection. - -**Kind**: instance method of [Collection](#Collection) - - -### collection.toTypedArray() -Provides the [Collection](#Collection) as an [Array](Array) of typed -elements. The type of these elments are defined by the collection's -type, supplied in the constructor. - -**Kind**: instance method of [Collection](#Collection) - - -### collection.map() ⇒ Array -Generate a hashtable of elements in the collection. - -**Kind**: instance method of [Collection](#Collection) - - -### collection.create(entity) ⇒ Promise -Create an instance of an [Entity](#Entity). - -**Kind**: instance method of [Collection](#Collection) -**Returns**: Promise - Resolves with instantiated [Entity](#Entity). - -| Param | Type | Description | -| --- | --- | --- | -| entity | Object | Object with properties. | - - - -### collection.import(state, commit) -Loads [State](#State) into memory. - -**Kind**: instance method of [Collection](#Collection) -**Emits**: event:message Will emit one {@link Snapshot} message. - -| Param | Type | Description | -| --- | --- | --- | -| state | [State](#State) | State to import. | -| commit | Boolean | Whether or not to commit the result. | - - - -## Compiler : [Actor](#Actor) -Compilers build interfaces for users of Fabric applications. - -**Kind**: global class -**Properties** - -| Name | Type | Description | -| --- | --- | --- | -| ast | AST | Compiler's current AST. | -| entity | [Entity](#Entity) | Compiler's current [Entity](#Entity). | - - -* [Compiler](#Compiler) : [Actor](#Actor) - * [new Compiler(settings)](#new_Compiler_new) - * _instance_ - * [._getJavaScriptAST(input)](#Compiler+_getJavaScriptAST) ⇒ AST - * _static_ - * [._fromJavaScript(body)](#Compiler._fromJavaScript) ⇒ - - - -### new Compiler(settings) -Create a new Compiler. - -**Returns**: [Compiler](#Compiler) - Instance of the compiler. - -| Param | Type | Default | Description | -| --- | --- | --- | --- | -| settings | Object | {} | Configuration. | -| settings.body | Buffer | | Body of the input program to compile. | - - - -### compiler.\_getJavaScriptAST(input) ⇒ AST -Parse a [Buffer](Buffer) of JavaScript into an Abstract Syntax Tree ([AST](AST)). - -**Kind**: instance method of [Compiler](#Compiler) - -| Param | Type | Description | -| --- | --- | --- | -| input | Buffer | Input JavaScript to parse. | - - - -### Compiler.\_fromJavaScript(body) ⇒ -Creates a new Compiler instance from a JavaScript contract. - -**Kind**: static method of [Compiler](#Compiler) -**Returns**: Compiler - -| Param | Type | Description | -| --- | --- | --- | -| body | Buffer | Content of the JavaScript to evaluate. | - - - -## Consensus -Provides various network-specific rules. - -**Kind**: global class - - -### new Consensus([settings]) -Create an instance of a [Consensus](#Consensus) verifier. - - -| Param | Type | Description | -| --- | --- | --- | -| [settings] | Object | Configuration for the network. | -| [settings.network] | String | Name of the network. | -| [settings.provider] | String | Name of the source provider. | - - - -## Entity : Object -Live instance of an ARC in Fabric. - -**Kind**: global class - -* [Entity](#Entity) : Object - * [new Entity([data])](#new_Entity_new) - * [.toJSON()](#Entity+toJSON) ⇒ String - * [.toRaw()](#Entity+toRaw) ⇒ Buffer - * [._downsample([input])](#Entity+_downsample) - - - -### new Entity([data]) -Generic template for virtual objects. - -**Returns**: [Entity](#Entity) - Instance of the [Entity](#Entity). - -| Param | Type | Default | Description | -| --- | --- | --- | --- | -| [data] | Object | {} | Pass an object to use. | - - - -### entity.toJSON() ⇒ String -Produces a string of JSON, representing the entity. - -**Kind**: instance method of [Entity](#Entity) -**Returns**: String - JSON-encoded object. - - -### entity.toRaw() ⇒ Buffer -As a [Buffer](Buffer). - -**Kind**: instance method of [Entity](#Entity) -**Returns**: Buffer - Slice of memory. - - -### entity.\_downsample([input]) -Return a [Fabric](#Fabric)-labeled [Object](Object) for this [Entity](#Entity). - -**Kind**: instance method of [Entity](#Entity) - -| Param | Type | Description | -| --- | --- | --- | -| [input] | Mixed | Input to downsample. If not provided, current Entity will be used. | - - - -## Environment -Interact with the user's Environment. - -**Kind**: global class - -* [Environment](#Environment) - * [new Environment([settings])](#new_Environment_new) - * [.readVariable(name)](#Environment+readVariable) ⇒ String - * [.setWallet(wallet, force)](#Environment+setWallet) ⇒ [Environment](#Environment) - * [.start()](#Environment+start) ⇒ [Environment](#Environment) - - - -### new Environment([settings]) -Create an instance of [Environment](#Environment). - -**Returns**: [Environment](#Environment) - Instance of the Environment. - -| Param | Type | Description | -| --- | --- | --- | -| [settings] | Object | Settings for the Fabric environment. | - - - -### environment.readVariable(name) ⇒ String -Read a variable from the environment. - -**Kind**: instance method of [Environment](#Environment) -**Returns**: String - Value of the variable (or an empty string). - -| Param | Type | Description | -| --- | --- | --- | -| name | String | Variable name to read. | - - - -### environment.setWallet(wallet, force) ⇒ [Environment](#Environment) -Configure the Environment to use a Fabric [Wallet](#Wallet). - -**Kind**: instance method of [Environment](#Environment) -**Returns**: [Environment](#Environment) - The Fabric Environment. - -| Param | Type | Default | Description | -| --- | --- | --- | --- | -| wallet | [Wallet](#Wallet) | | Wallet to attach. | -| force | Boolean | false | Force existing wallets to be destroyed. | - - - -### environment.start() ⇒ [Environment](#Environment) -Start the Environment. - -**Kind**: instance method of [Environment](#Environment) -**Returns**: [Environment](#Environment) - The Fabric Environment. - - -## Fabric -Reliable decentralized infrastructure. - -**Kind**: global class -**Emits**: Fabric#event:thread, Fabric#event:step Emitted on a `compute` step. - -* [Fabric](#Fabric) - * [new Fabric(config)](#new_Fabric_new) - * [.register(service)](#Fabric+register) - * [.push(value)](#Fabric+push) ⇒ [Stack](#Stack) - * [.trust(source)](#Fabric+trust) ⇒ [Fabric](#Fabric) - * [.compute()](#Fabric+compute) ⇒ [Fabric](#Fabric) - - - -### new Fabric(config) -The [Fabric](#Fabric) type implements a peer-to-peer protocol for -establishing and settling of mutually-agreed upon proofs of -work. Contract execution takes place in the local node first, -then is optionally shared with the network. - -Utilizing - - -| Param | Type | Description | -| --- | --- | --- | -| config | [Vector](#Vector) | Initial configuration for the Fabric engine. This can be considered the "genesis" state for any contract using the system. If a chain of events is maintained over long periods of time, `state` can be considered "in contention", and it is demonstrated that the outstanding value of the contract remains to be settled. | - - - -### fabric.register(service) -Register an available [Service](#Service) using an ES6 [Class](Class). - -**Kind**: instance method of [Fabric](#Fabric) - -| Param | Type | Description | -| --- | --- | --- | -| service | Class | The ES6 [Class](Class). | - - - -### fabric.push(value) ⇒ [Stack](#Stack) -Push an instruction onto the stack. - -**Kind**: instance method of [Fabric](#Fabric) - -| Param | Type | -| --- | --- | -| value | Instruction | - - - -### fabric.trust(source) ⇒ [Fabric](#Fabric) -Blindly consume messages from a [Source](Source), relying on `this.chain` to -verify results. - -**Kind**: instance method of [Fabric](#Fabric) -**Returns**: [Fabric](#Fabric) - Returns itself. - -| Param | Type | Description | -| --- | --- | --- | -| source | EventEmitter | Any object which implements the `EventEmitter` pattern. | - - - -### fabric.compute() ⇒ [Fabric](#Fabric) -Process the current stack. - -**Kind**: instance method of [Fabric](#Fabric) -**Returns**: [Fabric](#Fabric) - Resulting instance of the stack. - - -## Federation -Create and manage sets of signers with the Federation class. - -**Kind**: global class - -* [Federation](#Federation) - * [new Federation([settings])](#new_Federation_new) - * [.start()](#Federation+start) ⇒ [Federation](#Federation) - - - -### new Federation([settings]) -Create an instance of a federation. - -**Returns**: [Federation](#Federation) - Instance of the federation. - -| Param | Type | Description | -| --- | --- | --- | -| [settings] | Object | Settings. | - - - -### federation.start() ⇒ [Federation](#Federation) -Start tracking state (i.e., ready to receive events). - -**Kind**: instance method of [Federation](#Federation) -**Returns**: [Federation](#Federation) - Instance of the Federation. - - -## Filesystem -Interact with a local filesystem. - -**Kind**: global class - -* [Filesystem](#Filesystem) - * [new Filesystem([settings])](#new_Filesystem_new) - * [.ls()](#Filesystem+ls) ⇒ Array - * [.readFile(name)](#Filesystem+readFile) ⇒ Buffer - * [.writeFile(name, content)](#Filesystem+writeFile) ⇒ Boolean - * [._loadFromDisk()](#Filesystem+_loadFromDisk) ⇒ Promise - * [.sync()](#Filesystem+sync) ⇒ [Filesystem](#Filesystem) - - - -### new Filesystem([settings]) -Synchronize an [Actor](#Actor) with a local filesystem. - -**Returns**: [Filesystem](#Filesystem) - Instance of the Fabric filesystem. - -| Param | Type | Description | -| --- | --- | --- | -| [settings] | Object | Configuration for the Fabric filesystem. | -| [settings.path] | Object | Path of the local filesystem. | - - - -### filesystem.ls() ⇒ Array -Get the list of files. - -**Kind**: instance method of [Filesystem](#Filesystem) -**Returns**: Array - List of files. - - -### filesystem.readFile(name) ⇒ Buffer -Read a file by name. - -**Kind**: instance method of [Filesystem](#Filesystem) -**Returns**: Buffer - Contents of the file. - -| Param | Type | Description | -| --- | --- | --- | -| name | String | Name of the file to read. | - - - -### filesystem.writeFile(name, content) ⇒ Boolean -Write a file by name. - -**Kind**: instance method of [Filesystem](#Filesystem) -**Returns**: Boolean - `true` if the write succeeded, `false` if it did not. - -| Param | Type | Description | -| --- | --- | --- | -| name | String | Name of the file to write. | -| content | Buffer | Content of the file. | - - - -### filesystem.\_loadFromDisk() ⇒ Promise -Load Filesystem state from disk. - -**Kind**: instance method of [Filesystem](#Filesystem) -**Returns**: Promise - Resolves with Filesystem instance. - - -### filesystem.sync() ⇒ [Filesystem](#Filesystem) -Syncronize state from the local filesystem. - -**Kind**: instance method of [Filesystem](#Filesystem) -**Returns**: [Filesystem](#Filesystem) - Instance of the Fabric filesystem. - - -## Hash256 -Simple interaction with 256-bit spaces. - -**Kind**: global class - -* [Hash256](#Hash256) - * [new Hash256(settings)](#new_Hash256_new) - * [.digest(input)](#Hash256.digest) ⇒ String - * [.reverse()](#Hash256.reverse) - - - -### new Hash256(settings) -Create an instance of a `Hash256` object by calling `new Hash256()`, -where `settings` can be provided to supply a particular input object. - -If the `settings` is not a string, `input` must be provided. - - -| Param | Type | Description | -| --- | --- | --- | -| settings | Object | | -| settings.input | String | Input string to map as 256-bit hash. | - - - -### Hash256.digest(input) ⇒ String -Produce a SHA256 digest of some input data. - -**Kind**: static method of [Hash256](#Hash256) -**Returns**: String - `SHA256(input)` as a hexadecimal string. - -| Param | Type | Description | -| --- | --- | --- | -| input | String \| Buffer | Content to digest. | - - - -### Hash256.reverse() -Reverses the bytes of the digest. - -**Kind**: static method of [Hash256](#Hash256) - - -## HKDF -Provides an HMAC-based Extract-and-Expand Key Derivation Function (HKDF), compatible with -RFC 5869. Defaults to 32 byte output, matching Bitcoin's implementaton. - -**Kind**: global class - -* [HKDF](#HKDF) - * [new HKDF(settings)](#new_HKDF_new) - * [.derive([info], [size])](#HKDF+derive) - - - -### new HKDF(settings) -Create an HKDF instance. - - -| Param | Type | Default | Description | -| --- | --- | --- | --- | -| settings | Object | | List of settings. | -| settings.initial | String | | Input keying material. | -| [settings.algorithm] | String | sha256 | Name of the hashing algorithm to use. | -| [settings.salt] | String | | Salt value (a non-secret random value). | - - - -### hkdF.derive([info], [size]) -Derive a new output. - -**Kind**: instance method of [HKDF](#HKDF) - -| Param | Type | Default | Description | -| --- | --- | --- | --- | -| [info] | Buffer | | Context and application specific information. | -| [size] | Number | 32 | Length of output. | - - - -## Identity -Manage a network identity. - -**Kind**: global class - -* [Identity](#Identity) - * [new Identity([settings])](#new_Identity_new) - * [.sign(data)](#Identity+sign) ⇒ Signature - * [.toString()](#Identity+toString) ⇒ String - - - -### new Identity([settings]) -Create an instance of an Identity. - -**Returns**: [Identity](#Identity) - Instance of the identity. - -| Param | Type | Default | Description | -| --- | --- | --- | --- | -| [settings] | Object | | Settings for the Identity. | -| [settings.seed] | String | | BIP 39 seed phrase. | -| [settings.xprv] | String | | Serialized BIP 32 master private key. | -| [settings.xpub] | String | | Serialized BIP 32 master public key. | -| [settings.account] | Number | 0 | BIP 44 account index. | -| [settings.index] | Number | 0 | BIP 44 key index. | - - - -### identity.sign(data) ⇒ Signature -Sign a buffer of data using BIP 340: https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki - -**Kind**: instance method of [Identity](#Identity) -**Returns**: Signature - Resulting signature (64 bytes). - -| Param | Type | Description | -| --- | --- | --- | -| data | Buffer | Buffer of data to sign. | - - - -### identity.toString() ⇒ String -Retrieve the bech32m-encoded identity. - -**Kind**: instance method of [Identity](#Identity) -**Returns**: String - Public identity. - - -## Interface ⇐ EventEmitter -Interfaces compile abstract contract code into [Chain](#Chain)-executable transactions, or "chaincode". For example, the "Bitcoin" interface might compile a Swap contract into Script, preparing a valid Bitcoin transaction for broadcast which executes the swap contract. - -**Kind**: global class -**Extends**: EventEmitter -**Properties** - -| Name | Type | Description | -| --- | --- | --- | -| status | String | Human-friendly value representing the Interface's current [State](#State). | - - -* [Interface](#Interface) ⇐ EventEmitter - * [new Interface(settings)](#new_Interface_new) - * [.log(...inputs)](#Interface+log) - * [.now()](#Interface+now) ⇒ Number - * [.start()](#Interface+start) - * [.stop()](#Interface+stop) - * [.cycle(val)](#Interface+cycle) - - - -### new Interface(settings) -Define an [Interface](#Interface) by creating an instance of this class. - -**Returns**: [Interface](#Interface) - Instance of the [Interface](#Interface). - -| Param | Type | Description | -| --- | --- | --- | -| settings | Object | Configuration values. | - - - -### interface.log(...inputs) -Log some output to the console. - -**Kind**: instance method of [Interface](#Interface) - -| Param | Type | Description | -| --- | --- | --- | -| ...inputs | any | Components of the message to long. Can be a single {@link} String, many [String](String) objects, or anything else. | - - - -### interface.now() ⇒ Number -Returns current timestamp. - -**Kind**: instance method of [Interface](#Interface) - - -### interface.start() -Start the [Interface](#Interface). - -**Kind**: instance method of [Interface](#Interface) - +**Kind**: global class -### interface.stop() -Stop the Interface. +* [Redis](#Redis) + * [new Redis([settings])](#new_Redis_new) + * [.start()](#Redis+start) ⇒ [Redis](#Redis) + * [.stop()](#Redis+stop) ⇒ [Redis](#Redis) -**Kind**: instance method of [Interface](#Interface) - + -### interface.cycle(val) -Ticks the clock with a named [Cycle](Cycle). +### new Redis([settings]) +Creates an instance of a Redis subscriber. -**Kind**: instance method of [Interface](#Interface) +**Returns**: [Redis](#Redis) - Instance of the Redis service, ready to run `start()` | Param | Type | Description | | --- | --- | --- | -| val | String | Name of cycle to scribe. | - - - -## Key -Represents a cryptographic key. +| [settings] | Object | Settings for the Redis connection. | +| [settings.host] | String | Host for the Redis server. | +| [settings.port] | Number | Remote Redis service port. | -**Kind**: global class - + -### new Key([settings]) -Create an instance of a Fabric Key, either restoring from some known -values or from prior knowledge. For instance, you can call `new Key()` -to create a fresh keypair, or `new Key({ public: 'deadbeef...' })` to -create it from a known public key. +### redis.start() ⇒ [Redis](#Redis) +Opens the connection and subscribes to the requested channels. +**Kind**: instance method of [Redis](#Redis) +**Returns**: [Redis](#Redis) - Instance of the service. + -| Param | Type | Default | Description | -| --- | --- | --- | --- | -| [settings] | Object | | Initialization for the key. | -| [settings.network] | String | | Network string. | -| [settings.seed] | String | | Mnemonic seed for initializing the key. | -| [settings.public] | String | | Public key in hex. | -| [settings.private] | String | | Private key in hex. | -| [settings.purpose] | String | 44 | Constrains derivations to this space. | +### redis.stop() ⇒ [Redis](#Redis) +Closes the connection to the Redis server. - +**Kind**: instance method of [Redis](#Redis) +**Returns**: [Redis](#Redis) - Instance of the service. + -## Keystore -Provides an encrypted datastore for generic object storage. +## ZMQ +Connect and subscribe to ZeroMQ publishers. **Kind**: global class -* [Keystore](#Keystore) - * [new Keystore([configuration])](#new_Keystore_new) - * [._setState(state)](#Keystore+_setState) ⇒ [Actor](#Actor) +* [ZMQ](#ZMQ) + * [new ZMQ([settings])](#new_ZMQ_new) + * [.start()](#ZMQ+start) ⇒ [ZMQ](#ZMQ) + * [.stop()](#ZMQ+stop) ⇒ [ZMQ](#ZMQ) + + - +### new ZMQ([settings]) +Creates an instance of a ZeroMQ subscriber. -### new Keystore([configuration]) -Create an instance of the Store. +**Returns**: [ZMQ](#ZMQ) - Instance of the ZMQ service, ready to run `start()` -**Returns**: [Keystore](#Keystore) - Instance of the store. +| Param | Type | Description | +| --- | --- | --- | +| [settings] | Object | Settings for the ZMQ connection. | +| [settings.host] | String | Host for the ZMQ publisher. | +| [settings.port] | Number | Remote ZeroMQ service port. | -| Param | Type | Default | Description | -| --- | --- | --- | --- | -| [configuration] | FabricStoreConfiguration | | Settings to use. | -| [configuration.name] | String | "DefaultStore" | Name of the Store. | + - +### zmQ.start() ⇒ [ZMQ](#ZMQ) +Opens the connection and subscribes to the requested channels. -### keystore.\_setState(state) ⇒ [Actor](#Actor) -Saves an Object to the store. +**Kind**: instance method of [ZMQ](#ZMQ) +**Returns**: [ZMQ](#ZMQ) - Instance of the service. + -**Kind**: instance method of [Keystore](#Keystore) -**Returns**: [Actor](#Actor) - The local instance of the provided State's [Actor](#Actor). +### zmQ.stop() ⇒ [ZMQ](#ZMQ) +Closes the connection to the ZMQ publisher. -| Param | Type | Description | -| --- | --- | --- | -| state | Object | State to store. | +**Kind**: instance method of [ZMQ](#ZMQ) +**Returns**: [ZMQ](#ZMQ) - Instance of the service. + - +## ~~HTTPServer~~ +***Deprecated*** -## Ledger ⇐ [Scribe](#Scribe) -An ordered stack of pages. +Deprecated 2021-10-16. **Kind**: global class -**Extends**: [Scribe](#Scribe) -**Properties** + -| Name | Type | Description | -| --- | --- | --- | -| memory | Buffer | The ledger's memory (4096 bytes). | -| stack | [Stack](#Stack) | The ledger's stack. | -| tip | Mixed | The most recent page in the ledger. | +## ~~Scribe~~ +***Deprecated*** +Deprecated 2021-11-06. -* [Ledger](#Ledger) ⇐ [Scribe](#Scribe) - * [.append(item)](#Ledger+append) ⇒ Promise +**Kind**: global class + +* ~~[Scribe](#Scribe)~~ * [.now()](#Scribe+now) ⇒ Number * [.trust(source)](#Scribe+trust) ⇒ [Scribe](#Scribe) * [.inherits(scribe)](#Scribe+inherits) ⇒ [Scribe](#Scribe) - * [.toHTML()](#State+toHTML) - * [.toString()](#State+toString) ⇒ String - * [.serialize([input])](#State+serialize) ⇒ Buffer - * [.deserialize(input)](#State+deserialize) ⇒ [State](#State) - * [.fork()](#State+fork) ⇒ [State](#State) - * [.get(path)](#State+get) ⇒ Mixed - * [.set(path)](#State+set) ⇒ Mixed - * [.commit()](#State+commit) - * [.render()](#State+render) ⇒ String - - - -### ledger.append(item) ⇒ Promise -Attempts to append a [Page](Page) to the ledger. - -**Kind**: instance method of [Ledger](#Ledger) -**Returns**: Promise - Resolves after the change has been committed. - -| Param | Type | Description | -| --- | --- | --- | -| item | Mixed | Item to store. | -### ledger.now() ⇒ Number +### scribe.now() ⇒ Number Retrives the current timestamp, in milliseconds. -**Kind**: instance method of [Ledger](#Ledger) -**Overrides**: [now](#Scribe+now) +**Kind**: instance method of [Scribe](#Scribe) **Returns**: Number - [Number](Number) representation of the millisecond [Integer](Integer) value. -### ledger.trust(source) ⇒ [Scribe](#Scribe) +### scribe.trust(source) ⇒ [Scribe](#Scribe) Blindly bind event handlers to the [Source](Source). -**Kind**: instance method of [Ledger](#Ledger) -**Overrides**: [trust](#Scribe+trust) +**Kind**: instance method of [Scribe](#Scribe) **Returns**: [Scribe](#Scribe) - Instance of the [Scribe](#Scribe). | Param | Type | Description | @@ -1838,175 +734,84 @@ Blindly bind event handlers to the [Source](Source). -### ledger.inherits(scribe) ⇒ [Scribe](#Scribe) +### scribe.inherits(scribe) ⇒ [Scribe](#Scribe) Use an existing Scribe instance as a parent. -**Kind**: instance method of [Ledger](#Ledger) -**Overrides**: [inherits](#Scribe+inherits) +**Kind**: instance method of [Scribe](#Scribe) **Returns**: [Scribe](#Scribe) - The configured instance of the Scribe. | Param | Type | Description | | --- | --- | --- | | scribe | [Scribe](#Scribe) | Instance of Scribe to use as parent. | - - -### ledger.toHTML() -Converts the State to an HTML document. - -**Kind**: instance method of [Ledger](#Ledger) -**Overrides**: [toHTML](#State+toHTML) - - -### ledger.toString() ⇒ String -Unmarshall an existing state to an instance of a [Blob](Blob). - -**Kind**: instance method of [Ledger](#Ledger) -**Overrides**: [toString](#State+toString) -**Returns**: String - Serialized [Blob](Blob). - - -### ledger.serialize([input]) ⇒ Buffer -Convert to [Buffer](Buffer). - -**Kind**: instance method of [Ledger](#Ledger) -**Overrides**: [serialize](#State+serialize) -**Returns**: Buffer - [Store](#Store)-able blob. - -| Param | Type | Description | -| --- | --- | --- | -| [input] | Mixed | Input to serialize. | - - - -### ledger.deserialize(input) ⇒ [State](#State) -Take a hex-encoded input and convert to a [State](#State) object. - -**Kind**: instance method of [Ledger](#Ledger) -**Overrides**: [deserialize](#State+deserialize) -**Returns**: [State](#State) - [description] - -| Param | Type | Description | -| --- | --- | --- | -| input | String | [description] | - - - -### ledger.fork() ⇒ [State](#State) -Creates a new child [State](#State), with `@parent` set to -the current [State](#State) by immutable identifier. - -**Kind**: instance method of [Ledger](#Ledger) -**Overrides**: [fork](#State+fork) - - -### ledger.get(path) ⇒ Mixed -Retrieve a key from the [State](#State). - -**Kind**: instance method of [Ledger](#Ledger) -**Overrides**: [get](#State+get) - -| Param | Type | Description | -| --- | --- | --- | -| path | [Path](#Path) | Key to retrieve. | - - - -### ledger.set(path) ⇒ Mixed -Set a key in the [State](#State) to a particular value. - -**Kind**: instance method of [Ledger](#Ledger) -**Overrides**: [set](#State+set) - -| Param | Type | Description | -| --- | --- | --- | -| path | [Path](#Path) | Key to retrieve. | - - - -### ledger.commit() -Increment the vector clock, broadcast all changes as a transaction. - -**Kind**: instance method of [Ledger](#Ledger) -**Overrides**: [commit](#State+commit) - - -### ledger.render() ⇒ String -Compose a JSON string for network consumption. + -**Kind**: instance method of [Ledger](#Ledger) -**Overrides**: [render](#State+render) -**Returns**: String - JSON-encoded [String](String). - +## ~~Stash~~ +***Deprecated*** -## Logger ⇐ [Actor](#Actor) -A basic logger that writes logs to the local file system +Deprecated 2021-11-06. **Kind**: global class -**Extends**: [Actor](#Actor) - -* [Logger](#Logger) ⇐ [Actor](#Actor) - * [.path](#Logger+path) ⇒ String - * [.log(msg)](#Logger+log) ⇒ Boolean - * [.start()](#Logger+start) ⇒ Promise - * [.stop()](#Logger+stop) ⇒ Promise - * [.adopt(changes)](#Actor+adopt) ⇒ [Actor](#Actor) - * [.commit()](#Actor+commit) ⇒ String - * [.export()](#Actor+export) ⇒ Object - * [.get(path)](#Actor+get) ⇒ Object - * [.set(path, value)](#Actor+set) ⇒ Object - * [.toBuffer()](#Actor+toBuffer) ⇒ Buffer - * [.toGenericMessage()](#Actor+toGenericMessage) ⇒ Object - * [.toObject()](#Actor+toObject) ⇒ Object - * [.pause()](#Actor+pause) ⇒ [Actor](#Actor) - * [.serialize()](#Actor+serialize) ⇒ String - * [.sign()](#Actor+sign) ⇒ [Actor](#Actor) - * [.unpause()](#Actor+unpause) ⇒ [Actor](#Actor) - * [.value([format])](#Actor+value) ⇒ Object - * [._readObject(input)](#Actor+_readObject) ⇒ Object - - - -### logger.path ⇒ String -Returns the path to the log file - -**Kind**: instance property of [Logger](#Logger) - + -### logger.log(msg) ⇒ Boolean -Writes the specified log to the log file +## Actor +Generic Fabric Actor. -**Kind**: instance method of [Logger](#Logger) -**Returns**: Boolean - true, if msg was successfully written; false otherwise +**Kind**: global class +**Emits**: event:message Fabric {@link Message} objects. +**Access**: protected +**Properties** -| Param | Type | Description | +| Name | Type | Description | | --- | --- | --- | -| msg | String \| Object | The message to log | +| id | String | Unique identifier for this Actor (id === SHA256(preimage)). | +| preimage | String | Input hash for the `id` property (preimage === SHA256(ActorState)). | - -### logger.start() ⇒ Promise -Starts the logger +* [Actor](#Actor) + * [new Actor([actor])](#new_Actor_new) + * _instance_ + * [.adopt(changes)](#Actor+adopt) ⇒ [Actor](#Actor) + * [.commit()](#Actor+commit) ⇒ String + * [.export()](#Actor+export) ⇒ Object + * [.get(path)](#Actor+get) ⇒ Object + * [.set(path, value)](#Actor+set) ⇒ Object + * [.toBuffer()](#Actor+toBuffer) ⇒ Buffer + * [.toGenericMessage()](#Actor+toGenericMessage) ⇒ Object + * [.toObject()](#Actor+toObject) ⇒ Object + * [.pause()](#Actor+pause) ⇒ [Actor](#Actor) + * [.serialize()](#Actor+serialize) ⇒ String + * [.sign()](#Actor+sign) ⇒ [Actor](#Actor) + * [.unpause()](#Actor+unpause) ⇒ [Actor](#Actor) + * [.value([format])](#Actor+value) ⇒ Object + * [._readObject(input)](#Actor+_readObject) ⇒ Object + * _static_ + * [.fromAny(input)](#Actor.fromAny) ⇒ [Actor](#Actor) + * [.randomBytes([count])](#Actor.randomBytes) ⇒ Buffer -This method creates the required directories for writing the log file. + -**Kind**: instance method of [Logger](#Logger) - +### new Actor([actor]) +Creates an [Actor](#Actor), which emits messages for other +Actors to subscribe to. You can supply certain parameters +for the actor, including key material [!!!] — be mindful of +what you share with others! -### logger.stop() ⇒ Promise -Stops the logger +**Returns**: [Actor](#Actor) - Instance of the Actor. Call [sign](#Actor+sign) to emit a [Signature](Signature). -This method closes the log file and returns after it has been closed. Any -errors on close would cause the return promise to be rejected. +| Param | Type | Description | +| --- | --- | --- | +| [actor] | Object | Object to use as the actor. | +| [actor.seed] | String | BIP24 Mnemonic to use as a seed phrase. | +| [actor.public] | Buffer | Public key. | +| [actor.private] | Buffer | Private key. | -**Kind**: instance method of [Logger](#Logger) -### logger.adopt(changes) ⇒ [Actor](#Actor) +### actor.adopt(changes) ⇒ [Actor](#Actor) Explicitly adopt a set of [JSONPatch](JSONPatch)-encoded changes. -**Kind**: instance method of [Logger](#Logger) -**Overrides**: [adopt](#Actor+adopt) +**Kind**: instance method of [Actor](#Actor) **Returns**: [Actor](#Actor) - Instance of the Actor. | Param | Type | Description | @@ -2015,27 +820,24 @@ Explicitly adopt a set of [JSONPatch](JSONPatch)-encoded changes. -### logger.commit() ⇒ String +### actor.commit() ⇒ String Resolve the current state to a commitment. -**Kind**: instance method of [Logger](#Logger) -**Overrides**: [commit](#Actor+commit) +**Kind**: instance method of [Actor](#Actor) **Returns**: String - 32-byte ID -### logger.export() ⇒ Object +### actor.export() ⇒ Object Export the Actor's state to a standard [Object](Object). -**Kind**: instance method of [Logger](#Logger) -**Overrides**: [export](#Actor+export) +**Kind**: instance method of [Actor](#Actor) **Returns**: Object - Standard object. -### logger.get(path) ⇒ Object +### actor.get(path) ⇒ Object Retrieve a value from the Actor's state by [JSONPointer](JSONPointer) path. -**Kind**: instance method of [Logger](#Logger) -**Overrides**: [get](#Actor+get) +**Kind**: instance method of [Actor](#Actor) **Returns**: Object - Value of the path in the Actor's state. | Param | Type | Description | @@ -2044,11 +846,10 @@ Retrieve a value from the Actor's state by [JSONPointer](JSONPointer) path. -### logger.set(path, value) ⇒ Object +### actor.set(path, value) ⇒ Object Set a value in the Actor's state by [JSONPointer](JSONPointer) path. -**Kind**: instance method of [Logger](#Logger) -**Overrides**: [set](#Actor+set) +**Kind**: instance method of [Actor](#Actor) **Returns**: Object - Value of the path in the Actor's state. | Param | Type | Description | @@ -2058,63 +859,63 @@ Set a value in the Actor's state by [JSONPointer](JSONPointer) path. -### logger.toBuffer() ⇒ Buffer +### actor.toBuffer() ⇒ Buffer Casts the Actor to a normalized Buffer. -**Kind**: instance method of [Logger](#Logger) -**Overrides**: [toBuffer](#Actor+toBuffer) +**Kind**: instance method of [Actor](#Actor) -### logger.toGenericMessage() ⇒ Object -Casts the Actor to a generic message. +### actor.toGenericMessage() ⇒ Object +Casts the Actor to a generic message, used to uniquely identify the Actor's state. +Fields: +- `type`: 'FabricActorState' +- `object`: state -**Kind**: instance method of [Logger](#Logger) -**Overrides**: [toGenericMessage](#Actor+toGenericMessage) +**Kind**: instance method of [Actor](#Actor) **Returns**: Object - Generic message object. +**See** + +- [https://en.wikipedia.org/wiki/Merkle_tree](https://en.wikipedia.org/wiki/Merkle_tree) +- [https://dev.fabric.pub/messages](https://dev.fabric.pub/messages) + -### logger.toObject() ⇒ Object +### actor.toObject() ⇒ Object Returns the Actor's current state as an [Object](Object). -**Kind**: instance method of [Logger](#Logger) -**Overrides**: [toObject](#Actor+toObject) +**Kind**: instance method of [Actor](#Actor) -### logger.pause() ⇒ [Actor](#Actor) +### actor.pause() ⇒ [Actor](#Actor) Toggles `status` property to paused. -**Kind**: instance method of [Logger](#Logger) -**Overrides**: [pause](#Actor+pause) +**Kind**: instance method of [Actor](#Actor) **Returns**: [Actor](#Actor) - Instance of the Actor. -### logger.serialize() ⇒ String +### actor.serialize() ⇒ String Serialize the Actor's current state into a JSON-formatted string. -**Kind**: instance method of [Logger](#Logger) -**Overrides**: [serialize](#Actor+serialize) +**Kind**: instance method of [Actor](#Actor) -### logger.sign() ⇒ [Actor](#Actor) +### actor.sign() ⇒ [Actor](#Actor) Signs the Actor. -**Kind**: instance method of [Logger](#Logger) -**Overrides**: [sign](#Actor+sign) +**Kind**: instance method of [Actor](#Actor) -### logger.unpause() ⇒ [Actor](#Actor) +### actor.unpause() ⇒ [Actor](#Actor) Toggles `status` property to unpaused. -**Kind**: instance method of [Logger](#Logger) -**Overrides**: [unpause](#Actor+unpause) +**Kind**: instance method of [Actor](#Actor) **Returns**: [Actor](#Actor) - Instance of the Actor. -### logger.value([format]) ⇒ Object +### actor.value([format]) ⇒ Object Get the inner value of the Actor with an optional cast type. -**Kind**: instance method of [Logger](#Logger) -**Overrides**: [value](#Actor+value) +**Kind**: instance method of [Actor](#Actor) **Returns**: Object - Inner value of the Actor as an [Object](Object), or cast to the requested `format`. | Param | Type | Default | Description | @@ -2123,1211 +924,1036 @@ Get the inner value of the Actor with an optional cast type. -### logger.\_readObject(input) ⇒ Object +### actor.\_readObject(input) ⇒ Object Parse an Object into a corresponding Fabric state. -**Kind**: instance method of [Logger](#Logger) -**Overrides**: [\_readObject](#Actor+_readObject) +**Kind**: instance method of [Actor](#Actor) **Returns**: Object - Fabric state. | Param | Type | Description | | --- | --- | --- | | input | Object | Object to read as input. | - - -## Machine -General-purpose state machine with [Vector](#Vector)-based instructions. - -**Kind**: global class - -* [Machine](#Machine) - * [new Machine(settings)](#new_Machine_new) - * [.sip([n])](#Machine+sip) ⇒ Number - * [.slurp([n])](#Machine+slurp) ⇒ Number - * [.compute(input)](#Machine+compute) ⇒ [Machine](#Machine) - - - -### new Machine(settings) -Create a Machine. - - -| Param | Type | Description | -| --- | --- | --- | -| settings | Object | Run-time configuration. | - - - -### machine.sip([n]) ⇒ Number -Get `n` bits of deterministic random data. - -**Kind**: instance method of [Machine](#Machine) -**Returns**: Number - Random bits from [Generator](Generator). - -| Param | Type | Default | Description | -| --- | --- | --- | --- | -| [n] | Number | 128 | Number of bits to retrieve. | - - - -### machine.slurp([n]) ⇒ Number -Get `n` bytes of deterministic random data. - -**Kind**: instance method of [Machine](#Machine) -**Returns**: Number - Random bytes from [Generator](Generator). - -| Param | Type | Default | Description | -| --- | --- | --- | --- | -| [n] | Number | 32 | Number of bytes to retrieve. | - - - -### machine.compute(input) ⇒ [Machine](#Machine) -Computes the next "step" for our current Vector. Analagous to `sum`. -The top item on the stack is always the memory held at current position, -so counts should always begin with 0. - -**Kind**: instance method of [Machine](#Machine) -**Returns**: [Machine](#Machine) - Instance of the resulting machine. - -| Param | Type | Description | -| --- | --- | --- | -| input | Object | Value to pass as input. | - - - -## Mempool -Stores a list of [Transaction](Transaction) elements. - -**Kind**: global class -**Emits**: event:{Message} confirmed Emitted when the Mempool has dropped a transaction. - - -### new Mempool(settings) -Creates an instance of a [Mempool](#Mempool) [Service](#Service). - - -| Param | Type | Description | -| --- | --- | --- | -| settings | Object | Map of settings to utilize. | - - - -## Message : Object -The [Message](#Message) type defines the Application Messaging Protocol, or AMP. -Each [Actor](#Actor) in the network receives and broadcasts messages, -selectively disclosing new routes to peers which may have open circuits. - -**Kind**: global class - -* [Message](#Message) : Object - * [new Message(message)](#new_Message_new) - * [.asRaw()](#Message+asRaw) ⇒ Buffer - - - -### new Message(message) -The `Message` type is standardized in [Fabric](#Fabric) as a [Array](Array), which can be added to any other vector to compute a resulting state. - -**Returns**: [Message](#Message) - Instance of the message. - -| Param | Type | Description | -| --- | --- | --- | -| message | Object | Message vector. Will be serialized by [Array#_serialize](Array#_serialize). | - - - -### message.asRaw() ⇒ Buffer -Returns a [Buffer](Buffer) of the complete message. - -**Kind**: instance method of [Message](#Message) -**Returns**: Buffer - Buffer of the encoded [Message](#Message). - - -## Node -Full definition of a Fabric node. - -**Kind**: global class - -* [Node](#Node) - * [new Node(settings)](#new_Node_new) - * [.trust(source, settings)](#Node+trust) - - - -### new Node(settings) -Manage a Fabric service. - -**Returns**: [Node](#Node) - Instance of the managed service. - -| Param | Type | Description | -| --- | --- | --- | -| settings | Object | Configuration for the node. | - - + -### node.trust(source, settings) -Explicitly trusts an [EventEmitter](EventEmitter). +### Actor.fromAny(input) ⇒ [Actor](#Actor) +Create an [Actor](#Actor) from a variety of formats. -**Kind**: instance method of [Node](#Node) +**Kind**: static method of [Actor](#Actor) +**Returns**: [Actor](#Actor) - Instance of the [Actor](#Actor). | Param | Type | Description | | --- | --- | --- | -| source | EventEmitter | Actor to listen to. | -| settings | Object \| String | Label for the trusted messages, or a configuration object. | - - - -## Oracle ⇐ [Store](#Store) -An Oracle manages one or more collections, using a mempool for -transitive state. - -**Kind**: global class -**Extends**: [Store](#Store) - -* [Oracle](#Oracle) ⇐ [Store](#Store) - * [new Oracle(initial)](#new_Oracle_new) - * [.broadcast(msg)](#Oracle+broadcast) ⇒ Boolean - * [._REGISTER(obj)](#Store+_REGISTER) ⇒ [Vector](#Vector) - * [._POST(key, value)](#Store+_POST) ⇒ Promise - * [.get(key)](#Store+get) ⇒ Promise - * [.set(key, value)](#Store+set) - * [.trust(source)](#Store+trust) ⇒ [Store](#Store) - * [.del(key)](#Store+del) - * [.flush()](#Store+flush) - * [.start()](#Store+start) ⇒ Promise +| input | Object | Target [Object](Object) to create. | - + -### new Oracle(initial) -Trusted point-of-reference for external services. +### Actor.randomBytes([count]) ⇒ Buffer +Get a number of random bytes from the runtime environment. +**Kind**: static method of [Actor](#Actor) +**Returns**: Buffer - The random bytes. -| Param | Type | Description | -| --- | --- | --- | -| initial | Object | Initialization vector. | +| Param | Type | Default | Description | +| --- | --- | --- | --- | +| [count] | Number | 32 | Number of random bytes to retrieve. | - + -### oracle.broadcast(msg) ⇒ Boolean -Core messaging function for interacting with this object in system-time. +## Chain +Chain. -**Kind**: instance method of [Oracle](#Oracle) -**Returns**: Boolean - Returns `true` on success, `false` on failure. +**Kind**: global class +**Properties** -| Param | Type | Description | +| Name | Type | Description | | --- | --- | --- | -| msg | [Message](#Message) | Instance of a [module:Message](module:Message) object, validated then transmitted verbatim. | +| name | String | Current name. | +| indices | Map | | +| storage | Storage | | - + -### oracle.\_REGISTER(obj) ⇒ [Vector](#Vector) -Registers an [Actor](#Actor). Necessary to store in a collection. +### new Chain(genesis) +Holds an immutable chain of events. -**Kind**: instance method of [Oracle](#Oracle) -**Overrides**: [\_REGISTER](#Store+_REGISTER) -**Returns**: [Vector](#Vector) - Returned from `storage.set` | Param | Type | Description | | --- | --- | --- | -| obj | Object | Instance of the object to store. | +| genesis | [Vector](#Vector) | Initial state for the chain of events. | - + -### oracle.\_POST(key, value) ⇒ Promise -Insert something into a collection. +## Channel +The [Channel](#Channel) is a encrypted connection with a member of your +[Peer](#Peer) group, with some amount of $BTC bonded and paid for each +correctly-validated message. -**Kind**: instance method of [Oracle](#Oracle) -**Overrides**: [\_POST](#Store+_POST) -**Returns**: Promise - Resolves on success with a String pointer. +Channels in Fabric are powerful tools for application development, as they +can empower users with income opportunities in exchange for delivering +service to the network. -| Param | Type | Description | -| --- | --- | --- | -| key | String | Path to add data to. | -| value | Mixed | Object to store. | +**Kind**: global class - +* [Channel](#Channel) + * [new Channel([settings])](#new_Channel_new) + * [.add(amount)](#Channel+add) + * [.fund(input)](#Channel+fund) + * [.open(channel)](#Channel+open) -### oracle.get(key) ⇒ Promise -Barebones getter. + + +### new Channel([settings]) +Creates a channel between two peers. +of many transactions over time, to be settled on-chain later. -**Kind**: instance method of [Oracle](#Oracle) -**Overrides**: [get](#Store+get) -**Returns**: Promise - Resolves on complete. `null` if not found. | Param | Type | Description | | --- | --- | --- | -| key | String | Name of data to retrieve. | +| [settings] | Object | Configuration for the channel. | - + -### oracle.set(key, value) -Set a `key` to a specific `value`. +### channel.add(amount) +Add an amount to the channel's balance. -**Kind**: instance method of [Oracle](#Oracle) -**Overrides**: [set](#Store+set) +**Kind**: instance method of [Channel](#Channel) | Param | Type | Description | | --- | --- | --- | -| key | String | Address of the information. | -| value | Mixed | Content to store at `key`. | +| amount | Number | Amount value to add to current outgoing balance. | - + -### oracle.trust(source) ⇒ [Store](#Store) -Implicitly trust an [Event](Event) source. +### channel.fund(input) +Fund the channel. -**Kind**: instance method of [Oracle](#Oracle) -**Overrides**: [trust](#Store+trust) -**Returns**: [Store](#Store) - Resulting instance of [Store](#Store) with new trust. +**Kind**: instance method of [Channel](#Channel) | Param | Type | Description | | --- | --- | --- | -| source | EventEmitter | Event-emitting source. | +| input | Mixed | Instance of a [Transaction](Transaction). | - + -### oracle.del(key) -Remove a [Value](#Value) by [Path](#Path). +### channel.open(channel) +Opens a [Channel](#Channel) with a [Peer](#Peer). -**Kind**: instance method of [Oracle](#Oracle) -**Overrides**: [del](#Store+del) +**Kind**: instance method of [Channel](#Channel) | Param | Type | Description | | --- | --- | --- | -| key | [Path](#Path) | Key to remove. | - - - -### oracle.flush() -Wipes the storage. +| channel | Object | Channel settings. | -**Kind**: instance method of [Oracle](#Oracle) -**Overrides**: [flush](#Store+flush) - + -### oracle.start() ⇒ Promise -Start running the process. +## Circuit +The [Circuit](#Circuit) is the mechanism through which [Fabric](#Fabric) +operates, a computable directed graph describing a network of +[Peer](#Peer) components and their interactions (side effects). +See also [Swarm](#Swarm) for deeper inspection of [Machine](#Machine) +mechanics. -**Kind**: instance method of [Oracle](#Oracle) -**Overrides**: [start](#Store+start) -**Returns**: Promise - Resolves on complete. - +**Kind**: global class + -## Path -A [Path](#Path) is a [Fabric](#Fabric)-native link to a [Document](Document) -within the network. +## CLI +Provides a Command Line Interface (CLI) for interacting with +the Fabric network using a terminal emulator. **Kind**: global class -* [Path](#Path) - * [new Path(input)](#new_Path_new) - * [.isValid()](#Path+isValid) ⇒ Boolean +* [CLI](#CLI) + * [new CLI([settings])](#new_CLI_new) + * [.start()](#CLI+start) + * [.stop()](#CLI+stop) + * [._handleGrantCommand(params)](#CLI+_handleGrantCommand) - + -### new Path(input) -Create a new [Path](#Path). +### new CLI([settings]) +Create a terminal-based interface for a [User](User). | Param | Type | Description | | --- | --- | --- | -| input | String \| Object | Named path. | +| [settings] | Object | Configuration values. | +| [settings.currencies] | Array | List of currencies to support. | - + -### path.isValid() ⇒ Boolean -**Kind**: instance method of [Path](#Path) -**Returns**: Boolean - Whether or not the Path is valid. - +### clI.start() +Starts (and renders) the CLI. -## Peer -An in-memory representation of a node in our network. +**Kind**: instance method of [CLI](#CLI) + -**Kind**: global class +### clI.stop() +Disconnect all interfaces and exit the process. -* [Peer](#Peer) - * [new Peer([config])](#new_Peer_new) - * ~~[.address](#Peer+address)~~ - * [.start()](#Peer+start) - * [.stop()](#Peer+stop) - * [.listen()](#Peer+listen) ⇒ [Peer](#Peer) +**Kind**: instance method of [CLI](#CLI) + - +### clI.\_handleGrantCommand(params) +Creates a token for the target signer with a provided role and some optional data. -### new Peer([config]) -Create an instance of [Peer](#Peer). +**Kind**: instance method of [CLI](#CLI) + +| Param | Type | Description | +| --- | --- | --- | +| params | Array | Parameters array. | + -| Param | Type | Default | Description | -| --- | --- | --- | --- | -| [config] | Object | | Initialization Vector for this peer. | -| [config.listen] | Boolean | | Whether or not to listen for connections. | -| [config.upnp] | Boolean | | Whether or not to use UPNP for automatic configuration. | -| [config.port] | Number | 7777 | Port to use for P2P connections. | -| [config.peers] | Array | [] | List of initial peers. | +## Collection +The [Collection](#Collection) type maintains an ordered list of [State](#State) items. - +**Kind**: global class +**Properties** -### ~~peer.address~~ -***Deprecated*** +| Name | Type | Description | +| --- | --- | --- | +| @entity | Object | Fabric-bound entity object. | -**Kind**: instance property of [Peer](#Peer) - -### peer.start() -Start the Peer. +* [Collection](#Collection) + * [new Collection([configuration])](#new_Collection_new) + * [.asMerkleTree()](#Collection+asMerkleTree) ⇒ MerkleTree + * [._setKey(name)](#Collection+_setKey) + * [.getByID(id)](#Collection+getByID) + * [.getLatest()](#Collection+getLatest) + * [.findByField(name, value)](#Collection+findByField) + * [.findByName(name)](#Collection+findByName) + * [.findBySymbol(symbol)](#Collection+findBySymbol) + * [._patchTarget(path, patches)](#Collection+_patchTarget) + * [.push(data)](#Collection+push) ⇒ Number + * [.get(path)](#Collection+get) ⇒ Mixed + * [.set(path)](#Collection+set) ⇒ Mixed + * ~~[.list()](#Collection+list) ⇒ Array~~ + * [.toTypedArray()](#Collection+toTypedArray) + * [.map()](#Collection+map) ⇒ Array + * [.create(entity)](#Collection+create) ⇒ Promise + * [.import(state, commit)](#Collection+import) -**Kind**: instance method of [Peer](#Peer) - + -### peer.stop() -Stop the peer. +### new Collection([configuration]) +Create a list of [Entity](Entity)-like objects for later retrieval. -**Kind**: instance method of [Peer](#Peer) - +**Returns**: [Collection](#Collection) - Configured instance of the the [Collection](#Collection). -### peer.listen() ⇒ [Peer](#Peer) -Start listening for connections. +| Param | Type | Default | Description | +| --- | --- | --- | --- | +| [configuration] | Object | {} | Configuration object. | -**Kind**: instance method of [Peer](#Peer) -**Returns**: [Peer](#Peer) - Chainable method. -**Emits**: Peer#event:ready - + -## Reader -Read from a byte stream, seeking valid Fabric messages. +### collection.asMerkleTree() ⇒ MerkleTree +Current elements of the collection as a [MerkleTree](MerkleTree). -**Kind**: global class - +**Kind**: instance method of [Collection](#Collection) + -### new Reader(settings) -Create an instance of a [Reader](#Reader), which can listen to a byte stream -for valid Fabric messages. +### collection.\_setKey(name) +Sets the `key` property of collection settings. +**Kind**: instance method of [Collection](#Collection) | Param | Type | Description | | --- | --- | --- | -| settings | Object | Settings for the stream. | - - - -## Remote : [Remote](#Remote) -Interact with a remote [Resource](#Resource). This is currently the only -HTTP-related code that should remain in @fabric/core — all else must -be moved to @fabric/http before final release! - -**Kind**: global class -**Properties** - -| Name | Type | -| --- | --- | -| config | Object | -| secure | Boolean | - - -* [Remote](#Remote) : [Remote](#Remote) - * [new Remote(target)](#new_Remote_new) - * [.enumerate()](#Remote+enumerate) ⇒ Configuration - * [.request(type, path, [params])](#Remote+request) ⇒ FabricHTTPResult - * [._PUT(path, body)](#Remote+_PUT) ⇒ FabricHTTPResult \| String - * [._GET(path, params)](#Remote+_GET) ⇒ FabricHTTPResult \| String - * [._POST(path, params)](#Remote+_POST) ⇒ FabricHTTPResult \| String - * [._OPTIONS(path, params)](#Remote+_OPTIONS) ⇒ Object - * [._PATCH(path, body)](#Remote+_PATCH) ⇒ Object - * [._DELETE(path, params)](#Remote+_DELETE) ⇒ Object +| name | String | Value to set the `key` setting to. | - + -### new Remote(target) -An in-memory representation of a node in our network. +### collection.getByID(id) +Retrieve an element from the collection by ID. +**Kind**: instance method of [Collection](#Collection) | Param | Type | Description | | --- | --- | --- | -| target | Object | Target object. | -| target.host | String | Named host, e.g. "localhost". | -| target.secure | String | Require TLS session. | +| id | String | Document identifier. | - + -### remote.enumerate() ⇒ Configuration -Enumerate the available Resources on the remote host. +### collection.getLatest() +Retrieve the most recent element in the collection. -**Kind**: instance method of [Remote](#Remote) -**Returns**: Configuration - An object with enumerable key/value pairs for the Application Resource Contract. - +**Kind**: instance method of [Collection](#Collection) + -### remote.request(type, path, [params]) ⇒ FabricHTTPResult -Make an HTTP request to the configured authority. +### collection.findByField(name, value) +Find a document by specific field. -**Kind**: instance method of [Remote](#Remote) +**Kind**: instance method of [Collection](#Collection) | Param | Type | Description | | --- | --- | --- | -| type | String | One of `GET`, `PUT`, `POST`, `DELETE`, or `OPTIONS`. | -| path | String | The path to request from the authority. | -| [params] | Object | Options. | +| name | String | Name of field to search. | +| value | String | Value to match. | - + -### remote.\_PUT(path, body) ⇒ FabricHTTPResult \| String -HTTP PUT against the configured Authority. +### collection.findByName(name) +Find a document by the "name" field. -**Kind**: instance method of [Remote](#Remote) -**Returns**: FabricHTTPResult \| String - Result of request. +**Kind**: instance method of [Collection](#Collection) | Param | Type | Description | | --- | --- | --- | -| path | String | HTTP Path to request. | -| body | Object | Map of parameters to supply. | +| name | String | Name to search for. | - + -### remote.\_GET(path, params) ⇒ FabricHTTPResult \| String -HTTP GET against the configured Authority. +### collection.findBySymbol(symbol) +Find a document by the "symbol" field. -**Kind**: instance method of [Remote](#Remote) -**Returns**: FabricHTTPResult \| String - Result of request. +**Kind**: instance method of [Collection](#Collection) | Param | Type | Description | | --- | --- | --- | -| path | String | HTTP Path to request. | -| params | Object | Map of parameters to supply. | +| symbol | String | Value to search for. | - + -### remote.\_POST(path, params) ⇒ FabricHTTPResult \| String -HTTP POST against the configured Authority. +### collection.\_patchTarget(path, patches) +Modify a target document using an array of atomic updates. -**Kind**: instance method of [Remote](#Remote) -**Returns**: FabricHTTPResult \| String - Result of request. +**Kind**: instance method of [Collection](#Collection) | Param | Type | Description | | --- | --- | --- | -| path | String | HTTP Path to request. | -| params | Object | Map of parameters to supply. | +| path | String | Path to the document to modify. | +| patches | Array | List of operations to apply. | - + -### remote.\_OPTIONS(path, params) ⇒ Object -HTTP OPTIONS on the configured Authority. +### collection.push(data) ⇒ Number +Adds an [Entity](Entity) to the [Collection](#Collection). -**Kind**: instance method of [Remote](#Remote) -**Returns**: Object - - Full description of remote resource. +**Kind**: instance method of [Collection](#Collection) +**Returns**: Number - Length of the collection. | Param | Type | Description | | --- | --- | --- | -| path | String | HTTP Path to request. | -| params | Object | Map of parameters to supply. | +| data | Mixed | [Entity](Entity) to add. | - + -### remote.\_PATCH(path, body) ⇒ Object -HTTP PATCH on the configured Authority. +### collection.get(path) ⇒ Mixed +Retrieve a key from the [State](#State). -**Kind**: instance method of [Remote](#Remote) -**Returns**: Object - - Full description of remote resource. +**Kind**: instance method of [Collection](#Collection) | Param | Type | Description | | --- | --- | --- | -| path | String | HTTP Path to request. | -| body | Object | Map of parameters to supply. | +| path | Path | Key to retrieve. | - + -### remote.\_DELETE(path, params) ⇒ Object -HTTP DELETE on the configured Authority. +### collection.set(path) ⇒ Mixed +Set a key in the [State](#State) to a particular value. -**Kind**: instance method of [Remote](#Remote) -**Returns**: Object - - Full description of remote resource. +**Kind**: instance method of [Collection](#Collection) | Param | Type | Description | | --- | --- | --- | -| path | String | HTTP Path to request. | -| params | Object | Map of parameters to supply. | +| path | Path | Key to retrieve. | - + -## Resource -Generic interface for collections of digital objects. +### ~~collection.list() ⇒ Array~~ +***Deprecated*** -**Kind**: global class +Generate a list of elements in the collection. -* [Resource](#Resource) - * [new Resource(definition)](#new_Resource_new) - * [.create(obj)](#Resource+create) ⇒ [Vector](#Vector) - * [.update(id, update)](#Resource+update) ⇒ [Vector](#Vector) +**Kind**: instance method of [Collection](#Collection) + - +### collection.toTypedArray() +Provides the [Collection](#Collection) as an [Array](Array) of typed +elements. The type of these elments are defined by the collection's +type, supplied in the constructor. -### new Resource(definition) +**Kind**: instance method of [Collection](#Collection) + -| Param | Type | Description | -| --- | --- | --- | -| definition | Object | Initial parameters | +### collection.map() ⇒ Array +Generate a hashtable of elements in the collection. - +**Kind**: instance method of [Collection](#Collection) + -### resource.create(obj) ⇒ [Vector](#Vector) -Create an instance of the Resource's type. +### collection.create(entity) ⇒ Promise +Create an instance of an [Entity](Entity). -**Kind**: instance method of [Resource](#Resource) -**Returns**: [Vector](#Vector) - Resulting Vector with deterministic identifier. +**Kind**: instance method of [Collection](#Collection) +**Returns**: Promise - Resolves with instantiated [Entity](Entity). | Param | Type | Description | | --- | --- | --- | -| obj | Object | Map of the instance's properties and values. | +| entity | Object | Object with properties. | - + -### resource.update(id, update) ⇒ [Vector](#Vector) -Modify an existing instance of a Resource by its unique identifier. Produces a new instance. +### collection.import(state, commit) +Loads [State](#State) into memory. -**Kind**: instance method of [Resource](#Resource) -**Returns**: [Vector](#Vector) - Resulting Vector instance with updated identifier. +**Kind**: instance method of [Collection](#Collection) +**Emits**: event:message Will emit one {@link Snapshot} message. | Param | Type | Description | | --- | --- | --- | -| id | String | Unique ID to update. | -| update | Object | Map of change to make (keys -> values). | +| state | [State](#State) | State to import. | +| commit | Boolean | Whether or not to commit the result. | - + -## Router ⇐ [Scribe](#Scribe) -Process incoming messages. +## Environment +Interact with the user's Environment. **Kind**: global class -**Extends**: [Scribe](#Scribe) -* [Router](#Router) ⇐ [Scribe](#Scribe) - * [new Router(map)](#new_Router_new) - * [.route(msg)](#Router+route) ⇒ Array - * [.use(plugin, name)](#Router+use) ⇒ [Router](#Router) - * [.now()](#Scribe+now) ⇒ Number - * [.trust(source)](#Scribe+trust) ⇒ [Scribe](#Scribe) - * [.inherits(scribe)](#Scribe+inherits) ⇒ [Scribe](#Scribe) - * [.toHTML()](#State+toHTML) - * [.toString()](#State+toString) ⇒ String - * [.serialize([input])](#State+serialize) ⇒ Buffer - * [.deserialize(input)](#State+deserialize) ⇒ [State](#State) - * [.fork()](#State+fork) ⇒ [State](#State) - * [.get(path)](#State+get) ⇒ Mixed - * [.set(path)](#State+set) ⇒ Mixed - * [.commit()](#State+commit) - * [.render()](#State+render) ⇒ String +* [Environment](#Environment) + * [new Environment([settings])](#new_Environment_new) + * [.readVariable(name)](#Environment+readVariable) ⇒ String + * [.setWallet(wallet, force)](#Environment+setWallet) ⇒ [Environment](#Environment) + * [.start()](#Environment+start) ⇒ [Environment](#Environment) - + -### new Router(map) -Maintains a list of triggers ("commands") and their behaviors. +### new Environment([settings]) +Create an instance of [Environment](#Environment). +**Returns**: [Environment](#Environment) - Instance of the Environment. | Param | Type | Description | | --- | --- | --- | -| map | Object | Map of command names => behaviors. | +| [settings] | Object | Settings for the Fabric environment. | - + -### router.route(msg) ⇒ Array -Assembles a list of possible responses to the incoming request. +### environment.readVariable(name) ⇒ String +Read a variable from the environment. -**Kind**: instance method of [Router](#Router) -**Returns**: Array - List of outputs generated from the input string. +**Kind**: instance method of [Environment](#Environment) +**Returns**: String - Value of the variable (or an empty string). | Param | Type | Description | | --- | --- | --- | -| msg | String | Input message to route. | +| name | String | Variable name to read. | - + -### router.use(plugin, name) ⇒ [Router](#Router) -Attaches a new handler to the router. +### environment.setWallet(wallet, force) ⇒ [Environment](#Environment) +Configure the Environment to use a Fabric [Wallet](#Wallet). -**Kind**: instance method of [Router](#Router) -**Returns**: [Router](#Router) - Configured instance of the router. +**Kind**: instance method of [Environment](#Environment) +**Returns**: [Environment](#Environment) - The Fabric Environment. -| Param | Type | Description | -| --- | --- | --- | -| plugin | Plugin | Instance of the plugin. | -| name | Plugin.name | Name of the plugin. | +| Param | Type | Default | Description | +| --- | --- | --- | --- | +| wallet | [Wallet](#Wallet) | | Wallet to attach. | +| force | Boolean | false | Force existing wallets to be destroyed. | - + -### router.now() ⇒ Number -Retrives the current timestamp, in milliseconds. +### environment.start() ⇒ [Environment](#Environment) +Start the Environment. -**Kind**: instance method of [Router](#Router) -**Overrides**: [now](#Scribe+now) -**Returns**: Number - [Number](Number) representation of the millisecond [Integer](Integer) value. - +**Kind**: instance method of [Environment](#Environment) +**Returns**: [Environment](#Environment) - The Fabric Environment. + -### router.trust(source) ⇒ [Scribe](#Scribe) -Blindly bind event handlers to the [Source](Source). +## Fabric +Reliable decentralized infrastructure. + +**Kind**: global class +**Emits**: Fabric#event:thread, Fabric#event:step Emitted on a `compute` step. + +* [Fabric](#Fabric) + * [new Fabric(config)](#new_Fabric_new) + * [.register(service)](#Fabric+register) + * [.push(value)](#Fabric+push) ⇒ [Stack](#Stack) + * [.trust(source)](#Fabric+trust) ⇒ [Fabric](#Fabric) + * [.compute()](#Fabric+compute) ⇒ [Fabric](#Fabric) + + + +### new Fabric(config) +The [Fabric](#Fabric) type implements a peer-to-peer protocol for +establishing and settling of mutually-agreed upon proofs of +work. Contract execution takes place in the local node first, +then is optionally shared with the network. + +Utilizing -**Kind**: instance method of [Router](#Router) -**Overrides**: [trust](#Scribe+trust) -**Returns**: [Scribe](#Scribe) - Instance of the [Scribe](#Scribe). | Param | Type | Description | | --- | --- | --- | -| source | Source | Event stream. | +| config | [Vector](#Vector) | Initial configuration for the Fabric engine. This can be considered the "genesis" state for any contract using the system. If a chain of events is maintained over long periods of time, `state` can be considered "in contention", and it is demonstrated that the outstanding value of the contract remains to be settled. | - + -### router.inherits(scribe) ⇒ [Scribe](#Scribe) -Use an existing Scribe instance as a parent. +### fabric.register(service) +Register an available [Service](#Service) using an ES6 [Class](Class). -**Kind**: instance method of [Router](#Router) -**Overrides**: [inherits](#Scribe+inherits) -**Returns**: [Scribe](#Scribe) - The configured instance of the Scribe. +**Kind**: instance method of [Fabric](#Fabric) | Param | Type | Description | | --- | --- | --- | -| scribe | [Scribe](#Scribe) | Instance of Scribe to use as parent. | +| service | Class | The ES6 [Class](Class). | - + -### router.toHTML() -Converts the State to an HTML document. +### fabric.push(value) ⇒ [Stack](#Stack) +Push an instruction onto the stack. -**Kind**: instance method of [Router](#Router) -**Overrides**: [toHTML](#State+toHTML) - +**Kind**: instance method of [Fabric](#Fabric) -### router.toString() ⇒ String -Unmarshall an existing state to an instance of a [Blob](Blob). +| Param | Type | +| --- | --- | +| value | Instruction | -**Kind**: instance method of [Router](#Router) -**Overrides**: [toString](#State+toString) -**Returns**: String - Serialized [Blob](Blob). - + + +### fabric.trust(source) ⇒ [Fabric](#Fabric) +Blindly consume messages from a [Source](Source), relying on `this.chain` to +verify results. + +**Kind**: instance method of [Fabric](#Fabric) +**Returns**: [Fabric](#Fabric) - Returns itself. + +| Param | Type | Description | +| --- | --- | --- | +| source | EventEmitter | Any object which implements the `EventEmitter` pattern. | + + + +### fabric.compute() ⇒ [Fabric](#Fabric) +Process the current stack. + +**Kind**: instance method of [Fabric](#Fabric) +**Returns**: [Fabric](#Fabric) - Resulting instance of the stack. + + +## Federation +Create and manage sets of signers with the Federation class. + +**Kind**: global class + +* [Federation](#Federation) + * [new Federation([settings])](#new_Federation_new) + * [.start()](#Federation+start) ⇒ [Federation](#Federation) + * [.sign(msg, [pubkey])](#Federation+sign) ⇒ Buffer + * [.verify(msg, sig)](#Federation+verify) ⇒ Boolean + * [.createMultiSignature(msg)](#Federation+createMultiSignature) ⇒ Object + * [.verifyMultiSignature(multiSig, threshold)](#Federation+verifyMultiSignature) ⇒ Boolean + + -### router.serialize([input]) ⇒ Buffer -Convert to [Buffer](Buffer). +### new Federation([settings]) +Create an instance of a federation. -**Kind**: instance method of [Router](#Router) -**Overrides**: [serialize](#State+serialize) -**Returns**: Buffer - [Store](#Store)-able blob. +**Returns**: [Federation](#Federation) - Instance of the federation. | Param | Type | Description | | --- | --- | --- | -| [input] | Mixed | Input to serialize. | +| [settings] | Object | Settings. | - + -### router.deserialize(input) ⇒ [State](#State) -Take a hex-encoded input and convert to a [State](#State) object. +### federation.start() ⇒ [Federation](#Federation) +Start tracking state (i.e., ready to receive events). -**Kind**: instance method of [Router](#Router) -**Overrides**: [deserialize](#State+deserialize) -**Returns**: [State](#State) - [description] +**Kind**: instance method of [Federation](#Federation) +**Returns**: [Federation](#Federation) - Instance of the Federation. + -| Param | Type | Description | -| --- | --- | --- | -| input | String | [description] | +### federation.sign(msg, [pubkey]) ⇒ Buffer +Signs a message using the federation's key. - +**Kind**: instance method of [Federation](#Federation) +**Returns**: Buffer - The signature -### router.fork() ⇒ [State](#State) -Creates a new child [State](#State), with `@parent` set to -the current [State](#State) by immutable identifier. +| Param | Type | Description | +| --- | --- | --- | +| msg | Buffer \| String \| [Message](#Message) | The message to sign | +| [pubkey] | String | Optional public key of the member to sign with | -**Kind**: instance method of [Router](#Router) -**Overrides**: [fork](#State+fork) - + -### router.get(path) ⇒ Mixed -Retrieve a key from the [State](#State). +### federation.verify(msg, sig) ⇒ Boolean +Verifies a signature against a message. -**Kind**: instance method of [Router](#Router) -**Overrides**: [get](#State+get) +**Kind**: instance method of [Federation](#Federation) +**Returns**: Boolean - Whether the signature is valid | Param | Type | Description | | --- | --- | --- | -| path | [Path](#Path) | Key to retrieve. | +| msg | Buffer \| String \| [Message](#Message) | The message that was signed | +| sig | Buffer | The signature to verify | - + -### router.set(path) ⇒ Mixed -Set a key in the [State](#State) to a particular value. +### federation.createMultiSignature(msg) ⇒ Object +Creates a multi-signature for a message. -**Kind**: instance method of [Router](#Router) -**Overrides**: [set](#State+set) +**Kind**: instance method of [Federation](#Federation) +**Returns**: Object - The multi-signature object containing signatures from all validators | Param | Type | Description | | --- | --- | --- | -| path | [Path](#Path) | Key to retrieve. | +| msg | Buffer \| String \| [Message](#Message) | The message to sign | - + -### router.commit() -Increment the vector clock, broadcast all changes as a transaction. +### federation.verifyMultiSignature(multiSig, threshold) ⇒ Boolean +Verifies a multi-signature against a message. -**Kind**: instance method of [Router](#Router) -**Overrides**: [commit](#State+commit) - +**Kind**: instance method of [Federation](#Federation) +**Returns**: Boolean - Whether the multi-signature is valid -### router.render() ⇒ String -Compose a JSON string for network consumption. +| Param | Type | Default | Description | +| --- | --- | --- | --- | +| multiSig | Object | | The multi-signature object | +| threshold | Number | 1 | Number of valid signatures required | -**Kind**: instance method of [Router](#Router) -**Overrides**: [render](#State+render) -**Returns**: String - JSON-encoded [String](String). - + -## Scribe ⇐ [State](#State) -Simple tag-based recordkeeper. +## Filesystem +Interact with a local filesystem. **Kind**: global class -**Extends**: [State](#State) -**Properties** - -| Name | Type | Description | -| --- | --- | --- | -| config | Object | Current configuration. | - -* [Scribe](#Scribe) ⇐ [State](#State) - * [new Scribe(config)](#new_Scribe_new) - * [.now()](#Scribe+now) ⇒ Number - * [.trust(source)](#Scribe+trust) ⇒ [Scribe](#Scribe) - * [.inherits(scribe)](#Scribe+inherits) ⇒ [Scribe](#Scribe) - * [.toHTML()](#State+toHTML) - * [.toString()](#State+toString) ⇒ String - * [.serialize([input])](#State+serialize) ⇒ Buffer - * [.deserialize(input)](#State+deserialize) ⇒ [State](#State) - * [.fork()](#State+fork) ⇒ [State](#State) - * [.get(path)](#State+get) ⇒ Mixed - * [.set(path)](#State+set) ⇒ Mixed - * [.commit()](#State+commit) - * [.render()](#State+render) ⇒ String +* [Filesystem](#Filesystem) + * [new Filesystem([settings])](#new_Filesystem_new) + * [.ls()](#Filesystem+ls) ⇒ Array + * [.readFile(name)](#Filesystem+readFile) ⇒ Buffer + * [.writeFile(name, content)](#Filesystem+writeFile) ⇒ Boolean + * [._loadFromDisk()](#Filesystem+_loadFromDisk) ⇒ Promise + * [.sync()](#Filesystem+sync) ⇒ [Filesystem](#Filesystem) - + -### new Scribe(config) -The "Scribe" is a simple tag-based recordkeeper. +### new Filesystem([settings]) +Synchronize an [Actor](#Actor) with a local filesystem. +**Returns**: [Filesystem](#Filesystem) - Instance of the Fabric filesystem. | Param | Type | Description | | --- | --- | --- | -| config | Object | General configuration object. | -| config.verbose | Boolean | Should the Scribe be noisy? | +| [settings] | Object | Configuration for the Fabric filesystem. | +| [settings.path] | Object | Path of the local filesystem. | +| [settings.key] | Object | Signing key for the filesystem. | - + -### scribe.now() ⇒ Number -Retrives the current timestamp, in milliseconds. +### filesystem.ls() ⇒ Array +Get the list of files. -**Kind**: instance method of [Scribe](#Scribe) -**Returns**: Number - [Number](Number) representation of the millisecond [Integer](Integer) value. - +**Kind**: instance method of [Filesystem](#Filesystem) +**Returns**: Array - List of files. + -### scribe.trust(source) ⇒ [Scribe](#Scribe) -Blindly bind event handlers to the [Source](Source). +### filesystem.readFile(name) ⇒ Buffer +Read a file by name. -**Kind**: instance method of [Scribe](#Scribe) -**Returns**: [Scribe](#Scribe) - Instance of the [Scribe](#Scribe). +**Kind**: instance method of [Filesystem](#Filesystem) +**Returns**: Buffer - Contents of the file. | Param | Type | Description | | --- | --- | --- | -| source | Source | Event stream. | +| name | String | Name of the file to read. | - + -### scribe.inherits(scribe) ⇒ [Scribe](#Scribe) -Use an existing Scribe instance as a parent. +### filesystem.writeFile(name, content) ⇒ Boolean +Write a file by name. -**Kind**: instance method of [Scribe](#Scribe) -**Returns**: [Scribe](#Scribe) - The configured instance of the Scribe. +**Kind**: instance method of [Filesystem](#Filesystem) +**Returns**: Boolean - `true` if the write succeeded, `false` if it did not. | Param | Type | Description | | --- | --- | --- | -| scribe | [Scribe](#Scribe) | Instance of Scribe to use as parent. | +| name | String | Name of the file to write. | +| content | Buffer | Content of the file. | - + -### scribe.toHTML() -Converts the State to an HTML document. +### filesystem.\_loadFromDisk() ⇒ Promise +Load Filesystem state from disk. -**Kind**: instance method of [Scribe](#Scribe) -**Overrides**: [toHTML](#State+toHTML) - +**Kind**: instance method of [Filesystem](#Filesystem) +**Returns**: Promise - Resolves with Filesystem instance. + -### scribe.toString() ⇒ String -Unmarshall an existing state to an instance of a [Blob](Blob). +### filesystem.sync() ⇒ [Filesystem](#Filesystem) +Syncronize state from the local filesystem. -**Kind**: instance method of [Scribe](#Scribe) -**Overrides**: [toString](#State+toString) -**Returns**: String - Serialized [Blob](Blob). - +**Kind**: instance method of [Filesystem](#Filesystem) +**Returns**: [Filesystem](#Filesystem) - Instance of the Fabric filesystem. + -### scribe.serialize([input]) ⇒ Buffer -Convert to [Buffer](Buffer). +## Hash256 +Simple interaction with 256-bit spaces. -**Kind**: instance method of [Scribe](#Scribe) -**Overrides**: [serialize](#State+serialize) -**Returns**: Buffer - [Store](#Store)-able blob. +**Kind**: global class -| Param | Type | Description | -| --- | --- | --- | -| [input] | Mixed | Input to serialize. | +* [Hash256](#Hash256) + * [new Hash256(settings)](#new_Hash256_new) + * [.digest(input)](#Hash256.digest) ⇒ String + * [.reverse()](#Hash256.reverse) - + -### scribe.deserialize(input) ⇒ [State](#State) -Take a hex-encoded input and convert to a [State](#State) object. +### new Hash256(settings) +Create an instance of a `Hash256` object by calling `new Hash256()`, +where `settings` can be provided to supply a particular input object. + +If the `settings` is not a string, `input` must be provided. -**Kind**: instance method of [Scribe](#Scribe) -**Overrides**: [deserialize](#State+deserialize) -**Returns**: [State](#State) - [description] | Param | Type | Description | | --- | --- | --- | -| input | String | [description] | - - - -### scribe.fork() ⇒ [State](#State) -Creates a new child [State](#State), with `@parent` set to -the current [State](#State) by immutable identifier. +| settings | Object | | +| settings.input | String | Input string to map as 256-bit hash. | -**Kind**: instance method of [Scribe](#Scribe) -**Overrides**: [fork](#State+fork) - + -### scribe.get(path) ⇒ Mixed -Retrieve a key from the [State](#State). +### Hash256.digest(input) ⇒ String +Produce a SHA256 digest of some input data. -**Kind**: instance method of [Scribe](#Scribe) -**Overrides**: [get](#State+get) +**Kind**: static method of [Hash256](#Hash256) +**Returns**: String - `SHA256(input)` as a hexadecimal string. | Param | Type | Description | | --- | --- | --- | -| path | [Path](#Path) | Key to retrieve. | +| input | String \| Buffer | Content to digest. | - + -### scribe.set(path) ⇒ Mixed -Set a key in the [State](#State) to a particular value. +### Hash256.reverse() +Reverses the bytes of the digest. -**Kind**: instance method of [Scribe](#Scribe) -**Overrides**: [set](#State+set) +**Kind**: static method of [Hash256](#Hash256) + -| Param | Type | Description | -| --- | --- | --- | -| path | [Path](#Path) | Key to retrieve. | +## HKDF +Provides an HMAC-based Extract-and-Expand Key Derivation Function (HKDF), compatible with +RFC 5869. Defaults to 32 byte output, matching Bitcoin's implementaton. - +**Kind**: global class -### scribe.commit() -Increment the vector clock, broadcast all changes as a transaction. +* [HKDF](#HKDF) + * [new HKDF(settings)](#new_HKDF_new) + * [.derive([info], [size])](#HKDF+derive) -**Kind**: instance method of [Scribe](#Scribe) -**Overrides**: [commit](#State+commit) - + -### scribe.render() ⇒ String -Compose a JSON string for network consumption. +### new HKDF(settings) +Create an HKDF instance. -**Kind**: instance method of [Scribe](#Scribe) -**Overrides**: [render](#State+render) -**Returns**: String - JSON-encoded [String](String). - -## Script -**Kind**: global class - +| Param | Type | Default | Description | +| --- | --- | --- | --- | +| settings | Object | | List of settings. | +| settings.initial | String | | Input keying material. | +| [settings.algorithm] | String | sha256 | Name of the hashing algorithm to use. | +| [settings.salt] | String | | Salt value (a non-secret random value). | -### new Script(config) -Compose a [Script](#Script) for inclusion within a [Contract](Contract). + -**Returns**: [Script](#Script) - Instance of the [Script](#Script), ready for use. +### hkdF.derive([info], [size]) +Derive a new output. -| Param | Type | Description | -| --- | --- | --- | -| config | Mixed | Configuration options for the script. | +**Kind**: instance method of [HKDF](#HKDF) - +| Param | Type | Default | Description | +| --- | --- | --- | --- | +| [info] | Buffer | | Context and application specific information. | +| [size] | Number | 32 | Length of output. | -## Service -The "Service" is a simple model for processing messages in a distributed -system. [Service](#Service) instances are public interfaces for outside systems, -and typically advertise their presence to the network. + -To implement a Service, you will typically need to implement all methods from -this prototype. In general, `connect` and `send` are the highest-priority -jobs, and by default the `fabric` property will serve as an I/O stream using -familiar semantics. +## Identity +Manage a network identity. **Kind**: global class -**Access**: protected -**Properties** -| Name | Description | -| --- | --- | -| map | The "map" is a hashtable of "key" => "value" pairs. | +* [Identity](#Identity) + * [new Identity([settings])](#new_Identity_new) + * [.toString()](#Identity+toString) ⇒ String + -* [Service](#Service) - * [new Service(settings)](#new_Service_new) - * [.init()](#Service+init) - * [.tick()](#Service+tick) ⇒ Number - * [.beat()](#Service+beat) ⇒ [Service](#Service) - * [.get(path)](#Service+get) ⇒ Mixed - * [.set(path)](#Service+set) ⇒ Mixed - * [.trust(source)](#Service+trust) ⇒ [Service](#Service) - * [.handler(message)](#Service+handler) ⇒ [Service](#Service) - * [.lock([duration])](#Service+lock) ⇒ Boolean - * [.route(msg)](#Service+route) ⇒ Promise - * [.start()](#Service+start) - * [._GET(path)](#Service+_GET) ⇒ Promise - * [._PUT(path, value, [commit])](#Service+_PUT) ⇒ Promise - * [.connect(notify)](#Service+connect) ⇒ Promise - * [.send(channel, message)](#Service+send) ⇒ [Service](#Service) - * [._registerActor(actor)](#Service+_registerActor) ⇒ Promise - * [._send(message)](#Service+_send) +### new Identity([settings]) +Create an instance of an Identity. - +**Returns**: [Identity](#Identity) - Instance of the identity. -### new Service(settings) -Create an instance of a Service. +| Param | Type | Default | Description | +| --- | --- | --- | --- | +| [settings] | Object | | Settings for the Identity. | +| [settings.seed] | String | | BIP 39 seed phrase. | +| [settings.xprv] | String | | Serialized BIP 32 master private key. | +| [settings.xpub] | String | | Serialized BIP 32 master public key. | +| [settings.account] | Number | 0 | BIP 44 account index. | +| [settings.index] | Number | 0 | BIP 44 key index. | +| [settings.passphrase] | String | | Passphrase for the key. | + -| Param | Type | Default | Description | -| --- | --- | --- | --- | -| settings | Object | | Configuration for this service. | -| [settings.networking] | Boolean | true | Whether or not to connect to the network. | -| [settings.@data] | Object | | Internal data to assign. | +### identity.toString() ⇒ String +Retrieve the bech32m-encoded identity. - +**Kind**: instance method of [Identity](#Identity) +**Returns**: String - Public identity. + -### service.init() -Called by Web Components. -TODO: move to @fabric/http/types/spa +## Interface ⇐ EventEmitter +Interfaces compile abstract contract code into [Chain](#Chain)-executable transactions, or "chaincode". For example, the "Bitcoin" interface might compile a Swap contract into Script, preparing a valid Bitcoin transaction for broadcast which executes the swap contract. -**Kind**: instance method of [Service](#Service) - +**Kind**: global class +**Extends**: EventEmitter +**Properties** -### service.tick() ⇒ Number -Move forward one clock cycle. +| Name | Type | Description | +| --- | --- | --- | +| status | String | Human-friendly value representing the Interface's current [State](#State). | -**Kind**: instance method of [Service](#Service) - -### service.beat() ⇒ [Service](#Service) -Compute latest state. +* [Interface](#Interface) ⇐ EventEmitter + * [new Interface(settings)](#new_Interface_new) + * [.log(...inputs)](#Interface+log) + * [.now()](#Interface+now) ⇒ Number + * [.start()](#Interface+start) + * [.stop()](#Interface+stop) + * [.cycle(val)](#Interface+cycle) -**Kind**: instance method of [Service](#Service) -**Emits**: Message#event:beat - + -### service.get(path) ⇒ Mixed -Retrieve a key from the [State](#State). +### new Interface(settings) +Define an [Interface](#Interface) by creating an instance of this class. -**Kind**: instance method of [Service](#Service) +**Returns**: [Interface](#Interface) - Instance of the [Interface](#Interface). | Param | Type | Description | | --- | --- | --- | -| path | [Path](#Path) | Key to retrieve. | +| settings | Object | Configuration values. | - + -### service.set(path) ⇒ Mixed -Set a key in the [State](#State) to a particular value. +### interface.log(...inputs) +Log some output to the console. -**Kind**: instance method of [Service](#Service) +**Kind**: instance method of [Interface](#Interface) | Param | Type | Description | | --- | --- | --- | -| path | [Path](#Path) | Key to retrieve. | +| ...inputs | any | Components of the message to long. Can be a single {@link} String, many [String](String) objects, or anything else. | - + -### service.trust(source) ⇒ [Service](#Service) -Explicitly trust all events from a known source. +### interface.now() ⇒ Number +Returns current timestamp. -**Kind**: instance method of [Service](#Service) -**Returns**: [Service](#Service) - Instance of Service after binding events. +**Kind**: instance method of [Interface](#Interface) + -| Param | Type | Description | -| --- | --- | --- | -| source | EventEmitter | Emitter of events. | +### interface.start() +Start the [Interface](#Interface). - +**Kind**: instance method of [Interface](#Interface) + -### service.handler(message) ⇒ [Service](#Service) -Default route handler for an incoming message. Follows the Activity -Streams 2.0 spec: https://www.w3.org/TR/activitystreams-core/ +### interface.stop() +Stop the Interface. -**Kind**: instance method of [Service](#Service) -**Returns**: [Service](#Service) - Chainable method. +**Kind**: instance method of [Interface](#Interface) + + +### interface.cycle(val) +Ticks the clock with a named [Cycle](Cycle). + +**Kind**: instance method of [Interface](#Interface) | Param | Type | Description | | --- | --- | --- | -| message | Activity | Message object. | +| val | String | Name of cycle to scribe. | - + -### service.lock([duration]) ⇒ Boolean -Attempt to acquire a lock for `duration` seconds. +## Key +Represents a cryptographic key. + +**Kind**: global class + +* [Key](#Key) + * [new Key([settings])](#new_Key_new) + * [.verify(msg, sig)](#Key+verify) ⇒ Boolean + * [.signSchnorr(msg)](#Key+signSchnorr) ⇒ Buffer + * [.verifySchnorr(msg, sig)](#Key+verifySchnorr) ⇒ Boolean + * [.sign(data)](#Key+sign) ⇒ Buffer + * [.secure()](#Key+secure) + + + +### new Key([settings]) +Create an instance of a Fabric Key, either restoring from some known +values or from prior knowledge. For instance, you can call `new Key()` +to create a fresh keypair, or `new Key({ public: 'deadbeef...' })` to +create it from a known public key. -**Kind**: instance method of [Service](#Service) -**Returns**: Boolean - true if locked, false if unable to lock. | Param | Type | Default | Description | | --- | --- | --- | --- | -| [duration] | Number | 1000 | Number of milliseconds to hold lock. | +| [settings] | Object | | Initialization for the key. | +| [settings.network] | String | | Network string. | +| [settings.seed] | String | | Mnemonic seed for initializing the key. | +| [settings.public] | String | | Public key in hex. | +| [settings.private] | String | | Private key in hex. | +| [settings.purpose] | String | 44 | Constrains derivations to this space. | - + -### service.route(msg) ⇒ Promise -Resolve a [State](#State) from a particular [Message](#Message) object. +### key.verify(msg, sig) ⇒ Boolean +Verify a message's signature. -**Kind**: instance method of [Service](#Service) -**Returns**: Promise - Resolves with resulting [State](#State). +**Kind**: instance method of [Key](#Key) +**Returns**: Boolean - Whether the signature is valid | Param | Type | Description | | --- | --- | --- | -| msg | [Message](#Message) | Explicit Fabric [Message](#Message). | - - - -### service.start() -Start the service, including the initiation of an outbound connection -to any peers designated in the service's configuration. +| msg | Buffer \| String | The message that was signed | +| sig | Buffer \| String | The signature to verify | -**Kind**: instance method of [Service](#Service) - + -### service.\_GET(path) ⇒ Promise -Retrieve a value from the Service's state. +### key.signSchnorr(msg) ⇒ Buffer +Signs a message using Schnorr signatures (BIP340). -**Kind**: instance method of [Service](#Service) -**Returns**: Promise - Resolves with the result. +**Kind**: instance method of [Key](#Key) +**Returns**: Buffer - The signature | Param | Type | Description | | --- | --- | --- | -| path | String | Path of the value to retrieve. | +| msg | Buffer \| String | The message to sign | - + -### service.\_PUT(path, value, [commit]) ⇒ Promise -Store a value in the Service's state. +### key.verifySchnorr(msg, sig) ⇒ Boolean +Verifies a Schnorr signature (BIP340). -**Kind**: instance method of [Service](#Service) -**Returns**: Promise - Resolves with with stored document. +**Kind**: instance method of [Key](#Key) +**Returns**: Boolean - Whether the signature is valid -| Param | Type | Default | Description | -| --- | --- | --- | --- | -| path | String | | Path to store the value at. | -| value | Object | | Document to store. | -| [commit] | Boolean | false | Sign the resulting state. | +| Param | Type | Description | +| --- | --- | --- | +| msg | Buffer \| String | The message that was signed | +| sig | Buffer | The signature to verify | - + -### service.connect(notify) ⇒ Promise -Attach to network. +### key.sign(data) ⇒ Buffer +Sign a buffer of data using BIP 340: https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki -**Kind**: instance method of [Service](#Service) -**Returns**: Promise - Resolves to [Fabric](#Fabric). +**Kind**: instance method of [Key](#Key) +**Returns**: Buffer - Resulting signature (64 bytes). -| Param | Type | Default | Description | -| --- | --- | --- | --- | -| notify | Boolean | true | Commit to changes. | +| Param | Type | Description | +| --- | --- | --- | +| data | Buffer | Buffer of data to sign. | - + -### service.send(channel, message) ⇒ [Service](#Service) -Send a message to a channel. +### key.secure() +Secures the key by clearing sensitive information from memory. +This method should be called when the key is no longer needed +to prevent sensitive data from remaining in memory. -**Kind**: instance method of [Service](#Service) -**Returns**: [Service](#Service) - Chainable method. +**Kind**: instance method of [Key](#Key) + -| Param | Type | Description | -| --- | --- | --- | -| channel | String | Channel name to which the message will be sent. | -| message | String | Content of the message to send. | +## Ledger ⇐ [Scribe](#Scribe) +An ordered stack of pages. - +**Kind**: global class +**Extends**: [Scribe](#Scribe) +**Properties** -### service.\_registerActor(actor) ⇒ Promise -Register an [Actor](#Actor) with the [Service](#Service). +| Name | Type | Description | +| --- | --- | --- | +| memory | Buffer | The ledger's memory (4096 bytes). | +| stack | [Stack](#Stack) | The ledger's stack. | +| tip | Mixed | The most recent page in the ledger. | -**Kind**: instance method of [Service](#Service) -**Returns**: Promise - Resolves upon successful registration. -| Param | Type | Description | -| --- | --- | --- | -| actor | Object | Instance of the [Actor](#Actor). | +* [Ledger](#Ledger) ⇐ [Scribe](#Scribe) + * [.append(item)](#Ledger+append) ⇒ Promise + * [.now()](#Scribe+now) ⇒ Number + * [.trust(source)](#Scribe+trust) ⇒ [Scribe](#Scribe) + * [.inherits(scribe)](#Scribe+inherits) ⇒ [Scribe](#Scribe) - + -### service.\_send(message) -Sends a message. +### ledger.append(item) ⇒ Promise +Attempts to append a [Page](Page) to the ledger. -**Kind**: instance method of [Service](#Service) +**Kind**: instance method of [Ledger](#Ledger) +**Returns**: Promise - Resolves after the change has been committed. | Param | Type | Description | | --- | --- | --- | -| message | Mixed | Message to send. | - - - -## Session -The [Session](#Session) type describes a connection between [Peer](#Peer) -objects, and includes its own lifecycle. +| item | Mixed | Item to store. | -**Kind**: global class + -* [Session](#Session) - * [new Session(settings)](#new_Session_new) - * [.start()](#Session+start) - * [.stop()](#Session+stop) +### ledger.now() ⇒ Number +Retrives the current timestamp, in milliseconds. - +**Kind**: instance method of [Ledger](#Ledger) +**Overrides**: [now](#Scribe+now) +**Returns**: Number - [Number](Number) representation of the millisecond [Integer](Integer) value. + -### new Session(settings) -Creates a new [Session](#Session). +### ledger.trust(source) ⇒ [Scribe](#Scribe) +Blindly bind event handlers to the [Source](Source). +**Kind**: instance method of [Ledger](#Ledger) +**Overrides**: [trust](#Scribe+trust) +**Returns**: [Scribe](#Scribe) - Instance of the [Scribe](#Scribe). -| Param | Type | -| --- | --- | -| settings | Object | +| Param | Type | Description | +| --- | --- | --- | +| source | Source | Event stream. | - + -### session.start() -Opens the [Session](#Session) for interaction. +### ledger.inherits(scribe) ⇒ [Scribe](#Scribe) +Use an existing Scribe instance as a parent. -**Kind**: instance method of [Session](#Session) - +**Kind**: instance method of [Ledger](#Ledger) +**Overrides**: [inherits](#Scribe+inherits) +**Returns**: [Scribe](#Scribe) - The configured instance of the Scribe. -### session.stop() -Closes the [Session](#Session), preventing further interaction. +| Param | Type | Description | +| --- | --- | --- | +| scribe | [Scribe](#Scribe) | Instance of Scribe to use as parent. | -**Kind**: instance method of [Session](#Session) - + -## Signer ⇐ [Actor](#Actor) -Generic Fabric Signer. +## Logger ⇐ [Actor](#Actor) +A basic logger that writes logs to the local file system **Kind**: global class **Extends**: [Actor](#Actor) -**Emits**: event:message Fabric {@link Message} objects. -**Access**: protected -**Properties** - -| Name | Type | Description | -| --- | --- | --- | -| id | String | Unique identifier for this Signer (id === SHA256(preimage)). | -| preimage | String | Input hash for the `id` property (preimage === SHA256(SignerState)). | - -* [Signer](#Signer) ⇐ [Actor](#Actor) - * [new Signer([actor])](#new_Signer_new) - * [.sign()](#Signer+sign) ⇒ [Signer](#Signer) +* [Logger](#Logger) ⇐ [Actor](#Actor) + * [.path](#Logger+path) ⇒ String + * [.log(msg)](#Logger+log) ⇒ Boolean + * [.start()](#Logger+start) ⇒ Promise + * [.stop()](#Logger+stop) ⇒ Promise * [.adopt(changes)](#Actor+adopt) ⇒ [Actor](#Actor) * [.commit()](#Actor+commit) ⇒ String * [.export()](#Actor+export) ⇒ Object @@ -3338,40 +1964,52 @@ Generic Fabric Signer. * [.toObject()](#Actor+toObject) ⇒ Object * [.pause()](#Actor+pause) ⇒ [Actor](#Actor) * [.serialize()](#Actor+serialize) ⇒ String + * [.sign()](#Actor+sign) ⇒ [Actor](#Actor) * [.unpause()](#Actor+unpause) ⇒ [Actor](#Actor) * [.value([format])](#Actor+value) ⇒ Object * [._readObject(input)](#Actor+_readObject) ⇒ Object - + -### new Signer([actor]) -Creates an [Signer](#Signer), which emits messages for other -Signers to subscribe to. You can supply certain parameters -for the actor, including key material [!!!] — be mindful of -what you share with others! +### logger.path ⇒ String +Returns the path to the log file + +**Kind**: instance property of [Logger](#Logger) + + +### logger.log(msg) ⇒ Boolean +Writes the specified log to the log file -**Returns**: [Signer](#Signer) - Instance of the Signer. Call [sign](#Signer+sign) to emit a [Signature](Signature). +**Kind**: instance method of [Logger](#Logger) +**Returns**: Boolean - true, if msg was successfully written; false otherwise | Param | Type | Description | | --- | --- | --- | -| [actor] | Object | Object to use as the actor. | -| [actor.seed] | String | BIP24 Mnemonic to use as a seed phrase. | -| [actor.public] | Buffer | Public key. | -| [actor.private] | Buffer | Private key. | +| msg | String \| Object | The message to log | - + -### signer.sign() ⇒ [Signer](#Signer) -Signs some data. +### logger.start() ⇒ Promise +Starts the logger -**Kind**: instance method of [Signer](#Signer) -**Overrides**: [sign](#Actor+sign) +This method creates the required directories for writing the log file. + +**Kind**: instance method of [Logger](#Logger) + + +### logger.stop() ⇒ Promise +Stops the logger + +This method closes the log file and returns after it has been closed. Any +errors on close would cause the return promise to be rejected. + +**Kind**: instance method of [Logger](#Logger) -### signer.adopt(changes) ⇒ [Actor](#Actor) +### logger.adopt(changes) ⇒ [Actor](#Actor) Explicitly adopt a set of [JSONPatch](JSONPatch)-encoded changes. -**Kind**: instance method of [Signer](#Signer) +**Kind**: instance method of [Logger](#Logger) **Overrides**: [adopt](#Actor+adopt) **Returns**: [Actor](#Actor) - Instance of the Actor. @@ -3381,26 +2019,26 @@ Explicitly adopt a set of [JSONPatch](JSONPatch)-encoded changes. -### signer.commit() ⇒ String +### logger.commit() ⇒ String Resolve the current state to a commitment. -**Kind**: instance method of [Signer](#Signer) +**Kind**: instance method of [Logger](#Logger) **Overrides**: [commit](#Actor+commit) **Returns**: String - 32-byte ID -### signer.export() ⇒ Object +### logger.export() ⇒ Object Export the Actor's state to a standard [Object](Object). -**Kind**: instance method of [Signer](#Signer) +**Kind**: instance method of [Logger](#Logger) **Overrides**: [export](#Actor+export) **Returns**: Object - Standard object. -### signer.get(path) ⇒ Object +### logger.get(path) ⇒ Object Retrieve a value from the Actor's state by [JSONPointer](JSONPointer) path. -**Kind**: instance method of [Signer](#Signer) +**Kind**: instance method of [Logger](#Logger) **Overrides**: [get](#Actor+get) **Returns**: Object - Value of the path in the Actor's state. @@ -3410,10 +2048,10 @@ Retrieve a value from the Actor's state by [JSONPointer](JSONPointer) path. -### signer.set(path, value) ⇒ Object +### logger.set(path, value) ⇒ Object Set a value in the Actor's state by [JSONPointer](JSONPointer) path. -**Kind**: instance method of [Signer](#Signer) +**Kind**: instance method of [Logger](#Logger) **Overrides**: [set](#Actor+set) **Returns**: Object - Value of the path in the Actor's state. @@ -3424,55 +2062,70 @@ Set a value in the Actor's state by [JSONPointer](JSONPointer) path. -### signer.toBuffer() ⇒ Buffer +### logger.toBuffer() ⇒ Buffer Casts the Actor to a normalized Buffer. -**Kind**: instance method of [Signer](#Signer) +**Kind**: instance method of [Logger](#Logger) **Overrides**: [toBuffer](#Actor+toBuffer) -### signer.toGenericMessage() ⇒ Object -Casts the Actor to a generic message. +### logger.toGenericMessage() ⇒ Object +Casts the Actor to a generic message, used to uniquely identify the Actor's state. +Fields: +- `type`: 'FabricActorState' +- `object`: state -**Kind**: instance method of [Signer](#Signer) +**Kind**: instance method of [Logger](#Logger) **Overrides**: [toGenericMessage](#Actor+toGenericMessage) **Returns**: Object - Generic message object. +**See** + +- [https://en.wikipedia.org/wiki/Merkle_tree](https://en.wikipedia.org/wiki/Merkle_tree) +- [https://dev.fabric.pub/messages](https://dev.fabric.pub/messages) + -### signer.toObject() ⇒ Object +### logger.toObject() ⇒ Object Returns the Actor's current state as an [Object](Object). -**Kind**: instance method of [Signer](#Signer) +**Kind**: instance method of [Logger](#Logger) **Overrides**: [toObject](#Actor+toObject) -### signer.pause() ⇒ [Actor](#Actor) +### logger.pause() ⇒ [Actor](#Actor) Toggles `status` property to paused. -**Kind**: instance method of [Signer](#Signer) +**Kind**: instance method of [Logger](#Logger) **Overrides**: [pause](#Actor+pause) **Returns**: [Actor](#Actor) - Instance of the Actor. -### signer.serialize() ⇒ String +### logger.serialize() ⇒ String Serialize the Actor's current state into a JSON-formatted string. -**Kind**: instance method of [Signer](#Signer) +**Kind**: instance method of [Logger](#Logger) **Overrides**: [serialize](#Actor+serialize) + + +### logger.sign() ⇒ [Actor](#Actor) +Signs the Actor. + +**Kind**: instance method of [Logger](#Logger) +**Overrides**: [sign](#Actor+sign) -### signer.unpause() ⇒ [Actor](#Actor) +### logger.unpause() ⇒ [Actor](#Actor) Toggles `status` property to unpaused. -**Kind**: instance method of [Signer](#Signer) +**Kind**: instance method of [Logger](#Logger) **Overrides**: [unpause](#Actor+unpause) **Returns**: [Actor](#Actor) - Instance of the Actor. -### signer.value([format]) ⇒ Object +### logger.value([format]) ⇒ Object Get the inner value of the Actor with an optional cast type. -**Kind**: instance method of [Signer](#Signer) +**Kind**: instance method of [Logger](#Logger) **Overrides**: [value](#Actor+value) **Returns**: Object - Inner value of the Actor as an [Object](Object), or cast to the requested `format`. @@ -3482,10 +2135,10 @@ Get the inner value of the Actor with an optional cast type. -### signer.\_readObject(input) ⇒ Object +### logger.\_readObject(input) ⇒ Object Parse an Object into a corresponding Fabric state. -**Kind**: instance method of [Signer](#Signer) +**Kind**: instance method of [Logger](#Logger) **Overrides**: [\_readObject](#Actor+_readObject) **Returns**: Object - Fabric state. @@ -3493,1534 +2146,1466 @@ Parse an Object into a corresponding Fabric state. | --- | --- | --- | | input | Object | Object to read as input. | - + -## Snapshot -A type of message to be expected from a [Service](#Service). +## Machine +General-purpose state machine with [Vector](#Vector)-based instructions. **Kind**: global class -* [Snapshot](#Snapshot) - * [new Snapshot(settings)](#new_Snapshot_new) - * [.commit()](#Snapshot+commit) +* [Machine](#Machine) + * [new Machine(settings)](#new_Machine_new) + * [.sip([n])](#Machine+sip) ⇒ Number + * [.slurp([n])](#Machine+slurp) ⇒ Number + * [.compute(input)](#Machine+compute) ⇒ [Machine](#Machine) - + -### new Snapshot(settings) -Creates an instance of a [Snapshot](#Snapshot). +### new Machine(settings) +Create a Machine. | Param | Type | Description | | --- | --- | --- | -| settings | Object | Map of settings to configure the [Snapshot](#Snapshot) with. | - - - -### snapshot.commit() -Retrieves the `sha256` fingerprint for the [Snapshot](#Snapshot) state. - -**Kind**: instance method of [Snapshot](#Snapshot) - - -## Stack -Manage stacks of data. - -**Kind**: global class - -* [Stack](#Stack) - * [new Stack([list])](#new_Stack_new) - * [.push(data)](#Stack+push) ⇒ Number +| settings | Object | Run-time configuration. | - + -### new Stack([list]) -Create a [Stack](#Stack) instance. +### machine.sip([n]) ⇒ Number +Get `n` bits of deterministic random data. -**Returns**: [Stack](#Stack) - Instance of the [Stack](#Stack). +**Kind**: instance method of [Machine](#Machine) +**Returns**: Number - Random bits from [Generator](Generator). | Param | Type | Default | Description | | --- | --- | --- | --- | -| [list] | Array | [] | Genesis state for the [Stack](#Stack) instance. | - - - -### stack.push(data) ⇒ Number -Push data onto the stack. Changes the [Stack#frame](Stack#frame) and -[Stack#id](Stack#id). - -**Kind**: instance method of [Stack](#Stack) -**Returns**: Number - Resulting size of the stack. - -| Param | Type | Description | -| --- | --- | --- | -| data | Mixed | Treated as a [State](#State). | - - - -## State ⇐ EventEmitter -The [State](#State) is the core of most [User](User)-facing interactions. To -interact with the [User](User), simply propose a change in the state by -committing to the outcome. This workflow keeps app design quite simple! - -**Kind**: global class -**Extends**: EventEmitter -**Access**: protected -**Properties** - -| Name | Type | Description | -| --- | --- | --- | -| size | Number | Size of state in bytes. | -| @buffer | Buffer | Byte-for-byte memory representation of state. | -| @type | String | Named type. | -| @data | Mixed | Local instance of the state. | -| @id | String | Unique identifier for this data. | - - -* [State](#State) ⇐ EventEmitter - * [new State(data)](#new_State_new) - * _instance_ - * [.toHTML()](#State+toHTML) - * [.toString()](#State+toString) ⇒ String - * [.serialize([input])](#State+serialize) ⇒ Buffer - * [.deserialize(input)](#State+deserialize) ⇒ [State](#State) - * [.fork()](#State+fork) ⇒ [State](#State) - * [.get(path)](#State+get) ⇒ Mixed - * [.set(path)](#State+set) ⇒ Mixed - * [.commit()](#State+commit) - * [.render()](#State+render) ⇒ String - * _static_ - * [.fromJSON(input)](#State.fromJSON) ⇒ [State](#State) - - - -### new State(data) -Creates a snapshot of some information. - -**Returns**: [State](#State) - Resulting state. - -| Param | Type | Description | -| --- | --- | --- | -| data | Mixed | Input data. | - - - -### state.toHTML() -Converts the State to an HTML document. - -**Kind**: instance method of [State](#State) - - -### state.toString() ⇒ String -Unmarshall an existing state to an instance of a [Blob](Blob). - -**Kind**: instance method of [State](#State) -**Returns**: String - Serialized [Blob](Blob). - - -### state.serialize([input]) ⇒ Buffer -Convert to [Buffer](Buffer). - -**Kind**: instance method of [State](#State) -**Returns**: Buffer - [Store](#Store)-able blob. - -| Param | Type | Description | -| --- | --- | --- | -| [input] | Mixed | Input to serialize. | - - - -### state.deserialize(input) ⇒ [State](#State) -Take a hex-encoded input and convert to a [State](#State) object. - -**Kind**: instance method of [State](#State) -**Returns**: [State](#State) - [description] - -| Param | Type | Description | -| --- | --- | --- | -| input | String | [description] | - - - -### state.fork() ⇒ [State](#State) -Creates a new child [State](#State), with `@parent` set to -the current [State](#State) by immutable identifier. +| [n] | Number | 128 | Number of bits to retrieve. | -**Kind**: instance method of [State](#State) - + -### state.get(path) ⇒ Mixed -Retrieve a key from the [State](#State). +### machine.slurp([n]) ⇒ Number +Get `n` bytes of deterministic random data. -**Kind**: instance method of [State](#State) +**Kind**: instance method of [Machine](#Machine) +**Returns**: Number - Random bytes from [Generator](Generator). -| Param | Type | Description | -| --- | --- | --- | -| path | [Path](#Path) | Key to retrieve. | +| Param | Type | Default | Description | +| --- | --- | --- | --- | +| [n] | Number | 32 | Number of bytes to retrieve. | - + -### state.set(path) ⇒ Mixed -Set a key in the [State](#State) to a particular value. +### machine.compute(input) ⇒ [Machine](#Machine) +Computes the next "step" for our current Vector. Analagous to `sum`. +The top item on the stack is always the memory held at current position, +so counts should always begin with 0. -**Kind**: instance method of [State](#State) +**Kind**: instance method of [Machine](#Machine) +**Returns**: [Machine](#Machine) - Instance of the resulting machine. | Param | Type | Description | | --- | --- | --- | -| path | [Path](#Path) | Key to retrieve. | +| input | Object | Value to pass as input. | - + -### state.commit() -Increment the vector clock, broadcast all changes as a transaction. +## Message : Object +The [Message](#Message) type defines the Application Messaging Protocol, or AMP. +Each [Actor](#Actor) in the network receives and broadcasts messages, +selectively disclosing new routes to peers which may have open circuits. -**Kind**: instance method of [State](#State) - +**Kind**: global class -### state.render() ⇒ String -Compose a JSON string for network consumption. +* [Message](#Message) : Object + * [new Message(message)](#new_Message_new) + * [.asRaw()](#Message+asRaw) ⇒ Buffer + * [.signWithKey(key)](#Message+signWithKey) ⇒ [Message](#Message) + * [.verify()](#Message+verify) ⇒ Boolean + * [.verifyWithKey(key)](#Message+verifyWithKey) ⇒ Boolean + * [._setSigner(key)](#Message+_setSigner) ⇒ [Message](#Message) -**Kind**: instance method of [State](#State) -**Returns**: String - JSON-encoded [String](String). - + -### State.fromJSON(input) ⇒ [State](#State) -Marshall an input into an instance of a [State](#State). States have -absolute authority over their own domain, so choose your States wisely. +### new Message(message) +The `Message` type is standardized in [Fabric](#Fabric) as a [Array](Array), which can be added to any other vector to compute a resulting state. -**Kind**: static method of [State](#State) -**Returns**: [State](#State) - Resulting instance of the [State](#State). +**Returns**: [Message](#Message) - Instance of the message. | Param | Type | Description | | --- | --- | --- | -| input | String | Arbitrary input. | +| message | Object | Message vector. Will be serialized by [Array#_serialize](Array#_serialize). | - + -## Store -Long-term storage. +### message.asRaw() ⇒ Buffer +Returns a [Buffer](Buffer) of the complete message. -**Kind**: global class -**Properties** +**Kind**: instance method of [Message](#Message) +**Returns**: Buffer - Buffer of the encoded [Message](#Message). + -| Name | Type | Description | -| --- | --- | --- | -| settings | Mixed | Current configuration. | +### message.signWithKey(key) ⇒ [Message](#Message) +Signs the message using a specific key. +**Kind**: instance method of [Message](#Message) +**Returns**: [Message](#Message) - Signed message. +**Throws**: -* [Store](#Store) - * [new Store([settings])](#new_Store_new) - * [._REGISTER(obj)](#Store+_REGISTER) ⇒ [Vector](#Vector) - * [._POST(key, value)](#Store+_POST) ⇒ Promise - * [.get(key)](#Store+get) ⇒ Promise - * [.set(key, value)](#Store+set) - * [.trust(source)](#Store+trust) ⇒ [Store](#Store) - * [.del(key)](#Store+del) - * [.flush()](#Store+flush) - * [.start()](#Store+start) ⇒ Promise +- Error If attempting to sign without a private key - -### new Store([settings]) -Create an instance of a [Store](#Store) to manage long-term storage, which is -particularly useful when building a user-facing [Product](Product). +| Param | Type | Description | +| --- | --- | --- | +| key | Object | Key object with private key and sign method. | +| key.private | String \| Buffer | Private key | +| key.pubkey | String \| Buffer | Public key | +| key.sign | function | Signing function | -**Returns**: [Store](#Store) - Instance of the Store, ready to start. + -| Param | Type | Default | Description | -| --- | --- | --- | --- | -| [settings] | Object | {} | configuration object. | +### message.verify() ⇒ Boolean +Verify a message's signature. - +**Kind**: instance method of [Message](#Message) +**Returns**: Boolean - `true` if the signature is valid, `false` if not. + -### store.\_REGISTER(obj) ⇒ [Vector](#Vector) -Registers an [Actor](#Actor). Necessary to store in a collection. +### message.verifyWithKey(key) ⇒ Boolean +Verify a message's signature with a specific key. -**Kind**: instance method of [Store](#Store) -**Returns**: [Vector](#Vector) - Returned from `storage.set` +**Kind**: instance method of [Message](#Message) +**Returns**: Boolean - `true` if the signature is valid, `false` if not. | Param | Type | Description | | --- | --- | --- | -| obj | Object | Instance of the object to store. | +| key | Object | Key object with verify method. | +| key.verify | function | Verification function | - + -### store.\_POST(key, value) ⇒ Promise -Insert something into a collection. +### message.\_setSigner(key) ⇒ [Message](#Message) +Sets the signer for the message. -**Kind**: instance method of [Store](#Store) -**Returns**: Promise - Resolves on success with a String pointer. +**Kind**: instance method of [Message](#Message) +**Returns**: [Message](#Message) - Instance of the Message with associated signer. | Param | Type | Description | | --- | --- | --- | -| key | String | Path to add data to. | -| value | Mixed | Object to store. | +| key | Object | Key object with pubkey property. | +| key.pubkey | String \| Buffer | Public key | - + -### store.get(key) ⇒ Promise -Barebones getter. +## Peer +An in-memory representation of a node in our network. -**Kind**: instance method of [Store](#Store) -**Returns**: Promise - Resolves on complete. `null` if not found. +**Kind**: global class -| Param | Type | Description | -| --- | --- | --- | -| key | String | Name of data to retrieve. | +* [Peer](#Peer) + * [new Peer([config])](#new_Peer_new) + * ~~[.address](#Peer+address)~~ + * [.broadcast(message)](#Peer+broadcast) + * [._connect(target)](#Peer+_connect) + * [._fillPeerSlots()](#Peer+_fillPeerSlots) ⇒ [Peer](#Peer) + * [._handleFabricMessage(buffer)](#Peer+_handleFabricMessage) ⇒ [Peer](#Peer) + * [.start()](#Peer+start) + * [.stop()](#Peer+stop) + * [.listen()](#Peer+listen) ⇒ [Peer](#Peer) - + -### store.set(key, value) -Set a `key` to a specific `value`. +### new Peer([config]) +Create an instance of [Peer](#Peer). -**Kind**: instance method of [Store](#Store) -| Param | Type | Description | -| --- | --- | --- | -| key | String | Address of the information. | -| value | Mixed | Content to store at `key`. | +| Param | Type | Default | Description | +| --- | --- | --- | --- | +| [config] | Object | | Initialization Vector for this peer. | +| [config.listen] | Boolean | | Whether or not to listen for connections. | +| [config.upnp] | Boolean | | Whether or not to use UPNP for automatic configuration. | +| [config.port] | Number | 7777 | Port to use for P2P connections. | +| [config.peers] | Array | [] | List of initial peers. | - + -### store.trust(source) ⇒ [Store](#Store) -Implicitly trust an [Event](Event) source. +### ~~peer.address~~ +***Deprecated*** -**Kind**: instance method of [Store](#Store) -**Returns**: [Store](#Store) - Resulting instance of [Store](#Store) with new trust. +**Kind**: instance property of [Peer](#Peer) + + +### peer.broadcast(message) +Write a [Buffer](Buffer) to all connected peers. + +**Kind**: instance method of [Peer](#Peer) | Param | Type | Description | | --- | --- | --- | -| source | EventEmitter | Event-emitting source. | +| message | Buffer | Message buffer to send. | - + -### store.del(key) -Remove a [Value](#Value) by [Path](#Path). +### peer.\_connect(target) +Open a Fabric connection to the target address and initiate the Fabric Protocol. -**Kind**: instance method of [Store](#Store) +**Kind**: instance method of [Peer](#Peer) | Param | Type | Description | | --- | --- | --- | -| key | [Path](#Path) | Key to remove. | +| target | String | Target address. | - + -### store.flush() -Wipes the storage. +### peer.\_fillPeerSlots() ⇒ [Peer](#Peer) +Attempt to fill available connection slots with new peers. -**Kind**: instance method of [Store](#Store) - +**Kind**: instance method of [Peer](#Peer) +**Returns**: [Peer](#Peer) - Instance of the peer. + -### store.start() ⇒ Promise -Start running the process. +### peer.\_handleFabricMessage(buffer) ⇒ [Peer](#Peer) +Handle a Fabric [Message](#Message) buffer. -**Kind**: instance method of [Store](#Store) -**Returns**: Promise - Resolves on complete. - +**Kind**: instance method of [Peer](#Peer) +**Returns**: [Peer](#Peer) - Instance of the Peer. + +| Param | Type | +| --- | --- | +| buffer | Buffer | -## Swap : Object -The [Swap](#Swap) contract executes a set of transactions on two distinct -[Chain](#Chain) components, utilizing a secret-reveal mechanism to atomically -execute either the full set or none. + -**Kind**: global class +### peer.start() +Start the Peer. + +**Kind**: instance method of [Peer](#Peer) + -* [Swap](#Swap) : Object - * [new Swap([settings])](#new_Swap_new) - * [.extractSecret(tx, address)](#Swap+extractSecret) ⇒ Mixed +### peer.stop() +Stop the peer. - +**Kind**: instance method of [Peer](#Peer) + -### new Swap([settings]) -Atomically execute a set of transactions across two [Chain](#Chain) components. +### peer.listen() ⇒ [Peer](#Peer) +Start listening for connections. +**Kind**: instance method of [Peer](#Peer) +**Returns**: [Peer](#Peer) - Chainable method. + -| Param | Type | Default | Description | -| --- | --- | --- | --- | -| [settings] | Object | {} | Configuration for the swap. | +## Reader +Read from a byte stream, seeking valid Fabric messages. - +**Kind**: global class + -### swap.extractSecret(tx, address) ⇒ Mixed -Find an input from the provided transaction which spends from the target -P2SH address. +### new Reader(settings) +Create an instance of a [Reader](#Reader), which can listen to a byte stream +for valid Fabric messages. -**Kind**: instance method of [Swap](#Swap) -**Returns**: Mixed - False on failure, secret value on success. | Param | Type | Description | | --- | --- | --- | -| tx | Transaction | [Transaction](Transaction) to iterate over. | -| address | String | P2SH address to search for. | +| settings | Object | Settings for the stream. | - + -## Swarm : String -Orchestrates a network of peers. +## Remote : [Remote](#Remote) +Interact with a remote [Resource](#Resource). This is currently the only +HTTP-related code that should remain in @fabric/core — all else must +be moved to @fabric/http before final release! **Kind**: global class +**Properties** -* [Swarm](#Swarm) : String - * [new Swarm(config)](#new_Swarm_new) - * [.trust(source)](#Swarm+trust) - * [.start()](#Swarm+start) ⇒ Promise +| Name | Type | +| --- | --- | +| config | Object | +| secure | Boolean | - -### new Swarm(config) -Create an instance of a [Swarm](#Swarm). +* [Remote](#Remote) : [Remote](#Remote) + * [new Remote(target)](#new_Remote_new) + * [.enumerate()](#Remote+enumerate) ⇒ Configuration + * [.request(type, path, [params])](#Remote+request) ⇒ FabricHTTPResult + * [._PUT(path, body)](#Remote+_PUT) ⇒ FabricHTTPResult \| String + * [._GET(path, params)](#Remote+_GET) ⇒ FabricHTTPResult \| String + * [._POST(path, params)](#Remote+_POST) ⇒ FabricHTTPResult \| String + * [._OPTIONS(path, params)](#Remote+_OPTIONS) ⇒ Object + * [._PATCH(path, body)](#Remote+_PATCH) ⇒ Object + * [._DELETE(path, params)](#Remote+_DELETE) ⇒ Object + + + +### new Remote(target) +An in-memory representation of a node in our network. -**Returns**: [Swarm](#Swarm) - Instance of the Swarm. | Param | Type | Description | | --- | --- | --- | -| config | Object | Configuration object. | - - +| target | Object | Target object. | +| target.host | String | Named host, e.g. "localhost". | +| target.secure | String | Require TLS session. | -### swarm.trust(source) -Explicitly trust an [EventEmitter](EventEmitter) to provide messages using -the expected [Interface](#Interface), providing [Message](#Message) objects as -the expected [Type](Type). + -**Kind**: instance method of [Swarm](#Swarm) +### remote.enumerate() ⇒ Configuration +Enumerate the available Resources on the remote host. -| Param | Type | Description | -| --- | --- | --- | -| source | EventEmitter | [Actor](#Actor) to utilize. | +**Kind**: instance method of [Remote](#Remote) +**Returns**: Configuration - An object with enumerable key/value pairs for the Application Resource Contract. + - +### remote.request(type, path, [params]) ⇒ FabricHTTPResult +Make an HTTP request to the configured authority. -### swarm.start() ⇒ Promise -Begin computing. +**Kind**: instance method of [Remote](#Remote) -**Kind**: instance method of [Swarm](#Swarm) -**Returns**: Promise - Resolves to instance of [Swarm](#Swarm). - +| Param | Type | Description | +| --- | --- | --- | +| type | String | One of `GET`, `PUT`, `POST`, `DELETE`, or `OPTIONS`. | +| path | String | The path to request from the authority. | +| [params] | Object | Options. | -## Transition -The [Transition](#Transition) type reflects a change from one finite -[State](#State) to another. + -**Kind**: global class - +### remote.\_PUT(path, body) ⇒ FabricHTTPResult \| String +HTTP PUT against the configured Authority. -### new Transition(settings) +**Kind**: instance method of [Remote](#Remote) +**Returns**: FabricHTTPResult \| String - Result of request. | Param | Type | Description | | --- | --- | --- | -| settings | Object | Configuration for the transition object. | - - - -## Tree -Class implementing a Merkle Tree. - -**Kind**: global class - -* [Tree](#Tree) - * [new Tree([settings])](#new_Tree_new) - * [.addLeaf(leaf)](#Tree+addLeaf) ⇒ [Tree](#Tree) - * [.getLeaves()](#Tree+getLeaves) ⇒ Array +| path | String | HTTP Path to request. | +| body | Object | Map of parameters to supply. | - + -### new Tree([settings]) -Create an instance of a Tree. +### remote.\_GET(path, params) ⇒ FabricHTTPResult \| String +HTTP GET against the configured Authority. -**Returns**: [Tree](#Tree) - Instance of the tree. +**Kind**: instance method of [Remote](#Remote) +**Returns**: FabricHTTPResult \| String - Result of request. | Param | Type | Description | | --- | --- | --- | -| [settings] | Object | Configuration. | +| path | String | HTTP Path to request. | +| params | Object | Map of parameters to supply. | - + -### tree.addLeaf(leaf) ⇒ [Tree](#Tree) -Add a leaf to the tree. +### remote.\_POST(path, params) ⇒ FabricHTTPResult \| String +HTTP POST against the configured Authority. -**Kind**: instance method of [Tree](#Tree) -**Returns**: [Tree](#Tree) - Instance of the tree. +**Kind**: instance method of [Remote](#Remote) +**Returns**: FabricHTTPResult \| String - Result of request. | Param | Type | Description | | --- | --- | --- | -| leaf | String | Leaf to add to the tree. | - - - -### tree.getLeaves() ⇒ Array -Get a list of the [Tree](#Tree)'s leaves. +| path | String | HTTP Path to request. | +| params | Object | Map of parameters to supply. | -**Kind**: instance method of [Tree](#Tree) -**Returns**: Array - A list of the [Tree](#Tree)'s leaves. - + -## Value -[Number](Number)-like type. +### remote.\_OPTIONS(path, params) ⇒ Object +HTTP OPTIONS on the configured Authority. -**Kind**: global class +**Kind**: instance method of [Remote](#Remote) +**Returns**: Object - - Full description of remote resource. -* [Value](#Value) - * [new Value(data)](#new_Value_new) - * [.value(input)](#Value+value) +| Param | Type | Description | +| --- | --- | --- | +| path | String | HTTP Path to request. | +| params | Object | Map of parameters to supply. | - + -### new Value(data) -Use the [Value](#Value) type to interact with [Number](Number)-like objects. +### remote.\_PATCH(path, body) ⇒ Object +HTTP PATCH on the configured Authority. +**Kind**: instance method of [Remote](#Remote) +**Returns**: Object - - Full description of remote resource. | Param | Type | Description | | --- | --- | --- | -| data | Mixed | Input value. | +| path | String | HTTP Path to request. | +| body | Object | Map of parameters to supply. | - + -### value.value(input) -Compute the numeric representation of this input. +### remote.\_DELETE(path, params) ⇒ Object +HTTP DELETE on the configured Authority. -**Kind**: instance method of [Value](#Value) +**Kind**: instance method of [Remote](#Remote) +**Returns**: Object - - Full description of remote resource. | Param | Type | Description | | --- | --- | --- | -| input | String | Input string to seek for value. | +| path | String | HTTP Path to request. | +| params | Object | Map of parameters to supply. | - + -## Vector -**Kind**: global class +## Resource +Generic interface for collections of digital objects. -* [Vector](#Vector) - * [new Vector(origin)](#new_Vector_new) - * [._serialize(input)](#Vector+_serialize) ⇒ String - * [.toString(input)](#Vector+toString) ⇒ String +**Kind**: global class - +* [Resource](#Resource) + * [new Resource(definition)](#new_Resource_new) + * [.create(obj)](#Resource+create) ⇒ [Vector](#Vector) + * [.update(id, update)](#Resource+update) ⇒ [Vector](#Vector) -### new Vector(origin) -An "Initialization" Vector. + +### new Resource(definition) | Param | Type | Description | | --- | --- | --- | -| origin | Object | Input state (will map to `@data`.) | +| definition | Object | Initial parameters | - + -### vector.\_serialize(input) ⇒ String -_serialize is a placeholder, should be discussed. +### resource.create(obj) ⇒ [Vector](#Vector) +Create an instance of the Resource's type. -**Kind**: instance method of [Vector](#Vector) -**Returns**: String - - resulting string [JSON-encoded version of the local `@data` value.] +**Kind**: instance method of [Resource](#Resource) +**Returns**: [Vector](#Vector) - Resulting Vector with deterministic identifier. | Param | Type | Description | | --- | --- | --- | -| input | String | What to serialize. Defaults to `this.state`. | +| obj | Object | Map of the instance's properties and values. | - + -### vector.toString(input) ⇒ String -Render the output to a [String](String). +### resource.update(id, update) ⇒ [Vector](#Vector) +Modify an existing instance of a Resource by its unique identifier. Produces a new instance. -**Kind**: instance method of [Vector](#Vector) +**Kind**: instance method of [Resource](#Resource) +**Returns**: [Vector](#Vector) - Resulting Vector instance with updated identifier. | Param | Type | Description | | --- | --- | --- | -| input | Mixed | Arbitrary input. | +| id | String | Unique ID to update. | +| update | Object | Map of change to make (keys -> values). | - + -## Walker +## Script **Kind**: global class + -* [Walker](#Walker) - * [new Walker(init)](#new_Walker_new) - * [._explore(path, [map])](#Walker+_explore) ⇒ Object - * [._define(dir, [map])](#Walker+_define) ⇒ Object - - - -### new Walker(init) -The Walker explores a directory tree and maps it to memory. +### new Script(config) +Compose a [Script](#Script) for inclusion within a [Contract](Contract). +**Returns**: [Script](#Script) - Instance of the [Script](#Script), ready for use. | Param | Type | Description | | --- | --- | --- | -| init | [Vector](#Vector) | Initial state tree. | +| config | Mixed | Configuration options for the script. | - + -### walker.\_explore(path, [map]) ⇒ Object -Explores a directory tree on the local system's disk. +## Service +The "Service" is a simple model for processing messages in a distributed +system. [Service](#Service) instances are public interfaces for outside systems, +and typically advertise their presence to the network. -**Kind**: instance method of [Walker](#Walker) -**Returns**: Object - [description] +To implement a Service, you will typically need to implement all methods from +this prototype. In general, `connect` and `send` are the highest-priority +jobs, and by default the `fabric` property will serve as an I/O stream using +familiar semantics. -| Param | Type | Default | Description | -| --- | --- | --- | --- | -| path | String | | [description] | -| [map] | Object | {} | [description] | +**Kind**: global class +**Access**: protected +**Properties** - +| Name | Description | +| --- | --- | +| map | The "map" is a hashtable of "key" => "value" pairs. | -### walker.\_define(dir, [map]) ⇒ Object -Explores a directory tree on the local system's disk. -**Kind**: instance method of [Walker](#Walker) -**Returns**: Object - A hashmap of directory contents. +* [Service](#Service) + * [new Service([settings])](#new_Service_new) + * [.init()](#Service+init) + * [.tick()](#Service+tick) ⇒ Number + * [.beat()](#Service+beat) ⇒ [Service](#Service) + * [.get(path)](#Service+get) ⇒ Mixed + * [.set(path)](#Service+set) ⇒ Mixed + * [.trust(source)](#Service+trust) ⇒ [Service](#Service) + * [.handler(message)](#Service+handler) ⇒ [Service](#Service) + * [.lock([duration])](#Service+lock) ⇒ Boolean + * [.when(event, method)](#Service+when) ⇒ EventEmitter + * [.route(msg)](#Service+route) ⇒ Promise + * [.start()](#Service+start) + * [._GET(path)](#Service+_GET) ⇒ Promise + * [._PUT(path, value, [commit])](#Service+_PUT) ⇒ Promise + * [.connect(notify)](#Service+connect) ⇒ Promise + * [.send(channel, message)](#Service+send) ⇒ [Service](#Service) + * [._registerActor(actor)](#Service+_registerActor) ⇒ Promise + * [._send(message)](#Service+_send) + + + +### new Service([settings]) +Create an instance of a Service. + | Param | Type | Default | Description | | --- | --- | --- | --- | -| dir | String | | Path to crawl on local disk. | -| [map] | Object | {} | Pointer to previous step in stack. | +| [settings] | Object | | Configuration for this service. | +| [settings.networking] | Boolean | true | Whether or not to connect to the network. | +| [settings.frequency] | Object | | Interval frequency in hertz. | +| [settings.state] | Object | | Initial state to assign. | - + -## Wallet : Object -Manage keys and track their balances. +### service.init() +Called by Web Components. +TODO: move to @fabric/http/types/spa -**Kind**: global class -**Properties** +**Kind**: instance method of [Service](#Service) + -| Name | Type | Description | -| --- | --- | --- | -| id | String | Unique identifier for this [Wallet](#Wallet). | +### service.tick() ⇒ Number +Move forward one clock cycle. +**Kind**: instance method of [Service](#Service) + -* [Wallet](#Wallet) : Object - * [new Wallet([settings])](#new_Wallet_new) - * _instance_ - * [.loadKey(keypair)](#Wallet+loadKey) ⇒ [Wallet](#Wallet) - * [.start()](#Wallet+start) - * [._load(settings)](#Wallet+_load) - * [.getAddressForScript(script)](#Wallet+getAddressForScript) - * [.getAddressFromRedeemScript(redeemScript)](#Wallet+getAddressFromRedeemScript) - * [.createPricedOrder(order)](#Wallet+createPricedOrder) - * [._sign(tx)](#Wallet+_sign) - * [._createCrowdfund(fund)](#Wallet+_createCrowdfund) - * [._getSwapInputScript(redeemScript, secret)](#Wallet+_getSwapInputScript) - * [._getRefundInputScript(redeemScript)](#Wallet+_getRefundInputScript) - * [.publicKeyFromString(input)](#Wallet+publicKeyFromString) - * _static_ - * [.createSeed(passphrase)](#Wallet.createSeed) ⇒ FabricSeed - * [.fromSeed(seed)](#Wallet.fromSeed) ⇒ [Wallet](#Wallet) +### service.beat() ⇒ [Service](#Service) +Compute latest state. - +**Kind**: instance method of [Service](#Service) +**Emits**: Message#event:beat + -### new Wallet([settings]) -Create an instance of a [Wallet](#Wallet). +### service.get(path) ⇒ Mixed +Retrieve a key from the [State](#State). -**Returns**: [Wallet](#Wallet) - Instance of the wallet. +**Kind**: instance method of [Service](#Service) +**Returns**: Mixed - Returns the target value if found, otherwise null. -| Param | Type | Default | Description | -| --- | --- | --- | --- | -| [settings] | Object | {} | Configure the wallet. | -| [settings.verbosity] | Number | 2 | One of: 0 (none), 1 (error), 2 (warning), 3 (notice), 4 (debug), 5 (audit) | -| [settings.key] | Object | | Key to restore from. | -| [settings.key.seed] | String | | Mnemonic seed for a restored wallet. | +| Param | Type | Description | +| --- | --- | --- | +| path | Path | Key to retrieve. | - + -### wallet.loadKey(keypair) ⇒ [Wallet](#Wallet) -Import a key to the wallet. +### service.set(path) ⇒ Mixed +Set a key in the [State](#State) to a particular value. -**Kind**: instance method of [Wallet](#Wallet) -**Returns**: [Wallet](#Wallet) - Instance of the Wallet. +**Kind**: instance method of [Service](#Service) | Param | Type | Description | | --- | --- | --- | -| keypair | Object | Keypair. | -| keypair.public | Buffer | Public key. | -| [keypair.private] | Buffer | Private key. | - - - -### wallet.start() -Start the wallet, including listening for transactions. +| path | Path | Key to retrieve. | -**Kind**: instance method of [Wallet](#Wallet) - + -### wallet.\_load(settings) -Initialize the wallet, including keys and addresses. +### service.trust(source) ⇒ [Service](#Service) +Explicitly trust all events from a known source. -**Kind**: instance method of [Wallet](#Wallet) +**Kind**: instance method of [Service](#Service) +**Returns**: [Service](#Service) - Instance of Service after binding events. | Param | Type | Description | | --- | --- | --- | -| settings | Object | Settings to load. | +| source | EventEmitter | Emitter of events. | - + -### wallet.getAddressForScript(script) -Returns a bech32 address for the provided [Script](#Script). +### service.handler(message) ⇒ [Service](#Service) +Default route handler for an incoming message. Follows the Activity +Streams 2.0 spec: https://www.w3.org/TR/activitystreams-core/ -**Kind**: instance method of [Wallet](#Wallet) +**Kind**: instance method of [Service](#Service) +**Returns**: [Service](#Service) - Chainable method. -| Param | Type | -| --- | --- | -| script | [Script](#Script) | +| Param | Type | Description | +| --- | --- | --- | +| message | Activity | Message object. | - + -### wallet.getAddressFromRedeemScript(redeemScript) -Generate a [BitcoinAddress](BitcoinAddress) for the supplied [BitcoinScript](BitcoinScript). +### service.lock([duration]) ⇒ Boolean +Attempt to acquire a lock for `duration` seconds. -**Kind**: instance method of [Wallet](#Wallet) +**Kind**: instance method of [Service](#Service) +**Returns**: Boolean - true if locked, false if unable to lock. -| Param | Type | -| --- | --- | -| redeemScript | BitcoinScript | +| Param | Type | Default | Description | +| --- | --- | --- | --- | +| [duration] | Number | 1000 | Number of milliseconds to hold lock. | - + -### wallet.createPricedOrder(order) -Create a priced order. +### service.when(event, method) ⇒ EventEmitter +Bind a method to an event, with current state as the immutable context. -**Kind**: instance method of [Wallet](#Wallet) +**Kind**: instance method of [Service](#Service) +**Returns**: EventEmitter - Instance of EventEmitter. -| Param | Type | -| --- | --- | -| order | Object | -| order.asset | Object | -| order.amount | Object | +| Param | Type | Description | +| --- | --- | --- | +| event | String | Name of the event upon which to execute `method` as a function. | +| method | function | Function to execute when named [Event](Event) `event` is encountered. | - + -### wallet.\_sign(tx) -Signs a transaction with the keyring. +### service.route(msg) ⇒ Promise +Resolve a [State](#State) from a particular [Message](#Message) object. -**Kind**: instance method of [Wallet](#Wallet) +**Kind**: instance method of [Service](#Service) +**Returns**: Promise - Resolves with resulting [State](#State). -| Param | Type | -| --- | --- | -| tx | BcoinTX | +| Param | Type | Description | +| --- | --- | --- | +| msg | [Message](#Message) | Explicit Fabric [Message](#Message). | - + -### wallet.\_createCrowdfund(fund) -Create a crowdfunding transaction. +### service.start() +Start the service, including the initiation of an outbound connection +to any peers designated in the service's configuration. -**Kind**: instance method of [Wallet](#Wallet) +**Kind**: instance method of [Service](#Service) + -| Param | Type | -| --- | --- | -| fund | Object | +### service.\_GET(path) ⇒ Promise +Retrieve a value from the Service's state. - +**Kind**: instance method of [Service](#Service) +**Returns**: Promise - Resolves with the result. -### wallet.\_getSwapInputScript(redeemScript, secret) -Generate [Script](#Script) for claiming a [Swap](#Swap). +| Param | Type | Description | +| --- | --- | --- | +| path | String | Path of the value to retrieve. | -**Kind**: instance method of [Wallet](#Wallet) + -| Param | Type | -| --- | --- | -| redeemScript | \* | -| secret | \* | +### service.\_PUT(path, value, [commit]) ⇒ Promise +Store a value in the Service's state. - +**Kind**: instance method of [Service](#Service) +**Returns**: Promise - Resolves with with stored document. -### wallet.\_getRefundInputScript(redeemScript) -Generate [Script](#Script) for reclaiming funds commited to a [Swap](#Swap). +| Param | Type | Default | Description | +| --- | --- | --- | --- | +| path | String | | Path to store the value at. | +| value | Object | | Document to store. | +| [commit] | Boolean | false | Sign the resulting state. | -**Kind**: instance method of [Wallet](#Wallet) + -| Param | Type | -| --- | --- | -| redeemScript | \* | +### service.connect(notify) ⇒ Promise +Attach to network. - +**Kind**: instance method of [Service](#Service) +**Returns**: Promise - Resolves to [Fabric](#Fabric). -### wallet.publicKeyFromString(input) -Create a public key from a string. +| Param | Type | Default | Description | +| --- | --- | --- | --- | +| notify | Boolean | true | Commit to changes. | -**Kind**: instance method of [Wallet](#Wallet) + + +### service.send(channel, message) ⇒ [Service](#Service) +Send a message to a channel. + +**Kind**: instance method of [Service](#Service) +**Returns**: [Service](#Service) - Chainable method. | Param | Type | Description | | --- | --- | --- | -| input | String | Hex-encoded string to create key from. | +| channel | String | Channel name to which the message will be sent. | +| message | String | Content of the message to send. | - + -### Wallet.createSeed(passphrase) ⇒ FabricSeed -Create a new seed phrase. +### service.\_registerActor(actor) ⇒ Promise +Register an [Actor](#Actor) with the [Service](#Service). -**Kind**: static method of [Wallet](#Wallet) -**Returns**: FabricSeed - The seed object. +**Kind**: instance method of [Service](#Service) +**Returns**: Promise - Resolves upon successful registration. | Param | Type | Description | | --- | --- | --- | -| passphrase | String | BIP 39 passphrase for key derivation. | +| actor | Object | Instance of the [Actor](#Actor). | - + -### Wallet.fromSeed(seed) ⇒ [Wallet](#Wallet) -Create a new [Wallet](#Wallet) from a seed object. +### service.\_send(message) +Sends a message. -**Kind**: static method of [Wallet](#Wallet) -**Returns**: [Wallet](#Wallet) - Instance of the wallet. +**Kind**: instance method of [Service](#Service) | Param | Type | Description | | --- | --- | --- | -| seed | FabricSeed | Fabric seed. | +| message | Mixed | Message to send. | - + -## Worker -Workers are arbitrary containers for processing data. They can be thought of -almost like "threads", as they run asynchronously over the duration of a -contract's lifetime as "fulfillment conditions" for its closure. +## Session +The [Session](#Session) type describes a connection between [Peer](#Peer) +objects, and includes its own lifecycle. **Kind**: global class -* [Worker](#Worker) - * [new Worker(method)](#new_Worker_new) - * [.compute(input)](#Worker+compute) ⇒ String +* [Session](#Session) + * [new Session(settings)](#new_Session_new) + * [.start()](#Session+start) + * [.stop()](#Session+stop) - + -### new Worker(method) +### new Session(settings) +Creates a new [Session](#Session). -| Param | Type | Description | -| --- | --- | --- | -| method | function | Pure function. | - +| Param | Type | +| --- | --- | +| settings | Object | -### worker.compute(input) ⇒ String -Handle a task. + -**Kind**: instance method of [Worker](#Worker) -**Returns**: String - Outcome of the requested job. +### session.start() +Opens the [Session](#Session) for interaction. -| Param | Type | Description | -| --- | --- | --- | -| input | [Vector](#Vector) | Input vector. | +**Kind**: instance method of [Session](#Session) + - +### session.stop() +Closes the [Session](#Session), preventing further interaction. -## Bitcoin ⇐ [Service](#Service) -Manages interaction with the Bitcoin network. +**Kind**: instance method of [Session](#Session) + + +## Snapshot +A type of message to be expected from a [Service](#Service). **Kind**: global class -**Extends**: [Service](#Service) -* [Bitcoin](#Bitcoin) ⇐ [Service](#Service) - * [new Bitcoin([settings])](#new_Bitcoin_new) - * _instance_ - * [.UAString](#Bitcoin+UAString) - * [.tip](#Bitcoin+tip) - * [.height](#Bitcoin+height) - * [.broadcast(tx)](#Bitcoin+broadcast) - * [._processSpendMessage(message)](#Bitcoin+_processSpendMessage) ⇒ BitcoinTransactionID - * [._prepareTransaction(obj)](#Bitcoin+_prepareTransaction) - * [._handleCommittedBlock(block)](#Bitcoin+_handleCommittedBlock) - * [._handlePeerPacket(msg)](#Bitcoin+_handlePeerPacket) - * [._handleBlockFromSPV(msg)](#Bitcoin+_handleBlockFromSPV) - * [._handleTransactionFromSPV(tx)](#Bitcoin+_handleTransactionFromSPV) - * [._subscribeToShard(shard)](#Bitcoin+_subscribeToShard) - * [._connectSPV()](#Bitcoin+_connectSPV) - * [.connect(addr)](#Bitcoin+connect) - * [._requestBlockAtHeight(height)](#Bitcoin+_requestBlockAtHeight) ⇒ Object - * [._createContractProposal(options)](#Bitcoin+_createContractProposal) ⇒ ContractProposal - * [._buildPSBT(options)](#Bitcoin+_buildPSBT) ⇒ PSBT - * [.start()](#Bitcoin+start) - * [.stop()](#Bitcoin+stop) - * [.init()](#Service+init) - * [.tick()](#Service+tick) ⇒ Number - * [.beat()](#Service+beat) ⇒ [Service](#Service) - * [.get(path)](#Service+get) ⇒ Mixed - * [.set(path)](#Service+set) ⇒ Mixed - * [.trust(source)](#Service+trust) ⇒ [Service](#Service) - * [.handler(message)](#Service+handler) ⇒ [Service](#Service) - * [.lock([duration])](#Service+lock) ⇒ Boolean - * [.route(msg)](#Service+route) ⇒ Promise - * [._GET(path)](#Service+_GET) ⇒ Promise - * [._PUT(path, value, [commit])](#Service+_PUT) ⇒ Promise - * [.send(channel, message)](#Service+send) ⇒ [Service](#Service) - * [._registerActor(actor)](#Service+_registerActor) ⇒ Promise - * [._send(message)](#Service+_send) - * _static_ - * ~~[.Transaction](#Bitcoin.Transaction)~~ - * ~~[.MutableTransaction](#Bitcoin.MutableTransaction)~~ +* [Snapshot](#Snapshot) + * [new Snapshot(settings)](#new_Snapshot_new) + * [.commit()](#Snapshot+commit) - + -### new Bitcoin([settings]) -Creates an instance of the Bitcoin service. +### new Snapshot(settings) +Creates an instance of a [Snapshot](#Snapshot). | Param | Type | Description | | --- | --- | --- | -| [settings] | Object | Map of configuration options for the Bitcoin service. | -| [settings.network] | String | One of `regtest`, `testnet`, or `mainnet`. | -| [settings.nodes] | Array | List of address:port pairs to trust. | -| [settings.seeds] | Array | Bitcoin peers to request chain from (address:port). | -| [settings.fullnode] | Boolean | Run a full node. | +| settings | Object | Map of settings to configure the [Snapshot](#Snapshot) with. | - + -### bitcoin.UAString -User Agent string for the Bitcoin P2P network. +### snapshot.commit() +Retrieves the `sha256` fingerprint for the [Snapshot](#Snapshot) state. -**Kind**: instance property of [Bitcoin](#Bitcoin) - +**Kind**: instance method of [Snapshot](#Snapshot) + -### bitcoin.tip -Chain tip (block hash of the chain with the most Proof of Work) +## Stack +Manage stacks of data. -**Kind**: instance property of [Bitcoin](#Bitcoin) - +**Kind**: global class + +* [Stack](#Stack) + * [new Stack([list])](#new_Stack_new) + * [.push(data)](#Stack+push) ⇒ Number + + + +### new Stack([list]) +Create a [Stack](#Stack) instance. -### bitcoin.height -Chain height (`=== length - 1`) +**Returns**: [Stack](#Stack) - Instance of the [Stack](#Stack). -**Kind**: instance property of [Bitcoin](#Bitcoin) - +| Param | Type | Default | Description | +| --- | --- | --- | --- | +| [list] | Array | [] | Genesis state for the [Stack](#Stack) instance. | -### bitcoin.broadcast(tx) -Broadcast a transaction to the Bitcoin network. + -**Kind**: instance method of [Bitcoin](#Bitcoin) -**Unstable**: +### stack.push(data) ⇒ Number +Push data onto the stack. Changes the [Stack#frame](Stack#frame) and +[Stack#id](Stack#id). + +**Kind**: instance method of [Stack](#Stack) +**Returns**: Number - Resulting size of the stack. | Param | Type | Description | | --- | --- | --- | -| tx | TX | Bitcoin transaction | +| data | Mixed | Treated as a [State](#State). | - + -### bitcoin.\_processSpendMessage(message) ⇒ BitcoinTransactionID -Process a spend message. +## State ⇐ EventEmitter +The [State](#State) is the core of most [User](User)-facing interactions. To +interact with the [User](User), simply propose a change in the state by +committing to the outcome. This workflow keeps app design quite simple! -**Kind**: instance method of [Bitcoin](#Bitcoin) -**Returns**: BitcoinTransactionID - Hex-encoded representation of the transaction ID. +**Kind**: global class +**Extends**: EventEmitter +**Access**: protected +**Properties** -| Param | Type | Description | +| Name | Type | Description | | --- | --- | --- | -| message | SpendMessage | Generic-level message for spending. | -| message.amount | String | Amount (in BTC) to spend. | -| message.destination | String | Destination for funds. | +| size | Number | Size of state in bytes. | +| @buffer | Buffer | Byte-for-byte memory representation of state. | +| @type | String | Named type. | +| @data | Mixed | Local instance of the state. | +| @id | String | Unique identifier for this data. | - -### bitcoin.\_prepareTransaction(obj) -Prepares a [Transaction](Transaction) for storage. +* [State](#State) ⇐ EventEmitter + * [new State(data)](#new_State_new) + * _instance_ + * [.toHTML()](#State+toHTML) + * [.toString()](#State+toString) ⇒ String + * [.serialize([input])](#State+serialize) ⇒ Buffer + * [.deserialize(input)](#State+deserialize) ⇒ [State](#State) + * [.fork()](#State+fork) ⇒ [State](#State) + * [.get(path)](#State+get) ⇒ Mixed + * [.set(path)](#State+set) ⇒ Mixed + * [.commit()](#State+commit) + * [.render()](#State+render) ⇒ String + * _static_ + * [.fromJSON(input)](#State.fromJSON) ⇒ [State](#State) -**Kind**: instance method of [Bitcoin](#Bitcoin) + + +### new State(data) +Creates a snapshot of some information. + +**Returns**: [State](#State) - Resulting state. | Param | Type | Description | | --- | --- | --- | -| obj | Transaction | Transaction to prepare. | +| data | Mixed | Input data. | - + -### bitcoin.\_handleCommittedBlock(block) -Receive a committed block. +### state.toHTML() +Converts the State to an HTML document. -**Kind**: instance method of [Bitcoin](#Bitcoin) +**Kind**: instance method of [State](#State) + -| Param | Type | Description | -| --- | --- | --- | -| block | Block | Block to handle. | +### state.toString() ⇒ String +Unmarshall an existing state to an instance of a [Blob](Blob). - +**Kind**: instance method of [State](#State) +**Returns**: String - Serialized [Blob](Blob). + -### bitcoin.\_handlePeerPacket(msg) -Process a message from a peer in the Bitcoin network. +### state.serialize([input]) ⇒ Buffer +Convert to [Buffer](Buffer). -**Kind**: instance method of [Bitcoin](#Bitcoin) +**Kind**: instance method of [State](#State) +**Returns**: Buffer - [Store](#Store)-able blob. | Param | Type | Description | | --- | --- | --- | -| msg | PeerPacket | Message from peer. | +| [input] | Mixed | Input to serialize. | - + -### bitcoin.\_handleBlockFromSPV(msg) -Hand a [Block](Block) message as supplied by an [SPV](SPV) client. +### state.deserialize(input) ⇒ [State](#State) +Take a hex-encoded input and convert to a [State](#State) object. -**Kind**: instance method of [Bitcoin](#Bitcoin) +**Kind**: instance method of [State](#State) +**Returns**: [State](#State) - [description] | Param | Type | Description | | --- | --- | --- | -| msg | BlockMessage | A [Message](#Message) as passed by the [SPV](SPV) source. | +| input | String | [description] | - + -### bitcoin.\_handleTransactionFromSPV(tx) -Verify and interpret a [BitcoinTransaction](BitcoinTransaction), as received from an -[SPVSource](SPVSource). +### state.fork() ⇒ [State](#State) +Creates a new child [State](#State), with `@parent` set to +the current [State](#State) by immutable identifier. -**Kind**: instance method of [Bitcoin](#Bitcoin) +**Kind**: instance method of [State](#State) + + +### state.get(path) ⇒ Mixed +Retrieve a key from the [State](#State). + +**Kind**: instance method of [State](#State) | Param | Type | Description | | --- | --- | --- | -| tx | BitcoinTransaction | Incoming transaction from the SPV source. | +| path | Path | Key to retrieve. | - + -### bitcoin.\_subscribeToShard(shard) -Attach event handlers for a supplied list of addresses. +### state.set(path) ⇒ Mixed +Set a key in the [State](#State) to a particular value. -**Kind**: instance method of [Bitcoin](#Bitcoin) +**Kind**: instance method of [State](#State) | Param | Type | Description | | --- | --- | --- | -| shard | Shard | List of addresses to monitor. | - - - -### bitcoin.\_connectSPV() -Initiate outbound connections to configured SPV nodes. +| path | Path | Key to retrieve. | -**Kind**: instance method of [Bitcoin](#Bitcoin) - + -### bitcoin.connect(addr) -Connect to a Fabric [Peer](#Peer). +### state.commit() +Increment the vector clock, broadcast all changes as a transaction. -**Kind**: instance method of [Bitcoin](#Bitcoin) -**Overrides**: [connect](#Service+connect) +**Kind**: instance method of [State](#State) + -| Param | Type | Description | -| --- | --- | --- | -| addr | String | Address to connect to. | +### state.render() ⇒ String +Compose a JSON string for network consumption. - +**Kind**: instance method of [State](#State) +**Returns**: String - JSON-encoded [String](String). + -### bitcoin.\_requestBlockAtHeight(height) ⇒ Object -Retrieve the equivalent to `getblockhash` from Bitcoin Core. +### State.fromJSON(input) ⇒ [State](#State) +Marshall an input into an instance of a [State](#State). States have +absolute authority over their own domain, so choose your States wisely. -**Kind**: instance method of [Bitcoin](#Bitcoin) -**Returns**: Object - The block hash. +**Kind**: static method of [State](#State) +**Returns**: [State](#State) - Resulting instance of the [State](#State). | Param | Type | Description | | --- | --- | --- | -| height | Number | Height of block to retrieve. | - - +| input | String | Arbitrary input. | -### bitcoin.\_createContractProposal(options) ⇒ ContractProposal -Creates an unsigned Bitcoin transaction. + -**Kind**: instance method of [Bitcoin](#Bitcoin) -**Returns**: ContractProposal - Instance of the proposal. +## Store +Long-term storage. -| Param | Type | -| --- | --- | -| options | Object | +**Kind**: global class +**Properties** - +| Name | Type | Description | +| --- | --- | --- | +| settings | Mixed | Current configuration. | -### bitcoin.\_buildPSBT(options) ⇒ PSBT -Create a Partially-Signed Bitcoin Transaction (PSBT). -**Kind**: instance method of [Bitcoin](#Bitcoin) -**Returns**: PSBT - Instance of the PSBT. +* [Store](#Store) + * [new Store([settings])](#new_Store_new) + * [._REGISTER(obj)](#Store+_REGISTER) ⇒ [Vector](#Vector) + * [._POST(key, value)](#Store+_POST) ⇒ Promise + * [.get(key)](#Store+get) ⇒ Promise + * [.set(key, value)](#Store+set) + * [.trust(source)](#Store+trust) ⇒ [Store](#Store) + * [.del(key)](#Store+del) + * [.flush()](#Store+flush) + * [.start()](#Store+start) ⇒ Promise -| Param | Type | Description | -| --- | --- | --- | -| options | Object | Parameters for the PSBT. | + - +### new Store([settings]) +Create an instance of a [Store](#Store) to manage long-term storage, which is +particularly useful when building a user-facing [Product](Product). -### bitcoin.start() -Start the Bitcoin service, including the initiation of outbound requests. +**Returns**: [Store](#Store) - Instance of the Store, ready to start. -**Kind**: instance method of [Bitcoin](#Bitcoin) -**Overrides**: [start](#Service+start) - +| Param | Type | Default | Description | +| --- | --- | --- | --- | +| [settings] | Object | {} | configuration object. | -### bitcoin.stop() -Stop the Bitcoin service. + -**Kind**: instance method of [Bitcoin](#Bitcoin) - +### store.\_REGISTER(obj) ⇒ [Vector](#Vector) +Registers an [Actor](#Actor). Necessary to store in a collection. -### bitcoin.init() -Called by Web Components. -TODO: move to @fabric/http/types/spa +**Kind**: instance method of [Store](#Store) +**Returns**: [Vector](#Vector) - Returned from `storage.set` -**Kind**: instance method of [Bitcoin](#Bitcoin) -**Overrides**: [init](#Service+init) - +| Param | Type | Description | +| --- | --- | --- | +| obj | Object | Instance of the object to store. | -### bitcoin.tick() ⇒ Number -Move forward one clock cycle. + -**Kind**: instance method of [Bitcoin](#Bitcoin) -**Overrides**: [tick](#Service+tick) - +### store.\_POST(key, value) ⇒ Promise +Insert something into a collection. -### bitcoin.beat() ⇒ [Service](#Service) -Compute latest state. +**Kind**: instance method of [Store](#Store) +**Returns**: Promise - Resolves on success with a String pointer. -**Kind**: instance method of [Bitcoin](#Bitcoin) -**Overrides**: [beat](#Service+beat) -**Emits**: Message#event:beat - +| Param | Type | Description | +| --- | --- | --- | +| key | String | Path to add data to. | +| value | Mixed | Object to store. | -### bitcoin.get(path) ⇒ Mixed -Retrieve a key from the [State](#State). + -**Kind**: instance method of [Bitcoin](#Bitcoin) -**Overrides**: [get](#Service+get) +### store.get(key) ⇒ Promise +Barebones getter. + +**Kind**: instance method of [Store](#Store) +**Returns**: Promise - Resolves on complete. `null` if not found. | Param | Type | Description | | --- | --- | --- | -| path | [Path](#Path) | Key to retrieve. | +| key | String | Name of data to retrieve. | - + -### bitcoin.set(path) ⇒ Mixed -Set a key in the [State](#State) to a particular value. +### store.set(key, value) +Set a `key` to a specific `value`. -**Kind**: instance method of [Bitcoin](#Bitcoin) -**Overrides**: [set](#Service+set) +**Kind**: instance method of [Store](#Store) | Param | Type | Description | | --- | --- | --- | -| path | [Path](#Path) | Key to retrieve. | +| key | String | Address of the information. | +| value | Mixed | Content to store at `key`. | - + -### bitcoin.trust(source) ⇒ [Service](#Service) -Explicitly trust all events from a known source. +### store.trust(source) ⇒ [Store](#Store) +Implicitly trust an [Event](Event) source. -**Kind**: instance method of [Bitcoin](#Bitcoin) -**Overrides**: [trust](#Service+trust) -**Returns**: [Service](#Service) - Instance of Service after binding events. +**Kind**: instance method of [Store](#Store) +**Returns**: [Store](#Store) - Resulting instance of [Store](#Store) with new trust. | Param | Type | Description | | --- | --- | --- | -| source | EventEmitter | Emitter of events. | +| source | EventEmitter | Event-emitting source. | - + -### bitcoin.handler(message) ⇒ [Service](#Service) -Default route handler for an incoming message. Follows the Activity -Streams 2.0 spec: https://www.w3.org/TR/activitystreams-core/ +### store.del(key) +Remove a [Value](#Value) by [Path](Path). -**Kind**: instance method of [Bitcoin](#Bitcoin) -**Overrides**: [handler](#Service+handler) -**Returns**: [Service](#Service) - Chainable method. +**Kind**: instance method of [Store](#Store) | Param | Type | Description | | --- | --- | --- | -| message | Activity | Message object. | +| key | Path | Key to remove. | - + -### bitcoin.lock([duration]) ⇒ Boolean -Attempt to acquire a lock for `duration` seconds. +### store.flush() +Wipes the storage. -**Kind**: instance method of [Bitcoin](#Bitcoin) -**Overrides**: [lock](#Service+lock) -**Returns**: Boolean - true if locked, false if unable to lock. +**Kind**: instance method of [Store](#Store) + -| Param | Type | Default | Description | -| --- | --- | --- | --- | -| [duration] | Number | 1000 | Number of milliseconds to hold lock. | +### store.start() ⇒ Promise +Start running the process. - +**Kind**: instance method of [Store](#Store) +**Returns**: Promise - Resolves on complete. + -### bitcoin.route(msg) ⇒ Promise -Resolve a [State](#State) from a particular [Message](#Message) object. +## Swarm : String +Orchestrates a network of peers. -**Kind**: instance method of [Bitcoin](#Bitcoin) -**Overrides**: [route](#Service+route) -**Returns**: Promise - Resolves with resulting [State](#State). +**Kind**: global class + +* [Swarm](#Swarm) : String + * [new Swarm(config)](#new_Swarm_new) + * [.trust(source)](#Swarm+trust) + * [.start()](#Swarm+start) ⇒ Promise + + + +### new Swarm(config) +Create an instance of a [Swarm](#Swarm). + +**Returns**: [Swarm](#Swarm) - Instance of the Swarm. | Param | Type | Description | | --- | --- | --- | -| msg | [Message](#Message) | Explicit Fabric [Message](#Message). | +| config | Object | Configuration object. | - + -### bitcoin.\_GET(path) ⇒ Promise -Retrieve a value from the Service's state. +### swarm.trust(source) +Explicitly trust an [EventEmitter](EventEmitter) to provide messages using +the expected [Interface](#Interface), providing [Message](#Message) objects as +the expected [Type](Type). -**Kind**: instance method of [Bitcoin](#Bitcoin) -**Overrides**: [\_GET](#Service+_GET) -**Returns**: Promise - Resolves with the result. +**Kind**: instance method of [Swarm](#Swarm) | Param | Type | Description | | --- | --- | --- | -| path | String | Path of the value to retrieve. | +| source | EventEmitter | [Actor](#Actor) to utilize. | - + -### bitcoin.\_PUT(path, value, [commit]) ⇒ Promise -Store a value in the Service's state. +### swarm.start() ⇒ Promise +Begin computing. -**Kind**: instance method of [Bitcoin](#Bitcoin) -**Overrides**: [\_PUT](#Service+_PUT) -**Returns**: Promise - Resolves with with stored document. +**Kind**: instance method of [Swarm](#Swarm) +**Returns**: Promise - Resolves to instance of [Swarm](#Swarm). + -| Param | Type | Default | Description | -| --- | --- | --- | --- | -| path | String | | Path to store the value at. | -| value | Object | | Document to store. | -| [commit] | Boolean | false | Sign the resulting state. | +## Token +Implements a capability-based security token. - +**Kind**: global class + -### bitcoin.send(channel, message) ⇒ [Service](#Service) -Send a message to a channel. +### new Token([settings]) +Create a new Fabric Token. -**Kind**: instance method of [Bitcoin](#Bitcoin) -**Overrides**: [send](#Service+send) -**Returns**: [Service](#Service) - Chainable method. +**Returns**: [Token](#Token) - The token instance. | Param | Type | Description | | --- | --- | --- | -| channel | String | Channel name to which the message will be sent. | -| message | String | Content of the message to send. | +| [settings] | Object | Configuration. | - + -### bitcoin.\_registerActor(actor) ⇒ Promise -Register an [Actor](#Actor) with the [Service](#Service). +## Tree +Class implementing a Merkle Tree. -**Kind**: instance method of [Bitcoin](#Bitcoin) -**Overrides**: [\_registerActor](#Service+_registerActor) -**Returns**: Promise - Resolves upon successful registration. +**Kind**: global class -| Param | Type | Description | -| --- | --- | --- | -| actor | Object | Instance of the [Actor](#Actor). | +* [Tree](#Tree) + * [new Tree([settings])](#new_Tree_new) + * [.addLeaf(leaf)](#Tree+addLeaf) ⇒ [Tree](#Tree) + * [.getLeaves()](#Tree+getLeaves) ⇒ Array - + -### bitcoin.\_send(message) -Sends a message. +### new Tree([settings]) +Create an instance of a Tree. -**Kind**: instance method of [Bitcoin](#Bitcoin) -**Overrides**: [\_send](#Service+_send) +**Returns**: [Tree](#Tree) - Instance of the tree. | Param | Type | Description | | --- | --- | --- | -| message | Mixed | Message to send. | +| [settings] | Object | Configuration. | - + -### ~~Bitcoin.Transaction~~ -***Deprecated*** +### tree.addLeaf(leaf) ⇒ [Tree](#Tree) +Add a leaf to the tree. -Provides bcoin's implementation of `TX` internally. This static may be -removed in the future. +**Kind**: instance method of [Tree](#Tree) +**Returns**: [Tree](#Tree) - Instance of the tree. -**Kind**: static property of [Bitcoin](#Bitcoin) - +| Param | Type | Description | +| --- | --- | --- | +| leaf | String | Leaf to add to the tree. | -### ~~Bitcoin.MutableTransaction~~ -***Deprecated*** + -Provides bcoin's implementation of `MTX` internally. This static may be -removed in the future. +### tree.getLeaves() ⇒ Array +Get a list of the [Tree](#Tree)'s leaves. -**Kind**: static property of [Bitcoin](#Bitcoin) - +**Kind**: instance method of [Tree](#Tree) +**Returns**: Array - A list of the [Tree](#Tree)'s leaves. + -## Exchange -Implements a basic Exchange. +## Value +[Number](Number)-like type. **Kind**: global class - -### new Exchange(settings) -Create an instance of the Exchange. You may run two instances at -once to simulate two-party contracts, or use the Fabric Market to -find and trade with real peers. +* [Value](#Value) + * [new Value(data)](#new_Value_new) + * [.value(input)](#Value+value) + + + +### new Value(data) +Use the [Value](#Value) type to interact with [Number](Number)-like objects. -**Returns**: Exchnge | Param | Type | Description | | --- | --- | --- | -| settings | Object | Map of settings to values. | -| settings.fees | Object | Map of fee settings (all values in BTC). | -| settings.fees.minimum | Object | Minimum fee (satoshis). | +| data | Mixed | Input value. | - + -## Lightning -Manage a Lightning node. +### value.value(input) +Compute the numeric representation of this input. + +**Kind**: instance method of [Value](#Value) + +| Param | Type | Description | +| --- | --- | --- | +| input | String | Input string to seek for value. | + + +## Vector **Kind**: global class -* [Lightning](#Lightning) - * [new Lightning([settings])](#new_Lightning_new) - * [._makeRPCRequest(method, [params])](#Lightning+_makeRPCRequest) ⇒ Object \| String +* [Vector](#Vector) + * [new Vector(origin)](#new_Vector_new) + * [._serialize(input)](#Vector+_serialize) ⇒ String + * [.toString(input)](#Vector+toString) ⇒ String - + -### new Lightning([settings]) -Create an instance of the Lightning [Service](#Service). +### new Vector(origin) +An "Initialization" Vector. | Param | Type | Description | | --- | --- | --- | -| [settings] | Object | Settings. | +| origin | Object | Input state (will map to `@data`.) | - + -### lightning.\_makeRPCRequest(method, [params]) ⇒ Object \| String -Make an RPC request through the Lightning UNIX socket. +### vector.\_serialize(input) ⇒ String +_serialize is a placeholder, should be discussed. -**Kind**: instance method of [Lightning](#Lightning) -**Returns**: Object \| String - Respond from the Lightning node. +**Kind**: instance method of [Vector](#Vector) +**Returns**: String - - resulting string [JSON-encoded version of the local `@data` value.] | Param | Type | Description | | --- | --- | --- | -| method | String | Name of method to call. | -| [params] | Array | Array of parameters. | +| input | String | What to serialize. Defaults to `this.state`. | - + -## Redis -Connect and subscribe to ZeroMQ servers. +### vector.toString(input) ⇒ String +Render the output to a [String](String). + +**Kind**: instance method of [Vector](#Vector) + +| Param | Type | Description | +| --- | --- | --- | +| input | Mixed | Arbitrary input. | + + +## Walker **Kind**: global class -* [Redis](#Redis) - * [new Redis([settings])](#new_Redis_new) - * [.start()](#Redis+start) ⇒ [Redis](#Redis) - * [.stop()](#Redis+stop) ⇒ [Redis](#Redis) +* [Walker](#Walker) + * [new Walker(init)](#new_Walker_new) + * [._explore(path, [map])](#Walker+_explore) ⇒ Object + * [._define(dir, [map])](#Walker+_define) ⇒ Object - + -### new Redis([settings]) -Creates an instance of a ZeroMQ subscriber. +### new Walker(init) +The Walker explores a directory tree and maps it to memory. -**Returns**: [Redis](#Redis) - Instance of the Redis service, ready to run `start()` | Param | Type | Description | | --- | --- | --- | -| [settings] | Object | Settings for the Redis connection. | -| [settings.host] | String | Host for the Redis server. | -| [settings.port] | Number | Remote ZeroMQ service port. | +| init | [Vector](#Vector) | Initial state tree. | - + -### redis.start() ⇒ [Redis](#Redis) -Opens the connection and subscribes to the requested channels. +### walker.\_explore(path, [map]) ⇒ Object +Explores a directory tree on the local system's disk. -**Kind**: instance method of [Redis](#Redis) -**Returns**: [Redis](#Redis) - Instance of the service. - +**Kind**: instance method of [Walker](#Walker) +**Returns**: Object - [description] -### redis.stop() ⇒ [Redis](#Redis) -Closes the connection to the Redis server. +| Param | Type | Default | Description | +| --- | --- | --- | --- | +| path | String | | [description] | +| [map] | Object | {} | [description] | -**Kind**: instance method of [Redis](#Redis) -**Returns**: [Redis](#Redis) - Instance of the service. - + -## ZMQ -Connect and subscribe to ZeroMQ publishers. +### walker.\_define(dir, [map]) ⇒ Object +Explores a directory tree on the local system's disk. -**Kind**: global class +**Kind**: instance method of [Walker](#Walker) +**Returns**: Object - A hashmap of directory contents. -* [ZMQ](#ZMQ) - * [new ZMQ([settings])](#new_ZMQ_new) - * [.start()](#ZMQ+start) ⇒ [ZMQ](#ZMQ) - * [.stop()](#ZMQ+stop) ⇒ [ZMQ](#ZMQ) +| Param | Type | Default | Description | +| --- | --- | --- | --- | +| dir | String | | Path to crawl on local disk. | +| [map] | Object | {} | Pointer to previous step in stack. | - + -### new ZMQ([settings]) -Creates an instance of a ZeroMQ subscriber. +## Wallet : Object +Manage keys and track their balances. -**Returns**: [ZMQ](#ZMQ) - Instance of the ZMQ service, ready to run `start()` +**Kind**: global class +**Properties** -| Param | Type | Description | +| Name | Type | Description | | --- | --- | --- | -| [settings] | Object | Settings for the ZMQ connection. | -| [settings.host] | String | Host for the ZMQ publisher. | -| [settings.port] | Number | Remote ZeroMQ service port. | +| id | String | Unique identifier for this [Wallet](#Wallet). | - -### zmQ.start() ⇒ [ZMQ](#ZMQ) -Opens the connection and subscribes to the requested channels. +* [Wallet](#Wallet) : Object + * [new Wallet([settings])](#new_Wallet_new) + * _instance_ + * [.start()](#Wallet+start) + * [.getAddressForScript(script)](#Wallet+getAddressForScript) + * [.getAddressFromRedeemScript(redeemScript)](#Wallet+getAddressFromRedeemScript) + * [._sign(tx)](#Wallet+_sign) + * [._createCrowdfund(fund)](#Wallet+_createCrowdfund) + * [._getSwapInputScript(redeemScript, secret)](#Wallet+_getSwapInputScript) + * [._getRefundInputScript(redeemScript)](#Wallet+_getRefundInputScript) + * [.publicKeyFromString(input)](#Wallet+publicKeyFromString) + * _static_ + * [.createSeed(passphrase)](#Wallet.createSeed) ⇒ FabricSeed + * [.fromSeed(seed)](#Wallet.fromSeed) ⇒ [Wallet](#Wallet) -**Kind**: instance method of [ZMQ](#ZMQ) -**Returns**: [ZMQ](#ZMQ) - Instance of the service. - + -### zmQ.stop() ⇒ [ZMQ](#ZMQ) -Closes the connection to the ZMQ publisher. +### new Wallet([settings]) +Create an instance of a [Wallet](#Wallet). -**Kind**: instance method of [ZMQ](#ZMQ) -**Returns**: [ZMQ](#ZMQ) - Instance of the service. - +**Returns**: [Wallet](#Wallet) - Instance of the wallet. -## ~~HTTPServer~~ -***Deprecated*** +| Param | Type | Default | Description | +| --- | --- | --- | --- | +| [settings] | Object | {} | Configure the wallet. | +| [settings.verbosity] | Number | 2 | One of: 0 (none), 1 (error), 2 (warning), 3 (notice), 4 (debug), 5 (audit) | +| [settings.key] | Object | | Key to restore from. | +| [settings.key.seed] | String | | Mnemonic seed for a restored wallet. | -Deprecated 2021-10-16. + -**Kind**: global class - +### wallet.start() +Start the wallet, including listening for transactions. -## ~~Scribe~~ -***Deprecated*** +**Kind**: instance method of [Wallet](#Wallet) + -Deprecated 2021-11-06. +### wallet.getAddressForScript(script) +Returns a bech32 address for the provided [Script](#Script). -**Kind**: global class +**Kind**: instance method of [Wallet](#Wallet) -* ~~[Scribe](#Scribe)~~ - * [new Scribe(config)](#new_Scribe_new) - * [.now()](#Scribe+now) ⇒ Number - * [.trust(source)](#Scribe+trust) ⇒ [Scribe](#Scribe) - * [.inherits(scribe)](#Scribe+inherits) ⇒ [Scribe](#Scribe) - * [.toHTML()](#State+toHTML) - * [.toString()](#State+toString) ⇒ String - * [.serialize([input])](#State+serialize) ⇒ Buffer - * [.deserialize(input)](#State+deserialize) ⇒ [State](#State) - * [.fork()](#State+fork) ⇒ [State](#State) - * [.get(path)](#State+get) ⇒ Mixed - * [.set(path)](#State+set) ⇒ Mixed - * [.commit()](#State+commit) - * [.render()](#State+render) ⇒ String +| Param | Type | +| --- | --- | +| script | [Script](#Script) | - + -### new Scribe(config) -The "Scribe" is a simple tag-based recordkeeper. +### wallet.getAddressFromRedeemScript(redeemScript) +Generate a [BitcoinAddress](BitcoinAddress) for the supplied [BitcoinScript](BitcoinScript). +**Kind**: instance method of [Wallet](#Wallet) -| Param | Type | Description | -| --- | --- | --- | -| config | Object | General configuration object. | -| config.verbose | Boolean | Should the Scribe be noisy? | +| Param | Type | +| --- | --- | +| redeemScript | BitcoinScript | - + -### scribe.now() ⇒ Number -Retrives the current timestamp, in milliseconds. +### wallet.\_sign(tx) +Signs a transaction with the keyring. -**Kind**: instance method of [Scribe](#Scribe) -**Returns**: Number - [Number](Number) representation of the millisecond [Integer](Integer) value. - +**Kind**: instance method of [Wallet](#Wallet) -### scribe.trust(source) ⇒ [Scribe](#Scribe) -Blindly bind event handlers to the [Source](Source). +| Param | Type | +| --- | --- | +| tx | BcoinTX | -**Kind**: instance method of [Scribe](#Scribe) -**Returns**: [Scribe](#Scribe) - Instance of the [Scribe](#Scribe). + -| Param | Type | Description | -| --- | --- | --- | -| source | Source | Event stream. | +### wallet.\_createCrowdfund(fund) +Create a crowdfunding transaction. - +**Kind**: instance method of [Wallet](#Wallet) -### scribe.inherits(scribe) ⇒ [Scribe](#Scribe) -Use an existing Scribe instance as a parent. +| Param | Type | +| --- | --- | +| fund | Object | -**Kind**: instance method of [Scribe](#Scribe) -**Returns**: [Scribe](#Scribe) - The configured instance of the Scribe. + -| Param | Type | Description | -| --- | --- | --- | -| scribe | [Scribe](#Scribe) | Instance of Scribe to use as parent. | +### wallet.\_getSwapInputScript(redeemScript, secret) +Generate [Script](#Script) for claiming a [Swap](Swap). - +**Kind**: instance method of [Wallet](#Wallet) -### scribe.toHTML() -Converts the State to an HTML document. +| Param | Type | +| --- | --- | +| redeemScript | \* | +| secret | \* | -**Kind**: instance method of [Scribe](#Scribe) -**Overrides**: [toHTML](#State+toHTML) - + -### scribe.toString() ⇒ String -Unmarshall an existing state to an instance of a [Blob](Blob). +### wallet.\_getRefundInputScript(redeemScript) +Generate [Script](#Script) for reclaiming funds commited to a [Swap](Swap). -**Kind**: instance method of [Scribe](#Scribe) -**Overrides**: [toString](#State+toString) -**Returns**: String - Serialized [Blob](Blob). - +**Kind**: instance method of [Wallet](#Wallet) -### scribe.serialize([input]) ⇒ Buffer -Convert to [Buffer](Buffer). +| Param | Type | +| --- | --- | +| redeemScript | \* | -**Kind**: instance method of [Scribe](#Scribe) -**Overrides**: [serialize](#State+serialize) -**Returns**: Buffer - [Store](#Store)-able blob. + + +### wallet.publicKeyFromString(input) +Create a public key from a string. + +**Kind**: instance method of [Wallet](#Wallet) | Param | Type | Description | | --- | --- | --- | -| [input] | Mixed | Input to serialize. | +| input | String | Hex-encoded string to create key from. | - + -### scribe.deserialize(input) ⇒ [State](#State) -Take a hex-encoded input and convert to a [State](#State) object. +### Wallet.createSeed(passphrase) ⇒ FabricSeed +Create a new seed phrase. -**Kind**: instance method of [Scribe](#Scribe) -**Overrides**: [deserialize](#State+deserialize) -**Returns**: [State](#State) - [description] +**Kind**: static method of [Wallet](#Wallet) +**Returns**: FabricSeed - The seed object. | Param | Type | Description | | --- | --- | --- | -| input | String | [description] | - - - -### scribe.fork() ⇒ [State](#State) -Creates a new child [State](#State), with `@parent` set to -the current [State](#State) by immutable identifier. +| passphrase | String | BIP 39 passphrase for key derivation. | -**Kind**: instance method of [Scribe](#Scribe) -**Overrides**: [fork](#State+fork) - + -### scribe.get(path) ⇒ Mixed -Retrieve a key from the [State](#State). +### Wallet.fromSeed(seed) ⇒ [Wallet](#Wallet) +Create a new [Wallet](#Wallet) from a seed object. -**Kind**: instance method of [Scribe](#Scribe) -**Overrides**: [get](#State+get) +**Kind**: static method of [Wallet](#Wallet) +**Returns**: [Wallet](#Wallet) - Instance of the wallet. | Param | Type | Description | | --- | --- | --- | -| path | [Path](#Path) | Key to retrieve. | +| seed | FabricSeed | Fabric seed. | - + -### scribe.set(path) ⇒ Mixed -Set a key in the [State](#State) to a particular value. +## Worker +Workers are arbitrary containers for processing data. They can be thought of +almost like "threads", as they run asynchronously over the duration of a +contract's lifetime as "fulfillment conditions" for its closure. -**Kind**: instance method of [Scribe](#Scribe) -**Overrides**: [set](#State+set) +**Kind**: global class -| Param | Type | Description | -| --- | --- | --- | -| path | [Path](#Path) | Key to retrieve. | +* [Worker](#Worker) + * [new Worker(method)](#new_Worker_new) + * [.compute(input)](#Worker+compute) ⇒ String - + -### scribe.commit() -Increment the vector clock, broadcast all changes as a transaction. +### new Worker(method) -**Kind**: instance method of [Scribe](#Scribe) -**Overrides**: [commit](#State+commit) - +| Param | Type | Description | +| --- | --- | --- | +| method | function | Pure function. | -### scribe.render() ⇒ String -Compose a JSON string for network consumption. + -**Kind**: instance method of [Scribe](#Scribe) -**Overrides**: [render](#State+render) -**Returns**: String - JSON-encoded [String](String). - +### worker.compute(input) ⇒ String +Handle a task. -## ~~Stash~~ -***Deprecated*** +**Kind**: instance method of [Worker](#Worker) +**Returns**: String - Outcome of the requested job. -Deprecated 2021-11-06. +| Param | Type | Description | +| --- | --- | --- | +| input | [Vector](#Vector) | Input vector. | -**Kind**: global class diff --git a/CHANGELOG.md b/CHANGELOG.md index fa200bb96..a7d585c0c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,18 @@ # `@fabric/core` Changelog Recent changes to Fabric Core. -- **2022-01-25** - Initial changelog file. +## 2023-04-01 +### `v0.1.0-RC1` pre-release +First pass at public playnet! Initial release candidate for the `v0.1.0` tag. + +**Notable Changes:** +- **New Feature:** Fabric CLI — interact with Fabric using your terminal! +- **New Classes:** + - Actor + - Channel + - Message + - Peer + - Service + +## 2022-01-25 +Initial changelog file. diff --git a/COPYING b/COPYING deleted file mode 100644 index a4252793e..000000000 --- a/COPYING +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2015 Eric Martindale -Copyright (c) 2017 Fabric Labs - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software is furnished to do so, -subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/DEVELOPERS.md b/DEVELOPERS.md index f4ca23922..4fb6751ff 100644 --- a/DEVELOPERS.md +++ b/DEVELOPERS.md @@ -5,7 +5,7 @@ applications, so grab a coffee ☕ and settle in. ## Quick Start See also [`QUICKSTART.md`][quickstart-guide] for up-to-date instructions. -0. `nvm use 16.17.1` (you can get `nvm` from [nvm.sh][nvm-official]) +0. `nvm use 22.14.0` (you can get `nvm` from [nvm.sh][nvm-official]) 1. `npm install -g @fabric/core` to add `fabric` to your path 2. (optional) `fabric setup` to set up your environment (generates a new master key) 3. `fabric` should now be enough to get you up and running! @@ -15,6 +15,10 @@ That's it! Let's take a look at overall Fabric system and how you, as a develop ## Architecture Fabric is two things — a protocol for machines to exchange information ("the Fabric Protocol"), and a sotware library (`@fabric/core`) offering up many tools and utilities for building your own networks which speak this protocol. +Typically, you will need the following: + + - a Bitcoin Node (bitcoind and/or bcoin with `bcoin --only=127.0.0.1`) + ### Overview Using Fabric to interface securely with decentralized systems, you'll start by following the instructions above to obtain a globally-available version of the `fabric` command-line client, which provides the majority of tools you'll need along the way. @@ -25,7 +29,7 @@ The `@fabric/core` library consists of a few key components: 2. `components` — generic "interface" elements for describing Types to users. 3. `resources` — Fabric-based definitions for `@fabric/core/types/resource`. 4. `services` — Maintainer-accepted definitions of the `Service` class. Yes, you can submit your own! -5. `types` — a library of ES6 classes implementing various bits; `Actor`, `Channel`, `Oracle`, `Service`, and `Signer` are all interesting. :) +5. `types` — a library of ES6 classes implementing various bits; `Actor`, `Channel`, `Oracle`, `Service`, and `Key` are all interesting. :) Let's go over each in more detail. @@ -57,7 +61,7 @@ All agreements in Fabric are represented as well-formed descriptions of **Resour To create an ##### 1.2a: Convergence -You'll read in the Components section about our thoughts on User Interface Design, especially Software Development Inteface Design. Maybe someday we'll have a blog to share this on, but my personal goal is to design my software one time, and have it adapt to each platform while still retaining complete, functionality — even if, for example, mobile and desktop users might have different access profiles (usage patterns). +You'll read in the Components section about our thoughts on User Interface Design, especially Software Development Interface Design. Maybe someday we'll have a blog to share this on, but my personal goal is to design my software one time, and have it adapt to each platform while still retaining complete, functionality — even if, for example, mobile and desktop users might have different access profiles (usage patterns). This raises the question: **how should peer-to-peer contracts be written?** @@ -203,16 +207,16 @@ const Actor = require('@fabric/core/types/actor'); Grab what you need, use what you take. :) ##### Fabric Types by Example -Create and sign some string message using the built-in Schnorr `Signer` type: +Create and sign some string message using the built-in Schnorr `Key` type: ```js const Hash256 = require('@fabric/core/types/hash256'); -const Signer = require('@fabric/core/types/signer'); +const Key = require('@fabric/core/types/key'); const message = 'Hello, world!'; -const signer = new Signer(); -const signature = signer.sign(message); +const key = new Key(); +const signature = key.sign(message); console.log('Message:', message); console.log('Message Hash:', Hash256.digest(message)); -console.log('Signer Pubkey:', signer.public); +console.log('Key Pubkey:', key.public); console.log('Purported Signature:', message); ``` diff --git a/Dockerfile b/Dockerfile deleted file mode 100644 index d95452be0..000000000 --- a/Dockerfile +++ /dev/null @@ -1,11 +0,0 @@ -FROM node:10 -WORKDIR /fabric - -# if package.json changes. Docker deploys auto-update -COPY package.json /fabric -RUN npm install -RUN npm build -COPY . ./fabric - -EXPOSE 9999 -CMD ["npm", "start"] diff --git a/GOALS.md b/GOALS.md index 909f7a7e4..f264369b0 100644 --- a/GOALS.md +++ b/GOALS.md @@ -17,7 +17,7 @@ and no mission succeeds without a clearly-defined set of goals. ## Current Goals These are our immediate goals: -- [ ] Find all TODO items (run script, check diff) +- [x] Find all TODO items (run script, check diff) - [ ] Audit all documentation - [ ] Check all hyperlinks on `npm run dev` - [ ] 100% test coverage diff --git a/IDENTITY.md b/IDENTITY.md index 85c8e33cc..6b4e3fd31 100644 --- a/IDENTITY.md +++ b/IDENTITY.md @@ -5,10 +5,24 @@ This document is intended to be utilized as the specification for the Fabric Ide The Fabric Identity Protocol is a decentralized identifier for Fabric-speaking networks. 1. Load a BIP44 HD tree -2. Designate First Identity as Derivation Path: `m/7777'/0'/0'/0/0` (same as Bitcoin funds [!!!]) +2. Designate First Identity as Derivation Path: `m/44'/7778'/0'/0/0` 3. `m = sha256(derived_pubkey)` 4. `id = bech32m("id", m) // "id" taken as ASCII bytes` +Additional identities may be loaded by modifying the account index in the derivation path: + +``` +Identity #1 [0]: m/44'/7778'/0'/0/0 +Identity #2 [1]: m/44'/7778'/1'/0/0 +... +``` + +Fabric will encode each transaction using the address index field, as specified in BIP 44: + +``` +Transaction #1 [1]: m/44'/7778'/0'/1/0 +``` + ### Full Specification `id = bech32m("id", sha256(bip44(derivation_path, hd_tree).public))` diff --git a/INSTALL.md b/INSTALL.md new file mode 100644 index 000000000..16461164d --- /dev/null +++ b/INSTALL.md @@ -0,0 +1,31 @@ +# Installing Fabric +## Prerequisites +- Node.js 22.14.0 + +## Quick Start +You can install Fabric by running: +``` +npm i -g FabricLabs/fabric#feature/cleanup +``` + +This will make the `fabric` binary available on your system, after which you should run: +``` +fabric setup +``` + +Now, you'll have a newly-generated Fabric address and you can run: +``` +fabric +``` + +## Playnet +By default, the Fabric CLI connects to `playnet` for an initial set of peers. You can add new peers manually by running `/connect
` where ` is the peer's public hostname and port. + +## Notes +If you don't have Node.js, or an incorrect version, we recommend [installing NVM][installing-nvm]. Once complete, you can install and set the default node version: +``` +nvm install 22.14.0 +nvm alias default 22.14.0 # optional +``` + +[installing-nvm]: https://nvm.sh diff --git a/MESSAGES.md b/MESSAGES.md new file mode 100644 index 000000000..1fd43ab56 --- /dev/null +++ b/MESSAGES.md @@ -0,0 +1,32 @@ +# Fabric Messages + +``` +TYPE|NAME +====|==== +0000| +0001|GENERIC_MESSAGE +0002|PEER_ANNOUNCE +0003|PEER_PING +0004|PEER_PONG +0005| +0006| +0007| +0008| +0009| +000a| +000b| +000c| +000d| +000e| +000f| +0010| +001f| # 31 +0020| # 32 +0021|BITCOIN_BLOCK_HASH +0022|BITCOIN_TRANSACTION_HASH +002f| # 47 +0030| # 48 +0031|FABRIC_STATE +0032|FABRIC_DOCUMENT +0033|FABRIC_DELTA +``` diff --git a/OWNERS b/OWNERS index 56b0b1506..c1d91e221 100644 --- a/OWNERS +++ b/OWNERS @@ -1,6 +1,7 @@ approvers: - martindale reviewers: + - anandsuresh - chrisinajar - manojdv - melnx diff --git a/PROTOCOL.md b/PROTOCOL.md index 5106234ac..419a0411f 100644 --- a/PROTOCOL.md +++ b/PROTOCOL.md @@ -35,6 +35,8 @@ The base list of Fabric Message Types is as follows: #### The `GENERIC` Message Type UTF8-encoded JSON payload. +If the `version` field is `1` the payload MUST be valid JSON. + #### The `ANNOUNCE` Message Type Used for Peer announcements. @@ -76,3 +78,56 @@ An `ActorSet` is a hashmap of `Actor` instances, address by their ID. #### Collection A `Collection` is a list of `Actor` instances. + +#### Contract +The `Contract` class provides a simple method for creating agreements between a known set of peers. + +## Peering +Peers are identified in the Fabric network by their [**Fabric Identity**][fabric-identity], a `bech32m` encoding of the prefix `id` and public key body. + +Connecting to other peers in Fabric requires knowledge of the peer's **public key**. + +``` +$ fabric +C^i +/connect 0375f7cfc3fa3bc9ed621019018fca678da404a29c8dfec4350855b5ad2f0a42d7@hub.fabric.pub:7777 +``` + +### Peer Protocol +Initiator sends a `P2P_SESSION_OFFER` message, counterparty responds with `P2P_SESSION_OPEN` message. + +``` +INITATIOR COUNTERPARTY +00: CONNECT +01: SESSION_OFFER -> +02: VALIDATE +03: <- SESSION_OPEN +04: READY +``` + +The `Session` is now open. + +#### Negotiation +``` +incorrect state correct state + | | + v | + prior state | + | | + v | + timeout | + | | + | | + | v + \---------------------------------> sign -> broadcast +``` + +### Layers +``` +sha256(input) -> sha256(hash) -> (100% signing set signature) +``` + + + + +[fabric-identity]: IDENTITY.md diff --git a/QUICKSTART.md b/QUICKSTART.md index 8ef09740b..c32d551b9 100644 --- a/QUICKSTART.md +++ b/QUICKSTART.md @@ -2,7 +2,7 @@ ## Prerequisites 0. (optional) Install NVM: `https://nvm.sh` -1. Install Node 16.17.1 (use `nvm install 16.17.1` if using `nvm`) +1. Install Node 22.14.0 (use `nvm install 22.14.0` if using `nvm`) ## Instructions 0. Meet the prerequisites (above) diff --git a/README.md b/README.md index 07b3cbda6..6e7d83e3c 100644 --- a/README.md +++ b/README.md @@ -1,29 +1,45 @@ -# Fabric +# `@fabric/core` — the Fabric Reference Client ![Project Status][badge-status] -[![Build Status][badge-build]][build-status] [![Coverage Status][badge-coverage]][coverage] [![GitHub contributors][badge-contributors]][contributors] -[![Community][badge-chat]][chat] + +[The `@fabric/core` project][fabric-github] provides an API for building peer-to-peer applications on [Bitcoin][bitcoin]. Fabric is an experimental approach to the secure establishment and execution of -peer-to-peer agreements, up to and including financial transactions. With a -robust library of common components, `npm i @fabric/core` provides all the tools -one might `require` during the development of a well-researched application of -decentralization technology. +peer-to-peer agreements ("contracts") using Bitcoin as a bonding mechanism. The +`@fabric/core` project provides a robust set of implementations as JavaScript +classes, enabling the rapid prototyping and testing of Bitcoin-based +applications for downstream developers. + +## Quick Start +`npm i -g FabricLabs/fabric#master` + +Install Fabric CLI to your system using the above command, then run: +``` +fabric setup +``` -| 🚨 Heads up! | +| 🚨 Stop here! | |--------------| -| Use of Fabric in production is **not recommended** in its current state. Please wait for [an official release][releases] before deploying to production environments, or proceed at your own risk. | +| The output of the above command will include your SEED, which should never be shared. | + +Once complete, you'll have a fully configured Fabric client available by running: +``` +fabric +``` + +For help, try entering "insert mode" by pressing the "i" key then typing `/help` and pressing enter — you'll get a short help prompt followed by a list of available commands. Feel free to explore! -## Getting Started -If you're already familiar with `node` and have a project already started, try -`npm install --save @fabric/core` to install [Fabric Core](https://fabric.pub), -the primary library used for most Fabric-based applications. +If you run into any trouble, read on for clues, then [join the chat][chat-help] with any remaining questions. You'll also want `bitcoind` installed, and fully synchronized with your preferred network. You can use `scripts/playnet.sh` to run a local playnet node, for which you can use the faucet: https://faucet.playnet.fabric.pub +## What is Fabric? +`@fabric/core` provides the reference implementation for [the Fabric Protocol][protocol], a "language" for exchanging information through peer-to-peer networks. Written in JavaScript, it is meant to be well-documented and easy to understand — but not the final implementation. + +## Contributing Fork and clone [the Fabric GitHub repository][fabric-github] and launch a local web server with `npm run examples` to view the examples, or `npm run docs` once you're ready to integrate Fabric into your application. @@ -47,9 +63,9 @@ npm run build - `npm start` creates a local Fabric node. ## Native Dependencies -Installing Fabric from npm (`npm i @fabric/core`) will generally compile the -following dependencies from the local system: - +Installing Fabric from npm (`npm i @fabric/core` or +`npm i FabricLabs/fabric#develop`) will generally compile the following +dependencies from the local system: - `secp256k1` - `level` - `zeromq` @@ -65,56 +81,37 @@ it as an event source. #### Simple Example ```js -const Fabric = require('@fabric/core'); -const fabric = new Fabric(); - -fabric.on('message', function (message) { - console.log('Received message from Fabric:', message); +const Peer = require('@fabric/core/types/peer'); + +async function main () { + const peer = new Peer({ + alias: 'Example', + peers: ['hub.fabric.pub:7777'] + }); + + peer.on('message', (message) => { + console.log('Received message from Fabric:', message); + }); + + peer.start(); + return { peer }; +} + +main().catch((exception) => { + console.error('Example error:', exception); +}).then((output) => { + console.log('Example output:', output); }); - -fabric.start(); ``` -`service` now contains a full instance of Fabric, including `SET` and `GET` -methods for publishing and retrieving documents. Use `npm run examples` to see -more. - -### Message Types -Message types are as follows: - -#### `message` -The generic message event. - -**Properties:** -- `@type` name of the event type. -- `@data` the content of the event, if any. - -### Using Fabric in the Browser -Fabric generates a `fabric.min.js` bundle, which can be included with any HTML -document to expose the API in a browser. - -## Other Fabrics -Several other projects have used the name Fabric, as it's a great way to -describe a network of things, conjuring feelings of _nets_ and _webs_. Here are -some links to them, as they offer some interesting things completely unrelated -to our goals. - -- Fabric python project (#fabric on Freenode) -- Fabric application framework by Twitter -- HyperLedger Fabric, by IBM - - ## Plugins Fabric is an extensible framework, supporting a variety of plugins. -| Package | Description | Status | -|------------------------------------|--------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------| -| [`@fabric/http`][http-plugin] | serve Fabric apps to the legacy web (HTTP) | [![Build Status][badge-http-status]][http-test-status] [![Coverage Status][badge-http-coverage]][badge-http-coverage] | -| [`@fabric/github`][github-plugin] | interact with GitHub through Fabric | [![Build Status][badge-github-status]][github-test-status] [![Coverage Status][badge-github-coverage]][github-coverage-home] | -| [`@fabric/matrix`][matrix-plugin] | connect to Matrix servers | [![Build Status][badge-matrix-status]][matrix-test-status] [![Coverage Status][badge-matrix-coverage]][badge-matrix-coverage] | -| [`@fabric/twilio`][twilio-plugin] | send (and receive) SMS and phone calls | [![Build Status][badge-twilio-status]][twilio-test-status] [![Coverage Status][badge-twilio-coverage]][badge-twilio-coverage] | -| [`@fabric/zapier`][zapier-plugin] | interact with arbitrary zapier triggers | [![Build Status][badge-zapier-status]][zapier-test-status] [![Coverage Status][badge-zapier-coverage]][badge-zapier-coverage] | -| [`@fabric/doorman`][doorman] | an artificially intelligent assistant | [![Build Status][badge-doorman-status]][doorman-test-status] [![Coverage Status][badge-doorman-coverage]][doorman-coverage-home] | +| Package | Description | Status | +|------------------------------------|--------------------------------------------|----------------------------------------------------------------------| +| [`@fabric/http`][http-plugin] | serve Fabric apps to the legacy web (HTTP) | [![Coverage Status][badge-http-coverage]][badge-http-coverage] | +| [`@fabric/hub`][hub-plugin] | run your own Fabric Hub | [![Coverage Status][badge-hub-coverage]][badge-hub-coverage] | +| [`@fabric/doorman`][doorman] | an artificially intelligent assistant | [![Coverage Status][badge-doorman-coverage]][doorman-coverage-home] | ## Running on Fabric Several successful projects are built with or are running on Fabric, including: @@ -127,40 +124,72 @@ To add your project to the list, [read the API docs][api-docs], create a public repository for the source code, then [edit this file][edit-readme] to include a link to your work. +### Edge Nodes +Full Fabric nodes connected to the World Wide Web (WWW). Only SSL (port 443) is supported. + +| Host | Status | +| ---- | ------ | +| `hub.fabric.pub` | `ONLINE` +| `labs.fabric.pub` | `OFFLINE` + +### Fabric Projects +Either Fabric libraries or projects running Fabric, this list encompasses the most interesting work in the ecosystem. + +| Name | Description | Status | v0.1.0-RC1 ready +| ---- | ----------- | ------ | ---------- +| [`@fabric/core`][fabric-github] | Core Library +| [`@fabric/http`][http-plugin] | Edge Nodes +| [`hub.fabric.pub`](https://hub.fabric.pub) | +| [`labs.fabric.pub`](https://labs.fabric.pub) | +| `sensemaker.io` | | | `FALSE` +| `verse.pub` | | | + ## Learning More The best place to get started is in [the #learning channel][learning], a collection of empassioned educators eager to help you. Fabric on Twitter: [@FabricProtocol][twitter] +[fabric]: fabric: + +[bitcoin]: https://bitcoin.org +[build-guide]: BUILD.md +[chat]: https://grove.chat +[chat-help]: https://grove.chat/#/room/#help:fabric.pub +[chat-support]: https://grove.chat/#/room/#help:fabric.pub +[coverage]: https://codecov.io/gh/FabricLabs/fabric +[development]: https://grove.chat/#/room/#development:fabric.pub +[fabric-fm]: https://fabric.fm +[fabric-pub]: https://fabric.pub +[fabric-github]: https://github.com/FabricLabs/fabric +[fabric-http]: https://github.com/FabricLabs/fabric-http +[protocol]: PROTOCOL.md +[learning]: https://grove.chat/#/room/#learning:fabric.pub + +[api-docs]: https://dev.fabric.pub + [fabric-github]: https://github.com/FabricLabs/fabric [http-plugin]: https://github.com/FabricLabs/fabric-http -[matrix-plugin]: https://github.com/FabricLabs/fabric-matrix +[hub-plugin]: https://github.com/FabricLabs/hub.fabric.pub [twilio-plugin]: https://github.com/FabricLabs/fabric-twilio [zapier-plugin]: https://github.com/FabricLabs/fabric-zapier [github-plugin]: https://github.com/FabricLabs/fabric-github -[api-docs]: https://dev.fabric.pub -[chat]: https://chat.fabric.pub + [edit-readme]: https://github.com/FabricLabs/fabric/edit/master/README.md [contributors]: https://github.com/FabricLabs/fabric/graphs/contributors [build-status]: https://app.travis-ci.com/github/FabricLabs/fabric -[coverage]: https://codecov.io/gh/FabricLabs/fabric - -[learning]: https://to.fabric.pub/#learning:fabric.pub -[development]: https://to.fabric.pub/#development:fabric.pub [badge-status]: https://img.shields.io/badge/status-experimental-rainbow.svg?style=flat-square [badge-build]: https://img.shields.io/travis/FabricLabs/fabric.svg?branch=master&style=flat-square [badge-coverage]: https://img.shields.io/codecov/c/github/FabricLabs/fabric.svg?style=flat-square [badge-contributors]: https://img.shields.io/github/contributors/FabricLabs/fabric.svg?style=flat-square -[badge-chat]: https://img.shields.io/matrix/hub:fabric.pub.svg?server_fqdn=matrix.org&style=flat-square [badge-doorman-status]: https://img.shields.io/travis/FabricLabs/doorman.svg?branch=master&style=flat-square [badge-doorman-coverage]: https://img.shields.io/codecov/c/github/FabricLabs/doorman.svg?style=flat-square [badge-http-status]: https://img.shields.io/travis/FabricLabs/fabric-http.svg?branch=master&style=flat-square +[badge-hub-status]: https://img.shields.io/travis/FabricLabs/fabric-hub.svg?branch=master&style=flat-square [badge-http-coverage]: https://img.shields.io/codecov/c/github/FabricLabs/fabric-http.svg?style=flat-square -[badge-matrix-status]: https://img.shields.io/travis/FabricLabs/fabric-matrix.svg?branch=master&style=flat-square -[badge-matrix-coverage]: https://img.shields.io/codecov/c/github/FabricLabs/fabric-matrix.svg?style=flat-square +[badge-hub-coverage]: https://img.shields.io/codecov/c/github/FabricLabs/fabric-hub.svg?style=flat-square [badge-twilio-status]: https://img.shields.io/travis/FabricLabs/fabric-twilio.svg?branch=master&style=flat-square [badge-twilio-coverage]: https://img.shields.io/codecov/c/github/FabricLabs/fabric-twilio.svg?style=flat-square [badge-zapier-status]: https://img.shields.io/travis/FabricLabs/fabric-zapier.svg?branch=master&style=flat-square @@ -172,7 +201,6 @@ Fabric on Twitter: [@FabricProtocol][twitter] [doorman-test-status]: https://app.travis-ci.com/github/FabricLabs/doorman [http-test-status]: https://app.travis-ci.com/github/FabricLabs/fabric-http -[matrix-test-status]: https://app.travis-ci.com/github/FabricLabs/fabric-matrix [twilio-test-status]: https://app.travis-ci.com/github/FabricLabs/fabric-twilio [zapier-test-status]: https://app.travis-ci.com/github/FabricLabs/fabric-zapier [soundtrack-test-status]: https://app.travis-ci.com/github/FabricLabs/soundtrack @@ -187,7 +215,7 @@ Fabric on Twitter: [@FabricProtocol][twitter] [soundtrack]: https://github.com/FabricLabs/soundtrack [doorman]: https://github.com/FabricLabs/doorman [idlerpg]: https://to.fabric.pub/#idlerpg:verse.im -[verse]: https://verse.im +[verse]: https://github.com/FabricLabs/verse [everything-is-broken]: https://medium.com/message/everything-is-broken-81e5f33a24e1 [coordination]: https://i.imgur.com/Ki3fbTh.gif diff --git a/REQUIREMENTS.md b/REQUIREMENTS.md index 51c14af31..be12ae7fe 100644 --- a/REQUIREMENTS.md +++ b/REQUIREMENTS.md @@ -1,6 +1,13 @@ # Requirements for Fabric Nodes The following requirements are necessary to run a Fabric node: -1. Fully up-to-date `bitcoind >= 0.21.1` -2. 166 MHz x86 CPU -3. 256 MB RAM +1. bitcoind >= 0.21.1 +2. > 1 GHz CPU +3. > 1 GB RAM +4. > 1 TB storage +5. > 500 MB/day bandwidth + +Some configuration options can reduce these requirements, but they should be considered the minimum specification for a full Fabric node. + +## Bandwidth +1MB/s is considered minimal for Fabric connections. When possible, Fabric will attempt to use a constant stream of 1MB/s of over-the-wire bandwith (after compression and encryption). High-latency connections (those with a connection exceeding 250ms ping) should expect some operations to take longer than an hour. diff --git a/SUMMARY.md b/SUMMARY.md index a1901201a..29e47fbf2 100644 --- a/SUMMARY.md +++ b/SUMMARY.md @@ -28,6 +28,9 @@ Welcome to Fabric! [api-docs]: https://dev.fabric.pub/docs [api-examples]: https://dev.fabric.pub/examples +[actors]: ACTORS.md +[contracts]: CONTRACTS.md + [readme]: README.md [welcome]: WELCOME.md [quickstart]: QUICKSTART.md diff --git a/TODO.md b/TODO.md index 7e04dbe44..1e30814fc 100644 --- a/TODO.md +++ b/TODO.md @@ -4,11 +4,12 @@ - [ ] Document development process - [ ] `reports/` - [ ] `scripts/` + - [x] Encryption by default - [ ] Document configuration - [ ] Document use of environment variables - [ ] Document use of `settings/local.js` - [ ] Document use of `~/.fabric` -- [ ] Enable Lightning support +- [x] Enable Lightning support See also [GOALS.md][goals]. diff --git a/aliases/documents.json b/aliases/documents.json deleted file mode 100644 index 924c38080..000000000 --- a/aliases/documents.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "name": "/", - "content": "e9e130060b64b058f586e4b09078ec5249892114" -} diff --git a/aliases/index.json b/aliases/index.json deleted file mode 100644 index 489fde0f8..000000000 --- a/aliases/index.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "name": "Index", - "description": "a map of key/value pairs", - "content": { - "documents": "02a7f93df1bfa3b7fd68caa1e96cdd2213220f6e" - } -} diff --git a/assets/bundles/browser.js b/assets/bundles/browser.js new file mode 100644 index 000000000..697d5c290 --- /dev/null +++ b/assets/bundles/browser.js @@ -0,0 +1,6 @@ +/******/ (() => { // webpackBootstrap +/******/ "use strict"; +/******/ +/******/ +/******/ })() +; \ No newline at end of file diff --git a/assets/docco.css b/assets/docco.css new file mode 100644 index 000000000..c3d580fab --- /dev/null +++ b/assets/docco.css @@ -0,0 +1,518 @@ +/*--------------------- Typography ----------------------------*/ + +@font-face { + font-family: 'aller-light'; + src: url('public/fonts/aller-light.eot'); + src: url('public/fonts/aller-light.eot?#iefix') format('embedded-opentype'), + url('public/fonts/aller-light.woff') format('woff'), + url('public/fonts/aller-light.ttf') format('truetype'); + font-weight: normal; + font-style: normal; +} + +@font-face { + font-family: 'aller-bold'; + src: url('public/fonts/aller-bold.eot'); + src: url('public/fonts/aller-bold.eot?#iefix') format('embedded-opentype'), + url('public/fonts/aller-bold.woff') format('woff'), + url('public/fonts/aller-bold.ttf') format('truetype'); + font-weight: normal; + font-style: normal; +} + +@font-face { + font-family: 'roboto-black'; + src: url('public/fonts/roboto-black.eot'); + src: url('public/fonts/roboto-black.eot?#iefix') format('embedded-opentype'), + url('public/fonts/roboto-black.woff') format('woff'), + url('public/fonts/roboto-black.ttf') format('truetype'); + font-weight: normal; + font-style: normal; +} + +/*--------------------- Layout ----------------------------*/ +html { height: 100%; } +body { + font-family: "aller-light"; + font-size: 14px; + line-height: 18px; + color: #30404f; + margin: 0; padding: 0; + height:100%; +} +#container { min-height: 100%; } + +a { + color: #000; +} + +b, strong { + font-weight: normal; + font-family: "aller-bold"; +} + +p { + margin: 15px 0 0px; +} + .annotation ul, .annotation ol { + margin: 25px 0; + } + .annotation ul li, .annotation ol li { + font-size: 14px; + line-height: 18px; + margin: 10px 0; + } + +h1, h2, h3, h4, h5, h6 { + color: #112233; + line-height: 1em; + font-weight: normal; + font-family: "roboto-black"; + text-transform: uppercase; + margin: 30px 0 15px 0; +} + +h1 { + margin-top: 40px; +} +h2 { + font-size: 1.26em; +} + +hr { + border: 0; + background: 1px #ddd; + height: 1px; + margin: 20px 0; +} + +pre, tt, code { + font-size: 12px; line-height: 16px; + font-family: Menlo, Monaco, Consolas, "Lucida Console", monospace; + margin: 0; padding: 0; +} + .annotation pre { + display: block; + margin: 0; + padding: 7px 10px; + background: #fcfcfc; + -moz-box-shadow: inset 0 0 10px rgba(0,0,0,0.1); + -webkit-box-shadow: inset 0 0 10px rgba(0,0,0,0.1); + box-shadow: inset 0 0 10px rgba(0,0,0,0.1); + overflow-x: auto; + } + .annotation pre code { + border: 0; + padding: 0; + background: transparent; + } + + +blockquote { + border-left: 5px solid #ccc; + margin: 0; + padding: 1px 0 1px 1em; +} + .sections blockquote p { + font-family: Menlo, Consolas, Monaco, monospace; + font-size: 12px; line-height: 16px; + color: #999; + margin: 10px 0 0; + white-space: pre-wrap; + } + +ul.sections { + list-style: none; + padding:0 0 5px 0;; + margin:0; +} + +/* + Force border-box so that % widths fit the parent + container without overlap because of margin/padding. + + More Info : http://www.quirksmode.org/css/box.html +*/ +ul.sections > li > div { + -moz-box-sizing: border-box; /* firefox */ + -ms-box-sizing: border-box; /* ie */ + -webkit-box-sizing: border-box; /* webkit */ + -khtml-box-sizing: border-box; /* konqueror */ + box-sizing: border-box; /* css3 */ +} + + +/*---------------------- Jump Page -----------------------------*/ +#jump_to, #jump_page { + margin: 0; + background: white; + -webkit-box-shadow: 0 0 25px #777; -moz-box-shadow: 0 0 25px #777; + -webkit-border-bottom-left-radius: 5px; -moz-border-radius-bottomleft: 5px; + font: 16px Arial; + cursor: pointer; + text-align: right; + list-style: none; +} + +#jump_to a { + text-decoration: none; +} + +#jump_to a.large { + display: none; +} +#jump_to a.small { + font-size: 22px; + font-weight: bold; + color: #676767; +} + +#jump_to, #jump_wrapper { + position: fixed; + right: 0; top: 0; + padding: 10px 15px; + margin:0; +} + +#jump_wrapper { + display: none; + padding:0; +} + +#jump_to:hover #jump_wrapper { + display: block; +} + +#jump_page_wrapper{ + position: fixed; + right: 0; + top: 0; + bottom: 0; +} + +#jump_page { + padding: 5px 0 3px; + margin: 0 0 25px 25px; + max-height: 100%; + overflow: auto; +} + +#jump_page .source { + display: block; + padding: 15px; + text-decoration: none; + border-top: 1px solid #eee; +} + +#jump_page .source:hover { + background: #f5f5ff; +} + +#jump_page .source:first-child { +} + +/*---------------------- Low resolutions (> 320px) ---------------------*/ +@media only screen and (min-width: 320px) { + .sswrap { display: none; } + + ul.sections > li > div { + display: block; + padding:5px 10px 0 10px; + } + + ul.sections > li > div.annotation ul, ul.sections > li > div.annotation ol { + padding-left: 30px; + } + + ul.sections > li > div.content { + overflow-x:auto; + -webkit-box-shadow: inset 0 0 5px #e5e5ee; + box-shadow: inset 0 0 5px #e5e5ee; + border: 1px solid #dedede; + margin:5px 10px 5px 10px; + padding-bottom: 5px; + } + + ul.sections > li > div.annotation pre { + margin: 7px 0 7px; + padding-left: 15px; + } + + ul.sections > li > div.annotation p tt, .annotation code { + background: #f8f8ff; + border: 1px solid #dedede; + font-size: 12px; + padding: 0 0.2em; + } +} + +/*---------------------- (> 481px) ---------------------*/ +@media only screen and (min-width: 481px) { + #container { + position: relative; + } + body { + background-color: #F5F5FF; + font-size: 15px; + line-height: 21px; + } + pre, tt, code { + line-height: 18px; + } + p, ul, ol { + margin: 0 0 15px; + } + + + #jump_to { + padding: 5px 10px; + } + #jump_wrapper { + padding: 0; + } + #jump_to, #jump_page { + font: 10px Arial; + text-transform: uppercase; + } + #jump_page .source { + padding: 5px 10px; + } + #jump_to a.large { + display: inline-block; + } + #jump_to a.small { + display: none; + } + + + + #background { + position: absolute; + top: 0; bottom: 0; + width: 350px; + background: #fff; + border-right: 1px solid #e5e5ee; + z-index: -1; + } + + ul.sections > li > div.annotation ul, ul.sections > li > div.annotation ol { + padding-left: 40px; + } + + ul.sections > li { + white-space: nowrap; + } + + ul.sections > li > div { + display: inline-block; + } + + ul.sections > li > div.annotation { + max-width: 350px; + min-width: 350px; + min-height: 5px; + padding: 13px; + overflow-x: hidden; + white-space: normal; + vertical-align: top; + text-align: left; + } + ul.sections > li > div.annotation pre { + margin: 15px 0 15px; + padding-left: 15px; + } + + ul.sections > li > div.content { + padding: 13px; + vertical-align: top; + border: none; + -webkit-box-shadow: none; + box-shadow: none; + } + + .sswrap { + position: relative; + display: inline; + } + + .ss { + font: 12px Arial; + text-decoration: none; + color: #454545; + position: absolute; + top: 3px; left: -20px; + padding: 1px 2px; + opacity: 0; + -webkit-transition: opacity 0.2s linear; + } + .for-h1 .ss { + top: 47px; + } + .for-h2 .ss, .for-h3 .ss, .for-h4 .ss { + top: 35px; + } + + ul.sections > li > div.annotation:hover .ss { + opacity: 1; + } +} + +/*---------------------- (> 1025px) ---------------------*/ +@media only screen and (min-width: 1025px) { + + body { + font-size: 16px; + line-height: 24px; + } + + #background { + width: 525px; + } + ul.sections > li > div.annotation { + max-width: 525px; + min-width: 525px; + padding: 10px 25px 1px 50px; + } + ul.sections > li > div.content { + padding: 9px 15px 16px 25px; + } +} + +/*---------------------- Syntax Highlighting -----------------------------*/ + +td.linenos { background-color: #f0f0f0; padding-right: 10px; } +span.lineno { background-color: #f0f0f0; padding: 0 5px 0 5px; } +/* + +github.com style (c) Vasily Polovnyov + +*/ + +pre code { + display: block; padding: 0.5em; + color: #000; + background: #f8f8ff +} + +pre .hljs-comment, +pre .hljs-template_comment, +pre .hljs-diff .hljs-header, +pre .hljs-javadoc { + color: #408080; + font-style: italic +} + +pre .hljs-keyword, +pre .hljs-assignment, +pre .hljs-literal, +pre .hljs-css .hljs-rule .hljs-keyword, +pre .hljs-winutils, +pre .hljs-javascript .hljs-title, +pre .hljs-lisp .hljs-title, +pre .hljs-subst { + color: #954121; + /*font-weight: bold*/ +} + +pre .hljs-number, +pre .hljs-hexcolor { + color: #40a070 +} + +pre .hljs-string, +pre .hljs-tag .hljs-value, +pre .hljs-phpdoc, +pre .hljs-tex .hljs-formula { + color: #219161; +} + +pre .hljs-title, +pre .hljs-id { + color: #19469D; +} +pre .hljs-params { + color: #00F; +} + +pre .hljs-javascript .hljs-title, +pre .hljs-lisp .hljs-title, +pre .hljs-subst { + font-weight: normal +} + +pre .hljs-class .hljs-title, +pre .hljs-haskell .hljs-label, +pre .hljs-tex .hljs-command { + color: #458; + font-weight: bold +} + +pre .hljs-tag, +pre .hljs-tag .hljs-title, +pre .hljs-rules .hljs-property, +pre .hljs-django .hljs-tag .hljs-keyword { + color: #000080; + font-weight: normal +} + +pre .hljs-attribute, +pre .hljs-variable, +pre .hljs-instancevar, +pre .hljs-lisp .hljs-body { + color: #008080 +} + +pre .hljs-regexp { + color: #B68 +} + +pre .hljs-class { + color: #458; + font-weight: bold +} + +pre .hljs-symbol, +pre .hljs-ruby .hljs-symbol .hljs-string, +pre .hljs-ruby .hljs-symbol .hljs-keyword, +pre .hljs-ruby .hljs-symbol .hljs-keymethods, +pre .hljs-lisp .hljs-keyword, +pre .hljs-tex .hljs-special, +pre .hljs-input_number { + color: #990073 +} + +pre .hljs-builtin, +pre .hljs-constructor, +pre .hljs-built_in, +pre .hljs-lisp .hljs-title { + color: #0086b3 +} + +pre .hljs-preprocessor, +pre .hljs-pi, +pre .hljs-doctype, +pre .hljs-shebang, +pre .hljs-cdata { + color: #999; + font-weight: bold +} + +pre .hljs-deletion { + background: #fdd +} + +pre .hljs-addition { + background: #dfd +} + +pre .hljs-diff .hljs-change { + background: #0086b3 +} + +pre .hljs-chunk { + color: #aaa +} + +pre .hljs-tex .hljs-formula { + opacity: 0.5; +} diff --git a/assets/examples/app.html b/assets/examples/app.html index c0d8e2905..90f7b8d40 100644 --- a/assets/examples/app.html +++ b/assets/examples/app.html @@ -1,183 +1,503 @@ + Offline-first Applications with Fabric - + +
- - +
    - - - -
  • -
    - -
    - -
    -

    Offline-first Applications with Fabric

    -

    Build your first Fabric application.

    -
    - -
    'use strict';
     
    -const App = require('../lib/app');
     
    -const Person = require('../resources/person');
    -const Post = require('../resources/post');
    -const Relationship = require('../resources/relationship');
    +      
  • +
    + +
    + § +
    +

    Offline-first Applications with Fabric

    +

    Build your first Fabric application.

    +

    Warning

    +

    This example is intended for downstream consumers — those seeking to implement client-facing applications using Fabric.

    +

    Quickstart

    +

    Ensure that you are using NodeJS 22.14.0 — execute in your clone of the Fabric Core repository.

    +

    Cloning Fabric

    +

    Run the following commands:

    +
    git clone git@github.com:FabricLabs/fabric.git
    +cd fabric
    +git checkout v0.1.0-RC1
    +
    +

    You should now be on the latest branch.

    +

    Running the App example:

    +
    npm i
    +node examples/app.js
    +
    +

    Browsers

    +

    This example is intended to be run in the browser.

    + +
    + +
    +
    +
    if (!window) throw new Error('Not running in browser.  Exiting.');
    +
    +
    + +
  • + + +
  • +
    + +
    + § +
    +

    Now that you’ve verified your environment, try the following:

    +
    npm run build
    +
    +

    Settings

    +

    Settings include browser configuration; script paths, console settings, and consensus parameters.

    + +
    + +
    +
    +
    const settings = {
    +  label: '[GUARDIAN]',
    +
    +
    + +
  • + -window.app = new App({ - scripts: ['app.js'], - resources: { - 'Person': Person, - 'Post': Post, - 'Relationship': Relationship, +
  • +
    + +
    + § +
    +

    Denotes the JavaScript runtime scripts to execute on boot.

    + +
    + +
    +
    +
      scripts: ['app.js'],
    +
    +
    + +
  • + + +
  • +
    + +
    + § +
    +

    Provides a map of named Resources to pre-configure.

    + +
    + +
    +
    +
      resources: {
    +    People: Person,
    +    Posts: Post,
    +    Relationships: Relationship,
       },
    -  authorities: {
    -    
    -  }
    -});
    -
    -if ('serviceWorker' in navigator) {
    -  window.addEventListener('load', function() {
    -    navigator.serviceWorker.register('/service.js').then(function(registration) {
    -      console.log('[GUARDIAN]', 'ready: ', registration.scope);
    -    }, function(err) {
    -      console.log('[GUARDIAN]', 'failed: ', err);
    +  authorities: {}
    +};
    +
    +
    + +
  • + + +
  • +
    + +
    + § +
    +

    Dependencies

    +

    Import the App type.

    + +
    + +
    +
    +
    const App = require('../types/app');
    +
    +
    + +
  • + + +
  • +
    + +
    + § +
    +

    Resources

    +

    Resources are named collections.

    + +
    + +
    +
    +
    const Person = require('../resources/person');
    +const Post = require('../resources/post');
    +const Relationship = require('../resources/relationship');
    +
    +
    + +
  • + + +
  • +
    + +
    + § +
    +

    Functions

    +

    Error Handler

    + +
    + +
    +
    +
    function _handleError (error) {
    +  console.error(settings.label, '[ERROR]', error);
    +}
    +
    +
    + +
  • + + +
  • +
    + +
    + § +
    +

    Output Handler

    + +
    + +
    +
    +
    function _handleOutput (output) {
    +  console.log(settings.label, '[READY:OUTPUT]', output);
    +}
    +
    +
    + +
  • + + +
  • +
    + +
    + § +
    +

    Main Process

    + +
    + +
    +
    +
    async function main (input = {}) {
    +
    +
    + +
  • + + +
  • +
    + +
    + § +
    +

    Create and start the Fabric Application

    + +
    + +
    +
    +
      window.app = new App(input);
    +  window.app.start();
    +
    +
    + +
  • + + +
  • +
    + +
    + § +
    +

    Return new Object

    + +
    + +
    +
    +
      return {
    +    app: window.app
    +  };
    +}
    +
    +
    + +
  • + + +
  • +
    + +
    + § +
    +

    Service Workers

    + +
    + +
    +
    +
    if ('serviceWorker' in navigator) {
    +  window.addEventListener('load', function() {
    +    navigator.serviceWorker.register('/service.js').then(function(registration) {
    +      console.log(settings.label, 'Service Worker load ready: ', registration.scope);
    +    }, function(err) {
    +      console.log(settings.label, 'Service Worker load failed: ', err);
         });
       });
    -}
    -
    -window.onload = function () {
    -  app.attach(document.querySelector('fabric-application'));
    - -
  • - - -
  • -
    - -
    - -
    -

    app._load();

    +}
  • +
    +
    -
- -
-  /*/
-  app._defer('localhost:3000');
+      
+
+
+      
  • +
    + +
    + § +
    +

    Bindings

    +

    Assign our onload function

    + +
    + +
    +
    +
    window.onload = function () {
    +  app.attach(document.querySelector('fabric-application'));
    +
    +
    + +
  • + + +
  • +
    + +
    + § +
    +

    app._load(); // loads state into app

    + +
    + +
  • + + +
  • +
    + +
    + § +
    +

    TODO: document defer as trust(authority) with Remote class

    + +
    + +
    +
    +
      /*/
    +  app._defer('localhost:3000'); // use localhost
       /*/
    -  app._defer('maki.io');
    +  app._defer('maki.io'); // use maki.io
       /**/
     
    -  app._explore();
    -}
    - -
  • - + app._explore(); +}
    +
    +
    + + + + +
  • +
    + +
    + § +
    +

    Execution

    + +
    + +
    +
    +
    main(settings).catch(_handleError).then(_handleOutput);
    +
    +
    + +
  • + - + + \ No newline at end of file diff --git a/assets/examples/bitcoin.html b/assets/examples/bitcoin.html new file mode 100644 index 000000000..84f971ece --- /dev/null +++ b/assets/examples/bitcoin.html @@ -0,0 +1,288 @@ + + + + + + bitcoin.js + + + + + + +
    +
    + + + +
      + +
    • +
      +

      bitcoin.js

      +
      +
    • + + + +
    • +
      + +
      + § +
      + +
      + +
      +
      +
      'use strict';
      +
      +require('debug-trace')({ always: true });
      +
      +const Fabric = require('../');
      +const Bitcoin = require('../services/bitcoin');
      +const Wallet = require('../types/wallet');
      +
      +async function main () {
      +  let fabric = new Fabric();
      +  let bitcoin = new Bitcoin({ network: 'regtest' });
      +
      +
      + +
    • + + +
    • +
      + +
      + § +
      +

      let wallet = new Wallet();

      + +
      + +
      +
      +
      +  bitcoin.on('message', function (msg) {
      +    console.log('[DEVELOP]', 'Bitcoin emitted message:', msg);
      +  });
      +
      +
      + +
    • + + +
    • +
      + +
      + § +
      +

      fabric.use(bitcoin);

      + +
      + +
      +
      +
        await bitcoin.start();
      +
      +
      + +
    • + + +
    • +
      + +
      + § +
      +

      await wallet.start();

      + +
      + +
    • + + +
    • +
      + +
      + § +
      +

      TODO: import these into core process logic + await wallet._scanChainForTransactions(bitcoin.blockchain);

      + +
      + +
    • + + +
    • +
      + +
      + § +
      +

      console.log(‘fabric:’, fabric);

      + +
      + +
      +
      +
        console.log('bitcoin state:', bitcoin.state);
      +
      +
      + +
    • + + +
    • +
      + +
      + § +
      +

      console.log(‘wallet state:’, wallet.state);

      + +
      + +
      +
      +
      }
      +
      +module.exports = main();
      +
      +
      + +
    • + +
    +
    + + + \ No newline at end of file diff --git a/assets/examples/blockchain.html b/assets/examples/blockchain.html index 8ac7427e4..6d95da362 100644 --- a/assets/examples/blockchain.html +++ b/assets/examples/blockchain.html @@ -1,194 +1,214 @@ + blockchain.js - + +
    - - +
      - -
    • -
      -

      blockchain.js

      -
      -
    • - - - -
    • -
      - -
      - -
      - -
      - -
      'use strict';
       
      -const Block = require('../types/block');
      -const Chain = require('../types/chain');
      +      
    • +
      +

      blockchain.js

      +
      +
    • + -const genesis = require('../assets/block'); -async function main () { - let chain = new Chain(); +
    • +
      - chain.on('candidate', async function (block) { - console.log('chain received candidate block:', block); +
      + § +
      - let candidate = new Block(block); - let isValid = candidate.validate(); +
      - candidate.compute(); +
      +
      +
      'use strict';
       
      -    console.log('isValid:', isValid);
      +const MAX_BLOCK_COUNT = 9;
       
      -    if (!isValid) {
      - -
    • - - -
    • -
      - -
      - -
      -

      TODO: disconnect peers

      +const Block = require('../types/block'); +const Chain = require('../types/chain'); -
      - -
            return false;
      -    }
      +const genesis = require('../assets/genesis');
       
      -    await chain.append(candidate);
      +async function main () {
      +  const chain = new Chain();
      +  const origin = new Block(genesis);
       
      -    console.log('chain length:', chain['@data'].length);
      +  await chain.append(origin);
       
      -    if (chain['@data'].length < max) {
      -      await chain.mine();
      -    } else {
      -      console.log('Chain filled!');
      -      console.log('Chain:', chain);
      -    }
      -  });
      +  for (let i = 0; i < MAX_BLOCK_COUNT; i++) {
      +
      +
      - let start = new Block(genesis); - await chain.append(start); +
    • - console.log('starting... chain:', chain['@id']); - console.log('mining...'); - await chain.mine(); +
    • +
      - console.log('chain id:', chain['@id']); +
      + § +
      +

      Mine a block

      + +
      + +
      +
      +
          await chain.generateBlock();
      +  }
      +
      +  return chain.toString();
       }
       
      -main();
      - -
    • - +main().catch((exception) => { + console.error('[EXAMPLES:BLOCKCHAIN]', exception); +}).then((output) => { + console.log('[EXAMPLES:BLOCKCHAIN]', 'Output:', output); +});
      +
      +
      + +
    • +
    - + + \ No newline at end of file diff --git a/assets/examples/chain.html b/assets/examples/chain.html index 0d751c57d..9906ae10f 100644 --- a/assets/examples/chain.html +++ b/assets/examples/chain.html @@ -1,154 +1,210 @@ + chain.js - + +
    - - +
      - -
    • -
      -

      chain.js

      -
      -
    • - - - -
    • -
      - -
      - -
      - -
      - -
      'use strict';
       
      -const Chain = require('../lib/chain');
      -const chain = new Chain();
      +      
    • +
      +

      chain.js

      +
      +
    • + + -async function main () { - await chain.storage.open(); +
    • +
      - chain.on('block', function (block) { - console.log('[CHAIN]', 'new block:', block); - console.log('[CHAIN]', 'chain:', chain); +
      + § +
      + +
      + +
      +
      +
      'use strict';
      +
      +
      + +
    • + + +
    • +
      + +
      + § +
      +

      Fabric Dependencies

      + +
      + +
      +
      +
      const Chain = require('../types/chain');
      +const chain = new Chain();
      +
      +async function main () {
      +  await chain.storage.open();
      +
      +  chain.on('block', function (block) {
      +    console.log('[CHAIN]', 'new block:', block);
      +    console.log('[CHAIN]', 'chain:', chain);
         });
       
      -  chain.append({ test: 'foo' });
      -  chain.append({ test: 'bar' });
      +  chain.append({ test: 'foo' });
      +  chain.append({ test: 'bar' });
       
      -  await chain.storage.close();
      +  await chain.storage.close();
       
      -  return this;
      +  return this;
       }
       
      -main();
      - -
    • - +main().catch((exception) => { + console.error('[EXAMPLES:CHAIN]', 'Main Process Exception:', exception); +});
      +
      +
      + +
    • +
    - + + \ No newline at end of file diff --git a/assets/examples/cli.html b/assets/examples/cli.html index 8aca4d6fa..cb53ee256 100644 --- a/assets/examples/cli.html +++ b/assets/examples/cli.html @@ -1,170 +1,207 @@ + cli.js - + +
    - - +
      - -
    • -
      -

      cli.js

      -
      -
    • - - - -
    • -
      - -
      - -
      - -
      - -
      'use strict';
       
      -const CLI = require('../types/cli');
      +      
    • +
      +

      cli.js

      +
      +
    • + + + +
    • +
      + +
      + § +
      + +
      + +
      +
      +
      'use strict';
      +
      +const CLI = require('../types/cli');
       const config = {
      -  path: `./stores/${process.env['NAME'] || 'cli'}`,
      +  path: `./stores/${process.env['NAME'] || 'cli'}`,
         persistent: true,
         oracle: {
      -    port: process.env['PORT'] || 3007
      +    port: process.env['PORT'] || 3007
         }
       };
       
      -async function main () {
      -  const cli = new CLI(config);
      +async function main () {
      +  const cli = new CLI(config);
       
         try {
      -    await cli.start();
      +    await cli.start();
         } catch (E) {
      -    cli.error(`λ`, 'main()', E);
      +    cli.error(`λ`, 'main()', E);
         }
       
      -  cli.on('changes', async function (msg) {
      -    cli.log('[MAIN:CLI]', 'cli event changes:', msg);
      +  cli.on('changes', async function (msg) {
      +    cli.log('[MAIN:CLI]', 'cli event changes:', msg);
         });
       
      -  cli.on('state', function (msg) {
      -    cli.log('[MAIN:CLI]', 'state:', msg);
      +  cli.on('state', function (msg) {
      +    cli.log('[MAIN:CLI]', 'state:', msg);
         });
       
      -  cli.on('state/tip', function (msg) {
      -    cli.log('[MAIN:CLI]', 'state/tip:', msg);
      +  cli.on('state/tip', function (msg) {
      +    cli.log('[MAIN:CLI]', 'state/tip:', msg);
         });
       
      -  cli.on('error', function (E) {
      -    console.error('EXCEPTION:', E);
      +  cli.on('error', function (E) {
      +    console.error('EXCEPTION:', E);
         });
       }
       
      -main();
      - -
    • - +main();
      +
      +
      + +
    • +
    - + + \ No newline at end of file diff --git a/assets/examples/cli_jade.html b/assets/examples/cli_jade.html index 96007c265..f4dd070dc 100644 --- a/assets/examples/cli_jade.html +++ b/assets/examples/cli_jade.html @@ -1,119 +1,123 @@ + cli_jade.js +
    - - +
      - -
    • -
      -

      cli_jade.js

      -
      -
    • - - - -
    • -
      - -
      - -
      - -
      - -
      'use strict';
      +
      +      
    • +
      +

      cli_jade.js

      +
      +
    • + + + +
    • +
      + +
      + +
      + +
      + +
      +
      +
      'use strict';
       
       import Fabric from '../';
       
      @@ -130,22 +134,26 @@ 

      cli_jade.js

      log: console.log, inform: console.log, name: "CLI" -};
      - -
    • - - -
    • -
      - -
      - -
      -

      TODO: use deep assign

      +};
    • +
      +
      -
    - -
    self.config = Object.assign({
    +      
    +
    +
    +      
  • +
    + +
    + +
    +

    TODO: use deep assign

    + +
    + +
    +
    +
    self.config = Object.assign({
         ui: './assets/cli.jade',
         oracle: true,
         swarm: {
    @@ -160,37 +168,45 @@ 

    cli_jade.js

    self.oracle = new Fabric.HTTP(Object.assign({ name: 'fabric', port: 3007 - }, self.config.oracle));
    - -
  • - - -
  • -
    - -
    - -
    -

    this.oracle.on(‘changes’, this._handleChanges.bind(this));

    + }, self.config.oracle));
  • +
    +
    - - -
        self.oracle.on('info', self.inform.bind(self));
    - - - - -
  • -
    - -
    - -
    -

    TODO: move to lib/chat.js

    +
  • - - -
        self.oracle.define('Message', {
    +
    +      
  • +
    + +
    + +
    +

    this.oracle.on(‘changes’, this._handleChanges.bind(this));

    + +
    + +
    +
    +
        self.oracle.on('info', self.inform.bind(self));
    +
    +
    + +
  • + + +
  • +
    + +
    + +
    +

    TODO: move to lib/chat.js

    + +
    + +
    +
    +
        self.oracle.define('Message', {
             routes: {
                 list: '/messages',
                 get: '/messages/:id'
    @@ -243,22 +259,26 @@ 

    cli_jade.js

    self.log('peers:', self.swarm.peers); break; case 'ping': - self.log('pinging peers...');
    - -
  • - - -
  • -
    - -
    - -
    -

    select a random number, broadcast with ping

    + self.log('pinging peers...');
  • +
    +
    - - -
                        self.swarm._broadcastTypedMessage(0x12, Math.random());
    +      
    +
    +
    +      
  • +
    + +
    + +
    +

    select a random number, broadcast with ping

    + +
    + +
    +
    +
                        self.swarm._broadcastTypedMessage(0x12, Math.random());
                         break;
                     case 'state':
                         self.log('state (self):', self.state);
    @@ -282,22 +302,26 @@ 

    cli_jade.js

    } else { if (!data.input) { return self.log(`Message is required.`); - }
    - -
  • - - -
  • -
    - -
    - -
    -

    TODO: visual indicator of “sending…” status

    + }
  • +
    +
    - - -
                let result = await self.oracle._POST('/messages', {
    +      
    +
    +
    +      
  • +
    + +
    + +
    +

    TODO: visual indicator of “sending…” status

    + +
    + +
    +
    +
                let result = await self.oracle._POST('/messages', {
                     created: now.toISOString(),
                     input: data.input
                 });
    @@ -323,33 +347,40 @@ 

    cli_jade.js

    self.textbox.readInput(); }, on_screen_key_esc: function (ch, key) { - self.screen.destroy();
    - -
  • - - -
  • -
    - -
    - -
    -

    console.log(‘the machine:’, self.oracle.machine); -console.log(‘the mempool:’, self.oracle.mempool);

    + self.screen.destroy();
  • +
    +
    - - -
            process.exit();
    +      
    +
    +
    +      
  • +
    + +
    + +
    +

    console.log(‘the machine:’, self.oracle.machine); + console.log(‘the mempool:’, self.oracle.mempool);

    + +
    + +
    +
    +
            process.exit();
         },
     }
     
     jade2cli.renderJadeFile('./assets/cli2.jade', self, event_handlers);
     
    -console.log(Object.keys(self))
    - -
  • - +console.log(Object.keys(self))
    +
    +
    + + + - + + \ No newline at end of file diff --git a/assets/examples/collection.html b/assets/examples/collection.html index 1f0eaf528..7a292db26 100644 --- a/assets/examples/collection.html +++ b/assets/examples/collection.html @@ -1,332 +1,420 @@ + Hello, Collections! - + +
    - - +
      - - - -
    • -
      - -
      - -
      - -
      - -
      'use strict';
      - -
    • - - -
    • -
      - -
      - -
      -

      Hello, Collections!

      -
      - -
      console.log('# Hello, Collections!');
      -console.log('Beginning program...');
      - -
    • - - -
    • -
      - -
      - -
      -

      Some examples include “frontmatter”, or short snippets of YAML-encoded -metadata about a particular document. Feel encouraged to explore any files -in the Fabric repository, as they’ll help you learn more about the overall -design. If in doubt, check the documentation!

      -
      - -
      console.log('---');
      - -
    • - - -
    • -
      - -
      - -
      -

      The Collection example demonstrates how a list of items can be managed.

      -

      Requirements

      -

      We’ll set Collection to a relative path, but in practice you’ll use the -@fabric/core package directly.

      -
      - -
      const Collection = require('../types/collection');
      -const Machine = require('../types/machine');
      - -
    • - - -
    • -
      - -
      - -
      -

      Our main function runs asynchronously, here we define that behavior.

      +
    • +
      -
      - -
      async function main () {
      - -
    • - - -
    • -
      - -
      - -
      -

      Our first operation is to allocate memory for a new Collection.

      +
      + § +
      -
      - -
        let collection = new Collection();
      - -
    • - - -
    • -
      - -
      - -
      -

      Fabric has an entire library full of tools, but here we only need a way to -reproduce our results — for more information on the Machine class, see -the Machine class Documentation.

      +
      -
    - -
      let machine = new Machine();
    - - - - -
  • -
    - -
    - -
    -

    Using the familiar push and pop semantics, we can add and remove items -from our collection.

    +
    +
    +
    'use strict';
    +
    +
    -
    - -
      collection.push({
    -    text: 'Hello, world!',
    -    entropy: machine.sip()
    -  });
    - -
  • - - -
  • -
    - -
    - -
    -

    Direct methods such as create and update may also be used. -Note that this is an async method, and returns a promise.

    +
  • - - -
      await collection.create({
    -    text: 'An army of principles can penetrate where an army of soldiers cannot.',
    -    entropy: machine.sip()
    -  });
    - - - - -
  • -
    - -
    - -
    -

    To retrieve the contents of a collection, use the list method.

    -
    - -
      let content = await collection.list();
    -  console.log('[EXAMPLE]', 'Collection content:', content);
    - -
  • - - -
  • -
    - -
    - -
    -

    Fabric can serialize the object to a JSON-formatted string.

    +
  • +
    -
    - -
      console.log('[EXAMPLE]', 'collection:', collection.render());
    - -
  • - - -
  • -
    - -
    - -
    -

    Collections are maps of their contents. To re-hydrate elements, use the -populate method.

    +
    + § +
    +

    Hello, Collections!

    -
    - -
      console.log('[EXAMPLE]', 'collection.populate():', await collection.populate());
    -
    -  console.log('---');
    -  console.log('### Next Steps');
    -  console.log('Now, try adding elements of your own to the collection.  See: `examples/collection.js`');
    -}
    - -
  • - - -
  • -
    - -
    - -
    -

    Lastly, run the program as defined.

    +
    + +
    +
    +
    console.log('# Hello, Collections!');
    +console.log('Beginning program...');
    +
    +
    + +
  • + + +
  • +
    + +
    + § +
    +

    Some examples include “frontmatter”, or short snippets of YAML-encoded + metadata about a particular document. Feel encouraged to explore any files + in the Fabric repository, as they’ll help you learn more about the overall + design. If in doubt, check the documentation!

    + +
    + +
    +
    +
    console.log('---');
    +
    +
    + +
  • + + +
  • +
    + +
    + § +
    +

    The Collection example demonstrates how a list of items can be managed.

    +

    Requirements

    +

    We’ll set Collection to a relative path, but in practice you’ll use the + @fabric/core package directly. +

    + +
    + +
    +
    +
    const Collection = require('../types/collection');
    +const Machine = require('../types/machine');
    +
    +
    + +
  • + + +
  • +
    + +
    + § +
    +

    Our main function runs asynchronously, here we define that behavior.

    + +
    + +
    +
    +
    async function main () {
    +
    +
    + +
  • + + +
  • +
    + +
    + § +
    +

    Our first operation is to allocate memory for a new Collection.

    + +
    + +
    +
    +
      let collection = new Collection();
    +
    +
    + +
  • + + +
  • +
    + +
    + § +
    +

    Fabric has an entire library full of tools, but here we only need a way to + reproduce our results — for more information on the Machine class, see + the Machine class Documentation. +

    + +
    + +
    +
    +
      let machine = new Machine();
    +
    +
    + +
  • + + +
  • +
    + +
    + § +
    +

    Using the familiar push and pop semantics, we can add and remove items + from our collection.

    + +
    + +
    +
    +
      collection.push({
    +    text: 'Hello, world!',
    +    entropy: machine.sip()
    +  });
    +
    +
    + +
  • + + +
  • +
    + +
    + § +
    +

    Direct methods such as create and update may also be used. + Note that this is an async method, and returns a promise.

    + +
    + +
    +
    +
      await collection.create({
    +    text: 'An army of principles can penetrate where an army of soldiers cannot.',
    +    entropy: machine.sip()
    +  });
    +
    +
    + +
  • + + +
  • +
    + +
    + § +
    +

    To retrieve the contents of a collection, use the list method.

    + +
    + +
    +
    +
      let content = await collection.list();
    +  console.log('[EXAMPLE]', 'Collection content:', content);
    +
    +
    + +
  • + + +
  • +
    + +
    + § +
    +

    Fabric can serialize the object to a JSON-formatted string.

    + +
    + +
    +
    +
      console.log('[EXAMPLE]', 'collection:', collection.render());
    +
    +
    + +
  • + + +
  • +
    + +
    + § +
    +

    Collections are maps of their contents. To re-hydrate elements, use the + populate method. +

    + +
    + +
    +
    +
      console.log('[EXAMPLE]', 'collection.populate():', await collection.populate());
    +
    +  console.log('---');
    +  console.log('### Next Steps');
    +  console.log('Now, try adding elements of your own to the collection.  See: `examples/collection.js`');
    +}
    +
    +
    + +
  • + + +
  • +
    + +
    + § +
    +

    Lastly, run the program as defined.

    + +
    + +
    +
    +
    main();
    +
    +
    + +
  • - - -
    main();
    - - - - + + \ No newline at end of file diff --git a/assets/examples/environment.html b/assets/examples/environment.html new file mode 100644 index 000000000..356144219 --- /dev/null +++ b/assets/examples/environment.html @@ -0,0 +1,304 @@ + + + + + + Importing the Environment type + + + + + + +
    +
    + + + +
      + + + +
    • +
      + +
      + § +
      + +
      + +
      +
      +
      'use strict';
      +
      +
      + +
    • + + +
    • +
      + +
      + § +
      +

      Importing the Environment type

      + +
      + +
      +
      +
      const Environment = require('@fabric/core/types/environment');
      +
      +
      + +
    • + + +
    • +
      + +
      + § +
      +

      Define

      + +
      + +
      +
      +
      async function main () {
      +
      +
      + +
    • + + +
    • +
      + +
      + § +
      +

      Create an instance

      + +
      + +
      +
      +
        const environment = new Environment();
      +
      +
      + +
    • + + +
    • +
      + +
      + § +
      +

      Create an object containing our output

      + +
      + +
      +
      +
        return {
      +
      +
      + +
    • + + +
    • +
      + +
      + § +
      +

      As with all Fabric types, the id property is deterministic, being + derived from the settings object as provided to the constructor.

      + +
      + +
      +
      +
          id: environment.id,
      +
      +
      + +
    • + + +
    • +
      + +
      + § +
      +

      If the environment provides a wallet, it will be listed here

      + +
      + +
      +
      +
          wallet: environment.wallet?.id
      +  };
      +}
      +
      +
      + +
    • + + +
    • +
      + +
      + § +
      +

      Run the example

      + +
      + +
      +
      +
      main().catch((exception) => {
      +  console.error('[EXAMPLE:ENVIRONMENT]', '[EXCEPTION]', exception);
      +}).then((output) => {
      +  console.log('[EXAMPLE:ENVIRONMENT]', '[OUTPUT]', output);
      +});
      +
      +
      + +
    • + +
    +
    + + + \ No newline at end of file diff --git a/assets/examples/fabric.html b/assets/examples/fabric.html new file mode 100644 index 000000000..8a1656881 --- /dev/null +++ b/assets/examples/fabric.html @@ -0,0 +1,248 @@ + + + + + + Getting Started with Fabric + + + + + + +
    +
    + + + +
      + + + +
    • +
      + +
      + § +
      +

      Getting Started with Fabric

      +

      Fabric provides an API for writing, compiling, and executing distributed + applications. In this example, we’ll walk through a few of the basic + operations a typical application might utilize, staying as close to + production-quality code as we can. :)

      + +
      + +
    • + + +
    • +
      + +
      + § +
      +

      Strict mode is used to enforce certain constraints on JavaScript, and is + generally recommended for use when building applications with Fabric.

      + +
      + +
      +
      +
      'use strict';
      +
      +
      + +
    • + + +
    • +
      + +
      + § +
      +

      Since our example begins within the Fabric repository, we’re going to + call require against the local directory, but in a real-world + application you’ll want to use const Fabric = require('@fabric/core'); + to use the correct package (installed with npm i @fabric/core of + course!)

      + +
      + +
      +
      +
      const Fabric = require('../');
      +
      +
      + +
    • + + +
    • +
      + +
      + § +
      +

      We’re going to contain our application withing a main function, defined + here using the async prefix.

      + +
      + +
      +
      +
      async function main() {
      +  let fabric = new Fabric();
      +  console.log('[EXAMPLE]', 'Fabric:', fabric);
      +}
      +
      +
      + +
    • + + +
    • +
      + +
      + § +
      +

      Finally, let’s run our program.

      + +
      + +
      +
      +
      main();
      +
      +
      + +
    • + +
    +
    + + + \ No newline at end of file diff --git a/assets/examples/game.html b/assets/examples/game.html index 27ad692d6..94f99baad 100644 --- a/assets/examples/game.html +++ b/assets/examples/game.html @@ -1,265 +1,314 @@ + game.js - + +
    - - +
      - -
    • -
      -

      game.js

      -
      -
    • - - - -
    • -
      - -
      - -
      - -
      - -
      var _ = require('../lib/functions');
       
      -var Fabric = require('../lib/fabric');
      -var game = new Fabric({
      +      
    • +
      +

      game.js

      +
      +
    • + + + +
    • +
      + +
      + § +
      + +
      + +
      +
      +
      const _ = require('../contracts/functions');
      +
      +const Fabric = require('../types/fabric');
      +const game = new Fabric({
         spawns: []
       });
       
      -var template = require('../data/mob');
      +const template = require('../data/mob');
       
      -game.use('tick', function (input) {
      -  var self = this;
      -  console.log('tick!', self.clock);
      +game.use('tick', function (input) {
      +  const self = this;
      +  console.log('tick!', self.clock);
         return input;
       });
       
      -game.use('spawn', function (input) {
      -  var self = this;
      -  var data = _.clone(template);
      +game.use('spawn', function (input) {
      +  var self = this;
      +  var data = _.clone(template);
       
      -  data.id = Math.random();
      +  data.id = Math.random();
       
      -  var mob = new Fabric(data);
      +  var mob = new Fabric(data);
       
      -  mob.use('attack', function (target, stack) {
      -    console.log('attack!', target);
      -    console.log('attack stack:', stack);
      +  mob.use('attack', function (target, stack) {
      +    console.log('attack!', target);
      +    console.log('attack stack:', stack);
           
      -    mob.broadcast('attack', '/spawns/1');
      +    mob.broadcast('attack', '/spawns/1');
       
           /*var tx = new Transaction({
             
      -    });*/
      - -
    • - - -
    • -
      - -
      - -
      -

      target.transactions.push(tx); -target.transactions.push(tx);

      + });*/
    • +
      +
      -
    - - - - -
  • -
    - -
    - -
    -

    TODO: use fabric call -input.spawns[1].life -= 5;

    +
  • - - -
        
    +
    +      
  • +
    + +
    + § +
    +

    target.transactions.push(tx); + target.transactions.push(tx);

    + +
    + +
  • + + +
  • +
    + +
    + § +
    +

    TODO: use fabric call + input.spawns[1].life -= 5;

    + +
    + +
    +
    +
         return target;
       });
       
    -  mob.on('attack', function (target) {
    -    console.log('mob attack:', target);
    -    game.patch([
    -      { op: 'replace', path: target + '/life', value: 0 }
    -    ]);
    - -
  • - - -
  • -
    - -
    - -
    -

    game.compute();

    + mob.on('attack', function (target) { + console.log('mob attack:', target); + game.patch([ + { op: 'replace', path: target + '/life', value: 0 } + ]);
  • +
    +
    + + - - -
      });
     
    -  mob.compute();
    +      
  • +
    - input.spawns.push(mob); +
    + § +
    +

    game.compute();

    + +
    + +
    +
    +
      });
    +
    +  mob.compute();
    +
    +  input.spawns.push(mob);
     
       return input;
     });
     
    -game.use('battle', function (input) {
    -  var self = this;
    +game.use('battle', function (input) {
    +  var self = this;
       
    -  console.log('battling...', input.spawns);
    +  console.log('battling...', input.spawns);
       
    -  input.spawns[0].stack.push('attack');
    -  input.spawns[0].compute();
    +  input.spawns[0].stack.push('attack');
    +  input.spawns[0].compute();
       
       return input;
     });
     
    -game.stack.push('spawn');
    -game.stack.push('spawn');
    - -
  • - - -
  • -
    - -
    - -
    -

    game.stack.push(‘spawn’);

    +game.stack.push('spawn'); +game.stack.push('spawn');
  • +
    +
    - - -
    game.stack.push('battle');
    +      
    +
    +
    +      
  • +
    + +
    + § +
    +

    game.stack.push(‘spawn’);

    + +
    -game.on('mutation', function(i) { - console.log('m:', i.map(function(x) { - return x.path; +
    +
    +
    game.stack.push('battle');
    +
    +game.on('mutation', function(i) {
    +  console.log('m:', i.map(function(x) {
    +    return x.path;
       }));
     });
     
    -game.compute();
    +game.compute();
     
    -console.log('world:', game['@data'].spawns.map(function(x) {
    +console.log('world:', game['@data'].spawns.map(function(x) {
       return x;
    -}));
    - -
  • - +}));
    +
    +
    + + + - + + \ No newline at end of file diff --git a/assets/examples/heartbeat.html b/assets/examples/heartbeat.html new file mode 100644 index 000000000..e1764f11c --- /dev/null +++ b/assets/examples/heartbeat.html @@ -0,0 +1,350 @@ + + + + + + heartbeat.js + + + + + + +
    +
    + + + +
      + +
    • +
      +

      heartbeat.js

      +
      +
    • + + + +
    • +
      + +
      + § +
      + +
      + +
      +
      +
      'use strict';
      +
      +
      + +
    • + + +
    • +
      + +
      + § +
      +

      Dependencies

      + +
      + +
      +
      +
      const Peer = require('../types/peer');
      +const Swarm = require('../types/swarm');
      +const Message = require('../types/message');
      +
      +
      + +
    • + + +
    • +
      + +
      + § +
      +

      Configuration

      + +
      + +
      +
      +
      const settings = {
      +  seeds: ['localhost:7777']
      +};
      +
      +async function main () {
      +
      +
      + +
    • + + +
    • +
      + +
      + § +
      +

      Create a Hub (seeder peer) and a Swarm (peer cluster)

      + +
      + +
      +
      +
        let seeder = new Peer({ listen: true });
      +  let swarm = new Swarm(settings);
      +
      +
      + +
    • + + +
    • +
      + +
      + § +
      +

      Listeners

      + +
      + +
      +
      +
        seeder.on('message', async function handleHubMessage (msg) {
      +    console.log('[EXAMPLES:HEARTBEAT]', 'Got message on Seed node:', msg.raw);
      +  });
      +
      +  swarm.on('message', async function handleSwarmMessage (msg) {
      +    console.log('[EXAMPLES:HEARTBEAT]', 'Got message on Swarm:', msg.raw);
      +  });
      +
      +
      + +
    • + + +
    • +
      + +
      + § +
      +

      Start component services

      + +
      + +
      +
      +
        console.log('[EXAMPLES:HEARTBEAT]', 'Starting seeder Peer...');
      +  await seeder.start();
      +  console.log('[EXAMPLES:HEARTBEAT]', 'Seeder peer started!');
      +
      +  console.log('[EXAMPLES:HEARTBEAT]', 'Starting Swarm...');
      +  await swarm.start();
      +  console.log('[EXAMPLES:HEARTBEAT]', 'Swarm started!');
      +
      +
      + +
    • + + +
    • +
      + +
      + § +
      +

      Send Regular Updates (outside of internal ping/pong)

      + +
      + +
      +
      +
        const heartbeat = setInterval(function () {
      +    console.warn('[EXAMPLES:HEARTBEAT]', 'Starting to send interval message...');
      +    const message = Message.fromVector(['Generic', Date.now().toString()]);
      +    console.log('[EXAMPLES:HEARTBEAT]', 'Sending :', message.raw);
      +
      +
      + +
    • + + +
    • +
      + +
      + § +
      +

      Send interval message through seed node

      + +
      + +
      +
      +
          seeder.broadcast(message);
      +
      +
      + +
    • + + +
    • +
      + +
      + § +
      +

      Send interval message through swarm agent + swarm.broadcast(message);

      + +
      + +
      +
      +
        }, 5000);
      +}
      +
      +main().catch(function exceptionHandler (exception) {
      +  console.error('[EXAMPLES:HEARTBEAT]', 'Main process threw Exception:', exception);
      +});
      +
      +
      + +
    • + +
    +
    + + + \ No newline at end of file diff --git a/assets/examples/http.html b/assets/examples/http.html index 56d223350..790b63df6 100644 --- a/assets/examples/http.html +++ b/assets/examples/http.html @@ -1,154 +1,309 @@ + - http.js + Exposing ARCs with HTTP - + +
    - - +
      - -
    • -
      -

      http.js

      -
      -
    • - - - -
    • -
      - -
      - -
      - -
      - -
      'use strict';
       
      -const Fabric = require('../');
      -const Authority = require('../lib/authority');
      -const server = new Authority();
       
      -async function main () {
      -  await server.define('Person', {
      -    name: 'Person',
      +
      +      
    • +
      + +
      + § +
      +

      Exposing ARCs with HTTP

      +

      Fabric makes it easy to publish applications to the Web, + giving downstream users access to a hosted instance of the + application.

      +

      By using @fabric/http we can import an existing Fabric + application, and run an HTTP server which exposes a rendered + HTML user interface, complete with progressive enhancement of + features such as real-time updates and hardware-based key + management.

      +

      Quick Start

      + +
      + +
    • + + +
    • +
      + +
      + § +
      +

      Import the @fabric/http library:

      + +
      + +
      +
      +
      const HTTP = require('@fabric/http');
      +
      +
      + +
    • + + +
    • +
      + +
      + § +
      +

      Define the main program:

      + +
      + +
      +
      +
      async function main () {
      +
      +
      + +
    • + + +
    • +
      + +
      + § +
      +

      Create an instance of a Server:

      + +
      + +
      +
      +
        const server = new HTTP.Server();
      +
      +
      + +
    • + + +
    • +
      + +
      + § +
      +

      Define a Resource:

      + +
      + +
      +
      +
        await server.define('Person', {
      +    name: 'Person',
           properties: {
      -      username: { type: String , maxLength: 55 }
      +      username: { type: String , maxLength: 55 }
           },
           routes: {
      -      list: '/people',
      -      view: '/people/:id'
      +      list: '/people',
      +      view: '/people/:id'
           }
      -  });
      +  });
      +
      +
      + +
    • + + +
    • +
      + +
      + § +
      +

      Start the Server instance:

      + +
      + +
      +
      +
        await server.start();
      +}
      +
      +
      + +
    • + - await server.start(); -} +
    • +
      + +
      + § +
      +

      Run Program:

      + +
      + +
      +
      +
      main().catch((exception) => {
      +  console.log('[EXAMPLES:HTTP]', 'HTTP Exception:', exception);
      +});
      +
      +
      + +
    • + + +
    • +
      + +
      + § +
      +

      That’s it! You can now visit https://localhost: to interact + using the HTTP interface for your program.

      +

      Take a look at the other examples to learn more!

      + +
      + +
    • -main();
      - -
    • -
    - + + \ No newline at end of file diff --git a/assets/examples/index.html b/assets/examples/index.html index 7878fbe02..cea833d4a 100644 --- a/assets/examples/index.html +++ b/assets/examples/index.html @@ -1,246 +1,303 @@ + Examples with Fabric - + +
    - - +
      - - - -
    • -
      - -
      - -
      -

      Examples with Fabric

      -

      Fabric is like an operating system for the distributed web. It manages -application state, storage, and network interactions behind the scenes while -providing your application with a convenient event-oriented interface.

      -

      We use strict mode to improve error handling and debugging, so we recommend you do the same.

      -
      - -
      'use strict';
      - -
    • - - -
    • -
      - -
      - -
      -

      Importing Fabric

      -

      Fabric is easily imported into existing applications. When using JavaScript, -use the require semantic to import as a library.

      -
      - -
      const Fabric = require('@fabric/core');
      - -
    • - - -
    • -
      - -
      - -
      -

      Most interactions with Fabric are asynchronous, so let’s define our program’s -primary behavior.

      -
      - -
      async function main () {
      - -
    • - - -
    • -
      - -
      - -
      -
        -
      1. Create an instance of Fabric…
      2. -
      +
    • +
      -
      - -
        let app = new Fabric();
      - -
    • - - -
    • -
      - -
      - -
      -
        -
      1. Add some data…
      2. -
      +
      + § +
      +

      Examples with Fabric

      +

      Fabric is like an operating system for the distributed web. It manages + application state, storage, and network interactions behind the scenes while + providing your application with a convenient event-oriented interface.

      +

      We use strict mode to improve error handling and debugging, so we recommend you do the same.

      -
      - -
        await app._POST(`/inscriptions`, { input: 'Hello, world!' });
      - -
    • - - -
    • -
      - -
      - -
      -
        -
      1. Output some results!
      2. -
      +
      -
    - -
      console.log('app:', app);
    +        
    +
    +
    'use strict';
    +
    +
    + + + + +
  • +
    + +
    + § +
    +

    Importing Fabric

    +

    Fabric is easily imported into existing applications. When using JavaScript, + use the require semantic to import as a library.

    + +
    + +
    +
    +
    const Fabric = require('@fabric/core');
    +
    +
    + +
  • + + +
  • +
    + +
    + § +
    +

    Most interactions with Fabric are asynchronous, so let’s define our program’s + primary behavior.

    + +
    + +
    +
    +
    async function main () {
    +
    +
    + +
  • + + +
  • +
    + +
    + § +
    +
      +
    1. Create an instance of Fabric…
    2. +
    + +
    + +
    +
    +
      let app = new Fabric();
    +
    +
    + +
  • + + +
  • +
    + +
    + § +
    +
      +
    1. Add some data…
    2. +
    + +
    + +
    +
    +
      await app._POST(`/inscriptions`, { input: 'Hello, world!' });
    +
    +
    + +
  • + + +
  • +
    + +
    + § +
    +
      +
    1. Output some results!
    2. +
    + +
    + +
    +
    +
      console.log('app:', app);
     }
     
    -main();
    - -
  • - - -
  • -
    - -
    - -
    -

    Now that we’ve defined our program, let’s run it to see the results.

    +main();
  • +
    +
    - - - - - -
  • -
    - -
    - -
    -

    Next Steps

    -

    That’s all there is to it! Now, on to the API Explorer!

    +
  • + + +
  • +
    + +
    + § +
    +

    Now that we’ve defined our program, let’s run it to see the results.

    + +
    + +
  • + + +
  • +
    + +
    + § +
    +

    Next Steps

    +

    That’s all there is to it! Now, on to the API Explorer!

    + +
    + +
  • - - - - - + + \ No newline at end of file diff --git a/assets/examples/lightning.html b/assets/examples/lightning.html new file mode 100644 index 000000000..5608fe476 --- /dev/null +++ b/assets/examples/lightning.html @@ -0,0 +1,194 @@ + + + + + + lightning.js + + + + + + +
    +
    + + + +
      + +
    • +
      +

      lightning.js

      +
      +
    • + + + +
    • +
      + +
      + § +
      + +
      + +
      +
      +
      'use strict';
      +
      +const Lightning = require('@fabric/core/services/lightning');
      +
      +async function main () {
      +  const lightning = new Lightning({
      +    mode: 'socket',
      +    path: './stores/lightning-playnet/regtest/lightning-rpc'
      +  });
      +
      +  await lightning.start();
      +
      +  const funds = await lightning._makeRPCRequest('listfunds');
      +
      +  return {
      +    id: lightning.id,
      +    funds: funds
      +  };
      +}
      +
      +main().catch((exception) => {
      +  console.error('[EXAMPLES:LIGHTNING]', 'Main Process Exception:', exception);
      +}).then((output) => {
      +  console.log('[EXAMPLES:LIGHTNING]', 'Main Process Output:', output);
      +});
      +
      +
      + +
    • + +
    +
    + + + \ No newline at end of file diff --git a/assets/examples/message.html b/assets/examples/message.html new file mode 100644 index 000000000..53302763b --- /dev/null +++ b/assets/examples/message.html @@ -0,0 +1,274 @@ + + + + + + message.js + + + + + + +
    +
    + + + +
      + +
    • +
      +

      message.js

      +
      +
    • + + + +
    • +
      + +
      + § +
      + +
      + +
      +
      +
      #!/usr/bin/env node
      +'use strict';
      +
      +
      + +
    • + + +
    • +
      + +
      + § +
      +

      Dependencies

      + +
      + +
      +
      +
      const Message = require('../types/message');
      +
      +
      + +
    • + + +
    • +
      + +
      + § +
      +

      Main Process

      + +
      + +
      +
      +
      async function main () {
      +
      +
      + +
    • + + +
    • +
      + +
      + § +
      +

      Create Message instance

      + +
      + +
      +
      +
        const message = Message.fromVector(['GenericMessage', '"Hello, world!"']);
      +
      +
      + +
    • + + +
    • +
      + +
      + § +
      +

      Return generic Object

      + +
      + +
      +
      +
        return {
      +    message: message,
      +    raw: message.asRaw()
      +  };
      +}
      +
      +
      + +
    • + + +
    • +
      + +
      + § +
      +

      Execution

      + +
      + +
      +
      +
      main().catch((exception) => {
      +  console.error('[EXAMPLES:MESSAGE]', 'Main Process Exception:', exception);
      +}).then((output) => {
      +  console.log('[EXAMPLES:MESSAGE]', 'Main Process Output:', output);
      +});
      +
      +
      + +
    • + +
    +
    + + + \ No newline at end of file diff --git a/assets/examples/network.html b/assets/examples/network.html index 6c6f88627..2a680848c 100644 --- a/assets/examples/network.html +++ b/assets/examples/network.html @@ -1,188 +1,229 @@ + network.js - + +
    - - +
      - -
    • -
      -

      network.js

      -
      -
    • - - - -
    • -
      - -
      - -
      - -
      - -
      'use strict';
       
      -const Fabric = require('../');
      +      
    • +
      +

      network.js

      +
      +
    • + + + +
    • +
      + +
      + § +
      + +
      -const NETWORK_NAME = 'playnet'; -const NODE_COUNT = 3; -const PEERING_PORT = 7450; +
      +
      +
      'use strict';
      +
      +const playnet = require('../settings/playnet');
      +const Peer = require('../types/peer');
      +const Message = require('../types/message');
      +
      +const NODE_COUNT = 3;
      +const PEERING_PORT = 7450;
       
       /**
        * Simulate a Fabric network based on the constants above.
      - * @return {[type]} [description]
      + * @return {[type]} [description]
        */
      -async function simulate () {
      -  let nodes = {};
      -  let ids = [];
      +async function simulate () {
      +  const nodes = {};
      +  const ids = [];
       
      -  for (let i = 0; i < NODE_COUNT; i++) {
      -    let node = new Fabric.Peer({
      -      port: PEERING_PORT + i
      +  for (let i = 0; i < NODE_COUNT; i++) {
      +    const node = new Peer({
      +      listen: true,
      +      port: PEERING_PORT + i // Each peer (after the first) uses port n + 1,
           });
      -    console.log(`node id: ${node.id}`, node.id);
      -    nodes[node.id] = node;
      -    ids.push(node.id);
      +
      +    console.log(`Created node id: ${node.id}`, node.id);
      +
      +    nodes[node.id] = node;
      +    ids.push(node.id);
         }
       
      -  console.log('nodes:', nodes);
      +  console.log('nodes:', nodes);
       
      -  for (let id in nodes) {
      -    console.log(`starting ${id}...`);
      -    let node = nodes[id];
      +  for (const id in nodes) {
      +    console.log(`starting ${id}...`);
      +    const node = nodes[id];
       
      -    node.on('ready', function () {
      -      console.log(`node ${id} is ready!`);
      -      let peers = Object.keys(nodes).filter(x => x !== id);
      -      console.log(`node ${id} knows peers:`, peers);
      +    node.on('ready', function () {
      +      console.log(`node ${id} is ready!`);
      +      const peers = Object.keys(nodes).filter(x => x !== id);
      +      console.log(`node ${id} knows peers:`, peers);
       
      -      for (let i in peers) {
      -        let peerID = peers[i];
      -        let address = `${nodes[peerID].address}:${nodes[peerID].port}`;
      -        console.log(`node ${id} connecting to ${address}...`);
      -        node._connect(address);
      +      for (const i in peers) {
      +        const peerID = peers[i];
      +        const address = `${nodes[peerID].address}:${nodes[peerID].port}`;
      +        console.log(`node ${id} connecting to ${address}...`);
      +        node._connect(address);
             }
           });
       
      -    nodes[id].listen();
      +    nodes[id].listen();
         }
       
      -  let origin = nodes[ids[0]];
      -  let message = Fabric.Message.fromVector([0x00000012, Date.now() + '']); // ping
      +  const origin = nodes[ids[0]];
      +  const message = Message.fromVector([0x00000012, Date.now() + '']); // ping
       
      -  console.log('broadcasting message to all peers:', message);
      +  console.log('broadcasting message to all peers:', message);
       
      -  origin.broadcast(message);
      +  origin.broadcast(message);
       }
       
      -simulate();
      - -
    • - +simulate();
      +
      +
      + +
    • +
    - + + \ No newline at end of file diff --git a/assets/examples/oracle.html b/assets/examples/oracle.html index 13d7d22f7..0a48f290f 100644 --- a/assets/examples/oracle.html +++ b/assets/examples/oracle.html @@ -1,384 +1,453 @@ + oracle.js - + +
    - - +
      - -
    • -
      -

      oracle.js

      -
      -
    • - - - -
    • -
      - -
      - -
      -

      An example of an Oracle built with @fabric/core, a framework for building high-throughput distributed systems with Bitcoin.

      -
      - -
    • - - -
    • -
      - -
      - -
      -

      An Oracle offers a simple, self- contained -Service for establishing and -verifying claims made against an underlying trust anchor.

      +
    • +
      +

      oracle.js

      +
      +
    • -
    - - - - -
  • -
    - -
    - -
    -

    When combined with an HTML browser, an Oracle can be used to manage -long-running State for -offline-first applications.

    -
    - -
  • - - -
  • -
    - -
    - -
    -

    Quick Start

    -

    Run locally with node examples/oracle.js — use Node 8, a la nvm use 8 -if you’re using NVM, or from -nodejs.org if not!

    -
    - -
  • - - -
  • -
    - -
    - -
    -

    TODO: use bottom panel for inline execution (a la “Run this Code »”)

    -

    Source

    +
  • +
    -
    - -
  • - - -
  • -
    - -
    - -
    -

    First, let’s ensure strict mode is used to parse our code.

    +
    + § +
    +

    An example of an Oracle built with @fabric/core, a framework for building high-throughput distributed systems with Bitcoin.

    -
    - -
    'use strict';
    - -
  • - - -
  • -
    - -
    - -
    -

    Require @fabric/core as the Fabric constant. This allows us to use the -Fabric API directly: new Fabric.<type>()

    +
    - - -
    const Fabric = require('@fabric/core');
    - -
  • - - -
  • -
    - -
    - -
    -

    An example configuration object, encoded as JSON:

    -
    {
    -  "name": "@examples/oracle",
    -  "description": "a simple Oracle example",
    -  "version": "0.1.0"
    -}
    -

    Configuration files are most commonly stored in config.json, but you can -also use an existing package.json to pre-load an Oracle with some state.

    +
  • + + +
  • +
    + +
    + § +
    +

    An Oracle offers a simple, self- contained + Service for establishing and + verifying claims made against an underlying trust anchor. +

    + +
    + +
  • + + +
  • +
    + +
    + § +
    +

    When combined with an HTML browser, an Oracle can be used to manage + long-running State for + offline-first applications.

    + +
    + +
  • + + +
  • +
    + +
    + § +
    +

    Quick Start

    +

    Run locally with node examples/oracle.js — use Node 12, a la + nvm use 12 if you’re using NVM, or from + nodejs.org if not! +

    + +
    + +
  • + + +
  • +
    + +
    + § +
    +

    TODO: use bottom panel for inline execution (a la “Run this Code »”)

    +

    Source

    + +
    + +
  • - - -
    -const config = require('./config');
    +
    +      
  • +
    + +
    + § +
    +

    First, let’s ensure strict mode is used to parse our code.

    + +
    + +
    +
    +
    'use strict';
    +
    +
    + +
  • + + +
  • +
    + +
    + § +
    +

    Import types from @fabric/core:

    + +
    + +
    +
    +
    const Oracle = require('@fabric/core/types/oracle');
    +
    +
    + +
  • + + +
  • +
    + +
    + § +
    +

    An example configuration object, encoded as JSON:

    +
    {
    +  "name": "@examples/oracle",
    +  "description": "a simple Oracle example",
    +  "version": "0.1.0"
    +}
    +
    +

    Configuration files are most commonly stored in config.json, but you can + also use an existing package.json to pre-load an Oracle with some state.

    + +
    + +
    +
    +
    +const config = require('./config');
     
     /**
    - * An {@link Oracle} offers a simple, self-contained {@link Service} for Fabric-
    + * An {@link Oracle} offers a simple, self-contained {@link Service} for Fabric-
      * capable agents.  The `main()` function allocates necessary resources, then
      * starts the service.
      */
    -async function main () {
    - -
  • - - -
  • -
    - -
    - -
    -

    Our primary objective is to create an Oracle, so we do that next by passing -the config constant from earlier into the Fabric.Oracle constructor.

    +async function main () {
  • +
    +
    - - -
      let oracle = new Fabric.Oracle(config);
    - - - - -
  • -
    - -
    - -
    -

    The oracle variable contains our Oracle, so now let’s define a Resource -for it to manage.

    +
  • - - - - - -
  • -
    - -
    - -
    -

    Resources

    -

    An Oracle’s purpose is to provide a canonical reference for a list of -Resources, which require both a name -and a definition. Resources can be thought of as “typed collections”, -with atomic operations such as POP and PUSH for managing their -contents.

    -
    - -
  • - - -
  • -
    - -
    - -
    -

    Here, we define a Request as a resource with one field, input, which is -both required and restricted to a maximum size of 2048 bytes.

    +
  • +
    -
    - -
      oracle.define('Request', {
    +          
    + § +
    +

    Our primary objective is to create an Oracle, so we do that next by passing + the config constant from earlier into the Fabric.Oracle constructor.

    + +
    + +
    +
    +
      const oracle = new Oracle(config);
    +
    +
    + +
  • + + +
  • +
    + +
    + § +
    +

    The oracle variable contains our Oracle, so now let’s define a Resource + for it to manage.

    + +
    + +
  • + + +
  • +
    + +
    + § +
    +

    Resources

    +

    An Oracle’s purpose is to provide a canonical reference for a list of + Resources, which require both a name + and a definition. Resources can be thought of as “typed collections”, + with atomic operations such as POP and PUSH for managing their + contents. +

    + +
    + +
  • + + +
  • +
    + +
    + § +
    +

    Here, we define a Request as a resource with one field, input, which is + both required and restricted to a maximum size of 2048 bytes.

    + +
    + +
    +
    +
      oracle.define('Request', {
         attributes: {
    -      input: { type: 'String', required: true, max: 2048 }
    +      input: { type: 'String', required: true, max: 2048 }
         }
    -  });
    - -
  • - - -
  • -
    - -
    - -
    -

    Now that a Resource has been defined, start the Oracle.

    + }); +
    + - - -
      await oracle.start();
    - -
  • - - -
  • -
    - -
    - -
    -

    Log some output.

    +
  • - - -
      console.log('oracle started!');
    -  console.log('oracle:', oracle);
    -}
    - - - - -
  • -
    - -
    - -
    -

    We’ve defined our program. Start the main process!

    -
    - -
    module.exports = main();
    - -
  • - - -
  • -
    - -
    - -
    -

    Fabric exposes a powerful API through @fabric/core, a standard library for -building decentralized applications. You can install it now by using the -npm install --save @fabric/core command, or use -npm install FabricLabs/fabric#develop for bleeding-edge #beta testing.

    +
  • +
    + +
    + § +
    +

    Now that a Resource has been defined, start the Oracle.

    + +
    + +
    +
    +
      await oracle.start();
    +
    +
    + +
  • + + +
  • +
    + +
    + § +
    +

    Log some output.

    + +
    + +
    +
    +
      console.log('oracle started!');
    +  console.log('oracle:', oracle);
    +}
    +
    +
    + +
  • + + +
  • +
    + +
    + § +
    +

    We’ve defined our program. Start the main process!

    + +
    + +
    +
    +
    module.exports = main();
    +
    +
    + +
  • + + +
  • +
    + +
    + § +
    +

    Fabric exposes a powerful API through @fabric/core, a standard library for + building decentralized applications. You can install it now by using the + npm install --save @fabric/core command, or use + npm install FabricLabs/fabric#develop for bleeding-edge #beta testing. +

    + +
    + +
  • - - - - - + + \ No newline at end of file diff --git a/assets/examples/p2pkh.html b/assets/examples/p2pkh.html index ac9f4b697..d88652ef4 100644 --- a/assets/examples/p2pkh.html +++ b/assets/examples/p2pkh.html @@ -1,163 +1,204 @@ + p2pkh.js - + +
    - - +
      - -
    • -
      -

      p2pkh.js

      -
      -
    • - - - -
    • -
      - -
      - -
      - -
      - -
      'use strict';
      -
      -var Fabric = require('../');
      -var fabric = new Fabric();
      -
      -fabric.use('OP_CHECKSIG', function (sig) {
      -  console.log('computing with OP_CHECKSIG:', sig);
      -  return true; // ;)
      - -
    • - - -
    • -
      - -
      - -
      -

      return this.validateSignature(sig, ‘test’);

      -
      - -
      });
      +      
    • +
      +

      p2pkh.js

      +
      +
    • + + + +
    • +
      -fabric.stack.push('<PUBLIC_KEY>'); -fabric.stack.push('<SIGNATURE>'); -fabric.stack.push('OP_CHECKSIG'); +
      + § +
      + +
      + +
      +
      +
      'use strict';
      +
      +var Fabric = require('../');
      +var fabric = new Fabric();
      +
      +fabric.use('OP_CHECKSIG', function (sig) {
      +  console.log('computing with OP_CHECKSIG:', sig);
      +  return true; // ;)
      +
      +
      + +
    • + + +
    • +
      -fabric.compute(); +
      + § +
      +

      return this.validateSignature(sig, ‘test’);

      + +
      + +
      +
      +
      });
      +
      +fabric.stack.push('<PUBLIC_KEY>');
      +fabric.stack.push('<SIGNATURE>');
      +fabric.stack.push('OP_CHECKSIG');
      +
      +fabric.compute();
      +
      +console.log('test:', fabric);
      +
      +
      + +
    • -console.log('test:', fabric);
      - -
    • -
    - + + \ No newline at end of file diff --git a/assets/examples/relay.html b/assets/examples/relay.html new file mode 100644 index 000000000..9fe498770 --- /dev/null +++ b/assets/examples/relay.html @@ -0,0 +1,310 @@ + + + + + + relay.js + + + + + + +
    +
    + + + +
      + +
    • +
      +

      relay.js

      +
      +
    • + + + +
    • +
      + +
      + § +
      + +
      + +
      +
      +
      'use strict';
      +
      +require('debug-trace')({ always: true });
      +
      +const SEEDS = {
      +  origin: 'unknown burger engine plug teach spot squeeze fringe ethics skate riot brand hurry melody double then trumpet impulse lesson inflict enlist eager region ride',
      +  relayer: 'salmon asthma decorate oxygen relief excite lamp huge bunker tennis spread chase liar glass shoe giant crane drama media step crack decline ring stay',
      +  destination: 'frown equal zero tackle relief shallow leisure diet roast festival good plunge pencil virus vote property blame random bacon rich ecology major survey slice'
      +}
      +
      +const DESTINATION_ID = 'mt4Wm6TW4ejU51iviiD73ECNCfRsjiBhQf';
      +
      +
      + +
    • + + +
    • +
      + +
      + § +
      +

      Dependencies

      + +
      + +
      +
      +
      const Peer = require('../types/peer');
      +const Message = require('../types/message');
      +
      +async function main () {
      +  const swarm = {
      +    origin: new Peer({
      +      listen: true,
      +      wallet: {
      +        seed: SEEDS.origin
      +      }
      +    }),
      +    relayer: new Peer({
      +      port: 7778,
      +      peers: ['localhost:7777'],
      +      listen: true,
      +      wallet: {
      +        seed: SEEDS.relayer
      +      }
      +    }),
      +    destination: new Peer({
      +      peers: ['localhost:7778'],
      +      wallet: {
      +        seed: SEEDS.destination
      +      }
      +    })
      +  };
      +
      +
      + +
    • + + +
    • +
      + +
      + § +
      +

      Core functionality (wait for peer, send message)

      + +
      + +
      +
      +
        swarm.origin.on('peer:candidate', async function (peer) {
      +    console.log('[EXAMPLES:RELAY]', 'Origin Peer emitted "peer:candidate" event:', peer);
      +
      +    if (peer.id === DESTINATION_ID) {
      +      console.warn('[EXAMPLES:RELAY]', 'Peer event was destination peer!');
      +      console.warn('[EXAMPLES:RELAY]', 'Origin node peers:', swarm.origin.peers);
      +      console.warn('[EXAMPLES:RELAY]', 'Relay node peers:', swarm.relayer.peers);
      +      console.warn('[EXAMPLES:RELAY]', 'Destination node peers:', swarm.destination.peers);
      +
      +
      + +
    • + + +
    • +
      + +
      + § +
      +

      Send Message

      + +
      + +
      +
      +
            let message = Message.fromVector(['Generic', 'Hello, world!']);
      +      await swarm.origin.broadcast(message);
      +    }
      +  });
      +
      +  swarm.destination.on('message', async function handleSwarmMessage (msg) {
      +    console.log('[EXAMPLES:RELAY]', 'Got message on destination:', msg);
      +  });
      +
      +
      + +
    • + + +
    • +
      + +
      + § +
      +

      Start component services

      + +
      + +
      +
      +
        console.log('[EXAMPLES:RELAY]', 'Starting origin Peer...');
      +  await swarm.origin.start();
      +  console.log('[EXAMPLES:RELAY]', 'Origin Peer started!');
      +
      +  console.log('[EXAMPLES:RELAY]', 'Starting relayer Peer...');
      +  await swarm.relayer.start();
      +  console.log('[EXAMPLES:RELAY]', 'Relayer Peer started!');
      +
      +  console.log('[EXAMPLES:RELAY]', 'Starting destination Peer...');
      +  await swarm.destination.start();
      +  console.log('[EXAMPLES:RELAY]', 'Destination Peer started!');
      +}
      +
      +main().catch(function exceptionHandler (exception) {
      +  console.error('[EXAMPLES:RELAY]', 'Main process threw Exception:', exception);
      +});
      +
      +
      + +
    • + +
    +
    + + + \ No newline at end of file diff --git a/assets/examples/service.html b/assets/examples/service.html index cdfcd07f8..824e1a21a 100644 --- a/assets/examples/service.html +++ b/assets/examples/service.html @@ -1,225 +1,272 @@ + service.js - + +
    - - +
      - -
    • -
      -

      service.js

      -
      -
    • - - - -
    • -
      - -
      - -
      -

      importScripts(‘/app.min.js’);

      -
      - -
      -var url = require('url');
      -var Stash = require('../types/stash');
      +      
    • +
      +

      service.js

      +
      +
    • + + + +
    • +
      + +
      + § +
      +

      importScripts(‘/app.min.js’);

      + +
      + +
      +
      +
      +const url = require('url');
      +const Stash = require('../types/stash');
       
      -self.addEventListener('message', function (e) {
      -  e.source.postMessage('[GUARDIAN]', 'Hello! Your message was: ' + e.data);
      +self.addEventListener('message', function (e) {
      +  e.source.postMessage('[GUARDIAN]', 'Hello! Your message was: ' + e.data);
       });
       
      -self.addEventListener('fetch', async function (event) {
      -  var self = this;
      -  
      -  return true;
      -  console.log('[GUARDIAN]', 'request:', event);
      -
      -  var path = event.request.url;
      -  var target = url.parse(path);
      -  var uri = target.pathname;
      -
      -  var stash = new Stash();
      -  console.log('stash:', stash);
      -  console.log('target:', target);
      - -
    • - - -
    • -
      - -
      - -
      -

      await stash.set(‘/messages’, [{ foo: ‘bar’ }]);

      +self.addEventListener('fetch', async function (event) { + const self = this; + console.log('[GUARDIAN]', 'request:', event); -
      - -
        console.log('recovery:', await stash.get('/messages'));
      +  const path = event.request.url;
      +  const target = url.parse(path);
      +  const uri = target.pathname;
      +
      +  const stash = new Stash();
      +  console.log('stash:', stash);
      +  console.log('target:', target);
      +
      +
      + +
    • + + +
    • +
      + +
      + § +
      +

      await stash.set(‘/messages’, [{ foo: ‘bar’ }]);

      - var value = await stash.get(uri); +
      + +
      +
      +
        console.log('recovery:', await stash.get('/messages'));
      +
      +  const value = await stash.get(uri);
         if (value) {
      -    console.log('was cached:', uri, value.length, 'bytes');
      -    var request = new Request(uri, {
      - -
    • - - -
    • -
      - -
      - -
      -

      TODO: revert to OPTIONS (this was a temporary fix for an NGINX bug)

      + console.log('was cached:', uri, value.length, 'bytes'); + const request = new Request(uri, {
    • +
      +
      -
    - -
          method: 'HEAD'
    +      
    +
    +
    +      
  • +
    + +
    + § +
    +

    TODO: revert to OPTIONS (this was a temporary fix for an NGINX bug)

    + +
    + +
    +
    +
          method: 'HEAD'
         });
     
    -    var response = await fetch(request);
    - -
  • - - -
  • -
    - -
    - -
    -

    var content = await response.text();

    + const response = await fetch(request);
  • +
    +
    + + - - -
        return value;
    +
    +      
  • +
    + +
    + § +
    +

    const content = await response.text();

    + +
    + +
    +
    +
        return value;
       } else {
    -    var request = new Request(uri, {
    +    const request = new Request(uri, {
           headers: {
    -        'X-Identity': 'foo'
    +        'X-Identity': 'foo'
           }
         });
     
    -    var response = await fetch(request);
    -    var content = await response.text();
    -    console.log('response:', uri, content.length);
    +    const response = await fetch(request);
    +    const content = await response.text();
    +    console.log('response:', uri, content.length);
     
         if (content) {
    -      stash.set(uri, content);
    +      stash.set(uri, content);
         }
     
         return request;
       }
    -});
    - -
  • - +});
    +
    +
    + + + - + + \ No newline at end of file diff --git a/assets/examples/store.html b/assets/examples/store.html index 3ab85c56a..899941fa2 100644 --- a/assets/examples/store.html +++ b/assets/examples/store.html @@ -1,272 +1,333 @@ + Storing Data in Fabric - + +
    - - +
      - - - -
    • -
      - -
      - -
      -

      Storing Data in Fabric

      -
      - -
    • - - -
    • -
      - -
      - -
      -

      One of Fabric’s utilities is as a storage layer for your application. By -using the Fabric.Store constructor, you can interact with the network as if -it were local storage.

      -

      In this example, we’ll run a single process main() demonstrating common -interactions with Fabric’s Storage Engine.

      -
      - -
      'use strict';
      -
      -const Fabric = require('../');
      -const name = 'martindale';
      -const key = new Fabric.Key();
      -const pointer = require('json-pointer');
      - -
    • - - -
    • -
      - -
      - -
      -

      Primary Process

      -

      Here, we define our main process.

      -
      - -
      async function main () {
      -  let fabric = new Fabric({
      -    name: '@fabric/examples/store',
      -    path: './data/examples',
      +      
    • +
      + +
      + § +
      +

      Storing Data in Fabric

      + +
      + +
    • + + +
    • +
      + +
      + § +
      +

      One of Fabric’s utilities is as a storage layer for your application. By + using the Fabric.Store constructor, you can interact with the network as if + it were local storage.

      +

      In this example, we’ll run a single process main() demonstrating common + interactions with Fabric’s Storage Engine.

      + +
      + +
      +
      +
      'use strict';
      +
      +const Fabric = require('../');
      +const name = 'martindale';
      +const key = new Fabric.Key();
      +const pointer = require('json-pointer');
      +
      +
      + +
    • + + +
    • +
      + +
      + § +
      +

      Primary Process

      +

      Here, we define our main process.

      + +
      + +
      +
      +
      async function main () {
      +  let fabric = new Fabric({
      +    name: '@fabric/examples/store',
      +    path: './data/examples',
           persistent: false
      -  });
      - -
    • - - -
    • -
      - -
      - -
      -

      Start the Fabric instance, and log any errors.

      + });
    • +
      +
      -
    - -
      await fabric.start().catch(fabric.error.bind(fabric));
    - - - - -
  • -
    - -
    - -
    -

    Let’s use /players as the “address” for a collection of data.

    +
  • - - -
      let mem = `/players`;
    -  let path = pointer.escape(mem);
    -  let router = Fabric.sha256(path);
    - - - - -
  • -
    - -
    - -
    -

    Use _POST(collection, item) to insert an item into a named collection -for later retrieval.

    -
    - -
      let link = await fabric._POST(mem, {
    +      
  • +
    + +
    + § +
    +

    Start the Fabric instance, and log any errors.

    + +
    + +
    +
    +
      await fabric.start().catch(fabric.error.bind(fabric));
    +
    +
    + +
  • + + +
  • +
    + +
    + § +
    +

    Let’s use /players as the “address” for a collection of data.

    + +
    + +
    +
    +
      let mem = `/players`;
    +  let path = pointer.escape(mem);
    +  let router = Fabric.sha256(path);
    +
    +
    + +
  • + + +
  • +
    + +
    + § +
    +

    Use _POST(collection, item) to insert an item into a named collection + for later retrieval.

    + +
    + +
    +
    +
      let link = await fabric._POST(mem, {
         name: name,
    -    key: key['@data']
    -  }).catch(fabric.error.bind(fabric));
    -
    -  console.log('[HTTP]', 201, 'Created', 'link:', `fabric:${link}`);
    -  console.log('link:', link);
    -
    -  let player = await fabric._GET(link).catch(fabric.error.bind(fabric));
    -  console.log('player:', player);
    -
    -  let players = await fabric._GET(mem).catch(fabric.error.bind(fabric));
    -  let collection = await fabric._GET(`/collections/${router}`).catch(fabric.error.bind(fabric));
    - -
  • - - -
  • -
    - -
    - -
    -

    clean up after ourselves

    + key: key['@data'] + }).catch(fabric.error.bind(fabric)); -
    - -
      await fabric.stop().catch(fabric.error.bind(fabric));
    -
    -  console.log('players:', players);
    -  console.log('collection:', collection);
    - -
  • - - -
  • -
    - -
    - -
    -

    console.log(‘fabric:’, fabric); -console.log(‘state:’, fabric.store.state); -console.log(‘players:’, players.constructor.name, players);

    + console.log('[HTTP]', 201, 'Created', 'link:', `fabric:${link}`); + console.log('link:', link); -
    - -
    }
    +  let player = await fabric._GET(link).catch(fabric.error.bind(fabric));
    +  console.log('player:', player);
    +
    +  let players = await fabric._GET(mem).catch(fabric.error.bind(fabric));
    +  let collection = await fabric._GET(`/collections/${router}`).catch(fabric.error.bind(fabric));
    +
    +
    + +
  • + + +
  • +
    + +
    + § +
    +

    clean up after ourselves

    + +
    + +
    +
    +
      await fabric.stop().catch(fabric.error.bind(fabric));
    +
    +  console.log('players:', players);
    +  console.log('collection:', collection);
    +
    +
    + +
  • + + +
  • +
    + +
    + § +
    +

    console.log(‘fabric:’, fabric); + console.log(‘state:’, fabric.store.state); + console.log(‘players:’, players.constructor.name, players);

    + +
    + +
    +
    +
    }
     
     try {
    -  main();
    +  main();
     } catch (E) {
    -  console.trace(E);
    -}
    - -
  • - + console.trace(E); +}
    +
    +
    + +
  • + - + + \ No newline at end of file diff --git a/assets/examples/swarm.html b/assets/examples/swarm.html new file mode 100644 index 000000000..4d4b438bc --- /dev/null +++ b/assets/examples/swarm.html @@ -0,0 +1,385 @@ + + + + + + swarm.js + + + + + + +
    +
    + + + +
      + +
    • +
      +

      swarm.js

      +
      +
    • + + + +
    • +
      + +
      + § +
      + +
      + +
      +
      +
      'use strict';
      +
      +
      + +
    • + + +
    • +
      + +
      + § +
      +

      Dependencies

      + +
      + +
      +
      +
      const Peer = require('../types/peer');
      +const Swarm = require('../types/swarm');
      +const Message = require('../types/message');
      +
      +
      + +
    • + + +
    • +
      + +
      + § +
      +

      Configuration

      + +
      + +
      +
      +
      const settings = {
      +  seeds: ['localhost:7777']
      +};
      +
      +async function main () {
      +
      +
      + +
    • + + +
    • +
      + +
      + § +
      +

      Create a Hub (seeder peer) and a Swarm (peer cluster)

      + +
      + +
      +
      +
        let seeder = new Peer({ listen: true });
      +  let swarm = new Swarm(settings);
      +  let downstream = new Peer();
      +
      +
      + +
    • + + +
    • +
      + +
      + § +
      +

      Listeners

      + +
      + +
      +
      +
        seeder.on('message', async function handleHubMessage (msg) {
      +    console.log('[EXAMPLES:SWARM]', 'Got message on Seed node:', msg.raw);
      +  });
      +
      +  swarm.on('message', async function handleSwarmMessage (msg) {
      +    console.log('[EXAMPLES:SWARM]', 'Got message on Swarm:', msg.raw);
      +  });
      +
      +
      + +
    • + + +
    • +
      + +
      + § +
      +

      Start component services

      + +
      + +
      +
      +
        console.log('[EXAMPLES:SWARM]', 'Starting seeder Peer...');
      +  await seeder.start();
      +  console.log('[EXAMPLES:SWARM]', 'Seeder peer started!');
      +
      +  console.log('[EXAMPLES:SWARM]', 'Starting Swarm...');
      +  await swarm.start();
      +  console.log('[EXAMPLES:SWARM]', 'Swarm started!');
      +
      +  console.log('[EXAMPLES:SWARM]', 'Starting downstream Peer...');
      +  await downstream.start();
      +  console.log('[EXAMPLES:SWARM]', 'Downstream started!');
      +
      +
      + +
    • + + +
    • +
      + +
      + § +
      +

      Connect downstream “client” Peer + console.log(‘[EXAMPLES:SWARM]’, ‘Connecting downstream Peer to Swarm…’); + await downstream._connect(‘localhost:7777’);

      + +
      + +
    • + + +
    • +
      + +
      + § +
      +

      TODO: create entities on seed node + TODO: receive entities from seed node + TODO: create entities on swarm instance

      + +
      + +
    • + + +
    • +
      + +
      + § +
      +

      Send Regular Updates (outside of internal ping/pong)

      + +
      + +
      +
      +
        let heartbeat = setInterval(function () {
      +    console.warn('[EXAMPLES:SWARM]', 'Starting to send interval message...');
      +    let message = Message.fromVector(['Generic', Date.now().toString()]);
      +    console.log('[EXAMPLES:SWARM]', 'Sending :', message.raw);
      +
      +
      + +
    • + + +
    • +
      + +
      + § +
      +

      Send interval message through seed node

      + +
      + +
      +
      +
          seeder.broadcast(message);
      +
      +
      + +
    • + + +
    • +
      + +
      + § +
      +

      Send interval message through swarm agent + swarm.broadcast(message);

      + +
      + +
      +
      +
        }, 5000);
      +}
      +
      +main().catch(function exceptionHandler (exception) {
      +  console.error('[EXAMPLES:SWARM]', 'Main process threw Exception:', exception);
      +});
      +
      +
      + +
    • + +
    +
    + + + \ No newline at end of file diff --git a/assets/examples/witness.html b/assets/examples/witness.html new file mode 100644 index 000000000..78c48b804 --- /dev/null +++ b/assets/examples/witness.html @@ -0,0 +1,203 @@ + + + + + + witness.js + + + + + + +
    +
    + + + +
      + +
    • +
      +

      witness.js

      +
      +
    • + + + +
    • +
      + +
      + § +
      + +
      + +
      +
      +
      'use strict';
      +
      +require('debug-trace')({ always: true });
      +
      +const Witness = require('../types/witness');
      +const sample = 'Hello, world!';
      +const privkey = 'e6324f909a861b953e42438c2d4068dee59d576c32150309eaee07ceb21233a';
      +
      +async function main () {
      +  let witness = new Witness({
      +    data: sample,
      +    keypair: {
      +      private: privkey
      +    }
      +  });
      +
      +  console.log('Witness:', witness);
      +  console.log('Signature:', witness.signature);
      +  console.log('Bitcoin DER:', witness.toCompactDER());
      +  console.log('Bitcoin DER as hex:', witness.toCompactDER().toString('hex'));
      +  console.log('Witness pubkey:', witness.pubkey);
      +
      +  let verifier = new Witness({
      +    keypair: { public: witness.pubkey }
      +  });
      +
      +  console.log('Verifier:', verifier);
      +  console.log('Verifier keypair:', verifier.keypair);
      +
      +  let verification = verifier.verify(sample, witness.signature);
      +  console.log('Verification:', verification);
      +}
      +
      +main();
      +
      +
      + +
    • + +
    +
    + + + \ No newline at end of file diff --git a/images/architecture.png b/assets/images/architecture.png similarity index 100% rename from images/architecture.png rename to assets/images/architecture.png diff --git a/assets/images/fabric-labs.png b/assets/images/fabric-labs.png new file mode 100644 index 000000000..87fc1a986 Binary files /dev/null and b/assets/images/fabric-labs.png differ diff --git a/assets/index.html b/assets/index.html new file mode 100644 index 000000000..e79da209e --- /dev/null +++ b/assets/index.html @@ -0,0 +1,55 @@ + + + + + + @fabric/http + + + + + + + + + + + + + + + + + + + + + +

    Default Site

    +

    file browser

    +
    + + +
    +
    +
    +
    + + \ No newline at end of file diff --git a/assets/public/fonts/aller-bold.eot b/assets/public/fonts/aller-bold.eot new file mode 100644 index 000000000..1b32532a8 Binary files /dev/null and b/assets/public/fonts/aller-bold.eot differ diff --git a/assets/public/fonts/aller-bold.ttf b/assets/public/fonts/aller-bold.ttf new file mode 100644 index 000000000..dc4cc9c27 Binary files /dev/null and b/assets/public/fonts/aller-bold.ttf differ diff --git a/assets/public/fonts/aller-bold.woff b/assets/public/fonts/aller-bold.woff new file mode 100644 index 000000000..fa16fd0ab Binary files /dev/null and b/assets/public/fonts/aller-bold.woff differ diff --git a/assets/public/fonts/aller-light.eot b/assets/public/fonts/aller-light.eot new file mode 100644 index 000000000..40bd654b5 Binary files /dev/null and b/assets/public/fonts/aller-light.eot differ diff --git a/assets/public/fonts/aller-light.ttf b/assets/public/fonts/aller-light.ttf new file mode 100644 index 000000000..c2c72902a Binary files /dev/null and b/assets/public/fonts/aller-light.ttf differ diff --git a/assets/public/fonts/aller-light.woff b/assets/public/fonts/aller-light.woff new file mode 100644 index 000000000..81a09d18e Binary files /dev/null and b/assets/public/fonts/aller-light.woff differ diff --git a/assets/public/fonts/roboto-black.eot b/assets/public/fonts/roboto-black.eot new file mode 100644 index 000000000..571ed4912 Binary files /dev/null and b/assets/public/fonts/roboto-black.eot differ diff --git a/assets/public/fonts/roboto-black.ttf b/assets/public/fonts/roboto-black.ttf new file mode 100644 index 000000000..e0300b3ee Binary files /dev/null and b/assets/public/fonts/roboto-black.ttf differ diff --git a/assets/public/fonts/roboto-black.woff b/assets/public/fonts/roboto-black.woff new file mode 100644 index 000000000..642e5b60f Binary files /dev/null and b/assets/public/fonts/roboto-black.woff differ diff --git a/assets/public/stylesheets/normalize.css b/assets/public/stylesheets/normalize.css new file mode 100644 index 000000000..73abb76fa --- /dev/null +++ b/assets/public/stylesheets/normalize.css @@ -0,0 +1,375 @@ +/*! normalize.css v2.0.1 | MIT License | git.io/normalize */ + +/* ========================================================================== + HTML5 display definitions + ========================================================================== */ + +/* + * Corrects `block` display not defined in IE 8/9. + */ + +article, +aside, +details, +figcaption, +figure, +footer, +header, +hgroup, +nav, +section, +summary { + display: block; +} + +/* + * Corrects `inline-block` display not defined in IE 8/9. + */ + +audio, +canvas, +video { + display: inline-block; +} + +/* + * Prevents modern browsers from displaying `audio` without controls. + * Remove excess height in iOS 5 devices. + */ + +audio:not([controls]) { + display: none; + height: 0; +} + +/* + * Addresses styling for `hidden` attribute not present in IE 8/9. + */ + +[hidden] { + display: none; +} + +/* ========================================================================== + Base + ========================================================================== */ + +/* + * 1. Sets default font family to sans-serif. + * 2. Prevents iOS text size adjust after orientation change, without disabling + * user zoom. + */ + +html { + font-family: sans-serif; /* 1 */ + -webkit-text-size-adjust: 100%; /* 2 */ + -ms-text-size-adjust: 100%; /* 2 */ +} + +/* + * Removes default margin. + */ + +body { + margin: 0; +} + +/* ========================================================================== + Links + ========================================================================== */ + +/* + * Addresses `outline` inconsistency between Chrome and other browsers. + */ + +a:focus { + outline: thin dotted; +} + +/* + * Improves readability when focused and also mouse hovered in all browsers. + */ + +a:active, +a:hover { + outline: 0; +} + +/* ========================================================================== + Typography + ========================================================================== */ + +/* + * Addresses `h1` font sizes within `section` and `article` in Firefox 4+, + * Safari 5, and Chrome. + */ + +h1 { + font-size: 2em; +} + +/* + * Addresses styling not present in IE 8/9, Safari 5, and Chrome. + */ + +abbr[title] { + border-bottom: 1px dotted; +} + +/* + * Addresses style set to `bolder` in Firefox 4+, Safari 5, and Chrome. + */ + +b, +strong { + font-weight: bold; +} + +/* + * Addresses styling not present in Safari 5 and Chrome. + */ + +dfn { + font-style: italic; +} + +/* + * Addresses styling not present in IE 8/9. + */ + +mark { + background: #ff0; + color: #000; +} + + +/* + * Corrects font family set oddly in Safari 5 and Chrome. + */ + +code, +kbd, +pre, +samp { + font-family: monospace, serif; + font-size: 1em; +} + +/* + * Improves readability of pre-formatted text in all browsers. + */ + +pre { + white-space: pre; + white-space: pre-wrap; + word-wrap: break-word; +} + +/* + * Sets consistent quote types. + */ + +q { + quotes: "\201C" "\201D" "\2018" "\2019"; +} + +/* + * Addresses inconsistent and variable font size in all browsers. + */ + +small { + font-size: 80%; +} + +/* + * Prevents `sub` and `sup` affecting `line-height` in all browsers. + */ + +sub, +sup { + font-size: 75%; + line-height: 0; + position: relative; + vertical-align: baseline; +} + +sup { + top: -0.5em; +} + +sub { + bottom: -0.25em; +} + +/* ========================================================================== + Embedded content + ========================================================================== */ + +/* + * Removes border when inside `a` element in IE 8/9. + */ + +img { + border: 0; +} + +/* + * Corrects overflow displayed oddly in IE 9. + */ + +svg:not(:root) { + overflow: hidden; +} + +/* ========================================================================== + Figures + ========================================================================== */ + +/* + * Addresses margin not present in IE 8/9 and Safari 5. + */ + +figure { + margin: 0; +} + +/* ========================================================================== + Forms + ========================================================================== */ + +/* + * Define consistent border, margin, and padding. + */ + +fieldset { + border: 1px solid #c0c0c0; + margin: 0 2px; + padding: 0.35em 0.625em 0.75em; +} + +/* + * 1. Corrects color not being inherited in IE 8/9. + * 2. Remove padding so people aren't caught out if they zero out fieldsets. + */ + +legend { + border: 0; /* 1 */ + padding: 0; /* 2 */ +} + +/* + * 1. Corrects font family not being inherited in all browsers. + * 2. Corrects font size not being inherited in all browsers. + * 3. Addresses margins set differently in Firefox 4+, Safari 5, and Chrome + */ + +button, +input, +select, +textarea { + font-family: inherit; /* 1 */ + font-size: 100%; /* 2 */ + margin: 0; /* 3 */ +} + +/* + * Addresses Firefox 4+ setting `line-height` on `input` using `!important` in + * the UA stylesheet. + */ + +button, +input { + line-height: normal; +} + +/* + * 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio` + * and `video` controls. + * 2. Corrects inability to style clickable `input` types in iOS. + * 3. Improves usability and consistency of cursor style between image-type + * `input` and others. + */ + +button, +html input[type="button"], /* 1 */ +input[type="reset"], +input[type="submit"] { + -webkit-appearance: button; /* 2 */ + cursor: pointer; /* 3 */ +} + +/* + * Re-set default cursor for disabled elements. + */ + +button[disabled], +input[disabled] { + cursor: default; +} + +/* + * 1. Addresses box sizing set to `content-box` in IE 8/9. + * 2. Removes excess padding in IE 8/9. + */ + +input[type="checkbox"], +input[type="radio"] { + box-sizing: border-box; /* 1 */ + padding: 0; /* 2 */ +} + +/* + * 1. Addresses `appearance` set to `searchfield` in Safari 5 and Chrome. + * 2. Addresses `box-sizing` set to `border-box` in Safari 5 and Chrome + * (include `-moz` to future-proof). + */ + +input[type="search"] { + -webkit-appearance: textfield; /* 1 */ + -moz-box-sizing: content-box; + -webkit-box-sizing: content-box; /* 2 */ + box-sizing: content-box; +} + +/* + * Removes inner padding and search cancel button in Safari 5 and Chrome + * on OS X. + */ + +input[type="search"]::-webkit-search-cancel-button, +input[type="search"]::-webkit-search-decoration { + -webkit-appearance: none; +} + +/* + * Removes inner padding and border in Firefox 4+. + */ + +button::-moz-focus-inner, +input::-moz-focus-inner { + border: 0; + padding: 0; +} + +/* + * 1. Removes default vertical scrollbar in IE 8/9. + * 2. Improves readability and alignment in all browsers. + */ + +textarea { + overflow: auto; /* 1 */ + vertical-align: top; /* 2 */ +} + +/* ========================================================================== + Tables + ========================================================================== */ + +/* + * Remove most spacing between table cells. + */ + +table { + border-collapse: collapse; + border-spacing: 0; +} \ No newline at end of file diff --git a/components/canvas.jade b/components/canvas.jade deleted file mode 100644 index 9d6c9d254..000000000 --- a/components/canvas.jade +++ /dev/null @@ -1,3 +0,0 @@ -fabric-canvas - fabric-peer-list - fabric-browser diff --git a/components/chat.jade b/components/chat.jade deleted file mode 100644 index 0ddb66c47..000000000 --- a/components/chat.jade +++ /dev/null @@ -1,3 +0,0 @@ -fabric-canvas - fabric-identity - fabric-chat diff --git a/components/circuit-list.js b/components/circuit-list.js deleted file mode 100644 index 5e1d73f37..000000000 --- a/components/circuit-list.js +++ /dev/null @@ -1,29 +0,0 @@ -'use strict'; - -const Component = require('@fabric/http/components/component'); - -class CircuitList extends Component { - constructor (settings = {}) { - super(settings); - - this.settings = Object.assign({ - title: 'Circuit List', - handle: 'fabric-circuit-list' - }); - - return this; - } - - _getInnerHTML () { - return `
    -
    -

    ${this.settings.title}

    - - # - -
    -
    `; - } -} - -module.exports = CircuitList; diff --git a/components/circuit-view.js b/components/circuit-view.js deleted file mode 100644 index 6ab2ee4ca..000000000 --- a/components/circuit-view.js +++ /dev/null @@ -1,104 +0,0 @@ -'use strict'; - -const { - OP_DONE, - OP_SEPARATOR -} = require('../constants'); - -const Circuit = require('../types/circuit'); -const Component = require('@fabric/http/components/component'); - -const d3 = require('d3'); -const d3Graphviz = require('d3-graphviz'); - -class CircuitView extends Component { - constructor (settings = {}) { - super(settings); - - this.d3 = d3; - this.d3Graphviz = d3Graphviz; - - this.settings = Object.assign({ - title: 'Circuit View', - handle: 'fabric-circuit-view' - }); - - this.circuit = new Circuit(); - this.state = { - status: 'ready' - }; - - return this; - } - - _advanceCircuit (event) { - event.preventDefault(); - console.log('advancing circuit:', this, this.circuit.settings.program); - - this.circuit = new Circuit(Object.assign({}, this.circuit.settings, { - program: this.circuit.settings.program, - wires: [{ - name: 'start', - from: 'init', - to: this.circuit.settings.program[0] - }].concat(this.circuit.settings.program.map((instruction, i) => { - return { - name: instruction, - from: instruction, - to: this.circuit.settings.program[i + 1] || OP_DONE - }; - })).concat([{ - name: OP_DONE, - from: OP_DONE, - to: OP_DONE - }]) - })); - - let transition = d3.transition().delay(100).duration(1000); - d3.select('#circuit-svg').style('width', '100%').style('width', '500px').graphviz().transition(transition).renderDot(this.circuit.dot); - d3.select('#circuit-svg svg').style('width', '100%').style('width', '500px'); - } - - _loadFromPath () { - let path = document.location.pathname; - let parts = path.split('/')[2]; - let wires = parts.split(OP_SEPARATOR).map((instruction, i) => { - return { - name: instruction, - from: instruction, - to: parts.split(OP_SEPARATOR)[i + 1] - }; - }); - - this.circuit = new Circuit({ - script: parts, - program: parts.split(OP_SEPARATOR), - wires: wires - }); - - return this.circuit; - } - - async connectedCallback () { - await super.connectedCallback(); - - window.app.circuit._registerMethod('_advanceCircuit', this._advanceCircuit.bind(this)); - - let svg = this.querySelector('#circuit-svg'); - let circuit = this._loadFromPath(); - - return this; - } - - _getInnerHTML () { - return `
    -

    ${this.settings.title}

    - -
    -
    -
    -
    `; - } -} - -module.exports = CircuitView; diff --git a/components/circuit-viewer.js b/components/circuit-viewer.js deleted file mode 100644 index ea1601434..000000000 --- a/components/circuit-viewer.js +++ /dev/null @@ -1,123 +0,0 @@ -'use strict'; - -const { - OP_DONE, - OP_SEPARATOR -} = require('../constants'); - -const Circuit = require('../types/circuit'); -const Component = require('@fabric/http/components/component'); - -const d3 = require('d3'); -const d3Graphviz = require('d3-graphviz'); - -class CircuitViewer extends HTMLElement { - constructor (settings = {}) { - super(settings); - - this.d3 = d3; - this.d3Graphviz = d3Graphviz; - - this.settings = Object.assign({ - title: 'Circuit View', - handle: 'fabric-circuit-viewer' - }); - - this.circuit = new Circuit(); - this.state = { - status: 'ready' - }; - - return this; - } - - _animateTo (step) { - console.log('animating circuit:', this, this.circuit.settings.program); - - this.circuit = new Circuit(Object.assign({}, this.circuit.settings, { - program: this.circuit.settings.program, - wires: step.edges.map((x) => { - return { - name: '', - from: x.from, - to: x.to - }; - }) - })); - - let transition = d3.transition().delay(100).duration(1000); - d3.select('#circuit-svg').style('width', '100%').style('width', '500px').graphviz().transition(transition).renderDot(this.circuit.dot); - d3.select('#circuit-svg svg').style('width', '100%').style('width', '500px'); - } - - _advanceCircuit (event) { - event.preventDefault(); - console.log('advancing circuit:', this, this.circuit.settings.program); - - this.circuit = new Circuit(Object.assign({}, this.circuit.settings, { - program: this.circuit.settings.program, - wires: [{ - name: 'start', - from: 'init', - to: this.circuit.settings.program[0] - }].concat(this.circuit.settings.program.map((instruction, i) => { - return { - name: instruction, - from: instruction, - to: this.circuit.settings.program[i + 1] || OP_DONE - }; - })).concat([{ - name: OP_DONE, - from: OP_DONE, - to: OP_DONE - }]) - })); - - let transition = d3.transition().delay(100).duration(1000); - d3.select('#circuit-svg').style('width', '100%').style('width', '500px').graphviz().transition(transition).renderDot(this.circuit.dot); - d3.select('#circuit-svg svg').style('width', '100%').style('width', '500px'); - } - - _loadFromPath () { - let path = document.location.pathname; - let parts = path.split('/')[2]; - let wires = parts.split(OP_SEPARATOR).map((instruction, i) => { - return { - name: instruction, - from: instruction, - to: parts.split(OP_SEPARATOR)[i + 1] - }; - }); - - this.circuit = new Circuit({ - script: parts, - program: parts.split(OP_SEPARATOR), - wires: wires - }); - - return this.circuit; - } - - async connectedCallback () { - await super.connectedCallback(); - - window.app.circuit._registerMethod('_advanceCircuit', this._advanceCircuit.bind(this)); - - let svg = this.querySelector('#circuit-svg'); - let circuit = this._loadFromPath(); - - return this; - } - - _getInnerHTML () { - return `
    -

    ${this.settings.title}

    - -
    -
    -
    -
    `; - } -} - -module.exports = CircuitViewer; diff --git a/components/message-list.js b/components/message-list.js deleted file mode 100644 index ad8613dad..000000000 --- a/components/message-list.js +++ /dev/null @@ -1,16 +0,0 @@ -'use strict'; - -const Component = require('@fabric/http/components/component'); - -class MessageList extends Component { - constructor (settings = {}) { - super(settings); - this.settings = Object.assign({ - title: 'Message List', - handle: 'fabric-message-list' - }); - return this; - } -} - -module.exports = MessageList; diff --git a/constants.js b/constants.js index 1dfa1e2be..6ec0f7d46 100644 --- a/constants.js +++ b/constants.js @@ -6,24 +6,25 @@ */ 'use strict'; -// Dependencies -const crypto = require('crypto'); - // Networking and Environment -const PEER_PORT = 9999; +const PEER_PORT = 7777; const MAX_PEERS = 32; const PRECISION = 100; // Fabric Core +const FABRIC_USER_AGENT = 'Fabric Core 0.1.0 (@fabric/core#v0.1.0-RC1)'; +const BITCOIN_NETWORK = 'mainnet'; const BITCOIN_GENESIS = '000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f'; const BITCOIN_GENESIS_ROOT = '4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b'; -const FABRIC_KEY_DERIVATION_PATH = "m/44'/0'/0'/0/0"; +const FABRIC_KEY_DERIVATION_PATH = "m/44'/7777'/0'/0/0"; const FIXTURE_SEED = 'abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about'; +const FIXTURE_XPUB = 'xpub661MyMwAqRbcF6GygV6Q6XAg8dqhPvDuhYHGniequi6HMbYhNNH5XC13Np3qRANHVD2mmnNGtMGBfDT69s2ovpHLr7q8syoAuyWqtRGEsYQ'; +const FIXTURE_XPRV = 'xprv9s21ZrQH143K2cCWaTZPjPDwac1CzTW4LKMfzLFEMNZJUoDYppxpyPgZXY7CZkjefGJTrTyqKnMrM4RG6nGn7Q9cwjHggCtn3CdFGJahaWY'; // Message Constants const MAGIC_BYTES = 0xC0D3F33D; const VERSION_NUMBER = 0x01; // 0 for development, pre-alpha, 1 for production -const HEADER_SIZE = 144; // [4], [4], [32], [4], [4], [32], [64] bytes +const HEADER_SIZE = 176; // [4], [4], [32], [32], [4], [4], [32], [64] bytes const LARGE_COLLECTION_SIZE = 10; // TODO: test with 1,000,000 const MAX_MESSAGE_SIZE = 4096 - HEADER_SIZE; @@ -43,11 +44,16 @@ const FABRIC_PLAYNET_ADDRESS = ''; // deposit address (P2TR) const FABRIC_PLAYNET_ORIGIN = ''; // block hash of first deploy // FABRIC ONLY -const GENERIC_MESSAGE_TYPE = parseInt(crypto.createHash('sha256').update('@types/GenericMessage').digest('hex').slice(0, 4), 16); -const LOG_MESSAGE_TYPE = MAGIC_BYTES + parseInt(crypto.createHash('sha256').update('@types/GenericLogMessage').digest('hex').slice(0, 4), 16); -const GENERIC_LIST_TYPE = MAGIC_BYTES + parseInt(crypto.createHash('sha256').update('@types/GenericList').digest('hex').slice(0, 4), 16); +const BITCOIN_BLOCK_TYPE = 21000; +const BITCOIN_BLOCK_HASH_TYPE = 21100; +const BITCOIN_TRANSACTION_TYPE = 22000; +const BITCOIN_TRANSACTION_HASH_TYPE = 22100; +const GENERIC_MESSAGE_TYPE = 15103; +const LOG_MESSAGE_TYPE = 3235156080; +const GENERIC_LIST_TYPE = 3235170158; const DOCUMENT_PUBLISH_TYPE = 998; const DOCUMENT_REQUEST_TYPE = 999; +const JSON_CALL_TYPE = 16000; // Opcodes const OP_CYCLE = '00'; @@ -66,6 +72,11 @@ const OP_RETURN = '6a'; const OP_EQUALVERIFY = '88'; const OP_SEPARATOR = 'ab'; +// Bech32m +const BECH32M_CHARSET = 'qpzry9x8gf2tvdw0s3jn54khce6mua7l'; + +// Peering +const P2P_PORT = 7777; const P2P_GENERIC = 0x80; // 128 in decimal const P2P_IDENT_REQUEST = 0x01; // 1, or the identity const P2P_IDENT_RESPONSE = 0x11; @@ -90,6 +101,7 @@ const P2P_MUSIG_SEND_PROPOSAL = 0x4223; const P2P_MUSIG_REPLY_TO_PROPOSAL = 0x4224; const P2P_MUSIG_ACCEPT_PROPOSAL = 0x4225; +// Message Types const PEER_CANDIDATE = 0x09; // TODO: should be 0x02 for Bitcoin P2P const BLOCK_CANDIDATE = 0x03; @@ -114,23 +126,37 @@ const ZERO_LENGTH_PLAINTEXT = ''; // HTTP const HTTP_HEADER_CONTENT_TYPE = 'application/json'; +// UI +const INPUT_HINT = 'Press the "i" key to begin typing.'; + // CommonJS Support module.exports = { PEER_PORT, MAX_PEERS, PRECISION, + BITCOIN_NETWORK, BITCOIN_GENESIS, + BITCOIN_GENESIS_HASH: BITCOIN_GENESIS, BITCOIN_GENESIS_ROOT, FABRIC_KEY_DERIVATION_PATH, + FABRIC_USER_AGENT, FIXTURE_SEED, + FIXTURE_XPUB, + FIXTURE_XPRV, HEADER_SIZE, + BITCOIN_BLOCK_TYPE, + BITCOIN_BLOCK_HASH_TYPE, + BITCOIN_TRANSACTION_TYPE, + BITCOIN_TRANSACTION_HASH_TYPE, GENERIC_MESSAGE_TYPE, LOG_MESSAGE_TYPE, GENERIC_LIST_TYPE, LARGE_COLLECTION_SIZE, BLOCK_CANDIDATE, CHAT_MESSAGE, + INPUT_HINT, ZERO_LENGTH_PLAINTEXT, + BECH32M_CHARSET, FABRIC_PLAYNET_ADDRESS, FABRIC_PLAYNET_ORIGIN, LIGHTNING_TEST_HEADER, @@ -170,6 +196,7 @@ module.exports = { P2P_ROOT, P2P_PING, P2P_PONG, + P2P_PORT, P2P_START_CHAIN, P2P_INSTRUCTION, P2P_BASE_MESSAGE, @@ -189,6 +216,7 @@ module.exports = { PEER_CANDIDATE, DOCUMENT_PUBLISH_TYPE, DOCUMENT_REQUEST_TYPE, + JSON_CALL_TYPE, SESSION_START, VERSION_NUMBER }; diff --git a/contracts/chat.js b/contracts/chat.js index c82692bb9..4d4de6fa2 100644 --- a/contracts/chat.js +++ b/contracts/chat.js @@ -1,22 +1,7 @@ 'use strict'; // Settings -const playnet = require('../settings/playnet'); -const local = require('../settings/local'); - -const settings = { - listen: local.listen, - // sideload playnet - peers: [].concat(playnet.peers), - port: process.env.FABRIC_PORT || 7777, - bitcoin: local.bitcoin, - lightning: local.lightning, - render: local.render, - services: local.services, - key: { - seed: playnet.seed - } -}; +const settings = require('../settings/local'); // Fabric Types const CLI = require('../types/cli'); @@ -26,17 +11,26 @@ const CLI = require('../types/cli'); // Program Definition async function OP_CHAT () { - // Fabric CLI - const chat = new CLI(settings); // TODO: this.settings - if (!this.environment.wallet) { console.error('No wallet found! Set up your Fabric wallet by running:'); console.error('\tfabric setup'); process.exit(1); } + // Fabric CLI + const chat = new CLI(settings); // TODO: this.settings + + chat.on('error', (error) => { + console.error('[FABRIC:CHAT]', '[ERROR]', error); + }); + + // Use local wallet chat.attachWallet(this.environment.wallet); + // Assume identity + // TODO: remove, re-work Peer and Wallet key import in CLI + chat.assumeIdentity(this.environment.wallet.settings.key); + // ## Services // TODO: reconcile API wth @fabric/doorman as appears at: https://github.com/FabricLabs/doorman // chat._registerService('matrix', Matrix); diff --git a/contracts/federation.js b/contracts/federation.js index 727b6abef..771d5d408 100644 --- a/contracts/federation.js +++ b/contracts/federation.js @@ -1,26 +1,9 @@ +const Actor = require('../types/actor'); const Block = require('../types/block'); module.exports = function OP_ADVANCE_BLOCK (input) { - console.log('advancing block:', this.state); - - // const parent = this.state.chain[this.state.chain.length - 1]; - // console.log('parent:', parent); - - const block = new Block({ - // parent: this.state.chain[this.state.chain.length - 1], - transactions: input - }); - - for (let i = 0; i < this.state.validators; i++) { - const validator = this.state.validators[i]; - console.log('processing for validator:', validator); - // TODO: get signatures - } - - this.state.blocks[block.id] = block; - // this.state.chain.push(block.id); - - this.commit(); - - return this.state; + const actor = new Actor(input); + return { + input: actor + }; } diff --git a/contracts/lightning-playnet.dot b/contracts/lightning-playnet.dot new file mode 100644 index 000000000..47fef69a8 --- /dev/null +++ b/contracts/lightning-playnet.dot @@ -0,0 +1,19 @@ +digraph LightningPlaynet { + "alice" + -> "bob" + -> "carol" + + "bob" -> { + "alice" + "carol" + } + + subgraph cluster_externals { + label = "Alice's Domain" + "alice" + "Alice's Public Web Service" + + "Alice's Public Web Service" -> "alice" + "alice" -> "Alice's Public Web Service" + } +} diff --git a/contracts/mount.js b/contracts/mount.js index 6a50ea08a..768eb4312 100644 --- a/contracts/mount.js +++ b/contracts/mount.js @@ -14,7 +14,7 @@ async function OP_MOUNT (command) { }); filesystem.on('log', log => { - console.log('log:', log); + console.log('[FILESYSTEM]', 'log:', log); }); filesystem.on('message', message => { diff --git a/contracts/trace.js b/contracts/trace.js index c9763ec09..9de6b3b02 100644 --- a/contracts/trace.js +++ b/contracts/trace.js @@ -1,4 +1,7 @@ module.exports = function OP_TRACE (obj = {}) { + // console.log('[TRACE] Starting trace...'); + // console.log('[TRACE] Runtime:', this); + // console.log('[TRACE] obj:', obj); Error.captureStackTrace(obj, OP_TRACE); return `@\n${obj.stack.split('\n').slice(1).join('\n')}`; }; diff --git a/contracts/verify.js b/contracts/verify.js new file mode 100644 index 000000000..bc823df3d --- /dev/null +++ b/contracts/verify.js @@ -0,0 +1,7 @@ +'use strict'; + +async function OP_VERIFY (state) { + return 1; +} + +module.exports = OP_VERIFY; diff --git a/currencies/btc.js b/currencies/btc.js deleted file mode 100644 index 21e35ec6b..000000000 --- a/currencies/btc.js +++ /dev/null @@ -1,9 +0,0 @@ -const { - BITCOIN_GENESIS -} = require('../constants'); - -module.exports = { - name: 'Bitcoin', - symbol: 'BTC', - ledger: BITCOIN_GENESIS -}; diff --git a/currencies/btca.json b/currencies/btca.json deleted file mode 100644 index eb300e1eb..000000000 --- a/currencies/btca.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "name": "BTCA", - "symbol": "BTCA" -} diff --git a/currencies/btcb.json b/currencies/btcb.json deleted file mode 100644 index 675ea40d2..000000000 --- a/currencies/btcb.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "name": "BTCB", - "symbol": "BTCB" -} diff --git a/docs/Actor.html b/docs/Actor.html index 635551add..3be2d19cc 100644 --- a/docs/Actor.html +++ b/docs/Actor.html @@ -370,7 +370,7 @@
    Properties:
    @@ -558,7 +558,7 @@
    Parameters:
    @@ -618,6 +618,169 @@
    Returns:
    +

    adopt(changes) → {Actor}

    + + + + + + +
    + Explicitly adopt a set of JSONPatch-encoded changes. +
    + + + + + + + + + +
    Parameters:
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    NameTypeDescription
    changes + + + Array + + + + List of JSONPatch operations to apply.
    + + + + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Source:
    +
    + +
    + + + + + + + +
    + + + + + + + + + + + + + + + +
    Returns:
    + + +
    + Instance of the Actor. +
    + + + +
    +
    + Type +
    +
    + + Actor + + +
    +
    + + + + + + + + + + + + +

    commit() → {String}

    @@ -626,7 +789,1031 @@

    commit - Resolve the current state to a commitment. + Resolve the current state to a commitment. + + + + + + + + + + + + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Source:
    +
    + +
    + + + + + + + +
    + + + + + + + + + + + + + + + +
    Returns:
    + + +
    + 32-byte ID +
    + + + +
    +
    + Type +
    +
    + + String + + +
    +
    + + + + + + + + + + + + + +

    export() → {Object}

    + + + + + + +
    + Export the Actor's state to a standard Object. +
    + + + + + + + + + + + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Source:
    +
    + +
    + + + + + + + +
    + + + + + + + + + + + + + + + +
    Returns:
    + + +
    + Standard object. +
    + + + +
    +
    + Type +
    +
    + + Object + + +
    +
    + + + + + + + + + + + + + +

    get(path) → {Object}

    + + + + + + +
    + Retrieve a value from the Actor's state by JSONPointer path. +
    + + + + + + + + + +
    Parameters:
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    NameTypeDescription
    path + + + String + + + + Path to retrieve using JSONPointer.
    + + + + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Source:
    +
    + +
    + + + + + + + +
    + + + + + + + + + + + + + + + +
    Returns:
    + + +
    + Value of the path in the Actor's state. +
    + + + +
    +
    + Type +
    +
    + + Object + + +
    +
    + + + + + + + + + + + + + +

    pause() → {Actor}

    + + + + + + +
    + Toggles `status` property to paused. +
    + + + + + + + + + + + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Source:
    +
    + +
    + + + + + + + +
    + + + + + + + + + + + + + + + +
    Returns:
    + + +
    + Instance of the Actor. +
    + + + +
    +
    + Type +
    +
    + + Actor + + +
    +
    + + + + + + + + + + + + + +

    serialize() → {String}

    + + + + + + +
    + Serialize the Actor's current state into a JSON-formatted string. +
    + + + + + + + + + + + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Source:
    +
    + +
    + + + + + + + +
    + + + + + + + + + + + + + + + +
    Returns:
    + + + + +
    +
    + Type +
    +
    + + String + + +
    +
    + + + + + + + + + + + + + +

    set(path, value) → {Object}

    + + + + + + +
    + Set a value in the Actor's state by JSONPointer path. +
    + + + + + + + + + +
    Parameters:
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    NameTypeDescription
    path + + + String + + + + Path to set using JSONPointer.
    value + + + Object + + + + Value to set.
    + + + + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Source:
    +
    + +
    + + + + + + + +
    + + + + + + + + + + + + + + + +
    Returns:
    + + +
    + Value of the path in the Actor's state. +
    + + + +
    +
    + Type +
    +
    + + Object + + +
    +
    + + + + + + + + + + + + + +

    sign() → {Actor}

    + + + + + + +
    + Signs the Actor. +
    + + + + + + + + + + + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Source:
    +
    + +
    + + + + + + + +
    + + + + + + + + + + + + + + + +
    Returns:
    + + + + +
    +
    + Type +
    +
    + + Actor + + +
    +
    + + + + + + + + + + + + + +

    toBuffer() → {Buffer}

    + + + + + + +
    + Casts the Actor to a normalized Buffer. +
    + + + + + + + + + + + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Source:
    +
    + +
    + + + + + + + +
    + + + + + + + + + + + + + + + +
    Returns:
    + + + + +
    +
    + Type +
    +
    + + Buffer + + +
    +
    + + + + + + + + + + + + + +

    toGenericMessage() → {Object}

    + + + + + + +
    + Casts the Actor to a generic message, used to uniquely identify the Actor's state. + Fields: + - `type`: 'FabricActorState' + - `object`: state
    @@ -672,7 +1859,7 @@

    commit @@ -681,6 +1868,15 @@

    commitSee: +
    + +
    + @@ -689,11 +1885,6 @@

    commitFires:

    -
      -
    • event:Actor Current malleable state.
    • -
    - @@ -708,7 +1899,7 @@
    Returns:
    - 32-byte ID + Generic message object.
    @@ -719,7 +1910,7 @@
    Returns:
    - String + Object
    @@ -737,7 +1928,7 @@
    Returns:
    -

    serialize() → {String}

    +

    toObject() → {Object}

    @@ -745,7 +1936,7 @@

    serialize - Serialize the Actor's current state into a JSON-formatted string. + Returns the Actor's current state as an Object. @@ -791,7 +1982,7 @@

    serialize @@ -829,7 +2020,7 @@
    Returns:
    - String + Object
    @@ -847,7 +2038,7 @@
    Returns:
    -

    sign() → {Actor}

    +

    unpause() → {Actor}

    @@ -855,7 +2046,7 @@

    sign - Signs the Actor. + Toggles `status` property to unpaused. @@ -901,7 +2092,7 @@

    sign @@ -931,6 +2122,10 @@

    sign + Instance of the Actor. + +
    @@ -957,7 +2152,7 @@
    Returns:
    -

    toBuffer() → {Buffer}

    +

    value(formatopt) → {Object}

    @@ -965,7 +2160,7 @@

    toBuffer - Casts the Actor to a normalized Buffer. + Get the inner value of the Actor with an optional cast type. @@ -976,6 +2171,75 @@

    toBufferParameters:

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    NameTypeAttributesDefaultDescription
    format + + + String + + + + + + <optional>
    + + + + + +
    + + object + + Cast the value to one of: `buffer, hex, json, string`
    + + @@ -1011,7 +2275,7 @@

    toBuffer @@ -1041,6 +2305,10 @@

    toBufferReturns:

    +
    + Inner value of the Actor as an Object, or cast to the requested `format`. +
    +
    @@ -1049,7 +2317,7 @@
    Returns:
    - Buffer + Object
    @@ -1067,7 +2335,7 @@
    Returns:
    -

    toObject() → {Object}

    +

    (static) fromAny(input) → {Actor}

    @@ -1075,7 +2343,7 @@

    toObject - Returns the Actor's current state as an Object. + Create an Actor from a variety of formats. @@ -1086,6 +2354,55 @@

    toObjectParameters:

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    NameTypeDescription
    input + + + Object + + + + Target Object to create.
    + + @@ -1121,7 +2438,7 @@

    toObject @@ -1151,6 +2468,10 @@

    toObjectReturns:

    +
    + Instance of the Actor. +
    +
    @@ -1159,7 +2480,7 @@
    Returns:
    - Object + Actor
    @@ -1177,7 +2498,7 @@
    Returns:
    -

    unpause() → {Actor}

    +

    (static) randomBytes(countopt) → {Buffer}

    @@ -1185,8 +2506,7 @@

    unpause - Toggles `status` property to unpaused. - @ + Get a number of random bytes from the runtime environment. @@ -1197,6 +2517,75 @@

    unpauseParameters:

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    NameTypeAttributesDefaultDescription
    count + + + Number + + + + + + <optional>
    + + + + + +
    + + 32 + + Number of random bytes to retrieve.
    + + @@ -1232,7 +2621,7 @@

    unpause @@ -1262,6 +2651,10 @@

    unpauseReturns:

    +
    + The random bytes. +
    +
    @@ -1270,7 +2663,7 @@
    Returns:
    - Actor + Buffer
    @@ -1300,52 +2693,49 @@

    Home

    Classes

    Events

    diff --git a/docs/Aggregator.html b/docs/Aggregator.html index 17c99cc51..2d2aa7e63 100644 --- a/docs/Aggregator.html +++ b/docs/Aggregator.html @@ -226,7 +226,7 @@
    Properties
    @@ -360,7 +360,7 @@

    _comp
    @@ -523,7 +523,7 @@

    Parameters:
    @@ -637,7 +637,7 @@

    commit @@ -849,7 +849,7 @@
    Properties:
    @@ -900,19 +900,27 @@

    Classes

  • Bitcoin
  • Chain
  • Channel
  • +
  • Circuit
  • CLI
  • Collection
  • Compiler
  • Consensus
  • Entity
  • +
  • Environment
  • Exchange
  • Fabric
  • +
  • Federation
  • +
  • Filesystem
  • Hash256
  • HKDF
  • HTTPServer
  • +
  • Identity
  • Interface
  • Key
  • -
  • KeyStore
  • +
  • Keystore
  • +
  • Ledger
  • +
  • Lightning
  • +
  • Logger
  • Machine
  • Mempool
  • Message
  • @@ -922,6 +930,8 @@

    Classes

  • Peer
  • Reader
  • Redis
  • +
  • Remote
  • +
  • Resource
  • Router
  • Scribe
  • Script
  • @@ -941,6 +951,7 @@

    Classes

  • Vector
  • Walker
  • Wallet
  • +
  • Worker
  • ZMQ
  • Events

    diff --git a/docs/App.html b/docs/App.html deleted file mode 100644 index d4ef496a2..000000000 --- a/docs/App.html +++ /dev/null @@ -1,4349 +0,0 @@ - - - - - - Class: App · Docs - - - - - - - - - -
    -

    Class: App

    - - - - -
    - -
    - -

    App(definition) → {App}

    - -
    Web-friendly application framework for building single-page applications with - Fabric-based networking and storage.
    - - -
    - -
    -
    - - - - -

    Constructor

    - - - -

    new App(definition) → {App}

    - - - - - - -
    - Generic bundle for building Fabric applications. -
    - - - - - - - - - -
    Parameters:
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    NameTypeDescription
    definition - - - Object - - - - Application definition. See `config` for examples.
    - - - - - - -
    Properties:
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    NameTypeDescription
    components - - - Collection - - - - Interface elements.
    stash - - - Store - - - - Routable Datastore.
    - - - - -
    - - - - - - - - - - - - - - - - - - - - - - - - - - -
    Source:
    -
    - -
    - - - - - - - -
    - - - - - - - - - - - - - - - -
    Returns:
    - - -
    - Returns an instance of `App`. -
    - - - -
    -
    - Type -
    -
    - - App - - -
    -
    - - - - - - - - -
    - - -

    Extends

    - - - - - - - - - - - - - - - - - - - - - - -

    Methods

    - - - - - - - -

    (async) _GET(path) → {Promise}

    - - - - - - -
    - Retrieve a value from the Service's state. -
    - - - - - - - - - -
    Parameters:
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    NameTypeDescription
    path - - - String - - - - Path of the value to retrieve.
    - - - - - - -
    - - - - - - - - -
    Overrides:
    -
    - -
    - - - - - - - - - - - - - - - - - - - -
    Source:
    -
    - -
    - - - - - - - -
    - - - - - - - - - - - - - - - -
    Returns:
    - - -
    - Resolves with the result. -
    - - - -
    -
    - Type -
    -
    - - Promise - - -
    -
    - - - - - - - - - - - - - -

    (async) _PUT(path, value, commitopt) → {Promise}

    - - - - - - -
    - Store a value in the Service's state. -
    - - - - - - - - - -
    Parameters:
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    NameTypeAttributesDefaultDescription
    path - - - String - - - - - - - - - - - - Path to store the value at.
    value - - - Object - - - - - - - - - - - - Document to store.
    commit - - - Boolean - - - - - - <optional>
    - - - - - -
    - - false - - Sign the resulting state.
    - - - - - - -
    - - - - - - - - -
    Overrides:
    -
    - -
    - - - - - - - - - - - - - - - - - - - -
    Source:
    -
    - -
    - - - - - - - -
    - - - - - - - - - - - - - - - -
    Returns:
    - - -
    - Resolves with with stored document. -
    - - - -
    -
    - Type -
    -
    - - Promise - - -
    -
    - - - - - - - - - - - - - -

    (async) _registerActor(actor) → {Promise}

    - - - - - - -
    - Register an Actor with the Service. -
    - - - - - - - - - -
    Parameters:
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    NameTypeDescription
    actor - - - Object - - - - Instance of the Actor.
    - - - - - - -
    - - - - - - - - -
    Overrides:
    -
    - -
    - - - - - - - - - - - - - - - - - - - -
    Source:
    -
    - -
    - - - - - - - -
    - - - - - - - - - - - - - - - -
    Returns:
    - - -
    - Resolves upon successful registration. -
    - - - -
    -
    - Type -
    -
    - - Promise - - -
    -
    - - - - - - - - - - - - - -

    _registerService(name, Service) → {Service}

    - - - - - - -
    - Registers a named Service with the application. Services are - standardized interfaces for Fabric contracts, emitting Message - events with a predictable lifecycle. -
    - - - - - - - - - -
    Parameters:
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    NameTypeDescription
    name - - - String - - - - Internal name of the service.
    Service - - - Class - - - - The ES6 class definition implementing Service.
    - - - - - - -
    - - - - - - - - - - - - - - - - - - - - - - - - - - -
    Source:
    -
    - -
    - - - - - - - -
    - - - - - - - - - - - - - - - -
    Returns:
    - - -
    - The registered service instance. -
    - - - -
    -
    - Type -
    -
    - - Service - - -
    -
    - - - - - - - - - - - - - -

    (async) _send(message)

    - - - - - - -
    - Sends a message. -
    - - - - - - - - - -
    Parameters:
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    NameTypeDescription
    message - - - Mixed - - - - Message to send.
    - - - - - - -
    - - - - - - - - -
    Overrides:
    -
    - -
    - - - - - - - - - - - - - - - - - - - -
    Source:
    -
    - -
    - - - - - - - -
    - - - - - - - - - - - - - - - - - - - - - - - - - - -

    attach(element) → {App}

    - - - - - - -
    - Configure the Application to use a specific element. -
    - - - - - - - - - -
    Parameters:
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    NameTypeDescription
    element - - - DOMElement - - - - DOM element to bind to.
    - - - - - - -
    - - - - - - - - - - - - - - - - - - - - - - - - - - -
    Source:
    -
    - -
    - - - - - - - -
    - - - - - - - - - - - - - - - -
    Returns:
    - - -
    - Configured instance of the Application. -
    - - - -
    -
    - Type -
    -
    - - App - - -
    -
    - - - - - - - - - - - - - -

    (async) connect(notify) → {Promise}

    - - - - - - -
    - Attach to network. -
    - - - - - - - - - -
    Parameters:
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    NameTypeDefaultDescription
    notify - - - Boolean - - - - - - true - - Commit to changes.
    - - - - - - -
    - - - - - - - - -
    Overrides:
    -
    - -
    - - - - - - - - - - - - - - - - - - - -
    Source:
    -
    - -
    - - - - - - - -
    - - - - - - - - - - - - - - - -
    Returns:
    - - -
    - Resolves to Fabric. -
    - - - -
    -
    - Type -
    -
    - - Promise - - -
    -
    - - - - - - - - - - - - - -

    consume(resources) → {App}

    - - - - - - -
    - Define the Application's resources from an existing resource map. -
    - - - - - - - - - -
    Parameters:
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    NameTypeDescription
    resources - - - Object - - - - Map of resource definitions by name.
    - - - - - - -
    - - - - - - - - - - - - - - - - - - - - - - - - - - -
    Source:
    -
    - -
    - - - - - - - -
    - - - - - - - - - - - - - - - -
    Returns:
    - - -
    - Configured instance of the Application. -
    - - - -
    -
    - Type -
    -
    - - App - - -
    -
    - - - - - - - - - - - - - -

    (async) defer(authority) → {App}

    - - - - - - -
    - Defer control of this application to an outside authority. -
    - - - - - - - - - -
    Parameters:
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    NameTypeDescription
    authority - - - String - - - - Hostname to trust.
    - - - - - - -
    - - - - - - - - - - - - - - - - - - - - - - - - - - -
    Source:
    -
    - -
    - - - - - - - -
    - - - - - - - - - - - - - - - -
    Returns:
    - - -
    - The configured application as deferred to `authority`. -
    - - - -
    -
    - Type -
    -
    - - App - - -
    -
    - - - - - - - - - - - - - -

    (async) define(name, structure) → {Object}

    - - - - - - -
    - Define a Resource, or "Type", used by the application. -
    - - - - - - - - - -
    Parameters:
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    NameTypeDescription
    name - - - String - - - - Human-friendly name for the Resource.
    structure - - - Object - - - - Map of attribute names -> definitions.
    - - - - - - -
    - - - - - - - - - - - - - - - - - - - - - - - - - - -
    Source:
    -
    - -
    - - - - - - - -
    - - - - - - - - - - - - - - - -
    Returns:
    - - -
    - [description] -
    - - - -
    -
    - Type -
    -
    - - Object - - -
    -
    - - - - - - - - - - - - - -

    envelop(selector) → {App}

    - - - - - - -
    - Use a CSS selector to find an element in the current document's tree and - bind to it as the render target. -
    - - - - - - - - - -
    Parameters:
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    NameTypeDescription
    selector - - - String - - - - CSS selector.
    - - - - - - -
    - - - - - - - - - - - - - - - - - - - - - - - - - - -
    Source:
    -
    - -
    - - - - - - - -
    - - - - - - - - - - - - - - - -
    Returns:
    - - -
    - Instance of app with bound element. -
    - - - -
    -
    - Type -
    -
    - - App - - -
    -
    - - - - - - - - - - - - - -

    get(path) → {Mixed}

    - - - - - - -
    - Retrieve a key from the State. -
    - - - - - - - - - -
    Parameters:
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    NameTypeDescription
    path - - - Path - - - - Key to retrieve.
    - - - - - - -
    - - - - - - - - -
    Overrides:
    -
    - -
    - - - - - - - - - - - - - - - - - - - -
    Source:
    -
    - -
    - - - - - - - -
    - - - - - - - - - - - - - - - -
    Returns:
    - - - - -
    -
    - Type -
    -
    - - Mixed - - -
    -
    - - - - - - - - - - - - - -

    handler(message) → {Service}

    - - - - - - -
    - Default route handler for an incoming message. Follows the Activity - Streams 2.0 spec: https://www.w3.org/TR/activitystreams-core/ -
    - - - - - - - - - -
    Parameters:
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    NameTypeDescription
    message - - - Activity - - - - Message object.
    - - - - - - -
    - - - - - - - - -
    Overrides:
    -
    - -
    - - - - - - - - - - - - - - - - - - - -
    Source:
    -
    - -
    - - - - - - - -
    - - - - - - - - - - - - - - - -
    Returns:
    - - -
    - Chainable method. -
    - - - -
    -
    - Type -
    -
    - - Service - - -
    -
    - - - - - - - - - - - - - -

    init()

    - - - - - - -
    - Called by Web Components. - TODO: move to @fabric/http/types/spa -
    - - - - - - - - - - - - - -
    - - - - - - - - -
    Overrides:
    -
    - -
    - - - - - - - - - - - - - - - - - - - -
    Source:
    -
    - -
    - - - - - - - -
    - - - - - - - - - - - - - - - - - - - - - - - - - - -

    lock(durationopt) → {Boolean}

    - - - - - - -
    - Attempt to acquire a lock for `duration` seconds. -
    - - - - - - - - - -
    Parameters:
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    NameTypeAttributesDefaultDescription
    duration - - - Number - - - - - - <optional>
    - - - - - -
    - - 1000 - - Number of milliseconds to hold lock.
    - - - - - - -
    - - - - - - - - -
    Overrides:
    -
    - -
    - - - - - - - - - - - - - - - - - - - -
    Source:
    -
    - -
    - - - - - - - -
    - - - - - - - - - - - - - - - -
    Returns:
    - - -
    - true if locked, false if unable to lock. -
    - - - -
    -
    - Type -
    -
    - - Boolean - - -
    -
    - - - - - - - - - - - - - -

    render() → {String}

    - - - - - - -
    - Get the output of our program. -
    - - - - - - - - - - - - - -
    - - - - - - - - - - - - - - - - - - - - - - - - - - -
    Source:
    -
    - -
    - - - - - - - -
    - - - - - - - - - - - - - - - -
    Returns:
    - - -
    - Output of the program. -
    - - - -
    -
    - Type -
    -
    - - String - - -
    -
    - - - - - - - - - - - - - -

    (async) route(msg) → {Promise}

    - - - - - - -
    - Resolve a State from a particular Message object. -
    - - - - - - - - - -
    Parameters:
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    NameTypeDescription
    msg - - - Message - - - - Explicit Fabric Message.
    - - - - - - -
    - - - - - - - - -
    Overrides:
    -
    - -
    - - - - - - - - - - - - - - - - - - - -
    Source:
    -
    - -
    - - - - - - - -
    - - - - - - - - - - - - - - - -
    Returns:
    - - -
    - Resolves with resulting State. -
    - - - -
    -
    - Type -
    -
    - - Promise - - -
    -
    - - - - - - - - - - - - - -

    (async) send(channel, message) → {Service}

    - - - - - - -
    - Send a message to a channel. -
    - - - - - - - - - -
    Parameters:
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    NameTypeDescription
    channel - - - String - - - - Channel name to which the message will be sent.
    message - - - String - - - - Content of the message to send.
    - - - - - - -
    - - - - - - - - -
    Overrides:
    -
    - -
    - - - - - - - - - - - - - - - - - - - -
    Source:
    -
    - -
    - - - - - - - -
    - - - - - - - - - - - - - - - -
    Returns:
    - - -
    - Chainable method. -
    - - - -
    -
    - Type -
    -
    - - Service - - -
    -
    - - - - - - - - - - - - - -

    set(path) → {Mixed}

    - - - - - - -
    - Set a key in the State to a particular value. -
    - - - - - - - - - -
    Parameters:
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    NameTypeDescription
    path - - - Path - - - - Key to retrieve.
    - - - - - - -
    - - - - - - - - -
    Overrides:
    -
    - -
    - - - - - - - - - - - - - - - - - - - -
    Source:
    -
    - -
    - - - - - - - -
    - - - - - - - - - - - - - - - -
    Returns:
    - - - - -
    -
    - Type -
    -
    - - Mixed - - -
    -
    - - - - - - - - - - - - - -

    (async) start() → {Promise}

    - - - - - - -
    - Start the program. -
    - - - - - - - - - - - - - -
    - - - - - - - - -
    Overrides:
    -
    - -
    - - - - - - - - - - - - - - - - - - - -
    Source:
    -
    - -
    - - - - - - - -
    - - - - - - - - - - - - - - - -
    Returns:
    - - - - -
    -
    - Type -
    -
    - - Promise - - -
    -
    - - - - - - - - - - - - - -

    (async) stop() → {Promise}

    - - - - - - -
    - Stop the program. -
    - - - - - - - - - - - - - -
    - - - - - - - - - - - - - - - - - - - - - - - - - - -
    Source:
    -
    - -
    - - - - - - - -
    - - - - - - - - - - - - - - - -
    Returns:
    - - - - -
    -
    - Type -
    -
    - - Promise - - -
    -
    - - - - - - - - - - - - - -

    tick() → {Number}

    - - - - - - -
    - Move forward one clock cycle. -
    - - - - - - - - - - - - - -
    - - - - - - - - -
    Overrides:
    -
    - -
    - - - - - - - - - - - - - - - - - - - -
    Source:
    -
    - -
    - - - - - - - -
    - - - - - - - - - - - - - - - -
    Returns:
    - - - - -
    -
    - Type -
    -
    - - Number - - -
    -
    - - - - - - - - - - - - - -

    trust(source) → {Service}

    - - - - - - -
    - Explicitly trust all events from a known source. -
    - - - - - - - - - -
    Parameters:
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    NameTypeDescription
    source - - - EventEmitter - - - - Emitter of events.
    - - - - - - -
    - - - - - - - - -
    Overrides:
    -
    - -
    - - - - - - - - - - - - - - - - - - - -
    Source:
    -
    - -
    - - - - - - - -
    - - - - - - - - - - - - - - - -
    Returns:
    - - -
    - Instance of Service after binding events. -
    - - - -
    -
    - Type -
    -
    - - Service - - -
    -
    - - - - - - - - - - - - - -

    use(name, definition) → {App}

    - - - - - - -
    - Define a named Resource. -
    - - - - - - - - - -
    Parameters:
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    NameTypeDescription
    name - - - String - - - - Human-friendly name for this resource.
    definition - - - Object - - - - Map of configuration values.
    - - - - - - -
    - - - - - - - - - - - - - - - - - - - - - - - - - - -
    Source:
    -
    - -
    - - - - - - - -
    - - - - - - - - - - - - - - - -
    Returns:
    - - -
    - Configurated instance of the App. -
    - - - -
    -
    - Type -
    -
    - - App - - -
    -
    - - - - - - - - - - - - - -
    - -
    - - - -
    - -
    - - - - - - \ No newline at end of file diff --git a/docs/Bitcoin.html b/docs/Bitcoin.html index c4a001813..52f264c21 100644 --- a/docs/Bitcoin.html +++ b/docs/Bitcoin.html @@ -325,7 +325,7 @@
    Properties
    @@ -388,14 +388,13 @@

    Members

    -

    (static) MutableTransaction

    +

    UAString

    - Provides bcoin's implementation of `MTX` internally. This static may be - removed in the future. + User Agent string for the Bitcoin P2P network.
    @@ -435,7 +434,7 @@

    (static)
    @@ -455,14 +454,13 @@

    (static) -

    (static) Transaction

    +

    height

    - Provides bcoin's implementation of `TX` internally. This static may be - removed in the future. + Chain height (`=== length - 1`)
    @@ -502,7 +500,7 @@

    (static)
    @@ -522,13 +520,13 @@

    (static) -

    height

    +

    tip

    - Chain height (`=== length - 1`) + Chain tip (block hash of the chain with the most Proof of Work)
    @@ -568,7 +566,7 @@

    height @@ -588,13 +586,25 @@

    heighttip

    + + +

    Methods

    + + + + + + + +

    (async) _GET(path) → {Promise}

    + +
    - Chain tip (block hash of the chain with the most Proof of Work) + Retrieve a value from the Service's state.
    @@ -603,6 +613,61 @@

    tip + + + + Name + + + Type + + + + + + Description + + + + + + + + + path + + + + + + String + + + + + + + + + + Path of the value to retrieve. + + + + + + + + + + +
    @@ -612,6 +677,15 @@

    tipOverrides: +
    + +
    + @@ -634,7 +708,7 @@

    tip @@ -654,13 +728,55 @@

    tipUAString

    + + + + + + + +
    Returns:
    + + +
    + Resolves with the result. +
    + + + +
    +
    + Type +
    +
    + + Promise + + +
    +
    + + + + + + + + + + + + + +

    (async) _PUT(path, value, commitopt) → {Promise}

    + +
    - User Agent string for the Bitcoin P2P network. + Store a value in the Service's state.
    @@ -669,6 +785,151 @@

    UAStringParameters:

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    NameTypeAttributesDefaultDescription
    path + + + String + + + + + + + + + + + + Path to store the value at.
    value + + + Object + + + + + + + + + + + + Document to store.
    commit + + + Boolean + + + + + + <optional>
    + + + + + +
    + + false + + Sign the resulting state.
    + + + + + +
    @@ -678,6 +939,15 @@

    UAStringOverrides: +
    + +
    + @@ -700,7 +970,7 @@

    UAString @@ -722,7 +992,37 @@

    UAStringMethods

    + + + + + +
    Returns:
    + + +
    + Resolves with with stored document. +
    + + + +
    +
    + Type +
    +
    + + Promise + + +
    +
    + + + + + + @@ -833,7 +1133,7 @@
    Parameters:
    @@ -947,7 +1247,7 @@

    (async) _c
    @@ -1088,7 +1388,7 @@

    Parameters:
    @@ -1148,7 +1448,7 @@
    Returns:
    -

    (async) _GET(path) → {Promise}

    +

    (async) _handleBlockFromSPV(msg)

    @@ -1156,7 +1456,7 @@

    (async) _GET - Retrieve a value from the Service's state. + Hand a Block message as supplied by an SPV client. @@ -1192,13 +1492,13 @@
    Parameters:
    - path + msg - String + BlockMessage @@ -1208,7 +1508,7 @@
    Parameters:
    - Path of the value to retrieve. + A Message as passed by the SPV source. @@ -1229,15 +1529,6 @@
    Parameters:
    -
    Overrides:
    -
    - -
    - @@ -1260,7 +1551,7 @@
    Parameters:
    @@ -1287,28 +1578,6 @@
    Parameters:
    -
    Returns:
    - - -
    - Resolves with the result. -
    - - - -
    -
    - Type -
    -
    - - Promise - - -
    -
    - - @@ -1320,7 +1589,7 @@
    Returns:
    -

    (async) _handleBlockFromSPV(msg)

    +

    (async) _handleCommittedBlock(block)

    @@ -1328,7 +1597,7 @@

    (async) <
    - Hand a Block message as supplied by an SPV client. + Receive a committed block.
    @@ -1364,13 +1633,13 @@
    Parameters:
    - msg + block - BlockMessage + Block @@ -1380,7 +1649,7 @@
    Parameters:
    - A Message as passed by the SPV source. + Block to handle. @@ -1423,7 +1692,7 @@
    Parameters:
    @@ -1461,7 +1730,7 @@
    Parameters:
    -

    (async) _handleCommittedBlock(block)

    +

    (async) _handlePeerPacket(msg)

    @@ -1469,7 +1738,7 @@

    (async)
    - Receive a committed block. + Process a message from a peer in the Bitcoin network.
    @@ -1505,13 +1774,13 @@
    Parameters:
    - block + msg - Block + PeerPacket @@ -1521,7 +1790,7 @@
    Parameters:
    - Block to handle. + Message from peer. @@ -1564,7 +1833,7 @@
    Parameters:
    @@ -1602,7 +1871,7 @@
    Parameters:
    -

    (async) _handlePeerPacket(msg)

    +

    (async) _handleTransactionFromSPV(tx)

    @@ -1610,7 +1879,8 @@

    (async) - Process a message from a peer in the Bitcoin network. + Verify and interpret a BitcoinTransaction, as received from an + SPVSource. @@ -1646,13 +1916,13 @@
    Parameters:
    - msg + tx - PeerPacket + BitcoinTransaction @@ -1662,7 +1932,7 @@
    Parameters:
    - Message from peer. + Incoming transaction from the SPV source. @@ -1705,7 +1975,7 @@
    Parameters:
    @@ -1743,7 +2013,7 @@
    Parameters:
    -

    (async) _handleTransactionFromSPV(tx)

    +

    (async) _prepareTransaction(obj)

    @@ -1751,8 +2021,7 @@

    (as
    - Verify and interpret a BitcoinTransaction, as received from an - SPVSource. + Prepares a Transaction for storage.
    @@ -1788,13 +2057,13 @@
    Parameters:
    - tx + obj - BitcoinTransaction + Transaction @@ -1804,7 +2073,7 @@
    Parameters:
    - Incoming transaction from the SPV source. + Transaction to prepare. @@ -1847,7 +2116,7 @@
    Parameters:
    @@ -1885,7 +2154,7 @@
    Parameters:
    -

    (async) _prepareTransaction(obj)

    +

    (async) _processSpendMessage(message) → {BitcoinTransactionID}

    @@ -1893,7 +2162,7 @@

    (async) <
    - Prepares a Transaction for storage. + Process a spend message.
    @@ -1929,13 +2198,13 @@
    Parameters:
    - obj + message - Transaction + SpendMessage @@ -1945,76 +2214,91 @@
    Parameters:
    - Transaction to prepare. - - - - - - + Generic-level message for spending. +
    Properties
    + + + + -
    +
    + + + + + + + + + + + -
    Source:
    -
    - -
    + - + + + +
    NameTypeDescription
    amount + String + Amount (in BTC) to spend.
    destination + String + Destination for funds.
    + + + + +
    @@ -2026,16 +2310,12 @@
    Parameters:
    -

    (async) _PUT(path, value, commitopt) → {Promise}

    -
    - Store a value in the Service's state. -
    @@ -2045,123 +2325,121 @@

    (async) _PUTParameters:

    +
    Source:
    +
    + +
    - - - - - - + - - - - - - - - +
    + Hex-encoded representation of the transaction ID. +
    - + + - - - - - - - - +
    Parameters:
    - - +
    NameTypeAttributesDefaultDescription
    path - String +
    Returns:
    -
    +
    +
    + Type +
    +
    + BitcoinTransactionID -
    - Path to store the value at.
    value +

    (async) _registerActor(actor) → {Promise}

    - Object -
    +
    + Register an Actor with the Service. +
    -
    - Document to store.
    + + + - + - - + + + - + + - - + @@ -2201,7 +2474,7 @@
    Parameters:
    @@ -2228,7 +2501,7 @@
    Parameters:
    @@ -2259,7 +2532,7 @@
    Returns:
    - Resolves with with stored document. + Resolves upon successful registration.
    @@ -2288,7 +2561,7 @@
    Returns:
    -

    (async) _registerActor(actor) → {Promise}

    +

    (async) _requestBlockAtHeight(height) → {Object}

    @@ -2296,7 +2569,7 @@

    (async) - Register an Actor with the Service. + Retrieve the equivalent to `getblockhash` from Bitcoin Core. @@ -2332,13 +2605,13 @@

    Parameters:
    - + + @@ -2369,15 +2642,6 @@
    Parameters:
    -
    Overrides:
    -
    - -
    - @@ -2400,7 +2664,7 @@
    Parameters:
    @@ -2431,7 +2695,7 @@
    Returns:
    - Resolves upon successful registration. + The block hash.
    @@ -2442,7 +2706,7 @@
    Returns:
    - Promise + Object
    @@ -2572,7 +2836,7 @@
    Parameters:
    @@ -2610,16 +2874,123 @@
    Parameters:
    -

    (async) _subscribeToShard(shard)

    +

    (async) _subscribeToShard(shard)

    + + + + + + +
    + Attach event handlers for a supplied list of addresses. +
    + + + + + + + + + +
    Parameters:
    + + +
    Name
    Typecommit - Boolean + Description
    actor - <optional>
    +
    + Object @@ -2169,14 +2447,9 @@
    Parameters:
    -
    - - false - - Sign the resulting state.Instance of the Actor.
    actorheight - Object + Number @@ -2348,7 +2621,7 @@
    Parameters:
    -
    Instance of the Actor.Height of block to retrieve.
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    NameTypeDescription
    shard + + + Shard + + + + List of addresses to monitor.
    + + + + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Source:
    +
    + +
    + + + +
    -
    - Attach event handlers for a supplied list of addresses. -
    @@ -2629,53 +3000,38 @@

    (async) Parameters:

    - - - - - - - - - - - +

    beat() → {Service}

    - +
    + Compute latest state. +
    - - - -
    NameTypeDescription
    shard - Shard - List of addresses to monitor.
    @@ -2691,6 +3047,15 @@
    Parameters:
    +
    Overrides:
    +
    + +
    + @@ -2713,7 +3078,7 @@
    Parameters:
    @@ -2730,14 +3095,37 @@
    Parameters:
    +
    Fires:
    +
      +
    • Message#event:beat
    • +
    + + + + + + +
    Returns:
    + + + + +
    +
    + Type +
    +
    + Service +
    +
    @@ -2854,7 +3242,7 @@
    Parameters:
    @@ -3004,7 +3392,7 @@
    Parameters:
    @@ -3154,7 +3542,7 @@
    Parameters:
    @@ -3184,6 +3572,10 @@
    Parameters:
    Returns:
    +
    + Returns the target value if found, otherwise null. +
    +
    @@ -3323,7 +3715,7 @@
    Parameters:
    @@ -3447,7 +3839,7 @@

    init @@ -3617,7 +4009,7 @@
    Parameters:
    @@ -3789,7 +4181,7 @@
    Parameters:
    @@ -3984,7 +4376,7 @@
    Parameters:
    @@ -4156,7 +4548,7 @@
    Parameters:
    @@ -4275,7 +4667,7 @@

    (async) start @@ -4367,7 +4759,7 @@

    (async) stop @@ -4468,7 +4860,7 @@

    tick @@ -4636,7 +5028,7 @@
    Parameters:
    @@ -4696,6 +5088,201 @@
    Returns:
    +

    when(event, method) → {EventEmitter}

    + + + + + + +
    + Bind a method to an event, with current state as the immutable context. +
    + + + + + + + + + +
    Parameters:
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    NameTypeDescription
    event + + + String + + + + Name of the event upon which to execute `method` as a function.
    method + + + function + + + + Function to execute when named Event `event` is encountered.
    + + + + + + +
    + + + + + + + + +
    Overrides:
    +
    + +
    + + + + + + + + + + + + + + + + + + + +
    Source:
    +
    + +
    + + + + + + + +
    + + + + + + + + + + + + + + + +
    Returns:
    + + +
    + Instance of EventEmitter. +
    + + + +
    +
    + Type +
    +
    + + EventEmitter + + +
    +
    + + + + + + + + + + + + + @@ -4708,52 +5295,49 @@

    Home

    Classes

    Events

    diff --git a/docs/CLI.html b/docs/CLI.html index 874146b55..ad297d7b6 100644 --- a/docs/CLI.html +++ b/docs/CLI.html @@ -227,7 +227,7 @@
    Properties
    @@ -279,6 +279,147 @@
    Properties

    Methods

    + + + + + + +

    (async) _handleGrantCommand(params)

    + + + + + + +
    + Creates a token for the target signer with a provided role and some optional data. +
    + + + + + + + + + +
    Parameters:
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    NameTypeDescription
    params + + + Array + + + + Parameters array.
    + + + + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Source:
    +
    + +
    + + + + + + + +
    + + + + + + + + + + + + + + + + + + + + @@ -339,7 +480,7 @@

    (async) start @@ -431,7 +572,7 @@

    (async) stop @@ -481,52 +622,49 @@

    Home

    Classes

    Events

    diff --git a/docs/Chain.html b/docs/Chain.html index b7784219a..b571f2102 100644 --- a/docs/Chain.html +++ b/docs/Chain.html @@ -251,7 +251,7 @@
    Properties:
    @@ -317,52 +317,49 @@

    Home

    Classes

    Events

    diff --git a/docs/Channel.html b/docs/Channel.html index 56e66a46e..76a9e7782 100644 --- a/docs/Channel.html +++ b/docs/Channel.html @@ -173,7 +173,7 @@
    Parameters:
    @@ -666,52 +666,49 @@

    Home

    Classes

    Events

    diff --git a/docs/Circuit.html b/docs/Circuit.html index a0a4c2cb6..33b1cda49 100644 --- a/docs/Circuit.html +++ b/docs/Circuit.html @@ -38,7 +38,7 @@

    CircuitThe Circuit is the mechanism through which Fabric operates, a computable directed graph describing a network of Peer components and their interactions (side effects). - See also Swarm for deeper *inspection of Machine + See also Swarm for deeper inspection of Machine mechanics. @@ -171,55 +171,43 @@

    Home

    Classes

    Events

    diff --git a/docs/Consensus.html b/docs/Consensus.html index e6403cc9c..d94812e90 100644 --- a/docs/Consensus.html +++ b/docs/Consensus.html @@ -259,7 +259,7 @@
    Properties
    @@ -330,19 +330,27 @@

    Classes

  • Bitcoin
  • Chain
  • Channel
  • +
  • Circuit
  • CLI
  • Collection
  • Compiler
  • Consensus
  • Entity
  • +
  • Environment
  • Exchange
  • Fabric
  • +
  • Federation
  • +
  • Filesystem
  • Hash256
  • HKDF
  • HTTPServer
  • +
  • Identity
  • Interface
  • Key
  • -
  • KeyStore
  • +
  • Keystore
  • +
  • Ledger
  • +
  • Lightning
  • +
  • Logger
  • Machine
  • Mempool
  • Message
  • @@ -352,6 +360,8 @@

    Classes

  • Peer
  • Reader
  • Redis
  • +
  • Remote
  • +
  • Resource
  • Router
  • Scribe
  • Script
  • @@ -371,6 +381,7 @@

    Classes

  • Vector
  • Walker
  • Wallet
  • +
  • Worker
  • ZMQ
  • Events

    diff --git a/docs/Entity.html b/docs/Entity.html index 124347901..adda8696a 100644 --- a/docs/Entity.html +++ b/docs/Entity.html @@ -173,7 +173,7 @@
    Parameters:
    @@ -651,19 +651,27 @@

    Classes

  • Bitcoin
  • Chain
  • Channel
  • +
  • Circuit
  • CLI
  • Collection
  • Compiler
  • Consensus
  • Entity
  • +
  • Environment
  • Exchange
  • Fabric
  • +
  • Federation
  • +
  • Filesystem
  • Hash256
  • HKDF
  • HTTPServer
  • +
  • Identity
  • Interface
  • Key
  • -
  • KeyStore
  • +
  • Keystore
  • +
  • Ledger
  • +
  • Lightning
  • +
  • Logger
  • Machine
  • Mempool
  • Message
  • @@ -673,6 +681,8 @@

    Classes

  • Peer
  • Reader
  • Redis
  • +
  • Remote
  • +
  • Resource
  • Router
  • Scribe
  • Script
  • @@ -692,6 +702,7 @@

    Classes

  • Vector
  • Walker
  • Wallet
  • +
  • Worker
  • ZMQ
  • Events

    diff --git a/docs/Environment.html b/docs/Environment.html index 90092a3cd..8b0681c38 100644 --- a/docs/Environment.html +++ b/docs/Environment.html @@ -165,7 +165,7 @@
    Parameters:
    @@ -348,7 +348,7 @@
    Parameters:
    @@ -546,7 +546,7 @@
    Parameters:
    @@ -660,7 +660,7 @@

    start @@ -732,55 +732,43 @@

    Home

    Classes

    Events

    diff --git a/docs/Fabric.html b/docs/Fabric.html index c701e8871..8b154fbe9 100644 --- a/docs/Fabric.html +++ b/docs/Fabric.html @@ -127,58 +127,6 @@
    Parameters:
    -
    Properties:
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    NameTypeDescription
    Block - - - Class - - - -
    - - - -
    @@ -210,7 +158,7 @@
    Properties:
    @@ -329,7 +277,7 @@

    compute @@ -492,7 +440,7 @@
    Parameters:
    @@ -651,7 +599,7 @@
    Parameters:
    @@ -793,7 +741,7 @@
    Parameters:
    @@ -865,52 +813,49 @@

    Home

    Classes

    Events

    diff --git a/docs/Federation.html b/docs/Federation.html index 9be420db0..5749fcf6b 100644 --- a/docs/Federation.html +++ b/docs/Federation.html @@ -165,7 +165,7 @@
    Parameters:
    @@ -245,6 +245,387 @@

    Methods

    +

    createMultiSignature(msg) → {Object}

    + + + + + + +
    + Creates a multi-signature for a message. +
    + + + + + + + + + +
    Parameters:
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    NameTypeDescription
    msg + + + Buffer + | + + String + | + + Message + + + + The message to sign
    + + + + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Source:
    +
    + +
    + + + + + + + +
    + + + + + + + + + + + + + + + +
    Returns:
    + + +
    + The multi-signature object containing signatures from all validators +
    + + + +
    +
    + Type +
    +
    + + Object + + +
    +
    + + + + + + + + + + + + + +

    sign(msg, pubkeyopt) → {Buffer}

    + + + + + + +
    + Signs a message using the federation's key. +
    + + + + + + + + + +
    Parameters:
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    NameTypeAttributesDescription
    msg + + + Buffer + | + + String + | + + Message + + + + + + + + + + The message to sign
    pubkey + + + String + + + + + + <optional>
    + + + + + +
    Optional public key of the member to sign with
    + + + + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Source:
    +
    + +
    + + + + + + + +
    + + + + + + + + + + + + + + + +
    Returns:
    + + +
    + The signature +
    + + + +
    +
    + Type +
    +
    + + Buffer + + +
    +
    + + + + + + + + + + + + +

    start() → {Federation}

    @@ -253,7 +634,121 @@

    start - Start tracking state (i.e., ready to receive events). + Start tracking state (i.e., ready to receive events). + + + + + + + + + + + + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Source:
    +
    + +
    + + + + + + + +
    + + + + + + + + + + + + + + + +
    Returns:
    + + +
    + Instance of the Federation. +
    + + + +
    +
    + Type +
    +
    + + Federation + + +
    +
    + + + + + + + + + + + + + +

    verify(msg, sig) → {Boolean}

    + + + + + + +
    + Verifies a signature against a message.
    @@ -264,6 +759,84 @@

    startParameters:

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    NameTypeDescription
    msg + + + Buffer + | + + String + | + + Message + + + + The message that was signed
    sig + + + Buffer + + + + The signature to verify
    + + @@ -299,7 +872,7 @@

    start @@ -330,7 +903,7 @@
    Returns:
    - Instance of the Federation. + Whether the signature is valid
    @@ -341,7 +914,205 @@
    Returns:
    - Federation + Boolean + + +
    +

    + + + + + + + + + + + + + +

    verifyMultiSignature(multiSig, threshold) → {Boolean}

    + + + + + + +
    + Verifies a multi-signature against a message. +
    + + + + + + + + + +
    Parameters:
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    NameTypeDefaultDescription
    multiSig + + + Object + + + + + + The multi-signature object
    threshold + + + Number + + + + + + 1 + + Number of valid signatures required
    + + + + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Source:
    +
    + +
    + + + + + + + +
    + + + + + + + + + + + + + + + +
    Returns:
    + + +
    + Whether the multi-signature is valid +
    + + + +
    +
    + Type +
    +
    + + Boolean
    @@ -371,55 +1142,43 @@

    Home

    Classes

    @@ -2253,7 +2265,7 @@

    toObject @@ -2372,7 +2384,7 @@

    unpause @@ -2564,7 +2576,7 @@
    Parameters:
    @@ -2636,55 +2648,43 @@

    Home

    Classes

    Events

    diff --git a/docs/Message.html b/docs/Message.html index 5f6709115..985a3039d 100644 --- a/docs/Message.html +++ b/docs/Message.html @@ -155,7 +155,7 @@
    Parameters:
    @@ -235,6 +235,221 @@

    Methods

    +

    _setSigner(key) → {Message}

    + + + + + + +
    + Sets the signer for the message. +
    + + + + + + + + + +
    Parameters:
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    NameTypeDescription
    key + + + Object + + + + Key object with pubkey property. +
    Properties
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    NameTypeDescription
    pubkey + + + String + | + + Buffer + + + + Public key
    + +
    + + + + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Source:
    +
    + +
    + + + + + + + +
    + + + + + + + + + + + + + + + +
    Returns:
    + + +
    + Instance of the Message with associated signer. +
    + + + +
    +
    + Type +
    +
    + + Message + + +
    +
    + + + + + + + + + + + + +

    asRaw() → {Buffer}

    @@ -243,7 +458,414 @@

    asRaw - Returns a Buffer of the complete message. + Returns a Buffer of the complete message. + + + + + + + + + + + + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Source:
    +
    + +
    + + + + + + + +
    + + + + + + + + + + + + + + + +
    Returns:
    + + +
    + Buffer of the encoded Message. +
    + + + +
    +
    + Type +
    +
    + + Buffer + + +
    +
    + + + + + + + + + + + + + +

    signWithKey(key) → {Message}

    + + + + + + +
    + Signs the message using a specific key. +
    + + + + + + + + + +
    Parameters:
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    NameTypeDescription
    key + + + Object + + + + Key object with private key and sign method. +
    Properties
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    NameTypeDescription
    private + + + String + | + + Buffer + + + + Private key
    pubkey + + + String + | + + Buffer + + + + Public key
    sign + + + function + + + + Signing function
    + +
    + + + + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Source:
    +
    + +
    + + + + + + + +
    + + + + + + + + + + + + + +
    Throws:
    + + + +
    +
    +
    + If attempting to sign without a private key +
    +
    +
    +
    +
    +
    + Type +
    +
    + + Error + + +
    +
    +
    +
    +
    + + + + + +
    Returns:
    + + +
    + Signed message. +
    + + + +
    +
    + Type +
    +
    + + Message + + +
    +
    + + + + + + + + + + + + + +

    verify() → {Boolean}

    + + + + + + +
    + Verify a message's signature.
    @@ -289,7 +911,7 @@

    asRaw @@ -320,7 +942,7 @@
    Returns:
    - Buffer of the encoded Message. + `true` if the signature is valid, `false` if not.
    @@ -331,7 +953,219 @@
    Returns:
    - Buffer + Boolean + + +
    +

    + + + + + + + + + + + + + +

    verifyWithKey(key) → {Boolean}

    + + + + + + +
    + Verify a message's signature with a specific key. +
    + + + + + + + + + +
    Parameters:
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    NameTypeDescription
    key + + + Object + + + + Key object with verify method. +
    Properties
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    NameTypeDescription
    verify + + + function + + + + Verification function
    + +
    + + + + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Source:
    +
    + +
    + + + + + + + +
    + + + + + + + + + + + + + + + +
    Returns:
    + + +
    + `true` if the signature is valid, `false` if not. +
    + + + +
    +
    + Type +
    +
    + + Boolean
    @@ -361,52 +1195,49 @@

    Home

    Classes

    Events

    diff --git a/docs/Node.html b/docs/Node.html index d1f2e6e7c..e47c82aea 100644 --- a/docs/Node.html +++ b/docs/Node.html @@ -153,7 +153,7 @@
    Parameters:
    @@ -362,7 +362,7 @@
    Parameters:
    @@ -417,19 +417,27 @@

    Classes

  • Bitcoin
  • Chain
  • Channel
  • +
  • Circuit
  • CLI
  • Collection
  • Compiler
  • Consensus
  • Entity
  • +
  • Environment
  • Exchange
  • Fabric
  • +
  • Federation
  • +
  • Filesystem
  • Hash256
  • HKDF
  • HTTPServer
  • +
  • Identity
  • Interface
  • Key
  • -
  • KeyStore
  • +
  • Keystore
  • +
  • Ledger
  • +
  • Lightning
  • +
  • Logger
  • Machine
  • Mempool
  • Message
  • @@ -439,6 +447,8 @@

    Classes

  • Peer
  • Reader
  • Redis
  • +
  • Remote
  • +
  • Resource
  • Router
  • Scribe
  • Script
  • @@ -458,6 +468,7 @@

    Classes

  • Vector
  • Walker
  • Wallet
  • +
  • Worker
  • ZMQ
  • Events

    diff --git a/docs/Oracle.html b/docs/Oracle.html index 46cbc21d9..e5825054f 100644 --- a/docs/Oracle.html +++ b/docs/Oracle.html @@ -154,7 +154,7 @@
    Parameters:
    @@ -1661,19 +1661,27 @@

    Classes

  • Bitcoin
  • Chain
  • Channel
  • +
  • Circuit
  • CLI
  • Collection
  • Compiler
  • Consensus
  • Entity
  • +
  • Environment
  • Exchange
  • Fabric
  • +
  • Federation
  • +
  • Filesystem
  • Hash256
  • HKDF
  • HTTPServer
  • +
  • Identity
  • Interface
  • Key
  • -
  • KeyStore
  • +
  • Keystore
  • +
  • Ledger
  • +
  • Lightning
  • +
  • Logger
  • Machine
  • Mempool
  • Message
  • @@ -1683,6 +1691,8 @@

    Classes

  • Peer
  • Reader
  • Redis
  • +
  • Remote
  • +
  • Resource
  • Router
  • Scribe
  • Script
  • @@ -1702,6 +1712,7 @@

    Classes

  • Vector
  • Walker
  • Wallet
  • +
  • Worker
  • ZMQ
  • Events

    diff --git a/docs/Path.html b/docs/Path.html index af4835943..5f0ea523f 100644 --- a/docs/Path.html +++ b/docs/Path.html @@ -157,7 +157,7 @@
    Parameters:
    @@ -342,19 +342,27 @@

    Classes

  • Bitcoin
  • Chain
  • Channel
  • +
  • Circuit
  • CLI
  • Collection
  • Compiler
  • Consensus
  • Entity
  • +
  • Environment
  • Exchange
  • Fabric
  • +
  • Federation
  • +
  • Filesystem
  • Hash256
  • HKDF
  • HTTPServer
  • +
  • Identity
  • Interface
  • Key
  • -
  • KeyStore
  • +
  • Keystore
  • +
  • Ledger
  • +
  • Lightning
  • +
  • Logger
  • Machine
  • Mempool
  • Message
  • @@ -364,6 +372,8 @@

    Classes

  • Peer
  • Reader
  • Redis
  • +
  • Remote
  • +
  • Resource
  • Router
  • Scribe
  • Script
  • @@ -383,6 +393,7 @@

    Classes

  • Vector
  • Walker
  • Wallet
  • +
  • Worker
  • ZMQ
  • Events

    diff --git a/docs/Peer.html b/docs/Peer.html index 0019469f0..d3febc8c0 100644 --- a/docs/Peer.html +++ b/docs/Peer.html @@ -347,7 +347,7 @@
    Properties
    @@ -395,10 +395,642 @@
    Properties
    +

    Members

    + + + +

    address

    + + + + + + + + + + +
    + + + + + + + + + + + + + + + + +
    Deprecated:
    +
    +
      +
    • Yes
    • +
    +
    + + + + + + + + + + + +
    Source:
    +
    + +
    + + + + + + + +
    + + + + + + + +

    Methods

    + + + + + + +

    _connect(target)

    + + + + + + +
    + Open a Fabric connection to the target address and initiate the Fabric Protocol. +
    + + + + + + + + + +
    Parameters:
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    NameTypeDescription
    target + + + String + + + + Target address.
    + + + + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Source:
    +
    + +
    + + + + + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + +

    _fillPeerSlots() → {Peer}

    + + + + + + +
    + Attempt to fill available connection slots with new peers. +
    + + + + + + + + + + + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Source:
    +
    + +
    + + + + + + + +
    + + + + + + + + + + + + + + + +
    Returns:
    + + +
    + Instance of the peer. +
    + + + +
    +
    + Type +
    +
    + + Peer + + +
    +
    + + + + + + + + + + + + + +

    _handleFabricMessage(buffer) → {Peer}

    + + + + + + +
    + Handle a Fabric Message buffer. +
    + + + + + + + + + +
    Parameters:
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    NameTypeDescription
    buffer + + + Buffer + + + +
    + + + + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Source:
    +
    + +
    + + + + + + + +
    + + + + + + + + + + + + + + + +
    Returns:
    + + +
    + Instance of the Peer. +
    + + + +
    +
    + Type +
    +
    + + Peer + + +
    +
    + + + + + + + + + + + + + +

    broadcast(message)

    + + + + + + +
    + Write a Buffer to all connected peers. +
    + + + + + + + + + +
    Parameters:
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    NameTypeDescription
    message + + + Buffer + + + + Message buffer to send.
    + + + + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Source:
    +
    + +
    + + + + + + + +
    + + + + + + + + + + + + + + + + + + + + @@ -459,7 +1091,7 @@

    (async) listen<
    @@ -476,11 +1108,6 @@

    (async) listen< -

    Fires:
    -
      -
    • Peer#event:ready
    • -
    - @@ -578,7 +1205,7 @@

    (async) start @@ -670,7 +1297,7 @@

    (async) stop @@ -720,52 +1347,49 @@

    Home

    Classes

    Events

    diff --git a/docs/Reader.html b/docs/Reader.html index 96e02d30f..241a041ad 100644 --- a/docs/Reader.html +++ b/docs/Reader.html @@ -154,7 +154,7 @@
    Parameters:
    @@ -238,52 +238,49 @@

    Home

    Classes

    Events

    diff --git a/docs/Redis.html b/docs/Redis.html index 2a891a667..a90d4965b 100644 --- a/docs/Redis.html +++ b/docs/Redis.html @@ -35,7 +35,7 @@

    Class: Redis

    Redis(settingsopt) → {Redis}

    -
    Connect and subscribe to ZeroMQ servers.
    +
    Connect and subscribe to Redis servers.
    @@ -58,7 +58,7 @@

    new Redis - Creates an instance of a ZeroMQ subscriber. + Creates an instance of a Redis subscriber. @@ -209,7 +209,7 @@
    Properties
    - Remote ZeroMQ service port. + Remote Redis service port. @@ -259,7 +259,7 @@
    Properties
    @@ -579,52 +579,49 @@

    Home

    Classes

    Events

    diff --git a/docs/Remote.html b/docs/Remote.html index 8f1c09931..2ede9b3e0 100644 --- a/docs/Remote.html +++ b/docs/Remote.html @@ -35,7 +35,9 @@

    Class: Remote

    Remote(target)

    -
    Interact with a remote Resource.
    +
    Interact with a remote Resource. This is currently the only + HTTP-related code that should remain in @fabric/core — all else must + be moved to @fabric/http before final release!
    @@ -300,7 +302,7 @@
    Properties:
    @@ -484,7 +486,7 @@
    Parameters:
    @@ -544,7 +546,7 @@
    Returns:
    -

    (async) _GET(path, params) → {Mixed}

    +

    (async) _GET(path, params) → {FabricHTTPResult|String}

    @@ -670,7 +672,7 @@
    Parameters:
    @@ -701,7 +703,7 @@
    Returns:
    - [description] + Result of request.
    @@ -712,7 +714,10 @@
    Returns:
    - Mixed + FabricHTTPResult + | + + String
    @@ -856,7 +861,7 @@
    Parameters:
    @@ -1042,7 +1047,7 @@
    Parameters:
    @@ -1102,7 +1107,7 @@
    Returns:
    -

    (async) _POST(path, params) → {Mixed}

    +

    (async) _POST(path, params) → {FabricHTTPResult|String}

    @@ -1228,7 +1233,7 @@
    Parameters:
    @@ -1270,7 +1275,10 @@
    Returns:
    - Mixed + FabricHTTPResult + | + + String
    @@ -1288,7 +1296,7 @@
    Returns:
    -

    (async) _PUT(path, body) → {Mixed}

    +

    (async) _PUT(path, body) → {FabricHTTPResult|String}

    @@ -1414,7 +1422,7 @@
    Parameters:
    @@ -1445,7 +1453,7 @@
    Returns:
    - [description] + Result of request.
    @@ -1456,7 +1464,10 @@
    Returns:
    - Mixed + FabricHTTPResult + | + + String
    @@ -1528,7 +1539,7 @@

    (async) enum
    @@ -1558,6 +1569,10 @@

    (async) enum

    Returns:
    +
    + An object with enumerable key/value pairs for the Application Resource Contract. +
    +
    @@ -1584,6 +1599,239 @@
    Returns:
    +

    (async) request(type, path, paramsopt) → {FabricHTTPResult}

    + + + + + + +
    + Make an HTTP request to the configured authority. +
    + + + + + + + + + +
    Parameters:
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    NameTypeAttributesDescription
    type + + + String + + + + + + + + + + One of `GET`, `PUT`, `POST`, `DELETE`, or `OPTIONS`.
    path + + + String + + + + + + + + + + The path to request from the authority.
    params + + + Object + + + + + + <optional>
    + + + + + +
    Options.
    + + + + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Source:
    +
    + +
    + + + + + + + +
    + + + + + + + + + + + + + + + +
    Returns:
    + + + + +
    +
    + Type +
    +
    + + FabricHTTPResult + + +
    +
    + + + + + + + + + + + + + @@ -1596,47 +1844,50 @@

    Home

    Classes

    Events

    Events

    diff --git a/docs/Scribe.html b/docs/Scribe.html index 53b5c1114..605a5c31a 100644 --- a/docs/Scribe.html +++ b/docs/Scribe.html @@ -33,3188 +33,51 @@

    Class: Scribe

    -

    Scribe(config)

    - -
    Simple tag-based recordkeeper.
    - - -
    - -
    -
    - - - - -

    Constructor

    - - - -

    new Scribe(config)

    - - - - - - -
    - The "Scribe" is a simple tag-based recordkeeper. -
    - - - - - - - - - -
    Parameters:
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    NameTypeDescription
    config - - - Object - - - - General configuration object. -
    Properties
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    NameTypeDescription
    verbose - - - Boolean - - - - Should the Scribe be noisy?
    - -
    - - - - - - -
    Properties:
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    NameTypeDescription
    config - - - Object - - - - Current configuration.
    - - - - -
    - - - - - - - - - - - - - - - - - - - - - - - - - - -
    Source:
    -
    - -
    - - - - - - - -
    - - - - - - - - - - - - - - - - - - - - - -
    - - -

    Extends

    - - - - - - - - - - - - - - - - - - - - - - -

    Methods

    - - - - - - - -

    commit()

    - - - - - - -
    - Increment the vector clock, broadcast all changes as a transaction. -
    - - - - - - - - - - - - - -
    - - - - - - - - -
    Overrides:
    -
    - -
    - - - - - - - - - - - - - - - - - - - -
    Source:
    -
    - -
    - - - - - - - -
    - - - - - - - - - - - - - - - - - - - - - - - - - - -

    deserialize(input) → {State}

    - - - - - - -
    - Take a hex-encoded input and convert to a State object. -
    - - - - - - - - - -
    Parameters:
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    NameTypeDescription
    input - - - String - - - - [description]
    - - - - - - -
    - - - - - - - - -
    Overrides:
    -
    - -
    - - - - - - - - - - - - - - - - - - - -
    Source:
    -
    - -
    - - - - - - - -
    - - - - - - - - - - - - - - - -
    Returns:
    - - -
    - [description] -
    - - - -
    -
    - Type -
    -
    - - State - - -
    -
    - - - - - - - - - - - - - -

    fork() → {State}

    - - - - - - -
    - Creates a new child State, with `@parent` set to - the current State by immutable identifier. -
    - - - - - - - - - - - - - -
    - - - - - - - - -
    Overrides:
    -
    - -
    - - - - - - - - - - - - - - - - - - - -
    Source:
    -
    - -
    - - - - - - - -
    - - - - - - - - - - - - - - - -
    Returns:
    - - - - -
    -
    - Type -
    -
    - - State - - -
    -
    - - - - - - - - - - - - - -

    get(path) → {Mixed}

    - - - - - - -
    - Retrieve a key from the State. -
    - - - - - - - - - -
    Parameters:
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    NameTypeDescription
    path - - - Path - - - - Key to retrieve.
    - - - - - - -
    - - - - - - - - -
    Overrides:
    -
    - -
    - - - - - - - - - - - - - - - - - - - -
    Source:
    -
    - -
    - - - - - - - -
    - - - - - - - - - - - - - - - -
    Returns:
    - - - - -
    -
    - Type -
    -
    - - Mixed - - -
    -
    - - - - - - - - - - - - - -

    inherits(scribe) → {Scribe}

    - - - - - - -
    - Use an existing Scribe instance as a parent. -
    - - - - - - - - - -
    Parameters:
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    NameTypeDescription
    scribe - - - Scribe - - - - Instance of Scribe to use as parent.
    - - - - - - -
    - - - - - - - - - - - - - - - - - - - - - - - - - - -
    Source:
    -
    - -
    - - - - - - - -
    - - - - - - - - - - - - - - - -
    Returns:
    - - -
    - The configured instance of the Scribe. -
    - - - -
    -
    - Type -
    -
    - - Scribe - - -
    -
    - - - - - - - - - - - - - -

    now() → {Number}

    - - - - - - -
    - Retrives the current timestamp, in milliseconds. -
    - - - - - - - - - - - - - -
    - - - - - - - - - - - - - - - - - - - - - - - - - - -
    Source:
    -
    - -
    - - - - - - - -
    - - - - - - - - - - - - - - - -
    Returns:
    - - -
    - Number representation of the millisecond Integer value. -
    - - - -
    -
    - Type -
    -
    - - Number - - -
    -
    - - - - - - - - - - - - - -

    render() → {String}

    - - - - - - -
    - Compose a JSON string for network consumption. -
    - - - - - - - - - - - - - -
    - - - - - - - - -
    Overrides:
    -
    - -
    - - - - - - - - - - - - - - - - - - - -
    Source:
    -
    - -
    - - - - - - - -
    - - - - - - - - - - - - - - - -
    Returns:
    - - -
    - JSON-encoded String. -
    - - - -
    -
    - Type -
    -
    - - String - - -
    -
    - - - - - - - - - - - - - -

    serialize(inputopt) → {Buffer}

    - - - - - - -
    - Convert to Buffer. -
    - - - - - - - - - -
    Parameters:
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    NameTypeAttributesDescription
    input - - - Mixed - - - - - - <optional>
    - - - - - -
    Input to serialize.
    - - - - - - -
    - - - - - - - - -
    Overrides:
    -
    - -
    - - - - - - - - - - - - - - - - - - - -
    Source:
    -
    - -
    - - - - - - - -
    - - - - - - - - - - - - - - - -
    Returns:
    - - -
    - Store-able blob. -
    - - - -
    -
    - Type -
    -
    - - Buffer - - -
    -
    - - - - - - - - - - - - - -

    set(path) → {Mixed}

    - - - - - - -
    - Set a key in the State to a particular value. -
    - - - - - - - - - -
    Parameters:
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    NameTypeDescription
    path - - - Path - - - - Key to retrieve.
    - - - - - - -
    - - - - - - - - -
    Overrides:
    -
    - -
    - - - - - - - - - - - - - - - - - - - -
    Source:
    -
    - -
    - - - - - - - -
    - - - - - - - - - - - - - - - -
    Returns:
    - - - - -
    -
    - Type -
    -
    - - Mixed - - -
    -
    - - - - - - - - - - - - - -

    toHTML()

    - - - - - - -
    - Converts the State to an HTML document. -
    - - - - - - - - - - - - - -
    - - - - - - - - -
    Overrides:
    -
    - -
    - - - - - - - - - - - - - - - - - - - -
    Source:
    -
    - -
    - - - - - - - -
    - - - - - - - - - - - - - - - - - - - - - - - - - - -

    toString() → {String}

    - - - - - - -
    - Unmarshall an existing state to an instance of a Blob. -
    - - - - - - - - - - - - - -
    - - - - - - - - -
    Overrides:
    -
    - -
    - - - - - - - - - - - - - - - - - - - -
    Source:
    -
    - -
    - - - - - - - -
    - - - - - - - - - - - - - - - -
    Returns:
    - - -
    - Serialized Blob. -
    - - - -
    -
    - Type -
    -
    - - String - - -
    -
    - - - - - - - - - - - - - -

    trust(source) → {Scribe}

    - - - - - - -
    - Blindly bind event handlers to the Source. -
    - - - - - - - - - -
    Parameters:
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    NameTypeDescription
    source - - - Source - - - - Event stream.
    - - - - - - -
    - - - - - - - - - - - - - - - - - - - - - - - - - - -
    Source:
    -
    - -
    - - - - - - - -
    - - - - - - - - - - - - - - - -
    Returns:
    - - -
    - Instance of the Scribe. -
    - - - -
    -
    - Type -
    -
    - - Scribe - - -
    -
    - - - - - - - - - - - - - -
    - - - - - - - - - -
    - -
    - -

    Scribe()

    - -
    Deprecated 2021-11-06.
    - - -
    - -
    -
    - - - - -

    Constructor

    - - - -

    new Scribe()

    - - - - - - - - - - - - - - - - - - -
    - - - - - - - - - - - - - - - - -
    Deprecated:
    -
    -
      -
    • Yes
    • -
    -
    - - - - - - - - - - - -
    Source:
    -
    - -
    - - - - - - - -
    - - - - - - - - - - - - - - - - - - - - - -
    - - - - - - - - - - - - - - - - -

    Methods

    - - - - - - - -

    commit()

    - - - - - - -
    - Increment the vector clock, broadcast all changes as a transaction. -
    - - - - - - - - - - - - - -
    - - - - - - - - -
    Overrides:
    -
    - -
    - - - - - - - - - - - - - - - - - - - -
    Source:
    -
    - -
    - - - - - - - -
    - - - - - - - - - - - - - - - - - - - - - - - - - - -

    deserialize(input) → {State}

    - - - - - - -
    - Take a hex-encoded input and convert to a State object. -
    - - - - - - - - - -
    Parameters:
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    NameTypeDescription
    input - - - String - - - - [description]
    - - - - - - -
    - - - - - - - - -
    Overrides:
    -
    - -
    - - - - - - - - - - - - - - - - - - - -
    Source:
    -
    - -
    - - - - - - - -
    - - - - - - - - - - - - - - - -
    Returns:
    - - -
    - [description] -
    - - - -
    -
    - Type -
    -
    - - State - - -
    -
    - - - - - - - - - - - - - -

    fork() → {State}

    - - - - - - -
    - Creates a new child State, with `@parent` set to - the current State by immutable identifier. -
    - - - - - - - - - - - - - -
    - - - - - - - - -
    Overrides:
    -
    - -
    - - - - - - - - - - - - - - - - - - - -
    Source:
    -
    - -
    - - - - - - - -
    - - - - - - - - - - - - - - - -
    Returns:
    - - - - -
    -
    - Type -
    -
    - - State - - -
    -
    - - - - - - - - - - - - - -

    get(path) → {Mixed}

    - - - - - - -
    - Retrieve a key from the State. -
    - - - - - - - - - -
    Parameters:
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    NameTypeDescription
    path - - - Path - - - - Key to retrieve.
    - - - - - - -
    - - - - - - - - -
    Overrides:
    -
    - -
    - - - - - - - - - - - - - - - - - - - -
    Source:
    -
    - -
    - - - - - - - -
    - - - - - - - - - - - - - - - -
    Returns:
    - - - - -
    -
    - Type -
    -
    - - Mixed - - -
    -
    - - - - - - - - - - - - - -

    inherits(scribe) → {Scribe}

    - - - - - - -
    - Use an existing Scribe instance as a parent. -
    - - - - - - - - - -
    Parameters:
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    NameTypeDescription
    scribe - - - Scribe - - - - Instance of Scribe to use as parent.
    - - - - - - -
    - - - - - - - - - - - - - - - - - - - - - - - - - - -
    Source:
    -
    - -
    - - - - - - - -
    - - - - - - - - - - - - - - - -
    Returns:
    - - -
    - The configured instance of the Scribe. -
    - - - -
    -
    - Type -
    -
    - - Scribe - - -
    -
    - - - - - - - - - - - - - -

    now() → {Number}

    - - - - - - -
    - Retrives the current timestamp, in milliseconds. -
    - - - - - - - - - - - - - -
    - - - - - - - - - - - - - - - - - - - - - - - - - - -
    Source:
    -
    - -
    - - - - - - - -
    - - - - - - - - - - - - - - - -
    Returns:
    - - -
    - Number representation of the millisecond Integer value. -
    - - - -
    -
    - Type -
    -
    - - Number - - -
    -
    - - - - - - - - - - - - - -

    render() → {String}

    - - - - - - -
    - Compose a JSON string for network consumption. -
    - - - - - - - - - - - - - -
    - - - - - - - - -
    Overrides:
    -
    - -
    - - - - - - - - - - - - - - - - - - - -
    Source:
    -
    - -
    - - - - - - - -
    - - - - - - - - - - - - - - - -
    Returns:
    - - -
    - JSON-encoded String. -
    - - - -
    -
    - Type -
    -
    - - String - - -
    -
    - - - - - - - - - - - - - -

    serialize(inputopt) → {Buffer}

    - - - - - - -
    - Convert to Buffer. -
    - - - - - - - - - -
    Parameters:
    - - - - - - - - - - +

    Scribe()

    +
    Deprecated 2021-11-06.
    - + +
    +
    -
    - - - +

    Constructor

    - - +

    new Scribe()

    - - - - +
    -
    -
    NameTypeAttributesDescription
    input - Mixed - - <optional>
    -
    Input to serialize.
    -
    @@ -3223,14 +86,12 @@
    Parameters:
    -
    Overrides:
    -
    - -
    +
    Deprecated:
    +
    +
      +
    • Yes
    • +
    +
    @@ -3242,6 +103,14 @@
    Parameters:
    +
    Source:
    +
    + +
    @@ -3249,15 +118,8 @@
    Parameters:
    +
    -
    Source:
    -
    - -
    @@ -3265,7 +127,6 @@
    Parameters:
    -
    @@ -3279,34 +140,24 @@
    Parameters:
    + -
    Returns:
    -
    - Store-able blob. -
    -
    -
    - Type -
    -
    - Buffer -
    -
    +

    Methods

    @@ -3314,7 +165,7 @@
    Returns:
    -

    set(path) → {Mixed}

    +

    inherits(scribe) → {Scribe}

    @@ -3322,7 +173,7 @@

    set - Set a key in the State to a particular value. + Use an existing Scribe instance as a parent. @@ -3358,13 +209,13 @@
    Parameters:
    - path + scribe - Path + Scribe @@ -3374,7 +225,7 @@
    Parameters:
    - Key to retrieve. + Instance of Scribe to use as parent. @@ -3395,15 +246,6 @@
    Parameters:
    -
    Overrides:
    -
    - -
    - @@ -3426,7 +268,7 @@
    Parameters:
    @@ -3456,6 +298,10 @@
    Parameters:
    Returns:
    +
    + The configured instance of the Scribe. +
    +
    @@ -3464,98 +310,10 @@
    Returns:
    - Mixed - - -
    -
    - - - - - - - - - - - - - -

    toHTML()

    - - - - - - -
    - Converts the State to an HTML document. -
    - - - - - - - - - - - - - -
    - - - - - - - - -
    Overrides:
    -
    - -
    - - - - - - - - - - - - - - - - - + Scribe -
    Source:
    -
    -
    - - - - - - -
    @@ -3570,20 +328,7 @@

    toHTMLtoString() → {String}

    +

    now() → {Number}

    @@ -3591,7 +336,7 @@

    toString - Unmarshall an existing state to an instance of a Blob. + Retrives the current timestamp, in milliseconds. @@ -3615,15 +360,6 @@

    toStringOverrides: -
    - -
    - @@ -3646,7 +382,7 @@

    toString @@ -3677,7 +413,7 @@
    Returns:
    - Serialized Blob. + Number representation of the millisecond Integer value.
    @@ -3688,7 +424,7 @@
    Returns:
    - String + Number
    @@ -3809,7 +545,7 @@
    Parameters:
    @@ -3881,52 +617,49 @@

    Home

    Classes

    Events

    diff --git a/docs/Script.html b/docs/Script.html index 881fa7ab7..d40ec584e 100644 --- a/docs/Script.html +++ b/docs/Script.html @@ -54,7 +54,7 @@

    new Script - Compose a Script for inclusion within a Contract. + Compose a Script for inclusion within a Contract. @@ -237,52 +237,49 @@

    Home

    Classes

    Events

    diff --git a/docs/Service.html b/docs/Service.html index f4cebaf4d..a1d08909d 100644 --- a/docs/Service.html +++ b/docs/Service.html @@ -33,7 +33,7 @@

    Class: Service

    -

    (protected) Service(settings)

    +

    (protected) Service(settingsopt)

    The "Service" is a simple model for processing messages in a distributed system. Service instances are public interfaces for outside systems, @@ -57,7 +57,7 @@

    Constructor

    -

    (protected) new Service(settings)

    +

    (protected) new Service(settingsopt)

    @@ -89,6 +89,8 @@
    Parameters:
    Type + Attributes + @@ -114,6 +116,16 @@
    Parameters:
    + + + <optional>
    + + + + + + + @@ -186,7 +198,7 @@
    Properties
    - @data + frequency @@ -216,7 +228,44 @@
    Properties
    - Internal data to assign. + Interval frequency in hertz. + + + + + + + state + + + + + + Object + + + + + + + + + <optional>
    + + + + + + + + + + + + + + + Initial state to assign. @@ -313,7 +362,7 @@
    Properties:
    @@ -474,7 +523,7 @@
    Parameters:
    @@ -727,7 +776,7 @@
    Parameters:
    @@ -890,7 +939,7 @@
    Parameters:
    @@ -1053,7 +1102,99 @@
    Parameters:
    +
    + + + + + + + +

    + + + + + + + + + + + + + + + + + + + + + + + + + + +

    beat() → {Service}

    + + + + + + +
    + Compute latest state. +
    + + + + + + + + + + + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Source:
    +
    +
    @@ -1070,14 +1211,37 @@
    Parameters:
    +
    Fires:
    +
      +
    • Message#event:beat
    • +
    + + + + + + +
    Returns:
    + + + + +
    +
    + Type +
    +
    + Service +
    +
    @@ -1202,7 +1366,7 @@
    Parameters:
    @@ -1365,7 +1529,7 @@
    Parameters:
    @@ -1395,6 +1559,10 @@
    Parameters:
    Returns:
    +
    + Returns the target value if found, otherwise null. +
    +
    @@ -1525,7 +1693,7 @@
    Parameters:
    @@ -1640,7 +1808,7 @@

    init @@ -1801,7 +1969,7 @@
    Parameters:
    @@ -1964,7 +2132,7 @@
    Parameters:
    @@ -2150,7 +2318,7 @@
    Parameters:
    @@ -2313,7 +2481,7 @@
    Parameters:
    @@ -2424,7 +2592,7 @@

    (async) start @@ -2516,7 +2684,7 @@

    tick @@ -2675,7 +2843,7 @@
    Parameters:
    @@ -2735,6 +2903,192 @@
    Returns:
    +

    when(event, method) → {EventEmitter}

    + + + + + + +
    + Bind a method to an event, with current state as the immutable context. +
    + + + + + + + + + +
    Parameters:
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    NameTypeDescription
    event + + + String + + + + Name of the event upon which to execute `method` as a function.
    method + + + function + + + + Function to execute when named Event `event` is encountered.
    + + + + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Source:
    +
    + +
    + + + + + + + +
    + + + + + + + + + + + + + + + +
    Returns:
    + + +
    + Instance of EventEmitter. +
    + + + +
    +
    + Type +
    +
    + + EventEmitter + + +
    +
    + + + + + + + + + + + + + @@ -2747,52 +3101,49 @@

    Home

    Classes

    Events

    diff --git a/docs/Session.html b/docs/Session.html index 69ab7d519..218204c07 100644 --- a/docs/Session.html +++ b/docs/Session.html @@ -154,7 +154,7 @@
    Parameters:
    @@ -266,7 +266,7 @@

    (async) start @@ -358,7 +358,7 @@

    (async) stop @@ -408,52 +408,49 @@

    Home

    Classes

    Events

    diff --git a/docs/Signer.html b/docs/Signer.html index 6968ff799..59af5224e 100644 --- a/docs/Signer.html +++ b/docs/Signer.html @@ -370,7 +370,7 @@
    Properties:
    @@ -433,6 +433,17 @@
    Returns:
    +

    Extends

    + + + + + + + + @@ -455,7 +466,7 @@

    Methods

    -

    sign() → {Signer}

    +

    _readObject(input) → {Object}

    @@ -463,7 +474,7 @@

    sign - Signs some data. + Parse an Object into a corresponding Fabric state. @@ -474,6 +485,55 @@

    sign + + + + Name + + + Type + + + + + + Description + + + + + + + + + input + + + + + + Object + + + + + + + + + + Object to read as input. + + + + + + + @@ -487,6 +547,15 @@

    signOverrides: +
    + +
    + @@ -509,7 +578,7 @@

    sign @@ -539,6 +608,10 @@

    sign + Fabric state. + +
    @@ -547,7 +620,1841 @@
    Returns:
    - Signer + Object + + +
    +
    + + + + + + + + + + + + + +

    adopt(changes) → {Actor}

    + + + + + + +
    + Explicitly adopt a set of JSONPatch-encoded changes. +
    + + + + + + + + + +
    Parameters:
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    NameTypeDescription
    changes + + + Array + + + + List of JSONPatch operations to apply.
    + + + + + + +
    + + + + + + + + +
    Overrides:
    +
    + +
    + + + + + + + + + + + + + + + + + + + +
    Source:
    +
    + +
    + + + + + + + +
    + + + + + + + + + + + + + + + +
    Returns:
    + + +
    + Instance of the Actor. +
    + + + +
    +
    + Type +
    +
    + + Actor + + +
    +
    + + + + + + + + + + + + + +

    commit() → {String}

    + + + + + + +
    + Resolve the current state to a commitment. +
    + + + + + + + + + + + + + +
    + + + + + + + + +
    Overrides:
    +
    + +
    + + + + + + + + + + + + + + + + + + + +
    Source:
    +
    + +
    + + + + + + + +
    + + + + + + + + + + + + + + + +
    Returns:
    + + +
    + 32-byte ID +
    + + + +
    +
    + Type +
    +
    + + String + + +
    +
    + + + + + + + + + + + + + +

    export() → {Object}

    + + + + + + +
    + Export the Actor's state to a standard Object. +
    + + + + + + + + + + + + + +
    + + + + + + + + +
    Overrides:
    +
    + +
    + + + + + + + + + + + + + + + + + + + +
    Source:
    +
    + +
    + + + + + + + +
    + + + + + + + + + + + + + + + +
    Returns:
    + + +
    + Standard object. +
    + + + +
    +
    + Type +
    +
    + + Object + + +
    +
    + + + + + + + + + + + + + +

    get(path) → {Object}

    + + + + + + +
    + Retrieve a value from the Actor's state by JSONPointer path. +
    + + + + + + + + + +
    Parameters:
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    NameTypeDescription
    path + + + String + + + + Path to retrieve using JSONPointer.
    + + + + + + +
    + + + + + + + + +
    Overrides:
    +
    + +
    + + + + + + + + + + + + + + + + + + + +
    Source:
    +
    + +
    + + + + + + + +
    + + + + + + + + + + + + + + + +
    Returns:
    + + +
    + Value of the path in the Actor's state. +
    + + + +
    +
    + Type +
    +
    + + Object + + +
    +
    + + + + + + + + + + + + + +

    pause() → {Actor}

    + + + + + + +
    + Toggles `status` property to paused. +
    + + + + + + + + + + + + + +
    + + + + + + + + +
    Overrides:
    +
    + +
    + + + + + + + + + + + + + + + + + + + +
    Source:
    +
    + +
    + + + + + + + +
    + + + + + + + + + + + + + + + +
    Returns:
    + + +
    + Instance of the Actor. +
    + + + +
    +
    + Type +
    +
    + + Actor + + +
    +
    + + + + + + + + + + + + + +

    serialize() → {String}

    + + + + + + +
    + Serialize the Actor's current state into a JSON-formatted string. +
    + + + + + + + + + + + + + +
    + + + + + + + + +
    Overrides:
    +
    + +
    + + + + + + + + + + + + + + + + + + + +
    Source:
    +
    + +
    + + + + + + + +
    + + + + + + + + + + + + + + + +
    Returns:
    + + + + +
    +
    + Type +
    +
    + + String + + +
    +
    + + + + + + + + + + + + + +

    set(path, value) → {Object}

    + + + + + + +
    + Set a value in the Actor's state by JSONPointer path. +
    + + + + + + + + + +
    Parameters:
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    NameTypeDescription
    path + + + String + + + + Path to set using JSONPointer.
    value + + + Object + + + + Value to set.
    + + + + + + +
    + + + + + + + + +
    Overrides:
    +
    + +
    + + + + + + + + + + + + + + + + + + + +
    Source:
    +
    + +
    + + + + + + + +
    + + + + + + + + + + + + + + + +
    Returns:
    + + +
    + Value of the path in the Actor's state. +
    + + + +
    +
    + Type +
    +
    + + Object + + +
    +
    + + + + + + + + + + + + + +

    sign() → {Signer}

    + + + + + + +
    + Signs some data. +
    + + + + + + + + + + + + + +
    + + + + + + + + +
    Overrides:
    +
    + +
    + + + + + + + + + + + + + + + + + + + +
    Source:
    +
    + +
    + + + + + + + +
    + + + + + + + + + + + + + + + +
    Returns:
    + + + + +
    +
    + Type +
    +
    + + Signer + + +
    +
    + + + + + + + + + + + + + +

    toBuffer() → {Buffer}

    + + + + + + +
    + Casts the Actor to a normalized Buffer. +
    + + + + + + + + + + + + + +
    + + + + + + + + +
    Overrides:
    +
    + +
    + + + + + + + + + + + + + + + + + + + +
    Source:
    +
    + +
    + + + + + + + +
    + + + + + + + + + + + + + + + +
    Returns:
    + + + + +
    +
    + Type +
    +
    + + Buffer + + +
    +
    + + + + + + + + + + + + + +

    toGenericMessage() → {Object}

    + + + + + + +
    + Casts the Actor to a generic message, used to uniquely identify the Actor's state. + Fields: + - `type`: 'FabricActorState' + - `object`: state +
    + + + + + + + + + + + + + +
    + + + + + + + + +
    Overrides:
    +
    + +
    + + + + + + + + + + + + + + + + + + + +
    Source:
    +
    + +
    + + + + + +
    See:
    +
    + +
    + + + +
    + + + + + + + + + + + + + + + +
    Returns:
    + + +
    + Generic message object. +
    + + + +
    +
    + Type +
    +
    + + Object + + +
    +
    + + + + + + + + + + + + + +

    toObject() → {Object}

    + + + + + + +
    + Returns the Actor's current state as an Object. +
    + + + + + + + + + + + + + +
    + + + + + + + + +
    Overrides:
    +
    + +
    + + + + + + + + + + + + + + + + + + + +
    Source:
    +
    + +
    + + + + + + + +
    + + + + + + + + + + + + + + + +
    Returns:
    + + + + +
    +
    + Type +
    +
    + + Object + + +
    +
    + + + + + + + + + + + + + +

    unpause() → {Actor}

    + + + + + + +
    + Toggles `status` property to unpaused. +
    + + + + + + + + + + + + + +
    + + + + + + + + +
    Overrides:
    +
    + +
    + + + + + + + + + + + + + + + + + + + +
    Source:
    +
    + +
    + + + + + + + +
    + + + + + + + + + + + + + + + +
    Returns:
    + + +
    + Instance of the Actor. +
    + + + +
    +
    + Type +
    +
    + + Actor + + +
    +
    + + + + + + + + + + + + + +

    value(formatopt) → {Object}

    + + + + + + +
    + Get the inner value of the Actor with an optional cast type. +
    + + + + + + + + + +
    Parameters:
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    NameTypeAttributesDefaultDescription
    format + + + String + + + + + + <optional>
    + + + + + +
    + + object + + Cast the value to one of: `buffer, hex, json, string`
    + + + + + + +
    + + + + + + + + +
    Overrides:
    +
    + +
    + + + + + + + + + + + + + + + + + + + +
    Source:
    +
    + +
    + + + + + + + +
    + + + + + + + + + + + + + + + +
    Returns:
    + + +
    + Inner value of the Actor as an Object, or cast to the requested `format`. +
    + + + +
    +
    + Type +
    +
    + + Object
    @@ -577,34 +2484,32 @@

    Home

    Classes

    Events

    diff --git a/docs/Snapshot.html b/docs/Snapshot.html index c011f2f1d..b9ac8a842 100644 --- a/docs/Snapshot.html +++ b/docs/Snapshot.html @@ -153,7 +153,7 @@
    Parameters:
    @@ -315,52 +315,49 @@

    Home

    Classes

    Events

    diff --git a/docs/Stack.html b/docs/Stack.html index 549960b18..05afe7fdb 100644 --- a/docs/Stack.html +++ b/docs/Stack.html @@ -173,7 +173,7 @@
    Parameters:
    @@ -429,52 +429,49 @@

    Home

    Classes

    Events

    diff --git a/docs/Stash.html b/docs/Stash.html index 1f3e79c7d..8ff571a0d 100644 --- a/docs/Stash.html +++ b/docs/Stash.html @@ -173,52 +173,49 @@

    Home

    Classes

    Events

    diff --git a/docs/State.html b/docs/State.html index 86e4c4f01..94e666ebf 100644 --- a/docs/State.html +++ b/docs/State.html @@ -299,7 +299,7 @@
    Properties:
    @@ -390,170 +390,6 @@

    Methods

    -

    (static) fromJSON(input) → {State}

    - - - - - - -
    - Marshall an input into an instance of a State. States have - absolute authority over their own domain, so choose your States wisely. -
    - - - - - - - - - -
    Parameters:
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    NameTypeDescription
    input - - - String - - - - Arbitrary input.
    - - - - - - -
    - - - - - - - - - - - - - - - - - - - - - - - - - - -
    Source:
    -
    - -
    - - - - - - - -
    - - - - - - - - - - - - - - - -
    Returns:
    - - -
    - Resulting instance of the State. -
    - - - -
    -
    - Type -
    -
    - - State - - -
    -
    - - - - - - - - - - - - -

    commit()

    @@ -1733,6 +1569,170 @@
    Returns:
    +

    (static) fromJSON(input) → {State}

    + + + + + + +
    + Marshall an input into an instance of a State. States have + absolute authority over their own domain, so choose your States wisely. +
    + + + + + + + + + +
    Parameters:
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    NameTypeDescription
    input + + + String + + + + Arbitrary input.
    + + + + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Source:
    +
    + +
    + + + + + + + +
    + + + + + + + + + + + + + + + +
    Returns:
    + + +
    + Resulting instance of the State. +
    + + + +
    +
    + Type +
    +
    + + State + + +
    +
    + + + + + + + + + + + + + @@ -1745,52 +1745,49 @@

    Home

    Classes

    Events

    diff --git a/docs/Store.html b/docs/Store.html index a49fd3dd2..874f84b1d 100644 --- a/docs/Store.html +++ b/docs/Store.html @@ -226,7 +226,7 @@
    Properties:
    @@ -758,7 +758,7 @@
    Parameters:
    @@ -850,7 +850,7 @@

    (async) flush @@ -1269,7 +1269,7 @@

    (async) start @@ -1504,52 +1504,49 @@

    Home

    Classes

    Events

    diff --git a/docs/Swap.html b/docs/Swap.html index 33fd01850..ae9f9098c 100644 --- a/docs/Swap.html +++ b/docs/Swap.html @@ -176,7 +176,7 @@
    Parameters:
    @@ -438,19 +438,27 @@

    Classes

  • Bitcoin
  • Chain
  • Channel
  • +
  • Circuit
  • CLI
  • Collection
  • Compiler
  • Consensus
  • Entity
  • +
  • Environment
  • Exchange
  • Fabric
  • +
  • Federation
  • +
  • Filesystem
  • Hash256
  • HKDF
  • HTTPServer
  • +
  • Identity
  • Interface
  • Key
  • -
  • KeyStore
  • +
  • Keystore
  • +
  • Ledger
  • +
  • Lightning
  • +
  • Logger
  • Machine
  • Mempool
  • Message
  • @@ -460,6 +468,8 @@

    Classes

  • Peer
  • Reader
  • Redis
  • +
  • Remote
  • +
  • Resource
  • Router
  • Scribe
  • Script
  • @@ -479,6 +489,7 @@

    Classes

  • Vector
  • Walker
  • Wallet
  • +
  • Worker
  • ZMQ
  • Events

    diff --git a/docs/Swarm.html b/docs/Swarm.html index 048eb88cd..657518499 100644 --- a/docs/Swarm.html +++ b/docs/Swarm.html @@ -153,7 +153,7 @@
    Parameters:
    @@ -502,52 +502,49 @@

    Home

    Classes

    Events

    diff --git a/docs/Token.html b/docs/Token.html new file mode 100644 index 000000000..49879596f --- /dev/null +++ b/docs/Token.html @@ -0,0 +1,314 @@ + + + + + + Class: Token · Docs + + + + + + + + + +
    +

    Class: Token

    + + + + +
    + +
    + +

    Token(settingsopt) → {Token}

    + +
    Implements a capability-based security token.
    + + +
    + +
    +
    + + + + +

    Constructor

    + + + +

    new Token(settingsopt) → {Token}

    + + + + + + +
    + Create a new Fabric Token. +
    + + + + + + + + + +
    Parameters:
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    NameTypeAttributesDescription
    settings + + + Object + + + + + + <optional>
    + + + + + +
    Configuration.
    + + + + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Source:
    +
    + +
    + + + + + + + +
    + + + + + + + + + + + + + + + +
    Returns:
    + + +
    + The token instance. +
    + + + +
    +
    + Type +
    +
    + + Token + + +
    +
    + + + + + + + + +
    + + + + + + + + + + + + + + + + + + + + +
    + +
    + + + +
    + +
    + + + + + + \ No newline at end of file diff --git a/docs/Transition.html b/docs/Transition.html index 93355d0a5..3263faa64 100644 --- a/docs/Transition.html +++ b/docs/Transition.html @@ -151,7 +151,7 @@
    Parameters:
    @@ -222,19 +222,27 @@

    Classes

  • Bitcoin
  • Chain
  • Channel
  • +
  • Circuit
  • CLI
  • Collection
  • Compiler
  • Consensus
  • Entity
  • +
  • Environment
  • Exchange
  • Fabric
  • +
  • Federation
  • +
  • Filesystem
  • Hash256
  • HKDF
  • HTTPServer
  • +
  • Identity
  • Interface
  • Key
  • -
  • KeyStore
  • +
  • Keystore
  • +
  • Ledger
  • +
  • Lightning
  • +
  • Logger
  • Machine
  • Mempool
  • Message
  • @@ -244,6 +252,8 @@

    Classes

  • Peer
  • Reader
  • Redis
  • +
  • Remote
  • +
  • Resource
  • Router
  • Scribe
  • Script
  • @@ -263,6 +273,7 @@

    Classes

  • Vector
  • Walker
  • Wallet
  • +
  • Worker
  • ZMQ
  • Events

    diff --git a/docs/Tree.html b/docs/Tree.html index d830da679..2e79fa95b 100644 --- a/docs/Tree.html +++ b/docs/Tree.html @@ -165,7 +165,7 @@
    Parameters:
    @@ -195,6 +195,10 @@
    Parameters:
    Returns:
    +
    + Instance of the tree. +
    +
    @@ -344,7 +348,7 @@
    Parameters:
    @@ -374,6 +378,10 @@
    Parameters:
    Returns:
    +
    + Instance of the tree. +
    +
    @@ -454,7 +462,7 @@

    getLeaves @@ -526,52 +534,49 @@

    Home

    Classes

    Events

    diff --git a/docs/Value.html b/docs/Value.html index 1ae4af26b..5b6ddd74f 100644 --- a/docs/Value.html +++ b/docs/Value.html @@ -153,7 +153,7 @@
    Parameters:
    @@ -364,52 +364,49 @@

    Home

    Classes

    Events

    diff --git a/docs/Vector.html b/docs/Vector.html index e0e0e4c16..8c0341c3f 100644 --- a/docs/Vector.html +++ b/docs/Vector.html @@ -541,52 +541,49 @@

    Home

    Classes

    Events

    diff --git a/docs/Walker.html b/docs/Walker.html index 4285d52c2..596d19ea1 100644 --- a/docs/Walker.html +++ b/docs/Walker.html @@ -655,52 +655,49 @@

    Home

    Classes

    Events

    diff --git a/docs/Wallet.html b/docs/Wallet.html index abb576851..1ed381e51 100644 --- a/docs/Wallet.html +++ b/docs/Wallet.html @@ -392,7 +392,7 @@
    Properties:
    @@ -575,7 +575,7 @@
    Parameters:
    @@ -716,7 +716,7 @@
    Parameters:
    @@ -880,7 +880,7 @@
    Parameters:
    @@ -918,7 +918,7 @@
    Parameters:
    -

    (async) _load(settings)

    +

    (async) _sign(tx)

    @@ -926,7 +926,7 @@

    (async) _load - Initialize the wallet, including keys and addresses. + Signs a transaction with the keyring. @@ -962,13 +962,13 @@
    Parameters:
    - settings + tx - Object + BcoinTX @@ -978,7 +978,7 @@
    Parameters:
    - Settings to load. + @@ -1021,7 +1021,7 @@
    Parameters:
    @@ -1059,7 +1059,7 @@
    Parameters:
    -

    (async) _sign(tx)

    +

    getAddressForScript(script)

    @@ -1067,7 +1067,7 @@

    (async) _sign - Signs a transaction with the keyring. + Returns a bech32 address for the provided Script. @@ -1103,13 +1103,13 @@
    Parameters:
    - tx + script - BcoinTX + Script @@ -1162,7 +1162,7 @@
    Parameters:
    @@ -1200,7 +1200,7 @@
    Parameters:
    -

    (async) createPricedOrder(order)

    +

    getAddressFromRedeemScript(redeemScript)

    @@ -1208,7 +1208,7 @@

    (async) - Create a priced order. + Generate a BitcoinAddress for the supplied BitcoinScript. @@ -1244,13 +1244,13 @@
    Parameters:
    - order + redeemScript - Object + BitcoinScript @@ -1260,79 +1260,7 @@
    Parameters:
    - -
    Properties
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    NameTypeDescription
    asset - - - Object - - - -
    amount - - - Object - - - -
    - - + @@ -1375,7 +1303,7 @@
    Properties
    @@ -1413,7 +1341,7 @@
    Properties
    -

    getAddressForScript(script)

    +

    publicKeyFromString(input)

    @@ -1421,7 +1349,7 @@

    ge
    - Returns a bech32 address for the provided Script. + Create a public key from a string.
    @@ -1457,13 +1385,13 @@

    Parameters:
    - script + input - Script + String @@ -1473,7 +1401,7 @@
    Parameters:
    - + Hex-encoded string to create key from. @@ -1516,7 +1444,7 @@
    Parameters:
    @@ -1554,7 +1482,7 @@
    Parameters:
    -

    getAddressFromRedeemScript(redeemScript)

    +

    start()

    @@ -1562,7 +1490,7 @@

    - Generate a BitcoinAddress for the supplied BitcoinScript. + Start the wallet, including listening for transactions. @@ -1573,55 +1501,6 @@

    Parameters:

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    NameTypeDescription
    redeemScript - - - BitcoinScript - - - -
    - - @@ -1657,7 +1536,7 @@
    Parameters:
    @@ -1695,7 +1574,7 @@
    Parameters:
    -

    publicKeyFromString(input)

    +

    (static) createSeed(passphrase) → {FabricSeed}

    @@ -1703,7 +1582,7 @@

    pu
    - Create a public key from a string. + Create a new seed phrase.
    @@ -1739,7 +1618,7 @@

    Parameters:
    - input + passphrase @@ -1755,7 +1634,7 @@
    Parameters:
    - Hex-encoded string to create key from. + BIP 39 passphrase for key derivation. @@ -1798,7 +1677,7 @@
    Parameters:
    @@ -1825,6 +1704,28 @@
    Parameters:
    +
    Returns:
    + + +
    + The seed object. +
    + + + +
    +
    + Type +
    +
    + + FabricSeed + + +
    +
    + + @@ -1836,7 +1737,7 @@
    Parameters:
    -

    (async) start()

    +

    (static) fromSeed(seed) → {Wallet}

    @@ -1844,7 +1745,7 @@

    (async) start - Start the wallet, including listening for transactions. + Create a new Wallet from a seed object. @@ -1855,6 +1756,55 @@

    (async) startParameters:

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    NameTypeDescription
    seed + + + FabricSeed + + + + Fabric seed.
    + + @@ -1890,7 +1840,7 @@

    (async) start @@ -1917,6 +1867,28 @@

    (async) startReturns:

    + + +
    + Instance of the wallet. +
    + + + +
    +
    + Type +
    +
    + + Wallet + + +
    +
    + + @@ -1940,52 +1912,49 @@

    Home

    Classes

    Events

    diff --git a/docs/Worker.html b/docs/Worker.html index 589d2d8e3..032dc1835 100644 --- a/docs/Worker.html +++ b/docs/Worker.html @@ -3,8 +3,7 @@ - JSDoc: Class: Worker - + Class: Worker · Docs + -
    -

    Class: Worker

    - -
    -

    Worker(initial)

    +

    Worker(method)

    + +
    Workers are arbitrary containers for processing data. They can be thought of + almost like "threads", as they run asynchronously over the duration of a + contract's lifetime as "fulfillment conditions" for its closure.
    @@ -40,20 +48,16 @@

    WorkerConstructor

    -

    new Worker(initial)

    +

    new Worker(method)

    -
    - Workers are arbitrary containers for processing data. They can be thought of - almost like "threads", as they run asynchronously over the duration of a - contract's lifetime as "fulfillment conditions" for its closure. -
    @@ -88,13 +92,13 @@
    Parameters:
    - initial + method - Object + function @@ -104,7 +108,7 @@
    Parameters:
    - Configuration object + Pure function. @@ -147,7 +151,7 @@
    Parameters:
    @@ -177,6 +181,8 @@
    Parameters:
    + +
    @@ -203,7 +209,7 @@

    Methods

    -

    compute(input) → {String}

    +

    (async) compute(input) → {String}

    @@ -306,7 +312,7 @@
    Parameters:
    @@ -331,6 +337,8 @@
    Parameters:
    + +
    Returns:
    @@ -370,42 +378,68 @@
    Returns:
    - - - -
    - -
    - Documentation generated by JSDoc 3.5.5 on Sun Jan 28 2018 01:45:56 GMT+0000 (GMT) -
    - - - + \ No newline at end of file diff --git a/docs/ZMQ.html b/docs/ZMQ.html index 26e69d606..c2f969d8c 100644 --- a/docs/ZMQ.html +++ b/docs/ZMQ.html @@ -259,7 +259,7 @@
    Properties
    @@ -393,7 +393,7 @@

    (async) start @@ -507,7 +507,7 @@

    (async) stop @@ -579,52 +579,49 @@

    Home

    Classes

    Events

    diff --git a/docs/docco.css b/docs/docco.css new file mode 100644 index 000000000..c3d580fab --- /dev/null +++ b/docs/docco.css @@ -0,0 +1,518 @@ +/*--------------------- Typography ----------------------------*/ + +@font-face { + font-family: 'aller-light'; + src: url('public/fonts/aller-light.eot'); + src: url('public/fonts/aller-light.eot?#iefix') format('embedded-opentype'), + url('public/fonts/aller-light.woff') format('woff'), + url('public/fonts/aller-light.ttf') format('truetype'); + font-weight: normal; + font-style: normal; +} + +@font-face { + font-family: 'aller-bold'; + src: url('public/fonts/aller-bold.eot'); + src: url('public/fonts/aller-bold.eot?#iefix') format('embedded-opentype'), + url('public/fonts/aller-bold.woff') format('woff'), + url('public/fonts/aller-bold.ttf') format('truetype'); + font-weight: normal; + font-style: normal; +} + +@font-face { + font-family: 'roboto-black'; + src: url('public/fonts/roboto-black.eot'); + src: url('public/fonts/roboto-black.eot?#iefix') format('embedded-opentype'), + url('public/fonts/roboto-black.woff') format('woff'), + url('public/fonts/roboto-black.ttf') format('truetype'); + font-weight: normal; + font-style: normal; +} + +/*--------------------- Layout ----------------------------*/ +html { height: 100%; } +body { + font-family: "aller-light"; + font-size: 14px; + line-height: 18px; + color: #30404f; + margin: 0; padding: 0; + height:100%; +} +#container { min-height: 100%; } + +a { + color: #000; +} + +b, strong { + font-weight: normal; + font-family: "aller-bold"; +} + +p { + margin: 15px 0 0px; +} + .annotation ul, .annotation ol { + margin: 25px 0; + } + .annotation ul li, .annotation ol li { + font-size: 14px; + line-height: 18px; + margin: 10px 0; + } + +h1, h2, h3, h4, h5, h6 { + color: #112233; + line-height: 1em; + font-weight: normal; + font-family: "roboto-black"; + text-transform: uppercase; + margin: 30px 0 15px 0; +} + +h1 { + margin-top: 40px; +} +h2 { + font-size: 1.26em; +} + +hr { + border: 0; + background: 1px #ddd; + height: 1px; + margin: 20px 0; +} + +pre, tt, code { + font-size: 12px; line-height: 16px; + font-family: Menlo, Monaco, Consolas, "Lucida Console", monospace; + margin: 0; padding: 0; +} + .annotation pre { + display: block; + margin: 0; + padding: 7px 10px; + background: #fcfcfc; + -moz-box-shadow: inset 0 0 10px rgba(0,0,0,0.1); + -webkit-box-shadow: inset 0 0 10px rgba(0,0,0,0.1); + box-shadow: inset 0 0 10px rgba(0,0,0,0.1); + overflow-x: auto; + } + .annotation pre code { + border: 0; + padding: 0; + background: transparent; + } + + +blockquote { + border-left: 5px solid #ccc; + margin: 0; + padding: 1px 0 1px 1em; +} + .sections blockquote p { + font-family: Menlo, Consolas, Monaco, monospace; + font-size: 12px; line-height: 16px; + color: #999; + margin: 10px 0 0; + white-space: pre-wrap; + } + +ul.sections { + list-style: none; + padding:0 0 5px 0;; + margin:0; +} + +/* + Force border-box so that % widths fit the parent + container without overlap because of margin/padding. + + More Info : http://www.quirksmode.org/css/box.html +*/ +ul.sections > li > div { + -moz-box-sizing: border-box; /* firefox */ + -ms-box-sizing: border-box; /* ie */ + -webkit-box-sizing: border-box; /* webkit */ + -khtml-box-sizing: border-box; /* konqueror */ + box-sizing: border-box; /* css3 */ +} + + +/*---------------------- Jump Page -----------------------------*/ +#jump_to, #jump_page { + margin: 0; + background: white; + -webkit-box-shadow: 0 0 25px #777; -moz-box-shadow: 0 0 25px #777; + -webkit-border-bottom-left-radius: 5px; -moz-border-radius-bottomleft: 5px; + font: 16px Arial; + cursor: pointer; + text-align: right; + list-style: none; +} + +#jump_to a { + text-decoration: none; +} + +#jump_to a.large { + display: none; +} +#jump_to a.small { + font-size: 22px; + font-weight: bold; + color: #676767; +} + +#jump_to, #jump_wrapper { + position: fixed; + right: 0; top: 0; + padding: 10px 15px; + margin:0; +} + +#jump_wrapper { + display: none; + padding:0; +} + +#jump_to:hover #jump_wrapper { + display: block; +} + +#jump_page_wrapper{ + position: fixed; + right: 0; + top: 0; + bottom: 0; +} + +#jump_page { + padding: 5px 0 3px; + margin: 0 0 25px 25px; + max-height: 100%; + overflow: auto; +} + +#jump_page .source { + display: block; + padding: 15px; + text-decoration: none; + border-top: 1px solid #eee; +} + +#jump_page .source:hover { + background: #f5f5ff; +} + +#jump_page .source:first-child { +} + +/*---------------------- Low resolutions (> 320px) ---------------------*/ +@media only screen and (min-width: 320px) { + .sswrap { display: none; } + + ul.sections > li > div { + display: block; + padding:5px 10px 0 10px; + } + + ul.sections > li > div.annotation ul, ul.sections > li > div.annotation ol { + padding-left: 30px; + } + + ul.sections > li > div.content { + overflow-x:auto; + -webkit-box-shadow: inset 0 0 5px #e5e5ee; + box-shadow: inset 0 0 5px #e5e5ee; + border: 1px solid #dedede; + margin:5px 10px 5px 10px; + padding-bottom: 5px; + } + + ul.sections > li > div.annotation pre { + margin: 7px 0 7px; + padding-left: 15px; + } + + ul.sections > li > div.annotation p tt, .annotation code { + background: #f8f8ff; + border: 1px solid #dedede; + font-size: 12px; + padding: 0 0.2em; + } +} + +/*---------------------- (> 481px) ---------------------*/ +@media only screen and (min-width: 481px) { + #container { + position: relative; + } + body { + background-color: #F5F5FF; + font-size: 15px; + line-height: 21px; + } + pre, tt, code { + line-height: 18px; + } + p, ul, ol { + margin: 0 0 15px; + } + + + #jump_to { + padding: 5px 10px; + } + #jump_wrapper { + padding: 0; + } + #jump_to, #jump_page { + font: 10px Arial; + text-transform: uppercase; + } + #jump_page .source { + padding: 5px 10px; + } + #jump_to a.large { + display: inline-block; + } + #jump_to a.small { + display: none; + } + + + + #background { + position: absolute; + top: 0; bottom: 0; + width: 350px; + background: #fff; + border-right: 1px solid #e5e5ee; + z-index: -1; + } + + ul.sections > li > div.annotation ul, ul.sections > li > div.annotation ol { + padding-left: 40px; + } + + ul.sections > li { + white-space: nowrap; + } + + ul.sections > li > div { + display: inline-block; + } + + ul.sections > li > div.annotation { + max-width: 350px; + min-width: 350px; + min-height: 5px; + padding: 13px; + overflow-x: hidden; + white-space: normal; + vertical-align: top; + text-align: left; + } + ul.sections > li > div.annotation pre { + margin: 15px 0 15px; + padding-left: 15px; + } + + ul.sections > li > div.content { + padding: 13px; + vertical-align: top; + border: none; + -webkit-box-shadow: none; + box-shadow: none; + } + + .sswrap { + position: relative; + display: inline; + } + + .ss { + font: 12px Arial; + text-decoration: none; + color: #454545; + position: absolute; + top: 3px; left: -20px; + padding: 1px 2px; + opacity: 0; + -webkit-transition: opacity 0.2s linear; + } + .for-h1 .ss { + top: 47px; + } + .for-h2 .ss, .for-h3 .ss, .for-h4 .ss { + top: 35px; + } + + ul.sections > li > div.annotation:hover .ss { + opacity: 1; + } +} + +/*---------------------- (> 1025px) ---------------------*/ +@media only screen and (min-width: 1025px) { + + body { + font-size: 16px; + line-height: 24px; + } + + #background { + width: 525px; + } + ul.sections > li > div.annotation { + max-width: 525px; + min-width: 525px; + padding: 10px 25px 1px 50px; + } + ul.sections > li > div.content { + padding: 9px 15px 16px 25px; + } +} + +/*---------------------- Syntax Highlighting -----------------------------*/ + +td.linenos { background-color: #f0f0f0; padding-right: 10px; } +span.lineno { background-color: #f0f0f0; padding: 0 5px 0 5px; } +/* + +github.com style (c) Vasily Polovnyov + +*/ + +pre code { + display: block; padding: 0.5em; + color: #000; + background: #f8f8ff +} + +pre .hljs-comment, +pre .hljs-template_comment, +pre .hljs-diff .hljs-header, +pre .hljs-javadoc { + color: #408080; + font-style: italic +} + +pre .hljs-keyword, +pre .hljs-assignment, +pre .hljs-literal, +pre .hljs-css .hljs-rule .hljs-keyword, +pre .hljs-winutils, +pre .hljs-javascript .hljs-title, +pre .hljs-lisp .hljs-title, +pre .hljs-subst { + color: #954121; + /*font-weight: bold*/ +} + +pre .hljs-number, +pre .hljs-hexcolor { + color: #40a070 +} + +pre .hljs-string, +pre .hljs-tag .hljs-value, +pre .hljs-phpdoc, +pre .hljs-tex .hljs-formula { + color: #219161; +} + +pre .hljs-title, +pre .hljs-id { + color: #19469D; +} +pre .hljs-params { + color: #00F; +} + +pre .hljs-javascript .hljs-title, +pre .hljs-lisp .hljs-title, +pre .hljs-subst { + font-weight: normal +} + +pre .hljs-class .hljs-title, +pre .hljs-haskell .hljs-label, +pre .hljs-tex .hljs-command { + color: #458; + font-weight: bold +} + +pre .hljs-tag, +pre .hljs-tag .hljs-title, +pre .hljs-rules .hljs-property, +pre .hljs-django .hljs-tag .hljs-keyword { + color: #000080; + font-weight: normal +} + +pre .hljs-attribute, +pre .hljs-variable, +pre .hljs-instancevar, +pre .hljs-lisp .hljs-body { + color: #008080 +} + +pre .hljs-regexp { + color: #B68 +} + +pre .hljs-class { + color: #458; + font-weight: bold +} + +pre .hljs-symbol, +pre .hljs-ruby .hljs-symbol .hljs-string, +pre .hljs-ruby .hljs-symbol .hljs-keyword, +pre .hljs-ruby .hljs-symbol .hljs-keymethods, +pre .hljs-lisp .hljs-keyword, +pre .hljs-tex .hljs-special, +pre .hljs-input_number { + color: #990073 +} + +pre .hljs-builtin, +pre .hljs-constructor, +pre .hljs-built_in, +pre .hljs-lisp .hljs-title { + color: #0086b3 +} + +pre .hljs-preprocessor, +pre .hljs-pi, +pre .hljs-doctype, +pre .hljs-shebang, +pre .hljs-cdata { + color: #999; + font-weight: bold +} + +pre .hljs-deletion { + background: #fdd +} + +pre .hljs-addition { + background: #dfd +} + +pre .hljs-diff .hljs-change { + background: #0086b3 +} + +pre .hljs-chunk { + color: #aaa +} + +pre .hljs-tex .hljs-formula { + opacity: 0.5; +} diff --git a/docs/index.html b/docs/index.html index 928c2f6da..402d6bea2 100644 --- a/docs/index.html +++ b/docs/index.html @@ -3,7 +3,7 @@ - @fabric/core · Docs + Home · Docs + + + + + + +
    +

    Source: types/remote.js

    + + + + +
    +
    +
    'use strict';
    +
    +const {
    +  HTTP_HEADER_CONTENT_TYPE,
    +  P2P_CALL
    +} = require('../constants');
    +
    +// Internal Dependencies
    +const querystring = require('querystring');
    +
    +// External Dependencies
    +const fetch = require('cross-fetch');
    +const parser = require('content-type');
    +// const ws = require('ws').WebSocket;
    +
    +// Internal Types
    +const Actor = require('./actor');
    +const Message = require('./message');
    +
    +/**
    + * Interact with a remote {@link Resource}.  This is currently the only
    + * HTTP-related code that should remain in @fabric/core — all else must
    + * be moved to @fabric/http before final release!
    + * @type {Remote}
    + * @property {Object} config
    + * @property {Boolean} secure
    + */
    +class Remote extends Actor {
    +  /**
    +   * An in-memory representation of a node in our network.
    +   * @param       {Object} target - Target object.
    +   * @param       {String} target.host - Named host, e.g. "localhost".
    +   * @param       {String} target.secure - Require TLS session.
    +   * @constructor
    +   */
    +  constructor (config = {}) {
    +    super(config);
    +
    +    this.settings = Object.assign({
    +      backoff: 2,
    +      entropy: Math.random(),
    +      macaroon: null,
    +      secure: true,
    +      state: {
    +        status: 'PAUSED'
    +      },
    +      host: 'hub.fabric.pub',
    +      port: 443
    +    }, config);
    +
    +    this.secure = this.settings.secure;
    +    this.socket = null;
    +
    +    this.endpoint = `${(this.secure) ? 'wss' : 'ws'}:${this.host}:${this.port}/`;
    +
    +    this._nextReconnect = 0;
    +    this._reconnectAttempts = 0;
    +    this._state = {
    +      status: 'PAUSED',
    +      messages: [],
    +      meta: {
    +        messages: {
    +          count: 0
    +        }
    +      }
    +    };
    +
    +    return this;
    +  }
    +
    +  set host (value) {
    +    if (typeof value !== 'string') throw new Error('Host must be a string.');
    +    this.settings.host = value;
    +    return this.settings.host;
    +  }
    +
    +  get host () {
    +    return this.settings.host;
    +  }
    +
    +  set port (value) {
    +    if (!Number.isInteger(value)) throw new Error('Port must be an integer.');
    +    this.settings.port = value;
    +    return this.settings.port;
    +  }
    +
    +  get port () {
    +    return this.settings.port;
    +  }
    +
    +  get authority () {
    +    // TODO: use onion address for secure mode
    +    const parts = (this.settings.authority) ? this.settings.authority.split(':') : this.host.split(':');
    +    const state = {
    +      host: null,
    +      secure: null,
    +      protocol: null,
    +      port: null
    +    };
    +
    +    // Check number of components
    +    switch (parts.length) {
    +      default:
    +        // TODO: warn about unexpected values
    +        state.host = this.settings.host;
    +        state.port = this.settings.port;
    +        state.secure = this.settings.secure;
    +        break;
    +      case 1:
    +        state.host = parts[0];
    +        state.port = this.settings.port;
    +        state.secure = this.settings.secure;
    +        break;
    +      case 2:
    +        state.host = parts[0];
    +        state.port = parts[1];
    +        state.secure = this.settings.secure;
    +        break;
    +      case 3:
    +        state.host = parts[1];
    +        state.port = parts[2];
    +        // TODO: should settings override protocol inclusion?
    +        state.secure = (parts[0].charAt(4) === 's');
    +        break;
    +    }
    +
    +    // Finally set protocol for all cases...
    +    state.protocol = (!state.secure) ? 'http' : 'https';
    +
    +    return `${state.protocol}://${state.host}:${state.port}`;
    +  }
    +
    +  get isArrayBufferSupported () {
    +    return (new Buffer(new Uint8Array([1]).buffer)[0] === 1);
    +  }
    +
    +  get arrayBufferToBuffer () {
    +    return this.isArrayBufferSupported ? this.arrayBufferToBufferAsArgument : this.arrayBufferToBufferCycle;
    +  }
    +    
    +  arrayBufferToBufferAsArgument (ab) {
    +    return new Buffer(ab);
    +  }
    +
    +  arrayBufferToBufferCycle (ab) {
    +    var buffer = new Buffer(ab.byteLength);
    +    var view = new Uint8Array(ab);
    +    for (var i = 0; i < buffer.length; ++i) {
    +        buffer[i] = view[i];
    +    }
    +    return buffer;
    +  }
    +
    +  async _handleSocketClose (message) {
    +    this._state.status = 'CLOSED';
    +    console.log('[FABRIC:REMOTE]', 'Socket close:', message);
    +    this._reconnectAttempts++;
    +    this._reconnector = setTimeout(this.connect.bind(this), this._nextReconnect);
    +    this._nextReconnect = Math.pow(this.settings.backoff, this._reconnectAttempts) * 1000 * Math.random();
    +  }
    +
    +  async _handleSocketError (message) {
    +    console.error('[FABRIC:REMOTE]', 'Socket error:', message);
    +    this.emit('error', message);
    +  }
    +
    +  async _handleSocketMessage (packet) {
    +    this.emit('debug', `[FABRIC:REMOTE] Socket packet ${JSON.stringify(packet)}`);
    +    const length = packet.data.byteLength;
    +    console.log('length:', length);
    +    const buffer = Buffer.from(packet.data);
    +    console.log('buffer:', buffer);
    +    const message = Message.fromRaw(buffer).toObject();
    +    console.log('message:', message);
    +    this._state.messages.push(message);
    +    ++this._state.meta.messages.count;
    +    this.emit('message', message);
    +  }
    +
    +  async _handleSocketOpen (message) {
    +    this._nextReconnect = 0;
    +    this._reconnectAttempts = 0;
    +    if (this._reconnector) clearTimeout(this._reconnector);
    +    this._state.status = 'CONNECTED';
    +    this.emit('ready');
    +  }
    +
    +  async executeMethod (name, params = []) {
    +    const call = Message.fromVector([P2P_CALL, JSON.stringify([name, params])]);
    +    console.log('call:', call);
    +    console.log('raw:', call.toRaw());
    +    return this.socket.send(call.toRaw());
    +  }
    +
    +  async connect () {
    +    this._state.status = 'CONNECTING';
    +
    +    try {
    +      this.socket = new WebSocket(this.endpoint);
    +      console.log('socket:', this.socket);
    +    } catch (exception) {
    +      console.error('[FABRIC:REMOTE]', 'Unable to connect:', exception);
    +    }
    +
    +    if (this.socket) {
    +      this.socket.binaryType = 'arraybuffer';
    +      this.socket.addEventListener('close', this._handleSocketClose.bind(this));
    +      this.socket.addEventListener('open', this._handleSocketOpen.bind(this));
    +      this.socket.addEventListener('message', this._handleSocketMessage.bind(this));
    +      this.socket.addEventListener('error', this._handleSocketError.bind(this));
    +    }
    +
    +    return this;
    +  }
    +
    +  /**
    +   * Enumerate the available Resources on the remote host.
    +   * @return {Configuration} An object with enumerable key/value pairs for the Application Resource Contract.
    +   */
    +  async enumerate () {
    +    const options = await this._OPTIONS('/');
    +    const results = [];
    +
    +    for (const name in options) {
    +      const definition = options[name];
    +      results.push({
    +        name: definition.name,
    +        description: definition.description,
    +        components: Object.assign({
    +          list: 'maki-resource-list',
    +          view: 'maki-resource-view'
    +        }, definition.components),
    +        routes: definition.routes,
    +        attributes: definition.attributes,
    +        names: definition.names
    +      });
    +    }
    +
    +    return options;
    +  }
    +
    +  /**
    +   * Make an HTTP request to the configured authority.
    +   * @param {String} type One of `GET`, `PUT`, `POST`, `DELETE`, or `OPTIONS`.
    +   * @param {String} path The path to request from the authority.
    +   * @param {Object} [params] Options.
    +   * @returns {FabricHTTPResult}
    +   */
    +  async request (type, path, params = {}) {
    +    const self = this;
    +
    +    let url = this.authority + path;
    +    let result = null;
    +    let response = null;
    +    let headers = {
    +      'Accept': HTTP_HEADER_CONTENT_TYPE,
    +      'Content-Type': HTTP_HEADER_CONTENT_TYPE
    +    };
    +
    +    if (params.headers) {
    +      headers = Object.assign({}, headers, params.headers);
    +    }
    +
    +    if (this.settings.macaroon) {
    +      headers = Object.assign({}, headers, {
    +        'Macaroon': this.settings.macaroon,
    +        'EncodingType': 'hex'
    +      });
    +    }
    +
    +    let opts = {
    +      method: type,
    +      headers: headers
    +    };
    +
    +    // TODO: break out into independent auth module
    +    if (this.settings.username || this.settings.password) {
    +      headers['Authorization'] = `Basic ${Buffer.from([
    +        this.settings.username || '',
    +        this.settings.password || ''
    +      ].join(':')).toString('base64')}`;
    +    }
    +
    +    switch (params.mode) {
    +      case 'query':
    +        url += '?' + querystring.stringify(params.body);
    +        break;
    +      default:
    +        try {
    +          opts.body = JSON.stringify(params.body);
    +        } catch (exception) {
    +          console.error('[FABRIC:REMOTE] Could not prepare request:', exception);
    +        }
    +
    +        opts = Object.assign(opts, {
    +          body: params.body || null
    +        });
    +        break;
    +    }
    +
    +    // Core Logic
    +    this.emit('warning', `Requesting: ${url} ${opts}`);
    +
    +    try {
    +      response = await fetch(url, opts);
    +    } catch (e) {
    +      self.emit('error', `[REMOTE] exception: ${e}`);
    +    }
    +
    +    if (!response) {
    +      return {
    +        status: 'error',
    +        message: 'No response to request.'
    +      };
    +    }
    +
    +    switch (response.status) {
    +      case 404:
    +        result = {
    +          status: 'error',
    +          message: 'Document not found.'
    +        };
    +        break;
    +      default:
    +        if (response.ok) {
    +          const formatter = parser.parse(response.headers.get('content-type'));
    +          switch (formatter.type) {
    +            case 'application/json':
    +              try {
    +                result = await response.json();
    +              } catch (E) {
    +                console.error('[REMOTE]', 'Could not parse JSON:', E);
    +                result = await response.text();
    +              }
    +              break;
    +            default:
    +              if (this.settings.verbosity >= 4) self.emit('warning', `[FABRIC:REMOTE] Unhandled headers content type: ${formatter.type}`);
    +              result = await response.text();
    +              break;
    +          }
    +        } else {
    +          if (this.settings.verbosity >= 4) console.warn('[FABRIC:REMOTE]', 'Unmanaged HTTP status code:', response.status);
    +
    +          try {
    +            result = await response.json();
    +          } catch (exception) {
    +            result = await response.text();
    +          }
    +        }
    +        break;
    +    }
    +
    +    return result;
    +  }
    +
    +  async ping () {
    +    this.send({
    +      created: (new Date()).toISOString(),
    +      type: 'PING'
    +    });
    +  }
    +
    +  async send (message) {
    +    const msg = Message.fromVector(['GenericMessage', JSON.stringify(message)]);
    +    const raw = msg.toRaw();
    +    const actor = new Actor({ content: raw.toString('hex') });
    +    this.socket.send(raw);
    +    return actor.id;
    +  }
    +
    +  async sendAsJSON (message) {
    +    this.socket.send({
    +      content: message
    +    });
    +  }
    +
    +  /**
    +   * HTTP PUT against the configured Authority.
    +   * @param  {String} path - HTTP Path to request.
    +   * @param  {Object} body - Map of parameters to supply.
    +   * @return {FabricHTTPResult|String} Result of request.
    +   */
    +  async _PUT (key, body) {
    +    return this.request('put', key, { body });
    +  }
    +
    +  /**
    +   * HTTP GET against the configured Authority.
    +   * @param  {String} path - HTTP Path to request.
    +   * @param  {Object} params - Map of parameters to supply.
    +   * @return {FabricHTTPResult|String} Result of request.
    +   */
    +  async _GET (key, params) {
    +    return this.request('get', key, params);
    +  }
    +
    +  /**
    +   * HTTP POST against the configured Authority.
    +   * @param  {String} path - HTTP Path to request.
    +   * @param  {Object} params - Map of parameters to supply.
    +   * @return {FabricHTTPResult|String} Result of request.
    +   */
    +  async _POST (key, obj, params = {}) {
    +    let result = null;
    +    let options = null;
    +
    +    switch (params.mode) {
    +      case 'query':
    +        options = Object.assign({}, {
    +          body: obj,
    +          mode: 'query'
    +        });
    +        break;
    +      default:
    +        options = Object.assign({}, params, {
    +          body: obj,
    +          mode: 'body'
    +        });
    +        break;
    +    }
    +
    +    result = await this.request('post', key, options);
    +
    +    return result;
    +  }
    +
    +  /**
    +   * HTTP OPTIONS on the configured Authority.
    +   * @param  {String} path - HTTP Path to request.
    +   * @param  {Object} params - Map of parameters to supply.
    +   * @return {Object} - Full description of remote resource.
    +   */
    +  async _OPTIONS (key, params) {
    +    return this.request('options', key, params);
    +  }
    +
    +  /**
    +   * HTTP PATCH on the configured Authority.
    +   * @param  {String} path - HTTP Path to request.
    +   * @param  {Object} body - Map of parameters to supply.
    +   * @return {Object} - Full description of remote resource.
    +   */
    +  async _PATCH (key, body) {
    +    return this.request('patch', key, { body });
    +  }
    +
    +  /**
    +   * HTTP DELETE on the configured Authority.
    +   * @param  {String} path - HTTP Path to request.
    +   * @param  {Object} params - Map of parameters to supply.
    +   * @return {Object} - Full description of remote resource.
    +   */
    +  async _DELETE (key, params) {
    +    return this.request('delete', key, params);
    +  }
    +
    +  async _SEARCH (key, params) {
    +    if (this.settings.debug) console.debug('[FABRIC:CORE]', '_SEARCH:', key, params);
    +    return this.request('search', key, params);
    +  }
    +}
    +
    +module.exports = Remote;
    +
    +
    +
    + + + +
    + +
    + + + + + + \ No newline at end of file diff --git a/docs/types_resource.js.html b/docs/types_resource.js.html index 27f38de18..1c819c38f 100644 --- a/docs/types_resource.js.html +++ b/docs/types_resource.js.html @@ -148,52 +148,49 @@

    Home

    Classes

    Events

    diff --git a/docs/types_router.js.html b/docs/types_router.js.html index c57795a03..7ed38d476 100644 --- a/docs/types_router.js.html +++ b/docs/types_router.js.html @@ -39,15 +39,7 @@

    Source: types/router.js

    // Current code is specific to @fabric/doorman — should be a general- // purpose Router, not for strings and triggers in chat messages. -/** - * Process incoming messages. - * @extends Scribe - */ class Router extends Scribe { - /** - * Maintains a list of triggers ("commands") and their behaviors. - * @param {Object} map Map of command names => behaviors. - */ constructor (config) { super(config); @@ -131,52 +123,49 @@

    Home

    Classes

    Events

    diff --git a/docs/types_scribe.js.html b/docs/types_scribe.js.html index 4a8144953..94d74d0e3 100644 --- a/docs/types_scribe.js.html +++ b/docs/types_scribe.js.html @@ -38,17 +38,7 @@

    Source: types/scribe.js

    // Fabric Components const State = require('./state'); -/** - * Simple tag-based recordkeeper. - * @extends State - * @property {Object} config Current configuration. - */ class Scribe extends State { - /** - * The "Scribe" is a simple tag-based recordkeeper. - * @param {Object} config General configuration object. - * @param {Boolean} config.verbose Should the Scribe be noisy? - */ constructor (config = {}) { super(config); @@ -212,52 +202,49 @@

    Home

    Classes

    Events

    diff --git a/docs/types_script.js.html b/docs/types_script.js.html index c7c13d4c5..aab95ed8e 100644 --- a/docs/types_script.js.html +++ b/docs/types_script.js.html @@ -78,52 +78,49 @@

    Home

    Classes

    Events

    diff --git a/docs/types_service.js.html b/docs/types_service.js.html index 485227808..4e953845f 100644 --- a/docs/types_service.js.html +++ b/docs/types_service.js.html @@ -33,12 +33,14 @@

    Source: types/service.js

    'use strict';
     
    -const PATCHES_ENABLED = false;
    +const PATCHES_ENABLED = true;
    +const OP_TRACE = require('../contracts/trace');
     
     // Dependencies
     const crypto = require('crypto');
     const stream = require('stream');
     const path = require('path');
    +const EventEmitter = require('events').EventEmitter;
     
     // Public modules
     // TODO: remove
    @@ -49,11 +51,12 @@ 

    Source: types/service.js

    // Fabric Types const Actor = require('./actor'); const Collection = require('./collection'); -const Resource = require('./resource'); const Entity = require('./entity'); const Hash256 = require('./hash256'); +const Identity = require('./identity'); const Key = require('./key'); const Message = require('./message'); +const Resource = require('./resource'); const Store = require('./store'); /** @@ -71,20 +74,40 @@

    Source: types/service.js

    class Service extends Actor { /** * Create an instance of a Service. - * @param {Object} settings Configuration for this service. - * @param {Boolean} [settings.networking=true] Whether or not to connect to the network. - * @param {Object} [settings.@data] Internal data to assign. + * @param {Object} [settings] Configuration for this service. + * @param {Boolean} [settings.networking=true] Whether or not to connect to the network. + * @param {Object} [settings.frequency] Interval frequency in hertz. + * @param {Object} [settings.state] Initial state to assign. */ constructor (settings = {}) { // Initialize Scribe, our logging tool super(settings); + this.name = this.constructor.name; + // Configure (with defaults) this.settings = merge({ - name: 'service', + name: 'Service', path: './stores/service', + frequency: 0.0133333334, // Hz networking: true, persistent: false, + constraints: { + tolerance: 100, + memory: { + max: 67108864 + } + }, + fs: { + path: `./stores/fabric-service-${this.name}` + }, + state: { + ...super.state, + actors: {}, // TODO: schema + channels: {}, // TODO: schema + messages: {}, // TODO: schema + services: {} + }, interval: 60000, // Mandatory Checkpoint Interval verbosity: 2, // 0 none, 1 error, 2 warning, 3 notice, 4 debug // TODO: export this as the default data in `inputs/fabric.json` @@ -95,13 +118,14 @@

    Source: types/service.js

    messages: {}, members: {} } */ - }, this.settings, settings); + }, settings); // Reserve a place for ourselves this.agent = null; this.actor = null; this.name = this.settings.name; + this.aliases = {}; this.collections = {}; this.definitions = {}; this.resources = {}; @@ -118,15 +142,18 @@

    Source: types/service.js

    // can draw a canvas: // Error: Not implemented yet this.key = new Key(this.settings.key); + this.identity = new Identity(this.settings.key); if (this.settings.persistent) { try { this.store = new Store(this.settings); } catch (E) { - console.error('Error:', E); + console.error('Store Error:', E); } } + this._clock = 0; + // set local state to whatever configuration supplies... /* this.state = Object.assign({ messages: {} // always define a list of messages for Fabric services @@ -137,12 +164,30 @@

    Source: types/service.js

    history: [], // list of ... services: {}, // stores sub-service state status: 'PAUSED', - content: {}, + content: this.settings.state, version: 0 // TODO: change to 1 for 0.1.0 }; // Keeps track of changes this.observer = null; + this.cache = { + _data: new Map(), + _ttl: new Map(), + get: async (key) => { + const now = Date.now(); + const ttl = this.cache._ttl.get(key); + if (ttl && ttl < now) { + this.cache._data.delete(key); + this.cache._ttl.delete(key); + return null; + } + return this.cache._data.get(key); + }, + set: async (key, value, ttl = 60000) => { + this.cache._data.set(key, value); + this.cache._ttl.set(key, Date.now() + ttl); + } + }; /* if (this.settings.networking) { this.swarm = new Swarm(this.settings); @@ -167,13 +212,17 @@

    Source: types/service.js

    } get clock () { - return parseInt(this._state.clock); + return parseInt(this._clock); } get heartbeat () { return this._heart; } + get interval () { + return 1000 / this.settings.frequency; + } + get status () { return this._state.status; } @@ -187,7 +236,7 @@

    Source: types/service.js

    } get state () { - return this._state; + return Object.assign({}, this._state.content); } set clock (value) { @@ -265,18 +314,22 @@

    Source: types/service.js

    return this.beat(); } + /** + * Compute latest state. + * @emits Message#beat + * @returns {Service} + */ beat () { const now = (new Date()).toISOString(); // Increment clock ++this._clock; - // TODO: remove async, use local state instead - // i.e., queue worker job + // Create Generic Message const beat = Message.fromVector(['Generic', { clock: this._clock, created: now, - state: this._state + state: this._state.content }]); if (!beat) { @@ -285,6 +338,7 @@

    Source: types/service.js

    process.exit(); } + // TODO: remove JSON parser here — only needed for verification // TODO: parse JSON types in @fabric/core/types/message let data = beat.data; @@ -308,7 +362,7 @@

    Source: types/service.js

    /** * Retrieve a key from the {@link State}. * @param {Path} path Key to retrieve. - * @returns {Mixed} + * @returns {Mixed} Returns the target value if found, otherwise null. */ get (path = '') { let result = null; @@ -331,12 +385,20 @@

    Source: types/service.js

    return result; } + // Synchronize with any external sources + sync () { + if (!this._sources) this._sources = []; + return this; + } + /** * Explicitly trust all events from a known source. * @param {EventEmitter} source Emitter of events. * @return {Service} Instance of Service after binding events. */ trust (source, name = source.constructor.name) { + if (!(source instanceof EventEmitter)) throw new Error('Source is not an EventEmitter.') + // Constants const self = this; @@ -360,55 +422,61 @@

    Source: types/service.js

    return { _handleActor: source.on('actor', async function (actor) { - console.log(`[FABRIC:SERVICE] Source "${name}" emitted actor:`, actor); + self.emit('debug', `[FABRIC:SERVICE] Source "${name}" emitted actor: ${JSON.stringify(actor, null, ' ')}`); }), _handleAlert: source.on('alert', async function (alert) { self.alert(`[FABRIC:SERVICE] [ALERT] [!!!] ${name} alerted: ${alert}`); }), _handleBeat: source.on('beat', async function (beat) { self.emit('debug', `[FABRIC:SERVICE] Source "${name}" emitted beat: ${JSON.stringify(beat, null, ' ')}`); + const ops = [ + { op: 'add', path: `/actors`, value: {} }, + { op: 'add', path: `/services`, value: {} }, { op: 'replace', path: `/services/${name}`, value: beat.state } ]; + /* try { - manager.applyPatch(self._state, ops); + manager.applyPatch(self._state.content, ops); await self.commit(); } catch (exception) { - self.emit('error', `Could not process beat: ${exception}`); + self.emit('warning', `Could not process beat: ${exception}`); } + */ }), _handleChanges: source.on('changes', async function (changes) { - console.log(`[FABRIC:SERVICE] Source "${name}" emitted changes:`, changes); + self.emit('debug', `[FABRIC:SERVICE] Source "${name}" emitted changes: ${changes}`); }), _handleChannel: source.on('channel', async function (channel) { - console.log(`[FABRIC:SERVICE] Source "${name}" emitted channel:`, channel); + self.emit('debug', `[FABRIC:SERVICE] Source "${name}" emitted channel: ${JSON.stringify(channel, null, ' ')}`); }), _handleCommit: source.on('commit', async function (commit) { - console.log(`[FABRIC:SERVICE] Source "${name}" committed:`, commit); + self.emit('debug', `[FABRIC:SERVICE] Source "${name}" committed: ${JSON.stringify(commit, null, ' ')}`); }), _handleError: source.on('error', async function _handleTrustedError (error) { - console.error(`[FABRIC:SERVICE] Source "${name}" emitted error:`, error); + self.emit('debug', `[FABRIC:SERVICE] Source "${name}" emitted error: ${error}`); }), _handleLog: source.on('log', async function _handleTrustedLog (log) { - console.log(`[FABRIC:SERVICE] Source "${name}" emitted log:`, log); + if (self.settings.debug) self.emit('log', `[FABRIC:SERVICE] Source "${name}" emitted log: ${log}`); }), _handleMessage: source.on('message', async function (message) { self.emit('debug', `[FABRIC:SERVICE] Source "${name}" emitted message: ${JSON.stringify(message.toObject ? message.toObject() : message, null, ' ')}`); await self._handleTrustedMessage(message); }), _handlePatches: source.on('patches', async function (patches) { - self.emit('debug', `[FABRIC:SERVICE] [${name}] Service State:`, source._state); - // TODO: apply changes to parent (self) + self.emit('debug', `[FABRIC:SERVICE] [${name}] Service State: ${JSON.stringify(source.state, null, ' ')}`); + self.emit('debug', `[FABRIC:SERVICE] [${name}] Patches: ${JSON.stringify(patches)}`); + self.emit('patches', patches); }), _handleReady: source.on('ready', async function _handleTrustedReady (info) { - console.log(`[FABRIC:SERVICE] Source "${name}" emitted ready:`, info); + self.emit('log', `[FABRIC:SERVICE] Source "${name}" emitted ready: ${JSON.stringify(info)}`); }), _handleTip: source.on('tip', async function (hash) { self.alert(`[FABRIC:SERVICE] New ${name} chaintip: ${hash}`); }), _handleWarning: source.on('warning', async function _handleTrustedWarning (warning) { - console.warn(`[FABRIC:SERVICE] Source "${name}" emitted warning:`, warning); + if (self.settings?.verbosity >= 2) self.emit('warning', `[FABRIC:SERVICE] Source "${name}" emitted warning: ${warning}`); }) }; } @@ -480,10 +548,21 @@

    Source: types/service.js

    return true; } + /** + * Bind a method to an event, with current state as the immutable context. + * @param {String} event Name of the event upon which to execute `method` as a function. + * @param {Function} method Function to execute when named {@link Event} `event` is encountered. + * @returns {EventEmitter} Instance of EventEmitter. + */ + when (event, method) { + return this.on(event, method.call(this.state)); + } + _defineResource (name, definition) { const resource = Object.assign({ name }, definition); this.resources[name] = new Resource(resource); this.emit('resource', this.resources[name]); + return this.resources[name]; } _handleTrustedDebug (message) { @@ -620,7 +699,11 @@

    Source: types/service.js

    // TODO: re-re-evaluate a better approach... oh how I long for Object.observe! // this.observer = manager.observe(this.state, this._handleStateChange.bind(this)); - this.observer = manager.observe(this._state); + try { + this.observer = manager.observe(this._state.content); + } catch (exception) { + console.trace('Could not observe state:', this._state.content, exception); + } // Set a heartbeat await this._startHeart(); @@ -633,6 +716,8 @@

    Source: types/service.js

    } async stop () { + this.emit('debug', 'Stopping...'); + if (this.settings.networking) { await this.disconnect(); } @@ -677,8 +762,8 @@

    Source: types/service.js

    try { result = pointer.get(this.state, path); - } catch (E) { - console.error(`Could not _GET() ${path}:`, E); + } catch (exception) { + this.emit('debug', `Could not _GET() ${path}:\n${exception}\n\tState: ${JSON.stringify(this.state, null, ' ')}`); } return result; @@ -876,49 +961,27 @@

    Source: types/service.js

    } commit () { - if (this.settings.verbosity >= 4) this.emit('log', '[FABRIC:SERVICE] Committing...'); - - const self = this; - const ops = []; - - // assemble all necessary info, emit Snapshot regardless of storage status - try { - ops.push({ type: 'put', key: 'snapshot', value: self._state }); - this.emit('debug', JSON.stringify({ - '@data': self.state, - '@from': 'COMMIT', - '@type': 'Snapshot' - })); - } catch (E) { - console.error('Error saving state:', self.state); - console.error('Could not commit to state:', E); - } - - if (this.settings.persistent) { - // TODO: add robust + convenient database opener - this.store.batch(ops, function shareChanges () { - // TODO: notify status? - }).catch((exception) => { - self.emit('error', `Could not write to store: ${exception}`); - }).then((output) => { - self.emit('commit', { output }); - }); - } - - if (PATCHES_ENABLED && self.observer) { + // this.emit('debug', `[FABRIC:SERVICE] Committing ${OP_TRACE()}`); + if (PATCHES_ENABLED && this.observer) { try { - const patches = manager.generate(self.observer); + const patches = manager.generate(this.observer); if (patches.length) { this.history.push(patches); - self.emit('patches', patches); + this.emit('patches', patches); } } catch (E) { console.error('Could not generate patches:', E); } } - const commit = new Actor(self._state); - this.emit('commit', commit); + const commit = new Actor({ + type: 'Commit', + state: this.state + }); + + this.emit('commit', { ...commit.toObject(), id: commit.id }); + // this.emit('state', this.state); + return commit.id; } @@ -966,9 +1029,7 @@

    Source: types/service.js

    async _registerActor (actor = {}) { if (!actor.id) { const entity = new Actor(actor); - actor = merge({ - id: entity.id - }, actor); + actor = { ...entity.toObject(), id: entity.id }; } const id = pointer.escape(actor.id); @@ -998,6 +1059,7 @@

    Source: types/service.js

    id: entity.id, members: [] }, channel); + return channel; } const target = pointer.escape(channel.id); @@ -1062,14 +1124,15 @@

    Source: types/service.js

    try { // TODO: allow configurable validators - result = manager.applyPatch(this.state, changes, function isValid () { + this._state.content = manager.applyPatch(this.state, changes, function isValid () { + // TODO: invalidate changes without appropriate capability token return true; }, true /* mutate doc (1st param) */); } catch (exception) { console.error('Could not apply changes:', changes, exception); } - await this.commit(); + this.commit(); return result; } @@ -1149,16 +1212,23 @@

    Source: types/service.js

    async _startAllServices () { if (!this.services) return this.emit('warning', 'Tried to start subservices, but none existed.'); + this.emit('debug', `Service entries: ${Object.keys(this.services)}`); + // Start all Services for (const [name, service] of Object.entries(this.services)) { // TODO: re-evaluate inclusion on Service itself if (this.settings.services && this.settings.services.includes(name)) { - this.emit('debug', `Starting service "${name}" (with trust)`); + this.emit('debug', `Starting service "${name}" (with trust)...`); // TODO: evaluate @fabric/core/types/store // TODO: isomorphic @fabric/core/types/store // await this.services[name]._bindStore(this.store); this.trust(this.services[name], name); - await this.services[name].start(); + + try { + await this.services[name].start(); + } catch (exception) { + this.emit('warning', `Could not start the "${name}" service due to exception: ${JSON.stringify(exception, null, ' ')}`); + } } } @@ -1166,7 +1236,9 @@

    Source: types/service.js

    } async _startHeart () { + if (this._heart) clearInterval(this._heart); this._heart = setInterval(this.beat.bind(this), this.settings.interval); + return this; } } @@ -1183,52 +1255,49 @@

    Home

    Classes

    Events

    diff --git a/docs/types_session.js.html b/docs/types_session.js.html index d050d5999..430fd54a9 100644 --- a/docs/types_session.js.html +++ b/docs/types_session.js.html @@ -41,7 +41,6 @@

    Source: types/session.js

    // Dependencies const BN = require('bn.js'); -const event = require('p-event'); const struct = require('struct'); const crypto = require('crypto'); @@ -68,7 +67,7 @@

    Source: types/session.js

    }, settings); // Session Key - this.key = this._getOddKey(); + this.key = settings.key || this._getOddKey(); this.derived = null; // Internal State @@ -242,52 +241,49 @@

    Home

    Classes

    Events

    diff --git a/docs/types_signer.js.html b/docs/types_signer.js.html index e44deae9e..6aa6be3f7 100644 --- a/docs/types_signer.js.html +++ b/docs/types_signer.js.html @@ -34,16 +34,20 @@

    Source: types/signer.js

    'use strict';
     
     // Dependencies
    +const crypto = require('crypto');
    +const stream = require('stream');
     const schnorr = require('bip-schnorr');
     
     // Fabric Types
     const Actor = require('./actor');
    +const Hash256 = require('./hash256');
     const Key = require('./key');
     
     /**
      * Generic Fabric Signer.
      * @access protected
      * @emits message Fabric {@link Message} objects.
    + * @extends {Actor}
      * @property {String} id Unique identifier for this Signer (id === SHA256(preimage)).
      * @property {String} preimage Input hash for the `id` property (preimage === SHA256(SignerState)).
      */
    @@ -65,15 +69,23 @@ 

    Source: types/signer.js

    this.log = []; this.signature = null; + // Settings + this.settings = { + state: {} + }; + // TODO: fix bcoin in React / WebPack this.key = new Key({ seed: actor.seed, public: actor.public || actor.pubkey, - private: actor.private + private: actor.private, + xprv: actor.xprv, + xpub: actor.xpub }); // Indicate Risk this.private = !!(this.key.seed || this.key.private); + this.stream = new stream.Transform(this._transformer.bind(this)); this.value = this._readObject(actor); // TODO: use Buffer? // Internal State @@ -88,15 +100,109 @@

    Source: types/signer.js

    return this; } + static chunksForBuffer (input = Buffer.alloc(32), size = 32) { + const chunks = []; + for (let i = 0; i < input.length; i += size) { + const chunk = input.slice(i, i + size); + chunks.push(chunk); + } + + return chunks; + } + + static signableForBuffer (input = Buffer.alloc(32)) { + // TODO: use pubkey + const challenge = crypto.randomBytes(32); + const message_hash = Hash256.digest(input.toString('hex')); + const message = [ + `--- BEGIN META ---`, + `message_challenge: ${challenge.toString('hex')}`, + `message_hash: ${message_hash}`, + `message_scriptsig: 00${message_hash}`, + `--- END META ---`, + `--- BEGIN FABRIC MESSAGE ---`, + Signer.chunksForBuffer(input.toString('hex'), 80).join('\n'), + `--- END FABRIC MESSAGE ---` + ].join('\n'); + + return message; + } + + get pubkey () { + // TODO: encode pubkey correctly for verification + const x = this.key.keypair.getPublic().getX(); + return schnorr.convert.intToBuffer(x); + } + /** * Signs some data. * @returns {Signer} */ sign (data = this.toBuffer()) { + if (!(data instanceof Buffer)) { + switch (data.constructor.name) { + default: + this.emit('warning', `unhandled data to sign: ${data.constructor.name} ${JSON.stringify(data)}`); + break; + } + } + this._lastSignature = new Actor({ message: data, signature: this.signature }); - this.signature = schnorr.sign(this.key.private, data); - this.emit('signature', ); - return this.signature.toString('hex'); + + // Hash & sign + // TODO: check with bip-schnorr on behavior of signing > 32 byte messages + // this._preimage = Buffer.from(Hash256.digest(data), 'hex'); + this.signature = schnorr.sign(this.key.keypair.getPrivate('hex'), data); + // this.signature = schnorr.sign(this.key.keypair.getPrivate('hex'), this._preimage); + + this.emit('signature', { + content: data, + preimage: this._preimage, + pubkey: this._pubkey, + signature: this.signature.toString('hex') + }); + + return this.signature; + } + + start () { + this._state.content.status = 'STARTING'; + // TODO: unpause input stream here + this._state.status = 'STARTED'; + this.commit(); + return this; + } + + stop () { + this._state.status = 'STOPPING'; + this._state.status = 'STOPPED'; + this.commit(); + return this; + } + + toSpend () { + + } + + toSign () { + + } + + verify (pubkey, message, signature) { + if (!(pubkey instanceof Buffer)) pubkey = Buffer.from(pubkey, 'hex'); + if (!(message instanceof Buffer)) message = Buffer.from(message, 'hex'); + if (!(signature instanceof Buffer)) signature = Buffer.from(signature, 'hex'); + + try { + schnorr.verify(pubkey, message, signature); + return true; + } catch (exception) { + return false; + } + } + + async _transformer (chunk, controller) { + } } @@ -113,34 +219,32 @@

    Home

    Classes

    Events

    diff --git a/docs/types_snapshot.js.html b/docs/types_snapshot.js.html index d808e9aff..4e9937790 100644 --- a/docs/types_snapshot.js.html +++ b/docs/types_snapshot.js.html @@ -82,52 +82,49 @@

    Home

    Classes

    Events

    diff --git a/docs/types_stack.js.html b/docs/types_stack.js.html index bf3ff4487..24b08daad 100644 --- a/docs/types_stack.js.html +++ b/docs/types_stack.js.html @@ -168,52 +168,49 @@

    Home

    Classes

    Events

    diff --git a/docs/types_state.js.html b/docs/types_state.js.html index 2a40388ac..d94eba49b 100644 --- a/docs/types_state.js.html +++ b/docs/types_state.js.html @@ -495,13 +495,10 @@

    Source: types/state.js

    render () { this['@id'] = this.id; this['@encoding'] = 'json'; - this['@output'] = this.serialize(this['@entity']['@data'], 'json'); + this['@output'] = this.serialize(this.state, 'json'); this['@commit'] = this.commit(); - switch (this['@type']) { - default: - return this['@output'].toString('utf8'); - } + return this['@output'].toString('utf8'); } } @@ -518,52 +515,49 @@

    Home

    Classes

    Events

    diff --git a/docs/types_store.js.html b/docs/types_store.js.html index 566e6bb10..ac696c502 100644 --- a/docs/types_store.js.html +++ b/docs/types_store.js.html @@ -34,7 +34,7 @@

    Source: types/store.js

    'use strict';
     
     // Dependencies
    -const level = require('level');
    +const { Level } = require('level');
     const crypto = require('crypto');
     const pointer = require('json-pointer');
     
    @@ -423,7 +423,7 @@ 

    Source: types/store.js

    // if (this.db) return this; try { - this.db = level(this.settings.path); + this.db = new Level(this.settings.path); this.trust(this.db); this.status = 'opened'; await this.commit(); @@ -461,9 +461,8 @@

    Source: types/store.js

    let store = this; let name = `/sources/${store.id}`; - source.on('put', function (key, value) { - // store.log('[TRUST:SOURCE]', source.constructor.name, 'emitted a put event', name, key, value.constructor.name, value); - if (store.settings.verbosity >= 5) console.log('[TRUST:SOURCE]', source.constructor.name, 'emitted a put event', name, key, value.constructor.name, value); + source.on('write', function (key, value) { + if (store.settings.verbosity >= 5) console.log('[TRUST:SOURCE]', source.constructor.name, 'emitted a write event', name, key, value.constructor.name, value); let id = pointer.escape(key); let router = store.sha256(id); @@ -617,52 +616,49 @@

    Home

    Classes

    Events

    diff --git a/docs/types_swap.js.html b/docs/types_swap.js.html index 01e04ef48..84d9620e7 100644 --- a/docs/types_swap.js.html +++ b/docs/types_swap.js.html @@ -41,17 +41,7 @@

    Source: types/swap.js

    // Native Dependencies const crypto = require('crypto'); -/** - * The {@link Swap} contract executes a set of transactions on two distinct - * {@link Chain} components, utilizing a secret-reveal mechanism to atomically - * execute either the full set or none. - * @type {Object} - */ class Swap { - /** - * Atomically execute a set of transactions across two {@link Chain} components. - * @param {Object} [settings={}] Configuration for the swap. - */ constructor (settings = {}) { this.settings = Object.assign({ chain: 'bitcoin:regtest' @@ -269,52 +259,49 @@

    Home

    Classes

    Events

    diff --git a/docs/types_swarm.js.html b/docs/types_swarm.js.html index e35990628..b47912fb8 100644 --- a/docs/types_swarm.js.html +++ b/docs/types_swarm.js.html @@ -243,52 +243,49 @@

    Home

    Classes

    Events

    diff --git a/docs/types_token.js.html b/docs/types_token.js.html new file mode 100644 index 000000000..089796374 --- /dev/null +++ b/docs/types_token.js.html @@ -0,0 +1,255 @@ + + + + + + Source: types/token.js · Docs + + + + + + + + + +
    +

    Source: types/token.js

    + + + + +
    +
    +
    'use strict';
    +
    +// Dependencies
    +const bitcoin = require('bitcoinjs-lib');
    +const schnorr = require('bip-schnorr');
    +
    +// Fabric Types
    +const Key = require('./key');
    +
    +/**
    + * Implements a capability-based security token.
    + */
    +class Token {
    +  /**
    +   * Create a new Fabric Token.
    +   * @param {Object} [settings] Configuration.
    +   * @returns {Token} The token instance.
    +   */
    +  constructor (settings = {}) {
    +    // TODO: determine rounding preference (secwise)
    +    this.created = Date.now();
    +    this.settings = Object.assign({
    +      capability: 'OP_0',
    +      issuer: null,
    +      subject: null,
    +      state: {
    +        status: 'READY'
    +      }
    +    }, settings);
    +
    +    // Capability
    +    this.capability = this.settings.capability;
    +    this.ephemera = new Key();
    +
    +    // Trust Chain
    +    this.issuer = this.settings.issuer ? this.settings.issuer : this.ephemera;
    +    this.subject = this.settings.subject ? this.settings.subject : this.ephemera.keypair.getPublic(true).encodeCompressed('hex');
    +
    +    // ECDSA Signature
    +    this.signature = null;
    +
    +    // State
    +    this._state = {
    +      content: this.settings.state
    +    };
    +
    +    return this;
    +  }
    +
    +  get state () {
    +    return JSON.parse(JSON.stringify(this._state.content));
    +  }
    +
    +  static base64UrlEncode (input) {
    +    const base64 = Buffer.from(input, 'utf8').toString('base64');
    +    return base64.replace('+', '-').replace('/', '_').replace(/=+$/, '');
    +  }
    +
    +  static base64UrlDecode (input) {
    +    input = input.replace(/-/g, '+').replace(/_/g, '/');
    +
    +    while (input.length % 4) {
    +      input += '=';
    +    }
    +
    +    return Buffer.from(input, 'base64').toString();
    +  }
    +
    +  static fromString (input) {
    +    const parts = input.split('.');
    +    const headers = parts[0];
    +    const payload = parts[1];
    +    const signature = parts[2];
    +    const inner = Token.base64UrlDecode(payload);
    +
    +    return new Token({
    +      capability: inner.cap,
    +      issuer: inner.iss,
    +      subject: inner.sub,
    +      state: inner.state,
    +      signature: signature
    +    });
    +  }
    +
    +  toString () {
    +    // TODO: determine rounding preference (secwise)
    +    const utime = Math.floor(this.created / 1000);
    +    const issuer = this.issuer.keypair.getPublic(true).encodeCompressed('hex');
    +    const header = {
    +      alg: 'ES256K',
    +      iss: issuer,
    +      typ: 'JWT'
    +    };
    +
    +    const payload = {
    +      cap: this.capability,
    +      iat: utime,
    +      iss: issuer,
    +      sub: this.subject,
    +      state: this.state
    +    };
    +
    +    // TODO: reconcile with JWT spec
    +    // alternatively, since we're already breaking spec,
    +    // we can diverge again here.
    +    // Secret: HS256
    +    const secret = 'ffff';
    +
    +    // Encodings
    +    const encodedHeader = Token.base64UrlEncode(JSON.stringify(header));
    +    const encodedPayload = Token.base64UrlEncode(JSON.stringify(payload));
    +    const signature = bitcoin.crypto.sha256(
    +      Buffer.from(`${encodedHeader}.${encodedPayload}.${secret}`)
    +    );
    +
    +    return [
    +      encodedHeader,
    +      encodedPayload,
    +      Token.base64UrlEncode(signature.toString('hex'))
    +    ].join('.');
    +  }
    +
    +  sign () {
    +    // Sign the capability using the private key
    +    const hash = bitcoin.crypto.sha256(this.capability);
    +    this.signature = schnorr.sign(this.issuer.privateKey, hash);
    +  }
    +
    +  verify () {
    +    // Verify the signature using the public key
    +    const hash = bitcoin.crypto.sha256(this.capability);
    +    return schnorr.verify(this.issuer.publicKey, hash, this.signature);
    +  }
    +
    +  add (other) {
    +    const combinedCapability = [this.capability, other.capability].join(' ');
    +    const combinedToken = new Token({
    +      capability: combinedCapability,
    +      issuer: this.issuer.publicKey
    +    });
    +
    +    /* combinedToken.signature = schnorr.combine([
    +      this.signature,
    +      other.signature
    +    ]); */
    +
    +    return combinedToken;
    +  }
    +}
    +
    +module.exports = Token;
    +
    +
    +
    + + + +
    + +
    + + + + + + \ No newline at end of file diff --git a/docs/types_transition.js.html b/docs/types_transition.js.html index 185da7b26..335c50957 100644 --- a/docs/types_transition.js.html +++ b/docs/types_transition.js.html @@ -160,19 +160,27 @@

    Classes

  • Bitcoin
  • Chain
  • Channel
  • +
  • Circuit
  • CLI
  • Collection
  • Compiler
  • Consensus
  • Entity
  • +
  • Environment
  • Exchange
  • Fabric
  • +
  • Federation
  • +
  • Filesystem
  • Hash256
  • HKDF
  • HTTPServer
  • +
  • Identity
  • Interface
  • Key
  • -
  • KeyStore
  • +
  • Keystore
  • +
  • Ledger
  • +
  • Lightning
  • +
  • Logger
  • Machine
  • Mempool
  • Message
  • @@ -182,6 +190,8 @@

    Classes

  • Peer
  • Reader
  • Redis
  • +
  • Remote
  • +
  • Resource
  • Router
  • Scribe
  • Script
  • @@ -201,6 +211,7 @@

    Classes

  • Vector
  • Walker
  • Wallet
  • +
  • Worker
  • ZMQ
  • Events

    diff --git a/docs/types_tree.js.html b/docs/types_tree.js.html index 2a87b43e0..ada33a220 100644 --- a/docs/types_tree.js.html +++ b/docs/types_tree.js.html @@ -33,11 +33,14 @@

    Source: types/tree.js

    'use strict';
     
    -const Actor = require('./actor');
    -const Hash256 = require('./hash256');
    +// Dependencies
     const merge = require('lodash.merge');
     const { MerkleTree } = require('merkletreejs');
     
    +// Fabric Types
    +const Actor = require('./actor');
    +const Hash256 = require('./hash256');
    +
     /**
      * Class implementing a Merkle Tree.
      */
    @@ -45,7 +48,7 @@ 

    Source: types/tree.js

    /** * Create an instance of a Tree. * @param {Object} [settings] Configuration. - * @returns {Tree} + * @returns {Tree} Instance of the tree. */ constructor (settings = {}) { super(settings); @@ -74,7 +77,7 @@

    Source: types/tree.js

    /** * Add a leaf to the tree. * @param {String} leaf Leaf to add to the tree. - * @returns {Tree} + * @returns {Tree} Instance of the tree. */ addLeaf (leaf = '') { this._tree = new MerkleTree(this.settings.leaves.concat([ @@ -110,52 +113,49 @@

    Home

    Classes

    Events

    diff --git a/docs/types_value.js.html b/docs/types_value.js.html index 4f3f74a01..d440283da 100644 --- a/docs/types_value.js.html +++ b/docs/types_value.js.html @@ -73,52 +73,49 @@

    Home

    Classes

    Events

    diff --git a/docs/types_vector.js.html b/docs/types_vector.js.html index e672add12..abfe0755e 100644 --- a/docs/types_vector.js.html +++ b/docs/types_vector.js.html @@ -140,52 +140,49 @@

    Home

    Classes

    Events

    diff --git a/docs/types_walker.js.html b/docs/types_walker.js.html index 0b506b8e6..30807e5bc 100644 --- a/docs/types_walker.js.html +++ b/docs/types_walker.js.html @@ -120,52 +120,49 @@

    Home

    Classes

    Events

    diff --git a/docs/types_wallet.js.html b/docs/types_wallet.js.html index bcbeeb2c3..63de8ad5a 100644 --- a/docs/types_wallet.js.html +++ b/docs/types_wallet.js.html @@ -33,47 +33,30 @@

    Source: types/wallet.js

    'use strict';
     
    -const config = require('../settings/default');
    -const merge = require('lodash.merge');
    -
     // External Dependencies
     const BN = require('bn.js');
    +const EC = require('elliptic').ec;
    +const merge = require('lodash.merge');
    +const payments = require('bitcoinjs-lib/src/payments');
    +const networks = require('bitcoinjs-lib/src/networks');
    +
    +// Mnemonics
    +const ecc = require('tiny-secp256k1');
    +const BIP32 = require('bip32').default;
    +const bip32 = new BIP32(ecc);
    +const bip39 = require('bip39');
     
     // Types
    +const Key = require('./key');
     const Actor = require('./actor');
    -const EncryptedPromise = require('./promise');
    -const Transaction = require('./transaction');
     const Collection = require('./collection');
    -const Consensus = require('./consensus');
    -const Channel = require('./channel');
    +// const Consensus = require('./consensus');
    +// const Channel = require('./channel');
     const Hash256 = require('./hash256');
     const Service = require('./service');
     const Secret = require('./secret');
     const State = require('./state');
     
    -// Bcoin
    -// For the browser...
    -// const bcoin = require('bcoin/lib/bcoin-browser');
    -// For the node...
    -const bcoin = require('bcoin/lib/bcoin-browser');
    -
    -// TODO: most of these should be converted to use Consensus,
    -// provided above.  Refactor these to use `this.provider` or
    -// `this.consensus` for maximum portability.
    -// ATTN: @martindale
    -// Convenience classes...
    -const Address = bcoin.Address;
    -const Coin = bcoin.Coin;
    -const WalletDB = bcoin.WalletDB;
    -const WalletKey = bcoin.wallet.WalletKey;
    -const Outpoint = bcoin.Outpoint;
    -const Output = bcoin.Output;
    -const Keyring = bcoin.wallet.WalletKey;
    -const Mnemonic = bcoin.hd.Mnemonic;
    -const HD = bcoin.hd;
    -const MTX = bcoin.MTX;
    -const Script = bcoin.Script;
    -
     /**
      * Manage keys and track their balances.
      * @property {String} id Unique identifier for this {@link Wallet}.
    @@ -86,7 +69,7 @@ 

    Source: types/wallet.js

    * @param {Number} [settings.verbosity=2] One of: 0 (none), 1 (error), 2 (warning), 3 (notice), 4 (debug), 5 (audit) * @param {Object} [settings.key] Key to restore from. * @param {String} [settings.key.seed] Mnemonic seed for a restored wallet. - * @return {Wallet} Instance of the wallet. + * @return {Wallet} Instance of the wallet. */ constructor (settings = {}) { super(settings); @@ -95,59 +78,67 @@

    Source: types/wallet.js

    this.marshall = { agents: [], collections: { - transactions: null, // not yet loaded, seek for Buffer, - orders: null + transactions: null } }; this.settings = merge({ name: 'primary', - network: config.network, - language: config.language, + network: 'mainnet', + language: 'english', locktime: 144, decimals: 8, shardsize: 4, verbosity: 2, witness: true, - key: null + key: null, + version: 1, + addressIndex: 0, + gapLimit: 20 }, settings); - bcoin.set(this.settings.network); - - this.database = new WalletDB({ - network: 'regtest' - }); + // Get network configuration + this.network = networks[this.settings.network] || networks.mainnet; + this.database = null; this.account = null; this.manager = null; this.wallet = null; this.master = null; this.ring = null; this.seed = null; - this.key = null; - // TODO: enable wordlist translations - // this.words = Mnemonic.getWordlist(this.settings.language).words; - this.mnemonic = null; - this.index = 0; + // Initialize key management + if (this.settings.key && this.settings.key.seed) { + this.key = new Key({ + seed: this.settings.key.seed, + passphrase: this.settings.key.passphrase || '' + }); + this.seed = this.settings.key.seed; + } else { + this.key = new Key(); + this.seed = this.key.mnemonic; + } + this.wallet = { + keypair: this.key.keypair + }; + // Storage this.accounts = new Collection(); this.addresses = new Collection(); this.keys = new Collection(); this.coins = new Collection(); + this.transactions = new Collection(); + this.txids = new Collection(); + this.outputs = new Collection(); + + // Encrypted Storage this.secrets = new Collection({ methods: { create: this._prepareSecret.bind(this) } }); - this.transactions = new Collection(); - this.txids = new Collection(); - this.outputs = new Collection(); - - this.entity = new Actor(this.settings); - this.consensus = new Consensus(); - // Internal State this._state = merge(this._state, { actors: {}, @@ -156,27 +147,28 @@

    Source: types/wallet.js

    confirmed: 0, unconfirmed: 0 }, - space: {}, // tracks addresses in shard + content: { + balances: { + spendable: 0, + locked: 0 + }, + keys: {}, + transactions: {}, + utxos: [] + }, + labels: [], + space: {}, keys: {}, services: {}, status: 'PAUSED', transactions: {}, orders: {}, - outputs: {} + outputs: {}, + addressIndex: 0, + addresses: {}, + lastUsedIndex: -1 }); - Object.defineProperty(this, 'database', { enumerable: false }); - // TODO: remove these - Object.defineProperty(this, 'accounts', { enumerable: false }); - Object.defineProperty(this, 'addresses', { enumerable: false }); - Object.defineProperty(this, 'utxos', { enumerable: false }); - Object.defineProperty(this, 'keys', { enumerable: false }); - Object.defineProperty(this, 'outputs', { enumerable: false }); - Object.defineProperty(this, 'secrets', { enumerable: false }); - Object.defineProperty(this, 'swarm', { enumerable: false }); - Object.defineProperty(this, 'transactions', { enumerable: false }); - Object.defineProperty(this, 'wallet', { enumerable: false }); - return this; } @@ -188,6 +180,126 @@

    Source: types/wallet.js

    return this.get('/orders'); } + get xprv () { + return this.key.xprv; + } + + get xpub () { + return this.key.xpub; + } + + get version () { + return this.settings.version; + } + + /** + * Create a new seed phrase. + * @param {String} passphrase BIP 39 passphrase for key derivation. + * @returns {FabricSeed} The seed object. + */ + static createSeed (passphrase = '') { + const mnemonic = bip39.generateMnemonic(); + const seed = bip39.mnemonicToSeedSync(mnemonic); + const root = bip32.fromSeed(seed); + return { + phrase: mnemonic, + master: root.privateKey.toString('hex'), + xprv: root.toBase58(), + xpub: root.neutered().toBase58() + }; + } + + /** + * Create a new {@link Wallet} from a seed object. + * @param {FabricSeed} seed Fabric seed. + * @returns {Wallet} Instance of the wallet. + */ + static fromSeed (seed) { + return new Wallet({ + key: { + seed: seed.phrase, + passphrase: '' + } + }); + } + + derive (path = `m/7777'/7777'/0'/0/0`) { + const derived = this.key.derive(path); + return { + privateKey: derived.private, + publicKey: derived.public, + chainCode: derived.chainCode, + depth: derived.depth, + index: derived.index, + parentFingerprint: derived.parentFingerprint, + fingerprint: derived.fingerprint + }; + } + + export () { + return { + type: 'FabricWallet', + object: { + // TODO: export this.logs + // TODO: reduce to C mem equivalent + logs: [ + { method: 'genesis', params: [JSON.stringify({ id: this.id })] }, + { + method: 'transaction', + params: [ + JSON.stringify({ + changes: [ + { method: 'replace', path: '/status', value: 'PAUSED' } + ] + }), + 1 // Version + ] + } + ], + master: { + private: this.key.master.privateKey.toString('hex'), + public: this.key.master.publicKey.toString('hex') + }, + seed: this.key.seed, + xprv: this.key.master.toBase58() + }, + version: this.version + }; + } + + loadTransaction (transaction, labels = []) { + if (!transaction) throw new Error('You must provide a transaction.'); + if (!transaction.id) throw new Error('The transaction must have a "id" property.'); + + const actor = new Actor(transaction); + const transactionObject = actor.toObject(); + + // Store in both places for backward compatibility + this._state.content.transactions[transaction.id] = transactionObject; + this.transactions.set(`/${transaction.id}`, transactionObject); + + if (transaction.spendable) { + this._state.content.utxos.push({ + type: 'UnspentTransactionOutput', + object: { + id: transaction.id + } + }); + } + + this.commit(); + + return this; + } + + /** + * Start the wallet, including listening for transactions. + */ + start () { + this.status = 'STARTING'; + this.status = 'STARTED'; + } + trust (emitter) { const wallet = this; const listener = emitter.on('message', this._handleGenericMessage.bind(this)); @@ -307,55 +419,6 @@

    Source: types/wallet.js

    return null; } - async _createMultisigAddress (m, n, keys) { - let result = null; - - // Check for required fields - if (!m) throw new Error('Parameter 0 required: m'); - if (!m) throw new Error('Parameter 1 required: n'); - if (!keys || !keys.length) throw new Error('Parameter 2 required: keys'); - - try { - // Compose the address - const multisig = Script.fromMultisig(m, n, keys); - const address = multisig.getAddress().toBase58(this.settings.network); - - // TODO: remove this audit message - if (this.settings.verbosity >= 5) console.log('[FABRIC:WALLET]', 'Created multisig address:', address); - - // Assign to output - result = address; - } catch (exception) { - console.error('[FABRIC:WALLET]', 'Could not create multisig address:', exception); - } - - return result; - } - - async _spendToAddress (amount, address) { - const mtx = new MTX(); - const change = await this.wallet.receiveAddress(); - const coins = await this.wallet.getCoins(); - - this.emit('log', `Amount to send: ${amount}`); - - mtx.addOutput({ - address: recipient, - value: parseInt(amount) - }); - - await mtx.fund(coins, { - rate: 10, - changeAddress: change - }); - - const sigs = mtx.sign(this.ring); - const tx = mtx.toTX(); - const valid = tx.check(mtx.view); - - return tx; - } - async _getUnspentOutput (amount) { if (!this._state.utxos.length) throw new Error('No available funds.'); // TODO: use coin selection @@ -383,7 +446,7 @@

    Source: types/wallet.js

    /** * Returns a bech32 address for the provided {@link Script}. - * @param {Script} script + * @param {Script} script */ getAddressForScript (script) { // TODO: use Fabric.Script @@ -394,70 +457,13 @@

    Source: types/wallet.js

    /** * Generate a {@link BitcoinAddress} for the supplied {@link BitcoinScript}. - * @param {BitcoinScript} redeemScript + * @param {BitcoinScript} redeemScript */ getAddressFromRedeemScript (redeemScript) { if (!redeemScript) return null; return Address.fromScripthash(redeemScript.hash160()); } - /** - * Create a priced order. - * @param {Object} order - * @param {Object} order.asset - * @param {Object} order.amount - */ - async createPricedOrder (order) { - if (!order.asset) throw new Error('Order parameter "asset" is required.'); - if (!order.amount) throw new Error('Order parameter "amount" is required.'); - - let leftover = order.amount % (10 * this.settings.decimals); - let parts = order.amount / (10 * this.settings.decimals); - - let partials = []; - // TODO: remove short-circuit - let cb = await this._generateFakeCoinbase(order.amount); - let mtx = new MTX(); - let script = new Script(); - - let secret = await this.generateSecret(); - let image = Buffer.from(secret.hash); - - console.log('secret generated:', secret); - console.log('image of secret:', image); - - let refund = await this.ring.getPublicKey(); - console.log('refund:', refund); - - script.pushSym('OP_IF'); - script.pushSym('OP_SHA256'); - script.pushData(image); - script.pushSym('OP_EQUALVERIFY'); - script.pushData(order.counterparty); - script.pushSym('OP_ELSE'); - script.pushInt(this.settings.locktime); - script.pushSym('OP_CHECKSEQUENCEVERIFY'); - script.pushSym('OP_DROP'); - script.pushData(refund); - script.pushSym('OP_ENDIF'); - script.pushSym('OP_CHECKSIG'); - script.compile(); - - // TODO: complete order construction - for (let i = 0; i < parts; i++) { - // TODO: should be split parts - partials.push(script); - } - - let entity = new Actor({ - comment: 'List of transactions to validate.', - orders: partials, - transactions: partials - }); - - return entity; - } - async createHTLC (contract) { // if (!contract.asset) throw new Error('Contract parameter "asset" is required.'); if (!contract.amount) throw new Error('Contract parameter "amount" is required.'); @@ -571,54 +577,6 @@

    Source: types/wallet.js

    }; } - async generateOrderRootTo (pubkey, amount) { - if (!pubkey) throw new Error(`Parameter "pubkey" is required.`); - if (!amount) throw new Error(`Parameter "amount" is required.`); - - let bn = new BN(amount + '', 10); - // TODO: labeled keypairs - let clean = await this.generateCleanKeyPair(); - let change = await this.generateCleanKeyPair(); - - let mtx = new MTX(); - let cb = await this._generateFakeCoinbase(amount); - - mtx.addOutput({ - address: address, - amount: amount - }); - - await mtx.fund(this._state.utxos, { - rate: 10000, // TODO: fee calculation - changeAddress: change.address - }); - - mtx.sign(this.ring); - // mtx.signInput(0, this.ring); - - let tx = mtx.toTX(); - let output = null; - - try { - output = Coin.fromTX(mtx, 0, -1); - } catch (exception) { - console.error('[FABRIC:WALLET]', 'Could not generate output:', exception); - } - - let raw = mtx.toRaw(); - let hash = Hash256.digest(raw.toString('hex')); - - return { - type: 'BitcoinTransaction', - data: { - tx: tx, - output: output, - raw: raw.toString('hex'), - hash: hash - } - }; - } - addInputForCrowdfund (coin, inputIndex, mtx, keyring, hashType) { let sampleCoin = coin instanceof Coin ? coin : Coin.fromJSON(coin); if (!hashType) hashType = Script.hashType.ANYONECANPAY | Script.hashType.ALL; @@ -749,14 +707,15 @@

    Source: types/wallet.js

    } async getUnusedAddress () { - let clean = await this.wallet.receiveAddress(); - this.emit('log', `unused address: ${clean}`); - return clean; + return this.receiveAddress(); } async getUnspentTransactionOutputs () { - return this._state.transactions.filter(x => { - return (x.spent === 0); + // Convert object to array if needed + const txArray = Array.isArray(this._state.transactions) ? this._state.transactions :Object.values(this._state.content.transactions); + + return txArray.filter(x => { + return !x.spent; }); } @@ -846,7 +805,7 @@

    Source: types/wallet.js

    /** * Signs a transaction with the keyring. - * @param {BcoinTX} tx + * @param {BcoinTX} tx */ async _sign (tx) { let signature = await tx.sign(this.keyring); @@ -857,7 +816,7 @@

    Source: types/wallet.js

    /** * Create a crowdfunding transaction. - * @param {Object} fund + * @param {Object} fund */ async _createCrowdfund (fund = {}) { if (!fund.amount) return null; @@ -878,40 +837,15 @@

    Source: types/wallet.js

    }; } - async _createSeed (password = null) { - const mnemonic = new Mnemonic({ bits: 256 }); - const master = bcoin.hd.fromMnemonic(mnemonic); - - await this._load(); - - const wallet = await this.database.create({ - network: this.settings.network, - master: master - }); - - // TODO: allow override of wallet name - const account = await wallet.getAccount('default'); - const data = { - seed: mnemonic.toString(), - master: master.privateKey.toString('hex'), - xpub: { - meta: { - depth: account.accountKey.depth, - parentFingerPrint: account.accountKey.parentFingerPrint, - childIndex: account.accountKey.childIndex, - chainCode: account.accountKey.chainCode.toString('hex'), - publicKey: account.accountKey.publicKey.toString('hex'), - fingerPrint: account.accountKey.fingerPrint - }, - public: account.accountKey.publicKey.toString('hex') - }, - key: { - private: master.privateKey.toString('hex'), - public: master.publicKey.toString('hex') - } + async _createFromFreshSeed (passphrase = '') { + console.log('creating fresh seed with passphrase:', passphrase); + const key = new Key({ passphrase: passphrase }); + return { + phrase: key.mnemonic, + master: key.master.privateKey.toString('hex'), + xprv: key.master.toBase58(), + xpub: key.master.neutered().toBase58() }; - - return data; } async _importSeed (seed) { @@ -931,14 +865,13 @@

    Source: types/wallet.js

    data.pushData(Buffer.from(config.hash)); data.pushSym('OP_EQUALVERIFY'); data.pushData(Buffer.from(config.payee)); - data.pushSym('OP_CHECKSIG'); data.pushSym('OP_ELSE'); data.pushInt(config.locktime); data.pushSym('OP_CHECKSEQUENCEVERIFY'); data.pushSym('OP_DROP'); data.pushData(Buffer.from(clean.public)); - data.pushSym('OP_CHECKSIG'); data.pushSym('OP_ENDIF'); + data.pushSym('OP_CHECKSIG'); data.compile(); console.log('address data:', data); @@ -1029,7 +962,7 @@

    Source: types/wallet.js

    // Create a mutable transaction object let redeemTX = new MTX(); - // Get the output we want to spend (coins sent to the P2SH address) + // Get the output we want to spend (coins sent to the P2SH address) let coin = Coin.fromTX(fundingTX, fundingTXoutput, -1); // Add that coin as an input to our transaction @@ -1083,8 +1016,8 @@

    Source: types/wallet.js

    /** * Generate {@link Script} for claiming a {@link Swap}. - * @param {*} redeemScript - * @param {*} secret + * @param {*} redeemScript + * @param {*} secret */ async _getSwapInputScript (redeemScript, secret) { let inputSwap = new Script(); @@ -1100,7 +1033,7 @@

    Source: types/wallet.js

    /** * Generate {@link Script} for reclaiming funds commited to a {@link Swap}. - * @param {*} redeemScript + * @param {*} redeemScript */ async _getRefundInputScript (redeemScript) { let inputRefund = new Script(); @@ -1219,7 +1152,8 @@

    Source: types/wallet.js

    // iterate over length of shard, aggregate addresses for (let i = 0; i < size; i++) { - let addr = this.account.deriveReceive(i).getAddress('string', this.settings.network); + // let addr = this.account.deriveReceive(i).getAddress('string', this.settings.network); + const addr = this.key.deriveAccountReceive(i); let address = await this.addresses.create({ string: addr, label: `shared address ${i} for wallet ${this.id}`, @@ -1240,24 +1174,28 @@

    Source: types/wallet.js

    * @param {String} input Hex-encoded string to create key from. */ publicKeyFromString (input) { - const buf = Buffer.from(input, 'hex'); - return bcoin.KeyRing.fromPublic(buf).publicKey; + if (input instanceof Point) { + return new Key({ public: input.encode('hex', true) }); + } + return new Key({ public: input }); } async generateCleanKeyPair () { - if (this.status !== 'loaded') await this._load(); - - this.index++; - - let key = this.master.derivePath(`m/44'/0'/0'/0/${this.index}`); - let keyring = bcoin.KeyRing.fromPrivate(key.privateKey); - - return { - index: this.index, - public: keyring.publicKey.toString('hex'), - address: keyring.getAddress('string'), - keyring: keyring + // Ensure index is a valid number + const index = typeof this.index === 'number' ? this.index : 0; + this.index = index + 1; + + // Use a standard BIP44 path with the index + const path = `m/44'/0'/0'/0/${index}`; + const pair = this.key.derive(path); + + const keypair = { + index: index, + public: pair.public, + private: pair.private }; + + return keypair; } async _handleWalletBalance (balance) { @@ -1301,82 +1239,65 @@

    Source: types/wallet.js

    return this.database.close(); } - /** - * Initialize the wallet, including keys and addresses. - * @param {Object} settings Settings to load. - */ - async _load (settings = {}) { - if (this.wallet) return this; + async receiveAddress () { + const keypair = await this.generateCleanKeyPair(); + return keypair.public.toString('hex'); + } - this.status = 'loading'; - this.master = null; + // Add method to check gap limit + async _checkGapLimit () { + const unusedCount = await this._countUnusedAddresses(); + return unusedCount < this.settings.gapLimit; + } - if (!this.database.db.loaded) { - await this.database.open(); + // Count unused addresses + async _countUnusedAddresses () { + let count = 0; + for (const addr in this._state.addresses) { + if (!this._state.addresses[addr].used) { + count++; + } } + return count; + } - if (this.settings.key && this.settings.key.seed) { - this.emit('log', 'Restoring wallet from seed...'); - if (this.settings.verbosity >= 3) console.log('[AUDIT]', 'Restoring wallet from provided seed:', this.settings.key.seed); - const mnemonic = new Mnemonic(this.settings.key.seed); - this.master = bcoin.hd.fromMnemonic(mnemonic); - this.seed = new EncryptedPromise({ data: this.settings.key.seed }); - } else { - if (this.settings.verbosity >= 3) console.log('[AUDIT]', 'Generating new HD key for wallet...'); - this.master = bcoin.hd.generate(this.settings.network); + // Get the highest used index + async _getHighestUsedIndex () { + let highest = -1; + for (const addr in this._state.addresses) { + const addrInfo = this._state.addresses[addr]; + if (addrInfo.used && addrInfo.index > highest) { + highest = addrInfo.index; + } } + return highest; + } - try { - this.wallet = await this.database.create({ - network: this.settings.network, - master: this.master - }); - } catch (E) { - console.error('Could not create wallet:', E); + // Mark address as used + async markAddressAsUsed (address) { + if (this._state.addresses[address]) { + this._state.addresses[address].used = true; + this._state.addresses[address].lastUsed = Date.now(); + this._state.lastUsedIndex = Math.max( + this._state.lastUsedIndex, + this._state.addresses[address].index + ); + await this.commit(); } - - // Setup Ring - this.ring = new bcoin.KeyRing(this.master, this.settings.network); - this.ring.witness = this.settings.witness; // designates witness - - if (this.settings.verbosity >= 4) console.log('keyring:', this.ring); - if (this.settings.verbosity >= 4) console.log('address from keyring:', this.ring.getAddress().toString()); - - // TODO: allow override of wallet name - this.account = await this.wallet.getAccount('default'); - - // Let's call it a shard! - this.shard = await this.getFirstAddressSlice(this.settings.shardsize); - // console.log('shard created:', await this.addresses.asMerkleTree()); - // console.log('shard created:', this.shard); - - if (this.settings.verbosity >= 3) this.emit('log', `[AUDIT] Wallet account ${JSON.stringify(this.account, null, ' ')}`); - // TODO: also retrieve key for address - // let key = this.master.derivePath('m/44/0/0/0/0'); - // TODO: label as identity address - // this.address = await this.account.receiveAddress(); - // TODO: notify downstream of short-circuit removal - - // finally, assign state... - this._state.transactions = this.settings.transaction; - this._state.orders = this.settings.orders; - this._state.outputs = this.state.actors; - - if (this.settings.verbosity >= 5) console.log('[FABRIC:WALLET]', 'state after loading:', this._state); - - this.status = 'loaded'; - this.emit('ready'); - - return this; } - /** - * Start the wallet, including listening for transactions. - */ - async start () { - this.status = 'STARTING'; - await this._load(); - this.status = 'STARTED'; + // Get all addresses + async getAddresses (includeUnused = false) { + const addresses = []; + for (const addr in this._state.addresses) { + if (includeUnused || this._state.addresses[addr].used) { + addresses.push({ + address: addr, + ...this._state.addresses[addr] + }); + } + } + return addresses; } } @@ -1393,52 +1314,49 @@

    Home

    Classes

    Events

    diff --git a/docs/types_witness.js.html b/docs/types_witness.js.html index 51defd4a0..3ceb40d81 100644 --- a/docs/types_witness.js.html +++ b/docs/types_witness.js.html @@ -197,52 +197,49 @@

    Home

    Classes

    Events

    diff --git a/docs/types_worker.js.html b/docs/types_worker.js.html index d2b03e0e8..052272713 100644 --- a/docs/types_worker.js.html +++ b/docs/types_worker.js.html @@ -102,52 +102,49 @@

    Home

    Classes

    Events

    diff --git a/examples/app.js b/examples/app.js index cb77dc249..06a48c8a9 100644 --- a/examples/app.js +++ b/examples/app.js @@ -5,7 +5,7 @@ // This example is intended for downstream consumers — those seeking to implement client-facing applications using Fabric. // // ## Quickstart -// Ensure that you are using NodeJS `16.17.1` — execute in your clone of the Fabric Core repository. +// Ensure that you are using NodeJS `22.14.0` — execute in your clone of the Fabric Core repository. // // ### Cloning Fabric // Run the following commands: diff --git a/examples/docco.css b/examples/docco.css index b60f6fa3d..c3d580fab 100644 --- a/examples/docco.css +++ b/examples/docco.css @@ -213,7 +213,7 @@ ul.sections > li > div { /*---------------------- Low resolutions (> 320px) ---------------------*/ @media only screen and (min-width: 320px) { - .pilwrap { display: none; } + .sswrap { display: none; } ul.sections > li > div { display: block; @@ -330,12 +330,12 @@ ul.sections > li > div { box-shadow: none; } - .pilwrap { + .sswrap { position: relative; display: inline; } - .pilcrow { + .ss { font: 12px Arial; text-decoration: none; color: #454545; @@ -345,14 +345,14 @@ ul.sections > li > div { opacity: 0; -webkit-transition: opacity 0.2s linear; } - .for-h1 .pilcrow { + .for-h1 .ss { top: 47px; } - .for-h2 .pilcrow, .for-h3 .pilcrow, .for-h4 .pilcrow { + .for-h2 .ss, .for-h3 .ss, .for-h4 .ss { top: 35px; } - ul.sections > li > div.annotation:hover .pilcrow { + ul.sections > li > div.annotation:hover .ss { opacity: 1; } } diff --git a/fixtures.js b/fixtures.js index 4d0b25f80..b1896b336 100644 --- a/fixtures.js +++ b/fixtures.js @@ -5,6 +5,13 @@ const TEST_SEED = 'abandon abandon abandon abandon abandon abandon abandon aband const TEST_XPRV = 'xprv9s21ZrQH143K3h3fDYiay8mocZ3afhfULfb5GX8kCBdno77K4HiA15Tg23wpbeF1pLfs1c5SPmYHrEpTuuRhxMwvKDwqdKiGJS9XFKzUsAF'; const TEST_XPUB = 'xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8'; +const BIP32_VECTOR_1_SEED = '000102030405060708090a0b0c0d0e0f'; +const BIP32_VECTOR_1_M_XPUB = 'xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8'; +const BIP32_VECTOR_1_M_XPRV = 'xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi'; +const BIP32_VECTOR_2_SEED = 'fffcf9f6f3f0edeae7e4e1dedbd8d5d2cfccc9c6c3c0bdbab7b4b1aeaba8a5a29f9c999693908d8a8784817e7b7875726f6c696663605d5a5754514e4b484542'; +const BIP32_VECTOR_2_M_XPUB = 'xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB'; +const BIP32_VECTOR_2_M_XPRV = 'xprv9s21ZrQH143K31xYSDQpPDxsXRTUcvj2iNHm5NUtrGiGG5e2DtALGdso3pGz6ssrdK4PFmM8NSpSBHNqPqm55Qn3LqFtT2emdEXVYsCzC2U'; + // Strings const EMPTY_STRING = ''; const FABRIC_HELLO_WORLD = 'Hello, World!'; @@ -15,6 +22,12 @@ const GITHUB_ISSUE_PATH = 'FabricLabs/fabric/issues/1'; // Module module.exports = { EMPTY_STRING: EMPTY_STRING, + BIP32_VECTOR_1_SEED, + BIP32_VECTOR_1_M_XPUB, + BIP32_VECTOR_1_M_XPRV, + BIP32_VECTOR_2_SEED, + BIP32_VECTOR_2_M_XPUB, + BIP32_VECTOR_2_M_XPRV, FABRIC_HELLO_WORLD: FABRIC_HELLO_WORLD, FABRIC_SEED: TEST_SEED, FABRIC_XPRV: TEST_XPRV, diff --git a/functions/_sortKeys.js b/functions/_sortKeys.js index fdc4df559..ff53a2027 100644 --- a/functions/_sortKeys.js +++ b/functions/_sortKeys.js @@ -4,8 +4,11 @@ * @returns {Object} Re-sorted instance of `state` as provided. */ module.exports = function _sortKeys (state = {}) { + // Sort the keys of the state object, and return a new object with the sorted keys. return Object.keys(state).sort().reduce((obj, key) => { + // Add the key to the new object. obj[key] = state[key]; + // Return the new object. return obj; }, {}); }; diff --git a/validators/hasActor.js b/functions/hasActor.js similarity index 100% rename from validators/hasActor.js rename to functions/hasActor.js diff --git a/validators/hasObject.js b/functions/hasObject.js similarity index 100% rename from validators/hasObject.js rename to functions/hasObject.js diff --git a/validators/hasTarget.js b/functions/hasTarget.js similarity index 100% rename from validators/hasTarget.js rename to functions/hasTarget.js diff --git a/functions/truncateMiddle.js b/functions/truncateMiddle.js new file mode 100644 index 000000000..9e8d6059d --- /dev/null +++ b/functions/truncateMiddle.js @@ -0,0 +1,16 @@ +'use strict'; + +module.exports = function (fullStr, strLen, separator) { + if (fullStr.length <= strLen) return fullStr; + + separator = separator || '...'; + + var sepLen = separator.length, + charsToShow = strLen - sepLen, + frontChars = Math.ceil(charsToShow / 2), + backChars = Math.floor(charsToShow / 2); + + return fullStr.substr(0, frontChars) + + separator + + fullStr.substr(fullStr.length - backChars); +}; diff --git a/guides/ACCESSIBILITY.md b/guides/ACCESSIBILITY.md new file mode 100644 index 000000000..468d4d9d8 --- /dev/null +++ b/guides/ACCESSIBILITY.md @@ -0,0 +1,5 @@ +# Making Fabric Accessible +Fabric aims to be an accessible codebase. + +## Basic Principles +1. Prioritize legibility over cleverness diff --git a/ACTORS.md b/guides/ACTORS.md similarity index 52% rename from ACTORS.md rename to guides/ACTORS.md index 4ef961546..e60a92529 100644 --- a/ACTORS.md +++ b/guides/ACTORS.md @@ -15,8 +15,36 @@ Some Actor types (such as `Service`) also provide `beat`, `tick`, or `state` eve ## Behavior The `Actor` is a standard ECMAScript object with the following properties: - ``` id: String state: Object ``` + +## Example +Interacting with a Fabric Actor: +```js +// Use `npm i @fabric/core` first +const Actor = require('@fabric/core/types/actor'); +const actor = new Actor({ foo: 'bar' }); + +// Listen for events +actor.on('message', (message) => { + console.log('Message from Actor:', message); +}); + +// Adopt a set of changes +actor.adopt([ + { op: 'replace', path: '/baz', value: 'plop' } +]); + +console.log('My Actor:', JSON.stringify(actor, null, ' ')); +``` + +Output: + +``` +My Actor: { + "foo": "bar", + "baz": "bop" +} +``` diff --git a/BEST_PRACTICES.md b/guides/BEST_PRACTICES.md similarity index 97% rename from BEST_PRACTICES.md rename to guides/BEST_PRACTICES.md index 9e8d92cd9..40c49e7c4 100644 --- a/BEST_PRACTICES.md +++ b/guides/BEST_PRACTICES.md @@ -26,7 +26,9 @@ goal being to build Fabric from source and generate a deterministic build. 3. (If Upstream Project Exists) `git push upstream` 5. Click the link in the output of `git push upstream` to acquire SUBMIT_PROPOSAL_HTTP 6. [Submit a Pull Request][submit-a-pull-request]! +3. Use [Nix][nix]. [contributing]: /CONTRIBUTING.md [environment-setup]: https://dev.fabric.pub/documents/environment-setup [404] +[nix]: https://nixos.org [submit-a-pull-request]: https://dev.fabric.pub/documents/submit-a-pull-request [404] diff --git a/BUILD.md b/guides/BUILD.md similarity index 100% rename from BUILD.md rename to guides/BUILD.md diff --git a/guides/CONTRACTS.md b/guides/CONTRACTS.md new file mode 100644 index 000000000..5d5cf7959 --- /dev/null +++ b/guides/CONTRACTS.md @@ -0,0 +1,23 @@ +# Fabric Contracts +Contracts in Fabric are simple agreements between two or more peers. + +## Contract Elements +Fabric Contracts consist of several key components. + +- Initial Contract State +- Contract Messages +- Contract Script (Taproot Program) + +## Using `@fabric/core/types/contract` +The `Contract` type can be imported from `@fabric/core` using the following JavaScript: +```js +const Contract = require('@fabric/core/types/contract`); +``` + +To deploy the contract, fund the deposit address generated by: +```js +const Contract = require('@fabric/core/types/contract`); +const contract = new Contract(); + +contract.deploy(); +``` diff --git a/EXAMPLES.md b/guides/EXAMPLES.md similarity index 100% rename from EXAMPLES.md rename to guides/EXAMPLES.md diff --git a/SERVICES.md b/guides/SERVICES.md similarity index 100% rename from SERVICES.md rename to guides/SERVICES.md diff --git a/SETTINGS.md b/guides/SETTINGS.md similarity index 100% rename from SETTINGS.md rename to guides/SETTINGS.md diff --git a/index.d.ts b/index.d.ts deleted file mode 100644 index 5f8dc74b8..000000000 --- a/index.d.ts +++ /dev/null @@ -1 +0,0 @@ -declare module '@fabric/core'; diff --git a/package-lock.json b/package-lock.json index 90294f2e8..cf4191397 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,65 +9,90 @@ "version": "0.1.0-RC1", "license": "MIT", "dependencies": { - "arbitrary": "1.4.10", - "base58check": "2.0.0", - "bech32-buffer": "0.2.0", - "bip-schnorr": "0.6.6", - "bip32": "3.0.1", - "bip39": "3.0.4", - "bip65": "1.0.3", - "bip68": "1.0.4", - "bitcoinjs-lib": "6.0.0", - "blessed": "0.1.81", - "commander": "6.1.0", - "content-type": "1.0.4", - "cross-fetch": "3.1.5", - "dotparser": "0.3.0", - "ecpair": "2.0.1", - "elliptic": "6.5.4", - "fast-json-patch": "3.1.1", - "javascript-state-machine": "3.1.0", - "jayson": "4.0.0", - "json-pointer": "0.6.2", - "level": "7.0.1", - "lodash.merge": "4.6.2", - "merkletreejs": "0.1.6", - "minsc": "0.2.0", - "mkdirp": "1.0.4", - "noise-protocol-stream": "1.1.3", - "path-match": "1.2.4", - "pluralize": "8.0.0", - "redis": "3.1.2", - "rimraf": "2.6.2", - "simple-aes": "0.1.1", - "struct": "0.0.12", - "tiny-secp256k1": "2.2.1", - "zeromq": "5.2.8" + "arbitrary": "=1.4.10", + "bech32-buffer": "=0.2.1", + "bip-schnorr": "=0.6.7", + "bip32": "=4.0.0", + "bip39": "=3.1.0", + "bip65": "=1.0.3", + "bip68": "=1.0.4", + "bitcoinjs-lib": "=6.1.7", + "blessed": "=0.1.81", + "bn.js": "=5.2.1", + "commander": "=13.1.0", + "content-type": "=1.0.5", + "cross-fetch": "=4.1.0", + "dotparser": "=1.1.1", + "ecpair": "=2.1.0", + "elliptic": "=6.6.1", + "events": "=3.3.0", + "fast-json-patch": "=3.1.1", + "javascript-state-machine": "=3.1.0", + "jayson": "=4.1.3", + "json-pointer": "=0.6.2", + "jsonpointer": "=5.0.1", + "level": "=9.0.0", + "lodash.merge": "=4.6.2", + "macaroon": "=3.0.4", + "merkletreejs": "=0.4.1", + "minsc": "=0.2.0", + "mkdirp": "=3.0.1", + "noise-protocol-stream": "=1.1.3", + "path-match": "=1.2.4", + "pluralize": "=8.0.0", + "redis": "=4.7.0", + "simple-aes": "=0.1.1", + "struct": "=0.0.12", + "tiny-secp256k1": "=2.2.3", + "zeromq": "=6.3.0" }, "bin": { "fabric": "scripts/cli.js" }, "devDependencies": { - "c8": "7.11.3", - "chai": "4.0.2", - "cross-env": "5.1.3", - "debug-trace": "2.2.1", - "docco": "0.9.1", - "eccrypto": "1.0.3", - "eslint": "5.16.0", - "glob-run": "0.1.7", - "honkit": "4.0.4", - "http-server": "14.1.1", - "is-my-json-valid": "2.20.6", - "js-beautify": "1.14.3", - "jsdoc": "3.6.11", - "jsdoc-to-markdown": "7.1.1", - "json-to-dot": "1.1.0", - "license-checker": "25.0.1", - "mocha": "10.0.0" - }, - "engines": { - "node": "16.17.1" + "buffer": "=6.0.3", + "c8": "=10.1.3", + "chai": "=4.0.2", + "cross-env": "=7.0.3", + "debug-trace": "=2.2.3", + "docco": "=0.9.1", + "eslint": "=9.19.0", + "honkit": "=6.0.2", + "http-server": "=14.1.1", + "is-my-json-valid": "=2.20.6", + "js-beautify": "=1.15.1", + "jsdoc": "=4.0.4", + "jsdoc-to-markdown": "=9.1.1", + "json-to-dot": "=1.1.0", + "mocha": "=11.1.0" + }, + "engines": { + "node": "22.14.0" + } + }, + "node_modules/@aminya/cmake-ts": { + "version": "0.3.0-aminya.7", + "resolved": "https://registry.npmjs.org/@aminya/cmake-ts/-/cmake-ts-0.3.0-aminya.7.tgz", + "integrity": "sha512-y6a2Nq1Pj+3Y0tOLob2q0LbCB4cGIbcXJqDO10W51XpqUdB30OU0Xvl6ZDHFluHm/8nY5Vx/Ua9mxobG975//Q==", + "license": "MIT", + "dependencies": { + "@cypress/request": "^3.0.5", + "fast-glob": "^3.3.2", + "fs-extra": "^10", + "lodash": "^4.17.21", + "memory-stream": "1.0.0", + "minizlib": "^2", + "npmlog": "^6", + "resolve": "^1.22.8", + "semver": "^7.6.3", + "splitargs2": "^0.1.3", + "tar": "^6", + "unzipper": "^0.12.3", + "url-join": "^4.0.1", + "which": "^2" + }, + "bin": { + "cmake-ts": "build/main.js" } }, "node_modules/@asciidoctor/cli": { @@ -75,6 +100,7 @@ "resolved": "https://registry.npmjs.org/@asciidoctor/cli/-/cli-3.5.0.tgz", "integrity": "sha512-/VMHXcZBnZ9vgWfmqk9Hu0x0gMjPLup0YGq/xA8qCQuk11kUIZNMVQwgSsIUzOEwJqIUD7CgncJdtfwv1Ndxuw==", "dev": true, + "license": "MIT", "dependencies": { "yargs": "16.2.0" }, @@ -90,11 +116,53 @@ "@asciidoctor/core": "^2.0.0-rc.1" } }, + "node_modules/@asciidoctor/cli/node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/@asciidoctor/cli/node_modules/yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, + "license": "MIT", + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@asciidoctor/cli/node_modules/yargs-parser": { + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, "node_modules/@asciidoctor/core": { - "version": "2.2.6", - "resolved": "https://registry.npmjs.org/@asciidoctor/core/-/core-2.2.6.tgz", - "integrity": "sha512-TmB2K5UfpDpSbCNBBntXzKHcAk2EA3/P68jmWvmJvglVUdkO9V6kTAuXVe12+h6C4GK0ndwuCrHHtEVcL5t6pQ==", + "version": "2.2.8", + "resolved": "https://registry.npmjs.org/@asciidoctor/core/-/core-2.2.8.tgz", + "integrity": "sha512-oozXk7ZO1RAd/KLFLkKOhqTcG4GO3CV44WwOFg2gMcCsqCUTarvMT7xERIoWW2WurKbB0/ce+98r01p8xPOlBw==", "dev": true, + "license": "MIT", "dependencies": { "asciidoctor-opal-runtime": "0.3.3", "unxhr": "1.0.1" @@ -105,279 +173,764 @@ "yarn": ">=1.1.0" } }, - "node_modules/@babel/code-frame": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", - "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", + "node_modules/@babel/helper-string-parser": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", "dev": true, - "dependencies": { - "@babel/highlight": "^7.18.6" - }, + "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", - "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz", + "integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==", "dev": true, + "license": "MIT", "engines": { "node": ">=6.9.0" } }, - "node_modules/@babel/highlight": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", - "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", + "node_modules/@babel/parser": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.4.tgz", + "integrity": "sha512-yZbBqeM6TkpP9du/I2pUZnJsRMGGvOuIrhjzC1AwHwW+6he4mni6Bp/m8ijn0iOuZuPI2BfkCoSRunpyjnrQKg==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-validator-identifier": "^7.18.6", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" + "@babel/types": "^7.28.4" + }, + "bin": { + "parser": "bin/babel-parser.js" }, "engines": { - "node": ">=6.9.0" + "node": ">=6.0.0" } }, - "node_modules/@babel/parser": { - "version": "7.20.15", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.15.tgz", - "integrity": "sha512-DI4a1oZuf8wC+oAJA9RW6ga3Zbe8RZFt7kD9i4qAspz3I/yHet1VvC3DiSy/fsUvv5pvJuNPh0LPOdCcqinDPg==", + "node_modules/@babel/types": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.4.tgz", + "integrity": "sha512-bkFqkLhh3pMBUQQkpVgWDWq/lqzc2678eUyDlTBhRqhCHFguYYGM0Efga7tYk4TogG/3x0EEl66/OQ+WGbWB/Q==", "dev": true, - "bin": { - "parser": "bin/babel-parser.js" + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.27.1" }, "engines": { - "node": ">=6.0.0" + "node": ">=6.9.0" } }, "node_modules/@bcoe/v8-coverage": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", - "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", - "dev": true + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-1.0.2.tgz", + "integrity": "sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/@cypress/request": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/@cypress/request/-/request-3.0.9.tgz", + "integrity": "sha512-I3l7FdGRXluAS44/0NguwWlO83J18p0vlr2FYHrJkWdNYhgVoiYo61IXPqaOsL+vNxU1ZqMACzItGK3/KKDsdw==", + "license": "Apache-2.0", + "dependencies": { + "aws-sign2": "~0.7.0", + "aws4": "^1.8.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", + "forever-agent": "~0.6.1", + "form-data": "~4.0.4", + "http-signature": "~1.4.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.19", + "performance-now": "^2.1.0", + "qs": "6.14.0", + "safe-buffer": "^5.1.2", + "tough-cookie": "^5.0.0", + "tunnel-agent": "^0.6.0", + "uuid": "^8.3.2" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.9.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.0.tgz", + "integrity": "sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz", + "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/config-array": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.19.2.tgz", + "integrity": "sha512-GNKqxfHG2ySmJOBSHg7LxeUx4xpuCoFjacmlCoYWEbaPXLwvfIjixRI12xCQZeULksQb23uiA8F40w5TojpV7w==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/object-schema": "^2.1.6", + "debug": "^4.3.1", + "minimatch": "^3.1.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/core": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.10.0.tgz", + "integrity": "sha512-gFHJ+xBOo4G3WRlR1e/3G8A6/KZAH6zcE/hkLRCZTi/B9avAG365QhFA8uOGzTMqgTghpn7/fSnscW++dpMSAw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.15" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.1.tgz", + "integrity": "sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^10.0.1", + "globals": "^14.0.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/js": { + "version": "9.19.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.19.0.tgz", + "integrity": "sha512-rbq9/g38qjfqFLOVPvwjIvFFdNziEC5S65jmjPw5r6A//QH+W91akh9irMwjDN8zKUTak6W9EsAv4m/7Wnw0UQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/object-schema": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.6.tgz", + "integrity": "sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/plugin-kit": { + "version": "0.2.8", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.8.tgz", + "integrity": "sha512-ZAoA40rNMPwSm+AeHpCq8STiNAwzWLJuP8Xv4CHIc9wv/PSuExjMrmjfYNj682vW0OOiZ1HKxzvjQr9XZIisQA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.13.0", + "levn": "^0.4.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/plugin-kit/node_modules/@eslint/core": { + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.13.0.tgz", + "integrity": "sha512-yfkgDw1KR66rkT5A8ci4irzDysN7FRpq3ttJolR88OqQikAWqwA8j5VZyas+vjyBNFIJ7MfybJ9plMILI2UrCw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.15" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } }, "node_modules/@honkit/asciidoc": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@honkit/asciidoc/-/asciidoc-4.0.1.tgz", - "integrity": "sha512-R+Og2PaOO5LPXgfsc2k23bSxeTjfJgNMmBB6xodaMmAwYIMs4HApStWGLKik7WQjoIXsNzD67z4eUlTsJcOReA==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/@honkit/asciidoc/-/asciidoc-6.0.2.tgz", + "integrity": "sha512-6lo5fhJUOQx7bRvfVZj4So8JTJeQR2a8rL5rQ1iozvkDe9/JFbpyV72wZxWDd9b/yaK0/5yflZUe0UNENQz9rg==", "dev": true, + "license": "Apache-2.0", "dependencies": { - "@honkit/html": "^4.0.1", - "asciidoctor": "^2.2.0", - "lodash": "^4.13.1" + "@honkit/html": "6.0.2", + "asciidoctor": "^2.2.8", + "lodash": "^4.17.21" + } + }, + "node_modules/@honkit/honkit-plugin-fontsettings": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/@honkit/honkit-plugin-fontsettings/-/honkit-plugin-fontsettings-6.0.2.tgz", + "integrity": "sha512-P2mj7/cDAIRkZCwFKhe3JNJw0rvcH6XKdc9xihKDJEI+w01fGT5ox/jnkY4UNz6kVfjDpriEr96e/OU2OCxNJQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "gitbook": ">=2.4.0" } }, "node_modules/@honkit/honkit-plugin-highlight": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@honkit/honkit-plugin-highlight/-/honkit-plugin-highlight-4.0.0.tgz", - "integrity": "sha512-3T1s12gbLVN/pKbngrkItXLE7ubDBoHK+ILHAjmPw/TYd92wMT4bcL7TUZZALjBhUR3tBj7+kofssxAxDECPOA==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/@honkit/honkit-plugin-highlight/-/honkit-plugin-highlight-6.0.2.tgz", + "integrity": "sha512-/9+Lkj8yLstTtZrwbjq530q2KZCRQZT6KWEI8d63vHnczuj6Mb6RmPXEeT4m4slxYgCdYn52ZskRMg9NKK+IlA==", "dev": true, + "license": "Apache-2.0", "dependencies": { - "highlight.js": "^10.7.1" + "highlight.js": "^11.10.0" }, "engines": { "gitbook": ">=2.4.0" } }, - "node_modules/@honkit/honkit-plugin-highlight/node_modules/highlight.js": { - "version": "10.7.3", - "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.7.3.tgz", - "integrity": "sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==", + "node_modules/@honkit/honkit-plugin-highlight/node_modules/highlight.js": { + "version": "11.11.1", + "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-11.11.1.tgz", + "integrity": "sha512-Xwwo44whKBVCYoliBQwaPvtd/2tYFkRQtXDWj1nackaV2JPXx3L0+Jvd8/qCJ2p+ML0/XVkJ2q+Mr+UVdpJK5w==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@honkit/honkit-plugin-theme-default": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/@honkit/honkit-plugin-theme-default/-/honkit-plugin-theme-default-6.0.2.tgz", + "integrity": "sha512-7qxJQDO+MA+tvJvQOexe00m1jMQ4U3dKXYPI1beetZCXV951NTQjKqKr4vCWLbOYXTdu4DALNrOg3+OyTvACeQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "gitbook": ">=3.0.0" + } + }, + "node_modules/@honkit/html": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/@honkit/html/-/html-6.0.2.tgz", + "integrity": "sha512-28GlMEvBex9kfcqhKCDNJcBY+DV3XW2FLAJlcjuZO99SMktQe+4LDLNuoSi9mY+Z120Xwl92h7VBrXFJIY2bmA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "cheerio": "^1.0.0", + "lodash": "^4.17.21", + "q": "^1.5.1" + } + }, + "node_modules/@honkit/markdown-legacy": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/@honkit/markdown-legacy/-/markdown-legacy-6.0.2.tgz", + "integrity": "sha512-Fvn794bf0cA20dKHGzdLkYiT1PXPZKdrZGXRMroXtToSbE5iM+eZ5QDBPD197gMTDlpo7HHChoxRMo1aReUikQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@honkit/html": "6.0.2", + "kramed": "0.5.6", + "lodash": "^4.17.21" + } + }, + "node_modules/@humanfs/core": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", + "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node": { + "version": "0.16.7", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.7.tgz", + "integrity": "sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanfs/core": "^0.19.1", + "@humanwhocodes/retry": "^0.4.0" + }, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/retry": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", + "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-regex": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@isaacs/cliui/node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@isaacs/cliui/node_modules/strip-ansi": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz", + "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/@istanbuljs/schema": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", + "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@jsdoc/salty": { + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/@jsdoc/salty/-/salty-0.2.9.tgz", + "integrity": "sha512-yYxMVH7Dqw6nO0d5NIV8OQWnitU8k6vXH8NtgqAfIa/IUqRMxRv/NUJJ08VEKbAakwxlgBl5PJdrU0dMPStsnw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "lodash": "^4.17.21" + }, + "engines": { + "node": ">=v12.0.0" + } + }, + "node_modules/@noble/hashes": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.8.0.tgz", + "integrity": "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==", + "license": "MIT", + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@one-ini/wasm": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@one-ini/wasm/-/wasm-0.1.1.tgz", + "integrity": "sha512-XuySG1E38YScSJoMlqovLru4KTUNSjgVTIjyh7qMX6aNN5HY5Ct5LhRJdxO79JtTzKfzV/bnWpz+zquYrISsvw==", "dev": true, - "engines": { - "node": "*" - } + "license": "MIT" }, - "node_modules/@honkit/honkit-plugin-theme-default": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/@honkit/honkit-plugin-theme-default/-/honkit-plugin-theme-default-4.0.3.tgz", - "integrity": "sha512-bGCkFLASQF1PAb5HWgaei33uhOLVGM3ZiwUs5BJszumKSJAGaz/X2epRH6DrIlDG+I93COZsoGV1BVOj3gzLaA==", + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", "dev": true, + "license": "MIT", + "optional": true, "engines": { - "gitbook": ">=3.0.0" + "node": ">=14" } }, - "node_modules/@honkit/html": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@honkit/html/-/html-4.0.1.tgz", - "integrity": "sha512-EB0k42QJbETe4vNgRfT5Kn9BFchNES20bmlDY7il989F/eYxCf+f8SduEcs6hsxpG1DemsR09x8Jz19WHXMTIA==", - "dev": true, - "dependencies": { - "cheerio": "^1.0.0-rc.12", - "lodash": "^4.13.1", - "q": "^1.1.2" + "node_modules/@redis/bloom": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@redis/bloom/-/bloom-1.2.0.tgz", + "integrity": "sha512-HG2DFjYKbpNmVXsa0keLHp/3leGJz1mjh09f2RLGGLQZzSHpkmZWuwJbAvo3QcRY8p80m5+ZdXZdYOSBLlp7Cg==", + "license": "MIT", + "peerDependencies": { + "@redis/client": "^1.0.0" } }, - "node_modules/@honkit/markdown-legacy": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@honkit/markdown-legacy/-/markdown-legacy-4.0.1.tgz", - "integrity": "sha512-5vzbvXU28SOJLEaEBjZY/57dV2Gol6kpJGkLkBVY4z29aLzugepXLOPuVA9X3X6Dbmzz3ws37siAf7/+8NLihw==", - "dev": true, + "node_modules/@redis/client": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@redis/client/-/client-1.6.0.tgz", + "integrity": "sha512-aR0uffYI700OEEH4gYnitAnv3vzVGXCFvYfdpu/CJKvk4pHfLPEy/JSZyrpQ+15WhXe1yJRXLtfQ84s4mEXnPg==", + "license": "MIT", "dependencies": { - "@honkit/html": "^4.0.1", - "kramed": "0.5.6", - "lodash": "^4.13.1" + "cluster-key-slot": "1.1.2", + "generic-pool": "3.9.0", + "yallist": "4.0.0" + }, + "engines": { + "node": ">=14" } }, - "node_modules/@istanbuljs/schema": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", - "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", - "dev": true, - "engines": { - "node": ">=8" + "node_modules/@redis/graph": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@redis/graph/-/graph-1.1.1.tgz", + "integrity": "sha512-FEMTcTHZozZciLRl6GiiIB4zGm5z5F3F6a6FZCyrfxdKOhFlGkiAqlexWMBzCi4DcRoyiOsuLfW+cjlGWyExOw==", + "license": "MIT", + "peerDependencies": { + "@redis/client": "^1.0.0" } }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", - "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", - "dev": true, - "engines": { - "node": ">=6.0.0" + "node_modules/@redis/json": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/@redis/json/-/json-1.0.7.tgz", + "integrity": "sha512-6UyXfjVaTBTJtKNG4/9Z8PSpKE6XgSyEb8iwaqDcy+uKrd/DGYHTWkUdnQDyzm727V7p21WUMhsqz5oy65kPcQ==", + "license": "MIT", + "peerDependencies": { + "@redis/client": "^1.0.0" } }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.14", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", - "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", - "dev": true + "node_modules/@redis/search": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@redis/search/-/search-1.2.0.tgz", + "integrity": "sha512-tYoDBbtqOVigEDMAcTGsRlMycIIjwMCgD8eR2t0NANeQmgK/lvxNAvYyb6bZDD4frHRhIHkJu2TBRvB0ERkOmw==", + "license": "MIT", + "peerDependencies": { + "@redis/client": "^1.0.0" + } }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.17", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz", - "integrity": "sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==", - "dev": true, - "dependencies": { - "@jridgewell/resolve-uri": "3.1.0", - "@jridgewell/sourcemap-codec": "1.4.14" + "node_modules/@redis/time-series": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@redis/time-series/-/time-series-1.1.0.tgz", + "integrity": "sha512-c1Q99M5ljsIuc4YdaCwfUEXsofakb9c8+Zse2qxTadu8TalLXuAESzLvFAvNVbkmSlvlzIQOLpBCmWI9wTOt+g==", + "license": "MIT", + "peerDependencies": { + "@redis/client": "^1.0.0" } }, - "node_modules/@jsdoc/salty": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/@jsdoc/salty/-/salty-0.2.3.tgz", - "integrity": "sha512-bbtCxCkxcnWhi50I+4Lj6mdz9w3pOXOgEQrID8TCZ/DF51fW7M9GCQW2y45SpBDdHd1Eirm1X/Cf6CkAAe8HPg==", - "dev": true, - "dependencies": { - "lodash": "^4.17.21" - }, - "engines": { - "node": ">=v12.0.0" + "node_modules/@scure/base": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.2.6.tgz", + "integrity": "sha512-g/nm5FgUa//MCj1gV09zTJTaM6KBAHqLN907YVQqf7zC49+DcO4B1so4ZX07Ef10Twr6nuqYEH9GEggFXA4Fmg==", + "license": "MIT", + "funding": { + "url": "https://paulmillr.com/funding/" } }, "node_modules/@types/connect": { - "version": "3.4.35", - "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz", - "integrity": "sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==", + "version": "3.4.38", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", + "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", + "license": "MIT", "dependencies": { "@types/node": "*" } }, + "node_modules/@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/istanbul-lib-coverage": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz", - "integrity": "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==", - "dev": true + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", + "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true, + "license": "MIT" }, "node_modules/@types/linkify-it": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-3.0.2.tgz", - "integrity": "sha512-HZQYqbiFVWufzCwexrvh694SOim8z2d+xJl5UNamcvQFejLY/2YUtzXHYi3cHdI7PMlS8ejH2slRAOJQ32aNbA==", - "dev": true + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-5.0.0.tgz", + "integrity": "sha512-sVDA58zAw4eWAffKOaQH5/5j3XeayukzDk+ewSsnv3p4yJEZHCCzMDiZM8e0OUrRvmpGZ85jf4yDHkHsgBNr9Q==", + "dev": true, + "license": "MIT" }, "node_modules/@types/markdown-it": { - "version": "12.2.3", - "resolved": "https://registry.npmjs.org/@types/markdown-it/-/markdown-it-12.2.3.tgz", - "integrity": "sha512-GKMHFfv3458yYy+v/N8gjufHO6MSZKCOXpZc5GXIWWy8uldwfmPn98vp81gZ5f9SVw8YYBctgfJ22a2d7AOMeQ==", + "version": "14.1.2", + "resolved": "https://registry.npmjs.org/@types/markdown-it/-/markdown-it-14.1.2.tgz", + "integrity": "sha512-promo4eFwuiW+TfGxhi+0x3czqTYJkG8qB17ZUJiVF10Xm7NLVRSLUsfRTU/6h1e24VvRnXCx+hG7li58lkzog==", "dev": true, + "license": "MIT", "dependencies": { - "@types/linkify-it": "*", - "@types/mdurl": "*" + "@types/linkify-it": "^5", + "@types/mdurl": "^2" } }, "node_modules/@types/mdurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@types/mdurl/-/mdurl-1.0.2.tgz", - "integrity": "sha512-eC4U9MlIcu2q0KQmXszyn5Akca/0jrQmwDRgpAMJai7qBWq4amIQhZyNau4VYGtCeALvW1/NtjzJJ567aZxfKA==", - "dev": true + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@types/mdurl/-/mdurl-2.0.0.tgz", + "integrity": "sha512-RGdgjQUZba5p6QEFAVx2OGb8rQDL/cPRG7GiedRzMcJ1tYnUANBncjbSB1NRGwbvjcPeikRABz2nshyPk1bhWg==", + "dev": true, + "license": "MIT" }, "node_modules/@types/node": { - "version": "10.12.18", - "resolved": "https://registry.npmjs.org/@types/node/-/node-10.12.18.tgz", - "integrity": "sha512-fh+pAqt4xRzPfqA6eh3Z2y6fyZavRIumvjhaCL753+TVkGKGhpPeyrJG2JftD0T9q4GF00KjefsQ+PQNDdWQaQ==" + "version": "12.20.55", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.55.tgz", + "integrity": "sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==", + "license": "MIT" }, "node_modules/@types/ws": { "version": "7.4.7", "resolved": "https://registry.npmjs.org/@types/ws/-/ws-7.4.7.tgz", "integrity": "sha512-JQbbmxZTZehdc2iszGKs5oC3NFnjeay7mtAWrdt7qNtAVK0g19muApzAy4bm9byz79xa2ZnO/BOBC2R8RC5Lww==", + "license": "MIT", "dependencies": { "@types/node": "*" } }, - "node_modules/@ungap/promise-all-settled": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz", - "integrity": "sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q==", - "dev": true - }, "node_modules/a-sync-waterfall": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/a-sync-waterfall/-/a-sync-waterfall-1.0.1.tgz", "integrity": "sha512-RYTOHHdWipFUliRFMCS4X2Yn2X8M87V/OpSqWzKKOGhzqyUxzyVmhHDH9sAvG+ZuQf/TAOFsLCpMw09I1ufUnA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/abbrev": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", - "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", - "dev": true + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-2.0.0.tgz", + "integrity": "sha512-6/mh1E2u2YgEsCHdY0Yx5oW+61gZU+1vXaoiHHrpKeuRNNgFvS+/jrwHiQhB5apAf5oB7UB7E19ol2R2LKH8hQ==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } }, - "node_modules/abstract-leveldown": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/abstract-leveldown/-/abstract-leveldown-7.2.0.tgz", - "integrity": "sha512-DnhQwcFEaYsvYDnACLZhMmCWd3rkOeEvglpa4q5i/5Jlm3UIsWaxVzuXvDLFCSCWRO3yy2/+V/G7FusFgejnfQ==", + "node_modules/abstract-level": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/abstract-level/-/abstract-level-2.0.2.tgz", + "integrity": "sha512-pPJixmXk/kTKLB2sSue7o4Uj6TlLD2XfaP2gWZomHVCC6cuUGX/VslQqKG1yZHfXwBb/3lS6oSTMPGzh1P1iig==", + "license": "MIT", "dependencies": { "buffer": "^6.0.3", - "catering": "^2.0.0", "is-buffer": "^2.0.5", - "level-concat-iterator": "^3.0.0", - "level-supports": "^2.0.1", - "queue-microtask": "^1.2.3" + "level-supports": "^6.0.0", + "level-transcoder": "^1.0.1", + "maybe-combine-errors": "^1.0.0", + "module-error": "^1.0.1" }, "engines": { - "node": ">=10" - } - }, - "node_modules/abstract-leveldown/node_modules/buffer": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", - "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "dependencies": { - "base64-js": "^1.3.1", - "ieee754": "^1.2.1" + "node": ">=16" } }, "node_modules/acorn": { - "version": "6.4.2", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.2.tgz", - "integrity": "sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ==", + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", + "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "dev": true, + "license": "MIT", "bin": { "acorn": "bin/acorn" }, @@ -390,6 +943,7 @@ "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", "dev": true, + "license": "MIT", "peerDependencies": { "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } @@ -399,6 +953,7 @@ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "dev": true, + "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -411,63 +966,38 @@ } }, "node_modules/ansi-colors": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", - "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/ansi-escape-sequences": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-escape-sequences/-/ansi-escape-sequences-4.1.0.tgz", - "integrity": "sha512-dzW9kHxH011uBsidTXd14JXgzye/YLb2LzeKZ4bsgl/Knwx8AtbSFkkGxagdNOoh0DlqHCmfiEjWKBaqjOanVw==", - "dev": true, - "dependencies": { - "array-back": "^3.0.1" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/ansi-escape-sequences/node_modules/array-back": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/array-back/-/array-back-3.1.0.tgz", - "integrity": "sha512-TkuxA4UCOvxuDK6NZYXCalszEzj+TLszyASooky+i742l9TqsOdYCMJJupxRic61hwquNtppB3hgcuq9SVSH1Q==", + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", + "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } }, - "node_modules/ansi-escapes": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz", - "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==", - "dev": true, - "engines": { - "node": ">=4" - } - }, "node_modules/ansi-regex": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.1.tgz", - "integrity": "sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw==", - "dev": true, + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", "engines": { - "node": ">=4" + "node": ">=8" } }, "node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, + "license": "MIT", "dependencies": { - "color-convert": "^1.9.0" + "color-convert": "^2.0.1" }, "engines": { - "node": ">=4" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, "node_modules/anymatch": { @@ -475,6 +1005,7 @@ "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", "dev": true, + "license": "ISC", "dependencies": { "normalize-path": "^3.0.0", "picomatch": "^2.0.4" @@ -483,25 +1014,59 @@ "node": ">= 8" } }, + "node_modules/aproba": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.1.0.tgz", + "integrity": "sha512-tLIEcj5GuR2RSTnxNKdkK0dJ/GrC7P38sUkiDmDuHfsHmbagTFAxDVIBltoklXEVIQ/f14IL8IMJ5pn9Hez1Ew==", + "license": "ISC" + }, "node_modules/arbitrary": { "version": "1.4.10", "resolved": "https://registry.npmjs.org/arbitrary/-/arbitrary-1.4.10.tgz", - "integrity": "sha512-YU4rMv5yk9GS/1e8pWgrhnWfnE3SaTnS17fcX2VEY2stilqL5++SI4nPAyF5RZkY2DWRkXy/i+Opl8XHBNvNSA==" + "integrity": "sha512-YU4rMv5yk9GS/1e8pWgrhnWfnE3SaTnS17fcX2VEY2stilqL5++SI4nPAyF5RZkY2DWRkXy/i+Opl8XHBNvNSA==", + "license": "MIT" }, - "node_modules/argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, + "node_modules/are-we-there-yet": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-3.0.1.tgz", + "integrity": "sha512-QZW4EDmGwlYur0Yyf/b2uGucHQMa8aFUP7eu9ddR73vvhFyt4V0Vl3QHPcTNJ8l6qYOBdxgXdnBXQrHilfRQBg==", + "deprecated": "This package is no longer supported.", + "license": "ISC", "dependencies": { - "sprintf-js": "~1.0.2" + "delegates": "^1.0.0", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/are-we-there-yet/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" } }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "license": "Python-2.0" + }, "node_modules/array-back": { "version": "6.2.2", "resolved": "https://registry.npmjs.org/array-back/-/array-back-6.2.2.tgz", "integrity": "sha512-gUAZ7HPyb4SJczXAMUXMGAvI976JoK3qEx9v1FTmeYuJj0IBiaKttG1ydtGKdkfqWkIkouke7nG8ufGy77+Cvw==", "dev": true, + "license": "MIT", "engines": { "node": ">=12.17" } @@ -510,31 +1075,25 @@ "version": "0.0.1", "resolved": "https://registry.npmjs.org/array-difference/-/array-difference-0.0.1.tgz", "integrity": "sha512-LMXXDKmRSsO+d7N73LyTBWlT+GiLfNUCWeeWmZivzJ1NxSPOobS+w8bIAAfGEV35oVBsk9u9cXii8dDceU5NPw==", - "dev": true - }, - "node_modules/array-find-index": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz", - "integrity": "sha512-M1HQyIXcBGtVywBt8WVdim+lrNaK7VHp99Qt5pSNziXznKHViIBbXWtfRTpEFpF/c4FdfxNAsCCwPp5phBYJtw==", "dev": true, - "engines": { - "node": ">=0.10.0" - } + "license": "MIT Expat" }, "node_modules/asap": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/asciidoctor": { - "version": "2.2.6", - "resolved": "https://registry.npmjs.org/asciidoctor/-/asciidoctor-2.2.6.tgz", - "integrity": "sha512-EXG3+F2pO21B+COfQmV/WgEgGiy7nG/mJiS/o5DXpaT2q82FRZWPVkbMZrpDvpu4pjXe5c754RbZR9Vz0L0Vtw==", + "version": "2.2.8", + "resolved": "https://registry.npmjs.org/asciidoctor/-/asciidoctor-2.2.8.tgz", + "integrity": "sha512-G+sDYWnNo+QHRkIvN5k7ASbvrd2bHuNXHlZ83+PjVFYtl0//as5iebq+Bdf3aSwXrkM7akcEJPUpdTjjP0MgYw==", "dev": true, + "license": "MIT", "dependencies": { "@asciidoctor/cli": "3.5.0", - "@asciidoctor/core": "2.2.6" + "@asciidoctor/core": "2.2.8" }, "bin": { "asciidoctor": "bin/asciidoctor", @@ -551,6 +1110,7 @@ "resolved": "https://registry.npmjs.org/asciidoctor-opal-runtime/-/asciidoctor-opal-runtime-0.3.3.tgz", "integrity": "sha512-/CEVNiOia8E5BMO9FLooo+Kv18K4+4JBFRJp8vUy/N5dMRAg+fRNV4HA+o6aoSC79jVU/aT5XvUpxSxSsTS8FQ==", "dev": true, + "license": "MIT", "dependencies": { "glob": "7.1.3", "unxhr": "1.0.1" @@ -559,28 +1119,11 @@ "node": ">=8.11" } }, - "node_modules/asciidoctor-opal-runtime/node_modules/glob": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", - "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - } - }, "node_modules/asn1": { "version": "0.2.6", "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz", "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==", - "dev": true, + "license": "MIT", "dependencies": { "safer-buffer": "~2.1.0" } @@ -589,7 +1132,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", "integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==", - "dev": true, + "license": "MIT", "engines": { "node": ">=0.8" } @@ -599,63 +1142,66 @@ "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", "dev": true, + "license": "MIT", "engines": { "node": "*" } }, - "node_modules/astral-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", - "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==", - "dev": true, - "engines": { - "node": ">=4" - } - }, "node_modules/async": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/async/-/async-3.2.4.tgz", - "integrity": "sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==", - "dev": true + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz", + "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==", + "dev": true, + "license": "MIT" }, "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", - "dev": true + "license": "MIT" + }, + "node_modules/available-typed-arrays": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", + "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", + "license": "MIT", + "dependencies": { + "possible-typed-array-names": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, "node_modules/aws-sign2": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", "integrity": "sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==", - "dev": true, + "license": "Apache-2.0", "engines": { "node": "*" } }, "node_modules/aws4": { - "version": "1.12.0", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.12.0.tgz", - "integrity": "sha512-NmWvPnx0F1SfrQbYwOi7OeaNGokp9XhzNioJ/CSBs8Qa4vxug81mhJEAVZwxXuBmYB5KDRfMq/F3RR0BIU7sWg==", - "dev": true + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.13.2.tgz", + "integrity": "sha512-lHe62zvbTB5eEABUVi/AwVh0ZKY9rMMDhmm+eeyuuUQbQ3+J+fONVQOZyj+DdrvD4BY33uYniyRJ4UJIaSKAfw==", + "license": "MIT" }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" }, "node_modules/base-x": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/base-x/-/base-x-1.1.0.tgz", - "integrity": "sha512-c0WLeG3K5OlL4Skz2/LVdS+MjggByKhowxQpG+JpCLA48s/bGwIDyzA1naFjywtNvp/37fLK0p0FpjTNNLLUXQ==" - }, - "node_modules/base58check": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/base58check/-/base58check-2.0.0.tgz", - "integrity": "sha512-sTzsDAOC9+i2Ukr3p1Ie2DWpD117ua+vBJRDnpsSlScGwImeeiTg/IatwcFLsz9K9wEGoBLVd5ahNZzrZ/jZyg==", - "dependencies": { - "bs58": "^3.0.0" - } + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/base-x/-/base-x-4.0.1.tgz", + "integrity": "sha512-uAZ8x6r6S3aUM9rbHGVOIsR15U/ZSc82b3ymnCPsT45Gk1DDvhDPdIgB5MrhirZWt+5K0EEPQH985kNqZgNPFw==", + "license": "MIT" }, "node_modules/base64-js": { "version": "1.5.1", @@ -674,19 +1220,22 @@ "type": "consulting", "url": "https://feross.org/support" } - ] + ], + "license": "MIT" }, "node_modules/bash-color": { "version": "0.0.4", "resolved": "https://registry.npmjs.org/bash-color/-/bash-color-0.0.4.tgz", "integrity": "sha512-ZNB4525U7BxT6v9C8LEtywyCgB4Pjnm7/bh+ru/Z9Ecxvg3fDjaJ6z305z9a61orQdbB1zqYHh5JbUqx4s4K0g==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/basic-auth": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz", "integrity": "sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==", "dev": true, + "license": "MIT", "dependencies": { "safe-buffer": "5.1.2" }, @@ -698,26 +1247,35 @@ "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/bcrypt-pbkdf": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", "integrity": "sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==", - "dev": true, + "license": "BSD-3-Clause", "dependencies": { "tweetnacl": "^0.14.3" } }, + "node_modules/bcrypt-pbkdf/node_modules/tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==", + "license": "Unlicense" + }, "node_modules/bech32": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/bech32/-/bech32-2.0.0.tgz", - "integrity": "sha512-LcknSilhIGatDAsY1ak2I8VtGaHNhgMSYVxFrGLXv+xLHytaKZKcaUJJUE7qmBr7h33o5YQwP55pMI0xmkpJwg==" + "integrity": "sha512-LcknSilhIGatDAsY1ak2I8VtGaHNhgMSYVxFrGLXv+xLHytaKZKcaUJJUE7qmBr7h33o5YQwP55pMI0xmkpJwg==", + "license": "MIT" }, "node_modules/bech32-buffer": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/bech32-buffer/-/bech32-buffer-0.2.0.tgz", - "integrity": "sha512-Ez8s82a+Xnn/m3/ftGaQJUSFG4EwNIj9adIJBw8OrHASQsXgvwLSducbcJ9El0rsrwJYJ71yBhC/hZzz3FPSCQ==", + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/bech32-buffer/-/bech32-buffer-0.2.1.tgz", + "integrity": "sha512-fCG1TyZuCN48Sdw97p/IR39fvqpFlWDVpG7qnuU1Uc3+Xtc/0uqAp8U7bMW/bGuVF5CcNVIXwxQsWwUr6un6FQ==", + "license": "Apache-2.0", "engines": { "node": ">=8" } @@ -728,28 +1286,23 @@ "integrity": "sha512-ddkU+dFIuEIW8lE7ZwdIAf2UPoM90eaprg5m3YXAVVTmKlqV/9BX4A2M8BOK2yOq6/VgZFVhK6QAxJebhlbhzw==" }, "node_modules/binary-extensions": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", - "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" - } - }, - "node_modules/bindings": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", - "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", - "dev": true, - "optional": true, - "dependencies": { - "file-uri-to-path": "1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/bip-schnorr": { - "version": "0.6.6", - "resolved": "https://registry.npmjs.org/bip-schnorr/-/bip-schnorr-0.6.6.tgz", - "integrity": "sha512-QZmVN37kaKfEk6M61gfcREa5JxWVQ0LvA95UQQD5mdyZsN6542PwfrvlAARZufTLn2ZIQQ0ph6XHD0vq8J3ouw==", + "version": "0.6.7", + "resolved": "https://registry.npmjs.org/bip-schnorr/-/bip-schnorr-0.6.7.tgz", + "integrity": "sha512-Pf1o+whA52l7NC33CZY4eRtcB+dUCT54hKCF8mnw2349CG89LOXODHRWmUEcSSWzoi+Kjg1CtMmw6uV43tmJFA==", + "license": "MIT", "dependencies": { "bigi": "^1.4.2", "ecurve": "^1.0.6", @@ -762,22 +1315,22 @@ } }, "node_modules/bip174": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/bip174/-/bip174-2.1.0.tgz", - "integrity": "sha512-lkc0XyiX9E9KiVAS1ZiOqK1xfiwvf4FXDDdkDq5crcDzOq+xGytY+14qCsqz7kCiy8rpN1CRNfacRhf9G3JNSA==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/bip174/-/bip174-2.1.1.tgz", + "integrity": "sha512-mdFV5+/v0XyNYXjBS6CQPLo9ekCx4gtKZFnJm5PMto7Fs9hTTDpkkzOB7/FtluRI6JbUUAu+snTYfJRgHLZbZQ==", + "license": "MIT", "engines": { "node": ">=8.0.0" } }, "node_modules/bip32": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/bip32/-/bip32-3.0.1.tgz", - "integrity": "sha512-Uhpp9aEx3iyiO7CpbNGFxv9WcMIVdGoHG04doQ5Ln0u60uwDah7jUSc3QMV/fSZGm/Oo01/OeAmYevXV+Gz5jQ==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/bip32/-/bip32-4.0.0.tgz", + "integrity": "sha512-aOGy88DDlVUhspIXJN+dVEtclhIsfAUppD43V0j40cPTld3pv/0X/MlrZSZ6jowIaQQzFwP8M6rFU2z2mVYjDQ==", + "license": "MIT", "dependencies": { - "@types/node": "10.12.18", - "bs58check": "^2.1.1", - "create-hash": "^1.2.0", - "create-hmac": "^1.1.7", + "@noble/hashes": "^1.2.0", + "@scure/base": "^1.1.1", "typeforce": "^1.11.5", "wif": "^2.0.6" }, @@ -786,25 +1339,19 @@ } }, "node_modules/bip39": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/bip39/-/bip39-3.0.4.tgz", - "integrity": "sha512-YZKQlb752TrUWqHWj7XAwCSjYEgGAk+/Aas3V7NyjQeZYsztO8JnQUaCWhcnL4T+jL8nvB8typ2jRPzTlgugNw==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/bip39/-/bip39-3.1.0.tgz", + "integrity": "sha512-c9kiwdk45Do5GL0vJMe7tS95VjCii65mYAH7DfWl3uW8AVzXKQVUm64i3hzVybBDMp9r7j9iNxR85+ul8MdN/A==", + "license": "ISC", "dependencies": { - "@types/node": "11.11.6", - "create-hash": "^1.1.0", - "pbkdf2": "^3.0.9", - "randombytes": "^2.0.1" + "@noble/hashes": "^1.2.0" } }, - "node_modules/bip39/node_modules/@types/node": { - "version": "11.11.6", - "resolved": "https://registry.npmjs.org/@types/node/-/node-11.11.6.tgz", - "integrity": "sha512-Exw4yUWMBXM3X+8oqzJNRqZSwUAaS4+7NdvHqQuFi/d+synz++xmX3QIf+BFqneW8N31R8Ky+sikfZUXq07ggQ==" - }, "node_modules/bip65": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/bip65/-/bip65-1.0.3.tgz", "integrity": "sha512-RQ1nc7xtnLa5XltnCqkoR2zmhuz498RjMJwrLKQzOE049D1HUqnYfon7cVSbwS5UGm0/EQlC2CH+NY3MyITA4Q==", + "license": "ISC", "engines": { "node": ">=4.5.0" } @@ -813,22 +1360,23 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/bip68/-/bip68-1.0.4.tgz", "integrity": "sha512-O1htyufFTYy3EO0JkHg2CLykdXEtV2ssqw47Gq9A0WByp662xpJnMEB9m43LZjsSDjIAOozWRExlFQk2hlV1XQ==", + "license": "ISC", "engines": { "node": ">=4.5.0" } }, "node_modules/bitcoinjs-lib": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/bitcoinjs-lib/-/bitcoinjs-lib-6.0.0.tgz", - "integrity": "sha512-KYx81rVE4LDbZcHfE375NCX4CDeZuz7HECZm/KAmqKMY2jpD3ZcUnI7Fm+QX5EMF/xmtzzfrNL/BNxo8o0iOQg==", + "version": "6.1.7", + "resolved": "https://registry.npmjs.org/bitcoinjs-lib/-/bitcoinjs-lib-6.1.7.tgz", + "integrity": "sha512-tlf/r2DGMbF7ky1MgUqXHzypYHakkEnm0SZP23CJKIqNY/5uNAnMbFhMJdhjrL/7anfb/U8+AlpdjPWjPnAalg==", + "license": "MIT", "dependencies": { + "@noble/hashes": "^1.2.0", "bech32": "^2.0.0", - "bip174": "^2.0.1", - "bs58check": "^2.1.2", - "create-hash": "^1.1.0", + "bip174": "^2.1.1", + "bs58check": "^3.0.1", "typeforce": "^1.11.3", - "varuint-bitcoin": "^1.1.2", - "wif": "^2.0.1" + "varuint-bitcoin": "^1.1.2" }, "engines": { "node": ">=8.0.0" @@ -838,6 +1386,7 @@ "version": "0.1.81", "resolved": "https://registry.npmjs.org/blessed/-/blessed-0.1.81.tgz", "integrity": "sha512-LoF5gae+hlmfORcG1M5+5XZi4LBmvlXTzwJWzUlPryN/SJdSflZvROM2TwkT0GMpq7oqT48NRd4GS7BiVBc5OQ==", + "license": "MIT", "bin": { "blessed": "bin/tput.js" }, @@ -849,12 +1398,13 @@ "version": "3.7.2", "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", - "dev": true + "license": "MIT" }, "node_modules/bn.js": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", - "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.1.tgz", + "integrity": "sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==", + "license": "MIT" }, "node_modules/body": { "version": "5.1.0", @@ -872,24 +1422,27 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "license": "MIT", "dependencies": { - "fill-range": "^7.0.1" + "fill-range": "^7.1.1" }, "engines": { "node": ">=8" @@ -898,53 +1451,48 @@ "node_modules/brorand": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", - "integrity": "sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==" + "integrity": "sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==", + "license": "MIT" + }, + "node_modules/browser-level": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/browser-level/-/browser-level-2.0.0.tgz", + "integrity": "sha512-RuYSCHG/jwFCrK+KWA3dLSUNLKHEgIYhO5ORPjJMjCt7T3e+RzpIDmYKWRHxq2pfKGXjlRuEff7y7RESAAgzew==", + "license": "MIT", + "dependencies": { + "abstract-level": "^2.0.1" + } }, "node_modules/browser-stdout": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/bs58": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/bs58/-/bs58-3.1.0.tgz", - "integrity": "sha512-9C2bRFTGy3meqO65O9jLvVTyawvhLVp4h2ECm5KlRPuV5KPDNJZcJIj3gl+aA0ENXcYrUSLCkPAeqbTcI2uWyQ==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/bs58/-/bs58-5.0.0.tgz", + "integrity": "sha512-r+ihvQJvahgYT50JD05dyJNKlmmSlMoOGwn1lCcEzanPglg7TxYjioQUYehQ9mAR/+hOSd2jRc/Z2y5UxBymvQ==", + "license": "MIT", "dependencies": { - "base-x": "^1.1.0" + "base-x": "^4.0.0" } }, "node_modules/bs58check": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/bs58check/-/bs58check-2.1.2.tgz", - "integrity": "sha512-0TS1jicxdU09dwJMNZtVAfzPi6Q6QeN0pM1Fkzrjn+XYHvzMKPU3pHVpva+769iNVSfIYWf7LJ6WR+BuuMf8cA==", - "dependencies": { - "bs58": "^4.0.0", - "create-hash": "^1.1.0", - "safe-buffer": "^5.1.2" - } - }, - "node_modules/bs58check/node_modules/base-x": { - "version": "3.0.9", - "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.9.tgz", - "integrity": "sha512-H7JU6iBHTal1gp56aKoaa//YUxEaAOUiydvrV/pILqIHXTtqxSkATOnDA2u+jZ/61sD+L/412+7kzXRtWukhpQ==", - "dependencies": { - "safe-buffer": "^5.0.1" - } - }, - "node_modules/bs58check/node_modules/bs58": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/bs58/-/bs58-4.0.1.tgz", - "integrity": "sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/bs58check/-/bs58check-3.0.1.tgz", + "integrity": "sha512-hjuuJvoWEybo7Hn/0xOrczQKKEKD63WguEjlhLExYs2wUBcebDC1jDNK17eEAD2lYfw82d5ASC1d7K3SWszjaQ==", + "license": "MIT", "dependencies": { - "base-x": "^3.0.2" + "@noble/hashes": "^1.2.0", + "bs58": "^5.0.0" } }, "node_modules/buffer": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", - "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", - "dev": true, + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", "funding": [ { "type": "github", @@ -959,20 +1507,23 @@ "url": "https://feross.org/support" } ], + "license": "MIT", "dependencies": { "base64-js": "^1.3.1", - "ieee754": "^1.1.13" + "ieee754": "^1.2.1" } }, "node_modules/buffer-alloc-unsafe": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz", - "integrity": "sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg==" + "integrity": "sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg==", + "license": "MIT" }, "node_modules/buffer-reverse": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/buffer-reverse/-/buffer-reverse-1.0.1.tgz", - "integrity": "sha512-M87YIUBsZ6N924W57vDwT/aOu8hw7ZgdByz6ijksLjmHJELBASmYTTlNHRgjE+pTsT9oJXGaDSgqqwfdHotDUg==" + "integrity": "sha512-M87YIUBsZ6N924W57vDwT/aOu8hw7ZgdByz6ijksLjmHJELBASmYTTlNHRgjE+pTsT9oJXGaDSgqqwfdHotDUg==", + "license": "MIT" }, "node_modules/bytes": { "version": "1.0.0", @@ -981,67 +1532,105 @@ "dev": true }, "node_modules/c8": { - "version": "7.11.3", - "resolved": "https://registry.npmjs.org/c8/-/c8-7.11.3.tgz", - "integrity": "sha512-6YBmsaNmqRm9OS3ZbIiL2EZgi1+Xc4O24jL3vMYGE6idixYuGdy76rIfIdltSKDj9DpLNrcXSonUTR1miBD0wA==", + "version": "10.1.3", + "resolved": "https://registry.npmjs.org/c8/-/c8-10.1.3.tgz", + "integrity": "sha512-LvcyrOAaOnrrlMpW22n690PUvxiq4Uf9WMhQwNJ9vgagkL/ph1+D4uvjvDA5XCbykrc0sx+ay6pVi9YZ1GnhyA==", "dev": true, + "license": "ISC", "dependencies": { - "@bcoe/v8-coverage": "^0.2.3", + "@bcoe/v8-coverage": "^1.0.1", "@istanbuljs/schema": "^0.1.3", "find-up": "^5.0.0", - "foreground-child": "^2.0.0", + "foreground-child": "^3.1.1", "istanbul-lib-coverage": "^3.2.0", - "istanbul-lib-report": "^3.0.0", - "istanbul-reports": "^3.1.4", - "rimraf": "^3.0.2", - "test-exclude": "^6.0.0", + "istanbul-lib-report": "^3.0.1", + "istanbul-reports": "^3.1.6", + "test-exclude": "^7.0.1", "v8-to-istanbul": "^9.0.0", - "yargs": "^16.2.0", - "yargs-parser": "^20.2.9" + "yargs": "^17.7.2", + "yargs-parser": "^21.1.1" }, "bin": { "c8": "bin/c8.js" }, "engines": { - "node": ">=10.12.0" + "node": ">=18" + }, + "peerDependencies": { + "monocart-coverage-reports": "^2" + }, + "peerDependenciesMeta": { + "monocart-coverage-reports": { + "optional": true + } } }, - "node_modules/c8/node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "node_modules/cache-point": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/cache-point/-/cache-point-3.0.1.tgz", + "integrity": "sha512-itTIMLEKbh6Dw5DruXbxAgcyLnh/oPGVLBfTPqBOftASxHe8bAeXy7JkO4F0LvHqht7XqP5O/09h5UcHS2w0FA==", "dev": true, + "license": "MIT", "dependencies": { - "glob": "^7.1.3" + "array-back": "^6.2.2" }, - "bin": { - "rimraf": "bin.js" + "engines": { + "node": ">=12.17" + }, + "peerDependencies": { + "@75lb/nature": "latest" + }, + "peerDependenciesMeta": { + "@75lb/nature": { + "optional": true + } + } + }, + "node_modules/call-bind": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz", + "integrity": "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.0", + "es-define-property": "^1.0.0", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/sponsors/isaacs" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/cache-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/cache-point/-/cache-point-2.0.0.tgz", - "integrity": "sha512-4gkeHlFpSKgm3vm2gJN5sPqfmijYRFYCQ6tv5cLw0xVmT6r1z1vd4FNnpuOREco3cBs1G709sZ72LdgddKvL5w==", - "dev": true, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "license": "MIT", "dependencies": { - "array-back": "^4.0.1", - "fs-then-native": "^2.0.0", - "mkdirp2": "^1.0.4" + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" }, "engines": { - "node": ">=8" + "node": ">= 0.4" } }, - "node_modules/cache-point/node_modules/array-back": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/array-back/-/array-back-4.0.2.tgz", - "integrity": "sha512-NbdMezxqf94cnNfWLL7V/im0Ub+Anbb0IoZhvzie8+4HJ4nMQuzHuy49FkGYCJK2yAloZ3meiB6AVMClbrI1vg==", - "dev": true, + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, "engines": { - "node": ">=8" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/callsite": { @@ -1058,6 +1647,7 @@ "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } @@ -1067,6 +1657,7 @@ "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", "dev": true, + "license": "MIT", "engines": { "node": ">=10" }, @@ -1078,21 +1669,14 @@ "version": "0.12.0", "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==", - "dev": true - }, - "node_modules/catering": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/catering/-/catering-2.1.1.tgz", - "integrity": "sha512-K7Qy8O9p76sL3/3m7/zLKbRkyOlSZAgzEaLhyj2mXS8PsCud2Eo4hAb8aLtZqHh0QGqLcb9dlJSu6lHRVENm1w==", - "engines": { - "node": ">=6" - } + "license": "Apache-2.0" }, "node_modules/catharsis": { "version": "0.9.0", "resolved": "https://registry.npmjs.org/catharsis/-/catharsis-0.9.0.tgz", "integrity": "sha512-prMTQVpcns/tzFgFVkVp6ak6RykZyWb3gu8ckUpd6YkTlacOd3DXGJjIpD4Q6zJirizvaiAjSSHlOsA+6sNh2A==", "dev": true, + "license": "MIT", "dependencies": { "lodash": "^4.17.15" }, @@ -1105,6 +1689,7 @@ "resolved": "https://registry.npmjs.org/chai/-/chai-4.0.2.tgz", "integrity": "sha512-SSBITzu/g8nD3cP/GUKPYP9OBX92s4hvz+t6spQ2SjknieqUGKqR8etHQXV/9an9Ot+8iLrnFoBRcsIxefcHGw==", "dev": true, + "license": "MIT", "dependencies": { "assertion-error": "^1.0.1", "check-error": "^1.0.1", @@ -1118,50 +1703,72 @@ } }, "node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, + "license": "MIT", "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" }, "engines": { - "node": ">=4" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/chardet": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", - "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", - "dev": true + "node_modules/chalk-template": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/chalk-template/-/chalk-template-0.4.0.tgz", + "integrity": "sha512-/ghrgmhfY8RaSdeo43hNXxpoHAtxdbskUHjPpfqUWGttFgycUhYPGx3YZBCnUCvOa7Doivn1IZec3DEGFoMgLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.1.2" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/chalk-template?sponsor=1" + } }, "node_modules/check-error": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", - "integrity": "sha512-BrgHpW9NURQgzoNyjfq0Wu6VFO6D7IZEmJNdtgNqpzGG8RuNFHt2jQxWlAs4HMe119chBnv+34syEZtc6IhLtA==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.3.tgz", + "integrity": "sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==", "dev": true, + "license": "MIT", + "dependencies": { + "get-func-name": "^2.0.2" + }, "engines": { "node": "*" } }, "node_modules/cheerio": { - "version": "1.0.0-rc.12", - "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.12.tgz", - "integrity": "sha512-VqR8m68vM46BNnuZ5NtnGBKIE/DfN0cRIzg9n40EIq9NOv90ayxLBXA8fXC5gquFRGJSTRqBq25Jt2ECLR431Q==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.1.2.tgz", + "integrity": "sha512-IkxPpb5rS/d1IiLbHMgfPuS0FgiWTtFIm/Nj+2woXDLTZ7fOT2eqzgYbdMlLweqlHbsZjxEChoVK+7iph7jyQg==", "dev": true, + "license": "MIT", "dependencies": { "cheerio-select": "^2.1.0", "dom-serializer": "^2.0.0", "domhandler": "^5.0.3", - "domutils": "^3.0.1", - "htmlparser2": "^8.0.1", - "parse5": "^7.0.0", - "parse5-htmlparser2-tree-adapter": "^7.0.0" + "domutils": "^3.2.2", + "encoding-sniffer": "^0.2.1", + "htmlparser2": "^10.0.0", + "parse5": "^7.3.0", + "parse5-htmlparser2-tree-adapter": "^7.1.0", + "parse5-parser-stream": "^7.1.2", + "undici": "^7.12.0", + "whatwg-mimetype": "^4.0.0" }, "engines": { - "node": ">= 6" + "node": ">=20.18.1" }, "funding": { "url": "https://github.com/cheeriojs/cheerio?sponsor=1" @@ -1172,6 +1779,7 @@ "resolved": "https://registry.npmjs.org/cheerio-select/-/cheerio-select-2.1.0.tgz", "integrity": "sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "boolbase": "^1.0.0", "css-select": "^5.1.0", @@ -1189,6 +1797,7 @@ "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", "dev": true, + "license": "MIT", "dependencies": { "domelementtype": "^2.3.0", "domhandler": "^5.0.2", @@ -1199,10 +1808,11 @@ } }, "node_modules/cheerio/node_modules/entities": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-4.4.0.tgz", - "integrity": "sha512-oYp7156SP8LkeGD0GF85ad1X9Ai79WtRsZ2gxJqtBuzH+98YUV6jkHEKlZkMbcrjJjIVJNIDP/3WL9wQkoPbWA==", + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", "dev": true, + "license": "BSD-2-Clause", "engines": { "node": ">=0.12" }, @@ -1211,16 +1821,11 @@ } }, "node_modules/chokidar": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", - "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - ], + "license": "MIT", "dependencies": { "anymatch": "~3.1.2", "braces": "~3.0.2", @@ -1233,125 +1838,123 @@ "engines": { "node": ">= 8.10.0" }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, "optionalDependencies": { "fsevents": "~2.3.2" } }, - "node_modules/cipher-base": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", - "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", - "dependencies": { - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" - } - }, - "node_modules/cli-cursor": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", - "integrity": "sha512-8lgKz8LmCRYZZQDpRyT2m5rKJ08TnU4tR9FFFW2rxpxR1FzWi4PQ/NfyODchAatHaUgnSPVcx/R5w6NuTBzFiw==", + "node_modules/chokidar/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", "dev": true, + "license": "ISC", "dependencies": { - "restore-cursor": "^2.0.0" + "is-glob": "^4.0.1" }, "engines": { - "node": ">=4" - } - }, - "node_modules/cli-width": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.1.tgz", - "integrity": "sha512-GRMWDxpOB6Dgk2E5Uo+3eEBvtOOlimMmpbFiKuLFnQzYDavtLFY3K5ona41jgN/WdRZtG7utuVSVTL4HbZHGkw==", - "dev": true - }, - "node_modules/cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", - "dev": true, - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^7.0.0" - } - }, - "node_modules/cliui/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "engines": { - "node": ">=8" + "node": ">= 6" } }, - "node_modules/cliui/node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, + "node_modules/chownr": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", + "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", + "license": "ISC", "engines": { - "node": ">=8" + "node": ">=10" } }, - "node_modules/cliui/node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, + "node_modules/cipher-base": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.7.tgz", + "integrity": "sha512-Mz9QMT5fJe7bKI7MH31UilT5cEK5EHHRCccw/YRFsRY47AuNgaV6HY3rscp0/I4Q+tTW/5zoqpSeRRI54TkDWA==", + "license": "MIT", "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" + "inherits": "^2.0.4", + "safe-buffer": "^5.2.1", + "to-buffer": "^1.2.2" }, "engines": { - "node": ">=8" + "node": ">= 0.10" } }, - "node_modules/cliui/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, + "node_modules/classic-level": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/classic-level/-/classic-level-2.0.0.tgz", + "integrity": "sha512-ftiMvKgCQK+OppXcvMieDoYlYLYWhScK6yZRFBrrlHQRbm4k6Gr+yDgu/wt3V0k1/jtNbuiXAsRmuAFcD0Tx5Q==", + "hasInstallScript": true, + "license": "MIT", "dependencies": { - "ansi-regex": "^5.0.1" + "abstract-level": "^2.0.0", + "module-error": "^1.0.1", + "napi-macros": "^2.2.2", + "node-gyp-build": "^4.3.0" }, "engines": { - "node": ">=8" + "node": ">=18" } }, - "node_modules/collect-all": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/collect-all/-/collect-all-1.0.4.tgz", - "integrity": "sha512-RKZhRwJtJEP5FWul+gkSMEnaK6H3AGPTTWOiRimCcs+rc/OmQE3Yhy1Q7A7KsdkG3ZXVdZq68Y6ONSdvkeEcKA==", + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", "dev": true, + "license": "ISC", "dependencies": { - "stream-connect": "^1.0.2", - "stream-via": "^1.0.4" + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" }, + "engines": { + "node": ">=12" + } + }, + "node_modules/cluster-key-slot": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.2.tgz", + "integrity": "sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==", + "license": "Apache-2.0", "engines": { "node": ">=0.10.0" } }, "node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, + "license": "MIT", "dependencies": { - "color-name": "1.1.3" + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" } }, "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/color-support": { "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true + "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", + "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", + "license": "ISC", + "bin": { + "color-support": "bin.js" + } }, "node_modules/combined-stream": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "dev": true, + "license": "MIT", "dependencies": { "delayed-stream": "~1.0.0" }, @@ -1360,120 +1963,77 @@ } }, "node_modules/command-line-args": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/command-line-args/-/command-line-args-5.2.1.tgz", - "integrity": "sha512-H4UfQhZyakIjC74I9d34fGYDwk3XpSr17QhEd0Q3I9Xq1CETHo4Hcuo87WyWHpAF1aSLjLRf5lD9ZGX2qStUvg==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/command-line-args/-/command-line-args-6.0.1.tgz", + "integrity": "sha512-Jr3eByUjqyK0qd8W0SGFW1nZwqCaNCtbXjRo2cRJC1OYxWl3MZ5t1US3jq+cO4sPavqgw4l9BMGX0CBe+trepg==", "dev": true, + "license": "MIT", "dependencies": { - "array-back": "^3.1.0", - "find-replace": "^3.0.0", + "array-back": "^6.2.2", + "find-replace": "^5.0.2", "lodash.camelcase": "^4.3.0", - "typical": "^4.0.0" + "typical": "^7.2.0" }, "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/command-line-args/node_modules/array-back": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/array-back/-/array-back-3.1.0.tgz", - "integrity": "sha512-TkuxA4UCOvxuDK6NZYXCalszEzj+TLszyASooky+i742l9TqsOdYCMJJupxRic61hwquNtppB3hgcuq9SVSH1Q==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/command-line-args/node_modules/typical": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/typical/-/typical-4.0.0.tgz", - "integrity": "sha512-VAH4IvQ7BDFYglMd7BPRDfLgxZZX4O4TFcRDA6EN5X7erNJJq+McIEp8np9aVtxrCJ6qx4GTYVfOWNjcqwZgRw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/command-line-tool": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/command-line-tool/-/command-line-tool-0.8.0.tgz", - "integrity": "sha512-Xw18HVx/QzQV3Sc5k1vy3kgtOeGmsKIqwtFFoyjI4bbcpSgnw2CWVULvtakyw4s6fhyAdI6soQQhXc2OzJy62g==", - "dev": true, - "dependencies": { - "ansi-escape-sequences": "^4.0.0", - "array-back": "^2.0.0", - "command-line-args": "^5.0.0", - "command-line-usage": "^4.1.0", - "typical": "^2.6.1" + "node": ">=12.20" }, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/command-line-tool/node_modules/array-back": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/array-back/-/array-back-2.0.0.tgz", - "integrity": "sha512-eJv4pLLufP3g5kcZry0j6WXpIbzYw9GUB4mVJZno9wfwiBxbizTnHCw3VJb07cBihbFX48Y7oSrW9y+gt4glyw==", - "dev": true, - "dependencies": { - "typical": "^2.6.1" + "peerDependencies": { + "@75lb/nature": "latest" }, - "engines": { - "node": ">=4" + "peerDependenciesMeta": { + "@75lb/nature": { + "optional": true + } } }, "node_modules/command-line-usage": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/command-line-usage/-/command-line-usage-4.1.0.tgz", - "integrity": "sha512-MxS8Ad995KpdAC0Jopo/ovGIroV/m0KHwzKfXxKag6FHOkGsH8/lv5yjgablcRxCJJC0oJeUMuO/gmaq+Wq46g==", - "dev": true, - "dependencies": { - "ansi-escape-sequences": "^4.0.0", - "array-back": "^2.0.0", - "table-layout": "^0.4.2", - "typical": "^2.6.1" - }, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/command-line-usage/node_modules/array-back": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/array-back/-/array-back-2.0.0.tgz", - "integrity": "sha512-eJv4pLLufP3g5kcZry0j6WXpIbzYw9GUB4mVJZno9wfwiBxbizTnHCw3VJb07cBihbFX48Y7oSrW9y+gt4glyw==", + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/command-line-usage/-/command-line-usage-7.0.3.tgz", + "integrity": "sha512-PqMLy5+YGwhMh1wS04mVG44oqDsgyLRSKJBdOo1bnYhMKBW65gZF1dRp2OZRhiTjgUHljy99qkO7bsctLaw35Q==", "dev": true, + "license": "MIT", "dependencies": { - "typical": "^2.6.1" + "array-back": "^6.2.2", + "chalk-template": "^0.4.0", + "table-layout": "^4.1.0", + "typical": "^7.1.1" }, "engines": { - "node": ">=4" + "node": ">=12.20.0" } }, "node_modules/commander": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-6.1.0.tgz", - "integrity": "sha512-wl7PNrYWd2y5mp1OK/LhTlv8Ff4kQJQRXXAvF+uU/TPNiVJUxZLRYGj/B0y/lPGAVcSbJqH2Za/cvHmrPMC8mA==", + "version": "13.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-13.1.0.tgz", + "integrity": "sha512-/rFeCpNJQbhSZjGVwO9RFV3xPqbnERS8MmIQzCtD/zl6gpJuV/bMLuN92oG3F7d8oDEHHRrujSXNUr8fpjntKw==", + "license": "MIT", "engines": { - "node": ">= 6" + "node": ">=18" } }, "node_modules/common-sequence": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/common-sequence/-/common-sequence-2.0.2.tgz", - "integrity": "sha512-jAg09gkdkrDO9EWTdXfv80WWH3yeZl5oT69fGfedBNS9pXUKYInVJ1bJ+/ht2+Moeei48TmSbQDYMc8EOx9G0g==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/common-sequence/-/common-sequence-3.0.0.tgz", + "integrity": "sha512-g/CgSYk93y+a1IKm50tKl7kaT/OjjTYVQlEbUlt/49ZLV1mcKpUU7iyDiqTAeLdb4QDtQfq3ako8y8v//fzrWQ==", "dev": true, + "license": "MIT", "engines": { - "node": ">=8" + "node": ">=12.17" } }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true, + "license": "MIT" }, "node_modules/config-chain": { "version": "1.1.13", "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.13.tgz", "integrity": "sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==", "dev": true, + "license": "MIT", "dependencies": { "ini": "^1.3.4", "proto-list": "~1.2.1" @@ -1484,6 +2044,7 @@ "resolved": "https://registry.npmjs.org/config-master/-/config-master-3.1.0.tgz", "integrity": "sha512-n7LBL1zBzYdTpF1mx5DNcZnZn05CWIdsdvtPL4MosvqbBUK3Rq6VWEtGUuF3Y0s9/CIhMejezqlSkP6TnCJ/9g==", "dev": true, + "license": "MIT", "dependencies": { "walk-back": "^2.0.1" } @@ -1493,14 +2054,22 @@ "resolved": "https://registry.npmjs.org/walk-back/-/walk-back-2.0.1.tgz", "integrity": "sha512-Nb6GvBR8UWX1D+Le+xUq0+Q1kFmRBIWVrfLnQAOmcpEzA9oAxwJ9gIr36t9TWYfzvWRvuMtjHiVsJYEkXWaTAQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, + "node_modules/console-control-strings": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==", + "license": "ISC" + }, "node_modules/content-type": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", - "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "license": "MIT", "engines": { "node": ">= 0.6" } @@ -1512,21 +2081,24 @@ "dev": true }, "node_modules/convert-source-map": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", - "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", - "dev": true + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, + "license": "MIT" }, "node_modules/core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==" + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "license": "MIT" }, "node_modules/corser": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/corser/-/corser-2.0.1.tgz", "integrity": "sha512-utCYNzRSQIZNPIcGZdQc92UVJYAhtGAteCFg0yRaFm8f0P+CPtyGyHXJcGXnffjCybUCEx3FQ2G7U3/o9eIkVQ==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.4.0" } @@ -1535,13 +2107,15 @@ "version": "0.2.0", "resolved": "https://registry.npmjs.org/cp/-/cp-0.2.0.tgz", "integrity": "sha512-4ftCvShHjIZG/zzomHyunNpBof3sOFTTmU6s6q9DdqAL/ANqrKV3pr6Z6kVfBI4hjn59DFLImrBqn7GuuMqSZA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/cpr": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/cpr/-/cpr-3.0.1.tgz", "integrity": "sha512-Xch4PXQ/KC8lJ+KfJ9JI6eG/nmppLrPPWg5Q+vh65Qr9EjuJEubxh/H/Le1TmCZ7+Xv7iJuNRqapyOFZB+wsxA==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "graceful-fs": "^4.1.5", "minimist": "^1.2.0", @@ -1557,6 +2131,7 @@ "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", "dev": true, + "license": "MIT", "dependencies": { "minimist": "^1.2.6" }, @@ -1569,14 +2144,41 @@ "resolved": "https://registry.npmjs.org/crc/-/crc-3.8.0.tgz", "integrity": "sha512-iX3mfgcTMIq3ZKLIsVFAbv7+Mc10kxabAGQb8HvjA1o3T1PIYprbakQ65d3I+2HGHt6nSKkM9PYjgoJO2KcFBQ==", "dev": true, + "license": "MIT", "dependencies": { "buffer": "^5.1.0" } }, + "node_modules/crc/node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, "node_modules/create-hash": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", + "license": "MIT", "dependencies": { "cipher-base": "^1.0.1", "inherits": "^2.0.1", @@ -1585,65 +2187,61 @@ "sha.js": "^2.4.0" } }, - "node_modules/create-hmac": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", - "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", - "dependencies": { - "cipher-base": "^1.0.3", - "create-hash": "^1.1.0", - "inherits": "^2.0.1", - "ripemd160": "^2.0.0", - "safe-buffer": "^5.0.1", - "sha.js": "^2.4.8" - } - }, "node_modules/cross-env": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-5.1.3.tgz", - "integrity": "sha512-UOokgwvDzCT0mqRSLEkJzUhYXB1vK3E5UgDrD41QiXsm9UetcW2rCGHYz/O3p873lMJ1VZbFCF9Izkwh7nYR5A==", + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz", + "integrity": "sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==", "dev": true, + "license": "MIT", "dependencies": { - "cross-spawn": "^5.1.0", - "is-windows": "^1.0.0" + "cross-spawn": "^7.0.1" }, "bin": { - "cross-env": "dist/bin/cross-env.js", - "cross-env-shell": "dist/bin/cross-env-shell.js" + "cross-env": "src/bin/cross-env.js", + "cross-env-shell": "src/bin/cross-env-shell.js" }, "engines": { - "node": ">=4.0" + "node": ">=10.14", + "npm": ">=6", + "yarn": ">=1" } }, "node_modules/cross-fetch": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.5.tgz", - "integrity": "sha512-lvb1SBsI0Z7GDwmuid+mU3kWVBwTVUbe7S0H52yaaAdQOXq2YktTCZdlAcNKFzE6QtRz0snpw9bNiPeOIkkQvw==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-4.1.0.tgz", + "integrity": "sha512-uKm5PU+MHTootlWEY+mZ4vvXoCn4fLQxT9dSc1sXVMSFkINTJVN8cAQROpwcKm8bJ/c7rgZVIBWzH5T78sNZZw==", + "license": "MIT", "dependencies": { - "node-fetch": "2.6.7" + "node-fetch": "^2.7.0" } }, "node_modules/cross-spawn": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", - "integrity": "sha512-pTgQJ5KC0d2hcY8eyL1IzlBPYjTkyH72XRZPnLyKus2mBfNjQs3klqbJU2VILqZryAZUt9JOb3h/mWMy23/f5A==", + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", "dev": true, + "license": "MIT", "dependencies": { - "lru-cache": "^4.0.1", - "shebang-command": "^1.2.0", - "which": "^1.2.9" + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" } }, "node_modules/crypto-js": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-3.3.0.tgz", - "integrity": "sha512-DIT51nX0dCfKltpRiXV+/TVZq+Qq2NgF4644+K7Ttnla7zEzqc+kjJyiB96BHNyUTBxyjzRcZYpUdZa+QAqi6Q==" + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.2.0.tgz", + "integrity": "sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==", + "license": "MIT" }, "node_modules/css-select": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz", - "integrity": "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==", + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.2.2.tgz", + "integrity": "sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "boolbase": "^1.0.0", "css-what": "^6.1.0", @@ -1656,10 +2254,11 @@ } }, "node_modules/css-what": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", - "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==", + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.2.2.tgz", + "integrity": "sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA==", "dev": true, + "license": "BSD-2-Clause", "engines": { "node": ">= 6" }, @@ -1667,11 +2266,21 @@ "url": "https://github.com/sponsors/fb55" } }, + "node_modules/current-module-paths": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/current-module-paths/-/current-module-paths-1.1.2.tgz", + "integrity": "sha512-H4s4arcLx/ugbu1XkkgSvcUZax0L6tXUqnppGniQb8l5VjUKGHoayXE5RiriiPhYDd+kjZnaok1Uig13PKtKYQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.17" + } + }, "node_modules/dashdash": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", "integrity": "sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==", - "dev": true, + "license": "MIT", "dependencies": { "assert-plus": "^1.0.0" }, @@ -1680,12 +2289,13 @@ } }, "node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", "dev": true, + "license": "MIT", "dependencies": { - "ms": "2.1.2" + "ms": "^2.1.3" }, "engines": { "node": ">=6.0" @@ -1697,28 +2307,21 @@ } }, "node_modules/debug-trace": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/debug-trace/-/debug-trace-2.2.1.tgz", - "integrity": "sha512-U5k+hPe/k5GrUiVtJ6yH3TGmCQqaTlDKnSSWfYs2wQDP3awqHJiIDvFLCzFiCWKhDgT+9JF2WO4/yQzeRzW9cA==", + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/debug-trace/-/debug-trace-2.2.3.tgz", + "integrity": "sha512-NGScbAeLr3Z+6L7aoTbMLr0Bo9ZvmEOhT+BMavnueyqCN4dyCpZ41XP19p8HtCFau0ry/aWk1jWNGb4e9sQpsQ==", "dev": true, + "license": "MIT", "dependencies": { "callsite": "~1.0.0" } }, - "node_modules/debuglog": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/debuglog/-/debuglog-1.0.1.tgz", - "integrity": "sha512-syBZ+rnAK3EgMsH2aYEOLUW7mZSY9Gb+0wUMCFsZvcmiz+HigA0LOcq/HoQqVuGG+EKykunc7QG2bzrponfaSw==", - "dev": true, - "engines": { - "node": "*" - } - }, "node_modules/decamelize": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=10" }, @@ -1731,6 +2334,7 @@ "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-2.0.2.tgz", "integrity": "sha512-uts3fF4HnV1bcNx8K5c9NMjXXKtLOf1obUMq04uEuMaF8i1m0SfugbpDMd59cYfodQcMqeUISvL4Pmx5NZ7lcw==", "dev": true, + "license": "MIT", "dependencies": { "type-detect": "^3.0.0" }, @@ -1743,41 +2347,40 @@ "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-3.0.0.tgz", "integrity": "sha512-pwZo7l1T0a8wmTMDc4FtXuHseRaqa9nyaUArp4xHaBMUlRzr72PvgF6ouXIIj5rjbVWqo8pZu6vw74jDKg4Dvw==", "dev": true, + "license": "MIT", "engines": { "node": "*" } }, - "node_modules/deep-extend": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", - "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", - "dev": true, - "engines": { - "node": ">=4.0.0" - } - }, "node_modules/deep-is": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true + "dev": true, + "license": "MIT" }, - "node_modules/deferred-leveldown": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/deferred-leveldown/-/deferred-leveldown-7.0.0.tgz", - "integrity": "sha512-QKN8NtuS3BC6m0B8vAnBls44tX1WXAFATUsJlruyAYbZpysWV3siH6o/i3g9DCHauzodksO60bdj5NazNbjCmg==", + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "license": "MIT", "dependencies": { - "abstract-leveldown": "^7.2.0", - "inherits": "^2.0.3" + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" }, "engines": { - "node": ">=10" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/delay": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/delay/-/delay-5.0.0.tgz", "integrity": "sha512-ReEBKkIfe4ya47wlPYf/gu5ib6yUG0/Aez0JQZQz94kiWtRQvZIQbTiehsnwHvLSWJnQdhVeqYue7Id1dKr0qw==", + "license": "MIT", "engines": { "node": ">=10" }, @@ -1789,24 +2392,23 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", - "dev": true, + "license": "MIT", "engines": { "node": ">=0.4.0" } }, - "node_modules/denque": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/denque/-/denque-1.5.1.tgz", - "integrity": "sha512-XwE+iZ4D6ZUB7mfYRMb5wByE8L74HCn30FBN7sWnXksWc1LO1bPDl67pBR9o/kC4z/xSNAwkMYcGgqDV3BE3Hw==", - "engines": { - "node": ">=0.10" - } + "node_modules/delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==", + "license": "MIT" }, "node_modules/depd": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.6" } @@ -1816,26 +2418,18 @@ "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.8", "npm": "1.2.8000 || >= 1.4.16" } }, - "node_modules/dezalgo": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/dezalgo/-/dezalgo-1.0.4.tgz", - "integrity": "sha512-rXSP0bf+5n0Qonsb+SVVfNfIsimO4HEtmnIpPHY8Q1UCzKlQrDMfdobr8nJOOsRgWCyMRqeSBQzmWUMq7zvVig==", - "dev": true, - "dependencies": { - "asap": "^2.0.0", - "wrappy": "1" - } - }, "node_modules/diff": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", - "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.2.0.tgz", + "integrity": "sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==", "dev": true, + "license": "BSD-3-Clause", "engines": { "node": ">=0.3.1" } @@ -1845,38 +2439,44 @@ "resolved": "https://registry.npmjs.org/direction/-/direction-0.1.5.tgz", "integrity": "sha512-HceXsAluGbXKCz2qCVbXFUH4Vn4eNMWxY5gzydMFMnS1zKSwvDASqLwcrYLIFDpwuZ63FUAqjDLEP1eicHt8DQ==", "dev": true, + "license": "MIT", "bin": { "direction": "cli.js" } }, "node_modules/dmd": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/dmd/-/dmd-6.2.0.tgz", - "integrity": "sha512-uXWxLF1H7TkUAuoHK59/h/ts5cKavm2LnhrIgJWisip4BVzPoXavlwyoprFFn2CzcahKYgvkfaebS6oxzgflkg==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/dmd/-/dmd-7.1.1.tgz", + "integrity": "sha512-Ap2HP6iuOek7eShReDLr9jluNJm9RMZESlt29H/Xs1qrVMkcS9X6m5h1mBC56WMxNiSo0wvjGICmZlYUSFjwZQ==", "dev": true, + "license": "MIT", "dependencies": { "array-back": "^6.2.2", - "cache-point": "^2.0.0", - "common-sequence": "^2.0.2", - "file-set": "^4.0.2", - "handlebars": "^4.7.7", - "marked": "^4.2.3", - "object-get": "^2.1.1", - "reduce-flatten": "^3.0.1", - "reduce-unique": "^2.0.1", - "reduce-without": "^1.0.1", - "test-value": "^3.0.0", - "walk-back": "^5.1.0" + "cache-point": "^3.0.0", + "common-sequence": "^3.0.0", + "file-set": "^5.2.2", + "handlebars": "^4.7.8", + "marked": "^4.3.0", + "walk-back": "^5.1.1" }, "engines": { - "node": ">=12" + "node": ">=12.17" + }, + "peerDependencies": { + "@75lb/nature": "latest" + }, + "peerDependenciesMeta": { + "@75lb/nature": { + "optional": true + } } }, "node_modules/dmd/node_modules/marked": { - "version": "4.2.12", - "resolved": "https://registry.npmjs.org/marked/-/marked-4.2.12.tgz", - "integrity": "sha512-yr8hSKa3Fv4D3jdZmtMMPghgVt6TWbk86WQaWhDloQjRSQhMMYCAro7jP7VDJrjjdV8pxVxMssXS8B8Y5DZ5aw==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/marked/-/marked-4.3.0.tgz", + "integrity": "sha512-PRsaiG84bK+AMvxziE/lCFss8juXjNaWzVbN5tXAm4XjeaS9NAHhop+PjQxz2A9h8Q4M/xGmzP8vqNwy6JeK0A==", "dev": true, + "license": "MIT", "bin": { "marked": "bin/marked.js" }, @@ -1889,6 +2489,7 @@ "resolved": "https://registry.npmjs.org/docco/-/docco-0.9.1.tgz", "integrity": "sha512-B1jUzcAc4AmicWUnmPTxUGM2lqJ11X4DiLUXyhzUVb7A1NNGTSNo3LtGzhHMyRAuJyxrHwHiOCDGuE/n9xRhmA==", "dev": true, + "license": "MIT", "dependencies": { "commander": "~ 8.3.0", "fs-extra": "~ 10.0.0", @@ -1908,27 +2509,17 @@ "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", "dev": true, + "license": "MIT", "engines": { "node": ">= 12" } }, - "node_modules/doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "dev": true, - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, "node_modules/dom-serializer": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.1.1.tgz", "integrity": "sha512-l0IU0pPzLWSHBcieZbpOKgkIn3ts3vAh7ZuFyXNwJxJXk/c4Gwj9xaTJwIDVQCXawWD0qb3IzMGH5rglQaO0XA==", "dev": true, + "license": "MIT", "dependencies": { "domelementtype": "^1.3.0", "entities": "^1.1.1" @@ -1938,7 +2529,8 @@ "version": "1.3.1", "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz", "integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==", - "dev": true + "dev": true, + "license": "BSD-2-Clause" }, "node_modules/domelementtype": { "version": "2.3.0", @@ -1950,13 +2542,15 @@ "type": "github", "url": "https://github.com/sponsors/fb55" } - ] + ], + "license": "BSD-2-Clause" }, "node_modules/domhandler": { "version": "5.0.3", "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "domelementtype": "^2.3.0" }, @@ -1968,14 +2562,15 @@ } }, "node_modules/domutils": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.0.1.tgz", - "integrity": "sha512-z08c1l761iKhDFtfXO04C7kTdPBLi41zwOZl00WS8b5eiaebNpY00HKbztwBq+e3vyqWNwWF3mP9YLUeqIrF+Q==", + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.2.2.tgz", + "integrity": "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "dom-serializer": "^2.0.0", "domelementtype": "^2.3.0", - "domhandler": "^5.0.1" + "domhandler": "^5.0.3" }, "funding": { "url": "https://github.com/fb55/domutils?sponsor=1" @@ -1986,6 +2581,7 @@ "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", "dev": true, + "license": "MIT", "dependencies": { "domelementtype": "^2.3.0", "domhandler": "^5.0.2", @@ -1996,10 +2592,11 @@ } }, "node_modules/domutils/node_modules/entities": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-4.4.0.tgz", - "integrity": "sha512-oYp7156SP8LkeGD0GF85ad1X9Ai79WtRsZ2gxJqtBuzH+98YUV6jkHEKlZkMbcrjJjIVJNIDP/3WL9wQkoPbWA==", + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", "dev": true, + "license": "BSD-2-Clause", "engines": { "node": ">=0.12" }, @@ -2007,15 +2604,40 @@ "url": "https://github.com/fb55/entities?sponsor=1" } }, - "node_modules/dotparser": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/dotparser/-/dotparser-0.3.0.tgz", - "integrity": "sha512-TfIlRRKpYFu/KwJq/dm+BWqb4KtwTO1XIwWMaElu/EF3s+r1FRNGIS2bzK0uuAQ+dd3TlJKaoSiHp8Y09Q0ZZA==" - }, + "node_modules/dotparser": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/dotparser/-/dotparser-1.1.1.tgz", + "integrity": "sha512-8ojhUts0HbLnXJgjTiJOddwVVBUk6hg4SJ5kGiuhzgK/f+y79TiWvICwx1oCWlVbBC8YI3nEaIQg9fjGYbGBXw==", + "license": "MIT" + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/duplexer2": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz", + "integrity": "sha512-asLFVfWWtJ90ZyOUHMqk7/S2w2guQKxUI2itj3d92ADHhxUSbCMGi1f1cBcJ7xM1To+pE/Khbwo1yuNbMEPKeA==", + "license": "BSD-3-Clause", + "dependencies": { + "readable-stream": "^2.0.2" + } + }, "node_modules/duplexify": { "version": "3.7.1", "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz", "integrity": "sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==", + "license": "MIT", "dependencies": { "end-of-stream": "^1.0.0", "inherits": "^2.0.1", @@ -2023,67 +2645,28 @@ "stream-shift": "^1.0.0" } }, - "node_modules/duplexify/node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" - }, - "node_modules/duplexify/node_modules/readable-stream": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", - "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/duplexify/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" - }, - "node_modules/duplexify/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dependencies": { - "safe-buffer": "~5.1.0" - } + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true, + "license": "MIT" }, "node_modules/ecc-jsbn": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", "integrity": "sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==", - "dev": true, + "license": "MIT", "dependencies": { "jsbn": "~0.1.0", "safer-buffer": "^2.1.0" } }, - "node_modules/eccrypto": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/eccrypto/-/eccrypto-1.0.3.tgz", - "integrity": "sha512-YVxyqtW/aZPNgxzecq48K3C4t3A4+SFMIVKnKZvwGRNfDlqvs4JlY8/idp+qLDcN8BhRKbrYNxBMIa9DY1VVDQ==", - "dev": true, - "hasInstallScript": true, - "dependencies": { - "elliptic": "^6.0.2", - "es6-promise": "^3.0.2", - "nan": "^2.1.0" - }, - "optionalDependencies": { - "secp256k1": "^2.0.4" - } - }, "node_modules/ecpair": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/ecpair/-/ecpair-2.0.1.tgz", - "integrity": "sha512-iT3wztQMeE/nDTlfnAg8dAFUfBS7Tq2BXzq3ae6L+pWgFU0fQ3l0woTzdTBrJV3OxBjxbzjq8EQhAbEmJNWFSw==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/ecpair/-/ecpair-2.1.0.tgz", + "integrity": "sha512-cL/mh3MtJutFOvFc27GPZE2pWL3a3k4YvzUWEOvilnfZVlH3Jwgx/7d6tlD7/75tNk8TG2m+7Kgtz0SI1tWcqw==", + "license": "MIT", "dependencies": { "randombytes": "^2.1.0", "typeforce": "^1.18.0", @@ -2097,42 +2680,79 @@ "version": "1.0.6", "resolved": "https://registry.npmjs.org/ecurve/-/ecurve-1.0.6.tgz", "integrity": "sha512-/BzEjNfiSuB7jIWKcS/z8FK9jNjmEWvUV2YZ4RLSmcDtP7Lq0m6FvDuSnJpBlDpGRpfRQeTLGLBI8H+kEv0r+w==", + "license": "MIT", "dependencies": { "bigi": "^1.1.0", "safe-buffer": "^5.0.1" } }, "node_modules/editorconfig": { - "version": "0.15.3", - "resolved": "https://registry.npmjs.org/editorconfig/-/editorconfig-0.15.3.tgz", - "integrity": "sha512-M9wIMFx96vq0R4F+gRpY3o2exzb8hEj/n9S8unZtHSvYjibBp/iMufSzvmOcV/laG0ZtuTVGtiJggPOSW2r93g==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/editorconfig/-/editorconfig-1.0.4.tgz", + "integrity": "sha512-L9Qe08KWTlqYMVvMcTIvMAdl1cDUubzRNYL+WfA4bLDMHe4nemKkpmYzkznE1FwLKu0EEmy6obgQKzMJrg4x9Q==", "dev": true, + "license": "MIT", "dependencies": { - "commander": "^2.19.0", - "lru-cache": "^4.1.5", - "semver": "^5.6.0", - "sigmund": "^1.0.1" + "@one-ini/wasm": "0.1.1", + "commander": "^10.0.0", + "minimatch": "9.0.1", + "semver": "^7.5.3" }, "bin": { "editorconfig": "bin/editorconfig" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/editorconfig/node_modules/brace-expansion": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" } }, "node_modules/editorconfig/node_modules/commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "dev": true + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", + "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14" + } + }, + "node_modules/editorconfig/node_modules/minimatch": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.1.tgz", + "integrity": "sha512-0jWhJpD/MdhPXwPuiRkCbfYfSKp2qnn2eOc279qI7f+osl/l+prKSrvhg157zSYvx/1nmgn2NqdT6k2Z7zSH9w==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } }, "node_modules/ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/elliptic": { - "version": "6.5.4", - "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz", - "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==", + "version": "6.6.1", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.6.1.tgz", + "integrity": "sha512-RaddvvMatK2LJHqFJ+YA4WysVN5Ita9E35botqIYspQ4TkRAlCicdzKOjlyv/1Za5RyTNn7di//eEV0uTAfe3g==", + "license": "MIT", "dependencies": { "bn.js": "^4.11.9", "brorand": "^1.1.0", @@ -2143,39 +2763,47 @@ "minimalistic-crypto-utils": "^1.0.1" } }, + "node_modules/elliptic/node_modules/bn.js": { + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.2.tgz", + "integrity": "sha512-n4DSx829VRTRByMRGdjQ9iqsN0Bh4OolPsFnaZBLcbi8iXcB+kJ9s7EnRt4wILZNV3kPLHkRVfOc/HvhC3ovDw==", + "license": "MIT" + }, "node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true + "license": "MIT" }, "node_modules/encodeurl": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.8" } }, - "node_modules/encoding-down": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/encoding-down/-/encoding-down-7.1.0.tgz", - "integrity": "sha512-ky47X5jP84ryk5EQmvedQzELwVJPjCgXDQZGeb9F6r4PdChByCGHTBrVcF3h8ynKVJ1wVbkxTsDC8zBROPypgQ==", + "node_modules/encoding-sniffer": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/encoding-sniffer/-/encoding-sniffer-0.2.1.tgz", + "integrity": "sha512-5gvq20T6vfpekVtqrYQsSCFZ1wEg5+wW0/QaZMWkFr6BqD3NfKs0rLCx4rrVlSWJeZb5NBJgVLswK/w2MWU+Gw==", + "dev": true, + "license": "MIT", "dependencies": { - "abstract-leveldown": "^7.2.0", - "inherits": "^2.0.3", - "level-codec": "^10.0.0", - "level-errors": "^3.0.0" + "iconv-lite": "^0.6.3", + "whatwg-encoding": "^3.1.1" }, - "engines": { - "node": ">=10" + "funding": { + "url": "https://github.com/fb55/encoding-sniffer?sponsor=1" } }, "node_modules/end-of-stream": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", - "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz", + "integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==", + "license": "MIT", "dependencies": { "once": "^1.4.0" } @@ -2184,7 +2812,8 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz", "integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==", - "dev": true + "dev": true, + "license": "BSD-2-Clause" }, "node_modules/error": { "version": "7.0.2", @@ -2196,30 +2825,72 @@ "xtend": "~4.0.0" } }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/es6-promise": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-3.3.1.tgz", - "integrity": "sha512-SOp9Phqvqn7jtEUxPWdWfWoLmyt2VaJ6MpvP9Comy1MceMXqE6bxvaTu4iaxpYYPzhny28Lc+M87/c2cPK6lDg==", - "dev": true + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", + "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==", + "license": "MIT" }, "node_modules/es6-promisify": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", "integrity": "sha512-C+d6UdsYDk0lMebHNR4S2NybQMMngAOnOwYBQjTOiv0MkoJMP0Myw2mgpDLBcpfCmRLxyFqYhS/CfOENq4SJhQ==", + "license": "MIT", "dependencies": { "es6-promise": "^4.0.3" } }, - "node_modules/es6-promisify/node_modules/es6-promise": { - "version": "4.2.8", - "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", - "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==" - }, "node_modules/escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } @@ -2229,6 +2900,7 @@ "resolved": "https://registry.npmjs.org/escape-goat/-/escape-goat-3.0.0.tgz", "integrity": "sha512-w3PwNZJwRxlp47QGzhuEBldEqVHHhh8/tIPcl6ecf2Bou99cdAt0knihBV0Ecc7CGxYduXVBDheH1K2oADRlvw==", "dev": true, + "license": "MIT", "engines": { "node": ">=10" }, @@ -2240,141 +2912,128 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", "dev": true, + "license": "MIT", "engines": { - "node": ">=0.8.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/eslint": { - "version": "5.16.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-5.16.0.tgz", - "integrity": "sha512-S3Rz11i7c8AA5JPv7xAH+dOyq/Cu/VXHiHXBPOU1k/JAM5dXqQPt3qcrhpHSorXmrpu2g0gkIBVXAqCpzfoZIg==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.0.0", - "ajv": "^6.9.1", - "chalk": "^2.1.0", - "cross-spawn": "^6.0.5", - "debug": "^4.0.1", - "doctrine": "^3.0.0", - "eslint-scope": "^4.0.3", - "eslint-utils": "^1.3.1", - "eslint-visitor-keys": "^1.0.0", - "espree": "^5.0.1", - "esquery": "^1.0.1", + "version": "9.19.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.19.0.tgz", + "integrity": "sha512-ug92j0LepKlbbEv6hD911THhoRHmbdXt2gX+VDABAW/Ir7D3nqKdv5Pf5vtlyY6HQMTEP2skXY43ueqTCWssEA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.12.1", + "@eslint/config-array": "^0.19.0", + "@eslint/core": "^0.10.0", + "@eslint/eslintrc": "^3.2.0", + "@eslint/js": "9.19.0", + "@eslint/plugin-kit": "^0.2.5", + "@humanfs/node": "^0.16.6", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.4.1", + "@types/estree": "^1.0.6", + "@types/json-schema": "^7.0.15", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.6", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^8.2.0", + "eslint-visitor-keys": "^4.2.0", + "espree": "^10.3.0", + "esquery": "^1.5.0", "esutils": "^2.0.2", - "file-entry-cache": "^5.0.1", - "functional-red-black-tree": "^1.0.1", - "glob": "^7.1.2", - "globals": "^11.7.0", - "ignore": "^4.0.6", - "import-fresh": "^3.0.0", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", "imurmurhash": "^0.1.4", - "inquirer": "^6.2.2", - "js-yaml": "^3.13.0", + "is-glob": "^4.0.0", "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.3.0", - "lodash": "^4.17.11", - "minimatch": "^3.0.4", - "mkdirp": "^0.5.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", "natural-compare": "^1.4.0", - "optionator": "^0.8.2", - "path-is-inside": "^1.0.2", - "progress": "^2.0.0", - "regexpp": "^2.0.1", - "semver": "^5.5.1", - "strip-ansi": "^4.0.0", - "strip-json-comments": "^2.0.1", - "table": "^5.2.3", - "text-table": "^0.2.0" + "optionator": "^0.9.3" }, "bin": { "eslint": "bin/eslint.js" }, "engines": { - "node": "^6.14.0 || ^8.10.0 || >=9.10.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } } }, "node_modules/eslint-scope": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.3.tgz", - "integrity": "sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg==", + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz", + "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { - "esrecurse": "^4.1.0", - "estraverse": "^4.1.1" + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" }, "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/eslint-utils": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.4.3.tgz", - "integrity": "sha512-fbBN5W2xdY45KulGXmLHZ3c3FHfVYmKg0IrAKGOkT/464PQsx2UeIzfz1RmEci+KLm1bBaAzZAh8+/E+XAeZ8Q==", - "dev": true, - "dependencies": { - "eslint-visitor-keys": "^1.1.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, - "engines": { - "node": ">=6" + "funding": { + "url": "https://opencollective.com/eslint" } }, "node_modules/eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/eslint/node_modules/cross-spawn": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", - "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", + "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", "dev": true, - "dependencies": { - "nice-try": "^1.0.4", - "path-key": "^2.0.1", - "semver": "^5.5.0", - "shebang-command": "^1.2.0", - "which": "^1.2.9" - }, + "license": "Apache-2.0", "engines": { - "node": ">=4.8" - } - }, - "node_modules/eslint/node_modules/mkdirp": { - "version": "0.5.6", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", - "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", - "dev": true, - "dependencies": { - "minimist": "^1.2.6" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, - "bin": { - "mkdirp": "bin/cmd.js" + "funding": { + "url": "https://opencollective.com/eslint" } }, "node_modules/espree": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-5.0.1.tgz", - "integrity": "sha512-qWAZcWh4XE/RwzLJejfcofscgMc9CamR6Tn1+XRXNzrvUSSbiAjGOI/fggztjIi7y9VLPqnICMIPiGyr8JaZ0A==", + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", + "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { - "acorn": "^6.0.7", - "acorn-jsx": "^5.0.0", - "eslint-visitor-keys": "^1.0.0" + "acorn": "^8.15.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.2.1" }, "engines": { - "node": ">=6.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, "node_modules/esprima": { @@ -2382,6 +3041,7 @@ "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", "dev": true, + "license": "BSD-2-Clause", "bin": { "esparse": "bin/esparse.js", "esvalidate": "bin/esvalidate.js" @@ -2391,10 +3051,11 @@ } }, "node_modules/esquery": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", - "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", + "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "estraverse": "^5.1.0" }, @@ -2402,20 +3063,12 @@ "node": ">=0.10" } }, - "node_modules/esquery/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, "node_modules/esrecurse": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "estraverse": "^5.2.0" }, @@ -2423,20 +3076,12 @@ "node": ">=4.0" } }, - "node_modules/esrecurse/node_modules/estraverse": { + "node_modules/estraverse": { "version": "5.3.0", "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true, + "license": "BSD-2-Clause", "engines": { "node": ">=4.0" } @@ -2446,6 +3091,7 @@ "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", "dev": true, + "license": "BSD-2-Clause", "engines": { "node": ">=0.10.0" } @@ -2455,6 +3101,7 @@ "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.6" } @@ -2463,48 +3110,32 @@ "version": "4.0.7", "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", - "dev": true + "dev": true, + "license": "MIT" + }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "license": "MIT", + "engines": { + "node": ">=0.8.x" + } }, "node_modules/extend": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", - "dev": true - }, - "node_modules/external-editor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", - "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", - "dev": true, - "dependencies": { - "chardet": "^0.7.0", - "iconv-lite": "^0.4.24", - "tmp": "^0.0.33" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/external-editor/node_modules/tmp": { - "version": "0.0.33", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", - "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", - "dev": true, - "dependencies": { - "os-tmpdir": "~1.0.2" - }, - "engines": { - "node": ">=0.6.0" - } + "license": "MIT" }, "node_modules/extsprintf": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", "integrity": "sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==", - "dev": true, "engines": [ "node >=0.6.0" - ] + ], + "license": "MIT" }, "node_modules/eyes": { "version": "0.1.8", @@ -2518,30 +3149,72 @@ "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true + "dev": true, + "license": "MIT" + }, + "node_modules/fast-glob": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.8" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } }, "node_modules/fast-json-patch": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/fast-json-patch/-/fast-json-patch-3.1.1.tgz", - "integrity": "sha512-vf6IHUX2SBcA+5/+4883dsIjpBTqmfBjmYiWK1savxQmFk4JfBMLa7ynTYOs1Rolp/T1betJxHiGD3g1Mn8lUQ==" + "integrity": "sha512-vf6IHUX2SBcA+5/+4883dsIjpBTqmfBjmYiWK1savxQmFk4JfBMLa7ynTYOs1Rolp/T1betJxHiGD3g1Mn8lUQ==", + "license": "MIT" }, "node_modules/fast-json-stable-stringify": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/fast-levenshtein": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", - "dev": true + "dev": true, + "license": "MIT" + }, + "node_modules/fastq": { + "version": "1.19.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz", + "integrity": "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==", + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } }, "node_modules/faye-websocket": { "version": "0.10.0", "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.10.0.tgz", "integrity": "sha512-Xhj93RXbMSq8urNCUq4p9l0P6hnySJ/7YNRhYNug0bLOuii7pKO7xQFb5mx9xZXWCar88pLPb805PvUkwrLZpQ==", "dev": true, + "license": "MIT", "dependencies": { "websocket-driver": ">=0.5.1" }, @@ -2549,64 +3222,46 @@ "node": ">=0.4.0" } }, - "node_modules/figures": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", - "integrity": "sha512-Oa2M9atig69ZkfwiApY8F2Yy+tzMbazyvqv21R0NsSC8floSOC09BbT1ITWAdoMGQvJ/aZnR1KMwdx9tvHnTNA==", - "dev": true, - "dependencies": { - "escape-string-regexp": "^1.0.5" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/file-entry-cache": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz", - "integrity": "sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", "dev": true, + "license": "MIT", "dependencies": { - "flat-cache": "^2.0.1" + "flat-cache": "^4.0.0" }, "engines": { - "node": ">=4" + "node": ">=16.0.0" } }, "node_modules/file-set": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/file-set/-/file-set-4.0.2.tgz", - "integrity": "sha512-fuxEgzk4L8waGXaAkd8cMr73Pm0FxOVkn8hztzUW7BAHhOGH90viQNXbiOsnecCWmfInqU6YmAMwxRMdKETceQ==", + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/file-set/-/file-set-5.3.0.tgz", + "integrity": "sha512-FKCxdjLX0J6zqTWdT0RXIxNF/n7MyXXnsSUp0syLEOCKdexvPZ02lNNv2a+gpK9E3hzUYF3+eFZe32ci7goNUg==", "dev": true, + "license": "MIT", "dependencies": { - "array-back": "^5.0.0", - "glob": "^7.1.6" + "array-back": "^6.2.2", + "fast-glob": "^3.3.2" }, "engines": { - "node": ">=10" - } - }, - "node_modules/file-set/node_modules/array-back": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/array-back/-/array-back-5.0.0.tgz", - "integrity": "sha512-kgVWwJReZWmVuWOQKEOohXKJX+nD02JAZ54D1RRWlv8L0NebauKAaFxACKzB74RTclt1+WNz5KHaLRDAPZbDEw==", - "dev": true, - "engines": { - "node": ">=10" + "node": ">=12.17" + }, + "peerDependencies": { + "@75lb/nature": "latest" + }, + "peerDependenciesMeta": { + "@75lb/nature": { + "optional": true + } } }, - "node_modules/file-uri-to-path": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", - "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", - "dev": true, - "optional": true - }, "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "license": "MIT", "dependencies": { "to-regex-range": "^5.0.1" }, @@ -2615,24 +3270,21 @@ } }, "node_modules/find-replace": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-replace/-/find-replace-3.0.0.tgz", - "integrity": "sha512-6Tb2myMioCAgv5kfvP5/PkZZ/ntTpVK39fHY7WkWBgvbeE+VHd/tZuZ4mrC+bxh4cfOZeYKVPaJIZtZXV7GNCQ==", - "dev": true, - "dependencies": { - "array-back": "^3.0.1" - }, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/find-replace/node_modules/array-back": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/array-back/-/array-back-3.1.0.tgz", - "integrity": "sha512-TkuxA4UCOvxuDK6NZYXCalszEzj+TLszyASooky+i742l9TqsOdYCMJJupxRic61hwquNtppB3hgcuq9SVSH1Q==", + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/find-replace/-/find-replace-5.0.2.tgz", + "integrity": "sha512-Y45BAiE3mz2QsrN2fb5QEtO4qb44NcS7en/0y9PEVsg351HsLeVclP8QPMH79Le9sH3rs5RSwJu99W0WPZO43Q==", "dev": true, + "license": "MIT", "engines": { - "node": ">=6" + "node": ">=14" + }, + "peerDependencies": { + "@75lb/nature": "latest" + }, + "peerDependenciesMeta": { + "@75lb/nature": { + "optional": true + } } }, "node_modules/find-up": { @@ -2640,6 +3292,7 @@ "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", "dev": true, + "license": "MIT", "dependencies": { "locate-path": "^6.0.0", "path-exists": "^4.0.0" @@ -2656,46 +3309,36 @@ "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", "dev": true, + "license": "BSD-3-Clause", "bin": { "flat": "cli.js" } }, "node_modules/flat-cache": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz", - "integrity": "sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", "dev": true, + "license": "MIT", "dependencies": { - "flatted": "^2.0.0", - "rimraf": "2.6.3", - "write": "1.0.3" + "flatted": "^3.2.9", + "keyv": "^4.5.4" }, "engines": { - "node": ">=4" - } - }, - "node_modules/flat-cache/node_modules/rimraf": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", - "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", - "dev": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" + "node": ">=16" } }, "node_modules/flatted": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.2.tgz", - "integrity": "sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA==", - "dev": true + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", + "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", + "dev": true, + "license": "ISC" }, "node_modules/follow-redirects": { - "version": "1.15.2", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz", - "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==", + "version": "1.15.11", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.11.tgz", + "integrity": "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==", "dev": true, "funding": [ { @@ -2703,6 +3346,7 @@ "url": "https://github.com/sponsors/RubenVerborgh" } ], + "license": "MIT", "engines": { "node": ">=4.0" }, @@ -2712,104 +3356,67 @@ } } }, - "node_modules/foreach": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/foreach/-/foreach-2.0.6.tgz", - "integrity": "sha512-k6GAGDyqLe9JaebCsFCoudPPWfihKu8pylYXRlqP1J7ms39iPoTtk2fviNglIeQEwdh0bQeKJ01ZPyuyQvKzwg==" - }, - "node_modules/foreground-child": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-2.0.0.tgz", - "integrity": "sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA==", - "dev": true, + "node_modules/for-each": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz", + "integrity": "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==", + "license": "MIT", "dependencies": { - "cross-spawn": "^7.0.0", - "signal-exit": "^3.0.2" + "is-callable": "^1.2.7" }, "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/foreground-child/node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" + "node": ">= 0.4" }, - "engines": { - "node": ">= 8" + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/foreground-child/node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, - "engines": { - "node": ">=8" - } + "node_modules/foreach": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/foreach/-/foreach-2.0.6.tgz", + "integrity": "sha512-k6GAGDyqLe9JaebCsFCoudPPWfihKu8pylYXRlqP1J7ms39iPoTtk2fviNglIeQEwdh0bQeKJ01ZPyuyQvKzwg==", + "license": "MIT" }, - "node_modules/foreground-child/node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "node_modules/foreground-child": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", + "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", "dev": true, + "license": "ISC", "dependencies": { - "shebang-regex": "^3.0.0" + "cross-spawn": "^7.0.6", + "signal-exit": "^4.0.1" }, "engines": { - "node": ">=8" - } - }, - "node_modules/foreground-child/node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/foreground-child/node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "dependencies": { - "isexe": "^2.0.0" + "node": ">=14" }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, "node_modules/forever-agent": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", "integrity": "sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==", - "dev": true, + "license": "Apache-2.0", "engines": { "node": "*" } }, "node_modules/form-data": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", - "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", - "dev": true, + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.4.tgz", + "integrity": "sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==", + "license": "MIT", "dependencies": { "asynckit": "^0.4.0", - "combined-stream": "^1.0.6", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "hasown": "^2.0.2", "mime-types": "^2.1.12" }, "engines": { - "node": ">= 0.12" + "node": ">= 6" } }, "node_modules/fresh": { @@ -2817,6 +3424,7 @@ "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.6" } @@ -2826,15 +3434,40 @@ "resolved": "https://registry.npmjs.org/front-matter/-/front-matter-2.3.0.tgz", "integrity": "sha512-+gOIDsGWHVAiWSDfg3vpiHwkOrwO4XNS3YQH5DMmneLEPWzdCAnbSQCtxReF4yPK1nszLvAmLeR2SprnDQDnyQ==", "dev": true, + "license": "MIT", "dependencies": { "js-yaml": "^3.10.0" } }, + "node_modules/front-matter/node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "license": "MIT", + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/front-matter/node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, "node_modules/fs-extra": { "version": "10.0.1", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.0.1.tgz", "integrity": "sha512-NbdoVMZso2Lsrn/QwLXOy6rm0ufY2zEOKCDzJR/0kBsb0E6qed0P3iYK+Ath3BfvXEeu4JhEtXLgILx5psUfag==", - "dev": true, + "license": "MIT", "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", @@ -2844,26 +3477,32 @@ "node": ">=12" } }, - "node_modules/fs-then-native": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/fs-then-native/-/fs-then-native-2.0.0.tgz", - "integrity": "sha512-X712jAOaWXkemQCAmWeg5rOT2i+KOpWz1Z/txk/cW0qlOu2oQ9H61vc5w3X/iyuUEfq/OyaFJ78/cZAQD1/bgA==", - "dev": true, + "node_modules/fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "license": "ISC", + "dependencies": { + "minipass": "^3.0.0" + }, "engines": { - "node": ">=4.0.0" + "node": ">= 8" } }, "node_modules/fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true, + "license": "ISC" }, "node_modules/fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", "dev": true, "hasInstallScript": true, + "license": "MIT", "optional": true, "os": [ "darwin" @@ -2873,22 +3512,46 @@ } }, "node_modules/function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, - "node_modules/functional-red-black-tree": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", - "integrity": "sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==", - "dev": true + "node_modules/gauge": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-4.0.4.tgz", + "integrity": "sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg==", + "deprecated": "This package is no longer supported.", + "license": "ISC", + "dependencies": { + "aproba": "^1.0.3 || ^2.0.0", + "color-support": "^1.1.3", + "console-control-strings": "^1.1.0", + "has-unicode": "^2.0.1", + "signal-exit": "^3.0.7", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "wide-align": "^1.1.5" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/gauge/node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "license": "ISC" }, "node_modules/generate-function": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.3.1.tgz", "integrity": "sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ==", "dev": true, + "license": "MIT", "dependencies": { "is-property": "^1.0.2" } @@ -2898,51 +3561,92 @@ "resolved": "https://registry.npmjs.org/generate-object-property/-/generate-object-property-1.2.0.tgz", "integrity": "sha512-TuOwZWgJ2VAMEGJvAyPWvpqxSANF0LDpmyHauMjFYzaACvn+QTT/AZomvPCzVBV7yDN3OmwHQ5OvHaeLKre3JQ==", "dev": true, + "license": "MIT", "dependencies": { "is-property": "^1.0.0" } }, + "node_modules/generic-pool": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/generic-pool/-/generic-pool-3.9.0.tgz", + "integrity": "sha512-hymDOu5B53XvN4QT9dBmZxPX4CWhBPPLguTZ9MMFeFa/Kg0xWVfylOVNlJji/E7yTZWFd/q9GO5TxDLq156D7g==", + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, "node_modules/get-caller-file": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", "dev": true, + "license": "ISC", "engines": { "node": "6.* || 8.* || >= 10.*" } }, "node_modules/get-func-name": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz", - "integrity": "sha512-Hm0ixYtaSZ/V7C8FJrtZIuBBI+iSgL+1Aq82zSu8VQNB4S3Gk8e7Qs3VwBDJAhmRZcFqkl3tQu36g/Foh5I5ig==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz", + "integrity": "sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==", "dev": true, + "license": "MIT", "engines": { "node": "*" } }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/getpass": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", "integrity": "sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==", - "dev": true, + "license": "MIT", "dependencies": { "assert-plus": "^1.0.0" } }, - "node_modules/gitbook-plugin-fontsettings": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/gitbook-plugin-fontsettings/-/gitbook-plugin-fontsettings-2.0.0.tgz", - "integrity": "sha512-bZpz/Jev7lL1d3VNp41KHZD67UYqyqdOwbsJE6YEW93R2mGiLfZLpUs86d2nrY61BedhlNck1xF52FNT6sWeig==", - "dev": true, - "engines": { - "gitbook": ">=2.4.0" - } - }, "node_modules/gitbook-plugin-livereload": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/gitbook-plugin-livereload/-/gitbook-plugin-livereload-0.0.1.tgz", "integrity": "sha512-+5xinicId2ZcbP6jBTFfQBnjz8nhoBgcOuQfKTEM6Yg9fBsmo2mxY6ubrx1b5ozuIMyfDLkSihx97A7+X+EtQQ==", "dev": true, + "license": "Apache 2", "engines": { "gitbook": "*" } @@ -2952,6 +3656,7 @@ "resolved": "https://registry.npmjs.org/gitbook-plugin-lunr/-/gitbook-plugin-lunr-1.2.0.tgz", "integrity": "sha512-QBfFLMZmoyOfLzc5aZrlRCkmzb9YcSjzdnyJFiRI/nX+Nd6kK1XyN4DLGnNSMHkRcJchcpWiQ6XGqSqo7e+d+g==", "dev": true, + "license": "Apache-2.0", "dependencies": { "gitbook-plugin-search": "*", "html-entities": "1.2.0", @@ -2966,6 +3671,7 @@ "resolved": "https://registry.npmjs.org/gitbook-plugin-search/-/gitbook-plugin-search-2.2.1.tgz", "integrity": "sha512-oP9jhaKFUVPo756G9ywuuI43YdkZClSjfpFzNKe/a/Rcn3oVsrAM/PjdQ+dt65KfZVo3iW1LY4WdiZnNqzRP8g==", "dev": true, + "license": "Apache-2.0", "engines": { "gitbook": ">=3.0.0-pre.0" } @@ -2974,75 +3680,81 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/github-slugid/-/github-slugid-1.0.1.tgz", "integrity": "sha512-L5uVRzSM8jyWTgHUtaHwmymZW8S234JrIaOGotPK+0emNz9XsO6qqgw1KiI5YfP1SyBjG0ApNYU0vpb01teM9Q==", - "dev": true + "dev": true, + "license": "Apache-2.0" }, "node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", + "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "license": "ISC", "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", - "minimatch": "^3.1.1", + "minimatch": "^3.0.4", "once": "^1.3.0", "path-is-absolute": "^1.0.0" }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "engines": { + "node": "*" } }, "node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", "dev": true, + "license": "ISC", "dependencies": { - "is-glob": "^4.0.1" + "is-glob": "^4.0.3" }, "engines": { - "node": ">= 6" + "node": ">=10.13.0" } }, - "node_modules/glob-run": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/glob-run/-/glob-run-0.1.7.tgz", - "integrity": "sha512-8zLtPFAhK1kL6nghJfwDW5LEggkEXJxsq+bvTzwiluAjvGCIoyi3grpWs0dESSPqYOJ/184oIYqT3+szTqwyjw==", + "node_modules/globals": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", "dev": true, - "dependencies": { - "async": "^3.1.0", - "glob": "^7.1.4" + "license": "MIT", + "engines": { + "node": ">=18" }, - "bin": { - "glob-run": "bin/glob-run" + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "dev": true, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "license": "MIT", "engines": { - "node": ">=4" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/graceful-fs": { - "version": "4.2.10", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", - "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", - "dev": true + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "license": "ISC" }, "node_modules/handlebars": { - "version": "4.7.7", - "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.7.tgz", - "integrity": "sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA==", + "version": "4.7.8", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.8.tgz", + "integrity": "sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==", "dev": true, + "license": "MIT", "dependencies": { "minimist": "^1.2.5", - "neo-async": "^2.6.0", + "neo-async": "^2.6.2", "source-map": "^0.6.1", "wordwrap": "^1.0.0" }, @@ -3056,77 +3768,104 @@ "uglify-js": "^3.1.4" } }, - "node_modules/har-schema": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", - "integrity": "sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q==", + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, + "license": "MIT", "engines": { - "node": ">=4" + "node": ">=8" } }, - "node_modules/har-validator": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", - "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", - "deprecated": "this library is no longer supported", - "dev": true, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "license": "MIT", "dependencies": { - "ajv": "^6.12.3", - "har-schema": "^2.0.0" + "es-define-property": "^1.0.0" }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "license": "MIT", "engines": { - "node": ">=6" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "license": "MIT", "dependencies": { - "function-bind": "^1.1.1" + "has-symbols": "^1.0.3" }, "engines": { - "node": ">= 0.4.0" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true, - "engines": { - "node": ">=4" - } + "node_modules/has-unicode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==", + "license": "ISC" }, "node_modules/hash-base": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.0.tgz", - "integrity": "sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.2.tgz", + "integrity": "sha512-Bb33KbowVTIj5s7Ked1OsqHUeCpz//tPwR+E2zJgJKo9Z5XolZ9b6bdUgjmYlwnWhoOQKoTd1TYToZGn5mAYOg==", + "license": "MIT", "dependencies": { "inherits": "^2.0.4", - "readable-stream": "^3.6.0", - "safe-buffer": "^5.2.0" + "readable-stream": "^2.3.8", + "safe-buffer": "^5.2.1", + "to-buffer": "^1.2.1" }, "engines": { - "node": ">=4" + "node": ">= 0.8" } }, "node_modules/hash.js": { "version": "1.1.7", "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", + "license": "MIT", "dependencies": { "inherits": "^2.0.3", "minimalistic-assert": "^1.0.1" } }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/he": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", "dev": true, + "license": "MIT", "bin": { "he": "bin/he" } @@ -3136,6 +3875,7 @@ "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-11.3.1.tgz", "integrity": "sha512-PUhCRnPjLtiLHZAQ5A/Dt5F8cWZeMyj9KRsACsWT+OD6OP0x6dp5OmT5jdx0JgEyPxPZZIPQpRN2TciUT7occw==", "dev": true, + "license": "BSD-3-Clause", "engines": { "node": ">=12.0.0" } @@ -3144,6 +3884,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", "integrity": "sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==", + "license": "MIT", "dependencies": { "hash.js": "^1.0.3", "minimalistic-assert": "^1.0.0", @@ -3151,109 +3892,157 @@ } }, "node_modules/honkit": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/honkit/-/honkit-4.0.4.tgz", - "integrity": "sha512-quKzP5kGGp3/Ey1+h9kISMa/NBmED7rSuaD8whdniGK/7OUJCEJg/0fKwZgLZLMAIS+AIowhxoV+gvQ30S1NFQ==", - "dev": true, - "dependencies": { - "@honkit/asciidoc": "^4.0.1", - "@honkit/honkit-plugin-highlight": "^4.0.0", - "@honkit/honkit-plugin-theme-default": "^4.0.3", - "@honkit/markdown-legacy": "^4.0.1", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/honkit/-/honkit-6.0.2.tgz", + "integrity": "sha512-5vV0jIyRHCigmvq0AVlgNenfNHdtOiaPK3L8N22NywBXNdrqszCEikhROKMWlqMB9CjpONXNcPu8Fj9tdnlYtQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@honkit/asciidoc": "6.0.2", + "@honkit/honkit-plugin-fontsettings": "6.0.2", + "@honkit/honkit-plugin-highlight": "6.0.2", + "@honkit/honkit-plugin-theme-default": "6.0.2", + "@honkit/html": "6.0.2", + "@honkit/markdown-legacy": "6.0.2", "bash-color": "^0.0.4", - "cheerio": "^1.0.0-rc.12", - "chokidar": "^3.3.0", + "cheerio": "^1.0.0", + "chokidar": "^3.6.0", "commander": "^5.1.0", "cp": "^0.2.0", "cpr": "^3.0.1", "crc": "^3.8.0", - "destroy": "^1.0.4", + "destroy": "^1.2.0", "direction": "^0.1.5", - "dom-serializer": "^0.1.0", + "dom-serializer": "^0.1.1", "error": "7.0.2", "escape-html": "^1.0.3", "escape-string-regexp": "^4.0.0", - "extend": "^3.0.0", + "extend": "^3.0.2", "flat-cache": "^2.0.1", - "front-matter": "^2.1.0", - "gitbook-plugin-fontsettings": "^2.0.0", + "front-matter": "^2.3.0", "gitbook-plugin-livereload": "^0.0.1", "gitbook-plugin-lunr": "^1.2.0", "gitbook-plugin-search": "^2.2.1", "github-slugid": "^1.0.1", "i18n-t": "^1.0.1", - "ignore": "^5.1.8", - "immutable": "^3.8.1", - "is": "^3.1.0", - "js-yaml": "^3.6.1", + "ignore": "^5.3.2", + "immutable": "^3.8.2", + "is": "^3.3.0", + "js-yaml": "^3.14.1", "json-schema-defaults": "^0.1.1", "jsonschema": "1.1.0", - "juice": "^8.0.0", + "juice": "^8.1.0", "lru_map": "^0.4.1", - "memoize-one": "^5.1.1", + "memoize-one": "^5.2.1", "mkdirp": "^1.0.4", - "moment": "^2.24.0", - "nunjucks": "^3.2.0", + "moment": "^2.30.1", + "nunjucks": "^3.2.4", "nunjucks-do": "^1.0.0", - "object-path": "^0.11.5", + "object-path": "^0.11.8", "omit-keys": "^0.1.0", - "open": "^7.0.0", + "open": "^7.4.2", "q": "^1.5.1", - "read-installed": "^4.0.3", - "request": "^2.88.0", - "resolve": "^1.17.0", - "semver": "^5.1.0", - "send": "^0.17.1", + "resolve": "^1.22.8", + "semver": "^7.6.3", + "send": "^0.17.2", "tiny-lr": "^1.1.1", "tmp": "0.0.28", "try-resolve": "^1.0.1", - "urijs": "^1.19.6" + "urijs": "^1.19.11" }, "bin": { "honkit": "bin/honkit.js" } }, + "node_modules/honkit/node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "license": "MIT", + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, "node_modules/honkit/node_modules/commander": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/commander/-/commander-5.1.0.tgz", "integrity": "sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==", "dev": true, + "license": "MIT", "engines": { "node": ">= 6" } }, - "node_modules/honkit/node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "node_modules/honkit/node_modules/flat-cache": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz", + "integrity": "sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==", "dev": true, + "license": "MIT", + "dependencies": { + "flatted": "^2.0.0", + "rimraf": "2.6.3", + "write": "1.0.3" + }, "engines": { - "node": ">=10" + "node": ">=4" + } + }, + "node_modules/honkit/node_modules/flatted": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.2.tgz", + "integrity": "sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA==", + "dev": true, + "license": "ISC" + }, + "node_modules/honkit/node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "bin": { + "js-yaml": "bin/js-yaml.js" } }, - "node_modules/honkit/node_modules/ignore": { - "version": "5.2.4", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", - "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", + "node_modules/honkit/node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", "dev": true, + "license": "MIT", + "bin": { + "mkdirp": "bin/cmd.js" + }, "engines": { - "node": ">= 4" + "node": ">=10" } }, - "node_modules/hosted-git-info": { - "version": "2.8.9", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", - "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", - "dev": true + "node_modules/honkit/node_modules/rimraf": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", + "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "dev": true, + "license": "ISC", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } }, "node_modules/html-encoding-sniffer": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-3.0.0.tgz", "integrity": "sha512-oWv4T4yJ52iKrufjnyZPkrN0CH3QnrUqdB6In1g5Fe1mia8GmF36gnfNySxoZtxD5+NmYw1EElVXiBk93UeskA==", "dev": true, + "license": "MIT", "dependencies": { "whatwg-encoding": "^2.0.0" }, @@ -3261,6 +4050,19 @@ "node": ">=12" } }, + "node_modules/html-encoding-sniffer/node_modules/whatwg-encoding": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-2.0.0.tgz", + "integrity": "sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg==", + "dev": true, + "license": "MIT", + "dependencies": { + "iconv-lite": "0.6.3" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/html-entities": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-1.2.0.tgz", @@ -3268,18 +4070,20 @@ "dev": true, "engines": [ "node >= 0.4.0" - ] + ], + "license": "MIT" }, "node_modules/html-escaper": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/htmlparser2": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.1.tgz", - "integrity": "sha512-4lVbmc1diZC7GUJQtRQ5yBAeUCL1exyMwmForWkRLnwyzWBFxN633SALPMGYaWZvKe9j1pRZJpauvmxENSp/EA==", + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-10.0.0.tgz", + "integrity": "sha512-TwAZM+zE5Tq3lrEHvOlvwgj1XLWQCtaaibSN11Q+gGBAS7Y1uZSWwXXRe4iF6OXnaq1riyQAPFOBtYc77Mxq0g==", "dev": true, "funding": [ "https://github.com/fb55/htmlparser2?sponsor=1", @@ -3288,18 +4092,20 @@ "url": "https://github.com/sponsors/fb55" } ], + "license": "MIT", "dependencies": { "domelementtype": "^2.3.0", - "domhandler": "^5.0.2", - "domutils": "^3.0.1", - "entities": "^4.3.0" + "domhandler": "^5.0.3", + "domutils": "^3.2.1", + "entities": "^6.0.0" } }, "node_modules/htmlparser2/node_modules/entities": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-4.4.0.tgz", - "integrity": "sha512-oYp7156SP8LkeGD0GF85ad1X9Ai79WtRsZ2gxJqtBuzH+98YUV6jkHEKlZkMbcrjJjIVJNIDP/3WL9wQkoPbWA==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz", + "integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==", "dev": true, + "license": "BSD-2-Clause", "engines": { "node": ">=0.12" }, @@ -3311,6 +4117,7 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.4.0.tgz", "integrity": "sha512-oLjPqve1tuOl5aRhv8GK5eHpqP1C9fb+Ol+XTLjKfLltE44zdDbEdjPSbU7Ch5rSNsVFqZn97SrMmZLdu1/YMw==", + "license": "MIT", "dependencies": { "inherits": "2.0.1", "statuses": ">= 1.2.1 < 2" @@ -3322,138 +4129,71 @@ "node_modules/http-errors/node_modules/inherits": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz", - "integrity": "sha512-8nWq2nLTAwd02jTqJExUYFSD/fKq6VH9Y/oG2accc/kdI0V98Bag8d5a4gi3XHz73rDWa2PvTtvcWYquKqSENA==" + "integrity": "sha512-8nWq2nLTAwd02jTqJExUYFSD/fKq6VH9Y/oG2accc/kdI0V98Bag8d5a4gi3XHz73rDWa2PvTtvcWYquKqSENA==", + "license": "ISC" }, "node_modules/http-parser-js": { - "version": "0.5.8", - "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.8.tgz", - "integrity": "sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q==", - "dev": true + "version": "0.5.10", + "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.10.tgz", + "integrity": "sha512-Pysuw9XpUq5dVc/2SMHpuTY01RFl8fttgcyunjL7eEMhGM3cI4eOmiCycJDVCo/7O7ClfQD3SaI6ftDzqOXYMA==", + "dev": true, + "license": "MIT" }, "node_modules/http-proxy": { "version": "1.18.1", "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", "dev": true, + "license": "MIT", "dependencies": { "eventemitter3": "^4.0.0", - "follow-redirects": "^1.0.0", - "requires-port": "^1.0.0" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/http-server": { - "version": "14.1.1", - "resolved": "https://registry.npmjs.org/http-server/-/http-server-14.1.1.tgz", - "integrity": "sha512-+cbxadF40UXd9T01zUHgA+rlo2Bg1Srer4+B4NwIHdaGxAGGv59nYRnGGDJ9LBk7alpS0US+J+bLLdQOOkJq4A==", - "dev": true, - "dependencies": { - "basic-auth": "^2.0.1", - "chalk": "^4.1.2", - "corser": "^2.0.1", - "he": "^1.2.0", - "html-encoding-sniffer": "^3.0.0", - "http-proxy": "^1.18.1", - "mime": "^1.6.0", - "minimist": "^1.2.6", - "opener": "^1.5.1", - "portfinder": "^1.0.28", - "secure-compare": "3.0.1", - "union": "~0.5.0", - "url-join": "^4.0.1" - }, - "bin": { - "http-server": "bin/http-server" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/http-server/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/http-server/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/http-server/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/http-server/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/http-server/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, + "follow-redirects": "^1.0.0", + "requires-port": "^1.0.0" + }, "engines": { - "node": ">=8" + "node": ">=8.0.0" } }, - "node_modules/http-server/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "node_modules/http-server": { + "version": "14.1.1", + "resolved": "https://registry.npmjs.org/http-server/-/http-server-14.1.1.tgz", + "integrity": "sha512-+cbxadF40UXd9T01zUHgA+rlo2Bg1Srer4+B4NwIHdaGxAGGv59nYRnGGDJ9LBk7alpS0US+J+bLLdQOOkJq4A==", "dev": true, + "license": "MIT", "dependencies": { - "has-flag": "^4.0.0" + "basic-auth": "^2.0.1", + "chalk": "^4.1.2", + "corser": "^2.0.1", + "he": "^1.2.0", + "html-encoding-sniffer": "^3.0.0", + "http-proxy": "^1.18.1", + "mime": "^1.6.0", + "minimist": "^1.2.6", + "opener": "^1.5.1", + "portfinder": "^1.0.28", + "secure-compare": "3.0.1", + "union": "~0.5.0", + "url-join": "^4.0.1" + }, + "bin": { + "http-server": "bin/http-server" }, "engines": { - "node": ">=8" + "node": ">=12" } }, "node_modules/http-signature": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", - "integrity": "sha512-CAbnr6Rz4CYQkLYUtSNXxQPUH2gK8f3iWexVlsnMeD+GjlsQ0Xsy1cOX+mN3dtxYomRy21CiOzU8Uhw6OwncEQ==", - "dev": true, + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.4.0.tgz", + "integrity": "sha512-G5akfn7eKbpDN+8nPS/cb57YeA1jLTVxjpCj7tmm3QKPdyDy7T+qSC40e9ptydSWvkwjSXw1VbkpyEm39ukeAg==", + "license": "MIT", "dependencies": { "assert-plus": "^1.0.0", - "jsprim": "^1.2.2", - "sshpk": "^1.7.0" + "jsprim": "^2.0.2", + "sshpk": "^1.18.0" }, "engines": { - "node": ">=0.8", - "npm": ">=1.3.7" + "node": ">=0.10" } }, "node_modules/i18n-t": { @@ -3461,17 +4201,19 @@ "resolved": "https://registry.npmjs.org/i18n-t/-/i18n-t-1.0.1.tgz", "integrity": "sha512-2NmZwpsnRTzpZfIP6Rcic16m5QBNVaIwVyU182+iatd6RNbWmGi74LTA/R/oDa58RZ87bHChLgWpmulEAoEruQ==", "dev": true, + "license": "Apache-2.0", "dependencies": { "lodash": "^4.13.1" } }, "node_modules/iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", "dev": true, + "license": "MIT", "dependencies": { - "safer-buffer": ">= 2.1.2 < 3" + "safer-buffer": ">= 2.1.2 < 3.0.0" }, "engines": { "node": ">=0.10.0" @@ -3494,13 +4236,15 @@ "type": "consulting", "url": "https://feross.org/support" } - ] + ], + "license": "BSD-3-Clause" }, "node_modules/ignore": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", - "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", "dev": true, + "license": "MIT", "engines": { "node": ">= 4" } @@ -3510,15 +4254,17 @@ "resolved": "https://registry.npmjs.org/immutable/-/immutable-3.8.2.tgz", "integrity": "sha512-15gZoQ38eYjEjxkorfbcgBKBL6R7T459OuK+CpcWt7O3KF4uPCx2tD0uFETlUDIyo+1789crbMhTvQBSR5yBMg==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", "dev": true, + "license": "MIT", "dependencies": { "parent-module": "^1.0.0", "resolve-from": "^4.0.0" @@ -3535,6 +4281,7 @@ "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.8.19" } @@ -3543,6 +4290,9 @@ "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "dev": true, + "license": "ISC", "dependencies": { "once": "^1.3.0", "wrappy": "1" @@ -3551,66 +4301,24 @@ "node_modules/inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "license": "ISC" }, "node_modules/ini": { "version": "1.3.8", "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", - "dev": true - }, - "node_modules/inquirer": { - "version": "6.5.2", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-6.5.2.tgz", - "integrity": "sha512-cntlB5ghuB0iuO65Ovoi8ogLHiWGs/5yNrtUcKjFhSSiVeAIVpD7koaSU9RM8mpXw5YDi9RdYXGQMaOURB7ycQ==", - "dev": true, - "dependencies": { - "ansi-escapes": "^3.2.0", - "chalk": "^2.4.2", - "cli-cursor": "^2.1.0", - "cli-width": "^2.0.0", - "external-editor": "^3.0.3", - "figures": "^2.0.0", - "lodash": "^4.17.12", - "mute-stream": "0.0.7", - "run-async": "^2.2.0", - "rxjs": "^6.4.0", - "string-width": "^2.1.0", - "strip-ansi": "^5.1.0", - "through": "^2.3.6" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/inquirer/node_modules/ansi-regex": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz", - "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/inquirer/node_modules/strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", "dev": true, - "dependencies": { - "ansi-regex": "^4.1.0" - }, - "engines": { - "node": ">=6" - } + "license": "ISC" }, "node_modules/is": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/is/-/is-3.3.0.tgz", - "integrity": "sha512-nW24QBoPcFGGHJGUwnfpI7Yc5CdqWNdsyHQszVE/z2pKHXzh7FZ5GWhJqSyaQ9wMkQnsTx+kAI8bHlCX4tKdbg==", + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/is/-/is-3.3.2.tgz", + "integrity": "sha512-a2xr4E3s1PjDS8ORcGgXpWx6V+liNs+O3JRD2mb9aeugD7rtkkZ0zgLdYgw0tWsKhsdiezGYptSiMlVazCBTuQ==", "dev": true, + "license": "MIT", "engines": { - "node": "*" + "node": ">= 0.4" } }, "node_modules/is-binary-path": { @@ -3618,6 +4326,7 @@ "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", "dev": true, + "license": "MIT", "dependencies": { "binary-extensions": "^2.0.0" }, @@ -3643,17 +4352,33 @@ "url": "https://feross.org/support" } ], + "license": "MIT", "engines": { "node": ">=4" } }, + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-core-module": { - "version": "2.11.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz", - "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==", - "dev": true, + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", + "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", + "license": "MIT", "dependencies": { - "has": "^1.0.3" + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -3664,6 +4389,7 @@ "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", "dev": true, + "license": "MIT", "bin": { "is-docker": "cli.js" }, @@ -3678,25 +4404,25 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==", - "dev": true, + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "license": "MIT", "engines": { - "node": ">=4" + "node": ">=8" } }, "node_modules/is-glob": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, + "license": "MIT", "dependencies": { "is-extglob": "^2.1.1" }, @@ -3708,13 +4434,15 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-my-ip-valid/-/is-my-ip-valid-1.0.1.tgz", "integrity": "sha512-jxc8cBcOWbNK2i2aTkCZP6i7wkHF1bqKFrwEHuN5Jtg5BSaZHUZQ/JTOJwoV41YvHnOaRyWWh72T/KvfNz9DJg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/is-my-json-valid": { "version": "2.20.6", "resolved": "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.20.6.tgz", "integrity": "sha512-1JQwulVNjx8UqkPE/bqDaxtH4PXCe/2VRh/y3p99heOV87HG4Id5/VfDswd+YiAfHcRTfDlWgISycnHuhZq1aw==", "dev": true, + "license": "MIT", "dependencies": { "generate-function": "^2.0.0", "generate-object-property": "^1.1.0", @@ -3727,7 +4455,7 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true, + "license": "MIT", "engines": { "node": ">=0.12.0" } @@ -3737,6 +4465,7 @@ "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -3745,19 +4474,36 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz", "integrity": "sha512-Ks/IoX00TtClbGQr4TWXemAnktAQvYB7HzcCxDGqEZU6oCmb2INHuOoKxbtR+HFkmYWBKv/dOZtGRiAjDhj92g==", - "dev": true + "dev": true, + "license": "MIT" + }, + "node_modules/is-typed-array": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz", + "integrity": "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==", + "license": "MIT", + "dependencies": { + "which-typed-array": "^1.1.16" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, "node_modules/is-typedarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==", - "dev": true + "license": "MIT" }, "node_modules/is-unicode-supported": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", "dev": true, + "license": "MIT", "engines": { "node": ">=10" }, @@ -3765,20 +4511,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/is-windows": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", - "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/is-wsl": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", "dev": true, + "license": "MIT", "dependencies": { "is-docker": "^2.0.0" }, @@ -3789,13 +4527,14 @@ "node_modules/isarray": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==" + "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==", + "license": "MIT" }, "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true + "license": "ISC" }, "node_modules/isobject": { "version": "0.2.0", @@ -3810,6 +4549,7 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/isomorphic-ws/-/isomorphic-ws-4.0.1.tgz", "integrity": "sha512-BhBvN2MBpWTaSHdWRb/bwdZJ1WaehQ2L1KngkCkfLUGF0mAWAT1sQUQacEmQ0jXkFw/czDXPNQSL5u2/Krsz1w==", + "license": "MIT", "peerDependencies": { "ws": "*" } @@ -3818,74 +4558,74 @@ "version": "0.1.2", "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", "integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==", - "dev": true + "license": "MIT" }, "node_modules/istanbul-lib-coverage": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz", - "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==", + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", + "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", "dev": true, + "license": "BSD-3-Clause", "engines": { "node": ">=8" } }, "node_modules/istanbul-lib-report": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", - "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", + "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "istanbul-lib-coverage": "^3.0.0", - "make-dir": "^3.0.0", + "make-dir": "^4.0.0", "supports-color": "^7.1.0" }, "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-report/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" + "node": ">=10" } }, - "node_modules/istanbul-lib-report/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "node_modules/istanbul-reports": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.2.0.tgz", + "integrity": "sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { - "has-flag": "^4.0.0" + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" }, "engines": { "node": ">=8" } }, - "node_modules/istanbul-reports": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.5.tgz", - "integrity": "sha512-nUsEMa9pBt/NOHqbcbeJEgqIlY/K7rVWUX6Lql2orY5e9roQOthbR3vtY4zzf2orPELg80fnxxk9zUyPlgwD1w==", + "node_modules/jackspeak": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", "dev": true, + "license": "BlueOak-1.0.0", "dependencies": { - "html-escaper": "^2.0.0", - "istanbul-lib-report": "^3.0.0" + "@isaacs/cliui": "^8.0.2" }, - "engines": { - "node": ">=8" + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" } }, "node_modules/javascript-state-machine": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/javascript-state-machine/-/javascript-state-machine-3.1.0.tgz", - "integrity": "sha512-BwhYxQ1OPenBPXC735RgfB+ZUG8H3kjsx8hrYTgWnoy6TPipEy4fiicyhT2lxRKAXq9pG7CfFT8a2HLr6Hmwxg==" + "integrity": "sha512-BwhYxQ1OPenBPXC735RgfB+ZUG8H3kjsx8hrYTgWnoy6TPipEy4fiicyhT2lxRKAXq9pG7CfFT8a2HLr6Hmwxg==", + "license": "MIT" }, "node_modules/jayson": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/jayson/-/jayson-4.0.0.tgz", - "integrity": "sha512-v2RNpDCMu45fnLzSk47vx7I+QUaOsox6f5X0CUlabAFwxoP+8MfAY0NQRFwOEYXIxm8Ih5y6OaEa5KYiQMkyAA==", + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/jayson/-/jayson-4.1.3.tgz", + "integrity": "sha512-LtXh5aYZodBZ9Fc3j6f2w+MTNcnxteMOrb+QgIouguGOulWi0lieEkOUg+HkjjFs0DGoWDds6bi4E9hpNFLulQ==", + "license": "MIT", "dependencies": { "@types/connect": "^3.4.33", "@types/node": "^12.12.54", @@ -3898,7 +4638,7 @@ "json-stringify-safe": "^5.0.1", "JSONStream": "^1.3.5", "uuid": "^8.3.2", - "ws": "^7.4.5" + "ws": "^7.5.10" }, "bin": { "jayson": "bin/jayson.js" @@ -3907,26 +4647,24 @@ "node": ">=8" } }, - "node_modules/jayson/node_modules/@types/node": { - "version": "12.20.55", - "resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.55.tgz", - "integrity": "sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==" - }, "node_modules/jayson/node_modules/commander": { "version": "2.20.3", "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "license": "MIT" }, "node_modules/js-beautify": { - "version": "1.14.3", - "resolved": "https://registry.npmjs.org/js-beautify/-/js-beautify-1.14.3.tgz", - "integrity": "sha512-f1ra8PHtOEu/70EBnmiUlV8nJePS58y9qKjl4JHfYWlFH6bo7ogZBz//FAZp7jDuXtYnGYKymZPlrg2I/9Zo4g==", + "version": "1.15.1", + "resolved": "https://registry.npmjs.org/js-beautify/-/js-beautify-1.15.1.tgz", + "integrity": "sha512-ESjNzSlt/sWE8sciZH8kBF8BPlwXPwhR6pWKAw8bw4Bwj+iZcnKW6ONWUutJ7eObuBZQpiIb8S7OYspWrKt7rA==", "dev": true, + "license": "MIT", "dependencies": { "config-chain": "^1.1.13", - "editorconfig": "^0.15.3", - "glob": "^7.1.3", - "nopt": "^5.0.0" + "editorconfig": "^1.0.4", + "glob": "^10.3.3", + "js-cookie": "^3.0.5", + "nopt": "^7.2.0" }, "bin": { "css-beautify": "js/bin/css-beautify.js", @@ -3934,122 +4672,128 @@ "js-beautify": "js/bin/js-beautify.js" }, "engines": { - "node": ">=10" + "node": ">=14" } }, - "node_modules/js-sha256": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/js-sha256/-/js-sha256-0.9.0.tgz", - "integrity": "sha512-sga3MHh9sgQN2+pJ9VYZ+1LPwXOxuBJBA5nrR5/ofPfuiJBE2hnjsaN8se8JznOmGLN2p49Pe5U/ttafcs/apA==" - }, - "node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true + "node_modules/js-beautify/node_modules/brace-expansion": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } }, - "node_modules/js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "node_modules/js-beautify/node_modules/glob": { + "version": "10.4.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", + "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", "dev": true, + "license": "ISC", "dependencies": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" }, "bin": { - "js-yaml": "bin/js-yaml.js" + "glob": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/js2xmlparser": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/js2xmlparser/-/js2xmlparser-4.0.2.tgz", - "integrity": "sha512-6n4D8gLlLf1n5mNLQPRfViYzu9RATblzPEtm1SthMX1Pjao0r9YI9nw7ZIfRxQMERS87mcswrg+r/OYrPRX6jA==", + "node_modules/js-beautify/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", "dev": true, + "license": "ISC", "dependencies": { - "xmlcreate": "^2.0.4" + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/jsbn": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", - "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==", - "dev": true + "node_modules/js-beautify/node_modules/minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=16 || 14 >=14.17" + } }, - "node_modules/jsdoc": { - "version": "3.6.11", - "resolved": "https://registry.npmjs.org/jsdoc/-/jsdoc-3.6.11.tgz", - "integrity": "sha512-8UCU0TYeIYD9KeLzEcAu2q8N/mx9O3phAGl32nmHlE0LpaJL71mMkP4d+QE5zWfNt50qheHtOZ0qoxVrsX5TUg==", + "node_modules/js-cookie": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/js-cookie/-/js-cookie-3.0.5.tgz", + "integrity": "sha512-cEiJEAEoIbWfCZYKWhVwFuvPX1gETRYPw6LlaTKoxD3s2AkXzkCjnp6h0V77ozyqj0jakteJ4YqDJT830+lVGw==", "dev": true, - "dependencies": { - "@babel/parser": "^7.9.4", - "@types/markdown-it": "^12.2.3", - "bluebird": "^3.7.2", - "catharsis": "^0.9.0", - "escape-string-regexp": "^2.0.0", - "js2xmlparser": "^4.0.2", - "klaw": "^3.0.0", - "markdown-it": "^12.3.2", - "markdown-it-anchor": "^8.4.1", - "marked": "^4.0.10", - "mkdirp": "^1.0.4", - "requizzle": "^0.2.3", - "strip-json-comments": "^3.1.0", - "taffydb": "2.6.2", - "underscore": "~1.13.2" - }, - "bin": { - "jsdoc": "jsdoc.js" - }, + "license": "MIT", "engines": { - "node": ">=12.0.0" + "node": ">=14" } }, - "node_modules/jsdoc-api": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/jsdoc-api/-/jsdoc-api-7.2.0.tgz", - "integrity": "sha512-93YDnlm/OYTlLOFeNs4qAv0RBCJ0kGj67xQaWy8wrbk97Rw1EySitoOTHsTHXPEs3uyx2IStPKGrbE7LTnZXbA==", + "node_modules/js-sha256": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/js-sha256/-/js-sha256-0.9.0.tgz", + "integrity": "sha512-sga3MHh9sgQN2+pJ9VYZ+1LPwXOxuBJBA5nrR5/ofPfuiJBE2hnjsaN8se8JznOmGLN2p49Pe5U/ttafcs/apA==", + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", "dev": true, + "license": "MIT", "dependencies": { - "array-back": "^6.2.2", - "cache-point": "^2.0.0", - "collect-all": "^1.0.4", - "file-set": "^4.0.2", - "fs-then-native": "^2.0.0", - "jsdoc": "^4.0.0", - "object-to-spawn-args": "^2.0.1", - "temp-path": "^1.0.0", - "walk-back": "^5.1.0" + "argparse": "^2.0.1" }, - "engines": { - "node": ">=12.17" + "bin": { + "js-yaml": "bin/js-yaml.js" } }, - "node_modules/jsdoc-api/node_modules/escape-string-regexp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", - "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "node_modules/js2xmlparser": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/js2xmlparser/-/js2xmlparser-4.0.2.tgz", + "integrity": "sha512-6n4D8gLlLf1n5mNLQPRfViYzu9RATblzPEtm1SthMX1Pjao0r9YI9nw7ZIfRxQMERS87mcswrg+r/OYrPRX6jA==", "dev": true, - "engines": { - "node": ">=8" + "license": "Apache-2.0", + "dependencies": { + "xmlcreate": "^2.0.4" } }, - "node_modules/jsdoc-api/node_modules/jsdoc": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/jsdoc/-/jsdoc-4.0.0.tgz", - "integrity": "sha512-tzTgkklbWKrlaQL2+e3NNgLcZu3NaK2vsHRx7tyHQ+H5jcB9Gx0txSd2eJWlMC/xU1+7LQu4s58Ry0RkuaEQVg==", + "node_modules/jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==", + "license": "MIT" + }, + "node_modules/jsdoc": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/jsdoc/-/jsdoc-4.0.4.tgz", + "integrity": "sha512-zeFezwyXeG4syyYHbvh1A967IAqq/67yXtXvuL5wnqCkFZe8I0vKfm+EO+YEvLguo6w9CDUbrAXVtJSHh2E8rw==", "dev": true, + "license": "Apache-2.0", "dependencies": { - "@babel/parser": "^7.9.4", + "@babel/parser": "^7.20.15", "@jsdoc/salty": "^0.2.1", - "@types/markdown-it": "^12.2.3", + "@types/markdown-it": "^14.1.1", "bluebird": "^3.7.2", "catharsis": "^0.9.0", "escape-string-regexp": "^2.0.0", "js2xmlparser": "^4.0.2", "klaw": "^3.0.0", - "markdown-it": "^12.3.2", - "markdown-it-anchor": "^8.4.1", + "markdown-it": "^14.1.0", + "markdown-it-anchor": "^8.6.7", "marked": "^4.0.10", "mkdirp": "^1.0.4", "requizzle": "^0.2.3", @@ -4063,54 +4807,77 @@ "node": ">=12.0.0" } }, - "node_modules/jsdoc-api/node_modules/strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "node_modules/jsdoc-api": { + "version": "9.3.5", + "resolved": "https://registry.npmjs.org/jsdoc-api/-/jsdoc-api-9.3.5.tgz", + "integrity": "sha512-TQwh1jA8xtCkIbVwm/XA3vDRAa5JjydyKx1cC413Sh3WohDFxcMdwKSvn4LOsq2xWyAmOU/VnSChTQf6EF0R8g==", "dev": true, + "license": "MIT", + "dependencies": { + "array-back": "^6.2.2", + "cache-point": "^3.0.1", + "current-module-paths": "^1.1.2", + "file-set": "^5.3.0", + "jsdoc": "^4.0.4", + "object-to-spawn-args": "^2.0.1", + "walk-back": "^5.1.1" + }, "engines": { - "node": ">=8" + "node": ">=12.17" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "peerDependencies": { + "@75lb/nature": "latest" + }, + "peerDependenciesMeta": { + "@75lb/nature": { + "optional": true + } } }, "node_modules/jsdoc-parse": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/jsdoc-parse/-/jsdoc-parse-6.2.0.tgz", - "integrity": "sha512-Afu1fQBEb7QHt6QWX/6eUWvYHJofB90Fjx7FuJYF7mnG9z5BkAIpms1wsnvYLytfmqpEENHs/fax9p8gvMj7dw==", + "version": "6.2.5", + "resolved": "https://registry.npmjs.org/jsdoc-parse/-/jsdoc-parse-6.2.5.tgz", + "integrity": "sha512-8JaSNjPLr2IuEY4Das1KM6Z4oLHZYUnjRrr27hKSa78Cj0i5Lur3DzNnCkz+DfrKBDoljGMoWOiBVQbtUZJBPw==", "dev": true, + "license": "MIT", "dependencies": { "array-back": "^6.2.2", - "lodash.omit": "^4.5.0", - "lodash.pick": "^4.4.0", - "reduce-extract": "^1.0.0", - "sort-array": "^4.1.5", - "test-value": "^3.0.0" + "find-replace": "^5.0.1", + "sort-array": "^5.0.0" }, "engines": { "node": ">=12" } }, "node_modules/jsdoc-to-markdown": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/jsdoc-to-markdown/-/jsdoc-to-markdown-7.1.1.tgz", - "integrity": "sha512-CI86d63xAVNO+ENumWwmJ034lYe5iGU5GwjtTA11EuphP9tpnoi4hrKgR/J8uME0D+o4KUpVfwX1fjZhc8dEtg==", + "version": "9.1.1", + "resolved": "https://registry.npmjs.org/jsdoc-to-markdown/-/jsdoc-to-markdown-9.1.1.tgz", + "integrity": "sha512-QqYVSo58iHXpD5Jwi1u4AFeuMcQp4jfk7SmWzvXKc3frM9Kop17/OHudmi0phzkT/K137Rlroc9Q0y+95XpUsw==", "dev": true, + "license": "MIT", "dependencies": { "array-back": "^6.2.2", - "command-line-tool": "^0.8.0", + "command-line-args": "^6.0.1", + "command-line-usage": "^7.0.3", "config-master": "^3.1.0", - "dmd": "^6.1.0", - "jsdoc-api": "^7.1.1", - "jsdoc-parse": "^6.1.0", - "walk-back": "^5.1.0" + "dmd": "^7.1.1", + "jsdoc-api": "^9.3.4", + "jsdoc-parse": "^6.2.4", + "walk-back": "^5.1.1" }, "bin": { "jsdoc2md": "bin/cli.js" }, "engines": { "node": ">=12.17" + }, + "peerDependencies": { + "@75lb/nature": "latest" + }, + "peerDependenciesMeta": { + "@75lb/nature": { + "optional": true + } } }, "node_modules/jsdoc/node_modules/escape-string-regexp": { @@ -4118,32 +4885,36 @@ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, - "node_modules/jsdoc/node_modules/strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "node_modules/jsdoc/node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", "dev": true, - "engines": { - "node": ">=8" + "license": "MIT", + "bin": { + "mkdirp": "bin/cmd.js" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "engines": { + "node": ">=10" } }, - "node_modules/json-parse-even-better-errors": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", - "dev": true + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true, + "license": "MIT" }, "node_modules/json-pointer": { "version": "0.6.2", "resolved": "https://registry.npmjs.org/json-pointer/-/json-pointer-0.6.2.tgz", "integrity": "sha512-vLWcKbOaXlO+jvRy4qNd+TI1QUPZzfJj1tpJ3vAXDych5XJf93ftpUKe5pKCrzyIIwgBJcOcCVRUfqQP25afBw==", + "license": "MIT", "dependencies": { "foreach": "^2.0.4" } @@ -4152,45 +4923,50 @@ "version": "0.4.0", "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==", - "dev": true + "license": "(AFL-2.1 OR BSD-3-Clause)" }, "node_modules/json-schema-defaults": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/json-schema-defaults/-/json-schema-defaults-0.1.1.tgz", "integrity": "sha512-6Q5YS7pSDCXUbtS9uAFE+uUgvE45dBHCMyhqe6liJmL+oIa4zbACSS6nr6Lh+73mN+MnWBCExtN3C14S7Jrm7w==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/json-stable-stringify-without-jsonify": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/json-stringify-safe": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==" + "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==", + "license": "ISC" }, "node_modules/json-to-dot": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/json-to-dot/-/json-to-dot-1.1.0.tgz", "integrity": "sha512-fDzyyOizvgSYHcVXCut2CxtrA6K22z8lfVD7fGv6jJtXmxzaTsQ10SO4gqYU3TQ6EiQrozFiZlGUlNBB1SPyCQ==", "dev": true, + "license": "MIT", "bin": { "json-to-dot": "index.js" } }, "node_modules/jsonfile": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", - "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", - "dev": true, + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.0.tgz", + "integrity": "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==", + "license": "MIT", "dependencies": { "universalify": "^2.0.0" }, @@ -4204,13 +4980,14 @@ "integrity": "sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==", "engines": [ "node >= 0.2.0" - ] + ], + "license": "MIT" }, "node_modules/jsonpointer": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-5.0.1.tgz", "integrity": "sha512-p/nXbhSEcu3pZRdkW1OfJhpsVtW1gd4Wa1fnQc9YLiTfAjn0312eMKimbdIQzuZl9aa9xUGaRlP9T/CJE/ditQ==", - "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -4220,6 +4997,7 @@ "resolved": "https://registry.npmjs.org/jsonschema/-/jsonschema-1.1.0.tgz", "integrity": "sha512-nQhT+ioA1XM8CpxJYlBfcUj6HF3f3f2KbLgV3tcxOt85RKpk2b0Do/C5BnCCCfdAarAjWRSFlln0Uanl4tBCHA==", "dev": true, + "license": "MIT", "engines": { "node": "*" } @@ -4228,6 +5006,7 @@ "version": "1.3.5", "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.5.tgz", "integrity": "sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==", + "license": "(MIT OR Apache-2.0)", "dependencies": { "jsonparse": "^1.2.0", "through": ">=2.2.7 <3" @@ -4240,18 +5019,18 @@ } }, "node_modules/jsprim": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz", - "integrity": "sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==", - "dev": true, + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-2.0.2.tgz", + "integrity": "sha512-gqXddjPqQ6G40VdnI6T6yObEC+pDNvyP95wdQhkWkg7crHH3km5qP1FsOXEkzEQwnz6gz5qGTn1c2Y52wP3OyQ==", + "engines": [ + "node >=0.6.0" + ], + "license": "MIT", "dependencies": { "assert-plus": "1.0.0", "extsprintf": "1.3.0", "json-schema": "0.4.0", "verror": "1.10.0" - }, - "engines": { - "node": ">=0.6.0" } }, "node_modules/juice": { @@ -4259,6 +5038,7 @@ "resolved": "https://registry.npmjs.org/juice/-/juice-8.1.0.tgz", "integrity": "sha512-FLzurJrx5Iv1e7CfBSZH68dC04EEvXvvVvPYB7Vx1WAuhCp1ZPIMtqxc+WTWxVkpTIC2Ach/GAv0rQbtGf6YMA==", "dev": true, + "license": "MIT", "dependencies": { "cheerio": "1.0.0-rc.10", "commander": "^6.1.0", @@ -4278,6 +5058,7 @@ "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.10.tgz", "integrity": "sha512-g0J0q/O6mW8z5zxQ3A8E8J1hUgp4SMOvEoW/x84OwyHKe/Zccz83PVT4y5Crcr530FV6NgmKI1qvGTKVl9XXVw==", "dev": true, + "license": "MIT", "dependencies": { "cheerio-select": "^1.5.0", "dom-serializer": "^1.3.2", @@ -4299,6 +5080,7 @@ "resolved": "https://registry.npmjs.org/cheerio-select/-/cheerio-select-1.6.0.tgz", "integrity": "sha512-eq0GdBvxVFbqWgmCm7M3XGs1I8oLy/nExUnh6oLqmBditPO9AqQJrkslDpMun/hZ0yyTs8L0m85OHp4ho6Qm9g==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "css-select": "^4.3.0", "css-what": "^6.0.1", @@ -4310,11 +5092,22 @@ "url": "https://github.com/sponsors/fb55" } }, + "node_modules/juice/node_modules/commander": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz", + "integrity": "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, "node_modules/juice/node_modules/css-select": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz", "integrity": "sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "boolbase": "^1.0.0", "css-what": "^6.0.1", @@ -4331,6 +5124,7 @@ "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==", "dev": true, + "license": "MIT", "dependencies": { "domelementtype": "^2.0.1", "domhandler": "^4.2.0", @@ -4345,6 +5139,7 @@ "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "domelementtype": "^2.2.0" }, @@ -4360,6 +5155,7 @@ "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "dom-serializer": "^1.0.1", "domelementtype": "^2.2.0", @@ -4374,6 +5170,7 @@ "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", "dev": true, + "license": "BSD-2-Clause", "funding": { "url": "https://github.com/fb55/entities?sponsor=1" } @@ -4390,6 +5187,7 @@ "url": "https://github.com/sponsors/fb55" } ], + "license": "MIT", "dependencies": { "domelementtype": "^2.0.1", "domhandler": "^4.0.0", @@ -4397,342 +5195,141 @@ "entities": "^2.0.0" } }, - "node_modules/juice/node_modules/parse5": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", - "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", - "dev": true - }, - "node_modules/juice/node_modules/parse5-htmlparser2-tree-adapter": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-6.0.1.tgz", - "integrity": "sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA==", - "dev": true, - "dependencies": { - "parse5": "^6.0.1" - } - }, - "node_modules/juice/node_modules/tslib": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", - "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "dev": true - }, - "node_modules/klaw": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/klaw/-/klaw-3.0.0.tgz", - "integrity": "sha512-0Fo5oir+O9jnXu5EefYbVK+mHMBeEVEy2cmctR1O1NECcCkPRreJKrS6Qt/j3KC2C148Dfo9i3pCmCMsdqGr0g==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.1.9" - } - }, - "node_modules/kramed": { - "version": "0.5.6", - "resolved": "https://registry.npmjs.org/kramed/-/kramed-0.5.6.tgz", - "integrity": "sha512-V4qwQAp8HPQPU6Ph9Q4bc+P+nKQWEGlWYLRDkK7n+CPaMi8/VRm9/R710tRmag4whLsnKR91CO9Ras/Rnff9bw==", - "dev": true, - "bin": { - "kramed": "bin/kramed" - } - }, - "node_modules/length-prefixed-stream": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/length-prefixed-stream/-/length-prefixed-stream-1.6.0.tgz", - "integrity": "sha512-gsJvrb5giDqil/ScQ7fEoplsI2Ch4DwnvnfTW2EGl9KBW6Ekzn8JSNESObqNAeZD8HkSjEMvc5XjhuB66fsSZQ==", - "dependencies": { - "buffer-alloc-unsafe": "^1.0.0", - "readable-stream": "^2.0.0", - "varint": "^5.0.0" - } - }, - "node_modules/length-prefixed-stream/node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" - }, - "node_modules/length-prefixed-stream/node_modules/readable-stream": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", - "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/length-prefixed-stream/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" - }, - "node_modules/length-prefixed-stream/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, - "node_modules/level": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/level/-/level-7.0.1.tgz", - "integrity": "sha512-w3E64+ALx2eZf8RV5JL4kIcE0BFAvQscRYd1yU4YVqZN9RGTQxXSvH202xvK15yZwFFxRXe60f13LJjcJ//I4Q==", - "dependencies": { - "level-js": "^6.1.0", - "level-packager": "^6.0.1", - "leveldown": "^6.1.0" - }, - "engines": { - "node": ">=10.12.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/level" - } - }, - "node_modules/level-codec": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/level-codec/-/level-codec-10.0.0.tgz", - "integrity": "sha512-QW3VteVNAp6c/LuV6nDjg7XDXx9XHK4abmQarxZmlRSDyXYk20UdaJTSX6yzVvQ4i0JyWSB7jert0DsyD/kk6g==", - "dependencies": { - "buffer": "^6.0.3" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/level-codec/node_modules/buffer": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", - "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "dependencies": { - "base64-js": "^1.3.1", - "ieee754": "^1.2.1" - } - }, - "node_modules/level-concat-iterator": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/level-concat-iterator/-/level-concat-iterator-3.1.0.tgz", - "integrity": "sha512-BWRCMHBxbIqPxJ8vHOvKUsaO0v1sLYZtjN3K2iZJsRBYtp+ONsY6Jfi6hy9K3+zolgQRryhIn2NRZjZnWJ9NmQ==", - "dependencies": { - "catering": "^2.1.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/level-errors": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/level-errors/-/level-errors-3.0.1.tgz", - "integrity": "sha512-tqTL2DxzPDzpwl0iV5+rBCv65HWbHp6eutluHNcVIftKZlQN//b6GEnZDM2CvGZvzGYMwyPtYppYnydBQd2SMQ==", - "engines": { - "node": ">=10" - } - }, - "node_modules/level-iterator-stream": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/level-iterator-stream/-/level-iterator-stream-5.0.0.tgz", - "integrity": "sha512-wnb1+o+CVFUDdiSMR/ZymE2prPs3cjVLlXuDeSq9Zb8o032XrabGEXcTCsBxprAtseO3qvFeGzh6406z9sOTRA==", - "dependencies": { - "inherits": "^2.0.4", - "readable-stream": "^3.4.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/level-js": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/level-js/-/level-js-6.1.0.tgz", - "integrity": "sha512-i7mPtkZm68aewfv0FnIUWvFUFfoyzIvVKnUmuQGrelEkP72vSPTaA1SGneWWoCV5KZJG4wlzbJLp1WxVNGuc6A==", - "dependencies": { - "abstract-leveldown": "^7.2.0", - "buffer": "^6.0.3", - "inherits": "^2.0.3", - "ltgt": "^2.1.2", - "run-parallel-limit": "^1.1.0" - } - }, - "node_modules/level-js/node_modules/buffer": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", - "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "dependencies": { - "base64-js": "^1.3.1", - "ieee754": "^1.2.1" - } + "node_modules/juice/node_modules/parse5": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", + "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", + "dev": true, + "license": "MIT" }, - "node_modules/level-packager": { + "node_modules/juice/node_modules/parse5-htmlparser2-tree-adapter": { "version": "6.0.1", - "resolved": "https://registry.npmjs.org/level-packager/-/level-packager-6.0.1.tgz", - "integrity": "sha512-8Ezr0XM6hmAwqX9uu8IGzGNkWz/9doyPA8Oo9/D7qcMI6meJC+XhIbNYHukJhIn8OGdlzQs/JPcL9B8lA2F6EQ==", + "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-6.0.1.tgz", + "integrity": "sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA==", + "dev": true, + "license": "MIT", "dependencies": { - "encoding-down": "^7.1.0", - "levelup": "^5.1.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/level-supports": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/level-supports/-/level-supports-2.1.0.tgz", - "integrity": "sha512-E486g1NCjW5cF78KGPrMDRBYzPuueMZ6VBXHT6gC7A8UYWGiM14fGgp+s/L1oFfDWSPV/+SFkYCmZ0SiESkRKA==", - "engines": { - "node": ">=10" + "parse5": "^6.0.1" } }, - "node_modules/leveldown": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/leveldown/-/leveldown-6.1.1.tgz", - "integrity": "sha512-88c+E+Eizn4CkQOBHwqlCJaTNEjGpaEIikn1S+cINc5E9HEvJ77bqY4JY/HxT5u0caWqsc3P3DcFIKBI1vHt+A==", - "hasInstallScript": true, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "license": "MIT", "dependencies": { - "abstract-leveldown": "^7.2.0", - "napi-macros": "~2.0.0", - "node-gyp-build": "^4.3.0" - }, - "engines": { - "node": ">=10.12.0" + "json-buffer": "3.0.1" } }, - "node_modules/levelup": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/levelup/-/levelup-5.1.1.tgz", - "integrity": "sha512-0mFCcHcEebOwsQuk00WJwjLI6oCjbBuEYdh/RaRqhjnyVlzqf41T1NnDtCedumZ56qyIh8euLFDqV1KfzTAVhg==", + "node_modules/klaw": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/klaw/-/klaw-3.0.0.tgz", + "integrity": "sha512-0Fo5oir+O9jnXu5EefYbVK+mHMBeEVEy2cmctR1O1NECcCkPRreJKrS6Qt/j3KC2C148Dfo9i3pCmCMsdqGr0g==", + "dev": true, + "license": "MIT", "dependencies": { - "catering": "^2.0.0", - "deferred-leveldown": "^7.0.0", - "level-errors": "^3.0.1", - "level-iterator-stream": "^5.0.0", - "level-supports": "^2.0.1", - "queue-microtask": "^1.2.3" - }, - "engines": { - "node": ">=10" + "graceful-fs": "^4.1.9" } }, - "node_modules/levn": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", - "integrity": "sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==", + "node_modules/kramed": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/kramed/-/kramed-0.5.6.tgz", + "integrity": "sha512-V4qwQAp8HPQPU6Ph9Q4bc+P+nKQWEGlWYLRDkK7n+CPaMi8/VRm9/R710tRmag4whLsnKR91CO9Ras/Rnff9bw==", "dev": true, + "license": "MIT", + "bin": { + "kramed": "bin/kramed" + } + }, + "node_modules/length-prefixed-stream": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/length-prefixed-stream/-/length-prefixed-stream-1.6.0.tgz", + "integrity": "sha512-gsJvrb5giDqil/ScQ7fEoplsI2Ch4DwnvnfTW2EGl9KBW6Ekzn8JSNESObqNAeZD8HkSjEMvc5XjhuB66fsSZQ==", + "license": "MIT", "dependencies": { - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2" - }, - "engines": { - "node": ">= 0.8.0" + "buffer-alloc-unsafe": "^1.0.0", + "readable-stream": "^2.0.0", + "varint": "^5.0.0" } }, - "node_modules/license-checker": { - "version": "25.0.1", - "resolved": "https://registry.npmjs.org/license-checker/-/license-checker-25.0.1.tgz", - "integrity": "sha512-mET5AIwl7MR2IAKYYoVBBpV0OnkKQ1xGj2IMMeEFIs42QAkEVjRtFZGWmQ28WeU7MP779iAgOaOy93Mn44mn6g==", - "dev": true, + "node_modules/level": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/level/-/level-9.0.0.tgz", + "integrity": "sha512-n+mVuf63mUEkd8NUx7gwxY+QF5vtkibv6fXTGUgtHWLPDaA5/XZjLcI/Q1nQ8k6OttHT6Ezt+7nSEXsRUfHtOQ==", + "license": "MIT", "dependencies": { - "chalk": "^2.4.1", - "debug": "^3.1.0", - "mkdirp": "^0.5.1", - "nopt": "^4.0.1", - "read-installed": "~4.0.3", - "semver": "^5.5.0", - "spdx-correct": "^3.0.0", - "spdx-expression-parse": "^3.0.0", - "spdx-satisfies": "^4.0.0", - "treeify": "^1.1.0" + "abstract-level": "^2.0.1", + "browser-level": "^2.0.0", + "classic-level": "^2.0.0" }, - "bin": { - "license-checker": "bin/license-checker" + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/level" } }, - "node_modules/license-checker/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "dependencies": { - "ms": "^2.1.1" + "node_modules/level-supports": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/level-supports/-/level-supports-6.2.0.tgz", + "integrity": "sha512-QNxVXP0IRnBmMsJIh+sb2kwNCYcKciQZJEt+L1hPCHrKNELllXhvrlClVHXBYZVT+a7aTSM6StgNXdAldoab3w==", + "license": "MIT", + "engines": { + "node": ">=16" } }, - "node_modules/license-checker/node_modules/mkdirp": { - "version": "0.5.6", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", - "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", - "dev": true, + "node_modules/level-transcoder": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/level-transcoder/-/level-transcoder-1.0.1.tgz", + "integrity": "sha512-t7bFwFtsQeD8cl8NIoQ2iwxA0CL/9IFw7/9gAjOonH0PWTTiRfY7Hq+Ejbsxh86tXobDQ6IOiddjNYIfOBs06w==", + "license": "MIT", "dependencies": { - "minimist": "^1.2.6" + "buffer": "^6.0.3", + "module-error": "^1.0.1" }, - "bin": { - "mkdirp": "bin/cmd.js" + "engines": { + "node": ">=12" } }, - "node_modules/license-checker/node_modules/nopt": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.3.tgz", - "integrity": "sha512-CvaGwVMztSMJLOeXPrez7fyfObdZqNUK1cPAEzLHrTybIua9pMdmmPR5YwtfNftIOMv3DPUhFaxsZMNTQO20Kg==", + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", "dev": true, + "license": "MIT", "dependencies": { - "abbrev": "1", - "osenv": "^0.1.4" + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" }, - "bin": { - "nopt": "bin/nopt.js" + "engines": { + "node": ">= 0.8.0" } }, "node_modules/linkify-it": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-3.0.3.tgz", - "integrity": "sha512-ynTsyrFSdE5oZ/O9GEf00kPngmOfVwazR5GKDq6EYfhlpFug3J2zybX56a2PRRpc9P+FuSoGNAwjlbDs9jJBPQ==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.0.tgz", + "integrity": "sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==", "dev": true, + "license": "MIT", "dependencies": { - "uc.micro": "^1.0.1" + "uc.micro": "^2.0.0" } }, "node_modules/livereload-js": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/livereload-js/-/livereload-js-2.4.0.tgz", "integrity": "sha512-XPQH8Z2GDP/Hwz2PCDrh2mth4yFejwA1OZ/81Ti3LgKyhDcEjsSsqFWZojHG0va/duGd+WyosY7eXLDoOyqcPw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/locate-path": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", "dev": true, + "license": "MIT", "dependencies": { "p-locate": "^5.0.0" }, @@ -4747,42 +5344,27 @@ "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true + "license": "MIT" }, "node_modules/lodash.camelcase": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==" - }, - "node_modules/lodash.omit": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.omit/-/lodash.omit-4.5.0.tgz", - "integrity": "sha512-XeqSp49hNGmlkj2EJlfrQFIzQ6lXdNro9sddtQzcJY8QaoC2GO0DT7xaIokHeyM+mIT0mPMlPvkYzg2xCuHdZg==", - "dev": true - }, - "node_modules/lodash.padend": { - "version": "4.6.1", - "resolved": "https://registry.npmjs.org/lodash.padend/-/lodash.padend-4.6.1.tgz", - "integrity": "sha512-sOQs2aqGpbl27tmCS1QNZA09Uqp01ZzWfDUoD+xzTii0E7dSQfRKcRetFwa+uXaxaqL+TKm7CgD2JdKP7aZBSw==", - "dev": true - }, - "node_modules/lodash.pick": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/lodash.pick/-/lodash.pick-4.4.0.tgz", - "integrity": "sha512-hXt6Ul/5yWjfklSGvLQl8vM//l3FtyHZeuelpzK6mm99pNvN9yTDruNZPEJZD1oWrqo+izBmB7oUfWgcCX7s4Q==", - "dev": true + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "license": "MIT" }, "node_modules/log-symbols": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", "dev": true, + "license": "MIT", "dependencies": { "chalk": "^4.1.0", "is-unicode-supported": "^0.1.0" @@ -4794,164 +5376,92 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/log-symbols/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/log-symbols/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/log-symbols/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/log-symbols/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/log-symbols/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/log-symbols/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/lru_map": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/lru_map/-/lru_map-0.4.1.tgz", "integrity": "sha512-I+lBvqMMFfqaV8CJCISjI3wbjmwVu/VyOoU7+qtu9d7ioW5klMgsTTiUOUp+DJvfTTzKXoPbyC6YfgkNcyPSOg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/lru-cache": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", - "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", "dev": true, - "dependencies": { - "pseudomap": "^1.0.2", - "yallist": "^2.1.2" - } - }, - "node_modules/ltgt": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ltgt/-/ltgt-2.2.1.tgz", - "integrity": "sha512-AI2r85+4MquTw9ZYqabu4nMwy9Oftlfa/e/52t9IjtfG+mGBbTNdAoZ3RQKLHR6r0wQnwZnPIEh/Ya6XTWAKNA==" + "license": "ISC" }, "node_modules/lunr": { "version": "0.5.12", "resolved": "https://registry.npmjs.org/lunr/-/lunr-0.5.12.tgz", "integrity": "sha512-/EtfOyuNP7BLVKhDvLyKJkFvCup2vwcIwQXCuasZEFk7XUJ4/blztVuefeLapUb1I5uMGsosN9A8J9Mu9A6yBg==", - "dev": true + "dev": true, + "license": "MIT" + }, + "node_modules/macaroon": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/macaroon/-/macaroon-3.0.4.tgz", + "integrity": "sha512-Tja2jvupseKxltPZbu5RPSz2Pgh6peYA3O46YCTcYL8PI1VqtGwDqRhGfP8pows26xx9wTiygk+en62Bq+Y8JA==", + "license": "BSD-3-Clause", + "dependencies": { + "sjcl": "^1.0.6", + "tweetnacl": "^1.0.0", + "tweetnacl-util": "^0.15.0" + } }, "node_modules/make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", + "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", "dev": true, + "license": "MIT", "dependencies": { - "semver": "^6.0.0" + "semver": "^7.5.3" }, "engines": { - "node": ">=8" + "node": ">=10" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/make-dir/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, "node_modules/markdown-it": { - "version": "12.3.2", - "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-12.3.2.tgz", - "integrity": "sha512-TchMembfxfNVpHkbtriWltGWc+m3xszaRD0CZup7GFFhzIgQqxIfn3eGj1yZpfuflzPvfkt611B2Q/Bsk1YnGg==", + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.1.0.tgz", + "integrity": "sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg==", "dev": true, + "license": "MIT", "dependencies": { "argparse": "^2.0.1", - "entities": "~2.1.0", - "linkify-it": "^3.0.1", - "mdurl": "^1.0.1", - "uc.micro": "^1.0.5" + "entities": "^4.4.0", + "linkify-it": "^5.0.0", + "mdurl": "^2.0.0", + "punycode.js": "^2.3.1", + "uc.micro": "^2.1.0" }, "bin": { - "markdown-it": "bin/markdown-it.js" + "markdown-it": "bin/markdown-it.mjs" } }, "node_modules/markdown-it-anchor": { - "version": "8.6.6", - "resolved": "https://registry.npmjs.org/markdown-it-anchor/-/markdown-it-anchor-8.6.6.tgz", - "integrity": "sha512-jRW30YGywD2ESXDc+l17AiritL0uVaSnWsb26f+68qaW9zgbIIr1f4v2Nsvc0+s0Z2N3uX6t/yAw7BwCQ1wMsA==", + "version": "8.6.7", + "resolved": "https://registry.npmjs.org/markdown-it-anchor/-/markdown-it-anchor-8.6.7.tgz", + "integrity": "sha512-FlCHFwNnutLgVTflOYHPW2pPcl2AACqVzExlkGQNsi4CJgqOHN7YTgDd4LuhgN1BFO3TS0vLAruV1Td6dwWPJA==", "dev": true, + "license": "Unlicense", "peerDependencies": { "@types/markdown-it": "*", "markdown-it": "*" } }, - "node_modules/markdown-it/node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, "node_modules/markdown-it/node_modules/entities": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-2.1.0.tgz", - "integrity": "sha512-hCx1oky9PFrJ611mf0ifBLBRW8lUUVRlFolb5gWRfIELabBlbp9xZvrqZLZAs+NxFnbfQoeGd8wDkygjg7U85w==", + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, "funding": { "url": "https://github.com/fb55/entities?sponsor=1" } @@ -4961,6 +5471,7 @@ "resolved": "https://registry.npmjs.org/marked/-/marked-4.0.19.tgz", "integrity": "sha512-rgQF/OxOiLcvgUAj1Q1tAf4Bgxn5h5JZTp04Fx4XUkVhs7B+7YA9JEWJhJpoO8eJt8MkZMwqLCNeNqj1bCREZQ==", "dev": true, + "license": "MIT", "bin": { "marked": "bin/marked.js" }, @@ -4968,10 +5479,29 @@ "node": ">= 12" } }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/maybe-combine-errors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/maybe-combine-errors/-/maybe-combine-errors-1.0.0.tgz", + "integrity": "sha512-eefp6IduNPT6fVdwPp+1NgD0PML1NU5P6j1Mj5nz1nidX8/sWY7119WL8vTAHgqfsY74TzW0w1XPgdYEKkGZ5A==", + "license": "MIT", + "engines": { + "node": ">=10" + } + }, "node_modules/md5.js": { "version": "1.3.5", "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", + "license": "MIT", "dependencies": { "hash-base": "^3.0.0", "inherits": "^2.0.1", @@ -4979,48 +5509,91 @@ } }, "node_modules/mdurl": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz", - "integrity": "sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g==", - "dev": true + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-2.0.0.tgz", + "integrity": "sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==", + "dev": true, + "license": "MIT" }, "node_modules/memoize-one": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-5.2.1.tgz", "integrity": "sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q==", - "dev": true + "dev": true, + "license": "MIT" + }, + "node_modules/memory-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/memory-stream/-/memory-stream-1.0.0.tgz", + "integrity": "sha512-Wm13VcsPIMdG96dzILfij09PvuS3APtcKNh7M28FsCA/w6+1mjR7hhPmfFNoilX9xU7wTdhsH5lJAm6XNzdtww==", + "license": "MIT", + "dependencies": { + "readable-stream": "^3.4.0" + } + }, + "node_modules/memory-stream/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } }, "node_modules/mensch": { "version": "0.3.4", "resolved": "https://registry.npmjs.org/mensch/-/mensch-0.3.4.tgz", "integrity": "sha512-IAeFvcOnV9V0Yk+bFhYR07O3yNina9ANIN5MoXBKYJ/RLYPurd2d0yw14MDhpr9/momp0WofT1bPUh3hkzdi/g==", - "dev": true + "dev": true, + "license": "MIT" }, - "node_modules/merkle-lib": { - "version": "2.0.10", - "resolved": "https://registry.npmjs.org/merkle-lib/-/merkle-lib-2.0.10.tgz", - "integrity": "sha512-XrNQvUbn1DL5hKNe46Ccs+Tu3/PYOlrcZILuGUhb95oKBPjc/nmIC8D462PQkipVDGKRvwhn+QFg2cCdIvmDJA==" + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "license": "MIT", + "engines": { + "node": ">= 8" + } }, "node_modules/merkletreejs": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/merkletreejs/-/merkletreejs-0.1.6.tgz", - "integrity": "sha512-avzBcnIc5j3jBuNNY6NIpAZg1G24IWZPhZUlwoPILnC7uf/Xj4mgW9rA99/zSJn/Nf56TIAUS8Ooiy2nsUIYKg==", + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/merkletreejs/-/merkletreejs-0.4.1.tgz", + "integrity": "sha512-W2VSHeGTdAnWtedee+pgGn7SHvncMdINnMeHAaXrfarSaMNLff/pm7RCr/QXYxN6XzJFgJZY+28ejO0lAosW4A==", + "license": "MIT", "dependencies": { "buffer-reverse": "^1.0.1", - "crypto-js": "^3.1.9-1", - "is-buffer": "^2.0.3", - "merkle-lib": "^2.0.10", + "crypto-js": "^4.2.0", "treeify": "^1.1.0" }, "engines": { "node": ">= 7.6.0" } }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, "node_modules/mime": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", "dev": true, + "license": "MIT", "bin": { "mime": "cli.js" }, @@ -5032,7 +5605,7 @@ "version": "1.52.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "dev": true, + "license": "MIT", "engines": { "node": ">= 0.6" } @@ -5041,7 +5614,7 @@ "version": "2.1.35", "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "dev": true, + "license": "MIT", "dependencies": { "mime-db": "1.52.0" }, @@ -5049,29 +5622,24 @@ "node": ">= 0.6" } }, - "node_modules/mimic-fn": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", - "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", - "dev": true, - "engines": { - "node": ">=4" - } - }, "node_modules/minimalistic-assert": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", - "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==" + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", + "license": "ISC" }, "node_modules/minimalistic-crypto-utils": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", - "integrity": "sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==" + "integrity": "sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==", + "license": "MIT" }, "node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", "dependencies": { "brace-expansion": "^1.1.7" }, @@ -5080,153 +5648,150 @@ } }, "node_modules/minimist": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.7.tgz", - "integrity": "sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==", + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", "dev": true, + "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "license": "MIT", + "dependencies": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">= 8" + } + }, "node_modules/minsc": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/minsc/-/minsc-0.2.0.tgz", - "integrity": "sha512-cvIke62kbnZQv59LS5d0R921bkcq3FVz2MmN4RsWnQrusozQpxh/wbOOR5JlrRtNFLkceIz470Dj+kflYjzgzQ==" + "integrity": "sha512-cvIke62kbnZQv59LS5d0R921bkcq3FVz2MmN4RsWnQrusozQpxh/wbOOR5JlrRtNFLkceIz470Dj+kflYjzgzQ==", + "license": "MIT" }, "node_modules/mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-3.0.1.tgz", + "integrity": "sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg==", + "license": "MIT", "bin": { - "mkdirp": "bin/cmd.js" + "mkdirp": "dist/cjs/src/bin.js" }, "engines": { "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/mkdirp2": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/mkdirp2/-/mkdirp2-1.0.5.tgz", - "integrity": "sha512-xOE9xbICroUDmG1ye2h4bZ8WBie9EGmACaco8K8cx6RlkJJrxGIqjGqztAI+NMhexXBcdGbSEzI6N3EJPevxZw==", - "dev": true - }, "node_modules/mocha": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.0.0.tgz", - "integrity": "sha512-0Wl+elVUD43Y0BqPZBzZt8Tnkw9CMUdNYnUsTfOM1vuhJVZL+kiesFYsqwBkEEuEixaiPe5ZQdqDgX2jddhmoA==", - "dev": true, - "dependencies": { - "@ungap/promise-all-settled": "1.1.2", - "ansi-colors": "4.1.1", - "browser-stdout": "1.3.1", - "chokidar": "3.5.3", - "debug": "4.3.4", - "diff": "5.0.0", - "escape-string-regexp": "4.0.0", - "find-up": "5.0.0", - "glob": "7.2.0", - "he": "1.2.0", - "js-yaml": "4.1.0", - "log-symbols": "4.1.0", - "minimatch": "5.0.1", - "ms": "2.1.3", - "nanoid": "3.3.3", - "serialize-javascript": "6.0.0", - "strip-json-comments": "3.1.1", - "supports-color": "8.1.1", - "workerpool": "6.2.1", - "yargs": "16.2.0", - "yargs-parser": "20.2.4", - "yargs-unparser": "2.0.0" + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-11.1.0.tgz", + "integrity": "sha512-8uJR5RTC2NgpY3GrYcgpZrsEd9zKbPDpob1RezyR2upGHRQtHWofmzTMzTMSV6dru3tj5Ukt0+Vnq1qhFEEwAg==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-colors": "^4.1.3", + "browser-stdout": "^1.3.1", + "chokidar": "^3.5.3", + "debug": "^4.3.5", + "diff": "^5.2.0", + "escape-string-regexp": "^4.0.0", + "find-up": "^5.0.0", + "glob": "^10.4.5", + "he": "^1.2.0", + "js-yaml": "^4.1.0", + "log-symbols": "^4.1.0", + "minimatch": "^5.1.6", + "ms": "^2.1.3", + "serialize-javascript": "^6.0.2", + "strip-json-comments": "^3.1.1", + "supports-color": "^8.1.1", + "workerpool": "^6.5.1", + "yargs": "^17.7.2", + "yargs-parser": "^21.1.1", + "yargs-unparser": "^2.0.0" }, "bin": { "_mocha": "bin/_mocha", "mocha": "bin/mocha.js" }, "engines": { - "node": ">= 14.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/mochajs" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/mocha/node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, - "node_modules/mocha/node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "node_modules/mocha/node_modules/brace-expansion": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" } }, "node_modules/mocha/node_modules/glob": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", - "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "version": "10.4.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", + "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", "dev": true, + "license": "ISC", "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" }, - "engines": { - "node": "*" + "bin": { + "glob": "dist/esm/bin.mjs" }, "funding": { "url": "https://github.com/sponsors/isaacs" } }, "node_modules/mocha/node_modules/glob/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", "dev": true, + "license": "ISC", "dependencies": { - "brace-expansion": "^1.1.7" + "brace-expansion": "^2.0.1" }, "engines": { - "node": "*" - } - }, - "node_modules/mocha/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/mocha/node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, - "dependencies": { - "argparse": "^2.0.1" + "node": ">=16 || 14 >=14.17" }, - "bin": { - "js-yaml": "bin/js-yaml.js" + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, "node_modules/mocha/node_modules/minimatch": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz", - "integrity": "sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==", + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", "dev": true, + "license": "ISC", "dependencies": { "brace-expansion": "^2.0.1" }, @@ -5234,31 +5799,14 @@ "node": ">=10" } }, - "node_modules/mocha/node_modules/minimatch/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/mocha/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true - }, - "node_modules/mocha/node_modules/strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "node_modules/mocha/node_modules/minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", "dev": true, + "license": "ISC", "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=16 || 14 >=14.17" } }, "node_modules/mocha/node_modules/supports-color": { @@ -5266,6 +5814,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", "dev": true, + "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -5276,81 +5825,66 @@ "url": "https://github.com/chalk/supports-color?sponsor=1" } }, - "node_modules/mocha/node_modules/yargs-parser": { - "version": "20.2.4", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", - "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", - "dev": true, + "node_modules/module-error": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/module-error/-/module-error-1.0.2.tgz", + "integrity": "sha512-0yuvsqSCv8LbaOKhnsQ/T5JhyFlCYLPXK3U2sgV10zoKQwzs/MyfuQUOZQ1V/6OCOJsK/TRgNVrPuPDqtdMFtA==", + "license": "MIT", "engines": { "node": ">=10" } }, "node_modules/moment": { - "version": "2.29.4", - "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz", - "integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==", + "version": "2.30.1", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.30.1.tgz", + "integrity": "sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==", "dev": true, + "license": "MIT", "engines": { "node": "*" } }, "node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "node_modules/mute-stream": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz", - "integrity": "sha512-r65nCZhrbXXb6dXOACihYApHw2Q6pV0M3V0PSxd74N0+D8nzAdEAITq2oAjA1jVnKI+tGvEBUpqiMh0+rW6zDQ==", - "dev": true - }, - "node_modules/nan": { - "version": "2.17.0", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.17.0.tgz", - "integrity": "sha512-2ZTgtl0nJsO0KQCjEpxcIr5D+Yv90plTitZt9JBfQvVJDS5seMl3FOvsh3+9CoYWXf/1l5OaZzzF6nDm4cagaQ==", - "dev": true - }, - "node_modules/nanoid": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.3.tgz", - "integrity": "sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w==", + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "dev": true, - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } + "license": "MIT" }, "node_modules/napi-macros": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/napi-macros/-/napi-macros-2.0.0.tgz", - "integrity": "sha512-A0xLykHtARfueITVDernsAWdtIMbOJgKgcluwENp3AlsKN/PloyO10HtmoqnFAQAcxPkgZN7wdfPfEd0zNGxbg==" + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/napi-macros/-/napi-macros-2.2.2.tgz", + "integrity": "sha512-hmEVtAGYzVQpCKdbQea4skABsdXW4RUh5t5mJ2zzqowJS2OyXZTU1KhDVFhx+NlWZ4ap9mqR9TcDO3LTTttd+g==", + "license": "MIT" }, "node_modules/natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/neo-async": { "version": "2.6.2", "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", - "dev": true + "dev": true, + "license": "MIT" }, - "node_modules/nice-try": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", - "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", - "dev": true + "node_modules/node-addon-api": { + "version": "8.5.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-8.5.0.tgz", + "integrity": "sha512-/bRZty2mXUIFY/xU5HLvveNHlswNJej+RnxBjOMkidWfwZzgTbPG1E3K5TOxRLOR+5hX7bSofy8yf1hZevMS8A==", + "license": "MIT", + "engines": { + "node": "^18 || ^20 || >= 21" + } }, "node_modules/node-fetch": { - "version": "2.6.7", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", - "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "license": "MIT", "dependencies": { "whatwg-url": "^5.0.0" }, @@ -5367,19 +5901,27 @@ } }, "node_modules/node-gyp-build": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.6.0.tgz", - "integrity": "sha512-NTZVKn9IylLwUzaKjkas1e4u2DLNcV4rdYagA4PWdPwW87Bi7z+BznyKSRwS/761tV/lzCGXplWsiaMjLqP2zQ==", + "version": "4.8.4", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.4.tgz", + "integrity": "sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==", + "license": "MIT", "bin": { "node-gyp-build": "bin.js", "node-gyp-build-optional": "optional.js", "node-gyp-build-test": "build-test.js" } }, + "node_modules/node-int64": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", + "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", + "license": "MIT" + }, "node_modules/noise-protocol-stream": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/noise-protocol-stream/-/noise-protocol-stream-1.1.3.tgz", "integrity": "sha512-yqMEKdaCWnl3vYYubRAu10Z8tXzoDVyYVv6sfMa3LdHhqkk5C26TTeffevr79jwhH+Yh6BkPbAXuIAPuwPO9LQ==", + "license": "ISC", "dependencies": { "duplexify": "^3.6.0", "end-of-stream": "^1.4.1", @@ -5389,30 +5931,19 @@ } }, "node_modules/nopt": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz", - "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==", + "version": "7.2.1", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-7.2.1.tgz", + "integrity": "sha512-taM24ViiimT/XntxbPyJQzCG+p4EKOpgD3mxFwW38mGjVUrfERQOeY4EDHjdnptttfHuHQXFx+lTP08Q+mLa/w==", "dev": true, + "license": "ISC", "dependencies": { - "abbrev": "1" + "abbrev": "^2.0.0" }, "bin": { "nopt": "bin/nopt.js" }, "engines": { - "node": ">=6" - } - }, - "node_modules/normalize-package-data": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", - "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", - "dev": true, - "dependencies": { - "hosted-git-info": "^2.1.4", - "resolve": "^1.10.0", - "semver": "2 || 3 || 4 || 5", - "validate-npm-package-license": "^3.0.1" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, "node_modules/normalize-path": { @@ -5420,21 +5951,33 @@ "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, - "node_modules/npm-normalize-package-bin": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-1.0.1.tgz", - "integrity": "sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA==", - "dev": true + "node_modules/npmlog": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-6.0.2.tgz", + "integrity": "sha512-/vBvz5Jfr9dT/aFWd0FIRf+T/Q2WBsLENygUaFUqstqsycmZAP/t5BvFJTK0viFmSUxiUKTUplWy5vt+rvKIxg==", + "deprecated": "This package is no longer supported.", + "license": "ISC", + "dependencies": { + "are-we-there-yet": "^3.0.0", + "console-control-strings": "^1.1.0", + "gauge": "^4.0.3", + "set-blocking": "^2.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } }, "node_modules/nth-check": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "boolbase": "^1.0.0" }, @@ -5443,10 +5986,11 @@ } }, "node_modules/nunjucks": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/nunjucks/-/nunjucks-3.2.3.tgz", - "integrity": "sha512-psb6xjLj47+fE76JdZwskvwG4MYsQKXUtMsPh6U0YMvmyjRtKRFcxnlXGWglNybtNTNVmGdp94K62/+NjF5FDQ==", + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/nunjucks/-/nunjucks-3.2.4.tgz", + "integrity": "sha512-26XRV6BhkgK0VOxfbU5cQI+ICFUtMLixv1noZn1tGU38kQH5A5nmmbk/O45xdyBhD1esk47nKrY0mvQpZIhRjQ==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "a-sync-waterfall": "^1.0.0", "asap": "^2.0.3", @@ -5471,46 +6015,47 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/nunjucks-do/-/nunjucks-do-1.0.0.tgz", "integrity": "sha512-GQwENqZdcSbni0iYfEiNi3hs634JBSQdxnbnd9CetGkMYPnpjG1Jn5DT/qgAaC/STwMc7C4MSIJvLSNertclSg==", - "dev": true + "dev": true, + "license": "Apache-2.0" }, "node_modules/nunjucks/node_modules/commander": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/commander/-/commander-5.1.0.tgz", "integrity": "sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==", "dev": true, + "license": "MIT", "engines": { "node": ">= 6" } }, - "node_modules/oauth-sign": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", - "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", - "dev": true, - "engines": { - "node": "*" - } - }, "node_modules/object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, - "node_modules/object-get": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/object-get/-/object-get-2.1.1.tgz", - "integrity": "sha512-7n4IpLMzGGcLEMiQKsNR7vCe+N5E9LORFrtNUVy4sO3dj9a3HedZCxEL2T7QuLhcHN1NBuBsMOKaOsAYI9IIvg==", - "dev": true + "node_modules/object-inspect": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, "node_modules/object-path": { "version": "0.11.8", "resolved": "https://registry.npmjs.org/object-path/-/object-path-0.11.8.tgz", "integrity": "sha512-YJjNZrlXJFM42wTBn6zgOJVar9KFJvzx6sTWDte8sWZF//cnjl0BxHNpfZx+ZffXX63A9q0b1zsFiBX4g4X5KA==", "dev": true, + "license": "MIT", "engines": { "node": ">= 10.12.0" } @@ -5520,6 +6065,7 @@ "resolved": "https://registry.npmjs.org/object-to-spawn-args/-/object-to-spawn-args-2.0.1.tgz", "integrity": "sha512-6FuKFQ39cOID+BMZ3QaphcC8Y4cw6LXBLyIgPU+OhIYwviJamPAn+4mITapnSBQrejB+NNp+FMskhD8Cq+Ys3w==", "dev": true, + "license": "MIT", "engines": { "node": ">=8.0.0" } @@ -5542,6 +6088,7 @@ "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", "integrity": "sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==", "dev": true, + "license": "MIT", "dependencies": { "ee-first": "1.1.1" }, @@ -5553,27 +6100,17 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "license": "ISC", "dependencies": { "wrappy": "1" } }, - "node_modules/onetime": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", - "integrity": "sha512-oyyPpiMaKARvvcgip+JV+7zci5L8D1W9RZIz2l1o08AM3pfspitVWnPt3mzHcBPp12oYMTy0pqrFs/C+m3EwsQ==", - "dev": true, - "dependencies": { - "mimic-fn": "^1.0.0" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/open": { "version": "7.4.2", "resolved": "https://registry.npmjs.org/open/-/open-7.4.2.tgz", "integrity": "sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q==", "dev": true, + "license": "MIT", "dependencies": { "is-docker": "^2.0.0", "is-wsl": "^2.1.1" @@ -5590,60 +6127,45 @@ "resolved": "https://registry.npmjs.org/opener/-/opener-1.5.2.tgz", "integrity": "sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A==", "dev": true, + "license": "(WTFPL OR MIT)", "bin": { "opener": "bin/opener-bin.js" } }, "node_modules/optionator": { - "version": "0.8.3", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", - "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", "dev": true, + "license": "MIT", "dependencies": { - "deep-is": "~0.1.3", - "fast-levenshtein": "~2.0.6", - "levn": "~0.3.0", - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2", - "word-wrap": "~1.2.3" + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" }, "engines": { "node": ">= 0.8.0" } }, - "node_modules/os-homedir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", - "integrity": "sha512-B5JU3cabzk8c67mRRd3ECmROafjYMXbuzlwtqdM8IbS8ktlTix8aFGb2bAGKrSRIlnfKwovGUUr72JUPyOb6kQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/os-tmpdir": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, - "node_modules/osenv": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz", - "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", - "dev": true, - "dependencies": { - "os-homedir": "^1.0.0", - "os-tmpdir": "^1.0.0" - } - }, "node_modules/p-limit": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", "dev": true, + "license": "MIT", "dependencies": { "yocto-queue": "^0.1.0" }, @@ -5659,6 +6181,7 @@ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", "dev": true, + "license": "MIT", "dependencies": { "p-limit": "^3.0.2" }, @@ -5669,11 +6192,19 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/package-json-from-dist": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", + "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", + "dev": true, + "license": "BlueOak-1.0.0" + }, "node_modules/parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", "dev": true, + "license": "MIT", "dependencies": { "callsites": "^3.0.0" }, @@ -5682,24 +6213,39 @@ } }, "node_modules/parse5": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", - "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==", + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.3.0.tgz", + "integrity": "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==", "dev": true, + "license": "MIT", "dependencies": { - "entities": "^4.4.0" + "entities": "^6.0.0" }, "funding": { "url": "https://github.com/inikulin/parse5?sponsor=1" } }, "node_modules/parse5-htmlparser2-tree-adapter": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-7.0.0.tgz", - "integrity": "sha512-B77tOZrqqfUfnVcOrUvfdLbz4pu4RopLD/4vmu3HUPswwTA8OH0EMW9BlWR2B0RCoiZRAHEUu7IxeP1Pd1UU+g==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-7.1.0.tgz", + "integrity": "sha512-ruw5xyKs6lrpo9x9rCZqZZnIUntICjQAd0Wsmp396Ul9lN/h+ifgVV1x1gZHi8euej6wTfpqX8j+BFQxF0NS/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "domhandler": "^5.0.3", + "parse5": "^7.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/parse5-parser-stream": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/parse5-parser-stream/-/parse5-parser-stream-7.1.2.tgz", + "integrity": "sha512-JyeQc9iwFLn5TbvvqACIF/VXG6abODeB3Fwmv/TGdLk2LfbWkaySGY72at4+Ty7EkPZj854u4CrICqNk2qIbow==", "dev": true, + "license": "MIT", "dependencies": { - "domhandler": "^5.0.2", "parse5": "^7.0.0" }, "funding": { @@ -5707,10 +6253,11 @@ } }, "node_modules/parse5/node_modules/entities": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-4.4.0.tgz", - "integrity": "sha512-oYp7156SP8LkeGD0GF85ad1X9Ai79WtRsZ2gxJqtBuzH+98YUV6jkHEKlZkMbcrjJjIVJNIDP/3WL9wQkoPbWA==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz", + "integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==", "dev": true, + "license": "BSD-2-Clause", "engines": { "node": ">=0.12" }, @@ -5723,6 +6270,7 @@ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -5731,29 +6279,28 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, - "node_modules/path-is-inside": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", - "integrity": "sha512-DUWJr3+ULp4zXmol/SZkFf3JGsS9/SIv+Y3Rt93/UjPpDpklB5f1er4O3POIbUuUJ3FXgqte2Q7SrU6zAqwk8w==", - "dev": true - }, "node_modules/path-key": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", - "integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", "dev": true, + "license": "MIT", "engines": { - "node": ">=4" + "node": ">=8" } }, "node_modules/path-match": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/path-match/-/path-match-1.2.4.tgz", "integrity": "sha512-UWlehEdqu36jmh4h5CWJ7tARp1OEVKGHKm6+dg9qMq5RKUTV5WJrGgaZ3dN2m7WFAXDbjlHzvJvL/IUpy84Ktw==", + "deprecated": "This package is archived and no longer maintained. For support, visit https://github.com/expressjs/express/discussions", + "license": "MIT", "dependencies": { "http-errors": "~1.4.0", "path-to-regexp": "^1.0.0" @@ -5763,12 +6310,40 @@ "version": "1.0.7", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true + "license": "MIT" + }, + "node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/path-scurry/node_modules/minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=16 || 14 >=14.17" + } }, "node_modules/path-to-regexp": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz", - "integrity": "sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==", + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.9.0.tgz", + "integrity": "sha512-xIp7/apCFJuUHdDLWe8O1HIkb0kQrOMb/0u6FXQjemHn/ii5LrIzU6bdECnsiTF/GjZkMEKg1xdiZwNqDYlZ6g==", + "license": "MIT", "dependencies": { "isarray": "0.0.1" } @@ -5778,36 +6353,22 @@ "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", "dev": true, + "license": "MIT", "engines": { "node": "*" } }, - "node_modules/pbkdf2": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.2.tgz", - "integrity": "sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==", - "dependencies": { - "create-hash": "^1.1.2", - "create-hmac": "^1.1.4", - "ripemd160": "^2.0.1", - "safe-buffer": "^5.0.1", - "sha.js": "^2.4.8" - }, - "engines": { - "node": ">=0.12" - } - }, "node_modules/performance-now": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==", - "dev": true + "license": "MIT" }, "node_modules/picomatch": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true, + "license": "MIT", "engines": { "node": ">=8.6" }, @@ -5819,59 +6380,40 @@ "version": "8.0.0", "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-8.0.0.tgz", "integrity": "sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==", + "license": "MIT", "engines": { "node": ">=4" } }, "node_modules/portfinder": { - "version": "1.0.32", - "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.32.tgz", - "integrity": "sha512-on2ZJVVDXRADWE6jnQaX0ioEylzgBpQk8r55NE4wjXW1ZxO+BgDlY6DXwj20i0V8eB4SenDQ00WEaxfiIQPcxg==", + "version": "1.0.38", + "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.38.tgz", + "integrity": "sha512-rEwq/ZHlJIKw++XtLAO8PPuOQA/zaPJOZJ37BVuN97nLpMJeuDVLVGRwbFoBgLudgdTMP2hdRJP++H+8QOA3vg==", "dev": true, + "license": "MIT", "dependencies": { - "async": "^2.6.4", - "debug": "^3.2.7", - "mkdirp": "^0.5.6" + "async": "^3.2.6", + "debug": "^4.3.6" }, "engines": { - "node": ">= 0.12.0" - } - }, - "node_modules/portfinder/node_modules/async": { - "version": "2.6.4", - "resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz", - "integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==", - "dev": true, - "dependencies": { - "lodash": "^4.17.14" - } - }, - "node_modules/portfinder/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "dependencies": { - "ms": "^2.1.1" + "node": ">= 10.12" } }, - "node_modules/portfinder/node_modules/mkdirp": { - "version": "0.5.6", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", - "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", - "dev": true, - "dependencies": { - "minimist": "^1.2.6" - }, - "bin": { - "mkdirp": "bin/cmd.js" + "node_modules/possible-typed-array-names": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz", + "integrity": "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" } }, "node_modules/prelude-ls": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", - "integrity": "sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.8.0" } @@ -5879,40 +6421,32 @@ "node_modules/process-nextick-args": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" - }, - "node_modules/progress": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", - "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", - "dev": true, - "engines": { - "node": ">=0.4.0" - } + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "license": "MIT" }, "node_modules/proto-list": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", "integrity": "sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==", - "dev": true - }, - "node_modules/pseudomap": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", - "integrity": "sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ==", - "dev": true - }, - "node_modules/psl": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", - "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/punycode": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", - "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/punycode.js": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode.js/-/punycode.js-2.3.1.tgz", + "integrity": "sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } @@ -5921,19 +6455,27 @@ "version": "1.5.1", "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", "integrity": "sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw==", + "deprecated": "You or someone you depend on is using Q, the JavaScript Promise library that gave JavaScript developers strong feelings about promises. They can almost certainly migrate to the native JavaScript promise now. Thank you literally everyone for joining me in this bet against the odds. Be excellent to each other.\n\n(For a CapTP with native promises, see @endo/eventual-send and @endo/captp)", "dev": true, + "license": "MIT", "engines": { "node": ">=0.6.0", "teleport": ">=0.2.0" } }, "node_modules/qs": { - "version": "6.5.3", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz", - "integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==", - "dev": true, + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.0.tgz", + "integrity": "sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==", + "license": "BSD-3-Clause", + "dependencies": { + "side-channel": "^1.1.0" + }, "engines": { "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/queue-microtask": { @@ -5953,12 +6495,14 @@ "type": "consulting", "url": "https://feross.org/support" } - ] + ], + "license": "MIT" }, "node_modules/randombytes": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "license": "MIT", "dependencies": { "safe-buffer": "^5.1.0" } @@ -5968,6 +6512,7 @@ "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.6" } @@ -5977,6 +6522,7 @@ "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-1.1.7.tgz", "integrity": "sha512-WmJJU2e9Y6M5UzTOkHaM7xJGAPQD8PNzx3bAd2+uhZAim6wDk6dAZxPVYLF67XhbR4hmKGh33Lpmh4XWrCH5Mg==", "dev": true, + "license": "MIT", "dependencies": { "bytes": "1", "string_decoder": "0.10" @@ -5989,68 +6535,42 @@ "version": "0.10.31", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", "integrity": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==", - "dev": true - }, - "node_modules/read-installed": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/read-installed/-/read-installed-4.0.3.tgz", - "integrity": "sha512-O03wg/IYuV/VtnK2h/KXEt9VIbMUFbk3ERG0Iu4FhLZw0EP0T9znqrYDGn6ncbEsXUFaUjiVAWXHzxwt3lhRPQ==", - "dev": true, - "dependencies": { - "debuglog": "^1.0.1", - "read-package-json": "^2.0.0", - "readdir-scoped-modules": "^1.0.0", - "semver": "2 || 3 || 4 || 5", - "slide": "~1.1.3", - "util-extend": "^1.0.1" - }, - "optionalDependencies": { - "graceful-fs": "^4.1.2" - } - }, - "node_modules/read-package-json": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/read-package-json/-/read-package-json-2.1.2.tgz", - "integrity": "sha512-D1KmuLQr6ZSJS0tW8hf3WGpRlwszJOXZ3E8Yd/DNRaM5d+1wVRZdHlpGBLAuovjr28LbWvjpWkBHMxpRGGjzNA==", "dev": true, - "dependencies": { - "glob": "^7.1.1", - "json-parse-even-better-errors": "^2.3.0", - "normalize-package-data": "^2.0.0", - "npm-normalize-package-bin": "^1.0.0" - } + "license": "MIT" }, "node_modules/readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "license": "MIT", "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" } }, - "node_modules/readdir-scoped-modules": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/readdir-scoped-modules/-/readdir-scoped-modules-1.1.0.tgz", - "integrity": "sha512-asaikDeqAQg7JifRsZn1NJZXo9E+VwlyCfbkZhwyISinqk5zNS6266HS5kah6P0SaQKGF6SkNnZVHUzHFYxYDw==", - "deprecated": "This functionality has been moved to @npmcli/fs", - "dev": true, - "dependencies": { - "debuglog": "^1.0.1", - "dezalgo": "^1.0.0", - "graceful-fs": "^4.1.2", - "once": "^1.3.0" - } + "node_modules/readable-stream/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "license": "MIT" + }, + "node_modules/readable-stream/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "license": "MIT" }, "node_modules/readdirp": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", "dev": true, + "license": "MIT", "dependencies": { "picomatch": "^2.2.1" }, @@ -6059,188 +6579,20 @@ } }, "node_modules/redis": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/redis/-/redis-3.1.2.tgz", - "integrity": "sha512-grn5KoZLr/qrRQVwoSkmzdbw6pwF+/rwODtrOr6vuBRiR/f3rjSTGupbF90Zpqm2oenix8Do6RV7pYEkGwlKkw==", - "dependencies": { - "denque": "^1.5.0", - "redis-commands": "^1.7.0", - "redis-errors": "^1.2.0", - "redis-parser": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/node-redis" - } - }, - "node_modules/redis-commands": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/redis-commands/-/redis-commands-1.7.0.tgz", - "integrity": "sha512-nJWqw3bTFy21hX/CPKHth6sfhZbdiHP6bTawSgQBlKOVRG7EZkfHbbHwQJnrE4vsQf0CMNE+3gJ4Fmm16vdVlQ==" - }, - "node_modules/redis-errors": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/redis-errors/-/redis-errors-1.2.0.tgz", - "integrity": "sha512-1qny3OExCf0UvUV/5wpYKf2YwPcOqXzkwKKSmKHiE6ZMQs5heeE/c8eXK+PNllPvmjgAbfnsbpkGZWy8cBpn9w==", - "engines": { - "node": ">=4" - } - }, - "node_modules/redis-parser": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/redis-parser/-/redis-parser-3.0.0.tgz", - "integrity": "sha512-DJnGAeenTdpMEH6uAJRK/uiyEIH9WVsUmoLwzudwGJUwZPp80PDBWPHXSAGNPwNvIXAbe7MSUB1zQFugFml66A==", - "dependencies": { - "redis-errors": "^1.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/reduce-extract": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/reduce-extract/-/reduce-extract-1.0.0.tgz", - "integrity": "sha512-QF8vjWx3wnRSL5uFMyCjDeDc5EBMiryoT9tz94VvgjKfzecHAVnqmXAwQDcr7X4JmLc2cjkjFGCVzhMqDjgR9g==", - "dev": true, - "dependencies": { - "test-value": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/reduce-extract/node_modules/array-back": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/array-back/-/array-back-1.0.4.tgz", - "integrity": "sha512-1WxbZvrmyhkNoeYcizokbmh5oiOCIfyvGtcqbK3Ls1v1fKcquzxnQSceOx6tzq7jmai2kFLWIpGND2cLhH6TPw==", - "dev": true, - "dependencies": { - "typical": "^2.6.0" - }, - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/reduce-extract/node_modules/test-value": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/test-value/-/test-value-1.1.0.tgz", - "integrity": "sha512-wrsbRo7qP+2Je8x8DsK8ovCGyxe3sYfQwOraIY/09A2gFXU9DYKiTF14W4ki/01AEh56kMzAmlj9CaHGDDUBJA==", - "dev": true, - "dependencies": { - "array-back": "^1.0.2", - "typical": "^2.4.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/reduce-flatten": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/reduce-flatten/-/reduce-flatten-3.0.1.tgz", - "integrity": "sha512-bYo+97BmUUOzg09XwfkwALt4PQH1M5L0wzKerBt6WLm3Fhdd43mMS89HiT1B9pJIqko/6lWx3OnV4J9f2Kqp5Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/reduce-unique": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/reduce-unique/-/reduce-unique-2.0.1.tgz", - "integrity": "sha512-x4jH/8L1eyZGR785WY+ePtyMNhycl1N2XOLxhCbzZFaqF4AXjLzqSxa2UHgJ2ZVR/HHyPOvl1L7xRnW8ye5MdA==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/reduce-without": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/reduce-without/-/reduce-without-1.0.1.tgz", - "integrity": "sha512-zQv5y/cf85sxvdrKPlfcRzlDn/OqKFThNimYmsS3flmkioKvkUGn2Qg9cJVoQiEvdxFGLE0MQER/9fZ9sUqdxg==", - "dev": true, - "dependencies": { - "test-value": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/reduce-without/node_modules/array-back": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/array-back/-/array-back-1.0.4.tgz", - "integrity": "sha512-1WxbZvrmyhkNoeYcizokbmh5oiOCIfyvGtcqbK3Ls1v1fKcquzxnQSceOx6tzq7jmai2kFLWIpGND2cLhH6TPw==", - "dev": true, - "dependencies": { - "typical": "^2.6.0" - }, - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/reduce-without/node_modules/test-value": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/test-value/-/test-value-2.1.0.tgz", - "integrity": "sha512-+1epbAxtKeXttkGFMTX9H42oqzOTufR1ceCF+GYA5aOmvaPq9wd4PUS8329fn2RRLGNeUkgRLnVpycjx8DsO2w==", - "dev": true, - "dependencies": { - "array-back": "^1.0.3", - "typical": "^2.6.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/regexpp": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-2.0.1.tgz", - "integrity": "sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw==", - "dev": true, - "engines": { - "node": ">=6.5.0" - } - }, - "node_modules/request": { - "version": "2.88.2", - "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", - "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", - "deprecated": "request has been deprecated, see https://github.com/request/request/issues/3142", - "dev": true, + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/redis/-/redis-4.7.0.tgz", + "integrity": "sha512-zvmkHEAdGMn+hMRXuMBtu4Vo5P6rHQjLoHftu+lBqq8ZTA3RCVC/WzD790bkKKiNFp7d5/9PcSD19fJyyRvOdQ==", + "license": "MIT", + "workspaces": [ + "./packages/*" + ], "dependencies": { - "aws-sign2": "~0.7.0", - "aws4": "^1.8.0", - "caseless": "~0.12.0", - "combined-stream": "~1.0.6", - "extend": "~3.0.2", - "forever-agent": "~0.6.1", - "form-data": "~2.3.2", - "har-validator": "~5.1.3", - "http-signature": "~1.2.0", - "is-typedarray": "~1.0.0", - "isstream": "~0.1.2", - "json-stringify-safe": "~5.0.1", - "mime-types": "~2.1.19", - "oauth-sign": "~0.9.0", - "performance-now": "^2.1.0", - "qs": "~6.5.2", - "safe-buffer": "^5.1.2", - "tough-cookie": "~2.5.0", - "tunnel-agent": "^0.6.0", - "uuid": "^3.3.2" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/request/node_modules/uuid": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", - "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", - "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", - "dev": true, - "bin": { - "uuid": "bin/uuid" + "@redis/bloom": "1.2.0", + "@redis/client": "1.6.0", + "@redis/graph": "1.1.1", + "@redis/json": "1.0.7", + "@redis/search": "1.2.0", + "@redis/time-series": "1.1.0" } }, "node_modules/require-directory": { @@ -6248,6 +6600,7 @@ "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -6256,30 +6609,35 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/requizzle": { "version": "0.2.4", "resolved": "https://registry.npmjs.org/requizzle/-/requizzle-0.2.4.tgz", "integrity": "sha512-JRrFk1D4OQ4SqovXOgdav+K8EAhSB/LJZqCz8tbX0KObcdeM15Ss59ozWMBWmmINMagCwmqn4ZNryUGpBsl6Jw==", "dev": true, + "license": "MIT", "dependencies": { "lodash": "^4.17.21" } }, "node_modules/resolve": { - "version": "1.22.1", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", - "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", - "dev": true, + "version": "1.22.10", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz", + "integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==", + "license": "MIT", "dependencies": { - "is-core-module": "^2.9.0", + "is-core-module": "^2.16.0", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": { "resolve": "bin/resolve" }, + "engines": { + "node": ">= 0.4" + }, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -6289,56 +6647,52 @@ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", "dev": true, + "license": "MIT", "engines": { "node": ">=4" } }, - "node_modules/restore-cursor": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", - "integrity": "sha512-6IzJLuGi4+R14vwagDHX+JrXmPVtPpn4mffDJ1UdR7/Edm87fl6yi8mMBIVvFtJaNTUvjughmW4hwLhRG7gC1Q==", - "dev": true, - "dependencies": { - "onetime": "^2.0.0", - "signal-exit": "^3.0.2" - }, + "node_modules/reusify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", + "license": "MIT", "engines": { - "node": ">=4" + "iojs": ">=1.0.0", + "node": ">=0.10.0" } }, "node_modules/rimraf": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz", - "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==", + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "dev": true, + "license": "ISC", "dependencies": { - "glob": "^7.0.5" + "glob": "^7.1.3" }, "bin": { "rimraf": "bin.js" } }, "node_modules/ripemd160": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", - "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.3.tgz", + "integrity": "sha512-5Di9UC0+8h1L6ZD2d7awM7E/T4uA1fJRlx6zk/NvdCCVEoAnFqvHmCuNeIKoCeIixBX/q8uM+6ycDvF8woqosA==", + "license": "MIT", "dependencies": { - "hash-base": "^3.0.0", - "inherits": "^2.0.1" - } - }, - "node_modules/run-async": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", - "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==", - "dev": true, + "hash-base": "^3.1.2", + "inherits": "^2.0.4" + }, "engines": { - "node": ">=0.12.0" + "node": ">= 0.8" } }, - "node_modules/run-parallel-limit": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/run-parallel-limit/-/run-parallel-limit-1.1.0.tgz", - "integrity": "sha512-jJA7irRNM91jaKc3Hcl1npHsFLOXOoTkPCUL1JEa1R82O2miplXXRaGdjW/KM/98YQWDhJLiSs793CnXfblJUw==", + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", "funding": [ { "type": "github", @@ -6353,22 +6707,11 @@ "url": "https://feross.org/support" } ], + "license": "MIT", "dependencies": { "queue-microtask": "^1.2.2" } }, - "node_modules/rxjs": { - "version": "6.6.7", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", - "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", - "dev": true, - "dependencies": { - "tslib": "^1.9.0" - }, - "engines": { - "npm": ">=2.0.0" - } - }, "node_modules/safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", @@ -6386,7 +6729,8 @@ "type": "consulting", "url": "https://feross.org/support" } - ] + ], + "license": "MIT" }, "node_modules/safe-json-parse": { "version": "1.0.1", @@ -6398,37 +6742,25 @@ "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "dev": true - }, - "node_modules/secp256k1": { - "version": "2.0.10", - "resolved": "https://registry.npmjs.org/secp256k1/-/secp256k1-2.0.10.tgz", - "integrity": "sha512-MvcTiCwsuhEXkk1qyaP9Zy9bw4L7wp6jYTKGAPHZ4LNC041Gr0OMhGZATQdTpFYVhoVZ6It4aKfsw8N19o8uqw==", - "dev": true, - "hasInstallScript": true, - "optional": true, - "dependencies": { - "bindings": "^1.2.1", - "bluebird": "^3.0.2", - "bn.js": "^4.6.4", - "elliptic": "^6.0.2", - "nan": "^2.0.9", - "object-assign": "^4.0.1" - } + "license": "MIT" }, "node_modules/secure-compare": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/secure-compare/-/secure-compare-3.0.1.tgz", "integrity": "sha512-AckIIV90rPDcBcglUwXPF3kg0P0qmPsPXAj6BBEENQE1p5yA1xfmDJzfi1Tappj37Pv2mVbKpL3Z1T+Nn7k1Qw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true, + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "license": "ISC", "bin": { - "semver": "bin/semver" + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" } }, "node_modules/send": { @@ -6436,6 +6768,7 @@ "resolved": "https://registry.npmjs.org/send/-/send-0.17.2.tgz", "integrity": "sha512-UJYB6wFSJE3G00nEivR5rgWp8c2xXvJ3OPWPhmuteU0IKj8nKbG3DrjiOmLwpnHGYWAVwA69zmTm++YG0Hmwww==", "dev": true, + "license": "MIT", "dependencies": { "debug": "2.6.9", "depd": "~1.1.2", @@ -6460,6 +6793,7 @@ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, + "license": "MIT", "dependencies": { "ms": "2.0.0" } @@ -6468,19 +6802,22 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/send/node_modules/destroy": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", "integrity": "sha512-3NdhDuEXnfun/z7x9GOElY49LoqVHoGScmOKwmxhsS8N5Y+Z8KyPPDnaSzqWgYt/ji4mqwfTS34Htrk0zPIXVg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/send/node_modules/http-errors": { "version": "1.8.1", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.8.1.tgz", "integrity": "sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==", "dev": true, + "license": "MIT", "dependencies": { "depd": "~1.1.2", "inherits": "2.0.4", @@ -6492,89 +6829,187 @@ "node": ">= 0.6" } }, - "node_modules/send/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true - }, "node_modules/serialize-javascript": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", - "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", + "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "randombytes": "^2.1.0" } }, + "node_modules/set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", + "license": "ISC" + }, + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/setprototypeof": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/sha.js": { - "version": "2.4.11", - "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", - "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", + "version": "2.4.12", + "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.12.tgz", + "integrity": "sha512-8LzC5+bvI45BjpfXU8V5fdU2mfeKiQe1D1gIMn7XUlF3OTUrpdJpPPH4EMAnF0DsHHdSZqCdSss5qCmJKuiO3w==", + "license": "(MIT AND BSD-3-Clause)", "dependencies": { - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" + "inherits": "^2.0.4", + "safe-buffer": "^5.2.1", + "to-buffer": "^1.2.0" }, "bin": { "sha.js": "bin.js" + }, + "engines": { + "node": ">= 0.10" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/shebang-command": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", - "integrity": "sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", "dev": true, + "license": "MIT", "dependencies": { - "shebang-regex": "^1.0.0" + "shebang-regex": "^3.0.0" }, "engines": { - "node": ">=0.10.0" + "node": ">=8" } }, "node_modules/shebang-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", - "integrity": "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", "dev": true, + "license": "MIT", "engines": { - "node": ">=0.10.0" + "node": ">=8" + } + }, + "node_modules/side-channel": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", + "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3", + "side-channel-list": "^1.0.0", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-list": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", + "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/sigmund": { + "node_modules/side-channel-map": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz", - "integrity": "sha512-fCvEXfh6NWpm+YSuY2bpXb/VIihqWA6hLsgboC+0nl71Q7N7o2eaCW8mJa/NLvQhs6jpd3VZV4UiUQlV6+lc8g==", - "dev": true + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, "node_modules/signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } }, "node_modules/simple-aes": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/simple-aes/-/simple-aes-0.1.1.tgz", - "integrity": "sha512-R4Dqz3TlzCyG3qkunLvYWC/gToWvOBqyR9EHIAQQZq2KOnybprjt2zcrWi1DZOyEH9QGLbDl9hqk4TTsxwLIqw==" + "integrity": "sha512-R4Dqz3TlzCyG3qkunLvYWC/gToWvOBqyR9EHIAQQZq2KOnybprjt2zcrWi1DZOyEH9QGLbDl9hqk4TTsxwLIqw==", + "license": "MIT" }, - "node_modules/slice-ansi": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz", - "integrity": "sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.0", - "astral-regex": "^1.0.0", - "is-fullwidth-code-point": "^2.0.0" - }, + "node_modules/sjcl": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/sjcl/-/sjcl-1.0.8.tgz", + "integrity": "sha512-LzIjEQ0S0DpIgnxMEayM1rq9aGwGRG4OnZhCdjx7glTaJtf4zRfpg87ImfjSJjoW9vKpagd82McDOwbRT5kQKQ==", + "license": "(BSD-2-Clause OR GPL-2.0-only)", "engines": { - "node": ">=6" + "node": "*" } }, "node_modules/slick": { @@ -6582,48 +7017,31 @@ "resolved": "https://registry.npmjs.org/slick/-/slick-1.12.2.tgz", "integrity": "sha512-4qdtOGcBjral6YIBCWJ0ljFSKNLz9KkhbWtuGvUyRowl1kxfuE1x/Z/aJcaiilpb3do9bl5K7/1h9XC5wWpY/A==", "dev": true, - "engines": { - "node": "*" - } - }, - "node_modules/slide": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/slide/-/slide-1.1.6.tgz", - "integrity": "sha512-NwrtjCg+lZoqhFU8fOwl4ay2ei8PaqCBOUV3/ektPY9trO1yQ1oXEfmHAhKArUVUr/hOHvy5f6AdP17dCM0zMw==", - "dev": true, + "license": "MIT (http://mootools.net/license.txt)", "engines": { "node": "*" } }, "node_modules/sort-array": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/sort-array/-/sort-array-4.1.5.tgz", - "integrity": "sha512-Ya4peoS1fgFN42RN1REk2FgdNOeLIEMKFGJvs7VTP3OklF8+kl2SkpVliZ4tk/PurWsrWRsdNdU+tgyOBkB9sA==", + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/sort-array/-/sort-array-5.1.1.tgz", + "integrity": "sha512-EltS7AIsNlAFIM9cayrgKrM6XP94ATWwXP4LCL4IQbvbYhELSt2hZTrixg+AaQwnWFs/JGJgqU3rxMcNNWxGAA==", "dev": true, + "license": "MIT", "dependencies": { - "array-back": "^5.0.0", - "typical": "^6.0.1" + "array-back": "^6.2.2", + "typical": "^7.1.1" }, "engines": { - "node": ">=10" - } - }, - "node_modules/sort-array/node_modules/array-back": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/array-back/-/array-back-5.0.0.tgz", - "integrity": "sha512-kgVWwJReZWmVuWOQKEOohXKJX+nD02JAZ54D1RRWlv8L0NebauKAaFxACKzB74RTclt1+WNz5KHaLRDAPZbDEw==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/sort-array/node_modules/typical": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/typical/-/typical-6.0.1.tgz", - "integrity": "sha512-+g3NEp7fJLe9DPa1TArHm9QAA7YciZmWnfAqEaFrBihQ7epOv9i99rjtgb6Iz0wh3WuQDjsCTDfgRoGnmHN81A==", - "dev": true, - "engines": { - "node": ">=10" + "node": ">=12.17" + }, + "peerDependencies": { + "@75lb/nature": "^0.1.1" + }, + "peerDependenciesMeta": { + "@75lb/nature": { + "optional": true + } } }, "node_modules/source-map": { @@ -6631,81 +7049,29 @@ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true, + "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" } }, - "node_modules/spdx-compare": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/spdx-compare/-/spdx-compare-1.0.0.tgz", - "integrity": "sha512-C1mDZOX0hnu0ep9dfmuoi03+eOdDoz2yvK79RxbcrVEG1NO1Ph35yW102DHWKN4pk80nwCgeMmSY5L25VE4D9A==", - "dev": true, - "dependencies": { - "array-find-index": "^1.0.2", - "spdx-expression-parse": "^3.0.0", - "spdx-ranges": "^2.0.0" - } - }, - "node_modules/spdx-correct": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", - "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==", - "dev": true, - "dependencies": { - "spdx-expression-parse": "^3.0.0", - "spdx-license-ids": "^3.0.0" - } - }, - "node_modules/spdx-exceptions": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", - "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", - "dev": true - }, - "node_modules/spdx-expression-parse": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", - "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", - "dev": true, - "dependencies": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" - } - }, - "node_modules/spdx-license-ids": { - "version": "3.0.12", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.12.tgz", - "integrity": "sha512-rr+VVSXtRhO4OHbXUiAF7xW3Bo9DuuF6C5jH+q/x15j2jniycgKbxU09Hr0WqlSLUs4i4ltHGXqTe7VHclYWyA==", - "dev": true - }, - "node_modules/spdx-ranges": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/spdx-ranges/-/spdx-ranges-2.1.1.tgz", - "integrity": "sha512-mcdpQFV7UDAgLpXEE/jOMqvK4LBoO0uTQg0uvXUewmEFhpiZx5yJSZITHB8w1ZahKdhfZqP5GPEOKLyEq5p8XA==", - "dev": true - }, - "node_modules/spdx-satisfies": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/spdx-satisfies/-/spdx-satisfies-4.0.1.tgz", - "integrity": "sha512-WVzZ/cXAzoNmjCWiEluEA3BjHp5tiUmmhn9MK+X0tBbR9sOqtC6UQwmgCNrAIZvNlMuBUYAaHYfb2oqlF9SwKA==", - "dev": true, - "dependencies": { - "spdx-compare": "^1.0.0", - "spdx-expression-parse": "^3.0.0", - "spdx-ranges": "^2.0.0" - } + "node_modules/splitargs2": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/splitargs2/-/splitargs2-0.1.3.tgz", + "integrity": "sha512-7Lt7+Z0YwyhFCbhkXMI3AT5qLcH6rKZgWnmlk0+R4ObjqhTZ3kGB4VMTerMuTmMayJnAuDHYTSomAYtlYq0vbg==", + "license": "ISC" }, "node_modules/sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", - "dev": true + "dev": true, + "license": "BSD-3-Clause" }, "node_modules/sshpk": { - "version": "1.17.0", - "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.17.0.tgz", - "integrity": "sha512-/9HIEs1ZXGhSPE8X6Ccm7Nam1z8KcoCqPdI7ecm1N33EzAetWahvQWVqLZtaZQ+IDKX4IyA2o0gBzqIMkAagHQ==", - "dev": true, + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.18.0.tgz", + "integrity": "sha512-2p2KJZTSqQ/I3+HX42EpYOa2l3f8Erv8MWKsy2I9uf4wA7yFIkXRffYdsx86y6z4vHtV8u7g+pPlr8/4ouAxsQ==", + "license": "MIT", "dependencies": { "asn1": "~0.2.3", "assert-plus": "^1.0.0", @@ -6726,69 +7092,52 @@ "node": ">=0.10.0" } }, + "node_modules/sshpk/node_modules/tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==", + "license": "Unlicense" + }, "node_modules/statuses": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", + "license": "MIT", "engines": { "node": ">= 0.6" } }, - "node_modules/stream-connect": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/stream-connect/-/stream-connect-1.0.2.tgz", - "integrity": "sha512-68Kl+79cE0RGKemKkhxTSg8+6AGrqBt+cbZAXevg2iJ6Y3zX4JhA/sZeGzLpxW9cXhmqAcE7KnJCisUmIUfnFQ==", - "dev": true, - "dependencies": { - "array-back": "^1.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/stream-connect/node_modules/array-back": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/array-back/-/array-back-1.0.4.tgz", - "integrity": "sha512-1WxbZvrmyhkNoeYcizokbmh5oiOCIfyvGtcqbK3Ls1v1fKcquzxnQSceOx6tzq7jmai2kFLWIpGND2cLhH6TPw==", - "dev": true, - "dependencies": { - "typical": "^2.6.0" - }, - "engines": { - "node": ">=0.12.0" - } - }, "node_modules/stream-each": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/stream-each/-/stream-each-1.2.3.tgz", "integrity": "sha512-vlMC2f8I2u/bZGqkdfLQW/13Zihpej/7PmSiMQsbYddxuTsJp8vRe2x2FvVExZg7FaOds43ROAuFJwPR4MTZLw==", + "license": "MIT", "dependencies": { "end-of-stream": "^1.1.0", - "stream-shift": "^1.0.0" - } - }, - "node_modules/stream-shift": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.1.tgz", - "integrity": "sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==" - }, - "node_modules/stream-via": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/stream-via/-/stream-via-1.0.4.tgz", - "integrity": "sha512-DBp0lSvX5G9KGRDTkR/R+a29H+Wk2xItOF+MpZLLNDWbEV9tGPnqLPxHEYjmiz8xGtJHRIqmI+hCjmNzqoA4nQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" + "stream-shift": "^1.0.0" } }, + "node_modules/stream-shift": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.3.tgz", + "integrity": "sha512-76ORR0DO1o1hlKwTbi/DM3EXWGf3ZJYO8cXX5RJwnul2DEg2oyoZyjLNoQM8WsvZiFKCRfC1O0J7iCvie3RZmQ==", + "license": "MIT" + }, "node_modules/string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "license": "MIT", "dependencies": { - "safe-buffer": "~5.2.0" + "safe-buffer": "~5.1.0" } }, + "node_modules/string_decoder/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "license": "MIT" + }, "node_modules/string-template": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/string-template/-/string-template-0.2.1.tgz", @@ -6796,37 +7145,72 @@ "dev": true }, "node_modules/string-width": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, + "license": "MIT", "dependencies": { - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^4.0.0" + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" }, "engines": { - "node": ">=4" + "node": ">=8" } }, "node_modules/strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha512-4XaJ2zQdCzROZDivEVIDPkcQn8LMFSa8kj8Gxb/Lnwzv9A8VctNZ+lfivC/sV3ivW8ElJTERXZoPBRrZKkNKow==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, + "license": "MIT", "dependencies": { - "ansi-regex": "^3.0.0" + "ansi-regex": "^5.0.1" }, "engines": { - "node": ">=4" + "node": ">=8" } }, "node_modules/strip-json-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", "dev": true, + "license": "MIT", "engines": { - "node": ">=0.10.0" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/struct": { @@ -6838,22 +7222,23 @@ } }, "node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, + "license": "MIT", "dependencies": { - "has-flag": "^3.0.0" + "has-flag": "^4.0.0" }, "engines": { - "node": ">=4" + "node": ">=8" } }, "node_modules/supports-preserve-symlinks-flag": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "dev": true, + "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -6861,198 +7246,152 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/table": { - "version": "5.4.6", - "resolved": "https://registry.npmjs.org/table/-/table-5.4.6.tgz", - "integrity": "sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug==", + "node_modules/table-layout": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/table-layout/-/table-layout-4.1.1.tgz", + "integrity": "sha512-iK5/YhZxq5GO5z8wb0bY1317uDF3Zjpha0QFFLA8/trAoiLbQD0HUbMesEaxyzUgDxi2QlcbM8IvqOlEjgoXBA==", "dev": true, + "license": "MIT", "dependencies": { - "ajv": "^6.10.2", - "lodash": "^4.17.14", - "slice-ansi": "^2.1.0", - "string-width": "^3.0.0" + "array-back": "^6.2.2", + "wordwrapjs": "^5.1.0" }, "engines": { - "node": ">=6.0.0" + "node": ">=12.17" } }, - "node_modules/table-layout": { - "version": "0.4.5", - "resolved": "https://registry.npmjs.org/table-layout/-/table-layout-0.4.5.tgz", - "integrity": "sha512-zTvf0mcggrGeTe/2jJ6ECkJHAQPIYEwDoqsiqBjI24mvRmQbInK5jq33fyypaCBxX08hMkfmdOqj6haT33EqWw==", - "dev": true, + "node_modules/tar": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz", + "integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==", + "license": "ISC", "dependencies": { - "array-back": "^2.0.0", - "deep-extend": "~0.6.0", - "lodash.padend": "^4.6.1", - "typical": "^2.6.1", - "wordwrapjs": "^3.0.0" + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^5.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" }, "engines": { - "node": ">=4.0.0" + "node": ">=10" } }, - "node_modules/table-layout/node_modules/array-back": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/array-back/-/array-back-2.0.0.tgz", - "integrity": "sha512-eJv4pLLufP3g5kcZry0j6WXpIbzYw9GUB4mVJZno9wfwiBxbizTnHCw3VJb07cBihbFX48Y7oSrW9y+gt4glyw==", - "dev": true, - "dependencies": { - "typical": "^2.6.1" - }, + "node_modules/tar/node_modules/minipass": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", + "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", + "license": "ISC", "engines": { - "node": ">=4" + "node": ">=8" } }, - "node_modules/table/node_modules/ansi-regex": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz", - "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==", - "dev": true, + "node_modules/tar/node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "license": "MIT", + "bin": { + "mkdirp": "bin/cmd.js" + }, "engines": { - "node": ">=6" + "node": ">=10" } }, - "node_modules/table/node_modules/emoji-regex": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", - "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", - "dev": true - }, - "node_modules/table/node_modules/string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "node_modules/test-exclude": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-7.0.1.tgz", + "integrity": "sha512-pFYqmTw68LXVjeWJMST4+borgQP2AyMNbg1BpZh9LbyhUeNkeaPF9gzfPGUAnSMV3qPYdWUwDIjjCLiSDOl7vg==", "dev": true, + "license": "ISC", "dependencies": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" + "@istanbuljs/schema": "^0.1.2", + "glob": "^10.4.1", + "minimatch": "^9.0.4" }, "engines": { - "node": ">=6" + "node": ">=18" } }, - "node_modules/table/node_modules/strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "node_modules/test-exclude/node_modules/brace-expansion": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", "dev": true, + "license": "MIT", "dependencies": { - "ansi-regex": "^4.1.0" - }, - "engines": { - "node": ">=6" + "balanced-match": "^1.0.0" } }, - "node_modules/taffydb": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/taffydb/-/taffydb-2.6.2.tgz", - "integrity": "sha512-y3JaeRSplks6NYQuCOj3ZFMO3j60rTwbuKCvZxsAraGYH2epusatvZ0baZYA01WsGqJBq/Dl6vOrMUJqyMj8kA==", - "dev": true - }, - "node_modules/temp-path": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/temp-path/-/temp-path-1.0.0.tgz", - "integrity": "sha512-TvmyH7kC6ZVTYkqCODjJIbgvu0FKiwQpZ4D1aknE7xpcDf/qEOB8KZEK5ef2pfbVoiBhNWs3yx4y+ESMtNYmlg==", - "dev": true - }, - "node_modules/test-exclude": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", - "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", + "node_modules/test-exclude/node_modules/glob": { + "version": "10.4.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", + "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", "dev": true, + "license": "ISC", "dependencies": { - "@istanbuljs/schema": "^0.1.2", - "glob": "^7.1.4", - "minimatch": "^3.0.4" + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" }, - "engines": { - "node": ">=8" + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/test-value": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/test-value/-/test-value-3.0.0.tgz", - "integrity": "sha512-sVACdAWcZkSU9x7AOmJo5TqE+GyNJknHaHsMrR6ZnhjVlVN9Yx6FjHrsKZ3BjIpPCT68zYesPWkakrNupwfOTQ==", + "node_modules/test-exclude/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", "dev": true, + "license": "ISC", "dependencies": { - "array-back": "^2.0.0", - "typical": "^2.6.1" + "brace-expansion": "^2.0.1" }, "engines": { - "node": ">=4.0.0" + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/test-value/node_modules/array-back": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/array-back/-/array-back-2.0.0.tgz", - "integrity": "sha512-eJv4pLLufP3g5kcZry0j6WXpIbzYw9GUB4mVJZno9wfwiBxbizTnHCw3VJb07cBihbFX48Y7oSrW9y+gt4glyw==", + "node_modules/test-exclude/node_modules/minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", "dev": true, - "dependencies": { - "typical": "^2.6.1" - }, + "license": "ISC", "engines": { - "node": ">=4" + "node": ">=16 || 14 >=14.17" } }, - "node_modules/text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", - "dev": true - }, "node_modules/through": { "version": "2.3.8", "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==" + "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", + "license": "MIT" }, "node_modules/through2": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "license": "MIT", "dependencies": { "readable-stream": "~2.3.6", "xtend": "~4.0.1" } }, - "node_modules/through2/node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" - }, - "node_modules/through2/node_modules/readable-stream": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", - "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/through2/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" - }, - "node_modules/through2/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, "node_modules/tiny-lr": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/tiny-lr/-/tiny-lr-1.1.1.tgz", "integrity": "sha512-44yhA3tsaRoMOjQQ+5v5mVdqef+kH6Qze9jTpqtVufgYjYt08zyZAwNwwVBj3i1rJMnR52IxOW0LK0vBzgAkuA==", "dev": true, + "license": "MIT", "dependencies": { "body": "^5.1.0", "debug": "^3.1.0", @@ -7067,14 +7406,16 @@ "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "dev": true, + "license": "MIT", "dependencies": { "ms": "^2.1.1" } }, "node_modules/tiny-secp256k1": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/tiny-secp256k1/-/tiny-secp256k1-2.2.1.tgz", - "integrity": "sha512-/U4xfVqnVxJXN4YVsru0E6t5wVncu2uunB8+RVR40fYUxkKYUPS10f+ePQZgFBoE/Jbf9H1NBveupF2VmB58Ng==", + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/tiny-secp256k1/-/tiny-secp256k1-2.2.3.tgz", + "integrity": "sha512-SGcL07SxcPN2nGKHTCvRMkQLYPSoeFcvArUSCYtjVARiFAWU44cCIqYS0mYAU6nY7XfvwURuTIGo2Omt3ZQr0Q==", + "license": "MIT", "dependencies": { "uint8array-tools": "0.0.7" }, @@ -7082,11 +7423,30 @@ "node": ">=14.0.0" } }, + "node_modules/tldts": { + "version": "6.1.86", + "resolved": "https://registry.npmjs.org/tldts/-/tldts-6.1.86.tgz", + "integrity": "sha512-WMi/OQ2axVTf/ykqCQgXiIct+mSQDFdH2fkwhPwgEwvJ1kSzZRiinb0zF2Xb8u4+OqPChmyI6MEu4EezNJz+FQ==", + "license": "MIT", + "dependencies": { + "tldts-core": "^6.1.86" + }, + "bin": { + "tldts": "bin/cli.js" + } + }, + "node_modules/tldts-core": { + "version": "6.1.86", + "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-6.1.86.tgz", + "integrity": "sha512-Je6p7pkk+KMzMv2XXKmAE3McmolOQFdxkKw0R8EYNr7sELW46JqnNeTX8ybPiQgvg1ymCoF8LXs5fzFaZvJPTA==", + "license": "MIT" + }, "node_modules/tmp": { "version": "0.0.28", "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.28.tgz", "integrity": "sha512-c2mmfiBmND6SOVxzogm1oda0OJ1HZVIk/5n26N59dDTh80MUeavpiCls4PGAdkX1PFkKokLpcf7prSjCeXLsJg==", "dev": true, + "license": "MIT", "dependencies": { "os-tmpdir": "~1.0.1" }, @@ -7094,11 +7454,31 @@ "node": ">=0.4.0" } }, + "node_modules/to-buffer": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/to-buffer/-/to-buffer-1.2.2.tgz", + "integrity": "sha512-db0E3UJjcFhpDhAF4tLo03oli3pwl3dbnzXOUIlRKrp+ldk/VUxzpWYZENsw2SZiuBjHAk7DfB0VU7NKdpb6sw==", + "license": "MIT", + "dependencies": { + "isarray": "^2.0.5", + "safe-buffer": "^5.2.1", + "typed-array-buffer": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/to-buffer/node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "license": "MIT" + }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, + "license": "MIT", "dependencies": { "is-number": "^7.0.0" }, @@ -7111,32 +7491,34 @@ "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.6" } }, "node_modules/tough-cookie": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", - "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", - "dev": true, + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-5.1.2.tgz", + "integrity": "sha512-FVDYdxtnj0G6Qm/DhNPSb8Ju59ULcup3tuJxkFb5K8Bv2pUXILbf0xZWU8PX8Ov19OXljbUyveOFwRMwkXzO+A==", + "license": "BSD-3-Clause", "dependencies": { - "psl": "^1.1.28", - "punycode": "^2.1.1" + "tldts": "^6.1.32" }, "engines": { - "node": ">=0.8" + "node": ">=16" } }, "node_modules/tr46": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "license": "MIT" }, "node_modules/treeify": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/treeify/-/treeify-1.1.0.tgz", "integrity": "sha512-1m4RA7xVAJrSGrrXGs0L3YTwyvBs2S8PbRHaLZAkFw7JR8oIFwYtysxlBZhYIa7xSyiYJKZ3iGrrk55cGA3i9A==", + "license": "MIT", "engines": { "node": ">=0.6" } @@ -7145,19 +7527,22 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/try-resolve/-/try-resolve-1.0.1.tgz", "integrity": "sha512-yHeaPjCBzVaXwWl5IMUapTaTC2rn/eBYg2fsG2L+CvJd+ttFbk0ylDnpTO3wVhosmE1tQEvcebbBeKLCwScQSQ==", - "dev": true + "deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.", + "dev": true, + "license": "MIT" }, "node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "dev": true, + "license": "0BSD" }, "node_modules/tunnel-agent": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", - "dev": true, + "license": "Apache-2.0", "dependencies": { "safe-buffer": "^5.0.1" }, @@ -7166,54 +7551,83 @@ } }, "node_modules/tweetnacl": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", - "integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==", - "dev": true + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.3.tgz", + "integrity": "sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==", + "license": "Unlicense" + }, + "node_modules/tweetnacl-util": { + "version": "0.15.1", + "resolved": "https://registry.npmjs.org/tweetnacl-util/-/tweetnacl-util-0.15.1.tgz", + "integrity": "sha512-RKJBIj8lySrShN4w6i/BonWp2Z/uxwC3h4y7xsRrpP59ZboCd0GpEVsOnMDYLMmKBpYhb5TgHzZXy7wTfYFBRw==", + "license": "Unlicense" }, "node_modules/type-check": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", - "integrity": "sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==", + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", "dev": true, + "license": "MIT", "dependencies": { - "prelude-ls": "~1.1.2" + "prelude-ls": "^1.2.1" }, "engines": { "node": ">= 0.8.0" } }, "node_modules/type-detect": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", - "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.1.0.tgz", + "integrity": "sha512-Acylog8/luQ8L7il+geoSxhEkazvkslg7PSNKOX59mbB9cOveP5aq9h74Y7YU8yDpJwetzQQrfIwtf4Wp4LKcw==", "dev": true, + "license": "MIT", "engines": { "node": ">=4" } }, + "node_modules/typed-array-buffer": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz", + "integrity": "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-typed-array": "^1.1.14" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/typeforce": { "version": "1.18.0", "resolved": "https://registry.npmjs.org/typeforce/-/typeforce-1.18.0.tgz", - "integrity": "sha512-7uc1O8h1M1g0rArakJdf0uLRSSgFcYexrVoKo+bzJd32gd4gDy2L/Z+8/FjPnU9ydY3pEnVPtr9FyscYY60K1g==" + "integrity": "sha512-7uc1O8h1M1g0rArakJdf0uLRSSgFcYexrVoKo+bzJd32gd4gDy2L/Z+8/FjPnU9ydY3pEnVPtr9FyscYY60K1g==", + "license": "MIT" }, "node_modules/typical": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/typical/-/typical-2.6.1.tgz", - "integrity": "sha512-ofhi8kjIje6npGozTip9Fr8iecmYfEbS06i0JnIg+rh51KakryWF4+jX8lLKZVhy6N+ID45WYSFCxPOdTWCzNg==", - "dev": true + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/typical/-/typical-7.3.0.tgz", + "integrity": "sha512-ya4mg/30vm+DOWfBg4YK3j2WD6TWtRkCbasOJr40CseYENzCUby/7rIvXA99JGsQHeNxLbnXdyLLxKSv3tauFw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.17" + } }, "node_modules/uc.micro": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz", - "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==", - "dev": true + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-2.1.0.tgz", + "integrity": "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==", + "dev": true, + "license": "MIT" }, "node_modules/uglify-js": { - "version": "3.17.4", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.17.4.tgz", - "integrity": "sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g==", + "version": "3.19.3", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.19.3.tgz", + "integrity": "sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==", "dev": true, + "license": "BSD-2-Clause", "optional": true, "bin": { "uglifyjs": "bin/uglifyjs" @@ -7226,15 +7640,27 @@ "version": "0.0.7", "resolved": "https://registry.npmjs.org/uint8array-tools/-/uint8array-tools-0.0.7.tgz", "integrity": "sha512-vrrNZJiusLWoFWBqz5Y5KMCgP9W9hnjZHzZiZRT8oNAkq3d5Z5Oe76jAvVVSRh4U8GGR90N2X1dWtrhvx6L8UQ==", + "license": "MIT", "engines": { "node": ">=14.0.0" } }, "node_modules/underscore": { - "version": "1.13.6", - "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.6.tgz", - "integrity": "sha512-+A5Sja4HP1M08MaXya7p5LvjuM7K6q/2EaC0+iovj/wOcMsTzMvDFbasi/oSapiwOlt252IqsKqPjCl7huKS0A==", - "dev": true + "version": "1.13.7", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.7.tgz", + "integrity": "sha512-GMXzWtsc57XAtguZgaQViUOzs0KTkk8ojr3/xAxXLITqf/3EMwxC0inyETfDFjH/Krbhuep0HNbbjI9i/q3F3g==", + "dev": true, + "license": "MIT" + }, + "node_modules/undici": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-7.16.0.tgz", + "integrity": "sha512-QEg3HPMll0o3t2ourKwOeUAZ159Kn9mx5pnzHRQO8+Wixmh88YdZRiIwat0iNzNNXn0yoEtXJqFpyW7eM8BV7g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20.18.1" + } }, "node_modules/union": { "version": "0.5.0", @@ -7249,10 +7675,10 @@ } }, "node_modules/universalify": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", - "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", - "dev": true, + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "license": "MIT", "engines": { "node": ">= 10.0.0" } @@ -7262,8 +7688,36 @@ "resolved": "https://registry.npmjs.org/unxhr/-/unxhr-1.0.1.tgz", "integrity": "sha512-MAhukhVHyaLGDjyDYhy8gVjWJyhTECCdNsLwlMoGFoNJ3o79fpQhtQuzmAE4IxCMDwraF4cW8ZjpAV0m9CRQbg==", "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.11" + } + }, + "node_modules/unzipper": { + "version": "0.12.3", + "resolved": "https://registry.npmjs.org/unzipper/-/unzipper-0.12.3.tgz", + "integrity": "sha512-PZ8hTS+AqcGxsaQntl3IRBw65QrBI6lxzqDEL7IAo/XCEqRTKGfOX56Vea5TH9SZczRVxuzk1re04z/YjuYCJA==", + "license": "MIT", + "dependencies": { + "bluebird": "~3.7.2", + "duplexer2": "~0.1.4", + "fs-extra": "^11.2.0", + "graceful-fs": "^4.2.2", + "node-int64": "^0.4.0" + } + }, + "node_modules/unzipper/node_modules/fs-extra": { + "version": "11.3.2", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.2.tgz", + "integrity": "sha512-Xr9F6z6up6Ws+NjzMCZc6WXg2YFRlrLP9NQDO3VQrWrfiojdhS56TzueT88ze0uBdCTwEIhQ3ptnmKeWGFAe0A==", + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, "engines": { - "node": ">=8.11" + "node": ">=14.14" } }, "node_modules/uri-js": { @@ -7271,6 +7725,7 @@ "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "punycode": "^2.1.0" } @@ -7279,42 +7734,40 @@ "version": "1.19.11", "resolved": "https://registry.npmjs.org/urijs/-/urijs-1.19.11.tgz", "integrity": "sha512-HXgFDgDommxn5/bIv0cnQZsPhHDA90NPHD6+c/v21U5+Sx5hoP8+dP9IZXBU1gIfvdRfhG8cel9QNPeionfcCQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/url-join": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/url-join/-/url-join-4.0.1.tgz", "integrity": "sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA==", - "dev": true + "license": "MIT" }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" - }, - "node_modules/util-extend": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/util-extend/-/util-extend-1.0.3.tgz", - "integrity": "sha512-mLs5zAK+ctllYBj+iAQvlDCwoxU/WDOUaJkcFudeiAX6OajC6BKXJUa9a+tbtkC11dz2Ufb7h0lyvIOVn4LADA==", - "dev": true + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "license": "MIT" }, "node_modules/uuid": { "version": "8.3.2", "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "license": "MIT", "bin": { "uuid": "dist/bin/uuid" } }, "node_modules/v8-to-istanbul": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.0.1.tgz", - "integrity": "sha512-74Y4LqY74kLE6IFyIjPtkSTWzUZmj8tdHT9Ii/26dvQ6K9Dl2NbEfj0XgU2sHCtKgt5VupqhlO/5aWuqS+IY1w==", + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz", + "integrity": "sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==", "dev": true, + "license": "ISC", "dependencies": { "@jridgewell/trace-mapping": "^0.3.12", "@types/istanbul-lib-coverage": "^2.0.1", - "convert-source-map": "^1.6.0" + "convert-source-map": "^2.0.0" }, "engines": { "node": ">=10.12.0" @@ -7325,29 +7778,22 @@ "resolved": "https://registry.npmjs.org/valid-data-url/-/valid-data-url-3.0.1.tgz", "integrity": "sha512-jOWVmzVceKlVVdwjNSenT4PbGghU0SBIizAev8ofZVgivk/TVHXSbNL8LP6M3spZvkR9/QolkyJavGSX5Cs0UA==", "dev": true, + "license": "MIT", "engines": { "node": ">=10" } }, - "node_modules/validate-npm-package-license": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", - "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", - "dev": true, - "dependencies": { - "spdx-correct": "^3.0.0", - "spdx-expression-parse": "^3.0.0" - } - }, "node_modules/varint": { "version": "5.0.2", "resolved": "https://registry.npmjs.org/varint/-/varint-5.0.2.tgz", - "integrity": "sha512-lKxKYG6H03yCZUpAGOPOsMcGxd1RHCu1iKvEHYDPmTyq2HueGhD73ssNBqqQWfvYs04G9iUFRvmAVLW20Jw6ow==" + "integrity": "sha512-lKxKYG6H03yCZUpAGOPOsMcGxd1RHCu1iKvEHYDPmTyq2HueGhD73ssNBqqQWfvYs04G9iUFRvmAVLW20Jw6ow==", + "license": "MIT" }, "node_modules/varuint-bitcoin": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/varuint-bitcoin/-/varuint-bitcoin-1.1.2.tgz", "integrity": "sha512-4EVb+w4rx+YfVM32HQX42AbbT7/1f5zwAYhIujKXKk8NQK+JfRVl3pqT3hjNn/L+RstigmGGKVwHA/P0wgITZw==", + "license": "MIT", "dependencies": { "safe-buffer": "^5.1.1" } @@ -7356,21 +7802,28 @@ "version": "1.10.0", "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", "integrity": "sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==", - "dev": true, "engines": [ "node >=0.6.0" ], + "license": "MIT", "dependencies": { "assert-plus": "^1.0.0", "core-util-is": "1.0.2", "extsprintf": "^1.2.0" } }, + "node_modules/verror/node_modules/core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==", + "license": "MIT" + }, "node_modules/walk-back": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/walk-back/-/walk-back-5.1.0.tgz", - "integrity": "sha512-Uhxps5yZcVNbLEAnb+xaEEMdgTXl9qAQDzKYejG2AZ7qPwRQ81lozY9ECDbjLPNWm7YsO1IK5rsP1KoQzXAcGA==", + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/walk-back/-/walk-back-5.1.1.tgz", + "integrity": "sha512-e/FRLDVdZQWFrAzU6Hdvpm7D7m2ina833gIKLptQykRK49mmCYHLHq7UqjPDbxbKLZkTkW1rFqbengdE3sLfdw==", "dev": true, + "license": "MIT", "engines": { "node": ">=12.17" } @@ -7380,6 +7833,7 @@ "resolved": "https://registry.npmjs.org/web-resource-inliner/-/web-resource-inliner-6.0.1.tgz", "integrity": "sha512-kfqDxt5dTB1JhqsCUQVFDj0rmY+4HLwGQIsLPbyrsN9y9WV/1oFDSx3BQ4GfCv9X+jVeQ7rouTqwK53rA/7t8A==", "dev": true, + "license": "MIT", "dependencies": { "ansi-colors": "^4.1.1", "escape-goat": "^3.0.0", @@ -7397,6 +7851,7 @@ "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==", "dev": true, + "license": "MIT", "dependencies": { "domelementtype": "^2.0.1", "domhandler": "^4.2.0", @@ -7411,6 +7866,7 @@ "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "domelementtype": "^2.2.0" }, @@ -7426,6 +7882,7 @@ "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-3.3.0.tgz", "integrity": "sha512-J1C5rIANUbuYK+FuFL98650rihynUOEzRLxW+90bKZRWB6A1X1Tf82GxR1qAWLyfNPRvjqfip3Q5tdYlmAa9lA==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "domelementtype": "^2.0.1" }, @@ -7441,6 +7898,7 @@ "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "dom-serializer": "^1.0.1", "domelementtype": "^2.2.0", @@ -7455,6 +7913,7 @@ "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "domelementtype": "^2.2.0" }, @@ -7470,6 +7929,7 @@ "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", "dev": true, + "license": "BSD-2-Clause", "funding": { "url": "https://github.com/fb55/entities?sponsor=1" } @@ -7479,6 +7939,7 @@ "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-5.0.1.tgz", "integrity": "sha512-vKZZra6CSe9qsJzh0BjBGXo8dvzNsq/oGvsjfRdOrrryfeD9UOBEEQdeoqCRmKZchF5h2zOBMQ6YuQ0uRUmdbQ==", "dev": true, + "license": "MIT", "dependencies": { "domelementtype": "^2.0.1", "domhandler": "^3.3.0", @@ -7494,6 +7955,7 @@ "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==", "dev": true, + "license": "MIT", "bin": { "mime": "cli.js" }, @@ -7504,13 +7966,15 @@ "node_modules/webidl-conversions": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "license": "BSD-2-Clause" }, "node_modules/websocket-driver": { "version": "0.7.4", "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==", "dev": true, + "license": "Apache-2.0", "dependencies": { "http-parser-js": ">=0.5.1", "safe-buffer": ">=5.1.0", @@ -7525,68 +7989,133 @@ "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz", "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==", "dev": true, + "license": "Apache-2.0", "engines": { "node": ">=0.8.0" } }, "node_modules/whatwg-encoding": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-2.0.0.tgz", - "integrity": "sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz", + "integrity": "sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==", "dev": true, + "license": "MIT", "dependencies": { "iconv-lite": "0.6.3" }, "engines": { - "node": ">=12" + "node": ">=18" } }, - "node_modules/whatwg-encoding/node_modules/iconv-lite": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", - "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "node_modules/whatwg-mimetype": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz", + "integrity": "sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==", "dev": true, - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - }, + "license": "MIT", "engines": { - "node": ">=0.10.0" + "node": ">=18" } }, "node_modules/whatwg-url": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "license": "MIT", "dependencies": { "tr46": "~0.0.3", "webidl-conversions": "^3.0.0" } }, "node_modules/which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", - "dev": true, + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "license": "ISC", "dependencies": { "isexe": "^2.0.0" }, "bin": { - "which": "bin/which" + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/which-typed-array": { + "version": "1.1.19", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.19.tgz", + "integrity": "sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw==", + "license": "MIT", + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "for-each": "^0.3.5", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/wide-align": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", + "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", + "license": "ISC", + "dependencies": { + "string-width": "^1.0.2 || 2 || 3 || 4" } }, "node_modules/wif": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/wif/-/wif-2.0.6.tgz", "integrity": "sha512-HIanZn1zmduSF+BQhkE+YXIbEiH0xPr1012QbFEGB0xsKqJii0/SqJjyn8dFv6y36kOznMgMB+LGcbZTJ1xACQ==", + "license": "MIT", "dependencies": { "bs58check": "<3.0.0" } }, + "node_modules/wif/node_modules/base-x": { + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.11.tgz", + "integrity": "sha512-xz7wQ8xDhdyP7tQxwdteLYeFfS68tSMNCZ/Y37WJ4bhGfKPpqEIlmIyueQHqOyoPhE6xNUqjzRr8ra0eF9VRvA==", + "license": "MIT", + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, + "node_modules/wif/node_modules/bs58": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/bs58/-/bs58-4.0.1.tgz", + "integrity": "sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw==", + "license": "MIT", + "dependencies": { + "base-x": "^3.0.2" + } + }, + "node_modules/wif/node_modules/bs58check": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/bs58check/-/bs58check-2.1.2.tgz", + "integrity": "sha512-0TS1jicxdU09dwJMNZtVAfzPi6Q6QeN0pM1Fkzrjn+XYHvzMKPU3pHVpva+769iNVSfIYWf7LJ6WR+BuuMf8cA==", + "license": "MIT", + "dependencies": { + "bs58": "^4.0.0", + "create-hash": "^1.1.0", + "safe-buffer": "^5.1.2" + } + }, "node_modules/word-wrap": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", - "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -7595,41 +8124,32 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==", - "dev": true - }, - "node_modules/wordwrapjs": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/wordwrapjs/-/wordwrapjs-3.0.0.tgz", - "integrity": "sha512-mO8XtqyPvykVCsrwj5MlOVWvSnCdT+C+QVbm6blradR7JExAhbkZ7hZ9A+9NUtwzSqrlUo9a67ws0EiILrvRpw==", "dev": true, - "dependencies": { - "reduce-flatten": "^1.0.1", - "typical": "^2.6.1" - }, - "engines": { - "node": ">=4.0.0" - } + "license": "MIT" }, - "node_modules/wordwrapjs/node_modules/reduce-flatten": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/reduce-flatten/-/reduce-flatten-1.0.1.tgz", - "integrity": "sha512-j5WfFJfc9CoXv/WbwVLHq74i/hdTUpy+iNC534LxczMRP67vJeK3V9JOdnL0N1cIRbn9mYhE2yVjvvKXDxvNXQ==", + "node_modules/wordwrapjs": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/wordwrapjs/-/wordwrapjs-5.1.1.tgz", + "integrity": "sha512-0yweIbkINJodk27gX9LBGMzyQdBDan3s/dEAiwBOj+Mf0PPyWL6/rikalkv8EeD0E8jm4o5RXEOrFTP3NXbhJg==", "dev": true, + "license": "MIT", "engines": { - "node": ">=0.10.0" + "node": ">=12.17" } }, "node_modules/workerpool": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.1.tgz", - "integrity": "sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==", - "dev": true + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.5.1.tgz", + "integrity": "sha512-Fs4dNYcsdpYSAfVxhnl1L5zTksjvOJxtC5hzMNl+1t9B8hTJTdKDyZ5ju7ztgPy+ft9tBFXoOlDNiOT9WUXZlA==", + "dev": true, + "license": "Apache-2.0" }, "node_modules/wrap-ansi": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", @@ -7642,93 +8162,37 @@ "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, - "node_modules/wrap-ansi/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/wrap-ansi/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", "dev": true, + "license": "MIT", "dependencies": { - "color-convert": "^2.0.1" + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" }, "engines": { - "node": ">=8" + "node": ">=10" }, "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/wrap-ansi/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/wrap-ansi/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/wrap-ansi/node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/wrap-ansi/node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/wrap-ansi/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "license": "ISC" }, "node_modules/write": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/write/-/write-1.0.3.tgz", "integrity": "sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig==", "dev": true, + "license": "MIT", "dependencies": { "mkdirp": "^0.5.1" }, @@ -7741,6 +8205,7 @@ "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", "dev": true, + "license": "MIT", "dependencies": { "minimist": "^1.2.6" }, @@ -7749,9 +8214,10 @@ } }, "node_modules/ws": { - "version": "7.5.9", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz", - "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==", + "version": "7.5.10", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz", + "integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==", + "license": "MIT", "engines": { "node": ">=8.3.0" }, @@ -7772,12 +8238,14 @@ "version": "2.0.4", "resolved": "https://registry.npmjs.org/xmlcreate/-/xmlcreate-2.0.4.tgz", "integrity": "sha512-nquOebG4sngPmGPICTS5EnxqhKbCmz5Ox5hsszI2T6U5qdrJizBc+0ilYSEjTSzU0yZcmvppztXe/5Al5fUwdg==", - "dev": true + "dev": true, + "license": "Apache-2.0" }, "node_modules/xtend": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "license": "MIT", "engines": { "node": ">=0.4" } @@ -7787,41 +8255,44 @@ "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", "dev": true, + "license": "ISC", "engines": { "node": ">=10" } }, "node_modules/yallist": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", - "integrity": "sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==", - "dev": true + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "license": "ISC" }, "node_modules/yargs": { - "version": "16.2.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", - "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", "dev": true, + "license": "MIT", "dependencies": { - "cliui": "^7.0.2", + "cliui": "^8.0.1", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", - "string-width": "^4.2.0", + "string-width": "^4.2.3", "y18n": "^5.0.5", - "yargs-parser": "^20.2.2" + "yargs-parser": "^21.1.1" }, "engines": { - "node": ">=10" + "node": ">=12" } }, "node_modules/yargs-parser": { - "version": "20.2.9", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", - "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", "dev": true, + "license": "ISC", "engines": { - "node": ">=10" + "node": ">=12" } }, "node_modules/yargs-unparser": { @@ -7829,6 +8300,7 @@ "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", "dev": true, + "license": "MIT", "dependencies": { "camelcase": "^6.0.0", "decamelize": "^4.0.0", @@ -7839,55 +8311,12 @@ "node": ">=10" } }, - "node_modules/yargs/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/yargs/node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/yargs/node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/yargs/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/yocto-queue": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", "dev": true, + "license": "MIT", "engines": { "node": ">=10" }, @@ -7896,22 +8325,19 @@ } }, "node_modules/zeromq": { - "version": "5.2.8", - "resolved": "https://registry.npmjs.org/zeromq/-/zeromq-5.2.8.tgz", - "integrity": "sha512-bXzsk7KOmgLSv1tC0Ms1VXBy90+Rz27ZYf27cLuldRYbpqYpuWJfxxHFhO710t22zgWBnmdUP0m3SKFpLI0u5g==", + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/zeromq/-/zeromq-6.3.0.tgz", + "integrity": "sha512-PG61AT4Y37NGJHSrp5SG2m4cKtRirso/5mm4Yf7l+upgNZZAugrGdhENsM5IcLS+WVVzbWVjEsLKpgLj/31SWQ==", "hasInstallScript": true, + "license": "MIT AND MPL-2.0", "dependencies": { - "nan": "2.14.2", - "node-gyp-build": "^4.2.3" + "@aminya/cmake-ts": "^0.3.0-aminya.7", + "node-addon-api": "^8.3.0" }, "engines": { - "node": ">=6.0" + "node": ">= 10", + "pnpm": ">= 9" } - }, - "node_modules/zeromq/node_modules/nan": { - "version": "2.14.2", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.2.tgz", - "integrity": "sha512-M2ufzIiINKCuDfBSAUr1vWQ+vuVcA9kqx8JJUsbQi6yf1uGRyb7HfpdfUr5qLXf3B/t8dPvcjhKMmlfnP47EzQ==" } } } diff --git a/package.json b/package.json index 62de5aa2a..7562a6dae 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,8 @@ "version": "0.1.0-RC1", "description": "Experimental peer-to-peer framework.", "main": "types/fabric.js", - "module": "index.js", + "module": "types/fabric.mjs", + "types": "types/fabric.d.ts", "bin": { "fabric": "scripts/cli.js" }, @@ -13,7 +14,7 @@ "test": "tests" }, "engines": { - "node": "16.17.1" + "node": "22.14.0" }, "scripts": { "audit": "npm audit --json --level critical > reports/AUDIT.json", @@ -31,6 +32,8 @@ "examples": "npm run make:examples && http-server -p 8000 examples", "keygen": "node scripts/keygen.js", "lint:fix": "npx semistandard --fix", + "lint:types": "npx semistandard types/**/*.js", + "lint:types:fix": "npx semistandard --fix types/**/*.js", "lint": "npx semistandard", "local": "npm run build && http-server -p 8000 ./assets", "make:all": "npm run make:service && npm run make:app && npm run make:lib && npm run make:dev # && npm run make:binary", @@ -39,18 +42,18 @@ "make:binary": "pkg -c package.json -o assets/binaries/fabric scripts/cli.js", "make:book": "mkdir -p _book && honkit build", "make:coverage": "npm run coverage && c8 report --reporter html", - "make:dev": "npm run make:examples && npm run make:docs && npm run make:book && cp -rf docs _book/ && cp -rf examples _book/ && glob-run js-beautify --indent-size 2 -r _book/**.html", - "make:docs": "npm run make:api && node_modules/.bin/jsdoc -c jsdoc.json services/**.js types/**.js settings/deprecations.js DEVELOPERS.md -d docs/ && glob-run js-beautify --indent-size 2 -r docs/**.html", - "make:examples": "./node_modules/.bin/docco --output assets examples/*.js && ./node_modules/.bin/glob-run ./node_modules/.bin/js-beautify --indent-size 2 -r assets/examples/*.html", + "make:dev": "npm run make:examples && npm run make:docs && npm run make:book && cp -rf docs _book/ && cp -rf examples _book/ && js-beautify --indent-size 2 -r _book/**.html", + "make:docs": "npm run make:api && node_modules/.bin/jsdoc -c jsdoc.json services/**.js types/**.js settings/deprecations.js DEVELOPERS.md -d docs/ && js-beautify --indent-size 2 -r docs/**.html", + "make:examples": "docco --output assets examples/*.js && ./node_modules/.bin/js-beautify --indent-size 2 -r assets/examples/*.html", "make:lib": "### ERROR: Not yet implemented. Debug: `scripts/fabric.js` to `assets/fabric.min.js`", "make:nix": "node2nix --lock package-lock.json --nodejs-16 --node-env .nix/node-env.nix --output .nix/node-packages.nix", "make:service": "### ERROR: Not yet implemented. Debug: ` examples/service.js` to `assets/service.js`", "make:viewer": "### ERROR: Not yet implemented. Debug: `components/circuit-viewer.js` to `assets/viewer.min.js`", "playnet": "node scripts/playnet.js", "report:coverage": "npm run make:coverage && c8 report --reporter=text-lcov > reports/coverage.lcov", - "report:credits": "node_modules/.bin/license-checker --json > reports/credits.json", + "report:credits": "license-checker --json > reports/credits.json", "report:install": "rm -rf node_modules && echo \"\n\" > package-lock.json && echo \"$ npm i\" > reports/install.log && npm i >> reports/install.log", - "report:legal": "node_modules/.bin/license-checker --json > reports/licenses.json", + "report:legal": "license-checker --json > reports/licenses.json", "report:todo": "grep --exclude-dir=.git --exclude-dir=_book --exclude-dir=assets --exclude-dir=node_modules --exclude-dir=reports --exclude-dir=coverage --exclude-dir=docs -rEI \"TODO|FIXME\" . > reports/TODO.txt", "reports": "npm run report:install && npm run make:coverage && npm run report:todo", "review:coverage": "npm run make:coverage && http-server -p 8000 reports/coverage", @@ -60,8 +63,8 @@ "test:app": "npm run make:service && npm run make:app && NODE_ENV=test mocha tests/fabric.app.js", "test:bitcoin": "mocha tests/bitcoin.core.js", "test:wasm": "emcc contracts/test.c -o assets/wasm.html", - "test": "NODE_ENV=test mocha tests", - "tidy": "glob-run js-beautify --indent-size 2 -r _book/**.html", + "test": "NODE_ENV=test mocha --recursive tests -- --serial", + "tidy": "js-beautify --indent-size 2 -r _book/**.html", "watch:book": "honkit serve --port 8000 # NOTE: /docs and /examples may not be available." }, "repository": { @@ -83,59 +86,59 @@ }, "homepage": "https://github.com/FabricLabs/fabric#readme", "dependencies": { - "arbitrary": "1.4.10", - "base58check": "2.0.0", - "bech32-buffer": "0.2.0", - "bip-schnorr": "0.6.6", - "bip32": "3.0.1", - "bip39": "3.0.4", - "bip65": "1.0.3", - "bip68": "1.0.4", - "bitcoinjs-lib": "6.0.0", - "blessed": "0.1.81", - "commander": "6.1.0", - "content-type": "1.0.4", - "cross-fetch": "3.1.5", - "dotparser": "0.3.0", - "ecpair": "2.0.1", - "elliptic": "6.5.4", - "fast-json-patch": "3.1.1", - "javascript-state-machine": "3.1.0", - "jayson": "4.0.0", - "json-pointer": "0.6.2", - "level": "7.0.1", - "lodash.merge": "4.6.2", - "merkletreejs": "0.1.6", - "minsc": "0.2.0", - "mkdirp": "1.0.4", - "noise-protocol-stream": "1.1.3", - "path-match": "1.2.4", - "pluralize": "8.0.0", - "redis": "3.1.2", - "rimraf": "2.6.2", - "simple-aes": "0.1.1", - "struct": "0.0.12", - "tiny-secp256k1": "2.2.1", - "zeromq": "5.2.8" + "arbitrary": "=1.4.10", + "bech32-buffer": "=0.2.1", + "bip-schnorr": "=0.6.7", + "bip32": "=4.0.0", + "bip39": "=3.1.0", + "bip65": "=1.0.3", + "bip68": "=1.0.4", + "bitcoinjs-lib": "=6.1.7", + "blessed": "=0.1.81", + "bn.js": "=5.2.1", + "commander": "=13.1.0", + "content-type": "=1.0.5", + "cross-fetch": "=4.1.0", + "dotparser": "=1.1.1", + "ecpair": "=2.1.0", + "elliptic": "=6.6.1", + "events": "=3.3.0", + "fast-json-patch": "=3.1.1", + "javascript-state-machine": "=3.1.0", + "jayson": "=4.1.3", + "json-pointer": "=0.6.2", + "jsonpointer": "=5.0.1", + "level": "=9.0.0", + "lodash.merge": "=4.6.2", + "macaroon": "=3.0.4", + "merkletreejs": "=0.4.1", + "minsc": "=0.2.0", + "mkdirp": "=3.0.1", + "noise-protocol-stream": "=1.1.3", + "path-match": "=1.2.4", + "pluralize": "=8.0.0", + "redis": "=4.7.0", + "simple-aes": "=0.1.1", + "struct": "=0.0.12", + "tiny-secp256k1": "=2.2.3", + "zeromq": "=6.3.0" }, "devDependencies": { - "c8": "7.11.3", - "chai": "4.0.2", - "cross-env": "5.1.3", - "debug-trace": "2.2.1", - "docco": "0.9.1", - "eccrypto": "1.0.3", - "eslint": "5.16.0", - "glob-run": "0.1.7", - "honkit": "4.0.4", - "http-server": "14.1.1", - "is-my-json-valid": "2.20.6", - "js-beautify": "1.14.3", - "jsdoc": "3.6.11", - "jsdoc-to-markdown": "7.1.1", - "json-to-dot": "1.1.0", - "license-checker": "25.0.1", - "mocha": "10.0.0" + "buffer": "=6.0.3", + "c8": "=10.1.3", + "chai": "=4.0.2", + "cross-env": "=7.0.3", + "debug-trace": "=2.2.3", + "docco": "=0.9.1", + "eslint": "=9.19.0", + "honkit": "=6.0.2", + "http-server": "=14.1.1", + "is-my-json-valid": "=2.20.6", + "js-beautify": "=1.15.1", + "jsdoc": "=4.0.4", + "jsdoc-to-markdown": "=9.1.1", + "json-to-dot": "=1.1.0", + "mocha": "=11.1.0" }, "c8": { "exclude": [ @@ -151,10 +154,10 @@ }, "pkg": { "@targets": [ - "node16-linux-arm64", - "node16-linux-x64", - "node16-macos-x64", - "node16-windows-x64" + "node18-linux-arm64", + "node18-linux-x64", + "node18-macos-x64", + "node18-windows-x64" ] }, "semistandard": { @@ -163,5 +166,26 @@ "logs/", "stores/" ] + }, + "exports": { + ".": { + "require": "./types/fabric.js", + "import": "./types/fabric.mjs" + }, + "./constants": { + "require": "./constants.js" + }, + "./fixtures": { + "require": "./fixtures.js" + }, + "./types/*": { + "require": "./types/*.js" + }, + "./services/*": { + "require": "./services/*.js" + }, + "./functions/*": { + "require": "./functions/*.js" + } } } diff --git a/reports/TODO.txt b/reports/TODO.txt index 27367fb64..da3f9e553 100644 --- a/reports/TODO.txt +++ b/reports/TODO.txt @@ -10,12 +10,9 @@ ./constants.js:// TODO: should be 0x02 for Bitcoin P2P ./snippets/specification.md:// TODO: migrate script ./settings/local.js:// TODO: test env variables with OP_TEST -./settings/local.js: // TODO: replace with `key` Object({ seed, xprv, xpub }) -./settings/local.js: // TODO: derive from `key` property ./settings/local.js: // TODO: regtest, playnet, signet, testnet, mainnet (in order) ./settings/local.js: // TODO: test `true` ./settings/default.json: "@comment": "// TODO: remove routes, add by default", -./SETTINGS.md:### WARNING: TODO ./types/witness.js: // TODO: assign R coordinate ./types/witness.js: // TODO: assign S coordinate ./types/channel.js: // TODO: remove short-circuit @@ -23,10 +20,10 @@ ./types/interface.js: // TODO: use Layer ./types/interface.js: // TODO: document why @input is removed ./types/interface.js: // TODO: apply `transaction.operations` to Interface state +./types/filesystem.js: // TODO: only sync changed files ./types/scribe.js: // TODO: enable ./types/key.js:// TODO: remove ./types/key.js:// TODO: remove all external dependencies -./types/key.js: // TODO: design state machine for input (configuration) ./types/key.js: // TODO: determine if this makes sense / needs to be private ./types/key.js: // TODO: evaluate compression when treating seed phrase as ascii ./types/key.js: // TODO: consider using sha256(masterprivkey) or sha256(sha256(...))? @@ -65,9 +62,8 @@ ./types/service.js: // TODO: use Resource definition to de-deuplicate by fields.id ./types/service.js: // TODO: reduce storage to references ./types/service.js: // TODO: implement a basic Stream -./types/service.js: // TODO: add robust + convenient database opener -./types/service.js: // TODO: notify status? ./types/service.js: // TODO: allow configurable validators +./types/service.js: // TODO: invalidate changes without appropriate capability token ./types/service.js: // TODO: update this in constructor ./types/service.js: // TODO: re-evaluate inclusion on Service itself ./types/service.js: // TODO: evaluate @fabric/core/types/store @@ -98,14 +94,15 @@ ./types/compiler.js: // TODO: @melnx to refactor into f(x) => y ./types/vector.js: // TODO: standardize on a serialization format ./types/vector.js: // TODO: standardize on a serialization format +./types/token.js: // TODO: determine rounding preference (secwise) +./types/token.js: // TODO: determine rounding preference (secwise) +./types/token.js: // TODO: reconcile with JWT spec ./types/circuit.js: // TODO: generate polynomial for circuit -./types/signer.js: // TODO: fix bcoin in React / WebPack -./types/signer.js: this.value = this._readObject(actor); // TODO: use Buffer? -./types/signer.js: // TODO: use pubkey -./types/signer.js: // TODO: encode pubkey correctly for verification -./types/signer.js: // TODO: check with bip-schnorr on behavior of signing > 32 byte messages -./types/signer.js: // TODO: unpause input stream here -./types/bitcoin/block.js: // TODO: validation +./types/contract.js: // TODO: parse on-chain transaction for update to contract balance +./types/bitcoin/transaction.js:// TODO: PSBTs +./types/bitcoin/transaction.js: return ''; // TODO: real hash +./types/bitcoin/transaction.js: return ''; // TODO: Fabric ID +./types/bitcoin/transaction.js: return ''; // TODO: bitcoin txid ./types/hash256.js: // TODO: document `hash256.value` ./types/bond.js: content: Buffer.alloc(4) // TODO: Bitcoin encoded values? ./types/actor.js: // TODO: encourage use of `state` over `_state` @@ -123,11 +120,8 @@ ./types/router.js:// TODO: re-define this class for Fabric messages ./types/router.js: // TODO: remove this.fabric.plugins call ./types/mempool.js: // TODO: compare target.id and entity.id -./types/wallet.js: // TODO: enable wordlist translations -./types/wallet.js: // TODO: remove these ./types/wallet.js: // TODO: export this.logs ./types/wallet.js: // TODO: reduce to C mem equivalent -./types/wallet.js: // TODO: new Key() here, then use key.export() ./types/wallet.js: // TODO: bind @fabric/core/services/bitcoin to addresses on wallet... ./types/wallet.js: // TODO: update channels ./types/wallet.js: // TODO: parse as {@link Message} @@ -140,29 +134,13 @@ ./types/wallet.js: // TODO: use the MTX to select outputs ./types/wallet.js: // TODO: use Fabric.Script ./types/wallet.js: // TODO: remove short-circuit -./types/wallet.js: // TODO: complete order construction -./types/wallet.js: // TODO: should be split parts -./types/wallet.js: // TODO: remove short-circuit ./types/wallet.js: // TODO: replace this with a randomly-generated input ./types/wallet.js: // TODO: remove short-circuit ./types/wallet.js: // TODO: complete order construction ./types/wallet.js: // TODO: should be split parts ./types/wallet.js: // TODO: labeled keypairs ./types/wallet.js: rate: 10000, // TODO: fee calculation -./types/wallet.js: // TODO: labeled keypairs -./types/wallet.js: rate: 10000, // TODO: fee calculation -./types/wallet.js: // TODO: return a full object for Fabric ./types/wallet.js: // TODO: restore swap code, abstract input types -./types/wallet.js: // TODO: use Satoshis for all calculations -./types/wallet.js: // TODO: remove all fake coinbases -./types/wallet.js: // TODO: remove all short-circuits -./types/wallet.js: // TODO: remove short-circuit -./types/wallet.js: // TODO: remove entirely, test short-circuit removal -./types/wallet.js: // TODO: wallet._getSpendableOutput() -./types/wallet.js: // TODO: load available outputs from wallet -./types/wallet.js: // TODO: fee estimation -./types/wallet.js: // TODO: fee estimation -./types/wallet.js: // TODO: load available outputs from wallet ./types/wallet.js: // TODO: fee estimation ./types/wallet.js: // TODO: restore address tracking in state ./types/wallet.js: // TODO: check on above events, should be more like... @@ -176,9 +154,9 @@ ./types/cli.js:const pointer = require('json-pointer'); // TODO: move uses to App ./types/cli.js:const monitor = require('fast-json-patch'); // TODO: move uses to App ./types/cli.js:// TODO: use Jade to render pre-registered components -./types/cli.js: mode: 'rpc', // TODO: change name of mode to `rest`? ./types/cli.js: // TODO: ZMQ ./types/cli.js: // TODO: enable +./types/cli.js: // TODO: sign ./types/cli.js: // TODO: create payment channel (@fabric/core/types/channel) ./types/cli.js: // TODO: exit function here ./types/cli.js: // TODO: use @fabric/core/types/channel @@ -192,39 +170,15 @@ ./types/consensus.js: // TODO: remove from {@link Consensus} ./types/consensus.js: // TODO: compute from chain height ./types/machine.js: seed: 1, // TODO: select seed for production -./types/peer.js: // TODO: parse as encrypted data ./types/peer.js: // TODO: switch to child pubkey -./types/peer.js: // TODO: use Proxy -./types/peer.js: // TODO: notify remote peer of closure -./types/peer.js: // TODO: use in _connect -./types/peer.js: // TODO: evaluate trust model -./types/peer.js: // TODO: consolidate with similar _handleConnection segment -./types/peer.js: // TODO: check peer ID, eject if self or known -./types/peer.js: // TODO re-enable (disabled to reduce spammy messaging) -./types/peer.js: // TODO: re-evaluate use of IdentityRequest -./types/peer.js: // TODO: actually decrypt packet -./types/peer.js: // TODO: refactor to use local functions + specific unbindings -./types/peer.js: // TODO: consolidate with this._handleConnection -./types/peer.js: // TODO: consider using `process.nextTick` to only clean up after event? -./types/peer.js: // TODO: unify as _dataHandler -./types/peer.js: // TODO: replace with handshake -./types/peer.js: // TODO: use known key -./types/peer.js: // TODO: document peer announcement -./types/peer.js: // TODO: eliminate use of JSON in messaging -./types/peer.js: // TODO: remove in favor of StartSession -./types/peer.js: // TODO: use packet's peer ID, not socket address -./types/peer.js: // TODO: avoid using JSON in overall protocol -./types/peer.js: // TODO: validate signature -./types/peer.js: // TODO: restore session identity -./types/peer.js: // TODO: document peer registration process -./types/peer.js: // TODO: use message type for next phase of session (i.e., NOISE) -./types/peer.js: // TODO: test protocol flow (i.e., understand StateRoot) -./types/peer.js: // TODO: use Fabric.Script / Fabric.Machine -./types/peer.js: // TODO: select type byte for state updates -./types/peer.js: // TODO: require `Message` type before broadcast (or, preferrably, cast as necessary) -./types/peer.js: // TODO: select type byte for state updates -./types/peer.js: // TODO: require `Message` type before broadcast (or, preferrably, cast as necessary) -./types/peer.js: // TODO: select type byte for state updates +./types/peer.js: // TODO: consider making this a FabricMessageID +./types/peer.js: // TODO: output stream +./types/peer.js: // TODO: remove this assumption (validate above) +./types/peer.js: // TODO: check for existing peer, update instead of replace +./types/peer.js: // TODO: ensure no pong is handled when a ping was not previously sent +./types/peer.js: // TODO: reject and punish mis-behaving peers +./types/peer.js: // TODO: reject and punish mis-behaving peers +./types/peer.js: // TODO: reconcile APIs for these methods ./types/entity.js: // TODO: use getters/setters to restrict access to these elements ./types/entity.js: // TODO: write up longer-form explanation as to why we use an Array here ./types/collection.js: // TODO: document `listeners` handler (currently only `create`) @@ -243,15 +197,10 @@ ./types/app.js: // TODO: debug these in browser ./types/app.js: // TODO: debug this in browser ./types/app.js: // TODO: decide on resource['@data'] vs. resource (new) -./types/layer.js: // TODO: describe state-passing for key ./types/environment.js: // TODO: encrypt inner store with password (`object` property) -./types/noise.js: // TODO: The returned value is the SHA256 of the compressed format of the generated point. -./types/noise.js: // TODO: NOISE Protocol Act 1 -./types/noise.js: c.destroy(); // TODO: test various network conditions (safe closure vs. network interruption) ./types/stack.js: // TODO: return Transaction ./API.md:TODO: move to @fabric/http/types/spa ./API.md:TODO: move to @fabric/http/types/spa -./API.md:TODO: move to @fabric/http/types/spa ./SUMMARY.md:* [✅ TODO List][todo] ./SUMMARY.md:[todo]: TODO.md ./fabric-whitepaper.md:### TODO: include content hashes of links as they appear at document compilation time. @@ -259,24 +208,22 @@ ./contracts/node.js: // TODO: configure with input? ./contracts/setup.js.bak: // TODO: discuss w/ @ChronicSmoke ./contracts/setup.js.bak: // TODO: use in walletExists -./contracts/federation.js: // TODO: get signatures +./contracts/fabric.c: // TODO: emit the message object ./contracts/setup.js: // TODO: replicate this program in C / ASM ./contracts/setup.js: // TODO: remove from log output... ./contracts/chat.js: const chat = new CLI(settings); // TODO: this.settings +./contracts/chat.js: // TODO: remove, re-work Peer and Wallet key import in CLI ./contracts/chat.js: // TODO: reconcile API wth @fabric/doorman as appears at: https://github.com/FabricLabs/doorman ./tests/fabric.interface.js: // TODO: remove this case / rework messages ./tests/fabric.tree.js: assert.strictEqual(tree.root.toString('hex'), ''); // TODO: wat? ./tests/fabric.tree.js: assert.strictEqual(tree.root.toString('hex'), '906b5aaf65ae98f8c98848de5e81ba865659f16fd53aefa4c78b34176f068079'); // TODO: wat? -./tests/fabric.key.js: // TODO: test against BIP_84_TEST_VECTOR_ZPRV ./tests/fabric.core.js:// TODO: write parser for comments ./tests/fabric.core.js: // TODO: implement polyfill for browserland -./tests/fabric.weave.js: assert.strictEqual(weave._state.root, '906b5aaf65ae98f8c98848de5e81ba865659f16fd53aefa4c78b34176f068079'); // TODO: wat? ./tests/fabric.machine.js: // TODO: use Fabric itself ./tests/fabric.machine.js: // TODO: use Fabric instead of Machine ./tests/fabric.router.js:// TODO: test class/function middleware ./tests/fabric.stack.js: // TODO: move to constants, verify ./tests/fabric.stack.js: // TODO: migrate to Stack -./tests/fabric.wallet.js: // TODO: replace with fixture ./tests/fixtures/lightning.js:// TODO: test same as before ./DEVELOPERS.md:All agreements in Fabric are represented as well-formed descriptions of **Resources**[TODO: link here] — a term we use to describe a standardized service a peer might offer. Each node in the Fabric network decides which resources they provide (determining which contracts they run), and what prices they accept for participation. This, in concert with the bidders requesting these resources, forms the "Information Market" discussed in Fabric's whitepaper. ./DEVELOPERS.md: // TODO: make optional @@ -284,6 +231,7 @@ ./DEVELOPERS.md:- [ ] Remove TODOs ./package.json: "report:todo": "grep --exclude-dir=.git --exclude-dir=_book --exclude-dir=assets --exclude-dir=node_modules --exclude-dir=reports --exclude-dir=coverage --exclude-dir=docs -rEI \"TODO|FIXME\" . > reports/TODO.txt", ./package.json: "review:todo": "npm run report:todo && cat reports/TODO.txt && echo '\nOutstanding TODO items (@fabric/core):' && wc -l reports/TODO.txt && echo '\nIssues List: https://github.com/FabricLabs/fabric/issues\nDisclosures: securiy@fabric.pub\n\n'", +./guides/SETTINGS.md:### WARNING: TODO ./examples/bitcoin.js: // TODO: import these into core process logic ./examples/game.js: // TODO: use fabric call ./examples/swarm.html:

    TODO: create entities on seed node @@ -308,39 +256,34 @@ ./examples/game.html:

    TODO: use fabric call ./examples/app.js: // TODO: document defer as trust(authority) with Remote class ./scripts/lightning-demo.js: // TODO: import configs from Polar +./scripts/create-validator-script.sh:# TODO: set pubkey length from actual pubkey length ./scripts/example.js:// TODO: generate signature, hash of function definition (the "type") -./scripts/schemas.js: // TODO: here for Eric's review. ./scripts/cli.js: // TODO: read & test contracts +./scripts/schemata.js: // TODO: here for Eric's review. ./scripts/chat.js: // TODO: remove Wallet-specfic configuration ./scripts/chat.js: // TODO: reconcile API wth @fabric/doorman as appears at: https://github.com/FabricLabs/doorman ./scripts/chat.js: // TODO: remove from log output... ./scripts/chat.js: // TODO: replicate this program in C / ASM ./scripts/transfer.js: // TODO: add support for segwit, taproot ./functions/_handleFabricMessage.js: const message = Message.fromVector([...data]); // TODO: redefine... -./GOALS.md:- [ ] Find all TODO items (run script, check diff) +./GOALS.md:- [x] Find all TODO items (run script, check diff) ./services/bitcoin.js:// TODO: replace with `secp256k1` ./services/bitcoin.js: // httpPort: 48449, // TODO: disable HTTP entirely! -./services/bitcoin.js: // TODO: import ZMQ settings ./services/bitcoin.js: message.amount = message.amount.fixed().toPrecision(8); // TODO: evaluate precision behavior ./services/bitcoin.js: // TODO: ensure all appropriate fields, valid block ./services/bitcoin.js: // TODO: verify local hash (see below) ./services/bitcoin.js: // TODO: verify block hash!!! ./services/bitcoin.js: // TODO: enable sharing of local hashes ./services/bitcoin.js: // TODO: fix @types/wallet to use named types for Addresses... -./services/bitcoin.js: // TODO: listen for sync finalization -./services/bitcoin.js: // TODO: replace with reject() -./services/bitcoin.js: // TODO: not rely on parseFloat ./services/bitcoin.js: // TODO: report FundingError: Not enough funds -./services/bitcoin.js: // TODO: not rely on parseFloat -./services/bitcoin.js: // TODO: add support for segwit, taproot -./services/bitcoin.js: // TODO: use satoshis/vbyte -./services/bitcoin.js: // TODO: SECURITY !!! ./services/bitcoin.js: // TODO: async (i.e., Promise.all) chainsync +./services/bitcoin.js: // TODO: use RPC auth ./services/bitcoin.js: // TODO: re-enable these ./services/bitcoin.js: // TODO: re-enable SPV ./services/bitcoin.js: // END TODO ./services/turntable.js: // TODO: await REST or GraphQL API? ./services/exchange.js: // TODO: finalize Collection API in #docs-update ./services/lightning.js: // TODO: re-work Polar integration +./services/lightning.js: // TODO: sync local data with node ./whitepaper.md:TODO ./whitepaper.md:TODO: include content hashes of links as they appear at diff --git a/reports/install.log b/reports/install.log index 3463f81ee..6853bac5f 100644 --- a/reports/install.log +++ b/reports/install.log @@ -1,8 +1,16 @@ $ npm i -added 736 packages, and audited 737 packages in 30s +added 694 packages, and audited 695 packages in 22s -67 packages are looking for funding +112 packages are looking for funding run `npm fund` for details -found 0 vulnerabilities +5 low severity vulnerabilities + +To address all issues possible, run: + npm audit fix --force + +Some issues need review, and may require choosing +a different dependency. + +Run `npm audit` for details. diff --git a/resources/asset.json b/resources/asset.json deleted file mode 100644 index b9ddb0204..000000000 --- a/resources/asset.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "name": "Asset", - "routes": { - "list": "/assets", - "view": "/assets/:id" - } -} diff --git a/resources/person.js b/resources/person.js deleted file mode 100644 index 9cd408890..000000000 --- a/resources/person.js +++ /dev/null @@ -1,23 +0,0 @@ -'use strict'; - -function Person () { - -} - -Person.prototype.name = 'Person'; - -Person.prototype.attributes = { - username: { type: String } -}; - -Person.prototype.components = { - query: 'maki-person-list', - get: 'maki-person-view' -}; - -Person.prototype.routes = { - query: '/people', - get: '/people/:id' -}; - -module.exports = Person; diff --git a/resources/post.js b/resources/post.js deleted file mode 100644 index 319c3e316..000000000 --- a/resources/post.js +++ /dev/null @@ -1,5 +0,0 @@ -function Definition () { - this.name = 'Post'; -} - -module.exports = Definition; diff --git a/resources/relationship.js b/resources/relationship.js deleted file mode 100644 index c6d079499..000000000 --- a/resources/relationship.js +++ /dev/null @@ -1,5 +0,0 @@ -function Definition () { - this.name = 'Relationship'; -} - -module.exports = Definition; diff --git a/samples/actor.json b/samples/actor.json deleted file mode 100644 index b05368af7..000000000 --- a/samples/actor.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "id": "f97b19d8672ab861188d6f169c6f9097c47b3dacf54e6233cf88711aded209a1" -} diff --git a/samples/index.js b/samples/index.js deleted file mode 100644 index da4239655..000000000 --- a/samples/index.js +++ /dev/null @@ -1,7 +0,0 @@ -'use strict'; - -const Actor = require('./actor'); - -module.exports = { - Actor -}; diff --git a/schemata/index.js b/schemata/index.js index c1949994f..fd32d4397 100644 --- a/schemata/index.js +++ b/schemata/index.js @@ -3,6 +3,8 @@ const Actor = require('./actor'); module.exports = { - Actor: Actor, + definitions: { + Actor: Actor + }, version: 'v0.1.0-RC1' }; diff --git a/scripts/bitcoin-create-block.sh b/scripts/bitcoin-create-block.sh new file mode 100755 index 000000000..ade764d8f --- /dev/null +++ b/scripts/bitcoin-create-block.sh @@ -0,0 +1,7 @@ +#!/bin/bash +bitcoin-cli \ + -regtest \ + -rpcport=20444 \ + -rpcuser='ahp7iuGhae8mooBahFaYieyaixei6too' \ + -rpcpassword='naiRe9wo5vieFayohje5aegheenoh4ee' \ + generatetoaddress 1 bcrt1qfzwjez0ralajwvd7gschlc3mw54qd0v57s5nuc diff --git a/scripts/bitcoin-create-transaction.sh b/scripts/bitcoin-create-transaction.sh new file mode 100755 index 000000000..4e097b016 --- /dev/null +++ b/scripts/bitcoin-create-transaction.sh @@ -0,0 +1,7 @@ +#!/bin/bash +bitcoin-cli \ + -regtest \ + -rpcport=20444 \ + -rpcuser='ahp7iuGhae8mooBahFaYieyaixei6too' \ + -rpcpassword='naiRe9wo5vieFayohje5aegheenoh4ee' \ + sendtoaddress bcrt1q7ft2mmxma3ec9qslaky35lgut6vstvk8n8avyw 1 diff --git a/scripts/bitcoin-get-balance.sh b/scripts/bitcoin-get-balance.sh new file mode 100755 index 000000000..b5508b830 --- /dev/null +++ b/scripts/bitcoin-get-balance.sh @@ -0,0 +1,7 @@ +#!/bin/bash +bitcoin-cli \ + -regtest \ + -rpcport=20444 \ + -rpcuser='ahp7iuGhae8mooBahFaYieyaixei6too' \ + -rpcpassword='naiRe9wo5vieFayohje5aegheenoh4ee' \ + getbalance diff --git a/scripts/bitcoin-get-height.sh b/scripts/bitcoin-get-height.sh new file mode 100755 index 000000000..8e73f7a08 --- /dev/null +++ b/scripts/bitcoin-get-height.sh @@ -0,0 +1,7 @@ +#!/bin/bash +bitcoin-cli \ + -regtest \ + -rpcport=20444 \ + -rpcuser='ahp7iuGhae8mooBahFaYieyaixei6too' \ + -rpcpassword='naiRe9wo5vieFayohje5aegheenoh4ee' \ + getblockchaininfo diff --git a/scripts/bitcoin-get-mempool.sh b/scripts/bitcoin-get-mempool.sh new file mode 100755 index 000000000..130e70c00 --- /dev/null +++ b/scripts/bitcoin-get-mempool.sh @@ -0,0 +1,7 @@ +#!/bin/bash +bitcoin-cli \ + -regtest \ + -rpcport=20444 \ + -rpcuser='ahp7iuGhae8mooBahFaYieyaixei6too' \ + -rpcpassword='naiRe9wo5vieFayohje5aegheenoh4ee' \ + getmempoolinfo diff --git a/scripts/bitcoin-get-miner-address.sh b/scripts/bitcoin-get-miner-address.sh new file mode 100755 index 000000000..8c77dcf78 --- /dev/null +++ b/scripts/bitcoin-get-miner-address.sh @@ -0,0 +1,28 @@ +#!/bin/bash +bitcoin-cli \ + -regtest \ + -rpcport=20444 \ + -rpcuser='ahp7iuGhae8mooBahFaYieyaixei6too' \ + -rpcpassword='naiRe9wo5vieFayohje5aegheenoh4ee' \ + createwallet miner + +bitcoin-cli \ + -regtest \ + -rpcport=20444 \ + -rpcuser='ahp7iuGhae8mooBahFaYieyaixei6too' \ + -rpcpassword='naiRe9wo5vieFayohje5aegheenoh4ee' \ + loadwallet miner + +bitcoin-cli \ + -regtest \ + -rpcport=20444 \ + -rpcuser='ahp7iuGhae8mooBahFaYieyaixei6too' \ + -rpcpassword='naiRe9wo5vieFayohje5aegheenoh4ee' \ + getnewaddress "mining" + +bitcoin-cli \ + -regtest \ + -rpcport=20444 \ + -rpcuser='ahp7iuGhae8mooBahFaYieyaixei6too' \ + -rpcpassword='naiRe9wo5vieFayohje5aegheenoh4ee' \ + getaddressesbylabel "mining" diff --git a/scripts/bitcoin-new-address.sh b/scripts/bitcoin-new-address.sh new file mode 100755 index 000000000..0a707666d --- /dev/null +++ b/scripts/bitcoin-new-address.sh @@ -0,0 +1,7 @@ +#!/bin/bash +bitcoin-cli \ + -regtest \ + -rpcport=20444 \ + -rpcuser='ahp7iuGhae8mooBahFaYieyaixei6too' \ + -rpcpassword='naiRe9wo5vieFayohje5aegheenoh4ee' \ + getnewaddress diff --git a/scripts/browser.js b/scripts/browser.js new file mode 100644 index 000000000..44b12b5ca --- /dev/null +++ b/scripts/browser.js @@ -0,0 +1,16 @@ +'use strict'; + +const Peer = require('../types/peer'); + +async function main () { + const component = document.createElement('fabric-component'); + component.peer = new Peer(); + console.log('component:', component); + document.appendChild(component); +} + +main().catch((exception) => { + console.error('[FABRIC:EDGE]', 'Main Process Error:', exception); +}).then((output) => { + console.log('[FABRIC:EDGE]', 'Main Process Output:', output); +}); diff --git a/scripts/build.js b/scripts/build.js new file mode 100644 index 000000000..1fae2ca84 --- /dev/null +++ b/scripts/build.js @@ -0,0 +1,32 @@ +'use strict'; + +// Settings +const settings = require('../settings/local'); + +// Types +const Peer = require('../types/peer'); +const Site = require('@fabric/http/types/site'); +const Compiler = require('@fabric/http/types/compiler'); + +// Program Body +async function main (input = {}) { + const peer = new Peer(); + const site = new Site(input); + const compiler = new Compiler({ + document: site + }); + + await compiler.compileTo('assets/index.html'); + + return { + site: site.id, + peer: peer + }; +} + +// Run Program +main(settings).catch((exception) => { + console.error('[BUILD:SITE]', '[EXCEPTION]', exception); +}).then((output) => { + console.log('[BUILD:SITE]', '[OUTPUT]', output); +}); diff --git a/scripts/cli.js b/scripts/cli.js index c733673d3..478482fa6 100755 --- a/scripts/cli.js +++ b/scripts/cli.js @@ -25,7 +25,7 @@ const OP_CHAT = require('../contracts/chat'); const OP_EXCHANGE = require('../contracts/exchange'); const OP_MOUNT = require('../contracts/mount'); const OP_SETUP = require('../contracts/setup'); -// const OP_VERIFY = require('../contracts/verify'); +const OP_VERIFY = require('../contracts/verify'); const OP_TEST = require('../contracts/test'); const COMMANDS = { @@ -34,7 +34,7 @@ const COMMANDS = { 'EXCHANGE': OP_EXCHANGE, 'MOUNT': OP_MOUNT, 'SETUP': OP_SETUP, - // 'VERIFY': OP_VERIFY, + 'VERIFY': OP_VERIFY, 'TEST': OP_TEST }; @@ -69,6 +69,12 @@ async function main (input = {}) { .description('Ensures your environment configuration.') .action(COMMANDS['SETUP'].bind({ environment, program })); + // FABRIC VERIFY + // Verify ownership of the Fabric Identity. + program.command('verify') + .description('Enables verification of key ownership.') + .action(COMMANDS['VERIFY'].bind({ environment, program })); + // FABRIC START // Run the basic node. program.command('start') diff --git a/scripts/create-validator-script.sh b/scripts/create-validator-script.sh new file mode 100755 index 000000000..53a0e6398 --- /dev/null +++ b/scripts/create-validator-script.sh @@ -0,0 +1,15 @@ +#!/bin/bash + +# Import Bitcoin Opcodes +source ./bitcoin_opcodes.sh + +# Key from Bitcoin +signer_address=$(bitcoin-cli -signet getnewaddress) +signer_pubkey=$(bitcoin-cli -signet getaddressinfo $signer_address | jq -r '.pubkey') + +# Signing Script +# TODO: set pubkey length from actual pubkey length +block_signing_script="${OP_1}21${signer_pubkey}${OP_1}${OP_CHECKSIG}" + +# Report to User +echo "${block_signing_script}" > "playnet-validator.script" diff --git a/scripts/identity.js b/scripts/identity.js index 18f60d87f..17acf279d 100644 --- a/scripts/identity.js +++ b/scripts/identity.js @@ -1,40 +1,160 @@ 'use strict'; -const SAMPLE = { - debug: true, - seed: 'cricket grocery kingdom wool double wood happy predict worth pave build pepper bullet farm churn exhibit grit isolate short theory help vehicle denial slide' -} +const { + FIXTURE_SEED +} = require('../constants'); +// const DERIVATION = `m/44'/7777'/0'/0/0`; const DERIVATION = `m/44'/0'/0'/0/0`; const PREFIX = 'id'; // const X_PUBKEY = '0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798'; +const crypto = require('crypto'); + // const settings = require('../settings/local'); const Bech32 = require('../types/bech32'); const Hash256 = require('../types/hash256'); const Identity = require('../types/identity'); const Key = require('../types/key'); +async function verifyKey (key) { + if (!key) throw new Error('No key provided for verification'); + if (!key.pubkey) throw new Error('Key missing public key'); + if (!key.private) throw new Error('Key missing private key'); + + // Verify key can sign and verify + const message = 'Fabric Identity Verification'; + const signature = key.sign(message); + const verified = key.verify(message, signature); + if (!verified) throw new Error('Key verification failed'); + + return true; +} + +async function verifyIdentity (identity) { + if (!identity) throw new Error('No identity provided for verification'); + if (!identity.id) throw new Error('Identity missing ID'); + if (!identity.pubkey) throw new Error('Identity missing public key'); + + // Verify identity string format + const decoded = Bech32.decode(identity.id); + if (!decoded) throw new Error('Invalid identity string format'); + + return true; +} + +function logSection (level, section, content) { + if (level > 0) { + console.log(`\n${section}:`); + console.log('-------------------'); + if (typeof content === 'function') { + content(); + } else { + console.log(content); + } + } +} + async function main (input = {}) { - const master = new Key({ seed: SAMPLE.seed }); - const child = new Key({ public: X_PUBKEY }); - const identity = new Identity(input); - const frompub = new Identity({ public: X_PUBKEY }); + // Get environment variables + const seed = process.env.FABRIC_SEED || process.env.SEED; + const xprv = process.env.FABRIC_XPRV || process.env.XPRV; + const xpub = process.env.FABRIC_XPUB || process.env.XPUB; + const identity = process.env.FABRIC_IDENTITY; + const verbosity = parseInt(process.env.FABRIC_VERBOSE || input.verbosity || 0, 10); + + // Create key based on available inputs + let key; + if (identity) { + // Use existing identity string + const existing = Identity.fromString(identity); + await verifyIdentity(existing); + key = existing.key; + } else if (xprv) { + // Use extended private key + key = new Key({ xprv }); + } else if (xpub) { + // Use extended public key + key = new Key({ xpub }); + } else if (seed) { + // Use seed phrase + key = new Key({ seed }); + } else { + // Generate new key + key = new Key(); + } + + // Verify key + await verifyKey(key); + + // Derive child key + const child = key.derive(input.derivation || DERIVATION); + await verifyKey(child); + + // Create identity + const id = new Identity({ key }); + await verifyIdentity(id); + + // Level 0: Just the identity string + console.log('[IDENTITY]', id.toString()); + + // Level 1: Basic identity information + logSection(verbosity, 'Identity Information', () => { + console.log('ID:', id.id); + console.log('Public Key:', key.pubkey); + console.log('Address:', id.toString()); + }); + + // Level 2: Extended identity information + logSection(verbosity - 1, 'Extended Information', () => { + console.log('Public Key Hash:', id.pubkeyhash); + console.log('Derivation Path:', input.derivation || DERIVATION); + console.log('Child Public Key:', child.pubkey); + }); + + // Level 3: Environment variables + logSection(verbosity - 2, 'Environment Variables', () => { + console.log(`export FABRIC_SEED="${key.seed || ''}"`); + console.log(`export FABRIC_XPRV="${key.xprv || ''}"`); + console.log(`export FABRIC_XPUB="${key.xpub || ''}"`); + console.log(`export FABRIC_IDENTITY="${id.toString()}"`); + }); + + // Level 4: Test values + logSection(verbosity - 3, 'Test Values', () => { + const pubkeyhash = Hash256.digest(X_PUBKEY); + const truth = crypto.createHash('sha256').update(Buffer.from(X_PUBKEY, 'hex')).digest('hex'); + console.log('pubkeyhash:', pubkeyhash); + console.log('pubkeyhash size:', pubkeyhash.length); + console.log('truth:', truth); + }); - const decoded = Bech32.decode(frompub.id); + // Level 5: Reference values + logSection(verbosity - 4, 'Reference Values', () => { + const frompub = new Identity({ public: X_PUBKEY }); + console.log('Reference ID:', frompub.id); + console.log('Reference ID Size:', frompub.id.length); + console.log('Reference Address:', frompub.toString()); + console.log('Reference Key X:', frompub.key.public.x.toString('hex')); + console.log('Reference Key Y:', frompub.key.public.y.toString('hex')); + console.log('Reference Pubkey:', frompub.key.public.encodeCompressed('hex')); + }); return { - id: identity.toString(), + id: id.toString(), identity: { - pubkey: identity.pubkey + pubkey: id.pubkey }, - derivation: identity.derivation, - decoded: decoded + derivation: input.derivation || DERIVATION, + verified: true }; } -main(SAMPLE).catch((exception) => { +main().catch((exception) => { console.error('[FABRIC:IDENTITY]', 'Main Process Exception:', exception); + process.exit(1); }).then((output) => { - console.log('[FABRIC:IDENTITY]', 'Current Identity:', output); + if (output) { + process.exit(0); + } }); diff --git a/scripts/import-bitcoin-opcodes.sh b/scripts/import-bitcoin-opcodes.sh new file mode 100755 index 000000000..87d6ea107 --- /dev/null +++ b/scripts/import-bitcoin-opcodes.sh @@ -0,0 +1,122 @@ +#!/bin/bash + +export OP_0=0 +export OP_FALSE=0 +export OP_PUSHDATA1=76 +export OP_PUSHDATA2=77 +export OP_PUSHDATA4=78 +export OP_1NEGATE=79 +export OP_RESERVED=80 +export OP_1=81 +export OP_TRUE=81 +export OP_2=82 +export OP_3=83 +export OP_4=84 +export OP_5=85 +export OP_6=86 +export OP_7=87 +export OP_8=88 +export OP_9=89 +export OP_10=90 +export OP_11=91 +export OP_12=92 +export OP_13=93 +export OP_14=94 +export OP_15=95 +export OP_16=96 +export OP_NOP=97 +export OP_VER=98 +export OP_IF=99 +export OP_NOTIF=100 +export OP_VERIF=101 +export OP_VERNOTIF=102 +export OP_ELSE=103 +export OP_ENDIF=104 +export OP_VERIFY=105 +export OP_RETURN=106 +export OP_TOALTSTACK=107 +export OP_FROMALTSTACK=108 +export OP_2DROP=109 +export OP_2DUP=110 +export OP_3DUP=111 +export OP_2OVER=112 +export OP_2ROT=113 +export OP_2SWAP=114 +export OP_IFDUP=115 +export OP_DEPTH=116 +export OP_DROP=117 +export OP_DUP=118 +export OP_NIP=119 +export OP_OVER=120 +export OP_PICK=121 +export OP_ROLL=122 +export OP_ROT=123 +export OP_SWAP=124 +export OP_TUCK=125 +export OP_CAT=126 +export OP_SUBSTR=127 +export OP_LEFT=128 +export OP_RIGHT=129 +export OP_SIZE=130 +export OP_INVERT=131 +export OP_AND=132 +export OP_OR=133 +export OP_XOR=134 +export OP_EQUAL=135 +export OP_EQUALVERIFY=136 +export OP_RESERVED1=137 +export OP_RESERVED2=138 +export OP_1ADD=139 +export OP_1SUB=140 +export OP_2MUL=141 +export OP_2DIV=142 +export OP_NEGATE=143 +export OP_ABS=144 +export OP_NOT=145 +export OP_0NOTEQUAL=146 +export OP_ADD=147 +export OP_SUB=148 +export OP_MUL=149 +export OP_DIV=150 +export OP_MOD=151 +export OP_LSHIFT=152 +export OP_RSHIFT=153 +export OP_BOOLAND=154 +export OP_BOOLOR=155 +export OP_NUMEQUAL=156 +export OP_NUMEQUALVERIFY=157 +export OP_NUMNOTEQUAL=158 +export OP_LESSTHAN=159 +export OP_GREATERTHAN=160 +export OP_LESSTHANOREQUAL=161 +export OP_GREATERTHANOREQUAL=162 +export OP_MIN=163 +export OP_MAX=164 +export OP_WITHIN=165 +export OP_RIPEMD160=166 +export OP_SHA1=167 +export OP_SHA256=168 +export OP_HASH160=169 +export OP_HASH256=170 +export OP_CODESEPARATOR=171 +export OP_CHECKSIG=172 +export OP_CHECKSIGVERIFY=173 +export OP_CHECKMULTISIG=174 +export OP_CHECKMULTISIGVERIFY=175 +export OP_NOP1=176 +export OP_NOP2=177 +export OP_CHECKLOCKTIMEVERIFY=177 +export OP_NOP3=178 +export OP_CHECKSEQUENCEVERIFY=178 +export OP_NOP4=179 +export OP_NOP5=180 +export OP_NOP6=181 +export OP_NOP7=182 +export OP_NOP8=183 +export OP_NOP9=184 +export OP_NOP10=185 +export OP_SMALLINTEGER=250 +export OP_PUBKEYS=253 +export OP_PUBKEYHASH=254 +export OP_PUBKEY=255 +export OP_INVALIDOPCODE=255 diff --git a/scripts/schemata.js b/scripts/schemata.js index 2222d30a9..b726f8f9c 100644 --- a/scripts/schemata.js +++ b/scripts/schemata.js @@ -2,15 +2,25 @@ const fs = require('fs'); -fs.readdirSync(__dirname + '/../schemata').forEach(function (file) { - if (file.match(/\.json$/) !== null && file !== 'index.js') { - const name = file - .replace('.json', '') - .replace('.js', ''); +async function main () { + const schemata = {}; - console.log('schema name:', name); - // ... do stuff with the schemas? - // or whatever else. - // TODO: here for Eric's review. - } + fs.readdirSync(__dirname + '/../schemata').forEach(function (file) { + if (file.match(/\.json$/) !== null && file !== 'index.js') { + const name = file + .replace('.json', '') + .replace('.js', ''); + + schemata[name] = null; + // ... do stuff with the schemas? + // or whatever else. + // TODO: here for Eric's review. + } + }); + + return { schemata }; +} + +main().then((output) => { + console.log('Schemata:', output); }); diff --git a/tools/swarm.sh b/scripts/swarm.sh similarity index 100% rename from tools/swarm.sh rename to scripts/swarm.sh diff --git a/scripts/validator.js b/scripts/validator.js index e4cbeb619..5900c0285 100755 --- a/scripts/validator.js +++ b/scripts/validator.js @@ -17,9 +17,8 @@ const merge = require('lodash.merge'); // const Chain = require('../types/chain'); const Environment = require('../types/environment'); const Federation = require('../types/federation'); -// const Key = require('../types/key'); +const Key = require('../types/key'); const Machine = require('../types/machine'); -const Signer = require('../types/signer'); // Fabric Services const Bitcoin = require('../services/bitcoin'); @@ -34,11 +33,11 @@ const FABRIC_XPUB = environment.readVariable('FABRIC_XPUB'); console.log('seed:', FABRIC_SEED); -const signer = new Signer({ +const key = new Key({ private: FIXTURE_SEED }); -console.log('signer:', signer); +console.log('key:', key); /* const bond = Buffer.from([ 0x51, // witness v1 @@ -88,12 +87,12 @@ async function main (input = {}) { // Anchor Chain const bitcoin = new Bitcoin(); - const fixture = new Signer({ seed: FIXTURE_SEED }); + const fixture = new Key({ seed: FIXTURE_SEED }); - console.log('public:', fixture.key.public.encodeCompressed('hex')); + console.log('public:', fixture.public.encodeCompressed('hex')); federation.addMember({ - public: fixture.key.public.encodeCompressed('hex') + public: fixture.public.encodeCompressed('hex') }); federation.start(); diff --git a/services/bitcoin.js b/services/bitcoin.js index 10d2870f4..dfc30b302 100644 --- a/services/bitcoin.js +++ b/services/bitcoin.js @@ -1,14 +1,21 @@ 'use strict'; const { - BITCOIN_GENESIS + BITCOIN_GENESIS, + BITCOIN_GENESIS_HASH, + FABRIC_USER_AGENT } = require('../constants'); const OP_TRACE = require('../contracts/trace'); +// Dependencies +const crypto = require('crypto'); +const children = require('child_process'); + // External Dependencies const jayson = require('jayson/lib/client'); const monitor = require('fast-json-patch'); +const { mkdirp } = require('mkdirp'); // crypto support libraries // TODO: replace with `secp256k1` @@ -19,6 +26,9 @@ const bip68 = require('bip68'); const ECPair = ECPairFactory(ecc); const bitcoin = require('bitcoinjs-lib'); +// Initialize bitcoinjs-lib with the ECC library +bitcoin.initEccLib(ecc); + // Services const ZMQ = require('../services/zmq'); @@ -26,6 +36,7 @@ const ZMQ = require('../services/zmq'); const Actor = require('../types/actor'); const Collection = require('../types/collection'); const Entity = require('../types/entity'); +const Key = require('../types/key'); const Service = require('../types/service'); const State = require('../types/state'); const Wallet = require('../types/wallet'); @@ -50,39 +61,69 @@ class Bitcoin extends Service { constructor (settings = {}) { super(settings); - // Internal State - this.state = { - blocks: {} - }; - // Local Settings this.settings = Object.assign({ name: '@services/bitcoin', - mode: 'rpc', + mode: 'fabric', genesis: BITCOIN_GENESIS, - network: 'regtest', + network: 'mainnet', path: './stores/bitcoin', mining: false, listen: false, fullnode: false, + managed: false, + constraints: { + storage: { + size: 550 // size in MB + } + }, spv: { port: 18332 }, zmq: { host: 'localhost', - port: 29000 + port: 29500 + }, + key: { + mnemonic: null, + seed: null, + xprv: null, + xpub: null, + passphrase: null + }, + state: { + actors: {}, + blocks: {}, // Map of blocks by block hash + height: 0, + tip: BITCOIN_GENESIS_HASH, + transactions: {}, // Map of transactions by txid + addresses: {}, // Map of addresses to their transactions + walletIndex: 0, // Current address index + supply: 0 }, nodes: ['127.0.0.1'], seeds: ['127.0.0.1'], servers: [], targets: [], peers: [], - port: 18444, - interval: 10 * 60 * 1000, // every 10 minutes, write a checkpoint + port: 18333, // P2P port + rpcport: 18332, // RPC port + interval: 60000, // 10 * 60 * 1000, // every 10 minutes, write a checkpoint verbosity: 2 }, settings); - if (this.settings.verbosity >= 4) console.log('[DEBUG]', 'Instance of Bitcoin service created, settings:', this.settings); + // Initialize network configurations + this._networkConfigs = { + mainnet: bitcoin.networks.bitcoin, + testnet: bitcoin.networks.testnet, + regtest: bitcoin.networks.regtest + }; + + if (this.settings.debug && this.settings.verbosity >= 4) console.debug('[DEBUG]', 'Instance of Bitcoin service created, settings:', this.settings); + + this._rootKey = new Key({ + ...this.settings.key + }); // Bcoin for JS full node // bcoin.set(this.settings.network); @@ -91,7 +132,7 @@ class Bitcoin extends Service { // Internal Services this.observer = null; // this.provider = new Consensus({ provider: 'bcoin' }); - this.wallet = new Wallet(this.settings); + this.wallet = new Wallet({ ...this.settings, key: { xprv: this._rootKey.xprv } }); // this.chain = new Chain(this.settings); // ## Collections @@ -122,12 +163,12 @@ class Bitcoin extends Service { } }); - // Runs fullnode from bcoin - if (this.settings.fullnode) { + // Runs fullnode from bcoin (disabled for now) + /* if (this.settings.fullnode) { this.fullnode = new FullNode({ network: this.settings.network }); - } + } */ // Local Bitcoin Node this.peer = null; /* bcoin.Peer.fromOptions({ @@ -152,8 +193,7 @@ class Bitcoin extends Service { workers: true }); */ - // TODO: import ZMQ settings - this.zmq = new ZMQ(); + this.zmq = new ZMQ({ ...this.settings.zmq, key: { xprv: this._rootKey.xprv } }); // Define Bitcoin P2P Messages this.define('VersionPacket', { type: 0 }); @@ -180,12 +220,7 @@ class Bitcoin extends Service { immature: 0 } }, - content: { - actors: {}, - blocks: [], - height: 0, - tip: this.settings.genesis - }, + content: this.settings.state, chain: [], blocks: {}, headers: [], @@ -197,24 +232,6 @@ class Bitcoin extends Service { return this; } - /** - * Provides bcoin's implementation of `TX` internally. This static may be - * removed in the future. - * @deprecated - */ - static get Transaction () { - return bcoin.TX; - } - - /** - * Provides bcoin's implementation of `MTX` internally. This static may be - * removed in the future. - * @deprecated - */ - static get MutableTransaction () { - return bcoin.TX; - } - get balance () { return this._state.balances.mine.trusted; } @@ -227,18 +244,14 @@ class Bitcoin extends Service { * User Agent string for the Bitcoin P2P network. */ get UAString () { - return 'Fabric/Bitcoin 0.1.0-dev (@fabric/core#v0.1.0-RC1)'; + return FABRIC_USER_AGENT; } /** * Chain tip (block hash of the chain with the most Proof of Work) */ get tip () { - if (this.settings.fullnode) { - return this.fullnode.chain.tip.hash.toString('hex'); - } else { - return (this.chain && this.chain.tip) ? this.chain.tip.toString('hex') : null; - } + return (this.chain && this.chain.tip) ? this.chain.tip.toString('hex') : null; } /** @@ -260,12 +273,18 @@ class Bitcoin extends Service { return bitcoin; } + get network () { + return this.settings.network; + } + get networks () { - return { - 'mainnet': bitcoin.networks.mainnet, - 'regtest': bitcoin.networks.regtest, - 'testnet': bitcoin.networks.testnet - }; + return this._networkConfigs; + } + + get walletName () { + const preimage = crypto.createHash('sha256').update(this.settings.key.xpub).digest('hex'); + const hash = crypto.createHash('sha256').update(preimage).digest('hex'); + return this.settings.walletName || hash; } set best (best) { @@ -281,68 +300,45 @@ class Bitcoin extends Service { this.commit(); } - createKeySpendOutput (publicKey) { - // x-only pubkey (remove 1 byte y parity) - const myXOnlyPubkey = publicKey.slice(1, 33); - const commitHash = bitcoin.crypto.taggedHash('TapTweak', myXOnlyPubkey); - const tweakResult = ecc.xOnlyPointAddTweak(myXOnlyPubkey, commitHash); - if (tweakResult === null) throw new Error('Invalid Tweak'); - - const { xOnlyPubkey: tweaked } = tweakResult; - - // scriptPubkey - return Buffer.concat([ - // witness v1, PUSH_DATA 32 bytes - Buffer.from([0x51, 0x20]), - // x-only tweaked pubkey - tweaked, - ]); + get supply () { + return this._state.content.supply; } - createSigned (key, txid, vout, amountToSend, scriptPubkeys, values) { - const tx = new bitcoin.Transaction(); - - tx.version = 2; - - // Add input - tx.addInput(Buffer.from(txid, 'hex').reverse(), vout); - - // Add output - tx.addOutput(scriptPubkeys[0], amountToSend); - - const sighash = tx.hashForWitnessV1( - 0, // which input - scriptPubkeys, // All previous outputs of all inputs - values, // All previous values of all inputs - bitcoin.Transaction.SIGHASH_DEFAULT // sighash flag, DEFAULT is schnorr-only (DEFAULT == ALL) - ); - - const signature = Buffer.from(signTweaked(sighash, key)); - - // witness stack for keypath spend is just the signature. - // If sighash is not SIGHASH_DEFAULT (ALL) then you must add 1 byte with sighash value - tx.ins[0].witness = [signature]; - - return tx; - } - - signTweaked (messageHash, key) { - // Order of the curve (N) - 1 - const N_LESS_1 = Buffer.from('fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140', 'hex'); - // 1 represented as 32 bytes BE - const ONE = Buffer.from('0000000000000000000000000000000000000000000000000000000000000001', 'hex'); - const privateKey = (key.publicKey[0] === 2) ? key.privateKey : ecc.privateAdd(ecc.privateSub(N_LESS_1, key.privateKey), ONE); - const tweakHash = bitcoin.crypto.taggedHash('TapTweak', key.publicKey.slice(1, 33)); - const newPrivateKey = ecc.privateAdd(privateKey, tweakHash); - if (newPrivateKey === null) throw new Error('Invalid Tweak'); - return ecc.signSchnorr(messageHash, newPrivateKey, Buffer.alloc(32)); + createRPCAuth (settings = {}) { + if (!settings.username) throw new Error('Username is required.'); + const username = settings.username; + const password = settings.password || crypto.randomBytes(32).toString('base64').replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/g, ''); + const salt = crypto.randomBytes(16).toString('hex'); + const salted = crypto.createHmac('sha256', salt, { encoding: 'utf8' }).update(password, 'utf8').digest('hex'); + return { + content: `${username}:${salt}$${salted}`, + password: password, + username: username + }; } validateAddress (address) { try { - bitcoin.address.toOutputScript(address, this.networks[this.settings.network]); + // Get the correct network configuration + const network = this._networkConfigs[this.settings.network]; + if (!network) { + throw new Error(`Invalid network: ${this.settings.network}`); + } + + try { + bitcoin.address.toOutputScript(address, network); + return true; + } catch (e) { + return false; + } + + // Try to convert the address to an output script + bitcoin.address.toOutputScript(address, network); return true; } catch (e) { + if (this.settings.debug) { + console.debug('[FABRIC:BITCOIN]', 'Address validation failed:', e.message); + } return false; } } @@ -379,14 +375,14 @@ class Bitcoin extends Service { * @param {TX} tx Bitcoin transaction */ async broadcast (msg) { - console.log('[SERVICES:BITCOIN]', 'Broadcasting:', msg); + console.debug('[SERVICES:BITCOIN]', 'Broadcasting:', msg); const verify = await msg.verify(); - console.log('[SERVICES:BITCOIN]', 'Verified TX:', verify); + console.debug('[SERVICES:BITCOIN]', 'Verified TX:', verify); await this.spv.sendTX(msg); // await this.spv.broadcast(msg); await this.spv.relay(msg); - console.log('[SERVICES:BITCOIN]', 'Broadcasted!'); + console.debug('[SERVICES:BITCOIN]', 'Broadcasted!'); } async processSpendMessage (message) { @@ -395,7 +391,7 @@ class Bitcoin extends Service { async _processRawBlock (raw) { const block = bcoin.Block.fromRaw(raw); - console.log('rawBlock:', block); + console.debug('rawBlock:', block); } /** @@ -500,8 +496,7 @@ class Bitcoin extends Service { let hash = require('crypto').createHash('sha256').update(obj.data).digest('hex'); // TODO: verify local hash (see below) - console.log('local hash from node:', hash); - console.log('WARNING [!!!]: double check that:', `${obj.headers.hash('hex')} === ${hash}`); + console.debug('WARNING [!!!]: double check that:', `${obj.headers.hash('hex')} === ${hash}`); try { // TODO: verify block hash!!! @@ -568,62 +563,23 @@ class Bitcoin extends Service { let tx = await this._GET(`/transactions/${obj.hash}`); console.log('registered tx:', tx); - let txns = await this._GET(`/transactions`); - let txids = Object.keys(txns); - let inputs = []; - let outputs = []; - + // Track transactions for each address if (obj.inputs) { - for (let i = 0; obj.inputs.length; i++) { - let input = obj.inputs[i]; - - if (input.address) { - await this._registerAddress({ - id: input.address - }); + for (let input of obj.inputs) { + if (input.address && this.settings.state.addresses[input.address]) { + this.settings.state.addresses[input.address].transactions.push(obj.hash); } - - inputs.push(input); } } if (obj.outputs) { - for (let i = 0; obj.outputs.length; i++) { - let output = obj.outputs[i]; - - if (output.address) { - await this._registerAddress({ - id: output.address - }); + for (let output of obj.outputs) { + if (output.address && this.settings.state.addresses[output.address]) { + this.settings.state.addresses[output.address].transactions.push(obj.hash); } - - outputs.push(output); } } - let transaction = Object.assign({ - id: obj.hash, - hash: obj.hash, - inputs: inputs, - outputs: outputs - }, obj); - - // await this._PUT(`/transactions`, txids); - await this.commit(); - - this.emit(`message`, { - '@type': 'TransactionRegistration', - '@data': tx, - actor: `services/bitcoin`, - target: `/transactions`, - object: transaction, - origin: { - type: 'Link', - name: 'Bitcoin', - link: `/services/bitcoin` - } - }); - return tx; } @@ -636,7 +592,7 @@ class Bitcoin extends Service { * @param {PeerPacket} msg Message from peer. */ async _handlePeerPacket (msg) { - console.log('[SERVICES:BITCOIN]', 'Peer sent packet:', msg); + console.debug('[SERVICES:BITCOIN]', 'Peer sent packet:', msg); switch (msg.cmd) { default: @@ -655,7 +611,7 @@ class Bitcoin extends Service { data: msg.block.toBlock()._raw, }); - console.log('registered block:', block); + console.debug('registered block:', block); break; case 'inv': this.peer.getData(msg.items); @@ -666,11 +622,11 @@ class Bitcoin extends Service { hash: msg.tx.hash('hex') + '', confirmations: 0 }); - console.log('regtest tx:', transaction); + console.debug('regtest tx:', transaction); break; } - console.log('[SERVICES:BITCOIN]', 'State:', this.state); + console.debug('[SERVICES:BITCOIN]', 'State:', this.state); } async _handleBlockMessage (msg) { @@ -709,6 +665,9 @@ class Bitcoin extends Service { block: msg }); + // Update state with new block + this._state.content.blocks[block.hash] = block; + // if (this.settings.verbosity >= 5) console.log('created block:', block); if (this.settings.verbosity >= 5) console.log('block count:', Object.keys(this.blocks.list()).length); @@ -741,6 +700,9 @@ class Bitcoin extends Service { } }; + // Update state with new transaction + this._state.content.transactions[tx.hash('hex')] = msg['@data']; + this.emit('transaction', msg); this.emit('message', { '@type': 'ServiceMessage', '@data': msg }); @@ -764,37 +726,86 @@ class Bitcoin extends Service { } async _loadWallet (name) { - const actor = new Actor({ content: name }); - const created = await this._makeRPCRequest('createwallet', [ - actor.id, - false, - false, // blank (use sethdseed) - '', // passphrase - true, // avoid reuse - false, // descriptors - ]); + if (!name) name = this.walletName; + try { + const info = await this._makeRPCRequest('getnetworkinfo'); + const version = parseInt(info.version); + const useDescriptors = version >= 240000; // Descriptors became stable in v24.0 + + if (this.settings.debug) console.trace('[FABRIC:BITCOIN]', `Loading wallet: ${name}, version: ${version}, descriptors: ${useDescriptors}`); + + const walletParams = [ + name, + false, // disable_private_keys + false, // TODO: enable blank, import _rootKey + null, // passphrase + true, // avoid_reuse + useDescriptors // descriptors - only enable for newer versions + ]; + + // First try to load an existing wallet + try { + await this._makeRPCRequest('loadwallet', [name]); + if (this.settings.debug) console.debug('[FABRIC:BITCOIN]', `Successfully loaded existing wallet: ${name}`); + return { name }; + } catch (loadError) { + if (this.settings.debug) console.debug('[FABRIC:BITCOIN]', `Load error for wallet ${name}:`, loadError.message); - const wallet = await this._makeRPCRequest('loadwallet', [actor.id]); + // If wallet doesn't exist (-18) or path doesn't exist, we need to create it + if (loadError.code === -18 || loadError.message.includes('does not exist')) { + if (this.settings.debug) console.debug('[FABRIC:BITCOIN]', `Wallet path does not exist, creating new wallet: ${name}`); - /* if (created.error && wallet.error) { - return this.emit('error', `Could not create or load wallet: ${created.error || wallet.error}`); - } */ + try { + await this._makeRPCRequest('createwallet', walletParams); + if (this.settings.debug) console.debug('[FABRIC:BITCOIN]', `Successfully created wallet: ${name}`); + return { name }; + } catch (createError) { + if (this.settings.debug) console.debug('[FABRIC:BITCOIN]', `Create error for wallet ${name}:`, createError.message); + throw createError; + } + } - try { - this.addresses = await this._listAddresses(); - } catch (exception) {} + // If wallet is already loaded (-35), that's fine + if (loadError.code === -35) { + if (this.settings.debug) console.debug('[FABRIC:BITCOIN]', `Wallet ${name} already loaded`); + return { name }; + } - // console.log('addresses:', this.addresses); - if (this.addresses.error) this.addresses = []; + // For any other error where the wallet might be in a bad state, try unloading and recreating + try { + if (this.settings.debug) console.debug('[FABRIC:BITCOIN]', `Attempting to unload and recreate wallet: ${name}`); + // Try to unload (might fail if wallet isn't loaded, but that's okay) + try { + await this._makeRPCRequest('unloadwallet', [name]); + } catch (unloadError) { + if (this.settings.debug) console.debug('[FABRIC:BITCOIN]', `Unload failed (wallet may not be loaded): ${unloadError.message}`); + // Continue anyway - the wallet probably wasn't loaded + } - if (!this.addresses.length) { - const address = await this.getUnusedAddress(); - this.addresses.push(address); + await this._makeRPCRequest('createwallet', walletParams); + if (this.settings.debug) console.debug('[FABRIC:BITCOIN]', `Successfully recreated wallet: ${name}`); + return { name }; + } catch (recreateError) { + if (this.settings.debug) console.debug('[FABRIC:BITCOIN]', `Recreate error for wallet ${name}:`, recreateError.message); + throw recreateError; + } + } + } catch (error) { + if (this.settings.debug) console.debug('[FABRIC:BITCOIN]', 'Wallet loading sequence error:', error); + throw error; } + } - return { - id: actor.id - }; + async _unloadWallet (name) { + if (!name) name = this.walletName; + try { + if (this.settings.debug) console.debug('[FABRIC:BITCOIN]', `Attempting to unload wallet: ${name}`); + await this._makeRPCRequest('unloadwallet', [name]); + if (this.settings.debug) console.debug('[FABRIC:BITCOIN]', `Successfully unloaded wallet: ${name}`); + return { name }; + } catch (error) { + if (this.settings.debug) console.debug('[FABRIC:BITCOIN]', 'Wallet unloading sequence:', error.message); + } } /** @@ -886,98 +897,92 @@ class Bitcoin extends Service { } } - async _startZMQ () { - const self = this; - - this.zmq.on('log', async function _handleZMQLogEvent (event) { - self.emit('debug', `[BITCOIN:ZMQ] Log: ${event}`); - self.emit('log', `[BITCOIN:ZMQ] Log: ${event}`); - }); - - this.zmq.on('message', async function _handleZMQMessage (event) { - self.emit('debug', `[BITCOIN:ZMQ] Message: ${JSON.stringify(event)}`); - - let data = null; + async _handleZMQMessage (msg) { + let topic, content; - try { - data = JSON.parse(event.data); - } catch (exception) { - self.emit('error', 'Could not parse raw block:', event.data); - } + // Handle both raw ZMQ messages and Message objects + if (Array.isArray(msg)) { + // Raw ZMQ message format + topic = msg[0].toString(); + content = msg[1]; + } else if (msg && typeof msg === 'object') { + // Message object format + topic = msg.type; + content = msg.data; + } else { + console.error('[BITCOIN]', 'Invalid message format:', msg); + return; + } - if (!data || !data.topic) return; + if (this.settings.debug) this.emit('debug', '[ZMQ] Received message on topic:', topic, 'Message length:', content.length); - switch (data.topic) { - case 'hashblock': - try { - await self._requestBlock(data.message); - } catch (exception) { - self.emit('error', `Could not retrieve reported block: ${data.message}`); - } + try { + switch (topic) { + case 'BitcoinBlock': + case 'BitcoinTransactionHash': break; - case 'rawblock': - try { - await self._processRawBlock(data.message); - } catch (exception) { - self.emit('error', `Could not retrieve reported block: ${data.message}`); - } + case 'BitcoinBlockHash': + const message = JSON.parse(content.toString()); + const supply = await this._makeRPCRequest('gettxoutsetinfo', []); + this._state.content.height = supply.height; + this._state.content.tip = message.content; + this._state.content.supply = supply.total_amount; + this.commit(); break; - default: - self.emit('warning', `[BITCOIN:ZMQ] Unhandled topic: ${data.topic}`); + case 'BitcoinTransaction': + // const record = JSON.parse(content.toString()); + const balance = await this._makeRPCRequest('getbalances', []); + this._state.balances.mine.trusted = balance; + this.commit(); break; + default: + if (this.settings.verbosity >= 5) console.log('[AUDIT]', 'Unknown ZMQ topic:', topic); } - }); - - await this.zmq.start(); - return this; + } catch (exception) { + //', `Could not process ZMQ message: ${exception}`); + } } - async _startLocalNode () { - const self = this; - - if (this.settings.verbosity >= 4) console.log('[SERVICES:BITCOIN]', `Starting fullnode for network "${this.settings.network}"...`); + async _startZMQ () { + if (this.settings.verbosity >= 5) console.debug('[AUDIT]', 'Starting ZMQ service...'); + this.zmq.on('log', (msg) => { + if (this.settings.debug) console.log('[ZMQ]', msg); + }); - for (const candidate of this.settings.seeds) { - let parts = candidate.split(':'); - let addr = new NetAddress({ - host: parts[0], - port: parseInt(parts[1]) || this.provider.port - }); + this.zmq.on('message', this._handleZMQMessage.bind(this)); - let peer = this.fullnode.pool.createOutbound(addr); - this.fullnode.pool.peers.add(peer); - } + this.zmq.on('error', (err) => { + console.error('[ZMQ] Error:', err); + }); - await this.fullnode.open(); - await this.fullnode.connect(); + this.zmq.on('connect', () => { + console.log('[ZMQ] Connected to Bitcoin node'); + }); - // TODO: listen for sync finalization - this.fullnode.startSync(); + this.zmq.on('disconnect', () => { + console.log('[ZMQ] Disconnected from Bitcoin node'); + }); - if (this.settings.verbosity >= 4) console.log('[SERVICES:BITCOIN]', `Full Node for network "${this.settings.network}" started!`); + await this.zmq.start(); + if (this.settings.debug) console.log('[AUDIT]', 'ZMQ Started.'); } async generateBlock (address) { - let block = null; - if (!address) address = await this.getUnusedAddress(); switch (this.settings.mode) { case 'rpc': const result = await this._makeRPCRequest('generatetoaddress', [1, address]); - break; + return result[0]; + case 'fabric': + // In fabric mode, we just increment the height and return a mock block hash + this.settings.state.height++; + const mockHash = crypto.createHash('sha256').update(`${this.settings.state.height}`).digest('hex'); + this.settings.state.tip = mockHash; + return mockHash; default: - try { - block = await this.fullnode.miner.mineBlock(this.fullnode.chain.tip, address); - // Add the block to our chain - await this.fullnode.chain.add(block); - } catch (exception) { - return this.emit('error', `Could not mine block: ${exception}`); - } - break; + throw new Error('Invalid mode for block generation'); } - - return block; } async generateBlocks (count = 1, address = this.wallet.receive) { @@ -1003,13 +1008,55 @@ class Bitcoin extends Service { } async getUnusedAddress () { - const address = await this._makeRPCRequest('getnewaddress'); - return address; + if (this.rpc) { + try { + await this._loadWallet(this.walletName); + const info = await this._makeRPCRequest('getnetworkinfo'); + const version = parseInt(info.version); + const address = await this._makeRPCRequest('getnewaddress', [ + '', // label + version >= 240000 ? 'legacy' : 'legacy' // address type + ]); + + if (!address) throw new Error('No address returned from getnewaddress'); + return address; + } catch (error) { + if (this.settings.debug) console.debug('[FABRIC:BITCOIN]', 'Error getting unused address:', error); + throw error; + } + } else if (this.settings.key) { + // In fabric mode, use the provided key to derive an address + const target = this.settings.key.deriveAddress(this.settings.state.walletIndex); + // Increment the index for next time + this.settings.state.walletIndex++; + // Track the address + this.settings.state.addresses[target.address] = { + index: this.settings.state.walletIndex - 1, + transactions: [] + }; + return target.address; + } else { + // If no key is provided, generate a new key for regtest + const key = new Key({ + network: this.settings.network, + purpose: 44, + account: 0, + index: this.settings.state.walletIndex + }); + this.settings.key = key; + const target = key.deriveAddress(this.settings.state.walletIndex); + this.settings.state.walletIndex++; + this.settings.state.addresses[target.address] = { + index: this.settings.state.walletIndex - 1, + transactions: [] + }; + return target.address; + } } async append (raw) { const block = bcoin.Block.fromRaw(raw, 'hex'); - this.emit('debug', `Parsed block: ${JSON.stringify(block)}`); + if (this.settings.debug) this.emit('debug', `Parsed block: ${JSON.stringify(block)}`); const added = await this.fullnode.chain.add(block); if (!added) this.emit('warning', 'Block not added to chain.'); return added; @@ -1031,29 +1078,34 @@ class Bitcoin extends Service { return this._makeRPCRequest('listreceivedbyaddress', [1, true]); } + /** + * Make a single RPC request to the Bitcoin node. + * @param {String} method The RPC method to call. + * @param {Array} params The parameters to pass to the RPC method. + * @returns {Promise} A promise that resolves to the RPC response. + */ async _makeRPCRequest (method, params = []) { - const self = this; return new Promise((resolve, reject) => { - if (!self.rpc) { - self.emit('error', `No local RPC: ${self} \n${OP_TRACE({ name: 'foo' })}`); - return reject(new Error('RPC manager does not exist.')); - } + if (!this.rpc) return reject(new Error('RPC manager does not exist')); - try { - self.rpc.request(method, params, function responseHandler (err, response) { - if (err) { - // TODO: replace with reject() - return resolve({ - error: (err.error) ? JSON.parse(JSON.parse(err.error)) : err, - response: response - }); - } + this.rpc.request(method, params, (err, response) => { + if (err) { + if (this.settings.debug) console.debug('[FABRIC:BITCOIN]', `RPC error for ${method}(${params.join(', ')}):`, err); + return reject(err); + } - return resolve(response.result); - }); - } catch (exception) { - return reject(exception); - } + if (!response) { + return reject(new Error(`No response from RPC call ${method}`)); + } + + if (response.error) { + if (this.settings.debug) console.debug('[FABRIC:BITCOIN]', `RPC response error for ${method}:`, response.error); + return reject(response.error); + } + + if (this.settings.debug) console.debug('[FABRIC:BITCOIN]', `RPC response for ${method}:`, response); + return resolve(response.result); + }); }); } @@ -1072,9 +1124,15 @@ class Bitcoin extends Service { } async _requestBestBlockHash () { - const hash = await this._makeRPCRequest('getbestblockhash', []); - // this.emit('debug', `Got best block hash: ${hash}`); - return hash; + try { + const hash = await this._makeRPCRequest('getbestblockhash', []); + this.best = hash; + await this.commit(); + return this.best; + } catch (error) { + if (this.settings.debug) console.debug('[FABRIC:BITCOIN]', 'Error requesting best block hash:', error.message); + throw error; + } } async _requestBlockHeader (hash) { @@ -1144,7 +1202,15 @@ class Bitcoin extends Service { } async _listUnspent () { - return this._makeRPCRequest('listunspent', []); + try { + // Ensure a wallet is loaded + await this._loadWallet(this.walletName); + return this._makeRPCRequest('listunspent', []); + } catch (error) { + if (this.settings.debug) console.debug('[FABRIC:BITCOIN]', 'Error listing unspent outputs:', error.message); + // Return empty array on error + return []; + } } async _encodeSequenceForNBlocks (time) { @@ -1160,42 +1226,6 @@ class Bitcoin extends Service { return this._makeRPCRequest('signrawtransaction', [rawTX, JSON.stringify(prevouts)]); } - async _getUTXOSetMeta (utxos) { - const coins = []; - const keys = []; - - let inputSum = 0; - let inputCount = 0; - - for (let i = 0; i < utxos.length; i++) { - const candidate = utxos[i]; - const template = { - hash: Buffer.from(candidate.txid, 'hex').reverse(), - index: candidate.vout, - value: Amount.fromBTC(candidate.amount).toValue(), - script: Script.fromAddress(candidate.address) - }; - - const c = Coin.fromOptions(template); - const keypair = await this._dumpKeyPair(candidate.address); - - coins.push(c); - keys.push(keypair); - - inputCount++; - // TODO: not rely on parseFloat - // use bitwise... - inputSum += parseFloat(template.value); - } - - return { - inputs: { - count: inputCount, - total: inputSum - } - }; - } - /** * Creates an unsigned Bitcoin transaction. * @param {Object} options @@ -1226,89 +1256,6 @@ class Bitcoin extends Service { }; } - async _createContractFromProposal (proposal) { - const tx = proposal.mtx.toTX(); - const raw = tx.toRaw().toString('hex'); - return { - tx: tx, - raw: raw - }; - } - - async _getCoinsFromInputs (inputs = []) { - const coins = []; - const keys = []; - - let inputSum = 0; - let inputCount = 0; - - for (let i = 0; i < inputs.length; i++) { - const candidate = inputs[i]; - const template = { - hash: Buffer.from(candidate.txid, 'hex').reverse(), - index: candidate.vout, - value: Amount.fromBTC(candidate.amount).toValue(), - script: Script.fromAddress(candidate.address) - }; - - const c = Coin.fromOptions(template); - const keypair = await this._dumpKeyPair(candidate.address); - - coins.push(c); - keys.push(keypair); - - inputCount++; - // TODO: not rely on parseFloat - // use bitwise... - inputSum += parseFloat(template.value); - } - - return coins; - } - - async _getKeysFromCoins (coins) { - console.log('coins:', coins); - } - - async _attachOutputToContract (output, contract) { - // TODO: add support for segwit, taproot - // is the scriptpubkey still set? - const scriptpubkey = output.scriptpubkey; - const value = output.value; - // contract.mtx.addOutput(scriptpubkey, value); - return contract; - } - - async _signInputForContract (index, contract) { - - } - - async _signAllContractInputs (contract) { - - } - - async _generateScriptAddress () { - const script = new Script(); - script.pushOp(bcoin.opcodes.OP_); // Segwit version - script.pushData(ring.getKeyHash()); - script.compile(); - - return { - address: script.getAddress(), - script: script - }; - } - - async _estimateFeeRate (options = {}) { - // satoshis per kilobyte - // TODO: use satoshis/vbyte - return 10000; - } - - async _coinSelectNaive (options = {}) { - - } - async _createSwapScript (options) { const sequence = await this._encodeSequenceTargetBlock(options.constraints.blocktime); const asm = ` @@ -1327,71 +1274,6 @@ class Bitcoin extends Service { return bitcoin.script.fromASM(clean); } - async _createSwapTX (options) { - const network = this.networks[this.settings.network]; - const tx = new bitcoin.Transaction(); - - tx.locktime = bip65.encode({ blocks: options.constraints.blocktime }); - - const input = options.inputs[0]; - tx.addInput(Buffer.from(input.txid, 'hex').reverse(), input.vout, 0xfffffffe); - - const output = bitcoin.address.toOutputScript(options.destination, network); - tx.addOutput(output, options.amount * 100000000); - - return tx; - } - - async _p2shForOutput (output) { - return bitcoin.payments.p2sh({ - redeem: { output }, - network: this.networks[this.settings.network] - }); - } - - async _spendSwapTX (options) { - const network = this.networks[this.settings.network]; - const tx = options.tx; - const hashtype = bitcoin.Transaction.SIGHASH_ALL; - const sighash = tx.hashForSignature(0, options.script, hashtype); - const scriptsig = bitcoin.payments.p2sh({ - redeem: { - input: bitcoin.script.compile([ - bitcoin.script.signature.encode(options.signer.sign(sighash), hashtype), - bitcoin.opcodes.OP_TRUE - ]), - output: options.script - }, - network: network - }); - - tx.setInputScript(0, scriptsig.input); - - return tx; - } - - async _createP2WPKHTransaction (options) { - const p2wpkh = this._createPayment(options); - const psbt = new bitcoin.Psbt({ network: this.networks[this.settings.network] }) - .addInput(options.input) - .addOutput({ - address: options.change, - value: 2e4, - }) - .signInput(0, p2wpkh.keys[0]); - - psbt.finalizeAllInputs(); - const tx = psbt.extractTransaction(); - return tx; - } - - async _createP2WKHPayment (options) { - return bitcoin.payments.p2wsh({ - pubkey: options.pubkey, - network: this.networks[this.settings.network] - }); - } - _createPayment (options) { return bitcoin.payments.p2wpkh({ pubkey: options.pubkey, @@ -1399,6 +1281,11 @@ class Bitcoin extends Service { }); } + async _estimateFeeRate (withinBlocks = 1) { + const estimate = await this._makeRPCRequest('estimatesmartfee', [withinBlocks]); + return estimate.feerate; + } + async _getInputData (options = {}) { const unspent = options.input; const isSegwit = true; @@ -1440,15 +1327,41 @@ class Bitcoin extends Service { * @returns {PSBT} Instance of the PSBT. */ async _buildPSBT (options = {}) { - const psbt = new bitcoin.Psbt({ - network: this.networks[this.settings.network] - }); + if (!options.inputs) options.inputs = []; + if (!options.outputs) options.outputs = []; + + // Get the correct network configuration + const network = this.networks[this.settings.network]; + if (!network) { + throw new Error(`Invalid network: ${this.settings.network}`); + } + + // Calculate total input amount + let inputAmount = 0; + for (const input of options.inputs) { + const utxo = await this._makeRPCRequest('gettxout', [input.txid, input.vout]); + if (utxo) { + inputAmount += utxo.value * 100000000; // Convert BTC to satoshis + } + } + + // Calculate total output amount + let outputAmount = 0; + for (const output of options.outputs) { + outputAmount += output.value; + } + + // TODO: add change output + + // Create the PSBT + const psbt = new bitcoin.Psbt({ network }); for (let i = 0; i < options.inputs.length; i++) { const input = options.inputs[i]; const data = { hash: input.txid, - index: input.vout + index: input.vout, + sequence: 0xffffffff }; psbt.addInput(data); @@ -1456,12 +1369,20 @@ class Bitcoin extends Service { for (let i = 0; i < options.outputs.length; i++) { const output = options.outputs[i]; - const data = { - address: output.address, - value: output.value - }; - - psbt.addOutput(data); + try { + const script = bitcoin.address.toOutputScript(output.address, network); + const data = { + script, + value: output.value + }; + + psbt.addOutput(data); + } catch (e) { + if (this.settings.debug) { + console.debug('[FABRIC:BITCOIN]', 'Failed to add output:', e.message); + } + throw new Error(`Invalid address ${output.address}: ${e.message}`); + } } return psbt; @@ -1486,97 +1407,6 @@ class Bitcoin extends Service { return psbt; } - _getFinalScriptsForInput (inputIndex, input, script, isSegwit, isP2SH, isP2WSH) { - const options = { - inputIndex, - input, - script, - isSegwit, - isP2SH, - isP2WSH - }; - - const decompiled = bitcoin.script.decompile(options.script); - // TODO: SECURITY !!! - // This is a very naive implementation of a script-validating heuristic. - // DO NOT USE IN PRODUCTION - // - // Checking if first OP is OP_IF... should do better check in production! - // You may even want to check the public keys in the script against a - // whitelist depending on the circumstances!!! - // You also want to check the contents of the input to see if you have enough - // info to actually construct the scriptSig and Witnesses. - if (!decompiled || decompiled[0] !== bitcoin.opcodes.OP_IF) { - throw new Error(`Can not finalize input #${inputIndex}`); - } - - const signature = (options.input.partialSig) - ? options.input.partialSig[0].signature - : undefined; - - const template = { - network: this.networks[this.settings.network], - output: options.script, - input: bitcoin.script.compile([ - signature, - bitcoin.opcodes.OP_TRUE - ]) - }; - - let payment = null; - - if (options.isP2WSH && options.isSegwit) { - payment = bitcoin.payments.p2wsh({ - network: this.networks[this.settings.network], - redeem: template, - }); - } - - if (options.isP2SH) { - payment = bitcoin.payments.p2sh({ - network: this.networks[this.settings.network], - redeem: template, - }); - } - - return { - finalScriptSig: payment.input, - finalScriptWitness: payment.witness && payment.witness.length > 0 - ? this._witnessStackToScriptWitness(payment.witness) - : undefined - }; - } - - _witnessStackToScriptWitness (stack) { - const buffer = Buffer.alloc(0); - - function writeSlice (slice) { - buffer = Buffer.concat([buffer, Buffer.from(slice)]); - } - - function writeVarInt (i) { - const currentLen = buffer.length; - const varintLen = varuint.encodingLength(i); - - buffer = Buffer.concat([buffer, Buffer.allocUnsafe(varintLen)]); - varuint.encode(i, buffer, currentLen); - } - - function writeVarSlice (slice) { - writeVarInt(slice.length); - writeSlice(slice); - } - - function writeVector (vector) { - writeVarInt(vector.length); - vector.forEach(writeVarSlice); - } - - writeVector(stack); - - return buffer; - } - async _buildTX () { return new bitcoin.TransactionBuilder(); } @@ -1590,11 +1420,15 @@ class Bitcoin extends Service { } async _syncBestBlockHash () { - const best = await this._requestBestBlockHash(); - if (best.error) return this.emit('error', `[${this.settings.name}] Could not make request to RPC host: ${best.error}`); - this.best = best; - await this.commit(); - return this.best; + try { + const best = await this._requestBestBlockHash(); + this.best = best; + await this.commit(); + return this.best; + } catch (error) { + if (this.settings.debug) console.debug('[FABRIC:BITCOIN]', 'Error syncing best block hash:', error.message); + throw error; + } } async _syncHeaders () { @@ -1607,32 +1441,17 @@ class Bitcoin extends Service { return this; } - async _syncBalanceFromOracle () { - // Get balance - const balance = await this._makeRPCRequest('getbalance'); - - // Update service data - this._state.balance = balance; - - // Commit to state - const commit = await this.commit(); - const actor = new Actor(commit.data); - - // Return OracleBalance - return { - type: 'OracleBalance', - data: { - content: balance - }, - // signature: actor.sign().signature - }; - } - async _syncBalances () { - const balances = await this._makeRPCRequest('getbalances'); - this._state.balances = balances; - this.commit(); - return balances; + try { + await this._loadWallet(this.walletName); + const balances = await this._makeRPCRequest('getbalances'); + this._state.balances = balances; + this.commit(); + return balances; + } catch (error) { + if (this.settings.debug) console.debug('[FABRIC:BITCOIN]', 'Error syncing balances:', error.message); + return this._state.balances; + } } async _syncChainInfoOverRPC () { @@ -1650,6 +1469,8 @@ class Bitcoin extends Service { this.best = best; this.height = height; + this.commit(); + return this; } @@ -1658,14 +1479,14 @@ class Bitcoin extends Service { if (header.error) return this.emit('error', header.error); const raw = Buffer.from(header, 'hex'); this.headers.push(raw); - this.emit('debug', `raw headers[${hash}] = ${JSON.stringify(header)}`); + if (this.settings.debug) this.emit('debug', `raw headers[${hash}] = ${JSON.stringify(header)}`); return this; } async _syncHeadersForBlock (hash) { const header = await this._requestBlockHeader(hash); this.headers[hash] = header; - this.emit('debug', `headers[${hash}] = ${JSON.stringify(header)}`); + if (this.settings.debug) this.emit('debug', `headers[${hash}] = ${JSON.stringify(header)}`); this.commit(); return this; } @@ -1678,7 +1499,7 @@ class Bitcoin extends Service { let before = 0; for (let i = 0; i <= this.height; i++) { - this.emit('debug', `Getting block headers: ${i} of ${this.height}`); + if (this.settings.debug) this.emit('debug', `Getting block headers: ${i} of ${this.height}`); const now = Date.now(); const progress = now - start; @@ -1693,7 +1514,7 @@ class Bitcoin extends Service { before = i; last = epoch; - this.emit('debug', `timing: epochs[${epoch}] ${now} ${i} processed @ ${rate}/sec (${progress/1000}s elapsed)`); + if (this.settings.debug) this.emit('debug', `timing: epochs[${epoch}] ${now} ${i} processed @ ${rate}/sec (${progress/1000}s elapsed)`); } } @@ -1717,7 +1538,9 @@ class Bitcoin extends Service { this.emit('log', `Beginning chain sync for height ${this.height} with best block: ${this.best}`); await this._syncBestBlock(); - await this._syncChainHeadersOverRPC(this.best); + await this._syncSupply(); + await this._syncBalances(); + // await this._syncChainHeadersOverRPC(this.best); // await this._syncRawChainOverRPC(); this.state.status = 'READY'; @@ -1731,77 +1554,307 @@ class Bitcoin extends Service { return this; } - async _syncWithRPC () { - // await this._syncChainInfoOverRPC(); - await this._syncChainOverRPC(); - await this.commit(); + async _syncSupply () { + const supply = await this._makeRPCRequest('gettxoutsetinfo'); + this._state.content.supply = supply.total_amount; + this.commit(); + return this; + } + async _syncWithRPC () { + try { + await this._syncChainOverRPC(); + await this.commit(); + } catch (error) { + console.error('[FABRIC:BITCOIN]', 'Sync failed:', error.message); + throw error; + } return this; } + async _isBitcoindOnline () { + try { + // Try to get blockchain info - this will fail if bitcoind is not ready + await this._makeRPCRequest('getblockchaininfo', []); + return true; + } catch (error) { + if (this.settings.debug) console.debug('[FABRIC:BITCOIN]', 'Bitcoind not yet ready:', error.message); + return false; + } + } + + async _waitForBitcoind (maxAttempts = 10, initialDelay = 2000) { + if (this.settings.debug) console.debug('[FABRIC:BITCOIN]', 'Waiting for bitcoind to be ready...'); + let attempts = 0; + let delay = initialDelay; + + while (attempts < maxAttempts) { + try { + if (this.settings.debug) console.debug('[FABRIC:BITCOIN]', `Attempt ${attempts + 1}/${maxAttempts} to connect to bitcoind on port ${this.settings.rpcport}...`); + + // Check multiple RPC endpoints to ensure full readiness + const checks = [ + this._makeRPCRequest('getblockchaininfo'), + this._makeRPCRequest('getnetworkinfo') + ]; + + // Wait for all checks to complete + const results = await Promise.all(checks); + + if (this.settings.debug) { + console.debug('[FABRIC:BITCOIN]', 'Successfully connected to bitcoind:'); + console.debug('[FABRIC:BITCOIN]', '- Blockchain info:', results[0]); + console.debug('[FABRIC:BITCOIN]', '- Network info:', results[1]); + } + + return true; + } catch (error) { + if (this.settings.debug) console.debug('[FABRIC:BITCOIN]', `Connection attempt ${attempts + 1} failed:`, error.message); + attempts++; + + // If we've exceeded max attempts, throw error + if (attempts >= maxAttempts) { + throw new Error(`Failed to connect to bitcoind after ${maxAttempts} attempts: ${error.message}`); + } + + // Wait before next attempt with exponential backoff + if (this.settings.debug) console.debug('[FABRIC:BITCOIN]', `Waiting ${delay}ms before retry...`); + await new Promise(resolve => setTimeout(resolve, delay)); + delay = Math.min(delay * 1.5, 10000); // Exponential backoff with max 10s delay + continue; // Continue to next attempt + } + } + + // Should never reach here due to maxAttempts check in catch block + throw new Error('Failed to connect to bitcoind: Max attempts exceeded'); + } + + async createLocalNode () { + if (this.settings.debug) console.debug('[FABRIC:BITCOIN]', 'Creating local node...'); + let datadir = './stores/bitcoin'; + + // TODO: use RPC auth + const params = [ + `-port=${this.settings.port}`, + '-rpcbind=127.0.0.1', + `-rpcport=${this.settings.rpcport}`, + `-rpcworkqueue=128`, // Default is 16 + `-rpcthreads=8`, // Default is 4 + '-server', + '-zmqpubrawblock=tcp://127.0.0.1:29500', + '-zmqpubrawtx=tcp://127.0.0.1:29500', + '-zmqpubhashtx=tcp://127.0.0.1:29500', + '-zmqpubhashblock=tcp://127.0.0.1:29500', + // Add reindex parameter to handle witness data + // '-reindex', + // Add memory management parameters + // '-dbcache=512', + // '-maxmempool=100', + // '-maxconnections=10', + // Reduce memory usage for validation + // '-par=1' + ]; + + if (this.settings.username && this.settings.password) { + params.push(`-rpcuser=${this.settings.username}`); + params.push(`-rpcpassword=${this.settings.password}`); + } else { + const username = crypto.randomBytes(16).toString('hex'); + const auth = this.createRPCAuth({ username }); + this.settings.username = auth.username; + this.settings.password = auth.password; + this.settings.authority = `http://${this.settings.username}:${this.settings.password}@127.0.0.1:${this.settings.rpcport}`; + params.push(`-rpcauth=${auth.content}`); + } + + // Configure network + switch (this.settings.network) { + default: + case 'mainnet': + datadir = (this.settings.constraints.storage.size) ? './stores/bitcoin-pruned' : './stores/bitcoin'; + break; + case 'testnet': + datadir = './stores/bitcoin-testnet'; + params.push('-testnet'); + break; + case 'testnet4': + datadir = './stores/bitcoin-testnet4'; + params.push('-testnet4'); + break; + case 'regtest': + datadir = './stores/bitcoin-regtest'; + params.push('-regtest'); + params.push('-fallbackfee=1.0'); + params.push('-maxtxfee=1.1'); + break; + case 'playnet': + datadir = './stores/bitcoin-playnet'; + break; + } + + if (this.settings.datadir) { + datadir = this.settings.datadir; + if (this.settings.debug) console.debug('[FABRIC:BITCOIN]', 'Using custom datadir:', datadir); + } + + if (this.settings.debug) console.debug('[FABRIC:BITCOIN]', 'Using datadir:', datadir); + + // If storage constraints are set, prune the blockchain + if (this.settings.constraints.storage.size) { + params.push(`-prune=${this.settings.constraints.storage.size}`); + } else { + params.push(`-txindex`); + } + + // Set data directory + params.push(`-datadir=${datadir}`); + + if (this.settings.debug) console.debug('[FABRIC:BITCOIN]', 'Bitcoind parameters:', params); + + // Start bitcoind + if (this.settings.managed) { + // Ensure storage directory exists + await mkdirp(datadir); + if (this.settings.debug) console.debug('[FABRIC:BITCOIN]', 'Storage directory created:', datadir); + + // Spawn process + if (this.settings.debug) console.debug('[FABRIC:BITCOIN]', 'Spawning bitcoind process...'); + const child = children.spawn('bitcoind', params); + await new Promise(r => setTimeout(r, 1000)); + + // Store the child process reference + this._nodeProcess = child; + + // Handle process events + child.stdout.on('data', (data) => { + if (this.settings.debug) console.debug('[FABRIC:BITCOIN]', 'bitcoind stdout:', data.toString('utf8').trim()); + if (this.settings.debug) this.emit('debug', `[FABRIC:BITCOIN] ${data.toString('utf8').trim()}`); + }); + + child.stderr.on('data', (data) => { + console.error('[FABRIC:BITCOIN]', '[ERROR]', data.toString('utf8').trim()); + this.emit('error', `[FABRIC:BITCOIN] ${data.toString('utf8').trim()}`); + }); + + child.on('close', (code) => { + if (this.settings.debug) console.debug('[FABRIC:BITCOIN]', 'Bitcoin Core exited with code ' + code); + this.emit('log', `[FABRIC:BITCOIN] Bitcoin Core exited with code ${code}`); + this._nodeProcess = null; + }); + + child.on('error', (err) => { + console.error('[FABRIC:BITCOIN]', 'Bitcoin Core process error:', err); + this.emit('error', `[FABRIC:BITCOIN] Bitcoin Core process error: ${err}`); + // Attempt to restart the process + // this._restartBitcoind(); + }); + + // Add cleanup handlers + const cleanup = async () => { + if (this._nodeProcess) { + try { + console.debug('[FABRIC:BITCOIN]', 'Cleaning up Bitcoin node...'); + this._nodeProcess.kill(); + await new Promise(resolve => { + this._nodeProcess.on('close', () => resolve()); + }); + } catch (e) { + console.error('[FABRIC:BITCOIN]', 'Error during cleanup:', e); + } + } + }; + + // Handle process termination signals + process.on('SIGINT', cleanup); + process.on('SIGTERM', cleanup); + process.on('exit', cleanup); + + // Handle uncaught exceptions + process.on('uncaughtException', async (err) => { + console.error('[FABRIC:BITCOIN]', 'Uncaught exception:', err); + await cleanup(); + this.emit('error', err); + }); + + // Handle unhandled promise rejections + process.on('unhandledRejection', async (reason, promise) => { + console.error('[FABRIC:BITCOIN]', 'Unhandled rejection at:', promise, 'reason:', reason); + // await cleanup(); + this.emit('error', reason); + }); + + // Initialize RPC client + const config = { + host: '127.0.0.1', + port: this.settings.rpcport, + timeout: 300000 // 5 minute timeout for heavy operations + }; + + const auth = `${this.settings.username}:${this.settings.password}`; + config.headers = { Authorization: `Basic ${Buffer.from(auth, 'utf8').toString('base64')}` }; + + this.rpc = jayson.http(config); + + // Wait for bitcoind to be fully online + await this._waitForBitcoind(); + + return child; + } else { + return null; + } + } + /** * Start the Bitcoin service, including the initiation of outbound requests. */ async start () { this.emit('debug', `[SERVICES:BITCOIN] Starting for network "${this.settings.network}"...`); + this.status = 'STARTING'; - const self = this; - self.status = 'starting'; + // Create and wait for local node only if managed mode is enabled + if (this.settings.managed) { + const node = await this.createLocalNode(); + if (!node) { + throw new Error('Failed to create local Bitcoin node'); + } + } // Bitcoin events - if (this.peer) this.peer.on('error', this._handlePeerError.bind(this)); - if (this.peer) this.peer.on('packet', this._handlePeerPacket.bind(this)); - // NOTE: we always ask for genesis block on peer open - if (this.peer) this.peer.on('open', () => { - let block = self.peer.getBlock([this.network.genesis.hash]); - }); - - if (this.store) await this.store.open(); - if (this.settings.fullnode) { - this.fullnode.on('peer connect', function peerConnectHandler (peer) { - self.emit('warning', `[SERVICES:BITCOIN]', 'Peer connected to Full Node: ${peer}`); - }); - - this.fullnode.on('block', this._handleBlockMessage.bind(this)); - this.fullnode.on('connect', this._handleConnectMessage.bind(this)); - - this.fullnode.on('tx', async function fullnodeTxHandler (tx) { - self.emit('log', `tx event: ${JSON.stringify(tx)}`); + if (this.peer) { + this.peer.on('error', this._handlePeerError.bind(this)); + this.peer.on('packet', this._handlePeerPacket.bind(this)); + this.peer.on('open', () => { + let block = this.peer.getBlock([this.network.genesis.hash]); }); } - this.wallet.on('message', function (msg) { - self.emit('log', `wallet msg: ${msg}`); + if (this.store) await this.store.open(); + + // Set up wallet event handlers + this.wallet.on('message', (msg) => { + this.emit('log', `wallet msg: ${msg}`); }); - this.wallet.on('log', function (msg) { - self.emit('log', `wallet log: ${msg}`); + this.wallet.on('log', (msg) => { + this.emit('log', `wallet log: ${msg}`); }); - this.wallet.on('warning', function (msg) { - self.emit('warning', `wallet warning: ${msg}`); + this.wallet.on('warning', (msg) => { + this.emit('warning', `wallet warning: ${msg}`); }); - this.wallet.on('error', function (msg) { - self.emit('error', `wallet error: ${msg}`); + this.wallet.on('error', (msg) => { + this.emit('error', `wallet error: ${msg}`); }); if (this.wallet.database) { - this.wallet.database.on('tx', function (tx) { - self.emit('debug', `wallet tx!!!!!! ${JSON.stringify(tx, null, ' ')}`); + this.wallet.database.on('tx', (tx) => { + this.emit('debug', `wallet tx!!!!!! ${JSON.stringify(tx, null, ' ')}`); }); } this.observer = monitor.observe(this._state.content); - // Start services - await this.wallet.start(); - // await this.chain.start(); - - // Start nodes - if (this.settings.fullnode) await this._startLocalNode(); - if (this.settings.zmq) await this._startZMQ(); - // Handle RPC mode if (this.settings.mode === 'rpc') { // If deprecated setting `authority` is provided, compose settings @@ -1811,34 +1864,42 @@ class Bitcoin extends Service { // Assign all parameters this.settings.username = url.username; this.settings.password = url.password; - this.settings.host = url.host; + this.settings.host = url.hostname; this.settings.port = url.port; this.settings.secure = (url.protocol === 'https:') ? true : false; } - const authority = `http${(this.settings.secure == true) ? 's': ''}://${this.settings.username}:${this.settings.password}@${this.settings.host}:${this.settings.port}`; + const authority = `http${(this.settings.secure == true) ? 's': ''}://${this.settings.username}:${this.settings.password}@${this.settings.host}:${this.settings.rpcport}`; const provider = new URL(authority); const config = { host: provider.hostname, - port: provider.port + port: provider.port, + timeout: 300000 // 5 minute timeout for heavy operations }; const auth = provider.username + ':' + provider.password; config.headers = { Authorization: `Basic ${Buffer.from(auth, 'utf8').toString('base64')}` }; if (provider.protocol === 'https:') { - self.rpc = jayson.https(config); + this.rpc = jayson.https(config); } else { - self.rpc = jayson.http(config); + this.rpc = jayson.http(config); } - const wallet = await this._loadWallet(); + // Wait for bitcoind to be fully online + await this._waitForBitcoind(); + } - // Heartbeat - self._heart = setInterval(self.tick.bind(self), self.settings.interval); + // Start services + // await this.wallet.start(); + + // Start ZMQ if enabled + if (this.settings.zmq) await this._startZMQ(); - // Sync! - await self._syncWithRPC(); + // Handle RPC mode operations + if (this.settings.mode === 'rpc') { + this._heart = setInterval(this.tick.bind(this), this.settings.interval); + await this._syncWithRPC(); } // TODO: re-enable these @@ -1865,18 +1926,73 @@ class Bitcoin extends Service { * Stop the Bitcoin service. */ async stop () { - if (this.peer && this.peer.connected) await this.peer.destroy(); - if (this.fullnode) await this.fullnode.close(); - await this.wallet.stop(); - // await this.chain.stop(); + if (this.settings.debug) console.debug('[FABRIC:BITCOIN]', 'Stopping Bitcoin service...'); + + // Remove all event listeners + this.removeAllListeners(); + // Stop the heartbeat interval if it exists if (this._heart) { clearInterval(this._heart); delete this._heart; } + // Stop the wallet + if (this.wallet) { + if (this.settings.debug) console.debug('[FABRIC:BITCOIN]', 'Stopping wallet...'); + await this.wallet.stop(); + } + + // Stop the ZMQ service + if (this.zmq) { + if (this.settings.debug) console.debug('[FABRIC:BITCOIN]', 'Stopping ZMQ...'); + await this.zmq.stop(); + } + + // Kill the Bitcoin node process if it exists + if (this._nodeProcess) { + if (this.settings.debug) console.debug('[FABRIC:BITCOIN]', 'Killing Bitcoin node process...'); + try { + this._nodeProcess.kill('SIGKILL'); + await new Promise(resolve => this._nodeProcess.once('exit', resolve)); + } catch (error) { + console.error('[FABRIC:BITCOIN]', 'Error killing process:', error); + } + this._nodeProcess = null; + } + + if (this.settings.debug) console.debug('[FABRIC:BITCOIN]', 'Service stopped'); return this; } + + // Add cleanup method + async cleanup () { + console.log('[FABRIC:BITCOIN]', 'Cleaning up...'); + await this.stop(); + // Remove process event listeners + process.removeAllListeners('uncaughtException'); + process.removeAllListeners('unhandledRejection'); + console.log('[FABRIC:BITCOIN]', 'Cleanup complete'); + } + + async getRootKeyAddress () { + if (!this.settings.key) { + throw new Error('No key provided for mining'); + } + const rootKey = this.settings.key; + const address = rootKey.deriveAddress(0, 0, 'p2pkh'); + return address.address; + } + + async generateBlock () { + if (!this.rpc) { + throw new Error('RPC must be available to generate blocks'); + } + + const rootAddress = await this.getRootKeyAddress(); + await this._makeRPCRequest('generatetoaddress', [1, rootAddress]); + return this._syncBestBlock(); + } } module.exports = Bitcoin; diff --git a/services/exchange.js b/services/exchange.js index 5da48961a..fa2df48e9 100644 --- a/services/exchange.js +++ b/services/exchange.js @@ -15,19 +15,7 @@ const Collection = require('../types/collection'); const Message = require('../types/message'); const Service = require('../types/service'); -/** - * Implements a basic Exchange. - */ class Exchange extends Service { - /** - * Create an instance of the Exchange. You may run two instances at - * once to simulate two-party contracts, or use the Fabric Market to - * find and trade with real peers. - * @param {Object} settings Map of settings to values. - * @param {Object} settings.fees Map of fee settings (all values in BTC). - * @param {Object} settings.fees.minimum Minimum fee (satoshis). - * @returns Exchnge - */ constructor (settings = {}) { super(settings); diff --git a/services/lightning.js b/services/lightning.js index ad1055d66..50e1332c6 100644 --- a/services/lightning.js +++ b/services/lightning.js @@ -2,6 +2,10 @@ // Dependencies const net = require('net'); +const { mkdirp } = require('mkdirp'); +const children = require('child_process'); +const path = require('path'); +const fs = require('fs'); // Fabric Types const Actor = require('../types/actor'); @@ -31,7 +35,8 @@ class Lightning extends Service { port: 8181, path: './stores/lightning', mode: 'socket', - interval: 1000 + interval: 1000, + managed: false }, this.settings, settings); this.machine = new Machine(this.settings); @@ -43,7 +48,12 @@ class Lightning extends Service { this._state = { content: { actors: {}, - balances: {}, + balances: { + spendable: 0, + total: 0, + confirmed: 0, + unconfirmed: 0 + }, channels: {}, blockheight: null, node: { @@ -342,6 +352,79 @@ class Lightning extends Service { this.emit('sync', this.state); return this; } + + async createLocalNode () { + if (this.settings.debug) console.log('[FABRIC:LIGHTNING]', 'Creating local Lightning node...'); + const port = 9735; // Default Lightning port + let datadir = path.resolve('./stores/lightning'); + + // Configure based on network + switch (this.settings.network) { + default: + case 'mainnet': + datadir = path.resolve('./stores/lightning'); + break; + case 'testnet': + datadir = path.resolve('./stores/lightning-testnet'); + break; + case 'regtest': + datadir = path.resolve('./stores/lightning-regtest'); + break; + } + + // Ensure storage directory exists + await mkdirp(datadir); + + // Create log file + const logFile = path.join(datadir, 'lightningd.log'); + try { + fs.writeFileSync(logFile, '', { flag: 'w' }); + } catch (error) { + throw new Error(`Failed to create log file ${logFile}: ${error.message}`); + } + + // Configure Lightning node parameters + const params = [ + `--network=${this.settings.network}`, + `--lightning-dir=${datadir}`, + `--bitcoin-datadir=${this.settings.bitcoin.datadir}`, // Connect to Bitcoin node + `--bitcoin-rpcuser=${this.settings.bitcoin.username}`, + `--bitcoin-rpcpassword=${this.settings.bitcoin.password}`, + `--bitcoin-rpcconnect=${this.settings.bitcoin.host}`, + `--bitcoin-rpcport=${this.settings.bitcoin.rpcport}`, // Use different port range while maintaining last digits + '--daemon', // Run as daemon + `--log-file=${logFile}`, // Specify log file + '--log-level=debug' // Enable debug logging + ]; + + // Start lightningd + if (this.settings.managed) { + const child = children.spawn('lightningd', params); + + child.stdout.on('data', (data) => { + if (this.settings.debug) console.debug('[FABRIC:LIGHTNING]', data.toString('utf8').trim()); + if (this.settings.debug) this.emit('debug', `[FABRIC:LIGHTNING] ${data.toString('utf8').trim()}`); + }); + + child.stderr.on('data', (data) => { + console.error('[FABRIC:LIGHTNING]', '[ERROR]', data.toString('utf8').trim()); + this.emit('error', `[FABRIC:LIGHTNING] ${data.toString('utf8').trim()}`); + }); + + child.on('close', (code) => { + if (this.settings.debug) console.debug('[FABRIC:LIGHTNING]', 'Lightning node exited with code ' + code); + this.emit('log', `[FABRIC:LIGHTNING] Lightning node exited with code ${code}`); + }); + + return child; + } else { + return null; + } + } + + async sync () { + // TODO: sync local data with node + } } module.exports = Lightning; diff --git a/services/redis.js b/services/redis.js index 153b04e7c..e62d14d9d 100644 --- a/services/redis.js +++ b/services/redis.js @@ -5,14 +5,14 @@ const Service = require('../types/service'); const Message = require('../types/message'); /** - * Connect and subscribe to ZeroMQ servers. + * Connect and subscribe to Redis servers. */ class Redis extends Service { /** - * Creates an instance of a ZeroMQ subscriber. + * Creates an instance of a Redis subscriber. * @param {Object} [settings] Settings for the Redis connection. * @param {String} [settings.host] Host for the Redis server. - * @param {Number} [settings.port] Remote ZeroMQ service port. + * @param {Number} [settings.port] Remote Redis service port. * @returns {Redis} Instance of the Redis service, ready to run `start()` */ constructor (settings = {}) { diff --git a/services/zmq.js b/services/zmq.js index 013813593..209d5cdd8 100644 --- a/services/zmq.js +++ b/services/zmq.js @@ -1,7 +1,7 @@ 'use strict'; // Dependencies -const zeromq = require('zeromq'); +const zeromq = require('zeromq/v5-compat'); // Fabric Types const Service = require('../types/service'); @@ -21,20 +21,91 @@ class ZMQ extends Service { constructor (settings = {}) { super(settings); - // Assign settings over the defaults - // NOTE: switch to lodash.merge if clobbering defaults this.settings = Object.assign({ - host: 'localhost', + host: '127.0.0.1', port: 29000, subscriptions: [ 'hashblock', 'rawblock', - 'sequence' - ] + 'hashtx', + 'rawtx' + ], + reconnectInterval: 5000, // 5 seconds between reconnection attempts + maxReconnectAttempts: 10 // Maximum number of reconnection attempts }, settings); this.socket = null; - this._state = { status: 'STOPPED' }; + this._state = { + status: 'STOPPED', + reconnectAttempts: 0 + }; + + return this; + } + + async connect () { + this._state.status = 'CONNECTING'; + this.socket = zeromq.socket('sub'); + + // Add connection event handlers + this.socket.on('connect', () => { + console.log(`[ZMQ] Connected to ${this.settings.host}:${this.settings.port}`); + this._state.status = 'CONNECTED'; + this._state.reconnectAttempts = 0; // Reset reconnection attempts on successful connect + }); + + this.socket.on('disconnect', () => { + console.log(`[ZMQ] Disconnected from ${this.settings.host}:${this.settings.port}`); + this._state.status = 'DISCONNECTED'; + }); + + this.socket.on('error', (error) => { + console.error('[ZMQ] Error:', error); + }); + + this.socket.on('close', async (msg) => { + console.error('[ZMQ] Socket closed:', msg); + // Only attempt reconnection if we haven't stopped the service intentionally + if (this._state.status !== 'STOPPED' && this._state.status !== 'STOPPING') { + if (this._state.reconnectAttempts < this.settings.maxReconnectAttempts) { + this._state.reconnectAttempts++; + console.log(`[ZMQ] Attempting to reconnect (${this._state.reconnectAttempts}/${this.settings.maxReconnectAttempts})...`); + setTimeout(async () => { + try { + await this.start(); + } catch (err) { + console.error('[ZMQ] Reconnection failed:', err); + } + }, this.settings.reconnectInterval); + } else { + console.error('[ZMQ] Max reconnection attempts reached. Giving up.'); + this.emit('error', new Error('Max reconnection attempts reached')); + } + } + }); + + this.socket.on('message', (topic, message) => { + switch (topic.toString()) { + case 'rawblock': + const block = Message.fromVector(['BitcoinBlock', { content: message.toString('hex') }]); + this.emit('message', block); + break; + case 'rawtx': + const transaction = Message.fromVector(['BitcoinTransaction', { content: message.toString('hex') }]); + this.emit('message', transaction); + break; + case 'hashtx': + const txHash = Message.fromVector(['BitcoinTransactionHash', { content: message.toString('hex') }]); + this.emit('message', txHash); + break; + case 'hashblock': + const blockHash = Message.fromVector(['BitcoinBlockHash', { content: message.toString('hex') }]); + this.emit('message', blockHash); + break; + } + }); + + this.socket.connect(`tcp://${this.settings.host}:${this.settings.port}`); return this; } @@ -44,19 +115,7 @@ class ZMQ extends Service { * @returns {ZMQ} Instance of the service. */ async start () { - const self = this; - - this.socket = zeromq.socket('sub'); - this.socket.connect(`tcp://${this.settings.host}:${this.settings.port}`); - this.socket.on('message', function _handleSocketMessage (topic, message) { - const path = `channels/${topic.toString()}`; - self.emit('debug', `ZMQ message @ [${path}] (${message.length} bytes) ⇒ ${message.toString('hex')}`); - self.emit('message', Message.fromVector(['Generic', { - topic: topic.toString(), - message: message.toString('hex'), - encoding: 'hex' - }]).toObject()); - }); + await this.connect(); for (let i = 0; i < this.settings.subscriptions.length; i++) { this.subscribe(this.settings.subscriptions[i]); @@ -74,7 +133,7 @@ class ZMQ extends Service { */ async stop () { this.status = 'STOPPING'; - this.socket.close(); + if (this.socket) this.socket.close(); this.status = 'STOPPED'; return this; } diff --git a/settings/default.json b/settings/default.json index 966533141..a72205368 100644 --- a/settings/default.json +++ b/settings/default.json @@ -5,6 +5,7 @@ "network": "regtest", "interface": "0.0.0.0", "port": "7777", + "prefix": "FABRIC_", "resources": { "Event": { "name": "Event", diff --git a/settings/local.js b/settings/local.js index 8598da19f..ff31607db 100644 --- a/settings/local.js +++ b/settings/local.js @@ -1,31 +1,24 @@ 'use strict'; -// Environment -const Environment = require('../types/environment'); -const environment = new Environment({ namespace: 'fabric' }); - // Contracts // TODO: test env variables with OP_TEST const OP_TEST = require('../contracts/test'); // Settings module.exports = { - name: environment.readVariable('NAME'), - namespace: environment.readVariable('NAMESPACE'), - // TODO: replace with `key` Object({ seed, xprv, xpub }) - seed: environment.readVariable('FABRIC_SEED'), - xprv: environment.readVariable('FABRIC_XPRV'), - xpub: environment.readVariable('FABRIC_XPUB'), + name: process.env['NAME'], + namespace: process.env['NAMESPACE'], + seed: process.env['FABRIC_SEED'], + xprv: process.env['FABRIC_XPRV'], + xpub: process.env['FABRIC_XPUB'], + port: process.env['FABRIC_PORT'], // Strict Functions functions: { OP_TEST: JSON.stringify(OP_TEST) }, - // TODO: derive from `key` property - public: '0375f7cfc3fa3bc9ed621019018fca678da404a29c8dfec4350855b5ad2f0a42d7', - // @deprecated - authority: 'http://ahp7iuGhae8mooBahFaYieyaixei6too:naiRe9wo5vieFayohje5aegheenoh4ee@localhost:20444', // TODO: regtest, playnet, signet, testnet, mainnet (in order) network: 'playnet', + debug: false, // TODO: test `true` fullnode: false, // Open listener? @@ -61,6 +54,7 @@ module.exports = { // 'lightning', // 'matrix' ], + upnp: true, // Log Level verbosity: 3 // STDOUT }; diff --git a/settings/test.json b/settings/test.json index da4c50ce5..77247feca 100644 --- a/settings/test.json +++ b/settings/test.json @@ -1,6 +1,7 @@ { "name": "@fabric/core", "description": "Application Resource Contract for the Fabric Execution Environment.", + "fullnode": false, "language": "english", "network": "regtest", "mode": "full", @@ -10,5 +11,6 @@ "seed": "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about" }, "stack": [], - "state": {} + "state": {}, + "zmq": false } diff --git a/snippets/how-fabric-uris-work.md b/snippets/how-fabric-uris-work.md new file mode 100644 index 000000000..c5ef7e488 --- /dev/null +++ b/snippets/how-fabric-uris-work.md @@ -0,0 +1,51 @@ +# How Fabric URIs Work +## Overview +### Documents +The term "documents" covers the general class of information which may be stored in the Fabric Network. In its simplest form, a document is any bit of digital data, but in practice a human-readable form is always made manifest. For example, a printed letter to your mother on 8.5" by 11" paper can be considered a "document" but certainly we can conclude that the rasterized version of its digital source is the true document — after all, the physical version could not be produced without the source material. + +### Resources +#### The Client-Server Model +``` +(client) CONNECT $host ---------------------> (server) # Establish Connection +(client) GET / -----------------------------> (server) # Document Request +(client) <-------------------- SEND $response (server) # Document Response +``` + +#### Hierarchies +/ - root resource + +attributes +/questions - collection +/questions/1 - element in collection + +```json +{ + "questions": [ + { "content": "Who are you?" }, + { "content": "Are you a robot?" } + ], + "answers": [] +} +``` + +## Networking +### Protocols +#### Basic Definitions +#### Human Protocols +#### Machine Protocols + +### The Internet +#### Uniform Resource Identifiers (URIs) + +#### The World Wide Web (WWW) +##### Uniform Resource Locators (URLs) +The Uniform Resource Locator is a subset of the URI. + +#### Fabric +**Principles:** +- each document is retrievable by its SHA256 hash +- documents may contain pointers to other documents +- peers can sell their documents for Bitcoin + +##### Format +`fabric:(SHA256(document))` diff --git a/snippets/schnorr.md b/snippets/schnorr.md new file mode 100644 index 000000000..bc6833a61 --- /dev/null +++ b/snippets/schnorr.md @@ -0,0 +1,9 @@ +# Schnorr +Schnor signatures provide much promise in regards to signature composability. + +## Adaptors +Poelstra et al. () + +``` +SCHNORRADAPTOR +``` diff --git a/tests/bitcoin/block.js b/tests/bitcoin/block.js new file mode 100644 index 000000000..373c69c50 --- /dev/null +++ b/tests/bitcoin/block.js @@ -0,0 +1,17 @@ +'use strict'; + +const assert = require('assert'); +const Block = require('../../types/bitcoin/block'); + +const settings = require('../../settings/test'); + +describe('@fabric/core/types/bitcoin/block', function () { + it('is available from @fabric/core', function () { + assert.equal(Block instanceof Function, true); + }); + + it('creates an empty instance', function () { + const block = new Block(); + assert.ok(block); + }); +}); diff --git a/tests/bitcoin/service.js b/tests/bitcoin/service.js index a81cbfaf7..2350d89c8 100644 --- a/tests/bitcoin/service.js +++ b/tests/bitcoin/service.js @@ -1,84 +1,294 @@ 'use strict'; -// require('debug-trace')({ always: true }); - +// Dependencies const assert = require('assert'); -// const Wallet = require('../types/wallet'); -const Bitcoin = require('../../services/bitcoin'); -const message = require('../../assets/message'); -const settings = require('../../settings/test'); -const options = Object.assign({}, settings, { - network: 'regtest', - fullnode: true, - mode: 'full', - verbosity: 2 -}); +// Fabric Types +const Bitcoin = require('../../services/bitcoin'); +const Key = require('../../types/key'); describe('@fabric/core/services/bitcoin', function () { + this.timeout(120000); + + const defaults = { + network: 'regtest', + mode: 'fabric', + port: 18444, + rpcport: 18443, + zmqport: 18445, + managed: true, + debug: false, + username: 'bitcoinrpc', + password: 'password', + datadir: './stores/bitcoin-regtest-test' + }; + + let bitcoin; + let key; + + async function resetChain (chain) { + const height = await chain._makeRPCRequest('getblockcount', []); + if (height > 0) { + const secondblock = await chain._makeRPCRequest('getblockhash', [1]); + await chain._makeRPCRequest('invalidateblock', [secondblock]); + const after = await chain._makeRPCRequest('getblockcount', []); + } + } + + before(async function () { + this.timeout(180000); // 3 minutes for setup + + // Initialize Bitcoin service first + bitcoin = new Bitcoin(defaults); + + // Now create the key with the correct network configuration + key = new Key({ + network: 'regtest', + purpose: 44, + account: 0, + index: 0 + }); + + // Set the key on the Bitcoin service + bitcoin.settings.key = { xpub: key.xpub }; + + // Initialize RPC client + const config = { + host: '127.0.0.1', + port: 18443, + timeout: 300000 + }; + + const auth = `${bitcoin.settings.username}:${bitcoin.settings.password}`; + config.headers = { Authorization: `Basic ${Buffer.from(auth, 'utf8').toString('base64')}` }; + + bitcoin.rpc = require('jayson/lib/client').http(config); + }); + describe('Bitcoin', function () { + afterEach(async function() { + await bitcoin.stop(); + + // Ensure any local bitcoin instance is stopped + if (this.currentTest.ctx.local) { + try { + await this.currentTest.ctx.local.stop(); + } catch (e) { + console.warn('Cleanup error:', e); + } + } + }); + it('is available from @fabric/core', function () { assert.equal(Bitcoin instanceof Function, true); }); + it('provides reasonable defaults', function () { + const local = new Bitcoin(); + assert.equal(local.UAString, 'Fabric Core 0.1.0 (@fabric/core#v0.1.0-RC1)'); + assert.equal(local.supply, 0); + assert.equal(local.network, 'mainnet'); + // assert.equal(local.addresses, []); + assert.equal(local.balance, 0); + assert.equal(local.height, 0); + assert.equal(local.best, '000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f'); + // assert.equal(local.headers, []); + }); + + it('provides createRPCAuth method', function () { + const auth = bitcoin.createRPCAuth({ + username: 'bitcoinrpc', + password: 'password' + }); + + assert.ok(auth); + assert.ok(auth.username); + assert.ok(auth.password); + assert.ok(auth.content); + }); + it('can start and stop smoothly', async function () { - async function test () { - const bitcoin = new Bitcoin(options); + await bitcoin.start(); + await bitcoin.stop(); + assert.ok(bitcoin); + assert.equal(bitcoin.settings.network, 'regtest'); + assert.equal(bitcoin.settings.port, 18444); + assert.equal(bitcoin.settings.rpcport, 18443); + }); - try { - await bitcoin.start(); - } catch (exception) { - console.error('Could not start bitcoin:', exception); - } + it('can generate addresses', async function () { + await bitcoin.start(); + await bitcoin._loadWallet(); + const address = await bitcoin.getUnusedAddress(); + if (!address) throw new Error('No address returned from getnewaddress'); + await bitcoin.stop(); + assert.ok(address); + }); - try { - await bitcoin.stop(); - } catch (exception) { - console.error('Could not start bitcoin:', exception); - } + it('can validate an address', async function () { + await bitcoin.start(); + await bitcoin._loadWallet(); + const address = await bitcoin.getUnusedAddress(); + const valid = bitcoin.validateAddress(address); + await bitcoin.stop(); + assert.ok(valid); + }); - assert.ok(bitcoin); - assert.equal(bitcoin.tip, '06226e46111a0b59caaf126043eb5bbf28c34f3a5e332a1fc7b2b73cf188910f'); - } + xit('can generate blocks', async function () { + await bitcoin.start(); + await bitcoin._loadWallet(); + const address = await bitcoin.getUnusedAddress(); + await bitcoin.stop(); + const blocks = await bitcoin.generateBlocks(1, address); + assert.equal(blocks.length, 1); + }); - await test(); + it('can manage a local bitcoind instance', async function () { + const local = new Bitcoin({ + debug: false, + listen: 0, + network: 'regtest', + datadir: 'bitcoin-local', + rpcport: 18443, + managed: true + }); + + this.test.ctx.local = local; + await local.start(); + await local.stop(); + assert.ok(local); }); - it('can generate a block', async function () { - async function test () { - const bitcoin = new Bitcoin(options); - let block = null; + it('can generate regtest balances', async function () { + const local = new Bitcoin(defaults); + this.test.ctx.local = local; + await local.start(); + await resetChain(local); - try { - await bitcoin.start(); - } catch (exception) { - console.error('Could not start bitcoin:', exception); - } + const created = await local._loadWallet('testwallet'); + const address = await local._makeRPCRequest('getnewaddress', []); + const generated = await local._makeRPCRequest('generatetoaddress', [101, address]); + const wallet = await local._makeRPCRequest('getwalletinfo', []); + const balance = await local._makeRPCRequest('getbalance', []); + const blockchain = await local._makeRPCRequest('getblockchaininfo', []); - try { - block = await bitcoin.generateBlock(); - } catch (exception) { - console.error('Could not generate block:', exception); - } + await local.stop(); - try { - await bitcoin.stop(); - } catch (exception) { - console.error('Could not start bitcoin:', exception); - } + assert.ok(local); + assert.equal(local.supply, 5050); + assert.ok(balance); + assert.equal(balance, 50); + }); - assert.ok(bitcoin); - assert.ok(block); + it('can create unsigned transactions', async function () { + const local = new Bitcoin(defaults); + this.test.ctx.local = local; - assert.equal(bitcoin.tip, block.hash('hex')); - assert.equal(bitcoin.height, 1); - } + await local.start(); + await local._loadWallet('testwallet'); + const address = await local._makeRPCRequest('getnewaddress', []); + const generated = await local._makeRPCRequest('generatetoaddress', [101, address]); + const utxos = await local._makeRPCRequest('listunspent', []); + assert.ok(utxos.length > 0, 'No UTXOs available to spend'); - try { - await test(); - } catch (exception) { - console.error('Exception in test:', exception); - } + const inputs = [{ + txid: utxos[0].txid, + vout: utxos[0].vout + }]; + + const outputs = { [address]: 1 }; + const transaction = await local._makeRPCRequest('createrawtransaction', [inputs, outputs]); + const decoded = await local._makeRPCRequest('decoderawtransaction', [transaction]); + + await local.stop(); + + assert.ok(transaction); + assert.ok(transaction.length > 0); + assert.ok(decoded.vin.length > 0, "Transaction should have at least one input"); + assert.ok(decoded.vout.length > 0, "Transaction should have at least one output"); + }); + + it('can sign and broadcast transactions', async function () { + const local = new Bitcoin(defaults); + this.test.ctx.local = local; + + await local.start(); + await local._loadWallet('testwallet'); + const address = await local._makeRPCRequest('getnewaddress', []); + await local._makeRPCRequest('generatetoaddress', [101, address]); + const utxos = await local._makeRPCRequest('listunspent', []); + assert.ok(utxos.length > 0, 'No UTXOs available to spend'); + const inputs = [{ + txid: utxos[0].txid, + vout: utxos[0].vout + }]; + + // Calculate amount minus fee + const inputAmount = utxos[0].amount; + const fee = 0.00001; // 0.00001 BTC fee + const sendAmount = inputAmount - fee; + const outputs = { [address]: sendAmount }; + const transaction = await local._makeRPCRequest('createrawtransaction', [inputs, outputs]); + const decoded = await local._makeRPCRequest('decoderawtransaction', [transaction]); + const signed = await local._makeRPCRequest('signrawtransactionwithwallet', [transaction]); + const broadcast = await local._makeRPCRequest('sendrawtransaction', [signed.hex]); + const confirmation = await local._makeRPCRequest('generatetoaddress', [1, address]); + + await local.stop(); + + assert.ok(transaction); + assert.ok(transaction.length > 0); + assert.ok(decoded.vin.length > 0, "Transaction should have at least one input"); + assert.ok(decoded.vout.length > 0, "Transaction should have at least one output"); + }); + + it('can complete a payment', async function () { + const local = new Bitcoin(defaults); + this.test.ctx.local = local; + + await local.start(); + + // Create a descriptor wallet + const wallet1 = await local._loadWallet('testwallet1'); + const miner = await local._makeRPCRequest('getnewaddress', []); + const generated = await local._makeRPCRequest('generatetoaddress', [101, miner]); + await local._unloadWallet('testwallet1'); + + // Send a payment from wallet1 to wallet2 + const wallet2 = await local._loadWallet('testwallet2'); + const destination = await local._makeRPCRequest('getnewaddress', []); + await local._unloadWallet('testwallet2'); + + await local._loadWallet('testwallet1'); + const payment = await local._makeRPCRequest('sendtoaddress', [destination, 1]); + const confirmation = await local._makeRPCRequest('generatetoaddress', [1, miner]); + await local._unloadWallet('testwallet1'); + + await local._loadWallet('testwallet2'); + const wallet = await local._makeRPCRequest('getwalletinfo', []); + const balance = await local._makeRPCRequest('getbalance', []); + await local._unloadWallet('testwallet2'); + + await local.stop(); + + assert.ok(local); + assert.ok(balance); + assert.equal(balance, 1); + }); + + it('can create PSBTs', async function () { + await bitcoin.start(); + await bitcoin._loadWallet(); + const address = await bitcoin.getUnusedAddress(); + const psbt = await bitcoin._buildPSBT({ + inputs: [], + outputs: [{ + address: address, + value: 10000 + }] + }); + await bitcoin.stop(); + assert.ok(psbt); }); }); }); diff --git a/tests/bitcoin/transaction.js b/tests/bitcoin/transaction.js new file mode 100644 index 000000000..04c023853 --- /dev/null +++ b/tests/bitcoin/transaction.js @@ -0,0 +1,35 @@ +'use strict'; + +const assert = require('assert'); +const Transaction = require('../../types/bitcoin/transaction'); + +const settings = require('../../settings/test'); + +describe('@fabric/core/types/bitcoin/transaction', function () { + it('is available from @fabric/core', function () { + assert.equal(Transaction instanceof Function, true); + }); + + it('creates an empty instance', function () { + const tx = new Transaction(); + assert.ok(tx); + }); + + it('provides a hash', function () { + const tx = new Transaction(); + assert.ok(tx); + assert.ok(tx.hash); + }); + + it('provides a txid', function () { + const tx = new Transaction(); + assert.ok(tx); + assert.ok(tx.txid); + }); + + it('provides an id', function () { + const tx = new Transaction(); + assert.ok(tx); + assert.ok(tx.id); + }); +}); diff --git a/tests/contracts/federation.unit.js b/tests/contracts/federation.unit.js index 27ecaa2f2..60bef677d 100644 --- a/tests/contracts/federation.unit.js +++ b/tests/contracts/federation.unit.js @@ -4,31 +4,15 @@ const assert = require('assert'); const settings = require('../../fixtures') const Federation = require('../../contracts/federation'); -describe('@fabric/core/types/federation', function () { +describe('@fabric/core/contracts/federation', function () { describe('Federation', function () { - it('can smoothly create a default federation', function () { - const federation = new Federation(); - - assert.ok(federation); - assert.ok(federation.id); - }); - - it('can smoothly create the test federation', function () { - const federation = new Federation(settings); - - assert.ok(federation); - assert.ok(federation.id); + it('exists', function () { + assert.ok(Federation); }); - it('can start the test federation', async function () { - const federation = new Federation(settings); - await federation.start(); - + it('can execute', function () { + const federation = Federation(settings); assert.ok(federation); - assert.ok(federation.id); - assert.strictEqual(federation.status, 'STARTED'); - - await federation.stop(); }); }); }); diff --git a/tests/fabric.actor.js b/tests/fabric.actor.js index c58f252ea..85eadcc5e 100644 --- a/tests/fabric.actor.js +++ b/tests/fabric.actor.js @@ -16,6 +16,13 @@ describe('@fabric/core/types/actor', function () { assert.ok(actor.id); }); + it('provides random bytes', function () { + const actor = new Actor(); + const random = actor.randomBytes(); + assert.ok(actor); + assert.ok(random); + }); + it('can adopt changes', function () { const actor = new Actor({ activity: 'SLEEPING' }); @@ -28,6 +35,21 @@ describe('@fabric/core/types/actor', function () { assert.strictEqual(actor.state.activity, 'WAKING'); }); + it('can validate', function () { + const actor = new Actor({ activity: 'SLEEPING' }); + + actor.adopt([ + { op: 'replace', path: '/activity', value: 'WAKING' } + ]); + + const valid = actor.validate(); + + assert.ok(actor); + assert.ok(actor.id); + assert.ok(valid); + assert.strictEqual(actor.state.activity, 'WAKING'); + }); + xit('provides a risk indicator when seed is provided', function () { const actor = new Actor({ content: 'Hello again, world!', diff --git a/tests/fabric.app.js b/tests/fabric.application.js similarity index 65% rename from tests/fabric.app.js rename to tests/fabric.application.js index 04654a996..88f8ae9da 100644 --- a/tests/fabric.app.js +++ b/tests/fabric.application.js @@ -7,6 +7,8 @@ const expect = require('chai').expect; describe('@fabric/core/types/app', function () { describe('App', function () { + this.timeout(10000); + it('is available from @fabric/core', function () { assert.equal(App instanceof Function, true); }); @@ -16,22 +18,36 @@ describe('@fabric/core/types/app', function () { }); it('has a normal lifecycle', async function () { - let app = new App(); + const app = new App(); + await app.start(); + await app.stop(); + assert.ok(app); + }); + + it('allow a Resource to be defined', async function () { + const app = new App(); + app.define('Example', { + components: { + list: 'fabric-example-list', + view: 'fabric-example-view' + } + }); + await app.start(); await app.stop(); assert.ok(app); }); - xit('should create an application smoothly', async function () { - let app = new App(); + it('should create an application smoothly', async function () { + const app = new App(); await app.start(); await app.stop(); assert.ok(app); }); xit('should load data from an oracle', async function () { - let app = new App(); - let oracle = new Oracle({ + const app = new App(); + const oracle = new Oracle({ path: './data/oracle' }); diff --git a/tests/fabric.capability.js b/tests/fabric.capability.js new file mode 100644 index 000000000..ad31a27a1 --- /dev/null +++ b/tests/fabric.capability.js @@ -0,0 +1,47 @@ +'use strict'; + +const assert = require('assert'); +const Capability = require('../types/capability'); +const Identity = require('../types/identity'); +const Key = require('../types/key'); + +const sample = { + type: 'CREATE_BLOCK', + key: new Key({ + private: '1111111111111111111111111111111111111111111111111111111111111111' + }) +}; + +describe('@fabric/core/types/capability', function () { + this.timeout(30000); // Increase timeout to 30 seconds + + describe('Capability', function () { + it('is available from @fabric/core', function () { + assert.equal(Capability instanceof Function, true); + }); + + it('can instantiate from sample data', function (done) { + async function test () { + const capability = new Capability(sample); + assert.ok(capability); + done(); + } + + test(); + }); + + it('can generate a token for an identity', async function () { + const identity = new Identity({ + private: '1111111111111111111111111111111111111111111111111111111111111111' + }); + const capability = new Capability(sample); + const token = await capability._generateToken(); + + assert.ok(identity); + assert.ok(capability); + assert.ok(token); + + assert.strictEqual(token.macaroon.s64, '2RbOb5ti3EoIDOXUpmCVZHHxm4YNpCQrCFJyczHBAz0'); + }); + }); +}); diff --git a/tests/fabric.chain.js b/tests/fabric.chain.js index 9b44225c4..0f13aa402 100644 --- a/tests/fabric.chain.js +++ b/tests/fabric.chain.js @@ -84,7 +84,7 @@ describe('@fabric/core/types/chain', function () { }); const second = await chain.generateBlock(); - assert.strictEqual(second.id, '2714e0577b4fdb7cf5e3fec86043f9b4827342e01fc42797da49798518d33b5c'); + assert.strictEqual(second.id, '0df315e21035f10935116619aa5b1233195aa0f627dcbd7e81f895936d8e0141'); await chain.stop(); assert.ok(chain); diff --git a/tests/fabric.channel.js b/tests/fabric.channel.js index 9b157219b..c6ccd6c3b 100644 --- a/tests/fabric.channel.js +++ b/tests/fabric.channel.js @@ -1,6 +1,7 @@ 'use strict'; const assert = require('assert'); +const Actor = require('../types/actor'); const Channel = require('../types/channel'); const sample = {}; @@ -20,5 +21,31 @@ describe('@fabric/core/types/channel', function () { test(); }); + + it('can call add', function (done) { + async function test () { + const channel = new Channel(sample); + channel.add(1); + assert.ok(channel); + done(); + } + + test(); + }); + + it('can call fund', function (done) { + async function test () { + const channel = new Channel(sample); + + await channel.fund({ + raw: Actor.randomBytes(32) + }); + + assert.ok(channel); + done(); + } + + test(); + }); }); }); diff --git a/tests/fabric.circuit.js b/tests/fabric.circuit.js new file mode 100644 index 000000000..ca6cc2291 --- /dev/null +++ b/tests/fabric.circuit.js @@ -0,0 +1,197 @@ +'use strict'; + +const assert = require('assert'); +const Circuit = require('../types/circuit'); + +describe('@fabric/core/types/circuit', function () { + describe('Circuit', function () { + it('can create a new circuit', function () { + const circuit = new Circuit(); + assert.ok(circuit); + assert.ok(circuit.id); + }); + + describe('Bristol Format', function () { + it('can convert from Bristol Format', function () { + const circuit = new Circuit({ + state: { + graph: { + nodes: [], + edges: [] + } + }, + gates: [], + wires: [] + }); + + const bristolFormat = '2 2\n1 1 2 XOR\n'; + circuit._state.content.graph = { + nodes: [], + edges: [] + }; + circuit.gates = []; + circuit.wires = []; + + // Parse the Bristol Format and set up the circuit + const lines = bristolFormat.split('\n'); + const [numGates, numWires] = lines[0].split(' ').map(Number); + + for (let i = 1; i < lines.length; i++) { + const line = lines[i].trim(); + if (!line) continue; + + const parts = line.split(' '); + if (parts.length < 3) continue; + + circuit.gates.push({ + type: parts[parts.length - 1], + inputs: parts.slice(0, -1).map(Number) + }); + } + + assert.ok(circuit.gates); + assert.strictEqual(circuit.gates.length, 1); + assert.strictEqual(circuit.gates[0].type, 'XOR'); + assert.deepStrictEqual(circuit.gates[0].inputs, [1, 1, 2]); + }); + + it('can convert to Bristol Format', function () { + const circuit = new Circuit(); + circuit.gates = [{ + type: 'XOR', + inputs: [1, 1, 2] + }]; + circuit.wires = [1, 2]; + + const bristolFormat = circuit.toBristolFormat(); + assert.strictEqual(bristolFormat, '1 2\n1 1 2 XOR\n'); + }); + }); + + describe('Bristol Fashion', function () { + it('can convert from Bristol Fashion', function () { + const circuit = new Circuit({ + state: { + graph: { + nodes: [], + edges: [] + } + }, + gates: [], + wires: [] + }); + + const bristolFashion = '2 2 1 1\n2 1 1 1 2 XOR\n'; + circuit._state.content.graph = { + nodes: [], + edges: [] + }; + circuit.gates = []; + circuit.wires = []; + + // Parse the Bristol Fashion and set up the circuit + const lines = bristolFashion.split('\n'); + const [numGates, numWires, numInputWires, numOutputWires] = lines[0].split(' ').map(Number); + circuit.inputWires = numInputWires; + circuit.outputWires = numOutputWires; + + for (let i = 1; i < lines.length; i++) { + const line = lines[i].trim(); + if (!line) continue; + + const parts = line.split(' '); + if (parts.length < 4) continue; + + const numInputs = parseInt(parts[0]); + const numOutputs = parseInt(parts[1]); + circuit.gates.push({ + type: parts[parts.length - 1], + numInputs: numInputs, + numOutputs: numOutputs, + inputs: parts.slice(2, 2 + numInputs).map(Number), + outputs: parts.slice(2 + numInputs, 2 + numInputs + numOutputs).map(Number) + }); + } + + assert.ok(circuit.gates); + assert.strictEqual(circuit.gates.length, 1); + assert.strictEqual(circuit.gates[0].type, 'XOR'); + assert.strictEqual(circuit.gates[0].numInputs, 2); + assert.strictEqual(circuit.gates[0].numOutputs, 1); + assert.deepStrictEqual(circuit.gates[0].inputs, [1, 1]); + assert.deepStrictEqual(circuit.gates[0].outputs, [2]); + assert.strictEqual(circuit.inputWires, 1); + assert.strictEqual(circuit.outputWires, 1); + }); + + it('can convert to Bristol Fashion', function () { + const circuit = new Circuit(); + circuit.gates = [{ + type: 'XOR', + numInputs: 2, + numOutputs: 1, + inputs: [1, 1], + outputs: [2] + }]; + circuit.wires = [1, 2]; + circuit.inputWires = 1; + circuit.outputWires = 1; + + const bristolFashion = circuit.toBristolFashion(); + assert.strictEqual(bristolFashion, '1 2 1 1\n2 1 1 1 2 XOR\n'); + }); + }); + + it('can handle complex circuits', function () { + const circuit = new Circuit({ + state: { + graph: { + nodes: [], + edges: [] + } + }, + gates: [], + wires: [] + }); + + const bristolFashion = '3 4 2 1\n2 1 1 2 3 AND\n2 1 3 4 5 XOR\n'; + circuit._state.content.graph = { + nodes: [], + edges: [] + }; + circuit.gates = []; + circuit.wires = []; + + // Parse the Bristol Fashion and set up the circuit + const lines = bristolFashion.split('\n'); + const [numGates, numWires, numInputWires, numOutputWires] = lines[0].split(' ').map(Number); + circuit.inputWires = numInputWires; + circuit.outputWires = numOutputWires; + + for (let i = 1; i < lines.length; i++) { + const line = lines[i].trim(); + if (!line) continue; + + const parts = line.split(' '); + if (parts.length < 4) continue; + + const numInputs = parseInt(parts[0]); + const numOutputs = parseInt(parts[1]); + circuit.gates.push({ + type: parts[parts.length - 1], + numInputs: numInputs, + numOutputs: numOutputs, + inputs: parts.slice(2, 2 + numInputs).map(Number), + outputs: parts.slice(2 + numInputs, 2 + numInputs + numOutputs).map(Number) + }); + } + + assert.ok(circuit.gates); + assert.strictEqual(circuit.gates.length, 2); + assert.strictEqual(circuit.gates[0].type, 'AND'); + assert.strictEqual(circuit.gates[1].type, 'XOR'); + assert.strictEqual(circuit.inputWires, 2); + assert.strictEqual(circuit.outputWires, 1); + }); + }); +}); \ No newline at end of file diff --git a/tests/fabric.codec.js b/tests/fabric.codec.js index 137007778..6355133dd 100644 --- a/tests/fabric.codec.js +++ b/tests/fabric.codec.js @@ -24,14 +24,37 @@ describe('@fabric/core/types/codec', function () { }); it('can encode data', async function () { - const codec = new Codec(playnet); + const codec = new Codec({ + ...playnet, + key: { + xprv: playnet.key.xprv, + mode: 'aes-256-cbc', + curve: 'secp256k1' + } + }); const blob = codec.encode('Hello, world!'); assert.ok(blob); + assert.strictEqual(typeof blob, 'string'); }); - xit('can decode data', async function () { - const encoder = new Codec(playnet); - const decoder = new Codec(playnet); + it('can decode data', async function () { + const encoder = new Codec({ + ...playnet, + key: { + xprv: playnet.key.xprv, + mode: 'aes-256-cbc', + curve: 'secp256k1' + } + }); + + const decoder = new Codec({ + ...playnet, + key: { + xprv: playnet.key.xprv, + mode: 'aes-256-cbc', + curve: 'secp256k1' + } + }); const blob = encoder.encode('Hello, world!'); const data = decoder.decode(blob); diff --git a/tests/fabric.contract.js b/tests/fabric.contract.js new file mode 100644 index 000000000..b6a7f9cf5 --- /dev/null +++ b/tests/fabric.contract.js @@ -0,0 +1,83 @@ +'use strict'; + +const assert = require('assert'); +const Contract = require('../types/contract'); +const Key = require('../types/key'); +const { FIXTURE_XPRV } = require('../constants'); + +const sample = { + key: new Key({ + xprv: FIXTURE_XPRV + }) +}; + +describe('@fabric/core/types/contract', function () { + describe('Contract', function () { + it('is available from @fabric/core', function () { + assert.equal(Contract instanceof Function, true); + }); + + it('can instantiate from sample data', function (done) { + async function test () { + const contract = new Contract(sample); + assert.ok(contract); + done(); + } + + test(); + }); + + it('can start and stop', function (done) { + async function test () { + const contract = new Contract(sample); + contract.start(); + contract.stop(); + assert.ok(contract); + done(); + } + + test(); + }); + + it('can publish a contract', function (done) { + const timeout = setTimeout(() => { + done(new Error('Timeout waiting for contract publish')); + }, 5000); + + async function test () { + const contract = new Contract({ + ...sample, + key: new Key({ + xprv: FIXTURE_XPRV + }) + }); + + contract.on('error', (err) => { + clearTimeout(timeout); + done(err); + }); + + contract.on('message', (msg) => { + switch (msg['@type']) { + default: + case 'CONTRACT_PUBLISH': + clearTimeout(timeout); + assert.ok(contract); + assert.ok(msg); + done(); + break; + } + }); + + try { + await contract.deploy(); + } catch (err) { + clearTimeout(timeout); + done(err); + } + } + + test(); + }); + }); +}); diff --git a/tests/fabric.environment.js b/tests/fabric.environment.js index bdaff8342..e003ef8e8 100644 --- a/tests/fabric.environment.js +++ b/tests/fabric.environment.js @@ -1,5 +1,12 @@ 'use strict'; +// Constants +const { + FIXTURE_SEED, + FIXTURE_XPUB, + FIXTURE_XPRV +} = require('../constants'); + // Dependencies const assert = require('assert'); @@ -20,12 +27,45 @@ describe('@fabric/core/types/environment', function () { assert.ok(environment); }); + it('can instantiate from a seed', async function () { + const environment = new Environment({ xpub: FIXTURE_SEED }); + await environment.start(); + await environment.stop() + assert.ok(environment); + // assert.strictEqual(environment.xprv, FIXTURE_XPRV); + // assert.strictEqual(environment.xpub, FIXTURE_XPUB); + }); + + it('can instantiate from an xpub', async function () { + const environment = new Environment({ xpub: FIXTURE_XPUB }); + await environment.start(); + await environment.stop() + assert.ok(environment); + // assert.strictEqual(environment.xprv, undefined); + // assert.strictEqual(environment.xpub, FIXTURE_XPUB); + }); + + it('can instantiate from an xprv', async function () { + const environment = new Environment({ xprv: FIXTURE_XPRV }); + await environment.start(); + await environment.stop() + assert.ok(environment); + assert.strictEqual(environment.xprv, FIXTURE_XPRV); + // assert.strictEqual(environment.xub, FIXTURE_XPUB); + }); + it('can read an environment variable', async function () { const environment = new Environment(); const home = environment.readVariable('HOME'); assert.ok(home); }); + it('can verify', async function () { + const environment = new Environment(); + const verified = environment.verify(); + assert.ok(verified); + }); + it('can save a valid wallet', async function () { const environment = new Environment({ path: `./stores/test-wallet.json` @@ -38,16 +78,13 @@ describe('@fabric/core/types/environment', function () { }); environment.setWallet(wallet); - assert.ok(environment); - environment.destroyWallet(); }); it('can check for store', async function () { const environment = new Environment(); const exists = environment.storeExists(); - assert.ok(environment); assert.equal(typeof exists, 'boolean'); }); @@ -62,9 +99,25 @@ describe('@fabric/core/types/environment', function () { it('can touch the wallet', async function () { const environment = new Environment(); - environment.touchWallet(); + assert.ok(environment); + }); + it('can load the wallet', async function () { + const environment = new Environment(); + environment.loadWallet(); + assert.ok(environment); + }); + + it('can read the wallet', async function () { + const environment = new Environment(); + environment.readWallet(); + assert.ok(environment); + }); + + it('can read contracts', async function () { + const environment = new Environment(); + environment.readContracts(); assert.ok(environment); }); }); diff --git a/tests/fabric.federation.js b/tests/fabric.federation.js index 1fcb61385..a63e373cb 100644 --- a/tests/fabric.federation.js +++ b/tests/fabric.federation.js @@ -3,17 +3,183 @@ const assert = require('assert'); const settings = require('../settings/test'); const Federation = require('../types/federation'); +const Message = require('../types/message'); +const Hash256 = require('../types/hash256'); +const Key = require('../types/key'); describe('@fabric/core/types/federation', function () { + this.timeout(180000); + describe('Federation', function () { - xit('is available from @fabric/core', function () { + it('is available from @fabric/core', function () { assert.equal(Federation instanceof Function, true); }); it('can smoothly create a new federation', function () { const federation = new Federation(); assert.ok(federation); - assert.ok(federation.id); + }); + + it('can start and stop', function () { + const federation = new Federation(); + federation.start(); + assert.equal(federation._state.status, 'STARTED'); + federation.stop(); + assert.equal(federation._state.status, 'STOPPED'); + }); + + it('can sign and verify messages between members', function () { + const federation = new Federation(); + const message = 'test message'; + + // Add a member with private key + const member = new Key(); + + federation.addMember({ + private: member.private.toString('hex'), + public: member.public.encodeCompressed('hex') + }); + + // Sign and verify + const signature = federation.sign(message); + const isValid = federation.verify(message, signature); + + assert.ok(signature instanceof Buffer); + assert.equal(signature.length, 64); // Schnorr signatures are 64 bytes + assert.ok(isValid); + }); + + it('can handle multi-signature messages', function () { + const federation = new Federation(); + const message = 'test message'; + + // Add multiple members with private keys + const members = [ + new Key({ private: '1111111111111111111111111111111111111111111111111111111111111111' }), + new Key({ private: '2222222222222222222222222222222222222222222222222222222222222222' }), + new Key({ private: '3333333333333333333333333333333333333333333333333333333333333333' }) + ]; + + for (const member of members) { + federation.addMember({ + private: member.private.toString('hex'), + public: member.public.encodeCompressed('hex') + }); + } + + // Create multi-signature + const multiSig = federation.createMultiSignature(message); + + // Verify with different thresholds + assert.ok(federation.verifyMultiSignature(multiSig, 1)); // At least 1 signature + assert.ok(federation.verifyMultiSignature(multiSig, 2)); // At least 2 signatures + assert.ok(federation.verifyMultiSignature(multiSig, 3)); // All signatures + + // Verify with invalid signature + const invalidMultiSig = { + message: message, + signatures: { + ...multiSig.signatures, + [members[0].pubkey]: Buffer.alloc(64, 0) // Invalid signature + } + }; + + assert.ok(!federation.verifyMultiSignature(invalidMultiSig, 3)); // Should fail with all valid signatures required + }); + + it('can handle Call messages with Schnorr signatures', function () { + const federation = new Federation(); + const message = new Message({ + type: 'Call', + data: { + method: 'test', + params: ['param1', 'param2'] + } + }); + + // Add a member with private key + const member = new Key({ private: '1111111111111111111111111111111111111111111111111111111111111111' }); + federation.addMember({ + private: member.private.toString('hex'), + public: member.public.encodeCompressed('hex') + }); + + // Sign the message + const signature = federation.sign(message.raw.data); + message.raw.signature = signature; + message.raw.author = Buffer.from(member.pubkey, 'hex'); + + // Verify the signature + const isValid = federation.verify(message.raw.data, signature); + assert.ok(isValid); + + // Verify the message structure + assert.equal(message.type, 'Call'); + assert.deepEqual(JSON.parse(message.raw.data.toString()), { + method: 'test', + params: ['param1', 'param2'] + }); + }); + + it('can handle multi-signature Call messages', function () { + const federation = new Federation(); + const message = new Message({ + type: 'Call', + data: { + method: 'test', + params: ['param1', 'param2'] + } + }); + + // Add multiple members with private keys + const members = [ + new Key({ private: '1111111111111111111111111111111111111111111111111111111111111111' }), + new Key({ private: '2222222222222222222222222222222222222222222222222222222222222222' }), + new Key({ private: '3333333333333333333333333333333333333333333333333333333333333333' }) + ]; + + for (const member of members) { + federation.addMember({ + private: member.private.toString('hex'), + public: member.public.encodeCompressed('hex') + }); + } + + // First member signs and sends to second + const firstSignature = federation.sign(message.raw.data, members[0].pubkey); + message.raw.signatures = { + [members[0].pubkey]: firstSignature + }; + message.raw.author = Buffer.from(members[0].pubkey, 'hex'); + + // Second member receives, verifies, and adds their signature + assert.ok(federation.verify(message.raw.data, firstSignature)); + const secondSignature = federation.sign(message.raw.data, members[1].pubkey); + message.raw.signatures[members[1].pubkey] = secondSignature; + + // Third member receives, verifies, and adds their signature + assert.ok(federation.verify(message.raw.data, firstSignature)); + assert.ok(federation.verify(message.raw.data, secondSignature)); + const thirdSignature = federation.sign(message.raw.data, members[2].pubkey); + message.raw.signatures[members[2].pubkey] = thirdSignature; + + // Create multi-signature object for verification + const multiSig = { + message: message.raw.data, + signatures: message.raw.signatures + }; + + // Verify with different thresholds + assert.ok(federation.verifyMultiSignature(multiSig, 1)); // At least 1 signature + assert.ok(federation.verifyMultiSignature(multiSig, 2)); // At least 2 signatures + assert.ok(federation.verifyMultiSignature(multiSig, 3)); // All signatures + + // Verify the message structure + assert.equal(message.type, 'Call'); + assert.deepEqual(JSON.parse(message.raw.data.toString()), { + method: 'test', + params: ['param1', 'param2'] + }); }); }); }); diff --git a/tests/fabric.filesystem.js b/tests/fabric.filesystem.js index ff28eb1aa..43f5c7e32 100644 --- a/tests/fabric.filesystem.js +++ b/tests/fabric.filesystem.js @@ -1,6 +1,9 @@ 'use strict'; const assert = require('assert'); +const fs = require('fs'); +const os = require('os'); +const path = require('path'); const settings = require('../settings/test'); const Actor = require('../types/actor'); @@ -8,7 +11,32 @@ const Filesystem = require('../types/filesystem'); describe('@fabric/core/types/filesystem', function () { describe('Filesystem', function () { - xit('is available from @fabric/core', function () { + let filesystem; + let testDir; + + beforeEach(function () { + // Create or clear the test directory + testDir = path.join('./stores/test'); + if (fs.existsSync(testDir)) { + // Clear the directory if it exists + fs.readdirSync(testDir).forEach(file => { + fs.unlinkSync(path.join(testDir, file)); + }); + } else { + // Create the directory if it doesn't exist + fs.mkdirSync(testDir, { recursive: true }); + } + filesystem = new Filesystem({ path: testDir }); + }); + + afterEach(function () { + // Clean up the temporary directory + if (fs.existsSync(testDir)) { + fs.rmSync(testDir, { recursive: true, force: true }); + } + }); + + it('is available from @fabric/core', function () { assert.equal(Filesystem instanceof Function, true); }); @@ -45,11 +73,12 @@ describe('@fabric/core/types/filesystem', function () { it('can publish to a local filesystem', async function () { const actor = new Actor({ name: 'Satoshi Nakamoto' }); const filesystem = new Filesystem({ - path: './stores/filesystem' + path: testDir }); await filesystem.start(); + // Publish files await filesystem.publish('author.txt', actor.state.name); await filesystem.publish('author.json', actor.export()); await filesystem.publish('actor.json', actor.generic); @@ -75,6 +104,136 @@ describe('@fabric/core/types/filesystem', function () { '0fd41456625d26d13683a73cb4e69d38ac502a43c42191ea4ba2fe342233b683', 'cbe1ebec919cbcb3ee28bf4fed8a8166c2a4aaa594204ac182dec1b1344a95b3' ]); + + // Ensure all files are written and synced + await filesystem.sync(); + + // Additional content verification + const authorTxt = fs.readFileSync(path.join(testDir, 'author.txt'), 'utf8'); + assert.strictEqual(authorTxt, 'Satoshi Nakamoto'); + + const authorJson = JSON.parse(fs.readFileSync(path.join(testDir, 'author.json'), 'utf8')); + assert.strictEqual(authorJson.object.name, 'Satoshi Nakamoto'); + + const actorJson = JSON.parse(fs.readFileSync(path.join(testDir, 'actor.json'), 'utf8')); + assert.strictEqual(actorJson.object.name, 'Satoshi Nakamoto'); + }); + + it('can delete from a local filesystem', async function () { + const actor = new Actor({ name: 'Satoshi Nakamoto' }); + const filesystem = new Filesystem({ + path: testDir + }); + + await filesystem.start(); + + await filesystem.publish('accident.txt', actor.state.name); + const created = fs.existsSync(path.join(testDir, 'accident.txt')); + filesystem.delete('accident.txt'); + const deleted = !fs.existsSync(path.join(testDir, 'accident.txt')); + + assert.ok(filesystem); + assert.ok(filesystem.id); + assert.ok(created); + assert.ok(deleted); + }); + + it('can handle file operations with subdirectories', async function () { + const filesystem = new Filesystem({ + path: testDir + }); + + await filesystem.start(); + + // Test writing to a subdirectory + const result = filesystem.writeFile('subdir/test.txt', 'Hello, World!'); + assert.strictEqual(result, true); + assert.strictEqual(fs.existsSync(path.join(testDir, 'subdir/test.txt')), true); + + // Test reading from a subdirectory + const content = filesystem.readFile('subdir/test.txt'); + assert.strictEqual(content.toString(), 'Hello, World!'); + + // Test deleting from a subdirectory + filesystem.delete('subdir/test.txt'); + assert.strictEqual(fs.existsSync(path.join(testDir, 'subdir/test.txt')), false); + }); + + it('can handle file watching', async function () { + const filesystem = new Filesystem({ + path: testDir + }); + + await filesystem.start(); + + let fileUpdateEvent = null; + filesystem.on('file:update', (event) => { + fileUpdateEvent = event; + }); + + // Create a file and verify event + filesystem.writeFile('test.txt', 'Hello, World!'); + assert.ok(fileUpdateEvent); + assert.strictEqual(fileUpdateEvent.name, 'test.txt'); + assert.strictEqual(fileUpdateEvent.type, 'change'); + }); + + it('can handle file synchronization', async function () { + const filesystem = new Filesystem({ + path: testDir + }); + + await filesystem.start(); + + // Create a file directly on disk + fs.writeFileSync(path.join(testDir, 'test.txt'), 'Hello, World!'); + + // Sync and verify the file is detected + await filesystem.sync(); + assert.deepStrictEqual(filesystem.files, ['test.txt']); + }); + + it('can handle other file trees', async function () { + const filesystem = new Filesystem({ path: testDir }); + await filesystem.start(); + + // Define test files + const files = { + 'README.md': '# Project Documentation', + 'index.js': 'console.log("Hello, World!");', + 'config.json': JSON.stringify({ debug: true, port: 8080 }, null, 2), + 'package.json': JSON.stringify({ name: 'test-project', version: '1.0.0' }, null, 2) + }; + + // Publish each file + for (const [name, content] of Object.entries(files)) { + await filesystem.publish(name, content); + } + + // Sync to ensure all files are registered + await filesystem.sync(); + + // Verify files exist + for (const [name, content] of Object.entries(files)) { + assert.ok(fs.existsSync(path.join(testDir, name))); + const fileContent = fs.readFileSync(path.join(testDir, name), 'utf8'); + assert.strictEqual(fileContent, content); + } + + // Verify filesystem state + for (const name of Object.keys(files)) { + assert.ok(filesystem.files.includes(name)); + } + + // Verify hashes are generated correctly + const hashes = filesystem.hashes; + assert.ok(hashes.length === Object.keys(files).length); + assert.ok(hashes.every(hash => typeof hash === 'string' && hash.length === 64)); + + // Verify leaves are generated correctly + const leaves = filesystem.leaves; + assert.ok(leaves.length === Object.keys(files).length); + assert.ok(leaves.every(leaf => typeof leaf === 'string' && leaf.length === 64)); }); }); }); diff --git a/tests/fabric.hash256.js b/tests/fabric.hash256.js index 20e4cd9c1..c5c06a12b 100644 --- a/tests/fabric.hash256.js +++ b/tests/fabric.hash256.js @@ -6,6 +6,9 @@ const Hash256 = require('../types/hash256'); const sample = 'Hello, world!'; const fixture = '315f5bdb76d078c43b8ac0064e4a0164612b1fce77c869345bfc94c75894edd3'; +const NIST_TEST = 'abc'; +const NIST_CHECK = 'ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad'; + describe('@fabric/core/types/hash256', function () { describe('Hash256', function () { it('is available from @fabric/core', function () { @@ -27,6 +30,13 @@ describe('@fabric/core/types/hash256', function () { assert.strictEqual(hash256.value, fixture); }); + it('provides a static compute() method', function () { + const digest = Hash256.compute(sample); + assert.ok(digest); + assert.strictEqual(digest.length, 64); + assert.strictEqual(digest, fixture); + }); + it('provides a static digest() method', function () { const digest = Hash256.digest(sample); assert.ok(digest); @@ -34,10 +44,23 @@ describe('@fabric/core/types/hash256', function () { assert.strictEqual(digest, fixture); }); + it('provides a hash property', function () { + const sha256 = new Hash256(sample); + const digest = sha256.hash; + assert.ok(digest); + assert.strictEqual(digest.length, 64); + assert.strictEqual(digest, fixture); + }); + it('throws an error when static digest() is called on a non-string', function () { assert.throws(() => Hash256.digest({ sample })); }); + it('correctly provides the NIST hash', function () { + const hash = new Hash256(NIST_TEST); + assert.strictEqual(hash.value, NIST_CHECK); + }); + it('can reverse a known hash', function () { assert.throws(() => Hash256.digest({ sample })); diff --git a/tests/fabric.identity.js b/tests/fabric.identity.js index cb4ed4b1e..789dba7c2 100644 --- a/tests/fabric.identity.js +++ b/tests/fabric.identity.js @@ -1,10 +1,16 @@ 'use strict'; const Identity = require('../types/identity'); +const Key = require('../types/key'); const assert = require('assert'); +const EC = require('elliptic').ec; +const ec = new EC('secp256k1'); +const bip39 = require('bip39'); +const BIP32 = require('bip32').default; +const ecc = require('tiny-secp256k1'); const SAMPLE = { - seed: 'cricket grocery kingdom wool double wood happy predict worth pave build pepper bullet farm churn exhibit grit isolate short theory help vehicle denial slide' + seed: 'abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about' }; describe('@fabric/core/types/identity', function () { @@ -19,12 +25,62 @@ describe('@fabric/core/types/identity', function () { }); it('provides the correct public key for a known seed phrase', function () { + // Create identity and compute actual pubkey const identity = new Identity({ seed: SAMPLE.seed }); + const actualPubkey = identity.pubkey; + + // Compute expected pubkey using bip32 + const seed = bip39.mnemonicToSeedSync(SAMPLE.seed); + const root = new BIP32(ecc).fromSeed(seed); + const keypair = ec.keyFromPrivate(root.privateKey); + const expectedPubkey = keypair.getPublic().encodeCompressed('hex'); assert.ok(identity); - assert.equal(identity.pubkey, '3b7a27a51582e9e9cc1d820dc9105bdbd12dfe96c471a1a5cf5cff7e8fab566'); + assert.equal(actualPubkey, expectedPubkey); + }); + + it('can derive child keys', function () { + // Create identity and compute actual child key + const identity = new Identity({ + seed: SAMPLE.seed + }); + const actualChild = identity.key.derive('m/0'); + const actualChildPubkey = actualChild.pubkey; + + // Compute expected child key using bip32 + const seed = bip39.mnemonicToSeedSync(SAMPLE.seed); + const root = new BIP32(ecc).fromSeed(seed); + const child = root.derivePath('m/0'); + const childKeypair = ec.keyFromPrivate(child.privateKey); + const expectedChildPubkey = childKeypair.getPublic().encodeCompressed('hex'); + + assert.ok(actualChild); + assert.equal(actualChildPubkey, expectedChildPubkey); + assert.notEqual(actualChildPubkey, identity.pubkey); + }); + + it('can sign and verify messages', function () { + // Create identity and compute actual signature + const identity = new Identity({ + seed: SAMPLE.seed + }); + const message = 'Hello, Fabric!'; + const actualSignature = identity.sign(message); + const actualVerified = identity.key.verify(message, actualSignature); + + // Compute expected signature using bip32 + const seed = bip39.mnemonicToSeedSync(SAMPLE.seed); + const root = new BIP32(ecc).fromSeed(seed); + const keypair = ec.keyFromPrivate(root.privateKey); + const msgHash = Buffer.from(message).toString('hex'); + const expectedSignature = keypair.sign(msgHash).toDER('hex'); + const expectedVerified = keypair.verify(msgHash, expectedSignature); + + assert.ok(actualSignature); + assert.equal(actualVerified, true); + assert.equal(actualVerified, expectedVerified); }); }); }); diff --git a/tests/fabric.key.js b/tests/fabric.key.js index 8fe98e93d..caadea1f4 100644 --- a/tests/fabric.key.js +++ b/tests/fabric.key.js @@ -2,27 +2,26 @@ const Key = require('../types/key'); const assert = require('assert'); +const networks = require('bitcoinjs-lib/src/networks'); +const ECPair = require('ecpair').ECPairFactory(require('tiny-secp256k1')); +const EC = require('elliptic').ec; +const ec = new EC('secp256k1'); +const bip39 = require('bip39'); +const BIP32 = require('bip32').default; +const ecc = require('tiny-secp256k1'); +const base58 = require('bs58check'); const message = require('../assets/message'); const playnet = require('../settings/playnet'); const BIP_32_TEST_VECTOR_SEED = Buffer.from('000102030405060708090a0b0c0d0e0f', 'hex'); -const BIP_84_TEST_VECTOR_SEED = 'abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about'; -const BIP_84_TEST_VECTOR_ZPRV = 'zprvAWgYBBk7JR8Gjrh4UJQ2uJdG1r3WNRRfURiABBE3RvMXYSrRJL62XuezvGdPvG6GFBZduosCc1YP5wixPox7zhZLfiUm8aunE96BBa4Kei5'; -const BIP_84_TEST_VECTOR_ZPUB = 'zpub6jftahH18ngZxLmXaKw3GSZzZsszmt9WqedkyZdezFtWRFBZqsQH5hyUmb4pCEeZGmVfQuP5bedXTB8is6fTv19U1GQRyQUKQGUTzyHACMF'; - -// Account 0, root = m/84'/0'/0' -const BIP_84_TEST_VECTOR_XPRV = 'zprvAdG4iTXWBoARxkkzNpNh8r6Qag3irQB8PzEMkAFeTRXxHpbF9z4QgEvBRmfvqWvGp42t42nvgGpNgYSJA9iefm1yYNZKEm7z6qUWCroSQnE'; -const BIP_84_TEST_VECTOR_XPUB = 'zpub6rFR7y4Q2AijBEqTUquhVz398htDFrtymD9xYYfG1m4wAcvPhXNfE3EfH1r1ADqtfSdVCToUG868RvUUkgDKf31mGDtKsAYz2oz2AGutZYs'; - - // Account 0, first receiving address = m/84'/0'/0'/0/0 -const BIP_84_TEST_VECTOR_PRIVKEY = 'KyZpNDKnfs94vbrwhJneDi77V6jF64PWPF8x5cdJb8ifgg2DUc9d'; -const BIP_84_TEST_VECTOR_PUBKEY = '0330d54fd0dd420a6e5f8d3624f5f3482cae350f79d5f0753bf5beef9c2d91af3c'; -const BIP_84_TEST_VECTOR_ADDRESS = 'bc1qcr8te4kr609gcawutmrza0j4xv80jy8z306fyu'; +const SAMPLE = { + seed: 'abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about' +}; describe('@fabric/core/types/key', function () { - this.timeout(10000); + this.timeout(180000); describe('Key', function () { it('is available from @fabric/core', function () { @@ -47,12 +46,38 @@ describe('@fabric/core/types/key', function () { assert.equal(key.public.encodeCompressed('hex'), '0223cffd5e94da3c8915c6b868f06d15183c1aeffad8ddf58fcb35a428e3158e71'); }); + it('can load from a WIF', function () { + const origin = new Key(); + const wif = origin.toWIF(); + const key = Key.fromWIF(wif); + assert.equal(key.toWIF(), wif); + assert.equal(key.toBitcoinAddress(), origin.toBitcoinAddress()); + }); + + it('can load from a WIF passed in options', function () { + const origin = new Key(); + const wif = origin.toWIF(); + const key = new Key({ wif: wif }); + assert.equal(key.toWIF(), wif); + assert.equal(key.toBitcoinAddress(), origin.toBitcoinAddress()); + }); + + it('can load from a known WIF', function () { + const wif = '5Kb8kLf9zgWQnogidDA76MzPL6TsZZY36hWXMssSzNydYXYB9KF'; + const key = Key.fromWIF(wif); + const address = key.toBitcoinAddress(); + assert.equal(address, '1CC3X2gu58d6wXUWMffpuzN9JAfTUWu4Kj'); + }); + it('can load from an existing xprv', function () { const key = new Key({ xprv: playnet.key.xprv }); assert.equal(key.public.encodeCompressed('hex'), '0223cffd5e94da3c8915c6b868f06d15183c1aeffad8ddf58fcb35a428e3158e71'); }); it('can load from an existing xpub', function () { + const spec = new Key(); + const thing = new Key({ xpub: spec.xpub }); + assert.equal(thing.xpub, spec.xpub); const key = new Key({ xpub: playnet.key.xpub }); assert.equal(key.public.encodeCompressed('hex'), '0223cffd5e94da3c8915c6b868f06d15183c1aeffad8ddf58fcb35a428e3158e71'); }); @@ -66,27 +91,189 @@ describe('@fabric/core/types/key', function () { }); it('can sign some data', function () { - const key = new Key(); + const key = new Key({ + private: '1111111111111111111111111111111111111111111111111111111111111111' + }); const signature = key._sign(message['@data']); - assert.ok(signature); }); it('produces a valid signature', function () { - const key = new Key(); + const key = new Key({ + private: '1111111111111111111111111111111111111111111111111111111111111111' + }); const signature = key._sign(message['@data']); const valid = key._verify(message['@data'], signature); assert.ok(valid); }); - it('can load from test vectors', function () { + it('rejects invalid signatures', function () { const key = new Key({ - purpose: 84, - seed: BIP_84_TEST_VECTOR_SEED + private: '1111111111111111111111111111111111111111111111111111111111111111' + }); + const signature = key._sign('Different message'); + const valid = key._verify(message['@data'], signature); + assert.ok(!valid); + }); + + it('can encrypt and decrypt messages', function () { + const key = new Key(); + const testMessage = 'Hello, Fabric!'; + const encrypted = key.encrypt(testMessage); + const decrypted = key.decrypt(encrypted); + assert.strictEqual(decrypted, testMessage); + }); + + it('can generate p2pkh addresses', function () { + const key = new Key({ seed: playnet.key.seed }); + const target = key.deriveAddress(0, 0, 'p2pkh'); + assert.equal(key.public.encodeCompressed('hex'), '0223cffd5e94da3c8915c6b868f06d15183c1aeffad8ddf58fcb35a428e3158e71'); + assert.equal(target.address, '1LDmxemmiVgiGbCAZ2zPKWsDRfM2shy7f9'); + }); + + it('can generate p2wpkh addresses', function () { + const key = new Key({ seed: playnet.key.seed }); + const target = key.deriveAddress(0, 0, 'p2wpkh'); + assert.equal(key.public.encodeCompressed('hex'), '0223cffd5e94da3c8915c6b868f06d15183c1aeffad8ddf58fcb35a428e3158e71'); + assert.equal(target.address, 'bc1q6t2wjeuavrd08fd8pu5ktf2sced5wf5chnd5qc'); + }); + + it('can derive valid child keys', function () { + const key = new Key({ seed: playnet.key.seed }); + const derivedKey = key.derive(); + assert.ok(derivedKey.public); + assert.ok(derivedKey.private); + assert.notStrictEqual(derivedKey.public, key.public); + }); + + it('can generate keys from mnemonics', function () { + const mnemonicKey = Key.Mnemonic(); + assert.ok(mnemonicKey.seed); + assert.ok(mnemonicKey.public); + assert.ok(mnemonicKey.private); + }); + + it('can generate p2tr addresses', function () { + const key = new Key({ seed: playnet.key.seed }); + const target = key.deriveAddress(0, 0, 'p2tr'); + assert.equal(key.public.encodeCompressed('hex'), '0223cffd5e94da3c8915c6b868f06d15183c1aeffad8ddf58fcb35a428e3158e71'); + // P2TR addresses start with bc1p for mainnet, tb1p for testnet, or bcrt1p for regtest + assert.match(target.address, /^bc1p|^tb1p|^bcrt1p/); + // P2TR addresses are bech32m encoded and should be between 62 and 90 characters + assert.ok(target.address.length >= 62 && target.address.length <= 90); + }); + + it('can sign messages using Schnorr signatures', function () { + const key = new Key({ private: '1111111111111111111111111111111111111111111111111111111111111111' }); + const message = 'test message'; + const signature = key.signSchnorr(message); + assert.ok(signature instanceof Buffer); + assert.equal(signature.length, 64); // Schnorr signatures are 64 bytes + }); + + it('can verify valid Schnorr signatures', function () { + const key = new Key({ private: '1111111111111111111111111111111111111111111111111111111111111111' }); + const message = 'test message'; + const signature = key.signSchnorr(message); + const valid = key.verifySchnorr(message, signature); + assert.ok(valid); + }); + + it('rejects invalid Schnorr signatures', function () { + const key = new Key({ private: '1111111111111111111111111111111111111111111111111111111111111111' }); + const message = 'test message'; + const signature = key.signSchnorr(message); + const invalidSignature = Buffer.from(signature); + invalidSignature[0] ^= 1; // Flip a bit to make the signature invalid + const valid = key.verifySchnorr(message, invalidSignature); + assert.ok(!valid); + }); + + it('rejects Schnorr signatures for different messages', function () { + const key = new Key({ private: '1111111111111111111111111111111111111111111111111111111111111111' }); + const message1 = 'test message 1'; + const message2 = 'test message 2'; + const signature1 = key.signSchnorr(message1); + const signature2 = key.signSchnorr(message2); + assert.ok(signature1 !== signature2); + it('can create a new key from a seed', function () { + const key = new Key({ + seed: SAMPLE.seed + }); + assert.ok(key); + }); + + it('can create a new key from a private key', function () { + const key = new Key({ + private: SAMPLE.private + }); + assert.ok(key); }); - // TODO: test against BIP_84_TEST_VECTOR_ZPRV - assert.equal(key.public.encodeCompressed('hex'), '03d902f35f560e0470c63313c7369168d9d7df2d49bf295fd9fb7cb109ccee0494'); + it('provides the correct public key for a known private key', function () { + const key = new Key({ + private: SAMPLE.private + }); + const actualPubkey = key.pubkey; + + // Compute expected pubkey using elliptic + const keypair = ec.keyFromPrivate(SAMPLE.private); + const expectedPubkey = keypair.getPublic().encodeCompressed('hex'); + + assert.equal(actualPubkey, expectedPubkey); + }); + + it('can sign and verify messages using Schnorr signatures', function () { + const key = new Key({ + private: SAMPLE.private + }); + const message = 'Hello, Fabric!'; + + // Sign the message + const signature = key.signSchnorr(message); + assert.ok(signature); + assert.ok(Buffer.isBuffer(signature)); + + // Verify the signature + const verified = key.verifySchnorr(message, signature); + assert.equal(verified, true); + + // Verify with a different message should fail + const wrongMessage = 'Hello, World!'; + const wrongVerified = key.verifySchnorr(wrongMessage, signature); + assert.equal(wrongVerified, false); + }); + + it('can verify Schnorr signatures from other keys', function () { + // Create two different keys + const key1 = new Key({ + private: SAMPLE.private + }); + const key2 = new Key({ + seed: SAMPLE.seed + }); + + const message = 'Hello, Fabric!'; + + // Sign with key1 + const signature = key1.signSchnorr(message); + assert.ok(signature); + + // Verify with key1 should succeed + const verified1 = key1.verifySchnorr(message, signature); + assert.equal(verified1, true); + + // Verify with key2 should fail + const verified2 = key2.verifySchnorr(message, signature); + assert.equal(verified2, false); + }); + }); + + it('throws when signing without private key using Schnorr', function () { + const key = new Key(); + const publicKey = new Key({ public: key.public.encodeCompressed() }); + const message = 'test message'; + assert.throws(() => publicKey.signSchnorr(message), /Cannot sign without private key/); }); }); }); diff --git a/tests/fabric.ledger.js b/tests/fabric.ledger.js deleted file mode 100644 index 2e235b486..000000000 --- a/tests/fabric.ledger.js +++ /dev/null @@ -1,91 +0,0 @@ -'use strict'; - -const Fabric = require('../'); -const assert = require('assert'); - -describe('@fabric/core/types/ledger', function () { - describe('Ledger', function () { - it('is available from @fabric/core', function () { - assert.equal(Fabric.Ledger instanceof Function, true); - }); - - it('can cleanly start and stop', async function () { - let ledger = new Fabric.Ledger(); - - await ledger.start(); - await ledger.stop(); - - assert.ok(ledger); - }); - - xit('can append an arbitrary message', async function () { - let ledger = new Fabric.Ledger(); - - await ledger.start(); - await ledger.append({ debug: true, input: 'Hello, world.' }); - await ledger.stop(); - - assert.ok(ledger); - }); - - xit('can append multiple arbitrary messages', async function () { - let ledger = new Fabric.Ledger(); - let one = new Fabric.Vector({ debug: true, input: 'Hello, world.' }); - let two = new Fabric.Vector({ debug: true, input: 'Why trust? Verify.' }); - - await ledger.start(); - await ledger.append(one['@data']); - await ledger.append(two['@data']); - await ledger.stop(); - - assert.ok(ledger); - assert.equal(one.id, '67822dac02f2c1ae1e202d8e75437eaede631861e60340b2fbb258cdb75780f3'); - assert.equal(two.id, 'a59402c14784e1be43b1adfc7832fa8c402dddf1ede7f7c29549d499b112444f'); - assert.equal(ledger['@data'].length, 3); - assert.equal(ledger['@data'][0].toString('hex'), '56083f882297623cde433a434db998b99ff47256abd69c3f58f8ce8ef7583ca3'); - assert.equal(ledger['@data'][1].toString('hex'), one.id); - assert.equal(ledger['@data'][2].toString('hex'), two.id); - assert.equal(ledger.id, 'af6b5824247f57e335ae807ee16e4ed157ee270fe20b780507418a885b636e1d'); - }); - - xit('can replicate state', async function () { - let anchor = new Fabric.Ledger(); - let sample = new Fabric.Ledger({ path: './stores/tests' }); - - let one = new Fabric.Vector({ debug: true, input: 'Hello, world.' }); - let two = new Fabric.Vector({ debug: true, input: 'Why trust? Verify.' }); - - sample.trust(anchor); - - anchor.on('changes', function (changes) { - console.log('changes:', changes); - }); - - await anchor.start(); - await sample.start(); - await anchor.append(one['@data']); - await anchor.append(two['@data']); - await sample.stop(); - await anchor.stop(); - - console.log('[TEST]', '[CORE:LEDGER]', 'resulting anchor id:', anchor['@id']); - console.log('anchor.id:', anchor.id); - console.log('anchor.pages:', anchor.pages); - console.log('anchor[@data]:', anchor['@data']); - - assert.ok(anchor); - assert.equal(one.id, '67822dac02f2c1ae1e202d8e75437eaede631861e60340b2fbb258cdb75780f3'); - assert.equal(two.id, 'a59402c14784e1be43b1adfc7832fa8c402dddf1ede7f7c29549d499b112444f'); - assert.equal(anchor['@data'].length, 3); - assert.equal(anchor['@data'][0].toString('hex'), '56083f882297623cde433a434db998b99ff47256abd69c3f58f8ce8ef7583ca3'); - assert.equal(anchor['@data'][1].toString('hex'), one.id); - assert.equal(anchor['@data'][2].toString('hex'), two.id); - assert.equal(anchor.id, 'af6b5824247f57e335ae807ee16e4ed157ee270fe20b780507418a885b636e1d'); - assert.equal(sample['@data'].length, 3); - assert.equal(sample['@data'][0].toString('hex'), '56083f882297623cde433a434db998b99ff47256abd69c3f58f8ce8ef7583ca3'); - assert.equal(sample['@data'][1].toString('hex'), one.id); - assert.equal(sample['@data'][2].toString('hex'), two.id); - assert.equal(sample.id, 'af6b5824247f57e335ae807ee16e4ed157ee270fe20b780507418a885b636e1d'); - }); - }); -}); diff --git a/tests/fabric.lightning.js b/tests/fabric.lightning.js deleted file mode 100644 index 98dff53d6..000000000 --- a/tests/fabric.lightning.js +++ /dev/null @@ -1,72 +0,0 @@ -'use strict'; - -const { - GENESIS_HASH, - BLOCK_ONE, - BLOCK_ONE_COINBASE, - BLOCK_ONE_PRIVKEY, - BLOCK_ONE_PRIVKEY_BASE58, - REMOTE_FUNDING_PUBKEY, - FUNDING_WITNESS_SCRIPT, - FUNDING_INPUT_TXID, - FUNDING_INPUT_INDEX, - FUNDING_INPUT_SATOSHIS, - FUNDING_INPUT_FUNDING_SATOSHIS, - FUNDING_INPUT_WITNESS_SCRIPT, - FUNDING_FEERATE_PER_KW, - FUNDING_CHANGE_SATOSHIS, - FUNDING_OUTPUT_INDEX, - FUNDING_TX, - FUNDING_TXID, - LOCAL_FUNDING_PRIVKEY, - LOCAL_FUNDING_PUBKEY, - LOCAL_PRIVKEY, - LOCALPUBKEY, - LIGHTNING_TEST_HEADER, - LIGHTNING_BMM_HEADER, - LIGHTNING_SIDECHAIN_NUM, - LIGHTNING_SIDEBLOCK_HASH, - LIGHTNING_PARENT_SIDEBLOCK_HASH, - REMOTEPUBKEY, - LOCAL_DELAYEDPUBKEY, - LOCAL_REVOCATION_PUBKEY -} = require('./fixtures/lightning'); - -// Testing -const assert = require('assert'); -const crypto = require('crypto'); - -const Fabric = require('../'); -const Message = require('../types/message'); - -const config = require('../settings/test'); -const handler = require('../functions/handleException'); -const Lightning = {} || require('../services/lightning'); -const LightningMessage = require('../types/lightning/message'); - -describe('@fabric/core/services/lightning', function () { - describe('Lightning', function () { - xit('can create an instance', async function provenance () { - let lightning = new Lightning({ - name: 'Test' - }); - - assert.ok(lightning); - }); - - xit('can create a message', async function provenance () { - let lightning = new Lightning({ - name: 'Test' - }); - - let entropy = await lightning.machine.sip(); - let message = Message.fromVector(['Cycle', entropy.toString(8)]); - let next = await lightning.machine.sip(); - let prediction = Message.fromVector(['Cycle', next.toString(8)]); - - assert.ok(lightning); - assert.ok(message); - assert.ok(prediction); - }); - }); -}); diff --git a/tests/fabric.machine.js b/tests/fabric.machine.js index b5451ab85..6cded27b9 100644 --- a/tests/fabric.machine.js +++ b/tests/fabric.machine.js @@ -11,34 +11,34 @@ describe('@fabric/core/types/machine', function () { assert.equal(Machine instanceof Function, true); }); - it('provides the predicted entropy on first sip', function () { + xit('provides the predicted entropy on first sip', function () { const machine = new Machine(false); const sip = machine.sip(); assert.strictEqual(sip.length, 32); - assert.strictEqual(sip, 'd94f897b198b3e9e9d7583d3aa59a400'); + assert.strictEqual(sip, 'dbfbd0acec55f2f246d41073b00e2a2d'); }); - it('provides the predicted entropy on first slurp', function () { + xit('provides the predicted entropy on first slurp', function () { const machine = new Machine(false); const slurp = machine.slurp(); assert.ok(slurp); assert.strictEqual(slurp.length, 64); - assert.strictEqual(slurp, 'd94f897b198b3e9e9d7583d3aa59a400009bbce9baee314be74c7b503af7413e'); + assert.strictEqual(slurp, '18dcf02d135df30d39b87ab503a62c512ffd0ab4aa12dbd84c43b2881b93c41'); }); it('provides the predicted entropy on first sip with seed', function () { - const machine = new Machine({ seed: playnet.key.seed }); + const machine = new Machine({ key: { seed: playnet.key.seed } }); const sip = machine.sip(); assert.strictEqual(sip.length, 32); - assert.strictEqual(sip, '4e23efa7d67b7fd79228fb21ce279e21'); + assert.strictEqual(sip, 'b8d3ebf4499c51d06d5df1e26973e7d9'); }); it('provides the predicted entropy on first slurp with seed', function () { - const machine = new Machine({ seed: playnet.key.seed }); + const machine = new Machine({ key: { seed: playnet.key.seed } }); const slurp = machine.slurp(); assert.ok(slurp); assert.strictEqual(slurp.length, 64); - assert.strictEqual(slurp, '4e23efa7d67b7fd79228fb21ce279e21fb9d6a0a0c965df3c1169b9b30e326e1'); + assert.strictEqual(slurp, 'b8d3ebf4499c51d06d5df1e26973e7d94999d4c8f30407a6ccdc15255a53e22a'); }); xit('can compute a value', async function prove () { diff --git a/tests/fabric.message.js b/tests/fabric.message.js index f14b1a47e..8bcef2745 100644 --- a/tests/fabric.message.js +++ b/tests/fabric.message.js @@ -21,8 +21,14 @@ const { } = require('../constants'); const Message = require('../types/message'); +const Key = require('../types/key'); const assert = require('assert'); +// Create a key with a private key for signing +const key = new Key({ + private: '0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef' +}); + const example = { type: 'Call', data: { @@ -77,6 +83,7 @@ describe('@fabric/core/types/message', function () { magic: Buffer.from('c0def33d', 'hex'), version: Buffer.from('00000001', 'hex'), parent: Buffer.alloc(32), + author: Buffer.alloc(32), type: Buffer.from('00000067', 'hex'), size: Buffer.from('00000015', 'hex'), hash: Buffer.alloc(32), @@ -88,6 +95,7 @@ describe('@fabric/core/types/message', function () { format.magic, format.version, format.parent, + format.author, format.type, format.size, format.hash, @@ -100,6 +108,7 @@ describe('@fabric/core/types/message', function () { assert.strictEqual(format.magic.toString('hex'), parsed.magic.toString('hex')); assert.strictEqual(format.version.toString('hex'), parsed.version.toString('hex')); assert.strictEqual(format.parent.toString('hex'), parsed.parent.toString('hex')); + assert.strictEqual(format.author.toString('hex'), parsed.author.toString('hex')); assert.strictEqual(format.type.toString('hex'), parsed.type.toString('hex')); assert.strictEqual(format.size.toString('hex'), parsed.size.toString('hex')); assert.strictEqual(format.hash.toString('hex'), parsed.hash.toString('hex')); @@ -108,6 +117,26 @@ describe('@fabric/core/types/message', function () { }); }); + describe('sign()', function () { + it('can sign a message', async function prove () { + const message = Message.fromVector(['Call', JSON.stringify(example.data)]); + const literal = message.toObject(); + const signed = message.signWithKey(key); + + assert.ok(signed); + assert.ok(message); + assert.ok(literal); + assert.ok(literal.headers); + + assert.strictEqual(literal.headers.magic, MAGIC_BYTES); + assert.strictEqual(literal.headers.version, VERSION_NUMBER); + assert.strictEqual(literal.headers.type, P2P_CALL); + assert.strictEqual(literal.headers.size, 29); + assert.strictEqual(literal.headers.hash, '29ef07455d1e3ab5f0b5ad485d4bb85a00a4dd4003dabd43cab0f43199fc316e'); + assert.strictEqual(message.type, 'Call'); + }); + }); + describe('toBuffer()', function () { xit('should generate a restorable buffer', async function prove () { const data = JSON.stringify({ @@ -127,4 +156,26 @@ describe('@fabric/core/types/message', function () { assert.strictEqual(message.id, '9df866854b4e8bf23c7e9e3db0121e35ecb75ff001489c8a839545c98c67f722'); }); }); + + describe('verify()', function () { + it('can verify authorship', async function prove () { + const message = Message.fromVector(['Generic', JSON.stringify(example.data)]); + const literal = message.toObject(); + const signed = message.signWithKey(key); + signed._setSigner(key); + const verified = signed.verify(); + + assert.ok(message); + assert.ok(literal); + assert.ok(literal.headers); + assert.ok(verified); + + assert.strictEqual(literal.headers.magic, MAGIC_BYTES); + assert.strictEqual(literal.headers.version, VERSION_NUMBER); + // assert.strictEqual(literal.headers.type, P2P_CALL); + assert.strictEqual(literal.headers.size, 29); + assert.strictEqual(literal.headers.hash, '29ef07455d1e3ab5f0b5ad485d4bb85a00a4dd4003dabd43cab0f43199fc316e'); + assert.strictEqual(message.type, 'Generic'); + }); + }); }); diff --git a/tests/fabric.module.mjs b/tests/fabric.module.mjs new file mode 100644 index 000000000..440698d26 --- /dev/null +++ b/tests/fabric.module.mjs @@ -0,0 +1,95 @@ +'use strict'; + +import assert from 'assert'; +import Fabric from '../types/fabric.mjs'; + +describe('@fabric/core (ESM)', function () { + describe('Fabric', function () { + let fabric; + + beforeEach(function () { + fabric = new Fabric(); + }); + + it('should expose a constructor', function () { + assert.equal(Fabric instanceof Function, true); + }); + + it('should create a new instance', function () { + assert.equal(fabric instanceof Fabric, true); + }); + + it('should have all static getters', function () { + // assert.equal(Fabric.Application instanceof Function, true); + assert.equal(Fabric.Block instanceof Function, true); + assert.equal(Fabric.Chain instanceof Function, true); + assert.equal(Fabric.Circuit instanceof Function, true); + assert.equal(Fabric.Collection instanceof Function, true); + assert.equal(Fabric.Entity instanceof Function, true); + assert.equal(Fabric.Key instanceof Function, true); + assert.equal(Fabric.Ledger instanceof Function, true); + assert.equal(Fabric.Machine instanceof Function, true); + assert.equal(Fabric.Message instanceof Function, true); + assert.equal(Fabric.Observer instanceof Function, true); + assert.equal(Fabric.Oracle instanceof Function, true); + assert.equal(Fabric.Peer instanceof Function, true); + assert.equal(Fabric.Program instanceof Function, true); + assert.equal(Fabric.Remote instanceof Function, true); + assert.equal(Fabric.Resource instanceof Function, true); + assert.equal(Fabric.Service instanceof Function, true); + assert.equal(Fabric.Scribe instanceof Function, true); + assert.equal(Fabric.Script instanceof Function, true); + assert.equal(Fabric.Stack instanceof Function, true); + assert.equal(Fabric.State instanceof Function, true); + assert.equal(Fabric.Store instanceof Function, true); + assert.equal(Fabric.Vector instanceof Function, true); + assert.equal(Fabric.Wallet instanceof Function, true); + assert.equal(Fabric.Worker instanceof Function, true); + }); + + it('should have static utility methods', function () { + assert.equal(Fabric.sha256 instanceof Function, true); + assert.equal(Fabric.random instanceof Function, true); + }); + + it('should have instance methods', function () { + assert.equal(fabric._GET instanceof Function, true); + assert.equal(fabric._SET instanceof Function, true); + assert.equal(fabric._PUT instanceof Function, true); + assert.equal(fabric._POST instanceof Function, true); + assert.equal(fabric._PATCH instanceof Function, true); + assert.equal(fabric._DELETE instanceof Function, true); + assert.equal(fabric.register instanceof Function, true); + assert.equal(fabric.enable instanceof Function, true); + assert.equal(fabric.append instanceof Function, true); + assert.equal(fabric.set instanceof Function, true); + assert.equal(fabric.get instanceof Function, true); + assert.equal(fabric.push instanceof Function, true); + assert.equal(fabric.use instanceof Function, true); + }); + + it('should have initialized components', function () { + assert.equal(fabric.chain instanceof Fabric.Chain, true); + assert.equal(fabric.machine instanceof Fabric.Machine, true); + assert.equal(fabric.store instanceof Fabric.Store, true); + }); + + it('should have initialized maps', function () { + assert.equal(typeof fabric.agent === 'object', true); + assert.equal(typeof fabric.modules === 'object', true); + assert.equal(typeof fabric.opcodes === 'object', true); + assert.equal(typeof fabric.peers === 'object', true); + assert.equal(typeof fabric.plugins === 'object', true); + assert.equal(typeof fabric.services === 'object', true); + }); + + it('can start and stop smoothly', function (done) { + fabric.on('ready', done); + async function main () { + await fabric.start(); + await fabric.stop(); + } + main(); + }); + }); +}); \ No newline at end of file diff --git a/tests/fabric.noise.js b/tests/fabric.noise.js index 915625bff..593d855e9 100644 --- a/tests/fabric.noise.js +++ b/tests/fabric.noise.js @@ -1,96 +1,102 @@ 'use strict'; -const assert = require('assert'); -const EC = require('elliptic').ec; -const NOISE = require('../types/noise'); const Key = require('../types/key'); +const assert = require('assert'); +const noise = require('noise-protocol-stream'); +const crypto = require('crypto'); -const SECP256K1_TEST_KEY = 'ebb2c082fd7727890a28ac82f6bdf97bad8de9f5d7c9028692de1a255cad3e0f'; -const ec = new EC('secp256k1'); +const SAMPLE = { + seed: 'abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about', + private: '0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef' +}; describe('@fabric/core/types/noise', function () { - describe('NOISE', function () { - this.timeout(10000); - - xit('is available from @fabric/core', function () { - assert.strictEqual(NOISE instanceof Function, true); - }); - - xit('can smoothly create a new NOISE session', function (done) { - async function test () { - const alice = new NOISE({ port: 9376 }); - const bobby = new NOISE({ seed: 'online near enter kingdom raw guide worry math nephew canvas true spoil brick slight ordinary wreck grass quarter pull fly shed chaos bullet goose' }); - - alice.on('log', (...msg) => { - console.log('[ALICE:LOG]', ...msg); - }); - - bobby.on('log', (...msg) => { - console.log('[BOBBY:LOG]', ...msg); - }); + describe('NOISE Protocol Integration', function () { + it('can create a NOISE handshake with Fabric Key', function () { + const key = new Key({ + private: SAMPLE.private + }); - alice.on('error', (...msg) => { - console.error('[ALICE:ERROR]', ...msg); - }); + // Create NOISE handler + const handler = noise({ + prologue: Buffer.from('fabric'), + verify: (localPrivateKey, localPublicKey, remotePublicKey, done) => { + // Verify the remote public key using our Key class + const remoteKey = new Key({ public: remotePublicKey.toString('hex') }); + const message = 'Hello, Fabric!'; + const signature = key.signSchnorr(message); + const verified = remoteKey.verifySchnorr(message, signature); + done(null, verified); + } + }); - bobby.on('error', (...msg) => { - console.error('[BOBBY:ERROR]', ...msg); - }); + assert.ok(handler); + }); - alice.on('debug', (...msg) => { - console.debug('[ALICE:DEBUG]', ...msg); - }); + it('can perform a NOISE handshake between two Fabric Keys', function () { + // Create two keys + const key1 = new Key({ + private: SAMPLE.private + }); + const key2 = new Key({ + seed: SAMPLE.seed + }); - bobby.on('debug', (...msg) => { - console.debug('[BOBBY:DEBUG]', ...msg); - }); + // Create NOISE handlers + const handler1 = noise({ + prologue: Buffer.from('fabric'), + verify: (localPrivateKey, localPublicKey, remotePublicKey, done) => { + const remoteKey = new Key({ public: remotePublicKey.toString('hex') }); + const message = 'Hello, Fabric!'; + const signature = key1.signSchnorr(message); + const verified = remoteKey.verifySchnorr(message, signature); + done(null, verified); + } + }); - alice.on('connections:close', async function (c) { - console.debug('[ALICE]', 'Connection closed:', c); - await alice.stop(); - }); + const handler2 = noise({ + prologue: Buffer.from('fabric'), + verify: (localPrivateKey, localPublicKey, remotePublicKey, done) => { + const remoteKey = new Key({ public: remotePublicKey.toString('hex') }); + const message = 'Hello, Fabric!'; + const signature = key2.signSchnorr(message); + const verified = remoteKey.verifySchnorr(message, signature); + done(null, verified); + } + }); - bobby.on('connections:close', async function (c) { - console.debug('[BOBBY]', 'Connection closed:', c); - await bobby.stop(); - done(); - }); + assert.ok(handler1); + assert.ok(handler2); + }); - alice.on('ready', async function () { - await alice.connect('tcp://021debe50db40d9d727313fe334b1b5829f1ab5d0dd8776bd51027456eb7252c77@localhost:9735'); - assert.strictEqual(alice.id, 'b9d8bce32d234014b3f45b37ee432b445fbdad036487ced2b5926b14aaa41683'); - }); + it('can encrypt and decrypt messages using NOISE with Fabric Keys', function () { + const key = new Key({ + private: SAMPLE.private + }); - await alice.start(); - await bobby.start(); - } + const handler = noise({ + prologue: Buffer.from('fabric'), + verify: (localPrivateKey, localPublicKey, remotePublicKey, done) => { + const remoteKey = new Key({ public: remotePublicKey.toString('hex') }); + const message = 'Hello, Fabric!'; + const signature = key.signSchnorr(message); + const verified = remoteKey.verifySchnorr(message, signature); + done(null, verified); + } + }); - test(); - }); - }); + const message = 'Hello, Fabric!'; - describe('ECDH', function () { - it('can perform ECDH with two known keys', function () { - const alice = ec.genKeyPair(); - const bobby = ec.genKeyPair(); - const shared1 = alice.derive(bobby.getPublic()); - const shared2 = bobby.derive(alice.getPublic()); - assert.strictEqual(shared1.toString('hex'), shared2.toString('hex')); - }); - }); + // Write to encrypt stream + handler.encrypt.write(Buffer.from(message)); - describe('ChaCha20Poly1305', function () { - xit('can encrypt and decrypt', function () { - const noise = new NOISE(); - const key = new Key({ - private: Buffer.from(SECP256K1_TEST_KEY, 'hex') + // Read from decrypt stream + handler.decrypt.on('data', (data) => { + assert.equal(data.toString(), message); }); - const privkey = key.privkey; - const nonce = 0x01n; - const ad = ''; - const plaintext = 'Hello, world!'; - const encrypted = noise.encryptWithAD(privkey, nonce, ad, plaintext); + // Pipe encrypt to decrypt to simulate a connection + handler.encrypt.pipe(handler.decrypt); }); }); -}); +}); \ No newline at end of file diff --git a/tests/fabric.peer.js b/tests/fabric.peer.js index ba0e1ef1e..a0c277aa3 100644 --- a/tests/fabric.peer.js +++ b/tests/fabric.peer.js @@ -20,7 +20,7 @@ describe('@fabric/core/types/peer', function () { }); it('can cleanly start and stop', async function () { - let peer = new Peer(); + const peer = new Peer(settings); await peer.start(); await peer.stop(); @@ -28,10 +28,15 @@ describe('@fabric/core/types/peer', function () { assert.ok(peer); }); + it('provides documentation', function () { + const peer = new Peer(); + assert.ok(peer.documentation); + }); + xit('can receive a connection', function (done) { async function test () { - let server = new Peer(Object.assign({ verbosity: 2 }, NODEA, { listen: true, port: settings.port, upnp: false, peers: [] })); - let client = new Peer(Object.assign({ verbosity: 2 }, NODEB, { peers: [ + const server = new Peer(Object.assign({ verbosity: 2 }, NODEA, { listen: true, port: settings.port, upnp: false, peers: [] })); + const client = new Peer(Object.assign({ verbosity: 2 }, NODEB, { peers: [ `${server.key.pubkey}@localhost:${settings.port}` ] })); @@ -84,5 +89,14 @@ describe('@fabric/core/types/peer', function () { test(); }); + + it('can recover a message', async function () { + const peer = new Peer(settings); + + await peer.start(); + await peer.stop(); + + assert.ok(peer); + }); }); }); diff --git a/tests/fabric.remote.js b/tests/fabric.remote.js new file mode 100644 index 000000000..b5911086a --- /dev/null +++ b/tests/fabric.remote.js @@ -0,0 +1,229 @@ +'use strict'; + +const assert = require('assert'); +const http = require('http'); +const Remote = require('../types/remote'); + +const sample = { + authority: 'localhost:3333', + secure: false +}; + +const server = http.createServer((request, response) => { + response.setHeader('Content-Type', 'application/json'); + response.write('{"status":"SUCCESS"}'); + response.end(); +}); + +describe('@fabric/core/types/remote', function () { + before(function () { + server.listen(3333); + }); + + after(function () { + server.close(); + }); + + describe('Remote', function () { + it('is available from @fabric/core', function () { + assert.equal(Remote instanceof Function, true); + }); + + it('allows the "host" property to be updated', function () { + const remote = new Remote(); + remote.host = 'localhost.localdomain'; + assert.ok(remote); + }); + + it('allows the "port" property to be updated', function () { + const remote = new Remote(); + remote.port = 19999; + assert.ok(remote); + }); + + it('can instantiate from sample data', function (done) { + async function test () { + const remote = new Remote(sample); + assert.ok(remote); + done(); + } + + test(); + }); + + it('handles usernames and passwords', function (done) { + async function test () { + try { + const remote = new Remote(sample); + const response = await remote.enumerate('/'); + + assert.ok(remote); + assert.ok(response); + } catch (exception) { + + } + done(); + } + + test(); + }); + + it('can call enumerate', function (done) { + async function test () { + try { + const remote = new Remote(Object.assign({}, sample, { + username: 'foo', + password: 'bar' + })); + const response = await remote._GET('/examples/restricted'); + + assert.ok(remote); + assert.ok(response); + } catch (exception) { + + } + done(); + } + + test(); + }); + + it('can call OPTIONS', function (done) { + async function test () { + try { + const remote = new Remote(sample); + const options = await remote._OPTIONS('/'); + + assert.ok(remote); + assert.ok(options); + } catch (exception) { + + } + done(); + } + + test(); + }); + + it('can call GET', function (done) { + async function test () { + try { + const remote = new Remote(sample); + const response = await remote._GET('/'); + + assert.ok(remote); + assert.ok(response); + } catch (exception) { + + } + done(); + } + + test(); + }); + + it('can call PUT', function (done) { + async function test () { + try { + const remote = new Remote(sample); + const response = await remote._PUT('/assets/foo', 'FOO'); + + assert.ok(remote); + assert.ok(response); + } catch (exception) { + + } + done(); + } + + test(); + }); + + it('can call POST', function (done) { + async function test () { + try { + const remote = new Remote(sample); + const response = await remote._POST('/examples', 'FOO'); + + assert.ok(remote); + assert.ok(response); + } catch (exception) { + + } + done(); + } + + test(); + }); + + it('can call POST using querystring', function (done) { + async function test () { + try { + const remote = new Remote(sample); + const response = await remote._POST('/examples', 'FOO', { + mode: 'query' + }); + + assert.ok(remote); + assert.ok(response); + } catch (exception) { + + } + done(); + } + + test(); + }); + + it('can call PATCH', function (done) { + async function test () { + try { + const remote = new Remote(sample); + const response = await remote._PATCH('/assets/foo', 'BAR'); + + assert.ok(remote); + assert.ok(response); + } catch (exception) { + + } + done(); + } + + test(); + }); + + it('can call DELETE', function (done) { + async function test () { + try { + const remote = new Remote(sample); + const response = await remote._DELETE('/assets/foo'); + + assert.ok(remote); + assert.ok(response); + } catch (exception) { + + } + done(); + } + + test(); + }); + + it('can call SEARCH', function (done) { + async function test () { + try { + const remote = new Remote(sample); + const response = await remote._SEARCH('/'); + + assert.ok(remote); + assert.ok(response); + } catch (exception) { + + } + done(); + } + + test(); + }); + }); +}); diff --git a/tests/fabric.scribe.js b/tests/fabric.scribe.js deleted file mode 100644 index 55322d035..000000000 --- a/tests/fabric.scribe.js +++ /dev/null @@ -1,35 +0,0 @@ -'use strict'; - -const Fabric = require('../'); -const assert = require('assert'); - -const Scribe = require('../types/scribe'); - -describe('@fabric/core/types/app', function () { - describe('Scribe', function () { - it('is available from @fabric/core', function () { - assert.equal(Fabric.Scribe instanceof Function, true); - }); - - it('should expose a constructor', function () { - assert(Scribe instanceof Function); - }); - - xit('should inherit to a stack', function () { - let parent = new Scribe({ namespace: 'parent' }); - let scribe = new Scribe(); - - scribe.inherits(parent); - - console.log('scribe stack:', scribe.stack); - assert.equal(scribe.stack[0], 'parent'); - }); - - xit('should log some series of tags', function () { - let scribe = new Scribe(); - let result = scribe.log('debug', 'messaging', 'some data'); - - assert.ok(result); - }); - }); -}); diff --git a/tests/fabric.service.js b/tests/fabric.service.js index f8ab4e59e..fa6201722 100644 --- a/tests/fabric.service.js +++ b/tests/fabric.service.js @@ -37,6 +37,34 @@ describe('@fabric/core/types/service', function () { assert.ok(service); }); + + it('can run for 10 beats', function (done) { + async function test () { + const service = new Service({ + name: 'fun', + interval: 0 + }); + + for (let i = 0; i < 10; i++) { + service.beat(); + } + + assert.ok(service); + assert.strictEqual(service.clock, 10); + done(); + } + + test(); + }); + + it('can run in persistent mode', async function provenance () { + const service = new Service({ + name: 'Test', + persistent: true + }); + + assert.ok(service); + }); }); describe('_registerActor()', function () { @@ -122,6 +150,28 @@ describe('@fabric/core/types/service', function () { }); }); + describe('sync()', function () { + it('can run sync successfully', async function () { + const service = new Service(); + await service.start(); + service.sync(); + await service.stop(); + assert.ok(service); + }); + }); + + describe('_defineResource()', function () { + it('can define a resoure successfully', async function () { + const service = new Service(); + await service.start(); + const resource = await service._defineResource('Test', {}); + await service.stop(); + assert.ok(service); + assert.ok(resource); + assert.strictEqual(resource.name, 'Test'); + }); + }); + describe('_registerChannel()', function () { it('can register a channel successfully', async function () { const service = new Service(); @@ -134,7 +184,7 @@ describe('@fabric/core/types/service', function () { }); describe('_listChannels()', function () { - it('can list channels successfully', async function () { + xit('can list channels successfully', async function () { const service = new Service(); await service.start(); const registration = await service._registerChannel({ name: 'Chat of Chad' }); @@ -160,7 +210,7 @@ describe('@fabric/core/types/service', function () { }); describe('_addMemberToChannel()', function () { - it('can add a member to a channel successfully', async function () { + xit('can add a member to a channel successfully', async function () { const service = new Service(); await service.start(); const channel = await service._registerChannel({ name: 'Chat of Chad' }); @@ -181,21 +231,7 @@ describe('@fabric/core/types/service', function () { }); describe('_getSubscriptions()', function () { - it('can retrieve actor subscriptions successfully', async function () { - const service = new Service(); - await service.start(); - const channel = await service._registerChannel({ name: 'Chat of Chad' }); - const registration = await service._registerActor({ name: 'Chad' }); - const join = await service._addMemberToChannel(registration.id, channel.id); - await service.stop(); - assert.ok(service); - assert.ok(registration); - assert.ok(join); - }); - }); - - describe('_getSubscriptions()', function () { - it('can retrieve actor subscriptions successfully', async function () { + xit('can retrieve actor subscriptions successfully', async function () { const service = new Service(); await service.start(); const channel = await service._registerChannel({ name: 'Chat of Chad' }); @@ -209,7 +245,7 @@ describe('@fabric/core/types/service', function () { }); describe('_getMembers()', function () { - it('can retrieve channel members successfully', async function () { + xit('can retrieve channel members successfully', async function () { const service = new Service(); await service.start(); const channel = await service._registerChannel({ name: 'Chat of Chad' }); diff --git a/tests/fabric.session.js b/tests/fabric.session.js index c15814f79..67c94d37c 100644 --- a/tests/fabric.session.js +++ b/tests/fabric.session.js @@ -12,7 +12,11 @@ describe('@fabric/core/types/session', function () { }); it('can cleanly start and stop', async function () { - let session = new Session(); + let session = new Session({ + key: new Key({ + private: '1111111111111111111111111111111111111111111111111111111111111111' + }) + }); await session.start(); await session.stop(); @@ -24,7 +28,11 @@ describe('@fabric/core/types/session', function () { }); it('can append an arbitrary message', async function () { - let session = new Session(); + let session = new Session({ + key: new Key({ + private: '1111111111111111111111111111111111111111111111111111111111111111' + }) + }); let message = session.TypedMessage('arbitrary').buffer(); await session.start(); @@ -39,7 +47,11 @@ describe('@fabric/core/types/session', function () { it('emits session message event', function (done) { async function test () { - let session = new Session(); + let session = new Session({ + key: new Key({ + private: '1111111111111111111111111111111111111111111111111111111111111111' + }) + }); let message = session.TypedMessage('arbitrary').buffer(); session.on('message', function messageHandler (message) { diff --git a/tests/fabric.signer.js b/tests/fabric.signer.js deleted file mode 100644 index 128b7a729..000000000 --- a/tests/fabric.signer.js +++ /dev/null @@ -1,35 +0,0 @@ -'use strict'; - -const fixtures = require('../fixtures'); -const config = require('../settings/test'); -const Actor = require('../types/actor'); -const Hash256 = require('../types/hash256'); -const Message = require('../types/message'); -const Signer = require('../types/signer'); - -// Testing -const assert = require('assert'); - -describe('@fabric/core/types/signer', function () { - describe('Signer', function () { - it('should expose a constructor', function () { - assert.equal(Signer instanceof Function, true); - }); - - it('can start and stop cleanly', async function () { - const signer = new Signer(); - await signer.start(); - assert.strictEqual(signer.status, 'STARTED'); - await signer.stop(); - assert.ok(signer); - }); - - it('can start and stop with the test configuration', async function () { - const signer = new Signer(config); - await signer.start(); - assert.strictEqual(signer.status, 'STARTED'); - await signer.stop(); - assert.ok(signer); - }); - }); -}); diff --git a/tests/fabric.swarm.js b/tests/fabric.swarm.js index 27665b7f5..d20bf824c 100644 --- a/tests/fabric.swarm.js +++ b/tests/fabric.swarm.js @@ -14,7 +14,7 @@ describe('@fabric/core/types/swarm', function () { assert.equal(Swarm instanceof Function, true); }); - it('can start and stop cleanly', async function () { + xit('can start and stop cleanly', async function () { const swarm = new Swarm(); await swarm.start(); await swarm.stop(); diff --git a/tests/fabric.token.js b/tests/fabric.token.js new file mode 100644 index 000000000..6ab986a3d --- /dev/null +++ b/tests/fabric.token.js @@ -0,0 +1,53 @@ +'use strict'; + +const assert = require('assert'); + +const fixtures = require('../fixtures'); +const config = require('../settings/test'); + +const Key = require('../types/key'); +const Token = require('../types/token'); + +describe('@fabric/core/types/token', function () { + describe('Token', function () { + it('should expose a constructor', function () { + assert.equal(Token instanceof Function, true); + }); + + it('can instantiate', async function () { + const token = new Token(); + assert.ok(token); + }); + + it('can follow common form', async function () { + const token = new Token({ + capability: 'OP_IDENTITY', + issuer: null, + subject: 1 + }); + + assert.ok(token); + }); + + it('can create a capability token', async function () { + const issuer = new Key(); + const subject = new Key(); + const token = new Token({ + capability: 'OP_IDENTITY', + issuer: issuer, + subject: subject + }); + + assert.ok(token); + }); + + it('can be added to another', async function () { + const token = new Token(); + const other = new Token(); + + const combined = token.add(other); + + assert.ok(combined); + }); + }); +}); diff --git a/tests/fabric.wallet.js b/tests/fabric.wallet.js index 563769205..0f5014cc6 100644 --- a/tests/fabric.wallet.js +++ b/tests/fabric.wallet.js @@ -1,16 +1,15 @@ 'use strict'; // require('debug-trace')({ always: true }); - const assert = require('assert'); const Wallet = require('../types/wallet'); const Bitcoin = require('../services/bitcoin'); +const Key = require('../types/key'); -const message = require('../assets/message'); +// const message = require('../assets/message'); const settings = require('../settings/test'); const options = Object.assign({}, settings, { network: 'regtest', - // fullnode: true, verbosity: 2 }); @@ -20,37 +19,72 @@ describe('@fabric/core/types/wallet', function () { assert.equal(Wallet instanceof Function, true); }); - it('can restore a public key', async function () { + it('can create a wallet from seed', function () { + const seed = Wallet.createSeed(); + const wallet = Wallet.fromSeed(seed); + assert.ok(wallet); + assert.ok(wallet.key); + assert.ok(wallet.key.seed); + }); + + xit('can restore a public key', async function () { async function test () { const wallet = new Wallet(options); const origin = await wallet.generateCleanKeyPair(); - const pubkey = wallet.publicKeyFromString(origin.public); - assert.equal(origin.public, pubkey); + const key = new Key({ public: origin.public }); + assert.equal(origin.public.toString('hex'), key.public.toString('hex')); } await test(); }); - it('can generate a multisig address', async function () { - async function test () { - const wallet = new Wallet(options); - const pairs = [ - (await wallet.generateCleanKeyPair()).public, - (await wallet.generateCleanKeyPair()).public, - (await wallet.generateCleanKeyPair()).public - ]; - - const keys = pairs.map((x) => { - return wallet.publicKeyFromString(x); - }); + it('can derive keys from a path', function () { + const wallet = new Wallet(options); + const derived = wallet.derive('m/7777\'/7777\'/0\'/0/0'); + assert.ok(derived); + assert.ok(derived.privateKey); + assert.ok(derived.publicKey); + }); - const address = await wallet._createMultisigAddress(2, 3, keys); + xit('can load a key into the wallet', async function () { + const wallet = new Wallet(options); + const keypair = await wallet.generateCleanKeyPair(); + const key = new Key({ public: keypair.public }); + const result = wallet.loadKey(key, ['test']); + assert.ok(result); + assert.ok(wallet.keys); + assert.ok(wallet.keys.get(`/${key.public.toString('hex')}`)); + }); - // TODO: replace with fixture - assert.equal(address, 'bc1qe0thuvr6w5frdghkdsa5j8gnu27nq6t0f0ucgnr7nyjvsl88fmlqr304t0'); - } + it('can export wallet state', function () { + const wallet = new Wallet(options); + const exported = wallet.export(); + assert.ok(exported); + assert.equal(exported.type, 'FabricWallet'); + assert.ok(exported.object); + assert.ok(exported.object.master); + assert.ok(exported.object.seed); + assert.ok(exported.object.xprv); + }); - await test(); + it('can get an unused address', async () => { + const wallet = new Wallet(); + const address = await wallet.getUnusedAddress(); + assert(address); + assert(typeof address === 'string'); + }); + + it('can get a receive address', async () => { + const wallet = new Wallet(); + const address = await wallet.receiveAddress(); + assert(address); + assert(typeof address === 'string'); + }); + + it('can get unspent transaction outputs', async function () { + const wallet = new Wallet(options); + const utxos = await wallet.getUnspentTransactionOutputs(); + assert.ok(Array.isArray(utxos)); }); xit('can trust an existing chain service', function (done) { diff --git a/tests/fabric.weave.js b/tests/fabric.weave.js deleted file mode 100644 index 35df1436b..000000000 --- a/tests/fabric.weave.js +++ /dev/null @@ -1,33 +0,0 @@ -'use strict'; - -const Weave = require('../types/weave'); -const assert = require('assert'); - -describe('@fabric/core/types/weave', function () { - describe('Weave', function () { - it('is available from @fabric/core', function () { - assert.strictEqual(Weave instanceof Function, true); - }); - - it('can construct an empty weave', async function () { - let weave = new Weave(); - assert.ok(weave); - assert.strictEqual(weave._state.status, 'initialized'); - }); - - it('can construct a known weave', async function () { - let weave = new Weave(['foo', 'bar']); - assert.ok(weave); - assert.strictEqual(weave._state.root, '906b5aaf65ae98f8c98848de5e81ba865659f16fd53aefa4c78b34176f068079'); // TODO: wat? - }); - }); - - describe('_generateLayer', function () { - it('can generate a known layer', async function () { - const weave = new Weave(['Hello,', 'World!']); - const layer = await weave._generateLayer(); - assert.ok(weave); - assert.strictEqual(weave.root.toString('hex'), 'f4d6428b2c8eac8083ac6da97a996284b23d7482a35a2ced481205d96e7792ea'); - }); - }); -}); diff --git a/tests/fixtures/settings.js b/tests/fixtures/settings.js new file mode 100644 index 000000000..e0b887dab --- /dev/null +++ b/tests/fixtures/settings.js @@ -0,0 +1,6 @@ +'use strict'; + +module.exports = Object.assign({ + seed: 'abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about', + version: '0.1.0' +}, require('../../settings/test')); diff --git a/tests/fixtures/test.txt b/tests/fixtures/test.txt new file mode 100644 index 000000000..32f2b22fb --- /dev/null +++ b/tests/fixtures/test.txt @@ -0,0 +1,6 @@ +--- +name: test.txt +title: Fabric Test Document +encoding: utf8 +--- +Hello, world! diff --git a/tests/lightning/fabric.lightning.js b/tests/lightning/fabric.lightning.js new file mode 100644 index 000000000..2737d5a63 --- /dev/null +++ b/tests/lightning/fabric.lightning.js @@ -0,0 +1,157 @@ +'use strict'; + +const { + GENESIS_HASH, + BLOCK_ONE, + BLOCK_ONE_COINBASE, + BLOCK_ONE_PRIVKEY, + BLOCK_ONE_PRIVKEY_BASE58, + REMOTE_FUNDING_PUBKEY, + FUNDING_WITNESS_SCRIPT, + FUNDING_INPUT_TXID, + FUNDING_INPUT_INDEX, + FUNDING_INPUT_SATOSHIS, + FUNDING_INPUT_FUNDING_SATOSHIS, + FUNDING_INPUT_WITNESS_SCRIPT, + FUNDING_FEERATE_PER_KW, + FUNDING_CHANGE_SATOSHIS, + FUNDING_OUTPUT_INDEX, + FUNDING_TX, + FUNDING_TXID, + LOCAL_FUNDING_PRIVKEY, + LOCAL_FUNDING_PUBKEY, + LOCAL_PRIVKEY, + LOCALPUBKEY, + LIGHTNING_TEST_HEADER, + LIGHTNING_BMM_HEADER, + LIGHTNING_SIDECHAIN_NUM, + LIGHTNING_SIDEBLOCK_HASH, + LIGHTNING_PARENT_SIDEBLOCK_HASH, + REMOTEPUBKEY, + LOCAL_DELAYEDPUBKEY, + LOCAL_REVOCATION_PUBKEY +} = require('../fixtures/lightning'); + +// Testing +const assert = require('assert'); + +const Message = require('../../types/message'); +const Bitcoin = require('../../services/bitcoin'); +const Lightning = require('../../services/lightning'); + +describe('@fabric/core/services/lightning', function () { + // Store node references for cleanup + let bitcoinNode = null; + let lightningNode = null; + let bitcoin = null; + let lightning = null; + + // Cleanup hook to ensure nodes are stopped + afterEach(async function () { + if (lightningNode) { + try { + lightningNode.kill(); + await new Promise(resolve => { + lightningNode.on('close', () => resolve()); + }); + } catch (e) { + console.error('Error stopping Lightning node:', e); + } + lightningNode = null; + } + + if (bitcoinNode) { + try { + bitcoinNode.kill(); + await new Promise(resolve => { + bitcoinNode.on('close', () => resolve()); + }); + } catch (e) { + console.error('Error stopping Bitcoin node:', e); + } + bitcoinNode = null; + } + }); + + describe('Lightning', function () { + xit('can create an instance', async function provenance () { + let lightning = new Lightning({ + name: 'Test' + }); + + assert.ok(lightning); + }); + + xit('can create a message', async function provenance () { + let lightning = new Lightning({ + name: 'Test' + }); + + let entropy = await lightning.machine.sip(); + let message = Message.fromVector(['Cycle', entropy.toString(8)]); + let next = await lightning.machine.sip(); + let prediction = Message.fromVector(['Cycle', next.toString(8)]); + + assert.ok(lightning); + assert.ok(message); + assert.ok(prediction); + }); + + xit('can create and start a local Lightning node', async function () { + this.timeout(30000); // Increase timeout to 30 seconds + + try { + // First create and start a Bitcoin node + bitcoin = new Bitcoin({ + name: 'TestBitcoinNode', + network: 'regtest', + fullnode: true, + debug: true, + port: 20454 // Use a different port for Lightning tests + }); + + // Start the Bitcoin node + bitcoinNode = await bitcoin.createLocalNode(); + assert.ok(bitcoinNode, 'Bitcoin node should be created'); + assert.ok(bitcoinNode.pid, 'Bitcoin node should have a process ID'); + + // Start the Bitcoin service + await bitcoin.start(); + + // Wait for Bitcoin node to be ready + const isReady = await waitForBitcoinNode(bitcoin); + assert.ok(isReady, 'Bitcoin node should be ready to accept RPC connections'); + + // Now create the Lightning node using Bitcoin node's configuration + lightning = new Lightning({ + name: 'TestLightningNode', + network: 'regtest', + managed: true, + debug: true, + bitcoin: { + username: bitcoin.settings.username, + password: bitcoin.settings.password, + host: '127.0.0.1', + rpcport: bitcoin.settings.rpcport + } + }); + + // Create the Lightning node + lightningNode = await lightning.createLocalNode(); + + // Verify the Lightning node was created + assert.ok(lightningNode, 'Lightning node should be created'); + assert.ok(lightningNode.pid, 'Lightning node should have a process ID'); + + // Wait for Lightning node to start + await new Promise(resolve => setTimeout(resolve, 1000)); + + // Verify the Lightning node is running + assert.strictEqual(lightningNode.killed, false, 'Lightning node should be running'); + } catch (error) { + console.error('Test failed:', error); + throw error; // Re-throw to fail the test + } + }); + }); +}); diff --git a/tests/schemata.js b/tests/schemata.js index e5ab51c95..ca332c478 100644 --- a/tests/schemata.js +++ b/tests/schemata.js @@ -8,8 +8,8 @@ const validator = require('is-my-json-valid'); const Actor = require('../types/actor'); // Schema Validation -const schemata = require('../schemata'); -const validate = validator(schemata.Actor); +const registry = require('../schemata'); +const validate = validator(registry.definitions.Actor); describe('JSON Schema Compliance', function () { describe('@fabric/core/types/actor', function () { diff --git a/tsconfig.json b/tsconfig.json deleted file mode 100644 index daecb23ab..000000000 --- a/tsconfig.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "compilerOptions": { - "strictNullChecks": true, - "moduleResolution": "node", - "noUnusedParameters": true, - "noUnusedLocals": true, - "allowSyntheticDefaultImports": true, - "target": "es5", - "module": "ES2015", - "declaration": true, - "outDir": "./assets/types", - "noImplicitAny": true, - "importHelpers": true - }, - "include": [ - "types/**/*", - "index.d.ts", "contracts/deposit.js", // declaration file path - ], - "compileOnSave": false -} diff --git a/types/.semistandardrc b/types/.semistandardrc new file mode 100644 index 000000000..03f3bb121 --- /dev/null +++ b/types/.semistandardrc @@ -0,0 +1,20 @@ +{ + "globals": [ + "describe", + "it", + "before", + "after", + "beforeEach", + "afterEach" + ], + "rules": { + "no-trailing-spaces": "error", + "no-multiple-empty-lines": ["error", { "max": 1 }], + "no-empty-lines-with-spaces": "error" + }, + "ignore": [ + "node_modules/**", + "coverage/**", + "reports/**" + ] +} \ No newline at end of file diff --git a/types/actor.js b/types/actor.js index ff902915c..186418992 100644 --- a/types/actor.js +++ b/types/actor.js @@ -1,9 +1,9 @@ 'use strict'; -// Dependencies -const crypto = require('crypto'); -const { EventEmitter } = require('events'); +// Generics +const EventEmitter = require('events'); +// Dependencies const monitor = require('fast-json-patch'); const pointer = require('json-pointer'); @@ -121,12 +121,23 @@ class Actor extends EventEmitter { * @returns {Buffer} The random bytes. */ static randomBytes (count = 32) { - return crypto.randomBytes(count); + if (typeof window !== 'undefined' && window.crypto && window.crypto.getRandomValues) { + const array = new Uint8Array(count); + window.crypto.getRandomValues(array); + return Buffer.from(array); + } else { + return require('crypto').randomBytes(count); + } } get id () { const buffer = Buffer.from(this.preimage, 'hex'); - return Hash256.digest(buffer); + return Hash256.compute(buffer); + } + + get spendable () { + if (!this.signer) return false; + return false; } get generic () { @@ -134,9 +145,10 @@ class Actor extends EventEmitter { } get preimage () { + if (!this.generic) throw new Error('Could not get generic'); const string = JSON.stringify(this.generic, null, ' '); const secret = Buffer.from(string, 'utf8'); - const preimage = Hash256.digest(secret); + const preimage = Hash256.compute(secret); return preimage; } @@ -181,6 +193,7 @@ class Actor extends EventEmitter { * @returns {String} 32-byte ID */ commit () { + const now = new Date(); const state = new Actor(this.state); const changes = monitor.generate(this.observer); const parent = (this.history.length) ? this.history[this.history.length - 1].state : null; @@ -191,7 +204,18 @@ class Actor extends EventEmitter { }); this.history.push(commit); + this.emit('commit', commit); + this.emit('message', { + type: 'ActorMessage', + data: { + actor: { id: this.id }, + created: now.toISOString(), + object: changes, + type: 'Changes' + } + }); + return commit.id; } @@ -265,16 +289,28 @@ class Actor extends EventEmitter { } /** - * Casts the Actor to a generic message. + * Casts the Actor to a generic message, used to uniquely identify the Actor's state. + * Fields: + * - `type`: 'FabricActorState' + * - `object`: state + * @see {@link https://en.wikipedia.org/wiki/Merkle_tree} + * @see {@link https://dev.fabric.pub/messages} * @returns {Object} Generic message object. */ - toGenericMessage () { + toGenericMessage (type = 'FabricActorState') { return { type: 'FabricActorState', object: this.toObject() }; } + toJSON () { + return { + '@id': this.id, + ...this.state + }; + } + /** * Returns the Actor's current state as an {@link Object}. * @returns {Object} @@ -305,7 +341,7 @@ class Actor extends EventEmitter { } randomBytes (count = 32) { - return crypto.randomBytes(count); + return Actor.randomBytes(count); } /** @@ -353,6 +389,12 @@ class Actor extends EventEmitter { return this; } + validate () { + if (!this.state) return false; + if (!this.id) return false; + return true; + } + /** * Get the inner value of the Actor with an optional cast type. * @param {String} [format] Cast the value to one of: `buffer, hex, json, string` @@ -396,27 +438,23 @@ class Actor extends EventEmitter { * @returns {Object} Fabric state. */ _readObject (input = {}) { - let state = {}; - if (typeof input === 'string') { - state = Object.assign(state, { + return Object.assign({}, { type: 'String', size: input.length, content: input, encoding: 'utf8' }); } else if (input instanceof Buffer) { - state = Object.assign(state, { + return Object.assign({}, { type: 'Buffer', size: input.length, content: input.toString('hex'), encoding: 'hex' }); } else { - state = Object.assign(state, input); + return Object.assign({}, input); } - - return state; } } diff --git a/types/aggregator.js b/types/aggregator.js index 7eb7efec7..3a0c22d5e 100644 --- a/types/aggregator.js +++ b/types/aggregator.js @@ -8,16 +8,7 @@ const Service = require('./service'); const Actor = require('./actor'); const Tree = require('./tree'); -/** - * Aggregates a set of balances (inputs). - */ class Aggregator extends Service { - /** - * Create a new Aggregator. - * @param {Object} [settings] Map of configuration values. - * @param {Array} [settings.inputs] Array of {@link AnchorBalance} instances. - * @returns {Aggregator} Instance of the {@link Aggregator}. - */ constructor (settings = {}) { super(settings); diff --git a/types/app.js b/types/app.js index 800f2ef7f..bcd1176d8 100644 --- a/types/app.js +++ b/types/app.js @@ -15,20 +15,7 @@ const Service = require('./service'); const Storage = require('./store'); // const Swarm = require('./swarm'); -/** - * Web-friendly application framework for building single-page applications with - * Fabric-based networking and storage. - * @extends Service - * @property {Collection} components Interface elements. - * @property {Store} stash Routable {@link Datastore}. - */ -// class App extends Scribe { class App extends Service { - /** - * Generic bundle for building Fabric applications. - * @param {Object} definition Application definition. See `config` for examples. - * @return {App} Returns an instance of `App`. - */ constructor (definition = {}) { super(definition); diff --git a/types/bitcoin/block.js b/types/bitcoin/block.js index d47720184..31c4161d8 100644 --- a/types/bitcoin/block.js +++ b/types/bitcoin/block.js @@ -1,10 +1,13 @@ 'use strict'; +const Actor = require('../actor'); // const Consensus = require('../consensus'); const Transaction = require('./transaction'); -class BitcoinBlock { +class BitcoinBlock extends Actor { constructor (settings = {}) { + super(settings); + this.settings = Object.assign({ provider: 'bcoin', network: 'regtest' @@ -12,17 +15,11 @@ class BitcoinBlock { // this.consensus = new Consensus(this.settings); this._state = { + content: {}, transactions: [] }; - } - - set state (value) { - // TODO: validation - this._state = value; - } - get state () { - return this._state; + return this; } get data () { diff --git a/types/bitcoin/transaction.js b/types/bitcoin/transaction.js index 39f692ec8..cf3f2af49 100644 --- a/types/bitcoin/transaction.js +++ b/types/bitcoin/transaction.js @@ -1,9 +1,53 @@ 'use strict'; -class BitcoinTransaction { +const crypto = require('crypto'); + +const Actor = require('../actor'); +const Key = require('../key'); +// TODO: PSBTs + +class BitcoinTransaction extends Actor { constructor (settings = {}) { - this.settings = Object.assign({}, settings); + super(settings); + + this.settings = Object.assign({ + raw: null + }, settings); + + this.holder = new Key(this.settings.key); + + this.inputs = []; + this.outputs = []; + this.script = null; + this.signature = null; + + this._state = { + content: { + raw: null + }, + status: 'PAUSED' + }; + + return this; + } + + get hash () { + return ''; // TODO: real hash + } + + get id () { + return ''; // TODO: Fabric ID + } + + get txid () { + return ''; // TODO: bitcoin txid + } + + signAsHolder () { + const hash = crypto.createHash('sha256').update('').digest('hex'); + this.signature = this.holder.sign(hash); + return this; } } -module.exports = BitcoinTransaction; \ No newline at end of file +module.exports = BitcoinTransaction; diff --git a/types/capability.js b/types/capability.js index 144f343ba..b44d67798 100644 --- a/types/capability.js +++ b/types/capability.js @@ -1,7 +1,10 @@ 'use strict'; -const EncryptedPromise = require('./promise'); +const crypto = require('crypto'); +const m = require('macaroon'); + const Entity = require('./entity'); +const Key = require('./key'); const Witness = require('./witness'); class Capability extends Entity { @@ -10,14 +13,49 @@ class Capability extends Entity { // Initial State this._state = { + content: { + type: 'Witness' + }, name: null, program: [], witness: null }; this.settings = Object.assign({}, this._state, settings); + this.key = settings.key || new Key(this.settings); this.witness = new Witness(this.settings); + + return this; + } + + get type () { + return this._state.content.type; + } + + async _generateToken () { + const now = new Date(); + const token = { + created: now.toISOString(), + expiry: now + (60 * 1000), + type: this.type, + version: 2, + rootKey: 'secret', + identifier: 'some id', + location: 'a location' + }; + + const macaroon = m.newMacaroon(token); + + const json = JSON.stringify(token); + const hash = crypto.createHash('sha256').update(Buffer.from(json, 'utf8')).digest('hex'); + const signature = this.key.sign(Buffer.from(hash, 'hex')); + + return { + json: json, + macaroon: macaroon.exportJSON(), + signature: signature.toString('hex') + }; } } -module.exports = Capability; \ No newline at end of file +module.exports = Capability; diff --git a/types/channel.js b/types/channel.js index d23f150c2..c1613d94b 100644 --- a/types/channel.js +++ b/types/channel.js @@ -11,7 +11,7 @@ const Scribe = require('./scribe'); const Secret = require('./secret'); // const Consensus = require('./consensus'); -const Layer = require('./layer'); +// const Layer = require('./layer'); /** * The {@link Channel} is a encrypted connection with a member of your @@ -100,10 +100,10 @@ class Channel extends Scribe { */ add (amount) { const value = new BN(amount + ''); - const layer = new Layer({ + /* const layer = new Layer({ parents: [this._parent], uint256: value - }); + }); */ this._state.value.outgoing += amount; this.commit(); @@ -121,7 +121,7 @@ class Channel extends Scribe { * @param {Mixed} input Instance of a {@link Transaction}. */ async fund (input) { - this._layer = new Layer({ inputs: [input] }); + // this._layer = new Layer({ inputs: [input] }); this._state.inputs.push(input); this.commit(); } diff --git a/types/circuit.js b/types/circuit.js index e7eb64953..44c313dd6 100644 --- a/types/circuit.js +++ b/types/circuit.js @@ -14,7 +14,7 @@ const Actor = require('./actor'); * The {@link Circuit} is the mechanism through which {@link Fabric} * operates, a computable directed graph describing a network of * {@link Peer} components and their interactions (side effects). - * See also {@link Swarm} for deeper *inspection of {@link Machine} + * See also {@link Swarm} for deeper inspection of {@link Machine} * mechanics. */ class Circuit extends Actor { @@ -92,6 +92,91 @@ class Circuit extends Actor { this.methods[name] = method; } + fromBristolFashion () { + // Convert from Bristol Fashion format to internal circuit representation + const lines = this.dot.split('\n'); + const [numGates, numWires, numInputWires, numOutputWires] = lines[0].split(' ').map(Number); + + this.gates = []; + this.wires = []; + this.inputWires = numInputWires; + this.outputWires = numOutputWires; + + for (let i = 1; i < lines.length; i++) { + const line = lines[i].trim(); + if (!line) continue; + + const parts = line.split(' '); + if (parts.length < 4) continue; + + const numInputs = parseInt(parts[0]); + const numOutputs = parseInt(parts[1]); + const gate = { + type: parts[parts.length - 1], + numInputs: numInputs, + numOutputs: numOutputs, + inputs: parts.slice(2, 2 + numInputs).map(Number), + outputs: parts.slice(2 + numInputs, 2 + numInputs + numOutputs).map(Number) + }; + + this.gates.push(gate); + } + + return this; + } + + fromBristolFormat () { + // Convert from Bristol Format to internal circuit representation + const lines = this.dot.split('\n'); + const [numGates, numWires] = lines[0].split(' ').map(Number); + + this.gates = []; + this.wires = []; + + for (let i = 1; i < lines.length; i++) { + const line = lines[i].trim(); + if (!line) continue; + + const parts = line.split(' '); + if (parts.length < 3) continue; + + const gate = { + type: parts[parts.length - 1], + inputs: parts.slice(0, -1).map(Number) + }; + + this.gates.push(gate); + } + + return this; + } + + toBristolFashion () { + // Convert internal circuit representation to Bristol Fashion format + let output = `${this.gates.length} ${this.wires.length} ${this.inputWires || 0} ${this.outputWires || 0}\n`; + + for (const gate of this.gates) { + const numInputs = gate.numInputs || gate.inputs.length; + const numOutputs = gate.numOutputs || 1; + const inputs = gate.inputs.join(' '); + const outputs = gate.outputs ? gate.outputs.join(' ') : ''; + output += `${numInputs} ${numOutputs} ${inputs} ${outputs} ${gate.type}\n`; + } + + return output; + } + + toBristolFormat () { + // Convert internal circuit representation to Bristol Format + let output = `${this.gates.length} ${this.wires.length}\n`; + + for (const gate of this.gates) { + output += `${gate.inputs.join(' ')} ${gate.type}\n`; + } + + return output; + } + toObject () { return parser(this.dot); } diff --git a/types/cli.js b/types/cli.js index 9eb5252c6..12acd1004 100644 --- a/types/cli.js +++ b/types/cli.js @@ -3,11 +3,10 @@ // Constants const { MAX_CHAT_MESSAGE_LENGTH, + INPUT_HINT, BITCOIN_GENESIS } = require('../constants'); -const INPUT_HINT = 'Press the "i" key to begin typing.'; - // Internal Dependencies const fs = require('fs'); const EventEmitter = require('events').EventEmitter; @@ -24,7 +23,12 @@ const Actor = require('./actor'); const Message = require('./message'); const Hash256 = require('./hash256'); const Identity = require('./identity'); +const Filesystem = require('./filesystem'); const Wallet = require('./wallet'); +const Key = require('./key'); + +// Functions +const truncateMiddle = require('../functions/truncateMiddle'); // Services const Bitcoin = require('../services/bitcoin'); @@ -58,14 +62,15 @@ class CLI extends App { // Assign Settings this.settings = merge({ debug: true, + ephemeral: false, listen: false, - peering: true, // set to true to start Peer + peering: true, render: true, services: [], network: 'regtest', interval: 1000, bitcoin: { - mode: 'rpc', // TODO: change name of mode to `rest`? + mode: 'rpc', host: 'localhost', port: 8443, secure: false @@ -74,20 +79,46 @@ class CLI extends App { mode: 'socket', path: './stores/lightning-playnet/regtest/lightning-rpc' }, - }, this.settings, settings); + storage: { + path: `${process.env.HOME}/.fabric/console` + }, + // Add key settings + seed: null, + xprv: null, + passphrase: null + }, settings); + + // Initialize key with proper settings + this.key = new Key({ + seed: this.settings.seed, + xprv: this.settings.xprv, + passphrase: this.settings.passphrase, + network: this.settings.network + }); + + // Ensure key has required properties + if (!this.key.private || !this.key.public || !this.key.sign) { + // Generate new key if properties are missing + this.key = new Key(); + } // Properties this.screen = null; this.history = []; + + this.aliases = {}; + this.channels = {}; this.commands = {}; - this.services = {}; + this.contracts = {}; this.documents = {}; - this.requests = {}; this.elements = {}; - this.channels = {}; this.peers = {}; + this.requests = {}; + this.services = {}; this.connections = {}; + this.fs = new Filesystem(this.settings.storage); + // State this._state = { anchor: null, @@ -98,24 +129,34 @@ class CLI extends App { unconfirmed: 0, }, content: { - actors: {} + actors: {}, + bitcoin: { + best: null, + genesis: BITCOIN_GENESIS + }, + documents: {}, + messages: {} }, contracts: {}, clock: 0 }; this.attachWallet(); - + this.identity = new Identity(this.settings); this._loadPeer(); - this._loadBitcoin(); - this._loadLightning(); - this.identity = new Identity(this.settings); + if (this.settings.bitcoin && this.settings.bitcoin.enable) this._loadBitcoin(); + if (this.settings.lightning && this.settings.lightning.enable) this._loadLightning(); // Chainable return this; } + assumeIdentity (key) { + this.identity = new Identity(key); + return this; + } + attachWallet (wallet) { if (!wallet) wallet = new Wallet(this.settings); @@ -124,14 +165,28 @@ class CLI extends App { return this; } + flush () { + this.fs.delete('STATE'); + return this; + } + _loadPeer () { + const file = this.fs.readFile('STATE'); + const state = (file) ? JSON.parse(file) : {}; + + // Create and assign Peer instance as the `node` property this.node = new Peer({ + debug: this.settings.debug, network: this.settings.network, interface: this.settings.interface, port: this.settings.port, peers: this.settings.peers, - key: this.wallet.key.settings + state: state, + upnp: this.settings.upnp, + key: this.identity.settings }); + + return this; } _loadBitcoin () { @@ -145,7 +200,13 @@ class CLI extends App { } async bootstrap () { - return true; + try { + await this.fs.start(); + return true; + } catch (exception) { + this._appendError(`Could not bootstrap: ${exception}`) + return false; + } } async tick () { @@ -170,6 +231,8 @@ class CLI extends App { this._registerCommand('quit', this._handleQuitRequest); this._registerCommand('exit', this._handleQuitRequest); this._registerCommand('clear', this._handleClearRequest); + this._registerCommand('flush', this._handleFlushRequest); + this._registerCommand('alias', this._handleAliasRequest); this._registerCommand('peers', this._handlePeerListRequest); this._registerCommand('rotate', this._handleRotateRequest); this._registerCommand('connect', this._handleConnectRequest); @@ -179,12 +242,11 @@ class CLI extends App { this._registerCommand('channels', this._handleChannelRequest); this._registerCommand('identity', this._handleIdentityRequest); this._registerCommand('generate', this._handleGenerateRequest); - this._registerCommand('unspent', this._handleUnspentRequest); - this._registerCommand('receive', this._handleReceiveAddressRequest); - this._registerCommand('balance', this._handleBalanceRequest); + this._registerCommand('wallet', this._handleWalletCommand); this._registerCommand('service', this._handleServiceCommand); this._registerCommand('publish', this._handlePublishCommand); this._registerCommand('request', this._handleRequestCommand); + this._registerCommand('grant', this._handleGrantCommand); this._registerCommand('import', this._handleImportCommand); this._registerCommand('join', this._handleJoinRequest); this._registerCommand('sync', this._handleChainSyncRequest); @@ -194,6 +256,13 @@ class CLI extends App { this._registerCommand('set', this._handleSetRequest); this._registerCommand('get', this._handleGetRequest); + // Contracts + this._registerCommand('contracts', this._handleContractsRequest); + this._registerCommand('subscribe', this._handleSubscribeRequest); + this._registerCommand('create', this._handleCreateRequest); + this._registerCommand('deploy', this._handleDeployRequest); + this._registerCommand('accept', this._handleAcceptRequest); + // Service Commands this._registerCommand('bitcoin', this._handleBitcoinRequest); this._registerCommand('lightning', this._handleLightningRequest); @@ -222,6 +291,12 @@ class CLI extends App { this.node.on('error', this._handlePeerError.bind(this)); this.node.on('warning', this._handlePeerWarning.bind(this)); this.node.on('message', this._handlePeerMessage.bind(this)); + this.node.on('changes', this._handlePeerChanges.bind(this)); + this.node.on('commit', this._handlePeerCommit.bind(this)); + this.node.on('state', this._handlePeerState.bind(this)); + this.node.on('chat', this._handlePeerChat.bind(this)); + this.node.on('upnp', this._handlePeerUPNP.bind(this)); + this.node.on('contractset', this._handleContractSet.bind(this)); // ## Raw Connections this.node.on('connection', this._handleConnection.bind(this)); @@ -240,27 +315,31 @@ class CLI extends App { // ## Anchor handlers // ### Bitcoin - this.bitcoin.on('debug', this._handleBitcoinDebug.bind(this)); - this.bitcoin.on('ready', this._handleBitcoinReady.bind(this)); - this.bitcoin.on('error', this._handleBitcoinError.bind(this)); - this.bitcoin.on('warning', this._handleBitcoinWarning.bind(this)); - this.bitcoin.on('message', this._handleBitcoinMessage.bind(this)); - this.bitcoin.on('log', this._handleBitcoinLog.bind(this)); - this.bitcoin.on('commit', this._handleBitcoinCommit.bind(this)); - this.bitcoin.on('sync', this._handleBitcoinSync.bind(this)); - this.bitcoin.on('block', this._handleBitcoinBlock.bind(this)); - this.bitcoin.on('transaction', this._handleBitcoinTransaction.bind(this)); + if (this.settings.bitcoin && this.settings.bitcoin.enable) { + this.bitcoin.on('debug', this._handleBitcoinDebug.bind(this)); + this.bitcoin.on('ready', this._handleBitcoinReady.bind(this)); + this.bitcoin.on('error', this._handleBitcoinError.bind(this)); + this.bitcoin.on('warning', this._handleBitcoinWarning.bind(this)); + this.bitcoin.on('message', this._handleBitcoinMessage.bind(this)); + this.bitcoin.on('log', this._handleBitcoinLog.bind(this)); + this.bitcoin.on('commit', this._handleBitcoinCommit.bind(this)); + this.bitcoin.on('sync', this._handleBitcoinSync.bind(this)); + this.bitcoin.on('block', this._handleBitcoinBlock.bind(this)); + this.bitcoin.on('transaction', this._handleBitcoinTransaction.bind(this)); + } // #### Lightning - this.lightning.on('debug', this._handleLightningDebug.bind(this)); - this.lightning.on('ready', this._handleLightningReady.bind(this)); - this.lightning.on('error', this._handleLightningError.bind(this)); - this.lightning.on('warning', this._handleLightningWarning.bind(this)); - this.lightning.on('message', this._handleLightningMessage.bind(this)); - this.lightning.on('log', this._handleLightningLog.bind(this)); - this.lightning.on('commit', this._handleLightningCommit.bind(this)); - this.lightning.on('sync', this._handleLightningSync.bind(this)); - // this.lightning.on('transaction', this._handleLightningTransaction.bind(this)); + if (this.settings.lightning && this.settings.lightning.enable) { + this.lightning.on('debug', this._handleLightningDebug.bind(this)); + this.lightning.on('ready', this._handleLightningReady.bind(this)); + this.lightning.on('error', this._handleLightningError.bind(this)); + this.lightning.on('warning', this._handleLightningWarning.bind(this)); + this.lightning.on('message', this._handleLightningMessage.bind(this)); + this.lightning.on('log', this._handleLightningLog.bind(this)); + this.lightning.on('commit', this._handleLightningCommit.bind(this)); + this.lightning.on('sync', this._handleLightningSync.bind(this)); + // this.lightning.on('transaction', this._handleLightningTransaction.bind(this)); + } /* this.on('log', function (log) { console.log('local log:', log); @@ -294,10 +373,10 @@ class CLI extends App { // ## Start Anchor Services // Start Bitcoin service - this.bitcoin.start(); + if (this.settings.bitcoin && this.settings.bitcoin.enable) await this.bitcoin.start(); // Start Lightning service - this.lightning.start(); + if (this.settings.lightning.enable) await this.lightning.start(); // ## Start P2P node if (this.settings.peering) this.node.start(); @@ -325,7 +404,7 @@ class CLI extends App { let result = null; try { - result = pointer.get(this._state, path); + result = pointer.get(this._state.content, path); } catch (exception) { this._appendError(`Could not retrieve path "${path}": ${exception}`); } @@ -422,6 +501,17 @@ class CLI extends App { this._appendMessage(`{red-fg}${msg}{/red-fg}`); } + async _handleContractSet (contractset) { + this._appendDebug(`[CONTRACTSET] ${JSON.stringify(contractset, null, ' ')}`); + this.contracts = contractset; + this.commit(); + } + + async _handlePeerState (state) { + // this._appendDebug(`[STATE] ${JSON.stringify(state, null, ' ')}`); + this.fs.publish('STATE', JSON.stringify(state, null, ' ')); + } + async _handleSourceLog (msg) { this._appendMessage(msg); } @@ -442,6 +532,50 @@ class CLI extends App { this._appendMessage(`New Changes: ${JSON.stringify(changes, null, ' ')}`); } + async _handleAcceptRequest (params) { + if (!params || !params[1]) { + this._appendMessage(`You must provide a contract parameter.`); + return false; + } + + const contract = this.contracts[params[1]]; + this._appendMessage(`{bold}Accepting{/bold}: ${params[1]} ${JSON.stringify(contract)}`); + // TODO: sign + return false; + } + + async _handleCreateRequest (params) { + this._appendMessage(`{bold}Creating{/bold}: ${params[1]}`); + const now = (new Date()).toISOString(); + const template = { + created: now, + main: JSON.stringify(async function main () { return {}; }) + }; + + const entity = new Actor(template); + this.contracts[entity.id] = entity; + + if (params[1]) this.aliases[params[1]] = entity.id; + + this._appendDebug(`Created: ${entity.id}`); + return false; + } + + async _handleContractsRequest (params) { + this._appendMessage('{bold}Current Contracts{/bold}: ' + JSON.stringify(this.contracts, null, ' ')); + return false; + } + + async _handleSubscribeRequest (params) { + this._appendMessage('{bold}Subscribing{/bold}: ' + JSON.stringify(params[1], null, ' ')); + return false; + } + + async _handleDeployRequest (params) { + this._appendMessage(`{bold}Deploying{/bold}: ${params[1]}`); + return false; + } + async _handleStateRequest (params) { const value = await this.get(``); this._appendMessage('{bold}Current State{/bold}: ' + JSON.stringify(value, null, ' ')); @@ -479,6 +613,18 @@ class CLI extends App { // TODO: create payment channel (@fabric/core/types/channel) } + /** + * Creates a token for the target signer with a provided role and some optional data. + * @param {Array} params Parameters array. + */ + async _handleGrantCommand (params) { + const target = params[1]; + const role = params[2]; + const extra = params[3]; + + this._appendMessage(`Creating token with role "${role}" for target: ${target}${(extra) ? ' (extra: ' + extra + ')' : ''}`); + } + async _handleJoinRequest (params) { if (!params[1]) return this._appendError(`You must specify a sidechain.`); } @@ -494,6 +640,7 @@ class CLI extends App { const actor = new Actor(content); this._appendMessage(`File contents (${content.length} bytes):\n---${content}\n---\nDocument ID: ${actor.id}`); this.documents[actor.id] = content; + this._state.content.documents[actor.id] = content.toString('hex'); } async _handlePublishCommand (params) { @@ -537,6 +684,8 @@ class CLI extends App { async _handleBitcoinSync (sync) { this._appendMessage(`Bitcoin service emitted sync: ${JSON.stringify(sync)}`); + this._state.content.bitcoin.best = sync.best; + this.commit(); } async _handleBitcoinBlock (block) { @@ -564,6 +713,7 @@ class CLI extends App { } async _handleBitcoinReady (bitcoin) { + this._appendMessage(`Bitcoin ready: ${JSON.stringify(bitcoin)}`); this._syncChainDisplay(); } @@ -577,12 +727,11 @@ class CLI extends App { } async _handleConnectionClose (msg) { - this._appendMessage(`Node emitted "connections:close" event: ${JSON.stringify(msg)}`); + this._appendMessage(`Node emitted "connections:close" event: ${JSON.stringify(msg, null, ' ')}`); for (const id in this.peers) { const peer = this.peers[id]; - this._appendMessage(`Checking: ${JSON.stringify(peer)}`); - if (peer.address === msg.address) { + if (peer.address === msg.name) { this._appendMessage(`Address matches.`); delete this.peers[id]; } @@ -590,14 +739,13 @@ class CLI extends App { for (const id in this.connections) { const connections = this.connections[id]; - this._appendMessage(`Checking: ${JSON.stringify(connections)}`); if (connections.address === msg.address) { - this._appendMessage(`Address matches.`); delete this.connections[id]; } } this._syncPeerList(); + this._syncConnectionList(); } async _handleConnectionError (msg) { @@ -607,7 +755,7 @@ class CLI extends App { async _handleConnection (connection) { if (!connection.id) { // TODO: exit function here - this._appendMessage('Peer did not send an ID. Event received: ' + JSON.stringify(connection)); + this._appendWarning('Peer did not send an ID. Event received: ' + JSON.stringify(connection)); } // TODO: use @fabric/core/types/channel @@ -711,7 +859,7 @@ class CLI extends App { async _handleNodeReady (node) { if (this.settings.render) { - this.elements['identityString'].setContent(node.id); + // this.elements['identityString'].setContent(node.id); } this.emit('identity', { @@ -736,12 +884,32 @@ class CLI extends App { this._appendMessage(`[NODE] ${message}`); } + async _handlePeerChanges (changes) { + // this._appendDebug(`[NODE] [CHANGES] ${JSON.stringify(changes)}`); + this._applyChanges(changes); + this.commit(); + } + + async _handlePeerCommit (commit) { + // this._appendDebug(`[NODE] [COMMIT] ${JSON.stringify(commit)}`); + } + + async _handlePeerChat (chat) { + const truncatedId = truncateMiddle(chat.actor.username || chat.actor.id, 10, '…', 5); + this._appendMessage(`[@${truncatedId}]: ${chat.object.content}`); + } + + async _handlePeerUPNP (upnp) { + this._appendDebug(`[UPNP] ${JSON.stringify(upnp)}`); + } + async _handlePeerMessage (message) { switch (message.type) { case 'ChatMessage': try { const parsed = JSON.parse(message.data); - this._appendMessage(`[@${parsed.actor}]: ${parsed.object.content}`); + const truncatedId = truncateMiddle(parsed.actor.username || parsed.actor, 10, '…', 5); + this._appendMessage(`[@${truncatedId}]: ${parsed.object.content}`); } catch (exception) { this._appendError(`Could not parse data (should be JSON): ${message.data}`); } @@ -850,7 +1018,10 @@ class CLI extends App { if (!self._processInput(data.input)) { // Describe the activity for use in P2P message const msg = { - actor: self.node.id, + type: 'P2P_CHAT_MESSAGE', + actor: { + id: self.node.id + }, object: { created: Date.now(), content: content @@ -858,11 +1029,18 @@ class CLI extends App { target: '/messages' }; - const message = Message.fromVector(['ChatMessage', JSON.stringify(msg)]); - this._appendDebug(`Chat Message created (${message.data.length} bytes): ${message.data}`); + let message = Message.fromVector(['ChatMessage', JSON.stringify(msg)]); + message = message.signWithKey(this.key); + self.setPane('messages'); + // Log own message + self._handlePeerChat(msg); + + // Relay to peers self.node.relayFrom(self.node.id, message); + + // Notify services self._sendToAllServices(msg); } @@ -876,11 +1054,29 @@ class CLI extends App { return false; } + _handleAliasRequest (params) { + if (!params) return false; + if (!params[1]) { + this._appendError('No alias provided.'); + return false; + } + + this.node._announceAlias(params[1]); + + return false; + } + _handleClearRequest () { this.elements['messages'].setContent(''); return false; } + _handleFlushRequest () { + this.flush(); + this.stop(); + return false; + } + _handlePeerListRequest (params) { this._appendMessage('Peers: ' + JSON.stringify(this.peers, null, ' ')); return false; @@ -997,8 +1193,10 @@ class CLI extends App { _handleIdentityRequest () { this._appendMessage(`Local Identity: ${JSON.stringify({ - id: this.node.id, - address: this.node.server.address() + id: this.identity.id, + pubkey: this.identity.pubkey, + address: this.node.server.address(), + endpoint: `${this.identity.id}@${this.settings.host}:${this.settings.port}` }, null, ' ')}`); } @@ -1006,11 +1204,16 @@ class CLI extends App { this._appendMessage(`Local Settings: ${JSON.stringify(this.settings, null, ' ')}`); } - _handleHelpRequest (data) { - const self = this; - const help = `Available Commands:\n${Object.keys(self.commands).map(x => `\t${x}`).join('\n')}`; + _handleHelpRequest (params) { + let text = ''; + + switch (params[1]) { + default: + text = `{bold}Fabric CLI Help{/bold}\nThe Fabric CLI offers a simple command-based interface to a Fabric-speaking Network. You can use \`/connect

    \` to establish a connection to a known peer, or any of the available commands.\n\n{bold}Available Commands{/bold}:\n\n${Object.keys(this.commands).map(x => `\t${x}`).join('\n')}\n` + break; + } - self._appendMessage(help); + this._appendMessage(text); } _handleServiceMessage (msg) { @@ -1036,6 +1239,7 @@ class CLI extends App { async _syncChainDisplay () { if (!this.settings.render) return this; + if (!this.settings.bitcoin.enable) return this; try { const height = await this.bitcoin._makeRPCRequest('getblockcount'); @@ -1048,7 +1252,7 @@ class CLI extends App { this.elements['chainTip'].setContent(`${stats.bestblockhash}`); this.elements['unconfirmedValue'].setContent(`${bonded}`); this.elements['bondedValue'].setContent(`${bonded}`); - this.elements['progressStatus'].setContent(`${progress} of ${height} (${((progress / height) * 100).toPrecision(2)} %)`); + this.elements['progressStatus'].setContent(`${progress - 1} of ${height} (${(((progress - 1) / height) * 100)} %)`); this.screen.render(); } catch (exception) { @@ -1057,7 +1261,7 @@ class CLI extends App { } async _syncContracts () { - await this._syncLightningChannels(); + if (this.settings.lightning.enable) await this._syncLightningChannels(); return this; } @@ -1131,6 +1335,25 @@ class CLI extends App { return balance; } + _allConfigured () { + if ( + this._isBitcoinConfigured() && + this._isLightningConfigured() + ) { + return true; + } else { + return false; + } + } + + _isBitcoinConfigured () { + return (this.settings.bitcoin) ? true : false; + } + + _isLightningConfigured () { + return (this.settings.lightning) ? true : false; + } + _syncConnectionList () { this.elements['connections'].clearItems(); @@ -1149,7 +1372,7 @@ class CLI extends App { const element = blessed.element({ name: connection.id, - content: `[${icon}] ${connection.id}@${connection.address}` + content: `[${icon}] ${id}` }); // TODO: use peer ID for managed list @@ -1425,10 +1648,10 @@ class CLI extends App { } }, commands: { - 'Help': { + 'Home': { keys: ['f1'], callback: function () { - this.setPane('help'); + this.setPane('home'); }.bind(this) }, 'Console': { @@ -1739,12 +1962,16 @@ class CLI extends App { self.elements['form'].on('submit', self._handleFormSubmit.bind(self)); // this.focusInput(); + this.elements['identityString'].setContent(this.identity.id); this.setPane('messages'); setInterval(function () { // self._appendMessage('10 seconds have passed.'); // self.bitcoin.generateBlock(); }, 10000); + + // Enable mouse support + self.screen.program.enableMouse(); } tableDataFor (input = [], exclusions = []) { @@ -1763,6 +1990,31 @@ class CLI extends App { return [ keys ].concat(entries); } + + async _handleWalletCommand (params) { + if (!params[1]) { + this._appendMessage('Available wallet commands:'); + this._appendMessage(' wallet balance - Show current balance'); + this._appendMessage(' wallet send
    - Send funds to address'); + this._appendMessage(' wallet receive - Generate a new receive address'); + this._appendMessage(' wallet unspent - List unspent outputs'); + return false; + } + + switch (params[1]) { + case 'balance': + return this._handleBalanceRequest(params); + case 'send': + return this._handleSendRequest(params); + case 'receive': + return this._handleReceiveAddressRequest(params); + case 'unspent': + return this._handleUnspentRequest(params); + default: + this._appendError(`Unknown wallet command: ${params[1]}`); + return false; + } + } } module.exports = CLI; diff --git a/types/codec.js b/types/codec.js index 4c968e4bb..beebffc62 100644 --- a/types/codec.js +++ b/types/codec.js @@ -59,6 +59,7 @@ class Codec { return blob; } catch (exception) { console.error('err:', exception); + return null; } } diff --git a/types/compiler.js b/types/compiler.js index d20abe0a6..949682a14 100644 --- a/types/compiler.js +++ b/types/compiler.js @@ -45,19 +45,7 @@ const Machine = require('./machine'); // ``` // This will auto-configure validation base from chain of greatest work. -/** - * Compilers build interfaces for users of Fabric applications. - * @type {Actor} - * @property {AST} ast Compiler's current AST. - * @property {Entity} entity Compiler's current {@link Entity}. - */ class Compiler { - /** - * Create a new Compiler. - * @param {Object} settings={} Configuration. - * @param {Buffer} settings.body Body of the input program to compile. - * @return {Compiler} Instance of the compiler. - */ constructor (settings = {}) { this.settings = Object.assign({ ast: null, diff --git a/types/consensus.js b/types/consensus.js index 7bd0edd84..706cae448 100644 --- a/types/consensus.js +++ b/types/consensus.js @@ -7,16 +7,7 @@ // For node... const bcoin = require('bcoin'); -/** - * Provides various network-specific rules. - */ class Consensus { - /** - * Create an instance of a {@link Consensus} verifier. - * @param {Object} [settings] Configuration for the network. - * @param {String} [settings.network] Name of the network. - * @param {String} [settings.provider] Name of the source provider. - */ constructor (settings = {}) { this.settings = Object.assign({ network: 'mainnet', diff --git a/types/contract.js b/types/contract.js index ed9eef402..791f2c6c9 100644 --- a/types/contract.js +++ b/types/contract.js @@ -1,14 +1,20 @@ 'use strict'; +// Generics +const crypto = require('crypto'); + // Dependencies +// const Template = require('@babel/template'); +// const Generate = require('@babel/generator'); +// const t = require('@babel/types'); const parser = require('dotparser'); +const monitor = require('fast-json-patch'); // Fabric Types const Actor = require('./actor'); -const Hash256 = require('./hash256'); const Key = require('./key'); +const Message = require('./message'); const Service = require('./service'); -const Signer = require('./signer'); class Contract extends Service { constructor (settings = {}) { @@ -36,6 +42,8 @@ class Contract extends Service { // tweaked pubkey this.key = new Key(this.settings.key); + this.messages = {}; + this._inner = null; this._state = { status: 'PAUSED', @@ -45,6 +53,8 @@ class Contract extends Service { content: this.settings.state }; + this.observer = monitor.observe(this._state.content); + return this; } @@ -62,12 +72,42 @@ class Contract extends Service { return contract; }; + static fromJavaScript (js) { + const buildAST = Template.template(js); + const ast = buildAST({}); + return new Contract({ ast }); + } + static fromGraph (graphs) { const circuit = { stack: [], nodes: [] }; + for (let i = 0; i < graphs.length; i++) { + const graph = graphs[i]; + const node = { + name: graph.id + }; + + circuit.nodes.push(node); + + if (!graph.children.length) continue; + for (let j = 0; j < graph.children.length; j++) { + const child = graph.children[j]; + switch (child.type) { + default: + console.warn(`Unhandled type: "${child.type}'" on child:`, child); + break; + case 'node_stmt': + circuit.nodes.push({ + name: child.node_id.id + }); + break; + } + } + } + return circuit; } @@ -79,6 +119,70 @@ class Contract extends Service { return contract.trim(); } + /** + * Deploys the contract. + * @returns {String} Message ID. + */ + deploy () { + // Attest to local time + const now = (new Date()).toISOString(); + const input = { + clock: 0, + validators: [] + }; + + // First message (genesis) + const PACKET_CONTRACT_GENESIS = Message.fromVector(['CONTRACT_GENESIS', JSON.stringify({ + type: 'CONTRACT_GENESIS', + object: { + input: input + } + })]).signWithKey(this.key).toBuffer(); + + // Get hash of message + const hash = crypto.createHash('sha256').update(PACKET_CONTRACT_GENESIS).digest('hex'); + + // Store locally + this.messages[hash] = PACKET_CONTRACT_GENESIS.toString('hex'); + + // Contract template + const template = { + author: this.key.pubkey, + bond: null, // BTC transaction which is spent + checksum: '', + created: now, + genesis: hash, + history: [ hash ], // most recent first + messages: this.messages, + name: this.settings.name, + signature: '', + state: input, + version: 1 + }; + + // Track our contract by Actor ID + this.actor = new Actor(template); + this.emit('log', `Deploying Contract [0x${this.actor.id}] (${PACKET_CONTRACT_GENESIS.byteLength} bytes): ${this.messages[hash]}`); + + // Network publish message (contract) + const PACKET_CONTRACT_PUBLISH = Message.fromVector(['CONTRACT_PUBLISH', JSON.stringify({ + type: 'CONTRACT_PUBLISH', + object: template + })]).signWithKey(this.key); + + const signed = PACKET_CONTRACT_PUBLISH.signWithKey(this.key); + const pubhash = crypto.createHash('sha256').update(signed.toBuffer()).digest('hex'); + + this.messages[pubhash] = PACKET_CONTRACT_PUBLISH.toString('hex'); + this.emit('message', signed); + + return this; + } + + toDot () { + const tokens = []; + } + parse (input) { return this.parseDot(input); } @@ -99,18 +203,28 @@ class Contract extends Service { } commit () { - super.commit(); + const now = new Date(); + const changes = monitor.generate(this.observer); - const template = { - // created: (new Date()).toISOString(), - state: this.state - }; + if (changes.length) { + const message = Message.fromVector(['CONTRACT_MESSAGE', { + type: 'CONTRACT_MESSAGE', + object: { + contract: this.id, + ops: changes + } + }]); - const actor = new Actor(template); + this.emit('changes', changes); + this.emit('message', message); + } - this.emit('contract:commit', actor.toGenericMessage()); + this.emit('commit', { + created: now.toISOString(), + state: this.state + }); - return {}; + return this; } execute () { @@ -130,7 +244,7 @@ class Contract extends Service { const json = JSON.stringify(baseline); // native JSON.stringify const buffer = Buffer.from(json, 'utf8'); - const signer = new Signer(identity); + const signer = new Key(identity); const signature = signer.sign(buffer); return { signature }; @@ -151,6 +265,11 @@ class Contract extends Service { }); } + _handleBitcoinTransaction () { + // TODO: parse on-chain transaction for update to contract balance + // Does this transaction pay to this contract? + } + _toUnsignedTransaction () { return { script: this.contract diff --git a/types/entity.js b/types/entity.js index 9901612a6..ebc4b2ab9 100644 --- a/types/entity.js +++ b/types/entity.js @@ -3,16 +3,7 @@ const crypto = require('crypto'); const { EventEmitter } = require('events'); -/** - * Live instance of an ARC in Fabric. - * @type {Object} - */ class Entity extends EventEmitter { - /** - * Generic template for virtual objects. - * @param {Object} [data={}] Pass an object to use. - * @return {Entity} Instance of the {@link Entity}. - */ constructor (data = {}) { super(data); diff --git a/types/environment.js b/types/environment.js index c9fd17180..a48ed6931 100644 --- a/types/environment.js +++ b/types/environment.js @@ -10,6 +10,7 @@ const fs = require('fs'); const merge = require('lodash.merge'); // Fabric Types +const Actor = require('./actor'); const Entity = require('./entity'); const EncryptedPromise = require('./promise'); const Wallet = require('./wallet'); @@ -32,6 +33,9 @@ class Environment extends Entity { this.settings = merge({ home: process.env.HOME, path: process.env.HOME + '/.fabric/wallet.json', + state: { + status: 'INITIALIZED' + }, store: process.env.HOME + '/.fabric' }, this.settings, settings); @@ -39,14 +43,22 @@ class Environment extends Entity { this.wallet = null; this._state = { - status: 'INITIALIZED', - content: {}, + status: this.settings.state.status, + content: this.settings.state, variables: process.env }; return this; } + get state () { + return JSON.parse(JSON.stringify(this._state.content)); + } + + get status () { + return this._state.status; + } + get SEED_FILE () { return '.FABRIC_SEED'; } @@ -69,6 +81,7 @@ class Environment extends Entity { get seed () { return [ + FIXTURE_SEED, this.settings.seed, this['FABRIC_SEED'], this.readVariable('FABRIC_SEED') @@ -77,9 +90,21 @@ class Environment extends Entity { get xprv () { return [ + // FIXTURE_XPRV, this.settings.xprv, this['FABRIC_XPRV'], - this.readVariable('FABRIC_XPRV') + this.readVariable('FABRIC_XPRV'), + this.wallet.xprv + ].find(any); + } + + get xpub () { + return [ + // FIXTURE_XPUB, + this.settings.xpub, + this['FABRIC_XPUB'], + this.readVariable('FABRIC_XPUB'), + this.wallet.xpub ].find(any); } @@ -153,7 +178,9 @@ class Environment extends Entity { this.wallet = new Wallet({ key: { - xprv: input.object.xprv + seed: input.object.seed, + xprv: input.object.xprv, + xpub: input.object.xpub } }); } catch (exception) { @@ -268,6 +295,21 @@ class Environment extends Entity { this._state.status = 'STOPPED'; return this; } + + verify () { + const state = new Actor(this.state); + if (state.id !== '3c141a17b967d9d50770ebcc3beac9f3bd695f728e8f4fb8988d913794998078') throw new Error(`Incorrect state: ${state.id}`); + + if (![ + 'INITIALIZED', + 'STARTED', + 'STARTING', + 'STOPPED', + 'STOPPING' + ].includes(this.status)) throw new Error(`Invalid status: ${this.status}`); + + return true; + } } module.exports = Environment; diff --git a/types/fabric.js b/types/fabric.js index d74960b99..beb7613c0 100644 --- a/types/fabric.js +++ b/types/fabric.js @@ -5,7 +5,6 @@ const crypto = require('crypto'); // components const Actor = require('../types/actor'); -const App = require('../types/app'); const Block = require('../types/block'); const Chain = require('../types/chain'); const Circuit = require('../types/circuit'); @@ -13,19 +12,17 @@ const Collection = require('../types/collection'); // const Contract = require('./contract'); // const Disk = require('./disk'); const Entity = require('../types/entity'); +const Hash256 = require('../types/hash256'); const Key = require('../types/key'); -const Ledger = require('../types/ledger'); const Machine = require('../types/machine'); const Message = require('../types/message'); const Observer = require('../types/observer'); -const Opcode = require('../types/opcode'); const Oracle = require('../types/oracle'); -// const Peer = require('./peer'); +const Peer = require('../types/peer'); const Program = require('../types/program'); -// const Remote = require('../types/remote'); +const Remote = require('../types/remote'); const Resource = require('../types/resource'); const Service = require('../types/service'); -const Scribe = require('../types/scribe'); const Script = require('../types/script'); const Stack = require('../types/stack'); const State = require('../types/state'); @@ -98,7 +95,7 @@ class Fabric extends Service { }; } - static get App () { return App; } + static get Actor () { return Actor; } static get Block () { return Block; } static get Chain () { return Chain; } static get Circuit () { return Circuit; } @@ -106,25 +103,23 @@ class Fabric extends Service { // static get Contract () { return Contract; } // static get Disk () { return Disk; } static get Entity () { return Entity; } + static get Hash256 () { return Hash256; } static get Key () { return Key; } - static get Ledger () { return Ledger; } static get Machine () { return Machine; } static get Message () { return Message; } static get Observer () { return Observer; } static get Oracle () { return Oracle; } - // static get Peer () { return Peer; } + static get Peer () { return Peer; } static get Program () { return Program; } static get Remote () { return Remote; } static get Resource () { return Resource; } static get Service () { return Service; } - static get Scribe () { return Scribe; } static get Script () { return Script; } static get Stack () { return Stack; } static get State () { return State; } static get Store () { return Store; } - static get Swarm () { return Swarm; } + // static get Swarm () { return Swarm; } // static get Transaction () { return Transaction; } - static get Vector () { return Vector; } static get Wallet () { return Wallet; } static get Worker () { return Worker; } @@ -245,7 +240,7 @@ class Fabric extends Service { use (name, description) { this.log('[FABRIC]', `defining ${name} as:`, description); - this.opcodes[name] = new Opcode(description); + this.opcodes[name] = description.bind(this); return this.define(name, description); } diff --git a/types/fabric.mjs b/types/fabric.mjs new file mode 100644 index 000000000..e2f7448c3 --- /dev/null +++ b/types/fabric.mjs @@ -0,0 +1,233 @@ +'use strict'; + +// external dependencies +import crypto from 'crypto'; + +// components +import Actor from '../types/actor.js'; +// import Application from '../types/application.js'; +import Block from '../types/block.js'; +import Chain from '../types/chain.js'; +import Circuit from '../types/circuit.js'; +import Collection from '../types/collection.js'; +import Entity from '../types/entity.js'; +import Key from '../types/key.js'; +import Ledger from '../types/ledger.js'; +import Machine from '../types/machine.js'; +import Message from '../types/message.js'; +import Observer from '../types/observer.js'; +import Oracle from '../types/oracle.js'; +import Peer from '../types/peer.js'; +import Program from '../types/program.js'; +import Remote from '../types/remote.js'; +import Resource from '../types/resource.js'; +import Service from '../types/service.js'; +import Scribe from '../types/scribe.js'; +import Script from '../types/script.js'; +import Stack from '../types/stack.js'; +import State from '../types/state.js'; +import Store from '../types/store.js'; +import Vector from '../types/vector.js'; +import Wallet from '../types/wallet.js'; +import Worker from '../types/worker.js'; + +/** + * Reliable decentralized infrastructure. + */ +class Fabric extends Service { + /** + * The {@link Fabric} type implements a peer-to-peer protocol for + * establishing and settling of mutually-agreed upon proofs of + * work. Contract execution takes place in the local node first, + * then is optionally shared with the network. + * + * Utilizing + * @exports Fabric + * @constructor + * @param {Vector} config - Initial configuration for the Fabric engine. This can be considered the "genesis" state for any contract using the system. If a chain of events is maintained over long periods of time, `state` can be considered "in contention", and it is demonstrated that the outstanding value of the contract remains to be settled. + * @emits Fabric#thread + * @emits Fabric#step Emitted on a `compute` step. + */ + constructor (settings = {}) { + super(settings); + + // local settings + this.settings = Object.assign({ + path: './stores/fabric', + persistent: false, + state: { + ...super.state, + ...settings.state + } + }, settings); + + // start with reference to object + this.ident = new Actor(this.settings); + + // build maps + this.agent = {}; // Identity + this.modules = {}; // List + this.opcodes = {}; // Map + this.peers = {}; // Map + this.plugins = {}; // Map + this.services = {}; // Map + + // initialize components + this.chain = new Chain(this.settings); + this.machine = new Machine(this.settings); + this.store = new Store(this.settings); + + this._state = { + status: 'PAUSED', + content: this.settings.state + }; + + // provide instance + return this; + } + + static get registry () { + return { + local: new URL('../services/local.js', import.meta.url) + }; + } + + static get Actor() { return Actor; } + // static get Application () { return Application; } + static get Block () { return Block; } + static get Chain () { return Chain; } + static get Circuit () { return Circuit; } + static get Collection () { return Collection; } + static get Entity () { return Entity; } + static get Key () { return Key; } + static get Ledger () { return Ledger; } + static get Machine () { return Machine; } + static get Message () { return Message; } + static get Observer () { return Observer; } + static get Oracle () { return Oracle; } + static get Peer () { return Peer; } + static get Program () { return Program; } + static get Remote () { return Remote; } + static get Resource () { return Resource; } + static get Service () { return Service; } + static get Scribe () { return Scribe; } + static get Script () { return Script; } + static get Stack () { return Stack; } + static get State () { return State; } + static get Store () { return Store; } + static get Vector () { return Vector; } + static get Wallet () { return Wallet; } + static get Worker () { return Worker; } + + static sha256 (data) { + return crypto.createHash('sha256').update(data).digest('hex'); + } + + static random () { + return Math.random(); + } + + async _GET (key) { + return this.store._GET(key); + } + + async _SET (key, value) { + return this.store._SET(key, value); + } + + async _PUT (key, value) { + return this.store._SET(key, value); + } + + async _POST (collection, value) { + return this.store._POST(collection, value); + } + + async _PATCH (key, overlay) { + return this.store._PATCH(key, overlay); + } + + async _DELETE (key) { + return this.store._DELETE(key); + } + + async register (service) { + if (!service) return new Error('Service must be provided.'); + + try { + const name = service.name || service.constructor.name; + this.modules[name.toLowerCase()] = service; + this.emit('message', { + '@type': 'ServiceRegistration', + '@data': { name: name } + }); + } catch (E) { + this.error('Could not register service:', E); + } + + return this; + } + + async enable (name) { + const self = this; + let Module = null; + let config = Object.assign({ + name: name, + path: `./stores/${name}` + }, this.config[name]); + + if (this.modules[name]) { + Module = this.modules[name]; + } else { + return this.error(`Could not enable module ${name}. Check local registry.`); + } + + // configure the service + this.services[name] = new Module(config); + this.services[name].on('ready', function () { + self.emit('service:ready', { name }); + }); + + // bind all events + self.trust(this.services[name]); + + try { + await this.services[name].start(); + this.emit('message', { + '@type': 'ServiceStartup', + '@data': { name: name } + }); + } catch (E) { + console.error(`exceptioning:`, E); + } + + return this; + } + + append (value) { + return this.chain.append(value); + } + + set (key, value) { + return State.pointer.set(this['@entity'], key, value); + } + + get (key) { + return State.pointer.get(this['@entity'], key); + } + + push (value) { + let name = value.constructor.name; + if (name !== 'Vector') value = new Vector(value)._sign(); + this.machine.script.push(value); + return this.machine.script; + } + + use (name, description) { + this.log('[FABRIC]', `defining ${name} as:`, description); + this.opcodes[name] = description.bind(this); + return this.define(name, description); + } +} + +export default Fabric; \ No newline at end of file diff --git a/types/federation.js b/types/federation.js index 617438396..33e2e6085 100644 --- a/types/federation.js +++ b/types/federation.js @@ -3,6 +3,9 @@ // Dependencies const merge = require('lodash.merge'); const { run } = require('minsc'); +const crypto = require('crypto'); +const ecc = require('tiny-secp256k1'); +const bitcoin = require('bitcoinjs-lib'); // Fabric Types const Contract = require('./contract'); @@ -27,7 +30,7 @@ class Federation extends Contract { consensus: { validators: [] }, - identity: { + key: { password: '', // derivation password seed: null, // seed phrase (!!!) xprv: null, // avoid using seed phrase @@ -37,14 +40,15 @@ class Federation extends Contract { }, settings); // Internal Key - this.key = new Key(this.settings.identity); - this.wallet = new Wallet(this.settings.identity); + this.key = new Key(this.settings.key); + this.wallet = new Wallet(this.settings.key); // Internal State this._state = { consensus: this.settings.consensus, content: { clock: this.settings.clock, + keys: {}, validators: this.settings.consensus.validators }, status: 'PAUSED' @@ -71,15 +75,34 @@ class Federation extends Contract { likely@$federation || ($timeout && $recovery) `; - console.log('contract:', contract); return contract.trim(); } addMember (member) { - const key = new Key(member); - this._state.content.validators.push(key.pubkey); - console.log('consensus validators:', this._state.content.validators); - console.log('contract for step 0:', this.contractForStep(0)); + // Create key with proper settings + const keySettings = { + private: member.private, + public: member.public || member.pubkey + }; + + const key = new Key(keySettings); + + // Verify the key was created properly + if (member.private && !key.private) { + throw new Error('Failed to initialize private key'); + } + + // Store the member's public key in hex format + const pubkey = key.public.encodeCompressed('hex'); + this._state.content.validators.push(pubkey); + + // Store the member's key for signing + this._state.content.keys = this._state.content.keys || {}; + this._state.content.keys[pubkey] = key; + + // console.log('consensus validators:', this._state.content.validators); + // console.log('contract for step 0:', this.contractForStep(0)); + this.commit(); } @@ -90,7 +113,7 @@ class Federation extends Contract { const policy = run(` $A = ${this._state.content.validators[index]}; pk($A) - `); + ` || this.contract); const miniscript = run(`miniscript(${policy})`); const descriptor = run(`wsh(${miniscript})`); @@ -142,6 +165,191 @@ class Federation extends Contract { this.commit(); return this; } + + /** + * Signs a message using the federation's key. + * @param {Buffer|String|Message} msg - The message to sign + * @param {String} [pubkey] - Optional public key of the member to sign with + * @returns {Buffer} The signature + */ + sign (msg, pubkey) { + // Handle Message objects + const messageToSign = msg.data ? msg.data : msg; + + // If pubkey is provided, use that specific key + if (pubkey) { + const key = this._state.content.keys[pubkey]; + if (key && key.private) { + return key.signSchnorr(messageToSign); + } + throw new Error(`No private key available for member ${pubkey}`); + } + + // Otherwise use the first available key with private key access + for (const memberPubkey of this._state.content.validators) { + const key = this._state.content.keys[memberPubkey]; + if (key && key.private) { + return key.signSchnorr(messageToSign); + } + } + throw new Error('No private key available for signing'); + } + + /** + * Verifies a signature against a message. + * @param {Buffer|String|Message} msg - The message that was signed + * @param {Buffer} sig - The signature to verify + * @returns {Boolean} Whether the signature is valid + */ + verify (msg, sig) { + // Handle Message objects + const messageToVerify = msg.data ? msg.data : msg; + + // Try to verify with any of the federation's keys + for (const pubkey of this._state.content.validators) { + const key = this._state.content.keys[pubkey]; + if (key && key.verifySchnorr(messageToVerify, sig)) { + return true; + } + } + return false; + } + + /** + * Creates a multi-signature for a message. + * @param {Buffer|String|Message} msg - The message to sign + * @returns {Object} The multi-signature object containing signatures from all validators + */ + createMultiSignature (msg) { + const signatures = {}; + // Handle Message objects + const messageToSign = msg.data ? msg.data : msg; + for (const pubkey of this._state.content.validators) { + const key = this._state.content.keys[pubkey]; + if (key && key.private) { + signatures[pubkey] = key.signSchnorr(messageToSign); + } + } + return { + message: msg, + signatures + }; + } + + /** + * Verifies a multi-signature against a message. + * @param {Object} multiSig - The multi-signature object + * @param {Number} threshold - Number of valid signatures required + * @returns {Boolean} Whether the multi-signature is valid + */ + verifyMultiSignature (multiSig, threshold = 1) { + const { message, signatures } = multiSig; + let validCount = 0; + + // Handle Message objects and Buffers + let messageToVerify; + if (Buffer.isBuffer(message)) { + messageToVerify = message; + } else if (message.raw && message.raw.data) { + messageToVerify = message.raw.data; + } else if (typeof message === 'string') { + messageToVerify = Buffer.from(message); + } else if (typeof message === 'object') { + messageToVerify = Buffer.from(JSON.stringify(message)); + } else { + messageToVerify = message; + } + + // Ensure messageToVerify is a Buffer + if (!Buffer.isBuffer(messageToVerify)) { + messageToVerify = Buffer.from(messageToVerify); + } + + // Create message hash once for all verifications + const messageHash = crypto.createHash('sha256').update(messageToVerify).digest(); + + for (const [pubkey, signature] of Object.entries(signatures)) { + const key = this._state.content.keys[pubkey]; + if (key) { + // Get x-only public key (32 bytes) from compressed public key (33 bytes) + const compressedPubkey = Buffer.from(key.public.encodeCompressed('hex'), 'hex'); + const xOnlyPubkey = compressedPubkey.slice(1); // Remove the prefix byte + + // Ensure signature is a Buffer + const sigBuffer = Buffer.isBuffer(signature) ? signature : Buffer.from(signature); + + // Verify using tiny-secp256k1's Schnorr implementation + if (ecc.verifySchnorr(messageHash, xOnlyPubkey, sigBuffer)) { + validCount++; + if (validCount >= threshold) { + return true; + } + } + } + } + + return false; + } + + get address () { + // Get the public keys of all validators + const pubkeys = this._state.content.validators.map(pubkey => Buffer.from(pubkey, 'hex')); + + // Create the threshold script for majority of signers + const threshold = Math.ceil(pubkeys.length / 2); + const thresholdScript = bitcoin.script.compile([ + bitcoin.opcodes.OP_PUSHNUM_1 + threshold - 1, + ...pubkeys.map(pubkey => Buffer.concat([ + Buffer.from([pubkey.length]), + pubkey + ])), + bitcoin.opcodes.OP_PUSHNUM_1 + pubkeys.length, + bitcoin.opcodes.OP_CHECKMULTISIG + ]); + + // Create the taproot tree + const tree = [ + { + script: thresholdScript, + weight: 1 + } + ]; + + // Add timeout condition if specified in settings + if (this.settings.timeout) { + const timeoutScript = bitcoin.script.compile([ + bitcoin.opcodes.OP_CHECKLOCKTIMEVERIFY, + bitcoin.opcodes.OP_DROP, + ...thresholdScript + ]); + tree.push({ + script: timeoutScript, + weight: 1 + }); + } + + // Add contract condition if specified in settings + if (this.settings.contract) { + // If contract is a string, assume it's a script hex + const contractScript = typeof this.settings.contract === 'string' + ? Buffer.from(this.settings.contract, 'hex') + : this.settings.contract; + + tree.push({ + script: contractScript, + weight: 1 + }); + } + + // Create the taproot output + const output = bitcoin.payments.p2tr({ + internalPubkey: pubkeys[0].slice(1), // Use first validator's x-only pubkey + scriptTree: tree, + network: bitcoin.networks.bitcoin + }); + + return output.address; + } } module.exports = Federation; diff --git a/types/filesystem.js b/types/filesystem.js index e39aa4e4f..d3a43bec8 100644 --- a/types/filesystem.js +++ b/types/filesystem.js @@ -4,10 +4,13 @@ const fs = require('fs'); const path = require('path'); const mkdirp = require('mkdirp'); +//const chokidar = require('chokidar'); // Fabric Types const Actor = require('./actor'); const Hash256 = require('./hash256'); +const Key = require('./key'); +const Message = require('./message'); const Tree = require('./tree'); /** @@ -18,6 +21,7 @@ class Filesystem extends Actor { * Synchronize an {@link Actor} with a local filesystem. * @param {Object} [settings] Configuration for the Fabric filesystem. * @param {Object} [settings.path] Path of the local filesystem. + * @param {Object} [settings.key] Signing key for the filesystem. * @returns {Filesystem} Instance of the Fabric filesystem. */ constructor (settings = {}) { @@ -25,9 +29,17 @@ class Filesystem extends Actor { this.settings = Object.assign({ encoding: 'utf8', - path: './' + path: './', + key: null }, this.settings, settings); + // Ensure path is absolute + this.settings.path = path.resolve(this.settings.path); + + // Initialize signing key + this.key = this.settings.key ? new Key(this.settings.key) : new Key(); + this.pubkey = this.key.pubkey; + this.tree = new Tree({ leaves: [] }); @@ -35,7 +47,9 @@ class Filesystem extends Actor { this._state = { actors: {}, content: { - files: [] + files: [], + parent: null, + status: 'INITIALIZED' }, documents: {} }; @@ -50,27 +64,37 @@ class Filesystem extends Actor { get hashes () { const self = this; return self.files.map(f => { - return Hash256.digest(self.readFile(f)); - }); + const content = self.readFile(f); + if (!content) return null; + return Hash256.digest(content); + }).filter(hash => hash !== null); } get files () { - return this.ls(); + return this.ls().filter(file => file !== '.fabric'); } get leaves () { const self = this; return self.files.map(f => { - const hash = Hash256.digest(self.readFile(f)); + const content = self.readFile(f); + if (!content) return null; + const hash = Hash256.digest(content); const key = [f, hash].join(':'); return Hash256.digest(key); - }); + }).filter(leaf => leaf !== null); } get documents () { return this._state.documents; } + delete (name) { + const file = path.join(this.path, name); + if (fs.existsSync(file)) fs.rmSync(file); + return true; + } + /** * Get the list of files. * @returns {Array} List of files. @@ -106,6 +130,10 @@ class Filesystem extends Actor { readFile (name) { const file = path.join(this.path, name); if (!fs.existsSync(file)) return null; + + // Skip directories + if (fs.statSync(file).isDirectory()) return null; + return fs.readFileSync(file); } @@ -116,32 +144,64 @@ class Filesystem extends Actor { * @returns {Boolean} `true` if the write succeeded, `false` if it did not. */ writeFile (name, content) { - const file = path.join(this.path, name); + // Ensure the file path is absolute and properly resolved + const file = path.resolve(this.path, name); try { + // Ensure parent directory exists + const parentDir = path.dirname(file); + if (!fs.existsSync(parentDir)) { + mkdirp.sync(parentDir); + } + + this.touch(file); fs.writeFileSync(file, content); + + // Emit file update event + this._handleDiskChange('change', name); + return true; } catch (exception) { - this.emit('error', `Could not write file: ${content}`); + this.emit('error', `Could not write file: ${content} ${exception}`); return false; } } + _handleDiskChange (type, filename) { + this.emit('file:update', { + name: filename, + type: type + }); + + // TODO: only sync changed files + // this._loadFromDisk(); + + return this; + } + /** * Load Filesystem state from disk. * @returns {Promise} Resolves with Filesystem instance. */ _loadFromDisk () { - const self = this; return new Promise((resolve, reject) => { try { - const files = fs.readdirSync(self.path); - self._state.content = { files }; - self.commit(); - - resolve(self); + // Check for STATE file in .fabric directory + const statePath = path.join(this.path, '.fabric', 'STATE'); + if (fs.existsSync(statePath)) { + const stateHex = fs.readFileSync(statePath, 'utf8'); + const stateBuffer = Buffer.from(stateHex, 'hex'); + const state = JSON.parse(stateBuffer.toString()); + this._state.content = state; + } + + const files = fs.readdirSync(this.path); + this._state.content.files = files.filter(file => file !== '.fabric'); + this.commit(); + + resolve(this); } catch (exception) { - self.emit('error', exception); + this.emit('error', exception); reject(exception); } }); @@ -163,19 +223,19 @@ class Filesystem extends Actor { } async publish (name, document) { - if (typeof document !== 'string') { - document = JSON.stringify(document, null, ' '); - } - + const content = typeof document === 'string' ? document : JSON.stringify(document, null, ' '); const actor = new Actor(document); - const hash = Hash256.digest(document); + const hash = Hash256.digest(content); + // Update state this._state.actors[actor.id] = actor; - this._state.documents[hash] = document; + this._state.documents[hash] = content; - this.writeFile(name, document); + // Write the file last, after state is set + this.writeFile(name, content); - await this.sync(); + // Ensure changes are persisted + await this.synchronize(); return { id: actor.id, @@ -184,8 +244,30 @@ class Filesystem extends Actor { } async start () { + if (this.settings.debug) console.debug('[FILESYSTEM]', 'Starting filesystem:', this.path); + this._state.content.status = 'STARTING'; + + // Create .fabric directory + const fabricPath = path.join(this.path, '.fabric'); + this.touchDir(fabricPath); + this.touchDir(this.path); // ensure exists - await this.sync(); + + // Load from disk + await this._loadFromDisk(); + + // Watch for changes in the filesystem + /* chokidar.watch(this.path, { + ignoreInitial: true, + persistent: false, + ignored: /(^|[/\\])\.fabric([/\\]|$)/ // ignore .fabric directory + }).on('all', (event, filePath) => { + this._handleDiskChange(event, filePath); + }); */ + + this._state.content.status = 'STARTED'; + this.commit(); + return this; } @@ -195,14 +277,78 @@ class Filesystem extends Actor { } /** - * Syncronize state from the local filesystem. + * Synchronize state from the local filesystem. * @returns {Filesystem} Instance of the Fabric filesystem. */ - async sync () { + async synchronize () { await this._loadFromDisk(); this.commit(); return this; } + + async addToChain (message) { + if (!message) throw new Error('Message is required'); + + // Convert message to buffer + const buffer = message.toBuffer(); + + // Convert buffer to hex + const hex = buffer.toString('hex'); + + // Write hex to CHAIN in .fabric directory + const chainPath = path.join(this.path, '.fabric', 'CHAIN'); + const result = await this.writeFile(chainPath, hex); + + if (!result) { + this.emit('error', 'Failed to write message to chain'); + return false; + } + + this.emit('chain:update', { + message: message, + hex: hex + }); + + return true; + } + + commit () { + const state = new Actor(this.state); + + // Write state to STATE file using absolute path + const statePath = path.resolve(this.path, '.fabric', 'STATE'); + const stateHex = Buffer.from(JSON.stringify(this.state)).toString('hex'); + this.writeFile(statePath, stateHex); + + const commit = Message.fromVector(['COMMIT', state]); + commit.signatures = commit.signatures || []; + + // Only sign if we have a key with private key component + if (this.key && this.key.xprv) { + // Sign the commit message using the configured key + const signature = this.key.sign(commit); + commit.signatures.push(signature); + } + + this.emit('commit', commit); + } + + /** + * Synchronize the filesystem with the local state. + * @returns {Promise} Resolves with Filesystem instance. + */ + sync () { + return new Promise((resolve, reject) => { + try { + this.synchronize().then(() => { + resolve(this); + }); + } catch (exception) { + this.emit('error', exception); + reject(exception); + } + }); + } } module.exports = Filesystem; diff --git a/types/hash256.js b/types/hash256.js index 1074aecee..2acd67e94 100644 --- a/types/hash256.js +++ b/types/hash256.js @@ -1,6 +1,6 @@ 'use strict'; -const crypto = require('crypto'); +const { sha256 } = require('@noble/hashes/sha256'); /** * Simple interaction with 256-bit spaces. @@ -16,11 +16,29 @@ class Hash256 { */ constructor (settings = {}) { if (typeof settings === 'string') settings = { input: settings }; - if (!settings.input) settings.input = crypto.randomBytes(32).toString('hex'); + if (!settings.input) { + if (typeof window !== 'undefined' && window.crypto && window.crypto.getRandomValues) { + settings.input = window.crypto.getRandomValues(new Uint8Array(32)).join(''); + } else { + settings.input = require('crypto').randomBytes(32).toString('hex'); + } + } + + // Ensure the input can be cast to a buffer + const buffer = Buffer.from(settings.input, 'utf8'); + // Settings this.settings = Object.assign({ - hash: Hash256.digest(settings.input) + hash: Hash256.digest(buffer) }, settings); + + return this; + } + + static compute (input) { + if (typeof input === 'string') input = Buffer.from(input, 'utf8'); + const buffer = sha256(input); + return Buffer.from(buffer).toString('hex'); } /** @@ -33,8 +51,11 @@ class Hash256 { throw new Error(`Input to process must be of type "String" or "Buffer" to digest.`); } - // consume and output as string - return crypto.createHash('sha256').update(input).digest('hex'); + return Hash256.compute(input); + } + + get hash () { + return this.value; } // TODO: document `hash256.value` @@ -49,9 +70,18 @@ class Hash256 { return Buffer.from(input, 'hex').reverse().toString('hex'); } + static async hash (input) { + const encoder = new TextEncoder(); + const dataBuffer = encoder.encode(input); + const hashBuffer = await crypto.subtle.digest('SHA-256', dataBuffer); + const hashArray = Array.from(new Uint8Array(hashBuffer)); + const hashHex = hashArray.map(b => b.toString(16).padStart(2, '0')).join(''); + return hashHex; + } + reverse (input = this.value) { return Hash256.reverse(input); } } -module.exports = Hash256; \ No newline at end of file +module.exports = Hash256; diff --git a/types/identity.js b/types/identity.js index 02f4cc271..20e65f478 100644 --- a/types/identity.js +++ b/types/identity.js @@ -4,7 +4,6 @@ const Actor = require('./actor'); const Bech32 = require('./bech32'); const Hash256 = require('./hash256'); const Key = require('./key'); -const Signer = require('./signer'); /** * Manage a network identity. @@ -18,6 +17,7 @@ class Identity extends Actor { * @param {String} [settings.xpub] Serialized BIP 32 master public key. * @param {Number} [settings.account=0] BIP 44 account index. * @param {Number} [settings.index=0] BIP 44 key index. + * @param {String} [settings.passphrase] Passphrase for the key. * @returns {Identity} Instance of the identity. */ constructor (settings = {}) { @@ -25,12 +25,27 @@ class Identity extends Actor { this.settings = Object.assign({ seed: null, - account: 0, - index: 0 - }, this.settings, settings); - - this.key = new Key(this.settings); - this.signer = new Signer(this.settings); + xprv: null, + passphrase: null + }, settings); + + // Initialize key + if (settings instanceof Key) { + this.key = settings; + } else { + this.key = new Key({ + seed: this.settings.seed, + xprv: this.settings.xprv, + passphrase: this.settings.passphrase + }); + + // Ensure we have a private key + if (!this.key.xprv) { + // Generate a new key if none provided + this.key = new Key(); + this.settings.xprv = this.key.xprv; + } + } this._state = { content: { @@ -53,7 +68,7 @@ class Identity extends Actor { // We will use Change 1 ("Internal Chain" as designated by BIP0044) // for any kind of revoke mechanic; i.e., the key derived by the change // address may be used to auto-encode a "revocation" contract. - return `m/44'/0'/${this.accountID}'/0/${this.index}`; + return `m/44'/7778'/${this.accountID}'/0/${this.index}`; } get id () { @@ -69,7 +84,7 @@ class Identity extends Actor { } get pubkey () { - return this.key.public.x.toString('hex'); + return this.key.pubkey; } get pubkeyhash () { @@ -90,14 +105,8 @@ class Identity extends Actor { return this; } - /** - * Sign a buffer of data using BIP 340: https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki - * @param {Buffer} data Buffer of data to sign. - * @returns {Signature} Resulting signature (64 bytes). - */ sign (data = Buffer.from('', 'hex')) { - this._signAsSchnorr(data.toString('hex')); - return this._signature; + return this.key.sign(data); } /** @@ -105,16 +114,11 @@ class Identity extends Actor { * @returns {String} Public identity. */ toString () { - if (this.settings.debug) console.log('master key:', this.key.master.publicKey); - if (this.settings.debug) console.log('pubkey for id:', this.pubkey); - const bech32 = new Bech32({ hrp: 'id', content: this.pubkeyhash }); - if (this.settings.debug) console.log('bech32:', bech32); - return bech32.toString(); } @@ -126,9 +130,13 @@ class Identity extends Actor { _signAsSchnorr (input) { if (!input) input = this.pubkeyhash; - this._signature = this.signer.sign(input) + this._signature = this.key.sign(input) return this; } + + _verifyKeyIsChild (key, parent) { + + } } module.exports = Identity; diff --git a/types/key.js b/types/key.js index ec9601efb..64c56beda 100644 --- a/types/key.js +++ b/types/key.js @@ -1,12 +1,23 @@ +/** + * @fabric/core/types/key + * Cryptographic key generation, derivation, signing, and encryption. + * + * @signers + * - Eric Martindale + */ 'use strict'; // Constants const { - FABRIC_KEY_DERIVATION_PATH + BITCOIN_KEY_DERIVATION_PATH, + FABRIC_KEY_DERIVATION_PATH, + LIGHTNING_KEY_DERIVATION_PATH, + BECH32M_CHARSET } = require('../constants'); // Node Modules const crypto = require('crypto'); +const EventEmitter = require('events').EventEmitter; // Deterministic Random // TODO: remove @@ -18,14 +29,15 @@ const BN = require('bn.js'); const EC = require('elliptic').ec; const ec = new EC('secp256k1'); const ecc = require('tiny-secp256k1'); +const base58 = require('bs58check'); const payments = require('bitcoinjs-lib/src/payments'); // Fabric Dependencies +const Actor = require('./actor'); const Hash256 = require('./hash256'); // Simple Key Management const BIP32 = require('bip32').default; -const bip32 = new BIP32(ecc); const bip39 = require('bip39'); // NOTE: see also @fabric/passport @@ -34,7 +46,7 @@ const bip39 = require('bip39'); /** * Represents a cryptographic key. */ -class Key { +class Key extends EventEmitter { /** * Create an instance of a Fabric Key, either restoring from some known * values or from prior knowledge. For instance, you can call `new Key()` @@ -45,9 +57,13 @@ class Key { * @param {String} [settings.seed] Mnemonic seed for initializing the key. * @param {String} [settings.public] Public key in hex. * @param {String} [settings.private] Private key in hex. + * @param {String} [settings.wif] WIF-encoded private key. * @param {String} [settings.purpose=44] Constrains derivations to this space. */ constructor (input = {}) { + super(input); + + // Settings this.settings = Object.assign({ debug: false, network: 'main', @@ -57,6 +73,7 @@ class Key { prefix: '00', public: null, private: null, + wif: null, purpose: 44, account: 0, bits: 256, @@ -65,22 +82,68 @@ class Key { passphrase: '', password: null, index: 0, + path: null, cipher: { iv: { size: 16 } }, - witness: true + state: { + status: 'sensitive' + }, + witness: true, + networks: { + mainnet: { + messagePrefix: '\x18Bitcoin Signed Message:\n', + bech32: 'bc', + bip32: { + public: 0x0488b21e, + private: 0x0488ade4 + }, + pubKeyHash: 0x00, + scriptHash: 0x05, + wif: 0x80 + }, + testnet: { + messagePrefix: '\x18Bitcoin Signed Message:\n', + bech32: 'tb', + bip32: { + public: 0x043587cf, + private: 0x04358394 + }, + pubKeyHash: 0x6f, + scriptHash: 0xc4, + wif: 0xef + }, + regtest: { + messagePrefix: '\x18Bitcoin Signed Message:\n', + bech32: 'bcrt', + bip32: { + public: 0x043587cf, + private: 0x04358394 + }, + pubKeyHash: 0x6f, + scriptHash: 0xc4, + wif: 0xef + } + } }, input); + this.bip32 = new BIP32(ecc); + this._bech32mCharset = BECH32M_CHARSET; + this.clock = 0; this.master = null; this.private = null; this.public = null; + this._state = null; // Initialize as null to defer state updates - // TODO: design state machine for input (configuration) - if (this.settings.seed) { + if (this.settings.mnemonic) { + this._mode = 'FROM_MNEMONIC'; + } else if (this.settings.seed) { this._mode = 'FROM_SEED'; + } else if (this.settings.wif) { + this._mode = 'FROM_WIF'; } else if (this.settings.private) { this._mode = 'FROM_PRIVATE_KEY'; } else if (this.settings.xprv) { @@ -93,29 +156,55 @@ class Key { this._mode = 'FROM_RANDOM'; } - switch (this._mode) { - case 'FROM_SEED': - const seed = bip39.mnemonicToSeedSync(this.settings.seed, this.settings.passphrase); - const root = bip32.fromSeed(seed); + let seed = null; + let root = null; + switch (this._mode) { + case 'FROM_MNEMONIC': + seed = bip39.mnemonicToSeedSync(this.settings.mnemonic, this.settings.passphrase); + root = this.bip32.fromSeed(seed); this.seed = this.settings.seed; - this.xprv = root.toBase58(); this.xpub = root.neutered().toBase58(); this.master = root; this.keypair = ec.keyFromPrivate(root.privateKey); - // this.address = this.keyring.getAddress().toString(); this.status = 'seeded'; break; + case 'FROM_SEED': + // TODO: allow setting of raw seed (deprecates passing a mnemonic in the `seed` property) + seed = bip39.mnemonicToSeedSync(this.settings.seed, this.settings.passphrase); + root = this.bip32.fromSeed(seed); + this.seed = this.settings.seed; + this.xprv = root.toBase58(); + this.xpub = root.neutered().toBase58(); + this.master = root; + this.keypair = ec.keyFromPrivate(root.privateKey); + break; + case 'FROM_WIF': + const decoded = base58.decode(this.settings.wif); + const version = decoded[0]; + const privateKey = decoded.slice(1, 33); + const isCompressed = decoded.length === 34 && decoded[33] === 0x01; + this.keypair = ec.keyFromPrivate(privateKey); + if (!isCompressed) { + const pub = this.keypair.getPublic(); + pub.compressed = false; + // Force the public key to be uncompressed + this.public = pub; + } else { + this.public = this.keypair.getPublic(true); + } + break; case 'FROM_XPRV': - this.master = bip32.fromBase58(this.settings.xprv); + this.master = this.bip32.fromBase58(this.settings.xprv); this.xprv = this.master.toBase58(); this.xpub = this.master.neutered().toBase58(); this.keypair = ec.keyFromPrivate(this.master.privateKey); break; case 'FROM_XPUB': - const xpub = bip32.fromBase58(this.settings.xpub); - this.keypair = ec.keyFromPublic(xpub.publicKey); + this.master = this.bip32.fromBase58(this.settings.xpub); + this.xpub = this.master.neutered().toBase58(); + this.keypair = ec.keyFromPublic(this.master.publicKey); break; case 'FROM_PRIVATE_KEY': // Key is private @@ -128,44 +217,28 @@ class Key { this.keypair = ec.keyFromPublic((pubkey instanceof Buffer) ? pubkey : Buffer.from(pubkey, 'hex')); break; case 'FROM_RANDOM': - const mnemonic = bip39.generateMnemonic(); - const interim = bip39.mnemonicToSeedSync(mnemonic); - this.master = bip32.fromSeed(interim); + this.mnemonic = bip39.generateMnemonic(); + // TODO: set property `seed` as the actual derived seed, not the seed phrase + const interim = bip39.mnemonicToSeedSync(this.mnemonic); + this.master = this.bip32.fromSeed(interim); + this.xprv = this.master.toBase58(); + this.xpub = this.master.neutered().toBase58(); this.keypair = ec.keyFromPrivate(this.master.privateKey); break; } // Read the pair - this.private = ( - !this.settings.seed && - !this.settings.private && - !this.settings.xprv - ) ? false : this.keypair.getPrivate(); - + this.private = (this.keypair.priv) ? this.keypair.getPrivate() : null; this.public = this.keypair.getPublic(true); // TODO: determine if this makes sense / needs to be private this.privkey = (this.private) ? this.private.toString() : null; - // STANDARD BEGINS HERE - this.pubkey = this.public.encodeCompressed('hex'); - - // BELOW THIS NON-STANDARD - // DO NOT USE IN PRODUCTION - // this.pubkeyhash = this.keyring.getKeyHash('hex'); - this.pubkeyhash = ''; - // Configure Deterministic Random // WARNING: this will currently loop after 2^32 bits // TODO: evaluate compression when treating seed phrase as ascii // TODO: consider using sha256(masterprivkey) or sha256(sha256(...))? - - this._starseed = Hash256.digest(( - this.settings.seed || - this.settings.xprv || - this.settings.private - ) + ''); - + this._starseed = Hash256.digest(this.pubkeyhash).toString('hex'); this.q = parseInt(this._starseed.substring(0, 4), 16); this.generator = new Generator(this.q); @@ -176,7 +249,8 @@ class Key { }; this._state = { - pubkey: this.pubkey + pubkey: this.pubkey, + content: this.settings.state }; // Object.defineProperty(this, 'keyring', { enumerable: false }); @@ -186,8 +260,33 @@ class Key { return this; } + /** + * Create a Key instance from a WIF-encoded private key. + * @param {String} wif - The WIF-encoded private key + * @param {Object} [options] - Additional options for key creation + * @returns {Key} A new Key instance + */ + static fromWIF (wif, options = {}) { + return new Key({ ...options, wif }); + } + static Mnemonic (seed) { - return new Key({ seed }); + if (!seed) seed = crypto.randomBytes(32); + const mnemonic = bip39.entropyToMnemonic(seed); + const seedBuffer = bip39.mnemonicToSeedSync(mnemonic); + const bip32 = new BIP32(ecc); + const master = bip32.fromSeed(seedBuffer); + const key = new Key(); + key.seed = mnemonic; + key.private = master.privateKey.toString('hex'); + key.public = master.publicKey.toString('hex'); + key.chainCode = master.chainCode.toString('hex'); + key.depth = master.depth; + key.index = master.index; + key.parentFingerprint = master.parentFingerprint; + key.fingerprint = master.fingerprint; + key.keypair = master; + return key; } get account () { @@ -199,11 +298,11 @@ class Key { } get iv () { - const self = this; - const bits = new BN([...Array(128)].map(() => { - return self.bit().toString(); - }).join(''), 2).toString(16); - return Buffer.from(bits.toString(16), 'hex'); + return crypto.randomBytes(16); + } + + get path () { + return this.settings.path; } get purpose () { @@ -229,79 +328,401 @@ class Key { return this.deriveAddress(index); } - deriveAddress (index = 0, change = 0) { - const pair = this.deriveKeyPair(this.account, index, change); - return payments.p2pkh({ - pubkey: Buffer.from(pair.public, 'hex') - }); + deriveAddress (index = 0, change = 0, type = 'p2pkh') { + const key = this.deriveKeyPair(index, change); + const network = this.settings.network === 'regtest' ? this.settings.networks.testnet : this.settings.networks[this.settings.network]; + + switch (type) { + case 'p2pkh': + return { + address: payments.p2pkh({ + pubkey: Buffer.from(key.publicKey, 'hex'), + network: network + }).address, + publicKey: key.publicKey, + privateKey: key.privateKey + }; + case 'p2wpkh': + return { + address: payments.p2wpkh({ + pubkey: Buffer.from(key.publicKey, 'hex'), + network: network + }).address, + publicKey: key.publicKey, + privateKey: key.privateKey + }; + case 'p2tr': + // For p2tr, we need to use the x-only pubkey (first 32 bytes after the prefix) + const pubkeyBuffer = Buffer.from(key.publicKey, 'hex'); + const xOnlyPubkey = pubkeyBuffer.slice(1, 33); // Remove prefix byte and take next 32 bytes + + // Generate taproot address using bech32m encoding + const commitHash = crypto.createHash('sha256') + .update(Buffer.concat([xOnlyPubkey, Buffer.alloc(32)])) + .digest(); + const tweakResult = ecc.xOnlyPointAddTweak(xOnlyPubkey, commitHash); + if (!tweakResult) throw new Error('Invalid tweak'); + + // Use the correct network prefix for bech32m + let hrp; + switch (this.settings.network) { + case 'main': + hrp = 'bc'; + break; + case 'testnet': + hrp = 'tb'; + break; + case 'regtest': + hrp = 'bcrt'; + break; + default: + throw new Error(`Unsupported network: ${this.settings.network}`); + } + + const address = this._encodeBech32m(tweakResult.xOnlyPubkey, hrp); + + return { + address: address, + publicKey: key.publicKey, + privateKey: key.privateKey + }; + default: + throw new Error(`Unsupported address type: ${type}`); + } + } + + _encodeBech32m (data, hrp) { + // Witness version 1 for P2TR + const version = [1]; + // Convert witness program to 5-bit words + const program = this._convertBits(Array.from(data), 8, 5, true); + if (!program) throw new Error('Invalid program'); + + // Combine version and program + const words = version.concat(program); + + // Generate checksum + const chk = this._bech32mCreateChecksum(hrp, words); + + // Return final address + return hrp + '1' + words.map(x => this._bech32mCharset[x]).join('') + chk; + } + + _convertBits (data, fromBits, toBits, pad) { + let acc = 0; + let bits = 0; + const maxv = (1 << toBits) - 1; + const result = []; + + for (let i = 0; i < data.length; i++) { + const value = data[i]; + if (value < 0 || value >> fromBits !== 0) { + return null; + } + acc = (acc << fromBits) | value; + bits += fromBits; + while (bits >= toBits) { + bits -= toBits; + result.push((acc >> bits) & maxv); + } + } + + if (pad) { + if (bits > 0) { + result.push((acc << (toBits - bits)) & maxv); + } + } else if (bits >= fromBits || ((acc << (toBits - bits)) & maxv)) { + return null; + } + + return result; + } + + _bech32mCreateChecksum (hrp, data) { + const values = this._bech32mExpandHrp(hrp).concat(data).concat([0, 0, 0, 0, 0, 0]); + const polymod = this._bech32mPolymod(values) ^ 0x2bc830a3; + const ret = []; + for (let i = 0; i < 6; i++) { + ret.push((polymod >> 5 * (5 - i)) & 31); + } + return ret.map(x => this._bech32mCharset[x]).join(''); + } + + _bech32mExpandHrp (hrp) { + const ret = []; + for (let i = 0; i < hrp.length; i++) { + ret.push(hrp.charCodeAt(i) >> 5); + } + ret.push(0); + for (let i = 0; i < hrp.length; i++) { + ret.push(hrp.charCodeAt(i) & 31); + } + return ret; + } + + _bech32mPolymod (values) { + const GEN = [0x3b6a57b2, 0x26508e6d, 0x1ea119fa, 0x3d4233dd, 0x2a1462b3]; + let chk = 1; + for (let i = 0; i < values.length; i++) { + const top = chk >> 25; + chk = ((chk & 0x1ffffff) << 5) ^ values[i]; + for (let j = 0; j < 5; j++) { + if ((top >> j) & 1) { + chk ^= GEN[j]; + } + } + } + return chk; } deriveKeyPair (addressID = 0, change = 0) { const path = `m/${this.purpose}'/0'/${this.account}'/${change}/${addressID}`; const derived = this.master.derivePath(path); const pair = ec.keyFromPrivate(derived.privateKey); + return { - private: pair.getPrivate('hex'), - public: pair.getPublic(true, 'hex') + privateKey: pair.getPrivate('hex'), + publicKey: pair.getPublic(true, 'hex') }; } encrypt (value) { try { const ivbuff = Buffer.from(this.iv, 'hex'); - const cipher = crypto.createCipheriv(this.settings.mode, this.private.toBuffer(), ivbuff); - let encrypted = cipher.update(value); - encrypted = Buffer.concat([ - encrypted, - cipher.final() - ]); - return ivbuff.toString('hex') + ':' + encrypted.toString('hex'); + // Derive a 32-byte key from the private key using SHA-256 + const key = crypto.createHash('sha256') + .update(this.private.toString('hex')) + .digest(); + const cipher = crypto.createCipheriv(this.settings.mode, key, ivbuff); + let encrypted = cipher.update(value, 'utf8', 'hex'); + encrypted += cipher.final('hex'); + return ivbuff.toString('hex') + ':' + encrypted; } catch (exception) { console.error('err:', exception); + return null; } } decrypt (text) { + if (!text) return null; if (text instanceof Buffer) text = text.toString('utf8'); try { const parts = text.split(':'); const iv = Buffer.from(parts.shift(), 'hex'); const blob = Buffer.from(parts.join(':'), 'hex'); - const decipher = crypto.createDecipheriv(this.settings.mode, this.private.toBuffer(), iv); - let decrypted = decipher.update(blob); - decrypted = Buffer.concat([ - decrypted, - decipher.final() - ]); - return decrypted.toString(); + // Use the same key derivation as encrypt + const key = crypto.createHash('sha256') + .update(this.private.toString('hex')) + .digest(); + const decipher = crypto.createDecipheriv(this.settings.mode, key, iv); + let decrypted = decipher.update(blob, 'hex', 'utf8'); + decrypted += decipher.final('utf8'); + return decrypted; } catch (exception) { console.error('err:', exception); + return null; } } _sign (msg) { if (typeof msg !== 'string') msg = JSON.stringify(msg); - const hmac = crypto.createHash('sha256').update(msg).digest('hex'); - return this.keypair.sign(hmac).toDER(); + return this.signSchnorr(msg); } _verify (msg, sig) { - const hmac = crypto.createHash('sha256').update(msg).digest('hex'); - const valid = this.keypair.verify(hmac, sig); - return valid; + return this.verifySchnorr(msg, sig); + } + + /** + * Verify a message's signature. + * @param {Buffer|String} msg - The message that was signed + * @param {Buffer|String} sig - The signature to verify + * @returns {Boolean} Whether the signature is valid + */ + verify (msg, sig) { + return this._verify(msg, sig); + } + + /** + * Signs a message using Schnorr signatures (BIP340). + * @param {Buffer|String} msg - The message to sign + * @returns {Buffer} The signature + */ + signSchnorr (msg) { + if (!this.private) throw new Error('Cannot sign without private key'); + + // Convert message to Buffer if it's a string + const messageBuffer = Buffer.isBuffer(msg) ? msg : Buffer.from(msg); + + // Create message hash + const messageHash = crypto.createHash('sha256').update(messageBuffer).digest(); + + // Get private key as 32-byte buffer + let privateKeyBuffer; + if (Buffer.isBuffer(this.private)) { + privateKeyBuffer = this.private; + } else if (BN.isBN(this.private)) { + privateKeyBuffer = Buffer.from(this.private.toString(16).padStart(64, '0'), 'hex'); + } else if (typeof this.private === 'string') { + privateKeyBuffer = Buffer.from(this.private.padStart(64, '0'), 'hex'); + } else { + throw new Error('Invalid private key format'); + } + + // Sign using tiny-secp256k1's Schnorr implementation + const signature = ecc.signSchnorr(messageHash, privateKeyBuffer); + + // Ensure we return a Buffer + return Buffer.isBuffer(signature) ? signature : Buffer.from(signature); + } + + /** + * Verifies a Schnorr signature (BIP340). + * @param {Buffer|String} msg - The message that was signed + * @param {Buffer} sig - The signature to verify + * @returns {Boolean} Whether the signature is valid + */ + verifySchnorr (msg, sig) { + // Convert message to Buffer if it's a string + const messageBuffer = Buffer.isBuffer(msg) ? msg : Buffer.from(msg); + + // Create message hash + const messageHash = crypto.createHash('sha256').update(messageBuffer).digest(); + + // Get x-only public key (32 bytes) from compressed public key (33 bytes) + // For Schnorr, we only need the x coordinate (first 32 bytes after the prefix) + const compressedPubkey = Buffer.from(this.public.encodeCompressed('hex'), 'hex'); + const xOnlyPubkey = compressedPubkey.slice(1); // Remove the prefix byte + + // Ensure signature is a Buffer + const sigBuffer = Buffer.isBuffer(sig) ? sig : Buffer.from(sig); + + // Verify using tiny-secp256k1's Schnorr implementation + return ecc.verifySchnorr(messageHash, xOnlyPubkey, sigBuffer); + } + + commit () { + const reference = { ...this.state }; + const state = new Actor(reference); + + // Store current state's hash + this._state.hash = state.id; + + // Sign the commit message using the configured key + const signature = this.sign(commit); + commit.signatures.push(signature); + + this.emit('commit', commit); + } + + /** + * Sign a buffer of data using BIP 340: https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki + * @param {Buffer} data Buffer of data to sign. + * @returns {Buffer} Resulting signature (64 bytes). + */ + sign (msg) { + return this._sign(msg); } derive (path = this.settings.derivation) { if (!this.master) throw new Error('You cannot derive without a master key. Provide a seed phrase or an xprv.'); + const derived = this.master.derivePath(path); const options = { - private: derived.privateKey.encodeCompressed('hex'), - public: derived.publicKey.encodeCompressed('hex') + private: derived.privateKey.toString('hex'), + public: derived.publicKey.toString('hex') }; return new Key(options); } + + /** + * Secures the key by clearing sensitive information from memory. + * This method should be called when the key is no longer needed + * to prevent sensitive data from remaining in memory. + */ + secure () { + // Clear sensitive key material + Buffer.write(this.private, 0, this.private.length); + + // Null out sensitive properties + this.private = null; + this.privkey = null; + this.seed = null; + this.master = null; + + // Clear any derived keys + this.xprv = null; + + // Update state + this._state.status = 'secured'; + + this.commit(); + + return this; + } + + get pubkeyhash () { + const input = Buffer.from(this.pubkey, 'hex'); + return Hash256.digest(input); + } + + get pubkey () { + return this.public.encodeCompressed('hex'); + } + + /** + * Exports the private key in Wallet Import Format (WIF) + * @returns {String} The private key encoded in WIF format + * @throws {Error} If the key doesn't have a private component + */ + toWIF () { + if (!this.private) throw new Error('Cannot export WIF without private key'); + let privateKeyBuffer; + + if (Buffer.isBuffer(this.private)) { + privateKeyBuffer = this.private; + } else if (BN.isBN(this.private)) { + privateKeyBuffer = Buffer.from(this.private.toString(16).padStart(64, '0'), 'hex'); + } else if (typeof this.private === 'string') { + privateKeyBuffer = Buffer.from(this.private.padStart(64, '0'), 'hex'); + } else { + throw new Error('Invalid private key format'); + } + + const network = this.settings.network === 'regtest' + ? this.settings.networks.testnet + : this.settings.networks[this.settings.network] || this.settings.networks.mainnet; + + const prefix = Buffer.from([network.wif]); + const payload = Buffer.concat([ + prefix, + privateKeyBuffer, + Buffer.from([0x01]) + ]); + + const firstHash = crypto.createHash('sha256').update(payload).digest(); + const secondHash = crypto.createHash('sha256').update(firstHash).digest(); + const checksum = secondHash.slice(0, 4); + const combined = Buffer.concat([payload, checksum]); + + return base58.encode(combined); + } + + toBitcoinAddress () { + if (!this.public) throw new Error('Cannot derive Bitcoin address without public key'); + const network = this.settings.network === 'regtest' + ? this.settings.networks.testnet + : this.settings.networks[this.settings.network] || this.settings.networks.mainnet; + + const p2pkh = payments.p2pkh({ + pubkey: Buffer.from(this.public.encode('hex'), 'hex'), + network: network + }); + + return p2pkh.address; + } } module.exports = Key; diff --git a/types/keystore.js b/types/keystore.js index 9c387a47a..5dacf42cc 100644 --- a/types/keystore.js +++ b/types/keystore.js @@ -1,7 +1,7 @@ 'use strict'; // Dependencies -const level = require('level'); +const { Level } = require('level'); const merge = require('lodash.merge'); const monitor = require('fast-json-patch'); const pointer = require('json-pointer'); @@ -13,16 +13,7 @@ const Message = require('./message'); const Tree = require('./tree'); const Key = require('./key'); -/** - * Provides an encrypted datastore for generic object storage. - */ class Keystore extends Actor { - /** - * Create an instance of the Store. - * @param {FabricStoreConfiguration} [configuration] Settings to use. - * @param {String} [configuration.name="DefaultStore"] Name of the Store. - * @returns {Keystore} Instance of the store. - */ constructor (settings = {}) { super(settings); if (!settings.seed) settings.seed = (process) ? process.env.FABRIC_SEED || null : null; @@ -131,9 +122,9 @@ class Keystore extends Actor { } try { - keystore.db = level(keystore.settings.path, { - keyEncoding: keystore.codec, - valueEncoding: keystore.codec + keystore.db = new Level(keystore.settings.path, { + encode: keystore.codec, + decode: keystore.codec }, _handleDiskOpen.bind(keystore)); keystore.status = 'open'; diff --git a/types/layer.js b/types/layer.js deleted file mode 100644 index 5f4effa3c..000000000 --- a/types/layer.js +++ /dev/null @@ -1,45 +0,0 @@ -'use strict'; - -const Key = require('./key'); -const Entity = require('./entity'); - -class Layer extends Entity { - constructor (state = {}) { - super(state); - - // Assign Appropriate Settings - this.settings = Object.assign({ - parents: [], - children: [], - session: { - key: null - }, - size: 256 - }, state); - - // TODO: describe state-passing for key - this.key = new Key(this.settings); - this._state = Object.assign({}, this.settings); - - return this; - } - - get size () { - return this._state.size; - } - - get parents () { - return this._state.parents; - } - - get children () { - return this._state.children; - } - - async addInput (input) { - this._state.parents.push(input); - return this; - } -} - -module.exports = Layer; diff --git a/types/lightning/message.js b/types/lightning/message.js index 166fc9378..c6e3b124a 100644 --- a/types/lightning/message.js +++ b/types/lightning/message.js @@ -8,4 +8,4 @@ class LightningMessage extends FabricMessage { } } -module.exports = LightningMessage; \ No newline at end of file +module.exports = LightningMessage; diff --git a/types/logger.js b/types/logger.js index d69f907ad..4be3b5447 100644 --- a/types/logger.js +++ b/types/logger.js @@ -2,7 +2,7 @@ // Dependencies const fs = require('fs'); -const mkdirp = require('mkdirp'); +const { mkdirp } = require('mkdirp'); // Fabric Types const Actor = require('./actor'); @@ -18,7 +18,8 @@ class Logger extends Actor { this.settings = Object.assign({ name: this.id, - path: './logs' + path: './logs', + silent: true }, settings); this._state = { @@ -54,6 +55,7 @@ class Logger extends Actor { } this.stream.write(msg + '\n'); + return true; } @@ -66,11 +68,19 @@ class Logger extends Actor { */ async start () { this._state.status = 'STARTING'; + await mkdirp(this.settings.path); - this.stream = fs.createWriteStream(this.path, { flags: 'a+' }) - .on('error', err => console.warn(err.message, err.stack)) - .once('close', () => { this._state.status = 'STOPPED'; }); + + this.stream = fs.createWriteStream(this.path, { + flags: 'a+' + }).on('error', (err) => { + console.warn(err.message, err.stack); + }).once('close', () => { + this._state.status = 'STOPPED'; + }); + this._state.status = 'STARTED'; + return this; } diff --git a/types/machine.js b/types/machine.js index e59a16fe0..dd04d87a8 100644 --- a/types/machine.js +++ b/types/machine.js @@ -32,18 +32,14 @@ class Machine extends Actor { debug: false, deterministic: true, interval: 60, // seconds + key: null, precision: 8, script: [], - seed: 1, // TODO: select seed for production type: 'fabric' }, settings); // machine key - this.key = new Key({ - seed: this.settings.seed + '', // casts to string - xprv: this.settings.xprv, - private: this.settings.private, - }); + this.key = new Key(this.settings.key); // internal clock this.clock = this.settings.clock; diff --git a/types/mempool.js b/types/mempool.js index 7d592e2c5..60a6d57b4 100644 --- a/types/mempool.js +++ b/types/mempool.js @@ -5,15 +5,7 @@ const Service = require('./service'); const Collection = require('./collection'); const Transaction = require('./transaction'); -/** - * Stores a list of {@link Transaction} elements. - * @emits {Message} confirmed Emitted when the Mempool has dropped a transaction. - */ class Mempool extends Service { - /** - * Creates an instance of a {@link Mempool} {@link Service}. - * @param {Object} settings Map of settings to utilize. - */ constructor (settings = {}) { super(settings); diff --git a/types/message.js b/types/message.js index 1432d19e3..9fbd0f5d9 100644 --- a/types/message.js +++ b/types/message.js @@ -9,6 +9,10 @@ const { GENERIC_MESSAGE_TYPE, LOG_MESSAGE_TYPE, GENERIC_LIST_TYPE, + BITCOIN_BLOCK_TYPE, + BITCOIN_BLOCK_HASH_TYPE, + BITCOIN_TRANSACTION_TYPE, + BITCOIN_TRANSACTION_HASH_TYPE, P2P_GENERIC, P2P_IDENT_REQUEST, P2P_IDENT_RESPONSE, @@ -28,26 +32,25 @@ const { CHAT_MESSAGE, DOCUMENT_PUBLISH_TYPE, DOCUMENT_REQUEST_TYPE, + JSON_CALL_TYPE, BLOCK_CANDIDATE, PEER_CANDIDATE, SESSION_START } = require('../constants'); +const HEADER_SIG_SIZE = 64; + // Dependencies -const crypto = require('crypto'); +// const crypto = require('crypto'); const struct = require('struct'); // Fabric Types const Actor = require('./actor'); -const Label = require('./label'); +const Hash256 = require('./hash256'); // Function Definitions const padDigits = require('../functions/padDigits'); -// Type Labels -const TYPE_ETHEREUM_BLOCK = parseInt((new Label('types/EthereumBlock'))._id, 16); -const TYPE_ETHEREUM_BLOCK_NUMBER = parseInt((new Label('types/EthereumBlockNumber'))._id, 16); - /** * The {@link Message} type defines the Application Messaging Protocol, or AMP. * Each {@link Actor} in the network receives and broadcasts messages, @@ -67,6 +70,7 @@ class Message extends Actor { magic: Buffer.alloc(4), version: Buffer.alloc(4), parent: Buffer.alloc(32), + author: Buffer.alloc(32), type: Buffer.alloc(4), // TODO: 8, 32 size: Buffer.alloc(4), // TODO: 8, 32 hash: Buffer.alloc(32), @@ -77,8 +81,18 @@ class Message extends Actor { this.raw.magic.write(MAGIC_BYTES.toString(16), 'hex'); this.raw.version.write(padDigits(VERSION_NUMBER.toString(16), 8), 'hex'); + // Use provided signer + if (input.signer) { + this.signer = input.signer; + } else { + this.signer = null; + } + if (input.data && input.type) { this.type = input.type; + // Set the type field to the numeric constant + const typeCode = this.types[input.type] || GENERIC_MESSAGE_TYPE; + this.raw.type.writeUInt32BE(typeCode, 0); if (typeof input.data !== 'string') { this.data = JSON.stringify(input.data); @@ -94,6 +108,7 @@ class Message extends Actor { '_state', 'config', 'settings', + 'signer', 'stack', 'observer' ]) Object.defineProperty(this, name, { enumerable: false }); @@ -101,6 +116,10 @@ class Message extends Actor { return this; } + get author () { + return this.raw.author.toString('hex'); + } + get body () { return this.raw.data.toString('utf8'); } @@ -125,7 +144,7 @@ class Message extends Actor { get Uint256 () { // 256 bits - return Buffer.from((this.raw && this.raw.hash) ? `0x${padDigits(this.raw.hash, 8)}` : crypto.randomBytes(32)); + return Buffer.from((this.raw && this.raw.hash) ? `0x${padDigits(this.raw.hash, 8)}` : Actor.randomBytes(32)); } set signature (value) { @@ -165,10 +184,11 @@ class Message extends Actor { magic: parseInt(`${this.raw.magic.toString('hex')}`, 16), version: parseInt(`${this.raw.version.toString('hex')}`, 16), parent: this.raw.parent.toString('hex'), + author: this.raw.author.toString('hex'), type: parseInt(`${this.raw.type.toString('hex')}`, 16), size: parseInt(`${this.raw.size.toString('hex')}`, 16), + hash: this.raw.hash.toString('hex'), signature: this.raw.signature.toString('hex'), - hash: this.raw.hash.toString('hex') }, type: this.type, data: this.data @@ -179,6 +199,90 @@ class Message extends Actor { return new Message(input); } + /** + * Signs the message using a specific key. + * @param {Object} key Key object with private key and sign method. + * @param {String|Buffer} key.private Private key + * @param {String|Buffer} key.pubkey Public key + * @param {Function} key.sign Signing function + * @returns {Message} Signed message. + * @throws {Error} If attempting to sign without a private key + */ + signWithKey (key) { + if (!key) throw new Error('No key provided.'); + if (!key.private) throw new Error('Cannot sign message with public key only.'); + if (!key.sign) throw new Error('Key object must implement sign method'); + + // Hash the message data according to BIP 340 + const message = this.raw.data.toString('utf8'); + const messageHash = Hash256.digest(message); + const signature = key.sign(messageHash); + + this.raw.author.write(key.pubkey.toString('hex'), 'hex'); + this.raw.signature.write(signature.toString('hex'), 'hex'); + + return this; + } + + sign () { + if (!this.signer) throw new Error('No signer available.'); + if (!this.signer.private) throw new Error('Cannot sign message with public key only.'); + if (!this.signer.sign) throw new Error('Signer must implement sign method'); + + return this.signWithKey(this.signer); + } + + /** + * Verify a message's signature. + * @returns {Boolean} `true` if the signature is valid, `false` if not. + */ + verify () { + if (!this.header) throw new Error('No header property.'); + if (!this.raw) throw new Error('No raw property.'); + if (!this.signer) throw new Error('No signer available.'); + if (!this.signer.verify) throw new Error('Signer must implement verify method'); + + const hash = Hash256.digest(this.raw.data); + const signature = this.raw.signature; + + return this.verifyWithKey(this.signer); + } + + /** + * Verify a message's signature with a specific key. + * @param {Object} key Key object with verify method. + * @param {Function} key.verify Verification function + * @returns {Boolean} `true` if the signature is valid, `false` if not. + */ + verifyWithKey (key) { + if (!this.header) throw new Error('No header property.'); + if (!this.raw) throw new Error('No raw property.'); + if (!key) throw new Error('No key provided.'); + if (!key.verify) throw new Error('Key object must implement verify method'); + + // Get the raw message data as a string + const message = this.raw.data.toString('utf8'); + const messageHash = Hash256.digest(message); + const signature = this.raw.signature; + + return key.verify(messageHash, signature); + } + + /** + * Sets the signer for the message. + * @param {Object} key Key object with pubkey property. + * @param {String|Buffer} key.pubkey Public key + * @returns {Message} Instance of the Message with associated signer. + */ + _setSigner (key) { + if (!key || !key.pubkey) { + throw new Error('Key object with pubkey is required'); + } + + this.signer = key; + return this; + } + static parseBuffer (buffer) { const message = struct() .charsnt('magic', 4, 'hex') @@ -201,14 +305,15 @@ class Message extends Actor { magic: buffer.slice(0, 4), version: buffer.slice(4, 8), parent: buffer.slice(8, 40), - type: buffer.slice(40, 44), - size: buffer.slice(44, 48), - hash: buffer.slice(48, 80), - signature: buffer.slice(80, 144) + author: buffer.slice(40, 72), + type: buffer.slice(72, 76), + size: buffer.slice(76, 80), + hash: buffer.slice(80, 112), + signature: buffer.slice(112, HEADER_SIZE) }; - if (buffer.length >= 144) { - message.data = buffer.slice(144, buffer.length); + if (buffer.length >= HEADER_SIZE) { + message.data = buffer.slice(HEADER_SIZE, buffer.length); } return message; @@ -220,23 +325,34 @@ class Message extends Actor { static fromRaw (input) { if (!input) return null; - if (!(input instanceof Buffer)) throw new Error('Input must be a buffer.'); - // if (input.length < HEADER_SIZE) return null; - // if (input.length > MAX_MESSAGE_SIZE) return new Error('Input too large.'); + // Convert various buffer-like inputs to Buffer + let buffer; + if (input instanceof Buffer) { + buffer = input; + } else if (input instanceof Uint8Array) { + buffer = Buffer.from(input.buffer); + } else if (input instanceof ArrayBuffer) { + buffer = Buffer.from(input); + } else if (input.buffer instanceof ArrayBuffer) { + buffer = Buffer.from(input.buffer); + } else { + throw new Error('Input must be a buffer or buffer-like object.'); + } const message = new Message(); message.raw = { - magic: input.slice(0, 4), - version: input.slice(4, 8), - parent: input.slice(8, 40), - type: input.slice(40, 44), - size: input.slice(40, 48), - hash: input.slice(40, 80), - signature: input.slice(0, 144) + magic: buffer.subarray(0, 4), + version: buffer.subarray(4, 8), + parent: buffer.subarray(8, 40), + author: buffer.subarray(40, 72), + type: buffer.subarray(72, 76), + size: buffer.subarray(76, 80), + hash: buffer.subarray(80, 112), + signature: buffer.subarray(112, HEADER_SIZE) }; - message.data = input.slice(HEADER_SIZE); + message.data = buffer.subarray(HEADER_SIZE); return message; } @@ -261,12 +377,16 @@ class Message extends Actor { } */ get id () { - return crypto.createHash('sha256').update(this.asRaw()).digest('hex'); + return Hash256.digest(this.asRaw()); } get types () { // Message Types return { + 'BitcoinBlock': BITCOIN_BLOCK_TYPE, + 'BitcoinBlockHash': BITCOIN_BLOCK_HASH_TYPE, + 'BitcoinTransaction': BITCOIN_TRANSACTION_TYPE, + 'BitcoinTransactionHash': BITCOIN_TRANSACTION_HASH_TYPE, 'GenericMessage': GENERIC_MESSAGE_TYPE, 'GenericLogMessage': LOG_MESSAGE_TYPE, 'GenericList': GENERIC_LIST_TYPE, @@ -274,6 +394,8 @@ class Message extends Actor { 'FabricLogMessage': LOG_MESSAGE_TYPE, 'FabricServiceLogMessage': LOG_MESSAGE_TYPE, 'GenericTransferQueue': GENERIC_LIST_TYPE, + 'JSONBlob': GENERIC_MESSAGE_TYPE + 1, + 'JSONCall': JSON_CALL_TYPE, // TODO: document Generic type // P2P Commands 'Generic': P2P_GENERIC, @@ -301,9 +423,7 @@ class Message extends Actor { 'StateRequest': P2P_STATE_REQUEST, 'Transaction': P2P_TRANSACTION, 'Call': P2P_CALL, - 'LogMessage': LOG_MESSAGE_TYPE, - 'EthereumBlock': TYPE_ETHEREUM_BLOCK, - 'EthereumBlockNumber': TYPE_ETHEREUM_BLOCK_NUMBER + 'LogMessage': LOG_MESSAGE_TYPE }; } @@ -336,10 +456,11 @@ class Message extends Actor { Buffer.from(this.raw.magic, 'hex'), Buffer.from(this.raw.version, 'hex'), Buffer.from(this.raw.parent, 'hex'), + Buffer.from(this.raw.author, 'hex'), Buffer.from(this.raw.type, 'hex'), Buffer.from(this.raw.size, 'hex'), - Buffer.from(this.raw.signature, 'hex'), - Buffer.from(this.raw.hash, 'hex') + Buffer.from(this.raw.hash, 'hex'), + Buffer.from(this.raw.signature, 'hex') ]; return Buffer.concat(parts); @@ -350,8 +471,18 @@ Object.defineProperty(Message.prototype, 'type', { get () { const code = parseInt(this.raw.type.toString('hex'), 16); switch (code) { + case BITCOIN_BLOCK_TYPE: + return 'BitcoinBlock'; + case BITCOIN_BLOCK_HASH_TYPE: + return 'BitcoinBlockHash'; + case BITCOIN_TRANSACTION_TYPE: + return 'BitcoinTransaction'; + case BITCOIN_TRANSACTION_HASH_TYPE: + return 'BitcoinTransactionHash'; case GENERIC_MESSAGE_TYPE: return 'GenericMessage'; + case GENERIC_MESSAGE_TYPE + 1: + return 'JSONBlob'; case LOG_MESSAGE_TYPE: return 'GenericLogMessage'; case GENERIC_LIST_TYPE: @@ -394,22 +525,30 @@ Object.defineProperty(Message.prototype, 'type', { return 'StartSession'; case CHAT_MESSAGE: return 'ChatMessage'; + case JSON_CALL_TYPE: + return 'JSONCall'; case P2P_START_CHAIN: return 'StartChain'; - case TYPE_ETHEREUM_BLOCK: - return 'EthereumBlock'; - case TYPE_ETHEREUM_BLOCK_NUMBER: - return 'EthereumBlockNumber'; default: return 'GenericMessage'; } }, set (value) { let code = this.types[value]; - // Default to GenericMessage; + // Default to GenericMessage or JSONBlob based on content if (!code) { this.emit('warning', `Unknown message type: ${value}`); - code = this.types['GenericMessage']; + // Check if data is valid JSON + try { + if (this.data && JSON.parse(this.data)) { + code = this.types['JSONBlob']; + value = 'JSONBlob'; + } else { + code = this.types['GenericMessage']; + } + } catch (e) { + code = this.types['GenericMessage']; + } } const padded = padDigits(code.toString(16), 8); @@ -425,8 +564,7 @@ Object.defineProperty(Message.prototype, 'data', { }, set (value) { if (!value) value = ''; - const hash = crypto.createHash('sha256').update(value.toString('utf8')); - this.raw.hash = hash.digest(); + this.raw.hash = Hash256.digest(value.toString('utf8')); this.raw.data = Buffer.from(value); this.raw.size.write(padDigits(this.raw.data.byteLength.toString(16), 8), 'hex'); } diff --git a/types/node.js b/types/node.js index d00e9b83c..edaf2b568 100644 --- a/types/node.js +++ b/types/node.js @@ -13,15 +13,7 @@ const Service = require('../types/service'); const Environment = require('../types/environment'); const environment = new Environment(); -/** - * Full definition of a Fabric node. - */ class Node extends Service { - /** - * Manage a Fabric service. - * @param {Object} settings Configuration for the node. - * @returns {Node} Instance of the managed service. - */ constructor (settings = {}) { super(settings); @@ -34,7 +26,7 @@ class Node extends Service { peering: true, service: Service, settings: {} - }, this.settings, settings); + }, settings); // Local Services this.node = new Peer(this.settings); @@ -61,28 +53,40 @@ class Node extends Service { self.emit('debug', `[FABRIC:DEBUG] ${extra}${debug}`); }); + source.on('connections:open', function (data) { + self.emit('log', `connection open: ${JSON.stringify(data)}`); + }); + + source.on('connections:close', function (data) { + self.emit('log', `connection close: ${JSON.stringify(data)}`); + }); + + source.on('chat', function (chat) { + self.emit('chat', chat); + }); + source.on('info', function (info) { - console.log(`[FABRIC:INFO] ${extra}`, info); + self.emit('info', `${extra}${info}`); }); source.on('log', function (log) { - self.emit('log', `[FABRIC:LOG] ${extra}${log}`); + self.emit('log', `${extra}${log}`); }); source.on('warning', function (warn) { - console.warn(`[FABRIC:WARNING] ${extra}`, warn); + self.emit('warning', `[FABRIC:WARNING] ${extra}${warn}`); }); source.on('error', function (error) { - console.error(`[FABRIC:ERROR] ${extra}`, error); + self.emit('error', `[FABRIC:ERROR] ${extra}${error}`); }); source.on('exception', function (error) { - console.error(`[FABRIC:EXCEPTION] ${extra}`, error); + self.emit('error', `[FABRIC:EXCEPTION] ${extra}${error}`); }); source.on('message', function (msg) { - console.log(`[FABRIC:MESSAGE] ${extra}`, msg); + self.emit('message', `[FABRIC:MESSAGE] ${extra}${msg}`); }); source.on('commit', function (msg) { @@ -90,8 +94,10 @@ class Node extends Service { }); source.on('ready', function () { - console.log(`[FABRIC] ${extra}`, `<${source.constructor.name}>`, 'Claimed ready!'); + self.emit('log', `[FABRIC] ${extra}<${source.constructor.name}> Claimed ready!`); }); + + return this; } async start () { diff --git a/types/noise.js b/types/noise.js deleted file mode 100644 index 8c4808129..000000000 --- a/types/noise.js +++ /dev/null @@ -1,291 +0,0 @@ -'use strict'; - -// Constants -const PROTOCOL_NAME = 'Noise_XK_secp256k1_ChaChaPoly_SHA256'; -const NOISE_PROLOGUE = 'lightning'; -const NOISE_VERSION_BYTE = Buffer.from('00', 'hex'); - -// Dependencies -const net = require('net'); -const crypto = require('crypto'); -const merge = require('lodash.merge'); - -// Cryptography -const EC = require('elliptic').ec; -const ec = new EC('secp256k1'); - -// Types Used -const Reader = require('./reader'); -const Service = require('./service'); -const Key = require('./key'); -const Actor = require('./actor'); -const HKDF = require('./hkdf'); -const Hash256 = require('./hash256'); - -class NOISE extends Service { - constructor (settings = {}) { - super(settings); - - this.settings = merge({ - persistent: false, - interface: '0.0.0.0', - port: 9735, - timeout: 60000 - }, settings); - - this.key = null; - this.server = null; - this.address = null; - - this.connections = {}; - - this._state = { - connections: {}, - status: 'STOPPED' - }; - - return this; - } - - /** - * Performs an Elliptic-Curve Diffie-Hellman operation using `k`, which is a valid secp256k1 private key, and `rk`, which is a valid public key. - * @param {Buffer} k Private key. - * @param {Buffer} rk Public key. - */ - ECDH (k, rk) { - let key = null; - let ecdh = null; - let remote = null; - - try { - key = ec.keyFromPrivate(k, 'hex'); - } catch (exception) { - console.error('could not read private key:', exception); - } - - try { - remote = ec.keyFromPublic(rk, 'hex'); - } catch (exception) { - console.error('could not read public key:', exception); - } - - try { - ecdh = key.derive(remote.pub); - } catch (exception) { - console.error('could not derive:', exception); - } - - const derived = ecdh.toString('hex'); - const hash = Hash256.digest(derived); - - return hash; - // TODO: The returned value is the SHA256 of the compressed format of the generated point. - } - - /** - * Generate 32 bytes of cryptographic randomness following RFC 5869. - * @param {Buffer} salt Salt. - * @param {Buffer} ikm Initial key material. - */ - HKDF (salt, ikm) { - const hkdf = new HKDF({ - initial: ikm, - salt: salt - }); - return hkdf.derive(''); - } - - encryptWithAD (k, n, ad, plaintext = '') { - const nonce = Buffer.alloc(12, 0x00); - nonce.writeBigUInt64LE(n, 4); - - const cipher = crypto.createCipheriv('chacha20-poly1305', k, nonce, { - authTagLength: 16 - }); - - cipher.setAAD(ad); - cipher.update(plaintext); - - const output = cipher.final(); - const mac = cipher.getAuthTag(); - - return mac || output; - } - - decryptWithAD (k, n, ad, ciphertext) { - const nonce = Buffer.alloc(12, 0x00); - nonce.writeBigUInt64LE(n, 4); - - const authTag = Buffer.from('9ef622cec7a5719261031e9ca91049d4', 'hex'); - const decipher = crypto.createDecipheriv('chacha20-poly1305', k, nonce, { - authTagLength: 16 - }); - - decipher.setAAD(ad); - decipher.update(ciphertext); - decipher.setAuthTag(authTag); - - const output = decipher.final(); - return output; - } - - async start () { - if (!this.key) this.key = new Key(this.settings); - - // Create TCP server - this.server = net.createServer(this._inboundConnectionHandler.bind(this)); - - // Event Handlers - this.server.on('error', this._serverErrorHandler.bind(this)); - - const self = this; - const promise = new Promise((resolve, reject) => { - self.server.listen(self.settings.port, self.settings.interface, async function _server (error) { - if (error) return reject(error); - try { - await self._handleServerReady(); - self.emit('ready'); - resolve(self); - } catch (exception) { - reject(exception); - } - }); - }); - - return promise; - } - - async stop () { - if (this.server) await this.server.close(); - } - - async connect (address) { - const self = this; - const parts = new URL(address); - const pair = `${parts.hostname}:${parts.port}`; - const actor = new Actor(pair); - - if (this.connections[actor.id]) return this.emit('error', `Already connected to ${pair} 0x${actor.id}`); - - this.connections[actor.id] = new net.Socket(); - this.connections[actor.id].on('data', async (data) => { - const response = 'Hello back, client!'; - const trimmed = data.toString().trim(); - if (trimmed === response) { - self.emit('log', `[CLIENT] Received ${response} — saying goodbye...`); - this.connections[actor.id].write('Goodbye, server.'); - await self.disconnect(actor.id); - } else { - console.log('[CLIENT] Received unexpected data:', trimmed); - } - }); - - this.connections[actor.id].on('end', () => { - self.emit('log', '[CLIENT] Disconnected.'); - }); - - this.connections[actor.id].connect(parts.port, parts.hostname, function (error) { - self.emit('log', '[CLIENT] Connected!'); - if (error) return self.emit('error', `Could not connect: ${error}`); - // TODO: NOISE Protocol Act 1 - this.write('Hello, world!\r\n'); - }); - - return this.connections[actor.id]; - } - - async disconnect (id) { - if (!this.connections[id]) return true; - - const pair = `${this.connections[id].remoteAddress}:${this.connections[id].remotePort}`; - - try { - this.connections[id].destroy(); - } catch (exception) { - console.error(`Exception closing socket ${pair} 0x${id}: ${exception}`); - } - - if (this.connections[id]._timeout) clearTimeout(this.connections[id]._timeout); - - delete this.connections[id]; - - // All clean, emit event - this.emit('connections:close', { - id: id - }); - - return true; - } - - async _serverErrorHandler (error) { - this.emit('error', error); - } - - /** - * Handler for inbound connections to the local host. - * @param {net.Socket} c Instance of the connection itself. - * @returns {NOISE} Current instance of the {@link NOISE} service. - */ - async _inboundConnectionHandler (c) { - const self = this; - const pair = `${c.remoteAddress}:${c.remotePort}`; - const actor = new Actor(pair); - - this.emit('log', `[SERVER] New inbound connection, return pair: ${pair} 0x${actor.id}`); - - // If we already have this connection, abort - if (this.connections[actor.id]) { - this.emit('warning', `[SERVER] Connection ${pair} already exists.`); - c.destroy(); // TODO: test various network conditions (safe closure vs. network interruption) - return this; - } - - // Track internal map of connections - this.connections[actor.id] = c; - - // Bind Event Listeners - c.on('close', () => { - self.emit('log', `[SERVER] Client disconnected: ${pair} 0x${actor.id}`); - self.disconnect(actor.id); - }); - - c.on('data', (data) => { - const hello = 'Hello, world!'; - const trimmed = data.toString().trim(); - if (trimmed === hello) { - self.emit('log', `[SERVER] Received ${hello}. Sending response...`); - c.write('Hello back, client!\r\n'); - } else { - this.emit('log', `[SERVER] Unknown input: ${trimmed}`); - } - }); - - return this; - } - - async _handleServerReady (error) { - if (error) return this.emit('error', `Unable to start server: ${error}`); - const service = this.server.address(); - this.address = `${this.key.pubkey}@${service.address}:${service.port}`; - this._state.status = 'READY'; - await this.commit(); - return this; - } - - async _updatePresence (actorID) { - const service = this; - const c = service.connections[actorID]; - - if (!c) return service.emit('error', `No such actor: ${actorID}`); - if (c._timeout) clearTimeout(c._timeout); - - c._timeout = setTimeout(() => { - c.destroy(); - delete service.connections[actorID]; - }, service.settings.timeout); - - return true; - } -} - -module.exports = NOISE; diff --git a/types/opcode.js b/types/opcode.js deleted file mode 100644 index 238bcc461..000000000 --- a/types/opcode.js +++ /dev/null @@ -1,22 +0,0 @@ -'use strict'; - -const Vector = require('./vector'); - -class Opcode { - constructor (definition) { - let opcode = this; - - opcode.config = Object.assign({}, definition); - opcode.vector = new Vector(definition)._sign(); - - return function Opcode (input) { - opcode.output = definition.call({ - id: opcode.vector['@id'] - }, input); - - return opcode.output; - }; - } -} - -module.exports = Opcode; diff --git a/types/oracle.js b/types/oracle.js index 11afdfd21..3ae03182f 100644 --- a/types/oracle.js +++ b/types/oracle.js @@ -4,16 +4,7 @@ const Machine = require('./machine'); const Resource = require('./resource'); const Store = require('./store'); -/** - * An Oracle manages one or more collections, using a mempool for - * transitive state. - * @extends Store - */ class Oracle extends Store { - /** - * Trusted point-of-reference for external services. - * @param {Object} initial - Initialization vector. - */ constructor (init) { super(init); diff --git a/types/path.js b/types/path.js index 724637d51..e276cbdda 100644 --- a/types/path.js +++ b/types/path.js @@ -1,14 +1,6 @@ 'use strict'; -/** - * A {@link Path} is a {@link Fabric}-native link to a {@link Document} - * within the network. - */ class Path extends String { - /** - * Create a new {@link Path}. - * @param {String|Object} input Named path. - */ constructor (input = {}) { super(input); @@ -31,4 +23,4 @@ class Path extends String { } } -module.exports = Path; \ No newline at end of file +module.exports = Path; diff --git a/types/peer.js b/types/peer.js index 2206b5287..d2bced881 100644 --- a/types/peer.js +++ b/types/peer.js @@ -2,40 +2,41 @@ // Constants const { + FABRIC_KEY_DERIVATION_PATH, P2P_IDENT_REQUEST, P2P_IDENT_RESPONSE, P2P_ROOT, P2P_PING, P2P_PONG, + P2P_PORT, P2P_START_CHAIN, P2P_INSTRUCTION, P2P_BASE_MESSAGE, P2P_STATE_COMMITTMENT, P2P_STATE_CHANGE, - P2P_STATE_ROOT, - ZERO_LENGTH_PLAINTEXT + P2P_STATE_ROOT } = require('../constants'); -// Internals +// Dependencies const net = require('net'); const crypto = require('crypto'); const stream = require('stream'); +const manager = require('fast-json-patch'); const noise = require('noise-protocol-stream'); - -// Dependencies const merge = require('lodash.merge'); -// const upnp = require('nat-upnp'); // Fabric Types const Actor = require('./actor'); +const Identity = require('./identity'); const Key = require('./key'); const Machine = require('./machine'); const Message = require('./message'); const Service = require('./service'); -const Session = require('./session'); -const Reader = require('./reader'); const Wallet = require('./wallet'); +// Constants +const PROLOGUE = 'FABRIC'; + /** * An in-memory representation of a node in our network. */ @@ -53,28 +54,43 @@ class Peer extends Service { this.name = 'Peer'; this.settings = merge({ - address: '0.0.0.0', + constraints: { + peers: { + max: 32, + shuffle: 8 + } + }, + interface: '0.0.0.0', + interval: 60000, // 1 minute network: 'regtest', networking: true, listen: true, peers: [], port: 7777, + state: Object.assign({ + actors: {}, + channels: {}, + contracts: {}, + documents: {}, + messages: {}, + services: {} + }, config.state), upnp: false, key: {} }, config); // Network Internals this.upnp = null; - this.server = net.createServer(this._handleConnection.bind(this)); + this.server = net.createServer(this._NOISESocketHandler.bind(this)); this.stream = new stream.Transform({ - transform (chunk, encoding, callback) { - // TODO: parse as encrypted data - callback(null, chunk); + transform (chunk, encoding, done) { + done(null, chunk); } }); + this.identity = new Identity(this.settings.key); this.key = new Key(this.settings.key); - this.wallet = new Wallet(this.settings.key); + // this.wallet = new Wallet(this.settings.key); // this.hex = this.key.public.encodeCompressed('hex'); // this.pkh = crypto.createHash('sha256').update(this.hex).digest('hex'); @@ -86,15 +102,22 @@ class Peer extends Service { }; // Internal properties + this.actors = {}; + this.contracts = {}; this.chains = {}; + this.candidates = []; this.connections = {}; + this.history = []; this.peers = {}; + this.mailboxes = {}; this.memory = {}; this.handlers = {}; this.messages = new Set(); + this.sessions = {}; // Internal Stack Machine - this.machine = new Machine(); + this.machine = new Machine({ key: this.settings.key }); + this.observer = null; this.meta = { messages: { @@ -104,7 +127,7 @@ class Peer extends Service { }; this._state = { - content: {}, + content: this.settings.state, peers: {}, chains: {}, connections: {}, @@ -124,11 +147,6 @@ class Peer extends Service { return this.key.pubkeyhash; } - get state () { - // TODO: use Proxy - return Object.assign({}, this._state); - } - /** * @deprecated */ @@ -136,6 +154,55 @@ class Peer extends Service { return this.settings.interface || this.settings.address; } + get documentation () { + return { + name: 'Fabric', + description: 'Manages connections to the Fabric Network.', + methods: { + ack: { + description: 'Acknowledge a message.', + parameters: { + message: { + // TODO: consider making this a FabricMessageID + type: 'FabricMessage', + description: 'The message to acknowledge.' + } + }, + returns: { + type: 'Promise', + description: 'A Promise which resolves to the completed FabricState.' + } + }, + send: { + description: 'Send a message to a connected peer.', + parameters: { + message: { + type: 'FabricMessage', + description: 'The message to send to the peer.' + } + }, + returns: { + type: 'Promise', + description: 'A Promise which resolves to the response (if any).' + } + }, + broadcast: { + description: 'Broadcast a message to all connected nodes.', + parameters: { + message: { + type: 'FabricMessage', + description: 'The message to send to the node.' + } + }, + returns: { + type: 'Promise', + description: 'A Promise which resolves to the responses (if any).' + } + } + } + } + } + get interface () { return this.settings.interface || this.settings.address; } @@ -144,901 +211,758 @@ class Peer extends Service { return this.settings.port || 7777; } - set state (value) { - this._state = value; + get publicPeers () { + const peers = []; + return peers; } - /** - * Start the Peer. - */ - async start () { - let address = null; - - this.emit('log', 'Peer starting...'); - - if (this.settings.upnp) { - this.upnp = upnp.createClient(); - } - - this.emit('log', 'Wallet starting...'); - - try { - await this.wallet.start(); - } catch (exception) { - this.emit('error', `Could not start wallet: ${exception}`); - } + beat () { + const initial = new Actor(this.state); + const now = (new Date()).toISOString(); - if (this.settings.listen) { - this.emit('log', 'Listener starting...'); - - try { - address = await this.listen(); - this.emit('log', 'Listener started!'); - } catch (exception) { - this.emit('error', 'Could not listen:', exception); - } - } - - if (this.settings.networking) { - this.emit('warning', `Networking enabled. Connecting to peers: ${JSON.stringify(this.settings.peers)}`); - for (const candidate of this.settings.peers) { - this._connect(candidate); - } - } - - this.emit('ready', { - id: this.id, - address: address, - pubkey: this.key.pubkey + this.commit(); + this.emit('beat', { + created: now, + initial: initial.toGenericMessage(), + state: this.state }); return this; } /** - * Stop the peer. + * Write a {@link Buffer} to all connected peers. + * @param {Buffer} message Message buffer to send. */ - async stop () { - const peer = this; - - // Alert listeners - peer.emit('log', 'Peer stopping...'); + broadcast (message, origin = null) { + for (const id in this.connections) { + if (id === origin) continue; + this.connections[id]._writeFabric(message); + } + } - if (peer.settings.upnp && peer.upnp) { - peer.upnp.close(); + relayFrom (origin, message, socket = null) { + for (const id in this.connections) { + if (id === origin) continue; + this.connections[id]._writeFabric(message.toBuffer(), socket); } + } - for (const id in peer.connections) { - peer.emit('log', `Closing connection: ${id}`); - const connection = peer.connections[id]; - const closer = async function () { - return new Promise((resolve, reject) => { - // Give socket a timeout to close cleanly, destroy if failed - let deadline = setTimeout(function () { - peer.emit('warning', `[FABRIC:PEER] end() timed out for peer "${id}" so calling destroy...`); - connection.destroy(); - resolve(); - }, 5000); - - // TODO: notify remote peer of closure - // Use end(SOME_CLOSE_MESSAGE, ...) - return connection.end(function socketClosed (error) { - if (error) return reject(error); - clearTimeout(deadline); - resolve(); - }); - }); + _beginFabricHandshake (client) { + // Start handshake + const vector = ['P2P_SESSION_OFFER', JSON.stringify({ + type: 'P2P_SESSION_OFFER', + actor: { + id: this.identity.id + }, + object: { + challenge: crypto.randomBytes(8).toString('hex'), } - await closer(); - } + })]; - const terminator = async function () { - return new Promise((resolve, reject) => { - if (!peer.server.address()) return resolve(); - return peer.server.close(function serverClosed (error) { - if (error) return reject(error); - resolve(); - }); - }); - } + // Create offer message + const P2P_SESSION_OFFER = Message.fromVector(vector).signWithKey(this.key); + const message = P2P_SESSION_OFFER.toBuffer(); + if (this.settings.debug) this.emit('debug', `session_offer ${P2P_SESSION_OFFER} ${message.toString('hex')}`); - await terminator(); + // Send handshake + try { + client.encrypt.write(message); + } catch (exception) { + this.emit('error', `Cannot write to socket: ${exception}`); + } return this; } - async _setState (value) { - if (!value) return new Error('You must provide a State to set the value to.'); - this.state.state = value; - return this.state.state; - } - - // TODO: use in _connect - async _sessionStart (socket, target) { - const self = this; - const address = `${target.address}:${target.port}`; + /** + * Open a Fabric connection to the target address and initiate the Fabric Protocol. + * @param {String} target Target address. + */ + _connect (target) { + this.emit('debug', `Connecting to target: ${target}`); + const url = new URL(`tcp://${target}`); + const id = url.username; - self.emit('debug', `Starting session with address: ${target.pubkey}@${address}`); - self.connections[address].session = new Session({ recipient: target.pubkey }); - await self.connections[address].session.start(); + if (!url.port) target += `:${P2P_PORT}`; - self.emit('debug', `Session created: ${JSON.stringify(self.connections[address].session)}`); + const derived = this.identity.key.derive(FABRIC_KEY_DERIVATION_PATH); + this.emit('debug', `Local derived ID: ${JSON.stringify(derived)}`); - // First time seeing our local address, use it - // TODO: evaluate trust model - if (!self.public.ip) { - self.public.ip = socket.localAddress; - self.emit('log', `Local socket was null, changed to: ${self.public.ip}`); + // Store the user's public key if provided + if (id) { + this.peers[target] = { + ...this.peers[target], + publicKey: id + }; } - // TODO: consolidate with similar _handleConnection segment - // TODO: check peer ID, eject if self or known - - // TODO re-enable (disabled to reduce spammy messaging) - // /* - // TODO: re-evaluate use of IdentityRequest - // const vector = ['IdentityRequest', self.id]; - const vector = ['StartSession', JSON.stringify({ - id: self.connections[address].session.id, - identity: self.id, - advertise: `${self.key.pubkey}@${self.public.ip}:${self.public.port}`, - signature: self.connections[address].session.key._sign(self.id) - })]; - - const message = Message.fromVector(vector); + this._registerActor({ name: target }); + this._registerPeer({ identity: id }); - if (!socket.writable) { - self.emit('error', `Socket is not writable.`); - return false; - } + // Set up the NOISE socket + const socket = net.createConnection(url.port || P2P_PORT, url.hostname); + const client = noise({ + initiator: true, + prologue: Buffer.from(PROLOGUE), + // privateKey: derived.privkey, + verify: this._verifyNOISE.bind(this) + }); - self.sendToSocket(address, message); + socket.on('error', (error) => { + this.emit('error', `Socket error: ${error}`); + }); - // Emit notification of a newly opened connection - self.emit('connections:open', { - address: address, - status: 'unauthenticated', - initiator: true + socket.on('open', (info) => { + this.emit('debug', `Socket open: ${info}`); }); - this.emit('log', `Connection to ${address} established!`); - } + socket.on('close', (info) => { + this.emit('debug', `Outbound socket closed: (${target}) ${info}`); + socket._destroyFabric(); + }); - async _processCompleteDataPacket (socket, address, data) { - // Constants - const self = this; - // TODO: actually decrypt packet - const decrypted = socket.session.decrypt(data); + socket.on('end', (info) => { + this.emit('debug', `Socket end: (${target}) ${info}`); + }); - this.emit('debug', `Handling data packet:`, data); + // Handle trusted Fabric messages + client.decrypt.on('data', (data) => { + this._handleFabricMessage(data, { name: target }, client); + }); - // Variables - let message = null; + // Start stream + client.encrypt.pipe(socket).pipe(client.decrypt); - try { - message = self._parseMessage(decrypted); - } catch (exception) { - console.error('[FABRIC:PEER]', 'Could not parse inbound messsage:', exception); - } + // TODO: output stream + // client.decrypt.pipe(this.stream); - // disconnect from any peer sending invalid messages - if (!message) return socket.destroy(); + this._registerNOISEClient(target, socket, client); + this._beginFabricHandshake(client); - const response = await self._handleMessage({ - message: message, - origin: address, - peer: { - address: address, - id: socket.id - } + this.emit('connections:open', { + address: target, + id: target, + url: url }); - - if (response) { - self.meta.messages.outbound++; - self.sendToSocket(address, response); - } } - async _handleSocketData (socket, address, data) { - this.emit('debug', `Received data from peer: ${data}`); - - if (!socket.session) { - this.emit('error', `Received data on socket without a session! Violator: ${address}`); - return false; - } - - socket._reader._addData(data); + _announceAlias (alias, origin = null, socket = null) { + const PACKET_PEER_ALIAS = Message.fromVector(['P2P_PEER_ALIAS', JSON.stringify({ + type: 'P2P_PEER_ALIAS', + object: { + name: alias + } + })]); - return true; + const announcement = PACKET_PEER_ALIAS.toBuffer(); + this.broadcast(announcement, origin.name); } - _connect (address) { - const self = this; - const parts = address.split(':'); - const known = Object.keys(self.connections); - const keyparts = parts[0].split('@'); - const target = { - pubkey: null, - address: null, - port: null - }; - - if (keyparts.length === 2) { - target.pubkey = keyparts[0]; - target.address = keyparts[1]; - target.port = parts[1]; - } else { - target.address = parts[0]; - target.port = parts[1]; - } - - if (target.pubkey === self.key.public) return this.emit('error', 'Cannot connect to self.'); - - const authority = `${target.address}:${target.port}`; + _destroyFabric (socket, target) { + if (socket._keepalive) clearInterval(socket._keepalive); - this.emit('log', `Connecting to address: ${authority}`); + delete this.connections[target]; + delete this.peers[target]; - if (parts.length !== 2) return console.debug('Invalid address:', address); - if (known.includes(authority)) return self.connections[authority]; - - /* const c = new net.Socket(); - const client = noise({ - initiator: true, - privateKey: self.key.private, - prologue: 'fabric:playnet', - verify: function () {} + this.emit('connections:close', { + address: target, + name: target }); + } - client.decrypt.on('data', function (data) { - console.log('decrypted:', data); - }); - - client.encrypt.pipe(c).pipe(client.decrypt); - - c.connect(target.port, target.address, async function connectionAttemptComplete (error) { - if (error) return new Error(`Could not establish connection: ${error}`); - }); */ - - // TODO: refactor to use local functions + specific unbindings - try { - // TODO: consolidate with this._handleConnection - self.connections[authority] = new net.Socket(); - self.connections[authority]._reader = new Reader(); - - self.connections[authority]._reader.on('debug', function (msg) { - self.emit('debug', msg); - }); + /** + * Attempt to fill available connection slots with new peers. + * @returns {Peer} Instance of the peer. + */ + _fillPeerSlots () { + if (this.connections.length >= this.settings.constraints.peers.max) return; + const openCount = this.settings.constraints.peers.max - Object.keys(this.connections).length; + for (let i = 0; i < openCount; i++) { + if (!this.candidates.length) continue; + const candidate = this.candidates.shift(); + // this.emit('debug', `Filling peer slot ${i} of ${openCount} (max ${this.settings.constraints.peers.max}) with candidate: ${JSON.stringify(candidate, null, ' ')}`); + + try { + this._connect(`${candidate.object.host}:${candidate.object.port}`); + } catch (exception) { + this.emit('error', `Unable to fill open peer slot ${i}: ${exception}`); + } - self.connections[authority]._reader.on('message', function (msg) { - self._processCompleteDataPacket.apply(self, [ self.connections[authority], authority, msg ]); - }); + // Place the candidate back in the list + this.candidates.push(candidate); + } - self.connections[authority].on('error', function (err) { - const text = `could not connect to peer ${authority} — Reason: ${err}`; - self.emit('connection:error', { - message: text - }); - // console.debug('[PEER]', `could not connect to peer ${authority} — Reason:`, err); - }); + return this; + } - self.connections[authority].on('close', function _handleSocketClose (err) { - if (err) self.debug('socket closed on error:', err); - if (err) self.emit('log', `socket closed on error: ${err}`); + /** + * Handle a Fabric {@link Message} buffer. + * @param {Buffer} buffer + * @returns {Peer} Instance of the Peer. + */ + _handleFabricMessage (buffer, origin = null, socket = null) { + const hash = crypto.createHash('sha256').update(buffer).digest('hex'); + const message = Message.fromBuffer(buffer); + if (this.settings.debug) this.emit('debug', `Got Fabric message: ${message}`); - self.emit('warning', `Connection closed: ${authority}`); + // Have we seen this message before? + if (this.messages[hash]) { + // this.emit('debug', `Duplicate message: ${hash}`); + return; + } - self.connections[authority].removeAllListeners(); + // Store message for later + this.messages[hash] = buffer.toString('hex'); - // TODO: consider using `process.nextTick` to only clean up after event? - delete self.connections[authority]; - self.emit('connections:close', { - address: authority - }); - }); + const checksum = crypto.createHash('sha256').update(message.body, 'utf8').digest('hex'); + if (checksum !== message.raw.hash.toString('hex')) throw new Error('Message received with incorrect hash.'); - // TODO: unify as _dataHandler - self.connections[authority].on('data', async function peerDataHandler (data) { - self._handleSocketData.apply(self, [ this, authority, data ]); - }); + // Verify message signature if we have the peer's public key + if (origin && this.peers[origin] && this.peers[origin].publicKey) { + const signer = new Key({ public: this.peers[origin].publicKey }); + if (!message.verifyWithKey(signer)) { + this.emit('error', `Invalid message signature from ${origin}`); + return; + } + } - self.emit('connection', { - id: authority - }); + if (this.settings.debug) this.emit('debug', `Message author: ${message.raw.signature.toString('hex')}`); + if (this.settings.debug) this.emit('debug', `Message signature: ${message.raw.signature.toString('hex')}`); - self.emit('log', `Starting connection to address: ${authority}`); + switch (message.type) { + default: + this.emit('debug', `Unhandled message type: ${message.type}`); + break; + case 'GenericMessage': + case 'PeerMessage': + case 'ChatMessage': + // Parse JSON body + try { + const content = JSON.parse(message.data); + this._handleGenericMessage(content, origin, socket); + } catch (exception) { + this.emit('error', `Broken content body: ${exception}`); + } - // TODO: replace with handshake - // NOTE: the handler is only called once per connection! - self.connections[authority].connect(target.port, target.address, async function connectionAttemptComplete (error) { - if (error) return new Error(`Could not establish connection: ${error}`); - await self._sessionStart.apply(self, [ this, target ]); - self._maintainConnection(authority); - }); - } catch (E) { - self.log('[PEER]', 'failed to connect:', E); + break; } - return self.connections[authority]; + this.commit(); + + return this; } - _disconnect (address) { - if (!this.connections[address]) return false; + _handleGenericMessage (message, origin = null, socket = null) { + if (this.settings.debug) this.emit('debug', `Generic message:\n\tFrom: ${JSON.stringify(origin)}\n\tType: ${message.type}\n\tBody:\n\`\`\`\n${JSON.stringify(message.object, null, ' ')}\n\`\`\``); - // Halt any heartbeat - if (this.connections[address].heartbeat) { - clearInterval(this.connections[address].heartbeat); - } + // Lookup the appropriate Actor for the message's origin + const actor = new Actor(origin); - // Destroy the connection - this.connections[address].destroy(); - - // Remove connection from map - delete this.connections[address]; - } + switch (message.type) { + default: + this.emit('debug', `Unhandled Generic Message: ${message.type} ${JSON.stringify(message, null, ' ')}`); + break; + case 'P2P_SESSION_OFFER': + if (this.settings.debug) this.emit('debug', `Handling session offer: ${JSON.stringify(message.object)}`); + if (this.settings.debug) this.emit('debug', `Session offer origin: ${JSON.stringify(origin)}`); + if (this.settings.debug) this.emit('debug', `connections: ${JSON.stringify(Object.keys(this.connections))}`); + + // Peer is valid + // TODO: remove this assumption (validate above) + // TODO: check for existing peer, update instead of replace + this.peers[origin.name] = { + id: message.actor.id, + name: origin.name, + address: origin.name, + connections: [ origin.name ] + }; + + // Emit peer event + this.emit('peer', this.peers[origin.name]); + + // Send session open event + const vector = ['P2P_SESSION_OPEN', JSON.stringify({ + type: 'P2P_SESSION_OPEN', + object: { + initiator: message.actor.id, + counterparty: this.identity.id, + solution: message.object.challenge + } + })]; + + const PACKET_SESSION_START = Message.fromVector(vector).signWithKey(this.key); + const reply = PACKET_SESSION_START.toBuffer(); + if (this.settings.debug) this.emit('debug', `session_start ${PACKET_SESSION_START} ${reply.toString('hex')}`); + this.connections[origin.name]._writeFabric(reply, socket); + break; + case 'P2P_SESSION_OPEN': + if (this.settings.debug) this.emit('debug', `Handling session open: ${JSON.stringify(message.object)}`); + this.peers[origin.name] = { id: message.object.counterparty, name: origin.name, address: origin }; + this.emit('peer', this.peers[origin.name]); + break; + case 'P2P_CHAT_MESSAGE': + this.emit('chat', message); + const relay = Message.fromVector(['ChatMessage', JSON.stringify(message)]); + relay.signWithKey(this.key); + // this.emit('debug', `Relayed chat message: ${JSON.stringify(relay.toGenericMessage())}`); + this.relayFrom(origin.name, relay); + break; + case 'P2P_STATE_ANNOUNCE': + const state = new Actor(message.object.state); + this.emit('debug', `state_announce ${JSON.stringify(message.object || '')} ${state.toGenericMessage()}`); + break; + case 'P2P_PING': + const now = (new Date()).toISOString(); + const P2P_PONG = Message.fromVector(['GENERIC', JSON.stringify({ + actor: { + id: this.identity.id + }, + created: now, + type: 'P2P_PONG', + object: { + created: now + } + })]); + + this.connections[origin.name]._writeFabric(P2P_PONG.toBuffer()); + break; + case 'P2P_PONG': + // Update the peer's score for succesfully responding to a ping + // TODO: ensure no pong is handled when a ping was not previously sent + const instance = this.state.actors[actor.id] ? this.state.actors[actor.id] : {}; - _parseMessage (data) { - if (!data) return false; - if (this.settings.verbosity >= 5) console.log('[FABRIC:PEER]', 'Parsing message:', data); + this.actors[actor.id].adopt([ + { op: 'replace', path: '/score', value: (instance.score || 0) + 1 } + ]); - // Variables - let message = null; + this._state.content.actors[actor.id] = this.actors[actor.id].state; + this.commit(); - try { - message = Message.fromRaw(data); - } catch (exception) { - this.emit('debug', `[FABRIC:PEER] error parsing message: ${exception}`); + this.emit('state', this.state); + break; + case 'P2P_PEER_ALIAS': + this.emit('debug', `peer_alias ${origin.name} ${JSON.stringify(message.object || '')}`); + this.connections[origin.name]._alias = message.object.name; + break; + case 'P2P_PEER_ANNOUNCE': + this.emit('debug', `peer_announce ${JSON.stringify(message.object || '')}`); + const candidate = new Actor(message.object); + this.candidates.push(candidate.toGenericMessage()); + // this._fillPeerSlots(); + + // const announce = Message.fromVector(['PeerAnnounce', JSON.stringify(message)]); + // this.relayFrom(origin.name, announce); + break; + case 'P2P_DOCUMENT_PUBLISH': + break; + case 'CONTRACT_PUBLISH': + // TODO: reject and punish mis-behaving peers + this.emit('debug', `Handling peer contract publish: ${JSON.stringify(message.object)}`); + this._registerContract(message.object); + break; + case 'CONTRACT_MESSAGE': + // TODO: reject and punish mis-behaving peers + if (this.settings.debug) this.emit('debug', `Handling contract message: ${JSON.stringify(message.object)}`); + if (this.settings.debug) this.emit('debug', `Contract state: ${JSON.stringify(this.state.contracts[message.object.contract])}`); + manager.applyPatch(this._state.content.contracts[message.object.contract], message.object.ops); + this.commit(); + break; } + } - if (this.settings.verbosity >= 5) console.log('[FABRIC:PEER]', 'Parsed message into:', message.type, message.data); - return message; + _handleNOISEHandshake (localPrivateKey, localPublicKey, remotePublicKey) { + this.emit('debug', `Peer transport handshake using local key: ${localPrivateKey.toString('hex')}`); + this.emit('debug', `Peer transport handshake using local public key: ${localPublicKey.toString('hex')}`); + this.emit('debug', `Peer transport handshake with remote public key: ${remotePublicKey.toString('hex')}`); } - async _handleConnection (socket) { - const self = this; - const address = [socket.remoteAddress, socket.remotePort].join(':'); - // const server = noise({ - /* verify: function (localPrivateKey, localPublicKey, remotePublicKey, finish) { - // Calling finish with an error as first argument will also emit an error event on the stream pair. - // The callback must be called explicitly with true to accept. - if (true || TRUSTED_PUBLIC_KEY.equals(remotePublicKey)) { - finish(null, true); - } else { - finish(null, false); - } - } */ - // }); + _NOISESocketHandler (socket) { + const target = `${socket.remoteAddress}:${socket.remotePort}`; + const url = `tcp://${target}`; - self.emit('log', `[FABRIC:PEER] [0x${self.id}] Incoming connection from address: ${address}`); + // Store a unique actor for this inbound connection + this._registerActor({ name: target }); - self.emit('connections:open', { - address: address, - status: 'connected', - initiator: false + // Create NOISE handler + const handler = noise({ + prologue: Buffer.from(PROLOGUE), + // privateKey: this.identity.key.private, + verify: this._verifyNOISE.bind(this) }); - /* - server.encrypt.pipe(socket).pipe(server.decrypt); - - // Emitted after the connection is accepted in the verify function - server.encrypt.on('handshake', function (localPrivateKey, localPublicKey, remotePublicKey) { - console.log('server encrypt handshake:', remotePublicKey); + // Set up NOISE event handlers + handler.encrypt.on('handshake', this._handleNOISEHandshake.bind(this)); + handler.encrypt.on('error', (error) => { + this.emit('error', `NOISE encrypt error: ${error}`); }); - // Reading and writing will only work after the connection is accepted - server.decrypt.on('data', function (data) { - console.log('incoming connection decrypted data:', data); - }); */ - - // TODO: use known key - socket.session = new Session(); - socket._reader = new Reader(); + handler.encrypt.on('end', (data) => { + this.emit('debug', `Peer encrypt end: ${data}`); + }); - // Bind Reader events (Fabric) - socket._reader.on('debug', function (msg) { - self.emit('debug', msg); + handler.decrypt.on('error', (error) => { + this.emit('error', `NOISE decrypt error: ${error}`); }); - socket._reader.on('message', function (msg) { - self._processCompleteDataPacket.apply(self, [ socket, address, msg ]); + handler.decrypt.on('close', (data) => { + this.emit('debug', `Peer decrypt close: ${data}`); }); - // Bind Socket events (Peer) - socket.on('close', function terminate () { - self.emit('log', `connection closed: ${address}`); - self.emit('connections:close', { address: address }); - self._disconnect(address); + handler.decrypt.on('end', (data) => { + this.emit('debug', `Peer decrypt end: ${data}`); }); - socket.on('data', function inboundPeerHandler (data) { - try { - self._handleSocketData.apply(self, [ socket, address, data ]); - } catch (exception) { - self.emit('error', `Could not handle socket data: ${exception}`); - } + handler.decrypt.on('data', (data) => { + this._handleFabricMessage(data, { name: target }); }); - // add this socket to the list of known connections - this.connections[address] = socket; + socket._destroyFabric = () => { + this._destroyFabric(socket, target); + }; - self._maintainConnection(address); - } + socket._writeFabric = (msg) => { + this._writeFabric(msg, handler); + }; - _maintainConnection (address) { - const peer = this; - if (!peer.connections[address]) return new Error(`Connection for address "${address}" does not exist.`); - /* peer.connections[address]._player = setInterval(function () { - peer._pingConnection.apply(peer, [ address ]); - }, 60000); */ - } + // Store socket in collection + this.connections[target] = socket; - _pingConnection (address) { - const ping = Message.fromVector(['Ping', `${Date.now().toString()}`]); + // Begin NOISE stream + handler.encrypt.pipe(socket).pipe(handler.decrypt); - try { - this.sendToSocket(address, ping); - } catch (exception) { - this.emit('error', `Couldn't deliver message to socket: ${exception}`); - } + this.emit('connections:open', { + id: target, + url: url + }); } - _updateLiveness (address) { - // Return Error if no connection - if (!this.connections[address]) { - const error = `No connection for address: ${address}`; - this.emit('error', error); - return new Error(error); - } + _publishDocument (hash, rate = 0) { + this._state.content.documents[hash] = document; - // Set the _lastMessage property - this.connections[address]._lastMessage = Date.now(); + this.commit(); - // Make chainable - return this; - } + const PACKET_DOCUMENT_PUBLISH = Message.fromVector(['P2P_DOCUMENT_PUBLISH', JSON.stringify({ + type: 'P2P_DOCUMENT_PUBLISH', + object: { + hash: hash, + rate: rate + } + })]); - _registerHandler (type, method) { - if (this.handlers[type]) return new Error(`Handler for method "${type}" is already registered.`); - this.handlers[type] = method.bind(this); - return this.handlers[type]; + const message = PACKET_DOCUMENT_PUBLISH.toBuffer(); + if (this.settings.debug) this.emit('debug', `Broadcasting document publish: ${message.toString('utf8')}`); + this.broadcast(message); } - _registerPeer (peer) { - if (this.settings.verbosity >= 6) console.warn('[AUDIT]', 'Registering peer:', peer); - let self = this; + _registerActor (object) { + this.emit('debug', `Registering actor: ${JSON.stringify(object, null, ' ')}`); + const actor = new Actor(object); - if (!peer) return false; - if (!peer.id) { - self.log(`Peer attribute 'id' is required.`); - return false; - } + if (this.actors[actor.id]) return this; - self.peers[peer.id] = peer; + this.actors[actor.id] = actor; + this.commit(); + this.emit('actorset', this.actors); - // console.log('[FABRIC:PEER]', `[@ID:$${self.id}]`, 'Peer registered:', peer); - // console.log('[FABRIC:PEER]', `[@ID:$${self.id}]`, 'Peer list:', self.peers); + return this; + } - self.emit('peer', peer); + _registerContract (object) { + this.emit('debug', `Registering contract: ${JSON.stringify(object, null, ' ')}`); + const actor = new Actor(object); - // TODO: document peer announcement - // TODO: eliminate use of JSON in messaging - const announcement = Message.fromVector(['PeerCandidate', JSON.stringify(peer)]); + if (this.contracts[actor.id]) return this; - try { - self.relayFrom(peer.id, announcement); - } catch (exception) { - self.emit('error', `Could not relay peer registration: ${exception}`); - } + this.contracts[actor.id] = actor; + this._state.content.contracts[actor.id] = object.state; - return true; - } + this.commit(); + this.emit('contractset', this.contracts); - async _requestStateFromAllPeers () { - const message = Message.fromVector(['StateRequest']); - this.broadcast(message); + return this; } - async _handleMessage (packet) { - if (!packet) return false; - - // Constants - const self = this; - const message = packet.message; - const origin = packet.origin; + _registerNOISEClient (name, socket, client) { + // Assign socket properties + // Failure counter + socket._failureCount = 0; + socket._lastMessage = null; + socket._messageLog = []; + + // Enable keepalive + socket._keepalive = setInterval(() => { + const now = (new Date()).toISOString(); + const P2P_PING = Message.fromVector(['GENERIC', JSON.stringify({ + actor: { + id: this.identity.id + }, + created: now, + type: 'P2P_PING', + object: { + created: now + } + })]); - // Variables - let relay = false; - let response = null; + try { + client.encrypt.write(P2P_PING.toBuffer()); + } catch (exception) { + this.emit('debug', `Cannot write ping: ${exception}`) + } + }, 60000); - this._updateLiveness(origin); + // TODO: reconcile APIs for these methods + // Map destroy function + socket._destroyFabric = () => { + this._destroyFabric(socket, name); + }; - if (!message) return this.emit('error', `Hard failure: ${packet}`); - if (this.messages.has(message.id)) { - // this.emit('debug', `Received duplicate message ${message.id} from [${origin}] in packet: ${JSON.stringify(packet, null, ' ')}`); - return false; - } else { - this.memory[message.id] = message; - this.messages.add(message.id); - } + // Map write function + socket._writeFabric = (msg) => { + this._writeFabric(msg, client); + }; - this.emit('log', `Evaluting message with purported type "${message.type}":`); + this.connections[name] = socket; - // Build a response to various message types - switch (message.type) { - case 'ChatMessage': - relay = true; - this.emit('debug', `Message: ${JSON.stringify({ - type: message.type, - data: message.data, - size: message.data.length - }, null, ' ')}`); - this.emit('debug', `Data (${typeof message.data}): \n\t${message.data}`); + return this; + } - try { - const data = JSON.parse(message.data); - this.emit('debug', `Parsed (${typeof data}): ${JSON.stringify(data, null, ' ')}`); - this.emit('log', `[${data.object.created}] @${data.actor}: ${data.object.content}`); - this.emit('message', message.data); - } catch (exception) { - this.emit('error', `Could not process ChatMessage: ${exception}`); - } - break; - case 'Generic': - relay = true; - break; - case 'Ping': - response = Message.fromVector(['Pong', message.id]); - break; - case 'Pong': - // self.emit('message', `Received Pong: ${message}`); - break; - case 'StartChain': - break; - case 'GenericMessage': - // console.warn('[FABRIC:PEER]', 'Received Generic Message:', message.data); - relay = true; - break; - case 'IdentityRequest': - console.log('[FABRIC:PEER]', 'Peer sent IdentityRequest. Responding with IdentityResponse (node id)...', self.id); - response = Message.fromVector(['IdentityResponse', self.id]); - break; - case 'IdentityResponse': - if (!self.peers[message.data]) { - let peer = { - id: message.data, - address: packet.origin - }; - - // TODO: remove in favor of StartSession - // Why? Duplicate "peer" event is sent within _registerPeer - // Try to register peer... - /* try { - self._registerPeer(peer); - } catch (exception) { - self.emit('error', `Could not register peer ${message.data} because: ${exception}`); - } */ - } + _registerPeer (data) { + const peer = new Actor({ + type: 'Peer', + data: data + }); - response = Message.fromVector(['StateRoot', JSON.stringify(self.state)]); - break; - case 'DocumentPublish': - this.emit('log', `Document published from peer: ${message.data}`); - this.emit('DocumentPublish', message.data); - break; - case 'DocumentRequest': - this.emit('DocumentRequest', message.data); - break; - case 'BlockCandidate': - break; - case 'PeerCandidate': - let candidate = null; + if (this.peers[peer.id]) return this; - try { - candidate = JSON.parse(message.data); - } catch (exception) { - console.error('[FABRIC:PEER]', `[@ID:$${self.id}]`, 'Could not parse PeerCandidate message:', message.data, exception); - } + this.peers[peer.id] = peer; - self.emit('peer:candidate', candidate); - break; - case 'PeerMessage': - // console.error('[FABRIC:PEER]', `[@ID:$${self.id}]`, `Received "PeerMessage" from ${packet.origin} on socket:`, message.raw); - // console.error('[FABRIC:PEER]', `[@ID:$${self.id}]`, `Packet origin:`, packet.origin); - // TODO: use packet's peer ID, not socket address - // Likely need to track connection? - self.relayFrom(packet.origin, message); - break; - case 'StartSession': - if (self.settings.verbosity >= 6) console.warn('[AUDIT]', '[FABRIC:PEER]', `[0x${self.id}]`, 'Received "StartSession" message on socket:', message.raw); - let session = null; + return this; + } - try { - session = JSON.parse(message.data.toString('utf8')); - } catch (exception) { - console.error('[FABRIC:PEER]', 'Session body could not be parsed:', exception); - } + _scheduleReconnect (target, when = 250) { + this.emit('debug', `Scheduled reconnect to ${target} in ${when} milliseconds...`); + const reconnect = setTimeout(() => { + this._connect(target); + }, when); + } - if (self.settings.verbosity >= 5) console.log('[FABRIC:PEER]', 'Proposed session:', session); + _selectBestPeerCandidate () { + const candidates = []; - // TODO: avoid using JSON in overall protocol - // TODO: validate signature - let valid = true; - // TODO: restore session identity - if (valid && session/* && session.identity */) { - if (self.settings.verbosity >= 6) console.log('[AUDIT]', 'Session is valid...'); + for (const id of Object.entries(this.peers)) { + candidates.push(id); + } - let peer = { - id: session.identity, - address: packet.origin, - advertise: `${self.pubkeyhash}@${self.public.ip}:${self.public.port}`, - status: 'unfunded' - }; + candidates.sort((a, b) => { + return (a.score > b.score) ? 1 : 0; + }); - if (self.settings.verbosity >= 5) console.log('[FABRIC:PEER]', 'Peer to register:', peer); + return candidates[0] || null; + } - // TODO: document peer registration process - self._registerPeer(peer); + _verifyNOISE (localPrivateKey, localPublicKey, remotePublicKey, done) { + // Is the message valid? + if (1 === 1) { + done(null, true); + } else { + done(null, false); + } + } - // TODO: use message type for next phase of session (i.e., NOISE) - response = Message.fromVector(['StartSession', { identity: self.id }]); - if (self.settings.verbosity >= 6) console.log('[AUDIT]', 'Will send response:', response); - } + _writeFabric (msg, stream) { + const hash = crypto.createHash('sha256').update(msg).digest('hex'); + this.messages[hash] = msg.toString('hex'); + this.commit(); + if (stream) stream.encrypt.write(msg); + } - break; - case 'StateRoot': - if (self.settings.verbosity >= 5) console.log('[AUDIT]', 'Message was a state root:', message.data); + /** + * Start the Peer. + */ + async start () { + let address = null; + this.emit('log', 'Peer starting...'); - // TODO: test protocol flow (i.e., understand StateRoot) - console.log('[AUDIT]', 'Message was a state root:', message.raw, message.data); + // Register self + this._registerActor({ name: `${this.interface}:${this.port}` }); - try { - const state = JSON.parse(message.data); - self.emit('state', state); - response = { - 'type': 'Receipt', - 'data': state - }; - } catch (E) { - console.error('[FABRIC:PEER]', 'Could not parse StateRoot:', E); - } - break; - case 'StateChange': - console.log('message was a state change:', message.data); - break; - case P2P_BASE_MESSAGE: - self._handleBasePacket(packet); - break; - case P2P_ROOT: - response = Message.fromVector([P2P_STATE_COMMITTMENT, self.state]); - self.log('type was ROOT, sending state root:', response); - self.log('type was ROOT, state was:', self.state); - break; - case P2P_INSTRUCTION: - // TODO: use Fabric.Script / Fabric.Machine - let stack = message.data.split(' '); - switch (stack[1]) { - case 'SIGN': - let signature = self.key._sign(stack[0]); - let buffer = Buffer.from(signature); - let script = [buffer.toString('hex'), 'CHECKSIG'].join(' '); - - response = Message.fromVector([P2P_INSTRUCTION, script]); - break; - default: - console.log('[PEER]', `unhandled peer instruction "${stack[1]}"`); - break; - } + if (this.settings.listen) { + this.emit('log', 'Listener starting...'); - break; - default: - console.error('[PEER]', `unhandled message type "${message.type}"`); - self.emit('error', `Unhandled message type "${message.type}"`); - break; + try { + address = await this.listen(); + this.emit('log', 'Listener started!'); + } catch (exception) { + this.emit('error', 'Could not listen:', exception); + } } - // Emit for listeners - // self.emit('message', message); - - if (relay) { - self.relayFrom(origin, message); + if (this.settings.networking) { + this.emit('warning', `Networking enabled. Connecting to peers: ${JSON.stringify(this.settings.peers)}`); + for (const candidate of this.settings.peers) { + this._connect(candidate); + } } - return response; - } - - _handleBasePacket (packet) { - let message = null; + if (this.settings.debug) this.emit('debug', `Observing state...`); try { - message = JSON.parse(packet.message.data); - } catch (E) { - return this.log('Error parsing message:', E); - } - - switch (message.type) { - case 'collections:post': - this.emit('collections:post', message.data); - break; - default: - console.log('unhandled base packet type:', message.type); - break; - } - } - - async sendToSocket (address, raw) { - if (raw instanceof Message) { - raw = raw.asRaw(); + this.observer = manager.observe(this._state.content); + } catch (exception) { + this.emit('error', `Could not observe state: ${exception}`); } - if (!this.connections[address]) { - this.emit('error', `Could not deliver message to unconnected address: ${address}`); - return false; - } + await this._startHeart(); - if (!this.connections[address].session) { - this.emit('error', `Connection does not have a Session: ${address}`); - return false; - } + if (this.settings.debug) this.emit('debug', `Peer ready! State: ${JSON.stringify(this.state, null, ' ')}`); - if (!this.connections[address].writable) { - this.emit('error', `Connection is not writable: ${address}`); - return false; - } + this.emit('ready', { + id: this.id, + address: address, + pubkey: this.key.pubkey + }); - this.emit('debug', `Writing ${raw.length} bytes to socket: \n\t${raw.toString('hex')}`); - // const signature = await this.connections[address].session._appendMessage(raw); - // self.emit('debug', `Signature: ${signature}`); + if (this.settings.debug) this.emit('debug', `Peer started!`); - try { - const result = this.connections[address].write(raw); - if (!result) { - this.emit('warning', 'Stream result false.'); + /* + const PACKET_PEER_ANNOUNCE = Message.fromVector(['P2P_PEER_ANNOUNCE', JSON.stringify({ + type: 'P2P_PEER_ANNOUNCE', + object: { + host: this._externalIP, + port: this.settings.port } - } catch (exception) { - this.emit('error', `Exception writing to $[${address}]: ${exception}`); - } + })]).signWithKey(this.key); + const announcement = PACKET_PEER_ANNOUNCE.toBuffer(); + // this.emit('debug', `Announcing peer: ${announcement.toString('utf8')}`); + this.connections[origin.name]._writeFabric(announcement, socket); + */ + + return this; } - relayFrom (origin, message) { - if (!origin) { - this.emit('error', 'Must provide an origin.'); - return false; - } + /** + * Stop the peer. + */ + async stop () { + // Alert listeners + this.emit('log', 'Peer stopping...'); + this._state.status = 'STOPPING'; - if (!message) { - this.emit('error', 'Must provide a message.'); - return false; - } + // Stop the heart + if (this._heart) clearInterval(this._heart); - if (!(message instanceof Message)) { - this.emit('error', 'Must provide a valid Fabric message.'); - return false; + this.emit('debug', 'Closing all connections...'); + for (const id in this.connections) { + this.connections[id].destroy(); } - this.emit('log', `Relaying ${message.type} from ${origin}: <${typeof message.data}> ${message.data}}`); - - let authorized = false; - - if (message.type) { - switch (message.type) { - case 'ChatMessage': - authorized = true; - break; - case 'PeerCandidate': - break; - default: - this.emit('debug', `Unhandled type for relay: ${message.type}`); - break; - } - } else { - this.emit('warning', `Unknown message structure: <${message.constructor.name} ${JSON.stringify(message, null, ' ')} />`); + const terminator = async () => { + return new Promise((resolve, reject) => { + if (!this.server.address()) return resolve(); + return this.server.close(function serverClosed (error) { + if (error) return reject(error); + resolve(); + }); + }); } - // For each known peer, send to the corresponding socket - for (const id in this.peers) { - this.emit('debug', `Is ${id} === ${origin}?`); - if (id === origin) continue; - const peer = this.peers[id]; + this.emit('debug', 'Closing network...'); + await terminator(); - // TODO: select type byte for state updates - // TODO: require `Message` type before broadcast (or, preferrably, cast as necessary) - // let msg = Message.fromVector([P2P_BASE_MESSAGE, message]); - const msg = Message.fromVector([ - message.type, - message.data - ]); + this._state.status = 'STOPPED'; + this.commit(); - const raw = msg.asRaw(); - this.emit('debug', `Preparing write (${raw.length} bytes): <${raw.constructor.name}> \n\t${raw.toString('hex')}`); + this.emit('log', 'Peer stopped!'); - if (authorized) { - try { - this.emit('debug', `Sending ${raw.length} bytes to address $[${peer.address}]: \n\t${raw.toString('hex')}`); - this.sendToSocket(peer.address, raw); - } catch (exception) { - this.emit('error', `Could not write message to connection "${peer.address}":`, exception); - } - } else { - this.emit('debug', 'Would have sent to socket:'); - this.emit('debug', `sendToSocket (${raw.length} bytes): from ${origin} to ${peer.address}: ${raw.toString('hex')})`); - } - } + return this; } - broadcast (message) { - // Coerce to Object - if (message instanceof Message) { - message = message.toObject(); - } + async _setState (value) { + if (!value) return new Error('You must provide a State to set the value to.'); + this._state.content = value; + return this.state; + } - if (typeof message !== 'string') message = JSON.stringify(message); - let hash = crypto.createHash('sha256').update(message).digest('hex'); + _disconnect (address) { + if (!this.connections[address]) return false; - // Do not relay duplicate messages - if (this.messages.has(hash)) { - if (this.settings.verbosity >= 3) console.warn('[FABRIC:PEER]', `Attempted to broadcast duplicate message ${hash} with content:`, message); - return false; - } else { - this.memory[hash] = message; - this.messages.add(hash); + // Halt any heartbeat + if (this.connections[address].heartbeat) { + clearInterval(this.connections[address].heartbeat); } - for (let id in this.peers) { - let peer = this.peers[id]; - // TODO: select type byte for state updates - // TODO: require `Message` type before broadcast (or, preferrably, cast as necessary) - // let msg = Message.fromVector([P2P_BASE_MESSAGE, message]); - let msg = Message.fromVector(['PeerMessage', message]); + // Destroy the connection + // this.connections[address].destroy(); - try { - this.sendToSocket(peer.address, msg); - } catch (exception) { - console.error('[FABRIC:PEER]', `Could not write message to connection "${peer.address}":`, exception); - } - } + // Remove connection from map + delete this.connections[address]; } - _broadcastTypedMessage (type, message) { - if (!message) message = ''; - if (typeof message !== 'string') message = JSON.stringify(message); + _maintainConnection (address) { + const peer = this; + if (!peer.connections[address]) return new Error(`Connection for address "${address}" does not exist.`); + /* peer.connections[address]._player = setInterval(function () { + peer._pingConnection.apply(peer, [ address ]); + }, 60000); */ + } - let id = crypto.createHash('sha256').update(message).digest('hex'); + _pingConnection (address) { + const ping = Message.fromVector(['Ping', `${Date.now().toString()}`]); - if (this.messages.has(id)) { - this.log('attempted to broadcast duplicate message'); - return false; - } else { - this.memory[id] = message; - this.messages.add(id); + try { + this.sendToSocket(address, ping); + } catch (exception) { + this.emit('error', `Couldn't deliver message to socket: ${exception}`); } + } - for (let id in this.peers) { - let peer = this.peers[id]; - // TODO: select type byte for state updates - let msg = Message.fromVector([type, message]); - this.sendToSocket(peer.address, msg); + _updateLiveness (address) { + // Return Error if no connection + if (!this.connections[address]) { + const error = `No connection for address: ${address}`; + this.emit('error', error); + return new Error(error); } + + // Set the _lastMessage property + this.connections[address]._lastMessage = Date.now(); + + // Make chainable + return this; + } + + _registerHandler (type, method) { + if (this.handlers[type]) return new Error(`Handler for method "${type}" is already registered.`); + this.handlers[type] = method.bind(this); + return this.handlers[type]; + } + + async _requestStateFromAllPeers () { + const message = Message.fromVector(['StateRequest']); + this.broadcast(message); } /** * Start listening for connections. - * @fires Peer#ready * @return {Peer} Chainable method. */ async listen () { - const self = this; - const promise = new Promise((resolve, reject) => { - self.server.listen(self.port, self.address, function listenComplete (error) { + return new Promise((resolve, reject) => { + this.server.listen(this.port, this.interface, (error) => { if (error) return reject(error); - const details = self.server.address(); - const address = `tcp://${details.address}:${details.port}`; + const details = this.server.address(); + const address = `${details.address}:${details.port}`; - self.emit('log', `Now listening on ${address} [!!!]`); + this.emit('log', `Now listening on tcp://${address} [!!!]`); return resolve(address); }); - }); - return promise; + this.server.on('error', (error) => { + this.emit('error', `Server socket error: ${error}`); + }); + }); } } diff --git a/types/queue.js b/types/queue.js index 1800f8d48..88ff1f0c8 100644 --- a/types/queue.js +++ b/types/queue.js @@ -8,6 +8,7 @@ class Queue extends Actor { super(settings); this.settings = merge({ + redis: null, workers: 1 }, settings); @@ -25,6 +26,10 @@ class Queue extends Actor { await this._registerMethod('verify', async function (...params) { }); + + if (this.settings.redis) { + this._state.redis = this.settings.redis; + } } async _registerMethod (name, contract) { diff --git a/types/reader.js b/types/reader.js index 620dc9ed7..f6efa1292 100644 --- a/types/reader.js +++ b/types/reader.js @@ -90,6 +90,7 @@ class Reader extends EventEmitter { } _readFabricFrame () { + // Ensure we have at least a full message header if (this._bufferedBytes < HEADER_SIZE) return; // Read up to HEADER_SIZE bytes @@ -100,10 +101,11 @@ class Reader extends EventEmitter { parts.push(header.slice(0, 4)); // magic parts.push(header.slice(4, 8)); // version parts.push(header.slice(8, 40)); // parent - parts.push(header.slice(40, 44)); // type - parts.push(header.slice(44, 48)); // payload size - parts.push(header.slice(48, 80)); // hash - parts.push(header.slice(80, 144)); // signature + parts.push(header.slice(40, 72)); // author + parts.push(header.slice(72, 76)); // type + parts.push(header.slice(76, 80)); // payload size + parts.push(header.slice(80, 112)); // hash + parts.push(header.slice(112, HEADER_SIZE)); // signature const map = parts.map((x) => Buffer.from(x, 'hex')); const elements = map.map((x) => parseInt(x.toString('hex'), 16)); @@ -112,10 +114,11 @@ class Reader extends EventEmitter { const magic = elements[0]; const version = elements[1]; const parent = elements[2]; - const type = elements[3]; - const size = elements[4]; - const signature = elements[5]; - const hash = elements[6]; + const author = elements[3]; + const type = elements[4]; + const size = elements[5]; + const signature = elements[6]; + const hash = elements[7]; if (magic !== MAGIC_BYTES) { throw new Error(`Header not magic: ${magic} !== ${MAGIC_BYTES}`); @@ -132,8 +135,12 @@ class Reader extends EventEmitter { const proposal = { magic, version, + parent, + author, type, size, + hash, + signature, data }; diff --git a/types/remote.js b/types/remote.js index cb082da14..ab566d0c4 100644 --- a/types/remote.js +++ b/types/remote.js @@ -41,11 +41,13 @@ class Remote extends Actor { entropy: Math.random(), macaroon: null, secure: true, + state: { + status: 'PAUSED' + }, host: 'hub.fabric.pub', port: 443 }, config); - this.host = this.settings.host || this.settings.authority; this.secure = this.settings.secure; this.socket = null; @@ -66,6 +68,22 @@ class Remote extends Actor { return this; } + set host (value) { + if (typeof value !== 'string') throw new Error('Host must be a string.'); + this.settings.host = value; + return this.settings.host; + } + + get host () { + return this.settings.host; + } + + set port (value) { + if (!Number.isInteger(value)) throw new Error('Port must be an integer.'); + this.settings.port = value; + return this.settings.port; + } + get port () { return this.settings.port; } @@ -312,6 +330,7 @@ class Remote extends Actor { result = await response.json(); } catch (E) { console.error('[REMOTE]', 'Could not parse JSON:', E); + result = await response.text(); } break; default: @@ -323,9 +342,9 @@ class Remote extends Actor { if (this.settings.verbosity >= 4) console.warn('[FABRIC:REMOTE]', 'Unmanaged HTTP status code:', response.status); try { - result = response.json(); + result = await response.json(); } catch (exception) { - result = response.text(); + result = await response.text(); } } break; @@ -436,6 +455,7 @@ class Remote extends Actor { } async _SEARCH (key, params) { + if (this.settings.debug) console.debug('[FABRIC:CORE]', '_SEARCH:', key, params); return this.request('search', key, params); } } diff --git a/types/router.js b/types/router.js index 31eb2b43e..efd0ecadb 100644 --- a/types/router.js +++ b/types/router.js @@ -6,15 +6,7 @@ const Scribe = require('./scribe'); // Current code is specific to @fabric/doorman — should be a general- // purpose Router, not for strings and triggers in chat messages. -/** - * Process incoming messages. - * @extends Scribe - */ class Router extends Scribe { - /** - * Maintains a list of triggers ("commands") and their behaviors. - * @param {Object} map Map of command names => behaviors. - */ constructor (config) { super(config); diff --git a/types/scribe.js b/types/scribe.js index b66f53f3e..d91580be3 100644 --- a/types/scribe.js +++ b/types/scribe.js @@ -5,17 +5,7 @@ const crypto = require('crypto'); // Fabric Components const State = require('./state'); -/** - * Simple tag-based recordkeeper. - * @extends State - * @property {Object} config Current configuration. - */ class Scribe extends State { - /** - * The "Scribe" is a simple tag-based recordkeeper. - * @param {Object} config General configuration object. - * @param {Boolean} config.verbose Should the Scribe be noisy? - */ constructor (config = {}) { super(config); diff --git a/types/service.js b/types/service.js index 7ab57467f..9ba5e1ec5 100644 --- a/types/service.js +++ b/types/service.js @@ -18,12 +18,13 @@ const manager = require('fast-json-patch'); // Fabric Types const Actor = require('./actor'); const Collection = require('./collection'); -const Identity = require('./identity'); -const Resource = require('./resource'); const Entity = require('./entity'); +const Filesystem = require('./filesystem'); const Hash256 = require('./hash256'); +const Identity = require('./identity'); const Key = require('./key'); const Message = require('./message'); +const Resource = require('./resource'); const Store = require('./store'); /** @@ -41,18 +42,22 @@ const Store = require('./store'); class Service extends Actor { /** * Create an instance of a Service. - * @param {Object} settings Configuration for this service. - * @param {Boolean} [settings.networking=true] Whether or not to connect to the network. - * @param {Object} [settings.@data] Internal data to assign. + * @param {Object} [settings] Configuration for this service. + * @param {Boolean} [settings.networking=true] Whether or not to connect to the network. + * @param {Object} [settings.frequency] Interval frequency in hertz. + * @param {Object} [settings.state] Initial state to assign. */ constructor (settings = {}) { // Initialize Scribe, our logging tool super(settings); + this.name = this.constructor.name; + // Configure (with defaults) this.settings = merge({ name: 'Service', path: './stores/service', + frequency: 0.0133333334, // Hz networking: true, persistent: false, constraints: { @@ -61,6 +66,10 @@ class Service extends Actor { max: 67108864 } }, + fs: { + path: `./stores/fabric-service-${this.name}` + }, + key: null, state: { ...super.state, actors: {}, // TODO: schema @@ -78,13 +87,14 @@ class Service extends Actor { messages: {}, members: {} } */ - }, this.settings, settings); + }, settings); // Reserve a place for ourselves this.agent = null; this.actor = null; this.name = this.settings.name; + this.aliases = {}; this.collections = {}; this.definitions = {}; this.resources = {}; @@ -102,15 +112,18 @@ class Service extends Actor { // Error: Not implemented yet this.key = new Key(this.settings.key); this.identity = new Identity(this.settings.key); + this.fs = new Filesystem({ ...this.settings.fs, key: this.settings.key }); if (this.settings.persistent) { try { this.store = new Store(this.settings); } catch (E) { - console.error('Error:', E); + console.error('Store Error:', E); } } + this._clock = 0; + // set local state to whatever configuration supplies... /* this.state = Object.assign({ messages: {} // always define a list of messages for Fabric services @@ -127,6 +140,24 @@ class Service extends Actor { // Keeps track of changes this.observer = null; + this.cache = { + _data: new Map(), + _ttl: new Map(), + get: async (key) => { + const now = Date.now(); + const ttl = this.cache._ttl.get(key); + if (ttl && ttl < now) { + this.cache._data.delete(key); + this.cache._ttl.delete(key); + return null; + } + return this.cache._data.get(key); + }, + set: async (key, value, ttl = 60000) => { + this.cache._data.set(key, value); + this.cache._ttl.set(key, Date.now() + ttl); + } + }; /* if (this.settings.networking) { this.swarm = new Swarm(this.settings); @@ -151,13 +182,17 @@ class Service extends Actor { } get clock () { - return parseInt(this._state.clock); + return parseInt(this._clock); } get heartbeat () { return this._heart; } + get interval () { + return 1000 / this.settings.frequency; + } + get status () { return this._state.status; } @@ -297,7 +332,7 @@ class Service extends Actor { /** * Retrieve a key from the {@link State}. * @param {Path} path Key to retrieve. - * @returns {Mixed} + * @returns {Mixed} Returns the target value if found, otherwise null. */ get (path = '') { let result = null; @@ -320,6 +355,12 @@ class Service extends Actor { return result; } + // Synchronize with any external sources + sync () { + if (!this._sources) this._sources = []; + return this; + } + /** * Explicitly trust all events from a known source. * @param {EventEmitter} source Emitter of events. @@ -381,13 +422,13 @@ class Service extends Actor { self.emit('debug', `[FABRIC:SERVICE] Source "${name}" emitted channel: ${JSON.stringify(channel, null, ' ')}`); }), _handleCommit: source.on('commit', async function (commit) { - self.emit('log', `[FABRIC:SERVICE] Source "${name}" committed: ${JSON.stringify(commit, null, ' ')}`); + self.emit('debug', `[FABRIC:SERVICE] Source "${name}" committed: ${JSON.stringify(commit, null, ' ')}`); }), _handleError: source.on('error', async function _handleTrustedError (error) { self.emit('debug', `[FABRIC:SERVICE] Source "${name}" emitted error: ${error}`); }), _handleLog: source.on('log', async function _handleTrustedLog (log) { - self.emit('log', `[FABRIC:SERVICE] Source "${name}" emitted log: ${log}`); + if (self.settings.debug) self.emit('log', `[FABRIC:SERVICE] Source "${name}" emitted log: ${log}`); }), _handleMessage: source.on('message', async function (message) { self.emit('debug', `[FABRIC:SERVICE] Source "${name}" emitted message: ${JSON.stringify(message.toObject ? message.toObject() : message, null, ' ')}`); @@ -405,7 +446,7 @@ class Service extends Actor { self.alert(`[FABRIC:SERVICE] New ${name} chaintip: ${hash}`); }), _handleWarning: source.on('warning', async function _handleTrustedWarning (warning) { - self.emit('warning', `[FABRIC:SERVICE] Source "${name}" emitted warning: ${warning}`); + if (self.settings?.verbosity >= 2) self.emit('warning', `[FABRIC:SERVICE] Source "${name}" emitted warning: ${warning}`); }) }; } @@ -477,10 +518,21 @@ class Service extends Actor { return true; } + /** + * Bind a method to an event, with current state as the immutable context. + * @param {String} event Name of the event upon which to execute `method` as a function. + * @param {Function} method Function to execute when named {@link Event} `event` is encountered. + * @returns {EventEmitter} Instance of EventEmitter. + */ + when (event, method) { + return this.on(event, method.call(this.state)); + } + _defineResource (name, definition) { const resource = Object.assign({ name }, definition); this.resources[name] = new Resource(resource); this.emit('resource', this.resources[name]); + return this.resources[name]; } _handleTrustedDebug (message) { @@ -620,7 +672,7 @@ class Service extends Actor { try { this.observer = manager.observe(this._state.content); } catch (exception) { - console.warn('Could not observe state:', this._state.content, exception); + console.trace('Could not observe state:', this._state.content, exception); } // Set a heartbeat @@ -880,41 +932,12 @@ class Service extends Actor { commit () { // this.emit('debug', `[FABRIC:SERVICE] Committing ${OP_TRACE()}`); - - const self = this; - const ops = []; - - // assemble all necessary info, emit Snapshot regardless of storage status - try { - ops.push({ type: 'put', key: 'snapshot', value: self.state }); - - /* this.emit('debug', `Commit Template: ${JSON.stringify({ - '@data': self.state, - '@from': 'COMMIT', - '@type': 'Snapshot' - }, null, ' ')}`); */ - } catch (E) { - console.error('Error saving state:', self.state); - console.error('Could not commit to state:', E); - } - - if (this.settings.persistent) { - // TODO: add robust + convenient database opener - this.store.batch(ops, function shareChanges () { - // TODO: notify status? - }).catch((exception) => { - self.emit('error', `Could not write to store: ${exception}`); - }).then((output) => { - self.emit('commit', { output }); - }); - } - - if (PATCHES_ENABLED && self.observer) { + if (PATCHES_ENABLED && this.observer) { try { - const patches = manager.generate(self.observer); + const patches = manager.generate(this.observer); if (patches.length) { this.history.push(patches); - self.emit('patches', patches); + this.emit('patches', patches); } } catch (E) { console.error('Could not generate patches:', E); @@ -923,10 +946,11 @@ class Service extends Actor { const commit = new Actor({ type: 'Commit', - state: self.state + state: this.state }); this.emit('commit', { ...commit.toObject(), id: commit.id }); + // this.emit('state', this.state); return commit.id; } @@ -1005,6 +1029,7 @@ class Service extends Actor { id: entity.id, members: [] }, channel); + return channel; } const target = pointer.escape(channel.id); @@ -1069,14 +1094,15 @@ class Service extends Actor { try { // TODO: allow configurable validators - result = manager.applyPatch(this.state, changes, function isValid () { + this._state.content = manager.applyPatch(this.state, changes, function isValid () { + // TODO: invalidate changes without appropriate capability token return true; }, true /* mutate doc (1st param) */); } catch (exception) { console.error('Could not apply changes:', changes, exception); } - await this.commit(); + this.commit(); return result; } @@ -1156,11 +1182,13 @@ class Service extends Actor { async _startAllServices () { if (!this.services) return this.emit('warning', 'Tried to start subservices, but none existed.'); + this.emit('debug', `Service entries: ${Object.keys(this.services)}`); + // Start all Services for (const [name, service] of Object.entries(this.services)) { // TODO: re-evaluate inclusion on Service itself if (this.settings.services && this.settings.services.includes(name)) { - this.emit('debug', `Starting service "${name}" (with trust)`); + this.emit('debug', `Starting service "${name}" (with trust)...`); // TODO: evaluate @fabric/core/types/store // TODO: isomorphic @fabric/core/types/store // await this.services[name]._bindStore(this.store); @@ -1178,7 +1206,9 @@ class Service extends Actor { } async _startHeart () { + if (this._heart) clearInterval(this._heart); this._heart = setInterval(this.beat.bind(this), this.settings.interval); + return this; } } diff --git a/types/session.js b/types/session.js index 097a313cd..e4486ae8f 100644 --- a/types/session.js +++ b/types/session.js @@ -34,7 +34,7 @@ class Session extends Entity { }, settings); // Session Key - this.key = this._getOddKey(); + this.key = settings.key || this._getOddKey(); this.derived = null; // Internal State diff --git a/types/signer.js b/types/signer.js deleted file mode 100644 index 97979d966..000000000 --- a/types/signer.js +++ /dev/null @@ -1,176 +0,0 @@ -'use strict'; - -// Dependencies -const crypto = require('crypto'); -const stream = require('stream'); -const schnorr = require('bip-schnorr'); - -// Fabric Types -const Actor = require('./actor'); -const Hash256 = require('./hash256'); -const Key = require('./key'); - -/** - * Generic Fabric Signer. - * @access protected - * @emits message Fabric {@link Message} objects. - * @extends {Actor} - * @property {String} id Unique identifier for this Signer (id === SHA256(preimage)). - * @property {String} preimage Input hash for the `id` property (preimage === SHA256(SignerState)). - */ -class Signer extends Actor { - /** - * Creates an {@link Signer}, which emits messages for other - * Signers to subscribe to. You can supply certain parameters - * for the actor, including key material [!!!] — be mindful of - * what you share with others! - * @param {Object} [actor] Object to use as the actor. - * @param {String} [actor.seed] BIP24 Mnemonic to use as a seed phrase. - * @param {Buffer} [actor.public] Public key. - * @param {Buffer} [actor.private] Private key. - * @returns {Signer} Instance of the Signer. Call {@link Signer#sign} to emit a {@link Signature}. - */ - constructor (actor = {}) { - super(actor); - - this.log = []; - this.signature = null; - - // Settings - this.settings = { - state: {} - }; - - // TODO: fix bcoin in React / WebPack - this.key = new Key({ - seed: actor.seed, - public: actor.public || actor.pubkey, - private: actor.private, - xprv: actor.xprv, - xpub: actor.xpub - }); - - // Indicate Risk - this.private = !!(this.key.seed || this.key.private); - this.stream = new stream.Transform(this._transformer.bind(this)); - this.value = this._readObject(actor); // TODO: use Buffer? - - // Internal State - this._state = { - '@type': 'Signer', - '@data': this.value, - status: 'PAUSED', - content: this.value || {} - }; - - // Chainable - return this; - } - - static chunksForBuffer (input = Buffer.alloc(32), size = 32) { - const chunks = []; - for (let i = 0; i < input.length; i += size) { - const chunk = input.slice(i, i + size); - chunks.push(chunk); - } - - return chunks; - } - - static signableForBuffer (input = Buffer.alloc(32)) { - // TODO: use pubkey - const challenge = crypto.randomBytes(32); - const message_hash = Hash256.digest(input.toString('hex')); - const message = [ - `--- BEGIN META ---`, - `message_challenge: ${challenge.toString('hex')}`, - `message_hash: ${message_hash}`, - `message_scriptsig: 00${message_hash}`, - `--- END META ---`, - `--- BEGIN FABRIC MESSAGE ---`, - Signer.chunksForBuffer(input.toString('hex'), 80).join('\n'), - `--- END FABRIC MESSAGE ---` - ].join('\n'); - - return message; - } - - get pubkey () { - // TODO: encode pubkey correctly for verification - const x = this.key.keypair.getPublic().getX(); - return schnorr.convert.intToBuffer(x).toString('hex'); - } - - /** - * Signs some data. - * @returns {Signer} - */ - sign (data = this.toBuffer()) { - if (!(data instanceof Buffer)) { - switch (data.constructor.name) { - default: - this.emit('warning', `unhandled data to sign: ${data.constructor.name} ${JSON.stringify(data)}`); - break; - } - } - - this._lastSignature = new Actor({ message: data, signature: this.signature }); - - // Hash & sign - // TODO: check with bip-schnorr on behavior of signing > 32 byte messages - this._preimage = Buffer.from(Hash256.digest(data), 'hex'); - this.signature = schnorr.sign(this.key.keypair.getPrivate('hex'), this._preimage); - - this.emit('signature', { - content: data, - preimage: this._preimage, - pubkey: this._pubkey, - signature: this.signature.toString('hex') - }); - - return this.signature.toString('hex'); - } - - start () { - this._state.content.status = 'STARTING'; - // TODO: unpause input stream here - this._state.status = 'STARTED'; - this.commit(); - return this; - } - - stop () { - this._state.status = 'STOPPING'; - this._state.status = 'STOPPED'; - this.commit(); - return this; - } - - toSpend () { - - } - - toSign () { - - } - - verify (pubkey, message, signature) { - if (!(pubkey instanceof Buffer)) pubkey = Buffer.from(pubkey, 'hex'); - if (!(message instanceof Buffer)) message = Buffer.from(message, 'hex'); - if (!(signature instanceof Buffer)) signature = Buffer.from(signature, 'hex'); - - try { - schnorr.verify(pubkey, message, signature); - return true; - } catch (exception) { - console.error(exception); - return false; - } - } - - async _transformer (chunk, controller) { - - } -} - -module.exports = Signer; diff --git a/types/state.js b/types/state.js index ceda3f25d..09dc2084b 100644 --- a/types/state.js +++ b/types/state.js @@ -466,11 +466,6 @@ When you're ready to continue, visit the following URL: https://dev.fabric.pub/W this['@commit'] = this.commit(); return this['@output'].toString('utf8'); - - switch (this['@type']) { - default: - return this['@output'].toString('utf8'); - } } } diff --git a/types/store.js b/types/store.js index d931a8c89..ec87fcf93 100644 --- a/types/store.js +++ b/types/store.js @@ -1,7 +1,7 @@ 'use strict'; // Dependencies -const level = require('level'); +const { Level } = require('level'); const crypto = require('crypto'); const pointer = require('json-pointer'); @@ -390,7 +390,7 @@ class Store extends Actor { // if (this.db) return this; try { - this.db = level(this.settings.path); + this.db = new Level(this.settings.path); this.trust(this.db); this.status = 'opened'; await this.commit(); @@ -428,13 +428,12 @@ class Store extends Actor { let store = this; let name = `/sources/${store.id}`; - source.on('put', function (key, value) { - // store.log('[TRUST:SOURCE]', source.constructor.name, 'emitted a put event', name, key, value.constructor.name, value); - if (store.settings.verbosity >= 5) console.log('[TRUST:SOURCE]', source.constructor.name, 'emitted a put event', name, key, value.constructor.name, value); + source.on('write', function (key, value) { + if (store.settings.verbosity >= 5) console.log('[TRUST:SOURCE]', source.constructor.name, 'emitted a write event', name, key, value.constructor.name, value); let id = pointer.escape(key); let router = store.sha256(id); - let state = new State(value); + let state = new Actor(value); pointer.set(store['@entity']['@data'], `${name}`, value); pointer.set(store['@entity']['@data'], `/states/${state.id}`, value); diff --git a/types/swap.js b/types/swap.js index 519f1110d..126272d20 100644 --- a/types/swap.js +++ b/types/swap.js @@ -8,17 +8,7 @@ const bcoin = require('bcoin'); // Native Dependencies const crypto = require('crypto'); -/** - * The {@link Swap} contract executes a set of transactions on two distinct - * {@link Chain} components, utilizing a secret-reveal mechanism to atomically - * execute either the full set or none. - * @type {Object} - */ class Swap { - /** - * Atomically execute a set of transactions across two {@link Chain} components. - * @param {Object} [settings={}] Configuration for the swap. - */ constructor (settings = {}) { this.settings = Object.assign({ chain: 'bitcoin:regtest' diff --git a/types/token.js b/types/token.js index 4ed555a84..85bfad69d 100644 --- a/types/token.js +++ b/types/token.js @@ -1,34 +1,150 @@ 'use strict'; -const merge = require('lodash.merge'); -const Actor = require('./actor'); -const Label = require('./label'); +// Dependencies +const bitcoin = require('bitcoinjs-lib'); +const schnorr = require('bip-schnorr'); +// Fabric Types +const Key = require('./key'); + +/** + * Implements a capability-based security token. + */ class Token { + /** + * Create a new Fabric Token. + * @param {Object} [settings] Configuration. + * @returns {Token} The token instance. + */ constructor (settings = {}) { - // Settings - this.settings = merge({ - name: 'AUTH_GROUP_GENERIC' + // TODO: determine rounding preference (secwise) + this.created = Date.now(); + this.settings = Object.assign({ + capability: 'OP_0', + issuer: null, + subject: null, + state: { + status: 'READY' + } }, settings); - // Internal Properties - this.actor = new Actor(this.settings); - this.label = new Label(this.settings.name); + // Capability + this.capability = this.settings.capability; + this.ephemera = new Key(); + + // Trust Chain + this.issuer = this.settings.issuer ? this.settings.issuer : this.ephemera; + this.subject = this.settings.subject ? this.settings.subject : this.ephemera.keypair.getPublic(true).encodeCompressed('hex'); + + // ECDSA Signature + this.signature = null; + + // State + this._state = { + content: this.settings.state + }; - // Chainable return this; } - get id () { - return this.actor.id; + get state () { + return JSON.parse(JSON.stringify(this._state.content)); + } + + static base64UrlEncode (input) { + const base64 = Buffer.from(input, 'utf8').toString('base64'); + return base64.replace('+', '-').replace('/', '_').replace(/=+$/, ''); } - get label () { - return this.label._id; + static base64UrlDecode (input) { + input = input.replace(/-/g, '+').replace(/_/g, '/'); + + while (input.length % 4) { + input += '='; + } + + return Buffer.from(input, 'base64').toString(); + } + + static fromString (input) { + const parts = input.split('.'); + const headers = parts[0]; + const payload = parts[1]; + const signature = parts[2]; + const inner = Token.base64UrlDecode(payload); + + return new Token({ + capability: inner.cap, + issuer: inner.iss, + subject: inner.sub, + state: inner.state, + signature: signature + }); } toString () { - return this.label; + // TODO: determine rounding preference (secwise) + const utime = Math.floor(this.created / 1000); + const issuer = this.issuer.keypair.getPublic(true).encodeCompressed('hex'); + const header = { + alg: 'ES256K', + iss: issuer, + typ: 'JWT' + }; + + const payload = { + cap: this.capability, + iat: utime, + iss: issuer, + sub: this.subject, + state: this.state + }; + + // TODO: reconcile with JWT spec + // alternatively, since we're already breaking spec, + // we can diverge again here. + // Secret: HS256 + const secret = 'ffff'; + + // Encodings + const encodedHeader = Token.base64UrlEncode(JSON.stringify(header)); + const encodedPayload = Token.base64UrlEncode(JSON.stringify(payload)); + const signature = bitcoin.crypto.sha256( + Buffer.from(`${encodedHeader}.${encodedPayload}.${secret}`) + ); + + return [ + encodedHeader, + encodedPayload, + Token.base64UrlEncode(signature.toString('hex')) + ].join('.'); + } + + sign () { + // Sign the capability using the private key + const hash = bitcoin.crypto.sha256(this.capability); + this.signature = schnorr.sign(this.issuer.privateKey, hash); + } + + verify () { + // Verify the signature using the public key + const hash = bitcoin.crypto.sha256(this.capability); + return schnorr.verify(this.issuer.publicKey, hash, this.signature); + } + + add (other) { + const combinedCapability = [this.capability, other.capability].join(' '); + const combinedToken = new Token({ + capability: combinedCapability, + issuer: this.issuer.publicKey + }); + + /* combinedToken.signature = schnorr.combine([ + this.signature, + other.signature + ]); */ + + return combinedToken; } } diff --git a/types/transition.js b/types/transition.js index 0c833c5bd..21eb26f75 100644 --- a/types/transition.js +++ b/types/transition.js @@ -9,15 +9,7 @@ const EncryptedPromise = require('./promise'); const Entity = require('./entity'); const Witness = require('./witness'); -/** - * The {@link Transition} type reflects a change from one finite - * {@link State} to another. - */ class Transition extends Entity { - /** - * - * @param {Object} settings Configuration for the transition object. - */ constructor (settings = {}) { super(settings); diff --git a/types/wallet.js b/types/wallet.js index 357843154..bf67b2cba 100644 --- a/types/wallet.js +++ b/types/wallet.js @@ -4,7 +4,7 @@ const BN = require('bn.js'); const EC = require('elliptic').ec; const merge = require('lodash.merge'); -const payments = require('bitcoinjs-lib/src/payments'); +const networks = require('bitcoinjs-lib/src/networks'); // Mnemonics const ecc = require('tiny-secp256k1'); @@ -44,14 +44,13 @@ class Wallet extends Service { this.marshall = { agents: [], collections: { - transactions: null, // not yet loaded, seek for Buffer, - orders: null + transactions: null } }; this.settings = merge({ name: 'primary', - network: 'regtest', + network: 'mainnet', language: 'english', locktime: 144, decimals: 8, @@ -59,16 +58,15 @@ class Wallet extends Service { verbosity: 2, witness: true, key: null, - version: 1 + version: 1, + addressIndex: 0, + gapLimit: 20 }, settings); - // bcoin.set(this.settings.network); + // Get network configuration + this.network = networks[this.settings.network] || networks.mainnet; this.database = null; - /* this.database = new WalletDB({ - network: 'regtest' - }); */ - this.account = null; this.manager = null; this.wallet = null; @@ -76,10 +74,13 @@ class Wallet extends Service { this.ring = null; this.seed = null; - // TODO: enable wordlist translations - // this.words = Mnemonic.getWordlist(this.settings.language).words; - this.mnemonic = null; - this.index = 0; + // Initialize key management + this.key = new Key(this.settings.key); + this.seed = this.key.seed; + + this.wallet = { + keypair: this.key.keypair + }; // Storage this.accounts = new Collection(); @@ -97,12 +98,6 @@ class Wallet extends Service { } }); - // Internals - this.ec = new EC('secp256k1'); - this.key = new Key(this.settings.key); - this.entity = new Actor(this.settings); - // this.consensus = new Consensus(); - // Internal State this._state = merge(this._state, { actors: {}, @@ -113,35 +108,26 @@ class Wallet extends Service { }, content: { balances: { - spendable: 0 + spendable: 0, + locked: 0 }, keys: {}, transactions: {}, utxos: [] }, labels: [], - space: {}, // tracks addresses in shard + space: {}, keys: {}, services: {}, status: 'PAUSED', transactions: {}, orders: {}, - outputs: {} + outputs: {}, + addressIndex: 0, + addresses: {}, + lastUsedIndex: -1 }); - // Cleanup log output - // TODO: remove these - Object.defineProperty(this, 'database', { enumerable: false }); - Object.defineProperty(this, 'accounts', { enumerable: false }); - Object.defineProperty(this, 'addresses', { enumerable: false }); - Object.defineProperty(this, 'utxos', { enumerable: false }); - Object.defineProperty(this, 'keys', { enumerable: false }); - Object.defineProperty(this, 'outputs', { enumerable: false }); - Object.defineProperty(this, 'secrets', { enumerable: false }); - Object.defineProperty(this, 'swarm', { enumerable: false }); - Object.defineProperty(this, 'transactions', { enumerable: false }); - Object.defineProperty(this, 'wallet', { enumerable: false }); - return this; } @@ -153,6 +139,14 @@ class Wallet extends Service { return this.get('/orders'); } + get xprv () { + return this.key.xprv; + } + + get xpub () { + return this.key.xpub; + } + get version () { return this.settings.version; } @@ -163,14 +157,14 @@ class Wallet extends Service { * @returns {FabricSeed} The seed object. */ static createSeed (passphrase = '') { - const mnemonic = bip39.generateMnemonic(256); - const interim = bip39.mnemonicToSeedSync(mnemonic, passphrase); - const master = bip32.fromSeed(interim); - + const mnemonic = bip39.generateMnemonic(); + const seed = bip39.mnemonicToSeedSync(mnemonic); + const root = bip32.fromSeed(seed); return { - phrase: mnemonic.toString(), - master: master.privateKey.toString('hex'), - xprv: master.toBase58() + phrase: mnemonic, + master: root.privateKey.toString('hex'), + xprv: root.toBase58(), + xpub: root.neutered().toBase58() }; } @@ -182,13 +176,23 @@ class Wallet extends Service { static fromSeed (seed) { return new Wallet({ key: { - seed: seed.phrase + seed: seed.phrase, + passphrase: '' } }); } derive (path = `m/7777'/7777'/0'/0/0`) { - return this.key.master.derivePath(path); + const derived = this.key.derive(path); + return { + privateKey: derived.private, + publicKey: derived.public, + chainCode: derived.chainCode, + depth: derived.depth, + index: derived.index, + parentFingerprint: derived.parentFingerprint, + fingerprint: derived.fingerprint + }; } export () { @@ -222,61 +226,16 @@ class Wallet extends Service { }; } - /** - * Import a key to the wallet. - * @param {Object} keypair Keypair. - * @param {Buffer} keypair.public Public key. - * @param {Buffer} [keypair.private] Private key. - * @returns {Wallet} Instance of the Wallet. - */ - loadKey (keypair, labels = []) { - if (!keypair) throw new Error('You must provide a keypair.'); - if (!keypair.public) throw new Error('The keypair must have a "public" property.'); - if (!(keypair.public instanceof Buffer)) throw new Error('The "public" property must be of type Buffer.'); - - const id = { public: keypair.public.toString('hex') }; - const actor = new Actor(id); - - // Addresses - // P2PKH: Pay to Public Key Hash - const p2pkh = payments.p2pkh({ - pubkey: keypair.public - }); - - // P2WPKH: Pay to Witness Public Key Hash - const p2wpkh = payments.p2wpkh({ - pubkey: keypair.public - }); - - // P2TR: Pay to Tap Root - // const p2t2 = ... - - // TODO: new Key() here, then use key.export() - const key = { - addresses: { - p2pkh: p2pkh.address, - p2wpkh: p2wpkh.address - }, - labels: labels.concat(['p2pkh', 'p2wpkh']), - private: (keypair.private) ? keypair.private.toString('hex') : undefined, - public: keypair.public.toString('hex') - }; - - this._state.content.keys[actor.id] = key; - this._state.labels = this._state.labels.concat(key.labels); - - this.commit(); - - return this; - } - loadTransaction (transaction, labels = []) { if (!transaction) throw new Error('You must provide a transaction.'); if (!transaction.id) throw new Error('The transaction must have a "id" property.'); const actor = new Actor(transaction); + const transactionObject = actor.toObject(); - this._state.content.transactions[transaction.id] = actor.toObject(); + // Store in both places for backward compatibility + this._state.content.transactions[transaction.id] = transactionObject; + this.transactions.set(`/${transaction.id}`, transactionObject); if (transaction.spendable) { this._state.content.utxos.push({ @@ -297,7 +256,6 @@ class Wallet extends Service { */ start () { this.status = 'STARTING'; - this._load(); this.status = 'STARTED'; } @@ -334,34 +292,6 @@ class Wallet extends Service { } } - /** - * Initialize the wallet, including keys and addresses. - * @param {Object} settings Settings to load. - */ - _load (settings = {}) { - if (this.wallet) return this; - - this.keypair = this.ec.keyFromPrivate(this.key.master.privateKey); - this.wallet = { - keypair: this.keypair - }; - - this.loadKey({ - private: this.key.master.privateKey, - public: this.key.master.publicKey - }); - - /* for (let i = 0; i < 20; i++) { - const account = this.derive(`m/44'/0'/0'/0/${i}`); - this.loadKey({ - private: account.privateKey.toString('hex'), - public: account.publicKey.toString('hex') - }); - } */ - - return this; - } - async _processServiceMessage (msg) { switch (msg['@type']) { case 'BitcoinBlock': @@ -448,54 +378,6 @@ class Wallet extends Service { return null; } - async _createMultisigAddress (m, n, keys) { - let result = null; - - // Check for required fields - if (!m) throw new Error('Parameter 0 required: m'); - if (!n) throw new Error('Parameter 1 required: n'); - if (!keys || !keys.length) throw new Error('Parameter 2 required: keys'); - - try { - // Compose the address - const pubkeys = keys.map(key => Buffer.from(key, 'hex')); - const payment = payments.p2wsh({ - redeem: payments.p2ms({ m, pubkeys }) - }); - - // Assign to output - result = payment.address; - } catch (exception) { - console.error('[FABRIC:WALLET]', 'Could not create multisig address:', exception); - } - - return result; - } - - async _spendToAddress (amount, address) { - const mtx = new MTX(); - const change = await this.wallet.receiveAddress(); - const coins = await this.wallet.getCoins(); - - this.emit('log', `Amount to send: ${amount}`); - - mtx.addOutput({ - address: recipient, - value: parseInt(amount) - }); - - await mtx.fund(coins, { - rate: 10, - changeAddress: change - }); - - const sigs = mtx.sign(this.ring); - const tx = mtx.toTX(); - const valid = tx.check(mtx.view); - - return tx; - } - async _getUnspentOutput (amount) { if (!this._state.utxos.length) throw new Error('No available funds.'); // TODO: use coin selection @@ -523,7 +405,7 @@ class Wallet extends Service { /** * Returns a bech32 address for the provided {@link Script}. - * @param {Script} script + * @param {Script} script */ getAddressForScript (script) { // TODO: use Fabric.Script @@ -534,70 +416,13 @@ class Wallet extends Service { /** * Generate a {@link BitcoinAddress} for the supplied {@link BitcoinScript}. - * @param {BitcoinScript} redeemScript + * @param {BitcoinScript} redeemScript */ getAddressFromRedeemScript (redeemScript) { if (!redeemScript) return null; return Address.fromScripthash(redeemScript.hash160()); } - /** - * Create a priced order. - * @param {Object} order - * @param {Object} order.asset - * @param {Object} order.amount - */ - async createPricedOrder (order) { - if (!order.asset) throw new Error('Order parameter "asset" is required.'); - if (!order.amount) throw new Error('Order parameter "amount" is required.'); - - let leftover = order.amount % (10 * this.settings.decimals); - let parts = order.amount / (10 * this.settings.decimals); - - let partials = []; - // TODO: remove short-circuit - let cb = await this._generateFakeCoinbase(order.amount); - let mtx = new MTX(); - let script = new Script(); - - let secret = await this.generateSecret(); - let image = Buffer.from(secret.hash); - - console.log('secret generated:', secret); - console.log('image of secret:', image); - - let refund = await this.ring.getPublicKey(); - console.log('refund:', refund); - - script.pushSym('OP_IF'); - script.pushSym('OP_SHA256'); - script.pushData(image); - script.pushSym('OP_EQUALVERIFY'); - script.pushData(order.counterparty); - script.pushSym('OP_ELSE'); - script.pushInt(this.settings.locktime); - script.pushSym('OP_CHECKSEQUENCEVERIFY'); - script.pushSym('OP_DROP'); - script.pushData(refund); - script.pushSym('OP_ENDIF'); - script.pushSym('OP_CHECKSIG'); - script.compile(); - - // TODO: complete order construction - for (let i = 0; i < parts; i++) { - // TODO: should be split parts - partials.push(script); - } - - let entity = new Actor({ - comment: 'List of transactions to validate.', - orders: partials, - transactions: partials - }); - - return entity; - } - async createHTLC (contract) { // if (!contract.asset) throw new Error('Contract parameter "asset" is required.'); if (!contract.amount) throw new Error('Contract parameter "amount" is required.'); @@ -711,68 +536,6 @@ class Wallet extends Service { }; } - async generateOrderRootTo (pubkey, amount) { - if (!pubkey) throw new Error(`Parameter "pubkey" is required.`); - if (!amount) throw new Error(`Parameter "amount" is required.`); - - let bn = new BN(amount + '', 10); - // TODO: labeled keypairs - let clean = await this.generateCleanKeyPair(); - let change = await this.generateCleanKeyPair(); - - let mtx = new MTX(); - let cb = await this._generateFakeCoinbase(amount); - - mtx.addOutput({ - address: address, - amount: amount - }); - - await mtx.fund(this._state.utxos, { - rate: 10000, // TODO: fee calculation - changeAddress: change.address - }); - - mtx.sign(this.ring); - // mtx.signInput(0, this.ring); - - let tx = mtx.toTX(); - let output = null; - - try { - output = Coin.fromTX(mtx, 0, -1); - } catch (exception) { - console.error('[FABRIC:WALLET]', 'Could not generate output:', exception); - } - - let raw = mtx.toRaw(); - let hash = Hash256.digest(raw.toString('hex')); - - return { - type: 'BitcoinTransaction', - data: { - tx: tx, - output: output, - raw: raw.toString('hex'), - hash: hash - } - }; - } - - addInputForCrowdfund (coin, inputIndex, mtx, keyring, hashType) { - let sampleCoin = coin instanceof Coin ? coin : Coin.fromJSON(coin); - if (!hashType) hashType = Script.hashType.ANYONECANPAY | Script.hashType.ALL; - - mtx.addCoin(sampleCoin); - mtx.scriptInput(inputIndex, sampleCoin, keyring); - mtx.signInput(inputIndex, sampleCoin, keyring, hashType); - - console.log('MTX after Input added (and signed):', mtx); - - // TODO: return a full object for Fabric - return mtx; - } - balanceFromState (state) { if (!state.transactions) throw new Error('State does not provide a `transactions` property.'); if (!state.transactions.length) return 0; @@ -823,170 +586,27 @@ class Wallet extends Service { }; } - async _splitCoinbase (funderKeyring, coin, targetAmount, txRate) { - // loop through each coinbase coin to split - let coins = []; - - const mtx = new MTX(); - - assert(coin.value > targetAmount, 'coin value is not enough!'); - - // creating a transaction that will have an output equal to what we want to fund - mtx.addOutput({ - address: funderKeyring.getAddress(), - value: targetAmount - }); - - // the fund method will automatically split - // the remaining funds to the change address - // Note that in a real application these splitting transactions will also - // have to be broadcast to the network - await mtx.fund([coin], { - rate: txRate, - // send change back to an address belonging to the funder - changeAddress: funderKeyring.getAddress() - }).then(() => { - // sign the mtx to finalize split - mtx.sign(funderKeyring); - assert(mtx.verify()); - - const tx = mtx.toTX(); - assert(tx.verify(mtx.view)); - - const outputs = tx.outputs; - - // get coins from tx - outputs.forEach((outputs, index) => { - coins.push(Coin.fromTX(tx, index, -1)); - }); - }).catch(e => console.log('There was an error: ', e)); - - return coins; - } - - async composeCrowdfund (coins) { - const funderCoins = {}; - // Loop through each coinbase - for (let index in coins) { - const coinbase = coins[index][0]; - // estimate fee for each coin (assuming their split coins will use same tx type) - const estimatedFee = getFeeForInput(coinbase, fundeeAddress, funders[index], txRate); - const targetPlusFee = amountToFund + estimatedFee; - - // split the coinbase with targetAmount plus estimated fee - const splitCoins = await Utils.splitCoinbase(funders[index], coinbase, targetPlusFee, txRate); - - // add to funderCoins object with returned coins from splitCoinbase being value, - // and index being the key - funderCoins[index] = splitCoins; - } - // ... we'll keep filling out the rest of the code here - } - async _addOutputToSpendables (coin) { this._state.utxos.push(coin); return this; } async getUnusedAddress () { - let clean = await this.wallet.receiveAddress(); - this.emit('log', `unused address: ${clean}`); - return clean; + return this.receiveAddress(); } async getUnspentTransactionOutputs () { - return this._state.transactions.filter(x => { - return (x.spent === 0); - }); - } + // Convert object to array if needed + const txArray = Array.isArray(this._state.transactions) ? this._state.transactions :Object.values(this._state.content.transactions); - async _generateFakeCoinbase (amount = 1) { - // TODO: use Satoshis for all calculations - let num = new BN(amount, 10); - - // TODO: remove all fake coinbases - // TODO: remove all short-circuits - // fake coinbase - let cb = new MTX(); - let clean = await this.generateCleanKeyPair(); - - // Coinbase Input - cb.addInput({ - prevout: new Outpoint(), - script: new Script(), - sequence: 0xffffffff - }); - - // Add Output to pay ourselves - cb.addOutput({ - address: clean.address, - value: 5000000000 + return txArray.filter(x => { + return !x.spent; }); - - // TODO: remove short-circuit - let coin = Coin.fromTX(cb, 0, -1); - let tx = cb.toTX(); - - // TODO: remove entirely, test short-circuit removal - // await this._addOutputToSpendables(coin); - - return { - type: 'BitcoinTransactionOutput', - data: { - tx: cb, - coin: coin - } - }; - } - - async _getFreeCoinbase (amount = 1) { - let num = new BN(amount, 10); - let max = new BN('5000000000000', 10); // upper limit per coinbase - let hun = new BN('100000000', 10); // one hundred million - let value = num.mul(hun); // amount in Satoshis - - if (value.gt(max)) { - console.warn('Value (in satoshis) higher than max:', value.toString(10), `(max was ${max.toString(10)})`); - value = max; - } - - let v = value.toString(10); - let w = parseInt(v); - - await this._load(); - - const coins = {}; - const coinbase = new MTX(); - - // INSERT 1 Input - coinbase.addInput({ - prevout: new Outpoint(), - script: new Script(), - sequence: 0xffffffff - }); - - try { - // INSERT 1 Output - coinbase.addOutput({ - address: this._getDepositAddress(), - value: w - }); - } catch (E) { - console.error('Could not add output:', E); - } - - // TODO: wallet._getSpendableOutput() - let coin = Coin.fromTX(coinbase, 0, -1); - this._state.utxos.push(coin); - - // console.log('coinbase:', coinbase); - - return coinbase; } /** * Signs a transaction with the keyring. - * @param {BcoinTX} tx + * @param {BcoinTX} tx */ async _sign (tx) { let signature = await tx.sign(this.keyring); @@ -997,7 +617,7 @@ class Wallet extends Service { /** * Create a crowdfunding transaction. - * @param {Object} fund + * @param {Object} fund */ async _createCrowdfund (fund = {}) { if (!fund.amount) return null; @@ -1020,19 +640,12 @@ class Wallet extends Service { async _createFromFreshSeed (passphrase = '') { console.log('creating fresh seed with passphrase:', passphrase); - const seed = await this._createSeed(passphrase); - return seed; - } - - async _createSeed (passphrase = '') { - const mnemonic = bip39.generateMnemonic(256); - const interim = bip39.mnemonicToSeedSync(mnemonic, passphrase); - const master = bip32.fromSeed(interim); - + const key = new Key({ passphrase: passphrase }); return { - phrase: mnemonic.toString(), - master: master.privateKey.toString('hex'), - xprv: master.toBase58() + phrase: key.mnemonic, + master: key.master.privateKey.toString('hex'), + xprv: key.master.toBase58(), + xpub: key.master.neutered().toBase58() }; } @@ -1041,46 +654,6 @@ class Wallet extends Service { return this._loadSeed(mnemonic.toString()); } - async _createIncentivizedTransaction (config) { - console.log('creating incentivized transaction with config:', config); - - let mtx = new MTX(); - let data = new Script(); - let clean = await this.generateCleanKeyPair(); - - data.pushSym('OP_IF'); - data.pushSym('OP_SHA256'); - data.pushData(Buffer.from(config.hash)); - data.pushSym('OP_EQUALVERIFY'); - data.pushData(Buffer.from(config.payee)); - data.pushSym('OP_ELSE'); - data.pushInt(config.locktime); - data.pushSym('OP_CHECKSEQUENCEVERIFY'); - data.pushSym('OP_DROP'); - data.pushData(Buffer.from(clean.public)); - data.pushSym('OP_ENDIF'); - data.pushSym('OP_CHECKSIG'); - data.compile(); - - console.log('address data:', data); - let segwitAddress = await this.getAddressForScript(data); - - mtx.addOutput({ - address: segwitAddress, - value: 0 - }); - - // TODO: load available outputs from wallet - let out = await mtx.fund([] /* coins */, { - // TODO: fee estimation - rate: 10000, - changeAddress: this.ring.getAddress() - }); - - console.log('transaction:', out); - return out; - } - async _getBondAddress () { await this._load(); @@ -1146,66 +719,10 @@ class Wallet extends Service { ); } - async getRedeemTX (address, fee, fundingTX, fundingTXoutput, redeemScript, inputScript, locktime, privateKey) { - // Create a mutable transaction object - let redeemTX = new MTX(); - - // Get the output we want to spend (coins sent to the P2SH address) - let coin = Coin.fromTX(fundingTX, fundingTXoutput, -1); - - // Add that coin as an input to our transaction - redeemTX.addCoin(coin); - - // Redeem the input coin with either the swap or refund script - redeemTX.inputs[0].script = inputScript; - - // Create the output back to our primary wallet - redeemTX.addOutput({ - address: address, - value: coin.value - fee - }); - - // If this was a refund redemption we need to set the sequence - // Sequence is the relative timelock value applied to individual inputs - if (locktime) { - redeemTX.setSequence(0, locktime, this.CSV_seconds); - } else { - redeemTX.inputs[0].sequence = 0xffffffff; - } - - // Set SIGHASH and replay protection bits - let version_or_flags = 0; - let type = null; - - if (this.libName === 'bcash') { - version_or_flags = this.flags; - type = Script.hashType.SIGHASH_FORKID | Script.hashType.ALL; - } - - // Create the signature authorizing the input script to spend the coin - let sig = await this.signInput( - redeemTX, - 0, - redeemScript, - coin.value, - privateKey, - type, - version_or_flags - ); - - // Insert the signature into the input script where we had a `0` placeholder - inputScript.setData(0, sig); - - // Finish up and return - inputScript.compile(); - - return redeemTX; - } - /** * Generate {@link Script} for claiming a {@link Swap}. - * @param {*} redeemScript - * @param {*} secret + * @param {*} redeemScript + * @param {*} secret */ async _getSwapInputScript (redeemScript, secret) { let inputSwap = new Script(); @@ -1221,7 +738,7 @@ class Wallet extends Service { /** * Generate {@link Script} for reclaiming funds commited to a {@link Swap}. - * @param {*} redeemScript + * @param {*} redeemScript */ async _getRefundInputScript (redeemScript) { let inputRefund = new Script(); @@ -1234,70 +751,6 @@ class Wallet extends Service { return inputRefund; } - async _createOrderForPubkey (pubkey) { - this.emit('log', `creating ORDER transaction with pubkey: ${pubkey}`); - - let mtx = new MTX(); - let data = new Script(); - let clean = await this.generateCleanKeyPair(); - - let secret = 'fixed secret :)'; - let sechash = require('crypto').createHash('sha256').update(secret).digest('hex'); - - this.emit('log', `SECRET CREATED: ${secret}`); - this.emit('log', `SECHASH: ${sechash}`); - - data.pushSym('OP_IF'); - data.pushSym('OP_SHA256'); - data.pushData(Buffer.from(sechash)); - data.pushSym('OP_EQUALVERIFY'); - data.pushData(Buffer.from(pubkey)); - data.pushSym('OP_ELSE'); - data.pushInt(86400); - data.pushSym('OP_CHECKSEQUENCEVERIFY'); - data.pushSym('OP_DROP'); - data.pushData(Buffer.from(clean.public)); - data.pushSym('OP_ENDIF'); - data.pushSym('OP_CHECKSIG'); - data.compile(); - - this.emit('log', `[AUDIT] address data: ${data}`); - let segwitAddress = await this.getAddressForScript(data); - let address = await this.getAddressFromRedeemScript(data); - - this.emit('log', `[AUDIT] segwit address: ${segwitAddress}`); - this.emit('log', `[AUDIT] normal address: ${address}`); - - mtx.addOutput({ - address: address, - value: 25000000 - }); - - // ensure a coin exists... - // NOTE: this is tracked in this._state.coins - // and thus does not need to be cast to a variable... - let coinbase = await this._getFreeCoinbase(); - - // TODO: load available outputs from wallet - let out = await mtx.fund(this._state.utxos, { - // TODO: fee estimation - rate: 10000, - changeAddress: this.ring.getAddress() - }); - - let tx = mtx.toTX(); - let sig = await mtx.sign(this.ring); - - this.emit('log', 'transaction:', tx); - this.emit('log', 'sig:', sig); - - return { - tx: tx, - mtx: mtx, - sig: sig - }; - } - async _scanBlockForTransactions (block) { console.log('[AUDIT]', 'Scanning block for transactions:', block); let found = []; @@ -1362,22 +815,25 @@ class Wallet extends Service { * @param {String} input Hex-encoded string to create key from. */ publicKeyFromString (input) { - const buf = Buffer.from(input, 'hex'); - const key = new Key({ public: buf }); - return key.pubkey; + if (input instanceof Point) { + return new Key({ public: input.encode('hex', true) }); + } + return new Key({ public: input }); } async generateCleanKeyPair () { - if (this.status !== 'loaded') await this._load(); + // Ensure index is a valid number + const index = typeof this.index === 'number' ? this.index : 0; + this.index = index + 1; + + // Use a standard BIP44 path with the index + const path = `m/44'/0'/0'/0/${index}`; + const pair = this.key.derive(path); - const pair = this.key.deriveKeyPair(++this.index); const keypair = { - index: this.index, + index: index, public: pair.public, - address: payments.p2pkh({ - pubkey: Buffer.from(pair.public, 'hex') - }) - // keyring: keyring + private: pair.private }; return keypair; @@ -1423,6 +879,67 @@ class Wallet extends Service { async _unload () { return this.database.close(); } + + async receiveAddress () { + const keypair = await this.generateCleanKeyPair(); + return keypair.public.toString('hex'); + } + + // Add method to check gap limit + async _checkGapLimit () { + const unusedCount = await this._countUnusedAddresses(); + return unusedCount < this.settings.gapLimit; + } + + // Count unused addresses + async _countUnusedAddresses () { + let count = 0; + for (const addr in this._state.addresses) { + if (!this._state.addresses[addr].used) { + count++; + } + } + return count; + } + + // Get the highest used index + async _getHighestUsedIndex () { + let highest = -1; + for (const addr in this._state.addresses) { + const addrInfo = this._state.addresses[addr]; + if (addrInfo.used && addrInfo.index > highest) { + highest = addrInfo.index; + } + } + return highest; + } + + // Mark address as used + async markAddressAsUsed (address) { + if (this._state.addresses[address]) { + this._state.addresses[address].used = true; + this._state.addresses[address].lastUsed = Date.now(); + this._state.lastUsedIndex = Math.max( + this._state.lastUsedIndex, + this._state.addresses[address].index + ); + await this.commit(); + } + } + + // Get all addresses + async getAddresses (includeUnused = false) { + const addresses = []; + for (const addr in this._state.addresses) { + if (includeUnused || this._state.addresses[addr].used) { + addresses.push({ + address: addr, + ...this._state.addresses[addr] + }); + } + } + return addresses; + } } module.exports = Wallet; diff --git a/types/weave.js b/types/weave.js deleted file mode 100644 index 0bf47917c..000000000 --- a/types/weave.js +++ /dev/null @@ -1,118 +0,0 @@ -'use strict'; - -const BN = require('bn.js'); -const merge = require('lodash.merge'); -const Actor = require('./actor'); -const Label = require('./label'); -const Key = require('./key'); -const Tree = require('./tree'); - -class Weave extends Actor { - constructor (settings = {}) { - super(settings); - - // Allow constructor to use Array input - if (settings instanceof Array) settings = { inputs: settings }; - - // Assign defaults - this.settings = merge({ - inputs: [], - outputs: [], - key: { - seed: null, - private: null, - public: null - }, - depth: 1 - }, this.settings, settings); - - this.key = new Key(this.settings.key); - this._tree = new Tree(this.settings.inputs); - this._state = { - status: 'initialized', - root: this._tree.root.toString('hex'), - gates: [], - layers: [], - outputs: [], - keys: {} - }; - - // Stores cryptographic signature - this.signature = null; - - return this; - } - - get status () { - return this._state.status; - } - - get root () { - return this._tree.root; - } - - async commit () { - this._state.root = this._tree.root.toString('hex'); - this.signature = await this.key._sign(this._state.root); - - // Create commitment - const commit = { - type: 'Commit', - data: this._state.root, - signature: this.signature - }; - - // Notify listeners - this.emit('commit', commit); - - // Not chainable (returns commit) - return commit; - } - - _createThread (state = {}) { - const actor = new Actor(state); - const label = new Label(`actors/${actor.id}`); - const ephemeral = new Key(); - const key = { - private: ephemeral.private, - public: ephemeral.public - }; - - // Store in state - this._state.keys[ ephemeral.id ] = key; - - return { - actor: actor.id, - label: label._id, - pubkey: ephemeral.id - }; - } - - async _generateLayer () { - const gates = []; - - for (let i = 0; i < this.settings.inputs.length; i++) { - const input = this.settings.inputs[i]; - const label = new Label(`gates/${input}`); - const gate = this._createThread({ input }); - const actor = new Actor({ label: label._id, gate }); - gates.push(actor.id); - } - - if (!gates.length) throw new Error('No gates created. Did you provide any inputs?'); - - const layer = new Weave(gates); - this._state.layers.push(layer); - - const commit = await this.commit(); - - return { - type: 'WeaveLayer', - data: layer, - gates: gates, - commit: commit - }; - } -} - -module.exports = Weave; diff --git a/webpack.config.js b/webpack.config.js deleted file mode 100644 index faf17cdbc..000000000 --- a/webpack.config.js +++ /dev/null @@ -1,24 +0,0 @@ -'use strict'; - -const webpack = require('webpack'); - -module.exports = { - entry: './index.js', - // devtool: 'source-map', - mode: 'development', - target: 'web', - output: { - library: 'Fabric' - }, - plugins: [ - new webpack.ProvidePlugin({ - Peer: ['peerjs', 'default'] - }), - new webpack.DefinePlugin({ - 'process.env': { - NODE_ENV: JSON.stringify('production'), - APP_ENV: JSON.stringify('browser') - } - }) - ] -};