@varlock/nextjs-integration 0.0.1 → 0.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.
package/README.md CHANGED
@@ -2,217 +2,16 @@
2
2
 
3
3
  This package helps you integrate [varlock](https://varlock.dev) into a [Next.js](https://nextjs.org) project.
4
4
 
5
- It is designed as a drop-in replacement for `@next/env`, which is the internal package that Next.js uses to load `.env` files.
5
+ It is designed as a drop-in replacement for [`@next/env`](https://www.npmjs.com/package/@next/env), which is the internal package that Next.js uses to load `.env` files, as well as a small plugin for your `next.config.*` file that enables additional security features.
6
6
 
7
- It also provides a plugin for your `next.config.*` file to enable additional security features, such as:
8
- - Redacting sensitive config values from logs
9
- - Preventing sensitive config values from being leaked – both at build time and runtime
7
+ Compared to the default `@next/env` behavior, this package provides:
10
8
 
9
+ - validation of your env vars against your `.env.schema`
10
+ - type-generation and type-safe env var access with built-in docs
11
+ - redaction of sensitive values from application logs
12
+ - leak detection and prevention, both at build and runtime
13
+ - more flexible multi-env handling - you can load env-specific files other than `.env.development`/`.env.production`
11
14
 
12
- ## Installation
13
-
14
- First install this module and `varlock` using your package manager of choice:
15
- > `npm install @varlock/nextjs-integration varlock` (or pnpm, yarn, etc)
16
-
17
- ### Step 1: Install `@next/env` override
18
-
19
- You must tell your package manager to override all resolution of `@next/env` with `@varlock/nextjs-integration`.
20
-
21
- The method for doing this depends on your package manager:
22
-
23
- **NPM**
24
- See [NPM overrides docs](https://docs.npmjs.com/cli/v9/configuring-npm/package-json#overrides)
25
-
26
- NPM lets you reference another installed dependency in overrides. For example: `"dep-to-override": "$other-installed-dep"`.
27
-
28
- _package.json_
29
- ```
30
- "dependencies": {
31
- // ...
32
- "@varlock/nextjs-integration": "^1.2.3"
33
- },
34
- "overrides": {
35
- "@next/env": "$@varlock/nextjs-integration"
36
- }
37
- ```
38
-
39
- **Yarn**
40
- See [yarn resolutions docs](https://yarnpkg.com/configuration/manifest#resolutions)
41
-
42
- _package.json_
43
- ```
44
- "resolutions": {
45
- "**/@next/env": "npm:@varlock/nextjs-integration@^1.2.3"
46
- }
47
- ```
48
-
49
- > ⚠️ If in a monorepo, this must be done in the monorepo root package.json file
50
-
51
- **pnpm**
52
- See [pnpm overrides docs](https://pnpm.io/settings#overrides)
53
-
54
- > ⚠️ This must be set in `pnpm-workspace.yaml`, regardless of whether you are using a monorepo or not
55
-
56
- _pnpm-workspace.yaml_
57
- ```
58
- overrides:
59
- "@next/env": "npm:@varlock/nextjs-integration@^1.2.3"
60
- ```
61
-
62
-
63
- ### Step 2: Enable `next.config.*` plugin
64
-
65
- While using _only_ the override will swap `.env` loading duties over to varlock, to get the full benefits, you must also add a config plugin in your `next.config.ts` (or `next.config.js`) file.
66
-
67
- Next.js does not have a proper plugin system, but we can add a small transformation function on top of your existing config, which will install the necessary adjustments.
68
-
69
- Here is an example of how to do this:
70
-
71
- ```ts
72
- import type { NextConfig } from "next";
73
- import { varlockNextConfigPlugin } from '@varlock/nextjs-integration/plugin';
74
-
75
- const nextConfig: NextConfig = {
76
- // your existing config...
77
- };
78
-
79
- export default varlockNextConfigPlugin()(nextConfig);
80
- ```
81
-
82
-
83
-
84
- ## Accessing env vars in your code
85
- While your resolved config will be re-injected as normal env vars and you can continue to use `process.env.SOMEVAR` as usual, we recommend using varlock's imported `ENV` object instead. For example:
86
-
87
- ```ts
88
- import { ENV } from 'varlock/env';
89
-
90
- console.log(process.env.SOMEVAR); // 🆗 still works
91
- console.log(ENV.SOMEVAR); // ✨ but this is recommended
92
- ```
93
-
94
- ### Type-safety
95
-
96
- To enable type-safety and IntelliSense for your env vars, you must enable the [`@generateTypes` root decorator](https://varlock.dev/reference/root-decorators/#generatetypes) in your `.env.schema`.
97
- > ⚠️ If you ran `npx varlock init`, this will likely already be enabled for you.
98
-
99
- ```env-spec
100
- # @generateTypes(lang='ts', path='env.d.ts')
101
- # ---
102
- # your config items...
103
- ```
104
-
105
- This will make types available both for `process.env` and for varlock's `ENV` object.
106
-
107
- ### Why use `ENV` instead of `process.env`?
108
- - Any non-string values (e.g., number, boolean) will actually be their coerced value, rather than a string
109
- - _All_ non-sensitive items will be replaced at build time, not just `NEXT_PUBLIC_` prefixed items
110
- - Better error messages when using invalid keys, or server-side keys that are not available on the client
111
- - Enables further DX improvements in the future, such as tighter control over which items are bundled at build time.
112
-
113
-
114
-
115
- ## Managing multiple environments (dev, preview, prod, etc)
116
-
117
- Varlock excels at managing multiple environments and can load multiple _environment-specific_ .env files (e.g., `.env.development`, `.env.preview`, `.env.production`, etc.).
118
-
119
- While `.env.schema`, `.env`, and `.env.local` will always be loaded, loading env-specific files is controlled by a notion of an _environment flag_.
120
-
121
- [Next.js .env handling](https://nextjs.org/docs/pages/guides/environment-variables#loading-environment-variables-with-nextenv) has the following behavior to set the env flag and control loading env-specific .env files:
122
- - use `test` if `NODE_ENV` is set to `test`
123
- - otherwise use `development` if running `next dev`
124
- - otherwise use `production`
125
-
126
- By default, this module will match that behaviour, but we recommend using the [`@envFlag` root decorator](https://varlock.dev/reference/root-decorators/#envflag) in your `.env.schema` to specify your own _custom environment flag_, such as `APP_ENV`.
127
-
128
- **⚠️ Without a custom env flag, you will not have the ability to use a non-production env file (e.g., `.env.preview`, `.env.staging`, etc) for your non-prod deployments.**
129
-
130
- How we set the value of our env flag will depend on your deployment platform.
131
-
132
- When running locally, or building and deploying your next app on a platform you control, you can set it explicitly, often passed in via `package.json` scripts. For example:
133
- ```json
134
- // package.json
135
- "scripts": {
136
- "build:preview": "APP_ENV=preview next build",
137
- "start:preview": "APP_ENV=preview next start",
138
- "build:prod": "APP_ENV=production next build",
139
- "start:prod": "APP_ENV=production next start",
140
- "test": "APP_ENV=test jest"
141
- }
142
- ```
143
-
144
- However on some cloud platforms (e.g., Vercel, Cloudflare, etc), you may not have control over a boot command, or even the ability to vary environment variables as you would like.
145
- Even if you do, it's not always ideal to have this configuration buried in a UI rather than your code.
146
-
147
- In these cases, we can set the value of `APP_ENV` (or whatever you name your env flag) using resolver functions to transform existing env vars that the platform's CI/CD pipeline provides (e.g., branch name, platform's notion of env, etc)
148
-
149
- The following examples show how you could do this, but note that you could segment your environments (and name them) however you like.
150
-
151
- ### Vercel
152
-
153
- In Vercel, you can set `APP_ENV` explicitly in their env vars UI. But to keep everything contained in your schema, you can use the injected `VERCEL_ENV`.
154
-
155
- ```env-spec
156
- # @envFlag=APP_ENV
157
- # ---
158
- # current environment type, injected by vercel during deployments
159
- # @type=enum(development, preview, production)
160
- # @docsUrl="https://vercel.com/docs/environment-variables/system-environment-variables#system-environment-variables"
161
- VERCEL_ENV=
162
- # Our env flag, used to toggle loading of env-specific files
163
- APP_ENV=fallback($VERCEL_ENV, development)
164
- ```
165
-
166
- If you need more specific environments based on branch names, you can use `VERCEL_GIT_COMMIT_REF` instead. See the Cloudflare example below for more details.
167
-
168
- ### Cloudflare Workers Build
169
-
170
- In Cloudflare Workers Builds, it is not possible to alter our build command for prod versus non-prod builds, and there is no concept of branch-specific env vars.
171
-
172
- We must rely on the current branch name, injected as `WORKERS_CI_BRANCH`, to determine what our env flag should be.
173
-
174
- We can use the following strategy to set our env flag:
175
- - `production` – if `WORKERS_CI_BRANCH` is set to `main`, this is a production deployment
176
- - `preview` – if `WORKERS_CI_BRANCH` is set to anything else, this is a preview deployment
177
- - `development` – if `WORKERS_CI_BRANCH` is not set, this means we are not within CI, so we must be doing local development
178
- - `test` – we can set this explicitly in our test command. For example, in our `package.json` scripts, we could use `"test": "APP_ENV=test jest"`.
179
-
180
- ```env-spec
181
- # @envFlag=APP_ENV
182
- # ---
183
- # current branch set by Cloudflare Workers Build
184
- # @docsUrl="https://developers.cloudflare.com/workers/ci-cd/builds/configuration/#environment-variables"
185
- WORKERS_CI_BRANCH=
186
- # Our env flag, used to toggle loading of env-specific files
187
- # @type=enum(development, preview, production, test)
188
- APP_ENV=remap($WORKERS_CI_BRANCH, production="main", preview=regex(.*), development=undefined)
189
- ```
190
-
191
- ## Managing Sensitive Config Values
192
-
193
- Next.js itself uses the [`NEXT_PUBLIC_` prefix](https://nextjs.org/docs/pages/guides/environment-variables#bundling-environment-variables-for-the-browser) to determine which env vars can be considered _public_ (i.e., not sensitive). These public vars will be bundled at build-time made available in the browser.
194
-
195
- Varlock controls the default sensitive behavior via the [`@defaultSensitive` root decorator](https://varlock.dev/reference/root-decorators/#defaultsensitive).
196
-
197
- If you want to continue using the prefix, you can use `# @defaultSensitive=inferFromPrefix('NEXT_PUBLIC_')` in your `.env.schema` file.
198
-
199
- ```env-spec
200
- # @defaultSensitive=inferFromPrefix('NEXT_PUBLIC_')
201
- # ---
202
- FOO= # sensitive
203
- NEXT_PUBLIC_FOO= # non-sensitive, due to prefix
204
- ```
205
-
206
- However, we recommend you set `@defaultSensitive` to `true` or `false` and then explicitly tag individual items using the [`@sensitive`](https://varlock.dev/reference/item-decorators/#sensitive) item decorator. For example:
207
-
208
- ```env-spec
209
- # @defaultSensitive=true
210
- # ---
211
- SECRET_FOO= # will be sensitive, due to default
212
- # @sensitive=false
213
- NON_SECRET_FOO=
214
- ```
215
-
216
- > ⚠️ NOTE - All non-sensitive items will be bundled at build-time via varlock's `ENV` object, while `process.env` replacements will only include `NEXT_PUBLIC_` prefixed items.
15
+ See [our docs site](https://varlock.dev/integrations/nextjs/) for complete installation and usage instructions.
217
16
 
218
17
 
@@ -195,8 +195,8 @@ function loadEnvConfig(dir, dev, log = console, forceReload = false, onReload) {
195
195
  varlockLoadedEnv = JSON.parse(varlockLoadedEnvBuf.toString());
196
196
  } catch (err) {
197
197
  const { status, stdout, stderr } = err;
198
- const stdoutStr = stdout?.toString();
199
- const stderrStr = stderr?.toString();
198
+ const stdoutStr = stdout?.toString() || "";
199
+ const stderrStr = stderr?.toString() || "";
200
200
  if (stderrStr.includes("command not found")) {
201
201
  console.error([
202
202
  "",
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/next-env-compat.ts"],"names":["initialEnv","path","fs","execSync","resetRedactionMap","patchGlobalConsole","initVarlockEnv"],"mappings":"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","file":"next-env-compat.js","sourcesContent":["/**\n * Drop-in replacement for @next/env that uses varlock instead of dotenv\n *\n * This must be the default export of the module, and it must stay compatible with @next/env\n */\n\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport { execSync, type spawnSync } from 'child_process';\nimport { type SerializedEnvGraph } from 'varlock';\nimport { initVarlockEnv, resetRedactionMap } from 'varlock/env';\nimport { patchGlobalConsole } from 'varlock/patch-console';\n\nexport type Env = { [key: string]: string | undefined };\nexport type LoadedEnvFiles = Array<{\n path: string\n contents: string\n env: Env\n}>;\n\n/** will store the original values of process.env */\nexport let initialEnv: Env | undefined;\n\nlet lastReloadAt: Date | undefined;\n\nlet varlockLoadedEnv: SerializedEnvGraph;\nlet combinedEnv: Env | undefined;\nlet parsedEnv: Env | undefined;\n// this is used by next just to display the list of .env files in a startup log\nlet loadedEnvFiles: LoadedEnvFiles = [];\nlet rootDir: string | undefined;\n\n// @next/env exports this info and currently it is only used to display\n// a list of filenames loaded, for example: `Environments: .env, .env.development`\nfunction getVarlockSourcesAsLoadedEnvFiles(): LoadedEnvFiles {\n const envFiles = varlockLoadedEnv.sources\n .filter((s) => s.enabled && s.label !== 'process.env')\n .map((s) => ({\n path: s.label,\n contents: '',\n env: {},\n }));\n if (envFiles.length) {\n // this adds an additional line, below the list of files\n envFiles.push({ path: '\\n ✨ loaded by varlock ✨', contents: '', env: {} });\n }\n return envFiles;\n}\n\nconst IS_WORKER = !!process.env.NEXT_PRIVATE_WORKER;\nfunction debug(...args: Array<any>) {\n if (!process.env.DEBUG_VARLOCK_NEXT_INTEGRATION) return;\n console.log(\n IS_WORKER ? 'worker -- ' : 'server -- ',\n ...args,\n );\n}\ndebug('✨ LOADED @next/env module!');\n\n\n// Next.js only watches .env, .env.local, .env.development, .env.development.local\n// but we want to trigger reloads when .env.schema changes\n// so we set up an extra watcher, and trigger no-op changes to one of those files\nlet extraWatcherEnabled = false;\nconst NEXT_WATCHED_ENV_FILES = ['.env', '.env.local', '.env.development', '.env.development.local'];\nfunction enableExtraFileWatchers() {\n if (extraWatcherEnabled || IS_WORKER) return;\n extraWatcherEnabled = true;\n\n if (!rootDir) throw new Error('expected rootDir to be set');\n const envSchemaPath = path.join(rootDir, '.env.schema');\n // its faster to update an existing file, so we check if the user has any\n // otherwise we can create and destroy\n let envFilePathToUpdate: string | null = null;\n for (const envFileName of NEXT_WATCHED_ENV_FILES) {\n const filePath = path.join(rootDir, envFileName);\n if (fs.existsSync(filePath)) {\n envFilePathToUpdate = filePath;\n break;\n }\n }\n let destroyFile = false;\n if (!envFilePathToUpdate) {\n envFilePathToUpdate ||= path.join(rootDir, '.env');\n destroyFile = true;\n }\n\n debug('set up extra file watchers', envFilePathToUpdate, destroyFile);\n\n fs.watchFile(envSchemaPath, { interval: 500 }, (curr, prev) => {\n if (destroyFile) {\n fs.writeFileSync(envFilePathToUpdate, '# trigger reload', 'utf-8');\n setTimeout(() => {\n fs.unlinkSync(envFilePathToUpdate);\n }, 500);\n } else {\n const currentContents = fs.readFileSync(envFilePathToUpdate, 'utf-8');\n fs.writeFileSync(envFilePathToUpdate, currentContents, 'utf-8');\n }\n });\n}\n\nfunction detectOpenNextCloudflareBuild() {\n try {\n // the above works if the build is happening within CI, but we may need to do this for local builds or other CI platforms\n // so we can try to detect if we are within an open-next build by looking at the process info\n\n // we will look at the process tree to try to determine if we are in a opennext build\n // process tree looks like:\n // - opennext-cloudflare build > npm run build > next build\n\n // get grandparent process id\n const pppid = parseInt(execSync(`ps -o ppid= -p ${process.ppid}`).toString().trim());\n // const processInfo = execSync('ps -p '+grandparentPid+' -o command');\n // output looks like\n // ---\n // COMMAND\n // node /.../node_modules/.bin/opennextjs-cloudflare build\n //\n // ---\n const commandName = execSync(`ps -p ${pppid} -o command`).toString().split('\\n')[1];\n if (commandName.endsWith('.bin/opennextjs-cloudflare build')) {\n return true;\n }\n } catch (err) {\n // do nothing\n }\n return false;\n}\n\nfunction writeResolvedEnvFile() {\n // things get complicated on platforms like vercel/cloudflare, they do some of their own magic to load env vars\n // our loader (this file) will run during the _build_ process, but not when the platform is handling server rendered requests\n // also opennext is needed to run outside of vercel, so that adds other changes\n // so we export an additional .env file which the platform itself will automatically load\n\n const dotEnvStrLines = [];\n for (const [itemKey, itemInfo] of Object.entries(varlockLoadedEnv.config)) {\n if (itemInfo.value !== undefined) dotEnvStrLines.push(`${itemKey}=${JSON.stringify(itemInfo.value)}`);\n }\n\n if (\n detectOpenNextCloudflareBuild()\n || process.env.VERCEL || process.env.WORKERS_CI || process.env._VARLOCK_EXPORT_RESOLVED_ENV_FILE\n ) {\n dotEnvStrLines.unshift(`\n# 🛑 DO NOT CHECK THIS FILE INTO VERSION CONTROL 🛑\n# This file was automatically generated by @varlock/nextjs-integration\n# It contains a _fully resolved env_ to pass to platforms (ex: vercel, cloudflare, etc)\n# that are doing their own magic when booting up nextjs in certain scenarios\n#\n# It likely contains sensitive config data and should be deleted after use\n#\n# @disable # tells varlock to ignore this file\n# ---\n `);\n // this is the fully resolved env, which includes additional metadata about each item\n // our runtime code uses this to provide coerced values, redact sensitive values, etc\n dotEnvStrLines.push(`__VARLOCK_ENV=${JSON.stringify(varlockLoadedEnv)}`);\n\n let resolvedEnvFileName = '.env.production.local';\n if (process.env._VARLOCK_EXPORT_RESOLVED_ENV_FILE && !(['true', '1'].includes(process.env._VARLOCK_EXPORT_RESOLVED_ENV_FILE))) {\n resolvedEnvFileName = process.env._VARLOCK_EXPORT_RESOLVED_ENV_FILE;\n }\n if (!rootDir) throw new Error('expected rootDir to be set');\n fs.writeFileSync(path.resolve(rootDir, resolvedEnvFileName), dotEnvStrLines.join('\\n'), 'utf-8');\n }\n}\n\n// - these methods are the same as the original module -----------------\n\nexport function updateInitialEnv(newEnv: Env) {\n if (Object.keys(newEnv).length) {\n debug('updateInitialEnv', newEnv);\n Object.assign(initialEnv || {}, newEnv);\n }\n}\n\ntype Log = {\n info: (...args: Array<any>) => void\n error: (...args: Array<any>) => void\n};\n\nfunction replaceProcessEnv(sourceEnv: Env) {\n Object.keys(process.env).forEach((key) => {\n // Allow mutating internal Next.js env variables after the server has initiated.\n // This is necessary for dynamic things like the IPC server port.\n if (!key.startsWith('__NEXT_PRIVATE')) {\n if (sourceEnv[key] === undefined || sourceEnv[key] === '') {\n delete process.env[key];\n }\n }\n });\n\n Object.entries(sourceEnv).forEach(([key, value]) => {\n process.env[key] = value;\n });\n}\n\n// in original module, but does not appear to be used\nexport function processEnv(\n _loadedEnvFiles: LoadedEnvFiles,\n _dir?: string,\n _log: Log = console,\n _forceReload = false,\n _onReload?: (envFilePath: string) => void,\n) {\n return [process.env];\n}\n\nexport function resetEnv() {\n if (initialEnv) {\n replaceProcessEnv(initialEnv);\n }\n}\n\nexport function loadEnvConfig(\n dir: string,\n dev?: boolean,\n log: Log = console,\n forceReload = false,\n onReload?: (envFilePath: string) => void,\n): {\n combinedEnv: Env\n parsedEnv: Env | undefined\n loadedEnvFiles: LoadedEnvFiles\n } {\n if (!initialEnv) {\n initialEnv ||= { ...process.env };\n }\n debug('loadEnvConfig!', 'forceReload = ', forceReload);\n\n rootDir ||= dir;\n if (rootDir !== dir) throw new Error('root directory changed');\n\n if (dev) enableExtraFileWatchers();\n\n let useCachedEnv = !!process.env.__VARLOCK_ENV;\n if (forceReload) {\n if (!lastReloadAt) {\n lastReloadAt = new Date();\n } else if (lastReloadAt.getTime() < Date.now() - 1000) {\n lastReloadAt = new Date();\n useCachedEnv = false;\n }\n }\n\n if (useCachedEnv) {\n if (!varlockLoadedEnv) {\n varlockLoadedEnv = JSON.parse(process.env.__VARLOCK_ENV || '{}');\n parsedEnv = Object.fromEntries(\n Object.entries(varlockLoadedEnv.config).map(([key, value]) => [key, value.value]),\n );\n\n resetRedactionMap(varlockLoadedEnv);\n debug('patching console with varlock redactor');\n patchGlobalConsole();\n }\n\n combinedEnv = { ...initialEnv, ...parsedEnv };\n\n debug('>> USING CACHED ENV');\n\n return { combinedEnv, parsedEnv, loadedEnvFiles };\n }\n\n lastReloadAt = new Date();\n\n debug('>> RELOADING ENV');\n replaceProcessEnv(initialEnv);\n\n // we must match @next/env default behaviour for which .env.XXX files to load\n // which is based on the current command (`next dev` vs `next build`) and `NODE_ENV=test`\n // however we will pass it through and let the user ignore it by setting their own `@envFlag`\n let envFromNextCommand = dev ? 'development' : 'production';\n if (process.env.NODE_ENV === 'test') envFromNextCommand = 'test';\n debug('Inferred env mode (to match @next/env):', envFromNextCommand);\n\n try {\n const varlockLoadedEnvBuf = execSync(`varlock load --format json-full --env ${envFromNextCommand}`, {\n env: initialEnv as any,\n });\n varlockLoadedEnv = JSON.parse(varlockLoadedEnvBuf.toString());\n } catch (err) {\n const { status, stdout, stderr } = err as ReturnType<typeof spawnSync>;\n const stdoutStr = stdout?.toString();\n const stderrStr = stderr?.toString();\n if (stderrStr.includes('command not found')) {\n console.error([\n '',\n '❌ ERROR: varlock not found',\n 'varlock is a required peer dependency of @varlock/nextjs-integration',\n '',\n 'Please add varlock as a dependency to your project (e.g., `npm install varlock`)',\n ].join('\\n'));\n throw new Error('missing peer dependency - varlock');\n }\n if (stdoutStr) console.log(stdoutStr);\n if (stderrStr) console.error(stderrStr);\n\n // in a build, we want to fail and exit, while in dev we can keep retrying when changes are detected\n if (!dev) process.exit(1);\n\n return { combinedEnv: {}, parsedEnv: {}, loadedEnvFiles: [] };\n }\n\n parsedEnv = {};\n for (const [itemKey, itemInfo] of Object.entries(varlockLoadedEnv.config)) {\n parsedEnv[itemKey] = itemInfo.value;\n }\n debug('LOADED ENV:', parsedEnv);\n process.env.__VARLOCK_ENV = JSON.stringify(varlockLoadedEnv);\n initVarlockEnv(); // calling this will set process.env vars\n\n resetRedactionMap(varlockLoadedEnv);\n debug('patching console with varlock redactor');\n patchGlobalConsole();\n\n combinedEnv = { ...initialEnv, ...parsedEnv };\n loadedEnvFiles = getVarlockSourcesAsLoadedEnvFiles();\n\n // if not a dev build, we may need to write a temp resolved .env file\n if (!dev) writeResolvedEnvFile();\n\n return { combinedEnv, parsedEnv, loadedEnvFiles };\n}\n"]}
1
+ {"version":3,"sources":["../src/next-env-compat.ts"],"names":["initialEnv","path","fs","execSync","resetRedactionMap","patchGlobalConsole","initVarlockEnv"],"mappings":"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","file":"next-env-compat.js","sourcesContent":["/**\n * Drop-in replacement for @next/env that uses varlock instead of dotenv\n *\n * This must be the default export of the module, and it must stay compatible with @next/env\n */\n\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport { execSync, type spawnSync } from 'child_process';\nimport { type SerializedEnvGraph } from 'varlock';\nimport { initVarlockEnv, resetRedactionMap } from 'varlock/env';\nimport { patchGlobalConsole } from 'varlock/patch-console';\n\nexport type Env = { [key: string]: string | undefined };\nexport type LoadedEnvFiles = Array<{\n path: string\n contents: string\n env: Env\n}>;\n\n/** will store the original values of process.env */\nexport let initialEnv: Env | undefined;\n\nlet lastReloadAt: Date | undefined;\n\nlet varlockLoadedEnv: SerializedEnvGraph;\nlet combinedEnv: Env | undefined;\nlet parsedEnv: Env | undefined;\n// this is used by next just to display the list of .env files in a startup log\nlet loadedEnvFiles: LoadedEnvFiles = [];\nlet rootDir: string | undefined;\n\n// @next/env exports this info and currently it is only used to display\n// a list of filenames loaded, for example: `Environments: .env, .env.development`\nfunction getVarlockSourcesAsLoadedEnvFiles(): LoadedEnvFiles {\n const envFiles = varlockLoadedEnv.sources\n .filter((s) => s.enabled && s.label !== 'process.env')\n .map((s) => ({\n path: s.label,\n contents: '',\n env: {},\n }));\n if (envFiles.length) {\n // this adds an additional line, below the list of files\n envFiles.push({ path: '\\n ✨ loaded by varlock ✨', contents: '', env: {} });\n }\n return envFiles;\n}\n\nconst IS_WORKER = !!process.env.NEXT_PRIVATE_WORKER;\nfunction debug(...args: Array<any>) {\n if (!process.env.DEBUG_VARLOCK_NEXT_INTEGRATION) return;\n console.log(\n IS_WORKER ? 'worker -- ' : 'server -- ',\n ...args,\n );\n}\ndebug('✨ LOADED @next/env module!');\n\n\n// Next.js only watches .env, .env.local, .env.development, .env.development.local\n// but we want to trigger reloads when .env.schema changes\n// so we set up an extra watcher, and trigger no-op changes to one of those files\nlet extraWatcherEnabled = false;\nconst NEXT_WATCHED_ENV_FILES = ['.env', '.env.local', '.env.development', '.env.development.local'];\nfunction enableExtraFileWatchers() {\n if (extraWatcherEnabled || IS_WORKER) return;\n extraWatcherEnabled = true;\n\n if (!rootDir) throw new Error('expected rootDir to be set');\n const envSchemaPath = path.join(rootDir, '.env.schema');\n // its faster to update an existing file, so we check if the user has any\n // otherwise we can create and destroy\n let envFilePathToUpdate: string | null = null;\n for (const envFileName of NEXT_WATCHED_ENV_FILES) {\n const filePath = path.join(rootDir, envFileName);\n if (fs.existsSync(filePath)) {\n envFilePathToUpdate = filePath;\n break;\n }\n }\n let destroyFile = false;\n if (!envFilePathToUpdate) {\n envFilePathToUpdate ||= path.join(rootDir, '.env');\n destroyFile = true;\n }\n\n debug('set up extra file watchers', envFilePathToUpdate, destroyFile);\n\n fs.watchFile(envSchemaPath, { interval: 500 }, (curr, prev) => {\n if (destroyFile) {\n fs.writeFileSync(envFilePathToUpdate, '# trigger reload', 'utf-8');\n setTimeout(() => {\n fs.unlinkSync(envFilePathToUpdate);\n }, 500);\n } else {\n const currentContents = fs.readFileSync(envFilePathToUpdate, 'utf-8');\n fs.writeFileSync(envFilePathToUpdate, currentContents, 'utf-8');\n }\n });\n}\n\nfunction detectOpenNextCloudflareBuild() {\n try {\n // the above works if the build is happening within CI, but we may need to do this for local builds or other CI platforms\n // so we can try to detect if we are within an open-next build by looking at the process info\n\n // we will look at the process tree to try to determine if we are in a opennext build\n // process tree looks like:\n // - opennext-cloudflare build > npm run build > next build\n\n // get grandparent process id\n const pppid = parseInt(execSync(`ps -o ppid= -p ${process.ppid}`).toString().trim());\n // const processInfo = execSync('ps -p '+grandparentPid+' -o command');\n // output looks like\n // ---\n // COMMAND\n // node /.../node_modules/.bin/opennextjs-cloudflare build\n //\n // ---\n const commandName = execSync(`ps -p ${pppid} -o command`).toString().split('\\n')[1];\n if (commandName.endsWith('.bin/opennextjs-cloudflare build')) {\n return true;\n }\n } catch (err) {\n // do nothing\n }\n return false;\n}\n\nfunction writeResolvedEnvFile() {\n // things get complicated on platforms like vercel/cloudflare, they do some of their own magic to load env vars\n // our loader (this file) will run during the _build_ process, but not when the platform is handling server rendered requests\n // also opennext is needed to run outside of vercel, so that adds other changes\n // so we export an additional .env file which the platform itself will automatically load\n\n const dotEnvStrLines = [];\n for (const [itemKey, itemInfo] of Object.entries(varlockLoadedEnv.config)) {\n if (itemInfo.value !== undefined) dotEnvStrLines.push(`${itemKey}=${JSON.stringify(itemInfo.value)}`);\n }\n\n if (\n detectOpenNextCloudflareBuild()\n || process.env.VERCEL || process.env.WORKERS_CI || process.env._VARLOCK_EXPORT_RESOLVED_ENV_FILE\n ) {\n dotEnvStrLines.unshift(`\n# 🛑 DO NOT CHECK THIS FILE INTO VERSION CONTROL 🛑\n# This file was automatically generated by @varlock/nextjs-integration\n# It contains a _fully resolved env_ to pass to platforms (ex: vercel, cloudflare, etc)\n# that are doing their own magic when booting up nextjs in certain scenarios\n#\n# It likely contains sensitive config data and should be deleted after use\n#\n# @disable # tells varlock to ignore this file\n# ---\n `);\n // this is the fully resolved env, which includes additional metadata about each item\n // our runtime code uses this to provide coerced values, redact sensitive values, etc\n dotEnvStrLines.push(`__VARLOCK_ENV=${JSON.stringify(varlockLoadedEnv)}`);\n\n let resolvedEnvFileName = '.env.production.local';\n if (process.env._VARLOCK_EXPORT_RESOLVED_ENV_FILE && !(['true', '1'].includes(process.env._VARLOCK_EXPORT_RESOLVED_ENV_FILE))) {\n resolvedEnvFileName = process.env._VARLOCK_EXPORT_RESOLVED_ENV_FILE;\n }\n if (!rootDir) throw new Error('expected rootDir to be set');\n fs.writeFileSync(path.resolve(rootDir, resolvedEnvFileName), dotEnvStrLines.join('\\n'), 'utf-8');\n }\n}\n\n// - these methods are the same as the original module -----------------\n\nexport function updateInitialEnv(newEnv: Env) {\n if (Object.keys(newEnv).length) {\n debug('updateInitialEnv', newEnv);\n Object.assign(initialEnv || {}, newEnv);\n }\n}\n\ntype Log = {\n info: (...args: Array<any>) => void\n error: (...args: Array<any>) => void\n};\n\nfunction replaceProcessEnv(sourceEnv: Env) {\n Object.keys(process.env).forEach((key) => {\n // Allow mutating internal Next.js env variables after the server has initiated.\n // This is necessary for dynamic things like the IPC server port.\n if (!key.startsWith('__NEXT_PRIVATE')) {\n if (sourceEnv[key] === undefined || sourceEnv[key] === '') {\n delete process.env[key];\n }\n }\n });\n\n Object.entries(sourceEnv).forEach(([key, value]) => {\n process.env[key] = value;\n });\n}\n\n// in original module, but does not appear to be used\nexport function processEnv(\n _loadedEnvFiles: LoadedEnvFiles,\n _dir?: string,\n _log: Log = console,\n _forceReload = false,\n _onReload?: (envFilePath: string) => void,\n) {\n return [process.env];\n}\n\nexport function resetEnv() {\n if (initialEnv) {\n replaceProcessEnv(initialEnv);\n }\n}\n\nexport function loadEnvConfig(\n dir: string,\n dev?: boolean,\n log: Log = console,\n forceReload = false,\n onReload?: (envFilePath: string) => void,\n): {\n combinedEnv: Env\n parsedEnv: Env | undefined\n loadedEnvFiles: LoadedEnvFiles\n } {\n if (!initialEnv) {\n initialEnv ||= { ...process.env };\n }\n debug('loadEnvConfig!', 'forceReload = ', forceReload);\n\n rootDir ||= dir;\n if (rootDir !== dir) throw new Error('root directory changed');\n\n if (dev) enableExtraFileWatchers();\n\n let useCachedEnv = !!process.env.__VARLOCK_ENV;\n if (forceReload) {\n if (!lastReloadAt) {\n lastReloadAt = new Date();\n } else if (lastReloadAt.getTime() < Date.now() - 1000) {\n lastReloadAt = new Date();\n useCachedEnv = false;\n }\n }\n\n if (useCachedEnv) {\n if (!varlockLoadedEnv) {\n varlockLoadedEnv = JSON.parse(process.env.__VARLOCK_ENV || '{}');\n parsedEnv = Object.fromEntries(\n Object.entries(varlockLoadedEnv.config).map(([key, value]) => [key, value.value]),\n );\n\n resetRedactionMap(varlockLoadedEnv);\n debug('patching console with varlock redactor');\n patchGlobalConsole();\n }\n\n combinedEnv = { ...initialEnv, ...parsedEnv };\n\n debug('>> USING CACHED ENV');\n\n return { combinedEnv, parsedEnv, loadedEnvFiles };\n }\n\n lastReloadAt = new Date();\n\n debug('>> RELOADING ENV');\n replaceProcessEnv(initialEnv);\n\n // we must match @next/env default behaviour for which .env.XXX files to load\n // which is based on the current command (`next dev` vs `next build`) and `NODE_ENV=test`\n // however we will pass it through and let the user ignore it by setting their own `@envFlag`\n let envFromNextCommand = dev ? 'development' : 'production';\n if (process.env.NODE_ENV === 'test') envFromNextCommand = 'test';\n debug('Inferred env mode (to match @next/env):', envFromNextCommand);\n\n try {\n const varlockLoadedEnvBuf = execSync(`varlock load --format json-full --env ${envFromNextCommand}`, {\n env: initialEnv as any,\n });\n varlockLoadedEnv = JSON.parse(varlockLoadedEnvBuf.toString());\n } catch (err) {\n const { status, stdout, stderr } = err as ReturnType<typeof spawnSync>;\n const stdoutStr = stdout?.toString() || '';\n const stderrStr = stderr?.toString() || '';\n if (stderrStr.includes('command not found')) {\n console.error([\n '',\n '❌ ERROR: varlock not found',\n 'varlock is a required peer dependency of @varlock/nextjs-integration',\n '',\n 'Please add varlock as a dependency to your project (e.g., `npm install varlock`)',\n ].join('\\n'));\n throw new Error('missing peer dependency - varlock');\n }\n if (stdoutStr) console.log(stdoutStr);\n if (stderrStr) console.error(stderrStr);\n\n // in a build, we want to fail and exit, while in dev we can keep retrying when changes are detected\n if (!dev) process.exit(1);\n\n return { combinedEnv: {}, parsedEnv: {}, loadedEnvFiles: [] };\n }\n\n parsedEnv = {};\n for (const [itemKey, itemInfo] of Object.entries(varlockLoadedEnv.config)) {\n parsedEnv[itemKey] = itemInfo.value;\n }\n debug('LOADED ENV:', parsedEnv);\n process.env.__VARLOCK_ENV = JSON.stringify(varlockLoadedEnv);\n initVarlockEnv(); // calling this will set process.env vars\n\n resetRedactionMap(varlockLoadedEnv);\n debug('patching console with varlock redactor');\n patchGlobalConsole();\n\n combinedEnv = { ...initialEnv, ...parsedEnv };\n loadedEnvFiles = getVarlockSourcesAsLoadedEnvFiles();\n\n // if not a dev build, we may need to write a temp resolved .env file\n if (!dev) writeResolvedEnvFile();\n\n return { combinedEnv, parsedEnv, loadedEnvFiles };\n}\n"]}
package/dist/plugin.js CHANGED
@@ -64,6 +64,17 @@ function varlockNextConfigPlugin(pluginOptions) {
64
64
  } else {
65
65
  resolvedNextConfig = nextConfig;
66
66
  }
67
+ if (process.env.TURBOPACK || process.env.npm_config_turbopack) {
68
+ console.error([
69
+ "\u{1F6A8} @varlock/nextjs-integration: Turbopack is not yet supported for varlockNextConfigPlugin \u{1F6A8}",
70
+ "",
71
+ "You can either stop using the `--turbopack` flag",
72
+ "or remove this plugin from your config, and only use the @next/env override.",
73
+ "However if you don't use the plugin, you will not get all the benefits of this integration.",
74
+ ""
75
+ ].join("\n"));
76
+ throw new Error("varlockNextConfigPlugin: Turbopack is not yet supported");
77
+ }
67
78
  return {
68
79
  ...resolvedNextConfig,
69
80
  webpack(webpackConfig, options) {
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/plugin.ts"],"names":["patchGlobalConsole","fs","scanForLeaks","varlockSettings","patchGlobalServerResponse","redactSensitiveConfig","path"],"mappings":";;;;;;;;;;;;;;AAYA,IAAI,CAAC,OAAQ,CAAA,GAAA,CAAI,aAAe,EAAA;AAC9B,EAAA,OAAA,CAAQ,KAAM,CAAA;AAAA,IACZ,0DAAA;AAAA,IACA,EAAA;AAAA,IACA,gFAAA;AAAA,IACA,kEAAA;AAAA,IACA;AAAA,GACF,CAAE,IAAK,CAAA,IAAI,CAAC,CAAA;AACZ,EAAM,MAAA,IAAI,MAAM,oDAAoD,CAAA;AACtE;AAEAA,+BAAmB,EAAA;AAEnB,IAAM,SAAY,GAAA,CAAC,CAAC,OAAA,CAAQ,GAAI,CAAA,mBAAA;AAChC,SAAS,SAAS,IAAkB,EAAA;AAClC,EAAI,IAAA,CAAC,OAAQ,CAAA,GAAA,CAAI,8BAAgC,EAAA;AACjD,EAAQ,OAAA,CAAA,GAAA;AAAA,IACN,QAAA;AAAA,IACA,YAAY,WAAc,GAAA,UAAA;AAAA,IAC1B,IAAA;AAAA,IACA,GAAG;AAAA,GACL;AACF;AACA,KAAA,CAAM,wDAAmD,CAAA;AAEzD,IAAM,mBAAsB,GAAA,0BAAA;AAM5B,IAAI,kBAAqB,GAAA,KAAA;AACzB,eAAe,gBAAgB,WAAqB,EAAA;AAClD,EAAqB,kBAAA,GAAA,IAAA;AACrB,EAAA,WAAA,MAAiB,QAAQC,mBAAG,CAAA,QAAA,CAAS,KAAK,CAAG,EAAA,WAAW,YAAY,CAAG,EAAA;AACrE,IAAA,MAAM,eAAe,MAAMA,mBAAA,CAAG,QAAS,CAAA,QAAA,CAAS,MAAM,MAAM,CAAA;AAC5D,IAAAC,gBAAA,CAAa,YAAc,EAAA,EAAE,MAAQ,EAAA,+BAAA,EAAiC,MAAM,CAAA;AAAA;AAEhF;AAMA,SAAS,oBAAuB,GAAA;AAE9B,EAAM,MAAA,eAAA,GAAkBD,oBAAG,QAAS,CAAA,SAAA;AACpC,EAAAA,mBAAA,CAAG,QAAS,CAAA,SAAA,GAAY,eAAe,oBAAA,CAAA,GAAwB,IAAM,EAAA;AACnE,IAAA,MAAM,QAAW,GAAA,IAAA,CAAK,CAAC,CAAA,CAAE,QAAS,EAAA;AAIlC,IAAA,IAAI,QAAS,CAAA,QAAA,CAAS,gCAAgC,CAAA,IAAK,CAAC,kBAAoB,EAAA;AAC9E,MAAA,MAAM,cAAc,QAAS,CAAA,SAAA,CAAU,GAAG,QAAS,CAAA,WAAA,CAAY,GAAG,CAAC,CAAA;AACnE,MAAA,MAAM,gBAAgB,WAAW,CAAA;AAAA;AAcnC,IAAA,OAAO,eAAgB,CAAA,IAAA,CAAK,IAAM,EAAA,GAAG,IAAI,CAAA;AAAA,GAC3C;AACF;AAWO,SAAS,wBAAwB,aAAsC,EAAA;AAG5E,EAAA,OAAO,CAAC,UAA0E,KAAA;AAChF,IAAO,OAAA,OAAO,OAAe,QAA4C,KAAA;AACvE,MAAI,IAAA,kBAAA;AACJ,MAAI,IAAA,OAAO,eAAe,UAAY,EAAA;AACpC,QAAM,MAAA,kBAAA,GAAqB,UAAW,CAAA,KAAA,EAAO,QAAQ,CAAA;AACrD,QAAA,kBAAA,GAAqB,MAAM,kBAAA;AAAA,OACtB,MAAA;AACL,QAAqB,kBAAA,GAAA,UAAA;AAAA;AAGvB,MAAO,OAAA;AAAA,QACL,GAAG,kBAAA;AAAA,QACH,OAAA,CAAQ,eAAe,OAAS,EAAA;AAC9B,UAAA,MAAM,EAAE,QAAA,EAAU,GAAK,EAAA,WAAA,EAAgB,GAAA,OAAA;AAEvC,UAAA,IAAIE,oBAAgB,YAAc,EAAA;AAGhC,YAAqB,oBAAA,EAAA;AAGrB,YAA0BC,6CAAA,CAAA;AAAA;AAAA,cAExB,iBAAA,EAAmB,CAAC,4BAA4B,CAAA;AAAA;AAAA,cAEhD,oBAAsB,EAAA;AAAA,aACvB,CAAA;AAAA;AAIH,UAAA,MAAM,UAAU,OAAQ,CAAA,OAAA;AAGxB,UAAA,IAAI,mBAAmB,OAAS,EAAA;AAC9B,YAAgB,aAAA,GAAA,kBAAA,CAAmB,OAAQ,CAAA,aAAA,EAAe,OAAO,CAAA;AAAA;AAKnE,UAAA,MAAM,qBAAqB,EAAC;AAE5B,UAAA,IAAI,CAAC,OAAQ,CAAA,GAAA,CAAI,eAAqB,MAAA,IAAI,MAAM,oDAAoD,CAAA;AACpG,UAAA,MAAM,UAAa,GAAA,IAAA,CAAK,KAAM,CAAA,OAAA,CAAQ,IAAI,aAAa,CAAA;AACvD,UAAW,KAAA,MAAA,OAAA,IAAW,WAAW,MAAQ,EAAA;AACvC,YAAM,MAAA,IAAA,GAAO,UAAW,CAAA,MAAA,CAAO,OAAO,CAAA;AAEtC,YAAI,IAAA,CAAC,KAAK,WAAa,EAAA;AACrB,cAAA,kBAAA,CAAmB,OAAO,OAAO,CAAA,CAAE,IAAI,IAAK,CAAA,SAAA,CAAU,KAAK,KAAK,CAAA;AAAA;AAClE;AAGF,UAAA,KAAA,CAAM,+BAA+B,kBAAkB,CAAA;AACvD,UAAA,aAAA,CAAc,QAAQ,IAAK,CAAA,IAAI,OAAQ,CAAA,YAAA,CAAa,kBAAkB,CAAC,CAAA;AAEvE,UAAA,IAAID,oBAAgB,YAAc,EAAA;AAChC,YAAA,aAAA,CAAc,QAAQ,IAAK,CAAA;AAAA,cACzB,MAAM,QAAe,EAAA;AACnB,gBAAA,QAAA,CAAS,MAAM,YAAa,CAAA,GAAA,CAAI,mBAAqB,EAAA,CAAC,MAAW,YAAsB,KAAA;AACrF,kBAAM,MAAA,EAAE,OAAS,EAAA,UAAA,EAAe,GAAA,YAAA;AAChC,kBAAA,KAAA,CAAM,eAAe,UAAU,CAAA;AAE/B,kBAAA,IACE,UAAW,CAAA,QAAA,CAAS,uBAAuB,CAAA,IAExC,WAAW,QAAS,CAAA,OAAO,CAC3B,IAAA,UAAA,CAAW,SAAS,OAAO,CAAA,IAC3B,UAAW,CAAA,QAAA,CAAS,MAAM,CAC7B,EAAA;AAGA,oBAAI,IAAA;AACF,sBAAAD,gBAAA,CAAa,OAAS,EAAA;AAAA,wBACpB,MAAQ,EAAA,wDAAA;AAAA,wBACR,IAAM,EAAA;AAAA,uBACP,CAAA;AAAA,6BACM,GAAK,EAAA;AACZ,sBAAA,IAAI,GAAK,EAAA;AAEP,wBAAAD,mBAAA,CAAG,cAAc,UAAY,EAAAI,yBAAA,CAAsB,OAAQ,CAAA,QAAA,EAAU,CAAC,CAAA;AAAA,uBACjE,MAAA;AACL,wBAAM,MAAA,GAAA;AAAA;AACR;AACF;AACF,iBACD,CAAA;AAAA;AACH,aACD,CAAA;AAAA;AAYH,UAAS,SAAA,mCAAA,CAAoC,cAAc,KAAO,EAAA;AAChE,YAAA,OAAO,SAAU,UAAiB,EAAA;AAChC,cAAM,MAAA,aAAA,GAAgB,WAAW,MAAO,EAAA;AAIxC,cAAA,MAAM,YAAe,GAAAC,qBAAA,CAAK,OAAQ,CAAA,SAAA,EAAW,yBAAyB,CAAA;AACtE,cAAA,MAAM,WAAc,GAAAL,mBAAA,CAAG,YAAa,CAAA,YAAA,EAAc,MAAM,CAAA;AAGxD,cAAA,MAAM,gBAAmB,GAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,gBAUvB,WAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,gBAgBA;AAAA,eACF,CAAE,KAAK,IAAI,CAAA;AAEX,cAAA,OAAO,IAAI,OAAA,CAAQ,OAAQ,CAAA,SAAA,CAAU,gBAAgB,CAAA;AAAA,aACvD;AAAA;AAGF,UAAA,aAAA,CAAc,QAAQ,IAAK,CAAA;AAAA,YACzB,MAAM,QAAe,EAAA;AACnB,cAAA,QAAA,CAAS,KAAM,CAAA,eAAA,CAAgB,GAAI,CAAA,mBAAA,EAAqB,CAAC,WAAqB,KAAA;AAC5E,gBAAA,WAAA,CAAY,MAAM,aAAc,CAAA,GAAA;AAAA,kBAC9B;AAAA,oBACE,IAAM,EAAA,mBAAA;AAAA,oBACN,KAAA,EAAO,QAAQ,WAAY,CAAA;AAAA,mBAC7B;AAAA,kBACA,MAAM;AAEJ,oBAAI,IAAA,WAAA,CAAY,QAAS,CAAA,oBAAoB,CAAG,EAAA;AAC9C,sBAAY,WAAA,CAAA,WAAA,CAAY,oBAAsB,EAAA,mCAAA,EAAqC,CAAA;AAAA;AAErF,oBAAI,IAAA,WAAA,CAAY,QAAS,CAAA,uBAAuB,CAAG,EAAA;AACjD,sBAAY,WAAA,CAAA,WAAA,CAAY,uBAAyB,EAAA,mCAAA,EAAqC,CAAA;AAAA;AAExF,oBAAI,IAAA,WAAA,CAAY,QAAS,CAAA,wBAAwB,CAAG,EAAA;AAClD,sBAAY,WAAA,CAAA,WAAA,CAAY,wBAA0B,EAAA,mCAAA,EAAqC,CAAA;AAAA;AAEzF,oBAAI,IAAA,WAAA,CAAY,QAAS,CAAA,2BAA2B,CAAG,EAAA;AACrD,sBAAY,WAAA,CAAA,WAAA,CAAY,2BAA6B,EAAA,mCAAA,EAAqC,CAAA;AAAA;AAG5F,oBAAI,IAAA,WAAA,CAAY,QAAS,CAAA,yBAAyB,CAAG,EAAA;AACnD,sBAAA,WAAA,CAAY,WAAY,CAAA,yBAAA,EAA2B,mCAAoC,CAAA,IAAI,CAAC,CAAA;AAAA;AAC9F;AACF,iBACF;AAAA,eACD,CAAA;AAAA;AACH,WAED,CAAA;AAED,UAAO,OAAA,aAAA;AAAA;AACT,OACF;AAAA,KACF;AAAA,GACF;AACF","file":"plugin.js","sourcesContent":["import fs from 'node:fs';\nimport path from 'node:path';\nimport type { NextConfig } from 'next';\n\nimport { redactSensitiveConfig, scanForLeaks, varlockSettings } from 'varlock/env';\nimport { patchGlobalServerResponse } from 'varlock/patch-server-response';\nimport { patchGlobalConsole } from 'varlock/patch-console';\n\nimport { type SerializedEnvGraph } from 'varlock';\n\n// make sure varlock has acutally loaded the env files\n// NOTE - we dont need to call `initVarlockEnv` becuase the next-env-compat has already been loaded and called it\nif (!process.env.__VARLOCK_ENV) {\n console.error([\n '🚨 process.env.__VARLOCK_ENV is not set 🚨',\n '',\n 'To use this plugin, you must override @next/env with @varlock/next-integration',\n 'See https://varlock.dev/integrations/nextjs for more information',\n '',\n ].join('\\n'));\n throw new Error('VarlockNextWebpackPlugin: __VARLOCK_ENV is not set');\n}\n\npatchGlobalConsole();\n\nconst IS_WORKER = !!process.env.NEXT_PRIVATE_WORKER;\nfunction debug(...args: Array<any>) {\n if (!process.env.DEBUG_VARLOCK_NEXT_INTEGRATION) return;\n console.log(\n 'plugin',\n IS_WORKER ? '[worker] ' : '[server]',\n '--',\n ...args,\n );\n}\ndebug('✨ LOADED @varlock/next-integration/plugin module!');\n\nconst WEBPACK_PLUGIN_NAME = 'VarlockNextWebpackPlugin';\n\ntype VarlockPluginOptions = {\n // injectResolvedConfigAtBuildTime: boolean,\n};\n\nlet scannedStaticFiles = false;\nasync function scanStaticFiles(nextDirPath: string) {\n scannedStaticFiles = true;\n for await (const file of fs.promises.glob(`${nextDirPath}/**/*.html`)) {\n const fileContents = await fs.promises.readFile(file, 'utf8');\n scanForLeaks(fileContents, { method: 'nextjs scan static html files', file });\n }\n}\n\n// not all file writes go through this, at least in Next 15\n// (likely because webpack and prerendering are happening in workers)\n// but we can use this to monitor writing of certain files and give ourselves a \"hook\"\n// which we can then scan existing files\nfunction patchGlobalFsMethods() {\n // patch fs.promises.writeFile\n const origWriteFileFn = fs.promises.writeFile;\n fs.promises.writeFile = async function dmnoPatchedWriteFile(...args) {\n const filePath = args[0].toString();\n // const fileContents = args[1].toString();\n // console.log('⚡️ patched fs.promises.writeFile', filePath);\n\n if (filePath.endsWith('/.next/next-server.js.nft.json') && !scannedStaticFiles) {\n const nextDirPath = filePath.substring(0, filePath.lastIndexOf('/'));\n await scanStaticFiles(nextDirPath);\n }\n\n // // naively enable/disable detection based on file extension... probably not the best logic but it might be enough?\n // if (\n // filePath.endsWith('.html')\n // || filePath.endsWith('.rsc')\n // || filePath.endsWith('.body')\n // // we also need to scan .js files, but they are already built by webpack so we can't catch it here\n // ) {\n // // TODO: better error details to help user _find_ the problem\n // scanForLeaks(fileContents, { method: 'nextjs fs.writeFile', file: filePath });\n // }\n\n return origWriteFileFn.call(this, ...args);\n };\n}\n\n\n\nexport type NextConfigFunction = (\n phase: string,\n defaults: { defaultConfig: NextConfig },\n) => NextConfig | PromiseLike<NextConfig>;\n\n\n// we make this a plugin a function because we'll likely end up adding some options\nexport function varlockNextConfigPlugin(pluginOptions?: VarlockPluginOptions) {\n // nextjs doesnt have a proper plugin system :(\n // so we use a function which takes in a config object and returns an augmented one\n return (nextConfig: any | NextConfig | NextConfigFunction): NextConfigFunction => {\n return async (phase: string, defaults: { defaultConfig: NextConfig }) => {\n let resolvedNextConfig: NextConfig;\n if (typeof nextConfig === 'function') {\n const nextConfigFnResult = nextConfig(phase, defaults);\n resolvedNextConfig = await nextConfigFnResult;\n } else {\n resolvedNextConfig = nextConfig;\n }\n\n return {\n ...resolvedNextConfig,\n webpack(webpackConfig, options) {\n const { isServer, dev, nextRuntime } = options;\n\n if (varlockSettings.preventLeaks) {\n // we patch fs methods - ideally we would just path them to scan while files are written\n // but instead we use it to detect what phase the build is in, and then run our own scan on already built files\n patchGlobalFsMethods();\n\n // have to wait to run this until here when we know if this is dev mode or not\n patchGlobalServerResponse({\n // ignore sourcemaps - although we may in future want to scrub them?\n ignoreUrlPatterns: [/^\\/__nextjs_source-map\\?.*/],\n // in dev mode, we redact the secrets rather than throwing, because otherwise the dev server crashes\n redactInsteadOfThrow: dev,\n });\n }\n\n // webpack itself is passed in so we dont have to import it (or make it a dependency)\n const webpack = options.webpack;\n\n // apply existing user customizations if there are any\n if (resolvedNextConfig.webpack) {\n webpackConfig = resolvedNextConfig.webpack(webpackConfig, options);\n }\n\n\n // Set up build-time replacements / rewrites (using webpack.DefinePlugin)\n const staticReplacements = {} as Record<string, string>;\n // TODO: use shared helper function?\n if (!process.env.__VARLOCK_ENV) throw new Error('VarlockNextWebpackPlugin: __VARLOCK_ENV is not set');\n const varlockEnv = JSON.parse(process.env.__VARLOCK_ENV) as SerializedEnvGraph;\n for (const itemKey in varlockEnv.config) {\n const item = varlockEnv.config[itemKey];\n // TODO: probably want to reimplement static/dynamic logic, and allow sensitive+static / public+dynamic\n if (!item.isSensitive) {\n staticReplacements[`ENV.${itemKey}`] = JSON.stringify(item.value);\n }\n }\n\n debug('adding static replacements!', staticReplacements);\n webpackConfig.plugins.push(new webpack.DefinePlugin(staticReplacements));\n\n if (varlockSettings.preventLeaks) {\n webpackConfig.plugins.push({\n apply(compiler: any) {\n compiler.hooks.assetEmitted.tap(WEBPACK_PLUGIN_NAME, (file: any, assetDetails: any) => {\n const { content, targetPath } = assetDetails;\n debug('emit file: ', targetPath);\n\n if (\n targetPath.includes('/.next/static/chunks/')\n // Dont think these actually ever happen?\n || targetPath.endsWith('.html')\n || targetPath.endsWith('.body')\n || targetPath.endsWith('.rsc')\n ) {\n // NOTE - in dev mode the request hangs on the error, but the console error should help\n // and during a build, it will actually fail the build\n try {\n scanForLeaks(content, {\n method: '@varlock/nextjs-integration/plugin - assetEmitted hook',\n file: targetPath,\n });\n } catch (err) {\n if (dev) {\n // overwrite file with redacted version\n fs.writeFileSync(targetPath, redactSensitiveConfig(content.toString()));\n } else {\n throw err;\n }\n }\n }\n });\n },\n });\n }\n\n\n\n\n // we need to inject the dmno globals injector and call it\n // and in vercel/netlify etc where we can't run via `dmno run` we need to inject the resolved config into the build\n // not sure if this is the best way, but injecting into the `webpack-runtime.js` file seems to run everywhere\n\n // updates the webpack source to inject dmno global logic and call it\n // we run this on the runtimes for serverless and edge\n function injectVarlockInitIntoWebpackRuntime(edgeRuntime = false) {\n return function (origSource: any) {\n const origSourceStr = origSource.source();\n\n // we will inline the injector code, but need a different version if we are running in the edge runtime\n // const injectorSrc = getCjsModuleSource(`dmno/injector-standalone${edgeRuntime ? '/edge' : ''}`);\n const injectorPath = path.resolve(__dirname, './patch-next-runtime.js');\n const injectorSrc = fs.readFileSync(injectorPath, 'utf8');\n\n\n const updatedSourceStr = [\n // we use `headers()` to force next into dynamic rendering mode, but on the edge runtime it's always dynamic\n // (see below for where headers is used)\n // !edgeRuntime ? 'const { headers } = require(\"next/headers\");' : '',\n\n // // code built for edge runtime does not have `module.exports` or `exports` but we are inlining some already built common-js code\n // // so we just create them. It's not needed since it is inlined and we call the function right away\n // edgeRuntime ? 'const module = { exports: {} }; const exports = {}' : '',\n\n // inline the dmno injector code and then call it\n injectorSrc,\n\n // 'injectDmnoGlobals({',\n // injectResolvedConfigAtBuildTime ? `injectedConfig: ${JSON.stringify(injectedDmnoEnv)},` : '',\n\n // // attempts to force the route into dynamic rendering mode so it wont put our our dynamic value into a pre-rendered page\n // // however we have to wrap in try/catch because you can only call headers() within certain parts of the page... so it's not 100% foolproof\n // !edgeRuntime ? `\n // onItemAccess: async (item) => {\n // if (item.dynamic) {\n // try { headers(); }\n // catch (err) {}\n // }\n // },` : '',\n // '});',\n\n origSourceStr,\n ].join('\\n');\n\n return new webpack.sources.RawSource(updatedSourceStr);\n };\n }\n\n webpackConfig.plugins.push({\n apply(compiler: any) {\n compiler.hooks.thisCompilation.tap(WEBPACK_PLUGIN_NAME, (compilation: any) => {\n compilation.hooks.processAssets.tap(\n {\n name: WEBPACK_PLUGIN_NAME,\n stage: webpack.Compilation.PROCESS_ASSETS_STAGE_ADDITIONS,\n },\n () => {\n // not sure why, but these paths are different in build vs dev\n if (compilation.getAsset('webpack-runtime.js')) {\n compilation.updateAsset('webpack-runtime.js', injectVarlockInitIntoWebpackRuntime());\n }\n if (compilation.getAsset('../webpack-runtime.js')) {\n compilation.updateAsset('../webpack-runtime.js', injectVarlockInitIntoWebpackRuntime());\n }\n if (compilation.getAsset('webpack-api-runtime.js')) {\n compilation.updateAsset('webpack-api-runtime.js', injectVarlockInitIntoWebpackRuntime());\n }\n if (compilation.getAsset('../webpack-api-runtime.js')) {\n compilation.updateAsset('../webpack-api-runtime.js', injectVarlockInitIntoWebpackRuntime());\n }\n\n if (compilation.getAsset('edge-runtime-webpack.js')) {\n compilation.updateAsset('edge-runtime-webpack.js', injectVarlockInitIntoWebpackRuntime(true));\n }\n },\n );\n });\n },\n\n });\n\n return webpackConfig; // must return the modified config\n },\n };\n };\n };\n}\n"]}
1
+ {"version":3,"sources":["../src/plugin.ts"],"names":["patchGlobalConsole","fs","scanForLeaks","varlockSettings","patchGlobalServerResponse","redactSensitiveConfig","path"],"mappings":";;;;;;;;;;;;;;AAcA,IAAI,CAAC,OAAQ,CAAA,GAAA,CAAI,aAAe,EAAA;AAC9B,EAAA,OAAA,CAAQ,KAAM,CAAA;AAAA,IACZ,0DAAA;AAAA,IACA,EAAA;AAAA,IACA,gFAAA;AAAA,IACA,kEAAA;AAAA,IACA;AAAA,GACF,CAAE,IAAK,CAAA,IAAI,CAAC,CAAA;AACZ,EAAM,MAAA,IAAI,MAAM,oDAAoD,CAAA;AACtE;AAEAA,+BAAmB,EAAA;AAEnB,IAAM,SAAY,GAAA,CAAC,CAAC,OAAA,CAAQ,GAAI,CAAA,mBAAA;AAChC,SAAS,SAAS,IAAkB,EAAA;AAClC,EAAI,IAAA,CAAC,OAAQ,CAAA,GAAA,CAAI,8BAAgC,EAAA;AACjD,EAAQ,OAAA,CAAA,GAAA;AAAA,IACN,QAAA;AAAA,IACA,YAAY,WAAc,GAAA,UAAA;AAAA,IAC1B,IAAA;AAAA,IACA,GAAG;AAAA,GACL;AACF;AACA,KAAA,CAAM,wDAAmD,CAAA;AAEzD,IAAM,mBAAsB,GAAA,0BAAA;AAM5B,IAAI,kBAAqB,GAAA,KAAA;AACzB,eAAe,gBAAgB,WAAqB,EAAA;AAClD,EAAqB,kBAAA,GAAA,IAAA;AACrB,EAAA,WAAA,MAAiB,QAAQC,mBAAG,CAAA,QAAA,CAAS,KAAK,CAAG,EAAA,WAAW,YAAY,CAAG,EAAA;AACrE,IAAA,MAAM,eAAe,MAAMA,mBAAA,CAAG,QAAS,CAAA,QAAA,CAAS,MAAM,MAAM,CAAA;AAC5D,IAAAC,gBAAA,CAAa,YAAc,EAAA,EAAE,MAAQ,EAAA,+BAAA,EAAiC,MAAM,CAAA;AAAA;AAEhF;AAMA,SAAS,oBAAuB,GAAA;AAE9B,EAAM,MAAA,eAAA,GAAkBD,oBAAG,QAAS,CAAA,SAAA;AACpC,EAAAA,mBAAA,CAAG,QAAS,CAAA,SAAA,GAAY,eAAe,oBAAA,CAAA,GAAwB,IAAM,EAAA;AACnE,IAAA,MAAM,QAAW,GAAA,IAAA,CAAK,CAAC,CAAA,CAAE,QAAS,EAAA;AAIlC,IAAA,IAAI,QAAS,CAAA,QAAA,CAAS,gCAAgC,CAAA,IAAK,CAAC,kBAAoB,EAAA;AAC9E,MAAA,MAAM,cAAc,QAAS,CAAA,SAAA,CAAU,GAAG,QAAS,CAAA,WAAA,CAAY,GAAG,CAAC,CAAA;AACnE,MAAA,MAAM,gBAAgB,WAAW,CAAA;AAAA;AAcnC,IAAA,OAAO,eAAgB,CAAA,IAAA,CAAK,IAAM,EAAA,GAAG,IAAI,CAAA;AAAA,GAC3C;AACF;AAWO,SAAS,wBAAwB,aAAsC,EAAA;AAG5E,EAAA,OAAO,CAAC,UAA0E,KAAA;AAChF,IAAO,OAAA,OAAO,OAAe,QAA4C,KAAA;AACvE,MAAI,IAAA,kBAAA;AACJ,MAAI,IAAA,OAAO,eAAe,UAAY,EAAA;AACpC,QAAM,MAAA,kBAAA,GAAqB,UAAW,CAAA,KAAA,EAAO,QAAQ,CAAA;AACrD,QAAA,kBAAA,GAAqB,MAAM,kBAAA;AAAA,OACtB,MAAA;AACL,QAAqB,kBAAA,GAAA,UAAA;AAAA;AAGvB,MAAA,IAAI,OAAQ,CAAA,GAAA,CAAI,SAAa,IAAA,OAAA,CAAQ,IAAI,oBAAsB,EAAA;AAC7D,QAAA,OAAA,CAAQ,KAAM,CAAA;AAAA,UACZ,6GAAA;AAAA,UACA,EAAA;AAAA,UACA,kDAAA;AAAA,UACA,8EAAA;AAAA,UACA,6FAAA;AAAA,UACA;AAAA,SACF,CAAE,IAAK,CAAA,IAAI,CAAC,CAAA;AACZ,QAAM,MAAA,IAAI,MAAM,yDAAyD,CAAA;AAAA;AAG3E,MAAO,OAAA;AAAA,QACL,GAAG,kBAAA;AAAA,QACH,OAAA,CAAQ,eAAe,OAAS,EAAA;AAC9B,UAAA,MAAM,EAAE,QAAA,EAAU,GAAK,EAAA,WAAA,EAAgB,GAAA,OAAA;AAEvC,UAAA,IAAIE,oBAAgB,YAAc,EAAA;AAGhC,YAAqB,oBAAA,EAAA;AAGrB,YAA0BC,6CAAA,CAAA;AAAA;AAAA,cAExB,iBAAA,EAAmB,CAAC,4BAA4B,CAAA;AAAA;AAAA,cAEhD,oBAAsB,EAAA;AAAA,aACvB,CAAA;AAAA;AAIH,UAAA,MAAM,UAAU,OAAQ,CAAA,OAAA;AAGxB,UAAA,IAAI,mBAAmB,OAAS,EAAA;AAC9B,YAAgB,aAAA,GAAA,kBAAA,CAAmB,OAAQ,CAAA,aAAA,EAAe,OAAO,CAAA;AAAA;AAKnE,UAAA,MAAM,qBAAqB,EAAC;AAE5B,UAAA,IAAI,CAAC,OAAQ,CAAA,GAAA,CAAI,eAAqB,MAAA,IAAI,MAAM,oDAAoD,CAAA;AACpG,UAAA,MAAM,UAAa,GAAA,IAAA,CAAK,KAAM,CAAA,OAAA,CAAQ,IAAI,aAAa,CAAA;AACvD,UAAW,KAAA,MAAA,OAAA,IAAW,WAAW,MAAQ,EAAA;AACvC,YAAM,MAAA,IAAA,GAAO,UAAW,CAAA,MAAA,CAAO,OAAO,CAAA;AAEtC,YAAI,IAAA,CAAC,KAAK,WAAa,EAAA;AACrB,cAAA,kBAAA,CAAmB,OAAO,OAAO,CAAA,CAAE,IAAI,IAAK,CAAA,SAAA,CAAU,KAAK,KAAK,CAAA;AAAA;AAClE;AAGF,UAAA,KAAA,CAAM,+BAA+B,kBAAkB,CAAA;AACvD,UAAA,aAAA,CAAc,QAAQ,IAAK,CAAA,IAAI,OAAQ,CAAA,YAAA,CAAa,kBAAkB,CAAC,CAAA;AAEvE,UAAA,IAAID,oBAAgB,YAAc,EAAA;AAChC,YAAA,aAAA,CAAc,QAAQ,IAAK,CAAA;AAAA,cACzB,MAAM,QAAe,EAAA;AACnB,gBAAA,QAAA,CAAS,MAAM,YAAa,CAAA,GAAA,CAAI,mBAAqB,EAAA,CAAC,MAAW,YAAsB,KAAA;AACrF,kBAAM,MAAA,EAAE,OAAS,EAAA,UAAA,EAAe,GAAA,YAAA;AAChC,kBAAA,KAAA,CAAM,eAAe,UAAU,CAAA;AAE/B,kBAAA,IACE,UAAW,CAAA,QAAA,CAAS,uBAAuB,CAAA,IAExC,WAAW,QAAS,CAAA,OAAO,CAC3B,IAAA,UAAA,CAAW,SAAS,OAAO,CAAA,IAC3B,UAAW,CAAA,QAAA,CAAS,MAAM,CAC7B,EAAA;AAGA,oBAAI,IAAA;AACF,sBAAAD,gBAAA,CAAa,OAAS,EAAA;AAAA,wBACpB,MAAQ,EAAA,wDAAA;AAAA,wBACR,IAAM,EAAA;AAAA,uBACP,CAAA;AAAA,6BACM,GAAK,EAAA;AACZ,sBAAA,IAAI,GAAK,EAAA;AAEP,wBAAAD,mBAAA,CAAG,cAAc,UAAY,EAAAI,yBAAA,CAAsB,OAAQ,CAAA,QAAA,EAAU,CAAC,CAAA;AAAA,uBACjE,MAAA;AACL,wBAAM,MAAA,GAAA;AAAA;AACR;AACF;AACF,iBACD,CAAA;AAAA;AACH,aACD,CAAA;AAAA;AAYH,UAAS,SAAA,mCAAA,CAAoC,cAAc,KAAO,EAAA;AAChE,YAAA,OAAO,SAAU,UAAiB,EAAA;AAChC,cAAM,MAAA,aAAA,GAAgB,WAAW,MAAO,EAAA;AAIxC,cAAA,MAAM,YAAe,GAAAC,qBAAA,CAAK,OAAQ,CAAA,SAAA,EAAW,yBAAyB,CAAA;AACtE,cAAA,MAAM,WAAc,GAAAL,mBAAA,CAAG,YAAa,CAAA,YAAA,EAAc,MAAM,CAAA;AAGxD,cAAA,MAAM,gBAAmB,GAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,gBAUvB,WAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,gBAgBA;AAAA,eACF,CAAE,KAAK,IAAI,CAAA;AAEX,cAAA,OAAO,IAAI,OAAA,CAAQ,OAAQ,CAAA,SAAA,CAAU,gBAAgB,CAAA;AAAA,aACvD;AAAA;AAGF,UAAA,aAAA,CAAc,QAAQ,IAAK,CAAA;AAAA,YACzB,MAAM,QAAe,EAAA;AACnB,cAAA,QAAA,CAAS,KAAM,CAAA,eAAA,CAAgB,GAAI,CAAA,mBAAA,EAAqB,CAAC,WAAqB,KAAA;AAC5E,gBAAA,WAAA,CAAY,MAAM,aAAc,CAAA,GAAA;AAAA,kBAC9B;AAAA,oBACE,IAAM,EAAA,mBAAA;AAAA,oBACN,KAAA,EAAO,QAAQ,WAAY,CAAA;AAAA,mBAC7B;AAAA,kBACA,MAAM;AAEJ,oBAAI,IAAA,WAAA,CAAY,QAAS,CAAA,oBAAoB,CAAG,EAAA;AAC9C,sBAAY,WAAA,CAAA,WAAA,CAAY,oBAAsB,EAAA,mCAAA,EAAqC,CAAA;AAAA;AAErF,oBAAI,IAAA,WAAA,CAAY,QAAS,CAAA,uBAAuB,CAAG,EAAA;AACjD,sBAAY,WAAA,CAAA,WAAA,CAAY,uBAAyB,EAAA,mCAAA,EAAqC,CAAA;AAAA;AAExF,oBAAI,IAAA,WAAA,CAAY,QAAS,CAAA,wBAAwB,CAAG,EAAA;AAClD,sBAAY,WAAA,CAAA,WAAA,CAAY,wBAA0B,EAAA,mCAAA,EAAqC,CAAA;AAAA;AAEzF,oBAAI,IAAA,WAAA,CAAY,QAAS,CAAA,2BAA2B,CAAG,EAAA;AACrD,sBAAY,WAAA,CAAA,WAAA,CAAY,2BAA6B,EAAA,mCAAA,EAAqC,CAAA;AAAA;AAG5F,oBAAI,IAAA,WAAA,CAAY,QAAS,CAAA,yBAAyB,CAAG,EAAA;AACnD,sBAAA,WAAA,CAAY,WAAY,CAAA,yBAAA,EAA2B,mCAAoC,CAAA,IAAI,CAAC,CAAA;AAAA;AAC9F;AACF,iBACF;AAAA,eACD,CAAA;AAAA;AACH,WAED,CAAA;AAED,UAAO,OAAA,aAAA;AAAA;AACT,OACF;AAAA,KACF;AAAA,GACF;AACF","file":"plugin.js","sourcesContent":["/* eslint-disable no-console */\n\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport type { NextConfig } from 'next';\n\nimport { redactSensitiveConfig, scanForLeaks, varlockSettings } from 'varlock/env';\nimport { patchGlobalServerResponse } from 'varlock/patch-server-response';\nimport { patchGlobalConsole } from 'varlock/patch-console';\n\nimport { type SerializedEnvGraph } from 'varlock';\n\n// make sure varlock has acutally loaded the env files\n// NOTE - we dont need to call `initVarlockEnv` becuase the next-env-compat has already been loaded and called it\nif (!process.env.__VARLOCK_ENV) {\n console.error([\n '🚨 process.env.__VARLOCK_ENV is not set 🚨',\n '',\n 'To use this plugin, you must override @next/env with @varlock/next-integration',\n 'See https://varlock.dev/integrations/nextjs for more information',\n '',\n ].join('\\n'));\n throw new Error('VarlockNextWebpackPlugin: __VARLOCK_ENV is not set');\n}\n\npatchGlobalConsole();\n\nconst IS_WORKER = !!process.env.NEXT_PRIVATE_WORKER;\nfunction debug(...args: Array<any>) {\n if (!process.env.DEBUG_VARLOCK_NEXT_INTEGRATION) return;\n console.log(\n 'plugin',\n IS_WORKER ? '[worker] ' : '[server]',\n '--',\n ...args,\n );\n}\ndebug('✨ LOADED @varlock/next-integration/plugin module!');\n\nconst WEBPACK_PLUGIN_NAME = 'VarlockNextWebpackPlugin';\n\ntype VarlockPluginOptions = {\n // injectResolvedConfigAtBuildTime: boolean,\n};\n\nlet scannedStaticFiles = false;\nasync function scanStaticFiles(nextDirPath: string) {\n scannedStaticFiles = true;\n for await (const file of fs.promises.glob(`${nextDirPath}/**/*.html`)) {\n const fileContents = await fs.promises.readFile(file, 'utf8');\n scanForLeaks(fileContents, { method: 'nextjs scan static html files', file });\n }\n}\n\n// not all file writes go through this, at least in Next 15\n// (likely because webpack and prerendering are happening in workers)\n// but we can use this to monitor writing of certain files and give ourselves a \"hook\"\n// which we can then scan existing files\nfunction patchGlobalFsMethods() {\n // patch fs.promises.writeFile\n const origWriteFileFn = fs.promises.writeFile;\n fs.promises.writeFile = async function dmnoPatchedWriteFile(...args) {\n const filePath = args[0].toString();\n // const fileContents = args[1].toString();\n // console.log('⚡️ patched fs.promises.writeFile', filePath);\n\n if (filePath.endsWith('/.next/next-server.js.nft.json') && !scannedStaticFiles) {\n const nextDirPath = filePath.substring(0, filePath.lastIndexOf('/'));\n await scanStaticFiles(nextDirPath);\n }\n\n // // naively enable/disable detection based on file extension... probably not the best logic but it might be enough?\n // if (\n // filePath.endsWith('.html')\n // || filePath.endsWith('.rsc')\n // || filePath.endsWith('.body')\n // // we also need to scan .js files, but they are already built by webpack so we can't catch it here\n // ) {\n // // TODO: better error details to help user _find_ the problem\n // scanForLeaks(fileContents, { method: 'nextjs fs.writeFile', file: filePath });\n // }\n\n return origWriteFileFn.call(this, ...args);\n };\n}\n\n\n\nexport type NextConfigFunction = (\n phase: string,\n defaults: { defaultConfig: NextConfig },\n) => NextConfig | PromiseLike<NextConfig>;\n\n\n// we make this a plugin a function because we'll likely end up adding some options\nexport function varlockNextConfigPlugin(pluginOptions?: VarlockPluginOptions) {\n // nextjs doesnt have a proper plugin system :(\n // so we use a function which takes in a config object and returns an augmented one\n return (nextConfig: any | NextConfig | NextConfigFunction): NextConfigFunction => {\n return async (phase: string, defaults: { defaultConfig: NextConfig }) => {\n let resolvedNextConfig: NextConfig;\n if (typeof nextConfig === 'function') {\n const nextConfigFnResult = nextConfig(phase, defaults);\n resolvedNextConfig = await nextConfigFnResult;\n } else {\n resolvedNextConfig = nextConfig;\n }\n\n if (process.env.TURBOPACK || process.env.npm_config_turbopack) {\n console.error([\n '🚨 @varlock/nextjs-integration: Turbopack is not yet supported for varlockNextConfigPlugin 🚨',\n '',\n 'You can either stop using the `--turbopack` flag',\n 'or remove this plugin from your config, and only use the @next/env override.',\n \"However if you don't use the plugin, you will not get all the benefits of this integration.\",\n '',\n ].join('\\n'));\n throw new Error('varlockNextConfigPlugin: Turbopack is not yet supported');\n }\n\n return {\n ...resolvedNextConfig,\n webpack(webpackConfig, options) {\n const { isServer, dev, nextRuntime } = options;\n\n if (varlockSettings.preventLeaks) {\n // we patch fs methods - ideally we would just path them to scan while files are written\n // but instead we use it to detect what phase the build is in, and then run our own scan on already built files\n patchGlobalFsMethods();\n\n // have to wait to run this until here when we know if this is dev mode or not\n patchGlobalServerResponse({\n // ignore sourcemaps - although we may in future want to scrub them?\n ignoreUrlPatterns: [/^\\/__nextjs_source-map\\?.*/],\n // in dev mode, we redact the secrets rather than throwing, because otherwise the dev server crashes\n redactInsteadOfThrow: dev,\n });\n }\n\n // webpack itself is passed in so we dont have to import it (or make it a dependency)\n const webpack = options.webpack;\n\n // apply existing user customizations if there are any\n if (resolvedNextConfig.webpack) {\n webpackConfig = resolvedNextConfig.webpack(webpackConfig, options);\n }\n\n\n // Set up build-time replacements / rewrites (using webpack.DefinePlugin)\n const staticReplacements = {} as Record<string, string>;\n // TODO: use shared helper function?\n if (!process.env.__VARLOCK_ENV) throw new Error('VarlockNextWebpackPlugin: __VARLOCK_ENV is not set');\n const varlockEnv = JSON.parse(process.env.__VARLOCK_ENV) as SerializedEnvGraph;\n for (const itemKey in varlockEnv.config) {\n const item = varlockEnv.config[itemKey];\n // TODO: probably want to reimplement static/dynamic logic, and allow sensitive+static / public+dynamic\n if (!item.isSensitive) {\n staticReplacements[`ENV.${itemKey}`] = JSON.stringify(item.value);\n }\n }\n\n debug('adding static replacements!', staticReplacements);\n webpackConfig.plugins.push(new webpack.DefinePlugin(staticReplacements));\n\n if (varlockSettings.preventLeaks) {\n webpackConfig.plugins.push({\n apply(compiler: any) {\n compiler.hooks.assetEmitted.tap(WEBPACK_PLUGIN_NAME, (file: any, assetDetails: any) => {\n const { content, targetPath } = assetDetails;\n debug('emit file: ', targetPath);\n\n if (\n targetPath.includes('/.next/static/chunks/')\n // Dont think these actually ever happen?\n || targetPath.endsWith('.html')\n || targetPath.endsWith('.body')\n || targetPath.endsWith('.rsc')\n ) {\n // NOTE - in dev mode the request hangs on the error, but the console error should help\n // and during a build, it will actually fail the build\n try {\n scanForLeaks(content, {\n method: '@varlock/nextjs-integration/plugin - assetEmitted hook',\n file: targetPath,\n });\n } catch (err) {\n if (dev) {\n // overwrite file with redacted version\n fs.writeFileSync(targetPath, redactSensitiveConfig(content.toString()));\n } else {\n throw err;\n }\n }\n }\n });\n },\n });\n }\n\n\n\n\n // we need to inject the dmno globals injector and call it\n // and in vercel/netlify etc where we can't run via `dmno run` we need to inject the resolved config into the build\n // not sure if this is the best way, but injecting into the `webpack-runtime.js` file seems to run everywhere\n\n // updates the webpack source to inject dmno global logic and call it\n // we run this on the runtimes for serverless and edge\n function injectVarlockInitIntoWebpackRuntime(edgeRuntime = false) {\n return function (origSource: any) {\n const origSourceStr = origSource.source();\n\n // we will inline the injector code, but need a different version if we are running in the edge runtime\n // const injectorSrc = getCjsModuleSource(`dmno/injector-standalone${edgeRuntime ? '/edge' : ''}`);\n const injectorPath = path.resolve(__dirname, './patch-next-runtime.js');\n const injectorSrc = fs.readFileSync(injectorPath, 'utf8');\n\n\n const updatedSourceStr = [\n // we use `headers()` to force next into dynamic rendering mode, but on the edge runtime it's always dynamic\n // (see below for where headers is used)\n // !edgeRuntime ? 'const { headers } = require(\"next/headers\");' : '',\n\n // // code built for edge runtime does not have `module.exports` or `exports` but we are inlining some already built common-js code\n // // so we just create them. It's not needed since it is inlined and we call the function right away\n // edgeRuntime ? 'const module = { exports: {} }; const exports = {}' : '',\n\n // inline the dmno injector code and then call it\n injectorSrc,\n\n // 'injectDmnoGlobals({',\n // injectResolvedConfigAtBuildTime ? `injectedConfig: ${JSON.stringify(injectedDmnoEnv)},` : '',\n\n // // attempts to force the route into dynamic rendering mode so it wont put our our dynamic value into a pre-rendered page\n // // however we have to wrap in try/catch because you can only call headers() within certain parts of the page... so it's not 100% foolproof\n // !edgeRuntime ? `\n // onItemAccess: async (item) => {\n // if (item.dynamic) {\n // try { headers(); }\n // catch (err) {}\n // }\n // },` : '',\n // '});',\n\n origSourceStr,\n ].join('\\n');\n\n return new webpack.sources.RawSource(updatedSourceStr);\n };\n }\n\n webpackConfig.plugins.push({\n apply(compiler: any) {\n compiler.hooks.thisCompilation.tap(WEBPACK_PLUGIN_NAME, (compilation: any) => {\n compilation.hooks.processAssets.tap(\n {\n name: WEBPACK_PLUGIN_NAME,\n stage: webpack.Compilation.PROCESS_ASSETS_STAGE_ADDITIONS,\n },\n () => {\n // not sure why, but these paths are different in build vs dev\n if (compilation.getAsset('webpack-runtime.js')) {\n compilation.updateAsset('webpack-runtime.js', injectVarlockInitIntoWebpackRuntime());\n }\n if (compilation.getAsset('../webpack-runtime.js')) {\n compilation.updateAsset('../webpack-runtime.js', injectVarlockInitIntoWebpackRuntime());\n }\n if (compilation.getAsset('webpack-api-runtime.js')) {\n compilation.updateAsset('webpack-api-runtime.js', injectVarlockInitIntoWebpackRuntime());\n }\n if (compilation.getAsset('../webpack-api-runtime.js')) {\n compilation.updateAsset('../webpack-api-runtime.js', injectVarlockInitIntoWebpackRuntime());\n }\n\n if (compilation.getAsset('edge-runtime-webpack.js')) {\n compilation.updateAsset('edge-runtime-webpack.js', injectVarlockInitIntoWebpackRuntime(true));\n }\n },\n );\n });\n },\n\n });\n\n return webpackConfig; // must return the modified config\n },\n };\n };\n };\n}\n"]}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@varlock/nextjs-integration",
3
3
  "description": "drop-in replacement for @next/env that uses varlock to load .env files with validation and extra security features",
4
- "version": "0.0.1",
4
+ "version": "0.0.3",
5
5
  "repository": {
6
6
  "type": "git",
7
7
  "url": "https://github.com/dmno-dev/varlock.git",
@@ -11,7 +11,6 @@
11
11
  "types": "dist/next-env-compat.d.ts",
12
12
  "exports": {
13
13
  ".": "./dist/next-env-compat.js",
14
- "./runtime": "./dist/runtime.js",
15
14
  "./plugin": "./dist/plugin.js"
16
15
  },
17
16
  "files": [
@@ -37,12 +36,13 @@
37
36
  },
38
37
  "peerDependencies": {
39
38
  "next": ">=14",
40
- "varlock": "0.0.2"
39
+ "varlock": "^0.0.4"
41
40
  },
42
41
  "devDependencies": {
43
42
  "@types/node": "^22.15.32",
44
43
  "tsup": "^8.2.4",
45
- "varlock": "0.0.2"
44
+ "vitest": "^3.2.4",
45
+ "varlock": "^0.0.4"
46
46
  },
47
47
  "scripts": {
48
48
  "dev": "tsup --watch",