@revojs/auth 0.2.8 → 0.2.9

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.
Files changed (42) hide show
  1. package/dist/index.d.ts +167 -16
  2. package/dist/index.js +232 -33
  3. package/dist/module/index.d.ts +1 -0
  4. package/dist/module/index.js +55 -52
  5. package/dist/organization/routes/auth/invitations/accept/post.d.ts +4 -0
  6. package/dist/organization/routes/auth/invitations/accept/post.js +46 -0
  7. package/dist/organization/routes/auth/organizations/[organizationId]/get.d.ts +4 -0
  8. package/dist/organization/routes/auth/organizations/[organizationId]/get.js +14 -0
  9. package/dist/organization/routes/auth/organizations/[organizationId]/invitations/[invitationId]/delete.d.ts +4 -0
  10. package/dist/organization/routes/auth/organizations/[organizationId]/invitations/[invitationId]/delete.js +34 -0
  11. package/dist/organization/routes/auth/organizations/[organizationId]/invitations/get.d.ts +4 -0
  12. package/dist/organization/routes/auth/organizations/[organizationId]/invitations/get.js +22 -0
  13. package/dist/organization/routes/auth/organizations/[organizationId]/invitations/post.d.ts +4 -0
  14. package/dist/organization/routes/auth/organizations/[organizationId]/invitations/post.js +56 -0
  15. package/dist/organization/routes/auth/organizations/[organizationId]/memberships/[membershipId]/delete.d.ts +4 -0
  16. package/dist/organization/routes/auth/organizations/[organizationId]/memberships/[membershipId]/delete.js +30 -0
  17. package/dist/organization/routes/auth/organizations/[organizationId]/memberships/[membershipId]/patch.d.ts +4 -0
  18. package/dist/organization/routes/auth/organizations/[organizationId]/memberships/[membershipId]/patch.js +35 -0
  19. package/dist/organization/routes/auth/organizations/[organizationId]/memberships/get.d.ts +4 -0
  20. package/dist/organization/routes/auth/organizations/[organizationId]/memberships/get.js +14 -0
  21. package/dist/organization/routes/auth/organizations/[organizationId]/ownership/post.d.ts +4 -0
  22. package/dist/organization/routes/auth/organizations/[organizationId]/ownership/post.js +38 -0
  23. package/dist/organization/routes/auth/organizations/[organizationId]/patch.d.ts +4 -0
  24. package/dist/organization/routes/auth/organizations/[organizationId]/patch.js +36 -0
  25. package/dist/organization/routes/auth/organizations/[organizationId]/traces/get.d.ts +4 -0
  26. package/dist/organization/routes/auth/organizations/[organizationId]/traces/get.js +26 -0
  27. package/dist/organization/routes/auth/organizations/get.d.ts +4 -0
  28. package/dist/organization/routes/auth/organizations/get.js +11 -0
  29. package/dist/organization/routes/auth/organizations/post.d.ts +4 -0
  30. package/dist/organization/routes/auth/organizations/post.js +40 -0
  31. package/dist/routes/auth/+middleware.d.ts +4 -0
  32. package/dist/routes/auth/+middleware.js +9 -0
  33. package/dist/routes/auth/sessions/delete.js +2 -3
  34. package/dist/routes/auth/sessions/get.js +3 -5
  35. package/dist/routes/auth/sessions/post.js +4 -6
  36. package/dist/storage/mysql.d.ts +272 -0
  37. package/dist/storage/mysql.js +184 -0
  38. package/dist/storage/postgresql.d.ts +272 -0
  39. package/dist/storage/postgresql.js +184 -0
  40. package/dist/storage/sqlite.d.ts +272 -0
  41. package/dist/storage/sqlite.js +184 -0
  42. package/package.json +15 -1
package/dist/index.d.ts CHANGED
@@ -8,6 +8,60 @@ export type PasskeyMethod = InferInput<typeof passkeyMethodSchema>;
8
8
  export type ProviderMethod = InferInput<typeof providerMethodSchema>;
9
9
  export type Method = InferInput<typeof methodSchema>;
10
10
  export type Providers = "apple" | "github" | "google" | "microsoft";
