@mui/internal-docs-infra 0.12.1-canary.38 → 0.12.1-canary.39
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/cli/loadNextConfig.d.mts +1 -2
- package/cli/loadNextConfig.mjs +3 -9
- package/cli/runValidate.mjs +1 -3
- package/cli/validateWorker.mjs +0 -1
- package/package.json +2 -2
- package/pipeline/loadPrecomputedTypes/loadPrecomputedTypes.d.mts +0 -6
- package/pipeline/loadPrecomputedTypes/loadPrecomputedTypes.mjs +0 -4
- package/pipeline/loadServerTypesMeta/loadServerTypesMeta.d.mts +0 -5
- package/pipeline/loadServerTypesMeta/loadServerTypesMeta.mjs +2 -3
- package/pipeline/loadServerTypesMeta/socketClient.d.mts +10 -15
- package/pipeline/loadServerTypesMeta/socketClient.mjs +38 -40
- package/pipeline/loadServerTypesMeta/socketServer.d.mts +1 -1
- package/pipeline/loadServerTypesMeta/socketServer.mjs +4 -9
- package/pipeline/loadServerTypesMeta/worker.mjs +1 -3
- package/pipeline/loadServerTypesMeta/workerManager.d.mts +1 -1
- package/pipeline/loadServerTypesMeta/workerManager.mjs +10 -21
- package/pipeline/syncTypes/syncTypes.d.mts +0 -5
- package/pipeline/syncTypes/syncTypes.mjs +0 -1
package/cli/loadNextConfig.d.mts
CHANGED
|
@@ -25,7 +25,6 @@ export type ExtractedNextConfigOptions = {
|
|
|
25
25
|
/** Props to re-include when inherited from these externally declared types. */
|
|
26
26
|
inheritedExternalProps?: InheritedExternalPropsConfig;
|
|
27
27
|
useVisibleDescription?: boolean;
|
|
28
|
-
socketDir?: string;
|
|
29
28
|
/** Page-index cache directory configured on the sitemap loader. */
|
|
30
29
|
cacheDir?: string;
|
|
31
30
|
/** Demo index patterns that opted into automatic `client.ts` generation. */
|
|
@@ -35,7 +34,7 @@ export type ExtractedNextConfigOptions = {
|
|
|
35
34
|
};
|
|
36
35
|
/**
|
|
37
36
|
* Searches turbopack rules for docs-infra options (ordering,
|
|
38
|
-
* descriptionReplacements,
|
|
37
|
+
* descriptionReplacements, useVisibleDescription, cacheDir).
|
|
39
38
|
*
|
|
40
39
|
* Exported for tests.
|
|
41
40
|
*/
|
package/cli/loadNextConfig.mjs
CHANGED
|
@@ -32,7 +32,7 @@ function extractUseVisibleDescriptionFromRemarkPlugins(remarkPlugins) {
|
|
|
32
32
|
}
|
|
33
33
|
|
|
34
34
|
/**
|
|
35
|
-
* Extracts docs-infra options (ordering, descriptionReplacements,
|
|
35
|
+
* Extracts docs-infra options (ordering, descriptionReplacements,
|
|
36
36
|
* useVisibleDescription) from loader options in a single pass.
|
|
37
37
|
*/
|
|
38
38
|
function extractOptionsFromLoaderEntries(loaders) {
|
|
@@ -50,9 +50,6 @@ function extractOptionsFromLoaderEntries(loaders) {
|
|
|
50
50
|
if (!result.inheritedExternalProps && loader.loader === TYPES_LOADER && loader.options?.inheritedExternalProps) {
|
|
51
51
|
result.inheritedExternalProps = loader.options.inheritedExternalProps;
|
|
52
52
|
}
|
|
53
|
-
if (!result.socketDir && loader.loader === TYPES_LOADER && typeof loader.options?.socketDir === 'string') {
|
|
54
|
-
result.socketDir = loader.options.socketDir;
|
|
55
|
-
}
|
|
56
53
|
if (!result.cacheDir && loader.loader === SITEMAP_LOADER && typeof loader.options?.cacheDir === 'string') {
|
|
57
54
|
result.cacheDir = loader.options.cacheDir;
|
|
58
55
|
}
|
|
@@ -68,7 +65,7 @@ function extractOptionsFromLoaderEntries(loaders) {
|
|
|
68
65
|
|
|
69
66
|
/**
|
|
70
67
|
* Searches turbopack rules for docs-infra options (ordering,
|
|
71
|
-
* descriptionReplacements,
|
|
68
|
+
* descriptionReplacements, useVisibleDescription, cacheDir).
|
|
72
69
|
*
|
|
73
70
|
* Exported for tests.
|
|
74
71
|
*/
|
|
@@ -88,7 +85,6 @@ export function extractOptionsFromTurbopack(config) {
|
|
|
88
85
|
merged.descriptionReplacements ??= extracted.descriptionReplacements;
|
|
89
86
|
merged.inheritedExternalProps ??= extracted.inheritedExternalProps;
|
|
90
87
|
merged.useVisibleDescription ??= extracted.useVisibleDescription;
|
|
91
|
-
merged.socketDir ??= extracted.socketDir;
|
|
92
88
|
merged.cacheDir ??= extracted.cacheDir;
|
|
93
89
|
}
|
|
94
90
|
return merged;
|
|
@@ -165,7 +161,7 @@ function callWebpackSafely(config) {
|
|
|
165
161
|
|
|
166
162
|
/**
|
|
167
163
|
* Calls the webpack function with a minimal config and extracts docs-infra
|
|
168
|
-
* options (ordering, descriptionReplacements,
|
|
164
|
+
* options (ordering, descriptionReplacements, useVisibleDescription)
|
|
169
165
|
* from the resulting rules.
|
|
170
166
|
*/
|
|
171
167
|
function extractOptionsFromWebpackResult(result) {
|
|
@@ -177,7 +173,6 @@ function extractOptionsFromWebpackResult(result) {
|
|
|
177
173
|
merged.descriptionReplacements ??= extracted.descriptionReplacements;
|
|
178
174
|
merged.inheritedExternalProps ??= extracted.inheritedExternalProps;
|
|
179
175
|
merged.useVisibleDescription ??= extracted.useVisibleDescription;
|
|
180
|
-
merged.socketDir ??= extracted.socketDir;
|
|
181
176
|
merged.cacheDir ??= extracted.cacheDir;
|
|
182
177
|
}
|
|
183
178
|
return merged;
|
|
@@ -336,7 +331,6 @@ export async function extractDocsInfraOptionsFromNextConfig(dir) {
|
|
|
336
331
|
descriptionReplacements: turbopack.descriptionReplacements ?? webpack.descriptionReplacements,
|
|
337
332
|
inheritedExternalProps: turbopack.inheritedExternalProps ?? webpack.inheritedExternalProps,
|
|
338
333
|
useVisibleDescription: turbopack.useVisibleDescription ?? webpack.useVisibleDescription,
|
|
339
|
-
socketDir: turbopack.socketDir ?? webpack.socketDir,
|
|
340
334
|
cacheDir: turbopack.cacheDir ?? webpack.cacheDir,
|
|
341
335
|
demoClientRequirements: demoClientRequirements.length > 0 ? demoClientRequirements : undefined,
|
|
342
336
|
demoPageRequirements: demoPageRequirements.length > 0 ? demoPageRequirements : undefined
|
package/cli/runValidate.mjs
CHANGED
|
@@ -90,12 +90,11 @@ const runValidate = {
|
|
|
90
90
|
descriptionReplacements,
|
|
91
91
|
inheritedExternalProps,
|
|
92
92
|
useVisibleDescription = false,
|
|
93
|
-
socketDir: configSocketDir,
|
|
94
93
|
cacheDir: configCacheDir,
|
|
95
94
|
demoClientRequirements = [],
|
|
96
95
|
demoPageRequirements = []
|
|
97
96
|
} = await extractDocsInfraOptionsFromNextConfig(cwd);
|
|
98
|
-
|
|
97
|
+
|
|
99
98
|
// Use the same page-index cache directory that the sitemap loader reads at build time.
|
|
100
99
|
// The index validation pass writes cache entries even when committed indexes are current.
|
|
101
100
|
const cacheDir = configCacheDir ?? DEFAULT_CACHE_DIR;
|
|
@@ -302,7 +301,6 @@ const runValidate = {
|
|
|
302
301
|
ordering,
|
|
303
302
|
descriptionReplacements,
|
|
304
303
|
inheritedExternalProps,
|
|
305
|
-
socketDir,
|
|
306
304
|
cacheDir
|
|
307
305
|
}
|
|
308
306
|
});
|
package/cli/validateWorker.mjs
CHANGED
|
@@ -75,7 +75,6 @@ if (parentPort) {
|
|
|
75
75
|
ordering: task.syncTypesOptions.ordering,
|
|
76
76
|
descriptionReplacements: task.syncTypesOptions.descriptionReplacements,
|
|
77
77
|
inheritedExternalProps: task.syncTypesOptions.inheritedExternalProps,
|
|
78
|
-
socketDir: task.syncTypesOptions.socketDir,
|
|
79
78
|
cacheDir: task.syncTypesOptions.cacheDir
|
|
80
79
|
});
|
|
81
80
|
parentPort.postMessage({
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mui/internal-docs-infra",
|
|
3
|
-
"version": "0.12.1-canary.
|
|
3
|
+
"version": "0.12.1-canary.39",
|
|
4
4
|
"author": "MUI Team",
|
|
5
5
|
"description": "MUI Infra - internal documentation creation tools.",
|
|
6
6
|
"license": "MIT",
|
|
@@ -804,5 +804,5 @@
|
|
|
804
804
|
"bin": {
|
|
805
805
|
"docs-infra": "./cli/index.mjs"
|
|
806
806
|
},
|
|
807
|
-
"gitSha": "
|
|
807
|
+
"gitSha": "3ce58e4dbb827caca255cf9b285beafd9f10967f"
|
|
808
808
|
}
|
|
@@ -18,12 +18,6 @@ export type LoaderOptions = {
|
|
|
18
18
|
};
|
|
19
19
|
/** Options for formatting types in tables */
|
|
20
20
|
formatting?: FormatInlineTypeOptions;
|
|
21
|
-
/**
|
|
22
|
-
* Directory path for socket and lock files used for IPC between workers.
|
|
23
|
-
* Useful for Windows where the default temp directory may not support Unix domain sockets.
|
|
24
|
-
* @example '.next/docs-infra'
|
|
25
|
-
*/
|
|
26
|
-
socketDir?: string;
|
|
27
21
|
/**
|
|
28
22
|
* Options for updating the parent index page with component metadata.
|
|
29
23
|
* When provided, will call syncPageIndex to update the parent directory's page.mdx
|
|
@@ -60,9 +60,6 @@ export async function loadPrecomputedTypes(source) {
|
|
|
60
60
|
return;
|
|
61
61
|
}
|
|
62
62
|
|
|
63
|
-
// Resolve socket directory from loader options
|
|
64
|
-
const socketDir = options.socketDir ? path.resolve(rootContext, options.socketDir) : undefined;
|
|
65
|
-
|
|
66
63
|
// Convert types.ts path to types.md path
|
|
67
64
|
const typesMarkdownPath = this.resourcePath.replace(/\.tsx?$/, '.md');
|
|
68
65
|
|
|
@@ -86,7 +83,6 @@ export async function loadPrecomputedTypes(source) {
|
|
|
86
83
|
variants: typesMetaCall.variants,
|
|
87
84
|
watchSourceDirectly: Boolean(typesMetaCall.structuredOptions?.watchSourceDirectly),
|
|
88
85
|
formattingOptions: options.formatting,
|
|
89
|
-
socketDir,
|
|
90
86
|
performanceLogging: options.performance?.logging,
|
|
91
87
|
updateParentIndex,
|
|
92
88
|
externalTypesPattern: options.externalTypesPattern,
|
|
@@ -68,11 +68,6 @@ export interface LoadServerTypesMetaOptions {
|
|
|
68
68
|
watchSourceDirectly?: boolean;
|
|
69
69
|
/** Options for formatting types in tables */
|
|
70
70
|
formattingOptions?: FormatInlineTypeOptions;
|
|
71
|
-
/**
|
|
72
|
-
* Directory path for socket and lock files used for IPC between workers.
|
|
73
|
-
* Useful for Windows where the default temp directory may not support Unix domain sockets.
|
|
74
|
-
*/
|
|
75
|
-
socketDir?: string;
|
|
76
71
|
/**
|
|
77
72
|
* Optional regex pattern string to filter which external types to include.
|
|
78
73
|
* External types are named union types (like `Orientation = 'horizontal' | 'vertical'`)
|
|
@@ -38,8 +38,7 @@ export async function loadServerTypesMeta(options) {
|
|
|
38
38
|
rootContext,
|
|
39
39
|
variants,
|
|
40
40
|
watchSourceDirectly,
|
|
41
|
-
formattingOptions
|
|
42
|
-
socketDir
|
|
41
|
+
formattingOptions
|
|
43
42
|
} = options;
|
|
44
43
|
|
|
45
44
|
// Derive relative path and resource name from inputs
|
|
@@ -156,7 +155,7 @@ export async function loadServerTypesMeta(options) {
|
|
|
156
155
|
}, [functionName, relativePath]);
|
|
157
156
|
|
|
158
157
|
// Process types — use the worker manager singleton (which adapts to main vs worker thread)
|
|
159
|
-
const workerManager = getWorkerManager(
|
|
158
|
+
const workerManager = getWorkerManager();
|
|
160
159
|
const workerStartTime = performance.now();
|
|
161
160
|
const workerResult = await workerManager.processTypes({
|
|
162
161
|
projectPath: config.projectPath,
|
|
@@ -9,36 +9,34 @@
|
|
|
9
9
|
*/
|
|
10
10
|
import type { WorkerRequest, WorkerResponse } from "./worker.mjs";
|
|
11
11
|
/**
|
|
12
|
-
* Get the path to the IPC endpoint (Unix socket or Windows named pipe)
|
|
13
|
-
*
|
|
12
|
+
* Get the path to the IPC endpoint (Unix socket or Windows named pipe).
|
|
13
|
+
* Throws when the resulting Unix socket path is too long for the platform,
|
|
14
|
+
* so that every worker fails with the cause instead of only the one that goes
|
|
15
|
+
* on to bind the socket.
|
|
14
16
|
*/
|
|
15
|
-
export declare function getSocketPath(
|
|
17
|
+
export declare function getSocketPath(): string;
|
|
16
18
|
/**
|
|
17
19
|
* Get the path to the lock file used for server election
|
|
18
|
-
* @param socketDir - Optional custom directory for socket files
|
|
19
20
|
*/
|
|
20
|
-
export declare function getLockPath(
|
|
21
|
+
export declare function getLockPath(): string;
|
|
21
22
|
/**
|
|
22
23
|
* Ensure the socket directory exists
|
|
23
|
-
* @param socketDir - Optional custom directory for socket files
|
|
24
24
|
*/
|
|
25
|
-
export declare function ensureSocketDir(
|
|
25
|
+
export declare function ensureSocketDir(): Promise<void>;
|
|
26
26
|
/**
|
|
27
27
|
* Wait for the IPC endpoint to become available.
|
|
28
28
|
* On Unix: Polls the filesystem for the socket file to appear. We avoid
|
|
29
29
|
* `fs.watch` here because on macOS it does not reliably fire events when a
|
|
30
30
|
* unix domain socket file is created.
|
|
31
31
|
* On Windows: Polls by attempting to connect to the named pipe.
|
|
32
|
-
* @param socketDir - Optional custom directory for socket files (Unix only)
|
|
33
32
|
* @param timeoutMs - Timeout in milliseconds (default: 5000)
|
|
34
33
|
*/
|
|
35
|
-
export declare function waitForSocketFile(
|
|
34
|
+
export declare function waitForSocketFile(timeoutMs?: number): Promise<void>;
|
|
36
35
|
/**
|
|
37
36
|
* Try to acquire the server lock using proper-lockfile
|
|
38
37
|
* Returns true if successfully acquired (this worker should be server)
|
|
39
|
-
* @param socketDir - Optional custom directory for socket files
|
|
40
38
|
*/
|
|
41
|
-
export declare function tryAcquireServerLock(
|
|
39
|
+
export declare function tryAcquireServerLock(): Promise<boolean>;
|
|
42
40
|
/**
|
|
43
41
|
* Release the server lock
|
|
44
42
|
*/
|
|
@@ -46,19 +44,16 @@ export declare function releaseServerLock(): Promise<void>;
|
|
|
46
44
|
/**
|
|
47
45
|
* Check if there's an existing worker socket file
|
|
48
46
|
* Note: The socket server will clean up stale sockets on startup
|
|
49
|
-
* @param socketDir - Optional custom directory for socket files
|
|
50
47
|
*/
|
|
51
|
-
export declare function hasExistingWorker(
|
|
48
|
+
export declare function hasExistingWorker(): Promise<boolean>;
|
|
52
49
|
/**
|
|
53
50
|
* Client for communicating with an existing worker via socket
|
|
54
51
|
*/
|
|
55
52
|
export declare class SocketClient {
|
|
56
53
|
private socket;
|
|
57
54
|
private messageId;
|
|
58
|
-
private socketDir;
|
|
59
55
|
private pendingRequests;
|
|
60
56
|
private buffer;
|
|
61
|
-
constructor(socketDir?: string);
|
|
62
57
|
/**
|
|
63
58
|
* Connect to the worker socket with retry logic
|
|
64
59
|
*/
|
|
@@ -39,50 +39,54 @@ function getDefaultSocketDir() {
|
|
|
39
39
|
|
|
40
40
|
/**
|
|
41
41
|
* Get the effective socket directory for Unix sockets and lock files.
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
*
|
|
42
|
+
* Shared temp directories (CI runner temp or system tmp) are namespaced with a
|
|
43
|
+
* short hash of the project directory so concurrent docs-infra processes from
|
|
44
|
+
* different projects don't collide on the same socket/lock files.
|
|
45
|
+
*
|
|
46
|
+
* `MUI_DOCS_INFRA_SOCKET_DIR` overrides the directory for the rare host whose
|
|
47
|
+
* temp directory can't host a Unix domain socket. It is used as-is, so it has to
|
|
48
|
+
* be an absolute path short enough to stay under the platform's socket path
|
|
49
|
+
* limit, and unique per checkout if several run at once.
|
|
48
50
|
*/
|
|
49
|
-
function getEffectiveSocketDir(
|
|
50
|
-
|
|
51
|
-
return socketDir;
|
|
52
|
-
}
|
|
53
|
-
return `${getDefaultSocketDir()}/mui-docs-infra-${projectHash}`;
|
|
51
|
+
function getEffectiveSocketDir() {
|
|
52
|
+
return process.env.MUI_DOCS_INFRA_SOCKET_DIR ?? `${getDefaultSocketDir()}/mui-docs-infra-${projectHash}`;
|
|
54
53
|
}
|
|
55
54
|
|
|
56
55
|
/**
|
|
57
|
-
* Get the path to the IPC endpoint (Unix socket or Windows named pipe)
|
|
58
|
-
*
|
|
56
|
+
* Get the path to the IPC endpoint (Unix socket or Windows named pipe).
|
|
57
|
+
* Throws when the resulting Unix socket path is too long for the platform,
|
|
58
|
+
* so that every worker fails with the cause instead of only the one that goes
|
|
59
|
+
* on to bind the socket.
|
|
59
60
|
*/
|
|
60
|
-
export function getSocketPath(
|
|
61
|
+
export function getSocketPath() {
|
|
61
62
|
if (isWindows) {
|
|
62
63
|
// Windows named pipe using extended-length path format
|
|
63
64
|
// Uses effective socket dir to ensure uniqueness per project (prevents conflicts between parallel builds)
|
|
64
|
-
return join('\\\\?\\pipe', getEffectiveSocketDir(
|
|
65
|
+
return join('\\\\?\\pipe', getEffectiveSocketDir(), 'types');
|
|
65
66
|
}
|
|
66
|
-
const
|
|
67
|
-
|
|
67
|
+
const socketPath = join(getEffectiveSocketDir(), 'types.sock');
|
|
68
|
+
|
|
69
|
+
// Unix domain sockets have a max path length (sun_path field in sockaddr_un):
|
|
70
|
+
// Linux: 108 bytes, macOS/BSD: 104 bytes
|
|
71
|
+
const maxSocketPath = process.platform === 'darwin' ? 104 : 108;
|
|
72
|
+
if (Buffer.byteLength(socketPath) >= maxSocketPath) {
|
|
73
|
+
throw new Error(`Socket path exceeds the maximum length of ${maxSocketPath} bytes ` + `for this platform (${Buffer.byteLength(socketPath)} bytes): ${socketPath}. ` + `Set MUI_DOCS_INFRA_SOCKET_DIR to a shorter directory.`);
|
|
74
|
+
}
|
|
75
|
+
return socketPath;
|
|
68
76
|
}
|
|
69
77
|
|
|
70
78
|
/**
|
|
71
79
|
* Get the path to the lock file used for server election
|
|
72
|
-
* @param socketDir - Optional custom directory for socket files
|
|
73
80
|
*/
|
|
74
|
-
export function getLockPath(
|
|
75
|
-
|
|
76
|
-
return join(dir, 'types.lock');
|
|
81
|
+
export function getLockPath() {
|
|
82
|
+
return join(getEffectiveSocketDir(), 'types.lock');
|
|
77
83
|
}
|
|
78
84
|
|
|
79
85
|
/**
|
|
80
86
|
* Ensure the socket directory exists
|
|
81
|
-
* @param socketDir - Optional custom directory for socket files
|
|
82
87
|
*/
|
|
83
|
-
export async function ensureSocketDir(
|
|
84
|
-
|
|
85
|
-
await mkdir(dir, {
|
|
88
|
+
export async function ensureSocketDir() {
|
|
89
|
+
await mkdir(getEffectiveSocketDir(), {
|
|
86
90
|
recursive: true
|
|
87
91
|
});
|
|
88
92
|
}
|
|
@@ -131,11 +135,10 @@ function sleep(ms) {
|
|
|
131
135
|
* `fs.watch` here because on macOS it does not reliably fire events when a
|
|
132
136
|
* unix domain socket file is created.
|
|
133
137
|
* On Windows: Polls by attempting to connect to the named pipe.
|
|
134
|
-
* @param socketDir - Optional custom directory for socket files (Unix only)
|
|
135
138
|
* @param timeoutMs - Timeout in milliseconds (default: 5000)
|
|
136
139
|
*/
|
|
137
|
-
export async function waitForSocketFile(
|
|
138
|
-
const socketPath = getSocketPath(
|
|
140
|
+
export async function waitForSocketFile(timeoutMs = 5000) {
|
|
141
|
+
const socketPath = getSocketPath();
|
|
139
142
|
const pollInterval = 50;
|
|
140
143
|
const startTime = Date.now();
|
|
141
144
|
if (isWindows) {
|
|
@@ -151,7 +154,7 @@ export async function waitForSocketFile(socketDir, timeoutMs = 5000) {
|
|
|
151
154
|
}
|
|
152
155
|
|
|
153
156
|
// Ensure the directory exists so the first stat doesn't fail spuriously
|
|
154
|
-
await mkdir(getEffectiveSocketDir(
|
|
157
|
+
await mkdir(getEffectiveSocketDir(), {
|
|
155
158
|
recursive: true
|
|
156
159
|
});
|
|
157
160
|
while (Date.now() - startTime < timeoutMs) {
|
|
@@ -171,13 +174,12 @@ let lockReleaseFunction = null;
|
|
|
171
174
|
/**
|
|
172
175
|
* Try to acquire the server lock using proper-lockfile
|
|
173
176
|
* Returns true if successfully acquired (this worker should be server)
|
|
174
|
-
* @param socketDir - Optional custom directory for socket files
|
|
175
177
|
*/
|
|
176
|
-
export async function tryAcquireServerLock(
|
|
177
|
-
const lockPath = getLockPath(
|
|
178
|
+
export async function tryAcquireServerLock() {
|
|
179
|
+
const lockPath = getLockPath();
|
|
178
180
|
|
|
179
181
|
// Ensure the directory exists
|
|
180
|
-
await ensureSocketDir(
|
|
182
|
+
await ensureSocketDir();
|
|
181
183
|
try {
|
|
182
184
|
// Try to acquire the lock with no retries (immediate check)
|
|
183
185
|
// Stale locks will be detected after 3 seconds (server should start quickly)
|
|
@@ -216,10 +218,9 @@ export async function releaseServerLock() {
|
|
|
216
218
|
/**
|
|
217
219
|
* Check if there's an existing worker socket file
|
|
218
220
|
* Note: The socket server will clean up stale sockets on startup
|
|
219
|
-
* @param socketDir - Optional custom directory for socket files
|
|
220
221
|
*/
|
|
221
|
-
export async function hasExistingWorker(
|
|
222
|
-
return fileExists(getSocketPath(
|
|
222
|
+
export async function hasExistingWorker() {
|
|
223
|
+
return fileExists(getSocketPath());
|
|
223
224
|
}
|
|
224
225
|
|
|
225
226
|
/**
|
|
@@ -230,15 +231,12 @@ export class SocketClient {
|
|
|
230
231
|
messageId = 0;
|
|
231
232
|
pendingRequests = new Map();
|
|
232
233
|
buffer = '';
|
|
233
|
-
constructor(socketDir) {
|
|
234
|
-
this.socketDir = socketDir;
|
|
235
|
-
}
|
|
236
234
|
|
|
237
235
|
/**
|
|
238
236
|
* Connect to the worker socket with retry logic
|
|
239
237
|
*/
|
|
240
238
|
async connect(retryCount = 0, maxRetries = 10, retryDelay = 50) {
|
|
241
|
-
const socketPath = getSocketPath(
|
|
239
|
+
const socketPath = getSocketPath();
|
|
242
240
|
try {
|
|
243
241
|
await this.attemptConnect(socketPath);
|
|
244
242
|
} catch (error) {
|
|
@@ -26,7 +26,7 @@ export declare class SocketServer {
|
|
|
26
26
|
/**
|
|
27
27
|
* Create and initialize a socket server
|
|
28
28
|
*/
|
|
29
|
-
static create(requestHandler: (request: WorkerRequest) => Promise<WorkerResponse
|
|
29
|
+
static create(requestHandler: (request: WorkerRequest) => Promise<WorkerResponse>): Promise<SocketServer>;
|
|
30
30
|
/**
|
|
31
31
|
* Start the socket server
|
|
32
32
|
*/
|
|
@@ -44,18 +44,13 @@ export class SocketServer {
|
|
|
44
44
|
/**
|
|
45
45
|
* Create and initialize a socket server
|
|
46
46
|
*/
|
|
47
|
-
static async create(requestHandler
|
|
48
|
-
|
|
47
|
+
static async create(requestHandler) {
|
|
48
|
+
// Throws here if the path is too long for the platform's socket limit
|
|
49
|
+
const socketPath = getSocketPath();
|
|
49
50
|
|
|
50
51
|
// Ensure the directory exists (only needed for Unix sockets)
|
|
51
52
|
if (!isWindows) {
|
|
52
|
-
|
|
53
|
-
// Linux: 108 bytes, macOS/BSD: 104 bytes
|
|
54
|
-
const maxSocketPath = process.platform === 'darwin' ? 104 : 108;
|
|
55
|
-
if (Buffer.byteLength(socketPath) >= maxSocketPath) {
|
|
56
|
-
throw new Error(`Socket path exceeds the maximum length of ${maxSocketPath} bytes ` + `for this platform (${Buffer.byteLength(socketPath)} bytes): ${socketPath}. ` + `Use a shorter socketDir path or avoid deeply nesting your project directory.`);
|
|
57
|
-
}
|
|
58
|
-
await ensureSocketDir(socketDir);
|
|
53
|
+
await ensureSocketDir();
|
|
59
54
|
|
|
60
55
|
// Clean up existing socket file if it exists (might be stale from previous build)
|
|
61
56
|
if (await fileExists(socketPath)) {
|
|
@@ -6,14 +6,12 @@ import { processTypes } from "./processTypes.mjs";
|
|
|
6
6
|
|
|
7
7
|
// Re-export types for convenience
|
|
8
8
|
|
|
9
|
-
// Get socket directory from worker data (if provided)
|
|
10
|
-
const socketDir = workerData?.socketDir;
|
|
11
9
|
// When true, start a socket server so other workers can connect via IPC.
|
|
12
10
|
const isServer = workerData?.isServer === true;
|
|
13
11
|
let socketServer = null;
|
|
14
12
|
|
|
15
13
|
// If told to be a server, start the socket server for other workers to connect to.
|
|
16
|
-
const socketReady = isServer ? SocketServer.create(processTypes
|
|
14
|
+
const socketReady = isServer ? SocketServer.create(processTypes).then(async server => {
|
|
17
15
|
socketServer = server;
|
|
18
16
|
await server.start();
|
|
19
17
|
}) : Promise.resolve();
|
|
@@ -6,5 +6,5 @@ export interface TypesProcessor {
|
|
|
6
6
|
processTypes(request: WorkerRequest): Promise<WorkerResponse>;
|
|
7
7
|
terminate(): void;
|
|
8
8
|
}
|
|
9
|
-
export declare function getWorkerManager(
|
|
9
|
+
export declare function getWorkerManager(): TypesProcessor;
|
|
10
10
|
export declare function terminateWorkerManager(): void;
|
|
@@ -20,20 +20,15 @@ class TypesMetaWorkerManager {
|
|
|
20
20
|
worker = null;
|
|
21
21
|
pendingRequests = new Map();
|
|
22
22
|
requestId = 0;
|
|
23
|
-
constructor(
|
|
23
|
+
constructor() {
|
|
24
24
|
// Worker file must be compiled JS, not TS
|
|
25
25
|
// Use import.meta.url to get current directory in ESM
|
|
26
26
|
const currentDir = path.dirname(fileURLToPath(import.meta.url));
|
|
27
27
|
this.workerPath = path.join(currentDir, 'worker.mjs');
|
|
28
|
-
this.socketDir = socketDir;
|
|
29
28
|
}
|
|
30
29
|
ensureWorker() {
|
|
31
30
|
if (!this.worker) {
|
|
32
|
-
this.worker = new Worker(this.workerPath
|
|
33
|
-
workerData: this.socketDir ? {
|
|
34
|
-
socketDir: this.socketDir
|
|
35
|
-
} : undefined
|
|
36
|
-
});
|
|
31
|
+
this.worker = new Worker(this.workerPath);
|
|
37
32
|
this.worker.on('message', response => {
|
|
38
33
|
const {
|
|
39
34
|
requestId,
|
|
@@ -101,9 +96,6 @@ class WorkerThreadTypesProcessor {
|
|
|
101
96
|
initPromise = null;
|
|
102
97
|
socketClient = null;
|
|
103
98
|
serverWorker = null;
|
|
104
|
-
constructor(socketDir) {
|
|
105
|
-
this.socketDir = socketDir;
|
|
106
|
-
}
|
|
107
99
|
ensureInit() {
|
|
108
100
|
if (!this.initPromise) {
|
|
109
101
|
this.initPromise = this.init().catch(error => {
|
|
@@ -115,7 +107,7 @@ class WorkerThreadTypesProcessor {
|
|
|
115
107
|
return this.initPromise;
|
|
116
108
|
}
|
|
117
109
|
async init() {
|
|
118
|
-
const isServer = await tryAcquireServerLock(
|
|
110
|
+
const isServer = await tryAcquireServerLock();
|
|
119
111
|
if (isServer) {
|
|
120
112
|
// We won the lock — spawn the bare worker which will become a socket server.
|
|
121
113
|
// Keep the lock held so no other worker tries to spawn a second server.
|
|
@@ -123,10 +115,7 @@ class WorkerThreadTypesProcessor {
|
|
|
123
115
|
const workerPath = path.join(currentDir, 'worker.mjs');
|
|
124
116
|
this.serverWorker = new Worker(workerPath, {
|
|
125
117
|
workerData: {
|
|
126
|
-
isServer: true
|
|
127
|
-
...(this.socketDir && {
|
|
128
|
-
socketDir: this.socketDir
|
|
129
|
-
})
|
|
118
|
+
isServer: true
|
|
130
119
|
}
|
|
131
120
|
});
|
|
132
121
|
this.serverWorker.on('error', error => {
|
|
@@ -134,7 +123,7 @@ class WorkerThreadTypesProcessor {
|
|
|
134
123
|
});
|
|
135
124
|
try {
|
|
136
125
|
// Wait for the socket file to appear, then release the lock.
|
|
137
|
-
await waitForSocketFile(
|
|
126
|
+
await waitForSocketFile(30_000);
|
|
138
127
|
} catch (error) {
|
|
139
128
|
// Server worker crashed before creating the socket — release the lock
|
|
140
129
|
// so another worker can become the server on a subsequent attempt.
|
|
@@ -144,9 +133,9 @@ class WorkerThreadTypesProcessor {
|
|
|
144
133
|
await releaseServerLock();
|
|
145
134
|
} else {
|
|
146
135
|
// Another worker is the server — wait for the socket file.
|
|
147
|
-
await waitForSocketFile(
|
|
136
|
+
await waitForSocketFile(30_000);
|
|
148
137
|
}
|
|
149
|
-
this.socketClient = new SocketClient(
|
|
138
|
+
this.socketClient = new SocketClient();
|
|
150
139
|
await this.socketClient.connect();
|
|
151
140
|
}
|
|
152
141
|
async processTypes(request) {
|
|
@@ -169,15 +158,15 @@ class WorkerThreadTypesProcessor {
|
|
|
169
158
|
// In Turbopack dev mode, each compilation can have separate globalThis contexts,
|
|
170
159
|
// but they all share the same Node.js process object
|
|
171
160
|
const WORKER_MANAGER_KEY = Symbol.for('@mui/docs-infra/types-meta-worker-manager');
|
|
172
|
-
export function getWorkerManager(
|
|
161
|
+
export function getWorkerManager() {
|
|
173
162
|
const processObj = process;
|
|
174
163
|
if (!processObj[WORKER_MANAGER_KEY]) {
|
|
175
164
|
if (isMainThread) {
|
|
176
165
|
// Main thread (webpack/Next.js): spawn a worker that does lock election internally
|
|
177
|
-
processObj[WORKER_MANAGER_KEY] = new TypesMetaWorkerManager(
|
|
166
|
+
processObj[WORKER_MANAGER_KEY] = new TypesMetaWorkerManager();
|
|
178
167
|
} else {
|
|
179
168
|
// Worker thread (validate workers): do lock election here to avoid nested workers
|
|
180
|
-
processObj[WORKER_MANAGER_KEY] = new WorkerThreadTypesProcessor(
|
|
169
|
+
processObj[WORKER_MANAGER_KEY] = new WorkerThreadTypesProcessor();
|
|
181
170
|
}
|
|
182
171
|
}
|
|
183
172
|
return processObj[WORKER_MANAGER_KEY];
|
|
@@ -21,11 +21,6 @@ export interface SyncTypesOptions {
|
|
|
21
21
|
watchSourceDirectly?: boolean;
|
|
22
22
|
/** Options for formatting types in tables */
|
|
23
23
|
formattingOptions?: FormatInlineTypeOptions;
|
|
24
|
-
/**
|
|
25
|
-
* Directory path for socket and lock files used for IPC between workers.
|
|
26
|
-
* Useful for Windows where the default temp directory may not support Unix domain sockets.
|
|
27
|
-
*/
|
|
28
|
-
socketDir?: string;
|
|
29
24
|
/** Enable performance logging */
|
|
30
25
|
performanceLogging?: boolean;
|
|
31
26
|
/**
|
|
@@ -193,7 +193,6 @@ export async function syncTypes(options) {
|
|
|
193
193
|
variants: options.variants,
|
|
194
194
|
watchSourceDirectly: options.watchSourceDirectly,
|
|
195
195
|
formattingOptions: options.formattingOptions,
|
|
196
|
-
socketDir: options.socketDir,
|
|
197
196
|
externalTypesPattern: options.externalTypesPattern,
|
|
198
197
|
ordering: options.ordering,
|
|
199
198
|
descriptionReplacements: options.descriptionReplacements,
|