@canarygate/sdk 0.1.0 → 0.1.2

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 CHANGED
@@ -2,8 +2,8 @@
2
2
 
3
3
  Feature flag client for [CanaryGate](https://github.com/rborges98/canarygate).
4
4
 
5
- - **Server (Node.js)** — snapshot on `init()` + live updates via SSE, with auto-reconnect and heartbeat detection
6
- - **Browser** — flags fetched once and cached; SSE stays off to protect your infrastructure
5
+ - **Server (Node.js)** — snapshot on `init()` + live updates via SSE, auto-reconnect and heartbeat
6
+ - **Browser** — snapshot + polling via `pollIntervalMs`
7
7
 
8
8
  ## Install
9
9
 
@@ -19,12 +19,11 @@ npm install @canarygate/sdk
19
19
  import { CanaryGate } from '@canarygate/sdk/server'
20
20
 
21
21
  const gate = new CanaryGate('your-api-key', {
22
- environment: 'production',
23
- stream: true
22
+ environment: 'production'
24
23
  })
25
24
 
26
25
  await gate.init()
27
- // flags keep updating in the background via SSE
26
+ // the snapshot is fetched and SSE opens automatically
28
27
 
29
28
  gate.disconnect() // when shutting down
30
29
  ```
@@ -70,7 +69,7 @@ Rollout evaluation hashes `userId` deterministically — the same user always ge
70
69
  | -------------------- | --------- | ----------------------- | ------------------------------------------------ |
71
70
  | `baseUrl` | `string` | `http://localhost:3001` | CanaryGate API base URL |
72
71
  | `environment` | `string` | — | Environment to evaluate flags against |
73
- | `stream` | `boolean` | `false` | Real-time SSE updates (server mode only) |
72
+ | `pollIntervalMs` | `number` | `30000` | Browser polling interval in ms (clamped to a 3000ms minimum). Set `0` to disable |
74
73
  | `reconnectDelay` | `number` | `5000` | Initial SSE reconnect delay (ms) |
75
74
  | `maxReconnectDelay` | `number` | `30000` | Reconnect delay cap, exponential backoff (ms) |
76
75
  | `heartbeatTimeoutMs` | `number` | `65000` | Silence window before treating the stream as dead |
@@ -79,7 +78,7 @@ Rollout evaluation hashes `userId` deterministically — the same user always ge
79
78
 
80
79
  | Method | Description |
81
80
  | --------------------- | -------------------------------------------------- |
82
- | `init()` | Fetches flags and starts the stream when enabled |
81
+ | `init()` | Fetches the snapshot; the server entry opens SSE, the browser entry starts polling |
83
82
  | `getFlag(key, ctx?)` | Evaluates one flag (`boolean` or `rollout`) |
84
83
  | `getFlags(ctx?)` | Evaluates all cached flags |
85
84
  | `isStale()` | Whether the last sync attempt failed |
@@ -89,9 +88,13 @@ Rollout evaluation hashes `userId` deterministically — the same user always ge
89
88
  ## How sync works
90
89
 
91
90
  1. `init()` fetches a full snapshot from `/sdk/flags`.
92
- 2. With `stream: true`, an SSE connection receives granular updates per change.
91
+ 2. The server entry always opens an SSE connection that receives granular updates per change; the browser entry polls the snapshot every `pollIntervalMs`.
93
92
  3. On disconnect, the SDK reconnects with exponential backoff and does a full resync over the snapshot endpoint.
94
93
 
94
+ ## Entry-point guards
95
+
96
+ Each entry point is bound to its environment: the server entry throws `Error('@canarygate/sdk/server is server-only. In browsers import from "@canarygate/sdk/client" instead.')` if used where `window` exists, and the client entry throws a browser-only error if used where there is no `window`.
97
+
95
98
  ## License
96
99
 
97
100
  [MIT](./LICENSE)
@@ -16,7 +16,8 @@ type FlagEvaluationContext = {
16
16
  type CanaryGateOptions = {
17
17
  baseUrl?: string;
18
18
  environment?: string;
19
- stream?: boolean;
19
+ /** Browser polling interval in ms. Default: 30000; minimum enforced: 3000. Set 0 to disable. Server always uses SSE instead. */
20
+ pollIntervalMs?: number;
20
21
  reconnectDelay?: number;
21
22
  maxReconnectDelay?: number;
22
23
  heartbeatTimeoutMs?: number;
@@ -31,19 +32,20 @@ declare class CanaryGateBase {
31
32
  private readonly reconnectDelay;
32
33
  private readonly maxReconnectDelay;
33
34
  private readonly heartbeatTimeoutMs;
35
+ private readonly pollIntervalMs;
34
36
  private cache;
35
37
  private cacheVersions;
36
38
  private readonly anonId;
37
39
  private streamAbortController;
38
40
  private reconnectTimeout;
39
41
  private heartbeatTimeout;
42
+ private pollTimeout;
40
43
  private streamRetryDelay;
41
44
  private reconnectAttempts;
42
45
  private stale;
43
46
  private lastSyncAt;
44
47
  private destroyed;
45
48
  constructor(apiKey: string, options: CanaryGateOptions | undefined, streamEnabled: boolean, anonIdFactory: () => string);
46
- protected warnStreamDisabled(): void;
47
49
  init(): Promise<void>;
48
50
  private replaceCacheFromSnapshot;
49
51
  private fetchFlags;
@@ -55,6 +57,8 @@ declare class CanaryGateBase {
55
57
  private scheduleReconnect;
56
58
  private consumeStream;
57
59
  private connectStream;
60
+ private startPolling;
61
+ private stopPolling;
58
62
  getFlag(key: string, context?: FlagEvaluationContext): FlagData | undefined;
59
63
  getFlags(context?: FlagEvaluationContext): FlagData[];
60
64
  isStale(): boolean;
@@ -16,7 +16,8 @@ type FlagEvaluationContext = {
16
16
  type CanaryGateOptions = {
17
17
  baseUrl?: string;
18
18
  environment?: string;
19
- stream?: boolean;
19
+ /** Browser polling interval in ms. Default: 30000; minimum enforced: 3000. Set 0 to disable. Server always uses SSE instead. */
20
+ pollIntervalMs?: number;
20
21
  reconnectDelay?: number;
21
22
  maxReconnectDelay?: number;
22
23
  heartbeatTimeoutMs?: number;
@@ -31,19 +32,20 @@ declare class CanaryGateBase {
31
32
  private readonly reconnectDelay;
32
33
  private readonly maxReconnectDelay;
33
34
  private readonly heartbeatTimeoutMs;
35
+ private readonly pollIntervalMs;
34
36
  private cache;
35
37
  private cacheVersions;
36
38
  private readonly anonId;
37
39
  private streamAbortController;
38
40
  private reconnectTimeout;
39
41
  private heartbeatTimeout;
42
+ private pollTimeout;
40
43
  private streamRetryDelay;
41
44
  private reconnectAttempts;
42
45
  private stale;
43
46
  private lastSyncAt;
44
47
  private destroyed;
45
48
  constructor(apiKey: string, options: CanaryGateOptions | undefined, streamEnabled: boolean, anonIdFactory: () => string);
46
- protected warnStreamDisabled(): void;
47
49
  init(): Promise<void>;
48
50
  private replaceCacheFromSnapshot;
49
51
  private fetchFlags;
@@ -55,6 +57,8 @@ declare class CanaryGateBase {
55
57
  private scheduleReconnect;
56
58
  private consumeStream;
57
59
  private connectStream;
60
+ private startPolling;
61
+ private stopPolling;
58
62
  getFlag(key: string, context?: FlagEvaluationContext): FlagData | undefined;
59
63
  getFlags(context?: FlagEvaluationContext): FlagData[];
60
64
  isStale(): boolean;
@@ -42,6 +42,8 @@ function parseSseEventBlock(block) {
42
42
  // src/canary-gate-base.ts
43
43
  var DEFAULT_MAX_RECONNECT_DELAY_MS = 3e4;
44
44
  var DEFAULT_HEARTBEAT_TIMEOUT_MS = 65e3;
45
+ var DEFAULT_POLL_INTERVAL_MS = 3e4;
46
+ var MIN_POLL_INTERVAL_MS = 3e3;
45
47
  function isAbortError(error) {
46
48
  return error instanceof DOMException && error.name === "AbortError" || error instanceof Error && error.name === "AbortError";
47
49
  }
@@ -59,6 +61,7 @@ var CanaryGateBase = class {
59
61
  this.streamAbortController = null;
60
62
  this.reconnectTimeout = null;
61
63
  this.heartbeatTimeout = null;
64
+ this.pollTimeout = null;
62
65
  this.reconnectAttempts = 0;
63
66
  this.stale = false;
64
67
  this.lastSyncAt = null;
@@ -74,17 +77,23 @@ var CanaryGateBase = class {
74
77
  this.reconnectDelay
75
78
  );
76
79
  this.heartbeatTimeoutMs = options.heartbeatTimeoutMs ?? DEFAULT_HEARTBEAT_TIMEOUT_MS;
80
+ this.pollIntervalMs = options.pollIntervalMs ?? DEFAULT_POLL_INTERVAL_MS;
81
+ if (options.pollIntervalMs !== void 0 && options.pollIntervalMs > 0 && options.pollIntervalMs < MIN_POLL_INTERVAL_MS) {
82
+ console.warn(
83
+ `[canarygate] pollIntervalMs must be at least ${MIN_POLL_INTERVAL_MS}ms; clamped to ${MIN_POLL_INTERVAL_MS}.`
84
+ );
85
+ this.pollIntervalMs = MIN_POLL_INTERVAL_MS;
86
+ }
77
87
  this.streamRetryDelay = this.reconnectDelay;
78
88
  this.anonId = anonIdFactory();
79
89
  }
80
- warnStreamDisabled() {
81
- console.warn(
82
- "[canarygate] Real-time streams (SSE) are disabled in browser environments to protect network architecture."
83
- );
84
- }
85
90
  async init() {
86
91
  await this.fetchFlags();
87
- if (this.streamEnabled) this.connectStream();
92
+ if (this.streamEnabled) {
93
+ this.connectStream();
94
+ } else {
95
+ this.startPolling();
96
+ }
88
97
  }
89
98
  replaceCacheFromSnapshot(flags, requestedAt) {
90
99
  const nextCache = /* @__PURE__ */ new Map();
@@ -270,6 +279,20 @@ var CanaryGateBase = class {
270
279
  this.streamAbortController = abortController;
271
280
  void this.consumeStream(abortController);
272
281
  }
282
+ startPolling() {
283
+ if (this.destroyed || this.streamEnabled || this.pollIntervalMs <= 0 || this.pollTimeout) {
284
+ return;
285
+ }
286
+ this.pollTimeout = setInterval(() => {
287
+ void this.fetchFlags();
288
+ }, this.pollIntervalMs);
289
+ }
290
+ stopPolling() {
291
+ if (this.pollTimeout) {
292
+ clearInterval(this.pollTimeout);
293
+ this.pollTimeout = null;
294
+ }
295
+ }
273
296
  getFlag(key, context) {
274
297
  const raw = this.cache.get(key);
275
298
  if (!raw) return void 0;
@@ -298,6 +321,7 @@ var CanaryGateBase = class {
298
321
  }
299
322
  disconnect() {
300
323
  this.destroyed = true;
324
+ this.stopPolling();
301
325
  if (this.reconnectTimeout) {
302
326
  clearTimeout(this.reconnectTimeout);
303
327
  this.reconnectTimeout = null;
package/dist/client.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- import { C as CanaryGateBase, a as CanaryGateOptions } from './canary-gate-base-D069Q1Z_.mjs';
1
+ import { C as CanaryGateBase, a as CanaryGateOptions } from './canary-gate-base-iXS3mVyK.mjs';
2
2
 
3
3
  declare class CanaryGate extends CanaryGateBase {
4
4
  constructor(apiKey: string, options?: CanaryGateOptions);
package/dist/client.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { C as CanaryGateBase, a as CanaryGateOptions } from './canary-gate-base-D069Q1Z_.js';
1
+ import { C as CanaryGateBase, a as CanaryGateOptions } from './canary-gate-base-iXS3mVyK.js';
2
2
 
3
3
  declare class CanaryGate extends CanaryGateBase {
4
4
  constructor(apiKey: string, options?: CanaryGateOptions);
package/dist/client.js CHANGED
@@ -68,6 +68,8 @@ function parseSseEventBlock(block) {
68
68
  // src/canary-gate-base.ts
69
69
  var DEFAULT_MAX_RECONNECT_DELAY_MS = 3e4;
70
70
  var DEFAULT_HEARTBEAT_TIMEOUT_MS = 65e3;
71
+ var DEFAULT_POLL_INTERVAL_MS = 3e4;
72
+ var MIN_POLL_INTERVAL_MS = 3e3;
71
73
  function isAbortError(error) {
72
74
  return error instanceof DOMException && error.name === "AbortError" || error instanceof Error && error.name === "AbortError";
73
75
  }
@@ -85,6 +87,7 @@ var CanaryGateBase = class {
85
87
  this.streamAbortController = null;
86
88
  this.reconnectTimeout = null;
87
89
  this.heartbeatTimeout = null;
90
+ this.pollTimeout = null;
88
91
  this.reconnectAttempts = 0;
89
92
  this.stale = false;
90
93
  this.lastSyncAt = null;
@@ -100,17 +103,23 @@ var CanaryGateBase = class {
100
103
  this.reconnectDelay
101
104
  );
102
105
  this.heartbeatTimeoutMs = options.heartbeatTimeoutMs ?? DEFAULT_HEARTBEAT_TIMEOUT_MS;
106
+ this.pollIntervalMs = options.pollIntervalMs ?? DEFAULT_POLL_INTERVAL_MS;
107
+ if (options.pollIntervalMs !== void 0 && options.pollIntervalMs > 0 && options.pollIntervalMs < MIN_POLL_INTERVAL_MS) {
108
+ console.warn(
109
+ `[canarygate] pollIntervalMs must be at least ${MIN_POLL_INTERVAL_MS}ms; clamped to ${MIN_POLL_INTERVAL_MS}.`
110
+ );
111
+ this.pollIntervalMs = MIN_POLL_INTERVAL_MS;
112
+ }
103
113
  this.streamRetryDelay = this.reconnectDelay;
104
114
  this.anonId = anonIdFactory();
105
115
  }
106
- warnStreamDisabled() {
107
- console.warn(
108
- "[canarygate] Real-time streams (SSE) are disabled in browser environments to protect network architecture."
109
- );
110
- }
111
116
  async init() {
112
117
  await this.fetchFlags();
113
- if (this.streamEnabled) this.connectStream();
118
+ if (this.streamEnabled) {
119
+ this.connectStream();
120
+ } else {
121
+ this.startPolling();
122
+ }
114
123
  }
115
124
  replaceCacheFromSnapshot(flags, requestedAt) {
116
125
  const nextCache = /* @__PURE__ */ new Map();
@@ -296,6 +305,20 @@ var CanaryGateBase = class {
296
305
  this.streamAbortController = abortController;
297
306
  void this.consumeStream(abortController);
298
307
  }
308
+ startPolling() {
309
+ if (this.destroyed || this.streamEnabled || this.pollIntervalMs <= 0 || this.pollTimeout) {
310
+ return;
311
+ }
312
+ this.pollTimeout = setInterval(() => {
313
+ void this.fetchFlags();
314
+ }, this.pollIntervalMs);
315
+ }
316
+ stopPolling() {
317
+ if (this.pollTimeout) {
318
+ clearInterval(this.pollTimeout);
319
+ this.pollTimeout = null;
320
+ }
321
+ }
299
322
  getFlag(key, context) {
300
323
  const raw = this.cache.get(key);
301
324
  if (!raw) return void 0;
@@ -324,6 +347,7 @@ var CanaryGateBase = class {
324
347
  }
325
348
  disconnect() {
326
349
  this.destroyed = true;
350
+ this.stopPolling();
327
351
  if (this.reconnectTimeout) {
328
352
  clearTimeout(this.reconnectTimeout);
329
353
  this.reconnectTimeout = null;
@@ -348,10 +372,12 @@ function getOrCreateAnonId() {
348
372
  }
349
373
  var CanaryGate = class extends CanaryGateBase {
350
374
  constructor(apiKey, options = {}) {
351
- super(apiKey, options, false, getOrCreateAnonId);
352
- if (options.stream === true) {
353
- this.warnStreamDisabled();
375
+ if (typeof window === "undefined") {
376
+ throw new Error(
377
+ '@canarygate/sdk/client is browser-only. On server runtimes (Node.js, Deno, Bun, Edge) import from "@canarygate/sdk/server" instead.'
378
+ );
354
379
  }
380
+ super(apiKey, options, false, getOrCreateAnonId);
355
381
  }
356
382
  };
357
383
  // Annotate the CommonJS export names for ESM import in node:
package/dist/client.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  CanaryGateBase
3
- } from "./chunk-7KAJ7OJO.mjs";
3
+ } from "./chunk-LMPIWD3Z.mjs";
4
4
 
5
5
  // src/client.ts
6
6
  var ANON_ID_KEY = "__cg_anon_id__";
@@ -16,10 +16,12 @@ function getOrCreateAnonId() {
16
16
  }
17
17
  var CanaryGate = class extends CanaryGateBase {
18
18
  constructor(apiKey, options = {}) {
19
- super(apiKey, options, false, getOrCreateAnonId);
20
- if (options.stream === true) {
21
- this.warnStreamDisabled();
19
+ if (typeof window === "undefined") {
20
+ throw new Error(
21
+ '@canarygate/sdk/client is browser-only. On server runtimes (Node.js, Deno, Bun, Edge) import from "@canarygate/sdk/server" instead.'
22
+ );
22
23
  }
24
+ super(apiKey, options, false, getOrCreateAnonId);
23
25
  }
24
26
  };
25
27
  export {
package/dist/server.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- import { C as CanaryGateBase, a as CanaryGateOptions } from './canary-gate-base-D069Q1Z_.mjs';
1
+ import { C as CanaryGateBase, a as CanaryGateOptions } from './canary-gate-base-iXS3mVyK.mjs';
2
2
 
3
3
  declare class CanaryGate extends CanaryGateBase {
4
4
  constructor(apiKey: string, options?: CanaryGateOptions);
package/dist/server.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { C as CanaryGateBase, a as CanaryGateOptions } from './canary-gate-base-D069Q1Z_.js';
1
+ import { C as CanaryGateBase, a as CanaryGateOptions } from './canary-gate-base-iXS3mVyK.js';
2
2
 
3
3
  declare class CanaryGate extends CanaryGateBase {
4
4
  constructor(apiKey: string, options?: CanaryGateOptions);
package/dist/server.js CHANGED
@@ -68,6 +68,8 @@ function parseSseEventBlock(block) {
68
68
  // src/canary-gate-base.ts
69
69
  var DEFAULT_MAX_RECONNECT_DELAY_MS = 3e4;
70
70
  var DEFAULT_HEARTBEAT_TIMEOUT_MS = 65e3;
71
+ var DEFAULT_POLL_INTERVAL_MS = 3e4;
72
+ var MIN_POLL_INTERVAL_MS = 3e3;
71
73
  function isAbortError(error) {
72
74
  return error instanceof DOMException && error.name === "AbortError" || error instanceof Error && error.name === "AbortError";
73
75
  }
@@ -85,6 +87,7 @@ var CanaryGateBase = class {
85
87
  this.streamAbortController = null;
86
88
  this.reconnectTimeout = null;
87
89
  this.heartbeatTimeout = null;
90
+ this.pollTimeout = null;
88
91
  this.reconnectAttempts = 0;
89
92
  this.stale = false;
90
93
  this.lastSyncAt = null;
@@ -100,17 +103,23 @@ var CanaryGateBase = class {
100
103
  this.reconnectDelay
101
104
  );
102
105
  this.heartbeatTimeoutMs = options.heartbeatTimeoutMs ?? DEFAULT_HEARTBEAT_TIMEOUT_MS;
106
+ this.pollIntervalMs = options.pollIntervalMs ?? DEFAULT_POLL_INTERVAL_MS;
107
+ if (options.pollIntervalMs !== void 0 && options.pollIntervalMs > 0 && options.pollIntervalMs < MIN_POLL_INTERVAL_MS) {
108
+ console.warn(
109
+ `[canarygate] pollIntervalMs must be at least ${MIN_POLL_INTERVAL_MS}ms; clamped to ${MIN_POLL_INTERVAL_MS}.`
110
+ );
111
+ this.pollIntervalMs = MIN_POLL_INTERVAL_MS;
112
+ }
103
113
  this.streamRetryDelay = this.reconnectDelay;
104
114
  this.anonId = anonIdFactory();
105
115
  }
106
- warnStreamDisabled() {
107
- console.warn(
108
- "[canarygate] Real-time streams (SSE) are disabled in browser environments to protect network architecture."
109
- );
110
- }
111
116
  async init() {
112
117
  await this.fetchFlags();
113
- if (this.streamEnabled) this.connectStream();
118
+ if (this.streamEnabled) {
119
+ this.connectStream();
120
+ } else {
121
+ this.startPolling();
122
+ }
114
123
  }
115
124
  replaceCacheFromSnapshot(flags, requestedAt) {
116
125
  const nextCache = /* @__PURE__ */ new Map();
@@ -296,6 +305,20 @@ var CanaryGateBase = class {
296
305
  this.streamAbortController = abortController;
297
306
  void this.consumeStream(abortController);
298
307
  }
308
+ startPolling() {
309
+ if (this.destroyed || this.streamEnabled || this.pollIntervalMs <= 0 || this.pollTimeout) {
310
+ return;
311
+ }
312
+ this.pollTimeout = setInterval(() => {
313
+ void this.fetchFlags();
314
+ }, this.pollIntervalMs);
315
+ }
316
+ stopPolling() {
317
+ if (this.pollTimeout) {
318
+ clearInterval(this.pollTimeout);
319
+ this.pollTimeout = null;
320
+ }
321
+ }
299
322
  getFlag(key, context) {
300
323
  const raw = this.cache.get(key);
301
324
  if (!raw) return void 0;
@@ -324,6 +347,7 @@ var CanaryGateBase = class {
324
347
  }
325
348
  disconnect() {
326
349
  this.destroyed = true;
350
+ this.stopPolling();
327
351
  if (this.reconnectTimeout) {
328
352
  clearTimeout(this.reconnectTimeout);
329
353
  this.reconnectTimeout = null;
@@ -337,7 +361,12 @@ var CanaryGateBase = class {
337
361
  // src/server.ts
338
362
  var CanaryGate = class extends CanaryGateBase {
339
363
  constructor(apiKey, options = {}) {
340
- super(apiKey, options, options.stream ?? false, () => crypto.randomUUID());
364
+ if (typeof window !== "undefined") {
365
+ throw new Error(
366
+ '@canarygate/sdk/server is server-only. In browsers import from "@canarygate/sdk/client" instead.'
367
+ );
368
+ }
369
+ super(apiKey, options, true, () => crypto.randomUUID());
341
370
  }
342
371
  };
343
372
  // Annotate the CommonJS export names for ESM import in node:
package/dist/server.mjs CHANGED
@@ -1,11 +1,16 @@
1
1
  import {
2
2
  CanaryGateBase
3
- } from "./chunk-7KAJ7OJO.mjs";
3
+ } from "./chunk-LMPIWD3Z.mjs";
4
4
 
5
5
  // src/server.ts
6
6
  var CanaryGate = class extends CanaryGateBase {
7
7
  constructor(apiKey, options = {}) {
8
- super(apiKey, options, options.stream ?? false, () => crypto.randomUUID());
8
+ if (typeof window !== "undefined") {
9
+ throw new Error(
10
+ '@canarygate/sdk/server is server-only. In browsers import from "@canarygate/sdk/client" instead.'
11
+ );
12
+ }
13
+ super(apiKey, options, true, () => crypto.randomUUID());
9
14
  }
10
15
  };
11
16
  export {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@canarygate/sdk",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "CanaryGate SDK — feature flags with real-time SSE streaming",
5
5
  "exports": {
6
6
  "./client": {
@@ -15,20 +15,18 @@
15
15
  },
16
16
  "./package.json": "./package.json"
17
17
  },
18
- "files": [
19
- "dist",
20
- "README.md",
21
- "LICENSE"
22
- ],
18
+ "files": ["dist", "README.md", "LICENSE"],
19
+ "scripts": {
20
+ "build": "tsup src/client.ts src/server.ts --format esm,cjs --dts --out-dir dist",
21
+ "check-types": "tsc --noEmit",
22
+ "test": "vitest run",
23
+ "test:watch": "vitest",
24
+ "test:coverage": "vitest run --coverage",
25
+ "prepublishOnly": "pnpm build"
26
+ },
23
27
  "sideEffects": false,
24
28
  "license": "MIT",
25
- "keywords": [
26
- "feature-flags",
27
- "feature-toggles",
28
- "sse",
29
- "real-time",
30
- "rollout"
31
- ],
29
+ "keywords": ["feature-flags", "feature-toggles", "sse", "real-time", "rollout"],
32
30
  "repository": {
33
31
  "type": "git",
34
32
  "url": "git+https://github.com/rborges98/canarygate.git",
@@ -47,12 +45,5 @@
47
45
  "tsup": "^8.5.1",
48
46
  "typescript": "^5",
49
47
  "vitest": "^3.0.0"
50
- },
51
- "scripts": {
52
- "build": "tsup src/client.ts src/server.ts --format esm,cjs --dts --out-dir dist",
53
- "check-types": "tsc --noEmit",
54
- "test": "vitest run",
55
- "test:watch": "vitest",
56
- "test:coverage": "vitest run --coverage"
57
48
  }
58
- }
49
+ }