@dereekb/firebase-server 13.32.0 → 13.34.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.
Files changed (79) hide show
  1. package/calcom/index.cjs.default.js +1 -0
  2. package/calcom/index.cjs.js +1451 -0
  3. package/calcom/index.cjs.mjs +2 -0
  4. package/calcom/index.d.ts +1 -0
  5. package/calcom/index.esm.js +1437 -0
  6. package/calcom/package.json +29 -0
  7. package/calcom/src/index.d.ts +1 -0
  8. package/calcom/src/lib/calcom.oauth.connection.cache.d.ts +49 -0
  9. package/calcom/src/lib/calcom.oauth.connection.config.d.ts +75 -0
  10. package/calcom/src/lib/calcom.oauth.connection.context.d.ts +84 -0
  11. package/calcom/src/lib/calcom.oauth.connection.controller.d.ts +18 -0
  12. package/calcom/src/lib/calcom.oauth.connection.module.d.ts +55 -0
  13. package/calcom/src/lib/calcom.oauth.connection.service.d.ts +33 -0
  14. package/calcom/src/lib/index.d.ts +6 -0
  15. package/discord/index.cjs.default.js +1 -0
  16. package/discord/index.cjs.js +761 -0
  17. package/discord/index.cjs.mjs +2 -0
  18. package/discord/index.d.ts +1 -0
  19. package/discord/index.esm.js +753 -0
  20. package/discord/package.json +29 -0
  21. package/discord/src/index.d.ts +1 -0
  22. package/discord/src/lib/discord.oauth.connection.config.d.ts +69 -0
  23. package/discord/src/lib/discord.oauth.connection.controller.d.ts +18 -0
  24. package/discord/src/lib/discord.oauth.connection.module.d.ts +39 -0
  25. package/discord/src/lib/discord.oauth.connection.service.d.ts +43 -0
  26. package/discord/src/lib/index.d.ts +4 -0
  27. package/index.cjs.js +42 -9
  28. package/index.esm.js +42 -9
  29. package/mailgun/package.json +9 -9
  30. package/mcp/package.json +11 -11
  31. package/model/index.cjs.js +4243 -855
  32. package/model/index.esm.js +4183 -862
  33. package/model/package.json +10 -9
  34. package/model/src/lib/index.d.ts +2 -0
  35. package/model/src/lib/system/index.d.ts +2 -0
  36. package/model/src/lib/system/system.private.d.ts +63 -0
  37. package/model/src/lib/system/system.private.module.d.ts +70 -0
  38. package/model/src/lib/userexternalconnection/index.d.ts +8 -0
  39. package/model/src/lib/userexternalconnection/oauth/index.d.ts +7 -0
  40. package/model/src/lib/userexternalconnection/oauth/userexternalconnection.oauth.config.d.ts +110 -0
  41. package/model/src/lib/userexternalconnection/oauth/userexternalconnection.oauth.controller.d.ts +68 -0
  42. package/model/src/lib/userexternalconnection/oauth/userexternalconnection.oauth.error.d.ts +29 -0
  43. package/model/src/lib/userexternalconnection/oauth/userexternalconnection.oauth.refresh.d.ts +24 -0
  44. package/model/src/lib/userexternalconnection/oauth/userexternalconnection.oauth.registry.d.ts +54 -0
  45. package/model/src/lib/userexternalconnection/oauth/userexternalconnection.oauth.service.d.ts +216 -0
  46. package/model/src/lib/userexternalconnection/oauth/userexternalconnection.oauth.state.d.ts +114 -0
  47. package/model/src/lib/userexternalconnection/userexternalconnection.accessor.service.d.ts +111 -0
  48. package/model/src/lib/userexternalconnection/userexternalconnection.action.server.d.ts +172 -0
  49. package/model/src/lib/userexternalconnection/userexternalconnection.error.d.ts +44 -0
  50. package/model/src/lib/userexternalconnection/userexternalconnection.module.d.ts +129 -0
  51. package/model/src/lib/userexternalconnection/userexternalconnection.private.d.ts +192 -0
  52. package/model/src/lib/userexternalconnection/userexternalconnection.reader.service.d.ts +157 -0
  53. package/model/src/lib/userexternalconnection/userexternalconnection.refresh.service.d.ts +46 -0
  54. package/oidc/index.cjs.js +104 -78
  55. package/oidc/index.esm.js +104 -78
  56. package/oidc/package.json +10 -10
  57. package/package.json +24 -10
  58. package/src/lib/env/env.config.d.ts +15 -0
  59. package/src/lib/env/env.service.d.ts +7 -0
  60. package/src/lib/firestore/snapshot/snapshot.field.encrypt.d.ts +21 -2
  61. package/src/lib/nest/env/env.service.d.ts +1 -0
  62. package/test/index.cjs.js +14 -2
  63. package/test/index.esm.js +15 -3
  64. package/test/package.json +11 -11
  65. package/test/src/lib/firebase/firebase.admin.auth.d.ts +1 -1
  66. package/twilio/package.json +8 -8
  67. package/zoho/README.md +38 -0
  68. package/zoho/index.cjs.js +1418 -64
  69. package/zoho/index.esm.js +1401 -67
  70. package/zoho/package.json +13 -9
  71. package/zoho/src/lib/index.d.ts +6 -0
  72. package/zoho/src/lib/zoho.accounts.firebase.d.ts +10 -3
  73. package/zoho/src/lib/zoho.accounts.firebase.module.d.ts +51 -0
  74. package/zoho/src/lib/zoho.accounts.firebase.system.d.ts +51 -8
  75. package/zoho/src/lib/zoho.oauth.connection.cache.d.ts +45 -0
  76. package/zoho/src/lib/zoho.oauth.connection.config.d.ts +80 -0
  77. package/zoho/src/lib/zoho.oauth.connection.controller.d.ts +18 -0
  78. package/zoho/src/lib/zoho.oauth.connection.module.d.ts +43 -0
  79. package/zoho/src/lib/zoho.oauth.connection.service.d.ts +107 -0
