Add comprehensive installation and setup documentation

- Add GETTING_STARTED.md with quick start guide and development modes
- Add INSTALL.sh automated installation script
- Add INSTALLATION_CHECKLIST.md, INSTALLATION_SUCCESS.md, and INSTALLATION_SUMMARY.md
- Add QUICK_REFERENCE.md for common commands
- Add SETUP_GUIDE.md with detailed setup instructions
- Update README.md with improved project overview
- Add did-wallet app dependencies and node_modules
This commit is contained in:
Dorian
2026-01-27 17:18:21 +00:00
parent a81f655133
commit 0d073fa89e
22658 changed files with 4494151 additions and 6 deletions
+4
View File
@@ -0,0 +1,4 @@
This project is dual licensed under MIT and Apache-2.0.
MIT: https://www.opensource.org/licenses/mit
Apache-2.0: https://www.apache.org/licenses/license-2.0
+140
View File
@@ -0,0 +1,140 @@
# it-pushable <!-- omit in toc -->
[![codecov](https://img.shields.io/codecov/c/github/alanshaw/it-pushable.svg?style=flat-square)](https://codecov.io/gh/alanshaw/it-pushable)
[![CI](https://img.shields.io/github/actions/workflow/status/alanshaw/it-pushable/js-test-and-release.yml?branch=master\&style=flat-square)](https://github.com/alanshaw/it-pushable/actions/workflows/js-test-and-release.yml?query=branch%3Amaster)
> An iterable that you can push values into
# About
An iterable that you can push values into.
## Example
```js
import { pushable } from 'it-pushable'
const source = pushable()
setTimeout(() => source.push('hello'), 100)
setTimeout(() => source.push('world'), 200)
setTimeout(() => source.end(), 300)
const start = Date.now()
for await (const value of source) {
console.log(`got "${value}" after ${Date.now() - start}ms`)
}
console.log(`done after ${Date.now() - start}ms`)
// Output:
// got "hello" after 105ms
// got "world" after 207ms
// done after 309ms
```
## Example
```js
import { pushableV } from 'it-pushable'
import all from 'it-all'
const source = pushableV()
source.push(1)
source.push(2)
source.push(3)
source.end()
console.info(await all(source))
// Output:
// [ [1, 2, 3] ]
```
## Table of contents <!-- omit in toc -->
- [Install](#install)
- [Browser `<script>` tag](#browser-script-tag)
- [Usage](#usage)
- [Related](#related)
- [API Docs](#api-docs)
- [License](#license)
- [Contribution](#contribution)
## Install
```console
$ npm i it-pushable
```
### Browser `<script>` tag
Loading this module through a script tag will make it's exports available as `ItPushable` in the global namespace.
```html
<script src="https://unpkg.com/it-pushable/dist/index.min.js"></script>
```
## Usage
```js
import { pushable } from 'it-pushable'
const source = pushable()
setTimeout(() => source.push('hello'), 100)
setTimeout(() => source.push('world'), 200)
setTimeout(() => source.end(), 300)
const start = Date.now()
for await (const value of source) {
console.log(`got "${value}" after ${Date.now() - start}ms`)
}
console.log(`done after ${Date.now() - start}ms`)
/*
Output:
got "hello" after 105ms
got "world" after 207ms
done after 309ms
*/
```
```js
import { pushableV } from 'it-pushable'
import all from 'it-all'
const source = pushableV()
source.push(1)
source.push(2)
source.push(3)
source.end()
console.info(await all(source))
/*
Output:
[ [1, 2, 3] ]
*/
```
## Related
- [`it-pipe`](https://www.npmjs.com/package/it-pipe) Utility to "pipe" async iterables together
## API Docs
- <https://alanshaw.github.io/it-pushable>
## License
Licensed under either of
- Apache 2.0, ([LICENSE-APACHE](LICENSE-APACHE) / <http://www.apache.org/licenses/LICENSE-2.0>)
- MIT ([LICENSE-MIT](LICENSE-MIT) / <http://opensource.org/licenses/MIT>)
## Contribution
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.
+3
View File
@@ -0,0 +1,3 @@
(function (root, factory) {(typeof module === 'object' && module.exports) ? module.exports = factory() : root.ItPushable = factory()}(typeof self !== 'undefined' ? self : this, function () {
"use strict";var ItPushable=(()=>{var y=Object.defineProperty;var S=Object.getOwnPropertyDescriptor;var _=Object.getOwnPropertyNames;var M=Object.prototype.hasOwnProperty;var P=(i,e)=>{for(var r in e)y(i,r,{get:e[r],enumerable:!0})},A=(i,e,r,t)=>{if(e&&typeof e=="object"||typeof e=="function")for(let u of _(e))!M.call(i,u)&&u!==r&&y(i,u,{get:()=>e[u],enumerable:!(t=S(e,u))||t.enumerable});return i};var I=i=>A(y({},"__esModule",{value:!0}),i);var T={};P(T,{AbortError:()=>b,pushable:()=>R,pushableV:()=>j});function c(){let i={};return i.promise=new Promise((e,r)=>{i.resolve=e,i.reject=r}),i}var p=class{buffer;mask;top;btm;next;constructor(e){if(!(e>0)||e-1&e)throw new Error("Max size for a FixedFIFO should be a power of two");this.buffer=new Array(e),this.mask=e-1,this.top=0,this.btm=0,this.next=null}push(e){return this.buffer[this.top]!==void 0?!1:(this.buffer[this.top]=e,this.top=this.top+1&this.mask,!0)}shift(){let e=this.buffer[this.btm];if(e!==void 0)return this.buffer[this.btm]=void 0,this.btm=this.btm+1&this.mask,e}isEmpty(){return this.buffer[this.btm]===void 0}},a=class{size;hwm;head;tail;constructor(e={}){this.hwm=e.splitLimit??16,this.head=new p(this.hwm),this.tail=this.head,this.size=0}calculateSize(e){return e?.byteLength!=null?e.byteLength:1}push(e){if(e?.value!=null&&(this.size+=this.calculateSize(e.value)),!this.head.push(e)){let r=this.head;this.head=r.next=new p(2*this.head.buffer.length),this.head.push(e)}}shift(){let e=this.tail.shift();if(e===void 0&&this.tail.next!=null){let r=this.tail.next;this.tail.next=null,this.tail=r,e=this.tail.shift()}return e?.value!=null&&(this.size-=this.calculateSize(e.value)),e}isEmpty(){return this.head.isEmpty()}};var b=class extends Error{type;code;constructor(e,r){super(e??"The operation was aborted"),this.type="aborted",this.code=r??"ABORT_ERR"}};function R(i={}){return g(r=>{let t=r.shift();if(t==null)return{done:!0};if(t.error!=null)throw t.error;return{done:t.done===!0,value:t.value}},i)}function j(i={}){return g(r=>{let t,u=[];for(;!r.isEmpty()&&(t=r.shift(),t!=null);){if(t.error!=null)throw t.error;t.done===!1&&u.push(t.value)}return t==null?{done:!0}:{done:t.done===!0,value:u}},i)}function g(i,e){e=e??{};let r=e.onEnd,t=new a,u,l,f,m=c(),v=async()=>{try{return t.isEmpty()?f?{done:!0}:await new Promise((n,s)=>{l=d=>{l=null,t.push(d);try{n(i(t))}catch(h){s(h)}return u}}):i(t)}finally{t.isEmpty()&&queueMicrotask(()=>{m.resolve(),m=c()})}},x=n=>l!=null?l(n):(t.push(n),u),z=n=>(t=new a,l!=null?l({error:n}):(t.push({error:n}),u)),E=n=>{if(f)return u;if(e?.objectMode!==!0&&n?.byteLength==null)throw new Error("objectMode was not true but tried to push non-Uint8Array value");return x({done:!1,value:n})},w=n=>f?u:(f=!0,n!=null?z(n):x({done:!0})),L=()=>(t=new a,w(),{done:!0}),k=n=>(w(n),{done:!0});if(u={[Symbol.asyncIterator](){return this},next:v,return:L,throw:k,push:E,end:w,get readableLength(){return t.size},onEmpty:async n=>{let s=n?.signal;if(s?.throwIfAborted(),t.isEmpty())return;let d,h;s!=null&&(d=new Promise((q,N)=>{h=()=>{N(new b)},s.addEventListener("abort",h)}));try{await Promise.race([m.promise,d])}finally{h!=null&&s!=null&&s?.removeEventListener("abort",h)}}},r==null)return u;let o=u;return u={[Symbol.asyncIterator](){return this},next(){return o.next()},throw(n){return o.throw(n),r!=null&&(r(n),r=void 0),{done:!0}},return(){return o.return(),r!=null&&(r(),r=void 0),{done:!0}},push:E,end(n){return o.end(n),r!=null&&(r(n),r=void 0),u},get readableLength(){return o.readableLength},onEmpty:n=>o.onEmpty(n)},u}return I(T);})();
return ItPushable}));
+23
View File
@@ -0,0 +1,23 @@
export interface Next<T> {
done?: boolean;
error?: Error;
value?: T;
}
export interface FIFOOptions {
/**
* When the queue reaches this size, it will be split into head/tail parts
*/
splitLimit?: number;
}
export declare class FIFO<T> {
size: number;
private readonly hwm;
private head;
private tail;
constructor(options?: FIFOOptions);
calculateSize(obj: any): number;
push(val: Next<T>): void;
shift(): Next<T> | undefined;
isEmpty(): boolean;
}
//# sourceMappingURL=fifo.d.ts.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"fifo.d.ts","sourceRoot":"","sources":["../../src/fifo.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,IAAI,CAAC,CAAC;IACrB,IAAI,CAAC,EAAE,OAAO,CAAA;IACd,KAAK,CAAC,EAAE,KAAK,CAAA;IACb,KAAK,CAAC,EAAE,CAAC,CAAA;CACV;AAiDD,MAAM,WAAW,WAAW;IAC1B;;OAEG;IACH,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB;AAED,qBAAa,IAAI,CAAC,CAAC;IACV,IAAI,EAAE,MAAM,CAAA;IACnB,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAQ;IAC5B,OAAO,CAAC,IAAI,CAAc;IAC1B,OAAO,CAAC,IAAI,CAAc;gBAEb,OAAO,GAAE,WAAgB;IAOtC,aAAa,CAAE,GAAG,EAAE,GAAG,GAAG,MAAM;IAQhC,IAAI,CAAE,GAAG,EAAE,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI;IAYzB,KAAK,IAAK,IAAI,CAAC,CAAC,CAAC,GAAG,SAAS;IAiB7B,OAAO,IAAK,OAAO;CAGpB"}
+83
View File
@@ -0,0 +1,83 @@
// ported from https://www.npmjs.com/package/fast-fifo
class FixedFIFO {
buffer;
mask;
top;
btm;
next;
constructor(hwm) {
if (!(hwm > 0) || ((hwm - 1) & hwm) !== 0) {
throw new Error('Max size for a FixedFIFO should be a power of two');
}
this.buffer = new Array(hwm);
this.mask = hwm - 1;
this.top = 0;
this.btm = 0;
this.next = null;
}
push(data) {
if (this.buffer[this.top] !== undefined) {
return false;
}
this.buffer[this.top] = data;
this.top = (this.top + 1) & this.mask;
return true;
}
shift() {
const last = this.buffer[this.btm];
if (last === undefined) {
return undefined;
}
this.buffer[this.btm] = undefined;
this.btm = (this.btm + 1) & this.mask;
return last;
}
isEmpty() {
return this.buffer[this.btm] === undefined;
}
}
export class FIFO {
size;
hwm;
head;
tail;
constructor(options = {}) {
this.hwm = options.splitLimit ?? 16;
this.head = new FixedFIFO(this.hwm);
this.tail = this.head;
this.size = 0;
}
calculateSize(obj) {
if (obj?.byteLength != null) {
return obj.byteLength;
}
return 1;
}
push(val) {
if (val?.value != null) {
this.size += this.calculateSize(val.value);
}
if (!this.head.push(val)) {
const prev = this.head;
this.head = prev.next = new FixedFIFO(2 * this.head.buffer.length);
this.head.push(val);
}
}
shift() {
let val = this.tail.shift();
if (val === undefined && (this.tail.next != null)) {
const next = this.tail.next;
this.tail.next = null;
this.tail = next;
val = this.tail.shift();
}
if (val?.value != null) {
this.size -= this.calculateSize(val.value);
}
return val;
}
isEmpty() {
return this.head.isEmpty();
}
}
//# sourceMappingURL=fifo.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"fifo.js","sourceRoot":"","sources":["../../src/fifo.ts"],"names":[],"mappings":"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"}
+135
View File
@@ -0,0 +1,135 @@
/**
* @packageDocumentation
*
* An iterable that you can push values into.
*
* @example
*
* ```js
* import { pushable } from 'it-pushable'
*
* const source = pushable()
*
* setTimeout(() => source.push('hello'), 100)
* setTimeout(() => source.push('world'), 200)
* setTimeout(() => source.end(), 300)
*
* const start = Date.now()
*
* for await (const value of source) {
* console.log(`got "${value}" after ${Date.now() - start}ms`)
* }
* console.log(`done after ${Date.now() - start}ms`)
*
* // Output:
* // got "hello" after 105ms
* // got "world" after 207ms
* // done after 309ms
* ```
*
* @example
*
* ```js
* import { pushableV } from 'it-pushable'
* import all from 'it-all'
*
* const source = pushableV()
*
* source.push(1)
* source.push(2)
* source.push(3)
* source.end()
*
* console.info(await all(source))
*
* // Output:
* // [ [1, 2, 3] ]
* ```
*/
export declare class AbortError extends Error {
type: string;
code: string;
constructor(message?: string, code?: string);
}
export interface AbortOptions {
signal?: AbortSignal;
}
interface BasePushable<T> {
/**
* End the iterable after all values in the buffer (if any) have been yielded. If an
* error is passed the buffer is cleared immediately and the next iteration will
* throw the passed error
*/
end(err?: Error): this;
/**
* Push a value into the iterable. Values are yielded from the iterable in the order
* they are pushed. Values not yet consumed from the iterable are buffered.
*/
push(value: T): this;
/**
* Returns a promise that resolves when the underlying queue becomes empty (e.g.
* this.readableLength === 0).
*
* If an AbortSignal is passed as an option and that signal aborts, it only
* causes the returned promise to reject - it does not end the pushable.
*/
onEmpty(options?: AbortOptions): Promise<void>;
/**
* This property contains the number of bytes (or objects) in the queue ready to be read.
*
* If `objectMode` is true, this is the number of objects in the queue, if false it's the
* total number of bytes in the queue.
*/
readableLength: number;
}
/**
* An iterable that you can push values into.
*/
export interface Pushable<T, R = void, N = unknown> extends AsyncGenerator<T, R, N>, BasePushable<T> {
}
/**
* Similar to `pushable`, except it yields multiple buffered chunks at a time. All values yielded from the iterable will be arrays.
*/
export interface PushableV<T, R = void, N = unknown> extends AsyncGenerator<T[], R, N>, BasePushable<T> {
}
export interface Options {
/**
* A boolean value that means non-`Uint8Array`s will be passed to `.push`, default: `false`
*/
objectMode?: boolean;
/**
* A function called after *all* values have been yielded from the iterator (including
* buffered values). In the case when the iterator is ended with an error it will be
* passed the error as a parameter.
*/
onEnd?(err?: Error): void;
}
export interface DoneResult {
done: true;
}
export interface ValueResult<T> {
done: false;
value: T;
}
export type NextResult<T> = ValueResult<T> | DoneResult;
export interface ObjectPushableOptions extends Options {
objectMode: true;
}
export interface BytePushableOptions extends Options {
objectMode?: false;
}
/**
* Create a new async iterable. The values yielded from calls to `.next()`
* or when used in a `for await of`loop are "pushed" into the iterable.
* Returns an async iterable object with additional methods.
*/
export declare function pushable<T extends {
byteLength: number;
} = Uint8Array>(options?: BytePushableOptions): Pushable<T>;
export declare function pushable<T>(options: ObjectPushableOptions): Pushable<T>;
export declare function pushableV<T extends {
byteLength: number;
} = Uint8Array>(options?: BytePushableOptions): PushableV<T>;
export declare function pushableV<T>(options: ObjectPushableOptions): PushableV<T>;
export {};
//# sourceMappingURL=index.d.ts.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+CG;AAKH,qBAAa,UAAW,SAAQ,KAAK;IACnC,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;gBAEC,OAAO,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM;CAK7C;AAED,MAAM,WAAW,YAAY;IAC3B,MAAM,CAAC,EAAE,WAAW,CAAA;CACrB;AAED,UAAU,YAAY,CAAC,CAAC;IACtB;;;;OAIG;IACH,GAAG,CAAC,GAAG,CAAC,EAAE,KAAK,GAAG,IAAI,CAAA;IAEtB;;;OAGG;IACH,IAAI,CAAC,KAAK,EAAE,CAAC,GAAG,IAAI,CAAA;IAEpB;;;;;;OAMG;IACH,OAAO,CAAC,OAAO,CAAC,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAE9C;;;;;OAKG;IACH,cAAc,EAAE,MAAM,CAAA;CACvB;AAED;;GAEG;AACH,MAAM,WAAW,QAAQ,CAAC,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,CAAC,GAAG,OAAO,CAAE,SAAQ,cAAc,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,YAAY,CAAC,CAAC,CAAC;CAAG;AAEvG;;GAEG;AACH,MAAM,WAAW,SAAS,CAAC,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,CAAC,GAAG,OAAO,CAAE,SAAQ,cAAc,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,YAAY,CAAC,CAAC,CAAC;CAAG;AAE1G,MAAM,WAAW,OAAO;IACtB;;OAEG;IACH,UAAU,CAAC,EAAE,OAAO,CAAA;IAEpB;;;;OAIG;IACH,KAAK,CAAC,CAAC,GAAG,CAAC,EAAE,KAAK,GAAG,IAAI,CAAA;CAC1B;AAED,MAAM,WAAW,UAAU;IAAG,IAAI,EAAE,IAAI,CAAA;CAAE;AAC1C,MAAM,WAAW,WAAW,CAAC,CAAC;IAAI,IAAI,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,CAAC,CAAA;CAAE;AACzD,MAAM,MAAM,UAAU,CAAC,CAAC,IAAI,WAAW,CAAC,CAAC,CAAC,GAAG,UAAU,CAAA;AAIvD,MAAM,WAAW,qBAAsB,SAAQ,OAAO;IACpD,UAAU,EAAE,IAAI,CAAA;CACjB;AAED,MAAM,WAAW,mBAAoB,SAAQ,OAAO;IAClD,UAAU,CAAC,EAAE,KAAK,CAAA;CACnB;AAED;;;;GAIG;AACH,wBAAgB,QAAQ,CAAC,CAAC,SAAS;IAAE,UAAU,EAAE,MAAM,CAAA;CAAE,GAAG,UAAU,EAAG,OAAO,CAAC,EAAE,mBAAmB,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAA;AACpH,wBAAgB,QAAQ,CAAC,CAAC,EAAG,OAAO,EAAE,qBAAqB,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAA;AAuBzE,wBAAgB,SAAS,CAAC,CAAC,SAAS;IAAE,UAAU,EAAE,MAAM,CAAA;CAAE,GAAG,UAAU,EAAG,OAAO,CAAC,EAAE,mBAAmB,GAAG,SAAS,CAAC,CAAC,CAAC,CAAA;AACtH,wBAAgB,SAAS,CAAC,CAAC,EAAG,OAAO,EAAE,qBAAqB,GAAG,SAAS,CAAC,CAAC,CAAC,CAAA"}
+267
View File
@@ -0,0 +1,267 @@
/**
* @packageDocumentation
*
* An iterable that you can push values into.
*
* @example
*
* ```js
* import { pushable } from 'it-pushable'
*
* const source = pushable()
*
* setTimeout(() => source.push('hello'), 100)
* setTimeout(() => source.push('world'), 200)
* setTimeout(() => source.end(), 300)
*
* const start = Date.now()
*
* for await (const value of source) {
* console.log(`got "${value}" after ${Date.now() - start}ms`)
* }
* console.log(`done after ${Date.now() - start}ms`)
*
* // Output:
* // got "hello" after 105ms
* // got "world" after 207ms
* // done after 309ms
* ```
*
* @example
*
* ```js
* import { pushableV } from 'it-pushable'
* import all from 'it-all'
*
* const source = pushableV()
*
* source.push(1)
* source.push(2)
* source.push(3)
* source.end()
*
* console.info(await all(source))
*
* // Output:
* // [ [1, 2, 3] ]
* ```
*/
import deferred from 'p-defer';
import { FIFO } from './fifo.js';
export class AbortError extends Error {
type;
code;
constructor(message, code) {
super(message ?? 'The operation was aborted');
this.type = 'aborted';
this.code = code ?? 'ABORT_ERR';
}
}
export function pushable(options = {}) {
const getNext = (buffer) => {
const next = buffer.shift();
if (next == null) {
return { done: true };
}
if (next.error != null) {
throw next.error;
}
return {
done: next.done === true,
// @ts-expect-error if done is false, value will be present
value: next.value
};
};
return _pushable(getNext, options);
}
export function pushableV(options = {}) {
const getNext = (buffer) => {
let next;
const values = [];
while (!buffer.isEmpty()) {
next = buffer.shift();
if (next == null) {
break;
}
if (next.error != null) {
throw next.error;
}
if (next.done === false) {
// @ts-expect-error if done is false value should be pushed
values.push(next.value);
}
}
if (next == null) {
return { done: true };
}
return {
done: next.done === true,
value: values
};
};
return _pushable(getNext, options);
}
function _pushable(getNext, options) {
options = options ?? {};
let onEnd = options.onEnd;
let buffer = new FIFO();
let pushable;
let onNext;
let ended;
let drain = deferred();
const waitNext = async () => {
try {
if (!buffer.isEmpty()) {
return getNext(buffer);
}
if (ended) {
return { done: true };
}
return await new Promise((resolve, reject) => {
onNext = (next) => {
onNext = null;
buffer.push(next);
try {
resolve(getNext(buffer));
}
catch (err) {
reject(err);
}
return pushable;
};
});
}
finally {
if (buffer.isEmpty()) {
// settle promise in the microtask queue to give consumers a chance to
// await after calling .push
queueMicrotask(() => {
drain.resolve();
drain = deferred();
});
}
}
};
const bufferNext = (next) => {
if (onNext != null) {
return onNext(next);
}
buffer.push(next);
return pushable;
};
const bufferError = (err) => {
buffer = new FIFO();
if (onNext != null) {
return onNext({ error: err });
}
buffer.push({ error: err });
return pushable;
};
const push = (value) => {
if (ended) {
return pushable;
}
// @ts-expect-error `byteLength` is not declared on PushType
if (options?.objectMode !== true && value?.byteLength == null) {
throw new Error('objectMode was not true but tried to push non-Uint8Array value');
}
return bufferNext({ done: false, value });
};
const end = (err) => {
if (ended)
return pushable;
ended = true;
return (err != null) ? bufferError(err) : bufferNext({ done: true });
};
const _return = () => {
buffer = new FIFO();
end();
return { done: true };
};
const _throw = (err) => {
end(err);
return { done: true };
};
pushable = {
[Symbol.asyncIterator]() { return this; },
next: waitNext,
return: _return,
throw: _throw,
push,
end,
get readableLength() {
return buffer.size;
},
onEmpty: async (options) => {
const signal = options?.signal;
signal?.throwIfAborted();
if (buffer.isEmpty()) {
return;
}
let cancel;
let listener;
if (signal != null) {
cancel = new Promise((resolve, reject) => {
listener = () => {
reject(new AbortError());
};
signal.addEventListener('abort', listener);
});
}
try {
await Promise.race([
drain.promise,
cancel
]);
}
finally {
if (listener != null && signal != null) {
signal?.removeEventListener('abort', listener);
}
}
}
};
if (onEnd == null) {
return pushable;
}
const _pushable = pushable;
pushable = {
[Symbol.asyncIterator]() { return this; },
next() {
return _pushable.next();
},
throw(err) {
_pushable.throw(err);
if (onEnd != null) {
onEnd(err);
onEnd = undefined;
}
return { done: true };
},
return() {
_pushable.return();
if (onEnd != null) {
onEnd();
onEnd = undefined;
}
return { done: true };
},
push,
end(err) {
_pushable.end(err);
if (onEnd != null) {
onEnd(err);
onEnd = undefined;
}
return pushable;
},
get readableLength() {
return _pushable.readableLength;
},
onEmpty: (opts) => {
return _pushable.onEmpty(opts);
}
};
return pushable;
}
//# sourceMappingURL=index.js.map
File diff suppressed because one or more lines are too long
+26
View File
@@ -0,0 +1,26 @@
{
"AbortError": "https://alanshaw.github.io/it-pushable/classes/AbortError.html",
".:AbortError": "https://alanshaw.github.io/it-pushable/classes/AbortError.html",
"AbortOptions": "https://alanshaw.github.io/it-pushable/interfaces/AbortOptions.html",
".:AbortOptions": "https://alanshaw.github.io/it-pushable/interfaces/AbortOptions.html",
"BytePushableOptions": "https://alanshaw.github.io/it-pushable/interfaces/BytePushableOptions.html",
".:BytePushableOptions": "https://alanshaw.github.io/it-pushable/interfaces/BytePushableOptions.html",
"DoneResult": "https://alanshaw.github.io/it-pushable/interfaces/DoneResult.html",
".:DoneResult": "https://alanshaw.github.io/it-pushable/interfaces/DoneResult.html",
"ObjectPushableOptions": "https://alanshaw.github.io/it-pushable/interfaces/ObjectPushableOptions.html",
".:ObjectPushableOptions": "https://alanshaw.github.io/it-pushable/interfaces/ObjectPushableOptions.html",
"Options": "https://alanshaw.github.io/it-pushable/interfaces/Options.html",
".:Options": "https://alanshaw.github.io/it-pushable/interfaces/Options.html",
"Pushable": "https://alanshaw.github.io/it-pushable/interfaces/Pushable.html",
".:Pushable": "https://alanshaw.github.io/it-pushable/interfaces/Pushable.html",
"PushableV": "https://alanshaw.github.io/it-pushable/interfaces/PushableV.html",
".:PushableV": "https://alanshaw.github.io/it-pushable/interfaces/PushableV.html",
"ValueResult": "https://alanshaw.github.io/it-pushable/interfaces/ValueResult.html",
".:ValueResult": "https://alanshaw.github.io/it-pushable/interfaces/ValueResult.html",
"NextResult": "https://alanshaw.github.io/it-pushable/types/NextResult.html",
".:NextResult": "https://alanshaw.github.io/it-pushable/types/NextResult.html",
"pushable": "https://alanshaw.github.io/it-pushable/functions/pushable-1.html",
".:pushable": "https://alanshaw.github.io/it-pushable/functions/pushable-1.html",
"pushableV": "https://alanshaw.github.io/it-pushable/functions/pushableV-1.html",
".:pushableV": "https://alanshaw.github.io/it-pushable/functions/pushableV-1.html"
}
+152
View File
@@ -0,0 +1,152 @@
{
"name": "it-pushable",
"version": "3.2.3",
"description": "An iterable that you can push values into",
"author": "Alan Shaw",
"license": "Apache-2.0 OR MIT",
"homepage": "https://github.com/alanshaw/it-pushable#readme",
"repository": {
"type": "git",
"url": "git+https://github.com/alanshaw/it-pushable.git"
},
"bugs": {
"url": "https://github.com/alanshaw/it-pushable/issues"
},
"keywords": [
"iterable",
"iterator",
"push",
"pushable"
],
"type": "module",
"types": "./dist/src/index.d.ts",
"files": [
"src",
"dist",
"!dist/test",
"!**/*.tsbuildinfo"
],
"exports": {
".": {
"types": "./dist/src/index.d.ts",
"import": "./dist/src/index.js"
}
},
"eslintConfig": {
"extends": "ipfs",
"parserOptions": {
"project": true,
"sourceType": "module"
}
},
"release": {
"branches": [
"master"
],
"plugins": [
[
"@semantic-release/commit-analyzer",
{
"preset": "conventionalcommits",
"releaseRules": [
{
"breaking": true,
"release": "major"
},
{
"revert": true,
"release": "patch"
},
{
"type": "feat",
"release": "minor"
},
{
"type": "fix",
"release": "patch"
},
{
"type": "docs",
"release": "patch"
},
{
"type": "test",
"release": "patch"
},
{
"type": "deps",
"release": "patch"
},
{
"scope": "no-release",
"release": false
}
]
}
],
[
"@semantic-release/release-notes-generator",
{
"preset": "conventionalcommits",
"presetConfig": {
"types": [
{
"type": "feat",
"section": "Features"
},
{
"type": "fix",
"section": "Bug Fixes"
},
{
"type": "chore",
"section": "Trivial Changes"
},
{
"type": "docs",
"section": "Documentation"
},
{
"type": "deps",
"section": "Dependencies"
},
{
"type": "test",
"section": "Tests"
}
]
}
}
],
"@semantic-release/changelog",
"@semantic-release/npm",
"@semantic-release/github",
"@semantic-release/git"
]
},
"scripts": {
"clean": "aegir clean",
"lint": "aegir lint",
"dep-check": "aegir dep-check",
"build": "aegir build",
"test": "aegir test -f ./dist/test",
"test:chrome": "aegir test -t browser --cov",
"test:chrome-webworker": "aegir test -t webworker",
"test:firefox": "aegir test -t browser -- --browser firefox",
"test:firefox-webworker": "aegir test -t webworker -- --browser firefox",
"test:node": "aegir test -t node --cov",
"test:electron-main": "aegir test -t electron-main",
"release": "aegir release",
"docs": "aegir docs"
},
"dependencies": {
"p-defer": "^4.0.0"
},
"devDependencies": {
"@types/fast-fifo": "^1.0.0",
"aegir": "^41.0.5",
"it-all": "^3.0.1",
"it-pipe": "^3.0.1",
"uint8arraylist": "^2.0.0"
}
}
+116
View File
@@ -0,0 +1,116 @@
// ported from https://www.npmjs.com/package/fast-fifo
export interface Next<T> {
done?: boolean
error?: Error
value?: T
}
class FixedFIFO<T> {
public buffer: Array<Next<T> | undefined>
private readonly mask: number
private top: number
private btm: number
public next: FixedFIFO<T> | null
constructor (hwm: number) {
if (!(hwm > 0) || ((hwm - 1) & hwm) !== 0) {
throw new Error('Max size for a FixedFIFO should be a power of two')
}
this.buffer = new Array(hwm)
this.mask = hwm - 1
this.top = 0
this.btm = 0
this.next = null
}
push (data: Next<T>): boolean {
if (this.buffer[this.top] !== undefined) {
return false
}
this.buffer[this.top] = data
this.top = (this.top + 1) & this.mask
return true
}
shift (): Next<T> | undefined {
const last = this.buffer[this.btm]
if (last === undefined) {
return undefined
}
this.buffer[this.btm] = undefined
this.btm = (this.btm + 1) & this.mask
return last
}
isEmpty (): boolean {
return this.buffer[this.btm] === undefined
}
}
export interface FIFOOptions {
/**
* When the queue reaches this size, it will be split into head/tail parts
*/
splitLimit?: number
}
export class FIFO<T> {
public size: number
private readonly hwm: number
private head: FixedFIFO<T>
private tail: FixedFIFO<T>
constructor (options: FIFOOptions = {}) {
this.hwm = options.splitLimit ?? 16
this.head = new FixedFIFO<T>(this.hwm)
this.tail = this.head
this.size = 0
}
calculateSize (obj: any): number {
if (obj?.byteLength != null) {
return obj.byteLength
}
return 1
}
push (val: Next<T>): void {
if (val?.value != null) {
this.size += this.calculateSize(val.value)
}
if (!this.head.push(val)) {
const prev = this.head
this.head = prev.next = new FixedFIFO<T>(2 * this.head.buffer.length)
this.head.push(val)
}
}
shift (): Next<T> | undefined {
let val = this.tail.shift()
if (val === undefined && (this.tail.next != null)) {
const next = this.tail.next
this.tail.next = null
this.tail = next
val = this.tail.shift()
}
if (val?.value != null) {
this.size -= this.calculateSize(val.value)
}
return val
}
isEmpty (): boolean {
return this.head.isEmpty()
}
}
+394
View File
@@ -0,0 +1,394 @@
/**
* @packageDocumentation
*
* An iterable that you can push values into.
*
* @example
*
* ```js
* import { pushable } from 'it-pushable'
*
* const source = pushable()
*
* setTimeout(() => source.push('hello'), 100)
* setTimeout(() => source.push('world'), 200)
* setTimeout(() => source.end(), 300)
*
* const start = Date.now()
*
* for await (const value of source) {
* console.log(`got "${value}" after ${Date.now() - start}ms`)
* }
* console.log(`done after ${Date.now() - start}ms`)
*
* // Output:
* // got "hello" after 105ms
* // got "world" after 207ms
* // done after 309ms
* ```
*
* @example
*
* ```js
* import { pushableV } from 'it-pushable'
* import all from 'it-all'
*
* const source = pushableV()
*
* source.push(1)
* source.push(2)
* source.push(3)
* source.end()
*
* console.info(await all(source))
*
* // Output:
* // [ [1, 2, 3] ]
* ```
*/
import deferred from 'p-defer'
import { FIFO, type Next } from './fifo.js'
export class AbortError extends Error {
type: string
code: string
constructor (message?: string, code?: string) {
super(message ?? 'The operation was aborted')
this.type = 'aborted'
this.code = code ?? 'ABORT_ERR'
}
}
export interface AbortOptions {
signal?: AbortSignal
}
interface BasePushable<T> {
/**
* End the iterable after all values in the buffer (if any) have been yielded. If an
* error is passed the buffer is cleared immediately and the next iteration will
* throw the passed error
*/
end(err?: Error): this
/**
* Push a value into the iterable. Values are yielded from the iterable in the order
* they are pushed. Values not yet consumed from the iterable are buffered.
*/
push(value: T): this
/**
* Returns a promise that resolves when the underlying queue becomes empty (e.g.
* this.readableLength === 0).
*
* If an AbortSignal is passed as an option and that signal aborts, it only
* causes the returned promise to reject - it does not end the pushable.
*/
onEmpty(options?: AbortOptions): Promise<void>
/**
* This property contains the number of bytes (or objects) in the queue ready to be read.
*
* If `objectMode` is true, this is the number of objects in the queue, if false it's the
* total number of bytes in the queue.
*/
readableLength: number
}
/**
* An iterable that you can push values into.
*/
export interface Pushable<T, R = void, N = unknown> extends AsyncGenerator<T, R, N>, BasePushable<T> {}
/**
* Similar to `pushable`, except it yields multiple buffered chunks at a time. All values yielded from the iterable will be arrays.
*/
export interface PushableV<T, R = void, N = unknown> extends AsyncGenerator<T[], R, N>, BasePushable<T> {}
export interface Options {
/**
* A boolean value that means non-`Uint8Array`s will be passed to `.push`, default: `false`
*/
objectMode?: boolean
/**
* A function called after *all* values have been yielded from the iterator (including
* buffered values). In the case when the iterator is ended with an error it will be
* passed the error as a parameter.
*/
onEnd?(err?: Error): void
}
export interface DoneResult { done: true }
export interface ValueResult<T> { done: false, value: T }
export type NextResult<T> = ValueResult<T> | DoneResult
interface getNext<T, V = T> { (buffer: FIFO<T>): NextResult<V> }
export interface ObjectPushableOptions extends Options {
objectMode: true
}
export interface BytePushableOptions extends Options {
objectMode?: false
}
/**
* Create a new async iterable. The values yielded from calls to `.next()`
* or when used in a `for await of`loop are "pushed" into the iterable.
* Returns an async iterable object with additional methods.
*/
export function pushable<T extends { byteLength: number } = Uint8Array> (options?: BytePushableOptions): Pushable<T>
export function pushable<T> (options: ObjectPushableOptions): Pushable<T>
export function pushable<T> (options: Options = {}): Pushable<T> {
const getNext = (buffer: FIFO<T>): NextResult<T> => {
const next: Next<T> | undefined = buffer.shift()
if (next == null) {
return { done: true }
}
if (next.error != null) {
throw next.error
}
return {
done: next.done === true,
// @ts-expect-error if done is false, value will be present
value: next.value
}
}
return _pushable<T, T, Pushable<T>>(getNext, options)
}
export function pushableV<T extends { byteLength: number } = Uint8Array> (options?: BytePushableOptions): PushableV<T>
export function pushableV<T> (options: ObjectPushableOptions): PushableV<T>
export function pushableV<T> (options: Options = {}): PushableV<T> {
const getNext = (buffer: FIFO<T>): NextResult<T[]> => {
let next: Next<T> | undefined
const values: T[] = []
while (!buffer.isEmpty()) {
next = buffer.shift()
if (next == null) {
break
}
if (next.error != null) {
throw next.error
}
if (next.done === false) {
// @ts-expect-error if done is false value should be pushed
values.push(next.value)
}
}
if (next == null) {
return { done: true }
}
return {
done: next.done === true,
value: values
}
}
return _pushable<T, T[], PushableV<T>>(getNext, options)
}
function _pushable<PushType, ValueType, ReturnType> (getNext: getNext<PushType, ValueType>, options?: Options): ReturnType {
options = options ?? {}
let onEnd = options.onEnd
let buffer = new FIFO<PushType>()
let pushable: any
let onNext: ((next: Next<PushType>) => ReturnType) | null
let ended: boolean
let drain = deferred()
const waitNext = async (): Promise<NextResult<ValueType>> => {
try {
if (!buffer.isEmpty()) {
return getNext(buffer)
}
if (ended) {
return { done: true }
}
return await new Promise<NextResult<ValueType>>((resolve, reject) => {
onNext = (next: Next<PushType>) => {
onNext = null
buffer.push(next)
try {
resolve(getNext(buffer))
} catch (err) {
reject(err)
}
return pushable
}
})
} finally {
if (buffer.isEmpty()) {
// settle promise in the microtask queue to give consumers a chance to
// await after calling .push
queueMicrotask(() => {
drain.resolve()
drain = deferred()
})
}
}
}
const bufferNext = (next: Next<PushType>): ReturnType => {
if (onNext != null) {
return onNext(next)
}
buffer.push(next)
return pushable
}
const bufferError = (err: Error): ReturnType => {
buffer = new FIFO()
if (onNext != null) {
return onNext({ error: err })
}
buffer.push({ error: err })
return pushable
}
const push = (value: PushType): ReturnType => {
if (ended) {
return pushable
}
// @ts-expect-error `byteLength` is not declared on PushType
if (options?.objectMode !== true && value?.byteLength == null) {
throw new Error('objectMode was not true but tried to push non-Uint8Array value')
}
return bufferNext({ done: false, value })
}
const end = (err?: Error): ReturnType => {
if (ended) return pushable
ended = true
return (err != null) ? bufferError(err) : bufferNext({ done: true })
}
const _return = (): DoneResult => {
buffer = new FIFO()
end()
return { done: true }
}
const _throw = (err: Error): DoneResult => {
end(err)
return { done: true }
}
pushable = {
[Symbol.asyncIterator] () { return this },
next: waitNext,
return: _return,
throw: _throw,
push,
end,
get readableLength (): number {
return buffer.size
},
onEmpty: async (options?: AbortOptions) => {
const signal = options?.signal
signal?.throwIfAborted()
if (buffer.isEmpty()) {
return
}
let cancel: Promise<void> | undefined
let listener: (() => void) | undefined
if (signal != null) {
cancel = new Promise((resolve, reject) => {
listener = () => {
reject(new AbortError())
}
signal.addEventListener('abort', listener)
})
}
try {
await Promise.race([
drain.promise,
cancel
])
} finally {
if (listener != null && signal != null) {
signal?.removeEventListener('abort', listener)
}
}
}
}
if (onEnd == null) {
return pushable
}
const _pushable = pushable
pushable = {
[Symbol.asyncIterator] () { return this },
next () {
return _pushable.next()
},
throw (err: Error) {
_pushable.throw(err)
if (onEnd != null) {
onEnd(err)
onEnd = undefined
}
return { done: true }
},
return () {
_pushable.return()
if (onEnd != null) {
onEnd()
onEnd = undefined
}
return { done: true }
},
push,
end (err: Error) {
_pushable.end(err)
if (onEnd != null) {
onEnd(err)
onEnd = undefined
}
return pushable
},
get readableLength () {
return _pushable.readableLength
},
onEmpty: (opts?: AbortOptions) => {
return _pushable.onEmpty(opts)
}
}
return pushable
}