svas 0.1.9 → 1.1.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.
@@ -1,8 +1,15 @@
1
1
  import type { Props } from "./Async";
2
+ declare function $$render<T>(): {
3
+ props: Props<T>;
4
+ exports: {};
5
+ bindings: "";
6
+ slots: {};
7
+ events: {};
8
+ };
2
9
  declare class __sveltets_Render<T> {
3
- props(): Props<T>;
4
- events(): {};
5
- slots(): {};
10
+ props(): ReturnType<typeof $$render<T>>['props'];
11
+ events(): ReturnType<typeof $$render<T>>['events'];
12
+ slots(): ReturnType<typeof $$render<T>>['slots'];
6
13
  bindings(): "";
7
14
  exports(): {};
8
15
  }
@@ -0,0 +1,3 @@
1
+ import type { Readable } from "svelte/store";
2
+ import type { Maybe } from "./Maybe";
3
+ export declare function awaited<T>(store: Readable<Maybe<T>>): Promise<T | Error>;
@@ -0,0 +1,4 @@
1
+ import { waitUntil } from "./waitUntil";
2
+ export function awaited(store) {
3
+ return waitUntil(store, (value) => value !== null);
4
+ }
@@ -4,37 +4,29 @@ import type { GetOptions, Values } from './values';
4
4
  export declare class Collection<T extends Identifiable, E extends Error = Error> implements Readable<Maybe<T[], E>> {
5
5
  private readonly store;
6
6
  private readonly values?;
7
- private readonly fetch;
8
- private readonly map;
9
- private readonly sort;
7
+ private readonly request;
10
8
  private readonly revalidate;
11
9
  private readonly stale;
12
10
  private timestamp;
13
11
  constructor(options: Options<T, E>);
14
12
  subscribe(run: Subscriber<Maybe<T[], E>>, invalidate?: () => void): Unsubscriber;
15
- add<I = T>(item: Input<T, typeof this.map, I>): void;
13
+ add(item: T): void;
16
14
  get(id: string, options?: GetOptions): Readable<Maybe<T, E>>;
17
15
  extract(id: string): T | null;
18
16
  delete(id: string): void;
19
- set<I = T>(item: Input<T, typeof this.map, I>, options?: SetOptions): Readable<T | E>;
20
- preset<I = T>(item: Input<T, typeof this.map, I>): void;
21
- reset(id: string): void;
17
+ set(item: T, options?: SetOptions): void;
22
18
  update(id: string, update: (item: T) => T | void, options?: SetOptions): void;
23
19
  sync(): this;
24
- replace<I = T>(items: Array<Input<T, typeof this.map, I>>): void;
20
+ fetch(): Promise<this>;
21
+ replace(items: T[]): void;
25
22
  private refresh;
26
23
  private persist;
27
24
  private bind;
28
25
  private clear;
29
26
  }
