updating-secrets 0.2.0 → 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.
@@ -1,5 +1,5 @@
1
- import { GetSecretValueCommandOutput, type GetSecretValueCommand } from '@aws-sdk/client-secrets-manager';
2
- import { ProcessedSecretDefinitions } from '../secrets-definition/define-secrets.js';
1
+ import { type GetSecretValueCommand, type GetSecretValueCommandOutput } from '@aws-sdk/client-secrets-manager';
2
+ import { type ProcessedSecretDefinitions } from '../secrets-definition/define-secrets.js';
3
3
  import { BaseSecretsAdapter } from './base.adapter.js';
4
4
  /**
5
5
  * Minimal subset of AWS's `SecretsManagerClient` from the
@@ -1,5 +1,5 @@
1
- import type { JsonCompatibleValue, MaybePromise } from '@augment-vir/common';
2
- import { ProcessedSecretDefinitions } from '../secrets-definition/define-secrets.js';
1
+ import { type JsonCompatibleValue, type MaybePromise } from '@augment-vir/common';
2
+ import { type ProcessedSecretDefinitions } from '../secrets-definition/define-secrets.js';
3
3
  /**
4
4
  * Raw secret values as returned by an adapter's `loadSecrets` method.
5
5
  *
@@ -0,0 +1,70 @@
1
+ import { type Values } from '@augment-vir/common';
2
+ import { type ListSecretsOptions, type Secret } from '@infisical/sdk';
3
+ import { type ProcessedSecretDefinitions } from '../secrets-definition/define-secrets.js';
4
+ import { BaseSecretsAdapter, type RawSecrets } from './base.adapter.js';
5
+ /**
6
+ * Intermediate type for processing secrets from Infisical. Used in {@link InfisicalAdapter} and
7
+ * helper functions.
8
+ *
9
+ * @category Internal
10
+ */
11
+ export type MappedInfisicalSecrets = {
12
+ [SecretKey in string]: string | MappedInfisicalSecrets | Error;
13
+ };
14
+ /**
15
+ * The necessary subset of the `InfisicalSDK` API that {@link InfisicalAdapter} requires.
16
+ *
17
+ * @category Internal
18
+ */
19
+ export type NeededInfisicalSdk = {
20
+ /** Get the Infisical secrets client. */
21
+ secrets(): {
22
+ /** List the Infisical secrets. */
23
+ listSecrets(options: ListSecretsOptions): Promise<{
24
+ secrets: NeededInfisicalSecret[];
25
+ }>;
26
+ };
27
+ };
28
+ /**
29
+ * The necessary subset of the Infisical `Secret` type that {@link InfisicalAdapter} requires.
30
+ *
31
+ * @category Internal
32
+ */
33
+ export type NeededInfisicalSecret = Pick<Secret, 'secretKey' | 'secretPath' | 'secretValue'>;
34
+ /**
35
+ * Loads secrets from Infisical. A `InfisicalSDK` instance must be provided. The `InfisicalSDK`
36
+ * instance must also be authorized _before_ passing it into this.
37
+ *
38
+ * @category Adapters
39
+ */
40
+ export declare class InfisicalAdapter extends BaseSecretsAdapter {
41
+ /**
42
+ * Make sure that you've already authenticated this client.
43
+ * (`client.auth().universalAuth.login()`)
44
+ */
45
+ protected readonly infisicalClient: Readonly<NeededInfisicalSdk>;
46
+ /** `'dev'`, `'staging'`, `'prod'`, etc. */
47
+ protected readonly infisicalEnvironment: string;
48
+ constructor(
49
+ /**
50
+ * Make sure that you've already authenticated this client.
51
+ * (`client.auth().universalAuth.login()`)
52
+ */
53
+ infisicalClient: Readonly<NeededInfisicalSdk>,
54
+ /** `'dev'`, `'staging'`, `'prod'`, etc. */
55
+ infisicalEnvironment: string);
56
+ /** Load secrets from the provided `InfisicalSDK`. */
57
+ loadSecrets(secrets: ProcessedSecretDefinitions): RawSecrets;
58
+ }
59
+ /**
60
+ * Get an Infisical secret value nested within an object.
61
+ *
62
+ * @category Internal
63
+ */
64
+ export declare function getNested(parent: MappedInfisicalSecrets, keys: string[]): Values<MappedInfisicalSecrets>;
65
+ /**
66
+ * Set an Infisical secret value nested within an object.
67
+ *
68
+ * @category Internal
69
+ */
70
+ export declare function setNested(parent: MappedInfisicalSecrets, keys: string[], value: string): void;
@@ -0,0 +1,168 @@
1
+ import { check } from '@augment-vir/assert';
2
+ import { ensureError, getOrSet, mapObjectValuesSync, parseWithJson5, removePrefix, removeSuffix, stringify, wrapInTry, } from '@augment-vir/common';
3
+ import { BaseSecretsAdapter } from './base.adapter.js';
4
+ /**
5
+ * Loads secrets from Infisical. A `InfisicalSDK` instance must be provided. The `InfisicalSDK`
6
+ * instance must also be authorized _before_ passing it into this.
7
+ *
8
+ * @category Adapters
9
+ */
10
+ export class InfisicalAdapter extends BaseSecretsAdapter {
11
+ infisicalClient;
12
+ infisicalEnvironment;
13
+ constructor(
14
+ /**
15
+ * Make sure that you've already authenticated this client.
16
+ * (`client.auth().universalAuth.login()`)
17
+ */
18
+ infisicalClient,
19
+ /** `'dev'`, `'staging'`, `'prod'`, etc. */
20
+ infisicalEnvironment) {
21
+ super('InfisicalAdapter');
22
+ this.infisicalClient = infisicalClient;
23
+ this.infisicalEnvironment = infisicalEnvironment;
24
+ }
25
+ /** Load secrets from the provided `InfisicalSDK`. */
26
+ loadSecrets(secrets) {
27
+ const secretsCache = {};
28
+ return mapObjectValuesSync(secrets, (secretName, secretDefinition) => {
29
+ const infisicalConfig = secretDefinition.adapterConfig.infisical;
30
+ if (!infisicalConfig) {
31
+ return new Error(`No Infisical adapter config (required for using InfisicalAdapter) defined for secret '${secretDefinition.secretName}'.`);
32
+ }
33
+ const projectSecretsPromise = getOrSet(secretsCache, infisicalConfig.projectId, () => {
34
+ try {
35
+ return (this.infisicalClient
36
+ .secrets()
37
+ .listSecrets({
38
+ recursive: true,
39
+ environment: this.infisicalEnvironment,
40
+ projectId: infisicalConfig.projectId,
41
+ viewSecretValue: true,
42
+ })
43
+ .then(({ secrets }) => {
44
+ return mapInfisicalSecrets(secrets);
45
+ })
46
+ /* node:coverage ignore next 3 */
47
+ .catch((error) => {
48
+ return ensureError(error);
49
+ }));
50
+ }
51
+ catch (error) {
52
+ return Promise.reject(ensureError(error));
53
+ }
54
+ });
55
+ return projectSecretsPromise
56
+ .then((projectSecrets) => {
57
+ /* node:coverage ignore next 3 */
58
+ if (projectSecrets instanceof Error) {
59
+ return projectSecrets;
60
+ }
61
+ const folderValue = infisicalConfig.folderPath === '/' || !infisicalConfig.folderPath
62
+ ? projectSecrets
63
+ : getNested(projectSecrets, removeSuffix({
64
+ value: removePrefix({
65
+ value: infisicalConfig.folderPath,
66
+ prefix: '/',
67
+ }),
68
+ suffix: '/',
69
+ }).split('/'));
70
+ /* node:coverage ignore next 3 */
71
+ if (check.isError(folderValue)) {
72
+ return folderValue;
73
+ }
74
+ if (infisicalConfig.keyInFolder) {
75
+ if (check.isString(folderValue)) {
76
+ throw new TypeError(`Cannot get keyInFolder of a non-folder.`);
77
+ }
78
+ else if (check.hasKey(folderValue, infisicalConfig.keyInFolder)) {
79
+ const value = folderValue[infisicalConfig.keyInFolder];
80
+ if (secretDefinition.shapeDefinition && check.isString(value)) {
81
+ return wrapInTry(() => parseWithJson5(value), {
82
+ fallbackValue: folderValue,
83
+ });
84
+ }
85
+ else {
86
+ return value;
87
+ }
88
+ }
89
+ else {
90
+ throw new Error(`Secret key not in folder '${infisicalConfig.folderPath}'`);
91
+ }
92
+ }
93
+ else {
94
+ return folderValue;
95
+ }
96
+ })
97
+ .catch((error) => {
98
+ return ensureError(error);
99
+ });
100
+ });
101
+ }
102
+ }
103
+ function mapInfisicalSecrets(secrets) {
104
+ const secretsMap = {};
105
+ secrets.forEach((secret) => {
106
+ if (!secret.secretPath || secret.secretPath === '/') {
107
+ secretsMap[secret.secretKey] = secret.secretValue;
108
+ }
109
+ else {
110
+ setNested(secretsMap, removeSuffix({
111
+ value: removePrefix({ value: secret.secretPath, prefix: '/' }),
112
+ suffix: '/',
113
+ })
114
+ .split('/')
115
+ .concat(secret.secretKey), secret.secretValue);
116
+ }
117
+ });
118
+ return secretsMap;
119
+ }
120
+ /**
121
+ * Get an Infisical secret value nested within an object.
122
+ *
123
+ * @category Internal
124
+ */
125
+ export function getNested(parent, keys) {
126
+ const nextKey = keys[0];
127
+ if (nextKey == undefined) {
128
+ throw new Error('Invalid key or ran out of keys.');
129
+ }
130
+ const nextParent = parent[nextKey];
131
+ if (!nextParent) {
132
+ throw new Error(`Nothing at key '${nextKey}'`);
133
+ }
134
+ else if (nextParent instanceof Error) {
135
+ throw nextParent;
136
+ }
137
+ if (keys.length > 1) {
138
+ if (check.isString(nextParent)) {
139
+ throw new TypeError(`Keys still remain but received string value: ${stringify({ keys })}`);
140
+ }
141
+ return getNested(nextParent, keys.slice(1));
142
+ }
143
+ else {
144
+ return nextParent;
145
+ }
146
+ }
147
+ /**
148
+ * Set an Infisical secret value nested within an object.
149
+ *
150
+ * @category Internal
151
+ */
152
+ export function setNested(parent, keys, value) {
153
+ const nextKey = keys[0];
154
+ if (nextKey == undefined) {
155
+ throw new Error('Invalid key or ran out of keys.');
156
+ }
157
+ if (keys.length === 1) {
158
+ parent[nextKey] = value;
159
+ return;
160
+ }
161
+ const nextParent = getOrSet(parent, nextKey, () => {
162
+ return {};
163
+ });
164
+ if (check.isString(nextParent) || check.isError(nextParent)) {
165
+ throw new TypeError(`Cannot set key '${nextKey}'; it's already set to a non-object.`);
166
+ }
167
+ return setNested(nextParent, keys.slice(1), value);
168
+ }
@@ -1,5 +1,5 @@
1
1
  import { type MaybePromise, type PartialWithUndefined } from '@augment-vir/common';
