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.
@@ -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
- let appleKeyFailureLogged = false;
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 (!appleKeyFailureLogged) {
40
- appleKeyFailureLogged = true;
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.\nlet appleKeyFailureLogged = false\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 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 (!appleKeyFailureLogged) {\n appleKeyFailureLogged = true\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,IAAI,wBAAwB;;;;;AAK5B,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,uBAAuB;GAC1B,wBAAwB;GACxB,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"}
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"}
@@ -13,4 +13,5 @@ export declare const authClient: import("better-auth/client").AuthClient<{
13
13
  };
14
14
  }>;
15
15
  //#endregion
16
+ export {};
16
17
  //# sourceMappingURL=auth-client.d.ts.map
@@ -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
@@ -99,4 +99,5 @@ export type BetterAuthOptionsFactory = <const Config extends AuthConfig, const P
99
99
  */
100
100
  export declare const createBetterAuthOptions: BetterAuthOptionsFactory;
101
101
  //#endregion
102
+ export {};
102
103
  //# sourceMappingURL=better-auth.d.ts.map
@@ -83,4 +83,5 @@ export declare class BillingService<const Options extends BillingOptions> implem
83
83
  constructor(options: Options);
84
84
  }
85
85
  //#endregion
86
+ export {};
86
87
  //# sourceMappingURL=client.d.ts.map
@@ -15,4 +15,5 @@ export declare abstract class DurableObjectClient<T extends Rpc.DurableObjectBra
15
15
  private run;
16
16
  }
17
17
  //#endregion
18
+ export {};
18
19
  //# sourceMappingURL=durable-object-client.d.ts.map
@@ -37,4 +37,5 @@ export declare class DurableObjectCallError extends AppError {
37
37
  });
38
38
  }
39
39
  //#endregion
40
+ export {};
40
41
  //# sourceMappingURL=durable-object-errors.d.ts.map
@@ -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;;;;;;;;;;;;;;;;;;;;;;;;;;;;YAAjB;;;;;;;;;;;;;;;;qBAYA,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"}
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"}
@@ -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;;;;;;;;;;;;;;;;;;;;;;;;;;YAAjB;;;;;;;;;;;;;;;;qBAMA,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
+ {"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;EAAA;;;;;;wBAMnB,mBAAmB,mBAAmB,UAAS,OAAO,eAAoB"}
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
@@ -18,4 +18,5 @@ type StripeFixture = {
18
18
  */
19
19
  export declare function stripeFixture(respond: (request: Request) => Response | Promise<Response>): StripeFixture;
20
20
  //#endregion
21
+ export {};
21
22
  //# sourceMappingURL=stripe.d.ts.map
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.38.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.2",
83
- "zod": "^4.6.5"
82
+ "uuid": "^14.0.3",
83
+ "zod": "^4.6.7"
84
84
  },
85
85
  "devDependencies": {
86
- "@better-auth/stripe": "^1.7.7",
87
- "@cloudflare/vitest-plugin": "^1.3.4",
88
- "@cloudflare/workers-types": "5.20260930.2",
89
- "@mdn/browser-compat-data": "^8.1.4",
90
- "@oxlint/plugins": "^1.86.0",
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.6.0",
93
- "@sentry/tanstackstart-react": "^11.6.0",
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.1",
97
- "@tanstack/react-router": "^1.170.41",
98
- "@tanstack/react-start": "^1.168.60",
99
- "@tanstack/start-client-core": "^1.170.34",
100
- "@tanstack/start-storage-context": "^1.167.36",
101
- "@types/node": "^26.6.3",
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": "^4.1.11",
105
- "auth": "^1.7.7",
106
- "better-auth": "^1.7.7",
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.3",
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.63.0",
112
- "posthog-js": "^1.435.6",
113
- "posthog-node": "^5.55.0",
114
- "react": "^19.3.0",
115
- "resend": "^6.31.0",
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.0",
122
+ "tsdown": "^0.23.1",
119
123
  "typescript": "^7.0.2",
120
- "vitest": "^4.1.11",
121
- "wrangler": "^4.145.0"
124
+ "vitest": "^5.0.5",
125
+ "wrangler": "^4.151.1"
122
126
  },
123
127
  "peerDependencies": {
124
- "@better-auth/stripe": "^1.7.7",
125
- "@mdn/browser-compat-data": "^8.1.4",
126
- "@oxlint/plugins": "^1.86.0",
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.6.0",
129
- "@sentry/tanstackstart-react": "^11.6.0",
130
- "@tanstack/react-router": "^1.170.41",
131
- "@tanstack/react-start": "^1.168.60",
132
- "better-auth": "^1.7.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.3",
138
+ "drizzle-orm": "^0.45.4",
135
139
  "pg": "^8.23.1",
136
- "posthog-js": "^1.435.6",
137
- "posthog-node": "^5.55.0",
138
- "react": "^19.3.0",
139
- "resend": "^6.31.0",
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
- let appleKeyFailureLogged = false
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 (!appleKeyFailureLogged) {
58
- appleKeyFailureLogged = true
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 ''