@setgo/sdk 1.0.1

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 (59) hide show
  1. package/README.md +184 -0
  2. package/dist/core/client.d.ts +81 -0
  3. package/dist/core/client.d.ts.map +1 -0
  4. package/dist/core/client.js +319 -0
  5. package/dist/core/index.d.ts +8 -0
  6. package/dist/core/index.d.ts.map +1 -0
  7. package/dist/core/index.js +14 -0
  8. package/dist/core/metrics-reporter.d.ts +40 -0
  9. package/dist/core/metrics-reporter.d.ts.map +1 -0
  10. package/dist/core/metrics-reporter.js +152 -0
  11. package/dist/core/repository.d.ts +37 -0
  12. package/dist/core/repository.d.ts.map +1 -0
  13. package/dist/core/repository.js +58 -0
  14. package/dist/core/strategy-evaluator.d.ts +43 -0
  15. package/dist/core/strategy-evaluator.d.ts.map +1 -0
  16. package/dist/core/strategy-evaluator.js +209 -0
  17. package/dist/errors/index.d.ts +22 -0
  18. package/dist/errors/index.d.ts.map +1 -0
  19. package/dist/errors/index.js +52 -0
  20. package/dist/index.d.ts +25 -0
  21. package/dist/index.d.ts.map +1 -0
  22. package/dist/index.js +38 -0
  23. package/dist/nestjs/index.d.ts +7 -0
  24. package/dist/nestjs/index.d.ts.map +1 -0
  25. package/dist/nestjs/index.js +13 -0
  26. package/dist/nestjs/setgo.constants.d.ts +6 -0
  27. package/dist/nestjs/setgo.constants.d.ts.map +1 -0
  28. package/dist/nestjs/setgo.constants.js +8 -0
  29. package/dist/nestjs/setgo.module.d.ts +20 -0
  30. package/dist/nestjs/setgo.module.d.ts.map +1 -0
  31. package/dist/nestjs/setgo.module.js +64 -0
  32. package/dist/nestjs/setgo.service.d.ts +34 -0
  33. package/dist/nestjs/setgo.service.d.ts.map +1 -0
  34. package/dist/nestjs/setgo.service.js +84 -0
  35. package/dist/types/config.d.ts +41 -0
  36. package/dist/types/config.d.ts.map +1 -0
  37. package/dist/types/config.js +5 -0
  38. package/dist/types/events.d.ts +21 -0
  39. package/dist/types/events.d.ts.map +1 -0
  40. package/dist/types/events.js +5 -0
  41. package/dist/types/features.d.ts +41 -0
  42. package/dist/types/features.d.ts.map +1 -0
  43. package/dist/types/features.js +5 -0
  44. package/dist/types/index.d.ts +8 -0
  45. package/dist/types/index.d.ts.map +1 -0
  46. package/dist/types/index.js +5 -0
  47. package/dist/types/metrics.d.ts +16 -0
  48. package/dist/types/metrics.d.ts.map +1 -0
  49. package/dist/types/metrics.js +5 -0
  50. package/dist/utils/index.d.ts +6 -0
  51. package/dist/utils/index.d.ts.map +1 -0
  52. package/dist/utils/index.js +12 -0
  53. package/dist/utils/ip-matcher.d.ts +14 -0
  54. package/dist/utils/ip-matcher.d.ts.map +1 -0
  55. package/dist/utils/ip-matcher.js +165 -0
  56. package/dist/utils/murmurhash.d.ts +10 -0
  57. package/dist/utils/murmurhash.d.ts.map +1 -0
  58. package/dist/utils/murmurhash.js +59 -0
  59. package/package.json +72 -0
