@palbase/web 6.0.0 → 7.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/{analytics-facade-Cp3d4QI-.d.ts → analytics-facade-CZIwbsvG.d.ts} +65 -1
- package/dist/{analytics-facade-CaluA4bW.d.cts → analytics-facade-esr6cOBN.d.cts} +65 -1
- package/dist/{chunk-BNAGRUIQ.js → chunk-ACCJV6FV.js} +32 -2
- package/dist/chunk-ACCJV6FV.js.map +1 -0
- package/dist/{chunk-KOJ4OAAR.js → chunk-P6TWUWZC.js} +209 -3
- package/dist/chunk-P6TWUWZC.js.map +1 -0
- package/dist/{chunk-OWLTZG2V.js → chunk-ZC6Q3GPX.js} +2 -2
- package/dist/index.cjs +207 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.js +2 -2
- package/dist/internal.cjs +238 -2
- package/dist/internal.cjs.map +1 -1
- package/dist/internal.d.cts +3 -3
- package/dist/internal.d.ts +3 -3
- package/dist/internal.js +2 -2
- package/dist/next/client.cjs +238 -2
- package/dist/next/client.cjs.map +1 -1
- package/dist/next/client.js +2 -2
- package/dist/next/index.cjs +238 -2
- package/dist/next/index.cjs.map +1 -1
- package/dist/next/index.d.cts +2 -2
- package/dist/next/index.d.ts +2 -2
- package/dist/next/index.js +3 -3
- package/dist/next/proxy.js +2 -2
- package/dist/{pb-DUK5qy81.d.ts → pb-AWwslm5m.d.ts} +1 -1
- package/dist/{pb-DvV6ftmf.d.cts → pb-BT-vKA4j.d.cts} +1 -1
- package/dist/react/index.cjs +1 -1
- package/dist/react/index.cjs.map +1 -1
- package/dist/react/index.d.cts +1 -1
- package/dist/react/index.d.ts +1 -1
- package/dist/react/index.js +2 -2
- package/package.json +1 -1
- package/dist/chunk-BNAGRUIQ.js.map +0 -1
- package/dist/chunk-KOJ4OAAR.js.map +0 -1
- /package/dist/{chunk-OWLTZG2V.js.map → chunk-ZC6Q3GPX.js.map} +0 -0
package/dist/internal.d.cts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { P as PalbeConfig } from './analytics-facade-
|
|
2
|
-
export { d as PalbeRuntime, e as buildRuntime } from './analytics-facade-
|
|
1
|
+
import { P as PalbeConfig } from './analytics-facade-esr6cOBN.cjs';
|
|
2
|
+
export { d as PalbeRuntime, e as buildRuntime } from './analytics-facade-esr6cOBN.cjs';
|
|
3
3
|
import { B as BackendError } from './errors-fDoNdTrJ.cjs';
|
|
4
|
-
export { P as PB, c as createBoundClient } from './pb-
|
|
4
|
+
export { P as PB, c as createBoundClient } from './pb-BT-vKA4j.cjs';
|
|
5
5
|
import './storage-BPaeSG8K.cjs';
|
|
6
6
|
import './pooled-flags-4GtDtsiu.js';
|
|
7
7
|
|
package/dist/internal.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { P as PalbeConfig } from './analytics-facade-
|
|
2
|
-
export { d as PalbeRuntime, e as buildRuntime } from './analytics-facade-
|
|
1
|
+
import { P as PalbeConfig } from './analytics-facade-CZIwbsvG.js';
|
|
2
|
+
export { d as PalbeRuntime, e as buildRuntime } from './analytics-facade-CZIwbsvG.js';
|
|
3
3
|
import { B as BackendError } from './errors-fDoNdTrJ.js';
|
|
4
|
-
export { P as PB, c as createBoundClient } from './pb-
|
|
4
|
+
export { P as PB, c as createBoundClient } from './pb-AWwslm5m.js';
|
|
5
5
|
import './storage-BPaeSG8K.js';
|
|
6
6
|
import './pooled-flags-4GtDtsiu.js';
|
|
7
7
|
|
package/dist/internal.js
CHANGED
|
@@ -6,8 +6,8 @@ import {
|
|
|
6
6
|
createBoundClient,
|
|
7
7
|
getRuntime,
|
|
8
8
|
onConfigured
|
|
9
|
-
} from "./chunk-
|
|
10
|
-
import "./chunk-
|
|
9
|
+
} from "./chunk-P6TWUWZC.js";
|
|
10
|
+
import "./chunk-ACCJV6FV.js";
|
|
11
11
|
import "./chunk-CFDU23TB.js";
|
|
12
12
|
import "./chunk-PZ5AY32C.js";
|
|
13
13
|
export {
|
package/dist/next/client.cjs
CHANGED
|
@@ -49,6 +49,27 @@ var PalbaseError = class extends Error {
|
|
|
49
49
|
this.details = details;
|
|
50
50
|
}
|
|
51
51
|
};
|
|
52
|
+
function detectPlatform() {
|
|
53
|
+
if (typeof Deno !== "undefined") {
|
|
54
|
+
return "deno";
|
|
55
|
+
}
|
|
56
|
+
if (process?.versions) {
|
|
57
|
+
if ("bun" in process.versions) {
|
|
58
|
+
return "bun";
|
|
59
|
+
}
|
|
60
|
+
if ("node" in process.versions) {
|
|
61
|
+
return "node";
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
if (typeof navigator !== "undefined" && navigator.product === "ReactNative") {
|
|
65
|
+
return "react-native";
|
|
66
|
+
}
|
|
67
|
+
return "browser";
|
|
68
|
+
}
|
|
69
|
+
function wirePlatform() {
|
|
70
|
+
const host = detectPlatform();
|
|
71
|
+
return host === "browser" ? "web" : host;
|
|
72
|
+
}
|
|
52
73
|
var PALBASE_DEFAULT_HOST = "api.palbase.studio";
|
|
53
74
|
var API_KEY_RE = /^pb_([a-z0-9]{4,24})_c[A-Za-z0-9]{20}$/;
|
|
54
75
|
function parseEnvironmentRef(apiKey) {
|
|
@@ -134,8 +155,17 @@ var HttpClient = class _HttpClient {
|
|
|
134
155
|
}
|
|
135
156
|
buildHeaders(options) {
|
|
136
157
|
const headers = {
|
|
137
|
-
"Content-Type": "application/json"
|
|
158
|
+
"Content-Type": "application/json",
|
|
159
|
+
// Client identity, the web counterpart of the iOS SDK's
|
|
160
|
+
// ClientInfo.augment(). The server reads these to resolve flag targeting
|
|
161
|
+
// conditions and to label telemetry, so an app declares nothing and calls
|
|
162
|
+
// nothing — whatever the SDK can know, it sends.
|
|
163
|
+
"X-Platform": wirePlatform()
|
|
138
164
|
};
|
|
165
|
+
const appVersion = this.options?.appVersion?.trim();
|
|
166
|
+
if (appVersion) {
|
|
167
|
+
headers["X-Palbase-Client-Version"] = appVersion;
|
|
168
|
+
}
|
|
139
169
|
const effectiveKey = this.apiKey;
|
|
140
170
|
if (effectiveKey) {
|
|
141
171
|
headers["apikey"] = effectiveKey;
|
|
@@ -1248,6 +1278,162 @@ function asWireAuthResult(raw) {
|
|
|
1248
1278
|
return raw;
|
|
1249
1279
|
}
|
|
1250
1280
|
|
|
1281
|
+
// src/passkey.ts
|
|
1282
|
+
function base64UrlToBytes(value) {
|
|
1283
|
+
const padded = value.replace(/-/g, "+").replace(/_/g, "/");
|
|
1284
|
+
const binary = atob(padded.padEnd(padded.length + (4 - padded.length % 4) % 4, "="));
|
|
1285
|
+
const bytes = new Uint8Array(new ArrayBuffer(binary.length));
|
|
1286
|
+
for (let i = 0; i < binary.length; i += 1) bytes[i] = binary.charCodeAt(i);
|
|
1287
|
+
return bytes;
|
|
1288
|
+
}
|
|
1289
|
+
function bytesToBase64Url(buffer) {
|
|
1290
|
+
const bytes = new Uint8Array(buffer);
|
|
1291
|
+
let binary = "";
|
|
1292
|
+
for (const b of bytes) binary += String.fromCharCode(b);
|
|
1293
|
+
return btoa(binary).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
|
|
1294
|
+
}
|
|
1295
|
+
function requireString(source, key) {
|
|
1296
|
+
const value = source[key];
|
|
1297
|
+
if (typeof value !== "string" || value === "") {
|
|
1298
|
+
throw new Error(`passkey options are missing ${key}`);
|
|
1299
|
+
}
|
|
1300
|
+
return value;
|
|
1301
|
+
}
|
|
1302
|
+
function toCreationOptions(publicKey) {
|
|
1303
|
+
const rp = publicKey.rp;
|
|
1304
|
+
const user = publicKey.user;
|
|
1305
|
+
if (!user?.id) {
|
|
1306
|
+
throw new Error("passkey options carry no user id \u2014 the credential would be unusable");
|
|
1307
|
+
}
|
|
1308
|
+
const excludeCredentials = Array.isArray(publicKey.excludeCredentials) ? publicKey.excludeCredentials.map((c) => ({
|
|
1309
|
+
id: base64UrlToBytes(c.id),
|
|
1310
|
+
type: "public-key"
|
|
1311
|
+
})) : void 0;
|
|
1312
|
+
return {
|
|
1313
|
+
challenge: base64UrlToBytes(requireString(publicKey, "challenge")),
|
|
1314
|
+
rp: { id: rp?.id, name: rp?.name ?? rp?.id ?? "" },
|
|
1315
|
+
user: {
|
|
1316
|
+
id: base64UrlToBytes(user.id),
|
|
1317
|
+
name: user.name ?? "",
|
|
1318
|
+
displayName: user.displayName ?? user.name ?? ""
|
|
1319
|
+
},
|
|
1320
|
+
pubKeyCredParams: publicKey.pubKeyCredParams ?? [],
|
|
1321
|
+
authenticatorSelection: publicKey.authenticatorSelection,
|
|
1322
|
+
timeout: publicKey.timeout,
|
|
1323
|
+
attestation: publicKey.attestation,
|
|
1324
|
+
excludeCredentials
|
|
1325
|
+
};
|
|
1326
|
+
}
|
|
1327
|
+
function toRequestOptions(publicKey) {
|
|
1328
|
+
const allowCredentials = Array.isArray(publicKey.allowCredentials) ? publicKey.allowCredentials.map((c) => ({
|
|
1329
|
+
id: base64UrlToBytes(c.id),
|
|
1330
|
+
type: "public-key"
|
|
1331
|
+
})) : void 0;
|
|
1332
|
+
return {
|
|
1333
|
+
challenge: base64UrlToBytes(requireString(publicKey, "challenge")),
|
|
1334
|
+
rpId: publicKey.rpId,
|
|
1335
|
+
timeout: publicKey.timeout,
|
|
1336
|
+
userVerification: publicKey.userVerification,
|
|
1337
|
+
allowCredentials
|
|
1338
|
+
};
|
|
1339
|
+
}
|
|
1340
|
+
function attestationToJSON(credential) {
|
|
1341
|
+
const response = credential.response;
|
|
1342
|
+
return {
|
|
1343
|
+
id: credential.id,
|
|
1344
|
+
rawId: bytesToBase64Url(credential.rawId),
|
|
1345
|
+
type: credential.type,
|
|
1346
|
+
response: {
|
|
1347
|
+
clientDataJSON: bytesToBase64Url(response.clientDataJSON),
|
|
1348
|
+
attestationObject: bytesToBase64Url(response.attestationObject)
|
|
1349
|
+
}
|
|
1350
|
+
};
|
|
1351
|
+
}
|
|
1352
|
+
function assertionToJSON(credential) {
|
|
1353
|
+
const response = credential.response;
|
|
1354
|
+
return {
|
|
1355
|
+
id: credential.id,
|
|
1356
|
+
rawId: bytesToBase64Url(credential.rawId),
|
|
1357
|
+
type: credential.type,
|
|
1358
|
+
response: {
|
|
1359
|
+
clientDataJSON: bytesToBase64Url(response.clientDataJSON),
|
|
1360
|
+
authenticatorData: bytesToBase64Url(response.authenticatorData),
|
|
1361
|
+
signature: bytesToBase64Url(response.signature),
|
|
1362
|
+
// The user handle is how palauth resolves WHO signed in on a discoverable
|
|
1363
|
+
// login — there is no identifier in the request.
|
|
1364
|
+
userHandle: response.userHandle ? bytesToBase64Url(response.userHandle) : null
|
|
1365
|
+
}
|
|
1366
|
+
};
|
|
1367
|
+
}
|
|
1368
|
+
function isPasskeySupported() {
|
|
1369
|
+
return typeof window !== "undefined" && typeof window.PublicKeyCredential === "function" && typeof navigator !== "undefined" && navigator.credentials !== void 0;
|
|
1370
|
+
}
|
|
1371
|
+
function ensureSupported() {
|
|
1372
|
+
if (!isPasskeySupported()) {
|
|
1373
|
+
throw new Error("This browser cannot use passkeys \u2014 offer a password or e-mail sign-in");
|
|
1374
|
+
}
|
|
1375
|
+
}
|
|
1376
|
+
async function createCredential(publicKey) {
|
|
1377
|
+
const credential = await navigator.credentials.create({
|
|
1378
|
+
publicKey: toCreationOptions(publicKey)
|
|
1379
|
+
});
|
|
1380
|
+
if (credential === null) {
|
|
1381
|
+
throw new Error("the browser returned no credential");
|
|
1382
|
+
}
|
|
1383
|
+
return credential;
|
|
1384
|
+
}
|
|
1385
|
+
async function getCredential(publicKey) {
|
|
1386
|
+
const credential = await navigator.credentials.get({
|
|
1387
|
+
publicKey: toRequestOptions(publicKey)
|
|
1388
|
+
});
|
|
1389
|
+
if (credential === null) {
|
|
1390
|
+
throw new Error("the browser returned no credential");
|
|
1391
|
+
}
|
|
1392
|
+
return credential;
|
|
1393
|
+
}
|
|
1394
|
+
async function passkeySignIn(rt) {
|
|
1395
|
+
ensureSupported();
|
|
1396
|
+
const envelope = await palbeRequest(rt, "POST", "/auth/webauthn/login/begin", {
|
|
1397
|
+
body: {}
|
|
1398
|
+
});
|
|
1399
|
+
const credential = await getCredential(envelope.options.publicKey);
|
|
1400
|
+
const raw = await palbeRequest(rt, "POST", "/auth/webauthn/login/finish", {
|
|
1401
|
+
body: assertionToJSON(credential)
|
|
1402
|
+
});
|
|
1403
|
+
const result = asWireAuthResult(raw);
|
|
1404
|
+
if (result === null) {
|
|
1405
|
+
throw new Error("passkey sign-in returned an unusable session");
|
|
1406
|
+
}
|
|
1407
|
+
return result;
|
|
1408
|
+
}
|
|
1409
|
+
async function passkeySignUp(rt, email, displayName) {
|
|
1410
|
+
ensureSupported();
|
|
1411
|
+
const begun = await palbeRequest(rt, "POST", "/auth/webauthn/signup/begin", {
|
|
1412
|
+
body: { email, user_name: displayName }
|
|
1413
|
+
});
|
|
1414
|
+
const credential = await createCredential(begun.options.publicKey);
|
|
1415
|
+
await palbeRequest(
|
|
1416
|
+
rt,
|
|
1417
|
+
"POST",
|
|
1418
|
+
`/auth/webauthn/signup/finish?user_id=${encodeURIComponent(begun.user_id)}`,
|
|
1419
|
+
{ body: attestationToJSON(credential) }
|
|
1420
|
+
);
|
|
1421
|
+
return await passkeySignIn(rt);
|
|
1422
|
+
}
|
|
1423
|
+
async function passkeyRegister(rt, name) {
|
|
1424
|
+
ensureSupported();
|
|
1425
|
+
const envelope = await palbeRequest(
|
|
1426
|
+
rt,
|
|
1427
|
+
"POST",
|
|
1428
|
+
"/auth/webauthn/register/begin",
|
|
1429
|
+
{ body: { name } }
|
|
1430
|
+
);
|
|
1431
|
+
const credential = await createCredential(envelope.options.publicKey);
|
|
1432
|
+
await palbeRequest(rt, "POST", "/auth/webauthn/register/finish", {
|
|
1433
|
+
body: attestationToJSON(credential)
|
|
1434
|
+
});
|
|
1435
|
+
}
|
|
1436
|
+
|
|
1251
1437
|
// src/auth-facade.ts
|
|
1252
1438
|
function mapWireUser(raw) {
|
|
1253
1439
|
return {
|
|
@@ -1384,6 +1570,23 @@ var PalbeAuth = class {
|
|
|
1384
1570
|
const raw = await palbeRequest(this.rt, "GET", "/auth/user");
|
|
1385
1571
|
return mapWireUser(raw);
|
|
1386
1572
|
}
|
|
1573
|
+
/**
|
|
1574
|
+
* Which credentials this account actually has.
|
|
1575
|
+
*
|
|
1576
|
+
* An account reached through Google has no password, so showing it a
|
|
1577
|
+
* "current password" field gives the user something they can never fill —
|
|
1578
|
+
* and `getUser()` cannot tell you, because GET /auth/user carries no
|
|
1579
|
+
* credential information. Read this before rendering any re-auth or
|
|
1580
|
+
* change-password form.
|
|
1581
|
+
*/
|
|
1582
|
+
async getSignInMethods() {
|
|
1583
|
+
const raw = await palbeRequest(this.rt, "GET", "/auth/me");
|
|
1584
|
+
return {
|
|
1585
|
+
password: raw.has_password,
|
|
1586
|
+
mfa: raw.has_mfa,
|
|
1587
|
+
providers: raw.providers ?? null
|
|
1588
|
+
};
|
|
1589
|
+
}
|
|
1387
1590
|
async refreshUser() {
|
|
1388
1591
|
const user = await this.getUser();
|
|
1389
1592
|
const changed = !usersEqual(user, this.cachedUser);
|
|
@@ -1585,6 +1788,39 @@ var PalbeAuth = class {
|
|
|
1585
1788
|
return this.adopt(data);
|
|
1586
1789
|
});
|
|
1587
1790
|
}
|
|
1791
|
+
/**
|
|
1792
|
+
* Sign in with a passkey stored for this Environment. No identifier is typed:
|
|
1793
|
+
* the browser lists the accounts it holds and the user picks one.
|
|
1794
|
+
*
|
|
1795
|
+
* Throws when the browser cannot run a ceremony — check `passkeysSupported`
|
|
1796
|
+
* first and keep a password or e-mail path beside the button.
|
|
1797
|
+
*/
|
|
1798
|
+
async signInWithPasskey() {
|
|
1799
|
+
return this.withSigningIn(async () => this.adoptWire(await passkeySignIn(this.rt)));
|
|
1800
|
+
}
|
|
1801
|
+
/**
|
|
1802
|
+
* Create an account whose only credential is a passkey — the e-mail is the
|
|
1803
|
+
* identifier, the passkey is the credential, and no password ever exists.
|
|
1804
|
+
*/
|
|
1805
|
+
async signUpWithPasskey(email, displayName) {
|
|
1806
|
+
return this.withSigningIn(
|
|
1807
|
+
async () => this.adoptWire(await passkeySignUp(this.rt, email, displayName))
|
|
1808
|
+
);
|
|
1809
|
+
}
|
|
1810
|
+
/**
|
|
1811
|
+
* Add a passkey to the signed-in account, so the next sign-in is one tap.
|
|
1812
|
+
*
|
|
1813
|
+
* Rejects with a 403 `reauthentication_required` when the session is not
|
|
1814
|
+
* recent: a passkey outlives a password reset, so enrolling one takes more
|
|
1815
|
+
* than a valid session.
|
|
1816
|
+
*/
|
|
1817
|
+
async registerPasskey(name) {
|
|
1818
|
+
await passkeyRegister(this.rt, name);
|
|
1819
|
+
}
|
|
1820
|
+
/** Whether this browser can run a passkey ceremony at all. */
|
|
1821
|
+
get passkeysSupported() {
|
|
1822
|
+
return isPasskeySupported();
|
|
1823
|
+
}
|
|
1588
1824
|
async signInWithOAuth(params) {
|
|
1589
1825
|
const { redirect = true, ...opts } = params;
|
|
1590
1826
|
const { url } = unwrap(await this.rt.authClient.getOAuthURL(opts));
|
|
@@ -8828,7 +9064,7 @@ function defaultSessionStorage(key) {
|
|
|
8828
9064
|
}
|
|
8829
9065
|
|
|
8830
9066
|
// src/version.ts
|
|
8831
|
-
var VERSION = "
|
|
9067
|
+
var VERSION = "7.1.0";
|
|
8832
9068
|
|
|
8833
9069
|
// src/runtime.ts
|
|
8834
9070
|
function buildRuntime(config) {
|