@geastack/core 0.1.29 → 0.1.31

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@geastack/core",
3
- "version": "0.1.29",
3
+ "version": "0.1.31",
4
4
  "description": "GeaStack app API, reactivity headers, runtime sources, and type declarations.",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -62,8 +62,8 @@
62
62
  "@babel/types": "^7.23.0",
63
63
  "@geajs/core": "1.5.1",
64
64
  "@geajs/vite-plugin": "1.5.0",
65
- "@geastack/compiler": "^1.0.19",
66
- "@geastack/geatsc-plugin-gea": "^0.1.9",
65
+ "@geastack/compiler": "^1.0.20",
66
+ "@geastack/geatsc-plugin-gea": "^0.1.13",
67
67
  "opentype.js": "^2.0.0",
68
68
  "vite": "^8.0.0"
69
69
  }
package/runtime.cpp CHANGED
@@ -57,8 +57,8 @@ namespace {
57
57
  void run_app_frame(int timestampMs, void *context)
58
58
  {
59
59
  (void)context;
60
- events::TouchRuntime::poll(timestampMs);
61
- services::BatteryService::poll(timestampMs);
60
+ // Canvas-only inference excludes input/battery consumers. These services
61
+ // belong to the full runtime and are not linked in the reduced source set.
62
62
  app::Application::frame(timestampMs);
63
63
  }
64
64
 
@@ -363,6 +363,16 @@ bool Runtime::boot(const RuntimeOptions &options)
363
363
  // correctly in PSRAM the whole time. Display::init() now claims its floor
364
364
  // before this line, and this bring-up shrinks it the designed way.
365
365
  services::DiagnosticsServer::print("Starting WiFi after display init\n");
366
+ // This synchronous boot path bypasses WifiStation::ensureBringUp(),
367
+ // which normally yields display staging before allocating the radio.
368
+ // No frame task is running yet, so apply the reservation here rather
369
+ // than waiting for a frame that cannot run until init() returns.
370
+ // Keep the already-secured minimum pipeline, yielding the rest before
371
+ // both radio and application audio allocations. A fixed 56 KiB shrink
372
+ // left a 52 KiB staging pool on this boot path and starved I2S DMA.
373
+ gea::platform::display::Display::reserveInternal(
374
+ static_cast<std::size_t>(gea::platform::display::Display::flushBufferBytes()));
375
+ gea::platform::display::Display::applyPendingInternalReserve();
366
376
  network::wifi().init();
367
377
  }
368
378
  #endif
@@ -406,6 +416,14 @@ bool Runtime::boot(const RuntimeOptions &options)
406
416
  services::HeapProbe::log("runtime:after_frame_start");
407
417
  services::StackProbe::logCurrentTask("runtime:after_frame_start");
408
418
  services::HeapTaskSummary::log("runtime:after_frame_start");
419
+ #if GEA_EMBEDDED_WIFI_EARLY_CONNECT
420
+ // The early-connect loan protects radio, app, and task initialization.
421
+ // They now own their allocations; let the frame task grow staging into
422
+ // the remaining heap instead of retaining the two-row boot floor forever.
423
+ // Allocation still observes the DMA reserve and falls back when RAM is tight.
424
+ if (GEA_EMBEDDED_WIFI_SSID[0] != '\0')
425
+ gea::platform::display::Display::reserveInternal(0);
426
+ #endif
409
427
  services::RuntimeLog::appStarted(networkReady);
410
428
  #endif
411
429
 
@@ -6,8 +6,9 @@ import { spawnSync } from 'node:child_process'
6
6
  import { createRequire } from 'node:module'
7
7
  import { fileURLToPath, pathToFileURL } from 'node:url'
8
8
  import { inlineJsonImports, transformGeaEmbeddedCompatSource } from './gea-embedded-compat-transform.mjs'
9
- import { shouldIgnoreCompatStagingDirectory } from './gea-embedded-compat-staging.mjs'
9
+ import { normalizeEmbeddedJsxOptions, shouldIgnoreCompatStagingDirectory } from './gea-embedded-compat-staging.mjs'
10
10
  import { dotEnvDefines, inlineProcessEnv } from './dotenv-defines.mjs'
