@nebulr-group/bridge-svelte 0.3.2 → 0.4.0-beta.0

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.
Files changed (85) hide show
  1. package/dist/client/BridgeBootstrap.d.ts +1 -1
  2. package/dist/client/BridgeBootstrap.js +104 -27
  3. package/dist/client/BridgeBootstrap.svelte +65 -4
  4. package/dist/client/BridgeBootstrap.svelte.d.ts +2 -0
  5. package/dist/client/BridgeProvider.svelte +31 -0
  6. package/dist/client/BridgeProvider.svelte.d.ts +8 -0
  7. package/dist/client/components/developer/ApiTokenManagement.svelte +1 -1
  8. package/dist/client/components/sdk-auth/LoginForm.svelte +10 -7
  9. package/dist/client/components/sdk-auth/LoginForm.svelte.d.ts +1 -1
  10. package/dist/client/components/sdk-auth/PasskeyLogin.svelte +1 -1
  11. package/dist/client/components/sdk-auth/PasskeySetup.svelte +1 -1
  12. package/dist/client/components/sdk-auth/SsoButton.svelte +1 -1
  13. package/dist/client/components/sdk-auth/SsoButton.svelte.d.ts +1 -1
  14. package/dist/client/components/sdk-auth/TenantSelector.svelte +1 -1
  15. package/dist/client/components/sdk-auth/TenantSelector.svelte.d.ts +1 -1
  16. package/dist/client/components/sdk-auth/WorkspaceSelector.svelte +3 -3
  17. package/dist/client/components/sdk-auth/WorkspaceSelector.svelte.d.ts +3 -3
  18. package/dist/client/components/subscription/BridgeBillingNotice.svelte +389 -0
  19. package/dist/client/components/subscription/BridgeBillingNotice.svelte.d.ts +19 -0
  20. package/dist/client/components/subscription/BridgePaywall.svelte +94 -0
  21. package/dist/client/components/subscription/BridgePaywall.svelte.d.ts +19 -0
  22. package/dist/client/components/subscription/BridgeQuotaBanner.svelte +275 -0
  23. package/dist/client/components/subscription/BridgeQuotaBanner.svelte.d.ts +24 -0
  24. package/dist/client/components/subscription/BridgeSubscriptionStatus.svelte +116 -0
  25. package/dist/client/components/subscription/BridgeSubscriptionStatus.svelte.d.ts +7 -0
  26. package/dist/client/components/subscription/PlanSelector.svelte +22 -14
  27. package/dist/client/components/subscription/PlanSelector.svelte.d.ts +3 -3
  28. package/dist/client/components/subscription/billing-notice-gate.test.d.ts +1 -0
  29. package/dist/client/components/subscription/billing-notice-gate.test.js +83 -0
  30. package/dist/client/components/team/TeamAddUserDialog.svelte +1 -1
  31. package/dist/client/components/team/TeamAddUserDialog.svelte.d.ts +1 -1
  32. package/dist/client/components/team/TeamEditUserDialog.svelte +1 -1
  33. package/dist/client/components/team/TeamEditUserDialog.svelte.d.ts +1 -1
  34. package/dist/client/components/team/TeamProfileForm.svelte +1 -1
  35. package/dist/client/components/team/TeamUserList.svelte +1 -1
  36. package/dist/client/components/team/TeamWorkspaceForm.svelte +1 -1
  37. package/dist/client/tracking/pii-hashing.spec.js +4 -14
  38. package/dist/core/bridge-instance.d.ts +1 -2
  39. package/dist/core/bridge-instance.js +0 -4
  40. package/dist/core/bridge-runtime.d.ts +101 -0
  41. package/dist/core/bridge-runtime.js +290 -0
  42. package/dist/core/bridge-runtime.test.d.ts +1 -0
  43. package/dist/core/bridge-runtime.test.js +203 -0
  44. package/dist/core/bridge.d.ts +93 -0
  45. package/dist/core/bridge.js +108 -0
  46. package/dist/core/bridge.test.d.ts +1 -0
  47. package/dist/core/bridge.test.js +224 -0
  48. package/dist/core/events.d.ts +74 -0
  49. package/dist/core/events.js +64 -0
  50. package/dist/core/events.test.d.ts +1 -0
  51. package/dist/core/events.test.js +116 -0
  52. package/dist/core/lazy-slice.d.ts +74 -0
  53. package/dist/core/lazy-slice.js +124 -0
  54. package/dist/core/lazy-slice.test.d.ts +1 -0
  55. package/dist/core/lazy-slice.test.js +144 -0
  56. package/dist/core/realtime-status.d.ts +6 -0
  57. package/dist/core/realtime-status.js +15 -0
  58. package/dist/core/snapshot-stores.d.ts +69 -0
  59. package/dist/core/snapshot-stores.js +64 -0
  60. package/dist/core/use-bridge.d.ts +13 -0
  61. package/dist/core/use-bridge.js +46 -0
  62. package/dist/core/use-bridge.test.d.ts +1 -0
  63. package/dist/core/use-bridge.test.js +24 -0
  64. package/dist/flags/FeatureFlag.svelte +57 -0
  65. package/dist/flags/FeatureFlag.svelte.d.ts +37 -0
  66. package/dist/flags/bootstrap.d.ts +72 -0
  67. package/dist/flags/bootstrap.js +323 -0
  68. package/dist/flags/bootstrap.test.d.ts +1 -0
  69. package/dist/flags/bootstrap.test.js +195 -0
  70. package/dist/flags/flag.svelte.d.ts +31 -0
  71. package/dist/flags/flag.svelte.js +99 -0
  72. package/dist/flags/index.d.ts +8 -0
  73. package/dist/flags/index.js +20 -0
  74. package/dist/flags/index.test.d.ts +1 -0
  75. package/dist/flags/index.test.js +81 -0
  76. package/dist/flags/realtime-status.d.ts +1 -0
  77. package/dist/flags/realtime-status.js +4 -0
  78. package/dist/flags/registry.d.ts +27 -0
  79. package/dist/flags/registry.js +63 -0
  80. package/dist/flags/us13-integration.test.d.ts +1 -0
  81. package/dist/flags/us13-integration.test.js +168 -0
  82. package/dist/index.d.ts +14 -1
  83. package/dist/index.js +31 -2
  84. package/dist/styles.d.ts +2 -0
  85. package/package.json +92 -86
