@yaasl/core 0.7.0-alpha.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/@types/base/Stateful.d.ts +19 -0
- package/dist/@types/base/atom.d.ts +38 -0
- package/dist/@types/base/config.d.ts +16 -0
- package/dist/@types/base/derive.d.ts +19 -0
- package/dist/@types/base/index.d.ts +4 -0
- package/dist/@types/index.d.ts +2 -0
- package/dist/@types/middleware/MiddlewareDispatcher.d.ts +14 -0
- package/dist/@types/middleware/expiration.d.ts +17 -0
- package/dist/@types/middleware/index.d.ts +10 -0
- package/dist/@types/middleware/indexedDb.d.ts +15 -0
- package/dist/@types/middleware/localStorage.d.ts +28 -0
- package/dist/@types/middleware/middleware.d.ts +31 -0
- package/dist/@types/middleware/migration.d.ts +19 -0
- package/dist/@types/utils/Expiration.d.ts +18 -0
- package/dist/@types/utils/LocalStorage.d.ts +17 -0
- package/dist/@types/utils/Store.d.ts +9 -0
- package/dist/@types/utils/Thenable.d.ts +7 -0
- package/dist/cjs/base/Stateful.js +36 -0
- package/dist/cjs/base/atom.js +67 -0
- package/dist/cjs/base/config.js +11 -0
- package/dist/cjs/base/derive.js +32 -0
- package/dist/cjs/base/index.js +20 -0
- package/dist/cjs/index.js +18 -0
- package/dist/cjs/middleware/MiddlewareDispatcher.js +34 -0
- package/dist/cjs/middleware/expiration.js +48 -0
- package/dist/cjs/middleware/index.js +14 -0
- package/dist/cjs/middleware/indexedDb.js +49 -0
- package/dist/cjs/middleware/localStorage.js +38 -0
- package/dist/cjs/middleware/middleware.js +19 -0
- package/dist/cjs/middleware/migration.js +91 -0
- package/dist/cjs/utils/Expiration.js +64 -0
- package/dist/cjs/utils/LocalStorage.js +60 -0
- package/dist/cjs/utils/Store.js +50 -0
- package/dist/cjs/utils/Thenable.js +25 -0
- package/dist/mjs/base/Stateful.js +32 -0
- package/dist/mjs/base/atom.js +51 -0
- package/dist/mjs/base/config.js +8 -0
- package/dist/mjs/base/derive.js +27 -0
- package/dist/mjs/base/index.js +4 -0
- package/dist/mjs/index.js +2 -0
- package/dist/mjs/middleware/MiddlewareDispatcher.js +30 -0
- package/dist/mjs/middleware/expiration.js +47 -0
- package/dist/mjs/middleware/index.js +5 -0
- package/dist/mjs/middleware/indexedDb.js +35 -0
- package/dist/mjs/middleware/localStorage.js +35 -0
- package/dist/mjs/middleware/middleware.js +15 -0
- package/dist/mjs/middleware/migration.js +86 -0
- package/dist/mjs/utils/Expiration.js +60 -0
- package/dist/mjs/utils/LocalStorage.js +54 -0
- package/dist/mjs/utils/Store.js +33 -0
- package/dist/mjs/utils/Thenable.js +21 -0
- package/package.json +57 -0
- package/tsconfig.json +3 -0
- package/tsconfig.node.json +9 -0
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export declare class Stateful<Value = unknown> {
|
|
2
|
+
protected value: Value;
|
|
3
|
+
private listeners;
|
|
4
|
+
constructor(value: Value);
|
|
5
|
+
/** Read the value of state.
|
|
6
|
+
*
|
|
7
|
+
* @returns The current value.
|
|
8
|
+
**/
|
|
9
|
+
get(): Value;
|
|
10
|
+
/** Subscribe to value changes.
|
|
11
|
+
*
|
|
12
|
+
* @param callback Function to use the new value.
|
|
13
|
+
*
|
|
14
|
+
* @returns A callback to unsubscribe the passed callback.
|
|
15
|
+
*/
|
|
16
|
+
subscribe(callback: (value: Value) => void): () => boolean;
|
|
17
|
+
private emit;
|
|
18
|
+
protected update(value: Value): void;
|
|
19
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { SetStateAction } from "@yaasl/utils";
|
|
2
|
+
import { Stateful } from "./Stateful";
|
|
3
|
+
import { MiddlewareAtomCallback } from "../middleware/middleware";
|
|
4
|
+
interface AtomConfig<AtomValue> {
|
|
5
|
+
/** Value that will be returned if the atom is not defined in the store */
|
|
6
|
+
defaultValue: AtomValue;
|
|
7
|
+
/** Name of the atom. Must be unique among all atoms. */
|
|
8
|
+
name?: string;
|
|
9
|
+
/** Middleware that will be applied on the atom */
|
|
10
|
+
middleware?: MiddlewareAtomCallback<any>[];
|
|
11
|
+
}
|
|
12
|
+
export declare class Atom<AtomValue = unknown> extends Stateful<AtomValue> {
|
|
13
|
+
readonly defaultValue: AtomValue;
|
|
14
|
+
readonly name: string;
|
|
15
|
+
didInit: Promise<void> | boolean;
|
|
16
|
+
constructor({ defaultValue, name, middleware, }: AtomConfig<AtomValue>);
|
|
17
|
+
/** Set the value of the atom.
|
|
18
|
+
*
|
|
19
|
+
* @param next New value or function to create the
|
|
20
|
+
* new value based off the previous value.
|
|
21
|
+
*/
|
|
22
|
+
set(next: SetStateAction<AtomValue>): void;
|
|
23
|
+
/** Resolve the value of a promise and set as atom value.
|
|
24
|
+
*
|
|
25
|
+
* @param promise Promise to unwrap
|
|
26
|
+
*/
|
|
27
|
+
unwrap(promise: Promise<AtomValue>): Promise<AtomValue>;
|
|
28
|
+
}
|
|
29
|
+
/** Creates an atom store.
|
|
30
|
+
*
|
|
31
|
+
* @param config.defaultValue Value that will be used initially.
|
|
32
|
+
* @param config.name Name of the atom. Must be unique among all atoms. Defaults to "atom-{number}".
|
|
33
|
+
* @param config.middleware Middleware that will be applied on the atom.
|
|
34
|
+
*
|
|
35
|
+
* @returns An atom instance.
|
|
36
|
+
**/
|
|
37
|
+
export declare const atom: <AtomValue>(config: AtomConfig<AtomValue>) => Atom<AtomValue>;
|
|
38
|
+
export {};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
interface Config {
|
|
2
|
+
/** Global name to make internal keys unique
|
|
3
|
+
* among UIs on the same domain.
|
|
4
|
+
*
|
|
5
|
+
* (e.g. local storage keys look like this if a name is set:
|
|
6
|
+
* "{config-name}/{atom-name}")
|
|
7
|
+
**/
|
|
8
|
+
name?: string;
|
|
9
|
+
}
|
|
10
|
+
/** Global configuration object to change internal behavior of yaasl.
|
|
11
|
+
*
|
|
12
|
+
* Values should be set once in your application entrypoint,
|
|
13
|
+
* before yaasl is being used.
|
|
14
|
+
**/
|
|
15
|
+
export declare const CONFIG: Config;
|
|
16
|
+
export {};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { Stateful } from "./Stateful";
|
|
2
|
+
type Derivation<T> = (context: {
|
|
3
|
+
get: <V>(dep: Stateful<V>) => V;
|
|
4
|
+
}) => T;
|
|
5
|
+
export declare class Derive<DerivedValue> extends Stateful<DerivedValue> {
|
|
6
|
+
private readonly derivation;
|
|
7
|
+
private dependencies;
|
|
8
|
+
constructor(derivation: Derivation<DerivedValue>);
|
|
9
|
+
private addDependency;
|
|
10
|
+
private deriveUpdate;
|
|
11
|
+
}
|
|
12
|
+
/** Creates a value, derived from one or more atoms or other derived values.
|
|
13
|
+
*
|
|
14
|
+
* @param get Function to derive the new value.
|
|
15
|
+
*
|
|
16
|
+
* @returns A derived instance.
|
|
17
|
+
**/
|
|
18
|
+
export declare const derive: <DerivedValue>(get: Derivation<DerivedValue>) => Derive<DerivedValue>;
|
|
19
|
+
export {};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { MiddlewareAtomCallback } from "./middleware";
|
|
2
|
+
import { Atom } from "../base/atom";
|
|
3
|
+
interface MiddlewareDispatcherConstructor {
|
|
4
|
+
atom: Atom<any>;
|
|
5
|
+
middleware: MiddlewareAtomCallback<any>[];
|
|
6
|
+
}
|
|
7
|
+
export declare class MiddlewareDispatcher {
|
|
8
|
+
didInit: Promise<void> | boolean;
|
|
9
|
+
private middleware;
|
|
10
|
+
constructor({ atom, middleware }: MiddlewareDispatcherConstructor);
|
|
11
|
+
private subscribeSetters;
|
|
12
|
+
private callMiddlewareAction;
|
|
13
|
+
}
|
|
14
|
+
export {};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export interface ExpirationOptions {
|
|
2
|
+
/** Date at which the value expires */
|
|
3
|
+
expiresAt?: Date | (() => Date);
|
|
4
|
+
/** Milliseconds in which the value expires. Will be ignored if expiresAt is set. */
|
|
5
|
+
expiresIn?: number | (() => number);
|
|
6
|
+
}
|
|
7
|
+
/** Middleware to make an atom value expirable and reset to its defaulValue.
|
|
8
|
+
*
|
|
9
|
+
* __Note:__ When using `expiresAt`, a function returning the date should be prefered since using a static date might end in an infinite loop.
|
|
10
|
+
*
|
|
11
|
+
* @param {ExpirationOptions | undefined} options
|
|
12
|
+
* @param options.expiresAt Date at which the value expires
|
|
13
|
+
* @param options.expiresIn Milliseconds in which the value expires. Will be ignored if expiresAt is set.
|
|
14
|
+
*
|
|
15
|
+
* @returns The middleware to be used on atoms.
|
|
16
|
+
**/
|
|
17
|
+
export declare const expiration: (__0_0: ExpirationOptions) => import("./middleware").MiddlewareAtomCallback<ExpirationOptions>;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export { middleware } from "./middleware";
|
|
2
|
+
export type { Middleware } from "./middleware";
|
|
3
|
+
export { localStorage } from "./localStorage";
|
|
4
|
+
export type { LocalStorageOptions, LocalStorageParser } from "./localStorage";
|
|
5
|
+
export { indexedDb } from "./indexedDb";
|
|
6
|
+
export type { IndexedDbOptions } from "./indexedDb";
|
|
7
|
+
export { expiration } from "./expiration";
|
|
8
|
+
export type { ExpirationOptions } from "./expiration";
|
|
9
|
+
export { migration, createMigrationStep } from "./migration";
|
|
10
|
+
export type { MigrationOptions, MigrationStep } from "./migration";
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export interface IndexedDbOptions {
|
|
2
|
+
/** Use your own store key. Will be `atom.name` by default. */
|
|
3
|
+
key?: string;
|
|
4
|
+
}
|
|
5
|
+
/** Middleware to save and load atom values to an indexedDb.
|
|
6
|
+
*
|
|
7
|
+
* Will use one database and store for all atoms with your `CONFIG.name`
|
|
8
|
+
* as name or `yaasl` if not set.
|
|
9
|
+
*
|
|
10
|
+
* @param {IndexedDbOptions | undefined} options
|
|
11
|
+
* @param options.key Use your own store key. Will be `atom.name` by default.
|
|
12
|
+
*
|
|
13
|
+
* @returns The middleware to be used on atoms.
|
|
14
|
+
**/
|
|
15
|
+
export declare const indexedDb: (...[optionsArg]: [] | [undefined] | [IndexedDbOptions]) => import("./middleware").MiddlewareAtomCallback<IndexedDbOptions | undefined>;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
export interface LocalStorageParser<T = any> {
|
|
2
|
+
parse: (value: string) => T;
|
|
3
|
+
stringify: (value: T) => string;
|
|
4
|
+
}
|
|
5
|
+
export interface LocalStorageOptions {
|
|
6
|
+
/** Use your own key for the local storage.
|
|
7
|
+
* Will be "{config-name}/{atom-name}" by default.
|
|
8
|
+
*/
|
|
9
|
+
key?: string;
|
|
10
|
+
/** Disable the synchronization of values over browser tabs */
|
|
11
|
+
noTabSync?: boolean;
|
|
12
|
+
/** Custom functions to stringify and parse values.
|
|
13
|
+
* Defaults to JSON.stringify and JSON.parse.
|
|
14
|
+
* Use this when handling complex datatypes like Maps or Sets.
|
|
15
|
+
*/
|
|
16
|
+
parser?: LocalStorageParser;
|
|
17
|
+
}
|
|
18
|
+
/** Middleware to save and load atom values to the local storage.
|
|
19
|
+
*
|
|
20
|
+
* @param {LocalStorageOptions | undefined} options
|
|
21
|
+
* @param options.key Use your own key for the local storage.
|
|
22
|
+
* Will be "{config-name}/{atom-name}" by default.
|
|
23
|
+
* @param options.noTabSync Disable the synchronization of values over browser tabs.
|
|
24
|
+
* @param options.parser Custom functions to stringify and parse values. Defaults to JSON.stringify and JSON.parse. Use this when handling complex datatypes like Maps or Sets.
|
|
25
|
+
*
|
|
26
|
+
* @returns The middleware to be used on atoms.
|
|
27
|
+
**/
|
|
28
|
+
export declare const localStorage: (...[optionsArg]: [] | [undefined] | [LocalStorageOptions]) => import("./middleware").MiddlewareAtomCallback<LocalStorageOptions | undefined>;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { Atom } from "../base";
|
|
2
|
+
export type ActionType = "init" | "didInit" | "set";
|
|
3
|
+
interface MiddlewarePayload<Options> {
|
|
4
|
+
value: unknown;
|
|
5
|
+
atom: Atom;
|
|
6
|
+
options: Options;
|
|
7
|
+
}
|
|
8
|
+
export interface MiddlewareActions<Options> {
|
|
9
|
+
init?: (payload: MiddlewarePayload<Options>) => Promise<any> | void;
|
|
10
|
+
didInit?: (payload: MiddlewarePayload<Options>) => Promise<any> | void;
|
|
11
|
+
set?: (payload: MiddlewarePayload<Options>) => void;
|
|
12
|
+
}
|
|
13
|
+
interface MiddlewareSetupProps<Options> {
|
|
14
|
+
atom: Atom;
|
|
15
|
+
options: Options;
|
|
16
|
+
}
|
|
17
|
+
export type MiddlewareAtomCallback<Options> = (atom: Atom<any>) => Middleware<Options>;
|
|
18
|
+
export type MiddlewareSetup<Options> = MiddlewareActions<Options> | ((props: MiddlewareSetupProps<Options>) => MiddlewareActions<Options>);
|
|
19
|
+
export interface Middleware<Options = unknown> {
|
|
20
|
+
options: Options;
|
|
21
|
+
actions: MiddlewareActions<Options>;
|
|
22
|
+
}
|
|
23
|
+
/** Create middlewares to be used in combination with atoms.
|
|
24
|
+
*
|
|
25
|
+
* @param setup Middleware actions or function to create middleware actions.
|
|
26
|
+
* Middleware actions are fired in the atom lifecycle, alongside to the subscriptions.
|
|
27
|
+
*
|
|
28
|
+
* @returns A middleware function to be used in atoms.
|
|
29
|
+
**/
|
|
30
|
+
export declare const middleware: <Options = undefined>(setup: MiddlewareSetup<Options>) => (...[optionsArg]: Options extends undefined ? [Options] | [] : [Options]) => MiddlewareAtomCallback<Options>;
|
|
31
|
+
export {};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export interface MigrationStep<Version extends string = string, PreviousVersion extends string | null = string | null, OldData = any, NewData = any> {
|
|
2
|
+
/** Previous version of the data, before performing the migration */
|
|
3
|
+
previous: PreviousVersion;
|
|
4
|
+
/** Version of the data after the migration */
|
|
5
|
+
version: Version;
|
|
6
|
+
/** Function to migrate the data */
|
|
7
|
+
migrate: (data: OldData) => NewData;
|
|
8
|
+
/** Function to validate the data before migrating */
|
|
9
|
+
validate?: (data: unknown) => data is OldData;
|
|
10
|
+
}
|
|
11
|
+
export interface MigrationOptions {
|
|
12
|
+
/** Migration steps to perform.
|
|
13
|
+
*
|
|
14
|
+
* Note: One step must have a `previous` version set to null as entry point.
|
|
15
|
+
**/
|
|
16
|
+
steps: MigrationStep[];
|
|
17
|
+
}
|
|
18
|
+
export declare const migration: (__0_0: MigrationOptions) => import("./middleware").MiddlewareAtomCallback<MigrationOptions>;
|
|
19
|
+
export declare const createMigrationStep: <Version extends string, PreviousVersion extends string | null, OldData, NewData>(migration: MigrationStep<Version, PreviousVersion, OldData, NewData>) => MigrationStep<Version, PreviousVersion, OldData, NewData>;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export interface ExpirationOptions {
|
|
2
|
+
/** Local storage key to persist the expiration */
|
|
3
|
+
key: string;
|
|
4
|
+
/** Date at which the value expires */
|
|
5
|
+
expiresAt?: Date | (() => Date);
|
|
6
|
+
/** Milliseconds in which the value expires. Will be ignored if expiresAt is set. */
|
|
7
|
+
expiresIn?: number | (() => number);
|
|
8
|
+
}
|
|
9
|
+
export declare class Expiration {
|
|
10
|
+
private readonly key;
|
|
11
|
+
private readonly getExpiration;
|
|
12
|
+
private timeout;
|
|
13
|
+
constructor({ key, expiresAt, expiresIn }: ExpirationOptions);
|
|
14
|
+
remove(): void;
|
|
15
|
+
private dispatchExpiration;
|
|
16
|
+
init(onExpire: () => void): void;
|
|
17
|
+
set(onExpire: () => void): void;
|
|
18
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { Dispatch } from "@yaasl/utils";
|
|
2
|
+
export interface LocalStorageParser<T = any> {
|
|
3
|
+
parse: (value: string) => T;
|
|
4
|
+
stringify: (value: T) => string;
|
|
5
|
+
}
|
|
6
|
+
export interface LocalStorageConstructorOptions<T> {
|
|
7
|
+
parser?: LocalStorageParser<T>;
|
|
8
|
+
onTabSync?: Dispatch<T | null>;
|
|
9
|
+
}
|
|
10
|
+
export declare class LocalStorage<T = unknown> {
|
|
11
|
+
private readonly key;
|
|
12
|
+
private parser;
|
|
13
|
+
constructor(key: string, options?: LocalStorageConstructorOptions<T>);
|
|
14
|
+
get(): T | null;
|
|
15
|
+
set(value: T): void;
|
|
16
|
+
remove(): void;
|
|
17
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
type Executor<T, R> = ((value: T) => R | PromiseLike<R>) | undefined | null;
|
|
2
|
+
export declare class Thenable<T = undefined> implements PromiseLike<T> {
|
|
3
|
+
private value?;
|
|
4
|
+
constructor(value?: T | undefined);
|
|
5
|
+
then<Result = T, Reject = never>(onfulfilled?: Executor<T, Result>, onrejected?: Executor<any, Reject>): PromiseLike<Result | Reject>;
|
|
6
|
+
}
|
|
7
|
+
export {};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Stateful = void 0;
|
|
4
|
+
class Stateful {
|
|
5
|
+
constructor(value) {
|
|
6
|
+
this.value = value;
|
|
7
|
+
this.listeners = new Set();
|
|
8
|
+
}
|
|
9
|
+
/** Read the value of state.
|
|
10
|
+
*
|
|
11
|
+
* @returns The current value.
|
|
12
|
+
**/
|
|
13
|
+
get() {
|
|
14
|
+
return this.value;
|
|
15
|
+
}
|
|
16
|
+
/** Subscribe to value changes.
|
|
17
|
+
*
|
|
18
|
+
* @param callback Function to use the new value.
|
|
19
|
+
*
|
|
20
|
+
* @returns A callback to unsubscribe the passed callback.
|
|
21
|
+
*/
|
|
22
|
+
subscribe(callback) {
|
|
23
|
+
this.listeners.add(callback);
|
|
24
|
+
return () => this.listeners.delete(callback);
|
|
25
|
+
}
|
|
26
|
+
emit() {
|
|
27
|
+
this.listeners.forEach(listener => listener(this.get()));
|
|
28
|
+
}
|
|
29
|
+
update(value) {
|
|
30
|
+
if (this.value !== value) {
|
|
31
|
+
this.value = value;
|
|
32
|
+
this.emit();
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
exports.Stateful = Stateful;
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.atom = exports.Atom = void 0;
|
|
13
|
+
const Stateful_1 = require("./Stateful");
|
|
14
|
+
const MiddlewareDispatcher_1 = require("../middleware/MiddlewareDispatcher");
|
|
15
|
+
let key = 0;
|
|
16
|
+
class Atom extends Stateful_1.Stateful {
|
|
17
|
+
constructor({ defaultValue, name = `atom-${++key}`, middleware, }) {
|
|
18
|
+
super(defaultValue);
|
|
19
|
+
this.didInit = false;
|
|
20
|
+
this.name = name;
|
|
21
|
+
this.defaultValue = defaultValue;
|
|
22
|
+
if (!middleware || middleware.length === 0) {
|
|
23
|
+
this.didInit = true;
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
const { didInit } = new MiddlewareDispatcher_1.MiddlewareDispatcher({ atom: this, middleware });
|
|
27
|
+
if (typeof didInit === "boolean") {
|
|
28
|
+
this.didInit = didInit;
|
|
29
|
+
}
|
|
30
|
+
else {
|
|
31
|
+
this.didInit = didInit.then(() => {
|
|
32
|
+
this.didInit = true;
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
/** Set the value of the atom.
|
|
37
|
+
*
|
|
38
|
+
* @param next New value or function to create the
|
|
39
|
+
* new value based off the previous value.
|
|
40
|
+
*/
|
|
41
|
+
set(next) {
|
|
42
|
+
const value = next instanceof Function ? next(this.get()) : next;
|
|
43
|
+
super.update(value);
|
|
44
|
+
}
|
|
45
|
+
/** Resolve the value of a promise and set as atom value.
|
|
46
|
+
*
|
|
47
|
+
* @param promise Promise to unwrap
|
|
48
|
+
*/
|
|
49
|
+
unwrap(promise) {
|
|
50
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
51
|
+
const value = yield promise;
|
|
52
|
+
this.set(value);
|
|
53
|
+
return value;
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
exports.Atom = Atom;
|
|
58
|
+
/** Creates an atom store.
|
|
59
|
+
*
|
|
60
|
+
* @param config.defaultValue Value that will be used initially.
|
|
61
|
+
* @param config.name Name of the atom. Must be unique among all atoms. Defaults to "atom-{number}".
|
|
62
|
+
* @param config.middleware Middleware that will be applied on the atom.
|
|
63
|
+
*
|
|
64
|
+
* @returns An atom instance.
|
|
65
|
+
**/
|
|
66
|
+
const atom = (config) => new Atom(config);
|
|
67
|
+
exports.atom = atom;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.CONFIG = void 0;
|
|
4
|
+
/** Global configuration object to change internal behavior of yaasl.
|
|
5
|
+
*
|
|
6
|
+
* Values should be set once in your application entrypoint,
|
|
7
|
+
* before yaasl is being used.
|
|
8
|
+
**/
|
|
9
|
+
exports.CONFIG = {
|
|
10
|
+
name: undefined,
|
|
11
|
+
};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.derive = exports.Derive = void 0;
|
|
4
|
+
const Stateful_1 = require("./Stateful");
|
|
5
|
+
class Derive extends Stateful_1.Stateful {
|
|
6
|
+
constructor(derivation) {
|
|
7
|
+
super(undefined);
|
|
8
|
+
this.derivation = derivation;
|
|
9
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
10
|
+
this.dependencies = new Set();
|
|
11
|
+
this.value = derivation({ get: dep => this.addDependency(dep) });
|
|
12
|
+
}
|
|
13
|
+
addDependency(dependency) {
|
|
14
|
+
if (!this.dependencies.has(dependency)) {
|
|
15
|
+
dependency.subscribe(() => this.deriveUpdate());
|
|
16
|
+
this.dependencies.add(dependency);
|
|
17
|
+
}
|
|
18
|
+
return dependency.get();
|
|
19
|
+
}
|
|
20
|
+
deriveUpdate() {
|
|
21
|
+
this.update(this.derivation({ get: dep => this.addDependency(dep) }));
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
exports.Derive = Derive;
|
|
25
|
+
/** Creates a value, derived from one or more atoms or other derived values.
|
|
26
|
+
*
|
|
27
|
+
* @param get Function to derive the new value.
|
|
28
|
+
*
|
|
29
|
+
* @returns A derived instance.
|
|
30
|
+
**/
|
|
31
|
+
const derive = (get) => new Derive(get);
|
|
32
|
+
exports.derive = derive;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./atom"), exports);
|
|
18
|
+
__exportStar(require("./derive"), exports);
|
|
19
|
+
__exportStar(require("./config"), exports);
|
|
20
|
+
__exportStar(require("./Stateful"), exports);
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./base"), exports);
|
|
18
|
+
__exportStar(require("./middleware"), exports);
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.MiddlewareDispatcher = void 0;
|
|
4
|
+
const Thenable_1 = require("../utils/Thenable");
|
|
5
|
+
const isPromise = (value) => value instanceof Promise;
|
|
6
|
+
class MiddlewareDispatcher {
|
|
7
|
+
constructor({ atom, middleware }) {
|
|
8
|
+
this.didInit = false;
|
|
9
|
+
this.middleware = [];
|
|
10
|
+
this.middleware = middleware.map(create => create(atom));
|
|
11
|
+
const result = this.callMiddlewareAction("init", atom)
|
|
12
|
+
.then(() => this.subscribeSetters(atom))
|
|
13
|
+
.then(() => this.callMiddlewareAction("didInit", atom))
|
|
14
|
+
.then(() => {
|
|
15
|
+
this.didInit = true;
|
|
16
|
+
});
|
|
17
|
+
if (result instanceof Promise) {
|
|
18
|
+
this.didInit = result;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
subscribeSetters(atom) {
|
|
22
|
+
atom.subscribe(value => void this.callMiddlewareAction("set", atom, value));
|
|
23
|
+
}
|
|
24
|
+
callMiddlewareAction(action, atom, value = atom.get()) {
|
|
25
|
+
const result = this.middleware.map(middleware => {
|
|
26
|
+
const { actions, options } = middleware;
|
|
27
|
+
const actionFn = actions[action];
|
|
28
|
+
return actionFn === null || actionFn === void 0 ? void 0 : actionFn({ value, atom, options });
|
|
29
|
+
});
|
|
30
|
+
const promises = result.filter(isPromise);
|
|
31
|
+
return promises.length ? Promise.all(promises) : new Thenable_1.Thenable();
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
exports.MiddlewareDispatcher = MiddlewareDispatcher;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.expiration = void 0;
|
|
4
|
+
const middleware_1 = require("./middleware");
|
|
5
|
+
const base_1 = require("../base");
|
|
6
|
+
const Expiration_1 = require("../utils/Expiration");
|
|
7
|
+
const STORAGE = window.localStorage;
|
|
8
|
+
const syncOverBrowserTabs = (observingKey, onChange) => window.addEventListener("storage", ({ key, newValue }) => {
|
|
9
|
+
if (observingKey !== key)
|
|
10
|
+
return;
|
|
11
|
+
const currentValue = STORAGE.getItem(observingKey);
|
|
12
|
+
if (currentValue === newValue)
|
|
13
|
+
return;
|
|
14
|
+
onChange(newValue);
|
|
15
|
+
});
|
|
16
|
+
/** Middleware to make an atom value expirable and reset to its defaulValue.
|
|
17
|
+
*
|
|
18
|
+
* __Note:__ When using `expiresAt`, a function returning the date should be prefered since using a static date might end in an infinite loop.
|
|
19
|
+
*
|
|
20
|
+
* @param {ExpirationOptions | undefined} options
|
|
21
|
+
* @param options.expiresAt Date at which the value expires
|
|
22
|
+
* @param options.expiresIn Milliseconds in which the value expires. Will be ignored if expiresAt is set.
|
|
23
|
+
*
|
|
24
|
+
* @returns The middleware to be used on atoms.
|
|
25
|
+
**/
|
|
26
|
+
exports.expiration = (0, middleware_1.middleware)(({ atom, options = {} }) => {
|
|
27
|
+
var _a;
|
|
28
|
+
const hasExpiration = Boolean((_a = options.expiresAt) !== null && _a !== void 0 ? _a : options.expiresIn);
|
|
29
|
+
if (!hasExpiration)
|
|
30
|
+
return {};
|
|
31
|
+
const key = base_1.CONFIG.name ? `${base_1.CONFIG.name}/${atom.name}` : atom.name;
|
|
32
|
+
const expiration = new Expiration_1.Expiration(Object.assign(Object.assign({}, options), { key: `${key}-expires-at` }));
|
|
33
|
+
const reset = () => {
|
|
34
|
+
expiration.remove();
|
|
35
|
+
atom.set(atom.defaultValue);
|
|
36
|
+
};
|
|
37
|
+
return {
|
|
38
|
+
init: () => {
|
|
39
|
+
expiration.init(reset);
|
|
40
|
+
syncOverBrowserTabs(key, () => expiration.init(reset));
|
|
41
|
+
},
|
|
42
|
+
set: ({ value }) => {
|
|
43
|
+
if (value === atom.defaultValue)
|
|
44
|
+
return;
|
|
45
|
+
expiration.set(reset);
|
|
46
|
+
},
|
|
47
|
+
};
|
|
48
|
+
});
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createMigrationStep = exports.migration = exports.expiration = exports.indexedDb = exports.localStorage = exports.middleware = void 0;
|
|
4
|
+
var middleware_1 = require("./middleware");
|
|
5
|
+
Object.defineProperty(exports, "middleware", { enumerable: true, get: function () { return middleware_1.middleware; } });
|
|
6
|
+
var localStorage_1 = require("./localStorage");
|
|
7
|
+
Object.defineProperty(exports, "localStorage", { enumerable: true, get: function () { return localStorage_1.localStorage; } });
|
|
8
|
+
var indexedDb_1 = require("./indexedDb");
|
|
9
|
+
Object.defineProperty(exports, "indexedDb", { enumerable: true, get: function () { return indexedDb_1.indexedDb; } });
|
|
10
|
+
var expiration_1 = require("./expiration");
|
|
11
|
+
Object.defineProperty(exports, "expiration", { enumerable: true, get: function () { return expiration_1.expiration; } });
|
|
12
|
+
var migration_1 = require("./migration");
|
|
13
|
+
Object.defineProperty(exports, "migration", { enumerable: true, get: function () { return migration_1.migration; } });
|
|
14
|
+
Object.defineProperty(exports, "createMigrationStep", { enumerable: true, get: function () { return migration_1.createMigrationStep; } });
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.indexedDb = void 0;
|
|
13
|
+
const middleware_1 = require("./middleware");
|
|
14
|
+
const base_1 = require("../base");
|
|
15
|
+
const Store_1 = require("../utils/Store");
|
|
16
|
+
let atomDb = null;
|
|
17
|
+
/** Middleware to save and load atom values to an indexedDb.
|
|
18
|
+
*
|
|
19
|
+
* Will use one database and store for all atoms with your `CONFIG.name`
|
|
20
|
+
* as name or `yaasl` if not set.
|
|
21
|
+
*
|
|
22
|
+
* @param {IndexedDbOptions | undefined} options
|
|
23
|
+
* @param options.key Use your own store key. Will be `atom.name` by default.
|
|
24
|
+
*
|
|
25
|
+
* @returns The middleware to be used on atoms.
|
|
26
|
+
**/
|
|
27
|
+
exports.indexedDb = (0, middleware_1.middleware)(({ atom, options }) => {
|
|
28
|
+
var _a;
|
|
29
|
+
const key = (_a = options === null || options === void 0 ? void 0 : options.key) !== null && _a !== void 0 ? _a : atom.name;
|
|
30
|
+
return {
|
|
31
|
+
init: ({ atom }) => {
|
|
32
|
+
var _a;
|
|
33
|
+
if (!atomDb) {
|
|
34
|
+
atomDb = new Store_1.Store((_a = base_1.CONFIG.name) !== null && _a !== void 0 ? _a : "yaasl");
|
|
35
|
+
}
|
|
36
|
+
return atomDb.get(key).then((value) => __awaiter(void 0, void 0, void 0, function* () {
|
|
37
|
+
if (value !== undefined) {
|
|
38
|
+
atom.set(value);
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
yield (atomDb === null || atomDb === void 0 ? void 0 : atomDb.set(key, atom.defaultValue));
|
|
42
|
+
}
|
|
43
|
+
}));
|
|
44
|
+
},
|
|
45
|
+
set: ({ value }) => {
|
|
46
|
+
void (atomDb === null || atomDb === void 0 ? void 0 : atomDb.set(key, value));
|
|
47
|
+
},
|
|
48
|
+
};
|
|
49
|
+
});
|