firetender 0.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.
- package/README.md +145 -0
- package/dist/DocWrapper.d.ts +15 -0
- package/dist/DocWrapper.js +26 -0
- package/dist/DocWrapper.js.map +1 -0
- package/dist/FireTenderDoc.d.ts +32 -0
- package/dist/FireTenderDoc.js +133 -0
- package/dist/FireTenderDoc.js.map +1 -0
- package/dist/Timestamps.d.ts +27 -0
- package/dist/Timestamps.js +40 -0
- package/dist/Timestamps.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +23 -0
- package/dist/index.js.map +1 -0
- package/dist/proxies.d.ts +3 -0
- package/dist/proxies.js +113 -0
- package/dist/proxies.js.map +1 -0
- package/package.json +53 -0
package/README.md
ADDED
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
# FireTender
|
|
2
|
+
|
|
3
|
+
FireTender is a wrapper for Firestore documents to make reading and writing them
|
|
4
|
+
simpler and safer. A Firestore doc looks like any other Typescript object, and
|
|
5
|
+
they are validated upon reading and writing.
|
|
6
|
+
|
|
7
|
+
Querying and concurrency are not yet supported. I'm adding features as I need
|
|
8
|
+
them, but contributions are most welcome. See the list of [alternative
|
|
9
|
+
packages](#alternatives) at the end of this README if you're looking for
|
|
10
|
+
something more mature.
|
|
11
|
+
|
|
12
|
+
## Usage
|
|
13
|
+
|
|
14
|
+
To illustrate, let's run through the basics of defining, creating, reading, and
|
|
15
|
+
modifying a Firestore document.
|
|
16
|
+
|
|
17
|
+
### Define your schemas
|
|
18
|
+
|
|
19
|
+
First, we define the document schemas and their validation criteria with
|
|
20
|
+
[Zod](https://github.com/colinhacks/zod). If you've used Joi or Yup, you will
|
|
21
|
+
find Zod very similar. Optional collections should use `.default({})` or
|
|
22
|
+
`.default([])` to simplify later access. Here we define a schema for types of
|
|
23
|
+
pizza, because I was hungry when I first wrote this.
|
|
24
|
+
|
|
25
|
+
Then create `pizzaWrapper`, which is a factory that makes objects to wrap
|
|
26
|
+
Firestore documents and enforce the given schema.
|
|
27
|
+
|
|
28
|
+
```javascript
|
|
29
|
+
import { doc } from "firebase/firestore";
|
|
30
|
+
import { DocWrapper } from "firetender";
|
|
31
|
+
import { z } from "zod";
|
|
32
|
+
|
|
33
|
+
const pizzaSchema = z.object({
|
|
34
|
+
name: z.string(),
|
|
35
|
+
description: z.string().optional(),
|
|
36
|
+
toppings: z.record(
|
|
37
|
+
z.string(),
|
|
38
|
+
z.object({
|
|
39
|
+
isIncluded: z.boolean().default(true),
|
|
40
|
+
surcharge: z.number().positive().optional(),
|
|
41
|
+
placement: z.enum(["left", "right", "entire"]).default("entire"),
|
|
42
|
+
})
|
|
43
|
+
.refine((topping) => topping.isIncluded || topping.surcharge, {
|
|
44
|
+
message: "Toppings that are not included must have a surcharge.",
|
|
45
|
+
path: ["surcharge"],
|
|
46
|
+
})
|
|
47
|
+
),
|
|
48
|
+
tags: z.array(z.string()).default([]),
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
const pizzaWrapper = new DocWrapper(pizzaSchema);
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### Add a document
|
|
55
|
+
|
|
56
|
+
Let's add a document to the `pizzas` collection with an ID of `margherita`. We
|
|
57
|
+
use `DocWrapper.prototype.createNew()` to create a validated local object
|
|
58
|
+
representing a new document in the collection. We then add the doc to Firestore
|
|
59
|
+
by calling its `.write()` method.
|
|
60
|
+
|
|
61
|
+
```javascript
|
|
62
|
+
const docRef = doc(db, "pizzas", "margherita");
|
|
63
|
+
const pizza = pizzaWrapper.createNew(docRef, {
|
|
64
|
+
name: "Margherita",
|
|
65
|
+
toppings: { "fresh mozzarella": {}, "fresh basil": {} },
|
|
66
|
+
tags: ["traditional"],
|
|
67
|
+
});
|
|
68
|
+
await pizza.write();
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
If we don't care about the doc ID, we can also pass a collection reference
|
|
72
|
+
(e.g., `collection(db, "pizzas")`) to `.createNew()`. Firestore will assign a
|
|
73
|
+
random ID.
|
|
74
|
+
|
|
75
|
+
### Read and modify a document
|
|
76
|
+
|
|
77
|
+
To read or modify an existing document, we instantiate a doc wrapper using
|
|
78
|
+
`DocWrapper.prototype.wrapExisting()`, passing in the doc's Firestore reference.
|
|
79
|
+
To read from it, we call `.load()` and access the data with `.ro` (read only);
|
|
80
|
+
to write, we modify the `.rw` accessor and then call `.write()`. They can be
|
|
81
|
+
used in combination, like so:
|
|
82
|
+
|
|
83
|
+
```javascript
|
|
84
|
+
const meats = ["pepperoni", "chicken", "sausage"];
|
|
85
|
+
const pizza = await pizzaWrapper.wrapExisting(docRef).load();
|
|
86
|
+
const isMeatIncluded = Object.entries(pizza.ro.toppings).some(
|
|
87
|
+
([name, topping]) => topping.isIncluded && name in meats
|
|
88
|
+
);
|
|
89
|
+
if (!isMeatIncluded) {
|
|
90
|
+
pizza.rw.toppings.tags.push("vegetarian");
|
|
91
|
+
}
|
|
92
|
+
await pizza.write();
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### Make a copy
|
|
96
|
+
|
|
97
|
+
Here we create a new pizza in the same collection. Alternatively, a document
|
|
98
|
+
can be copied to elsewhere by specifying a document or collection reference.
|
|
99
|
+
|
|
100
|
+
```javascript
|
|
101
|
+
const sourceRef = doc(db, "pizza", "margherita");
|
|
102
|
+
const sourcePizza = await pizzaWrapper.wrapExisting(sourceRef).load();
|
|
103
|
+
const newPizza = sourcePizza.copy("meaty margh");
|
|
104
|
+
newPizza.name = "Meaty Margh";
|
|
105
|
+
newPizza.toppings.sausage = {};
|
|
106
|
+
newPizza.toppings.pepperoni = { included: false, surcharge: 1.25 };
|
|
107
|
+
newPizza.toppings.chicken = { included: false, surcharge: 1.50 };
|
|
108
|
+
delete newPizza.toppings["fresh basil"];
|
|
109
|
+
delete newPizza.tags.vegetarian;
|
|
110
|
+
newPizza.write();
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
## TODO
|
|
114
|
+
|
|
115
|
+
* Concurrency
|
|
116
|
+
* Listen for changes and update the object if it has not been locally
|
|
117
|
+
modified. Provide an onChange() callback option.
|
|
118
|
+
* Support the Firestore transaction API.
|
|
119
|
+
* Queries
|
|
120
|
+
* Document deletion
|
|
121
|
+
* Improved timestamp handling
|
|
122
|
+
* Prod releases
|
|
123
|
+
* Block on failing tests
|
|
124
|
+
* Minify code (esbuild?)
|
|
125
|
+
* Release on github
|
|
126
|
+
|
|
127
|
+
## Alternatives
|
|
128
|
+
|
|
129
|
+
This project is not at all stable yet. If you're looking for a more mature
|
|
130
|
+
Firestore helper, check out:
|
|
131
|
+
|
|
132
|
+
* [Vuefire](https://github.com/vuejs/vuefire) and
|
|
133
|
+
[Reactfire](https://github.com/FirebaseExtended/reactfire) for integration
|
|
134
|
+
with their respective frameworks.
|
|
135
|
+
|
|
136
|
+
* [Fireschema](https://github.com/yarnaimo/fireschema): Another strongly typed
|
|
137
|
+
framework for building and using schemas in Firestore.
|
|
138
|
+
|
|
139
|
+
* [firestore-fp](https://github.com/mobily/firestore-fp): If you are a
|
|
140
|
+
functional programming aficionado.
|
|
141
|
+
|
|
142
|
+
* [simplyfire](https://github.com/coturiv/simplyfire): A brilliantly named
|
|
143
|
+
simplified API that is focused more on querying.
|
|
144
|
+
|
|
145
|
+
I'm sure there are many more, and apologies if I missed your favorite.
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { CollectionReference, DocumentReference } from "firebase/firestore";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
import { FireTenderDoc, FireTenderDocOptions } from "./FireTenderDoc";
|
|
4
|
+
/**
|
|
5
|
+
* Factory for FireTenderDoc objects based on the given schema.
|
|
6
|
+
*/
|
|
7
|
+
export declare class DocWrapper<SchemaType extends z.SomeZodObject, DataType extends {
|
|
8
|
+
[x: string]: any;
|
|
9
|
+
} = z.infer<SchemaType>> {
|
|
10
|
+
private schema;
|
|
11
|
+
constructor(schema: SchemaType);
|
|
12
|
+
createNew(ref: DocumentReference | CollectionReference, initialData: any, // TODO: change to "DataType," after defaults are dropped.
|
|
13
|
+
options?: FireTenderDocOptions): FireTenderDoc<SchemaType, DataType>;
|
|
14
|
+
wrapExisting(ref: DocumentReference | CollectionReference, options?: FireTenderDocOptions): FireTenderDoc<SchemaType, DataType>;
|
|
15
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DocWrapper = void 0;
|
|
4
|
+
const FireTenderDoc_1 = require("./FireTenderDoc");
|
|
5
|
+
/**
|
|
6
|
+
* Factory for FireTenderDoc objects based on the given schema.
|
|
7
|
+
*/
|
|
8
|
+
class DocWrapper {
|
|
9
|
+
constructor(schema) {
|
|
10
|
+
this.schema = schema;
|
|
11
|
+
}
|
|
12
|
+
createNew(ref, initialData, // TODO: change to "DataType," after defaults are dropped.
|
|
13
|
+
options = {}) {
|
|
14
|
+
const mergedOptions = {
|
|
15
|
+
...options,
|
|
16
|
+
createDoc: true,
|
|
17
|
+
initialData,
|
|
18
|
+
};
|
|
19
|
+
return new FireTenderDoc_1.FireTenderDoc(this.schema, ref, mergedOptions);
|
|
20
|
+
}
|
|
21
|
+
wrapExisting(ref, options = {}) {
|
|
22
|
+
return new FireTenderDoc_1.FireTenderDoc(this.schema, ref, options);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
exports.DocWrapper = DocWrapper;
|
|
26
|
+
//# sourceMappingURL=DocWrapper.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DocWrapper.js","sourceRoot":"","sources":["../src/DocWrapper.ts"],"names":[],"mappings":";;;AAEA,mDAAsE;AAEtE;;GAEG;AACH,MAAa,UAAU;IAErB,YAAoB,MAAkB;QAAlB,WAAM,GAAN,MAAM,CAAY;IAAG,CAAC;IAE1C,SAAS,CACP,GAA4C,EAC5C,WAAgB,EAAE,0DAA0D;IAC5E,UAAgC,EAAE;QAElC,MAAM,aAAa,GAAyB;YAC1C,GAAG,OAAO;YACV,SAAS,EAAE,IAAI;YACf,WAAW;SACZ,CAAC;QACF,OAAO,IAAI,6BAAa,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,EAAE,aAAa,CAAC,CAAC;IAC5D,CAAC;IAED,YAAY,CACV,GAA4C,EAC5C,UAAgC,EAAE;QAElC,OAAO,IAAI,6BAAa,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,EAAE,OAAO,CAAC,CAAC;IACtD,CAAC;CACF;AAvBD,gCAuBC"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { CollectionReference, DocumentReference } from "firebase/firestore";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
export declare type DeepReadonly<T> = T extends Array<infer ArrKey> ? ReadonlyArray<DeepReadonly<ArrKey>> : T extends Map<infer MapKey, infer MapVal> ? ReadonlyMap<DeepReadonly<MapKey>, DeepReadonly<MapVal>> : T extends Set<infer SetKey> ? ReadonlySet<DeepReadonly<SetKey>> : T extends Record<any, unknown> ? {
|
|
4
|
+
readonly [ObjKey in keyof T]: DeepReadonly<T[ObjKey]>;
|
|
5
|
+
} : T;
|
|
6
|
+
export declare type FireTenderDocOptions = {
|
|
7
|
+
createDoc?: true;
|
|
8
|
+
initialData?: any;
|
|
9
|
+
};
|
|
10
|
+
/**
|
|
11
|
+
* Helper class for reading and writing Firestore data based on Zod schemas.
|
|
12
|
+
*/
|
|
13
|
+
export declare class FireTenderDoc<SchemaType extends z.SomeZodObject, DataType extends {
|
|
14
|
+
[x: string]: any;
|
|
15
|
+
} = z.infer<SchemaType>> {
|
|
16
|
+
readonly schema: SchemaType;
|
|
17
|
+
private ref;
|
|
18
|
+
private isNewDoc;
|
|
19
|
+
private docID;
|
|
20
|
+
private data;
|
|
21
|
+
private dataProxy;
|
|
22
|
+
private updates;
|
|
23
|
+
constructor(schema: SchemaType, ref: DocumentReference | CollectionReference, options?: FireTenderDocOptions);
|
|
24
|
+
get id(): string | undefined;
|
|
25
|
+
get docRef(): DocumentReference;
|
|
26
|
+
copy(dest?: DocumentReference | CollectionReference | string | undefined, options?: FireTenderDocOptions): FireTenderDoc<SchemaType, DataType>;
|
|
27
|
+
load(force?: boolean): Promise<this>;
|
|
28
|
+
get ro(): DeepReadonly<DataType>;
|
|
29
|
+
get rw(): DataType;
|
|
30
|
+
write(): Promise<void>;
|
|
31
|
+
private onChange;
|
|
32
|
+
}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.FireTenderDoc = void 0;
|
|
4
|
+
const firestore_1 = require("firebase/firestore");
|
|
5
|
+
const proxies_1 = require("./proxies");
|
|
6
|
+
function assertIsDefined(value) {
|
|
7
|
+
if (value === undefined || value === null) {
|
|
8
|
+
throw new TypeError(`${value} is not defined`);
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Helper class for reading and writing Firestore data based on Zod schemas.
|
|
13
|
+
*/
|
|
14
|
+
class FireTenderDoc {
|
|
15
|
+
constructor(schema, ref, options = {}) {
|
|
16
|
+
this.docID = undefined;
|
|
17
|
+
this.data = undefined;
|
|
18
|
+
this.dataProxy = undefined;
|
|
19
|
+
this.updates = new Map();
|
|
20
|
+
this.schema = schema;
|
|
21
|
+
this.ref = ref;
|
|
22
|
+
this.isNewDoc = options.createDoc ?? false;
|
|
23
|
+
console.log(ref, ref instanceof firestore_1.DocumentReference, options);
|
|
24
|
+
if (this.isNewDoc) {
|
|
25
|
+
if (!options.initialData) {
|
|
26
|
+
throw ReferenceError("Initial data must be given when creating a new doc.");
|
|
27
|
+
}
|
|
28
|
+
this.data = schema.parse(options.initialData);
|
|
29
|
+
}
|
|
30
|
+
if (this.ref.type === "document") {
|
|
31
|
+
this.docID = this.ref.path.split("/").pop();
|
|
32
|
+
}
|
|
33
|
+
else if (!this.isNewDoc) {
|
|
34
|
+
throw TypeError("FireTender can only take a collection reference when creating a new document. Use FireTender.createDoc() if this is your intent.");
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
get id() {
|
|
38
|
+
return this.docID;
|
|
39
|
+
}
|
|
40
|
+
get docRef() {
|
|
41
|
+
if (this.ref.type === "document") {
|
|
42
|
+
return this.ref;
|
|
43
|
+
}
|
|
44
|
+
throw Error("docRef can only be accessed after the new doc has been written.");
|
|
45
|
+
}
|
|
46
|
+
copy(dest = undefined, options = {}) {
|
|
47
|
+
if (!this.data) {
|
|
48
|
+
throw Error("You must call load() before making a copy.");
|
|
49
|
+
}
|
|
50
|
+
let ref;
|
|
51
|
+
if (dest && typeof dest !== "string") {
|
|
52
|
+
ref = dest;
|
|
53
|
+
}
|
|
54
|
+
else {
|
|
55
|
+
const collectionRef = this.ref.type === "document" ? this.ref.parent : this.ref;
|
|
56
|
+
if (dest) {
|
|
57
|
+
ref = (0, firestore_1.doc)(collectionRef, dest);
|
|
58
|
+
}
|
|
59
|
+
else {
|
|
60
|
+
ref = collectionRef;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
const mergedOptions = {
|
|
64
|
+
...options,
|
|
65
|
+
createDoc: true,
|
|
66
|
+
initialData: this.data,
|
|
67
|
+
};
|
|
68
|
+
return new FireTenderDoc(this.schema, ref, mergedOptions);
|
|
69
|
+
}
|
|
70
|
+
async load(force = false) {
|
|
71
|
+
if (this.isNewDoc || this.ref.type === "collection") {
|
|
72
|
+
throw Error("load() should not be called for new documents.");
|
|
73
|
+
}
|
|
74
|
+
if (!this.data || force) {
|
|
75
|
+
const snapshot = await (0, firestore_1.getDoc)(this.ref);
|
|
76
|
+
if (!snapshot.exists()) {
|
|
77
|
+
throw new Error("Document does not exist.");
|
|
78
|
+
}
|
|
79
|
+
this.data = this.schema.parse(snapshot.data());
|
|
80
|
+
// Dereference the old proxy, if any, to force a recapture of data.
|
|
81
|
+
this.dataProxy = undefined;
|
|
82
|
+
}
|
|
83
|
+
return this;
|
|
84
|
+
}
|
|
85
|
+
get ro() {
|
|
86
|
+
if (!this.data) {
|
|
87
|
+
throw Error("You must call load() before using the .ro accessor.");
|
|
88
|
+
}
|
|
89
|
+
return this.data;
|
|
90
|
+
}
|
|
91
|
+
get rw() {
|
|
92
|
+
if (this.isNewDoc) {
|
|
93
|
+
// No need to monitor changes if we're creating rather than updating.
|
|
94
|
+
return this.data;
|
|
95
|
+
}
|
|
96
|
+
if (!this.dataProxy) {
|
|
97
|
+
if (!this.data) {
|
|
98
|
+
throw Error("You must call load() before using the .rw accessor.");
|
|
99
|
+
}
|
|
100
|
+
this.dataProxy = (0, proxies_1.watchFieldForChanges)([], this.schema, this.data, this.onChange.bind(this));
|
|
101
|
+
}
|
|
102
|
+
return this.dataProxy;
|
|
103
|
+
}
|
|
104
|
+
async write() {
|
|
105
|
+
if (this.isNewDoc) {
|
|
106
|
+
assertIsDefined(this.data);
|
|
107
|
+
if (this.ref.type === "document") {
|
|
108
|
+
await (0, firestore_1.setDoc)(this.ref, this.data);
|
|
109
|
+
}
|
|
110
|
+
else {
|
|
111
|
+
this.ref = await (0, firestore_1.addDoc)(this.ref, this.data);
|
|
112
|
+
this.docID = this.ref.path.split("/").pop();
|
|
113
|
+
}
|
|
114
|
+
this.isNewDoc = false;
|
|
115
|
+
}
|
|
116
|
+
else {
|
|
117
|
+
if (!(this.ref.type === "document")) {
|
|
118
|
+
// We should never get here.
|
|
119
|
+
throw Error("Internal error. FireTender object should always reference a document when updating an existing doc.");
|
|
120
|
+
}
|
|
121
|
+
if (this.updates.size === 0) {
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
const flatUpdateList = Array.from(this.updates.entries()).flat();
|
|
125
|
+
await (0, firestore_1.updateDoc)(this.ref, flatUpdateList[0], flatUpdateList[1], ...flatUpdateList.slice(2));
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
onChange(fieldPath, newValue) {
|
|
129
|
+
this.updates.set(fieldPath.join("."), newValue);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
exports.FireTenderDoc = FireTenderDoc;
|
|
133
|
+
//# sourceMappingURL=FireTenderDoc.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FireTenderDoc.js","sourceRoot":"","sources":["../src/FireTenderDoc.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
/**
|
|
3
|
+
* Timestamp representation used by Firestore: seconds and nanoseconds since the
|
|
4
|
+
* epoch.
|
|
5
|
+
*/
|
|
6
|
+
export declare const timestampSchema: z.ZodObject<{
|
|
7
|
+
seconds: z.ZodNumber;
|
|
8
|
+
nanoseconds: z.ZodNumber;
|
|
9
|
+
}, "strip", z.ZodTypeAny, {
|
|
10
|
+
seconds: number;
|
|
11
|
+
nanoseconds: number;
|
|
12
|
+
}, {
|
|
13
|
+
seconds: number;
|
|
14
|
+
nanoseconds: number;
|
|
15
|
+
}>;
|
|
16
|
+
export declare type TimestampData = z.infer<typeof timestampSchema>;
|
|
17
|
+
export declare function dateFromTimestamp(timestamp: TimestampData): Date;
|
|
18
|
+
export declare function makeTTL(daysFromNow?: number): {
|
|
19
|
+
seconds: number;
|
|
20
|
+
nanoseconds: number;
|
|
21
|
+
};
|
|
22
|
+
export declare function timestampFromDate(date: Date): TimestampData;
|
|
23
|
+
export declare function timestampFromUnixMillis(msSinceEpoch: number): TimestampData;
|
|
24
|
+
export declare function nowTimestamp(): {
|
|
25
|
+
seconds: number;
|
|
26
|
+
nanoseconds: number;
|
|
27
|
+
};
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.nowTimestamp = exports.timestampFromUnixMillis = exports.timestampFromDate = exports.makeTTL = exports.dateFromTimestamp = exports.timestampSchema = void 0;
|
|
4
|
+
const zod_1 = require("zod");
|
|
5
|
+
/**
|
|
6
|
+
* Timestamp representation used by Firestore: seconds and nanoseconds since the
|
|
7
|
+
* epoch.
|
|
8
|
+
*/
|
|
9
|
+
exports.timestampSchema = zod_1.z.object({
|
|
10
|
+
seconds: zod_1.z.number().positive().int(),
|
|
11
|
+
nanoseconds: zod_1.z.number().nonnegative().int(),
|
|
12
|
+
});
|
|
13
|
+
// TODO: probably want to move these timestamp functions into their own helper
|
|
14
|
+
// module
|
|
15
|
+
function dateFromTimestamp(timestamp) {
|
|
16
|
+
return new Date(timestamp.seconds * 1e3 + timestamp.nanoseconds / 1e6);
|
|
17
|
+
}
|
|
18
|
+
exports.dateFromTimestamp = dateFromTimestamp;
|
|
19
|
+
function makeTTL(daysFromNow = 30) {
|
|
20
|
+
// TODO: is there a way to use the server time rather than Date.now()?
|
|
21
|
+
return timestampFromUnixMillis(Date.now() + daysFromNow * 24 * 60 * 60 * 1000);
|
|
22
|
+
}
|
|
23
|
+
exports.makeTTL = makeTTL;
|
|
24
|
+
function timestampFromDate(date) {
|
|
25
|
+
return timestampFromUnixMillis(date.getTime());
|
|
26
|
+
}
|
|
27
|
+
exports.timestampFromDate = timestampFromDate;
|
|
28
|
+
function timestampFromUnixMillis(msSinceEpoch) {
|
|
29
|
+
return {
|
|
30
|
+
seconds: Math.floor(msSinceEpoch / 1000),
|
|
31
|
+
nanoseconds: Math.floor((msSinceEpoch % 1000) * 1000000),
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
exports.timestampFromUnixMillis = timestampFromUnixMillis;
|
|
35
|
+
function nowTimestamp() {
|
|
36
|
+
// TODO: is there a way to use the server time rather than Date.now()?
|
|
37
|
+
return timestampFromUnixMillis(Date.now());
|
|
38
|
+
}
|
|
39
|
+
exports.nowTimestamp = nowTimestamp;
|
|
40
|
+
//# sourceMappingURL=Timestamps.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Timestamps.js","sourceRoot":"","sources":["../src/Timestamps.ts"],"names":[],"mappings":";;;AAAA,6BAAwB;AAExB;;;GAGG;AACU,QAAA,eAAe,GAAG,OAAC,CAAC,MAAM,CAAC;IACtC,OAAO,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,GAAG,EAAE;IACpC,WAAW,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,WAAW,EAAE,CAAC,GAAG,EAAE;CAC5C,CAAC,CAAC;AAGH,8EAA8E;AAC9E,SAAS;AAET,SAAgB,iBAAiB,CAAC,SAAwB;IACxD,OAAO,IAAI,IAAI,CAAC,SAAS,CAAC,OAAO,GAAG,GAAG,GAAG,SAAS,CAAC,WAAW,GAAG,GAAG,CAAC,CAAC;AACzE,CAAC;AAFD,8CAEC;AAED,SAAgB,OAAO,CAAC,WAAW,GAAG,EAAE;IACtC,sEAAsE;IACtE,OAAO,uBAAuB,CAC5B,IAAI,CAAC,GAAG,EAAE,GAAG,WAAW,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAC/C,CAAC;AACJ,CAAC;AALD,0BAKC;AAED,SAAgB,iBAAiB,CAAC,IAAU;IAC1C,OAAO,uBAAuB,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC;AACjD,CAAC;AAFD,8CAEC;AAED,SAAgB,uBAAuB,CAAC,YAAoB;IAC1D,OAAO;QACL,OAAO,EAAE,IAAI,CAAC,KAAK,CAAC,YAAY,GAAG,IAAI,CAAC;QACxC,WAAW,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,YAAY,GAAG,IAAI,CAAC,GAAG,OAAO,CAAC;KACzD,CAAC;AACJ,CAAC;AALD,0DAKC;AAED,SAAgB,YAAY;IAC1B,sEAAsE;IACtE,OAAO,uBAAuB,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC;AAC7C,CAAC;AAHD,oCAGC"}
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
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
|
+
exports.FireTenderDoc = exports.DocWrapper = void 0;
|
|
18
|
+
var DocWrapper_1 = require("./DocWrapper");
|
|
19
|
+
Object.defineProperty(exports, "DocWrapper", { enumerable: true, get: function () { return DocWrapper_1.DocWrapper; } });
|
|
20
|
+
var FireTenderDoc_1 = require("./FireTenderDoc");
|
|
21
|
+
Object.defineProperty(exports, "FireTenderDoc", { enumerable: true, get: function () { return FireTenderDoc_1.FireTenderDoc; } });
|
|
22
|
+
__exportStar(require("./Timestamps"), exports);
|
|
23
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;AAAA,2CAA0C;AAAjC,wGAAA,UAAU,OAAA;AACnB,iDAAgD;AAAvC,8GAAA,aAAa,OAAA;AACtB,+CAA6B"}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export declare function watchArrayForChanges<ArrayElementType, FieldSchemaType extends z.ZodTypeAny>(arrayPath: string[], array: ArrayElementType[], fieldSchema: FieldSchemaType, field: z.infer<FieldSchemaType>, onChange: (path: string[], newValue: any) => void): z.infer<FieldSchemaType>;
|
|
3
|
+
export declare function watchFieldForChanges<FieldSchemaType extends z.ZodTypeAny>(fieldPath: string[], fieldSchema: FieldSchemaType, field: z.infer<FieldSchemaType>, onChange: (path: string[], newValue: any) => void): z.infer<FieldSchemaType>;
|
package/dist/proxies.js
ADDED
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.watchFieldForChanges = exports.watchArrayForChanges = void 0;
|
|
4
|
+
const firestore_1 = require("firebase/firestore");
|
|
5
|
+
const zod_1 = require("zod");
|
|
6
|
+
function assertKeyIsString(key) {
|
|
7
|
+
if (typeof key !== "string") {
|
|
8
|
+
throw TypeError("Property access using symbols is not supported.");
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
function unwrapSchema(schema) {
|
|
12
|
+
if (schema instanceof zod_1.z.ZodOptional || schema instanceof zod_1.z.ZodNullable) {
|
|
13
|
+
return unwrapSchema(schema.unwrap());
|
|
14
|
+
}
|
|
15
|
+
if (schema instanceof zod_1.z.ZodDefault) {
|
|
16
|
+
return unwrapSchema(schema.removeDefault());
|
|
17
|
+
}
|
|
18
|
+
if (schema instanceof zod_1.z.ZodEffects) {
|
|
19
|
+
return unwrapSchema(schema.innerType());
|
|
20
|
+
}
|
|
21
|
+
return schema;
|
|
22
|
+
}
|
|
23
|
+
function getPropertySchema(parentSchema, propertyKey) {
|
|
24
|
+
const schema = unwrapSchema(parentSchema);
|
|
25
|
+
if (schema instanceof zod_1.z.ZodRecord) {
|
|
26
|
+
return schema.valueSchema;
|
|
27
|
+
}
|
|
28
|
+
if (schema instanceof zod_1.z.ZodArray) {
|
|
29
|
+
return schema.element;
|
|
30
|
+
}
|
|
31
|
+
if (schema instanceof zod_1.z.ZodObject) {
|
|
32
|
+
return schema.shape[propertyKey];
|
|
33
|
+
}
|
|
34
|
+
throw TypeError(`Unsupported schema type for property "${propertyKey}": ${schema.constructor.name}`);
|
|
35
|
+
}
|
|
36
|
+
function watchArrayForChanges(arrayPath, array, fieldSchema, field, onChange) {
|
|
37
|
+
return new Proxy(field, {
|
|
38
|
+
get(target, propertyKey) {
|
|
39
|
+
assertKeyIsString(propertyKey);
|
|
40
|
+
const property = target[propertyKey];
|
|
41
|
+
if (property instanceof Function) {
|
|
42
|
+
const result = (...args) => property.apply(field, args);
|
|
43
|
+
// TODO (easy): have a list of functions that don't trigger onChange.
|
|
44
|
+
// TODO (harder): also handle at, foreach, etc. methods to chain proxies
|
|
45
|
+
// down from them. But life's too short for that.
|
|
46
|
+
onChange(arrayPath, array);
|
|
47
|
+
return result;
|
|
48
|
+
}
|
|
49
|
+
if (property instanceof Object) {
|
|
50
|
+
return watchArrayForChanges(arrayPath, array, getPropertySchema(fieldSchema, propertyKey), property, onChange);
|
|
51
|
+
}
|
|
52
|
+
return property;
|
|
53
|
+
},
|
|
54
|
+
set(target, propertyKey, value) {
|
|
55
|
+
assertKeyIsString(propertyKey);
|
|
56
|
+
const propertySchema = getPropertySchema(fieldSchema, propertyKey);
|
|
57
|
+
const parsedValue = propertySchema.parse(value);
|
|
58
|
+
const result = Reflect.set(target, propertyKey, parsedValue);
|
|
59
|
+
onChange(arrayPath, array);
|
|
60
|
+
return result;
|
|
61
|
+
},
|
|
62
|
+
deleteProperty(target, propertyKey) {
|
|
63
|
+
assertKeyIsString(propertyKey);
|
|
64
|
+
// Calling Reflect.deleteProperty on an array item sets it to undefined,
|
|
65
|
+
// which causes Firestore updates to fail unless ignoreUndefinedProperties
|
|
66
|
+
// is set, and which is generally not what we want. Hence splice.
|
|
67
|
+
const removedValues = array.splice(Number(propertyKey), 1);
|
|
68
|
+
if (removedValues.length !== 1) {
|
|
69
|
+
throw RangeError(`Failed to delete array item with index ${propertyKey}. Out of bounds?`);
|
|
70
|
+
}
|
|
71
|
+
if (target === array) {
|
|
72
|
+
onChange(arrayPath, (0, firestore_1.arrayRemove)(removedValues[0]));
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
onChange(arrayPath, array);
|
|
76
|
+
}
|
|
77
|
+
return true;
|
|
78
|
+
},
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
exports.watchArrayForChanges = watchArrayForChanges;
|
|
82
|
+
function watchFieldForChanges(fieldPath, fieldSchema, field, onChange) {
|
|
83
|
+
return new Proxy(field, {
|
|
84
|
+
get(target, propertyKey) {
|
|
85
|
+
assertKeyIsString(propertyKey);
|
|
86
|
+
const property = target[propertyKey];
|
|
87
|
+
if (property instanceof Function) {
|
|
88
|
+
return (...args) => property.apply(field, args);
|
|
89
|
+
}
|
|
90
|
+
if (property instanceof Array) {
|
|
91
|
+
return watchArrayForChanges([...fieldPath, propertyKey], property, getPropertySchema(fieldSchema, propertyKey), property, onChange);
|
|
92
|
+
}
|
|
93
|
+
if (property instanceof Object) {
|
|
94
|
+
return watchFieldForChanges([...fieldPath, propertyKey], getPropertySchema(fieldSchema, propertyKey), property, onChange);
|
|
95
|
+
}
|
|
96
|
+
return property;
|
|
97
|
+
},
|
|
98
|
+
set(target, propertyKey, value) {
|
|
99
|
+
assertKeyIsString(propertyKey);
|
|
100
|
+
const propertySchema = getPropertySchema(fieldSchema, propertyKey);
|
|
101
|
+
const parsedValue = propertySchema.parse(value);
|
|
102
|
+
onChange([...fieldPath, propertyKey], parsedValue);
|
|
103
|
+
return Reflect.set(target, propertyKey, parsedValue);
|
|
104
|
+
},
|
|
105
|
+
deleteProperty(target, propertyKey) {
|
|
106
|
+
assertKeyIsString(propertyKey);
|
|
107
|
+
onChange([...fieldPath, propertyKey], (0, firestore_1.deleteField)());
|
|
108
|
+
return Reflect.deleteProperty(target, propertyKey);
|
|
109
|
+
},
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
exports.watchFieldForChanges = watchFieldForChanges;
|
|
113
|
+
//# sourceMappingURL=proxies.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"proxies.js","sourceRoot":"","sources":["../src/proxies.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "firetender",
|
|
3
|
+
"displayName": "FireTender",
|
|
4
|
+
"description": "Typescript wrapper for Firestore documents",
|
|
5
|
+
"version": "0.1.0",
|
|
6
|
+
"author": "Jake Hartman",
|
|
7
|
+
"license": "MIT",
|
|
8
|
+
"homepage": "https://github.com/jakes-space/firetender",
|
|
9
|
+
"repository": {
|
|
10
|
+
"type": "git",
|
|
11
|
+
"url": "https://github.com/jakes-space/firetender.git"
|
|
12
|
+
},
|
|
13
|
+
"keywords": [
|
|
14
|
+
"firestore",
|
|
15
|
+
"typescript",
|
|
16
|
+
"schema"
|
|
17
|
+
],
|
|
18
|
+
"types": "./dist/index.d.ts",
|
|
19
|
+
"main": "./dist/index.js",
|
|
20
|
+
"exports": {
|
|
21
|
+
".": {
|
|
22
|
+
"types": "./dist/index.d.ts",
|
|
23
|
+
"import": "./dist/index.js"
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
"files": [
|
|
27
|
+
"/dist"
|
|
28
|
+
],
|
|
29
|
+
"scripts": {
|
|
30
|
+
"lint": "eslint",
|
|
31
|
+
"test": "jest"
|
|
32
|
+
},
|
|
33
|
+
"dependencies": {
|
|
34
|
+
"firebase": "^9.13.0",
|
|
35
|
+
"zod": "^3.19.1"
|
|
36
|
+
},
|
|
37
|
+
"devDependencies": {
|
|
38
|
+
"@firebase/rules-unit-testing": "^2.0.5",
|
|
39
|
+
"@rushstack/eslint-patch": "^1.2.0",
|
|
40
|
+
"@types/jest": "^29.2.0",
|
|
41
|
+
"@typescript-eslint/eslint-plugin": "^5.41.0",
|
|
42
|
+
"@typescript-eslint/parser": "^5.41.0",
|
|
43
|
+
"eslint": "^8.26.0",
|
|
44
|
+
"eslint-config-prettier": "^8.5.0",
|
|
45
|
+
"eslint-import-resolver-typescript": "^3.5.2",
|
|
46
|
+
"eslint-plugin-import": "^2.26.0",
|
|
47
|
+
"jest": "^29.2.2",
|
|
48
|
+
"prettier": "^2.7.1",
|
|
49
|
+
"ts-jest": "^29.0.3",
|
|
50
|
+
"tslib": "^2.4.1",
|
|
51
|
+
"typescript": "^4.8.4"
|
|
52
|
+
}
|
|
53
|
+
}
|