@@ -1,7 +1,7 @@
1
1
  import type { RouteGuardConfig } from '../auth/route-guard.js';
2
2
  import { waitForBridge as _waitForBridge } from '../core/bridge-instance.js';
3
3
  import type { BridgeConfig } from '../shared/types/config.js';
4
- export declare function bridgeBootstrap(url: URL, config: BridgeConfig | string, routeConfig?: RouteGuardConfig): Promise<{
4
+ export declare function bridgeBootstrap(url: URL, config: BridgeConfig | string, routeConfig?: RouteGuardConfig, kitFetch?: typeof globalThis.fetch): Promise<{
5
5
  flagsReady: Promise<void>;
6
6
  } | undefined>;
7
7
  export declare const bridgeReady: import("svelte/store").Readable<boolean>;
@@ -1,12 +1,13 @@
1
1
  // src/lib/bridge/bootstrap.ts
2
- import { isRedirect, redirect } from '@sveltejs/kit';
2
+ import { redirect, isRedirect } from '@sveltejs/kit';
3
3
  import { get } from 'svelte/store';
4
4
  import { createRouteGuard } from '../auth/route-guard.js';
5
5
  import { getBridgeAuth, bridgeReadyStore, markReady, waitForBridge as _waitForBridge, } from '../core/bridge-instance.js';
6
+ import { useBridge } from '@nebulr-group/bridge-auth-core';
6
7
  import { featureFlags } from '../shared/feature-flag.js';
7
8
  import { logger } from '../shared/logger.js';
8
9
  import { bridgeConfig, getConfig } from './stores/config.store.js';
9
- export async function bridgeBootstrap(url, config, routeConfig = { rules: [], defaultAccess: 'protected' }) {
10
+ export async function bridgeBootstrap(url, config, routeConfig = { rules: [], defaultAccess: 'protected' }, kitFetch) {
10
11
  // If we've already completed bootstrap once, short-circuit
11
12
  if (get(bridgeReadyStore)) {
12
13
  return;
@@ -20,49 +21,85 @@ export async function bridgeBootstrap(url, config, routeConfig = { rules: [], de
20
21
  }
21
22
  // 1. Initialize configuration (synchronously) — this also calls initBridge()
22
23
  bridgeConfig.initConfig(finalConfig, routeConfig);
23
- // 1a. If we're on bridge OAuth callback route, let bridge dedicated route handle it
24
+ // 1a. Unified callback handler detects what is calling back and routes accordingly
24
25
  try {
25
26
  const resolvedCallbackUrl = getConfig().callbackUrl;
26
27
  const callbackPath = resolvedCallbackUrl ? new URL(resolvedCallbackUrl).pathname : null;
27
28
  if (callbackPath && url.pathname === callbackPath) {
28
- logger.debug('[bridgeBootstrap] callback route detected, skipping bootstrap flow');
29
- const bridge = getBridgeAuth();
29
+ logger.debug('[bridgeBootstrap] callback route detected');
30
30
  const code = url.searchParams.get('code');
31
- logger.debug('[bridgeBootstrap] callback code check', { hasCode: !!code, pathname: url.pathname });
31
+ const sessionId = url.searchParams.get('session_id');
32
+ const stripeSuccess = url.searchParams.has('stripe_success');
33
+ const stripeCancel = url.searchParams.has('stripe_cancel');
34
+ // Strip any session_id Stripe appends to the redirect param destination
35
+ const rawRedirect = url.searchParams.get('redirect') ?? '/subscription';
36
+ const redirectTo = rawRedirect.split('?')[0];
32
37
  if (code) {
38
+ // OAuth callback
39
+ const bridge = getBridgeAuth();
33
40
  try {
34
- logger.debug('[bridgeBootstrap] calling handleCallback');
35
- await bridge.handleCallback(code);
36
- // Verify tokens before redirect
37
- const tokensAfterCallback = bridge.getTokens();
38
- const isAuthAfterCallback = !!tokensAfterCallback?.accessToken;
39
- logger.debug('[bridgeBootstrap] after handleCallback', {
40
- hasTokens: !!tokensAfterCallback?.accessToken,
41
- isAuthenticated: isAuthAfterCallback
42
- });
43
- // Redirect bridge user to bridge home page after bridge callback is handled
44
- // Preserve payment status if present (from post-payment redirect)
41
+ logger.debug('[bridgeBootstrap] OAuth callback — calling handleCallback');
42
+ // bridge-auth-core calls history.replaceState to strip ?code= from the URL.
43
+ // SvelteKit intercepts replaceState as a navigation event, cancelling the
44
+ // current load before our redirect can propagate. Use the native prototype
45
+ // method directly so the URL is cleaned up without triggering SvelteKit's
46
+ // navigation interceptor.
47
+ const svelteReplaceState = history.replaceState;
48
+ history.replaceState = History.prototype.replaceState.bind(history);
49
+ try {
50
+ await bridge.handleCallback(code);
51
+ }
52
+ finally {
53
+ history.replaceState = svelteReplaceState;
54
+ }
45
55
  const payment = url.searchParams.get('payment');
46
- const redirectUrl = payment ? `/?payment=${payment}` : '/';
47
- logger.debug('[bridgeBootstrap] redirecting to', { redirectUrl, payment });
48
- redirect(303, redirectUrl);
56
+ redirect(303, payment ? `/?payment=${payment}` : '/');
49
57
  }
50
58
  catch (err) {
51
- if (isRedirect(err)) {
52
- throw err; // Re-throw redirect so SvelteKit can handle it
59
+ if (isRedirect(err))
60
+ throw err;
61
+ logger.error('[bridgeBootstrap] OAuth callback error:', err);
62
+ }
63
+ }
64
+ else if (stripeSuccess && sessionId) {
65
+ // Stripe payment success — verify with bridge-api (server calls Stripe directly),
66
+ // then refresh tokens so the new JWT has shouldSelectPlan: false before redirect.
67
+ logger.debug('[bridgeBootstrap] Stripe success callback — confirming with bridge-api');
68
+ const bridge = getBridgeAuth();
69
+ const ctx = bridge.getApiContext();
70
+ try {
71
+ const res = await (kitFetch ?? fetch)(`${ctx.apiBaseUrl}/v1/account/stripe/confirm-checkout`, {
72
+ method: 'POST',
73
+ headers: { 'Content-Type': 'application/json' },
74
+ body: JSON.stringify({ sessionId, appId: ctx.appId }),
75
+ });
76
+ if (!res.ok) {
77
+ logger.warn('[bridgeBootstrap] confirm-checkout failed', res.status);
78
+ redirect(303, getConfig().billing?.paymentErrorRoute ?? '/payment-error');
53
79
  }
54
- logger.error('[bridgeBootstrap] Auth callback error:', err);
80
+ await bridge.refreshTokens();
81
+ redirect(303, redirectTo);
82
+ }
83
+ catch (err) {
84
+ if (isRedirect(err))
85
+ throw err;
86
+ logger.warn('[bridgeBootstrap] confirm-checkout error', err);
87
+ redirect(303, getConfig().billing?.paymentErrorRoute ?? '/payment-error');
55
88
  }
56
89
  }
90
+ else if (stripeCancel) {
91
+ // Stripe payment cancelled
92
+ logger.debug('[bridgeBootstrap] Stripe cancel callback — redirecting to', redirectTo);
93
+ redirect(303, redirectTo);
94
+ }
57
95
  else {
58
- logger.warn('[bridgeBootstrap] callback route detected but no code parameter');
96
+ logger.warn('[bridgeBootstrap] callback route reached with no recognised signal');
59
97
  }
60
98
  }
61
99
  }
62
100
  catch (e) {
63
- if (isRedirect(e)) {
64
- throw e; // Re-throw redirect so SvelteKit can handle it
65
- }
101
+ if (isRedirect(e))
102
+ throw e;
66
103
  logger.warn('[bridgeBootstrap] failed parsing callbackUrl', e);
67
104
  }
68
105
  // 2. Ensure tokens are fresh if needed
@@ -75,6 +112,46 @@ export async function bridgeBootstrap(url, config, routeConfig = { rules: [], de
75
112
  catch {
76
113
  // Non-fatal — stale tokens will be caught by route guard
77
114
  }
115
+ // 2b. Paywall redirect — fires before any page renders. Reads shouldSelectPlan
116
+ // and paymentsAutoRedirect from getSubscriptionStatus(). Only redirects when:
117
+ // - billing.paywallRoute is configured
118
+ // - the current path is not already the paywall route (no redirect loop)
119
+ // - the tenant is authenticated but has not selected a plan
120
+ // - the app has not opted out via paymentsAutoRedirect: false
121
+ try {
122
+ const paywallRoute = getConfig().billing?.paywallRoute;
123
+ if (paywallRoute && url.pathname !== paywallRoute) {
124
+ const bridge = getBridgeAuth();
125
+ if (bridge.isAuthenticated()) {
126
+ const status = await bridge.getSubscriptionStatus();
127
+ if (status?.shouldSelectPlan === true && status?.paymentsAutoRedirect !== false) {
128
+ logger.debug('[bridgeBootstrap] paywall redirect', paywallRoute);
129
+ redirect(303, paywallRoute);
130
+ }
131
+ }
132
+ }
133
+ }
134
+ catch (e) {
135
+ if (isRedirect(e))
136
+ throw e;
137
+ // Non-fatal — fail open if subscription fetch errors
138
+ }
139
+ // 2c. Auto-manage billing state so the notice/gate render without the
140
+ // integrator wiring a mount, and `hard` billing route rules can decide.
141
+ try {
142
+ const bridge = getBridgeAuth();
143
+ const ctx = bridge.getApiContext();
144
+ if (ctx.accessToken) {
145
+ await useBridge().subscription.mount({
146
+ apiBaseUrl: ctx.apiBaseUrl,
147
+ accessToken: ctx.accessToken,
148
+ appId: ctx.appId,
149
+ });
150
+ }
151
+ }
152
+ catch {
153
+ // Non-fatal — gate fails open; the notice hydrates lazily on first render.
154
+ }
78
155
  // 3. Fire flag fetch without awaiting so GQL queries can start in parallel.
79
156
  // The flagsReady promise is passed to the guard and returned to callers
80
157
  // so routes that need flags can still await before rendering.
@@ -1,15 +1,33 @@
1
1
  <script lang="ts">
2
2
  import { beforeNavigate, goto } from '$app/navigation';
3
- import { onMount } from 'svelte';
3
+ import { onMount, onDestroy } from 'svelte';
4
4
  import { createRouteGuard } from '../auth/route-guard.js';
5
5
  import { getBridgeAuth } from '../core/bridge-instance.js';
6
+ import { bridge as bridgeSurface } from '../core/bridge.js';
7
+ import { setBridgeContext } from '../core/use-bridge.js';
6
8
  import { getConfig } from './stores/config.store.js';
9
+ import {
10
+ startBridgeRuntime,
11
+ stopBridgeRuntime,
12
+ type StartBridgeRuntimeOptions,
13
+ } from '../core/bridge-runtime.js';
14
+ import { loadSubscription, ensureAppConfig } from '../core/bridge-instance.js';
7
15
 
8
- // Props: require config to be passed by consumer, now including onBootstrapComplete
9
- let {onBootstrapComplete }: {
10
- onBootstrapComplete?: () => void
16
+ // Props: optional `runtime` overrides for advanced/debug use (websocketFactory,
17
+ // reconnect overrides, etc.); `onBootstrapComplete` callback fires after the
18
+ // runtime + any auto-detected capabilities (flags) have attached.
19
+ let {
20
+ runtime,
21
+ onBootstrapComplete,
22
+ }: {
23
+ runtime?: StartBridgeRuntimeOptions;
24
+ onBootstrapComplete?: () => void;
11
25
  } = $props();
12
26
 
27
+ // Phase 4 (TBP-288/320) — expose the unified bridge surface via Svelte
28
+ // context so descendants can call `useBridge()`.
29
+ setBridgeContext(bridgeSurface);
30
+
13
31
  const guard = createRouteGuard();
14
32
 
15
33
  async function handleRoute(pathname: string, cancel?: () => void) {
@@ -31,11 +49,54 @@
31
49
  }
32
50
  }
33
51
 
52
+ // Stash a teardown for the dynamically-attached capabilities (today: flags).
53
+ let _capabilityStop: (() => Promise<void>) | undefined;
54
+
34
55
  onMount(async () => {
56
+ // Start the core runtime — realtime client, channel scoping, billing-store
57
+ // attach, session.snapshot fanout, billing-family event dispatch.
58
+ startBridgeRuntime(runtime);
59
+
60
+ // Fetch app config outside load() so we use the correct fetch context.
61
+ // LoginForm also calls ensureAppConfig() — both share the same in-flight promise.
62
+ void ensureAppConfig();
63
+
64
+ // Sync subscription when landing on any page after Stripe checkout success.
65
+ // BridgeBootstrap.ts runs server-side where sessionStorage is unavailable,
66
+ // so we write it here (client onMount) before calling loadSubscription().
67
+ const sessionId = new URLSearchParams(window.location.search).get('session_id');
68
+ if (sessionId) {
69
+ sessionStorage.setItem('bridge_checkout_session_id', sessionId);
70
+ loadSubscription().catch(() => { /* non-fatal */ });
71
+ }
72
+
73
+ // Auto-detect Feature Flags 2.0. If `@nebulr-group/bridge-svelte/flags` is
74
+ // on the dependency graph, attach the flag-specific runtime onto the
75
+ // already-started core (BridgeFlags instance, attribute providers,
76
+ // telemetry, hydrate, reactivity). The dynamic import means auth-only apps
77
+ // never pull the flags bundle.
78
+ try {
79
+ const flagsMod = await import('../flags/bootstrap.js');
80
+ const bundle = flagsMod.createBridgeFlags();
81
+ _capabilityStop = bundle.stop;
82
+ } catch {
83
+ // /flags entry not installed — auth-only app, skip flag attach.
84
+ }
85
+
35
86
  // Auth-core manages auto-refresh internally — no startAutoRefresh() needed
36
87
  if (onBootstrapComplete) onBootstrapComplete();
37
88
  });
38
89
 
90
+ onDestroy(() => {
91
+ void (async () => {
92
+ if (_capabilityStop) {
93
+ try { await _capabilityStop(); } catch { /* ignore */ }
94
+ _capabilityStop = undefined;
95
+ }
96
+ await stopBridgeRuntime();
97
+ })();
98
+ });
99
+
39
100
  beforeNavigate(async ({ to, cancel }) => {
40
101
  if (!to) return;
41
102
  await handleRoute(to.url.pathname, cancel);
@@ -1,4 +1,6 @@
1
+ import { type StartBridgeRuntimeOptions } from '../core/bridge-runtime.js';
1
2
  type $$ComponentProps = {
3
+ runtime?: StartBridgeRuntimeOptions;
2
4
  onBootstrapComplete?: () => void;
3
5
  };
4
6
  declare const BridgeBootstrap: import("svelte").Component<$$ComponentProps, {}, "">;
@@ -0,0 +1,31 @@
1
+ <!--
2
+ Phase 4 (TBP-288/320) — minimal context provider for the bridge surface.
3
+
4
+ Wrap your app:
5
+ <BridgeProvider>
6
+ <YourApp />
7
+ </BridgeProvider>
8
+
9
+ Without props, it sets the module-level singleton into context. To override
10
+ (SSR, multi-tenant tests, storybook), pass `{ bridge }`.
11
+
12
+ Distinct from <BridgeBootstrap>: that one orchestrates the full bootstrap
13
+ side effects (OAuth callback, route guards, billing mount). This is just
14
+ a thin context-setting wrapper. The two are composable — wrap
15
+ <BridgeBootstrap> in a <BridgeProvider> if you need both.
16
+ -->
17
+ <script lang="ts">
18
+ import { bridge as singleton } from '../core/bridge.js';
19
+ import { setBridgeContext } from '../core/use-bridge.js';
20
+ import type { BridgeSurface } from '../core/bridge.js';
21
+
22
+ interface Props {
23
+ bridge?: BridgeSurface;
24
+ children?: import('svelte').Snippet;
25
+ }
26
+ const { bridge = singleton, children }: Props = $props();
27
+
28
+ setBridgeContext(bridge);
29
+ </script>
30
+
31
+ {@render children?.()}
@@ -0,0 +1,8 @@
1
+ import type { BridgeSurface } from '../core/bridge.js';
2
+ interface Props {
3
+ bridge?: BridgeSurface;
4
+ children?: import('svelte').Snippet;
5
+ }
6
+ declare const BridgeProvider: import("svelte").Component<Props, {}, "">;
7
+ type BridgeProvider = ReturnType<typeof BridgeProvider>;
8
+ export default BridgeProvider;
@@ -1,7 +1,7 @@
1
1
  <script lang="ts">
2
2
  import type { HTMLAttributes } from 'svelte/elements';
3
3
  import { getBridgeAuth } from '../../../core/bridge-instance.js';
4
- import type { ApiToken, AvailablePrivilege, CreateApiTokenInput } from '@thebridge/auth-core';
4
+ import type { ApiToken, AvailablePrivilege, CreateApiTokenInput } from '@nebulr-group/bridge-auth-core';
5
5
 
6
6
  interface Props extends HTMLAttributes<HTMLDivElement> {}
7
7
 
@@ -1,7 +1,7 @@
1
1
  <script lang="ts">
2
2
  import type { Snippet } from 'svelte';
3
3
  import type { HTMLAttributes } from 'svelte/elements';
4
- import type { AppConfig, FederationConnection } from '@thebridge/auth-core';
4
+ import type { AppConfig, FederationConnection } from '@nebulr-group/bridge-auth-core';
5
5
  import { onMount } from 'svelte';
6
6
  import { getBridgeAuth, authState, appConfigStore, ensureAppConfig } from '../../../core/bridge-instance.js';
7
7
  import { getConfig } from '../../stores/config.store.js';
@@ -83,12 +83,15 @@
83
83
  function buildSsoConnections(appConfig: AppConfig | null): FederationConnection[] {
84
84
  if (!appConfig) return [];
85
85
  const out: FederationConnection[] = [];
86
- if (appConfig.googleSsoEnabled) out.push({ id: 'google', type: 'google', name: 'Google' });
87
- if (appConfig.azureAdSsoEnabled) out.push({ id: 'azure', type: 'ms-azure-ad', name: 'Microsoft' });
88
- if (appConfig.linkedinSsoEnabled) out.push({ id: 'linkedin', type: 'linkedin', name: 'LinkedIn' });
89
- if (appConfig.githubSsoEnabled) out.push({ id: 'github', type: 'github', name: 'GitHub' });
90
- if (appConfig.facebookSsoEnabled) out.push({ id: 'facebook', type: 'facebook', name: 'Facebook' });
91
- if (appConfig.appleSsoEnabled) out.push({ id: 'apple', type: 'apple', name: 'Apple' });
86
+ if (appConfig.googleSsoEnabled) out.push({ id: 'google', type: 'google', name: 'Google' });
87
+ if (appConfig.azureSsoEnabled) out.push({ id: 'azure', type: 'ms-azure-ad', name: 'Microsoft' });
88
+ // Remaining providers (LinkedIn, GitHub, Facebook, Apple, custom SAML/OIDC)
89
+ // come from the canonical federationConnections list. Skip google/azure so
90
+ // they don't duplicate the built-in toggles above.
91
+ for (const conn of appConfig.federationConnections ?? []) {
92
+ if (conn.type === 'google' || conn.type === 'ms-azure-ad') continue;
93
+ out.push(conn);
94
+ }
92
95
  return out;
93
96
  }
94
97
 
@@ -1,6 +1,6 @@
1
1
  import type { Snippet } from 'svelte';
2
2
  import type { HTMLAttributes } from 'svelte/elements';
3
- import type { FederationConnection } from '@thebridge/auth-core';
3
+ import type { FederationConnection } from '@nebulr-group/bridge-auth-core';
4
4
  interface Props extends HTMLAttributes<HTMLDivElement> {
5
5
  /** Override signup link visibility. Default: derived from app config (signupEnabled). */
6
6
  showSignupLink?: boolean | undefined;
@@ -44,7 +44,7 @@
44
44
  } else {
45
45
  // @ts-ignore — @simplewebauthn/browser is an optional peer dependency
46
46
  const mod = await import('@simplewebauthn/browser');
47
- authResponse = await mod.startAuthentication({ optionsJSON: options, useBrowserAutofill: autofill });
47
+ authResponse = await mod.startAuthentication({ optionsJSON: options as any, useBrowserAutofill: autofill });
48
48
  }
49
49
 
50
50
  await getBridgeAuth().authenticateWithPasskey(authResponse);
@@ -58,7 +58,7 @@
58
58
  } else {
59
59
  // @ts-ignore — @simplewebauthn/browser is an optional peer dependency
60
60
  const mod = await import('@simplewebauthn/browser');
61
- regResponse = await mod.startRegistration({ optionsJSON: options });
61
+ regResponse = await mod.startRegistration({ optionsJSON: options as any });
62
62
  }
63
63
 
64
64
  const result = await getBridgeAuth().verifyPasskeyRegistration(regResponse, token);
@@ -1,7 +1,7 @@
1
1
  <script lang="ts">
2
2
  import type { Snippet } from 'svelte';
3
3
  import type { HTMLButtonAttributes } from 'svelte/elements';
4
- import type { FederationConnection } from '@thebridge/auth-core';
4
+ import type { FederationConnection } from '@nebulr-group/bridge-auth-core';
5
5
  import { getBridgeAuth } from '../../../core/bridge-instance.js';
6
6
  import Spinner from './shared/Spinner.svelte';
7
7
 
@@ -1,6 +1,6 @@
1
1
  import type { Snippet } from 'svelte';
2
2
  import type { HTMLButtonAttributes } from 'svelte/elements';
3
- import type { FederationConnection } from '@thebridge/auth-core';
3
+ import type { FederationConnection } from '@nebulr-group/bridge-auth-core';
4
4
  interface Props extends HTMLButtonAttributes {
5
5
  connection: FederationConnection;
6
6
  label?: string;
@@ -1,7 +1,7 @@
1
1
  <script lang="ts">
2
2
  import type { Snippet } from 'svelte';
3
3
  import type { HTMLAttributes } from 'svelte/elements';
4
- import type { TenantUser } from '@thebridge/auth-core';
4
+ import type { TenantUser } from '@nebulr-group/bridge-auth-core';
5
5
  import { getBridgeAuth, tenantUsersStore } from '../../../core/bridge-instance.js';
6
6
  import AuthFormWrapper from './shared/AuthFormWrapper.svelte';
7
7
  import Spinner from './shared/Spinner.svelte';
@@ -1,6 +1,6 @@
1
1
  import type { Snippet } from 'svelte';
2
2
  import type { HTMLAttributes } from 'svelte/elements';
3
- import type { TenantUser } from '@thebridge/auth-core';
3
+ import type { TenantUser } from '@nebulr-group/bridge-auth-core';
4
4
  interface Props extends HTMLAttributes<HTMLDivElement> {
5
5
  onSelect?: () => void;
6
6
  onError?: (error: Error) => void;
@@ -1,13 +1,13 @@
1
1
  <script lang="ts">
2
- import type { HTMLDivAttributes } from 'svelte/elements';
2
+ import type { HTMLAttributes } from 'svelte/elements';
3
3
  import type { Snippet } from 'svelte';
4
- import type { Workspace } from '@thebridge/auth-core';
4
+ import type { Workspace } from '@nebulr-group/bridge-auth-core';
5
5
  import { onMount } from 'svelte';
6
6
  import { getBridgeAuth, profileStore } from '../../../core/bridge-instance.js';
7
7
  import Spinner from './shared/Spinner.svelte';
8
8
  import Alert from './shared/Alert.svelte';
9
9
 
10
- interface Props extends HTMLDivAttributes {
10
+ interface Props extends HTMLAttributes<HTMLDivElement> {
11
11
  onSwitch?: () => void;
12
12
  onError?: (error: Error) => void;
13
13
  workspaceItem?: Snippet<[{ workspace: Workspace; isActive: boolean; isLoading: boolean; onSelect: () => void }]>;
@@ -1,7 +1,7 @@
1
- import type { HTMLDivAttributes } from 'svelte/elements';
1
+ import type { HTMLAttributes } from 'svelte/elements';
2
2
  import type { Snippet } from 'svelte';
3
- import type { Workspace } from '@thebridge/auth-core';
4
- interface Props extends HTMLDivAttributes {
3
+ import type { Workspace } from '@nebulr-group/bridge-auth-core';
4
+ interface Props extends HTMLAttributes<HTMLDivElement> {
5
5
  onSwitch?: () => void;
6
6
  onError?: (error: Error) => void;
7
7
  workspaceItem?: Snippet<[{