@caryhu/codemine-forge 0.0.1-alpha.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.
Files changed (84) hide show
  1. package/README.md +108 -0
  2. package/dist/build-pipeline/browser-bundle.d.ts +31 -0
  3. package/dist/build-pipeline/browser-bundle.js +584 -0
  4. package/dist/build-pipeline/diagnostics.d.ts +7 -0
  5. package/dist/build-pipeline/diagnostics.js +68 -0
  6. package/dist/build-pipeline/index.d.ts +3 -0
  7. package/dist/build-pipeline/index.js +16 -0
  8. package/dist/build-pipeline/pipeline.d.ts +12 -0
  9. package/dist/build-pipeline/pipeline.js +273 -0
  10. package/dist/build-pipeline/types.d.ts +77 -0
  11. package/dist/build-pipeline/types.js +4 -0
  12. package/dist/dev-server-preview/diagnostics.d.ts +5 -0
  13. package/dist/dev-server-preview/diagnostics.js +40 -0
  14. package/dist/dev-server-preview/index.d.ts +4 -0
  15. package/dist/dev-server-preview/index.js +16 -0
  16. package/dist/dev-server-preview/preview-document.d.ts +2 -0
  17. package/dist/dev-server-preview/preview-document.js +153 -0
  18. package/dist/dev-server-preview/server.d.ts +26 -0
  19. package/dist/dev-server-preview/server.js +279 -0
  20. package/dist/dev-server-preview/types.d.ts +105 -0
  21. package/dist/dev-server-preview/types.js +4 -0
  22. package/dist/esbuild-wasm-worker/diagnostics.d.ts +12 -0
  23. package/dist/esbuild-wasm-worker/diagnostics.js +53 -0
  24. package/dist/esbuild-wasm-worker/index.d.ts +4 -0
  25. package/dist/esbuild-wasm-worker/index.js +18 -0
  26. package/dist/esbuild-wasm-worker/service.d.ts +26 -0
  27. package/dist/esbuild-wasm-worker/service.js +260 -0
  28. package/dist/esbuild-wasm-worker/types.d.ts +139 -0
  29. package/dist/esbuild-wasm-worker/types.js +5 -0
  30. package/dist/esbuild-wasm-worker/worker-adapter.d.ts +38 -0
  31. package/dist/esbuild-wasm-worker/worker-adapter.js +165 -0
  32. package/dist/esbuild-wasm-worker/worker.d.ts +1 -0
  33. package/dist/esbuild-wasm-worker/worker.js +4 -0
  34. package/dist/forge-controller.d.ts +38 -0
  35. package/dist/forge-controller.js +79 -0
  36. package/dist/index.d.ts +7 -0
  37. package/dist/index.js +88 -0
  38. package/dist/package-resolution/cdn-source.d.ts +11 -0
  39. package/dist/package-resolution/cdn-source.js +164 -0
  40. package/dist/package-resolution/diagnostics.d.ts +15 -0
  41. package/dist/package-resolution/diagnostics.js +51 -0
  42. package/dist/package-resolution/errors.d.ts +5 -0
  43. package/dist/package-resolution/errors.js +11 -0
  44. package/dist/package-resolution/index.d.ts +6 -0
  45. package/dist/package-resolution/index.js +23 -0
  46. package/dist/package-resolution/manifest.d.ts +5 -0
  47. package/dist/package-resolution/manifest.js +128 -0
  48. package/dist/package-resolution/resolver.d.ts +17 -0
  49. package/dist/package-resolution/resolver.js +172 -0
  50. package/dist/package-resolution/types.d.ts +98 -0
  51. package/dist/package-resolution/types.js +4 -0
  52. package/dist/terminal-commands/diagnostics.d.ts +3 -0
  53. package/dist/terminal-commands/diagnostics.js +21 -0
  54. package/dist/terminal-commands/index.d.ts +7 -0
  55. package/dist/terminal-commands/index.js +22 -0
  56. package/dist/terminal-commands/npm-build.d.ts +7 -0
  57. package/dist/terminal-commands/npm-build.js +63 -0
  58. package/dist/terminal-commands/npm-dev.d.ts +7 -0
  59. package/dist/terminal-commands/npm-dev.js +68 -0
  60. package/dist/terminal-commands/npm-install.d.ts +8 -0
  61. package/dist/terminal-commands/npm-install.js +56 -0
  62. package/dist/terminal-commands/parser.d.ts +2 -0
  63. package/dist/terminal-commands/parser.js +52 -0
  64. package/dist/terminal-commands/terminal.d.ts +12 -0
  65. package/dist/terminal-commands/terminal.js +73 -0
  66. package/dist/terminal-commands/types.d.ts +65 -0
  67. package/dist/terminal-commands/types.js +4 -0
  68. package/dist/virtual-file-system/diagnostics.d.ts +14 -0
  69. package/dist/virtual-file-system/diagnostics.js +55 -0
  70. package/dist/virtual-file-system/errors.d.ts +5 -0
  71. package/dist/virtual-file-system/errors.js +11 -0
  72. package/dist/virtual-file-system/index.d.ts +26 -0
  73. package/dist/virtual-file-system/index.js +47 -0
  74. package/dist/virtual-file-system/limits.d.ts +4 -0
  75. package/dist/virtual-file-system/limits.js +33 -0
  76. package/dist/virtual-file-system/memory.d.ts +33 -0
  77. package/dist/virtual-file-system/memory.js +551 -0
  78. package/dist/virtual-file-system/path.d.ts +9 -0
  79. package/dist/virtual-file-system/path.js +47 -0
  80. package/dist/virtual-file-system/storage.d.ts +32 -0
  81. package/dist/virtual-file-system/storage.js +194 -0
  82. package/dist/virtual-file-system/types.d.ts +165 -0
  83. package/dist/virtual-file-system/types.js +2 -0
  84. package/package.json +43 -0
