@absolutejs/auth 0.26.0-beta.3 → 0.26.0-beta.4

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,102 @@
1
+ import { type AnyPgDatabase } from '../stores/postgres';
2
+ import type { RoleStore } from './types';
3
+ export declare const rolesTable: import("drizzle-orm/pg-core").PgTableWithColumns<{
4
+ name: "auth_roles";
5
+ schema: undefined;
6
+ columns: {
7
+ created_at_ms: import("drizzle-orm/pg-core").PgColumn<{
8
+ name: "created_at_ms";
9
+ tableName: "auth_roles";
10
+ dataType: "number";
11
+ columnType: "PgBigInt53";
12
+ data: number;
13
+ driverParam: string | number;
14
+ notNull: true;
15
+ hasDefault: false;
16
+ isPrimaryKey: false;
17
+ isAutoincrement: false;
18
+ hasRuntimeDefault: false;
19
+ enumValues: undefined;
20
+ baseColumn: never;
21
+ identity: undefined;
22
+ generated: undefined;
23
+ }, {}, {}>;
24
+ organization_id: import("drizzle-orm/pg-core").PgColumn<{
25
+ name: "organization_id";
26
+ tableName: "auth_roles";
27
+ dataType: "string";
28
+ columnType: "PgVarchar";
29
+ data: string;
30
+ driverParam: string;
31
+ notNull: true;
32
+ hasDefault: true;
33
+ isPrimaryKey: false;
34
+ isAutoincrement: false;
35
+ hasRuntimeDefault: false;
36
+ enumValues: [string, ...string[]];
37
+ baseColumn: never;
38
+ identity: undefined;
39
+ generated: undefined;
40
+ }, {}, {
41
+ length: 255;
42
+ }>;
43
+ permissions: import("drizzle-orm/pg-core").PgColumn<{
44
+ name: "permissions";
45
+ tableName: "auth_roles";
46
+ dataType: "json";
47
+ columnType: "PgJsonb";
48
+ data: string[];
49
+ driverParam: unknown;
50
+ notNull: true;
51
+ hasDefault: true;
52
+ isPrimaryKey: false;
53
+ isAutoincrement: false;
54
+ hasRuntimeDefault: false;
55
+ enumValues: undefined;
56
+ baseColumn: never;
57
+ identity: undefined;
58
+ generated: undefined;
59
+ }, {}, {
60
+ $type: string[];
61
+ }>;
62
+ slug: import("drizzle-orm/pg-core").PgColumn<{
63
+ name: "slug";
64
+ tableName: "auth_roles";
65
+ dataType: "string";
66
+ columnType: "PgVarchar";
67
+ data: string;
68
+ driverParam: string;
69
+ notNull: true;
70
+ hasDefault: false;
71
+ isPrimaryKey: false;
72
+ isAutoincrement: false;
73
+ hasRuntimeDefault: false;
74
+ enumValues: [string, ...string[]];
75
+ baseColumn: never;
76
+ identity: undefined;
77
+ generated: undefined;
78
+ }, {}, {
79
+ length: 128;
80
+ }>;
81
+ updated_at_ms: import("drizzle-orm/pg-core").PgColumn<{
82
+ name: "updated_at_ms";
83
+ tableName: "auth_roles";
84
+ dataType: "number";
85
+ columnType: "PgBigInt53";
86
+ data: number;
87
+ driverParam: string | number;
88
+ notNull: true;
89
+ hasDefault: false;
90
+ isPrimaryKey: false;
91
+ isAutoincrement: false;
92
+ hasRuntimeDefault: false;
93
+ enumValues: undefined;
94
+ baseColumn: never;
95
+ identity: undefined;
96
+ generated: undefined;
97
+ }, {}, {}>;
98
+ };
99
+ dialect: "pg";
100
+ }>;
101
+ export declare const createNeonRoleStore: (databaseUrl: string) => RoleStore;
102
+ export declare const createPostgresRoleStore: (db: AnyPgDatabase) => RoleStore;
@@ -0,0 +1,17 @@
1
+ import type { OrganizationStore } from '../organizations/types';
2
+ import type { OrganizationId } from '../tenancy';
3
+ import type { RoleStore } from './types';
4
+ export declare const createMembershipPermissionResolver: <UserType>({ getUserId, organizationStore, roleStore }: {
5
+ getUserId: (user: UserType) => string;
6
+ organizationStore: OrganizationStore;
7
+ roleStore: RoleStore;
8
+ }) => ({ organizationId, permission, user }: {
9
+ organizationId?: OrganizationId;
10
+ permission: string;
11
+ user: UserType;
12
+ }) => Promise<boolean>;
13
+ export declare const resolvePermissions: ({ organizationId, roleStore, roles }: {
14
+ organizationId?: OrganizationId;
15
+ roleStore: RoleStore;
16
+ roles: string[];
17
+ }) => Promise<Set<string>>;
@@ -0,0 +1,106 @@
1
+ import { Elysia } from 'elysia';
2
+ import type { SessionRecord } from '../types';
3
+ import { type RolesRouteProps } from './config';
4
+ export declare const roleRoutes: <UserType>({ authSessionStore, canManageRoles, emit, getUserId, onRolesAssigned, organizationStore, roleStore, rolesRoute }: RolesRouteProps<UserType>) => Elysia<"", {
5
+ decorator: {};
6
+ store: {
7
+ session: SessionRecord<UserType>;
8
+ unregisteredSession: import("..").UnregisteredSessionRecord;
9
+ };
10
+ derive: {};
11
+ resolve: {};
12
+ }, {
13
+ typebox: {};
14
+ error: {};
15
+ }, {
16
+ schema: {};
17
+ standaloneSchema: {};
18
+ macro: {};
19
+ macroFn: {};
20
+ parser: {};
21
+ response: {};
22
+ }, {
23
+ [x: string]: {
24
+ ":organizationId": {
25
+ get: {
26
+ body: unknown;
27
+ params: {
28
+ organizationId: string;
29
+ };
30
+ query: unknown;
31
+ headers: unknown;
32
+ response: {
33
+ 200: {
34
+ readonly roles: readonly import("./types").Role[];
35
+ };
36
+ 401: "Authentication required";
37
+ 403: "Cannot manage roles";
38
+ 422: {
39
+ type: "validation";
40
+ on: string;
41
+ summary?: string;
42
+ message?: string;
43
+ found?: unknown;
44
+ property?: string;
45
+ expected?: string;
46
+ };
47
+ };
48
+ };
49
+ };
50
+ };
51
+ } & {
52
+ [x: string]: {
53
+ ":organizationId": {
54
+ members: {
55
+ ":userId": {
56
+ put: {
57
+ body: {
58
+ roles: string[];
59
+ };
60
+ params: {
61
+ userId: string;
62
+ organizationId: string;
63
+ };
64
+ query: unknown;
65
+ headers: unknown;
66
+ response: {
67
+ 200: {
68
+ readonly roles: string[];
69
+ };
70
+ 401: "Authentication required";
71
+ 403: "Cannot manage roles";
72
+ 404: "Membership not found";
73
+ 422: {
74
+ type: "validation";
75
+ on: string;
76
+ summary?: string;
77
+ message?: string;
78
+ found?: unknown;
79
+ property?: string;
80
+ expected?: string;
81
+ };
82
+ };
83
+ };
84
+ };
85
+ };
86
+ };
87
+ };
88
+ }, {
89
+ derive: {};
90
+ resolve: {};
91
+ schema: {};
92
+ standaloneSchema: {};
93
+ response: {};
94
+ }, {
95
+ derive: {};
96
+ resolve: {};
97
+ schema: {};
98
+ standaloneSchema: {};
99
+ response: {};
100
+ } & {
101
+ derive: {};
102
+ resolve: {};
103
+ schema: {};
104
+ standaloneSchema: {};
105
+ response: {};
106
+ }>;
@@ -0,0 +1,14 @@
1
+ import type { OrganizationId } from '../tenancy';
2
+ export type Role = {
3
+ createdAt: number;
4
+ organizationId?: OrganizationId;
5
+ permissions: string[];
6
+ slug: string;
7
+ updatedAt: number;
8
+ };
9
+ export type RoleStore = {
10
+ deleteRole: (slug: string, organizationId?: OrganizationId) => Promise<void>;
11
+ getRole: (slug: string, organizationId?: OrganizationId) => Promise<Role | undefined>;
12
+ listRoles: (organizationId?: OrganizationId) => Promise<Role[]>;
13
+ saveRole: (role: Role) => Promise<void>;
14
+ };
package/dist/types.d.ts CHANGED
@@ -9,11 +9,15 @@ import type { AuthIdentityConflict } from './errors';
9
9
  import type { AuthHtmxConfig, AuthHtmxUser } from './htmx/types';