@@ -1,19 +1,20 @@
1
1
  {
2
2
  "name": "@dereekb/firebase-server/model",
3
- "version": "13.32.0",
3
+ "version": "13.34.0",
4
4
  "peerDependencies": {
5
- "@dereekb/analytics": "13.32.0",
6
- "@dereekb/date": "13.32.0",
7
- "@dereekb/firebase": "13.32.0",
8
- "@dereekb/firebase-server": "13.32.0",
9
- "@dereekb/model": "13.32.0",
10
- "@dereekb/nestjs": "13.32.0",
11
- "@dereekb/rxjs": "13.32.0",
12
- "@dereekb/util": "13.32.0",
5
+ "@dereekb/analytics": "13.34.0",
6
+ "@dereekb/date": "13.34.0",
7
+ "@dereekb/firebase": "13.34.0",
8
+ "@dereekb/firebase-server": "13.34.0",
9
+ "@dereekb/model": "13.34.0",
10
+ "@dereekb/nestjs": "13.34.0",
11
+ "@dereekb/rxjs": "13.34.0",
12
+ "@dereekb/util": "13.34.0",
13
13
  "@nestjs/common": "^11.1.19",
14
14
  "@nestjs/config": "^4.0.4",
15
15
  "archiver": "^7.0.1",
16
16
  "date-fns": "^4.1.0",
17
+ "express": "^5.2.1",
17
18
  "firebase-functions": "^7.2.5",
18
19
  "make-error": "^1.3.6",
19
20
  "@cantoo/pdf-lib": "^2.6.5",
@@ -1,3 +1,5 @@
1
1
  export * from './mailgun';
2
2
  export * from './notification';
3
3
  export * from './storagefile';
4
+ export * from './system';
5
+ export * from './userexternalconnection';
@@ -0,0 +1,2 @@
1
+ export * from './system.private';
2
+ export * from './system.private.module';
@@ -0,0 +1,63 @@
1
+ import { type Maybe } from '@dereekb/util';
2
+ import { AbstractFirestoreDocument, type CollectionReference, type FirestoreCollection, type FirestoreContext, type SystemState, type SystemStateStoredData, type SystemStateStoredDataConverterMap, type SystemStateUnknownTypeBehavior } from '@dereekb/firebase';
3
+ /**
4
+ * Provides access to the {@link SystemStatePrivate} collection.
5
+ *
6
+ * Provided ONLY by a server module. This is deliberately never declared on an app's shared
7
+ * `FirestoreCollections` class: `provideAppFirestoreCollections()` hard-codes a
8
+ * `(context: FirestoreContext) => T` factory, which cannot carry the encryption secrets a private
9
+ * converter needs — so the private collection structurally cannot leak into the client-shared
10
+ * collection set.
11
+ */
12
+ export declare abstract class SystemStatePrivateFirestoreCollections {
13
+ abstract readonly systemStatePrivateCollection: SystemStatePrivateFirestoreCollection;
14
+ }
15
+ /**
16
+ * Firestore model identity for {@link SystemStatePrivate} documents.
17
+ *
18
+ * The server-only counterpart of `systemStateIdentity` from `@dereekb/firebase`. Same document
19
+ * shape, same "document id is the type identifier" singleton convention — but a separate `sysp`
20
+ * collection, so a secret-bearing document is never reachable through the client-shared SystemState
21
+ * collection or the generic admin model service registered against it.
22
+ *
23
+ * This is a server-side only model. It has no provisions for client-side access, and deliberately
24
+ * has NO `firestore.rules` match block — the implicit default-deny is what denies every client, and
25
+ * a block here would only create an opportunity to grant access by accident.
26
+ */
27
+ export declare const systemStatePrivateIdentity: import("@dereekb/firebase").RootFirestoreModelIdentity<"systemStatePrivate", "sysp">;
28
+ export declare class SystemStatePrivateDocument<T extends SystemStateStoredData = SystemStateStoredData> extends AbstractFirestoreDocument<SystemState<T>, SystemStatePrivateDocument<T>, typeof systemStatePrivateIdentity> {
29
+ get modelIdentity(): import("@dereekb/firebase").RootFirestoreModelIdentity<"systemStatePrivate", "sysp">;
30
+ }
31
+ /**
32
+ * Returns the Firestore {@link CollectionReference} for {@link SystemStatePrivate} documents.
33
+ *
34
+ * @param context - The Firestore context to create the collection reference from.
35
+ * @returns The typed collection reference.
36
+ */
37
+ export declare function systemStatePrivateCollectionReference(context: FirestoreContext): CollectionReference<SystemState>;
38
+ export type SystemStatePrivateFirestoreCollection<T extends SystemStateStoredData = SystemStateStoredData> = FirestoreCollection<SystemState<T>, SystemStatePrivateDocument<T>>;
39
+ /**
40
+ * Configuration for creating a {@link SystemStatePrivateFirestoreCollection}.
41
+ */
42
+ export interface SystemStatePrivateFirestoreCollectionConfig {
43
+ readonly firestoreContext: FirestoreContext;
44
+ /**
45
+ * Server-only stored-data converters, keyed by SystemStateTypeIdentifier.
46
+ */
47
+ readonly converters: SystemStateStoredDataConverterMap;
48
+ /**
49
+ * Behavior when a document's type has no registered converter. Defaults to `error`.
50
+ *
51
+ * A private type that was not registered must never silently pass through — that would read a
52
+ * secret-bearing document without its field mapping, returning encrypted fields as raw ciphertext
53
+ * and dates as raw `Timestamp`s, with nothing to signal it.
54
+ */
55
+ readonly unknownTypeBehavior?: Maybe<SystemStateUnknownTypeBehavior>;
56
+ }
57
+ /**
58
+ * Creates a {@link SystemStatePrivateFirestoreCollection}.
59
+ *
60
+ * @param config - The Firestore context, converters, and unknown-type behavior.
61
+ * @returns The configured server-only SystemState collection.
62
+ */
63
+ export declare function systemStatePrivateFirestoreCollection(config: SystemStatePrivateFirestoreCollectionConfig): SystemStatePrivateFirestoreCollection;
@@ -0,0 +1,70 @@
1
+ import { type ModuleMetadata, type Provider } from '@nestjs/common';
2
+ import { type Maybe } from '@dereekb/util';
3
+ import { type FirestoreContext, type SystemStateStoredDataConverterMap, type SystemStateUnknownTypeBehavior } from '@dereekb/firebase';
4
+ import { SystemStatePrivateFirestoreCollections } from './system.private';
5
+ /**
6
+ * Configuration for the {@link SystemStatePrivateFirestoreCollections} provider.
7
+ */
8
+ export declare abstract class SystemStatePrivateModuleConfig {
9
+ /**
10
+ * Server-only stored-data converters, keyed by SystemStateTypeIdentifier.
11
+ *
12
+ * Secret-bearing converters are built by the app, which owns its own `ConfigService`/env access —
13
+ * the framework never sees the secrets.
14
+ */
15
+ abstract readonly converters: SystemStateStoredDataConverterMap;
16
+ /**
17
+ * Behavior when a document's type has no registered converter. Defaults to `error`.
18
+ */
19
+ abstract readonly unknownTypeBehavior?: Maybe<SystemStateUnknownTypeBehavior>;
20
+ }
21
+ /**
22
+ * Creates the {@link SystemStatePrivateFirestoreCollections}.
23
+ *
24
+ * This is a bespoke provider rather than a `provideAppFirestoreCollections()` entry because that
25
+ * helper hard-codes a `(context: FirestoreContext) => T` factory and cannot carry the converters
26
+ * (and therefore the encryption secrets) this collection needs.
27
+ *
28
+ * @param firestoreContext - The Firestore context.
29
+ * @param config - The module configuration carrying the server-only converters.
30
+ * @returns The server-only collections.
31
+ */
32
+ export declare function systemStatePrivateFirestoreCollectionsFactory(firestoreContext: FirestoreContext, config: SystemStatePrivateModuleConfig): SystemStatePrivateFirestoreCollections;
33
+ /**
34
+ * Configuration for {@link appSystemStatePrivateModuleMetadata}.
35
+ */
36
+ export interface ProvideAppSystemStatePrivateModuleMetadataConfig extends Pick<ModuleMetadata, 'imports' | 'exports' | 'providers'> {
37
+ /**
38
+ * Provider for {@link SystemStatePrivateModuleConfig}.
39
+ *
40
+ * The app declares this so it can inject its own `ConfigService`/env service and build each
41
+ * secret-bearing converter itself.
42
+ */
43
+ readonly configProvider: Provider;
44
+ }
45
+ /**
46
+ * Generates NestJS {@link ModuleMetadata} for an app's server-only SystemState module.
47
+ *
48
+ * IMPORTANT: do NOT add {@link SystemStatePrivateFirestoreCollections} to an app's shared
49
+ * `FirestoreCollections` class. Keeping it on its own provider is what stops the private collection
50
+ * from reaching client-shared code.
51
+ *
52
+ * @param config - The app's config provider plus optional additional module metadata.
53
+ * @returns Module metadata ready for the `@Module()` decorator.
54
+ *
55
+ * @example
56
+ * ```typescript
57
+ * @Module(
58
+ * appSystemStatePrivateModuleMetadata({
59
+ * configProvider: {
60
+ * provide: SystemStatePrivateModuleConfig,
61
+ * useFactory: myConfigFactory,
62
+ * inject: [ConfigService, FirebaseServerEnvService]
63
+ * },
64
+ * imports: [ConfigModule]
65
+ * })
66
+ * )
67
+ * export class AppSystemStatePrivateModule {}
68
+ * ```
69
+ */
70
+ export declare function appSystemStatePrivateModuleMetadata(config: ProvideAppSystemStatePrivateModuleMetadataConfig): ModuleMetadata;
@@ -0,0 +1,8 @@
1
+ export * from './oauth';
2
+ export * from './userexternalconnection.private';
3
+ export * from './userexternalconnection.accessor.service';
4
+ export * from './userexternalconnection.action.server';
5
+ export * from './userexternalconnection.error';
6
+ export * from './userexternalconnection.module';
7
+ export * from './userexternalconnection.reader.service';
8
+ export * from './userexternalconnection.refresh.service';
@@ -0,0 +1,7 @@
1
+ export * from './userexternalconnection.oauth.config';
2
+ export * from './userexternalconnection.oauth.controller';
3
+ export * from './userexternalconnection.oauth.error';
4
+ export * from './userexternalconnection.oauth.refresh';
5
+ export * from './userexternalconnection.oauth.registry';
6
+ export * from './userexternalconnection.oauth.service';
7
+ export * from './userexternalconnection.oauth.state';
@@ -0,0 +1,110 @@
1
+ import { type UserExternalConnectionProviderType } from '@dereekb/firebase';
2
+ import { type FirebaseServerEnvService } from '@dereekb/firebase-server';
3
+ import { type Maybe, type WebsiteUrl } from '@dereekb/util';
4
+ /**
5
+ * Controller path a provider's external-connection OAuth endpoints are mounted at.
6
+ *
7
+ * Matches the Angular registry's `DEFAULT_EXTERNAL_CONNECTION_AUTHORIZE_PATH_FACTORY`, which builds
8
+ * `/oauth/<providerType>/authorize`.
9
+ *
10
+ * @param providerType - The provider to build a controller path for.
11
+ * @returns The controller path, without a leading slash.
12
+ *
13
+ * @__NO_SIDE_EFFECTS__
14
+ */
15
+ export declare function userExternalConnectionOAuthControllerPath(providerType: UserExternalConnectionProviderType): string;
16
+ /**
17
+ * Routes to exclude from an app's global API route prefix so a provider's callback controller stays
18
+ * mounted at `/oauth/<providerType>/*`.
19
+ *
20
+ * Spread the result into the `exclude` list of the app's `globalApiRoutePrefix` config, alongside
21
+ * `FIREBASE_SERVER_OIDC_ROUTES_FOR_GLOBAL_ROUTE_EXCLUDE`. Without it an `/api` prefix moves the
22
+ * routes to `/api/oauth/<providerType>/*`, which no longer matches the redirect URI registered with
23
+ * the provider — and providers require a byte-identical match, so this is not something they
24
+ * tolerate.
25
+ *
26
+ * @param providerType - The provider whose routes should be excluded.
27
+ * @returns The route patterns to exclude.
28
+ *
29
+ * @__NO_SIDE_EFFECTS__
30
+ */
31
+ export declare function userExternalConnectionOAuthRoutesForGlobalRouteExclude(providerType: UserExternalConnectionProviderType): string[];
32
+ export interface UserExternalConnectionOAuthRedirectUriInput {
33
+ /**
34
+ * The origin the OAuth endpoints are reachable at, e.g. `https://example.com`.
35
+ */
36
+ readonly origin: WebsiteUrl;
37
+ readonly providerType: UserExternalConnectionProviderType;
38
+ }
39
+ /**
40
+ * Builds the redirect URI to register with a provider.
41
+ *
42
+ * Derived from {@link userExternalConnectionOAuthControllerPath}, the same expression the controller
43
+ * mounts on, so the registered URI cannot drift from the route that serves it.
44
+ *
45
+ * @param input - The origin and the provider.
46
+ * @returns The redirect URI.
47
+ *
48
+ * @__NO_SIDE_EFFECTS__
49
+ */
50
+ export declare function userExternalConnectionOAuthRedirectUri(input: UserExternalConnectionOAuthRedirectUriInput): WebsiteUrl;
51
+ export interface UserExternalConnectionOAuthApiConfig {
52
+ /**
53
+ * The provider this flow connects.
54
+ */
55
+ readonly providerType: UserExternalConnectionProviderType;
56
+ /**
57
+ * The redirect URI registered on the provider's OAuth client.
58
+ *
59
+ * Must match the registered value byte-for-byte, including the port, since it is sent on both the
60
+ * authorize redirect and the token exchange.
61
+ */
62
+ readonly redirectUri: WebsiteUrl;
63
+ /**
64
+ * Where the user is sent after a connection succeeds.
65
+ */
66
+ readonly successUrl: WebsiteUrl;
67
+ /**
68
+ * Where the user is sent after a connection fails. Defaults to the `successUrl`.
69
+ */
70
+ readonly failureUrl?: Maybe<WebsiteUrl>;
71
+ }
72
+ /**
73
+ * Configuration for an {@link AbstractUserExternalConnectionOAuthService}.
74
+ *
75
+ * Provided privately by each provider's module, so two registered providers never collide on this
76
+ * token.
77
+ */
78
+ export declare abstract class UserExternalConnectionOAuthServiceConfig {
79
+ readonly userExternalConnectionOAuth: UserExternalConnectionOAuthApiConfig;
80
+ static assertValidConfig(config: UserExternalConnectionOAuthServiceConfig): void;
81
+ }
82
+ export interface UserExternalConnectionOAuthServiceConfigFactoryConfig {
83
+ /**
84
+ * Used to resolve the OAuth origin and the app URL. No part of this configuration is read from the
85
+ * environment as a value — only the origins the app is already configured with.
86
+ */
87
+ readonly envService: FirebaseServerEnvService;
88
+ readonly providerType: UserExternalConnectionProviderType;
89
+ /**
90
+ * Path on the app URL the user is returned to after a successful connect, e.g. `/app/settings`.
91
+ */
92
+ readonly successPath: string;
93
+ /**
94
+ * Path on the app URL the user is returned to after a failed connect. Defaults to `successPath`.
95
+ */
96
+ readonly failurePath?: Maybe<string>;
97
+ }
98
+ /**
99
+ * Builds a provider's OAuth configuration from the app's configured origins plus code-declared
100
+ * return paths.
101
+ *
102
+ * The redirect URI is derived rather than configured: it is the app's OAuth origin joined to the
103
+ * same controller path the callback mounts on. Registering a provider therefore requires no
104
+ * deployment configuration of its own.
105
+ *
106
+ * @param config - The env service, the provider, and the return paths.
107
+ * @returns The validated service configuration.
108
+ * @throws {Error} When no app URL is configured, or the derived URIs are inconsistent.
109
+ */
110
+ export declare function userExternalConnectionOAuthServiceConfigFactory(config: UserExternalConnectionOAuthServiceConfigFactoryConfig): UserExternalConnectionOAuthServiceConfig;
@@ -0,0 +1,68 @@
1
+ import { type Request, type Response } from 'express';
2
+ import { type Maybe } from '@dereekb/util';
3
+ import { type AbstractUserExternalConnectionOAuthService, type UserExternalConnectionOAuthCallbackQueryValues, type UserExternalConnectionOAuthState } from './userexternalconnection.oauth.service';
4
+ /**
5
+ * HTTP status used for the handoff redirects.
6
+ *
7
+ * A 302 keeps the redirect non-cacheable, which matters because each authorize URL carries a
8
+ * single-use `state`.
9
+ */
10
+ export declare const USER_EXTERNAL_CONNECTION_OAUTH_REDIRECT_STATUS = 302;
11
+ /**
12
+ * Query parameters a provider sends to the redirect URI.
13
+ *
14
+ * Snake-cased because these are the wire names — `error_description` is what RFC 6749 4.1.2.1
15
+ * specifies, so it is read as-is rather than renamed at the boundary.
16
+ */
17
+ export interface UserExternalConnectionOAuthCallbackQuery extends UserExternalConnectionOAuthCallbackQueryValues {
18
+ readonly code?: Maybe<string>;
19
+ readonly state?: Maybe<UserExternalConnectionOAuthState>;
20
+ readonly error?: Maybe<string>;
21
+ readonly error_description?: Maybe<string>;
22
+ }
23
+ /**
24
+ * The two endpoints of an external-connection authorization-code handoff.
25
+ *
26
+ * A provider ships its own controller so it keeps full control of its route surface; extending this
27
+ * means it declares only the mount point and its constructor:
28
+ *
29
+ * ```ts
30
+ * @Controller(CALCOM_USER_EXTERNAL_CONNECTION_OAUTH_CONTROLLER_PATH)
31
+ * export class CalcomUserExternalConnectionOAuthController extends AbstractUserExternalConnectionOAuthController {
32
+ * constructor(@Inject(CalcomUserExternalConnectionOAuthService) readonly oauthService: CalcomUserExternalConnectionOAuthService) {
33
+ * super();
34
+ * }
35
+ * }
36
+ * ```
37
+ *
38
+ * Mount at {@link userExternalConnectionOAuthControllerPath}, and exclude those routes from any
39
+ * global API route prefix with {@link userExternalConnectionOAuthRoutesForGlobalRouteExclude} — the
40
+ * redirect URI registered with a provider must match byte-for-byte, so a prefix silently breaks it.
41
+ */
42
+ export declare abstract class AbstractUserExternalConnectionOAuthController {
43
+ abstract readonly oauthService: AbstractUserExternalConnectionOAuthService;
44
+ /**
45
+ * Begins the handoff by redirecting the user's browser to the provider's consent screen.
46
+ *
47
+ * Carries the `state` resolved for the request; a request without one is bounced to the failure
48
+ * URL rather than sent to the provider.
49
+ *
50
+ * @param request - The incoming authorize request, which the state is read from.
51
+ * @param response - The response to issue the redirect on.
52
+ */
53
+ authorize(request: Request, response: Response): void;
54
+ /**
55
+ * Completes the handoff: verifies the returned `state`, exchanges the authorization code, and
56
+ * redirects to the configured success or failure URL.
57
+ *
58
+ * On refusal a provider sends `error` / `error_description` in place of a `code` (RFC 6749
59
+ * 4.1.2.1), so both are read and passed through — otherwise a rejected scope or a denied consent
60
+ * is indistinguishable from a missing code.
61
+ *
62
+ * @param query - The callback query parameters: `code` + `state` on approval, or `error` +
63
+ * `error_description` on refusal. Passed through whole, so a provider adapter can read the
64
+ * extras its exchange needs.
65
+ * @param response - The response to issue the redirect on.
66
+ */
67
+ callback(query: UserExternalConnectionOAuthCallbackQuery, response: Response): Promise<void>;
68
+ }
@@ -0,0 +1,29 @@
1
+ import { type UserExternalConnectionErrorCode } from '@dereekb/firebase';
2
+ import { type Maybe } from '@dereekb/util';
3
+ /**
4
+ * An error a provider reported on the redirect back, rather than one thrown on our side.
5
+ *
6
+ * Per RFC 6749 4.1.2.1 the authorization server redirects to the `redirect_uri` with these instead
7
+ * of a `code` when it refuses the request. Reading them is what keeps a declined consent or a
8
+ * rejected scope from being misreported as a missing authorization code.
9
+ */
10
+ export interface UserExternalConnectionOAuthProviderError {
11
+ /**
12
+ * The OAuth error code, e.g. `invalid_request`, `invalid_scope`, `access_denied`.
13
+ */
14
+ readonly error: string;
15
+ /**
16
+ * The provider's human-readable explanation, when it sent one.
17
+ */
18
+ readonly errorDescription?: Maybe<string>;
19
+ }
20
+ /**
21
+ * Maps an OAuth refusal reported by a provider to the connection entry's error code.
22
+ *
23
+ * The codes are the standard OAuth 2.0 ones, so this mapping is the same for every provider. A
24
+ * failure thrown on our own side has no provider error and stays `provider_error`.
25
+ *
26
+ * @param providerError - The error the provider reported on the redirect, when it reported one.
27
+ * @returns The error code to record on the connection entry.
28
+ */
29
+ export declare function userExternalConnectionErrorCodeForOAuthProviderError(providerError: Maybe<UserExternalConnectionOAuthProviderError>): UserExternalConnectionErrorCode;
@@ -0,0 +1,24 @@
1
+ import { type UserExternalConnectionCredentialsRefresher } from '../userexternalconnection.refresh.service';
2
+ import { type UserExternalConnectionOAuthProviderRegistry } from './userexternalconnection.oauth.registry';
3
+ /**
4
+ * Configuration for {@link userExternalConnectionOAuthRegistryCredentialsRefresher}.
5
+ */
6
+ export interface UserExternalConnectionOAuthRegistryCredentialsRefresherConfig {
7
+ readonly registry: UserExternalConnectionOAuthProviderRegistry;
8
+ }
9
+ /**
10
+ * Creates a {@link UserExternalConnectionCredentialsRefresher} that renews credentials through the
11
+ * app's registered OAuth provider services.
12
+ *
13
+ * The bridge between the two layers: the reader knows it needs a refresh but nothing about providers,
14
+ * and each provider service knows how to refresh but nothing about who is asking. Dispatch is by
15
+ * provider type, so a provider the app never registered — or registered without a `refreshCredentials`
16
+ * implementation — resolves to null, which the reader reports as "cannot renew" rather than as a
17
+ * failure of the provider.
18
+ *
19
+ * @param config - The provider registry to dispatch through.
20
+ * @returns A refresher backed by the registry.
21
+ *
22
+ * @__NO_SIDE_EFFECTS__
23
+ */
24
+ export declare function userExternalConnectionOAuthRegistryCredentialsRefresher(config: UserExternalConnectionOAuthRegistryCredentialsRefresherConfig): UserExternalConnectionCredentialsRefresher;
@@ -0,0 +1,54 @@
1
+ import { type InjectionToken, type Provider } from '@nestjs/common';
2
+ import { type UserExternalConnectionProviderType } from '@dereekb/firebase';
3
+ import { type Maybe } from '@dereekb/util';
4
+ import { type AbstractUserExternalConnectionOAuthService } from './userexternalconnection.oauth.service';
5
+ /**
6
+ * The providers an app has an OAuth authorize/callback flow mounted for.
7
+ *
8
+ * Built FROM the registered services rather than from a hand-maintained list, so it cannot disagree
9
+ * with which provider modules the app actually imported. A provider absent from it has no endpoint
10
+ * to send the user to, so minting a state for it would hand back something unusable.
11
+ */
12
+ export declare abstract class UserExternalConnectionOAuthProviderRegistry {
13
+ abstract readonly providerTypes: ReadonlySet<UserExternalConnectionProviderType>;
14
+ /**
15
+ * Whether the app can begin an OAuth handoff for this provider.
16
+ */
17
+ abstract hasAuthorizeFlowForProviderType(providerType: UserExternalConnectionProviderType): boolean;
18
+ /**
19
+ * Throws when the app has no OAuth handoff for this provider.
20
+ *
21
+ * @throws A precondition-conflict HttpsError.
22
+ */
23
+ abstract assertHasAuthorizeFlowForProviderType(providerType: UserExternalConnectionProviderType): void;
24
+ /**
25
+ * The registered service for a provider, when there is one.
26
+ */
27
+ abstract serviceForProviderType(providerType: UserExternalConnectionProviderType): Maybe<AbstractUserExternalConnectionOAuthService>;
28
+ }
29
+ /**
30
+ * Creates the registry from the app's registered OAuth services.
31
+ *
32
+ * @param services - Every {@link AbstractUserExternalConnectionOAuthService} the app has mounted.
33
+ * @returns The registry.
34
+ * @throws {Error} When two services claim the same provider type.
35
+ *
36
+ * @__NO_SIDE_EFFECTS__
37
+ */
38
+ export declare function userExternalConnectionOAuthProviderRegistry(services: AbstractUserExternalConnectionOAuthService[]): UserExternalConnectionOAuthProviderRegistry;
39
+ /**
40
+ * Creates the NestJS provider for the {@link UserExternalConnectionOAuthProviderRegistry}.
41
+ *
42
+ * Declared by the app rather than by the UserExternalConnection module, because each provider module
43
+ * imports that module for its actions and state coder — so the registry must live somewhere that can
44
+ * import the provider modules without a cycle.
45
+ *
46
+ * Registering a provider is then one module import plus one token here.
47
+ *
48
+ * @param oauthServiceTokens - Tokens of the registered `AbstractUserExternalConnectionOAuthService`
49
+ * providers, whose modules must be imported by the declaring module.
50
+ * @returns The NestJS provider.
51
+ *
52
+ * @__NO_SIDE_EFFECTS__
53
+ */
54
+ export declare function userExternalConnectionOAuthProviderRegistryProvider(oauthServiceTokens: InjectionToken[]): Provider;