@jskit-ai/auth-provider-supabase-core 0.1.99 → 0.1.101

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.
@@ -1,7 +1,7 @@
1
1
  export default Object.freeze({
2
2
  "packageVersion": 1,
3
3
  "packageId": "@jskit-ai/auth-provider-supabase-core",
4
- "version": "0.1.99",
4
+ "version": "0.1.101",
5
5
  "kind": "runtime",
6
6
  "options": {
7
7
  "auth-supabase-url": {
@@ -83,8 +83,8 @@ export default Object.freeze({
83
83
  "mutations": {
84
84
  "dependencies": {
85
85
  "runtime": {
86
- "@jskit-ai/auth-core": "0.1.99",
87
- "@jskit-ai/kernel": "0.1.101",
86
+ "@jskit-ai/auth-core": "0.1.101",
87
+ "@jskit-ai/kernel": "0.1.103",
88
88
  "dotenv": "^16.4.5",
89
89
  "@supabase/supabase-js": "^2.57.4",
90
90
  "jose": "^6.1.0"
@@ -138,10 +138,10 @@ export default Object.freeze({
138
138
  "file": "config/server.js",
139
139
  "position": "bottom",
140
140
  "skipIfContains": "config.auth.profileMode =",
141
- "value": "\nconfig.auth ||= {};\nconfig.auth.profileMode = \"standalone\";\n",
142
- "reason": "Use standalone auth profile sync until a users package enables users-backed sync.",
141
+ "value": "\nconfig.auth ||= {};\nconfig.auth.profileMode = \"provider\";\n",
142
+ "reason": "Use provider-owned auth profiles until a users package enables users-backed sync.",
143
143
  "category": "runtime-config",
144
- "id": "auth-profile-mode-standalone"
144
+ "id": "auth-profile-mode-provider"
145
145
  },
146
146
  {
147
147
  "op": "append-text",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jskit-ai/auth-provider-supabase-core",
3
- "version": "0.1.99",
3
+ "version": "0.1.101",
4
4
  "type": "module",
5
5
  "scripts": {
6
6
  "test": "node --test"
@@ -12,8 +12,8 @@
12
12
  "./client": "./src/client/index.js"
13
13
  },
14
14
  "dependencies": {
15
- "@jskit-ai/auth-core": "0.1.99",
16
- "@jskit-ai/kernel": "0.1.101",
15
+ "@jskit-ai/auth-core": "0.1.101",
16
+ "@jskit-ai/kernel": "0.1.103",
17
17
  "json-rest-schema": "1.x.x",
18
18
  "jose": "^6.1.0",
19
19
  "@supabase/supabase-js": "^2.57.4",
@@ -315,10 +315,14 @@ function createAccountFlows(deps) {
315
315
  };
316
316
  }
317
317
 
318
- async function updateDisplayName(request, displayName) {
318
+ async function updateDisplayName(request, payload = {}) {
319
319
  ensureConfigured();
320
320
 
321
- const normalizedDisplayName = String(displayName || "").trim();
321
+ const normalizedDisplayName = String(
322
+ payload && typeof payload === "object" && !Array.isArray(payload)
323
+ ? payload.displayName
324
+ : payload
325
+ ).trim();
322
326
  if (!normalizedDisplayName) {
323
327
  throw validationError({
324
328
  displayName: "Display name is required."
@@ -1,49 +1,5 @@
1
- import { createSchema } from "json-rest-schema";
2
- import {
3
- emptyInputValidator
4
- } from "@jskit-ai/kernel/shared/actions/actionContributorHelpers";
5
- import {
6
- composeSchemaDefinitions
7
- } from "@jskit-ai/kernel/shared/validators";
8
- import { deepFreeze } from "@jskit-ai/kernel/shared/support/deepFreeze";
9
- import {
10
- authRegisterCommand,
11
- authRegisterConfirmationResendCommand,
12
- authLoginPasswordCommand,
13
- authLoginOtpRequestCommand,
14
- authLoginOtpVerifyCommand,
15
- authLoginOAuthStartCommand,
16
- authLoginOAuthCompleteCommand,
17
- authDevLoginAsCommand,
18
- authPasswordResetRequestCommand,
19
- authPasswordRecoveryCompleteCommand,
20
- authPasswordResetCommand
21
- } from "@jskit-ai/auth-core/shared/commands";
22
-
23
- const authLoginOAuthStartInput = composeSchemaDefinitions([
24
- authLoginOAuthStartCommand.operation.params,
25
- authLoginOAuthStartCommand.operation.query
26
- ], {
27
- mode: "patch",
28
- context: "authContributor.authLoginOAuthStartInput"
29
- });
30
-
31
- const authLogoutOutput = deepFreeze({
32
- schema: createSchema({
33
- ok: { type: "boolean", required: true },
34
- clearSession: { type: "boolean", required: true }
35
- }),
36
- mode: "replace"
37
- });
38
-
39
- function requireRequestContext(context, actionId) {
40
- const request = context?.requestMeta?.request || null;
41
- if (request) {
42
- return request;
43
- }
44
-
45
- throw new Error(`${actionId} requires request context.`);
46
- }
1
+ import { authDevLoginAsCommand } from "@jskit-ai/auth-core/shared/commands";
2
+ import { requireRequestContext } from "@jskit-ai/auth-core/server/actions/auth.contributor";
47
3
 
48
4
  const devLoginAsAction = Object.freeze({
49
5
  id: "auth.dev.loginAs",
@@ -62,236 +18,4 @@ const devLoginAsAction = Object.freeze({
62
18
  }
63
19
  });
64
20
 
65
- const authActionsBeforeDevLogin = Object.freeze([
66
- {
67
- id: "auth.register",
68
- version: 1,
69
- kind: "command",
70
- channels: ["api", "internal"],
71
- surfacesFrom: "enabled",
72
- input: authRegisterCommand.operation.body,
73
- idempotency: "none",
74
- audit: {
75
- actionName: "auth.register"
76
- },
77
- observability: {},
78
- async execute(input, _context, deps) {
79
- return deps.authService.register(input);
80
- }
81
- },
82
- {
83
- id: "auth.register.confirmation.resend",
84
- version: 1,
85
- kind: "command",
86
- channels: ["api", "internal"],
87
- surfacesFrom: "enabled",
88
- input: authRegisterConfirmationResendCommand.operation.body,
89
- idempotency: "none",
90
- audit: {
91
- actionName: "auth.register.confirmation.resend"
92
- },
93
- observability: {},
94
- async execute(input, _context, deps) {
95
- return deps.authService.resendRegisterConfirmation(input);
96
- }
97
- },
98
- {
99
- id: "auth.login.password",
100
- version: 1,
101
- kind: "command",
102
- channels: ["api", "internal"],
103
- surfacesFrom: "enabled",
104
- input: authLoginPasswordCommand.operation.body,
105
- idempotency: "none",
106
- audit: {
107
- actionName: "auth.login.password"
108
- },
109
- observability: {},
110
- async execute(input, _context, deps) {
111
- return deps.authService.login(input);
112
- }
113
- },
114
- {
115
- id: "auth.login.otp.request",
116
- version: 1,
117
- kind: "command",
118
- channels: ["api", "internal"],
119
- surfacesFrom: "enabled",
120
- input: authLoginOtpRequestCommand.operation.body,
121
- idempotency: "none",
122
- audit: {
123
- actionName: "auth.login.otp.request"
124
- },
125
- observability: {},
126
- async execute(input, _context, deps) {
127
- return deps.authService.requestOtpLogin(input);
128
- }
129
- },
130
- {
131
- id: "auth.login.otp.verify",
132
- version: 1,
133
- kind: "command",
134
- channels: ["api", "internal"],
135
- surfacesFrom: "enabled",
136
- input: authLoginOtpVerifyCommand.operation.body,
137
- idempotency: "none",
138
- audit: {
139
- actionName: "auth.login.otp.verify"
140
- },
141
- observability: {},
142
- async execute(input, _context, deps) {
143
- return deps.authService.verifyOtpLogin(input);
144
- }
145
- },
146
- {
147
- id: "auth.login.oauth.start",
148
- version: 1,
149
- kind: "command",
150
- channels: ["api", "internal"],
151
- surfacesFrom: "enabled",
152
- input: authLoginOAuthStartInput,
153
- idempotency: "none",
154
- audit: {
155
- actionName: "auth.login.oauth.start"
156
- },
157
- observability: {},
158
- async execute(input, _context, deps) {
159
- return deps.authService.oauthStart(input);
160
- }
161
- },
162
- {
163
- id: "auth.login.oauth.complete",
164
- version: 1,
165
- kind: "command",
166
- channels: ["api", "internal"],
167
- surfacesFrom: "enabled",
168
- input: authLoginOAuthCompleteCommand.operation.body,
169
- idempotency: "none",
170
- audit: {
171
- actionName: "auth.login.oauth.complete"
172
- },
173
- observability: {},
174
- async execute(input, _context, deps) {
175
- return deps.authService.oauthComplete(input);
176
- }
177
- }
178
- ]);
179
-
180
- const authActionsAfterDevLogin = Object.freeze([
181
- {
182
- id: "auth.password.reset.request",
183
- version: 1,
184
- kind: "command",
185
- channels: ["api", "internal"],
186
- surfacesFrom: "enabled",
187
- input: authPasswordResetRequestCommand.operation.body,
188
- idempotency: "none",
189
- audit: {
190
- actionName: "auth.password.reset.request"
191
- },
192
- observability: {},
193
- async execute(input, _context, deps) {
194
- return deps.authService.requestPasswordReset(input);
195
- }
196
- },
197
- {
198
- id: "auth.password.recovery.complete",
199
- version: 1,
200
- kind: "command",
201
- channels: ["api", "internal"],
202
- surfacesFrom: "enabled",
203
- input: authPasswordRecoveryCompleteCommand.operation.body,
204
- idempotency: "none",
205
- audit: {
206
- actionName: "auth.password.recovery.complete"
207
- },
208
- observability: {},
209
- async execute(input, _context, deps) {
210
- return deps.authService.completePasswordRecovery(input);
211
- }
212
- },
213
- {
214
- id: "auth.password.reset",
215
- version: 1,
216
- kind: "command",
217
- channels: ["api", "internal"],
218
- surfacesFrom: "enabled",
219
- input: authPasswordResetCommand.operation.body,
220
- idempotency: "none",
221
- audit: {
222
- actionName: "auth.password.reset"
223
- },
224
- observability: {},
225
- async execute(input, context, deps) {
226
- return deps.authService.resetPassword(requireRequestContext(context, "auth.password.reset"), input);
227
- }
228
- },
229
- {
230
- id: "auth.logout",
231
- version: 1,
232
- kind: "command",
233
- channels: ["api", "automation", "internal"],
234
- surfacesFrom: "enabled",
235
- input: emptyInputValidator,
236
- output: authLogoutOutput,
237
- idempotency: "none",
238
- audit: {
239
- actionName: "auth.logout"
240
- },
241
- observability: {},
242
- async execute(_input, context, deps) {
243
- let logoutResult = {
244
- ok: true,
245
- clearSession: true
246
- };
247
- if (deps.authService && typeof deps.authService.logout === "function") {
248
- logoutResult = await deps.authService.logout(requireRequestContext(context, "auth.logout"));
249
- }
250
-
251
- if (deps.authSessionEventsService && typeof deps.authSessionEventsService.notifySessionChanged === "function") {
252
- await deps.authSessionEventsService.notifySessionChanged({
253
- context
254
- });
255
- }
256
- return {
257
- ok: logoutResult?.ok !== false,
258
- clearSession: logoutResult?.clearSession !== false
259
- };
260
- }
261
- },
262
- {
263
- id: "auth.session.read",
264
- version: 1,
265
- kind: "query",
266
- channels: ["api", "internal"],
267
- surfacesFrom: "enabled",
268
- input: emptyInputValidator,
269
- idempotency: "none",
270
- audit: {
271
- actionName: "auth.session.read"
272
- },
273
- observability: {},
274
- async execute(_input, context, deps) {
275
- return deps.authService.authenticateRequest(requireRequestContext(context, "auth.session.read"));
276
- }
277
- }
278
- ]);
279
-
280
- const baseAuthActions = Object.freeze([
281
- ...authActionsBeforeDevLogin,
282
- ...authActionsAfterDevLogin
283
- ]);
284
-
285
- function buildAuthActions({ includeDevLoginAs = false } = {}) {
286
- if (!includeDevLoginAs) {
287
- return baseAuthActions;
288
- }
289
-
290
- return Object.freeze([
291
- ...authActionsBeforeDevLogin,
292
- devLoginAsAction,
293
- ...authActionsAfterDevLogin
294
- ]);
295
- }
296
-
297
- export { baseAuthActions, buildAuthActions, devLoginAsAction };
21
+ export { devLoginAsAction };
@@ -10,6 +10,7 @@ import {
10
10
  buildAuthMethodDefinitions,
11
11
  buildOAuthMethodId
12
12
  } from "@jskit-ai/auth-core/shared/authMethods";
13
+ import { buildSecurityStatusFromAuthMethodsStatus as buildCoreSecurityStatusFromAuthMethodsStatus } from "@jskit-ai/auth-core/shared/authSecurityStatus";
13
14
 
14
15
  function normalizeIdentityProviderId(value) {
15
16
  return String(value || "")
@@ -168,29 +169,8 @@ function buildAuthMethodsStatusFromSupabaseUser(user, options = {}) {
168
169
  return buildAuthMethodsStatusFromProviderIds(collectProviderIdsFromSupabaseUser(user), options);
169
170
  }
170
171
 
171
- function buildSecurityStatusFromAuthMethodsStatus(authMethodsStatus) {
172
- const minimumEnabledMethods = Number(authMethodsStatus?.minimumEnabledMethods || AUTH_METHOD_MINIMUM_ENABLED);
173
- let enabledMethodsCount = 0;
174
-
175
- const storedCount = Number(authMethodsStatus?.enabledMethodsCount);
176
- if (Number.isFinite(storedCount)) {
177
- enabledMethodsCount = storedCount;
178
- } else if (Array.isArray(authMethodsStatus?.methods)) {
179
- enabledMethodsCount = countEnabledMethods(authMethodsStatus.methods);
180
- }
181
-
182
- return {
183
- mfa: {
184
- status: "not_enabled",
185
- enrolled: false,
186
- methods: []
187
- },
188
- authPolicy: {
189
- minimumEnabledMethods,
190
- enabledMethodsCount
191
- },
192
- authMethods: Array.isArray(authMethodsStatus?.methods) ? authMethodsStatus.methods : []
193
- };
172
+ function buildSecurityStatusFromAuthMethodsStatus(authMethodsStatus, options = {}) {
173
+ return buildCoreSecurityStatusFromAuthMethodsStatus(authMethodsStatus, options);
194
174
  }
195
175
 
196
176
  function findAuthMethodById(authMethodsStatus, methodId) {
@@ -1,2 +1,2 @@
1
1
  export { createService, __testables } from "./service.js";
2
- export { baseAuthActions, buildAuthActions, devLoginAsAction } from "./actions/auth.contributor.js";
2
+ export { devLoginAsAction } from "./actions/auth.contributor.js";
@@ -18,6 +18,7 @@ function createPasswordSecurityFlows(deps) {
18
18
  mapRecoveryError,
19
19
  syncProfileFromSupabaseUser,
20
20
  setSessionFromRequestCookies,
21
+ setRecoverySessionFromRequestCookies,
21
22
  resolvePasswordSignInPolicyForUserId,
22
23
  mapPasswordUpdateError,
23
24
  setPasswordSetupRequiredForUserId,
@@ -130,7 +131,10 @@ function createPasswordSecurityFlows(deps) {
130
131
 
131
132
  return {
132
133
  profile,
133
- session
134
+ session: {
135
+ ...session,
136
+ purpose: "recovery"
137
+ }
134
138
  };
135
139
  }
136
140
 
@@ -144,7 +148,7 @@ function createPasswordSecurityFlows(deps) {
144
148
  const parsed = result.validatedObject;
145
149
 
146
150
  const supabase = getSupabaseClient();
147
- const sessionResponse = await setSessionFromRequestCookies(request, {
151
+ const sessionResponse = await setRecoverySessionFromRequestCookies(request, {
148
152
  supabaseClient: supabase
149
153
  });
150
154
  const profile = await syncProfileFromSupabaseUser(
@@ -169,6 +173,14 @@ function createPasswordSecurityFlows(deps) {
169
173
 
170
174
  const updatedProfile = await syncProfileFromSupabaseUser(user, user.email);
171
175
  await setPasswordSetupRequiredForUserId(updatedProfile.id, false);
176
+
177
+ const signOutResponse = await supabase.auth.signOut({
178
+ scope: "local"
179
+ });
180
+
181
+ if (signOutResponse.error) {
182
+ throw mapAuthError(signOutResponse.error, Number(signOutResponse.error?.status || 400));
183
+ }
172
184
  }
173
185
 
174
186
  async function changePassword(request, payload) {