@protobase/client 0.3.5 → 0.4.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.
@@ -0,0 +1,18 @@
1
+ import { passkeyClient } from "@better-auth/passkey/client";
2
+ import { createAuthClient } from "better-auth/client";
3
+ import { emailOTPClient, jwtClient, twoFactorClient } from "better-auth/client/plugins";
4
+ //#region src/better-auth-client.ts
5
+ /** Better Auth's browser client with the plugins `createAuth` turns on: tokens, emailed codes, two-factor authentication and passkeys. */
6
+ const betterAuthClient = (baseURL, basePath, fetch) => createAuthClient({
7
+ baseURL,
8
+ basePath,
9
+ plugins: [
10
+ jwtClient(),
11
+ emailOTPClient(),
12
+ twoFactorClient(),
13
+ passkeyClient()
14
+ ],
15
+ fetchOptions: { customFetchImpl: fetch }
16
+ });
17
+ //#endregion
18
+ export { betterAuthClient };
package/dist/index.d.ts CHANGED
@@ -3,7 +3,13 @@ import { ClientOptions } from "./transport.js";
3
3
  import { BatchOp, BatchRef, BatchResult, Facet, Histogram, HistogramBucket, ListPage, Meta, MetaResult, RecordOf, RecordPermissions, ResourcePermissions, ResourceRef, Series, SeriesParams, SeriesPoint, Stored } from "./types.js";
4
4
  import { Client, createClient } from "./client.js";
5
5
  import { ApiError, PreconditionFailedError, ProblemDetails, ProblemError, isApiError } from "./problem.js";
6
- import { AuthError, AuthSession, AuthSessionOptions, AuthUser, SetupStatus, createAuthSession, createStaticSession, tokenExpiry } from "./auth.js";
6
+ import { SignInPolicy, SignInPolicyClient, SignInPolicyState, SignInRule, StaffAccessRule } from "./sign-in-policy.js";
7
+ import { AccountSecurity, AccountSignIn, AuthenticatorSetup, Passkey, RequiredSetup } from "./account-security.js";
8
+ import { StaffSignIn, StaffSignInClient } from "./staff-sign-in.js";
9
+ import { AuthUser, SetupStatus, SignInMethod, SignInResult, TwoFactorMethod } from "./auth-types.js";
10
+ import { AuthError } from "./auth-error.js";
11
+ import { AuthSession, AuthSessionOptions, createAuthSession, tokenExpiry } from "./auth.js";
12
+ import { createStaticSession } from "./static-session.js";
7
13
  import { AssistantClient, AssistantClientOptions, AssistantConnection, createAssistantClient } from "./assistant.js";
8
14
  import { RuntimeClient, RuntimeClientOptions, RuntimePolicy, RuntimeStatus, createRuntimeClient } from "./runtime.js";
9
- export { ApiError, type AssistantClient, type AssistantClientOptions, type AssistantConnection, AuthError, type AuthSession, type AuthSessionOptions, type AuthUser, type BatchOp, type BatchRef, type BatchResult, type Client, type ClientOptions, type Facet, type FilterInput, type Histogram, type HistogramBucket, type ListPage, type ListParams, type Meta, type MetaResult, PreconditionFailedError, type ProblemDetails, type ProblemError, type RecordOf, type RecordPermissions, type ResourcePermissions, type ResourceRef, type RuntimeClient, type RuntimeClientOptions, type RuntimePolicy, type RuntimeStatus, type Series, type SeriesParams, type SeriesPoint, type SetupStatus, type Stored, createAssistantClient, createAuthSession, createClient, createRuntimeClient, createStaticSession, filterText, isApiError, listWire, tokenExpiry };
15
+ export { type AccountSecurity, type AccountSignIn, ApiError, type AssistantClient, type AssistantClientOptions, type AssistantConnection, AuthError, type AuthSession, type AuthSessionOptions, type AuthUser, type AuthenticatorSetup, type BatchOp, type BatchRef, type BatchResult, type Client, type ClientOptions, type Facet, type FilterInput, type Histogram, type HistogramBucket, type ListPage, type ListParams, type Meta, type MetaResult, type Passkey, PreconditionFailedError, type ProblemDetails, type ProblemError, type RecordOf, type RecordPermissions, type RequiredSetup, type ResourcePermissions, type ResourceRef, type RuntimeClient, type RuntimeClientOptions, type RuntimePolicy, type RuntimeStatus, type Series, type SeriesParams, type SeriesPoint, type SetupStatus, type SignInMethod, type SignInPolicy, type SignInPolicyClient, type SignInPolicyState, type SignInResult, type SignInRule, type StaffAccessRule, type StaffSignIn, type StaffSignInClient, type Stored, type TwoFactorMethod, createAssistantClient, createAuthSession, createClient, createRuntimeClient, createStaticSession, filterText, isApiError, listWire, tokenExpiry };
package/dist/index.js CHANGED
@@ -1,7 +1,9 @@
1
1
  import { filterText, listWire } from "./query-string.js";
