Files
dsh-context/scripts/build.mjs
T
bowenliang123 cd7282ad53 refactor: package dsh-context as an installable dsh bundle
- src/host.js: ESM Cordis plugin; serve snapshots over the generic
  Connection RPC channel /dsh-context (ctx.connection.rpc) instead of the
  dynamic-runner harness.handle seat; lazily resolve sessions/sessionQuery.
- src/client.js: browser half in web-boot bundle shape (require('react'),
  inject connection/slots/locale, plugin-owned style tag, setInterval poll).
- package.json: dsh.bundle (cordis.patch.yml layer) + dsh.client (web UI)
  manifests, ./client export.
- cordis.patch.yml: inserts the dsh-context loader row.
- scripts/build.mjs: zero-dependency build of lib/index.js + lib/client.js
  with smoke checks; scripts/test-host.mjs + scripts/test-client.mjs:
  functional tests for both halves.
- scripts/publish.sh: npm publish driven by NPM_TOKEN, auto version bump.
2026-08-14 17:11:56 +08:00

59 lines
2.4 KiB
JavaScript
Executable File

#!/usr/bin/env node
/**
* dsh-context build — zero-dependency.
*
* Produces the npm-package artifacts under lib/:
* lib/index.js — host half: src/host.js verbatim (plain ESM Cordis plugin).
* lib/client.js — client half: src/client.js wrapped in the web boot
* handoff `window.__ModuleLoader__.load({ id, factory })`,
* the closure-factory format every `dsh.client` package's
* `./client` export must use (React and other platform
* modules arrive through the injected `require`).
*
* Also runs smoke checks: both outputs must parse, and the host half must
* import with the expected plugin shape.
*/
import { mkdir, readFile, writeFile } from 'node:fs/promises'
import { dirname, join } from 'node:path'
import { fileURLToPath } from 'node:url'
const ROOT = join(dirname(fileURLToPath(import.meta.url)), '..')
const pkg = JSON.parse(await readFile(join(ROOT, 'package.json'), 'utf8'))
await mkdir(join(ROOT, 'lib'), { recursive: true })
// ---- host half: verbatim copy ----
const hostSource = await readFile(join(ROOT, 'src', 'host.js'), 'utf8')
await writeFile(join(ROOT, 'lib', 'index.js'), hostSource)
// ---- client half: closure-factory bundle ----
const clientSource = await readFile(join(ROOT, 'src', 'client.js'), 'utf8')
const bundle = [
'/* dsh-context client bundle — generated by scripts/build.mjs from src/client.js */',
'window.__ModuleLoader__.load({',
` id: ${JSON.stringify(pkg.name)},`,
' factory: (require) => {',
' var module = { exports: {} };',
' var exports = module.exports;',
clientSource.replace(/\s+$/, '\n'),
' return module.exports;',
' },',
'});',
'',
].join('\n')
await writeFile(join(ROOT, 'lib', 'client.js'), bundle)
// ---- smoke checks ----
new Function(bundle) // syntax parse only; never executes (window is undefined here)
const host = await import(join(ROOT, 'lib', 'index.js'))
if (host.name !== 'dsh-context' || !Array.isArray(host.inject) || typeof host.apply !== 'function') {
throw new Error('host half does not expose the expected plugin shape (name/inject/apply)')
}
if (host.inject.includes('connection') !== true) {
throw new Error('host half must inject the connection service')
}
console.log(`built ${pkg.name}:`)
console.log(' lib/index.js (host half, ESM)')
console.log(' lib/client.js (client half, __ModuleLoader__ closure bundle)')