@peektravel/app-utilities 0.2.10 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +301 -125
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +199 -26
- package/dist/index.d.ts +199 -26
- package/dist/index.js +299 -126
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -25,11 +25,11 @@ var jwt__namespace = /*#__PURE__*/_interopNamespace(jwt);
|
|
|
25
25
|
|
|
26
26
|
// src/peek-access-service.ts
|
|
27
27
|
|
|
28
|
-
// src/internal/gateway-endpoints.ts
|
|
28
|
+
// src/internal/peek/gateway-endpoints.ts
|
|
29
29
|
var SALES_ENDPOINT = "sales";
|
|
30
30
|
var V2_EXTENDABLE_SLUG = "peek_backoffice_api-v1";
|
|
31
31
|
|
|
32
|
-
// src/internal/account-users/account-user-converter.ts
|
|
32
|
+
// src/internal/peek/account-users/account-user-converter.ts
|
|
33
33
|
var ACTIVE_STATUS = "ACTIVE";
|
|
34
34
|
function fromAccountUserNode(node) {
|
|
35
35
|
if (!node || node.status !== ACTIVE_STATUS) {
|
|
@@ -57,7 +57,7 @@ function fromAccountUserNodes(nodes) {
|
|
|
57
57
|
return users;
|
|
58
58
|
}
|
|
59
59
|
|
|
60
|
-
// src/internal/account-users/account-user-queries.ts
|
|
60
|
+
// src/internal/peek/account-users/account-user-queries.ts
|
|
61
61
|
var USER_QUERY = `
|
|
62
62
|
query Sales($first: Int, $after: String) {
|
|
63
63
|
accountUsers(first: $first, after: $after) {
|
|
@@ -103,7 +103,7 @@ var USER_BY_FILTER_QUERY = `
|
|
|
103
103
|
}
|
|
104
104
|
`;
|
|
105
105
|
|
|
106
|
-
// src/internal/account-users/account-user-service.ts
|
|
106
|
+
// src/internal/peek/account-users/account-user-service.ts
|
|
107
107
|
var DEFAULT_PAGE_SIZE = 50;
|
|
108
108
|
var AccountUserService = class {
|
|
109
109
|
constructor(client, options = {}) {
|
|
@@ -157,7 +157,7 @@ var AccountUserService = class {
|
|
|
157
157
|
}
|
|
158
158
|
};
|
|
159
159
|
|
|
160
|
-
// src/internal/availability/availability-queries.ts
|
|
160
|
+
// src/internal/peek/availability/availability-queries.ts
|
|
161
161
|
var AVAILABILITY_TIMES_QUERY = `
|
|
162
162
|
query Sales($activityId: ID!, $resourceOptionQuantities: [ResourceOptionQuantityData!]!, $date: Date!) {
|
|
163
163
|
availabilityTimes(activityId: $activityId, resourceOptionQuantities: $resourceOptionQuantities, date: $date) {
|
|
@@ -182,7 +182,7 @@ var AVAILABILITY_TIMES_QUERY = `
|
|
|
182
182
|
}
|
|
183
183
|
`;
|
|
184
184
|
|
|
185
|
-
// src/internal/availability/availability-service.ts
|
|
185
|
+
// src/internal/peek/availability/availability-service.ts
|
|
186
186
|
var AvailabilityService = class {
|
|
187
187
|
constructor(client) {
|
|
188
188
|
this.client = client;
|
|
@@ -203,12 +203,12 @@ var AvailabilityService = class {
|
|
|
203
203
|
}
|
|
204
204
|
};
|
|
205
205
|
|
|
206
|
-
// src/models/product.ts
|
|
206
|
+
// src/models/peek/product.ts
|
|
207
207
|
var ACTIVITY_PRODUCT_TYPE = "ACTIVITY";
|
|
208
208
|
var RENTAL_PRODUCT_TYPE = "RENTAL";
|
|
209
209
|
var ADD_ON_PRODUCT_TYPE = "ADD-ON";
|
|
210
210
|
|
|
211
|
-
// src/internal/bookings/booking-queries.ts
|
|
211
|
+
// src/internal/peek/bookings/booking-queries.ts
|
|
212
212
|
var SEARCH_BY_PURCHASE_DATE = "purchaseDate";
|
|
213
213
|
var SEARCH_BY_ACTIVITY_DATE = "activityDate";
|
|
214
214
|
function normalizeBookingId(bookingId) {
|
|
@@ -569,7 +569,7 @@ function buildBookingsVariables(params) {
|
|
|
569
569
|
};
|
|
570
570
|
}
|
|
571
571
|
|
|
572
|
-
// src/internal/bookings/booking-converter.ts
|
|
572
|
+
// src/internal/peek/bookings/booking-converter.ts
|
|
573
573
|
var UNKNOWN = "unknown";
|
|
574
574
|
var PEEK_PRO_DEEP_LINK_BASE = "http://pro-app.peek.com/-/order";
|
|
575
575
|
var SOURCE_SOURCE_MAP = {
|
|
@@ -800,7 +800,7 @@ function mapPrice(priceData) {
|
|
|
800
800
|
};
|
|
801
801
|
}
|
|
802
802
|
|
|
803
|
-
// src/internal/bookings/booking-guest-converter.ts
|
|
803
|
+
// src/internal/peek/bookings/booking-guest-converter.ts
|
|
804
804
|
function fromBookingGuestsResponse(response) {
|
|
805
805
|
const firstEdge = (response?.sales?.edges ?? [])[0];
|
|
806
806
|
if (!firstEdge) {
|
|
@@ -821,7 +821,7 @@ function fromBookingGuestsResponse(response) {
|
|
|
821
821
|
return guests;
|
|
822
822
|
}
|
|
823
823
|
|
|
824
|
-
// src/internal/bookings/payments-on-file-converter.ts
|
|
824
|
+
// src/internal/peek/bookings/payments-on-file-converter.ts
|
|
825
825
|
function fromPaymentsOnFileResponse(response, bookingId) {
|
|
826
826
|
const firstEdge = (response?.sales?.edges ?? [])[0];
|
|
827
827
|
if (!firstEdge) {
|
|
@@ -863,7 +863,7 @@ function dateOnly(iso) {
|
|
|
863
863
|
return iso.split("T")[0] ?? iso;
|
|
864
864
|
}
|
|
865
865
|
|
|
866
|
-
// src/internal/bookings/addon-queries.ts
|
|
866
|
+
// src/internal/peek/bookings/addon-queries.ts
|
|
867
867
|
var RESERVATION_STATUS_CONFIRMED = "CONFIRMED";
|
|
868
868
|
var ADDON_OPTION_STATUS_CANCELED = "CANCELED";
|
|
869
869
|
var SALES_ADDONS_PAGE_SIZE = 100;
|
|
@@ -907,7 +907,7 @@ function buildSalesAddonsVariables(searchString) {
|
|
|
907
907
|
};
|
|
908
908
|
}
|
|
909
909
|
|
|
910
|
-
// src/internal/bookings/addon-converter.ts
|
|
910
|
+
// src/internal/peek/bookings/addon-converter.ts
|
|
911
911
|
var ERROR_INCONSISTENT_ADDON_ITEM_ID = "Add-on group contains options with mismatched item IDs";
|
|
912
912
|
function parseSaleNode(node) {
|
|
913
913
|
const bookingId = node.id || "";
|
|
@@ -969,7 +969,7 @@ function toBookingAddon(item) {
|
|
|
969
969
|
return { addonId, addonName, total: item.total, addonOptions };
|
|
970
970
|
}
|
|
971
971
|
|
|
972
|
-
// src/internal/bookings/booking-service.ts
|
|
972
|
+
// src/internal/peek/bookings/booking-service.ts
|
|
973
973
|
var DEFAULT_PAGE_SIZE2 = 50;
|
|
974
974
|
var DEFAULT_CANCEL_NOTE = "Canceled";
|
|
975
975
|
var DEFAULT_CUSTOMER_MESSAGE = "Charge initiated via API";
|
|
@@ -1719,7 +1719,7 @@ function buildCancellation(items, addonOptionId, quantity) {
|
|
|
1719
1719
|
return { bookingQuotes, canceledCount };
|
|
1720
1720
|
}
|
|
1721
1721
|
|
|
1722
|
-
// src/internal/daily-notes/daily-note-converter.ts
|
|
1722
|
+
// src/internal/peek/daily-notes/daily-note-converter.ts
|
|
1723
1723
|
function toDailyNote(response) {
|
|
1724
1724
|
const union = response?.dailyNote;
|
|
1725
1725
|
if (!union) {
|
|
@@ -1740,7 +1740,7 @@ function cleanNote(note) {
|
|
|
1740
1740
|
return { note: note.note };
|
|
1741
1741
|
}
|
|
1742
1742
|
|
|
1743
|
-
// src/internal/daily-notes/daily-note-queries.ts
|
|
1743
|
+
// src/internal/peek/daily-notes/daily-note-queries.ts
|
|
1744
1744
|
var GLOBAL_NOTE_TYPE = "DASHBOARD";
|
|
1745
1745
|
var DAILY_NOTE_TODAY_QUERY = `
|
|
1746
1746
|
query dailyNote($type: GlobalNoteType!) {
|
|
@@ -1771,7 +1771,7 @@ function buildUpsertDailyNoteVariables(note) {
|
|
|
1771
1771
|
return { input: { type: GLOBAL_NOTE_TYPE, note } };
|
|
1772
1772
|
}
|
|
1773
1773
|
|
|
1774
|
-
// src/internal/daily-notes/daily-note-service.ts
|
|
1774
|
+
// src/internal/peek/daily-notes/daily-note-service.ts
|
|
1775
1775
|
var DailyNoteService = class {
|
|
1776
1776
|
constructor(client) {
|
|
1777
1777
|
this.client = client;
|
|
@@ -1794,6 +1794,53 @@ var DailyNoteService = class {
|
|
|
1794
1794
|
return fromUpsertResponse(body.data);
|
|
1795
1795
|
}
|
|
1796
1796
|
};
|
|
1797
|
+
var TokenManager = class {
|
|
1798
|
+
constructor(options) {
|
|
1799
|
+
this.options = options;
|
|
1800
|
+
}
|
|
1801
|
+
options;
|
|
1802
|
+
cached;
|
|
1803
|
+
/**
|
|
1804
|
+
* Returns a valid bearer token, reusing the cached one until it is within
|
|
1805
|
+
* `leewaySeconds` of expiring, at which point a fresh token is minted.
|
|
1806
|
+
*/
|
|
1807
|
+
getToken() {
|
|
1808
|
+
const now = Date.now();
|
|
1809
|
+
if (this.cached && now < this.cached.expiresAtMs) {
|
|
1810
|
+
return this.cached.token;
|
|
1811
|
+
}
|
|
1812
|
+
const { secret, issuer, installId, ttlSeconds, leewaySeconds } = this.options;
|
|
1813
|
+
const token = jwt__namespace.sign({}, secret, {
|
|
1814
|
+
expiresIn: ttlSeconds,
|
|
1815
|
+
issuer,
|
|
1816
|
+
subject: installId
|
|
1817
|
+
});
|
|
1818
|
+
this.cached = {
|
|
1819
|
+
token,
|
|
1820
|
+
expiresAtMs: now + (ttlSeconds - leewaySeconds) * 1e3
|
|
1821
|
+
};
|
|
1822
|
+
return token;
|
|
1823
|
+
}
|
|
1824
|
+
};
|
|
1825
|
+
|
|
1826
|
+
// src/access-service-config.ts
|
|
1827
|
+
var DEFAULT_TOKEN_TTL_SECONDS = 3600;
|
|
1828
|
+
var DEFAULT_TOKEN_REFRESH_LEEWAY_SECONDS = 60;
|
|
1829
|
+
var DEFAULT_RETRY_DELAYS_MS = [1e3, 2e3, 4e3];
|
|
1830
|
+
function requireNonEmpty(value, name, serviceName) {
|
|
1831
|
+
if (!value) {
|
|
1832
|
+
throw new Error(`${serviceName}: "${name}" is required`);
|
|
1833
|
+
}
|
|
1834
|
+
}
|
|
1835
|
+
function createTokenManager(config) {
|
|
1836
|
+
return new TokenManager({
|
|
1837
|
+
secret: config.jwtSecret,
|
|
1838
|
+
issuer: config.issuer,
|
|
1839
|
+
installId: config.installId,
|
|
1840
|
+
ttlSeconds: config.tokenTtlSeconds ?? DEFAULT_TOKEN_TTL_SECONDS,
|
|
1841
|
+
leewaySeconds: config.tokenRefreshLeewaySeconds ?? DEFAULT_TOKEN_REFRESH_LEEWAY_SECONDS
|
|
1842
|
+
});
|
|
1843
|
+
}
|
|
1797
1844
|
|
|
1798
1845
|
// src/errors.ts
|
|
1799
1846
|
var AdminAccountRequiredError = class extends Error {
|
|
@@ -1821,11 +1868,49 @@ var PeekGraphQLError = class extends Error {
|
|
|
1821
1868
|
this.graphqlErrors = graphqlErrors;
|
|
1822
1869
|
}
|
|
1823
1870
|
};
|
|
1871
|
+
var CngApiError = class extends Error {
|
|
1872
|
+
/** The HTTP status that triggered this error. */
|
|
1873
|
+
statusCode;
|
|
1874
|
+
/** The raw response body (parsed JSON when possible, otherwise text). */
|
|
1875
|
+
body;
|
|
1876
|
+
constructor(statusCode, body, message) {
|
|
1877
|
+
super(message ?? `CNG request failed with HTTP ${statusCode}`);
|
|
1878
|
+
this.name = "CngApiError";
|
|
1879
|
+
this.statusCode = statusCode;
|
|
1880
|
+
this.body = body;
|
|
1881
|
+
}
|
|
1882
|
+
};
|
|
1824
1883
|
|
|
1825
|
-
// src/internal/
|
|
1884
|
+
// src/internal/http-transport.ts
|
|
1826
1885
|
var RATE_LIMIT_STATUS = 429;
|
|
1827
1886
|
var ADMIN_ACCOUNT_REQUIRED_STATUS = 418;
|
|
1828
1887
|
var sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
1888
|
+
async function requestWithRetry(http, url, init, label, onResponse) {
|
|
1889
|
+
const { retryDelaysMs, logger, fetchFn } = http;
|
|
1890
|
+
for (let attempt = 0; attempt <= retryDelaysMs.length; attempt++) {
|
|
1891
|
+
const response = await fetchFn(url, init);
|
|
1892
|
+
if (response.status === ADMIN_ACCOUNT_REQUIRED_STATUS) {
|
|
1893
|
+
logger.warn(`Admin account required for ${label} (HTTP 418)`, { url });
|
|
1894
|
+
throw new AdminAccountRequiredError();
|
|
1895
|
+
}
|
|
1896
|
+
if (response.status === RATE_LIMIT_STATUS) {
|
|
1897
|
+
const delay = retryDelaysMs[attempt];
|
|
1898
|
+
if (delay !== void 0) {
|
|
1899
|
+
logger.warn(
|
|
1900
|
+
`Rate limited on ${label}, retrying in ${delay}ms (attempt ${attempt + 1}/${retryDelaysMs.length})`
|
|
1901
|
+
);
|
|
1902
|
+
await sleep(delay);
|
|
1903
|
+
continue;
|
|
1904
|
+
}
|
|
1905
|
+
logger.error(`Rate limit exceeded for ${label}`, { url });
|
|
1906
|
+
throw new RateLimitError();
|
|
1907
|
+
}
|
|
1908
|
+
return onResponse(response);
|
|
1909
|
+
}
|
|
1910
|
+
throw new RateLimitError();
|
|
1911
|
+
}
|
|
1912
|
+
|
|
1913
|
+
// src/internal/peek/graphql-client.ts
|
|
1829
1914
|
var GraphQLClient = class {
|
|
1830
1915
|
constructor(options) {
|
|
1831
1916
|
this.options = options;
|
|
@@ -1833,50 +1918,39 @@ var GraphQLClient = class {
|
|
|
1833
1918
|
options;
|
|
1834
1919
|
/**
|
|
1835
1920
|
* Executes a GraphQL query against the named endpoint and returns the raw
|
|
1836
|
-
* response body. Retries on HTTP 429 per the configured backoff
|
|
1921
|
+
* response body. Retries on HTTP 429 per the configured backoff (via the
|
|
1922
|
+
* shared {@link requestWithRetry} loop).
|
|
1837
1923
|
*/
|
|
1838
1924
|
async request(endpointName, query, variables) {
|
|
1839
|
-
const {
|
|
1925
|
+
const { logger } = this.options;
|
|
1840
1926
|
const url = this.endpoint(endpointName);
|
|
1841
1927
|
const collapsedQuery = query.replace(/\s+/g, " ").trim();
|
|
1842
1928
|
logger.info("Making GraphQL request", { url, endpointName });
|
|
1843
|
-
|
|
1844
|
-
|
|
1929
|
+
return requestWithRetry(
|
|
1930
|
+
this.options,
|
|
1931
|
+
url,
|
|
1932
|
+
{
|
|
1845
1933
|
method: "POST",
|
|
1846
1934
|
headers: this.buildHeaders(),
|
|
1847
1935
|
body: JSON.stringify({ query: collapsedQuery, variables })
|
|
1848
|
-
}
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
);
|
|
1859
|
-
await sleep(delay);
|
|
1860
|
-
continue;
|
|
1936
|
+
},
|
|
1937
|
+
endpointName,
|
|
1938
|
+
async (response) => {
|
|
1939
|
+
const body = await response.json();
|
|
1940
|
+
if (body.errors) {
|
|
1941
|
+
logger.error(`GraphQL errors for ${endpointName}`, {
|
|
1942
|
+
url,
|
|
1943
|
+
graphqlErrors: JSON.stringify(body.errors)
|
|
1944
|
+
});
|
|
1945
|
+
throw new PeekGraphQLError(body.errors);
|
|
1861
1946
|
}
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
logger.error(`GraphQL errors for ${endpointName}`, {
|
|
1868
|
-
url,
|
|
1869
|
-
graphqlErrors: JSON.stringify(body.errors)
|
|
1870
|
-
});
|
|
1871
|
-
throw new PeekGraphQLError(body.errors);
|
|
1872
|
-
}
|
|
1873
|
-
if (!response.ok) {
|
|
1874
|
-
logger.error(`GraphQL request failed with HTTP ${response.status}`, { url });
|
|
1875
|
-
throw new Error(`GraphQL request failed with HTTP ${response.status}`);
|
|
1947
|
+
if (!response.ok) {
|
|
1948
|
+
logger.error(`GraphQL request failed with HTTP ${response.status}`, { url });
|
|
1949
|
+
throw new Error(`GraphQL request failed with HTTP ${response.status}`);
|
|
1950
|
+
}
|
|
1951
|
+
return body;
|
|
1876
1952
|
}
|
|
1877
|
-
|
|
1878
|
-
}
|
|
1879
|
-
throw new RateLimitError();
|
|
1953
|
+
);
|
|
1880
1954
|
}
|
|
1881
1955
|
endpoint(endpointName) {
|
|
1882
1956
|
const { baseUrl, appId, endpointPathPrefix } = this.options;
|
|
@@ -1895,7 +1969,7 @@ var GraphQLClient = class {
|
|
|
1895
1969
|
}
|
|
1896
1970
|
};
|
|
1897
1971
|
|
|
1898
|
-
// src/internal/memberships/membership-converter.ts
|
|
1972
|
+
// src/internal/peek/memberships/membership-converter.ts
|
|
1899
1973
|
function fromMembershipsResponse(response) {
|
|
1900
1974
|
return (response?.memberships ?? []).flatMap(
|
|
1901
1975
|
(membership) => (membership.membershipVariants ?? []).map((variant) => ({
|
|
@@ -1910,7 +1984,7 @@ function fromMembershipsResponse(response) {
|
|
|
1910
1984
|
);
|
|
1911
1985
|
}
|
|
1912
1986
|
|
|
1913
|
-
// src/internal/memberships/membership-queries.ts
|
|
1987
|
+
// src/internal/peek/memberships/membership-queries.ts
|
|
1914
1988
|
var MEMBERSHIPS_QUERY = `
|
|
1915
1989
|
query Sales {
|
|
1916
1990
|
memberships {
|
|
@@ -1955,7 +2029,7 @@ var CREATE_MEMBERSHIP_ORDER_FROM_QUOTE_MUTATION = `
|
|
|
1955
2029
|
}
|
|
1956
2030
|
`;
|
|
1957
2031
|
|
|
1958
|
-
// src/internal/memberships/membership-service.ts
|
|
2032
|
+
// src/internal/peek/memberships/membership-service.ts
|
|
1959
2033
|
var QUOTE_STATUS_CONFIRMED = "CONFIRMED";
|
|
1960
2034
|
var DEFAULT_BALANCE_AMOUNT = "0.00";
|
|
1961
2035
|
var DEFAULT_BALANCE_CURRENCY = "USD";
|
|
@@ -2061,7 +2135,7 @@ function validatePurchaseInput(input) {
|
|
|
2061
2135
|
}
|
|
2062
2136
|
}
|
|
2063
2137
|
|
|
2064
|
-
// src/internal/resellers/channel-converter.ts
|
|
2138
|
+
// src/internal/peek/resellers/channel-converter.ts
|
|
2065
2139
|
function fromChannelsResponse(response) {
|
|
2066
2140
|
return (response?.channels ?? []).map(fromChannelNode);
|
|
2067
2141
|
}
|
|
@@ -2082,7 +2156,7 @@ function fromChannelNode(node) {
|
|
|
2082
2156
|
};
|
|
2083
2157
|
}
|
|
2084
2158
|
|
|
2085
|
-
// src/internal/resellers/channel-queries.ts
|
|
2159
|
+
// src/internal/peek/resellers/channel-queries.ts
|
|
2086
2160
|
var CHANNELS_QUERY = `
|
|
2087
2161
|
query Sales($first: Int) {
|
|
2088
2162
|
channels {
|
|
@@ -2106,7 +2180,7 @@ var CHANNELS_QUERY = `
|
|
|
2106
2180
|
}
|
|
2107
2181
|
`;
|
|
2108
2182
|
|
|
2109
|
-
// src/internal/resellers/reseller-service.ts
|
|
2183
|
+
// src/internal/peek/resellers/reseller-service.ts
|
|
2110
2184
|
var DEFAULT_AGENTS_PER_CHANNEL = 10;
|
|
2111
2185
|
var ResellerService = class {
|
|
2112
2186
|
constructor(client) {
|
|
@@ -2125,7 +2199,7 @@ var ResellerService = class {
|
|
|
2125
2199
|
}
|
|
2126
2200
|
};
|
|
2127
2201
|
|
|
2128
|
-
// src/internal/resource-pools/resource-pool-converter.ts
|
|
2202
|
+
// src/internal/peek/resource-pools/resource-pool-converter.ts
|
|
2129
2203
|
function fromResourcePoolsResponse(response) {
|
|
2130
2204
|
return (response?.resourcePools ?? []).map(fromResourcePoolNode);
|
|
2131
2205
|
}
|
|
@@ -2153,7 +2227,7 @@ function fromAccountUser(accountUser) {
|
|
|
2153
2227
|
};
|
|
2154
2228
|
}
|
|
2155
2229
|
|
|
2156
|
-
// src/internal/resource-pools/resource-pool-queries.ts
|
|
2230
|
+
// src/internal/peek/resource-pools/resource-pool-queries.ts
|
|
2157
2231
|
var RESOURCE_POOLS_QUERY = `
|
|
2158
2232
|
query Sales($filter: ResourcePoolsFilter) {
|
|
2159
2233
|
resourcePools(filter: $filter) {
|
|
@@ -2174,7 +2248,7 @@ var RESOURCE_POOLS_QUERY = `
|
|
|
2174
2248
|
}
|
|
2175
2249
|
`;
|
|
2176
2250
|
|
|
2177
|
-
// src/internal/resource-pools/resource-pool-service.ts
|
|
2251
|
+
// src/internal/peek/resource-pools/resource-pool-service.ts
|
|
2178
2252
|
var DEFAULT_MODE = "ALL";
|
|
2179
2253
|
var ResourcePoolService = class {
|
|
2180
2254
|
constructor(client) {
|
|
@@ -2194,7 +2268,7 @@ var ResourcePoolService = class {
|
|
|
2194
2268
|
}
|
|
2195
2269
|
};
|
|
2196
2270
|
|
|
2197
|
-
// src/internal/reviews/review-converter.ts
|
|
2271
|
+
// src/internal/peek/reviews/review-converter.ts
|
|
2198
2272
|
var ISO_DATE_LENGTH = 10;
|
|
2199
2273
|
function toDateOnly(isoDateTime) {
|
|
2200
2274
|
return isoDateTime.slice(0, ISO_DATE_LENGTH);
|
|
@@ -2218,13 +2292,13 @@ function fromReviewNode(node) {
|
|
|
2218
2292
|
};
|
|
2219
2293
|
}
|
|
2220
2294
|
|
|
2221
|
-
// src/internal/reviews/review-cursor.ts
|
|
2295
|
+
// src/internal/peek/reviews/review-cursor.ts
|
|
2222
2296
|
function encodeCursor(offset, pageSize) {
|
|
2223
2297
|
const start = Math.max(0, offset - pageSize + 1);
|
|
2224
2298
|
return Buffer.from(`range:${start}..${offset},${offset}`).toString("base64");
|
|
2225
2299
|
}
|
|
2226
2300
|
|
|
2227
|
-
// src/internal/reviews/review-queries.ts
|
|
2301
|
+
// src/internal/peek/reviews/review-queries.ts
|
|
2228
2302
|
var REVIEWS_QUERY = `
|
|
2229
2303
|
query Reviews($first: Int, $filter: ReviewFilter, $after: String) {
|
|
2230
2304
|
reviews(first: $first, filter: $filter, after: $after) {
|
|
@@ -2259,7 +2333,7 @@ function buildReviewsVariables(params) {
|
|
|
2259
2333
|
};
|
|
2260
2334
|
}
|
|
2261
2335
|
|
|
2262
|
-
// src/internal/reviews/review-service.ts
|
|
2336
|
+
// src/internal/peek/reviews/review-service.ts
|
|
2263
2337
|
var DEFAULT_REVIEW_COUNT = 50;
|
|
2264
2338
|
var MIN_REVIEW_COUNT = 1;
|
|
2265
2339
|
var MAX_REVIEW_COUNT = 50;
|
|
@@ -2320,7 +2394,7 @@ var ReviewService = class {
|
|
|
2320
2394
|
}
|
|
2321
2395
|
};
|
|
2322
2396
|
|
|
2323
|
-
// src/internal/timeslots/timeslot-converter.ts
|
|
2397
|
+
// src/internal/peek/timeslots/timeslot-converter.ts
|
|
2324
2398
|
function fromTimeslotNodes(nodes, productId) {
|
|
2325
2399
|
if (!Array.isArray(nodes) || nodes.length === 0) {
|
|
2326
2400
|
return [];
|
|
@@ -2378,7 +2452,7 @@ function mapAssignedResources(allocations) {
|
|
|
2378
2452
|
});
|
|
2379
2453
|
}
|
|
2380
2454
|
|
|
2381
|
-
// src/internal/timeslots/guide-matcher.ts
|
|
2455
|
+
// src/internal/peek/timeslots/guide-matcher.ts
|
|
2382
2456
|
function matchGuideToResourcePool(guideId, guideResourcePools, accountUsers) {
|
|
2383
2457
|
const directIdMatch = guideResourcePools.find((pool) => pool.id === guideId);
|
|
2384
2458
|
if (directIdMatch) {
|
|
@@ -2412,7 +2486,7 @@ function matchGuideToResourcePool(guideId, guideResourcePools, accountUsers) {
|
|
|
2412
2486
|
return null;
|
|
2413
2487
|
}
|
|
2414
2488
|
|
|
2415
|
-
// src/internal/timeslots/resource-allocation-queries.ts
|
|
2489
|
+
// src/internal/peek/timeslots/resource-allocation-queries.ts
|
|
2416
2490
|
var RESOURCE_ALLOCATION_BULK_REQUEST_MUTATION = `
|
|
2417
2491
|
mutation ResourceAllocationBulkRequest($input: ResourceAllocationBulkRequestInput!) {
|
|
2418
2492
|
resourceAllocationBulkRequest(input: $input) {
|
|
@@ -2431,7 +2505,7 @@ function buildResourceAllocationVariables(timeslotIds, resourcePoolIds, status)
|
|
|
2431
2505
|
return { input: { timeslotIds, resourcePoolIds, status } };
|
|
2432
2506
|
}
|
|
2433
2507
|
|
|
2434
|
-
// src/internal/timeslots/timeslot-queries.ts
|
|
2508
|
+
// src/internal/peek/timeslots/timeslot-queries.ts
|
|
2435
2509
|
var TIMESLOTS_QUERY = `
|
|
2436
2510
|
query Sales($params: TimeslotsFilter!) {
|
|
2437
2511
|
timeslots(filter: $params) {
|
|
@@ -2534,7 +2608,7 @@ function buildTimeslotVariables(productId, date, filter) {
|
|
|
2534
2608
|
return { params };
|
|
2535
2609
|
}
|
|
2536
2610
|
|
|
2537
|
-
// src/internal/timeslots/timeslot-service.ts
|
|
2611
|
+
// src/internal/peek/timeslots/timeslot-service.ts
|
|
2538
2612
|
var GUIDE_CATEGORY = "guide";
|
|
2539
2613
|
var ERROR_MISSING_TIMESLOTS_OR_GUIDES = "At least one timeslot and one guide are required";
|
|
2540
2614
|
var ERROR_INVALID_ACTION = "Invalid action. Must be either assign or unassign";
|
|
@@ -2651,7 +2725,7 @@ function normalizeDate(date) {
|
|
|
2651
2725
|
return date.split("T")[0] ?? date;
|
|
2652
2726
|
}
|
|
2653
2727
|
|
|
2654
|
-
// src/internal/products/product-converter.ts
|
|
2728
|
+
// src/internal/peek/products/product-converter.ts
|
|
2655
2729
|
var ADD_ON_COLOR = "#FFFFFF";
|
|
2656
2730
|
function fromActivities(activities) {
|
|
2657
2731
|
return activities.map(fromActivity);
|
|
@@ -2690,7 +2764,7 @@ function fromItemOptionNodes(nodes) {
|
|
|
2690
2764
|
return Array.from(grouped.values());
|
|
2691
2765
|
}
|
|
2692
2766
|
|
|
2693
|
-
// src/internal/products/product-queries.ts
|
|
2767
|
+
// src/internal/peek/products/product-queries.ts
|
|
2694
2768
|
var PRODUCTS_QUERY = `
|
|
2695
2769
|
query Sales {
|
|
2696
2770
|
activities {
|
|
@@ -2730,7 +2804,7 @@ var ITEM_OPTIONS_QUERY = `
|
|
|
2730
2804
|
}
|
|
2731
2805
|
`;
|
|
2732
2806
|
|
|
2733
|
-
// src/internal/products/product-service.ts
|
|
2807
|
+
// src/internal/peek/products/product-service.ts
|
|
2734
2808
|
var DEFAULT_ITEM_OPTIONS_PAGE_SIZE = 50;
|
|
2735
2809
|
var ProductService = class {
|
|
2736
2810
|
constructor(client, options = {}) {
|
|
@@ -2807,7 +2881,7 @@ var ProductService = class {
|
|
|
2807
2881
|
}
|
|
2808
2882
|
};
|
|
2809
2883
|
|
|
2810
|
-
// src/internal/promo-codes/promo-code-queries.ts
|
|
2884
|
+
// src/internal/peek/promo-codes/promo-code-queries.ts
|
|
2811
2885
|
var PROMO_CODES_QUERY = `
|
|
2812
2886
|
query Sales($first: Int, $after: String) {
|
|
2813
2887
|
promoCodes(first: $first, after: $after) {
|
|
@@ -2846,7 +2920,7 @@ var CREATE_PROMO_CODE_MUTATION = `
|
|
|
2846
2920
|
}
|
|
2847
2921
|
`;
|
|
2848
2922
|
|
|
2849
|
-
// src/internal/promo-codes/promo-code-service.ts
|
|
2923
|
+
// src/internal/peek/promo-codes/promo-code-service.ts
|
|
2850
2924
|
var DEFAULT_PAGE_SIZE3 = 50;
|
|
2851
2925
|
var DEFAULT_CURRENCY = "USD";
|
|
2852
2926
|
var CURRENCY_PATTERN = /^[A-Z]{3}$/;
|
|
@@ -2925,34 +2999,6 @@ var PromoCodeService = class {
|
|
|
2925
2999
|
return { id: result.id, name: result.name };
|
|
2926
3000
|
}
|
|
2927
3001
|
};
|
|
2928
|
-
var TokenManager = class {
|
|
2929
|
-
constructor(options) {
|
|
2930
|
-
this.options = options;
|
|
2931
|
-
}
|
|
2932
|
-
options;
|
|
2933
|
-
cached;
|
|
2934
|
-
/**
|
|
2935
|
-
* Returns a valid bearer token, reusing the cached one until it is within
|
|
2936
|
-
* `leewaySeconds` of expiring, at which point a fresh token is minted.
|
|
2937
|
-
*/
|
|
2938
|
-
getToken() {
|
|
2939
|
-
const now = Date.now();
|
|
2940
|
-
if (this.cached && now < this.cached.expiresAtMs) {
|
|
2941
|
-
return this.cached.token;
|
|
2942
|
-
}
|
|
2943
|
-
const { secret, issuer, installId, ttlSeconds, leewaySeconds } = this.options;
|
|
2944
|
-
const token = jwt__namespace.sign({}, secret, {
|
|
2945
|
-
expiresIn: ttlSeconds,
|
|
2946
|
-
issuer,
|
|
2947
|
-
subject: installId
|
|
2948
|
-
});
|
|
2949
|
-
this.cached = {
|
|
2950
|
-
token,
|
|
2951
|
-
expiresAtMs: now + (ttlSeconds - leewaySeconds) * 1e3
|
|
2952
|
-
};
|
|
2953
|
-
return token;
|
|
2954
|
-
}
|
|
2955
|
-
};
|
|
2956
3002
|
|
|
2957
3003
|
// src/logger.ts
|
|
2958
3004
|
var noopLogger = {
|
|
@@ -2967,9 +3013,6 @@ var noopLogger = {
|
|
|
2967
3013
|
// src/peek-access-service.ts
|
|
2968
3014
|
var DEFAULT_BASE_URL = "https://apps.peekapis.com/backoffice-gql";
|
|
2969
3015
|
var DEFAULT_V2_BASE_URL = "https://app-registry.peeklabs.com/installations-api";
|
|
2970
|
-
var DEFAULT_TOKEN_TTL_SECONDS = 3600;
|
|
2971
|
-
var DEFAULT_TOKEN_REFRESH_LEEWAY_SECONDS = 60;
|
|
2972
|
-
var DEFAULT_RETRY_DELAYS_MS = [1e3, 2e3, 4e3];
|
|
2973
3016
|
var PEEK_TOKEN_ISSUER = "app_registry_v2";
|
|
2974
3017
|
var PeekAccessService = class {
|
|
2975
3018
|
client;
|
|
@@ -2988,20 +3031,14 @@ var PeekAccessService = class {
|
|
|
2988
3031
|
reviewService;
|
|
2989
3032
|
constructor(config) {
|
|
2990
3033
|
const isV2 = config.mode === "v2";
|
|
2991
|
-
requireNonEmpty(config.installId, "installId");
|
|
2992
|
-
requireNonEmpty(config.jwtSecret, "jwtSecret");
|
|
2993
|
-
requireNonEmpty(config.issuer, "issuer");
|
|
2994
|
-
requireNonEmpty(config.appId, "appId");
|
|
2995
|
-
if (!isV2) requireNonEmpty(config.gatewayKey ?? "", "gatewayKey");
|
|
3034
|
+
requireNonEmpty(config.installId, "installId", "PeekAccessService");
|
|
3035
|
+
requireNonEmpty(config.jwtSecret, "jwtSecret", "PeekAccessService");
|
|
3036
|
+
requireNonEmpty(config.issuer, "issuer", "PeekAccessService");
|
|
3037
|
+
requireNonEmpty(config.appId, "appId", "PeekAccessService");
|
|
3038
|
+
if (!isV2) requireNonEmpty(config.gatewayKey ?? "", "gatewayKey", "PeekAccessService");
|
|
2996
3039
|
this.jwtSecret = config.jwtSecret;
|
|
2997
3040
|
const logger = config.logger ?? noopLogger;
|
|
2998
|
-
const tokens =
|
|
2999
|
-
secret: config.jwtSecret,
|
|
3000
|
-
issuer: config.issuer,
|
|
3001
|
-
installId: config.installId,
|
|
3002
|
-
ttlSeconds: config.tokenTtlSeconds ?? DEFAULT_TOKEN_TTL_SECONDS,
|
|
3003
|
-
leewaySeconds: config.tokenRefreshLeewaySeconds ?? DEFAULT_TOKEN_REFRESH_LEEWAY_SECONDS
|
|
3004
|
-
});
|
|
3041
|
+
const tokens = createTokenManager(config);
|
|
3005
3042
|
const defaultBaseUrl = isV2 ? DEFAULT_V2_BASE_URL : DEFAULT_BASE_URL;
|
|
3006
3043
|
this.client = new GraphQLClient({
|
|
3007
3044
|
baseUrl: config.baseUrl ?? defaultBaseUrl,
|
|
@@ -3048,7 +3085,8 @@ var PeekAccessService = class {
|
|
|
3048
3085
|
id: u.id,
|
|
3049
3086
|
isAdmin: u.is_admin,
|
|
3050
3087
|
locale: u.locale,
|
|
3051
|
-
name: u.name
|
|
3088
|
+
name: u.name,
|
|
3089
|
+
platform: u.platform
|
|
3052
3090
|
}
|
|
3053
3091
|
};
|
|
3054
3092
|
}
|
|
@@ -3327,13 +3365,148 @@ var PeekAccessService = class {
|
|
|
3327
3365
|
return this.getReviewService().getReviews(productId, reviewCount, reviewOffset);
|
|
3328
3366
|
}
|
|
3329
3367
|
};
|
|
3330
|
-
|
|
3331
|
-
|
|
3332
|
-
|
|
3333
|
-
|
|
3368
|
+
|
|
3369
|
+
// src/internal/cng/endpoints.ts
|
|
3370
|
+
var CNG_EXTENDABLE_SLUG = "cng_backoffice_api-v1";
|
|
3371
|
+
var PRODUCTS_PATH = "api/v2/commerce-config/products";
|
|
3372
|
+
|
|
3373
|
+
// src/models/cng/product.ts
|
|
3374
|
+
var ACTIVITY_PRODUCT_TYPE2 = "ACTIVITY";
|
|
3375
|
+
|
|
3376
|
+
// src/internal/cng/products/product-converter.ts
|
|
3377
|
+
function fromProductNodes(nodes) {
|
|
3378
|
+
return nodes.map(fromProductNode);
|
|
3379
|
+
}
|
|
3380
|
+
function fromProductNode(node) {
|
|
3381
|
+
return {
|
|
3382
|
+
productId: node.id || "",
|
|
3383
|
+
name: node.name || "",
|
|
3384
|
+
type: node.product_type || ACTIVITY_PRODUCT_TYPE2,
|
|
3385
|
+
color: node.color_hex || "",
|
|
3386
|
+
tickets: (node.tickets ?? []).map((ticket) => ({
|
|
3387
|
+
id: ticket.id,
|
|
3388
|
+
name: ticket.name
|
|
3389
|
+
}))
|
|
3390
|
+
};
|
|
3334
3391
|
}
|
|
3335
3392
|
|
|
3336
|
-
// src/internal/
|
|
3393
|
+
// src/internal/cng/products/product-service.ts
|
|
3394
|
+
var CngProductService = class {
|
|
3395
|
+
constructor(client) {
|
|
3396
|
+
this.client = client;
|
|
3397
|
+
}
|
|
3398
|
+
client;
|
|
3399
|
+
/**
|
|
3400
|
+
* Returns every activity as a single flat list.
|
|
3401
|
+
*
|
|
3402
|
+
* @example
|
|
3403
|
+
* ```ts
|
|
3404
|
+
* const activities = await cng.getProductService().getAllActivities();
|
|
3405
|
+
* ```
|
|
3406
|
+
*/
|
|
3407
|
+
async getAllActivities() {
|
|
3408
|
+
const body = await this.client.get(
|
|
3409
|
+
PRODUCTS_PATH
|
|
3410
|
+
);
|
|
3411
|
+
const nodes = Array.isArray(body) ? body : body?.products ?? [];
|
|
3412
|
+
return fromProductNodes(nodes ?? []);
|
|
3413
|
+
}
|
|
3414
|
+
};
|
|
3415
|
+
|
|
3416
|
+
// src/internal/cng/rest-client.ts
|
|
3417
|
+
var RestClient = class {
|
|
3418
|
+
constructor(options) {
|
|
3419
|
+
this.options = options;
|
|
3420
|
+
}
|
|
3421
|
+
options;
|
|
3422
|
+
/**
|
|
3423
|
+
* Issues a GET against the named REST path and returns the parsed JSON body.
|
|
3424
|
+
* Retries on HTTP 429 per the configured backoff (via the shared
|
|
3425
|
+
* {@link requestWithRetry} loop).
|
|
3426
|
+
*
|
|
3427
|
+
* @throws {AdminAccountRequiredError} on HTTP 418
|
|
3428
|
+
* @throws {RateLimitError} on HTTP 429 after retries are exhausted
|
|
3429
|
+
* @throws {CngApiError} on any other non-2xx response
|
|
3430
|
+
*/
|
|
3431
|
+
async get(path) {
|
|
3432
|
+
const { logger } = this.options;
|
|
3433
|
+
const url = this.endpoint(path);
|
|
3434
|
+
logger.info("Making CNG request", { url, path });
|
|
3435
|
+
return requestWithRetry(
|
|
3436
|
+
this.options,
|
|
3437
|
+
url,
|
|
3438
|
+
{ method: "GET", headers: this.buildHeaders() },
|
|
3439
|
+
path,
|
|
3440
|
+
async (response) => {
|
|
3441
|
+
const body = await this.parseBody(response);
|
|
3442
|
+
if (!response.ok) {
|
|
3443
|
+
logger.error(`CNG request failed with HTTP ${response.status}`, { url });
|
|
3444
|
+
throw new CngApiError(response.status, body);
|
|
3445
|
+
}
|
|
3446
|
+
return body;
|
|
3447
|
+
}
|
|
3448
|
+
);
|
|
3449
|
+
}
|
|
3450
|
+
/** Reads the response body as JSON, falling back to raw text when unparseable. */
|
|
3451
|
+
async parseBody(response) {
|
|
3452
|
+
const text = await response.text();
|
|
3453
|
+
try {
|
|
3454
|
+
return JSON.parse(text);
|
|
3455
|
+
} catch {
|
|
3456
|
+
return text;
|
|
3457
|
+
}
|
|
3458
|
+
}
|
|
3459
|
+
endpoint(path) {
|
|
3460
|
+
const { baseUrl, appId, extendableSlug } = this.options;
|
|
3461
|
+
return `${baseUrl}/${appId}/${extendableSlug}/${path}`;
|
|
3462
|
+
}
|
|
3463
|
+
buildHeaders() {
|
|
3464
|
+
return {
|
|
3465
|
+
"X-Peek-Auth": `Bearer ${this.options.getToken()}`,
|
|
3466
|
+
"Content-Type": "application/json"
|
|
3467
|
+
};
|
|
3468
|
+
}
|
|
3469
|
+
};
|
|
3470
|
+
|
|
3471
|
+
// src/cng-access-service.ts
|
|
3472
|
+
var DEFAULT_BASE_URL2 = "https://app-registry.peeklabs.com/installations-api";
|
|
3473
|
+
var CngAccessService = class {
|
|
3474
|
+
client;
|
|
3475
|
+
productService;
|
|
3476
|
+
constructor(config) {
|
|
3477
|
+
requireNonEmpty(config.installId, "installId", "CngAccessService");
|
|
3478
|
+
requireNonEmpty(config.jwtSecret, "jwtSecret", "CngAccessService");
|
|
3479
|
+
requireNonEmpty(config.issuer, "issuer", "CngAccessService");
|
|
3480
|
+
requireNonEmpty(config.appId, "appId", "CngAccessService");
|
|
3481
|
+
const logger = config.logger ?? noopLogger;
|
|
3482
|
+
const tokens = createTokenManager(config);
|
|
3483
|
+
this.client = new RestClient({
|
|
3484
|
+
baseUrl: config.baseUrl ?? DEFAULT_BASE_URL2,
|
|
3485
|
+
appId: config.appId,
|
|
3486
|
+
extendableSlug: CNG_EXTENDABLE_SLUG,
|
|
3487
|
+
getToken: () => tokens.getToken(),
|
|
3488
|
+
retryDelaysMs: config.retryDelaysMs ?? DEFAULT_RETRY_DELAYS_MS,
|
|
3489
|
+
logger,
|
|
3490
|
+
fetchFn: config.fetch ?? globalThis.fetch
|
|
3491
|
+
});
|
|
3492
|
+
}
|
|
3493
|
+
/**
|
|
3494
|
+
* Returns the {@link CngProductService} for this install, bound to the shared
|
|
3495
|
+
* authenticated transport. The instance is created lazily and reused.
|
|
3496
|
+
*/
|
|
3497
|
+
getProductService() {
|
|
3498
|
+
if (!this.productService) {
|
|
3499
|
+
this.productService = new CngProductService(this.client);
|
|
3500
|
+
}
|
|
3501
|
+
return this.productService;
|
|
3502
|
+
}
|
|
3503
|
+
/** All activities. Delegates to {@link CngProductService.getAllActivities}. */
|
|
3504
|
+
getAllActivities() {
|
|
3505
|
+
return this.getProductService().getAllActivities();
|
|
3506
|
+
}
|
|
3507
|
+
};
|
|
3508
|
+
|
|
3509
|
+
// src/internal/peek/bookings/booking-webhook.ts
|
|
3337
3510
|
var PAYLOAD_BOOKING_KEY = "booking";
|
|
3338
3511
|
var VALUE_OPEN_TOKEN = "value {";
|
|
3339
3512
|
var PRICE_BREAKDOWN_KEYS = [
|
|
@@ -3383,7 +3556,7 @@ function hasPriceBreakdown(node) {
|
|
|
3383
3556
|
return PRICE_BREAKDOWN_KEYS.some((key) => key in value);
|
|
3384
3557
|
}
|
|
3385
3558
|
|
|
3386
|
-
// src/internal/waivers/waiver-webhook.ts
|
|
3559
|
+
// src/internal/peek/waivers/waiver-webhook.ts
|
|
3387
3560
|
var PAYLOAD_WAIVER_KEY = "waiver";
|
|
3388
3561
|
function parseWaiverWebhook(payload) {
|
|
3389
3562
|
return fromWaiverNode(extractWaiverNode(payload));
|
|
@@ -3424,6 +3597,9 @@ exports.AccountUserService = AccountUserService;
|
|
|
3424
3597
|
exports.AdminAccountRequiredError = AdminAccountRequiredError;
|
|
3425
3598
|
exports.AvailabilityService = AvailabilityService;
|
|
3426
3599
|
exports.BookingService = BookingService;
|
|
3600
|
+
exports.CngAccessService = CngAccessService;
|
|
3601
|
+
exports.CngApiError = CngApiError;
|
|
3602
|
+
exports.CngProductService = CngProductService;
|
|
3427
3603
|
exports.DailyNoteService = DailyNoteService;
|
|
3428
3604
|
exports.MembershipService = MembershipService;
|
|
3429
3605
|
exports.PeekAccessService = PeekAccessService;
|