@absolutejs/auth 0.28.0 → 0.29.0-beta.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/index.d.ts CHANGED
@@ -14892,6 +14892,8 @@ export { createNeonPasswordlessTokenStore, createPostgresPasswordlessTokenStore,
14892
14892
  export * from './webhooks/config';
14893
14893
  export * from './webhooks/types';
14894
14894
  export { createWebhookDispatcher } from './webhooks/dispatcher';
14895
+ export { createInMemoryWebhookDeliveryStore } from './webhooks/inMemoryStore';
14896
+ export { createNeonWebhookDeliveryStore, createPostgresWebhookDeliveryStore, webhookDeliveriesTable } from './webhooks/postgresStore';
14895
14897
  export { signWebhook, verifyWebhookSignature } from './webhooks/sign';
14896
14898
  export * from './portal/config';
14897
14899
  export * from './portal/types';
package/dist/index.js CHANGED
@@ -7920,6 +7920,14 @@ var webauthnRoutes = ({
7920
7920
 
7921
7921
  // src/webhooks/config.ts
7922
7922
  var DEFAULT_TIMEOUT_SECONDS = 5;
7923
+ var DEFAULT_RETRY_ATTEMPTS = 3;
7924
+ var DEFAULT_RETRY_INITIAL_DELAY_MS = MILLISECONDS_IN_A_SECOND;
7925
+ var DEFAULT_RETRY_BACKOFF_MULTIPLIER = 2;
7926
+ var DEFAULT_WEBHOOK_RETRY = {
7927
+ attempts: DEFAULT_RETRY_ATTEMPTS,
7928
+ backoffMultiplier: DEFAULT_RETRY_BACKOFF_MULTIPLIER,
7929
+ initialDelayMs: DEFAULT_RETRY_INITIAL_DELAY_MS
7930
+ };
7923
7931
  var DEFAULT_WEBHOOK_TIMEOUT_MS = MILLISECONDS_IN_A_SECOND * DEFAULT_TIMEOUT_SECONDS;
7924
7932
 
7925
7933
  // src/webhooks/sign.ts
@@ -7952,12 +7960,145 @@ var verifyWebhookSignature = async ({
7952
7960
  };
7953
7961
 
7954
7962
  // src/webhooks/dispatcher.ts
7963
+ var defaultSleep = (delayMs) => new Promise((resolve) => setTimeout(resolve, delayMs));
7964
+ var attemptOnce = async ({
7965
+ envelope,
7966
+ endpoint,
7967
+ fetchImpl,
7968
+ payload,
7969
+ signature,
7970
+ timeoutMs,
7971
+ timestamp
7972
+ }) => {
7973
+ const response = await fetchImpl(endpoint.url, {
7974
+ body: payload,
7975
+ headers: {
7976
+ "content-type": "application/json",
7977
+ "webhook-id": envelope.id,
7978
+ "webhook-signature": signature,
7979
+ "webhook-timestamp": timestamp
7980
+ },
7981
+ method: "POST",
7982
+ signal: AbortSignal.timeout(timeoutMs)
7983
+ });
7984
+ if (!response.ok) {
7985
+ throw new Error(`Webhook delivery returned ${response.status}`);
7986
+ }
7987
+ return response.status;
7988
+ };
7989
+ var errorMessage = (error) => error instanceof Error ? error.message : String(error);
7990
+ var statusFromError = (error) => {
7991
+ if (!(error instanceof Error))
7992
+ return;
7993
+ const match = /returned (\d+)/.exec(error.message);
7994
+ return match?.[1] === undefined ? undefined : Number(match[1]);
7995
+ };
7996
+ var persistFailure = async ({
7997
+ attempts,
7998
+ deliveryStore,
7999
+ endpoint,
8000
+ envelope,
8001
+ lastError
8002
+ }) => {
8003
+ if (deliveryStore === undefined)
8004
+ return;
8005
+ const record = {
8006
+ attempts,
8007
+ createdAt: Date.now(),
8008
+ endpointUrl: endpoint.url,
8009
+ envelope,
8010
+ lastError: errorMessage(lastError),
8011
+ lastStatus: statusFromError(lastError)
8012
+ };
8013
+ await deliveryStore.recordFailure(record);
8014
+ };
8015
+ var tryDeliverThenBackoff = async ({
8016
+ attempt,
8017
+ endpoint,
8018
+ envelope,
8019
+ fetchImpl,
8020
+ payload,
8021
+ retry,
8022
+ signature,
8023
+ sleep,
8024
+ timeoutMs,
8025
+ timestamp
8026
+ }) => {
8027
+ try {
8028
+ await attemptOnce({
8029
+ endpoint,
8030
+ envelope,
8031
+ fetchImpl,
8032
+ payload,
8033
+ signature,
8034
+ timeoutMs,
8035
+ timestamp
8036
+ });
8037
+ return;
8038
+ } catch (error) {
8039
+ const isLastAttempt = attempt >= retry.attempts - 1;
8040
+ await (isLastAttempt ? Promise.resolve() : sleep(retry.initialDelayMs * retry.backoffMultiplier ** attempt));
8041
+ return error;
8042
+ }
8043
+ };
8044
+ var deliverToEndpoint = async ({
8045
+ deliveryStore,
8046
+ endpoint,
8047
+ envelope,
8048
+ fetchImpl,
8049
+ onDeliveryError,
8050
+ payload,
8051
+ retry,
8052
+ signature,
8053
+ sleep,
8054
+ timeoutMs,
8055
+ timestamp
8056
+ }) => {
8057
+ let lastError;
8058
+ for (let attempt = 0;attempt < retry.attempts; attempt++) {
8059
+ const error = await tryDeliverThenBackoff({
8060
+ attempt,
8061
+ endpoint,
8062
+ envelope,
8063
+ fetchImpl,
8064
+ payload,
8065
+ retry,
8066
+ signature,
8067
+ sleep,
8068
+ timeoutMs,
8069
+ timestamp
8070
+ });
8071
+ if (error === undefined)
8072
+ return;
8073
+ lastError = error;
8074
+ }
8075
+ await onDeliveryError?.({
8076
+ endpoint,
8077
+ error: lastError,
8078
+ event: envelope
8079
+ });
8080
+ await persistFailure({
8081
+ attempts: retry.attempts,
8082
+ deliveryStore,
8083
+ endpoint,
8084
+ envelope,
8085
+ lastError
8086
+ });
8087
+ };
7955
8088
  var createWebhookDispatcher = ({
8089
+ deliveryStore,
7956
8090
  endpoints,
7957
8091
  fetch: fetchImpl = globalThis.fetch,
7958
8092
  onDeliveryError,
8093
+ retry,
8094
+ sleep = defaultSleep,
7959
8095
  timeoutMs = DEFAULT_WEBHOOK_TIMEOUT_MS
7960
8096
  }) => {
8097
+ const effectiveRetry = {
8098
+ attempts: retry?.attempts ?? DEFAULT_WEBHOOK_RETRY.attempts,
8099
+ backoffMultiplier: retry?.backoffMultiplier ?? DEFAULT_WEBHOOK_RETRY.backoffMultiplier,
8100
+ initialDelayMs: retry?.initialDelayMs ?? DEFAULT_WEBHOOK_RETRY.initialDelayMs
8101
+ };
7961
8102
  const dispatch = async (event) => {
7962
8103
  const envelope = {
7963
8104
  createdAt: Date.now(),
@@ -7967,35 +8108,26 @@ var createWebhookDispatcher = ({
7967
8108
  };
7968
8109
  const payload = JSON.stringify(envelope);
7969
8110
  const timestamp = Math.floor(Date.now() / MILLISECONDS_IN_A_SECOND).toString();
7970
- await Promise.all(endpoints.map(async (endpoint) => {
7971
- try {
7972
- const signature = await signWebhook({
7973
- id: envelope.id,
7974
- payload,
7975
- secret: endpoint.secret,
7976
- timestamp
7977
- });
7978
- const response = await fetchImpl(endpoint.url, {
7979
- body: payload,
7980
- headers: {
7981
- "content-type": "application/json",
7982
- "webhook-id": envelope.id,
7983
- "webhook-signature": signature,
7984
- "webhook-timestamp": timestamp
7985
- },
7986
- method: "POST",
7987
- signal: AbortSignal.timeout(timeoutMs)
7988
- });
7989
- if (!response.ok) {
7990
- throw new Error(`Webhook delivery returned ${response.status}`);
7991
- }
7992
- } catch (error) {
7993
- await onDeliveryError?.({
7994
- endpoint,
7995
- error,
7996
- event: envelope
7997
- });
7998
- }
8111
+ await Promise.all(endpoints.filter((endpoint) => endpoint.events === undefined || endpoint.events.includes(event.type)).map(async (endpoint) => {
8112
+ const signature = await signWebhook({
8113
+ id: envelope.id,
8114
+ payload,
8115
+ secret: endpoint.secret,
8116
+ timestamp
8117
+ });
8118
+ await deliverToEndpoint({
8119
+ deliveryStore,
8120
+ endpoint,
8121
+ envelope,
8122
+ fetchImpl,
8123
+ onDeliveryError,
8124
+ payload,
8125
+ retry: effectiveRetry,
8126
+ signature,
8127
+ sleep,
8128
+ timeoutMs,
8129
+ timestamp
8130
+ });
7999
8131
  }));
8000
8132
  };
8001
8133
  return dispatch;
@@ -21318,6 +21450,62 @@ var createPostgresPasswordlessTokenStore = (db) => ({
21318
21450
  });
21319
21451
  }
21320
21452
  });
21453
+ // src/webhooks/inMemoryStore.ts
21454
+ var DEFAULT_LIST_LIMIT = 100;
21455
+ var createInMemoryWebhookDeliveryStore = () => {
21456
+ const failures = new Map;
21457
+ return {
21458
+ listFailed: async (limit = DEFAULT_LIST_LIMIT) => Array.from(failures.values()).sort((left, right) => right.createdAt - left.createdAt).slice(0, limit),
21459
+ recordFailure: async (delivery) => {
21460
+ failures.set(delivery.envelope.id, delivery);
21461
+ },
21462
+ removeFailure: async (envelopeId) => {
21463
+ failures.delete(envelopeId);
21464
+ }
21465
+ };
21466
+ };
21467
+ // src/webhooks/postgresStore.ts
21468
+ var ID_LENGTH15 = 255;
21469
+ var URL_LENGTH = 2048;
21470
+ var DEFAULT_LIST_LIMIT2 = 100;
21471
+ var webhookDeliveriesTable = pgTable("auth_webhook_deliveries", {
21472
+ attempts: bigint("attempts", { mode: "number" }).notNull(),
21473
+ created_at_ms: bigint("created_at_ms", { mode: "number" }).notNull(),
21474
+ endpoint_url: varchar("endpoint_url", { length: URL_LENGTH }).notNull(),
21475
+ envelope_id: varchar("envelope_id", { length: ID_LENGTH15 }).primaryKey(),
21476
+ envelope_json: jsonb("envelope_json").$type().notNull(),
21477
+ last_error: text("last_error"),
21478
+ last_status: bigint("last_status", { mode: "number" })
21479
+ });
21480
+ var toDelivery = (row) => ({
21481
+ attempts: row.attempts,
21482
+ createdAt: row.created_at_ms,
21483
+ endpointUrl: row.endpoint_url,
21484
+ envelope: row.envelope_json,
21485
+ lastError: row.last_error ?? undefined,
21486
+ lastStatus: row.last_status ?? undefined
21487
+ });
21488
+ var createNeonWebhookDeliveryStore = (databaseUrl) => createPostgresWebhookDeliveryStore(createNeonDatabase(databaseUrl));
21489
+ var createPostgresWebhookDeliveryStore = (db) => ({
21490
+ listFailed: async (limit = DEFAULT_LIST_LIMIT2) => {
21491
+ const rows = await db.select().from(webhookDeliveriesTable).orderBy(desc(webhookDeliveriesTable.created_at_ms)).limit(limit);
21492
+ return rows.map(toDelivery);
21493
+ },
21494
+ recordFailure: async (delivery) => {
21495
+ await db.insert(webhookDeliveriesTable).values({
21496
+ attempts: delivery.attempts,
21497
+ created_at_ms: delivery.createdAt,
21498
+ endpoint_url: delivery.endpointUrl,
21499
+ envelope_id: delivery.envelope.id,
21500
+ envelope_json: delivery.envelope,
21501
+ last_error: delivery.lastError ?? null,
21502
+ last_status: delivery.lastStatus ?? null
21503
+ });
21504
+ },
21505
+ removeFailure: async (envelopeId) => {
21506
+ await db.delete(webhookDeliveriesTable).where(eq(webhookDeliveriesTable.envelope_id, envelopeId));
21507
+ }
21508
+ });
21321
21509
  // src/portal/inMemorySetupSessionStore.ts
21322
21510
  var cloneSession = (value) => ({
21323
21511
  ...value,
@@ -21339,19 +21527,19 @@ var createInMemorySetupSessionStore = () => {
21339
21527
  };
21340
21528
  };
21341
21529
  // src/portal/postgresSetupSessionStore.ts
21342
- var ID_LENGTH15 = 255;
21530
+ var ID_LENGTH16 = 255;
21343
21531
  var setupSessionsTable = pgTable("auth_setup_sessions", {
21344
21532
  capabilities: jsonb("capabilities").$type().notNull().default([]),
21345
21533
  created_at_ms: bigint("created_at_ms", { mode: "number" }).notNull(),
21346
- created_by: varchar("created_by", { length: ID_LENGTH15 }),
21534
+ created_by: varchar("created_by", { length: ID_LENGTH16 }),
21347
21535
  expires_at_ms: bigint("expires_at_ms", { mode: "number" }).notNull(),
21348
21536
  organization_id: varchar("organization_id", {
21349
- length: ID_LENGTH15
21537
+ length: ID_LENGTH16
21350
21538
  }).notNull(),
21351
21539
  setup_session_id: varchar("setup_session_id", {
21352
- length: ID_LENGTH15
21540
+ length: ID_LENGTH16
21353
21541
  }).primaryKey(),
21354
- token_hash: varchar("token_hash", { length: ID_LENGTH15 }).notNull().unique()
21542
+ token_hash: varchar("token_hash", { length: ID_LENGTH16 }).notNull().unique()
21355
21543
  });
21356
21544
  var toSession = (row) => ({
21357
21545
  capabilities: row.capabilities,
@@ -21542,6 +21730,7 @@ var auth = async ({
21542
21730
  };
21543
21731
  export {
21544
21732
  writeWarrant,
21733
+ webhookDeliveriesTable,
21545
21734
  webauthnRoutes,
21546
21735
  webauthnCredentialsTable,
21547
21736
  warrantsTable,
@@ -21707,6 +21896,7 @@ export {
21707
21896
  createRiskEngine,
21708
21897
  createRedisLockoutStore,
21709
21898
  createRedisAuthSessionStore,
21899
+ createPostgresWebhookDeliveryStore,
21710
21900
  createPostgresWebAuthnCredentialStore,
21711
21901
  createPostgresWarrantStore,
21712
21902
  createPostgresVaultStore,
@@ -21731,6 +21921,7 @@ export {
21731
21921
  createPostgresAccessTokenStore,
21732
21922
  createOrganization,
21733
21923
  createOAuthLinkedProviderCredentialResolver,
21924
+ createNeonWebhookDeliveryStore,
21734
21925
  createNeonWebAuthnCredentialStore,
21735
21926
  createNeonWarrantStore,
21736
21927
  createNeonVaultStore,
@@ -21761,6 +21952,7 @@ export {
21761
21952
  createMembershipPermissionResolver,
21762
21953
  createLockoutGuard,
21763
21954
  createLinkedProviderCredentialResolver,
21955
+ createInMemoryWebhookDeliveryStore,
21764
21956
  createInMemoryWebAuthnCredentialStore,
21765
21957
  createInMemoryWarrantStore,
21766
21958
  createInMemoryVaultStore,
@@ -21818,6 +22010,7 @@ export {
21818
22010
  acceptInvitation,
21819
22011
  WEBAUTHN_CHALLENGE_COOKIE,
21820
22012
  DEFAULT_WEBHOOK_TIMEOUT_MS,
22013
+ DEFAULT_WEBHOOK_RETRY,
21821
22014
  DEFAULT_WEBAUTHN_SESSION_TTL_MS,
21822
22015
  DEFAULT_WEBAUTHN_ROUTE,
21823
22016
  DEFAULT_WEBAUTHN_CHALLENGE_TTL_MS,
@@ -21846,5 +22039,5 @@ export {
21846
22039
  AuthIdentityConflictError
21847
22040
  };
21848
22041
 
21849
- //# debugId=E246ECC6A14E235864756E2164756E21
22042
+ //# debugId=451C9751C02E5E2164756E2164756E21
21850
22043
  //# sourceMappingURL=index.js.map