@peektravel/app-utilities 0.9.0 → 0.9.2
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/README.md +6 -3
- package/dist/index.cjs +152 -41
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +113 -57
- package/dist/index.d.ts +113 -57
- package/dist/index.js +152 -41
- package/dist/index.js.map +1 -1
- package/docs/webhooks.md +11 -8
- package/llms.txt +25 -8
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -317,9 +317,12 @@ event data**; the fields it shares with the token (`installId` / `accountId` /
|
|
|
317
317
|
the body omits them. The token authenticates the whole delivery, so the body is
|
|
318
318
|
trusted within a verified request. This webhook is the only source of
|
|
319
319
|
`accountId`, `timezone`, and `apiUrl` in the package, since no GraphQL read
|
|
320
|
-
returns them — **persist them per install**. `apiUrl` is the install's
|
|
321
|
-
|
|
322
|
-
|
|
320
|
+
returns them — **persist them per install**. `apiUrl` is the install's **base API
|
|
321
|
+
URL**: pass it straight through (don't reconstruct it from `appId`) as the access
|
|
322
|
+
service's `apiUrl` — each service class appends its own backoffice slug (e.g.
|
|
323
|
+
`peek_backoffice_api-v1`) when it makes a call, stripping the slug back off if the
|
|
324
|
+
URL you pass already carries it and throwing if it carries a different platform's
|
|
325
|
+
slug — or hand the whole install to
|
|
323
326
|
`createAccessServiceForInstall(install, { jwtSecret, issuer })`, which picks the
|
|
324
327
|
service by `platform` and wires the endpoint for you. Every event is a **full
|
|
325
328
|
snapshot** — an `update_installed` carries the same fields as the original
|
package/dist/index.cjs
CHANGED
|
@@ -23,9 +23,29 @@ function _interopNamespace(e) {
|
|
|
23
23
|
|
|
24
24
|
var jwt__namespace = /*#__PURE__*/_interopNamespace(jwt);
|
|
25
25
|
|
|
26
|
+
// src/internal/api-endpoints.ts
|
|
27
|
+
var ApiEndpoints = class {
|
|
28
|
+
constructor(paths) {
|
|
29
|
+
this.paths = paths;
|
|
30
|
+
}
|
|
31
|
+
paths;
|
|
32
|
+
/** The relative path (slug) for `endpoint`, appended to the base API URL. */
|
|
33
|
+
pathFor(endpoint) {
|
|
34
|
+
return this.paths[endpoint];
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
function joinUrl(...parts) {
|
|
38
|
+
return parts.filter((part) => part.length > 0).join("/");
|
|
39
|
+
}
|
|
40
|
+
|
|
26
41
|
// src/internal/peek/gateway-endpoints.ts
|
|
27
42
|
var SALES_ENDPOINT = "sales";
|
|
28
43
|
var V2_EXTENDABLE_SLUG = "peek_backoffice_api-v1";
|
|
44
|
+
function peekApiEndpoints(useRegistrySlug) {
|
|
45
|
+
return new ApiEndpoints({
|
|
46
|
+
[SALES_ENDPOINT]: useRegistrySlug ? V2_EXTENDABLE_SLUG : SALES_ENDPOINT
|
|
47
|
+
});
|
|
48
|
+
}
|
|
29
49
|
|
|
30
50
|
// src/internal/peek/account-users/account-user-converter.ts
|
|
31
51
|
var ACTIVE_STATUS = "ACTIVE";
|
|
@@ -1092,6 +1112,9 @@ var QUESTION_TYPE_SELECT_ONE = "SELECT_ONE";
|
|
|
1092
1112
|
var QUESTION_TYPE_LOCATION = "LOCATION";
|
|
1093
1113
|
var QUESTION_ID_REGEX = /^cq_[a-z0-9]+$/;
|
|
1094
1114
|
var OPTION_ID_REGEX = /^cqao_[a-z0-9]+$/;
|
|
1115
|
+
function isCustomQuestionId(idOrText) {
|
|
1116
|
+
return QUESTION_ID_REGEX.test(idOrText);
|
|
1117
|
+
}
|
|
1095
1118
|
var CHECKBOX_TRUE = /* @__PURE__ */ new Set(["yes", "true"]);
|
|
1096
1119
|
var CHECKBOX_VALID = /* @__PURE__ */ new Set(["yes", "no", "true", "false"]);
|
|
1097
1120
|
var CHECKBOX_TEXT_TRUE = "Yes";
|
|
@@ -1109,10 +1132,13 @@ var errMissingRequired = (text, id) => `Custom question "${text}" (${id}) is req
|
|
|
1109
1132
|
function normalize(value) {
|
|
1110
1133
|
return value.toLowerCase().replace(/[^a-z0-9]/g, "");
|
|
1111
1134
|
}
|
|
1112
|
-
function resolveQuestion(idOrText, questions) {
|
|
1135
|
+
function resolveQuestion(idOrText, questions, acceptAllIds) {
|
|
1113
1136
|
if (QUESTION_ID_REGEX.test(idOrText)) {
|
|
1114
1137
|
const byId = questions.find((question) => question.id === idOrText);
|
|
1115
|
-
if (!byId)
|
|
1138
|
+
if (!byId) {
|
|
1139
|
+
if (acceptAllIds) return null;
|
|
1140
|
+
throw new Error(errUnknownQuestionId(idOrText));
|
|
1141
|
+
}
|
|
1116
1142
|
return byId;
|
|
1117
1143
|
}
|
|
1118
1144
|
const target = normalize(idOrText);
|
|
@@ -1137,8 +1163,11 @@ function resolveOption(value, question) {
|
|
|
1137
1163
|
if (matches.length > 1) throw new Error(errAmbiguousOption(value, question.id));
|
|
1138
1164
|
return matches[0];
|
|
1139
1165
|
}
|
|
1140
|
-
function resolveOne(answer, questions) {
|
|
1141
|
-
const question = resolveQuestion(answer.questionIdOrText, questions);
|
|
1166
|
+
function resolveOne(answer, questions, acceptAllIds) {
|
|
1167
|
+
const question = resolveQuestion(answer.questionIdOrText, questions, acceptAllIds);
|
|
1168
|
+
if (!question) {
|
|
1169
|
+
return { questionId: answer.questionIdOrText, questionAnswerText: answer.value };
|
|
1170
|
+
}
|
|
1142
1171
|
if (question.perGuest) {
|
|
1143
1172
|
throw new Error(errPerGuestUnsupported(question.id));
|
|
1144
1173
|
}
|
|
@@ -1171,7 +1200,8 @@ function resolveOne(answer, questions) {
|
|
|
1171
1200
|
}
|
|
1172
1201
|
}
|
|
1173
1202
|
function resolveCustomQuestionAnswers(answers, questions, options) {
|
|
1174
|
-
const
|
|
1203
|
+
const acceptAllIds = options?.acceptAllIds ?? false;
|
|
1204
|
+
const resolved = answers.map((answer) => resolveOne(answer, questions, acceptAllIds));
|
|
1175
1205
|
if (options?.requireRequired) {
|
|
1176
1206
|
assertRequiredAnswered(resolved, questions);
|
|
1177
1207
|
}
|
|
@@ -1779,19 +1809,22 @@ ${note}`;
|
|
|
1779
1809
|
* Resolves the input's custom-question answers into the quote's
|
|
1780
1810
|
* `questionAnswers` payload (each tagged with a fresh `refid`), or `null` when
|
|
1781
1811
|
* none were supplied. Fetches the activity's custom questions to validate
|
|
1782
|
-
* against; throws on the first unmatched/ambiguous/invalid answer.
|
|
1812
|
+
* against; throws on the first unmatched/ambiguous/invalid answer. When
|
|
1813
|
+
* `acceptAllCustomQuestionIds` is set the fetch is skipped if every answer is
|
|
1814
|
+
* given by id (a by-name answer still needs the list to resolve).
|
|
1783
1815
|
*/
|
|
1784
1816
|
async buildQuestionAnswers(input) {
|
|
1785
1817
|
const answers = input.customQuestionAnswers ?? [];
|
|
1786
1818
|
const requireRequired = input.requireRequiredQuestions ?? false;
|
|
1819
|
+
const acceptAllIds = input.acceptAllCustomQuestionIds ?? false;
|
|
1787
1820
|
if (answers.length === 0 && !requireRequired) {
|
|
1788
1821
|
return null;
|
|
1789
1822
|
}
|
|
1790
|
-
const
|
|
1791
|
-
|
|
1792
|
-
);
|
|
1823
|
+
const needsQuestions = !acceptAllIds || requireRequired || answers.some((answer) => !isCustomQuestionId(answer.questionIdOrText));
|
|
1824
|
+
const questions = needsQuestions ? await this.deps.productService.getCustomQuestions(input.activityId) : [];
|
|
1793
1825
|
const resolved = resolveCustomQuestionAnswers(answers, questions, {
|
|
1794
|
-
requireRequired
|
|
1826
|
+
requireRequired,
|
|
1827
|
+
acceptAllIds
|
|
1795
1828
|
});
|
|
1796
1829
|
if (resolved.length === 0) {
|
|
1797
1830
|
return null;
|
|
@@ -2099,6 +2132,21 @@ function requireNonEmpty(value, name, serviceName) {
|
|
|
2099
2132
|
throw new Error(`${serviceName}: "${name}" is required`);
|
|
2100
2133
|
}
|
|
2101
2134
|
}
|
|
2135
|
+
var EXTENDABLE_SLUG_RE = /^([a-z0-9]+)[-_]backoffice[-_]api[-_]v1$/i;
|
|
2136
|
+
function resolveBaseApiUrl(apiUrl, platformSlug, serviceName) {
|
|
2137
|
+
const trimmed = apiUrl.replace(/\/+$/, "");
|
|
2138
|
+
const lastSegment = trimmed.slice(trimmed.lastIndexOf("/") + 1);
|
|
2139
|
+
const found = EXTENDABLE_SLUG_RE.exec(lastSegment);
|
|
2140
|
+
if (!found) return trimmed;
|
|
2141
|
+
const foundPlatform = found[1].toLowerCase();
|
|
2142
|
+
const expectedPlatform = EXTENDABLE_SLUG_RE.exec(platformSlug)[1].toLowerCase();
|
|
2143
|
+
if (foundPlatform !== expectedPlatform) {
|
|
2144
|
+
throw new Error(
|
|
2145
|
+
`${serviceName}: "apiUrl" carries a "${foundPlatform}" backoffice slug but this service targets "${expectedPlatform}" \u2014 pass the install's ${expectedPlatform} app endpoint`
|
|
2146
|
+
);
|
|
2147
|
+
}
|
|
2148
|
+
return trimmed.slice(0, trimmed.lastIndexOf("/"));
|
|
2149
|
+
}
|
|
2102
2150
|
function createTokenManager(config) {
|
|
2103
2151
|
return new TokenManager({
|
|
2104
2152
|
secret: config.jwtSecret,
|
|
@@ -2149,7 +2197,7 @@ async function requestWithRetry(http, url, init, label, onResponse) {
|
|
|
2149
2197
|
// src/internal/sdk-headers.ts
|
|
2150
2198
|
var SDK_HEADER_NAME = "x-peek-sdk";
|
|
2151
2199
|
var SDK_PLATFORM = "js";
|
|
2152
|
-
var SDK_VERSION = "0.9.
|
|
2200
|
+
var SDK_VERSION = "0.9.2";
|
|
2153
2201
|
var SDK_HEADER_VALUE = `${SDK_PLATFORM}-${SDK_VERSION}`;
|
|
2154
2202
|
|
|
2155
2203
|
// src/internal/peek/graphql-client.ts
|
|
@@ -2197,10 +2245,8 @@ var GraphQLClient = class {
|
|
|
2197
2245
|
);
|
|
2198
2246
|
}
|
|
2199
2247
|
endpoint(endpointName) {
|
|
2200
|
-
const {
|
|
2201
|
-
|
|
2202
|
-
const prefix = endpointPathPrefix ? `${endpointPathPrefix}/` : "";
|
|
2203
|
-
return `${baseUrl}/${appId}/${prefix}${endpointName}`;
|
|
2248
|
+
const { baseApiUrl, endpoints } = this.options;
|
|
2249
|
+
return joinUrl(baseApiUrl, endpoints.pathFor(endpointName));
|
|
2204
2250
|
}
|
|
2205
2251
|
buildHeaders() {
|
|
2206
2252
|
const headers = {
|
|
@@ -2576,6 +2622,23 @@ function fromReviewNode(node) {
|
|
|
2576
2622
|
comment: node.comment ?? null
|
|
2577
2623
|
};
|
|
2578
2624
|
}
|
|
2625
|
+
function fromActivityReviewSummaryNode(node) {
|
|
2626
|
+
const meta = node.reviewMeta;
|
|
2627
|
+
return {
|
|
2628
|
+
productId: node.id,
|
|
2629
|
+
productName: node.name,
|
|
2630
|
+
avgRating: meta?.avgRating ?? null,
|
|
2631
|
+
countTotal: meta?.count ?? 0,
|
|
2632
|
+
countOneStar: meta?.oneStar ?? 0,
|
|
2633
|
+
countTwoStar: meta?.twoStar ?? 0,
|
|
2634
|
+
countThreeStar: meta?.threeStar ?? 0,
|
|
2635
|
+
countFourStar: meta?.fourStar ?? 0,
|
|
2636
|
+
countFiveStar: meta?.fiveStar ?? 0
|
|
2637
|
+
};
|
|
2638
|
+
}
|
|
2639
|
+
function fromActivityReviewSummaryNodes(nodes) {
|
|
2640
|
+
return nodes.map(fromActivityReviewSummaryNode);
|
|
2641
|
+
}
|
|
2579
2642
|
|
|
2580
2643
|
// src/internal/peek/reviews/review-cursor.ts
|
|
2581
2644
|
function encodeCursor(offset, pageSize) {
|
|
@@ -2611,6 +2674,23 @@ function buildReviewsQuery(fullCustomerAccess) {
|
|
|
2611
2674
|
}
|
|
2612
2675
|
`;
|
|
2613
2676
|
}
|
|
2677
|
+
var REVIEW_SUMMARIES_QUERY = `
|
|
2678
|
+
query ReviewSummaries {
|
|
2679
|
+
activities {
|
|
2680
|
+
id
|
|
2681
|
+
name
|
|
2682
|
+
reviewMeta {
|
|
2683
|
+
avgRating
|
|
2684
|
+
count
|
|
2685
|
+
fiveStar
|
|
2686
|
+
fourStar
|
|
2687
|
+
threeStar
|
|
2688
|
+
twoStar
|
|
2689
|
+
oneStar
|
|
2690
|
+
}
|
|
2691
|
+
}
|
|
2692
|
+
}
|
|
2693
|
+
`;
|
|
2614
2694
|
function buildReviewsVariables(params) {
|
|
2615
2695
|
return {
|
|
2616
2696
|
first: params.first,
|
|
@@ -2670,6 +2750,29 @@ var ReviewService = class {
|
|
|
2670
2750
|
const edges = body.data?.reviews?.edges ?? [];
|
|
2671
2751
|
return edges.map((edge) => fromReviewNode(edge.node));
|
|
2672
2752
|
}
|
|
2753
|
+
/**
|
|
2754
|
+
* Returns an aggregate review summary for **every** activity — its average
|
|
2755
|
+
* rating and the count of reviews at each star level. This reads the same
|
|
2756
|
+
* activity list as `getAllProducts`; it carries no per-review detail or PII, so
|
|
2757
|
+
* it is unaffected by `fullCustomerAccess`. An activity with no reviews comes
|
|
2758
|
+
* back with a `null` `avgRating` and zero counts.
|
|
2759
|
+
*
|
|
2760
|
+
* @example
|
|
2761
|
+
* ```ts
|
|
2762
|
+
* const summaries = await peek.getReviewService().getAllReviewSummaries();
|
|
2763
|
+
* for (const s of summaries) {
|
|
2764
|
+
* console.log(s.productName, s.avgRating, s.countTotal);
|
|
2765
|
+
* }
|
|
2766
|
+
* ```
|
|
2767
|
+
*/
|
|
2768
|
+
async getAllReviewSummaries() {
|
|
2769
|
+
const body = await this.client.request(
|
|
2770
|
+
SALES_ENDPOINT,
|
|
2771
|
+
REVIEW_SUMMARIES_QUERY,
|
|
2772
|
+
{}
|
|
2773
|
+
);
|
|
2774
|
+
return fromActivityReviewSummaryNodes(body.data?.activities ?? []);
|
|
2775
|
+
}
|
|
2673
2776
|
validate(productId, reviewCount, reviewOffset) {
|
|
2674
2777
|
if (!productId) {
|
|
2675
2778
|
throw new Error(ERROR_PRODUCT_ID_REQUIRED);
|
|
@@ -3823,17 +3926,17 @@ var PeekAccessService = class {
|
|
|
3823
3926
|
this.jwtSecret = config.jwtSecret;
|
|
3824
3927
|
const logger = config.logger ?? noopLogger;
|
|
3825
3928
|
const tokens = createTokenManager(config);
|
|
3929
|
+
const useRegistrySlug = hasApiUrl || isV2;
|
|
3826
3930
|
const defaultBaseUrl = isV2 ? DEFAULT_V2_BASE_URL : DEFAULT_BASE_URL;
|
|
3931
|
+
const baseApiUrl = hasApiUrl ? resolveBaseApiUrl(config.apiUrl, V2_EXTENDABLE_SLUG, "PeekAccessService") : `${config.baseUrl ?? defaultBaseUrl}/${config.appId}`;
|
|
3827
3932
|
this.client = new GraphQLClient({
|
|
3828
|
-
|
|
3829
|
-
|
|
3830
|
-
appId: hasApiUrl ? void 0 : config.appId,
|
|
3933
|
+
baseApiUrl,
|
|
3934
|
+
endpoints: peekApiEndpoints(useRegistrySlug),
|
|
3831
3935
|
gatewayKey: config.gatewayKey,
|
|
3832
3936
|
getToken: () => tokens.getToken(),
|
|
3833
3937
|
retryDelaysMs: config.retryDelaysMs ?? DEFAULT_RETRY_DELAYS_MS,
|
|
3834
3938
|
logger,
|
|
3835
|
-
fetchFn: config.fetch ?? globalThis.fetch
|
|
3836
|
-
endpointPathPrefix: !hasApiUrl && isV2 ? V2_EXTENDABLE_SLUG : void 0
|
|
3939
|
+
fetchFn: config.fetch ?? globalThis.fetch
|
|
3837
3940
|
});
|
|
3838
3941
|
this.productServiceOptions = {
|
|
3839
3942
|
itemOptionsPageSize: config.itemOptionsPageSize
|
|
@@ -4187,7 +4290,11 @@ var PeekAccessService = class {
|
|
|
4187
4290
|
|
|
4188
4291
|
// src/internal/cng/endpoints.ts
|
|
4189
4292
|
var CNG_EXTENDABLE_SLUG = "cng_backoffice_api-v1";
|
|
4293
|
+
var CNG_PRODUCTS_ENDPOINT = "products";
|
|
4190
4294
|
var PRODUCTS_PATH = "api/v2/app-registry/products?active=1";
|
|
4295
|
+
var CNG_API_ENDPOINTS = new ApiEndpoints({
|
|
4296
|
+
[CNG_PRODUCTS_ENDPOINT]: CNG_EXTENDABLE_SLUG
|
|
4297
|
+
});
|
|
4191
4298
|
|
|
4192
4299
|
// src/models/cng/product.ts
|
|
4193
4300
|
var ACTIVITY_PRODUCT_TYPE2 = "ACTIVITY";
|
|
@@ -4221,7 +4328,10 @@ var CngProductService = class {
|
|
|
4221
4328
|
* ```
|
|
4222
4329
|
*/
|
|
4223
4330
|
async getAllActivities() {
|
|
4224
|
-
const body = await this.client.get(
|
|
4331
|
+
const body = await this.client.get(
|
|
4332
|
+
CNG_PRODUCTS_ENDPOINT,
|
|
4333
|
+
PRODUCTS_PATH
|
|
4334
|
+
);
|
|
4225
4335
|
return fromProductNodes(body?.data ?? []);
|
|
4226
4336
|
}
|
|
4227
4337
|
};
|
|
@@ -4243,9 +4353,9 @@ var RestClient = class {
|
|
|
4243
4353
|
* @throws {CngPermissionError} on HTTP 403 (app missing a permission)
|
|
4244
4354
|
* @throws {CngApiError} on any other non-2xx response
|
|
4245
4355
|
*/
|
|
4246
|
-
async get(path) {
|
|
4356
|
+
async get(endpoint, path) {
|
|
4247
4357
|
const { logger } = this.options;
|
|
4248
|
-
const url = this.endpoint(path);
|
|
4358
|
+
const url = this.endpoint(endpoint, path);
|
|
4249
4359
|
logger.info("Making CNG request", { url, path });
|
|
4250
4360
|
return requestWithRetry(
|
|
4251
4361
|
this.options,
|
|
@@ -4267,10 +4377,9 @@ var RestClient = class {
|
|
|
4267
4377
|
}
|
|
4268
4378
|
);
|
|
4269
4379
|
}
|
|
4270
|
-
endpoint(path) {
|
|
4271
|
-
const {
|
|
4272
|
-
|
|
4273
|
-
return `${baseUrl}/${appId}/${extendableSlug}/${path}`;
|
|
4380
|
+
endpoint(endpoint, path) {
|
|
4381
|
+
const { baseApiUrl, endpoints } = this.options;
|
|
4382
|
+
return joinUrl(baseApiUrl, endpoints.pathFor(endpoint), path);
|
|
4274
4383
|
}
|
|
4275
4384
|
buildHeaders() {
|
|
4276
4385
|
return {
|
|
@@ -4300,11 +4409,10 @@ var CngAccessService = class {
|
|
|
4300
4409
|
if (!hasApiUrl) requireNonEmpty(config.appId ?? "", "appId", "CngAccessService");
|
|
4301
4410
|
const logger = config.logger ?? noopLogger;
|
|
4302
4411
|
const tokens = createTokenManager(config);
|
|
4412
|
+
const baseApiUrl = hasApiUrl ? resolveBaseApiUrl(config.apiUrl, CNG_EXTENDABLE_SLUG, "CngAccessService") : `${config.baseUrl ?? DEFAULT_BASE_URL2}/${config.appId}`;
|
|
4303
4413
|
this.client = new RestClient({
|
|
4304
|
-
|
|
4305
|
-
|
|
4306
|
-
appId: hasApiUrl ? void 0 : config.appId,
|
|
4307
|
-
extendableSlug: CNG_EXTENDABLE_SLUG,
|
|
4414
|
+
baseApiUrl,
|
|
4415
|
+
endpoints: CNG_API_ENDPOINTS,
|
|
4308
4416
|
getToken: () => tokens.getToken(),
|
|
4309
4417
|
retryDelaysMs: config.retryDelaysMs ?? DEFAULT_RETRY_DELAYS_MS,
|
|
4310
4418
|
logger,
|
|
@@ -4329,7 +4437,11 @@ var CngAccessService = class {
|
|
|
4329
4437
|
|
|
4330
4438
|
// src/internal/acme/endpoints.ts
|
|
4331
4439
|
var ACME_EXTENDABLE_SLUG = "acme_backoffice_api-v1";
|
|
4440
|
+
var ACME_TEMPLATES_ENDPOINT = "templates";
|
|
4332
4441
|
var TEMPLATES_PATH = "v2/b2b/event/templates/names?pageSize=-1&page=1";
|
|
4442
|
+
var ACME_API_ENDPOINTS = new ApiEndpoints({
|
|
4443
|
+
[ACME_TEMPLATES_ENDPOINT]: ACME_EXTENDABLE_SLUG
|
|
4444
|
+
});
|
|
4333
4445
|
|
|
4334
4446
|
// src/models/acme/product.ts
|
|
4335
4447
|
var ACME_ACTIVITY_TYPE = "standard";
|
|
@@ -4367,6 +4479,7 @@ var AcmeProductService = class {
|
|
|
4367
4479
|
*/
|
|
4368
4480
|
async getAllActivities() {
|
|
4369
4481
|
const body = await this.client.get(
|
|
4482
|
+
ACME_TEMPLATES_ENDPOINT,
|
|
4370
4483
|
TEMPLATES_PATH
|
|
4371
4484
|
);
|
|
4372
4485
|
const nodes = Array.isArray(body) ? body : body?.list ?? [];
|
|
@@ -4389,9 +4502,9 @@ var RestClient2 = class {
|
|
|
4389
4502
|
* @throws {RateLimitError} on HTTP 429 after retries are exhausted
|
|
4390
4503
|
* @throws {AcmeApiError} on any other non-2xx response
|
|
4391
4504
|
*/
|
|
4392
|
-
async get(path) {
|
|
4505
|
+
async get(endpoint, path) {
|
|
4393
4506
|
const { logger } = this.options;
|
|
4394
|
-
const url = this.endpoint(path);
|
|
4507
|
+
const url = this.endpoint(endpoint, path);
|
|
4395
4508
|
logger.info("Making ACME request", { url, path });
|
|
4396
4509
|
return requestWithRetry(
|
|
4397
4510
|
this.options,
|
|
@@ -4408,10 +4521,9 @@ var RestClient2 = class {
|
|
|
4408
4521
|
}
|
|
4409
4522
|
);
|
|
4410
4523
|
}
|
|
4411
|
-
endpoint(path) {
|
|
4412
|
-
const {
|
|
4413
|
-
|
|
4414
|
-
return `${baseUrl}/${appId}/${extendableSlug}/${path}`;
|
|
4524
|
+
endpoint(endpoint, path) {
|
|
4525
|
+
const { baseApiUrl, endpoints } = this.options;
|
|
4526
|
+
return joinUrl(baseApiUrl, endpoints.pathFor(endpoint), path);
|
|
4415
4527
|
}
|
|
4416
4528
|
buildHeaders() {
|
|
4417
4529
|
return {
|
|
@@ -4435,11 +4547,10 @@ var AcmeAccessService = class {
|
|
|
4435
4547
|
if (!hasApiUrl) requireNonEmpty(config.appId ?? "", "appId", "AcmeAccessService");
|
|
4436
4548
|
const logger = config.logger ?? noopLogger;
|
|
4437
4549
|
const tokens = createTokenManager(config);
|
|
4550
|
+
const baseApiUrl = hasApiUrl ? resolveBaseApiUrl(config.apiUrl, ACME_EXTENDABLE_SLUG, "AcmeAccessService") : `${config.baseUrl ?? DEFAULT_BASE_URL3}/${config.appId}`;
|
|
4438
4551
|
this.client = new RestClient2({
|
|
4439
|
-
|
|
4440
|
-
|
|
4441
|
-
appId: hasApiUrl ? void 0 : config.appId,
|
|
4442
|
-
extendableSlug: ACME_EXTENDABLE_SLUG,
|
|
4552
|
+
baseApiUrl,
|
|
4553
|
+
endpoints: ACME_API_ENDPOINTS,
|
|
4443
4554
|
getToken: () => tokens.getToken(),
|
|
4444
4555
|
retryDelaysMs: config.retryDelaysMs ?? DEFAULT_RETRY_DELAYS_MS,
|
|
4445
4556
|
logger,
|