@jskit-ai/auth-provider-supabase-core 0.1.55 → 0.1.57

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.55",
4
+ "version": "0.1.57",
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.55",
87
- "@jskit-ai/kernel": "0.1.56",
86
+ "@jskit-ai/auth-core": "0.1.57",
87
+ "@jskit-ai/kernel": "0.1.58",
88
88
  "dotenv": "^16.4.5",
89
89
  "@supabase/supabase-js": "^2.57.4",
90
90
  "jose": "^6.1.0"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jskit-ai/auth-provider-supabase-core",
3
- "version": "0.1.55",
3
+ "version": "0.1.57",
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.55",
16
- "@jskit-ai/kernel": "0.1.56",
15
+ "@jskit-ai/auth-core": "0.1.57",
16
+ "@jskit-ai/kernel": "0.1.58",
17
17
  "json-rest-schema": "1.x.x",
18
18
  "jose": "^6.1.0",
19
19
  "@supabase/supabase-js": "^2.57.4"
@@ -9,6 +9,7 @@ import { buildAuthActions } from "../lib/actions/auth.contributor.js";
9
9
  const AUTH_PROFILE_MODE_STANDALONE = "standalone";
10
10
  const AUTH_PROFILE_MODE_USERS = "users";
11
11
  const SUPPORTED_AUTH_PROFILE_MODES = Object.freeze([AUTH_PROFILE_MODE_STANDALONE, AUTH_PROFILE_MODE_USERS]);
12
+ const INTERNAL_JSON_REST_API = "internal.json-rest-api";
12
13
 
13
14
  function splitCsv(value) {
14
15
  return String(value || "")
@@ -186,6 +187,21 @@ function resolveOptionalRepositories(scope) {
186
187
  return repositories;
187
188
  }
188
189
 
190
+ function isDeferredJsonRestBootGap(app, error) {
191
+ const hasUserProfilesRepository = typeof app?.has === "function" && app.has("internal.repository.user-profiles");
192
+ const hasJsonRestApi = typeof app?.has === "function" && app.has(INTERNAL_JSON_REST_API);
193
+ const message = String(error?.message || "");
194
+ const causeMessage = String(error?.cause?.message || "");
195
+ const combined = `${message}\n${causeMessage}`;
196
+
197
+ return (
198
+ hasUserProfilesRepository &&
199
+ !hasJsonRestApi &&
200
+ /internal\.json-rest-api/.test(combined) &&
201
+ /not registered/i.test(combined)
202
+ );
203
+ }
204
+
189
205
  function applyAuthServiceDecorators(scope, authService) {
190
206
  let decoratedAuthService = authService;
191
207
 
@@ -315,7 +331,18 @@ class AuthSupabaseServiceProvider {
315
331
  return;
316
332
  }
317
333
 
318
- app.make("authService");
334
+ try {
335
+ app.make("authService");
336
+ } catch (error) {
337
+ // In users mode, repo bindings can exist after register() while the json-rest host
338
+ // token is still unavailable until json-rest-api.core.boot(). Defer eager authService
339
+ // materialization only for that exact lifecycle gap; every other configuration error
340
+ // should still fail fast during boot.
341
+ if (isDeferredJsonRestBootGap(app, error)) {
342
+ return;
343
+ }
344
+ throw error;
345
+ }
319
346
  }
320
347
  }
321
348
 
@@ -3,6 +3,7 @@ import test from "node:test";
3
3
  import { createApplication } from "@jskit-ai/kernel/_testable";
4
4
  import { registerAuthServiceDecorator } from "@jskit-ai/auth-core/server/authServiceDecoratorRegistry";
5
5
  import { ActionRuntimeServiceProvider } from "@jskit-ai/kernel/server/actions";
6
+ import { createProviderClass } from "../../kernel/shared/runtime/application.js";
6
7
  import { AuthSupabaseServiceProvider } from "../src/server/providers/AuthSupabaseServiceProvider.js";
7
8
 
8
9
  function createAppConfigFixture() {
@@ -405,6 +406,81 @@ test("auth supabase provider rejects dev auth bypass without internal.repository
405
406
  );
406
407
  });
407
408
 
409
+ test("auth supabase provider defers eager dev auth materialization until json-rest host is available", async () => {
410
+ const DeferredUserProfilesRepositoryProvider = createProviderClass({
411
+ id: "aaa.deferred-user-profiles-repository",
412
+ register(app) {
413
+ app.singleton("internal.repository.user-profiles", (scope) => {
414
+ const api = scope.make("internal.json-rest-api");
415
+
416
+ return {
417
+ api,
418
+ async findById() {
419
+ return null;
420
+ },
421
+ async findByEmail() {
422
+ return null;
423
+ }
424
+ };
425
+ });
426
+ }
427
+ });
428
+
429
+ const DeferredJsonRestApiProvider = createProviderClass({
430
+ id: "json-rest-api.core",
431
+ boot(app) {
432
+ app.instance("internal.json-rest-api", {
433
+ scopes: new Map()
434
+ });
435
+ }
436
+ });
437
+
438
+ const app = createApplication();
439
+ app.instance("appConfig", createAppConfigFixture());
440
+ app.instance("jskit.env", {
441
+ AUTH_DEV_BYPASS_ENABLED: "true",
442
+ AUTH_DEV_BYPASS_SECRET: "dev-bootstrap-secret",
443
+ AUTH_PROFILE_MODE: "users",
444
+ APP_PUBLIC_URL: "http://localhost:5173",
445
+ NODE_ENV: "development"
446
+ });
447
+ app.instance("jskit.logger", {
448
+ info() {},
449
+ warn() {},
450
+ error() {},
451
+ debug() {}
452
+ });
453
+ app.instance("domainEvents", {
454
+ async publish() {}
455
+ });
456
+ app.instance("users.profile.sync.service", {
457
+ async findByIdentity() {
458
+ return null;
459
+ },
460
+ async syncIdentityProfile(profile) {
461
+ return {
462
+ id: 1,
463
+ authProvider: String(profile?.authProvider || "supabase"),
464
+ authProviderUserSid: String(profile?.authProviderUserSid || "user-1"),
465
+ email: String(profile?.email || "test@example.com"),
466
+ displayName: String(profile?.displayName || "Test User")
467
+ };
468
+ }
469
+ });
470
+
471
+ await app.start({
472
+ providers: [
473
+ ActionRuntimeServiceProvider,
474
+ DeferredUserProfilesRepositoryProvider,
475
+ AuthSupabaseServiceProvider,
476
+ DeferredJsonRestApiProvider
477
+ ]
478
+ });
479
+
480
+ const authService = app.make("authService");
481
+ assert.equal(typeof authService?.devLoginAs, "function");
482
+ });
483
+
408
484
  test("auth supabase provider reads oauth providers from appConfig.auth.oauth", async () => {
409
485
  const app = createApplication();
410
486
  app.instance("appConfig", {