@dereekb/firebase 13.36.0 → 13.38.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/eslint/index.cjs.js +501 -1
- package/eslint/index.esm.js +497 -2
- package/eslint/package.json +3 -3
- package/eslint/src/lib/index.d.ts +1 -0
- package/eslint/src/lib/plugin.d.ts +2 -0
- package/eslint/src/lib/prefer-clearable-arktype.rule.d.ts +115 -0
- package/index.cjs.js +102 -5
- package/index.esm.js +101 -7
- package/package.json +5 -5
- package/src/lib/common/auth/oidc/oidc.d.ts +26 -0
- package/src/lib/common/firestore/accessor/document.d.ts +8 -3
- package/src/lib/common/firestore/snapshot/snapshot.field.d.ts +64 -1
- package/src/lib/common/model/model.service.d.ts +29 -1
- package/src/lib/model/notification/notification.d.ts +3 -0
- package/src/lib/model/system/system.d.ts +1 -0
- package/test/package.json +6 -6
|
@@ -105,10 +105,15 @@ export declare abstract class AbstractFirestoreDocument<T, D extends AbstractFir
|
|
|
105
105
|
*/
|
|
106
106
|
snapshot(): Promise<DocumentSnapshot<T>>;
|
|
107
107
|
/**
|
|
108
|
-
* Retrieves the data of the document,
|
|
108
|
+
* Retrieves the data of the document, always fetching from Firestore.
|
|
109
109
|
*
|
|
110
|
-
*
|
|
111
|
-
*
|
|
110
|
+
* Delegates to {@link snapshot}, so the read is unconditional and the cache is only WRITTEN to, not
|
|
111
|
+
* consulted — a caller that wants the cached value should read {@link cache} directly.
|
|
112
|
+
*
|
|
113
|
+
* The returned data is converter-applied: declared defaults are filled in, undeclared fields are
|
|
114
|
+
* stripped, and encoded fields (`firestoreEncodedArray`, `firestoreBitwiseSet`) are decoded. This is
|
|
115
|
+
* byte-for-byte what the model API's `readDocument` returns, which is what lets `dbx-cli` read the
|
|
116
|
+
* same document over either transport and get the same answer.
|
|
112
117
|
*
|
|
113
118
|
* @param options - Overrides forwarded to `DocumentSnapshot.data()`, if any.
|
|
114
119
|
* @returns Resolves with the document data, or undefined when the document does not exist.
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
*/
|
|
31
31
|
import { type WebsiteLink, type GrantedRole, type WebsiteFileLink } from '@dereekb/model';
|
|
32
32
|
import { type DateCellRange, type DateCellSchedule } from '@dereekb/date';
|
|
33
|
-
import { type ModelFieldMapFunctionsConfig, type GetterOrValue, type Maybe, type ModelFieldMapConvertFunction, type PrimativeKey, type ReadKeyFunction, type ModelFieldMapFunctionsWithDefaultsConfig, type FilterUniqueStringsTransformConfig, type MapFunction, type FilterKeyValueTuplesInput, type ModelKey, type ToModelMapFunctionsInput, type ModelMapFunctionsRef, type LatLngPrecision, type LatLngString, type TimezoneString, type PrimativeKeyStringDencoderFunction, type PrimativeKeyDencoderFunction, type UnitedStatesAddress, type ZoomLevel, type FilterUniqueFunction, type BitwiseEncodedSet, type BitwiseObjectDencoder, type SortCompareFunctionRef, type TransformNumberFunctionConfigInput, type TransformStringFunctionConfigInput, type DecisionFunction, type ISO8601DateString, type FilterFunction } from '@dereekb/util';
|
|
33
|
+
import { type ModelFieldMapFunctionsConfig, type GetterOrValue, type Maybe, type ModelFieldMapConvertFunction, type PrimativeKey, type ReadKeyFunction, type ModelFieldMapFunctionsWithDefaultsConfig, type FilterUniqueStringsTransformConfig, type MapFunction, type FilterKeyValueTuplesInput, type CopyValueDeepConfig, type ModelKey, type ToModelMapFunctionsInput, type ModelMapFunctionsRef, type LatLngPrecision, type LatLngString, type TimezoneString, type PrimativeKeyStringDencoderFunction, type PrimativeKeyDencoderFunction, type UnitedStatesAddress, type ZoomLevel, type FilterUniqueFunction, type BitwiseEncodedSet, type BitwiseObjectDencoder, type SortCompareFunctionRef, type TransformNumberFunctionConfigInput, type TransformStringFunctionConfigInput, type DecisionFunction, type ISO8601DateString, type FilterFunction } from '@dereekb/util';
|
|
34
34
|
import { type FirestoreModelData } from './snapshot.type';
|
|
35
35
|
/**
|
|
36
36
|
* Base configuration for Firestore field mapping.
|
|
@@ -315,6 +315,69 @@ export declare function optionalFirestoreField<V, D>(config?: OptionalFirestoreF
|
|
|
315
315
|
* @returns A field mapping configuration for optional values
|
|
316
316
|
*/
|
|
317
317
|
export declare function optionalFirestoreField<T>(config?: OptionalFirestoreFieldConfigWithOneTypeTransform<T>): FirestoreModelFieldMapFunctionsConfig<Maybe<T>, Maybe<T>>;
|
|
318
|
+
/**
|
|
319
|
+
* Configuration for {@link optionalFirestorePassthroughJsonField}.
|
|
320
|
+
*
|
|
321
|
+
* Extends {@link CopyValueDeepConfig}, which is what configures the filtering applied on the way in: by
|
|
322
|
+
* default `filter` strips `undefined` values at every depth. `arrayValues`, `filterEmptyValues`, and
|
|
323
|
+
* `transform` are passed through to the copy as-is.
|
|
324
|
+
*
|
|
325
|
+
* @template T - Type for both the model field and Firestore field
|
|
326
|
+
*/
|
|
327
|
+
export interface OptionalFirestorePassthroughJsonFieldConfig<T extends object> extends CopyValueDeepConfig, Pick<OptionalFirestoreFieldConfig<T, T>, 'defaultReadValue'> {
|
|
328
|
+
/**
|
|
329
|
+
* Whether to store `null` instead of an object that has no keys left after filtering. Defaults to `false`.
|
|
330
|
+
*/
|
|
331
|
+
readonly dontStoreIfEmpty?: boolean;
|
|
332
|
+
}
|
|
333
|
+
/**
|
|
334
|
+
* Creates a field mapping configuration for an optional object field that is stored as-is, aside from
|
|
335
|
+
* the values the filter strips out on the way in.
|
|
336
|
+
*
|
|
337
|
+
* This is the field for json a converter should not model: a third-party api response, a request config
|
|
338
|
+
* whose parameters the vendor extends without warning, an sdk-shaped payload. A strict converter would
|
|
339
|
+
* silently drop whatever it does not name; this one keeps everything.
|
|
340
|
+
*
|
|
341
|
+
* The one thing it does not keep is a value Firestore rejects. Firestore refuses an explicit `undefined`
|
|
342
|
+
* outright — one absent optional field anywhere in the payload fails the whole write — and such a value
|
|
343
|
+
* is exactly what assembling json from `Maybe` inputs produces (a usage object built from whichever
|
|
344
|
+
* token counts a response happened to report, a config a caller spread a `Maybe` into). Solved per-writer
|
|
345
|
+
* it has to be remembered at every call site; solved here it cannot be forgotten.
|
|
346
|
+
*
|
|
347
|
+
* The filtering is RECURSIVE, since json of this kind is nested and its interior is just as capable of
|
|
348
|
+
* carrying an `undefined` as its top level. Non-plain values are retained by reference, so a `Date` (or
|
|
349
|
+
* a `Timestamp`, or a `DocumentReference`) survives the copy intact.
|
|
350
|
+
*
|
|
351
|
+
* Filtering happens on WRITE only. Reads are the plain passthrough — no copy, no traversal — since data
|
|
352
|
+
* that came out of Firestore cannot contain the values being filtered in the first place.
|
|
353
|
+
*
|
|
354
|
+
* A top-level `null` still clears the field: {@link optionalFirestoreField} short-circuits `x == null`
|
|
355
|
+
* ahead of the transform, so `update({ myField: null })` is untouched by this.
|
|
356
|
+
*
|
|
357
|
+
* @param config - Filtering and storage configuration. Defaults to stripping `undefined` values at every depth.
|
|
358
|
+
* @returns A field mapping configuration for optional passthrough json values.
|
|
359
|
+
*
|
|
360
|
+
* @dbxModelSnapshotField
|
|
361
|
+
* @dbxModelSnapshotFieldCategory object
|
|
362
|
+
* @dbxModelSnapshotFieldOptional true
|
|
363
|
+
* @dbxModelSnapshotFieldTags json, passthrough, object, raw, optional, undefined, filter, recursive, factory
|
|
364
|
+
* @dbxModelSnapshotFieldRelated optional-firestore-field, firestore-pass-through-field, firestore-sub-object
|
|
365
|
+
* @template T - Type for both the model field and Firestore field
|
|
366
|
+
*
|
|
367
|
+
* @example
|
|
368
|
+
* ```ts
|
|
369
|
+
* fields: {
|
|
370
|
+
* // { model: 'm', temperature: undefined, provider: { only: ['openai'], sort: undefined } }
|
|
371
|
+
* // stores as { model: 'm', provider: { only: ['openai'] } }
|
|
372
|
+
* config: optionalFirestorePassthroughJsonField<MyVendorConfig>(),
|
|
373
|
+
* // store null rather than an empty object when nothing survives the filtering
|
|
374
|
+
* usage: optionalFirestorePassthroughJsonField<MyVendorUsage>({ filterEmptyValues: true, dontStoreIfEmpty: true })
|
|
375
|
+
* }
|
|
376
|
+
* ```
|
|
377
|
+
*
|
|
378
|
+
* @__NO_SIDE_EFFECTS__
|
|
379
|
+
*/
|
|
380
|
+
export declare function optionalFirestorePassthroughJsonField<T extends object>(config?: OptionalFirestorePassthroughJsonFieldConfig<T>): FirestoreModelFieldMapFunctionsConfig<Maybe<T>, Maybe<T>>;
|
|
318
381
|
/**
|
|
319
382
|
* Configuration for a Firestore field with default model value but without conversion functions.
|
|
320
383
|
*
|
|
@@ -21,6 +21,12 @@ export type FirebaseModelServiceContext = FirebasePermissionContext & FirebasePe
|
|
|
21
21
|
* @template R - the granted role type for this model
|
|
22
22
|
*/
|
|
23
23
|
export interface FirebaseModelService<C extends FirebaseModelServiceContext, T, D extends FirestoreDocument<T> = FirestoreDocument<T>, R extends GrantedRole = GrantedRole> extends FirebaseModelPermissionService<C, T, D, R>, FirebaseModelLoader<C, T, D>, FirebaseModelCollectionLoader<any, T, D> {
|
|
24
|
+
/**
|
|
25
|
+
* Whether this model is SERVER-ONLY: unreachable by any client, on any read path.
|
|
26
|
+
*
|
|
27
|
+
* See {@link FirebaseModelServiceConfig.serverOnly}.
|
|
28
|
+
*/
|
|
29
|
+
readonly serverOnly?: boolean;
|
|
24
30
|
}
|
|
25
31
|
/**
|
|
26
32
|
* Lazy getter for a {@link FirebaseModelService}, typically used in the service factory map.
|
|
@@ -33,6 +39,22 @@ export type FirebaseModelServiceGetter<C extends FirebaseModelServiceContext, T,
|
|
|
33
39
|
* from the collection loader.
|
|
34
40
|
*/
|
|
35
41
|
export interface FirebaseModelServiceConfig<C extends FirebaseModelServiceContext, T, D extends FirestoreDocument<T> = FirestoreDocument<T>, R extends GrantedRole = GrantedRole> extends Omit<FirebasePermissionServiceInstanceDelegate<C, T, D, R>, 'loadModelForKey'>, FirebaseModelCollectionLoader<C, T, D> {
|
|
42
|
+
/**
|
|
43
|
+
* Marks this model SERVER-ONLY: no client may read it, on any path.
|
|
44
|
+
*
|
|
45
|
+
* `roleMapForModel` and `firestore.rules` are two independent authorization systems, and the
|
|
46
|
+
* model API runs under the Admin SDK — so it evaluates the former and bypasses the latter
|
|
47
|
+
* entirely. For a model whose rules file has no match block (or an `allow read: if false`), that
|
|
48
|
+
* divergence is a LEAK: the rules say server-only, and the model API hands the document to a
|
|
49
|
+
* client anyway.
|
|
50
|
+
*
|
|
51
|
+
* Setting this closes the gap by refusing the read ahead of `useModel`, so both read paths agree.
|
|
52
|
+
* It is a routing decision, not a permission computation — hence a flag rather than a role.
|
|
53
|
+
*
|
|
54
|
+
* Opt-in by design: absent means today's behaviour, which is the backward-compatible direction
|
|
55
|
+
* for a framework. Downstream apps are unaffected until they set it.
|
|
56
|
+
*/
|
|
57
|
+
readonly serverOnly?: boolean;
|
|
36
58
|
}
|
|
37
59
|
/**
|
|
38
60
|
* Creates a {@link FirebaseModelService} that wires together model loading and permission evaluation.
|
|
@@ -78,7 +100,13 @@ export type LimitedInContextFirebaseModelService<C extends FirebasePermissionErr
|
|
|
78
100
|
* Calling `service(modelOrKey)` returns an {@link InModelContextFirebaseModelService} with role checking and assertions.
|
|
79
101
|
* Also provides `forKey(key)` for key-based lookup.
|
|
80
102
|
*/
|
|
81
|
-
export type InContextFirebaseModelService<C extends FirebasePermissionErrorContext, T, D extends FirestoreDocument<T> = FirestoreDocument<T>, R extends GrantedRole = GrantedRole> = InModelContextFirebaseModelServiceFactory<C, T, D, R> & LimitedInContextFirebaseModelService<C, T, D, R
|
|
103
|
+
export type InContextFirebaseModelService<C extends FirebasePermissionErrorContext, T, D extends FirestoreDocument<T> = FirestoreDocument<T>, R extends GrantedRole = GrantedRole> = InModelContextFirebaseModelServiceFactory<C, T, D, R> & LimitedInContextFirebaseModelService<C, T, D, R> & {
|
|
104
|
+
/**
|
|
105
|
+
* Mirrors {@link FirebaseModelServiceConfig.serverOnly}, so a caller holding only the
|
|
106
|
+
* context-bound service can gate on it without reaching back for the config.
|
|
107
|
+
*/
|
|
108
|
+
readonly serverOnly?: boolean;
|
|
109
|
+
};
|
|
82
110
|
/**
|
|
83
111
|
* Factory that binds a {@link FirebaseModelService} to a specific context, producing an {@link InContextFirebaseModelService}.
|
|
84
112
|
*/
|
|
@@ -593,6 +593,7 @@ export interface NotificationSendCheckpoints {
|
|
|
593
593
|
*
|
|
594
594
|
* @dbxModel
|
|
595
595
|
* @dbxModelRead system
|
|
596
|
+
* @dbxModelServerOnly
|
|
596
597
|
*/
|
|
597
598
|
export interface Notification extends NotificationSendFlags, NotificationSendCheckpoints {
|
|
598
599
|
/**
|
|
@@ -753,6 +754,7 @@ export declare const NOTIFICATION_WEEK_NOTIFICATION_ITEM_LIMIT = 5000;
|
|
|
753
754
|
*
|
|
754
755
|
* @dbxModel
|
|
755
756
|
* @dbxModelRead system
|
|
757
|
+
* @dbxModelServerOnly
|
|
756
758
|
*/
|
|
757
759
|
export interface NotificationWeek {
|
|
758
760
|
/**
|
|
@@ -854,6 +856,7 @@ export declare const NOTIFICATION_LOGGED_EVENT_DAY_ITEM_CONVERTER: PagedItemConv
|
|
|
854
856
|
*
|
|
855
857
|
* @dbxModel
|
|
856
858
|
* @dbxModelRead system
|
|
859
|
+
* @dbxModelServerOnly
|
|
857
860
|
*/
|
|
858
861
|
export interface NotificationLoggedEventDay {
|
|
859
862
|
/**
|
|
@@ -68,6 +68,7 @@ export type SystemStateStoredData = Record<string, any>;
|
|
|
68
68
|
* @dbxModel
|
|
69
69
|
* @dbxModelRead system
|
|
70
70
|
* @dbxModelArchetype system-state-singleton
|
|
71
|
+
* @dbxModelServerOnly
|
|
71
72
|
*/
|
|
72
73
|
export interface SystemState<T extends SystemStateStoredData = SystemStateStoredData> {
|
|
73
74
|
/**
|
package/test/package.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dereekb/firebase/test",
|
|
3
|
-
"version": "13.
|
|
3
|
+
"version": "13.38.0",
|
|
4
4
|
"peerDependencies": {
|
|
5
|
-
"@dereekb/date": "13.
|
|
6
|
-
"@dereekb/firebase": "13.
|
|
7
|
-
"@dereekb/model": "13.
|
|
8
|
-
"@dereekb/rxjs": "13.
|
|
9
|
-
"@dereekb/util": "13.
|
|
5
|
+
"@dereekb/date": "13.38.0",
|
|
6
|
+
"@dereekb/firebase": "13.38.0",
|
|
7
|
+
"@dereekb/model": "13.38.0",
|
|
8
|
+
"@dereekb/rxjs": "13.38.0",
|
|
9
|
+
"@dereekb/util": "13.38.0",
|
|
10
10
|
"@firebase/rules-unit-testing": "5.0.0",
|
|
11
11
|
"date-fns": "^4.1.0",
|
|
12
12
|
"firebase": "^12.12.1",
|