2
- import type { SecretDefinitions, SecretValues } from '../secrets-definition/define-secrets.js';
2
+ import { type SecretDefinitions, type SecretValues } from '../secrets-definition/define-secrets.js';
3
3
  import { BaseSecretsAdapter } from './base.adapter.js';
4
4
  /**
5
5
  * Options for {@link SecretsJsonFileAdapter}.
@@ -1,4 +1,4 @@
1
- import type { JsonCompatibleValue } from '@augment-vir/common';
1
+ import { type JsonCompatibleValue } from '@augment-vir/common';
2
2
  import { BaseSecretsAdapter } from './base.adapter.js';
3
3
  /**
4
4
  * This adapter is constructed with a static set of secrets and that static set of secrets is always
package/dist/index.d.ts CHANGED
@@ -1,10 +1,12 @@
1
1
  export * from './adapters/all-adapters.js';
2
2
  export * from './adapters/aws-secrets-manager.adapter.js';
3
3
  export * from './adapters/base.adapter.js';
4
+ export * from './adapters/infisical.adapter.js';
4
5
  export * from './adapters/secrets-json-file.adapter.js';
5
6
  export * from './adapters/static-secrets.adapter.js';
6
7
  export * from './public-mocks/mock-aws-secrets-manager.js';
7
8
  export * from './public-mocks/mock-fs.js';
9
+ export * from './public-mocks/mock-infisical-sdk.js';
8
10
  export * from './secret-load.error.js';
9
11
  export * from './secrets-definition/define-secrets.js';
10
12
  export * from './updating-secrets.js';
package/dist/index.js CHANGED
@@ -1,10 +1,12 @@
1
1
  export * from './adapters/all-adapters.js';
2
2
  export * from './adapters/aws-secrets-manager.adapter.js';
3
3
  export * from './adapters/base.adapter.js';
4
+ export * from './adapters/infisical.adapter.js';
4
5
  export * from './adapters/secrets-json-file.adapter.js';
5
6
  export * from './adapters/static-secrets.adapter.js';
6
7
  export * from './public-mocks/mock-aws-secrets-manager.js';
7
8
  export * from './public-mocks/mock-fs.js';
9
+ export * from './public-mocks/mock-infisical-sdk.js';
8
10
  export * from './secret-load.error.js';
9
11
  export * from './secrets-definition/define-secrets.js';
10
12
  export * from './updating-secrets.js';
@@ -1,6 +1,6 @@
1
- import type { MaybePromise } from '@augment-vir/common';
2
- import type { RequireExactlyOne } from 'type-fest';
3
- import { SecretsJsonFileAdapterOptions } from '../adapters/secrets-json-file.adapter.js';
1
+ import { type MaybePromise } from '@augment-vir/common';
2
+ import { type RequireExactlyOne } from 'type-fest';
3
+ import { type SecretsJsonFileAdapterOptions } from '../adapters/secrets-json-file.adapter.js';
4
4
  /**
5
5
  * Mock data for {@link createMockFs}. There are two possible options contained herein, but only one
6
6
  * may be used at a time.
@@ -0,0 +1,70 @@
1
+ import { type JsonCompatibleValue } from '@augment-vir/common';
2
+ import { type InfisicalSDK, type ListSecretsOptions, type Secret } from '@infisical/sdk';
3
+ import { type RequireExactlyOne } from 'type-fest';
4
+ /**
5
+ * Mock secrets setup for {@link MockAwsSecretsManagerClient}.
6
+ *
7
+ * @category Internal
8
+ */
9
+ export type MockInfisicalSecrets = {
10
+ projectId: string;
11
+ /** `'dev'`, `'staging'`, `'prod'`, etc. */
12
+ env: string;
13
+ secrets: {
14
+ [SecretKey in string]: {
15
+ folderPath?: string | undefined;
16
+ } & RequireExactlyOne<{
17
+ /**
18
+ * A value that will be JSON stringified for the `.SecretString` output of AWS Secrets
19
+ * Manager.
20
+ */
21
+ preJson: JsonCompatibleValue;
22
+ /** Set the raw `.SecretString` output of AWS Secrets Manager directly. */
23
+ rawString: string;
24
+ }>;
25
+ };
26
+ }[];
27
+ /**
28
+ * A mock implementation of `InfisicalSDK` from the
29
+ * [@infisical/sdk](https://www.npmjs.com/package/@infisical/sdk) package. This only mocks what is
30
+ * necessary for the infisical adapter to work.
31
+ *
32
+ * @category Mocks
33
+ */
34
+ export declare class MockInfisicalSdk {
35
+ /** Mock secrets that will be used in `secrets().listSecrets()` */
36
+ readonly mockSecrets: Readonly<MockInfisicalSecrets>;
37
+ /** Keeps track of whether this SDK has been authorized or not. */
38
+ protected isAuthorized: boolean;
39
+ constructor(
40
+ /** Mock secrets that will be used in `secrets().listSecrets()` */
41
+ mockSecrets: Readonly<MockInfisicalSecrets>);
42
+ /** Mock of `InfisicalSDK.auth()` */
43
+ auth(): {
44
+ /** Mock of `InfisicalSDK.auth().universalAuth` */
45
+ universalAuth: {
46
+ /** Mock of `InfisicalSDK.auth().universalAuth.login()` */
47
+ login: (options: import("@infisical/sdk").UniversalAuthLoginRequest) => Promise<InfisicalSDK>;
48
+ /** Mock of `InfisicalSDK.auth().universalAuth.renew()` */
49
+ renew(): never;
50
+ };
51
+ /** Mock of `InfisicalSDK.auth().accessToken` */
52
+ accessToken: (token: string) => InfisicalSDK;
53
+ /** Mock of `InfisicalSDK.auth().awsIamAuth` */
54
+ awsIamAuth: {
55
+ /** Mock of `InfisicalSDK.auth().awsIamAuth.login()` */
56
+ login: (options?: {
57
+ identityId?: string;
58
+ } | undefined) => Promise<InfisicalSDK>;
59
+ /** Mock of `InfisicalSDK.auth().awsIamAuth.renew()` */
60
+ renew(): never;
61
+ };
62
+ };
63
+ /** Mock of `InfisicalSDK.secrets()` */
64
+ secrets(): {
65
+ /** Mock of `InfisicalSDK.secrets().listSecrets()` */
66
+ listSecrets: ({ projectId, environment }: ListSecretsOptions) => Promise<{
67
+ secrets: Partial<Secret>[];
68
+ }>;
69
+ };
70
+ }
@@ -0,0 +1,84 @@
1
+ import { getObjectTypedEntries, stringifyWithJson5, } from '@augment-vir/common';
2
+ /**
3
+ * A mock implementation of `InfisicalSDK` from the
4
+ * [@infisical/sdk](https://www.npmjs.com/package/@infisical/sdk) package. This only mocks what is
5
+ * necessary for the infisical adapter to work.
6
+ *
7
+ * @category Mocks
8
+ */
9
+ export class MockInfisicalSdk {
10
+ mockSecrets;
11
+ /** Keeps track of whether this SDK has been authorized or not. */
12
+ isAuthorized = false;
13
+ constructor(
14
+ /** Mock secrets that will be used in `secrets().listSecrets()` */
15
+ mockSecrets) {
16
+ this.mockSecrets = mockSecrets;
17
+ }
18
+ /** Mock of `InfisicalSDK.auth()` */
19
+ auth() {
20
+ return {
21
+ /** Mock of `InfisicalSDK.auth().universalAuth` */
22
+ universalAuth: {
23
+ /** Mock of `InfisicalSDK.auth().universalAuth.login()` */
24
+ login: (
25
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
26
+ ...params) => {
27
+ this.isAuthorized = true;
28
+ return Promise.resolve(this);
29
+ },
30
+ /** Mock of `InfisicalSDK.auth().universalAuth.renew()` */
31
+ renew() {
32
+ throw new Error('Not mocked.');
33
+ },
34
+ },
35
+ /** Mock of `InfisicalSDK.auth().accessToken` */
36
+ accessToken: (
37
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
38
+ ...params) => {
39
+ this.isAuthorized = true;
40
+ return this;
41
+ },
42
+ /** Mock of `InfisicalSDK.auth().awsIamAuth` */
43
+ awsIamAuth: {
44
+ /** Mock of `InfisicalSDK.auth().awsIamAuth.login()` */
45
+ login: (
46
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
47
+ ...params) => {
48
+ this.isAuthorized = true;
49
+ return Promise.resolve(this);
50
+ },
51
+ /** Mock of `InfisicalSDK.auth().awsIamAuth.renew()` */
52
+ renew() {
53
+ throw new Error('Not mocked.');
54
+ },
55
+ },
56
+ };
57
+ }
58
+ /** Mock of `InfisicalSDK.secrets()` */
59
+ secrets() {
60
+ return {
61
+ /** Mock of `InfisicalSDK.secrets().listSecrets()` */
62
+ listSecrets: ({ projectId, environment }) => {
63
+ if (!this.isAuthorized) {
64
+ throw new Error('Mock Infisical SDK client not authorized.');
65
+ }
66
+ const secrets = this.mockSecrets.find((mock) => mock.projectId === projectId && mock.env === environment)?.secrets;
67
+ if (!secrets) {
68
+ throw new Error('Invalid project.');
69
+ }
70
+ return Promise.resolve({
71
+ secrets: getObjectTypedEntries(secrets).map(([secretKey, mockDefinition,]) => {
72
+ return {
73
+ secretPath: mockDefinition.folderPath || '/',
74
+ secretKey,
75
+ secretValue: mockDefinition.preJson
76
+ ? stringifyWithJson5(mockDefinition.preJson)
77
+ : mockDefinition.rawString || '',
78
+ };
79
+ }),
80
+ });
81
+ },
82
+ };
83
+ }
84
+ }
@@ -1,6 +1,6 @@
1
1
  import { type PartialWithUndefined, type Values } from '@augment-vir/common';