11
+ import { resolveCompilerRuntimeEntry } from './gea-native-style-plugin.mjs'
11
12
  import {
12
13
  MODULE_HINT_SCOPE,
13
14
  applyBundledTypeHints,
@@ -75,9 +76,17 @@ const { parse } = requireFromLib('@babel/parser')
75
76
  const traverseModule = requireFromLib('@babel/traverse')
76
77
  const t = requireFromLib('@babel/types')
77
78
  const traverse = traverseModule.default || traverseModule
78
- const useStaticCssRules = !['0', 'false', 'no'].includes(String(process.env.GEA_STATIC_CSS_RULES ?? '1').toLowerCase())
79
- const useStaticCssTape = !['0', 'false', 'no'].includes(String(process.env.GEA_STATIC_CSS_TAPE ?? '1').toLowerCase())
80
- const staticCssTapeMinChunk = Math.max(1, Number.parseInt(process.env.GEA_STATIC_CSS_TAPE_MIN_CHUNK ?? '5', 10) || 1)
79
+ const buildConfigPath = readOption('--build-config') ?? process.env.GEA_BUILD_CONFIG_JSON
80
+ const nativeBuildSettings = buildConfigPath
81
+ ? JSON.parse(fs.readFileSync(path.resolve(buildConfigPath), 'utf8')).settings || {}
82
+ : {}
83
+ const compilerSettings = nativeBuildSettings.compiler || {}
84
+ for (const name of ['GEA_STATIC_CSS_RULES', 'GEA_STATIC_CSS_TAPE', 'GEA_STATIC_CSS_TAPE_MIN_CHUNK', 'GEA_CPP_TRANSLATION_UNITS', 'GEA_PER_FILE_UNITS', 'GEA_SKIP_STORE_RELOWER', 'GEA_EMBEDDED_DIRECT_CANVAS_CONTEXT', 'GEA_EMBEDDED_NUMBER_F32']) {
85
+ if (process.env[name] !== undefined) fail(`${name} is no longer a build override; declare compiler settings in package.json and build through gea`)
86
+ }
87
+ const useStaticCssRules = compilerSettings.staticCssRules ?? true
88
+ const useStaticCssTape = compilerSettings.staticCssTape ?? true
89
+ const staticCssTapeMinChunk = compilerSettings.staticCssTapeMinChunk ?? 5
81
90
 
82
91
  function readOption(name) {
83
92
  const index = args.indexOf(name)
@@ -360,6 +369,7 @@ function stateRuntimeAliasToTypeScript(stagedAppDir, compatSrcDir, stagingRoot)
360
369
  }
361
370
  }
362
371
  const options = config.compilerOptions ?? (config.compilerOptions = {})
372
+ normalizeEmbeddedJsxOptions(options)
363
373
  options.baseUrl = options.baseUrl ?? '.'
364
374
  const base = path.resolve(stagedAppDir, options.baseUrl)
365
375
  // Both specifiers, because the Vite config aliases both to the same
