@dereekb/firebase 13.31.0 → 13.33.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/package.json +3 -3
- package/index.cjs.js +1913 -765
- package/index.esm.js +1858 -768
- package/package.json +5 -5
- package/src/lib/common/firestore/snapshot/snapshot.field.d.ts +59 -4
- package/src/lib/model/index.d.ts +1 -0
- package/src/lib/model/notification/index.d.ts +2 -0
- package/src/lib/model/notification/notification.api.d.ts +102 -0
- package/src/lib/model/notification/notification.api.error.d.ts +15 -0
- package/src/lib/model/notification/notification.d.ts +11 -0
- package/src/lib/model/notification/notification.healthcheck.d.ts +616 -0
- package/src/lib/model/notification/notification.healthcheck.mailgun.d.ts +57 -0
- package/src/lib/model/userexternalconnection/index.d.ts +6 -0
- package/src/lib/model/userexternalconnection/userexternalconnection.action.d.ts +21 -0
- package/src/lib/model/userexternalconnection/userexternalconnection.api.d.ts +120 -0
- package/src/lib/model/userexternalconnection/userexternalconnection.d.ts +191 -0
- package/src/lib/model/userexternalconnection/userexternalconnection.id.d.ts +51 -0
- package/src/lib/model/userexternalconnection/userexternalconnection.query.d.ts +19 -0
- package/src/lib/model/userexternalconnection/userexternalconnection.util.d.ts +149 -0
- package/test/index.cjs.js +371 -50
- package/test/index.esm.js +362 -51
- package/test/package.json +6 -6
- package/test/src/lib/client/firebase.rules.d.ts +114 -0
- package/test/src/lib/client/index.d.ts +1 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { type AsyncFirebaseFunctionUpdateAction, type FirebaseFunctionUpdateAction } from '../../common';
|
|
2
|
+
import { type UserExternalConnectionDocument } from './userexternalconnection';
|
|
3
|
+
/**
|
|
4
|
+
* @module userexternalconnection.action
|
|
5
|
+
*
|
|
6
|
+
* Type aliases for UserExternalConnection server action functions.
|
|
7
|
+
*
|
|
8
|
+
* NOTE: there are no create/delete action aliases here on purpose. The document pair is only ever
|
|
9
|
+
* mutated through the paired per-provider connect/update/disconnect operations in
|
|
10
|
+
* `@dereekb/firebase-server/model`, which create and remove the documents themselves.
|
|
11
|
+
*
|
|
12
|
+
* @template P - the API parameter type for the action
|
|
13
|
+
*/
|
|
14
|
+
/**
|
|
15
|
+
* Synchronous update action targeting a {@link UserExternalConnectionDocument}.
|
|
16
|
+
*/
|
|
17
|
+
export type UserExternalConnectionUpdateAction<P extends object> = FirebaseFunctionUpdateAction<P, UserExternalConnectionDocument>;
|
|
18
|
+
/**
|
|
19
|
+
* Async update action targeting a {@link UserExternalConnectionDocument}.
|
|
20
|
+
*/
|
|
21
|
+
export type AsyncUserExternalConnectionUpdateAction<P extends object> = AsyncFirebaseFunctionUpdateAction<P, UserExternalConnectionDocument>;
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import { type Type } from 'arktype';
|
|
2
|
+
import { type InferredTargetModelParams } from '../../common/model/model/model.param';
|
|
3
|
+
import { type FirebaseFunctionTypeConfigMap, type ModelFirebaseCreateFunction, type ModelFirebaseCrudFunction, type ModelFirebaseCrudFunctionConfigMap, type ModelFirebaseFunctionMap } from '../../client';
|
|
4
|
+
import { type UserExternalConnectionTypes } from './userexternalconnection';
|
|
5
|
+
import { type UserExternalConnectionProviderType } from './userexternalconnection.id';
|
|
6
|
+
/**
|
|
7
|
+
* Parameters for creating the calling user's connection document.
|
|
8
|
+
*
|
|
9
|
+
* Deliberately empty: the document is keyed by uid, so there is nothing to target and nothing to
|
|
10
|
+
* seed it with — providers arrive one at a time through the OAuth flow, never at creation.
|
|
11
|
+
*
|
|
12
|
+
* @dbxModelApiParams
|
|
13
|
+
*/
|
|
14
|
+
export interface CreateUserExternalConnectionParams {
|
|
15
|
+
}
|
|
16
|
+
export declare const createUserExternalConnectionParamsType: Type<CreateUserExternalConnectionParams>;
|
|
17
|
+
/**
|
|
18
|
+
* Parameters for disconnecting the current user from a third-party provider.
|
|
19
|
+
*
|
|
20
|
+
* This is the ONLY write path a client has to the connection pair. There is deliberately no connect
|
|
21
|
+
* or update params type here: connecting requires credentials, which only the server ever sees.
|
|
22
|
+
*
|
|
23
|
+
* If no target model is provided, the current user's connection document is assumed.
|
|
24
|
+
*
|
|
25
|
+
* @dbxModelApiParams
|
|
26
|
+
*/
|
|
27
|
+
export interface DisconnectUserExternalConnectionParams extends InferredTargetModelParams {
|
|
28
|
+
/**
|
|
29
|
+
* The provider type to disconnect from.
|
|
30
|
+
*/
|
|
31
|
+
readonly providerType: UserExternalConnectionProviderType;
|
|
32
|
+
}
|
|
33
|
+
export declare const disconnectUserExternalConnectionParamsType: Type<DisconnectUserExternalConnectionParams>;
|
|
34
|
+
/**
|
|
35
|
+
* Parameters for beginning an OAuth connect handoff for a provider.
|
|
36
|
+
*
|
|
37
|
+
* @dbxModelApiParams
|
|
38
|
+
*/
|
|
39
|
+
export interface ReadUserExternalConnectionAuthorizeStateParams extends InferredTargetModelParams {
|
|
40
|
+
/**
|
|
41
|
+
* The provider type to begin connecting to.
|
|
42
|
+
*/
|
|
43
|
+
readonly providerType: UserExternalConnectionProviderType;
|
|
44
|
+
}
|
|
45
|
+
export declare const readUserExternalConnectionAuthorizeStateParamsType: Type<ReadUserExternalConnectionAuthorizeStateParams>;
|
|
46
|
+
/**
|
|
47
|
+
* The opaque, short-lived `state` to carry through a provider's OAuth handoff.
|
|
48
|
+
*
|
|
49
|
+
* Minting it requires an authenticated call, because a top-level navigation to the provider's
|
|
50
|
+
* authorize endpoint carries no credentials and the server must already know who is connecting. The
|
|
51
|
+
* client's only job is to pass this through — it must never append its ID token to the redirect.
|
|
52
|
+
*/
|
|
53
|
+
export interface UserExternalConnectionAuthorizeStateResult {
|
|
54
|
+
/**
|
|
55
|
+
* The state to send on the authorize request.
|
|
56
|
+
*/
|
|
57
|
+
readonly state: string;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Custom (non-CRUD) function type map for UserExternalConnection. There are none.
|
|
61
|
+
*/
|
|
62
|
+
export type UserExternalConnectionFunctionTypeMap = {};
|
|
63
|
+
export declare const USER_EXTERNAL_CONNECTION_FUNCTION_TYPE_CONFIG_MAP: FirebaseFunctionTypeConfigMap<UserExternalConnectionFunctionTypeMap>;
|
|
64
|
+
/**
|
|
65
|
+
* CRUD function configuration map for the UserExternalConnection model.
|
|
66
|
+
*/
|
|
67
|
+
export type UserExternalConnectionModelCrudFunctionsConfig = {
|
|
68
|
+
readonly userExternalConnection: {
|
|
69
|
+
/**
|
|
70
|
+
* Creates the calling user's connection document.
|
|
71
|
+
*
|
|
72
|
+
* Every other client-reachable operation asserts a role against this document, so it must exist
|
|
73
|
+
* before a user can begin a connect. Creating it is its own call — rather than a side effect of
|
|
74
|
+
* the first connect — so that "may this user have external connections at all?" is decided in
|
|
75
|
+
* one place instead of being folded into the OAuth handoff.
|
|
76
|
+
*
|
|
77
|
+
* Throws when the document already exists.
|
|
78
|
+
*/
|
|
79
|
+
create: CreateUserExternalConnectionParams;
|
|
80
|
+
read: {
|
|
81
|
+
/**
|
|
82
|
+
* Mints the short-lived `state` that begins an OAuth connect handoff for a provider.
|
|
83
|
+
*
|
|
84
|
+
* A read rather than an update: it changes nothing, it just proves who is asking. The app
|
|
85
|
+
* decides how the state is signed and how long it lives.
|
|
86
|
+
*/
|
|
87
|
+
authorizeState: [ReadUserExternalConnectionAuthorizeStateParams, UserExternalConnectionAuthorizeStateResult];
|
|
88
|
+
};
|
|
89
|
+
update: {
|
|
90
|
+
/**
|
|
91
|
+
* Disconnects the current user from the given provider.
|
|
92
|
+
*
|
|
93
|
+
* Removes the provider's credentials and its entry in one transaction, and recomputes the
|
|
94
|
+
* connected-provider array from the result.
|
|
95
|
+
*/
|
|
96
|
+
disconnect: DisconnectUserExternalConnectionParams;
|
|
97
|
+
};
|
|
98
|
+
};
|
|
99
|
+
};
|
|
100
|
+
export declare const USER_EXTERNAL_CONNECTION_MODEL_CRUD_FUNCTIONS_CONFIG: ModelFirebaseCrudFunctionConfigMap<UserExternalConnectionModelCrudFunctionsConfig, UserExternalConnectionTypes>;
|
|
101
|
+
/**
|
|
102
|
+
* Abstract class defining all callable UserExternalConnection cloud functions.
|
|
103
|
+
*
|
|
104
|
+
* Implement this in your app module to wire up the function endpoints.
|
|
105
|
+
*/
|
|
106
|
+
export declare abstract class UserExternalConnectionFunctions implements ModelFirebaseFunctionMap<UserExternalConnectionFunctionTypeMap, UserExternalConnectionModelCrudFunctionsConfig> {
|
|
107
|
+
abstract userExternalConnection: {
|
|
108
|
+
createUserExternalConnection: ModelFirebaseCreateFunction<CreateUserExternalConnectionParams>;
|
|
109
|
+
readUserExternalConnection: {
|
|
110
|
+
authorizeState: ModelFirebaseCrudFunction<ReadUserExternalConnectionAuthorizeStateParams, UserExternalConnectionAuthorizeStateResult>;
|
|
111
|
+
};
|
|
112
|
+
updateUserExternalConnection: {
|
|
113
|
+
disconnect: ModelFirebaseCrudFunction<DisconnectUserExternalConnectionParams>;
|
|
114
|
+
};
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Used to generate the UserExternalConnectionFunctions map for a Functions instance.
|
|
119
|
+
*/
|
|
120
|
+
export declare const userExternalConnectionFunctionMap: import("../..").ModelFirebaseFunctionMapFactory<UserExternalConnectionFunctionTypeMap, UserExternalConnectionModelCrudFunctionsConfig>;
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
import { type Maybe } from '@dereekb/util';
|
|
2
|
+
import { type GrantedReadRole, type GrantedUpdateRole } from '@dereekb/model';
|
|
3
|
+
import { AbstractFirestoreDocument, type CollectionReference, type FirestoreCollection, type FirestoreContext } from '../../common';
|
|
4
|
+
import { type UserRelated, type UserRelatedById } from '../user';
|
|
5
|
+
import { type UserExternalConnectionCapability, type UserExternalConnectionExternalAccountId, type UserExternalConnectionProviderType } from './userexternalconnection.id';
|
|
6
|
+
/**
|
|
7
|
+
* Provides access to the {@link UserExternalConnection} collection.
|
|
8
|
+
*
|
|
9
|
+
* NOTE: the private half of this model pair (`UserExternalConnectionPrivate`) is deliberately NOT
|
|
10
|
+
* declared here. It exists only in `@dereekb/firebase-server/model`, so client-shared code cannot
|
|
11
|
+
* name it.
|
|
12
|
+
*
|
|
13
|
+
* @dbxModelGroup UserExternalConnection
|
|
14
|
+
*/
|
|
15
|
+
export interface UserExternalConnectionFirestoreCollections {
|
|
16
|
+
readonly userExternalConnectionCollection: UserExternalConnectionFirestoreCollection;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Union of all UserExternalConnection model identity types.
|
|
20
|
+
*/
|
|
21
|
+
export type UserExternalConnectionTypes = typeof userExternalConnectionIdentity;
|
|
22
|
+
export declare const userExternalConnectionIdentity: import("../..").RootFirestoreModelIdentity<"userExternalConnection", "uec">;
|
|
23
|
+
/**
|
|
24
|
+
* Status of a single third-party connection.
|
|
25
|
+
*
|
|
26
|
+
* - `connected` — credentials are present and believed usable
|
|
27
|
+
* - `disconnected` — the user (or the server) revoked the connection. Retained only for history.
|
|
28
|
+
* - `error` — the connection exists but the credentials stopped working and need attention
|
|
29
|
+
*/
|
|
30
|
+
export type UserExternalConnectionEntryStatus = 'connected' | 'disconnected' | 'error';
|
|
31
|
+
export declare const USER_EXTERNAL_CONNECTION_ENTRY_STATUSES: UserExternalConnectionEntryStatus[];
|
|
32
|
+
/**
|
|
33
|
+
* Short code describing why an entry is in the `error` status.
|
|
34
|
+
*
|
|
35
|
+
* Deliberately a code and not a message: the UI decides the wording, and a stored message would
|
|
36
|
+
* leak provider internals into a client-readable document.
|
|
37
|
+
*/
|
|
38
|
+
export type UserExternalConnectionErrorCode = 'unauthorized' | 'expired' | 'revoked' | 'insufficient_scope' | 'provider_error' | 'unknown';
|
|
39
|
+
/**
|
|
40
|
+
* Per-provider connection state stored inside a {@link UserExternalConnection}.
|
|
41
|
+
*
|
|
42
|
+
* Every field here is DERIVED by the server from the credentials that were stored alongside it —
|
|
43
|
+
* see `userExternalConnectionEntryForOutcome()`. Nothing on this interface may be supplied directly
|
|
44
|
+
* by a caller, otherwise the summary could contradict the credentials it summarizes.
|
|
45
|
+
*
|
|
46
|
+
* @dbxModelSubObject
|
|
47
|
+
*/
|
|
48
|
+
export interface UserExternalConnectionEntry {
|
|
49
|
+
/**
|
|
50
|
+
* Current status of this connection.
|
|
51
|
+
*
|
|
52
|
+
* @dbxModelVariable status
|
|
53
|
+
*/
|
|
54
|
+
st: UserExternalConnectionEntryStatus;
|
|
55
|
+
/**
|
|
56
|
+
* Capabilities/scopes granted by the provider.
|
|
57
|
+
*
|
|
58
|
+
* @dbxModelVariable capabilities
|
|
59
|
+
*/
|
|
60
|
+
ca?: Maybe<UserExternalConnectionCapability[]>;
|
|
61
|
+
/**
|
|
62
|
+
* Identifier of the connected account within the provider.
|
|
63
|
+
*
|
|
64
|
+
* @dbxModelVariable externalAccountId
|
|
65
|
+
*/
|
|
66
|
+
ea?: Maybe<UserExternalConnectionExternalAccountId>;
|
|
67
|
+
/**
|
|
68
|
+
* Human-readable label for the connected account (e.g. the provider-side email or username).
|
|
69
|
+
*
|
|
70
|
+
* @dbxModelVariable label
|
|
71
|
+
*/
|
|
72
|
+
l?: Maybe<string>;
|
|
73
|
+
/**
|
|
74
|
+
* Date the connection was first established.
|
|
75
|
+
*
|
|
76
|
+
* @dbxModelVariable connectedAt
|
|
77
|
+
*/
|
|
78
|
+
coa?: Maybe<Date>;
|
|
79
|
+
/**
|
|
80
|
+
* Date the current access credentials expire at, when known.
|
|
81
|
+
*
|
|
82
|
+
* @dbxModelVariable expiresAt
|
|
83
|
+
*/
|
|
84
|
+
exa?: Maybe<Date>;
|
|
85
|
+
/**
|
|
86
|
+
* Date this entry was last updated at.
|
|
87
|
+
*
|
|
88
|
+
* @dbxModelVariable updatedAt
|
|
89
|
+
*/
|
|
90
|
+
uat: Date;
|
|
91
|
+
/**
|
|
92
|
+
* Reason the entry is in the `error` status. Cleared on any non-error outcome.
|
|
93
|
+
*
|
|
94
|
+
* @dbxModelVariable errorCode
|
|
95
|
+
*/
|
|
96
|
+
er?: Maybe<UserExternalConnectionErrorCode>;
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Map of provider type to the user's connection state for that provider.
|
|
100
|
+
*/
|
|
101
|
+
export type UserExternalConnectionEntryMap = Record<UserExternalConnectionProviderType, UserExternalConnectionEntry>;
|
|
102
|
+
/**
|
|
103
|
+
* The client-readable half of a user's third-party OAuth connection state.
|
|
104
|
+
*
|
|
105
|
+
* There is exactly ONE of these per user, keyed by uid — per-provider details live inside `e`
|
|
106
|
+
* rather than in separate documents. The server-only half holding the actual access/refresh
|
|
107
|
+
* tokens is `UserExternalConnectionPrivate` in `@dereekb/firebase-server/model`, which shares this
|
|
108
|
+
* document's id.
|
|
109
|
+
*
|
|
110
|
+
* The two documents are NEVER written independently. Every mutation goes through the paired
|
|
111
|
+
* transaction accessor in `@dereekb/firebase-server/model`, which derives everything on this
|
|
112
|
+
* document from the same input that produces the credentials. There is deliberately no sync,
|
|
113
|
+
* reconciliation, or drift-detection process — divergence is unrepresentable rather than detectable.
|
|
114
|
+
*
|
|
115
|
+
* @dbxModel
|
|
116
|
+
* @dbxModelRead owner
|
|
117
|
+
*/
|
|
118
|
+
export interface UserExternalConnection extends UserRelated, UserRelatedById {
|
|
119
|
+
/**
|
|
120
|
+
* Per-provider connection state, keyed by provider type.
|
|
121
|
+
*
|
|
122
|
+
* @dbxModelVariable entries
|
|
123
|
+
*/
|
|
124
|
+
e: UserExternalConnectionEntryMap;
|
|
125
|
+
/**
|
|
126
|
+
* DERIVED from `e`: every provider type whose entry status is `connected`.
|
|
127
|
+
*
|
|
128
|
+
* This exists solely so "which users are connected to X?" stays queryable after collapsing to a
|
|
129
|
+
* single document per user — Firestore cannot query across map keys, but it can `array-contains`
|
|
130
|
+
* this field. It is recomputed from `e` on every write and is never passed in by a caller.
|
|
131
|
+
*
|
|
132
|
+
* Entries in the `disconnected` or `error` status are excluded: a "usable connections" query that
|
|
133
|
+
* returned users whose credentials stopped working would be worse than useless, and
|
|
134
|
+
* `array-contains` cannot filter by status to compensate.
|
|
135
|
+
*
|
|
136
|
+
* @dbxModelVariable connectedProviderTypes
|
|
137
|
+
*/
|
|
138
|
+
c: UserExternalConnectionProviderType[];
|
|
139
|
+
/**
|
|
140
|
+
* Date this document was last updated at.
|
|
141
|
+
*
|
|
142
|
+
* @dbxModelVariable updatedAt
|
|
143
|
+
*/
|
|
144
|
+
uat: Date;
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Roles for a UserExternalConnection. Users can read their own connection state; all writes go
|
|
148
|
+
* through the server.
|
|
149
|
+
*
|
|
150
|
+
* `connect` and `disconnect` are called out separately from `update` because they are the only
|
|
151
|
+
* operations a client can reach, so an app can withhold either one (a user allowed to drop a
|
|
152
|
+
* connection but not to add another, or the reverse) without also withholding the server-driven
|
|
153
|
+
* writes that share `update`.
|
|
154
|
+
*/
|
|
155
|
+
export type UserExternalConnectionRoles = GrantedReadRole | GrantedUpdateRole | 'connect' | 'disconnect';
|
|
156
|
+
export declare class UserExternalConnectionDocument extends AbstractFirestoreDocument<UserExternalConnection, UserExternalConnectionDocument, typeof userExternalConnectionIdentity> {
|
|
157
|
+
get modelIdentity(): import("../..").RootFirestoreModelIdentity<"userExternalConnection", "uec">;
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Field conversions for a {@link UserExternalConnectionEntry}.
|
|
161
|
+
*/
|
|
162
|
+
export declare const userExternalConnectionEntryFields: {
|
|
163
|
+
st: import("../..").FirestoreModelFieldMapFunctionsConfig<UserExternalConnectionEntryStatus, UserExternalConnectionEntryStatus>;
|
|
164
|
+
ca: import("../..").FirestoreModelFieldMapFunctionsConfig<Maybe<string[]>, Maybe<string[]>>;
|
|
165
|
+
ea: import("../..").FirestoreModelFieldMapFunctionsConfig<Maybe<string>, Maybe<string>>;
|
|
166
|
+
l: import("../..").FirestoreModelFieldMapFunctionsConfig<Maybe<string>, Maybe<string>>;
|
|
167
|
+
coa: import("../..").FirestoreModelFieldMapFunctionsConfig<Maybe<Date>, Maybe<string>>;
|
|
168
|
+
exa: import("../..").FirestoreModelFieldMapFunctionsConfig<Maybe<Date>, Maybe<string>>;
|
|
169
|
+
uat: import("../..").FirestoreModelFieldMapFunctionsConfig<Date, string>;
|
|
170
|
+
er: import("../..").FirestoreModelFieldMapFunctionsConfig<Maybe<UserExternalConnectionErrorCode>, Maybe<UserExternalConnectionErrorCode>>;
|
|
171
|
+
};
|
|
172
|
+
export declare const userExternalConnectionConverter: import("../..").SnapshotConverterFunctions<UserExternalConnection, Partial<import("@dereekb/util").ReplaceType<UserExternalConnection, import("@dereekb/util").MaybeMap<object>, any>>>;
|
|
173
|
+
/**
|
|
174
|
+
* Copies the document id into `uid` on write, so the stored uid can never drift from the document id.
|
|
175
|
+
*/
|
|
176
|
+
export declare const userExternalConnectionAccessorFactory: import("../..").InterceptAccessorFactoryFunction<UserExternalConnection, import("../..").DocumentData>;
|
|
177
|
+
/**
|
|
178
|
+
* Returns the root Firestore collection reference for UserExternalConnection documents.
|
|
179
|
+
*
|
|
180
|
+
* @param context - The FirestoreContext used to resolve the collection.
|
|
181
|
+
* @returns A typed CollectionReference for the userExternalConnection collection.
|
|
182
|
+
*/
|
|
183
|
+
export declare function userExternalConnectionCollectionReference(context: FirestoreContext): CollectionReference<UserExternalConnection>;
|
|
184
|
+
export type UserExternalConnectionFirestoreCollection = FirestoreCollection<UserExternalConnection, UserExternalConnectionDocument>;
|
|
185
|
+
/**
|
|
186
|
+
* Creates the Firestore collection accessor for UserExternalConnection documents.
|
|
187
|
+
*
|
|
188
|
+
* @param firestoreContext - The FirestoreContext used to build the collection.
|
|
189
|
+
* @returns A UserExternalConnectionFirestoreCollection.
|
|
190
|
+
*/
|
|
191
|
+
export declare function userExternalConnectionFirestoreCollection(firestoreContext: FirestoreContext): UserExternalConnectionFirestoreCollection;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { type FirestoreModelId, type FirestoreModelKey } from '../../common';
|
|
2
|
+
/**
|
|
3
|
+
* Document id for a {@link UserExternalConnection}.
|
|
4
|
+
*
|
|
5
|
+
* The document id IS the user's Firebase Auth uid. There is exactly one document per user.
|
|
6
|
+
*/
|
|
7
|
+
export type UserExternalConnectionId = FirestoreModelId;
|
|
8
|
+
/**
|
|
9
|
+
* Full Firestore model key path for a {@link UserExternalConnection} document.
|
|
10
|
+
*/
|
|
11
|
+
export type UserExternalConnectionKey = FirestoreModelKey;
|
|
12
|
+
/**
|
|
13
|
+
* String identifier for a third-party service a user can connect their account to.
|
|
14
|
+
*
|
|
15
|
+
* Used as the key of the per-provider entry map on a UserExternalConnection, so it must be a
|
|
16
|
+
* valid Firestore map key (no dots or slashes) and must be identical on the server paths that
|
|
17
|
+
* write the connection and the client paths that render it.
|
|
18
|
+
*/
|
|
19
|
+
export type UserExternalConnectionProviderType = string;
|
|
20
|
+
/**
|
|
21
|
+
* Known third-party services the workspace ships provider support for.
|
|
22
|
+
*/
|
|
23
|
+
export type KnownUserExternalConnectionProviderType = 'calcom' | 'zoom' | 'discord' | 'zoho';
|
|
24
|
+
/**
|
|
25
|
+
* Provider type for Cal.com.
|
|
26
|
+
*
|
|
27
|
+
* Declared here rather than in a server package because the string is the map key on BOTH halves of
|
|
28
|
+
* the connection pair: the server's OAuth controller writes it and the client renders from it, so
|
|
29
|
+
* they must be the same literal.
|
|
30
|
+
*/
|
|
31
|
+
export declare const CALCOM_USER_EXTERNAL_CONNECTION_PROVIDER_TYPE: KnownUserExternalConnectionProviderType;
|
|
32
|
+
/**
|
|
33
|
+
* Provider type for Zoom.
|
|
34
|
+
*/
|
|
35
|
+
export declare const ZOOM_USER_EXTERNAL_CONNECTION_PROVIDER_TYPE: KnownUserExternalConnectionProviderType;
|
|
36
|
+
/**
|
|
37
|
+
* Provider type for Discord.
|
|
38
|
+
*/
|
|
39
|
+
export declare const DISCORD_USER_EXTERNAL_CONNECTION_PROVIDER_TYPE: KnownUserExternalConnectionProviderType;
|
|
40
|
+
/**
|
|
41
|
+
* Provider type for Zoho.
|
|
42
|
+
*/
|
|
43
|
+
export declare const ZOHO_USER_EXTERNAL_CONNECTION_PROVIDER_TYPE: KnownUserExternalConnectionProviderType;
|
|
44
|
+
/**
|
|
45
|
+
* A capability/scope string granted by a third-party provider (e.g. an OAuth scope).
|
|
46
|
+
*/
|
|
47
|
+
export type UserExternalConnectionCapability = string;
|
|
48
|
+
/**
|
|
49
|
+
* Identifier for the connected account within the third-party provider.
|
|
50
|
+
*/
|
|
51
|
+
export type UserExternalConnectionExternalAccountId = string;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { type FirestoreQueryConstraint } from '../../common';
|
|
2
|
+
import { type UserExternalConnectionProviderType } from './userexternalconnection.id';
|
|
3
|
+
/**
|
|
4
|
+
* Query for the UserExternalConnection documents that are currently connected to the given provider.
|
|
5
|
+
*
|
|
6
|
+
* This is the single reason the derived `c` array exists: with one document per user, provider ids
|
|
7
|
+
* are map keys, and Firestore cannot query across map keys.
|
|
8
|
+
*
|
|
9
|
+
* Only `connected` entries are members of `c`, so this never returns a user whose credentials are in
|
|
10
|
+
* the `error` or `disconnected` state.
|
|
11
|
+
*
|
|
12
|
+
* @param providerType - The provider type to search for.
|
|
13
|
+
* @returns Firestore query constraints matching users connected to that provider.
|
|
14
|
+
*
|
|
15
|
+
* @dbxModelFirebaseIndex
|
|
16
|
+
* @dbxModelFirebaseIndexModel UserExternalConnection
|
|
17
|
+
* @dbxModelFirebaseIndexScope COLLECTION
|
|
18
|
+
*/
|
|
19
|
+
export declare function userExternalConnectionsWithConnectedProviderQuery(providerType: UserExternalConnectionProviderType): FirestoreQueryConstraint[];
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import { type Maybe } from '@dereekb/util';
|
|
2
|
+
import { type FirebaseAuthUserId } from '../../common';
|
|
3
|
+
import { type UserExternalConnection, type UserExternalConnectionEntry, type UserExternalConnectionEntryMap, type UserExternalConnectionEntryStatus, type UserExternalConnectionErrorCode } from './userexternalconnection';
|
|
4
|
+
import { type UserExternalConnectionCapability, type UserExternalConnectionExternalAccountId, type UserExternalConnectionProviderType } from './userexternalconnection.id';
|
|
5
|
+
/**
|
|
6
|
+
* The facts about a granted third-party authorization that a {@link UserExternalConnectionEntry} is
|
|
7
|
+
* allowed to summarize.
|
|
8
|
+
*
|
|
9
|
+
* This is projected from the stored credentials by the server (see
|
|
10
|
+
* `userExternalConnectionGrantSummaryFromCredentials` in `@dereekb/firebase-server/model`), never
|
|
11
|
+
* assembled by a caller. That is what makes it impossible for the client-readable summary to claim
|
|
12
|
+
* scopes, an account, or an expiration the credentials do not actually have.
|
|
13
|
+
*/
|
|
14
|
+
export interface UserExternalConnectionGrantSummary {
|
|
15
|
+
readonly scopes?: Maybe<UserExternalConnectionCapability[]>;
|
|
16
|
+
readonly externalAccountId?: Maybe<UserExternalConnectionExternalAccountId>;
|
|
17
|
+
readonly label?: Maybe<string>;
|
|
18
|
+
readonly connectedAt?: Maybe<Date>;
|
|
19
|
+
readonly expiresAt?: Maybe<Date>;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* The SOLE producer of a {@link UserExternalConnection}'s `c` array.
|
|
23
|
+
*
|
|
24
|
+
* Membership is exactly the provider types whose entry status is `connected`. `disconnected` and
|
|
25
|
+
* `error` entries are excluded — the array backs a "which users can I actually call X for?" query,
|
|
26
|
+
* and `array-contains` has no way to filter by status afterwards.
|
|
27
|
+
*
|
|
28
|
+
* @param entries - The per-provider entry map to derive from.
|
|
29
|
+
* @returns The connected provider types, sorted for a stable stored value.
|
|
30
|
+
*/
|
|
31
|
+
export declare function userExternalConnectionConnectedProviderTypes(entries: Maybe<UserExternalConnectionEntryMap>): UserExternalConnectionProviderType[];
|
|
32
|
+
/**
|
|
33
|
+
* Input for {@link userExternalConnectionEntryForOutcome}.
|
|
34
|
+
*
|
|
35
|
+
* NOTE the shape: there is no parameter for any entry field. `ca`/`ea`/`l`/`exa` are copied off the
|
|
36
|
+
* `grant` (which is itself projected from the credentials), and `st`/`coa`/`uat` are computed. A
|
|
37
|
+
* caller has no way to describe a connection the credentials do not support.
|
|
38
|
+
*/
|
|
39
|
+
export interface UserExternalConnectionEntryForOutcomeInput {
|
|
40
|
+
/**
|
|
41
|
+
* The outcome of the operation that produced (or removed) the credentials.
|
|
42
|
+
*/
|
|
43
|
+
readonly outcome: UserExternalConnectionEntryStatus;
|
|
44
|
+
/**
|
|
45
|
+
* Summary of the grant the credentials carry. Required in practice for a `connected` outcome.
|
|
46
|
+
*/
|
|
47
|
+
readonly grant?: Maybe<UserExternalConnectionGrantSummary>;
|
|
48
|
+
/**
|
|
49
|
+
* Reason for an `error` outcome. Defaults to `unknown`.
|
|
50
|
+
*/
|
|
51
|
+
readonly error?: Maybe<UserExternalConnectionErrorCode>;
|
|
52
|
+
/**
|
|
53
|
+
* The entry currently stored for this provider, when there is one.
|
|
54
|
+
*/
|
|
55
|
+
readonly previous?: Maybe<UserExternalConnectionEntry>;
|
|
56
|
+
/**
|
|
57
|
+
* Whether a `disconnected` outcome should retain a history entry rather than removing the key.
|
|
58
|
+
*
|
|
59
|
+
* Defaults to false.
|
|
60
|
+
*/
|
|
61
|
+
readonly retainEntry?: Maybe<boolean>;
|
|
62
|
+
/**
|
|
63
|
+
* The instant the operation is being applied at.
|
|
64
|
+
*/
|
|
65
|
+
readonly now: Date;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Derives the {@link UserExternalConnectionEntry} for an operation's outcome.
|
|
69
|
+
*
|
|
70
|
+
* @param input - The outcome plus the grant it derives from.
|
|
71
|
+
* @returns The next entry, or null when the provider's entry should be REMOVED from the map.
|
|
72
|
+
*/
|
|
73
|
+
export declare function userExternalConnectionEntryForOutcome(input: UserExternalConnectionEntryForOutcomeInput): Maybe<UserExternalConnectionEntry>;
|
|
74
|
+
/**
|
|
75
|
+
* Input for {@link applyUserExternalConnectionEntry}.
|
|
76
|
+
*/
|
|
77
|
+
export interface ApplyUserExternalConnectionEntryInput {
|
|
78
|
+
/**
|
|
79
|
+
* The currently stored document, when one exists.
|
|
80
|
+
*/
|
|
81
|
+
readonly current?: Maybe<UserExternalConnection>;
|
|
82
|
+
readonly uid: FirebaseAuthUserId;
|
|
83
|
+
readonly providerType: UserExternalConnectionProviderType;
|
|
84
|
+
/**
|
|
85
|
+
* The next entry for this provider, or null to remove the provider's key entirely.
|
|
86
|
+
*/
|
|
87
|
+
readonly entry: Maybe<UserExternalConnectionEntry>;
|
|
88
|
+
readonly now: Date;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Applies a single provider's entry and returns the COMPLETE next document.
|
|
92
|
+
*
|
|
93
|
+
* Returning the whole value (rather than a patch) is what keeps `c` honest: this is the only
|
|
94
|
+
* exported way to change `e`, and it always recomputes `c` from the resulting map. There is no
|
|
95
|
+
* exported path that touches one without the other.
|
|
96
|
+
*
|
|
97
|
+
* @param input - The current document plus the provider entry to apply.
|
|
98
|
+
* @returns The next UserExternalConnection value to write.
|
|
99
|
+
*/
|
|
100
|
+
export declare function applyUserExternalConnectionEntry(input: ApplyUserExternalConnectionEntryInput): UserExternalConnection;
|
|
101
|
+
/**
|
|
102
|
+
* Input for {@link emptyUserExternalConnection}.
|
|
103
|
+
*/
|
|
104
|
+
export interface EmptyUserExternalConnectionInput {
|
|
105
|
+
readonly uid: FirebaseAuthUserId;
|
|
106
|
+
readonly now: Date;
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Returns the value of a connection document that has no providers on it yet.
|
|
110
|
+
*
|
|
111
|
+
* Creating the document is its own operation, so the "no connections" value lives here beside
|
|
112
|
+
* {@link applyUserExternalConnectionEntry} rather than as a literal at the call site — both write
|
|
113
|
+
* the complete document, and `c` is empty here for the same reason it is derived there.
|
|
114
|
+
*
|
|
115
|
+
* @param input - The user the document belongs to and the instant to stamp it with.
|
|
116
|
+
* @returns The UserExternalConnection value for a user with no provider entries.
|
|
117
|
+
*/
|
|
118
|
+
export declare function emptyUserExternalConnection(input: EmptyUserExternalConnectionInput): UserExternalConnection;
|
|
119
|
+
/**
|
|
120
|
+
* Returns the entry for the given provider, if any.
|
|
121
|
+
*
|
|
122
|
+
* @param connection - The loaded connection document.
|
|
123
|
+
* @param providerType - The provider to read.
|
|
124
|
+
* @returns The provider's entry, or null when the user has no entry for it.
|
|
125
|
+
*/
|
|
126
|
+
export declare function userExternalConnectionEntryForProvider(connection: Maybe<UserExternalConnection>, providerType: UserExternalConnectionProviderType): Maybe<UserExternalConnectionEntry>;
|
|
127
|
+
/**
|
|
128
|
+
* Returns true if the entry is in the `connected` status.
|
|
129
|
+
*
|
|
130
|
+
* @param entry - The entry to check.
|
|
131
|
+
* @returns True when the entry is connected.
|
|
132
|
+
*/
|
|
133
|
+
export declare function userExternalConnectionEntryIsConnected(entry: Maybe<UserExternalConnectionEntry>): boolean;
|
|
134
|
+
/**
|
|
135
|
+
* Returns true if the entry declares an expiration that has already passed.
|
|
136
|
+
*
|
|
137
|
+
* @param entry - The entry to check.
|
|
138
|
+
* @param now - The instant to compare against. Defaults to the current time.
|
|
139
|
+
* @returns True when the entry's credentials are known to have expired.
|
|
140
|
+
*/
|
|
141
|
+
export declare function userExternalConnectionEntryIsExpired(entry: Maybe<UserExternalConnectionEntry>, now?: Date): boolean;
|
|
142
|
+
/**
|
|
143
|
+
* Returns true if the user is currently connected to the given provider.
|
|
144
|
+
*
|
|
145
|
+
* @param connection - The loaded connection document.
|
|
146
|
+
* @param providerType - The provider to check.
|
|
147
|
+
* @returns True when the provider's entry is connected.
|
|
148
|
+
*/
|
|
149
|
+
export declare function userExternalConnectionIsConnectedToProvider(connection: Maybe<UserExternalConnection>, providerType: UserExternalConnectionProviderType): boolean;
|