shelving 1.68.1 → 1.68.4

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.
Files changed (57) hide show
  1. package/feedback/Feedback.js +2 -2
  2. package/firestore/client/FirestoreClientProvider.d.ts +1 -1
  3. package/firestore/client/FirestoreClientProvider.js +13 -9
  4. package/firestore/lite/FirestoreLiteProvider.js +12 -8
  5. package/firestore/server/FirestoreServerProvider.d.ts +1 -1
  6. package/firestore/server/FirestoreServerProvider.js +7 -3
  7. package/markup/rules.js +18 -13
  8. package/package.json +1 -1
  9. package/provider/DebugProvider.js +29 -29
  10. package/provider/ThroughProvider.d.ts +4 -2
  11. package/provider/ThroughProvider.js +11 -3
  12. package/provider/ValidationProvider.js +2 -3
  13. package/react/useDocument.d.ts +2 -1
  14. package/react/useDocument.js +21 -19
  15. package/react/useQuery.d.ts +4 -2
  16. package/react/useQuery.js +39 -35
  17. package/schema/AllowSchema.js +4 -4
  18. package/schema/ArraySchema.js +3 -3
  19. package/schema/DateSchema.js +4 -4
  20. package/schema/NumberSchema.js +2 -2
  21. package/schema/SlugSchema.js +2 -2
  22. package/schema/ThroughSchema.d.ts +4 -2
  23. package/schema/ThroughSchema.js +10 -4
  24. package/update/ArrayUpdate.d.ts +2 -1
  25. package/update/ArrayUpdate.js +22 -3
  26. package/update/DataUpdate.d.ts +3 -2
  27. package/update/DataUpdate.js +42 -2
  28. package/update/Delete.d.ts +11 -0
  29. package/update/Delete.js +15 -0
  30. package/update/Increment.d.ts +5 -5
  31. package/update/Increment.js +5 -5
  32. package/update/ObjectUpdate.d.ts +8 -8
  33. package/update/ObjectUpdate.js +38 -18
  34. package/update/Update.d.ts +4 -1
  35. package/update/Update.js +6 -0
  36. package/update/hydrations.js +3 -1
  37. package/update/index.d.ts +2 -2
  38. package/update/index.js +2 -2
  39. package/util/color.d.ts +6 -2
  40. package/util/color.js +17 -11
  41. package/util/constants.d.ts +0 -2
  42. package/util/constants.js +0 -2
  43. package/util/data.d.ts +6 -6
  44. package/util/data.js +3 -3
  45. package/util/date.d.ts +5 -5
  46. package/util/date.js +19 -19
  47. package/util/jsx.d.ts +1 -0
  48. package/util/number.d.ts +3 -3
  49. package/util/number.js +5 -5
  50. package/util/search.js +2 -2
  51. package/util/string.d.ts +4 -4
  52. package/util/string.js +7 -7
  53. package/util/transform.js +2 -2
  54. package/util/validate.d.ts +9 -0
  55. package/util/validate.js +13 -2
  56. package/update/util.d.ts +0 -7
  57. package/update/util.js +0 -44
@@ -1,5 +1,5 @@
1
1
  import { debug } from "../util/debug.js";