11
+ export type MembershipStatus = "active" | "suspended";
12
+ export type InvitationStatus = "pending" | "accepted" | "revoked";
13
+ export type TraceAction = "organization.create" | "organization.update" | "organization.transferOwnership" | "membership.active" | "membership.suspended" | "membership.remove" | "invitation.create" | "invitation.accept" | "invitation.revoke";
14
+ export type TraceCursor = Pick<Trace, "createdAt" | "id">;
15
+ export type AuthStorage = AccountStorage & OrganizationStorage;
16
+ export interface Account {
17
+ id: string;
18
+ email: string;
19
+ password: string | null;
20
+ createdAt: Date;
21
+ }
22
+ export interface Identity {
23
+ id: string;
24
+ provider: string;
25
+ credential: string;
26
+ createdAt: Date;
27
+ accountId: string;
28
+ }
29
+ export interface Session {
30
+ id: string;
31
+ createdAt: Date;
32
+ accountId: string;
33
+ }
34
+ export interface AccountStorage {
35
+ getAccountByEmail: (email: string) => Promise<Account | undefined>;
36
+ getAccountById: (id: string) => Promise<Account | undefined>;
37
+ createAccount: (account: Account) => Promise<Account | undefined>;
38
+ deleteAccount: (id: string) => Promise<void>;
39
+ getIdentity: (provider: string, credential: string) => Promise<Identity | undefined>;
40
+ createIdentity: (identity: Identity) => Promise<Identity | undefined>;
41
+ getSession: (id: string, accountId: string) => Promise<Session | undefined>;
42
+ createSession: (session: Session) => Promise<Session | undefined>;
43
+ deleteSession: (id: string, accountId: string) => Promise<void>;
44
+ }
45
+ export interface OrganizationStorage {
46
+ transaction: <T>(run: (storage: AuthStorage) => Promise<T>) => Promise<T>;
47
+ getOrganization: (id: string) => Promise<Organization | undefined>;
48
+ listOrganizations: (accountId: string) => Promise<Array<Organization>>;
49
+ createOrganization: (organization: Organization) => Promise<void>;
50
+ updateOrganization: (id: string, values: Pick<Organization, "name" | "accountId">) => Promise<void>;
51
+ getMembership: (organizationId: string, accountId: string) => Promise<Membership | undefined>;
52
+ getMembershipById: (organizationId: string, id: string) => Promise<Membership | undefined>;
53
+ listMemberships: (organizationId: string) => Promise<Array<Membership>>;
54
+ createMembership: (membership: Membership) => Promise<void>;
55
+ updateMembership: (organizationId: string, id: string, status: MembershipStatus) => Promise<void>;
56
+ deleteMembership: (organizationId: string, id: string) => Promise<void>;
57
+ getInvitation: (organizationId: string, id: string) => Promise<Invitation | undefined>;
58
+ getInvitationByHash: (hash: string) => Promise<Invitation | undefined>;
59
+ listInvitations: (organizationId: string) => Promise<Array<Invitation>>;
60
+ createInvitation: (invitation: Invitation) => Promise<void>;
61
+ updateInvitation: (organizationId: string, id: string, status: InvitationStatus) => Promise<void>;
62
+ createTrace: (trace: Trace) => Promise<void>;
63
+ listTraces: (organizationId: string, limit: number, before?: TraceCursor) => Promise<Array<Trace>>;
64
+ }
11
65
  export interface Token {
12
66
  access_token: string;
13
67
  token_type: string;
@@ -50,28 +104,125 @@ export interface AuthProviderOptions {
50
104
  export interface AuthProvider {
51
105
  setup: (scope: Scope) => AuthProviderOptions;
52
106
  }
53
- export declare function useAuth(scope: Scope): {
107
+ export interface Organization {
108
+ id: string;
109
+ name: string;
110
+ accountId: string;
111
+ createdAt: Date;
112
+ }
113
+ export interface Membership {
114
+ id: string;
115
+ organizationId: string;
116
+ accountId: string;
117
+ status: MembershipStatus;
118
+ createdAt: Date;
119
+ }
120
+ export interface Invitation {
121
+ id: string;
122
+ organizationId: string;
123
+ email: string;
124
+ tokenHash: string;
125
+ invitedBy: string;
126
+ status: InvitationStatus;
127
+ expiresAt: Date;
128
+ createdAt: Date;
129
+ }
130
+ export interface Trace {
131
+ id: string;
132
+ organizationId: string;
133
+ accountId: string;
134
+ action: TraceAction;
135
+ subjectId: string;
136
+ content: string;
137
+ createdAt: Date;
138
+ }
139
+ export declare function useClientAuth(scope: Scope): {
54
140
  signInWithCredentials(credential: PasswordMethod | PasskeyMethod): Promise<unknown>;
55
141
  signInWithProvider(provider: Providers | (string & {}), redirectUrl: string): Promise<void>;
56
142
  signOut(): Promise<unknown>;
57
143
  };
58
- export declare function requireSession<T>(scope: Scope, redirectUrl: string): Promise<T>;
144
+ export declare function requireSession(scope: Scope, redirectUrl?: string): Promise<Session>;
59
145
  export declare function getCryptoKey(scope: Scope): Promise<CryptoKey>;
60
- export declare function getSession<T>(scope: Scope): Promise<T | undefined>;
61
- export declare function setSession<T>(scope: Scope, session: T): Promise<void>;
146
+ export declare function getSession(scope: Scope): Promise<Session | undefined>;
147
+ export declare function setSession(scope: Scope, session: Session): Promise<void>;
62
148
  export declare function clearSession(scope: Scope): void;
63
149
  export declare function defineAuthProvider(provider: AuthProvider): Route;
64
- export declare const AUTHORIZE_HOOK: import("revojs").Descriptor<(method: Method) => Awaitable<boolean>>;
65
- export declare const GET_PRINCIPAL_HOOK: import("revojs").Descriptor<(method: Method) => Awaitable<Principal | undefined>>;
66
- export declare const CREATE_PRINCIPAL_HOOK: import("revojs").Descriptor<(method: Method) => Awaitable<Principal | undefined>>;
67
- export declare const CREATE_SESSION_HOOK: import("revojs").Descriptor<(principal: Principal) => Awaitable<unknown>>;
68
- export declare const DELETE_SESSION_HOOK: import("revojs").Descriptor<(session: any) => Awaitable<unknown>>;
150
+ export declare function useServerAuth(scope: Scope): Promise<{
151
+ getAccountByEmail: (email: string) => Promise<Account | undefined>;
152
+ getAccountById: (id: string) => Promise<Account | undefined>;
153
+ createAccount: (account: Account) => Promise<Account | undefined>;
154
+ deleteAccount: (id: string) => Promise<void>;
155
+ getIdentity: (provider: string, credential: string) => Promise<Identity | undefined>;
156
+ createIdentity: (identity: Identity) => Promise<Identity | undefined>;
157
+ getSession: (id: string, accountId: string) => Promise<Session | undefined>;
158
+ createSession: (session: Session) => Promise<Session | undefined>;
159
+ deleteSession: (id: string, accountId: string) => Promise<void>;
160
+ transaction: <T>(run: (storage: AuthStorage) => Promise<T>) => Promise<T>;
161
+ getOrganization: (id: string) => Promise<Organization | undefined>;
162
+ listOrganizations: (accountId: string) => Promise<Array<Organization>>;
163
+ createOrganization: (organization: Organization) => Promise<void>;
164
+ updateOrganization: (id: string, values: Pick<Organization, "name" | "accountId">) => Promise<void>;
165
+ getMembership: (organizationId: string, accountId: string) => Promise<Membership | undefined>;
166
+ getMembershipById: (organizationId: string, id: string) => Promise<Membership | undefined>;
167
+ listMemberships: (organizationId: string) => Promise<Array<Membership>>;
168
+ createMembership: (membership: Membership) => Promise<void>;
169
+ updateMembership: (organizationId: string, id: string, status: MembershipStatus) => Promise<void>;
170
+ deleteMembership: (organizationId: string, id: string) => Promise<void>;
171
+ getInvitation: (organizationId: string, id: string) => Promise<Invitation | undefined>;
172
+ getInvitationByHash: (hash: string) => Promise<Invitation | undefined>;
173
+ listInvitations: (organizationId: string) => Promise<Array<Invitation>>;
174
+ createInvitation: (invitation: Invitation) => Promise<void>;
175
+ updateInvitation: (organizationId: string, id: string, status: InvitationStatus) => Promise<void>;
176
+ createTrace: (trace: Trace) => Promise<void>;
177
+ listTraces: (organizationId: string, limit: number, before?: TraceCursor) => Promise<Array<Trace>>;
178
+ }>;
179
+ export declare function useAccountStorage(scope: Scope): Promise<AccountStorage>;
180
+ export declare function useOrganizationStorage(scope: Scope): Promise<OrganizationStorage>;
181
+ export declare function getPrincipal(scope: Scope, method: Method): Promise<Principal | false | undefined>;
182
+ export declare function createPrincipal(scope: Scope, method: Method): Promise<Principal | undefined>;
183
+ export declare function createSession(scope: Scope, principal: Principal): Promise<Session | undefined>;
184
+ export declare const authIdSchema: import("valibot").SchemaWithPipe<readonly [import("valibot").StringSchema<undefined>, import("valibot").MinLengthAction<string, 1, undefined>, import("valibot").MaxLengthAction<string, 128, undefined>]>;
185
+ export declare const organizationNameSchema: import("valibot").SchemaWithPipe<readonly [import("valibot").StringSchema<undefined>, import("valibot").MaxLengthAction<string, 200, undefined>, import("valibot").TrimAction, import("valibot").MinLengthAction<string, 1, undefined>]>;
186
+ export declare const organizationParametersSchema: import("valibot").ObjectSchema<{
187
+ readonly organizationId: import("valibot").SchemaWithPipe<readonly [import("valibot").StringSchema<undefined>, import("valibot").MinLengthAction<string, 1, undefined>, import("valibot").MaxLengthAction<string, 128, undefined>]>;
188
+ }, undefined>;
189
+ export declare const membershipParametersSchema: import("valibot").ObjectSchema<{
190
+ readonly organizationId: import("valibot").SchemaWithPipe<readonly [import("valibot").StringSchema<undefined>, import("valibot").MinLengthAction<string, 1, undefined>, import("valibot").MaxLengthAction<string, 128, undefined>]>;
191
+ readonly membershipId: import("valibot").SchemaWithPipe<readonly [import("valibot").StringSchema<undefined>, import("valibot").MinLengthAction<string, 1, undefined>, import("valibot").MaxLengthAction<string, 128, undefined>]>;
192
+ }, undefined>;
193
+ export declare const BEFORE_PRINCIPAL_GET_HOOK: import("revojs").Descriptor<(method: Readonly<Method>) => Awaitable<void | boolean>>;
194
+ export declare const AFTER_PRINCIPAL_GET_HOOK: import("revojs").Descriptor<(principal: Readonly<Principal>, method: Readonly<Method>) => Awaitable<void>>;
195
+ export declare const BEFORE_PRINCIPAL_CREATE_HOOK: import("revojs").Descriptor<(method: Readonly<Method>) => Awaitable<void | boolean>>;
196
+ export declare const AFTER_PRINCIPAL_CREATE_HOOK: import("revojs").Descriptor<(principal: Readonly<Principal>, method: Readonly<Method>) => Awaitable<void>>;
197
+ export declare const BEFORE_ACCOUNT_GET_HOOK: import("revojs").Descriptor<(field: "id" | "email", value: string) => Awaitable<void | boolean>>;
198
+ export declare const AFTER_ACCOUNT_GET_HOOK: import("revojs").Descriptor<(account: Readonly<Account>) => Awaitable<void>>;
199
+ export declare const BEFORE_IDENTITY_GET_HOOK: import("revojs").Descriptor<(provider: string, credential: string) => Awaitable<void | boolean>>;
200
+ export declare const AFTER_IDENTITY_GET_HOOK: import("revojs").Descriptor<(identity: Readonly<Identity>) => Awaitable<void>>;
201
+ export declare const BEFORE_SESSION_GET_HOOK: import("revojs").Descriptor<(id: string, accountId: string) => Awaitable<void | boolean>>;
202
+ export declare const AFTER_SESSION_GET_HOOK: import("revojs").Descriptor<(session: Readonly<Session>) => Awaitable<void>>;
203
+ export declare const BEFORE_ACCOUNT_CREATE_HOOK: import("revojs").Descriptor<(account: Readonly<Account>, method: Readonly<Method>) => Awaitable<void | boolean | Record<string, unknown>>>;
204
+ export declare const AFTER_ACCOUNT_CREATE_HOOK: import("revojs").Descriptor<(account: Readonly<Account>) => Awaitable<void>>;
205
+ export declare const BEFORE_IDENTITY_CREATE_HOOK: import("revojs").Descriptor<(identity: Readonly<Identity>, method: Readonly<Method>) => Awaitable<void | boolean | Record<string, unknown>>>;
206
+ export declare const AFTER_IDENTITY_CREATE_HOOK: import("revojs").Descriptor<(identity: Readonly<Identity>) => Awaitable<void>>;
207
+ export declare const BEFORE_SESSION_CREATE_HOOK: import("revojs").Descriptor<(session: Readonly<Session>, principal: Readonly<Principal>) => Awaitable<void | boolean | Record<string, unknown>>>;
208
+ export declare const AFTER_SESSION_CREATE_HOOK: import("revojs").Descriptor<(session: Readonly<Session>) => Awaitable<void>>;
69
209
  export declare const registerAuthHooks: (scope: Scope, hooks: Partial<import("revojs").Hooks<{
70
- authorize: import("revojs").Descriptor<(method: Method) => Awaitable<boolean>>;
71
- getPrincipal: import("revojs").Descriptor<(method: Method) => Awaitable<Principal | undefined>>;
72
- createPrincipal: import("revojs").Descriptor<(method: Method) => Awaitable<Principal | undefined>>;
73
- createSession: import("revojs").Descriptor<(principal: Principal) => Awaitable<unknown>>;
74
- deleteSession: import("revojs").Descriptor<(session: any) => Awaitable<unknown>>;
210
+ beforePrincipalGet: import("revojs").Descriptor<(method: Readonly<Method>) => Awaitable<void | boolean>>;
211
+ afterPrincipalGet: import("revojs").Descriptor<(principal: Readonly<Principal>, method: Readonly<Method>) => Awaitable<void>>;
212
+ beforePrincipalCreate: import("revojs").Descriptor<(method: Readonly<Method>) => Awaitable<void | boolean>>;
213
+ afterPrincipalCreate: import("revojs").Descriptor<(principal: Readonly<Principal>, method: Readonly<Method>) => Awaitable<void>>;
214
+ beforeAccountGet: import("revojs").Descriptor<(field: "id" | "email", value: string) => Awaitable<void | boolean>>;
215
+ afterAccountGet: import("revojs").Descriptor<(account: Readonly<Account>) => Awaitable<void>>;
216
+ beforeIdentityGet: import("revojs").Descriptor<(provider: string, credential: string) => Awaitable<void | boolean>>;
217
+ afterIdentityGet: import("revojs").Descriptor<(identity: Readonly<Identity>) => Awaitable<void>>;
218
+ beforeSessionGet: import("revojs").Descriptor<(id: string, accountId: string) => Awaitable<void | boolean>>;
219
+ afterSessionGet: import("revojs").Descriptor<(session: Readonly<Session>) => Awaitable<void>>;
220
+ beforeAccountCreate: import("revojs").Descriptor<(account: Readonly<Account>, method: Readonly<Method>) => Awaitable<void | boolean | Record<string, unknown>>>;
221
+ afterAccountCreate: import("revojs").Descriptor<(account: Readonly<Account>) => Awaitable<void>>;
222
+ beforeIdentityCreate: import("revojs").Descriptor<(identity: Readonly<Identity>, method: Readonly<Method>) => Awaitable<void | boolean | Record<string, unknown>>>;
223
+ afterIdentityCreate: import("revojs").Descriptor<(identity: Readonly<Identity>) => Awaitable<void>>;
224
+ beforeSessionCreate: import("revojs").Descriptor<(session: Readonly<Session>, principal: Readonly<Principal>) => Awaitable<void | boolean | Record<string, unknown>>>;
225
+ afterSessionCreate: import("revojs").Descriptor<(session: Readonly<Session>) => Awaitable<void>>;
75
226
  }>>) => void;
76
227
  export declare const principalSchema: import("valibot").ObjectSchema<{
77
228
  readonly sub: import("valibot").StringSchema<undefined>;
@@ -86,7 +237,7 @@ export declare const passwordMethodSchema: import("valibot").ObjectSchema<{
86
237
  readonly type: import("valibot").LiteralSchema<"PASSWORD", undefined>;
87
238
  readonly email: import("valibot").StringSchema<undefined>;
88
239
  readonly password: import("valibot").StringSchema<undefined>;
89
- readonly register: import("valibot").OptionalSchema<import("valibot").BooleanSchema<undefined>, true>;
240
+ readonly register: import("valibot").OptionalSchema<import("valibot").BooleanSchema<undefined>, false>;
90
241
  }, undefined>;
91
242
  export declare const passkeyMethodSchema: import("valibot").ObjectSchema<{
92
243
  readonly type: import("valibot").LiteralSchema<"PASSKEY", undefined>;
@@ -109,7 +260,7 @@ export declare const methodSchema: import("valibot").UnionSchema<[import("valibo
109
260
  readonly type: import("valibot").LiteralSchema<"PASSWORD", undefined>;
110
261
  readonly email: import("valibot").StringSchema<undefined>;
111
262
  readonly password: import("valibot").StringSchema<undefined>;
112
- readonly register: import("valibot").OptionalSchema<import("valibot").BooleanSchema<undefined>, true>;
263
+ readonly register: import("valibot").OptionalSchema<import("valibot").BooleanSchema<undefined>, false>;
113
264
  }, undefined>, import("valibot").ObjectSchema<{
114
265
  readonly type: import("valibot").LiteralSchema<"PASSKEY", undefined>;
115
266
  }, undefined>, import("valibot").ObjectSchema<{
package/dist/index.js CHANGED
@@ -1,11 +1,12 @@
1
1
  import config from "#config/auth";
2
2
  import { isClient, isServer } from "#variables";
3
- import { deleteCookie, fetch, sendForbidden, sendRedirect, setCookie, useCookies, useHeaders, useQuery, useUrl, withQuery } from "@revojs/server";
4
- import { createRegisterHooks, defineHook, dispatchHook, dispatchHookSingle, useVariables } from "revojs";
3
+ import { deleteCookie, fetch, sendForbidden, sendRedirect, sendUnauthorized, setCookie, useCookies, useHeaders, useQuery, useUrl, withQuery } from "@revojs/server";
4
+ import { useStorageProvider } from "@revojs/storage";
5
+ import { createRegisterHooks, defineHook, dispatchHook, useVariables } from "revojs";
5
6
  import { mergeObjects } from "revojs/shared";
6
- import { boolean, literal, nullish, number, object, optional, parse, pipe, string, transform, union } from "valibot";
7
+ import { boolean, literal, maxLength, minLength, nullish, number, object, optional, parse, pipe, string, transform, trim, union } from "valibot";
7
8
  //#region src/index.ts
8
- function useAuth(scope) {
9
+ function useClientAuth(scope) {
9
10
  return {
10
11
  async signInWithCredentials(credential) {
11
12
  return await fetch(scope, `/auth/sessions`, {
@@ -23,21 +24,20 @@ function useAuth(scope) {
23
24
  };
24
25
  }
25
26
  async function requireSession(scope, redirectUrl) {
26
- if (isClient) {
27
+ if (isClient) try {
28
+ return await fetch(scope, "/auth/sessions", {
29
+ method: "GET",
30
+ headers: useHeaders(scope)
31
+ });
32
+ } catch (error) {
33
+ if (!redirectUrl) throw error;
27
34
  const { pathname } = useUrl(scope);
28
- try {
29
- return await fetch(scope, "/auth/sessions", {
30
- method: "GET",
31
- headers: useHeaders(scope)
32
- });
33
- } catch {
34
- if (redirectUrl !== pathname) globalThis.location.href = redirectUrl;
35
- }
35
+ if (redirectUrl !== pathname) globalThis.location.href = redirectUrl;
36
36
  }
37
37
  if (isServer) {
38
38
  const session = await getSession(scope);
39
39
  if (session) return session;
40
- throw sendRedirect(scope, redirectUrl);
40
+ throw redirectUrl ? sendRedirect(scope, redirectUrl) : sendUnauthorized(scope);
41
41
  }
42
42
  throw new Error("Session is unavailable");
43
43
  }
@@ -52,10 +52,21 @@ async function getSession(scope) {
52
52
  const session = useCookies(scope)[config.session.name];
53
53
  if (session) {
54
54
  const index = session.lastIndexOf(".");
55
- if (index > 0) try {
56
- const payload = session.slice(0, index);
57
- if (await crypto.subtle.verify("HMAC", await getCryptoKey(scope), Uint8Array.fromBase64(session.slice(index + 1), BASE64_VERIFY), Uint8Array.fromBase64(payload, BASE64_VERIFY))) return JSON.parse(decoder.decode(Uint8Array.fromBase64(payload, BASE64_VERIFY)));
58
- } catch {}
55
+ if (index > 0) {
56
+ let value;
57
+ try {
58
+ const payload = session.slice(0, index);
59
+ if (await crypto.subtle.verify("HMAC", await getCryptoKey(scope), Uint8Array.fromBase64(session.slice(index + 1), BASE64_VERIFY), Uint8Array.fromBase64(payload, BASE64_VERIFY))) value = JSON.parse(decoder.decode(Uint8Array.fromBase64(payload, BASE64_VERIFY)));
60
+ } catch {}
61
+ if (value) {
62
+ if ((await dispatchHook(scope, BEFORE_SESSION_GET_HOOK, value.id, value.accountId)).includes(false)) return;
63
+ const session = await (await useAccountStorage(scope)).getSession(value.id, value.accountId);
64
+ if (session && Number.isFinite(session.createdAt.getTime()) && (config.session.cookie.maxAge === void 0 || Date.now() < session.createdAt.getTime() + config.session.cookie.maxAge * 1e3)) {
65
+ await dispatchHook(scope, AFTER_SESSION_GET_HOOK, session);
66
+ return session;
67
+ }
68
+ }
69
+ }
59
70
  }
60
71
  }
61
72
  async function setSession(scope, session) {
@@ -114,10 +125,9 @@ function defineAuthProvider(provider) {
114
125
  ...options.userInfo.headers
115
126
  } }))
116
127
  };
117
- if ((await dispatchHook(scope, AUTHORIZE_HOOK, method)).includes(false)) return sendForbidden(scope);
118
- const principal = await dispatchHookSingle(scope, GET_PRINCIPAL_HOOK, method) ?? await dispatchHookSingle(scope, CREATE_PRINCIPAL_HOOK, method);
128
+ const principal = await getPrincipal(scope, method) ?? await createPrincipal(scope, method);
119
129
  if (principal) {
120
- const session = await dispatchHookSingle(scope, CREATE_SESSION_HOOK, principal);
130
+ const session = await createSession(scope, principal);
121
131
  if (session) {
122
132
  await setSession(scope, session);
123
133
  return sendRedirect(scope, flow.redirect);
@@ -155,17 +165,206 @@ function defineAuthProvider(provider) {
155
165
  return sendRedirect(scope, withQuery(scope, options.authorize.url, parameters));
156
166
  } };
157
167
  }
158
- var AUTHORIZE_HOOK = defineHook("AUTHORIZE_HOOK");
159
- var GET_PRINCIPAL_HOOK = defineHook("GET_PRINCIPAL_HOOK");
160
- var CREATE_PRINCIPAL_HOOK = defineHook("CREATE_PRINCIPAL_HOOK");
161
- var CREATE_SESSION_HOOK = defineHook("CREATE_SESSION_HOOK");
162
- var DELETE_SESSION_HOOK = defineHook("DELETE_SESSION_HOOK");
168
+ async function useServerAuth(scope) {
169
+ return {
170
+ ...await useAccountStorage(scope),
171
+ ...await useOrganizationStorage(scope)
172
+ };
173
+ }
174
+ async function useAccountStorage(scope) {
175
+ return useStorageProvider(scope, await Promise.all([
176
+ import("./storage/sqlite.js"),
177
+ import("./storage/postgresql.js"),
178
+ import("./storage/mysql.js")
179
+ ]), (provider) => provider.accountSchema).useAccountStorage(scope);
180
+ }
181
+ async function useOrganizationStorage(scope) {
182
+ if (!config.organizations) throw new Error("Organizations is disabled. Set auth.organizations to true to use Organizations storage.");
183
+ return useStorageProvider(scope, await Promise.all([
184
+ import("./storage/sqlite.js"),
185
+ import("./storage/postgresql.js"),
186
+ import("./storage/mysql.js")
187
+ ]), (provider) => provider.accountSchema).useOrganizationStorage(scope);
188
+ }
189
+ async function getPrincipal(scope, method) {
190
+ if (method.type === "PASSWORD") {
191
+ if ((await dispatchHook(scope, BEFORE_PRINCIPAL_GET_HOOK, method)).includes(false)) return false;
192
+ if ((await dispatchHook(scope, BEFORE_ACCOUNT_GET_HOOK, "email", method.email)).includes(false)) return false;
193
+ const account = await (await useAccountStorage(scope)).getAccountByEmail(method.email);
194
+ if (!account) return;
195
+ await dispatchHook(scope, AFTER_ACCOUNT_GET_HOOK, account);
196
+ if (account.password !== method.password) return;
197
+ const principal = {
198
+ sub: account.id,
199
+ email: account.email
200
+ };
201
+ await dispatchHook(scope, AFTER_PRINCIPAL_GET_HOOK, principal, method);
202
+ return principal;
203
+ } else if (method.type === "PROVIDER") {
204
+ if ((await dispatchHook(scope, BEFORE_PRINCIPAL_GET_HOOK, method)).includes(false)) return false;
205
+ if ((await dispatchHook(scope, BEFORE_IDENTITY_GET_HOOK, method.issuer, method.principal.sub)).includes(false)) return false;
206
+ const storage = await useAccountStorage(scope);
207
+ const identity = await storage.getIdentity(method.issuer, method.principal.sub);
208
+ if (!identity) return;
209
+ await dispatchHook(scope, AFTER_IDENTITY_GET_HOOK, identity);
210
+ if ((await dispatchHook(scope, BEFORE_ACCOUNT_GET_HOOK, "id", identity.accountId)).includes(false)) return false;
211
+ const account = await storage.getAccountById(identity.accountId);
212
+ if (!account) return;
213
+ await dispatchHook(scope, AFTER_ACCOUNT_GET_HOOK, account);
214
+ const principal = {
215
+ sub: account.id,
216
+ email: account.email
217
+ };
218
+ await dispatchHook(scope, AFTER_PRINCIPAL_GET_HOOK, principal, method);
219
+ return principal;
220
+ } else if (method.type === "PASSKEY") throw new Error("Passkey authentication is not implemented.");
221
+ }
222
+ async function createPrincipal(scope, method) {
223
+ if (method.type === "PASSWORD") {
224
+ if (!method.register) return;
225
+ if ((await dispatchHook(scope, BEFORE_PRINCIPAL_CREATE_HOOK, method)).includes(false)) return;
226
+ const storage = await useAccountStorage(scope);
227
+ if ((await dispatchHook(scope, BEFORE_ACCOUNT_GET_HOOK, "email", method.email)).includes(false)) return;
228
+ const existing = await storage.getAccountByEmail(method.email);
229
+ if (existing) {
230
+ await dispatchHook(scope, AFTER_ACCOUNT_GET_HOOK, existing);
231
+ return;
232
+ }
233
+ const account = {
234
+ id: crypto.randomUUID(),
235
+ email: method.email,
236
+ password: method.password,
237
+ createdAt: /* @__PURE__ */ new Date()
238
+ };
239
+ const beforeAccountCreate = await dispatchHook(scope, BEFORE_ACCOUNT_CREATE_HOOK, account, method);
240
+ if (beforeAccountCreate.includes(false)) return;
241
+ const accountFields = Object.keys(account);
242
+ for (const values of beforeAccountCreate) {
243
+ if (!values || typeof values !== "object") continue;
244
+ for (const key of Object.keys(values)) if (accountFields.includes(key)) throw new Error(`Auth account create values cannot replace field "${key}".`);
245
+ Object.assign(account, values);
246
+ }
247
+ const createdAccount = await storage.createAccount(account);
248
+ if (!createdAccount) throw new Error("Unable to read the created Auth account.");
249
+ await dispatchHook(scope, AFTER_ACCOUNT_CREATE_HOOK, createdAccount);
250
+ const principal = {
251
+ sub: createdAccount.id,
252
+ email: createdAccount.email
253
+ };
254
+ await dispatchHook(scope, AFTER_PRINCIPAL_CREATE_HOOK, principal, method);
255
+ return principal;
256
+ } else if (method.type === "PROVIDER") {
257
+ if ((await dispatchHook(scope, BEFORE_PRINCIPAL_CREATE_HOOK, method)).includes(false)) return;
258
+ const storage = await useAccountStorage(scope);
259
+ const account = {
260
+ id: crypto.randomUUID(),
261
+ email: method.principal.email ?? "",
262
+ password: null,
263
+ createdAt: /* @__PURE__ */ new Date()
264
+ };
265
+ const beforeAccountCreate = await dispatchHook(scope, BEFORE_ACCOUNT_CREATE_HOOK, account, method);
266
+ if (beforeAccountCreate.includes(false)) return;
267
+ const accountFields = Object.keys(account);
268
+ for (const values of beforeAccountCreate) {
269
+ if (!values || typeof values !== "object") continue;
270
+ for (const key of Object.keys(values)) if (accountFields.includes(key)) throw new Error(`Auth account create values cannot replace field "${key}".`);
271
+ Object.assign(account, values);
272
+ }
273
+ const identity = {
274
+ id: crypto.randomUUID(),
275
+ provider: method.issuer,
276
+ credential: method.principal.sub,
277
+ createdAt: /* @__PURE__ */ new Date(),
278
+ accountId: account.id
279
+ };
280
+ const beforeIdentityCreate = await dispatchHook(scope, BEFORE_IDENTITY_CREATE_HOOK, identity, method);
281
+ if (beforeIdentityCreate.includes(false)) return;
282
+ const identityFields = Object.keys(identity);
283
+ for (const values of beforeIdentityCreate) {
284
+ if (!values || typeof values !== "object") continue;
285
+ for (const key of Object.keys(values)) if (identityFields.includes(key)) throw new Error(`Auth identity create values cannot replace field "${key}".`);
286
+ Object.assign(identity, values);
287
+ }
288
+ const createdAccount = await storage.createAccount(account);
289
+ if (!createdAccount) throw new Error("Unable to read the created Auth account.");
290
+ let createdIdentity;
291
+ try {
292
+ createdIdentity = await storage.createIdentity(identity);
293
+ if (!createdIdentity) throw new Error("Unable to read the created Auth identity.");
294
+ } catch (error) {
295
+ await storage.deleteAccount(createdAccount.id);
296
+ throw error;
297
+ }
298
+ await dispatchHook(scope, AFTER_ACCOUNT_CREATE_HOOK, createdAccount);
299
+ await dispatchHook(scope, AFTER_IDENTITY_CREATE_HOOK, createdIdentity);
300
+ const principal = {
301
+ sub: createdAccount.id,
302
+ email: createdAccount.email
303
+ };
304
+ await dispatchHook(scope, AFTER_PRINCIPAL_CREATE_HOOK, principal, method);
305
+ return principal;
306
+ } else if (method.type === "PASSKEY") throw new Error("Passkey authentication is not implemented.");
307
+ }
308
+ async function createSession(scope, principal) {
309
+ const storage = await useAccountStorage(scope);
310
+ const session = {
311
+ id: crypto.randomUUID(),
312
+ createdAt: /* @__PURE__ */ new Date(),
313
+ accountId: principal.sub
314
+ };
315
+ const beforeSessionCreate = await dispatchHook(scope, BEFORE_SESSION_CREATE_HOOK, session, principal);
316
+ if (beforeSessionCreate.includes(false)) return;
317
+ const sessionFields = Object.keys(session);
318
+ for (const values of beforeSessionCreate) {
319
+ if (!values || typeof values !== "object") continue;
320
+ for (const key of Object.keys(values)) if (sessionFields.includes(key)) throw new Error(`Auth session create values cannot replace field "${key}".`);
321
+ Object.assign(session, values);
322
+ }
323
+ const created = await storage.createSession(session);
324
+ if (!created) throw new Error("Unable to read the created Auth session.");
325
+ await dispatchHook(scope, AFTER_SESSION_CREATE_HOOK, created);
326
+ return created;
327
+ }
328
+ var authIdSchema = pipe(string(), minLength(1), maxLength(128));
329
+ var organizationNameSchema = pipe(string(), maxLength(200), trim(), minLength(1));
330
+ var organizationParametersSchema = object({ organizationId: authIdSchema });
331
+ var membershipParametersSchema = object({
332
+ organizationId: authIdSchema,
333
+ membershipId: authIdSchema
334
+ });
335
+ var BEFORE_PRINCIPAL_GET_HOOK = defineHook("BEFORE_PRINCIPAL_GET_HOOK");
336
+ var AFTER_PRINCIPAL_GET_HOOK = defineHook("AFTER_PRINCIPAL_GET_HOOK");
337
+ var BEFORE_PRINCIPAL_CREATE_HOOK = defineHook("BEFORE_PRINCIPAL_CREATE_HOOK");
338
+ var AFTER_PRINCIPAL_CREATE_HOOK = defineHook("AFTER_PRINCIPAL_CREATE_HOOK");
339
+ var BEFORE_ACCOUNT_GET_HOOK = defineHook("BEFORE_ACCOUNT_GET_HOOK");
340
+ var AFTER_ACCOUNT_GET_HOOK = defineHook("AFTER_ACCOUNT_GET_HOOK");
341
+ var BEFORE_IDENTITY_GET_HOOK = defineHook("BEFORE_IDENTITY_GET_HOOK");
342
+ var AFTER_IDENTITY_GET_HOOK = defineHook("AFTER_IDENTITY_GET_HOOK");
343
+ var BEFORE_SESSION_GET_HOOK = defineHook("BEFORE_SESSION_GET_HOOK");
344
+ var AFTER_SESSION_GET_HOOK = defineHook("AFTER_SESSION_GET_HOOK");
345
+ var BEFORE_ACCOUNT_CREATE_HOOK = defineHook("BEFORE_ACCOUNT_CREATE_HOOK");
346
+ var AFTER_ACCOUNT_CREATE_HOOK = defineHook("AFTER_ACCOUNT_CREATE_HOOK");
347
+ var BEFORE_IDENTITY_CREATE_HOOK = defineHook("BEFORE_IDENTITY_CREATE_HOOK");
348
+ var AFTER_IDENTITY_CREATE_HOOK = defineHook("AFTER_IDENTITY_CREATE_HOOK");
349
+ var BEFORE_SESSION_CREATE_HOOK = defineHook("BEFORE_SESSION_CREATE_HOOK");
350
+ var AFTER_SESSION_CREATE_HOOK = defineHook("AFTER_SESSION_CREATE_HOOK");
163
351
  var registerAuthHooks = createRegisterHooks({
164
- authorize: AUTHORIZE_HOOK,
165
- getPrincipal: GET_PRINCIPAL_HOOK,
166
- createPrincipal: CREATE_PRINCIPAL_HOOK,
167
- createSession: CREATE_SESSION_HOOK,
168
- deleteSession: DELETE_SESSION_HOOK
352
+ beforePrincipalGet: BEFORE_PRINCIPAL_GET_HOOK,
353
+ afterPrincipalGet: AFTER_PRINCIPAL_GET_HOOK,
354
+ beforePrincipalCreate: BEFORE_PRINCIPAL_CREATE_HOOK,
355
+ afterPrincipalCreate: AFTER_PRINCIPAL_CREATE_HOOK,
356
+ beforeAccountGet: BEFORE_ACCOUNT_GET_HOOK,
357
+ afterAccountGet: AFTER_ACCOUNT_GET_HOOK,
358
+ beforeIdentityGet: BEFORE_IDENTITY_GET_HOOK,
359
+ afterIdentityGet: AFTER_IDENTITY_GET_HOOK,
360
+ beforeSessionGet: BEFORE_SESSION_GET_HOOK,
361
+ afterSessionGet: AFTER_SESSION_GET_HOOK,
362
+ beforeAccountCreate: BEFORE_ACCOUNT_CREATE_HOOK,
363
+ afterAccountCreate: AFTER_ACCOUNT_CREATE_HOOK,
364
+ beforeIdentityCreate: BEFORE_IDENTITY_CREATE_HOOK,
365
+ afterIdentityCreate: AFTER_IDENTITY_CREATE_HOOK,
366
+ beforeSessionCreate: BEFORE_SESSION_CREATE_HOOK,
367
+ afterSessionCreate: AFTER_SESSION_CREATE_HOOK
169
368
  });
170
369
  var principalSchema = object({
171
370
  sub: string(),
@@ -180,7 +379,7 @@ var passwordMethodSchema = object({
180
379
  type: literal("PASSWORD"),
181
380
  email: string(),
182
381
  password: string(),
183
- register: optional(boolean(), true)
382
+ register: optional(boolean(), false)
184
383
  });
185
384
  var passkeyMethodSchema = object({ type: literal("PASSKEY") });
186
385
  var providerMethodSchema = object({
@@ -234,4 +433,4 @@ var BASE64_VERIFY = { alphabet: "base64url" };
234
433
  var encoder = new TextEncoder();
235
434
  var decoder = new TextDecoder();
236
435
  //#endregion
237
- export { AUTHORIZE_HOOK, CREATE_PRINCIPAL_HOOK, CREATE_SESSION_HOOK, DELETE_SESSION_HOOK, GET_PRINCIPAL_HOOK, clearSession, defineAuthProvider, getCryptoKey, getSession, methodSchema, passkeyMethodSchema, passwordMethodSchema, principalSchema, providerMethodSchema, registerAuthHooks, requireSession, setSession, useAuth };
436
+ export { AFTER_ACCOUNT_CREATE_HOOK, AFTER_ACCOUNT_GET_HOOK, AFTER_IDENTITY_CREATE_HOOK, AFTER_IDENTITY_GET_HOOK, AFTER_PRINCIPAL_CREATE_HOOK, AFTER_PRINCIPAL_GET_HOOK, AFTER_SESSION_CREATE_HOOK, AFTER_SESSION_GET_HOOK, BEFORE_ACCOUNT_CREATE_HOOK, BEFORE_ACCOUNT_GET_HOOK, BEFORE_IDENTITY_CREATE_HOOK, BEFORE_IDENTITY_GET_HOOK, BEFORE_PRINCIPAL_CREATE_HOOK, BEFORE_PRINCIPAL_GET_HOOK, BEFORE_SESSION_CREATE_HOOK, BEFORE_SESSION_GET_HOOK, authIdSchema, clearSession, createPrincipal, createSession, defineAuthProvider, getCryptoKey, getPrincipal, getSession, membershipParametersSchema, methodSchema, organizationNameSchema, organizationParametersSchema, passkeyMethodSchema, passwordMethodSchema, principalSchema, providerMethodSchema, registerAuthHooks, requireSession, setSession, useAccountStorage, useClientAuth, useOrganizationStorage, useServerAuth };
@@ -6,6 +6,7 @@ export interface SessionOptions {
6
6
  cookie: CookieOptions;
7
7
  }
8
8
  export interface AuthConfig {
9
+ organizations: boolean;
9
10
  session: SessionOptions;
10
11
  providers?: Partial<Record<Providers | (string & {}), Mergeable<Pick<AuthProviderOptions, "scope" | "pkce" | "authorize" | "token" | "userInfo">>>>;
11
12
  }