@peektravel/app-utilities 0.7.2 → 0.7.4

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.cts CHANGED
@@ -1833,20 +1833,34 @@ declare const PEEK_PLATFORMS: readonly ["peek", "cng", "acme"];
1833
1833
  * claim is the single thing that identifies which platform a request came from.
1834
1834
  */
1835
1835
  type PeekPlatform = (typeof PEEK_PLATFORMS)[number];
1836
- /** User context embedded in a Peek auth token. */
1836
+ /**
1837
+ * User context embedded in a Peek auth token.
1838
+ *
1839
+ * Every field is nullable: the token is untrusted even after its signature
1840
+ * verifies, so a claim may be absent, `null`, or a sentinel (`""`, `"null"`)
1841
+ * that this package normalizes to `null`. Never assume a field is populated —
1842
+ * always null-check.
1843
+ */
1837
1844
  interface PeekAuthTokenUser {
1838
- /** User's email address. */
1839
- email: string;
1840
- /** User's Peek account ID */
1841
- id: string;
1842
- /** Whether the user has admin privileges. */
1843
- isAdmin: boolean;
1844
- /** User's locale (e.g. `"en"`). */
1845
- locale: string;
1846
- /** User's display name. */
1847
- name: string;
1848
- /** Which platform embedded the app for this session. */
1849
- platform: PeekPlatform;
1845
+ /** User's email address, or `null` if the token omits it. */
1846
+ email: string | null;
1847
+ /**
1848
+ * The user's own Peek user ID — it identifies the signed-in person, **not**
1849
+ * the account or partner they belong to. Use it only to key the user; never
1850
+ * treat it as an account/partner id. `null` when the token omits it.
1851
+ */
1852
+ id: string | null;
1853
+ /** Whether the user has admin privileges, or `null` if the token omits it. */
1854
+ isAdmin: boolean | null;
1855
+ /** User's locale (e.g. `"en"`), or `null` if the token omits it. */
1856
+ locale: string | null;
1857
+ /** User's display name, or `null` if the token omits it. */
1858
+ name: string | null;
1859
+ /**
1860
+ * Which platform embedded the app for this session, or `null` when the token
1861
+ * omits it or reports one this version of the package doesn't recognize.
1862
+ */
1863
+ platform: PeekPlatform | null;
1850
1864
  }
1851
1865
  /** Claims returned by {@link PeekAccessService.verifyPeekAuthToken}. */