2
2
  import { type ShapeDefinition } from 'object-shape-tester';
3
- import type { RequireExactlyOne } from 'type-fest';
3
+ import { type Exact, type RequireExactlyOne } from 'type-fest';
4
4
  /**
5
5
  * The shape definition for built-in handling of secret rotation. Use this shape in a secret
6
6
  * definition's `shape` property (when using {@link defineSecrets}).
@@ -67,6 +67,22 @@ export type SecretDefinitions = {
67
67
  */
68
68
  whereToFind: string;
69
69
  adapterConfig?: PartialWithUndefined<{
70
+ infisical: {
71
+ projectId: string;
72
+ folderPath?: string;
73
+ } & RequireExactlyOne<{
74
+ /**
75
+ * The name of the secret key within the given folder path. Use this when this
76
+ * secret definition corresponds exactly to a single secret entry in Infisical.
77
+ */
78
+ keyInFolder: string;
79
+ /**
80
+ * Set this to `true` to use the entire folder's contents as this secret's value.
81
+ * The folder will be loaded recursively, meaning all folders within this folder
82
+ * will also be loaded.
83
+ */
84
+ useWholeFolder: true;
85
+ }>;
70
86
  /**
71
87
  * Configuration for loading this secret from AWS. This is required if you're using the
72
88
  * AWS SecretsManager adapter, otherwise the secret will fail to load.
@@ -114,7 +130,9 @@ export type SecretDefinitions = {
114
130
  *
115
131
  * @category Define Secrets
116
132
  */
117
- export declare function defineSecrets<const Secrets extends SecretDefinitions>(secrets: Secrets): Secrets;
133
+ export declare function defineSecrets<const Secrets extends {
134
+ [Key in keyof Secrets]: Exact<Values<SecretDefinitions>, Secrets[Key]>;
135
+ } & SecretDefinitions>(secrets: Secrets): Secrets;
118
136
  /**
119
137
  * Processed secret definitions. This is what will be passed to all adapter `loadSecrets` methods.
120
138
  * This type is simply a more uniform and generic version of {@link SecretDefinitions}.
@@ -1,8 +1,7 @@
1
- import { Values, type PartialWithUndefined, type RequiredAndNotNull } from '@augment-vir/common';
1
+ import { type PartialWithUndefined, type RequiredAndNotNull, type Values } from '@augment-vir/common';
2
2
  import { type AnyDuration } from 'date-vir';
3
- import type { BaseSecretsAdapter } from './adapters/base.adapter.js';
4
- import type { SecretDefinitions } from './secrets-definition/define-secrets.js';
5
- import { ProcessedSecretDefinitions, RotatableSecretValue, SecretValues } from './secrets-definition/define-secrets.js';
3
+ import { type BaseSecretsAdapter } from './adapters/base.adapter.js';
4
+ import { type ProcessedSecretDefinitions, type RotatableSecretValue, type SecretDefinitions, type SecretValues } from './secrets-definition/define-secrets.js';
6
5
  /**
7
6
  * Options for {@link UpdatingSecrets} and {@link createUpdatingSecrets}.
8
7
  *
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "updating-secrets",
3
- "version": "0.2.0",
3
+ "version": "0.3.1",
4
4
  "description": "Automatically update secrets on an interval with support for seamless secret rotation.",
5
5
  "keywords": [
6
6
  "secrets",
@@ -44,52 +44,54 @@
44
44
  "test:update": "npm run test update"
45
45
  },
46
46
  "dependencies": {
47
- "@augment-vir/assert": "^31.13.0",
48
- "@augment-vir/common": "^31.13.0",
47
+ "@augment-vir/assert": "^31.23.3",
48
+ "@augment-vir/common": "^31.23.3",
49
49
  "date-vir": "^7.3.1",
50
- "object-shape-tester": "^5.1.5",
51
- "type-fest": "^4.40.0"
50
+ "object-shape-tester": "^5.1.6",
51
+ "type-fest": "^4.41.0"
52
52
  },
53
53
  "devDependencies": {
54
- "@augment-vir/test": "^31.13.0",
55
- "@aws-sdk/client-secrets-manager": "^3.787.0",
54
+ "@augment-vir/test": "^31.23.3",
55
+ "@aws-sdk/client-secrets-manager": "^3.826.0",
56
56
  "@eslint/eslintrc": "^3.3.1",
57
- "@eslint/js": "^9.25.0",
58
- "@stylistic/eslint-plugin": "^4.2.0",
59
- "@stylistic/eslint-plugin-ts": "^4.2.0",
60
- "@types/node": "^22.14.1",
61
- "@typescript-eslint/eslint-plugin": "^8.30.1",
57
+ "@eslint/js": "^9.28.0",
58
+ "@infisical/sdk": "^4.0.2",
59
+ "@stylistic/eslint-plugin": "^4.4.1",
60
+ "@stylistic/eslint-plugin-ts": "^4.4.1",
61
+ "@types/node": "^22.15.30",
62
+ "@typescript-eslint/eslint-plugin": "^8.33.1",
62
63
  "c8": "^10.1.3",
63
- "cspell": "^8.19.1",
64
- "dependency-cruiser": "^16.10.1",
65
- "esbuild": "^0.25.2",
66
- "eslint": "^9.25.0",
67
- "eslint-config-prettier": "^10.1.2",
68
- "eslint-plugin-jsdoc": "^50.6.9",
64
+ "cspell": "^9.0.2",
65
+ "dependency-cruiser": "^16.10.2",
66
+ "esbuild": "^0.25.5",
67
+ "eslint": "^9.28.0",
68
+ "eslint-config-prettier": "^10.1.5",
69
+ "eslint-plugin-jsdoc": "^50.7.1",
69
70
  "eslint-plugin-monorepo-cop": "^1.0.2",
70
71
  "eslint-plugin-playwright": "^2.2.0",
71
- "eslint-plugin-prettier": "^5.2.6",
72
+ "eslint-plugin-prettier": "^5.4.1",
72
73
  "eslint-plugin-require-extensions": "^0.1.3",
73
74
  "eslint-plugin-sonarjs": "^3.0.2",
74
- "eslint-plugin-unicorn": "^58.0.0",
75
+ "eslint-plugin-unicorn": "^59.0.1",
75
76
  "istanbul-smart-text-reporter": "^1.1.5",
76
77
  "markdown-code-example-inserter": "^3.0.3",
77
- "npm-check-updates": "^17.1.18",
78
+ "npm-check-updates": "^18.0.1",
78
79
  "prettier": "~3.3.3",
79
80
  "prettier-plugin-interpolated-html-tags": "^2.0.1",
80
81
  "prettier-plugin-jsdoc": "^1.3.2",
81
82
  "prettier-plugin-multiline-arrays": "^4.0.3",
82
83
  "prettier-plugin-organize-imports": "^4.1.0",
83
- "prettier-plugin-packagejson": "^2.5.10",
84
+ "prettier-plugin-packagejson": "^2.5.15",
84
85
  "prettier-plugin-sort-json": "^4.1.1",
85
- "prettier-plugin-toml": "^2.0.4",
86
- "typedoc": "^0.28.2",
86
+ "prettier-plugin-toml": "^2.0.5",
87
+ "typedoc": "^0.28.5",
87
88
  "typescript": "^5.8.3",
88
- "typescript-eslint": "^8.30.1",
89
- "virmator": "^13.13.5"
89
+ "typescript-eslint": "^8.33.1",
90
+ "virmator": "^13.15.4"
90
91
  },
91
92
  "peerDependencies": {
92
- "@aws-sdk/client-secrets-manager": ">=3"
93
+ "@aws-sdk/client-secrets-manager": ">=3",
94
+ "@infisical/sdk": ">=4"
93
95
  },
94
96
  "engines": {
95
97
  "node": ">=22"