@@ -458,23 +468,8 @@ function writeCompatViteConfig({ configPath, compatSrcDir, appDir, entry, viteOu
458
468
  // whole reactive runtime dynamically (gea_cpp_value, ill-formed auto-vectors,
459
469
  // proxy derefs). From source, everything is typed and lowers natively, exactly
460
470
  // like three.js/hono/mongodb. The env var still wins when explicitly set;
461
- // otherwise resolve the package's source entry via its node_modules symlink.
462
- let compilerRuntimeEntry = process.env.GEA_COMPILER_RUNTIME_SOURCE || ''
463
- if (!compilerRuntimeEntry) {
464
- for (const base of [appDir, coreRoot]) {
465
- try {
466
- const pkgDir = fs.realpathSync(path.join(base, 'node_modules/@geajs/core'))
467
- const srcIndex = path.join(pkgDir, 'src/index.ts')
468
- if (fs.existsSync(srcIndex) && fs.existsSync(path.join(pkgDir, 'src/compiler-runtime.ts'))) {
469
- compilerRuntimeEntry = srcIndex
470
- break
471
- }
472
- } catch {
473
- // No @geajs/core source under this base (e.g. published-only install) —
474
- // fall through; the alias stays empty and the dist runtime is used.
475
- }
476
- }
477
- }
471
+ // otherwise follow ordinary package resolution, including hoisted installs.
472
+ const compilerRuntimeEntry = process.env.GEA_COMPILER_RUNTIME_SOURCE || resolveCompilerRuntimeEntry([appDir, coreRoot])
478
473
  const compilerRuntimeAlias = compilerRuntimeEntry && fs.existsSync(compilerRuntimeEntry)
479
474
  ? ` { find: new RegExp('^@geajs/core$'), replacement: ${q(compilerRuntimeEntry)} },\n`
480
475
  : ''
@@ -4275,11 +4270,14 @@ const viteBin = path.resolve(readOption('--vite-bin') ?? path.join(path.dirname(
4275
4270
  const viteOutDir = path.resolve(readOption('--vite-out-dir') ?? path.join(outDir, 'dist'))
4276
4271
  const bundlePath = path.resolve(readOption('--bundle-out') ?? path.join(outDir, 'gea-vite-bundle.js'))
4277
4272
  const geaIrPath = path.resolve(readOption('--gea-ir-out') ?? path.join(viteOutDir, 'gea-ir.json'))
4278
- const moduleGraphOutOption = readOption('--module-graph-out') ?? process.env.GEA_VITE_MODULE_GRAPH_OUT
4279
- const moduleGraphOnly = hasFlag('--module-graph-only')
4280
- const moduleGraphCompileRequested = hasFlag('--compile-module-graph')
4281
- const moduleGraphCompileDisabled = hasFlag('--no-compile-module-graph')
4282
- const geaPluginSpecifier = path.resolve(readOption('--geatsc-gea-plugin') ?? requireFromLib.resolve('@geastack/geatsc-plugin-gea'))
4273
+ const moduleGraphOutOption = readOption('--module-graph-out') ?? (compilerSettings.moduleGraph === 'only' || compilerSettings.moduleGraph === 'compile' ? path.join(outDir, 'module-graph') : undefined) ?? process.env.GEA_VITE_MODULE_GRAPH_OUT
4274
+ const moduleGraphOnly = hasFlag('--module-graph-only') || compilerSettings.moduleGraph === 'only'
4275
+ const moduleGraphCompileRequested = hasFlag('--compile-module-graph') || compilerSettings.moduleGraph === 'compile'
4276
+ const moduleGraphCompileDisabled = hasFlag('--no-compile-module-graph') || compilerSettings.moduleGraph === 'disabled'
4277
+ const geaPluginSpecifier = path.resolve(
4278
+ readOption('--geatsc-gea-plugin') ??
4279
+ (process.env.GEA_PLUGIN_DIR ? path.join(process.env.GEA_PLUGIN_DIR, 'dist/index.js') : undefined) ??
4280
+ requireFromLib.resolve('@geastack/geatsc-plugin-gea'))
4283
4281
  const extraGeatscPlugins = readAllOptions('--extra-geatsc-plugin').map((plugin) => path.resolve(plugin))
4284
4282
  const appendJsFiles = readAllOptions('--append-js').map((file) => path.resolve(file))
4285
4283
  const entry = readOption('--entry') ?? 'index.tsx'
@@ -4568,21 +4566,17 @@ if (cppPreludeSymbol) geatscArgs.push('--plugin-option', `gea.cpp-prelude-symbol
4568
4566
  if (pixelPanelEndian) geatscArgs.push('--plugin-option', `gea.pixel-panel-endian=${pixelPanelEndian}`)
4569
4567
  if (cppBoard) geatscArgs.push('--cpp-board', cppBoard)
4570
4568
  if (cxxStandard) geatscArgs.push('--cxx-standard', cxxStandard)
4571
- if (hasFlag('--allow-any')) geatscArgs.push('--allow-any')
4569
+ if (hasFlag('--allow-any') || compilerSettings.allowAny) geatscArgs.push('--allow-any')
4572
4570
  if (entrySymbol) geatscArgs.push('--entry-symbol', entrySymbol)
4573
4571
  if (hasFlag('--isolate-symbols')) geatscArgs.push('--isolate-symbols')
4574
4572
  // One C++ unit per source module plus a shared header, instead of one unit for
4575
4573
  // the whole program. Every target already reads `geatsc-sources.txt` as a LIST,
4576
4574
  // so nothing downstream changes; see the compiler's docs/TRANSLATION-UNITS.md
4577
4575
  // for what it buys (parallel and incremental C++ builds) and what it costs.
4578
- // The env var is honored beside the flag so a target need not plumb one: every
4579
- // build in the tree goes through this script, and the boards' CMakeLists spell
4580
- // their geatsc command line by hand, so an env var reaches all of them at once
4581
- // (`GEA_PER_FILE_UNITS=1 <any build>`). build-macos.sh sets the flag itself and
4582
- // folds the variable into its freshness signature, because a layout change
4583
- // invalidates every generated file.
4584
- if (process.env.GEA_CPP_TRANSLATION_UNITS === 'balanced') geatscArgs.push('--translation-units', 'balanced')
4585
- else if (hasFlag('--per-file-units') || process.env.GEA_PER_FILE_UNITS === '1') geatscArgs.push('--translation-units', 'per-file')
4576
+ const translationUnits = readOption('--translation-units') ?? compilerSettings.translationUnits
4577
+ if (translationUnits === 'balanced') geatscArgs.push('--translation-units', 'balanced')
4578
+ else if (hasFlag('--per-file-units') || translationUnits === 'per-file') geatscArgs.push('--translation-units', 'per-file')
4579
+ geatscArgs.push('--plugin-option', `gea.store-relowering=${compilerSettings.storeRelowering !== false}`)
4586
4580
  if (hasFlag('--gea-ir-backend') || hasFlag('--gea-replace-renderers')) {
4587
4581
  geatscArgs.push('--plugin-option', 'gea.replace-renderers=true')
4588
4582
  }
@@ -15,3 +15,11 @@ const ignoredDirectorySet = new Set(COMPAT_STAGING_IGNORED_DIRECTORIES)
15
15
  export function shouldIgnoreCompatStagingDirectory(name) {
16
16
  return ignoredDirectorySet.has(name)
17
17
  }
18
+
19
+ // The browser JSX runtime declares Element as `any`. Embedded components are
20
+ // lowered through @geastack/core's typed global JSX namespace instead. Match
21
+ // the Component/Store import conversion without altering custom JSX providers
22
+ // or the application's original web tsconfig.
23
+ export function normalizeEmbeddedJsxOptions(options) {
24
+ if (options.jsxImportSource === '@geajs/core') delete options.jsxImportSource
25
+ }
@@ -151,7 +151,7 @@ function normalizeRuntimeCoreImports(ast) {
151
151
  const movedSpecs = []
152
152
 
153
153
  for (const node of ast.program.body) {
154
- if (!t.isImportDeclaration(node) || node.source.value !== '@geastack/core') {
154
+ if (!t.isImportDeclaration(node) || !['@geastack/core', '@geajs/core'].includes(node.source.value)) {
155
155
  nextBody.push(node)
156
156
  continue
157
157
  }
@@ -213,7 +213,7 @@ function transformTopLevelStatement(stmt) {
213
213
  }
214
214
 
215
215
  export function transformGeaEmbeddedCompatSource(code, filename) {
216
- if ((!code.includes('<') || !code.includes('>')) && !code.includes('@geastack/core')) return code
216
+ if ((!code.includes('<') || !code.includes('>')) && !code.includes('@geastack/core') && !code.includes('@geajs/core')) return code
217
217
 
218
218
  const ast = parser.parse(code, {
219
219
  sourceType: 'module',
@@ -1,5 +1,23 @@
1
1
  import fs from 'node:fs'
2
2
  import path from 'node:path'
3
+ import { createRequire } from 'node:module'
4
+
5
+ // Follow Node's node_modules search chain, including hoisted workspace installs.
6
+ // package.json need not be exposed by the package's exports map.
7
+ export function resolveCompilerRuntimeEntry(bases) {
8
+ for (const base of bases) {
9
+ const require = createRequire(path.join(path.resolve(base), 'package.json'))
10
+ for (const modules of require.resolve.paths('@geajs/core') || []) {
11
+ const source = path.join(modules, '@geajs/core/src')
12
+ const entry = path.join(source, 'index.ts')
13
+ if (fs.existsSync(entry) && fs.existsSync(path.join(source, 'compiler-runtime.ts')))
14
+ return fs.realpathSync(entry)
15
+ // An installed package shadows ancestors, even if it lacks typed sources.
16
+ if (fs.existsSync(path.join(modules, '@geajs/core/package.json'))) break
17
+ }
18
+ }
19
+ return ''
20
+ }
3
21
 
4
22
  /** Native lengths are raw numbers; only an authored CSS unit may introduce scaling. */
5
23
  export function geaNativeStylePlugin({ runtimeEntry }) {