@scriptc/compiler 0.0.33 → 0.0.34

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 (102) hide show
  1. package/dist/backend/cc-cache.test.js +122 -0
  2. package/dist/backend/cc-cache.test.js.map +1 -1
  3. package/dist/backend/cc.d.ts +19 -0
  4. package/dist/backend/cc.js +111 -20
  5. package/dist/backend/cc.js.map +1 -1
  6. package/dist/backend/emission/emit-exprs.js +26 -1
  7. package/dist/backend/emission/emit-exprs.js.map +1 -1
  8. package/dist/backend/emission/emit-shapes.js +37 -4
  9. package/dist/backend/emission/emit-shapes.js.map +1 -1
  10. package/dist/backend/emission/emitter.d.ts +11 -2
  11. package/dist/backend/emission/emitter.js +11 -5
  12. package/dist/backend/emission/emitter.js.map +1 -1
  13. package/dist/backend/library-identity.d.ts +22 -0
  14. package/dist/backend/library-identity.js +103 -0
  15. package/dist/backend/library-identity.js.map +1 -0
  16. package/dist/backend/llvm/emitter.d.ts +3 -0
  17. package/dist/backend/llvm/emitter.js +35 -5
  18. package/dist/backend/llvm/emitter.js.map +1 -1
  19. package/dist/backend/llvm/shapes.d.ts +1 -0
  20. package/dist/backend/llvm/shapes.js +25 -1
  21. package/dist/backend/llvm/shapes.js.map +1 -1
  22. package/dist/backend/mangle.d.ts +1 -0
  23. package/dist/backend/mangle.js +3 -0
  24. package/dist/backend/mangle.js.map +1 -1
  25. package/dist/backend/object-localize.d.ts +5 -5
  26. package/dist/backend/object-localize.js +19 -16
  27. package/dist/backend/object-localize.js.map +1 -1
  28. package/dist/backend/object-localize.test.js +37 -13
  29. package/dist/backend/object-localize.test.js.map +1 -1
  30. package/dist/frontend/input-tracker.d.ts +82 -0
  31. package/dist/frontend/input-tracker.js +380 -0
  32. package/dist/frontend/input-tracker.js.map +1 -0
  33. package/dist/frontend/input-tracker.test.d.ts +1 -0
  34. package/dist/frontend/input-tracker.test.js +137 -0
  35. package/dist/frontend/input-tracker.test.js.map +1 -0
  36. package/dist/frontend/lowering/lower-builtins.js +2 -8
  37. package/dist/frontend/lowering/lower-builtins.js.map +1 -1
  38. package/dist/frontend/lowering/lower-calls.js +155 -140
  39. package/dist/frontend/lowering/lower-calls.js.map +1 -1
  40. package/dist/frontend/lowering/lower-classes.js +3 -0
  41. package/dist/frontend/lowering/lower-classes.js.map +1 -1
  42. package/dist/frontend/lowering/lower-containers.js +48 -9
  43. package/dist/frontend/lowering/lower-containers.js.map +1 -1
  44. package/dist/frontend/lowering/lower-exprs.js +67 -1
  45. package/dist/frontend/lowering/lower-exprs.js.map +1 -1
  46. package/dist/frontend/lowering/lower-inspect.js +45 -26
  47. package/dist/frontend/lowering/lower-inspect.js.map +1 -1
  48. package/dist/frontend/lowering/lower-modules.js +1 -1
  49. package/dist/frontend/lowering/lower-modules.js.map +1 -1
  50. package/dist/frontend/lowering/lower-stmts.js +48 -3
  51. package/dist/frontend/lowering/lower-stmts.js.map +1 -1
  52. package/dist/frontend/lowering/lowerer.d.ts +67 -29
  53. package/dist/frontend/lowering/lowerer.js +410 -87
  54. package/dist/frontend/lowering/lowerer.js.map +1 -1
  55. package/dist/frontend/npm-static-rewrite.js +25 -26
  56. package/dist/frontend/npm-static-rewrite.js.map +1 -1
  57. package/dist/frontend/npm-static.js +29 -30
  58. package/dist/frontend/npm-static.js.map +1 -1
  59. package/dist/frontend/npm-static.test.d.ts +1 -0
  60. package/dist/frontend/npm-static.test.js +15 -0
  61. package/dist/frontend/npm-static.test.js.map +1 -0
  62. package/dist/frontend/npm.js +5 -17
  63. package/dist/frontend/npm.js.map +1 -1
  64. package/dist/frontend/program.js +2 -6
  65. package/dist/frontend/program.js.map +1 -1
  66. package/dist/frontend/resolve.js +8 -29
  67. package/dist/frontend/resolve.js.map +1 -1
  68. package/dist/frontend/ts7/program.js +17 -18
  69. package/dist/frontend/ts7/program.js.map +1 -1
  70. package/dist/frontend/types.d.ts +33 -0
  71. package/dist/frontend/types.js +114 -3
  72. package/dist/frontend/types.js.map +1 -1
  73. package/dist/index.d.ts +1 -1
  74. package/dist/index.js +241 -42
  75. package/dist/index.js.map +1 -1
  76. package/dist/ir/nodes.d.ts +21 -4
  77. package/dist/ir/nodes.js.map +1 -1
  78. package/dist/ir/serialize.d.ts +1 -1
  79. package/dist/ir/serialize.js +1 -1
  80. package/dist/ir/validate.js +31 -1
  81. package/dist/ir/validate.js.map +1 -1
  82. package/dist/library/early-cache.d.ts +65 -0
  83. package/dist/library/early-cache.js +380 -0
  84. package/dist/library/early-cache.js.map +1 -0
  85. package/dist/library/early-cache.test.d.ts +1 -0
  86. package/dist/library/early-cache.test.js +528 -0
  87. package/dist/library/early-cache.test.js.map +1 -0
  88. package/dist/library/int-infer.js +14 -0
  89. package/dist/library/int-infer.js.map +1 -1
  90. package/dist/library/int-infer.test.js +21 -4
  91. package/dist/library/int-infer.test.js.map +1 -1
  92. package/dist/library/semantic-source.d.ts +13 -0
  93. package/dist/library/semantic-source.js +257 -0
  94. package/dist/library/semantic-source.js.map +1 -0
  95. package/dist/library/semantic-source.test.d.ts +1 -0
  96. package/dist/library/semantic-source.test.js +113 -0
  97. package/dist/library/semantic-source.test.js.map +1 -0
  98. package/dist/library/sidecar.d.ts +6 -0
  99. package/dist/library/sidecar.js +11 -0
  100. package/dist/library/sidecar.js.map +1 -1
  101. package/package.json +2 -2
  102. package/surface-manifest.json +1 -1