2
2
  import { ApiError, PreconditionFailedError, isApiError } from "./problem.js";
3
3
  import { createClient } from "./client.js";
4
- import { AuthError, createAuthSession, createStaticSession, tokenExpiry } from "./auth.js";
4
+ import { AuthError } from "./auth-error.js";
5
+ import { createAuthSession, tokenExpiry } from "./auth.js";
6
+ import { createStaticSession } from "./static-session.js";
5
7
  import { createAssistantClient } from "./assistant.js";
6
8
  import { createRuntimeClient } from "./runtime.js";
7
9
  export { ApiError, AuthError, PreconditionFailedError, createAssistantClient, createAuthSession, createClient, createRuntimeClient, createStaticSession, filterText, isApiError, listWire, tokenExpiry };
@@ -0,0 +1,69 @@
1
+ import { authError } from "./auth-error.js";
2
+ //#region src/sign-in-flows.ts
3
+ /**
4
+ * The ways to sign in: a password, an emailed code or a passkey, and the second step after a password or a code for
5
+ * an account with two-factor authentication. `signedIn` runs once a session exists, to fetch the API token.
6
+ */
7
+ const signInFlows = (client, signedIn) => {
8
+ const finish = async (data) => {
9
+ if (data?.twoFactorRedirect) return {
10
+ kind: "two-factor",
11
+ methods: data.twoFactorMethods ?? []
12
+ };
13
+ await signedIn();
14
+ return {
15
+ kind: "signed-in",
16
+ user: data?.user
17
+ };
18
+ };
19
+ return {
20
+ signIn: async (email, password) => {
21
+ const { data, error } = await client.signIn.email({
22
+ email,
23
+ password
24
+ });
25
+ if (error || !data) throw authError(error, "Sign-in failed");
26
+ return finish(data);
27
+ },
28
+ /** Emails a sign-in code when an account has this address; the answer is the same either way. */
29
+ sendSignInCode: async (email) => {
30
+ const { error } = await client.emailOtp.sendVerificationOtp({
31
+ email,
32
+ type: "sign-in"
33
+ });
34
+ if (error) throw authError(error, "Could not send the code");
35
+ },
36
+ signInWithCode: async (email, code) => {
37
+ const { data, error } = await client.signIn.emailOtp({
38
+ email,
39
+ otp: code
40
+ });
41
+ if (error || !data) throw authError(error, "Sign-in failed");
42
+ return finish(data);
43
+ },
44
+ /** Asks the browser for one of the person's passkeys for this site. */
45
+ signInWithPasskey: async () => {
46
+ const { data, error } = await client.signIn.passkey();
47
+ if (error || !data) throw authError(error, "Sign-in failed");
48
+ await signedIn();
49
+ return data.user;
50
+ },
51
+ /** Emails the code for the second step, to the address of the account signing in. */
52
+ sendTwoFactorCode: async () => {
53
+ const { error } = await client.twoFactor.sendOtp();
54
+ if (error) throw authError(error, "Could not send the code");
55
+ },
56
+ /** Finishes a sign-in with the second step. `trustDevice` skips it in this browser for 30 days. */
57
+ verifyTwoFactor: async ({ method, code, trustDevice = false }) => {
58
+ const { data, error } = await (method === "totp" ? client.twoFactor.verifyTotp : method === "otp" ? client.twoFactor.verifyOtp : client.twoFactor.verifyBackupCode)({
59
+ code,
60
+ trustDevice
61
+ });
62
+ if (error || !data) throw authError(error, "The code did not work");
63
+ await signedIn();
64
+ return data.user;
65
+ }
66
+ };
67
+ };
68
+ //#endregion
69
+ export { signInFlows };
@@ -0,0 +1,37 @@
1
+ import { BetterAuthClient } from "./better-auth-client.js";
2
+ //#region src/sign-in-policy.d.ts
3
+ export type SignInRule = 'allowed' | 'required' | 'forbidden';
4
+ /** Whether the operator's staff may sign in as people: yes, yes and the person gets an email, or no. */
5
+ export type StaffAccessRule = 'allowed' | 'notify' | 'forbidden';
6
+ /**
7
+ * How people may sign in, as the server stores it: passwords and emailed codes are allowed or forbidden, passkeys and
8
+ * two-factor authentication can also be required (everyone without one is asked to set it up), and staff of the
9
+ * operator may sign in as people, with or without telling them, or not.
10
+ */
11
+ export type SignInPolicy = {
12
+ password: 'allowed' | 'forbidden';
13
+ emailCode: 'allowed' | 'forbidden';
14
+ passkey: SignInRule;
15
+ twoFactor: SignInRule;
16
+ staffAccess: StaffAccessRule;
17
+ };
18
+ /**
19
+ * The saved policy, how it applies (`effective`: emailed codes need mail, and without mail passwords stay on and staff
20
+ * who would have to tell the person cannot sign in), the name of the operator provider when staff can sign in at all,
21
+ * and who saved it when.
22
+ */
23
+ export type SignInPolicyState = {
24
+ policy: SignInPolicy;
25
+ effective: SignInPolicy;
26
+ mail: boolean;
27
+ operator?: string;
28
+ savedAt?: string;
29
+ savedBy?: string;
30
+ };
31
+ /** Reading and saving the sign-in policy, for admins. Saving rejects with `AuthError` saying why a policy cannot be saved. */
32
+ export declare const signInPolicyClient: (client: BetterAuthClient) => {
33
+ read: () => Promise<SignInPolicyState>;
34
+ save: (policy: SignInPolicy) => Promise<SignInPolicyState>;
35
+ };
36
+ export type SignInPolicyClient = ReturnType<typeof signInPolicyClient>;
37
+ //#endregion
@@ -0,0 +1,20 @@
1
+ import { authError } from "./auth-error.js";
2
+ //#region src/sign-in-policy.ts
3
+ /** Reading and saving the sign-in policy, for admins. Saving rejects with `AuthError` saying why a policy cannot be saved. */
4
+ const signInPolicyClient = (client) => ({
5
+ read: async () => {
6
+ const { data, error } = await client.$fetch("/policy/sign-in");
7
+ if (error || !data) throw authError(error, "Could not read the sign-in policy");
8
+ return data;
9
+ },
10
+ save: async (policy) => {
11
+ const { data, error } = await client.$fetch("/policy/sign-in", {
12
+ method: "POST",
13
+ body: policy
14
+ });
15
+ if (error || !data) throw authError(error, "Could not save the sign-in policy");
16
+ return data;
17
+ }
18
+ });
19
+ //#endregion
20
+ export { signInPolicyClient };
@@ -0,0 +1,32 @@
1
+ import { BetterAuthClient } from "./better-auth-client.js";
2
+ //#region src/staff-sign-in.d.ts
3
+ /** A staff sign-in as someone: who, as whom (`user`), why, and when it started and ends (or ended). */
4
+ export type StaffSignIn = {
5
+ id: string;
6
+ user: string;
7
+ staff: string;
8
+ staffName?: string;
9
+ reason: string;
10
+ startedAt: string;
11
+ expiresAt: string;
12
+ endedAt?: string;
13
+ };
14
+ /**
15
+ * Staff of the operator signing in as a person, for support. `start` answers the operator provider's URL, which sends
16
+ * the browser back to `callbackURL` signed in as the person, or with `?staff-error=<code>`. Each call rejects with `AuthError`.
17
+ */
18
+ export declare const staffSignInClient: (client: BetterAuthClient) => {
19
+ start: (input: {
20
+ email: string;
21
+ reason: string;
22
+ callbackURL: string;
23
+ }) => Promise<string>;
24
+ /** The staff sign-in behind this session, or `undefined` when the person signed in themselves. */
25
+ current: () => Promise<StaffSignIn | undefined>;
26
+ /** Ends the staff session; the browser is signed out. */
27
+ stop: () => Promise<void>;
28
+ /** For admins: the log of staff sign-ins, newest first. */
29
+ log: () => Promise<StaffSignIn[]>;
30
+ };
31
+ export type StaffSignInClient = ReturnType<typeof staffSignInClient>;
32
+ //#endregion
@@ -0,0 +1,45 @@
1
+ import { authError } from "./auth-error.js";
2
+ //#region src/staff-sign-in.ts
3
+ const iso = (value) => new Date(value).toISOString();
4
+ const entry = ({ startedAt, expiresAt, endedAt, ...rest }) => ({
5
+ ...rest,
6
+ startedAt: iso(startedAt),
7
+ expiresAt: iso(expiresAt),
8
+ ...endedAt && { endedAt: iso(endedAt) }
9
+ });
10
+ /**
11
+ * Staff of the operator signing in as a person, for support. `start` answers the operator provider's URL, which sends
12
+ * the browser back to `callbackURL` signed in as the person, or with `?staff-error=<code>`. Each call rejects with `AuthError`.
13
+ */
14
+ const staffSignInClient = (client) => ({
15
+ start: async (input) => {
16
+ const { data, error } = await client.$fetch("/staff/sign-in", {
17
+ method: "POST",
18
+ body: input
19
+ });
20
+ if (error || !data?.url) throw authError(error, "Could not start the staff sign-in");
21
+ return data.url;
22
+ },
23
+ /** The staff sign-in behind this session, or `undefined` when the person signed in themselves. */
24
+ current: async () => {
25
+ const { data, error } = await client.$fetch("/staff/session");
26
+ if (error || !data) throw authError(error, "Could not read the session");
27
+ return data.staff ? entry(data.staff) : void 0;
28
+ },
29
+ /** Ends the staff session; the browser is signed out. */
30
+ stop: async () => {
31
+ const { error } = await client.$fetch("/staff/stop", {
32
+ method: "POST",
33
+ body: {}
34
+ });
35
+ if (error) throw authError(error, "Could not end the staff session");
36
+ },
37
+ /** For admins: the log of staff sign-ins, newest first. */
38
+ log: async () => {
39
+ const { data, error } = await client.$fetch("/staff/sign-ins");
40
+ if (error || !data) throw authError(error, "Could not read the staff sign-ins");
41
+ return data.signIns.map(entry);
42
+ }
43
+ });
44
+ //#endregion
45
+ export { staffSignInClient };
@@ -0,0 +1,10 @@
1
+ import { AuthUser } from "./auth-types.js";
2
+ import { AuthSession } from "./auth.js";
3
+ //#region src/static-session.d.ts
4
+ /**
5
+ * A session that is already signed in with a token you hold, for stories and scripts (`protobase token <email>`).
6
+ * It never refreshes, so use a token that outlives the run. Its account has nothing to set up, and it cannot change
7
+ * passkeys, two-factor authentication or the sign-in policy, and is never a staff session.
8
+ */
9
+ export declare const createStaticSession: (token: string, user?: AuthUser) => AuthSession;
10
+ //#endregion
@@ -0,0 +1,81 @@
1
+ import { AuthError } from "./auth-error.js";
2
+ //#region src/static-session.ts
3
+ const unsupported = (what) => async () => {
4
+ throw new AuthError(`A static session cannot ${what}`, 400);
5
+ };
6
+ /**
7
+ * A session that is already signed in with a token you hold, for stories and scripts (`protobase token <email>`).
8
+ * It never refreshes, so use a token that outlives the run. Its account has nothing to set up, and it cannot change
9
+ * passkeys, two-factor authentication or the sign-in policy, and is never a staff session.
10
+ */
11
+ const createStaticSession = (token, user = {
12
+ id: "token",
13
+ email: "token",
14
+ name: "API token",
15
+ role: null
16
+ }) => ({
17
+ token: async () => token,
18
+ status: async () => ({
19
+ needsAdmin: false,
20
+ signInMethods: ["password"],
21
+ passwordReset: false,
22
+ socialProviders: []
23
+ }),
24
+ session: async () => user,
25
+ signIn: async () => ({
26
+ kind: "signed-in",
27
+ user
28
+ }),
29
+ sendSignInCode: async () => void 0,
30
+ signInWithCode: async () => ({
31
+ kind: "signed-in",
32
+ user
33
+ }),
34
+ signInWithPasskey: async () => user,
35
+ sendTwoFactorCode: async () => void 0,
36
+ verifyTwoFactor: async () => user,
37
+ signInSocial: unsupported("sign in with a provider"),
38
+ signOut: async () => void 0,
39
+ requestPasswordReset: async () => void 0,
40
+ resetPassword: async () => void 0,
41
+ account: {
42
+ signInMethods: async () => ({
43
+ policy: {
44
+ password: "allowed",
45
+ emailCode: "allowed",
46
+ passkey: "allowed",
47
+ twoFactor: "allowed",
48
+ staffAccess: "allowed"
49
+ },
50
+ mail: false,
51
+ account: {
52
+ password: false,
53
+ passkeys: 0,
54
+ twoFactor: false,
55
+ authenticatorApp: false
56
+ },
57
+ missing: []
58
+ }),
59
+ passkeys: async () => [],
60
+ addPasskey: unsupported("add a passkey"),
61
+ renamePasskey: unsupported("rename a passkey"),
62
+ removePasskey: unsupported("remove a passkey"),
63
+ startAuthenticatorApp: unsupported("turn on two-factor authentication"),
64
+ confirmAuthenticatorApp: unsupported("turn on two-factor authentication"),
65
+ turnOnEmailedCodes: unsupported("turn on two-factor authentication"),
66
+ turnOffTwoFactor: unsupported("turn off two-factor authentication"),
67
+ newBackupCodes: unsupported("make backup codes")
68
+ },
69
+ signInPolicy: {
70
+ read: unsupported("read the sign-in policy"),
71
+ save: unsupported("save the sign-in policy")
72
+ },
73
+ staff: {
74
+ start: unsupported("start a staff sign-in"),
75
+ current: async () => void 0,
76
+ stop: unsupported("end a staff session"),
77
+ log: unsupported("read the staff sign-ins")
78
+ }
79
+ });
80
+ //#endregion
81
+ export { createStaticSession };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@protobase/client",
3
- "version": "0.3.5",
3
+ "version": "0.4.0",
4
4
  "description": "Typed fetch client for the Protobase REST API.",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -29,8 +29,9 @@
29
29
  "access": "public"
30
30
  },
31
31
  "dependencies": {
32
- "@protobase/layout": "0.3.5",
33
- "@protobase/schema": "0.3.5",
32
+ "@better-auth/passkey": "^1.7.7",
33
+ "@protobase/layout": "0.4.0",
34
+ "@protobase/schema": "0.4.0",
34
35
  "better-auth": "^1.7.7"
35
36
  }
36
37
  }