@nexussdk/sdk 0.0.1 â 0.0.4
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/README.md +162 -0
- package/dist/index.cjs +2 -2
- package/dist/index.d.mts +41 -45
- package/dist/index.d.ts +41 -45
- package/dist/index.global.js +4 -4
- package/dist/index.mjs +2 -2
- package/dist/react.cjs +2 -2
- package/dist/react.d.mts +111 -76
- package/dist/react.d.ts +111 -76
- package/dist/react.mjs +2 -2
- package/dist/vue.cjs +2 -0
- package/dist/vue.d.mts +234 -0
- package/dist/vue.d.ts +234 -0
- package/dist/vue.mjs +2 -0
- package/package.json +62 -9
- package/.turbo/turbo-build.log +0 -45
- package/dist/index.cjs.map +0 -1
- package/dist/index.global.js.map +0 -1
- package/dist/index.mjs.map +0 -1
- package/dist/react.cjs.map +0 -1
- package/dist/react.mjs.map +0 -1
- package/src/index.ts +0 -27
- package/src/nexus.ts +0 -208
- package/src/react.tsx +0 -204
- package/tsconfig.json +0 -10
- package/tsup.config.ts +0 -40
package/README.md
ADDED
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
# @nexussdk/sdk
|
|
2
|
+
|
|
3
|
+
The official umbrella client SDK for the **Nexus Platform** â high-performance feature flags, error telemetry, and React hooks with zero runtime bloat (<8KB gzipped).
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/@nexussdk/sdk)
|
|
6
|
+
[](https://opensource.org/licenses/MIT)
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## Features
|
|
11
|
+
|
|
12
|
+
- ðĐ **Feature Flags & Remote Config**: Deterministic Murmur3 hashing, ABAC evaluation rules, and real-time SSE streaming updates.
|
|
13
|
+
- ⥠**Error Telemetry & Monitoring**: Automatic uncaught exception catching, unhandled promise rejection tracking, and regex-based PII scrubbing.
|
|
14
|
+
- âïļ **First-Class React 19 Support**: Idiomatic hooks (`useFlag`, `useNexus`) and `NexusProvider` context wrapper.
|
|
15
|
+
- ðŠķ **Ultra Lightweight**: Zero heavy dependencies, tree-shakeable, and sub-8KB gzipped footprint.
|
|
16
|
+
- ð **Type Safe**: Strict TypeScript contracts and autocomplete out of the box.
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## Installation
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
# npm
|
|
24
|
+
npm install @nexussdk/sdk
|
|
25
|
+
|
|
26
|
+
# pnpm
|
|
27
|
+
pnpm add @nexussdk/sdk
|
|
28
|
+
|
|
29
|
+
# yarn
|
|
30
|
+
yarn add @nexussdk/sdk
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
## Quick Start (Vanilla / Node / Browser)
|
|
36
|
+
|
|
37
|
+
```typescript
|
|
38
|
+
import { createNexus } from '@nexussdk/sdk';
|
|
39
|
+
|
|
40
|
+
const nexus = createNexus({
|
|
41
|
+
clientKey: 'pk_live_your_client_key',
|
|
42
|
+
baseUrl: 'https://api.nexusplatform.io',
|
|
43
|
+
environment: 'production',
|
|
44
|
+
user: {
|
|
45
|
+
id: 'usr_123',
|
|
46
|
+
email: 'user@example.com',
|
|
47
|
+
role: 'premium',
|
|
48
|
+
},
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
// 1. Evaluate feature flag
|
|
52
|
+
const isNewCheckout = await nexus.flags.isEnabled('new-checkout-flow', false);
|
|
53
|
+
if (isNewCheckout) {
|
|
54
|
+
// Render new checkout
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// 2. Capture error with breadcrumbs
|
|
58
|
+
try {
|
|
59
|
+
// your app logic
|
|
60
|
+
} catch (error) {
|
|
61
|
+
nexus.tracker.captureException(error, {
|
|
62
|
+
tags: { module: 'checkout' },
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
---
|
|
68
|
+
|
|
69
|
+
## React Integration
|
|
70
|
+
|
|
71
|
+
Wrap your application in `NexusProvider`:
|
|
72
|
+
|
|
73
|
+
```tsx
|
|
74
|
+
import React from 'react';
|
|
75
|
+
import { NexusProvider, useFlag, useNexus } from '@nexussdk/sdk/react';
|
|
76
|
+
|
|
77
|
+
function App() {
|
|
78
|
+
return (
|
|
79
|
+
<NexusProvider
|
|
80
|
+
config={{
|
|
81
|
+
clientKey: 'pk_live_your_client_key',
|
|
82
|
+
baseUrl: 'https://api.nexusplatform.io',
|
|
83
|
+
}}
|
|
84
|
+
>
|
|
85
|
+
<CheckoutPage />
|
|
86
|
+
</NexusProvider>
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function CheckoutPage() {
|
|
91
|
+
const isV2Enabled = useFlag('v2-checkout-button', false);
|
|
92
|
+
const nexus = useNexus();
|
|
93
|
+
|
|
94
|
+
const handleCheckout = () => {
|
|
95
|
+
nexus.tracker.addBreadcrumb('Clicked checkout', 'ui');
|
|
96
|
+
// Proceed to checkout
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
return (
|
|
100
|
+
<button onClick={handleCheckout}>
|
|
101
|
+
{isV2Enabled ? 'Express Checkout' : 'Standard Checkout'}
|
|
102
|
+
</button>
|
|
103
|
+
);
|
|
104
|
+
}
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
---
|
|
108
|
+
|
|
109
|
+
## Vue 3 & Nuxt 4 Integration
|
|
110
|
+
|
|
111
|
+
Install `NexusPlugin` and use the `<NexusGuard>` error boundary component:
|
|
112
|
+
|
|
113
|
+
```typescript
|
|
114
|
+
// main.ts
|
|
115
|
+
import { createApp } from 'vue';
|
|
116
|
+
import { NexusPlugin } from '@nexussdk/sdk/vue';
|
|
117
|
+
import App from './App.vue';
|
|
118
|
+
|
|
119
|
+
const app = createApp(App);
|
|
120
|
+
app.use(NexusPlugin, {
|
|
121
|
+
apiKey: 'pk_live_your_client_key',
|
|
122
|
+
environment: 'production',
|
|
123
|
+
autoCapture: true,
|
|
124
|
+
realtime: true,
|
|
125
|
+
});
|
|
126
|
+
app.mount('#app');
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
```vue
|
|
130
|
+
<!-- App.vue -->
|
|
131
|
+
<script setup lang="ts">
|
|
132
|
+
import { useFeatureFlag, NexusGuard } from '@nexussdk/sdk/vue';
|
|
133
|
+
|
|
134
|
+
const { isEnabled } = useFeatureFlag('new-checkout-flow', false);
|
|
135
|
+
</script>
|
|
136
|
+
|
|
137
|
+
<template>
|
|
138
|
+
<NexusGuard>
|
|
139
|
+
<button v-if="isEnabled">1-Click Express Checkout</button>
|
|
140
|
+
<button v-else>Standard Checkout</button>
|
|
141
|
+
</NexusGuard>
|
|
142
|
+
</template>
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
---
|
|
146
|
+
|
|
147
|
+
## Architecture & Subpackages
|
|
148
|
+
|
|
149
|
+
`@nexussdk/sdk` bundles the following specialized modules for maximum modularity:
|
|
150
|
+
|
|
151
|
+
| Package | Role |
|
|
152
|
+
|---|---|
|
|
153
|
+
| [`@nexussdk/contracts`](https://www.npmjs.com/package/@nexussdk/contracts) | SSOT TypeScript types and RFC 7807 error models |
|
|
154
|
+
| [`@nexussdk/core`](https://www.npmjs.com/package/@nexussdk/core) | Ring buffer transport kernel and environment resolvers |
|
|
155
|
+
| [`@nexussdk/flags`](https://www.npmjs.com/package/@nexussdk/flags) | Standalone feature flag evaluator, local dev server (`nexus-flags-dev`) & SSE manager |
|
|
156
|
+
| [`@nexussdk/tracker`](https://www.npmjs.com/package/@nexussdk/tracker) | Standalone error tracker, local dev server (`nexus-dev`) & PII sanitizer |
|
|
157
|
+
|
|
158
|
+
---
|
|
159
|
+
|
|
160
|
+
## License
|
|
161
|
+
|
|
162
|
+
MIT ÂĐ [Nexus Platform](https://github.com/Huynhdung295/NexusSDK)
|
package/dist/index.cjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
'use strict';var flags=require('@nexussdk/flags'),tracker=require('@nexussdk/tracker');var
|
|
2
|
-
|
|
1
|
+
'use strict';var flags=require('@nexussdk/flags'),tracker=require('@nexussdk/tracker');var o=class t{static instance=null;static vitalsCleanup=null;flags;tracker;constructor(e={}){let{apiKey:r,baseUrl:s,user:u,environment:p,tags:g,autoCapture:x,sampling:d,transport:f,vitals:n,devServer:a,flags:v,tracker:m}=e;this.flags=new flags.NexusFlagsClient({apiKey:r,baseUrl:s,user:u,...v});let l=s,b=f;if(a?.enabled){let i=a.port??4567;l=`http://${a.host??"localhost"}:${i}`;}if(this.tracker=new tracker.NexusTrackerClient({apiKey:r,baseUrl:l,environment:p,tags:g,autoCapture:x,sampling:d,transport:b,...m}),n){let i=typeof n=="object"?n:{};t.vitalsCleanup=tracker.attachWebVitals(this.tracker,i);}}static init(e={}){return t.instance||(t.instance=new t(e)),t.instance}static getInstance(){if(!t.instance)throw new Error('[Nexus SDK] Not initialized. Call Nexus.init({ apiKey: "..." }) first.');return t.instance}static isEnabled(e,r=false){return t.getInstance().flags.isEnabled(e,r)}static getVariant(e,r,s){return t.getInstance().flags.getVariant(e,r,s)}static captureError(e,r){t.getInstance().tracker.captureError(e,r);}static captureMessage(e,r="info",s){t.getInstance().tracker.captureMessage(e,r,s);}static addBreadcrumb(e){t.getInstance().tracker.addBreadcrumb(e);}static setExtra(e,r){t.getInstance().tracker.setExtra(e,r);}static attachWebVitals(e){return tracker.attachWebVitals(t.getInstance().tracker,e)}static async identify(e){let r=t.getInstance();r.tracker.setUser(e),await r.flags.identify(e);}static reset(){let e=t.getInstance();e.tracker.setUser(null),e.flags.reset();}static async destroy(){t.vitalsCleanup&&(t.vitalsCleanup(),t.vitalsCleanup=null),t.instance&&(await t.instance.tracker.flush(),t.instance.tracker.destroy(),t.instance.flags.destroy(),t.instance=null);}};
|
|
2
|
+
Object.defineProperty(exports,"NexusFlagsClient",{enumerable:true,get:function(){return flags.NexusFlagsClient}});Object.defineProperty(exports,"NexusGuardCore",{enumerable:true,get:function(){return tracker.NexusGuardCore}});Object.defineProperty(exports,"NexusTrackerClient",{enumerable:true,get:function(){return tracker.NexusTrackerClient}});Object.defineProperty(exports,"attachWebVitals",{enumerable:true,get:function(){return tracker.attachWebVitals}});exports.Nexus=o;
|
package/dist/index.d.mts
CHANGED
|
@@ -1,25 +1,36 @@
|
|
|
1
1
|
import { NexusFlagsClient, NexusFlagsOptions } from '@nexussdk/flags';
|
|
2
2
|
export { INexusFlagsClient, NexusFlagsClient, NexusFlagsOptions } from '@nexussdk/flags';
|
|
3
3
|
import { NexusTrackerClient, NexusTrackerOptions } from '@nexussdk/tracker';
|
|
4
|
-
export { INexusTrackerClient, NexusTrackerClient, NexusTrackerOptions } from '@nexussdk/tracker';
|
|
5
|
-
import { UserContext } from '@nexussdk/contracts';
|
|
6
|
-
export { ErrorEventPayload, FeatureFlag, FlagEvaluationResult, ProblemDetails, UserContext } from '@nexussdk/contracts';
|
|
4
|
+
export { INexusTrackerClient, NexusGuardCore, NexusGuardCoreOptions, NexusTrackerClient, NexusTrackerOptions, attachWebVitals } from '@nexussdk/tracker';
|
|
5
|
+
import { UserContext, SamplingConfig, TransportPlugin, PerformanceVitalsOptions, SeverityLevel, Breadcrumb } from '@nexussdk/contracts';
|
|
6
|
+
export { Breadcrumb, ErrorEventPayload, FeatureFlag, FlagEvaluationResult, NexusErrorInfo, PerformanceVitalEntry, PerformanceVitalsOptions, ProblemDetails, SamplingConfig, SeverityLevel, TransportPlugin, UserContext } from '@nexussdk/contracts';
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
9
|
* @fileoverview Unified Nexus singleton facade wrapping Flags and Tracker clients.
|
|
10
10
|
* @module @nexus/sdk/nexus
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
|
+
/**
|
|
14
|
+
* Dev server routing configuration.
|
|
15
|
+
*/
|
|
16
|
+
interface NexusDevServerOptions {
|
|
17
|
+
/** Enable local dev server ingestion mode. Auto-enabled in development if true. */
|
|
18
|
+
enabled?: boolean;
|
|
19
|
+
/** Port the dev server is listening on. Defaults to 4567. */
|
|
20
|
+
port?: number;
|
|
21
|
+
/** Host the dev server is bound to. Defaults to 'localhost'. */
|
|
22
|
+
host?: string;
|
|
23
|
+
}
|
|
13
24
|
/**
|
|
14
25
|
* Unified initialization options for the Nexus SDK umbrella.
|
|
15
26
|
*
|
|
16
27
|
* @example
|
|
17
28
|
* Nexus.init({
|
|
18
29
|
* apiKey: 'pk_live_...',
|
|
19
|
-
* baseUrl: 'http://localhost:8080',
|
|
20
30
|
* user: { id: 'usr_12345', country: 'VN' },
|
|
21
31
|
* environment: 'production',
|
|
22
32
|
* autoCapture: true,
|
|
33
|
+
* devServer: { enabled: process.env.NODE_ENV === 'development' },
|
|
23
34
|
* });
|
|
24
35
|
*/
|
|
25
36
|
interface NexusInitOptions {
|
|
@@ -35,6 +46,14 @@ interface NexusInitOptions {
|
|
|
35
46
|
tags?: Record<string, string>;
|
|
36
47
|
/** Toggle automated global error capture. Defaults to true. */
|
|
37
48
|
autoCapture?: boolean;
|
|
49
|
+
/** Client-side rate limiting and deduplication sampling options. */
|
|
50
|
+
sampling?: SamplingConfig;
|
|
51
|
+
/** Pluggable transport adapter ('fetch', 'console', 'localStorage', custom fn). */
|
|
52
|
+
transport?: TransportPlugin;
|
|
53
|
+
/** Web Vitals performance observer options, or true for default observation. */
|
|
54
|
+
vitals?: boolean | PerformanceVitalsOptions;
|
|
55
|
+
/** Local dev server auto-routing configuration. */
|
|
56
|
+
devServer?: NexusDevServerOptions;
|
|
38
57
|
/** Additional flags-specific options. */
|
|
39
58
|
flags?: Partial<NexusFlagsOptions>;
|
|
40
59
|
/** Additional tracker-specific options. */
|
|
@@ -61,6 +80,7 @@ interface NexusInitOptions {
|
|
|
61
80
|
*/
|
|
62
81
|
declare class Nexus {
|
|
63
82
|
private static instance;
|
|
83
|
+
private static vitalsCleanup;
|
|
64
84
|
/** The underlying feature flags client instance. */
|
|
65
85
|
readonly flags: NexusFlagsClient;
|
|
66
86
|
/** The underlying error tracker client instance. */
|
|
@@ -73,9 +93,6 @@ declare class Nexus {
|
|
|
73
93
|
*
|
|
74
94
|
* @param options - SDK configuration options.
|
|
75
95
|
* @returns The initialized Nexus singleton instance.
|
|
76
|
-
*
|
|
77
|
-
* @example
|
|
78
|
-
* const nexus = Nexus.init({ apiKey: 'pk_live_...' });
|
|
79
96
|
*/
|
|
80
97
|
static init(options?: NexusInitOptions): Nexus;
|
|
81
98
|
/**
|
|
@@ -83,69 +100,48 @@ declare class Nexus {
|
|
|
83
100
|
*
|
|
84
101
|
* @returns The active Nexus instance.
|
|
85
102
|
* @throws {Error} If `Nexus.init()` has not been called yet.
|
|
86
|
-
*
|
|
87
|
-
* @example
|
|
88
|
-
* const nexus = Nexus.getInstance();
|
|
89
|
-
* nexus.flags.isEnabled('checkout_v2');
|
|
90
103
|
*/
|
|
91
104
|
static getInstance(): Nexus;
|
|
92
105
|
/**
|
|
93
106
|
* Convenience method: Check if a feature flag is enabled.
|
|
94
|
-
*
|
|
95
|
-
* @param key - Flag identifier.
|
|
96
|
-
* @param defaultValue - Fallback if flag is missing.
|
|
97
|
-
* @returns Boolean enabled state.
|
|
98
|
-
*
|
|
99
|
-
* @example
|
|
100
|
-
* if (Nexus.isEnabled('checkout_redesign')) { ... }
|
|
101
107
|
*/
|
|
102
108
|
static isEnabled(key: string, defaultValue?: boolean): boolean;
|
|
103
109
|
/**
|
|
104
110
|
* Convenience method: Get a flag variant value.
|
|
105
|
-
*
|
|
106
|
-
* @param key - Flag identifier.
|
|
107
|
-
* @param variantKey - Variant property name.
|
|
108
|
-
* @param defaultValue - Fallback value.
|
|
109
|
-
* @returns Variant value cast to type T.
|
|
110
|
-
*
|
|
111
|
-
* @example
|
|
112
|
-
* const rate = Nexus.getVariant<number>('promo_banner_v2', 'discount_rate', 10);
|
|
113
111
|
*/
|
|
114
112
|
static getVariant<T = unknown>(key: string, variantKey: string, defaultValue?: T): T;
|
|
115
113
|
/**
|
|
116
114
|
* Convenience method: Capture an error manually.
|
|
117
|
-
*
|
|
118
|
-
* @param error - Error instance, string, or unknown value.
|
|
119
|
-
* @param extra - Optional metadata tags.
|
|
120
|
-
*
|
|
121
|
-
* @example
|
|
122
|
-
* Nexus.captureError(new TypeError('Cannot read properties of null'));
|
|
123
115
|
*/
|
|
124
116
|
static captureError(error: unknown, extra?: Record<string, unknown>): void;
|
|
117
|
+
/**
|
|
118
|
+
* Convenience method: Capture an informational or warning message event.
|
|
119
|
+
*/
|
|
120
|
+
static captureMessage(message: string, level?: SeverityLevel, extra?: Record<string, unknown>): void;
|
|
121
|
+
/**
|
|
122
|
+
* Convenience method: Add a breadcrumb manually.
|
|
123
|
+
*/
|
|
124
|
+
static addBreadcrumb(breadcrumb: Breadcrumb): void;
|
|
125
|
+
/**
|
|
126
|
+
* Convenience method: Set extra contextual metadata.
|
|
127
|
+
*/
|
|
128
|
+
static setExtra(key: string, value: unknown): void;
|
|
129
|
+
/**
|
|
130
|
+
* Convenience method: Attach Web Vitals observer to tracker.
|
|
131
|
+
*/
|
|
132
|
+
static attachWebVitals(options?: PerformanceVitalsOptions): () => void;
|
|
125
133
|
/**
|
|
126
134
|
* Convenience method: Update user context for both flags and tracker.
|
|
127
|
-
*
|
|
128
|
-
* @param user - New user context (merged with existing).
|
|
129
|
-
* @returns Promise resolving after flags refresh.
|
|
130
|
-
*
|
|
131
|
-
* @example
|
|
132
|
-
* await Nexus.identify({ id: 'usr_12345', country: 'VN' });
|
|
133
135
|
*/
|
|
134
136
|
static identify(user: UserContext): Promise<void>;
|
|
135
137
|
/**
|
|
136
138
|
* Resets user context to anonymous state (e.g. on logout).
|
|
137
|
-
*
|
|
138
|
-
* @example
|
|
139
|
-
* Nexus.reset(); // called on user logout
|
|
140
139
|
*/
|
|
141
140
|
static reset(): void;
|
|
142
141
|
/**
|
|
143
142
|
* Gracefully tears down both clients, closing SSE connections and flushing pending events.
|
|
144
|
-
*
|
|
145
|
-
* @example
|
|
146
|
-
* await Nexus.destroy();
|
|
147
143
|
*/
|
|
148
144
|
static destroy(): Promise<void>;
|
|
149
145
|
}
|
|
150
146
|
|
|
151
|
-
export { Nexus, type NexusInitOptions };
|
|
147
|
+
export { Nexus, type NexusDevServerOptions, type NexusInitOptions };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,25 +1,36 @@
|
|
|
1
1
|
import { NexusFlagsClient, NexusFlagsOptions } from '@nexussdk/flags';
|
|
2
2
|
export { INexusFlagsClient, NexusFlagsClient, NexusFlagsOptions } from '@nexussdk/flags';
|
|
3
3
|
import { NexusTrackerClient, NexusTrackerOptions } from '@nexussdk/tracker';
|
|
4
|
-
export { INexusTrackerClient, NexusTrackerClient, NexusTrackerOptions } from '@nexussdk/tracker';
|
|
5
|
-
import { UserContext } from '@nexussdk/contracts';
|
|
6
|
-
export { ErrorEventPayload, FeatureFlag, FlagEvaluationResult, ProblemDetails, UserContext } from '@nexussdk/contracts';
|
|
4
|
+
export { INexusTrackerClient, NexusGuardCore, NexusGuardCoreOptions, NexusTrackerClient, NexusTrackerOptions, attachWebVitals } from '@nexussdk/tracker';
|
|
5
|
+
import { UserContext, SamplingConfig, TransportPlugin, PerformanceVitalsOptions, SeverityLevel, Breadcrumb } from '@nexussdk/contracts';
|
|
6
|
+
export { Breadcrumb, ErrorEventPayload, FeatureFlag, FlagEvaluationResult, NexusErrorInfo, PerformanceVitalEntry, PerformanceVitalsOptions, ProblemDetails, SamplingConfig, SeverityLevel, TransportPlugin, UserContext } from '@nexussdk/contracts';
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
9
|
* @fileoverview Unified Nexus singleton facade wrapping Flags and Tracker clients.
|
|
10
10
|
* @module @nexus/sdk/nexus
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
|
+
/**
|
|
14
|
+
* Dev server routing configuration.
|
|
15
|
+
*/
|
|
16
|
+
interface NexusDevServerOptions {
|
|
17
|
+
/** Enable local dev server ingestion mode. Auto-enabled in development if true. */
|
|
18
|
+
enabled?: boolean;
|
|
19
|
+
/** Port the dev server is listening on. Defaults to 4567. */
|
|
20
|
+
port?: number;
|
|
21
|
+
/** Host the dev server is bound to. Defaults to 'localhost'. */
|
|
22
|
+
host?: string;
|
|
23
|
+
}
|
|
13
24
|
/**
|
|
14
25
|
* Unified initialization options for the Nexus SDK umbrella.
|
|
15
26
|
*
|
|
16
27
|
* @example
|
|
17
28
|
* Nexus.init({
|
|
18
29
|
* apiKey: 'pk_live_...',
|
|
19
|
-
* baseUrl: 'http://localhost:8080',
|
|
20
30
|
* user: { id: 'usr_12345', country: 'VN' },
|
|
21
31
|
* environment: 'production',
|
|
22
32
|
* autoCapture: true,
|
|
33
|
+
* devServer: { enabled: process.env.NODE_ENV === 'development' },
|
|
23
34
|
* });
|
|
24
35
|
*/
|
|
25
36
|
interface NexusInitOptions {
|
|
@@ -35,6 +46,14 @@ interface NexusInitOptions {
|
|
|
35
46
|
tags?: Record<string, string>;
|
|
36
47
|
/** Toggle automated global error capture. Defaults to true. */
|
|
37
48
|
autoCapture?: boolean;
|
|
49
|
+
/** Client-side rate limiting and deduplication sampling options. */
|
|
50
|
+
sampling?: SamplingConfig;
|
|
51
|
+
/** Pluggable transport adapter ('fetch', 'console', 'localStorage', custom fn). */
|
|
52
|
+
transport?: TransportPlugin;
|
|
53
|
+
/** Web Vitals performance observer options, or true for default observation. */
|
|
54
|
+
vitals?: boolean | PerformanceVitalsOptions;
|
|
55
|
+
/** Local dev server auto-routing configuration. */
|
|
56
|
+
devServer?: NexusDevServerOptions;
|
|
38
57
|
/** Additional flags-specific options. */
|
|
39
58
|
flags?: Partial<NexusFlagsOptions>;
|
|
40
59
|
/** Additional tracker-specific options. */
|
|
@@ -61,6 +80,7 @@ interface NexusInitOptions {
|
|
|
61
80
|
*/
|
|
62
81
|
declare class Nexus {
|
|
63
82
|
private static instance;
|
|
83
|
+
private static vitalsCleanup;
|
|
64
84
|
/** The underlying feature flags client instance. */
|
|
65
85
|
readonly flags: NexusFlagsClient;
|
|
66
86
|
/** The underlying error tracker client instance. */
|
|
@@ -73,9 +93,6 @@ declare class Nexus {
|
|
|
73
93
|
*
|
|
74
94
|
* @param options - SDK configuration options.
|
|
75
95
|
* @returns The initialized Nexus singleton instance.
|
|
76
|
-
*
|
|
77
|
-
* @example
|
|
78
|
-
* const nexus = Nexus.init({ apiKey: 'pk_live_...' });
|
|
79
96
|
*/
|
|
80
97
|
static init(options?: NexusInitOptions): Nexus;
|
|
81
98
|
/**
|
|
@@ -83,69 +100,48 @@ declare class Nexus {
|
|
|
83
100
|
*
|
|
84
101
|
* @returns The active Nexus instance.
|
|
85
102
|
* @throws {Error} If `Nexus.init()` has not been called yet.
|
|
86
|
-
*
|
|
87
|
-
* @example
|
|
88
|
-
* const nexus = Nexus.getInstance();
|
|
89
|
-
* nexus.flags.isEnabled('checkout_v2');
|
|
90
103
|
*/
|
|
91
104
|
static getInstance(): Nexus;
|
|
92
105
|
/**
|
|
93
106
|
* Convenience method: Check if a feature flag is enabled.
|
|
94
|
-
*
|
|
95
|
-
* @param key - Flag identifier.
|
|
96
|
-
* @param defaultValue - Fallback if flag is missing.
|
|
97
|
-
* @returns Boolean enabled state.
|
|
98
|
-
*
|
|
99
|
-
* @example
|
|
100
|
-
* if (Nexus.isEnabled('checkout_redesign')) { ... }
|
|
101
107
|
*/
|
|
102
108
|
static isEnabled(key: string, defaultValue?: boolean): boolean;
|
|
103
109
|
/**
|
|
104
110
|
* Convenience method: Get a flag variant value.
|
|
105
|
-
*
|
|
106
|
-
* @param key - Flag identifier.
|
|
107
|
-
* @param variantKey - Variant property name.
|
|
108
|
-
* @param defaultValue - Fallback value.
|
|
109
|
-
* @returns Variant value cast to type T.
|
|
110
|
-
*
|
|
111
|
-
* @example
|
|
112
|
-
* const rate = Nexus.getVariant<number>('promo_banner_v2', 'discount_rate', 10);
|
|
113
111
|
*/
|
|
114
112
|
static getVariant<T = unknown>(key: string, variantKey: string, defaultValue?: T): T;
|
|
115
113
|
/**
|
|
116
114
|
* Convenience method: Capture an error manually.
|
|
117
|
-
*
|
|
118
|
-
* @param error - Error instance, string, or unknown value.
|
|
119
|
-
* @param extra - Optional metadata tags.
|
|
120
|
-
*
|
|
121
|
-
* @example
|
|
122
|
-
* Nexus.captureError(new TypeError('Cannot read properties of null'));
|
|
123
115
|
*/
|
|
124
116
|
static captureError(error: unknown, extra?: Record<string, unknown>): void;
|
|
117
|
+
/**
|
|
118
|
+
* Convenience method: Capture an informational or warning message event.
|
|
119
|
+
*/
|
|
120
|
+
static captureMessage(message: string, level?: SeverityLevel, extra?: Record<string, unknown>): void;
|
|
121
|
+
/**
|
|
122
|
+
* Convenience method: Add a breadcrumb manually.
|
|
123
|
+
*/
|
|
124
|
+
static addBreadcrumb(breadcrumb: Breadcrumb): void;
|
|
125
|
+
/**
|
|
126
|
+
* Convenience method: Set extra contextual metadata.
|
|
127
|
+
*/
|
|
128
|
+
static setExtra(key: string, value: unknown): void;
|
|
129
|
+
/**
|
|
130
|
+
* Convenience method: Attach Web Vitals observer to tracker.
|
|
131
|
+
*/
|
|
132
|
+
static attachWebVitals(options?: PerformanceVitalsOptions): () => void;
|
|
125
133
|
/**
|
|
126
134
|
* Convenience method: Update user context for both flags and tracker.
|
|
127
|
-
*
|
|
128
|
-
* @param user - New user context (merged with existing).
|
|
129
|
-
* @returns Promise resolving after flags refresh.
|
|
130
|
-
*
|
|
131
|
-
* @example
|
|
132
|
-
* await Nexus.identify({ id: 'usr_12345', country: 'VN' });
|
|
133
135
|
*/
|
|
134
136
|
static identify(user: UserContext): Promise<void>;
|
|
135
137
|
/**
|
|
136
138
|
* Resets user context to anonymous state (e.g. on logout).
|
|
137
|
-
*
|
|
138
|
-
* @example
|
|
139
|
-
* Nexus.reset(); // called on user logout
|
|
140
139
|
*/
|
|
141
140
|
static reset(): void;
|
|
142
141
|
/**
|
|
143
142
|
* Gracefully tears down both clients, closing SSE connections and flushing pending events.
|
|
144
|
-
*
|
|
145
|
-
* @example
|
|
146
|
-
* await Nexus.destroy();
|
|
147
143
|
*/
|
|
148
144
|
static destroy(): Promise<void>;
|
|
149
145
|
}
|
|
150
146
|
|
|
151
|
-
export { Nexus, type NexusInitOptions };
|
|
147
|
+
export { Nexus, type NexusDevServerOptions, type NexusInitOptions };
|
package/dist/index.global.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
var Nexus=(function(exports){'use strict';function f(e,t=1e3,r=3e4){let n=t*Math.pow(2,e),s=Math.min(r,n);return Math.random()*s}function
|
|
1
|
+
var Nexus=(function(exports){'use strict';function f(e,t=1e3,r=3e4){let n=t*Math.pow(2,e),s=Math.min(r,n);return Math.random()*s}function L(e,t){return new Promise((r,n)=>{if(t?.aborted){n(new DOMException("Aborted","AbortError"));return}let s=setTimeout(r,e);t?.addEventListener("abort",()=>{clearTimeout(s),n(new DOMException("Aborted","AbortError"));});})}function W(e){return e>=500||e===429}async function M(e){let{url:t,method:r="GET",headers:n={},body:s,timeoutMs:a=5e3,maxRetries:o=3,retryBaseMs:c=1e3,retryMaxMs:u=3e4,signal:i}=e,l=new Error("Request failed");for(let h=0;h<=o;h++){if(i?.aborted)throw new DOMException("Request aborted by caller.","AbortError");let m=new AbortController,b=setTimeout(()=>m.abort(),a);i?.addEventListener("abort",()=>m.abort());try{let p={method:r,headers:{"Content-Type":"application/json",...n},signal:m.signal};s!==void 0&&(p.body=typeof s=="string"?s:JSON.stringify(s));let d=await fetch(t,p);if(clearTimeout(b),d.ok)return {data:await d.json(),status:d.status,headers:d.headers};if(W(d.status)&&h<o){l=new Error(`HTTP ${d.status}: ${d.statusText}`);let I=f(h,c,u);await L(I,i);continue}let y=await d.text().catch(()=>"");throw new Error(`HTTP ${d.status}: ${y}`)}catch(p){if(clearTimeout(b),p instanceof DOMException&&p.name==="AbortError")throw p;if(l=p instanceof Error?p:new Error(String(p)),h<o){let d=f(h,c,u);await L(d,i);}}}throw l}var P=class{capacity;buffer;head=0;count=0;constructor(e){if(e<1)throw new RangeError(`RingBuffer capacity must be >= 1, got ${e}`);this.capacity=e,this.buffer=new Array(e).fill(void 0);}push(e){this.buffer[this.head]=e,this.head=(this.head+1)%this.capacity,this.count<this.capacity&&this.count++;}toArray(){if(this.count===0)return [];let e=[];if(this.count<this.capacity)for(let t=0;t<this.count;t++)e.push(this.buffer[t]);else for(let t=0;t<this.capacity;t++)e.push(this.buffer[(this.head+t)%this.capacity]);return e}get size(){return this.count}get maxCapacity(){return this.capacity}get isFull(){return this.count===this.capacity}clear(){this.buffer.fill(void 0),this.head=0,this.count=0;}peek(){if(this.count===0)return;let e=(this.head-1+this.capacity)%this.capacity;return this.buffer[e]}};function E(e){try{let t=globalThis.process;if(typeof t<"u"&&t&&t.env)return t.env[e]??void 0}catch{}}function O(e){try{let t=typeof globalThis<"u"&&globalThis.__import_meta__;if(t&&t.env)return t.env[e]??void 0;let r=new Function("try { return import.meta; } catch(e) { return undefined; }")();if(r&&r.env)return r.env[e]??void 0}catch{}}function X(){try{if(typeof window<"u"&&window.__NEXUS_API_KEY__)return window.__NEXUS_API_KEY__}catch{}}function w(e){let t=e||X()||E("NEXUS_API_KEY")||E("NEXT_PUBLIC_NEXUS_API_KEY")||O("VITE_NEXUS_API_KEY")||E("NUXT_PUBLIC_NEXUS_API_KEY");if(!t||t.trim()==="")throw new Error(`[Nexus SDK] No API key found. Please provide one via:
|
|
2
2
|
1. Nexus.init({ apiKey: "pk_live_..." })
|
|
3
3
|
2. window.__NEXUS_API_KEY__ = "pk_live_..."
|
|
4
4
|
3. NEXUS_API_KEY env var
|
|
5
5
|
4. NEXT_PUBLIC_NEXUS_API_KEY (Next.js)
|
|
6
6
|
5. VITE_NEXUS_API_KEY (Vite)
|
|
7
|
-
6. NUXT_PUBLIC_NEXUS_API_KEY (Nuxt)`);return t.trim()}function
|
|
8
|
-
`);for(let n of r){let s=n.trim(),a=s.match(/^at\s+(.+?)\s+\((.+?):(\d+):(\d+)\)$/)||s.match(/^at\s+(.+?):(\d+):(\d+)$/)||s.match(/^at\s+\((.+?):(\d+):(\d+)\)$/);if(a){a.length===5?t.push({functionName:a[1]??"<anonymous>",fileName:a[2]??"<unknown>",lineNumber:parseInt(a[3]??"0",10),columnNumber:parseInt(a[4]??"0",10)}):a.length===4&&t.push({functionName:"<anonymous>",fileName:a[1]??"<unknown>",lineNumber:parseInt(a[2]??"0",10),columnNumber:parseInt(a[3]??"0",10)});continue}let i=s.match(/^(.+?)@(.+?):(\d+):(\d+)$/);i&&t.push({functionName:i[1]??"<anonymous>",fileName:i[2]??"<unknown>",lineNumber:parseInt(i[3]??"0",10),columnNumber:parseInt(i[4]??"0",10)});}return t}function Z(e,t,r){let n=r?.fileName??"unknown",s=r?.lineNumber??0,a=`${e}:${t}:${n}:${s}`,i=5381;for(let o=0;o<a.length;o++)i=(i<<5)+i+a.charCodeAt(o)>>>0;return `fp_${i.toString(16).padStart(8,"0")}`}var q=class{buffer;listenersAttached=false;clickHandler;popStateHandler;constructor(e){this.buffer=new C(e),this.clickHandler=this.handleClick.bind(this),this.popStateHandler=this.handleNavigation.bind(this);}push(e){let t=e.data?v(e.data):void 0;this.buffer.push({...e,data:t,timestamp:Date.now()});}getAll(){return this.buffer.toArray()}clear(){this.buffer.clear();}attachListeners(){this.listenersAttached||typeof window>"u"||(this.listenersAttached=true,document.addEventListener("click",this.clickHandler,{capture:true,passive:true}),window.addEventListener("popstate",this.popStateHandler,{passive:true}),this.interceptConsoleError());}detachListeners(){!this.listenersAttached||typeof window>"u"||(document.removeEventListener("click",this.clickHandler,{capture:true}),window.removeEventListener("popstate",this.popStateHandler),this.listenersAttached=false);}handleClick(e){let t=e.target;if(!t||t instanceof HTMLInputElement&&(t.type==="password"||t.hasAttribute("data-nexus-mask")))return;let r=this.describeElement(t);this.push({category:"ui.click",message:`Clicked ${r}`,level:"info",data:{elementTag:t.tagName.toLowerCase(),elementId:t.id||void 0,elementClass:t.className||void 0}});}handleNavigation(){this.push({category:"navigation",message:`Navigated to ${L(window.location.href)}`,level:"info",data:{url:L(window.location.href)}});}describeElement(e){let t=[e.tagName.toLowerCase()];return e.id&&t.push(`#${e.id}`),e.getAttribute("aria-label")&&t.push(`[aria-label="${e.getAttribute("aria-label")}"]`),t.join("")}interceptConsoleError(){let e=console.error.bind(console);console.error=(...t)=>{this.push({category:"console",message:t.map(String).join(" ").substring(0,500),level:"error"}),e(...t);};}},Q=class{options;maxRetries;isPageHiding=false;constructor(e){this.options=e,this.maxRetries=e.maxRetries??2,typeof document<"u"&&document.addEventListener("visibilitychange",()=>{document.visibilityState==="hidden"&&(this.isPageHiding=true);}),typeof window<"u"&&window.addEventListener("pagehide",()=>{this.isPageHiding=true;});}send(e){let t=E(e);if(this.isPageHiding&&typeof navigator<"u"&&typeof navigator.sendBeacon=="function"){let r=new Blob([t],{type:"application/json"});navigator.sendBeacon(this.options.endpoint,r);return}this.sendWithRetry(t,0);}async flush(e){let t=E(e);if(typeof navigator<"u"&&typeof navigator.sendBeacon=="function"){let r=new Blob([t],{type:"application/json"});navigator.sendBeacon(this.options.endpoint,r);return}await this.sendWithRetry(t,0);}async sendWithRetry(e,t){try{let r=await fetch(this.options.endpoint,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.options.apiKey}`},body:e,keepalive:!0});if(r.ok)return;if(r.status>=500&&t<this.maxRetries){let n=f(t,1e3,3e4);await new Promise(s=>setTimeout(s,n)),await this.sendWithRetry(e,t+1);}}catch{if(t<this.maxRetries){let r=f(t,1e3,3e4);await new Promise(n=>setTimeout(n,r)),await this.sendWithRetry(e,t+1);}}}};function ee(e){if(typeof window>"u")return ()=>{};let t=n=>{let s=n.error instanceof Error?n.error:new Error(n.message);e.captureError(s);},r=n=>{e.captureError(n.reason);};return window.addEventListener("error",t),window.addEventListener("unhandledrejection",r),()=>{window.removeEventListener("error",t),window.removeEventListener("unhandledrejection",r);}}var A=class{apiKey;environment;tags;beforeSend;breadcrumbManager;transport;userContext;dedupeMap=new Map;cleanupListeners;constructor(e={}){this.apiKey=m(e.apiKey);let t=y(e.baseUrl);this.environment=e.environment??"production",this.tags={...e.tags},this.beforeSend=e.beforeSend,this.breadcrumbManager=new q(Math.min(e.maxBreadcrumbs??20,50)),this.transport=new Q({endpoint:`${t}/api/v1/telemetry/errors`,apiKey:this.apiKey}),e.autoCapture!==false&&typeof window<"u"&&(this.breadcrumbManager.attachListeners(),this.cleanupListeners=ee(this));}captureError(e,t){let r=this.normalizeError(e),n=J(r.stack),s=Z(r.type,r.message,n[0]),a=this.dedupeMap.get(s);if(a){a.count+=1;return}let i={fingerprint:s,errorType:r.type,errorMessage:r.message,stackTrace:n,breadcrumbs:this.breadcrumbManager.getAll(),userContext:this.userContext,deviceContext:this.getDeviceContext(),tags:{environment:this.environment,...this.tags,...t},occurrenceCount:1,clientTimestamp:Date.now()},o=v(i),l=this.beforeSend?this.beforeSend(o):o;if(!l)return;this.transport.send(l);let c=setTimeout(()=>{let d=this.dedupeMap.get(s);if(d&&d.count>1){let p={...d.lastPayload,occurrenceCount:d.count,clientTimestamp:Date.now()};this.transport.send(p);}this.dedupeMap.delete(s);},1e4);this.dedupeMap.set(s,{timer:c,count:1,lastPayload:l});}addBreadcrumb(e){this.breadcrumbManager.push(e);}setUser(e){this.userContext=e??void 0;}setTag(e,t){this.tags[e]=t;}async flush(){for(let[e,t]of this.dedupeMap.entries()){if(clearTimeout(t.timer),t.count>0){let r={...t.lastPayload,occurrenceCount:t.count,clientTimestamp:Date.now()};await this.transport.flush(r);}this.dedupeMap.delete(e);}}destroy(){this.cleanupListeners?.(),this.breadcrumbManager.detachListeners(),this.breadcrumbManager.clear(),this.dedupeMap.forEach(e=>clearTimeout(e.timer)),this.dedupeMap.clear();}normalizeError(e){return e instanceof Error?{type:e.name||"Error",message:e.message,stack:e.stack}:typeof e=="string"?{type:"UnhandledException",message:e}:{type:"NonErrorRejection",message:String(e)}}getDeviceContext(){let e=typeof window<"u"&&typeof navigator<"u";return {userAgent:e?navigator.userAgent:"Node/SSR",currentUrl:e?window.location.href:"",viewport:e?`${window.innerWidth}x${window.innerHeight}`:void 0,timezone:Intl?.DateTimeFormat()?.resolvedOptions()?.timeZone,networkStatus:e&&"connection"in navigator?navigator.connection?.effectiveType??"unknown":void 0}}};var N=class e{static instance=null;flags;tracker;constructor(t={}){let{apiKey:r,baseUrl:n,user:s,environment:a,tags:i,autoCapture:o,flags:l,tracker:c}=t;this.flags=new S({apiKey:r,baseUrl:n,user:s,...l}),this.tracker=new A({apiKey:r,baseUrl:n,environment:a,tags:i,autoCapture:o,...c});}static init(t={}){return e.instance||(e.instance=new e(t)),e.instance}static getInstance(){if(!e.instance)throw new Error('[Nexus SDK] Not initialized. Call Nexus.init({ apiKey: "..." }) first.');return e.instance}static isEnabled(t,r=false){return e.getInstance().flags.isEnabled(t,r)}static getVariant(t,r,n){return e.getInstance().flags.getVariant(t,r,n)}static captureError(t,r){e.getInstance().tracker.captureError(t,r);}static async identify(t){let r=e.getInstance();r.tracker.setUser(t),await r.flags.identify(t);}static reset(){let t=e.getInstance();t.tracker.setUser(null),t.flags.reset();}static async destroy(){e.instance&&(await e.instance.tracker.flush(),e.instance.tracker.destroy(),e.instance.flags.destroy(),e.instance=null);}};exports.Nexus=N;exports.NexusFlagsClient=S;exports.NexusTrackerClient=A;return exports;})({});//# sourceMappingURL=index.global.js.map
|
|
9
|
-
|
|
7
|
+
6. NUXT_PUBLIC_NEXUS_API_KEY (Nuxt)`);return t.trim()}function S(e,t="https://api.nexus.dev"){return (e||E("NEXT_PUBLIC_NEXUS_URL")||O("VITE_NEXUS_URL")||t).replace(/\/$/,"")}function x(e,t,r,n){if(r>n)return "[MaxDepthExceeded]";if(e==null)return e;if(typeof e!="object"&&typeof e!="function")return typeof e=="bigint"||typeof e=="symbol"?e.toString():typeof e=="function"?"[Function]":e;if(e instanceof Error)return {name:e.name,message:e.message,stack:e.stack};if(t.has(e))return "[Circular]";if(t.add(e),Array.isArray(e)){let a=e.map(o=>x(o,t,r+1,n));return t.delete(e),a}let s={};for(let a of Object.keys(e)){let o=e[a];s[a]=x(o,t,r+1,n);}return t.delete(e),s}function T(e,t=8){let r=x(e,new WeakSet,0,t);try{return JSON.stringify(r)}catch{return JSON.stringify({error:"[SerializationFailed]"})}}function V(e,t=0){let r=t>>>0,n=3432918353,s=461845907,a=0,o=Math.floor(e.length/4)*4;for(;a<o;){let i=e.charCodeAt(a)&255|(e.charCodeAt(a+1)&255)<<8|(e.charCodeAt(a+2)&255)<<16|(e.charCodeAt(a+3)&255)<<24;i=Math.imul(i,n),i=i<<15|i>>>17,i=Math.imul(i,s),r^=i,r=r<<13|r>>>19,r=Math.imul(r,5)+3864292196>>>0,a+=4;}let c=0,u=e.length&3;return u>=3&&(c^=(e.charCodeAt(a+2)&255)<<16),u>=2&&(c^=(e.charCodeAt(a+1)&255)<<8),u>=1&&(c^=e.charCodeAt(a)&255,c=Math.imul(c,n),c=c<<15|c>>>17,c=Math.imul(c,s),r^=c),r^=e.length,r^=r>>>16,r=Math.imul(r,2246822507),r^=r>>>13,r=Math.imul(r,3266489909),r^=r>>>16,r>>>0}function G(e,t){let r=`${e}:${t}`;return V(r)%100}function R(e,t){let r=e.replace(/^v/,"").split(".").map(Number),n=t.replace(/^v/,"").split(".").map(Number);for(let s=0;s<3;s++){let a=(r[s]??0)-(n[s]??0);if(a!==0)return a}return 0}function z(e,t){let r=t.split("."),n=e;for(let s of r){if(n==null||typeof n!="object")return;n=n[s];}return n}function Y(e,t){let r=z(t,e.attribute),n=e.values;switch(e.operator){case "EQUALS":return r===n[0];case "NOT_EQUALS":return r!==n[0];case "IN":return n.includes(r);case "NOT_IN":return !n.includes(r);case "CONTAINS":return typeof r=="string"&&r.includes(String(n[0]));case "NOT_CONTAINS":return typeof r=="string"&&!r.includes(String(n[0]));case "STARTS_WITH":return typeof r=="string"&&r.startsWith(String(n[0]));case "ENDS_WITH":return typeof r=="string"&&r.endsWith(String(n[0]));case "GREATER_THAN":return typeof r=="number"&&r>Number(n[0]);case "LESS_THAN":return typeof r=="number"&&r<Number(n[0]);case "SEMVER_GTE":return typeof r=="string"&&typeof n[0]=="string"&&R(r,String(n[0]))>=0;case "SEMVER_LTE":return typeof r=="string"&&typeof n[0]=="string"&&R(r,String(n[0]))<=0;default:return false}}function U(e,t){if(!e.isEnabled)return {key:e.key,enabled:false,variants:{},reason:"KILL_SWITCH",version:e.version};if(e.targetingRules.length>0){if(!e.targetingRules.every(r=>Y(r,t)))return {key:e.key,enabled:false,variants:{},reason:"FALLBACK",version:e.version};if(e.rolloutPercentage>=100)return {key:e.key,enabled:true,variants:e.variants,reason:"TARGETING_MATCH",version:e.version}}if(e.rolloutPercentage>0){let r=t.id??"anon";return G(r,e.key)<e.rolloutPercentage?{key:e.key,enabled:true,variants:e.variants,reason:e.targetingRules.length>0?"TARGETING_MATCH":"ROLLOUT_MATCH",version:e.version}:{key:e.key,enabled:false,variants:{},reason:"FALLBACK",version:e.version}}return {key:e.key,enabled:false,variants:{},reason:"KILL_SWITCH",version:e.version}}var J=class{options;eventSource=null;connected=false;destroyed=false;reconnectAttempt=0;reconnectTimer=null;maxReconnects;constructor(e){this.options=e,this.maxReconnects=e.maxReconnects??1/0;}get isConnected(){return this.connected}connect(){this.destroyed||this.connected||this.eventSource||this.openConnection();}disconnect(){this.destroyed=true,this.cleanup();}openConnection(){if(!this.destroyed)try{let e=new URL(this.options.url);e.searchParams.set("apiKey",this.options.apiKey),this.eventSource=new EventSource(e.toString()),this.eventSource.addEventListener("open",()=>{this.connected=!0,this.reconnectAttempt=0,this.options.onStateChange?.(!0);}),this.eventSource.addEventListener("message",t=>{this.handleMessage(t.data);}),this.eventSource.addEventListener("flag_update",t=>{this.handleMessage(t.data);}),this.eventSource.addEventListener("FLAG_UPDATE",t=>{this.handleMessage(t.data);}),this.eventSource.addEventListener("FLAG_DELETE",t=>{this.handleMessage(t.data);}),this.eventSource.addEventListener("error",()=>{this.connected=!1,this.options.onStateChange?.(!1),this.cleanup(),this.scheduleReconnect();});}catch{this.scheduleReconnect();}}handleMessage(e){try{let t=JSON.parse(e);this.options.onEvent(t);}catch{}}cleanup(){this.eventSource&&(this.eventSource.close(),this.eventSource=null),this.reconnectTimer!==null&&(clearTimeout(this.reconnectTimer),this.reconnectTimer=null);}scheduleReconnect(){if(this.destroyed||this.reconnectAttempt>=this.maxReconnects)return;let e=f(this.reconnectAttempt,1e3,3e4);this.reconnectAttempt++,this.reconnectTimer=setTimeout(()=>{this.reconnectTimer=null,this.destroyed||this.openConnection();},e);}},Z="nexus_flags_",F="nexus_anon_id",q=class{memory=new Map;storageKey;localStorageAvailable;broadcastChannel=null;constructor(e){this.storageKey=`${Z}${e}`,this.localStorageAvailable=this.testLocalStorage(),this.hydrate(),this.setupBroadcastChannel();}set(e,t){this.memory.set(e,t),this.persist(),this.broadcastUpdate(e,t);}get(e){return this.memory.get(e)}setAll(e){for(let[t,r]of Object.entries(e))this.memory.set(t,r);this.persist();}delete(e){this.memory.delete(e),this.persist();}getAll(){return Object.fromEntries(this.memory.entries())}clear(){if(this.memory.clear(),this.localStorageAvailable)try{window.localStorage.removeItem(this.storageKey);}catch{}this.broadcastChannel?.close();}getOrCreateAnonymousId(){if(typeof window>"u")return "anon-ssr-node";if(this.localStorageAvailable)try{let e=window.localStorage.getItem(F);return e||(e=`anon_${Math.random().toString(36).substring(2,11)}`,window.localStorage.setItem(F,e)),e}catch{}return `anon_${Math.random().toString(36).substring(2,11)}`}testLocalStorage(){try{if(typeof window>"u")return !1;let e="__nexus_test__";return window.localStorage.setItem(e,"1"),window.localStorage.removeItem(e),!0}catch{return false}}hydrate(){if(this.localStorageAvailable)try{let e=window.localStorage.getItem(this.storageKey);if(e){let t=JSON.parse(e);for(let[r,n]of Object.entries(t))this.memory.set(r,n);}}catch{}}persist(){if(this.localStorageAvailable)try{window.localStorage.setItem(this.storageKey,JSON.stringify(Object.fromEntries(this.memory.entries())));}catch{}}setupBroadcastChannel(){try{typeof BroadcastChannel<"u"&&(this.broadcastChannel=new BroadcastChannel(`nexus_flags_${this.storageKey}`),this.broadcastChannel.onmessage=e=>{e.data?.key&&e.data?.result&&this.memory.set(e.data.key,e.data.result);});}catch{}}broadcastUpdate(e,t){try{this.broadcastChannel?.postMessage({key:e,result:t});}catch{}}},N=class{apiKey;baseUrl;timeoutMs;user;storage;listeners=new Map;sseManager;flagDefinitions=new Map;constructor(e={}){if(this.apiKey=w(e.apiKey),this.baseUrl=S(e.baseUrl),this.timeoutMs=e.timeoutMs??3e3,this.storage=new q(this.apiKey.substring(0,16)),this.user=e.user??{id:this.storage.getOrCreateAnonymousId()},e.bootstrap){let t={};for(let[r,n]of Object.entries(e.bootstrap))if(typeof n=="boolean")t[r]={key:r,enabled:n,variants:{},reason:n?"DEFAULT_ENABLED":"KILL_SWITCH",version:1};else if(n&&typeof n=="object"){let s=n,a=typeof s.enabled=="boolean"?s.enabled:typeof s.isEnabled=="boolean"?s.isEnabled:true;t[r]={key:s.key??r,enabled:a,variants:s.variants??{},reason:a?"DEFAULT_ENABLED":"KILL_SWITCH",version:typeof s.version=="number"?s.version:1};}this.storage.setAll(t);}e.realtime!==false&&this.initRealtimeSync(),this.refreshFlags();}isEnabled(e,t=false){let r=this.storage.get(e);return r!==void 0?r.enabled:t}getVariant(e,t,r){let n=this.storage.get(e);if(!n?.enabled||!n.variants)return r;let s=n.variants[t];return s!==void 0?s:r}async identify(e){this.user={...this.user,...e},await this.refreshFlags();}reset(){this.user={id:this.storage.getOrCreateAnonymousId()},this.refreshFlags();}onFlagChange(e,t){return this.listeners.has(e)||this.listeners.set(e,new Set),this.listeners.get(e).add(t),()=>this.listeners.get(e)?.delete(t)}destroy(){this.sseManager?.disconnect(),this.listeners.clear(),this.storage.clear();}initRealtimeSync(){this.sseManager=new J({url:`${this.baseUrl}/api/v1/flags/stream`,apiKey:this.apiKey,onEvent:e=>{if(e.type==="FLAG_UPDATE"&&e.data){let t=this.flagDefinitions.get(e.key),r=t?U(t,this.user):e.data;this.storage.set(e.key,r),this.listeners.get(e.key)?.forEach(n=>n(r));}else e.type==="FLAG_DELETE"&&(this.storage.delete(e.key),this.flagDefinitions.delete(e.key));}}),this.sseManager.connect();}async refreshFlags(){try{let e=await M({url:`${this.baseUrl}/api/v1/flags/eval`,method:"GET",headers:{Authorization:`Bearer ${this.apiKey}`,"X-Nexus-User-Id":this.user.id??"anon","X-Nexus-Country":this.user.country??""},timeoutMs:this.timeoutMs,maxRetries:2}),t=e.data,r=t&&typeof t=="object"&&"data"in t?t.data:e.data;if(r&&typeof r=="object")for(let[n,s]of Object.entries(r)){this.flagDefinitions.set(n,s);let a=U(s,this.user);this.storage.set(n,a),this.listeners.get(n)?.forEach(o=>o(a));}}catch{}}};var Q=/^(password|passwd|token|secret|authorization|bearer|auth|credit_?card|cvv|cvc|ssn|api_?key|access_?token|refresh_?token)$/i,ee=/\b(?:\d[ -]*?){13,16}\b/g,te=/[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/g,K=/([?&](token|auth|key|secret|password|api_key|access_token|refresh_token)=)[^&]*/gi;function re(e){return e.replace(ee,"[CARD_REDACTED]").replace(te,"[EMAIL_REDACTED]").replace(K,"$1[REDACTED]")}function C(e,t=0){if(t>5)return "[MaxDepthExceeded]";if(e==null)return e;if(typeof e=="string")return re(e);if(typeof e!="object")return e;if(Array.isArray(e))return e.map(n=>C(n,t+1));let r={};for(let[n,s]of Object.entries(e))Q.test(n)?r[n]="[REDACTED]":r[n]=C(s,t+1);return r}function B(e){return e.replace(K,"$1[REDACTED]")}function H(e){if(!e)return [];let t=[],r=e.split(`
|
|
8
|
+
`);for(let n of r){let s=n.trim(),a=s.match(/^at\s+(.+?)\s+\((.+?):(\d+):(\d+)\)$/)||s.match(/^at\s+(.+?):(\d+):(\d+)$/)||s.match(/^at\s+\((.+?):(\d+):(\d+)\)$/);if(a){a.length===5?t.push({functionName:a[1]??"<anonymous>",fileName:a[2]??"<unknown>",lineNumber:parseInt(a[3]??"0",10),columnNumber:parseInt(a[4]??"0",10)}):a.length===4&&t.push({functionName:"<anonymous>",fileName:a[1]??"<unknown>",lineNumber:parseInt(a[2]??"0",10),columnNumber:parseInt(a[3]??"0",10)});continue}let o=s.match(/^(.+?)@(.+?):(\d+):(\d+)$/);o&&t.push({functionName:o[1]??"<anonymous>",fileName:o[2]??"<unknown>",lineNumber:parseInt(o[3]??"0",10),columnNumber:parseInt(o[4]??"0",10)});}return t}function j(e,t,r){let n=r?.fileName??"unknown",s=r?.lineNumber??0,a=`${e}:${t}:${n}:${s}`,o=5381;for(let c=0;c<a.length;c++)o=(o<<5)+o+a.charCodeAt(c)>>>0;return `fp_${o.toString(16).padStart(8,"0")}`}var ne=class{buffer;listenersAttached=false;clickHandler;popStateHandler;constructor(e){this.buffer=new P(e),this.clickHandler=this.handleClick.bind(this),this.popStateHandler=this.handleNavigation.bind(this);}push(e){let t=e.data?C(e.data):void 0;this.buffer.push({...e,data:t,timestamp:Date.now()});}getAll(){return this.buffer.toArray()}clear(){this.buffer.clear();}attachListeners(){this.listenersAttached||typeof window>"u"||(this.listenersAttached=true,document.addEventListener("click",this.clickHandler,{capture:true,passive:true}),window.addEventListener("popstate",this.popStateHandler,{passive:true}),this.interceptConsoleError());}detachListeners(){!this.listenersAttached||typeof window>"u"||(document.removeEventListener("click",this.clickHandler,{capture:true}),window.removeEventListener("popstate",this.popStateHandler),this.listenersAttached=false);}handleClick(e){let t=e.target;if(!t||t instanceof HTMLInputElement&&(t.type==="password"||t.hasAttribute("data-nexus-mask")))return;let r=this.describeElement(t);this.push({category:"ui.click",message:`Clicked ${r}`,level:"info",data:{elementTag:t.tagName.toLowerCase(),elementId:t.id||void 0,elementClass:t.className||void 0}});}handleNavigation(){this.push({category:"navigation",message:`Navigated to ${B(window.location.href)}`,level:"info",data:{url:B(window.location.href)}});}describeElement(e){let t=[e.tagName.toLowerCase()];return e.id&&t.push(`#${e.id}`),e.getAttribute("aria-label")&&t.push(`[aria-label="${e.getAttribute("aria-label")}"]`),t.join("")}interceptConsoleError(){let e=console.error.bind(console);console.error=(...t)=>{this.push({category:"console",message:t.map(String).join(" ").substring(0,500),level:"error"}),e(...t);};}},$="nexus_events",D=200,se=class{options;maxRetries;plugin;isPageHiding=false;constructor(e){this.options=e,this.maxRetries=e.maxRetries??2,this.plugin=e.plugin??"fetch",this.plugin==="fetch"&&(typeof document<"u"&&document.addEventListener("visibilitychange",()=>{document.visibilityState==="hidden"&&(this.isPageHiding=true);}),typeof window<"u"&&window.addEventListener("pagehide",()=>{this.isPageHiding=true;}));}send(e){if(typeof this.plugin=="function"){this.plugin(e);return}switch(this.plugin){case "console":this.sendConsole(e);return;case "localStorage":this.sendLocalStorage(e);return;default:this.sendFetch(e);}}async flush(e){if(typeof this.plugin=="function"){await this.plugin(e);return}switch(this.plugin){case "console":this.sendConsole(e);return;case "localStorage":this.sendLocalStorage(e);return;default:{let t=T(e);if(typeof navigator<"u"&&typeof navigator.sendBeacon=="function"){let r=new Blob([t],{type:"application/json"});navigator.sendBeacon(this.options.endpoint,r);return}await this.sendWithRetry(t,0);}}}sendFetch(e){let t=T(e);if(this.isPageHiding&&typeof navigator<"u"&&typeof navigator.sendBeacon=="function"){let r=new Blob([t],{type:"application/json"});navigator.sendBeacon(this.options.endpoint,r);return}this.sendWithRetry(t,0);}sendConsole(e){let t=`[Nexus|${e.errorType}]`;console.group(t,e.errorMessage),console.warn("Fingerprint:",e.fingerprint),console.warn("Stack frames:",e.stackTrace.slice(0,3)),e.breadcrumbs.length>0&&console.warn("Last breadcrumbs:",e.breadcrumbs.slice(-5)),e.userContext&&console.warn("User:",e.userContext),console.groupEnd();}sendLocalStorage(e){if(!(typeof localStorage>"u"))try{let t=localStorage.getItem($),r=t?JSON.parse(t):[];r.push(e),r.length>D&&r.splice(0,r.length-D),localStorage.setItem($,T(r));}catch{}}async sendWithRetry(e,t){try{let r=await fetch(this.options.endpoint,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.options.apiKey}`},body:e,keepalive:!0});if(r.ok)return;if(r.status>=500&&t<this.maxRetries){let n=f(t,1e3,3e4);await new Promise(s=>setTimeout(s,n)),await this.sendWithRetry(e,t+1);}}catch{if(t<this.maxRetries){let r=f(t,1e3,3e4);await new Promise(n=>setTimeout(n,r)),await this.sendWithRetry(e,t+1);}}}};function ae(e){if(typeof window>"u")return ()=>{};let t=n=>{let s=n.error instanceof Error?n.error:new Error(n.message);e.captureError(s);},r=n=>{e.captureError(n.reason);};return window.addEventListener("error",t),window.addEventListener("unhandledrejection",r),()=>{window.removeEventListener("error",t),window.removeEventListener("unhandledrejection",r);}}var _=class{apiKey;environment;tags;extras;beforeSend;breadcrumbManager;transport;samplingRate;dedupeWindowMs;maxPerSession;sessionCaptureCount=0;userContext;dedupeMap=new Map;cleanupListeners;constructor(e={}){this.apiKey=w(e.apiKey);let t=S(e.baseUrl);this.environment=e.environment??"production",this.tags={...e.tags},this.extras={},this.beforeSend=e.beforeSend,this.samplingRate=Math.max(0,Math.min(1,e.sampling?.rate??1)),this.dedupeWindowMs=e.sampling?.dedupeWindow??1e4,this.maxPerSession=e.sampling?.maxPerSession??100,this.breadcrumbManager=new ne(Math.min(e.maxBreadcrumbs??20,50)),this.transport=new se({endpoint:`${t}/api/v1/telemetry/errors`,apiKey:this.apiKey,plugin:e.transport}),e.autoCapture!==false&&typeof window<"u"&&(this.breadcrumbManager.attachListeners(),this.cleanupListeners=ae(this));}captureError(e,t){if(this.sessionCaptureCount>=this.maxPerSession||this.samplingRate<1&&Math.random()>this.samplingRate)return;let r=this.normalizeError(e),n=H(r.stack),s=j(r.type,r.message,n[0]),a=this.dedupeMap.get(s);if(a){a.count+=1;return}let o={fingerprint:s,errorType:r.type,errorMessage:r.message,stackTrace:n,breadcrumbs:this.breadcrumbManager.getAll(),userContext:this.userContext,deviceContext:this.getDeviceContext(),tags:{environment:this.environment,...this.tags,...t},occurrenceCount:1,clientTimestamp:Date.now()},c=C(o),u=this.beforeSend?this.beforeSend(c):c;if(!u)return;this.transport.send(u),this.sessionCaptureCount++;let i=setTimeout(()=>{let l=this.dedupeMap.get(s);if(l&&l.count>1){let h={...l.lastPayload,occurrenceCount:l.count,clientTimestamp:Date.now()};this.transport.send(h);}this.dedupeMap.delete(s);},this.dedupeWindowMs);this.dedupeMap.set(s,{timer:i,count:1,lastPayload:u});}captureMessage(e,t="info",r){let n=new Error(e);n.name="NexusMessage",this.captureError(n,{_level:t,...r});}addBreadcrumb(e){this.breadcrumbManager.push(e);}setUser(e){this.userContext=e??void 0;}setTag(e,t){this.tags[e]=t;}setExtra(e,t){this.extras[e]=t;}async flush(){for(let[e,t]of this.dedupeMap.entries()){if(clearTimeout(t.timer),t.count>0){let r={...t.lastPayload,occurrenceCount:t.count,clientTimestamp:Date.now()};await this.transport.flush(r);}this.dedupeMap.delete(e);}}destroy(){this.cleanupListeners?.(),this.breadcrumbManager.detachListeners(),this.breadcrumbManager.clear(),this.dedupeMap.forEach(e=>clearTimeout(e.timer)),this.dedupeMap.clear();}normalizeError(e){return e instanceof Error?{type:e.name||"Error",message:e.message,stack:e.stack}:typeof e=="string"?{type:"UnhandledException",message:e}:{type:"NonErrorRejection",message:String(e)}}getDeviceContext(){let e=typeof window<"u"&&typeof navigator<"u";return {userAgent:e?navigator.userAgent:"Node/SSR",currentUrl:e?window.location.href:"",viewport:e?`${window.innerWidth}x${window.innerHeight}`:void 0,timezone:Intl?.DateTimeFormat()?.resolvedOptions()?.timeZone,networkStatus:e&&"connection"in navigator?navigator.connection?.effectiveType??"unknown":void 0}}},ie=class{_error=null;_errorInfo=null;_listeners=new Set;_tracker;_onError;_tags;_generateErrorId;constructor(e={}){this._tracker=e.tracker,this._onError=e.onError,this._tags=e.tags,this._generateErrorId=e.generateErrorId??(t=>{let r=H(t.stack);return `NX-${j(t.name,t.message,r[0]).replace(/^fp_/,"").slice(0,8).toUpperCase()}`});}get hasError(){return this._error!==null}get currentError(){return this._error}get errorInfo(){return this._errorInfo}capture(e,t){let r=e instanceof Error?e:new Error(String(e));this._error=r;let n=this._generateErrorId(r),s={error:r,errorId:n,reset:()=>this.recover(),componentStack:t?.componentStack};if(this._errorInfo=s,this._tracker)try{this._tracker.captureError(r,{tags:{...this._tags,...t?.tags,guardErrorId:n},componentStack:t?.componentStack});}catch(a){typeof console<"u"&&console.warn("[NexusGuardCore] Failed to forward error to tracker:",a);}if(this._onError)try{this._onError(r,s);}catch(a){typeof console<"u"&&console.warn("[NexusGuardCore] onError callback threw:",a);}return this._notify(),s}recover(){this._error!==null&&(this._error=null,this._errorInfo=null,this._notify());}reset(){this.recover();}subscribe(e){return this._listeners.add(e),e(this._errorInfo),()=>{this._listeners.delete(e);}}_notify(){for(let e of this._listeners)try{e(this._errorInfo);}catch(t){typeof console<"u"&&console.error("[NexusGuardCore] Subscriber threw error:",t);}}},oe={LCP:[2500,4e3],CLS:[.1,.25],FID:[100,300],TTFB:[800,1800],INP:[200,500],FCP:[1800,3e3]};function g(e,t){let[r,n]=oe[e]??[1/0,1/0];return t<=r?"good":t<=n?"needs-improvement":"poor"}function v(){return typeof performance>"u"?"navigate":performance.getEntriesByType("navigation")[0]?.type??"navigate"}function ce(e){if(typeof PerformanceObserver>"u")return ()=>{};let t=0,r=null;try{r=new PerformanceObserver(a=>{let o=a.getEntries(),c=o[o.length-1];c&&(t=c.startTime??0);}),r.observe({type:"largest-contentful-paint",buffered:!0});}catch{return ()=>{}}let n=()=>{t!==0&&e({name:"LCP",value:t,rating:g("LCP",t),delta:t,navigationType:v()});},s=()=>n();return document.addEventListener("visibilitychange",s,{once:true}),()=>{r?.disconnect(),document.removeEventListener("visibilitychange",s);}}function le(e){if(typeof PerformanceObserver>"u")return ()=>{};let t=0,r=null;try{r=new PerformanceObserver(a=>{for(let o of a.getEntries()){let c=o;c.hadRecentInput||(t+=c.value??0);}}),r.observe({type:"layout-shift",buffered:!0});}catch{return ()=>{}}let n=()=>{t!==0&&e({name:"CLS",value:t,rating:g("CLS",t),delta:t,navigationType:v()});},s=()=>n();return document.addEventListener("visibilitychange",s,{once:true}),()=>{r?.disconnect(),document.removeEventListener("visibilitychange",s);}}function ue(e){if(typeof PerformanceObserver>"u")return ()=>{};let t=null;try{t=new PerformanceObserver(r=>{let n=r.getEntries()[0];if(!n)return;let s=n.processingStart-n.startTime;e({name:"FID",value:s,rating:g("FID",s),delta:s,navigationType:v()}),t?.disconnect();}),t.observe({type:"first-input",buffered:!0});}catch{return ()=>{}}return ()=>t?.disconnect()}function de(e){if(typeof PerformanceObserver>"u")return ()=>{};try{let t=performance.getEntriesByType("navigation")[0];if(t){let r=t.responseStart-t.requestStart;e({name:"TTFB",value:r,rating:g("TTFB",r),delta:r,navigationType:t.type??"navigate"});}}catch{}return ()=>{}}function he(e){if(typeof PerformanceObserver>"u")return ()=>{};let t=0,r=null;try{r=new PerformanceObserver(a=>{for(let o of a.getEntries()){let c=o;c.duration>t&&(t=c.duration);}}),r.observe({type:"event",buffered:!0,durationThreshold:16});}catch{return ()=>{}}let n=()=>{t!==0&&e({name:"INP",value:t,rating:g("INP",t),delta:t,navigationType:v()});},s=()=>n();return document.addEventListener("visibilitychange",s,{once:true}),()=>{r?.disconnect(),document.removeEventListener("visibilitychange",s);}}function pe(e){if(typeof PerformanceObserver>"u")return ()=>{};let t=null;try{t=new PerformanceObserver(r=>{let n=r.getEntries().find(a=>a.name==="first-contentful-paint");if(!n)return;let s=n.startTime;e({name:"FCP",value:s,rating:g("FCP",s),delta:s,navigationType:v()}),t?.disconnect();}),t.observe({type:"paint",buffered:!0});}catch{return ()=>{}}return ()=>t?.disconnect()}function fe(e,t){if(typeof PerformanceObserver>"u")return ()=>{};let r=null;try{r=new PerformanceObserver(n=>{for(let s of n.getEntries())s.duration>=t&&e.addBreadcrumb({category:"custom",message:`Long task detected: ${Math.round(s.duration)}ms`,level:s.duration>=t*3?"error":"warning",data:{durationMs:Math.round(s.duration),startTime:Math.round(s.startTime)}});}),r.observe({type:"longtask",buffered:!0});}catch{return ()=>{}}return ()=>r?.disconnect()}var ge={LCP:ce,CLS:le,FID:ue,TTFB:de,INP:he,FCP:pe};function k(e,t={}){if(typeof window>"u")return ()=>{};let{captureAsEvents:r=false,poorRatingOnly:n=false,vitals:s=["LCP","CLS","FID","TTFB","INP","FCP"],longTaskThresholdMs:a=50}=t,o=i=>{n&&i.rating==="good"||(e.addBreadcrumb({category:"custom",message:`Web Vital ${i.name}: ${i.rating.toUpperCase()} (${Math.round(i.value)}${i.name==="CLS"?"":"ms"})`,level:i.rating==="poor"?"error":i.rating==="needs-improvement"?"warning":"info",data:{metric:i.name,value:i.value,rating:i.rating,navigationType:i.navigationType}}),r&&i.rating!=="good"&&e.captureMessage(`Performance degradation: ${i.name} is ${i.rating} (${Math.round(i.value)}${i.name==="CLS"?"":"ms"})`,i.rating==="poor"?"error":"warning",{metric:i.name,value:i.value,rating:i.rating,navigationType:i.navigationType}));},c=s.map(i=>{let l=ge[i];return l?l(o):()=>{}}),u=fe(e,a);return ()=>{c.forEach(i=>i()),u();}}var A=class e{static instance=null;static vitalsCleanup=null;flags;tracker;constructor(t={}){let{apiKey:r,baseUrl:n,user:s,environment:a,tags:o,autoCapture:c,sampling:u,transport:i,vitals:l,devServer:h,flags:m,tracker:b}=t;this.flags=new N({apiKey:r,baseUrl:n,user:s,...m});let p=n,d=i;if(h?.enabled){let y=h.port??4567;p=`http://${h.host??"localhost"}:${y}`;}if(this.tracker=new _({apiKey:r,baseUrl:p,environment:a,tags:o,autoCapture:c,sampling:u,transport:d,...b}),l){let y=typeof l=="object"?l:{};e.vitalsCleanup=k(this.tracker,y);}}static init(t={}){return e.instance||(e.instance=new e(t)),e.instance}static getInstance(){if(!e.instance)throw new Error('[Nexus SDK] Not initialized. Call Nexus.init({ apiKey: "..." }) first.');return e.instance}static isEnabled(t,r=false){return e.getInstance().flags.isEnabled(t,r)}static getVariant(t,r,n){return e.getInstance().flags.getVariant(t,r,n)}static captureError(t,r){e.getInstance().tracker.captureError(t,r);}static captureMessage(t,r="info",n){e.getInstance().tracker.captureMessage(t,r,n);}static addBreadcrumb(t){e.getInstance().tracker.addBreadcrumb(t);}static setExtra(t,r){e.getInstance().tracker.setExtra(t,r);}static attachWebVitals(t){return k(e.getInstance().tracker,t)}static async identify(t){let r=e.getInstance();r.tracker.setUser(t),await r.flags.identify(t);}static reset(){let t=e.getInstance();t.tracker.setUser(null),t.flags.reset();}static async destroy(){e.vitalsCleanup&&(e.vitalsCleanup(),e.vitalsCleanup=null),e.instance&&(await e.instance.tracker.flush(),e.instance.tracker.destroy(),e.instance.flags.destroy(),e.instance=null);}};
|
|
9
|
+
exports.Nexus=A;exports.NexusFlagsClient=N;exports.NexusGuardCore=ie;exports.NexusTrackerClient=_;exports.attachWebVitals=k;return exports;})({});
|
package/dist/index.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import {NexusFlagsClient}from'@nexussdk/flags';export{NexusFlagsClient}from'@nexussdk/flags';import {NexusTrackerClient}from'@nexussdk/tracker';export{NexusTrackerClient}from'@nexussdk/tracker';var
|
|
2
|
-
|
|
1
|
+
import {NexusFlagsClient}from'@nexussdk/flags';export{NexusFlagsClient}from'@nexussdk/flags';import {NexusTrackerClient,attachWebVitals}from'@nexussdk/tracker';export{NexusGuardCore,NexusTrackerClient,attachWebVitals}from'@nexussdk/tracker';var o=class t{static instance=null;static vitalsCleanup=null;flags;tracker;constructor(e={}){let{apiKey:r,baseUrl:s,user:u,environment:p,tags:g,autoCapture:x,sampling:d,transport:f,vitals:n,devServer:a,flags:v,tracker:m}=e;this.flags=new NexusFlagsClient({apiKey:r,baseUrl:s,user:u,...v});let l=s,b=f;if(a?.enabled){let i=a.port??4567;l=`http://${a.host??"localhost"}:${i}`;}if(this.tracker=new NexusTrackerClient({apiKey:r,baseUrl:l,environment:p,tags:g,autoCapture:x,sampling:d,transport:b,...m}),n){let i=typeof n=="object"?n:{};t.vitalsCleanup=attachWebVitals(this.tracker,i);}}static init(e={}){return t.instance||(t.instance=new t(e)),t.instance}static getInstance(){if(!t.instance)throw new Error('[Nexus SDK] Not initialized. Call Nexus.init({ apiKey: "..." }) first.');return t.instance}static isEnabled(e,r=false){return t.getInstance().flags.isEnabled(e,r)}static getVariant(e,r,s){return t.getInstance().flags.getVariant(e,r,s)}static captureError(e,r){t.getInstance().tracker.captureError(e,r);}static captureMessage(e,r="info",s){t.getInstance().tracker.captureMessage(e,r,s);}static addBreadcrumb(e){t.getInstance().tracker.addBreadcrumb(e);}static setExtra(e,r){t.getInstance().tracker.setExtra(e,r);}static attachWebVitals(e){return attachWebVitals(t.getInstance().tracker,e)}static async identify(e){let r=t.getInstance();r.tracker.setUser(e),await r.flags.identify(e);}static reset(){let e=t.getInstance();e.tracker.setUser(null),e.flags.reset();}static async destroy(){t.vitalsCleanup&&(t.vitalsCleanup(),t.vitalsCleanup=null),t.instance&&(await t.instance.tracker.flush(),t.instance.tracker.destroy(),t.instance.flags.destroy(),t.instance=null);}};
|
|
2
|
+
export{o as Nexus};
|