package/dist/index.js CHANGED
@@ -1,14 +1,15 @@
1
- import { mkdir, rm, writeFile } from "node:fs/promises";
1
+ import { mkdir, readFile, rm, writeFile } from "node:fs/promises";
2
2
  import { basename, dirname, join, resolve } from "node:path";
3
- import { CcCompileError, compileC, compileLibArchive, mobileLibraryTarget, mobileTargetRefusal, resolveCc, targetPlatform } from "./backend/cc.js";
3
+ import { buildCacheRoot, CcCompileError, compileC, compileLibArchive, mobileLibraryTarget, mobileTargetRefusal, prepareBuildCacheRoot, pruneBuildCache, resolveCc, targetPlatform } from "./backend/cc.js";
4
4
  import { emitModule } from "./backend/emission/emitter.js";
5
5
  import { emitLlvmModule, LlvmUnsupportedError } from "./backend/llvm/emitter.js";
6
+ import { rebaseLibrarySourceComments, replaceLibraryIdentity, stripLibraryIdentity, stripLibrarySourceComments } from "./backend/library-identity.js";
6
7
  import { checkerPanicDiag, ffiNativeBuildDiag, libAsyncExportDiag, libAsyncSurfaceDiag, libExportUnresolvedDiag, libGenericExportDiag, libIntBoundaryDiag, libNpmIneligibleDiag, libSidecarDiag, libUnmappableSignatureDiag, iceDiag, isCheckerPanic, LIB_INBOUND_BYTES_TRAP_CODE, LIB_RUNTIME_TRAP_CODES } from "./diagnostics/diagnostic.js";
7
8
  import { checkLibraryIntegerSlots, classSeed, hasIntSlots, numberCarrierKind } from "./library/int-infer.js";
