@peektravel/app-utilities 0.2.10 → 0.3.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.cjs +299 -124
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +190 -26
- package/dist/index.d.ts +190 -26
- package/dist/index.js +297 -125
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -3,11 +3,11 @@ import { randomUUID } from 'crypto';
|
|
|
3
3
|
|
|
4
4
|
// src/peek-access-service.ts
|
|
5
5
|
|
|
6
|
-
// src/internal/gateway-endpoints.ts
|
|
6
|
+
// src/internal/peek/gateway-endpoints.ts
|
|
7
7
|
var SALES_ENDPOINT = "sales";
|
|
8
8
|
var V2_EXTENDABLE_SLUG = "peek_backoffice_api-v1";
|
|
9
9
|
|
|
10
|
-
// src/internal/account-users/account-user-converter.ts
|
|
10
|
+
// src/internal/peek/account-users/account-user-converter.ts
|
|
11
11
|
var ACTIVE_STATUS = "ACTIVE";
|
|
12
12
|
function fromAccountUserNode(node) {
|
|
13
13
|
if (!node || node.status !== ACTIVE_STATUS) {
|
|
@@ -35,7 +35,7 @@ function fromAccountUserNodes(nodes) {
|
|
|
35
35
|
return users;
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
-
// src/internal/account-users/account-user-queries.ts
|
|
38
|
+
// src/internal/peek/account-users/account-user-queries.ts
|
|
39
39
|
var USER_QUERY = `
|
|
40
40
|
query Sales($first: Int, $after: String) {
|
|
41
41
|
accountUsers(first: $first, after: $after) {
|
|
@@ -81,7 +81,7 @@ var USER_BY_FILTER_QUERY = `
|
|
|
81
81
|
}
|
|
82
82
|
`;
|
|
83
83
|
|
|
84
|
-
// src/internal/account-users/account-user-service.ts
|
|
84
|
+
// src/internal/peek/account-users/account-user-service.ts
|
|
85
85
|
var DEFAULT_PAGE_SIZE = 50;
|
|
86
86
|
var AccountUserService = class {
|
|
87
87
|
constructor(client, options = {}) {
|
|
@@ -135,7 +135,7 @@ var AccountUserService = class {
|
|
|
135
135
|
}
|
|
136
136
|
};
|
|
137
137
|
|
|
138
|
-
// src/internal/availability/availability-queries.ts
|
|
138
|
+
// src/internal/peek/availability/availability-queries.ts
|
|
139
139
|
var AVAILABILITY_TIMES_QUERY = `
|
|
140
140
|
query Sales($activityId: ID!, $resourceOptionQuantities: [ResourceOptionQuantityData!]!, $date: Date!) {
|
|
141
141
|
availabilityTimes(activityId: $activityId, resourceOptionQuantities: $resourceOptionQuantities, date: $date) {
|
|
@@ -160,7 +160,7 @@ var AVAILABILITY_TIMES_QUERY = `
|
|
|
160
160
|
}
|
|
161
161
|
`;
|
|
162
162
|
|
|
163
|
-
// src/internal/availability/availability-service.ts
|
|
163
|
+
// src/internal/peek/availability/availability-service.ts
|
|
164
164
|
var AvailabilityService = class {
|
|
165
165
|
constructor(client) {
|
|
166
166
|
this.client = client;
|
|
@@ -181,12 +181,12 @@ var AvailabilityService = class {
|
|
|
181
181
|
}
|
|
182
182
|
};
|
|
183
183
|
|
|
184
|
-
// src/models/product.ts
|
|
184
|
+
// src/models/peek/product.ts
|
|
185
185
|
var ACTIVITY_PRODUCT_TYPE = "ACTIVITY";
|
|
186
186
|
var RENTAL_PRODUCT_TYPE = "RENTAL";
|
|
187
187
|
var ADD_ON_PRODUCT_TYPE = "ADD-ON";
|
|
188
188
|
|
|
189
|
-
// src/internal/bookings/booking-queries.ts
|
|
189
|
+
// src/internal/peek/bookings/booking-queries.ts
|
|
190
190
|
var SEARCH_BY_PURCHASE_DATE = "purchaseDate";
|
|
191
191
|
var SEARCH_BY_ACTIVITY_DATE = "activityDate";
|
|
192
192
|
function normalizeBookingId(bookingId) {
|
|
@@ -547,7 +547,7 @@ function buildBookingsVariables(params) {
|
|
|
547
547
|
};
|
|
548
548
|
}
|
|
549
549
|
|
|
550
|
-
// src/internal/bookings/booking-converter.ts
|
|
550
|
+
// src/internal/peek/bookings/booking-converter.ts
|
|
551
551
|
var UNKNOWN = "unknown";
|
|
552
552
|
var PEEK_PRO_DEEP_LINK_BASE = "http://pro-app.peek.com/-/order";
|
|
553
553
|
var SOURCE_SOURCE_MAP = {
|
|
@@ -778,7 +778,7 @@ function mapPrice(priceData) {
|
|
|
778
778
|
};
|
|
779
779
|
}
|
|
780
780
|
|
|
781
|
-
// src/internal/bookings/booking-guest-converter.ts
|
|
781
|
+
// src/internal/peek/bookings/booking-guest-converter.ts
|
|
782
782
|
function fromBookingGuestsResponse(response) {
|
|
783
783
|
const firstEdge = (response?.sales?.edges ?? [])[0];
|
|
784
784
|
if (!firstEdge) {
|
|
@@ -799,7 +799,7 @@ function fromBookingGuestsResponse(response) {
|
|
|
799
799
|
return guests;
|
|
800
800
|
}
|
|
801
801
|
|
|
802
|
-
// src/internal/bookings/payments-on-file-converter.ts
|
|
802
|
+
// src/internal/peek/bookings/payments-on-file-converter.ts
|
|
803
803
|
function fromPaymentsOnFileResponse(response, bookingId) {
|
|
804
804
|
const firstEdge = (response?.sales?.edges ?? [])[0];
|
|
805
805
|
if (!firstEdge) {
|
|
@@ -841,7 +841,7 @@ function dateOnly(iso) {
|
|
|
841
841
|
return iso.split("T")[0] ?? iso;
|
|
842
842
|
}
|
|
843
843
|
|
|
844
|
-
// src/internal/bookings/addon-queries.ts
|
|
844
|
+
// src/internal/peek/bookings/addon-queries.ts
|
|
845
845
|
var RESERVATION_STATUS_CONFIRMED = "CONFIRMED";
|
|
846
846
|
var ADDON_OPTION_STATUS_CANCELED = "CANCELED";
|
|
847
847
|
var SALES_ADDONS_PAGE_SIZE = 100;
|
|
@@ -885,7 +885,7 @@ function buildSalesAddonsVariables(searchString) {
|
|
|
885
885
|
};
|
|
886
886
|
}
|
|
887
887
|
|
|
888
|
-
// src/internal/bookings/addon-converter.ts
|
|
888
|
+
// src/internal/peek/bookings/addon-converter.ts
|
|
889
889
|
var ERROR_INCONSISTENT_ADDON_ITEM_ID = "Add-on group contains options with mismatched item IDs";
|
|
890
890
|
function parseSaleNode(node) {
|
|
891
891
|
const bookingId = node.id || "";
|
|
@@ -947,7 +947,7 @@ function toBookingAddon(item) {
|
|
|
947
947
|
return { addonId, addonName, total: item.total, addonOptions };
|
|
948
948
|
}
|
|
949
949
|
|
|
950
|
-
// src/internal/bookings/booking-service.ts
|
|
950
|
+
// src/internal/peek/bookings/booking-service.ts
|
|
951
951
|
var DEFAULT_PAGE_SIZE2 = 50;
|
|
952
952
|
var DEFAULT_CANCEL_NOTE = "Canceled";
|
|
953
953
|
var DEFAULT_CUSTOMER_MESSAGE = "Charge initiated via API";
|
|
@@ -1697,7 +1697,7 @@ function buildCancellation(items, addonOptionId, quantity) {
|
|
|
1697
1697
|
return { bookingQuotes, canceledCount };
|
|
1698
1698
|
}
|
|
1699
1699
|
|
|
1700
|
-
// src/internal/daily-notes/daily-note-converter.ts
|
|
1700
|
+
// src/internal/peek/daily-notes/daily-note-converter.ts
|
|
1701
1701
|
function toDailyNote(response) {
|
|
1702
1702
|
const union = response?.dailyNote;
|
|
1703
1703
|
if (!union) {
|
|
@@ -1718,7 +1718,7 @@ function cleanNote(note) {
|
|
|
1718
1718
|
return { note: note.note };
|
|
1719
1719
|
}
|
|
1720
1720
|
|
|
1721
|
-
// src/internal/daily-notes/daily-note-queries.ts
|
|
1721
|
+
// src/internal/peek/daily-notes/daily-note-queries.ts
|
|
1722
1722
|
var GLOBAL_NOTE_TYPE = "DASHBOARD";
|
|
1723
1723
|
var DAILY_NOTE_TODAY_QUERY = `
|
|
1724
1724
|
query dailyNote($type: GlobalNoteType!) {
|
|
@@ -1749,7 +1749,7 @@ function buildUpsertDailyNoteVariables(note) {
|
|
|
1749
1749
|
return { input: { type: GLOBAL_NOTE_TYPE, note } };
|
|
1750
1750
|
}
|
|
1751
1751
|
|
|
1752
|
-
// src/internal/daily-notes/daily-note-service.ts
|
|
1752
|
+
// src/internal/peek/daily-notes/daily-note-service.ts
|
|
1753
1753
|
var DailyNoteService = class {
|
|
1754
1754
|
constructor(client) {
|
|
1755
1755
|
this.client = client;
|
|
@@ -1772,6 +1772,53 @@ var DailyNoteService = class {
|
|
|
1772
1772
|
return fromUpsertResponse(body.data);
|
|
1773
1773
|
}
|
|
1774
1774
|
};
|
|
1775
|
+
var TokenManager = class {
|
|
1776
|
+
constructor(options) {
|
|
1777
|
+
this.options = options;
|
|
1778
|
+
}
|
|
1779
|
+
options;
|
|
1780
|
+
cached;
|
|
1781
|
+
/**
|
|
1782
|
+
* Returns a valid bearer token, reusing the cached one until it is within
|
|
1783
|
+
* `leewaySeconds` of expiring, at which point a fresh token is minted.
|
|
1784
|
+
*/
|
|
1785
|
+
getToken() {
|
|
1786
|
+
const now = Date.now();
|
|
1787
|
+
if (this.cached && now < this.cached.expiresAtMs) {
|
|
1788
|
+
return this.cached.token;
|
|
1789
|
+
}
|
|
1790
|
+
const { secret, issuer, installId, ttlSeconds, leewaySeconds } = this.options;
|
|
1791
|
+
const token = jwt.sign({}, secret, {
|
|
1792
|
+
expiresIn: ttlSeconds,
|
|
1793
|
+
issuer,
|
|
1794
|
+
subject: installId
|
|
1795
|
+
});
|
|
1796
|
+
this.cached = {
|
|
1797
|
+
token,
|
|
1798
|
+
expiresAtMs: now + (ttlSeconds - leewaySeconds) * 1e3
|
|
1799
|
+
};
|
|
1800
|
+
return token;
|
|
1801
|
+
}
|
|
1802
|
+
};
|
|
1803
|
+
|
|
1804
|
+
// src/access-service-config.ts
|
|
1805
|
+
var DEFAULT_TOKEN_TTL_SECONDS = 3600;
|
|
1806
|
+
var DEFAULT_TOKEN_REFRESH_LEEWAY_SECONDS = 60;
|
|
1807
|
+
var DEFAULT_RETRY_DELAYS_MS = [1e3, 2e3, 4e3];
|
|
1808
|
+
function requireNonEmpty(value, name, serviceName) {
|
|
1809
|
+
if (!value) {
|
|
1810
|
+
throw new Error(`${serviceName}: "${name}" is required`);
|
|
1811
|
+
}
|
|
1812
|
+
}
|
|
1813
|
+
function createTokenManager(config) {
|
|
1814
|
+
return new TokenManager({
|
|
1815
|
+
secret: config.jwtSecret,
|
|
1816
|
+
issuer: config.issuer,
|
|
1817
|
+
installId: config.installId,
|
|
1818
|
+
ttlSeconds: config.tokenTtlSeconds ?? DEFAULT_TOKEN_TTL_SECONDS,
|
|
1819
|
+
leewaySeconds: config.tokenRefreshLeewaySeconds ?? DEFAULT_TOKEN_REFRESH_LEEWAY_SECONDS
|
|
1820
|
+
});
|
|
1821
|
+
}
|
|
1775
1822
|
|
|
1776
1823
|
// src/errors.ts
|
|
1777
1824
|
var AdminAccountRequiredError = class extends Error {
|
|
@@ -1799,11 +1846,49 @@ var PeekGraphQLError = class extends Error {
|
|
|
1799
1846
|
this.graphqlErrors = graphqlErrors;
|
|
1800
1847
|
}
|
|
1801
1848
|
};
|
|
1849
|
+
var CngApiError = class extends Error {
|
|
1850
|
+
/** The HTTP status that triggered this error. */
|
|
1851
|
+
statusCode;
|
|
1852
|
+
/** The raw response body (parsed JSON when possible, otherwise text). */
|
|
1853
|
+
body;
|
|
1854
|
+
constructor(statusCode, body, message) {
|
|
1855
|
+
super(message ?? `CNG request failed with HTTP ${statusCode}`);
|
|
1856
|
+
this.name = "CngApiError";
|
|
1857
|
+
this.statusCode = statusCode;
|
|
1858
|
+
this.body = body;
|
|
1859
|
+
}
|
|
1860
|
+
};
|
|
1802
1861
|
|
|
1803
|
-
// src/internal/
|
|
1862
|
+
// src/internal/http-transport.ts
|
|
1804
1863
|
var RATE_LIMIT_STATUS = 429;
|
|
1805
1864
|
var ADMIN_ACCOUNT_REQUIRED_STATUS = 418;
|
|
1806
1865
|
var sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
1866
|
+
async function requestWithRetry(http, url, init, label, onResponse) {
|
|
1867
|
+
const { retryDelaysMs, logger, fetchFn } = http;
|
|
1868
|
+
for (let attempt = 0; attempt <= retryDelaysMs.length; attempt++) {
|
|
1869
|
+
const response = await fetchFn(url, init);
|
|
1870
|
+
if (response.status === ADMIN_ACCOUNT_REQUIRED_STATUS) {
|
|
1871
|
+
logger.warn(`Admin account required for ${label} (HTTP 418)`, { url });
|
|
1872
|
+
throw new AdminAccountRequiredError();
|
|
1873
|
+
}
|
|
1874
|
+
if (response.status === RATE_LIMIT_STATUS) {
|
|
1875
|
+
const delay = retryDelaysMs[attempt];
|
|
1876
|
+
if (delay !== void 0) {
|
|
1877
|
+
logger.warn(
|
|
1878
|
+
`Rate limited on ${label}, retrying in ${delay}ms (attempt ${attempt + 1}/${retryDelaysMs.length})`
|
|
1879
|
+
);
|
|
1880
|
+
await sleep(delay);
|
|
1881
|
+
continue;
|
|
1882
|
+
}
|
|
1883
|
+
logger.error(`Rate limit exceeded for ${label}`, { url });
|
|
1884
|
+
throw new RateLimitError();
|
|
1885
|
+
}
|
|
1886
|
+
return onResponse(response);
|
|
1887
|
+
}
|
|
1888
|
+
throw new RateLimitError();
|
|
1889
|
+
}
|
|
1890
|
+
|
|
1891
|
+
// src/internal/peek/graphql-client.ts
|
|
1807
1892
|
var GraphQLClient = class {
|
|
1808
1893
|
constructor(options) {
|
|
1809
1894
|
this.options = options;
|
|
@@ -1811,50 +1896,39 @@ var GraphQLClient = class {
|
|
|
1811
1896
|
options;
|
|
1812
1897
|
/**
|
|
1813
1898
|
* Executes a GraphQL query against the named endpoint and returns the raw
|
|
1814
|
-
* response body. Retries on HTTP 429 per the configured backoff
|
|
1899
|
+
* response body. Retries on HTTP 429 per the configured backoff (via the
|
|
1900
|
+
* shared {@link requestWithRetry} loop).
|
|
1815
1901
|
*/
|
|
1816
1902
|
async request(endpointName, query, variables) {
|
|
1817
|
-
const {
|
|
1903
|
+
const { logger } = this.options;
|
|
1818
1904
|
const url = this.endpoint(endpointName);
|
|
1819
1905
|
const collapsedQuery = query.replace(/\s+/g, " ").trim();
|
|
1820
1906
|
logger.info("Making GraphQL request", { url, endpointName });
|
|
1821
|
-
|
|
1822
|
-
|
|
1907
|
+
return requestWithRetry(
|
|
1908
|
+
this.options,
|
|
1909
|
+
url,
|
|
1910
|
+
{
|
|
1823
1911
|
method: "POST",
|
|
1824
1912
|
headers: this.buildHeaders(),
|
|
1825
1913
|
body: JSON.stringify({ query: collapsedQuery, variables })
|
|
1826
|
-
}
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
);
|
|
1837
|
-
await sleep(delay);
|
|
1838
|
-
continue;
|
|
1914
|
+
},
|
|
1915
|
+
endpointName,
|
|
1916
|
+
async (response) => {
|
|
1917
|
+
const body = await response.json();
|
|
1918
|
+
if (body.errors) {
|
|
1919
|
+
logger.error(`GraphQL errors for ${endpointName}`, {
|
|
1920
|
+
url,
|
|
1921
|
+
graphqlErrors: JSON.stringify(body.errors)
|
|
1922
|
+
});
|
|
1923
|
+
throw new PeekGraphQLError(body.errors);
|
|
1839
1924
|
}
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
logger.error(`GraphQL errors for ${endpointName}`, {
|
|
1846
|
-
url,
|
|
1847
|
-
graphqlErrors: JSON.stringify(body.errors)
|
|
1848
|
-
});
|
|
1849
|
-
throw new PeekGraphQLError(body.errors);
|
|
1850
|
-
}
|
|
1851
|
-
if (!response.ok) {
|
|
1852
|
-
logger.error(`GraphQL request failed with HTTP ${response.status}`, { url });
|
|
1853
|
-
throw new Error(`GraphQL request failed with HTTP ${response.status}`);
|
|
1925
|
+
if (!response.ok) {
|
|
1926
|
+
logger.error(`GraphQL request failed with HTTP ${response.status}`, { url });
|
|
1927
|
+
throw new Error(`GraphQL request failed with HTTP ${response.status}`);
|
|
1928
|
+
}
|
|
1929
|
+
return body;
|
|
1854
1930
|
}
|
|
1855
|
-
|
|
1856
|
-
}
|
|
1857
|
-
throw new RateLimitError();
|
|
1931
|
+
);
|
|
1858
1932
|
}
|
|
1859
1933
|
endpoint(endpointName) {
|
|
1860
1934
|
const { baseUrl, appId, endpointPathPrefix } = this.options;
|
|
@@ -1873,7 +1947,7 @@ var GraphQLClient = class {
|
|
|
1873
1947
|
}
|
|
1874
1948
|
};
|
|
1875
1949
|
|
|
1876
|
-
// src/internal/memberships/membership-converter.ts
|
|
1950
|
+
// src/internal/peek/memberships/membership-converter.ts
|
|
1877
1951
|
function fromMembershipsResponse(response) {
|
|
1878
1952
|
return (response?.memberships ?? []).flatMap(
|
|
1879
1953
|
(membership) => (membership.membershipVariants ?? []).map((variant) => ({
|
|
@@ -1888,7 +1962,7 @@ function fromMembershipsResponse(response) {
|
|
|
1888
1962
|
);
|
|
1889
1963
|
}
|
|
1890
1964
|
|
|
1891
|
-
// src/internal/memberships/membership-queries.ts
|
|
1965
|
+
// src/internal/peek/memberships/membership-queries.ts
|
|
1892
1966
|
var MEMBERSHIPS_QUERY = `
|
|
1893
1967
|
query Sales {
|
|
1894
1968
|
memberships {
|
|
@@ -1933,7 +2007,7 @@ var CREATE_MEMBERSHIP_ORDER_FROM_QUOTE_MUTATION = `
|
|
|
1933
2007
|
}
|
|
1934
2008
|
`;
|
|
1935
2009
|
|
|
1936
|
-
// src/internal/memberships/membership-service.ts
|
|
2010
|
+
// src/internal/peek/memberships/membership-service.ts
|
|
1937
2011
|
var QUOTE_STATUS_CONFIRMED = "CONFIRMED";
|
|
1938
2012
|
var DEFAULT_BALANCE_AMOUNT = "0.00";
|
|
1939
2013
|
var DEFAULT_BALANCE_CURRENCY = "USD";
|
|
@@ -2039,7 +2113,7 @@ function validatePurchaseInput(input) {
|
|
|
2039
2113
|
}
|
|
2040
2114
|
}
|
|
2041
2115
|
|
|
2042
|
-
// src/internal/resellers/channel-converter.ts
|
|
2116
|
+
// src/internal/peek/resellers/channel-converter.ts
|
|
2043
2117
|
function fromChannelsResponse(response) {
|
|
2044
2118
|
return (response?.channels ?? []).map(fromChannelNode);
|
|
2045
2119
|
}
|
|
@@ -2060,7 +2134,7 @@ function fromChannelNode(node) {
|
|
|
2060
2134
|
};
|
|
2061
2135
|
}
|
|
2062
2136
|
|
|
2063
|
-
// src/internal/resellers/channel-queries.ts
|
|
2137
|
+
// src/internal/peek/resellers/channel-queries.ts
|
|
2064
2138
|
var CHANNELS_QUERY = `
|
|
2065
2139
|
query Sales($first: Int) {
|
|
2066
2140
|
channels {
|
|
@@ -2084,7 +2158,7 @@ var CHANNELS_QUERY = `
|
|
|
2084
2158
|
}
|
|
2085
2159
|
`;
|
|
2086
2160
|
|
|
2087
|
-
// src/internal/resellers/reseller-service.ts
|
|
2161
|
+
// src/internal/peek/resellers/reseller-service.ts
|
|
2088
2162
|
var DEFAULT_AGENTS_PER_CHANNEL = 10;
|
|
2089
2163
|
var ResellerService = class {
|
|
2090
2164
|
constructor(client) {
|
|
@@ -2103,7 +2177,7 @@ var ResellerService = class {
|
|
|
2103
2177
|
}
|
|
2104
2178
|
};
|
|
2105
2179
|
|
|
2106
|
-
// src/internal/resource-pools/resource-pool-converter.ts
|
|
2180
|
+
// src/internal/peek/resource-pools/resource-pool-converter.ts
|
|
2107
2181
|
function fromResourcePoolsResponse(response) {
|
|
2108
2182
|
return (response?.resourcePools ?? []).map(fromResourcePoolNode);
|
|
2109
2183
|
}
|
|
@@ -2131,7 +2205,7 @@ function fromAccountUser(accountUser) {
|
|
|
2131
2205
|
};
|
|
2132
2206
|
}
|
|
2133
2207
|
|
|
2134
|
-
// src/internal/resource-pools/resource-pool-queries.ts
|
|
2208
|
+
// src/internal/peek/resource-pools/resource-pool-queries.ts
|
|
2135
2209
|
var RESOURCE_POOLS_QUERY = `
|
|
2136
2210
|
query Sales($filter: ResourcePoolsFilter) {
|
|
2137
2211
|
resourcePools(filter: $filter) {
|
|
@@ -2152,7 +2226,7 @@ var RESOURCE_POOLS_QUERY = `
|
|
|
2152
2226
|
}
|
|
2153
2227
|
`;
|
|
2154
2228
|
|
|
2155
|
-
// src/internal/resource-pools/resource-pool-service.ts
|
|
2229
|
+
// src/internal/peek/resource-pools/resource-pool-service.ts
|
|
2156
2230
|
var DEFAULT_MODE = "ALL";
|
|
2157
2231
|
var ResourcePoolService = class {
|
|
2158
2232
|
constructor(client) {
|
|
@@ -2172,7 +2246,7 @@ var ResourcePoolService = class {
|
|
|
2172
2246
|
}
|
|
2173
2247
|
};
|
|
2174
2248
|
|
|
2175
|
-
// src/internal/reviews/review-converter.ts
|
|
2249
|
+
// src/internal/peek/reviews/review-converter.ts
|
|
2176
2250
|
var ISO_DATE_LENGTH = 10;
|
|
2177
2251
|
function toDateOnly(isoDateTime) {
|
|
2178
2252
|
return isoDateTime.slice(0, ISO_DATE_LENGTH);
|
|
@@ -2196,13 +2270,13 @@ function fromReviewNode(node) {
|
|
|
2196
2270
|
};
|
|
2197
2271
|
}
|
|
2198
2272
|
|
|
2199
|
-
// src/internal/reviews/review-cursor.ts
|
|
2273
|
+
// src/internal/peek/reviews/review-cursor.ts
|
|
2200
2274
|
function encodeCursor(offset, pageSize) {
|
|
2201
2275
|
const start = Math.max(0, offset - pageSize + 1);
|
|
2202
2276
|
return Buffer.from(`range:${start}..${offset},${offset}`).toString("base64");
|
|
2203
2277
|
}
|
|
2204
2278
|
|
|
2205
|
-
// src/internal/reviews/review-queries.ts
|
|
2279
|
+
// src/internal/peek/reviews/review-queries.ts
|
|
2206
2280
|
var REVIEWS_QUERY = `
|
|
2207
2281
|
query Reviews($first: Int, $filter: ReviewFilter, $after: String) {
|
|
2208
2282
|
reviews(first: $first, filter: $filter, after: $after) {
|
|
@@ -2237,7 +2311,7 @@ function buildReviewsVariables(params) {
|
|
|
2237
2311
|
};
|
|
2238
2312
|
}
|
|
2239
2313
|
|
|
2240
|
-
// src/internal/reviews/review-service.ts
|
|
2314
|
+
// src/internal/peek/reviews/review-service.ts
|
|
2241
2315
|
var DEFAULT_REVIEW_COUNT = 50;
|
|
2242
2316
|
var MIN_REVIEW_COUNT = 1;
|
|
2243
2317
|
var MAX_REVIEW_COUNT = 50;
|
|
@@ -2298,7 +2372,7 @@ var ReviewService = class {
|
|
|
2298
2372
|
}
|
|
2299
2373
|
};
|
|
2300
2374
|
|
|
2301
|
-
// src/internal/timeslots/timeslot-converter.ts
|
|
2375
|
+
// src/internal/peek/timeslots/timeslot-converter.ts
|
|
2302
2376
|
function fromTimeslotNodes(nodes, productId) {
|
|
2303
2377
|
if (!Array.isArray(nodes) || nodes.length === 0) {
|
|
2304
2378
|
return [];
|
|
@@ -2356,7 +2430,7 @@ function mapAssignedResources(allocations) {
|
|
|
2356
2430
|
});
|
|
2357
2431
|
}
|
|
2358
2432
|
|
|
2359
|
-
// src/internal/timeslots/guide-matcher.ts
|
|
2433
|
+
// src/internal/peek/timeslots/guide-matcher.ts
|
|
2360
2434
|
function matchGuideToResourcePool(guideId, guideResourcePools, accountUsers) {
|
|
2361
2435
|
const directIdMatch = guideResourcePools.find((pool) => pool.id === guideId);
|
|
2362
2436
|
if (directIdMatch) {
|
|
@@ -2390,7 +2464,7 @@ function matchGuideToResourcePool(guideId, guideResourcePools, accountUsers) {
|
|
|
2390
2464
|
return null;
|
|
2391
2465
|
}
|
|
2392
2466
|
|
|
2393
|
-
// src/internal/timeslots/resource-allocation-queries.ts
|
|
2467
|
+
// src/internal/peek/timeslots/resource-allocation-queries.ts
|
|
2394
2468
|
var RESOURCE_ALLOCATION_BULK_REQUEST_MUTATION = `
|
|
2395
2469
|
mutation ResourceAllocationBulkRequest($input: ResourceAllocationBulkRequestInput!) {
|
|
2396
2470
|
resourceAllocationBulkRequest(input: $input) {
|
|
@@ -2409,7 +2483,7 @@ function buildResourceAllocationVariables(timeslotIds, resourcePoolIds, status)
|
|
|
2409
2483
|
return { input: { timeslotIds, resourcePoolIds, status } };
|
|
2410
2484
|
}
|
|
2411
2485
|
|
|
2412
|
-
// src/internal/timeslots/timeslot-queries.ts
|
|
2486
|
+
// src/internal/peek/timeslots/timeslot-queries.ts
|
|
2413
2487
|
var TIMESLOTS_QUERY = `
|
|
2414
2488
|
query Sales($params: TimeslotsFilter!) {
|
|
2415
2489
|
timeslots(filter: $params) {
|
|
@@ -2512,7 +2586,7 @@ function buildTimeslotVariables(productId, date, filter) {
|
|
|
2512
2586
|
return { params };
|
|
2513
2587
|
}
|
|
2514
2588
|
|
|
2515
|
-
// src/internal/timeslots/timeslot-service.ts
|
|
2589
|
+
// src/internal/peek/timeslots/timeslot-service.ts
|
|
2516
2590
|
var GUIDE_CATEGORY = "guide";
|
|
2517
2591
|
var ERROR_MISSING_TIMESLOTS_OR_GUIDES = "At least one timeslot and one guide are required";
|
|
2518
2592
|
var ERROR_INVALID_ACTION = "Invalid action. Must be either assign or unassign";
|
|
@@ -2629,7 +2703,7 @@ function normalizeDate(date) {
|
|
|
2629
2703
|
return date.split("T")[0] ?? date;
|
|
2630
2704
|
}
|
|
2631
2705
|
|
|
2632
|
-
// src/internal/products/product-converter.ts
|
|
2706
|
+
// src/internal/peek/products/product-converter.ts
|
|
2633
2707
|
var ADD_ON_COLOR = "#FFFFFF";
|
|
2634
2708
|
function fromActivities(activities) {
|
|
2635
2709
|
return activities.map(fromActivity);
|
|
@@ -2668,7 +2742,7 @@ function fromItemOptionNodes(nodes) {
|
|
|
2668
2742
|
return Array.from(grouped.values());
|
|
2669
2743
|
}
|
|
2670
2744
|
|
|
2671
|
-
// src/internal/products/product-queries.ts
|
|
2745
|
+
// src/internal/peek/products/product-queries.ts
|
|
2672
2746
|
var PRODUCTS_QUERY = `
|
|
2673
2747
|
query Sales {
|
|
2674
2748
|
activities {
|
|
@@ -2708,7 +2782,7 @@ var ITEM_OPTIONS_QUERY = `
|
|
|
2708
2782
|
}
|
|
2709
2783
|
`;
|
|
2710
2784
|
|
|
2711
|
-
// src/internal/products/product-service.ts
|
|
2785
|
+
// src/internal/peek/products/product-service.ts
|
|
2712
2786
|
var DEFAULT_ITEM_OPTIONS_PAGE_SIZE = 50;
|
|
2713
2787
|
var ProductService = class {
|
|
2714
2788
|
constructor(client, options = {}) {
|
|
@@ -2785,7 +2859,7 @@ var ProductService = class {
|
|
|
2785
2859
|
}
|
|
2786
2860
|
};
|
|
2787
2861
|
|
|
2788
|
-
// src/internal/promo-codes/promo-code-queries.ts
|
|
2862
|
+
// src/internal/peek/promo-codes/promo-code-queries.ts
|
|
2789
2863
|
var PROMO_CODES_QUERY = `
|
|
2790
2864
|
query Sales($first: Int, $after: String) {
|
|
2791
2865
|
promoCodes(first: $first, after: $after) {
|
|
@@ -2824,7 +2898,7 @@ var CREATE_PROMO_CODE_MUTATION = `
|
|
|
2824
2898
|
}
|
|
2825
2899
|
`;
|
|
2826
2900
|
|
|
2827
|
-
// src/internal/promo-codes/promo-code-service.ts
|
|
2901
|
+
// src/internal/peek/promo-codes/promo-code-service.ts
|
|
2828
2902
|
var DEFAULT_PAGE_SIZE3 = 50;
|
|
2829
2903
|
var DEFAULT_CURRENCY = "USD";
|
|
2830
2904
|
var CURRENCY_PATTERN = /^[A-Z]{3}$/;
|
|
@@ -2903,34 +2977,6 @@ var PromoCodeService = class {
|
|
|
2903
2977
|
return { id: result.id, name: result.name };
|
|
2904
2978
|
}
|
|
2905
2979
|
};
|
|
2906
|
-
var TokenManager = class {
|
|
2907
|
-
constructor(options) {
|
|
2908
|
-
this.options = options;
|
|
2909
|
-
}
|
|
2910
|
-
options;
|
|
2911
|
-
cached;
|
|
2912
|
-
/**
|
|
2913
|
-
* Returns a valid bearer token, reusing the cached one until it is within
|
|
2914
|
-
* `leewaySeconds` of expiring, at which point a fresh token is minted.
|
|
2915
|
-
*/
|
|
2916
|
-
getToken() {
|
|
2917
|
-
const now = Date.now();
|
|
2918
|
-
if (this.cached && now < this.cached.expiresAtMs) {
|
|
2919
|
-
return this.cached.token;
|
|
2920
|
-
}
|
|
2921
|
-
const { secret, issuer, installId, ttlSeconds, leewaySeconds } = this.options;
|
|
2922
|
-
const token = jwt.sign({}, secret, {
|
|
2923
|
-
expiresIn: ttlSeconds,
|
|
2924
|
-
issuer,
|
|
2925
|
-
subject: installId
|
|
2926
|
-
});
|
|
2927
|
-
this.cached = {
|
|
2928
|
-
token,
|
|
2929
|
-
expiresAtMs: now + (ttlSeconds - leewaySeconds) * 1e3
|
|
2930
|
-
};
|
|
2931
|
-
return token;
|
|
2932
|
-
}
|
|
2933
|
-
};
|
|
2934
2980
|
|
|
2935
2981
|
// src/logger.ts
|
|
2936
2982
|
var noopLogger = {
|
|
@@ -2945,9 +2991,6 @@ var noopLogger = {
|
|
|
2945
2991
|
// src/peek-access-service.ts
|
|
2946
2992
|
var DEFAULT_BASE_URL = "https://apps.peekapis.com/backoffice-gql";
|
|
2947
2993
|
var DEFAULT_V2_BASE_URL = "https://app-registry.peeklabs.com/installations-api";
|
|
2948
|
-
var DEFAULT_TOKEN_TTL_SECONDS = 3600;
|
|
2949
|
-
var DEFAULT_TOKEN_REFRESH_LEEWAY_SECONDS = 60;
|
|
2950
|
-
var DEFAULT_RETRY_DELAYS_MS = [1e3, 2e3, 4e3];
|
|
2951
2994
|
var PEEK_TOKEN_ISSUER = "app_registry_v2";
|
|
2952
2995
|
var PeekAccessService = class {
|
|
2953
2996
|
client;
|
|
@@ -2966,20 +3009,14 @@ var PeekAccessService = class {
|
|
|
2966
3009
|
reviewService;
|
|
2967
3010
|
constructor(config) {
|
|
2968
3011
|
const isV2 = config.mode === "v2";
|
|
2969
|
-
requireNonEmpty(config.installId, "installId");
|
|
2970
|
-
requireNonEmpty(config.jwtSecret, "jwtSecret");
|
|
2971
|
-
requireNonEmpty(config.issuer, "issuer");
|
|
2972
|
-
requireNonEmpty(config.appId, "appId");
|
|
2973
|
-
if (!isV2) requireNonEmpty(config.gatewayKey ?? "", "gatewayKey");
|
|
3012
|
+
requireNonEmpty(config.installId, "installId", "PeekAccessService");
|
|
3013
|
+
requireNonEmpty(config.jwtSecret, "jwtSecret", "PeekAccessService");
|
|
3014
|
+
requireNonEmpty(config.issuer, "issuer", "PeekAccessService");
|
|
3015
|
+
requireNonEmpty(config.appId, "appId", "PeekAccessService");
|
|
3016
|
+
if (!isV2) requireNonEmpty(config.gatewayKey ?? "", "gatewayKey", "PeekAccessService");
|
|
2974
3017
|
this.jwtSecret = config.jwtSecret;
|
|
2975
3018
|
const logger = config.logger ?? noopLogger;
|
|
2976
|
-
const tokens =
|
|
2977
|
-
secret: config.jwtSecret,
|
|
2978
|
-
issuer: config.issuer,
|
|
2979
|
-
installId: config.installId,
|
|
2980
|
-
ttlSeconds: config.tokenTtlSeconds ?? DEFAULT_TOKEN_TTL_SECONDS,
|
|
2981
|
-
leewaySeconds: config.tokenRefreshLeewaySeconds ?? DEFAULT_TOKEN_REFRESH_LEEWAY_SECONDS
|
|
2982
|
-
});
|
|
3019
|
+
const tokens = createTokenManager(config);
|
|
2983
3020
|
const defaultBaseUrl = isV2 ? DEFAULT_V2_BASE_URL : DEFAULT_BASE_URL;
|
|
2984
3021
|
this.client = new GraphQLClient({
|
|
2985
3022
|
baseUrl: config.baseUrl ?? defaultBaseUrl,
|
|
@@ -3305,13 +3342,148 @@ var PeekAccessService = class {
|
|
|
3305
3342
|
return this.getReviewService().getReviews(productId, reviewCount, reviewOffset);
|
|
3306
3343
|
}
|
|
3307
3344
|
};
|
|
3308
|
-
|
|
3309
|
-
|
|
3310
|
-
|
|
3311
|
-
|
|
3345
|
+
|
|
3346
|
+
// src/internal/cng/endpoints.ts
|
|
3347
|
+
var CNG_EXTENDABLE_SLUG = "cng_backoffice_api-v1";
|
|
3348
|
+
var PRODUCTS_PATH = "api/v2/commerce-config/products";
|
|
3349
|
+
|
|
3350
|
+
// src/models/cng/product.ts
|
|
3351
|
+
var ACTIVITY_PRODUCT_TYPE2 = "ACTIVITY";
|
|
3352
|
+
|
|
3353
|
+
// src/internal/cng/products/product-converter.ts
|
|
3354
|
+
function fromProductNodes(nodes) {
|
|
3355
|
+
return nodes.map(fromProductNode);
|
|
3356
|
+
}
|
|
3357
|
+
function fromProductNode(node) {
|
|
3358
|
+
return {
|
|
3359
|
+
productId: node.id || "",
|
|
3360
|
+
name: node.name || "",
|
|
3361
|
+
type: node.product_type || ACTIVITY_PRODUCT_TYPE2,
|
|
3362
|
+
color: node.color_hex || "",
|
|
3363
|
+
tickets: (node.tickets ?? []).map((ticket) => ({
|
|
3364
|
+
id: ticket.id,
|
|
3365
|
+
name: ticket.name
|
|
3366
|
+
}))
|
|
3367
|
+
};
|
|
3312
3368
|
}
|
|
3313
3369
|
|
|
3314
|
-
// src/internal/
|
|
3370
|
+
// src/internal/cng/products/product-service.ts
|
|
3371
|
+
var CngProductService = class {
|
|
3372
|
+
constructor(client) {
|
|
3373
|
+
this.client = client;
|
|
3374
|
+
}
|
|
3375
|
+
client;
|
|
3376
|
+
/**
|
|
3377
|
+
* Returns every activity as a single flat list.
|
|
3378
|
+
*
|
|
3379
|
+
* @example
|
|
3380
|
+
* ```ts
|
|
3381
|
+
* const activities = await cng.getProductService().getAllActivities();
|
|
3382
|
+
* ```
|
|
3383
|
+
*/
|
|
3384
|
+
async getAllActivities() {
|
|
3385
|
+
const body = await this.client.get(
|
|
3386
|
+
PRODUCTS_PATH
|
|
3387
|
+
);
|
|
3388
|
+
const nodes = Array.isArray(body) ? body : body?.products ?? [];
|
|
3389
|
+
return fromProductNodes(nodes ?? []);
|
|
3390
|
+
}
|
|
3391
|
+
};
|
|
3392
|
+
|
|
3393
|
+
// src/internal/cng/rest-client.ts
|
|
3394
|
+
var RestClient = class {
|
|
3395
|
+
constructor(options) {
|
|
3396
|
+
this.options = options;
|
|
3397
|
+
}
|
|
3398
|
+
options;
|
|
3399
|
+
/**
|
|
3400
|
+
* Issues a GET against the named REST path and returns the parsed JSON body.
|
|
3401
|
+
* Retries on HTTP 429 per the configured backoff (via the shared
|
|
3402
|
+
* {@link requestWithRetry} loop).
|
|
3403
|
+
*
|
|
3404
|
+
* @throws {AdminAccountRequiredError} on HTTP 418
|
|
3405
|
+
* @throws {RateLimitError} on HTTP 429 after retries are exhausted
|
|
3406
|
+
* @throws {CngApiError} on any other non-2xx response
|
|
3407
|
+
*/
|
|
3408
|
+
async get(path) {
|
|
3409
|
+
const { logger } = this.options;
|
|
3410
|
+
const url = this.endpoint(path);
|
|
3411
|
+
logger.info("Making CNG request", { url, path });
|
|
3412
|
+
return requestWithRetry(
|
|
3413
|
+
this.options,
|
|
3414
|
+
url,
|
|
3415
|
+
{ method: "GET", headers: this.buildHeaders() },
|
|
3416
|
+
path,
|
|
3417
|
+
async (response) => {
|
|
3418
|
+
const body = await this.parseBody(response);
|
|
3419
|
+
if (!response.ok) {
|
|
3420
|
+
logger.error(`CNG request failed with HTTP ${response.status}`, { url });
|
|
3421
|
+
throw new CngApiError(response.status, body);
|
|
3422
|
+
}
|
|
3423
|
+
return body;
|
|
3424
|
+
}
|
|
3425
|
+
);
|
|
3426
|
+
}
|
|
3427
|
+
/** Reads the response body as JSON, falling back to raw text when unparseable. */
|
|
3428
|
+
async parseBody(response) {
|
|
3429
|
+
const text = await response.text();
|
|
3430
|
+
try {
|
|
3431
|
+
return JSON.parse(text);
|
|
3432
|
+
} catch {
|
|
3433
|
+
return text;
|
|
3434
|
+
}
|
|
3435
|
+
}
|
|
3436
|
+
endpoint(path) {
|
|
3437
|
+
const { baseUrl, appId, extendableSlug } = this.options;
|
|
3438
|
+
return `${baseUrl}/${appId}/${extendableSlug}/${path}`;
|
|
3439
|
+
}
|
|
3440
|
+
buildHeaders() {
|
|
3441
|
+
return {
|
|
3442
|
+
"X-Peek-Auth": `Bearer ${this.options.getToken()}`,
|
|
3443
|
+
"Content-Type": "application/json"
|
|
3444
|
+
};
|
|
3445
|
+
}
|
|
3446
|
+
};
|
|
3447
|
+
|
|
3448
|
+
// src/cng-access-service.ts
|
|
3449
|
+
var DEFAULT_BASE_URL2 = "https://app-registry.peeklabs.com/installations-api";
|
|
3450
|
+
var CngAccessService = class {
|
|
3451
|
+
client;
|
|
3452
|
+
productService;
|
|
3453
|
+
constructor(config) {
|
|
3454
|
+
requireNonEmpty(config.installId, "installId", "CngAccessService");
|
|
3455
|
+
requireNonEmpty(config.jwtSecret, "jwtSecret", "CngAccessService");
|
|
3456
|
+
requireNonEmpty(config.issuer, "issuer", "CngAccessService");
|
|
3457
|
+
requireNonEmpty(config.appId, "appId", "CngAccessService");
|
|
3458
|
+
const logger = config.logger ?? noopLogger;
|
|
3459
|
+
const tokens = createTokenManager(config);
|
|
3460
|
+
this.client = new RestClient({
|
|
3461
|
+
baseUrl: config.baseUrl ?? DEFAULT_BASE_URL2,
|
|
3462
|
+
appId: config.appId,
|
|
3463
|
+
extendableSlug: CNG_EXTENDABLE_SLUG,
|
|
3464
|
+
getToken: () => tokens.getToken(),
|
|
3465
|
+
retryDelaysMs: config.retryDelaysMs ?? DEFAULT_RETRY_DELAYS_MS,
|
|
3466
|
+
logger,
|
|
3467
|
+
fetchFn: config.fetch ?? globalThis.fetch
|
|
3468
|
+
});
|
|
3469
|
+
}
|
|
3470
|
+
/**
|
|
3471
|
+
* Returns the {@link CngProductService} for this install, bound to the shared
|
|
3472
|
+
* authenticated transport. The instance is created lazily and reused.
|
|
3473
|
+
*/
|
|
3474
|
+
getProductService() {
|
|
3475
|
+
if (!this.productService) {
|
|
3476
|
+
this.productService = new CngProductService(this.client);
|
|
3477
|
+
}
|
|
3478
|
+
return this.productService;
|
|
3479
|
+
}
|
|
3480
|
+
/** All activities. Delegates to {@link CngProductService.getAllActivities}. */
|
|
3481
|
+
getAllActivities() {
|
|
3482
|
+
return this.getProductService().getAllActivities();
|
|
3483
|
+
}
|
|
3484
|
+
};
|
|
3485
|
+
|
|
3486
|
+
// src/internal/peek/bookings/booking-webhook.ts
|
|
3315
3487
|
var PAYLOAD_BOOKING_KEY = "booking";
|
|
3316
3488
|
var VALUE_OPEN_TOKEN = "value {";
|
|
3317
3489
|
var PRICE_BREAKDOWN_KEYS = [
|
|
@@ -3361,7 +3533,7 @@ function hasPriceBreakdown(node) {
|
|
|
3361
3533
|
return PRICE_BREAKDOWN_KEYS.some((key) => key in value);
|
|
3362
3534
|
}
|
|
3363
3535
|
|
|
3364
|
-
// src/internal/waivers/waiver-webhook.ts
|
|
3536
|
+
// src/internal/peek/waivers/waiver-webhook.ts
|
|
3365
3537
|
var PAYLOAD_WAIVER_KEY = "waiver";
|
|
3366
3538
|
function parseWaiverWebhook(payload) {
|
|
3367
3539
|
return fromWaiverNode(extractWaiverNode(payload));
|
|
@@ -3396,6 +3568,6 @@ function extractWaiverNode(payload) {
|
|
|
3396
3568
|
return record;
|
|
3397
3569
|
}
|
|
3398
3570
|
|
|
3399
|
-
export { ACTIVITY_PRODUCT_TYPE, ADD_ON_PRODUCT_TYPE, AccountUserService, AdminAccountRequiredError, AvailabilityService, BookingService, DailyNoteService, MembershipService, PeekAccessService, PeekGraphQLError, ProductService, PromoCodeService, RENTAL_PRODUCT_TYPE, RateLimitError, ResellerService, ResourcePoolService, ReviewService, TimeslotService, noopLogger, parseBookingWebhook, parseWaiverWebhook };
|
|
3571
|
+
export { ACTIVITY_PRODUCT_TYPE, ADD_ON_PRODUCT_TYPE, AccountUserService, AdminAccountRequiredError, AvailabilityService, BookingService, CngAccessService, CngApiError, CngProductService, DailyNoteService, MembershipService, PeekAccessService, PeekGraphQLError, ProductService, PromoCodeService, RENTAL_PRODUCT_TYPE, RateLimitError, ResellerService, ResourcePoolService, ReviewService, TimeslotService, noopLogger, parseBookingWebhook, parseWaiverWebhook };
|
|
3400
3572
|
//# sourceMappingURL=index.js.map
|
|
3401
3573
|
//# sourceMappingURL=index.js.map
|