30
- type Input<T, M, Default> = M extends (arg: infer P) => T ? P : Default;
31
27
  interface Options<T = unknown, E extends Error = Error> {
32
28
  /** Fetches the collection. */
33
- get?: () => Promise<any[] | E>;
34
- /** Maps the fetched item to the type of the collection. */
35
- map?: (item: any) => T;
36
- /** Sorting function applied on updates. */
37
- sort?: (a: T, b: T) => number;
29
+ get?: () => Promise<T[] | E>;
38
30
  /** Time in milliseconds before revalidating the collection. Defaults to 300 seconds. */
39
31
  revalidate?: number;
40
32
  /** Whether to keep the collection while revalidating. Defaults to false. */
@@ -50,14 +42,8 @@ export interface Identifiable {
50
42
  id: string;
51
43
  }
52
44
  export interface SetOptions {
53
- /** Whether to sort the collection after setting the item. Defaults to true. */
54
- sort?: boolean;
55
45
  /** Whether to add the item to the collection if it does not exist. Defaults to false. */
56
46
  add?: boolean;
57
- /** Whether value is transient. Defaults to false. */
58
- stash?: boolean;
59
- /** Whether to sync the collection values after setting the item. Defaults to true. */
60
- sync?: boolean;
61
47
  }
62
48
  export declare function collection<T extends Identifiable, E extends Error = Error>(options: Options<T, E>): Collection<T, E>;
63
49
  export {};
@@ -1,47 +1,35 @@
1
1
  import { writable } from 'svelte/store';
2
- import { browser } from '$app/environment';
3
2
  export class Collection {
4
3
  store;
5
4
  values;
6
- fetch;
7
- map;
8
- sort;
5
+ request;
9
6
  revalidate;
10
7
  stale;
11
8
  timestamp = 0;
12
9
  constructor(options) {
13
10
  this.store = writable(null);
14
11
  this.values = options.values;
15
- this.fetch = options.get;
16
- this.map = options.map;
17
- this.sort = options.sort;
12
+ this.request = options.get;
18
13
  this.revalidate = options.revalidate ?? DEFAULTS.revalidate;
19
14
  this.stale = options.stale ?? DEFAULTS.stale;
20
- if (browser) {
21
- if (options.persist !== undefined)
22
- this.persist(options.persist);
23
- if (options.bind !== undefined)
24
- this.bind(options.bind);
25
- }
15
+ if (options.persist !== undefined)
16
+ this.persist(options.persist);
17
+ if (options.bind !== undefined)
18
+ this.bind(options.bind);
26
19
  }
27
20
  subscribe(run, invalidate) {
28
21
  this.sync();
29
22
  return this.store.subscribe(run, invalidate);
30
23
  }
31
24
  add(item) {
32
- const value = this.map?.(item) ?? item;
33
- this.values?.set(value.id, value);
25
+ this.values?.set(item.id, item);
34
26
  this.store.update((items) => {
35
27
  if (items === null || items instanceof Error)
36
- return [value];
37
- else {
38
- if (items.find((item) => item.id === value.id) !== undefined)
39
- return items;
40
- items.unshift(value);
41
- if (this.sort !== undefined)
42
- items.sort(this.sort);
28
+ return [item];
29
+ else if (items.find((i) => i.id === item.id) !== undefined)
43
30
  return items;
44
- }
31
+ else
32
+ return [item, ...items];
45
33
  });
46
34
  }
47
35
  get(id, options) {
@@ -59,37 +47,20 @@ export class Collection {
59
47
  this.store.update((items) => {
60
48
  if (items === null || items instanceof Error)
61
49
  return items;
62
- return items.filter((item) => item.id !== id);
50
+ else
51
+ return items.filter((item) => item.id !== id);
63
52
  });
64
53
  }
65
54
  set(item, options) {
66
- const value = this.map?.(item) ?? item;
67
55
  this.store.update((items) => {
68
56
  if (items === null || items instanceof Error)
69
57
  return [item];
70
- const index = items.findIndex((i) => i.id === value.id);
58
+ const index = items.findIndex((i) => i.id === item.id);
71
59
  if (index === -1)
72
- return options?.add === true ? [value, ...items] : items;
73
- items[index] = value;
74
- if (this.sort !== undefined && options?.sort !== false)
75
- items.sort(this.sort);
60
+ return options?.add === true ? [item, ...items] : items;
61
+ items[index] = item;
76
62
  return items;
77
63
  });
78
- if (options?.sync === false)
79
- return this.values?.get(value.id);
80
- else
81
- return this.values?.set(value.id, value, options);
82
- }
83
- preset(item) {
84
- this.set(item, { stash: true });
85
- }
86
- reset(id) {
87
- if (this.values === undefined)
88
- throw new Error('Collection: values is not defined');
89
- const value = this.values?.reset(id);
90
- if (value === null || value instanceof Error)
91
- return;
92
- this.set(value, { sync: false });
93
64
  }
94
65
  update(id, update, options) {
95
66
  if (this.values === undefined)
@@ -105,30 +76,35 @@ export class Collection {
105
76
  if (stale) {
106
77
  if (!this.stale)
107
78
  this.clear();
108
- this.refresh();
79
+ void this.refresh();
109
80
  }
110
81
  return this;
111
82
  }
83
+ async fetch() {
84
+ await this.refresh();
85
+ return this;
86
+ }
112
87
  replace(items) {
113
- const values = this.map === undefined ? items : items.map((item) => this.map(item));
88
+ const values = items;
114
89
  this.store.set(values);
115
90
  this.timestamp = Date.now();
116
91
  if (this.values !== undefined)
117
92
  for (const value of values)
118
93
  this.values.set(value.id, value);
119
94
  }
120
- refresh() {
121
- if (this.fetch === undefined)
95
+ async refresh() {
96
+ if (this.request === undefined)
122
97
  return;
123
- this.fetch().then((items) => {
124
- if (!(items instanceof Error))
125
- this.replace(items);
126
- else
127
- this.store.set(items);
128
- });
98
+ const items = await this.request();
99
+ if (!(items instanceof Error))
100
+ this.replace(items);
101
+ else
102
+ this.store.set(items);
129
103
  this.timestamp = Date.now();
130
104
  }
131
105
  persist(key) {
106
+ if (typeof window === 'undefined')
107
+ return;
132
108
  const stored = localStorage.getItem(key);
133
109
  if (stored !== null) {
134
110
  const items = JSON.parse(stored);
package/dist/having.d.ts CHANGED
@@ -1,7 +1,3 @@
1
1
  import type { Readable } from 'svelte/store';
2
2
  import type { Maybe } from './Maybe';
3
- /**
4
- * Execute a callback once the store has a non-null and non-error value.
5
- */
6
3
  export declare function having<T>(store: Readable<Maybe<T>>): Promise<T>;
7
- export declare function having<T>(store: Readable<Maybe<T>>, callback: (value: T) => unknown | Promise<unknown>): void;
package/dist/having.js CHANGED
@@ -1,22 +1,4 @@
1
- export function having(store, callback) {
2
- const promise = new Promise((resolve) => {
3
- let completed = false;
4
- let unsubscribe = null;
5
- unsubscribe = store.subscribe((value) => {
6
- if (value === null || value instanceof Error)
7
- return;
8
- // A
9
- unsubscribe?.();
10
- completed = true;
11
- resolve(value);
12
- });
13
- // B
14
- if (completed)
15
- unsubscribe?.();
16
- // the execution order of A and B is uncertain
17
- });
18
- if (callback === undefined)
19
- return promise;
20
- else
21
- promise.then(callback);
1
+ import { waitUntil } from './waitUntil';
2
+ export function having(store) {
3
+ return waitUntil(store, (value) => value !== null && !(value instanceof Error));
22
4
  }
package/dist/index.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  export { collection, type Collection } from './collection';
2
2
  export { values, type Values } from './values';
3
3
  export { value } from './value';
4
+ export { awaited } from './awaited';
4
5
  export { having } from './having';
5
6
  export { ensure } from './ensure';
6
7
  export { sync } from './sync';
package/dist/index.js CHANGED
@@ -1,6 +1,7 @@
1
1
  export { collection } from './collection';
2
2
  export { values } from './values';
3
3
  export { value } from './value';
4
+ export { awaited } from './awaited';
4
5
  export { having } from './having';
5
6
  export { ensure } from './ensure';
6
7
  export { sync } from './sync';
package/dist/sync.d.ts CHANGED
@@ -1,6 +1,5 @@
1
1
  import type { Collection, Identifiable, SetOptions } from './collection';
2
- export declare function sync<T extends Comparable, I = T>(input: Input<T, Parameters<Collection<T>['add']>[0], I>, collection: Collection<T>, options?: Options): void;
3
- type Input<T, M, Default> = M extends (arg: infer P) => T ? P : Default;
2
+ export declare function sync<T extends Comparable>(collection: Collection<T>, tobe: T, options?: Options): void;
4
3
  interface Comparable extends Identifiable {
5
4
  _version: number;
6
5
  _deleted?: number | null;
package/dist/sync.js CHANGED
@@ -1,5 +1,4 @@
1
- export function sync(input, collection, options) {
2
- const tobe = input;
1
+ export function sync(collection, tobe, options) {
3
2
  if (tobe._deleted !== null && tobe._deleted !== undefined) {
4
3
  collection.delete(tobe.id);
5
4
  return;
package/dist/value.d.ts CHANGED
@@ -1,11 +1,9 @@
1
1
  import { type Readable, type Subscriber, type Unsubscriber, type Updater, type Writable } from 'svelte/store';
2
- type Input<T, M, Default> = M extends (arg: infer P) => T ? P : Default;
3
2
  declare class Value<T> implements Writable<T | null> {
4
3
  private readonly store;
5
- private readonly map?;
6
4
  private readonly default;
7
5
  constructor(options: Options<T>);
8
- set<I = T>(value: Input<T, typeof this.map, I> | null): void;
6
+ set(value: T | null): void;
9
7
  update(updater: Updater<T | null>): void;
10
8
  subscribe(run: Subscriber<T | null>, invalidate?: () => void): Unsubscriber;
11
9
  extract(): T | null;
@@ -26,10 +24,6 @@ interface Options<T> {
26
24
  * Nullify values when the bound store is null.
27
25
  */
28
26
  bind?: Readable<unknown | null>;
29
- /**
30
- * Maps values on set.
31
- */
32
- map?: (item: any) => T;
33
27
  /**
34
28
  * Default value.
35
29
  */
package/dist/value.js CHANGED
@@ -1,34 +1,22 @@
1
1
  import { get, writable } from 'svelte/store';
2
- import { browser } from '$app/environment';
3
2
  class Value {
4
3
  store;
5
- map;
6
4
  default;
7
5
  constructor(options) {
8
- const persist = browser && options.persist !== undefined;
9
6
  this.default = options.default ?? null;
10
- this.store = persist
11
- ? persistent(options.persist, this.default, options.session)
12
- : writable(this.default);
13
- if (browser) {
14
- if (options.bind)
15
- this.bind(options.bind);
16
- if (options.map)
17
- this.map = options.map;
18
- }
7
+ this.store = options.persist === undefined || typeof window === 'undefined'
8
+ ? writable(this.default)
9
+ : persistent(options.persist, this.default, options.session);
10
+ if (options.bind)
11
+ this.bind(options.bind);
19
12
  }
20
13
  set(value) {
21
- if (value !== null && this.map)
22
- value = this.map(value);
23
14
  this.store.set(value);
24
15
  }
25
16
  update(updater) {
26
17
  this.store.update((value) => {
27
18
  const updated = updater(value);
28
- if (this.map)
29
- return this.map(updated);
30
- else
31
- return updated;
19
+ return updated;
32
20
  });
33
21
  }
34
22
  subscribe(run, invalidate) {
package/dist/values.d.ts CHANGED
@@ -4,7 +4,6 @@ declare class Values<T, E extends Error = Error> {
4
4
  readonly persistent: boolean;
5
5
  private readonly values;
6
6
  private readonly fetch;
7
- private readonly map;
8
7
  private readonly revalidate;
9
8
  private readonly permanent;
10
9
  private readonly stale;
@@ -12,7 +11,7 @@ declare class Values<T, E extends Error = Error> {
12
11
  private ready;
13
12
  private dumping;
14
13
  constructor(options: Options<T, E>);
15
- set<I = T>(key: string, item: Input<T, typeof this.map, I> | E, options?: SetOptions): Readable<T | E>;
14
+ set(key: string, item: T | E, options?: SetOptions): Readable<T | E>;
16
15
  /**
17
16
  * Restores persistent value.
18
17
  */
@@ -27,16 +26,11 @@ declare class Values<T, E extends Error = Error> {
27
26
  private load;
28
27
  private bind;
29
28
  }
30
- type Input<T, M, Default> = M extends (arg: infer P) => T ? P : Default;
31
29
  interface Options<T = unknown, E extends Error = Error> {
32
30
  /**
33
31
  * Fetches the value
34
32
  */
35
- get?: (key: string) => Promise<Exclude<any, Error> | E>;
36
- /**
37
- * Maps the fetched value
38
- */
39
- map?: (item: any) => T;
33
+ get?: (key: string) => Promise<T | E>;
40
34
  /**
41
35
  * Time in milliseconds before revalidating the value.
42
36
  * Default is 60 seconds.
package/dist/values.js CHANGED
@@ -1,10 +1,8 @@
1
- import { browser } from '$app/environment';
2
1
  import { get, writable } from 'svelte/store';
3
2
  class Values {
4
3
  persistent;
5
4
  values = {};
6
5
  fetch;
7
- map;
8
6
  revalidate;
9
7
  permanent;
10
8
  stale;
@@ -13,20 +11,17 @@ class Values {
13
11
  dumping = null;
14
12
  constructor(options) {
15
13
  this.fetch = options.get;
16
- this.map = options.map;
17
14
  this.revalidate = options.revalidate ?? DEFAULTS.revalidate;
18
15
  this.permanent = options.permanent ?? DEFAULTS.permanent;
19
16
  this.stale = options.stale ?? DEFAULTS.stale;
20
17
  this.persist = options.persist;
21
18
  this.persistent = this.persist !== undefined;
22
- if (browser) {
23
- this.load();
24
- if (options.bind !== undefined)
25
- this.bind(options.bind);
26
- }
19
+ this.load();
20
+ if (options.bind !== undefined)
21
+ this.bind(options.bind);
27
22
  }
28
23
  set(key, item, options) {
29
- const value = this.map?.(item) ?? item;
24
+ const value = item;
30
25
  const entry = this.values[key] ?? (this.values[key] = this.create(value));
31
26
  if (options?.stash === true)
32
27
  this.stash(key);
@@ -100,7 +95,7 @@ class Values {
100
95
  entry.stash ??= get(store);
101
96
  }
102
97
  dump(delay = true) {
103
- if (this.persist === undefined || !browser)
98
+ if (this.persist === undefined || typeof window === 'undefined')
104
99
  return;
105
100
  if (delay) {
106
101
  this.dumping ??= setTimeout(() => this.dump(false), DUMP_GAP);
@@ -120,7 +115,7 @@ class Values {
120
115
  localStorage.setItem(this.persist, JSON.stringify(data));
121
116
  }
122
117
  load() {
123
- if (this.persist === undefined)
118
+ if (this.persist === undefined || typeof window === 'undefined')
124
119
  return;
125
120
  const data = localStorage.getItem(this.persist);
126
121
  if (data === null)
@@ -0,0 +1,2 @@
1
+ import type { Readable } from "svelte/store";
2
+ export declare function waitUntil<T>(store: Readable<T>, condition: (value: T) => boolean): Promise<T>;
@@ -0,0 +1,16 @@
1
+ export function waitUntil(store, condition) {
2
+ const promise = new Promise((resolve) => {
3
+ let completed = false;
4
+ let unsubscribe = null;
5
+ unsubscribe = store.subscribe((value) => {
6
+ if (!condition(value))
7
+ return;
8
+ unsubscribe?.();
9
+ completed = true;
10
+ resolve(value);
11
+ });
12
+ if (completed)
13
+ unsubscribe?.();
14
+ });
15
+ return promise;
16
+ }
package/package.json CHANGED
@@ -1,6 +1,7 @@
1
1
  {
2
2
  "name": "svas",
3
- "version": "0.1.9",
3
+ "version": "1.1.0",
4
+ "repository": "https://github.com/temich/svas",
4
5
  "scripts": {
5
6
  "dev": "vite dev",
6
7
  "build": "vite build && npm run prepack",
@@ -9,16 +10,14 @@
9
10
  "prepack": "svelte-kit sync && svelte-package && publint",
10
11
  "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
11
12
  "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
12
- "lint": "eslint ."
13
+ "lint": "eslint .",
14
+ "bump": "npx -y npm-check-updates --target minor -u"
13
15
  },
14
16
  "files": [
15
17
  "dist",
16
18
  "!dist/**/*.test.*",
17
19
  "!dist/**/*.spec.*"
18
20
  ],
19
- "sideEffects": [
20
- "**/*.css"
21
- ],
22
21
  "svelte": "./dist/index.js",
23
22
  "types": "./dist/index.d.ts",
24
23
  "type": "module",
@@ -30,27 +29,31 @@
30
29
  },
31
30
  "peerDependencies": {
32
31
  "@lucide/svelte": "*",
33
- "svelte": "^5.0.0",
34
- "@sveltejs/kit": "*"
32
+ "@sveltejs/kit": "*",
33
+ "svelte": "^5.0.0"
35
34
  },
36
35
  "devDependencies": {
37
- "@eslint/compat": "^1.2.9",
38
- "@eslint/js": "^9.18.0",
39
- "@sveltejs/adapter-auto": "^6.0.0",
40
- "@sveltejs/kit": "^2.16.0",
41
- "@sveltejs/package": "^2.0.0",
42
- "@sveltejs/vite-plugin-svelte": "^5.0.0",
43
- "autoprefixer": "^10.4.20",
44
- "eslint": "^9.18.0",
45
- "eslint-plugin-svelte": "^3.0.0",
46
- "globals": "^16.0.0",
47
- "publint": "^0.3.2",
48
- "svelte": "^5.0.0",
49
- "svelte-check": "^4.0.0",
50
- "tailwindcss": "^3.4.17",
51
- "typescript": "^5.0.0",
52
- "typescript-eslint": "^8.20.0",
53
- "vite": "^6.2.6"
36
+ "@eslint/compat": "^2.0.0",
37
+ "@eslint/js": "^9.39.1",
38
+ "@semantic-release/changelog": "^6.0.3",
39
+ "@semantic-release/commit-analyzer": "^13.0.1",
40
+ "@semantic-release/git": "^10.0.1",
41
+ "@semantic-release/github": "^12.0.2",
42
+ "@semantic-release/npm": "^13.1.2",
43
+ "@semantic-release/release-notes-generator": "^14.1.0",
44
+ "@sveltejs/adapter-auto": "^7.0.0",
45
+ "@sveltejs/kit": "^2.49.2",
46
+ "@sveltejs/package": "^2.5.7",
47
+ "@sveltejs/vite-plugin-svelte": "^6.2.1",
48
+ "eslint": "^9.39.1",
49
+ "eslint-plugin-svelte": "^3.13.1",
50
+ "globals": "^16.5.0",
51
+ "publint": "^0.3.15",
52
+ "svelte": "^5.45.8",
53
+ "svelte-check": "^4.3.4",
54
+ "typescript": "^5.9.3",
55
+ "typescript-eslint": "^8.49.0",
56
+ "vite": "^7.2.7"
54
57
  },
55
58
  "keywords": [
56
59
  "svelte"