@simplr-ai/node 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.
- package/README.md +38 -0
- package/dist/index.cjs +219 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +139 -2
- package/dist/index.d.ts +139 -2
- package/dist/index.js +217 -2
- package/dist/index.js.map +1 -1
- package/package.json +14 -3
package/README.md
CHANGED
|
@@ -87,6 +87,44 @@ app.post("/hooks/simplify", express.raw({ type: "application/json" }), (req, res
|
|
|
87
87
|
|
|
88
88
|
`verify(payload, header, secret, { toleranceSec })` returns a boolean; `constructEvent(...)` returns the parsed event or throws `WebhookVerificationError`.
|
|
89
89
|
|
|
90
|
+
## Server-side feature flags
|
|
91
|
+
|
|
92
|
+
Evaluate flags on the backend. Flag config is read with a **public** key (`pk_…`), so pass one alongside your secret key; evaluation is local and deterministic (same bucketing as the browser SDK).
|
|
93
|
+
|
|
94
|
+
```ts
|
|
95
|
+
const simplr = new Simplr({
|
|
96
|
+
apiKey: process.env.SIMPLR_API_KEY!, // sk_… for checks/orders/etc.
|
|
97
|
+
publicKey: process.env.SIMPLR_PUBLIC_KEY!, // pk_… for flags
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
await simplr.flags.initialize();
|
|
101
|
+
simplr.flags.setUser("user_123");
|
|
102
|
+
|
|
103
|
+
if (simplr.flags.isEnabled("new-checkout")) {
|
|
104
|
+
// gate a backend code path
|
|
105
|
+
}
|
|
106
|
+
simplr.flags.isEnabled("beta", { userId: "u1", attributes: { plan: "growth" } });
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
You can also use `SimplrFlags` standalone.
|
|
110
|
+
|
|
111
|
+
## Admin / measurement (`SimplrAdmin`)
|
|
112
|
+
|
|
113
|
+
Dashboard operations — usage/measurement, feature-flag CRUD, and RUM analytics — require a **portal token** (JWT), not an API key:
|
|
114
|
+
|
|
115
|
+
```ts
|
|
116
|
+
import { SimplrAdmin } from "@simplr-ai/node";
|
|
117
|
+
|
|
118
|
+
const admin = new SimplrAdmin({ token: process.env.SIMPLR_PORTAL_TOKEN! });
|
|
119
|
+
|
|
120
|
+
await admin.usage.stats(orgId); // usage counters
|
|
121
|
+
await admin.usage.billing(orgId); // per-service totals + estimated cost (API measurement)
|
|
122
|
+
await admin.flags.create(orgId, { key: "new-checkout", environment: "test", rollout_percentage: 10 });
|
|
123
|
+
await admin.flags.update(orgId, flagId, { rollout_percentage: 50 });
|
|
124
|
+
await admin.rum.overview(orgId, { application_id: "my-app" });
|
|
125
|
+
await admin.rum.sessions(orgId, { page: 1, limit: 50 });
|
|
126
|
+
```
|
|
127
|
+
|
|
90
128
|
## Errors
|
|
91
129
|
|
|
92
130
|
Non-2xx responses throw `SimplrError` with `.status` and `.body`.
|
package/dist/index.cjs
CHANGED
|
@@ -21,7 +21,9 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
21
21
|
var src_exports = {};
|
|
22
22
|
__export(src_exports, {
|
|
23
23
|
Simplr: () => Simplr,
|
|
24
|
+
SimplrAdmin: () => SimplrAdmin,
|
|
24
25
|
SimplrError: () => SimplrError,
|
|
26
|
+
SimplrFlags: () => SimplrFlags,
|
|
25
27
|
WebhookVerificationError: () => WebhookVerificationError,
|
|
26
28
|
constructWebhookEvent: () => constructEvent,
|
|
27
29
|
default: () => src_default,
|
|
@@ -56,7 +58,7 @@ async function apiRequest(cfg, method, path, body) {
|
|
|
56
58
|
method,
|
|
57
59
|
headers: {
|
|
58
60
|
"Content-Type": "application/json",
|
|
59
|
-
|
|
61
|
+
...cfg.authHeaders
|
|
60
62
|
},
|
|
61
63
|
body: body !== void 0 ? JSON.stringify(body) : void 0,
|
|
62
64
|
signal: controller.signal
|
|
@@ -137,6 +139,113 @@ var EdgeResource = class {
|
|
|
137
139
|
}
|
|
138
140
|
};
|
|
139
141
|
|
|
142
|
+
// src/flags.ts
|
|
143
|
+
function murmurHash3(input, seed = 0) {
|
|
144
|
+
let h1 = seed;
|
|
145
|
+
const c1 = 3432918353;
|
|
146
|
+
const c2 = 461845907;
|
|
147
|
+
for (let i = 0; i < input.length; i++) {
|
|
148
|
+
let k1 = input.charCodeAt(i);
|
|
149
|
+
k1 = Math.imul(k1, c1);
|
|
150
|
+
k1 = k1 << 15 | k1 >>> 17;
|
|
151
|
+
k1 = Math.imul(k1, c2);
|
|
152
|
+
h1 ^= k1;
|
|
153
|
+
h1 = h1 << 13 | h1 >>> 19;
|
|
154
|
+
h1 = Math.imul(h1, 5) + 3864292196;
|
|
155
|
+
}
|
|
156
|
+
h1 ^= input.length;
|
|
157
|
+
h1 ^= h1 >>> 16;
|
|
158
|
+
h1 = Math.imul(h1, 2246822507);
|
|
159
|
+
h1 ^= h1 >>> 13;
|
|
160
|
+
h1 = Math.imul(h1, 3266489909);
|
|
161
|
+
h1 ^= h1 >>> 16;
|
|
162
|
+
return h1 >>> 0;
|
|
163
|
+
}
|
|
164
|
+
function matchRule(rule, attributes) {
|
|
165
|
+
const actual = attributes[rule.attribute];
|
|
166
|
+
switch (rule.op) {
|
|
167
|
+
case "eq":
|
|
168
|
+
return String(actual) === rule.value;
|
|
169
|
+
case "neq":
|
|
170
|
+
return String(actual) !== rule.value;
|
|
171
|
+
case "contains":
|
|
172
|
+
return String(actual ?? "").includes(rule.value);
|
|
173
|
+
default:
|
|
174
|
+
return false;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
var SimplrFlags = class {
|
|
178
|
+
cfg;
|
|
179
|
+
environment;
|
|
180
|
+
refreshIntervalMs;
|
|
181
|
+
flags = {};
|
|
182
|
+
defaultUserId;
|
|
183
|
+
timer = null;
|
|
184
|
+
ready = false;
|
|
185
|
+
constructor(options) {
|
|
186
|
+
if (!options?.publicKey) throw new Error("SimplrFlags: `publicKey` is required");
|
|
187
|
+
this.cfg = {
|
|
188
|
+
authHeaders: { "X-API-Key": options.publicKey },
|
|
189
|
+
baseUrl: (options.baseUrl || "https://api.simplr.sh").replace(/\/+$/, ""),
|
|
190
|
+
timeoutMs: options.timeoutMs ?? 15e3,
|
|
191
|
+
fetchImpl: options.fetch ?? globalThis.fetch
|
|
192
|
+
};
|
|
193
|
+
this.environment = options.environment;
|
|
194
|
+
this.refreshIntervalMs = options.refreshIntervalMs ?? 6e4;
|
|
195
|
+
}
|
|
196
|
+
/** Fetch the flag config once and start the background refresh. */
|
|
197
|
+
async initialize() {
|
|
198
|
+
await this.refresh();
|
|
199
|
+
this.ready = true;
|
|
200
|
+
if (this.refreshIntervalMs > 0) {
|
|
201
|
+
this.timer = setInterval(() => {
|
|
202
|
+
void this.refresh();
|
|
203
|
+
}, this.refreshIntervalMs);
|
|
204
|
+
this.timer?.unref?.();
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
/** Set the default identifier used for bucketing when none is passed to isEnabled. */
|
|
208
|
+
setUser(userId) {
|
|
209
|
+
this.defaultUserId = userId;
|
|
210
|
+
}
|
|
211
|
+
/** Re-fetch the flag config (counts as one billable request). */
|
|
212
|
+
async refresh() {
|
|
213
|
+
const path = this.environment ? `/v1/flags?environment=${this.environment}` : "/v1/flags";
|
|
214
|
+
try {
|
|
215
|
+
const content = await apiRequest(this.cfg, "GET", path);
|
|
216
|
+
const list = content?.flags || [];
|
|
217
|
+
const map = {};
|
|
218
|
+
for (const f of list) map[f.key] = f;
|
|
219
|
+
this.flags = map;
|
|
220
|
+
} catch {
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
/** Evaluate a flag locally. Deterministic per user; no network call. */
|
|
224
|
+
isEnabled(key, ctx = {}) {
|
|
225
|
+
const f = this.flags[key];
|
|
226
|
+
if (!f || !f.enabled) return false;
|
|
227
|
+
const uid = ctx.userId || this.defaultUserId || "anonymous";
|
|
228
|
+
if (f.target_user_ids?.includes(uid)) return true;
|
|
229
|
+
if (ctx.attributes && f.rules?.length && f.rules.some((r) => matchRule(r, ctx.attributes))) {
|
|
230
|
+
return true;
|
|
231
|
+
}
|
|
232
|
+
if (f.rollout_percentage >= 100) return true;
|
|
233
|
+
if (f.rollout_percentage <= 0) return false;
|
|
234
|
+
return murmurHash3(`${key}:${uid}`) % 100 < f.rollout_percentage;
|
|
235
|
+
}
|
|
236
|
+
getAll() {
|
|
237
|
+
return { ...this.flags };
|
|
238
|
+
}
|
|
239
|
+
isReady() {
|
|
240
|
+
return this.ready;
|
|
241
|
+
}
|
|
242
|
+
/** Stop the background refresh timer. */
|
|
243
|
+
dispose() {
|
|
244
|
+
if (this.timer) clearInterval(this.timer);
|
|
245
|
+
this.timer = null;
|
|
246
|
+
}
|
|
247
|
+
};
|
|
248
|
+
|
|
140
249
|
// src/webhooks.ts
|
|
141
250
|
var webhooks_exports = {};
|
|
142
251
|
__export(webhooks_exports, {
|
|
@@ -191,6 +300,91 @@ function constructEvent(payload, header, secret, options = {}) {
|
|
|
191
300
|
}
|
|
192
301
|
var webhooks = { verify, constructEvent };
|
|
193
302
|
|
|
303
|
+
// src/admin.ts
|
|
304
|
+
function qs(params) {
|
|
305
|
+
const entries = Object.entries(params).filter(([, v]) => v !== void 0 && v !== null);
|
|
306
|
+
if (!entries.length) return "";
|
|
307
|
+
return "?" + entries.map(([k, v]) => `${k}=${encodeURIComponent(String(v))}`).join("&");
|
|
308
|
+
}
|
|
309
|
+
var UsageApi = class {
|
|
310
|
+
constructor(cfg) {
|
|
311
|
+
this.cfg = cfg;
|
|
312
|
+
}
|
|
313
|
+
cfg;
|
|
314
|
+
/** Aggregate usage stats for an org. */
|
|
315
|
+
stats(orgId) {
|
|
316
|
+
return apiRequest(this.cfg, "GET", `/v1/usage/stats${qs({ org_id: orgId })}`);
|
|
317
|
+
}
|
|
318
|
+
/** Raw usage logs for an org. */
|
|
319
|
+
logs(orgId, params = {}) {
|
|
320
|
+
return apiRequest(this.cfg, "GET", `/v1/usage/logs${qs({ org_id: orgId, ...params })}`);
|
|
321
|
+
}
|
|
322
|
+
/** Billing usage breakdown (per-service totals + estimated cost). */
|
|
323
|
+
billing(orgId) {
|
|
324
|
+
return apiRequest(this.cfg, "GET", `/v1/billing/usage${qs({ org_id: orgId })}`);
|
|
325
|
+
}
|
|
326
|
+
};
|
|
327
|
+
var FlagsAdminApi = class {
|
|
328
|
+
constructor(cfg) {
|
|
329
|
+
this.cfg = cfg;
|
|
330
|
+
}
|
|
331
|
+
cfg;
|
|
332
|
+
list(orgId, environment) {
|
|
333
|
+
return apiRequest(this.cfg, "GET", `/v1/feature-flags${qs({ org_id: orgId, environment })}`);
|
|
334
|
+
}
|
|
335
|
+
get(orgId, id) {
|
|
336
|
+
return apiRequest(this.cfg, "GET", `/v1/feature-flags/${id}${qs({ org_id: orgId })}`);
|
|
337
|
+
}
|
|
338
|
+
create(orgId, data) {
|
|
339
|
+
return apiRequest(this.cfg, "POST", "/v1/feature-flags", { org_id: orgId, ...data });
|
|
340
|
+
}
|
|
341
|
+
update(orgId, id, data) {
|
|
342
|
+
return apiRequest(this.cfg, "PATCH", `/v1/feature-flags/${id}`, { org_id: orgId, ...data });
|
|
343
|
+
}
|
|
344
|
+
remove(orgId, id) {
|
|
345
|
+
return apiRequest(this.cfg, "DELETE", `/v1/feature-flags/${id}${qs({ org_id: orgId })}`);
|
|
346
|
+
}
|
|
347
|
+
history(orgId, id, params = {}) {
|
|
348
|
+
return apiRequest(
|
|
349
|
+
this.cfg,
|
|
350
|
+
"GET",
|
|
351
|
+
`/v1/feature-flags/${id}/history${qs({ org_id: orgId, ...params })}`
|
|
352
|
+
);
|
|
353
|
+
}
|
|
354
|
+
};
|
|
355
|
+
var RumApi = class {
|
|
356
|
+
constructor(cfg) {
|
|
357
|
+
this.cfg = cfg;
|
|
358
|
+
}
|
|
359
|
+
cfg;
|
|
360
|
+
overview(orgId, params = {}) {
|
|
361
|
+
return apiRequest(this.cfg, "GET", `/v1/rum/overview${qs({ org_id: orgId, ...params })}`);
|
|
362
|
+
}
|
|
363
|
+
sessions(orgId, params = {}) {
|
|
364
|
+
return apiRequest(this.cfg, "GET", `/v1/rum/sessions${qs({ org_id: orgId, ...params })}`);
|
|
365
|
+
}
|
|
366
|
+
};
|
|
367
|
+
var SimplrAdmin = class {
|
|
368
|
+
usage;
|
|
369
|
+
flags;
|
|
370
|
+
rum;
|
|
371
|
+
constructor(options) {
|
|
372
|
+
if (!options?.token) throw new Error("SimplrAdmin: `token` is required");
|
|
373
|
+
const cfg = {
|
|
374
|
+
authHeaders: { Authorization: `Bearer ${options.token}` },
|
|
375
|
+
baseUrl: (options.baseUrl || "https://api.simplr.sh").replace(/\/+$/, ""),
|
|
376
|
+
timeoutMs: options.timeoutMs ?? 15e3,
|
|
377
|
+
fetchImpl: options.fetch ?? globalThis.fetch
|
|
378
|
+
};
|
|
379
|
+
if (typeof cfg.fetchImpl !== "function") {
|
|
380
|
+
throw new Error("SimplrAdmin: no global fetch available \u2014 use Node 18+ or pass `fetch`");
|
|
381
|
+
}
|
|
382
|
+
this.usage = new UsageApi(cfg);
|
|
383
|
+
this.flags = new FlagsAdminApi(cfg);
|
|
384
|
+
this.rum = new RumApi(cfg);
|
|
385
|
+
}
|
|
386
|
+
};
|
|
387
|
+
|
|
194
388
|
// src/index.ts
|
|
195
389
|
var DEFAULT_BASE_URL = "https://api.simplr.sh";
|
|
196
390
|
var Simplr = class {
|
|
@@ -200,10 +394,11 @@ var Simplr = class {
|
|
|
200
394
|
edge;
|
|
201
395
|
/** Webhook signature helpers (no network). */
|
|
202
396
|
webhooks = webhooks_exports;
|
|
397
|
+
_flags;
|
|
203
398
|
constructor(options) {
|
|
204
399
|
if (!options?.apiKey) throw new Error("Simplr: `apiKey` is required");
|
|
205
400
|
this.cfg = {
|
|
206
|
-
|
|
401
|
+
authHeaders: { "X-API-Key": options.apiKey },
|
|
207
402
|
baseUrl: (options.baseUrl || DEFAULT_BASE_URL).replace(/\/+$/, ""),
|
|
208
403
|
timeoutMs: options.timeoutMs ?? 15e3,
|
|
209
404
|
fetchImpl: options.fetch ?? globalThis.fetch
|
|
@@ -214,6 +409,26 @@ var Simplr = class {
|
|
|
214
409
|
this.orders = new OrdersResource(this.cfg);
|
|
215
410
|
this.phone = new PhoneResource(this.cfg);
|
|
216
411
|
this.edge = new EdgeResource(this.cfg);
|
|
412
|
+
if (options.publicKey) {
|
|
413
|
+
this._flags = new SimplrFlags({
|
|
414
|
+
publicKey: options.publicKey,
|
|
415
|
+
baseUrl: this.cfg.baseUrl,
|
|
416
|
+
timeoutMs: this.cfg.timeoutMs,
|
|
417
|
+
fetch: this.cfg.fetchImpl
|
|
418
|
+
});
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
/**
|
|
422
|
+
* Server-side feature flags. Requires a `publicKey` in the constructor options
|
|
423
|
+
* (flag config is read with the public key). Call `simplr.flags.initialize()` once.
|
|
424
|
+
*/
|
|
425
|
+
get flags() {
|
|
426
|
+
if (!this._flags) {
|
|
427
|
+
throw new Error(
|
|
428
|
+
"Simplr.flags requires a `publicKey` \u2014 pass it to `new Simplr({ apiKey, publicKey })`."
|
|
429
|
+
);
|
|
430
|
+
}
|
|
431
|
+
return this._flags;
|
|
217
432
|
}
|
|
218
433
|
/** Run an identity/fraud check. Provide any of email, phone, device, behavior. */
|
|
219
434
|
check(input) {
|
|
@@ -228,7 +443,9 @@ var src_default = Simplr;
|
|
|
228
443
|
// Annotate the CommonJS export names for ESM import in node:
|
|
229
444
|
0 && (module.exports = {
|
|
230
445
|
Simplr,
|
|
446
|
+
SimplrAdmin,
|
|
231
447
|
SimplrError,
|
|
448
|
+
SimplrFlags,
|
|
232
449
|
WebhookVerificationError,
|
|
233
450
|
constructWebhookEvent,
|
|
234
451
|
verifyWebhook
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/errors.ts","../src/http.ts","../src/resources.ts","../src/webhooks.ts"],"sourcesContent":["import { apiRequest, type HttpConfig } from \"./http.js\";\nimport { EdgeResource, OrdersResource, PhoneResource } from \"./resources.js\";\nimport * as webhooks from \"./webhooks.js\";\nimport type { BulkResult, CheckInput, CheckResult, SimplrOptions } from \"./types.js\";\n\nexport { SimplrError, WebhookVerificationError } from \"./errors.js\";\nexport * from \"./types.js\";\nexport { verify as verifyWebhook, constructEvent as constructWebhookEvent } from \"./webhooks.js\";\n\nconst DEFAULT_BASE_URL = \"https://api.simplr.sh\";\n\n/**\n * Simplr server-side client.\n *\n * ```ts\n * import { Simplr } from \"@simplr-ai/node\";\n * const simplr = new Simplr({ apiKey: process.env.SIMPLR_API_KEY! });\n * const result = await simplr.check({ email: \"user@example.com\", event_type: \"signup\" });\n * ```\n */\nexport class Simplr {\n private readonly cfg: HttpConfig;\n\n readonly orders: OrdersResource;\n readonly phone: PhoneResource;\n readonly edge: EdgeResource;\n /** Webhook signature helpers (no network). */\n readonly webhooks = webhooks;\n\n constructor(options: SimplrOptions) {\n if (!options?.apiKey) throw new Error(\"Simplr: `apiKey` is required\");\n this.cfg = {\n apiKey: options.apiKey,\n baseUrl: (options.baseUrl || DEFAULT_BASE_URL).replace(/\\/+$/, \"\"),\n timeoutMs: options.timeoutMs ?? 15000,\n fetchImpl: options.fetch ?? globalThis.fetch,\n };\n if (typeof this.cfg.fetchImpl !== \"function\") {\n throw new Error(\"Simplr: no global fetch available — use Node 18+ or pass `fetch` in options\");\n }\n this.orders = new OrdersResource(this.cfg);\n this.phone = new PhoneResource(this.cfg);\n this.edge = new EdgeResource(this.cfg);\n }\n\n /** Run an identity/fraud check. Provide any of email, phone, device, behavior. */\n check(input: CheckInput): Promise<CheckResult> {\n return apiRequest(this.cfg, \"POST\", \"/v1/check\", input);\n }\n\n /** Run up to 100 checks at once. */\n checkBulk(items: CheckInput[]): Promise<BulkResult<CheckResult>> {\n return apiRequest(this.cfg, \"POST\", \"/v1/check/bulk\", { items });\n }\n}\n\nexport default Simplr;\n","/** Thrown when the Simplr API returns a non-2xx response. */\nexport class SimplrError extends Error {\n readonly status: number;\n readonly body: unknown;\n\n constructor(message: string, status: number, body: unknown) {\n super(message);\n this.name = \"SimplrError\";\n this.status = status;\n this.body = body;\n }\n}\n\n/** Thrown when a webhook signature fails verification. */\nexport class WebhookVerificationError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"WebhookVerificationError\";\n }\n}\n","import { SimplrError } from \"./errors.js\";\n\nexport interface HttpConfig {\n apiKey: string;\n baseUrl: string;\n timeoutMs: number;\n fetchImpl: typeof fetch;\n}\n\n/**\n * Internal request helper. Sends X-API-Key, applies a timeout, and unwraps the\n * API's `{ success, message, content }` envelope (returning `content`).\n */\nexport async function apiRequest<T>(\n cfg: HttpConfig,\n method: \"GET\" | \"POST\" | \"PATCH\" | \"DELETE\",\n path: string,\n body?: unknown,\n): Promise<T> {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), cfg.timeoutMs);\n try {\n const res = await cfg.fetchImpl(`${cfg.baseUrl}${path}`, {\n method,\n headers: {\n \"Content-Type\": \"application/json\",\n \"X-API-Key\": cfg.apiKey,\n },\n body: body !== undefined ? JSON.stringify(body) : undefined,\n signal: controller.signal,\n });\n\n const text = await res.text();\n let parsed: any;\n try {\n parsed = text ? JSON.parse(text) : undefined;\n } catch {\n parsed = text;\n }\n\n if (!res.ok) {\n const message =\n (parsed && (parsed.message || parsed.error)) || `Simplr API error ${res.status}`;\n throw new SimplrError(message, res.status, parsed);\n }\n\n // Unwrap the standard envelope when present.\n return (parsed && typeof parsed === \"object\" && \"content\" in parsed\n ? parsed.content\n : parsed) as T;\n } catch (err) {\n if (err instanceof SimplrError) throw err;\n if (err instanceof Error && err.name === \"AbortError\") {\n throw new SimplrError(`Request to ${path} timed out after ${cfg.timeoutMs}ms`, 0, null);\n }\n throw new SimplrError(err instanceof Error ? err.message : \"Network error\", 0, null);\n } finally {\n clearTimeout(timer);\n }\n}\n","import { apiRequest, type HttpConfig } from \"./http.js\";\nimport type {\n BulkResult,\n EdgeLogEntry,\n OrderInput,\n OrderResult,\n PhoneReportInput,\n} from \"./types.js\";\n\n/** Order fraud scoring. */\nexport class OrdersResource {\n constructor(private readonly cfg: HttpConfig) {}\n\n /** Submit a single order for fraud scoring. */\n submit(order: OrderInput): Promise<OrderResult> {\n return apiRequest(this.cfg, \"POST\", \"/v1/orders\", order);\n }\n\n /** Submit up to 100 orders at once. */\n submitBulk(orders: OrderInput[]): Promise<BulkResult<OrderResult>> {\n return apiRequest(this.cfg, \"POST\", \"/v1/orders/bulk\", { orders });\n }\n}\n\n/** Phone intelligence + outcome reporting. */\nexport class PhoneResource {\n constructor(private readonly cfg: HttpConfig) {}\n\n /** Report the real-world outcome for a phone number to improve scoring. */\n report(input: PhoneReportInput): Promise<{ success: boolean }> {\n return apiRequest(this.cfg, \"POST\", \"/v1/check/phone/report\", input);\n }\n\n /** Fetch stored risk intelligence for a phone number. */\n intelligence(phone: string): Promise<Record<string, unknown>> {\n return apiRequest(this.cfg, \"GET\", `/v1/check/phone/intelligence/${encodeURIComponent(phone)}`);\n }\n}\n\n/** Edge device registration + log ingestion. */\nexport class EdgeResource {\n constructor(private readonly cfg: HttpConfig) {}\n\n /** Register an edge device. */\n registerDevice(input: { device_id: string; name?: string; firmware?: string; [k: string]: unknown }) {\n return apiRequest(this.cfg, \"POST\", \"/v1/edge/devices/register\", input);\n }\n\n /** Report a device heartbeat with health metrics. */\n heartbeat(deviceId: string, metrics: Record<string, unknown>) {\n return apiRequest(\n this.cfg,\n \"POST\",\n `/v1/edge/devices/${encodeURIComponent(deviceId)}/heartbeat`,\n metrics,\n );\n }\n\n /** Batch-ingest structured logs for a device. */\n ingestLogs(deviceId: string, logs: EdgeLogEntry[]) {\n return apiRequest(this.cfg, \"POST\", \"/v1/edge/logs\", { device_id: deviceId, logs });\n }\n}\n","import { createHmac, timingSafeEqual } from \"node:crypto\";\nimport { WebhookVerificationError } from \"./errors.js\";\n\nexport interface VerifyOptions {\n /** Reject signatures whose timestamp is older than this many seconds (default 300). 0 disables. */\n toleranceSec?: number;\n}\n\nfunction parseHeader(header: string): { t: string; v1: string } | null {\n // Format: \"t=<unix-seconds>,v1=<hex-hmac>\"\n const parts = header.split(\",\").map((p) => p.trim());\n let t = \"\";\n let v1 = \"\";\n for (const part of parts) {\n const [k, v] = part.split(\"=\");\n if (k === \"t\") t = v;\n if (k === \"v1\") v1 = v;\n }\n return t && v1 ? { t, v1 } : null;\n}\n\nfunction expectedSignature(timestamp: string, payload: string, secret: string): string {\n return createHmac(\"sha256\", secret).update(`${timestamp}.${payload}`).digest(\"hex\");\n}\n\nfunction safeEqualHex(a: string, b: string): boolean {\n if (a.length !== b.length) return false;\n try {\n return timingSafeEqual(Buffer.from(a, \"hex\"), Buffer.from(b, \"hex\"));\n } catch {\n return false;\n }\n}\n\n/**\n * Verify a Simplr webhook signature.\n *\n * @param payload The RAW request body string (do not re-serialize parsed JSON).\n * @param header The `X-Simplr-Signature` header value (`t=…,v1=…`).\n * @param secret The webhook's signing secret.\n * @returns true if the signature is valid and within the tolerance window.\n */\nexport function verify(\n payload: string | Buffer,\n header: string,\n secret: string,\n options: VerifyOptions = {},\n): boolean {\n const tolerance = options.toleranceSec ?? 300;\n const parsed = parseHeader(header || \"\");\n if (!parsed) return false;\n\n const body = typeof payload === \"string\" ? payload : payload.toString(\"utf8\");\n const expected = expectedSignature(parsed.t, body, secret);\n if (!safeEqualHex(parsed.v1, expected)) return false;\n\n if (tolerance > 0) {\n const ts = Number(parsed.t);\n if (!Number.isFinite(ts)) return false;\n const ageSec = Math.abs(Date.now() / 1000 - ts);\n if (ageSec > tolerance) return false;\n }\n return true;\n}\n\n/**\n * Verify the signature and return the parsed event object.\n * Throws {@link WebhookVerificationError} if verification fails.\n */\nexport function constructEvent<T = { event: string; data: unknown }>(\n payload: string | Buffer,\n header: string,\n secret: string,\n options: VerifyOptions = {},\n): T {\n if (!verify(payload, header, secret, options)) {\n throw new WebhookVerificationError(\"Webhook signature verification failed\");\n }\n const body = typeof payload === \"string\" ? payload : payload.toString(\"utf8\");\n return JSON.parse(body) as T;\n}\n\nexport const webhooks = { verify, constructEvent };\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/errors.ts","../src/http.ts","../src/resources.ts","../src/flags.ts","../src/webhooks.ts","../src/admin.ts"],"sourcesContent":["import { apiRequest, type HttpConfig } from \"./http.js\";\nimport { EdgeResource, OrdersResource, PhoneResource } from \"./resources.js\";\nimport { SimplrFlags } from \"./flags.js\";\nimport * as webhooks from \"./webhooks.js\";\nimport type { BulkResult, CheckInput, CheckResult, SimplrOptions } from \"./types.js\";\n\nexport { SimplrError, WebhookVerificationError } from \"./errors.js\";\nexport * from \"./types.js\";\nexport { verify as verifyWebhook, constructEvent as constructWebhookEvent } from \"./webhooks.js\";\nexport { SimplrFlags } from \"./flags.js\";\nexport type { FlagDefinition, FlagRule, FlagsOptions, EvalContext } from \"./flags.js\";\nexport { SimplrAdmin } from \"./admin.js\";\nexport type { SimplrAdminOptions } from \"./admin.js\";\n\nconst DEFAULT_BASE_URL = \"https://api.simplr.sh\";\n\n/**\n * Simplr server-side client.\n *\n * ```ts\n * import { Simplr } from \"@simplr-ai/node\";\n * const simplr = new Simplr({ apiKey: process.env.SIMPLR_API_KEY! });\n * const result = await simplr.check({ email: \"user@example.com\", event_type: \"signup\" });\n * ```\n */\nexport class Simplr {\n private readonly cfg: HttpConfig;\n\n readonly orders: OrdersResource;\n readonly phone: PhoneResource;\n readonly edge: EdgeResource;\n /** Webhook signature helpers (no network). */\n readonly webhooks = webhooks;\n\n private readonly _flags?: SimplrFlags;\n\n constructor(options: SimplrOptions) {\n if (!options?.apiKey) throw new Error(\"Simplr: `apiKey` is required\");\n this.cfg = {\n authHeaders: { \"X-API-Key\": options.apiKey },\n baseUrl: (options.baseUrl || DEFAULT_BASE_URL).replace(/\\/+$/, \"\"),\n timeoutMs: options.timeoutMs ?? 15000,\n fetchImpl: options.fetch ?? globalThis.fetch,\n };\n if (typeof this.cfg.fetchImpl !== \"function\") {\n throw new Error(\"Simplr: no global fetch available — use Node 18+ or pass `fetch` in options\");\n }\n this.orders = new OrdersResource(this.cfg);\n this.phone = new PhoneResource(this.cfg);\n this.edge = new EdgeResource(this.cfg);\n if (options.publicKey) {\n this._flags = new SimplrFlags({\n publicKey: options.publicKey,\n baseUrl: this.cfg.baseUrl,\n timeoutMs: this.cfg.timeoutMs,\n fetch: this.cfg.fetchImpl,\n });\n }\n }\n\n /**\n * Server-side feature flags. Requires a `publicKey` in the constructor options\n * (flag config is read with the public key). Call `simplr.flags.initialize()` once.\n */\n get flags(): SimplrFlags {\n if (!this._flags) {\n throw new Error(\n \"Simplr.flags requires a `publicKey` — pass it to `new Simplr({ apiKey, publicKey })`.\",\n );\n }\n return this._flags;\n }\n\n /** Run an identity/fraud check. Provide any of email, phone, device, behavior. */\n check(input: CheckInput): Promise<CheckResult> {\n return apiRequest(this.cfg, \"POST\", \"/v1/check\", input);\n }\n\n /** Run up to 100 checks at once. */\n checkBulk(items: CheckInput[]): Promise<BulkResult<CheckResult>> {\n return apiRequest(this.cfg, \"POST\", \"/v1/check/bulk\", { items });\n }\n}\n\nexport default Simplr;\n","/** Thrown when the Simplr API returns a non-2xx response. */\nexport class SimplrError extends Error {\n readonly status: number;\n readonly body: unknown;\n\n constructor(message: string, status: number, body: unknown) {\n super(message);\n this.name = \"SimplrError\";\n this.status = status;\n this.body = body;\n }\n}\n\n/** Thrown when a webhook signature fails verification. */\nexport class WebhookVerificationError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"WebhookVerificationError\";\n }\n}\n","import { SimplrError } from \"./errors.js\";\n\nexport interface HttpConfig {\n /** Auth headers to send (e.g. { \"X-API-Key\": \"sk_…\" } or { Authorization: \"Bearer …\" }). */\n authHeaders: Record<string, string>;\n baseUrl: string;\n timeoutMs: number;\n fetchImpl: typeof fetch;\n}\n\n/**\n * Internal request helper. Sends X-API-Key, applies a timeout, and unwraps the\n * API's `{ success, message, content }` envelope (returning `content`).\n */\nexport async function apiRequest<T>(\n cfg: HttpConfig,\n method: \"GET\" | \"POST\" | \"PATCH\" | \"DELETE\",\n path: string,\n body?: unknown,\n): Promise<T> {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), cfg.timeoutMs);\n try {\n const res = await cfg.fetchImpl(`${cfg.baseUrl}${path}`, {\n method,\n headers: {\n \"Content-Type\": \"application/json\",\n ...cfg.authHeaders,\n },\n body: body !== undefined ? JSON.stringify(body) : undefined,\n signal: controller.signal,\n });\n\n const text = await res.text();\n let parsed: any;\n try {\n parsed = text ? JSON.parse(text) : undefined;\n } catch {\n parsed = text;\n }\n\n if (!res.ok) {\n const message =\n (parsed && (parsed.message || parsed.error)) || `Simplr API error ${res.status}`;\n throw new SimplrError(message, res.status, parsed);\n }\n\n // Unwrap the standard envelope when present.\n return (parsed && typeof parsed === \"object\" && \"content\" in parsed\n ? parsed.content\n : parsed) as T;\n } catch (err) {\n if (err instanceof SimplrError) throw err;\n if (err instanceof Error && err.name === \"AbortError\") {\n throw new SimplrError(`Request to ${path} timed out after ${cfg.timeoutMs}ms`, 0, null);\n }\n throw new SimplrError(err instanceof Error ? err.message : \"Network error\", 0, null);\n } finally {\n clearTimeout(timer);\n }\n}\n","import { apiRequest, type HttpConfig } from \"./http.js\";\nimport type {\n BulkResult,\n EdgeLogEntry,\n OrderInput,\n OrderResult,\n PhoneReportInput,\n} from \"./types.js\";\n\n/** Order fraud scoring. */\nexport class OrdersResource {\n constructor(private readonly cfg: HttpConfig) {}\n\n /** Submit a single order for fraud scoring. */\n submit(order: OrderInput): Promise<OrderResult> {\n return apiRequest(this.cfg, \"POST\", \"/v1/orders\", order);\n }\n\n /** Submit up to 100 orders at once. */\n submitBulk(orders: OrderInput[]): Promise<BulkResult<OrderResult>> {\n return apiRequest(this.cfg, \"POST\", \"/v1/orders/bulk\", { orders });\n }\n}\n\n/** Phone intelligence + outcome reporting. */\nexport class PhoneResource {\n constructor(private readonly cfg: HttpConfig) {}\n\n /** Report the real-world outcome for a phone number to improve scoring. */\n report(input: PhoneReportInput): Promise<{ success: boolean }> {\n return apiRequest(this.cfg, \"POST\", \"/v1/check/phone/report\", input);\n }\n\n /** Fetch stored risk intelligence for a phone number. */\n intelligence(phone: string): Promise<Record<string, unknown>> {\n return apiRequest(this.cfg, \"GET\", `/v1/check/phone/intelligence/${encodeURIComponent(phone)}`);\n }\n}\n\n/** Edge device registration + log ingestion. */\nexport class EdgeResource {\n constructor(private readonly cfg: HttpConfig) {}\n\n /** Register an edge device. */\n registerDevice(input: { device_id: string; name?: string; firmware?: string; [k: string]: unknown }) {\n return apiRequest(this.cfg, \"POST\", \"/v1/edge/devices/register\", input);\n }\n\n /** Report a device heartbeat with health metrics. */\n heartbeat(deviceId: string, metrics: Record<string, unknown>) {\n return apiRequest(\n this.cfg,\n \"POST\",\n `/v1/edge/devices/${encodeURIComponent(deviceId)}/heartbeat`,\n metrics,\n );\n }\n\n /** Batch-ingest structured logs for a device. */\n ingestLogs(deviceId: string, logs: EdgeLogEntry[]) {\n return apiRequest(this.cfg, \"POST\", \"/v1/edge/logs\", { device_id: deviceId, logs });\n }\n}\n","import { apiRequest, type HttpConfig } from \"./http.js\";\n\n/**\n * MurmurHash3 (x86, 32-bit) — identical to the browser SDK so a given user\n * buckets the same way on the client and the server.\n */\nfunction murmurHash3(input: string, seed = 0): number {\n let h1 = seed;\n const c1 = 0xcc9e2d51;\n const c2 = 0x1b873593;\n for (let i = 0; i < input.length; i++) {\n let k1 = input.charCodeAt(i);\n k1 = Math.imul(k1, c1);\n k1 = (k1 << 15) | (k1 >>> 17);\n k1 = Math.imul(k1, c2);\n h1 ^= k1;\n h1 = (h1 << 13) | (h1 >>> 19);\n h1 = Math.imul(h1, 5) + 0xe6546b64;\n }\n h1 ^= input.length;\n h1 ^= h1 >>> 16;\n h1 = Math.imul(h1, 0x85ebca6b);\n h1 ^= h1 >>> 13;\n h1 = Math.imul(h1, 0xc2b2ae35);\n h1 ^= h1 >>> 16;\n return h1 >>> 0;\n}\n\nexport interface FlagRule {\n attribute: string;\n op: \"eq\" | \"neq\" | \"contains\";\n value: string;\n}\n\nexport interface FlagDefinition {\n key: string;\n enabled: boolean;\n rollout_percentage: number;\n target_user_ids: string[];\n rules: FlagRule[];\n}\n\nexport interface FlagsOptions {\n /** Public API key (pk_live_… / pk_test_…). Required — flags read uses the public key. */\n publicKey: string;\n /** API base URL. Defaults to https://api.simplr.sh. */\n baseUrl?: string;\n /** Which environment's flags to load. Defaults to the key's own environment. */\n environment?: \"live\" | \"test\";\n /** Auto-refresh interval in ms (default 60000; 0 disables). */\n refreshIntervalMs?: number;\n timeoutMs?: number;\n fetch?: typeof fetch;\n}\n\nexport interface EvalContext {\n userId?: string;\n attributes?: Record<string, unknown>;\n}\n\nfunction matchRule(rule: FlagRule, attributes: Record<string, unknown>): boolean {\n const actual = attributes[rule.attribute];\n switch (rule.op) {\n case \"eq\":\n return String(actual) === rule.value;\n case \"neq\":\n return String(actual) !== rule.value;\n case \"contains\":\n return String(actual ?? \"\").includes(rule.value);\n default:\n return false;\n }\n}\n\n/**\n * Server-side feature flags with local, deterministic evaluation.\n *\n * ```ts\n * const flags = new SimplrFlags({ publicKey: process.env.SIMPLR_PUBLIC_KEY! });\n * await flags.initialize();\n * if (flags.isEnabled(\"new-checkout\", { userId: \"user_123\" })) { ... }\n * ```\n */\nexport class SimplrFlags {\n private readonly cfg: HttpConfig;\n private readonly environment?: \"live\" | \"test\";\n private readonly refreshIntervalMs: number;\n private flags: Record<string, FlagDefinition> = {};\n private defaultUserId?: string;\n private timer: ReturnType<typeof setInterval> | null = null;\n private ready = false;\n\n constructor(options: FlagsOptions) {\n if (!options?.publicKey) throw new Error(\"SimplrFlags: `publicKey` is required\");\n this.cfg = {\n authHeaders: { \"X-API-Key\": options.publicKey },\n baseUrl: (options.baseUrl || \"https://api.simplr.sh\").replace(/\\/+$/, \"\"),\n timeoutMs: options.timeoutMs ?? 15000,\n fetchImpl: options.fetch ?? globalThis.fetch,\n };\n this.environment = options.environment;\n this.refreshIntervalMs = options.refreshIntervalMs ?? 60000;\n }\n\n /** Fetch the flag config once and start the background refresh. */\n async initialize(): Promise<void> {\n await this.refresh();\n this.ready = true;\n if (this.refreshIntervalMs > 0) {\n this.timer = setInterval(() => {\n void this.refresh();\n }, this.refreshIntervalMs);\n // Don't keep the process alive just for flag refreshes.\n (this.timer as any)?.unref?.();\n }\n }\n\n /** Set the default identifier used for bucketing when none is passed to isEnabled. */\n setUser(userId: string): void {\n this.defaultUserId = userId;\n }\n\n /** Re-fetch the flag config (counts as one billable request). */\n async refresh(): Promise<void> {\n const path = this.environment ? `/v1/flags?environment=${this.environment}` : \"/v1/flags\";\n try {\n const content = await apiRequest<{ flags: FlagDefinition[] }>(this.cfg, \"GET\", path);\n const list = content?.flags || [];\n const map: Record<string, FlagDefinition> = {};\n for (const f of list) map[f.key] = f;\n this.flags = map;\n } catch {\n // keep last-known flags on error\n }\n }\n\n /** Evaluate a flag locally. Deterministic per user; no network call. */\n isEnabled(key: string, ctx: EvalContext = {}): boolean {\n const f = this.flags[key];\n if (!f || !f.enabled) return false;\n\n const uid = ctx.userId || this.defaultUserId || \"anonymous\";\n if (f.target_user_ids?.includes(uid)) return true;\n if (ctx.attributes && f.rules?.length && f.rules.some((r) => matchRule(r, ctx.attributes!))) {\n return true;\n }\n if (f.rollout_percentage >= 100) return true;\n if (f.rollout_percentage <= 0) return false;\n return murmurHash3(`${key}:${uid}`) % 100 < f.rollout_percentage;\n }\n\n getAll(): Record<string, FlagDefinition> {\n return { ...this.flags };\n }\n\n isReady(): boolean {\n return this.ready;\n }\n\n /** Stop the background refresh timer. */\n dispose(): void {\n if (this.timer) clearInterval(this.timer);\n this.timer = null;\n }\n}\n","import { createHmac, timingSafeEqual } from \"node:crypto\";\nimport { WebhookVerificationError } from \"./errors.js\";\n\nexport interface VerifyOptions {\n /** Reject signatures whose timestamp is older than this many seconds (default 300). 0 disables. */\n toleranceSec?: number;\n}\n\nfunction parseHeader(header: string): { t: string; v1: string } | null {\n // Format: \"t=<unix-seconds>,v1=<hex-hmac>\"\n const parts = header.split(\",\").map((p) => p.trim());\n let t = \"\";\n let v1 = \"\";\n for (const part of parts) {\n const [k, v] = part.split(\"=\");\n if (k === \"t\") t = v;\n if (k === \"v1\") v1 = v;\n }\n return t && v1 ? { t, v1 } : null;\n}\n\nfunction expectedSignature(timestamp: string, payload: string, secret: string): string {\n return createHmac(\"sha256\", secret).update(`${timestamp}.${payload}`).digest(\"hex\");\n}\n\nfunction safeEqualHex(a: string, b: string): boolean {\n if (a.length !== b.length) return false;\n try {\n return timingSafeEqual(Buffer.from(a, \"hex\"), Buffer.from(b, \"hex\"));\n } catch {\n return false;\n }\n}\n\n/**\n * Verify a Simplr webhook signature.\n *\n * @param payload The RAW request body string (do not re-serialize parsed JSON).\n * @param header The `X-Simplr-Signature` header value (`t=…,v1=…`).\n * @param secret The webhook's signing secret.\n * @returns true if the signature is valid and within the tolerance window.\n */\nexport function verify(\n payload: string | Buffer,\n header: string,\n secret: string,\n options: VerifyOptions = {},\n): boolean {\n const tolerance = options.toleranceSec ?? 300;\n const parsed = parseHeader(header || \"\");\n if (!parsed) return false;\n\n const body = typeof payload === \"string\" ? payload : payload.toString(\"utf8\");\n const expected = expectedSignature(parsed.t, body, secret);\n if (!safeEqualHex(parsed.v1, expected)) return false;\n\n if (tolerance > 0) {\n const ts = Number(parsed.t);\n if (!Number.isFinite(ts)) return false;\n const ageSec = Math.abs(Date.now() / 1000 - ts);\n if (ageSec > tolerance) return false;\n }\n return true;\n}\n\n/**\n * Verify the signature and return the parsed event object.\n * Throws {@link WebhookVerificationError} if verification fails.\n */\nexport function constructEvent<T = { event: string; data: unknown }>(\n payload: string | Buffer,\n header: string,\n secret: string,\n options: VerifyOptions = {},\n): T {\n if (!verify(payload, header, secret, options)) {\n throw new WebhookVerificationError(\"Webhook signature verification failed\");\n }\n const body = typeof payload === \"string\" ? payload : payload.toString(\"utf8\");\n return JSON.parse(body) as T;\n}\n\nexport const webhooks = { verify, constructEvent };\n","import { apiRequest, type HttpConfig } from \"./http.js\";\n\nexport interface SimplrAdminOptions {\n /** Portal token (JWT) for dashboard/admin operations. */\n token: string;\n /** API base URL. Defaults to https://api.simplr.sh. */\n baseUrl?: string;\n timeoutMs?: number;\n fetch?: typeof fetch;\n}\n\nfunction qs(params: Record<string, unknown>): string {\n const entries = Object.entries(params).filter(([, v]) => v !== undefined && v !== null);\n if (!entries.length) return \"\";\n return \"?\" + entries.map(([k, v]) => `${k}=${encodeURIComponent(String(v))}`).join(\"&\");\n}\n\n/** Usage / measurement reads. */\nclass UsageApi {\n constructor(private readonly cfg: HttpConfig) {}\n /** Aggregate usage stats for an org. */\n stats(orgId: string) {\n return apiRequest(this.cfg, \"GET\", `/v1/usage/stats${qs({ org_id: orgId })}`);\n }\n /** Raw usage logs for an org. */\n logs(orgId: string, params: { page?: number; limit?: number } = {}) {\n return apiRequest(this.cfg, \"GET\", `/v1/usage/logs${qs({ org_id: orgId, ...params })}`);\n }\n /** Billing usage breakdown (per-service totals + estimated cost). */\n billing(orgId: string) {\n return apiRequest(this.cfg, \"GET\", `/v1/billing/usage${qs({ org_id: orgId })}`);\n }\n}\n\n/** Feature-flag administration (create/update/delete/history). */\nclass FlagsAdminApi {\n constructor(private readonly cfg: HttpConfig) {}\n list(orgId: string, environment?: \"live\" | \"test\") {\n return apiRequest(this.cfg, \"GET\", `/v1/feature-flags${qs({ org_id: orgId, environment })}`);\n }\n get(orgId: string, id: string) {\n return apiRequest(this.cfg, \"GET\", `/v1/feature-flags/${id}${qs({ org_id: orgId })}`);\n }\n create(orgId: string, data: Record<string, unknown>) {\n return apiRequest(this.cfg, \"POST\", \"/v1/feature-flags\", { org_id: orgId, ...data });\n }\n update(orgId: string, id: string, data: Record<string, unknown>) {\n return apiRequest(this.cfg, \"PATCH\", `/v1/feature-flags/${id}`, { org_id: orgId, ...data });\n }\n remove(orgId: string, id: string) {\n return apiRequest(this.cfg, \"DELETE\", `/v1/feature-flags/${id}${qs({ org_id: orgId })}`);\n }\n history(orgId: string, id: string, params: { limit?: number; offset?: number } = {}) {\n return apiRequest(\n this.cfg,\n \"GET\",\n `/v1/feature-flags/${id}/history${qs({ org_id: orgId, ...params })}`,\n );\n }\n}\n\n/** RUM analytics reads. */\nclass RumApi {\n constructor(private readonly cfg: HttpConfig) {}\n overview(orgId: string, params: { application_id?: string; start_date?: string; end_date?: string } = {}) {\n return apiRequest(this.cfg, \"GET\", `/v1/rum/overview${qs({ org_id: orgId, ...params })}`);\n }\n sessions(orgId: string, params: { page?: number; limit?: number; user_id?: string } = {}) {\n return apiRequest(this.cfg, \"GET\", `/v1/rum/sessions${qs({ org_id: orgId, ...params })}`);\n }\n}\n\n/**\n * Management client for dashboard/admin operations that require a portal token\n * (usage/measurement, feature-flag CRUD, RUM analytics).\n *\n * ```ts\n * const admin = new SimplrAdmin({ token: process.env.SIMPLR_PORTAL_TOKEN! });\n * const usage = await admin.usage.billing(orgId);\n * await admin.flags.create(orgId, { key: \"new-checkout\", environment: \"test\", rollout_percentage: 10 });\n * ```\n */\nexport class SimplrAdmin {\n readonly usage: UsageApi;\n readonly flags: FlagsAdminApi;\n readonly rum: RumApi;\n\n constructor(options: SimplrAdminOptions) {\n if (!options?.token) throw new Error(\"SimplrAdmin: `token` is required\");\n const cfg: HttpConfig = {\n authHeaders: { Authorization: `Bearer ${options.token}` },\n baseUrl: (options.baseUrl || \"https://api.simplr.sh\").replace(/\\/+$/, \"\"),\n timeoutMs: options.timeoutMs ?? 15000,\n fetchImpl: options.fetch ?? globalThis.fetch,\n };\n if (typeof cfg.fetchImpl !== \"function\") {\n throw new Error(\"SimplrAdmin: no global fetch available — use Node 18+ or pass `fetch`\");\n }\n this.usage = new UsageApi(cfg);\n this.flags = new FlagsAdminApi(cfg);\n this.rum = new RumApi(cfg);\n }\n}\n"],"mappings":"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","names":[]}
|
package/dist/index.d.cts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
interface HttpConfig {
|
|
2
|
-
|
|
2
|
+
/** Auth headers to send (e.g. { "X-API-Key": "sk_…" } or { Authorization: "Bearer …" }). */
|
|
3
|
+
authHeaders: Record<string, string>;
|
|
3
4
|
baseUrl: string;
|
|
4
5
|
timeoutMs: number;
|
|
5
6
|
fetchImpl: typeof fetch;
|
|
@@ -9,6 +10,8 @@ type RiskLevel = "low" | "medium" | "high" | "critical";
|
|
|
9
10
|
interface SimplrOptions {
|
|
10
11
|
/** Secret API key (sk_live_… / sk_test_…). Keep this server-side only. */
|
|
11
12
|
apiKey: string;
|
|
13
|
+
/** Public key (pk_…) — enables `simplr.flags` for server-side feature-flag evaluation. */
|
|
14
|
+
publicKey?: string;
|
|
12
15
|
/** API base URL. Defaults to https://api.simplr.sh. */
|
|
13
16
|
baseUrl?: string;
|
|
14
17
|
/** Per-request timeout in ms (default 15000). */
|
|
@@ -109,6 +112,66 @@ declare class EdgeResource {
|
|
|
109
112
|
ingestLogs(deviceId: string, logs: EdgeLogEntry[]): Promise<unknown>;
|
|
110
113
|
}
|
|
111
114
|
|
|
115
|
+
interface FlagRule {
|
|
116
|
+
attribute: string;
|
|
117
|
+
op: "eq" | "neq" | "contains";
|
|
118
|
+
value: string;
|
|
119
|
+
}
|
|
120
|
+
interface FlagDefinition {
|
|
121
|
+
key: string;
|
|
122
|
+
enabled: boolean;
|
|
123
|
+
rollout_percentage: number;
|
|
124
|
+
target_user_ids: string[];
|
|
125
|
+
rules: FlagRule[];
|
|
126
|
+
}
|
|
127
|
+
interface FlagsOptions {
|
|
128
|
+
/** Public API key (pk_live_… / pk_test_…). Required — flags read uses the public key. */
|
|
129
|
+
publicKey: string;
|
|
130
|
+
/** API base URL. Defaults to https://api.simplr.sh. */
|
|
131
|
+
baseUrl?: string;
|
|
132
|
+
/** Which environment's flags to load. Defaults to the key's own environment. */
|
|
133
|
+
environment?: "live" | "test";
|
|
134
|
+
/** Auto-refresh interval in ms (default 60000; 0 disables). */
|
|
135
|
+
refreshIntervalMs?: number;
|
|
136
|
+
timeoutMs?: number;
|
|
137
|
+
fetch?: typeof fetch;
|
|
138
|
+
}
|
|
139
|
+
interface EvalContext {
|
|
140
|
+
userId?: string;
|
|
141
|
+
attributes?: Record<string, unknown>;
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Server-side feature flags with local, deterministic evaluation.
|
|
145
|
+
*
|
|
146
|
+
* ```ts
|
|
147
|
+
* const flags = new SimplrFlags({ publicKey: process.env.SIMPLR_PUBLIC_KEY! });
|
|
148
|
+
* await flags.initialize();
|
|
149
|
+
* if (flags.isEnabled("new-checkout", { userId: "user_123" })) { ... }
|
|
150
|
+
* ```
|
|
151
|
+
*/
|
|
152
|
+
declare class SimplrFlags {
|
|
153
|
+
private readonly cfg;
|
|
154
|
+
private readonly environment?;
|
|
155
|
+
private readonly refreshIntervalMs;
|
|
156
|
+
private flags;
|
|
157
|
+
private defaultUserId?;
|
|
158
|
+
private timer;
|
|
159
|
+
private ready;
|
|
160
|
+
constructor(options: FlagsOptions);
|
|
161
|
+
/** Fetch the flag config once and start the background refresh. */
|
|
162
|
+
initialize(): Promise<void>;
|
|
163
|
+
/** Set the default identifier used for bucketing when none is passed to isEnabled. */
|
|
164
|
+
setUser(userId: string): void;
|
|
165
|
+
/** Re-fetch the flag config (counts as one billable request). */
|
|
166
|
+
refresh(): Promise<void>;
|
|
167
|
+
/** Evaluate a flag locally. Deterministic per user; no network call. */
|
|
168
|
+
isEnabled(key: string, ctx?: EvalContext): boolean;
|
|
169
|
+
getAll(): Record<string, FlagDefinition>;
|
|
170
|
+
isReady(): boolean;
|
|
171
|
+
/** Stop the background refresh timer. */
|
|
172
|
+
dispose(): void;
|
|
173
|
+
}
|
|
174
|
+
|
|
112
175
|
interface VerifyOptions {
|
|
113
176
|
/** Reject signatures whose timestamp is older than this many seconds (default 300). 0 disables. */
|
|
114
177
|
toleranceSec?: number;
|
|
@@ -154,6 +217,74 @@ declare class WebhookVerificationError extends Error {
|
|
|
154
217
|
constructor(message: string);
|
|
155
218
|
}
|
|
156
219
|
|
|
220
|
+
interface SimplrAdminOptions {
|
|
221
|
+
/** Portal token (JWT) for dashboard/admin operations. */
|
|
222
|
+
token: string;
|
|
223
|
+
/** API base URL. Defaults to https://api.simplr.sh. */
|
|
224
|
+
baseUrl?: string;
|
|
225
|
+
timeoutMs?: number;
|
|
226
|
+
fetch?: typeof fetch;
|
|
227
|
+
}
|
|
228
|
+
/** Usage / measurement reads. */
|
|
229
|
+
declare class UsageApi {
|
|
230
|
+
private readonly cfg;
|
|
231
|
+
constructor(cfg: HttpConfig);
|
|
232
|
+
/** Aggregate usage stats for an org. */
|
|
233
|
+
stats(orgId: string): Promise<unknown>;
|
|
234
|
+
/** Raw usage logs for an org. */
|
|
235
|
+
logs(orgId: string, params?: {
|
|
236
|
+
page?: number;
|
|
237
|
+
limit?: number;
|
|
238
|
+
}): Promise<unknown>;
|
|
239
|
+
/** Billing usage breakdown (per-service totals + estimated cost). */
|
|
240
|
+
billing(orgId: string): Promise<unknown>;
|
|
241
|
+
}
|
|
242
|
+
/** Feature-flag administration (create/update/delete/history). */
|
|
243
|
+
declare class FlagsAdminApi {
|
|
244
|
+
private readonly cfg;
|
|
245
|
+
constructor(cfg: HttpConfig);
|
|
246
|
+
list(orgId: string, environment?: "live" | "test"): Promise<unknown>;
|
|
247
|
+
get(orgId: string, id: string): Promise<unknown>;
|
|
248
|
+
create(orgId: string, data: Record<string, unknown>): Promise<unknown>;
|
|
249
|
+
update(orgId: string, id: string, data: Record<string, unknown>): Promise<unknown>;
|
|
250
|
+
remove(orgId: string, id: string): Promise<unknown>;
|
|
251
|
+
history(orgId: string, id: string, params?: {
|
|
252
|
+
limit?: number;
|
|
253
|
+
offset?: number;
|
|
254
|
+
}): Promise<unknown>;
|
|
255
|
+
}
|
|
256
|
+
/** RUM analytics reads. */
|
|
257
|
+
declare class RumApi {
|
|
258
|
+
private readonly cfg;
|
|
259
|
+
constructor(cfg: HttpConfig);
|
|
260
|
+
overview(orgId: string, params?: {
|
|
261
|
+
application_id?: string;
|
|
262
|
+
start_date?: string;
|
|
263
|
+
end_date?: string;
|
|
264
|
+
}): Promise<unknown>;
|
|
265
|
+
sessions(orgId: string, params?: {
|
|
266
|
+
page?: number;
|
|
267
|
+
limit?: number;
|
|
268
|
+
user_id?: string;
|
|
269
|
+
}): Promise<unknown>;
|
|
270
|
+
}
|
|
271
|
+
/**
|
|
272
|
+
* Management client for dashboard/admin operations that require a portal token
|
|
273
|
+
* (usage/measurement, feature-flag CRUD, RUM analytics).
|
|
274
|
+
*
|
|
275
|
+
* ```ts
|
|
276
|
+
* const admin = new SimplrAdmin({ token: process.env.SIMPLR_PORTAL_TOKEN! });
|
|
277
|
+
* const usage = await admin.usage.billing(orgId);
|
|
278
|
+
* await admin.flags.create(orgId, { key: "new-checkout", environment: "test", rollout_percentage: 10 });
|
|
279
|
+
* ```
|
|
280
|
+
*/
|
|
281
|
+
declare class SimplrAdmin {
|
|
282
|
+
readonly usage: UsageApi;
|
|
283
|
+
readonly flags: FlagsAdminApi;
|
|
284
|
+
readonly rum: RumApi;
|
|
285
|
+
constructor(options: SimplrAdminOptions);
|
|
286
|
+
}
|
|
287
|
+
|
|
157
288
|
/**
|
|
158
289
|
* Simplr server-side client.
|
|
159
290
|
*
|
|
@@ -170,11 +301,17 @@ declare class Simplr {
|
|
|
170
301
|
readonly edge: EdgeResource;
|
|
171
302
|
/** Webhook signature helpers (no network). */
|
|
172
303
|
readonly webhooks: typeof webhooks$1;
|
|
304
|
+
private readonly _flags?;
|
|
173
305
|
constructor(options: SimplrOptions);
|
|
306
|
+
/**
|
|
307
|
+
* Server-side feature flags. Requires a `publicKey` in the constructor options
|
|
308
|
+
* (flag config is read with the public key). Call `simplr.flags.initialize()` once.
|
|
309
|
+
*/
|
|
310
|
+
get flags(): SimplrFlags;
|
|
174
311
|
/** Run an identity/fraud check. Provide any of email, phone, device, behavior. */
|
|
175
312
|
check(input: CheckInput): Promise<CheckResult>;
|
|
176
313
|
/** Run up to 100 checks at once. */
|
|
177
314
|
checkBulk(items: CheckInput[]): Promise<BulkResult<CheckResult>>;
|
|
178
315
|
}
|
|
179
316
|
|
|
180
|
-
export { type BulkResult, type CheckInput, type CheckResult, type EdgeLogEntry, type OrderInput, type OrderResult, type PhoneOutcome, type PhoneReportInput, type RiskLevel, Simplr, SimplrError, type SimplrOptions, WebhookVerificationError, constructEvent as constructWebhookEvent, Simplr as default, verify as verifyWebhook };
|
|
317
|
+
export { type BulkResult, type CheckInput, type CheckResult, type EdgeLogEntry, type EvalContext, type FlagDefinition, type FlagRule, type FlagsOptions, type OrderInput, type OrderResult, type PhoneOutcome, type PhoneReportInput, type RiskLevel, Simplr, SimplrAdmin, type SimplrAdminOptions, SimplrError, SimplrFlags, type SimplrOptions, WebhookVerificationError, constructEvent as constructWebhookEvent, Simplr as default, verify as verifyWebhook };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
interface HttpConfig {
|
|
2
|
-
|
|
2
|
+
/** Auth headers to send (e.g. { "X-API-Key": "sk_…" } or { Authorization: "Bearer …" }). */
|
|
3
|
+
authHeaders: Record<string, string>;
|
|
3
4
|
baseUrl: string;
|
|
4
5
|
timeoutMs: number;
|
|
5
6
|
fetchImpl: typeof fetch;
|
|
@@ -9,6 +10,8 @@ type RiskLevel = "low" | "medium" | "high" | "critical";
|
|
|
9
10
|
interface SimplrOptions {
|
|
10
11
|
/** Secret API key (sk_live_… / sk_test_…). Keep this server-side only. */
|
|
11
12
|
apiKey: string;
|
|
13
|
+
/** Public key (pk_…) — enables `simplr.flags` for server-side feature-flag evaluation. */
|
|
14
|
+
publicKey?: string;
|
|
12
15
|
/** API base URL. Defaults to https://api.simplr.sh. */
|
|
13
16
|
baseUrl?: string;
|
|
14
17
|
/** Per-request timeout in ms (default 15000). */
|
|
@@ -109,6 +112,66 @@ declare class EdgeResource {
|
|
|
109
112
|
ingestLogs(deviceId: string, logs: EdgeLogEntry[]): Promise<unknown>;
|
|
110
113
|
}
|
|
111
114
|
|
|
115
|
+
interface FlagRule {
|
|
116
|
+
attribute: string;
|
|
117
|
+
op: "eq" | "neq" | "contains";
|
|
118
|
+
value: string;
|
|
119
|
+
}
|
|
120
|
+
interface FlagDefinition {
|
|
121
|
+
key: string;
|
|
122
|
+
enabled: boolean;
|
|
123
|
+
rollout_percentage: number;
|
|
124
|
+
target_user_ids: string[];
|
|
125
|
+
rules: FlagRule[];
|
|
126
|
+
}
|
|
127
|
+
interface FlagsOptions {
|
|
128
|
+
/** Public API key (pk_live_… / pk_test_…). Required — flags read uses the public key. */
|
|
129
|
+
publicKey: string;
|
|
130
|
+
/** API base URL. Defaults to https://api.simplr.sh. */
|
|
131
|
+
baseUrl?: string;
|
|
132
|
+
/** Which environment's flags to load. Defaults to the key's own environment. */
|
|
133
|
+
environment?: "live" | "test";
|
|
134
|
+
/** Auto-refresh interval in ms (default 60000; 0 disables). */
|
|
135
|
+
refreshIntervalMs?: number;
|
|
136
|
+
timeoutMs?: number;
|
|
137
|
+
fetch?: typeof fetch;
|
|
138
|
+
}
|
|
139
|
+
interface EvalContext {
|
|
140
|
+
userId?: string;
|
|
141
|
+
attributes?: Record<string, unknown>;
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Server-side feature flags with local, deterministic evaluation.
|
|
145
|
+
*
|
|
146
|
+
* ```ts
|
|
147
|
+
* const flags = new SimplrFlags({ publicKey: process.env.SIMPLR_PUBLIC_KEY! });
|
|
148
|
+
* await flags.initialize();
|
|
149
|
+
* if (flags.isEnabled("new-checkout", { userId: "user_123" })) { ... }
|
|
150
|
+
* ```
|
|
151
|
+
*/
|
|
152
|
+
declare class SimplrFlags {
|
|
153
|
+
private readonly cfg;
|
|
154
|
+
private readonly environment?;
|
|
155
|
+
private readonly refreshIntervalMs;
|
|
156
|
+
private flags;
|
|
157
|
+
private defaultUserId?;
|
|
158
|
+
private timer;
|
|
159
|
+
private ready;
|
|
160
|
+
constructor(options: FlagsOptions);
|
|
161
|
+
/** Fetch the flag config once and start the background refresh. */
|
|
162
|
+
initialize(): Promise<void>;
|
|
163
|
+
/** Set the default identifier used for bucketing when none is passed to isEnabled. */
|
|
164
|
+
setUser(userId: string): void;
|
|
165
|
+
/** Re-fetch the flag config (counts as one billable request). */
|
|
166
|
+
refresh(): Promise<void>;
|
|
167
|
+
/** Evaluate a flag locally. Deterministic per user; no network call. */
|
|
168
|
+
isEnabled(key: string, ctx?: EvalContext): boolean;
|
|
169
|
+
getAll(): Record<string, FlagDefinition>;
|
|
170
|
+
isReady(): boolean;
|
|
171
|
+
/** Stop the background refresh timer. */
|
|
172
|
+
dispose(): void;
|
|
173
|
+
}
|
|
174
|
+
|
|
112
175
|
interface VerifyOptions {
|
|
113
176
|
/** Reject signatures whose timestamp is older than this many seconds (default 300). 0 disables. */
|
|
114
177
|
toleranceSec?: number;
|
|
@@ -154,6 +217,74 @@ declare class WebhookVerificationError extends Error {
|
|
|
154
217
|
constructor(message: string);
|
|
155
218
|
}
|
|
156
219
|
|
|
220
|
+
interface SimplrAdminOptions {
|
|
221
|
+
/** Portal token (JWT) for dashboard/admin operations. */
|
|
222
|
+
token: string;
|
|
223
|
+
/** API base URL. Defaults to https://api.simplr.sh. */
|
|
224
|
+
baseUrl?: string;
|
|
225
|
+
timeoutMs?: number;
|
|
226
|
+
fetch?: typeof fetch;
|
|
227
|
+
}
|
|
228
|
+
/** Usage / measurement reads. */
|
|
229
|
+
declare class UsageApi {
|
|
230
|
+
private readonly cfg;
|
|
231
|
+
constructor(cfg: HttpConfig);
|
|
232
|
+
/** Aggregate usage stats for an org. */
|
|
233
|
+
stats(orgId: string): Promise<unknown>;
|
|
234
|
+
/** Raw usage logs for an org. */
|
|
235
|
+
logs(orgId: string, params?: {
|
|
236
|
+
page?: number;
|
|
237
|
+
limit?: number;
|
|
238
|
+
}): Promise<unknown>;
|
|
239
|
+
/** Billing usage breakdown (per-service totals + estimated cost). */
|
|
240
|
+
billing(orgId: string): Promise<unknown>;
|
|
241
|
+
}
|
|
242
|
+
/** Feature-flag administration (create/update/delete/history). */
|
|
243
|
+
declare class FlagsAdminApi {
|
|
244
|
+
private readonly cfg;
|
|
245
|
+
constructor(cfg: HttpConfig);
|
|
246
|
+
list(orgId: string, environment?: "live" | "test"): Promise<unknown>;
|
|
247
|
+
get(orgId: string, id: string): Promise<unknown>;
|
|
248
|
+
create(orgId: string, data: Record<string, unknown>): Promise<unknown>;
|
|
249
|
+
update(orgId: string, id: string, data: Record<string, unknown>): Promise<unknown>;
|
|
250
|
+
remove(orgId: string, id: string): Promise<unknown>;
|
|
251
|
+
history(orgId: string, id: string, params?: {
|
|
252
|
+
limit?: number;
|
|
253
|
+
offset?: number;
|
|
254
|
+
}): Promise<unknown>;
|
|
255
|
+
}
|
|
256
|
+
/** RUM analytics reads. */
|
|
257
|
+
declare class RumApi {
|
|
258
|
+
private readonly cfg;
|
|
259
|
+
constructor(cfg: HttpConfig);
|
|
260
|
+
overview(orgId: string, params?: {
|
|
261
|
+
application_id?: string;
|
|
262
|
+
start_date?: string;
|
|
263
|
+
end_date?: string;
|
|
264
|
+
}): Promise<unknown>;
|
|
265
|
+
sessions(orgId: string, params?: {
|
|
266
|
+
page?: number;
|
|
267
|
+
limit?: number;
|
|
268
|
+
user_id?: string;
|
|
269
|
+
}): Promise<unknown>;
|
|
270
|
+
}
|
|
271
|
+
/**
|
|
272
|
+
* Management client for dashboard/admin operations that require a portal token
|
|
273
|
+
* (usage/measurement, feature-flag CRUD, RUM analytics).
|
|
274
|
+
*
|
|
275
|
+
* ```ts
|
|
276
|
+
* const admin = new SimplrAdmin({ token: process.env.SIMPLR_PORTAL_TOKEN! });
|
|
277
|
+
* const usage = await admin.usage.billing(orgId);
|
|
278
|
+
* await admin.flags.create(orgId, { key: "new-checkout", environment: "test", rollout_percentage: 10 });
|
|
279
|
+
* ```
|
|
280
|
+
*/
|
|
281
|
+
declare class SimplrAdmin {
|
|
282
|
+
readonly usage: UsageApi;
|
|
283
|
+
readonly flags: FlagsAdminApi;
|
|
284
|
+
readonly rum: RumApi;
|
|
285
|
+
constructor(options: SimplrAdminOptions);
|
|
286
|
+
}
|
|
287
|
+
|
|
157
288
|
/**
|
|
158
289
|
* Simplr server-side client.
|
|
159
290
|
*
|
|
@@ -170,11 +301,17 @@ declare class Simplr {
|
|
|
170
301
|
readonly edge: EdgeResource;
|
|
171
302
|
/** Webhook signature helpers (no network). */
|
|
172
303
|
readonly webhooks: typeof webhooks$1;
|
|
304
|
+
private readonly _flags?;
|
|
173
305
|
constructor(options: SimplrOptions);
|
|
306
|
+
/**
|
|
307
|
+
* Server-side feature flags. Requires a `publicKey` in the constructor options
|
|
308
|
+
* (flag config is read with the public key). Call `simplr.flags.initialize()` once.
|
|
309
|
+
*/
|
|
310
|
+
get flags(): SimplrFlags;
|
|
174
311
|
/** Run an identity/fraud check. Provide any of email, phone, device, behavior. */
|
|
175
312
|
check(input: CheckInput): Promise<CheckResult>;
|
|
176
313
|
/** Run up to 100 checks at once. */
|
|
177
314
|
checkBulk(items: CheckInput[]): Promise<BulkResult<CheckResult>>;
|
|
178
315
|
}
|
|
179
316
|
|
|
180
|
-
export { type BulkResult, type CheckInput, type CheckResult, type EdgeLogEntry, type OrderInput, type OrderResult, type PhoneOutcome, type PhoneReportInput, type RiskLevel, Simplr, SimplrError, type SimplrOptions, WebhookVerificationError, constructEvent as constructWebhookEvent, Simplr as default, verify as verifyWebhook };
|
|
317
|
+
export { type BulkResult, type CheckInput, type CheckResult, type EdgeLogEntry, type EvalContext, type FlagDefinition, type FlagRule, type FlagsOptions, type OrderInput, type OrderResult, type PhoneOutcome, type PhoneReportInput, type RiskLevel, Simplr, SimplrAdmin, type SimplrAdminOptions, SimplrError, SimplrFlags, type SimplrOptions, WebhookVerificationError, constructEvent as constructWebhookEvent, Simplr as default, verify as verifyWebhook };
|
package/dist/index.js
CHANGED
|
@@ -31,7 +31,7 @@ async function apiRequest(cfg, method, path, body) {
|
|
|
31
31
|
method,
|
|
32
32
|
headers: {
|
|
33
33
|
"Content-Type": "application/json",
|
|
34
|
-
|
|
34
|
+
...cfg.authHeaders
|
|
35
35
|
},
|
|
36
36
|
body: body !== void 0 ? JSON.stringify(body) : void 0,
|
|
37
37
|
signal: controller.signal
|
|
@@ -112,6 +112,113 @@ var EdgeResource = class {
|
|
|
112
112
|
}
|
|
113
113
|
};
|
|
114
114
|
|
|
115
|
+
// src/flags.ts
|
|
116
|
+
function murmurHash3(input, seed = 0) {
|
|
117
|
+
let h1 = seed;
|
|
118
|
+
const c1 = 3432918353;
|
|
119
|
+
const c2 = 461845907;
|
|
120
|
+
for (let i = 0; i < input.length; i++) {
|
|
121
|
+
let k1 = input.charCodeAt(i);
|
|
122
|
+
k1 = Math.imul(k1, c1);
|
|
123
|
+
k1 = k1 << 15 | k1 >>> 17;
|
|
124
|
+
k1 = Math.imul(k1, c2);
|
|
125
|
+
h1 ^= k1;
|
|
126
|
+
h1 = h1 << 13 | h1 >>> 19;
|
|
127
|
+
h1 = Math.imul(h1, 5) + 3864292196;
|
|
128
|
+
}
|
|
129
|
+
h1 ^= input.length;
|
|
130
|
+
h1 ^= h1 >>> 16;
|
|
131
|
+
h1 = Math.imul(h1, 2246822507);
|
|
132
|
+
h1 ^= h1 >>> 13;
|
|
133
|
+
h1 = Math.imul(h1, 3266489909);
|
|
134
|
+
h1 ^= h1 >>> 16;
|
|
135
|
+
return h1 >>> 0;
|
|
136
|
+
}
|
|
137
|
+
function matchRule(rule, attributes) {
|
|
138
|
+
const actual = attributes[rule.attribute];
|
|
139
|
+
switch (rule.op) {
|
|
140
|
+
case "eq":
|
|
141
|
+
return String(actual) === rule.value;
|
|
142
|
+
case "neq":
|
|
143
|
+
return String(actual) !== rule.value;
|
|
144
|
+
case "contains":
|
|
145
|
+
return String(actual ?? "").includes(rule.value);
|
|
146
|
+
default:
|
|
147
|
+
return false;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
var SimplrFlags = class {
|
|
151
|
+
cfg;
|
|
152
|
+
environment;
|
|
153
|
+
refreshIntervalMs;
|
|
154
|
+
flags = {};
|
|
155
|
+
defaultUserId;
|
|
156
|
+
timer = null;
|
|
157
|
+
ready = false;
|
|
158
|
+
constructor(options) {
|
|
159
|
+
if (!options?.publicKey) throw new Error("SimplrFlags: `publicKey` is required");
|
|
160
|
+
this.cfg = {
|
|
161
|
+
authHeaders: { "X-API-Key": options.publicKey },
|
|
162
|
+
baseUrl: (options.baseUrl || "https://api.simplr.sh").replace(/\/+$/, ""),
|
|
163
|
+
timeoutMs: options.timeoutMs ?? 15e3,
|
|
164
|
+
fetchImpl: options.fetch ?? globalThis.fetch
|
|
165
|
+
};
|
|
166
|
+
this.environment = options.environment;
|
|
167
|
+
this.refreshIntervalMs = options.refreshIntervalMs ?? 6e4;
|
|
168
|
+
}
|
|
169
|
+
/** Fetch the flag config once and start the background refresh. */
|
|
170
|
+
async initialize() {
|
|
171
|
+
await this.refresh();
|
|
172
|
+
this.ready = true;
|
|
173
|
+
if (this.refreshIntervalMs > 0) {
|
|
174
|
+
this.timer = setInterval(() => {
|
|
175
|
+
void this.refresh();
|
|
176
|
+
}, this.refreshIntervalMs);
|
|
177
|
+
this.timer?.unref?.();
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
/** Set the default identifier used for bucketing when none is passed to isEnabled. */
|
|
181
|
+
setUser(userId) {
|
|
182
|
+
this.defaultUserId = userId;
|
|
183
|
+
}
|
|
184
|
+
/** Re-fetch the flag config (counts as one billable request). */
|
|
185
|
+
async refresh() {
|
|
186
|
+
const path = this.environment ? `/v1/flags?environment=${this.environment}` : "/v1/flags";
|
|
187
|
+
try {
|
|
188
|
+
const content = await apiRequest(this.cfg, "GET", path);
|
|
189
|
+
const list = content?.flags || [];
|
|
190
|
+
const map = {};
|
|
191
|
+
for (const f of list) map[f.key] = f;
|
|
192
|
+
this.flags = map;
|
|
193
|
+
} catch {
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
/** Evaluate a flag locally. Deterministic per user; no network call. */
|
|
197
|
+
isEnabled(key, ctx = {}) {
|
|
198
|
+
const f = this.flags[key];
|
|
199
|
+
if (!f || !f.enabled) return false;
|
|
200
|
+
const uid = ctx.userId || this.defaultUserId || "anonymous";
|
|
201
|
+
if (f.target_user_ids?.includes(uid)) return true;
|
|
202
|
+
if (ctx.attributes && f.rules?.length && f.rules.some((r) => matchRule(r, ctx.attributes))) {
|
|
203
|
+
return true;
|
|
204
|
+
}
|
|
205
|
+
if (f.rollout_percentage >= 100) return true;
|
|
206
|
+
if (f.rollout_percentage <= 0) return false;
|
|
207
|
+
return murmurHash3(`${key}:${uid}`) % 100 < f.rollout_percentage;
|
|
208
|
+
}
|
|
209
|
+
getAll() {
|
|
210
|
+
return { ...this.flags };
|
|
211
|
+
}
|
|
212
|
+
isReady() {
|
|
213
|
+
return this.ready;
|
|
214
|
+
}
|
|
215
|
+
/** Stop the background refresh timer. */
|
|
216
|
+
dispose() {
|
|
217
|
+
if (this.timer) clearInterval(this.timer);
|
|
218
|
+
this.timer = null;
|
|
219
|
+
}
|
|
220
|
+
};
|
|
221
|
+
|
|
115
222
|
// src/webhooks.ts
|
|
116
223
|
var webhooks_exports = {};
|
|
117
224
|
__export(webhooks_exports, {
|
|
@@ -166,6 +273,91 @@ function constructEvent(payload, header, secret, options = {}) {
|
|
|
166
273
|
}
|
|
167
274
|
var webhooks = { verify, constructEvent };
|
|
168
275
|
|
|
276
|
+
// src/admin.ts
|
|
277
|
+
function qs(params) {
|
|
278
|
+
const entries = Object.entries(params).filter(([, v]) => v !== void 0 && v !== null);
|
|
279
|
+
if (!entries.length) return "";
|
|
280
|
+
return "?" + entries.map(([k, v]) => `${k}=${encodeURIComponent(String(v))}`).join("&");
|
|
281
|
+
}
|
|
282
|
+
var UsageApi = class {
|
|
283
|
+
constructor(cfg) {
|
|
284
|
+
this.cfg = cfg;
|
|
285
|
+
}
|
|
286
|
+
cfg;
|
|
287
|
+
/** Aggregate usage stats for an org. */
|
|
288
|
+
stats(orgId) {
|
|
289
|
+
return apiRequest(this.cfg, "GET", `/v1/usage/stats${qs({ org_id: orgId })}`);
|
|
290
|
+
}
|
|
291
|
+
/** Raw usage logs for an org. */
|
|
292
|
+
logs(orgId, params = {}) {
|
|
293
|
+
return apiRequest(this.cfg, "GET", `/v1/usage/logs${qs({ org_id: orgId, ...params })}`);
|
|
294
|
+
}
|
|
295
|
+
/** Billing usage breakdown (per-service totals + estimated cost). */
|
|
296
|
+
billing(orgId) {
|
|
297
|
+
return apiRequest(this.cfg, "GET", `/v1/billing/usage${qs({ org_id: orgId })}`);
|
|
298
|
+
}
|
|
299
|
+
};
|
|
300
|
+
var FlagsAdminApi = class {
|
|
301
|
+
constructor(cfg) {
|
|
302
|
+
this.cfg = cfg;
|
|
303
|
+
}
|
|
304
|
+
cfg;
|
|
305
|
+
list(orgId, environment) {
|
|
306
|
+
return apiRequest(this.cfg, "GET", `/v1/feature-flags${qs({ org_id: orgId, environment })}`);
|
|
307
|
+
}
|
|
308
|
+
get(orgId, id) {
|
|
309
|
+
return apiRequest(this.cfg, "GET", `/v1/feature-flags/${id}${qs({ org_id: orgId })}`);
|
|
310
|
+
}
|
|
311
|
+
create(orgId, data) {
|
|
312
|
+
return apiRequest(this.cfg, "POST", "/v1/feature-flags", { org_id: orgId, ...data });
|
|
313
|
+
}
|
|
314
|
+
update(orgId, id, data) {
|
|
315
|
+
return apiRequest(this.cfg, "PATCH", `/v1/feature-flags/${id}`, { org_id: orgId, ...data });
|
|
316
|
+
}
|
|
317
|
+
remove(orgId, id) {
|
|
318
|
+
return apiRequest(this.cfg, "DELETE", `/v1/feature-flags/${id}${qs({ org_id: orgId })}`);
|
|
319
|
+
}
|
|
320
|
+
history(orgId, id, params = {}) {
|
|
321
|
+
return apiRequest(
|
|
322
|
+
this.cfg,
|
|
323
|
+
"GET",
|
|
324
|
+
`/v1/feature-flags/${id}/history${qs({ org_id: orgId, ...params })}`
|
|
325
|
+
);
|
|
326
|
+
}
|
|
327
|
+
};
|
|
328
|
+
var RumApi = class {
|
|
329
|
+
constructor(cfg) {
|
|
330
|
+
this.cfg = cfg;
|
|
331
|
+
}
|
|
332
|
+
cfg;
|
|
333
|
+
overview(orgId, params = {}) {
|
|
334
|
+
return apiRequest(this.cfg, "GET", `/v1/rum/overview${qs({ org_id: orgId, ...params })}`);
|
|
335
|
+
}
|
|
336
|
+
sessions(orgId, params = {}) {
|
|
337
|
+
return apiRequest(this.cfg, "GET", `/v1/rum/sessions${qs({ org_id: orgId, ...params })}`);
|
|
338
|
+
}
|
|
339
|
+
};
|
|
340
|
+
var SimplrAdmin = class {
|
|
341
|
+
usage;
|
|
342
|
+
flags;
|
|
343
|
+
rum;
|
|
344
|
+
constructor(options) {
|
|
345
|
+
if (!options?.token) throw new Error("SimplrAdmin: `token` is required");
|
|
346
|
+
const cfg = {
|
|
347
|
+
authHeaders: { Authorization: `Bearer ${options.token}` },
|
|
348
|
+
baseUrl: (options.baseUrl || "https://api.simplr.sh").replace(/\/+$/, ""),
|
|
349
|
+
timeoutMs: options.timeoutMs ?? 15e3,
|
|
350
|
+
fetchImpl: options.fetch ?? globalThis.fetch
|
|
351
|
+
};
|
|
352
|
+
if (typeof cfg.fetchImpl !== "function") {
|
|
353
|
+
throw new Error("SimplrAdmin: no global fetch available \u2014 use Node 18+ or pass `fetch`");
|
|
354
|
+
}
|
|
355
|
+
this.usage = new UsageApi(cfg);
|
|
356
|
+
this.flags = new FlagsAdminApi(cfg);
|
|
357
|
+
this.rum = new RumApi(cfg);
|
|
358
|
+
}
|
|
359
|
+
};
|
|
360
|
+
|
|
169
361
|
// src/index.ts
|
|
170
362
|
var DEFAULT_BASE_URL = "https://api.simplr.sh";
|
|
171
363
|
var Simplr = class {
|
|
@@ -175,10 +367,11 @@ var Simplr = class {
|
|
|
175
367
|
edge;
|
|
176
368
|
/** Webhook signature helpers (no network). */
|
|
177
369
|
webhooks = webhooks_exports;
|
|
370
|
+
_flags;
|
|
178
371
|
constructor(options) {
|
|
179
372
|
if (!options?.apiKey) throw new Error("Simplr: `apiKey` is required");
|
|
180
373
|
this.cfg = {
|
|
181
|
-
|
|
374
|
+
authHeaders: { "X-API-Key": options.apiKey },
|
|
182
375
|
baseUrl: (options.baseUrl || DEFAULT_BASE_URL).replace(/\/+$/, ""),
|
|
183
376
|
timeoutMs: options.timeoutMs ?? 15e3,
|
|
184
377
|
fetchImpl: options.fetch ?? globalThis.fetch
|
|
@@ -189,6 +382,26 @@ var Simplr = class {
|
|
|
189
382
|
this.orders = new OrdersResource(this.cfg);
|
|
190
383
|
this.phone = new PhoneResource(this.cfg);
|
|
191
384
|
this.edge = new EdgeResource(this.cfg);
|
|
385
|
+
if (options.publicKey) {
|
|
386
|
+
this._flags = new SimplrFlags({
|
|
387
|
+
publicKey: options.publicKey,
|
|
388
|
+
baseUrl: this.cfg.baseUrl,
|
|
389
|
+
timeoutMs: this.cfg.timeoutMs,
|
|
390
|
+
fetch: this.cfg.fetchImpl
|
|
391
|
+
});
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
/**
|
|
395
|
+
* Server-side feature flags. Requires a `publicKey` in the constructor options
|
|
396
|
+
* (flag config is read with the public key). Call `simplr.flags.initialize()` once.
|
|
397
|
+
*/
|
|
398
|
+
get flags() {
|
|
399
|
+
if (!this._flags) {
|
|
400
|
+
throw new Error(
|
|
401
|
+
"Simplr.flags requires a `publicKey` \u2014 pass it to `new Simplr({ apiKey, publicKey })`."
|
|
402
|
+
);
|
|
403
|
+
}
|
|
404
|
+
return this._flags;
|
|
192
405
|
}
|
|
193
406
|
/** Run an identity/fraud check. Provide any of email, phone, device, behavior. */
|
|
194
407
|
check(input) {
|
|
@@ -202,7 +415,9 @@ var Simplr = class {
|
|
|
202
415
|
var src_default = Simplr;
|
|
203
416
|
export {
|
|
204
417
|
Simplr,
|
|
418
|
+
SimplrAdmin,
|
|
205
419
|
SimplrError,
|
|
420
|
+
SimplrFlags,
|
|
206
421
|
WebhookVerificationError,
|
|
207
422
|
constructEvent as constructWebhookEvent,
|
|
208
423
|
src_default as default,
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/errors.ts","../src/http.ts","../src/resources.ts","../src/webhooks.ts","../src/index.ts"],"sourcesContent":["/** Thrown when the Simplr API returns a non-2xx response. */\nexport class SimplrError extends Error {\n readonly status: number;\n readonly body: unknown;\n\n constructor(message: string, status: number, body: unknown) {\n super(message);\n this.name = \"SimplrError\";\n this.status = status;\n this.body = body;\n }\n}\n\n/** Thrown when a webhook signature fails verification. */\nexport class WebhookVerificationError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"WebhookVerificationError\";\n }\n}\n","import { SimplrError } from \"./errors.js\";\n\nexport interface HttpConfig {\n apiKey: string;\n baseUrl: string;\n timeoutMs: number;\n fetchImpl: typeof fetch;\n}\n\n/**\n * Internal request helper. Sends X-API-Key, applies a timeout, and unwraps the\n * API's `{ success, message, content }` envelope (returning `content`).\n */\nexport async function apiRequest<T>(\n cfg: HttpConfig,\n method: \"GET\" | \"POST\" | \"PATCH\" | \"DELETE\",\n path: string,\n body?: unknown,\n): Promise<T> {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), cfg.timeoutMs);\n try {\n const res = await cfg.fetchImpl(`${cfg.baseUrl}${path}`, {\n method,\n headers: {\n \"Content-Type\": \"application/json\",\n \"X-API-Key\": cfg.apiKey,\n },\n body: body !== undefined ? JSON.stringify(body) : undefined,\n signal: controller.signal,\n });\n\n const text = await res.text();\n let parsed: any;\n try {\n parsed = text ? JSON.parse(text) : undefined;\n } catch {\n parsed = text;\n }\n\n if (!res.ok) {\n const message =\n (parsed && (parsed.message || parsed.error)) || `Simplr API error ${res.status}`;\n throw new SimplrError(message, res.status, parsed);\n }\n\n // Unwrap the standard envelope when present.\n return (parsed && typeof parsed === \"object\" && \"content\" in parsed\n ? parsed.content\n : parsed) as T;\n } catch (err) {\n if (err instanceof SimplrError) throw err;\n if (err instanceof Error && err.name === \"AbortError\") {\n throw new SimplrError(`Request to ${path} timed out after ${cfg.timeoutMs}ms`, 0, null);\n }\n throw new SimplrError(err instanceof Error ? err.message : \"Network error\", 0, null);\n } finally {\n clearTimeout(timer);\n }\n}\n","import { apiRequest, type HttpConfig } from \"./http.js\";\nimport type {\n BulkResult,\n EdgeLogEntry,\n OrderInput,\n OrderResult,\n PhoneReportInput,\n} from \"./types.js\";\n\n/** Order fraud scoring. */\nexport class OrdersResource {\n constructor(private readonly cfg: HttpConfig) {}\n\n /** Submit a single order for fraud scoring. */\n submit(order: OrderInput): Promise<OrderResult> {\n return apiRequest(this.cfg, \"POST\", \"/v1/orders\", order);\n }\n\n /** Submit up to 100 orders at once. */\n submitBulk(orders: OrderInput[]): Promise<BulkResult<OrderResult>> {\n return apiRequest(this.cfg, \"POST\", \"/v1/orders/bulk\", { orders });\n }\n}\n\n/** Phone intelligence + outcome reporting. */\nexport class PhoneResource {\n constructor(private readonly cfg: HttpConfig) {}\n\n /** Report the real-world outcome for a phone number to improve scoring. */\n report(input: PhoneReportInput): Promise<{ success: boolean }> {\n return apiRequest(this.cfg, \"POST\", \"/v1/check/phone/report\", input);\n }\n\n /** Fetch stored risk intelligence for a phone number. */\n intelligence(phone: string): Promise<Record<string, unknown>> {\n return apiRequest(this.cfg, \"GET\", `/v1/check/phone/intelligence/${encodeURIComponent(phone)}`);\n }\n}\n\n/** Edge device registration + log ingestion. */\nexport class EdgeResource {\n constructor(private readonly cfg: HttpConfig) {}\n\n /** Register an edge device. */\n registerDevice(input: { device_id: string; name?: string; firmware?: string; [k: string]: unknown }) {\n return apiRequest(this.cfg, \"POST\", \"/v1/edge/devices/register\", input);\n }\n\n /** Report a device heartbeat with health metrics. */\n heartbeat(deviceId: string, metrics: Record<string, unknown>) {\n return apiRequest(\n this.cfg,\n \"POST\",\n `/v1/edge/devices/${encodeURIComponent(deviceId)}/heartbeat`,\n metrics,\n );\n }\n\n /** Batch-ingest structured logs for a device. */\n ingestLogs(deviceId: string, logs: EdgeLogEntry[]) {\n return apiRequest(this.cfg, \"POST\", \"/v1/edge/logs\", { device_id: deviceId, logs });\n }\n}\n","import { createHmac, timingSafeEqual } from \"node:crypto\";\nimport { WebhookVerificationError } from \"./errors.js\";\n\nexport interface VerifyOptions {\n /** Reject signatures whose timestamp is older than this many seconds (default 300). 0 disables. */\n toleranceSec?: number;\n}\n\nfunction parseHeader(header: string): { t: string; v1: string } | null {\n // Format: \"t=<unix-seconds>,v1=<hex-hmac>\"\n const parts = header.split(\",\").map((p) => p.trim());\n let t = \"\";\n let v1 = \"\";\n for (const part of parts) {\n const [k, v] = part.split(\"=\");\n if (k === \"t\") t = v;\n if (k === \"v1\") v1 = v;\n }\n return t && v1 ? { t, v1 } : null;\n}\n\nfunction expectedSignature(timestamp: string, payload: string, secret: string): string {\n return createHmac(\"sha256\", secret).update(`${timestamp}.${payload}`).digest(\"hex\");\n}\n\nfunction safeEqualHex(a: string, b: string): boolean {\n if (a.length !== b.length) return false;\n try {\n return timingSafeEqual(Buffer.from(a, \"hex\"), Buffer.from(b, \"hex\"));\n } catch {\n return false;\n }\n}\n\n/**\n * Verify a Simplr webhook signature.\n *\n * @param payload The RAW request body string (do not re-serialize parsed JSON).\n * @param header The `X-Simplr-Signature` header value (`t=…,v1=…`).\n * @param secret The webhook's signing secret.\n * @returns true if the signature is valid and within the tolerance window.\n */\nexport function verify(\n payload: string | Buffer,\n header: string,\n secret: string,\n options: VerifyOptions = {},\n): boolean {\n const tolerance = options.toleranceSec ?? 300;\n const parsed = parseHeader(header || \"\");\n if (!parsed) return false;\n\n const body = typeof payload === \"string\" ? payload : payload.toString(\"utf8\");\n const expected = expectedSignature(parsed.t, body, secret);\n if (!safeEqualHex(parsed.v1, expected)) return false;\n\n if (tolerance > 0) {\n const ts = Number(parsed.t);\n if (!Number.isFinite(ts)) return false;\n const ageSec = Math.abs(Date.now() / 1000 - ts);\n if (ageSec > tolerance) return false;\n }\n return true;\n}\n\n/**\n * Verify the signature and return the parsed event object.\n * Throws {@link WebhookVerificationError} if verification fails.\n */\nexport function constructEvent<T = { event: string; data: unknown }>(\n payload: string | Buffer,\n header: string,\n secret: string,\n options: VerifyOptions = {},\n): T {\n if (!verify(payload, header, secret, options)) {\n throw new WebhookVerificationError(\"Webhook signature verification failed\");\n }\n const body = typeof payload === \"string\" ? payload : payload.toString(\"utf8\");\n return JSON.parse(body) as T;\n}\n\nexport const webhooks = { verify, constructEvent };\n","import { apiRequest, type HttpConfig } from \"./http.js\";\nimport { EdgeResource, OrdersResource, PhoneResource } from \"./resources.js\";\nimport * as webhooks from \"./webhooks.js\";\nimport type { BulkResult, CheckInput, CheckResult, SimplrOptions } from \"./types.js\";\n\nexport { SimplrError, WebhookVerificationError } from \"./errors.js\";\nexport * from \"./types.js\";\nexport { verify as verifyWebhook, constructEvent as constructWebhookEvent } from \"./webhooks.js\";\n\nconst DEFAULT_BASE_URL = \"https://api.simplr.sh\";\n\n/**\n * Simplr server-side client.\n *\n * ```ts\n * import { Simplr } from \"@simplr-ai/node\";\n * const simplr = new Simplr({ apiKey: process.env.SIMPLR_API_KEY! });\n * const result = await simplr.check({ email: \"user@example.com\", event_type: \"signup\" });\n * ```\n */\nexport class Simplr {\n private readonly cfg: HttpConfig;\n\n readonly orders: OrdersResource;\n readonly phone: PhoneResource;\n readonly edge: EdgeResource;\n /** Webhook signature helpers (no network). */\n readonly webhooks = webhooks;\n\n constructor(options: SimplrOptions) {\n if (!options?.apiKey) throw new Error(\"Simplr: `apiKey` is required\");\n this.cfg = {\n apiKey: options.apiKey,\n baseUrl: (options.baseUrl || DEFAULT_BASE_URL).replace(/\\/+$/, \"\"),\n timeoutMs: options.timeoutMs ?? 15000,\n fetchImpl: options.fetch ?? globalThis.fetch,\n };\n if (typeof this.cfg.fetchImpl !== \"function\") {\n throw new Error(\"Simplr: no global fetch available — use Node 18+ or pass `fetch` in options\");\n }\n this.orders = new OrdersResource(this.cfg);\n this.phone = new PhoneResource(this.cfg);\n this.edge = new EdgeResource(this.cfg);\n }\n\n /** Run an identity/fraud check. Provide any of email, phone, device, behavior. */\n check(input: CheckInput): Promise<CheckResult> {\n return apiRequest(this.cfg, \"POST\", \"/v1/check\", input);\n }\n\n /** Run up to 100 checks at once. */\n checkBulk(items: CheckInput[]): Promise<BulkResult<CheckResult>> {\n return apiRequest(this.cfg, \"POST\", \"/v1/check/bulk\", { items });\n }\n}\n\nexport default Simplr;\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/errors.ts","../src/http.ts","../src/resources.ts","../src/flags.ts","../src/webhooks.ts","../src/admin.ts","../src/index.ts"],"sourcesContent":["/** Thrown when the Simplr API returns a non-2xx response. */\nexport class SimplrError extends Error {\n readonly status: number;\n readonly body: unknown;\n\n constructor(message: string, status: number, body: unknown) {\n super(message);\n this.name = \"SimplrError\";\n this.status = status;\n this.body = body;\n }\n}\n\n/** Thrown when a webhook signature fails verification. */\nexport class WebhookVerificationError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"WebhookVerificationError\";\n }\n}\n","import { SimplrError } from \"./errors.js\";\n\nexport interface HttpConfig {\n /** Auth headers to send (e.g. { \"X-API-Key\": \"sk_…\" } or { Authorization: \"Bearer …\" }). */\n authHeaders: Record<string, string>;\n baseUrl: string;\n timeoutMs: number;\n fetchImpl: typeof fetch;\n}\n\n/**\n * Internal request helper. Sends X-API-Key, applies a timeout, and unwraps the\n * API's `{ success, message, content }` envelope (returning `content`).\n */\nexport async function apiRequest<T>(\n cfg: HttpConfig,\n method: \"GET\" | \"POST\" | \"PATCH\" | \"DELETE\",\n path: string,\n body?: unknown,\n): Promise<T> {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), cfg.timeoutMs);\n try {\n const res = await cfg.fetchImpl(`${cfg.baseUrl}${path}`, {\n method,\n headers: {\n \"Content-Type\": \"application/json\",\n ...cfg.authHeaders,\n },\n body: body !== undefined ? JSON.stringify(body) : undefined,\n signal: controller.signal,\n });\n\n const text = await res.text();\n let parsed: any;\n try {\n parsed = text ? JSON.parse(text) : undefined;\n } catch {\n parsed = text;\n }\n\n if (!res.ok) {\n const message =\n (parsed && (parsed.message || parsed.error)) || `Simplr API error ${res.status}`;\n throw new SimplrError(message, res.status, parsed);\n }\n\n // Unwrap the standard envelope when present.\n return (parsed && typeof parsed === \"object\" && \"content\" in parsed\n ? parsed.content\n : parsed) as T;\n } catch (err) {\n if (err instanceof SimplrError) throw err;\n if (err instanceof Error && err.name === \"AbortError\") {\n throw new SimplrError(`Request to ${path} timed out after ${cfg.timeoutMs}ms`, 0, null);\n }\n throw new SimplrError(err instanceof Error ? err.message : \"Network error\", 0, null);\n } finally {\n clearTimeout(timer);\n }\n}\n","import { apiRequest, type HttpConfig } from \"./http.js\";\nimport type {\n BulkResult,\n EdgeLogEntry,\n OrderInput,\n OrderResult,\n PhoneReportInput,\n} from \"./types.js\";\n\n/** Order fraud scoring. */\nexport class OrdersResource {\n constructor(private readonly cfg: HttpConfig) {}\n\n /** Submit a single order for fraud scoring. */\n submit(order: OrderInput): Promise<OrderResult> {\n return apiRequest(this.cfg, \"POST\", \"/v1/orders\", order);\n }\n\n /** Submit up to 100 orders at once. */\n submitBulk(orders: OrderInput[]): Promise<BulkResult<OrderResult>> {\n return apiRequest(this.cfg, \"POST\", \"/v1/orders/bulk\", { orders });\n }\n}\n\n/** Phone intelligence + outcome reporting. */\nexport class PhoneResource {\n constructor(private readonly cfg: HttpConfig) {}\n\n /** Report the real-world outcome for a phone number to improve scoring. */\n report(input: PhoneReportInput): Promise<{ success: boolean }> {\n return apiRequest(this.cfg, \"POST\", \"/v1/check/phone/report\", input);\n }\n\n /** Fetch stored risk intelligence for a phone number. */\n intelligence(phone: string): Promise<Record<string, unknown>> {\n return apiRequest(this.cfg, \"GET\", `/v1/check/phone/intelligence/${encodeURIComponent(phone)}`);\n }\n}\n\n/** Edge device registration + log ingestion. */\nexport class EdgeResource {\n constructor(private readonly cfg: HttpConfig) {}\n\n /** Register an edge device. */\n registerDevice(input: { device_id: string; name?: string; firmware?: string; [k: string]: unknown }) {\n return apiRequest(this.cfg, \"POST\", \"/v1/edge/devices/register\", input);\n }\n\n /** Report a device heartbeat with health metrics. */\n heartbeat(deviceId: string, metrics: Record<string, unknown>) {\n return apiRequest(\n this.cfg,\n \"POST\",\n `/v1/edge/devices/${encodeURIComponent(deviceId)}/heartbeat`,\n metrics,\n );\n }\n\n /** Batch-ingest structured logs for a device. */\n ingestLogs(deviceId: string, logs: EdgeLogEntry[]) {\n return apiRequest(this.cfg, \"POST\", \"/v1/edge/logs\", { device_id: deviceId, logs });\n }\n}\n","import { apiRequest, type HttpConfig } from \"./http.js\";\n\n/**\n * MurmurHash3 (x86, 32-bit) — identical to the browser SDK so a given user\n * buckets the same way on the client and the server.\n */\nfunction murmurHash3(input: string, seed = 0): number {\n let h1 = seed;\n const c1 = 0xcc9e2d51;\n const c2 = 0x1b873593;\n for (let i = 0; i < input.length; i++) {\n let k1 = input.charCodeAt(i);\n k1 = Math.imul(k1, c1);\n k1 = (k1 << 15) | (k1 >>> 17);\n k1 = Math.imul(k1, c2);\n h1 ^= k1;\n h1 = (h1 << 13) | (h1 >>> 19);\n h1 = Math.imul(h1, 5) + 0xe6546b64;\n }\n h1 ^= input.length;\n h1 ^= h1 >>> 16;\n h1 = Math.imul(h1, 0x85ebca6b);\n h1 ^= h1 >>> 13;\n h1 = Math.imul(h1, 0xc2b2ae35);\n h1 ^= h1 >>> 16;\n return h1 >>> 0;\n}\n\nexport interface FlagRule {\n attribute: string;\n op: \"eq\" | \"neq\" | \"contains\";\n value: string;\n}\n\nexport interface FlagDefinition {\n key: string;\n enabled: boolean;\n rollout_percentage: number;\n target_user_ids: string[];\n rules: FlagRule[];\n}\n\nexport interface FlagsOptions {\n /** Public API key (pk_live_… / pk_test_…). Required — flags read uses the public key. */\n publicKey: string;\n /** API base URL. Defaults to https://api.simplr.sh. */\n baseUrl?: string;\n /** Which environment's flags to load. Defaults to the key's own environment. */\n environment?: \"live\" | \"test\";\n /** Auto-refresh interval in ms (default 60000; 0 disables). */\n refreshIntervalMs?: number;\n timeoutMs?: number;\n fetch?: typeof fetch;\n}\n\nexport interface EvalContext {\n userId?: string;\n attributes?: Record<string, unknown>;\n}\n\nfunction matchRule(rule: FlagRule, attributes: Record<string, unknown>): boolean {\n const actual = attributes[rule.attribute];\n switch (rule.op) {\n case \"eq\":\n return String(actual) === rule.value;\n case \"neq\":\n return String(actual) !== rule.value;\n case \"contains\":\n return String(actual ?? \"\").includes(rule.value);\n default:\n return false;\n }\n}\n\n/**\n * Server-side feature flags with local, deterministic evaluation.\n *\n * ```ts\n * const flags = new SimplrFlags({ publicKey: process.env.SIMPLR_PUBLIC_KEY! });\n * await flags.initialize();\n * if (flags.isEnabled(\"new-checkout\", { userId: \"user_123\" })) { ... }\n * ```\n */\nexport class SimplrFlags {\n private readonly cfg: HttpConfig;\n private readonly environment?: \"live\" | \"test\";\n private readonly refreshIntervalMs: number;\n private flags: Record<string, FlagDefinition> = {};\n private defaultUserId?: string;\n private timer: ReturnType<typeof setInterval> | null = null;\n private ready = false;\n\n constructor(options: FlagsOptions) {\n if (!options?.publicKey) throw new Error(\"SimplrFlags: `publicKey` is required\");\n this.cfg = {\n authHeaders: { \"X-API-Key\": options.publicKey },\n baseUrl: (options.baseUrl || \"https://api.simplr.sh\").replace(/\\/+$/, \"\"),\n timeoutMs: options.timeoutMs ?? 15000,\n fetchImpl: options.fetch ?? globalThis.fetch,\n };\n this.environment = options.environment;\n this.refreshIntervalMs = options.refreshIntervalMs ?? 60000;\n }\n\n /** Fetch the flag config once and start the background refresh. */\n async initialize(): Promise<void> {\n await this.refresh();\n this.ready = true;\n if (this.refreshIntervalMs > 0) {\n this.timer = setInterval(() => {\n void this.refresh();\n }, this.refreshIntervalMs);\n // Don't keep the process alive just for flag refreshes.\n (this.timer as any)?.unref?.();\n }\n }\n\n /** Set the default identifier used for bucketing when none is passed to isEnabled. */\n setUser(userId: string): void {\n this.defaultUserId = userId;\n }\n\n /** Re-fetch the flag config (counts as one billable request). */\n async refresh(): Promise<void> {\n const path = this.environment ? `/v1/flags?environment=${this.environment}` : \"/v1/flags\";\n try {\n const content = await apiRequest<{ flags: FlagDefinition[] }>(this.cfg, \"GET\", path);\n const list = content?.flags || [];\n const map: Record<string, FlagDefinition> = {};\n for (const f of list) map[f.key] = f;\n this.flags = map;\n } catch {\n // keep last-known flags on error\n }\n }\n\n /** Evaluate a flag locally. Deterministic per user; no network call. */\n isEnabled(key: string, ctx: EvalContext = {}): boolean {\n const f = this.flags[key];\n if (!f || !f.enabled) return false;\n\n const uid = ctx.userId || this.defaultUserId || \"anonymous\";\n if (f.target_user_ids?.includes(uid)) return true;\n if (ctx.attributes && f.rules?.length && f.rules.some((r) => matchRule(r, ctx.attributes!))) {\n return true;\n }\n if (f.rollout_percentage >= 100) return true;\n if (f.rollout_percentage <= 0) return false;\n return murmurHash3(`${key}:${uid}`) % 100 < f.rollout_percentage;\n }\n\n getAll(): Record<string, FlagDefinition> {\n return { ...this.flags };\n }\n\n isReady(): boolean {\n return this.ready;\n }\n\n /** Stop the background refresh timer. */\n dispose(): void {\n if (this.timer) clearInterval(this.timer);\n this.timer = null;\n }\n}\n","import { createHmac, timingSafeEqual } from \"node:crypto\";\nimport { WebhookVerificationError } from \"./errors.js\";\n\nexport interface VerifyOptions {\n /** Reject signatures whose timestamp is older than this many seconds (default 300). 0 disables. */\n toleranceSec?: number;\n}\n\nfunction parseHeader(header: string): { t: string; v1: string } | null {\n // Format: \"t=<unix-seconds>,v1=<hex-hmac>\"\n const parts = header.split(\",\").map((p) => p.trim());\n let t = \"\";\n let v1 = \"\";\n for (const part of parts) {\n const [k, v] = part.split(\"=\");\n if (k === \"t\") t = v;\n if (k === \"v1\") v1 = v;\n }\n return t && v1 ? { t, v1 } : null;\n}\n\nfunction expectedSignature(timestamp: string, payload: string, secret: string): string {\n return createHmac(\"sha256\", secret).update(`${timestamp}.${payload}`).digest(\"hex\");\n}\n\nfunction safeEqualHex(a: string, b: string): boolean {\n if (a.length !== b.length) return false;\n try {\n return timingSafeEqual(Buffer.from(a, \"hex\"), Buffer.from(b, \"hex\"));\n } catch {\n return false;\n }\n}\n\n/**\n * Verify a Simplr webhook signature.\n *\n * @param payload The RAW request body string (do not re-serialize parsed JSON).\n * @param header The `X-Simplr-Signature` header value (`t=…,v1=…`).\n * @param secret The webhook's signing secret.\n * @returns true if the signature is valid and within the tolerance window.\n */\nexport function verify(\n payload: string | Buffer,\n header: string,\n secret: string,\n options: VerifyOptions = {},\n): boolean {\n const tolerance = options.toleranceSec ?? 300;\n const parsed = parseHeader(header || \"\");\n if (!parsed) return false;\n\n const body = typeof payload === \"string\" ? payload : payload.toString(\"utf8\");\n const expected = expectedSignature(parsed.t, body, secret);\n if (!safeEqualHex(parsed.v1, expected)) return false;\n\n if (tolerance > 0) {\n const ts = Number(parsed.t);\n if (!Number.isFinite(ts)) return false;\n const ageSec = Math.abs(Date.now() / 1000 - ts);\n if (ageSec > tolerance) return false;\n }\n return true;\n}\n\n/**\n * Verify the signature and return the parsed event object.\n * Throws {@link WebhookVerificationError} if verification fails.\n */\nexport function constructEvent<T = { event: string; data: unknown }>(\n payload: string | Buffer,\n header: string,\n secret: string,\n options: VerifyOptions = {},\n): T {\n if (!verify(payload, header, secret, options)) {\n throw new WebhookVerificationError(\"Webhook signature verification failed\");\n }\n const body = typeof payload === \"string\" ? payload : payload.toString(\"utf8\");\n return JSON.parse(body) as T;\n}\n\nexport const webhooks = { verify, constructEvent };\n","import { apiRequest, type HttpConfig } from \"./http.js\";\n\nexport interface SimplrAdminOptions {\n /** Portal token (JWT) for dashboard/admin operations. */\n token: string;\n /** API base URL. Defaults to https://api.simplr.sh. */\n baseUrl?: string;\n timeoutMs?: number;\n fetch?: typeof fetch;\n}\n\nfunction qs(params: Record<string, unknown>): string {\n const entries = Object.entries(params).filter(([, v]) => v !== undefined && v !== null);\n if (!entries.length) return \"\";\n return \"?\" + entries.map(([k, v]) => `${k}=${encodeURIComponent(String(v))}`).join(\"&\");\n}\n\n/** Usage / measurement reads. */\nclass UsageApi {\n constructor(private readonly cfg: HttpConfig) {}\n /** Aggregate usage stats for an org. */\n stats(orgId: string) {\n return apiRequest(this.cfg, \"GET\", `/v1/usage/stats${qs({ org_id: orgId })}`);\n }\n /** Raw usage logs for an org. */\n logs(orgId: string, params: { page?: number; limit?: number } = {}) {\n return apiRequest(this.cfg, \"GET\", `/v1/usage/logs${qs({ org_id: orgId, ...params })}`);\n }\n /** Billing usage breakdown (per-service totals + estimated cost). */\n billing(orgId: string) {\n return apiRequest(this.cfg, \"GET\", `/v1/billing/usage${qs({ org_id: orgId })}`);\n }\n}\n\n/** Feature-flag administration (create/update/delete/history). */\nclass FlagsAdminApi {\n constructor(private readonly cfg: HttpConfig) {}\n list(orgId: string, environment?: \"live\" | \"test\") {\n return apiRequest(this.cfg, \"GET\", `/v1/feature-flags${qs({ org_id: orgId, environment })}`);\n }\n get(orgId: string, id: string) {\n return apiRequest(this.cfg, \"GET\", `/v1/feature-flags/${id}${qs({ org_id: orgId })}`);\n }\n create(orgId: string, data: Record<string, unknown>) {\n return apiRequest(this.cfg, \"POST\", \"/v1/feature-flags\", { org_id: orgId, ...data });\n }\n update(orgId: string, id: string, data: Record<string, unknown>) {\n return apiRequest(this.cfg, \"PATCH\", `/v1/feature-flags/${id}`, { org_id: orgId, ...data });\n }\n remove(orgId: string, id: string) {\n return apiRequest(this.cfg, \"DELETE\", `/v1/feature-flags/${id}${qs({ org_id: orgId })}`);\n }\n history(orgId: string, id: string, params: { limit?: number; offset?: number } = {}) {\n return apiRequest(\n this.cfg,\n \"GET\",\n `/v1/feature-flags/${id}/history${qs({ org_id: orgId, ...params })}`,\n );\n }\n}\n\n/** RUM analytics reads. */\nclass RumApi {\n constructor(private readonly cfg: HttpConfig) {}\n overview(orgId: string, params: { application_id?: string; start_date?: string; end_date?: string } = {}) {\n return apiRequest(this.cfg, \"GET\", `/v1/rum/overview${qs({ org_id: orgId, ...params })}`);\n }\n sessions(orgId: string, params: { page?: number; limit?: number; user_id?: string } = {}) {\n return apiRequest(this.cfg, \"GET\", `/v1/rum/sessions${qs({ org_id: orgId, ...params })}`);\n }\n}\n\n/**\n * Management client for dashboard/admin operations that require a portal token\n * (usage/measurement, feature-flag CRUD, RUM analytics).\n *\n * ```ts\n * const admin = new SimplrAdmin({ token: process.env.SIMPLR_PORTAL_TOKEN! });\n * const usage = await admin.usage.billing(orgId);\n * await admin.flags.create(orgId, { key: \"new-checkout\", environment: \"test\", rollout_percentage: 10 });\n * ```\n */\nexport class SimplrAdmin {\n readonly usage: UsageApi;\n readonly flags: FlagsAdminApi;\n readonly rum: RumApi;\n\n constructor(options: SimplrAdminOptions) {\n if (!options?.token) throw new Error(\"SimplrAdmin: `token` is required\");\n const cfg: HttpConfig = {\n authHeaders: { Authorization: `Bearer ${options.token}` },\n baseUrl: (options.baseUrl || \"https://api.simplr.sh\").replace(/\\/+$/, \"\"),\n timeoutMs: options.timeoutMs ?? 15000,\n fetchImpl: options.fetch ?? globalThis.fetch,\n };\n if (typeof cfg.fetchImpl !== \"function\") {\n throw new Error(\"SimplrAdmin: no global fetch available — use Node 18+ or pass `fetch`\");\n }\n this.usage = new UsageApi(cfg);\n this.flags = new FlagsAdminApi(cfg);\n this.rum = new RumApi(cfg);\n }\n}\n","import { apiRequest, type HttpConfig } from \"./http.js\";\nimport { EdgeResource, OrdersResource, PhoneResource } from \"./resources.js\";\nimport { SimplrFlags } from \"./flags.js\";\nimport * as webhooks from \"./webhooks.js\";\nimport type { BulkResult, CheckInput, CheckResult, SimplrOptions } from \"./types.js\";\n\nexport { SimplrError, WebhookVerificationError } from \"./errors.js\";\nexport * from \"./types.js\";\nexport { verify as verifyWebhook, constructEvent as constructWebhookEvent } from \"./webhooks.js\";\nexport { SimplrFlags } from \"./flags.js\";\nexport type { FlagDefinition, FlagRule, FlagsOptions, EvalContext } from \"./flags.js\";\nexport { SimplrAdmin } from \"./admin.js\";\nexport type { SimplrAdminOptions } from \"./admin.js\";\n\nconst DEFAULT_BASE_URL = \"https://api.simplr.sh\";\n\n/**\n * Simplr server-side client.\n *\n * ```ts\n * import { Simplr } from \"@simplr-ai/node\";\n * const simplr = new Simplr({ apiKey: process.env.SIMPLR_API_KEY! });\n * const result = await simplr.check({ email: \"user@example.com\", event_type: \"signup\" });\n * ```\n */\nexport class Simplr {\n private readonly cfg: HttpConfig;\n\n readonly orders: OrdersResource;\n readonly phone: PhoneResource;\n readonly edge: EdgeResource;\n /** Webhook signature helpers (no network). */\n readonly webhooks = webhooks;\n\n private readonly _flags?: SimplrFlags;\n\n constructor(options: SimplrOptions) {\n if (!options?.apiKey) throw new Error(\"Simplr: `apiKey` is required\");\n this.cfg = {\n authHeaders: { \"X-API-Key\": options.apiKey },\n baseUrl: (options.baseUrl || DEFAULT_BASE_URL).replace(/\\/+$/, \"\"),\n timeoutMs: options.timeoutMs ?? 15000,\n fetchImpl: options.fetch ?? globalThis.fetch,\n };\n if (typeof this.cfg.fetchImpl !== \"function\") {\n throw new Error(\"Simplr: no global fetch available — use Node 18+ or pass `fetch` in options\");\n }\n this.orders = new OrdersResource(this.cfg);\n this.phone = new PhoneResource(this.cfg);\n this.edge = new EdgeResource(this.cfg);\n if (options.publicKey) {\n this._flags = new SimplrFlags({\n publicKey: options.publicKey,\n baseUrl: this.cfg.baseUrl,\n timeoutMs: this.cfg.timeoutMs,\n fetch: this.cfg.fetchImpl,\n });\n }\n }\n\n /**\n * Server-side feature flags. Requires a `publicKey` in the constructor options\n * (flag config is read with the public key). Call `simplr.flags.initialize()` once.\n */\n get flags(): SimplrFlags {\n if (!this._flags) {\n throw new Error(\n \"Simplr.flags requires a `publicKey` — pass it to `new Simplr({ apiKey, publicKey })`.\",\n );\n }\n return this._flags;\n }\n\n /** Run an identity/fraud check. Provide any of email, phone, device, behavior. */\n check(input: CheckInput): Promise<CheckResult> {\n return apiRequest(this.cfg, \"POST\", \"/v1/check\", input);\n }\n\n /** Run up to 100 checks at once. */\n checkBulk(items: CheckInput[]): Promise<BulkResult<CheckResult>> {\n return apiRequest(this.cfg, \"POST\", \"/v1/check/bulk\", { items });\n }\n}\n\nexport default Simplr;\n"],"mappings":"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","names":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@simplr-ai/node",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "Simplr server-side SDK for Node.js — fraud/identity checks, order scoring, edge ingestion, and webhook signature verification.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -19,7 +19,9 @@
|
|
|
19
19
|
}
|
|
20
20
|
}
|
|
21
21
|
},
|
|
22
|
-
"files": [
|
|
22
|
+
"files": [
|
|
23
|
+
"dist"
|
|
24
|
+
],
|
|
23
25
|
"engines": {
|
|
24
26
|
"node": ">=18"
|
|
25
27
|
},
|
|
@@ -34,5 +36,14 @@
|
|
|
34
36
|
"tsup": "^8.0.0",
|
|
35
37
|
"typescript": "^5.3.0"
|
|
36
38
|
},
|
|
37
|
-
"keywords": [
|
|
39
|
+
"keywords": [
|
|
40
|
+
"simplr",
|
|
41
|
+
"simplify",
|
|
42
|
+
"fraud",
|
|
43
|
+
"identity",
|
|
44
|
+
"feature-flags",
|
|
45
|
+
"webhooks",
|
|
46
|
+
"server",
|
|
47
|
+
"node"
|
|
48
|
+
]
|
|
38
49
|
}
|