@atlasauth/js 0.11.0 → 0.13.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/CHANGELOG.md +37 -0
- package/dist/atlas-captcha.d.ts +108 -0
- package/dist/atlas-captcha.js +315 -0
- package/dist/atlas-captcha.js.map +1 -0
- package/dist/captcha-controller.d.ts +11 -1
- package/dist/captcha-controller.js +5 -3
- package/dist/captcha-controller.js.map +1 -1
- package/dist/captcha-widget.d.ts +21 -2
- package/dist/captcha-widget.js +23 -11
- package/dist/captcha-widget.js.map +1 -1
- package/dist/captcha.js +14 -0
- package/dist/captcha.js.map +1 -1
- package/dist/fapi.d.ts +47 -0
- package/dist/fapi.js +62 -2
- package/dist/fapi.js.map +1 -1
- package/dist/index.d.ts +5 -0
- package/dist/index.js +9 -0
- package/dist/index.js.map +1 -1
- package/dist/instance-settings.d.ts +11 -0
- package/dist/instance-settings.js +32 -1
- package/dist/instance-settings.js.map +1 -1
- package/dist/referral.d.ts +149 -0
- package/dist/referral.js +399 -0
- package/dist/referral.js.map +1 -0
- package/dist/sdk-advisory.d.ts +44 -0
- package/dist/sdk-advisory.js +69 -0
- package/dist/sdk-advisory.js.map +1 -0
- package/dist/sign-out-events.d.ts +54 -0
- package/dist/sign-out-events.js +97 -0
- package/dist/sign-out-events.js.map +1 -0
- package/dist/version.d.ts +7 -0
- package/dist/version.js +11 -0
- package/dist/version.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Referral attribution: capture the referral a visitor arrived with and send it
|
|
3
|
+
* on every sign-in / sign-up start, so the user Atlas creates is attributed to
|
|
4
|
+
* whoever referred them.
|
|
5
|
+
*
|
|
6
|
+
* What is captured, when the instance has referrals on (`referrals` in
|
|
7
|
+
* `GET /v1/client/environment`):
|
|
8
|
+
* - the referral code from the page URL — the instance's URL parameters
|
|
9
|
+
* (default `ref`, `via`, `aff`) on the current page, the page the SDK first
|
|
10
|
+
* loaded on, and the `redirect_url` / `after_url` query of either;
|
|
11
|
+
* - with consent, the referral platform's first-party tracking cookie (the
|
|
12
|
+
* instance's `context_cookie`): JSON or URL-encoded JSON
|
|
13
|
+
* `{code?, clickId?, anonId?}`, or a plain click id. A URL code wins over the
|
|
14
|
+
* cookie's code.
|
|
15
|
+
*
|
|
16
|
+
* Consent: when Cookie Munch is on the page (`window.CookieMunch`), the cookie
|
|
17
|
+
* is read only when the instance's consent category is granted (else its
|
|
18
|
+
* fallback category). Without a consent manager the cookie is read only when
|
|
19
|
+
* the app says its own consent manager allowed it (`referralConsent:
|
|
20
|
+
* 'granted'`). Otherwise the URL code alone is sent. The SDK never writes the
|
|
21
|
+
* cookie. Nothing captured is trusted: the server re-validates every field.
|
|
22
|
+
*
|
|
23
|
+
* Opt out with `referral: false` (per client, or page-wide with
|
|
24
|
+
* {@link configureReferralCapture}).
|
|
25
|
+
*/
|
|
26
|
+
/** The instance's public referral settings, camelCased. */
|
|
27
|
+
export interface ReferralConfig {
|
|
28
|
+
enabled: boolean;
|
|
29
|
+
/** URL query parameters that carry a code, in priority order. */
|
|
30
|
+
urlParams: string[];
|
|
31
|
+
/** The tracking cookie to read under consent; null = never read a cookie. */
|
|
32
|
+
contextCookie: string | null;
|
|
33
|
+
consentCategory: string;
|
|
34
|
+
consentFallbackCategory: string | null;
|
|
35
|
+
/** `always`: a sign-up carrying a referral code must pass the bot challenge. */
|
|
36
|
+
challengeReferredSignups: 'always' | 'inherit';
|
|
37
|
+
}
|
|
38
|
+
/** The `referral` object a sign-in / sign-up request carries (snake_case, as the API takes it). */
|
|
39
|
+
export interface ReferralCapture {
|
|
40
|
+
code: string | null;
|
|
41
|
+
click_id: string | null;
|
|
42
|
+
anon_id: string | null;
|
|
43
|
+
consent: 'granted' | 'not_required';
|
|
44
|
+
/** ISO 8601. */
|
|
45
|
+
captured_at: string;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* The app's own consent decision for the referral cookie, used only when no
|
|
49
|
+
* Cookie Munch is on the page. `'granted'` / `true` allow reading it; anything
|
|
50
|
+
* else does not. A function is asked at each sign-in / sign-up start.
|
|
51
|
+
*/
|
|
52
|
+
export type ReferralConsent = 'granted' | 'denied' | boolean | (() => 'granted' | 'denied' | boolean | null | undefined);
|
|
53
|
+
/** The referral options a FAPI client and the prebuilt components take. */
|
|
54
|
+
export interface ReferralCaptureOptions {
|
|
55
|
+
/** `false` turns referral capture off. */
|
|
56
|
+
referral?: false | undefined;
|
|
57
|
+
/** See {@link ReferralConsent}. */
|
|
58
|
+
referralConsent?: ReferralConsent;
|
|
59
|
+
}
|
|
60
|
+
export declare const DISABLED_REFERRAL_CONFIG: Readonly<ReferralConfig>;
|
|
61
|
+
/** A well-formed code / click id / anonymous id, or null. */
|
|
62
|
+
export declare function referralToken(value: unknown): string | null;
|
|
63
|
+
/**
|
|
64
|
+
* Read the referral config from a `/v1/client/environment` body (or its
|
|
65
|
+
* `referrals` object). Missing or malformed → disabled.
|
|
66
|
+
*/
|
|
67
|
+
export declare function referralConfigFrom(body: unknown): ReferralConfig;
|
|
68
|
+
/** The first well-formed code among `params` in a query string. */
|
|
69
|
+
export declare function referralCodeFromSearch(search: string | null | undefined, params: readonly string[]): string | null;
|
|
70
|
+
/** The query strings a code may be in: each search, plus its `redirect_url` / `after_url` targets' queries. */
|
|
71
|
+
export declare function referralSearches(searches: readonly string[], base?: string): string[];
|
|
72
|
+
/**
|
|
73
|
+
* Parse a tracking-cookie value: JSON or URL-encoded JSON `{code?, clickId?,
|
|
74
|
+
* anonId?}` (snake_case accepted too); a plain value is a click id.
|
|
75
|
+
*/
|
|
76
|
+
export declare function parseReferralCookie(value: string | null | undefined): {
|
|
77
|
+
code: string | null;
|
|
78
|
+
clickId: string | null;
|
|
79
|
+
anonId: string | null;
|
|
80
|
+
} | null;
|
|
81
|
+
/** A cookie's value from a `document.cookie` string, or null. */
|
|
82
|
+
export declare function readCookieValue(cookies: string | null | undefined, name: string): string | null;
|
|
83
|
+
/**
|
|
84
|
+
* Whether the referral cookie may be read. Cookie Munch on the page decides
|
|
85
|
+
* when present (the instance's category, else its fallback category); else
|
|
86
|
+
* the app's own `referralConsent`.
|
|
87
|
+
*/
|
|
88
|
+
export declare function referralConsentGranted(config: Pick<ReferralConfig, 'consentCategory' | 'consentFallbackCategory'>, cookieMunch: unknown, appConsent: ReferralConsent | undefined): boolean;
|
|
89
|
+
/** Everything {@link captureReferral} reads from the page. */
|
|
90
|
+
export interface ReferralPage {
|
|
91
|
+
/** Query strings to look in, most relevant first (current page, landing page). */
|
|
92
|
+
searches: readonly string[];
|
|
93
|
+
/** `document.cookie`. */
|
|
94
|
+
cookies?: string | null;
|
|
95
|
+
/** `window.CookieMunch`, if any. */
|
|
96
|
+
cookieMunch?: unknown;
|
|
97
|
+
/** Base for resolving a relative redirect_url. */
|
|
98
|
+
base?: string;
|
|
99
|
+
/** ISO time of capture. */
|
|
100
|
+
capturedAt?: string;
|
|
101
|
+
}
|
|
102
|
+
/** Capture the referral for a request, or null when there is nothing to send. Pure. */
|
|
103
|
+
export declare function captureReferral(config: ReferralConfig, page: ReferralPage, appConsent?: ReferralConsent): ReferralCapture | null;
|
|
104
|
+
/** Whether a FAPI POST path starts or continues a sign-in / sign-up (and so takes `referral`). */
|
|
105
|
+
export declare function acceptsReferral(path: string): boolean;
|
|
106
|
+
/**
|
|
107
|
+
* Remember the current page's query, so a code the visitor landed with
|
|
108
|
+
* survives client-side navigation that drops it. In memory only (never
|
|
109
|
+
* stored). Called when the SDK loads and whenever a client is created.
|
|
110
|
+
*/
|
|
111
|
+
export declare function rememberReferralLanding(): void;
|
|
112
|
+
/**
|
|
113
|
+
* Page-wide referral options, for apps whose framework creates FAPI clients
|
|
114
|
+
* internally: `configureReferralCapture({ referral: false })` opts out,
|
|
115
|
+
* `{ referralConsent: 'granted' }` tells the SDK the app's own consent
|
|
116
|
+
* manager allowed the referral cookie. A client's own options win.
|
|
117
|
+
*/
|
|
118
|
+
export declare function configureReferralCapture(options: ReferralCaptureOptions): void;
|
|
119
|
+
/** The page-wide options set with {@link configureReferralCapture}. */
|
|
120
|
+
export declare function referralCaptureDefaults(): ReferralCaptureOptions;
|
|
121
|
+
/** The key an instance's referral config is cached under (a FAPI origin + publishable key). */
|
|
122
|
+
export declare function referralCacheKeyFor(baseUrl: string | null | undefined, publishableKey: string): string;
|
|
123
|
+
/**
|
|
124
|
+
* Record an instance's referral config from a `/v1/client/environment` or
|
|
125
|
+
* `/v1/appearance` body it was fetched with. A body without `referrals` (an
|
|
126
|
+
* older server) is ignored.
|
|
127
|
+
*/
|
|
128
|
+
export declare function seedReferralConfig(cacheKey: string, environmentBody: unknown): void;
|
|
129
|
+
/** Forget every cached referral config (tests; an app switching instances). */
|
|
130
|
+
export declare function resetReferralCapture(): void;
|
|
131
|
+
/** What the referral helpers need from a FAPI client. */
|
|
132
|
+
export interface ReferralClient {
|
|
133
|
+
readonly referralCacheKey: string;
|
|
134
|
+
readonly referralOptions: ReferralCaptureOptions;
|
|
135
|
+
get<T>(path: string): Promise<{
|
|
136
|
+
ok: boolean;
|
|
137
|
+
data: T | null;
|
|
138
|
+
}>;
|
|
139
|
+
}
|
|
140
|
+
/** The instance's referral config, fetched once per page (and seeded by any environment read). */
|
|
141
|
+
export declare function loadReferralConfig(client: ReferralClient): Promise<ReferralConfig>;
|
|
142
|
+
/** The referral this client should send now, or null (off, opted out, nothing captured). Never throws. */
|
|
143
|
+
export declare function currentReferral(client: ReferralClient): Promise<ReferralCapture | null>;
|
|
144
|
+
/**
|
|
145
|
+
* Whether a sign-up / sign-in form should show the bot challenge because a
|
|
146
|
+
* referral code was captured and the instance requires it for referred
|
|
147
|
+
* sign-ups (even with the captcha otherwise off).
|
|
148
|
+
*/
|
|
149
|
+
export declare function referralChallengeRequired(client: ReferralClient): Promise<boolean>;
|
package/dist/referral.js
ADDED
|
@@ -0,0 +1,399 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Referral attribution: capture the referral a visitor arrived with and send it
|
|
4
|
+
* on every sign-in / sign-up start, so the user Atlas creates is attributed to
|
|
5
|
+
* whoever referred them.
|
|
6
|
+
*
|
|
7
|
+
* What is captured, when the instance has referrals on (`referrals` in
|
|
8
|
+
* `GET /v1/client/environment`):
|
|
9
|
+
* - the referral code from the page URL — the instance's URL parameters
|
|
10
|
+
* (default `ref`, `via`, `aff`) on the current page, the page the SDK first
|
|
11
|
+
* loaded on, and the `redirect_url` / `after_url` query of either;
|
|
12
|
+
* - with consent, the referral platform's first-party tracking cookie (the
|
|
13
|
+
* instance's `context_cookie`): JSON or URL-encoded JSON
|
|
14
|
+
* `{code?, clickId?, anonId?}`, or a plain click id. A URL code wins over the
|
|
15
|
+
* cookie's code.
|
|
16
|
+
*
|
|
17
|
+
* Consent: when Cookie Munch is on the page (`window.CookieMunch`), the cookie
|
|
18
|
+
* is read only when the instance's consent category is granted (else its
|
|
19
|
+
* fallback category). Without a consent manager the cookie is read only when
|
|
20
|
+
* the app says its own consent manager allowed it (`referralConsent:
|
|
21
|
+
* 'granted'`). Otherwise the URL code alone is sent. The SDK never writes the
|
|
22
|
+
* cookie. Nothing captured is trusted: the server re-validates every field.
|
|
23
|
+
*
|
|
24
|
+
* Opt out with `referral: false` (per client, or page-wide with
|
|
25
|
+
* {@link configureReferralCapture}).
|
|
26
|
+
*/
|
|
27
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
28
|
+
exports.DISABLED_REFERRAL_CONFIG = void 0;
|
|
29
|
+
exports.referralToken = referralToken;
|
|
30
|
+
exports.referralConfigFrom = referralConfigFrom;
|
|
31
|
+
exports.referralCodeFromSearch = referralCodeFromSearch;
|
|
32
|
+
exports.referralSearches = referralSearches;
|
|
33
|
+
exports.parseReferralCookie = parseReferralCookie;
|
|
34
|
+
exports.readCookieValue = readCookieValue;
|
|
35
|
+
exports.referralConsentGranted = referralConsentGranted;
|
|
36
|
+
exports.captureReferral = captureReferral;
|
|
37
|
+
exports.acceptsReferral = acceptsReferral;
|
|
38
|
+
exports.rememberReferralLanding = rememberReferralLanding;
|
|
39
|
+
exports.configureReferralCapture = configureReferralCapture;
|
|
40
|
+
exports.referralCaptureDefaults = referralCaptureDefaults;
|
|
41
|
+
exports.referralCacheKeyFor = referralCacheKeyFor;
|
|
42
|
+
exports.seedReferralConfig = seedReferralConfig;
|
|
43
|
+
exports.resetReferralCapture = resetReferralCapture;
|
|
44
|
+
exports.loadReferralConfig = loadReferralConfig;
|
|
45
|
+
exports.currentReferral = currentReferral;
|
|
46
|
+
exports.referralChallengeRequired = referralChallengeRequired;
|
|
47
|
+
exports.DISABLED_REFERRAL_CONFIG = Object.freeze({
|
|
48
|
+
enabled: false,
|
|
49
|
+
urlParams: [],
|
|
50
|
+
contextCookie: null,
|
|
51
|
+
consentCategory: 'referrals',
|
|
52
|
+
consentFallbackCategory: 'marketing',
|
|
53
|
+
challengeReferredSignups: 'inherit',
|
|
54
|
+
});
|
|
55
|
+
const TOKEN = /^[A-Za-z0-9_-]{3,64}$/;
|
|
56
|
+
const PARAM = /^[A-Za-z0-9_.-]{1,40}$/;
|
|
57
|
+
const COOKIE_NAME = /^[A-Za-z0-9_.-]{1,64}$/;
|
|
58
|
+
const isRecord = (v) => !!v && typeof v === 'object' && !Array.isArray(v);
|
|
59
|
+
/** A well-formed code / click id / anonymous id, or null. */
|
|
60
|
+
function referralToken(value) {
|
|
61
|
+
if (typeof value !== 'string')
|
|
62
|
+
return null;
|
|
63
|
+
const v = value.trim();
|
|
64
|
+
return TOKEN.test(v) ? v : null;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Read the referral config from a `/v1/client/environment` body (or its
|
|
68
|
+
* `referrals` object). Missing or malformed → disabled.
|
|
69
|
+
*/
|
|
70
|
+
function referralConfigFrom(body) {
|
|
71
|
+
const raw = isRecord(body) && isRecord(body.referrals) ? body.referrals : body;
|
|
72
|
+
if (!isRecord(raw) || raw.enabled !== true)
|
|
73
|
+
return { ...exports.DISABLED_REFERRAL_CONFIG, urlParams: [] };
|
|
74
|
+
const params = Array.isArray(raw.url_params)
|
|
75
|
+
? raw.url_params.filter((p) => typeof p === 'string' && PARAM.test(p)).slice(0, 10)
|
|
76
|
+
: [];
|
|
77
|
+
return {
|
|
78
|
+
enabled: true,
|
|
79
|
+
urlParams: params.length ? params : ['ref', 'via', 'aff'],
|
|
80
|
+
contextCookie: typeof raw.context_cookie === 'string' && COOKIE_NAME.test(raw.context_cookie) ? raw.context_cookie : null,
|
|
81
|
+
consentCategory: typeof raw.consent_category === 'string' && raw.consent_category ? raw.consent_category : 'referrals',
|
|
82
|
+
consentFallbackCategory: typeof raw.consent_fallback_category === 'string' && raw.consent_fallback_category
|
|
83
|
+
? raw.consent_fallback_category
|
|
84
|
+
: null,
|
|
85
|
+
challengeReferredSignups: raw.challenge_referred_signups === 'always' ? 'always' : 'inherit',
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
/** The first well-formed code among `params` in a query string. */
|
|
89
|
+
function referralCodeFromSearch(search, params) {
|
|
90
|
+
if (!search)
|
|
91
|
+
return null;
|
|
92
|
+
let query;
|
|
93
|
+
try {
|
|
94
|
+
query = new URLSearchParams(search);
|
|
95
|
+
}
|
|
96
|
+
catch {
|
|
97
|
+
return null;
|
|
98
|
+
}
|
|
99
|
+
for (const name of params) {
|
|
100
|
+
const code = referralToken(query.get(name));
|
|
101
|
+
if (code)
|
|
102
|
+
return code;
|
|
103
|
+
}
|
|
104
|
+
return null;
|
|
105
|
+
}
|
|
106
|
+
/** The query strings a code may be in: each search, plus its `redirect_url` / `after_url` targets' queries. */
|
|
107
|
+
function referralSearches(searches, base) {
|
|
108
|
+
const out = [];
|
|
109
|
+
const add = (s) => {
|
|
110
|
+
if (s && !out.includes(s))
|
|
111
|
+
out.push(s);
|
|
112
|
+
};
|
|
113
|
+
for (const search of searches)
|
|
114
|
+
add(search);
|
|
115
|
+
for (const search of searches) {
|
|
116
|
+
let query;
|
|
117
|
+
try {
|
|
118
|
+
query = new URLSearchParams(search);
|
|
119
|
+
}
|
|
120
|
+
catch {
|
|
121
|
+
continue;
|
|
122
|
+
}
|
|
123
|
+
for (const key of ['redirect_url', 'after_url', 'redirect_url_complete', 'after_sign_up_url', 'after_sign_in_url']) {
|
|
124
|
+
const target = query.get(key);
|
|
125
|
+
if (!target)
|
|
126
|
+
continue;
|
|
127
|
+
try {
|
|
128
|
+
add(new URL(target, base ?? 'https://invalid.example').search);
|
|
129
|
+
}
|
|
130
|
+
catch {
|
|
131
|
+
// not a URL
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
return out;
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Parse a tracking-cookie value: JSON or URL-encoded JSON `{code?, clickId?,
|
|
139
|
+
* anonId?}` (snake_case accepted too); a plain value is a click id.
|
|
140
|
+
*/
|
|
141
|
+
function parseReferralCookie(value) {
|
|
142
|
+
if (typeof value !== 'string' || !value || value.length > 4096)
|
|
143
|
+
return null;
|
|
144
|
+
let decoded = value;
|
|
145
|
+
try {
|
|
146
|
+
decoded = decodeURIComponent(value);
|
|
147
|
+
}
|
|
148
|
+
catch {
|
|
149
|
+
// keep the raw value
|
|
150
|
+
}
|
|
151
|
+
const json = (s) => {
|
|
152
|
+
if (!s.startsWith('{'))
|
|
153
|
+
return null;
|
|
154
|
+
try {
|
|
155
|
+
const parsed = JSON.parse(s);
|
|
156
|
+
return isRecord(parsed) ? parsed : null;
|
|
157
|
+
}
|
|
158
|
+
catch {
|
|
159
|
+
return null;
|
|
160
|
+
}
|
|
161
|
+
};
|
|
162
|
+
const obj = json(value.trim()) ?? json(decoded.trim());
|
|
163
|
+
if (obj) {
|
|
164
|
+
const out = {
|
|
165
|
+
code: referralToken(obj.code),
|
|
166
|
+
clickId: referralToken(obj.clickId ?? obj.click_id),
|
|
167
|
+
anonId: referralToken(obj.anonId ?? obj.anon_id),
|
|
168
|
+
};
|
|
169
|
+
return out.code || out.clickId || out.anonId ? out : null;
|
|
170
|
+
}
|
|
171
|
+
const clickId = referralToken(decoded);
|
|
172
|
+
return clickId ? { code: null, clickId, anonId: null } : null;
|
|
173
|
+
}
|
|
174
|
+
/** A cookie's value from a `document.cookie` string, or null. */
|
|
175
|
+
function readCookieValue(cookies, name) {
|
|
176
|
+
if (!cookies)
|
|
177
|
+
return null;
|
|
178
|
+
for (const part of cookies.split(';')) {
|
|
179
|
+
const p = part.trim();
|
|
180
|
+
if (p.startsWith(`${name}=`))
|
|
181
|
+
return p.slice(name.length + 1);
|
|
182
|
+
}
|
|
183
|
+
return null;
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* Whether the referral cookie may be read. Cookie Munch on the page decides
|
|
187
|
+
* when present (the instance's category, else its fallback category); else
|
|
188
|
+
* the app's own `referralConsent`.
|
|
189
|
+
*/
|
|
190
|
+
function referralConsentGranted(config, cookieMunch, appConsent) {
|
|
191
|
+
let consent;
|
|
192
|
+
try {
|
|
193
|
+
consent = isRecord(cookieMunch) || typeof cookieMunch === 'function' ? cookieMunch.consent : undefined;
|
|
194
|
+
}
|
|
195
|
+
catch {
|
|
196
|
+
consent = undefined;
|
|
197
|
+
}
|
|
198
|
+
if (isRecord(consent)) {
|
|
199
|
+
let v = consent[config.consentCategory];
|
|
200
|
+
if (typeof v !== 'boolean' && config.consentFallbackCategory)
|
|
201
|
+
v = consent[config.consentFallbackCategory];
|
|
202
|
+
return v === true;
|
|
203
|
+
}
|
|
204
|
+
let decision = appConsent;
|
|
205
|
+
if (typeof appConsent === 'function') {
|
|
206
|
+
try {
|
|
207
|
+
decision = appConsent();
|
|
208
|
+
}
|
|
209
|
+
catch {
|
|
210
|
+
decision = undefined;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
return decision === 'granted' || decision === true;
|
|
214
|
+
}
|
|
215
|
+
/** Capture the referral for a request, or null when there is nothing to send. Pure. */
|
|
216
|
+
function captureReferral(config, page, appConsent) {
|
|
217
|
+
if (!config.enabled)
|
|
218
|
+
return null;
|
|
219
|
+
let code = null;
|
|
220
|
+
for (const search of referralSearches(page.searches, page.base)) {
|
|
221
|
+
code = referralCodeFromSearch(search, config.urlParams);
|
|
222
|
+
if (code)
|
|
223
|
+
break;
|
|
224
|
+
}
|
|
225
|
+
const cookie = config.contextCookie && referralConsentGranted(config, page.cookieMunch, appConsent)
|
|
226
|
+
? parseReferralCookie(readCookieValue(page.cookies, config.contextCookie))
|
|
227
|
+
: null;
|
|
228
|
+
const out = {
|
|
229
|
+
code: code ?? cookie?.code ?? null,
|
|
230
|
+
click_id: cookie?.clickId ?? null,
|
|
231
|
+
anon_id: cookie?.anonId ?? null,
|
|
232
|
+
consent: cookie ? 'granted' : 'not_required',
|
|
233
|
+
captured_at: page.capturedAt ?? new Date().toISOString(),
|
|
234
|
+
};
|
|
235
|
+
return out.code || out.click_id || out.anon_id ? out : null;
|
|
236
|
+
}
|
|
237
|
+
/** The FAPI POST paths that take `referral`: every sign-in / sign-up start and the steps that continue one. */
|
|
238
|
+
const REFERRAL_EXACT = new Set([
|
|
239
|
+
'/v1/client/sign_ups',
|
|
240
|
+
'/v1/client/sign_ins',
|
|
241
|
+
'/v1/client/sign_ins/oauth',
|
|
242
|
+
'/v1/client/sign_ins/sso',
|
|
243
|
+
'/v1/client/sign_ins/saml',
|
|
244
|
+
'/v1/client/sign_ins/discourse',
|
|
245
|
+
'/v1/client/sign_ins/id_token',
|
|
246
|
+
'/v1/client/sign_ins/id_token/nonce',
|
|
247
|
+
'/v1/client/sign_ins/external_jwt',
|
|
248
|
+
'/v1/client/sign_ins/ldap',
|
|
249
|
+
'/v1/client/sign_ins/passkey/finish',
|
|
250
|
+
'/v1/oauth/telegram',
|
|
251
|
+
'/v1/oauth/siwe/nonce',
|
|
252
|
+
'/v1/oauth/siwe/verify',
|
|
253
|
+
'/v1/oauth/siws/nonce',
|
|
254
|
+
'/v1/oauth/siws/verify',
|
|
255
|
+
'/v1/oauth/siwf/nonce',
|
|
256
|
+
'/v1/oauth/siwf/verify',
|
|
257
|
+
]);
|
|
258
|
+
const REFERRAL_STEP = /^\/v1\/client\/(sign_ins\/[^/]+\/(prepare_first_factor|attempt_first_factor)|sign_ups\/[^/]+\/(prepare_verification|attempt_verification))$/;
|
|
259
|
+
/** Whether a FAPI POST path starts or continues a sign-in / sign-up (and so takes `referral`). */
|
|
260
|
+
function acceptsReferral(path) {
|
|
261
|
+
const p = path.split('?')[0] ?? path;
|
|
262
|
+
return REFERRAL_EXACT.has(p) || REFERRAL_STEP.test(p);
|
|
263
|
+
}
|
|
264
|
+
const browser = () => typeof window === 'undefined' ? null : window;
|
|
265
|
+
/** The query strings the page has shown since the SDK loaded (the landing query first). */
|
|
266
|
+
const landingSearches = [];
|
|
267
|
+
let landingAt = null;
|
|
268
|
+
/**
|
|
269
|
+
* Remember the current page's query, so a code the visitor landed with
|
|
270
|
+
* survives client-side navigation that drops it. In memory only (never
|
|
271
|
+
* stored). Called when the SDK loads and whenever a client is created.
|
|
272
|
+
*/
|
|
273
|
+
function rememberReferralLanding() {
|
|
274
|
+
const search = browser()?.location?.search;
|
|
275
|
+
if (!search || landingSearches.includes(search))
|
|
276
|
+
return;
|
|
277
|
+
landingSearches.push(search);
|
|
278
|
+
landingAt ??= new Date().toISOString();
|
|
279
|
+
}
|
|
280
|
+
rememberReferralLanding();
|
|
281
|
+
let pageOptions = {};
|
|
282
|
+
/**
|
|
283
|
+
* Page-wide referral options, for apps whose framework creates FAPI clients
|
|
284
|
+
* internally: `configureReferralCapture({ referral: false })` opts out,
|
|
285
|
+
* `{ referralConsent: 'granted' }` tells the SDK the app's own consent
|
|
286
|
+
* manager allowed the referral cookie. A client's own options win.
|
|
287
|
+
*/
|
|
288
|
+
function configureReferralCapture(options) {
|
|
289
|
+
pageOptions = { ...options };
|
|
290
|
+
}
|
|
291
|
+
/** The page-wide options set with {@link configureReferralCapture}. */
|
|
292
|
+
function referralCaptureDefaults() {
|
|
293
|
+
return pageOptions;
|
|
294
|
+
}
|
|
295
|
+
const configs = new Map();
|
|
296
|
+
/** The key an instance's referral config is cached under (a FAPI origin + publishable key). */
|
|
297
|
+
function referralCacheKeyFor(baseUrl, publishableKey) {
|
|
298
|
+
return `${baseUrl ?? ''}|${publishableKey}`;
|
|
299
|
+
}
|
|
300
|
+
/**
|
|
301
|
+
* Record an instance's referral config from a `/v1/client/environment` or
|
|
302
|
+
* `/v1/appearance` body it was fetched with. A body without `referrals` (an
|
|
303
|
+
* older server) is ignored.
|
|
304
|
+
*/
|
|
305
|
+
function seedReferralConfig(cacheKey, environmentBody) {
|
|
306
|
+
if (!isRecord(environmentBody) || !('referrals' in environmentBody))
|
|
307
|
+
return;
|
|
308
|
+
configs.set(cacheKey, Promise.resolve(referralConfigFrom(environmentBody)));
|
|
309
|
+
}
|
|
310
|
+
/** Forget every cached referral config (tests; an app switching instances). */
|
|
311
|
+
function resetReferralCapture() {
|
|
312
|
+
configs.clear();
|
|
313
|
+
landingSearches.length = 0;
|
|
314
|
+
landingAt = null;
|
|
315
|
+
pageOptions = {};
|
|
316
|
+
}
|
|
317
|
+
/** The instance's referral config, fetched once per page (and seeded by any environment read). */
|
|
318
|
+
function loadReferralConfig(client) {
|
|
319
|
+
let pending = configs.get(client.referralCacheKey);
|
|
320
|
+
if (!pending) {
|
|
321
|
+
const key = client.referralCacheKey;
|
|
322
|
+
// A failed read reads as "off" for this start and is not cached, so a later
|
|
323
|
+
// start asks again.
|
|
324
|
+
const failed = () => {
|
|
325
|
+
if (configs.get(key) === pending)
|
|
326
|
+
configs.delete(key);
|
|
327
|
+
return { ...exports.DISABLED_REFERRAL_CONFIG, urlParams: [] };
|
|
328
|
+
};
|
|
329
|
+
pending = client
|
|
330
|
+
.get('/v1/client/environment')
|
|
331
|
+
.then((r) => (r.ok ? referralConfigFrom(r.data) : failed()))
|
|
332
|
+
.catch(failed);
|
|
333
|
+
configs.set(key, pending);
|
|
334
|
+
}
|
|
335
|
+
return pending;
|
|
336
|
+
}
|
|
337
|
+
/**
|
|
338
|
+
* No config yet (no environment / appearance read on this page) and no query
|
|
339
|
+
* anywhere to find a code in: nothing to send, and no reason to ask the
|
|
340
|
+
* server. A cookie-only referral is sent once a prebuilt form (or any
|
|
341
|
+
* environment read) has loaded the config.
|
|
342
|
+
*/
|
|
343
|
+
function worthAsking(client) {
|
|
344
|
+
return configs.has(client.referralCacheKey) || !!browser()?.location?.search || landingSearches.length > 0;
|
|
345
|
+
}
|
|
346
|
+
function effectiveOptions(client) {
|
|
347
|
+
const own = client.referralOptions;
|
|
348
|
+
return {
|
|
349
|
+
referral: own.referral ?? pageOptions.referral,
|
|
350
|
+
referralConsent: own.referralConsent ?? pageOptions.referralConsent,
|
|
351
|
+
};
|
|
352
|
+
}
|
|
353
|
+
/** The referral this client should send now, or null (off, opted out, nothing captured). Never throws. */
|
|
354
|
+
async function currentReferral(client) {
|
|
355
|
+
const win = browser();
|
|
356
|
+
if (!win)
|
|
357
|
+
return null;
|
|
358
|
+
const options = effectiveOptions(client);
|
|
359
|
+
if (options.referral === false)
|
|
360
|
+
return null;
|
|
361
|
+
try {
|
|
362
|
+
const current = win.location?.search ?? '';
|
|
363
|
+
if (!worthAsking(client))
|
|
364
|
+
return null;
|
|
365
|
+
const config = await loadReferralConfig(client);
|
|
366
|
+
if (!config.enabled)
|
|
367
|
+
return null;
|
|
368
|
+
return captureReferral(config, {
|
|
369
|
+
searches: [current, ...landingSearches],
|
|
370
|
+
cookies: win.document?.cookie ?? null,
|
|
371
|
+
cookieMunch: win.CookieMunch,
|
|
372
|
+
base: win.location?.href,
|
|
373
|
+
capturedAt: landingAt ?? undefined,
|
|
374
|
+
}, options.referralConsent);
|
|
375
|
+
}
|
|
376
|
+
catch {
|
|
377
|
+
return null;
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
/**
|
|
381
|
+
* Whether a sign-up / sign-in form should show the bot challenge because a
|
|
382
|
+
* referral code was captured and the instance requires it for referred
|
|
383
|
+
* sign-ups (even with the captcha otherwise off).
|
|
384
|
+
*/
|
|
385
|
+
async function referralChallengeRequired(client) {
|
|
386
|
+
if (!browser() || effectiveOptions(client).referral === false || !worthAsking(client))
|
|
387
|
+
return false;
|
|
388
|
+
try {
|
|
389
|
+
const config = await loadReferralConfig(client);
|
|
390
|
+
if (config.challengeReferredSignups !== 'always')
|
|
391
|
+
return false;
|
|
392
|
+
const ref = await currentReferral(client);
|
|
393
|
+
return !!ref?.code;
|
|
394
|
+
}
|
|
395
|
+
catch {
|
|
396
|
+
return false;
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
//# sourceMappingURL=referral.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"referral.js","sourceRoot":"","sources":["../src/referral.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;;;AA6DH,sCAIC;AAMD,gDAmBC;AAGD,wDAaC;AAGD,4CAwBC;AAMD,kDA8BC;AAGD,0CAOC;AAOD,wDAyBC;AAiBD,0CAuBC;AA0BD,0CAGC;AAsBD,0DAKC;AAWD,4DAEC;AAGD,0DAEC;AAKD,kDAEC;AAOD,gDAGC;AAGD,oDAKC;AAUD,gDAiBC;AAqBD,0CAwBC;AAOD,8DAUC;AA3YY,QAAA,wBAAwB,GAA6B,MAAM,CAAC,MAAM,CAAC;IAC9E,OAAO,EAAE,KAAK;IACd,SAAS,EAAE,EAAE;IACb,aAAa,EAAE,IAAI;IACnB,eAAe,EAAE,WAAW;IAC5B,uBAAuB,EAAE,WAAW;IACpC,wBAAwB,EAAE,SAAS;CACpC,CAAC,CAAC;AAEH,MAAM,KAAK,GAAG,uBAAuB,CAAC;AACtC,MAAM,KAAK,GAAG,wBAAwB,CAAC;AACvC,MAAM,WAAW,GAAG,wBAAwB,CAAC;AAE7C,MAAM,QAAQ,GAAG,CAAC,CAAU,EAAgC,EAAE,CAC5D,CAAC,CAAC,CAAC,IAAI,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AAEpD,6DAA6D;AAC7D,SAAgB,aAAa,CAAC,KAAc;IAC1C,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,IAAI,CAAC;IAC3C,MAAM,CAAC,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC;IACvB,OAAO,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AAClC,CAAC;AAED;;;GAGG;AACH,SAAgB,kBAAkB,CAAC,IAAa;IAC9C,MAAM,GAAG,GAAG,QAAQ,CAAC,IAAI,CAAC,IAAI,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC;IAC/E,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC,OAAO,KAAK,IAAI;QAAE,OAAO,EAAE,GAAG,gCAAwB,EAAE,SAAS,EAAE,EAAE,EAAE,CAAC;IAClG,MAAM,MAAM,GAAG,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC;QAC1C,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,EAAe,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,IAAI,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC;QAChG,CAAC,CAAC,EAAE,CAAC;IACP,OAAO;QACL,OAAO,EAAE,IAAI;QACb,SAAS,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,CAAC;QACzD,aAAa,EACX,OAAO,GAAG,CAAC,cAAc,KAAK,QAAQ,IAAI,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC,CAAC,IAAI;QAC5G,eAAe,EACb,OAAO,GAAG,CAAC,gBAAgB,KAAK,QAAQ,IAAI,GAAG,CAAC,gBAAgB,CAAC,CAAC,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC,CAAC,WAAW;QACvG,uBAAuB,EACrB,OAAO,GAAG,CAAC,yBAAyB,KAAK,QAAQ,IAAI,GAAG,CAAC,yBAAyB;YAChF,CAAC,CAAC,GAAG,CAAC,yBAAyB;YAC/B,CAAC,CAAC,IAAI;QACV,wBAAwB,EAAE,GAAG,CAAC,0BAA0B,KAAK,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS;KAC7F,CAAC;AACJ,CAAC;AAED,mEAAmE;AACnE,SAAgB,sBAAsB,CAAC,MAAiC,EAAE,MAAyB;IACjG,IAAI,CAAC,MAAM;QAAE,OAAO,IAAI,CAAC;IACzB,IAAI,KAAsB,CAAC;IAC3B,IAAI,CAAC;QACH,KAAK,GAAG,IAAI,eAAe,CAAC,MAAM,CAAC,CAAC;IACtC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;IACD,KAAK,MAAM,IAAI,IAAI,MAAM,EAAE,CAAC;QAC1B,MAAM,IAAI,GAAG,aAAa,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC;QAC5C,IAAI,IAAI;YAAE,OAAO,IAAI,CAAC;IACxB,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,+GAA+G;AAC/G,SAAgB,gBAAgB,CAAC,QAA2B,EAAE,IAAa;IACzE,MAAM,GAAG,GAAa,EAAE,CAAC;IACzB,MAAM,GAAG,GAAG,CAAC,CAA4B,EAAE,EAAE;QAC3C,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC;YAAE,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACzC,CAAC,CAAC;IACF,KAAK,MAAM,MAAM,IAAI,QAAQ;QAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAC3C,KAAK,MAAM,MAAM,IAAI,QAAQ,EAAE,CAAC;QAC9B,IAAI,KAAsB,CAAC;QAC3B,IAAI,CAAC;YACH,KAAK,GAAG,IAAI,eAAe,CAAC,MAAM,CAAC,CAAC;QACtC,CAAC;QAAC,MAAM,CAAC;YACP,SAAS;QACX,CAAC;QACD,KAAK,MAAM,GAAG,IAAI,CAAC,cAAc,EAAE,WAAW,EAAE,uBAAuB,EAAE,mBAAmB,EAAE,mBAAmB,CAAC,EAAE,CAAC;YACnH,MAAM,MAAM,GAAG,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;YAC9B,IAAI,CAAC,MAAM;gBAAE,SAAS;YACtB,IAAI,CAAC;gBACH,GAAG,CAAC,IAAI,GAAG,CAAC,MAAM,EAAE,IAAI,IAAI,yBAAyB,CAAC,CAAC,MAAM,CAAC,CAAC;YACjE,CAAC;YAAC,MAAM,CAAC;gBACP,YAAY;YACd,CAAC;QACH,CAAC;IACH,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED;;;GAGG;AACH,SAAgB,mBAAmB,CACjC,KAAgC;IAEhC,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,MAAM,GAAG,IAAI;QAAE,OAAO,IAAI,CAAC;IAC5E,IAAI,OAAO,GAAG,KAAK,CAAC;IACpB,IAAI,CAAC;QACH,OAAO,GAAG,kBAAkB,CAAC,KAAK,CAAC,CAAC;IACtC,CAAC;IAAC,MAAM,CAAC;QACP,qBAAqB;IACvB,CAAC;IACD,MAAM,IAAI,GAAG,CAAC,CAAS,EAAkC,EAAE;QACzD,IAAI,CAAC,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC;YAAE,OAAO,IAAI,CAAC;QACpC,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAY,CAAC;YACxC,OAAO,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC;QAC1C,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC,CAAC;IACF,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,IAAI,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC;IACvD,IAAI,GAAG,EAAE,CAAC;QACR,MAAM,GAAG,GAAG;YACV,IAAI,EAAE,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC;YAC7B,OAAO,EAAE,aAAa,CAAC,GAAG,CAAC,OAAO,IAAI,GAAG,CAAC,QAAQ,CAAC;YACnD,MAAM,EAAE,aAAa,CAAC,GAAG,CAAC,MAAM,IAAI,GAAG,CAAC,OAAO,CAAC;SACjD,CAAC;QACF,OAAO,GAAG,CAAC,IAAI,IAAI,GAAG,CAAC,OAAO,IAAI,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC;IAC5D,CAAC;IACD,MAAM,OAAO,GAAG,aAAa,CAAC,OAAO,CAAC,CAAC;IACvC,OAAO,OAAO,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;AAChE,CAAC;AAED,iEAAiE;AACjE,SAAgB,eAAe,CAAC,OAAkC,EAAE,IAAY;IAC9E,IAAI,CAAC,OAAO;QAAE,OAAO,IAAI,CAAC;IAC1B,KAAK,MAAM,IAAI,IAAI,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;QACtC,MAAM,CAAC,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;QACtB,IAAI,CAAC,CAAC,UAAU,CAAC,GAAG,IAAI,GAAG,CAAC;YAAE,OAAO,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IAChE,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;GAIG;AACH,SAAgB,sBAAsB,CACpC,MAA2E,EAC3E,WAAoB,EACpB,UAAuC;IAEvC,IAAI,OAAgB,CAAC;IACrB,IAAI,CAAC;QACH,OAAO,GAAG,QAAQ,CAAC,WAAW,CAAC,IAAI,OAAO,WAAW,KAAK,UAAU,CAAC,CAAC,CAAE,WAAqC,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC;IACpI,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,GAAG,SAAS,CAAC;IACtB,CAAC;IACD,IAAI,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;QACtB,IAAI,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC;QACxC,IAAI,OAAO,CAAC,KAAK,SAAS,IAAI,MAAM,CAAC,uBAAuB;YAAE,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,uBAAuB,CAAC,CAAC;QAC1G,OAAO,CAAC,KAAK,IAAI,CAAC;IACpB,CAAC;IACD,IAAI,QAAQ,GAAY,UAAU,CAAC;IACnC,IAAI,OAAO,UAAU,KAAK,UAAU,EAAE,CAAC;QACrC,IAAI,CAAC;YACH,QAAQ,GAAG,UAAU,EAAE,CAAC;QAC1B,CAAC;QAAC,MAAM,CAAC;YACP,QAAQ,GAAG,SAAS,CAAC;QACvB,CAAC;IACH,CAAC;IACD,OAAO,QAAQ,KAAK,SAAS,IAAI,QAAQ,KAAK,IAAI,CAAC;AACrD,CAAC;AAgBD,uFAAuF;AACvF,SAAgB,eAAe,CAC7B,MAAsB,EACtB,IAAkB,EAClB,UAA4B;IAE5B,IAAI,CAAC,MAAM,CAAC,OAAO;QAAE,OAAO,IAAI,CAAC;IACjC,IAAI,IAAI,GAAkB,IAAI,CAAC;IAC/B,KAAK,MAAM,MAAM,IAAI,gBAAgB,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QAChE,IAAI,GAAG,sBAAsB,CAAC,MAAM,EAAE,MAAM,CAAC,SAAS,CAAC,CAAC;QACxD,IAAI,IAAI;YAAE,MAAM;IAClB,CAAC;IACD,MAAM,MAAM,GACV,MAAM,CAAC,aAAa,IAAI,sBAAsB,CAAC,MAAM,EAAE,IAAI,CAAC,WAAW,EAAE,UAAU,CAAC;QAClF,CAAC,CAAC,mBAAmB,CAAC,eAAe,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,aAAa,CAAC,CAAC;QAC1E,CAAC,CAAC,IAAI,CAAC;IACX,MAAM,GAAG,GAAoB;QAC3B,IAAI,EAAE,IAAI,IAAI,MAAM,EAAE,IAAI,IAAI,IAAI;QAClC,QAAQ,EAAE,MAAM,EAAE,OAAO,IAAI,IAAI;QACjC,OAAO,EAAE,MAAM,EAAE,MAAM,IAAI,IAAI;QAC/B,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,cAAc;QAC5C,WAAW,EAAE,IAAI,CAAC,UAAU,IAAI,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;KACzD,CAAC;IACF,OAAO,GAAG,CAAC,IAAI,IAAI,GAAG,CAAC,QAAQ,IAAI,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC;AAC9D,CAAC;AAED,+GAA+G;AAC/G,MAAM,cAAc,GAAG,IAAI,GAAG,CAAC;IAC7B,qBAAqB;IACrB,qBAAqB;IACrB,2BAA2B;IAC3B,yBAAyB;IACzB,0BAA0B;IAC1B,+BAA+B;IAC/B,8BAA8B;IAC9B,oCAAoC;IACpC,kCAAkC;IAClC,0BAA0B;IAC1B,oCAAoC;IACpC,oBAAoB;IACpB,sBAAsB;IACtB,uBAAuB;IACvB,sBAAsB;IACtB,uBAAuB;IACvB,sBAAsB;IACtB,uBAAuB;CACxB,CAAC,CAAC;AACH,MAAM,aAAa,GAAG,6IAA6I,CAAC;AAEpK,kGAAkG;AAClG,SAAgB,eAAe,CAAC,IAAY;IAC1C,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC;IACrC,OAAO,cAAc,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AACxD,CAAC;AAUD,MAAM,OAAO,GAAG,GAAyB,EAAE,CACzC,OAAO,MAAM,KAAK,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAE,MAAmC,CAAC;AAE9E,2FAA2F;AAC3F,MAAM,eAAe,GAAa,EAAE,CAAC;AACrC,IAAI,SAAS,GAAkB,IAAI,CAAC;AAEpC;;;;GAIG;AACH,SAAgB,uBAAuB;IACrC,MAAM,MAAM,GAAG,OAAO,EAAE,EAAE,QAAQ,EAAE,MAAM,CAAC;IAC3C,IAAI,CAAC,MAAM,IAAI,eAAe,CAAC,QAAQ,CAAC,MAAM,CAAC;QAAE,OAAO;IACxD,eAAe,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAC7B,SAAS,KAAK,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;AACzC,CAAC;AACD,uBAAuB,EAAE,CAAC;AAE1B,IAAI,WAAW,GAA2B,EAAE,CAAC;AAE7C;;;;;GAKG;AACH,SAAgB,wBAAwB,CAAC,OAA+B;IACtE,WAAW,GAAG,EAAE,GAAG,OAAO,EAAE,CAAC;AAC/B,CAAC;AAED,uEAAuE;AACvE,SAAgB,uBAAuB;IACrC,OAAO,WAAW,CAAC;AACrB,CAAC;AAED,MAAM,OAAO,GAAG,IAAI,GAAG,EAAmC,CAAC;AAE3D,+FAA+F;AAC/F,SAAgB,mBAAmB,CAAC,OAAkC,EAAE,cAAsB;IAC5F,OAAO,GAAG,OAAO,IAAI,EAAE,IAAI,cAAc,EAAE,CAAC;AAC9C,CAAC;AAED;;;;GAIG;AACH,SAAgB,kBAAkB,CAAC,QAAgB,EAAE,eAAwB;IAC3E,IAAI,CAAC,QAAQ,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC,WAAW,IAAI,eAAe,CAAC;QAAE,OAAO;IAC5E,OAAO,CAAC,GAAG,CAAC,QAAQ,EAAE,OAAO,CAAC,OAAO,CAAC,kBAAkB,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;AAC9E,CAAC;AAED,+EAA+E;AAC/E,SAAgB,oBAAoB;IAClC,OAAO,CAAC,KAAK,EAAE,CAAC;IAChB,eAAe,CAAC,MAAM,GAAG,CAAC,CAAC;IAC3B,SAAS,GAAG,IAAI,CAAC;IACjB,WAAW,GAAG,EAAE,CAAC;AACnB,CAAC;AASD,kGAAkG;AAClG,SAAgB,kBAAkB,CAAC,MAAsB;IACvD,IAAI,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,gBAAgB,CAAC,CAAC;IACnD,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,MAAM,GAAG,GAAG,MAAM,CAAC,gBAAgB,CAAC;QACpC,4EAA4E;QAC5E,oBAAoB;QACpB,MAAM,MAAM,GAAG,GAAmB,EAAE;YAClC,IAAI,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,OAAO;gBAAE,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YACtD,OAAO,EAAE,GAAG,gCAAwB,EAAE,SAAS,EAAE,EAAE,EAAE,CAAC;QACxD,CAAC,CAAC;QACF,OAAO,GAAG,MAAM;aACb,GAAG,CAAU,wBAAwB,CAAC;aACtC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,kBAAkB,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC;aAC3D,KAAK,CAAC,MAAM,CAAC,CAAC;QACjB,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;IAC5B,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED;;;;;GAKG;AACH,SAAS,WAAW,CAAC,MAAsB;IACzC,OAAO,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,QAAQ,EAAE,MAAM,IAAI,eAAe,CAAC,MAAM,GAAG,CAAC,CAAC;AAC7G,CAAC;AAED,SAAS,gBAAgB,CAAC,MAAsB;IAC9C,MAAM,GAAG,GAAG,MAAM,CAAC,eAAe,CAAC;IACnC,OAAO;QACL,QAAQ,EAAE,GAAG,CAAC,QAAQ,IAAI,WAAW,CAAC,QAAQ;QAC9C,eAAe,EAAE,GAAG,CAAC,eAAe,IAAI,WAAW,CAAC,eAAe;KACpE,CAAC;AACJ,CAAC;AAED,0GAA0G;AACnG,KAAK,UAAU,eAAe,CAAC,MAAsB;IAC1D,MAAM,GAAG,GAAG,OAAO,EAAE,CAAC;IACtB,IAAI,CAAC,GAAG;QAAE,OAAO,IAAI,CAAC;IACtB,MAAM,OAAO,GAAG,gBAAgB,CAAC,MAAM,CAAC,CAAC;IACzC,IAAI,OAAO,CAAC,QAAQ,KAAK,KAAK;QAAE,OAAO,IAAI,CAAC;IAC5C,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,GAAG,CAAC,QAAQ,EAAE,MAAM,IAAI,EAAE,CAAC;QAC3C,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC;YAAE,OAAO,IAAI,CAAC;QACtC,MAAM,MAAM,GAAG,MAAM,kBAAkB,CAAC,MAAM,CAAC,CAAC;QAChD,IAAI,CAAC,MAAM,CAAC,OAAO;YAAE,OAAO,IAAI,CAAC;QACjC,OAAO,eAAe,CACpB,MAAM,EACN;YACE,QAAQ,EAAE,CAAC,OAAO,EAAE,GAAG,eAAe,CAAC;YACvC,OAAO,EAAE,GAAG,CAAC,QAAQ,EAAE,MAAM,IAAI,IAAI;YACrC,WAAW,EAAE,GAAG,CAAC,WAAW;YAC5B,IAAI,EAAE,GAAG,CAAC,QAAQ,EAAE,IAAI;YACxB,UAAU,EAAE,SAAS,IAAI,SAAS;SACnC,EACD,OAAO,CAAC,eAAe,CACxB,CAAC;IACJ,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED;;;;GAIG;AACI,KAAK,UAAU,yBAAyB,CAAC,MAAsB;IACpE,IAAI,CAAC,OAAO,EAAE,IAAI,gBAAgB,CAAC,MAAM,CAAC,CAAC,QAAQ,KAAK,KAAK,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC;QAAE,OAAO,KAAK,CAAC;IACpG,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,kBAAkB,CAAC,MAAM,CAAC,CAAC;QAChD,IAAI,MAAM,CAAC,wBAAwB,KAAK,QAAQ;YAAE,OAAO,KAAK,CAAC;QAC/D,MAAM,GAAG,GAAG,MAAM,eAAe,CAAC,MAAM,CAAC,CAAC;QAC1C,OAAO,CAAC,CAAC,GAAG,EAAE,IAAI,CAAC;IACrB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SDK version advisories.
|
|
3
|
+
*
|
|
4
|
+
* Every Atlas browser SDK names itself on its Frontend API requests
|
|
5
|
+
* (`X-Atlas-SDK: @atlasauth/react/0.10.0`). When that version has a known bug
|
|
6
|
+
* fixed in a later release, the response carries
|
|
7
|
+
* `Atlas-SDK-Advisory: upgrade; min=0.8.1; reason=email_code_sign_in` (several
|
|
8
|
+
* comma-separated), and the SDK logs ONE console warning per advisory per page
|
|
9
|
+
* load, so a pinned 0.x version (the caret trap: `^0.8.0` never moves past a
|
|
10
|
+
* lockfile's 0.8.0) is noticed by whoever opens the console.
|
|
11
|
+
*/
|
|
12
|
+
/** Which SDK a request comes from. */
|
|
13
|
+
export interface AtlasSdkInfo {
|
|
14
|
+
/** The npm package, e.g. `@atlasauth/react`. */
|
|
15
|
+
name: string;
|
|
16
|
+
version: string;
|
|
17
|
+
}
|
|
18
|
+
export declare const ATLAS_JS_SDK: AtlasSdkInfo;
|
|
19
|
+
/** The request header naming the SDK. */
|
|
20
|
+
export declare const SDK_HEADER = "x-atlas-sdk";
|
|
21
|
+
/** The response header carrying advisories (exposed to cross-origin SDKs by the Frontend API). */
|
|
22
|
+
export declare const SDK_ADVISORY_HEADER = "atlas-sdk-advisory";
|
|
23
|
+
/** `@atlasauth/react/0.10.0`. */
|
|
24
|
+
export declare function sdkHeaderValue(sdk: AtlasSdkInfo): string;
|
|
25
|
+
export interface SdkAdvisoryNotice {
|
|
26
|
+
action: string;
|
|
27
|
+
/** The first version that fixes it. */
|
|
28
|
+
min: string | null;
|
|
29
|
+
reason: string | null;
|
|
30
|
+
}
|
|
31
|
+
/** Parse an `Atlas-SDK-Advisory` value; unknown parameters are ignored, garbage yields []. */
|
|
32
|
+
export declare function parseSdkAdvisory(value: string | null | undefined): SdkAdvisoryNotice[];
|
|
33
|
+
/** Test hook: forget what has been logged, as a new page load would. */
|
|
34
|
+
export declare function resetSdkAdvisoryLog(): void;
|
|
35
|
+
/**
|
|
36
|
+
* Read a response's advisory header and warn once per page load per advisory.
|
|
37
|
+
* Never throws; a response without the header (or a server that does not send
|
|
38
|
+
* it) does nothing. Returns the advisories newly logged.
|
|
39
|
+
*/
|
|
40
|
+
export declare function reportSdkAdvisory(response: {
|
|
41
|
+
headers?: {
|
|
42
|
+
get(name: string): string | null;
|
|
43
|
+
};
|
|
44
|
+
} | null | undefined, sdk: AtlasSdkInfo, warn?: (message: string) => void): SdkAdvisoryNotice[];
|