8
9
  import { loadLibraryProfile, profileRemediation, profileTeaching } from "./library/profile.js";
9
10
  import { decorateLibraryRefusals, evaluateLibraryFences } from "./library/fence-eval.js";
10
11
  import { assembleTrapTeaching } from "./library/trap-teaching.js";
11
- import { buildSidecar, canonicalModuleGraph, canonicalPath, compilerReleaseVersion, libraryIdentityHashes, } from "./library/sidecar.js";
12
+ import { buildSidecar, canonicalModuleGraph, canonicalPath, compilerReleaseVersion, libraryIdentityHashes, updateSidecarIdentity, } from "./library/sidecar.js";
12
13
  import { validateSidecar } from "./library/sidecar-validate.js";
13
14
  import { entryFunctionExports } from "./frontend/lib-exports.js";
14
15
  import { entryContractFacts } from "./frontend/lib-contract.js";
@@ -18,11 +19,14 @@ import { validateModule } from "./ir/validate.js";
18
19
  import { canonicalBuiltinModule, checkPreflight, isNodeTypesPath, loadProgram, locOf, requiresOf, resolveNpmImport } from "./frontend/program.js";
19
20
  import { npmStaticIneligibleReason, npmStaticOffenders, npmStaticPackageOfPath } from "./frontend/npm-static.js";
20
21
  import { provenanceSources } from "./frontend/provenance-registry.js";
21
- import { resolveBareModule } from "./frontend/resolve.js";
22
+ import { clearResolveCaches, resolveBareModule } from "./frontend/resolve.js";
22
23
  import { isJsSourceFileName, isRelativeSpecifier } from "./frontend/shared.js";
23
24
  import { lowerToIr } from "./frontend/lowering/lowerer.js";
24
25
  import { loadFfiProfile } from "./ffi/profile.js";
25
26
  import { hasForeignFfiCallback } from "./backend/ffi-callbacks.js";
27
+ import { FrontendInputTracker, trackedReadFile } from "./frontend/input-tracker.js";
28
+ import { libraryFrontendImplementationFingerprint, publishEarlyLibraryCache, readEarlyLibraryCache, readSemanticLibraryCache } from "./library/early-cache.js";
29
+ import { createSourceLineRebaser } from "./library/semantic-source.js";
26
30
  export const VERSION = "0.0.1";
27
31
  export { compileC, runtimeSrcDir } from "./backend/cc.js";
28
32
  export { ANDROID_MIN_API, IPHONEOS_MIN_VERSION, isAndroidTarget, isIosTarget, isMobileTarget, mobileLibraryTarget, mobileTargetRefusal } from "./backend/cc.js";
