nestjs-infisical 1.0.3

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.
@@ -0,0 +1,2 @@
1
+ export * from './infisical.module';
2
+ export * from './infisical.types';
package/dist/index.js ADDED
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./infisical.module"), exports);
18
+ __exportStar(require("./infisical.types"), exports);
@@ -0,0 +1,8 @@
1
+ export declare function loadInfisicalSecrets(options: {
2
+ baseUrl: string;
3
+ token: string;
4
+ projectId: string;
5
+ environment: string;
6
+ override: boolean;
7
+ failFast: boolean;
8
+ }): Promise<void>;
@@ -0,0 +1,33 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.loadInfisicalSecrets = loadInfisicalSecrets;
7
+ const axios_1 = __importDefault(require("axios"));
8
+ const LOG_PREFIX = '[nestjs-infisical]';
9
+ async function loadInfisicalSecrets(options) {
10
+ try {
11
+ const response = await axios_1.default.get(`${options.baseUrl}/api/v3/secrets/raw`, {
12
+ headers: {
13
+ Authorization: `Bearer ${options.token}`,
14
+ },
15
+ params: {
16
+ projectId: options.projectId,
17
+ environment: options.environment,
18
+ },
19
+ });
20
+ const secrets = response.data?.secrets ?? {};
21
+ for (const [key, value] of Object.entries(secrets)) {
22
+ if (options.override || process.env[key] === undefined) {
23
+ process.env[key] = value;
24
+ }
25
+ }
26
+ }
27
+ catch (err) {
28
+ if (options.failFast) {
29
+ throw err;
30
+ }
31
+ console.warn(`${LOG_PREFIX} Failed to load secrets from Infisical. Continuing without secrets.`);
32
+ }
33
+ }
@@ -0,0 +1,6 @@
1
+ import { DynamicModule } from '@nestjs/common';
2
+ import { InfisicalModuleAsyncOptions, InfisicalModuleOptions } from './infisical.types';
3
+ export declare class InfisicalModule {
4
+ static forRoot(options?: InfisicalModuleOptions): DynamicModule;
5
+ static forRootAsync(options: InfisicalModuleAsyncOptions): DynamicModule;
6
+ }
@@ -0,0 +1,99 @@
1
+ "use strict";
2
+ var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) {
3
+ function accept(f) { if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); return f; }
4
+ var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value";
5
+ var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null;
6
+ var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {});
7
+ var _, done = false;
8
+ for (var i = decorators.length - 1; i >= 0; i--) {
9
+ var context = {};
10
+ for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p];
11
+ for (var p in contextIn.access) context.access[p] = contextIn.access[p];
12
+ context.addInitializer = function (f) { if (done) throw new TypeError("Cannot add initializers after decoration has completed"); extraInitializers.push(accept(f || null)); };
13
+ var result = (0, decorators[i])(kind === "accessor" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context);
14
+ if (kind === "accessor") {
15
+ if (result === void 0) continue;
16
+ if (result === null || typeof result !== "object") throw new TypeError("Object expected");
17
+ if (_ = accept(result.get)) descriptor.get = _;
18
+ if (_ = accept(result.set)) descriptor.set = _;
19
+ if (_ = accept(result.init)) initializers.unshift(_);
20
+ }
21
+ else if (_ = accept(result)) {
22
+ if (kind === "field") initializers.unshift(_);
23
+ else descriptor[key] = _;
24
+ }
25
+ }
26
+ if (target) Object.defineProperty(target, contextIn.name, descriptor);
27
+ done = true;
28
+ };
29
+ var __runInitializers = (this && this.__runInitializers) || function (thisArg, initializers, value) {
30
+ var useValue = arguments.length > 2;
31
+ for (var i = 0; i < initializers.length; i++) {
32
+ value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg);
33
+ }
34
+ return useValue ? value : void 0;
35
+ };
36
+ var __setFunctionName = (this && this.__setFunctionName) || function (f, name, prefix) {
37
+ if (typeof name === "symbol") name = name.description ? "[".concat(name.description, "]") : "";
38
+ return Object.defineProperty(f, "name", { configurable: true, value: prefix ? "".concat(prefix, " ", name) : name });
39
+ };
40
+ Object.defineProperty(exports, "__esModule", { value: true });
41
+ exports.InfisicalModule = void 0;
42
+ const common_1 = require("@nestjs/common");
43
+ const infisical_service_1 = require("./infisical.service");
44
+ let InfisicalModule = (() => {
45
+ let _classDecorators = [(0, common_1.Module)({})];
46
+ let _classDescriptor;
47
+ let _classExtraInitializers = [];
48
+ let _classThis;
49
+ var InfisicalModule = _classThis = class {
50
+ static forRoot(options = {}) {
51
+ const resolved = {
52
+ baseUrl: options.baseUrl ?? process.env.INFISICAL_BASE_URL,
53
+ token: options.token ?? process.env.INFISICAL_TOKEN,
54
+ projectId: options.projectId ?? process.env.INFISICAL_PROJECT_ID,
55
+ environment: options.environment ?? process.env.INFISICAL_ENVIRONMENT,
56
+ dotenv: options.dotenv,
57
+ override: options.override ?? true,
58
+ failFast: options.failFast ?? true,
59
+ };
60
+ return {
61
+ module: InfisicalModule,
62
+ providers: [
63
+ {
64
+ provide: 'INFISICAL_INIT',
65
+ useFactory: async () => {
66
+ await (0, infisical_service_1.initializeInfisical)(resolved);
67
+ },
68
+ },
69
+ ],
70
+ };
71
+ }
72
+ static forRootAsync(options) {
73
+ return {
74
+ module: InfisicalModule,
75
+ imports: options.imports,
76
+ providers: [
77
+ {
78
+ provide: 'INFISICAL_INIT',
79
+ inject: options.inject ?? [],
80
+ useFactory: async (...args) => {
81
+ const resolved = await options.useFactory(...args);
82
+ await (0, infisical_service_1.initializeInfisical)(resolved);
83
+ },
84
+ },
85
+ ],
86
+ };
87
+ }
88
+ };
89
+ __setFunctionName(_classThis, "InfisicalModule");
90
+ (() => {
91
+ const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(null) : void 0;
92
+ __esDecorate(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers);
93
+ InfisicalModule = _classThis = _classDescriptor.value;
94
+ if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
95
+ __runInitializers(_classThis, _classExtraInitializers);
96
+ })();
97
+ return InfisicalModule = _classThis;
98
+ })();
99
+ exports.InfisicalModule = InfisicalModule;
@@ -0,0 +1,2 @@
1
+ import { InfisicalModuleOptions } from './infisical.types';
2
+ export declare function initializeInfisical(options: InfisicalModuleOptions): Promise<void>;
@@ -0,0 +1,31 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.initializeInfisical = initializeInfisical;
7
+ const infisical_loader_1 = require("./infisical.loader");
8
+ const dotenv_1 = __importDefault(require("dotenv"));
9
+ const LOG_PREFIX = '[nestjs-infisical]';
10
+ async function initializeInfisical(options) {
11
+ const { dotenv: dotenvOptions, baseUrl, token, projectId, environment, override = true, failFast = true, } = options;
12
+ if (dotenvOptions !== false) {
13
+ dotenv_1.default.config(dotenvOptions);
14
+ }
15
+ const provided = [baseUrl, token, projectId, environment].filter(Boolean).length;
16
+ if (provided === 0) {
17
+ return;
18
+ }
19
+ if (provided !== 4) {
20
+ console.warn(`${LOG_PREFIX} Partial Infisical configuration detected. Secrets will not be loaded.`);
21
+ return;
22
+ }
23
+ await (0, infisical_loader_1.loadInfisicalSecrets)({
24
+ baseUrl: baseUrl,
25
+ token: token,
26
+ projectId: projectId,
27
+ environment: environment,
28
+ override,
29
+ failFast,
30
+ });
31
+ }
@@ -0,0 +1,15 @@
1
+ import { DotenvConfigOptions } from 'dotenv';
2
+ import { ModuleMetadata } from '@nestjs/common';
3
+ export interface InfisicalModuleOptions {
4
+ baseUrl?: string;
5
+ token?: string;
6
+ projectId?: string;
7
+ environment?: string;
8
+ dotenv?: DotenvConfigOptions | false;
9
+ override?: boolean;
10
+ failFast?: boolean;
11
+ }
12
+ export interface InfisicalModuleAsyncOptions extends Pick<ModuleMetadata, 'imports'> {
13
+ inject?: any[];
14
+ useFactory: (...args: any[]) => Promise<InfisicalModuleOptions> | InfisicalModuleOptions;
15
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
package/package.json ADDED
@@ -0,0 +1,32 @@
1
+ {
2
+ "name": "nestjs-infisical",
3
+ "version": "1.0.3",
4
+ "description": "CLI-free Infisical HTTP integration for NestJS",
5
+ "license": "MIT",
6
+ "main": "dist/index.js",
7
+ "types": "dist/index.d.ts",
8
+ "files": [
9
+ "dist"
10
+ ],
11
+ "scripts": {
12
+ "build": "tsc",
13
+ "prepublishOnly": "npm run build"
14
+ },
15
+ "dependencies": {
16
+ "axios": "^1.6.0",
17
+ "dotenv": "^16.4.0",
18
+ "typescript": "^5.9.3"
19
+ },
20
+ "peerDependencies": {
21
+ "@nestjs/common": "^9.0.0 || ^10.0.0"
22
+ },
23
+ "engines": {
24
+ "node": ">=18"
25
+ },
26
+ "publishConfig": {
27
+ "access": "public"
28
+ },
29
+ "devDependencies": {
30
+ "@types/node": "^25.0.3"
31
+ }
32
+ }
package/readme.md ADDED
@@ -0,0 +1,219 @@
1
+ # nestjs-infisical
2
+
3
+ nestjs-infisical is a **CLI-free**, **deterministic**, and **production-safe** Infisical integration for NestJS.
4
+
5
+ It loads secrets **once at application startup** using the **Infisical HTTP API only** and injects them into `process.env`, making it fully compatible with `@nestjs/config`.
6
+
7
+ This package is intentionally boring.
8
+
9
+ ---
10
+
11
+ ## Why This Package Exists
12
+
13
+ Most Infisical integrations rely on the Infisical CLI, background agents, or runtime polling.
14
+
15
+ This package exists to provide:
16
+
17
+ - No CLI dependency
18
+ - No background processes
19
+ - No runtime mutation
20
+ - Deterministic startup behavior
21
+ - Works in Docker, CI, and production
22
+ - Pure HTTP API usage
23
+
24
+ If you want secrets loaded **once at boot** and then forgotten, this is for you.
25
+
26
+ ---
27
+
28
+ ## What This Package Does
29
+
30
+ - Loads environment variables from `.env` using `dotenv` (optional)
31
+ - Fetches secrets from Infisical via HTTP
32
+ - Injects secrets into `process.env`
33
+ - Allows `@nestjs/config` to consume them normally
34
+ - Runs **only during application bootstrap**
35
+
36
+ ---
37
+
38
+ ## Load Order (IMPORTANT)
39
+
40
+ The load order is **strict and deterministic**:
41
+
42
+ ```text
43
+ dotenv (optional)
44
+
45
+ Infisical HTTP API
46
+
47
+ process.env
48
+
49
+ @nestjs/config
50
+ ```
51
+
52
+ This guarantees compatibility with `ConfigModule.forRoot()`.
53
+
54
+ ---
55
+
56
+ ## Installation
57
+
58
+ ```bash
59
+ npm install nestjs-infisical
60
+ ```
61
+
62
+ Node.js **>= 18** is required.
63
+
64
+ ---
65
+
66
+ ## Basic (Sync) Usage
67
+
68
+ ```ts
69
+ import { Module } from '@nestjs/common';
70
+ import { InfisicalModule } from 'nestjs-infisical';
71
+
72
+ @Module({
73
+ imports: [
74
+ InfisicalModule.forRoot({
75
+ baseUrl: 'https://app.infisical.com',
76
+ token: process.env.INFISICAL_TOKEN,
77
+ projectId: process.env.INFISICAL_PROJECT_ID,
78
+ environment: 'production',
79
+ }),
80
+ ],
81
+ })
82
+ export class AppModule {}
83
+ ```
84
+
85
+ Secrets will be injected into `process.env` before the application finishes bootstrapping.
86
+
87
+ ---
88
+
89
+ ## Async Usage (Recommended)
90
+
91
+ ```ts
92
+ import { Module } from '@nestjs/common';
93
+ import { ConfigModule, ConfigService } from '@nestjs/config';
94
+ import { InfisicalModule } from 'nestjs-infisical';
95
+
96
+ @Module({
97
+ imports: [
98
+ ConfigModule.forRoot(),
99
+ InfisicalModule.forRootAsync({
100
+ imports: [ConfigModule],
101
+ inject: [ConfigService],
102
+ useFactory: (config: ConfigService) => ({
103
+ baseUrl: config.get('INFISICAL_BASE_URL'),
104
+ token: config.get('INFISICAL_TOKEN'),
105
+ projectId: config.get('INFISICAL_PROJECT_ID'),
106
+ environment: config.get('INFISICAL_ENVIRONMENT'),
107
+ }),
108
+ }),
109
+ ],
110
+ })
111
+ export class AppModule {}
112
+ ```
113
+
114
+ ---
115
+
116
+ ## Dotenv Support
117
+
118
+ This package uses the **official `dotenv` package directly**.
119
+
120
+ ### Enable dotenv (default)
121
+
122
+ ```ts
123
+ InfisicalModule.forRoot({
124
+ dotenv: {
125
+ path: '.env.local',
126
+ },
127
+ });
128
+ ```
129
+
130
+ ### Disable dotenv
131
+
132
+ ```ts
133
+ InfisicalModule.forRoot({
134
+ dotenv: false,
135
+ });
136
+ ```
137
+
138
+ ---
139
+
140
+ ## Configuration Options
141
+
142
+ ```ts
143
+ interface InfisicalModuleOptions {
144
+ baseUrl?: string;
145
+ token?: string;
146
+ projectId?: string;
147
+ environment?: string;
148
+ dotenv?: DotenvConfigOptions | false;
149
+ override?: boolean; // default: true
150
+ failFast?: boolean; // default: true
151
+ }
152
+ ```
153
+
154
+ ### override
155
+
156
+ - `true` → Infisical secrets overwrite existing environment variables
157
+ - `false` → Existing environment variables are preserved
158
+
159
+ ### failFast
160
+
161
+ - `true` → Application startup fails if Infisical API fails
162
+ - `false` → Logs a warning and continues startup
163
+
164
+ ---
165
+
166
+ ## Edge Case Behavior
167
+
168
+ ### No Infisical Config Provided
169
+
170
+ Secrets are silently skipped. No logs, no errors.
171
+
172
+ ### Partial Infisical Config Provided
173
+
174
+ If only some Infisical values are provided:
175
+
176
+ ```text
177
+ [nestjs-infisical] Partial Infisical configuration detected. Secrets will not be loaded.
178
+ ```
179
+
180
+ Secrets are skipped intentionally.
181
+
182
+ ### Infisical API Failure
183
+
184
+ - `failFast: true` → Throws error and aborts startup
185
+ - `failFast: false` → Logs warning and continues
186
+
187
+ ---
188
+
189
+ ## Explicitly NOT Supported
190
+
191
+ This package does **not**:
192
+
193
+ - Use the Infisical CLI
194
+ - Add health checks
195
+ - Rotate secrets
196
+ - Poll or hot-reload secrets
197
+ - Cache secrets
198
+ - Add retries or backoff
199
+ - Add decorators
200
+ - Mutate NestJS internals
201
+ - Run after bootstrap
202
+
203
+ ---
204
+
205
+ ## Design Philosophy
206
+
207
+ - Startup-only
208
+ - Deterministic
209
+ - Boring
210
+ - Predictable
211
+ - `process.env` is the only contract
212
+
213
+ If you need dynamic secrets, rotation, or runtime behavior, use a different tool.
214
+
215
+ ---
216
+
217
+ ## License
218
+
219
+ MIT