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.
@@ -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.0",
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
  }