peachsim 0.1.2209 → 0.1.2213
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/cli/command-registry.ts +1 -0
- package/cli/commands/inspect/settling.ts +1 -1
- package/cli/commands/map.ts +576 -0
- package/cli/commands/runtime.ts +1 -1
- package/cli/main.ts +6 -0
- package/cli/outbound-endpoints.ts +11 -0
- package/dist-lib/agent-daemon-client.cjs +1 -1
- package/dist-lib/agent-events.cjs +1 -1
- package/dist-lib/attached-projects.cjs +1 -1
- package/dist-lib/auth/shared-session.cjs +1 -1
- package/dist-lib/backend-origin.cjs +1 -1
- package/dist-lib/beta.cjs +1 -1
- package/dist-lib/beta.mjs +1 -1
- package/dist-lib/bridge-constants.cjs +1 -1
- package/dist-lib/bridge-contract-input.cjs +1 -1
- package/dist-lib/bridge-contract-input.mjs +1 -1
- package/dist-lib/bridge-contract.cjs +1 -1
- package/dist-lib/bridge-contract.mjs +1 -1
- package/dist-lib/bundle-channel.cjs +282 -53
- package/dist-lib/capture-contract.cjs +1 -1
- package/dist-lib/capture-contract.mjs +1 -1
- package/dist-lib/cloud-contract.cjs +1 -1
- package/dist-lib/cloud-contract.mjs +1 -1
- package/dist-lib/cloud-test-args.cjs +1 -1
- package/dist-lib/cloud-test-args.mjs +1 -1
- package/dist-lib/cloud.cjs +1 -1
- package/dist-lib/cloud.mjs +1 -1
- package/dist-lib/config.cjs +1 -1
- package/dist-lib/config.mjs +1 -1
- package/dist-lib/detox/index.cjs +6 -3
- package/dist-lib/dev-bundle-resolution.cjs +1 -1
- package/dist-lib/expo-swift-bundle.cjs +280 -51
- package/dist-lib/expo-swift-metadata.cjs +1 -1
- package/dist-lib/expo-swift-metadata.mjs +1 -1
- package/dist-lib/home-paths.cjs +1 -1
- package/dist-lib/host/bridge-host.cjs +1264 -856
- package/dist-lib/host/fetch-proxy-handler.cjs +21 -5
- package/dist-lib/host/fetch-proxy-overrides.cjs +1 -1
- package/dist-lib/host/fetch-proxy-overrides.mjs +1 -1
- package/dist-lib/host/replacement-module-handler.cjs +1 -1
- package/dist-lib/host/websocket-proxy.cjs +1 -1
- package/dist-lib/index.cjs +1966 -752
- package/dist-lib/jump-to-source-babel.cjs +1 -1
- package/dist-lib/jump-to-source-native.cjs +1 -1
- package/dist-lib/kotlin-host.cjs +1 -1
- package/dist-lib/menu.cjs +1 -1
- package/dist-lib/menu.mjs +1 -1
- package/dist-lib/metro-fingerprint-registry.cjs +1 -1
- package/dist-lib/metro-fingerprint-registry.mjs +1 -1
- package/dist-lib/metro-production-bundle.cjs +1 -1
- package/dist-lib/metro-production-bundle.mjs +1 -1
- package/dist-lib/metro.cjs +1806 -593
- package/dist-lib/native-app-identity-project.cjs +19 -3
- package/dist-lib/native-app-identity-project.mjs +19 -3
- package/dist-lib/native-app-identity.cjs +1 -1
- package/dist-lib/native-app-identity.mjs +1 -1
- package/dist-lib/native-firebase-metadata.cjs +1 -1
- package/dist-lib/native-firebase-metadata.mjs +1 -1
- package/dist-lib/pdfium-raster.cjs +1 -1
- package/dist-lib/pdfium-raster.mjs +1 -1
- package/dist-lib/plist.cjs +1 -1
- package/dist-lib/plist.mjs +1 -1
- package/dist-lib/profiles.cjs +1 -1
- package/dist-lib/public-brand.cjs +1 -1
- package/dist-lib/public-origins-lib-esm.json +25 -24
- package/dist-lib/public-origins-lib.json +83 -53
- package/dist-lib/react-native-host-modules.cjs +1 -1
- package/dist-lib/react-native-host-modules.mjs +1 -1
- package/dist-lib/reap-browser.cjs +1 -1
- package/dist-lib/scripts/dev-server-scanner.cjs +1 -1
- package/dist-lib/sdk.cjs +2 -2
- package/dist-lib/sdk.mjs +2 -2
- package/dist-lib/skills.cjs +1800 -1334
- package/dist-lib/swift-compile.cjs +58 -12
- package/dist-lib/swift-compile.mjs +57 -12
- package/dist-lib/swift-package.cjs +1 -1
- package/dist-lib/swift-package.mjs +1 -1
- package/dist-lib/swift-submit.cjs +1 -1
- package/dist-lib/swift-submit.mjs +1 -1
- package/dist-lib/swift-toolchain.cjs +1 -1
- package/dist-lib/swift.cjs +1 -1
- package/dist-lib/vite-swift.cjs +257 -47
- package/dist-lib/vite.cjs +1530 -303
- package/dist-lib/worklet-executable.cjs +1 -1
- package/dist-lib/worklet-executable.mjs +1 -1
- package/dist-types/packages/peach-engine/src/engine/font-config.d.ts +1 -1
- package/dist-types/packages/peach-engine/src/engine/node.d.ts +1 -0
- package/kotlin/sdk.tar.gz +0 -0
- package/package.json +1 -1
- package/runtime-companion.json +1 -1
- package/sdk/ios/System/Library/Frameworks/CoreData.framework/Headers/CoreData.apinotes +35 -0
- package/sdk/ios/System/Library/Frameworks/CoreData.framework/Headers/CoreData.h +8 -0
- package/sdk/ios/System/Library/Frameworks/CoreData.framework/Headers/NSAttributeDescription.h +30 -0
- package/sdk/ios/System/Library/Frameworks/CoreData.framework/Headers/NSEntityDescription.h +14 -0
- package/sdk/ios/System/Library/Frameworks/CoreData.framework/Headers/NSExpressionDescription.h +10 -0
- package/sdk/ios/System/Library/Frameworks/CoreData.framework/Headers/NSFetchIndexDescription.h +13 -0
- package/sdk/ios/System/Library/Frameworks/CoreData.framework/Headers/NSFetchIndexElementDescription.h +18 -0
- package/sdk/ios/System/Library/Frameworks/CoreData.framework/Headers/NSManagedObject.h +11 -0
- package/sdk/ios/System/Library/Frameworks/CoreData.framework/Headers/NSManagedObjectContext.h +19 -0
- package/sdk/ios/System/Library/Frameworks/CoreData.framework/Headers/NSManagedObjectID.h +2 -0
- package/sdk/ios/System/Library/Frameworks/CoreData.framework/Headers/NSManagedObjectModel.h +3 -0
- package/sdk/ios/System/Library/Frameworks/CoreData.framework/Headers/NSMergePolicy.h +17 -0
- package/sdk/ios/System/Library/Frameworks/CoreData.framework/Headers/NSPersistentStore.h +8 -0
- package/sdk/ios/System/Library/Frameworks/CoreData.framework/Headers/NSPersistentStoreCoordinator.h +6 -0
- package/sdk/ios/System/Library/Frameworks/CoreData.framework/Headers/NSPropertyDescription.h +13 -0
- package/sdk/ios/System/Library/Frameworks/CoreData.framework/Headers/NSRelationshipDescription.h +21 -0
- package/sdk/ios/System/Library/Frameworks/QuartzCore.framework/Headers/CoreAnimation.h +2 -0
- package/sdk/ios/System/Library/Frameworks/UIKit.framework/Headers/UIImage.h +1 -10
- package/sdk/ios/System/Library/Frameworks/UIKit.framework/Headers/UIKit.apinotes +21 -0
- package/sdk/ios/System/Library/Frameworks/UIKit.framework/Headers/UINibLoading.h +1 -1
- package/sdk/ios/System/Library/Frameworks/UIKitTypes.framework/Headers/UIKitTypes.h +11 -0
- package/sdk/ios/usr/lib/swift/Combine.swiftmodule/arm64-apple-ios-simulator.swiftinterface +18 -0
- package/sdk/ios/usr/lib/swift/Foundation.swiftmodule/arm64-apple-ios-simulator.swiftinterface +1 -0
- package/sdk/ios/usr/lib/swift/SwiftUI.swiftmodule/arm64-apple-ios-simulator.swiftinterface +19 -0
- package/sdk/ios/usr/lib/swift/SwiftUICore.swiftmodule/arm64-apple-ios-simulator.swiftinterface +4 -0
- package/sdk/ios/usr/lib/swift/UIKit.swiftmodule/arm64-apple-ios-simulator.swiftinterface +4 -0
- package/sdk/ios/wasm/include/pthread.h +1 -0
- package/sdk/ios/wasm/include/signal.h +2 -2
- package/sdk/native-hashes.json +3 -3
- package/skills/contrast/SKILL.md +1 -0
- package/src/home-paths.ts +1 -1
- package/src/host/bridge-host.ts +101 -97
- package/src/metro-plugin.ts +4 -1
- package/src/native-static-libraries.ts +7 -0
- package/src/react-native-coverage/native-source-ranges-file.ts +1 -1
- package/src/runtime-assets.ts +0 -1
- package/src/runtime-delivery.ts +1 -1
- package/src/runtime-packs.ts +212 -0
- package/src/swift-compile.ts +48 -10
- package/src/swift-host.ts +22 -3
- package/src/swift-objc-compile.ts +1 -1
- package/src/swift-objc-import.ts +32 -2
- package/src/swift-objc-standin.ts +1 -1
- package/src/swift-packages.ts +53 -28
- package/src/swift-pdf-raster.ts +60 -4
- package/src/swift-shipped-archives.json +44 -0
- package/src/swift-shipped-binaries.ts +12 -0
- package/src/swift-standin-config.ts +4 -2
- package/src/swift-standin-emit.ts +9 -3
- package/src/swift-standins.ts +75 -8
- package/src/vite-plugin-one.ts +4 -1
package/src/host/bridge-host.ts
CHANGED
|
@@ -55,6 +55,7 @@ import {
|
|
|
55
55
|
sendFileWithRanges,
|
|
56
56
|
} from '../runtime-assets.ts'
|
|
57
57
|
import { rnxRuntime } from '../runtime-delivery.ts'
|
|
58
|
+
import { ensureRuntimePackFor } from '../runtime-packs.ts'
|
|
58
59
|
import { handleTurboRequest, TURBO_ROUTE } from '../turbo-bundle.ts'
|
|
59
60
|
import { AgentHost, type AgentHostOptions } from './agent-host.ts'
|
|
60
61
|
import { serveAppPackageResource } from './app-package-handler'
|
|
@@ -1920,116 +1921,119 @@ export class SootSimBridgeHost {
|
|
|
1920
1921
|
// inside baseDir that point outside — without it, an attacker who can
|
|
1921
1922
|
// drop a symlink in the runtime dir gets arbitrary-read through the
|
|
1922
1923
|
// daemon. realpath also collapses any remaining normalizable segments.
|
|
1923
|
-
|
|
1924
|
-
|
|
1925
|
-
|
|
1926
|
-
?
|
|
1927
|
-
|
|
1928
|
-
|
|
1929
|
-
|
|
1930
|
-
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
1924
|
+
// a pack-owned prefix downloads on first request before the file resolves
|
|
1925
|
+
void ensureRuntimePackFor(baseDir, rel).then(() =>
|
|
1926
|
+
fs.realpath(resolved, (realErr, realResolved) => {
|
|
1927
|
+
const servePath = realErr ? resolved : realResolved
|
|
1928
|
+
const servePathWithSep = servePath.endsWith(path.sep)
|
|
1929
|
+
? servePath
|
|
1930
|
+
: servePath + path.sep
|
|
1931
|
+
if (!realErr) {
|
|
1932
|
+
const realBaseWithSep = (() => {
|
|
1933
|
+
try {
|
|
1934
|
+
const rb = fs.realpathSync(baseDir)
|
|
1935
|
+
return rb.endsWith(path.sep) ? rb : rb + path.sep
|
|
1936
|
+
} catch {
|
|
1937
|
+
return baseWithSep
|
|
1938
|
+
}
|
|
1939
|
+
})()
|
|
1940
|
+
if (
|
|
1941
|
+
!servePathWithSep.startsWith(realBaseWithSep) &&
|
|
1942
|
+
servePath + path.sep !== realBaseWithSep
|
|
1943
|
+
) {
|
|
1944
|
+
res.writeHead(403)
|
|
1945
|
+
res.end('forbidden')
|
|
1946
|
+
return
|
|
1935
1947
|
}
|
|
1936
|
-
})()
|
|
1937
|
-
if (
|
|
1938
|
-
!servePathWithSep.startsWith(realBaseWithSep) &&
|
|
1939
|
-
servePath + path.sep !== realBaseWithSep
|
|
1940
|
-
) {
|
|
1941
|
-
res.writeHead(403)
|
|
1942
|
-
res.end('forbidden')
|
|
1943
|
-
return
|
|
1944
1948
|
}
|
|
1945
|
-
}
|
|
1946
1949
|
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
|
|
1950
|
-
|
|
1951
|
-
|
|
1952
|
-
|
|
1953
|
-
|
|
1954
|
-
res.writeHead(404)
|
|
1955
|
-
res.end('not found')
|
|
1956
|
-
return
|
|
1957
|
-
}
|
|
1958
|
-
// never SPA-fallback internal endpoint namespaces — those are
|
|
1959
|
-
// expected to return JSON (or a real 404) and the engine calls
|
|
1960
|
-
// .json() on the response. without this, a tenant-worker fetch
|
|
1961
|
-
// to an unimplemented /__foo or /api/foo gets a 200 + index.html
|
|
1962
|
-
// and explodes with "Unexpected token '<', '<!doctype'... is not
|
|
1963
|
-
// valid JSON". /__server-scan is the canonical case (see the
|
|
1964
|
-
// handler above).
|
|
1965
|
-
if (rel.startsWith('/__') || rel.startsWith('/api/') || rel === '/api') {
|
|
1966
|
-
res.writeHead(404, { 'Content-Type': 'text/plain; charset=utf-8' })
|
|
1967
|
-
res.end('not found')
|
|
1968
|
-
return
|
|
1969
|
-
}
|
|
1970
|
-
const indexPath = path.join(baseDir, 'index.html')
|
|
1971
|
-
fs.readFile(indexPath, (err2, data) => {
|
|
1972
|
-
if (err2) {
|
|
1950
|
+
fs.stat(servePath, (err, stats) => {
|
|
1951
|
+
if (err || !stats?.isFile()) {
|
|
1952
|
+
// SPA fallback — but only for extensionless paths. a 404 on
|
|
1953
|
+
// /main.a1b2c3.js should 404, not return index.html as js,
|
|
1954
|
+
// which the sim then chokes on.
|
|
1955
|
+
const ext = path.extname(rel).toLowerCase()
|
|
1956
|
+
if (ext && ext !== '.html') {
|
|
1973
1957
|
res.writeHead(404)
|
|
1974
1958
|
res.end('not found')
|
|
1975
1959
|
return
|
|
1976
1960
|
}
|
|
1977
|
-
|
|
1978
|
-
|
|
1979
|
-
|
|
1980
|
-
|
|
1981
|
-
|
|
1982
|
-
|
|
1961
|
+
// never SPA-fallback internal endpoint namespaces — those are
|
|
1962
|
+
// expected to return JSON (or a real 404) and the engine calls
|
|
1963
|
+
// .json() on the response. without this, a tenant-worker fetch
|
|
1964
|
+
// to an unimplemented /__foo or /api/foo gets a 200 + index.html
|
|
1965
|
+
// and explodes with "Unexpected token '<', '<!doctype'... is not
|
|
1966
|
+
// valid JSON". /__server-scan is the canonical case (see the
|
|
1967
|
+
// handler above).
|
|
1968
|
+
if (rel.startsWith('/__') || rel.startsWith('/api/') || rel === '/api') {
|
|
1969
|
+
res.writeHead(404, { 'Content-Type': 'text/plain; charset=utf-8' })
|
|
1970
|
+
res.end('not found')
|
|
1983
1971
|
return
|
|
1984
1972
|
}
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
|
|
1990
|
-
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
|
|
1996
|
-
|
|
1997
|
-
res.writeHead(200, {
|
|
1998
|
-
'Content-Type': contentType,
|
|
1999
|
-
'Cache-Control': 'no-store',
|
|
2000
|
-
// native file documents have an opaque origin when reading public fonts.
|
|
2001
|
-
...(publicEngineFont ? { 'Access-Control-Allow-Origin': '*' } : {}),
|
|
2002
|
-
})
|
|
2003
|
-
if (method === 'HEAD') {
|
|
2004
|
-
res.end()
|
|
2005
|
-
return
|
|
2006
|
-
}
|
|
2007
|
-
// html responses inline the daemon-injected `__sootsimSharedConfig`
|
|
2008
|
-
// global so the engine's settingsStore initializes from disk on
|
|
2009
|
-
// boot. for everything else stream the file straight through.
|
|
2010
|
-
if (ext === '.html') {
|
|
2011
|
-
fs.readFile(servePath, (readErr, data) => {
|
|
2012
|
-
if (readErr) {
|
|
2013
|
-
try {
|
|
1973
|
+
const indexPath = path.join(baseDir, 'index.html')
|
|
1974
|
+
fs.readFile(indexPath, (err2, data) => {
|
|
1975
|
+
if (err2) {
|
|
1976
|
+
res.writeHead(404)
|
|
1977
|
+
res.end('not found')
|
|
1978
|
+
return
|
|
1979
|
+
}
|
|
1980
|
+
res.writeHead(200, {
|
|
1981
|
+
'Content-Type': 'text/html; charset=utf-8',
|
|
1982
|
+
'Cache-Control': 'no-store',
|
|
1983
|
+
})
|
|
1984
|
+
if (method === 'HEAD') {
|
|
2014
1985
|
res.end()
|
|
2015
|
-
|
|
2016
|
-
|
|
2017
|
-
|
|
2018
|
-
|
|
2019
|
-
|
|
2020
|
-
)
|
|
1986
|
+
return
|
|
1987
|
+
}
|
|
1988
|
+
res.end(
|
|
1989
|
+
injectSharedConfigIntoHtml(data, this.effectivePort, this.contrastOrigin),
|
|
1990
|
+
)
|
|
1991
|
+
})
|
|
1992
|
+
return
|
|
1993
|
+
}
|
|
1994
|
+
const ext = path.extname(servePath).toLowerCase()
|
|
1995
|
+
const contentType = HTTP_MIME_TYPES[ext] || 'application/octet-stream'
|
|
1996
|
+
// no-store across the board: the runtime is served from a versioned
|
|
1997
|
+
// directory but the HTTP path doesn't include the version, so the
|
|
1998
|
+
// same URL serves different content after a runtime swap. caching
|
|
1999
|
+
// any asset means a stale-bundle reload after runtime:changed.
|
|
2000
|
+
res.writeHead(200, {
|
|
2001
|
+
'Content-Type': contentType,
|
|
2002
|
+
'Cache-Control': 'no-store',
|
|
2003
|
+
// native file documents have an opaque origin when reading public fonts.
|
|
2004
|
+
...(publicEngineFont ? { 'Access-Control-Allow-Origin': '*' } : {}),
|
|
2021
2005
|
})
|
|
2022
|
-
|
|
2023
|
-
}
|
|
2024
|
-
const stream = fs.createReadStream(servePath)
|
|
2025
|
-
stream.pipe(res)
|
|
2026
|
-
stream.on('error', () => {
|
|
2027
|
-
try {
|
|
2006
|
+
if (method === 'HEAD') {
|
|
2028
2007
|
res.end()
|
|
2029
|
-
|
|
2008
|
+
return
|
|
2009
|
+
}
|
|
2010
|
+
// html responses inline the daemon-injected `__sootsimSharedConfig`
|
|
2011
|
+
// global so the engine's settingsStore initializes from disk on
|
|
2012
|
+
// boot. for everything else stream the file straight through.
|
|
2013
|
+
if (ext === '.html') {
|
|
2014
|
+
fs.readFile(servePath, (readErr, data) => {
|
|
2015
|
+
if (readErr) {
|
|
2016
|
+
try {
|
|
2017
|
+
res.end()
|
|
2018
|
+
} catch {}
|
|
2019
|
+
return
|
|
2020
|
+
}
|
|
2021
|
+
res.end(
|
|
2022
|
+
injectSharedConfigIntoHtml(data, this.effectivePort, this.contrastOrigin),
|
|
2023
|
+
)
|
|
2024
|
+
})
|
|
2025
|
+
return
|
|
2026
|
+
}
|
|
2027
|
+
const stream = fs.createReadStream(servePath)
|
|
2028
|
+
stream.pipe(res)
|
|
2029
|
+
stream.on('error', () => {
|
|
2030
|
+
try {
|
|
2031
|
+
res.end()
|
|
2032
|
+
} catch {}
|
|
2033
|
+
})
|
|
2030
2034
|
})
|
|
2031
|
-
})
|
|
2032
|
-
|
|
2035
|
+
}),
|
|
2036
|
+
)
|
|
2033
2037
|
}
|
|
2034
2038
|
|
|
2035
2039
|
private sweepIdleCliClients() {
|
package/src/metro-plugin.ts
CHANGED
|
@@ -51,6 +51,7 @@ import {
|
|
|
51
51
|
serveRuntimeFile,
|
|
52
52
|
SOOTSIM_RUNTIME_MISSING_MESSAGE,
|
|
53
53
|
} from './runtime-assets'
|
|
54
|
+
import { ensureRuntimePackFor } from './runtime-packs'
|
|
54
55
|
import {
|
|
55
56
|
getRuntimePlatformAdapter,
|
|
56
57
|
isRuntimePlatform,
|
|
@@ -451,7 +452,7 @@ export function withPeach<T extends Record<string, unknown>>(
|
|
|
451
452
|
|
|
452
453
|
const server = connect()
|
|
453
454
|
|
|
454
|
-
server.use((req: any, res: any, next: any) => {
|
|
455
|
+
server.use(async (req: any, res: any, next: any) => {
|
|
455
456
|
if (isReplacementModuleRequestUrl(req.url)) {
|
|
456
457
|
void handleReplacementModuleRequest(req, res, {
|
|
457
458
|
servedRoots: [cfgProjectRoot, ...cfgWatchFolders],
|
|
@@ -501,6 +502,8 @@ export function withPeach<T extends Record<string, unknown>>(
|
|
|
501
502
|
return
|
|
502
503
|
}
|
|
503
504
|
|
|
505
|
+
await ensureRuntimePackFor(runtimeRoot, pathname)
|
|
506
|
+
|
|
504
507
|
// root-relative runtime assets emitted by the shell and engine vite
|
|
505
508
|
// builds. if a user app has its own /assets/foo request, we only
|
|
506
509
|
// intercept when that exact file exists in the runtime; otherwise
|
|
@@ -192,6 +192,13 @@ export const NATIVE_STATIC_LIBRARY_RECIPES = [
|
|
|
192
192
|
recipe: 'a2642115a5eeb04559c9f1daaa4b4cbe4b1c211533b4cc80cb8339a4477af205',
|
|
193
193
|
archive: 'libsksg.a',
|
|
194
194
|
},
|
|
195
|
+
{
|
|
196
|
+
name: 'webgpu_dawn',
|
|
197
|
+
nativeSha256: '95078993275bccc969b1dfa1ad0934cbacc05ae59e8aa2a6cc46ce93e97d4f69',
|
|
198
|
+
upstream: '3d786993a7ded64c4ebb4884b9b079db9ad0e580',
|
|
199
|
+
recipe: 'c55468cc976e837ad894133f2231beb7d1ed64633af7b457b8a2610d7df45994',
|
|
200
|
+
archive: 'libwebgpu_dawn.a',
|
|
201
|
+
},
|
|
195
202
|
]
|
|
196
203
|
|
|
197
204
|
export function nativeStaticLibraryEntry(
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { z } from 'zod'
|
|
2
|
-
import rangesData from '../../../peach-compat/src/generated/native-source-ranges.json'
|
|
2
|
+
import rangesData from '../../../peach-compat/src/generated/native-source-ranges.json' with { type: 'json' }
|
|
3
3
|
import type { NativeSourceRangesFile } from '../../../peach-compat/src/native-source-ranges-types'
|
|
4
4
|
|
|
5
5
|
const run = z.object({
|
package/src/runtime-assets.ts
CHANGED
package/src/runtime-delivery.ts
CHANGED
|
@@ -33,7 +33,7 @@ export const RNX_RUNTIME_PRODUCT: RuntimeProduct = {
|
|
|
33
33
|
id: 'peach',
|
|
34
34
|
defaultCdnOrigin: DEFAULT_RUNTIME_CDN_ORIGIN,
|
|
35
35
|
manifestPath: '/runtimes/manifest.json',
|
|
36
|
-
tarballPath: (version) => `/runtimes/sootsim-runtime-${version}.tar.
|
|
36
|
+
tarballPath: (version) => `/runtimes/sootsim-runtime-${version}.tar.zst`,
|
|
37
37
|
// the engine runtime is a static SPA: shell at the root, engine/ and
|
|
38
38
|
// engine-tenant/ beneath it. index.html is what the daemon and the
|
|
39
39
|
// vite/metro plugins serve, so its absence means the tarball is not one.
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
import fs from 'node:fs'
|
|
2
|
+
import path from 'node:path'
|
|
3
|
+
import { setTimeout } from 'node:timers'
|
|
4
|
+
import {
|
|
5
|
+
installVerifiedTarball,
|
|
6
|
+
RUNTIME_MERGE_PACK_DIR,
|
|
7
|
+
RUNTIME_MERGE_PACK_INSTALL,
|
|
8
|
+
RUNTIME_MERGE_PACK_MERGED,
|
|
9
|
+
RUNTIME_PACK_MARKER,
|
|
10
|
+
RUNTIME_PACK_PREFIXES,
|
|
11
|
+
RUNTIME_PACKS_FILE,
|
|
12
|
+
type RuntimePacks,
|
|
13
|
+
} from '@contrast/runtime-delivery'
|
|
14
|
+
import { rnxRuntime } from './runtime-delivery.ts'
|
|
15
|
+
|
|
16
|
+
// pieces only some apps reach ship beside the runtime archive, not in it. the
|
|
17
|
+
// archive carries `packs.json` naming each; the first request under a pack's
|
|
18
|
+
// prefix downloads it, checks its digest and lands it by rename, exactly as the
|
|
19
|
+
// archive itself installs. the desktop bundle keeps every prefix in place.
|
|
20
|
+
const inflight = new Map<string, Promise<void>>()
|
|
21
|
+
// an installed version's packs.json never changes
|
|
22
|
+
const packsByRoot = new Map<string, RuntimePacks | null>()
|
|
23
|
+
// listed pack files by basename, each with its runtime-relative path and pack
|
|
24
|
+
const listedByRoot = new Map<string, Map<string, { file: string; pack: string }[]>>()
|
|
25
|
+
|
|
26
|
+
function listedFiles(runtimeRoot: string) {
|
|
27
|
+
let listed = listedByRoot.get(runtimeRoot)
|
|
28
|
+
if (listed) return listed
|
|
29
|
+
listed = new Map()
|
|
30
|
+
for (const [pack, entry] of Object.entries(readPacks(runtimeRoot) ?? {}))
|
|
31
|
+
for (const file of entry.files ?? []) {
|
|
32
|
+
const name = path.posix.basename(file)
|
|
33
|
+
listed.set(name, [...(listed.get(name) ?? []), { file, pack }])
|
|
34
|
+
}
|
|
35
|
+
listedByRoot.set(runtimeRoot, listed)
|
|
36
|
+
return listed
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function readPacks(runtimeRoot: string): RuntimePacks | null {
|
|
40
|
+
const cached = packsByRoot.get(runtimeRoot)
|
|
41
|
+
if (cached !== undefined) return cached
|
|
42
|
+
const file = path.join(runtimeRoot, RUNTIME_PACKS_FILE)
|
|
43
|
+
if (!fs.existsSync(file)) {
|
|
44
|
+
packsByRoot.set(runtimeRoot, null)
|
|
45
|
+
return null
|
|
46
|
+
}
|
|
47
|
+
const parsed: unknown = JSON.parse(fs.readFileSync(file, 'utf8'))
|
|
48
|
+
const packs: RuntimePacks = {}
|
|
49
|
+
if (typeof parsed !== 'object' || parsed === null)
|
|
50
|
+
throw new Error(`${file} is not an object`)
|
|
51
|
+
for (const [prefix, entry] of Object.entries(parsed)) {
|
|
52
|
+
if (typeof entry?.file !== 'string' || typeof entry?.sha256 !== 'string')
|
|
53
|
+
throw new Error(`${file} entry ${prefix} lacks file and sha256`)
|
|
54
|
+
const files: unknown = entry.files
|
|
55
|
+
if (
|
|
56
|
+
files !== undefined &&
|
|
57
|
+
!(Array.isArray(files) && files.every((f) => typeof f === 'string'))
|
|
58
|
+
)
|
|
59
|
+
throw new Error(`${file} entry ${prefix} has files that are not paths`)
|
|
60
|
+
packs[prefix] = {
|
|
61
|
+
file: entry.file,
|
|
62
|
+
sha256: entry.sha256,
|
|
63
|
+
...(files ? { files } : {}),
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
packsByRoot.set(runtimeRoot, packs)
|
|
67
|
+
return packs
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/** make sure the pack that owns a request path is on disk. never rejects: a
|
|
71
|
+
* pack that cannot download logs once and the file then answers 404. */
|
|
72
|
+
export async function ensureRuntimePackFor(
|
|
73
|
+
runtimeRoot: string,
|
|
74
|
+
pathname: string,
|
|
75
|
+
): Promise<void> {
|
|
76
|
+
warmRuntimePacks(runtimeRoot)
|
|
77
|
+
const prefix = RUNTIME_PACK_PREFIXES.find((candidate) =>
|
|
78
|
+
pathname.includes(`/${candidate}`),
|
|
79
|
+
)
|
|
80
|
+
if (prefix) {
|
|
81
|
+
await installNamedPack(runtimeRoot, prefix)
|
|
82
|
+
return
|
|
83
|
+
}
|
|
84
|
+
const listed = listedFiles(runtimeRoot)
|
|
85
|
+
.get(path.posix.basename(pathname))
|
|
86
|
+
?.find(({ file }) => pathname.endsWith(`/${file}`))
|
|
87
|
+
if (listed) {
|
|
88
|
+
if (!fs.existsSync(path.join(runtimeRoot, listed.file)))
|
|
89
|
+
await installNamedPack(runtimeRoot, listed.pack)
|
|
90
|
+
return
|
|
91
|
+
}
|
|
92
|
+
const at = pathname.indexOf(`/${RUNTIME_MERGE_PACK_DIR}`)
|
|
93
|
+
if (at === -1) return
|
|
94
|
+
const tenantDir = path.join(runtimeRoot, RUNTIME_MERGE_PACK_DIR)
|
|
95
|
+
const rel = pathname.slice(at + RUNTIME_MERGE_PACK_DIR.length + 1)
|
|
96
|
+
// the production pack holds only chunks; a missing source map or json is a plain 404
|
|
97
|
+
if (!/\.m?js$/.test(rel) || fs.existsSync(path.join(tenantDir, rel))) return
|
|
98
|
+
await installNamedPack(runtimeRoot, RUNTIME_MERGE_PACK_DIR)
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function installNamedPack(runtimeRoot: string, name: string): Promise<boolean> {
|
|
102
|
+
if (name === RUNTIME_MERGE_PACK_DIR) {
|
|
103
|
+
const tenantDir = path.join(runtimeRoot, RUNTIME_MERGE_PACK_DIR)
|
|
104
|
+
return mergePack(
|
|
105
|
+
runtimeRoot,
|
|
106
|
+
name,
|
|
107
|
+
path.join(tenantDir, RUNTIME_MERGE_PACK_INSTALL),
|
|
108
|
+
tenantDir,
|
|
109
|
+
)
|
|
110
|
+
}
|
|
111
|
+
if (readPacks(runtimeRoot)?.[name]?.files)
|
|
112
|
+
return mergePack(
|
|
113
|
+
runtimeRoot,
|
|
114
|
+
name,
|
|
115
|
+
path.join(runtimeRoot, `.pack-${name}`),
|
|
116
|
+
runtimeRoot,
|
|
117
|
+
)
|
|
118
|
+
return installPack(runtimeRoot, name, path.join(runtimeRoot, name.slice(0, -1)))
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// once the first page has loaded, fetch every remaining pack one at a time so
|
|
122
|
+
// later use never waits on the network. a request for a pack joins its download;
|
|
123
|
+
// a failed download ends the warm, so an offline machine logs once.
|
|
124
|
+
const WARM_DELAY_MS = 30_000
|
|
125
|
+
const warming = new Set<string>()
|
|
126
|
+
|
|
127
|
+
function warmRuntimePacks(runtimeRoot: string): void {
|
|
128
|
+
if (warming.has(runtimeRoot)) return
|
|
129
|
+
warming.add(runtimeRoot)
|
|
130
|
+
const warm = async () => {
|
|
131
|
+
for (const name of Object.keys(readPacks(runtimeRoot) ?? {}))
|
|
132
|
+
if (!(await installNamedPack(runtimeRoot, name))) return
|
|
133
|
+
}
|
|
134
|
+
const schedule: (fn: () => void, ms: number) => NodeJS.Timeout = setTimeout
|
|
135
|
+
schedule(() => void warm(), WARM_DELAY_MS).unref()
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// a merge pack installs beside the tree it belongs to, then hard-links its files
|
|
139
|
+
// into place so the tree keeps one copy on disk. a link that already exists came
|
|
140
|
+
// from an earlier or concurrent merge of the same bytes.
|
|
141
|
+
async function mergePack(
|
|
142
|
+
runtimeRoot: string,
|
|
143
|
+
name: string,
|
|
144
|
+
installDir: string,
|
|
145
|
+
targetDir: string,
|
|
146
|
+
): Promise<boolean> {
|
|
147
|
+
if (fs.existsSync(path.join(installDir, RUNTIME_MERGE_PACK_MERGED))) return true
|
|
148
|
+
if (!(await installPack(runtimeRoot, name, installDir))) return false
|
|
149
|
+
const link = (sub: string): void => {
|
|
150
|
+
for (const entry of fs.readdirSync(path.join(installDir, sub), {
|
|
151
|
+
withFileTypes: true,
|
|
152
|
+
})) {
|
|
153
|
+
const child = path.join(sub, entry.name)
|
|
154
|
+
if (entry.isDirectory()) {
|
|
155
|
+
fs.mkdirSync(path.join(targetDir, child), { recursive: true })
|
|
156
|
+
link(child)
|
|
157
|
+
} else if (entry.name !== RUNTIME_PACK_MARKER) {
|
|
158
|
+
try {
|
|
159
|
+
fs.linkSync(path.join(installDir, child), path.join(targetDir, child))
|
|
160
|
+
} catch (error) {
|
|
161
|
+
if (!(error instanceof Error && 'code' in error && error.code === 'EEXIST'))
|
|
162
|
+
throw error
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
try {
|
|
168
|
+
link('')
|
|
169
|
+
fs.writeFileSync(path.join(installDir, RUNTIME_MERGE_PACK_MERGED), '')
|
|
170
|
+
return true
|
|
171
|
+
} catch (error) {
|
|
172
|
+
console.error(
|
|
173
|
+
`[peach] ${name} pack merge failed: ${error instanceof Error ? error.message : String(error)}`,
|
|
174
|
+
)
|
|
175
|
+
return false
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
async function installPack(
|
|
180
|
+
runtimeRoot: string,
|
|
181
|
+
prefix: string,
|
|
182
|
+
destDir: string,
|
|
183
|
+
): Promise<boolean> {
|
|
184
|
+
const marker = path.join(destDir, RUNTIME_PACK_MARKER)
|
|
185
|
+
if (fs.existsSync(marker)) return true
|
|
186
|
+
const pack = readPacks(runtimeRoot)?.[prefix]
|
|
187
|
+
// a runtime that shipped the prefix inline has no pack entry
|
|
188
|
+
if (!pack) return true
|
|
189
|
+
let install = inflight.get(destDir)
|
|
190
|
+
if (!install) {
|
|
191
|
+
const version = path.basename(runtimeRoot)
|
|
192
|
+
// the hash in the url keeps a refreshed pre-release from hitting a stale cached pack
|
|
193
|
+
const url = new URL(pack.file, rnxRuntime.tarballUrl(version))
|
|
194
|
+
url.searchParams.set('sha256', pack.sha256)
|
|
195
|
+
install = installVerifiedTarball({
|
|
196
|
+
url: url.toString(),
|
|
197
|
+
digest: { algorithm: 'sha256', encoding: 'hex', value: pack.sha256 },
|
|
198
|
+
destDir,
|
|
199
|
+
installedMarker: RUNTIME_PACK_MARKER,
|
|
200
|
+
label: `peach runtime ${version} pack ${prefix}`,
|
|
201
|
+
})
|
|
202
|
+
.catch((error: unknown) => {
|
|
203
|
+
console.error(
|
|
204
|
+
`[peach] ${prefix} pack download failed: ${error instanceof Error ? error.message : String(error)}`,
|
|
205
|
+
)
|
|
206
|
+
})
|
|
207
|
+
.finally(() => inflight.delete(destDir))
|
|
208
|
+
inflight.set(destDir, install)
|
|
209
|
+
}
|
|
210
|
+
await install
|
|
211
|
+
return fs.existsSync(marker)
|
|
212
|
+
}
|
package/src/swift-compile.ts
CHANGED
|
@@ -62,6 +62,7 @@ import {
|
|
|
62
62
|
SWIFT_OBJC_INTEROP_FLAGS,
|
|
63
63
|
swiftClangImporterFlags,
|
|
64
64
|
swiftObjCModuleMap,
|
|
65
|
+
swiftSubmoduleImports,
|
|
65
66
|
} from './swift-objc-import'
|
|
66
67
|
import { swiftObjCRuntimeFlags } from './swift-objc-runtime'
|
|
67
68
|
import { iosDeploymentMinimum, objcSdkIntakeFlags } from './swift-objc-standin'
|
|
@@ -3832,6 +3833,25 @@ function stripCCode(source: string): string {
|
|
|
3832
3833
|
return code
|
|
3833
3834
|
}
|
|
3834
3835
|
|
|
3836
|
+
// whether the unit's code under wasm32 takes its own return address, which
|
|
3837
|
+
// the WebAssembly backend rejects ("hasn't implemented __builtin_return_address"):
|
|
3838
|
+
// native machine code the target has no lowering for, like assembly. branches
|
|
3839
|
+
// the native architecture macros guard are not wasm code.
|
|
3840
|
+
const wasmMacroEnvironment: SwiftCMacroEnvironment = {
|
|
3841
|
+
...emptyMacroEnvironment,
|
|
3842
|
+
defines: new Map([
|
|
3843
|
+
['__wasm__', '1'],
|
|
3844
|
+
['__wasm32__', '1'],
|
|
3845
|
+
['__wasi__', '1'],
|
|
3846
|
+
]),
|
|
3847
|
+
}
|
|
3848
|
+
export function swiftCTakesReturnAddress(source: string): boolean {
|
|
3849
|
+
if (!source.includes('__builtin_return_address')) return false
|
|
3850
|
+
return /\b__builtin_return_address\s*\(/.test(
|
|
3851
|
+
cActiveCode(stripCCode(source), wasmMacroEnvironment),
|
|
3852
|
+
)
|
|
3853
|
+
}
|
|
3854
|
+
|
|
3835
3855
|
// every name the given sources define. order and conditions are not
|
|
3836
3856
|
// evaluated: a name defined anywhere makes its guards undecided.
|
|
3837
3857
|
export function swiftCDefinedNames(sources: Iterable<string>): Set<string> {
|
|
@@ -4360,6 +4380,11 @@ export function writeSwiftProject(
|
|
|
4360
4380
|
clangImportedModules.add(name)
|
|
4361
4381
|
}
|
|
4362
4382
|
}
|
|
4383
|
+
const submoduleImports = swiftSubmoduleImports(
|
|
4384
|
+
Object.entries(input.files).flatMap(([file, contents]) =>
|
|
4385
|
+
file.endsWith('.swift') ? [contents] : [],
|
|
4386
|
+
),
|
|
4387
|
+
)
|
|
4363
4388
|
const headerDirectory = path.join(layout.root, '.build', 'peach-cxx-headers')
|
|
4364
4389
|
const flattenedHeaders = new Set<string>()
|
|
4365
4390
|
// product header aliases belong to this input. keep emitted Swift headers,
|
|
@@ -4906,6 +4931,7 @@ export function writeSwiftProject(
|
|
|
4906
4931
|
swiftObjCModuleMap(
|
|
4907
4932
|
swiftTargetModuleName(target.name),
|
|
4908
4933
|
roots.map((file) => path.join(layout.root, file)),
|
|
4934
|
+
submoduleImports.get(swiftTargetModuleName(target.name)),
|
|
4909
4935
|
))
|
|
4910
4936
|
if (moduleContents === undefined)
|
|
4911
4937
|
throw new Error('missing original module map ' + modulemap)
|
|
@@ -5295,13 +5321,17 @@ export function writeSwiftProject(
|
|
|
5295
5321
|
modulemap,
|
|
5296
5322
|
originalMap
|
|
5297
5323
|
? `extern module ${moduleName} ${JSON.stringify(path.join(layout.root, originalMap))}\nmodule ${moduleName}.Swift {\n header ${JSON.stringify(path.join(headerDirectory, name + '-Swift.h'))}\n requires objc\n}\n`
|
|
5298
|
-
: swiftObjCModuleMap(
|
|
5299
|
-
|
|
5300
|
-
|
|
5301
|
-
|
|
5302
|
-
|
|
5303
|
-
|
|
5304
|
-
|
|
5324
|
+
: swiftObjCModuleMap(
|
|
5325
|
+
moduleName,
|
|
5326
|
+
[
|
|
5327
|
+
...(
|
|
5328
|
+
input.nativeTargets?.find((target) => target.name === name)
|
|
5329
|
+
?.publicHeaders ?? []
|
|
5330
|
+
).map((header) => path.join(layout.root, header)),
|
|
5331
|
+
path.join(headerDirectory, name + '-Swift.h'),
|
|
5332
|
+
],
|
|
5333
|
+
submoduleImports.get(moduleName),
|
|
5334
|
+
),
|
|
5305
5335
|
)
|
|
5306
5336
|
nativeHeaderFlags.push('-fmodule-map-file=' + modulemap)
|
|
5307
5337
|
}
|
|
@@ -6588,8 +6618,15 @@ async function buildFrameworkProducts(
|
|
|
6588
6618
|
const linked = frameworkLinkClosure(scratch, linkedTargets.targets)
|
|
6589
6619
|
const objects = linked.objects
|
|
6590
6620
|
if (linked.modules.has('UniformTypeIdentifiers')) {
|
|
6591
|
-
const
|
|
6592
|
-
|
|
6621
|
+
const constantsDir = path.join(scratch, 'uniform-type-constants')
|
|
6622
|
+
const constantsStamp = path.join(constantsDir, '.complete')
|
|
6623
|
+
const object = path.join(constantsDir, 'UniformTypeIdentifiers-NativeConstants.o')
|
|
6624
|
+
if (
|
|
6625
|
+
!existsSync(constantsStamp) ||
|
|
6626
|
+
readFileSync(constantsStamp, 'utf8') !== args.frameworkKey
|
|
6627
|
+
) {
|
|
6628
|
+
rmSync(constantsDir, { recursive: true, force: true })
|
|
6629
|
+
mkdirSync(constantsDir)
|
|
6593
6630
|
const sdkPaths = swiftSdkPaths(args.moduleRoot, args.toolchainBin)
|
|
6594
6631
|
compileUniformTypeConstants({
|
|
6595
6632
|
bin: args.toolchainBin,
|
|
@@ -6597,8 +6634,9 @@ async function buildFrameworkProducts(
|
|
|
6597
6634
|
darwin: sdkPaths.darwin,
|
|
6598
6635
|
packageRoot: args.moduleRoot,
|
|
6599
6636
|
minimum: darwinRecordsMinimum(),
|
|
6600
|
-
out:
|
|
6637
|
+
out: constantsDir,
|
|
6601
6638
|
})
|
|
6639
|
+
writeFileSync(constantsStamp, args.frameworkKey)
|
|
6602
6640
|
}
|
|
6603
6641
|
objects.push(object)
|
|
6604
6642
|
linked.owners.set(object, 'UniformTypeIdentifiers')
|
package/src/swift-host.ts
CHANGED
|
@@ -83,7 +83,8 @@ import {
|
|
|
83
83
|
type SwiftPackageGap,
|
|
84
84
|
type SwiftPackages,
|
|
85
85
|
} from './swift-packages'
|
|
86
|
-
import { rasterizePdfFile } from './swift-pdf-raster'
|
|
86
|
+
import { rasterizePdfFile, rasterizeSvgFile } from './swift-pdf-raster'
|
|
87
|
+
import { shippedBinaryDiffers } from './swift-shipped-binaries'
|
|
87
88
|
import {
|
|
88
89
|
packageInputPath,
|
|
89
90
|
readPackageFile as readSwiftSourceFile,
|
|
@@ -596,7 +597,7 @@ async function swiftPackages(
|
|
|
596
597
|
// compiling, or a placeholder package's swift target: each stands in from
|
|
597
598
|
// its public surface.
|
|
598
599
|
const standinArtifact = (binary: SwiftPackageBinary) =>
|
|
599
|
-
binary.publicHeaders === undefined || binary.
|
|
600
|
+
binary.publicHeaders === undefined || binary.unloweredSources !== undefined
|
|
600
601
|
const artifacts = reached.filter(standinArtifact)
|
|
601
602
|
if (entry.moduleRoot && entry.provided && artifacts.length > 0) {
|
|
602
603
|
const resolved = swiftModuleToolchain(entry.moduleRoot)
|
|
@@ -618,10 +619,16 @@ async function swiftPackages(
|
|
|
618
619
|
const cxxArtifacts = reached.filter(standinArtifact)
|
|
619
620
|
const generation = standinGenerationInputs(cxxArtifacts, toolchain, entry.behavior)
|
|
620
621
|
if (cached.standinKey !== generation) {
|
|
622
|
+
// an archive other than the one peach ships a module for stands in itself
|
|
623
|
+
const replaced = new Set(
|
|
624
|
+
cxxArtifacts
|
|
625
|
+
.filter((binary) => shippedBinaryDiffers(binary.target, binary.checksum))
|
|
626
|
+
.map((binary) => binary.target),
|
|
627
|
+
)
|
|
621
628
|
const built = await swiftStandins(
|
|
622
629
|
cxxArtifacts,
|
|
623
630
|
toolchain,
|
|
624
|
-
entry.provided,
|
|
631
|
+
new Set([...entry.provided].filter((name) => !replaced.has(name))),
|
|
625
632
|
entry.behavior,
|
|
626
633
|
)
|
|
627
634
|
cached.packages = await resolveSwiftPackagesAsync({
|
|
@@ -637,6 +644,9 @@ async function swiftPackages(
|
|
|
637
644
|
.map((binary) => binary.target)
|
|
638
645
|
.filter((target) => !built.gaps.has(target)),
|
|
639
646
|
]),
|
|
647
|
+
standinTargets: new Set(
|
|
648
|
+
[...replaced].filter((target) => !built.gaps.has(target)),
|
|
649
|
+
),
|
|
640
650
|
binaryGaps: built.gaps,
|
|
641
651
|
owners,
|
|
642
652
|
})
|
|
@@ -1941,6 +1951,15 @@ export function buildSwiftResourceTable(
|
|
|
1941
1951
|
throw new Error('swift image pack exceeds the compile service caps')
|
|
1942
1952
|
}
|
|
1943
1953
|
bytes = readPackageFile(project.packagePath, disk, limits.imageBytes)
|
|
1954
|
+
const svg =
|
|
1955
|
+
ext === '.svg'
|
|
1956
|
+
? rasterizeSvgFile(disk, createHash('sha256').update(bytes).digest('hex'))
|
|
1957
|
+
: null
|
|
1958
|
+
if (svg) {
|
|
1959
|
+
bytes = svg.bytes
|
|
1960
|
+
ext = '.png'
|
|
1961
|
+
uploadName = `${path.posix.basename(file, path.posix.extname(file))}.png`
|
|
1962
|
+
}
|
|
1944
1963
|
}
|
|
1945
1964
|
if (imageBytes + bytes.length > limits.imageTotalBytes) {
|
|
1946
1965
|
throw new Error('swift image pack exceeds the compile service caps')
|