@openge/forge-process-control-node 0.1.0 → 0.3.0-rc.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/README.md +29 -31
- package/dist/command-runner.d.ts.map +1 -1
- package/dist/command-runner.js +9 -6
- package/dist/command-runner.js.map +1 -1
- package/dist/contracts.d.ts +3 -0
- package/dist/contracts.d.ts.map +1 -1
- package/dist/index.d.ts +3 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/owned-process-scope.d.ts +4 -0
- package/dist/owned-process-scope.d.ts.map +1 -0
- package/dist/owned-process-scope.js +10 -0
- package/dist/owned-process-scope.js.map +1 -0
- package/dist/owned-scope/backend.d.ts +9 -0
- package/dist/owned-scope/backend.d.ts.map +1 -0
- package/dist/owned-scope/backend.js +2 -0
- package/dist/owned-scope/backend.js.map +1 -0
- package/dist/owned-scope/linux-native.d.ts +18 -0
- package/dist/owned-scope/linux-native.d.ts.map +1 -0
- package/dist/owned-scope/linux-native.js +45 -0
- package/dist/owned-scope/linux-native.js.map +1 -0
- package/dist/owned-scope/linux-subreaper.d.ts +16 -0
- package/dist/owned-scope/linux-subreaper.d.ts.map +1 -0
- package/dist/owned-scope/linux-subreaper.js +147 -0
- package/dist/owned-scope/linux-subreaper.js.map +1 -0
- package/dist/owned-scope/native-loader.d.ts +87 -0
- package/dist/owned-scope/native-loader.d.ts.map +1 -0
- package/dist/owned-scope/native-loader.js +17 -0
- package/dist/owned-scope/native-loader.js.map +1 -0
- package/dist/owned-scope/protocol.d.ts +20 -0
- package/dist/owned-scope/protocol.d.ts.map +1 -0
- package/dist/owned-scope/protocol.js +32 -0
- package/dist/owned-scope/protocol.js.map +1 -0
- package/dist/owned-scope/scope-host.d.ts +2 -0
- package/dist/owned-scope/scope-host.d.ts.map +1 -0
- package/dist/owned-scope/scope-host.js +91 -0
- package/dist/owned-scope/scope-host.js.map +1 -0
- package/dist/owned-scope/supervisor.d.ts +11 -0
- package/dist/owned-scope/supervisor.d.ts.map +1 -0
- package/dist/owned-scope/supervisor.js +265 -0
- package/dist/owned-scope/supervisor.js.map +1 -0
- package/dist/owned-scope/windows-job.d.ts +4 -0
- package/dist/owned-scope/windows-job.d.ts.map +1 -0
- package/dist/owned-scope/windows-job.js +142 -0
- package/dist/owned-scope/windows-job.js.map +1 -0
- package/dist/provider.d.ts +4 -2
- package/dist/provider.d.ts.map +1 -1
- package/dist/provider.js +93 -0
- package/dist/provider.js.map +1 -1
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -1,35 +1,33 @@
|
|
|
1
1
|
# `@openge/forge-process-control-node`
|
|
2
2
|
|
|
3
|
-
Explicit Windows and Posix Node.js Providers for
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
## License
|
|
3
|
+
Explicit Windows and Posix Node.js Providers for Foundation process control.
|
|
4
|
+
|
|
5
|
+
Use `createWindowsProcessIdentityReader()` or `createPosixProcessIdentityReader()`
|
|
6
|
+
for identity-only reads. Both implement the Core `ProcessIdentityReader` contract
|
|
7
|
+
and accept an optional `ProcessIdentityReaderOptions.runner` without requiring a
|
|
8
|
+
listener backend. The Windows identity reader uses .NET Process creation time
|
|
9
|
+
without loading PowerShell cmdlet modules and preserves the existing CIM JSON-date
|
|
10
|
+
start-token format. Posix retains `ps`. Permission failures are rejected without
|
|
11
|
+
retries or fallback sources; full Windows process queries retain their existing backend.
|
|
12
|
+
|
|
13
|
+
Explicit `createWindowsOwnedProcessScopeProvider()` and
|
|
14
|
+
`createLinuxOwnedProcessScopeProvider()` implement owned command scopes on
|
|
15
|
+
Windows x64 (Job Objects) and Linux/glibc x64 (subreaper, wait/reap and pidfds).
|
|
16
|
+
Other hosts, missing native capabilities or unsupported Job assignment fail
|
|
17
|
+
before the job starts. Owned scopes currently require force termination.
|
|
18
|
+
Windows verifies completed member handles and complete Job membership before
|
|
19
|
+
synchronizing delayed exit accounting; a live descendant is rejected immediately.
|
|
20
|
+
Koffi is pinned to 3.3.3 and loaded lazily from installed prebuilds; runtime code
|
|
21
|
+
never downloads or compiles a fallback. With pnpm, set `allowBuilds.koffi: false`
|
|
22
|
+
when installing to prevent Koffi's optional install-time compilation fallback.
|
|
23
|
+
|
|
24
|
+
These scopes manage trusted foreground commands, not a security sandbox.
|
|
25
|
+
Commands must not delegate execution to WMI, system services or another external
|
|
26
|
+
process owner. Normal closure differs from successful forced cleanup: cleanup
|
|
27
|
+
can prove emptiness while completion remains unknown.
|
|
28
|
+
|
|
29
|
+
Complete usage, backend selection, examples, termination semantics, and provider boundaries are maintained in the [中文使用文档](https://github.com/zopenge/foundation-forge/blob/main/docs/packages/process-execution/process-control-node.md).
|
|
30
|
+
|
|
31
|
+
For repository-wide capability discovery, see the [Foundation Forge documentation](https://github.com/zopenge/foundation-forge/blob/main/docs/README.md).
|
|
34
32
|
|
|
35
33
|
Licensed under the Apache License 2.0.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"command-runner.d.ts","sourceRoot":"","sources":["../src/command-runner.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"command-runner.d.ts","sourceRoot":"","sources":["../src/command-runner.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AAE3D,eAAO,MAAM,iBAAiB,EAAE,oBAyB9B,CAAC"}
|
package/dist/command-runner.js
CHANGED
|
@@ -1,16 +1,19 @@
|
|
|
1
1
|
import { execFile } from 'node:child_process';
|
|
2
|
-
|
|
2
|
+
import { ProcessControlError, processControlErrorCodes } from '@openge/forge-process-control';
|
|
3
|
+
export const runProcessCommand = async (request) => new Promise((resolve, reject) => {
|
|
3
4
|
execFile(request.command, [...request.args], {
|
|
4
5
|
encoding: 'utf8',
|
|
5
6
|
maxBuffer: 16 * 1_024 * 1_024,
|
|
6
7
|
signal: request.signal,
|
|
7
8
|
windowsHide: true,
|
|
8
9
|
}, (error, stdout, stderr) => {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
10
|
+
if (error !== null && typeof error.code !== 'number') {
|
|
11
|
+
reject(new ProcessControlError(request.signal?.aborted === true
|
|
12
|
+
? processControlErrorCodes.operationAborted
|
|
13
|
+
: processControlErrorCodes.commandFailed, { command: request.command }, error));
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
const exitCode = typeof error?.code === 'number' ? error.code : 0;
|
|
14
17
|
resolve({ exitCode, stderr, stdout });
|
|
15
18
|
});
|
|
16
19
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"command-runner.js","sourceRoot":"","sources":["../src/command-runner.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"command-runner.js","sourceRoot":"","sources":["../src/command-runner.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,mBAAmB,EAAE,wBAAwB,EAAE,MAAM,+BAA+B,CAAC;AAI9F,MAAM,CAAC,MAAM,iBAAiB,GAAyB,KAAK,EAAE,OAAO,EAAE,EAAE,CAAC,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;IACxG,QAAQ,CACN,OAAO,CAAC,OAAO,EACf,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,EACjB;QACE,QAAQ,EAAE,MAAM;QAChB,SAAS,EAAE,EAAE,GAAG,KAAK,GAAG,KAAK;QAC7B,MAAM,EAAE,OAAO,CAAC,MAAM;QACtB,WAAW,EAAE,IAAI;KAClB,EACD,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE;QACxB,IAAI,KAAK,KAAK,IAAI,IAAI,OAAO,KAAK,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YACrD,MAAM,CAAC,IAAI,mBAAmB,CAC5B,OAAO,CAAC,MAAM,EAAE,OAAO,KAAK,IAAI;gBAC9B,CAAC,CAAC,wBAAwB,CAAC,gBAAgB;gBAC3C,CAAC,CAAC,wBAAwB,CAAC,aAAa,EAC1C,EAAE,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE,EAC5B,KAAK,CACN,CAAC,CAAC;YACH,OAAO;QACT,CAAC;QACD,MAAM,QAAQ,GAAG,OAAO,KAAK,EAAE,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;QAClE,OAAO,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;IACxC,CAAC,CACF,CAAC;AACJ,CAAC,CAAC,CAAC"}
|
package/dist/contracts.d.ts
CHANGED
|
@@ -9,6 +9,9 @@ export interface ProcessCommandResult {
|
|
|
9
9
|
readonly stdout: string;
|
|
10
10
|
}
|
|
11
11
|
export type ProcessCommandRunner = (request: ProcessCommandRequest) => Promise<ProcessCommandResult>;
|
|
12
|
+
export interface ProcessIdentityReaderOptions {
|
|
13
|
+
readonly runner?: ProcessCommandRunner;
|
|
14
|
+
}
|
|
12
15
|
export interface WindowsProcessControlOptions {
|
|
13
16
|
readonly listenerBackend: 'netstat' | 'powershell';
|
|
14
17
|
readonly runner?: ProcessCommandRunner;
|
package/dist/contracts.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"contracts.d.ts","sourceRoot":"","sources":["../src/contracts.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,CAAC;IACjC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,CAAC;CAC/B;AAED,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,MAAM,oBAAoB,GAAG,CACjC,OAAO,EAAE,qBAAqB,KAC3B,OAAO,CAAC,oBAAoB,CAAC,CAAC;AAEnC,MAAM,WAAW,4BAA4B;IAC3C,QAAQ,CAAC,eAAe,EAAE,SAAS,GAAG,YAAY,CAAC;IACnD,QAAQ,CAAC,MAAM,CAAC,EAAE,oBAAoB,CAAC;CACxC;AAED,MAAM,WAAW,0BAA0B;IACzC,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,MAAM,CAAC,EAAE,oBAAoB,CAAC;CACxC"}
|
|
1
|
+
{"version":3,"file":"contracts.d.ts","sourceRoot":"","sources":["../src/contracts.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,CAAC;IACjC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,CAAC;CAC/B;AAED,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,MAAM,oBAAoB,GAAG,CACjC,OAAO,EAAE,qBAAqB,KAC3B,OAAO,CAAC,oBAAoB,CAAC,CAAC;AAEnC,MAAM,WAAW,4BAA4B;IAC3C,QAAQ,CAAC,MAAM,CAAC,EAAE,oBAAoB,CAAC;CACxC;AAED,MAAM,WAAW,4BAA4B;IAC3C,QAAQ,CAAC,eAAe,EAAE,SAAS,GAAG,YAAY,CAAC;IACnD,QAAQ,CAAC,MAAM,CAAC,EAAE,oBAAoB,CAAC;CACxC;AAED,MAAM,WAAW,0BAA0B;IACzC,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,MAAM,CAAC,EAAE,oBAAoB,CAAC;CACxC"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
-
export { type PosixProcessControlOptions, type ProcessCommandRequest, type ProcessCommandResult, type ProcessCommandRunner, type WindowsProcessControlOptions, } from './contracts.js';
|
|
2
|
-
export { createPosixProcessControl, createWindowsProcessControl } from './provider.js';
|
|
1
|
+
export { type PosixProcessControlOptions, type ProcessCommandRequest, type ProcessCommandResult, type ProcessCommandRunner, type ProcessIdentityReaderOptions, type WindowsProcessControlOptions, } from './contracts.js';
|
|
2
|
+
export { createPosixProcessControl, createPosixProcessIdentityReader, createWindowsProcessControl, createWindowsProcessIdentityReader, } from './provider.js';
|
|
3
|
+
export { createWindowsOwnedProcessScopeProvider, createLinuxOwnedProcessScopeProvider } from './owned-process-scope.js';
|
|
3
4
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,0BAA0B,EAC/B,KAAK,qBAAqB,EAC1B,KAAK,oBAAoB,EACzB,KAAK,oBAAoB,EACzB,KAAK,4BAA4B,GAClC,MAAM,gBAAgB,CAAC;AACxB,OAAO,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,0BAA0B,EAC/B,KAAK,qBAAqB,EAC1B,KAAK,oBAAoB,EACzB,KAAK,oBAAoB,EACzB,KAAK,4BAA4B,EACjC,KAAK,4BAA4B,GAClC,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACL,yBAAyB,EACzB,gCAAgC,EAChC,2BAA2B,EAC3B,kCAAkC,GACnC,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,sCAAsC,EAAE,oCAAoC,EAAE,MAAM,0BAA0B,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
1
|
export {} from './contracts.js';
|
|
2
|
-
export { createPosixProcessControl, createWindowsProcessControl } from './provider.js';
|
|
2
|
+
export { createPosixProcessControl, createPosixProcessIdentityReader, createWindowsProcessControl, createWindowsProcessIdentityReader, } from './provider.js';
|
|
3
|
+
export { createWindowsOwnedProcessScopeProvider, createLinuxOwnedProcessScopeProvider } from './owned-process-scope.js';
|
|
3
4
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAON,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACL,yBAAyB,EACzB,gCAAgC,EAChC,2BAA2B,EAC3B,kCAAkC,GACnC,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,sCAAsC,EAAE,oCAAoC,EAAE,MAAM,0BAA0B,CAAC"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { OwnedProcessScopeProvider } from '@openge/forge-process-control';
|
|
2
|
+
export declare function createWindowsOwnedProcessScopeProvider(): OwnedProcessScopeProvider;
|
|
3
|
+
export declare function createLinuxOwnedProcessScopeProvider(): OwnedProcessScopeProvider;
|
|
4
|
+
//# sourceMappingURL=owned-process-scope.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"owned-process-scope.d.ts","sourceRoot":"","sources":["../src/owned-process-scope.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,+BAA+B,CAAC;AAK/E,wBAAgB,sCAAsC,IAAI,yBAAyB,CAElF;AACD,wBAAgB,oCAAoC,IAAI,yBAAyB,CAEhF"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { startSupervisor } from './owned-scope/supervisor.js';
|
|
2
|
+
import { createWindowsJob } from './owned-scope/windows-job.js';
|
|
3
|
+
import { createLinuxSubreaper } from './owned-scope/linux-subreaper.js';
|
|
4
|
+
export function createWindowsOwnedProcessScopeProvider() {
|
|
5
|
+
return { start: (request, output) => startSupervisor(request, 'win32', createWindowsJob, output) };
|
|
6
|
+
}
|
|
7
|
+
export function createLinuxOwnedProcessScopeProvider() {
|
|
8
|
+
return { start: (request, output) => startSupervisor(request, 'linux', createLinuxSubreaper, output) };
|
|
9
|
+
}
|
|
10
|
+
//# sourceMappingURL=owned-process-scope.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"owned-process-scope.js","sourceRoot":"","sources":["../src/owned-process-scope.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAC9D,OAAO,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAChE,OAAO,EAAE,oBAAoB,EAAE,MAAM,kCAAkC,CAAC;AAExE,MAAM,UAAU,sCAAsC;IACpD,OAAO,EAAE,KAAK,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,CAAC,eAAe,CAAC,OAAO,EAAE,OAAO,EAAE,gBAAgB,EAAE,MAAM,CAAC,EAAE,CAAC;AACrG,CAAC;AACD,MAAM,UAAU,oCAAoC;IAClD,OAAO,EAAE,KAAK,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,CAAC,eAAe,CAAC,OAAO,EAAE,OAAO,EAAE,oBAAoB,EAAE,MAAM,CAAC,EAAE,CAAC;AACzG,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { ProcessIdentity } from '@openge/forge-process-control';
|
|
2
|
+
export interface ScopeBackend {
|
|
3
|
+
attach(pid: number): Promise<void>;
|
|
4
|
+
bind(identity: ProcessIdentity): Promise<void>;
|
|
5
|
+
empty(rootExited: boolean): Promise<boolean>;
|
|
6
|
+
force(): Promise<void>;
|
|
7
|
+
dispose(): Promise<void>;
|
|
8
|
+
}
|
|
9
|
+
//# sourceMappingURL=backend.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"backend.d.ts","sourceRoot":"","sources":["../../src/owned-scope/backend.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AAErE,MAAM,WAAW,YAAY;IAC3B,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACnC,IAAI,CAAC,QAAQ,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/C,KAAK,CAAC,UAAU,EAAE,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAC7C,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACvB,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CAC1B"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"backend.js","sourceRoot":"","sources":["../../src/owned-scope/backend.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/** 只调用 glibc 已导出的接口,不猜测 syscall 编号,也不在维护者进程设置 subreaper。 */
|
|
2
|
+
export declare function loadLinuxScopeNative(): Promise<{
|
|
3
|
+
establish(): void;
|
|
4
|
+
reap(): {
|
|
5
|
+
pid: number;
|
|
6
|
+
errno: number;
|
|
7
|
+
};
|
|
8
|
+
open(pid: number): {
|
|
9
|
+
fd: number;
|
|
10
|
+
errno: number;
|
|
11
|
+
};
|
|
12
|
+
signal(fd: number, value: number): {
|
|
13
|
+
ok: boolean;
|
|
14
|
+
errno: number;
|
|
15
|
+
};
|
|
16
|
+
close(fd: number): void;
|
|
17
|
+
}>;
|
|
18
|
+
//# sourceMappingURL=linux-native.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"linux-native.d.ts","sourceRoot":"","sources":["../../src/owned-scope/linux-native.ts"],"names":[],"mappings":"AAGA,4DAA4D;AAC5D,wBAAsB,oBAAoB;;YAsB5B;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE;cAC5B,MAAM,GAAG;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE;eACrC,MAAM,SAAS,MAAM,GAAG;QAAE,EAAE,EAAE,OAAO,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE;cACvD,MAAM;GAKrB"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { ProcessControlError, processControlErrorCodes } from '@openge/forge-process-control';
|
|
2
|
+
import { loadOwnedNative } from './native-loader.js';
|
|
3
|
+
/** 只调用 glibc 已导出的接口,不猜测 syscall 编号,也不在维护者进程设置 subreaper。 */
|
|
4
|
+
export async function loadLinuxScopeNative() {
|
|
5
|
+
try {
|
|
6
|
+
const k = await loadOwnedNative('linux'), lib = k.load('libc.so.6');
|
|
7
|
+
const set = lib.func('int prctl(int option, uintptr_t value, uintptr_t arg3, uintptr_t arg4, uintptr_t arg5)');
|
|
8
|
+
const get = lib.func('prctl', 'int', ['int', k.out(k.pointer('int')), 'uintptr_t', 'uintptr_t', 'uintptr_t']);
|
|
9
|
+
const wait = lib.func('waitpid', 'int', ['int', k.out(k.pointer('int')), 'int']);
|
|
10
|
+
const open = lib.func('int pidfd_open(int pid, unsigned int flags)');
|
|
11
|
+
const signal = lib.func('int pidfd_send_signal(int fd, int signal, void *info, unsigned int flags)');
|
|
12
|
+
const close = lib.func('int close(int fd)');
|
|
13
|
+
const state = [0];
|
|
14
|
+
if (get(37, state, 0, 0, 0) !== 0)
|
|
15
|
+
throw Error('SUBREAPER_PROBE');
|
|
16
|
+
const own = Number(open(process.pid, 0));
|
|
17
|
+
if (own < 0)
|
|
18
|
+
throw Error('PIDFD_PROBE');
|
|
19
|
+
let signaled = false, closed = false;
|
|
20
|
+
try {
|
|
21
|
+
signaled = signal(own, 0, null, 0) === 0;
|
|
22
|
+
}
|
|
23
|
+
finally {
|
|
24
|
+
closed = close(own) === 0;
|
|
25
|
+
}
|
|
26
|
+
if (!signaled || !closed)
|
|
27
|
+
throw Error('PIDFD_SIGNAL_PROBE');
|
|
28
|
+
return {
|
|
29
|
+
establish() {
|
|
30
|
+
const value = [0];
|
|
31
|
+
if (set(36, 1, 0, 0, 0) !== 0 || get(37, value, 0, 0, 0) !== 0 || value[0] !== 1)
|
|
32
|
+
throw Error('SUBREAPER_SETUP');
|
|
33
|
+
},
|
|
34
|
+
reap() { const status = [0], pid = Number(wait(-1, status, 1)); return { pid, errno: pid < 0 ? k.errno() : 0 }; },
|
|
35
|
+
open(pid) { const fd = Number(open(pid, 0)); return { fd, errno: fd < 0 ? k.errno() : 0 }; },
|
|
36
|
+
signal(fd, value) { const ok = signal(fd, value, null, 0) === 0; return { ok, errno: ok ? 0 : k.errno() }; },
|
|
37
|
+
close(fd) { if (close(fd) !== 0)
|
|
38
|
+
throw Error('PIDFD_CLOSE'); },
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
catch {
|
|
42
|
+
throw new ProcessControlError(processControlErrorCodes.scopeUnsupported, { reason: 'LINUX_GLIBC_SCOPE' });
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
//# sourceMappingURL=linux-native.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"linux-native.js","sourceRoot":"","sources":["../../src/owned-scope/linux-native.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { type ReadProcessIdentityRequest } from '@openge/forge-process-control';
|
|
2
|
+
import type { ScopeBackend } from './backend.js';
|
|
3
|
+
import { loadLinuxScopeNative } from './linux-native.js';
|
|
4
|
+
import type { SupervisorPort } from './supervisor.js';
|
|
5
|
+
declare function startTicks(pid: number): Promise<string>;
|
|
6
|
+
export declare function createLinuxSubreaper(port: SupervisorPort, io?: {
|
|
7
|
+
load: typeof loadLinuxScopeNative;
|
|
8
|
+
ticks: typeof startTicks;
|
|
9
|
+
readIdentity: (request: ReadProcessIdentityRequest) => Promise<import("@openge/forge-process-control").ReadProcessIdentityResult>;
|
|
10
|
+
}): Promise<ScopeBackend>;
|
|
11
|
+
export declare function createLinuxReaper(directClosed: () => boolean, timeoutMs: number): Promise<{
|
|
12
|
+
empty: () => boolean;
|
|
13
|
+
stop(): Promise<boolean>;
|
|
14
|
+
}>;
|
|
15
|
+
export {};
|
|
16
|
+
//# sourceMappingURL=linux-subreaper.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"linux-subreaper.d.ts","sourceRoot":"","sources":["../../src/owned-scope/linux-subreaper.ts"],"names":[],"mappings":"AACA,OAAO,EAAuE,KAAK,0BAA0B,EAAE,MAAM,+BAA+B,CAAC;AAErJ,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AACjD,OAAO,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AACzD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAEtD,iBAAe,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAKtD;AAED,wBAAsB,oBAAoB,CAAC,IAAI,EAAE,cAAc,EAAE,EAAE;;;4BADwB,0BAA0B;CACtC,GAAG,OAAO,CAAC,YAAY,CAAC,CA2CtG;AAED,wBAAsB,iBAAiB,CAAC,YAAY,EAAE,MAAM,OAAO,EAAE,SAAS,EAAE,MAAM;;YAepE,OAAO,CAAC,OAAO,CAAC;GAyBjC"}
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import { readFile } from 'node:fs/promises';
|
|
2
|
+
import { ProcessControlError, processControlErrorCodes } from '@openge/forge-process-control';
|
|
3
|
+
import { createPosixProcessIdentityReader } from '../provider.js';
|
|
4
|
+
import { loadLinuxScopeNative } from './linux-native.js';
|
|
5
|
+
async function startTicks(pid) {
|
|
6
|
+
const text = await readFile(`/proc/${String(pid)}/stat`, 'utf8');
|
|
7
|
+
const value = text.slice(text.lastIndexOf(')') + 2).split(' ')[19];
|
|
8
|
+
if (text.length > 65_536 || value === undefined || !/^\d+$/u.test(value))
|
|
9
|
+
throw Error('ROOT_STAT');
|
|
10
|
+
return value;
|
|
11
|
+
}
|
|
12
|
+
const defaultIo = { load: loadLinuxScopeNative, ticks: startTicks, readIdentity: (request) => createPosixProcessIdentityReader().readIdentity(request) };
|
|
13
|
+
export async function createLinuxSubreaper(port, io = defaultIo) {
|
|
14
|
+
const native = await io.load();
|
|
15
|
+
let fd, actual, provenEmpty = false, rootExited = false;
|
|
16
|
+
return {
|
|
17
|
+
attach: async (pid) => {
|
|
18
|
+
if (fd !== undefined)
|
|
19
|
+
throw Error('ATTACH_STATE');
|
|
20
|
+
// spawn 返回后先同步固定实例;未验证的 fd 只可关闭,不能接收终止信号。
|
|
21
|
+
const handle = native.open(pid);
|
|
22
|
+
if (handle.fd < 0)
|
|
23
|
+
throw Error('ROOT_PIDFD');
|
|
24
|
+
try {
|
|
25
|
+
port.assertRootInstance(pid);
|
|
26
|
+
const before = await io.ticks(pid), observed = await io.readIdentity({ pid, signal: port.startupSignal });
|
|
27
|
+
if (observed.status !== 'FOUND' || before !== await io.ticks(pid) || !native.signal(handle.fd, 0).ok)
|
|
28
|
+
throw Error('ROOT_INSTANCE');
|
|
29
|
+
port.assertRootInstance(pid);
|
|
30
|
+
actual = observed.identity;
|
|
31
|
+
fd = handle.fd;
|
|
32
|
+
}
|
|
33
|
+
catch (error) {
|
|
34
|
+
native.close(handle.fd);
|
|
35
|
+
throw error;
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
bind: async (identity) => {
|
|
39
|
+
if (!actual || fd === undefined || identity.pid !== actual.pid || identity.startToken !== actual.startToken || !native.signal(fd, 0).ok) {
|
|
40
|
+
throw new ProcessControlError(processControlErrorCodes.scopeBinding, { reason: 'ROOT_IDENTITY' });
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
empty: async (exited) => {
|
|
44
|
+
if (exited) {
|
|
45
|
+
rootExited = true;
|
|
46
|
+
return provenEmpty;
|
|
47
|
+
}
|
|
48
|
+
const result = await port.rpc('inspect');
|
|
49
|
+
provenEmpty = result.empty === true;
|
|
50
|
+
return provenEmpty;
|
|
51
|
+
},
|
|
52
|
+
force: async () => {
|
|
53
|
+
if (rootExited)
|
|
54
|
+
return;
|
|
55
|
+
try {
|
|
56
|
+
const result = await port.rpc('stop');
|
|
57
|
+
provenEmpty = result.empty === true;
|
|
58
|
+
if (!provenEmpty)
|
|
59
|
+
throw Error('CHILDREN_UNKNOWN');
|
|
60
|
+
await port.rpc('finish');
|
|
61
|
+
}
|
|
62
|
+
catch (error) {
|
|
63
|
+
// IPC 失效时请求自有 helper 收尾;不能用宿主进程差集代替后代归属。
|
|
64
|
+
if (fd !== undefined)
|
|
65
|
+
native.signal(fd, 15);
|
|
66
|
+
throw error;
|
|
67
|
+
}
|
|
68
|
+
},
|
|
69
|
+
dispose: async () => {
|
|
70
|
+
if (fd !== undefined) {
|
|
71
|
+
try {
|
|
72
|
+
if (!rootExited)
|
|
73
|
+
native.signal(fd, 9);
|
|
74
|
+
}
|
|
75
|
+
finally {
|
|
76
|
+
native.close(fd);
|
|
77
|
+
fd = undefined;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
},
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
export async function createLinuxReaper(directClosed, timeoutMs) {
|
|
84
|
+
const native = await loadLinuxScopeNative();
|
|
85
|
+
native.establish();
|
|
86
|
+
const empty = () => {
|
|
87
|
+
if (!directClosed())
|
|
88
|
+
return false;
|
|
89
|
+
for (let attempts = 0; attempts < 4096; attempts++) {
|
|
90
|
+
const result = native.reap();
|
|
91
|
+
if (result.pid > 0 || (result.pid < 0 && result.errno === 4))
|
|
92
|
+
continue;
|
|
93
|
+
if (result.pid === 0)
|
|
94
|
+
return false;
|
|
95
|
+
if (result.errno === 10)
|
|
96
|
+
return true;
|
|
97
|
+
throw Error('WAIT_UNKNOWN');
|
|
98
|
+
}
|
|
99
|
+
throw Error('REAP_LIMIT');
|
|
100
|
+
};
|
|
101
|
+
return {
|
|
102
|
+
empty,
|
|
103
|
+
async stop() {
|
|
104
|
+
const deadline = Date.now() + timeoutMs;
|
|
105
|
+
do {
|
|
106
|
+
if (empty())
|
|
107
|
+
return true;
|
|
108
|
+
const text = await readFile(`/proc/self/task/${String(process.pid)}/children`, 'utf8');
|
|
109
|
+
if (text.length > 65_536)
|
|
110
|
+
throw Error('CHILDREN_LIMIT');
|
|
111
|
+
const children = text.trim() ? text.trim().split(/\s+/u) : [];
|
|
112
|
+
if (children.length > 4096 || children.some(value => !/^[1-9]\d*$/u.test(value)))
|
|
113
|
+
throw Error('CHILDREN_INVALID');
|
|
114
|
+
for (const value of children) {
|
|
115
|
+
const pid = Number(value), opened = native.open(pid);
|
|
116
|
+
if (opened.fd < 0) {
|
|
117
|
+
if (opened.errno === 3)
|
|
118
|
+
continue;
|
|
119
|
+
throw Error('CHILD_PIDFD');
|
|
120
|
+
}
|
|
121
|
+
try {
|
|
122
|
+
let status;
|
|
123
|
+
try {
|
|
124
|
+
status = await readFile(`/proc/${value}/status`, 'utf8');
|
|
125
|
+
}
|
|
126
|
+
catch (error) {
|
|
127
|
+
if (error instanceof Error && 'code' in error && error.code === 'ENOENT')
|
|
128
|
+
continue;
|
|
129
|
+
throw error;
|
|
130
|
+
}
|
|
131
|
+
if (status.length > 65_536 || /^PPid:\s+(\d+)$/mu.exec(status)?.[1] !== String(process.pid))
|
|
132
|
+
continue;
|
|
133
|
+
const sent = native.signal(opened.fd, 9);
|
|
134
|
+
if (!sent.ok && sent.errno !== 3)
|
|
135
|
+
throw Error('CHILD_SIGNAL');
|
|
136
|
+
}
|
|
137
|
+
finally {
|
|
138
|
+
native.close(opened.fd);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
await new Promise(accept => setTimeout(accept, 10));
|
|
142
|
+
} while (Date.now() < deadline);
|
|
143
|
+
return empty();
|
|
144
|
+
},
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
//# sourceMappingURL=linux-subreaper.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"linux-subreaper.js","sourceRoot":"","sources":["../../src/owned-scope/linux-subreaper.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,mBAAmB,EAAE,wBAAwB,EAAyD,MAAM,+BAA+B,CAAC;AACrJ,OAAO,EAAE,gCAAgC,EAAE,MAAM,gBAAgB,CAAC;AAElE,OAAO,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AAGzD,KAAK,UAAU,UAAU,CAAC,GAAW;IACnC,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,SAAS,MAAM,CAAC,GAAG,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IACjE,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC;IACnE,IAAI,IAAI,CAAC,MAAM,GAAG,MAAM,IAAI,KAAK,KAAK,SAAS,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC;QAAE,MAAM,KAAK,CAAC,WAAW,CAAC,CAAC;IACnG,OAAO,KAAK,CAAC;AACf,CAAC;AACD,MAAM,SAAS,GAAG,EAAE,IAAI,EAAE,oBAAoB,EAAE,KAAK,EAAE,UAAU,EAAE,YAAY,EAAE,CAAC,OAAmC,EAAE,EAAE,CAAC,gCAAgC,EAAE,CAAC,YAAY,CAAC,OAAO,CAAC,EAAE,CAAC;AACrL,MAAM,CAAC,KAAK,UAAU,oBAAoB,CAAC,IAAoB,EAAE,EAAE,GAAG,SAAS;IAC7E,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC;IAC/B,IAAI,EAAsB,EAAE,MAAmC,EAAE,WAAW,GAAG,KAAK,EAAE,UAAU,GAAG,KAAK,CAAC;IACzG,OAAO;QACL,MAAM,EAAE,KAAK,EAAC,GAAG,EAAC,EAAE;YAClB,IAAI,EAAE,KAAK,SAAS;gBAAE,MAAM,KAAK,CAAC,cAAc,CAAC,CAAC;YAClD,0CAA0C;YAC1C,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YAChC,IAAI,MAAM,CAAC,EAAE,GAAG,CAAC;gBAAE,MAAM,KAAK,CAAC,YAAY,CAAC,CAAC;YAC7C,IAAI,CAAC;gBACH,IAAI,CAAC,kBAAkB,CAAC,GAAG,CAAC,CAAC;gBAC7B,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,QAAQ,GAAG,MAAM,EAAE,CAAC,YAAY,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,aAAa,EAAE,CAAC,CAAC;gBAC1G,IAAI,QAAQ,CAAC,MAAM,KAAK,OAAO,IAAI,MAAM,KAAK,MAAM,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE;oBAAE,MAAM,KAAK,CAAC,eAAe,CAAC,CAAC;gBACnI,IAAI,CAAC,kBAAkB,CAAC,GAAG,CAAC,CAAC;gBAAC,MAAM,GAAG,QAAQ,CAAC,QAAQ,CAAC;gBAAC,EAAE,GAAG,MAAM,CAAC,EAAE,CAAC;YAC3E,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;gBAAC,MAAM,KAAK,CAAC;YAAC,CAAC;QAC3D,CAAC;QACD,IAAI,EAAE,KAAK,EAAC,QAAQ,EAAC,EAAE;YACrB,IAAI,CAAC,MAAM,IAAI,EAAE,KAAK,SAAS,IAAI,QAAQ,CAAC,GAAG,KAAK,MAAM,CAAC,GAAG,IAAI,QAAQ,CAAC,UAAU,KAAK,MAAM,CAAC,UAAU,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;gBACxI,MAAM,IAAI,mBAAmB,CAAC,wBAAwB,CAAC,YAAY,EAAE,EAAE,MAAM,EAAE,eAAe,EAAE,CAAC,CAAC;YACpG,CAAC;QACH,CAAC;QACD,KAAK,EAAE,KAAK,EAAC,MAAM,EAAC,EAAE;YACpB,IAAI,MAAM,EAAE,CAAC;gBAAC,UAAU,GAAG,IAAI,CAAC;gBAAC,OAAO,WAAW,CAAC;YAAC,CAAC;YACtD,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;YAAC,WAAW,GAAG,MAAM,CAAC,KAAK,KAAK,IAAI,CAAC;YAAC,OAAO,WAAW,CAAC;QACpG,CAAC;QACD,KAAK,EAAE,KAAK,IAAI,EAAE;YAChB,IAAI,UAAU;gBAAE,OAAO;YACvB,IAAI,CAAC;gBACH,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;gBAAC,WAAW,GAAG,MAAM,CAAC,KAAK,KAAK,IAAI,CAAC;gBAC3E,IAAI,CAAC,WAAW;oBAAE,MAAM,KAAK,CAAC,kBAAkB,CAAC,CAAC;gBAClD,MAAM,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;YAC3B,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,yCAAyC;gBACzC,IAAI,EAAE,KAAK,SAAS;oBAAE,MAAM,CAAC,MAAM,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;gBAC5C,MAAM,KAAK,CAAC;YACd,CAAC;QACH,CAAC;QACD,OAAO,EAAE,KAAK,IAAI,EAAE;YAClB,IAAI,EAAE,KAAK,SAAS,EAAE,CAAC;gBACrB,IAAI,CAAC;oBAAC,IAAI,CAAC,UAAU;wBAAE,MAAM,CAAC,MAAM,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC;gBAAC,CAAC;wBAAS,CAAC;oBAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;oBAAC,EAAE,GAAG,SAAS,CAAC;gBAAC,CAAC;YAC9F,CAAC;QACH,CAAC;KACF,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,YAA2B,EAAE,SAAiB;IACpF,MAAM,MAAM,GAAG,MAAM,oBAAoB,EAAE,CAAC;IAAC,MAAM,CAAC,SAAS,EAAE,CAAC;IAChE,MAAM,KAAK,GAAG,GAAG,EAAE;QACjB,IAAI,CAAC,YAAY,EAAE;YAAE,OAAO,KAAK,CAAC;QAClC,KAAK,IAAI,QAAQ,GAAG,CAAC,EAAE,QAAQ,GAAG,IAAI,EAAE,QAAQ,EAAE,EAAE,CAAC;YACnD,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,EAAE,CAAC;YAC7B,IAAI,MAAM,CAAC,GAAG,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,GAAG,CAAC,IAAI,MAAM,CAAC,KAAK,KAAK,CAAC,CAAC;gBAAE,SAAS;YACvE,IAAI,MAAM,CAAC,GAAG,KAAK,CAAC;gBAAE,OAAO,KAAK,CAAC;YACnC,IAAI,MAAM,CAAC,KAAK,KAAK,EAAE;gBAAE,OAAO,IAAI,CAAC;YACrC,MAAM,KAAK,CAAC,cAAc,CAAC,CAAC;QAC9B,CAAC;QACD,MAAM,KAAK,CAAC,YAAY,CAAC,CAAC;IAC5B,CAAC,CAAC;IACF,OAAO;QACL,KAAK;QACL,KAAK,CAAC,IAAI;YACR,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,CAAC;YACxC,GAAG,CAAC;gBACF,IAAI,KAAK,EAAE;oBAAE,OAAO,IAAI,CAAC;gBACzB,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,mBAAmB,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC;gBACvF,IAAI,IAAI,CAAC,MAAM,GAAG,MAAM;oBAAE,MAAM,KAAK,CAAC,gBAAgB,CAAC,CAAC;gBACxD,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;gBAC9D,IAAI,QAAQ,CAAC,MAAM,GAAG,IAAI,IAAI,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;oBAAE,MAAM,KAAK,CAAC,kBAAkB,CAAC,CAAC;gBAClH,KAAK,MAAM,KAAK,IAAI,QAAQ,EAAE,CAAC;oBAC7B,MAAM,GAAG,GAAG,MAAM,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;oBACrD,IAAI,MAAM,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC;wBAAC,IAAI,MAAM,CAAC,KAAK,KAAK,CAAC;4BAAE,SAAS;wBAAC,MAAM,KAAK,CAAC,aAAa,CAAC,CAAC;oBAAC,CAAC;oBACpF,IAAI,CAAC;wBACH,IAAI,MAAc,CAAC;wBACnB,IAAI,CAAC;4BAAC,MAAM,GAAG,MAAM,QAAQ,CAAC,SAAS,KAAK,SAAS,EAAE,MAAM,CAAC,CAAC;wBAAC,CAAC;wBACjE,OAAO,KAAK,EAAE,CAAC;4BAAC,IAAI,KAAK,YAAY,KAAK,IAAI,MAAM,IAAI,KAAK,IAAI,KAAK,CAAC,IAAI,KAAK,QAAQ;gCAAE,SAAS;4BAAC,MAAM,KAAK,CAAC;wBAAC,CAAC;wBAClH,IAAI,MAAM,CAAC,MAAM,GAAG,MAAM,IAAI,mBAAmB,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC;4BAAE,SAAS;wBACtG,MAAM,IAAI,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC;wBACzC,IAAI,CAAC,IAAI,CAAC,EAAE,IAAI,IAAI,CAAC,KAAK,KAAK,CAAC;4BAAE,MAAM,KAAK,CAAC,cAAc,CAAC,CAAC;oBAChE,CAAC;4BAAS,CAAC;wBAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;oBAAC,CAAC;gBACxC,CAAC;gBACD,MAAM,IAAI,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,UAAU,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,CAAC;YACtD,CAAC,QAAQ,IAAI,CAAC,GAAG,EAAE,GAAG,QAAQ,EAAE;YAChC,OAAO,KAAK,EAAE,CAAC;QACjB,CAAC;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/** 只有显式启用 scope 才加载原生依赖;缺失预编译制品不触发构建或降级。 */
|
|
2
|
+
export declare function loadOwnedNative(platform: 'win32' | 'linux', importer?: () => Promise<{
|
|
3
|
+
LibraryHandle: import("koffi").LibraryHandle;
|
|
4
|
+
TypeObject: import("koffi").TypeObject;
|
|
5
|
+
Union: import("koffi").Union;
|
|
6
|
+
address: typeof import("koffi").address;
|
|
7
|
+
alias: typeof import("koffi").alias;
|
|
8
|
+
alignof: typeof import("koffi").alignof;
|
|
9
|
+
alloc: typeof import("koffi").alloc;
|
|
10
|
+
array: typeof import("koffi").array;
|
|
11
|
+
as: typeof import("koffi").as;
|
|
12
|
+
call: typeof import("koffi").call;
|
|
13
|
+
config: typeof import("koffi").config;
|
|
14
|
+
decode: typeof import("koffi").decode;
|
|
15
|
+
disposable: typeof import("koffi").disposable;
|
|
16
|
+
encode: typeof import("koffi").encode;
|
|
17
|
+
enumeration: typeof import("koffi").enumeration;
|
|
18
|
+
errno: typeof import("koffi").errno;
|
|
19
|
+
extension: typeof import("koffi").extension;
|
|
20
|
+
free: typeof import("koffi").free;
|
|
21
|
+
inout: typeof import("koffi").inout;
|
|
22
|
+
introspect: typeof import("koffi").introspect;
|
|
23
|
+
load: typeof import("koffi").load;
|
|
24
|
+
node: typeof import("koffi").node;
|
|
25
|
+
offsetof: typeof import("koffi").offsetof;
|
|
26
|
+
opaque: typeof import("koffi").opaque;
|
|
27
|
+
os: typeof import("koffi").os;
|
|
28
|
+
out: typeof import("koffi").out;
|
|
29
|
+
pack: typeof import("koffi").pack;
|
|
30
|
+
pointer: typeof import("koffi").pointer;
|
|
31
|
+
proto: typeof import("koffi").proto;
|
|
32
|
+
register: typeof import("koffi").register;
|
|
33
|
+
reset: typeof import("koffi").reset;
|
|
34
|
+
resolve: typeof import("koffi").resolve;
|
|
35
|
+
sizeof: typeof import("koffi").sizeof;
|
|
36
|
+
stats: typeof import("koffi").stats;
|
|
37
|
+
struct: typeof import("koffi").struct;
|
|
38
|
+
type: typeof import("koffi").type;
|
|
39
|
+
types: typeof import("koffi").types;
|
|
40
|
+
union: typeof import("koffi").union;
|
|
41
|
+
unregister: typeof import("koffi").unregister;
|
|
42
|
+
version: typeof import("koffi").version;
|
|
43
|
+
view: typeof import("koffi").view;
|
|
44
|
+
}>): Promise<{
|
|
45
|
+
LibraryHandle: import("koffi").LibraryHandle;
|
|
46
|
+
TypeObject: import("koffi").TypeObject;
|
|
47
|
+
Union: import("koffi").Union;
|
|
48
|
+
address: typeof import("koffi").address;
|
|
49
|
+
alias: typeof import("koffi").alias;
|
|
50
|
+
alignof: typeof import("koffi").alignof;
|
|
51
|
+
alloc: typeof import("koffi").alloc;
|
|
52
|
+
array: typeof import("koffi").array;
|
|
53
|
+
as: typeof import("koffi").as;
|
|
54
|
+
call: typeof import("koffi").call;
|
|
55
|
+
config: typeof import("koffi").config;
|
|
56
|
+
decode: typeof import("koffi").decode;
|
|
57
|
+
disposable: typeof import("koffi").disposable;
|
|
58
|
+
encode: typeof import("koffi").encode;
|
|
59
|
+
enumeration: typeof import("koffi").enumeration;
|
|
60
|
+
errno: typeof import("koffi").errno;
|
|
61
|
+
extension: typeof import("koffi").extension;
|
|
62
|
+
free: typeof import("koffi").free;
|
|
63
|
+
inout: typeof import("koffi").inout;
|
|
64
|
+
introspect: typeof import("koffi").introspect;
|
|
65
|
+
load: typeof import("koffi").load;
|
|
66
|
+
node: typeof import("koffi").node;
|
|
67
|
+
offsetof: typeof import("koffi").offsetof;
|
|
68
|
+
opaque: typeof import("koffi").opaque;
|
|
69
|
+
os: typeof import("koffi").os;
|
|
70
|
+
out: typeof import("koffi").out;
|
|
71
|
+
pack: typeof import("koffi").pack;
|
|
72
|
+
pointer: typeof import("koffi").pointer;
|
|
73
|
+
proto: typeof import("koffi").proto;
|
|
74
|
+
register: typeof import("koffi").register;
|
|
75
|
+
reset: typeof import("koffi").reset;
|
|
76
|
+
resolve: typeof import("koffi").resolve;
|
|
77
|
+
sizeof: typeof import("koffi").sizeof;
|
|
78
|
+
stats: typeof import("koffi").stats;
|
|
79
|
+
struct: typeof import("koffi").struct;
|
|
80
|
+
type: typeof import("koffi").type;
|
|
81
|
+
types: typeof import("koffi").types;
|
|
82
|
+
union: typeof import("koffi").union;
|
|
83
|
+
unregister: typeof import("koffi").unregister;
|
|
84
|
+
version: typeof import("koffi").version;
|
|
85
|
+
view: typeof import("koffi").view;
|
|
86
|
+
}>;
|
|
87
|
+
//# sourceMappingURL=native-loader.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"native-loader.d.ts","sourceRoot":"","sources":["../../src/owned-scope/native-loader.ts"],"names":[],"mappings":"AAGA,4CAA4C;AAC5C,wBAAsB,eAAe,CAAC,QAAQ,EAAE,OAAO,GAAG,OAAO,EAAE,QAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GASzF"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { ProcessControlError, processControlErrorCodes } from '@openge/forge-process-control';
|
|
2
|
+
const importNative = async () => (await import('koffi')).default;
|
|
3
|
+
/** 只有显式启用 scope 才加载原生依赖;缺失预编译制品不触发构建或降级。 */
|
|
4
|
+
export async function loadOwnedNative(platform, importer = importNative) {
|
|
5
|
+
if (process.platform !== platform || process.arch !== 'x64')
|
|
6
|
+
throw new ProcessControlError(processControlErrorCodes.scopeUnsupported, { reason: 'HOST', platform, architecture: process.arch });
|
|
7
|
+
try {
|
|
8
|
+
const native = await importer();
|
|
9
|
+
if (native.version !== '3.3.3')
|
|
10
|
+
throw new Error('NATIVE_VERSION');
|
|
11
|
+
return native;
|
|
12
|
+
}
|
|
13
|
+
catch {
|
|
14
|
+
throw new ProcessControlError(processControlErrorCodes.scopeUnsupported, { reason: 'NATIVE_PREBUILD', platform });
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=native-loader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"native-loader.js","sourceRoot":"","sources":["../../src/owned-scope/native-loader.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,wBAAwB,EAAE,MAAM,+BAA+B,CAAC;AAE9F,MAAM,YAAY,GAAG,KAAK,IAAI,EAAE,CAAC,CAAC,MAAM,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC;AACjE,4CAA4C;AAC5C,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,QAA2B,EAAE,QAAQ,GAAG,YAAY;IACxF,IAAI,OAAO,CAAC,QAAQ,KAAK,QAAQ,IAAI,OAAO,CAAC,IAAI,KAAK,KAAK;QAAE,MAAM,IAAI,mBAAmB,CAAC,wBAAwB,CAAC,gBAAgB,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,YAAY,EAAE,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC;IAChM,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,QAAQ,EAAE,CAAC;QAChC,IAAI,MAAM,CAAC,OAAO,KAAK,OAAO;YAAE,MAAM,IAAI,KAAK,CAAC,gBAAgB,CAAC,CAAC;QAClE,OAAO,MAAM,CAAC;IAChB,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,mBAAmB,CAAC,wBAAwB,CAAC,gBAAgB,EAAE,EAAE,MAAM,EAAE,iBAAiB,EAAE,QAAQ,EAAE,CAAC,CAAC;IACpH,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { type OwnedProcessLaunchRequest } from '@openge/forge-process-control';
|
|
2
|
+
export declare const controlLimit = 65536, launchLimit = 1048576;
|
|
3
|
+
export declare function object(value: unknown): Record<string, unknown>;
|
|
4
|
+
export declare function validateLaunch(value: unknown): asserts value is OwnedProcessLaunchRequest;
|
|
5
|
+
export interface ScopeKey {
|
|
6
|
+
readonly scopeId: string;
|
|
7
|
+
readonly binding: string;
|
|
8
|
+
readonly nonce: string;
|
|
9
|
+
}
|
|
10
|
+
export interface ScopeFrame extends ScopeKey {
|
|
11
|
+
readonly version: 1;
|
|
12
|
+
readonly sequence: number;
|
|
13
|
+
readonly type: string;
|
|
14
|
+
readonly id?: number;
|
|
15
|
+
readonly payload?: unknown;
|
|
16
|
+
}
|
|
17
|
+
export declare function frame(key: ScopeKey, sequence: number, type: string, payload?: unknown, id?: number): ScopeFrame;
|
|
18
|
+
export declare function readFrame(value: unknown, key: ScopeKey, sequence: number): ScopeFrame;
|
|
19
|
+
export declare function supervisorEnvironment(environment: Readonly<Record<string, string | undefined>>): NodeJS.ProcessEnv;
|
|
20
|
+
//# sourceMappingURL=protocol.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"protocol.d.ts","sourceRoot":"","sources":["../../src/owned-scope/protocol.ts"],"names":[],"mappings":"AAAA,OAAO,EAAiD,KAAK,yBAAyB,EAAE,MAAM,+BAA+B,CAAC;AAE9H,eAAO,MAAM,YAAY,QAAS,EAAE,WAAW,UAAY,CAAC;AAC5D,wBAAgB,MAAM,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAE9D;AACD,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC,KAAK,IAAI,yBAAyB,CAUzF;AACD,MAAM,WAAW,QAAQ;IAAG,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;CAAE;AACxG,MAAM,WAAW,UAAW,SAAQ,QAAQ;IAAG,QAAQ,CAAC,OAAO,EAAE,CAAC,CAAC;IAAC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAA;CAAE;AACxK,wBAAgB,KAAK,CAAC,GAAG,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,EAAE,EAAE,CAAC,EAAE,MAAM,GAAG,UAAU,CAE/G;AACD,wBAAgB,SAAS,CAAC,KAAK,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,GAAG,UAAU,CAMrF;AACD,wBAAgB,qBAAqB,CAAC,WAAW,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC,GAAG,MAAM,CAAC,UAAU,CAElH"}
|