@lincyaw/web 1.0.0-rc.8 → 1.0.0-rc.9

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": "@lincyaw/web",
3
- "version": "1.0.0-rc.8",
3
+ "version": "1.0.0-rc.9",
4
4
  "description": "Presmium's web renderer: one prebuilt viewer that shows the web form in the workbench, in a dev server and as a built site, with search and form switching",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -41,21 +41,21 @@
41
41
  "vite": "8.3.4",
42
42
  "react": "18.3.1",
43
43
  "react-dom": "18.3.1",
44
- "@lincyaw/design": "1.0.0-rc.8"
44
+ "@lincyaw/design": "1.0.0-rc.9"
45
45
  },
46
46
  "peerDependencies": {
47
- "@lincyaw/host": "^1.0.0-rc.8",
48
- "@lincyaw/kernel": "^1.0.0-rc.8",
49
- "@lincyaw/viewer": "^1.0.0-rc.8"
47
+ "@lincyaw/viewer": "^1.0.0-rc.9",
48
+ "@lincyaw/kernel": "^1.0.0-rc.9",
49
+ "@lincyaw/host": "^1.0.0-rc.9"
50
50
  },
51
51
  "devDependencies": {
52
52
  "@types/escape-html": "1.0.4",
53
53
  "@types/send": "^1.2.1",
54
54
  "@types/react": "18.3.28",
55
55
  "@types/react-dom": "18.3.7",
56
- "@lincyaw/cli": "1.0.0-rc.8",
57
- "@lincyaw/host": "1.0.0-rc.8",
58
- "@lincyaw/viewer": "1.0.0-rc.8",
59
- "@lincyaw/kernel": "1.0.0-rc.8"
56
+ "@lincyaw/cli": "1.0.0-rc.9",
57
+ "@lincyaw/kernel": "1.0.0-rc.9",
58
+ "@lincyaw/host": "1.0.0-rc.9",
59
+ "@lincyaw/viewer": "1.0.0-rc.9"
60
60
  }
61
61
  }
package/src/app/main.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { currentLocale, OPERATIONS, pluginsOf, presmiumService, registerPresmiumPlugin, startHost, createStore, observe, runtimeRevision } from '@lincyaw/host'
2
- import { previewAppearance } from '@lincyaw/kernel'
2
+ import { previewAppearance, reportStaleModule } from '@lincyaw/kernel'
3
3
  import type { IRDocument } from '@lincyaw/kernel'
4
4
  import { findView, syncViewerWithOperations } from '@lincyaw/viewer'
5
5
  import type { LiveUpdate } from '@lincyaw/viewer/domain'
@@ -83,6 +83,7 @@ async function bootPage(): Promise<void> {
83
83
  dark.set(isDark())
84
84
  const modules = await Promise.all(used(config.plugins ?? []).flatMap(([, own]) => own.plugins).map(load => load().catch((error: unknown) => {
85
85
  console.error('[presmium] a plugin module failed to load', error)
86
+ reportStaleModule(error)
86
87
  return {}
87
88
  })))
88
89
  modules.flatMap(module => pluginsOf(module)).forEach(registerPresmiumPlugin)
@@ -1,6 +1,6 @@
1
1
  import { componentErrors, createServerClient, pluginsOf, presmiumReport, provideServer, registerPresmiumPlugin, reportPluginFailure, setHostActive, startHost } from '@lincyaw/host'
2
2
  import type { ServerClient, SharedStates, SyncTransports } from '@lincyaw/host'
3
- import { errorMessage } from '@lincyaw/kernel'
3
+ import { errorMessage, reportStaleModule } from '@lincyaw/kernel'
4
4
  import type { IRDocument } from '@lincyaw/kernel'
5
5
  import { PmComponentFallback, tryInstallViewerPlugin, withSlideGlobals } from '@lincyaw/viewer'
6
6
  import type { Viewer } from '@lincyaw/viewer'
@@ -31,6 +31,7 @@ export async function startRuntime(loaders: RuntimeModules['plugins'], doc: IRDo
31
31
  const modules = await Promise.all(loaders.map(load => load().catch((error) => {
32
32
  failed = true
33
33
  console.error('[presmium] a plugin module failed to load', error)
34
+ reportStaleModule(error)
34
35
  return {}
35
36
  })))
36
37
  const plugins = modules.flatMap(module => pluginsOf(module))
@@ -33,6 +33,24 @@ const APPEARANCE = `(() => {
33
33
  if (asked === 'dark' || (asked !== 'light' && matchMedia('(prefers-color-scheme: dark)').matches)) document.documentElement.classList.add('dark')
34
34
  })()`
35
35
 
36
+ /**
37
+ * A page cached before a new deployment names an app version the deployment removed: its scripts and the modules they
38
+ * import then fail. The page loads once more, from the network, and gets the current version; at most once in 30 s.
39
+ */
40
+ const STALE = `(() => {
41
+ const key = 'presmium-stale-reload'
42
+ const reload = () => {
43
+ let last = 0
44
+ try { last = Number(sessionStorage.getItem(key)) || 0 } catch {}
45
+ if (Date.now() - last < 30000) return
46
+ try { sessionStorage.setItem(key, String(Date.now())) } catch {}
47
+ location.reload()
48
+ }
49
+ addEventListener('vite:preloadError', (event) => { event.preventDefault(); reload() })
50
+ addEventListener('unhandledrejection', (event) => { if (/dynamically imported module|Importing a module script failed|error loading dynamically imported module/i.test(String(event.reason && event.reason.message || event.reason))) reload() })
51
+ addEventListener('error', (event) => { const el = event.target; if (el && el.tagName === 'SCRIPT' && el.type === 'module') reload() }, true)
52
+ })()`
53
+
36
54
  const json = (value: unknown) => JSON.stringify(value).replace(/</g, '\\u003c')
37
55
 
38
56
  export function pageHtml(input: PageHtmlInput): string {
@@ -45,6 +63,7 @@ export function pageHtml(input: PageHtmlInput): string {
45
63
  `<title>${escapeHtml(input.title)}</title>`,
46
64
  ...(input.meta ?? []).map(tag => `<meta ${attributes(tag)}>`),
47
65
  `<script>${APPEARANCE}</script>`,
66
+ `<script>${STALE}</script>`,
48
67
  `<script type="importmap">${json({ imports })}</script>`,
49
68
  ...entry.css.map(file => `<link rel="stylesheet" href="${escapeHtml(`${appUrl}${file}`)}">`),
50
69
  // A workspace theme's fonts, tokens and styles come after the app's, so that they override them.