@ttsc/playground 0.22.0 → 0.24.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 +7 -0
- package/lib/src/compiler/internal/createWorkerCompilerService.d.ts +1 -1
- package/lib/src/compiler/internal/createWorkerCompilerService.js +44 -12
- package/lib/src/compiler/internal/createWorkerCompilerService.js.map +1 -1
- package/lib/src/compiler/loadTypiaSourcePack.d.ts +6 -4
- package/lib/src/compiler/loadTypiaSourcePack.js +101 -13
- package/lib/src/compiler/loadTypiaSourcePack.js.map +1 -1
- package/lib/src/compiler/normalizeError.js +11 -2
- package/lib/src/compiler/normalizeError.js.map +1 -1
- package/lib/src/index.d.ts +2 -2
- package/lib/src/index.js +3 -1
- package/lib/src/index.js.map +1 -1
- package/lib/src/react/PlaygroundShell.js +188 -106
- package/lib/src/react/PlaygroundShell.js.map +1 -1
- package/lib/src/react/internal/PlaygroundCompilerLifecycle.d.ts +39 -0
- package/lib/src/react/internal/PlaygroundCompilerLifecycle.js +79 -0
- package/lib/src/react/internal/PlaygroundCompilerLifecycle.js.map +1 -0
- package/lib/src/react/internal/PlaygroundExecutionLifecycle.d.ts +26 -0
- package/lib/src/react/internal/PlaygroundExecutionLifecycle.js +49 -0
- package/lib/src/react/internal/PlaygroundExecutionLifecycle.js.map +1 -0
- package/lib/src/react/internal/recoverTerminalCompilerWorker.d.ts +15 -0
- package/lib/src/react/internal/recoverTerminalCompilerWorker.js +35 -0
- package/lib/src/react/internal/recoverTerminalCompilerWorker.js.map +1 -0
- package/lib/src/sandbox/loadTypiaRuntimePack.d.ts +8 -5
- package/lib/src/sandbox/loadTypiaRuntimePack.js +98 -23
- package/lib/src/sandbox/loadTypiaRuntimePack.js.map +1 -1
- package/lib/src/structures/IInstallTypiaSourcePackOptions.d.ts +5 -1
- package/lib/src/structures/ILoadTypiaRuntimePackOptions.d.ts +7 -0
- package/lib/src/structures/ILoadTypiaRuntimePackOptions.js +3 -0
- package/lib/src/structures/ILoadTypiaRuntimePackOptions.js.map +1 -0
- package/lib/src/structures/IPlaygroundShellProps.d.ts +7 -0
- package/lib/src/structures/index.d.ts +1 -0
- package/lib/src/structures/index.js +1 -0
- package/lib/src/structures/index.js.map +1 -1
- package/package.json +3 -3
- package/src/compiler/internal/createWorkerCompilerService.ts +43 -17
- package/src/compiler/loadTypiaSourcePack.ts +155 -13
- package/src/compiler/normalizeError.ts +15 -2
- package/src/index.ts +8 -2
- package/src/react/PlaygroundShell.tsx +307 -193
- package/src/react/internal/PlaygroundCompilerLifecycle.ts +95 -0
- package/src/react/internal/PlaygroundExecutionLifecycle.ts +55 -0
- package/src/react/internal/recoverTerminalCompilerWorker.ts +41 -0
- package/src/sandbox/loadTypiaRuntimePack.ts +155 -19
- package/src/structures/IInstallTypiaSourcePackOptions.ts +5 -1
- package/src/structures/ILoadTypiaRuntimePackOptions.ts +7 -0
- package/src/structures/IPlaygroundShellProps.ts +7 -0
- package/src/structures/index.ts +1 -0
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
export interface IPlaygroundCompilerGeneration {
|
|
2
|
+
/** Whether this token still owns the active compiler Worker generation. */
|
|
3
|
+
isCurrent(): boolean;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Serializes dependency mutations and fences every asynchronous consumer of a
|
|
8
|
+
* compiler Worker generation.
|
|
9
|
+
*
|
|
10
|
+
* Invalidating a generation immediately makes its active task advisory-only and
|
|
11
|
+
* prevents its queued tasks from starting. New-generation tasks remain
|
|
12
|
+
* serialized behind an active old task so two dependency installers can never
|
|
13
|
+
* mutate the shared compiler filesystem concurrently.
|
|
14
|
+
*/
|
|
15
|
+
export class PlaygroundCompilerLifecycle {
|
|
16
|
+
private epoch: number = 0;
|
|
17
|
+
private queue: Promise<void> = Promise.resolve();
|
|
18
|
+
|
|
19
|
+
public capture(): IPlaygroundCompilerGeneration {
|
|
20
|
+
const epoch = this.epoch;
|
|
21
|
+
return {
|
|
22
|
+
isCurrent: () => this.epoch === epoch,
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
public invalidate(): IPlaygroundCompilerGeneration {
|
|
27
|
+
this.epoch++;
|
|
28
|
+
return this.capture();
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
public invalidateIfCurrent(
|
|
32
|
+
generation: IPlaygroundCompilerGeneration,
|
|
33
|
+
): IPlaygroundCompilerGeneration | undefined {
|
|
34
|
+
if (!generation.isCurrent()) return undefined;
|
|
35
|
+
return this.invalidate();
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Reset a Worker owned by `generation`, then clear its dependency metadata.
|
|
40
|
+
*
|
|
41
|
+
* The clear deliberately happens before a caller checks any independent
|
|
42
|
+
* source version. A source edit during reset still leaves an empty Worker, so
|
|
43
|
+
* its metadata must become empty too. A Worker-generation replacement
|
|
44
|
+
* performs its own synchronous clear and prevents this stale reset from
|
|
45
|
+
* clearing the replacement.
|
|
46
|
+
*/
|
|
47
|
+
public async resetWorkerIfCurrent(
|
|
48
|
+
generation: IPlaygroundCompilerGeneration,
|
|
49
|
+
reset: () => Promise<void>,
|
|
50
|
+
clear: () => void,
|
|
51
|
+
): Promise<boolean> {
|
|
52
|
+
if (!generation.isCurrent()) return false;
|
|
53
|
+
await reset();
|
|
54
|
+
if (!generation.isCurrent()) return false;
|
|
55
|
+
clear();
|
|
56
|
+
return true;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Run a Worker mutation and reconcile a source edit that lands during it.
|
|
61
|
+
*
|
|
62
|
+
* An RPC cannot be cancelled after it has started mutating the Worker's
|
|
63
|
+
* MemFS. If its source becomes stale before completion, reset that Worker and
|
|
64
|
+
* clear the matching dependency metadata before another source can reuse it.
|
|
65
|
+
*/
|
|
66
|
+
public async mutateWorkerIfCurrent(
|
|
67
|
+
generation: IPlaygroundCompilerGeneration,
|
|
68
|
+
isSourceCurrent: () => boolean,
|
|
69
|
+
mutate: () => Promise<unknown>,
|
|
70
|
+
reset: () => Promise<void>,
|
|
71
|
+
clear: () => void,
|
|
72
|
+
): Promise<boolean> {
|
|
73
|
+
if (!generation.isCurrent() || !isSourceCurrent()) return false;
|
|
74
|
+
await mutate();
|
|
75
|
+
if (!generation.isCurrent()) return false;
|
|
76
|
+
if (isSourceCurrent()) return true;
|
|
77
|
+
await this.resetWorkerIfCurrent(generation, reset, clear);
|
|
78
|
+
return false;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
public enqueue<T>(
|
|
82
|
+
task: (generation: IPlaygroundCompilerGeneration) => Promise<T>,
|
|
83
|
+
): Promise<T | undefined> {
|
|
84
|
+
const generation = this.capture();
|
|
85
|
+
const result = this.queue.then(async () => {
|
|
86
|
+
if (!generation.isCurrent()) return undefined;
|
|
87
|
+
return task(generation);
|
|
88
|
+
});
|
|
89
|
+
this.queue = result.then(
|
|
90
|
+
() => undefined,
|
|
91
|
+
() => undefined,
|
|
92
|
+
);
|
|
93
|
+
return result;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
export interface IPlaygroundExecutionAttempt {
|
|
2
|
+
/** Signal passed through every cancellable step owned by this attempt. */
|
|
3
|
+
readonly signal: AbortSignal;
|
|
4
|
+
/** Whether this attempt may still commit messages or state. */
|
|
5
|
+
isCurrent(): boolean;
|
|
6
|
+
/** Release the active slot if this is still the current attempt. */
|
|
7
|
+
finish(): boolean;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Owns the cancellation and stale-write boundary for Execute attempts.
|
|
12
|
+
*
|
|
13
|
+
* React state stays in `PlaygroundShell`; this small state machine keeps the
|
|
14
|
+
* supersession rules independently testable and makes every invalidation path
|
|
15
|
+
* use the same abort behavior.
|
|
16
|
+
*/
|
|
17
|
+
export class PlaygroundExecutionLifecycle {
|
|
18
|
+
private active: AbortController | null = null;
|
|
19
|
+
private epoch = 0;
|
|
20
|
+
|
|
21
|
+
public begin(): IPlaygroundExecutionAttempt {
|
|
22
|
+
this.invalidate("a newer Execute started");
|
|
23
|
+
const controller = new AbortController();
|
|
24
|
+
const epoch = this.epoch;
|
|
25
|
+
this.active = controller;
|
|
26
|
+
return {
|
|
27
|
+
signal: controller.signal,
|
|
28
|
+
isCurrent: () => this.epoch === epoch && this.active === controller,
|
|
29
|
+
finish: () => {
|
|
30
|
+
if (this.epoch !== epoch || this.active !== controller) return false;
|
|
31
|
+
this.active = null;
|
|
32
|
+
return true;
|
|
33
|
+
},
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Abort the active attempt and make its callbacks stale.
|
|
39
|
+
*
|
|
40
|
+
* Returns whether an active attempt was canceled.
|
|
41
|
+
*/
|
|
42
|
+
public invalidate(reason: string): boolean {
|
|
43
|
+
const active = this.active;
|
|
44
|
+
this.active = null;
|
|
45
|
+
++this.epoch;
|
|
46
|
+
active?.abort(createExecutionAbortError(reason));
|
|
47
|
+
return active !== null;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function createExecutionAbortError(reason: string): Error {
|
|
52
|
+
const error = new Error(`Playground execution aborted: ${reason}.`);
|
|
53
|
+
error.name = "AbortError";
|
|
54
|
+
return error;
|
|
55
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { BootTtscWorkerTerminationError } from "@ttsc/wasm";
|
|
2
|
+
|
|
3
|
+
export interface ITerminalCompilerWorkerRecovery {
|
|
4
|
+
/** Atomically claim and fence the failed Worker generation. */
|
|
5
|
+
claim(): boolean;
|
|
6
|
+
/** Close and clear that Worker generation. */
|
|
7
|
+
reset(): Promise<void>;
|
|
8
|
+
/** Publish the terminal error after the old Worker is no longer reachable. */
|
|
9
|
+
fail(error: unknown): void;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Replace a compiler Worker after its Go runtime started but boot never became
|
|
14
|
+
* usable. Returns false for ordinary compile, transport, and plugin failures.
|
|
15
|
+
*/
|
|
16
|
+
export async function recoverTerminalCompilerWorker(
|
|
17
|
+
error: unknown,
|
|
18
|
+
recovery: ITerminalCompilerWorkerRecovery,
|
|
19
|
+
): Promise<boolean> {
|
|
20
|
+
if (!requiresCompilerWorkerReplacement(error)) return false;
|
|
21
|
+
if (!recovery.claim()) return true;
|
|
22
|
+
try {
|
|
23
|
+
await recovery.reset();
|
|
24
|
+
} finally {
|
|
25
|
+
recovery.fail(error);
|
|
26
|
+
}
|
|
27
|
+
return true;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/** Recognize both local errors and their plain tgrid/JSON transport shape. */
|
|
31
|
+
export function requiresCompilerWorkerReplacement(error: unknown): boolean {
|
|
32
|
+
const code = BootTtscWorkerTerminationError.CODE;
|
|
33
|
+
const prefix = `[${code}] `;
|
|
34
|
+
if (typeof error === "string") return error.startsWith(prefix);
|
|
35
|
+
if (!error || typeof error !== "object") return false;
|
|
36
|
+
const record = error as { code?: unknown; message?: unknown };
|
|
37
|
+
return (
|
|
38
|
+
record.code === code ||
|
|
39
|
+
(typeof record.message === "string" && record.message.startsWith(prefix))
|
|
40
|
+
);
|
|
41
|
+
}
|
|
@@ -2,35 +2,171 @@
|
|
|
2
2
|
//
|
|
3
3
|
// The pack JSON itself is built by the site (e.g. `pack-typia-runtime.cjs`
|
|
4
4
|
// in the ttsc website) and served at a site-chosen URL. It mirrors the
|
|
5
|
-
// layout the typia transform's emit references
|
|
6
|
-
// `@typia/utils/lib/*`, etc.
|
|
7
|
-
// resolves to the matching pack entry.
|
|
5
|
+
// layout the typia transform's emit references -- `typia/lib/internal/*`,
|
|
6
|
+
// `@typia/utils/lib/*`, etc. -- so a bundle's
|
|
7
|
+
// `require("typia/lib/internal/X")` resolves to the matching pack entry.
|
|
8
|
+
import type { ILoadTypiaRuntimePackOptions } from "../structures/ILoadTypiaRuntimePackOptions";
|
|
8
9
|
|
|
9
|
-
|
|
10
|
+
interface RuntimePackEntry {
|
|
11
|
+
controller: AbortController;
|
|
12
|
+
promise: Promise<Record<string, string>>;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
interface RuntimePackCancellationReason {
|
|
16
|
+
kind: "abort" | "timeout";
|
|
17
|
+
reason?: unknown;
|
|
18
|
+
timeoutMs?: number;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
interface RuntimePackCancellation {
|
|
22
|
+
promise: Promise<never>;
|
|
23
|
+
dispose: () => void;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export const DEFAULT_RUNTIME_PACK_TIMEOUT_MS = 30_000;
|
|
27
|
+
|
|
28
|
+
const packCache = new Map<string, RuntimePackEntry>();
|
|
10
29
|
|
|
11
30
|
/**
|
|
12
|
-
* Fetches the prebuilt runtime pack once per URL.
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
31
|
+
* Fetches the prebuilt runtime pack once per URL.
|
|
32
|
+
*
|
|
33
|
+
* Concurrent callers share one load. A caller abort or deadline cancels that
|
|
34
|
+
* shared attempt; rejection removes it from the cache so the next call retries
|
|
35
|
+
* from scratch. Successful packs remain cached.
|
|
16
36
|
*/
|
|
17
|
-
export
|
|
37
|
+
export function loadTypiaRuntimePack(
|
|
18
38
|
url: string,
|
|
39
|
+
options: ILoadTypiaRuntimePackOptions = {},
|
|
19
40
|
): Promise<Record<string, string>> {
|
|
41
|
+
const timeoutMs = resolveRuntimePackTimeout(options.timeoutMs);
|
|
20
42
|
const cached = packCache.get(url);
|
|
21
|
-
if (cached)
|
|
43
|
+
if (cached) {
|
|
44
|
+
attachRuntimePackCancellation(cached, options.signal, timeoutMs);
|
|
45
|
+
return cached.promise;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const controller = new AbortController();
|
|
49
|
+
let phase = `fetching ${url}`;
|
|
50
|
+
const cancellation = createRuntimePackCancellation(
|
|
51
|
+
controller.signal,
|
|
52
|
+
() => phase,
|
|
53
|
+
);
|
|
54
|
+
let entry!: RuntimePackEntry;
|
|
22
55
|
const promise = (async () => {
|
|
23
|
-
const response = await
|
|
24
|
-
|
|
56
|
+
const response = await raceRuntimePackCancellation(
|
|
57
|
+
fetch(url, { signal: controller.signal }),
|
|
58
|
+
cancellation.promise,
|
|
59
|
+
controller.signal,
|
|
60
|
+
() => phase,
|
|
61
|
+
);
|
|
62
|
+
if (!response.ok)
|
|
25
63
|
throw new Error(
|
|
26
64
|
`loadTypiaRuntimePack: failed to fetch ${url}: ${response.status}`,
|
|
27
65
|
);
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
66
|
+
|
|
67
|
+
phase = `reading JSON from ${url}`;
|
|
68
|
+
return (await raceRuntimePackCancellation(
|
|
69
|
+
response.json(),
|
|
70
|
+
cancellation.promise,
|
|
71
|
+
controller.signal,
|
|
72
|
+
() => phase,
|
|
73
|
+
)) as Record<string, string>;
|
|
74
|
+
})()
|
|
75
|
+
.catch((error) => {
|
|
76
|
+
if (packCache.get(url) === entry) packCache.delete(url);
|
|
77
|
+
throw error;
|
|
78
|
+
})
|
|
79
|
+
.finally(cancellation.dispose);
|
|
80
|
+
|
|
81
|
+
entry = { controller, promise };
|
|
82
|
+
packCache.set(url, entry);
|
|
83
|
+
attachRuntimePackCancellation(entry, options.signal, timeoutMs);
|
|
35
84
|
return promise;
|
|
36
85
|
}
|
|
86
|
+
|
|
87
|
+
function resolveRuntimePackTimeout(timeoutMs: number | undefined): number {
|
|
88
|
+
const value = timeoutMs ?? DEFAULT_RUNTIME_PACK_TIMEOUT_MS;
|
|
89
|
+
if (!Number.isSafeInteger(value) || value <= 0 || value > 2_147_483_647)
|
|
90
|
+
throw new RangeError(
|
|
91
|
+
"loadTypiaRuntimePack: timeoutMs must be a positive integer no greater than 2147483647.",
|
|
92
|
+
);
|
|
93
|
+
return value;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function attachRuntimePackCancellation(
|
|
97
|
+
entry: RuntimePackEntry,
|
|
98
|
+
callerSignal: AbortSignal | undefined,
|
|
99
|
+
timeoutMs: number,
|
|
100
|
+
): void {
|
|
101
|
+
const abortFromCaller = (): void => {
|
|
102
|
+
if (!entry.controller.signal.aborted)
|
|
103
|
+
entry.controller.abort({
|
|
104
|
+
kind: "abort",
|
|
105
|
+
reason: callerSignal?.reason,
|
|
106
|
+
} satisfies RuntimePackCancellationReason);
|
|
107
|
+
};
|
|
108
|
+
if (callerSignal?.aborted) abortFromCaller();
|
|
109
|
+
else callerSignal?.addEventListener("abort", abortFromCaller, { once: true });
|
|
110
|
+
|
|
111
|
+
const timer = setTimeout(() => {
|
|
112
|
+
if (!entry.controller.signal.aborted)
|
|
113
|
+
entry.controller.abort({
|
|
114
|
+
kind: "timeout",
|
|
115
|
+
timeoutMs,
|
|
116
|
+
} satisfies RuntimePackCancellationReason);
|
|
117
|
+
}, timeoutMs);
|
|
118
|
+
const cleanup = (): void => {
|
|
119
|
+
clearTimeout(timer);
|
|
120
|
+
callerSignal?.removeEventListener("abort", abortFromCaller);
|
|
121
|
+
};
|
|
122
|
+
void entry.promise.then(cleanup, cleanup);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function createRuntimePackCancellation(
|
|
126
|
+
signal: AbortSignal,
|
|
127
|
+
getPhase: () => string,
|
|
128
|
+
): RuntimePackCancellation {
|
|
129
|
+
let rejectCancellation!: (error: Error) => void;
|
|
130
|
+
const promise = new Promise<never>((_resolve, reject) => {
|
|
131
|
+
rejectCancellation = reject;
|
|
132
|
+
});
|
|
133
|
+
const onAbort = (): void => {
|
|
134
|
+
rejectCancellation(runtimePackCancellationError(signal, getPhase()));
|
|
135
|
+
};
|
|
136
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
137
|
+
if (signal.aborted) onAbort();
|
|
138
|
+
return {
|
|
139
|
+
promise,
|
|
140
|
+
dispose: () => signal.removeEventListener("abort", onAbort),
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
async function raceRuntimePackCancellation<T>(
|
|
145
|
+
work: Promise<T>,
|
|
146
|
+
cancellation: Promise<never>,
|
|
147
|
+
signal: AbortSignal,
|
|
148
|
+
getPhase: () => string,
|
|
149
|
+
): Promise<T> {
|
|
150
|
+
try {
|
|
151
|
+
return await Promise.race([work, cancellation]);
|
|
152
|
+
} catch (error) {
|
|
153
|
+
if (signal.aborted) throw runtimePackCancellationError(signal, getPhase());
|
|
154
|
+
throw error;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
function runtimePackCancellationError(
|
|
159
|
+
signal: AbortSignal,
|
|
160
|
+
phase: string,
|
|
161
|
+
): Error {
|
|
162
|
+
const reason = signal.reason as RuntimePackCancellationReason | undefined;
|
|
163
|
+
if (reason?.kind === "timeout")
|
|
164
|
+
return new Error(
|
|
165
|
+
`loadTypiaRuntimePack: timed out after ${reason.timeoutMs}ms while ${phase}.`,
|
|
166
|
+
);
|
|
167
|
+
|
|
168
|
+
const error = new Error(`loadTypiaRuntimePack: aborted while ${phase}.`);
|
|
169
|
+
const cause = reason?.kind === "abort" ? reason.reason : signal.reason;
|
|
170
|
+
if (cause !== undefined) (error as Error & { cause?: unknown }).cause = cause;
|
|
171
|
+
return error;
|
|
172
|
+
}
|
|
@@ -10,9 +10,13 @@ export interface IInstallTypiaSourcePackOptions {
|
|
|
10
10
|
* matching `DEFAULT_WORK_DIR + "/node_modules"`.
|
|
11
11
|
*/
|
|
12
12
|
mountRoot?: string;
|
|
13
|
+
/** Cancel the shared in-flight load. */
|
|
14
|
+
signal?: AbortSignal;
|
|
15
|
+
/** Maximum fetch and JSON-read time. Defaults to 30 seconds. */
|
|
16
|
+
timeoutMs?: number;
|
|
13
17
|
/**
|
|
14
18
|
* Optional fetcher. Defaults to `globalThis.fetch`. Override for tests or for
|
|
15
19
|
* sites that want their own caching strategy.
|
|
16
20
|
*/
|
|
17
|
-
fetch?: (input: string) => Promise<Response>;
|
|
21
|
+
fetch?: (input: string, init?: RequestInit) => Promise<Response>;
|
|
18
22
|
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/** Cancellation and deadline policy for `loadTypiaRuntimePack`. */
|
|
2
|
+
export interface ILoadTypiaRuntimePackOptions {
|
|
3
|
+
/** Cancel the shared in-flight load. */
|
|
4
|
+
signal?: AbortSignal;
|
|
5
|
+
/** Maximum fetch and JSON-read time. Defaults to 30 seconds. */
|
|
6
|
+
timeoutMs?: number;
|
|
7
|
+
}
|
|
@@ -58,6 +58,12 @@ export interface IPlaygroundShellProps {
|
|
|
58
58
|
* union to `createSandboxRequire` — without this channel the in-page Execute
|
|
59
59
|
* sandbox cannot resolve any npm dependency the user installed.
|
|
60
60
|
*
|
|
61
|
+
* `sandbox.signal` aborts when source or compiler options change, a newer
|
|
62
|
+
* Execute starts, or the shell unmounts. Implementations must pass it through
|
|
63
|
+
* to cancellable setup such as runtime-pack fetches. Synchronous evaluated
|
|
64
|
+
* user code cannot be preempted and still requires an isolated executor when
|
|
65
|
+
* untrusted code is accepted.
|
|
66
|
+
*
|
|
61
67
|
* When omitted, the Execute UI is hidden.
|
|
62
68
|
*/
|
|
63
69
|
executeBundle?: (
|
|
@@ -65,6 +71,7 @@ export interface IPlaygroundShellProps {
|
|
|
65
71
|
sandbox: {
|
|
66
72
|
console: Record<string, (...args: unknown[]) => void>;
|
|
67
73
|
runtimeFiles: Record<string, string>;
|
|
74
|
+
signal: AbortSignal;
|
|
68
75
|
},
|
|
69
76
|
) => Promise<void>;
|
|
70
77
|
|
package/src/structures/index.ts
CHANGED
|
@@ -4,6 +4,7 @@ export * from "./IConsoleMessage";
|
|
|
4
4
|
export * from "./ICreateCompilerClientOptions";
|
|
5
5
|
export * from "./ICreateWorkerCompilerOptions";
|
|
6
6
|
export * from "./IInstallTypiaSourcePackOptions";
|
|
7
|
+
export * from "./ILoadTypiaRuntimePackOptions";
|
|
7
8
|
export * from "./ILintPluginConfig";
|
|
8
9
|
export * from "./IOptionToggle";
|
|
9
10
|
export * from "./IPlaygroundDependencyInstallOptions";
|