@dereekb/firebase-server 13.41.0 → 13.43.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/calcom/package.json +10 -10
- package/discord/package.json +10 -10
- package/index.esm.js +4 -13
- package/mailgun/package.json +9 -9
- package/mcp/index.esm.js +21 -33
- package/mcp/package.json +11 -11
- package/mcp/src/lib/service/mcp.manifest.d.ts +22 -0
- package/model/index.esm.js +18376 -13330
- package/model/package.json +9 -9
- package/model/src/lib/calendar/calendar.action.server.d.ts +123 -0
- package/model/src/lib/calendar/calendar.error.d.ts +22 -0
- package/model/src/lib/calendar/calendar.module.d.ts +69 -0
- package/model/src/lib/calendar/calendar.task.service.handler.d.ts +52 -0
- package/model/src/lib/calendar/index.d.ts +4 -0
- package/model/src/lib/formspace/formspace.action.server.d.ts +192 -0
- package/model/src/lib/formspace/formspace.error.d.ts +91 -0
- package/model/src/lib/formspace/formspace.module.d.ts +57 -0
- package/model/src/lib/formspace/formspace.task.service.handler.d.ts +97 -0
- package/model/src/lib/formspace/formspace.upload.initializer.d.ts +89 -0
- package/model/src/lib/formspace/formspace.validation.d.ts +174 -0
- package/model/src/lib/formspace/index.d.ts +6 -0
- package/model/src/lib/index.d.ts +2 -0
- package/model/src/lib/mailgun/index.d.ts +1 -0
- package/model/src/lib/mailgun/notification.send.service.mailgun.attachment.d.ts +40 -0
- package/model/src/lib/storagefile/storagefile.action.server.d.ts +11 -4
- package/model/src/lib/storagefile/storagefile.mcp.d.ts +38 -0
- package/model/src/lib/storagefile/storagefile.upload.service.initializer.d.ts +16 -0
- package/model/src/lib/system/index.d.ts +1 -0
- package/model/src/lib/system/system.scheduler.d.ts +144 -0
- package/oidc/index.esm.js +2 -2
- package/oidc/package.json +10 -10
- package/package.json +12 -12
- package/src/lib/storage/driver.accessor.d.ts +1 -1
- package/test/index.esm.js +2 -2
- package/test/package.json +11 -11
- package/twilio/package.json +8 -8
- package/zoho/package.json +10 -10
package/model/package.json
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dereekb/firebase-server/model",
|
|
3
|
-
"version": "13.
|
|
3
|
+
"version": "13.43.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"peerDependencies": {
|
|
6
|
-
"@dereekb/analytics": "13.
|
|
7
|
-
"@dereekb/date": "13.
|
|
8
|
-
"@dereekb/firebase": "13.
|
|
9
|
-
"@dereekb/firebase-server": "13.
|
|
10
|
-
"@dereekb/model": "13.
|
|
11
|
-
"@dereekb/nestjs": "13.
|
|
12
|
-
"@dereekb/rxjs": "13.
|
|
13
|
-
"@dereekb/util": "13.
|
|
6
|
+
"@dereekb/analytics": "13.43.0",
|
|
7
|
+
"@dereekb/date": "13.43.0",
|
|
8
|
+
"@dereekb/firebase": "13.43.0",
|
|
9
|
+
"@dereekb/firebase-server": "13.43.0",
|
|
10
|
+
"@dereekb/model": "13.43.0",
|
|
11
|
+
"@dereekb/nestjs": "13.43.0",
|
|
12
|
+
"@dereekb/rxjs": "13.43.0",
|
|
13
|
+
"@dereekb/util": "13.43.0",
|
|
14
14
|
"@nestjs/common": "^11.1.19",
|
|
15
15
|
"@nestjs/config": "^4.0.4",
|
|
16
16
|
"archiver": "^7.0.1",
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import { type AppCalendarTypeConfigServiceRef, type CalendarDocument, type CalendarFirestoreCollections, type FlagStaleCalendarsForSyncParams, type FlagStaleCalendarsForSyncResult, type RotateCalendarIcsParams, type RotateCalendarIcsResult, type SyncAllFlaggedCalendarsParams, type SyncAllFlaggedCalendarsResult, type SyncCalendarParams, type SyncCalendarResult } from '@dereekb/firebase';
|
|
2
|
+
import { type TransformAndValidateFunctionResult } from '@dereekb/model';
|
|
3
|
+
import { type InjectionToken } from '@nestjs/common';
|
|
4
|
+
import { type BaseStorageFileServerActionsContext } from '../storagefile/storagefile.action.server';
|
|
5
|
+
/**
|
|
6
|
+
* NestJS injection token for the {@link BaseCalendarServerActionsContext}.
|
|
7
|
+
*/
|
|
8
|
+
export declare const BASE_CALENDAR_SERVER_ACTION_CONTEXT_TOKEN: InjectionToken;
|
|
9
|
+
/**
|
|
10
|
+
* NestJS injection token for the fully assembled {@link CalendarServerActionsContext}.
|
|
11
|
+
*/
|
|
12
|
+
export declare const CALENDAR_SERVER_ACTION_CONTEXT_TOKEN: InjectionToken;
|
|
13
|
+
/**
|
|
14
|
+
* Minimal context providing the Firebase infrastructure, storage and Firestore collections every Calendar
|
|
15
|
+
* server action needs.
|
|
16
|
+
*
|
|
17
|
+
* Extends {@link BaseStorageFileServerActionsContext} because a Calendar's ICS feed IS a StorageFile: the
|
|
18
|
+
* sync and rotate paths re-flag it for processing, which builds a notification task. Taking the base
|
|
19
|
+
* context lets those paths build `processStorageFile` locally rather than injecting the whole
|
|
20
|
+
* StorageFileServerActions — and so keeps the Calendar module free of a StorageFileModule import.
|
|
21
|
+
*/
|
|
22
|
+
export interface BaseCalendarServerActionsContext extends BaseStorageFileServerActionsContext, CalendarFirestoreCollections {
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Full context for the Calendar server actions, adding the type registry.
|
|
26
|
+
*/
|
|
27
|
+
export interface CalendarServerActionsContext extends BaseCalendarServerActionsContext, AppCalendarTypeConfigServiceRef {
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* The publish-side server actions for the Calendar model.
|
|
31
|
+
*
|
|
32
|
+
* PUBLISH-ONLY BY DESIGN. There is no `upsertCalendarEvents` / `removeCalendarEvents` action: a caller
|
|
33
|
+
* already holds a transaction and an accessor when it decides to touch a calendar, so an action that opened
|
|
34
|
+
* its own transaction would either fight the caller's or force an awkward split write. Callers merge the
|
|
35
|
+
* `calendar.util.ts` templates into their own write instead, and those templates carry the `s: true`
|
|
36
|
+
* invariant that makes this sweep correct.
|
|
37
|
+
*
|
|
38
|
+
* {@link CalendarServerActions.rotateCalendarIcs} is the one action with a callable surface
|
|
39
|
+
* (`calendar/update/rotateIcs`), since revoking a published feed url has to be reachable by its owner. It
|
|
40
|
+
* enforces no permission of its own — the callable's role gate is the authorization.
|
|
41
|
+
*
|
|
42
|
+
* @see {@link calendarServerActions} for the concrete implementation factory.
|
|
43
|
+
*/
|
|
44
|
+
export declare abstract class CalendarServerActions {
|
|
45
|
+
abstract syncCalendar(params: SyncCalendarParams): Promise<TransformAndValidateFunctionResult<SyncCalendarParams, (calendarDocument: CalendarDocument) => Promise<SyncCalendarResult>>>;
|
|
46
|
+
abstract rotateCalendarIcs(params: RotateCalendarIcsParams): Promise<TransformAndValidateFunctionResult<RotateCalendarIcsParams, (calendarDocument: CalendarDocument) => Promise<RotateCalendarIcsResult>>>;
|
|
47
|
+
abstract syncAllFlaggedCalendars(params: SyncAllFlaggedCalendarsParams): Promise<TransformAndValidateFunctionResult<SyncAllFlaggedCalendarsParams, () => Promise<SyncAllFlaggedCalendarsResult>>>;
|
|
48
|
+
abstract flagStaleCalendarsForSync(params: FlagStaleCalendarsForSyncParams): Promise<TransformAndValidateFunctionResult<FlagStaleCalendarsForSyncParams, () => Promise<FlagStaleCalendarsForSyncResult>>>;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Creates a concrete {@link CalendarServerActions} implementation from the given context.
|
|
52
|
+
*
|
|
53
|
+
* @param context - The fully assembled calendar server actions context.
|
|
54
|
+
* @returns The server actions.
|
|
55
|
+
*/
|
|
56
|
+
export declare function calendarServerActions(context: CalendarServerActionsContext): CalendarServerActions;
|
|
57
|
+
/**
|
|
58
|
+
* Factory for the `syncCalendar` action, the Calendar counterpart of
|
|
59
|
+
* `regenerateStorageFileGroupContentFactory`.
|
|
60
|
+
*
|
|
61
|
+
* In ONE transaction it prunes the calendar, ensures its ICS StorageFile exists, and clears `s`. It does not
|
|
62
|
+
* write `sat` — that belongs to the processor's success path alone, which is what makes
|
|
63
|
+
* `s === false && sat < uat` mean "queued, not yet published" and lets `flagStaleCalendarsForSync()` heal a
|
|
64
|
+
* run that died in between.
|
|
65
|
+
*
|
|
66
|
+
* The re-flag of an EXISTING ICS StorageFile happens AFTER the transaction commits, through the public
|
|
67
|
+
* `processStorageFile` action rather than the by-convention-private in-transaction helper. That is safe
|
|
68
|
+
* precisely because of the invariant above: a lost re-flag self-heals within one resync interval instead of
|
|
69
|
+
* silently stranding the calendar.
|
|
70
|
+
*
|
|
71
|
+
* @param context - The calendar server actions context.
|
|
72
|
+
* @returns An async transform-and-validate function that syncs a single Calendar.
|
|
73
|
+
*/
|
|
74
|
+
export declare function syncCalendarFactory(context: CalendarServerActionsContext): import("@dereekb/model").TransformAndValidateFunctionResultFunction<SyncCalendarParams, (calendarDocument: CalendarDocument) => Promise<SyncCalendarResult>, object, unknown>;
|
|
75
|
+
/**
|
|
76
|
+
* Factory for the `rotateCalendarIcs` action: the REVOCATION primitive for a published feed url.
|
|
77
|
+
*
|
|
78
|
+
* A published feed url is a bearer credential — unguessable, but permanent until rotated, and stored by a
|
|
79
|
+
* subscriber (Google keeps it in the subscriber's account). Rotation is the only revocation available for a
|
|
80
|
+
* zero-auth feed, which is why it is a first-class action rather than a manual cleanup.
|
|
81
|
+
*
|
|
82
|
+
* It invents no new mechanism. `calendarIcsFileStoragePath()` keys the published object by the ICS
|
|
83
|
+
* StorageFile's OWN id, and `syncCalendarFactory` already mints a fresh StorageFile — new id, new path, new
|
|
84
|
+
* url — whenever the existing one is absent or QUEUED_FOR_DELETE. So in ONE transaction this simply:
|
|
85
|
+
*
|
|
86
|
+
* - flags the current ICS StorageFile for delete (the existing StorageFile delete machinery is what actually
|
|
87
|
+
* removes the old object, and therefore what actually revokes the old url)
|
|
88
|
+
* - clears `isf` and `iu`, and sets `s: true`
|
|
89
|
+
*
|
|
90
|
+
* `syncCalendar` is then called immediately after the transaction commits, so the replacement exists without
|
|
91
|
+
* waiting for the hourly sweep — and its publish is EXPEDITED (`runImmediately`) rather than left queued, so
|
|
92
|
+
* `iu` normally holds the new url by the time this returns.
|
|
93
|
+
*
|
|
94
|
+
* That expedite is the difference between a rotation and any other sync. Every other path can afford to let
|
|
95
|
+
* the sweep publish, because the calendar still has a working url in the meantime. A rotation does not: it
|
|
96
|
+
* has already revoked the old one, so until the replacement uploads the user has NO link at all. Result
|
|
97
|
+
* field `publishedIcs` reports whether the inline publish landed; the sweep remains the backstop when it
|
|
98
|
+
* did not.
|
|
99
|
+
*
|
|
100
|
+
* @param context - The calendar server actions context.
|
|
101
|
+
* @returns An async transform-and-validate function that rotates a single Calendar's ICS link.
|
|
102
|
+
*/
|
|
103
|
+
export declare function rotateCalendarIcsFactory(context: CalendarServerActionsContext): import("@dereekb/model").TransformAndValidateFunctionResultFunction<RotateCalendarIcsParams, (calendarDocument: CalendarDocument) => Promise<RotateCalendarIcsResult>, object, unknown>;
|
|
104
|
+
/**
|
|
105
|
+
* Factory for the `syncAllFlaggedCalendars` action, the Calendar counterpart of
|
|
106
|
+
* `regenerateAllFlaggedStorageFileGroupsContentFactory`.
|
|
107
|
+
*
|
|
108
|
+
* @param context - The calendar server actions context.
|
|
109
|
+
* @returns An async transform-and-validate function that sweeps every flagged Calendar.
|
|
110
|
+
*/
|
|
111
|
+
export declare function syncAllFlaggedCalendarsFactory(context: CalendarServerActionsContext): import("@dereekb/model").TransformAndValidateFunctionResultFunction<SyncAllFlaggedCalendarsParams, () => Promise<SyncAllFlaggedCalendarsResult>, object, unknown>;
|
|
112
|
+
/**
|
|
113
|
+
* Factory for the `flagStaleCalendarsForSync` action: the self-healing backstop.
|
|
114
|
+
*
|
|
115
|
+
* For every registered {@link CalendarType} it re-flags Calendars whose last successful publish predates that
|
|
116
|
+
* type's resync interval. That covers a sweep that cleared `s` but whose ICS never finished publishing, and
|
|
117
|
+
* it keeps an `expand`-mode calendar from sliding off the end of its expansion window — with no extra field
|
|
118
|
+
* and no extra mechanism.
|
|
119
|
+
*
|
|
120
|
+
* @param context - The calendar server actions context.
|
|
121
|
+
* @returns An async transform-and-validate function that re-flags stale Calendars.
|
|
122
|
+
*/
|
|
123
|
+
export declare function flagStaleCalendarsForSyncFactory(context: CalendarServerActionsContext): import("@dereekb/model").TransformAndValidateFunctionResultFunction<FlagStaleCalendarsForSyncParams, () => Promise<FlagStaleCalendarsForSyncResult>, object, unknown>;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Creates an error indicating the Calendar module was configured without an ICS domain.
|
|
3
|
+
*
|
|
4
|
+
* @returns An internal-server HttpsError with the CALENDAR_ICS_DOMAIN_NOT_CONFIGURED error code.
|
|
5
|
+
*/
|
|
6
|
+
export declare function calendarIcsDomainNotConfiguredError(): import("firebase-functions/https").HttpsError;
|
|
7
|
+
/**
|
|
8
|
+
* Creates an error indicating the Calendar's ICS StorageFile could not be resolved or created.
|
|
9
|
+
*
|
|
10
|
+
* @returns A precondition-conflict HttpsError with the CALENDAR_ICS_STORAGE_FILE_UNAVAILABLE error code.
|
|
11
|
+
*/
|
|
12
|
+
export declare function calendarIcsStorageFileUnavailableError(): import("firebase-functions/https").HttpsError;
|
|
13
|
+
/**
|
|
14
|
+
* Creates an error indicating the Calendar's ICS link was rotated again before its throttle window passed.
|
|
15
|
+
*
|
|
16
|
+
* Thrown by the rotate action when the calendar's stored rotation instant is too recent. The client derives
|
|
17
|
+
* the same window from the same field, so reaching this error means the caller bypassed the UI.
|
|
18
|
+
*
|
|
19
|
+
* @param nextRotateAt - The time the next rotation is allowed.
|
|
20
|
+
* @returns A precondition-conflict HttpsError with the CALENDAR_ICS_ROTATE_THROTTLED error code.
|
|
21
|
+
*/
|
|
22
|
+
export declare function calendarIcsRotateThrottledError(nextRotateAt: Date): import("firebase-functions/https").HttpsError;
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { type InjectionToken, type ModuleMetadata } from '@nestjs/common';
|
|
2
|
+
import { type Maybe } from '@dereekb/util';
|
|
3
|
+
import { AppCalendarTypeConfigService, type CalendarTypeConfig } from '@dereekb/firebase';
|
|
4
|
+
import { type BaseCalendarServerActionsContext, CalendarServerActions, type CalendarServerActionsContext } from './calendar.action.server';
|
|
5
|
+
/**
|
|
6
|
+
* NestJS injection token for the app's `CalendarTypeConfig[]` registry.
|
|
7
|
+
*
|
|
8
|
+
* Apps bind this token via {@link appCalendarModuleMetadata} by passing `calendarTypeConfigs`.
|
|
9
|
+
*/
|
|
10
|
+
export declare const CALENDAR_TYPE_CONFIGS_TOKEN: InjectionToken;
|
|
11
|
+
/**
|
|
12
|
+
* NestJS injection token for the domain every generated event UID is suffixed with.
|
|
13
|
+
*/
|
|
14
|
+
export declare const CALENDAR_ICS_DOMAIN_TOKEN: InjectionToken;
|
|
15
|
+
/**
|
|
16
|
+
* Factory that builds the app's {@link AppCalendarTypeConfigService} from its registered configs.
|
|
17
|
+
*
|
|
18
|
+
* @param calendarTypeConfigs - The app's calendar type registry.
|
|
19
|
+
* @returns The service.
|
|
20
|
+
*/
|
|
21
|
+
export declare function appCalendarTypeConfigServiceFactory(calendarTypeConfigs: CalendarTypeConfig[]): AppCalendarTypeConfigService;
|
|
22
|
+
/**
|
|
23
|
+
* Factory that assembles the full {@link CalendarServerActionsContext}.
|
|
24
|
+
*
|
|
25
|
+
* @param context - The base context providing Firebase infrastructure and collections.
|
|
26
|
+
* @param appCalendarTypeConfigServiceInstance - The app's calendar type registry service.
|
|
27
|
+
* @returns The fully assembled context.
|
|
28
|
+
*/
|
|
29
|
+
export declare function calendarServerActionsContextFactory(context: BaseCalendarServerActionsContext, appCalendarTypeConfigServiceInstance: AppCalendarTypeConfigService): CalendarServerActionsContext;
|
|
30
|
+
/**
|
|
31
|
+
* Factory that creates a {@link CalendarServerActions} instance from the assembled context.
|
|
32
|
+
*
|
|
33
|
+
* @param context - The fully assembled calendar server actions context.
|
|
34
|
+
* @returns The server actions.
|
|
35
|
+
*/
|
|
36
|
+
export declare function calendarServerActionsFactory(context: CalendarServerActionsContext): CalendarServerActions;
|
|
37
|
+
export interface ProvideAppCalendarMetadataConfig extends Pick<ModuleMetadata, 'imports' | 'exports' | 'providers'> {
|
|
38
|
+
/**
|
|
39
|
+
* The AppCalendarModule requires the following dependencies in order to initialize properly:
|
|
40
|
+
* - BaseCalendarServerActionsContext (BASE_CALENDAR_SERVER_ACTION_CONTEXT_TOKEN)
|
|
41
|
+
*
|
|
42
|
+
* This module declaration makes it easier to import a module that exports those dependencies.
|
|
43
|
+
*/
|
|
44
|
+
readonly dependencyModule?: Maybe<Required<ModuleMetadata>['imports']['0']>;
|
|
45
|
+
/**
|
|
46
|
+
* The app's {@link CalendarType} registry. Bound to {@link CALENDAR_TYPE_CONFIGS_TOKEN}.
|
|
47
|
+
*/
|
|
48
|
+
readonly calendarTypeConfigs: CalendarTypeConfig[];
|
|
49
|
+
/**
|
|
50
|
+
* The domain every generated event UID is suffixed with. I.E. "example.com".
|
|
51
|
+
*
|
|
52
|
+
* REQUIRED: the UID factory deliberately has no random fallback, since a UID that changes between
|
|
53
|
+
* publishes makes every client create a duplicate event rather than update the one it holds.
|
|
54
|
+
*/
|
|
55
|
+
readonly icsDomain: string;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Convenience function used to generate ModuleMetadata for an app's CalendarModule.
|
|
59
|
+
*
|
|
60
|
+
* By default this module exports:
|
|
61
|
+
* - CalendarServerActionsContext (CALENDAR_SERVER_ACTION_CONTEXT_TOKEN)
|
|
62
|
+
* - CalendarServerActions
|
|
63
|
+
* - AppCalendarTypeConfigService
|
|
64
|
+
* - CALENDAR_ICS_DOMAIN_TOKEN
|
|
65
|
+
*
|
|
66
|
+
* @param config - The module configuration.
|
|
67
|
+
* @returns The assembled {@link ModuleMetadata} for the calendar module.
|
|
68
|
+
*/
|
|
69
|
+
export declare function appCalendarModuleMetadata(config: ProvideAppCalendarMetadataConfig): ModuleMetadata;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { type AppCalendarTypeConfigService, type CalendarFirestoreCollections, type CalendarIcsStorageFileProcessingSubtask, type CalendarIcsStorageFileProcessingSubtaskMetadata, type FirebaseStorageAccessor } from '@dereekb/firebase';
|
|
2
|
+
import { type StorageFileProcessingPurposeSubtaskProcessorConfigWithTarget } from '../storagefile/storagefile.task.service.handler';
|
|
3
|
+
/**
|
|
4
|
+
* Cache-Control set on the published ICS object.
|
|
5
|
+
*
|
|
6
|
+
* A public GCS object otherwise defaults to `public, max-age=3600`, which lets a freshly regenerated feed be
|
|
7
|
+
* served stale from the edge for an hour on top of the subscriber's own polling lag. `Last-Modified` / `ETag`
|
|
8
|
+
* need no work here — GCS derives and serves them, and answers `304` to conditional GETs, automatically.
|
|
9
|
+
*/
|
|
10
|
+
export declare const CALENDAR_ICS_PUBLISHED_CACHE_CONTROL = "public, max-age=300, stale-while-revalidate=60";
|
|
11
|
+
/**
|
|
12
|
+
* Content-Disposition set on the published ICS object.
|
|
13
|
+
*
|
|
14
|
+
* `attachment` because the STORED disposition is now the only one a downloader gets: the download button
|
|
15
|
+
* derives the public url client-side, and a public url — unlike a signed one, whose `responseDisposition`
|
|
16
|
+
* the button used to set per-request — carries no override. Without this a browser hands `text/calendar`
|
|
17
|
+
* straight to the OS calendar app rather than saving it.
|
|
18
|
+
*
|
|
19
|
+
* Harmless for the subscribe channel, which was the reason this was `inline`: a calendar client fetches the
|
|
20
|
+
* feed programmatically and ignores `Content-Disposition` entirely.
|
|
21
|
+
*/
|
|
22
|
+
export declare const CALENDAR_ICS_PUBLISHED_CONTENT_DISPOSITION = "attachment; filename=\"calendar.ics\"";
|
|
23
|
+
/**
|
|
24
|
+
* Configuration for {@link calendarIcsStorageFileProcessingPurposeSubtaskProcessor}.
|
|
25
|
+
*/
|
|
26
|
+
export interface CalendarIcsStorageFileProcessingPurposeSubtaskProcessorConfig {
|
|
27
|
+
readonly calendarFirestoreCollections: CalendarFirestoreCollections;
|
|
28
|
+
readonly storageAccessor: FirebaseStorageAccessor;
|
|
29
|
+
readonly appCalendarTypeConfigService: AppCalendarTypeConfigService;
|
|
30
|
+
/**
|
|
31
|
+
* The domain every generated event UID is suffixed with.
|
|
32
|
+
*/
|
|
33
|
+
readonly icsDomain: string;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Creates the ICS subtask processor for Calendar publishing.
|
|
37
|
+
*
|
|
38
|
+
* Far shorter than the StorageFileGroup zip processor, and deliberately so: there is no stream branch,
|
|
39
|
+
* because `FirebaseStorageAccessorFile.upload()` is non-optional while `uploadStream?` is not, and an ICS for
|
|
40
|
+
* a few hundred events is tens of kilobytes.
|
|
41
|
+
*
|
|
42
|
+
* It renders with `now: calendar.uat` rather than the wall clock, so DTSTAMP moves only when the content
|
|
43
|
+
* moves — which is what makes the output byte-identical for identical input. The processor is idempotent: a
|
|
44
|
+
* retry simply re-renders and re-uploads.
|
|
45
|
+
*
|
|
46
|
+
* The shared cleanup step then writes `ps: SUCCESS`, `pcat: now`, `pn: null`, which is exactly "the published
|
|
47
|
+
* ICS is uploaded and current".
|
|
48
|
+
*
|
|
49
|
+
* @param config - The collections, storage accessor, type registry, and UID domain.
|
|
50
|
+
* @returns A subtask processor config targeting the Calendar ICS purpose.
|
|
51
|
+
*/
|
|
52
|
+
export declare function calendarIcsStorageFileProcessingPurposeSubtaskProcessor(config: CalendarIcsStorageFileProcessingPurposeSubtaskProcessorConfig): StorageFileProcessingPurposeSubtaskProcessorConfigWithTarget<CalendarIcsStorageFileProcessingSubtaskMetadata, CalendarIcsStorageFileProcessingSubtask>;
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
import { type AppFormSpaceTypeConfigServiceRef, type DeleteFormSpaceParams, type ExpireAllExpiredFormSpacesParams, type ExpireAllExpiredFormSpacesResult, type FirestoreContextReference, type FormSpaceDocument, type FormSpaceFirestoreCollections, type FormSpaceId, type NotificationFirestoreCollections, type ProcessAllQueuedFormSpacesParams, type ProcessAllQueuedFormSpacesResult, type RemoveFormSpaceFileParams, type StorageFileFirestoreCollections, type SubmitFormSpaceParams, type SubmitFormSpaceResult, type CreateFormSpaceParams, type UpdateFormSpaceParams } from '@dereekb/firebase';
|
|
2
|
+
import { type FirebaseServerActionsContext, type FirebaseServerAuthServiceRef } from '@dereekb/firebase-server';
|
|
3
|
+
import { type Maybe, type Milliseconds } from '@dereekb/util';
|
|
4
|
+
import { type TransformAndValidateFunctionResult } from '@dereekb/model';
|
|
5
|
+
import { type InjectionToken } from '@nestjs/common';
|
|
6
|
+
import { type NotificationExpediteServiceRef } from '../notification/notification.expedite.service';
|
|
7
|
+
/**
|
|
8
|
+
* NestJS injection token for the {@link BaseFormSpaceServerActionsContext}.
|
|
9
|
+
*/
|
|
10
|
+
export declare const BASE_FORM_SPACE_SERVER_ACTION_CONTEXT_TOKEN: InjectionToken;
|
|
11
|
+
/**
|
|
12
|
+
* NestJS injection token for the fully assembled {@link FormSpaceServerActionsContext}.
|
|
13
|
+
*/
|
|
14
|
+
export declare const FORM_SPACE_SERVER_ACTION_CONTEXT_TOKEN: InjectionToken;
|
|
15
|
+
/**
|
|
16
|
+
* Default page size for {@link expireAllExpiredFormSpacesFactory}.
|
|
17
|
+
*/
|
|
18
|
+
export declare const DEFAULT_FORM_SPACE_EXPIRATION_SWEEP_PAGE_SIZE = 50;
|
|
19
|
+
/**
|
|
20
|
+
* Default wall-clock budget for {@link expireAllExpiredFormSpacesFactory}: one minute.
|
|
21
|
+
*/
|
|
22
|
+
export declare const DEFAULT_FORM_SPACE_EXPIRATION_SWEEP_MAX_RUN_TIME: Milliseconds;
|
|
23
|
+
/**
|
|
24
|
+
* Minimal context providing the Firebase infrastructure and Firestore collections every FormSpace server
|
|
25
|
+
* action needs.
|
|
26
|
+
*/
|
|
27
|
+
export interface BaseFormSpaceServerActionsContext extends FirebaseServerActionsContext, FormSpaceFirestoreCollections, StorageFileFirestoreCollections, NotificationFirestoreCollections, NotificationExpediteServiceRef, FirebaseServerAuthServiceRef, FirestoreContextReference {
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Full context for the FormSpace server actions, adding the type registry.
|
|
31
|
+
*/
|
|
32
|
+
export interface FormSpaceServerActionsContext extends BaseFormSpaceServerActionsContext, AppFormSpaceTypeConfigServiceRef {
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Extra input for {@link FormSpaceServerActions.createFormSpace}, supplied by the callable rather than by
|
|
36
|
+
* the caller: the space's owner is WHO IS CALLING, never a value in the request body.
|
|
37
|
+
*/
|
|
38
|
+
export interface CreateFormSpaceActionInput {
|
|
39
|
+
readonly uid: string;
|
|
40
|
+
readonly ownerKey?: Maybe<string>;
|
|
41
|
+
/**
|
|
42
|
+
* Create the space at THIS id rather than at a generated one.
|
|
43
|
+
*
|
|
44
|
+
* For the SHARED shape — one space per target model, reached by everyone who reaches the target — a
|
|
45
|
+
* generated id lets two concurrent callers each mint one, and neither sees the other's files. Deriving
|
|
46
|
+
* the id with {@link formSpaceIdForModel} makes the create idempotent and lets a client read the space
|
|
47
|
+
* with a plain `get` before it has ever called create.
|
|
48
|
+
*/
|
|
49
|
+
readonly formSpaceId?: Maybe<FormSpaceId>;
|
|
50
|
+
/**
|
|
51
|
+
* Return the existing space when {@link formSpaceId} is already taken, instead of failing.
|
|
52
|
+
*
|
|
53
|
+
* Only meaningful alongside {@link formSpaceId} — a generated id can never collide.
|
|
54
|
+
*/
|
|
55
|
+
readonly getOrCreate?: Maybe<boolean>;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Extra input for {@link FormSpaceServerActions.removeFormSpaceFile}, supplied by the callable rather than by
|
|
59
|
+
* the caller: WHO is removing decides which files they may remove, so it can never be a value in the request
|
|
60
|
+
* body.
|
|
61
|
+
*/
|
|
62
|
+
export interface RemoveFormSpaceFileActionInput {
|
|
63
|
+
/**
|
|
64
|
+
* The uid of the caller.
|
|
65
|
+
*
|
|
66
|
+
* A REQUIRED key with a nullable value, so a call site has to state it rather than inherit an unrestricted
|
|
67
|
+
* remove by forgetting an optional argument. A null uid is refused by any slot whose
|
|
68
|
+
* {@link FormSpaceFileAccess} is `'uploader'`, which is the fail-closed direction.
|
|
69
|
+
*/
|
|
70
|
+
readonly uid: Maybe<string>;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* The server actions for the FormSpace model.
|
|
74
|
+
*
|
|
75
|
+
* @see {@link formSpaceServerActions} for the concrete implementation factory.
|
|
76
|
+
*/
|
|
77
|
+
export declare abstract class FormSpaceServerActions {
|
|
78
|
+
abstract createFormSpace(params: CreateFormSpaceParams): Promise<TransformAndValidateFunctionResult<CreateFormSpaceParams, (input: CreateFormSpaceActionInput) => Promise<FormSpaceDocument>>>;
|
|
79
|
+
abstract updateFormSpace(params: UpdateFormSpaceParams): Promise<TransformAndValidateFunctionResult<UpdateFormSpaceParams, (formSpaceDocument: FormSpaceDocument) => Promise<FormSpaceDocument>>>;
|
|
80
|
+
abstract submitFormSpace(params: SubmitFormSpaceParams): Promise<TransformAndValidateFunctionResult<SubmitFormSpaceParams, (formSpaceDocument: FormSpaceDocument) => Promise<SubmitFormSpaceResult>>>;
|
|
81
|
+
abstract removeFormSpaceFile(params: RemoveFormSpaceFileParams): Promise<TransformAndValidateFunctionResult<RemoveFormSpaceFileParams, (formSpaceDocument: FormSpaceDocument, input: RemoveFormSpaceFileActionInput) => Promise<FormSpaceDocument>>>;
|
|
82
|
+
abstract deleteFormSpace(params: DeleteFormSpaceParams): Promise<TransformAndValidateFunctionResult<DeleteFormSpaceParams, (formSpaceDocument: FormSpaceDocument) => Promise<void>>>;
|
|
83
|
+
abstract processAllQueuedFormSpaces(params: ProcessAllQueuedFormSpacesParams): Promise<TransformAndValidateFunctionResult<ProcessAllQueuedFormSpacesParams, () => Promise<ProcessAllQueuedFormSpacesResult>>>;
|
|
84
|
+
abstract expireAllExpiredFormSpaces(params: ExpireAllExpiredFormSpacesParams): Promise<TransformAndValidateFunctionResult<ExpireAllExpiredFormSpacesParams, () => Promise<ExpireAllExpiredFormSpacesResult>>>;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Creates a concrete {@link FormSpaceServerActions} implementation from the given context.
|
|
88
|
+
*
|
|
89
|
+
* @param context - The fully assembled FormSpace server actions context.
|
|
90
|
+
* @returns The server actions.
|
|
91
|
+
*/
|
|
92
|
+
export declare function formSpaceServerActions(context: FormSpaceServerActionsContext): FormSpaceServerActions;
|
|
93
|
+
/**
|
|
94
|
+
* Factory for the `createFormSpace` action.
|
|
95
|
+
*
|
|
96
|
+
* Rejects an unregistered {@link FormSpaceType} outright. This is the one place the registry is STRICT —
|
|
97
|
+
* a sweep over existing documents falls back to the default config so one bad document cannot take the
|
|
98
|
+
* pass down, but a space that could never be filled in or submitted should not be created at all.
|
|
99
|
+
*
|
|
100
|
+
* @param context - The FormSpace server actions context.
|
|
101
|
+
* @returns An async transform-and-validate function that creates a FormSpace.
|
|
102
|
+
*/
|
|
103
|
+
export declare function createFormSpaceFactory(context: FormSpaceServerActionsContext): import("@dereekb/model").TransformAndValidateFunctionResultFunction<CreateFormSpaceParams<import("@dereekb/firebase").FormSpaceData>, ({ uid, ownerKey, formSpaceId, getOrCreate }: CreateFormSpaceActionInput) => Promise<FormSpaceDocument>, object, unknown>;
|
|
104
|
+
/**
|
|
105
|
+
* Factory for the `updateFormSpace` action.
|
|
106
|
+
*
|
|
107
|
+
* `data` REPLACES the stored JSON rather than merging into it — the client owns the whole form, and a
|
|
108
|
+
* merge would make clearing a field impossible to express.
|
|
109
|
+
*
|
|
110
|
+
* @param context - The FormSpace server actions context.
|
|
111
|
+
* @returns An async transform-and-validate function that updates a draft FormSpace.
|
|
112
|
+
*/
|
|
113
|
+
export declare function updateFormSpaceFactory(context: FormSpaceServerActionsContext): import("@dereekb/model").TransformAndValidateFunctionResultFunction<UpdateFormSpaceParams<import("@dereekb/firebase").FormSpaceData>, (formSpaceDocument: FormSpaceDocument) => Promise<FormSpaceDocument>, object, unknown>;
|
|
114
|
+
/**
|
|
115
|
+
* Factory for the `submitFormSpace` action.
|
|
116
|
+
*
|
|
117
|
+
* The LOCK is taken in a transaction; the processing task is created afterwards. That split is deliberate:
|
|
118
|
+
* `createOrRunUniqueNotificationDocument()` does not accept a transaction, since running a task inside one
|
|
119
|
+
* would hold the lock across the whole handler. A crash in between leaves the space in
|
|
120
|
+
* QUEUED_FOR_PROCESSING with no task, which {@link processAllQueuedFormSpacesFactory} is the backstop for.
|
|
121
|
+
*
|
|
122
|
+
* @param context - The FormSpace server actions context.
|
|
123
|
+
* @returns An async transform-and-validate function that submits a FormSpace.
|
|
124
|
+
*/
|
|
125
|
+
export declare function submitFormSpaceFactory(context: FormSpaceServerActionsContext): import("@dereekb/model").TransformAndValidateFunctionResultFunction<SubmitFormSpaceParams, (formSpaceDocument: FormSpaceDocument) => Promise<SubmitFormSpaceResult>, object, unknown>;
|
|
126
|
+
/**
|
|
127
|
+
* Factory for the `removeFormSpaceFile` action.
|
|
128
|
+
*
|
|
129
|
+
* Drops one file from a slot. The StorageFile is FLAGGED, never deleted inline — the StorageFile delete
|
|
130
|
+
* sweep owns removing the object from GCS, and a second code path that removed it here is how an orphaned
|
|
131
|
+
* object gets left behind.
|
|
132
|
+
*
|
|
133
|
+
* `uc` is deliberately NOT decremented: it counts uploads ACCEPTED over the space's lifetime, and letting a
|
|
134
|
+
* remove refund it would turn `maxUploads` from a bound on work done into a bound on files retained, which
|
|
135
|
+
* an upload/remove loop could then evade entirely.
|
|
136
|
+
*
|
|
137
|
+
* The caller's `removeFile` ROLE opened the door; the type's {@link FormSpaceFileAccess} decides which files
|
|
138
|
+
* inside it are theirs. That second check is made HERE rather than in the callable because it is per-file
|
|
139
|
+
* and needs the space's own `f` array — the same snapshot the removal writes, read under the same
|
|
140
|
+
* transaction, so a concurrent supersede cannot slip a different file under the decision.
|
|
141
|
+
*
|
|
142
|
+
* @param context - The FormSpace server actions context.
|
|
143
|
+
* @returns An async transform-and-validate function that removes one file from a draft FormSpace.
|
|
144
|
+
*/
|
|
145
|
+
export declare function removeFormSpaceFileFactory(context: FormSpaceServerActionsContext): import("@dereekb/model").TransformAndValidateFunctionResultFunction<RemoveFormSpaceFileParams, (formSpaceDocument: FormSpaceDocument, input: RemoveFormSpaceFileActionInput) => Promise<FormSpaceDocument>, object, unknown>;
|
|
146
|
+
/**
|
|
147
|
+
* Creates (or re-runs) the unique submission task for a FormSpace and records its key on `pn`.
|
|
148
|
+
*
|
|
149
|
+
* Shared by `submitFormSpace` and the queued backstop sweep, which is what makes the backstop safe to run
|
|
150
|
+
* against a space whose task already exists: the task is unique per space, so a second attempt resolves to
|
|
151
|
+
* the same document rather than racing a second processor.
|
|
152
|
+
*
|
|
153
|
+
* @param context - The FormSpace server actions context.
|
|
154
|
+
* @returns Queues one FormSpace, reporting the task key and whether this call created it.
|
|
155
|
+
*/
|
|
156
|
+
export declare function _queueFormSpaceForProcessingFactory(context: FormSpaceServerActionsContext): (formSpaceDocument: FormSpaceDocument, runImmediately?: Maybe<boolean>) => Promise<SubmitFormSpaceResult>;
|
|
157
|
+
/**
|
|
158
|
+
* Factory for the `deleteFormSpace` action.
|
|
159
|
+
*
|
|
160
|
+
* Files are FLAGGED, not deleted: the StorageFile delete sweep owns removing the object from GCS, and
|
|
161
|
+
* duplicating that here would mean a second code path that can leave an orphaned object behind.
|
|
162
|
+
*
|
|
163
|
+
* @param context - The FormSpace server actions context.
|
|
164
|
+
* @returns An async transform-and-validate function that deletes a FormSpace and flags its files.
|
|
165
|
+
*/
|
|
166
|
+
export declare function deleteFormSpaceFactory(context: FormSpaceServerActionsContext): import("@dereekb/model").TransformAndValidateFunctionResultFunction<DeleteFormSpaceParams, (formSpaceDocument: FormSpaceDocument) => Promise<void>, object, unknown>;
|
|
167
|
+
/**
|
|
168
|
+
* Factory for the `processAllQueuedFormSpaces` action.
|
|
169
|
+
*
|
|
170
|
+
* The BACKSTOP for a submission whose task creation was lost between the lock transaction and the task
|
|
171
|
+
* write. It is safe to run against a space whose task already exists because the task is unique per space.
|
|
172
|
+
*
|
|
173
|
+
* @param context - The FormSpace server actions context.
|
|
174
|
+
* @returns An async transform-and-validate function that returns batch processing results.
|
|
175
|
+
*/
|
|
176
|
+
export declare function processAllQueuedFormSpacesFactory(context: FormSpaceServerActionsContext): import("@dereekb/model").TransformAndValidateFunctionResultFunction<ProcessAllQueuedFormSpacesParams, () => Promise<ProcessAllQueuedFormSpacesResult>, object, unknown>;
|
|
177
|
+
/**
|
|
178
|
+
* Factory for the `expireAllExpiredFormSpaces` action.
|
|
179
|
+
*
|
|
180
|
+
* A PAGED sweep with a pinned cutoff and a hard time budget, copying `openRouterRunTaskExpirationSweep`.
|
|
181
|
+
* `firestoreDate` persists an ISO8601 string, so Firestore's native TTL cannot be pointed at `eat` — this
|
|
182
|
+
* sweep is the mechanism, not a stopgap.
|
|
183
|
+
*
|
|
184
|
+
* No cursor is needed and one would be meaningless: expiring a page clears its `eat`, so the page no
|
|
185
|
+
* longer matches and re-running the query IS the next page. An empty page is therefore the only "done"
|
|
186
|
+
* signal, which is why the cutoff must be pinned — a cutoff advancing with the clock would let a space
|
|
187
|
+
* that ages mid-sweep join a page not yet reached, making the pass unbounded.
|
|
188
|
+
*
|
|
189
|
+
* @param context - The FormSpace server actions context.
|
|
190
|
+
* @returns An async transform-and-validate function that expires due FormSpaces.
|
|
191
|
+
*/
|
|
192
|
+
export declare function expireAllExpiredFormSpacesFactory(context: FormSpaceServerActionsContext): import("@dereekb/model").TransformAndValidateFunctionResultFunction<ExpireAllExpiredFormSpacesParams, () => Promise<ExpireAllExpiredFormSpacesResult>, object, unknown>;
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { type FormSpaceFileSlot, type FormSpaceId, type FormSpaceSubmitBlocker, type FormSpaceType, type FormSpaceUploadRejectionReason } from '@dereekb/firebase';
|
|
2
|
+
/**
|
|
3
|
+
* Creates an error indicating the app never registered the requested {@link FormSpaceType}.
|
|
4
|
+
*
|
|
5
|
+
* @param formSpaceType - The unregistered type.
|
|
6
|
+
* @returns A bad-request HttpsError with the FORM_SPACE_TYPE_NOT_REGISTERED error code.
|
|
7
|
+
*/
|
|
8
|
+
export declare function formSpaceTypeNotRegisteredError(formSpaceType: FormSpaceType): import("firebase-functions/https").HttpsError;
|
|
9
|
+
/**
|
|
10
|
+
* Creates an error indicating the FormSpace is no longer a draft, so it cannot be changed.
|
|
11
|
+
*
|
|
12
|
+
* @returns A precondition-conflict HttpsError with the FORM_SPACE_NOT_EDITABLE error code.
|
|
13
|
+
*/
|
|
14
|
+
export declare function formSpaceNotEditableError(): import("firebase-functions/https").HttpsError;
|
|
15
|
+
/**
|
|
16
|
+
* Creates an error indicating a required upload slot is still empty at submission time.
|
|
17
|
+
*
|
|
18
|
+
* @param slots - The unsatisfied slots.
|
|
19
|
+
* @returns A precondition-conflict HttpsError with the FORM_SPACE_REQUIRED_SLOT_MISSING error code.
|
|
20
|
+
*/
|
|
21
|
+
export declare function formSpaceRequiredSlotMissingError(slots: FormSpaceFileSlot[]): import("firebase-functions/https").HttpsError;
|
|
22
|
+
/**
|
|
23
|
+
* Creates an error indicating a slot holds a file that failed validation.
|
|
24
|
+
*
|
|
25
|
+
* Carries the per-file reasons rather than only the slot names: "the slot is not acceptable" is not
|
|
26
|
+
* actionable, "scan.png is not a readable PDF" is.
|
|
27
|
+
*
|
|
28
|
+
* @param blockers - The invalid-file blockers reported by `formSpaceSubmitBlockers`.
|
|
29
|
+
* @returns A precondition-conflict HttpsError with the FORM_SPACE_HAS_INVALID_FILES error code.
|
|
30
|
+
*/
|
|
31
|
+
export declare function formSpaceHasInvalidFilesError(blockers: FormSpaceSubmitBlocker[]): import("firebase-functions/https").HttpsError;
|
|
32
|
+
/**
|
|
33
|
+
* Creates an error indicating a slot is still awaiting a validation verdict.
|
|
34
|
+
*
|
|
35
|
+
* @param slots - The slots still being validated.
|
|
36
|
+
* @returns A precondition-conflict HttpsError with the FORM_SPACE_VALIDATION_PENDING error code.
|
|
37
|
+
*/
|
|
38
|
+
export declare function formSpaceValidationPendingError(slots: FormSpaceFileSlot[]): import("firebase-functions/https").HttpsError;
|
|
39
|
+
/**
|
|
40
|
+
* Creates an error indicating the slot does not hold the file that was asked to be removed.
|
|
41
|
+
*
|
|
42
|
+
* @param slot - The slot that was targeted.
|
|
43
|
+
* @returns A bad-request HttpsError with the FORM_SPACE_FILE_NOT_FOUND error code.
|
|
44
|
+
*/
|
|
45
|
+
export declare function formSpaceFileNotFoundError(slot: FormSpaceFileSlot): import("firebase-functions/https").HttpsError;
|
|
46
|
+
/**
|
|
47
|
+
* Creates an error indicating the caller may reach the FormSpace but not this file of it.
|
|
48
|
+
*
|
|
49
|
+
* Deliberately NOT a plain forbidden: the caller passed the space-level role check, and what refused them is
|
|
50
|
+
* the type's `FormSpaceFileAccess` narrowing to the file's own uploader. A distinct code lets a client say
|
|
51
|
+
* "that is someone else's file" rather than "you cannot edit this form".
|
|
52
|
+
*
|
|
53
|
+
* @param slot - The slot holding the file.
|
|
54
|
+
* @returns A bad-request HttpsError with the FORM_SPACE_FILE_ACCESS_DENIED error code.
|
|
55
|
+
*/
|
|
56
|
+
export declare function formSpaceFileAccessDeniedError(slot: FormSpaceFileSlot): import("firebase-functions/https").HttpsError;
|
|
57
|
+
/**
|
|
58
|
+
* Creates an error indicating the upload was rejected by the type's rules.
|
|
59
|
+
*
|
|
60
|
+
* @param reason - Why the upload was rejected.
|
|
61
|
+
* @returns A bad-request HttpsError with the FORM_SPACE_UPLOAD_NOT_ALLOWED error code.
|
|
62
|
+
*/
|
|
63
|
+
export declare function formSpaceUploadNotAllowedError(reason: FormSpaceUploadRejectionReason): import("firebase-functions/https").HttpsError;
|
|
64
|
+
/**
|
|
65
|
+
* Creates an error indicating the uploader is not the user the FormSpace belongs to.
|
|
66
|
+
*
|
|
67
|
+
* @returns A bad-request HttpsError with the FORM_SPACE_UPLOAD_USER_MISMATCH error code.
|
|
68
|
+
*/
|
|
69
|
+
export declare function formSpaceUploadUserMismatchError(): import("firebase-functions/https").HttpsError;
|
|
70
|
+
/**
|
|
71
|
+
* Creates an error indicating the referenced FormSpace does not exist.
|
|
72
|
+
*
|
|
73
|
+
* @returns An unavailable HttpsError with the FORM_SPACE_NOT_FOUND error code.
|
|
74
|
+
*/
|
|
75
|
+
export declare function formSpaceNotFoundError(): import("firebase-functions/https").HttpsError;
|
|
76
|
+
/**
|
|
77
|
+
* Creates an error indicating an explicit FormSpace id is already taken.
|
|
78
|
+
*
|
|
79
|
+
* @param formSpaceId - The id that already exists.
|
|
80
|
+
* @returns A precondition-conflict HttpsError with the FORM_SPACE_ALREADY_EXISTS error code.
|
|
81
|
+
*/
|
|
82
|
+
export declare function formSpaceAlreadyExistsError(formSpaceId: FormSpaceId): import("firebase-functions/https").HttpsError;
|
|
83
|
+
/**
|
|
84
|
+
* Creates an error indicating a get-or-create resolved to a space of a different type.
|
|
85
|
+
*
|
|
86
|
+
* @param formSpaceId - The id that resolved.
|
|
87
|
+
* @param expected - The type that was asked for.
|
|
88
|
+
* @param found - The type the existing space actually carries.
|
|
89
|
+
* @returns A precondition-conflict HttpsError with the FORM_SPACE_TYPE_MISMATCH error code.
|
|
90
|
+
*/
|
|
91
|
+
export declare function formSpaceTypeMismatchError(formSpaceId: FormSpaceId, expected: FormSpaceType, found: FormSpaceType): import("firebase-functions/https").HttpsError;
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { type InjectionToken, type ModuleMetadata } from '@nestjs/common';
|
|
2
|
+
import { type Maybe } from '@dereekb/util';
|
|
3
|
+
import { AppFormSpaceTypeConfigService, type FormSpaceTypeConfig } from '@dereekb/firebase';
|
|
4
|
+
import { type BaseFormSpaceServerActionsContext, FormSpaceServerActions, type FormSpaceServerActionsContext } from './formspace.action.server';
|
|
5
|
+
/**
|
|
6
|
+
* NestJS injection token for the app's `FormSpaceTypeConfig[]` registry.
|
|
7
|
+
*
|
|
8
|
+
* Apps bind this token via {@link appFormSpaceModuleMetadata} by passing `formSpaceTypeConfigs`.
|
|
9
|
+
*/
|
|
10
|
+
export declare const FORM_SPACE_TYPE_CONFIGS_TOKEN: InjectionToken;
|
|
11
|
+
/**
|
|
12
|
+
* Factory that builds the app's {@link AppFormSpaceTypeConfigService} from its registered configs.
|
|
13
|
+
*
|
|
14
|
+
* @param formSpaceTypeConfigs - The app's form space type registry.
|
|
15
|
+
* @returns The service.
|
|
16
|
+
*/
|
|
17
|
+
export declare function appFormSpaceTypeConfigServiceFactory(formSpaceTypeConfigs: FormSpaceTypeConfig[]): AppFormSpaceTypeConfigService;
|
|
18
|
+
/**
|
|
19
|
+
* Factory that assembles the full {@link FormSpaceServerActionsContext}.
|
|
20
|
+
*
|
|
21
|
+
* @param context - The base context providing Firebase infrastructure and collections.
|
|
22
|
+
* @param appFormSpaceTypeConfigServiceInstance - The app's form space type registry service.
|
|
23
|
+
* @returns The fully assembled context.
|
|
24
|
+
*/
|
|
25
|
+
export declare function formSpaceServerActionsContextFactory(context: BaseFormSpaceServerActionsContext, appFormSpaceTypeConfigServiceInstance: AppFormSpaceTypeConfigService): FormSpaceServerActionsContext;
|
|
26
|
+
/**
|
|
27
|
+
* Factory that creates a {@link FormSpaceServerActions} instance from the assembled context.
|
|
28
|
+
*
|
|
29
|
+
* @param context - The fully assembled form space server actions context.
|
|
30
|
+
* @returns The server actions.
|
|
31
|
+
*/
|
|
32
|
+
export declare function formSpaceServerActionsFactory(context: FormSpaceServerActionsContext): FormSpaceServerActions;
|
|
33
|
+
export interface ProvideAppFormSpaceMetadataConfig extends Pick<ModuleMetadata, 'imports' | 'exports' | 'providers'> {
|
|
34
|
+
/**
|
|
35
|
+
* The AppFormSpaceModule requires the following dependencies in order to initialize properly:
|
|
36
|
+
* - BaseFormSpaceServerActionsContext (BASE_FORM_SPACE_SERVER_ACTION_CONTEXT_TOKEN)
|
|
37
|
+
*
|
|
38
|
+
* This module declaration makes it easier to import a module that exports those dependencies.
|
|
39
|
+
*/
|
|
40
|
+
readonly dependencyModule?: Maybe<Required<ModuleMetadata>['imports']['0']>;
|
|
41
|
+
/**
|
|
42
|
+
* The app's {@link FormSpaceType} registry. Bound to {@link FORM_SPACE_TYPE_CONFIGS_TOKEN}.
|
|
43
|
+
*/
|
|
44
|
+
readonly formSpaceTypeConfigs: FormSpaceTypeConfig[];
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Convenience function used to generate ModuleMetadata for an app's FormSpaceModule.
|
|
48
|
+
*
|
|
49
|
+
* By default this module exports:
|
|
50
|
+
* - FormSpaceServerActionsContext (FORM_SPACE_SERVER_ACTION_CONTEXT_TOKEN)
|
|
51
|
+
* - FormSpaceServerActions
|
|
52
|
+
* - AppFormSpaceTypeConfigService
|
|
53
|
+
*
|
|
54
|
+
* @param config - The module configuration.
|
|
55
|
+
* @returns The assembled {@link ModuleMetadata} for the form space module.
|
|
56
|
+
*/
|
|
57
|
+
export declare function appFormSpaceModuleMetadata(config: ProvideAppFormSpaceMetadataConfig): ModuleMetadata;
|