hanzio 1.1.0 → 1.2.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/README.md +70 -4
- package/dist/api-wrapper/builders.d.ts +13 -2
- package/dist/api-wrapper/errors.d.ts +1 -0
- package/dist/api-wrapper/headers.d.ts +2 -1
- package/dist/api-wrapper/transport.d.ts +8 -5
- package/dist/api-wrapper/types.d.ts +1 -0
- package/dist/cache/index.d.ts +26 -0
- package/dist/secrets/core.d.ts +47 -0
- package/dist/secrets/deadline.d.ts +6 -0
- package/dist/secrets/environment.d.ts +9 -0
- package/dist/secrets/errors.d.ts +11 -0
- package/dist/secrets/index.d.ts +13 -25
- package/dist/secrets/infisical-cli.d.ts +6 -0
- package/dist/secrets/infisical-config.d.ts +17 -0
- package/dist/secrets/infisical-session.d.ts +4 -0
- package/dist/secrets/infisical.d.ts +8 -13
- package/dist/secrets/loaders.d.ts +5 -12
- package/dist/secrets/vite.d.ts +7 -3
- package/dist/secrets/worker-loader.d.ts +9 -0
- package/dist/secrets/worker.d.ts +3 -0
- package/dist/src/api-wrapper/index.js +152 -122
- package/dist/src/index.js +3173 -2713
- package/dist/src/jwt/index.js +2 -2
- package/dist/src/p-queue/index.js +3 -3
- package/dist/src/secrets/index.js +670 -402
- package/dist/src/secrets/infisical.js +451 -168
- package/dist/src/secrets/loaders.js +467 -174
- package/dist/src/secrets/vite.js +33 -11
- package/dist/src/secrets/worker.js +275 -0
- package/dist/src/sitemap/index.js +1 -1
- package/dist/src/zod/index.js +7 -7
- package/dist/typedswitch/index.d.ts +9 -5
- package/package.json +12 -3
- package/src/api-wrapper/builders.ts +68 -43
- package/src/api-wrapper/create-client.ts +82 -62
- package/src/api-wrapper/errors.ts +10 -0
- package/src/api-wrapper/headers.ts +14 -1
- package/src/api-wrapper/redaction.ts +1 -0
- package/src/api-wrapper/transport.ts +34 -38
- package/src/api-wrapper/types.ts +1 -0
- package/src/cache/index.ts +228 -61
- package/src/secrets/core.ts +348 -0
- package/src/secrets/deadline.ts +69 -0
- package/src/secrets/environment.ts +69 -0
- package/src/secrets/errors.ts +29 -0
- package/src/secrets/index.ts +79 -210
- package/src/secrets/infisical-cli.ts +99 -0
- package/src/secrets/infisical-config.ts +70 -0
- package/src/secrets/infisical-session.ts +42 -0
- package/src/secrets/infisical.ts +214 -66
- package/src/secrets/loaders.ts +24 -48
- package/src/secrets/vite.ts +44 -15
- package/src/secrets/worker-loader.ts +56 -0
- package/src/secrets/worker.ts +4 -0
- package/src/typedswitch/index.ts +80 -69
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
// src/secrets/infisical.ts
|
|
2
|
+
import { z as z2 } from "zod";
|
|
1
3
|
// src/api-wrapper/headers.ts
|
|
2
4
|
var CANONICAL_HEADER_NAMES = {
|
|
3
5
|
"content-type": "Content-Type",
|
|
@@ -38,13 +40,16 @@ function hasJsonContentType(headers) {
|
|
|
38
40
|
const ct = getHeader(headers, "content-type") ?? "";
|
|
39
41
|
return ct.includes("application/json");
|
|
40
42
|
}
|
|
41
|
-
function buildFetchBody(body, headers) {
|
|
43
|
+
function buildFetchBody(body, headers, configError) {
|
|
42
44
|
if (body === undefined || body === null)
|
|
43
45
|
return;
|
|
44
46
|
if (body instanceof FormData || body instanceof Blob)
|
|
45
47
|
return body;
|
|
46
48
|
if (hasJsonContentType(headers))
|
|
47
49
|
return JSON.stringify(body);
|
|
50
|
+
if (typeof body === "object" && (Object.getPrototypeOf(body) === Object.prototype || Object.getPrototypeOf(body) === null) && configError) {
|
|
51
|
+
throw configError("Request body is a plain object but Content-Type is not application/json");
|
|
52
|
+
}
|
|
48
53
|
return body;
|
|
49
54
|
}
|
|
50
55
|
function getHeadersAsObject(headers) {
|
|
@@ -339,39 +344,61 @@ var isNetworkError = (e) => e instanceof NetworkError;
|
|
|
339
344
|
var isRequestAbortedError = (e) => e instanceof RequestAbortedError;
|
|
340
345
|
var isConfigError = (e) => e instanceof ConfigError;
|
|
341
346
|
var isActionError = (e) => e instanceof ActionError;
|
|
347
|
+
function isNonRetryableApiError(error) {
|
|
348
|
+
return error instanceof HttpResponseError || error instanceof ResponseValidationError || error instanceof RequestValidationError || error instanceof ConfigError || error instanceof RequestAbortedError;
|
|
349
|
+
}
|
|
342
350
|
// src/api-wrapper/builders.ts
|
|
343
351
|
import { ZodError as ZodError2 } from "zod";
|
|
344
|
-
function
|
|
352
|
+
function formatQueryString(queryParams, doNotEncode) {
|
|
353
|
+
if (Object.keys(queryParams).length === 0)
|
|
354
|
+
return "";
|
|
355
|
+
return doNotEncode ? Object.entries(queryParams).map(([key, value]) => `${key}=${value}`).join("&") : new URLSearchParams(queryParams).toString();
|
|
356
|
+
}
|
|
357
|
+
function buildUrl(options) {
|
|
358
|
+
const {
|
|
359
|
+
endpoint,
|
|
360
|
+
params,
|
|
361
|
+
queryParams,
|
|
362
|
+
baseApiUrls,
|
|
363
|
+
defaultBaseApiUrl,
|
|
364
|
+
url,
|
|
365
|
+
doNotEncodeQueryParams,
|
|
366
|
+
configError
|
|
367
|
+
} = options;
|
|
368
|
+
let finalUrl;
|
|
345
369
|
if (url) {
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
}
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
throw configError(`Unknown base API URL: ${baseUrlKey}`);
|
|
370
|
+
finalUrl = replacePathParams(url, params, configError);
|
|
371
|
+
} else {
|
|
372
|
+
const defaultBaseUrl = defaultBaseApiUrl ?? Object.keys(baseApiUrls)[0];
|
|
373
|
+
if (!defaultBaseUrl) {
|
|
374
|
+
throw configError("At least one base API URL is required");
|
|
375
|
+
}
|
|
376
|
+
const baseUrlKey = endpoint.baseApiUrl ?? defaultBaseUrl;
|
|
377
|
+
const configBaseUrl = baseApiUrls[baseUrlKey];
|
|
378
|
+
if (!configBaseUrl) {
|
|
379
|
+
throw configError(`Unknown base API URL: ${baseUrlKey}`);
|
|
380
|
+
}
|
|
381
|
+
const baseUrl = typeof configBaseUrl === "function" ? configBaseUrl() : configBaseUrl;
|
|
382
|
+
const path = typeof endpoint.path === "function" ? endpoint.path(baseUrl) : endpoint.path;
|
|
383
|
+
finalUrl = `${baseUrl}${replacePathParams(path, params, configError)}`;
|
|
361
384
|
}
|
|
362
|
-
const
|
|
363
|
-
const path = typeof endpoint.path === "function" ? endpoint.path(baseUrl) : endpoint.path;
|
|
364
|
-
const finalUrl = replacePathParams(`${baseUrl}${path}`, params, configError);
|
|
365
|
-
const queryString = new URLSearchParams(buildQueryParamsRaw(endpoint, reqQuery)).toString();
|
|
385
|
+
const queryString = formatQueryString(queryParams, doNotEncodeQueryParams);
|
|
366
386
|
return {
|
|
367
387
|
finalUrl,
|
|
368
388
|
fullUrl: queryString ? `${finalUrl}?${queryString}` : finalUrl
|
|
369
389
|
};
|
|
370
390
|
}
|
|
371
|
-
function
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
391
|
+
function buildPathParams(endpoint, params, ctx) {
|
|
392
|
+
if (!endpoint.reqParamsSchema)
|
|
393
|
+
return params;
|
|
394
|
+
try {
|
|
395
|
+
return endpoint.reqParamsSchema.parse(params);
|
|
396
|
+
} catch (error) {
|
|
397
|
+
if (error instanceof ZodError2) {
|
|
398
|
+
throw new RequestValidationError(error, "params", params, ctx());
|
|
399
|
+
}
|
|
400
|
+
throw error;
|
|
401
|
+
}
|
|
375
402
|
}
|
|
376
403
|
function buildQueryParams(endpoint, query, ctx) {
|
|
377
404
|
const defaultParams = endpoint.reqDefaultQueryParams ?? {};
|
|
@@ -504,8 +531,8 @@ function createActionCache() {
|
|
|
504
531
|
function makeDefineAction() {
|
|
505
532
|
function defineAction(...args) {
|
|
506
533
|
if (args.length === 0) {
|
|
507
|
-
return (
|
|
508
|
-
...
|
|
534
|
+
return (def) => ({
|
|
535
|
+
...def,
|
|
509
536
|
noRuntimeInput: false
|
|
510
537
|
});
|
|
511
538
|
}
|
|
@@ -536,6 +563,7 @@ var SENSITIVE_BODY_KEYS = new Set([
|
|
|
536
563
|
"refresh_token",
|
|
537
564
|
"secret",
|
|
538
565
|
"client_secret",
|
|
566
|
+
"clientsecret",
|
|
539
567
|
"apikey",
|
|
540
568
|
"api_key"
|
|
541
569
|
]);
|
|
@@ -626,16 +654,14 @@ async function validateResponse(schema, data, ctx) {
|
|
|
626
654
|
}
|
|
627
655
|
}
|
|
628
656
|
async function httpRequest(config, ctx) {
|
|
629
|
-
const queryString = config.doNotEncodeQueryParams ? Object.entries(config.queryParams).map(([key, value]) => `${key}=${value}`).join("&") : new URLSearchParams(config.queryParams).toString();
|
|
630
|
-
const fullUrl = queryString ? `${config.url}?${queryString}` : config.url;
|
|
631
657
|
const timeoutController = new AbortController;
|
|
632
658
|
const timeout = config.timeoutMs === undefined ? undefined : setTimeout(() => timeoutController.abort(), config.timeoutMs);
|
|
633
659
|
const signal = mergeSignals(timeoutController.signal, config.userSignal);
|
|
634
660
|
try {
|
|
635
|
-
return await config.fetchFn(fullUrl, {
|
|
661
|
+
return await config.fetchFn(config.fullUrl, {
|
|
636
662
|
method: config.method,
|
|
637
663
|
headers: config.headers,
|
|
638
|
-
body: buildFetchBody(config.body, config.headers),
|
|
664
|
+
body: buildFetchBody(config.body, config.headers, (msg) => new ConfigError(msg, ctx())),
|
|
639
665
|
signal
|
|
640
666
|
});
|
|
641
667
|
} catch (error) {
|
|
@@ -648,6 +674,8 @@ async function httpRequest(config, ctx) {
|
|
|
648
674
|
}
|
|
649
675
|
throw new RequestAbortedError(ctx(), error);
|
|
650
676
|
}
|
|
677
|
+
if (error instanceof ConfigError)
|
|
678
|
+
throw error;
|
|
651
679
|
throw new NetworkError(error instanceof Error ? error.message : String(error), ctx(), error);
|
|
652
680
|
} finally {
|
|
653
681
|
if (timeout)
|
|
@@ -684,35 +712,26 @@ async function readErrorResponse(response) {
|
|
|
684
712
|
};
|
|
685
713
|
}
|
|
686
714
|
function getRetryDelay(params) {
|
|
715
|
+
const maxDelay = params.maxRetryDelayMs ?? 30000;
|
|
687
716
|
const { retryDelay, attempt, response } = params;
|
|
688
717
|
if (response && (response.status === 429 || response.status === 503)) {
|
|
689
718
|
const retryAfter = response.headers.get("retry-after");
|
|
690
719
|
if (retryAfter) {
|
|
691
720
|
const seconds = Number(retryAfter);
|
|
692
|
-
if (Number.isFinite(seconds))
|
|
693
|
-
return seconds * 1000;
|
|
721
|
+
if (Number.isFinite(seconds)) {
|
|
722
|
+
return Math.min(Math.max(0, seconds * 1000), maxDelay);
|
|
723
|
+
}
|
|
694
724
|
const dateMs = Date.parse(retryAfter);
|
|
695
725
|
if (!Number.isNaN(dateMs)) {
|
|
696
|
-
return Math.max(0, dateMs - Date.now());
|
|
726
|
+
return Math.min(Math.max(0, dateMs - Date.now()), maxDelay);
|
|
697
727
|
}
|
|
698
728
|
}
|
|
699
729
|
}
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
return retryDelay;
|
|
730
|
+
const delayMs = typeof retryDelay === "function" ? retryDelay(attempt) : retryDelay;
|
|
731
|
+
return Math.min(delayMs, maxDelay);
|
|
703
732
|
}
|
|
704
733
|
function shouldAttemptRetryOnError(error) {
|
|
705
|
-
|
|
706
|
-
return false;
|
|
707
|
-
if (error instanceof ResponseValidationError)
|
|
708
|
-
return false;
|
|
709
|
-
if (error instanceof RequestValidationError)
|
|
710
|
-
return false;
|
|
711
|
-
if (error instanceof ConfigError)
|
|
712
|
-
return false;
|
|
713
|
-
if (error instanceof RequestAbortedError)
|
|
714
|
-
return false;
|
|
715
|
-
return true;
|
|
734
|
+
return !isNonRetryableApiError(error);
|
|
716
735
|
}
|
|
717
736
|
function shouldAttemptRetryOnHttp(retryCtx) {
|
|
718
737
|
const { error, response } = retryCtx;
|
|
@@ -725,6 +744,7 @@ async function makeRequestWithRetry(args) {
|
|
|
725
744
|
config,
|
|
726
745
|
maxRetries,
|
|
727
746
|
retryDelay,
|
|
747
|
+
maxRetryDelayMs,
|
|
728
748
|
validateFn,
|
|
729
749
|
shouldRetry,
|
|
730
750
|
logger,
|
|
@@ -763,7 +783,8 @@ async function makeRequestWithRetry(args) {
|
|
|
763
783
|
const delayMs = getRetryDelay({
|
|
764
784
|
retryDelay,
|
|
765
785
|
attempt: retryCount,
|
|
766
|
-
response
|
|
786
|
+
response,
|
|
787
|
+
maxRetryDelayMs
|
|
767
788
|
});
|
|
768
789
|
await onRetry?.({
|
|
769
790
|
...retryCtx,
|
|
@@ -778,12 +799,12 @@ async function makeRequestWithRetry(args) {
|
|
|
778
799
|
throw new HttpResponseError(response.status, body, responseHeaders, ctx({ attempt: retryCount }));
|
|
779
800
|
}
|
|
780
801
|
return {
|
|
781
|
-
validatedData: await validateFn(response),
|
|
802
|
+
validatedData: await validateFn(response, retryCount),
|
|
782
803
|
retryCount,
|
|
783
804
|
httpStatus: response.status
|
|
784
805
|
};
|
|
785
806
|
} catch (error) {
|
|
786
|
-
if (error
|
|
807
|
+
if (isNonRetryableApiError(error)) {
|
|
787
808
|
throw error;
|
|
788
809
|
}
|
|
789
810
|
const retryCtx = {
|
|
@@ -800,7 +821,8 @@ async function makeRequestWithRetry(args) {
|
|
|
800
821
|
const delayMs = getRetryDelay({
|
|
801
822
|
retryDelay,
|
|
802
823
|
attempt: retryCount,
|
|
803
|
-
response: undefined
|
|
824
|
+
response: undefined,
|
|
825
|
+
maxRetryDelayMs
|
|
804
826
|
});
|
|
805
827
|
await onRetry?.({
|
|
806
828
|
...retryCtx,
|
|
@@ -814,19 +836,21 @@ async function makeRequestWithRetry(args) {
|
|
|
814
836
|
}
|
|
815
837
|
async function validateAndTransformResponse(endpoint, response, ctx) {
|
|
816
838
|
const responseHeaders = getHeadersAsObject(response.headers);
|
|
839
|
+
const text = await response.text();
|
|
840
|
+
const responseSizeBytes = new TextEncoder().encode(text).length;
|
|
817
841
|
let responseData;
|
|
818
842
|
if (hasJsonContentType(responseHeaders)) {
|
|
819
|
-
const text = await response.text();
|
|
820
843
|
try {
|
|
821
844
|
responseData = text === "" ? undefined : JSON.parse(text);
|
|
822
845
|
} catch (error) {
|
|
823
846
|
throw new ResponseValidationError(makeJsonParseZodError(error, text), text, ctx());
|
|
824
847
|
}
|
|
825
848
|
} else {
|
|
826
|
-
responseData =
|
|
849
|
+
responseData = text;
|
|
827
850
|
}
|
|
828
851
|
const transformedData = endpoint.resFormatter ? endpoint.resFormatter(responseData, responseHeaders) : responseData;
|
|
829
|
-
|
|
852
|
+
const data = await validateResponse(endpoint.resSchema, transformedData, ctx);
|
|
853
|
+
return { data, responseSizeBytes };
|
|
830
854
|
}
|
|
831
855
|
function defaultShouldRetry(ctx) {
|
|
832
856
|
if (ctx.error)
|
|
@@ -845,6 +869,28 @@ function isActionInvokeOptionsOnly(value) {
|
|
|
845
869
|
return false;
|
|
846
870
|
return Object.keys(value).every((k) => k === "signal" || k === "meta");
|
|
847
871
|
}
|
|
872
|
+
function resolveActionInvocation(action, actionName, first, second) {
|
|
873
|
+
if (!action.noRuntimeInput) {
|
|
874
|
+
return { input: first, options: second ?? {} };
|
|
875
|
+
}
|
|
876
|
+
if (first === undefined || first === null) {
|
|
877
|
+
return { input: undefined, options: second ?? {} };
|
|
878
|
+
}
|
|
879
|
+
if (second !== undefined) {
|
|
880
|
+
return { input: undefined, options: second };
|
|
881
|
+
}
|
|
882
|
+
if (isActionInvokeOptionsOnly(first)) {
|
|
883
|
+
return { input: undefined, options: first };
|
|
884
|
+
}
|
|
885
|
+
throw new ConfigError(`Action "${actionName}" does not accept input; pass only optional { signal, meta }`, {
|
|
886
|
+
endpoint: actionName,
|
|
887
|
+
method: "GET",
|
|
888
|
+
url: "",
|
|
889
|
+
attempt: 0,
|
|
890
|
+
maxRetries: 0,
|
|
891
|
+
elapsedMs: 0
|
|
892
|
+
});
|
|
893
|
+
}
|
|
848
894
|
function createApiClientImpl(apiConfig) {
|
|
849
895
|
let actions = {};
|
|
850
896
|
const cache = createActionCache();
|
|
@@ -873,22 +919,12 @@ function createApiClientImpl(apiConfig) {
|
|
|
873
919
|
throw await reportApiError(new ConfigError(`Unknown API endpoint: ${String(endpointKey)}`, ctx()), apiConfig);
|
|
874
920
|
}
|
|
875
921
|
baseContext.method = endpoint.method;
|
|
876
|
-
let
|
|
877
|
-
let fullUrl;
|
|
878
|
-
try {
|
|
879
|
-
const built = buildUrl(endpoint, rawInput.reqParams, rawInput.reqQuery, apiConfig.baseApiUrls, apiConfig.defaultBaseApiUrl, input.url, (msg) => new ConfigError(msg, ctx()));
|
|
880
|
-
finalUrl = built.finalUrl;
|
|
881
|
-
fullUrl = built.fullUrl;
|
|
882
|
-
} catch (e) {
|
|
883
|
-
if (e instanceof ApiError)
|
|
884
|
-
throw await reportApiError(e, apiConfig);
|
|
885
|
-
throw e;
|
|
886
|
-
}
|
|
887
|
-
baseContext.url = fullUrl;
|
|
922
|
+
let pathParams;
|
|
888
923
|
let queryParams;
|
|
889
924
|
let body;
|
|
890
925
|
let headers;
|
|
891
926
|
try {
|
|
927
|
+
pathParams = buildPathParams(endpoint, rawInput.reqParams, ctx);
|
|
892
928
|
queryParams = buildQueryParams(endpoint, rawInput.reqQuery, ctx);
|
|
893
929
|
body = buildRequestBody(endpoint, rawInput.reqBody, ctx);
|
|
894
930
|
headers = buildHeaders(endpoint, rawInput.reqHeaders, apiConfig.defaultHeaders ?? {}, ctx);
|
|
@@ -897,6 +933,25 @@ function createApiClientImpl(apiConfig) {
|
|
|
897
933
|
throw await reportApiError(e, apiConfig);
|
|
898
934
|
throw e;
|
|
899
935
|
}
|
|
936
|
+
let fullUrl;
|
|
937
|
+
try {
|
|
938
|
+
const built = buildUrl({
|
|
939
|
+
endpoint,
|
|
940
|
+
params: pathParams,
|
|
941
|
+
queryParams,
|
|
942
|
+
baseApiUrls: apiConfig.baseApiUrls,
|
|
943
|
+
defaultBaseApiUrl: apiConfig.defaultBaseApiUrl,
|
|
944
|
+
url: input.url,
|
|
945
|
+
doNotEncodeQueryParams: endpoint.doNotEncodeQueryParams,
|
|
946
|
+
configError: (msg) => new ConfigError(msg, ctx())
|
|
947
|
+
});
|
|
948
|
+
fullUrl = built.fullUrl;
|
|
949
|
+
} catch (e) {
|
|
950
|
+
if (e instanceof ApiError)
|
|
951
|
+
throw await reportApiError(e, apiConfig);
|
|
952
|
+
throw e;
|
|
953
|
+
}
|
|
954
|
+
baseContext.url = fullUrl;
|
|
900
955
|
baseContext.requestHeaders = headers;
|
|
901
956
|
baseContext.requestBody = body;
|
|
902
957
|
if (apiConfig.onRequest) {
|
|
@@ -921,11 +976,9 @@ function createApiClientImpl(apiConfig) {
|
|
|
921
976
|
}
|
|
922
977
|
const config = {
|
|
923
978
|
method: endpoint.method,
|
|
924
|
-
|
|
925
|
-
queryParams,
|
|
979
|
+
fullUrl,
|
|
926
980
|
body,
|
|
927
981
|
headers,
|
|
928
|
-
doNotEncodeQueryParams: endpoint.doNotEncodeQueryParams,
|
|
929
982
|
timeoutMs: input.timeoutMs ?? apiConfig.timeoutMs,
|
|
930
983
|
fetchFn: input.fetch ?? apiConfig.fetch ?? fetch,
|
|
931
984
|
userSignal: input.signal
|
|
@@ -935,7 +988,8 @@ function createApiClientImpl(apiConfig) {
|
|
|
935
988
|
config,
|
|
936
989
|
maxRetries,
|
|
937
990
|
retryDelay: apiConfig.retryDelayMs ?? 300,
|
|
938
|
-
|
|
991
|
+
maxRetryDelayMs: apiConfig.maxRetryDelayMs,
|
|
992
|
+
validateFn: (response, attempt) => validateAndTransformResponse(endpoint, response, (over) => ctx({ attempt, ...over })),
|
|
939
993
|
shouldRetry: apiConfig.shouldRetry ?? defaultShouldRetry,
|
|
940
994
|
logger: apiConfig.logger,
|
|
941
995
|
ctx,
|
|
@@ -947,10 +1001,10 @@ function createApiClientImpl(apiConfig) {
|
|
|
947
1001
|
onRetry: apiConfig.onRetry
|
|
948
1002
|
});
|
|
949
1003
|
const responseTimeMs = elapsed();
|
|
950
|
-
const responseSizeMb =
|
|
1004
|
+
const responseSizeMb = result.validatedData.responseSizeBytes / (1024 * 1024);
|
|
951
1005
|
const requestBodySizeMb = calculateSizeInMb(config.body);
|
|
952
1006
|
return {
|
|
953
|
-
data: result.validatedData,
|
|
1007
|
+
data: result.validatedData.data,
|
|
954
1008
|
requestBodySizeMb,
|
|
955
1009
|
responseSizeMb,
|
|
956
1010
|
responseTimeMs,
|
|
@@ -1006,22 +1060,14 @@ function createApiClientImpl(apiConfig) {
|
|
|
1006
1060
|
throw await reportApiError(wrapped, apiConfig);
|
|
1007
1061
|
}
|
|
1008
1062
|
}
|
|
1063
|
+
async function dispatchAction(name, first, second) {
|
|
1064
|
+
const action = actions[name];
|
|
1065
|
+
const { input, options } = resolveActionInvocation(action, name, first, second);
|
|
1066
|
+
return invokeAction(name, input, options);
|
|
1067
|
+
}
|
|
1009
1068
|
const request = async (key, input, options) => {
|
|
1010
1069
|
if (key in actions) {
|
|
1011
|
-
|
|
1012
|
-
if (action.noRuntimeInput) {
|
|
1013
|
-
if (input === undefined || input === null) {
|
|
1014
|
-
return invokeAction(key, undefined, options ?? {});
|
|
1015
|
-
}
|
|
1016
|
-
if (options !== undefined) {
|
|
1017
|
-
return invokeAction(key, undefined, options);
|
|
1018
|
-
}
|
|
1019
|
-
if (isActionInvokeOptionsOnly(input)) {
|
|
1020
|
-
return invokeAction(key, undefined, input);
|
|
1021
|
-
}
|
|
1022
|
-
return invokeAction(key, undefined, {});
|
|
1023
|
-
}
|
|
1024
|
-
return invokeAction(key, input, options);
|
|
1070
|
+
return dispatchAction(key, input, options);
|
|
1025
1071
|
}
|
|
1026
1072
|
return invokeEndpoint(key, input ?? {});
|
|
1027
1073
|
};
|
|
@@ -1035,22 +1081,7 @@ function createApiClientImpl(apiConfig) {
|
|
|
1035
1081
|
return (input) => invokeEndpoint(prop, input ?? {});
|
|
1036
1082
|
}
|
|
1037
1083
|
if (prop in actions) {
|
|
1038
|
-
|
|
1039
|
-
if (action.noRuntimeInput) {
|
|
1040
|
-
return (first, second) => {
|
|
1041
|
-
if (first === undefined || first === null) {
|
|
1042
|
-
return invokeAction(prop, undefined, second ?? {});
|
|
1043
|
-
}
|
|
1044
|
-
if (second !== undefined) {
|
|
1045
|
-
return invokeAction(prop, undefined, second);
|
|
1046
|
-
}
|
|
1047
|
-
if (isActionInvokeOptionsOnly(first)) {
|
|
1048
|
-
return invokeAction(prop, undefined, first);
|
|
1049
|
-
}
|
|
1050
|
-
return invokeAction(prop, undefined, {});
|
|
1051
|
-
};
|
|
1052
|
-
}
|
|
1053
|
-
return (input, opt) => invokeAction(prop, input, opt);
|
|
1084
|
+
return (first, second) => dispatchAction(prop, first, second);
|
|
1054
1085
|
}
|
|
1055
1086
|
return;
|
|
1056
1087
|
}
|
|
@@ -1078,72 +1109,306 @@ function createApiClientImpl(apiConfig) {
|
|
|
1078
1109
|
return proxy;
|
|
1079
1110
|
}
|
|
1080
1111
|
var createApiClient = (apiConfig) => createApiClientImpl(apiConfig);
|
|
1081
|
-
// src/secrets/
|
|
1112
|
+
// src/secrets/errors.ts
|
|
1113
|
+
class SecretLoadError extends Error {
|
|
1114
|
+
code;
|
|
1115
|
+
operation;
|
|
1116
|
+
status;
|
|
1117
|
+
constructor(code, message, details = {}) {
|
|
1118
|
+
super(message);
|
|
1119
|
+
this.name = "SecretLoadError";
|
|
1120
|
+
this.code = code;
|
|
1121
|
+
this.operation = details.operation;
|
|
1122
|
+
this.status = details.status;
|
|
1123
|
+
}
|
|
1124
|
+
}
|
|
1125
|
+
|
|
1126
|
+
// src/secrets/deadline.ts
|
|
1127
|
+
async function withSecretDeadline(options, operation) {
|
|
1128
|
+
const timeoutMs = options.timeoutMs ?? 30000;
|
|
1129
|
+
if (!Number.isFinite(timeoutMs) || timeoutMs <= 0 || timeoutMs > 2147483647) {
|
|
1130
|
+
throw new SecretLoadError("CONFIGURATION", "Secret timeoutMs must be a positive finite timer duration.");
|
|
1131
|
+
}
|
|
1132
|
+
const controller = new AbortController;
|
|
1133
|
+
const cancel = () => controller.abort(new SecretLoadError("ABORTED", "Secret loading was cancelled."));
|
|
1134
|
+
if (options.signal?.aborted) {
|
|
1135
|
+
cancel();
|
|
1136
|
+
} else {
|
|
1137
|
+
options.signal?.addEventListener("abort", cancel, { once: true });
|
|
1138
|
+
}
|
|
1139
|
+
const timer = setTimeout(() => controller.abort(new SecretLoadError("TIMEOUT", `Secret loading timed out after ${timeoutMs}ms.`)), timeoutMs);
|
|
1140
|
+
let rejectOnAbort = () => {};
|
|
1141
|
+
try {
|
|
1142
|
+
const aborted = new Promise((_, reject) => {
|
|
1143
|
+
rejectOnAbort = () => reject(controller.signal.reason);
|
|
1144
|
+
controller.signal.addEventListener("abort", rejectOnAbort, { once: true });
|
|
1145
|
+
});
|
|
1146
|
+
if (controller.signal.aborted) {
|
|
1147
|
+
throw controller.signal.reason;
|
|
1148
|
+
}
|
|
1149
|
+
return await Promise.race([operation(controller.signal), aborted]);
|
|
1150
|
+
} finally {
|
|
1151
|
+
clearTimeout(timer);
|
|
1152
|
+
options.signal?.removeEventListener("abort", cancel);
|
|
1153
|
+
controller.signal.removeEventListener("abort", rejectOnAbort);
|
|
1154
|
+
}
|
|
1155
|
+
}
|
|
1156
|
+
|
|
1157
|
+
// src/secrets/environment.ts
|
|
1158
|
+
function getProcessEnvironment() {
|
|
1159
|
+
return typeof process === "undefined" ? undefined : process.env;
|
|
1160
|
+
}
|
|
1161
|
+
function resolveSecretEnvironment(option, env) {
|
|
1162
|
+
const explicit = typeof option === "function" ? option() : option;
|
|
1163
|
+
if (typeof explicit === "object" && explicit !== null) {
|
|
1164
|
+
if (typeof explicit.slug !== "string" || !/^[a-zA-Z0-9][a-zA-Z0-9_-]*$/.test(explicit.slug)) {
|
|
1165
|
+
throw new SecretLoadError("CONFIGURATION", "Custom secret environment requires a valid slug.");
|
|
1166
|
+
}
|
|
1167
|
+
return explicit.slug;
|
|
1168
|
+
}
|
|
1169
|
+
const selected = explicit ?? env?.SECRETS_ENV;
|
|
1170
|
+
if (selected !== undefined) {
|
|
1171
|
+
if (selected === "production" || selected === "prod") {
|
|
1172
|
+
return "prod";
|
|
1173
|
+
}
|
|
1174
|
+
if (selected === "development" || selected === "dev") {
|
|
1175
|
+
return "dev";
|
|
1176
|
+
}
|
|
1177
|
+
if (selected === "staging") {
|
|
1178
|
+
return "staging";
|
|
1179
|
+
}
|
|
1180
|
+
throw new SecretLoadError("CONFIGURATION", "Invalid secret environment. Use dev, staging, prod, or an explicit { slug } option.");
|
|
1181
|
+
}
|
|
1182
|
+
if (env?.NODE_ENV === "production" || env?.NODE_ENV === "prod") {
|
|
1183
|
+
return "prod";
|
|
1184
|
+
}
|
|
1185
|
+
if (env?.NODE_ENV === "staging") {
|
|
1186
|
+
return "staging";
|
|
1187
|
+
}
|
|
1188
|
+
return "dev";
|
|
1189
|
+
}
|
|
1190
|
+
|
|
1191
|
+
// src/secrets/infisical-cli.ts
|
|
1192
|
+
async function readInfisicalCliToken(options) {
|
|
1193
|
+
const { execFile } = await import("node:child_process").catch(() => {
|
|
1194
|
+
throw new SecretLoadError("CLI", "Infisical CLI fallback requires a runtime with subprocess support. Provide Infisical client credentials or a custom secret loader.");
|
|
1195
|
+
});
|
|
1196
|
+
options.signal.throwIfAborted();
|
|
1197
|
+
const env = {
|
|
1198
|
+
...getProcessEnvironment(),
|
|
1199
|
+
INFISICAL_DISABLE_UPDATE_CHECK: "true"
|
|
1200
|
+
};
|
|
1201
|
+
delete env.INFISICAL_TOKEN;
|
|
1202
|
+
delete env.INFISICAL_UNIVERSAL_AUTH_ACCESS_TOKEN;
|
|
1203
|
+
delete env.TOKEN;
|
|
1204
|
+
try {
|
|
1205
|
+
const stdout = await new Promise((resolve, reject) => {
|
|
1206
|
+
const child = execFile("infisical", [
|
|
1207
|
+
"user",
|
|
1208
|
+
"get",
|
|
1209
|
+
"token",
|
|
1210
|
+
"--plain",
|
|
1211
|
+
`--domain=${options.siteUrl}`,
|
|
1212
|
+
"--silent"
|
|
1213
|
+
], {
|
|
1214
|
+
env,
|
|
1215
|
+
encoding: "utf8",
|
|
1216
|
+
shell: false,
|
|
1217
|
+
timeout: options.timeoutMs ?? 30000,
|
|
1218
|
+
signal: options.signal,
|
|
1219
|
+
killSignal: "SIGKILL",
|
|
1220
|
+
maxBuffer: 10485760,
|
|
1221
|
+
windowsHide: true
|
|
1222
|
+
}, (error, output) => {
|
|
1223
|
+
if (error) {
|
|
1224
|
+
reject(error);
|
|
1225
|
+
} else {
|
|
1226
|
+
resolve(output);
|
|
1227
|
+
}
|
|
1228
|
+
});
|
|
1229
|
+
child.stdin?.end();
|
|
1230
|
+
});
|
|
1231
|
+
return stdout.trim();
|
|
1232
|
+
} catch (error) {
|
|
1233
|
+
if (options.signal.aborted) {
|
|
1234
|
+
throw options.signal.reason;
|
|
1235
|
+
}
|
|
1236
|
+
const failure = error;
|
|
1237
|
+
if (failure?.code === "ENOENT") {
|
|
1238
|
+
throw new SecretLoadError("CLI", "Infisical CLI not found. Install infisical and ensure it is on PATH, or provide Infisical client credentials.");
|
|
1239
|
+
}
|
|
1240
|
+
if (failure?.code === "ERR_CHILD_PROCESS_STDIO_MAXBUFFER") {
|
|
1241
|
+
throw new SecretLoadError("CLI", "Infisical CLI output exceeded the 10 MiB limit.");
|
|
1242
|
+
}
|
|
1243
|
+
if (failure?.killed) {
|
|
1244
|
+
throw new SecretLoadError("TIMEOUT", `Infisical CLI timed out after ${(options.timeoutMs ?? 30000) / 1000} seconds or was terminated.`);
|
|
1245
|
+
}
|
|
1246
|
+
throw new SecretLoadError("CLI", `Infisical CLI session token failed. Run infisical login --domain=${options.siteUrl} and verify access to the configured organization, project, and environment.`);
|
|
1247
|
+
}
|
|
1248
|
+
}
|
|
1249
|
+
|
|
1250
|
+
// src/secrets/infisical-config.ts
|
|
1251
|
+
function validateInfisicalScope(options) {
|
|
1252
|
+
validateInfisicalOrganizationId(options.organizationId);
|
|
1253
|
+
let url;
|
|
1254
|
+
try {
|
|
1255
|
+
url = new URL(options.siteUrl);
|
|
1256
|
+
} catch {
|
|
1257
|
+
throw new SecretLoadError("CONFIGURATION", "Invalid Infisical siteUrl.");
|
|
1258
|
+
}
|
|
1259
|
+
if (!["http:", "https:"].includes(url.protocol) || url.username || url.password || url.search || url.hash) {
|
|
1260
|
+
throw new SecretLoadError("CONFIGURATION", "Infisical siteUrl must be an HTTP(S) URL without credentials, query, or fragment.");
|
|
1261
|
+
}
|
|
1262
|
+
if (!options.projectId.trim() || !options.environment.trim() || !(options.secretPath ?? "/").startsWith("/")) {
|
|
1263
|
+
throw new SecretLoadError("CONFIGURATION", "Infisical requires a projectId, environment, and absolute secretPath.");
|
|
1264
|
+
}
|
|
1265
|
+
}
|
|
1266
|
+
function validateInfisicalOrganizationId(organizationId) {
|
|
1267
|
+
if (typeof organizationId !== "string" || !organizationId.trim() || /\s/.test(organizationId)) {
|
|
1268
|
+
throw new SecretLoadError("CONFIGURATION", "Infisical organizationId is required and must be a nonempty ID without whitespace.");
|
|
1269
|
+
}
|
|
1270
|
+
}
|
|
1271
|
+
|
|
1272
|
+
// src/secrets/infisical-session.ts
|
|
1082
1273
|
import { z } from "zod";
|
|
1274
|
+
var sessionClaimsSchema = z.object({
|
|
1275
|
+
organizationId: z.string().optional(),
|
|
1276
|
+
subOrganizationId: z.string().optional(),
|
|
1277
|
+
exp: z.number().finite().optional()
|
|
1278
|
+
});
|
|
1279
|
+
function parseInfisicalSessionToken(token) {
|
|
1280
|
+
let claims;
|
|
1281
|
+
try {
|
|
1282
|
+
if (!/^[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+$/.test(token)) {
|
|
1283
|
+
throw new Error("Invalid token format");
|
|
1284
|
+
}
|
|
1285
|
+
const payload = token.split(".")[1];
|
|
1286
|
+
const json = atob(payload.replace(/-/g, "+").replace(/_/g, "/"));
|
|
1287
|
+
claims = sessionClaimsSchema.parse(JSON.parse(json));
|
|
1288
|
+
} catch {
|
|
1289
|
+
throw new SecretLoadError("AUTHENTICATION", "Infisical returned an invalid user session token. Run infisical login for the configured domain.");
|
|
1290
|
+
}
|
|
1291
|
+
if (claims.exp !== undefined && claims.exp <= Date.now() / 1000) {
|
|
1292
|
+
throw new SecretLoadError("AUTHENTICATION", "Infisical user session has expired. Run infisical login for the configured domain.");
|
|
1293
|
+
}
|
|
1294
|
+
return { organizationId: claims.subOrganizationId ?? claims.organizationId };
|
|
1295
|
+
}
|
|
1296
|
+
|
|
1297
|
+
// src/secrets/infisical.ts
|
|
1083
1298
|
var DEFAULT_INFISICAL_SITE_URL = "https://eu.infisical.com";
|
|
1084
1299
|
var defaultFetch = globalThis.fetch;
|
|
1085
|
-
var infisicalAuthResponseSchema =
|
|
1086
|
-
|
|
1300
|
+
var infisicalAuthResponseSchema = z2.object({ accessToken: z2.string() });
|
|
1301
|
+
var infisicalSecretSchema = z2.object({
|
|
1302
|
+
secretKey: z2.string(),
|
|
1303
|
+
secretValue: z2.string()
|
|
1087
1304
|
});
|
|
1088
|
-
var
|
|
1089
|
-
|
|
1090
|
-
secretValue: z.string()
|
|
1305
|
+
var infisicalSecretsResponseSchema = z2.object({
|
|
1306
|
+
secrets: z2.array(infisicalSecretSchema)
|
|
1091
1307
|
});
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1308
|
+
async function fetchInfisicalSecrets(options) {
|
|
1309
|
+
validateInfisicalScope(options);
|
|
1310
|
+
return withSecretDeadline(options, async (signal) => {
|
|
1311
|
+
let operation = "login";
|
|
1312
|
+
try {
|
|
1313
|
+
const infisical = createInfisicalApiClient(options.siteUrl);
|
|
1314
|
+
const { data: auth } = await infisical.request("login", {
|
|
1315
|
+
signal,
|
|
1316
|
+
reqBody: {
|
|
1317
|
+
clientId: options.clientId,
|
|
1318
|
+
clientSecret: options.clientSecret
|
|
1319
|
+
}
|
|
1320
|
+
});
|
|
1321
|
+
signal.throwIfAborted();
|
|
1322
|
+
operation = "listSecrets";
|
|
1323
|
+
return await listInfisicalSecrets(infisical, auth.accessToken, {
|
|
1324
|
+
...options,
|
|
1325
|
+
signal
|
|
1326
|
+
});
|
|
1327
|
+
} catch (error) {
|
|
1328
|
+
throwInfisicalHttpError(error, operation, signal);
|
|
1108
1329
|
}
|
|
1109
1330
|
});
|
|
1331
|
+
}
|
|
1332
|
+
async function loadInfisicalSecrets(options) {
|
|
1333
|
+
validateInfisicalScope(options);
|
|
1334
|
+
const env = getProcessEnvironment();
|
|
1335
|
+
const clientId = env?.[options.clientIdEnvKey];
|
|
1336
|
+
const clientSecret = env?.[options.clientSecretEnvKey];
|
|
1337
|
+
const mode = options.auth ?? "auto";
|
|
1338
|
+
if (!["auto", "http", "cli"].includes(mode)) {
|
|
1339
|
+
throw new SecretLoadError("CONFIGURATION", "Invalid Infisical auth mode.");
|
|
1340
|
+
}
|
|
1341
|
+
const useHttp = mode === "http" || mode === "auto" && Boolean(clientId && clientSecret);
|
|
1342
|
+
if (useHttp) {
|
|
1343
|
+
if (!clientId || !clientSecret) {
|
|
1344
|
+
throw new SecretLoadError("AUTHENTICATION", "Infisical HTTP authentication requires both client credentials.");
|
|
1345
|
+
}
|
|
1346
|
+
options.reportSource?.("Infisical HTTP");
|
|
1347
|
+
return fetchInfisicalSecrets({ ...options, clientId, clientSecret });
|
|
1348
|
+
}
|
|
1349
|
+
options.reportSource?.(`Infisical CLI session (organization=${options.organizationId} project=${options.projectId} environment=${options.environment})`);
|
|
1350
|
+
return withSecretDeadline(options, (signal) => fetchInfisicalSessionSecrets({ ...options, signal }));
|
|
1351
|
+
}
|
|
1352
|
+
async function fetchInfisicalSessionSecrets(options) {
|
|
1353
|
+
const { signal } = options;
|
|
1354
|
+
let token = await readInfisicalCliToken(options);
|
|
1355
|
+
signal.throwIfAborted();
|
|
1356
|
+
const session = parseInfisicalSessionToken(token);
|
|
1357
|
+
const infisical = createInfisicalApiClient(options.siteUrl);
|
|
1358
|
+
let operation = "selectOrganization";
|
|
1359
|
+
try {
|
|
1360
|
+
if (session.organizationId !== options.organizationId) {
|
|
1361
|
+
const { data } = await infisical.request("selectOrganization", {
|
|
1362
|
+
signal,
|
|
1363
|
+
reqHeaders: {
|
|
1364
|
+
Authorization: `Bearer ${token}`,
|
|
1365
|
+
"User-Agent": "hanzio/secrets"
|
|
1366
|
+
},
|
|
1367
|
+
reqBody: { organizationId: options.organizationId }
|
|
1368
|
+
});
|
|
1369
|
+
signal.throwIfAborted();
|
|
1370
|
+
if (data.isMfaEnabled) {
|
|
1371
|
+
throw new SecretLoadError("AUTHENTICATION", "Infisical requires MFA for this organization. Complete infisical login for the target organization and configured domain before loading secrets.", { operation });
|
|
1372
|
+
}
|
|
1373
|
+
const scopedSession = parseInfisicalSessionToken(data.token);
|
|
1374
|
+
if (scopedSession.organizationId !== options.organizationId) {
|
|
1375
|
+
throw new SecretLoadError("AUTHENTICATION", "Infisical returned a session for a different organization.", { operation });
|
|
1376
|
+
}
|
|
1377
|
+
token = data.token;
|
|
1378
|
+
}
|
|
1379
|
+
signal.throwIfAborted();
|
|
1380
|
+
operation = "listSecrets";
|
|
1381
|
+
return await listInfisicalSecrets(infisical, token, options);
|
|
1382
|
+
} catch (error) {
|
|
1383
|
+
throwInfisicalHttpError(error, operation, signal);
|
|
1384
|
+
}
|
|
1385
|
+
}
|
|
1386
|
+
async function listInfisicalSecrets(infisical, token, options) {
|
|
1110
1387
|
const { data } = await infisical.request("listSecrets", {
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
},
|
|
1388
|
+
signal: options.signal,
|
|
1389
|
+
reqHeaders: { Authorization: `Bearer ${token}` },
|
|
1114
1390
|
reqQuery: {
|
|
1115
|
-
environment,
|
|
1116
|
-
projectId,
|
|
1117
|
-
secretPath: "/",
|
|
1391
|
+
environment: options.environment,
|
|
1392
|
+
projectId: options.projectId,
|
|
1393
|
+
secretPath: options.secretPath ?? "/",
|
|
1118
1394
|
viewSecretValue: true,
|
|
1119
1395
|
expandSecretReferences: true,
|
|
1120
1396
|
includeImports: true
|
|
1121
1397
|
}
|
|
1122
1398
|
});
|
|
1123
|
-
const wantedKeys = new Set(keys);
|
|
1399
|
+
const wantedKeys = new Set(options.keys);
|
|
1124
1400
|
return Object.fromEntries(data.secrets.filter((secret) => wantedKeys.has(secret.secretKey)).map((secret) => [secret.secretKey, secret.secretValue]));
|
|
1125
1401
|
}
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
const
|
|
1135
|
-
|
|
1136
|
-
if (!clientId || !clientSecret) {
|
|
1137
|
-
throw new Error("Missing Infisical credentials");
|
|
1138
|
-
}
|
|
1139
|
-
return fetchInfisicalSecrets({
|
|
1140
|
-
keys,
|
|
1141
|
-
projectId,
|
|
1142
|
-
environment,
|
|
1143
|
-
siteUrl,
|
|
1144
|
-
clientId,
|
|
1145
|
-
clientSecret
|
|
1146
|
-
});
|
|
1402
|
+
function throwInfisicalHttpError(error, operation, signal) {
|
|
1403
|
+
if (signal.aborted) {
|
|
1404
|
+
throw signal.reason;
|
|
1405
|
+
}
|
|
1406
|
+
if (error instanceof SecretLoadError) {
|
|
1407
|
+
throw error;
|
|
1408
|
+
}
|
|
1409
|
+
const status = error instanceof HttpResponseError ? error.status : undefined;
|
|
1410
|
+
const guidance = operation === "selectOrganization" && (status === 401 || status === 403) ? " Run infisical login for the target organization and configured domain, then verify your access." : "";
|
|
1411
|
+
throw new SecretLoadError("HTTP", `Infisical HTTP ${operation} failed${status ? ` (status ${status})` : ""}.${guidance}`, { operation, status });
|
|
1147
1412
|
}
|
|
1148
1413
|
function createInfisicalApiClient(siteUrl) {
|
|
1149
1414
|
return createApiClient({
|
|
@@ -1155,12 +1420,26 @@ function createInfisicalApiClient(siteUrl) {
|
|
|
1155
1420
|
fetch: getFetch(),
|
|
1156
1421
|
retries: 1,
|
|
1157
1422
|
endpoints: {
|
|
1423
|
+
selectOrganization: {
|
|
1424
|
+
method: "POST",
|
|
1425
|
+
path: "/api/v3/auth/select-organization",
|
|
1426
|
+
reqHeadersSchema: z2.object({
|
|
1427
|
+
Authorization: z2.string(),
|
|
1428
|
+
"User-Agent": z2.string()
|
|
1429
|
+
}),
|
|
1430
|
+
reqBodySchema: z2.object({ organizationId: z2.string() }),
|
|
1431
|
+
resSchema: z2.object({
|
|
1432
|
+
token: z2.string().min(1),
|
|
1433
|
+
isMfaEnabled: z2.boolean().optional()
|
|
1434
|
+
}),
|
|
1435
|
+
reqBodyFormat: "json"
|
|
1436
|
+
},
|
|
1158
1437
|
login: {
|
|
1159
1438
|
method: "POST",
|
|
1160
1439
|
path: "/api/v1/auth/universal-auth/login",
|
|
1161
|
-
reqBodySchema:
|
|
1162
|
-
clientId:
|
|
1163
|
-
clientSecret:
|
|
1440
|
+
reqBodySchema: z2.object({
|
|
1441
|
+
clientId: z2.string(),
|
|
1442
|
+
clientSecret: z2.string()
|
|
1164
1443
|
}),
|
|
1165
1444
|
resSchema: infisicalAuthResponseSchema,
|
|
1166
1445
|
reqBodyFormat: "json"
|
|
@@ -1168,16 +1447,16 @@ function createInfisicalApiClient(siteUrl) {
|
|
|
1168
1447
|
listSecrets: {
|
|
1169
1448
|
method: "GET",
|
|
1170
1449
|
path: "/api/v4/secrets",
|
|
1171
|
-
reqHeadersSchema:
|
|
1172
|
-
Authorization:
|
|
1450
|
+
reqHeadersSchema: z2.object({
|
|
1451
|
+
Authorization: z2.string()
|
|
1173
1452
|
}),
|
|
1174
|
-
reqQuerySchema:
|
|
1175
|
-
projectId:
|
|
1176
|
-
environment:
|
|
1177
|
-
secretPath:
|
|
1178
|
-
viewSecretValue:
|
|
1179
|
-
expandSecretReferences:
|
|
1180
|
-
includeImports:
|
|
1453
|
+
reqQuerySchema: z2.object({
|
|
1454
|
+
projectId: z2.string(),
|
|
1455
|
+
environment: z2.string(),
|
|
1456
|
+
secretPath: z2.string(),
|
|
1457
|
+
viewSecretValue: z2.boolean(),
|
|
1458
|
+
expandSecretReferences: z2.boolean(),
|
|
1459
|
+
includeImports: z2.boolean()
|
|
1181
1460
|
}),
|
|
1182
1461
|
resSchema: infisicalSecretsResponseSchema
|
|
1183
1462
|
}
|
|
@@ -1185,21 +1464,26 @@ function createInfisicalApiClient(siteUrl) {
|
|
|
1185
1464
|
});
|
|
1186
1465
|
}
|
|
1187
1466
|
function getFetch() {
|
|
1188
|
-
|
|
1467
|
+
const fetchFn = globalThis.fetch ?? defaultFetch;
|
|
1468
|
+
return (input, init) => {
|
|
1469
|
+
init?.signal?.throwIfAborted();
|
|
1470
|
+
return fetchFn(input, init);
|
|
1471
|
+
};
|
|
1189
1472
|
}
|
|
1190
1473
|
|
|
1191
|
-
// src/secrets/
|
|
1474
|
+
// src/secrets/worker-loader.ts
|
|
1192
1475
|
function cloudflareWorkerEnvLoader(workerEnv) {
|
|
1193
|
-
|
|
1194
|
-
const out =
|
|
1476
|
+
const loader = async (ctx) => {
|
|
1477
|
+
const out = Object.create(null);
|
|
1195
1478
|
for (const key of ctx.keys) {
|
|
1196
|
-
const str = workerBindingToString(workerEnv[key]);
|
|
1479
|
+
const str = workerBindingToString(Object.hasOwn(workerEnv, key) ? workerEnv[key] : undefined);
|
|
1197
1480
|
if (str !== undefined) {
|
|
1198
1481
|
out[key] = str;
|
|
1199
1482
|
}
|
|
1200
1483
|
}
|
|
1201
1484
|
return out;
|
|
1202
1485
|
};
|
|
1486
|
+
return Object.assign(loader, { source: "Cloudflare Worker bindings" });
|
|
1203
1487
|
}
|
|
1204
1488
|
function workerBindingToString(value) {
|
|
1205
1489
|
if (value === undefined || value === null) {
|
|
@@ -1216,21 +1500,30 @@ function workerBindingToString(value) {
|
|
|
1216
1500
|
}
|
|
1217
1501
|
return String(value);
|
|
1218
1502
|
}
|
|
1503
|
+
|
|
1504
|
+
// src/secrets/loaders.ts
|
|
1219
1505
|
function infisicalLoader(config) {
|
|
1220
|
-
|
|
1506
|
+
validateInfisicalOrganizationId(config.organizationId);
|
|
1507
|
+
const loader = async (ctx) => fetchInfisicalSecrets({
|
|
1221
1508
|
keys: ctx.keys,
|
|
1222
1509
|
projectId: config.projectId,
|
|
1510
|
+
organizationId: config.organizationId,
|
|
1223
1511
|
environment: ctx.environment,
|
|
1224
1512
|
siteUrl: config.siteUrl ?? DEFAULT_INFISICAL_SITE_URL,
|
|
1225
1513
|
clientId: config.clientId,
|
|
1226
|
-
clientSecret: config.clientSecret
|
|
1514
|
+
clientSecret: config.clientSecret,
|
|
1515
|
+
secretPath: config.secretPath,
|
|
1516
|
+
timeoutMs: config.timeoutMs ?? ctx.timeoutMs,
|
|
1517
|
+
signal: ctx.signal
|
|
1227
1518
|
});
|
|
1519
|
+
return Object.assign(loader, { source: "Infisical HTTP" });
|
|
1228
1520
|
}
|
|
1229
1521
|
async function processEnvLoader(_ctx) {
|
|
1230
1522
|
return {};
|
|
1231
1523
|
}
|
|
1524
|
+
Object.assign(processEnvLoader, { source: "process.env" });
|
|
1232
1525
|
export {
|
|
1233
|
-
|
|
1526
|
+
cloudflareWorkerEnvLoader,
|
|
1234
1527
|
infisicalLoader,
|
|
1235
|
-
|
|
1528
|
+
processEnvLoader
|
|
1236
1529
|
};
|