New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

awai

Package Overview
Dependencies
Maintainers
1
Versions
38
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

awai - npm Package Compare versions

Comparing version 0.0.1-alpha-1 to 0.0.1-alpha-2

64

dist/index.d.ts

@@ -0,1 +1,33 @@

type Resolver<T> = (payload: T) => any;
type FilterPredicate<T> = (value: T) => boolean;
declare class AwaitableEvent<T> {
private _awaiters;
then(resolve: Resolver<T>): Promise<T>;
emit(value: T): void;
filter(predicate: FilterPredicate<T>): Promise<unknown>;
}
declare const delay: (ms: number) => Promise<void>;
declare const fork: (forkFn: () => Promise<any>) => Promise<void>;
declare const rejectAfter: (ms: number) => Promise<void>;
type Callback<A extends any[], R extends any> = (...args: A) => R;
type BaseEvents<Args> = {
invoked: AwaitableEvent<Args>;
failed: AwaitableEvent<any>;
};
type AsyncEvents<Args, Return> = BaseEvents<Args> & {
completed: AwaitableEvent<Return>;
};
declare function action<Args extends any[]>(): Function & {
events: BaseEvents<Args>;
};
declare function action<Args extends any[], Return extends any>(T: Callback<Args, Return>): Callback<Args, Return> & {
events: AsyncEvents<Args, Return>;
};
type AsyncSetter<T> = (nextValueOrResolver: T | Promise<T> | ((current?: T | undefined) => T | Promise<T>)) => void;

@@ -19,4 +51,2 @@

type Resolver<T> = (payload: T) => any;
interface ReadableAsyncState<T> {

@@ -74,32 +104,2 @@ events: {

type FilterPredicate<T> = (value: T) => boolean;
declare class AwaitableEvent<T> {
private _awaiters;
then(resolve: Resolver<T>): Promise<T>;
emit(value: T): void;
filter(predicate: FilterPredicate<T>): Promise<unknown>;
}
declare const delay: (ms: number) => Promise<void>;
declare const fork: (forkFn: () => Promise<any>) => Promise<void>;
declare const rejectAfter: (ms: number) => Promise<void>;
type Callback<A extends any[], R extends any> = (...args: A) => R;
type BaseEvents<Args> = {
invoked: AwaitableEvent<Args>;
failed: AwaitableEvent<any>;
};
type AsyncEvents<Args, Return> = BaseEvents<Args> & {
completed: AwaitableEvent<Return>;
};
declare function action<Args extends any[]>(): Function & {
events: BaseEvents<Args>;
};
declare function action<Args extends any[], Return extends any>(T: Callback<Args, Return>): Callback<Args, Return> & {
events: AsyncEvents<Args, Return>;
};
type InitialValue<T> = T | Promise<T> | (() => Promise<T>);

@@ -106,0 +106,0 @@ type AsyncState<T> = ReadableAsyncState<T> & WritableAsyncState<T>;

{
"name": "awai",
"version": "0.0.1-alpha-1",
"version": "0.0.1-alpha-2",
"author": "Yuriy Yakym",

@@ -11,3 +11,5 @@ "description": "State management library",

"type": "module",
"files": ["dist"],
"files": [
"dist"
],
"scripts": {

@@ -14,0 +16,0 @@ "build": "rm -rf dist && rollup -c rollup.config.js",

@@ -1,126 +0,14 @@

# [DIRTY DRAFT] JavaScript state management library
<div align="center">
<h1>Awai</h1>
<p>Minimalistic, dependency-free state management library</p>
Minimalistic, dependency-free, written in TypeScript.
Besides state management utils, this repository suggests unique architectural approach.
The architecture consists of three main parts: state, action and scenario.
The library was written using a concept of a promise-like object which has no terminal state and may resolve multiple times. Let's call it re-resolvable.
<div>
<img src="https://github.com/yuriyyakym/awai/actions/workflows/tests.yml/badge.svg" />
<img src="https://img.shields.io/badge/stability-experimental-blue.svg" />
</div>
Such re-resolvable can be used instead of event emitters, and when you try to do so, you are naturally forced into a different way of algorithmic thinking.
Let's create a simple state node, and dive deeper.
```ts
const counter = state(0);
```
`counter` is an object with following properties: `get`, `set`, `events`.
While `get` and `set` methods are self-explanatory, `events` property is quite unusual - every event is re-resolvable.
As of now, there is only `changed` event on state node.
A piece of code may be better than thousand of words:
```ts
const counter = state(0);
setTimeout(counter.set, 100, 'hello');
setTimeout(counter.set, 200, 'there');
const value1 = await counter.events.changed;
const value2 = await counter.events.changed;
console.log(`${value1} ${value2}`); // hello there
```
It's quite remarkable that `counter.events.changed` has always the same reference. Notice how it was resolved with two different values in the above snippet.
---
It's time to create some actions.
```ts
const increment = action(() => counter.set(current => current + 1));
const decrement = action(() => counter.set(current => current - 1));
```
Action is just a function which, similarly to state objects, has its re-resolvable `events`, for example:
```ts
setTimeout(increment, 100);
await increment.events.invoked;
console.log(`incremented after 100ms`);
```
More utils with re-resolvable events to come in future.
All this brings us to the `scenario` concept - an async function, which describes small piece of logics.
Let's say we've got a new requirement to preserve counter in `sessionStorage` (write-only for now).
```ts
scenario(async () => {
const value = await counter.events.changed;
sessionStorage.setItem('counter', value);
});
```
Scenario is a sequence of awaited events. Since those events are promise-like, they may be combined with other promises using Promise methods like `any`, `race`, `all`, etc.
Side note: beware of stale values when using `Promise.all`. Let's say you want a scenario to happen only after both user and license state nodes are updated.
```ts
// Wrong - user or license may be outdated
const [user, license] = await Promise.all([
userState.events.changed,
licenseState.events.changed,
]);
// Good - both user and license are up to date
await Promise.all([userState.events.changed, licenseState.events.changed]);
const user = userState.get();
const license = licenseState.get();
```
This library provides variety of syntax sugar helpers for scenarios. Like: `scenarioOnEvery`, `scenarioOnce`. More to be described later.
This is how you can implement state preserving using `scenarioOnEvery`:
```ts
scenarioOnEvery(counter.events.changed, async () => {
// There are two ways of retrieving state value: `state.get()` and `await state`
sessionStorage.setItem('counter', await counter);
});
```
---
Actions may be empty. When that's the case, they do nothing but emit `invoked` event when called, and this may be used to control a scenario flow. This is how we can implement `increment` and `decrement` functionalities:
```ts
const increment = action();
const decrement = action();
scenarioOnEvery(increment.events.invoked, () => {
counter.set(current => current + 1);
});
scenarioOnEvery(decrement.events.invoked, () => {
counter.set(current => current - 1);
});
```
---
More advanced example how to implement a debounced scenario:
```ts
const TIMEOUT_SYMBOL = Symbol();
scenarioOnEvery(increment.events.invoked, async () => {
const result = await Promise.race([
increment.events.invoked
delay(DEBOUNCE_TIMEOUT).then(() => TIMEOUT_SYMBOL),
]);
if (result === TIMEOUT_SYMBOL) {
// Some debounced functionality here
}
});
```
<br />
<p>| <a href="https://awai.vercel.app/">Documentation</a> |</p>
</div>

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc