@atlasauth/js 0.1.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/dist/attempt.d.ts +71 -0
- package/dist/attempt.js +89 -0
- package/dist/attempt.js.map +1 -0
- package/dist/check-session.d.ts +56 -0
- package/dist/check-session.js +106 -0
- package/dist/check-session.js.map +1 -0
- package/dist/connect.d.ts +50 -0
- package/dist/connect.js +72 -0
- package/dist/connect.js.map +1 -0
- package/dist/fapi.d.ts +123 -0
- package/dist/fapi.js +314 -0
- package/dist/fapi.js.map +1 -0
- package/dist/index.d.ts +15 -0
- package/dist/index.js +43 -0
- package/dist/index.js.map +1 -0
- package/dist/native.d.ts +112 -0
- package/dist/native.js +201 -0
- package/dist/native.js.map +1 -0
- package/dist/passkey.d.ts +70 -0
- package/dist/passkey.js +126 -0
- package/dist/passkey.js.map +1 -0
- package/dist/password-reset.d.ts +41 -0
- package/dist/password-reset.js +80 -0
- package/dist/password-reset.js.map +1 -0
- package/dist/reauth.d.ts +29 -0
- package/dist/reauth.js +45 -0
- package/dist/reauth.js.map +1 -0
- package/dist/redirect.d.ts +38 -0
- package/dist/redirect.js +56 -0
- package/dist/redirect.js.map +1 -0
- package/dist/siwe.d.ts +23 -0
- package/dist/siwe.js +28 -0
- package/dist/siwe.js.map +1 -0
- package/dist/tab-election.d.ts +68 -0
- package/dist/tab-election.js +111 -0
- package/dist/tab-election.js.map +1 -0
- package/dist/telegram.d.ts +25 -0
- package/dist/telegram.js +18 -0
- package/dist/telegram.js.map +1 -0
- package/dist/telemetry.d.ts +125 -0
- package/dist/telemetry.js +357 -0
- package/dist/telemetry.js.map +1 -0
- package/dist/token-cache.d.ts +74 -0
- package/dist/token-cache.js +104 -0
- package/dist/token-cache.js.map +1 -0
- package/package.json +26 -0
package/dist/fapi.js
ADDED
|
@@ -0,0 +1,314 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.initialFlow = exports.FapiClient = void 0;
|
|
4
|
+
exports.getProviderToken = getProviderToken;
|
|
5
|
+
exports.requestForStep = requestForStep;
|
|
6
|
+
exports.flowFromPending = flowFromPending;
|
|
7
|
+
exports.advance = advance;
|
|
8
|
+
exports.startSignUp = startSignUp;
|
|
9
|
+
exports.prepareFactor = prepareFactor;
|
|
10
|
+
exports.pollAttempt = pollAttempt;
|
|
11
|
+
exports.shouldKeepPolling = shouldKeepPolling;
|
|
12
|
+
const attempt_1 = require("./attempt");
|
|
13
|
+
class FapiClient {
|
|
14
|
+
options;
|
|
15
|
+
constructor(options) {
|
|
16
|
+
this.options = options;
|
|
17
|
+
}
|
|
18
|
+
async request(path, init = {}) {
|
|
19
|
+
const doFetch = this.options.fetchImpl ?? fetch;
|
|
20
|
+
let response;
|
|
21
|
+
try {
|
|
22
|
+
response = await doFetch(`${this.options.baseUrl ?? ''}${path}`, {
|
|
23
|
+
...init,
|
|
24
|
+
// Cookies carry the session. A request without this is indistinguishable
|
|
25
|
+
// from being signed out, which is a maddening bug to chase.
|
|
26
|
+
credentials: 'include',
|
|
27
|
+
headers: {
|
|
28
|
+
'x-publishable-key': this.options.publishableKey,
|
|
29
|
+
...(init.body ? { 'content-type': 'application/json' } : {}),
|
|
30
|
+
...init.headers,
|
|
31
|
+
},
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
/**
|
|
36
|
+
* A network failure is reported as a form-level error rather than thrown.
|
|
37
|
+
* A sign-in box that throws on a flaky connection unmounts itself and
|
|
38
|
+
* loses whatever the user had typed.
|
|
39
|
+
*/
|
|
40
|
+
return {
|
|
41
|
+
ok: false,
|
|
42
|
+
status: 0,
|
|
43
|
+
data: null,
|
|
44
|
+
errors: [{ code: 'NETWORK', message: 'We could not reach the server.' }],
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
let body = null;
|
|
48
|
+
try {
|
|
49
|
+
body = await response.json();
|
|
50
|
+
}
|
|
51
|
+
catch {
|
|
52
|
+
// A 204, or an error page from a proxy. Neither should crash the parse.
|
|
53
|
+
}
|
|
54
|
+
return {
|
|
55
|
+
ok: response.ok,
|
|
56
|
+
status: response.status,
|
|
57
|
+
data: response.ok ? body : null,
|
|
58
|
+
// §9.1 messages are written for humans and surfaced verbatim.
|
|
59
|
+
errors: response.ok ? [] : (0, attempt_1.fieldErrors)(body),
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
post(path, body) {
|
|
63
|
+
return this.request(path, {
|
|
64
|
+
method: 'POST',
|
|
65
|
+
body: body === undefined ? undefined : JSON.stringify(body),
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
get(path) {
|
|
69
|
+
return this.request(path, { method: 'GET' });
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
exports.FapiClient = FapiClient;
|
|
73
|
+
/**
|
|
74
|
+
* Fetch the signed-in user's provider access token. Returns null when there is
|
|
75
|
+
* no usable token (no linked account, or the provider granted none / revoked
|
|
76
|
+
* it) — the caller's cue to prompt a re-connect rather than treat it as fatal.
|
|
77
|
+
* The server refreshes a stale token on read, single-flight, so the token
|
|
78
|
+
* handed back is always live.
|
|
79
|
+
*/
|
|
80
|
+
async function getProviderToken(client, provider) {
|
|
81
|
+
const response = await client.get(`/v1/client/me/external_accounts/${encodeURIComponent(provider)}/token`);
|
|
82
|
+
if (!response.ok || !response.data)
|
|
83
|
+
return null;
|
|
84
|
+
return {
|
|
85
|
+
provider: response.data.provider,
|
|
86
|
+
accessToken: response.data.access_token,
|
|
87
|
+
expiresAt: response.data.expires_at ?? null,
|
|
88
|
+
scopes: response.data.scopes ?? [],
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
exports.initialFlow = {
|
|
92
|
+
attempt: null,
|
|
93
|
+
errors: [],
|
|
94
|
+
busy: false,
|
|
95
|
+
pollSecret: null,
|
|
96
|
+
ticket: null,
|
|
97
|
+
};
|
|
98
|
+
/**
|
|
99
|
+
* Which request the current step needs.
|
|
100
|
+
*
|
|
101
|
+
* Exported and tested separately from the network call, because this mapping is
|
|
102
|
+
* the part that can be wrong in a way nobody notices until a user is stuck.
|
|
103
|
+
*/
|
|
104
|
+
function requestForStep(attempt, values) {
|
|
105
|
+
if (!attempt) {
|
|
106
|
+
return {
|
|
107
|
+
path: '/v1/client/sign_ins',
|
|
108
|
+
// §5 carry a captcha token when the sign-in flow gates the identifier
|
|
109
|
+
// step (an always-on per-flow captcha, or a risk-triggered challenge the
|
|
110
|
+
// server answered with needs_captcha).
|
|
111
|
+
body: {
|
|
112
|
+
identifier: values.identifier ?? '',
|
|
113
|
+
...(values.captcha_token ? { captcha_token: values.captcha_token } : {}),
|
|
114
|
+
},
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
const step = (0, attempt_1.nextStep)(attempt);
|
|
118
|
+
const id = attempt.id ?? '';
|
|
119
|
+
switch (step.kind) {
|
|
120
|
+
case 'collect_identifier':
|
|
121
|
+
return {
|
|
122
|
+
path: '/v1/client/sign_ins',
|
|
123
|
+
body: {
|
|
124
|
+
identifier: values.identifier ?? '',
|
|
125
|
+
...(values.captcha_token ? { captcha_token: values.captcha_token } : {}),
|
|
126
|
+
},
|
|
127
|
+
};
|
|
128
|
+
case 'collect_first_factor':
|
|
129
|
+
/**
|
|
130
|
+
* An emailed code and a password both arrive as "the thing the user
|
|
131
|
+
* typed", but they are different strategies on the same endpoint. The
|
|
132
|
+
* presence of a code field is what distinguishes them — a client-declared
|
|
133
|
+
* strategy would be a field the client can get wrong.
|
|
134
|
+
*/
|
|
135
|
+
return values.code
|
|
136
|
+
? {
|
|
137
|
+
path: `/v1/client/sign_ins/${id}/attempt_first_factor`,
|
|
138
|
+
body: { strategy: 'email_code', code: values.code },
|
|
139
|
+
}
|
|
140
|
+
: {
|
|
141
|
+
path: `/v1/client/sign_ins/${id}/attempt_first_factor`,
|
|
142
|
+
body: { strategy: 'password', password: values.password ?? '' },
|
|
143
|
+
};
|
|
144
|
+
case 'collect_second_factor':
|
|
145
|
+
// Only ever the code (+ the §5.3 "remember this device" opt-in). Sending
|
|
146
|
+
// `password` here would be posting a credential to an endpoint that has no
|
|
147
|
+
// business seeing one.
|
|
148
|
+
return {
|
|
149
|
+
path: `/v1/client/sign_ins/${id}/attempt_second_factor`,
|
|
150
|
+
body: {
|
|
151
|
+
code: values.code ?? '',
|
|
152
|
+
...(values.remember_device === 'true' ? { remember_device: true } : {}),
|
|
153
|
+
},
|
|
154
|
+
};
|
|
155
|
+
/**
|
|
156
|
+
* §11.1 MFA policy `required`. Two consecutive codes, and the factor id
|
|
157
|
+
* from the prepare step — a different endpoint from the second factor,
|
|
158
|
+
* because there is no factor to verify against yet.
|
|
159
|
+
*/
|
|
160
|
+
case 'enroll_second_factor':
|
|
161
|
+
return {
|
|
162
|
+
path: `/v1/client/sign_ins/${id}/attempt_mfa_enrollment`,
|
|
163
|
+
body: {
|
|
164
|
+
factor_id: values.factorId ?? '',
|
|
165
|
+
codes: [values.code ?? '', values.secondCode ?? ''],
|
|
166
|
+
},
|
|
167
|
+
};
|
|
168
|
+
case 'collect_email_code':
|
|
169
|
+
return {
|
|
170
|
+
path: `/v1/client/sign_ups/${id}/attempt_verification`,
|
|
171
|
+
body: { code: values.code ?? '' },
|
|
172
|
+
};
|
|
173
|
+
case 'collect_captcha':
|
|
174
|
+
/**
|
|
175
|
+
* §5 the challenge marker carries no attempt id — the server withheld the
|
|
176
|
+
* attempt until the captcha clears. There is nothing to submit until the
|
|
177
|
+
* widget yields a token (the client should render the captcha, not POST);
|
|
178
|
+
* once solved, re-issue the identifier POST WITH the token to create the
|
|
179
|
+
* real attempt. Submitting without a token just re-triggers the challenge.
|
|
180
|
+
*/
|
|
181
|
+
return values.captcha_token
|
|
182
|
+
? {
|
|
183
|
+
path: '/v1/client/sign_ins',
|
|
184
|
+
body: {
|
|
185
|
+
identifier: values.identifier ?? '',
|
|
186
|
+
captcha_token: values.captcha_token,
|
|
187
|
+
},
|
|
188
|
+
}
|
|
189
|
+
: null;
|
|
190
|
+
case 'collect_new_password':
|
|
191
|
+
return {
|
|
192
|
+
path: `/v1/client/password_resets/${id}/set_new_password`,
|
|
193
|
+
body: { password: values.password ?? '' },
|
|
194
|
+
};
|
|
195
|
+
case 'await_oauth':
|
|
196
|
+
case 'done':
|
|
197
|
+
case 'restart':
|
|
198
|
+
case 'unknown':
|
|
199
|
+
/**
|
|
200
|
+
* Nothing to submit. Returning null rather than a best guess means a
|
|
201
|
+
* component cannot accidentally POST to an endpoint that does not apply
|
|
202
|
+
* to the state the server put it in.
|
|
203
|
+
*/
|
|
204
|
+
return null;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
/**
|
|
208
|
+
* §5.3: seed a flow from an attempt the app was handed mid-stream — an OAuth
|
|
209
|
+
* redirect that came back needing a second factor (`__atlas_status`), with no
|
|
210
|
+
* ticket because the server withheld the session until the factor is passed.
|
|
211
|
+
*
|
|
212
|
+
* The attempt id lets the next submit target the right attempt; the status
|
|
213
|
+
* routes the UI to the step the server is demanding. A null pending attempt —
|
|
214
|
+
* the ordinary fresh sign-in — yields the empty initial flow.
|
|
215
|
+
*/
|
|
216
|
+
function flowFromPending(pending) {
|
|
217
|
+
if (!pending)
|
|
218
|
+
return exports.initialFlow;
|
|
219
|
+
return {
|
|
220
|
+
...exports.initialFlow,
|
|
221
|
+
attempt: { id: pending.id, status: pending.status },
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
/** Advance the flow by one step. Never decides the next status itself. */
|
|
225
|
+
async function advance(client, state, values) {
|
|
226
|
+
const request = requestForStep(state.attempt, values);
|
|
227
|
+
if (!request)
|
|
228
|
+
return state;
|
|
229
|
+
const response = await client.post(request.path, request.body);
|
|
230
|
+
if (!response.ok || !response.data) {
|
|
231
|
+
/**
|
|
232
|
+
* The attempt is KEPT on failure. Clearing it would drop the user back to
|
|
233
|
+
* the identifier step after one wrong password, losing the progress they
|
|
234
|
+
* made and re-triggering the anti-enumeration path for no reason.
|
|
235
|
+
*/
|
|
236
|
+
return { ...state, busy: false, errors: response.errors };
|
|
237
|
+
}
|
|
238
|
+
return {
|
|
239
|
+
attempt: response.data,
|
|
240
|
+
errors: [],
|
|
241
|
+
busy: false,
|
|
242
|
+
pollSecret: state.pollSecret,
|
|
243
|
+
// A completion response carries the ticket to exchange for cookies.
|
|
244
|
+
ticket: response.data.ticket ?? null,
|
|
245
|
+
};
|
|
246
|
+
}
|
|
247
|
+
/**
|
|
248
|
+
* §5 Begin a password sign-up. POSTs email + password + the tenant's configured
|
|
249
|
+
* extra fields (name, company, phone, custom…) to `/v1/client/sign_ups` and
|
|
250
|
+
* returns a flow. Usually `needs_email_verification` — the shared `advance` then
|
|
251
|
+
* drives the emailed code to completion — or, when the instance doesn't gate on
|
|
252
|
+
* verification, a `complete` attempt carrying the session ticket.
|
|
253
|
+
*/
|
|
254
|
+
async function startSignUp(client, input) {
|
|
255
|
+
const hasFields = input.fields && Object.keys(input.fields).length > 0;
|
|
256
|
+
const response = await client.post('/v1/client/sign_ups', {
|
|
257
|
+
email: input.email,
|
|
258
|
+
password: input.password,
|
|
259
|
+
...(hasFields ? { fields: input.fields } : {}),
|
|
260
|
+
// §5.1 forward the legal-consent tick so the server can enforce a REQUIRED
|
|
261
|
+
// agreement (the disabled submit is only a client-side courtesy).
|
|
262
|
+
...(input.consent ? { consent: true } : {}),
|
|
263
|
+
// §5 the bot-defence token, when the sign-up flow's captcha is enabled.
|
|
264
|
+
...(input.captchaToken ? { captcha_token: input.captchaToken } : {}),
|
|
265
|
+
});
|
|
266
|
+
if (!response.ok || !response.data) {
|
|
267
|
+
return { ...exports.initialFlow, busy: false, errors: response.errors };
|
|
268
|
+
}
|
|
269
|
+
return {
|
|
270
|
+
attempt: response.data,
|
|
271
|
+
errors: [],
|
|
272
|
+
busy: false,
|
|
273
|
+
pollSecret: exports.initialFlow.pollSecret,
|
|
274
|
+
ticket: response.data.ticket ?? null,
|
|
275
|
+
};
|
|
276
|
+
}
|
|
277
|
+
/** §5.3: ask the server to send a code or a magic link. */
|
|
278
|
+
async function prepareFactor(client, state, strategy) {
|
|
279
|
+
const id = state.attempt?.id;
|
|
280
|
+
if (!id)
|
|
281
|
+
return state;
|
|
282
|
+
const response = await client.post(`/v1/client/sign_ins/${id}/prepare_first_factor`, { strategy });
|
|
283
|
+
if (!response.ok)
|
|
284
|
+
return { ...state, busy: false, errors: response.errors };
|
|
285
|
+
return {
|
|
286
|
+
...state,
|
|
287
|
+
busy: false,
|
|
288
|
+
errors: [],
|
|
289
|
+
// Held in memory only. It is what lets THIS tab collect a sign-in completed
|
|
290
|
+
// by a link opened on another device.
|
|
291
|
+
pollSecret: response.data?.poll_secret ?? null,
|
|
292
|
+
};
|
|
293
|
+
}
|
|
294
|
+
/**
|
|
295
|
+
* §5.3 polling. Returns the updated flow, and a ticket once the link has been
|
|
296
|
+
* opened somewhere.
|
|
297
|
+
*/
|
|
298
|
+
async function pollAttempt(client, state) {
|
|
299
|
+
const id = state.attempt?.id;
|
|
300
|
+
if (!id || !state.pollSecret)
|
|
301
|
+
return { state, ticket: null };
|
|
302
|
+
const response = await client.get(`/v1/client/sign_ins/${id}?poll_secret=${encodeURIComponent(state.pollSecret)}`);
|
|
303
|
+
if (!response.ok || !response.data)
|
|
304
|
+
return { state, ticket: null };
|
|
305
|
+
return {
|
|
306
|
+
state: { ...state, attempt: response.data },
|
|
307
|
+
ticket: response.data.ticket ?? null,
|
|
308
|
+
};
|
|
309
|
+
}
|
|
310
|
+
/** Whether polling should continue, so a tab does not poll a dead attempt forever. */
|
|
311
|
+
function shouldKeepPolling(state) {
|
|
312
|
+
return Boolean(state.pollSecret) && Boolean(state.attempt) && !(0, attempt_1.isTerminal)(state.attempt);
|
|
313
|
+
}
|
|
314
|
+
//# sourceMappingURL=fapi.js.map
|
package/dist/fapi.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fapi.js","sourceRoot":"","sources":["../src/fapi.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export * from './token-cache';
|
|
2
|
+
export * from './tab-election';
|
|
3
|
+
export * from './attempt';
|
|
4
|
+
export * from './redirect';
|
|
5
|
+
export * from './fapi';
|
|
6
|
+
export * from './native';
|
|
7
|
+
export * from './passkey';
|
|
8
|
+
export * from './telegram';
|
|
9
|
+
export * from './siwe';
|
|
10
|
+
export * from './telemetry';
|
|
11
|
+
export * from './reauth';
|
|
12
|
+
export * from './connect';
|
|
13
|
+
export * from './password-reset';
|
|
14
|
+
export * from './check-session';
|
|
15
|
+
export { type AuthzClaims, type ProtectCondition, type ProtectOutcome, type ProtectReason, evaluate, hasFromClaims, protectFromClaims, ForbiddenError, ROLE_KEY_PATTERN, PERMISSION_KEY_PATTERN, isRoleKey, isPermissionKey, } from '@atlasauth/authz';
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
exports.isPermissionKey = exports.isRoleKey = exports.PERMISSION_KEY_PATTERN = exports.ROLE_KEY_PATTERN = exports.ForbiddenError = exports.protectFromClaims = exports.hasFromClaims = exports.evaluate = void 0;
|
|
18
|
+
__exportStar(require("./token-cache"), exports);
|
|
19
|
+
__exportStar(require("./tab-election"), exports);
|
|
20
|
+
__exportStar(require("./attempt"), exports);
|
|
21
|
+
__exportStar(require("./redirect"), exports);
|
|
22
|
+
__exportStar(require("./fapi"), exports);
|
|
23
|
+
__exportStar(require("./native"), exports);
|
|
24
|
+
__exportStar(require("./passkey"), exports);
|
|
25
|
+
__exportStar(require("./telegram"), exports);
|
|
26
|
+
__exportStar(require("./siwe"), exports);
|
|
27
|
+
__exportStar(require("./telemetry"), exports);
|
|
28
|
+
__exportStar(require("./reauth"), exports);
|
|
29
|
+
__exportStar(require("./connect"), exports);
|
|
30
|
+
__exportStar(require("./password-reset"), exports);
|
|
31
|
+
__exportStar(require("./check-session"), exports);
|
|
32
|
+
// Framework-agnostic authorization primitive — `has()`/`evaluate` for any
|
|
33
|
+
// non-React/Next consumer reading org_role/org_permissions off its session.
|
|
34
|
+
var authz_1 = require("@atlasauth/authz");
|
|
35
|
+
Object.defineProperty(exports, "evaluate", { enumerable: true, get: function () { return authz_1.evaluate; } });
|
|
36
|
+
Object.defineProperty(exports, "hasFromClaims", { enumerable: true, get: function () { return authz_1.hasFromClaims; } });
|
|
37
|
+
Object.defineProperty(exports, "protectFromClaims", { enumerable: true, get: function () { return authz_1.protectFromClaims; } });
|
|
38
|
+
Object.defineProperty(exports, "ForbiddenError", { enumerable: true, get: function () { return authz_1.ForbiddenError; } });
|
|
39
|
+
Object.defineProperty(exports, "ROLE_KEY_PATTERN", { enumerable: true, get: function () { return authz_1.ROLE_KEY_PATTERN; } });
|
|
40
|
+
Object.defineProperty(exports, "PERMISSION_KEY_PATTERN", { enumerable: true, get: function () { return authz_1.PERMISSION_KEY_PATTERN; } });
|
|
41
|
+
Object.defineProperty(exports, "isRoleKey", { enumerable: true, get: function () { return authz_1.isRoleKey; } });
|
|
42
|
+
Object.defineProperty(exports, "isPermissionKey", { enumerable: true, get: function () { return authz_1.isPermissionKey; } });
|
|
43
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;AAAA,gDAA8B;AAC9B,iDAA+B;AAC/B,4CAA0B;AAC1B,6CAA2B;AAC3B,yCAAuB;AACvB,2CAAyB;AACzB,4CAA0B;AAC1B,6CAA2B;AAC3B,yCAAuB;AACvB,8CAA4B;AAC5B,2CAAyB;AACzB,4CAA0B;AAC1B,mDAAiC;AACjC,kDAAgC;AAChC,0EAA0E;AAC1E,4EAA4E;AAC5E,0CAa0B;AARxB,iGAAA,QAAQ,OAAA;AACR,sGAAA,aAAa,OAAA;AACb,0GAAA,iBAAiB,OAAA;AACjB,uGAAA,cAAc,OAAA;AACd,yGAAA,gBAAgB,OAAA;AAChB,+GAAA,sBAAsB,OAAA;AACtB,kGAAA,SAAS,OAAA;AACT,wGAAA,eAAe,OAAA"}
|
package/dist/native.d.ts
ADDED
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* §6 native / One-Tap sign-in — the client half.
|
|
3
|
+
*
|
|
4
|
+
* The SDK does not make HTTP calls (the app owns fetch + cookies), so this
|
|
5
|
+
* module is two pure helpers for the request/response shape plus a
|
|
6
|
+
* framework-agnostic Google Identity Services loader that resolves a credential
|
|
7
|
+
* id_token. The app posts that to `/v1/client/sign_ins/id_token` and then reads
|
|
8
|
+
* the result exactly like any other attempt (nextStep / a returned ticket).
|
|
9
|
+
*/
|
|
10
|
+
export interface NativeSignInBody {
|
|
11
|
+
provider: string;
|
|
12
|
+
id_token: string;
|
|
13
|
+
nonce?: string;
|
|
14
|
+
}
|
|
15
|
+
/** Build the POST body for `/v1/client/sign_ins/id_token`. */
|
|
16
|
+
export declare function nativeSignInBody(input: {
|
|
17
|
+
provider: string;
|
|
18
|
+
idToken: string;
|
|
19
|
+
nonce?: string;
|
|
20
|
+
}): NativeSignInBody;
|
|
21
|
+
export interface NativeSignInResult {
|
|
22
|
+
attemptId: string;
|
|
23
|
+
status: string;
|
|
24
|
+
/** Present only when the sign-in completed — exchange it for cookies. */
|
|
25
|
+
ticket?: string;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Parse the native sign-in response. A `ticket` means complete; a status
|
|
29
|
+
* without a ticket (e.g. `needs_second_factor`) means a factor is still owed —
|
|
30
|
+
* the same contract the redirect flow uses, so callers must not treat it as
|
|
31
|
+
* signed-in.
|
|
32
|
+
*/
|
|
33
|
+
export declare function parseNativeSignInResponse(body: unknown): NativeSignInResult | null;
|
|
34
|
+
interface GsiId {
|
|
35
|
+
initialize(config: Record<string, unknown>): void;
|
|
36
|
+
prompt(listener?: (notification: unknown) => void): void;
|
|
37
|
+
renderButton(parent: HTMLElement, options: Record<string, unknown>): void;
|
|
38
|
+
cancel(): void;
|
|
39
|
+
}
|
|
40
|
+
interface GsiHost {
|
|
41
|
+
google?: {
|
|
42
|
+
accounts?: {
|
|
43
|
+
id?: GsiId;
|
|
44
|
+
};
|
|
45
|
+
};
|
|
46
|
+
document: Document;
|
|
47
|
+
ResizeObserver?: typeof ResizeObserver;
|
|
48
|
+
}
|
|
49
|
+
/** Inject the GSI script once; resolves when it is ready. */
|
|
50
|
+
export declare function loadGoogleIdentityServices(doc: Document): Promise<void>;
|
|
51
|
+
/** Reset the one-shot loader (tests). */
|
|
52
|
+
export declare function resetGoogleIdentityServices(): void;
|
|
53
|
+
/**
|
|
54
|
+
* Load GSI and resolve a Google credential (an OIDC id_token) from One-Tap.
|
|
55
|
+
* The nonce, when supplied, is embedded in the credential and MUST be echoed to
|
|
56
|
+
* the server so it can bind the token to this request.
|
|
57
|
+
*/
|
|
58
|
+
export declare function requestGoogleCredential(opts: {
|
|
59
|
+
clientId: string;
|
|
60
|
+
nonce?: string;
|
|
61
|
+
autoSelect?: boolean;
|
|
62
|
+
host?: GsiHost;
|
|
63
|
+
}): Promise<string>;
|
|
64
|
+
/**
|
|
65
|
+
* Render the official "Sign in with Google" BUTTON into `parent` (and, when
|
|
66
|
+
* `oneTap` is set, also show the One-Tap prompt). Each resolved credential
|
|
67
|
+
* id_token is handed to `onCredential`, which the app posts to
|
|
68
|
+
* /v1/client/sign_ins/id_token. Unlike {@link requestGoogleCredential} this does
|
|
69
|
+
* not resolve once — a button can be clicked repeatedly — so it takes a
|
|
70
|
+
* callback. Framework-agnostic: the caller owns the DOM node and the fetch.
|
|
71
|
+
*/
|
|
72
|
+
export declare function renderGoogleButton(opts: {
|
|
73
|
+
parent: HTMLElement;
|
|
74
|
+
clientId: string;
|
|
75
|
+
nonce?: string;
|
|
76
|
+
onCredential: (idToken: string) => void;
|
|
77
|
+
onError?: (error: Error) => void;
|
|
78
|
+
/** GSI renderButton options (theme, size, text, shape, width…). */
|
|
79
|
+
buttonOptions?: Record<string, unknown>;
|
|
80
|
+
/** Also show the One-Tap prompt above the button. */
|
|
81
|
+
oneTap?: boolean;
|
|
82
|
+
host?: GsiHost;
|
|
83
|
+
}): Promise<void>;
|
|
84
|
+
/**
|
|
85
|
+
* Render YOUR uniform button, backed by Google's real (but invisible) GSI button.
|
|
86
|
+
*
|
|
87
|
+
* Google refuses to let you style its button, and One-Tap is FedCM-flaky — so to
|
|
88
|
+
* show your OWN button while still using the secretless id_token flow, you overlay
|
|
89
|
+
* Google's real button, at opacity 0, exactly on top of your styled one. The user
|
|
90
|
+
* sees your button; the click lands on Google's, which mints the id_token. No
|
|
91
|
+
* secret, no redirect.
|
|
92
|
+
*
|
|
93
|
+
* The failure mode people hit is misalignment — the invisible button not covering
|
|
94
|
+
* the visible one, so clicks miss. This guards against it: the overlay fills the
|
|
95
|
+
* wrapper, and a ResizeObserver keeps Google's button width matched to yours so
|
|
96
|
+
* the whole surface stays clickable as the layout changes.
|
|
97
|
+
*
|
|
98
|
+
* `wrapper` is YOUR styled button (or its container); it is made position:relative
|
|
99
|
+
* if it is not already positioned. Returns `{ destroy }` to tear the overlay down.
|
|
100
|
+
*/
|
|
101
|
+
export declare function renderGoogleOverlayButton(opts: {
|
|
102
|
+
wrapper: HTMLElement;
|
|
103
|
+
clientId: string;
|
|
104
|
+
nonce?: string;
|
|
105
|
+
onCredential: (idToken: string) => void;
|
|
106
|
+
onError?: (error: Error) => void;
|
|
107
|
+
size?: 'large' | 'medium' | 'small';
|
|
108
|
+
host?: GsiHost;
|
|
109
|
+
}): Promise<{
|
|
110
|
+
destroy: () => void;
|
|
111
|
+
}>;
|
|
112
|
+
export {};
|