shelving 1.51.3 → 1.53.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/db/Database.js CHANGED
@@ -168,9 +168,9 @@ export class DatabaseQuery extends Query {
168
168
  }
169
169
  /** Get the data for a document from a result for that document. */
170
170
  export function getQueryData(entries, ref) {
171
- const first = getFirstItem(entries);
172
- if (first)
173
- return getDocumentData(first[1], ref.doc(first[0]));
171
+ const data = getQueryResult(entries, ref);
172
+ if (data)
173
+ return data;
174
174
  throw new QueryRequiredError(ref);
175
175
  }
176
176
  /** Get the data for a document from a result for that document. */
@@ -178,7 +178,7 @@ export function getQueryResult(entries, ref) {
178
178
  const first = getFirstItem(entries);
179
179
  if (first)
180
180
  return getDocumentData(first[1], ref.doc(first[0]));
181
- throw new QueryRequiredError(ref);
181
+ return null;
182
182
  }
183
183
  /** A document reference within a specific database. */
184
184
  export class DatabaseDocument {
package/db/errors.d.ts CHANGED
@@ -7,16 +7,16 @@ export declare class DocumentRequiredError<T extends Data> extends RequiredError
7
7
  ref: DatabaseDocument<T>;
8
8
  constructor(ref: DatabaseDocument<T>);
9
9
  }
10
- /** Thrown if a query doesn't exist. */
11
- export declare class QueryRequiredError<T extends Data> extends RequiredError {
12
- ref: DatabaseQuery<T>;
13
- constructor(ref: DatabaseQuery<T>);
14
- }
15
10
  /** Thrown if a document can't validate. */
16
11
  export declare class DocumentValidationError<T extends Data> extends ValidationError {
17
12
  ref: DatabaseDocument<T>;
18
13
  constructor(ref: DatabaseDocument<T>, feedback: Feedback);
19
14
  }
15
+ /** Thrown if a query doesn't exist. */
16
+ export declare class QueryRequiredError<T extends Data> extends RequiredError {
17
+ ref: DatabaseQuery<T>;
18
+ constructor(ref: DatabaseQuery<T>);
19
+ }
20
20
  /** Thrown if a query can't validate a set of results. */
