@basementstudio/mitt-next-plugin 0.0.0-stage → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +15 -0
- package/dist/config.d.ts +44 -0
- package/dist/config.js +63 -0
- package/dist/config.js.map +1 -0
- package/dist/git.d.ts +33 -0
- package/dist/git.js +52 -0
- package/dist/git.js.map +1 -0
- package/dist/index.d.ts +33 -0
- package/dist/index.js +121 -0
- package/dist/index.js.map +1 -0
- package/dist/loader.d.ts +21 -0
- package/dist/loader.js +71 -0
- package/dist/loader.js.map +1 -0
- package/dist/manifest.d.ts +15 -0
- package/dist/manifest.js +88 -0
- package/dist/manifest.js.map +1 -0
- package/dist/node.d.ts +2 -0
- package/dist/node.js +5 -0
- package/dist/node.js.map +1 -0
- package/dist/setup.d.ts +27 -0
- package/dist/setup.js +441 -0
- package/dist/setup.js.map +1 -0
- package/dist/transform.d.ts +40 -0
- package/dist/transform.js +365 -0
- package/dist/transform.js.map +1 -0
- package/package.json +67 -4
- package/README.md +0 -3
package/LICENSE
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
Copyright (c) 2026 basement.studio. All rights reserved.
|
|
2
|
+
|
|
3
|
+
This software and its source code are proprietary and confidential to
|
|
4
|
+
basement.studio. No license, express or implied, is granted to use, copy,
|
|
5
|
+
modify, merge, publish, distribute, sublicense or sell this software, in
|
|
6
|
+
whole or in part, except under a separate written agreement with
|
|
7
|
+
basement.studio.
|
|
8
|
+
|
|
9
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
10
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
11
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
12
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
13
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
14
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
15
|
+
SOFTWARE.
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
export declare const CONFIG_FILE = "mitt.config.json";
|
|
2
|
+
export declare const DEFAULT_SECRET_ENV = "MITT_SECRET";
|
|
3
|
+
/**
|
|
4
|
+
* Used whenever no secret is configured outside production builds. It is public by definition, so
|
|
5
|
+
* IDs made with it only hide paths from casual readers: real deployments must set their own.
|
|
6
|
+
*/
|
|
7
|
+
export declare const DEV_SECRET = "mitt-dev-secret-not-for-production";
|
|
8
|
+
/**
|
|
9
|
+
* Short one-way digest of the secret. Loader options carry it instead of the secret because Next
|
|
10
|
+
* writes the whole config to `.next/required-server-files.json`; it still changes Turbopack's cache
|
|
11
|
+
* key whenever the secret changes.
|
|
12
|
+
*/
|
|
13
|
+
export declare function secretFingerprint(secret: string): string;
|
|
14
|
+
export type Env = Readonly<Record<string, string | undefined>>;
|
|
15
|
+
export interface ResolvedSecret {
|
|
16
|
+
/** Null only when the variable is unset and the dev fallback isn't allowed. */
|
|
17
|
+
secret: string | null;
|
|
18
|
+
secretEnv: string;
|
|
19
|
+
/** The variable is unset and the public dev secret stands in. */
|
|
20
|
+
devFallback: boolean;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* The one rule for which secret keys the IDs, shared by withMitt, the loader and the CLI so they
|
|
24
|
+
* can never disagree. An empty variable counts as unset.
|
|
25
|
+
*/
|
|
26
|
+
export declare function resolveSecret(secretEnv: string, env: Env, options: {
|
|
27
|
+
allowDev: true;
|
|
28
|
+
}): ResolvedSecret & {
|
|
29
|
+
secret: string;
|
|
30
|
+
};
|
|
31
|
+
export declare function resolveSecret(secretEnv: string, env: Env, options: {
|
|
32
|
+
allowDev: boolean;
|
|
33
|
+
}): ResolvedSecret;
|
|
34
|
+
export interface MittConfig {
|
|
35
|
+
/** Name of the environment variable holding the HMAC secret. */
|
|
36
|
+
secretEnv: string;
|
|
37
|
+
/** The raw `"project"` value, unvalidated: only the CLI uses it, and validates it itself. */
|
|
38
|
+
project: unknown;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Reads `mitt.config.json` from the app root, the one place both the plugin and the CLI take their
|
|
42
|
+
* settings from so they always derive the same IDs. A missing file means defaults.
|
|
43
|
+
*/
|
|
44
|
+
export declare function readMittConfig(appRoot: string): MittConfig;
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
import { readFileSync } from 'node:fs';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
export const CONFIG_FILE = 'mitt.config.json';
|
|
5
|
+
export const DEFAULT_SECRET_ENV = 'MITT_SECRET';
|
|
6
|
+
const DEFAULT_INCLUDE = '**/*.{tsx,jsx}';
|
|
7
|
+
/**
|
|
8
|
+
* Used whenever no secret is configured outside production builds. It is public by definition, so
|
|
9
|
+
* IDs made with it only hide paths from casual readers: real deployments must set their own.
|
|
10
|
+
*/
|
|
11
|
+
export const DEV_SECRET = 'mitt-dev-secret-not-for-production';
|
|
12
|
+
/**
|
|
13
|
+
* Short one-way digest of the secret. Loader options carry it instead of the secret because Next
|
|
14
|
+
* writes the whole config to `.next/required-server-files.json`; it still changes Turbopack's cache
|
|
15
|
+
* key whenever the secret changes.
|
|
16
|
+
*/
|
|
17
|
+
export function secretFingerprint(secret) {
|
|
18
|
+
return createHash('sha256').update(`mitt-fp\0${secret}`).digest('hex').slice(0, 16);
|
|
19
|
+
}
|
|
20
|
+
export function resolveSecret(secretEnv, env, { allowDev }) {
|
|
21
|
+
const fromEnv = env[secretEnv];
|
|
22
|
+
if (fromEnv)
|
|
23
|
+
return { secret: fromEnv, secretEnv, devFallback: false };
|
|
24
|
+
return allowDev
|
|
25
|
+
? { secret: DEV_SECRET, secretEnv, devFallback: true }
|
|
26
|
+
: { secret: null, secretEnv, devFallback: false };
|
|
27
|
+
}
|
|
28
|
+
function invalid(file, reason) {
|
|
29
|
+
return new Error(`[mitt] ${file}: ${reason}`);
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Reads `mitt.config.json` from the app root, the one place both the plugin and the CLI take their
|
|
33
|
+
* settings from so they always derive the same IDs. A missing file means defaults.
|
|
34
|
+
*/
|
|
35
|
+
export function readMittConfig(appRoot) {
|
|
36
|
+
const file = join(appRoot, CONFIG_FILE);
|
|
37
|
+
let raw;
|
|
38
|
+
try {
|
|
39
|
+
raw = readFileSync(file, 'utf8');
|
|
40
|
+
}
|
|
41
|
+
catch (error) {
|
|
42
|
+
if (error.code === 'ENOENT') {
|
|
43
|
+
return { secretEnv: DEFAULT_SECRET_ENV, project: undefined };
|
|
44
|
+
}
|
|
45
|
+
throw error;
|
|
46
|
+
}
|
|
47
|
+
const parsed = JSON.parse(raw);
|
|
48
|
+
if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) {
|
|
49
|
+
throw invalid(file, 'expected a JSON object');
|
|
50
|
+
}
|
|
51
|
+
const { secretEnv = DEFAULT_SECRET_ENV, include, project } = parsed;
|
|
52
|
+
if (typeof secretEnv !== 'string' || !/^[A-Z_][A-Z0-9_]*$/.test(secretEnv)) {
|
|
53
|
+
throw invalid(file, '"secretEnv" must be an environment variable name');
|
|
54
|
+
}
|
|
55
|
+
// The loader is registered for `*.tsx`/`*.jsx` and the manifest scans the same set. Custom globs
|
|
56
|
+
// would have to be honored identically by both, so until then only the default is accepted.
|
|
57
|
+
if (include !== undefined &&
|
|
58
|
+
!(Array.isArray(include) && include.length === 1 && include[0] === DEFAULT_INCLUDE)) {
|
|
59
|
+
throw invalid(file, `"include" only supports ["${DEFAULT_INCLUDE}"] for now`);
|
|
60
|
+
}
|
|
61
|
+
return { secretEnv, project };
|
|
62
|
+
}
|
|
63
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
|
package/dist/git.d.ts
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { DIRTY_SUFFIX } from '@basementstudio/mitt-shared/formats';
|
|
2
|
+
export { DIRTY_SUFFIX };
|
|
3
|
+
export interface GitOptions {
|
|
4
|
+
input?: string;
|
|
5
|
+
/** `buffer` returns raw bytes, for output that mixes headers and blob contents. */
|
|
6
|
+
encoding?: 'utf8' | 'buffer';
|
|
7
|
+
}
|
|
8
|
+
export declare function git(cwd: string, args: string[], options?: GitOptions & {
|
|
9
|
+
encoding?: 'utf8';
|
|
10
|
+
}): string;
|
|
11
|
+
export declare function git(cwd: string, args: string[], options: GitOptions & {
|
|
12
|
+
encoding: 'buffer';
|
|
13
|
+
}): Buffer;
|
|
14
|
+
export interface RepoLayout {
|
|
15
|
+
/** The repository's top level, realpath'd. */
|
|
16
|
+
root: string;
|
|
17
|
+
/** The app's directory relative to the repo root, POSIX; empty when they are the same. */
|
|
18
|
+
appPrefix: string;
|
|
19
|
+
}
|
|
20
|
+
/** Throws when `appRoot` is not inside a git repository. */
|
|
21
|
+
export declare function repoLayout(appRoot: string): RepoLayout;
|
|
22
|
+
export interface ResolveCommitOptions {
|
|
23
|
+
/**
|
|
24
|
+
* The served code is the live working tree (e.g. `next dev`), so a clean SHA would point the
|
|
25
|
+
* manifest at a tree that stops matching on the first edit.
|
|
26
|
+
*/
|
|
27
|
+
live?: boolean;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* `VERCEL_GIT_COMMIT_SHA`, else `HEAD` plus `-dirty` when the app's tree has changes, else null.
|
|
31
|
+
* Never throws: a missing git only means comments can't be pinned to a commit.
|
|
32
|
+
*/
|
|
33
|
+
export declare function resolveCommit(appRoot: string, options?: ResolveCommitOptions): string | null;
|
package/dist/git.js
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { execFileSync } from 'node:child_process';
|
|
2
|
+
import { realpathSync } from 'node:fs';
|
|
3
|
+
import { relative, sep } from 'node:path';
|
|
4
|
+
import { DIRTY_SUFFIX, SHA_PATTERN } from '@basementstudio/mitt-shared/formats';
|
|
5
|
+
export { DIRTY_SUFFIX };
|
|
6
|
+
export function git(cwd, args, options = {}) {
|
|
7
|
+
return execFileSync('git', args, {
|
|
8
|
+
cwd,
|
|
9
|
+
// `undefined` returns a Buffer; Node rejects 'buffer' once there is `input` to encode.
|
|
10
|
+
encoding: options.encoding === 'buffer' ? undefined : 'utf8',
|
|
11
|
+
input: options.input,
|
|
12
|
+
maxBuffer: 1024 * 1024 * 1024,
|
|
13
|
+
stdio: ['pipe', 'pipe', 'ignore'],
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
/** Throws when `appRoot` is not inside a git repository. */
|
|
17
|
+
export function repoLayout(appRoot) {
|
|
18
|
+
const root = realpathSync(git(appRoot, ['rev-parse', '--show-toplevel']).trim());
|
|
19
|
+
return { root, appPrefix: relative(root, realpathSync(appRoot)).split(sep).join('/') };
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* `VERCEL_GIT_COMMIT_SHA`, else `HEAD` plus `-dirty` when the app's tree has changes, else null.
|
|
23
|
+
* Never throws: a missing git only means comments can't be pinned to a commit.
|
|
24
|
+
*/
|
|
25
|
+
export function resolveCommit(appRoot, options = {}) {
|
|
26
|
+
const suffix = options.live ? DIRTY_SUFFIX : '';
|
|
27
|
+
const vercel = process.env.VERCEL_GIT_COMMIT_SHA?.trim();
|
|
28
|
+
if (vercel && SHA_PATTERN.test(vercel))
|
|
29
|
+
return `${vercel}${suffix}`;
|
|
30
|
+
let sha;
|
|
31
|
+
try {
|
|
32
|
+
sha = git(appRoot, ['rev-parse', 'HEAD']).trim();
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
if (!SHA_PATTERN.test(sha))
|
|
38
|
+
return null;
|
|
39
|
+
if (options.live)
|
|
40
|
+
return `${sha}${DIRTY_SUFFIX}`;
|
|
41
|
+
let dirty;
|
|
42
|
+
try {
|
|
43
|
+
// Scoped to the app: changes elsewhere in a monorepo don't alter the files the manifest reads.
|
|
44
|
+
dirty = git(appRoot, ['status', '--porcelain', '--', '.']).trim() !== '';
|
|
45
|
+
}
|
|
46
|
+
catch {
|
|
47
|
+
// Unknown state: the working tree is the only source guaranteed to match this build.
|
|
48
|
+
dirty = true;
|
|
49
|
+
}
|
|
50
|
+
return dirty ? `${sha}${DIRTY_SUFFIX}` : sha;
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=git.js.map
|
package/dist/git.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"git.js","sourceRoot":"","sources":["../src/git.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AACjD,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AACtC,OAAO,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,WAAW,CAAA;AACzC,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,qCAAqC,CAAA;AAE/E,OAAO,EAAE,YAAY,EAAE,CAAA;AAkBvB,MAAM,UAAU,GAAG,CAAC,GAAW,EAAE,IAAc,EAAE,OAAO,GAAe,EAAE;IACvE,OAAO,YAAY,CAAC,KAAK,EAAE,IAAI,EAAE;QAC/B,GAAG;QACH,uFAAuF;QACvF,QAAQ,EAAE,OAAO,CAAC,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM;QAC5D,KAAK,EAAE,OAAO,CAAC,KAAK;QACpB,SAAS,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI;QAC7B,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,CAAC;KAClC,CAAC,CAAA;AACJ,CAAC;AASD,4DAA4D;AAC5D,MAAM,UAAU,UAAU,CAAC,OAAe;IACxC,MAAM,IAAI,GAAG,YAAY,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC,WAAW,EAAE,iBAAiB,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAA;IAChF,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAA;AACxF,CAAC;AAUD;;;GAGG;AACH,MAAM,UAAU,aAAa,CAAC,OAAe,EAAE,OAAO,GAAyB,EAAE;IAC/E,MAAM,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,CAAA;IAC/C,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,qBAAqB,EAAE,IAAI,EAAE,CAAA;IACxD,IAAI,MAAM,IAAI,WAAW,CAAC,IAAI,CAAC,MAAM,CAAC;QAAE,OAAO,GAAG,MAAM,GAAG,MAAM,EAAE,CAAA;IAEnE,IAAI,GAAW,CAAA;IACf,IAAI,CAAC;QACH,GAAG,GAAG,GAAG,CAAC,OAAO,EAAE,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC,CAAC,IAAI,EAAE,CAAA;IAClD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAA;IACb,CAAC;IACD,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC;QAAE,OAAO,IAAI,CAAA;IACvC,IAAI,OAAO,CAAC,IAAI;QAAE,OAAO,GAAG,GAAG,GAAG,YAAY,EAAE,CAAA;IAEhD,IAAI,KAAc,CAAA;IAClB,IAAI,CAAC;QACH,+FAA+F;QAC/F,KAAK,GAAG,GAAG,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE,aAAa,EAAE,IAAI,EAAE,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,CAAA;IAC1E,CAAC;IAAC,MAAM,CAAC;QACP,qFAAqF;QACrF,KAAK,GAAG,IAAI,CAAA;IACd,CAAC;IACD,OAAO,KAAK,CAAC,CAAC,CAAC,GAAG,GAAG,GAAG,YAAY,EAAE,CAAC,CAAC,CAAC,GAAG,CAAA;AAC9C,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { NextConfig } from 'next';
|
|
2
|
+
export type { Entry, TransformOptions, TransformResult } from './transform.js';
|
|
3
|
+
export interface NextConfigContext {
|
|
4
|
+
defaultConfig: NextConfig;
|
|
5
|
+
}
|
|
6
|
+
export type NextConfigFunction = (phase: string, context: NextConfigContext) => NextConfig | Promise<NextConfig>;
|
|
7
|
+
export interface MittOptions {
|
|
8
|
+
/**
|
|
9
|
+
* Lets `next build` fall back to the public dev secret when the secret env var is unset. Only
|
|
10
|
+
* for builds that are never deployed (e.g. a local e2e target); the IDs it produces can be
|
|
11
|
+
* reversed by anyone who can guess file paths.
|
|
12
|
+
*/
|
|
13
|
+
allowDevSecretInBuild?: boolean;
|
|
14
|
+
/**
|
|
15
|
+
* The Next app directory. Defaults to the cwd, which is the app directory whenever Next runs
|
|
16
|
+
* from its package scripts. Next doesn't chdir, so `next build <dir>` from elsewhere needs this.
|
|
17
|
+
*/
|
|
18
|
+
root?: string;
|
|
19
|
+
/**
|
|
20
|
+
* Serve the setup checklist at `/__mitt` under `next dev` (ADR 0013). Default true. Never part
|
|
21
|
+
* of a production build, whatever this says.
|
|
22
|
+
*/
|
|
23
|
+
setupPage?: boolean;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Adds opaque `data-fb` IDs to every host element, in dev and in builds alike (#7): production
|
|
27
|
+
* comments need them to resolve (#2). No path, line or stega ever reaches the output (#3, #4).
|
|
28
|
+
*
|
|
29
|
+
* Returns a config function because the secret policy depends on the phase, and Next only passes
|
|
30
|
+
* the phase to config functions (`NEXT_PHASE` is set too late in `next build` to rely on). The
|
|
31
|
+
* secret itself never enters the config: Next writes the config into the server build output.
|
|
32
|
+
*/
|
|
33
|
+
export declare function withMitt(nextConfig?: NextConfig | NextConfigFunction, options?: MittOptions): NextConfigFunction;
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import { existsSync, realpathSync } from 'node:fs';
|
|
2
|
+
import { join, resolve } from 'node:path';
|
|
3
|
+
import { fileURLToPath } from 'node:url';
|
|
4
|
+
import { readMittConfig, resolveSecret, secretFingerprint } from './config.js';
|
|
5
|
+
import { resolveCommit } from './git.js';
|
|
6
|
+
// Values of `next/constants`, inlined so the plugin doesn't load Next at config time.
|
|
7
|
+
const PHASE_DEVELOPMENT_SERVER = 'phase-development-server';
|
|
8
|
+
const PHASE_PRODUCTION_BUILD = 'phase-production-build';
|
|
9
|
+
const LOADER_PATH = fileURLToPath(new URL('./loader.js', import.meta.url));
|
|
10
|
+
const JSX_GLOBS = ['*.tsx', '*.jsx'];
|
|
11
|
+
const NEXT_CONFIG_FILES = ['next.config.ts', 'next.config.mts', 'next.config.mjs', 'next.config.js'];
|
|
12
|
+
let warnedDevSecret = false;
|
|
13
|
+
// Next loads the config several times per build; git's answer doesn't change in between.
|
|
14
|
+
const commits = new Map();
|
|
15
|
+
function commitFor(root, live) {
|
|
16
|
+
const key = `${root}\0${live}\0${process.env.VERCEL_GIT_COMMIT_SHA ?? ''}`;
|
|
17
|
+
let commit = commits.get(key);
|
|
18
|
+
if (commit === undefined) {
|
|
19
|
+
commit = resolveCommit(root, { live });
|
|
20
|
+
commits.set(key, commit);
|
|
21
|
+
}
|
|
22
|
+
return commit;
|
|
23
|
+
}
|
|
24
|
+
// IDs are keyed by paths relative to this directory and the CLI rebuilds them from the same root,
|
|
25
|
+
// so a wrong guess would make every comment unresolvable (#2): fail the build instead.
|
|
26
|
+
function resolveRoot(option) {
|
|
27
|
+
const root = realpathSync(resolve(option ?? process.cwd()));
|
|
28
|
+
if (!NEXT_CONFIG_FILES.some((file) => existsSync(join(root, file)))) {
|
|
29
|
+
throw new Error(`[mitt] ${root} has no next.config file. Run Next from the app directory or pass ` +
|
|
30
|
+
'withMitt(config, { root }).');
|
|
31
|
+
}
|
|
32
|
+
return root;
|
|
33
|
+
}
|
|
34
|
+
// Only a fingerprint leaves this function; the loader re-reads the secret from the environment.
|
|
35
|
+
function secretOptions(secretEnv, allowDevSecret) {
|
|
36
|
+
const options = { secretEnv, allowDevSecret };
|
|
37
|
+
const { secret, devFallback } = resolveSecret(secretEnv, process.env, {
|
|
38
|
+
allowDev: allowDevSecret,
|
|
39
|
+
});
|
|
40
|
+
// No secret and no fallback: the loader fails the build when it first runs. Throwing here would
|
|
41
|
+
// also break `next typegen`, which loads the config in the build phase but never compiles.
|
|
42
|
+
if (secret === null)
|
|
43
|
+
return options;
|
|
44
|
+
if (devFallback && !warnedDevSecret) {
|
|
45
|
+
warnedDevSecret = true;
|
|
46
|
+
console.warn(`[mitt] ${secretEnv} is not set; using the public dev secret for data-fb IDs.`);
|
|
47
|
+
}
|
|
48
|
+
return { ...options, fingerprint: secretFingerprint(secret) };
|
|
49
|
+
}
|
|
50
|
+
function onlyLoaders(items) {
|
|
51
|
+
return items.every((item) => typeof item === 'string' || 'loader' in item);
|
|
52
|
+
}
|
|
53
|
+
// Ours goes first so it sees the file exactly as it is on disk (and in git): IDs are keyed by
|
|
54
|
+
// line and column, and the manifest rebuilds them from the raw source.
|
|
55
|
+
function prependRule(existing, rule) {
|
|
56
|
+
if (existing === undefined)
|
|
57
|
+
return rule;
|
|
58
|
+
if (!Array.isArray(existing))
|
|
59
|
+
return [rule, existing];
|
|
60
|
+
// A plain list of loaders is shorthand for one rule; keep it as one rule.
|
|
61
|
+
if (onlyLoaders(existing))
|
|
62
|
+
return [rule, { loaders: existing }];
|
|
63
|
+
return [rule, ...existing];
|
|
64
|
+
}
|
|
65
|
+
function withTurbopackRules(config, loader) {
|
|
66
|
+
const rules = { ...config.turbopack?.rules };
|
|
67
|
+
for (const glob of JSX_GLOBS) {
|
|
68
|
+
rules[glob] = prependRule(rules[glob], {
|
|
69
|
+
condition: { not: 'foreign' },
|
|
70
|
+
loaders: [{ loader: LOADER_PATH, options: { ...loader } }],
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
return { ...config, turbopack: { ...config.turbopack, rules } };
|
|
74
|
+
}
|
|
75
|
+
function withWebpackRule(config, loader) {
|
|
76
|
+
const userWebpack = config.webpack;
|
|
77
|
+
const webpack = (webpackConfig, context) => {
|
|
78
|
+
const target = webpackConfig;
|
|
79
|
+
target.module ??= {};
|
|
80
|
+
target.module.rules ??= [];
|
|
81
|
+
target.module.rules.push({
|
|
82
|
+
test: /\.[jt]sx$/,
|
|
83
|
+
exclude: /node_modules/,
|
|
84
|
+
enforce: 'pre',
|
|
85
|
+
use: [{ loader: LOADER_PATH, options: { ...loader } }],
|
|
86
|
+
});
|
|
87
|
+
return userWebpack ? userWebpack(webpackConfig, context) : webpackConfig;
|
|
88
|
+
};
|
|
89
|
+
return { ...config, webpack };
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Adds opaque `data-fb` IDs to every host element, in dev and in builds alike (#7): production
|
|
93
|
+
* comments need them to resolve (#2). No path, line or stega ever reaches the output (#3, #4).
|
|
94
|
+
*
|
|
95
|
+
* Returns a config function because the secret policy depends on the phase, and Next only passes
|
|
96
|
+
* the phase to config functions (`NEXT_PHASE` is set too late in `next build` to rely on). The
|
|
97
|
+
* secret itself never enters the config: Next writes the config into the server build output.
|
|
98
|
+
*/
|
|
99
|
+
export function withMitt(nextConfig = {}, options = {}) {
|
|
100
|
+
return async (phase, context) => {
|
|
101
|
+
const config = typeof nextConfig === 'function' ? await nextConfig(phase, context) : nextConfig;
|
|
102
|
+
// Only these phases compile code; `next start` and friends never run the loader.
|
|
103
|
+
if (phase !== PHASE_DEVELOPMENT_SERVER && phase !== PHASE_PRODUCTION_BUILD)
|
|
104
|
+
return config;
|
|
105
|
+
const root = resolveRoot(options.root);
|
|
106
|
+
const { secretEnv } = readMittConfig(root);
|
|
107
|
+
const allowDevSecret = phase === PHASE_DEVELOPMENT_SERVER || Boolean(options.allowDevSecretInBuild);
|
|
108
|
+
const loader = { ...secretOptions(secretEnv, allowDevSecret), root };
|
|
109
|
+
const commit = commitFor(root, phase === PHASE_DEVELOPMENT_SERVER);
|
|
110
|
+
// Loader options must be plain JSON without nulls, so a missing commit is simply omitted.
|
|
111
|
+
if (commit)
|
|
112
|
+
loader.commit = commit;
|
|
113
|
+
const withLoader = withWebpackRule(withTurbopackRules(config, loader), loader);
|
|
114
|
+
if (phase !== PHASE_DEVELOPMENT_SERVER || options.setupPage === false)
|
|
115
|
+
return withLoader;
|
|
116
|
+
// Loaded only here, so builds never even import it.
|
|
117
|
+
const { setupServerFor, withSetupRewrites } = await import('./setup.js');
|
|
118
|
+
return withSetupRewrites(withLoader, (await setupServerFor(root)).target);
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/loader.d.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { SourceMap } from 'magic-string';
|
|
2
|
+
export interface MittLoaderOptions {
|
|
3
|
+
/** Environment variable the secret is read from, in the loader's own process. */
|
|
4
|
+
secretEnv: string;
|
|
5
|
+
/** `secretFingerprint` of the secret withMitt saw; absent when it saw none. */
|
|
6
|
+
fingerprint?: string;
|
|
7
|
+
/** Whether the public dev secret may stand in when `secretEnv` is unset. */
|
|
8
|
+
allowDevSecret: boolean;
|
|
9
|
+
commit?: string;
|
|
10
|
+
/** Absolute path of the Next app root; IDs are keyed by paths relative to it. */
|
|
11
|
+
root: string;
|
|
12
|
+
}
|
|
13
|
+
export interface MittLoaderContext {
|
|
14
|
+
resourcePath: string;
|
|
15
|
+
/** Whether the bundler consumes loader sourcemaps (Turbopack drops them when false). */
|
|
16
|
+
sourceMap?: boolean;
|
|
17
|
+
getOptions?: () => unknown;
|
|
18
|
+
emitWarning?: (warning: Error) => void;
|
|
19
|
+
callback?: (error: Error | null, content?: string, sourceMap?: SourceMap | unknown) => void;
|
|
20
|
+
}
|
|
21
|
+
export default function mittLoader(this: MittLoaderContext, source: string, inputMap?: unknown): string | undefined;
|
package/dist/loader.js
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { basename, isAbsolute, relative, sep } from 'node:path';
|
|
2
|
+
import { resolveSecret, secretFingerprint } from './config.js';
|
|
3
|
+
import { transform } from './transform.js';
|
|
4
|
+
function readOptions(raw) {
|
|
5
|
+
const invalid = new Error('[mitt] invalid loader options: register the loader with withMitt()');
|
|
6
|
+
if (typeof raw !== 'object' || raw === null)
|
|
7
|
+
throw invalid;
|
|
8
|
+
const { secretEnv, fingerprint, allowDevSecret, commit, root } = raw;
|
|
9
|
+
if (typeof secretEnv !== 'string' || secretEnv === '' || typeof root !== 'string')
|
|
10
|
+
throw invalid;
|
|
11
|
+
const options = { secretEnv, allowDevSecret: allowDevSecret === true, root };
|
|
12
|
+
if (typeof fingerprint === 'string')
|
|
13
|
+
options.fingerprint = fingerprint;
|
|
14
|
+
if (typeof commit === 'string')
|
|
15
|
+
options.commit = commit;
|
|
16
|
+
return options;
|
|
17
|
+
}
|
|
18
|
+
let lastVerified;
|
|
19
|
+
// Here rather than at config load, so `next typegen` and `next start` (which load the config but
|
|
20
|
+
// never compile) work without the secret; a build that would emit IDs fails instead.
|
|
21
|
+
function loaderSecret({ secretEnv, fingerprint, allowDevSecret }) {
|
|
22
|
+
const { secret } = resolveSecret(secretEnv, process.env, { allowDev: allowDevSecret });
|
|
23
|
+
if (secret === null) {
|
|
24
|
+
throw new Error(`[mitt] ${secretEnv} is not set. Production builds need a per-project secret to key the ` +
|
|
25
|
+
'data-fb IDs; without one, anyone could recover file paths from the public HTML.');
|
|
26
|
+
}
|
|
27
|
+
if (fingerprint && `${fingerprint}:${secret}` !== lastVerified) {
|
|
28
|
+
// Turbopack caches output by options, which only carry the fingerprint: a secret that differs
|
|
29
|
+
// from the config's would mix IDs from two secrets in one build.
|
|
30
|
+
if (secretFingerprint(secret) !== fingerprint) {
|
|
31
|
+
throw new Error(`[mitt] ${secretEnv} changed after the config loaded. Restart Next so every data-fb ID ` +
|
|
32
|
+
'uses the same secret.');
|
|
33
|
+
}
|
|
34
|
+
lastVerified = `${fingerprint}:${secret}`;
|
|
35
|
+
}
|
|
36
|
+
return secret;
|
|
37
|
+
}
|
|
38
|
+
// A function of (source, options) plus the secret, which the fingerprint in the options pins:
|
|
39
|
+
// Turbopack caches loader output by those inputs, so any other input or side effect would make
|
|
40
|
+
// the cached output and the git-rebuilt manifest diverge.
|
|
41
|
+
// Keep it a default export: loader-runner `require()`s Turbopack loaders and reads `.default`.
|
|
42
|
+
export default function mittLoader(source, inputMap) {
|
|
43
|
+
const done = (code, map) => {
|
|
44
|
+
if (!this.callback)
|
|
45
|
+
return code;
|
|
46
|
+
this.callback(null, code, map);
|
|
47
|
+
return undefined;
|
|
48
|
+
};
|
|
49
|
+
const options = readOptions(this.getOptions?.());
|
|
50
|
+
const rel = relative(options.root, this.resourcePath);
|
|
51
|
+
// Defensive: the rules already exclude foreign code, but an ID for a path outside the app could
|
|
52
|
+
// never be resolved by the manifest.
|
|
53
|
+
if (rel === '' || rel.startsWith('..') || isAbsolute(rel))
|
|
54
|
+
return done(source, inputMap);
|
|
55
|
+
const segments = rel.split(sep);
|
|
56
|
+
if (segments.includes('node_modules'))
|
|
57
|
+
return done(source, inputMap);
|
|
58
|
+
const result = transform(source, {
|
|
59
|
+
relPath: segments.join('/'),
|
|
60
|
+
secret: loaderSecret(options),
|
|
61
|
+
commit: options.commit,
|
|
62
|
+
mapSource: basename(this.resourcePath),
|
|
63
|
+
sourceMap: this.sourceMap !== false,
|
|
64
|
+
});
|
|
65
|
+
if (result.warning)
|
|
66
|
+
this.emitWarning?.(new Error(result.warning));
|
|
67
|
+
if (result.code === source)
|
|
68
|
+
return done(source, inputMap);
|
|
69
|
+
return done(result.code, result.map ?? undefined);
|
|
70
|
+
}
|
|
71
|
+
//# sourceMappingURL=loader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loader.js","sourceRoot":"","sources":["../src/loader.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { type Entry } from './transform.js';
|
|
2
|
+
export * from './node.js';
|
|
3
|
+
export type { Entry } from './transform.js';
|
|
4
|
+
export interface BuildManifestOptions {
|
|
5
|
+
/** The Next app directory, the same root `withMitt` keys paths by. */
|
|
6
|
+
appRoot: string;
|
|
7
|
+
/** The commit a page reported in `data-fb-commit`; `-dirty` or null reads the working tree. */
|
|
8
|
+
commit: string | null;
|
|
9
|
+
secret: string;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Rebuilds the ID -> source map for a commit by running the loader's own transform over the files
|
|
13
|
+
* of that commit. Nothing is collected from the build, so a cached build can't make it wrong.
|
|
14
|
+
*/
|
|
15
|
+
export declare function buildManifest({ appRoot, commit, secret, }: BuildManifestOptions): Map<string, Entry>;
|
package/dist/manifest.js
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
// Node-only, and private by design (#3): it maps opaque IDs back to files and lines. Client code
|
|
2
|
+
// must never import it, and its output must never be served or bundled.
|
|
3
|
+
import { readFileSync, realpathSync } from 'node:fs';
|
|
4
|
+
import { DIRTY_SUFFIX, git, repoLayout } from './git.js';
|
|
5
|
+
import { transform } from './transform.js';
|
|
6
|
+
export * from './node.js';
|
|
7
|
+
const JSX_FILE = /\.[jt]sx$/;
|
|
8
|
+
function isSource(path) {
|
|
9
|
+
return JSX_FILE.test(path) && !path.split('/').includes('node_modules');
|
|
10
|
+
}
|
|
11
|
+
function workingTreeFiles(appRoot) {
|
|
12
|
+
// Paths come back relative to the cwd, i.e. the app root. Untracked files count: a dev server or
|
|
13
|
+
// dirty build serves them too.
|
|
14
|
+
const listed = git(appRoot, ['ls-files', '-z', '--cached', '--others', '--exclude-standard']);
|
|
15
|
+
const files = [];
|
|
16
|
+
for (const relPath of new Set(listed.split('\0'))) {
|
|
17
|
+
if (!relPath || !isSource(relPath))
|
|
18
|
+
continue;
|
|
19
|
+
let source;
|
|
20
|
+
try {
|
|
21
|
+
source = readFileSync(`${appRoot}/${relPath}`, 'utf8');
|
|
22
|
+
}
|
|
23
|
+
catch (error) {
|
|
24
|
+
// Tracked but deleted in the working tree: it isn't served either.
|
|
25
|
+
if (error.code === 'ENOENT')
|
|
26
|
+
continue;
|
|
27
|
+
throw error;
|
|
28
|
+
}
|
|
29
|
+
files.push({ relPath, source });
|
|
30
|
+
}
|
|
31
|
+
return files;
|
|
32
|
+
}
|
|
33
|
+
function commitFiles(repoRoot, appPrefix, sha) {
|
|
34
|
+
const pathspec = appPrefix ? [`${appPrefix}/`] : [];
|
|
35
|
+
const listed = git(repoRoot, ['ls-tree', '-r', '-z', '--name-only', sha, '--', ...pathspec]);
|
|
36
|
+
const paths = listed.split('\0').filter((path) => path && isSource(path));
|
|
37
|
+
if (paths.length === 0)
|
|
38
|
+
return [];
|
|
39
|
+
// One `cat-file --batch` process for every blob instead of a `git show` per file.
|
|
40
|
+
const output = git(repoRoot, ['cat-file', '--batch'], {
|
|
41
|
+
input: paths.map((path) => `${sha}:${path}\n`).join(''),
|
|
42
|
+
encoding: 'buffer',
|
|
43
|
+
});
|
|
44
|
+
const files = [];
|
|
45
|
+
let offset = 0;
|
|
46
|
+
for (const path of paths) {
|
|
47
|
+
const headerEnd = output.indexOf(0x0a, offset);
|
|
48
|
+
const header = output.toString('utf8', offset, headerEnd);
|
|
49
|
+
const size = Number(header.split(' ')[2]);
|
|
50
|
+
if (!header.includes(' blob ') || !Number.isInteger(size)) {
|
|
51
|
+
throw new Error(`[mitt] could not read ${path} at ${sha}: ${header}`);
|
|
52
|
+
}
|
|
53
|
+
const start = headerEnd + 1;
|
|
54
|
+
const source = output.toString('utf8', start, start + size);
|
|
55
|
+
offset = start + size + 1;
|
|
56
|
+
files.push({ relPath: appPrefix ? path.slice(appPrefix.length + 1) : path, source });
|
|
57
|
+
}
|
|
58
|
+
return files;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Rebuilds the ID -> source map for a commit by running the loader's own transform over the files
|
|
62
|
+
* of that commit. Nothing is collected from the build, so a cached build can't make it wrong.
|
|
63
|
+
*/
|
|
64
|
+
export function buildManifest({ appRoot, commit, secret, }) {
|
|
65
|
+
const root = realpathSync(appRoot);
|
|
66
|
+
let files;
|
|
67
|
+
if (commit === null || commit.endsWith(DIRTY_SUFFIX)) {
|
|
68
|
+
files = workingTreeFiles(root);
|
|
69
|
+
}
|
|
70
|
+
else {
|
|
71
|
+
const repo = repoLayout(root);
|
|
72
|
+
files = commitFiles(repo.root, repo.appPrefix, commit);
|
|
73
|
+
}
|
|
74
|
+
const manifest = new Map();
|
|
75
|
+
for (const { relPath, source } of files) {
|
|
76
|
+
for (const entry of transform(source, { relPath, secret, sourceMap: false }).entries) {
|
|
77
|
+
const existing = manifest.get(entry.id);
|
|
78
|
+
if (existing) {
|
|
79
|
+
// Would mean a truncated-HMAC collision; resolving either entry could misplace a comment.
|
|
80
|
+
throw new Error(`[mitt] duplicate data-fb ID ${entry.id}: ${existing.file}:${existing.line} and ` +
|
|
81
|
+
`${entry.file}:${entry.line}`);
|
|
82
|
+
}
|
|
83
|
+
manifest.set(entry.id, entry);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
return manifest;
|
|
87
|
+
}
|
|
88
|
+
//# sourceMappingURL=manifest.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manifest.js","sourceRoot":"","sources":["../src/manifest.ts"],"names":[],"mappings":"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"}
|
package/dist/node.d.ts
ADDED
package/dist/node.js
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
// Node-only and light: settings, secret and git plumbing shared by the plugin and the CLI, without
|
|
2
|
+
// the transform (oxc, magic-string) that `./manifest` adds on top.
|
|
3
|
+
export { CONFIG_FILE, DEFAULT_SECRET_ENV, DEV_SECRET, readMittConfig, resolveSecret, secretFingerprint, } from './config.js';
|
|
4
|
+
export { DIRTY_SUFFIX, git, repoLayout } from './git.js';
|
|
5
|
+
//# sourceMappingURL=node.js.map
|
package/dist/node.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"node.js","sourceRoot":"","sources":["../src/node.ts"],"names":[],"mappings":"AAAA,mGAAmG;AACnG,mEAAmE;AACnE,OAAO,EACL,WAAW,EACX,kBAAkB,EAClB,UAAU,EAIV,cAAc,EACd,aAAa,EACb,iBAAiB,GAClB,MAAM,aAAa,CAAA;AACpB,OAAO,EAAE,YAAY,EAAmB,GAAG,EAAmB,UAAU,EAAE,MAAM,UAAU,CAAA"}
|