own-auth 0.1.0 → 0.1.1
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/postgres/hosted-projects.d.ts +88 -0
- package/dist/postgres/hosted-projects.d.ts.map +1 -0
- package/dist/postgres/hosted-projects.js +454 -0
- package/dist/postgres/hosted-projects.js.map +1 -0
- package/dist/postgres/index.d.ts +20 -0
- package/dist/postgres/index.d.ts.map +1 -0
- package/dist/postgres/index.js +18 -0
- package/dist/postgres/index.js.map +1 -0
- package/dist/postgres/postgres-storage.d.ts +55 -0
- package/dist/postgres/postgres-storage.d.ts.map +1 -0
- package/dist/postgres/postgres-storage.js +648 -0
- package/dist/postgres/postgres-storage.js.map +1 -0
- package/migrations/001_initial.sql +227 -0
- package/migrations/002_hosted_projects.sql +38 -0
- package/package.json +14 -3
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
-- Own Auth initial Postgres schema.
|
|
2
|
+
-- IDs are generated by the auth engine so the schema stays portable across hosts.
|
|
3
|
+
|
|
4
|
+
create table if not exists own_auth_users (
|
|
5
|
+
id text primary key,
|
|
6
|
+
email text,
|
|
7
|
+
email_verified_at timestamptz,
|
|
8
|
+
phone text,
|
|
9
|
+
phone_verified_at timestamptz,
|
|
10
|
+
password_hash text,
|
|
11
|
+
name text,
|
|
12
|
+
image_url text,
|
|
13
|
+
disabled_at timestamptz,
|
|
14
|
+
metadata jsonb not null default '{}'::jsonb,
|
|
15
|
+
created_at timestamptz not null,
|
|
16
|
+
updated_at timestamptz not null,
|
|
17
|
+
last_login_at timestamptz
|
|
18
|
+
);
|
|
19
|
+
|
|
20
|
+
create unique index if not exists own_auth_users_email_unique
|
|
21
|
+
on own_auth_users (lower(email))
|
|
22
|
+
where email is not null;
|
|
23
|
+
|
|
24
|
+
create unique index if not exists own_auth_users_phone_unique
|
|
25
|
+
on own_auth_users (phone)
|
|
26
|
+
where phone is not null;
|
|
27
|
+
|
|
28
|
+
create table if not exists own_auth_accounts (
|
|
29
|
+
id text primary key,
|
|
30
|
+
user_id text not null references own_auth_users(id) on delete cascade,
|
|
31
|
+
provider text not null,
|
|
32
|
+
provider_account_id text not null,
|
|
33
|
+
provider_email text,
|
|
34
|
+
provider_phone text,
|
|
35
|
+
created_at timestamptz not null,
|
|
36
|
+
updated_at timestamptz not null,
|
|
37
|
+
constraint own_auth_accounts_provider_check
|
|
38
|
+
check (provider in ('password', 'magic_link', 'phone'))
|
|
39
|
+
);
|
|
40
|
+
|
|
41
|
+
create unique index if not exists own_auth_accounts_provider_account_unique
|
|
42
|
+
on own_auth_accounts (provider, provider_account_id);
|
|
43
|
+
|
|
44
|
+
create index if not exists own_auth_accounts_user_id_idx
|
|
45
|
+
on own_auth_accounts (user_id);
|
|
46
|
+
|
|
47
|
+
create table if not exists own_auth_sessions (
|
|
48
|
+
id text primary key,
|
|
49
|
+
user_id text not null references own_auth_users(id) on delete cascade,
|
|
50
|
+
token_hash text not null unique,
|
|
51
|
+
created_at timestamptz not null,
|
|
52
|
+
last_active_at timestamptz not null,
|
|
53
|
+
expires_at timestamptz not null,
|
|
54
|
+
idle_expires_at timestamptz not null,
|
|
55
|
+
ip_address text,
|
|
56
|
+
user_agent text,
|
|
57
|
+
revoked_at timestamptz,
|
|
58
|
+
revoke_reason text
|
|
59
|
+
);
|
|
60
|
+
|
|
61
|
+
create index if not exists own_auth_sessions_user_active_idx
|
|
62
|
+
on own_auth_sessions (user_id, revoked_at, expires_at, idle_expires_at);
|
|
63
|
+
|
|
64
|
+
create table if not exists own_auth_tokens (
|
|
65
|
+
id text primary key,
|
|
66
|
+
token_hash text not null unique,
|
|
67
|
+
type text not null,
|
|
68
|
+
user_id text references own_auth_users(id) on delete cascade,
|
|
69
|
+
email text,
|
|
70
|
+
phone text,
|
|
71
|
+
organisation_id text,
|
|
72
|
+
expires_at timestamptz not null,
|
|
73
|
+
used_at timestamptz,
|
|
74
|
+
created_at timestamptz not null,
|
|
75
|
+
constraint own_auth_tokens_type_check
|
|
76
|
+
check (type in (
|
|
77
|
+
'email_verification',
|
|
78
|
+
'password_reset',
|
|
79
|
+
'magic_link',
|
|
80
|
+
'organisation_invite',
|
|
81
|
+
'phone_verification'
|
|
82
|
+
))
|
|
83
|
+
);
|
|
84
|
+
|
|
85
|
+
create index if not exists own_auth_tokens_lookup_idx
|
|
86
|
+
on own_auth_tokens (token_hash, type, used_at, expires_at);
|
|
87
|
+
|
|
88
|
+
create table if not exists own_auth_sms_otps (
|
|
89
|
+
id text primary key,
|
|
90
|
+
phone text not null,
|
|
91
|
+
user_id text references own_auth_users(id) on delete cascade,
|
|
92
|
+
code_hash text not null,
|
|
93
|
+
purpose text not null,
|
|
94
|
+
expires_at timestamptz not null,
|
|
95
|
+
attempts integer not null default 0,
|
|
96
|
+
max_attempts integer not null default 5,
|
|
97
|
+
consumed_at timestamptz,
|
|
98
|
+
created_at timestamptz not null,
|
|
99
|
+
last_sent_at timestamptz not null,
|
|
100
|
+
constraint own_auth_sms_otps_purpose_check
|
|
101
|
+
check (purpose in ('phone_login', 'phone_verification', 'account_recovery')),
|
|
102
|
+
constraint own_auth_sms_otps_attempts_check
|
|
103
|
+
check (attempts >= 0 and max_attempts > 0)
|
|
104
|
+
);
|
|
105
|
+
|
|
106
|
+
create index if not exists own_auth_sms_otps_latest_idx
|
|
107
|
+
on own_auth_sms_otps (phone, purpose, created_at desc);
|
|
108
|
+
|
|
109
|
+
create table if not exists own_auth_organisations (
|
|
110
|
+
id text primary key,
|
|
111
|
+
name text not null,
|
|
112
|
+
slug text not null unique,
|
|
113
|
+
owner_user_id text not null references own_auth_users(id),
|
|
114
|
+
metadata jsonb not null default '{}'::jsonb,
|
|
115
|
+
created_at timestamptz not null,
|
|
116
|
+
updated_at timestamptz not null,
|
|
117
|
+
disabled_at timestamptz
|
|
118
|
+
);
|
|
119
|
+
|
|
120
|
+
create index if not exists own_auth_organisations_owner_idx
|
|
121
|
+
on own_auth_organisations (owner_user_id);
|
|
122
|
+
|
|
123
|
+
create table if not exists own_auth_organisation_members (
|
|
124
|
+
id text primary key,
|
|
125
|
+
organisation_id text not null references own_auth_organisations(id) on delete cascade,
|
|
126
|
+
user_id text not null references own_auth_users(id) on delete cascade,
|
|
127
|
+
role text not null,
|
|
128
|
+
status text not null,
|
|
129
|
+
joined_at timestamptz,
|
|
130
|
+
removed_at timestamptz,
|
|
131
|
+
created_at timestamptz not null,
|
|
132
|
+
updated_at timestamptz not null,
|
|
133
|
+
constraint own_auth_organisation_members_role_check
|
|
134
|
+
check (role in ('owner', 'admin', 'member')),
|
|
135
|
+
constraint own_auth_organisation_members_status_check
|
|
136
|
+
check (status in ('active', 'suspended', 'removed'))
|
|
137
|
+
);
|
|
138
|
+
|
|
139
|
+
create unique index if not exists own_auth_organisation_members_unique
|
|
140
|
+
on own_auth_organisation_members (organisation_id, user_id);
|
|
141
|
+
|
|
142
|
+
create index if not exists own_auth_organisation_members_user_idx
|
|
143
|
+
on own_auth_organisation_members (user_id, status);
|
|
144
|
+
|
|
145
|
+
create table if not exists own_auth_invitations (
|
|
146
|
+
id text primary key,
|
|
147
|
+
organisation_id text not null references own_auth_organisations(id) on delete cascade,
|
|
148
|
+
email text,
|
|
149
|
+
phone text,
|
|
150
|
+
role text not null,
|
|
151
|
+
invited_by_user_id text not null references own_auth_users(id),
|
|
152
|
+
status text not null,
|
|
153
|
+
expires_at timestamptz not null,
|
|
154
|
+
accepted_at timestamptz,
|
|
155
|
+
revoked_at timestamptz,
|
|
156
|
+
created_at timestamptz not null,
|
|
157
|
+
constraint own_auth_invitations_role_check
|
|
158
|
+
check (role in ('owner', 'admin', 'member')),
|
|
159
|
+
constraint own_auth_invitations_status_check
|
|
160
|
+
check (status in ('pending', 'accepted', 'expired', 'revoked')),
|
|
161
|
+
constraint own_auth_invitations_contact_check
|
|
162
|
+
check (email is not null or phone is not null)
|
|
163
|
+
);
|
|
164
|
+
|
|
165
|
+
create index if not exists own_auth_invitations_pending_email_idx
|
|
166
|
+
on own_auth_invitations (organisation_id, lower(email), status, created_at desc)
|
|
167
|
+
where email is not null;
|
|
168
|
+
|
|
169
|
+
create table if not exists own_auth_api_keys (
|
|
170
|
+
id text primary key,
|
|
171
|
+
key_prefix text not null unique,
|
|
172
|
+
key_hash text not null,
|
|
173
|
+
name text not null,
|
|
174
|
+
user_id text references own_auth_users(id) on delete cascade,
|
|
175
|
+
organisation_id text references own_auth_organisations(id) on delete cascade,
|
|
176
|
+
scopes text[] not null default array[]::text[],
|
|
177
|
+
status text not null default 'active',
|
|
178
|
+
expires_at timestamptz,
|
|
179
|
+
last_used_at timestamptz,
|
|
180
|
+
created_at timestamptz not null,
|
|
181
|
+
revoked_at timestamptz,
|
|
182
|
+
revoked_by text references own_auth_users(id),
|
|
183
|
+
metadata jsonb not null default '{}'::jsonb,
|
|
184
|
+
constraint own_auth_api_keys_status_check
|
|
185
|
+
check (status in ('active', 'revoked')),
|
|
186
|
+
constraint own_auth_api_keys_owner_check
|
|
187
|
+
check (user_id is not null or organisation_id is not null)
|
|
188
|
+
);
|
|
189
|
+
|
|
190
|
+
create index if not exists own_auth_api_keys_user_idx
|
|
191
|
+
on own_auth_api_keys (user_id, status);
|
|
192
|
+
|
|
193
|
+
create index if not exists own_auth_api_keys_organisation_idx
|
|
194
|
+
on own_auth_api_keys (organisation_id, status);
|
|
195
|
+
|
|
196
|
+
create table if not exists own_auth_audit_events (
|
|
197
|
+
id text primary key,
|
|
198
|
+
event_type text not null,
|
|
199
|
+
actor_user_id text references own_auth_users(id) on delete set null,
|
|
200
|
+
target_user_id text references own_auth_users(id) on delete set null,
|
|
201
|
+
organisation_id text references own_auth_organisations(id) on delete set null,
|
|
202
|
+
api_key_id text references own_auth_api_keys(id) on delete set null,
|
|
203
|
+
ip_address text,
|
|
204
|
+
user_agent text,
|
|
205
|
+
metadata jsonb not null default '{}'::jsonb,
|
|
206
|
+
created_at timestamptz not null
|
|
207
|
+
);
|
|
208
|
+
|
|
209
|
+
create index if not exists own_auth_audit_events_actor_idx
|
|
210
|
+
on own_auth_audit_events (actor_user_id, created_at desc);
|
|
211
|
+
|
|
212
|
+
create index if not exists own_auth_audit_events_target_idx
|
|
213
|
+
on own_auth_audit_events (target_user_id, created_at desc);
|
|
214
|
+
|
|
215
|
+
create index if not exists own_auth_audit_events_organisation_idx
|
|
216
|
+
on own_auth_audit_events (organisation_id, created_at desc);
|
|
217
|
+
|
|
218
|
+
create index if not exists own_auth_audit_events_api_key_idx
|
|
219
|
+
on own_auth_audit_events (api_key_id, created_at desc);
|
|
220
|
+
|
|
221
|
+
create table if not exists own_auth_rate_limits (
|
|
222
|
+
key text primary key,
|
|
223
|
+
count integer not null,
|
|
224
|
+
reset_at timestamptz not null,
|
|
225
|
+
constraint own_auth_rate_limits_count_check
|
|
226
|
+
check (count >= 0)
|
|
227
|
+
);
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
-- Own Auth hosted project control tables.
|
|
2
|
+
-- Project auth data lives in a separate Postgres schema per hosted project.
|
|
3
|
+
|
|
4
|
+
create table if not exists own_auth_hosted_projects (
|
|
5
|
+
id text primary key,
|
|
6
|
+
name text not null,
|
|
7
|
+
slug text not null unique,
|
|
8
|
+
owner_user_id text not null references own_auth_users(id) on delete cascade,
|
|
9
|
+
schema_name text not null unique,
|
|
10
|
+
metadata jsonb not null default '{}'::jsonb,
|
|
11
|
+
created_at timestamptz not null,
|
|
12
|
+
updated_at timestamptz not null,
|
|
13
|
+
disabled_at timestamptz
|
|
14
|
+
);
|
|
15
|
+
|
|
16
|
+
create index if not exists own_auth_hosted_projects_owner_idx
|
|
17
|
+
on own_auth_hosted_projects (owner_user_id, created_at desc);
|
|
18
|
+
|
|
19
|
+
create table if not exists own_auth_hosted_project_keys (
|
|
20
|
+
id text primary key,
|
|
21
|
+
project_id text not null references own_auth_hosted_projects(id) on delete cascade,
|
|
22
|
+
key_prefix text not null unique,
|
|
23
|
+
key_hash text not null,
|
|
24
|
+
name text not null,
|
|
25
|
+
scopes text[] not null default array[]::text[],
|
|
26
|
+
status text not null default 'active',
|
|
27
|
+
expires_at timestamptz,
|
|
28
|
+
last_used_at timestamptz,
|
|
29
|
+
created_at timestamptz not null,
|
|
30
|
+
revoked_at timestamptz,
|
|
31
|
+
revoked_by text references own_auth_users(id),
|
|
32
|
+
metadata jsonb not null default '{}'::jsonb,
|
|
33
|
+
constraint own_auth_hosted_project_keys_status_check
|
|
34
|
+
check (status in ('active', 'revoked'))
|
|
35
|
+
);
|
|
36
|
+
|
|
37
|
+
create index if not exists own_auth_hosted_project_keys_project_idx
|
|
38
|
+
on own_auth_hosted_project_keys (project_id, status);
|
package/package.json
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "own-auth",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Framework-independent auth engine for Own Auth.",
|
|
6
6
|
"main": "./dist/index.js",
|
|
7
7
|
"types": "./dist/index.d.ts",
|
|
8
8
|
"files": [
|
|
9
|
-
"dist"
|
|
9
|
+
"dist",
|
|
10
|
+
"migrations"
|
|
10
11
|
],
|
|
11
12
|
"publishConfig": {
|
|
12
13
|
"access": "public"
|
|
@@ -15,11 +16,21 @@
|
|
|
15
16
|
".": {
|
|
16
17
|
"types": "./dist/index.d.ts",
|
|
17
18
|
"default": "./dist/index.js"
|
|
18
|
-
}
|
|
19
|
+
},
|
|
20
|
+
"./postgres": {
|
|
21
|
+
"types": "./dist/postgres/index.d.ts",
|
|
22
|
+
"default": "./dist/postgres/index.js"
|
|
23
|
+
},
|
|
24
|
+
"./migrations/001_initial.sql": "./migrations/001_initial.sql",
|
|
25
|
+
"./migrations/002_hosted_projects.sql": "./migrations/002_hosted_projects.sql"
|
|
26
|
+
},
|
|
27
|
+
"devDependencies": {
|
|
28
|
+
"pg": "^8.16.3"
|
|
19
29
|
},
|
|
20
30
|
"scripts": {
|
|
21
31
|
"build": "tsc -p tsconfig.json",
|
|
22
32
|
"test": "vitest run",
|
|
33
|
+
"test:integration": "vitest run test/postgres/postgres-storage.integration.test.ts",
|
|
23
34
|
"typecheck": "tsc -p tsconfig.json --noEmit"
|
|
24
35
|
}
|
|
25
36
|
}
|