21
21
  export declare class QueryValidationError<T extends Data> extends ValidationError {
22
22
  ref: DatabaseQuery<T>;
package/db/errors.js CHANGED
@@ -2,27 +2,27 @@ import { RequiredError, ValidationError } from "../error/index.js";
2
2
  /** Thrown if a document doesn't exist. */
3
3
  export class DocumentRequiredError extends RequiredError {
4
4
  constructor(ref) {
5
- super(`Document "${ref.toString()}" does not exist`);
5
+ super(`Document ${ref.toString()} does not exist`);
6
6
  this.ref = ref;
7
7
  }
8
8
  }
9
9
  DocumentRequiredError.prototype.name = "DocumentRequiredError";
10
- /** Thrown if a query doesn't exist. */
11
- export class QueryRequiredError extends RequiredError {
12
- constructor(ref) {
13
- super(`Query "${ref.toString()}" has no results`);
14
- this.ref = ref;
15
- }
16
- }
17
- QueryRequiredError.prototype.name = "QueryRequiredError";
18
10
  /** Thrown if a document can't validate. */
19
11
  export class DocumentValidationError extends ValidationError {
20
12
  constructor(ref, feedback) {
21
- super(`Invalid data for "${ref.toString()}"`, feedback);
13
+ super(`Invalid data for ${ref.toString()}`, feedback);
22
14
  this.ref = ref;
23
15
  }
24
16
  }
25
17
  DocumentValidationError.prototype.name = "DocumentValidationError";
18
+ /** Thrown if a query doesn't exist. */
19
+ export class QueryRequiredError extends RequiredError {
20
+ constructor(ref) {
21
+ super(`Query ${ref.toString()} has no results`);
22
+ this.ref = ref;
23
+ }
24
+ }
25
+ QueryRequiredError.prototype.name = "QueryRequiredError";
26
26
  /** Thrown if a query can't validate a set of results. */
27
27
  export class QueryValidationError extends ValidationError {
28
28
  constructor(ref, feedback) {
package/markup/rules.d.ts CHANGED
@@ -38,7 +38,7 @@ export declare const FENCED_CODE_RULE: MarkupRule;
38
38
  export declare const PARAGRAPH_RULE: MarkupRule;
39
39
  /**
40
40
  * Markdown-style link.
41
- * - Link in standard Markdown format, e.g. `[http://google.com/maps](Google Maps)`
41
+ * - Link in standard Markdown format, e.g. `[Google Maps](http://google.com/maps)`
42
42
  * - If no title is specified a cleaned up version of the URL will be used, e.g. `google.com/maps`
43
43
  * - Does not need space before/after the link.
44
44
  * - If link is not valid (using `new URL(url)` then unparsed text will be returned.
@@ -46,11 +46,11 @@ export declare const PARAGRAPH_RULE: MarkupRule;
46
46
  */
47
47
  export declare const LINK_RULE: MarkupRule;
48
48
  /**
49
- * Autolinked URL starts with `http:` or `https:` and matches an unlimited number of non-space characters.
49
+ * Autolinked URL starts with `http:` or `https:` or `mailto:` (any scheme in `options.schemes`) and matches an unlimited number of non-space characters.
50
50
  * - If followed by space and then text in `()` round or `[]` square brackets that will be used as the title, e.g. `http://google.com/maps (Google Maps)` or `http://google.com/maps [Google Maps]` (this syntax is from Todoist and maybe other things too).
51
51
  * - If no title is specified a cleaned up version of the URL will be used, e.g. `google.com/maps`
52
52
  * - If link is not valid (using `new URL(url)` then unparsed text will be returned.
53
- * - For security only schemes that appear in the `options.schemes` will match (defaults to `http:` and `https:`).
53
+ * - For security only schemes that appear in `options.schemes` will match (defaults to `http:` and `https:`).
54
54
  */
55
55
  export declare const AUTOLINK_RULE: MarkupRule;
56
56
  /**
package/markup/rules.js CHANGED
@@ -127,58 +127,62 @@ export const PARAGRAPH_RULE = {
127
127
  };
128
128
  /**
129
129
  * Markdown-style link.
130
- * - Link in standard Markdown format, e.g. `[http://google.com/maps](Google Maps)`
130
+ * - Link in standard Markdown format, e.g. `[Google Maps](http://google.com/maps)`
131
131
  * - If no title is specified a cleaned up version of the URL will be used, e.g. `google.com/maps`
132
132
  * - Does not need space before/after the link.
133
133
  * - If link is not valid (using `new URL(url)` then unparsed text will be returned.
134
134
  * - For security only `http://` or `https://` links will work (if invalid the unparsed text will be returned).
135
135
  */
136
136
  export const LINK_RULE = {
137
- // Custom matcher to check the URL against the allowed schemes.
138
137
  regexp: /\[([^\]]*?)\]\(([^)]*?)\)/,
138
+ // Custom matcher to check the URL against the allowed schemes.
139
139
  match: (content, { schemes, url: base }) => {
140
140
  const matches = content.match(LINK_RULE.regexp);
141
- if (matches && typeof matches.index === "number") {
141
+ if (matches) {
142
142
  const [, title = "", href = ""] = matches;
143
143
  const url = toURL(href, base);
144
144
  if (url && url.protocol && schemes.includes(url.protocol)) {
145
145
  matches[1] = title.trim();
146
- matches[2] = url.href; // Use fixed URL from `new URL`
146
+ matches[2] = url.href;
147
147
  return matches;
148
148
  }
149
149
  }
150
150
  },
151
- render: ([, title = "", href = ""], { rel }) => ({
152
- type: href ? "a" : "span",
151
+ render: ([, title, href = ""], { rel }) => ({
152
+ type: "a",
153
153
  key: null,
154
- props: { children: title || formatUrl(href), href: href || undefined, rel },
154
+ props: { children: title || formatUrl(href), href, rel },
155
155
  }),
156
156
  contexts: ["inline", "list"],
157
157
  childContext: "link",
158
158
  };
159
159
  /**
160
- * Autolinked URL starts with `http:` or `https:` and matches an unlimited number of non-space characters.
160
+ * Autolinked URL starts with `http:` or `https:` or `mailto:` (any scheme in `options.schemes`) and matches an unlimited number of non-space characters.
161
161
  * - If followed by space and then text in `()` round or `[]` square brackets that will be used as the title, e.g. `http://google.com/maps (Google Maps)` or `http://google.com/maps [Google Maps]` (this syntax is from Todoist and maybe other things too).
162
162
  * - If no title is specified a cleaned up version of the URL will be used, e.g. `google.com/maps`
163
163
  * - If link is not valid (using `new URL(url)` then unparsed text will be returned.
164
- * - For security only schemes that appear in the `options.schemes` will match (defaults to `http:` and `https:`).
164
+ * - For security only schemes that appear in `options.schemes` will match (defaults to `http:` and `https:`).
165
165
  */
166
166
  export const AUTOLINK_RULE = {
167
+ regexp: /([a-z]+:\S+)(?: +(?:\(([^)]*?)\)|\[([^\]]*?)\]))?/,
167
168
  // Custom matcher to check the URL against the allowed schemes.
168
- regexp: /([a-zA-Z][a-zA-Z0-9-]*[a-zA-Z0-9]:\S+)(?: +(?:\(([^)]*?)\)|\[([^\]]*?)\]))?/,
169
169
  match: (content, { schemes, url: base }) => {
170
170
  const matches = content.match(AUTOLINK_RULE.regexp);
171
171
  if (matches && typeof matches.index === "number") {
172
- const [, href = "", title1 = "", title2 = ""] = matches;
172
+ const [, href = "", roundTitle = "", squareTitle = ""] = matches;
173
173
  const url = toURL(href, base);
174
174
  if (url && url.protocol && schemes.includes(url.protocol)) {
175
- matches[1] = (title1 || title2).trim();
176
- matches[2] = url.href;
175
+ matches[1] = url.href;
176
+ matches[2] = (roundTitle || squareTitle).trim();
177
177
  return matches;
178
178
  }
179
179
  }
180
180
  },
181
- render: LINK_RULE.render,
181
+ render: ([, href = "", title], { rel }) => ({
182
+ type: "a",
183
+ key: null,
184
+ props: { children: title || formatUrl(href), href, rel },
185
+ }),
182
186
  contexts: ["inline", "list"],
183
187
  childContext: "link",
184
188
  };