2
- import { toTitle } from "../util/string.js";
2
+ import { getTitle } from "../util/string.js";
3
3
  /**
4
4
  * The `Feedback` class represents a feedback message that should be shown to the user.
5
5
  * - Basic `Feedback` is neither good nor bad, `SuccessFeedback` indicates good news, and `ErrorFeedback` indicates bad news.
@@ -27,7 +27,7 @@ export class Feedback {
27
27
  if (v instanceof Feedback)
28
28
  messages[k] = v.feedback;
29
29
  else
30
- messages[k] = toTitle(v);
30
+ messages[k] = getTitle(v);
31
31
  }
32
32
  return messages;
33
33
  }
@@ -2,9 +2,9 @@ import type { Firestore } from "firebase/firestore";
2
2
  import type { DocumentReference, QueryReference } from "../../db/Reference.js";
3
3
  import type { Data, Entities, OptionalEntity } from "../../util/data.js";
4
4
  import type { Unsubscribe } from "../../observe/Observable.js";
5
+ import { Observer } from "../../observe/Observer.js";
5
6
  import { AsynchronousProvider, Provider } from "../../provider/Provider.js";
6
7
  import { DataUpdate } from "../../update/DataUpdate.js";
7
- import { Observer } from "../../observe/Observer.js";
8
8
  /**
9
9
  * Firestore client database provider.
10
10
  * - Works with the Firebase JS SDK.
@@ -1,11 +1,13 @@
1
1
  import { orderBy as firestoreOrderBy, where as firestoreWhere, limit as firestoreLimit, increment as firestoreIncrement, arrayUnion as firestoreArrayUnion, arrayRemove as firestoreArrayRemove, deleteField as firestoreDeleteField, collection as firestoreCollection, doc as firestoreDocument, query as firestoreQuery, onSnapshot, addDoc, setDoc, updateDoc, deleteDoc, getDoc, getDocs, } from "firebase/firestore";
2
+ import { dispatchError, dispatchNext } from "../../observe/Observer.js";
2
3
  import { UnsupportedError } from "../../error/UnsupportedError.js";
3
4
  import { Provider } from "../../provider/Provider.js";
4
5
  import { ArrayUpdate } from "../../update/ArrayUpdate.js";
5
6
  import { DataUpdate } from "../../update/DataUpdate.js";
6
7
  import { Increment } from "../../update/Increment.js";
7
8
  import { ObjectUpdate } from "../../update/ObjectUpdate.js";
8
- import { dispatchError, dispatchNext } from "../../observe/Observer.js";
9
+ import { Delete } from "../../update/Delete.js";
10
+ import { Update } from "../../update/Update.js";
9
11
  // Constants.
10
12
  // const ID = "__name__"; // DH: `__name__` is the entire path of the document. `__id__` is just ID.
11
13
  const ID = "__id__"; // Internal way Firestore Queries can reference the ID of the current document.
@@ -36,15 +38,15 @@ function getCollection(firestore, { collection }) {
36
38
  }
37
39
  /** Create a corresponding `QueryReference` from a Query. */
38
40
  function getQuery(firestore, ref) {
39
- const { sorts, filters, limit } = ref;
40
- const constraints = [];
41
+ return firestoreQuery(getCollection(firestore, ref), ...yieldQueryConstraints(ref));
42
+ }
43
+ function* yieldQueryConstraints({ sorts, filters, limit }) {
41
44
  for (const { key, direction } of sorts)
42
- constraints.push(firestoreOrderBy(key === "id" ? ID : key, DIRECTIONS[direction]));
45
+ yield firestoreOrderBy(key === "id" ? ID : key, DIRECTIONS[direction]);
43
46
  for (const { operator, key, value } of filters)
44
- constraints.push(firestoreWhere(key === "id" ? ID : key, OPERATORS[operator], value));
47
+ yield firestoreWhere(key === "id" ? ID : key, OPERATORS[operator], value);
45
48
  if (typeof limit === "number")
46
- constraints.push(firestoreLimit(limit));
47
- return firestoreQuery(getCollection(firestore, ref), ...constraints);
49
+ yield firestoreLimit(limit);
48
50
  }
