better-ship 0.25.0 → 0.27.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/dist/auth-secondary-storage-b9ptwPSB.d.ts +37 -0
- package/dist/auth-secondary-storage-b9ptwPSB.d.ts.map +1 -0
- package/dist/better-auth/secondary-storage.d.ts +1 -1
- package/dist/bin/notify-ci.d.ts +1 -0
- package/dist/bin/notify-ci.js +24 -0
- package/dist/bin/notify-ci.js.map +1 -0
- package/dist/client-Dv1Ch7yY.js +20 -0
- package/dist/client-Dv1Ch7yY.js.map +1 -0
- package/dist/cloudflare/auth-secondary-storage.d.ts +2 -36
- package/dist/cloudflare/durable-object-client.js +1 -1
- package/dist/cloudflare/durable-object-errors.js +2 -47
- package/dist/cloudflare/kv-client.js +1 -1
- package/dist/cloudflare/kv-errors.js +2 -143
- package/dist/cloudflare/r2-client.js +1 -1
- package/dist/cloudflare/r2-errors.js +2 -89
- package/dist/cloudflare/turnstile.d.ts +57 -0
- package/dist/cloudflare/turnstile.d.ts.map +1 -0
- package/dist/cloudflare/turnstile.js +191 -0
- package/dist/cloudflare/turnstile.js.map +1 -0
- package/dist/durable-object-errors-DkMFXQnK.js +48 -0
- package/dist/durable-object-errors-DkMFXQnK.js.map +1 -0
- package/dist/kv-errors-BUTpFy0t.js +144 -0
- package/dist/kv-errors-BUTpFy0t.js.map +1 -0
- package/dist/metrics-CWv37yf9.js +30 -0
- package/dist/metrics-CWv37yf9.js.map +1 -0
- package/dist/metrics-cv9P5nvk.d.ts +19 -0
- package/dist/metrics-cv9P5nvk.d.ts.map +1 -0
- package/dist/payment-service-DUYd3Itt.d.ts +52 -0
- package/dist/payment-service-DUYd3Itt.d.ts.map +1 -0
- package/dist/payment-service.error-CqF7GkNp.js +30 -0
- package/dist/payment-service.error-CqF7GkNp.js.map +1 -0
- package/dist/posthog/metrics.d.ts +2 -18
- package/dist/posthog/metrics.js +2 -29
- package/dist/posthog/server.d.ts +1 -1
- package/dist/posthog/server.js +1 -1
- package/dist/r2-errors-rk7n7rvk.js +90 -0
- package/dist/r2-errors-rk7n7rvk.js.map +1 -0
- package/dist/request-4vJEWxyZ.js +21 -0
- package/dist/request-4vJEWxyZ.js.map +1 -0
- package/dist/slack-webhook-j1FCPeu8.js +270 -0
- package/dist/slack-webhook-j1FCPeu8.js.map +1 -0
- package/dist/slack.d.ts +102 -0
- package/dist/slack.d.ts.map +1 -0
- package/dist/slack.js +3 -0
- package/dist/stripe/client.js +2 -19
- package/dist/stripe/payment-service.d.ts +2 -51
- package/dist/stripe/payment-service.error.js +2 -29
- package/dist/stripe/payment-service.js +1 -1
- package/dist/stripe/request.js +2 -20
- package/dist/stripe-fixture-yFUknTJO.js +33 -0
- package/dist/stripe-fixture-yFUknTJO.js.map +1 -0
- package/dist/testing/payment-service.d.ts +1 -1
- package/dist/testing/payment-service.js +2 -2
- package/dist/testing/stripe.js +2 -32
- package/package.json +7 -1
- package/src/infrastructure/cloudflare/turnstile/index.ts +7 -0
- package/src/infrastructure/cloudflare/turnstile/turnstile.error.ts +21 -0
- package/src/infrastructure/cloudflare/turnstile/turnstile.ts +261 -0
- package/src/infrastructure/slack/ci-message.ts +276 -0
- package/src/infrastructure/slack/index.ts +10 -0
- package/src/infrastructure/slack/notify-ci.ts +22 -0
- package/src/infrastructure/slack/slack-webhook.ts +36 -0
- package/dist/cloudflare/auth-secondary-storage.d.ts.map +0 -1
- package/dist/cloudflare/durable-object-errors.js.map +0 -1
- package/dist/cloudflare/kv-errors.js.map +0 -1
- package/dist/cloudflare/r2-errors.js.map +0 -1
- package/dist/posthog/metrics.d.ts.map +0 -1
- package/dist/posthog/metrics.js.map +0 -1
- package/dist/stripe/client.js.map +0 -1
- package/dist/stripe/payment-service.d.ts.map +0 -1
- package/dist/stripe/payment-service.error.js.map +0 -1
- package/dist/stripe/request.js.map +0 -1
- package/dist/testing/stripe.js.map +0 -1
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { Xt as AppError } from "./index-DUFS0SJ_.js";
|
|
2
|
+
import { DurableObject } from "cloudflare:workers";
|
|
3
|
+
//#region src/infrastructure/cloudflare/auth-secondary-storage.d.ts
|
|
4
|
+
/** The supplied TTL cannot produce a valid expiry timestamp. Retrying the same input cannot fix it. */
|
|
5
|
+
declare class InvalidTtlError extends AppError {
|
|
6
|
+
readonly _tag = "InvalidTtlError";
|
|
7
|
+
readonly classification = "terminal";
|
|
8
|
+
constructor();
|
|
9
|
+
}
|
|
10
|
+
/** The stored value cannot be incremented safely. The failed operation leaves it unchanged. */
|
|
11
|
+
declare class InvalidCounterError extends AppError {
|
|
12
|
+
readonly _tag = "InvalidCounterError";
|
|
13
|
+
readonly classification = "terminal";
|
|
14
|
+
constructor();
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Store one Better Auth secondary storage key per object. Export this class from the application's Worker entrypoint.
|
|
18
|
+
* Schedule cleanup at the caller's expiry; reads enforce expiry even when the alarm runs late.
|
|
19
|
+
* Requires compatibility date 2026-02-24 or later so deleteAll also removes the alarm atomically.
|
|
20
|
+
*/
|
|
21
|
+
declare class AuthSecondaryStorage extends DurableObject {
|
|
22
|
+
/** Return null for absent or expired values, even when the cleanup alarm has not run. */
|
|
23
|
+
get(): Promise<string | null>;
|
|
24
|
+
/** Replace the value and its expiry. Omit ttl to keep the value until deletion. */
|
|
25
|
+
set(value: string, ttl?: number): Promise<void>;
|
|
26
|
+
/** Remove the value and its cleanup alarm before answering. */
|
|
27
|
+
delete(): Promise<void>;
|
|
28
|
+
/** Consume the value once. Concurrent callers receive null after the first successful consumption. */
|
|
29
|
+
getAndDelete(): Promise<string | null>;
|
|
30
|
+
/** Increment atomically. Apply ttl only when creating a counter or replacing an expired counter. */
|
|
31
|
+
increment(ttl: number): Promise<number>;
|
|
32
|
+
/** Delete expired data. An old alarm must not delete a value whose expiry was extended. */
|
|
33
|
+
alarm(): Promise<void>;
|
|
34
|
+
}
|
|
35
|
+
//#endregion
|
|
36
|
+
export { InvalidCounterError as n, InvalidTtlError as r, AuthSecondaryStorage as t };
|
|
37
|
+
//# sourceMappingURL=auth-secondary-storage-b9ptwPSB.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth-secondary-storage-b9ptwPSB.d.ts","names":[],"sources":["../src/infrastructure/cloudflare/auth-secondary-storage.ts"],"mappings":";;;;cAWa,wBAAwB;WAC1B;WACA;EAET;;;cAMW,4BAA4B;WAC9B;WACA;EAET;;;;;;;cAUW,6BAA6B;;EAElC,OAAO;;EAMP,IAAI,eAAe,eAAe;;EAUlC,UAAU;;EAKV,gBAAgB;;EAQhB,UAAU,cAAc;;EAef,SAAS"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { AuthSecondaryStorage } from "../
|
|
1
|
+
import { t as AuthSecondaryStorage } from "../auth-secondary-storage-b9ptwPSB.js";
|
|
2
2
|
import { BetterAuthOptions } from "better-auth";
|
|
3
3
|
//#region src/infrastructure/better-auth/secondary-storage.d.ts
|
|
4
4
|
type SecondaryStorage = NonNullable<BetterAuthOptions['secondaryStorage']>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { a as parseCiRun, i as buildCiMessage, n as postSlackMessage } from "../slack-webhook-j1FCPeu8.js";
|
|
3
|
+
import { execFileSync } from "node:child_process";
|
|
4
|
+
|
|
5
|
+
//#region src/infrastructure/slack/notify-ci.ts
|
|
6
|
+
const webhookUrl = process.env.SLACK_WEBHOOK_URL;
|
|
7
|
+
if (webhookUrl === void 0 || webhookUrl === "") console.log("Slack notification skipped: SLACK_WEBHOOK_URL is unset.");
|
|
8
|
+
else {
|
|
9
|
+
const run = parseCiRun(process.env);
|
|
10
|
+
const git = (format) => execFileSync("git", [
|
|
11
|
+
"log",
|
|
12
|
+
"-1",
|
|
13
|
+
`--format=${format}`,
|
|
14
|
+
run.commitSha
|
|
15
|
+
], { encoding: "utf8" }).trim();
|
|
16
|
+
await postSlackMessage(webhookUrl, buildCiMessage(run, {
|
|
17
|
+
subject: git("%s"),
|
|
18
|
+
author: git("%an")
|
|
19
|
+
}));
|
|
20
|
+
console.log("Slack notification sent.");
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
//#endregion
|
|
24
|
+
//# sourceMappingURL=notify-ci.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"notify-ci.js","names":[],"sources":["../../src/infrastructure/slack/notify-ci.ts"],"sourcesContent":["#!/usr/bin/env node\n// Entry point of `better-ship-notify-ci`. Ported from suparelay and better-ship `.depot/scripts/notify-slack.sh`.\nimport { execFileSync } from 'node:child_process'\n\nimport { buildCiMessage, parseCiRun } from './ci-message.ts'\nimport { postSlackMessage } from './slack-webhook.ts'\n\nconst webhookUrl = process.env.SLACK_WEBHOOK_URL\nif (webhookUrl === undefined || webhookUrl === '') {\n console.log('Slack notification skipped: SLACK_WEBHOOK_URL is unset.')\n} else {\n const run = parseCiRun(process.env)\n const git = (format: string) =>\n execFileSync('git', ['log', '-1', `--format=${format}`, run.commitSha], {\n encoding: 'utf8',\n }).trim()\n await postSlackMessage(\n webhookUrl,\n buildCiMessage(run, { subject: git('%s'), author: git('%an') }),\n )\n console.log('Slack notification sent.')\n}\n"],"mappings":";;;;;AAOA,MAAM,aAAa,QAAQ,IAAI;AAC/B,IAAI,eAAe,UAAa,eAAe,IAC7C,QAAQ,IAAI,yDAAyD;KAChE;CACL,MAAM,MAAM,WAAW,QAAQ,GAAG;CAClC,MAAM,OAAO,WACX,aAAa,OAAO;EAAC;EAAO;EAAM,YAAY;EAAU,IAAI;CAAS,GAAG,EACtE,UAAU,OACZ,CAAC,CAAC,CAAC,KAAK;CACV,MAAM,iBACJ,YACA,eAAe,KAAK;EAAE,SAAS,IAAI,IAAI;EAAG,QAAQ,IAAI,KAAK;CAAE,CAAC,CAChE;CACA,QAAQ,IAAI,0BAA0B;AACxC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import Stripe from "stripe";
|
|
2
|
+
|
|
3
|
+
//#region src/infrastructure/stripe/client.ts
|
|
4
|
+
/** Default SDK retries; client configuration and individual requests can override this value. */
|
|
5
|
+
const STRIPE_REQUEST_OPTIONS = Object.freeze({ maxNetworkRetries: 2 });
|
|
6
|
+
/**
|
|
7
|
+
* Construct a native Stripe client with fetch transport and two SDK retries by default.
|
|
8
|
+
* Native configuration overrides these defaults. Inject the client into application services.
|
|
9
|
+
*/
|
|
10
|
+
function createStripeClient(secretKey, options = {}) {
|
|
11
|
+
return new Stripe(secretKey, {
|
|
12
|
+
httpClient: Stripe.createFetchHttpClient(),
|
|
13
|
+
...STRIPE_REQUEST_OPTIONS,
|
|
14
|
+
...options
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
//#endregion
|
|
19
|
+
export { createStripeClient as n, STRIPE_REQUEST_OPTIONS as t };
|
|
20
|
+
//# sourceMappingURL=client-Dv1Ch7yY.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client-Dv1Ch7yY.js","names":[],"sources":["../src/infrastructure/stripe/client.ts"],"sourcesContent":["import Stripe from 'stripe'\n\n/** Default SDK retries; client configuration and individual requests can override this value. */\nexport const STRIPE_REQUEST_OPTIONS = Object.freeze({ maxNetworkRetries: 2 })\n\n/**\n * Construct a native Stripe client with fetch transport and two SDK retries by default.\n * Native configuration overrides these defaults. Inject the client into application services.\n */\nexport function createStripeClient(secretKey: string, options: Stripe.StripeConfig = {}): Stripe {\n return new Stripe(secretKey, {\n httpClient: Stripe.createFetchHttpClient(),\n ...STRIPE_REQUEST_OPTIONS,\n ...options,\n })\n}\n"],"mappings":";;;;AAGA,MAAa,yBAAyB,OAAO,OAAO,EAAE,mBAAmB,EAAE,CAAC;;;;;AAM5E,SAAgB,mBAAmB,WAAmB,UAA+B,CAAC,GAAW;CAC/F,OAAO,IAAI,OAAO,WAAW;EAC3B,YAAY,OAAO,sBAAsB;EACzC,GAAG;EACH,GAAG;CACL,CAAC;AACH"}
|
|
@@ -1,36 +1,2 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
//#region src/infrastructure/cloudflare/auth-secondary-storage.d.ts
|
|
4
|
-
/** The supplied TTL cannot produce a valid expiry timestamp. Retrying the same input cannot fix it. */
|
|
5
|
-
export declare class InvalidTtlError extends AppError {
|
|
6
|
-
readonly _tag = "InvalidTtlError";
|
|
7
|
-
readonly classification = "terminal";
|
|
8
|
-
constructor();
|
|
9
|
-
}
|
|
10
|
-
/** The stored value cannot be incremented safely. The failed operation leaves it unchanged. */
|
|
11
|
-
export declare class InvalidCounterError extends AppError {
|
|
12
|
-
readonly _tag = "InvalidCounterError";
|
|
13
|
-
readonly classification = "terminal";
|
|
14
|
-
constructor();
|
|
15
|
-
}
|
|
16
|
-
/**
|
|
17
|
-
* Store one Better Auth secondary storage key per object. Export this class from the application's Worker entrypoint.
|
|
18
|
-
* Schedule cleanup at the caller's expiry; reads enforce expiry even when the alarm runs late.
|
|
19
|
-
* Requires compatibility date 2026-02-24 or later so deleteAll also removes the alarm atomically.
|
|
20
|
-
*/
|
|
21
|
-
export declare class AuthSecondaryStorage extends DurableObject {
|
|
22
|
-
/** Return null for absent or expired values, even when the cleanup alarm has not run. */
|
|
23
|
-
get(): Promise<string | null>;
|
|
24
|
-
/** Replace the value and its expiry. Omit ttl to keep the value until deletion. */
|
|
25
|
-
set(value: string, ttl?: number): Promise<void>;
|
|
26
|
-
/** Remove the value and its cleanup alarm before answering. */
|
|
27
|
-
delete(): Promise<void>;
|
|
28
|
-
/** Consume the value once. Concurrent callers receive null after the first successful consumption. */
|
|
29
|
-
getAndDelete(): Promise<string | null>;
|
|
30
|
-
/** Increment atomically. Apply ttl only when creating a counter or replacing an expired counter. */
|
|
31
|
-
increment(ttl: number): Promise<number>;
|
|
32
|
-
/** Delete expired data. An old alarm must not delete a value whose expiry was extended. */
|
|
33
|
-
alarm(): Promise<void>;
|
|
34
|
-
}
|
|
35
|
-
//#endregion
|
|
36
|
-
//# sourceMappingURL=auth-secondary-storage.d.ts.map
|
|
1
|
+
import { n as InvalidCounterError, r as InvalidTtlError, t as AuthSecondaryStorage } from "../auth-secondary-storage-b9ptwPSB.js";
|
|
2
|
+
export { AuthSecondaryStorage, InvalidCounterError, InvalidTtlError };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { b as shouldRetryFailure, v as isAbortError } from "../core-BiN6S_cm.js";
|
|
2
|
-
import { DurableObjectCallError, classifyDurableObjectError
|
|
2
|
+
import { i as isClassifiedDurableObjectError, n as DurableObjectCallError, r as classifyDurableObjectError } from "../durable-object-errors-DkMFXQnK.js";
|
|
3
3
|
import { Result } from "better-result";
|
|
4
4
|
|
|
5
5
|
//#region src/infrastructure/cloudflare/durable-object-client.ts
|
|
@@ -1,48 +1,3 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { z } from "zod";
|
|
1
|
+
import { a as isDurableObjectCallError, i as isClassifiedDurableObjectError, n as DurableObjectCallError, r as classifyDurableObjectError, t as DURABLE_OBJECT_CALL_ERROR } from "../durable-object-errors-DkMFXQnK.js";
|
|
3
2
|
|
|
4
|
-
|
|
5
|
-
/** Stable tag for a failed Durable Object call. */
|
|
6
|
-
const DURABLE_OBJECT_CALL_ERROR = "DurableObjectCallError";
|
|
7
|
-
const RemoteClassifiedErrorSchema = z.object({
|
|
8
|
-
_tag: z.string(),
|
|
9
|
-
classification: z.enum([
|
|
10
|
-
"transient",
|
|
11
|
-
"terminal",
|
|
12
|
-
"unknown"
|
|
13
|
-
]),
|
|
14
|
-
remote: z.literal(true)
|
|
15
|
-
});
|
|
16
|
-
const RemoteCallErrorSchema = RemoteClassifiedErrorSchema.extend({
|
|
17
|
-
_tag: z.literal(DURABLE_OBJECT_CALL_ERROR),
|
|
18
|
-
cause: z.unknown()
|
|
19
|
-
});
|
|
20
|
-
/** Recognize a judged local or remote error without admitting its tag to the public error table. */
|
|
21
|
-
function isClassifiedDurableObjectError(cause) {
|
|
22
|
-
return cause instanceof AppError || cause instanceof Error && RemoteClassifiedErrorSchema.safeParse(cause).success;
|
|
23
|
-
}
|
|
24
|
-
/** Classify the error itself. Its cause remains diagnostic evidence, not a second retry decision. */
|
|
25
|
-
function classifyDurableObjectError(cause) {
|
|
26
|
-
if (isAbortError(cause)) return "terminal";
|
|
27
|
-
if (isClassifiedDurableObjectError(cause)) return cause.classification;
|
|
28
|
-
if (isCloudflareOverloadedError(cause)) return "terminal";
|
|
29
|
-
if (isCloudflareRetryableError(cause) || isTransientCloudflareRuntimeError(cause) || isTransientTransportError(cause)) return "transient";
|
|
30
|
-
return "unknown";
|
|
31
|
-
}
|
|
32
|
-
/** Identify a local call error or its validated Workers RPC representation. */
|
|
33
|
-
function isDurableObjectCallError(cause) {
|
|
34
|
-
return cause instanceof DurableObjectCallError || cause instanceof Error && RemoteCallErrorSchema.safeParse(cause).success;
|
|
35
|
-
}
|
|
36
|
-
/** A call failed after retries stopped. Classification does not establish repeat safety. */
|
|
37
|
-
var DurableObjectCallError = class extends AppError {
|
|
38
|
-
_tag = DURABLE_OBJECT_CALL_ERROR;
|
|
39
|
-
classification;
|
|
40
|
-
constructor(args) {
|
|
41
|
-
super("Durable Object call failed", { cause: args.cause });
|
|
42
|
-
this.classification = classifyDurableObjectError(args.cause);
|
|
43
|
-
}
|
|
44
|
-
};
|
|
45
|
-
|
|
46
|
-
//#endregion
|
|
47
|
-
export { DURABLE_OBJECT_CALL_ERROR, DurableObjectCallError, classifyDurableObjectError, isClassifiedDurableObjectError, isDurableObjectCallError };
|
|
48
|
-
//# sourceMappingURL=durable-object-errors.js.map
|
|
3
|
+
export { DURABLE_OBJECT_CALL_ERROR, DurableObjectCallError, classifyDurableObjectError, isClassifiedDurableObjectError, isDurableObjectCallError };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { l as spreadJitterMs, s as exponentialDelayCapMs } from "../core-BiN6S_cm.js";
|
|
2
|
-
import {
|
|
2
|
+
import { i as isKVPutRateLimitError, n as decideKVRetry, t as KVError } from "../kv-errors-BUTpFy0t.js";
|
|
3
3
|
import { Result } from "better-result";
|
|
4
4
|
|
|
5
5
|
//#region src/infrastructure/cloudflare/kv-client.ts
|
|
@@ -1,144 +1,3 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { a as isRetryableKVError, i as isKVPutRateLimitError, n as decideKVRetry, o as isTerminalKVError, r as extractKVMeta, s as isTransientKVError, t as KVError } from "../kv-errors-BUTpFy0t.js";
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
/** Extract Typist's verified KV message formats, including nested causes. */
|
|
5
|
-
function extractKVMeta(cause) {
|
|
6
|
-
const message = getDeepErrorMessage(cause);
|
|
7
|
-
if (!message) return void 0;
|
|
8
|
-
const statusMatch = message.match(/\bKV\s+(GET|PUT|DELETE|LIST)\s+failed:\s+(\d{3})\b/);
|
|
9
|
-
const operation = statusMatch?.[1];
|
|
10
|
-
const status = statusMatch ? Number(statusMatch[2]) : void 0;
|
|
11
|
-
if (/Key name cannot be empty/i.test(message)) return {
|
|
12
|
-
kind: "invalid_key",
|
|
13
|
-
message,
|
|
14
|
-
status,
|
|
15
|
-
operation
|
|
16
|
-
};
|
|
17
|
-
if (/exceeds key length limit/i.test(message)) return {
|
|
18
|
-
kind: "key_too_large",
|
|
19
|
-
message,
|
|
20
|
-
status,
|
|
21
|
-
operation
|
|
22
|
-
};
|
|
23
|
-
if (/Invalid expiration_ttl/i.test(message)) return {
|
|
24
|
-
kind: "invalid_expiration_ttl",
|
|
25
|
-
message,
|
|
26
|
-
status,
|
|
27
|
-
operation
|
|
28
|
-
};
|
|
29
|
-
if (/Invalid expiration of/i.test(message)) return {
|
|
30
|
-
kind: "invalid_expiration",
|
|
31
|
-
message,
|
|
32
|
-
status,
|
|
33
|
-
operation
|
|
34
|
-
};
|
|
35
|
-
if (/Invalid cache_ttl/i.test(message)) return {
|
|
36
|
-
kind: "invalid_cache_ttl",
|
|
37
|
-
message,
|
|
38
|
-
status,
|
|
39
|
-
operation
|
|
40
|
-
};
|
|
41
|
-
if (/Invalid key_count_limit/i.test(message)) return {
|
|
42
|
-
kind: "invalid_list_limit",
|
|
43
|
-
message,
|
|
44
|
-
status,
|
|
45
|
-
operation
|
|
46
|
-
};
|
|
47
|
-
if (/value.*(too large|exceeds)|exceeds.*value/i.test(message)) return {
|
|
48
|
-
kind: "value_too_large",
|
|
49
|
-
message,
|
|
50
|
-
status,
|
|
51
|
-
operation
|
|
52
|
-
};
|
|
53
|
-
if (status === 429) return {
|
|
54
|
-
kind: "rate_limited",
|
|
55
|
-
message,
|
|
56
|
-
status,
|
|
57
|
-
operation
|
|
58
|
-
};
|
|
59
|
-
if (status !== void 0 && status >= 500) return {
|
|
60
|
-
kind: "server_error",
|
|
61
|
-
message,
|
|
62
|
-
status,
|
|
63
|
-
operation
|
|
64
|
-
};
|
|
65
|
-
if (status !== void 0 && status >= 400) return {
|
|
66
|
-
kind: "client_error",
|
|
67
|
-
message,
|
|
68
|
-
status,
|
|
69
|
-
operation
|
|
70
|
-
};
|
|
71
|
-
}
|
|
72
|
-
/** Identify recognized KV failures that another attempt cannot resolve. */
|
|
73
|
-
function isTerminalKVError(cause) {
|
|
74
|
-
const meta = extractKVMeta(cause);
|
|
75
|
-
if (!meta) return false;
|
|
76
|
-
if (meta.kind === "rate_limited" || meta.kind === "server_error") return false;
|
|
77
|
-
if (meta.status === 408) return false;
|
|
78
|
-
return true;
|
|
79
|
-
}
|
|
80
|
-
/** Identify a PUT rate limit that requires at least one second before retrying. */
|
|
81
|
-
function isKVPutRateLimitError(cause) {
|
|
82
|
-
const meta = extractKVMeta(cause);
|
|
83
|
-
return meta?.operation === "PUT" && meta.kind === "rate_limited";
|
|
84
|
-
}
|
|
85
|
-
/** Identify PUT rate limits, server failures, and request timeouts. */
|
|
86
|
-
function isTransientKVError(cause) {
|
|
87
|
-
const meta = extractKVMeta(cause);
|
|
88
|
-
if (!meta) return false;
|
|
89
|
-
return isKVPutRateLimitError(cause) || meta.kind === "server_error" || meta.status === 408;
|
|
90
|
-
}
|
|
91
|
-
/** Apply Typist's KV, overload, platform, and transport checks in their original order. */
|
|
92
|
-
function isRetryableKVError(cause) {
|
|
93
|
-
if (isTerminalKVError(cause)) return false;
|
|
94
|
-
if (isTransientKVError(cause)) return true;
|
|
95
|
-
if (isCloudflareOverloadedError(cause)) return false;
|
|
96
|
-
return isCloudflareRetryableError(cause) || isTransientTransportError(cause);
|
|
97
|
-
}
|
|
98
|
-
/** Return the existing retry decision and minimum delay in milliseconds. */
|
|
99
|
-
function decideKVRetry(cause) {
|
|
100
|
-
if (!isRetryableKVError(cause)) return { retry: false };
|
|
101
|
-
return {
|
|
102
|
-
retry: true,
|
|
103
|
-
retryAfterMs: isKVPutRateLimitError(cause) ? 1e3 : 0
|
|
104
|
-
};
|
|
105
|
-
}
|
|
106
|
-
/** A final KV failure with Typist's diagnostics and Better Ship's error classification. */
|
|
107
|
-
var KVError = class extends AppError {
|
|
108
|
-
_tag = "KVError";
|
|
109
|
-
classification;
|
|
110
|
-
retryable;
|
|
111
|
-
operation;
|
|
112
|
-
key;
|
|
113
|
-
cause;
|
|
114
|
-
kv;
|
|
115
|
-
context;
|
|
116
|
-
constructor(args) {
|
|
117
|
-
const kv = extractKVMeta(args.cause);
|
|
118
|
-
const causeMessage = getDeepErrorMessage(args.cause) || String(args.cause);
|
|
119
|
-
const keyContext = args.key === void 0 ? "" : ` for key "${args.key}"`;
|
|
120
|
-
super(`KV ${args.operation} failed${keyContext}: ${causeMessage}`, { cause: args.cause });
|
|
121
|
-
this.operation = args.operation;
|
|
122
|
-
this.key = args.key;
|
|
123
|
-
this.cause = args.cause;
|
|
124
|
-
this.kv = kv;
|
|
125
|
-
this.context = {
|
|
126
|
-
operation: args.operation,
|
|
127
|
-
key: args.key,
|
|
128
|
-
kv
|
|
129
|
-
};
|
|
130
|
-
this.retryable = isRetryableKVError(args.cause);
|
|
131
|
-
this.classification = isTerminalKVError(args.cause) ? "terminal" : this.retryable ? "transient" : "unknown";
|
|
132
|
-
}
|
|
133
|
-
};
|
|
134
|
-
function getDeepErrorMessage(cause) {
|
|
135
|
-
if (typeof cause === "string") return cause;
|
|
136
|
-
if (cause === null || cause === void 0) return "";
|
|
137
|
-
if (typeof cause === "number" || typeof cause === "boolean" || typeof cause === "bigint") return String(cause);
|
|
138
|
-
if (typeof cause !== "object") return "";
|
|
139
|
-
return `${"message" in cause && typeof cause.message === "string" ? cause.message : ""} ${"cause" in cause ? getDeepErrorMessage(cause.cause) : ""}`.trim();
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
//#endregion
|
|
143
|
-
export { KVError, decideKVRetry, extractKVMeta, isKVPutRateLimitError, isRetryableKVError, isTerminalKVError, isTransientKVError };
|
|
144
|
-
//# sourceMappingURL=kv-errors.js.map
|
|
3
|
+
export { KVError, decideKVRetry, extractKVMeta, isKVPutRateLimitError, isRetryableKVError, isTerminalKVError, isTransientKVError };
|
|
@@ -1,90 +1,3 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { z } from "zod";
|
|
1
|
+
import { n as R2JsonError, t as R2Error } from "../r2-errors-rk7n7rvk.js";
|
|
3
2
|
|
|
4
|
-
|
|
5
|
-
const R2FailureSchema = z.object({
|
|
6
|
-
code: z.number().int().positive(),
|
|
7
|
-
action: z.string().optional()
|
|
8
|
-
});
|
|
9
|
-
const classifications = /* @__PURE__ */ new Map([
|
|
10
|
-
[10001, "transient"],
|
|
11
|
-
[10043, "transient"],
|
|
12
|
-
[10054, "transient"],
|
|
13
|
-
[10058, "transient"],
|
|
14
|
-
[10013, "transient"],
|
|
15
|
-
[10002, "terminal"],
|
|
16
|
-
[10003, "terminal"],
|
|
17
|
-
[10018, "terminal"],
|
|
18
|
-
[10035, "terminal"],
|
|
19
|
-
[10042, "terminal"],
|
|
20
|
-
[10005, "terminal"],
|
|
21
|
-
[10006, "terminal"],
|
|
22
|
-
[10008, "terminal"],
|
|
23
|
-
[10009, "terminal"],
|
|
24
|
-
[10073, "terminal"],
|
|
25
|
-
[10007, "terminal"],
|
|
26
|
-
[10020, "terminal"],
|
|
27
|
-
[100100, "terminal"],
|
|
28
|
-
[10012, "terminal"],
|
|
29
|
-
[10069, "terminal"],
|
|
30
|
-
[10033, "terminal"],
|
|
31
|
-
[10014, "terminal"],
|
|
32
|
-
[10037, "terminal"],
|
|
33
|
-
[10039, "terminal"],
|
|
34
|
-
[10031, "terminal"],
|
|
35
|
-
[10011, "terminal"],
|
|
36
|
-
[10024, "terminal"],
|
|
37
|
-
[10025, "terminal"],
|
|
38
|
-
[10048, "terminal"]
|
|
39
|
-
]);
|
|
40
|
-
function extractR2Failure(cause) {
|
|
41
|
-
if (!(cause instanceof Error)) return void 0;
|
|
42
|
-
const parsed = R2FailureSchema.safeParse(cause);
|
|
43
|
-
if (parsed.success) return parsed.data;
|
|
44
|
-
const match = /\((\d{5,6})\)\s*$/.exec(cause.message);
|
|
45
|
-
return match?.[1] === void 0 ? void 0 : { code: Number(match[1]) };
|
|
46
|
-
}
|
|
47
|
-
function classifyR2Code(cause) {
|
|
48
|
-
const failure = extractR2Failure(cause);
|
|
49
|
-
return failure === void 0 ? void 0 : classifications.get(failure.code) ?? "unknown";
|
|
50
|
-
}
|
|
51
|
-
function classifyR2Error(cause) {
|
|
52
|
-
if (isAbortError(cause)) return "terminal";
|
|
53
|
-
if (cause instanceof AppError) return cause.classification;
|
|
54
|
-
return classifyBoundaryError({
|
|
55
|
-
cause,
|
|
56
|
-
classifyBoundary: classifyR2Code,
|
|
57
|
-
includeCloudflare: true
|
|
58
|
-
});
|
|
59
|
-
}
|
|
60
|
-
/** A raw binding failure after one attempt. Classification does not establish whether a mutation committed. */
|
|
61
|
-
var R2Error = class extends AppError {
|
|
62
|
-
_tag = "R2Error";
|
|
63
|
-
classification;
|
|
64
|
-
operation;
|
|
65
|
-
r2;
|
|
66
|
-
cause;
|
|
67
|
-
constructor(input) {
|
|
68
|
-
super(`R2 ${input.operation} failed`, { cause: input.cause });
|
|
69
|
-
this.operation = input.operation;
|
|
70
|
-
this.cause = input.cause;
|
|
71
|
-
this.r2 = extractR2Failure(input.cause);
|
|
72
|
-
this.classification = classifyR2Error(input.cause);
|
|
73
|
-
}
|
|
74
|
-
};
|
|
75
|
-
/** JSON serialization or syntax failed. Binding and body-read failures use R2Error. */
|
|
76
|
-
var R2JsonError = class extends AppError {
|
|
77
|
-
_tag = "R2JsonError";
|
|
78
|
-
classification = "terminal";
|
|
79
|
-
operation;
|
|
80
|
-
cause;
|
|
81
|
-
constructor(input) {
|
|
82
|
-
super(`R2 JSON ${input.operation} failed`, { cause: input.cause });
|
|
83
|
-
this.operation = input.operation;
|
|
84
|
-
this.cause = input.cause;
|
|
85
|
-
}
|
|
86
|
-
};
|
|
87
|
-
|
|
88
|
-
//#endregion
|
|
89
|
-
export { R2Error, R2JsonError };
|
|
90
|
-
//# sourceMappingURL=r2-errors.js.map
|
|
3
|
+
export { R2Error, R2JsonError };
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { Xt as AppError, Zt as FailureClassification } from "../index-DUFS0SJ_.js";
|
|
2
|
+
//#region src/infrastructure/cloudflare/turnstile/turnstile.error.d.ts
|
|
3
|
+
/**
|
|
4
|
+
* Siteverify did not produce a verdict.
|
|
5
|
+
* A rejected token is not this error. The caller logs it once.
|
|
6
|
+
*/
|
|
7
|
+
export declare class TurnstileVerificationError extends AppError {
|
|
8
|
+
readonly _tag = "TurnstileVerificationError";
|
|
9
|
+
readonly classification: FailureClassification;
|
|
10
|
+
readonly errorCodes: readonly string[];
|
|
11
|
+
constructor(args: {
|
|
12
|
+
readonly classification: FailureClassification;
|
|
13
|
+
readonly errorCodes: readonly string[];
|
|
14
|
+
readonly cause: unknown;
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
//#endregion
|
|
18
|
+
//#region src/infrastructure/cloudflare/turnstile/turnstile.d.ts
|
|
19
|
+
/** The values siteverify needs. The secret stays in the caller. */
|
|
20
|
+
type TurnstileCheck = {
|
|
21
|
+
readonly secretKey: string;
|
|
22
|
+
readonly token: string;
|
|
23
|
+
/** Visitor address from `CF-Connecting-IP`. Omit it when the request has none. */
|
|
24
|
+
readonly remoteIp?: string;
|
|
25
|
+
/** Widget action. A present, different action rejects. A missing action does not. */
|
|
26
|
+
readonly expectedAction?: string;
|
|
27
|
+
/** Allowed widget hostnames. A testing-key success skips this list. */
|
|
28
|
+
readonly expectedHostnames?: readonly string[];
|
|
29
|
+
/** UUID reused for this call's retries. Omit it and the call mints one. */
|
|
30
|
+
readonly idempotencyKey?: string;
|
|
31
|
+
};
|
|
32
|
+
/** A solved challenge, or a refusal siteverify already decided. */
|
|
33
|
+
type TurnstileVerdict = {
|
|
34
|
+
readonly _tag: 'Accepted';
|
|
35
|
+
readonly hostname: string;
|
|
36
|
+
readonly challengeTs: string;
|
|
37
|
+
readonly action?: string;
|
|
38
|
+
} | {
|
|
39
|
+
readonly _tag: 'Rejected';
|
|
40
|
+
readonly errorCodes: readonly string[];
|
|
41
|
+
};
|
|
42
|
+
/** Deadline and fetch overrides. Production calls omit this argument. */
|
|
43
|
+
type TurnstileVerifyOptions = {
|
|
44
|
+
/** Replaces global `fetch`. A test uses it for a response the testing secret cannot return. */
|
|
45
|
+
readonly fetch?: typeof fetch;
|
|
46
|
+
/** Siteverify deadline in milliseconds. The default is 10 seconds. */
|
|
47
|
+
readonly timeoutMs?: number;
|
|
48
|
+
};
|
|
49
|
+
/**
|
|
50
|
+
* Ask siteverify whether this token is a solved challenge.
|
|
51
|
+
* A rejection is a verdict. No verdict throws `TurnstileVerificationError`.
|
|
52
|
+
* A transient failure retries twice with the same idempotency key.
|
|
53
|
+
*/
|
|
54
|
+
export declare function verifyTurnstile(check: TurnstileCheck, options?: TurnstileVerifyOptions): Promise<TurnstileVerdict>;
|
|
55
|
+
//#endregion
|
|
56
|
+
export type { TurnstileCheck, TurnstileVerdict, TurnstileVerifyOptions };
|
|
57
|
+
//# sourceMappingURL=turnstile.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"turnstile.d.ts","names":[],"sources":["../../src/infrastructure/cloudflare/turnstile/turnstile.error.ts","../../src/infrastructure/cloudflare/turnstile/turnstile.ts"],"mappings":";;;;;;qBAMa,mCAAmC;WACrC;WACA,gBAAgB;WAChB;EAET,YAAY;aACD,gBAAgB;aAChB;aACA;;;;;;KCoCD;WACD;WACA;;WAEA;;WAEA;;WAEA;;WAEA;;;KAIC;WAEG;WACA;WACA;WACA;;WAGA;WACA;;;KAIH;;WAED,eAAe;;WAEf;;;;;;;wBAmBW,gBACpB,OAAO,gBACP,UAAS,yBACR,QAAQ"}
|