@@ -317,6 +321,11 @@ function packageNameOfBareSpecifier(specifier) {
317
321
  * static-or-refuse teaching, and the detection closes over the opted-in
318
322
  * packages' own bare edges (no island exists to serve a dep from). */
319
323
  function runFrontend(entryPath, npmStatic, externalTypes) {
324
+ // Resolver package/workspace metadata is intentionally shared across the
325
+ // several load attempts of ONE auto-detection fixpoint, but never across
326
+ // separate compiles in a long-lived process. A cache miss must observe
327
+ // package.json edits before it can publish a new early-library entry.
328
+ clearResolveCaches();
320
329
  const statuses = [];
321
330
  const npmSites = new Map();
322
331
  const judged = new Set();
@@ -1202,7 +1211,166 @@ function mergeSidecarIntSlots(cfg, facts, mod) {
1202
1211
  }
1203
1212
  return { ok: true, config: cfg };
1204
1213
  }
1214
+ function libraryNativeFeatures(mod, backend) {
1215
+ return {
1216
+ backend,
1217
+ regex: moduleUsesRegex(mod),
1218
+ assert: moduleUsesAssert(mod),
1219
+ inspect: moduleUsesInspect(mod),
1220
+ symbol: moduleUsesSymbol(mod),
1221
+ searchParams: moduleUsesSearchParams(mod),
1222
+ emitter: moduleUsesEmitter(mod),
1223
+ zlib: moduleUsesZlib(mod),
1224
+ copying: moduleUsesCopying(mod),
1225
+ textDecoderLegacy: moduleUsesLegacyTextDecoder(mod),
1226
+ ...(mod.lib?.identity !== undefined ? { buildId: mod.lib.identity.buildId } : {}),
1227
+ };
1228
+ }
1229
+ function libraryLocalizeSymbols(profile) {
1230
+ return profile.localizeRuntime
1231
+ ? [
1232
+ profile.initSymbol,
1233
+ profile.sinkRegisterSymbol,
1234
+ ...(profile.collectSymbol !== null ? [profile.collectSymbol] : []),
1235
+ ...(profile.resultResetSymbol !== null ? [profile.resultResetSymbol] : []),
1236
+ ...(profile.callbackRegisterSymbol !== null ? [profile.callbackRegisterSymbol] : []),
1237
+ ...(profile.sidecar !== null
1238
+ ? [profile.sidecar.buildIdSymbol, profile.sidecar.abiVersionSymbol]
1239
+ : []),
1240
+ ...profile.exports.map((entry) => entry.symbol),
1241
+ ]
1242
+ : undefined;
1243
+ }
1244
+ async function compileLibraryNative(profile, cPath, archivePath, sanitize, features) {
1245
+ const localizeSymbols = libraryLocalizeSymbols(profile);
1246
+ let identityCSource;
1247
+ let programSource;
1248
+ if (profile.sidecar !== null || profile.emission === "c") {
1249
+ const publicSource = await readFile(cPath, "utf8");
1250
+ programSource = publicSource;
1251
+ }
1252
+ if (profile.sidecar !== null) {
1253
+ if (features.buildId === undefined)
1254
+ throw new Error("library identity TU has no build id");
1255
+ const withoutIdentity = stripLibraryIdentity(programSource, profile.emission);
1256
+ if (withoutIdentity === programSource) {
1257
+ throw new Error("generated public library TU has no identity region");
1258
+ }
1259
+ programSource = withoutIdentity;
1260
+ identityCSource = [
1261
+ "#include <stdint.h>",
1262
+ "#include <inttypes.h>",
1263
+ `uint64_t ${profile.sidecar.buildIdSymbol}(void) { return UINT64_C(0x${features.buildId}); }`,
1264
+ `uint32_t ${profile.sidecar.abiVersionSymbol}(void) { return ${profile.sidecar.abiVersion}u; }`,
1265
+ "",
1266
+ ].join("\n");
1267
+ }
1268
+ if (profile.emission === "c") {
1269
+ programSource = stripLibrarySourceComments(programSource, profile.entry);
1270
+ }
1271
+ await compileLibArchive({
1272
+ cPath,
1273
+ ...(programSource !== undefined ? { programSource } : {}),
1274
+ ...(identityCSource !== undefined ? { identityCSource } : {}),
1275
+ outPath: archivePath,
1276
+ cacheIdentity: "scriptc-generated-library-v1",
1277
+ sanitize,
1278
+ optimization: profile.optimization,
1279
+ ...(localizeSymbols !== undefined ? { localizeSymbols } : {}),
1280
+ ...(profile.instancePerThread ? { threadInstances: true } : {}),
1281
+ regex: features.regex,
1282
+ assert: features.assert,
1283
+ inspect: features.inspect,
1284
+ symbol: features.symbol,
1285
+ searchParams: features.searchParams,
1286
+ emitter: features.emitter,
1287
+ zlib: features.zlib,
1288
+ copying: features.copying,
1289
+ textDecoderLegacy: features.textDecoderLegacy,
1290
+ });
1291
+ }
1292
+ async function emitSemanticLibraryHit(hit, profile, opts, archivePath, cacheRoot, cacheOptions, timing) {
1293
+ const mod = hit.mod;
1294
+ const rootDir = dirname(resolve(opts.profilePath));
1295
+ let sidecarJson = hit.sidecarJson;
1296
+ if (profile.sidecar !== null) {
1297
+ if (mod.lib?.identity === undefined || sidecarJson === null) {
1298
+ throw new Error("semantic library cache lost sidecar identity metadata");
1299
+ }
1300
+ const modules = canonicalModuleGraph(rootDir, hit.sourceTexts);
1301
+ const { buildId, sourceHash } = libraryIdentityHashes(compilerReleaseVersion(), profile.profileBytes, modules);
1302
+ mod.lib.identity.buildId = buildId;
1303
+ hit.native.buildId = buildId;
1304
+ sidecarJson = updateSidecarIdentity(sidecarJson, buildId, sourceHash);
1305
+ }
1306
+ const validation = validateModule(mod);
1307
+ if (validation.length > 0) {
1308
+ return {
1309
+ ok: false,
1310
+ diagnostics: validation.map((violation) => iceDiag(violation.message, violation.loc)),
1311
+ sourceTexts: hit.sourceTexts,
1312
+ };
1313
+ }
1314
+ await mkdir(opts.outDir, { recursive: true });
1315
+ const stem = basename(profile.entry).replace(/\.(ts|js|mjs|cjs)$/, "");
1316
+ const cPath = join(opts.outDir, `${stem}.lib.${profile.emission === "llvm" ? "ll" : "c"}`);
1317
+ let translationUnit = hit.translationUnit;
1318
+ if (profile.sidecar !== null) {
1319
+ translationUnit = replaceLibraryIdentity(translationUnit, profile.emission, mod.lib.identity);
1320
+ }
1321
+ if (profile.emission === "llvm") {
1322
+ await writeFile(cPath, translationUnit);
1323
+ }
1324
+ else {
1325
+ const previous = hit.previousSources.get(mod.sourceFile);
1326
+ const current = hit.sourceTexts.get(mod.sourceFile);
1327
+ if (previous === undefined || current === undefined) {
1328
+ throw new Error("semantic library cache lost the entry source text");
1329
+ }
1330
+ translationUnit = rebaseLibrarySourceComments(translationUnit, mod.sourceFile, createSourceLineRebaser(mod.sourceFile, previous, current));
1331
+ await writeFile(cPath, translationUnit);
1332
+ }
1333
+ timing("semantic-tu-restore", { output_bytes: Buffer.byteLength(translationUnit) });
1334
+ await rm(join(opts.outDir, `${stem}.lib.${profile.emission === "llvm" ? "c" : "ll"}`), { force: true });
1335
+ let irPath;
1336
+ if (opts.emitIr) {
1337
+ irPath = join(opts.outDir, `${stem}.lib.ir.json`);
1338
+ await writeFile(irPath, serializeModule(mod));
1339
+ }
1340
+ await compileLibraryNative(profile, cPath, archivePath, opts.sanitize ?? false, hit.native);
1341
+ timing("native-archive");
1342
+ let sidecarPath;
1343
+ if (sidecarJson !== null) {
1344
+ sidecarPath = profile.sidecar.path !== null
1345
+ ? resolve(dirname(archivePath), profile.sidecar.path)
1346
+ : `${archivePath}.contract.json`;
1347
+ await writeFile(sidecarPath, sidecarJson);
1348
+ }
1349
+ await publishEarlyLibraryCache(cacheRoot, cacheOptions, {
1350
+ cPath,
1351
+ native: hit.native,
1352
+ frontend: hit.frontend,
1353
+ semantic: { mod, sources: hit.sourceTexts },
1354
+ ...(irPath !== undefined ? { irPath } : {}),
1355
+ ...(sidecarPath !== undefined ? { sidecarPath } : {}),
1356
+ }).catch(() => undefined);
1357
+ await pruneBuildCache(cacheRoot);
1358
+ timing("semantic-cache-publish");
1359
+ timing("complete");
1360
+ return {
1361
+ ok: true,
1362
+ archivePath,
1363
+ cPath,
1364
+ backend: profile.emission,
1365
+ ...(irPath !== undefined ? { irPath } : {}),
1366
+ ...(sidecarPath !== undefined ? { sidecarPath } : {}),
1367
+ };
1368
+ }
1205
1369
  export async function compileLibrary(opts) {
1370
+ const frontendInputs = new FrontendInputTracker();
1371
+ return frontendInputs.run(() => compileLibraryTracked(opts, frontendInputs));
1372
+ }
1373
+ async function compileLibraryTracked(opts, frontendInputs) {
1206
1374
  const timingOn = process.env["SCRIPTC_TIMING"] === "1";
1207
1375
  const timingStart = performance.now();
1208
1376
  let timingLast = timingStart;
@@ -1227,6 +1395,21 @@ export async function compileLibrary(opts) {
1227
1395
  const profile = loadedProfile.profile;
1228
1396
  const entryPath = profile.entry;
1229
1397
  const buildPlatform = buildTargetPlatform();
1398
+ const profileDir = dirname(resolve(opts.profilePath));
1399
+ for (let directory = dirname(entryPath);; directory = dirname(directory)) {
1400
+ for (const name of ["tsconfig.json", "package.json"]) {
1401
+ // Project configuration and package-realm metadata can affect the
1402
+ // frontend even when TypeScript did not request their bytes through
1403
+ // its delegated filesystem callbacks (tsgo may read them server-side).
1404
+ frontendInputs.run(() => {
1405
+ const path = join(directory, name);
1406
+ trackedReadFile(path);
1407
+ });
1408
+ }
1409
+ if (directory === profileDir || dirname(directory) === directory)
1410
+ break;
1411
+ }
1412
+ const archivePath = opts.outPath ?? join(opts.outDir, `${basename(entryPath).replace(/\.(ts|js|mjs|cjs)$/, "")}.lib.a`);
1230
1413
  // Mobile-target admission first — a pure env/host check, so a refused
1231
1414
  // pairing never reaches toolchain discovery. iOS targets (device and
1232
1415
  // simulator) build on darwin hosts only: the Apple SDK sysroot and the
@@ -1283,6 +1466,44 @@ export async function compileLibrary(opts) {
1283
1466
  };
1284
1467
  }
1285
1468
  }
1469
+ const cacheRoot = provenanceSources() === null
1470
+ ? await prepareBuildCacheRoot(buildCacheRoot())
1471
+ : null;
1472
+ const earlyCacheOptions = {
1473
+ profilePath: opts.profilePath,
1474
+ profileBytes: profile.profileBytes,
1475
+ entryPath,
1476
+ outDir: opts.outDir,
1477
+ ...(opts.outPath !== undefined ? { outPath: opts.outPath } : {}),
1478
+ emitIr: opts.emitIr ?? false,
1479
+ sanitize: opts.sanitize ?? false,
1480
+ target: `${process.env["SCRIPTC_TARGET"] ?? "native"}:${buildPlatform}:${process.arch}`,
1481
+ compiler: [process.env["SCRIPTC_CC"] ?? "clang"],
1482
+ nodeVersion: process.version,
1483
+ implementation: await libraryFrontendImplementationFingerprint(),
1484
+ };
1485
+ const earlyHit = await readEarlyLibraryCache(cacheRoot, earlyCacheOptions, profile.sidecar === null ? undefined : profile.sidecar.path);
1486
+ if (earlyHit !== null) {
1487
+ timing("early-cache-hit");
1488
+ await compileLibraryNative(profile, earlyHit.cPath, archivePath, opts.sanitize ?? false, earlyHit.native);
1489
+ timing("native-archive");
1490
+ timing("complete");
1491
+ return {
1492
+ ok: true,
1493
+ archivePath,
1494
+ cPath: earlyHit.cPath,
1495
+ backend: earlyHit.native.backend,
1496
+ ...(earlyHit.irPath !== undefined ? { irPath: earlyHit.irPath } : {}),
1497
+ ...(earlyHit.sidecarPath !== undefined ? { sidecarPath: earlyHit.sidecarPath } : {}),
1498
+ };
1499
+ }
1500
+ timing("early-cache-miss");
1501
+ const semanticHit = await readSemanticLibraryCache(cacheRoot, earlyCacheOptions, profile.sidecar === null ? undefined : profile.sidecar.path);
1502
+ if (semanticHit !== null) {
1503
+ timing("semantic-cache-hit", { changed_sources: semanticHit.changedSources.length });
1504
+ return emitSemanticLibraryHit(semanticHit, profile, opts, archivePath, cacheRoot, earlyCacheOptions, timing);
1505
+ }
1506
+ timing("semantic-cache-miss");
1286
1507
  // Bare npm specifiers in a library graph take the STATIC-OR-REFUSE
1287
1508
  // posture: "lib" runs the same auto-detection and eligibility bar as
1288
1509
  // the executable lane's --npm-static (own .d.ts, unminified shipped JS,
@@ -1445,9 +1666,9 @@ export async function compileLibrary(opts) {
1445
1666
  // The ask-2 contract sidecar rides the same invocation. Identity first
1446
1667
  // (schema §2's worked build_id definition over compiler version, profile
1447
1668
  // bytes, and the sorted canonical module graph; source_hash per the
1448
- // profile's "module-graph" contract) — the u64 lands on the IR so both
1449
- // backends emit the identity getters from the ONE value the sidecar
1450
- // records (V12's coherence by construction), then the projection into
1669
+ // profile's "module-graph" contract) — the u64 lands on the IR so native
1670
+ // archive assembly emits the identity getters from the ONE value the
1671
+ // sidecar records (V12's coherence by construction), then the projection into
1451
1672
  // the schema (declaration orders from the AST) and the V1–V14
1452
1673
  // self-check before anything is written.
1453
1674
  let sidecarJson = null;
@@ -1532,41 +1753,8 @@ export async function compileLibrary(opts) {
1532
1753
  irPath = join(opts.outDir, `${stem}.lib.ir.json`);
1533
1754
  await writeFile(irPath, serializeModule(mod));
1534
1755
  }
1535
- const archivePath = opts.outPath ?? join(opts.outDir, `${stem}.lib.a`);
1536
- // Multi-instance library mode: the profile-declared external surface —
1537
- // the mode-provided entries, the identity getters, and the export map —
1538
- // is exactly the set the localization step keeps global.
1539
- const localizeSymbols = profile.localizeRuntime
1540
- ? [
1541
- profile.initSymbol,
1542
- profile.sinkRegisterSymbol,
1543
- ...(profile.collectSymbol !== null ? [profile.collectSymbol] : []),
1544
- ...(profile.resultResetSymbol !== null ? [profile.resultResetSymbol] : []),
1545
- ...(profile.callbackRegisterSymbol !== null ? [profile.callbackRegisterSymbol] : []),
1546
- ...(profile.sidecar !== null
1547
- ? [profile.sidecar.buildIdSymbol, profile.sidecar.abiVersionSymbol]
1548
- : []),
1549
- ...profile.exports.map((e) => e.symbol),
1550
- ]
1551
- : undefined;
1552
- await compileLibArchive({
1553
- cPath,
1554
- outPath: archivePath,
1555
- cacheIdentity: "scriptc-generated-library-v1",
1556
- sanitize: opts.sanitize ?? false,
1557
- optimization: profile.optimization,
1558
- ...(localizeSymbols !== undefined ? { localizeSymbols } : {}),
1559
- ...(profile.instancePerThread ? { threadInstances: true } : {}),
1560
- regex: moduleUsesRegex(mod),
1561
- assert: moduleUsesAssert(mod),
1562
- inspect: moduleUsesInspect(mod),
1563
- symbol: moduleUsesSymbol(mod),
1564
- searchParams: moduleUsesSearchParams(mod),
1565
- emitter: moduleUsesEmitter(mod),
1566
- zlib: moduleUsesZlib(mod),
1567
- copying: moduleUsesCopying(mod),
1568
- textDecoderLegacy: moduleUsesLegacyTextDecoder(mod),
1569
- });
1756
+ const nativeFeatures = libraryNativeFeatures(mod, profile.emission);
1757
+ await compileLibraryNative(profile, cPath, archivePath, opts.sanitize ?? false, nativeFeatures);
1570
1758
  timing("native-archive");
1571
1759
  // The sidecar lands beside the compiled object, written by the same
1572
1760
  // invocation (profile-declared name; the neutral default when the
@@ -1579,6 +1767,17 @@ export async function compileLibrary(opts) {
1579
1767
  : `${archivePath}.contract.json`;
1580
1768
  await writeFile(sidecarPath, sidecarJson);
1581
1769
  }
1770
+ const earlyPublish = {
1771
+ cPath,
1772
+ native: nativeFeatures,
1773
+ frontend: frontendInputs.snapshot(),
1774
+ semantic: { mod, sources: sourceTexts },
1775
+ ...(irPath !== undefined ? { irPath } : {}),
1776
+ ...(sidecarPath !== undefined ? { sidecarPath } : {}),
1777
+ };
1778
+ await publishEarlyLibraryCache(cacheRoot, earlyCacheOptions, earlyPublish).catch(() => undefined);
1779
+ await pruneBuildCache(cacheRoot);
1780
+ timing("early-cache-publish");
1582
1781
  timing("complete");
1583
1782
  return {
1584
1783
  ok: true,