49
51
  function getEntities(snapshot) {
50
52
  return snapshot.docs.map(getEntity);
@@ -60,7 +62,9 @@ function getOptionalEntity(snapshot) {
60
62
  /** Convert `Update` instances into corresponding Firestore `FieldValue` instances. */
61
63
  function* yieldFieldValues(updates, prefix = "") {
62
64
  for (const [key, update] of updates) {
63
- if (update === undefined)
65
+ if (!(update instanceof Update))
66
+ yield [`${prefix}${key}`, update];
67
+ else if (update instanceof Delete)
64
68
  yield [`${prefix}${key}`, firestoreDeleteField()];
65
69
  else if (update instanceof Increment)
66
70
  yield [`${prefix}${key}`, firestoreIncrement(update.amount)];
@@ -75,7 +79,7 @@ function* yieldFieldValues(updates, prefix = "") {
75
79
  yield [`${prefix}${key}`, firestoreArrayRemove(...update.deletes)];
76
80
  }
77
81
  else
78
- yield [`${prefix}${key}`, update];
82
+ yield [`${prefix}${key}`, update.transform()];
79
83
  }
80
84
  }
81
85
  /**
@@ -5,6 +5,8 @@ import { ArrayUpdate } from "../../update/ArrayUpdate.js";
5
5
  import { DataUpdate } from "../../update/DataUpdate.js";
6
6
  import { Increment } from "../../update/Increment.js";
7
7
  import { ObjectUpdate } from "../../update/ObjectUpdate.js";
8
+ import { Update } from "../../update/Update.js";
9
+ import { Delete } from "../../update/Delete.js";
8
10
  // Constants.
9
11
  // const ID = "__name__"; // DH: `__name__` is the entire path of the document. `__id__` is just ID.
10
12
  const ID = "__id__"; // Internal way Firestore Queries can reference the ID of the current document.
@@ -35,15 +37,15 @@ function getCollection(firestore, { collection }) {
35
37
  }
36
38
  /** Create a corresponding `QueryReference` from a Query. */
37
39
  function getQuery(firestore, ref) {
38
- const { sorts, filters, limit } = ref;
39
- const constraints = [];
40
+ return firestoreQuery(getCollection(firestore, ref), ...yieldQueryConstraints(ref));
41
+ }
42
+ function* yieldQueryConstraints({ sorts, filters, limit }) {
40
43
  for (const { key, direction } of sorts)
41
- constraints.push(firestoreOrderBy(key === "id" ? ID : key, DIRECTIONS[direction]));
44
+ yield firestoreOrderBy(key === "id" ? ID : key, DIRECTIONS[direction]);
42
45
  for (const { operator, key, value } of filters)
43
- constraints.push(firestoreWhere(key === "id" ? ID : key, OPERATORS[operator], value));
46
+ yield firestoreWhere(key === "id" ? ID : key, OPERATORS[operator], value);
44
47
  if (typeof limit === "number")
45
- constraints.push(firestoreLimit(limit));
46
- return firestoreQuery(getCollection(firestore, ref), ...constraints);
48
+ yield firestoreLimit(limit);
47
49
  }
48
50
  function getEntities(snapshot) {
49
51
  return snapshot.docs.map(getEntity);
@@ -59,7 +61,9 @@ function getOptionalData(snapshot) {
59
61
  /** Convert `Update` instances into corresponding Firestore `FieldValue` instances. */
60
62
  function* yieldFieldValues(updates, prefix = "") {
61
63
  for (const [key, update] of updates) {
62
- if (update === undefined)
64
+ if (!(update instanceof Update))
65
+ yield [`${prefix}${key}`, update];
66
+ else if (update instanceof Delete)
63
67
  yield [`${prefix}${key}`, firestoreDeleteField()];
64
68
  else if (update instanceof Increment)
65
69
  yield [`${prefix}${key}`, firestoreIncrement(update.amount)];
@@ -74,7 +78,7 @@ function* yieldFieldValues(updates, prefix = "") {
74
78
  yield [`${prefix}${key}`, firestoreArrayRemove(...update.deletes)];
75
79
  }
76
80
  else
77
- yield [`${prefix}${key}`, update];
81
+ yield [`${prefix}${key}`, update.transform()];
78
82
  }
79
83
  }
80
84
  /**
@@ -2,9 +2,9 @@ import { Firestore } from "@google-cloud/firestore";
2
2
  import type { DocumentReference, QueryReference } from "../../db/Reference.js";
3
3
  import type { Data, Entities, OptionalEntity } from "../../util/data.js";
4
4
  import type { Unsubscribe } from "../../observe/Observable.js";
5
+ import { Observer } from "../../observe/Observer.js";
5
6
  import { AsynchronousProvider, Provider } from "../../provider/Provider.js";
6
7
  import { DataUpdate } from "../../update/DataUpdate.js";
7
- import { Observer } from "../../observe/Observer.js";
8
8
  /**
9
9
  * Firestore server database provider.
10
10
  * - Works with the Firebase Admin SDK for Node.JS
@@ -1,11 +1,13 @@
1
1
  import { Firestore, FieldValue } from "@google-cloud/firestore";
2
+ import { dispatchError, dispatchNext } from "../../observe/Observer.js";
2
3
  import { UnsupportedError } from "../../error/UnsupportedError.js";
3
4
  import { Provider } from "../../provider/Provider.js";
4
5
  import { ArrayUpdate } from "../../update/ArrayUpdate.js";
5
6
  import { DataUpdate } from "../../update/DataUpdate.js";
6
7
  import { Increment } from "../../update/Increment.js";
7
8
  import { ObjectUpdate } from "../../update/ObjectUpdate.js";
8
- import { dispatchError, dispatchNext } from "../../observe/Observer.js";
9
+ import { Delete } from "../../update/Delete.js";
10
+ import { Update } from "../../update/Update.js";
9
11
  // Constants.
10
12
  // const ID = "__name__"; // DH: `__name__` is the entire path of the document. `__id__` is just ID.
11
13
  const ID = "__id__"; // Internal way Firestore Queries can reference the ID of the current document.
@@ -60,7 +62,9 @@ function getOptionalEntity(snapshot) {
60
62
  /** Convert `Update` instances into corresponding Firestore `FieldValue` instances. */
61
63
  function* yieldFieldValues(updates, prefix = "") {
62
64
  for (const [key, update] of updates) {
63
- if (update === undefined)
65
+ if (!(update instanceof Update))
66
+ yield [`${prefix}${key}`, update];
67
+ else if (update instanceof Delete)
64
68
  yield [`${prefix}${key}`, FieldValue.delete()];
65
69
  else if (update instanceof Increment)
66
70
  yield [`${prefix}${key}`, FieldValue.increment(update.amount)];
@@ -75,7 +79,7 @@ function* yieldFieldValues(updates, prefix = "") {
75
79
  yield [`${prefix}${key}`, FieldValue.arrayRemove(...update.deletes)];
76
80
  }
77
81
  else
78
- yield [`${prefix}${key}`, update];
82
+ yield [`${prefix}${key}`, update.transform()];
79
83
  }
80
84
  }
81
85
  /**
package/markup/rules.js CHANGED
@@ -12,7 +12,7 @@ const MATCH_INDENT = /^ {1,2}/gm;
12
12
  */
13
13
  export const HEADING_RULE = {
14
14
  regexp: getLineRegExp(`(#{1,6}) +(${MATCH_LINE.source})`),
15
- render: ([, prefix = "", children = ""]) => ({ type: `h${prefix.length}`, key: null, props: { children } }),
15
+ render: ([, prefix = "", children = ""]) => ({ type: `h${prefix.length}`, key: null, ref: null, props: { children } }),
16
16
  contexts: ["block"],
17
17
  childContext: "inline",
18
18
  };
@@ -25,7 +25,7 @@ export const HEADING_RULE = {
25
25
  */
26
26
  export const HORIZONTAL_RULE = {
27
27
  regexp: getLineRegExp(`([${BULLETS}])(?: *\\1){2,}`),
28
- render: () => ({ type: "hr", key: null, props: {} }),
28
+ render: () => ({ type: "hr", key: null, ref: null, props: {} }),
29
29
  contexts: ["block"],
30
30
  };
31
31
  /**
@@ -40,7 +40,7 @@ export const UNORDERED_LIST_RULE = {
40
40
  regexp: getBlockRegExp(`${UNORDERED}(${MATCH_BLOCK.source})`),
41
41
  render: ([, list = ""]) => {
42
42
  const children = list.split(SPLIT_UL_ITEMS).map(_mapUnorderedItem);
43
- return { type: "ul", key: null, props: { children } };
43
+ return { type: "ul", key: null, ref: null, props: { children } };
44
44
  },
45
45
  contexts: ["block", "list"],
46
46
  childContext: "list",
@@ -48,7 +48,7 @@ export const UNORDERED_LIST_RULE = {
48
48
  const SPLIT_UL_ITEMS = new RegExp(`\\n+${UNORDERED}`, "g");
49
49
  const _mapUnorderedItem = (item, key) => {
50
50
  const children = item.replace(MATCH_INDENT, "");
51
- return { type: "li", key, props: { children } };
51
+ return { type: "li", key, ref: null, props: { children } };
52
52
  };
53
53
  /**
54
54
  * Ordered list.
@@ -60,7 +60,7 @@ export const ORDERED_LIST_RULE = {
60
60
  regexp: getBlockRegExp(`(${ORDERED}${MATCH_BLOCK.source})`),
61
61
  render: ([, list = ""]) => {
62
62
  const children = list.split(SPLIT_OL_ITEMS).map(_mapOrderedItem);
63
- return { type: "ol", key: null, props: { children } };
63
+ return { type: "ol", key: null, ref: null, props: { children } };
64
64
  },
65
65
  contexts: ["block", "list"],
66
66
  childContext: "list",
@@ -73,7 +73,7 @@ const _mapOrderedItem = (item, key) => {
73
73
  .slice(firstSpace + 1)
74
74
  .trimStart()
75
75
  .replace(MATCH_INDENT, "");
76
- return { type: "li", key, props: { value, children } };
76
+ return { type: "li", key, ref: null, props: { value, children } };
77
77
  };
78
78
  /**
79
79
  * Blockquote block.
@@ -86,6 +86,7 @@ export const BLOCKQUOTE_RULE = {
86
86
  render: ([, quote = ""]) => ({
87
87
  type: "blockquote",
88
88
  key: null,
89
+ ref: null,
89
90
  props: { children: quote.replace(BLOCKQUOTE_LINES, "") },
90
91
  }),
91
92
  contexts: ["block", "list"],
@@ -105,10 +106,12 @@ export const FENCED_CODE_RULE = {
105
106
  render: ([, , file, children]) => ({
106
107
  type: "pre",
107
108
  key: null,
109
+ ref: null,
108
110
  props: {
109
111
  children: {
110
112
  type: "code",
111
113
  key: null,
114
+ ref: null,
112
115
  props: { "data-file": file || undefined, children },
113
116
  },
114
117
  },
@@ -121,7 +124,7 @@ export const FENCED_CODE_RULE = {
121
124
  */
122
125
  export const PARAGRAPH_RULE = {
123
126
  regexp: getBlockRegExp(` *(${MATCH_BLOCK.source})`),
124
- render: ([, children]) => ({ type: `p`, key: null, props: { children } }),
127
+ render: ([, children]) => ({ type: `p`, key: null, ref: null, props: { children } }),
125
128
  contexts: ["block"],
126
129
  childContext: "inline",
127
130
  priority: -10, // Lower precedence than other blocks so it matches last and paragraphs can be broken by other blocks.
@@ -152,6 +155,7 @@ export const LINK_RULE = {
152
155
  render: ([, title, href = ""], { rel }) => ({
153
156
  type: "a",
154
157
  key: null,
158
+ ref: null,
155
159
  props: { children: title || formatUrl(href), href, rel },
156
160
  }),
157
161
  contexts: ["inline", "list"],
@@ -182,6 +186,7 @@ export const AUTOLINK_RULE = {
182
186
  render: ([, href = "", title], { rel }) => ({
183
187
  type: "a",
184
188
  key: null,
189
+ ref: null,
185
190
  props: { children: title || formatUrl(href), href, rel },
186
191
  }),
187
192
  contexts: ["inline", "list"],
@@ -196,7 +201,7 @@ export const AUTOLINK_RULE = {
196
201
  */
197
202
  export const CODE_RULE = {
198
203
  regexp: getWrapRegExp("`+", MATCH_BLOCK.source),
199
- render: ([, , children]) => ({ type: "code", key: null, props: { children } }),
204
+ render: ([, , children]) => ({ type: "code", key: null, ref: null, props: { children } }),
200
205
  contexts: ["inline", "list"],
201
206
  priority: 10, // Higher priority than other inlines so it matches first before e.g. `strong` or `em` (from CommonMark spec: "Code span backticks have higher precedence than any other inline constructs except HTML tags and autolinks.")
202
207
  };
@@ -210,7 +215,7 @@ export const CODE_RULE = {
210
215
  */
211
216
  export const STRONG_RULE = {
212
217
  regexp: getWrapRegExp("\\*+"),
213
- render: ([, , children]) => ({ type: "strong", key: null, props: { children } }),
218
+ render: ([, , children]) => ({ type: "strong", key: null, ref: null, props: { children } }),
214
219
  contexts: ["inline", "list", "link"],
215
220
  childContext: "inline",
216
221
  };
@@ -224,7 +229,7 @@ export const STRONG_RULE = {
224
229
  */
225
230
  export const EMPHASIS_RULE = {
226
231
  regexp: getWrapRegExp("_+"),
227
- render: ([, , children]) => ({ type: "em", key: null, props: { children } }),
232
+ render: ([, , children]) => ({ type: "em", key: null, ref: null, props: { children } }),
228
233
  contexts: ["inline", "list", "link"],
229
234
  childContext: "inline",
230
235
  };
@@ -238,7 +243,7 @@ export const EMPHASIS_RULE = {
238
243
  */
239
244
  export const INSERT_RULE = {
240
245
  regexp: getWrapRegExp("\\+\\++"),
241
- render: ([, , children]) => ({ type: "ins", key: null, props: { children } }),
246
+ render: ([, , children]) => ({ type: "ins", key: null, ref: null, props: { children } }),
242
247
  contexts: ["inline", "list", "link"],
243
248
  childContext: "inline",
244
249
  };
@@ -252,7 +257,7 @@ export const INSERT_RULE = {
252
257
  */
253
258
  export const DELETE_RULE = {
254
259
  regexp: getWrapRegExp("--+|~~+"),
255
- render: ([, , children]) => ({ type: "del", key: null, props: { children } }),
260
+ render: ([, , children]) => ({ type: "del", key: null, ref: null, props: { children } }),
256
261
  contexts: ["inline", "list", "link"],
257
262
  childContext: "inline",
258
263
  };
@@ -266,7 +271,7 @@ export const DELETE_RULE = {
266
271
  */
267
272
  export const LINEBREAK_RULE = {
268
273
  regexp: /\n/,
269
- render: () => ({ type: "br", key: null, props: {} }),
274
+ render: () => ({ type: "br", key: null, ref: null, props: {} }),
270
275
  contexts: ["inline", "list", "link"],
271
276
  childContext: "inline",
272
277
  };
package/package.json CHANGED
@@ -11,7 +11,7 @@
11
11
  "state-management",
12
12
  "query-builder"
13
13
  ],
14
- "version": "1.68.1",
14
+ "version": "1.68.4",
15
15
  "repository": "https://github.com/dhoulb/shelving",
16
16
  "author": "Dave Houlbrooke <dave@shax.com>",
17
17
  "license": "0BSD",
@@ -5,154 +5,154 @@ import { ThroughProvider } from "./ThroughProvider.js";
5
5
  /** Provider that logs its operations to the console for debugging purposes. */
6
6
  export class DebugProvider extends ThroughProvider {
7
7
  getDocument(ref) {
8
- console.log(`Get "${ref}"`);
8
+ console.log(`Get ${ref}:`);
9
9
  try {
10
10
  const result = super.getDocument(ref);
11
11
  return isAsync(result)
12
12
  ? result.then(undefined, reason => {
13
- console.error(`Error getting "${ref}"`, reason);
13
+ console.error(`Error: Get ${ref}:`, reason);
14
14
  throw reason;
15
15
  })
16
16
  : result;
17
17
  }
18
18
  catch (reason) {
19
- console.error(`Error getting "${ref}"`, reason);
19
+ console.error(`Error: Get ${ref}:`, reason);
20
20
  throw reason;
21
21
  }
22
22
  }
23
23
  subscribeDocument(ref, observer) {
24
- console.log(`Subscribe "${ref}"`);
24
+ console.log(`Subscribe ${ref}:`);
25
25
  return super.subscribeDocument(ref, new DatabaseDebugObserver(ref, observer));
26
26
  }
27
27
  addDocument(ref, data) {
28
- console.log(`Add to "${ref}"`, data);
28
+ console.log(`Add ${ref}:`, data);
29
29
  try {
30
30
  const result = super.addDocument(ref, data);
31
31
  return isAsync(result)
32
32
  ? result.then(undefined, reason => {
33
- console.error(`Error adding to "${ref}"`, reason);
33
+ console.error(`Error: Add ${ref}:`, reason);
34
34
  throw reason;
35
35
  })
36
36
  : result;
37
37
  }
38
38
  catch (reason) {
39
- console.error(`Error adding to "${ref}"`, reason);
39
+ console.error(`Error: Add ${ref}:`, reason);
40
40
  throw reason;
41
41
  }
42
42
  }
43
43
  setDocument(ref, data) {
44
- console.log(`Set "${ref}"`, data);
44
+ console.log(`Set ${ref}:`, data);
45
45
  try {
46
46
  const result = super.setDocument(ref, data);
47
47
  return isAsync(result)
48
48
  ? result.then(undefined, reason => {
49
- console.error(`Error setting "${ref}"`, reason);
49
+ console.error(`Error: Set ${ref}:`, reason);
50
50
  throw reason;
51
51
  })
52
52
  : result;
53
53
  }
54
54
  catch (reason) {
55
- console.error(`Error setting "${ref}"`, reason);
55
+ console.error(`Error: Set ${ref}:`, reason);
56
56
  throw reason;
57
57
  }
58
58
  }
59
59
  updateDocument(ref, update) {
60
- console.log(`Update "${ref}"`, update.updates);
60
+ console.log(`Update ${ref}:`, update.updates);
61
61
  try {
62
62
  const result = super.updateDocument(ref, update);
63
63
  return isAsync(result)
64
64
  ? result.then(undefined, reason => {
65
- console.error(`Error updating "${ref}"`, reason);
65
+ console.error(`Error: Update ${ref}:`, reason);
66
66
  throw reason;
67
67
  })
68
68
  : result;
69
69
  }
70
70
  catch (reason) {
71
- console.error(`Error updating "${ref}"`, reason);
71
+ console.error(`Error: Update ${ref}:`, reason);
72
72
  throw reason;
73
73
  }
74
74
  }
75
75
  deleteDocument(ref) {
76
- console.log(`Delete "${ref}"`);
76
+ console.log(`Delete ${ref}:`);
77
77
  try {
78
78
  const result = super.deleteDocument(ref);
79
79
  return isAsync(result)
80
80
  ? result.then(undefined, reason => {
81
- console.error(`Error deleting "${ref}"`, reason);
81
+ console.error(`Error: Delete ${ref}:`, reason);
82
82
  throw reason;
83
83
  })
84
84
  : result;
85
85
  }
86
86
  catch (reason) {
87
- console.error(`Error deleting "${ref}"`, reason);
87
+ console.error(`Error: Delete ${ref}:`, reason);
88
88
  throw reason;
89
89
  }
90
90
  }
91
91
  getQuery(ref) {
92
- console.log(`Get "${ref}"`);
92
+ console.log(`Get ${ref}:`);
93
93
  try {
94
94
  const results = super.getQuery(ref);
95
95
  return isAsync(results)
96
96
  ? results.then(undefined, reason => {
97
- console.error(`Error getting "${ref}"`, reason);
97
+ console.error(`Error: Get ${ref}:`, reason);
98
98
  throw reason;
99
99
  })
100
100
  : results;
101
101
  }
102
102
  catch (reason) {
103
- console.error(`Error getting "${ref}"`, reason);
103
+ console.error(`Error: Get ${ref}:`, reason);
104
104
  throw reason;
105
105
  }
106
106
  }
107
107
  subscribeQuery(ref, observer) {
108
- console.log(`Subscribe "${ref}"`);
108
+ console.log(`Subscribe ${ref}:`);
109
109
  return super.subscribeQuery(ref, new DatabaseDebugObserver(ref, observer));
110
110
  }
111
111
  setQuery(ref, data) {
112
- console.log(`Set "${ref}"`, data);
112
+ console.log(`Set ${ref}:`, data);
113
113
  try {
114
114
  const result = super.setQuery(ref, data);
115
115
  return isAsync(result)
116
116
  ? result.then(undefined, reason => {
117
- console.error(`Error setting "${ref}"`, reason);
117
+ console.error(`Error: Set ${ref}:`, reason);
118
118
  throw reason;
119
119
  })
120
120
  : result;
121
121
  }
122
122
  catch (reason) {
123
- console.error(`Error setting "${ref}"`, reason);
123
+ console.error(`Error: Set ${ref}:`, reason);
124
124
  throw reason;
125
125
  }
126
126
  }
127
127
  updateQuery(ref, update) {
128
- console.log(`Update "${ref}"`, update.updates);
128
+ console.log(`Update ${ref}:`, update.updates);
129
129
  try {
130
130
  const result = super.updateQuery(ref, update);
131
131
  return isAsync(result)
132
132
  ? result.then(undefined, reason => {
133
- console.error(`Error updating "${ref}"`, reason);
133
+ console.error(`Error: Update ${ref}:`, reason);
134
134
  throw reason;
135
135
  })
136
136
  : result;
137
137
  }
138
138
  catch (reason) {
139
- console.error(`Error updating "${ref}"`, reason);
139
+ console.error(`Error: Update ${ref}:`, reason);
140
140
  throw reason;
141
141
  }
142
142
  }
143
143
  deleteQuery(ref) {
144
- console.log(`Delete "${ref}"`);
144
+ console.log(`Delete ${ref}:`);
145
145
  try {
146
146
  const result = super.deleteQuery(ref);
147
147
  return isAsync(result)
148
148
  ? result.then(undefined, reason => {
149
- console.error(`Error writing "${ref}"`, reason);
149
+ console.error(`Error: Delete ${ref}:`, reason);
150
150
  throw reason;
151
151
  })
152
152
  : result;
153
153
  }
154
154
  catch (reason) {
155
- console.error(`Error writing "${ref}"`, reason);
155
+ console.error(`Error: Delete ${ref}:`, reason);
156
156
  throw reason;
157
157
  }
158
158
  }
@@ -31,5 +31,7 @@ export interface SynchronousThroughProvider extends SynchronousProvider {
31
31
  export interface AsynchronousThroughProvider extends AsynchronousProvider {
32
32
  new (source: AsynchronousProvider): AsynchronousProvider;
33
33
  }
34
- /** Find a specific source provider in a database's provider stack. */
35
- export declare function findSourceProvider<P extends Provider>(provider: Provider, type: Class<P>): P | undefined;
34
+ /** Find a possible source provider in a database's provider stack (if it exists). */
35
+ export declare function getOptionalSourceProvider<P extends Provider>(provider: Provider, type: Class<P>): P | undefined;
36
+ /** Find a source provider in a database's provider stack. */
37
+ export declare function getSourceProvider<P extends Provider>(provider: Provider, type: Class<P>): P;
@@ -1,3 +1,4 @@
1
+ import { AssertionError } from "../error/AssertionError.js";
1
2
  import { Provider } from "./Provider.js";
2
3
  /**
3
4
  * Pass all reads and writes through to a source provider.
@@ -41,10 +42,17 @@ export class ThroughProvider extends Provider {
41
42
  return this.source.deleteQuery(ref);
42
43
  }
43
44
  }
44
- /** Find a specific source provider in a database's provider stack. */
45
- export function findSourceProvider(provider, type) {
45
+ /** Find a possible source provider in a database's provider stack (if it exists). */
46
+ export function getOptionalSourceProvider(provider, type) {
46
47
  if (provider instanceof type)
47
48
  return provider;
48
49
  if (provider instanceof ThroughProvider)
49
- return findSourceProvider(provider.source, type);
50
+ return getSourceProvider(provider.source, type);
51
+ }
52
+ /** Find a source provider in a database's provider stack. */
53
+ export function getSourceProvider(provider, type) {
54
+ const source = getOptionalSourceProvider(provider, type);
55
+ if (!source)
56
+ throw new AssertionError(`Source provider ${type.name} not found`, provider);
57
+ return source;
50
58
  }
@@ -1,6 +1,5 @@
1
1
  import { callAsync } from "../util/async.js";
2
2
  import { validate } from "../util/validate.js";
3
- import { validateUpdate } from "../update/util.js";
4
3
  import { Feedback } from "../feedback/Feedback.js";
5
4
  import { ValidationError } from "../error/ValidationError.js";
6
5
  import { InvalidFeedback } from "../feedback/InvalidFeedback.js";
@@ -21,7 +20,7 @@ export class ValidationProvider extends ThroughProvider {
21
20
  return super.setDocument(ref, validate(value, ref.validator));
22
21
  }
23
22
  updateDocument(ref, update) {
24
- return super.updateDocument(ref, validateUpdate(update, ref.validator));
23
+ return super.updateDocument(ref, update.validate(ref.validator));
25
24
  }
26
25
  getQuery(ref) {
27
26
  return callAsync(_validateEntities, super.getQuery(ref), ref);
@@ -33,7 +32,7 @@ export class ValidationProvider extends ThroughProvider {
33
32
  return super.setQuery(ref, validate(value, ref.validator));
34
33
  }
35
34
  updateQuery(ref, update) {
36
- return super.updateQuery(ref, validateUpdate(update, ref.validator));
35
+ return super.updateQuery(ref, update.validate(ref.validator));
37
36
  }
38
37
  }
39
38
  /** Validate an entity for a document reference. */
@@ -13,7 +13,8 @@ export declare class DocumentState<T extends Data> extends State<OptionalEntity<
13
13
  get exists(): boolean;
14
14
  constructor(ref: DocumentReference<T>);
15
15
  /** Refresh this state from the source provider. */
16
- readonly refresh: () => Promise<void>;
16
+ readonly refresh: () => void;
17
+ _refresh(): Promise<void>;
17
18
  /** Refresh this state if data in the cache is older than `maxAge` (in milliseconds). */
18
19
  refreshStale(maxAge: number): void;
19
20
  /** Subscribe this state to the source provider. */