scorezilla 0.1.0-next.0 → 0.1.0-next.3
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/CHANGELOG.md +116 -0
- package/README.md +37 -4
- package/dist/errors-CUAQsaVS.d.cts +292 -0
- package/dist/errors-CUAQsaVS.d.ts +292 -0
- package/dist/index.cjs +89 -32
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -283
- package/dist/index.d.ts +3 -283
- package/dist/index.js +89 -32
- package/dist/index.js.map +1 -1
- package/dist/server.cjs +688 -3
- package/dist/server.cjs.map +1 -1
- package/dist/server.d.cts +141 -1
- package/dist/server.d.ts +141 -1
- package/dist/server.js +687 -3
- package/dist/server.js.map +1 -1
- package/package.json +26 -21
package/dist/index.js
CHANGED
|
@@ -16,24 +16,10 @@ function validateConfig(cfg) {
|
|
|
16
16
|
}
|
|
17
17
|
let auth;
|
|
18
18
|
if (hasPublic) {
|
|
19
|
-
|
|
20
|
-
if (typeof pk !== "string" || !PUBLIC_KEY_PATTERN.test(pk)) {
|
|
21
|
-
throw new Error(
|
|
22
|
-
`scorezilla: publicKey must match ${PUBLIC_KEY_PATTERN.toString()} (got: ${typeof pk === "string" ? pk.slice(0, 12) + "\u2026" : typeof pk})`
|
|
23
|
-
);
|
|
24
|
-
}
|
|
25
|
-
auth = { kind: "public", key: pk };
|
|
19
|
+
auth = { kind: "public", key: validatePublicKeyValue(cfg.publicKey) };
|
|
26
20
|
} else {
|
|
27
|
-
const
|
|
28
|
-
|
|
29
|
-
throw new Error("scorezilla: secretKey must be an object with string `id` and `secret`");
|
|
30
|
-
}
|
|
31
|
-
if (!sk.secret.startsWith(SECRET_KEY_PREFIX)) {
|
|
32
|
-
throw new Error(
|
|
33
|
-
`scorezilla: secretKey.secret must start with "${SECRET_KEY_PREFIX}" (live keys only)`
|
|
34
|
-
);
|
|
35
|
-
}
|
|
36
|
-
auth = { kind: "secret", keyId: sk.id, secret: sk.secret };
|
|
21
|
+
const resolved = validateSecretKey(cfg);
|
|
22
|
+
auth = { kind: "secret", keyId: resolved.keyId, secret: resolved.secret };
|
|
37
23
|
}
|
|
38
24
|
const baseUrlRaw = cfg.baseUrl ?? DEFAULT_BASE_URL;
|
|
39
25
|
if (typeof baseUrlRaw !== "string" || baseUrlRaw.length === 0) {
|
|
@@ -44,10 +30,40 @@ function validateConfig(cfg) {
|
|
|
44
30
|
fetch: cfg.fetch,
|
|
45
31
|
timeoutMs: cfg.timeoutMs,
|
|
46
32
|
maxRetries: cfg.maxRetries,
|
|
33
|
+
sleepImpl: cfg.sleepImpl,
|
|
47
34
|
userAgent: cfg.userAgent,
|
|
48
35
|
auth
|
|
49
36
|
};
|
|
50
37
|
}
|
|
38
|
+
function validatePublicKeyValue(pk) {
|
|
39
|
+
if (typeof pk !== "string" || !PUBLIC_KEY_PATTERN.test(pk)) {
|
|
40
|
+
const shape = typeof pk === "string" ? `string of length ${pk.length}` : typeof pk;
|
|
41
|
+
throw new Error(
|
|
42
|
+
`scorezilla: publicKey must match ${PUBLIC_KEY_PATTERN.toString()} (got: ${shape})`
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
return pk;
|
|
46
|
+
}
|
|
47
|
+
var SECRET_KEY_PATTERN = /^sk_live_([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})_[A-Za-z0-9]+$/;
|
|
48
|
+
function validateSecretKey(cfg) {
|
|
49
|
+
if (!cfg || typeof cfg !== "object") {
|
|
50
|
+
throw new Error("scorezilla/server: config must be an object with a secretKey field");
|
|
51
|
+
}
|
|
52
|
+
const sk = cfg.secretKey;
|
|
53
|
+
if (typeof sk !== "string") {
|
|
54
|
+
throw new Error(
|
|
55
|
+
`scorezilla/server: secretKey must be a single string of the shape ${SECRET_KEY_PREFIX}<keyId>_<random> (got: ${typeof sk})`
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
const match = SECRET_KEY_PATTERN.exec(sk);
|
|
59
|
+
if (!match) {
|
|
60
|
+
const shape = `string of length ${sk.length}`;
|
|
61
|
+
throw new Error(
|
|
62
|
+
`scorezilla/server: secretKey must match ${SECRET_KEY_PATTERN.toString()} (got: ${shape}). v0.1.0-next.2 switched to a single-token format \u2014 if you have a pre-next.2 pair, issue a fresh key in the dashboard to upgrade.`
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
return { keyId: match[1], secret: sk };
|
|
66
|
+
}
|
|
51
67
|
|
|
52
68
|
// src/paths.ts
|
|
53
69
|
function encodeSegment(value, label) {
|
|
@@ -87,6 +103,12 @@ function truncateMessage(raw) {
|
|
|
87
103
|
const sliceEnd = Math.max(0, MESSAGE_MAX_CHARS - TRUNCATION_SUFFIX.length);
|
|
88
104
|
return raw.slice(0, sliceEnd) + TRUNCATION_SUFFIX;
|
|
89
105
|
}
|
|
106
|
+
function truncateField(raw) {
|
|
107
|
+
if (typeof raw !== "string") return void 0;
|
|
108
|
+
if (raw.length <= MESSAGE_MAX_CHARS) return raw;
|
|
109
|
+
const sliceEnd = Math.max(0, MESSAGE_MAX_CHARS - TRUNCATION_SUFFIX.length);
|
|
110
|
+
return raw.slice(0, sliceEnd) + TRUNCATION_SUFFIX;
|
|
111
|
+
}
|
|
90
112
|
var ScorezillaError = class _ScorezillaError extends Error {
|
|
91
113
|
/** HTTP status of the response, or {@link STATUS_NETWORK_ERROR} (0) for
|
|
92
114
|
* network / abort / timeout. */
|
|
@@ -117,11 +139,11 @@ var ScorezillaError = class _ScorezillaError extends Error {
|
|
|
117
139
|
this.name = "ScorezillaError";
|
|
118
140
|
this.status = init.status;
|
|
119
141
|
this.code = init.code;
|
|
120
|
-
this.reason = init.reason;
|
|
142
|
+
this.reason = truncateField(init.reason);
|
|
121
143
|
this.retryAfter = init.retryAfter;
|
|
122
|
-
this.requestId = init.requestId;
|
|
144
|
+
this.requestId = truncateField(init.requestId);
|
|
123
145
|
this.bound = init.bound;
|
|
124
|
-
this.layer = init.layer;
|
|
146
|
+
this.layer = truncateField(init.layer);
|
|
125
147
|
this.cause = init.cause;
|
|
126
148
|
Object.setPrototypeOf(this, _ScorezillaError.prototype);
|
|
127
149
|
if (typeof Error.captureStackTrace === "function") {
|
|
@@ -251,8 +273,9 @@ function shouldRetryError(err) {
|
|
|
251
273
|
function generateIdempotencyKey() {
|
|
252
274
|
const c = globalThis.crypto;
|
|
253
275
|
if (!c || typeof c.randomUUID !== "function") {
|
|
254
|
-
throw new
|
|
255
|
-
"scorezilla: globalThis.crypto.randomUUID is unavailable. The SDK requires Node \u2265 20 or a modern browser. Check your runtime."
|
|
276
|
+
throw new ScorezillaError(
|
|
277
|
+
"scorezilla: globalThis.crypto.randomUUID is unavailable. The SDK requires Node \u2265 20 or a modern browser. Check your runtime.",
|
|
278
|
+
{ status: 0, code: "internal_error" }
|
|
256
279
|
);
|
|
257
280
|
}
|
|
258
281
|
return c.randomUUID();
|
|
@@ -307,16 +330,24 @@ async function request(opts) {
|
|
|
307
330
|
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
308
331
|
const combined = combineSignalsWithTimeout(opts.signal, timeoutMs);
|
|
309
332
|
try {
|
|
333
|
+
const bodyString = opts.body !== void 0 ? JSON.stringify(opts.body) : "";
|
|
334
|
+
const perAttemptHeaders = { ...opts.headers ?? {} };
|
|
335
|
+
if (opts.signRequest) {
|
|
336
|
+
perAttemptHeaders.Authorization = await opts.signRequest({
|
|
337
|
+
method: opts.method,
|
|
338
|
+
pathAndQuery: opts.path,
|
|
339
|
+
body: bodyString
|
|
340
|
+
});
|
|
341
|
+
}
|
|
310
342
|
const init = {
|
|
311
343
|
method: opts.method,
|
|
312
|
-
headers: buildHeaders(opts, idempotencyKey),
|
|
344
|
+
headers: buildHeaders({ ...opts, headers: perAttemptHeaders }, idempotencyKey),
|
|
313
345
|
signal: combined.signal
|
|
314
346
|
};
|
|
315
347
|
if (opts.body !== void 0) {
|
|
316
|
-
init.body =
|
|
348
|
+
init.body = bodyString;
|
|
317
349
|
}
|
|
318
350
|
const response = await fetchImpl(url, init);
|
|
319
|
-
combined.cleanup();
|
|
320
351
|
if (response.ok) {
|
|
321
352
|
return await parseJson(response);
|
|
322
353
|
}
|
|
@@ -335,7 +366,6 @@ async function request(opts) {
|
|
|
335
366
|
}
|
|
336
367
|
throw err;
|
|
337
368
|
} catch (caught) {
|
|
338
|
-
combined.cleanup();
|
|
339
369
|
if (caught instanceof ScorezillaError) {
|
|
340
370
|
if (shouldRetryError(caught) && attempt < maxRetries) {
|
|
341
371
|
const delay = nextDelay(attempt, void 0, random);
|
|
@@ -353,6 +383,8 @@ async function request(opts) {
|
|
|
353
383
|
continue;
|
|
354
384
|
}
|
|
355
385
|
throw mapped;
|
|
386
|
+
} finally {
|
|
387
|
+
combined.cleanup();
|
|
356
388
|
}
|
|
357
389
|
}
|
|
358
390
|
throw lastError ?? new ScorezillaError("Request failed after retries", {
|
|
@@ -378,16 +410,38 @@ function buildHeaders(opts, idempotencyKey) {
|
|
|
378
410
|
return headers;
|
|
379
411
|
}
|
|
380
412
|
async function parseJson(response) {
|
|
413
|
+
const requestId = response.headers.get("X-Request-Id") ?? void 0;
|
|
414
|
+
let parsed;
|
|
381
415
|
try {
|
|
382
|
-
|
|
416
|
+
parsed = await response.json();
|
|
383
417
|
} catch (cause) {
|
|
384
418
|
throw new ScorezillaError("Response body was not valid JSON", {
|
|
385
419
|
status: response.status,
|
|
386
420
|
code: "invalid_json",
|
|
387
|
-
requestId
|
|
421
|
+
requestId,
|
|
388
422
|
cause
|
|
389
423
|
});
|
|
390
424
|
}
|
|
425
|
+
if (parsed === null || typeof parsed !== "object") {
|
|
426
|
+
const observed = parsed === null ? "null" : typeof parsed;
|
|
427
|
+
throw new ScorezillaError(`Response body was not a JSON object (got ${observed})`, {
|
|
428
|
+
status: response.status,
|
|
429
|
+
code: "invalid_json",
|
|
430
|
+
requestId
|
|
431
|
+
});
|
|
432
|
+
}
|
|
433
|
+
const okField = parsed.ok;
|
|
434
|
+
if (okField !== true) {
|
|
435
|
+
throw new ScorezillaError(
|
|
436
|
+
`Response body on a 2xx is missing the \`ok: true\` discriminator (got ok=${String(okField)})`,
|
|
437
|
+
{
|
|
438
|
+
status: response.status,
|
|
439
|
+
code: "invalid_json",
|
|
440
|
+
requestId
|
|
441
|
+
}
|
|
442
|
+
);
|
|
443
|
+
}
|
|
444
|
+
return parsed;
|
|
391
445
|
}
|
|
392
446
|
async function safelyParseErrorBody(response) {
|
|
393
447
|
try {
|
|
@@ -497,7 +551,7 @@ function validateMetadata(metadata) {
|
|
|
497
551
|
}
|
|
498
552
|
var Scorezilla = class _Scorezilla {
|
|
499
553
|
/** The package version, injected at build time from `package.json`. */
|
|
500
|
-
static version = "0.1.0-next.
|
|
554
|
+
static version = "0.1.0-next.3";
|
|
501
555
|
#config;
|
|
502
556
|
#userAgent;
|
|
503
557
|
#authHeader;
|
|
@@ -662,8 +716,11 @@ var Scorezilla = class _Scorezilla {
|
|
|
662
716
|
if (opts.body !== void 0) requestOpts.body = opts.body;
|
|
663
717
|
if (this.#config.fetch !== void 0) requestOpts.fetchImpl = this.#config.fetch;
|
|
664
718
|
if (this.#config.timeoutMs !== void 0) requestOpts.timeoutMs = this.#config.timeoutMs;
|
|
665
|
-
if (this.#config.maxRetries !== void 0) {
|
|
666
|
-
requestOpts.retry = {
|
|
719
|
+
if (this.#config.maxRetries !== void 0 || this.#config.sleepImpl !== void 0) {
|
|
720
|
+
requestOpts.retry = {
|
|
721
|
+
...this.#config.maxRetries !== void 0 ? { maxRetries: this.#config.maxRetries } : {},
|
|
722
|
+
...this.#config.sleepImpl !== void 0 ? { sleepImpl: this.#config.sleepImpl } : {}
|
|
723
|
+
};
|
|
667
724
|
}
|
|
668
725
|
return request(requestOpts);
|
|
669
726
|
}
|
|
@@ -673,7 +730,7 @@ function createClient(config) {
|
|
|
673
730
|
}
|
|
674
731
|
|
|
675
732
|
// src/index.ts
|
|
676
|
-
var SDK_VERSION = "0.1.0-next.
|
|
733
|
+
var SDK_VERSION = "0.1.0-next.3";
|
|
677
734
|
|
|
678
735
|
export { SDK_VERSION, Scorezilla, ScorezillaError, createClient, detectRuntime };
|
|
679
736
|
//# sourceMappingURL=index.js.map
|