@fanvue/builder-sdk 0.4.0 → 0.5.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/README.md +284 -0
- package/dist/bridge/index.d.ts +1 -1
- package/dist/bridge/index.js +2 -2
- package/dist/{bridge-CGVtI3hr.js → bridge-QnF7P4Co.js} +2 -2
- package/dist/{bridge-CGVtI3hr.js.map → bridge-QnF7P4Co.js.map} +1 -1
- package/dist/core/index.d.ts +2 -2
- package/dist/core/index.js +3 -3
- package/dist/{core-BqdYUMrJ.js → core-BhKiA55a.js} +1318 -9
- package/dist/core-BhKiA55a.js.map +1 -0
- package/dist/index-C3CXrRiw.d.ts +1412 -0
- package/dist/index-C3CXrRiw.d.ts.map +1 -0
- package/dist/{index-BRDYLBlc.d.ts → index-CEFYZtlb.d.ts} +2 -2
- package/dist/{index-BRDYLBlc.d.ts.map → index-CEFYZtlb.d.ts.map} +1 -1
- package/dist/{index-Dr-mZ0qP.d.ts → index-cf3ZMnLJ.d.ts} +26 -2
- package/dist/index-cf3ZMnLJ.d.ts.map +1 -0
- package/dist/index-v_6Z4Q0u.d.ts +84 -0
- package/dist/index-v_6Z4Q0u.d.ts.map +1 -0
- package/dist/{schemas-DbyHF7Xi.js → index.cjs-teGsk6HB.js} +1058 -977
- package/dist/index.cjs-teGsk6HB.js.map +1 -0
- package/dist/nextjs/embedded-app/index.d.ts +2 -2
- package/dist/nextjs/embedded-app/index.js +3 -3
- package/dist/nextjs/off-platform/index.d.ts +3 -3
- package/dist/nextjs/off-platform/index.d.ts.map +1 -1
- package/dist/nextjs/off-platform/index.js +4 -4
- package/dist/nextjs/off-platform/index.js.map +1 -1
- package/dist/nextjs-CvVhtMdb.js +144 -0
- package/dist/nextjs-CvVhtMdb.js.map +1 -0
- package/dist/react/index.d.ts +2 -2
- package/dist/react/index.js +3 -3
- package/package.json +1 -1
- package/dist/core-BqdYUMrJ.js.map +0 -1
- package/dist/index-C4ewLil3.d.ts +0 -48
- package/dist/index-C4ewLil3.d.ts.map +0 -1
- package/dist/index-ClbZoV_Z.d.ts +0 -420
- package/dist/index-ClbZoV_Z.d.ts.map +0 -1
- package/dist/index-Dr-mZ0qP.d.ts.map +0 -1
- package/dist/nextjs-B5Tqgt_n.js +0 -80
- package/dist/nextjs-B5Tqgt_n.js.map +0 -1
- package/dist/schemas-DbyHF7Xi.js.map +0 -1
|
@@ -0,0 +1,1412 @@
|
|
|
1
|
+
import { C as $strip, S as $loose, _ as ZodType, a as ZodDefault, c as ZodLiteral, d as ZodObject, f as ZodOptional, g as ZodTransform, h as ZodString, i as ZodCatch, l as ZodNullable, n as ZodArray, o as ZodDiscriminatedUnion, p as ZodPipe, r as ZodBoolean, s as ZodEnum, t as Result, u as ZodNumber, v as ZodURL, x as output, y as ZodUnion } from "./index-cf3ZMnLJ.js";
|
|
2
|
+
|
|
3
|
+
//#region src/core/constants.d.ts
|
|
4
|
+
/** The `Bearer ` token prefix (includes trailing space). */
|
|
5
|
+
declare const BEARER_PREFIX: "Bearer ";
|
|
6
|
+
/** Response header carrying a refreshed session JWT back to the client. */
|
|
7
|
+
declare const HEADER_UPDATED_SESSION: "X-Updated-Session";
|
|
8
|
+
//#endregion
|
|
9
|
+
//#region src/core/contracts/access-mode.d.ts
|
|
10
|
+
/**
|
|
11
|
+
* Access modes an experience can propose or carry on Fanvue.
|
|
12
|
+
*
|
|
13
|
+
* - `FREE` — visible and playable by anyone.
|
|
14
|
+
* - `SUBSCRIPTION` — requires an active subscription to the creator.
|
|
15
|
+
* - `PAID` — requires a one-off purchase.
|
|
16
|
+
* - `HIDDEN` — reachable only through a share grant, never listed.
|
|
17
|
+
*/
|
|
18
|
+
declare const FANVUE_ACCESS_MODES: readonly ["FREE", "SUBSCRIPTION", "PAID", "HIDDEN"];
|
|
19
|
+
/** An experience access mode. */
|
|
20
|
+
type FanvueAccessMode = (typeof FANVUE_ACCESS_MODES)[number];
|
|
21
|
+
/** Zod schema for {@link FanvueAccessMode}. */
|
|
22
|
+
declare const FanvueAccessModeSchema: ZodEnum<{
|
|
23
|
+
FREE: "FREE";
|
|
24
|
+
SUBSCRIPTION: "SUBSCRIPTION";
|
|
25
|
+
PAID: "PAID";
|
|
26
|
+
HIDDEN: "HIDDEN";
|
|
27
|
+
}>;
|
|
28
|
+
/**
|
|
29
|
+
* Every reason the platform reports when a fan **is** entitled to an
|
|
30
|
+
* experience, as emitted by fanguard's `resolveExperienceAccess`.
|
|
31
|
+
*
|
|
32
|
+
* Documented for completeness and for exhaustive logging/analytics; apps should
|
|
33
|
+
* branch on `entitlement.isEntitled` rather than on a specific reason, because
|
|
34
|
+
* this list grows without an API version bump.
|
|
35
|
+
*
|
|
36
|
+
* - `owner` — the requester is the creator who owns the experience.
|
|
37
|
+
* - `entitled_via_free`, `free` — the experience is `FREE`.
|
|
38
|
+
* - `entitled_via_subscription`, `subscribed` — active creator subscription.
|
|
39
|
+
* - `entitled_via_share` — reached through a share grant.
|
|
40
|
+
* - `purchased` — one-off purchase of the experience.
|
|
41
|
+
* - `app_subscribed` — subscription to the app itself.
|
|
42
|
+
* - `purchased_before_mode_change`, `app_subscribed_before_mode_change` —
|
|
43
|
+
* entitlement grandfathered from before the creator changed the access mode.
|
|
44
|
+
* - `hidden_token_exchange` — the documented exemption to the fail-closed rule:
|
|
45
|
+
* a `HIDDEN` experience exchanges its token without a prior grant.
|
|
46
|
+
*/
|
|
47
|
+
declare const EXPERIENCE_ENTITLED_REASONS: readonly ["owner", "entitled_via_free", "entitled_via_share", "entitled_via_subscription", "free", "subscribed", "purchased", "app_subscribed", "purchased_before_mode_change", "app_subscribed_before_mode_change", "hidden_token_exchange"];
|
|
48
|
+
/**
|
|
49
|
+
* A reason the platform reports for an entitled exchange.
|
|
50
|
+
*
|
|
51
|
+
* Open-ended (`string & {}`) for forward compatibility: the platform can add a
|
|
52
|
+
* reason at any time, and an app must not break on one it has not seen.
|
|
53
|
+
*/
|
|
54
|
+
type ExperienceEntitledReason = (typeof EXPERIENCE_ENTITLED_REASONS)[number] | (string & {});
|
|
55
|
+
/**
|
|
56
|
+
* Every reason the platform reports when a fan is **denied** an experience.
|
|
57
|
+
*
|
|
58
|
+
* These are the only three values fanguard emits today; the type stays open for
|
|
59
|
+
* forward compatibility.
|
|
60
|
+
*/
|
|
61
|
+
declare const EXPERIENCE_DENIAL_REASONS: readonly ["not_subscribed", "not_purchased", "no_share_grant"];
|
|
62
|
+
/**
|
|
63
|
+
* A reason the platform reports for a denied exchange.
|
|
64
|
+
*
|
|
65
|
+
* Open-ended (`string & {}`) so a newly added reason narrows to `null` in
|
|
66
|
+
* {@link accessModeFromDenialReason} instead of failing to type-check.
|
|
67
|
+
*/
|
|
68
|
+
type ExperienceDenialReason = (typeof EXPERIENCE_DENIAL_REASONS)[number] | (string & {});
|
|
69
|
+
/**
|
|
70
|
+
* Recovers the access mode a denied experience must be in, from the denial
|
|
71
|
+
* reason.
|
|
72
|
+
*
|
|
73
|
+
* The token exchange fails closed: an unentitled fan gets a 403 carrying only a
|
|
74
|
+
* denial `reason`, and the experience payload — with it the access mode — is
|
|
75
|
+
* withheld. Mapping the reason back is the only way a locked screen can show
|
|
76
|
+
* the right copy ("subscribe" vs "buy" vs "ask for the link"). An unrecognised
|
|
77
|
+
* reason maps to `null`, meaning "show the generic locked copy".
|
|
78
|
+
*
|
|
79
|
+
* @param reason - The `reason` field from the platform's 403 body.
|
|
80
|
+
* @returns The implied access mode, or `null` when the reason is unrecognised.
|
|
81
|
+
* @example
|
|
82
|
+
* accessModeFromDenialReason('not_subscribed'); // 'SUBSCRIPTION'
|
|
83
|
+
* accessModeFromDenialReason('not_purchased'); // 'PAID'
|
|
84
|
+
* accessModeFromDenialReason('no_share_grant'); // 'HIDDEN'
|
|
85
|
+
* accessModeFromDenialReason('something_new'); // null
|
|
86
|
+
*/
|
|
87
|
+
declare function accessModeFromDenialReason(reason: ExperienceDenialReason): FanvueAccessMode | null;
|
|
88
|
+
//#endregion
|
|
89
|
+
//#region src/core/contracts/env.d.ts
|
|
90
|
+
/**
|
|
91
|
+
* Zod schema for the `FANVUE_*` environment contract.
|
|
92
|
+
*
|
|
93
|
+
* - `FANVUE_APP_UUID` — the app's UUID on Fanvue. Checked against the `appUuid`
|
|
94
|
+
* an exchanged experience token carries, so a token minted for another app is
|
|
95
|
+
* rejected. Defaults to `""`.
|
|
96
|
+
* - `FANVUE_CLIENT_ID` / `FANVUE_CLIENT_SECRET` / `FANVUE_OAUTH_REDIRECT_URI` —
|
|
97
|
+
* OAuth client credentials. Default to `""`; see {@link isFanvueConfigured}.
|
|
98
|
+
* - `FANVUE_API_BASE_URL` — bare origin of the Fanvue API (no `/v0` suffix).
|
|
99
|
+
* Blank falls back to the default.
|
|
100
|
+
* - `FANVUE_AUTH_BASE_URL` — origin of the Fanvue authorization server. Blank
|
|
101
|
+
* falls back to the default.
|
|
102
|
+
* - `FANVUE_WEB_ORIGIN` — origin of the Fanvue web shell. The only variable
|
|
103
|
+
* with real URL validation, because it is concatenated into hrefs a creator
|
|
104
|
+
* or fan clicks: a schemeless value ships a dead link. Blank falls back to
|
|
105
|
+
* the default. Note this does not constrain the scheme.
|
|
106
|
+
* - `FANVUE_API_VERSION` — value sent as `X-Fanvue-API-Version`. Blank falls
|
|
107
|
+
* back to the default.
|
|
108
|
+
* - `FANVUE_EXPERIENCE_URL_TEMPLATE` — optional operator override for
|
|
109
|
+
* per-experience share links. Empty means "derive the URL".
|
|
110
|
+
*/
|
|
111
|
+
declare const FanvueEnvSchema: ZodObject<{
|
|
112
|
+
FANVUE_APP_UUID: ZodDefault<ZodString>;
|
|
113
|
+
FANVUE_CLIENT_ID: ZodDefault<ZodString>;
|
|
114
|
+
FANVUE_CLIENT_SECRET: ZodDefault<ZodString>;
|
|
115
|
+
FANVUE_OAUTH_REDIRECT_URI: ZodDefault<ZodString>;
|
|
116
|
+
FANVUE_API_BASE_URL: ZodPipe<ZodTransform<unknown, unknown>, ZodDefault<ZodString>>;
|
|
117
|
+
FANVUE_AUTH_BASE_URL: ZodPipe<ZodTransform<unknown, unknown>, ZodDefault<ZodString>>;
|
|
118
|
+
FANVUE_WEB_ORIGIN: ZodPipe<ZodTransform<unknown, unknown>, ZodDefault<ZodURL>>;
|
|
119
|
+
FANVUE_API_VERSION: ZodPipe<ZodTransform<unknown, unknown>, ZodDefault<ZodString>>;
|
|
120
|
+
FANVUE_EXPERIENCE_URL_TEMPLATE: ZodDefault<ZodString>;
|
|
121
|
+
}, $strip>;
|
|
122
|
+
/** The validated `FANVUE_*` environment. */
|
|
123
|
+
type FanvueEnv = output<typeof FanvueEnvSchema>;
|
|
124
|
+
/** A read-only view of an environment variable bag. */
|
|
125
|
+
type EnvSource = Readonly<Record<string, string | undefined>>;
|
|
126
|
+
/**
|
|
127
|
+
* Validates an environment bag against {@link FanvueEnvSchema}.
|
|
128
|
+
*
|
|
129
|
+
* Pure and uncached — takes the environment as a parameter so it is unit
|
|
130
|
+
* testable. Prefer {@link fanvueEnv} in application code.
|
|
131
|
+
*
|
|
132
|
+
* @param source - The variables to validate.
|
|
133
|
+
* @returns The validated environment.
|
|
134
|
+
* @throws If a present value fails validation (today: a non-URL
|
|
135
|
+
* `FANVUE_WEB_ORIGIN`).
|
|
136
|
+
*/
|
|
137
|
+
declare function parseFanvueEnv(source: EnvSource): FanvueEnv;
|
|
138
|
+
/**
|
|
139
|
+
* Returns the validated `FANVUE_*` environment, parsing `process.env` on first
|
|
140
|
+
* use and caching the result.
|
|
141
|
+
*
|
|
142
|
+
* @returns The validated environment.
|
|
143
|
+
* @throws If a present value fails validation.
|
|
144
|
+
* @example
|
|
145
|
+
* const baseUrl = fanvueEnv().FANVUE_API_BASE_URL;
|
|
146
|
+
*/
|
|
147
|
+
declare function fanvueEnv(): FanvueEnv;
|
|
148
|
+
/**
|
|
149
|
+
* Clears every piece of memoised state in this module: the {@link fanvueEnv}
|
|
150
|
+
* cache and {@link flagEnabled}'s warned-flag set.
|
|
151
|
+
*
|
|
152
|
+
* Intended for tests, which mutate `process.env` between cases and would
|
|
153
|
+
* otherwise see whichever value the first case happened to freeze. The warn-once
|
|
154
|
+
* set is cleared for the same reason — left in place, whether a case sees the
|
|
155
|
+
* warning depends on which case ran first.
|
|
156
|
+
*/
|
|
157
|
+
declare function resetFanvueEnvCache(): void;
|
|
158
|
+
/**
|
|
159
|
+
* Whether the four Fanvue credential variables are all set.
|
|
160
|
+
*
|
|
161
|
+
* Covers exactly the values OAuth configuration requires, because config
|
|
162
|
+
* creation throws on a missing one and an uncaught throw in a route surfaces as
|
|
163
|
+
* a 500. Call this first and return a "not configured" response instead.
|
|
164
|
+
*
|
|
165
|
+
* @param env - The environment to check. Defaults to the cached
|
|
166
|
+
* {@link fanvueEnv}.
|
|
167
|
+
* @returns `true` when app UUID, client id, client secret and redirect URI are
|
|
168
|
+
* all non-blank. Whitespace-only counts as unset, matching how the schema
|
|
169
|
+
* treats blank values everywhere else in this module.
|
|
170
|
+
* @example
|
|
171
|
+
* if (!isFanvueConfigured()) {
|
|
172
|
+
* return Response.json({ error: { code: 'fanvue_not_configured', message: '…' } }, { status: 503 });
|
|
173
|
+
* }
|
|
174
|
+
*/
|
|
175
|
+
declare function isFanvueConfigured(env?: FanvueEnv): boolean;
|
|
176
|
+
/**
|
|
177
|
+
* Reads a boolean environment flag.
|
|
178
|
+
*
|
|
179
|
+
* A strict `=== "true"` is how one app's `MCP_ENABLED="TRUE"` switched a whole
|
|
180
|
+
* subsystem off in staging: every route answered 404 and the value looked
|
|
181
|
+
* correct in the dashboard. A flag that fails closed on a casing typo and says
|
|
182
|
+
* nothing costs more than one that is simply off, because there is no signal to
|
|
183
|
+
* find. So surrounding whitespace and case do not matter, and a value that
|
|
184
|
+
* still cannot be read as a boolean is warned about **once per flag name** and
|
|
185
|
+
* treated as off — off is the safe answer, but not a silent one.
|
|
186
|
+
*
|
|
187
|
+
* @param name - The environment variable name.
|
|
188
|
+
* @param source - The variables to read from. Defaults to `process.env`.
|
|
189
|
+
* @returns `true` only for `"true"` (after trimming and lowercasing).
|
|
190
|
+
* @see {@link resetFanvueEnvCache} to clear the warned-flag set between tests.
|
|
191
|
+
* @example
|
|
192
|
+
* flagEnabled('MY_APP_DEV_MODE'); // reads process.env.MY_APP_DEV_MODE
|
|
193
|
+
* flagEnabled('MY_APP_DEV_MODE', { MY_APP_DEV_MODE: ' TRUE ' }); // true
|
|
194
|
+
*/
|
|
195
|
+
declare function flagEnabled(name: string, source?: EnvSource): boolean;
|
|
196
|
+
//#endregion
|
|
197
|
+
//#region src/core/contracts/errors.d.ts
|
|
198
|
+
/**
|
|
199
|
+
* `{ message }` — 404s, contactability rejections, invalid creator UUIDs, and
|
|
200
|
+
* the experience-exchange 403 (which adds `reason`). `code` appears on
|
|
201
|
+
* bulk-media per-item errors.
|
|
202
|
+
*/
|
|
203
|
+
declare const FanvueMessageErrorBodySchema: ZodObject<{
|
|
204
|
+
message: ZodString;
|
|
205
|
+
reason: ZodCatch<ZodOptional<ZodNullable<ZodString>>>;
|
|
206
|
+
code: ZodCatch<ZodOptional<ZodNullable<ZodString>>>;
|
|
207
|
+
}, $loose>;
|
|
208
|
+
/**
|
|
209
|
+
* `{ error }` — 401/403/500/503 and upstream tRPC failures, where `error` is the
|
|
210
|
+
* human text; and `{ error, message }` — version and age-verification failures,
|
|
211
|
+
* where `error` is a machine-readable code and `message` the human text.
|
|
212
|
+
*/
|
|
213
|
+
declare const FanvueErrorFieldBodySchema: ZodObject<{
|
|
214
|
+
error: ZodString;
|
|
215
|
+
message: ZodCatch<ZodOptional<ZodNullable<ZodString>>>;
|
|
216
|
+
reason: ZodCatch<ZodOptional<ZodNullable<ZodString>>>;
|
|
217
|
+
}, $loose>;
|
|
218
|
+
/** `{ errors: [{ code, message }] }` — Zod request-validation failures. */
|
|
219
|
+
declare const FanvueIssueListErrorBodySchema: ZodObject<{
|
|
220
|
+
errors: ZodArray<ZodObject<{
|
|
221
|
+
code: ZodCatch<ZodOptional<ZodNullable<ZodString>>>;
|
|
222
|
+
message: ZodString;
|
|
223
|
+
}, $loose>>;
|
|
224
|
+
}, $loose>;
|
|
225
|
+
/** `{ errors: ["Invalid page: too small"] }` — the pagination middleware. */
|
|
226
|
+
declare const FanvueStringListErrorBodySchema: ZodObject<{
|
|
227
|
+
errors: ZodArray<ZodString>;
|
|
228
|
+
}, $loose>;
|
|
229
|
+
/**
|
|
230
|
+
* Any of the four documented Fanvue API error bodies.
|
|
231
|
+
*
|
|
232
|
+
* Member order matters: the `errors` array shapes are tried first because they
|
|
233
|
+
* carry no `message`/`error` key of their own, then `{ error }` (which may also
|
|
234
|
+
* carry a `message`), then `{ message }` alone. Exported for callers that want
|
|
235
|
+
* to validate a body in one step; {@link parseFanvueErrorBody} tries the members
|
|
236
|
+
* individually so that one unreadable field cannot cost the whole body.
|
|
237
|
+
*/
|
|
238
|
+
declare const FanvueErrorBodySchema: ZodUnion<readonly [ZodObject<{
|
|
239
|
+
errors: ZodArray<ZodString>;
|
|
240
|
+
}, $loose>, ZodObject<{
|
|
241
|
+
errors: ZodArray<ZodObject<{
|
|
242
|
+
code: ZodCatch<ZodOptional<ZodNullable<ZodString>>>;
|
|
243
|
+
message: ZodString;
|
|
244
|
+
}, $loose>>;
|
|
245
|
+
}, $loose>, ZodObject<{
|
|
246
|
+
error: ZodString;
|
|
247
|
+
message: ZodCatch<ZodOptional<ZodNullable<ZodString>>>;
|
|
248
|
+
reason: ZodCatch<ZodOptional<ZodNullable<ZodString>>>;
|
|
249
|
+
}, $loose>, ZodObject<{
|
|
250
|
+
message: ZodString;
|
|
251
|
+
reason: ZodCatch<ZodOptional<ZodNullable<ZodString>>>;
|
|
252
|
+
code: ZodCatch<ZodOptional<ZodNullable<ZodString>>>;
|
|
253
|
+
}, $loose>]>;
|
|
254
|
+
/** A parsed Fanvue API error body, before normalisation. */
|
|
255
|
+
type FanvueErrorBody = output<typeof FanvueErrorBodySchema>;
|
|
256
|
+
/**
|
|
257
|
+
* A Fanvue API error body reduced to the three fields a caller can act on.
|
|
258
|
+
*
|
|
259
|
+
* @property message - Human-readable text for logs and debugging. Empty string
|
|
260
|
+
* when the body carried none; callers substitute their own generic message
|
|
261
|
+
* (which is what an end user should see — never upstream text).
|
|
262
|
+
* @property reason - The machine-readable reason, when the platform sent one.
|
|
263
|
+
* Load-bearing on the experience exchange: a 403 **with** a reason is an
|
|
264
|
+
* entitlement refusal, a bare 403 is an app-binding mismatch.
|
|
265
|
+
* @property code - The machine-readable code, when the platform sent one.
|
|
266
|
+
*/
|
|
267
|
+
type NormalisedFanvueError = {
|
|
268
|
+
message: string;
|
|
269
|
+
reason: string | null;
|
|
270
|
+
code: string | null;
|
|
271
|
+
};
|
|
272
|
+
/**
|
|
273
|
+
* Normalises any Fanvue API error body into {@link NormalisedFanvueError}.
|
|
274
|
+
*
|
|
275
|
+
* Never throws and never inspects the HTTP status: a body it cannot read yields
|
|
276
|
+
* an empty `message`, which the transport replaces with its own status-derived
|
|
277
|
+
* text. Multiple validation issues are joined with `; ` so a single log line
|
|
278
|
+
* carries all of them.
|
|
279
|
+
*
|
|
280
|
+
* The `{ error }` shape is disambiguated by whether a `message` sits next to it:
|
|
281
|
+
* `{ error: 'age_verification_required', message: 'Verify…' }` puts the code in
|
|
282
|
+
* `code` and the text in `message`, while a bare `{ error: 'Unauthorized' }` is
|
|
283
|
+
* treated as text only.
|
|
284
|
+
*
|
|
285
|
+
* @param body - A parsed JSON body (or anything at all).
|
|
286
|
+
* @returns The normalised error fields.
|
|
287
|
+
* @example
|
|
288
|
+
* parseFanvueErrorBody({ message: 'Fan is not entitled', reason: 'not_subscribed' });
|
|
289
|
+
* // { message: 'Fan is not entitled', reason: 'not_subscribed', code: null }
|
|
290
|
+
* parseFanvueErrorBody({ errors: [{ code: 'invalid_type', message: 'Expected string' }] });
|
|
291
|
+
* // { message: 'Expected string', reason: null, code: 'invalid_type' }
|
|
292
|
+
* parseFanvueErrorBody('<html>502</html>');
|
|
293
|
+
* // { message: '', reason: null, code: null }
|
|
294
|
+
*/
|
|
295
|
+
declare function parseFanvueErrorBody(body: unknown): NormalisedFanvueError;
|
|
296
|
+
/**
|
|
297
|
+
* Zod schema for an app's own error envelope: `{ error: { code, message } }`.
|
|
298
|
+
*
|
|
299
|
+
* Every Fanvue app helper produces this shape and every client parses it, so it
|
|
300
|
+
* is a contract rather than a convention. The `message` is what an end user
|
|
301
|
+
* reads — upstream and internal text belongs in the log, never in this body.
|
|
302
|
+
*/
|
|
303
|
+
declare const AppErrorEnvelopeSchema: ZodObject<{
|
|
304
|
+
error: ZodObject<{
|
|
305
|
+
code: ZodString;
|
|
306
|
+
message: ZodString;
|
|
307
|
+
}, $strip>;
|
|
308
|
+
}, $strip>;
|
|
309
|
+
/** An app's error response body. */
|
|
310
|
+
type AppErrorEnvelope = output<typeof AppErrorEnvelopeSchema>;
|
|
311
|
+
/**
|
|
312
|
+
* Canonical app-facing error codes for Fanvue-grant failures.
|
|
313
|
+
*
|
|
314
|
+
* - `fanvue_reconnect_required` (401) — the stored Fanvue grant is missing or
|
|
315
|
+
* dead. The creator must reopen the app from Fanvue.
|
|
316
|
+
* - `fanvue_permission_denied` (403) — the grant is alive but lacks the scope
|
|
317
|
+
* for this capability. Reconnecting re-consents the new scope.
|
|
318
|
+
* - `fanvue_api_error` (502) — the Fanvue API failed for any other reason.
|
|
319
|
+
*/
|
|
320
|
+
declare const FANVUE_APP_ERROR_CODES: {
|
|
321
|
+
readonly reconnectRequired: "fanvue_reconnect_required";
|
|
322
|
+
readonly permissionDenied: "fanvue_permission_denied";
|
|
323
|
+
readonly apiError: "fanvue_api_error";
|
|
324
|
+
};
|
|
325
|
+
/** One of the canonical app-facing Fanvue error codes. */
|
|
326
|
+
type FanvueAppErrorCode = (typeof FANVUE_APP_ERROR_CODES)[keyof typeof FANVUE_APP_ERROR_CODES];
|
|
327
|
+
/**
|
|
328
|
+
* The two 401 codes that mean the **Fanvue grant** is gone while the **app
|
|
329
|
+
* session** is still valid.
|
|
330
|
+
*
|
|
331
|
+
* A client that treats every 401 as session expiry signs the creator out of a
|
|
332
|
+
* working session and offers "Reload" — the one action that cannot restore a
|
|
333
|
+
* missing grant. Check membership of this set before running expiry handling,
|
|
334
|
+
* and route these to a reconnect prompt instead.
|
|
335
|
+
*
|
|
336
|
+
* @example
|
|
337
|
+
* if (status === 401 && !NON_SESSION_401_CODES.has(code)) {
|
|
338
|
+
* onSessionExpired();
|
|
339
|
+
* }
|
|
340
|
+
*/
|
|
341
|
+
declare const NON_SESSION_401_CODES: ReadonlySet<string>;
|
|
342
|
+
/**
|
|
343
|
+
* Zod schema for an OAuth 2.0 error response body, normalised to camelCase.
|
|
344
|
+
*
|
|
345
|
+
* Only `error` and `error_description` are kept. Hydra also returns
|
|
346
|
+
* `error_hint` and `error_debug`, which can echo request details back and have
|
|
347
|
+
* no place in an app's own error path.
|
|
348
|
+
*/
|
|
349
|
+
declare const OAuthErrorBodySchema: ZodPipe<ZodObject<{
|
|
350
|
+
error: ZodString;
|
|
351
|
+
error_description: ZodOptional<ZodNullable<ZodString>>;
|
|
352
|
+
}, $loose>, ZodTransform<{
|
|
353
|
+
error: string;
|
|
354
|
+
errorDescription: string | null;
|
|
355
|
+
}, {
|
|
356
|
+
[x: string]: unknown;
|
|
357
|
+
error: string;
|
|
358
|
+
error_description?: string | null | undefined;
|
|
359
|
+
}>>;
|
|
360
|
+
/**
|
|
361
|
+
* An OAuth 2.0 error response body.
|
|
362
|
+
*
|
|
363
|
+
* @property error - The RFC 6749 error code (`invalid_grant`, `invalid_client`,
|
|
364
|
+
* `invalid_scope`, …). This is the distinction that tells a dead refresh token
|
|
365
|
+
* apart from bad client credentials.
|
|
366
|
+
* @property errorDescription - The provider's human-readable description, or
|
|
367
|
+
* `null`. For logs and debugging only.
|
|
368
|
+
*/
|
|
369
|
+
type OAuthErrorBody = output<typeof OAuthErrorBodySchema>;
|
|
370
|
+
//#endregion
|
|
371
|
+
//#region src/core/contracts/experience-protocol.d.ts
|
|
372
|
+
/** Message type an app posts to request the publish modal. */
|
|
373
|
+
declare const PUBLISH_REQUEST_MESSAGE: "fanvue:experience:publish-request";
|
|
374
|
+
/** Message type Fanvue posts back with the outcome of a publish request. */
|
|
375
|
+
declare const PUBLISH_RESULT_MESSAGE: "fanvue:experience:publish-result";
|
|
376
|
+
/** Message type an app posts to request the unpublish confirmation. */
|
|
377
|
+
declare const UNPUBLISH_REQUEST_MESSAGE: "fanvue:experience:unpublish-request";
|
|
378
|
+
/** Message type Fanvue posts back with the outcome of an unpublish request. */
|
|
379
|
+
declare const UNPUBLISH_RESULT_MESSAGE: "fanvue:experience:unpublish-result";
|
|
380
|
+
/**
|
|
381
|
+
* Every message type in the protocol, in request/result pairs.
|
|
382
|
+
*
|
|
383
|
+
* Useful for filtering an incoming `MessageEvent` before schema validation.
|
|
384
|
+
*/
|
|
385
|
+
declare const EXPERIENCE_MESSAGE_TYPES: readonly ["fanvue:experience:publish-request", "fanvue:experience:publish-result", "fanvue:experience:unpublish-request", "fanvue:experience:unpublish-result"];
|
|
386
|
+
/** One of the four `fanvue:experience:*` message types. */
|
|
387
|
+
type ExperienceMessageType = (typeof EXPERIENCE_MESSAGE_TYPES)[number];
|
|
388
|
+
/**
|
|
389
|
+
* Zod schema for the app → Fanvue publish request.
|
|
390
|
+
*
|
|
391
|
+
* `token` is the opaque request token minted by
|
|
392
|
+
* `POST /v0/experiences/request-token` with `action: "publish"`.
|
|
393
|
+
*/
|
|
394
|
+
declare const PublishRequestMessageSchema: ZodObject<{
|
|
395
|
+
type: ZodLiteral<"fanvue:experience:publish-request">;
|
|
396
|
+
token: ZodString;
|
|
397
|
+
}, $strip>;
|
|
398
|
+
/** The app → Fanvue publish request message. */
|
|
399
|
+
type PublishRequestMessage = output<typeof PublishRequestMessageSchema>;
|
|
400
|
+
/**
|
|
401
|
+
* Zod schema for the app → Fanvue unpublish request.
|
|
402
|
+
*
|
|
403
|
+
* `token` is the opaque request token minted by
|
|
404
|
+
* `POST /v0/experiences/request-token` with `action: "unpublish"`.
|
|
405
|
+
*/
|
|
406
|
+
declare const UnpublishRequestMessageSchema: ZodObject<{
|
|
407
|
+
type: ZodLiteral<"fanvue:experience:unpublish-request">;
|
|
408
|
+
token: ZodString;
|
|
409
|
+
}, $strip>;
|
|
410
|
+
/** The app → Fanvue unpublish request message. */
|
|
411
|
+
type UnpublishRequestMessage = output<typeof UnpublishRequestMessageSchema>;
|
|
412
|
+
/**
|
|
413
|
+
* Zod schema for the Fanvue → app publish result.
|
|
414
|
+
*
|
|
415
|
+
* `experienceId` is optional rather than nullable because it mirrors the wire
|
|
416
|
+
* shape: Fanvue omits the key entirely when the creator cancels. `cancelled`
|
|
417
|
+
* covers both a dismissed modal and a server-side rejection of the request
|
|
418
|
+
* token — the two are not distinguishable from this side.
|
|
419
|
+
*
|
|
420
|
+
* Any string is accepted, including `""`. A receiver must not reject an
|
|
421
|
+
* otherwise well-formed result over a useless id: from the app's side a rejected
|
|
422
|
+
* message is indistinguishable from no reply at all, so a publish that did
|
|
423
|
+
* happen would hang until the bridge timed out. Treat a falsy `experienceId` the
|
|
424
|
+
* way an absent one is treated.
|
|
425
|
+
*/
|
|
426
|
+
declare const PublishResultMessageSchema: ZodObject<{
|
|
427
|
+
type: ZodLiteral<"fanvue:experience:publish-result">;
|
|
428
|
+
status: ZodEnum<{
|
|
429
|
+
published: "published";
|
|
430
|
+
cancelled: "cancelled";
|
|
431
|
+
}>;
|
|
432
|
+
experienceId: ZodOptional<ZodString>;
|
|
433
|
+
}, $strip>;
|
|
434
|
+
/** The Fanvue → app publish result message. */
|
|
435
|
+
type PublishResultMessage = output<typeof PublishResultMessageSchema>;
|
|
436
|
+
/** Zod schema for the Fanvue → app unpublish result. */
|
|
437
|
+
declare const UnpublishResultMessageSchema: ZodObject<{
|
|
438
|
+
type: ZodLiteral<"fanvue:experience:unpublish-result">;
|
|
439
|
+
status: ZodEnum<{
|
|
440
|
+
cancelled: "cancelled";
|
|
441
|
+
unpublished: "unpublished";
|
|
442
|
+
}>;
|
|
443
|
+
}, $strip>;
|
|
444
|
+
/** The Fanvue → app unpublish result message. */
|
|
445
|
+
type UnpublishResultMessage = output<typeof UnpublishResultMessageSchema>;
|
|
446
|
+
/**
|
|
447
|
+
* Zod schema for any message in the protocol, discriminated on `type`.
|
|
448
|
+
*
|
|
449
|
+
* @example
|
|
450
|
+
* const parsed = ExperienceMessageSchema.safeParse(event.data);
|
|
451
|
+
* if (parsed.success && parsed.data.type === PUBLISH_RESULT_MESSAGE) {
|
|
452
|
+
* // parsed.data is a PublishResultMessage
|
|
453
|
+
* }
|
|
454
|
+
*/
|
|
455
|
+
declare const ExperienceMessageSchema: ZodDiscriminatedUnion<[ZodObject<{
|
|
456
|
+
type: ZodLiteral<"fanvue:experience:publish-request">;
|
|
457
|
+
token: ZodString;
|
|
458
|
+
}, $strip>, ZodObject<{
|
|
459
|
+
type: ZodLiteral<"fanvue:experience:publish-result">;
|
|
460
|
+
status: ZodEnum<{
|
|
461
|
+
published: "published";
|
|
462
|
+
cancelled: "cancelled";
|
|
463
|
+
}>;
|
|
464
|
+
experienceId: ZodOptional<ZodString>;
|
|
465
|
+
}, $strip>, ZodObject<{
|
|
466
|
+
type: ZodLiteral<"fanvue:experience:unpublish-request">;
|
|
467
|
+
token: ZodString;
|
|
468
|
+
}, $strip>, ZodObject<{
|
|
469
|
+
type: ZodLiteral<"fanvue:experience:unpublish-result">;
|
|
470
|
+
status: ZodEnum<{
|
|
471
|
+
cancelled: "cancelled";
|
|
472
|
+
unpublished: "unpublished";
|
|
473
|
+
}>;
|
|
474
|
+
}, $strip>], "type">;
|
|
475
|
+
/** Any message in the `fanvue:experience:*` protocol. */
|
|
476
|
+
type ExperienceMessage = output<typeof ExperienceMessageSchema>;
|
|
477
|
+
/**
|
|
478
|
+
* Narrows unknown `MessageEvent` data to a {@link PublishResultMessage}.
|
|
479
|
+
*
|
|
480
|
+
* @param value - The raw `event.data` from a `message` event.
|
|
481
|
+
* @returns `true` when the value validates against the publish-result schema.
|
|
482
|
+
* @example
|
|
483
|
+
* if (isPublishResultMessage(event.data) && isFanvueOrigin(event.origin)) {
|
|
484
|
+
* settle(event.data);
|
|
485
|
+
* }
|
|
486
|
+
*/
|
|
487
|
+
declare function isPublishResultMessage(value: unknown): value is PublishResultMessage;
|
|
488
|
+
/**
|
|
489
|
+
* Narrows unknown `MessageEvent` data to an {@link UnpublishResultMessage}.
|
|
490
|
+
*
|
|
491
|
+
* @param value - The raw `event.data` from a `message` event.
|
|
492
|
+
* @returns `true` when the value validates against the unpublish-result schema.
|
|
493
|
+
*/
|
|
494
|
+
declare function isUnpublishResultMessage(value: unknown): value is UnpublishResultMessage;
|
|
495
|
+
/**
|
|
496
|
+
* Whether an origin belongs to the Fanvue web shell.
|
|
497
|
+
*
|
|
498
|
+
* Mirrors the `frame-ancestors 'self' https://fanvue.com https://*.fanvue.com`
|
|
499
|
+
* CSP allowlist every embedded app ships. Eden posts its replies with
|
|
500
|
+
* `targetOrigin: "*"`, so validating `event.origin` on receipt is the only
|
|
501
|
+
* app-side control against a sibling frame forging a publish success. Requires
|
|
502
|
+
* `https:` — a plaintext origin is never Fanvue.
|
|
503
|
+
*
|
|
504
|
+
* @param origin - The `event.origin` of an incoming message.
|
|
505
|
+
* @returns `true` for `https://fanvue.com` and any `https://*.fanvue.com` host.
|
|
506
|
+
* @example
|
|
507
|
+
* isFanvueOrigin('https://www.fanvue.com'); // true
|
|
508
|
+
* isFanvueOrigin('http://fanvue.com'); // false (not https)
|
|
509
|
+
* isFanvueOrigin('https://fanvue.com.evil.test'); // false
|
|
510
|
+
*/
|
|
511
|
+
declare function isFanvueOrigin(origin: string): boolean;
|
|
512
|
+
//#endregion
|
|
513
|
+
//#region src/core/contracts/pagination.d.ts
|
|
514
|
+
/**
|
|
515
|
+
* Largest `size` the platform accepts on an offset-paginated route.
|
|
516
|
+
*
|
|
517
|
+
* The API responds `400` above this, so callers clamp client-side (see
|
|
518
|
+
* {@link clampPageSize}) rather than turning an over-large request into a
|
|
519
|
+
* failure the caller cannot act on.
|
|
520
|
+
*/
|
|
521
|
+
declare const MAX_PAGE_SIZE = 50;
|
|
522
|
+
/** The platform's default `size` when the query parameter is omitted. */
|
|
523
|
+
declare const DEFAULT_PAGE_SIZE = 15;
|
|
524
|
+
/**
|
|
525
|
+
* Clamps a requested page size into the platform's accepted range.
|
|
526
|
+
*
|
|
527
|
+
* Non-finite and non-integer inputs fall back to {@link DEFAULT_PAGE_SIZE}
|
|
528
|
+
* rather than being rounded, because a fractional `size` is a caller bug and
|
|
529
|
+
* the platform would reject it.
|
|
530
|
+
*
|
|
531
|
+
* @param requested - The page size a caller asked for.
|
|
532
|
+
* @returns An integer in `[1, MAX_PAGE_SIZE]`.
|
|
533
|
+
* @example
|
|
534
|
+
* clampPageSize(200); // 50
|
|
535
|
+
* clampPageSize(0); // 1
|
|
536
|
+
* clampPageSize(NaN); // 15
|
|
537
|
+
*/
|
|
538
|
+
declare function clampPageSize(requested: number): number;
|
|
539
|
+
/**
|
|
540
|
+
* Zod schema for the `pagination` object on offset-paginated `v0` responses.
|
|
541
|
+
*
|
|
542
|
+
* `size` is the number of items actually returned, not the requested page size
|
|
543
|
+
* (styx builds it as `data.length`), and `hasMore` is the only reliable
|
|
544
|
+
* end-of-list signal — the platform does not send a total on most routes.
|
|
545
|
+
*
|
|
546
|
+
* `size` therefore allows `0`: paging past the end returns `{ data: [], size: 0 }`,
|
|
547
|
+
* which is a well-formed response and must not fail validation. The `1..50`
|
|
548
|
+
* bound belongs to the *request* parameter — see {@link clampPageSize}.
|
|
549
|
+
*/
|
|
550
|
+
declare const OffsetPaginationSchema: ZodObject<{
|
|
551
|
+
page: ZodNumber;
|
|
552
|
+
size: ZodNumber;
|
|
553
|
+
hasMore: ZodBoolean;
|
|
554
|
+
}, $strip>;
|
|
555
|
+
/** The `pagination` object on an offset-paginated response. */
|
|
556
|
+
type OffsetPagination = output<typeof OffsetPaginationSchema>;
|
|
557
|
+
/**
|
|
558
|
+
* Zod schema for `GET /v0/subscribers`' hybrid pagination.
|
|
559
|
+
*
|
|
560
|
+
* Offset fields plus a keyset cursor that is `null` when the caller sorts by
|
|
561
|
+
* name (that ordering cannot be resumed from a cursor).
|
|
562
|
+
*/
|
|
563
|
+
declare const HybridPaginationSchema: ZodObject<{
|
|
564
|
+
page: ZodNumber;
|
|
565
|
+
size: ZodNumber;
|
|
566
|
+
hasMore: ZodBoolean;
|
|
567
|
+
nextCursor: ZodNullable<ZodString>;
|
|
568
|
+
}, $strip>;
|
|
569
|
+
/** The `pagination` object on the hybrid `v0` subscribers response. */
|
|
570
|
+
type HybridPagination = output<typeof HybridPaginationSchema>;
|
|
571
|
+
/**
|
|
572
|
+
* Builds the response schema for an offset-paginated list of `item`.
|
|
573
|
+
*
|
|
574
|
+
* @param item - Schema for a single row of `data`.
|
|
575
|
+
* @returns A schema for `{ data, pagination }`.
|
|
576
|
+
* @example
|
|
577
|
+
* const SubscribersPageSchema = offsetPageSchema(SubscriberSchema);
|
|
578
|
+
* const page = SubscribersPageSchema.parse(body);
|
|
579
|
+
* page.pagination.hasMore; // boolean
|
|
580
|
+
*/
|
|
581
|
+
declare function offsetPageSchema<TItem extends ZodType>(item: TItem): ZodObject<{
|
|
582
|
+
data: ZodArray<TItem>;
|
|
583
|
+
pagination: typeof OffsetPaginationSchema;
|
|
584
|
+
}>;
|
|
585
|
+
/**
|
|
586
|
+
* Builds the response schema for a cursor-paginated list of `item`.
|
|
587
|
+
*
|
|
588
|
+
* `nextCursor` is `null` on the last page. Cursors are opaque and pin the
|
|
589
|
+
* sort, filters and creator they were minted for, so they cannot be replayed
|
|
590
|
+
* against a different query.
|
|
591
|
+
*
|
|
592
|
+
* `total` is the third field of the platform's `v1` keyset envelope
|
|
593
|
+
* (`{ data, nextCursor, total }`): the platform sends a number only where a
|
|
594
|
+
* count is free or cheap, `null` on large keyset lists (the count is the
|
|
595
|
+
* expensive query keyset avoids), and the older `v0` cursor routes omit the
|
|
596
|
+
* key entirely. All three normalise to `total: null` or a number here, so a
|
|
597
|
+
* caller never branches on "absent vs null".
|
|
598
|
+
*
|
|
599
|
+
* @param item - Schema for a single row of `data`.
|
|
600
|
+
* @returns A schema for `{ data, nextCursor, total }`.
|
|
601
|
+
* @example
|
|
602
|
+
* const PaymentsPageSchema = cursorPageSchema(CheckoutPaymentSchema);
|
|
603
|
+
* const page = PaymentsPageSchema.parse(body);
|
|
604
|
+
* const done = page.nextCursor === null;
|
|
605
|
+
*/
|
|
606
|
+
declare function cursorPageSchema<TItem extends ZodType>(item: TItem): ZodObject<{
|
|
607
|
+
data: ZodArray<TItem>;
|
|
608
|
+
nextCursor: ZodNullable<ZodString>;
|
|
609
|
+
total: ZodDefault<ZodNullable<ZodNumber>>;
|
|
610
|
+
}>;
|
|
611
|
+
//#endregion
|
|
612
|
+
//#region src/core/defaults.d.ts
|
|
613
|
+
/** Default OAuth scopes requested during authorization. */
|
|
614
|
+
declare const DEFAULT_SCOPES: "openid offline_access offline";
|
|
615
|
+
/** Default OAuth issuer URL for Fanvue authentication. */
|
|
616
|
+
declare const DEFAULT_ISSUER_URL: "https://auth.fanvue.com";
|
|
617
|
+
/** Default base URL for the Fanvue API. */
|
|
618
|
+
declare const DEFAULT_API_BASE_URL: "https://api.fanvue.com";
|
|
619
|
+
/** Default base URL for the Fanvue platform (embedded authorize-on-behalf). */
|
|
620
|
+
declare const DEFAULT_PLATFORM_URL: "https://www.fanvue.com";
|
|
621
|
+
/** The Fanvue API version header value sent with every request. */
|
|
622
|
+
declare const API_VERSION: "2025-06-26";
|
|
623
|
+
/**
|
|
624
|
+
* Validates that a URL belongs to the `fanvue.com` domain.
|
|
625
|
+
*
|
|
626
|
+
* @param url - The URL string to validate.
|
|
627
|
+
* @throws If the URL is malformed or its hostname is not `fanvue.com`
|
|
628
|
+
* (or a subdomain of it).
|
|
629
|
+
*/
|
|
630
|
+
declare function assertFanvueDomain(url: string): void;
|
|
631
|
+
//#endregion
|
|
632
|
+
//#region src/core/types.d.ts
|
|
633
|
+
/**
|
|
634
|
+
* Configuration for the OAuth client.
|
|
635
|
+
*
|
|
636
|
+
* @property clientId - The OAuth client ID.
|
|
637
|
+
* @property clientSecret - The OAuth client secret.
|
|
638
|
+
* @property redirectUri - The URI to redirect to after authentication.
|
|
639
|
+
* @property issuerUrl - The OAuth issuer URL, or `null` to use the default.
|
|
640
|
+
* @property apiBaseUrl - The Fanvue API base URL, or `null` to use the default.
|
|
641
|
+
* @property scopes - Additional OAuth scopes to request beyond the defaults, or `null` for defaults only.
|
|
642
|
+
* @property responseMode - The OAuth response mode (e.g., `fragment`), or `null` to omit.
|
|
643
|
+
* @property prompt - The OAuth prompt parameter (e.g., `consent`), or `null` to omit.
|
|
644
|
+
*/
|
|
645
|
+
interface OAuthConfig {
|
|
646
|
+
clientId: string;
|
|
647
|
+
clientSecret: string;
|
|
648
|
+
redirectUri: string;
|
|
649
|
+
issuerUrl: string | null;
|
|
650
|
+
apiBaseUrl: string | null;
|
|
651
|
+
scopes: string | null;
|
|
652
|
+
responseMode: string | null;
|
|
653
|
+
prompt: string | null;
|
|
654
|
+
}
|
|
655
|
+
/**
|
|
656
|
+
* The raw token response returned by the OAuth token endpoint.
|
|
657
|
+
*
|
|
658
|
+
* @property access_token - The access token issued by the authorization server.
|
|
659
|
+
* @property refresh_token - The refresh token, or `null` if not provided.
|
|
660
|
+
* @property expires_in - The lifetime in seconds of the access token.
|
|
661
|
+
* @property token_type - The type of the token (e.g., `Bearer`).
|
|
662
|
+
* @property scope - The scope of the access token, or `null` if not provided.
|
|
663
|
+
* @property id_token - The ID token, or `null` if not provided.
|
|
664
|
+
*/
|
|
665
|
+
interface TokenResponse {
|
|
666
|
+
access_token: string;
|
|
667
|
+
refresh_token: string | null;
|
|
668
|
+
expires_in: number;
|
|
669
|
+
token_type: string;
|
|
670
|
+
scope: string | null;
|
|
671
|
+
id_token: string | null;
|
|
672
|
+
}
|
|
673
|
+
/**
|
|
674
|
+
* The payload stored inside the encrypted session JWT.
|
|
675
|
+
*
|
|
676
|
+
* @property accessToken - The OAuth access token.
|
|
677
|
+
* @property refreshToken - The OAuth refresh token, or `null` if unavailable.
|
|
678
|
+
* @property expiresAt - The timestamp (in milliseconds) when the access token expires.
|
|
679
|
+
* @property tokenType - The type of the token (e.g., `Bearer`), or `null` if unavailable.
|
|
680
|
+
* @property scope - The granted scope, or `null` if unavailable.
|
|
681
|
+
* @property idToken - The ID token, or `null` if unavailable.
|
|
682
|
+
* @property userUuid - The unique identifier of the authenticated user.
|
|
683
|
+
* @property handle - The user's handle/username.
|
|
684
|
+
* @property displayName - The user's display name.
|
|
685
|
+
* @property isCreator - Whether the user is a creator.
|
|
686
|
+
* @property avatarUrl - The URL of the user's avatar, or `null` if not set.
|
|
687
|
+
*/
|
|
688
|
+
interface SessionPayload {
|
|
689
|
+
accessToken: string;
|
|
690
|
+
refreshToken: string | null;
|
|
691
|
+
expiresAt: number;
|
|
692
|
+
tokenType: string | null;
|
|
693
|
+
scope: string | null;
|
|
694
|
+
idToken: string | null;
|
|
695
|
+
userUuid: string;
|
|
696
|
+
handle: string;
|
|
697
|
+
displayName: string;
|
|
698
|
+
isCreator: boolean;
|
|
699
|
+
avatarUrl: string | null;
|
|
700
|
+
}
|
|
701
|
+
/**
|
|
702
|
+
* A Fanvue user profile as returned by the API.
|
|
703
|
+
*
|
|
704
|
+
* @property uuid - The unique identifier of the user.
|
|
705
|
+
* @property email - The user's email address.
|
|
706
|
+
* @property handle - The user's handle/username.
|
|
707
|
+
* @property displayName - The user's display name.
|
|
708
|
+
* @property isCreator - Whether the user is a creator.
|
|
709
|
+
* @property avatarUrl - The URL of the user's avatar, or `null` if not set.
|
|
710
|
+
* @property bannerUrl - The URL of the user's banner, or `null` if not set.
|
|
711
|
+
* @property createdAt - The ISO 8601 timestamp of when the user was created.
|
|
712
|
+
* @property updatedAt - The ISO 8601 timestamp of when the user was last updated, or `null`.
|
|
713
|
+
*/
|
|
714
|
+
interface FanvueUser {
|
|
715
|
+
uuid: string;
|
|
716
|
+
email: string;
|
|
717
|
+
handle: string;
|
|
718
|
+
displayName: string;
|
|
719
|
+
isCreator: boolean;
|
|
720
|
+
avatarUrl: string | null;
|
|
721
|
+
bannerUrl: string | null;
|
|
722
|
+
createdAt: string;
|
|
723
|
+
updatedAt: string | null;
|
|
724
|
+
}
|
|
725
|
+
/**
|
|
726
|
+
* Configuration for the embedded-app (delegated authorize-on-behalf) flow.
|
|
727
|
+
*
|
|
728
|
+
* Extends {@link OAuthConfig} with the Fanvue platform base URL that hosts
|
|
729
|
+
* the `authorize-on-behalf` endpoint.
|
|
730
|
+
*
|
|
731
|
+
* @property platformUrl - The Fanvue platform base URL, or `null` to use the default.
|
|
732
|
+
*/
|
|
733
|
+
interface EmbeddedAuthConfig extends OAuthConfig {
|
|
734
|
+
platformUrl: string | null;
|
|
735
|
+
}
|
|
736
|
+
/** Error type for JSON parsing failures. */
|
|
737
|
+
type JsonParseError = {
|
|
738
|
+
code: 'JSON_PARSE_ERROR';
|
|
739
|
+
rawText: string;
|
|
740
|
+
message: string;
|
|
741
|
+
};
|
|
742
|
+
/**
|
|
743
|
+
* Error type for OAuth operations (token exchange, refresh).
|
|
744
|
+
*
|
|
745
|
+
* `oauthError` carries the authorization server's own error body when it sent a
|
|
746
|
+
* readable one, and is `null` for network errors and unreadable bodies. It is
|
|
747
|
+
* the only way to tell a retired refresh token (`invalid_grant` — the creator
|
|
748
|
+
* must reconnect) from bad client credentials (`invalid_client` — the app is
|
|
749
|
+
* misconfigured); `statusCode` is `400` for both. Diagnostic only: never render
|
|
750
|
+
* it to an end user.
|
|
751
|
+
*/
|
|
752
|
+
type OAuthError = {
|
|
753
|
+
code: 'TOKEN_EXCHANGE_FAILED';
|
|
754
|
+
statusCode: number;
|
|
755
|
+
message: string;
|
|
756
|
+
oauthError: OAuthErrorBody | null;
|
|
757
|
+
} | {
|
|
758
|
+
code: 'TOKEN_REFRESH_FAILED';
|
|
759
|
+
statusCode: number;
|
|
760
|
+
message: string;
|
|
761
|
+
oauthError: OAuthErrorBody | null;
|
|
762
|
+
} | {
|
|
763
|
+
code: 'OAUTH_JSON_PARSE_ERROR';
|
|
764
|
+
rawText: string;
|
|
765
|
+
message: string;
|
|
766
|
+
} | {
|
|
767
|
+
code: 'OAUTH_VALIDATION_ERROR';
|
|
768
|
+
message: string;
|
|
769
|
+
};
|
|
770
|
+
/** Error type for Fanvue API requests. */
|
|
771
|
+
type ApiError = {
|
|
772
|
+
code: 'API_REQUEST_FAILED';
|
|
773
|
+
statusCode: number;
|
|
774
|
+
message: string;
|
|
775
|
+
} | {
|
|
776
|
+
code: 'API_JSON_PARSE_ERROR';
|
|
777
|
+
rawText: string;
|
|
778
|
+
message: string;
|
|
779
|
+
} | {
|
|
780
|
+
code: 'API_VALIDATION_ERROR';
|
|
781
|
+
message: string;
|
|
782
|
+
};
|
|
783
|
+
/** Error type for session JWT verification. */
|
|
784
|
+
type SessionVerifyError = {
|
|
785
|
+
code: 'JWT_VERIFY_FAILED';
|
|
786
|
+
message: string;
|
|
787
|
+
} | {
|
|
788
|
+
code: 'SESSION_VALIDATION_ERROR';
|
|
789
|
+
message: string;
|
|
790
|
+
};
|
|
791
|
+
/**
|
|
792
|
+
* Error type for the embedded authorize-on-behalf step.
|
|
793
|
+
*
|
|
794
|
+
* - `SESSION_TOKEN_REJECTED` — the platform rejected the session token
|
|
795
|
+
* (missing, malformed, or expired — they live ~60 seconds). The user must
|
|
796
|
+
* reopen the embedded surface to receive a fresh one.
|
|
797
|
+
* - `CONSENT_REQUIRED` — the creator has not approved (or has revoked) the
|
|
798
|
+
* in-platform consent for this app. Consent is granted in the Fanvue UI;
|
|
799
|
+
* the app cannot create it.
|
|
800
|
+
* - `AUTHORIZE_ON_BEHALF_FAILED` — any other failure (network error,
|
|
801
|
+
* unexpected status). `statusCode` is `0` for network errors.
|
|
802
|
+
* - `AUTHORIZE_STATE_MISMATCH` — the returned `state` did not match the one
|
|
803
|
+
* sent; the response must not be trusted.
|
|
804
|
+
*/
|
|
805
|
+
type EmbeddedAuthError = {
|
|
806
|
+
code: 'SESSION_TOKEN_REJECTED';
|
|
807
|
+
statusCode: number;
|
|
808
|
+
message: string;
|
|
809
|
+
} | {
|
|
810
|
+
code: 'CONSENT_REQUIRED';
|
|
811
|
+
statusCode: number;
|
|
812
|
+
message: string;
|
|
813
|
+
} | {
|
|
814
|
+
code: 'AUTHORIZE_ON_BEHALF_FAILED';
|
|
815
|
+
statusCode: number;
|
|
816
|
+
message: string;
|
|
817
|
+
} | {
|
|
818
|
+
code: 'AUTHORIZE_STATE_MISMATCH';
|
|
819
|
+
message: string;
|
|
820
|
+
} | {
|
|
821
|
+
code: 'EMBEDDED_JSON_PARSE_ERROR';
|
|
822
|
+
rawText: string;
|
|
823
|
+
message: string;
|
|
824
|
+
} | {
|
|
825
|
+
code: 'EMBEDDED_VALIDATION_ERROR';
|
|
826
|
+
message: string;
|
|
827
|
+
};
|
|
828
|
+
//#endregion
|
|
829
|
+
//#region src/core/oauth.d.ts
|
|
830
|
+
/**
|
|
831
|
+
* Builds an OAuth 2.0 authorization URL with PKCE parameters.
|
|
832
|
+
*
|
|
833
|
+
* @param config - The OAuth configuration.
|
|
834
|
+
* @param opts - Optional overrides. Pass `state` to use a deterministic state value.
|
|
835
|
+
* @returns The authorization URL, the PKCE code verifier, and the state parameter.
|
|
836
|
+
*/
|
|
837
|
+
declare function createAuthorizationUrl(config: OAuthConfig, opts?: {
|
|
838
|
+
state: string | null;
|
|
839
|
+
} | null): Promise<{
|
|
840
|
+
url: URL;
|
|
841
|
+
codeVerifier: string;
|
|
842
|
+
state: string;
|
|
843
|
+
}>;
|
|
844
|
+
/**
|
|
845
|
+
* Exchanges an authorization code for tokens using the OAuth token endpoint.
|
|
846
|
+
*
|
|
847
|
+
* @param config - The OAuth configuration.
|
|
848
|
+
* @param opts - The authorization code, PKCE code verifier, and optional redirect URI override.
|
|
849
|
+
* @returns A `Result` containing `TokenResponse` on success or `OAuthError` on
|
|
850
|
+
* failure. A `TOKEN_EXCHANGE_FAILED` error carries the authorization server's
|
|
851
|
+
* own `oauthError` body when it sent a readable one.
|
|
852
|
+
*/
|
|
853
|
+
declare function exchangeCodeForToken(config: OAuthConfig, opts: {
|
|
854
|
+
code: string;
|
|
855
|
+
codeVerifier: string;
|
|
856
|
+
redirectUri: string | null;
|
|
857
|
+
}): Promise<Result<TokenResponse, OAuthError>>;
|
|
858
|
+
/**
|
|
859
|
+
* Refreshes an access token using a refresh token.
|
|
860
|
+
*
|
|
861
|
+
* @param config - The OAuth configuration.
|
|
862
|
+
* @param refreshToken - The refresh token to use.
|
|
863
|
+
* @returns A `Result` containing `TokenResponse` on success or `OAuthError` on
|
|
864
|
+
* failure. A `TOKEN_REFRESH_FAILED` error carries the authorization server's
|
|
865
|
+
* own `oauthError` body when it sent a readable one — `invalid_grant` there
|
|
866
|
+
* means the stored refresh token is retired and the creator must reconnect.
|
|
867
|
+
*/
|
|
868
|
+
declare function refreshAccessToken(config: OAuthConfig, refreshToken: string): Promise<Result<TokenResponse, OAuthError>>;
|
|
869
|
+
//#endregion
|
|
870
|
+
//#region src/core/session.d.ts
|
|
871
|
+
/**
|
|
872
|
+
* Creates a signed JWT containing the given session payload.
|
|
873
|
+
*
|
|
874
|
+
* @param secret - The secret key used to sign the JWT.
|
|
875
|
+
* @param payload - The session data to embed in the token.
|
|
876
|
+
* @param expiresIn - How long until the token expires (e.g., `"30d"`), or `null` for the default (`"30d"`).
|
|
877
|
+
* @returns The signed JWT string.
|
|
878
|
+
*/
|
|
879
|
+
declare function createSessionJwt(secret: string, payload: SessionPayload, expiresIn?: string | null): Promise<string>;
|
|
880
|
+
/**
|
|
881
|
+
* Verifies a session JWT and returns the validated session payload.
|
|
882
|
+
*
|
|
883
|
+
* @param secret - The secret key used to verify the JWT signature.
|
|
884
|
+
* @param token - The JWT string to verify.
|
|
885
|
+
* @returns A {@link Result} containing the validated {@link SessionPayload}, or a {@link SessionVerifyError}.
|
|
886
|
+
*/
|
|
887
|
+
declare function verifySessionJwt(secret: string, token: string): Promise<Result<SessionPayload, SessionVerifyError>>;
|
|
888
|
+
//#endregion
|
|
889
|
+
//#region src/core/embedded.d.ts
|
|
890
|
+
/**
|
|
891
|
+
* The creator's active colour scheme, as resolved by Fanvue.
|
|
892
|
+
*
|
|
893
|
+
* Fanvue resolves a creator's "system" preference to the scheme actually being
|
|
894
|
+
* rendered, so this is always a definite value — never `'system'`.
|
|
895
|
+
*/
|
|
896
|
+
type FanvueTheme = 'light' | 'dark';
|
|
897
|
+
/**
|
|
898
|
+
* Extracts the embedded session token from a URL.
|
|
899
|
+
*
|
|
900
|
+
* When Fanvue opens an embedded app, it loads the app's embed URL with a
|
|
901
|
+
* short-lived session token appended as a `?token=` query parameter.
|
|
902
|
+
*
|
|
903
|
+
* @param url - The URL to read the token from (e.g. `window.location.href`).
|
|
904
|
+
* @returns The session token, or `null` when absent or the URL is malformed.
|
|
905
|
+
*/
|
|
906
|
+
declare function getSessionTokenFromUrl(url: string | URL): string | null;
|
|
907
|
+
/**
|
|
908
|
+
* Extracts the creator's active colour scheme from a URL.
|
|
909
|
+
*
|
|
910
|
+
* When Fanvue opens an embedded app, it appends the creator's resolved colour
|
|
911
|
+
* scheme as a `?theme=` query parameter (`light` or `dark`), letting the app
|
|
912
|
+
* theme-match Fanvue.
|
|
913
|
+
*
|
|
914
|
+
* @param url - The URL to read the theme from (e.g. `window.location.href`).
|
|
915
|
+
* @returns The {@link FanvueTheme}, or `null` when absent, unrecognised, or the
|
|
916
|
+
* URL is malformed (e.g. the app was opened outside Fanvue).
|
|
917
|
+
*/
|
|
918
|
+
declare function getThemeFromUrl(url: string | URL): FanvueTheme | null;
|
|
919
|
+
/**
|
|
920
|
+
* Requests an authorization code from the Fanvue platform on behalf of the
|
|
921
|
+
* creator currently using the embedded app.
|
|
922
|
+
*
|
|
923
|
+
* This is the "authorize" half of the delegated flow: the platform verifies
|
|
924
|
+
* the session token, runs the OAuth authorize as the creator, and returns the
|
|
925
|
+
* resulting authorization code. The PKCE verifier and client secret never
|
|
926
|
+
* leave the caller — only the challenge is sent.
|
|
927
|
+
*
|
|
928
|
+
* Most apps should use {@link exchangeSessionToken}, which composes this with
|
|
929
|
+
* the code exchange.
|
|
930
|
+
*
|
|
931
|
+
* @param config - The embedded auth configuration.
|
|
932
|
+
* @param sessionToken - The short-lived session token received in the iframe.
|
|
933
|
+
* @param opts - The PKCE code challenge and state to bind the code to.
|
|
934
|
+
* @returns A `Result` containing the authorization code on success or
|
|
935
|
+
* {@link EmbeddedAuthError} on failure.
|
|
936
|
+
*/
|
|
937
|
+
declare function requestAuthorizationCodeOnBehalf(config: EmbeddedAuthConfig, sessionToken: string, opts: {
|
|
938
|
+
codeChallenge: string;
|
|
939
|
+
state: string;
|
|
940
|
+
}): Promise<Result<{
|
|
941
|
+
code: string;
|
|
942
|
+
}, EmbeddedAuthError>>;
|
|
943
|
+
/**
|
|
944
|
+
* Exchanges an embedded session token for OAuth access and refresh tokens.
|
|
945
|
+
*
|
|
946
|
+
* Runs the complete delegated authorize-on-behalf flow:
|
|
947
|
+
*
|
|
948
|
+
* 1. Generates a PKCE verifier/challenge pair and a random `state`.
|
|
949
|
+
* 2. Asks the Fanvue platform to authorize as the creator
|
|
950
|
+
* ({@link requestAuthorizationCodeOnBehalf}).
|
|
951
|
+
* 3. Exchanges the returned code at the token endpoint using the client
|
|
952
|
+
* secret and PKCE verifier.
|
|
953
|
+
*
|
|
954
|
+
* Must run server-side: it uses the client secret. The session token should
|
|
955
|
+
* be used promptly — it expires after ~60 seconds.
|
|
956
|
+
*
|
|
957
|
+
* @param config - The embedded auth configuration. `redirectUri` must be a
|
|
958
|
+
* redirect URI registered on the OAuth client (it is never visited; it only
|
|
959
|
+
* binds the authorization code).
|
|
960
|
+
* @param sessionToken - The short-lived session token received in the iframe.
|
|
961
|
+
* @returns A `Result` containing {@link TokenResponse} on success or an
|
|
962
|
+
* {@link EmbeddedAuthError} / {@link OAuthError} on failure.
|
|
963
|
+
*/
|
|
964
|
+
declare function exchangeSessionToken(config: EmbeddedAuthConfig, sessionToken: string): Promise<Result<TokenResponse, EmbeddedAuthError | OAuthError>>;
|
|
965
|
+
//#endregion
|
|
966
|
+
//#region src/core/json.d.ts
|
|
967
|
+
/**
|
|
968
|
+
* Safely parses a JSON string, returning a `Result` instead of throwing.
|
|
969
|
+
*
|
|
970
|
+
* @param text - The raw text to parse as JSON.
|
|
971
|
+
* @returns `ok(parsed)` on success, or `err({ code, rawText, message })` on failure.
|
|
972
|
+
*/
|
|
973
|
+
declare function safeJsonParse(text: string): Result<unknown, JsonParseError>;
|
|
974
|
+
//#endregion
|
|
975
|
+
//#region src/core/schemas.d.ts
|
|
976
|
+
/** Zod schema for the raw token response from the OAuth token endpoint. */
|
|
977
|
+
declare const TokenResponseSchema: ZodObject<{
|
|
978
|
+
access_token: ZodString;
|
|
979
|
+
refresh_token: ZodDefault<ZodOptional<ZodNullable<ZodString>>>;
|
|
980
|
+
expires_in: ZodNumber;
|
|
981
|
+
token_type: ZodString;
|
|
982
|
+
scope: ZodDefault<ZodOptional<ZodNullable<ZodString>>>;
|
|
983
|
+
id_token: ZodDefault<ZodOptional<ZodNullable<ZodString>>>;
|
|
984
|
+
}, $strip>;
|
|
985
|
+
/** Zod schema for a Fanvue user profile. */
|
|
986
|
+
declare const FanvueUserSchema: ZodObject<{
|
|
987
|
+
uuid: ZodString;
|
|
988
|
+
email: ZodString;
|
|
989
|
+
handle: ZodString;
|
|
990
|
+
displayName: ZodString;
|
|
991
|
+
isCreator: ZodBoolean;
|
|
992
|
+
avatarUrl: ZodNullable<ZodString>;
|
|
993
|
+
bannerUrl: ZodNullable<ZodString>;
|
|
994
|
+
createdAt: ZodString;
|
|
995
|
+
updatedAt: ZodNullable<ZodString>;
|
|
996
|
+
}, $strip>;
|
|
997
|
+
/** Zod schema for the authorize-on-behalf response from the Fanvue platform. */
|
|
998
|
+
declare const AuthorizeOnBehalfResponseSchema: ZodObject<{
|
|
999
|
+
code: ZodString;
|
|
1000
|
+
state: ZodString;
|
|
1001
|
+
}, $strip>;
|
|
1002
|
+
/** Zod schema for the session JWT payload. */
|
|
1003
|
+
declare const SessionPayloadSchema: ZodObject<{
|
|
1004
|
+
accessToken: ZodString;
|
|
1005
|
+
refreshToken: ZodNullable<ZodString>;
|
|
1006
|
+
expiresAt: ZodNumber;
|
|
1007
|
+
tokenType: ZodNullable<ZodString>;
|
|
1008
|
+
scope: ZodNullable<ZodString>;
|
|
1009
|
+
idToken: ZodNullable<ZodString>;
|
|
1010
|
+
userUuid: ZodString;
|
|
1011
|
+
handle: ZodString;
|
|
1012
|
+
displayName: ZodString;
|
|
1013
|
+
isCreator: ZodBoolean;
|
|
1014
|
+
avatarUrl: ZodNullable<ZodString>;
|
|
1015
|
+
}, $loose>;
|
|
1016
|
+
//#endregion
|
|
1017
|
+
//#region src/core/client.d.ts
|
|
1018
|
+
/**
|
|
1019
|
+
* A client for making authenticated requests to the Fanvue API.
|
|
1020
|
+
*/
|
|
1021
|
+
interface FanvueClient {
|
|
1022
|
+
/**
|
|
1023
|
+
* Fetches the currently authenticated user's profile.
|
|
1024
|
+
*
|
|
1025
|
+
* @returns A `Result` containing the {@link FanvueUser} on success or `ApiError` on failure.
|
|
1026
|
+
*/
|
|
1027
|
+
getCurrentUser(): Promise<Result<FanvueUser, ApiError>>;
|
|
1028
|
+
}
|
|
1029
|
+
/**
|
|
1030
|
+
* Creates a new {@link FanvueClient} for making authenticated requests to the Fanvue API.
|
|
1031
|
+
*
|
|
1032
|
+
* @param accessToken - The OAuth access token to authenticate requests.
|
|
1033
|
+
* @param apiBaseUrl - The base URL for the Fanvue API, or `null` to use the default.
|
|
1034
|
+
* @returns A {@link FanvueClient} instance.
|
|
1035
|
+
*/
|
|
1036
|
+
declare function createFanvueClient(accessToken: string, apiBaseUrl: string | null): FanvueClient;
|
|
1037
|
+
//#endregion
|
|
1038
|
+
//#region src/core/machine-auth/machine-auth.d.ts
|
|
1039
|
+
/**
|
|
1040
|
+
* The outcome of authenticating a machine (cron / queue) request.
|
|
1041
|
+
*
|
|
1042
|
+
* `not_configured` is a separate arm on purpose: a deployment with no usable
|
|
1043
|
+
* credential has an operator problem, not an attacker, and the two must map to
|
|
1044
|
+
* different HTTP statuses (503 vs 401). Collapsing them hides a broken deploy
|
|
1045
|
+
* behind what looks like ordinary auth noise, and tells a caller to retry with
|
|
1046
|
+
* better credentials when no credential could ever work.
|
|
1047
|
+
*/
|
|
1048
|
+
type MachineAuthResult = {
|
|
1049
|
+
status: 'authorized';
|
|
1050
|
+
} | {
|
|
1051
|
+
status: 'unauthorized';
|
|
1052
|
+
} | {
|
|
1053
|
+
status: 'not_configured';
|
|
1054
|
+
};
|
|
1055
|
+
/**
|
|
1056
|
+
* A pluggable signed-request strategy — the second way a machine request can
|
|
1057
|
+
* authenticate itself.
|
|
1058
|
+
*
|
|
1059
|
+
* Implemented by the app so the SDK takes no queue-provider dependency. The
|
|
1060
|
+
* verifier owns its own key material and rotation; it must return `false`
|
|
1061
|
+
* (never throw) when it cannot verify, though a throw is caught and treated as
|
|
1062
|
+
* a failure regardless.
|
|
1063
|
+
*/
|
|
1064
|
+
interface SignedRequestVerifier {
|
|
1065
|
+
/**
|
|
1066
|
+
* @param request - The incoming request, whose URL and headers are usually
|
|
1067
|
+
* part of the signed material.
|
|
1068
|
+
* @param rawBody - The exact bytes received. Never a reserialized body: a
|
|
1069
|
+
* round-trip through `JSON.parse`/`stringify` changes whitespace and key
|
|
1070
|
+
* order and invalidates the signature.
|
|
1071
|
+
* @returns Whether the signature is authentic.
|
|
1072
|
+
*/
|
|
1073
|
+
verify: (request: Request, rawBody: Uint8Array) => Promise<boolean>;
|
|
1074
|
+
}
|
|
1075
|
+
/**
|
|
1076
|
+
* Credentials and strategies available to {@link requireMachineAuth}.
|
|
1077
|
+
*/
|
|
1078
|
+
interface MachineAuthOptions {
|
|
1079
|
+
/**
|
|
1080
|
+
* Shared bearer secret (the `CRON_SECRET` pattern). `null` when unset. A
|
|
1081
|
+
* secret shorter than {@link MINIMUM_BEARER_SECRET_LENGTH} is treated as
|
|
1082
|
+
* unset rather than compared.
|
|
1083
|
+
*/
|
|
1084
|
+
bearerSecret: string | null;
|
|
1085
|
+
/** Signed-request strategy, or `null` when the app plugs none in. */
|
|
1086
|
+
signedRequestVerifier: SignedRequestVerifier | null;
|
|
1087
|
+
/**
|
|
1088
|
+
* The exact request bytes, required by {@link signedRequestVerifier}. `null`
|
|
1089
|
+
* is allowed (and reads as an empty body) when no verifier is configured.
|
|
1090
|
+
*/
|
|
1091
|
+
rawBody: Uint8Array | null;
|
|
1092
|
+
}
|
|
1093
|
+
/**
|
|
1094
|
+
* Shortest bearer secret the SDK will compare against.
|
|
1095
|
+
*
|
|
1096
|
+
* A cron endpoint is reachable by anyone on the internet and its secret is
|
|
1097
|
+
* never rotated by a user, so a guessable one is a standing invitation. Below
|
|
1098
|
+
* this length the secret is treated as absent — the endpoint reports
|
|
1099
|
+
* `not_configured` instead of quietly accepting a weak credential.
|
|
1100
|
+
*/
|
|
1101
|
+
declare const MINIMUM_BEARER_SECRET_LENGTH = 32;
|
|
1102
|
+
/**
|
|
1103
|
+
* Authenticates a machine-invoked route (cron tick, queue drain, sweeper).
|
|
1104
|
+
*
|
|
1105
|
+
* Two strategies, tried in order, either of which is sufficient:
|
|
1106
|
+
*
|
|
1107
|
+
* 1. a shared bearer secret compared in constant time, and
|
|
1108
|
+
* 2. an app-supplied {@link SignedRequestVerifier}.
|
|
1109
|
+
*
|
|
1110
|
+
* Deny by default. When neither strategy is usable — no verifier and a missing
|
|
1111
|
+
* or too-short `bearerSecret` — the result is `not_configured`, which the
|
|
1112
|
+
* caller should surface as 503; `unauthorized` (401) means a strategy was
|
|
1113
|
+
* available and the request failed it.
|
|
1114
|
+
*
|
|
1115
|
+
* Web-standard `Request` only, so this works unchanged in a Next.js route
|
|
1116
|
+
* handler, a Node server and an edge function.
|
|
1117
|
+
*
|
|
1118
|
+
* @param request - The incoming machine request.
|
|
1119
|
+
* @param options - Available credentials and strategies.
|
|
1120
|
+
* @returns The discriminated {@link MachineAuthResult}.
|
|
1121
|
+
* @example
|
|
1122
|
+
* // Bearer-only cron route.
|
|
1123
|
+
* const auth = await requireMachineAuth(request, {
|
|
1124
|
+
* bearerSecret: process.env.CRON_SECRET ?? null,
|
|
1125
|
+
* signedRequestVerifier: null,
|
|
1126
|
+
* rawBody: null,
|
|
1127
|
+
* });
|
|
1128
|
+
* if (auth.status === 'not_configured') return new Response(null, { status: 503 });
|
|
1129
|
+
* if (auth.status === 'unauthorized') return new Response(null, { status: 401 });
|
|
1130
|
+
* @example
|
|
1131
|
+
* // Queue drain that also accepts QStash-signed deliveries. `@upstash/qstash`
|
|
1132
|
+
* // is intentionally NOT a dependency of this package — the app owns it:
|
|
1133
|
+
* //
|
|
1134
|
+
* // import { Receiver } from '@upstash/qstash';
|
|
1135
|
+
* //
|
|
1136
|
+
* // const qstashVerifier: SignedRequestVerifier = {
|
|
1137
|
+
* // verify: async (request, rawBody) => {
|
|
1138
|
+
* // const signature = request.headers.get('upstash-signature');
|
|
1139
|
+
* // const currentSigningKey = process.env.QSTASH_CURRENT_SIGNING_KEY;
|
|
1140
|
+
* // const nextSigningKey = process.env.QSTASH_NEXT_SIGNING_KEY;
|
|
1141
|
+
* // if (!signature || !currentSigningKey || !nextSigningKey) return false;
|
|
1142
|
+
* // return new Receiver({ currentSigningKey, nextSigningKey }).verify({
|
|
1143
|
+
* // signature,
|
|
1144
|
+
* // body: new TextDecoder().decode(rawBody),
|
|
1145
|
+
* // url: request.url,
|
|
1146
|
+
* // upstashRegion: request.headers.get('upstash-region') ?? undefined,
|
|
1147
|
+
* // });
|
|
1148
|
+
* // },
|
|
1149
|
+
* // };
|
|
1150
|
+
* //
|
|
1151
|
+
* // Pass the raw bytes, never a reparsed body:
|
|
1152
|
+
* const rawBody = new Uint8Array(await request.arrayBuffer());
|
|
1153
|
+
* const auth = await requireMachineAuth(request, {
|
|
1154
|
+
* bearerSecret: process.env.CRON_SECRET ?? null,
|
|
1155
|
+
* signedRequestVerifier: qstashVerifier,
|
|
1156
|
+
* rawBody,
|
|
1157
|
+
* });
|
|
1158
|
+
*/
|
|
1159
|
+
declare function requireMachineAuth(request: Request, options: MachineAuthOptions): Promise<MachineAuthResult>;
|
|
1160
|
+
/**
|
|
1161
|
+
* Clamps a caller-supplied batch size to a safe positive bound.
|
|
1162
|
+
*
|
|
1163
|
+
* Machine routes take `?limit=` to let an operator drain faster, which is also
|
|
1164
|
+
* an unauthenticated-shaped lever on database load, so the value is bounded
|
|
1165
|
+
* rather than trusted. Anything unparseable, non-integer, zero or negative
|
|
1166
|
+
* falls back to the default; the default itself is capped by `max`, so a
|
|
1167
|
+
* misconfigured default cannot exceed the ceiling either.
|
|
1168
|
+
*
|
|
1169
|
+
* The result is always a positive safe integer, even when `defaultSize` or
|
|
1170
|
+
* `max` is itself invalid (non-integer, zero or negative): a query builder
|
|
1171
|
+
* handed a negative limit can interpret it as "no limit" — the exact fail-open
|
|
1172
|
+
* this function exists to prevent — so a misconfigured constant degrades to a
|
|
1173
|
+
* batch size of 1, never to an unbounded one.
|
|
1174
|
+
*
|
|
1175
|
+
* @param requested - Raw query value, e.g. `searchParams.get('limit')`.
|
|
1176
|
+
* @param defaultSize - Size to use when `requested` is absent or invalid.
|
|
1177
|
+
* @param max - Hard ceiling.
|
|
1178
|
+
* @returns A positive safe integer batch size.
|
|
1179
|
+
* @example
|
|
1180
|
+
* boundedBatchSize(null, 20, 100); // 20
|
|
1181
|
+
* boundedBatchSize('0', 20, 100); // 20
|
|
1182
|
+
* boundedBatchSize('1000', 20, 100); // 100
|
|
1183
|
+
*/
|
|
1184
|
+
declare function boundedBatchSize(requested: string | null, defaultSize: number, max: number): number;
|
|
1185
|
+
//#endregion
|
|
1186
|
+
//#region src/core/observability/log-fields.d.ts
|
|
1187
|
+
/**
|
|
1188
|
+
* The log levels a structured event can be emitted at.
|
|
1189
|
+
*/
|
|
1190
|
+
type LogLevel = 'info' | 'warn' | 'error';
|
|
1191
|
+
/**
|
|
1192
|
+
* A scalar that is safe to place in a log line.
|
|
1193
|
+
*
|
|
1194
|
+
* Objects and arrays are deliberately absent: an allowlisted key whose value is
|
|
1195
|
+
* a structure would smuggle un-reviewed fields (an Error, a token bag, a whole
|
|
1196
|
+
* request) past the allowlist, so those values are dropped rather than
|
|
1197
|
+
* serialised.
|
|
1198
|
+
*/
|
|
1199
|
+
type SafeLogValue = string | number | boolean | null;
|
|
1200
|
+
/**
|
|
1201
|
+
* Filters an arbitrary field bag down to the fields that are safe to log.
|
|
1202
|
+
*
|
|
1203
|
+
* Created by {@link createSafeLogFields}.
|
|
1204
|
+
*/
|
|
1205
|
+
type SafeLogFields = (fields?: Record<string, unknown>) => Record<string, SafeLogValue>;
|
|
1206
|
+
/**
|
|
1207
|
+
* Emits one structured, allowlisted log event.
|
|
1208
|
+
*
|
|
1209
|
+
* Created by {@link createLogEvent}.
|
|
1210
|
+
*/
|
|
1211
|
+
type LogEvent = (level: LogLevel, event: string, fields?: Record<string, unknown>) => void;
|
|
1212
|
+
/**
|
|
1213
|
+
* The subset of `console` a {@link LogEvent} writes to. Injectable so the
|
|
1214
|
+
* privacy behaviour can be asserted in tests.
|
|
1215
|
+
*/
|
|
1216
|
+
interface LogSink {
|
|
1217
|
+
info: (...args: readonly unknown[]) => void;
|
|
1218
|
+
warn: (...args: readonly unknown[]) => void;
|
|
1219
|
+
error: (...args: readonly unknown[]) => void;
|
|
1220
|
+
}
|
|
1221
|
+
/**
|
|
1222
|
+
* Options for {@link createLogEvent}.
|
|
1223
|
+
*/
|
|
1224
|
+
interface LogEventOptions {
|
|
1225
|
+
/** Prefix written before the payload, e.g. `'[my-app]'`. */
|
|
1226
|
+
prefix: string;
|
|
1227
|
+
/** Allowlist to apply. Defaults to `createSafeLogFields()`. */
|
|
1228
|
+
safeLogFields: SafeLogFields;
|
|
1229
|
+
/** Where lines are written. Defaults to the global `console`. */
|
|
1230
|
+
sink: LogSink;
|
|
1231
|
+
}
|
|
1232
|
+
/**
|
|
1233
|
+
* The generic Fanvue log keys every app shares.
|
|
1234
|
+
*
|
|
1235
|
+
* Anything app-specific (a wheel id, a bounty id, a claim status) is added per
|
|
1236
|
+
* app via `createSafeLogFields(['wheelId', ...])`.
|
|
1237
|
+
*/
|
|
1238
|
+
declare const BASE_ALLOWED_LOG_KEYS: readonly string[];
|
|
1239
|
+
/**
|
|
1240
|
+
* Builds an allowlisting log-field filter.
|
|
1241
|
+
*
|
|
1242
|
+
* The returned function is the only sanctioned way to get caller-supplied
|
|
1243
|
+
* fields into a log line. It fails closed in three independent ways:
|
|
1244
|
+
*
|
|
1245
|
+
* 1. A key that is not allowlisted is dropped entirely (so a new field cannot
|
|
1246
|
+
* reach the logs until someone adds it to the list on purpose).
|
|
1247
|
+
* 2. A value that is not `string | number | boolean | null` is dropped — an
|
|
1248
|
+
* `Error`, a response body or a token bag is never serialised, even under an
|
|
1249
|
+
* allowlisted key.
|
|
1250
|
+
* 3. An allowlisted string value containing a UUID becomes `'[redacted-uuid]'`
|
|
1251
|
+
* (platform UUIDs identify real people; any version matches, including v7 —
|
|
1252
|
+
* see `UUID_PATTERN`), and one containing an email address becomes
|
|
1253
|
+
* `'[redacted-email]'`. The whole value is replaced, not just the match,
|
|
1254
|
+
* because the surrounding text is usually the same identifier restated.
|
|
1255
|
+
*
|
|
1256
|
+
* `undefined` values are dropped rather than logged as `undefined`.
|
|
1257
|
+
*
|
|
1258
|
+
* @param extraAllowedKeys - App-specific keys to allow in addition to
|
|
1259
|
+
* {@link BASE_ALLOWED_LOG_KEYS}.
|
|
1260
|
+
* @returns A `safeLogFields(fields)` filter.
|
|
1261
|
+
* @example
|
|
1262
|
+
* const safeLogFields = createSafeLogFields(['wheelId']);
|
|
1263
|
+
* safeLogFields({ wheelId: 'wheel_1', retryCount: 2, accessToken: 'secret' });
|
|
1264
|
+
* // => { wheelId: 'wheel_1', retryCount: 2 }
|
|
1265
|
+
*/
|
|
1266
|
+
declare function createSafeLogFields(extraAllowedKeys?: readonly string[]): SafeLogFields;
|
|
1267
|
+
/**
|
|
1268
|
+
* Reads a loggable name out of an unknown thrown value.
|
|
1269
|
+
*
|
|
1270
|
+
* Only the class name is returned — never `error.message`, which routinely
|
|
1271
|
+
* carries the very data the allowlist exists to keep out of the logs (upstream
|
|
1272
|
+
* response bodies, signed URLs, secrets embedded in connection strings).
|
|
1273
|
+
*
|
|
1274
|
+
* @param error - Any caught value.
|
|
1275
|
+
* @returns The `Error` subclass name, or the `typeof` of a non-Error throw.
|
|
1276
|
+
* @example
|
|
1277
|
+
* errorName(new TypeError('secret=abc')); // 'TypeError'
|
|
1278
|
+
* errorName('boom'); // 'string'
|
|
1279
|
+
*/
|
|
1280
|
+
declare function errorName(error: unknown): string;
|
|
1281
|
+
/**
|
|
1282
|
+
* Builds a structured event logger over an allowlist.
|
|
1283
|
+
*
|
|
1284
|
+
* The emitted shape is `prefix` followed by `{ event, ...safeFields }`, matching
|
|
1285
|
+
* the convention the apps already log in, so existing log-based dashboards keep
|
|
1286
|
+
* working after the lift.
|
|
1287
|
+
*
|
|
1288
|
+
* @param options - Prefix, allowlist and sink overrides. Every field is
|
|
1289
|
+
* optional; the defaults are `'[fanvue]'`, `createSafeLogFields()` and the
|
|
1290
|
+
* global `console`.
|
|
1291
|
+
* @returns A `logEvent(level, event, fields)` function.
|
|
1292
|
+
* @example
|
|
1293
|
+
* const logEvent = createLogEvent({ prefix: '[spinwheel]' });
|
|
1294
|
+
* logEvent('warn', 'exchange.retry', { httpStatus: 503, retryCount: 1 });
|
|
1295
|
+
* // [spinwheel] { event: 'exchange.retry', httpStatus: 503, retryCount: 1 }
|
|
1296
|
+
*/
|
|
1297
|
+
declare function createLogEvent(options?: Partial<LogEventOptions>): LogEvent;
|
|
1298
|
+
/**
|
|
1299
|
+
* A ready-made {@link LogEvent} over the base allowlist, prefixed `[fanvue]`.
|
|
1300
|
+
*
|
|
1301
|
+
* Use {@link createLogEvent} instead when the app has its own prefix or extra
|
|
1302
|
+
* allowlisted keys.
|
|
1303
|
+
*
|
|
1304
|
+
* @example
|
|
1305
|
+
* logEvent('error', 'session.exchange_failed', { errorName: errorName(err) });
|
|
1306
|
+
*/
|
|
1307
|
+
declare const logEvent: LogEvent;
|
|
1308
|
+
//#endregion
|
|
1309
|
+
//#region src/core/observability/readiness.d.ts
|
|
1310
|
+
/**
|
|
1311
|
+
* One named configuration check.
|
|
1312
|
+
*/
|
|
1313
|
+
interface ReadinessCheck {
|
|
1314
|
+
/** Stable machine-readable check name, e.g. `'fanvue_oauth'`. */
|
|
1315
|
+
name: string;
|
|
1316
|
+
/** Whether the check passes. */
|
|
1317
|
+
ready: boolean;
|
|
1318
|
+
/** Why it fails, or `null` when it passes. Never contains a secret value. */
|
|
1319
|
+
detail: string | null;
|
|
1320
|
+
}
|
|
1321
|
+
/** The environment shape the checks read, so `process.env` is never read directly. */
|
|
1322
|
+
type ReadinessEnv = Readonly<Record<string, string | undefined>>;
|
|
1323
|
+
/**
|
|
1324
|
+
* Reports whether the generic Fanvue configuration an embedded app depends on
|
|
1325
|
+
* is present, as a list of named checks suitable for a `/api/readyz` body.
|
|
1326
|
+
*
|
|
1327
|
+
* Pure by construction — the environment is a parameter, so a deployment's
|
|
1328
|
+
* readiness can be asserted in tests without mutating `process.env`. Two
|
|
1329
|
+
* checks:
|
|
1330
|
+
*
|
|
1331
|
+
* - `app_url` — the app's public base URL is set and https. Fanvue refuses to
|
|
1332
|
+
* embed a non-https origin, so an http (or unset) value means creators would
|
|
1333
|
+
* see an empty frame rather than an error.
|
|
1334
|
+
* - `fanvue_oauth` — all four OAuth credential variables are present. The
|
|
1335
|
+
* detail names the missing variables, never their values.
|
|
1336
|
+
*
|
|
1337
|
+
* Provider-specific checks are deliberately out of scope: webhook signature
|
|
1338
|
+
* readiness belongs to the webhooks module (which owns the contract), and
|
|
1339
|
+
* queue/cron credentials belong to whichever machine-auth strategy the app
|
|
1340
|
+
* plugs in.
|
|
1341
|
+
*
|
|
1342
|
+
* @param env - Environment to read. Defaults to `process.env`; on a runtime
|
|
1343
|
+
* with no `process` global (browser, some edge workers) it defaults to an
|
|
1344
|
+
* empty environment, so the probe reports not-ready instead of throwing a
|
|
1345
|
+
* `ReferenceError`.
|
|
1346
|
+
* @returns One {@link ReadinessCheck} per generic concern, in a stable order.
|
|
1347
|
+
* @example
|
|
1348
|
+
* const checks = configurationReadiness();
|
|
1349
|
+
* const ready = checks.every((check) => check.ready);
|
|
1350
|
+
* return Response.json({ ready, checks }, { status: ready ? 200 : 503 });
|
|
1351
|
+
*/
|
|
1352
|
+
declare function configurationReadiness(env?: ReadinessEnv): readonly ReadinessCheck[];
|
|
1353
|
+
//#endregion
|
|
1354
|
+
//#region src/core/observability/sentry-scrubber.d.ts
|
|
1355
|
+
/**
|
|
1356
|
+
* A `beforeSend`-compatible scrubber.
|
|
1357
|
+
*
|
|
1358
|
+
* Generic in the event type so it satisfies Sentry's `beforeSend` option
|
|
1359
|
+
* without this package importing `@sentry/*` — the returned function is
|
|
1360
|
+
* structurally assignable to `(event, hint) => event | null`.
|
|
1361
|
+
*/
|
|
1362
|
+
type SentryScrubber = <T>(event: T) => T;
|
|
1363
|
+
/**
|
|
1364
|
+
* Key-name fragments whose values are never allowed to reach an error tracker.
|
|
1365
|
+
*
|
|
1366
|
+
* Matched as a substring, case-insensitively, so `Authorization`,
|
|
1367
|
+
* `authorizationHeader`, `x-authorization`, `x-api-key` and `apiKey` all hit.
|
|
1368
|
+
* Substring matching over-redacts on purpose (`emailSent`, `iphoneModel`) —
|
|
1369
|
+
* losing a benign field fails closed, letting a credential or a fan's contact
|
|
1370
|
+
* detail through does not. Anything app-specific (`prizedetail`, `fanhmac`,
|
|
1371
|
+
* `seed`, …) is added per app via the `extraSensitiveKeyPattern` argument.
|
|
1372
|
+
*/
|
|
1373
|
+
declare const BASE_SENSITIVE_KEY_PATTERN: RegExp;
|
|
1374
|
+
/**
|
|
1375
|
+
* Builds a recursive `beforeSend` scrubber for Sentry (or any error tracker
|
|
1376
|
+
* with the same hook shape).
|
|
1377
|
+
*
|
|
1378
|
+
* Four redaction rules, applied to every node of the event:
|
|
1379
|
+
*
|
|
1380
|
+
* - a key matching {@link BASE_SENSITIVE_KEY_PATTERN} (or the app's extra
|
|
1381
|
+
* pattern) has its value replaced with `'[redacted]'`, whatever its type;
|
|
1382
|
+
* - every UUID inside a string becomes `'[redacted-uuid]'` — any version,
|
|
1383
|
+
* including v7;
|
|
1384
|
+
* - a string that parses as a URL keeps its origin and path but loses its query
|
|
1385
|
+
* string, fragment and userinfo;
|
|
1386
|
+
* - every email address inside a string becomes `'[redacted-email]'`.
|
|
1387
|
+
*
|
|
1388
|
+
* Bounded and total by construction, because a `beforeSend` that throws loses
|
|
1389
|
+
* the event and raises inside the caller: repeat visits yield `'[circular]'`
|
|
1390
|
+
* (`WeakSet`), nodes past a depth of 32 yield `'[max-depth]'`, and a property
|
|
1391
|
+
* whose getter throws yields `'[unreadable]'`. Each of those fails closed — an
|
|
1392
|
+
* untraversed value cannot leak.
|
|
1393
|
+
*
|
|
1394
|
+
* Deliberately dependency-free: the event is typed structurally, so the privacy
|
|
1395
|
+
* behaviour is unit-testable without a Sentry client and this package takes no
|
|
1396
|
+
* dependency on `@sentry/*`.
|
|
1397
|
+
*
|
|
1398
|
+
* @param extraSensitiveKeyPattern - Extra key fragments to redact, merged with
|
|
1399
|
+
* the base pattern. Its flags are ignored; matching is always
|
|
1400
|
+
* case-insensitive and stateless.
|
|
1401
|
+
* @returns A function suitable for `Sentry.init({ beforeSend })`.
|
|
1402
|
+
* @example
|
|
1403
|
+
* Sentry.init({
|
|
1404
|
+
* dsn,
|
|
1405
|
+
* enabled: Boolean(dsn),
|
|
1406
|
+
* beforeSend: createSentryScrubber(/(prizedetail|fanhmac|seed)/i),
|
|
1407
|
+
* });
|
|
1408
|
+
*/
|
|
1409
|
+
declare function createSentryScrubber(extraSensitiveKeyPattern?: RegExp | null): SentryScrubber;
|
|
1410
|
+
//#endregion
|
|
1411
|
+
export { DEFAULT_ISSUER_URL as $, resetFanvueEnvCache as $t, safeJsonParse as A, isUnpublishResultMessage as At, refreshAccessToken as B, FanvueStringListErrorBodySchema as Bt, requireMachineAuth as C, UNPUBLISH_RESULT_MESSAGE as Ct, FanvueUserSchema as D, UnpublishResultMessageSchema as Dt, AuthorizeOnBehalfResponseSchema as E, UnpublishResultMessage as Et, requestAuthorizationCodeOnBehalf as F, FanvueErrorBody as Ft, JsonParseError as G, parseFanvueErrorBody as Gt, EmbeddedAuthConfig as H, NormalisedFanvueError as Ht, createSessionJwt as I, FanvueErrorBodySchema as It, SessionPayload as J, FanvueEnvSchema as Jt, OAuthConfig as K, EnvSource as Kt, verifySessionJwt as L, FanvueErrorFieldBodySchema as Lt, exchangeSessionToken as M, AppErrorEnvelopeSchema as Mt, getSessionTokenFromUrl as N, FANVUE_APP_ERROR_CODES as Nt, SessionPayloadSchema as O, isFanvueOrigin as Ot, getThemeFromUrl as P, FanvueAppErrorCode as Pt, DEFAULT_API_BASE_URL as Q, parseFanvueEnv as Qt, createAuthorizationUrl as R, FanvueIssueListErrorBodySchema as Rt, boundedBatchSize as S, UNPUBLISH_REQUEST_MESSAGE as St, createFanvueClient as T, UnpublishRequestMessageSchema as Tt, EmbeddedAuthError as U, OAuthErrorBody as Ut, ApiError as V, NON_SESSION_401_CODES as Vt, FanvueUser as W, OAuthErrorBodySchema as Wt, TokenResponse as X, flagEnabled as Xt, SessionVerifyError as Y, fanvueEnv as Yt, API_VERSION as Z, isFanvueConfigured as Zt, logEvent as _, PUBLISH_RESULT_MESSAGE as _t, ReadinessEnv as a, FanvueAccessMode as an, HybridPaginationSchema as at, MachineAuthResult as b, PublishResultMessage as bt, LogEvent as c, BEARER_PREFIX as cn, OffsetPaginationSchema as ct, LogSink as d, offsetPageSchema as dt, EXPERIENCE_DENIAL_REASONS as en, DEFAULT_PLATFORM_URL as et, SafeLogFields as f, EXPERIENCE_MESSAGE_TYPES as ft, errorName as g, PUBLISH_REQUEST_MESSAGE as gt, createSafeLogFields as h, ExperienceMessageType as ht, ReadinessCheck as i, FANVUE_ACCESS_MODES as in, HybridPagination as it, FanvueTheme as j, AppErrorEnvelope as jt, TokenResponseSchema as k, isPublishResultMessage as kt, LogEventOptions as l, HEADER_UPDATED_SESSION as ln, clampPageSize as lt, createLogEvent as m, ExperienceMessageSchema as mt, SentryScrubber as n, ExperienceDenialReason as nn, assertFanvueDomain as nt, configurationReadiness as o, FanvueAccessModeSchema as on, MAX_PAGE_SIZE as ot, SafeLogValue as p, ExperienceMessage as pt, OAuthError as q, FanvueEnv as qt, createSentryScrubber as r, ExperienceEntitledReason as rn, DEFAULT_PAGE_SIZE as rt, BASE_ALLOWED_LOG_KEYS as s, accessModeFromDenialReason as sn, OffsetPagination as st, BASE_SENSITIVE_KEY_PATTERN as t, EXPERIENCE_ENTITLED_REASONS as tn, DEFAULT_SCOPES as tt, LogLevel as u, cursorPageSchema as ut, MINIMUM_BEARER_SECRET_LENGTH as v, PublishRequestMessage as vt, FanvueClient as w, UnpublishRequestMessage as wt, SignedRequestVerifier as x, PublishResultMessageSchema as xt, MachineAuthOptions as y, PublishRequestMessageSchema as yt, exchangeCodeForToken as z, FanvueMessageErrorBodySchema as zt };
|
|
1412
|
+
//# sourceMappingURL=index-C3CXrRiw.d.ts.map
|