@shipeasy/sdk 1.0.0 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -21,6 +21,10 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
21
21
  var server_exports = {};
22
22
  __export(server_exports, {
23
23
  FlagsClient: () => FlagsClient,
24
+ _resetShipeasyServerForTests: () => _resetShipeasyServerForTests,
25
+ configureShipeasyServer: () => configureShipeasyServer,
26
+ flags: () => flags,
27
+ getShipeasyServerClient: () => getShipeasyServerClient,
24
28
  version: () => version
25
29
  });
26
30
  module.exports = __toCommonJS(server_exports);
@@ -127,6 +131,7 @@ function evalGateInternal(gate, user) {
127
131
  var FlagsClient = class {
128
132
  apiKey;
129
133
  baseUrl;
134
+ env;
130
135
  flagsBlob = null;
131
136
  expsBlob = null;
132
137
  flagsEtag = null;
@@ -137,6 +142,7 @@ var FlagsClient = class {
137
142
  constructor(opts) {
138
143
  this.apiKey = opts.apiKey;
139
144
  this.baseUrl = (opts.baseUrl ?? "https://edge.shipeasy.dev").replace(/\/$/, "");
145
+ this.env = opts.env ?? "prod";
140
146
  }
141
147
  async init() {
142
148
  await this.fetchAll();
@@ -174,7 +180,7 @@ var FlagsClient = class {
174
180
  async fetchFlags() {
175
181
  const headers = { "X-SDK-Key": this.apiKey };
176
182
  if (this.flagsEtag) headers["If-None-Match"] = this.flagsEtag;
177
- const res = await globalThis.fetch(`${this.baseUrl}/sdk/flags`, { headers });
183
+ const res = await globalThis.fetch(`${this.baseUrl}/sdk/flags?env=${this.env}`, { headers });
178
184
  const interval = Number(res.headers.get("X-Poll-Interval") ?? "30") || 30;
179
185
  if (res.status === 304) return interval;
180
186
  if (!res.ok) throw new Error(`/sdk/flags returned ${res.status}`);
@@ -265,8 +271,63 @@ var FlagsClient = class {
265
271
  }).catch((err) => console.warn("[shipeasy] track failed:", String(err)));
266
272
  }
267
273
  };
274
+ var _server = null;
275
+ function configureShipeasyServer(opts) {
276
+ if (_server) return _server;
277
+ _server = new FlagsClient(opts);
278
+ return _server;
279
+ }
280
+ function getShipeasyServerClient() {
281
+ return _server;
282
+ }
283
+ function _resetShipeasyServerForTests() {
284
+ _server?.destroy();
285
+ _server = null;
286
+ }
287
+ var flags = {
288
+ configure(opts) {
289
+ configureShipeasyServer(opts);
290
+ },
291
+ /**
292
+ * Long-running server: starts the background poll. Call once at app boot.
293
+ * Throws if the initial fetch fails (caller decides whether to crash or degrade).
294
+ */
295
+ init() {
296
+ if (!_server) throw new Error("[shipeasy] flags.init called before configure()");
297
+ return _server.init();
298
+ },
299
+ /** Serverless / edge: fetch rules once, no background timer. */
300
+ initOnce() {
301
+ if (!_server) throw new Error("[shipeasy] flags.initOnce called before configure()");
302
+ return _server.initOnce();
303
+ },
304
+ /** Stop background timers. Safe to call repeatedly. */
305
+ destroy() {
306
+ _server?.destroy();
307
+ },
308
+ get(name, user) {
309
+ return _server?.getFlag(name, user) ?? false;
310
+ },
311
+ getConfig(name, decode) {
312
+ return _server?.getConfig(name, decode);
313
+ },
314
+ getExperiment(name, user, defaultParams, decode) {
315
+ return _server?.getExperiment(name, user, defaultParams, decode) ?? {
316
+ inExperiment: false,
317
+ group: "control",
318
+ params: defaultParams
319
+ };
320
+ },
321
+ track(userId, eventName, props) {
322
+ _server?.track(userId, eventName, props);
323
+ }
324
+ };
268
325
  // Annotate the CommonJS export names for ESM import in node:
269
326
  0 && (module.exports = {
270
327
  FlagsClient,
328
+ _resetShipeasyServerForTests,
329
+ configureShipeasyServer,
330
+ flags,
331
+ getShipeasyServerClient,
271
332
  version
272
333
  });
@@ -102,6 +102,7 @@ function evalGateInternal(gate, user) {
102
102
  var FlagsClient = class {
103
103
  apiKey;
104
104
  baseUrl;
105
+ env;
105
106
  flagsBlob = null;
106
107
  expsBlob = null;
107
108
  flagsEtag = null;
@@ -112,6 +113,7 @@ var FlagsClient = class {
112
113
  constructor(opts) {
113
114
  this.apiKey = opts.apiKey;
114
115
  this.baseUrl = (opts.baseUrl ?? "https://edge.shipeasy.dev").replace(/\/$/, "");
116
+ this.env = opts.env ?? "prod";
115
117
  }
116
118
  async init() {
117
119
  await this.fetchAll();
@@ -149,7 +151,7 @@ var FlagsClient = class {
149
151
  async fetchFlags() {
150
152
  const headers = { "X-SDK-Key": this.apiKey };
151
153
  if (this.flagsEtag) headers["If-None-Match"] = this.flagsEtag;
152
- const res = await globalThis.fetch(`${this.baseUrl}/sdk/flags`, { headers });
154
+ const res = await globalThis.fetch(`${this.baseUrl}/sdk/flags?env=${this.env}`, { headers });
153
155
  const interval = Number(res.headers.get("X-Poll-Interval") ?? "30") || 30;
154
156
  if (res.status === 304) return interval;
155
157
  if (!res.ok) throw new Error(`/sdk/flags returned ${res.status}`);
@@ -240,7 +242,62 @@ var FlagsClient = class {
240
242
  }).catch((err) => console.warn("[shipeasy] track failed:", String(err)));
241
243
  }
242
244
  };
245
+ var _server = null;
246
+ function configureShipeasyServer(opts) {
247
+ if (_server) return _server;
248
+ _server = new FlagsClient(opts);
249
+ return _server;
250
+ }
251
+ function getShipeasyServerClient() {
252
+ return _server;
253
+ }
254
+ function _resetShipeasyServerForTests() {
255
+ _server?.destroy();
256
+ _server = null;
257
+ }
258
+ var flags = {
259
+ configure(opts) {
260
+ configureShipeasyServer(opts);
261
+ },
262
+ /**
263
+ * Long-running server: starts the background poll. Call once at app boot.
264
+ * Throws if the initial fetch fails (caller decides whether to crash or degrade).
265
+ */
266
+ init() {
267
+ if (!_server) throw new Error("[shipeasy] flags.init called before configure()");
268
+ return _server.init();
269
+ },
270
+ /** Serverless / edge: fetch rules once, no background timer. */
271
+ initOnce() {
272
+ if (!_server) throw new Error("[shipeasy] flags.initOnce called before configure()");
273
+ return _server.initOnce();
274
+ },
275
+ /** Stop background timers. Safe to call repeatedly. */
276
+ destroy() {
277
+ _server?.destroy();
278
+ },
279
+ get(name, user) {
280
+ return _server?.getFlag(name, user) ?? false;
281
+ },
282
+ getConfig(name, decode) {
283
+ return _server?.getConfig(name, decode);
284
+ },
285
+ getExperiment(name, user, defaultParams, decode) {
286
+ return _server?.getExperiment(name, user, defaultParams, decode) ?? {
287
+ inExperiment: false,
288
+ group: "control",
289
+ params: defaultParams
290
+ };
291
+ },
292
+ track(userId, eventName, props) {
293
+ _server?.track(userId, eventName, props);
294
+ }
295
+ };
243
296
  export {
244
297
  FlagsClient,
298
+ _resetShipeasyServerForTests,
299
+ configureShipeasyServer,
300
+ flags,
301
+ getShipeasyServerClient,
245
302
  version
246
303
  };
package/package.json CHANGED
@@ -1,10 +1,25 @@
1
1
  {
2
2
  "name": "@shipeasy/sdk",
3
- "version": "1.0.0",
4
- "description": "Feature flag and experimentation SDK",
3
+ "version": "1.1.0",
4
+ "description": "Shipeasy SDK — feature gates, runtime configs, experiments, and metrics for the Shipeasy hosted service.",
5
+ "license": "SEE LICENSE IN LICENSE",
6
+ "homepage": "https://shipeasy.ai",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "https://github.com/shipeasy-ai/sdk.git"
10
+ },
11
+ "bugs": {
12
+ "url": "https://github.com/shipeasy-ai/sdk/issues"
13
+ },
5
14
  "main": "./dist/server/index.js",
6
15
  "module": "./dist/server/index.mjs",
7
16
  "browser": "./dist/client/index.js",
17
+ "typesVersions": {
18
+ "*": {
19
+ "client": ["./dist/client/index.d.ts"],
20
+ "server": ["./dist/server/index.d.ts"]
21
+ }
22
+ },
8
23
  "exports": {
9
24
  ".": {
10
25
  "node": "./dist/server/index.js",
@@ -23,13 +38,18 @@
23
38
  "./templates/*": "./templates/*.js"
24
39
  },
25
40
  "files": [
26
- "dist/",
27
- "templates/"
41
+ "dist/server/",
42
+ "dist/client/",
43
+ "templates/",
44
+ "LICENSE",
45
+ "README.md"
28
46
  ],
29
47
  "scripts": {
30
48
  "build": "tsup",
31
49
  "type-check": "tsc --noEmit",
32
- "test": "vitest"
50
+ "test": "vitest run",
51
+ "test:watch": "vitest",
52
+ "publish-loader": "wrangler r2 object put shipeasy-sdk/loader-v$npm_package_version.js --file=dist/loader/loader.global.js --content-type 'application/javascript; charset=utf-8' --cache-control 'public, max-age=31536000, immutable' --remote && wrangler r2 object put shipeasy-sdk/loader.js --file=dist/loader/loader.global.js --content-type 'application/javascript; charset=utf-8' --cache-control 'public, max-age=300' --remote"
33
53
  },
34
54
  "dependencies": {
35
55
  "murmurhash-js": "^1.0.0"
@@ -38,7 +58,8 @@
38
58
  "@types/murmurhash-js": "^1.0.6",
39
59
  "tsup": "^8.3.0",
40
60
  "typescript": "^5.7.4",
41
- "vitest": "^2.1.0"
61
+ "vitest": "^2.1.0",
62
+ "wrangler": "^4.83.0"
42
63
  },
43
64
  "peerDependencies": {
44
65
  "zod": "^4.0.0"
@@ -50,5 +71,8 @@
50
71
  },
51
72
  "publishConfig": {
52
73
  "access": "public"
74
+ },
75
+ "engines": {
76
+ "node": ">=20"
53
77
  }
54
78
  }