10
10
  import type { LockoutConfig } from './lockout/config';
11
11
  import type { MfaConfig } from './mfa/config';
12
+ import type { OrganizationsConfig } from './organizations/config';
13
+ import type { PasswordlessConfig } from './passwordless/config';
14
+ import type { RolesConfig } from './roles/config';
12
15
  import type { ScimConfig } from './scim/config';
13
16
  import type { SessionsConfig } from './session/sessionsConfig';
14
17
  import type { AuthSessionStore } from './session/types';
15
18
  import type { SSOConfig } from './sso/config';
16
19
  import type { WebAuthnConfig } from './webauthn/config';
20
+ import type { WebhooksConfig } from './webhooks/config';
17
21
  export type AuthIntent = 'login' | 'link_identity' | 'link_connector';
18
22
  export type OAuth2ProviderClientConfiguration<Provider extends ProviderOption> = {
19
23
  credentials: CredentialsFor<Provider>;
@@ -183,6 +187,11 @@ export type AuthConfig<UserType> = {
183
187
  * mounts register / verify-email / login / reset-password routes that produce the
184
188
  * same `SessionData<UserType>` as OAuth, transparent to `protectRoute`. */
185
189
  credentials?: CredentialsConfig<UserType>;
190
+ /** Passwordless login: magic links + email/SMS OTP. When present, mounts the magic-link flow
191
+ * (if `onSendMagicLink` is set) and/or the OTP flow (if `onSendOtp` is set) under
192
+ * `{passwordlessRoute}`; each verify route resolves the email to a user and mints the same
193
+ * `SessionData<UserType>` as every other flow. */
194
+ passwordless?: PasswordlessConfig<UserType>;
186
195
  /** Multi-factor auth (TOTP + backup codes). When present alongside `credentials`,
187
196
  * `auth()` auto-wires the login MFA gate, mounts the enroll/challenge routes, and
188
197
  * promotes the parked session once a factor is verified. */
@@ -203,6 +212,15 @@ export type AuthConfig<UserType> = {
203
212
  * mounts `{scimRoute}/Users` (+ `/ServiceProviderConfig`) with per-org bearer-token auth via
204
213
  * `scimTokenStore`, and maps SCIM resources to the consumer's user store through hooks. */
205
214
  scim?: ScimConfig;
215
+ /** First-class multi-tenancy (the WorkOS model). When present, mounts organization +
216
+ * membership + invitation routes under `{organizationsRoute}`: list the caller's orgs, create
217
+ * one (caller becomes owner), invite/accept/revoke by email, and list/remove members. Ties the
218
+ * bare `organizationId` used by SSO/SCIM/RBAC into a real tenant model with org-scoped roles. */
219
+ organizations?: OrganizationsConfig<UserType>;
220
+ /** Org-scoped roles & permissions (builds on `organizations`). When present, mounts routes to
221
+ * list an org's role definitions and set a member's roles. Pair with
222
+ * `createMembershipPermissionResolver` to make `authorization.hasPermission` turnkey. */
223
+ roles?: RolesConfig<UserType>;
206
224
  /** Role-based / attribute-based access control (E4). When present, `auth()` exposes a
207
225
  * `protectPermission(check, handler)` derive (alongside `protectRoute`) that delegates the
208
226
  * decision to your `hasPermission` hook — the package stays schema-agnostic about roles. */
@@ -217,6 +235,11 @@ export type AuthConfig<UserType> = {
217
235
  * → mints the same `SessionData<UserType>`). A `webauthnAdapter` wraps a vetted library (e.g.
218
236
  * `@simplewebauthn/server`); the package never bundles the WebAuthn crypto. */
219
237
  webauthn?: WebAuthnConfig<UserType>;
238
+ /** Signed outbound webhooks. When present, every emitted auth event (the audit taxonomy) is
239
+ * HMAC-signed (Standard Webhooks scheme) and POSTed to each endpoint. Delivery is best-effort
240
+ * and isolated per endpoint; configuring this alone (without `audit`) is enough to turn on
241
+ * event emission. PII redaction (`audit.redact`) applies before delivery. */
242
+ webhooks?: WebhooksConfig;
220
243
  /** Enable the built-in HTMX fragment routes (login, identities, connectors,
221
244
  * account, signout, delete-account). Supply provider display data + the
222
245
  * identity/connector data actions; the package owns the route wiring and
@@ -0,0 +1,21 @@
1
+ import type { WebhookEndpoint, WebhookEvent } from './types';
2
+ export declare const DEFAULT_WEBHOOK_TIMEOUT_MS: number;
3
+ export type WebhookFetch = (url: string, init: {
4
+ body: string;
5
+ headers: Record<string, string>;
6
+ method: string;
7
+ signal: AbortSignal;
8
+ }) => Promise<{
9
+ ok: boolean;
10
+ status: number;
11
+ }>;
12
+ export type WebhooksConfig = {
13
+ endpoints: WebhookEndpoint[];
14
+ fetch?: WebhookFetch;
15
+ onDeliveryError?: (context: {
16
+ endpoint: WebhookEndpoint;
17
+ error: unknown;
18
+ event: WebhookEvent;
19
+ }) => void | Promise<void>;
20
+ timeoutMs?: number;
21
+ };
@@ -0,0 +1,3 @@
1
+ import type { AuditEvent } from '../audit/types';
2
+ import { type WebhooksConfig } from './config';
3
+ export declare const createWebhookDispatcher: ({ endpoints, fetch: fetchImpl, onDeliveryError, timeoutMs }: WebhooksConfig) => (event: AuditEvent) => Promise<void>;
@@ -0,0 +1,11 @@
1
+ export declare const signWebhook: ({ id, payload, secret, timestamp }: {
2
+ id: string;
3
+ payload: string;
4
+ secret: string;
5
+ timestamp: string;
6
+ }) => Promise<string>;
7
+ export declare const verifyWebhookSignature: ({ headers, payload, secret }: {
8
+ headers: Record<string, string | undefined>;
9
+ payload: string;
10
+ secret: string;
11
+ }) => Promise<boolean>;
@@ -0,0 +1,11 @@
1
+ import type { AuditEvent, AuditEventType } from '../audit/types';
2
+ export type WebhookEndpoint = {
3
+ secret: string;
4
+ url: string;
5
+ };
6
+ export type WebhookEvent = {
7
+ createdAt: number;
8
+ data: AuditEvent;
9
+ id: string;
10
+ type: AuditEventType;
11
+ };
package/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "0.26.0-beta.3",
2
+ "version": "0.26.0-beta.4",
3
3
  "name": "@absolutejs/auth",
4
4
  "description": "An authorization library for absolutejs",
5
5
  "repository": {