forked from vercel/pkg
-
-
Notifications
You must be signed in to change notification settings - Fork 62
Expand file tree
/
Copy pathsea-assets.ts
More file actions
105 lines (92 loc) · 3.1 KB
/
sea-assets.ts
File metadata and controls
105 lines (92 loc) · 3.1 KB
1
2
3
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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
import { mkdir, writeFile } from 'fs/promises';
import { dirname, join } from 'path';
import { STORE_CONTENT, STORE_LINKS, STORE_STAT, snapshotify } from './common';
import { FileRecords, SymLinks } from './types';
export interface SeaManifest {
entrypoint: string;
directories: Record<string, string[]>;
stats: Record<
string,
{ size: number; isFile: boolean; isDirectory: boolean }
>;
symlinks: Record<string, string>;
}
export interface SeaAssetsResult {
assets: Record<string, string>;
manifestPath: string;
}
/**
* Transform walker/refiner output into SEA-compatible asset map and manifest.
*
* Asset keys use refiner paths (no /snapshot prefix) because @platformatic/vfs
* strips the mount prefix before passing paths to the provider. The entrypoint
* in the manifest uses the snapshotified path for process.argv[1] compatibility.
*
* Always uses POSIX '/' separator for manifest paths so the same blob works
* regardless of build platform. The bootstrap normalizes at runtime.
*/
export async function generateSeaAssets(
records: FileRecords,
entrypoint: string,
symLinks: SymLinks,
tmpDir: string,
): Promise<SeaAssetsResult> {
const assets: Record<string, string> = {};
// Normalize symlink paths to use POSIX separators, matching other manifest paths
const normalizedSymlinks: Record<string, string> = {};
for (const src in symLinks) {
normalizedSymlinks[snapshotify(src, '/')] = snapshotify(symLinks[src], '/');
}
const manifest: SeaManifest = {
// Always use '/' — the bootstrap normalizes for the runtime platform
entrypoint: snapshotify(entrypoint, '/'),
directories: {},
stats: {},
symlinks: normalizedSymlinks,
};
let modifiedFileCount = 0;
for (const snap in records) {
if (!records[snap]) continue;
const record = records[snap];
// Map file content to SEA asset
if (record[STORE_CONTENT]) {
if (record.body != null) {
// File was modified (patches, rewrites) — write to temp file
const tempPath = join(
tmpDir,
'assets',
`modified_${modifiedFileCount}`,
);
modifiedFileCount += 1;
await mkdir(dirname(tempPath), { recursive: true });
const content =
typeof record.body === 'string'
? Buffer.from(record.body)
: record.body;
await writeFile(tempPath, content);
assets[snap] = tempPath;
} else {
// Unmodified file — point to source on disk
assets[snap] = record.file;
}
}
// Collect directory entries
if (record[STORE_LINKS]) {
manifest.directories[snap] = [
...new Set(record[STORE_LINKS] as string[]),
];
}
// Collect stat metadata
if (record[STORE_STAT]) {
const stat = record[STORE_STAT];
manifest.stats[snap] = {
size: stat.size ?? 0,
isFile: Boolean(stat.isFileValue),
isDirectory: Boolean(stat.isDirectoryValue),
};
}
}
const manifestPath = join(tmpDir, '__pkg_manifest__.json');
await writeFile(manifestPath, JSON.stringify(manifest));
return { assets, manifestPath };
}