fix: multi-repo local dev (file:../ deps, package exports, missing deps)
This commit is contained in:
+1
@@ -0,0 +1 @@
|
||||
../hyperdht/bin.js
|
||||
+2613
File diff suppressed because it is too large
Load Diff
+201
@@ -0,0 +1,201 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
+160
@@ -0,0 +1,160 @@
|
||||
# @hyperswarm/secret-stream
|
||||
|
||||
### [See the full API docs at docs.holepunch.to](https://docs.holepunch.to/building-blocks/hyperswarm#secretstream)
|
||||
|
||||
Secret stream backed by Noise and libsodium's secretstream
|
||||
|
||||
```
|
||||
npm install @hyperswarm/secret-stream
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
You can either make a secret stream from an existing transport stream.
|
||||
|
||||
```js
|
||||
const SecretStream = require('@hyperswarm/secret-stream')
|
||||
|
||||
const a = new SecretStream(true, tcpClientStream)
|
||||
const b = new SecretStream(false, tcpServerStream)
|
||||
|
||||
// pipe the underlying rawstreams together
|
||||
|
||||
a.write(Buffer.from('hello encrypted!'))
|
||||
|
||||
b.on('data', function (data) {
|
||||
console.log(data) // <Buffer hello encrypted!>
|
||||
})
|
||||
```
|
||||
|
||||
Or by making your own pipeline
|
||||
|
||||
```js
|
||||
const a = new SecretStream(true)
|
||||
const b = new SecretStream(false)
|
||||
|
||||
// pipe the underlying rawstreams together
|
||||
a.rawStream.pipe(b.rawStream).pipe(a.rawStream)
|
||||
|
||||
a.write(Buffer.from('hello encrypted!'))
|
||||
|
||||
b.on('data', function (data) {
|
||||
console.log(data) // <Buffer hello encrypted!>
|
||||
})
|
||||
```
|
||||
|
||||
## API
|
||||
|
||||
#### `const s = new SecretStream(isInitiator, [rawStream], [options])`
|
||||
|
||||
Make a new stream. `isInitiator` is a boolean indication whether you are the client or the server.
|
||||
`rawStream` can be set to an underlying transport stream you want to run the noise stream over.
|
||||
|
||||
Options include:
|
||||
|
||||
```js
|
||||
{
|
||||
pattern: 'XX', // which noise pattern to use
|
||||
remotePublicKey, // set if your handshake requires it
|
||||
keyPair: { publicKey, secretKey },
|
||||
handshake: { // if you want to use an handshake performed elsewhere pass it here
|
||||
tx,
|
||||
rx,
|
||||
hash,
|
||||
publicKey,
|
||||
remotePublicKey
|
||||
},
|
||||
enableSend: true // (advanced) set false to disable the send API
|
||||
}
|
||||
```
|
||||
|
||||
The SecretStream returned is a Duplex stream that you use as as normal stream, to write/read data from,
|
||||
except it's payloads are encrypted using the libsodium secretstream.
|
||||
|
||||
Note that this uses ed25519 for the handshakes per default.
|
||||
|
||||
If need to load the key pair asynchronously, then secret-stream also supports passing in a promise
|
||||
instead of the keypair that later resolves to `{ publicKey, secretKey }`. The stream lifecycle will wait
|
||||
for the resolution and auto destroy the stream if the promise errors.
|
||||
|
||||
#### `s.start(rawStream, [options])`
|
||||
|
||||
Start a SecretStream from a rawStream asynchrously.
|
||||
|
||||
```js
|
||||
const s = new SecretStream({
|
||||
autoStart: false // call start manually
|
||||
})
|
||||
|
||||
// ... do async stuff or destroy the stream
|
||||
|
||||
s.start(rawStream, {
|
||||
... options from above
|
||||
})
|
||||
```
|
||||
|
||||
#### `s.setTimeout(ms)`
|
||||
|
||||
Set the stream timeout. If no data is received within a `ms` window,
|
||||
the stream is auto destroyed.
|
||||
|
||||
#### `s.setKeepAlive(ms)`
|
||||
|
||||
Send a heartbeat (empty message) every time the socket is idle for `ms` milliseconds. **Note:** If one side calls `s.setKeepAlive()` and the other does not, then the empty messages will be passed through to the piped stream.
|
||||
|
||||
#### `s.publicKey`
|
||||
|
||||
Get the local public key.
|
||||
|
||||
#### `s.remotePublicKey`
|
||||
|
||||
Get the remote's public key.
|
||||
Populated after `open` is emitted.
|
||||
|
||||
#### `s.handshakeHash`
|
||||
|
||||
Get the unique hash of this handshake.
|
||||
Populated after `open` is emitted.
|
||||
|
||||
#### `s.keepAlive`
|
||||
|
||||
Get the interval (in milliseconds) at which keep-alive messages are sent (0 means none are sent).
|
||||
|
||||
#### `s.sendKeepAlive()`
|
||||
|
||||
A convenience method that sends an empty message.
|
||||
|
||||
#### `s.rawBytesWritten`
|
||||
|
||||
The number of bytes (measured after encryption) written.
|
||||
|
||||
#### `s.rawBytesRead`
|
||||
|
||||
The number of bytes (measured before decryption) received.
|
||||
|
||||
#### `s.on('connect', onconnect)`
|
||||
|
||||
Emitted when the handshake is fully done.
|
||||
It is safe to write to the stream immediately though, as data is buffered
|
||||
internally before the handshake has been completed.
|
||||
|
||||
#### `await s.send(buffer)`
|
||||
|
||||
Sends an encrypted unordered message, see [udx-native](https://github.com/holepunchto/udx-native/tree/main?tab=readme-ov-file#await-streamsendbuffer) for details.
|
||||
This method with silently fail if called before handshake is complete or if the underlying rawStream is not an UDX-stream (not capable of UDP).
|
||||
|
||||
#### `s.trySend(buffer)`
|
||||
|
||||
Same as `send(buffer)` but does not return a promise.
|
||||
|
||||
#### `s.on('message', onmessage)`
|
||||
|
||||
Emmitted when an unordered message is received
|
||||
|
||||
#### `keyPair = SecretStream.keyPair([seed])`
|
||||
|
||||
Generate a ed25519 key pair.
|
||||
|
||||
## License
|
||||
|
||||
Apache-2.0
|
||||
+645
@@ -0,0 +1,645 @@
|
||||
const { Pull, Push, HEADERBYTES, KEYBYTES, ABYTES } = require('sodium-secretstream')
|
||||
const sodium = require('sodium-universal')
|
||||
const crypto = require('hypercore-crypto')
|
||||
const { Duplex, Writable, getStreamError } = require('streamx')
|
||||
const b4a = require('b4a')
|
||||
const Timeout = require('timeout-refresh')
|
||||
const unslab = require('unslab')
|
||||
const Bridge = require('./lib/bridge')
|
||||
const Handshake = require('./lib/handshake')
|
||||
|
||||
const IDHEADERBYTES = HEADERBYTES + 32
|
||||
const [NS_INITIATOR, NS_RESPONDER, NS_SEND] = crypto.namespace('hyperswarm/secret-stream', 3)
|
||||
const MAX_ATOMIC_WRITE = 256 * 256 * 256 - 1
|
||||
|
||||
module.exports = class NoiseSecretStream extends Duplex {
|
||||
constructor(isInitiator, rawStream, opts = {}) {
|
||||
super({ mapWritable: toBuffer })
|
||||
|
||||
if (typeof isInitiator !== 'boolean') {
|
||||
throw new Error('isInitiator should be a boolean')
|
||||
}
|
||||
|
||||
this.noiseStream = this
|
||||
this.isInitiator = isInitiator
|
||||
this.rawStream = null
|
||||
|
||||
this.publicKey = opts.publicKey || null
|
||||
this.remotePublicKey = opts.remotePublicKey || null
|
||||
this.handshakeHash = null
|
||||
this.connected = false
|
||||
this.keepAlive = opts.keepAlive || 0
|
||||
this.timeout = 0
|
||||
this.enableSend = opts.enableSend !== false
|
||||
|
||||
// pointer for upstream to set data here if they want
|
||||
this.userData = null
|
||||
|
||||
let openedDone = null
|
||||
this.opened = new Promise((resolve) => {
|
||||
openedDone = resolve
|
||||
})
|
||||
|
||||
this.rawBytesWritten = 0
|
||||
this.rawBytesRead = 0
|
||||
|
||||
// metadata used by 'hyperdht'
|
||||
this.relay = null
|
||||
this.puncher = null
|
||||
|
||||
// unwrapped raw stream
|
||||
this._rawStream = null
|
||||
|
||||
// handshake state
|
||||
this._handshake = null
|
||||
this._handshakePattern = opts.pattern || null
|
||||
this._handshakeDone = null
|
||||
|
||||
// message parsing state
|
||||
this._state = 0
|
||||
this._len = 0
|
||||
this._tmp = 1
|
||||
this._message = null
|
||||
|
||||
this._openedDone = openedDone
|
||||
this._startDone = null
|
||||
this._drainDone = null
|
||||
this._outgoingPlain = null
|
||||
this._outgoingWrapped = null
|
||||
this._utp = null
|
||||
this._setup = true
|
||||
this._ended = 2
|
||||
this._encrypt = null
|
||||
this._decrypt = null
|
||||
this._timeoutTimer = null
|
||||
this._keepAliveTimer = null
|
||||
this._sendState = null
|
||||
|
||||
if (opts.autoStart !== false) this.start(rawStream, opts)
|
||||
|
||||
// wiggle it to trigger open immediately (TODO add streamx option for this)
|
||||
this.resume()
|
||||
this.pause()
|
||||
}
|
||||
|
||||
static keyPair(seed) {
|
||||
return Handshake.keyPair(seed)
|
||||
}
|
||||
|
||||
static id(handshakeHash, isInitiator, id) {
|
||||
return streamId(handshakeHash, isInitiator, id)
|
||||
}
|
||||
|
||||
setTimeout(ms) {
|
||||
if (!ms) ms = 0
|
||||
|
||||
this._clearTimeout()
|
||||
this.timeout = ms
|
||||
|
||||
if (!ms || this.rawStream === null) return
|
||||
|
||||
this._timeoutTimer = Timeout.once(ms, destroyTimeout, this)
|
||||
this._timeoutTimer.unref()
|
||||
}
|
||||
|
||||
setKeepAlive(ms) {
|
||||
if (!ms) ms = 0
|
||||
|
||||
this._clearKeepAlive()
|
||||
|
||||
this.keepAlive = ms
|
||||
|
||||
if (!ms || this.rawStream === null) return
|
||||
|
||||
this._keepAliveTimer = Timeout.on(ms, sendKeepAlive, this)
|
||||
this._keepAliveTimer.unref()
|
||||
}
|
||||
|
||||
sendKeepAlive() {
|
||||
const empty = this.alloc(0)
|
||||
this.write(empty)
|
||||
}
|
||||
|
||||
start(rawStream, opts = {}) {
|
||||
if (rawStream) {
|
||||
this.rawStream = rawStream
|
||||
this._rawStream = rawStream
|
||||
if (typeof this.rawStream.setContentSize === 'function') {
|
||||
this._utp = rawStream
|
||||
}
|
||||
} else {
|
||||
this.rawStream = new Bridge(this)
|
||||
this._rawStream = this.rawStream.reverse
|
||||
}
|
||||
|
||||
this.rawStream.on('error', this._onrawerror.bind(this))
|
||||
this.rawStream.on('close', this._onrawclose.bind(this))
|
||||
|
||||
this._startHandshake(opts.handshake, opts.keyPair || null)
|
||||
this._continueOpen(null)
|
||||
|
||||
if (this.destroying) return
|
||||
|
||||
if (opts.data) this._onrawdata(opts.data)
|
||||
if (opts.ended) this._onrawend()
|
||||
|
||||
if (this.keepAlive > 0 && this._keepAliveTimer === null) {
|
||||
this.setKeepAlive(this.keepAlive)
|
||||
}
|
||||
|
||||
if (this.timeout > 0 && this._timeoutTimer === null) {
|
||||
this.setTimeout(this.timeout)
|
||||
}
|
||||
}
|
||||
|
||||
async flush() {
|
||||
if ((await this.opened) === false) return false
|
||||
if ((await Writable.drained(this)) === false) return false
|
||||
if (this.destroying) return false
|
||||
|
||||
if (this.rawStream !== null && this.rawStream.flush) {
|
||||
return await this.rawStream.flush()
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
_continueOpen(err) {
|
||||
if (err) this.destroy(err)
|
||||
if (this._startDone === null) return
|
||||
const done = this._startDone
|
||||
this._startDone = null
|
||||
this._open(done)
|
||||
}
|
||||
|
||||
_onkeypairpromise(p) {
|
||||
const self = this
|
||||
const cont = this._continueOpen.bind(this)
|
||||
|
||||
p.then(onkeypair, cont)
|
||||
|
||||
function onkeypair(kp) {
|
||||
self._onkeypair(kp)
|
||||
cont(null)
|
||||
}
|
||||
}
|
||||
|
||||
_onkeypair(keyPair) {
|
||||
const pattern = this._handshakePattern || 'XX'
|
||||
const remotePublicKey = this.remotePublicKey
|
||||
|
||||
this._handshake = new Handshake(this.isInitiator, keyPair, remotePublicKey, pattern)
|
||||
this.publicKey = this._handshake.keyPair.publicKey
|
||||
}
|
||||
|
||||
_startHandshake(handshake, keyPair) {
|
||||
if (handshake) {
|
||||
const { tx, rx, hash, publicKey, remotePublicKey } = handshake
|
||||
this._setupSecretStream(tx, rx, hash, publicKey, remotePublicKey)
|
||||
return
|
||||
}
|
||||
|
||||
if (!keyPair) keyPair = Handshake.keyPair()
|
||||
|
||||
if (typeof keyPair.then === 'function') {
|
||||
this._onkeypairpromise(keyPair)
|
||||
} else {
|
||||
this._onkeypair(keyPair)
|
||||
}
|
||||
}
|
||||
|
||||
_onrawerror(err) {
|
||||
this.destroy(err)
|
||||
}
|
||||
|
||||
_onrawclose() {
|
||||
if (this._ended !== 0) this.destroy()
|
||||
}
|
||||
|
||||
_onrawdata(data) {
|
||||
let offset = 0
|
||||
|
||||
if (this._timeoutTimer !== null) {
|
||||
this._timeoutTimer.refresh()
|
||||
}
|
||||
|
||||
do {
|
||||
switch (this._state) {
|
||||
case 0: {
|
||||
while (this._tmp !== 0x1000000 && offset < data.byteLength) {
|
||||
const v = data[offset++]
|
||||
this._len += this._tmp * v
|
||||
this._tmp *= 256
|
||||
}
|
||||
|
||||
if (this._tmp === 0x1000000) {
|
||||
this._tmp = 0
|
||||
this._state = 1
|
||||
const unprocessed = data.byteLength - offset
|
||||
if (unprocessed < this._len && this._utp !== null)
|
||||
this._utp.setContentSize(this._len - unprocessed)
|
||||
}
|
||||
|
||||
break
|
||||
}
|
||||
|
||||
case 1: {
|
||||
const missing = this._len - this._tmp
|
||||
const end = missing + offset
|
||||
|
||||
if (this._message === null && end <= data.byteLength) {
|
||||
this._message = data.subarray(offset, end)
|
||||
offset += missing
|
||||
this._incoming()
|
||||
break
|
||||
}
|
||||
|
||||
const unprocessed = data.byteLength - offset
|
||||
|
||||
if (this._message === null) {
|
||||
this._message = b4a.allocUnsafe(this._len)
|
||||
}
|
||||
|
||||
b4a.copy(data, this._message, this._tmp, offset)
|
||||
this._tmp += unprocessed
|
||||
|
||||
if (end <= data.byteLength) {
|
||||
offset += missing
|
||||
this._incoming()
|
||||
} else {
|
||||
offset += unprocessed
|
||||
}
|
||||
|
||||
break
|
||||
}
|
||||
}
|
||||
} while (offset < data.byteLength && !this.destroying)
|
||||
}
|
||||
|
||||
_onrawend() {
|
||||
this._ended--
|
||||
this.push(null)
|
||||
}
|
||||
|
||||
_onrawdrain() {
|
||||
const drain = this._drainDone
|
||||
if (drain === null) return
|
||||
this._drainDone = null
|
||||
drain()
|
||||
}
|
||||
|
||||
_read(cb) {
|
||||
this.rawStream.resume()
|
||||
cb(null)
|
||||
}
|
||||
|
||||
_incoming() {
|
||||
const message = this._message
|
||||
|
||||
this._state = 0
|
||||
this._len = 0
|
||||
this._tmp = 1
|
||||
this._message = null
|
||||
|
||||
if (this._setup === true) {
|
||||
if (this._handshake) {
|
||||
this._onhandshakert(this._handshake.recv(message))
|
||||
} else {
|
||||
if (message.byteLength !== IDHEADERBYTES) {
|
||||
this.destroy(new Error('Invalid header message received'))
|
||||
return
|
||||
}
|
||||
|
||||
const remoteId = message.subarray(0, 32)
|
||||
const expectedId = streamId(this.handshakeHash, !this.isInitiator)
|
||||
const header = message.subarray(32)
|
||||
|
||||
if (!b4a.equals(expectedId, remoteId)) {
|
||||
this.destroy(new Error('Invalid header received'))
|
||||
return
|
||||
}
|
||||
|
||||
this._decrypt.init(header)
|
||||
this._setup = false // setup is now done
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if (message.byteLength < ABYTES) {
|
||||
this.destroy(new Error('Invalid message received'))
|
||||
return
|
||||
}
|
||||
|
||||
this.rawBytesRead += message.byteLength
|
||||
|
||||
const plain = message.subarray(1, message.byteLength - ABYTES + 1)
|
||||
|
||||
try {
|
||||
this._decrypt.next(message, plain)
|
||||
} catch (err) {
|
||||
this.destroy(err)
|
||||
return
|
||||
}
|
||||
|
||||
// If keep alive is selective, eat the empty buffers (ie assume the other side has it enabled also)
|
||||
if (plain.byteLength === 0 && this.keepAlive !== 0) return
|
||||
|
||||
if (this.push(plain) === false) {
|
||||
this.rawStream.pause()
|
||||
}
|
||||
}
|
||||
|
||||
_onhandshakert(h) {
|
||||
if (this._handshakeDone === null) return
|
||||
|
||||
if (h !== null) {
|
||||
if (h.data) this._rawStream.write(h.data)
|
||||
if (!h.tx) return
|
||||
}
|
||||
|
||||
const done = this._handshakeDone
|
||||
const publicKey = this._handshake.keyPair.publicKey
|
||||
|
||||
this._handshakeDone = null
|
||||
this._handshake = null
|
||||
|
||||
if (h === null) return done(new Error('Noise handshake failed'))
|
||||
|
||||
this._setupSecretStream(h.tx, h.rx, h.hash, publicKey, h.remotePublicKey)
|
||||
this._resolveOpened(true)
|
||||
done(null)
|
||||
}
|
||||
|
||||
_setupSecretStream(tx, rx, handshakeHash, publicKey, remotePublicKey) {
|
||||
const buf = b4a.allocUnsafeSlow(3 + IDHEADERBYTES)
|
||||
writeUint24le(IDHEADERBYTES, buf)
|
||||
|
||||
this._encrypt = new Push(unslab(tx.subarray(0, KEYBYTES)), undefined, buf.subarray(3 + 32))
|
||||
this._decrypt = new Pull(unslab(rx.subarray(0, KEYBYTES)))
|
||||
|
||||
this.publicKey = publicKey
|
||||
this.remotePublicKey = remotePublicKey
|
||||
this.handshakeHash = handshakeHash
|
||||
|
||||
const id = buf.subarray(3, 3 + 32)
|
||||
streamId(handshakeHash, this.isInitiator, id)
|
||||
|
||||
// initialize secretbox state for unordered messages
|
||||
this._setupSecretSend(handshakeHash)
|
||||
|
||||
this.emit('handshake')
|
||||
// if rawStream is a bridge, also emit it there
|
||||
if (this.rawStream !== this._rawStream) this.rawStream.emit('handshake')
|
||||
|
||||
if (this.destroying) return
|
||||
|
||||
this._rawStream.write(buf)
|
||||
}
|
||||
|
||||
_setupSecretSend(handshakeHash) {
|
||||
this._sendState = b4a.allocUnsafeSlow(32 + 32 + 8 + 8)
|
||||
const encrypt = this._sendState.subarray(0, 32) // secrets
|
||||
const decrypt = this._sendState.subarray(32, 64)
|
||||
const counter = this._sendState.subarray(64, 72) // nonce
|
||||
const initial = this._sendState.subarray(72)
|
||||
|
||||
const inputs = this.isInitiator
|
||||
? [
|
||||
[NS_INITIATOR, NS_SEND],
|
||||
[NS_RESPONDER, NS_SEND]
|
||||
]
|
||||
: [
|
||||
[NS_RESPONDER, NS_SEND],
|
||||
[NS_INITIATOR, NS_SEND]
|
||||
]
|
||||
|
||||
sodium.crypto_generichash_batch(encrypt, inputs[0], handshakeHash)
|
||||
sodium.crypto_generichash_batch(decrypt, inputs[1], handshakeHash)
|
||||
|
||||
sodium.randombytes_buf(initial)
|
||||
counter.set(initial)
|
||||
}
|
||||
|
||||
_open(cb) {
|
||||
// no autostart or no handshake yet
|
||||
if (this._rawStream === null || (this._handshake === null && this._encrypt === null)) {
|
||||
this._startDone = cb
|
||||
return
|
||||
}
|
||||
|
||||
this._rawStream.on('data', this._onrawdata.bind(this))
|
||||
this._rawStream.on('end', this._onrawend.bind(this))
|
||||
this._rawStream.on('drain', this._onrawdrain.bind(this))
|
||||
|
||||
if (this.enableSend) this._rawStream.on('message', this._onmessage.bind(this))
|
||||
|
||||
if (this._encrypt !== null) {
|
||||
this._resolveOpened(true)
|
||||
return cb(null)
|
||||
}
|
||||
|
||||
this._handshakeDone = cb
|
||||
|
||||
if (this.isInitiator) this._onhandshakert(this._handshake.send())
|
||||
}
|
||||
|
||||
_predestroy() {
|
||||
if (this.rawStream) {
|
||||
const error = getStreamError(this)
|
||||
this.rawStream.destroy(error)
|
||||
}
|
||||
|
||||
if (this._startDone !== null) {
|
||||
const done = this._startDone
|
||||
this._startDone = null
|
||||
done(new Error('Stream destroyed'))
|
||||
}
|
||||
|
||||
if (this._handshakeDone !== null) {
|
||||
const done = this._handshakeDone
|
||||
this._handshakeDone = null
|
||||
done(new Error('Stream destroyed'))
|
||||
}
|
||||
|
||||
if (this._drainDone !== null) {
|
||||
const done = this._drainDone
|
||||
this._drainDone = null
|
||||
done(new Error('Stream destroyed'))
|
||||
}
|
||||
}
|
||||
|
||||
_write(data, cb) {
|
||||
let wrapped = this._outgoingWrapped
|
||||
|
||||
if (data !== this._outgoingPlain) {
|
||||
wrapped = b4a.allocUnsafe(data.byteLength + 3 + ABYTES)
|
||||
wrapped.set(data, 4)
|
||||
} else {
|
||||
this._outgoingWrapped = this._outgoingPlain = null
|
||||
}
|
||||
|
||||
if (wrapped.byteLength - 3 > MAX_ATOMIC_WRITE) {
|
||||
return cb(
|
||||
new Error(
|
||||
'Message is too large for an atomic write. Max size is ' + MAX_ATOMIC_WRITE + ' bytes.'
|
||||
)
|
||||
)
|
||||
}
|
||||
this.rawBytesWritten += wrapped.byteLength
|
||||
|
||||
writeUint24le(wrapped.byteLength - 3, wrapped)
|
||||
// offset 4 so we can do it in-place
|
||||
this._encrypt.next(wrapped.subarray(4, 4 + data.byteLength), wrapped.subarray(3))
|
||||
|
||||
if (this._keepAliveTimer !== null) this._keepAliveTimer.refresh()
|
||||
|
||||
if (this._rawStream.write(wrapped) === false) {
|
||||
this._drainDone = cb
|
||||
} else {
|
||||
cb(null)
|
||||
}
|
||||
}
|
||||
|
||||
_final(cb) {
|
||||
this._clearKeepAlive()
|
||||
this._ended--
|
||||
this._rawStream.end()
|
||||
cb(null)
|
||||
}
|
||||
|
||||
_resolveOpened(val) {
|
||||
if (this._openedDone === null) return
|
||||
const opened = this._openedDone
|
||||
this._openedDone = null
|
||||
opened(val)
|
||||
if (!val) return
|
||||
this.connected = true
|
||||
this.emit('connect')
|
||||
}
|
||||
|
||||
_clearTimeout() {
|
||||
if (this._timeoutTimer === null) return
|
||||
this._timeoutTimer.destroy()
|
||||
this._timeoutTimer = null
|
||||
this.timeout = 0
|
||||
}
|
||||
|
||||
_clearKeepAlive() {
|
||||
if (this._keepAliveTimer === null) return
|
||||
this._keepAliveTimer.destroy()
|
||||
this._keepAliveTimer = null
|
||||
this.keepAlive = 0
|
||||
}
|
||||
|
||||
_destroy(cb) {
|
||||
this._clearKeepAlive()
|
||||
this._clearTimeout()
|
||||
this._resolveOpened(false)
|
||||
cb(null)
|
||||
}
|
||||
|
||||
_boxMessage(buffer) {
|
||||
const MB = sodium.crypto_secretbox_MACBYTES // 16
|
||||
const NB = sodium.crypto_secretbox_NONCEBYTES // 24
|
||||
|
||||
const counter = this._sendState.subarray(64, 72)
|
||||
sodium.sodium_increment(counter)
|
||||
if (b4a.equals(counter, this._sendState.subarray(72))) {
|
||||
this.destroy(new Error('udp send nonce exchausted'))
|
||||
return
|
||||
}
|
||||
|
||||
const secret = this._sendState.subarray(0, 32)
|
||||
const envelope = b4a.allocUnsafe(8 + MB + buffer.byteLength)
|
||||
const nonce = envelope.subarray(0, NB)
|
||||
const ciphertext = envelope.subarray(8)
|
||||
|
||||
b4a.fill(nonce, 0) // pad suffix
|
||||
nonce.set(counter)
|
||||
|
||||
sodium.crypto_secretbox_easy(ciphertext, buffer, nonce, secret)
|
||||
return envelope
|
||||
}
|
||||
|
||||
send(buffer) {
|
||||
if (!this._sendState) return
|
||||
if (!this.rawStream?.send) return // udx-stream expected
|
||||
|
||||
const message = this._boxMessage(buffer)
|
||||
return this.rawStream.send(message)
|
||||
}
|
||||
|
||||
trySend(buffer) {
|
||||
if (!this._sendState) return
|
||||
if (!this.rawStream?.trySend) return // udx-stream expected
|
||||
|
||||
const message = this._boxMessage(buffer)
|
||||
this.rawStream.trySend(message)
|
||||
}
|
||||
|
||||
_onmessage(buffer) {
|
||||
if (!this._sendState) return // messages before handshake are dropped
|
||||
|
||||
const MB = sodium.crypto_secretbox_MACBYTES // 16
|
||||
const NB = sodium.crypto_secretbox_NONCEBYTES // 24
|
||||
|
||||
if (buffer.byteLength < NB) return // Invalid message
|
||||
|
||||
const nonce = b4a.allocUnsafe(NB)
|
||||
b4a.fill(nonce, 0)
|
||||
nonce.set(buffer.subarray(0, 8))
|
||||
|
||||
const secret = this._sendState.subarray(32, 64)
|
||||
const ciphertext = buffer.subarray(8)
|
||||
const plain = buffer.subarray(8, buffer.byteLength - MB)
|
||||
|
||||
if (ciphertext.byteLength < MB) return // invalid message
|
||||
|
||||
const success = sodium.crypto_secretbox_open_easy(plain, ciphertext, nonce, secret)
|
||||
|
||||
if (success) this.emit('message', plain)
|
||||
}
|
||||
|
||||
alloc(len) {
|
||||
const buf = b4a.allocUnsafe(len + 3 + ABYTES)
|
||||
this._outgoingWrapped = buf
|
||||
this._outgoingPlain = buf.subarray(4, buf.byteLength - ABYTES + 1)
|
||||
return this._outgoingPlain
|
||||
}
|
||||
|
||||
toJSON() {
|
||||
return {
|
||||
isInitiator: this.isInitiator,
|
||||
publicKey: this.publicKey && b4a.toString(this.publicKey, 'hex'),
|
||||
remotePublicKey: this.remotePublicKey && b4a.toString(this.remotePublicKey, 'hex'),
|
||||
connected: this.connected,
|
||||
destroying: this.destroying,
|
||||
destroyed: this.destroyed,
|
||||
rawStream: this.rawStream && this.rawStream.toJSON ? this.rawStream.toJSON() : null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function writeUint24le(n, buf) {
|
||||
buf[0] = n & 255
|
||||
buf[1] = (n >>> 8) & 255
|
||||
buf[2] = (n >>> 16) & 255
|
||||
}
|
||||
|
||||
function streamId(handshakeHash, isInitiator, out = b4a.allocUnsafe(32)) {
|
||||
sodium.crypto_generichash(out, isInitiator ? NS_INITIATOR : NS_RESPONDER, handshakeHash)
|
||||
return out
|
||||
}
|
||||
|
||||
function toBuffer(data) {
|
||||
return typeof data === 'string' ? b4a.from(data) : data
|
||||
}
|
||||
|
||||
function destroyTimeout() {
|
||||
this.destroy(new Error('Stream timed out'))
|
||||
}
|
||||
|
||||
function sendKeepAlive() {
|
||||
const empty = this.alloc(0)
|
||||
this.write(empty)
|
||||
}
|
||||
+76
@@ -0,0 +1,76 @@
|
||||
const { Duplex, Writable } = require('streamx')
|
||||
|
||||
class ReversePassThrough extends Duplex {
|
||||
constructor(s) {
|
||||
super()
|
||||
this._stream = s
|
||||
this._ondrain = null
|
||||
}
|
||||
|
||||
_write(data, cb) {
|
||||
if (this._stream.push(data) === false) {
|
||||
this._stream._ondrain = cb
|
||||
} else {
|
||||
cb(null)
|
||||
}
|
||||
}
|
||||
|
||||
_final(cb) {
|
||||
this._stream.push(null)
|
||||
cb(null)
|
||||
}
|
||||
|
||||
_read(cb) {
|
||||
const ondrain = this._ondrain
|
||||
this._ondrain = null
|
||||
if (ondrain) ondrain()
|
||||
cb(null)
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = class Bridge extends Duplex {
|
||||
constructor(noiseStream) {
|
||||
super()
|
||||
|
||||
this.noiseStream = noiseStream
|
||||
|
||||
this._ondrain = null
|
||||
this.reverse = new ReversePassThrough(this)
|
||||
}
|
||||
|
||||
get publicKey() {
|
||||
return this.noiseStream.publicKey
|
||||
}
|
||||
|
||||
get remotePublicKey() {
|
||||
return this.noiseStream.remotePublicKey
|
||||
}
|
||||
|
||||
get handshakeHash() {
|
||||
return this.noiseStream.handshakeHash
|
||||
}
|
||||
|
||||
flush() {
|
||||
return Writable.drained(this)
|
||||
}
|
||||
|
||||
_read(cb) {
|
||||
const ondrain = this._ondrain
|
||||
this._ondrain = null
|
||||
if (ondrain) ondrain()
|
||||
cb(null)
|
||||
}
|
||||
|
||||
_write(data, cb) {
|
||||
if (this.reverse.push(data) === false) {
|
||||
this.reverse._ondrain = cb
|
||||
} else {
|
||||
cb(null)
|
||||
}
|
||||
}
|
||||
|
||||
_final(cb) {
|
||||
this.reverse.push(null)
|
||||
cb(null)
|
||||
}
|
||||
}
|
||||
+78
@@ -0,0 +1,78 @@
|
||||
const sodium = require('sodium-universal')
|
||||
const curve = require('noise-curve-ed')
|
||||
const Noise = require('noise-handshake')
|
||||
const b4a = require('b4a')
|
||||
|
||||
const EMPTY = b4a.alloc(0)
|
||||
|
||||
module.exports = class Handshake {
|
||||
constructor(isInitiator, keyPair, remotePublicKey, pattern) {
|
||||
this.isInitiator = isInitiator
|
||||
this.keyPair = keyPair
|
||||
this.noise = new Noise(pattern, isInitiator, keyPair, { curve })
|
||||
this.noise.initialise(EMPTY, remotePublicKey)
|
||||
this.destroyed = false
|
||||
}
|
||||
|
||||
static keyPair(seed) {
|
||||
const publicKey = b4a.alloc(32)
|
||||
const secretKey = b4a.alloc(64)
|
||||
if (seed) sodium.crypto_sign_seed_keypair(publicKey, secretKey, seed)
|
||||
else sodium.crypto_sign_keypair(publicKey, secretKey)
|
||||
return { publicKey, secretKey }
|
||||
}
|
||||
|
||||
recv(data) {
|
||||
try {
|
||||
this.noise.recv(data)
|
||||
if (this.noise.complete) return this._return(null)
|
||||
return this.send()
|
||||
} catch {
|
||||
this.destroy()
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
// note that the data returned here is framed so we don't have to do an extra copy
|
||||
// when sending it...
|
||||
send() {
|
||||
try {
|
||||
const data = this.noise.send()
|
||||
const wrap = b4a.allocUnsafe(data.byteLength + 3)
|
||||
|
||||
writeUint24le(data.byteLength, wrap)
|
||||
wrap.set(data, 3)
|
||||
|
||||
return this._return(wrap)
|
||||
} catch {
|
||||
this.destroy()
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
destroy() {
|
||||
if (this.destroyed) return
|
||||
this.destroyed = true
|
||||
}
|
||||
|
||||
_return(data) {
|
||||
const tx = this.noise.complete ? b4a.toBuffer(this.noise.tx) : null
|
||||
const rx = this.noise.complete ? b4a.toBuffer(this.noise.rx) : null
|
||||
const hash = this.noise.complete ? b4a.toBuffer(this.noise.hash) : null
|
||||
const remotePublicKey = this.noise.complete ? b4a.toBuffer(this.noise.rs) : null
|
||||
|
||||
return {
|
||||
data,
|
||||
remotePublicKey,
|
||||
hash,
|
||||
tx,
|
||||
rx
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function writeUint24le(n, buf) {
|
||||
buf[0] = n & 255
|
||||
buf[1] = (n >>> 8) & 255
|
||||
buf[2] = (n >>> 16) & 255
|
||||
}
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
{
|
||||
"name": "@hyperswarm/secret-stream",
|
||||
"version": "6.9.1",
|
||||
"description": "Secret stream backed by Noise and libsodium's secretstream",
|
||||
"main": "index.js",
|
||||
"files": [
|
||||
"index.js",
|
||||
"lib/**.js"
|
||||
],
|
||||
"dependencies": {
|
||||
"b4a": "^1.1.0",
|
||||
"hypercore-crypto": "^3.3.1",
|
||||
"noise-curve-ed": "^2.0.1",
|
||||
"noise-handshake": "^4.0.0",
|
||||
"sodium-secretstream": "^1.1.0",
|
||||
"sodium-universal": "^5.0.0",
|
||||
"streamx": "^2.14.0",
|
||||
"timeout-refresh": "^2.0.0",
|
||||
"unslab": "^1.3.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"brittle": "^3.3.0",
|
||||
"prettier": "^3.6.2",
|
||||
"prettier-config-holepunch": "^2.0.0",
|
||||
"udx-native": "^1.13.2"
|
||||
},
|
||||
"scripts": {
|
||||
"format": "prettier --write .",
|
||||
"lint": "prettier --check .",
|
||||
"test": "brittle test.js"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/holepunchto/hyperswarm-secret-stream.git"
|
||||
},
|
||||
"author": "Mathias Buus (@mafintosh)",
|
||||
"license": "Apache-2.0",
|
||||
"bugs": {
|
||||
"url": "https://github.com/holepunchto/hyperswarm-secret-stream/issues"
|
||||
},
|
||||
"homepage": "https://github.com/holepunchto/hyperswarm-secret-stream"
|
||||
}
|
||||
+201
@@ -0,0 +1,201 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
+88
@@ -0,0 +1,88 @@
|
||||
# adaptive-timeout
|
||||
|
||||
Adaptive timeout calculation with EWMA-based tracking and fallback strategies.
|
||||
|
||||
## Install
|
||||
|
||||
```
|
||||
npm install adaptive-timeout
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
```js
|
||||
const AdaptiveTimeout = require('adaptive-timeout')
|
||||
|
||||
const timeouts = new AdaptiveTimeout()
|
||||
|
||||
// Record a sample when you get a response
|
||||
timeouts.put('10.0.0.1:8080', 150)
|
||||
|
||||
// Get timeout for next request (attempt 1, 2, 3...)
|
||||
timeouts.get('10.0.0.1:8080', 1) // adaptive based on recorded samples
|
||||
timeouts.get('unknown-peer', 1) // uses fallback strategy
|
||||
```
|
||||
|
||||
## API
|
||||
|
||||
#### `const timeouts = new AdaptiveTimeout([options])`
|
||||
|
||||
Create a new instance.
|
||||
|
||||
Options:
|
||||
|
||||
- `maxSize` - max cache entries (default: `65536`)
|
||||
- `maxAge` - entry TTL in ms (default: `600000` / 10 minutes)
|
||||
- `fallback` - timeout sequence for unknown keys (default: `[500, 750, 1000, 1500, 2000]`)
|
||||
- `min` - minimum timeout for known keys (default: `300`)
|
||||
- `max` - maximum timeout for known keys (default: `5000`)
|
||||
- `jitter` - random jitter range in ms (default: `256`)
|
||||
|
||||
#### `timeouts.put(key, value)`
|
||||
|
||||
Record a sample. Updates the exponentially weighted moving average.
|
||||
|
||||
Returns `{ avg, variance }`.
|
||||
|
||||
#### `timeouts.get(key, [attempt])`
|
||||
|
||||
Get a timeout value.
|
||||
|
||||
For known keys: calculates adaptive timeout with linear backoff based on attempt number.
|
||||
|
||||
For unknown keys: returns value from fallback sequence based on attempt number.
|
||||
|
||||
#### `timeouts.getValue(key)`
|
||||
|
||||
Get raw stats for a key. Returns `{ avg, variance }` or `null`.
|
||||
|
||||
#### `timeouts.has(key)`
|
||||
|
||||
Check if a key exists.
|
||||
|
||||
#### `timeouts.delete(key)`
|
||||
|
||||
Remove a key.
|
||||
|
||||
#### `timeouts.clear()`
|
||||
|
||||
Remove all entries.
|
||||
|
||||
#### `timeouts.size`
|
||||
|
||||
Number of entries.
|
||||
|
||||
## How it works
|
||||
|
||||
Uses TCP-style EWMA (exponentially weighted moving average) to track values:
|
||||
|
||||
- `avg` blends 87.5% old + 12.5% new sample
|
||||
- `variance` blends 75% old + 25% new deviation
|
||||
|
||||
Timeout for known keys: `(avg + 2 * variance) * attempt + jitter`
|
||||
|
||||
Unknown keys use an aggressive fallback sequence to probe quickly.
|
||||
|
||||
## License
|
||||
|
||||
Apache 2.0
|
||||
+58
@@ -0,0 +1,58 @@
|
||||
declare module '@holepunchto/adaptive-timeout' {
|
||||
interface AdaptiveTimeoutOptions {
|
||||
maxSize?: number
|
||||
maxAge?: number
|
||||
fallback?: number[]
|
||||
min?: number
|
||||
max?: number
|
||||
jitter?: number
|
||||
}
|
||||
|
||||
interface Stats {
|
||||
avg: number
|
||||
variance: number
|
||||
}
|
||||
|
||||
declare class AdaptiveTimeout {
|
||||
constructor(opts?: AdaptiveTimeoutOptions)
|
||||
|
||||
getValue(key: string): Stats | null
|
||||
put(key: string, value: number): Stats
|
||||
get(key: string, attempt?: number): number
|
||||
has(key: string): boolean
|
||||
delete(key: string): boolean
|
||||
clear(): void
|
||||
|
||||
// Default - aggressive ramp
|
||||
static TimeoutAggressive: string[]
|
||||
|
||||
// Linear - steady increase
|
||||
static TimeoutLinear: string[]
|
||||
|
||||
// Exponential - slow start, rapid backoff
|
||||
static TimeoutExponential: string[]
|
||||
|
||||
// Gentle - conservative, patient
|
||||
static TimeoutGentle: string[]
|
||||
|
||||
// Fast - rapid fire retries
|
||||
static TimeoutFast: string[]
|
||||
|
||||
// U-shape - long, short, long
|
||||
static TimeoutUShape: string[]
|
||||
|
||||
// Inverse U - short, long, short
|
||||
static TimeoutInverseU: string[]
|
||||
|
||||
// Sawtooth - alternating fast/slow
|
||||
static TimeoutSawtooth: string[]
|
||||
|
||||
// Plateau - quick ramp then steady
|
||||
static TimeoutPlateau: string[]
|
||||
|
||||
// Logarithmic - diminishing increases
|
||||
static TimeoutLogarithmic: string[]
|
||||
}
|
||||
|
||||
export = AdaptiveTimeout
|
||||
}
|
||||
+93
@@ -0,0 +1,93 @@
|
||||
const Cache = require('xache')
|
||||
|
||||
module.exports = class AdaptiveTimeout {
|
||||
constructor(opts = {}) {
|
||||
this._cache = new Cache({
|
||||
maxSize: opts.maxSize || 65536,
|
||||
maxAge: opts.maxAge || 10 * 60 * 1000 // 10 minutes
|
||||
})
|
||||
this._fallback = opts.fallback || AdaptiveTimeout.TimeoutExponential
|
||||
this._min = opts.min ?? 300
|
||||
this._max = opts.max || 4000
|
||||
this._jitter = opts.jitter ?? 256
|
||||
}
|
||||
|
||||
// Default - aggressive ramp
|
||||
static TimeoutAggressive = [500, 750, 1000, 1500, 2000]
|
||||
|
||||
// Linear - steady increase
|
||||
static TimeoutLinear = [500, 1000, 1500, 2000, 2500]
|
||||
|
||||
// Exponential - slow start, rapid backoff
|
||||
static TimeoutExponential = [250, 500, 1000, 2000, 4000]
|
||||
|
||||
// Gentle - conservative, patient
|
||||
static TimeoutGentle = [1000, 1250, 1500, 1750, 2000]
|
||||
|
||||
// Fast - rapid fire retries
|
||||
static TimeoutFast = [200, 400, 600, 800, 1000]
|
||||
|
||||
// U-shape - long, short, long
|
||||
static TimeoutUShape = [1500, 750, 500, 750, 1500]
|
||||
|
||||
// Inverse U - short, long, short
|
||||
static TimeoutInverseU = [500, 1000, 1500, 1000, 500]
|
||||
|
||||
// Sawtooth - alternating fast/slow
|
||||
static TimeoutSawtooth = [500, 1500, 500, 1500, 500]
|
||||
|
||||
// Plateau - quick ramp then steady
|
||||
static TimeoutPlateau = [500, 1000, 2000, 2000, 2000]
|
||||
|
||||
// Logarithmic - diminishing increases
|
||||
static TimeoutLogarithmic = [500, 1000, 1300, 1500, 1600]
|
||||
|
||||
getValue(key) {
|
||||
return this._cache.get(key)
|
||||
}
|
||||
|
||||
put(key, value) {
|
||||
let p = this._cache.get(key)
|
||||
|
||||
if (!p) {
|
||||
p = { avg: value, variance: value >> 1 }
|
||||
} else {
|
||||
// blend 75% old + 25% new deviation
|
||||
p.variance += (Math.abs(p.avg - value) - p.variance) >> 2
|
||||
// blend 87.5% old + 12.5% new sample
|
||||
p.avg += (value - p.avg) >> 3
|
||||
}
|
||||
|
||||
this._cache.set(key, p)
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
get(key, attempt = 1) {
|
||||
const p = this._cache.get(key)
|
||||
const jitter = (Math.random() * this._jitter) | 0
|
||||
|
||||
if (p) {
|
||||
// known - use adaptive with linear backoff
|
||||
const base = p.avg + (p.variance << 1)
|
||||
const backoff = base * attempt
|
||||
return Math.min(Math.max(backoff + jitter, this._min), this._max)
|
||||
} else {
|
||||
// unknown - use aggressive fallback
|
||||
const base = this._fallback[Math.min(attempt - 1, this._fallback.length - 1)]
|
||||
return base + jitter
|
||||
}
|
||||
}
|
||||
|
||||
has(key) {
|
||||
return this._cache.has(key)
|
||||
}
|
||||
|
||||
delete(key) {
|
||||
return this._cache.delete(key)
|
||||
}
|
||||
|
||||
clear() {
|
||||
this._cache.clear()
|
||||
}
|
||||
}
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
{
|
||||
"name": "adaptive-timeout",
|
||||
"version": "1.0.1",
|
||||
"description": "adaptive-timeout",
|
||||
"main": "index.js",
|
||||
"exports": {
|
||||
"./package": "./package.json",
|
||||
".": {
|
||||
"types": "./index.d.ts",
|
||||
"default": "./index.js"
|
||||
}
|
||||
},
|
||||
"files": [
|
||||
"package.json",
|
||||
"index.js",
|
||||
"index.d.ts"
|
||||
],
|
||||
"devDependencies": {
|
||||
"brittle": "^3.19.0",
|
||||
"lunte": "^1.2.0",
|
||||
"prettier": "^3.6.2",
|
||||
"prettier-config-holepunch": "^2.0.0"
|
||||
},
|
||||
"scripts": {
|
||||
"format": "prettier . --write",
|
||||
"test": "prettier . --check && lunte && brittle-bare test/index.js",
|
||||
"lint": "lunte"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/holepunchto/adaptive-timeout.git"
|
||||
},
|
||||
"author": "Holepunch Inc",
|
||||
"license": "Apache-2.0",
|
||||
"bugs": {
|
||||
"url": "https://github.com/holepunchto/adaptive-timeout/issues"
|
||||
},
|
||||
"homepage": "https://github.com/holepunchto/adaptive-timeout",
|
||||
"dependencies": {
|
||||
"xache": "^1.2.1"
|
||||
}
|
||||
}
|
||||
+201
@@ -0,0 +1,201 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
+153
@@ -0,0 +1,153 @@
|
||||
# Buffer for Array
|
||||
|
||||
Buffer for Array (B4A) provides a set of functions for bridging the gap between the Node.js `Buffer` class and the `Uint8Array` class. A browser compatibility layer is also included, making it possible to use B4A in both Node.js and browsers without having to worry about whether you're dealing with buffers or typed arrays.
|
||||
|
||||
## Installation
|
||||
|
||||
```sh
|
||||
npm i b4a
|
||||
```
|
||||
|
||||
### React Native
|
||||
|
||||
When imported from React Native `b4a` will make use of `react-native-b4a` for optimised buffer operations when available. All you need to do is install it:
|
||||
|
||||
```sh
|
||||
npm i react-native-b4a
|
||||
```
|
||||
|
||||
## API
|
||||
|
||||
#### `b4a.isBuffer(value)`
|
||||
|
||||
See https://nodejs.org/api/buffer.html#static-method-bufferisbufferobj
|
||||
|
||||
This will also return `true` when passed a `Uint8Array`.
|
||||
|
||||
#### `b4a.isEncoding(encoding)`
|
||||
|
||||
See https://nodejs.org/api/buffer.html#static-method-bufferisencodingencoding
|
||||
|
||||
#### `b4a.alloc(size[, fill[, encoding]])`
|
||||
|
||||
See https://nodejs.org/api/buffer.html#static-method-bufferallocsize-fill-encoding
|
||||
|
||||
#### `b4a.allocUnsafe(size)`
|
||||
|
||||
See https://nodejs.org/api/buffer.html#static-method-bufferallocunsafesize
|
||||
|
||||
#### `b4a.allocUnsafeSlow(size)`
|
||||
|
||||
See https://nodejs.org/api/buffer.html#static-method-bufferallocunsafeslowsize
|
||||
|
||||
#### `b4a.byteLength(string)`
|
||||
|
||||
See https://nodejs.org/api/buffer.html#static-method-bufferbytelengthstring-encoding
|
||||
|
||||
#### `b4a.compare(buf1, buf2)`
|
||||
|
||||
See https://nodejs.org/api/buffer.html#static-method-buffercomparebuf1-buf2
|
||||
|
||||
#### `b4a.concat(buffers[, totalLength])`
|
||||
|
||||
See https://nodejs.org/api/buffer.html#static-method-bufferconcatlist-totallength
|
||||
|
||||
#### `b4a.copy(source, target[, targetStart[, sourceStart[, sourceEnd]]])`
|
||||
|
||||
See https://nodejs.org/api/buffer.html#bufcopytarget-targetstart-sourcestart-sourceend
|
||||
|
||||
#### `b4a.equals(buf1, buf2)`
|
||||
|
||||
See https://nodejs.org/api/buffer.html#bufequalsotherbuffer
|
||||
|
||||
#### `b4a.fill(buffer, value[, offset[, end]][, encoding])`
|
||||
|
||||
See https://nodejs.org/api/buffer.html#buffillvalue-offset-end-encoding
|
||||
|
||||
#### `b4a.from(array)`
|
||||
|
||||
See https://nodejs.org/api/buffer.html#static-method-bufferfromarray
|
||||
|
||||
#### `b4a.from(arrayBuffer[, byteOffset[, length]])`
|
||||
|
||||
See https://nodejs.org/api/buffer.html#static-method-bufferfromarraybuffer-byteoffset-length
|
||||
|
||||
#### `b4a.from(buffer)`
|
||||
|
||||
See https://nodejs.org/api/buffer.html#static-method-bufferfrombuffer
|
||||
|
||||
#### `b4a.from(string[, encoding])`
|
||||
|
||||
See https://nodejs.org/api/buffer.html#static-method-bufferfromstring-encoding
|
||||
|
||||
#### `b4a.includes(buffer, value[, byteOffset][, encoding])`
|
||||
|
||||
See https://nodejs.org/api/buffer.html#bufincludesvalue-byteoffset-encoding
|
||||
|
||||
#### `b4a.indexOf(buffer, value[, byteOffset][, encoding])`
|
||||
|
||||
See https://nodejs.org/api/buffer.html#bufindexofvalue-byteoffset-encoding
|
||||
|
||||
#### `b4a.lastIndexOf(buffer, value[, byteOffset][, encoding])`
|
||||
|
||||
See https://nodejs.org/api/buffer.html#buflastindexofvalue-byteoffset-encoding
|
||||
|
||||
#### `b4a.swap16(buffer)`
|
||||
|
||||
See https://nodejs.org/api/buffer.html#bufswap16
|
||||
|
||||
#### `b4a.swap32(buffer)`
|
||||
|
||||
See https://nodejs.org/api/buffer.html#bufswap32
|
||||
|
||||
#### `b4a.swap64(buffer)`
|
||||
|
||||
See https://nodejs.org/api/buffer.html#bufswap64
|
||||
|
||||
#### `b4a.toBuffer(buffer)`
|
||||
|
||||
Convert a buffer to its canonical representation. In Node.js, the canonical representation is a `Buffer`. In the browser, the canonical representation is a `Uint8Array`.
|
||||
|
||||
#### `b4a.toString(buffer, [encoding[, start[, end]]])`
|
||||
|
||||
See https://nodejs.org/api/buffer.html#buftostringencoding-start-end
|
||||
|
||||
#### `b4a.write(buffer, string[, offset[, length]][, encoding])`
|
||||
|
||||
See https://nodejs.org/api/buffer.html#bufwritestring-offset-length-encoding
|
||||
|
||||
#### `b4a.writeDoubleLE(buffer, value[, offset])`
|
||||
|
||||
See https://nodejs.org/api/buffer.html#bufwritedoublelevalue-offset
|
||||
|
||||
#### `b4a.writeFloatLE(buffer, value[, offset])`
|
||||
|
||||
See https://nodejs.org/api/buffer.html#bufwritefloatlevalue-offset
|
||||
|
||||
#### `b4a.writeUInt32LE(buffer, value[, offset])`
|
||||
|
||||
https://nodejs.org/api/buffer.html#bufwriteuint32levalue-offset
|
||||
|
||||
#### `b4a.writeInt32LE(buffer, value[, offset])`
|
||||
|
||||
See https://nodejs.org/api/buffer.html#bufwriteint32levalue-offset
|
||||
|
||||
#### `b4a.readDoubleLE(buffer[, offset])`
|
||||
|
||||
See https://nodejs.org/api/buffer.html#bufreaddoubleleoffset
|
||||
|
||||
#### `b4a.readFloatLE(buffer[, offset])`
|
||||
|
||||
See https://nodejs.org/api/buffer.html#bufreadfloatleoffset
|
||||
|
||||
#### `b4a.readUInt32LE(buffer[, offset])`
|
||||
|
||||
See https://nodejs.org/api/buffer.html#bufreaduint32leoffset
|
||||
|
||||
#### `b4a.readInt32LE(buffer[, offset])`
|
||||
|
||||
See https://nodejs.org/api/buffer.html#bufreadint32leoffset
|
||||
|
||||
## License
|
||||
|
||||
Apache 2.0
|
||||
+541
@@ -0,0 +1,541 @@
|
||||
const ascii = require('./lib/ascii')
|
||||
const base64 = require('./lib/base64')
|
||||
const hex = require('./lib/hex')
|
||||
const latin1 = require('./lib/latin1')
|
||||
const utf8 = require('./lib/utf8')
|
||||
const utf16le = require('./lib/utf16le')
|
||||
|
||||
const LE = new Uint8Array(Uint16Array.of(0xff).buffer)[0] === 0xff
|
||||
|
||||
function codecFor(encoding) {
|
||||
switch (encoding) {
|
||||
case 'ascii':
|
||||
return ascii
|
||||
case 'base64':
|
||||
return base64
|
||||
case 'hex':
|
||||
return hex
|
||||
case 'binary':
|
||||
case 'latin1':
|
||||
return latin1
|
||||
case 'utf8':
|
||||
case 'utf-8':
|
||||
case undefined:
|
||||
case null:
|
||||
return utf8
|
||||
case 'ucs2':
|
||||
case 'ucs-2':
|
||||
case 'utf16le':
|
||||
case 'utf-16le':
|
||||
return utf16le
|
||||
default:
|
||||
throw new Error(`Unknown encoding '${encoding}'`)
|
||||
}
|
||||
}
|
||||
|
||||
function isBuffer(value) {
|
||||
return value instanceof Uint8Array
|
||||
}
|
||||
|
||||
function isEncoding(encoding) {
|
||||
try {
|
||||
codecFor(encoding)
|
||||
return true
|
||||
} catch {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
function alloc(size, fill, encoding) {
|
||||
const buffer = new Uint8Array(size)
|
||||
if (fill !== undefined) {
|
||||
exports.fill(buffer, fill, 0, buffer.byteLength, encoding)
|
||||
}
|
||||
return buffer
|
||||
}
|
||||
|
||||
function allocUnsafe(size) {
|
||||
return new Uint8Array(size)
|
||||
}
|
||||
|
||||
function allocUnsafeSlow(size) {
|
||||
return new Uint8Array(size)
|
||||
}
|
||||
|
||||
function byteLength(string, encoding) {
|
||||
return codecFor(encoding).byteLength(string)
|
||||
}
|
||||
|
||||
function compare(a, b) {
|
||||
if (a === b) return 0
|
||||
|
||||
const len = Math.min(a.byteLength, b.byteLength)
|
||||
|
||||
a = new DataView(a.buffer, a.byteOffset, a.byteLength)
|
||||
b = new DataView(b.buffer, b.byteOffset, b.byteLength)
|
||||
|
||||
let i = 0
|
||||
|
||||
for (let n = len - (len % 4); i < n; i += 4) {
|
||||
const x = a.getUint32(i, LE)
|
||||
const y = b.getUint32(i, LE)
|
||||
if (x !== y) break
|
||||
}
|
||||
|
||||
for (; i < len; i++) {
|
||||
const x = a.getUint8(i)
|
||||
const y = b.getUint8(i)
|
||||
if (x < y) return -1
|
||||
if (x > y) return 1
|
||||
}
|
||||
|
||||
return a.byteLength > b.byteLength ? 1 : a.byteLength < b.byteLength ? -1 : 0
|
||||
}
|
||||
|
||||
function concat(buffers, length) {
|
||||
if (length === undefined) {
|
||||
length = buffers.reduce((len, buffer) => len + buffer.byteLength, 0)
|
||||
}
|
||||
|
||||
const result = new Uint8Array(length)
|
||||
|
||||
let offset = 0
|
||||
|
||||
for (const buffer of buffers) {
|
||||
if (offset + buffer.byteLength > result.byteLength) {
|
||||
result.set(buffer.subarray(0, result.byteLength - offset), offset)
|
||||
return result
|
||||
}
|
||||
|
||||
result.set(buffer, offset)
|
||||
offset += buffer.byteLength
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
function copy(source, target, targetStart = 0, sourceStart = 0, sourceEnd = source.byteLength) {
|
||||
if (targetStart < 0) targetStart = 0
|
||||
if (targetStart >= target.byteLength) return 0
|
||||
|
||||
const targetLength = target.byteLength - targetStart
|
||||
|
||||
if (sourceStart < 0) sourceStart = 0
|
||||
if (sourceStart >= source.byteLength) return 0
|
||||
|
||||
if (sourceEnd <= sourceStart) return 0
|
||||
if (sourceEnd > source.byteLength) sourceEnd = source.byteLength
|
||||
|
||||
if (sourceEnd - sourceStart > targetLength) {
|
||||
sourceEnd = sourceStart + targetLength
|
||||
}
|
||||
|
||||
const sourceLength = sourceEnd - sourceStart
|
||||
|
||||
if (source === target) {
|
||||
target.copyWithin(targetStart, sourceStart, sourceEnd)
|
||||
} else {
|
||||
if (sourceStart !== 0 || sourceEnd !== source.byteLength) {
|
||||
source = source.subarray(sourceStart, sourceEnd)
|
||||
}
|
||||
|
||||
target.set(source, targetStart)
|
||||
}
|
||||
|
||||
return sourceLength
|
||||
}
|
||||
|
||||
function equals(a, b) {
|
||||
if (a === b) return true
|
||||
if (a.byteLength !== b.byteLength) return false
|
||||
|
||||
return compare(a, b) === 0
|
||||
}
|
||||
|
||||
function fill(buffer, value, offset = 0, end = buffer.byteLength, encoding = 'utf8') {
|
||||
if (typeof value === 'string') {
|
||||
if (typeof offset === 'string') {
|
||||
// fill(string, encoding)
|
||||
encoding = offset
|
||||
offset = 0
|
||||
end = buffer.byteLength
|
||||
} else if (typeof end === 'string') {
|
||||
// fill(string, offset, encoding)
|
||||
encoding = end
|
||||
end = buffer.byteLength
|
||||
}
|
||||
} else if (typeof value === 'number') {
|
||||
value = value & 0xff
|
||||
} else if (typeof value === 'boolean') {
|
||||
value = +value
|
||||
}
|
||||
|
||||
if (offset < 0) offset = 0
|
||||
if (offset >= buffer.byteLength) return buffer
|
||||
|
||||
if (end <= offset) return buffer
|
||||
if (end > buffer.byteLength) end = buffer.byteLength
|
||||
|
||||
if (typeof value === 'number') return buffer.fill(value, offset, end)
|
||||
|
||||
if (typeof value === 'string') value = exports.from(value, encoding)
|
||||
|
||||
const len = value.byteLength
|
||||
|
||||
for (let i = 0, n = end - offset; i < n; ++i) {
|
||||
buffer[i + offset] = value[i % len]
|
||||
}
|
||||
|
||||
return buffer
|
||||
}
|
||||
|
||||
function from(value, encodingOrOffset, length) {
|
||||
// from(string, encoding)
|
||||
if (typeof value === 'string') return fromString(value, encodingOrOffset)
|
||||
|
||||
// from(array)
|
||||
if (Array.isArray(value)) return fromArray(value)
|
||||
|
||||
// from(buffer)
|
||||
if (ArrayBuffer.isView(value)) return fromBuffer(value)
|
||||
|
||||
// from(arrayBuffer[, byteOffset[, length]])
|
||||
return fromArrayBuffer(value, encodingOrOffset, length)
|
||||
}
|
||||
|
||||
function fromString(string, encoding) {
|
||||
const codec = codecFor(encoding)
|
||||
const buffer = new Uint8Array(codec.byteLength(string))
|
||||
codec.write(buffer, string)
|
||||
return buffer
|
||||
}
|
||||
|
||||
function fromArray(array) {
|
||||
const buffer = new Uint8Array(array.length)
|
||||
buffer.set(array)
|
||||
return buffer
|
||||
}
|
||||
|
||||
function fromBuffer(buffer) {
|
||||
const copy = new Uint8Array(buffer.byteLength)
|
||||
copy.set(buffer)
|
||||
return copy
|
||||
}
|
||||
|
||||
function fromArrayBuffer(arrayBuffer, byteOffset, length) {
|
||||
return new Uint8Array(arrayBuffer, byteOffset, length)
|
||||
}
|
||||
|
||||
function includes(buffer, value, byteOffset, encoding) {
|
||||
return indexOf(buffer, value, byteOffset, encoding) !== -1
|
||||
}
|
||||
|
||||
function indexOf(buffer, value, byteOffset, encoding) {
|
||||
return bidirectionalIndexOf(buffer, value, byteOffset, encoding, true /* first */)
|
||||
}
|
||||
|
||||
function lastIndexOf(buffer, value, byteOffset, encoding) {
|
||||
return bidirectionalIndexOf(buffer, value, byteOffset, encoding, false /* last */)
|
||||
}
|
||||
|
||||
function bidirectionalIndexOf(buffer, value, byteOffset, encoding, first) {
|
||||
if (buffer.byteLength === 0) return -1
|
||||
|
||||
if (typeof byteOffset === 'string') {
|
||||
encoding = byteOffset
|
||||
byteOffset = 0
|
||||
} else if (byteOffset === undefined) {
|
||||
byteOffset = first ? 0 : buffer.length - 1
|
||||
} else if (byteOffset < 0) {
|
||||
byteOffset += buffer.byteLength
|
||||
}
|
||||
|
||||
if (byteOffset >= buffer.byteLength) {
|
||||
if (first) return -1
|
||||
else byteOffset = buffer.byteLength - 1
|
||||
} else if (byteOffset < 0) {
|
||||
if (first) byteOffset = 0
|
||||
else return -1
|
||||
}
|
||||
|
||||
if (typeof value === 'string') {
|
||||
value = from(value, encoding)
|
||||
} else if (typeof value === 'number') {
|
||||
value = value & 0xff
|
||||
|
||||
if (first) {
|
||||
return buffer.indexOf(value, byteOffset)
|
||||
} else {
|
||||
return buffer.lastIndexOf(value, byteOffset)
|
||||
}
|
||||
}
|
||||
|
||||
if (value.byteLength === 0) return -1
|
||||
|
||||
if (first) {
|
||||
let foundIndex = -1
|
||||
|
||||
for (let i = byteOffset; i < buffer.byteLength; i++) {
|
||||
if (buffer[i] === value[foundIndex === -1 ? 0 : i - foundIndex]) {
|
||||
if (foundIndex === -1) foundIndex = i
|
||||
if (i - foundIndex + 1 === value.byteLength) return foundIndex
|
||||
} else {
|
||||
if (foundIndex !== -1) i -= i - foundIndex
|
||||
foundIndex = -1
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (byteOffset + value.byteLength > buffer.byteLength) {
|
||||
byteOffset = buffer.byteLength - value.byteLength
|
||||
}
|
||||
|
||||
for (let i = byteOffset; i >= 0; i--) {
|
||||
let found = true
|
||||
|
||||
for (let j = 0; j < value.byteLength; j++) {
|
||||
if (buffer[i + j] !== value[j]) {
|
||||
found = false
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if (found) return i
|
||||
}
|
||||
}
|
||||
|
||||
return -1
|
||||
}
|
||||
|
||||
function swap(buffer, n, m) {
|
||||
const i = buffer[n]
|
||||
buffer[n] = buffer[m]
|
||||
buffer[m] = i
|
||||
}
|
||||
|
||||
function swap16(buffer) {
|
||||
const len = buffer.byteLength
|
||||
|
||||
if (len % 2 !== 0) {
|
||||
throw new RangeError('Buffer size must be a multiple of 16-bits')
|
||||
}
|
||||
|
||||
for (let i = 0; i < len; i += 2) swap(buffer, i, i + 1)
|
||||
|
||||
return buffer
|
||||
}
|
||||
|
||||
function swap32(buffer) {
|
||||
const len = buffer.byteLength
|
||||
|
||||
if (len % 4 !== 0) {
|
||||
throw new RangeError('Buffer size must be a multiple of 32-bits')
|
||||
}
|
||||
|
||||
for (let i = 0; i < len; i += 4) {
|
||||
swap(buffer, i, i + 3)
|
||||
swap(buffer, i + 1, i + 2)
|
||||
}
|
||||
|
||||
return buffer
|
||||
}
|
||||
|
||||
function swap64(buffer) {
|
||||
const len = buffer.byteLength
|
||||
|
||||
if (len % 8 !== 0) {
|
||||
throw new RangeError('Buffer size must be a multiple of 64-bits')
|
||||
}
|
||||
|
||||
for (let i = 0; i < len; i += 8) {
|
||||
swap(buffer, i, i + 7)
|
||||
swap(buffer, i + 1, i + 6)
|
||||
swap(buffer, i + 2, i + 5)
|
||||
swap(buffer, i + 3, i + 4)
|
||||
}
|
||||
|
||||
return buffer
|
||||
}
|
||||
|
||||
function toBuffer(buffer) {
|
||||
return buffer
|
||||
}
|
||||
|
||||
function toString(buffer, encoding = 'utf8', start = 0, end = buffer.byteLength) {
|
||||
// toString(buffer)
|
||||
if (arguments.length === 1) return utf8.toString(buffer)
|
||||
|
||||
// toString(buffer, encoding)
|
||||
if (arguments.length === 2) return codecFor(encoding).toString(buffer)
|
||||
|
||||
if (start < 0) start = 0
|
||||
if (start >= buffer.byteLength) return ''
|
||||
|
||||
if (end <= start) return ''
|
||||
if (end > buffer.byteLength) end = buffer.byteLength
|
||||
|
||||
if (start !== 0 || end !== buffer.byteLength) {
|
||||
buffer = buffer.subarray(start, end)
|
||||
}
|
||||
|
||||
return codecFor(encoding).toString(buffer)
|
||||
}
|
||||
|
||||
function write(buffer, string, offset = 0, length = buffer.byteLength, encoding) {
|
||||
// write(buffer, string)
|
||||
if (arguments.length === 2) return utf8.write(buffer, string)
|
||||
|
||||
if (typeof offset === 'string') {
|
||||
// write(buffer, string, encoding)
|
||||
encoding = offset
|
||||
offset = 0
|
||||
length = buffer.byteLength
|
||||
} else if (typeof length === 'string') {
|
||||
// write(buffer, string, offset, encoding)
|
||||
encoding = length
|
||||
length = buffer.byteLength - offset
|
||||
}
|
||||
|
||||
length = Math.min(length, exports.byteLength(string, encoding))
|
||||
|
||||
let start = offset
|
||||
if (start < 0) start = 0
|
||||
if (start >= buffer.byteLength) return 0
|
||||
|
||||
let end = offset + length
|
||||
if (end <= start) return 0
|
||||
if (end > buffer.byteLength) end = buffer.byteLength
|
||||
|
||||
if (start !== 0 || end !== buffer.byteLength) {
|
||||
buffer = buffer.subarray(start, end)
|
||||
}
|
||||
|
||||
return codecFor(encoding).write(buffer, string)
|
||||
}
|
||||
|
||||
function readDoubleBE(buffer, offset = 0) {
|
||||
const view = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength)
|
||||
return view.getFloat64(offset, false)
|
||||
}
|
||||
|
||||
function readDoubleLE(buffer, offset = 0) {
|
||||
const view = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength)
|
||||
return view.getFloat64(offset, true)
|
||||
}
|
||||
|
||||
function readFloatBE(buffer, offset = 0) {
|
||||
const view = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength)
|
||||
return view.getFloat32(offset, false)
|
||||
}
|
||||
|
||||
function readFloatLE(buffer, offset = 0) {
|
||||
const view = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength)
|
||||
return view.getFloat32(offset, true)
|
||||
}
|
||||
|
||||
function readInt32BE(buffer, offset = 0) {
|
||||
const view = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength)
|
||||
return view.getInt32(offset, false)
|
||||
}
|
||||
|
||||
function readInt32LE(buffer, offset = 0) {
|
||||
const view = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength)
|
||||
return view.getInt32(offset, true)
|
||||
}
|
||||
|
||||
function readUInt32BE(buffer, offset = 0) {
|
||||
const view = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength)
|
||||
return view.getUint32(offset, false)
|
||||
}
|
||||
|
||||
function readUInt32LE(buffer, offset = 0) {
|
||||
const view = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength)
|
||||
return view.getUint32(offset, true)
|
||||
}
|
||||
|
||||
function writeDoubleBE(buffer, value, offset = 0) {
|
||||
const view = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength)
|
||||
view.setFloat64(offset, value, false)
|
||||
return offset + 8
|
||||
}
|
||||
|
||||
function writeDoubleLE(buffer, value, offset = 0) {
|
||||
const view = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength)
|
||||
view.setFloat64(offset, value, true)
|
||||
return offset + 8
|
||||
}
|
||||
|
||||
function writeFloatBE(buffer, value, offset = 0) {
|
||||
const view = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength)
|
||||
view.setFloat32(offset, value, false)
|
||||
return offset + 4
|
||||
}
|
||||
|
||||
function writeFloatLE(buffer, value, offset = 0) {
|
||||
const view = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength)
|
||||
view.setFloat32(offset, value, true)
|
||||
return offset + 4
|
||||
}
|
||||
|
||||
function writeInt32BE(buffer, value, offset = 0) {
|
||||
const view = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength)
|
||||
view.setInt32(offset, value, false)
|
||||
return offset + 4
|
||||
}
|
||||
|
||||
function writeInt32LE(buffer, value, offset = 0) {
|
||||
const view = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength)
|
||||
view.setInt32(offset, value, true)
|
||||
return offset + 4
|
||||
}
|
||||
|
||||
function writeUInt32BE(buffer, value, offset = 0) {
|
||||
const view = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength)
|
||||
view.setUint32(offset, value, false)
|
||||
return offset + 4
|
||||
}
|
||||
|
||||
function writeUInt32LE(buffer, value, offset = 0) {
|
||||
const view = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength)
|
||||
view.setUint32(offset, value, true)
|
||||
return offset + 4
|
||||
}
|
||||
|
||||
module.exports = exports = {
|
||||
isBuffer,
|
||||
isEncoding,
|
||||
alloc,
|
||||
allocUnsafe,
|
||||
allocUnsafeSlow,
|
||||
byteLength,
|
||||
compare,
|
||||
concat,
|
||||
copy,
|
||||
equals,
|
||||
fill,
|
||||
from,
|
||||
includes,
|
||||
indexOf,
|
||||
lastIndexOf,
|
||||
swap16,
|
||||
swap32,
|
||||
swap64,
|
||||
toBuffer,
|
||||
toString,
|
||||
write,
|
||||
readDoubleBE,
|
||||
readDoubleLE,
|
||||
readFloatBE,
|
||||
readFloatLE,
|
||||
readInt32BE,
|
||||
readInt32LE,
|
||||
readUInt32BE,
|
||||
readUInt32LE,
|
||||
writeDoubleBE,
|
||||
writeDoubleLE,
|
||||
writeFloatBE,
|
||||
writeFloatLE,
|
||||
writeInt32BE,
|
||||
writeInt32LE,
|
||||
writeUInt32BE,
|
||||
writeUInt32LE
|
||||
}
|
||||
+188
@@ -0,0 +1,188 @@
|
||||
function isBuffer(value) {
|
||||
return Buffer.isBuffer(value) || value instanceof Uint8Array
|
||||
}
|
||||
|
||||
function isEncoding(encoding) {
|
||||
return Buffer.isEncoding(encoding)
|
||||
}
|
||||
|
||||
function alloc(size, fill, encoding) {
|
||||
return Buffer.alloc(size, fill, encoding)
|
||||
}
|
||||
|
||||
function allocUnsafe(size) {
|
||||
return Buffer.allocUnsafe(size)
|
||||
}
|
||||
|
||||
function allocUnsafeSlow(size) {
|
||||
return Buffer.allocUnsafeSlow(size)
|
||||
}
|
||||
|
||||
function byteLength(string, encoding) {
|
||||
return Buffer.byteLength(string, encoding)
|
||||
}
|
||||
|
||||
function compare(a, b) {
|
||||
return Buffer.compare(a, b)
|
||||
}
|
||||
|
||||
function concat(buffers, totalLength) {
|
||||
return Buffer.concat(buffers, totalLength)
|
||||
}
|
||||
|
||||
function copy(source, target, targetStart, start, end) {
|
||||
return toBuffer(source).copy(target, targetStart, start, end)
|
||||
}
|
||||
|
||||
function equals(a, b) {
|
||||
return toBuffer(a).equals(b)
|
||||
}
|
||||
|
||||
function fill(buffer, value, offset, end, encoding) {
|
||||
return toBuffer(buffer).fill(value, offset, end, encoding)
|
||||
}
|
||||
|
||||
function from(value, encodingOrOffset, length) {
|
||||
return Buffer.from(value, encodingOrOffset, length)
|
||||
}
|
||||
|
||||
function includes(buffer, value, byteOffset, encoding) {
|
||||
return toBuffer(buffer).includes(value, byteOffset, encoding)
|
||||
}
|
||||
|
||||
function indexOf(buffer, value, byfeOffset, encoding) {
|
||||
return toBuffer(buffer).indexOf(value, byfeOffset, encoding)
|
||||
}
|
||||
|
||||
function lastIndexOf(buffer, value, byteOffset, encoding) {
|
||||
return toBuffer(buffer).lastIndexOf(value, byteOffset, encoding)
|
||||
}
|
||||
|
||||
function swap16(buffer) {
|
||||
return toBuffer(buffer).swap16()
|
||||
}
|
||||
|
||||
function swap32(buffer) {
|
||||
return toBuffer(buffer).swap32()
|
||||
}
|
||||
|
||||
function swap64(buffer) {
|
||||
return toBuffer(buffer).swap64()
|
||||
}
|
||||
|
||||
function toBuffer(buffer) {
|
||||
if (Buffer.isBuffer(buffer)) return buffer
|
||||
return Buffer.from(buffer.buffer, buffer.byteOffset, buffer.byteLength)
|
||||
}
|
||||
|
||||
function toString(buffer, encoding, start, end) {
|
||||
return toBuffer(buffer).toString(encoding, start, end)
|
||||
}
|
||||
|
||||
function write(buffer, string, offset, length, encoding) {
|
||||
return toBuffer(buffer).write(string, offset, length, encoding)
|
||||
}
|
||||
|
||||
function readDoubleBE(buffer, offset) {
|
||||
return toBuffer(buffer).readDoubleBE(offset)
|
||||
}
|
||||
|
||||
function readDoubleLE(buffer, offset) {
|
||||
return toBuffer(buffer).readDoubleLE(offset)
|
||||
}
|
||||
|
||||
function readFloatBE(buffer, offset) {
|
||||
return toBuffer(buffer).readFloatBE(offset)
|
||||
}
|
||||
|
||||
function readFloatLE(buffer, offset) {
|
||||
return toBuffer(buffer).readFloatLE(offset)
|
||||
}
|
||||
|
||||
function readInt32BE(buffer, offset) {
|
||||
return toBuffer(buffer).readInt32BE(offset)
|
||||
}
|
||||
|
||||
function readInt32LE(buffer, offset) {
|
||||
return toBuffer(buffer).readInt32LE(offset)
|
||||
}
|
||||
|
||||
function readUInt32BE(buffer, offset) {
|
||||
return toBuffer(buffer).readUInt32BE(offset)
|
||||
}
|
||||
|
||||
function readUInt32LE(buffer, offset) {
|
||||
return toBuffer(buffer).readUInt32LE(offset)
|
||||
}
|
||||
|
||||
function writeDoubleBE(buffer, value, offset) {
|
||||
return toBuffer(buffer).writeDoubleBE(value, offset)
|
||||
}
|
||||
|
||||
function writeDoubleLE(buffer, value, offset) {
|
||||
return toBuffer(buffer).writeDoubleLE(value, offset)
|
||||
}
|
||||
|
||||
function writeFloatBE(buffer, value, offset) {
|
||||
return toBuffer(buffer).writeFloatBE(value, offset)
|
||||
}
|
||||
|
||||
function writeFloatLE(buffer, value, offset) {
|
||||
return toBuffer(buffer).writeFloatLE(value, offset)
|
||||
}
|
||||
|
||||
function writeInt32BE(buffer, value, offset) {
|
||||
return toBuffer(buffer).writeInt32BE(value, offset)
|
||||
}
|
||||
|
||||
function writeInt32LE(buffer, value, offset) {
|
||||
return toBuffer(buffer).writeInt32LE(value, offset)
|
||||
}
|
||||
|
||||
function writeUInt32BE(buffer, value, offset) {
|
||||
return toBuffer(buffer).writeUInt32BE(value, offset)
|
||||
}
|
||||
|
||||
function writeUInt32LE(buffer, value, offset) {
|
||||
return toBuffer(buffer).writeUInt32LE(value, offset)
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
isBuffer,
|
||||
isEncoding,
|
||||
alloc,
|
||||
allocUnsafe,
|
||||
allocUnsafeSlow,
|
||||
byteLength,
|
||||
compare,
|
||||
concat,
|
||||
copy,
|
||||
equals,
|
||||
fill,
|
||||
from,
|
||||
includes,
|
||||
indexOf,
|
||||
lastIndexOf,
|
||||
swap16,
|
||||
swap32,
|
||||
swap64,
|
||||
toBuffer,
|
||||
toString,
|
||||
write,
|
||||
readDoubleBE,
|
||||
readDoubleLE,
|
||||
readFloatBE,
|
||||
readFloatLE,
|
||||
readInt32BE,
|
||||
readInt32LE,
|
||||
readUInt32BE,
|
||||
readUInt32LE,
|
||||
writeDoubleBE,
|
||||
writeDoubleLE,
|
||||
writeFloatBE,
|
||||
writeFloatLE,
|
||||
writeInt32BE,
|
||||
writeInt32LE,
|
||||
writeUInt32BE,
|
||||
writeUInt32LE
|
||||
}
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
function byteLength(string) {
|
||||
return string.length
|
||||
}
|
||||
|
||||
function toString(buffer) {
|
||||
const len = buffer.byteLength
|
||||
|
||||
let result = ''
|
||||
|
||||
for (let i = 0; i < len; i++) {
|
||||
result += String.fromCharCode(buffer[i] & 0x7f)
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
function write(buffer, string) {
|
||||
const len = buffer.byteLength
|
||||
|
||||
for (let i = 0; i < len; i++) {
|
||||
buffer[i] = string.charCodeAt(i)
|
||||
}
|
||||
|
||||
return len
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
byteLength,
|
||||
toString,
|
||||
write
|
||||
}
|
||||
+64
@@ -0,0 +1,64 @@
|
||||
const alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
|
||||
|
||||
const codes = new Uint8Array(256)
|
||||
|
||||
for (let i = 0; i < alphabet.length; i++) {
|
||||
codes[alphabet.charCodeAt(i)] = i
|
||||
}
|
||||
|
||||
codes[/* - */ 0x2d] = 62
|
||||
codes[/* _ */ 0x5f] = 63
|
||||
|
||||
function byteLength(string) {
|
||||
let len = string.length
|
||||
|
||||
if (string.charCodeAt(len - 1) === 0x3d) len--
|
||||
if (len > 1 && string.charCodeAt(len - 1) === 0x3d) len--
|
||||
|
||||
return (len * 3) >>> 2
|
||||
}
|
||||
|
||||
function toString(buffer) {
|
||||
const len = buffer.byteLength
|
||||
|
||||
let result = ''
|
||||
|
||||
for (let i = 0; i < len; i += 3) {
|
||||
result +=
|
||||
alphabet[buffer[i] >> 2] +
|
||||
alphabet[((buffer[i] & 3) << 4) | (buffer[i + 1] >> 4)] +
|
||||
alphabet[((buffer[i + 1] & 15) << 2) | (buffer[i + 2] >> 6)] +
|
||||
alphabet[buffer[i + 2] & 63]
|
||||
}
|
||||
|
||||
if (len % 3 === 2) {
|
||||
result = result.substring(0, result.length - 1) + '='
|
||||
} else if (len % 3 === 1) {
|
||||
result = result.substring(0, result.length - 2) + '=='
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
function write(buffer, string) {
|
||||
const len = buffer.byteLength
|
||||
|
||||
for (let i = 0, j = 0; j < len; i += 4) {
|
||||
const a = codes[string.charCodeAt(i)]
|
||||
const b = codes[string.charCodeAt(i + 1)]
|
||||
const c = codes[string.charCodeAt(i + 2)]
|
||||
const d = codes[string.charCodeAt(i + 3)]
|
||||
|
||||
buffer[j++] = (a << 2) | (b >> 4)
|
||||
buffer[j++] = ((b & 15) << 4) | (c >> 2)
|
||||
buffer[j++] = ((c & 3) << 6) | (d & 63)
|
||||
}
|
||||
|
||||
return len
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
byteLength,
|
||||
toString,
|
||||
write
|
||||
}
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
function byteLength(string) {
|
||||
return string.length >>> 1
|
||||
}
|
||||
|
||||
function toString(buffer) {
|
||||
const len = buffer.byteLength
|
||||
|
||||
buffer = new DataView(buffer.buffer, buffer.byteOffset, len)
|
||||
|
||||
let result = ''
|
||||
let i = 0
|
||||
|
||||
for (let n = len - (len % 4); i < n; i += 4) {
|
||||
result += buffer.getUint32(i).toString(16).padStart(8, '0')
|
||||
}
|
||||
|
||||
for (; i < len; i++) {
|
||||
result += buffer.getUint8(i).toString(16).padStart(2, '0')
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
function write(buffer, string) {
|
||||
const len = buffer.byteLength
|
||||
|
||||
for (let i = 0; i < len; i++) {
|
||||
const a = hexValue(string.charCodeAt(i * 2))
|
||||
const b = hexValue(string.charCodeAt(i * 2 + 1))
|
||||
|
||||
if (a === undefined || b === undefined) {
|
||||
return i
|
||||
}
|
||||
|
||||
buffer[i] = (a << 4) | b
|
||||
}
|
||||
|
||||
return len
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
byteLength,
|
||||
toString,
|
||||
write
|
||||
}
|
||||
|
||||
function hexValue(char) {
|
||||
if (char >= 0x30 && char <= 0x39) return char - 0x30
|
||||
if (char >= 0x41 && char <= 0x46) return char - 0x41 + 10
|
||||
if (char >= 0x61 && char <= 0x66) return char - 0x61 + 10
|
||||
}
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
function byteLength(string) {
|
||||
return string.length
|
||||
}
|
||||
|
||||
function toString(buffer) {
|
||||
const len = buffer.byteLength
|
||||
|
||||
let result = ''
|
||||
|
||||
for (let i = 0; i < len; i++) {
|
||||
result += String.fromCharCode(buffer[i])
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
function write(buffer, string) {
|
||||
const len = buffer.byteLength
|
||||
|
||||
for (let i = 0; i < len; i++) {
|
||||
buffer[i] = string.charCodeAt(i)
|
||||
}
|
||||
|
||||
return len
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
byteLength,
|
||||
toString,
|
||||
write
|
||||
}
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
function byteLength(string) {
|
||||
return string.length * 2
|
||||
}
|
||||
|
||||
function toString(buffer) {
|
||||
const len = buffer.byteLength
|
||||
|
||||
let result = ''
|
||||
|
||||
for (let i = 0; i < len - 1; i += 2) {
|
||||
result += String.fromCharCode(buffer[i] + buffer[i + 1] * 256)
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
function write(buffer, string) {
|
||||
const len = buffer.byteLength
|
||||
|
||||
let units = len
|
||||
|
||||
for (let i = 0; i < string.length; ++i) {
|
||||
if ((units -= 2) < 0) break
|
||||
|
||||
const c = string.charCodeAt(i)
|
||||
const hi = c >> 8
|
||||
const lo = c % 256
|
||||
|
||||
buffer[i * 2] = lo
|
||||
buffer[i * 2 + 1] = hi
|
||||
}
|
||||
|
||||
return len
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
byteLength,
|
||||
toString,
|
||||
write
|
||||
}
|
||||
+144
@@ -0,0 +1,144 @@
|
||||
function byteLength(string) {
|
||||
let length = 0
|
||||
|
||||
for (let i = 0, n = string.length; i < n; i++) {
|
||||
const code = string.charCodeAt(i)
|
||||
|
||||
if (code >= 0xd800 && code <= 0xdbff && i + 1 < n) {
|
||||
const code = string.charCodeAt(i + 1)
|
||||
|
||||
if (code >= 0xdc00 && code <= 0xdfff) {
|
||||
length += 4
|
||||
i++
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
if (code <= 0x7f) length += 1
|
||||
else if (code <= 0x7ff) length += 2
|
||||
else length += 3
|
||||
}
|
||||
|
||||
return length
|
||||
}
|
||||
|
||||
let toString
|
||||
|
||||
if (typeof TextDecoder !== 'undefined') {
|
||||
const decoder = new TextDecoder()
|
||||
|
||||
toString = function toString(buffer) {
|
||||
return decoder.decode(buffer)
|
||||
}
|
||||
} else {
|
||||
toString = function toString(buffer) {
|
||||
const len = buffer.byteLength
|
||||
|
||||
let output = ''
|
||||
let i = 0
|
||||
|
||||
while (i < len) {
|
||||
let byte = buffer[i]
|
||||
|
||||
if (byte <= 0x7f) {
|
||||
output += String.fromCharCode(byte)
|
||||
i++
|
||||
continue
|
||||
}
|
||||
|
||||
let bytesNeeded = 0
|
||||
let codePoint = 0
|
||||
|
||||
if (byte <= 0xdf) {
|
||||
bytesNeeded = 1
|
||||
codePoint = byte & 0x1f
|
||||
} else if (byte <= 0xef) {
|
||||
bytesNeeded = 2
|
||||
codePoint = byte & 0x0f
|
||||
} else if (byte <= 0xf4) {
|
||||
bytesNeeded = 3
|
||||
codePoint = byte & 0x07
|
||||
}
|
||||
|
||||
if (len - i - bytesNeeded > 0) {
|
||||
let k = 0
|
||||
|
||||
while (k < bytesNeeded) {
|
||||
byte = buffer[i + k + 1]
|
||||
codePoint = (codePoint << 6) | (byte & 0x3f)
|
||||
k += 1
|
||||
}
|
||||
} else {
|
||||
codePoint = 0xfffd
|
||||
bytesNeeded = len - i
|
||||
}
|
||||
|
||||
output += String.fromCodePoint(codePoint)
|
||||
i += bytesNeeded + 1
|
||||
}
|
||||
|
||||
return output
|
||||
}
|
||||
}
|
||||
|
||||
let write
|
||||
|
||||
if (typeof TextEncoder !== 'undefined') {
|
||||
const encoder = new TextEncoder()
|
||||
|
||||
write = function write(buffer, string) {
|
||||
return encoder.encodeInto(string, buffer).written
|
||||
}
|
||||
} else {
|
||||
write = function write(buffer, string) {
|
||||
const len = buffer.byteLength
|
||||
|
||||
let i = 0
|
||||
let j = 0
|
||||
|
||||
while (i < string.length) {
|
||||
const code = string.codePointAt(i)
|
||||
|
||||
if (code <= 0x7f) {
|
||||
if (j + 1 > len) break
|
||||
buffer[j++] = code
|
||||
i++
|
||||
continue
|
||||
}
|
||||
|
||||
let count = 0
|
||||
let bits = 0
|
||||
|
||||
if (code <= 0x7ff) {
|
||||
count = 6
|
||||
bits = 0xc0
|
||||
} else if (code <= 0xffff) {
|
||||
count = 12
|
||||
bits = 0xe0
|
||||
} else if (code <= 0x1fffff) {
|
||||
count = 18
|
||||
bits = 0xf0
|
||||
}
|
||||
|
||||
if (j + count / 6 + 1 > len) break
|
||||
|
||||
buffer[j++] = bits | (code >> count)
|
||||
count -= 6
|
||||
|
||||
while (count >= 0) {
|
||||
buffer[j++] = 0x80 | ((code >> count) & 0x3f)
|
||||
count -= 6
|
||||
}
|
||||
|
||||
i += code >= 0x10000 ? 2 : 1
|
||||
}
|
||||
|
||||
return j
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
byteLength,
|
||||
toString,
|
||||
write
|
||||
}
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
{
|
||||
"name": "b4a",
|
||||
"version": "1.8.1",
|
||||
"description": "Bridging the gap between buffers and typed arrays",
|
||||
"exports": {
|
||||
"./package": "./package.json",
|
||||
".": {
|
||||
"react-native": "./react-native.js",
|
||||
"browser": "./browser.js",
|
||||
"default": "./index.js"
|
||||
}
|
||||
},
|
||||
"files": [
|
||||
"browser.js",
|
||||
"index.js",
|
||||
"react-native.js",
|
||||
"lib"
|
||||
],
|
||||
"scripts": {
|
||||
"format": "prettier --write . && lunte --fix",
|
||||
"lint": "prettier --check . && lunte",
|
||||
"test": "npm run test:bare && npm run test:node",
|
||||
"test:bare": "brittle-bare --coverage test.mjs",
|
||||
"test:node": "brittle-node --coverage test.mjs"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/holepunchto/b4a.git"
|
||||
},
|
||||
"author": "Holepunch",
|
||||
"license": "Apache-2.0",
|
||||
"bugs": {
|
||||
"url": "https://github.com/holepunchto/b4a/issues"
|
||||
},
|
||||
"homepage": "https://github.com/holepunchto/b4a#readme",
|
||||
"devDependencies": {
|
||||
"brittle": "^3.5.2",
|
||||
"lunte": "^1.7.0",
|
||||
"nanobench": "^3.0.0",
|
||||
"prettier": "^3.6.2",
|
||||
"prettier-config-holepunch": "^2.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react-native-b4a": "*"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"react-native-b4a": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
}
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
try {
|
||||
module.exports = require('react-native-b4a')
|
||||
} catch {
|
||||
module.exports = require('./browser')
|
||||
}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
cmake_minimum_required(VERSION 3.25)
|
||||
|
||||
find_package(cmake-bare REQUIRED PATHS node_modules/cmake-bare)
|
||||
|
||||
project(bare_abort C)
|
||||
|
||||
add_bare_module(bare_abort)
|
||||
|
||||
target_sources(
|
||||
${bare_abort}
|
||||
PRIVATE
|
||||
binding.c
|
||||
)
|
||||
+201
@@ -0,0 +1,201 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
# bare-abort
|
||||
|
||||
Cause abnormal program termination and generate a crash report.
|
||||
|
||||
```
|
||||
npm i bare-abort
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
```js
|
||||
const abort = require('bare-abort')
|
||||
|
||||
abort()
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
Apache-2.0
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
#include <assert.h>
|
||||
#include <bare.h>
|
||||
#include <js.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
static js_value_t *
|
||||
bare_abort(js_env_t *env, js_callback_info_t *info) {
|
||||
abort();
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static js_value_t *
|
||||
bare_abort_exports(js_env_t *env, js_value_t *exports) {
|
||||
int err;
|
||||
|
||||
#define V(name, fn) \
|
||||
{ \
|
||||
js_value_t *val; \
|
||||
err = js_create_function(env, name, -1, fn, NULL, &val); \
|
||||
assert(err == 0); \
|
||||
err = js_set_named_property(env, exports, name, val); \
|
||||
assert(err == 0); \
|
||||
}
|
||||
|
||||
V("abort", bare_abort)
|
||||
#undef V
|
||||
|
||||
return exports;
|
||||
}
|
||||
|
||||
BARE_MODULE(bare_abort, bare_abort_exports)
|
||||
+1
@@ -0,0 +1 @@
|
||||
module.exports = require.addon()
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
declare function abort(): never
|
||||
|
||||
export = abort
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
const binding = require('./binding')
|
||||
|
||||
module.exports = binding.abort
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
{
|
||||
"name": "bare-abort",
|
||||
"version": "2.0.13",
|
||||
"description": "Cause abnormal program termination and generate a crash report",
|
||||
"exports": {
|
||||
".": {
|
||||
"types": "./index.d.ts",
|
||||
"default": "./index.js"
|
||||
},
|
||||
"./package": "./package.json"
|
||||
},
|
||||
"files": [
|
||||
"index.js",
|
||||
"index.d.ts",
|
||||
"binding.c",
|
||||
"binding.js",
|
||||
"CMakeLists.txt",
|
||||
"prebuilds"
|
||||
],
|
||||
"addon": true,
|
||||
"scripts": {
|
||||
"test": "prettier . --check"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/holepunchto/bare-abort.git"
|
||||
},
|
||||
"author": "Holepunch",
|
||||
"license": "Apache-2.0",
|
||||
"bugs": {
|
||||
"url": "https://github.com/holepunchto/bare-abort/issues"
|
||||
},
|
||||
"homepage": "https://github.com/holepunchto/bare-abort#readme",
|
||||
"devDependencies": {
|
||||
"cmake-bare": "^1.1.7",
|
||||
"prettier": "^3.4.2",
|
||||
"prettier-config-standard": "^7.0.0"
|
||||
}
|
||||
}
|
||||
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
+201
@@ -0,0 +1,201 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
+156
@@ -0,0 +1,156 @@
|
||||
# bare-addon-resolve
|
||||
|
||||
Low-level addon resolution algorithm for Bare. The algorithm is implemented as a generator function that yields either package manifests to be read or resolution candidates to be tested by the caller. As a convenience, the main export is a synchronous and asynchronous iterable that relies on package manifests being read by a callback. For asynchronous iteration, the callback may return promises which will be awaited before being passed to the generator.
|
||||
|
||||
```
|
||||
npm i bare-addon-resolve
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
For synchronous resolution:
|
||||
|
||||
```js
|
||||
const resolve = require('bare-addon-resolve')
|
||||
|
||||
function readPackage(url) {
|
||||
// Read and parse `url` if it exists, otherwise `null`
|
||||
}
|
||||
|
||||
for (const resolution of resolve('./addon', new URL('file:///directory/'), readPackage)) {
|
||||
console.log(resolution)
|
||||
}
|
||||
```
|
||||
|
||||
For asynchronous resolution:
|
||||
|
||||
```js
|
||||
const resolve = require('bare-addon-resolve')
|
||||
|
||||
async function readPackage(url) {
|
||||
// Read and parse `url` if it exists, otherwise `null`
|
||||
}
|
||||
|
||||
for await (const resolution of resolve('./addon', new URL('file:///directory/'), readPackage)) {
|
||||
console.log(resolution)
|
||||
}
|
||||
```
|
||||
|
||||
## API
|
||||
|
||||
#### `const resolver = resolve(specifier, parentURL[, options][, readPackage])`
|
||||
|
||||
Resolve `specifier` relative to `parentURL`, which must be a WHATWG `URL` instance. `readPackage` is called with a `URL` instance for every package manifest to be read and must either return the parsed JSON package manifest, if it exists, or `null`. If `readPackage` returns a promise, synchronous iteration is not supported.
|
||||
|
||||
Options include:
|
||||
|
||||
```js
|
||||
options = {
|
||||
// A list of builtin addon specifiers. If matched, the protocol of the
|
||||
// resolved URL will be `builtinProtocol`.
|
||||
builtins: [],
|
||||
// The protocol to use for resolved builtin addon specifiers.
|
||||
builtinProtocol: 'builtin:',
|
||||
// Whether or not addons linked ahead-of-time should be resolved.
|
||||
linked: true,
|
||||
// The protocol to use for addons linked ahead-of-time.
|
||||
linkedProtocol: 'linked:',
|
||||
// The supported import conditions. "default" is always recognized.
|
||||
conditions: [],
|
||||
// An array reference which will contain the matched conditions when yielding
|
||||
// resolutions.
|
||||
matchedConditions: [],
|
||||
// The `<platform>-<arch>` combinations to look for when resolving dynamic
|
||||
// addons. If empty, only builtin specifiers can be resolved. In Bare,
|
||||
// pass `[Bare.Addon.host]`.
|
||||
hosts: [],
|
||||
// The file extensions to look for when resolving dynamic addons.
|
||||
extensions: [],
|
||||
// A map of preresolved imports with keys being serialized directory URLs and
|
||||
// values being "imports" maps.
|
||||
resolutions
|
||||
}
|
||||
```
|
||||
|
||||
#### `for (const resolution of resolver)`
|
||||
|
||||
Synchronously iterate the addon resolution candidates. The resolved addon is the first candidate that exists as a file on the file system.
|
||||
|
||||
#### `for await (const resolution of resolver)`
|
||||
|
||||
Asynchronously iterate the addon resolution candidates. If `readPackage` returns promises, these will be awaited. The same comments as `for (const resolution of resolver)` apply.
|
||||
|
||||
### Algorithm
|
||||
|
||||
The following generator functions implement the resolution algorithm. The yielded values have the following shape:
|
||||
|
||||
**Package manifest**
|
||||
|
||||
```js
|
||||
next.value = {
|
||||
package: URL
|
||||
}
|
||||
```
|
||||
|
||||
If the package manifest identified by `next.value.package` exists, `generator.next()` must be passed the parsed JSON value of the manifest. If it does not exist, pass `null` instead.
|
||||
|
||||
**Resolution candidate**
|
||||
|
||||
```js
|
||||
next.value = {
|
||||
resolution: URL
|
||||
}
|
||||
```
|
||||
|
||||
If the addon identified by `next.value.resolution` exists, `generator.next()` may be passed `true` to signal that the resolution for the current set of conditions has been identified. If it does not exist, pass `false` instead.
|
||||
|
||||
To drive the generator functions, a loop like the following can be used:
|
||||
|
||||
```js
|
||||
const generator = resolve.addon(specifier, parentURL)
|
||||
|
||||
let next = generator.next()
|
||||
|
||||
while (next.done !== true) {
|
||||
const value = next.value
|
||||
|
||||
if (value.package) {
|
||||
// Read and parse `value.package` if it exists, otherwise `null`
|
||||
let info
|
||||
|
||||
next = generator.next(info)
|
||||
} else {
|
||||
const resolution = value.resolution
|
||||
|
||||
// `true` if `resolution` was the correct candidate, otherwise `false`
|
||||
let resolved
|
||||
|
||||
next = generator.next(resolved)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Options are the same as `resolve()` for all functions.
|
||||
|
||||
> [!WARNING]
|
||||
> These functions are currently subject to change between minor releases. If using them directly, make sure to specify a tilde range (`~1.2.3`) when declaring the module dependency.
|
||||
|
||||
#### `const generator = resolve.addon(specifier, parentURL[, options])`
|
||||
|
||||
#### `const generator = resolve.url(url, parentURL[, options])`
|
||||
|
||||
#### `const generator = resolve.package(packageSpecifier, packageVersion, parentURL[, options])`
|
||||
|
||||
#### `const generator = resolve.packageSelf(packageName, packageSubpath, packageVersion, parentURL[, options])`
|
||||
|
||||
#### `const generator = resolve.preresolved(directoryURL, resolutions[, options])`
|
||||
|
||||
#### `const generator = resolve.file(filename, parentURL[, options])`
|
||||
|
||||
#### `const generator = resolve.directory(dirname, version, parentURL[, options])`
|
||||
|
||||
#### `const generator = resolve.linked(name, version[, options])`
|
||||
|
||||
## License
|
||||
|
||||
Apache-2.0
|
||||
+85
@@ -0,0 +1,85 @@
|
||||
import URL from 'bare-url'
|
||||
import { constants, type Builtins, type Conditions, type ResolutionsMap } from 'bare-module-resolve'
|
||||
|
||||
type JSON = string | number | boolean | JSON[] | { [key: string]: JSON }
|
||||
|
||||
interface ResolveOptions {
|
||||
builtinProtocol?: string
|
||||
builtins?: Builtins
|
||||
conditions?: Conditions
|
||||
extensions?: string[]
|
||||
host?: string
|
||||
hosts?: string[]
|
||||
linked?: boolean
|
||||
linkedProtocol?: string
|
||||
matchedConditions?: string[]
|
||||
resolutions?: ResolutionsMap
|
||||
}
|
||||
|
||||
declare function resolve(
|
||||
specifier: string,
|
||||
parentURL: URL,
|
||||
readPackage?: (url: URL) => JSON | null
|
||||
): Iterable<URL>
|
||||
|
||||
declare function resolve(
|
||||
specifier: string,
|
||||
parentURL: URL,
|
||||
readPackage: (url: URL) => Promise<JSON | null>
|
||||
): AsyncIterable<URL>
|
||||
|
||||
declare function resolve(
|
||||
specifier: string,
|
||||
parentURL: URL,
|
||||
opts: ResolveOptions,
|
||||
readPackage?: (url: URL) => JSON | null
|
||||
): Iterable<URL>
|
||||
|
||||
declare function resolve(
|
||||
specifier: string,
|
||||
parentURL: URL,
|
||||
opts: ResolveOptions,
|
||||
readPackage: (url: URL) => Promise<JSON | null>
|
||||
): AsyncIterable<URL>
|
||||
|
||||
declare namespace resolve {
|
||||
export { constants, type ResolveOptions }
|
||||
|
||||
export type Resolver = Generator<
|
||||
{ resolution: URL } | { package: URL },
|
||||
number,
|
||||
void | boolean | JSON | null
|
||||
>
|
||||
|
||||
export function addon(specifier: string, parentURL: URL, opts?: ResolveOptions): Resolver
|
||||
|
||||
export function url(specifier: string, parentURL: URL, opts?: ResolveOptions): Resolver
|
||||
|
||||
export function package(
|
||||
packageSpecifier: string,
|
||||
packageVersion: string,
|
||||
parentURL: URL,
|
||||
opts?: ResolveOptions
|
||||
): Resolver
|
||||
|
||||
export function packageSelf(
|
||||
packageName: string,
|
||||
packageSubpath: string,
|
||||
packageVersion: string,
|
||||
parentURL: URL,
|
||||
opts?: ResolveOptions
|
||||
): Resolver
|
||||
|
||||
export function file(filename: string, parentURL: URL, opts?: ResolveOptions): Resolver
|
||||
|
||||
export function directory(
|
||||
dirname: string,
|
||||
version: string,
|
||||
parentURL: URL,
|
||||
opts?: ResolveOptions
|
||||
): Resolver
|
||||
|
||||
export function linked(name: string, version?: string, opts?: ResolveOptions): Resolver
|
||||
}
|
||||
|
||||
export = resolve
|
||||
+471
@@ -0,0 +1,471 @@
|
||||
const resolve = require('bare-module-resolve')
|
||||
const { Version } = require('bare-semver')
|
||||
const errors = require('./lib/errors')
|
||||
|
||||
module.exports = exports = function resolve(specifier, parentURL, opts, readPackage) {
|
||||
if (typeof opts === 'function') {
|
||||
readPackage = opts
|
||||
opts = {}
|
||||
} else if (typeof readPackage !== 'function') {
|
||||
readPackage = defaultReadPackage
|
||||
}
|
||||
|
||||
return {
|
||||
*[Symbol.iterator]() {
|
||||
const generator = exports.addon(specifier, parentURL, opts)
|
||||
|
||||
let next = generator.next()
|
||||
|
||||
while (next.done !== true) {
|
||||
const value = next.value
|
||||
|
||||
if (value.package) {
|
||||
next = generator.next(readPackage(value.package))
|
||||
} else {
|
||||
next = generator.next(yield value.resolution)
|
||||
}
|
||||
}
|
||||
|
||||
return next.value
|
||||
},
|
||||
|
||||
async *[Symbol.asyncIterator]() {
|
||||
const generator = exports.addon(specifier, parentURL, opts)
|
||||
|
||||
let next = generator.next()
|
||||
|
||||
while (next.done !== true) {
|
||||
const value = next.value
|
||||
|
||||
if (value.package) {
|
||||
next = generator.next(await readPackage(value.package))
|
||||
} else {
|
||||
next = generator.next(yield value.resolution)
|
||||
}
|
||||
}
|
||||
|
||||
return next.value
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function defaultReadPackage() {
|
||||
return null
|
||||
}
|
||||
|
||||
const { UNRESOLVED, YIELDED, RESOLVED } = resolve.constants
|
||||
|
||||
exports.constants = {
|
||||
UNRESOLVED,
|
||||
YIELDED,
|
||||
RESOLVED
|
||||
}
|
||||
|
||||
exports.addon = function* (specifier, parentURL, opts = {}) {
|
||||
const { resolutions = null } = opts
|
||||
|
||||
if (exports.startsWithWindowsDriveLetter(specifier)) {
|
||||
specifier = '/' + specifier
|
||||
}
|
||||
|
||||
let status
|
||||
|
||||
if (resolutions) {
|
||||
status = yield* resolve.preresolved(specifier, resolutions, parentURL, opts)
|
||||
|
||||
if (status) return status
|
||||
}
|
||||
|
||||
status = yield* exports.url(specifier, parentURL, opts)
|
||||
|
||||
if (status) return status
|
||||
|
||||
let version = null
|
||||
|
||||
const i = specifier.lastIndexOf('@')
|
||||
|
||||
if (i > 0) {
|
||||
version = specifier.substring(i + 1)
|
||||
|
||||
try {
|
||||
Version.parse(version)
|
||||
|
||||
specifier = specifier.substring(0, i)
|
||||
} catch {
|
||||
version = null
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
specifier === '.' ||
|
||||
specifier === '..' ||
|
||||
specifier[0] === '/' ||
|
||||
specifier[0] === '\\' ||
|
||||
specifier.startsWith('./') ||
|
||||
specifier.startsWith('.\\') ||
|
||||
specifier.startsWith('../') ||
|
||||
specifier.startsWith('..\\')
|
||||
) {
|
||||
status = yield* exports.file(specifier, parentURL, opts)
|
||||
|
||||
if (status === RESOLVED) return status
|
||||
|
||||
return yield* exports.directory(specifier, version, parentURL, opts)
|
||||
}
|
||||
|
||||
return yield* exports.package(specifier, version, parentURL, opts)
|
||||
}
|
||||
|
||||
exports.url = function* (url, parentURL, opts = {}) {
|
||||
let resolution
|
||||
try {
|
||||
resolution = new URL(url)
|
||||
} catch {
|
||||
return UNRESOLVED
|
||||
}
|
||||
|
||||
const resolved = yield { resolution }
|
||||
|
||||
return resolved ? RESOLVED : YIELDED
|
||||
}
|
||||
|
||||
exports.package = function* (packageSpecifier, packageVersion, parentURL, opts = {}) {
|
||||
if (packageSpecifier === '') {
|
||||
throw errors.INVALID_ADDON_SPECIFIER(
|
||||
`Addon specifier '${packageSpecifier}' is not a valid package name`
|
||||
)
|
||||
}
|
||||
|
||||
let packageName
|
||||
|
||||
if (packageSpecifier[0] !== '@') {
|
||||
packageName = packageSpecifier.split('/', 1).join()
|
||||
} else {
|
||||
if (!packageSpecifier.includes('/')) {
|
||||
throw errors.INVALID_ADDON_SPECIFIER(
|
||||
`Addon specifier '${packageSpecifier}' is not a valid package name`
|
||||
)
|
||||
}
|
||||
|
||||
packageName = packageSpecifier.split('/', 2).join('/')
|
||||
}
|
||||
|
||||
if (packageName[0] === '.' || packageName.includes('\\') || packageName.includes('%')) {
|
||||
throw errors.INVALID_ADDON_SPECIFIER(
|
||||
`Addon specifier '${packageSpecifier}' is not a valid package name`
|
||||
)
|
||||
}
|
||||
|
||||
const packageSubpath = '.' + packageSpecifier.substring(packageName.length)
|
||||
|
||||
const status = yield* exports.packageSelf(
|
||||
packageName,
|
||||
packageSubpath,
|
||||
packageVersion,
|
||||
parentURL,
|
||||
opts
|
||||
)
|
||||
|
||||
if (status) return status
|
||||
|
||||
parentURL = new URL(parentURL.href)
|
||||
|
||||
do {
|
||||
const packageURL = new URL('node_modules/' + packageName + '/', parentURL)
|
||||
|
||||
parentURL.pathname = parentURL.pathname.substring(0, parentURL.pathname.lastIndexOf('/'))
|
||||
|
||||
const info = yield { package: new URL('package.json', packageURL) }
|
||||
|
||||
if (info) {
|
||||
return yield* exports.directory(packageSubpath, packageVersion, packageURL, opts)
|
||||
}
|
||||
} while (parentURL.pathname !== '' && parentURL.pathname !== '/')
|
||||
|
||||
return UNRESOLVED
|
||||
}
|
||||
|
||||
exports.packageSelf = function* (
|
||||
packageName,
|
||||
packageSubpath,
|
||||
packageVersion,
|
||||
parentURL,
|
||||
opts = {}
|
||||
) {
|
||||
for (const packageURL of resolve.lookupPackageScope(parentURL, opts)) {
|
||||
const info = yield { package: packageURL }
|
||||
|
||||
if (info) {
|
||||
if (info.name === packageName) {
|
||||
return yield* exports.directory(packageSubpath, packageVersion, packageURL, opts)
|
||||
}
|
||||
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return UNRESOLVED
|
||||
}
|
||||
|
||||
exports.lookupPrebuildsScope = function* lookupPrebuildsScope(url, opts = {}) {
|
||||
const scopeURL = new URL(url.href)
|
||||
|
||||
do {
|
||||
yield new URL('prebuilds/', scopeURL)
|
||||
|
||||
scopeURL.pathname = scopeURL.pathname.substring(0, scopeURL.pathname.lastIndexOf('/'))
|
||||
|
||||
if (
|
||||
scopeURL.pathname.length === 3 &&
|
||||
exports.isWindowsDriveLetter(scopeURL.pathname.substring(1))
|
||||
) {
|
||||
break
|
||||
}
|
||||
} while (scopeURL.pathname !== '' && scopeURL.pathname !== '/')
|
||||
}
|
||||
|
||||
exports.file = function* (filename, parentURL, opts = {}) {
|
||||
if (
|
||||
filename === '.' ||
|
||||
filename === '..' ||
|
||||
filename[filename.length - 1] === '/' ||
|
||||
filename[filename.length - 1] === '\\'
|
||||
) {
|
||||
return UNRESOLVED
|
||||
}
|
||||
|
||||
if (parentURL.protocol === 'file:' && /%2f|%5c/i.test(filename)) {
|
||||
throw errors.INVALID_ADDON_SPECIFIER(`Addon specifier '${filename}' is invalid`)
|
||||
}
|
||||
|
||||
const { extensions = [] } = opts
|
||||
|
||||
let status = UNRESOLVED
|
||||
|
||||
for (let ext of extensions) {
|
||||
if (filename.endsWith(ext)) ext = ''
|
||||
|
||||
if (yield { resolution: new URL(filename + ext, parentURL) }) {
|
||||
return RESOLVED
|
||||
}
|
||||
|
||||
status = YIELDED
|
||||
}
|
||||
|
||||
return status
|
||||
}
|
||||
|
||||
exports.directory = function* (dirname, version, parentURL, opts = {}) {
|
||||
const {
|
||||
host = null, // Shorthand for single host resolution
|
||||
hosts = host !== null ? [host] : [],
|
||||
builtins = [],
|
||||
matchedConditions = []
|
||||
} = opts
|
||||
|
||||
let directoryURL
|
||||
|
||||
if (dirname[dirname.length - 1] === '/' || dirname[dirname.length - 1] === '\\') {
|
||||
directoryURL = new URL(dirname, parentURL)
|
||||
} else {
|
||||
directoryURL = new URL(dirname + '/', parentURL)
|
||||
}
|
||||
|
||||
const unversioned = version === null
|
||||
|
||||
let name = null
|
||||
|
||||
const info = yield { package: new URL('package.json', directoryURL) }
|
||||
|
||||
if (info) {
|
||||
if (typeof info.name === 'string' && info.name !== '') {
|
||||
if (info.name.includes('__')) {
|
||||
throw errors.INVALID_PACKAGE_NAME(`Package name '${info.name}' is invalid`)
|
||||
}
|
||||
|
||||
name = info.name.replace(/\//g, '__').replace(/^@/, '')
|
||||
} else {
|
||||
return UNRESOLVED
|
||||
}
|
||||
|
||||
if (typeof info.version === 'string' && info.version !== '') {
|
||||
if (version !== null && info.version !== version) return UNRESOLVED
|
||||
|
||||
version = info.version
|
||||
}
|
||||
} else {
|
||||
return UNRESOLVED
|
||||
}
|
||||
|
||||
let status
|
||||
|
||||
status = yield* resolve.builtinTarget(name, version, builtins, opts)
|
||||
|
||||
if (status) return status
|
||||
|
||||
for (const prebuildsURL of exports.lookupPrebuildsScope(directoryURL, opts)) {
|
||||
status = UNRESOLVED
|
||||
|
||||
for (const host of hosts) {
|
||||
const conditions = host.split('-')
|
||||
|
||||
const universal = supportsUniversalPrebuilds(host)
|
||||
? conditions.with(1, 'universal').join('-')
|
||||
: null
|
||||
|
||||
matchedConditions.push(...conditions)
|
||||
|
||||
if (version !== null) {
|
||||
status |= yield* exports.file(host + '/' + name + '@' + version, prebuildsURL, opts)
|
||||
|
||||
if (universal) {
|
||||
status |= yield* exports.file(universal + '/' + name + '@' + version, prebuildsURL, opts)
|
||||
}
|
||||
}
|
||||
|
||||
if (unversioned) {
|
||||
status |= yield* exports.file(host + '/' + name, prebuildsURL, opts)
|
||||
|
||||
if (universal) {
|
||||
status |= yield* exports.file(universal + '/' + name, prebuildsURL, opts)
|
||||
}
|
||||
}
|
||||
|
||||
for (const _ of conditions) matchedConditions.pop()
|
||||
}
|
||||
|
||||
if (status === RESOLVED) return status
|
||||
}
|
||||
|
||||
return yield* exports.linked(name, version, opts)
|
||||
}
|
||||
|
||||
exports.linked = function* (name, version = null, opts = {}) {
|
||||
const {
|
||||
linked = true,
|
||||
host = null, // Shorthand for single host resolution
|
||||
hosts = host !== null ? [host] : [],
|
||||
matchedConditions = []
|
||||
} = opts
|
||||
|
||||
if (linked === false || hosts.length === 0) return UNRESOLVED
|
||||
|
||||
let status = UNRESOLVED
|
||||
|
||||
for (const host of hosts) {
|
||||
const [platform = null] = host.split('-', 1)
|
||||
|
||||
if (platform === null) continue
|
||||
|
||||
matchedConditions.push(platform)
|
||||
|
||||
status |= yield* platformArtefact(name, version, platform, opts)
|
||||
|
||||
matchedConditions.pop()
|
||||
}
|
||||
|
||||
return status
|
||||
}
|
||||
|
||||
function* platformArtefact(name, version = null, platform, opts = {}) {
|
||||
const { linkedProtocol = 'linked:' } = opts
|
||||
|
||||
if (platform === 'darwin' || platform === 'ios') {
|
||||
if (version !== null) {
|
||||
if (
|
||||
yield {
|
||||
resolution: new URL(`${linkedProtocol}${name}.${version}.framework/${name}.${version}`)
|
||||
}
|
||||
) {
|
||||
return RESOLVED
|
||||
}
|
||||
|
||||
if (platform === 'darwin') {
|
||||
if (
|
||||
yield {
|
||||
resolution: new URL(`${linkedProtocol}lib${name}.${version}.dylib`)
|
||||
}
|
||||
) {
|
||||
return RESOLVED
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
yield {
|
||||
resolution: new URL(`${linkedProtocol}${name}.framework/${name}`)
|
||||
}
|
||||
) {
|
||||
return RESOLVED
|
||||
}
|
||||
|
||||
if (platform === 'darwin') {
|
||||
if (
|
||||
yield {
|
||||
resolution: new URL(`${linkedProtocol}lib${name}.dylib`)
|
||||
}
|
||||
) {
|
||||
return RESOLVED
|
||||
}
|
||||
}
|
||||
|
||||
return YIELDED
|
||||
}
|
||||
|
||||
if (platform === 'linux' || platform === 'android') {
|
||||
if (version !== null) {
|
||||
if (
|
||||
yield {
|
||||
resolution: new URL(`${linkedProtocol}lib${name}.${version}.so`)
|
||||
}
|
||||
) {
|
||||
return RESOLVED
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
yield {
|
||||
resolution: new URL(`${linkedProtocol}lib${name}.so`)
|
||||
}
|
||||
) {
|
||||
return RESOLVED
|
||||
}
|
||||
|
||||
return YIELDED
|
||||
}
|
||||
|
||||
if (platform === 'win32') {
|
||||
if (version !== null) {
|
||||
if (
|
||||
yield {
|
||||
resolution: new URL(`${linkedProtocol}${name}-${version}.dll`)
|
||||
}
|
||||
) {
|
||||
return RESOLVED
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
yield {
|
||||
resolution: new URL(`${linkedProtocol}${name}.dll`)
|
||||
}
|
||||
) {
|
||||
return RESOLVED
|
||||
}
|
||||
}
|
||||
|
||||
return UNRESOLVED
|
||||
}
|
||||
|
||||
exports.isWindowsDriveLetter = resolve.isWindowsDriveLetter
|
||||
|
||||
exports.startsWithWindowsDriveLetter = resolve.startsWithWindowsDriveLetter
|
||||
|
||||
function supportsUniversalPrebuilds(host) {
|
||||
return (
|
||||
host === 'darwin-arm64' ||
|
||||
host === 'darwin-x64' ||
|
||||
host === 'ios-arm64-simulator' ||
|
||||
host === 'ios-x64-simulator'
|
||||
)
|
||||
}
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
declare class AddonResolveError extends Error {
|
||||
readonly code: string
|
||||
|
||||
static INVALID_ADDON_SPECIFIER(msg: string): AddonResolveError
|
||||
static INVALID_PACKAGE_NAME(msg: string): AddonResolveError
|
||||
}
|
||||
|
||||
export = AddonResolveError
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
module.exports = class AddonResolveError extends Error {
|
||||
constructor(msg, code, fn = AddonResolveError) {
|
||||
super(`${code}: ${msg}`)
|
||||
this.code = code
|
||||
|
||||
if (Error.captureStackTrace) {
|
||||
Error.captureStackTrace(this, fn)
|
||||
}
|
||||
}
|
||||
|
||||
get name() {
|
||||
return 'AddonResolveError'
|
||||
}
|
||||
|
||||
static INVALID_ADDON_SPECIFIER(msg) {
|
||||
return new AddonResolveError(
|
||||
msg,
|
||||
'INVALID_ADDON_SPECIFIER',
|
||||
AddonResolveError.INVALID_ADDON_SPECIFIER
|
||||
)
|
||||
}
|
||||
|
||||
static INVALID_PACKAGE_NAME(msg) {
|
||||
return new AddonResolveError(
|
||||
msg,
|
||||
'INVALID_PACKAGE_NAME',
|
||||
AddonResolveError.INVALID_PACKAGE_NAME
|
||||
)
|
||||
}
|
||||
}
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
{
|
||||
"name": "bare-addon-resolve",
|
||||
"version": "1.10.0",
|
||||
"description": "Low-level addon resolution algorithm for Bare",
|
||||
"exports": {
|
||||
"./package": "./package.json",
|
||||
".": {
|
||||
"types": "./index.d.ts",
|
||||
"default": "./index.js"
|
||||
},
|
||||
"./errors": {
|
||||
"types": "./lib/errors.d.ts",
|
||||
"default": "./lib/errors.js"
|
||||
}
|
||||
},
|
||||
"files": [
|
||||
"index.js",
|
||||
"index.d.ts",
|
||||
"lib"
|
||||
],
|
||||
"scripts": {
|
||||
"test": "prettier . --check && bare test.js"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/holepunchto/bare-addon-resolve.git"
|
||||
},
|
||||
"author": "Holepunch",
|
||||
"license": "Apache-2.0",
|
||||
"bugs": {
|
||||
"url": "https://github.com/holepunchto/bare-addon-resolve/issues"
|
||||
},
|
||||
"homepage": "https://github.com/holepunchto/bare-addon-resolve#readme",
|
||||
"dependencies": {
|
||||
"bare-module-resolve": "^1.10.0",
|
||||
"bare-semver": "^1.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"bare-url": "^2.1.3",
|
||||
"brittle": "^3.2.1",
|
||||
"prettier": "^3.3.3",
|
||||
"prettier-config-holepunch": "^2.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"bare-url": "*"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"bare-url": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
}
|
||||
+201
@@ -0,0 +1,201 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
# bare-ansi-escapes
|
||||
|
||||
Parse and produce ANSI escape sequences.
|
||||
|
||||
```
|
||||
npm i bare-ansi-escapes
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
```js
|
||||
const KeyDecoder = require('bare-ansi-escapes/key-decoder')
|
||||
|
||||
readableStream.pipe(new KeyDecoder()).on('data', (key) => console.log(key))
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
Apache-2.0
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
export const constants: { ESC: string; CSI: string; SGR: (n: number) => string }
|
||||
|
||||
export const cursorHide: string
|
||||
export const cursorShow: string
|
||||
|
||||
export function cursorUp(n?: number): string
|
||||
export function cursorDown(n?: number): string
|
||||
export function cursorForward(n?: number): string
|
||||
export function cursorBack(n?: number): string
|
||||
export function cursorNextLine(n?: number): string
|
||||
export function cursorPreviousLine(n?: number): string
|
||||
|
||||
export function cursorPosition(column: number, row?: number): string
|
||||
|
||||
export const eraseDisplayEnd: string
|
||||
export const eraseDisplayStart: string
|
||||
export const eraseDisplay: string
|
||||
export const eraseLineEnd: string
|
||||
export const eraseLineStart: string
|
||||
export const eraseLine: string
|
||||
|
||||
export function scrollUp(n?: number): string
|
||||
export function scrollDown(n?: number): string
|
||||
|
||||
export const modifierReset: string
|
||||
export const modifierBold: string
|
||||
export const modifierDim: string
|
||||
export const modifierItalic: string
|
||||
export const modifierUnderline: string
|
||||
export const modifierNormal: string
|
||||
export const modifierNotItalic: string
|
||||
export const modifierNotUnderline: string
|
||||
|
||||
export const colorBlack: string
|
||||
export const colorRed: string
|
||||
export const colorGreen: string
|
||||
export const colorYellow: string
|
||||
export const colorBlue: string
|
||||
export const colorMagenta: string
|
||||
export const colorCyan: string
|
||||
export const colorWhite: string
|
||||
export const colorDefault: string
|
||||
export const colorBrightBlack: string
|
||||
export const colorBrightRed: string
|
||||
export const colorBrightGreen: string
|
||||
export const colorBrightYellow: string
|
||||
export const colorBrightBlue: string
|
||||
export const colorBrightMagenta: string
|
||||
export const colorBrightCyan: string
|
||||
export const colorBrightWhite: string
|
||||
+90
@@ -0,0 +1,90 @@
|
||||
const ESC = '\x1b'
|
||||
const CSI = ESC + '['
|
||||
const SGR = (n) => CSI + n + 'm'
|
||||
|
||||
exports.constants = {
|
||||
ESC,
|
||||
CSI,
|
||||
SGR
|
||||
}
|
||||
|
||||
// https://en.wikipedia.org/wiki/ANSI_escape_code#CSI_(Control_Sequence_Introducer)_sequences
|
||||
|
||||
exports.cursorHide = CSI + '?25l'
|
||||
exports.cursorShow = CSI + '?25h'
|
||||
|
||||
exports.cursorUp = function cursorUp(n = 1) {
|
||||
return CSI + n + 'A'
|
||||
}
|
||||
|
||||
exports.cursorDown = function cursorDown(n = 1) {
|
||||
return CSI + n + 'B'
|
||||
}
|
||||
|
||||
exports.cursorForward = function cursorForward(n = 1) {
|
||||
return CSI + n + 'C'
|
||||
}
|
||||
|
||||
exports.cursorBack = function cursorBack(n = 1) {
|
||||
return CSI + n + 'D'
|
||||
}
|
||||
|
||||
exports.cursorNextLine = function cursorNextLine(n = 1) {
|
||||
return CSI + n + 'E'
|
||||
}
|
||||
|
||||
exports.cursorPreviousLine = function cursorPreviousLine(n = 1) {
|
||||
return CSI + n + 'F'
|
||||
}
|
||||
|
||||
exports.cursorPosition = function cursorPosition(column, row = 0) {
|
||||
if (row === 0) return CSI + (column + 1) + 'G'
|
||||
|
||||
return CSI + (row + 1) + ';' + (column + 1) + 'H'
|
||||
}
|
||||
|
||||
exports.eraseDisplayEnd = CSI + 'J'
|
||||
exports.eraseDisplayStart = CSI + '1J'
|
||||
exports.eraseDisplay = CSI + '2J'
|
||||
exports.eraseLineEnd = CSI + 'K'
|
||||
exports.eraseLineStart = CSI + '1K'
|
||||
exports.eraseLine = CSI + '2K'
|
||||
|
||||
exports.scrollUp = function scrollUp(n = 1) {
|
||||
return CSI + n + 'S'
|
||||
}
|
||||
|
||||
exports.scrollDown = function scrollDown(n = 1) {
|
||||
return CSI + n + 'T'
|
||||
}
|
||||
|
||||
// https://en.wikipedia.org/wiki/ANSI_escape_code#SGR_(Select_Graphic_Rendition)_parameters
|
||||
|
||||
exports.modifierReset = SGR(0)
|
||||
exports.modifierBold = SGR(1)
|
||||
exports.modifierDim = SGR(2)
|
||||
exports.modifierItalic = SGR(3)
|
||||
exports.modifierUnderline = SGR(4)
|
||||
exports.modifierNormal = SGR(22)
|
||||
exports.modifierNotItalic = SGR(23)
|
||||
exports.modifierNotUnderline = SGR(24)
|
||||
|
||||
// https://en.wikipedia.org/wiki/ANSI_escape_code#Colors
|
||||
|
||||
exports.colorBlack = SGR(30)
|
||||
exports.colorRed = SGR(31)
|
||||
exports.colorGreen = SGR(32)
|
||||
exports.colorYellow = SGR(33)
|
||||
exports.colorBlue = SGR(34)
|
||||
exports.colorMagenta = SGR(35)
|
||||
exports.colorCyan = SGR(36)
|
||||
exports.colorWhite = SGR(37)
|
||||
exports.colorDefault = SGR(39)
|
||||
exports.colorBrightBlack = SGR(90)
|
||||
exports.colorBrightRed = SGR(91)
|
||||
exports.colorBrightGreen = SGR(92)
|
||||
exports.colorBrightYellow = SGR(93)
|
||||
exports.colorBrightBlue = SGR(94)
|
||||
exports.colorBrightMagenta = SGR(95)
|
||||
exports.colorBrightCyan = SGR(96)
|
||||
exports.colorBrightWhite = SGR(97)
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
import { Transform, TransformEvents } from 'bare-stream'
|
||||
import { BufferEncoding } from 'bare-buffer'
|
||||
|
||||
interface KeyDecoderOptions {
|
||||
encoding?: BufferEncoding
|
||||
escapeCodeTimeout?: number
|
||||
}
|
||||
|
||||
interface KeyDecoderEvents extends TransformEvents {
|
||||
data: [key: Key]
|
||||
}
|
||||
|
||||
interface KeyDecoder<M extends KeyDecoderEvents = KeyDecoderEvents>
|
||||
extends Transform<M> {
|
||||
readonly encoding: BufferEncoding
|
||||
}
|
||||
|
||||
declare class KeyDecoder {
|
||||
constructor(opts?: KeyDecoderOptions)
|
||||
}
|
||||
|
||||
interface Key {
|
||||
readonly name: string
|
||||
readonly sequence: string
|
||||
readonly ctrl: boolean
|
||||
readonly meta: boolean
|
||||
readonly shift: boolean
|
||||
}
|
||||
|
||||
declare class Key {
|
||||
constructor(
|
||||
name: string | number,
|
||||
sequence: string,
|
||||
ctrl: boolean,
|
||||
meta: boolean,
|
||||
shift: boolean
|
||||
)
|
||||
}
|
||||
|
||||
declare namespace KeyDecoder {
|
||||
export type { KeyDecoderOptions, KeyDecoderEvents, Key }
|
||||
}
|
||||
|
||||
export = KeyDecoder
|
||||
+480
@@ -0,0 +1,480 @@
|
||||
const { Transform } = require('bare-stream')
|
||||
|
||||
const {
|
||||
constants: { ESC }
|
||||
} = require('.')
|
||||
|
||||
// https://en.wikipedia.org/wiki/ANSI_escape_code#Terminal_input_sequences
|
||||
|
||||
module.exports = class KeyDecoder extends Transform {
|
||||
constructor(opts = {}) {
|
||||
const { encoding = 'utf8', escapeCodeTimeout = 500 } = opts
|
||||
|
||||
super()
|
||||
|
||||
this.encoding = encoding
|
||||
|
||||
this._escapeDelay = escapeCodeTimeout
|
||||
this._escapeTimer = null
|
||||
|
||||
this._parser = parseKeys(this)
|
||||
this._parser.next()
|
||||
}
|
||||
|
||||
_transform(data, encoding, cb) {
|
||||
clearTimeout(this._escapeTimer)
|
||||
|
||||
if (data[0] > 127 && data.length === 1) {
|
||||
data[0] -= 128
|
||||
data = ESC + data.toString(this.encoding)
|
||||
} else {
|
||||
data = data.toString(this.encoding)
|
||||
}
|
||||
|
||||
let n = 0
|
||||
|
||||
for (const c of data) {
|
||||
n += c.length
|
||||
|
||||
this._parser.next(c)
|
||||
|
||||
if (n === data.length && c === ESC) {
|
||||
this._escapeTimer = setTimeout(
|
||||
this._escape.bind(this),
|
||||
this._escapeDelay
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
cb(null)
|
||||
}
|
||||
|
||||
_escape() {
|
||||
this._parser.next('')
|
||||
}
|
||||
}
|
||||
|
||||
class Key {
|
||||
constructor(name, sequence, ctrl, meta, shift) {
|
||||
this.name = typeof name === 'number' ? String.fromCharCode(name) : name
|
||||
this.sequence = sequence
|
||||
this.ctrl = ctrl
|
||||
this.meta = meta
|
||||
this.shift = shift
|
||||
}
|
||||
}
|
||||
|
||||
function charLengthAt(str, i) {
|
||||
if (str.length <= i) {
|
||||
return 1
|
||||
}
|
||||
|
||||
return str.codePointAt(i) >= 0x10000 ? 2 : 1
|
||||
}
|
||||
|
||||
function* parseKeys(stream) {
|
||||
while (true) {
|
||||
let c = yield
|
||||
let s = c
|
||||
let escaped = false
|
||||
|
||||
let name = null
|
||||
let ctrl = false
|
||||
let meta = false
|
||||
let shift = false
|
||||
|
||||
if (c === ESC) {
|
||||
escaped = true
|
||||
|
||||
s += c = yield
|
||||
|
||||
if (c === ESC) {
|
||||
s += c = yield
|
||||
}
|
||||
}
|
||||
|
||||
if (escaped && (c === 'O' || c === '[')) {
|
||||
let code = c
|
||||
let modifier = 0
|
||||
|
||||
if (c === 'O') {
|
||||
s += c = yield
|
||||
|
||||
if (c >= '0' && c <= '9') {
|
||||
modifier = (c >> 0) - 1
|
||||
s += c = yield
|
||||
}
|
||||
|
||||
code += c
|
||||
} else if (c === '[') {
|
||||
s += c = yield
|
||||
|
||||
if (c === '[') {
|
||||
code += c
|
||||
s += c = yield
|
||||
}
|
||||
|
||||
const start = s.length - 1
|
||||
|
||||
if (c >= '0' && c <= '9') {
|
||||
s += c = yield
|
||||
|
||||
if (c >= '0' && c <= '9') {
|
||||
s += c = yield
|
||||
|
||||
if (c >= '0' && c <= '9') {
|
||||
s += c = yield
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (c === ';') {
|
||||
s += c = yield
|
||||
|
||||
if (c >= '0' && c <= '9') {
|
||||
s += yield
|
||||
}
|
||||
}
|
||||
|
||||
const cmd = s.slice(start)
|
||||
|
||||
let match
|
||||
|
||||
if ((match = /^(?:(\d\d?)(?:;(\d))?([~^$])|(\d{3}~))$/.exec(cmd))) {
|
||||
if (match[4]) {
|
||||
code += match[4]
|
||||
} else {
|
||||
code += match[1] + match[3]
|
||||
modifier = (match[2] || 1) - 1
|
||||
}
|
||||
} else if ((match = /^((\d;)?(\d))?([A-Za-z])$/.exec(cmd))) {
|
||||
code += match[4]
|
||||
modifier = (match[3] || 1) - 1
|
||||
} else {
|
||||
code += cmd
|
||||
}
|
||||
}
|
||||
|
||||
ctrl = !!(modifier & 4)
|
||||
meta = !!(modifier & 10)
|
||||
shift = !!(modifier & 1)
|
||||
|
||||
switch (code) {
|
||||
/* xterm/gnome ESC [ letter (with modifier) */
|
||||
case '[P':
|
||||
name = 'f1'
|
||||
break
|
||||
case '[Q':
|
||||
name = 'f2'
|
||||
break
|
||||
case '[R':
|
||||
name = 'f3'
|
||||
break
|
||||
case '[S':
|
||||
name = 'f4'
|
||||
break
|
||||
|
||||
/* xterm/gnome ESC O letter (without modifier) */
|
||||
case 'OP':
|
||||
name = 'f1'
|
||||
break
|
||||
case 'OQ':
|
||||
name = 'f2'
|
||||
break
|
||||
case 'OR':
|
||||
name = 'f3'
|
||||
break
|
||||
case 'OS':
|
||||
name = 'f4'
|
||||
break
|
||||
|
||||
/* xterm/rxvt ESC [ number ~ */
|
||||
case '[11~':
|
||||
name = 'f1'
|
||||
break
|
||||
case '[12~':
|
||||
name = 'f2'
|
||||
break
|
||||
case '[13~':
|
||||
name = 'f3'
|
||||
break
|
||||
case '[14~':
|
||||
name = 'f4'
|
||||
break
|
||||
|
||||
/* paste bracket mode */
|
||||
case '[200~':
|
||||
name = 'paste-start'
|
||||
break
|
||||
case '[201~':
|
||||
name = 'paste-end'
|
||||
break
|
||||
|
||||
/* from Cygwin and used in libuv */
|
||||
case '[[A':
|
||||
name = 'f1'
|
||||
break
|
||||
case '[[B':
|
||||
name = 'f2'
|
||||
break
|
||||
case '[[C':
|
||||
name = 'f3'
|
||||
break
|
||||
case '[[D':
|
||||
name = 'f4'
|
||||
break
|
||||
case '[[E':
|
||||
name = 'f5'
|
||||
break
|
||||
|
||||
/* common */
|
||||
case '[15~':
|
||||
name = 'f5'
|
||||
break
|
||||
case '[17~':
|
||||
name = 'f6'
|
||||
break
|
||||
case '[18~':
|
||||
name = 'f7'
|
||||
break
|
||||
case '[19~':
|
||||
name = 'f8'
|
||||
break
|
||||
case '[20~':
|
||||
name = 'f9'
|
||||
break
|
||||
case '[21~':
|
||||
name = 'f10'
|
||||
break
|
||||
case '[23~':
|
||||
name = 'f11'
|
||||
break
|
||||
case '[24~':
|
||||
name = 'f12'
|
||||
break
|
||||
|
||||
/* xterm ESC [ letter */
|
||||
case '[A':
|
||||
name = 'up'
|
||||
break
|
||||
case '[B':
|
||||
name = 'down'
|
||||
break
|
||||
case '[C':
|
||||
name = 'right'
|
||||
break
|
||||
case '[D':
|
||||
name = 'left'
|
||||
break
|
||||
case '[E':
|
||||
name = 'clear'
|
||||
break
|
||||
case '[F':
|
||||
name = 'end'
|
||||
break
|
||||
case '[H':
|
||||
name = 'home'
|
||||
break
|
||||
|
||||
/* xterm/gnome ESC O letter */
|
||||
case 'OA':
|
||||
name = 'up'
|
||||
break
|
||||
case 'OB':
|
||||
name = 'down'
|
||||
break
|
||||
case 'OC':
|
||||
name = 'right'
|
||||
break
|
||||
case 'OD':
|
||||
name = 'left'
|
||||
break
|
||||
case 'OE':
|
||||
name = 'clear'
|
||||
break
|
||||
case 'OF':
|
||||
name = 'end'
|
||||
break
|
||||
case 'OH':
|
||||
name = 'home'
|
||||
break
|
||||
|
||||
/* xterm/rxvt ESC [ number ~ */
|
||||
case '[1~':
|
||||
name = 'home'
|
||||
break
|
||||
case '[2~':
|
||||
name = 'insert'
|
||||
break
|
||||
case '[3~':
|
||||
name = 'delete'
|
||||
break
|
||||
case '[4~':
|
||||
name = 'end'
|
||||
break
|
||||
case '[5~':
|
||||
name = 'pageup'
|
||||
break
|
||||
case '[6~':
|
||||
name = 'pagedown'
|
||||
break
|
||||
|
||||
/* putty */
|
||||
case '[[5~':
|
||||
name = 'pageup'
|
||||
break
|
||||
case '[[6~':
|
||||
name = 'pagedown'
|
||||
break
|
||||
|
||||
/* rxvt */
|
||||
case '[7~':
|
||||
name = 'home'
|
||||
break
|
||||
case '[8~':
|
||||
name = 'end'
|
||||
break
|
||||
|
||||
/* rxvt keys with modifiers */
|
||||
case '[a':
|
||||
name = 'up'
|
||||
shift = true
|
||||
break
|
||||
case '[b':
|
||||
name = 'down'
|
||||
shift = true
|
||||
break
|
||||
case '[c':
|
||||
name = 'right'
|
||||
shift = true
|
||||
break
|
||||
case '[d':
|
||||
name = 'left'
|
||||
shift = true
|
||||
break
|
||||
case '[e':
|
||||
name = 'clear'
|
||||
shift = true
|
||||
break
|
||||
|
||||
case '[2$':
|
||||
name = 'insert'
|
||||
shift = true
|
||||
break
|
||||
case '[3$':
|
||||
name = 'delete'
|
||||
shift = true
|
||||
break
|
||||
case '[5$':
|
||||
name = 'pageup'
|
||||
shift = true
|
||||
break
|
||||
case '[6$':
|
||||
name = 'pagedown'
|
||||
shift = true
|
||||
break
|
||||
case '[7$':
|
||||
name = 'home'
|
||||
shift = true
|
||||
break
|
||||
case '[8$':
|
||||
name = 'end'
|
||||
shift = true
|
||||
break
|
||||
|
||||
case 'Oa':
|
||||
name = 'up'
|
||||
ctrl = true
|
||||
break
|
||||
case 'Ob':
|
||||
name = 'down'
|
||||
ctrl = true
|
||||
break
|
||||
case 'Oc':
|
||||
name = 'right'
|
||||
ctrl = true
|
||||
break
|
||||
case 'Od':
|
||||
name = 'left'
|
||||
ctrl = true
|
||||
break
|
||||
case 'Oe':
|
||||
name = 'clear'
|
||||
ctrl = true
|
||||
break
|
||||
|
||||
case '[2^':
|
||||
name = 'insert'
|
||||
ctrl = true
|
||||
break
|
||||
case '[3^':
|
||||
name = 'delete'
|
||||
ctrl = true
|
||||
break
|
||||
case '[5^':
|
||||
name = 'pageup'
|
||||
ctrl = true
|
||||
break
|
||||
case '[6^':
|
||||
name = 'pagedown'
|
||||
ctrl = true
|
||||
break
|
||||
case '[7^':
|
||||
name = 'home'
|
||||
ctrl = true
|
||||
break
|
||||
case '[8^':
|
||||
name = 'end'
|
||||
ctrl = true
|
||||
break
|
||||
|
||||
case '[Z':
|
||||
name = 'tab'
|
||||
shift = true
|
||||
break
|
||||
default:
|
||||
name = 'undefined'
|
||||
break
|
||||
}
|
||||
} else if (c === '\r') {
|
||||
name = 'return'
|
||||
meta = escaped
|
||||
} else if (c === '\n') {
|
||||
name = 'linefeed'
|
||||
meta = escaped
|
||||
} else if (c === '\t') {
|
||||
name = 'tab'
|
||||
meta = escaped
|
||||
} else if (c === '\b' || c === '\x7f') {
|
||||
name = 'backspace'
|
||||
meta = escaped
|
||||
} else if (c === ESC) {
|
||||
name = 'escape'
|
||||
meta = escaped
|
||||
} else if (c === ' ') {
|
||||
name = 'space'
|
||||
meta = escaped
|
||||
} else if (!escaped && c <= '\x1a') {
|
||||
name = String.fromCharCode(c.charCodeAt(0) + 'a'.charCodeAt(0) - 1)
|
||||
ctrl = true
|
||||
} else if (/^[0-9A-Za-z]$/.exec(c) !== null) {
|
||||
name = c.toLowerCase()
|
||||
shift = /^[A-Z]$/.exec(c) !== null
|
||||
meta = escaped
|
||||
} else if (escaped) {
|
||||
name = c.length ? null : 'escape'
|
||||
meta = true
|
||||
}
|
||||
|
||||
const sequence = s
|
||||
|
||||
if (
|
||||
s.length > 0 &&
|
||||
(name !== null || escaped || charLengthAt(s, 0) === s.length)
|
||||
) {
|
||||
stream.push(
|
||||
new Key(name === null ? sequence : name, sequence, ctrl, meta, shift)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
{
|
||||
"name": "bare-ansi-escapes",
|
||||
"version": "2.2.3",
|
||||
"description": "Parse and produce ANSI escape sequences",
|
||||
"exports": {
|
||||
"./package": "./package.json",
|
||||
".": {
|
||||
"types": "./index.d.ts",
|
||||
"default": "./index.js"
|
||||
},
|
||||
"./key-decoder": {
|
||||
"types": "./key-decoder.d.ts",
|
||||
"default": "./key-decoder.js"
|
||||
}
|
||||
},
|
||||
"files": [
|
||||
"index.js",
|
||||
"index.d.ts",
|
||||
"key-decoder.js",
|
||||
"key-decoder.d.ts"
|
||||
],
|
||||
"scripts": {
|
||||
"test": "prettier . --check && bare test.js"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/holepunchto/bare-ansi-escapes.git"
|
||||
},
|
||||
"author": "Holepunch",
|
||||
"license": "Apache-2.0",
|
||||
"bugs": {
|
||||
"url": "https://github.com/holepunchto/bare-ansi-escapes/issues"
|
||||
},
|
||||
"homepage": "https://github.com/holepunchto/bare-ansi-escapes#readme",
|
||||
"dependencies": {
|
||||
"bare-stream": "^2.6.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"bare-buffer": "^3.0.2",
|
||||
"brittle": "^3.3.2",
|
||||
"prettier": "^3.4.2",
|
||||
"prettier-config-standard": "^7.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"bare-buffer": "*"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"bare-buffer": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
}
|
||||
+201
@@ -0,0 +1,201 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
# bare-assert
|
||||
|
||||
Assertion library for JavaScript.
|
||||
|
||||
```
|
||||
npm i bare-assert
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
Apache-2.0
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
declare function assert(value: any, message?: string | Error): void
|
||||
|
||||
declare namespace assert {
|
||||
export class AssertionError extends Error {
|
||||
constructor(opts?: {
|
||||
message?: string
|
||||
actual?: any
|
||||
expected?: any
|
||||
operator?: string
|
||||
})
|
||||
|
||||
actual?: any
|
||||
expected?: any
|
||||
operator?: string
|
||||
}
|
||||
|
||||
export function ok(value: any, message?: string | Error): void
|
||||
|
||||
export function equal(
|
||||
actual: any,
|
||||
expected: any,
|
||||
message?: string | Error
|
||||
): void
|
||||
|
||||
export function notEqual(
|
||||
actual: any,
|
||||
expected: any,
|
||||
message?: string | Error
|
||||
): void
|
||||
|
||||
export function strictEqual(
|
||||
actual: any,
|
||||
expected: any,
|
||||
message?: string | Error
|
||||
): void
|
||||
|
||||
export function notStrictEqual(
|
||||
actual: any,
|
||||
expected: any,
|
||||
message?: string | Error
|
||||
): void
|
||||
}
|
||||
|
||||
export = assert
|
||||
+95
@@ -0,0 +1,95 @@
|
||||
const inspect = require('bare-inspect')
|
||||
|
||||
class AssertionError extends Error {
|
||||
constructor(opts = {}) {
|
||||
let { message = null, actual, expected, operator } = opts
|
||||
|
||||
if (message === null) {
|
||||
message = `${inspect(actual)} ${operator} ${inspect(expected)}`
|
||||
}
|
||||
|
||||
super(message)
|
||||
|
||||
this.actual = actual
|
||||
this.expected = expected
|
||||
this.operator = operator
|
||||
}
|
||||
|
||||
get name() {
|
||||
return 'AssertionError'
|
||||
}
|
||||
|
||||
get code() {
|
||||
'ASSERTION'
|
||||
}
|
||||
}
|
||||
|
||||
function assertFail(opts, fn) {
|
||||
if (opts.message instanceof Error) throw opts.message
|
||||
|
||||
const err = new AssertionError(opts)
|
||||
|
||||
if (Error.captureStackTrace) Error.captureStackTrace(err, fn)
|
||||
|
||||
throw err
|
||||
}
|
||||
|
||||
module.exports = exports = function assert(actual, message) {
|
||||
if (actual) return
|
||||
|
||||
assertFail({ message, actual, expected: true, operator: '==' }, assert)
|
||||
}
|
||||
|
||||
exports.AssertionError = AssertionError
|
||||
|
||||
exports.fail = function fail(message) {
|
||||
if (message === undefined) message = 'Failed'
|
||||
|
||||
assertFail({ message, operator: 'fail' }, fail)
|
||||
}
|
||||
|
||||
exports.ok = function ok(actual, message) {
|
||||
if (actual) return
|
||||
|
||||
assertFail({ message, actual, expected: true, operator: '==' }, ok)
|
||||
}
|
||||
|
||||
exports.notOk = function ok(actual, message) {
|
||||
if (!actual) return
|
||||
|
||||
assertFail({ message, actual, expected: false, operator: '==' }, ok)
|
||||
}
|
||||
|
||||
exports.equal = function equal(actual, expected, message) {
|
||||
if (actual == expected || (actual !== actual && expected !== expected)) {
|
||||
return
|
||||
}
|
||||
|
||||
assertFail({ message, actual, expected, operator: '==' }, equal)
|
||||
}
|
||||
|
||||
exports.notEqual = function notEqual(actual, expected, message) {
|
||||
if (actual != expected && (actual === actual || expected === expected)) {
|
||||
return
|
||||
}
|
||||
|
||||
assertFail({ message, actual, expected, operator: '!=' }, notEqual)
|
||||
}
|
||||
|
||||
exports.strictEqual = function strictEqual(actual, expected, message) {
|
||||
if (Object.is(actual, expected)) return
|
||||
|
||||
assertFail(
|
||||
{ message, actual, expected, operator: 'strictEqual' },
|
||||
strictEqual
|
||||
)
|
||||
}
|
||||
|
||||
exports.notStrictEqual = function notStrictEqual(actual, expected, message) {
|
||||
if (!Object.is(actual, expected)) return
|
||||
|
||||
assertFail(
|
||||
{ message, actual, expected, operator: 'notStrictEqual' },
|
||||
notStrictEqual
|
||||
)
|
||||
}
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
{
|
||||
"name": "bare-assert",
|
||||
"version": "1.2.0",
|
||||
"description": "Assertion library for JavaScript",
|
||||
"exports": {
|
||||
".": {
|
||||
"types": "./index.d.ts",
|
||||
"default": "./index.js"
|
||||
},
|
||||
"./package": "./package.json"
|
||||
},
|
||||
"files": [
|
||||
"index.js",
|
||||
"index.d.ts"
|
||||
],
|
||||
"scripts": {
|
||||
"test": "prettier . --check && bare test.js"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/holepunchto/bare-assert.git"
|
||||
},
|
||||
"author": "Holepunch",
|
||||
"license": "Apache-2.0",
|
||||
"bugs": {
|
||||
"url": "https://github.com/holepunchto/bare-assert/issues"
|
||||
},
|
||||
"homepage": "https://github.com/holepunchto/bare-assert#readme",
|
||||
"dependencies": {
|
||||
"bare-inspect": "^3.1.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"brittle": "^3.1.1",
|
||||
"prettier": "^3.4.2",
|
||||
"prettier-config-standard": "^7.0.0"
|
||||
}
|
||||
}
|
||||
+201
@@ -0,0 +1,201 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
# bare-env
|
||||
|
||||
Environment variable support for JavaScript.
|
||||
|
||||
```
|
||||
npm i bare-env
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
``` js
|
||||
const env = require('bare-env')
|
||||
|
||||
console.log(env.PATH)
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
Apache-2.0
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
const os = require('bare-os')
|
||||
|
||||
module.exports = new Proxy(Object.create(null), {
|
||||
ownKeys (target) {
|
||||
return os.getEnvKeys()
|
||||
},
|
||||
|
||||
get (target, property) {
|
||||
if (typeof property !== 'string') return
|
||||
|
||||
return os.getEnv(property)
|
||||
},
|
||||
|
||||
has (target, property) {
|
||||
if (typeof property !== 'string') return false
|
||||
|
||||
return os.hasEnv(property)
|
||||
},
|
||||
|
||||
set (target, property, value) {
|
||||
if (typeof property !== 'string') return
|
||||
|
||||
const type = typeof value
|
||||
|
||||
if (type !== 'string' && type !== 'number' && type !== 'boolean') {
|
||||
throw new Error('Environment variable must be of type string, number, or boolean')
|
||||
}
|
||||
|
||||
value = String(value)
|
||||
|
||||
os.setEnv(property, value)
|
||||
|
||||
return true
|
||||
},
|
||||
|
||||
deleteProperty (target, property) {
|
||||
if (typeof property !== 'string') return
|
||||
|
||||
os.unsetEnv(property)
|
||||
},
|
||||
|
||||
getOwnPropertyDescriptor (target, property) {
|
||||
return {
|
||||
value: this.get(target, property),
|
||||
enumerable: true,
|
||||
configurable: true,
|
||||
writable: true
|
||||
}
|
||||
}
|
||||
})
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
{
|
||||
"name": "bare-env",
|
||||
"version": "3.0.0",
|
||||
"description": "Environment variable support for JavaScript",
|
||||
"main": "index.js",
|
||||
"files": [
|
||||
"index.js"
|
||||
],
|
||||
"scripts": {
|
||||
"test": "standard && bare test.js"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/holepunchto/bare-env.git"
|
||||
},
|
||||
"author": "Holepunch",
|
||||
"license": "Apache-2.0",
|
||||
"bugs": {
|
||||
"url": "https://github.com/holepunchto/bare-env/issues"
|
||||
},
|
||||
"homepage": "https://github.com/holepunchto/bare-env#readme",
|
||||
"dependencies": {
|
||||
"bare-os": "^3.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"brittle": "^3.2.1",
|
||||
"standard": "^17.0.0"
|
||||
}
|
||||
}
|
||||
+201
@@ -0,0 +1,201 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
# bare-events
|
||||
|
||||
Event emitters for JavaScript.
|
||||
|
||||
```
|
||||
npm install bare-events
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
```js
|
||||
const EventEmitter = require('bare-events')
|
||||
|
||||
const e = new EventEmitter()
|
||||
|
||||
e.on('hello', function (data) {
|
||||
console.log(data)
|
||||
})
|
||||
|
||||
e.emit('hello', 'world')
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
Apache-2.0
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
import * as events from './web'
|
||||
|
||||
type EventConstructor = typeof events.Event
|
||||
type CustomEventConstructor = typeof events.CustomEvent
|
||||
type EventTargetConstructor = typeof events.EventTarget
|
||||
|
||||
declare global {
|
||||
type Event = events.Event
|
||||
type CustomEvent<T = any> = events.CustomEvent<T>
|
||||
type EventTarget = events.EventTarget
|
||||
|
||||
const Event: EventConstructor
|
||||
const CustomEvent: CustomEventConstructor
|
||||
const EventTarget: EventTargetConstructor
|
||||
}
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
const events = require('./web')
|
||||
|
||||
global.Event = events.Event
|
||||
global.CustomEvent = events.CustomEvent
|
||||
global.EventTarget = events.EventTarget
|
||||
+81
@@ -0,0 +1,81 @@
|
||||
import { AbortSignal } from 'bare-abort-controller'
|
||||
|
||||
interface EventMap {
|
||||
[event: string | symbol]: unknown[]
|
||||
}
|
||||
|
||||
interface EventHandler<in A extends unknown[] = unknown[], out R = unknown> {
|
||||
(...args: A): R
|
||||
}
|
||||
|
||||
declare class EventEmitterError extends Error {
|
||||
static OPERATION_ABORTED(cause: Error, msg?: string): EventEmitterError
|
||||
static UNHANDLED_ERROR(cause: Error, msg?: string): EventEmitterError
|
||||
}
|
||||
|
||||
interface EventEmitter<in out M extends EventMap = EventMap> {
|
||||
addListener<E extends keyof M, R>(name: E, fn: EventHandler<M[E], R>): this
|
||||
|
||||
addOnceListener<E extends keyof M, R>(name: E, fn: EventHandler<M[E], R>): this
|
||||
|
||||
prependListener<E extends keyof M, R>(name: E, fn: EventHandler<M[E], R>): this
|
||||
|
||||
prependOnceListener<E extends keyof M, R>(name: E, fn: EventHandler<M[E], R>): this
|
||||
|
||||
removeListener<E extends keyof M, R>(name: E, fn: EventHandler<M[E], R>): this
|
||||
|
||||
removeAllListeners<E extends keyof M>(name?: E): this
|
||||
|
||||
on<E extends keyof M, R>(name: E, fn: EventHandler<M[E], R>): this
|
||||
|
||||
once<E extends keyof M, R>(name: E, fn: EventHandler<M[E], R>): this
|
||||
|
||||
off<E extends keyof M, R>(name: E, fn: EventHandler<M[E], R>): this
|
||||
|
||||
emit<E extends keyof M>(name: E, ...args: M[E]): boolean
|
||||
|
||||
listeners<E extends keyof M, R>(name: E): EventHandler<M[E], R>
|
||||
|
||||
listenerCount<E extends keyof M>(name: E): number
|
||||
|
||||
getMaxListeners(): number
|
||||
setMaxListeners(n: number): void
|
||||
}
|
||||
|
||||
declare class EventEmitter<in out M extends EventMap = EventMap> {}
|
||||
|
||||
declare namespace EventEmitter {
|
||||
export function on<M extends EventMap, E extends keyof M>(
|
||||
emitter: EventEmitter<M>,
|
||||
name: E,
|
||||
opts?: { signal?: AbortSignal }
|
||||
): AsyncIterableIterator<M[E]>
|
||||
|
||||
export function once<M extends EventMap, E extends keyof M>(
|
||||
emitter: EventEmitter<M>,
|
||||
name: E,
|
||||
opts?: { signal?: AbortSignal }
|
||||
): Promise<M[E]>
|
||||
|
||||
export function forward<F extends EventMap, E extends keyof F, T extends Pick<F, E>>(
|
||||
from: EventEmitter<F>,
|
||||
to: EventEmitter<T>,
|
||||
names: E | E[],
|
||||
opts?: { emit?: (name: E, ...args: T[E]) => void }
|
||||
): void
|
||||
|
||||
export function listenerCount<M extends EventMap, E extends keyof M>(
|
||||
emitter: EventEmitter<M>,
|
||||
name: E
|
||||
): number
|
||||
|
||||
export function getMaxListeners(emitter: EventEmitter): number
|
||||
|
||||
export function setMaxListeners(n: number, ...emitters: EventEmitter[]): void
|
||||
|
||||
export let defaultMaxListeners: number
|
||||
|
||||
export { EventEmitter, EventEmitterError as errors, EventMap, EventHandler }
|
||||
}
|
||||
|
||||
export = EventEmitter
|
||||
+367
@@ -0,0 +1,367 @@
|
||||
const errors = require('./lib/errors')
|
||||
|
||||
class EventListener {
|
||||
constructor() {
|
||||
this.list = []
|
||||
this.count = 0
|
||||
}
|
||||
|
||||
append(ctx, name, fn, once) {
|
||||
this.count++
|
||||
ctx.emit('newListener', name, fn) // Emit BEFORE adding
|
||||
this.list.push([fn, once])
|
||||
}
|
||||
|
||||
prepend(ctx, name, fn, once) {
|
||||
this.count++
|
||||
ctx.emit('newListener', name, fn) // Emit BEFORE adding
|
||||
this.list.unshift([fn, once])
|
||||
}
|
||||
|
||||
remove(ctx, name, fn) {
|
||||
for (let i = 0, n = this.list.length; i < n; i++) {
|
||||
const l = this.list[i]
|
||||
|
||||
if (l[0] === fn) {
|
||||
this.list.splice(i, 1)
|
||||
|
||||
if (this.count === 1) delete ctx._events[name]
|
||||
|
||||
ctx.emit('removeListener', name, fn) // Emit AFTER removing
|
||||
|
||||
this.count--
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
removeAll(ctx, name) {
|
||||
const list = [...this.list]
|
||||
this.list = []
|
||||
|
||||
if (this.count === list.length) delete ctx._events[name]
|
||||
|
||||
for (let i = list.length - 1; i >= 0; i--) {
|
||||
ctx.emit('removeListener', name, list[i][0]) // Emit AFTER removing
|
||||
}
|
||||
|
||||
this.count -= list.length
|
||||
}
|
||||
|
||||
emit(ctx, name, ...args) {
|
||||
const list = [...this.list]
|
||||
|
||||
for (let i = 0, n = list.length; i < n; i++) {
|
||||
const l = list[i]
|
||||
|
||||
if (l[1] === true) this.remove(ctx, name, l[0])
|
||||
|
||||
Reflect.apply(l[0], ctx, args)
|
||||
}
|
||||
|
||||
return list.length > 0
|
||||
}
|
||||
}
|
||||
|
||||
function appendListener(ctx, name, fn, once) {
|
||||
if (ctx._events === undefined) ctx._events = Object.create(null)
|
||||
const e = ctx._events[name] || (ctx._events[name] = new EventListener())
|
||||
e.append(ctx, name, fn, once)
|
||||
return ctx
|
||||
}
|
||||
|
||||
function prependListener(ctx, name, fn, once) {
|
||||
if (ctx._events === undefined) ctx._events = Object.create(null)
|
||||
const e = ctx._events[name] || (ctx._events[name] = new EventListener())
|
||||
e.prepend(ctx, name, fn, once)
|
||||
return ctx
|
||||
}
|
||||
|
||||
function removeListener(ctx, name, fn) {
|
||||
if (ctx._events === undefined) return ctx
|
||||
const e = ctx._events[name]
|
||||
if (e !== undefined) e.remove(ctx, name, fn)
|
||||
return ctx
|
||||
}
|
||||
|
||||
function throwUnhandledError(...args) {
|
||||
let err
|
||||
|
||||
if (args.length > 0) err = args[0]
|
||||
|
||||
if (err instanceof Error === false) err = errors.UNHANDLED_ERROR(err)
|
||||
|
||||
if (Error.captureStackTrace) {
|
||||
Error.captureStackTrace(err, exports.prototype.emit)
|
||||
}
|
||||
|
||||
queueMicrotask(() => {
|
||||
throw err
|
||||
})
|
||||
}
|
||||
|
||||
module.exports = exports = class EventEmitter {
|
||||
constructor() {
|
||||
this._events = Object.create(null)
|
||||
}
|
||||
|
||||
addListener(name, fn) {
|
||||
return appendListener(this, name, fn, false)
|
||||
}
|
||||
|
||||
addOnceListener(name, fn) {
|
||||
return appendListener(this, name, fn, true)
|
||||
}
|
||||
|
||||
prependListener(name, fn) {
|
||||
return prependListener(this, name, fn, false)
|
||||
}
|
||||
|
||||
prependOnceListener(name, fn) {
|
||||
return prependListener(this, name, fn, true)
|
||||
}
|
||||
|
||||
removeListener(name, fn) {
|
||||
return removeListener(this, name, fn)
|
||||
}
|
||||
|
||||
on(name, fn) {
|
||||
return appendListener(this, name, fn, false)
|
||||
}
|
||||
|
||||
once(name, fn) {
|
||||
return appendListener(this, name, fn, true)
|
||||
}
|
||||
|
||||
off(name, fn) {
|
||||
return removeListener(this, name, fn)
|
||||
}
|
||||
|
||||
emit(name, ...args) {
|
||||
if (name === 'error' && this._events !== undefined && this._events.error === undefined) {
|
||||
throwUnhandledError(...args)
|
||||
}
|
||||
|
||||
if (this._events === undefined) return false
|
||||
const e = this._events[name]
|
||||
return e === undefined ? false : e.emit(this, name, ...args)
|
||||
}
|
||||
|
||||
listeners(name) {
|
||||
if (this._events === undefined) return []
|
||||
const e = this._events[name]
|
||||
return e === undefined ? [] : [...e.list]
|
||||
}
|
||||
|
||||
listenerCount(name) {
|
||||
if (this._events === undefined) return 0
|
||||
const e = this._events[name]
|
||||
return e === undefined ? 0 : e.list.length
|
||||
}
|
||||
|
||||
getMaxListeners() {
|
||||
return EventEmitter.defaultMaxListeners
|
||||
}
|
||||
|
||||
setMaxListeners(n) {}
|
||||
|
||||
removeAllListeners(name) {
|
||||
if (arguments.length === 0) {
|
||||
for (const key of Reflect.ownKeys(this._events)) {
|
||||
if (key === 'removeListener') continue
|
||||
this.removeAllListeners(key)
|
||||
}
|
||||
this.removeAllListeners('removeListener')
|
||||
} else {
|
||||
const e = this._events[name]
|
||||
if (e !== undefined) e.removeAll(this, name)
|
||||
}
|
||||
return this
|
||||
}
|
||||
}
|
||||
|
||||
exports.EventEmitter = exports
|
||||
|
||||
exports.errors = errors
|
||||
|
||||
exports.defaultMaxListeners = 10
|
||||
|
||||
exports.on = function on(emitter, name, opts = {}) {
|
||||
const { signal } = opts
|
||||
|
||||
if (signal && signal.aborted) {
|
||||
throw errors.OPERATION_ABORTED(signal.reason)
|
||||
}
|
||||
|
||||
let error = null
|
||||
let done = false
|
||||
|
||||
const events = []
|
||||
const promises = []
|
||||
|
||||
if (name !== 'error') emitter.on('error', onerror)
|
||||
|
||||
if (signal) signal.addEventListener('abort', onabort)
|
||||
|
||||
emitter.on(name, onevent)
|
||||
|
||||
return {
|
||||
next() {
|
||||
if (events.length) {
|
||||
return Promise.resolve({ value: events.shift(), done: false })
|
||||
}
|
||||
|
||||
if (error) {
|
||||
const err = error
|
||||
|
||||
error = null
|
||||
|
||||
return Promise.reject(err)
|
||||
}
|
||||
|
||||
if (done) return onclose()
|
||||
|
||||
return new Promise((resolve, reject) => promises.push({ resolve, reject }))
|
||||
},
|
||||
|
||||
return() {
|
||||
return onclose()
|
||||
},
|
||||
|
||||
throw(err) {
|
||||
return onerror(err)
|
||||
},
|
||||
|
||||
[Symbol.asyncIterator]() {
|
||||
return this
|
||||
}
|
||||
}
|
||||
|
||||
function onevent(...args) {
|
||||
if (promises.length) {
|
||||
promises.shift().resolve({ value: args, done: false })
|
||||
} else {
|
||||
events.push(args)
|
||||
}
|
||||
}
|
||||
|
||||
function onerror(err) {
|
||||
emitter.off(name, onevent).off('error', onerror)
|
||||
|
||||
if (promises.length) {
|
||||
promises.shift().reject(err)
|
||||
} else {
|
||||
error = err
|
||||
}
|
||||
|
||||
return Promise.resolve({ done: true })
|
||||
}
|
||||
|
||||
function onabort() {
|
||||
signal.removeEventListener('abort', onabort)
|
||||
|
||||
onerror(errors.OPERATION_ABORTED(signal.reason))
|
||||
}
|
||||
|
||||
function onclose() {
|
||||
emitter.off(name, onevent)
|
||||
|
||||
if (name !== 'error') emitter.off('error', onerror)
|
||||
|
||||
if (signal) signal.removeEventListener('abort', onabort)
|
||||
|
||||
done = true
|
||||
|
||||
if (promises.length) promises.shift().resolve({ done: true })
|
||||
|
||||
return Promise.resolve({ done: true })
|
||||
}
|
||||
}
|
||||
|
||||
exports.once = function once(emitter, name, opts = {}) {
|
||||
const { signal } = opts
|
||||
|
||||
if (signal && signal.aborted) {
|
||||
return Promise.reject(errors.OPERATION_ABORTED(signal.reason))
|
||||
}
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
if (name !== 'error') emitter.on('error', onerror)
|
||||
|
||||
if (signal) signal.addEventListener('abort', onabort)
|
||||
|
||||
emitter.once(name, onevent)
|
||||
|
||||
function onevent(...args) {
|
||||
if (name !== 'error') emitter.off('error', onerror)
|
||||
|
||||
if (signal) signal.removeEventListener('abort', onabort)
|
||||
|
||||
resolve(args)
|
||||
}
|
||||
|
||||
function onerror(err) {
|
||||
emitter.off(name, onevent)
|
||||
|
||||
if (name !== 'error') emitter.off('error', onerror)
|
||||
|
||||
reject(err)
|
||||
}
|
||||
|
||||
function onabort() {
|
||||
signal.removeEventListener('abort', onabort)
|
||||
|
||||
onerror(errors.OPERATION_ABORTED(signal.reason))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
exports.forward = function forward(from, to, names, opts = {}) {
|
||||
if (typeof names === 'string') names = [names]
|
||||
|
||||
const { emit = to.emit.bind(to) } = opts
|
||||
|
||||
const listeners = names.map(
|
||||
(name) =>
|
||||
function onevent(...args) {
|
||||
emit(name, ...args)
|
||||
}
|
||||
)
|
||||
|
||||
to.on('newListener', (name) => {
|
||||
const i = names.indexOf(name)
|
||||
|
||||
if (i !== -1 && to.listenerCount(name) === 0) {
|
||||
from.on(name, listeners[i])
|
||||
}
|
||||
}).on('removeListener', (name) => {
|
||||
const i = names.indexOf(name)
|
||||
|
||||
if (i !== -1 && to.listenerCount(name) === 0) {
|
||||
from.off(name, listeners[i])
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
exports.listenerCount = function listenerCount(emitter, name) {
|
||||
return emitter.listenerCount(name)
|
||||
}
|
||||
|
||||
exports.getMaxListeners = function getMaxListeners(emitter) {
|
||||
if (typeof emitter.getMaxListeners === 'function') {
|
||||
return emitter.getMaxListeners()
|
||||
}
|
||||
|
||||
return exports.defaultMaxListeners
|
||||
}
|
||||
|
||||
exports.setMaxListeners = function setMaxListeners(n, ...emitters) {
|
||||
if (emitters.length === 0) exports.defaultMaxListeners = n
|
||||
else {
|
||||
for (const emitter of emitters) {
|
||||
if (typeof emitter.setMaxListeners === 'function') {
|
||||
emitter.setMaxListeners(n)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
module.exports = class EventEmitterError extends Error {
|
||||
constructor(msg, code, fn = EventEmitterError, opts) {
|
||||
super(`${code}: ${msg}`, opts)
|
||||
this.code = code
|
||||
|
||||
if (Error.captureStackTrace) {
|
||||
Error.captureStackTrace(this, fn)
|
||||
}
|
||||
}
|
||||
|
||||
get name() {
|
||||
return 'EventEmitterError'
|
||||
}
|
||||
|
||||
static OPERATION_ABORTED(cause, msg = 'Operation aborted') {
|
||||
return new EventEmitterError(msg, 'OPERATION_ABORTED', EventEmitterError.OPERATION_ABORTED, {
|
||||
cause
|
||||
})
|
||||
}
|
||||
|
||||
static UNHANDLED_ERROR(cause, msg = 'Unhandled error') {
|
||||
return new EventEmitterError(msg, 'UNHANDLED_ERROR', EventEmitterError.UNHANDLED_ERROR, {
|
||||
cause
|
||||
})
|
||||
}
|
||||
}
|
||||
+63
@@ -0,0 +1,63 @@
|
||||
{
|
||||
"name": "bare-events",
|
||||
"version": "2.8.3",
|
||||
"description": "Event emitters for JavaScript",
|
||||
"exports": {
|
||||
"./package": "./package.json",
|
||||
".": {
|
||||
"types": "./index.d.ts",
|
||||
"default": "./index.js"
|
||||
},
|
||||
"./global": {
|
||||
"types": "./global.d.ts",
|
||||
"default": "./global.js"
|
||||
},
|
||||
"./web": {
|
||||
"types": "./web.d.ts",
|
||||
"default": "./web.js"
|
||||
},
|
||||
"./errors": "./lib/errors.js"
|
||||
},
|
||||
"files": [
|
||||
"index.js",
|
||||
"index.d.ts",
|
||||
"global.js",
|
||||
"global.d.ts",
|
||||
"web.js",
|
||||
"web.d.ts",
|
||||
"lib"
|
||||
],
|
||||
"scripts": {
|
||||
"format": "prettier --write . && lunte --fix",
|
||||
"lint": "prettier --check . && lunte",
|
||||
"test": "npm run test:bare && npm run test:node",
|
||||
"test:bare": "brittle-bare --coverage test.js",
|
||||
"test:node": "brittle-node --coverage test.js"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/holepunchto/bare-events.git"
|
||||
},
|
||||
"author": "Holepunch",
|
||||
"license": "Apache-2.0",
|
||||
"bugs": {
|
||||
"url": "https://github.com/holepunchto/bare-events/issues"
|
||||
},
|
||||
"homepage": "https://github.com/holepunchto/bare-events#readme",
|
||||
"devDependencies": {
|
||||
"bare-abort-controller": "^1.0.0",
|
||||
"brittle": "^3.3.2",
|
||||
"lunte": "^1.8.0",
|
||||
"prettier": "^3.4.2",
|
||||
"prettier-config-holepunch": "^2.0.0",
|
||||
"uncaughts": "^1.1.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"bare-abort-controller": "*"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"bare-abort-controller": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
}
|
||||
+79
@@ -0,0 +1,79 @@
|
||||
interface AbortSignal extends EventTarget {}
|
||||
|
||||
export interface EventOptions {
|
||||
bubbles?: boolean
|
||||
cancelable?: boolean
|
||||
composed?: boolean
|
||||
}
|
||||
|
||||
export interface Event {
|
||||
readonly type: string
|
||||
readonly target: EventTarget | null
|
||||
readonly currentTarget: EventTarget | null
|
||||
readonly bubbles: boolean
|
||||
readonly cancelable: boolean
|
||||
readonly composed: boolean
|
||||
readonly defaultPrevented: boolean
|
||||
readonly isTrusted: boolean
|
||||
|
||||
preventDefault(): void
|
||||
stopPropagation(): void
|
||||
stopImmediatePropagation(): void
|
||||
}
|
||||
|
||||
export class Event {
|
||||
constructor(type: string, options?: EventOptions)
|
||||
}
|
||||
|
||||
export interface CustomEventOptions<T = any> extends EventOptions {
|
||||
detail?: T
|
||||
}
|
||||
|
||||
export interface CustomEvent<T = any> extends Event {
|
||||
readonly detail: T
|
||||
}
|
||||
|
||||
export class CustomEvent<T = any> {
|
||||
constructor(type: string, options?: CustomEventOptions<T>)
|
||||
}
|
||||
|
||||
export interface AddEventListenerOptions {
|
||||
capture?: boolean
|
||||
passive?: boolean
|
||||
once?: boolean
|
||||
signal?: AbortSignal | null
|
||||
}
|
||||
|
||||
export interface RemoveEventListenerOptions {
|
||||
capture?: boolean
|
||||
}
|
||||
|
||||
export interface EventTarget {
|
||||
addEventListener(
|
||||
type: string,
|
||||
callback: EventListener,
|
||||
options?: AddEventListenerOptions | boolean
|
||||
): void
|
||||
|
||||
removeEventListener(
|
||||
type: string,
|
||||
callback: EventListener,
|
||||
options?: RemoveEventListenerOptions | boolean
|
||||
): void
|
||||
|
||||
dispatchEvent(event: Event): boolean
|
||||
}
|
||||
|
||||
export class EventTarget {
|
||||
constructor()
|
||||
}
|
||||
|
||||
export type EventListener = EventCallback | EventHandler
|
||||
|
||||
export interface EventCallback {
|
||||
(event: Event): void
|
||||
}
|
||||
|
||||
export interface EventHandler {
|
||||
handleEvent(event: Event): void
|
||||
}
|
||||
+353
@@ -0,0 +1,353 @@
|
||||
// Event state
|
||||
const BUBBLES = 0x1
|
||||
const CANCELABLE = 0x2
|
||||
const COMPOSED = 0x4
|
||||
const CANCELED = 0x8
|
||||
const DISPATCH = 0x10
|
||||
const STOP = 0x20
|
||||
|
||||
// EventTarget state
|
||||
const CAPTURE = 0x1
|
||||
const PASSIVE = 0x2
|
||||
const ONCE = 0x4
|
||||
const REMOVED = 0x8
|
||||
|
||||
// https://dom.spec.whatwg.org/#event
|
||||
class Event {
|
||||
// https://dom.spec.whatwg.org/#dom-event-event
|
||||
constructor(type, options = {}) {
|
||||
const { bubbles = false, cancelable = false, composed = false } = options
|
||||
|
||||
this._type = type
|
||||
this._target = null
|
||||
this._state = 0
|
||||
|
||||
if (bubbles) this._state |= BUBBLES
|
||||
if (cancelable) this._state |= CANCELABLE
|
||||
if (composed) this._state |= COMPOSED
|
||||
}
|
||||
|
||||
// https://dom.spec.whatwg.org/#dom-event-type
|
||||
get type() {
|
||||
return this._type
|
||||
}
|
||||
|
||||
// https://dom.spec.whatwg.org/#dom-event-target
|
||||
get target() {
|
||||
return this._target
|
||||
}
|
||||
|
||||
// https://dom.spec.whatwg.org/#dom-event-currenttarget
|
||||
get currentTarget() {
|
||||
return null
|
||||
}
|
||||
|
||||
// https://dom.spec.whatwg.org/#dom-event-bubbles
|
||||
get bubbles() {
|
||||
return (this._state & BUBBLES) !== 0
|
||||
}
|
||||
|
||||
// https://dom.spec.whatwg.org/#dom-event-cancelable
|
||||
get cancelable() {
|
||||
return (this._state & CANCELABLE) !== 0
|
||||
}
|
||||
|
||||
// https://dom.spec.whatwg.org/#dom-event-composed
|
||||
get composed() {
|
||||
return (this._state & COMPOSED) !== 0
|
||||
}
|
||||
|
||||
// https://dom.spec.whatwg.org/#dom-event-defaultprevented
|
||||
get defaultPrevented() {
|
||||
return (this._state & CANCELED) !== 0
|
||||
}
|
||||
|
||||
// https://dom.spec.whatwg.org/#dom-event-istrusted
|
||||
get isTrusted() {
|
||||
return false
|
||||
}
|
||||
|
||||
// https://dom.spec.whatwg.org/#dom-event-preventdefault
|
||||
preventDefault() {
|
||||
if (this._state & CANCELABLE) this._state |= CANCELED
|
||||
}
|
||||
|
||||
// https://dom.spec.whatwg.org/#dom-event-stoppropagation
|
||||
stopPropagation() {}
|
||||
|
||||
// https://dom.spec.whatwg.org/#dom-event-stopimmediatepropagation
|
||||
stopImmediatePropagation() {
|
||||
this._state |= STOP
|
||||
}
|
||||
|
||||
toJSON() {
|
||||
return {
|
||||
type: this.type,
|
||||
target: this.target,
|
||||
bubbles: this.bubbles,
|
||||
cancelable: this.cancelable,
|
||||
composed: this.composed,
|
||||
defaultPrevented: this.defaultPrevented,
|
||||
isTrusted: this.isTrusted
|
||||
}
|
||||
}
|
||||
|
||||
[Symbol.for('bare.inspect')]() {
|
||||
return {
|
||||
__proto__: { constructor: Event },
|
||||
|
||||
type: this.type,
|
||||
target: this.target,
|
||||
bubbles: this.bubbles,
|
||||
cancelable: this.cancelable,
|
||||
composed: this.composed,
|
||||
defaultPrevented: this.defaultPrevented,
|
||||
isTrusted: this.isTrusted
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
exports.Event = Event
|
||||
|
||||
// https://dom.spec.whatwg.org/#customevent
|
||||
exports.CustomEvent = class CustomEvent extends Event {
|
||||
constructor(type, options = {}) {
|
||||
super(type, options)
|
||||
|
||||
const { detail = null } = options
|
||||
|
||||
this._detail = detail
|
||||
}
|
||||
|
||||
// https://dom.spec.whatwg.org/#dom-customevent-detail
|
||||
get detail() {
|
||||
return this._detail
|
||||
}
|
||||
}
|
||||
|
||||
// https://dom.spec.whatwg.org/#eventtarget
|
||||
exports.EventTarget = class EventTarget {
|
||||
// https://dom.spec.whatwg.org/#dom-eventtarget-eventtarget
|
||||
constructor() {
|
||||
this._listeners = new Map()
|
||||
}
|
||||
|
||||
// https://dom.spec.whatwg.org/#dom-eventtarget-addeventlistener
|
||||
addEventListener(type, callback = null, options = {}) {
|
||||
if (typeof options === 'boolean') options = { capture: options }
|
||||
|
||||
const { capture = false, passive = false, once = false, signal = null } = options
|
||||
|
||||
if (signal !== null && signal.aborted) return
|
||||
if (callback === null) return
|
||||
|
||||
const listener = new EventListener(type, callback, capture, passive, once, signal)
|
||||
|
||||
const listeners = this._listeners.get(type)
|
||||
|
||||
if (listeners !== undefined) {
|
||||
for (const existing of listeners) {
|
||||
if (callback === existing.callback && capture === existing.capture) {
|
||||
return // Duplicate listener
|
||||
}
|
||||
}
|
||||
|
||||
listener.link(listeners)
|
||||
} else {
|
||||
this._listeners.set(type, listener)
|
||||
}
|
||||
|
||||
if (signal !== null) {
|
||||
const self = this
|
||||
signal.addEventListener('abort', onabort)
|
||||
|
||||
function onabort() {
|
||||
self._unlink(type, listener)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// https://dom.spec.whatwg.org/#dom-eventtarget-removeeventlistener
|
||||
removeEventListener(type, callback = null, options = {}) {
|
||||
if (typeof options === 'boolean') options = { capture: options }
|
||||
|
||||
const { capture = false } = options
|
||||
|
||||
const listeners = this._listeners.get(type)
|
||||
|
||||
if (listeners === undefined) return
|
||||
|
||||
for (const existing of listeners) {
|
||||
if (callback === existing.callback && capture === existing.capture) {
|
||||
this._unlink(type, existing)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// https://dom.spec.whatwg.org/#dom-eventtarget-dispatchevent
|
||||
dispatchEvent(event) {
|
||||
event._target = this
|
||||
event._state |= DISPATCH
|
||||
|
||||
const listeners = this._listeners.get(event.type)
|
||||
|
||||
try {
|
||||
if (listeners === undefined) return true
|
||||
|
||||
const snapshot = Array.from(listeners)
|
||||
|
||||
for (const listener of snapshot) {
|
||||
// https://dom.spec.whatwg.org/#concept-event-listener-inner-invoke
|
||||
|
||||
if (listener.removed) continue
|
||||
|
||||
if (listener.once) this._unlink(event.type, listener)
|
||||
|
||||
let callback = listener.callback
|
||||
let context = this
|
||||
|
||||
if (typeof callback === 'object') {
|
||||
context = callback
|
||||
callback = callback.handleEvent
|
||||
}
|
||||
|
||||
Reflect.apply(callback, context, [event])
|
||||
|
||||
if (event._state & STOP) break
|
||||
}
|
||||
|
||||
return (event._state & CANCELED) === 0
|
||||
} finally {
|
||||
event._state &= ~DISPATCH
|
||||
event._state &= ~STOP
|
||||
}
|
||||
}
|
||||
|
||||
toJSON() {
|
||||
return {}
|
||||
}
|
||||
|
||||
[Symbol.for('bare.inspect')]() {
|
||||
return {
|
||||
__proto__: { constructor: EventTarget }
|
||||
}
|
||||
}
|
||||
|
||||
_unlink(type, listener) {
|
||||
if (listener.removed) return
|
||||
|
||||
const head = this._listeners.get(type)
|
||||
const next = listener.unlink()
|
||||
|
||||
if (head === listener) {
|
||||
if (next === listener) this._listeners.delete(type)
|
||||
else this._listeners.set(type, next)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// https://dom.spec.whatwg.org/#concept-event-listener
|
||||
class EventListener {
|
||||
constructor(type, callback, capture, passive, once, signal) {
|
||||
this._type = type
|
||||
this._callback = callback
|
||||
this._signal = signal
|
||||
this._state = 0
|
||||
|
||||
if (capture) this._state |= CAPTURE
|
||||
if (passive) this._state |= PASSIVE
|
||||
if (once) this._state |= ONCE
|
||||
|
||||
this._previous = this
|
||||
this._next = this
|
||||
}
|
||||
|
||||
get type() {
|
||||
return this._type
|
||||
}
|
||||
|
||||
get callback() {
|
||||
return this._callback
|
||||
}
|
||||
|
||||
get capture() {
|
||||
return (this._state & CAPTURE) !== 0
|
||||
}
|
||||
|
||||
get passive() {
|
||||
return (this._state & PASSIVE) !== 0
|
||||
}
|
||||
|
||||
get once() {
|
||||
return (this._state & ONCE) !== 0
|
||||
}
|
||||
|
||||
get removed() {
|
||||
return (this._state & REMOVED) !== 0
|
||||
}
|
||||
|
||||
link(listener) {
|
||||
const next = this._next
|
||||
const previous = listener._previous
|
||||
|
||||
this._next = listener
|
||||
listener._previous = this
|
||||
|
||||
previous._next = next
|
||||
next._previous = previous
|
||||
|
||||
return listener
|
||||
}
|
||||
|
||||
unlink() {
|
||||
if (this.removed) return this
|
||||
|
||||
this._state |= REMOVED
|
||||
|
||||
const next = this._next
|
||||
const previous = this._previous
|
||||
|
||||
this._next = this
|
||||
this._previous = this
|
||||
|
||||
previous._next = next
|
||||
next._previous = previous
|
||||
|
||||
return next
|
||||
}
|
||||
|
||||
*[Symbol.iterator]() {
|
||||
let current = this
|
||||
|
||||
while (true) {
|
||||
const next = current._next
|
||||
yield current
|
||||
if (next === this) break
|
||||
current = next
|
||||
}
|
||||
}
|
||||
|
||||
toJSON() {
|
||||
return {
|
||||
type: this.type,
|
||||
capture: this.capture,
|
||||
passive: this.passive,
|
||||
once: this.once,
|
||||
removed: this.removed
|
||||
}
|
||||
}
|
||||
|
||||
[Symbol.for('bare.inspect')]() {
|
||||
return {
|
||||
__proto__: { constructor: EventListener },
|
||||
|
||||
type: this.type,
|
||||
callback: this.callback,
|
||||
capture: this.capture,
|
||||
passive: this.passive,
|
||||
once: this.once,
|
||||
removed: this.removed
|
||||
}
|
||||
}
|
||||
}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
cmake_minimum_required(VERSION 4.0)
|
||||
|
||||
find_package(cmake-bare REQUIRED PATHS node_modules/cmake-bare)
|
||||
|
||||
project(bare_fs C)
|
||||
|
||||
add_bare_module(bare_fs)
|
||||
|
||||
target_sources(
|
||||
${bare_fs}
|
||||
PRIVATE
|
||||
binding.c
|
||||
)
|
||||
+201
@@ -0,0 +1,201 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
+989
@@ -0,0 +1,989 @@
|
||||
# bare-fs
|
||||
|
||||
Native file system operations for Bare. The API closely follows that of the Node.js `fs` module.
|
||||
|
||||
```
|
||||
npm i bare-fs
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
```js
|
||||
const fs = require('bare-fs')
|
||||
|
||||
const fd = await fs.open('hello.txt')
|
||||
|
||||
const buffer = Buffer.alloc(1024)
|
||||
|
||||
try {
|
||||
const length = await fs.read(fd, buffer)
|
||||
|
||||
console.log('Read', length, 'bytes')
|
||||
} finally {
|
||||
await fs.close(fd)
|
||||
}
|
||||
```
|
||||
|
||||
## API
|
||||
|
||||
#### `const fd = await fs.open(filepath[, flags[, mode]])`
|
||||
|
||||
Open a file, returning a file descriptor. `flags` defaults to `'r'` and `mode` defaults to `0o666`. `flags` may be a string such as `'r'`, `'w'`, `'a'`, `'r+'`, etc., or a numeric combination of `fs.constants` flags.
|
||||
|
||||
#### `fs.open(filepath[, flags[, mode]], callback)`
|
||||
|
||||
Callback version of `fs.open()`.
|
||||
|
||||
#### `const fd = fs.openSync(filepath[, flags[, mode]])`
|
||||
|
||||
Synchronous version of `fs.open()`.
|
||||
|
||||
#### `await fs.close(fd)`
|
||||
|
||||
Close a file descriptor.
|
||||
|
||||
#### `fs.close(fd, callback)`
|
||||
|
||||
Callback version of `fs.close()`.
|
||||
|
||||
#### `fs.closeSync(fd)`
|
||||
|
||||
Synchronous version of `fs.close()`.
|
||||
|
||||
#### `await fs.access(filepath[, mode])`
|
||||
|
||||
Check whether the file at `filepath` is accessible. `mode` defaults to `fs.constants.F_OK`.
|
||||
|
||||
#### `fs.access(filepath[, mode], callback)`
|
||||
|
||||
Callback version of `fs.access()`.
|
||||
|
||||
#### `fs.accessSync(filepath[, mode])`
|
||||
|
||||
Synchronous version of `fs.access()`.
|
||||
|
||||
#### `const exists = await fs.exists(filepath)`
|
||||
|
||||
Check whether a file exists at `filepath`. Returns `true` if the file is accessible, `false` otherwise.
|
||||
|
||||
#### `fs.exists(filepath, callback)`
|
||||
|
||||
Callback version of `fs.exists()`.
|
||||
|
||||
#### `const exists = fs.existsSync(filepath)`
|
||||
|
||||
Synchronous version of `fs.exists()`.
|
||||
|
||||
#### `const bytesRead = await fs.read(fd, buffer[, offset[, len[, pos]]])`
|
||||
|
||||
Read from a file descriptor into `buffer`. `offset` defaults to `0`, `len` defaults to `buffer.byteLength - offset`, and `pos` defaults to `-1` (current position). Returns the number of bytes read.
|
||||
|
||||
#### `fs.read(fd, buffer[, offset[, len[, pos]]], callback)`
|
||||
|
||||
Callback version of `fs.read()`.
|
||||
|
||||
#### `const bytesRead = fs.readSync(fd, buffer[, offset[, len[, pos]]])`
|
||||
|
||||
Synchronous version of `fs.read()`.
|
||||
|
||||
#### `const bytesRead = await fs.readv(fd, buffers[, pos])`
|
||||
|
||||
Read from a file descriptor into an array of `buffers`. `pos` defaults to `-1`.
|
||||
|
||||
#### `fs.readv(fd, buffers[, pos], callback)`
|
||||
|
||||
Callback version of `fs.readv()`.
|
||||
|
||||
#### `const bytesRead = fs.readvSync(fd, buffers[, pos])`
|
||||
|
||||
Synchronous version of `fs.readv()`.
|
||||
|
||||
#### `const bytesWritten = await fs.write(fd, data[, offset[, len[, pos]]])`
|
||||
|
||||
Write `data` to a file descriptor. When `data` is a string, the signature is `fs.write(fd, data[, pos[, encoding]])` where `encoding` defaults to `'utf8'`. Returns the number of bytes written.
|
||||
|
||||
#### `fs.write(fd, data[, offset[, len[, pos]]], callback)`
|
||||
|
||||
Callback version of `fs.write()`.
|
||||
|
||||
#### `const bytesWritten = fs.writeSync(fd, data[, offset[, len[, pos]]])`
|
||||
|
||||
Synchronous version of `fs.write()`.
|
||||
|
||||
#### `const bytesWritten = await fs.writev(fd, buffers[, pos])`
|
||||
|
||||
Write an array of `buffers` to a file descriptor. `pos` defaults to `-1`.
|
||||
|
||||
#### `fs.writev(fd, buffers[, pos], callback)`
|
||||
|
||||
Callback version of `fs.writev()`.
|
||||
|
||||
#### `const bytesWritten = fs.writevSync(fd, buffers[, pos])`
|
||||
|
||||
Synchronous version of `fs.writev()`.
|
||||
|
||||
#### `const stats = await fs.stat(filepath)`
|
||||
|
||||
Get the status of a file. Returns a `Stats` object.
|
||||
|
||||
#### `fs.stat(filepath, callback)`
|
||||
|
||||
Callback version of `fs.stat()`.
|
||||
|
||||
#### `const stats = fs.statSync(filepath)`
|
||||
|
||||
Synchronous version of `fs.stat()`.
|
||||
|
||||
#### `const stats = await fs.lstat(filepath)`
|
||||
|
||||
Like `fs.stat()`, but if `filepath` is a symbolic link, the link itself is statted, not the file it refers to.
|
||||
|
||||
#### `fs.lstat(filepath, callback)`
|
||||
|
||||
Callback version of `fs.lstat()`.
|
||||
|
||||
#### `const stats = fs.lstatSync(filepath)`
|
||||
|
||||
Synchronous version of `fs.lstat()`.
|
||||
|
||||
#### `const stats = await fs.fstat(fd)`
|
||||
|
||||
Get the status of a file by its file descriptor. Returns a `Stats` object.
|
||||
|
||||
#### `fs.fstat(fd, callback)`
|
||||
|
||||
Callback version of `fs.fstat()`.
|
||||
|
||||
#### `const stats = fs.fstatSync(fd)`
|
||||
|
||||
Synchronous version of `fs.fstat()`.
|
||||
|
||||
#### `const stats = await fs.statfs(filepath)`
|
||||
|
||||
Get filesystem statistics. Returns a `StatFs` object.
|
||||
|
||||
#### `fs.statfs(filepath, callback)`
|
||||
|
||||
Callback version of `fs.statfs()`.
|
||||
|
||||
#### `const stats = fs.statfsSync(filepath)`
|
||||
|
||||
Synchronous version of `fs.statfs()`.
|
||||
|
||||
#### `await fs.ftruncate(fd[, len])`
|
||||
|
||||
Truncate a file to `len` bytes. `len` defaults to `0`.
|
||||
|
||||
#### `fs.ftruncate(fd[, len], callback)`
|
||||
|
||||
Callback version of `fs.ftruncate()`.
|
||||
|
||||
#### `fs.ftruncateSync(fd[, len])`
|
||||
|
||||
Synchronous version of `fs.ftruncate()`.
|
||||
|
||||
#### `await fs.chmod(filepath, mode)`
|
||||
|
||||
Change the permissions of a file. `mode` may be a numeric mode or a string that will be parsed as octal.
|
||||
|
||||
#### `fs.chmod(filepath, mode, callback)`
|
||||
|
||||
Callback version of `fs.chmod()`.
|
||||
|
||||
#### `fs.chmodSync(filepath, mode)`
|
||||
|
||||
Synchronous version of `fs.chmod()`.
|
||||
|
||||
#### `await fs.fchmod(fd, mode)`
|
||||
|
||||
Change the permissions of a file by its file descriptor.
|
||||
|
||||
#### `fs.fchmod(fd, mode, callback)`
|
||||
|
||||
Callback version of `fs.fchmod()`.
|
||||
|
||||
#### `fs.fchmodSync(fd, mode)`
|
||||
|
||||
Synchronous version of `fs.fchmod()`.
|
||||
|
||||
#### `await fs.chown(filepath, uid, gid)`
|
||||
|
||||
Change the owner and group of a file.
|
||||
|
||||
**NOTE**: The `chown` functions are not implemented on Windows.
|
||||
|
||||
#### `fs.chown(filepath, uid, gid, callback)`
|
||||
|
||||
Callback version of `fs.chown()`.
|
||||
|
||||
#### `await fs.chownSync(filepath, uid, gid)`
|
||||
|
||||
Synchronous version of `fs.chown()`.
|
||||
|
||||
#### `await fs.lchown(filepath, uid, gid)`
|
||||
|
||||
Change the owner and group of a file, but if `filepath` is a symbolic link, the changes are applied only to the link, not the file it refers to.
|
||||
|
||||
#### `fs.lchown(filepath, uid, gid, callback)`
|
||||
|
||||
Callback version of `fs.lchown()`.
|
||||
|
||||
#### `fs.lchownSync(filepath, uid, gid)`
|
||||
|
||||
Synchronous version of `fs.lchown()`.
|
||||
|
||||
#### `await fs.fchown(filepath, uid, gid)`
|
||||
|
||||
Change the owner and group of a file by its file descriptor.
|
||||
|
||||
#### `fs.fchown(filepath, uid, gid, callback)`
|
||||
|
||||
Callback version of `fs.fchown()`.
|
||||
|
||||
#### `fs.fchownSync(filepath, uid, gid)`
|
||||
|
||||
Synchronous version of `fs.fchown()`.
|
||||
|
||||
#### `await fs.utimes(filepath, atime, mtime)`
|
||||
|
||||
Change the access and modification times of a file. Times may be numbers (seconds since epoch) or `Date` objects.
|
||||
|
||||
#### `fs.utimes(filepath, atime, mtime, callback)`
|
||||
|
||||
Callback version of `fs.utimes()`.
|
||||
|
||||
#### `fs.utimesSync(filepath, atime, mtime)`
|
||||
|
||||
Synchronous version of `fs.utimes()`.
|
||||
|
||||
#### `await fs.lutimes(filepath, atime, mtime)`
|
||||
|
||||
Like `fs.utimes()`, but if `filepath` is a symbolic link, the timestamps of the link is changed, not the file it refers to.
|
||||
|
||||
#### `fs.lutimes(filepath, atime, mtime, callback)`
|
||||
|
||||
Callback version of `fs.lutimes()`.
|
||||
|
||||
#### `fs.lutimesSync(filepath, atime, mtime)`
|
||||
|
||||
Synchronous version of `fs.lutimes()`.
|
||||
|
||||
#### `await fs.futimes(fd, atime, mtime)`
|
||||
|
||||
Change the access and modification times of a file by its file descriptor. Times may be numbers (seconds since epoch) or `Date` objects.
|
||||
|
||||
#### `fs.futimes(fd, atime, mtime, callback)`
|
||||
|
||||
Callback version of `fs.futimes()`.
|
||||
|
||||
#### `fs.futimesSync(fd, atime, mtime)`
|
||||
|
||||
Synchronous version of `fs.futimes()`.
|
||||
|
||||
#### `await fs.link(src, dst)`
|
||||
|
||||
Creates a new link (also known as a hard link) to an existing file.
|
||||
|
||||
#### `fs.link(src, dst, callback)`
|
||||
|
||||
Callback version of `fs.link()`.
|
||||
|
||||
#### `fs.linkSync(src, dst)`
|
||||
|
||||
Synchronous version of `fs.link()`.
|
||||
|
||||
#### `await fs.mkdir(filepath[, opts])`
|
||||
|
||||
Create a directory at `filepath`.
|
||||
|
||||
Options include:
|
||||
|
||||
```js
|
||||
options = {
|
||||
mode: 0o777,
|
||||
recursive: false
|
||||
}
|
||||
```
|
||||
|
||||
If `opts` is a number, it is treated as the `mode`. When `recursive` is `true`, parent directories are created as needed.
|
||||
|
||||
#### `fs.mkdir(filepath[, opts], callback)`
|
||||
|
||||
Callback version of `fs.mkdir()`.
|
||||
|
||||
#### `fs.mkdirSync(filepath[, opts])`
|
||||
|
||||
Synchronous version of `fs.mkdir()`.
|
||||
|
||||
#### `const path = await fs.mkdtemp(prefix)`
|
||||
|
||||
Create a unique temporary directory.
|
||||
|
||||
#### `fs.mkdtemp(prefix, callback)`
|
||||
|
||||
Callback version of `fs.mkdtemp()`.
|
||||
|
||||
#### `const path = fs.mkdtempSync(prefix)`
|
||||
|
||||
Synchronous version of `fs.mkdtemp()`.
|
||||
|
||||
#### `await fs.rmdir(filepath)`
|
||||
|
||||
Remove an empty directory.
|
||||
|
||||
#### `fs.rmdir(filepath, callback)`
|
||||
|
||||
Callback version of `fs.rmdir()`.
|
||||
|
||||
#### `fs.rmdirSync(filepath)`
|
||||
|
||||
Synchronous version of `fs.rmdir()`.
|
||||
|
||||
#### `await fs.rm(filepath[, opts])`
|
||||
|
||||
Remove a file or directory at `filepath`.
|
||||
|
||||
Options include:
|
||||
|
||||
```js
|
||||
options = {
|
||||
force: false,
|
||||
recursive: false
|
||||
}
|
||||
```
|
||||
|
||||
When `recursive` is `true`, directories are removed along with their contents. When `force` is `true`, no error is thrown if `filepath` does not exist.
|
||||
|
||||
#### `fs.rm(filepath[, opts], callback)`
|
||||
|
||||
Callback version of `fs.rm()`.
|
||||
|
||||
#### `fs.rmSync(filepath[, opts])`
|
||||
|
||||
Synchronous version of `fs.rm()`.
|
||||
|
||||
#### `await fs.unlink(filepath)`
|
||||
|
||||
Remove a file.
|
||||
|
||||
#### `fs.unlink(filepath, callback)`
|
||||
|
||||
Callback version of `fs.unlink()`.
|
||||
|
||||
#### `fs.unlinkSync(filepath)`
|
||||
|
||||
Synchronous version of `fs.unlink()`.
|
||||
|
||||
#### `await fs.rename(src, dst)`
|
||||
|
||||
Rename a file from `src` to `dst`.
|
||||
|
||||
#### `fs.rename(src, dst, callback)`
|
||||
|
||||
Callback version of `fs.rename()`.
|
||||
|
||||
#### `fs.renameSync(src, dst)`
|
||||
|
||||
Synchronous version of `fs.rename()`.
|
||||
|
||||
#### `await fs.copyFile(src, dst[, mode])`
|
||||
|
||||
Copy a file from `src` to `dst`. `mode` is an optional bitmask created from `fs.constants.COPYFILE_EXCL`, `fs.constants.COPYFILE_FICLONE`, or `fs.constants.COPYFILE_FICLONE_FORCE`.
|
||||
|
||||
#### `fs.copyFile(src, dst[, mode], callback)`
|
||||
|
||||
Callback version of `fs.copyFile()`.
|
||||
|
||||
#### `fs.copyFileSync(src, dst[, mode])`
|
||||
|
||||
Synchronous version of `fs.copyFile()`.
|
||||
|
||||
#### `await fs.cp(src, dst[, opts])`
|
||||
|
||||
Copy a file or directory from `src` to `dst`.
|
||||
|
||||
Options include:
|
||||
|
||||
```js
|
||||
options = {
|
||||
recursive: false
|
||||
}
|
||||
```
|
||||
|
||||
Set `recursive` to `true` to copy directories and their contents. Files are copied preserving their permissions.
|
||||
|
||||
#### `fs.cp(src, dst[, opts], callback)`
|
||||
|
||||
Callback version of `fs.cp()`.
|
||||
|
||||
#### `fs.cpSync(src, dst[, opts])`
|
||||
|
||||
Synchronous version of `fs.cp()`.
|
||||
|
||||
#### `const resolved = await fs.realpath(filepath[, opts])`
|
||||
|
||||
Resolve the real path of `filepath`, expanding all symbolic links.
|
||||
|
||||
Options include:
|
||||
|
||||
```js
|
||||
options = {
|
||||
encoding: 'utf8'
|
||||
}
|
||||
```
|
||||
|
||||
Set `encoding` to `'buffer'` to receive the result as a `Buffer`.
|
||||
|
||||
#### `fs.realpath(filepath[, opts], callback)`
|
||||
|
||||
Callback version of `fs.realpath()`.
|
||||
|
||||
#### `const resolved = fs.realpathSync(filepath[, opts])`
|
||||
|
||||
Synchronous version of `fs.realpath()`.
|
||||
|
||||
#### `const target = await fs.readlink(filepath[, opts])`
|
||||
|
||||
Read the target of a symbolic link.
|
||||
|
||||
Options include:
|
||||
|
||||
```js
|
||||
options = {
|
||||
encoding: 'utf8'
|
||||
}
|
||||
```
|
||||
|
||||
#### `fs.readlink(filepath[, opts], callback)`
|
||||
|
||||
Callback version of `fs.readlink()`.
|
||||
|
||||
#### `const target = fs.readlinkSync(filepath[, opts])`
|
||||
|
||||
Synchronous version of `fs.readlink()`.
|
||||
|
||||
#### `await fs.truncate(filename[, len])`
|
||||
|
||||
Truncate the file at `filename` to `len` bytes. `len` defaults to `0`.
|
||||
|
||||
#### `fs.truncate(filename[, len], callback)`
|
||||
|
||||
Callback version of `fs.truncate()`.
|
||||
|
||||
#### `fs.truncateSync(filename[, len])`
|
||||
|
||||
Synchronous version of `fs.truncate()`.
|
||||
|
||||
#### `await fs.symlink(target, filepath[, type])`
|
||||
|
||||
Create a symbolic link at `filepath` pointing to `target`. `type` may be `'file'`, `'dir'`, or `'junction'` (Windows only) or a numeric flag. On Windows, if `type` is not provided, it is inferred from the target.
|
||||
|
||||
#### `fs.symlink(target, filepath[, type], callback)`
|
||||
|
||||
Callback version of `fs.symlink()`.
|
||||
|
||||
#### `fs.symlinkSync(target, filepath[, type])`
|
||||
|
||||
Synchronous version of `fs.symlink()`.
|
||||
|
||||
#### `await fs.fsync(fd)`
|
||||
|
||||
Flush all modified in-core data of the file referred by its file descriptor to the disk device.
|
||||
|
||||
#### `fs.fsync(fs, callback)`
|
||||
|
||||
Callback version of `fs.fsync()`.
|
||||
|
||||
#### `fs.fsyncSync(fd)`
|
||||
|
||||
Synchronous version of `fs.fsync()`.
|
||||
|
||||
#### `await fs.fdatasync(fd)`
|
||||
|
||||
Similar to `fsync`, but does not flush modified metadata unless necessary.
|
||||
|
||||
#### `fs.fdatasync(fs, callback)`
|
||||
|
||||
Callback version of `fs.fdatasync()`.
|
||||
|
||||
#### `fs.fdatasyncSync(fd)`
|
||||
|
||||
Synchronous version of `fs.fdatasync()`.
|
||||
|
||||
#### `const dir = await fs.opendir(filepath[, opts])`
|
||||
|
||||
Open a directory for iteration. Returns a `Dir` object.
|
||||
|
||||
Options include:
|
||||
|
||||
```js
|
||||
options = {
|
||||
encoding: 'utf8',
|
||||
bufferSize: 32
|
||||
}
|
||||
```
|
||||
|
||||
#### `fs.opendir(filepath[, opts], callback)`
|
||||
|
||||
Callback version of `fs.opendir()`.
|
||||
|
||||
#### `const dir = fs.opendirSync(filepath[, opts])`
|
||||
|
||||
Synchronous version of `fs.opendir()`.
|
||||
|
||||
#### `const entries = await fs.readdir(filepath[, opts])`
|
||||
|
||||
Read the contents of a directory. Returns an array of filenames or, if `withFileTypes` is `true`, an array of `Dirent` objects.
|
||||
|
||||
Options include:
|
||||
|
||||
```js
|
||||
options = {
|
||||
encoding: 'utf8',
|
||||
withFileTypes: false,
|
||||
recursive: false
|
||||
}
|
||||
```
|
||||
|
||||
#### `fs.readdir(filepath[, opts], callback)`
|
||||
|
||||
Callback version of `fs.readdir()`.
|
||||
|
||||
#### `const entries = fs.readdirSync(filepath[, opts])`
|
||||
|
||||
Synchronous version of `fs.readdir()`.
|
||||
|
||||
#### `const data = await fs.readFile(filepath[, opts])`
|
||||
|
||||
Read the entire contents of a file. Returns a `Buffer` by default, or a string if an `encoding` is specified.
|
||||
|
||||
Options include:
|
||||
|
||||
```js
|
||||
options = {
|
||||
encoding: 'buffer',
|
||||
flag: 'r'
|
||||
}
|
||||
```
|
||||
|
||||
#### `fs.readFile(filepath[, opts], callback)`
|
||||
|
||||
Callback version of `fs.readFile()`.
|
||||
|
||||
#### `const data = fs.readFileSync(filepath[, opts])`
|
||||
|
||||
Synchronous version of `fs.readFile()`.
|
||||
|
||||
#### `await fs.writeFile(filepath, data[, opts])`
|
||||
|
||||
Write `data` to a file, replacing it if it already exists.
|
||||
|
||||
Options include:
|
||||
|
||||
```js
|
||||
options = {
|
||||
encoding: 'utf8',
|
||||
flag: 'w',
|
||||
mode: 0o666
|
||||
}
|
||||
```
|
||||
|
||||
#### `fs.writeFile(filepath, data[, opts], callback)`
|
||||
|
||||
Callback version of `fs.writeFile()`.
|
||||
|
||||
#### `fs.writeFileSync(filepath, data[, opts])`
|
||||
|
||||
Synchronous version of `fs.writeFile()`.
|
||||
|
||||
#### `await fs.appendFile(filepath, data[, opts])`
|
||||
|
||||
Append `data` to a file, creating it if it does not exist. Accepts the same options as `fs.writeFile()` but defaults to the `'a'` flag.
|
||||
|
||||
#### `fs.appendFile(filepath, data[, opts], callback)`
|
||||
|
||||
Callback version of `fs.appendFile()`.
|
||||
|
||||
#### `fs.appendFileSync(filepath, data[, opts])`
|
||||
|
||||
Synchronous version of `fs.appendFile()`.
|
||||
|
||||
#### `const watcher = fs.watch(filepath[, opts], callback)`
|
||||
|
||||
Watch a file or directory for changes. Returns a `Watcher` object. The `callback`, if provided, is called with `(eventType, filename)` on each change.
|
||||
|
||||
Options include:
|
||||
|
||||
```js
|
||||
options = {
|
||||
persistent: true,
|
||||
recursive: false,
|
||||
encoding: 'utf8'
|
||||
}
|
||||
```
|
||||
|
||||
#### `const stream = fs.createReadStream(path[, opts])`
|
||||
|
||||
Create a readable stream for a file. Returns a `ReadStream`.
|
||||
|
||||
Options include:
|
||||
|
||||
```js
|
||||
options = {
|
||||
fd: -1,
|
||||
flags: 'r',
|
||||
mode: 0o666,
|
||||
start: 0,
|
||||
end: Infinity
|
||||
}
|
||||
```
|
||||
|
||||
If `fd` is provided, `path` may be `null` and the stream reads from the given file descriptor.
|
||||
|
||||
#### `const stream = fs.createWriteStream(path[, opts])`
|
||||
|
||||
Create a writable stream for a file. Returns a `WriteStream`.
|
||||
|
||||
Options include:
|
||||
|
||||
```js
|
||||
options = {
|
||||
fd: -1,
|
||||
flags: 'w',
|
||||
mode: 0o666
|
||||
}
|
||||
```
|
||||
|
||||
If `fd` is provided, `path` may be `null` and the stream writes to the given file descriptor.
|
||||
|
||||
#### `fs.constants`
|
||||
|
||||
An object containing file system constants. See `fs/constants` for the full list. Commonly used constants include:
|
||||
|
||||
- `fs.constants.O_RDONLY`, `fs.constants.O_WRONLY`, `fs.constants.O_RDWR` — file access flags
|
||||
- `fs.constants.O_CREAT`, `fs.constants.O_TRUNC`, `fs.constants.O_APPEND` — file creation flags
|
||||
- `fs.constants.F_OK`, `fs.constants.R_OK`, `fs.constants.W_OK`, `fs.constants.X_OK` — file accessibility flags
|
||||
- `fs.constants.S_IFMT`, `fs.constants.S_IFREG`, `fs.constants.S_IFDIR`, `fs.constants.S_IFLNK` — file type flags
|
||||
- `fs.constants.COPYFILE_EXCL`, `fs.constants.COPYFILE_FICLONE`, `fs.constants.COPYFILE_FICLONE_FORCE` — copy flags
|
||||
|
||||
### `Stats`
|
||||
|
||||
Returned by `fs.stat()`, `fs.lstat()`, and `fs.fstat()`.
|
||||
|
||||
#### `stats.dev`
|
||||
|
||||
The device identifier.
|
||||
|
||||
#### `stats.mode`
|
||||
|
||||
The file mode (type and permissions).
|
||||
|
||||
#### `stats.nlink`
|
||||
|
||||
The number of hard links.
|
||||
|
||||
#### `stats.uid`
|
||||
|
||||
The user identifier of the file owner.
|
||||
|
||||
#### `stats.gid`
|
||||
|
||||
The group identifier of the file owner.
|
||||
|
||||
#### `stats.rdev`
|
||||
|
||||
The device identifier for special files.
|
||||
|
||||
#### `stats.blksize`
|
||||
|
||||
The file system block size for I/O operations.
|
||||
|
||||
#### `stats.ino`
|
||||
|
||||
The inode number.
|
||||
|
||||
#### `stats.size`
|
||||
|
||||
The size of the file in bytes.
|
||||
|
||||
#### `stats.blocks`
|
||||
|
||||
The number of 512-byte blocks allocated.
|
||||
|
||||
#### `stats.atimeMs`
|
||||
|
||||
The access time in milliseconds since the epoch.
|
||||
|
||||
#### `stats.mtimeMs`
|
||||
|
||||
The modification time in milliseconds since the epoch.
|
||||
|
||||
#### `stats.ctimeMs`
|
||||
|
||||
The change time in milliseconds since the epoch.
|
||||
|
||||
#### `stats.birthtimeMs`
|
||||
|
||||
The creation time in milliseconds since the epoch.
|
||||
|
||||
#### `stats.atime`
|
||||
|
||||
The access time as a `Date` object.
|
||||
|
||||
#### `stats.mtime`
|
||||
|
||||
The modification time as a `Date` object.
|
||||
|
||||
#### `stats.ctime`
|
||||
|
||||
The change time as a `Date` object.
|
||||
|
||||
#### `stats.birthtime`
|
||||
|
||||
The creation time as a `Date` object.
|
||||
|
||||
#### `stats.isDirectory()`
|
||||
|
||||
Returns `true` if the file is a directory.
|
||||
|
||||
#### `stats.isFile()`
|
||||
|
||||
Returns `true` if the file is a regular file.
|
||||
|
||||
#### `stats.isBlockDevice()`
|
||||
|
||||
Returns `true` if the file is a block device.
|
||||
|
||||
#### `stats.isCharacterDevice()`
|
||||
|
||||
Returns `true` if the file is a character device.
|
||||
|
||||
#### `stats.isFIFO()`
|
||||
|
||||
Returns `true` if the file is a FIFO (named pipe).
|
||||
|
||||
#### `stats.isSymbolicLink()`
|
||||
|
||||
Returns `true` if the file is a symbolic link. Only meaningful when using `fs.lstat()`.
|
||||
|
||||
#### `stats.isSocket()`
|
||||
|
||||
Returns `true` if the file is a socket.
|
||||
|
||||
### `Dir`
|
||||
|
||||
Returned by `fs.opendir()`. Supports both synchronous and asynchronous iteration.
|
||||
|
||||
#### `dir.path`
|
||||
|
||||
The path of the directory.
|
||||
|
||||
#### `const dirent = await dir.read()`
|
||||
|
||||
Read the next directory entry. Returns a `Dirent` or `null` when all entries have been read.
|
||||
|
||||
#### `dir.read(callback)`
|
||||
|
||||
Callback version of `dir.read()`.
|
||||
|
||||
#### `const dirent = dir.readSync()`
|
||||
|
||||
Synchronous version of `dir.read()`.
|
||||
|
||||
#### `await dir.close()`
|
||||
|
||||
Close the directory handle.
|
||||
|
||||
#### `dir.close(callback)`
|
||||
|
||||
Callback version of `dir.close()`.
|
||||
|
||||
#### `dir.closeSync()`
|
||||
|
||||
Synchronous version of `dir.close()`.
|
||||
|
||||
### `Dirent`
|
||||
|
||||
Represents a directory entry, returned when iterating a `Dir` or using `fs.readdir()` with `withFileTypes: true`.
|
||||
|
||||
#### `dirent.parentPath`
|
||||
|
||||
The path of the parent directory.
|
||||
|
||||
#### `dirent.name`
|
||||
|
||||
The name of the directory entry, as a string or `Buffer` depending on the encoding.
|
||||
|
||||
#### `dirent.type`
|
||||
|
||||
The numeric type of the directory entry.
|
||||
|
||||
#### `dirent.isFile()`
|
||||
|
||||
Returns `true` if the entry is a regular file.
|
||||
|
||||
#### `dirent.isDirectory()`
|
||||
|
||||
Returns `true` if the entry is a directory.
|
||||
|
||||
#### `dirent.isSymbolicLink()`
|
||||
|
||||
Returns `true` if the entry is a symbolic link.
|
||||
|
||||
#### `dirent.isFIFO()`
|
||||
|
||||
Returns `true` if the entry is a FIFO.
|
||||
|
||||
#### `dirent.isSocket()`
|
||||
|
||||
Returns `true` if the entry is a socket.
|
||||
|
||||
#### `dirent.isCharacterDevice()`
|
||||
|
||||
Returns `true` if the entry is a character device.
|
||||
|
||||
#### `dirent.isBlockDevice()`
|
||||
|
||||
Returns `true` if the entry is a block device.
|
||||
|
||||
### `ReadStream`
|
||||
|
||||
A readable stream for file data, created by `fs.createReadStream()`. Extends `Readable` from <https://github.com/holepunchto/bare-stream>.
|
||||
|
||||
#### `stream.path`
|
||||
|
||||
The file path, or `null` if opened by file descriptor.
|
||||
|
||||
#### `stream.fd`
|
||||
|
||||
The underlying file descriptor.
|
||||
|
||||
#### `stream.flags`
|
||||
|
||||
The flags the file was opened with.
|
||||
|
||||
#### `stream.mode`
|
||||
|
||||
The mode the file was opened with.
|
||||
|
||||
### `WriteStream`
|
||||
|
||||
A writable stream for file data, created by `fs.createWriteStream()`. Extends `Writable` from <https://github.com/holepunchto/bare-stream>.
|
||||
|
||||
#### `stream.path`
|
||||
|
||||
The file path, or `null` if opened by file descriptor.
|
||||
|
||||
#### `stream.fd`
|
||||
|
||||
The underlying file descriptor.
|
||||
|
||||
#### `stream.flags`
|
||||
|
||||
The flags the file was opened with.
|
||||
|
||||
#### `stream.mode`
|
||||
|
||||
The mode the file was opened with.
|
||||
|
||||
### `Watcher`
|
||||
|
||||
Watches for file system changes, created by `fs.watch()`. Extends `EventEmitter` from <https://github.com/holepunchto/bare-events>.
|
||||
|
||||
#### `watcher.close()`
|
||||
|
||||
Stop watching for changes.
|
||||
|
||||
#### `watcher.ref()`
|
||||
|
||||
Prevent the event loop from exiting while the watcher is active.
|
||||
|
||||
#### `watcher.unref()`
|
||||
|
||||
Allow the event loop to exit even if the watcher is still active.
|
||||
|
||||
#### `event: 'change'`
|
||||
|
||||
Emitted with `(eventType, filename)` when a change is detected. `eventType` is either `'rename'` or `'change'`.
|
||||
|
||||
#### `event: 'error'`
|
||||
|
||||
Emitted with `(err)` when an error occurs.
|
||||
|
||||
#### `event: 'close'`
|
||||
|
||||
Emitted when the watcher is closed.
|
||||
|
||||
### `FileHandle`
|
||||
|
||||
Returned by `require('bare-fs/promises').open()`. Provides an object-oriented API for working with file descriptors.
|
||||
|
||||
#### `await handle.close()`
|
||||
|
||||
Close the file handle.
|
||||
|
||||
#### `const { bytesRead, buffer } = await handle.read(buffer[, offset[, len[, pos]]])`
|
||||
|
||||
Read from the file into `buffer`.
|
||||
|
||||
#### `const { bytesRead, buffers } = await handle.readv(buffers[, pos])`
|
||||
|
||||
Read from the file into an array of `buffers`.
|
||||
|
||||
#### `const { bytesWritten, buffer } = await handle.write(data[, offset[, len[, pos]]])`
|
||||
|
||||
Write `data` to the file.
|
||||
|
||||
#### `const { bytesWritten, buffers } = await handle.writev(buffers[, pos])`
|
||||
|
||||
Write an array of `buffers` to the file.
|
||||
|
||||
#### `const stats = await handle.stat()`
|
||||
|
||||
Get the status of the file.
|
||||
|
||||
#### `await handle.chmod(mode)`
|
||||
|
||||
Change the permissions of the file.
|
||||
|
||||
#### `await handle.chown(uid, gid)`
|
||||
|
||||
Change the owner and group of the file.
|
||||
|
||||
**NOTE**: This function is not implemented on Windows.
|
||||
|
||||
#### `await handle.datasync()`
|
||||
|
||||
Similar to `fsync`, but does not flush modified metadata unless necessary.
|
||||
|
||||
#### `await handle.sync()`
|
||||
|
||||
Flush all modified in-core data of the file.
|
||||
|
||||
#### `await handle.truncate(len)`
|
||||
|
||||
Truncate the file.
|
||||
|
||||
#### `await handle.utimes(mode)`
|
||||
|
||||
Change the access and modification times of the file.
|
||||
|
||||
#### `const stream = handle.createReadStream([opts])`
|
||||
|
||||
Create a readable stream for the file.
|
||||
|
||||
#### `const stream = handle.createWriteStream([opts])`
|
||||
|
||||
Create a writable stream for the file.
|
||||
|
||||
#### `handle.fd`
|
||||
|
||||
The file descriptor number.
|
||||
|
||||
#### `event: 'close'`
|
||||
|
||||
Emitted when the file handle is closed.
|
||||
|
||||
## License
|
||||
|
||||
Apache-2.0
|
||||
+2889
File diff suppressed because it is too large
Load Diff
+1
@@ -0,0 +1 @@
|
||||
module.exports = require.addon()
|
||||
+1223
File diff suppressed because it is too large
Load Diff
+2842
File diff suppressed because it is too large
Load Diff
+49
@@ -0,0 +1,49 @@
|
||||
declare const constants: {
|
||||
O_RDWR: number
|
||||
O_RDONLY: number
|
||||
O_WRONLY: number
|
||||
O_CREAT: number
|
||||
O_TRUNC: number
|
||||
O_APPEND: number
|
||||
|
||||
F_OK: number
|
||||
R_OK: number
|
||||
W_OK: number
|
||||
X_OK: number
|
||||
|
||||
S_IFMT: number
|
||||
S_IFREG: number
|
||||
S_IFDIR: number
|
||||
S_IFCHR: number
|
||||
S_IFLNK: number
|
||||
S_IFBLK: number
|
||||
S_IFIFO: number
|
||||
S_IFSOCK: number
|
||||
|
||||
S_IRUSR: number
|
||||
S_IWUSR: number
|
||||
S_IXUSR: number
|
||||
S_IRGRP: number
|
||||
S_IWGRP: number
|
||||
S_IXGRP: number
|
||||
S_IROTH: number
|
||||
S_IWOTH: number
|
||||
S_IXOTH: number
|
||||
|
||||
UV_DIRENT_UNKNOWN: number
|
||||
UV_DIRENT_FILE: number
|
||||
UV_DIRENT_DIR: number
|
||||
UV_DIRENT_LINK: number
|
||||
UV_DIRENT_FIFO: number
|
||||
UV_DIRENT_SOCKET: number
|
||||
UV_DIRENT_CHAR: number
|
||||
UV_DIRENT_BLOCK: number
|
||||
|
||||
COPYFILE_EXCL: number
|
||||
COPYFILE_FICLONE: number
|
||||
COPYFILE_FICLONE_FORCE: number
|
||||
UV_FS_SYMLINK_DIR: number
|
||||
UV_FS_SYMLINK_JUNCTION: number
|
||||
}
|
||||
|
||||
export = constants
|
||||
+49
@@ -0,0 +1,49 @@
|
||||
const binding = require('../binding')
|
||||
|
||||
module.exports = {
|
||||
O_RDWR: binding.O_RDWR,
|
||||
O_RDONLY: binding.O_RDONLY,
|
||||
O_WRONLY: binding.O_WRONLY,
|
||||
O_CREAT: binding.O_CREAT,
|
||||
O_TRUNC: binding.O_TRUNC,
|
||||
O_APPEND: binding.O_APPEND,
|
||||
|
||||
F_OK: binding.F_OK || 0,
|
||||
R_OK: binding.R_OK || 0,
|
||||
W_OK: binding.W_OK || 0,
|
||||
X_OK: binding.X_OK || 0,
|
||||
|
||||
S_IFMT: binding.S_IFMT,
|
||||
S_IFREG: binding.S_IFREG,
|
||||
S_IFDIR: binding.S_IFDIR,
|
||||
S_IFCHR: binding.S_IFCHR,
|
||||
S_IFLNK: binding.S_IFLNK,
|
||||
S_IFBLK: binding.S_IFBLK || 0,
|
||||
S_IFIFO: binding.S_IFIFO || 0,
|
||||
S_IFSOCK: binding.S_IFSOCK || 0,
|
||||
|
||||
S_IRUSR: binding.S_IRUSR || 0,
|
||||
S_IWUSR: binding.S_IWUSR || 0,
|
||||
S_IXUSR: binding.S_IXUSR || 0,
|
||||
S_IRGRP: binding.S_IRGRP || 0,
|
||||
S_IWGRP: binding.S_IWGRP || 0,
|
||||
S_IXGRP: binding.S_IXGRP || 0,
|
||||
S_IROTH: binding.S_IROTH || 0,
|
||||
S_IWOTH: binding.S_IWOTH || 0,
|
||||
S_IXOTH: binding.S_IXOTH || 0,
|
||||
|
||||
UV_DIRENT_UNKNOWN: binding.UV_DIRENT_UNKNOWN,
|
||||
UV_DIRENT_FILE: binding.UV_DIRENT_FILE,
|
||||
UV_DIRENT_DIR: binding.UV_DIRENT_DIR,
|
||||
UV_DIRENT_LINK: binding.UV_DIRENT_LINK,
|
||||
UV_DIRENT_FIFO: binding.UV_DIRENT_FIFO,
|
||||
UV_DIRENT_SOCKET: binding.UV_DIRENT_SOCKET,
|
||||
UV_DIRENT_CHAR: binding.UV_DIRENT_CHAR,
|
||||
UV_DIRENT_BLOCK: binding.UV_DIRENT_BLOCK,
|
||||
|
||||
COPYFILE_EXCL: binding.UV_FS_COPYFILE_EXCL,
|
||||
COPYFILE_FICLONE: binding.UV_FS_COPYFILE_FICLONE,
|
||||
COPYFILE_FICLONE_FORCE: binding.UV_FS_COPYFILE_FICLONE_FORCE,
|
||||
UV_FS_SYMLINK_DIR: binding.UV_FS_SYMLINK_DIR,
|
||||
UV_FS_SYMLINK_JUNCTION: binding.UV_FS_SYMLINK_JUNCTION
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
declare class FileError extends Error {
|
||||
private constructor(msg: string)
|
||||
|
||||
readonly code: string
|
||||
readonly operation?: string
|
||||
readonly path?: string
|
||||
readonly destination?: string
|
||||
readonly fd?: number
|
||||
}
|
||||
|
||||
export = FileError
|
||||
+55
@@ -0,0 +1,55 @@
|
||||
const os = require('bare-os')
|
||||
|
||||
module.exports = class FileError extends Error {
|
||||
constructor(msg, opts = {}) {
|
||||
const { code, operation = null, path = null, destination = null, fd = -1 } = opts
|
||||
|
||||
if (operation !== null) msg += describe(operation, opts)
|
||||
|
||||
super(`${code}: ${msg}`)
|
||||
|
||||
this.code = code
|
||||
|
||||
if (operation !== null) this.operation = operation
|
||||
if (path !== null) this.path = path
|
||||
if (destination !== null) this.destination = destination
|
||||
if (fd !== -1) this.fd = fd
|
||||
}
|
||||
|
||||
get name() {
|
||||
return 'FileError'
|
||||
}
|
||||
|
||||
// For Node.js compatibility
|
||||
get errno() {
|
||||
return os.constants.errnos[this.code]
|
||||
}
|
||||
|
||||
// For Node.js compatibility
|
||||
get syscall() {
|
||||
return this.operation
|
||||
}
|
||||
|
||||
// For Node.js compatibility
|
||||
get dest() {
|
||||
return this.destination
|
||||
}
|
||||
}
|
||||
|
||||
function describe(operation, opts) {
|
||||
const { path = null, destination = null, fd = -1 } = opts
|
||||
|
||||
let result = `, ${operation}`
|
||||
|
||||
if (path !== null) {
|
||||
result += ` ${JSON.stringify(path)}`
|
||||
|
||||
if (destination !== null) {
|
||||
result += ` -> ${JSON.stringify(destination)}`
|
||||
}
|
||||
} else if (fd !== -1) {
|
||||
result += ` ${fd}`
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
+74
@@ -0,0 +1,74 @@
|
||||
{
|
||||
"name": "bare-fs",
|
||||
"version": "4.7.1",
|
||||
"description": "Native file system operations for Bare",
|
||||
"exports": {
|
||||
"./package": "./package.json",
|
||||
".": {
|
||||
"types": "./index.d.ts",
|
||||
"default": "./index.js"
|
||||
},
|
||||
"./promises": {
|
||||
"types": "./promises.d.ts",
|
||||
"default": "./promises.js"
|
||||
},
|
||||
"./constants": {
|
||||
"types": "./lib/constants.d.ts",
|
||||
"default": "./lib/constants.js"
|
||||
}
|
||||
},
|
||||
"files": [
|
||||
"index.js",
|
||||
"index.d.ts",
|
||||
"promises.js",
|
||||
"promises.d.ts",
|
||||
"binding.c",
|
||||
"binding.js",
|
||||
"CMakeLists.txt",
|
||||
"lib",
|
||||
"prebuilds"
|
||||
],
|
||||
"addon": true,
|
||||
"scripts": {
|
||||
"format": "prettier --write . && lunte --fix",
|
||||
"lint": "prettier --check . && lunte",
|
||||
"test": "brittle-bare --coverage test.js"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/holepunchto/bare-fs.git"
|
||||
},
|
||||
"author": "Holepunch",
|
||||
"license": "Apache-2.0",
|
||||
"bugs": {
|
||||
"url": "https://github.com/holepunchto/bare-fs/issues"
|
||||
},
|
||||
"homepage": "https://github.com/holepunchto/bare-fs#readme",
|
||||
"engines": {
|
||||
"bare": ">=1.16.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"bare-events": "^2.5.4",
|
||||
"bare-path": "^3.0.0",
|
||||
"bare-stream": "^2.6.4",
|
||||
"bare-url": "^2.2.2",
|
||||
"fast-fifo": "^1.3.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"bare-buffer": "^3.0.2",
|
||||
"bare-crypto": "^1.11.2",
|
||||
"brittle": "^3.1.1",
|
||||
"cmake-bare": "^1.1.7",
|
||||
"lunte": "^1.6.0",
|
||||
"prettier": "^3.4.1",
|
||||
"prettier-config-holepunch": "^2.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"bare-buffer": "*"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"bare-buffer": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
}
|
||||
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user