@nebulr-group/bridge-svelte 0.4.0-beta.2 → 0.4.0-beta.3
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/client/BridgeBootstrap.js +11 -6
- package/dist/core/bridge-instance.d.ts +0 -3
- package/dist/core/bridge-instance.js +4 -10
- package/dist/core/bridge.d.ts +3 -4
- package/dist/core/bridge.js +3 -4
- package/dist/core/bridge.test.js +2 -2
- package/dist/flags/bootstrap.js +2 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.js +1 -3
- package/package.json +1 -1
- package/dist/client/components/FeatureFlag.svelte +0 -37
- package/dist/client/components/FeatureFlag.svelte.d.ts +0 -15
- package/dist/shared/feature-flag.d.ts +0 -6
- package/dist/shared/feature-flag.js +0 -13
|
@@ -5,7 +5,6 @@ import { createRouteGuard } from '../auth/route-guard.js';
|
|
|
5
5
|
import { getBridgeAuth, bridgeReadyStore, markReady, waitForBridge as _waitForBridge, } from '../core/bridge-instance.js';
|
|
6
6
|
import { installBridgeAuthFetch } from '../core/bridge-runtime.js';
|
|
7
7
|
import { useBridge } from '@nebulr-group/bridge-auth-core';
|
|
8
|
-
import { featureFlags } from '../shared/feature-flag.js';
|
|
9
8
|
import { logger } from '../shared/logger.js';
|
|
10
9
|
import { bridgeConfig, getConfig } from './stores/config.store.js';
|
|
11
10
|
export async function bridgeBootstrap(url, config, routeConfig = { rules: [], defaultAccess: 'protected' }, kitFetch) {
|
|
@@ -158,11 +157,17 @@ export async function bridgeBootstrap(url, config, routeConfig = { rules: [], de
|
|
|
158
157
|
catch {
|
|
159
158
|
// Non-fatal — gate fails open; the notice hydrates lazily on first render.
|
|
160
159
|
}
|
|
161
|
-
// 3.
|
|
162
|
-
//
|
|
163
|
-
//
|
|
164
|
-
//
|
|
165
|
-
|
|
160
|
+
// 3. Warm the route-guard's flag cache without awaiting so GQL queries can
|
|
161
|
+
// start in parallel. `loadFeatureFlags()` populates the same auth-core
|
|
162
|
+
// FeatureFlagService the route guard evaluates `featureFlag` rules
|
|
163
|
+
// against; the flagsReady promise is passed to the guard and returned to
|
|
164
|
+
// callers so routes that gate on flags can await before rendering.
|
|
165
|
+
// (Component/programmatic flag reads use FF 2.0 `useFlag` / <FeatureFlag>.)
|
|
166
|
+
// Errors are logged, never thrown — flag failures must not crash bootstrap.
|
|
167
|
+
const flagsReady = getBridgeAuth()
|
|
168
|
+
.loadFeatureFlags()
|
|
169
|
+
.then(() => { })
|
|
170
|
+
.catch((err) => {
|
|
166
171
|
logger.warn('[bridgeBootstrap] Feature flags failed to load:', err);
|
|
167
172
|
});
|
|
168
173
|
// 4. Handle route guarding and redirects
|
|
@@ -39,8 +39,6 @@ export declare const isOnboarded: Readable<boolean>;
|
|
|
39
39
|
export declare const hasMultiTenantAccess: Readable<boolean>;
|
|
40
40
|
/** Tenant users for multi-tenant selection */
|
|
41
41
|
export declare const tenantUsersStore: Readable<TenantUser[]>;
|
|
42
|
-
/** Feature flags map */
|
|
43
|
-
export declare const flagsStore: Readable<Record<string, boolean>>;
|
|
44
42
|
/** Bridge ready state */
|
|
45
43
|
export declare const bridgeReadyStore: Readable<boolean>;
|
|
46
44
|
/** App-level config (SSO providers, feature flags, etc.) — loaded anonymously on init */
|
|
@@ -56,6 +54,5 @@ export declare const subscriptionStore: Readable<SubscriptionState>;
|
|
|
56
54
|
export declare function loadSubscription(): Promise<void>;
|
|
57
55
|
/** Lazy proxy to the BridgeAuth singleton — call methods directly: `auth.getToken()`, `auth.logout()`, etc. */
|
|
58
56
|
export declare const auth: BridgeAuth;
|
|
59
|
-
export declare const _flagsWritable: Writable<Record<string, boolean>>;
|
|
60
57
|
export declare const _profileWritable: Writable<Profile | null | undefined>;
|
|
61
58
|
export declare const _errorWritable: Writable<string | null>;
|
|
@@ -14,7 +14,6 @@ let _instance = null;
|
|
|
14
14
|
const _tokens = writable(null);
|
|
15
15
|
const _appConfig = writable(null);
|
|
16
16
|
const _profile = writable(undefined);
|
|
17
|
-
const _flags = writable({});
|
|
18
17
|
const _authState = writable('unauthenticated');
|
|
19
18
|
const _isLoading = writable(true);
|
|
20
19
|
const _error = writable(null);
|
|
@@ -46,19 +45,18 @@ export function initBridge(config) {
|
|
|
46
45
|
if (existingTokens) {
|
|
47
46
|
_tokens.set(existingTokens);
|
|
48
47
|
// Fetch profile for existing tokens
|
|
49
|
-
_instance.getProfile().then((p) => _profile.set(p ?? null)).catch(() =>
|
|
48
|
+
_instance.getProfile().then((p) => _profile.set(p ?? null)).catch((err) => logger.warn('[bridge-instance] profile fetch failed:', err));
|
|
50
49
|
}
|
|
51
50
|
_authState.set(_instance.getAuthState());
|
|
52
51
|
_isLoading.set(false);
|
|
53
52
|
// Wire auth-core events → Svelte stores
|
|
54
53
|
_instance.on('auth:login', (tokens) => {
|
|
55
54
|
_tokens.set(tokens);
|
|
56
|
-
_instance.getProfile().then((p) => _profile.set(p ?? null)).catch(() =>
|
|
55
|
+
_instance.getProfile().then((p) => _profile.set(p ?? null)).catch((err) => logger.warn('[bridge-instance] profile fetch failed:', err));
|
|
57
56
|
});
|
|
58
57
|
_instance.on('auth:logout', () => {
|
|
59
58
|
_tokens.set(null);
|
|
60
59
|
_profile.set(null);
|
|
61
|
-
_flags.set({});
|
|
62
60
|
});
|
|
63
61
|
_instance.on('auth:token-refreshed', (tokens) => {
|
|
64
62
|
_tokens.set(tokens);
|
|
@@ -77,9 +75,8 @@ export function initBridge(config) {
|
|
|
77
75
|
});
|
|
78
76
|
_instance.on('auth:workspace-changed', (tokens) => {
|
|
79
77
|
_tokens.set(tokens);
|
|
80
|
-
_flags.set({});
|
|
81
78
|
_subscriptionWritable.set({ status: null, plans: null, loading: false, error: null });
|
|
82
|
-
_instance.getProfile().then((p) => _profile.set(p ?? null)).catch(() =>
|
|
79
|
+
_instance.getProfile().then((p) => _profile.set(p ?? null)).catch((err) => logger.warn('[bridge-instance] profile fetch failed:', err));
|
|
83
80
|
});
|
|
84
81
|
_instance.on('auth:error', (err) => {
|
|
85
82
|
_error.set(err.message);
|
|
@@ -150,8 +147,6 @@ export const isOnboarded = _isOnboarded;
|
|
|
150
147
|
export const hasMultiTenantAccess = _hasMultiTenantAccess;
|
|
151
148
|
/** Tenant users for multi-tenant selection */
|
|
152
149
|
export const tenantUsersStore = _tenantUsers;
|
|
153
|
-
/** Feature flags map */
|
|
154
|
-
export const flagsStore = _flags;
|
|
155
150
|
/** Bridge ready state */
|
|
156
151
|
export const bridgeReadyStore = _ready;
|
|
157
152
|
/** App-level config (SSO providers, feature flags, etc.) — loaded anonymously on init */
|
|
@@ -183,11 +178,10 @@ export async function loadSubscription() {
|
|
|
183
178
|
export const auth = new Proxy({}, {
|
|
184
179
|
get(_, prop) {
|
|
185
180
|
const instance = getBridgeAuth();
|
|
186
|
-
const value = instance
|
|
181
|
+
const value = Reflect.get(instance, prop);
|
|
187
182
|
return typeof value === 'function' ? value.bind(instance) : value;
|
|
188
183
|
},
|
|
189
184
|
});
|
|
190
185
|
// ── Internal-only store writers (for use by wrapper modules) ───────────────────
|
|
191
|
-
export const _flagsWritable = _flags;
|
|
192
186
|
export const _profileWritable = _profile;
|
|
193
187
|
export const _errorWritable = _error;
|
package/dist/core/bridge.d.ts
CHANGED
|
@@ -8,10 +8,9 @@
|
|
|
8
8
|
* follow-up sub-tickets (TBP-322 `.load()` semantics + TBP-323 reactive
|
|
9
9
|
* binding for loaded slices).
|
|
10
10
|
*
|
|
11
|
-
* Backward compat: this is purely additive. The
|
|
12
|
-
* (`subscriptionStore`, `
|
|
13
|
-
*
|
|
14
|
-
* in deprecation warnings; for now both surfaces coexist.
|
|
11
|
+
* Backward compat: this is purely additive. The module-level stores
|
|
12
|
+
* (`subscriptionStore`, `appConfigStore`, etc.) continue to exist and are
|
|
13
|
+
* populated by the same internal state; both surfaces coexist.
|
|
15
14
|
*
|
|
16
15
|
* Note: `useBridge()` (Svelte context hook) lands in TBP-320. This module
|
|
17
16
|
* only exposes the singleton aggregate `bridge`; consumers can import it
|
package/dist/core/bridge.js
CHANGED
|
@@ -8,10 +8,9 @@
|
|
|
8
8
|
* follow-up sub-tickets (TBP-322 `.load()` semantics + TBP-323 reactive
|
|
9
9
|
* binding for loaded slices).
|
|
10
10
|
*
|
|
11
|
-
* Backward compat: this is purely additive. The
|
|
12
|
-
* (`subscriptionStore`, `
|
|
13
|
-
*
|
|
14
|
-
* in deprecation warnings; for now both surfaces coexist.
|
|
11
|
+
* Backward compat: this is purely additive. The module-level stores
|
|
12
|
+
* (`subscriptionStore`, `appConfigStore`, etc.) continue to exist and are
|
|
13
|
+
* populated by the same internal state; both surfaces coexist.
|
|
15
14
|
*
|
|
16
15
|
* Note: `useBridge()` (Svelte context hook) lands in TBP-320. This module
|
|
17
16
|
* only exposes the singleton aggregate `bridge`; consumers can import it
|
package/dist/core/bridge.test.js
CHANGED
|
@@ -218,7 +218,7 @@ describe('bridge.app.plans lazy slice (Phase 4, TBP-321/322)', () => {
|
|
|
218
218
|
});
|
|
219
219
|
it('apply() updates a loaded slice (TBP-323 reactive binding primitive)', async () => {
|
|
220
220
|
await bridge.app.plans.load();
|
|
221
|
-
bridge.app.plans.apply([{ key: 'enterprise', name: 'Enterprise' }]);
|
|
222
|
-
expect(get(bridge.app.plans)).toEqual([{ key: 'enterprise', name: 'Enterprise' }]);
|
|
221
|
+
bridge.app.plans.apply([{ key: 'enterprise', name: 'Enterprise', prices: [] }]);
|
|
222
|
+
expect(get(bridge.app.plans)).toEqual([{ key: 'enterprise', name: 'Enterprise', prices: [] }]);
|
|
223
223
|
});
|
|
224
224
|
});
|
package/dist/flags/bootstrap.js
CHANGED
|
@@ -27,11 +27,10 @@ export class BrowserIdentityStorage {
|
|
|
27
27
|
constructor(mode, key = 'bridge.anon_id') {
|
|
28
28
|
this.mode = mode;
|
|
29
29
|
this.key = key;
|
|
30
|
-
if (typeof
|
|
30
|
+
if (typeof window === 'undefined') {
|
|
31
31
|
throw new Error('BrowserIdentityStorage requires a window — use MemoryIdentityStorage on the server');
|
|
32
32
|
}
|
|
33
|
-
|
|
34
|
-
this.storage = mode === 'persistent' ? w.localStorage : w.sessionStorage;
|
|
33
|
+
this.storage = mode === 'persistent' ? window.localStorage : window.sessionStorage;
|
|
35
34
|
}
|
|
36
35
|
read() {
|
|
37
36
|
try {
|
package/dist/index.d.ts
CHANGED
|
@@ -5,10 +5,10 @@ export type { SubscriptionState } from './core/bridge-instance.js';
|
|
|
5
5
|
export { bridge } from './core/bridge.js';
|
|
6
6
|
export type { BridgeSurface, BridgeAppSurface, BridgeTenantSurface, } from './core/bridge.js';
|
|
7
7
|
export type { BrandingSnapshot, SubscriptionSnapshot, UserSnapshot, SessionSnapshotData, } from './core/snapshot-stores.js';
|
|
8
|
-
export type { BridgeEventHandlers } from './core/events.js';
|
|
8
|
+
export type { BridgeEventHandlers, BridgeEventsDispatcher } from './core/events.js';
|
|
9
9
|
export { default as BridgeBootstrap, default as BridgeProvider } from './client/BridgeBootstrap.svelte';
|
|
10
10
|
export { default as ApiTokenManagement } from './client/components/developer/ApiTokenManagement.svelte';
|
|
11
|
-
export { default as FeatureFlag } from './
|
|
11
|
+
export { default as FeatureFlag } from './flags/FeatureFlag.svelte';
|
|
12
12
|
export { default as ProfileName } from './client/components/ProfileName.svelte';
|
|
13
13
|
export { default as TeamManagementPanel } from './client/components/team/TeamManagementPanel.svelte';
|
|
14
14
|
export { default as TeamUserList } from './client/components/team/TeamUserList.svelte';
|
|
@@ -31,7 +31,6 @@ export { default as BridgeSubscriptionStatus } from './client/components/subscri
|
|
|
31
31
|
export { default as BridgeBillingNotice } from './client/components/subscription/BridgeBillingNotice.svelte';
|
|
32
32
|
export { default as BridgePaywall } from './client/components/subscription/BridgePaywall.svelte';
|
|
33
33
|
export { default as BridgeQuotaBanner } from './client/components/subscription/BridgeQuotaBanner.svelte';
|
|
34
|
-
export * from './shared/feature-flag.js';
|
|
35
34
|
export * from './auth/route-guard.js';
|
|
36
35
|
export * from './shared/profile.js';
|
|
37
36
|
export * from './shared/types/config.js';
|
|
@@ -41,6 +40,7 @@ export type { RedditConversionEvent, RedditEcommerce, RedditEcommerceItem, Reddi
|
|
|
41
40
|
export { sha256Email } from './client/tracking/pii-hashing.js';
|
|
42
41
|
export type { AuthConfigResponse, AuthResult, AuthState, BridgeAuthConfig, BridgeAuthEventName, BridgeAuthEvents, FederationConnection, MagicLinkResult, MfaResult, PasskeyAuthOptions, PasskeyRegistrationOptions, PasskeyVerificationResult, SignupResult, SsoOptions, SsoResult, TenantUser, } from '@nebulr-group/bridge-auth-core';
|
|
43
42
|
export { BridgeAuth, BridgeAuthError, HttpError, TeamService, ApiTokenService } from '@nebulr-group/bridge-auth-core';
|
|
43
|
+
export type { SessionStalePayload } from '@nebulr-group/bridge-auth-core';
|
|
44
44
|
export type { ApiToken, CreateApiTokenInput, CreateApiTokenResponse, } from '@nebulr-group/bridge-auth-core';
|
|
45
45
|
export type { TeamProfile, TeamProfileUpdateInput, TeamUser, TeamUserListResult, TeamUserUpdateInput, TeamWorkspace, TeamWorkspaceUpdateInput, } from '@nebulr-group/bridge-auth-core';
|
|
46
46
|
export type { Plan, PriceOfferSdk, SubscriptionStatus, CheckoutSession, Workspace, } from '@nebulr-group/bridge-auth-core';
|
package/dist/index.js
CHANGED
|
@@ -16,7 +16,7 @@ export { bridge } from './core/bridge.js';
|
|
|
16
16
|
// Components (Svelte components must have `export default`)
|
|
17
17
|
export { default as BridgeBootstrap, default as BridgeProvider } from './client/BridgeBootstrap.svelte';
|
|
18
18
|
export { default as ApiTokenManagement } from './client/components/developer/ApiTokenManagement.svelte';
|
|
19
|
-
export { default as FeatureFlag } from './
|
|
19
|
+
export { default as FeatureFlag } from './flags/FeatureFlag.svelte';
|
|
20
20
|
export { default as ProfileName } from './client/components/ProfileName.svelte';
|
|
21
21
|
export { default as TeamManagementPanel } from './client/components/team/TeamManagementPanel.svelte';
|
|
22
22
|
export { default as TeamUserList } from './client/components/team/TeamUserList.svelte';
|
|
@@ -49,8 +49,6 @@ export { default as BridgeBillingNotice } from './client/components/subscription
|
|
|
49
49
|
export { default as BridgePaywall } from './client/components/subscription/BridgePaywall.svelte';
|
|
50
50
|
// Billing 2.0 (Phase C / US-11) — live quota counter banner.
|
|
51
51
|
export { default as BridgeQuotaBanner } from './client/components/subscription/BridgeQuotaBanner.svelte';
|
|
52
|
-
// Feature flags
|
|
53
|
-
export * from './shared/feature-flag.js';
|
|
54
52
|
// Auth route guards
|
|
55
53
|
export * from './auth/route-guard.js';
|
|
56
54
|
// Types
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nebulr-group/bridge-svelte",
|
|
3
|
-
"version": "0.4.0-beta.
|
|
3
|
+
"version": "0.4.0-beta.3",
|
|
4
4
|
"description": "Bridge Svelte library, This library helps you to add bridge authentication and feature flags, and payments to your svelte application.",
|
|
5
5
|
"author": "Iman Pouya",
|
|
6
6
|
"license": "MIT",
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
<script lang="ts">
|
|
2
|
-
import type { Snippet } from 'svelte';
|
|
3
|
-
import { onMount } from 'svelte';
|
|
4
|
-
import { isFeatureEnabled } from '../../shared/feature-flag.js';
|
|
5
|
-
|
|
6
|
-
type FlagRenderArgs = { enabled: boolean; rawEnabled: boolean };
|
|
7
|
-
|
|
8
|
-
let {
|
|
9
|
-
flagName,
|
|
10
|
-
forceLive = false,
|
|
11
|
-
negate = false,
|
|
12
|
-
renderWhenDisabled = false,
|
|
13
|
-
children
|
|
14
|
-
}: {
|
|
15
|
-
flagName: string;
|
|
16
|
-
forceLive?: boolean;
|
|
17
|
-
negate?: boolean;
|
|
18
|
-
renderWhenDisabled?: boolean;
|
|
19
|
-
children?: Snippet<[FlagRenderArgs]>;
|
|
20
|
-
} = $props();
|
|
21
|
-
|
|
22
|
-
let enabled = $state(false);
|
|
23
|
-
let rawEnabled = $derived(enabled);
|
|
24
|
-
let effectiveEnabled = $derived(negate ? !enabled : enabled);
|
|
25
|
-
|
|
26
|
-
onMount(async () => {
|
|
27
|
-
enabled = await isFeatureEnabled(flagName, forceLive);
|
|
28
|
-
});
|
|
29
|
-
</script>
|
|
30
|
-
|
|
31
|
-
{#if children}
|
|
32
|
-
{#if renderWhenDisabled}
|
|
33
|
-
{@render children({ enabled: effectiveEnabled, rawEnabled })}
|
|
34
|
-
{:else if effectiveEnabled}
|
|
35
|
-
{@render children({ enabled: true, rawEnabled })}
|
|
36
|
-
{/if}
|
|
37
|
-
{/if}
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import type { Snippet } from 'svelte';
|
|
2
|
-
type FlagRenderArgs = {
|
|
3
|
-
enabled: boolean;
|
|
4
|
-
rawEnabled: boolean;
|
|
5
|
-
};
|
|
6
|
-
type $$ComponentProps = {
|
|
7
|
-
flagName: string;
|
|
8
|
-
forceLive?: boolean;
|
|
9
|
-
negate?: boolean;
|
|
10
|
-
renderWhenDisabled?: boolean;
|
|
11
|
-
children?: Snippet<[FlagRenderArgs]>;
|
|
12
|
-
};
|
|
13
|
-
declare const FeatureFlag: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
14
|
-
type FeatureFlag = ReturnType<typeof FeatureFlag>;
|
|
15
|
-
export default FeatureFlag;
|
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
export declare function loadFeatureFlags(): Promise<void>;
|
|
2
|
-
export declare function isFeatureEnabled(flag: string, forceLive?: boolean): Promise<boolean>;
|
|
3
|
-
export declare const featureFlags: {
|
|
4
|
-
flags: import("svelte/store").Writable<Record<string, boolean>>;
|
|
5
|
-
refresh: typeof loadFeatureFlags;
|
|
6
|
-
};
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
// src/lib/shared/feature-flag.ts — thin wrapper delegating to bridge-instance
|
|
2
|
-
import { getBridgeAuth, _flagsWritable, flagsStore } from '../core/bridge-instance.js';
|
|
3
|
-
export async function loadFeatureFlags() {
|
|
4
|
-
const flags = await getBridgeAuth().loadFeatureFlags();
|
|
5
|
-
_flagsWritable.set(flags);
|
|
6
|
-
}
|
|
7
|
-
export async function isFeatureEnabled(flag, forceLive = false) {
|
|
8
|
-
return getBridgeAuth().isFeatureEnabled(flag, { forceLive });
|
|
9
|
-
}
|
|
10
|
-
export const featureFlags = {
|
|
11
|
-
flags: flagsStore,
|
|
12
|
-
refresh: loadFeatureFlags
|
|
13
|
-
};
|