package/package.json CHANGED
@@ -11,7 +11,7 @@
11
11
  "state-management",
12
12
  "query-builder"
13
13
  ],
14
- "version": "1.51.3",
14
+ "version": "1.53.0",
15
15
  "repository": "https://github.com/dhoulb/shelving",
16
16
  "author": "Dave Houlbrooke <dave@shax.com>",
17
17
  "license": "0BSD",
@@ -63,13 +63,13 @@
63
63
  "@types/jest": "^27.4.0",
64
64
  "@types/react": "^17.0.39",
65
65
  "@types/react-dom": "^17.0.11",
66
- "@typescript-eslint/eslint-plugin": "^5.11.0",
67
- "@typescript-eslint/parser": "^5.11.0",
66
+ "@typescript-eslint/eslint-plugin": "^5.12.0",
67
+ "@typescript-eslint/parser": "^5.12.0",
68
68
  "eslint": "^8.9.0",
69
- "eslint-config-prettier": "^8.3.0",
69
+ "eslint-config-prettier": "^8.4.0",
70
70
  "eslint-plugin-import": "^2.25.4",
71
71
  "eslint-plugin-prettier": "^4.0.0",
72
- "firebase": "^9.6.6",
72
+ "firebase": "^9.6.7",
73
73
  "jest": "^27.5.1",
74
74
  "jest-ts-webcompat-resolver": "^1.0.0",
75
75
  "prettier": "^2.5.1",
