pyric 0.1.0-alpha.20 → 0.1.0-alpha.21
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 +64 -89
- package/dist/ai/blocked.d.ts +52 -0
- package/dist/ai/blocked.d.ts.map +1 -0
- package/dist/ai/blocked.js +83 -0
- package/dist/ai/blocked.js.map +1 -0
- package/dist/ai/broker/broker.d.ts +49 -0
- package/dist/ai/broker/broker.d.ts.map +1 -1
- package/dist/ai/broker/broker.js +90 -0
- package/dist/ai/broker/broker.js.map +1 -1
- package/dist/ai/broker/gemini-engine.d.ts +14 -1
- package/dist/ai/broker/gemini-engine.d.ts.map +1 -1
- package/dist/ai/broker/gemini-engine.js +30 -9
- package/dist/ai/broker/gemini-engine.js.map +1 -1
- package/dist/ai/broker/index.d.ts +2 -2
- package/dist/ai/broker/index.d.ts.map +1 -1
- package/dist/ai/broker/index.js +2 -2
- package/dist/ai/broker/index.js.map +1 -1
- package/dist/ai/broker/openai-engine.d.ts +10 -1
- package/dist/ai/broker/openai-engine.d.ts.map +1 -1
- package/dist/ai/broker/openai-engine.js +26 -4
- package/dist/ai/broker/openai-engine.js.map +1 -1
- package/dist/ai/broker/synthesizer.d.ts +14 -0
- package/dist/ai/broker/synthesizer.d.ts.map +1 -1
- package/dist/ai/broker/synthesizer.js +31 -0
- package/dist/ai/broker/synthesizer.js.map +1 -1
- package/dist/ai/broker/types.d.ts +24 -0
- package/dist/ai/broker/types.d.ts.map +1 -1
- package/dist/ai/internal.d.ts +5 -0
- package/dist/ai/internal.d.ts.map +1 -1
- package/dist/ai/internal.js +5 -0
- package/dist/ai/internal.js.map +1 -1
- package/dist/ai/response-helpers.d.ts.map +1 -1
- package/dist/ai/response-helpers.js +6 -24
- package/dist/ai/response-helpers.js.map +1 -1
- package/dist/analytics/index.d.ts +40 -0
- package/dist/analytics/index.d.ts.map +1 -0
- package/dist/analytics/index.js +25 -0
- package/dist/analytics/index.js.map +1 -0
- package/dist/app-check/index.d.ts +31 -0
- package/dist/app-check/index.d.ts.map +1 -0
- package/dist/app-check/index.js +20 -0
- package/dist/app-check/index.js.map +1 -0
- package/dist/database/controls.d.ts +1 -1
- package/dist/database/controls.js +1 -1
- package/dist/database/sandbox/rules-eval.d.ts +1 -1
- package/dist/database/sandbox/rules-eval.d.ts.map +1 -1
- package/dist/database/sandbox/rules-eval.js +2 -2
- package/dist/database/sandbox/rules-eval.js.map +1 -1
- package/dist/database/sandbox/write-plane.js +2 -2
- package/dist/database/sandbox/write-plane.js.map +1 -1
- package/dist/database/sandbox-controls.d.ts +12 -5
- package/dist/database/sandbox-controls.d.ts.map +1 -1
- package/dist/database/sandbox-controls.js +20 -9
- package/dist/database/sandbox-controls.js.map +1 -1
- package/dist/deferred/entry.d.ts +75 -0
- package/dist/deferred/entry.d.ts.map +1 -0
- package/dist/deferred/entry.js +143 -0
- package/dist/deferred/entry.js.map +1 -0
- package/dist/firestore/lite.d.ts +72 -0
- package/dist/firestore/lite.d.ts.map +1 -0
- package/dist/firestore/lite.js +22 -0
- package/dist/firestore/lite.js.map +1 -0
- package/dist/firestore/persistence.d.ts +2 -2
- package/dist/firestore/persistence.js +1 -1
- package/dist/functions/index.d.ts +29 -0
- package/dist/functions/index.d.ts.map +1 -0
- package/dist/functions/index.js +20 -0
- package/dist/functions/index.js.map +1 -0
- package/dist/performance/index.d.ts +22 -0
- package/dist/performance/index.d.ts.map +1 -0
- package/dist/performance/index.js +19 -0
- package/dist/performance/index.js.map +1 -0
- package/dist/remote-config/index.d.ts +40 -0
- package/dist/remote-config/index.d.ts.map +1 -0
- package/dist/remote-config/index.js +25 -0
- package/dist/remote-config/index.js.map +1 -0
- package/dist/rules/grammar/FirestoreValidator.d.ts.map +1 -1
- package/dist/rules/grammar/FirestoreValidator.js +43 -27
- package/dist/rules/grammar/FirestoreValidator.js.map +1 -1
- package/dist/rules/grammar/document-access-count.d.ts +24 -0
- package/dist/rules/grammar/document-access-count.d.ts.map +1 -0
- package/dist/rules/grammar/document-access-count.js +100 -0
- package/dist/rules/grammar/document-access-count.js.map +1 -0
- package/dist/rules/linter/ast-utils.d.ts +2 -6
- package/dist/rules/linter/ast-utils.d.ts.map +1 -1
- package/dist/rules/linter/ast-utils.js +2 -63
- package/dist/rules/linter/ast-utils.js.map +1 -1
- package/dist/rules/linter/hallucinations.d.ts +8 -0
- package/dist/rules/linter/hallucinations.d.ts.map +1 -1
- package/dist/rules/linter/hallucinations.js +121 -31
- package/dist/rules/linter/hallucinations.js.map +1 -1
- package/dist/rules/linter/linter.d.ts +10 -1
- package/dist/rules/linter/linter.d.ts.map +1 -1
- package/dist/rules/linter/linter.js +23 -9
- package/dist/rules/linter/linter.js.map +1 -1
- package/dist/rules/rtdb/grammar/simulator.d.ts.map +1 -1
- package/dist/rules/rtdb/grammar/simulator.js +13 -13
- package/dist/rules/rtdb/grammar/simulator.js.map +1 -1
- package/dist/rules/rtdb/simulation/handler.d.ts.map +1 -1
- package/dist/rules/rtdb/simulation/handler.js +96 -35
- package/dist/rules/rtdb/simulation/handler.js.map +1 -1
- package/dist/rules/simulator/document-lookups.d.ts +4 -0
- package/dist/rules/simulator/document-lookups.d.ts.map +1 -1
- package/dist/rules/simulator/document-lookups.js +42 -3
- package/dist/rules/simulator/document-lookups.js.map +1 -1
- package/dist/rules/simulator/eval-error.d.ts +11 -0
- package/dist/rules/simulator/eval-error.d.ts.map +1 -1
- package/dist/rules/simulator/eval-error.js +14 -0
- package/dist/rules/simulator/eval-error.js.map +1 -1
- package/dist/rules/simulator/evaluation-builtins.d.ts.map +1 -1
- package/dist/rules/simulator/evaluation-builtins.js +33 -8
- package/dist/rules/simulator/evaluation-builtins.js.map +1 -1
- package/dist/rules/simulator/evaluation-context.d.ts +12 -0
- package/dist/rules/simulator/evaluation-context.d.ts.map +1 -1
- package/dist/rules/simulator/evaluator.d.ts +1 -1
- package/dist/rules/simulator/evaluator.d.ts.map +1 -1
- package/dist/rules/simulator/evaluator.js +16 -4
- package/dist/rules/simulator/evaluator.js.map +1 -1
- package/dist/rules/simulator/handler.d.ts.map +1 -1
- package/dist/rules/simulator/handler.js +52 -5
- package/dist/rules/simulator/handler.js.map +1 -1
- package/dist/rules/simulator/lookup-budget.d.ts +37 -0
- package/dist/rules/simulator/lookup-budget.d.ts.map +1 -0
- package/dist/rules/simulator/lookup-budget.js +96 -0
- package/dist/rules/simulator/lookup-budget.js.map +1 -0
- package/dist/rules/stdlib-modules.d.ts +7 -0
- package/dist/rules/stdlib-modules.d.ts.map +1 -1
- package/dist/rules/stdlib-modules.js +11 -11
- package/dist/rules/stdlib-modules.js.map +1 -1
- package/dist/sandbox/admin-firestore/get-firestore.d.ts +6 -0
- package/dist/sandbox/admin-firestore/get-firestore.d.ts.map +1 -1
- package/dist/sandbox/admin-firestore/get-firestore.js +22 -3
- package/dist/sandbox/admin-firestore/get-firestore.js.map +1 -1
- package/dist/sandbox/index.d.ts +1 -1
- package/dist/sandbox/index.d.ts.map +1 -1
- package/dist/sandbox/index.js +1 -1
- package/dist/sandbox/index.js.map +1 -1
- package/dist/sandbox/persistence/types.d.ts +1 -1
- package/dist/sandbox/remote.d.ts +2 -2
- package/dist/sandbox/sandbox-context.d.ts +8 -1
- package/dist/sandbox/sandbox-context.d.ts.map +1 -1
- package/dist/sandbox/sandbox-context.js +59 -8
- package/dist/sandbox/sandbox-context.js.map +1 -1
- package/dist/sandbox/types/auth-state.d.ts +1 -0
- package/dist/sandbox/types/auth-state.d.ts.map +1 -1
- package/dist/sandbox/types/events.d.ts +2 -1
- package/dist/sandbox/types/events.d.ts.map +1 -1
- package/dist/sandbox/types/operation.d.ts +1 -0
- package/dist/sandbox/types/operation.d.ts.map +1 -1
- package/dist/storage/enforce.d.ts +20 -1
- package/dist/storage/enforce.d.ts.map +1 -1
- package/dist/storage/enforce.js +47 -14
- package/dist/storage/enforce.js.map +1 -1
- package/dist/storage/index.d.ts +1 -1
- package/dist/storage/index.d.ts.map +1 -1
- package/dist/storage/list.js +1 -1
- package/dist/storage/list.js.map +1 -1
- package/dist/storage/sandbox/rules-evaluation-error.d.ts +25 -0
- package/dist/storage/sandbox/rules-evaluation-error.d.ts.map +1 -1
- package/dist/storage/sandbox/rules-evaluation-error.js +29 -0
- package/dist/storage/sandbox/rules-evaluation-error.js.map +1 -1
- package/dist/storage/sandbox/rules-evaluator.d.ts +10 -5
- package/dist/storage/sandbox/rules-evaluator.d.ts.map +1 -1
- package/dist/storage/sandbox/rules-evaluator.js +105 -33
- package/dist/storage/sandbox/rules-evaluator.js.map +1 -1
- package/dist/storage/sandbox/rules-methods.d.ts.map +1 -1
- package/dist/storage/sandbox/rules-methods.js +17 -7
- package/dist/storage/sandbox/rules-methods.js.map +1 -1
- package/dist/storage/service.d.ts +23 -2
- package/dist/storage/service.d.ts.map +1 -1
- package/dist/storage/service.js +36 -26
- package/dist/storage/service.js.map +1 -1
- package/package.json +41 -1
- package/src/ai/blocked.ts +97 -0
- package/src/ai/broker/broker.ts +88 -0
- package/src/ai/broker/gemini-engine.ts +36 -9
- package/src/ai/broker/index.ts +2 -1
- package/src/ai/broker/openai-engine.ts +31 -3
- package/src/ai/broker/synthesizer.ts +34 -0
- package/src/ai/broker/types.ts +25 -0
- package/src/ai/internal.ts +5 -0
- package/src/ai/response-helpers.ts +6 -25
- package/src/analytics/index.ts +53 -0
- package/src/app/dispatch.test.ts +3 -1
- package/src/app-check/index.ts +41 -0
- package/src/database/controls.ts +1 -1
- package/src/database/sandbox/rules-eval.ts +2 -2
- package/src/database/sandbox/write-plane.ts +2 -2
- package/src/database/sandbox-controls.ts +29 -9
- package/src/deferred/entry.ts +167 -0
- package/src/firestore/lite.ts +91 -0
- package/src/firestore/persistence.ts +2 -2
- package/src/functions/index.ts +38 -0
- package/src/performance/index.ts +31 -0
- package/src/remote-config/index.ts +53 -0
- package/src/rules/grammar/FirestoreValidator.ts +44 -28
- package/src/rules/grammar/document-access-count.ts +75 -0
- package/src/rules/linter/ast-utils.ts +2 -36
- package/src/rules/linter/hallucinations.ts +123 -25
- package/src/rules/linter/linter.ts +32 -10
- package/src/rules/rtdb/grammar/simulator.ts +12 -13
- package/src/rules/rtdb/simulation/handler.ts +149 -46
- package/src/rules/simulator/document-lookups.ts +46 -3
- package/src/rules/simulator/eval-error.ts +16 -0
- package/src/rules/simulator/evaluation-builtins.ts +35 -8
- package/src/rules/simulator/evaluation-context.ts +12 -0
- package/src/rules/simulator/evaluator.ts +14 -3
- package/src/rules/simulator/handler.ts +68 -4
- package/src/rules/simulator/lookup-budget.ts +101 -0
- package/src/rules/stdlib-modules.ts +19 -11
- package/src/sandbox/admin-firestore/get-firestore.ts +19 -3
- package/src/sandbox/index.ts +5 -1
- package/src/sandbox/persistence/types.ts +1 -1
- package/src/sandbox/remote.ts +2 -2
- package/src/sandbox/sandbox-context.ts +69 -9
- package/src/sandbox/types/auth-state.ts +1 -1
- package/src/sandbox/types/events.ts +2 -1
- package/src/sandbox/types/operation.ts +1 -1
- package/src/storage/enforce.ts +53 -14
- package/src/storage/index.ts +1 -1
- package/src/storage/list.ts +1 -1
- package/src/storage/sandbox/rules-evaluation-error.ts +32 -0
- package/src/storage/sandbox/rules-evaluator.ts +109 -32
- package/src/storage/sandbox/rules-methods.ts +21 -7
- package/src/storage/service.ts +92 -27
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `pyric/firestore/lite` — a DEFERRED mirror of `firebase/firestore/lite`.
|
|
3
|
+
*
|
|
4
|
+
* The Lite SDK is a separate build of Firestore with no local cache, no
|
|
5
|
+
* listeners and no offline queue. pyric mirrors the full `firebase/firestore`
|
|
6
|
+
* surface against the in-process sandbox; the Lite build needs its own
|
|
7
|
+
* cache-free instance identity, so it is deferred rather than aliased — an
|
|
8
|
+
* alias would silently give Lite consumers listener-backed semantics the real
|
|
9
|
+
* Lite SDK does not have.
|
|
10
|
+
*
|
|
11
|
+
* Every symbol below resolves and links so an app that swaps `firebase` for
|
|
12
|
+
* `pyric` still loads; touching one throws `PyricDeferredApiError` naming this
|
|
13
|
+
* subpath. See `../deferred/entry.ts` for the full rationale.
|
|
14
|
+
*
|
|
15
|
+
* The value list is the exact public runtime surface of `firebase/firestore/lite`
|
|
16
|
+
* (Firebase Web SDK 12.13.0). Keep it in sync when this entry graduates to a
|
|
17
|
+
* real mirror.
|
|
18
|
+
*/
|
|
19
|
+
import { deferredEntry, type DeferredApi } from '../deferred/entry.js';
|
|
20
|
+
|
|
21
|
+
export { PyricDeferredApiError } from '../deferred/entry.js';
|
|
22
|
+
|
|
23
|
+
export const {
|
|
24
|
+
AggregateField, AggregateQuerySnapshot, Bytes, CollectionReference, DocumentReference,
|
|
25
|
+
DocumentSnapshot, FieldPath, FieldValue, Firestore, FirestoreError, GeoPoint, Query,
|
|
26
|
+
QueryCompositeFilterConstraint, QueryConstraint, QueryDocumentSnapshot, QueryEndAtConstraint,
|
|
27
|
+
QueryFieldFilterConstraint, QueryLimitConstraint, QueryOrderByConstraint, QuerySnapshot,
|
|
28
|
+
QueryStartAtConstraint, Timestamp, Transaction, VectorValue, WriteBatch, addDoc,
|
|
29
|
+
aggregateFieldEqual, aggregateQuerySnapshotEqual, and, arrayRemove, arrayUnion, average,
|
|
30
|
+
collection, collectionGroup, connectFirestoreEmulator, count, deleteDoc, deleteField, doc,
|
|
31
|
+
documentId, endAt, endBefore, getAggregate, getCount, getDoc, getDocs, getFirestore,
|
|
32
|
+
increment, initializeFirestore, limit, limitToLast, or, orderBy, query, queryEqual, refEqual,
|
|
33
|
+
runTransaction, serverTimestamp, setDoc, setLogLevel, snapshotEqual, startAfter, startAt,
|
|
34
|
+
sum, terminate, updateDoc, vector, where, writeBatch,
|
|
35
|
+
} = deferredEntry('firestore/lite');
|
|
36
|
+
|
|
37
|
+
// Type declarations. Aliased to the deferred placeholder so a consumer's own
|
|
38
|
+
// annotations keep type-checking: every deferred call returns `never`, which is
|
|
39
|
+
// assignable to any of these. Names that Firebase exports as a CLASS appear both
|
|
40
|
+
// here and above — a class is a value and a type, and both meanings must survive
|
|
41
|
+
// the swap.
|
|
42
|
+
export type AddPrefixToKeys = DeferredApi;
|
|
43
|
+
export type AggregateField = DeferredApi;
|
|
44
|
+
export type AggregateFieldType = DeferredApi;
|
|
45
|
+
export type AggregateQuerySnapshot = DeferredApi;
|
|
46
|
+
export type AggregateSpec = DeferredApi;
|
|
47
|
+
export type AggregateSpecData = DeferredApi;
|
|
48
|
+
export type AggregateType = DeferredApi;
|
|
49
|
+
export type Bytes = DeferredApi;
|
|
50
|
+
export type ChildUpdateFields = DeferredApi;
|
|
51
|
+
export type CollectionReference = DeferredApi;
|
|
52
|
+
export type DocumentData = DeferredApi;
|
|
53
|
+
export type DocumentReference = DeferredApi;
|
|
54
|
+
export type DocumentSnapshot = DeferredApi;
|
|
55
|
+
export type EmulatorMockTokenOptions = DeferredApi;
|
|
56
|
+
export type FieldPath = DeferredApi;
|
|
57
|
+
export type FieldValue = DeferredApi;
|
|
58
|
+
export type Firestore = DeferredApi;
|
|
59
|
+
export type FirestoreDataConverter = DeferredApi;
|
|
60
|
+
export type FirestoreError = DeferredApi;
|
|
61
|
+
export type FirestoreErrorCode = DeferredApi;
|
|
62
|
+
export type GeoPoint = DeferredApi;
|
|
63
|
+
export type LogLevel = DeferredApi;
|
|
64
|
+
export type NestedUpdateFields = DeferredApi;
|
|
65
|
+
export type OrderByDirection = DeferredApi;
|
|
66
|
+
export type PartialWithFieldValue = DeferredApi;
|
|
67
|
+
export type Primitive = DeferredApi;
|
|
68
|
+
export type Query = DeferredApi;
|
|
69
|
+
export type QueryCompositeFilterConstraint = DeferredApi;
|
|
70
|
+
export type QueryConstraint = DeferredApi;
|
|
71
|
+
export type QueryConstraintType = DeferredApi;
|
|
72
|
+
export type QueryDocumentSnapshot = DeferredApi;
|
|
73
|
+
export type QueryEndAtConstraint = DeferredApi;
|
|
74
|
+
export type QueryFieldFilterConstraint = DeferredApi;
|
|
75
|
+
export type QueryFilterConstraint = DeferredApi;
|
|
76
|
+
export type QueryLimitConstraint = DeferredApi;
|
|
77
|
+
export type QueryNonFilterConstraint = DeferredApi;
|
|
78
|
+
export type QueryOrderByConstraint = DeferredApi;
|
|
79
|
+
export type QuerySnapshot = DeferredApi;
|
|
80
|
+
export type QueryStartAtConstraint = DeferredApi;
|
|
81
|
+
export type SetOptions = DeferredApi;
|
|
82
|
+
export type Settings = DeferredApi;
|
|
83
|
+
export type Timestamp = DeferredApi;
|
|
84
|
+
export type Transaction = DeferredApi;
|
|
85
|
+
export type TransactionOptions = DeferredApi;
|
|
86
|
+
export type UnionToIntersection = DeferredApi;
|
|
87
|
+
export type UpdateData = DeferredApi;
|
|
88
|
+
export type VectorValue = DeferredApi;
|
|
89
|
+
export type WhereFilterOp = DeferredApi;
|
|
90
|
+
export type WithFieldValue = DeferredApi;
|
|
91
|
+
export type WriteBatch = DeferredApi;
|
|
@@ -191,7 +191,7 @@ const TAB_MANAGER_SYMBOL: unique symbol = Symbol('pyric/firestore/tabManager');
|
|
|
191
191
|
const GC_SYMBOL: unique symbol = Symbol('pyric/firestore/gc');
|
|
192
192
|
|
|
193
193
|
/** Opaque tab-manager config token. Inert — persistence is always on,
|
|
194
|
-
* and the SharedWorker/`pyric
|
|
194
|
+
* and the SharedWorker/`pyric sandbox` path already is the one shared
|
|
195
195
|
* store every tab talks to, so there is no separate multi-tab mode
|
|
196
196
|
* to opt into. Carries the requested kind only for debugging. */
|
|
197
197
|
export interface PersistentTabManager {
|
|
@@ -409,7 +409,7 @@ export type LogLevel = 'debug' | 'verbose' | 'info' | 'warn' | 'error' | 'silent
|
|
|
409
409
|
/**
|
|
410
410
|
* Accepted no-op: the sandbox has no modular-SDK-style logger to wire
|
|
411
411
|
* a level into (it uses host-level `console` logging directly, gated
|
|
412
|
-
* by `pyric
|
|
412
|
+
* by `pyric sandbox`'s own flags, not this call). Exists purely so app
|
|
413
413
|
* code that calls this defensively at startup doesn't crash on a
|
|
414
414
|
* missing export.
|
|
415
415
|
*/
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `pyric/functions` — a DEFERRED mirror of `firebase/functions`.
|
|
3
|
+
*
|
|
4
|
+
* Callable Cloud Functions dispatch to deployed server code. Mirroring this
|
|
5
|
+
* means running the user’s functions, which is the emulator’s job, not the
|
|
6
|
+
* in-process sandbox’s — deferred pending a decision on the function-host
|
|
7
|
+
* seam.
|
|
8
|
+
*
|
|
9
|
+
* Every symbol below resolves and links so an app that swaps `firebase` for
|
|
10
|
+
* `pyric` still loads; touching one throws `PyricDeferredApiError` naming this
|
|
11
|
+
* subpath. See `../deferred/entry.ts` for the full rationale.
|
|
12
|
+
*
|
|
13
|
+
* The value list is the exact public runtime surface of `firebase/functions`
|
|
14
|
+
* (Firebase Web SDK 12.13.0). Keep it in sync when this entry graduates to a
|
|
15
|
+
* real mirror.
|
|
16
|
+
*/
|
|
17
|
+
import { deferredEntry, type DeferredApi } from '../deferred/entry.js';
|
|
18
|
+
|
|
19
|
+
export { PyricDeferredApiError } from '../deferred/entry.js';
|
|
20
|
+
|
|
21
|
+
export const {
|
|
22
|
+
FunctionsError, connectFunctionsEmulator, getFunctions, httpsCallable, httpsCallableFromURL,
|
|
23
|
+
} = deferredEntry('functions');
|
|
24
|
+
|
|
25
|
+
// Type declarations. Aliased to the deferred placeholder so a consumer's own
|
|
26
|
+
// annotations keep type-checking: every deferred call returns `never`, which is
|
|
27
|
+
// assignable to any of these. Names that Firebase exports as a CLASS appear both
|
|
28
|
+
// here and above — a class is a value and a type, and both meanings must survive
|
|
29
|
+
// the swap.
|
|
30
|
+
export type Functions = DeferredApi;
|
|
31
|
+
export type FunctionsError = DeferredApi;
|
|
32
|
+
export type FunctionsErrorCode = DeferredApi;
|
|
33
|
+
export type FunctionsErrorCodeCore = DeferredApi;
|
|
34
|
+
export type HttpsCallable = DeferredApi;
|
|
35
|
+
export type HttpsCallableOptions = DeferredApi;
|
|
36
|
+
export type HttpsCallableResult = DeferredApi;
|
|
37
|
+
export type HttpsCallableStreamOptions = DeferredApi;
|
|
38
|
+
export type HttpsCallableStreamResult = DeferredApi;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `pyric/performance` — a DEFERRED mirror of `firebase/performance`.
|
|
3
|
+
*
|
|
4
|
+
* Performance Monitoring instruments real network and render timings and
|
|
5
|
+
* ships them to Google. Nothing about it is locally observable, so it is
|
|
6
|
+
* deferred.
|
|
7
|
+
*
|
|
8
|
+
* Every symbol below resolves and links so an app that swaps `firebase` for
|
|
9
|
+
* `pyric` still loads; touching one throws `PyricDeferredApiError` naming this
|
|
10
|
+
* subpath. See `../deferred/entry.ts` for the full rationale.
|
|
11
|
+
*
|
|
12
|
+
* The value list is the exact public runtime surface of `firebase/performance`
|
|
13
|
+
* (Firebase Web SDK 12.13.0). Keep it in sync when this entry graduates to a
|
|
14
|
+
* real mirror.
|
|
15
|
+
*/
|
|
16
|
+
import { deferredEntry, type DeferredApi } from '../deferred/entry.js';
|
|
17
|
+
|
|
18
|
+
export { PyricDeferredApiError } from '../deferred/entry.js';
|
|
19
|
+
|
|
20
|
+
export const {
|
|
21
|
+
getPerformance, initializePerformance, trace,
|
|
22
|
+
} = deferredEntry('performance');
|
|
23
|
+
|
|
24
|
+
// Type declarations. Aliased to the deferred placeholder so a consumer's own
|
|
25
|
+
// annotations keep type-checking: every deferred call returns `never`, which is
|
|
26
|
+
// assignable to any of these. Names that Firebase exports as a CLASS appear both
|
|
27
|
+
// here and above — a class is a value and a type, and both meanings must survive
|
|
28
|
+
// the swap.
|
|
29
|
+
export type FirebasePerformance = DeferredApi;
|
|
30
|
+
export type PerformanceSettings = DeferredApi;
|
|
31
|
+
export type PerformanceTrace = DeferredApi;
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `pyric/remote-config` — a DEFERRED mirror of `firebase/remote-config`.
|
|
3
|
+
*
|
|
4
|
+
* Remote Config serves server-side parameter values with fetch/activate
|
|
5
|
+
* caching semantics. Mirroring it needs a sandbox-side config store and a
|
|
6
|
+
* model of the fetch throttle — buildable, not yet built.
|
|
7
|
+
*
|
|
8
|
+
* Every symbol below resolves and links so an app that swaps `firebase` for
|
|
9
|
+
* `pyric` still loads; touching one throws `PyricDeferredApiError` naming this
|
|
10
|
+
* subpath. See `../deferred/entry.ts` for the full rationale.
|
|
11
|
+
*
|
|
12
|
+
* The value list is the exact public runtime surface of `firebase/remote-config`
|
|
13
|
+
* (Firebase Web SDK 12.13.0). Keep it in sync when this entry graduates to a
|
|
14
|
+
* real mirror.
|
|
15
|
+
*/
|
|
16
|
+
import { deferredEntry, type DeferredApi } from '../deferred/entry.js';
|
|
17
|
+
|
|
18
|
+
export { PyricDeferredApiError } from '../deferred/entry.js';
|
|
19
|
+
|
|
20
|
+
export const {
|
|
21
|
+
activate, ensureInitialized, fetchAndActivate, fetchConfig, getAll, getBoolean, getNumber,
|
|
22
|
+
getRemoteConfig, getString, getValue, onConfigUpdate, setCustomSignals,
|
|
23
|
+
setLogLevel,
|
|
24
|
+
} = deferredEntry('remote-config');
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* The one deferred symbol that answers instead of throwing: the real SDK
|
|
28
|
+
* resolves a boolean, and a deferred entry IS unsupported, so the standard
|
|
29
|
+
* `isSupported().then(ok => ok && get…(app))` guard must run — not crash.
|
|
30
|
+
*/
|
|
31
|
+
export const isSupported = async (): Promise<boolean> => false;
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
// Type declarations. Aliased to the deferred placeholder so a consumer's own
|
|
35
|
+
// annotations keep type-checking: every deferred call returns `never`, which is
|
|
36
|
+
// assignable to any of these. Names that Firebase exports as a CLASS appear both
|
|
37
|
+
// here and above — a class is a value and a type, and both meanings must survive
|
|
38
|
+
// the swap.
|
|
39
|
+
export type ConfigUpdate = DeferredApi;
|
|
40
|
+
export type ConfigUpdateObserver = DeferredApi;
|
|
41
|
+
export type CustomSignals = DeferredApi;
|
|
42
|
+
export type FetchResponse = DeferredApi;
|
|
43
|
+
export type FetchStatus = DeferredApi;
|
|
44
|
+
export type FetchType = DeferredApi;
|
|
45
|
+
export type FirebaseExperimentDescription = DeferredApi;
|
|
46
|
+
export type FirebaseRemoteConfigObject = DeferredApi;
|
|
47
|
+
export type LogLevel = DeferredApi;
|
|
48
|
+
export type RemoteConfig = DeferredApi;
|
|
49
|
+
export type RemoteConfigOptions = DeferredApi;
|
|
50
|
+
export type RemoteConfigSettings = DeferredApi;
|
|
51
|
+
export type Unsubscribe = DeferredApi;
|
|
52
|
+
export type Value = DeferredApi;
|
|
53
|
+
export type ValueSource = DeferredApi;
|
|
@@ -2,6 +2,7 @@ import type {
|
|
|
2
2
|
FirestoreRules, MatchBlock, AllowRule, FunctionDef, Expression, Operation,
|
|
3
3
|
} from './FirestoreAST.js';
|
|
4
4
|
import { RULES_BUILTIN_FUNCTIONS } from './builtin-functions.js';
|
|
5
|
+
import { countDocumentAccessCalls } from './document-access-count.js';
|
|
5
6
|
|
|
6
7
|
export interface ValidationFinding {
|
|
7
8
|
code: string;
|
|
@@ -26,8 +27,9 @@ export function validateFirestoreRules(ast: FirestoreRules): ValidationFinding[]
|
|
|
26
27
|
// SEC-4: Check for default deny
|
|
27
28
|
checkDefaultDeny(rootMatch, findings);
|
|
28
29
|
|
|
29
|
-
// QUA-3: Duplicate function names
|
|
30
|
-
|
|
30
|
+
// QUA-3: Duplicate function names in one scope (production compile
|
|
31
|
+
// rejection, so critical). Nested shadowing is legal and is not flagged.
|
|
32
|
+
checkDuplicateFunctions(ast, findings);
|
|
31
33
|
|
|
32
34
|
// QUA-4: Unused functions
|
|
33
35
|
checkUnusedFunctions(rootMatch, allCalls, findings);
|
|
@@ -124,12 +126,15 @@ function walkMatch(
|
|
|
124
126
|
});
|
|
125
127
|
}
|
|
126
128
|
|
|
127
|
-
// SEM-3:
|
|
128
|
-
|
|
129
|
+
// SEM-3: document access budget exceeded. Production allows exactly 10
|
|
130
|
+
// get/exists/getAfter/existsAfter reads per request evaluation; the
|
|
131
|
+
// 11th fails, so the finding fires only ABOVE 10 (same boundary as the
|
|
132
|
+
// linter's GET_COUNT error and the simulator's runtime LookupBudget).
|
|
133
|
+
const docReads = countDocumentAccessCalls(cond, fnMap);
|
|
129
134
|
if (docReads > 10) {
|
|
130
135
|
findings.push({
|
|
131
136
|
code: 'SEM-3', severity: 'high', path: pathStr, operation: opStr,
|
|
132
|
-
message: `Rule at ${pathStr}
|
|
137
|
+
message: `Rule at ${pathStr} may perform ${docReads} document access calls (get/exists/getAfter/existsAfter), which exceeds the 10-call budget`,
|
|
133
138
|
});
|
|
134
139
|
}
|
|
135
140
|
|
|
@@ -323,21 +328,6 @@ function referencesResourceData(expr: Expression): boolean {
|
|
|
323
328
|
);
|
|
324
329
|
}
|
|
325
330
|
|
|
326
|
-
function countDocReads(expr: Expression, functions: Map<string, FunctionDef>, visited = new Set<string>()): number {
|
|
327
|
-
let count = 0;
|
|
328
|
-
walkExpr(expr, e => {
|
|
329
|
-
if (e.type === 'functionCall' && (e.name === 'get' || e.name === 'exists' || e.name === 'getAfter')) {
|
|
330
|
-
count++;
|
|
331
|
-
}
|
|
332
|
-
// Follow user-defined function calls
|
|
333
|
-
if (e.type === 'functionCall' && functions.has(e.name) && !visited.has(e.name)) {
|
|
334
|
-
visited.add(e.name);
|
|
335
|
-
count += countDocReads(functions.get(e.name)!.body, functions, visited);
|
|
336
|
-
}
|
|
337
|
-
});
|
|
338
|
-
return count;
|
|
339
|
-
}
|
|
340
|
-
|
|
341
331
|
function collectFunctionCalls(expr: Expression): string[] {
|
|
342
332
|
const calls: string[] = [];
|
|
343
333
|
walkExpr(expr, e => {
|
|
@@ -357,22 +347,48 @@ function collectAllFunctions(match: MatchBlock): Set<string> {
|
|
|
357
347
|
}
|
|
358
348
|
|
|
359
349
|
// ---- QUA-3: Duplicate functions ----
|
|
350
|
+
//
|
|
351
|
+
// Production REJECTS two declarations of one function name in the SAME
|
|
352
|
+
// scope at compile time, so this is severity 'critical': the write gate
|
|
353
|
+
// (`write/handler.ts`) blocks only critical validator findings, and
|
|
354
|
+
// 'medium' folded to a mere warning that deployed anyway.
|
|
355
|
+
//
|
|
356
|
+
// A scope is one declaration list: the global list above `service`, the
|
|
357
|
+
// list directly inside `service`, or one match block's own list. A nested
|
|
358
|
+
// match block that redeclares a name from an enclosing scope SHADOWS it and
|
|
359
|
+
// is legal: the simulator implements shadowing in
|
|
360
|
+
// `simulator/match-resolution.ts`, and the production capture in
|
|
361
|
+
// `conformance/rules-corpus/storage/function-scopes-and-shadowing.ts` pins
|
|
362
|
+
// inner-shadows-outer as accepted. Flagging that would block a ruleset
|
|
363
|
+
// production deploys.
|
|
364
|
+
//
|
|
365
|
+
// The code stays QUA-3 (already registered and asserted by consumers);
|
|
366
|
+
// `DUPLICATE_FUNCTION` was considered and rejected, because the module
|
|
367
|
+
// resolver already uses that name for its own error code
|
|
368
|
+
// (`modules/resolver-core.ts`), and colliding would make mixed issue
|
|
369
|
+
// lists ambiguous.
|
|
370
|
+
|
|
371
|
+
function checkDuplicateFunctions(ast: FirestoreRules, findings: ValidationFinding[]) {
|
|
372
|
+
checkDupsInScope(ast.functions ?? [], 'global scope', findings);
|
|
373
|
+
checkDupsInScope(ast.service.functions ?? [], `service ${ast.service.name}`, findings);
|
|
374
|
+
checkDupsInMatchScopes(ast.service.match, findings);
|
|
375
|
+
}
|
|
360
376
|
|
|
361
|
-
function
|
|
377
|
+
function checkDupsInMatchScopes(match: MatchBlock, findings: ValidationFinding[]) {
|
|
362
378
|
checkDupsInScope(match.functions, match.path.raw, findings);
|
|
363
|
-
for (const child of match.children)
|
|
379
|
+
for (const child of match.children) checkDupsInMatchScopes(child, findings);
|
|
364
380
|
}
|
|
365
381
|
|
|
366
|
-
function checkDupsInScope(fns: FunctionDef[],
|
|
367
|
-
const
|
|
382
|
+
function checkDupsInScope(fns: readonly FunctionDef[], scope: string, findings: ValidationFinding[]) {
|
|
383
|
+
const declared = new Set<string>();
|
|
368
384
|
for (const fn of fns) {
|
|
369
|
-
if (
|
|
385
|
+
if (declared.has(fn.name)) {
|
|
370
386
|
findings.push({
|
|
371
|
-
code: 'QUA-3', severity: '
|
|
372
|
-
message: `Duplicate function '${fn.name}' in scope at
|
|
387
|
+
code: 'QUA-3', severity: 'critical', path: scope,
|
|
388
|
+
message: `Duplicate function '${fn.name}' declared twice in ${scope}. Production rejects duplicate function declarations in one scope at compile time`,
|
|
373
389
|
});
|
|
374
390
|
}
|
|
375
|
-
|
|
391
|
+
declared.add(fn.name);
|
|
376
392
|
}
|
|
377
393
|
}
|
|
378
394
|
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import type { Expression, FunctionDef } from './FirestoreAST.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* The four built-in document access calls production counts against a
|
|
5
|
+
* request's 10-read budget.
|
|
6
|
+
*/
|
|
7
|
+
const DOCUMENT_ACCESS_BUILTINS = new Set(['get', 'exists', 'getAfter', 'existsAfter']);
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Count the document access calls (get/exists/getAfter/existsAfter)
|
|
11
|
+
* reachable from a rule condition, expanding each user-defined function
|
|
12
|
+
* once PER CALL SITE. `isOwner(a) && isOwner(b) && isOwner(c)` with three
|
|
13
|
+
* gets inside `isOwner` costs nine, matching production where each call
|
|
14
|
+
* performs its own reads (different arguments mean different paths).
|
|
15
|
+
* A function's `let` bindings evaluate on every call, so their reads count
|
|
16
|
+
* too. The call stack guards recursion only, and entries unwind on return,
|
|
17
|
+
* so sibling call sites each pay full price.
|
|
18
|
+
*
|
|
19
|
+
* This is a static over-approximation: production caches repeated reads of
|
|
20
|
+
* the SAME path within a request (see site-docs
|
|
21
|
+
* secure/firestore-rules-limits.md), but path identity is not decidable
|
|
22
|
+
* statically, so every call site is charged. The cache-aware, distinct-path
|
|
23
|
+
* count is the runtime concern of LookupBudget in
|
|
24
|
+
* simulator/lookup-budget.ts, which counts what an evaluation actually
|
|
25
|
+
* reads rather than what a condition could reach.
|
|
26
|
+
*
|
|
27
|
+
* This is the single walker behind both static consumers: the validator's
|
|
28
|
+
* SEM-3 finding and the linter's GET_COUNT warning.
|
|
29
|
+
*/
|
|
30
|
+
export function countDocumentAccessCalls(
|
|
31
|
+
expr: Expression,
|
|
32
|
+
functions: Map<string, FunctionDef>,
|
|
33
|
+
callStack: Set<string> = new Set<string>(),
|
|
34
|
+
): number {
|
|
35
|
+
let count = 0;
|
|
36
|
+
|
|
37
|
+
const visit = (e: Expression): void => {
|
|
38
|
+
switch (e.type) {
|
|
39
|
+
case 'functionCall':
|
|
40
|
+
if (DOCUMENT_ACCESS_BUILTINS.has(e.name)) {
|
|
41
|
+
count++;
|
|
42
|
+
} else {
|
|
43
|
+
const fn = functions.get(e.name);
|
|
44
|
+
const isExpandable = fn !== undefined && !callStack.has(e.name);
|
|
45
|
+
if (isExpandable) {
|
|
46
|
+
callStack.add(e.name);
|
|
47
|
+
for (const binding of fn!.lets) visit(binding.value);
|
|
48
|
+
visit(fn!.body);
|
|
49
|
+
callStack.delete(e.name); // unwind: count once per call site, not once per rule
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
e.args.forEach(visit);
|
|
53
|
+
break;
|
|
54
|
+
case 'binaryOp': visit(e.left); visit(e.right); break;
|
|
55
|
+
case 'unaryOp': visit(e.operand); break;
|
|
56
|
+
case 'ternary': visit(e.condition); visit(e.consequent); visit(e.alternate); break;
|
|
57
|
+
case 'methodCall': visit(e.object); e.args.forEach(visit); break;
|
|
58
|
+
case 'memberAccess': visit(e.object); break;
|
|
59
|
+
case 'bracketAccess': visit(e.object); visit(e.index); break;
|
|
60
|
+
case 'sliceAccess': visit(e.object); visit(e.start); visit(e.end); break;
|
|
61
|
+
case 'inExpr': visit(e.element); visit(e.collection); break;
|
|
62
|
+
case 'isExpr': visit(e.value); break;
|
|
63
|
+
case 'listLiteral': e.elements.forEach(visit); break;
|
|
64
|
+
case 'mapLiteral': e.entries.forEach((entry) => { visit(entry.key); visit(entry.value); }); break;
|
|
65
|
+
case 'pathLiteral':
|
|
66
|
+
for (const segment of e.segments) {
|
|
67
|
+
if (typeof segment !== 'string') visit(segment);
|
|
68
|
+
}
|
|
69
|
+
break;
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
visit(expr);
|
|
74
|
+
return count;
|
|
75
|
+
}
|
|
@@ -218,44 +218,10 @@ export function maxCallDepth(start: string, graph: Map<string, string[]>, visite
|
|
|
218
218
|
return 1 + max;
|
|
219
219
|
}
|
|
220
220
|
|
|
221
|
-
/**
|
|
222
|
-
* Count get() and exists() calls reachable from an expression,
|
|
223
|
-
* following function calls transitively.
|
|
224
|
-
*/
|
|
225
|
-
export function countGetCalls(expr: Expression, functions: Map<string, FunctionDef>, visited = new Set<string>()): number {
|
|
226
|
-
let count = 0;
|
|
227
|
-
const walk = (e: Expression) => {
|
|
228
|
-
switch (e.type) {
|
|
229
|
-
case 'functionCall':
|
|
230
|
-
if (e.name === 'get' || e.name === 'exists') {
|
|
231
|
-
count++;
|
|
232
|
-
} else if (functions.has(e.name) && !visited.has(e.name)) {
|
|
233
|
-
visited.add(e.name);
|
|
234
|
-
const fn = functions.get(e.name)!;
|
|
235
|
-
walk(fn.body);
|
|
236
|
-
for (const b of fn.lets) walk(b.value);
|
|
237
|
-
}
|
|
238
|
-
e.args.forEach(walk);
|
|
239
|
-
break;
|
|
240
|
-
case 'binaryOp': walk(e.left); walk(e.right); break;
|
|
241
|
-
case 'unaryOp': walk(e.operand); break;
|
|
242
|
-
case 'methodCall': walk(e.object); e.args.forEach(walk); break;
|
|
243
|
-
case 'memberAccess': walk(e.object); break;
|
|
244
|
-
case 'bracketAccess': walk(e.object); walk(e.index); break;
|
|
245
|
-
case 'ternary': walk(e.condition); walk(e.consequent); walk(e.alternate); break;
|
|
246
|
-
case 'inExpr': walk(e.element); walk(e.collection); break;
|
|
247
|
-
case 'isExpr': walk(e.value); break;
|
|
248
|
-
case 'listLiteral': e.elements.forEach(walk); break;
|
|
249
|
-
case 'mapLiteral': e.entries.forEach(en => { walk(en.key); walk(en.value); }); break;
|
|
250
|
-
}
|
|
251
|
-
};
|
|
252
|
-
walk(expr);
|
|
253
|
-
return count;
|
|
254
|
-
}
|
|
255
|
-
|
|
256
221
|
/**
|
|
257
222
|
* Count how many times each user-defined function is called in an expression.
|
|
258
|
-
*
|
|
223
|
+
* Counts raw call-site occurrences at the top level only: it does not expand
|
|
224
|
+
* nested user-function bodies the way countDocumentAccessCalls does.
|
|
259
225
|
*/
|
|
260
226
|
export function countFunctionCallSites(expr: Expression, fnNames: Set<string>): Map<string, number> {
|
|
261
227
|
const counts = new Map<string, number>();
|