@secure-exec/typescript 0.0.0-nathan-release-0-3-0.2076211
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 +50 -0
- package/dist/index.d.ts +97 -0
- package/dist/index.js +314 -0
- package/package.json +36 -0
package/README.md
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# @secure-exec/typescript
|
|
2
|
+
|
|
3
|
+
Run the TypeScript compiler **inside the secure-exec sandbox**. The compiler is
|
|
4
|
+
projected into the VM and every compile and type-check happens in the guest, so
|
|
5
|
+
untrusted TypeScript never executes (or compiles) on the host.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```sh
|
|
10
|
+
npm install @secure-exec/typescript secure-exec
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Usage
|
|
14
|
+
|
|
15
|
+
```ts
|
|
16
|
+
import { createTypeScriptTools } from "@secure-exec/typescript";
|
|
17
|
+
|
|
18
|
+
const tools = createTypeScriptTools();
|
|
19
|
+
|
|
20
|
+
// Compile TypeScript to JavaScript inside the sandbox.
|
|
21
|
+
const compiled = await tools.compileSource({
|
|
22
|
+
sourceText: "const answer: number = 42;\nconsole.log(answer);",
|
|
23
|
+
compilerOptions: { module: "ESNext", target: "ES2022" },
|
|
24
|
+
});
|
|
25
|
+
console.log(compiled.outputText);
|
|
26
|
+
|
|
27
|
+
// Type-check inside the sandbox and get structured diagnostics back.
|
|
28
|
+
const checked = await tools.typecheckSource({
|
|
29
|
+
sourceText: `const total: number = "not a number";`,
|
|
30
|
+
});
|
|
31
|
+
console.log(checked.success, checked.diagnostics);
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## API
|
|
35
|
+
|
|
36
|
+
`createTypeScriptTools(options?)` returns:
|
|
37
|
+
|
|
38
|
+
- `compileSource({ sourceText, filePath?, cwd?, configFilePath?, compilerOptions? })`
|
|
39
|
+
-> `{ success, diagnostics, outputText, sourceMapText }`
|
|
40
|
+
- `typecheckSource({ sourceText, ... })` -> `{ success, diagnostics }`
|
|
41
|
+
- `compileProject({ cwd?, configFilePath? })`
|
|
42
|
+
-> `{ success, diagnostics, emitSkipped, emittedFiles }`
|
|
43
|
+
- `typecheckProject({ cwd?, configFilePath? })` -> `{ success, diagnostics }`
|
|
44
|
+
|
|
45
|
+
Each diagnostic is `{ code, category, message, filePath?, line?, column? }`.
|
|
46
|
+
|
|
47
|
+
Seed extra files into the VM with the `files` option, or project host
|
|
48
|
+
directories with the `mounts` option, to compile whole projects.
|
|
49
|
+
|
|
50
|
+
See the [documentation](https://secureexec.dev/docs) for details.
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @secure-exec/typescript — run the TypeScript compiler inside the sandbox.
|
|
3
|
+
*
|
|
4
|
+
* The TypeScript compiler (`typescript.js`) is projected into the VM's virtual
|
|
5
|
+
* filesystem and the compile/type-check program is executed in-guest through
|
|
6
|
+
* the `secure-exec` `NodeRuntime`. The compiler never runs on the host: every
|
|
7
|
+
* `createSourceFile`/`createProgram`/`emit` call happens inside the kernel
|
|
8
|
+
* isolation boundary, over the VM's filesystem.
|
|
9
|
+
*/
|
|
10
|
+
import type { HostDirectoryMount, NodeRuntimeCreateOptions } from "secure-exec";
|
|
11
|
+
/** VM permission policy, as accepted by `NodeRuntime.create`. */
|
|
12
|
+
export type Permissions = NonNullable<NodeRuntimeCreateOptions["permissions"]>;
|
|
13
|
+
/** A single TypeScript diagnostic, normalized for host consumption. */
|
|
14
|
+
export interface TypeScriptDiagnostic {
|
|
15
|
+
code: number;
|
|
16
|
+
category: "error" | "warning" | "suggestion" | "message";
|
|
17
|
+
message: string;
|
|
18
|
+
filePath?: string;
|
|
19
|
+
line?: number;
|
|
20
|
+
column?: number;
|
|
21
|
+
}
|
|
22
|
+
/** Result of a type-check (no emit). */
|
|
23
|
+
export interface TypeCheckResult {
|
|
24
|
+
success: boolean;
|
|
25
|
+
diagnostics: TypeScriptDiagnostic[];
|
|
26
|
+
}
|
|
27
|
+
/** Result of compiling a project (emit to the VM filesystem). */
|
|
28
|
+
export interface ProjectCompileResult extends TypeCheckResult {
|
|
29
|
+
emitSkipped: boolean;
|
|
30
|
+
emittedFiles: string[];
|
|
31
|
+
}
|
|
32
|
+
/** Result of compiling a single source string (emit returned in-memory). */
|
|
33
|
+
export interface SourceCompileResult extends TypeCheckResult {
|
|
34
|
+
outputText?: string;
|
|
35
|
+
sourceMapText?: string;
|
|
36
|
+
}
|
|
37
|
+
/** Options for the project-oriented tools. */
|
|
38
|
+
export interface ProjectCompilerOptions {
|
|
39
|
+
/** Working directory inside the VM. Defaults to `/root`. */
|
|
40
|
+
cwd?: string;
|
|
41
|
+
/** Explicit path to a `tsconfig.json` inside the VM. */
|
|
42
|
+
configFilePath?: string;
|
|
43
|
+
}
|
|
44
|
+
/** Options for the single-source tools. */
|
|
45
|
+
export interface SourceCompilerOptions {
|
|
46
|
+
/** TypeScript source text to compile or type-check. */
|
|
47
|
+
sourceText: string;
|
|
48
|
+
/** Virtual path the source should appear at. Defaults to a temp `.ts` file. */
|
|
49
|
+
filePath?: string;
|
|
50
|
+
/** Working directory inside the VM. Defaults to `/root`. */
|
|
51
|
+
cwd?: string;
|
|
52
|
+
/** Optional `tsconfig.json` whose `compilerOptions` are applied. */
|
|
53
|
+
configFilePath?: string;
|
|
54
|
+
/** Inline compiler options (esbuild/tsc JSON spelling). */
|
|
55
|
+
compilerOptions?: Record<string, unknown>;
|
|
56
|
+
}
|
|
57
|
+
/** Options for {@link createTypeScriptTools}. */
|
|
58
|
+
export interface TypeScriptToolsOptions {
|
|
59
|
+
/**
|
|
60
|
+
* Host directory of the `typescript` npm package to project into the VM.
|
|
61
|
+
* Defaults to the `typescript` package resolved from this package. The
|
|
62
|
+
* directory is mounted (read lazily) into the VM; the compiler never runs
|
|
63
|
+
* on the host.
|
|
64
|
+
*/
|
|
65
|
+
compilerPackageDir?: string;
|
|
66
|
+
/**
|
|
67
|
+
* Guest path the `typescript` package is mounted at. Defaults to
|
|
68
|
+
* `/root/node_modules/typescript` so it resolves as the `typescript`
|
|
69
|
+
* package inside the VM.
|
|
70
|
+
*/
|
|
71
|
+
compilerGuestDir?: string;
|
|
72
|
+
/** Extra files to seed into the VM (e.g. a `tsconfig.json` or sources). */
|
|
73
|
+
files?: Record<string, string | Uint8Array>;
|
|
74
|
+
/** Extra host directories to project into the VM, Docker-style. */
|
|
75
|
+
mounts?: HostDirectoryMount[];
|
|
76
|
+
/** Permission policy forwarded to the VM. */
|
|
77
|
+
permissions?: Permissions;
|
|
78
|
+
/** Environment variables visible to the guest compiler. */
|
|
79
|
+
env?: Record<string, string>;
|
|
80
|
+
}
|
|
81
|
+
/** The in-sandbox TypeScript tools returned by {@link createTypeScriptTools}. */
|
|
82
|
+
export interface TypeScriptTools {
|
|
83
|
+
/** Type-check a `tsconfig.json` project inside the VM. */
|
|
84
|
+
typecheckProject(options?: ProjectCompilerOptions): Promise<TypeCheckResult>;
|
|
85
|
+
/** Compile a `tsconfig.json` project, emitting into the VM filesystem. */
|
|
86
|
+
compileProject(options?: ProjectCompilerOptions): Promise<ProjectCompileResult>;
|
|
87
|
+
/** Type-check a single TypeScript source string inside the VM. */
|
|
88
|
+
typecheckSource(options: SourceCompilerOptions): Promise<TypeCheckResult>;
|
|
89
|
+
/** Compile a single TypeScript source string, returning the emitted JS. */
|
|
90
|
+
compileSource(options: SourceCompilerOptions): Promise<SourceCompileResult>;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Create a set of TypeScript tools whose compiler runs entirely inside the
|
|
94
|
+
* secure-exec sandbox. The compiler bundle is read from the host and projected
|
|
95
|
+
* into the VM filesystem; all compilation happens in-guest.
|
|
96
|
+
*/
|
|
97
|
+
export declare function createTypeScriptTools(options?: TypeScriptToolsOptions): TypeScriptTools;
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,314 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @secure-exec/typescript — run the TypeScript compiler inside the sandbox.
|
|
3
|
+
*
|
|
4
|
+
* The TypeScript compiler (`typescript.js`) is projected into the VM's virtual
|
|
5
|
+
* filesystem and the compile/type-check program is executed in-guest through
|
|
6
|
+
* the `secure-exec` `NodeRuntime`. The compiler never runs on the host: every
|
|
7
|
+
* `createSourceFile`/`createProgram`/`emit` call happens inside the kernel
|
|
8
|
+
* isolation boundary, over the VM's filesystem.
|
|
9
|
+
*/
|
|
10
|
+
import { createRequire } from "node:module";
|
|
11
|
+
import { dirname } from "node:path";
|
|
12
|
+
import { NodeRuntime } from "secure-exec";
|
|
13
|
+
const DEFAULT_COMPILER_GUEST_DIR = "/root/node_modules/typescript";
|
|
14
|
+
function resolveCompilerPackageDir(explicit) {
|
|
15
|
+
if (explicit) {
|
|
16
|
+
return explicit;
|
|
17
|
+
}
|
|
18
|
+
const require = createRequire(import.meta.url);
|
|
19
|
+
// `lib/typescript.js` is the full compiler bundle; its grandparent is the
|
|
20
|
+
// `typescript` package directory (containing package.json + lib/).
|
|
21
|
+
return dirname(dirname(require.resolve("typescript/lib/typescript.js")));
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Create a set of TypeScript tools whose compiler runs entirely inside the
|
|
25
|
+
* secure-exec sandbox. The compiler bundle is read from the host and projected
|
|
26
|
+
* into the VM filesystem; all compilation happens in-guest.
|
|
27
|
+
*/
|
|
28
|
+
export function createTypeScriptTools(options = {}) {
|
|
29
|
+
const compilerPackageDir = resolveCompilerPackageDir(options.compilerPackageDir);
|
|
30
|
+
const compilerGuestDir = options.compilerGuestDir ?? DEFAULT_COMPILER_GUEST_DIR;
|
|
31
|
+
const compilerGuestPath = `${compilerGuestDir}/lib/typescript.js`;
|
|
32
|
+
const compilerMount = {
|
|
33
|
+
guestPath: compilerGuestDir,
|
|
34
|
+
hostPath: compilerPackageDir,
|
|
35
|
+
readOnly: true,
|
|
36
|
+
};
|
|
37
|
+
const run = (request) => runCompilerRequest(request, compilerGuestPath, options, compilerMount);
|
|
38
|
+
return {
|
|
39
|
+
typecheckProject: (requestOptions = {}) => run({
|
|
40
|
+
kind: "typecheckProject",
|
|
41
|
+
options: requestOptions,
|
|
42
|
+
}),
|
|
43
|
+
compileProject: (requestOptions = {}) => run({
|
|
44
|
+
kind: "compileProject",
|
|
45
|
+
options: requestOptions,
|
|
46
|
+
}),
|
|
47
|
+
typecheckSource: (requestOptions) => run({ kind: "typecheckSource", options: requestOptions }),
|
|
48
|
+
compileSource: (requestOptions) => run({
|
|
49
|
+
kind: "compileSource",
|
|
50
|
+
options: requestOptions,
|
|
51
|
+
}),
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
async function runCompilerRequest(request, compilerGuestPath, toolsOptions, compilerMount) {
|
|
55
|
+
const createOptions = {
|
|
56
|
+
files: toolsOptions.files,
|
|
57
|
+
mounts: [compilerMount, ...(toolsOptions.mounts ?? [])],
|
|
58
|
+
permissions: toolsOptions.permissions,
|
|
59
|
+
env: toolsOptions.env,
|
|
60
|
+
};
|
|
61
|
+
const rt = await NodeRuntime.create(createOptions);
|
|
62
|
+
try {
|
|
63
|
+
const guestSource = buildCompilerGuestSource(request, compilerGuestPath);
|
|
64
|
+
const result = await rt.run(guestSource);
|
|
65
|
+
if (result.exitCode === 0 && result.value !== undefined) {
|
|
66
|
+
return result.value;
|
|
67
|
+
}
|
|
68
|
+
return createFailureResult(request.kind, result.stderr.trim() || `compiler exited with code ${result.exitCode}`);
|
|
69
|
+
}
|
|
70
|
+
catch (error) {
|
|
71
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
72
|
+
return createFailureResult(request.kind, message);
|
|
73
|
+
}
|
|
74
|
+
finally {
|
|
75
|
+
await rt.dispose();
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
function createFailureResult(kind, errorMessage) {
|
|
79
|
+
const diagnostic = {
|
|
80
|
+
code: 0,
|
|
81
|
+
category: "error",
|
|
82
|
+
message: errorMessage || "TypeScript compiler failed",
|
|
83
|
+
};
|
|
84
|
+
if (kind === "compileProject") {
|
|
85
|
+
return {
|
|
86
|
+
success: false,
|
|
87
|
+
diagnostics: [diagnostic],
|
|
88
|
+
emitSkipped: true,
|
|
89
|
+
emittedFiles: [],
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
return { success: false, diagnostics: [diagnostic] };
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Build the guest ES module that loads the projected compiler and runs the
|
|
96
|
+
* requested compile/type-check entirely inside the VM, then hands the result
|
|
97
|
+
* back to the host via `__return`.
|
|
98
|
+
*/
|
|
99
|
+
function buildCompilerGuestSource(request, compilerGuestPath) {
|
|
100
|
+
return [
|
|
101
|
+
`import { createRequire } from "node:module";`,
|
|
102
|
+
`import fs from "node:fs";`,
|
|
103
|
+
`import path from "node:path";`,
|
|
104
|
+
`const require = createRequire(${JSON.stringify(compilerGuestPath)});`,
|
|
105
|
+
`const ts = require(${JSON.stringify(compilerGuestPath)});`,
|
|
106
|
+
`const request = ${JSON.stringify(request)};`,
|
|
107
|
+
`const result = (${compilerGuestMain.toString()})(ts, fs, path, request);`,
|
|
108
|
+
`globalThis.__return(result);`,
|
|
109
|
+
].join("\n");
|
|
110
|
+
}
|
|
111
|
+
// NOTE: This function is serialized with `.toString()` and executed INSIDE the
|
|
112
|
+
// VM. It must be self-contained: it may only reference its parameters and the
|
|
113
|
+
// in-guest globals. Do not capture host-side variables.
|
|
114
|
+
function compilerGuestMain(ts, fs, path, request) {
|
|
115
|
+
function toDiagnostic(diagnostic) {
|
|
116
|
+
const message = ts
|
|
117
|
+
.flattenDiagnosticMessageText(diagnostic.messageText, "\n")
|
|
118
|
+
.trim();
|
|
119
|
+
const result = {
|
|
120
|
+
code: diagnostic.code,
|
|
121
|
+
category: toDiagnosticCategory(diagnostic.category),
|
|
122
|
+
message,
|
|
123
|
+
};
|
|
124
|
+
if (!diagnostic.file || diagnostic.start === undefined) {
|
|
125
|
+
return result;
|
|
126
|
+
}
|
|
127
|
+
const { line, character } = diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start);
|
|
128
|
+
result.filePath = diagnostic.file.fileName.replace(/\\/g, "/");
|
|
129
|
+
result.line = line + 1;
|
|
130
|
+
result.column = character + 1;
|
|
131
|
+
return result;
|
|
132
|
+
}
|
|
133
|
+
function toDiagnosticCategory(category) {
|
|
134
|
+
switch (category) {
|
|
135
|
+
case ts.DiagnosticCategory.Warning:
|
|
136
|
+
return "warning";
|
|
137
|
+
case ts.DiagnosticCategory.Suggestion:
|
|
138
|
+
return "suggestion";
|
|
139
|
+
case ts.DiagnosticCategory.Message:
|
|
140
|
+
return "message";
|
|
141
|
+
default:
|
|
142
|
+
return "error";
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
function hasErrors(diagnostics) {
|
|
146
|
+
return diagnostics.some((diagnostic) => diagnostic.category === "error");
|
|
147
|
+
}
|
|
148
|
+
function convertCompilerOptions(compilerOptions, basePath) {
|
|
149
|
+
if (!compilerOptions) {
|
|
150
|
+
return {};
|
|
151
|
+
}
|
|
152
|
+
const converted = ts.convertCompilerOptionsFromJson(compilerOptions, basePath);
|
|
153
|
+
if (converted.errors.length > 0) {
|
|
154
|
+
throw new Error(converted.errors
|
|
155
|
+
.map((diagnostic) => toDiagnostic(diagnostic).message)
|
|
156
|
+
.join("\n"));
|
|
157
|
+
}
|
|
158
|
+
return converted.options;
|
|
159
|
+
}
|
|
160
|
+
function resolveProjectConfig(options, overrideCompilerOptions = {}) {
|
|
161
|
+
const cwd = path.resolve(options.cwd ?? "/root");
|
|
162
|
+
const configFilePath = options.configFilePath
|
|
163
|
+
? path.resolve(cwd, options.configFilePath)
|
|
164
|
+
: ts.findConfigFile(cwd, ts.sys.fileExists, "tsconfig.json");
|
|
165
|
+
if (!configFilePath) {
|
|
166
|
+
throw new Error(`Unable to find tsconfig.json from '${cwd}'`);
|
|
167
|
+
}
|
|
168
|
+
const configFile = ts.readConfigFile(configFilePath, ts.sys.readFile);
|
|
169
|
+
if (configFile.error) {
|
|
170
|
+
return { parsed: null, diagnostics: [toDiagnostic(configFile.error)] };
|
|
171
|
+
}
|
|
172
|
+
const parsed = ts.parseJsonConfigFileContent(configFile.config, ts.sys, path.dirname(configFilePath), overrideCompilerOptions, configFilePath);
|
|
173
|
+
return { parsed, diagnostics: parsed.errors.map(toDiagnostic) };
|
|
174
|
+
}
|
|
175
|
+
function createSourceProgram(options, overrideCompilerOptions = {}) {
|
|
176
|
+
const cwd = path.resolve(options.cwd ?? "/root");
|
|
177
|
+
const filePath = path.resolve(cwd, options.filePath ?? "__secure_exec_typescript_input__.ts");
|
|
178
|
+
const projectCompilerOptions = options.configFilePath
|
|
179
|
+
? resolveProjectConfig({ cwd, configFilePath: options.configFilePath }, overrideCompilerOptions)
|
|
180
|
+
: { parsed: null, diagnostics: [] };
|
|
181
|
+
if (projectCompilerOptions.diagnostics.length > 0) {
|
|
182
|
+
return {
|
|
183
|
+
filePath,
|
|
184
|
+
program: null,
|
|
185
|
+
diagnostics: projectCompilerOptions.diagnostics,
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
const compilerOptions = {
|
|
189
|
+
target: ts.ScriptTarget.ES2022,
|
|
190
|
+
module: ts.ModuleKind.ESNext,
|
|
191
|
+
...projectCompilerOptions.parsed?.options,
|
|
192
|
+
...convertCompilerOptions(options.compilerOptions, cwd),
|
|
193
|
+
...overrideCompilerOptions,
|
|
194
|
+
};
|
|
195
|
+
const host = ts.createCompilerHost(compilerOptions);
|
|
196
|
+
const normalize = (candidate) => ts.sys.useCaseSensitiveFileNames ? candidate : candidate.toLowerCase();
|
|
197
|
+
const normalizedFilePath = normalize(filePath);
|
|
198
|
+
const defaultGetSourceFile = host.getSourceFile.bind(host);
|
|
199
|
+
const defaultReadFile = host.readFile.bind(host);
|
|
200
|
+
const defaultFileExists = host.fileExists.bind(host);
|
|
201
|
+
host.fileExists = (candidate) => normalize(candidate) === normalizedFilePath ||
|
|
202
|
+
defaultFileExists(candidate);
|
|
203
|
+
host.readFile = (candidate) => normalize(candidate) === normalizedFilePath
|
|
204
|
+
? options.sourceText
|
|
205
|
+
: defaultReadFile(candidate);
|
|
206
|
+
host.getSourceFile = (candidate, languageVersion, onError, shouldCreate) => normalize(candidate) === normalizedFilePath
|
|
207
|
+
? ts.createSourceFile(candidate, options.sourceText, languageVersion, true)
|
|
208
|
+
: defaultGetSourceFile(candidate, languageVersion, onError, shouldCreate);
|
|
209
|
+
return {
|
|
210
|
+
filePath,
|
|
211
|
+
program: ts.createProgram([filePath], compilerOptions, host),
|
|
212
|
+
diagnostics: [],
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
switch (request.kind) {
|
|
216
|
+
case "typecheckProject": {
|
|
217
|
+
const { parsed, diagnostics } = resolveProjectConfig(request.options, {
|
|
218
|
+
noEmit: true,
|
|
219
|
+
});
|
|
220
|
+
if (!parsed) {
|
|
221
|
+
return { success: false, diagnostics };
|
|
222
|
+
}
|
|
223
|
+
const program = ts.createProgram({
|
|
224
|
+
rootNames: parsed.fileNames,
|
|
225
|
+
options: parsed.options,
|
|
226
|
+
projectReferences: parsed.projectReferences,
|
|
227
|
+
});
|
|
228
|
+
const combined = ts
|
|
229
|
+
.sortAndDeduplicateDiagnostics([
|
|
230
|
+
...parsed.errors,
|
|
231
|
+
...ts.getPreEmitDiagnostics(program),
|
|
232
|
+
])
|
|
233
|
+
.map(toDiagnostic);
|
|
234
|
+
return { success: !hasErrors(combined), diagnostics: combined };
|
|
235
|
+
}
|
|
236
|
+
case "compileProject": {
|
|
237
|
+
const { parsed, diagnostics } = resolveProjectConfig(request.options);
|
|
238
|
+
if (!parsed) {
|
|
239
|
+
return {
|
|
240
|
+
success: false,
|
|
241
|
+
diagnostics,
|
|
242
|
+
emitSkipped: true,
|
|
243
|
+
emittedFiles: [],
|
|
244
|
+
};
|
|
245
|
+
}
|
|
246
|
+
const program = ts.createProgram({
|
|
247
|
+
rootNames: parsed.fileNames,
|
|
248
|
+
options: parsed.options,
|
|
249
|
+
projectReferences: parsed.projectReferences,
|
|
250
|
+
});
|
|
251
|
+
const emittedFiles = [];
|
|
252
|
+
const emitResult = program.emit(undefined, (fileName, text) => {
|
|
253
|
+
fs.mkdirSync(path.dirname(fileName), { recursive: true });
|
|
254
|
+
fs.writeFileSync(fileName, text, "utf8");
|
|
255
|
+
emittedFiles.push(fileName.replace(/\\/g, "/"));
|
|
256
|
+
});
|
|
257
|
+
const combined = ts
|
|
258
|
+
.sortAndDeduplicateDiagnostics([
|
|
259
|
+
...parsed.errors,
|
|
260
|
+
...ts.getPreEmitDiagnostics(program),
|
|
261
|
+
...emitResult.diagnostics,
|
|
262
|
+
])
|
|
263
|
+
.map(toDiagnostic);
|
|
264
|
+
return {
|
|
265
|
+
success: !hasErrors(combined),
|
|
266
|
+
diagnostics: combined,
|
|
267
|
+
emitSkipped: emitResult.emitSkipped,
|
|
268
|
+
emittedFiles,
|
|
269
|
+
};
|
|
270
|
+
}
|
|
271
|
+
case "typecheckSource": {
|
|
272
|
+
const { program, diagnostics } = createSourceProgram(request.options, {
|
|
273
|
+
noEmit: true,
|
|
274
|
+
});
|
|
275
|
+
if (!program) {
|
|
276
|
+
return { success: false, diagnostics };
|
|
277
|
+
}
|
|
278
|
+
const combined = ts
|
|
279
|
+
.sortAndDeduplicateDiagnostics(ts.getPreEmitDiagnostics(program))
|
|
280
|
+
.map(toDiagnostic);
|
|
281
|
+
return { success: !hasErrors(combined), diagnostics: combined };
|
|
282
|
+
}
|
|
283
|
+
case "compileSource": {
|
|
284
|
+
const { program, diagnostics } = createSourceProgram(request.options);
|
|
285
|
+
if (!program) {
|
|
286
|
+
return { success: false, diagnostics };
|
|
287
|
+
}
|
|
288
|
+
let outputText;
|
|
289
|
+
let sourceMapText;
|
|
290
|
+
const emitResult = program.emit(undefined, (fileName, text) => {
|
|
291
|
+
if (fileName.endsWith(".js") ||
|
|
292
|
+
fileName.endsWith(".mjs") ||
|
|
293
|
+
fileName.endsWith(".cjs")) {
|
|
294
|
+
outputText = text;
|
|
295
|
+
}
|
|
296
|
+
else if (fileName.endsWith(".map")) {
|
|
297
|
+
sourceMapText = text;
|
|
298
|
+
}
|
|
299
|
+
});
|
|
300
|
+
const combined = ts
|
|
301
|
+
.sortAndDeduplicateDiagnostics([
|
|
302
|
+
...ts.getPreEmitDiagnostics(program),
|
|
303
|
+
...emitResult.diagnostics,
|
|
304
|
+
])
|
|
305
|
+
.map(toDiagnostic);
|
|
306
|
+
return {
|
|
307
|
+
success: !hasErrors(combined),
|
|
308
|
+
diagnostics: combined,
|
|
309
|
+
outputText,
|
|
310
|
+
sourceMapText,
|
|
311
|
+
};
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@secure-exec/typescript",
|
|
3
|
+
"version": "0.0.0-nathan-release-0-3-0.2076211",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"license": "Apache-2.0",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"files": [
|
|
9
|
+
"dist",
|
|
10
|
+
"README.md"
|
|
11
|
+
],
|
|
12
|
+
"repository": {
|
|
13
|
+
"type": "git",
|
|
14
|
+
"url": "https://github.com/rivet-dev/secure-exec.git",
|
|
15
|
+
"directory": "packages/typescript"
|
|
16
|
+
},
|
|
17
|
+
"exports": {
|
|
18
|
+
".": {
|
|
19
|
+
"types": "./dist/index.d.ts",
|
|
20
|
+
"import": "./dist/index.js",
|
|
21
|
+
"default": "./dist/index.js"
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
"scripts": {
|
|
25
|
+
"build": "tsc",
|
|
26
|
+
"check-types": "tsc --noEmit"
|
|
27
|
+
},
|
|
28
|
+
"dependencies": {
|
|
29
|
+
"@secure-exec/core": "0.0.0-nathan-release-0-3-0.2076211",
|
|
30
|
+
"secure-exec": "0.0.0-nathan-release-0-3-0.2076211",
|
|
31
|
+
"typescript": "^5.9.3"
|
|
32
|
+
},
|
|
33
|
+
"devDependencies": {
|
|
34
|
+
"@types/node": "^22.10.2"
|
|
35
|
+
}
|
|
36
|
+
}
|