@@ -0,0 +1,32 @@
1
+ import { DatabaseDocument, DatabaseQuery } from "../db/Database.js";
2
+ import { Update } from "../update/Update.js";
3
+ import { Data, Result } from "../util/data.js";
4
+ import { Entries } from "../util/entry.js";
5
+ import { Observer, Unsubscriber } from "../util/observable.js";
6
+ import { ThroughProvider } from "./ThroughProvider.js";
7
+ /** Provider that wraps errors thrown from deeper providers in `DatabaseReadError` and `DatabaseWriteError` etc to make it easier to see what read/write caused the error. */
8
+ export declare class ErrorProvider extends ThroughProvider {
9
+ get<T extends Data>(ref: DatabaseDocument<T>): Result<T> | PromiseLike<Result<T>>;
10
+ subscribe<T extends Data>(ref: DatabaseDocument<T>, observer: Observer<Result<T>>): Unsubscriber;
11
+ add<T extends Data>(ref: DatabaseQuery<T>, data: T): string | PromiseLike<string>;
12
+ set<T extends Data>(ref: DatabaseDocument<T>, data: T): void | PromiseLike<void>;
13
+ update<T extends Data>(ref: DatabaseDocument<T>, updates: Update<T>): void | PromiseLike<void>;
14
+ delete<T extends Data>(ref: DatabaseDocument<T>): void | PromiseLike<void>;
15
+ getQuery<T extends Data>(ref: DatabaseQuery<T>): Entries<T> | PromiseLike<Entries<T>>;
16
+ subscribeQuery<T extends Data>(ref: DatabaseQuery<T>, observer: Observer<Entries<T>>): Unsubscriber;
17
+ setQuery<T extends Data>(ref: DatabaseQuery<T>, data: T): number | PromiseLike<number>;
18
+ updateQuery<T extends Data>(ref: DatabaseQuery<T>, updates: Update<T>): number | PromiseLike<number>;
19
+ deleteQuery<T extends Data>(ref: DatabaseQuery<T>): number | PromiseLike<number>;
20
+ }
21
+ /** Thrown if an error occurs while reading a query. */
22
+ export declare class DatabaseReadError<T extends Data> extends Error {
23
+ readonly error: Error;
24
+ readonly ref: DatabaseDocument<T> | DatabaseQuery<T>;
25
+ constructor(error: Error, ref: DatabaseDocument<T> | DatabaseQuery<T>);
26
+ }
27
+ /** Thrown if an error occurs while writing a document. */
28
+ export declare class DatabaseWriteError<T extends Data> extends Error {
29
+ readonly error: Error;
30
+ readonly ref: DatabaseDocument<T> | DatabaseQuery<T>;
31
+ constructor(error: Error, ref: DatabaseDocument<T> | DatabaseQuery<T>);
32
+ }
@@ -0,0 +1,175 @@
1
+ import { isAsync } from "../index.js";
2
+ import { ThroughObserver } from "../util/observable.js";
3
+ import { ThroughProvider } from "./ThroughProvider.js";
4
+ /** Provider that wraps errors thrown from deeper providers in `DatabaseReadError` and `DatabaseWriteError` etc to make it easier to see what read/write caused the error. */
5
+ export class ErrorProvider extends ThroughProvider {
6
+ get(ref) {
7
+ try {
8
+ const result = super.get(ref);
9
+ return isAsync(result)
10
+ ? result.then(undefined, err => {
11
+ throw err instanceof Error ? new DatabaseReadError(err, ref) : err;
12
+ })
13
+ : result;
14
+ }
15
+ catch (err) {
16
+ if (err instanceof Error)
17
+ throw new DatabaseReadError(err, ref);
18
+ throw err;
19
+ }
20
+ }
21
+ subscribe(ref, observer) {
22
+ return super.subscribe(ref, new DatabaseErrorObserver(ref, observer));
23
+ }
24
+ add(ref, data) {
25
+ try {
26
+ const result = super.add(ref, data);
27
+ return isAsync(result)
28
+ ? result.then(undefined, err => {
29
+ throw err instanceof Error ? new DatabaseWriteError(err, ref) : err;
30
+ })
31
+ : result;
32
+ }
33
+ catch (err) {
34
+ if (err instanceof Error)
35
+ throw new DatabaseWriteError(err, ref);
36
+ throw err;
37
+ }
38
+ }
39
+ set(ref, data) {
40
+ try {
41
+ const result = super.set(ref, data);
42
+ return isAsync(result)
43
+ ? result.then(undefined, err => {
44
+ throw err instanceof Error ? new DatabaseWriteError(err, ref) : err;
45
+ })
46
+ : result;
47
+ }
48
+ catch (err) {
49
+ if (err instanceof Error)
50
+ throw new DatabaseWriteError(err, ref);
51
+ throw err;
52
+ }
53
+ }
54
+ update(ref, updates) {
55
+ try {
56
+ const result = super.update(ref, updates);
57
+ return isAsync(result)
58
+ ? result.then(undefined, err => {
59
+ throw err instanceof Error ? new DatabaseWriteError(err, ref) : err;
60
+ })
61
+ : result;
62
+ }
63
+ catch (err) {
64
+ if (err instanceof Error)
65
+ throw new DatabaseWriteError(err, ref);
66
+ throw err;
67
+ }
68
+ }
69
+ delete(ref) {
70
+ try {
71
+ const result = super.delete(ref);
72
+ return isAsync(result)
73
+ ? result.then(undefined, err => {
74
+ throw err instanceof Error ? new DatabaseWriteError(err, ref) : err;
75
+ })
76
+ : result;
77
+ }
78
+ catch (err) {
79
+ if (err instanceof Error)
80
+ throw new DatabaseWriteError(err, ref);
81
+ throw err;
82
+ }
83
+ }
84
+ getQuery(ref) {
85
+ try {
86
+ const results = super.getQuery(ref);
87
+ return isAsync(results)
88
+ ? results.then(undefined, err => {
89
+ throw err instanceof Error ? new DatabaseReadError(err, ref) : err;
90
+ })
91
+ : results;
92
+ }
93
+ catch (err) {
94
+ if (err instanceof Error)
95
+ throw new DatabaseReadError(err, ref);
96
+ throw err;
97
+ }
98
+ }
99
+ subscribeQuery(ref, observer) {
100
+ return super.subscribeQuery(ref, new DatabaseErrorObserver(ref, observer));
101
+ }
102
+ setQuery(ref, data) {
103
+ try {
104
+ const result = super.setQuery(ref, data);
105
+ return isAsync(result)
106
+ ? result.then(undefined, err => {
107
+ throw err instanceof Error ? new DatabaseWriteError(err, ref) : err;
108
+ })
109
+ : result;
110
+ }
111
+ catch (err) {
112
+ if (err instanceof Error)
113
+ throw new DatabaseWriteError(err, ref);
114
+ throw err;
115
+ }
116
+ }
117
+ updateQuery(ref, updates) {
118
+ try {
119
+ const result = super.updateQuery(ref, updates);
120
+ return isAsync(result)
121
+ ? result.then(undefined, err => {
122
+ throw err instanceof Error ? new DatabaseWriteError(err, ref) : err;
123
+ })
124
+ : result;
125
+ }
126
+ catch (err) {
127
+ if (err instanceof Error)
128
+ throw new DatabaseWriteError(err, ref);
129
+ throw err;
130
+ }
131
+ }
132
+ deleteQuery(ref) {
133
+ try {
134
+ const result = super.deleteQuery(ref);
135
+ return isAsync(result)
136
+ ? result.then(undefined, err => {
137
+ throw err instanceof Error ? new DatabaseWriteError(err, ref) : err;
138
+ })
139
+ : result;
140
+ }
141
+ catch (err) {
142
+ if (err instanceof Error)
143
+ throw new DatabaseWriteError(err, ref);
144
+ throw err;
145
+ }
146
+ }
147
+ }
148
+ /** Thrown if an error occurs while reading a query. */
149
+ export class DatabaseReadError extends Error {
150
+ constructor(error, ref) {
151
+ super(`Error reading ${ref.toString()}:\n${error.message}`);
152
+ this.error = error;
153
+ this.ref = ref;
154
+ }
155
+ }
156
+ DatabaseReadError.prototype.name = "DatabaseReadError";
157
+ /** Thrown if an error occurs while writing a document. */
158
+ export class DatabaseWriteError extends Error {
159
+ constructor(error, ref) {
160
+ super(`Error writing ${ref.toString()}:\n${error.message}`);
161
+ this.error = error;
162
+ this.ref = ref;
163
+ }
164
+ }
165
+ DatabaseWriteError.prototype.name = "DocumentWriteError";
166
+ /** Observer that wraps errors in subscriptions in `DatabaseReadError` */
167
+ class DatabaseErrorObserver extends ThroughObserver {
168
+ constructor(ref, target) {
169
+ super(target);
170
+ this.ref = ref;
171
+ }
172
+ error(error) {
173
+ super.error(error instanceof Error ? new DatabaseReadError(error, this.ref) : error);
174
+ }
175
+ }
@@ -40,7 +40,7 @@ export declare abstract class Provider {
40
40
  *
41
41
  * @throws Error If a `Update` was provided but the document does not exist (ideally a `RequiredError` but may be provider-specific).
42
42
  */
43
- abstract set<T extends Data>(ref: DatabaseDocument<T>, value: T): void | PromiseLike<void>;
43
+ abstract set<T extends Data>(ref: DatabaseDocument<T>, data: T): void | PromiseLike<void>;
44
44
  /**
45
45
  * Update the data an existing document.
46
46
  *
@@ -4,3 +4,4 @@ export * from "./BatchProvider.js";
4
4
  export * from "./MemoryProvider.js";
5
5
  export * from "./ValidationProvider.js";
6
6
  export * from "./CacheProvider.js";
7
+ export * from "./ErrorProvider.js";
package/provider/index.js CHANGED
@@ -4,3 +4,4 @@ export * from "./BatchProvider.js";
4
4
  export * from "./MemoryProvider.js";
5
5
  export * from "./ValidationProvider.js";
6
6
  export * from "./CacheProvider.js";
7
+ export * from "./ErrorProvider.js";
package/query/Query.js CHANGED
@@ -70,6 +70,6 @@ export class Query extends Rule {
70
70
  }
71
71
  // Implement toString()
72
72
  toString() {
73
- return `${this.filters}&${this.sorts}${this.limit ? `&LIMIT=${this.limit}` : ""}`;
73
+ return `filters=${this.filters}&sorts=${this.sorts}&limit={this.limit || ""}`;
74
74
  }
75
75
  }
package/query/Rules.js CHANGED
@@ -19,7 +19,7 @@ export class Rules extends Rule {
19
19
  return this._rules.length;
20
20
  }
21
21
  toString() {
22
- return this._rules.map(toString).join("&");
22
+ return this._rules.map(toString).join(",");
23
23
  }
24
24
  /** Clone this set of rules but add additional rules. */
25
25
  with(...rules) {
@@ -1,5 +1,5 @@
1
1
  import { useState } from "react";
2
- import { CacheProvider, throwAsync, NOERROR, findSourceProvider, NOVALUE, callAsync, getDocumentData } from "../index.js";
2
+ import { CacheProvider, throwAsync, NOERROR, findSourceProvider, NOVALUE, callAsync, getDocumentData, isAsync } from "../index.js";
3
3
  import { usePureEffect } from "./usePureEffect.js";
4
4
  import { usePureMemo } from "./usePureMemo.js";
5
5
  import { usePureState } from "./usePureState.js";
@@ -9,13 +9,14 @@ export function useAsyncDocument(ref, maxAge = 1000) {
9
9
  // Create two states to hold the value and error.
10
10
  const [value, setNext] = usePureState(getCachedResult, memoRef);
11
11
  const [error, setError] = useState(NOERROR);
12
- if (error !== NOERROR)
13
- throw error; // If there's an error throw it.
14
12
  // Register effect.
15
13
  usePureEffect(subscribeEffect, memoRef, maxAge, setNext, setError);
16
14
  // Always return undefined if there's no ref.
17
15
  if (!ref)
18
16
  return undefined;
17
+ // If there's an error throw it.
18
+ if (error !== NOERROR)
19
+ throw error;
19
20
  // If document is cached return the cached value.
20
21
  if (value !== NOVALUE)
21
22
  return value;
@@ -24,7 +25,10 @@ export function useAsyncDocument(ref, maxAge = 1000) {
24
25
  if (maxAge === true)
25
26
  setTimeout(ref.subscribe({ next: setNext, error: setError }), 10000);
26
27
  // Return a promise for the result.
27
- return ref.result;
28
+ const result = ref.result;
29
+ if (isAsync(result))
30
+ result.then(setNext, setError);
31
+ return result;
28
32
  }
29
33
  /** Get the initial result for a reference from the cache. */
30
34
  function getCachedResult(ref) {
@@ -34,22 +38,30 @@ function getCachedResult(ref) {
34
38
  return provider.isCached(ref) ? provider.cache.get(ref) : NOVALUE;
35
39
  }
36
40
  /** Effect that subscribes a component to the cache for a reference. */
37
- function subscribeEffect(ref, maxAge, next, error) {
41
+ function subscribeEffect(ref, maxAge, setNext, setError) {
38
42
  if (ref) {
39
43
  const provider = findSourceProvider(ref.db.provider, CacheProvider);
40
- const stopCache = provider.cache.subscribe(ref, { next, error });
44
+ const stopCache = provider.cache.subscribe(ref, { next: setNext, error: setError });
41
45
  if (maxAge === true) {
42
46
  // If `maxAge` is true subscribe to the source for as long as this component is attached.
43
- const stopSource = ref.subscribe({ next, error });
47
+ const stopSource = ref.subscribe({ next: setNext, error: setError });
44
48
  return () => {
45
49
  stopCache();
46
50
  stopSource();
47
51
  };
48
52
  }
49
- else {
53
+ else if (provider.getCachedAge(ref) > maxAge) {
50
54
  // If cache provider's cached document is older than maxAge then force refresh the data.
51
- if (provider.getCachedAge(ref) > maxAge)
52
- Promise.resolve(ref.result).then(next, error);
55
+ try {
56
+ const result = ref.result;
57
+ if (isAsync(result))
58
+ result.then(setNext, setError);
59
+ else
60
+ setNext(result);
61
+ }
62
+ catch (e) {
63
+ setError(e);
64
+ }
53
65
  }
54
66
  return stopCache;
55
67
  }
package/react/useQuery.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { useState } from "react";
2
- import { CacheProvider, NOERROR, findSourceProvider, NOVALUE, getMap, callAsync, getQueryData, throwAsync, ResultsObserver, getQueryResult, } from "../index.js";
2
+ import { CacheProvider, NOERROR, findSourceProvider, NOVALUE, getMap, callAsync, getQueryData, throwAsync, ResultsObserver, getQueryResult, isAsync, } from "../index.js";
3
3
  import { usePureEffect } from "./usePureEffect.js";
4
4
  import { usePureMemo } from "./usePureMemo.js";
5
5
  import { usePureState } from "./usePureState.js";
@@ -24,7 +24,10 @@ export function useAsyncQuery(ref, maxAge = 1000) {
24
24
  if (maxAge === true)
25
25
  setTimeout(ref.subscribe({ next: setNext, error: setError }), 10000);
26
26
  // Return a promise for the result.
27
- return ref.results;
27
+ const results = ref.results;
28
+ if (isAsync(results))
29
+ results.then(setNext, setError);
30
+ return results;
28
31
  }
29
32
  /** Get the initial results for a reference from the cache. */
30
33
  function getCachedResults(ref) {
@@ -34,10 +37,10 @@ function getCachedResults(ref) {
34
37
  return provider.isCached(ref) ? getMap(provider.cache.getQuery(ref)) : NOVALUE;
35
38
  }
36
39
  /** Effect that subscribes a component to the cache for a reference. */
37
- function subscribeEffect(ref, maxAge, next, error) {
40
+ function subscribeEffect(ref, maxAge, setNext, setError) {
38
41
  if (ref) {
39
42
  const provider = findSourceProvider(ref.db.provider, CacheProvider);
40
- const observer = new ResultsObserver({ next, error });
43
+ const observer = new ResultsObserver({ next: setNext, error: setError });
41
44
  const stopCache = provider.cache.subscribeQuery(ref, observer);
42
45
  if (maxAge === true) {
43
46
  // If `maxAge` is true subscribe to the source for as long as this component is attached.
@@ -47,10 +50,19 @@ function subscribeEffect(ref, maxAge, next, error) {
47
50
  stopSource();
48
51
  };
49
52
  }
50
- else {
53
+ else if (provider.getCachedAge(ref) > maxAge) {
51
54
  // If cache provider's cached document is older than maxAge then force refresh the data.
52
- if (provider.getCachedAge(ref) > maxAge)
53
- Promise.resolve(ref.results).then(next, error);
55
+ Promise.resolve(ref.results).then(setNext, setError);
56
+ try {
57
+ const results = ref.results;
58
+ if (isAsync(results))
59
+ results.then(setNext, setError);
60
+ else
61
+ setNext(results);
62
+ }
63
+ catch (e) {
64
+ setError(e);
65
+ }
54
66
  }
55
67
  return stopCache;
56
68
  }
package/util/jsx.d.ts CHANGED
@@ -7,8 +7,8 @@ export declare type JSXProps = {
7
7
  readonly children?: JSXNode;
8
8
  };
9
9
  /** JSX element (similar to `React.ReactElement`) */
10
- export declare type JSXElement<P extends JSXProps = JSXProps, T extends string | JSXElementCreator<P> = string | JSXElementCreator<P>> = {
11
- type: T;
10
+ export declare type JSXElement<P extends JSXProps = JSXProps> = {
11
+ type: string | JSXElementCreator<P>;
12
12
  props: P;
13
13
  key: string | number | null;
14
14
  $$typeof?: symbol;