better-ship 0.38.0 → 0.39.1
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/better-auth/apple-client-secret.d.ts +1 -1
- package/dist/better-auth/apple-client-secret.js +4 -4
- package/dist/better-auth/apple-client-secret.js.map +1 -1
- package/dist/better-auth/auth-client.d.ts +1 -0
- package/dist/better-auth/secondary-storage.d.ts +1 -0
- package/dist/better-auth.d.ts +1 -0
- package/dist/billing/client.d.ts +1 -0
- package/dist/cloudflare/durable-object-client.d.ts +1 -0
- package/dist/cloudflare/durable-object-errors.d.ts +1 -0
- package/dist/cloudflare.d.ts.map +1 -1
- package/dist/postgres.d.ts.map +1 -1
- package/dist/stripe/client.d.ts.map +1 -1
- package/dist/stripe/event-map.d.ts +1 -0
- package/dist/testing/stripe.d.ts +1 -0
- package/package.json +47 -41
- package/src/infrastructure/better-auth/apple-client-secret.ts +4 -4
|
@@ -21,7 +21,7 @@ export declare class AppleClientSecretError extends AppError {
|
|
|
21
21
|
/**
|
|
22
22
|
* Sign Apple's six-month client secret synchronously, so Better Auth options can be built without awaiting it.
|
|
23
23
|
* Signing uses `node:crypto` as Typist does, so the Worker needs the `nodejs_compat` flag.
|
|
24
|
-
* Invalid private keys return an empty secret and log once per isolate, as in Typist.
|
|
24
|
+
* Invalid private keys return an empty secret and log once per key ID in each isolate, as in Typist.
|
|
25
25
|
*/
|
|
26
26
|
export declare function generateAppleClientSecret(config: AppleKeyConfig): string;
|
|
27
27
|
//#endregion
|
|
@@ -4,7 +4,7 @@ import { createPrivateKey, sign } from "node:crypto";
|
|
|
4
4
|
|
|
5
5
|
//#region src/infrastructure/better-auth/apple-client-secret.ts
|
|
6
6
|
const logger = createLogger("auth");
|
|
7
|
-
|
|
7
|
+
const loggedInvalidKeyIds = /* @__PURE__ */ new Set();
|
|
8
8
|
/**
|
|
9
9
|
* Apple caps `exp` at 15,777,000 seconds after `iat`; 180 days stays under it. Source:
|
|
10
10
|
* https://developer.apple.com/documentation/accountorganizationaldatasharing/creating-a-client-secret
|
|
@@ -29,15 +29,15 @@ function base64UrlJson(segment) {
|
|
|
29
29
|
/**
|
|
30
30
|
* Sign Apple's six-month client secret synchronously, so Better Auth options can be built without awaiting it.
|
|
31
31
|
* Signing uses `node:crypto` as Typist does, so the Worker needs the `nodejs_compat` flag.
|
|
32
|
-
* Invalid private keys return an empty secret and log once per isolate, as in Typist.
|
|
32
|
+
* Invalid private keys return an empty secret and log once per key ID in each isolate, as in Typist.
|
|
33
33
|
*/
|
|
34
34
|
function generateAppleClientSecret(config) {
|
|
35
35
|
const key = config.applePrivateKey.replace(/\\n/g, "\n");
|
|
36
36
|
try {
|
|
37
37
|
createPrivateKey(key);
|
|
38
38
|
} catch (error) {
|
|
39
|
-
if (!
|
|
40
|
-
|
|
39
|
+
if (!loggedInvalidKeyIds.has(config.appleKeyId)) {
|
|
40
|
+
loggedInvalidKeyIds.add(config.appleKeyId);
|
|
41
41
|
logger.error("apple_private_key_invalid", {
|
|
42
42
|
error,
|
|
43
43
|
keyId: config.appleKeyId
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"apple-client-secret.js","names":[],"sources":["../../src/infrastructure/better-auth/apple-client-secret.ts"],"sourcesContent":["import { Buffer } from 'node:buffer'\nimport { createPrivateKey, sign } from 'node:crypto'\n\nimport { AppError, createLogger } from '@/core'\n\nconst logger = createLogger('auth')\n// Typist reports an invalid key once per isolate because session checks repeatedly construct auth options.\
|
|
1
|
+
{"version":3,"file":"apple-client-secret.js","names":[],"sources":["../../src/infrastructure/better-auth/apple-client-secret.ts"],"sourcesContent":["import { Buffer } from 'node:buffer'\nimport { createPrivateKey, sign } from 'node:crypto'\n\nimport { AppError, createLogger } from '@/core'\n\nconst logger = createLogger('auth')\n// Typist reports an invalid key once per isolate because session checks repeatedly construct auth options.\nconst loggedInvalidKeyIds = new Set<string>()\n/**\n * Apple caps `exp` at 15,777,000 seconds after `iat`; 180 days stays under it. Source:\n * https://developer.apple.com/documentation/accountorganizationaldatasharing/creating-a-client-secret\n */\nconst SECRET_LIFETIME_SECONDS = 180 * 24 * 60 * 60\n\n/**\n * Apple's issuer and OAuth callback origin, and the `aud` claim of the client secret. Include it in\n * trustedOrigins when enabling Apple. Source: the same Apple page as `SECRET_LIFETIME_SECONDS`.\n */\nexport const APPLE_ORIGIN = 'https://appleid.apple.com'\n\n/** Apple credentials used to sign a client secret. Ported from Porte's apple-client-secret.ts. */\nexport type AppleKeyConfig = {\n readonly appleClientId: string\n readonly appleTeamId: string\n readonly appleKeyId: string\n readonly applePrivateKey: string\n}\n\n/** Apple signing failed. The application's error boundary owns reporting. */\nexport class AppleClientSecretError extends AppError {\n readonly _tag = 'AppleClientSecretError'\n readonly classification = 'terminal'\n\n constructor(cause: unknown) {\n super('Apple client secret signing failed', { cause })\n }\n}\n\n/** One JWS segment before encoding: the protected header or the claims. */\ntype JwsSegment = Readonly<Record<string, string | number>>\n\nfunction base64UrlJson(segment: JwsSegment): string {\n return Buffer.from(JSON.stringify(segment)).toString('base64url')\n}\n\n/**\n * Sign Apple's six-month client secret synchronously, so Better Auth options can be built without awaiting it.\n * Signing uses `node:crypto` as Typist does, so the Worker needs the `nodejs_compat` flag.\n * Invalid private keys return an empty secret and log once per key ID in each isolate, as in Typist.\n */\nexport function generateAppleClientSecret(config: AppleKeyConfig): string {\n const key = config.applePrivateKey.replace(/\\\\n/g, '\\n')\n // Validation only: workerd's sign() takes the PEM string, not the KeyObject.\n try {\n createPrivateKey(key)\n } catch (error) {\n if (!loggedInvalidKeyIds.has(config.appleKeyId)) {\n loggedInvalidKeyIds.add(config.appleKeyId)\n logger.error('apple_private_key_invalid', { error, keyId: config.appleKeyId })\n }\n return ''\n }\n const issuedAt = Math.floor(Date.now() / 1000)\n const header = base64UrlJson({ alg: 'ES256', kid: config.appleKeyId })\n const claims = base64UrlJson({\n iss: config.appleTeamId,\n sub: config.appleClientId,\n aud: APPLE_ORIGIN,\n iat: issuedAt,\n exp: issuedAt + SECRET_LIFETIME_SECONDS,\n })\n const input = `${header}.${claims}`\n try {\n // A JWS carries the raw r||s signature; OpenSSL emits DER unless told otherwise.\n const signature = sign('sha256', Buffer.from(input), { key, dsaEncoding: 'ieee-p1363' })\n // TypeScript 7 types the returned buffer without an encoding parameter on toString.\n return `${input}.${Buffer.from(signature).toString('base64url')}`\n } catch (cause) {\n throw new AppleClientSecretError(cause)\n }\n}\n"],"mappings":";;;;;AAKA,MAAM,SAAS,aAAa,MAAM;AAElC,MAAM,sCAAsB,IAAI,IAAY;;;;;AAK5C,MAAM,0BAA0B;;;;;AAMhC,MAAa,eAAe;;AAW5B,IAAa,yBAAb,cAA4C,SAAS;CACnD,AAAS,OAAO;CAChB,AAAS,iBAAiB;CAE1B,YAAY,OAAgB;EAC1B,MAAM,sCAAsC,EAAE,MAAM,CAAC;CACvD;AACF;AAKA,SAAS,cAAc,SAA6B;CAClD,OAAO,OAAO,KAAK,KAAK,UAAU,OAAO,CAAC,CAAC,CAAC,SAAS,WAAW;AAClE;;;;;;AAOA,SAAgB,0BAA0B,QAAgC;CACxE,MAAM,MAAM,OAAO,gBAAgB,QAAQ,QAAQ,IAAI;CAEvD,IAAI;EACF,iBAAiB,GAAG;CACtB,SAAS,OAAO;EACd,IAAI,CAAC,oBAAoB,IAAI,OAAO,UAAU,GAAG;GAC/C,oBAAoB,IAAI,OAAO,UAAU;GACzC,OAAO,MAAM,6BAA6B;IAAE;IAAO,OAAO,OAAO;GAAW,CAAC;EAC/E;EACA,OAAO;CACT;CACA,MAAM,WAAW,KAAK,MAAM,KAAK,IAAI,IAAI,GAAI;CAS7C,MAAM,QAAQ,GARC,cAAc;EAAE,KAAK;EAAS,KAAK,OAAO;CAAW,CAQ9C,EAAE,GAPT,cAAc;EAC3B,KAAK,OAAO;EACZ,KAAK,OAAO;EACZ,KAAK;EACL,KAAK;EACL,KAAK,WAAW;CAClB,CACgC;CAChC,IAAI;EAEF,MAAM,YAAY,KAAK,UAAU,OAAO,KAAK,KAAK,GAAG;GAAE;GAAK,aAAa;EAAa,CAAC;EAEvF,OAAO,GAAG,MAAM,GAAG,OAAO,KAAK,SAAS,CAAC,CAAC,SAAS,WAAW;CAChE,SAAS,OAAO;EACd,MAAM,IAAI,uBAAuB,KAAK;CACxC;AACF"}
|
|
@@ -8,4 +8,5 @@ type SecondaryStorage = NonNullable<BetterAuthOptions['secondaryStorage']>;
|
|
|
8
8
|
*/
|
|
9
9
|
export declare function createAuthSecondaryStorage(binding: Pick<DurableObjectNamespace<AuthSecondaryStorage>, 'getByName'>): SecondaryStorage;
|
|
10
10
|
//#endregion
|
|
11
|
+
export {};
|
|
11
12
|
//# sourceMappingURL=secondary-storage.d.ts.map
|
package/dist/better-auth.d.ts
CHANGED
package/dist/billing/client.d.ts
CHANGED
package/dist/cloudflare.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cloudflare.d.ts","names":[],"sources":["../src/infrastructure/cloudflare/d1-database-types.ts","../src/infrastructure/cloudflare/base-d1-repository.ts","../src/infrastructure/cloudflare/classify-d1-error.ts","../src/infrastructure/cloudflare/d1-message-store.ts","../src/infrastructure/cloudflare/d1-schema.ts","../src/infrastructure/cloudflare/d1-batch-transaction.ts","../src/infrastructure/cloudflare/d1-database-execution.ts","../src/infrastructure/cloudflare/d1-outbox-repository.ts"],"mappings":";;;;;;;KAKY,eAAe;;KAGf,KAAK,eAAe,iBAAiB,kBAAkB;;KAGvD,SAAS,eAAe,iBAAiB,KACnD,KAAK;;KAKK,KAAK,eAAe;WACrB,IAAI,KAAK;;;;;UCRH;EACf,iBAAiB,cAAc;EAC/B;;;;;;8BAOoB,iBAAiB,eAAe;qBACrB,IAAI,KAAK;EAAxC,YAA+B,IAAI,KAAK;;YAG9B,MAAM,WAAW;;YAKjB,KAAK,GAAG,mBAAmB,aAAa,YAAY,KAAK,QAAQ;;YAKjE,eAAe,WAAW;;;;;;;;wBCVtB,gBAAgB,gBAAgB,qBAAyB;;;;qBCb5D,eAAe,eAAe,uBACjC,iBAAiB,mBACd;EAEL,MAAM,WAAW,YAAY;EAc7B,cAAc,QAAQ,cAAc,eAAe;;;;;qBCtB9C,qDAAiB
|
|
1
|
+
{"version":3,"file":"cloudflare.d.ts","names":[],"sources":["../src/infrastructure/cloudflare/d1-database-types.ts","../src/infrastructure/cloudflare/base-d1-repository.ts","../src/infrastructure/cloudflare/classify-d1-error.ts","../src/infrastructure/cloudflare/d1-message-store.ts","../src/infrastructure/cloudflare/d1-schema.ts","../src/infrastructure/cloudflare/d1-batch-transaction.ts","../src/infrastructure/cloudflare/d1-database-execution.ts","../src/infrastructure/cloudflare/d1-outbox-repository.ts"],"mappings":";;;;;;;KAKY,eAAe;;KAGf,KAAK,eAAe,iBAAiB,kBAAkB;;KAGvD,SAAS,eAAe,iBAAiB,KACnD,KAAK;;KAKK,KAAK,eAAe;WACrB,IAAI,KAAK;;;;;UCRH;EACf,iBAAiB,cAAc;EAC/B;;;;;;8BAOoB,iBAAiB,eAAe;qBACrB,IAAI,KAAK;EAAxC,YAA+B,IAAI,KAAK;;YAG9B,MAAM,WAAW;;YAKjB,KAAK,GAAG,mBAAmB,aAAa,YAAY,KAAK,QAAQ;;YAKjE,eAAe,WAAW;;;;;;;;wBCVtB,gBAAgB,gBAAgB,qBAAyB;;;;qBCb5D,eAAe,eAAe,uBACjC,iBAAiB,mBACd;EAEL,MAAM,WAAW,YAAY;EAc7B,cAAc,QAAQ,cAAc,eAAe;;;;;qBCtB9C,qDAAiB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;qBAYjB,iDAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;qBCPb,mBAAmB,eAAe,0BAA0B,aACvE,KAAK;mBAEwB;EAA7B,YAA6B,IAAI,KAAK;EAEhC,YAAY,GAAG,OAAO,IAAI,KAAK,YAAY,QAAQ,KAAK,QAAQ;;;;;;;;wBCNlD,gBAAgB,GACpC,mBACA,YAAY,YAAY,IACxB;WAAoB;IACnB,QAAQ;;;;;;;qBCIE,mBAAmB,eAAe,0BAA0B;mBAIpD;mBAEA;mBALF;EAEjB,YACmB,IAAI,KAAK,SAC1B,UAAS,yBACQ,YAAW;;EAMxB,aAAa,oBAAoB,QAAQ;;EAmDzC,cAAc,OAAO,aAAa,UAAU,cAAc,iBAAiB;;EAgB3E,aAAa,OAAO,aAAa,UAAU,cAAc,iBAAiB;;EA6B1E,WACJ,OAAO,aACP,UAAU,cAAc,gBACxB,QAAQ,kBACR,uBACC;;EAqBG,sBAAsB,QAAQ,MAAM,oBAAoB;;EAqBxD,mBAAmB,QAAQ,MAAM,oBAAoB;;EAqBrD,qBAAqB,QAAQ,MAAM,oBAAoB"}
|
package/dist/postgres.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"postgres.d.ts","names":[],"sources":["../src/infrastructure/postgres/postgres-database-types.ts","../src/infrastructure/postgres/base-postgres-repository.ts","../src/infrastructure/postgres/postgres-message-store.ts","../src/infrastructure/postgres/postgres-schema.ts","../src/infrastructure/postgres/postgres-transaction.ts","../src/infrastructure/postgres/postgres-client.ts","../src/infrastructure/postgres/statement-outside-transaction.error.ts","../src/infrastructure/postgres/postgres-database-execution.ts","../src/infrastructure/postgres/classify-postgres-error.ts","../src/infrastructure/postgres/postgres-outbox-repository.ts"],"mappings":";;;;;;;;KAOY,qBAAqB;;KAGrB,WAAW,eAAe,iBAAiB,eAAe;;KAG1D,eAAe,eAAe,iBAAiB,KACzD,WAAW;;KAKD,sBAAsB,eAAe,iBAAiB,kBAChE,QACA,2BAA2B;;KAIjB,WAAW,eAAe;WAC3B,IAAI,sBAAsB;;;;;UClBpB;EACf,iBAAiB,cAAc;EAC/B;;;8BAIoB,uBAAuB,eAAe;qBAC3B,IAAI,sBAAsB;EAAzD,YAA+B,IAAI,sBAAsB;;YAG/C,KAAK,GAAG,mBAAmB,aAAa,YAAY,KAAK,QAAQ;;YAKjE,eAAe,WAAW;;;;;qBCfzB,qBAAqB,eAAe,0BAA0B;mBAC5C;EAA7B,YAA6B,IAAI,sBAAsB;EAEjD,MAAM,WAAW,YAAY;EAU7B,cAAc,QAAQ,cAAc,eAAe;;;;;qBCf9C,iDAAiB
|
|
1
|
+
{"version":3,"file":"postgres.d.ts","names":[],"sources":["../src/infrastructure/postgres/postgres-database-types.ts","../src/infrastructure/postgres/base-postgres-repository.ts","../src/infrastructure/postgres/postgres-message-store.ts","../src/infrastructure/postgres/postgres-schema.ts","../src/infrastructure/postgres/postgres-transaction.ts","../src/infrastructure/postgres/postgres-client.ts","../src/infrastructure/postgres/statement-outside-transaction.error.ts","../src/infrastructure/postgres/postgres-database-execution.ts","../src/infrastructure/postgres/classify-postgres-error.ts","../src/infrastructure/postgres/postgres-outbox-repository.ts"],"mappings":";;;;;;;;KAOY,qBAAqB;;KAGrB,WAAW,eAAe,iBAAiB,eAAe;;KAG1D,eAAe,eAAe,iBAAiB,KACzD,WAAW;;KAKD,sBAAsB,eAAe,iBAAiB,kBAChE,QACA,2BAA2B;;KAIjB,WAAW,eAAe;WAC3B,IAAI,sBAAsB;;;;;UClBpB;EACf,iBAAiB,cAAc;EAC/B;;;8BAIoB,uBAAuB,eAAe;qBAC3B,IAAI,sBAAsB;EAAzD,YAA+B,IAAI,sBAAsB;;YAG/C,KAAK,GAAG,mBAAmB,aAAa,YAAY,KAAK,QAAQ;;YAKjE,eAAe,WAAW;;;;;qBCfzB,qBAAqB,eAAe,0BAA0B;mBAC5C;EAA7B,YAA6B,IAAI,sBAAsB;EAEjD,MAAM,WAAW,YAAY;EAU7B,cAAc,QAAQ,cAAc,eAAe;;;;;qBCf9C,iDAAiB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;qBAMjB,6CAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;qBCAb,oBAAoB,eAAe,0BAA0B,aACxE,WAAW;mBAEkB;EAA7B,YAA6B,IAAI,WAAW;EAE5C,YAAY,GAAG,OAAO,IAAI,WAAW,YAAY,QAAQ,KAAK,QAAQ;;;;;;;;;;;;wBCFxD,gBAAgB,eAAe,eAC7C,0BACA,QAAQ,QACR,UAAU;EAqBR,wCAAE,eAAA;;;;EAEF,aAAK;;;;;;;;qBCnCI,yCAAyC;WAC3C;WACA;EAET;;;;;;;;;;wBCMoB,gBAAgB,GACpC,mBACA,YAAY,YAAY,IACxB;WAAoB;IACnB,QAAQ;;;;wBCkBK,sBACd,gBACA,oBACC;;;;;;;qBCvBU,oCAAoC;mBAI5B;mBAEA;mBALF;EAEjB,YACmB,IAAI,WAAW,gBAChC,UAAS,yBACQ,YAAW;;EAMxB,aAAa,oBAAoB,QAAQ;;EAoDzC,cAAc,OAAO,aAAa,UAAU,cAAc,iBAAiB;;EAmB3E,aAAa,OAAO,aAAa,UAAU,cAAc,iBAAiB;;EAwB1E,WACJ,OAAO,aACP,UAAU,cAAc,gBACxB,QAAQ,kBACR,uBACC;;EAwBG,sBAAsB,QAAQ,MAAM,oBAAoB;;EAqBxD,mBAAmB,QAAQ,MAAM,oBAAoB;;EAqBrD,qBAAqB,QAAQ,MAAM,oBAAoB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.d.ts","names":[],"sources":["../../src/infrastructure/stripe/client.ts"],"mappings":";;;qBAGa,wBAAsB
|
|
1
|
+
{"version":3,"file":"client.d.ts","names":[],"sources":["../../src/infrastructure/stripe/client.ts"],"mappings":";;;qBAGa,wBAAsB;;;;;;;wBAMnB,mBAAmB,mBAAmB,UAAS,OAAO,eAAoB"}
|
|
@@ -11,4 +11,5 @@ export declare function stripeEventMap<T>(map: { [K in Stripe.Event['type']]?: (
|
|
|
11
11
|
/** Identify one Stripe event delivery; different events for one payment retain different IDs. */
|
|
12
12
|
export declare function stripeEventId(event: Stripe.Event): string;
|
|
13
13
|
//#endregion
|
|
14
|
+
export {};
|
|
14
15
|
//# sourceMappingURL=event-map.d.ts.map
|
package/dist/testing/stripe.d.ts
CHANGED
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://www.schemastore.org/package.json",
|
|
3
3
|
"name": "better-ship",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.39.1",
|
|
5
5
|
"description": "Foundation for applications on Cloudflare Workers: logger, errors, message bus, infrastructure adapters, and UI primitives",
|
|
6
6
|
"license": "Apache-2.0",
|
|
7
7
|
"repository": {
|
|
@@ -79,64 +79,68 @@
|
|
|
79
79
|
"dependencies": {
|
|
80
80
|
"better-result": "^3.0.1",
|
|
81
81
|
"http-status-codes": "^2.3.0",
|
|
82
|
-
"uuid": "^14.0.
|
|
83
|
-
"zod": "^4.6.
|
|
82
|
+
"uuid": "^14.0.3",
|
|
83
|
+
"zod": "^4.6.7"
|
|
84
84
|
},
|
|
85
85
|
"devDependencies": {
|
|
86
|
-
"@better-auth/stripe": "^1.7.
|
|
87
|
-
"@cloudflare/vitest-plugin": "^1.
|
|
88
|
-
"@cloudflare/workers-types": "5.
|
|
89
|
-
"@
|
|
90
|
-
"@
|
|
86
|
+
"@better-auth/stripe": "^1.7.10",
|
|
87
|
+
"@cloudflare/vitest-plugin": "^1.4.4",
|
|
88
|
+
"@cloudflare/workers-types": "5.20261012.1",
|
|
89
|
+
"@fast-check/vitest": "^0.5.0",
|
|
90
|
+
"@mdn/browser-compat-data": "^8.1.6",
|
|
91
|
+
"@oxlint/plugins": "^1.88.0",
|
|
91
92
|
"@posthog/react": "^1.11.3",
|
|
92
|
-
"@sentry/cloudflare": "^11.
|
|
93
|
-
"@sentry/tanstackstart-react": "^11.
|
|
93
|
+
"@sentry/cloudflare": "^11.8.0",
|
|
94
|
+
"@sentry/tanstackstart-react": "^11.8.0",
|
|
94
95
|
"@tailwindcss/node": "^4.3.3",
|
|
95
96
|
"@tanstack/react-form": "^1.33.5",
|
|
96
|
-
"@tanstack/react-query": "^5.104.
|
|
97
|
-
"@tanstack/react-router": "^1.170.
|
|
98
|
-
"@tanstack/react-start": "^1.
|
|
99
|
-
"@tanstack/start-client-core": "^1.170.
|
|
100
|
-
"@tanstack/start-storage-context": "^1.167.
|
|
101
|
-
"@types/node": "^26.6.
|
|
97
|
+
"@tanstack/react-query": "^5.104.3",
|
|
98
|
+
"@tanstack/react-router": "^1.170.44",
|
|
99
|
+
"@tanstack/react-start": "^1.169.2",
|
|
100
|
+
"@tanstack/start-client-core": "^1.170.37",
|
|
101
|
+
"@tanstack/start-storage-context": "^1.167.39",
|
|
102
|
+
"@types/node": "^26.6.5",
|
|
102
103
|
"@types/pg": "^8.23.1",
|
|
103
104
|
"@types/react": "^19.3.0",
|
|
104
|
-
"@vitest/browser-playwright": "^
|
|
105
|
-
"
|
|
106
|
-
"
|
|
105
|
+
"@vitest/browser-playwright": "^5.0.5",
|
|
106
|
+
"@vitest/coverage-istanbul": "^5.0.5",
|
|
107
|
+
"auth": "^1.7.10",
|
|
108
|
+
"better-auth": "^1.7.10",
|
|
107
109
|
"browserslist": "^4.29.3",
|
|
108
110
|
"drizzle-kit": "^0.31.11",
|
|
109
|
-
"drizzle-orm": "^0.45.
|
|
111
|
+
"drizzle-orm": "^0.45.4",
|
|
112
|
+
"fast-check": "^4.10.2",
|
|
113
|
+
"msw": "^3.0.3",
|
|
110
114
|
"pg": "^8.23.1",
|
|
111
|
-
"playwright": "^1.
|
|
112
|
-
"posthog-js": "^1.
|
|
113
|
-
"posthog-node": "^5.
|
|
114
|
-
"react": "^19.3.
|
|
115
|
-
"resend": "^6.
|
|
115
|
+
"playwright": "^1.64.1",
|
|
116
|
+
"posthog-js": "^1.438.12",
|
|
117
|
+
"posthog-node": "^5.56.1",
|
|
118
|
+
"react": "^19.3.1",
|
|
119
|
+
"resend": "^6.33.0",
|
|
116
120
|
"standardwebhooks": "^1.1.1",
|
|
117
121
|
"stripe": "^22.6.2",
|
|
118
|
-
"tsdown": "^0.23.
|
|
122
|
+
"tsdown": "^0.23.1",
|
|
119
123
|
"typescript": "^7.0.2",
|
|
120
|
-
"vitest": "^
|
|
121
|
-
"wrangler": "^4.
|
|
124
|
+
"vitest": "^5.0.5",
|
|
125
|
+
"wrangler": "^4.151.1"
|
|
122
126
|
},
|
|
123
127
|
"peerDependencies": {
|
|
124
|
-
"@better-auth/stripe": "^1.7.
|
|
125
|
-
"@mdn/browser-compat-data": "^8.1.
|
|
126
|
-
"@oxlint/plugins": "^1.
|
|
128
|
+
"@better-auth/stripe": "^1.7.10",
|
|
129
|
+
"@mdn/browser-compat-data": "^8.1.6",
|
|
130
|
+
"@oxlint/plugins": "^1.88.0",
|
|
127
131
|
"@posthog/react": "^1.11.3",
|
|
128
|
-
"@sentry/cloudflare": "^11.
|
|
129
|
-
"@sentry/tanstackstart-react": "^11.
|
|
130
|
-
"@tanstack/react-router": "^1.170.
|
|
131
|
-
"@tanstack/react-start": "^1.
|
|
132
|
-
"better-auth": "^1.7.
|
|
132
|
+
"@sentry/cloudflare": "^11.8.0",
|
|
133
|
+
"@sentry/tanstackstart-react": "^11.8.0",
|
|
134
|
+
"@tanstack/react-router": "^1.170.44",
|
|
135
|
+
"@tanstack/react-start": "^1.169.2",
|
|
136
|
+
"better-auth": "^1.7.10",
|
|
133
137
|
"browserslist": "^4.29.3",
|
|
134
|
-
"drizzle-orm": "^0.45.
|
|
138
|
+
"drizzle-orm": "^0.45.4",
|
|
135
139
|
"pg": "^8.23.1",
|
|
136
|
-
"posthog-js": "^1.
|
|
137
|
-
"posthog-node": "^5.
|
|
138
|
-
"react": "^19.3.
|
|
139
|
-
"resend": "^6.
|
|
140
|
+
"posthog-js": "^1.438.12",
|
|
141
|
+
"posthog-node": "^5.56.1",
|
|
142
|
+
"react": "^19.3.1",
|
|
143
|
+
"resend": "^6.33.0",
|
|
140
144
|
"stripe": "^22.6.2"
|
|
141
145
|
},
|
|
142
146
|
"peerDependenciesMeta": {
|
|
@@ -202,6 +206,8 @@
|
|
|
202
206
|
"lint": "oxlint . --quiet",
|
|
203
207
|
"lint:fix": "oxlint . --fix --quiet",
|
|
204
208
|
"test": "vitest run",
|
|
209
|
+
"test:live": "TEST_LIVE=1 vitest run --tags-filter=live",
|
|
210
|
+
"test:coverage": "vitest run --coverage.enabled",
|
|
205
211
|
"cf-typegen": "wrangler types tests/infrastructure/cloudflare/worker-configuration.d.ts --config tests/infrastructure/cloudflare/wrangler.jsonc --include-runtime=false",
|
|
206
212
|
"db:generate:d1": "drizzle-kit generate --config drizzle.d1.config.ts",
|
|
207
213
|
"db:generate:postgres": "drizzle-kit generate --config drizzle.postgres.config.ts"
|
|
@@ -5,7 +5,7 @@ import { AppError, createLogger } from '@/core'
|
|
|
5
5
|
|
|
6
6
|
const logger = createLogger('auth')
|
|
7
7
|
// Typist reports an invalid key once per isolate because session checks repeatedly construct auth options.
|
|
8
|
-
|
|
8
|
+
const loggedInvalidKeyIds = new Set<string>()
|
|
9
9
|
/**
|
|
10
10
|
* Apple caps `exp` at 15,777,000 seconds after `iat`; 180 days stays under it. Source:
|
|
11
11
|
* https://developer.apple.com/documentation/accountorganizationaldatasharing/creating-a-client-secret
|
|
@@ -46,7 +46,7 @@ function base64UrlJson(segment: JwsSegment): string {
|
|
|
46
46
|
/**
|
|
47
47
|
* Sign Apple's six-month client secret synchronously, so Better Auth options can be built without awaiting it.
|
|
48
48
|
* Signing uses `node:crypto` as Typist does, so the Worker needs the `nodejs_compat` flag.
|
|
49
|
-
* Invalid private keys return an empty secret and log once per isolate, as in Typist.
|
|
49
|
+
* Invalid private keys return an empty secret and log once per key ID in each isolate, as in Typist.
|
|
50
50
|
*/
|
|
51
51
|
export function generateAppleClientSecret(config: AppleKeyConfig): string {
|
|
52
52
|
const key = config.applePrivateKey.replace(/\\n/g, '\n')
|
|
@@ -54,8 +54,8 @@ export function generateAppleClientSecret(config: AppleKeyConfig): string {
|
|
|
54
54
|
try {
|
|
55
55
|
createPrivateKey(key)
|
|
56
56
|
} catch (error) {
|
|
57
|
-
if (!
|
|
58
|
-
|
|
57
|
+
if (!loggedInvalidKeyIds.has(config.appleKeyId)) {
|
|
58
|
+
loggedInvalidKeyIds.add(config.appleKeyId)
|
|
59
59
|
logger.error('apple_private_key_invalid', { error, keyId: config.appleKeyId })
|
|
60
60
|
}
|
|
61
61
|
return ''
|