package/README.md ADDED
@@ -0,0 +1,184 @@
1
+ # @setgo/sdk
2
+
3
+ SDK oficial do SetGo Feature Flags para Node.js e NestJS.
4
+
5
+ ## Instalacao
6
+
7
+ ```bash
8
+ yarn add @setgo/sdk
9
+ ```
10
+
11
+ ## Uso Basico (Node.js)
12
+
13
+ ```typescript
14
+ import { SetGoClient } from '@setgo/sdk';
15
+
16
+ const client = new SetGoClient({
17
+ baseUrl: process.env.SETGO_URL,
18
+ token: process.env.SETGO_TOKEN,
19
+ appName: 'minha-app',
20
+ });
21
+
22
+ // Iniciar o cliente (registra e busca features)
23
+ await client.start();
24
+
25
+ // Verificar se uma feature esta habilitada
26
+ if (client.isEnabled('dark-mode', { userId: '123' })) {
27
+ // Feature habilitada para este usuario
28
+ }
29
+
30
+ // Obter uma feature especifica
31
+ const feature = client.getFeature('dark-mode');
32
+
33
+ // Obter todas as features
34
+ const features = client.getAllFeatures();
35
+
36
+ // Escutar eventos
37
+ client.on('update', (event) => {
38
+ console.log('Features atualizadas:', event.features);
39
+ });
40
+
41
+ client.on('error', (event) => {
42
+ console.error('Erro:', event.error);
43
+ });
44
+
45
+ // Parar o cliente (envia metricas pendentes)
46
+ await client.stop();
47
+ ```
48
+
49
+ ## Uso com NestJS
50
+
51
+ ### Configuracao do Modulo
52
+
53
+ ```typescript
54
+ import { Module } from '@nestjs/common';
55
+ import { ConfigModule, ConfigService } from '@nestjs/config';
56
+ import { SetGoModule } from '@setgo/sdk/nestjs';
57
+
58
+ @Module({
59
+ imports: [
60
+ SetGoModule.forRootAsync({
61
+ imports: [ConfigModule],
62
+ inject: [ConfigService],
63
+ useFactory: (config: ConfigService) => ({
64
+ baseUrl: config.get('SETGO_URL'),
65
+ token: config.get('SETGO_TOKEN'),
66
+ appName: config.get('APP_NAME'),
67
+ }),
68
+ }),
69
+ ],
70
+ })
71
+ export class AppModule {}
72
+ ```
73
+
74
+ ### Usando o Service
75
+
76
+ ```typescript
77
+ import { Injectable } from '@nestjs/common';
78
+ import { SetGoService } from '@setgo/sdk/nestjs';
79
+
80
+ @Injectable()
81
+ export class MyService {
82
+ constructor(private readonly setgo: SetGoService) {}
83
+
84
+ async doSomething(userId: string) {
85
+ if (this.setgo.isEnabled('new-feature', { userId })) {
86
+ // Feature habilitada
87
+ }
88
+ }
89
+ }
90
+ ```
91
+
92
+ ## Configuracao
93
+
94
+ | Opcao | Tipo | Padrao | Descricao |
95
+ |-------|------|--------|-----------|
96
+ | `baseUrl` | string | **obrigatorio** | URL da API do SetGo |
97
+ | `token` | string | **obrigatorio** | Token de API do cliente |
98
+ | `appName` | string | **obrigatorio** | Nome da aplicacao |
99
+ | `environment` | string | - | Ambiente (geralmente definido no token) |
100
+ | `instanceId` | string | auto-gerado | Identificador unico da instancia |
101
+ | `refreshInterval` | number | 15000 | Intervalo de polling em ms |
102
+ | `metricsInterval` | number | 60000 | Intervalo de envio de metricas em ms |
103
+ | `timeout` | number | 10000 | Timeout das requisicoes em ms |
104
+ | `disableMetrics` | boolean | false | Desabilitar coleta de metricas |
105
+
106
+ ## Contexto de Avaliacao
107
+
108
+ Ao avaliar uma feature, voce pode passar um contexto:
109
+
110
+ ```typescript
111
+ client.isEnabled('feature-name', {
112
+ userId: '123', // ID do usuario
113
+ sessionId: 'abc', // ID da sessao
114
+ remoteAddress: '192.168.1.1', // IP do cliente
115
+ properties: { // Propriedades customizadas
116
+ plan: 'premium',
117
+ country: 'BR',
118
+ },
119
+ });
120
+ ```
121
+
122
+ ## Estrategias Suportadas
123
+
124
+ O SDK avalia as seguintes estrategias localmente:
125
+
126
+ - **DEFAULT**: Feature habilitada/desabilitada globalmente
127
+ - **GRADUAL_ROLLOUT**: Rollout gradual baseado em porcentagem
128
+ - **USER_WITH_ID**: Habilita para usuarios especificos
129
+ - **FLEXIBLE_ROLLOUT**: Rollout com stickiness customizado
130
+ - **REMOTE_ADDRESS**: Habilita para IPs/CIDRs especificos
131
+
132
+ ## Eventos
133
+
134
+ ```typescript
135
+ // Quando o cliente esta pronto
136
+ client.on('ready', (event) => {
137
+ console.log('Pronto com', event.features.length, 'features');
138
+ });
139
+
140
+ // Quando features sao atualizadas
141
+ client.on('update', (event) => {
142
+ console.log('Versao', event.version, 'com', event.features.length, 'features');
143
+ });
144
+
145
+ // Quando ocorre um erro
146
+ client.on('error', (event) => {
147
+ console.error('Erro:', event.error);
148
+ });
149
+ ```
150
+
151
+ ## Tratamento de Erros
152
+
153
+ ```typescript
154
+ import { SetGoError, NetworkError, AuthenticationError, TimeoutError } from '@setgo/sdk';
155
+
156
+ try {
157
+ await client.start();
158
+ } catch (error) {
159
+ if (error instanceof AuthenticationError) {
160
+ // Token invalido
161
+ } else if (error instanceof NetworkError) {
162
+ // Erro de rede
163
+ } else if (error instanceof TimeoutError) {
164
+ // Timeout
165
+ }
166
+ }
167
+ ```
168
+
169
+ ## Metricas
170
+
171
+ O SDK coleta automaticamente metricas de uso (quantas vezes cada feature foi avaliada como true/false) e envia para a API em intervalos regulares. As metricas sao agregadas por hora.
172
+
173
+ Para desabilitar:
174
+
175
+ ```typescript
176
+ const client = new SetGoClient({
177
+ // ...
178
+ disableMetrics: true,
179
+ });
180
+ ```
181
+
182
+ ## Licenca
183
+
184
+ UNLICENSED - Uso interno apenas.
@@ -0,0 +1,81 @@
1
+ /**
2
+ * SetGo Client - main SDK entry point
3
+ */
4
+ import type { SetGoConfig, Feature, FeatureContext, SetGoEventType, SetGoEventHandler } from '../types/index.js';
5
+ export declare class SetGoClient {
6
+ private config;
7
+ private repository;
8
+ private metricsReporter;
9
+ private evaluator;
10
+ private pollInterval?;
11
+ private etag?;
12
+ private ready;
13
+ private started;
14
+ private events;
15
+ constructor(config: SetGoConfig);
16
+ /**
17
+ * Validate configuration
18
+ */
19
+ private validateConfig;
20
+ /**
21
+ * Generate a unique instance ID
22
+ */
23
+ private generateInstanceId;
24
+ /**
25
+ * Start the client - registers with API and starts polling
26
+ */
27
+ start(): Promise<void>;
28
+ /**
29
+ * Stop the client - stops polling and flushes metrics
30
+ */
31
+ stop(): Promise<void>;
32
+ /**
33
+ * Register client with the server
34
+ */
35
+ private register;
36
+ /**
37
+ * Start polling for feature updates
38
+ */
39
+ private startPolling;
40
+ /**
41
+ * Fetch features from the API
42
+ */
43
+ private fetchFeatures;
44
+ /**
45
+ * Make an HTTP request
46
+ */
47
+ private makeRequest;
48
+ /**
49
+ * Check if a feature is enabled
50
+ */
51
+ isEnabled(featureName: string, context?: FeatureContext): boolean;
52
+ /**
53
+ * Evaluate a feature's strategies
54
+ */
55
+ private evaluateFeature;
56
+ /**
57
+ * Get a feature by name
58
+ */
59
+ getFeature(featureName: string): Feature | undefined;
60
+ /**
61
+ * Get all features
62
+ */
63
+ getAllFeatures(): Feature[];
64
+ /**
65
+ * Check if client is ready
66
+ */
67
+ isReady(): boolean;
68
+ /**
69
+ * Subscribe to an event
70
+ */
71
+ on<T extends SetGoEventType>(event: T, handler: SetGoEventHandler<T>): void;
72
+ /**
73
+ * Unsubscribe from an event
74
+ */
75
+ off<T extends SetGoEventType>(event: T, handler: SetGoEventHandler<T>): void;
76
+ /**
77
+ * Emit an event
78
+ */
79
+ private emit;
80
+ }
81
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/core/client.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EACV,WAAW,EAEX,OAAO,EACP,cAAc,EAEd,cAAc,EACd,iBAAiB,EAKlB,MAAM,mBAAmB,CAAC;AAa3B,qBAAa,WAAW;IACtB,OAAO,CAAC,MAAM,CAAsB;IACpC,OAAO,CAAC,UAAU,CAAoB;IACtC,OAAO,CAAC,eAAe,CAAkB;IACzC,OAAO,CAAC,SAAS,CAAoB;IACrC,OAAO,CAAC,YAAY,CAAC,CAAiC;IACtD,OAAO,CAAC,IAAI,CAAC,CAAS;IACtB,OAAO,CAAC,KAAK,CAAkB;IAC/B,OAAO,CAAC,OAAO,CAAkB;IACjC,OAAO,CAAC,MAAM,CAA0E;gBAE5E,MAAM,EAAE,WAAW;IAyB/B;;OAEG;IACH,OAAO,CAAC,cAAc;IAYtB;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAI1B;;OAEG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAsC5B;;OAEG;IACG,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAmB3B;;OAEG;YACW,QAAQ;IAoBtB;;OAEG;IACH,OAAO,CAAC,YAAY;IAgBpB;;OAEG;YACW,aAAa;IAwC3B;;OAEG;YACW,WAAW;IA2DzB;;OAEG;IACH,SAAS,CAAC,WAAW,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,cAAc,GAAG,OAAO;IAqBjE;;OAEG;IACH,OAAO,CAAC,eAAe;IAmBvB;;OAEG;IACH,UAAU,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,GAAG,SAAS;IAIpD;;OAEG;IACH,cAAc,IAAI,OAAO,EAAE;IAI3B;;OAEG;IACH,OAAO,IAAI,OAAO;IAIlB;;OAEG;IACH,EAAE,CAAC,CAAC,SAAS,cAAc,EAAE,KAAK,EAAE,CAAC,EAAE,OAAO,EAAE,iBAAiB,CAAC,CAAC,CAAC,GAAG,IAAI;IAO3E;;OAEG;IACH,GAAG,CAAC,CAAC,SAAS,cAAc,EAAE,KAAK,EAAE,CAAC,EAAE,OAAO,EAAE,iBAAiB,CAAC,CAAC,CAAC,GAAG,IAAI;IAO5E;;OAEG;IACH,OAAO,CAAC,IAAI;CAkBb"}
@@ -0,0 +1,319 @@
1
+ "use strict";
2
+ /**
3
+ * SetGo Client - main SDK entry point
4
+ */
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.SetGoClient = void 0;
7
+ const repository_js_1 = require("./repository.js");
8
+ const metrics_reporter_js_1 = require("./metrics-reporter.js");
9
+ const strategy_evaluator_js_1 = require("./strategy-evaluator.js");
10
+ const index_js_1 = require("../errors/index.js");
11
+ const SDK_VERSION = '1.0.0';
12
+ class SetGoClient {
13
+ config;
14
+ repository;
15
+ metricsReporter;
16
+ evaluator;
17
+ pollInterval;
18
+ etag;
19
+ ready = false;
20
+ started = false;
21
+ events = new Map();
22
+ constructor(config) {
23
+ this.validateConfig(config);
24
+ this.config = {
25
+ baseUrl: config.baseUrl.replace(/\/$/, ''), // Remove trailing slash
26
+ token: config.token,
27
+ appName: config.appName,
28
+ environment: config.environment,
29
+ instanceId: config.instanceId ?? this.generateInstanceId(),
30
+ refreshInterval: config.refreshInterval ?? 15000,
31
+ metricsInterval: config.metricsInterval ?? 60000,
32
+ timeout: config.timeout ?? 10000,
33
+ disableMetrics: config.disableMetrics ?? false,
34
+ };
35
+ this.repository = new repository_js_1.FeatureRepository();
36
+ this.metricsReporter = new metrics_reporter_js_1.MetricsReporter(this.config);
37
+ this.evaluator = new strategy_evaluator_js_1.StrategyEvaluator();
38
+ // Initialize event maps
39
+ this.events.set('ready', new Set());
40
+ this.events.set('update', new Set());
41
+ this.events.set('error', new Set());
42
+ }
43
+ /**
44
+ * Validate configuration
45
+ */
46
+ validateConfig(config) {
47
+ if (!config.baseUrl) {
48
+ throw new index_js_1.ConfigurationError('baseUrl is required');
49
+ }
50
+ if (!config.token) {
51
+ throw new index_js_1.ConfigurationError('token is required');
52
+ }
53
+ if (!config.appName) {
54
+ throw new index_js_1.ConfigurationError('appName is required');
55
+ }
56
+ }
57
+ /**
58
+ * Generate a unique instance ID
59
+ */
60
+ generateInstanceId() {
61
+ return `${Date.now()}-${Math.random().toString(36).substring(2, 11)}`;
62
+ }
63
+ /**
64
+ * Start the client - registers with API and starts polling
65
+ */
66
+ async start() {
67
+ if (this.started) {
68
+ return;
69
+ }
70
+ this.started = true;
71
+ try {
72
+ // Register client with the server
73
+ await this.register();
74
+ // Initial feature fetch
75
+ await this.fetchFeatures();
76
+ // Mark as ready
77
+ this.ready = true;
78
+ // Emit ready event
79
+ this.emit('ready', {
80
+ type: 'ready',
81
+ features: this.repository.getAll(),
82
+ });
83
+ // Start polling
84
+ this.startPolling();
85
+ // Start metrics reporting
86
+ this.metricsReporter.start();
87
+ }
88
+ catch (error) {
89
+ this.started = false;
90
+ this.emit('error', {
91
+ type: 'error',
92
+ error: error instanceof Error ? error : new Error(String(error)),
93
+ });
94
+ throw error;
95
+ }
96
+ }
97
+ /**
98
+ * Stop the client - stops polling and flushes metrics
99
+ */
100
+ async stop() {
101
+ if (!this.started) {
102
+ return;
103
+ }
104
+ // Stop polling
105
+ if (this.pollInterval) {
106
+ clearInterval(this.pollInterval);
107
+ this.pollInterval = undefined;
108
+ }
109
+ // Flush remaining metrics
110
+ await this.metricsReporter.flush();
111
+ this.metricsReporter.stop();
112
+ this.started = false;
113
+ this.ready = false;
114
+ }
115
+ /**
116
+ * Register client with the server
117
+ */
118
+ async register() {
119
+ const url = `${this.config.baseUrl}/client/register`;
120
+ const payload = {
121
+ appName: this.config.appName,
122
+ instanceId: this.config.instanceId,
123
+ sdkVersion: SDK_VERSION,
124
+ platformInfo: {
125
+ nodeVersion: typeof process !== 'undefined' ? process.version : 'unknown',
126
+ platform: typeof process !== 'undefined' ? process.platform : 'unknown',
127
+ },
128
+ interval: this.config.refreshInterval,
129
+ };
130
+ await this.makeRequest(url, {
131
+ method: 'POST',
132
+ body: JSON.stringify(payload),
133
+ });
134
+ }
135
+ /**
136
+ * Start polling for feature updates
137
+ */
138
+ startPolling() {
139
+ this.pollInterval = setInterval(() => {
140
+ void this.fetchFeatures().catch((error) => {
141
+ this.emit('error', {
142
+ type: 'error',
143
+ error: error instanceof Error ? error : new Error(String(error)),
144
+ });
145
+ });
146
+ }, this.config.refreshInterval);
147
+ // Ensure the interval doesn't prevent Node.js from exiting
148
+ if (this.pollInterval.unref) {
149
+ this.pollInterval.unref();
150
+ }
151
+ }
152
+ /**
153
+ * Fetch features from the API
154
+ */
155
+ async fetchFeatures() {
156
+ const url = `${this.config.baseUrl}/client/features`;
157
+ const headers = {};
158
+ if (this.etag) {
159
+ headers['If-None-Match'] = this.etag;
160
+ }
161
+ const response = await this.makeRequest(url, {
162
+ method: 'GET',
163
+ headers,
164
+ expectNotModified: true,
165
+ });
166
+ // 304 Not Modified - no changes
167
+ if (response.status === 304) {
168
+ return;
169
+ }
170
+ const data = (await response.json());
171
+ const previousVersion = this.repository.getVersion();
172
+ this.repository.update(data);
173
+ // Update etag
174
+ const newEtag = response.headers.get('etag');
175
+ if (newEtag) {
176
+ this.etag = newEtag;
177
+ }
178
+ // Emit update event if version changed and client was already ready
179
+ if (this.ready && data.version !== previousVersion) {
180
+ this.emit('update', {
181
+ type: 'update',
182
+ features: this.repository.getAll(),
183
+ version: data.version,
184
+ });
185
+ }
186
+ }
187
+ /**
188
+ * Make an HTTP request
189
+ */
190
+ async makeRequest(url, options) {
191
+ const controller = new AbortController();
192
+ const timeoutId = setTimeout(() => controller.abort(), this.config.timeout);
193
+ try {
194
+ const response = await fetch(url, {
195
+ method: options.method,
196
+ headers: {
197
+ 'Content-Type': 'application/json',
198
+ Authorization: this.config.token,
199
+ ...options.headers,
200
+ },
201
+ body: options.body,
202
+ signal: controller.signal,
203
+ });
204
+ // Handle 304 Not Modified
205
+ if (options.expectNotModified && response.status === 304) {
206
+ return response;
207
+ }
208
+ if (response.status === 401 || response.status === 403) {
209
+ throw new index_js_1.AuthenticationError();
210
+ }
211
+ if (!response.ok) {
212
+ throw new index_js_1.NetworkError(`Request failed: ${response.statusText}`, response.status);
213
+ }
214
+ return response;
215
+ }
216
+ catch (error) {
217
+ if (error instanceof Error && error.name === 'AbortError') {
218
+ throw new index_js_1.TimeoutError();
219
+ }
220
+ if (error instanceof index_js_1.NetworkError ||
221
+ error instanceof index_js_1.AuthenticationError ||
222
+ error instanceof index_js_1.TimeoutError) {
223
+ throw error;
224
+ }
225
+ throw new index_js_1.NetworkError(`Request failed: ${error instanceof Error ? error.message : 'Unknown error'}`, undefined, error instanceof Error ? error : undefined);
226
+ }
227
+ finally {
228
+ clearTimeout(timeoutId);
229
+ }
230
+ }
231
+ /**
232
+ * Check if a feature is enabled
233
+ */
234
+ isEnabled(featureName, context) {
235
+ const feature = this.repository.get(featureName);
236
+ if (!feature) {
237
+ // Unknown feature - return false
238
+ this.metricsReporter.track(featureName, false);
239
+ return false;
240
+ }
241
+ if (!feature.enabled) {
242
+ // Feature is globally disabled
243
+ this.metricsReporter.track(featureName, false);
244
+ return false;
245
+ }
246
+ // Evaluate strategies
247
+ const enabled = this.evaluateFeature(feature, context);
248
+ this.metricsReporter.track(featureName, enabled);
249
+ return enabled;
250
+ }
251
+ /**
252
+ * Evaluate a feature's strategies
253
+ */
254
+ evaluateFeature(feature, context) {
255
+ if (!feature.strategies || feature.strategies.length === 0) {
256
+ // No strategies - return the feature's enabled status
257
+ return feature.enabled;
258
+ }
259
+ // Strategies are evaluated in order (by sortOrder)
260
+ // First matching enabled strategy wins
261
+ const sortedStrategies = [...feature.strategies].sort((a, b) => a.sortOrder - b.sortOrder);
262
+ for (const strategy of sortedStrategies) {
263
+ if (this.evaluator.evaluate(strategy, context)) {
264
+ return true;
265
+ }
266
+ }
267
+ return false;
268
+ }
269
+ /**
270
+ * Get a feature by name
271
+ */
272
+ getFeature(featureName) {
273
+ return this.repository.get(featureName);
274
+ }
275
+ /**
276
+ * Get all features
277
+ */
278
+ getAllFeatures() {
279
+ return this.repository.getAll();
280
+ }
281
+ /**
282
+ * Check if client is ready
283
+ */
284
+ isReady() {
285
+ return this.ready;
286
+ }
287
+ /**
288
+ * Subscribe to an event
289
+ */
290
+ on(event, handler) {
291
+ const handlers = this.events.get(event);
292
+ if (handlers) {
293
+ handlers.add(handler);
294
+ }
295
+ }
296
+ /**
297
+ * Unsubscribe from an event
298
+ */
299
+ off(event, handler) {
300
+ const handlers = this.events.get(event);
301
+ if (handlers) {
302
+ handlers.delete(handler);
303
+ }
304
+ }
305
+ emit(event, data) {
306
+ const handlers = this.events.get(event);
307
+ if (handlers) {
308
+ for (const handler of handlers) {
309
+ try {
310
+ handler(data);
311
+ }
312
+ catch {
313
+ // Ignore handler errors
314
+ }
315
+ }
316
+ }
317
+ }
318
+ }
319
+ exports.SetGoClient = SetGoClient;
@@ -0,0 +1,8 @@
1
+ /**
2
+ * SetGo SDK Core - Re-exports
3
+ */
4
+ export { SetGoClient } from './client.js';
5
+ export { FeatureRepository } from './repository.js';
6
+ export { StrategyEvaluator } from './strategy-evaluator.js';
7
+ export { MetricsReporter } from './metrics-reporter.js';
8
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/core/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACpD,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC"}
@@ -0,0 +1,14 @@
1
+ "use strict";
2
+ /**
3
+ * SetGo SDK Core - Re-exports
4
+ */
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.MetricsReporter = exports.StrategyEvaluator = exports.FeatureRepository = exports.SetGoClient = void 0;
7
+ var client_js_1 = require("./client.js");
8
+ Object.defineProperty(exports, "SetGoClient", { enumerable: true, get: function () { return client_js_1.SetGoClient; } });
9
+ var repository_js_1 = require("./repository.js");
10
+ Object.defineProperty(exports, "FeatureRepository", { enumerable: true, get: function () { return repository_js_1.FeatureRepository; } });
11
+ var strategy_evaluator_js_1 = require("./strategy-evaluator.js");
12
+ Object.defineProperty(exports, "StrategyEvaluator", { enumerable: true, get: function () { return strategy_evaluator_js_1.StrategyEvaluator; } });
13
+ var metrics_reporter_js_1 = require("./metrics-reporter.js");
14
+ Object.defineProperty(exports, "MetricsReporter", { enumerable: true, get: function () { return metrics_reporter_js_1.MetricsReporter; } });
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Metrics Reporter - collects and sends usage metrics
3
+ */
4
+ import type { ResolvedSetGoConfig } from '../types/index.js';
5
+ export declare class MetricsReporter {
6
+ private metrics;
7
+ private bucketStart;
8
+ private sendInterval?;
9
+ private config;
10
+ constructor(config: ResolvedSetGoConfig);
11
+ /**
12
+ * Get the current hour bucket timestamp
13
+ */
14
+ private getCurrentHourBucket;
15
+ /**
16
+ * Start the metrics reporting interval
17
+ */
18
+ start(): void;
19
+ /**
20
+ * Stop the metrics reporting interval
21
+ */
22
+ stop(): void;
23
+ /**
24
+ * Track a feature evaluation
25
+ */
26
+ track(featureName: string, enabled: boolean): void;
27
+ /**
28
+ * Flush metrics to the server
29
+ */
30
+ flush(): Promise<void>;
31
+ /**
32
+ * Send metrics to the API
33
+ */
34
+ private sendMetrics;
35
+ /**
36
+ * Get current metrics count (for testing/debugging)
37
+ */
38
+ getMetricsCount(): number;
39
+ }
40
+ //# sourceMappingURL=metrics-reporter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"metrics-reporter.d.ts","sourceRoot":"","sources":["../../src/core/metrics-reporter.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAiC,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAQ5F,qBAAa,eAAe;IAC1B,OAAO,CAAC,OAAO,CAA6C;IAC5D,OAAO,CAAC,WAAW,CAAO;IAC1B,OAAO,CAAC,YAAY,CAAC,CAAiC;IACtD,OAAO,CAAC,MAAM,CAAsB;gBAExB,MAAM,EAAE,mBAAmB;IAKvC;;OAEG;IACH,OAAO,CAAC,oBAAoB;IAM5B;;OAEG;IACH,KAAK,IAAI,IAAI;IAab;;OAEG;IACH,IAAI,IAAI,IAAI;IAOZ;;OAEG;IACH,KAAK,CAAC,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,IAAI;IAsBlD;;OAEG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAyC5B;;OAEG;YACW,WAAW;IAqCzB;;OAEG;IACH,eAAe,IAAI,MAAM;CAG1B"}