@@ -0,0 +1,12 @@
1
+ import { type ForgeBuildPipeline, type ForgeBuildPipelineOptions, type ForgeBuildRequest, type ForgeBuildResult } from "./types";
2
+ export declare class DefaultBuildPipeline implements ForgeBuildPipeline {
3
+ private readonly options;
4
+ readonly capability: "build-pipeline";
5
+ private readonly now;
6
+ constructor(options: ForgeBuildPipelineOptions);
7
+ build(request?: ForgeBuildRequest): Promise<ForgeBuildResult>;
8
+ private resolveEntry;
9
+ private failure;
10
+ }
11
+ export declare function createBuildPipeline(options: ForgeBuildPipelineOptions): ForgeBuildPipeline;
12
+ export declare function isSupportedViteBuildScript(script: string): boolean;
@@ -0,0 +1,273 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.isSupportedViteBuildScript = exports.createBuildPipeline = exports.DefaultBuildPipeline = void 0;
4
+ const package_resolution_1 = require("../package-resolution");
5
+ const virtual_file_system_1 = require("../virtual-file-system");
6
+ const diagnostics_1 = require("./diagnostics");
7
+ const browser_bundle_1 = require("./browser-bundle");
8
+ const types_1 = require("./types");
9
+ const BUILD_MANIFEST_PATH = "/.forge/build/build-manifest.json";
10
+ const VITE_CONFIG_PATHS = [
11
+ "/vite.config.js",
12
+ "/vite.config.mjs",
13
+ "/vite.config.ts",
14
+ ];
15
+ const DEFAULT_ENTRY_CANDIDATES = [
16
+ "/src/main.tsx",
17
+ "/src/main.jsx",
18
+ "/src/main.ts",
19
+ "/src/main.js",
20
+ ];
21
+ class DefaultBuildPipeline {
22
+ constructor(options) {
23
+ this.options = options;
24
+ this.capability = types_1.BUILD_PIPELINE_CAPABILITY;
25
+ this.now = options.now ?? (() => new Date().toISOString());
26
+ }
27
+ async build(request = {}) {
28
+ const timingStart = createTimingStart(this.now());
29
+ const mode = "production";
30
+ const warningDiagnostics = await detectViteConfigDiagnostics(this.options.fileSystem);
31
+ let manifest;
32
+ try {
33
+ manifest = await (0, package_resolution_1.readPackageManifest)(this.options.fileSystem);
34
+ }
35
+ catch (error) {
36
+ if (error instanceof package_resolution_1.ForgePackageResolutionError) {
37
+ return this.failure(mode, [error.diagnostic, ...warningDiagnostics], timingStart);
38
+ }
39
+ throw error;
40
+ }
41
+ const buildScript = manifest.scripts.build;
42
+ if (buildScript === undefined) {
43
+ return this.failure(mode, [(0, diagnostics_1.createMissingBuildScriptDiagnostic)(), ...warningDiagnostics], timingStart);
44
+ }
45
+ if (!isSupportedViteBuildScript(buildScript)) {
46
+ return this.failure(mode, [
47
+ (0, diagnostics_1.createUnsupportedBuildScriptDiagnostic)(buildScript),
48
+ ...warningDiagnostics,
49
+ ], timingStart);
50
+ }
51
+ const entry = await this.resolveEntry(request.entry);
52
+ if (entry === undefined) {
53
+ return this.failure(mode, [(0, diagnostics_1.createMissingEntryDiagnostic)(), ...warningDiagnostics], timingStart);
54
+ }
55
+ try {
56
+ const packageResolution = await this.options.packageResolver.resolve();
57
+ const sourceFiles = await collectSourceFiles(this.options.fileSystem);
58
+ const browserBundleResult = await (0, browser_bundle_1.createBrowserBundle)({
59
+ entry,
60
+ fileSystem: this.options.fileSystem,
61
+ packageResolution,
62
+ scriptTransformer: createEsbuildWorkerScriptTransformer(this.options.esbuildWorker),
63
+ });
64
+ if (browserBundleResult.diagnostics.length > 0) {
65
+ return this.failure(mode, [...browserBundleResult.diagnostics, ...warningDiagnostics], timingStart);
66
+ }
67
+ const buildManifest = createBuildManifest(entry, mode, sourceFiles, packageResolution, browserBundleResult.browserBundle);
68
+ const outputFiles = [
69
+ createBuildManifestOutput(buildManifest),
70
+ ...browserBundleResult.outputFiles,
71
+ ];
72
+ await writeBuildOutputFiles(this.options.fileSystem, outputFiles);
73
+ return {
74
+ success: true,
75
+ mode,
76
+ entry,
77
+ browserBundle: browserBundleResult.browserBundle,
78
+ manifest: buildManifest,
79
+ outputFiles,
80
+ diagnostics: warningDiagnostics,
81
+ packageResolution,
82
+ timing: completeTiming(timingStart, this.now()),
83
+ };
84
+ }
85
+ catch (error) {
86
+ if (error instanceof package_resolution_1.ForgePackageResolutionError) {
87
+ return this.failure(mode, [error.diagnostic, ...warningDiagnostics], timingStart);
88
+ }
89
+ throw error;
90
+ }
91
+ }
92
+ async resolveEntry(requestedEntry) {
93
+ if (requestedEntry !== undefined) {
94
+ const normalized = (0, virtual_file_system_1.normalizeForgePath)(requestedEntry);
95
+ return normalized.ok &&
96
+ (await this.options.fileSystem.exists(normalized.path))
97
+ ? normalized.path
98
+ : undefined;
99
+ }
100
+ const htmlEntry = await findHtmlModuleEntry(this.options.fileSystem);
101
+ if (htmlEntry !== undefined) {
102
+ return htmlEntry;
103
+ }
104
+ for (const candidate of DEFAULT_ENTRY_CANDIDATES) {
105
+ if (await this.options.fileSystem.exists(candidate)) {
106
+ return candidate;
107
+ }
108
+ }
109
+ return undefined;
110
+ }
111
+ failure(mode, diagnostics, timingStart) {
112
+ return {
113
+ success: false,
114
+ mode,
115
+ outputFiles: [],
116
+ diagnostics,
117
+ timing: completeTiming(timingStart, this.now()),
118
+ };
119
+ }
120
+ }
121
+ exports.DefaultBuildPipeline = DefaultBuildPipeline;
122
+ function createEsbuildWorkerScriptTransformer(esbuildWorker) {
123
+ if (esbuildWorker === undefined) {
124
+ return undefined;
125
+ }
126
+ let initialized = false;
127
+ return async ({ loader, sourcePath, sourceText }) => {
128
+ if (!initialized) {
129
+ const initializeResult = await esbuildWorker.initialize();
130
+ if (!initializeResult.success) {
131
+ return {
132
+ success: false,
133
+ diagnostics: [
134
+ (0, diagnostics_1.createEsbuildWorkerTransformDiagnostic)(sourcePath, initializeResult.diagnostics[0] ?? initializeResult.diagnostics),
135
+ ],
136
+ };
137
+ }
138
+ initialized = true;
139
+ }
140
+ const transformResult = await esbuildWorker.transform({
141
+ loader,
142
+ sourcePath,
143
+ sourceText,
144
+ target: "es2020",
145
+ });
146
+ if (!transformResult.success) {
147
+ return {
148
+ success: false,
149
+ diagnostics: [
150
+ (0, diagnostics_1.createEsbuildWorkerTransformDiagnostic)(sourcePath, transformResult.diagnostics[0] ?? transformResult.diagnostics),
151
+ ],
152
+ };
153
+ }
154
+ return {
155
+ success: true,
156
+ outputText: transformResult.outputText,
157
+ diagnostics: [],
158
+ };
159
+ };
160
+ }
161
+ async function detectViteConfigDiagnostics(fileSystem) {
162
+ const diagnostics = [];
163
+ for (const path of VITE_CONFIG_PATHS) {
164
+ if (await fileSystem.exists(path)) {
165
+ diagnostics.push((0, diagnostics_1.createViteConfigNotExecutedDiagnostic)(path));
166
+ }
167
+ }
168
+ return diagnostics;
169
+ }
170
+ function createBuildPipeline(options) {
171
+ return new DefaultBuildPipeline(options);
172
+ }
173
+ exports.createBuildPipeline = createBuildPipeline;
174
+ function isSupportedViteBuildScript(script) {
175
+ const argv = script.trim().split(/\s+/);
176
+ return argv.length >= 2 && argv[0] === "vite" && argv[1] === "build";
177
+ }
178
+ exports.isSupportedViteBuildScript = isSupportedViteBuildScript;
179
+ async function findHtmlModuleEntry(fileSystem) {
180
+ if (!(await fileSystem.exists("/index.html"))) {
181
+ return undefined;
182
+ }
183
+ const html = await fileSystem.readText("/index.html");
184
+ const scriptTags = html.match(/<script\b[^>]*>/gi) ?? [];
185
+ for (const scriptTag of scriptTags) {
186
+ if (!/\btype\s*=\s*["']module["']/i.test(scriptTag)) {
187
+ continue;
188
+ }
189
+ const sourceMatch = scriptTag.match(/\bsrc\s*=\s*["']([^"']+)["']/i);
190
+ if (sourceMatch === null) {
191
+ continue;
192
+ }
193
+ const normalized = (0, virtual_file_system_1.normalizeForgePath)(sourceMatch[1]);
194
+ if (normalized.ok && (await fileSystem.exists(normalized.path))) {
195
+ return normalized.path;
196
+ }
197
+ }
198
+ return undefined;
199
+ }
200
+ async function collectSourceFiles(fileSystem, path = "/") {
201
+ if (path === "/.forge" || path.startsWith("/.forge/")) {
202
+ return [];
203
+ }
204
+ const entries = await fileSystem.readdir(path);
205
+ const files = [];
206
+ for (const entry of entries) {
207
+ if (entry.kind === "directory") {
208
+ files.push(...(await collectSourceFiles(fileSystem, entry.path)));
209
+ continue;
210
+ }
211
+ files.push(entry.path);
212
+ }
213
+ return files.sort((left, right) => left.localeCompare(right));
214
+ }
215
+ function createBuildManifest(entry, mode, sourceFiles, packageResolution, browserBundle) {
216
+ return {
217
+ entry,
218
+ mode,
219
+ sourceFiles,
220
+ packageNames: packageResolution.packages.map((record) => record.name),
221
+ packageResolutionMode: packageResolution.lock.resolutionMode,
222
+ browserBundle: browserBundle === undefined
223
+ ? undefined
224
+ : {
225
+ entryOutputPath: browserBundle.entryOutputPath,
226
+ format: browserBundle.format,
227
+ importMapPath: browserBundle.importMapPath,
228
+ moduleCount: browserBundle.moduleCount,
229
+ outputPaths: browserBundle.outputPaths,
230
+ },
231
+ };
232
+ }
233
+ function createBuildManifestOutput(manifest) {
234
+ const content = `${JSON.stringify(manifest, null, 2)}\n`;
235
+ return {
236
+ path: BUILD_MANIFEST_PATH,
237
+ content,
238
+ contentType: "application/json",
239
+ size: new TextEncoder().encode(content).byteLength,
240
+ };
241
+ }
242
+ async function writeBuildOutputFiles(fileSystem, outputFiles) {
243
+ for (const outputFile of outputFiles) {
244
+ await ensureDirectory(fileSystem, dirname(outputFile.path));
245
+ await fileSystem.writeFile(outputFile.path, outputFile.content, {
246
+ contentType: outputFile.contentType,
247
+ source: "generated",
248
+ });
249
+ }
250
+ }
251
+ async function ensureDirectory(fileSystem, path) {
252
+ await fileSystem.mkdir(path, {
253
+ recursive: true,
254
+ source: "generated",
255
+ });
256
+ }
257
+ function dirname(path) {
258
+ const index = path.lastIndexOf("/");
259
+ return index <= 0 ? "/" : path.slice(0, index);
260
+ }
261
+ function createTimingStart(startedAt) {
262
+ return {
263
+ startedAt,
264
+ startedMs: Date.now(),
265
+ };
266
+ }
267
+ function completeTiming(start, endedAt) {
268
+ return {
269
+ startedAt: start.startedAt,
270
+ endedAt,
271
+ durationMs: Math.max(0, Date.now() - start.startedMs),
272
+ };
273
+ }
@@ -0,0 +1,77 @@
1
+ import type { ForgeImportMap, ForgePackageDiagnostic, ForgePackageResolutionResult, ForgePackageResolver } from "../package-resolution";
2
+ import type { ForgeEsbuildWasmWorkerDiagnostic, ForgeEsbuildWasmWorkerService } from "../esbuild-wasm-worker";
3
+ import type { ForgeVirtualFileSystem } from "../virtual-file-system";
4
+ export declare const BUILD_PIPELINE_CAPABILITY: "build-pipeline";
5
+ export type ForgeBuildMode = "production";
6
+ export type ForgeBuildPipelineDiagnosticCode = "esbuild_worker_transform_failed" | "missing_build_script" | "missing_entry" | "unresolved_import" | "unsupported_build_script" | "vite_config_not_executed";
7
+ export interface ForgeBuildPipelineDiagnostic {
8
+ readonly code: ForgeBuildPipelineDiagnosticCode;
9
+ readonly severity: "error" | "warning";
10
+ readonly message: string;
11
+ readonly path?: string;
12
+ readonly script?: string;
13
+ readonly importSpecifier?: string;
14
+ readonly importer?: string;
15
+ readonly cause?: unknown;
16
+ readonly workerDiagnostic?: ForgeEsbuildWasmWorkerDiagnostic;
17
+ }
18
+ export type ForgeBuildDiagnostic = ForgeBuildPipelineDiagnostic | ForgePackageDiagnostic;
19
+ export interface ForgeBuildOutputFile {
20
+ readonly path: string;
21
+ readonly content: string;
22
+ readonly contentType: string;
23
+ readonly size: number;
24
+ }
25
+ export interface ForgeBuildManifest {
26
+ readonly entry: string;
27
+ readonly mode: ForgeBuildMode;
28
+ readonly sourceFiles: readonly string[];
29
+ readonly packageNames: readonly string[];
30
+ readonly packageResolutionMode: string;
31
+ readonly browserBundle?: ForgeBrowserBundleManifest;
32
+ }
33
+ export interface ForgeBrowserBundleManifest {
34
+ readonly entryOutputPath: string;
35
+ readonly format: "esm";
36
+ readonly importMapPath: string;
37
+ readonly moduleCount: number;
38
+ readonly outputPaths: readonly string[];
39
+ }
40
+ export interface ForgeBrowserBundle {
41
+ readonly entry: string;
42
+ readonly entryOutputPath: string;
43
+ readonly format: "esm";
44
+ readonly importMap: ForgeImportMap;
45
+ readonly importMapPath: string;
46
+ readonly moduleCount: number;
47
+ readonly outputPaths: readonly string[];
48
+ }
49
+ export interface ForgeBuildTiming {
50
+ readonly startedAt: string;
51
+ readonly endedAt: string;
52
+ readonly durationMs: number;
53
+ }
54
+ export interface ForgeBuildResult {
55
+ readonly success: boolean;
56
+ readonly mode: ForgeBuildMode;
57
+ readonly entry?: string;
58
+ readonly browserBundle?: ForgeBrowserBundle;
59
+ readonly manifest?: ForgeBuildManifest;
60
+ readonly outputFiles: readonly ForgeBuildOutputFile[];
61
+ readonly diagnostics: readonly ForgeBuildDiagnostic[];
62
+ readonly packageResolution?: ForgePackageResolutionResult;
63
+ readonly timing: ForgeBuildTiming;
64
+ }
65
+ export interface ForgeBuildPipelineOptions {
66
+ readonly fileSystem: ForgeVirtualFileSystem;
67
+ readonly packageResolver: ForgePackageResolver;
68
+ readonly esbuildWorker?: ForgeEsbuildWasmWorkerService;
69
+ readonly now?: () => string;
70
+ }
71
+ export interface ForgeBuildRequest {
72
+ readonly entry?: string;
73
+ }
74
+ export interface ForgeBuildPipeline {
75
+ readonly capability: typeof BUILD_PIPELINE_CAPABILITY;
76
+ build(request?: ForgeBuildRequest): Promise<ForgeBuildResult>;
77
+ }
@@ -0,0 +1,4 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.BUILD_PIPELINE_CAPABILITY = void 0;
4
+ exports.BUILD_PIPELINE_CAPABILITY = "build-pipeline";
@@ -0,0 +1,5 @@
1
+ import type { ForgeDevServerPreviewDiagnostic } from "./types";
2
+ export declare function createMissingDevScriptDiagnostic(): ForgeDevServerPreviewDiagnostic;
3
+ export declare function createUnsupportedDevScriptDiagnostic(script: string): ForgeDevServerPreviewDiagnostic;
4
+ export declare function createSessionNotFoundDiagnostic(sessionId: string): ForgeDevServerPreviewDiagnostic;
5
+ export declare function createSessionStoppedDiagnostic(sessionId: string): ForgeDevServerPreviewDiagnostic;
@@ -0,0 +1,40 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createSessionStoppedDiagnostic = exports.createSessionNotFoundDiagnostic = exports.createUnsupportedDevScriptDiagnostic = exports.createMissingDevScriptDiagnostic = void 0;
4
+ function createMissingDevScriptDiagnostic() {
5
+ return {
6
+ code: "missing_dev_script",
7
+ severity: "error",
8
+ message: "Missing package.json scripts.dev for Forge preview.",
9
+ path: "/package.json",
10
+ };
11
+ }
12
+ exports.createMissingDevScriptDiagnostic = createMissingDevScriptDiagnostic;
13
+ function createUnsupportedDevScriptDiagnostic(script) {
14
+ return {
15
+ code: "unsupported_dev_script",
16
+ severity: "error",
17
+ message: `Unsupported dev script for Forge preview: ${script}.`,
18
+ path: "/package.json",
19
+ script,
20
+ };
21
+ }
22
+ exports.createUnsupportedDevScriptDiagnostic = createUnsupportedDevScriptDiagnostic;
23
+ function createSessionNotFoundDiagnostic(sessionId) {
24
+ return {
25
+ code: "session_not_found",
26
+ severity: "error",
27
+ message: `Forge dev session was not found: ${sessionId}.`,
28
+ sessionId,
29
+ };
30
+ }
31
+ exports.createSessionNotFoundDiagnostic = createSessionNotFoundDiagnostic;
32
+ function createSessionStoppedDiagnostic(sessionId) {
33
+ return {
34
+ code: "session_stopped",
35
+ severity: "error",
36
+ message: `Forge dev session is stopped: ${sessionId}.`,
37
+ sessionId,
38
+ };
39
+ }
40
+ exports.createSessionStoppedDiagnostic = createSessionStoppedDiagnostic;
@@ -0,0 +1,4 @@
1
+ export { createMissingDevScriptDiagnostic, createSessionNotFoundDiagnostic, createSessionStoppedDiagnostic, createUnsupportedDevScriptDiagnostic, } from "./diagnostics";
2
+ export { createForgePreviewDocument } from "./preview-document";
3
+ export { createDevServerPreview, DefaultDevServerPreview, isSupportedViteDevScript, } from "./server";
4
+ export { DEV_SERVER_PREVIEW_CAPABILITY, type ForgeCreatePreviewDocumentOptions, type ForgeDevServerPreview, type ForgeDevServerPreviewDiagnostic, type ForgeDevServerPreviewDiagnosticCode, type ForgeDevServerPreviewEvent, type ForgeDevServerPreviewEventListener, type ForgeDevServerPreviewOptions, type ForgeDevSession, type ForgeDevSessionDiagnostic, type ForgeDevSessionFailedEvent, type ForgeDevSessionFileChange, type ForgeDevSessionRefreshResult, type ForgeDevSessionStartedEvent, type ForgeDevSessionStartResult, type ForgeDevSessionStatus, type ForgeDevSessionStoppedEvent, type ForgeDevSessionStopResult, type ForgePreviewDocument, type ForgePreviewRefreshedEvent, type ForgeRebuildDevSessionOptions, type ForgeStartDevSessionOptions, } from "./types";
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DEV_SERVER_PREVIEW_CAPABILITY = exports.isSupportedViteDevScript = exports.DefaultDevServerPreview = exports.createDevServerPreview = exports.createForgePreviewDocument = exports.createUnsupportedDevScriptDiagnostic = exports.createSessionStoppedDiagnostic = exports.createSessionNotFoundDiagnostic = exports.createMissingDevScriptDiagnostic = void 0;
4
+ var diagnostics_1 = require("./diagnostics");
5
+ Object.defineProperty(exports, "createMissingDevScriptDiagnostic", { enumerable: true, get: function () { return diagnostics_1.createMissingDevScriptDiagnostic; } });
6
+ Object.defineProperty(exports, "createSessionNotFoundDiagnostic", { enumerable: true, get: function () { return diagnostics_1.createSessionNotFoundDiagnostic; } });
7
+ Object.defineProperty(exports, "createSessionStoppedDiagnostic", { enumerable: true, get: function () { return diagnostics_1.createSessionStoppedDiagnostic; } });
8
+ Object.defineProperty(exports, "createUnsupportedDevScriptDiagnostic", { enumerable: true, get: function () { return diagnostics_1.createUnsupportedDevScriptDiagnostic; } });
9
+ var preview_document_1 = require("./preview-document");
10
+ Object.defineProperty(exports, "createForgePreviewDocument", { enumerable: true, get: function () { return preview_document_1.createForgePreviewDocument; } });
11
+ var server_1 = require("./server");
12
+ Object.defineProperty(exports, "createDevServerPreview", { enumerable: true, get: function () { return server_1.createDevServerPreview; } });
13
+ Object.defineProperty(exports, "DefaultDevServerPreview", { enumerable: true, get: function () { return server_1.DefaultDevServerPreview; } });
14
+ Object.defineProperty(exports, "isSupportedViteDevScript", { enumerable: true, get: function () { return server_1.isSupportedViteDevScript; } });
15
+ var types_1 = require("./types");
16
+ Object.defineProperty(exports, "DEV_SERVER_PREVIEW_CAPABILITY", { enumerable: true, get: function () { return types_1.DEV_SERVER_PREVIEW_CAPABILITY; } });
@@ -0,0 +1,2 @@
1
+ import type { ForgeCreatePreviewDocumentOptions, ForgePreviewDocument } from "./types";
2
+ export declare function createForgePreviewDocument(options: ForgeCreatePreviewDocumentOptions): ForgePreviewDocument;
@@ -0,0 +1,153 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createForgePreviewDocument = void 0;
4
+ const DEFAULT_HTML_SHELL = [
5
+ "<!doctype html>",
6
+ "<html>",
7
+ "<head>",
8
+ ' <meta charset="UTF-8">',
9
+ ' <meta name="viewport" content="width=device-width, initial-scale=1.0">',
10
+ " <title>Forge Preview</title>",
11
+ "</head>",
12
+ "<body>",
13
+ ' <div id="root"></div>',
14
+ "</body>",
15
+ "</html>",
16
+ ].join("\n");
17
+ const PREVIEW_MODULE_SPECIFIER_PREFIX = "__forge_preview__/";
18
+ function createForgePreviewDocument(options) {
19
+ const htmlShell = options.htmlShell ?? DEFAULT_HTML_SHELL;
20
+ const browserBundle = options.buildResult.browserBundle;
21
+ const previewModuleSpecifiers = browserBundle === undefined
22
+ ? new Map()
23
+ : createPreviewModuleSpecifiers(options.buildResult.outputFiles);
24
+ const previewEntrySpecifier = browserBundle === undefined
25
+ ? undefined
26
+ : previewModuleSpecifiers.get(browserBundle.entryOutputPath) ??
27
+ browserBundle.entryOutputPath;
28
+ const metadata = {
29
+ browserBundle: browserBundle === undefined
30
+ ? undefined
31
+ : {
32
+ entryOutputPath: browserBundle.entryOutputPath,
33
+ format: browserBundle.format,
34
+ importMapPath: browserBundle.importMapPath,
35
+ moduleCount: browserBundle.moduleCount,
36
+ outputPaths: browserBundle.outputPaths,
37
+ },
38
+ entry: options.buildResult.entry,
39
+ mode: options.buildResult.mode,
40
+ outputFiles: options.buildResult.outputFiles.map((file) => ({
41
+ contentType: file.contentType,
42
+ path: file.path,
43
+ size: file.size,
44
+ })),
45
+ previewUrl: options.previewUrl,
46
+ revision: options.revision,
47
+ sessionId: options.sessionId,
48
+ };
49
+ const buildManifest = options.buildResult.outputFiles.find((file) => file.contentType === "application/json")?.content;
50
+ const previewImportMap = browserBundle === undefined
51
+ ? undefined
52
+ : createPreviewImportMap(options.buildResult.outputFiles, previewModuleSpecifiers);
53
+ const injection = [
54
+ `<script type="application/json" id="forge-preview-metadata">${escapeJsonForScript(JSON.stringify(metadata))}</script>`,
55
+ buildManifest === undefined
56
+ ? ""
57
+ : `<script type="application/json" id="forge-build-manifest">${escapeJsonForScript(buildManifest)}</script>`,
58
+ previewImportMap === undefined
59
+ ? ""
60
+ : `<script type="importmap" id="forge-browser-bundle-importmap">${escapeJsonForScript(JSON.stringify(previewImportMap))}</script>`,
61
+ browserBundle === undefined
62
+ ? ""
63
+ : `<script type="module" id="forge-browser-bundle-entry">import ${JSON.stringify(previewEntrySpecifier)};</script>`,
64
+ ]
65
+ .filter((line) => line.length > 0)
66
+ .join("\n");
67
+ return {
68
+ contentType: "text/html",
69
+ html: injectBeforeBodyEnd(removeProjectModuleScripts(htmlShell), injection),
70
+ revision: options.revision,
71
+ sessionId: options.sessionId,
72
+ };
73
+ }
74
+ exports.createForgePreviewDocument = createForgePreviewDocument;
75
+ function createPreviewImportMap(outputFiles, previewModuleSpecifiers) {
76
+ const importMapFile = outputFiles.find((file) => file.contentType === "application/importmap+json");
77
+ if (importMapFile === undefined) {
78
+ return undefined;
79
+ }
80
+ const importMap = JSON.parse(importMapFile.content);
81
+ const outputFileByPath = new Map(outputFiles.map((file) => [file.path, file]));
82
+ const imports = Object.fromEntries(Object.entries(importMap.imports ?? {}).map(([specifier, target]) => {
83
+ const outputFile = outputFileByPath.get(target);
84
+ if (outputFile === undefined) {
85
+ return [specifier, target];
86
+ }
87
+ const previewSpecifier = specifier === target
88
+ ? previewModuleSpecifiers.get(specifier) ?? specifier
89
+ : specifier;
90
+ const content = outputFile.contentType === "text/javascript"
91
+ ? rewritePreviewModuleSpecifiers(outputFile.content, previewModuleSpecifiers)
92
+ : outputFile.content;
93
+ return [previewSpecifier, createDataUrl(content, outputFile.contentType)];
94
+ }));
95
+ return { imports };
96
+ }
97
+ function createPreviewModuleSpecifiers(outputFiles) {
98
+ return new Map(outputFiles
99
+ .filter((file) => file.contentType === "text/javascript")
100
+ .map((file) => [file.path, createPreviewModuleSpecifier(file.path)]));
101
+ }
102
+ function createPreviewModuleSpecifier(path) {
103
+ return `${PREVIEW_MODULE_SPECIFIER_PREFIX}${path.replace(/^\//, "")}`;
104
+ }
105
+ function rewritePreviewModuleSpecifiers(source, previewModuleSpecifiers) {
106
+ if (previewModuleSpecifiers.size === 0) {
107
+ return source;
108
+ }
109
+ return source
110
+ .replace(/(\b(?:import|export)\s+(?:[^'"]*?\s+from\s*)?)(["'])([^"']+)\2/g, (match, prefix, quote, specifier) => {
111
+ const replacement = previewModuleSpecifiers.get(specifier);
112
+ return replacement === undefined
113
+ ? match
114
+ : `${prefix}${quote}${replacement}${quote}`;
115
+ })
116
+ .replace(/(\bimport\s*\(\s*)(["'])([^"']+)\2/g, (match, prefix, quote, specifier) => {
117
+ const replacement = previewModuleSpecifiers.get(specifier);
118
+ return replacement === undefined
119
+ ? match
120
+ : `${prefix}${quote}${replacement}${quote}`;
121
+ });
122
+ }
123
+ function createDataUrl(content, contentType) {
124
+ return `data:${contentType};base64,${toBase64(new TextEncoder().encode(content))}`;
125
+ }
126
+ function injectBeforeBodyEnd(html, injection) {
127
+ const bodyEnd = /<\/body\s*>/i;
128
+ if (bodyEnd.test(html)) {
129
+ return html.replace(bodyEnd, `${injection}\n</body>`);
130
+ }
131
+ return `${html}\n${injection}`;
132
+ }
133
+ function removeProjectModuleScripts(html) {
134
+ return html.replace(/<script\b(?=[^>]*\btype\s*=\s*["']module["'])[^>]*>[\s\S]*?<\/script\s*>/gi, "");
135
+ }
136
+ function escapeJsonForScript(json) {
137
+ return json.replace(/</g, "\\u003c");
138
+ }
139
+ function toBase64(bytes) {
140
+ const alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
141
+ let output = "";
142
+ for (let index = 0; index < bytes.length; index += 3) {
143
+ const first = bytes[index];
144
+ const second = bytes[index + 1];
145
+ const third = bytes[index + 2];
146
+ const triplet = (first << 16) | ((second ?? 0) << 8) | (third ?? 0);
147
+ output += alphabet[(triplet >> 18) & 63];
148
+ output += alphabet[(triplet >> 12) & 63];
149
+ output += second === undefined ? "=" : alphabet[(triplet >> 6) & 63];
150
+ output += third === undefined ? "=" : alphabet[triplet & 63];
151
+ }
152
+ return output;
153
+ }
@@ -0,0 +1,26 @@
1
+ import type { ForgeUnsubscribe } from "../virtual-file-system";
2
+ import { type ForgeDevServerPreview, type ForgeDevServerPreviewEventListener, type ForgeDevServerPreviewOptions, type ForgeDevSession, type ForgeDevSessionRefreshResult, type ForgeDevSessionStartResult, type ForgeDevSessionStopResult, type ForgeRebuildDevSessionOptions, type ForgeStartDevSessionOptions } from "./types";
3
+ export declare class DefaultDevServerPreview implements ForgeDevServerPreview {
4
+ private readonly options;
5
+ readonly capability: "dev-server-preview";
6
+ private readonly createSessionId;
7
+ private readonly listeners;
8
+ private readonly now;
9
+ private readonly sessions;
10
+ private nextSessionNumber;
11
+ constructor(options: ForgeDevServerPreviewOptions);
12
+ start(options?: ForgeStartDevSessionOptions): Promise<ForgeDevSessionStartResult>;
13
+ rebuild(sessionId: string, options?: ForgeRebuildDevSessionOptions): Promise<ForgeDevSessionRefreshResult>;
14
+ stop(sessionId: string): Promise<ForgeDevSessionStopResult>;
15
+ getSession(sessionId: string): ForgeDevSession | undefined;
16
+ watch(listener: ForgeDevServerPreviewEventListener): ForgeUnsubscribe;
17
+ private validateDevScript;
18
+ private failStart;
19
+ private handleFileEvent;
20
+ private performRebuild;
21
+ private createPreviewDocument;
22
+ private allocateSessionId;
23
+ private emit;
24
+ }
25
+ export declare function createDevServerPreview(options: ForgeDevServerPreviewOptions): ForgeDevServerPreview;
26
+ export declare function isSupportedViteDevScript(script: string): boolean;