1852
1866
  interface PeekAuthTokenClaims {
@@ -1854,8 +1868,11 @@ interface PeekAuthTokenClaims {
1854
1868
  installId: string;
1855
1869
  /** App display version at time of issuance. */
1856
1870
  displayVersion: string;
1857
- /** Authenticated user context. */
1858
- user: PeekAuthTokenUser;
1871
+ /**
1872
+ * Authenticated user context, or `null` when the token carries no `user`
1873
+ * block. Do not assume a session token always names a user.
1874
+ */
1875
+ user: PeekAuthTokenUser | null;
1859
1876
  }
1860
1877
  /** The Peek account an install belongs to, as reported on an install webhook. */
1861
1878
  interface InstallWebhookAccount {
@@ -1965,13 +1982,15 @@ declare class PeekAccessService {
1965
1982
  * malformed
1966
1983
  * - `TokenExpiredError` — past `exp`
1967
1984
  * - `NotBeforeError` — before `nbf`
1968
- * - `InvalidPeekTokenError` — signature valid but the `user` block is missing
1969
- * its `id`
1985
+ *
1986
+ * Claim *extraction* is defensive: once the signature verifies, a token with
1987
+ * no `user` block yields `claims.user === null`, and any individual user field
1988
+ * that is absent or a sentinel (`""`, `"null"`) is normalized to `null`. This
1989
+ * method never throws on a shape problem — only on a verification failure.
1970
1990
  *
1971
1991
  * @throws {JsonWebTokenError} signature invalid or token malformed
1972
1992
  * @throws {TokenExpiredError} token has expired
1973
1993
  * @throws {NotBeforeError} token not yet valid
1974
- * @throws {InvalidPeekTokenError} verified token has no `user.id`
1975
1994
  */
1976
1995
  verifyPeekAuthToken(token: string): PeekAuthTokenClaims;
1977
1996
  /**
@@ -2777,19 +2796,6 @@ declare class PeekHttpError extends Error {
2777
2796
  readonly body: unknown;
2778
2797
  constructor(statusCode: number, url: string, body: unknown, message?: string);
2779
2798
  }
2780
- /**
2781
- * Thrown when an `app_registry_v2` token passes signature/issuer/audience
2782
- * verification but its `user` block is missing a required `id`. The signature is
2783
- * authentic, so this signals a structurally malformed token from the app
2784
- * registry rather than a forged one — distinct from the `jsonwebtoken`
2785
- * `JsonWebTokenError` family. The offending field is preserved on
2786
- * {@link InvalidPeekTokenError.field}.
2787
- */
2788
- declare class InvalidPeekTokenError extends Error {
2789
- /** The token field that was missing or empty (e.g. `"user.id"`). */
2790
- readonly field: string;
2791
- constructor(field: string);
2792
- }
2793
2799
  /**
2794
2800
  * Thrown when a payment or booking-modification operation is called on an
2795
2801
  * access service that was constructed without `fullCustomerAccess` (PII access
@@ -2830,4 +2836,4 @@ declare class AcmeApiError extends Error {
2830
2836
  constructor(statusCode: number, body: unknown, message?: string);
2831
2837
  }
2832
2838
 
2833
- export { ACTIVITY_PRODUCT_TYPE, ADD_ON_PRODUCT_TYPE, type AccessOptions, type AccountUser, AccountUserService, type AccountUserServiceOptions, AcmeAccessService, type AcmeAccessServiceConfig, type AcmeActivity, type AcmeActivityTicket, AcmeApiError, AcmeProductService, type Activity, type ActivityOverrides, type ActivityTicket, type AddAddonInput, AdminAccountRequiredError, type Agent, type AssignGuideResult, type AssignedActivity, type AssignedResource, type Availability, AvailabilityService, type AvailabilityTime, type AvailabilityTimesQuery, type Booking, type BookingAddon, type BookingAddonMoney, type BookingAddonOption, type BookingAddons, type BookingAddonsMutationResult, type BookingPaymentsOnFile, type BookingReadOptions, type BookingSearchBy, BookingService, type BookingServiceOptions, type BookingTimeRangeSearch, type CancelBookingResult, type Channel, type ClearOverridesInput, CngAccessService, type CngAccessServiceConfig, CngApiError, CngProductService, type CreateBookingGuest, type CreateBookingInput, type CreateBookingTicket, type CreateEngineInput, type CreatePromoCodeInput, type CreatedBooking, type CreatedPricingEngine, type CreatedPromoCode, type CustomQuestionAnswer, type DailyNote, DailyNoteService, type Duration, type Guest, type GuestMetadata, type Guide, type GuideAssignment, INSTALL_STATUSES, type InstallAccessConfig, type InstallAccessService, type InstallAccessTarget, type InstallStatus, type InstallWebhook, type InstallWebhookAccount, type InstallWebhookClaims, InvalidPeekTokenError, type InvoiceLinkResult, type Logger, type MakePaymentInput, type MakePaymentResult, type Membership, type MembershipPurchaseInput, MembershipService, type NoteMode, type Payment, type PaymentSource, PeekAccessService, type PeekAccessServiceConfig, type PeekAuthTokenClaims, type PeekAuthTokenUser, PeekGraphQLError, PeekHttpError, type PeekPlatform, PiiAccessDisabledError, type Price, type PricingActivityContext, type PricingEngine, type PricingMoney, type PricingNamedRef, type PricingOverride, type PricingOverrideFilter, PricingService, type Product, type ProductMeetingLocation, ProductService, type ProductServiceOptions, type ProductTicket, type PromoCode, type PromoCodeFixedAmount, PromoCodeService, type PromoCodeServiceOptions, type PurchasedMembership, RENTAL_PRODUCT_TYPE, RateLimitError, type RefundInput, type RefundResult, ResellerService, type ResolvedOverride, type ResolvedPricingOverride, type ResolvedResourceOption, type Resource, type ResourceOptionOverride, type ResourceOptionQuantity, type ResourcePool, type ResourcePoolAccountUser, type ResourcePoolAssignment, type ResourcePoolMode, ResourcePoolService, type Review, ReviewService, type Ticket, type Timeslot, type TimeslotFilter, TimeslotService, type UpdateEngineInput, type UpdateTimeslotResult, type UpsertOverridesInput, type UpsertOverridesResult, type Waiver, createAccessServiceForInstall, noopLogger, parseBookingWebhook, parseInstallWebhook, parseWaiverWebhook, verifyInstallWebhook };
2839
+ export { ACTIVITY_PRODUCT_TYPE, ADD_ON_PRODUCT_TYPE, type AccessOptions, type AccountUser, AccountUserService, type AccountUserServiceOptions, AcmeAccessService, type AcmeAccessServiceConfig, type AcmeActivity, type AcmeActivityTicket, AcmeApiError, AcmeProductService, type Activity, type ActivityOverrides, type ActivityTicket, type AddAddonInput, AdminAccountRequiredError, type Agent, type AssignGuideResult, type AssignedActivity, type AssignedResource, type Availability, AvailabilityService, type AvailabilityTime, type AvailabilityTimesQuery, type Booking, type BookingAddon, type BookingAddonMoney, type BookingAddonOption, type BookingAddons, type BookingAddonsMutationResult, type BookingPaymentsOnFile, type BookingReadOptions, type BookingSearchBy, BookingService, type BookingServiceOptions, type BookingTimeRangeSearch, type CancelBookingResult, type Channel, type ClearOverridesInput, CngAccessService, type CngAccessServiceConfig, CngApiError, CngProductService, type CreateBookingGuest, type CreateBookingInput, type CreateBookingTicket, type CreateEngineInput, type CreatePromoCodeInput, type CreatedBooking, type CreatedPricingEngine, type CreatedPromoCode, type CustomQuestionAnswer, type DailyNote, DailyNoteService, type Duration, type Guest, type GuestMetadata, type Guide, type GuideAssignment, INSTALL_STATUSES, type InstallAccessConfig, type InstallAccessService, type InstallAccessTarget, type InstallStatus, type InstallWebhook, type InstallWebhookAccount, type InstallWebhookClaims, type InvoiceLinkResult, type Logger, type MakePaymentInput, type MakePaymentResult, type Membership, type MembershipPurchaseInput, MembershipService, type NoteMode, type Payment, type PaymentSource, PeekAccessService, type PeekAccessServiceConfig, type PeekAuthTokenClaims, type PeekAuthTokenUser, PeekGraphQLError, PeekHttpError, type PeekPlatform, PiiAccessDisabledError, type Price, type PricingActivityContext, type PricingEngine, type PricingMoney, type PricingNamedRef, type PricingOverride, type PricingOverrideFilter, PricingService, type Product, type ProductMeetingLocation, ProductService, type ProductServiceOptions, type ProductTicket, type PromoCode, type PromoCodeFixedAmount, PromoCodeService, type PromoCodeServiceOptions, type PurchasedMembership, RENTAL_PRODUCT_TYPE, RateLimitError, type RefundInput, type RefundResult, ResellerService, type ResolvedOverride, type ResolvedPricingOverride, type ResolvedResourceOption, type Resource, type ResourceOptionOverride, type ResourceOptionQuantity, type ResourcePool, type ResourcePoolAccountUser, type ResourcePoolAssignment, type ResourcePoolMode, ResourcePoolService, type Review, ReviewService, type Ticket, type Timeslot, type TimeslotFilter, TimeslotService, type UpdateEngineInput, type UpdateTimeslotResult, type UpsertOverridesInput, type UpsertOverridesResult, type Waiver, createAccessServiceForInstall, noopLogger, parseBookingWebhook, parseInstallWebhook, parseWaiverWebhook, verifyInstallWebhook };
package/dist/index.d.ts CHANGED
@@ -1833,20 +1833,34 @@ declare const PEEK_PLATFORMS: readonly ["peek", "cng", "acme"];
1833
1833
  * claim is the single thing that identifies which platform a request came from.
1834
1834
  */
1835
1835
  type PeekPlatform = (typeof PEEK_PLATFORMS)[number];
1836
- /** User context embedded in a Peek auth token. */
1836
+ /**
1837
+ * User context embedded in a Peek auth token.
1838
+ *
1839
+ * Every field is nullable: the token is untrusted even after its signature
1840
+ * verifies, so a claim may be absent, `null`, or a sentinel (`""`, `"null"`)
1841
+ * that this package normalizes to `null`. Never assume a field is populated —
1842
+ * always null-check.
1843
+ */
1837
1844
  interface PeekAuthTokenUser {
1838
- /** User's email address. */
1839
- email: string;
1840
- /** User's Peek account ID */
1841
- id: string;
1842
- /** Whether the user has admin privileges. */
1843
- isAdmin: boolean;
1844
- /** User's locale (e.g. `"en"`). */
1845
- locale: string;
1846
- /** User's display name. */
1847
- name: string;
1848
- /** Which platform embedded the app for this session. */
1849
- platform: PeekPlatform;
1845
+ /** User's email address, or `null` if the token omits it. */
1846
+ email: string | null;
1847
+ /**
1848
+ * The user's own Peek user ID — it identifies the signed-in person, **not**
1849
+ * the account or partner they belong to. Use it only to key the user; never
1850
+ * treat it as an account/partner id. `null` when the token omits it.
1851
+ */
1852
+ id: string | null;
1853
+ /** Whether the user has admin privileges, or `null` if the token omits it. */
1854
+ isAdmin: boolean | null;
1855
+ /** User's locale (e.g. `"en"`), or `null` if the token omits it. */
1856
+ locale: string | null;
1857
+ /** User's display name, or `null` if the token omits it. */
1858
+ name: string | null;
1859
+ /**
1860
+ * Which platform embedded the app for this session, or `null` when the token
1861
+ * omits it or reports one this version of the package doesn't recognize.
1862
+ */
1863
+ platform: PeekPlatform | null;
1850
1864
  }
1851
1865
  /** Claims returned by {@link PeekAccessService.verifyPeekAuthToken}. */
1852
1866
  interface PeekAuthTokenClaims {
@@ -1854,8 +1868,11 @@ interface PeekAuthTokenClaims {
1854
1868
  installId: string;
1855
1869
  /** App display version at time of issuance. */
1856
1870
  displayVersion: string;
1857
- /** Authenticated user context. */
1858
- user: PeekAuthTokenUser;
1871
+ /**
1872
+ * Authenticated user context, or `null` when the token carries no `user`
1873
+ * block. Do not assume a session token always names a user.
1874
+ */
1875
+ user: PeekAuthTokenUser | null;
1859
1876
  }
1860
1877
  /** The Peek account an install belongs to, as reported on an install webhook. */
1861
1878
  interface InstallWebhookAccount {
@@ -1965,13 +1982,15 @@ declare class PeekAccessService {
1965
1982
  * malformed
1966
1983
  * - `TokenExpiredError` — past `exp`
1967
1984
  * - `NotBeforeError` — before `nbf`
1968
- * - `InvalidPeekTokenError` — signature valid but the `user` block is missing
1969
- * its `id`
1985
+ *
1986
+ * Claim *extraction* is defensive: once the signature verifies, a token with
1987
+ * no `user` block yields `claims.user === null`, and any individual user field
1988
+ * that is absent or a sentinel (`""`, `"null"`) is normalized to `null`. This
1989
+ * method never throws on a shape problem — only on a verification failure.
1970
1990
  *
1971
1991
  * @throws {JsonWebTokenError} signature invalid or token malformed
1972
1992
  * @throws {TokenExpiredError} token has expired
1973
1993
  * @throws {NotBeforeError} token not yet valid
1974
- * @throws {InvalidPeekTokenError} verified token has no `user.id`
1975
1994
  */
1976
1995
  verifyPeekAuthToken(token: string): PeekAuthTokenClaims;
1977
1996
  /**
@@ -2777,19 +2796,6 @@ declare class PeekHttpError extends Error {
2777
2796
  readonly body: unknown;
2778
2797
  constructor(statusCode: number, url: string, body: unknown, message?: string);
2779
2798
  }
2780
- /**
2781
- * Thrown when an `app_registry_v2` token passes signature/issuer/audience
2782
- * verification but its `user` block is missing a required `id`. The signature is
2783
- * authentic, so this signals a structurally malformed token from the app
2784
- * registry rather than a forged one — distinct from the `jsonwebtoken`
2785
- * `JsonWebTokenError` family. The offending field is preserved on
2786
- * {@link InvalidPeekTokenError.field}.
2787
- */
2788
- declare class InvalidPeekTokenError extends Error {
2789
- /** The token field that was missing or empty (e.g. `"user.id"`). */
2790
- readonly field: string;
2791
- constructor(field: string);
2792
- }
2793
2799
  /**
2794
2800
  * Thrown when a payment or booking-modification operation is called on an
2795
2801
  * access service that was constructed without `fullCustomerAccess` (PII access
@@ -2830,4 +2836,4 @@ declare class AcmeApiError extends Error {
2830
2836
  constructor(statusCode: number, body: unknown, message?: string);
2831
2837
  }
2832
2838
 
2833
- export { ACTIVITY_PRODUCT_TYPE, ADD_ON_PRODUCT_TYPE, type AccessOptions, type AccountUser, AccountUserService, type AccountUserServiceOptions, AcmeAccessService, type AcmeAccessServiceConfig, type AcmeActivity, type AcmeActivityTicket, AcmeApiError, AcmeProductService, type Activity, type ActivityOverrides, type ActivityTicket, type AddAddonInput, AdminAccountRequiredError, type Agent, type AssignGuideResult, type AssignedActivity, type AssignedResource, type Availability, AvailabilityService, type AvailabilityTime, type AvailabilityTimesQuery, type Booking, type BookingAddon, type BookingAddonMoney, type BookingAddonOption, type BookingAddons, type BookingAddonsMutationResult, type BookingPaymentsOnFile, type BookingReadOptions, type BookingSearchBy, BookingService, type BookingServiceOptions, type BookingTimeRangeSearch, type CancelBookingResult, type Channel, type ClearOverridesInput, CngAccessService, type CngAccessServiceConfig, CngApiError, CngProductService, type CreateBookingGuest, type CreateBookingInput, type CreateBookingTicket, type CreateEngineInput, type CreatePromoCodeInput, type CreatedBooking, type CreatedPricingEngine, type CreatedPromoCode, type CustomQuestionAnswer, type DailyNote, DailyNoteService, type Duration, type Guest, type GuestMetadata, type Guide, type GuideAssignment, INSTALL_STATUSES, type InstallAccessConfig, type InstallAccessService, type InstallAccessTarget, type InstallStatus, type InstallWebhook, type InstallWebhookAccount, type InstallWebhookClaims, InvalidPeekTokenError, type InvoiceLinkResult, type Logger, type MakePaymentInput, type MakePaymentResult, type Membership, type MembershipPurchaseInput, MembershipService, type NoteMode, type Payment, type PaymentSource, PeekAccessService, type PeekAccessServiceConfig, type PeekAuthTokenClaims, type PeekAuthTokenUser, PeekGraphQLError, PeekHttpError, type PeekPlatform, PiiAccessDisabledError, type Price, type PricingActivityContext, type PricingEngine, type PricingMoney, type PricingNamedRef, type PricingOverride, type PricingOverrideFilter, PricingService, type Product, type ProductMeetingLocation, ProductService, type ProductServiceOptions, type ProductTicket, type PromoCode, type PromoCodeFixedAmount, PromoCodeService, type PromoCodeServiceOptions, type PurchasedMembership, RENTAL_PRODUCT_TYPE, RateLimitError, type RefundInput, type RefundResult, ResellerService, type ResolvedOverride, type ResolvedPricingOverride, type ResolvedResourceOption, type Resource, type ResourceOptionOverride, type ResourceOptionQuantity, type ResourcePool, type ResourcePoolAccountUser, type ResourcePoolAssignment, type ResourcePoolMode, ResourcePoolService, type Review, ReviewService, type Ticket, type Timeslot, type TimeslotFilter, TimeslotService, type UpdateEngineInput, type UpdateTimeslotResult, type UpsertOverridesInput, type UpsertOverridesResult, type Waiver, createAccessServiceForInstall, noopLogger, parseBookingWebhook, parseInstallWebhook, parseWaiverWebhook, verifyInstallWebhook };
2839
+ export { ACTIVITY_PRODUCT_TYPE, ADD_ON_PRODUCT_TYPE, type AccessOptions, type AccountUser, AccountUserService, type AccountUserServiceOptions, AcmeAccessService, type AcmeAccessServiceConfig, type AcmeActivity, type AcmeActivityTicket, AcmeApiError, AcmeProductService, type Activity, type ActivityOverrides, type ActivityTicket, type AddAddonInput, AdminAccountRequiredError, type Agent, type AssignGuideResult, type AssignedActivity, type AssignedResource, type Availability, AvailabilityService, type AvailabilityTime, type AvailabilityTimesQuery, type Booking, type BookingAddon, type BookingAddonMoney, type BookingAddonOption, type BookingAddons, type BookingAddonsMutationResult, type BookingPaymentsOnFile, type BookingReadOptions, type BookingSearchBy, BookingService, type BookingServiceOptions, type BookingTimeRangeSearch, type CancelBookingResult, type Channel, type ClearOverridesInput, CngAccessService, type CngAccessServiceConfig, CngApiError, CngProductService, type CreateBookingGuest, type CreateBookingInput, type CreateBookingTicket, type CreateEngineInput, type CreatePromoCodeInput, type CreatedBooking, type CreatedPricingEngine, type CreatedPromoCode, type CustomQuestionAnswer, type DailyNote, DailyNoteService, type Duration, type Guest, type GuestMetadata, type Guide, type GuideAssignment, INSTALL_STATUSES, type InstallAccessConfig, type InstallAccessService, type InstallAccessTarget, type InstallStatus, type InstallWebhook, type InstallWebhookAccount, type InstallWebhookClaims, type InvoiceLinkResult, type Logger, type MakePaymentInput, type MakePaymentResult, type Membership, type MembershipPurchaseInput, MembershipService, type NoteMode, type Payment, type PaymentSource, PeekAccessService, type PeekAccessServiceConfig, type PeekAuthTokenClaims, type PeekAuthTokenUser, PeekGraphQLError, PeekHttpError, type PeekPlatform, PiiAccessDisabledError, type Price, type PricingActivityContext, type PricingEngine, type PricingMoney, type PricingNamedRef, type PricingOverride, type PricingOverrideFilter, PricingService, type Product, type ProductMeetingLocation, ProductService, type ProductServiceOptions, type ProductTicket, type PromoCode, type PromoCodeFixedAmount, PromoCodeService, type PromoCodeServiceOptions, type PurchasedMembership, RENTAL_PRODUCT_TYPE, RateLimitError, type RefundInput, type RefundResult, ResellerService, type ResolvedOverride, type ResolvedPricingOverride, type ResolvedResourceOption, type Resource, type ResourceOptionOverride, type ResourceOptionQuantity, type ResourcePool, type ResourcePoolAccountUser, type ResourcePoolAssignment, type ResourcePoolMode, ResourcePoolService, type Review, ReviewService, type Ticket, type Timeslot, type TimeslotFilter, TimeslotService, type UpdateEngineInput, type UpdateTimeslotResult, type UpsertOverridesInput, type UpsertOverridesResult, type Waiver, createAccessServiceForInstall, noopLogger, parseBookingWebhook, parseInstallWebhook, parseWaiverWebhook, verifyInstallWebhook };
package/dist/index.js CHANGED
@@ -225,15 +225,6 @@ var PeekHttpError = class extends Error {
225
225
  this.body = body;
226
226
  }
227
227
  };
228
- var InvalidPeekTokenError = class extends Error {
229
- /** The token field that was missing or empty (e.g. `"user.id"`). */
230
- field;
231
- constructor(field) {
232
- super(`Peek token is missing required field "${field}"`);
233
- this.name = "InvalidPeekTokenError";
234
- this.field = field;
235
- }
236
- };
237
228
  var PiiAccessDisabledError = class extends Error {
238
229
  /** The name of the operation that was blocked (e.g. `"makePayment"`). */
239
230
  operation;
@@ -2038,6 +2029,11 @@ var GraphQLClient = class {
2038
2029
  return headers;
2039
2030
  }
2040
2031
  };
2032
+
2033
+ // src/models/peek/auth-token.ts
2034
+ var PEEK_PLATFORMS = ["peek", "cng", "acme"];
2035
+
2036
+ // src/internal/peek/peek-auth-token.ts
2041
2037
  var PEEK_TOKEN_ISSUER = "app_registry_v2";
2042
2038
  var PEEK_TOKEN_AUDIENCE = "Joken";
2043
2039
  var BEARER_PREFIX = "bearer ";
@@ -2045,6 +2041,16 @@ function stripBearer(token) {
2045
2041
  const trimmed = token.trim();
2046
2042
  return trimmed.toLowerCase().startsWith(BEARER_PREFIX) ? trimmed.slice(BEARER_PREFIX.length).trim() : trimmed;
2047
2043
  }
2044
+ var NULLISH_STRINGS = /* @__PURE__ */ new Set(["", "null"]);
2045
+ function cleanTokenString(value) {
2046
+ if (typeof value !== "string") return null;
2047
+ const trimmed = value.trim();
2048
+ return NULLISH_STRINGS.has(trimmed.toLowerCase()) ? null : trimmed;
2049
+ }
2050
+ function cleanTokenPlatform(value) {
2051
+ const cleaned = cleanTokenString(value);
2052
+ return cleaned !== null && PEEK_PLATFORMS.includes(cleaned) ? cleaned : null;
2053
+ }
2048
2054
  function verifyPeekJwt(token, secret) {
2049
2055
  return jwt.verify(stripBearer(token), secret, {
2050
2056
  issuer: PEEK_TOKEN_ISSUER,
@@ -2052,16 +2058,14 @@ function verifyPeekJwt(token, secret) {
2052
2058
  });
2053
2059
  }
2054
2060
  function mapPeekTokenUser(u) {
2055
- if (!u.id) {
2056
- throw new InvalidPeekTokenError("user.id");
2057
- }
2061
+ if (!u) return null;
2058
2062
  return {
2059
- email: u.email,
2060
- id: u.id,
2061
- isAdmin: u.is_admin,
2062
- locale: u.locale,
2063
- name: u.name,
2064
- platform: u.platform
2063
+ email: cleanTokenString(u.email),
2064
+ id: cleanTokenString(u.id),
2065
+ isAdmin: typeof u.is_admin === "boolean" ? u.is_admin : null,
2066
+ locale: cleanTokenString(u.locale),
2067
+ name: cleanTokenString(u.name),
2068
+ platform: cleanTokenPlatform(u.platform)
2065
2069
  };
2066
2070
  }
2067
2071
 
@@ -3581,13 +3585,15 @@ var PeekAccessService = class {
3581
3585
  * malformed
3582
3586
  * - `TokenExpiredError` — past `exp`
3583
3587
  * - `NotBeforeError` — before `nbf`
3584
- * - `InvalidPeekTokenError` — signature valid but the `user` block is missing
3585
- * its `id`
3588
+ *
3589
+ * Claim *extraction* is defensive: once the signature verifies, a token with
3590
+ * no `user` block yields `claims.user === null`, and any individual user field
3591
+ * that is absent or a sentinel (`""`, `"null"`) is normalized to `null`. This
3592
+ * method never throws on a shape problem — only on a verification failure.
3586
3593
  *
3587
3594
  * @throws {JsonWebTokenError} signature invalid or token malformed
3588
3595
  * @throws {TokenExpiredError} token has expired
3589
3596
  * @throws {NotBeforeError} token not yet valid
3590
- * @throws {InvalidPeekTokenError} verified token has no `user.id`
3591
3597
  */
3592
3598
  verifyPeekAuthToken(token) {
3593
3599
  const payload = verifyPeekJwt(token, this.jwtSecret);
@@ -4281,9 +4287,6 @@ function extractWaiverNode(payload) {
4281
4287
  return record;
4282
4288
  }
4283
4289
 
4284
- // src/models/peek/auth-token.ts
4285
- var PEEK_PLATFORMS = ["peek", "cng", "acme"];
4286
-
4287
4290
  // src/models/peek/install.ts
4288
4291
  var INSTALL_STATUSES = [
4289
4292
  "installed",
@@ -4332,8 +4335,8 @@ function parseInstallWebhook(token, body, secret) {
4332
4335
  };
4333
4336
  }
4334
4337
  function resolveInstallUser(bodyUser, tokenUser) {
4335
- if (bodyUser?.id) return mapPeekTokenUser(bodyUser);
4336
- return tokenUser ? mapPeekTokenUser(tokenUser) : null;
4338
+ if (cleanTokenString(bodyUser?.id) !== null) return mapPeekTokenUser(bodyUser);
4339
+ return mapPeekTokenUser(tokenUser);
4337
4340
  }
4338
4341
  function verifyInstallWebhook(token, secret) {
4339
4342
  const payload = verifyPeekJwt(token, secret);
@@ -4342,10 +4345,10 @@ function verifyInstallWebhook(token, secret) {
4342
4345
  account: { id: payload.account?.id ?? "" },
4343
4346
  status: payload.status ?? "",
4344
4347
  displayVersion: payload.display_version ?? "",
4345
- user: payload.user ? mapPeekTokenUser(payload.user) : null
4348
+ user: mapPeekTokenUser(payload.user)
4346
4349
  };
4347
4350
  }
4348
4351
 
4349
- export { ACTIVITY_PRODUCT_TYPE, ADD_ON_PRODUCT_TYPE, AccountUserService, AcmeAccessService, AcmeApiError, AcmeProductService, AdminAccountRequiredError, AvailabilityService, BookingService, CngAccessService, CngApiError, CngProductService, DailyNoteService, INSTALL_STATUSES, InvalidPeekTokenError, MembershipService, PeekAccessService, PeekGraphQLError, PeekHttpError, PiiAccessDisabledError, PricingService, ProductService, PromoCodeService, RENTAL_PRODUCT_TYPE, RateLimitError, ResellerService, ResourcePoolService, ReviewService, TimeslotService, createAccessServiceForInstall, noopLogger, parseBookingWebhook, parseInstallWebhook, parseWaiverWebhook, verifyInstallWebhook };
4352
+ export { ACTIVITY_PRODUCT_TYPE, ADD_ON_PRODUCT_TYPE, AccountUserService, AcmeAccessService, AcmeApiError, AcmeProductService, AdminAccountRequiredError, AvailabilityService, BookingService, CngAccessService, CngApiError, CngProductService, DailyNoteService, INSTALL_STATUSES, MembershipService, PeekAccessService, PeekGraphQLError, PeekHttpError, PiiAccessDisabledError, PricingService, ProductService, PromoCodeService, RENTAL_PRODUCT_TYPE, RateLimitError, ResellerService, ResourcePoolService, ReviewService, TimeslotService, createAccessServiceForInstall, noopLogger, parseBookingWebhook, parseInstallWebhook, parseWaiverWebhook, verifyInstallWebhook };
4350
4353
  //# sourceMappingURL=index.js.map
4351
4354
  //# sourceMappingURL=index.js.map