cordisx 0.1.0-beta.23 → 0.1.0-beta.24

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 (259) hide show
  1. package/THIRD_PARTY_NOTICES.md +7 -0
  2. package/dist/assets/icons/lucide-0.468.0/brain.svg +21 -0
  3. package/dist/native/CordisXEntry +0 -0
  4. package/dist/native/CordisXHostOpen +0 -0
  5. package/dist/native/CordisXLauncher +0 -0
  6. package/dist/native/CordisXStartupGate +0 -0
  7. package/dist/native/dock-agent.cjs +181 -0
  8. package/dist/native/native-helper-artifact.json +78 -0
  9. package/dist/native/startup-cover.cjs +272 -0
  10. package/dist/native/startup-cover.css +78 -0
  11. package/dist/native/startup-loading.html +17 -0
  12. package/dist/native/startup-navigation.cjs +166 -0
  13. package/dist/native/visibility-agent.cjs +224 -0
  14. package/dist/src/cli/host-lifecycle.d.ts +2 -0
  15. package/dist/src/cli/host-lifecycle.d.ts.map +1 -1
  16. package/dist/src/cli/host-lifecycle.js.map +1 -1
  17. package/dist/src/cli/native-submission-catalog-options.d.ts +8 -1
  18. package/dist/src/cli/native-submission-catalog-options.d.ts.map +1 -1
  19. package/dist/src/cli/native-submission-catalog-options.js +6 -2
  20. package/dist/src/cli/native-submission-catalog-options.js.map +1 -1
  21. package/dist/src/cli/renderer-composition.d.ts +1 -1
  22. package/dist/src/cli/run-command-dispatch.d.ts.map +1 -1
  23. package/dist/src/cli/run-command-dispatch.js +2 -2
  24. package/dist/src/cli/run-command-dispatch.js.map +1 -1
  25. package/dist/src/cli/run-command.d.ts.map +1 -1
  26. package/dist/src/cli/run-command.js +12 -2
  27. package/dist/src/cli/run-command.js.map +1 -1
  28. package/dist/src/cli/run-injected-host.d.ts +74 -0
  29. package/dist/src/cli/run-injected-host.d.ts.map +1 -0
  30. package/dist/src/cli/run-injected-host.js +218 -0
  31. package/dist/src/cli/run-injected-host.js.map +1 -0
  32. package/dist/src/cli/run-runtime.d.ts +81 -0
  33. package/dist/src/cli/run-runtime.d.ts.map +1 -0
  34. package/dist/src/cli/run-runtime.js +44 -0
  35. package/dist/src/cli/run-runtime.js.map +1 -0
  36. package/dist/src/cli/run-support.d.ts +4 -155
  37. package/dist/src/cli/run-support.d.ts.map +1 -1
  38. package/dist/src/cli/run-support.js +111 -280
  39. package/dist/src/cli/run-support.js.map +1 -1
  40. package/dist/src/cli/supervisor-runtime.d.ts +6 -0
  41. package/dist/src/cli/supervisor-runtime.d.ts.map +1 -1
  42. package/dist/src/cli/supervisor-runtime.js +29 -3
  43. package/dist/src/cli/supervisor-runtime.js.map +1 -1
  44. package/dist/src/config/home-config-profile-private.d.ts +7 -0
  45. package/dist/src/config/home-config-profile-private.d.ts.map +1 -0
  46. package/dist/src/config/home-config-profile-private.js +60 -0
  47. package/dist/src/config/home-config-profile-private.js.map +1 -0
  48. package/dist/src/config/home-config.d.ts +4 -0
  49. package/dist/src/config/home-config.d.ts.map +1 -1
  50. package/dist/src/config/home-config.js +5 -25
  51. package/dist/src/config/home-config.js.map +1 -1
  52. package/dist/src/launcher/cdp-installation-bootstrap.d.ts +1 -0
  53. package/dist/src/launcher/cdp-installation-bootstrap.d.ts.map +1 -1
  54. package/dist/src/launcher/cdp-installation-bootstrap.js +50 -5
  55. package/dist/src/launcher/cdp-installation-bootstrap.js.map +1 -1
  56. package/dist/src/launcher/cdp-installation.d.ts +1 -1
  57. package/dist/src/launcher/cdp-installation.d.ts.map +1 -1
  58. package/dist/src/launcher/cdp-installation.js +2 -1
  59. package/dist/src/launcher/cdp-installation.js.map +1 -1
  60. package/dist/src/launcher/cdp.d.ts +3 -0
  61. package/dist/src/launcher/cdp.d.ts.map +1 -1
  62. package/dist/src/launcher/cdp.js +47 -1
  63. package/dist/src/launcher/cdp.js.map +1 -1
  64. package/dist/src/launcher/codex-config-model-providers.d.ts +3 -0
  65. package/dist/src/launcher/codex-config-model-providers.d.ts.map +1 -1
  66. package/dist/src/launcher/codex-config-model-providers.js +13 -5
  67. package/dist/src/launcher/codex-config-model-providers.js.map +1 -1
  68. package/dist/src/launcher/managed-service-native-publications.d.ts +3 -0
  69. package/dist/src/launcher/managed-service-native-publications.d.ts.map +1 -1
  70. package/dist/src/launcher/managed-service-native-publications.js +18 -1
  71. package/dist/src/launcher/managed-service-native-publications.js.map +1 -1
  72. package/dist/src/launcher/managed-service-node-host.d.ts +1 -0
  73. package/dist/src/launcher/managed-service-node-host.d.ts.map +1 -1
  74. package/dist/src/launcher/managed-service-node-host.js +1 -0
  75. package/dist/src/launcher/managed-service-node-host.js.map +1 -1
  76. package/dist/src/launcher/managed-service-plugin-lifecycle.d.ts +6 -1
  77. package/dist/src/launcher/managed-service-plugin-lifecycle.d.ts.map +1 -1
  78. package/dist/src/launcher/managed-service-plugin-lifecycle.js +20 -1
  79. package/dist/src/launcher/managed-service-plugin-lifecycle.js.map +1 -1
  80. package/dist/src/launcher/managed-service-registration.d.ts +22 -0
  81. package/dist/src/launcher/managed-service-registration.d.ts.map +1 -0
  82. package/dist/src/launcher/managed-service-registration.js +134 -0
  83. package/dist/src/launcher/managed-service-registration.js.map +1 -0
  84. package/dist/src/launcher/managed-service-runtime-binding.d.ts +33 -0
  85. package/dist/src/launcher/managed-service-runtime-binding.d.ts.map +1 -0
  86. package/dist/src/launcher/managed-service-runtime-binding.js +72 -0
  87. package/dist/src/launcher/managed-service-runtime-binding.js.map +1 -0
  88. package/dist/src/launcher/managed-service-runtime.d.ts +4 -14
  89. package/dist/src/launcher/managed-service-runtime.d.ts.map +1 -1
  90. package/dist/src/launcher/managed-service-runtime.js +35 -196
  91. package/dist/src/launcher/managed-service-runtime.js.map +1 -1
  92. package/dist/src/launcher/model-catalog/configured-source.d.ts.map +1 -1
  93. package/dist/src/launcher/model-catalog/configured-source.js +13 -2
  94. package/dist/src/launcher/model-catalog/configured-source.js.map +1 -1
  95. package/dist/src/launcher/model-catalog/deepseek.d.ts.map +1 -1
  96. package/dist/src/launcher/model-catalog/deepseek.js +7 -2
  97. package/dist/src/launcher/model-catalog/deepseek.js.map +1 -1
  98. package/dist/src/launcher/model-catalog/managed-catalog-composition.d.ts +6 -0
  99. package/dist/src/launcher/model-catalog/managed-catalog-composition.d.ts.map +1 -1
  100. package/dist/src/launcher/model-catalog/managed-catalog-composition.js +185 -64
  101. package/dist/src/launcher/model-catalog/managed-catalog-composition.js.map +1 -1
  102. package/dist/src/launcher/model-catalog/managed-catalog-state.d.ts +2 -6
  103. package/dist/src/launcher/model-catalog/managed-catalog-state.d.ts.map +1 -1
  104. package/dist/src/launcher/model-catalog/managed-catalog-state.js +12 -53
  105. package/dist/src/launcher/model-catalog/managed-catalog-state.js.map +1 -1
  106. package/dist/src/launcher/model-catalog/managed-provider-owner.d.ts +7 -4
  107. package/dist/src/launcher/model-catalog/managed-provider-owner.d.ts.map +1 -1
  108. package/dist/src/launcher/model-catalog/managed-provider-owner.js +221 -119
  109. package/dist/src/launcher/model-catalog/managed-provider-owner.js.map +1 -1
  110. package/dist/src/launcher/model-catalog/managed-provider-schema.d.ts +1 -1
  111. package/dist/src/launcher/model-catalog/managed-provider-schema.d.ts.map +1 -1
  112. package/dist/src/launcher/model-catalog/native-catalog-management.d.ts +4 -0
  113. package/dist/src/launcher/model-catalog/native-catalog-management.d.ts.map +1 -1
  114. package/dist/src/launcher/model-catalog/native-catalog-management.js +79 -33
  115. package/dist/src/launcher/model-catalog/native-catalog-management.js.map +1 -1
  116. package/dist/src/launcher/model-catalog/openrouter.d.ts.map +1 -1
  117. package/dist/src/launcher/model-catalog/openrouter.js +6 -4
  118. package/dist/src/launcher/model-catalog/openrouter.js.map +1 -1
  119. package/dist/src/launcher/model-catalog/plugin-preference-source.d.ts +10 -0
  120. package/dist/src/launcher/model-catalog/plugin-preference-source.d.ts.map +1 -0
  121. package/dist/src/launcher/model-catalog/plugin-preference-source.js +37 -0
  122. package/dist/src/launcher/model-catalog/plugin-preference-source.js.map +1 -0
  123. package/dist/src/launcher/native-submission-composition.d.ts +7 -2
  124. package/dist/src/launcher/native-submission-composition.d.ts.map +1 -1
  125. package/dist/src/launcher/native-submission-composition.js +62 -11
  126. package/dist/src/launcher/native-submission-composition.js.map +1 -1
  127. package/dist/src/launcher/process-identity.d.ts +17 -2
  128. package/dist/src/launcher/process-identity.d.ts.map +1 -1
  129. package/dist/src/launcher/process-identity.js +126 -27
  130. package/dist/src/launcher/process-identity.js.map +1 -1
  131. package/dist/src/launcher/secret-store.d.ts +15 -1
  132. package/dist/src/launcher/secret-store.d.ts.map +1 -1
  133. package/dist/src/launcher/secret-store.js +92 -13
  134. package/dist/src/launcher/secret-store.js.map +1 -1
  135. package/dist/src/launcher/vite-development-generation.d.ts +2 -0
  136. package/dist/src/launcher/vite-development-generation.d.ts.map +1 -1
  137. package/dist/src/launcher/vite-development-generation.js +17 -10
  138. package/dist/src/launcher/vite-development-generation.js.map +1 -1
  139. package/dist/src/launcher/vite-development.d.ts +12 -0
  140. package/dist/src/launcher/vite-development.d.ts.map +1 -1
  141. package/dist/src/launcher/vite-development.js +153 -114
  142. package/dist/src/launcher/vite-development.js.map +1 -1
  143. package/dist/src/model-catalog/management-overlay.d.ts +25 -13
  144. package/dist/src/model-catalog/management-overlay.d.ts.map +1 -1
  145. package/dist/src/model-catalog/management-overlay.js +108 -52
  146. package/dist/src/model-catalog/management-overlay.js.map +1 -1
  147. package/dist/src/model-catalog/plugin-preference-authority.d.ts +82 -0
  148. package/dist/src/model-catalog/plugin-preference-authority.d.ts.map +1 -0
  149. package/dist/src/model-catalog/plugin-preference-authority.js +394 -0
  150. package/dist/src/model-catalog/plugin-preference-authority.js.map +1 -0
  151. package/dist/src/model-catalog-management.d.ts +23 -2
  152. package/dist/src/model-catalog-management.d.ts.map +1 -1
  153. package/dist/src/model-catalog-management.js +26 -1
  154. package/dist/src/model-catalog-management.js.map +1 -1
  155. package/dist/src/renderer/adapter/native-model-list.d.ts +32 -0
  156. package/dist/src/renderer/adapter/native-model-list.d.ts.map +1 -0
  157. package/dist/src/renderer/adapter/native-model-list.js +114 -0
  158. package/dist/src/renderer/adapter/native-model-list.js.map +1 -0
  159. package/dist/src/renderer/adapter/native-model-provider-interaction.d.ts +0 -1
  160. package/dist/src/renderer/adapter/native-model-provider-interaction.d.ts.map +1 -1
  161. package/dist/src/renderer/adapter/native-model-provider-interaction.js +8 -0
  162. package/dist/src/renderer/adapter/native-model-provider-interaction.js.map +1 -1
  163. package/dist/src/renderer/certified-permission-channel.d.ts +2 -1
  164. package/dist/src/renderer/certified-permission-channel.d.ts.map +1 -1
  165. package/dist/src/renderer/certified-permission-channel.js +13 -2
  166. package/dist/src/renderer/certified-permission-channel.js.map +1 -1
  167. package/dist/src/renderer/host-ui/BrainIcon.d.ts +5 -0
  168. package/dist/src/renderer/host-ui/BrainIcon.d.ts.map +1 -0
  169. package/dist/src/renderer/host-ui/BrainIcon.js +21 -0
  170. package/dist/src/renderer/host-ui/BrainIcon.js.map +1 -0
  171. package/dist/src/renderer/host-ui/HostMenu.d.ts +2 -1
  172. package/dist/src/renderer/host-ui/HostMenu.d.ts.map +1 -1
  173. package/dist/src/renderer/host-ui/HostMenu.js +56 -12
  174. package/dist/src/renderer/host-ui/HostMenu.js.map +1 -1
  175. package/dist/src/renderer/host-ui/MoreMenu.d.ts +2 -1
  176. package/dist/src/renderer/host-ui/MoreMenu.d.ts.map +1 -1
  177. package/dist/src/renderer/host-ui/MoreMenu.js +2 -2
  178. package/dist/src/renderer/host-ui/MoreMenu.js.map +1 -1
  179. package/dist/src/renderer/manager/pages/ModelServicesPage.d.ts.map +1 -1
  180. package/dist/src/renderer/manager/pages/ModelServicesPage.js +81 -18
  181. package/dist/src/renderer/manager/pages/ModelServicesPage.js.map +1 -1
  182. package/dist/src/renderer/manager/pages/model-catalog/CatalogBinding.d.ts +5 -3
  183. package/dist/src/renderer/manager/pages/model-catalog/CatalogBinding.d.ts.map +1 -1
  184. package/dist/src/renderer/manager/pages/model-catalog/CatalogBinding.js +84 -56
  185. package/dist/src/renderer/manager/pages/model-catalog/CatalogBinding.js.map +1 -1
  186. package/dist/src/renderer/manager/pages/model-catalog/model-catalog.css +268 -27
  187. package/dist/src/renderer/manager/pages/model-catalog/model-service-list.d.ts +5 -0
  188. package/dist/src/renderer/manager/pages/model-catalog/model-service-list.d.ts.map +1 -0
  189. package/dist/src/renderer/manager/pages/model-catalog/model-service-list.js +28 -0
  190. package/dist/src/renderer/manager/pages/model-catalog/model-service-list.js.map +1 -0
  191. package/dist/src/renderer/manager/pages/model-services.css +66 -12
  192. package/dist/src/renderer/model-catalog-client.d.ts.map +1 -1
  193. package/dist/src/renderer/model-catalog-client.js +2 -1
  194. package/dist/src/renderer/model-catalog-client.js.map +1 -1
  195. package/dist/src/renderer/model-catalog-projection.d.ts.map +1 -1
  196. package/dist/src/renderer/model-catalog-projection.js +22 -3
  197. package/dist/src/renderer/model-catalog-projection.js.map +1 -1
  198. package/dist/src/renderer/model-provider-copy.d.ts +2 -0
  199. package/dist/src/renderer/model-provider-copy.d.ts.map +1 -1
  200. package/dist/src/renderer/model-provider-copy.js +4 -0
  201. package/dist/src/renderer/model-provider-copy.js.map +1 -1
  202. package/dist/src/renderer/model-provider-preferences.d.ts +29 -0
  203. package/dist/src/renderer/model-provider-preferences.d.ts.map +1 -0
  204. package/dist/src/renderer/model-provider-preferences.js +33 -0
  205. package/dist/src/renderer/model-provider-preferences.js.map +1 -0
  206. package/dist/src/renderer/model-provider-reasoning.d.ts +2 -1
  207. package/dist/src/renderer/model-provider-reasoning.d.ts.map +1 -1
  208. package/dist/src/renderer/model-provider-reasoning.js +149 -31
  209. package/dist/src/renderer/model-provider-reasoning.js.map +1 -1
  210. package/dist/src/renderer/model-provider-selector.d.ts +22 -6
  211. package/dist/src/renderer/model-provider-selector.d.ts.map +1 -1
  212. package/dist/src/renderer/model-provider-selector.js +183 -57
  213. package/dist/src/renderer/model-provider-selector.js.map +1 -1
  214. package/dist/src/renderer/model-providers.css +292 -32
  215. package/dist/src/renderer/model-providers.d.ts +8 -1
  216. package/dist/src/renderer/model-providers.d.ts.map +1 -1
  217. package/dist/src/renderer/model-providers.js +19 -3
  218. package/dist/src/renderer/model-providers.js.map +1 -1
  219. package/dist/src/renderer/native-model-provider-transport.d.ts +8 -0
  220. package/dist/src/renderer/native-model-provider-transport.d.ts.map +1 -1
  221. package/dist/src/renderer/native-model-provider-transport.js +74 -3
  222. package/dist/src/renderer/native-model-provider-transport.js.map +1 -1
  223. package/dist/src/renderer/native-provider-submission-policy.d.ts +19 -0
  224. package/dist/src/renderer/native-provider-submission-policy.d.ts.map +1 -1
  225. package/dist/src/renderer/native-provider-submission-policy.js +18 -0
  226. package/dist/src/renderer/native-provider-submission-policy.js.map +1 -1
  227. package/dist/src/renderer/runtime-install.d.ts +4 -2
  228. package/dist/src/renderer/runtime-install.d.ts.map +1 -1
  229. package/dist/src/renderer/runtime-install.js +7 -2
  230. package/dist/src/renderer/runtime-install.js.map +1 -1
  231. package/dist/src/renderer/runtime-lifecycle-handle.d.ts.map +1 -1
  232. package/dist/src/renderer/runtime-lifecycle-handle.js +5 -0
  233. package/dist/src/renderer/runtime-lifecycle-handle.js.map +1 -1
  234. package/dist/src/renderer/runtime-shared.d.ts +3 -0
  235. package/dist/src/renderer/runtime-shared.d.ts.map +1 -1
  236. package/dist/src/renderer/runtime-shared.js.map +1 -1
  237. package/dist/src/renderer/runtime-start.d.ts.map +1 -1
  238. package/dist/src/renderer/runtime-start.js +5 -2
  239. package/dist/src/renderer/runtime-start.js.map +1 -1
  240. package/dist/src/renderer/ui-copy/model-catalog.d.ts +24 -0
  241. package/dist/src/renderer/ui-copy/model-catalog.d.ts.map +1 -1
  242. package/dist/src/renderer/ui-copy/model-catalog.js +6 -0
  243. package/dist/src/renderer/ui-copy/model-catalog.js.map +1 -1
  244. package/dist/src/renderer/ui-copy.d.ts +25 -1
  245. package/dist/src/renderer/ui-copy.d.ts.map +1 -1
  246. package/dist/src/renderer/vite-development-client.d.ts +4 -1
  247. package/dist/src/renderer/vite-development-client.d.ts.map +1 -1
  248. package/dist/src/renderer/vite-development-client.js +28 -10
  249. package/dist/src/renderer/vite-development-client.js.map +1 -1
  250. package/dist/src/shortcuts/dock.d.ts +2 -0
  251. package/dist/src/shortcuts/dock.d.ts.map +1 -1
  252. package/dist/src/shortcuts/dock.js +2 -1
  253. package/dist/src/shortcuts/dock.js.map +1 -1
  254. package/dist/src/shortcuts/startup-cover.d.ts +6 -0
  255. package/dist/src/shortcuts/startup-cover.d.ts.map +1 -1
  256. package/dist/src/shortcuts/startup-cover.js +38 -13
  257. package/dist/src/shortcuts/startup-cover.js.map +1 -1
  258. package/package.json +1 -1
  259. package/third_party/lucide-0.468.0-ISC.txt +15 -0
@@ -38,6 +38,13 @@ UI. Its license is included at `third_party/openai-apps-sdk-ui-MIT.txt`.
38
38
  The bundled MiniMax glyph is sourced from the MIT-licensed LobeHub Icons
39
39
  collection. Its license is included at `third_party/lobe-icons-MIT.txt`.
40
40
 
41
+ The model disclosure brain glyph is the upstream `brain.svg` asset from Lucide
42
+ `0.468.0`, sourced from
43
+ `https://raw.githubusercontent.com/lucide-icons/lucide/0.468.0/icons/brain.svg`.
44
+ Its ISC license is included at `third_party/lucide-0.468.0-ISC.txt`. CordisX
45
+ bundles only this single asset and does not install or redistribute the Lucide
46
+ package.
47
+
41
48
  Other bundled provider/model marks are attributed to their respective owners.
42
49
  Their inclusion identifies compatible services or model families and does not
43
50
  imply sponsorship, certification, or ownership by CordisX.
@@ -0,0 +1,21 @@
1
+ <svg
2
+ xmlns="http://www.w3.org/2000/svg"
3
+ width="24"
4
+ height="24"
5
+ viewBox="0 0 24 24"
6
+ fill="none"
7
+ stroke="currentColor"
8
+ stroke-width="2"
9
+ stroke-linecap="round"
10
+ stroke-linejoin="round"
11
+ >
12
+ <path d="M12 5a3 3 0 1 0-5.997.125 4 4 0 0 0-2.526 5.77 4 4 0 0 0 .556 6.588A4 4 0 1 0 12 18Z" />
13
+ <path d="M12 5a3 3 0 1 1 5.997.125 4 4 0 0 1 2.526 5.77 4 4 0 0 1-.556 6.588A4 4 0 1 1 12 18Z" />
14
+ <path d="M15 13a4.5 4.5 0 0 1-3-4 4.5 4.5 0 0 1-3 4" />
15
+ <path d="M17.599 6.5a3 3 0 0 0 .399-1.375" />
16
+ <path d="M6.003 5.125A3 3 0 0 0 6.401 6.5" />
17
+ <path d="M3.477 10.896a4 4 0 0 1 .585-.396" />
18
+ <path d="M19.938 10.5a4 4 0 0 1 .585.396" />
19
+ <path d="M6 18a4 4 0 0 1-1.967-.516" />
20
+ <path d="M19.967 17.484A4 4 0 0 1 18 18" />
21
+ </svg>
Binary file
Binary file
Binary file
Binary file
@@ -0,0 +1,181 @@
1
+ 'use strict'
2
+
3
+ // Loaded once into a verified CordisX-owned Electron main process. The
4
+ // inspector used to install it is closed before the Host is marked ready.
5
+ const fs = require('node:fs')
6
+ const net = require('node:net')
7
+ const path = require('node:path')
8
+ const { app, nativeImage, nativeTheme } = require('electron')
9
+
10
+ let installed = false
11
+ const PNG = Buffer.from([137, 80, 78, 71, 13, 10, 26, 10])
12
+
13
+ function privateFile(file) {
14
+ const fd = fs.openSync(file, fs.constants.O_RDONLY | fs.constants.O_NOFOLLOW)
15
+ try {
16
+ const info = fs.fstatSync(fd)
17
+ if (
18
+ !info.isFile() || info.uid !== process.getuid() || (info.mode & 0o077) !== 0
19
+ || info.size < PNG.length || info.size > 1024 * 1024
20
+ ) throw new Error('Unsafe Dock image')
21
+ const bytes = fs.readFileSync(fd)
22
+ if (!bytes.subarray(0, PNG.length).equals(PNG)) throw new Error('Invalid Dock image')
23
+ const image = nativeImage.createFromBuffer(bytes)
24
+ const size = image.getSize()
25
+ if (image.isEmpty() || size.width < 16 || size.height < 16 || size.width > 1024 || size.height > 1024) {
26
+ throw new Error('Invalid Dock image dimensions')
27
+ }
28
+ return image
29
+ } finally {
30
+ fs.closeSync(fd)
31
+ }
32
+ }
33
+
34
+ // The Host passes its selected nativeImage to dock.setIcon, after applying
35
+ // its own icon preference and system appearance. Compare opaque pixel lightness
36
+ // on a small normalized bitmap so its source crop and resolution do not matter.
37
+ function hostAppearance(input) {
38
+ if (input == null) return 'default'
39
+ const image = typeof input === 'string' ? nativeImage.createFromPath(input) : input
40
+ if (
41
+ !image || typeof image.isEmpty !== 'function' || image.isEmpty()
42
+ || typeof image.resize !== 'function'
43
+ ) return null
44
+ const bytes = image.resize({ width: 32, height: 32 }).toBitmap()
45
+ let total = 0
46
+ let pixels = 0
47
+ for (let offset = 0; offset + 3 < bytes.length; offset += 4) {
48
+ if (bytes[offset + 3] < 128) continue
49
+ total += bytes[offset] + bytes[offset + 1] + bytes[offset + 2]
50
+ pixels++
51
+ }
52
+ return pixels ? (total / pixels / 3 >= 145 ? 'light' : 'dark') : null
53
+ }
54
+
55
+ exports.install = async function install(options) {
56
+ if (installed || process.type !== 'browser' || process.pid !== options.pid) throw new Error('Invalid Dock owner')
57
+ if (
58
+ !/^[a-f0-9]{32}$/.test(options.entryId) || !/^[a-f0-9]{64}$/.test(options.token)
59
+ || !path.isAbsolute(options.socketPath) || !path.isAbsolute(options.iconPath)
60
+ || path.dirname(options.socketPath) !== path.dirname(options.iconPath)
61
+ || options.lightIconPath !== path.join(path.dirname(options.iconPath), 'dock-light.png')
62
+ || options.darkIconPath !== path.join(path.dirname(options.iconPath), 'dock-dark.png')
63
+ || options.defaultIconPath !== path.join(path.dirname(options.iconPath), 'dock-default.png')
64
+ ) {
65
+ throw new Error('Invalid Dock scope')
66
+ }
67
+ const directory = fs.lstatSync(path.dirname(options.socketPath))
68
+ if (
69
+ !directory.isDirectory() || directory.isSymbolicLink() || directory.uid !== process.getuid()
70
+ || (directory.mode & 0o077) !== 0
71
+ ) throw new Error('Unsafe Dock directory')
72
+ if (fs.existsSync(options.socketPath)) {
73
+ const old = fs.lstatSync(options.socketPath)
74
+ if (!old.isSocket() || old.uid !== process.getuid()) throw new Error('Unsafe stale Dock socket')
75
+ fs.unlinkSync(options.socketPath)
76
+ }
77
+ if (!app.dock || typeof app.dock.setIcon !== 'function') throw new Error('Host Dock API unavailable')
78
+ const original = app.dock.setIcon.bind(app.dock)
79
+ let hasImage = false
80
+ let selected = nativeTheme.shouldUseDarkColorsForSystemIntegratedUI ? 'dark' : 'light'
81
+ const apply = () => {
82
+ const file = fs.existsSync(options.iconPath)
83
+ ? options.iconPath
84
+ : selected === 'light'
85
+ ? options.lightIconPath
86
+ : selected === 'dark'
87
+ ? options.darkIconPath
88
+ : options.defaultIconPath
89
+ if (!fs.existsSync(file)) {
90
+ hasImage = false
91
+ return
92
+ }
93
+ original(privateFile(file))
94
+ hasImage = true
95
+ }
96
+ const server = net.createServer({ allowHalfOpen: true }, socket => {
97
+ let text = ''
98
+ let handled = false
99
+ socket.setEncoding('utf8')
100
+ socket.setTimeout(3000, () => socket.destroy())
101
+ socket.on('error', () => {})
102
+ socket.on('data', chunk => {
103
+ if (handled) return
104
+ text += chunk
105
+ if (text.length > 512) return socket.destroy()
106
+ const end = text.indexOf('\n')
107
+ if (end < 0) return
108
+ handled = true
109
+ const line = text.slice(0, end)
110
+ text = ''
111
+ try {
112
+ const request = JSON.parse(line)
113
+ if (
114
+ Object.keys(request).length !== 3 || request.token !== options.token
115
+ || request.entryId !== options.entryId || request.command !== 'refresh'
116
+ ) throw new Error('Denied')
117
+ apply()
118
+ socket.end('{"ok":true}\n')
119
+ } catch {
120
+ socket.end('{"ok":false}\n')
121
+ }
122
+ })
123
+ })
124
+ server.on('error', () => {})
125
+ await new Promise((resolve, reject) => {
126
+ server.once('error', reject)
127
+ server.listen(options.socketPath, resolve)
128
+ })
129
+ fs.chmodSync(options.socketPath, 0o600)
130
+ app.once('before-quit', () => {
131
+ server.close()
132
+ try {
133
+ fs.unlinkSync(options.socketPath)
134
+ } catch {}
135
+ })
136
+ app.dock.setIcon = image => {
137
+ try {
138
+ selected = hostAppearance(image) ?? selected
139
+ } catch {}
140
+ const result = original(image)
141
+ if (hasImage) {
142
+ queueMicrotask(() => {
143
+ try {
144
+ apply()
145
+ } catch {}
146
+ })
147
+ }
148
+ return result
149
+ }
150
+ nativeTheme.on('updated', () => {
151
+ // Follow the live system appearance when the Host does not issue another
152
+ // setIcon call. A Host call after this event still wins by updating
153
+ // selected before the deferred apply runs.
154
+ selected = nativeTheme.shouldUseDarkColorsForSystemIntegratedUI ? 'dark' : 'light'
155
+ if (hasImage) {
156
+ setTimeout(() => {
157
+ try {
158
+ apply()
159
+ } catch {}
160
+ }, 50)
161
+ }
162
+ })
163
+ // Automatic entries publish appearance variants rather than iconPath. Apply
164
+ // one before Host startup can select its own icon, then apply once more when
165
+ // Electron is ready so the final startup setIcon cannot win the race.
166
+ if (
167
+ [options.iconPath, options.lightIconPath, options.darkIconPath, options.defaultIconPath]
168
+ .some(file => fs.existsSync(file))
169
+ ) {
170
+ apply()
171
+ void app.whenReady().then(() =>
172
+ setTimeout(() => {
173
+ try {
174
+ apply()
175
+ } catch {}
176
+ }, 250)
177
+ ).catch(() => {})
178
+ }
179
+ installed = true
180
+ return { pid: process.pid, entryId: options.entryId, ready: true }
181
+ }
@@ -0,0 +1,78 @@
1
+ {
2
+ "schema": "cordisx/native-helper-artifact/v1",
3
+ "sourceCommit": "7ed2bf8fc92cd841c9454ab5d51d7288360816cc",
4
+ "deploymentTarget": "13.0",
5
+ "architectures": [
6
+ "arm64",
7
+ "x64"
8
+ ],
9
+ "inputs": {
10
+ "native/app-launcher.swift": "sha256:900aa9b31f293f7d493b93fadfa38083987de611597031a5158bf0111c0a52f2",
11
+ "native/host-open.swift": "sha256:a335a673534ac2338db3dcd4375ea92e6d20e0a521a086622b0d0b30a8191826",
12
+ "native/shortcut-helper/Entry.swift": "sha256:20b7584cff79b9605c03f20cdfdddfa2c43dbd0363457bd5b846804d0815b8f2",
13
+ "native/shortcut-helper/Images.swift": "sha256:911c21638b7d8c1aab1819b343598a5976389fee97ebaf9d7b5d6087e309838c",
14
+ "native/shortcut-helper/Runner.swift": "sha256:ace0e8d0c1916c81f34aa47a2ade64bf45507157fdbab1fefd0501cdfd08cf22",
15
+ "native/shortcut-helper/main.swift": "sha256:2514a383c1e71c0733edb105eb141f826e1c1fdd5947187799ca35be03b0a9ee",
16
+ "native/startup-gate.swift": "sha256:245c596fc45dbd9f08dd8e1fe204f9d8eebd4859f46fad1145499efadc8ff52d",
17
+ "native/dock-agent.cjs": "sha256:2a5f10f28df564a1d53a92d2a9f7ef5b39a728bf7f91086740358d9433635fb6",
18
+ "native/startup-cover.cjs": "sha256:b1d4fad013f536d22660535d71b52001dcfd7bc5b7b031f97118ae94cb0bbe39",
19
+ "native/startup-cover.css": "sha256:2b8c713fd5ba9dde302c3de630fba7d235d3e012892209cb3fd0d6f352d8a7a9",
20
+ "native/startup-loading.html": "sha256:aae67496961ce108ef9ddcde358ed283733afb4c6de534214f5f06243e121410",
21
+ "native/startup-navigation.cjs": "sha256:69ccfe9c4904774604b22b8cf99771633b080c48d6c2ee32abaa68b0c671fc62",
22
+ "native/visibility-agent.cjs": "sha256:25e819604cf1b62741e229437c331350715ebde3deee91444b8f8098b98552dc"
23
+ },
24
+ "helpers": {
25
+ "CordisXEntry": {
26
+ "sha256": "sha256:76ae13c7d1be4ab1d60d720353b07c0770506d84d266d6bc1f0a8e467efd92f4",
27
+ "mode": "0755",
28
+ "architectures": [
29
+ "arm64",
30
+ "x64"
31
+ ]
32
+ },
33
+ "CordisXHostOpen": {
34
+ "sha256": "sha256:2e7b79fcee38ba2b769ee55222deba196f8be81cdd967dc11da99f0c54d5f16a",
35
+ "mode": "0755",
36
+ "architectures": [
37
+ "arm64",
38
+ "x64"
39
+ ]
40
+ },
41
+ "CordisXLauncher": {
42
+ "sha256": "sha256:fa5646d6be7130e187e0c65e06593da9816adebb061c8b7763d31854d950135c",
43
+ "mode": "0755",
44
+ "architectures": [
45
+ "arm64",
46
+ "x64"
47
+ ]
48
+ },
49
+ "CordisXStartupGate": {
50
+ "sha256": "sha256:cdeb1be568cfba1579b90df3d4442077af43b1d35d786464a37e63452c7efe35",
51
+ "mode": "0755",
52
+ "architectures": [
53
+ "arm64",
54
+ "x64"
55
+ ]
56
+ }
57
+ },
58
+ "resources": {
59
+ "dock-agent.cjs": {
60
+ "sha256": "sha256:2a5f10f28df564a1d53a92d2a9f7ef5b39a728bf7f91086740358d9433635fb6"
61
+ },
62
+ "startup-cover.cjs": {
63
+ "sha256": "sha256:b1d4fad013f536d22660535d71b52001dcfd7bc5b7b031f97118ae94cb0bbe39"
64
+ },
65
+ "startup-cover.css": {
66
+ "sha256": "sha256:2b8c713fd5ba9dde302c3de630fba7d235d3e012892209cb3fd0d6f352d8a7a9"
67
+ },
68
+ "startup-loading.html": {
69
+ "sha256": "sha256:aae67496961ce108ef9ddcde358ed283733afb4c6de534214f5f06243e121410"
70
+ },
71
+ "startup-navigation.cjs": {
72
+ "sha256": "sha256:69ccfe9c4904774604b22b8cf99771633b080c48d6c2ee32abaa68b0c671fc62"
73
+ },
74
+ "visibility-agent.cjs": {
75
+ "sha256": "sha256:25e819604cf1b62741e229437c331350715ebde3deee91444b8f8098b98552dc"
76
+ }
77
+ }
78
+ }
@@ -0,0 +1,272 @@
1
+ // Host-owned startup cover. This code executes in the original
2
+ // main renderer, before its scripts, and never creates a native window/view.
3
+ function installCover(options, animateMark) {
4
+ if (globalThis.top !== globalThis || location.href !== options.url) return
5
+ if (globalThis.__cordisxStartupDocument) return
6
+ const receipt = Object.freeze({
7
+ generation: options.generation,
8
+ nonce: crypto.randomUUID(),
9
+ timeOrigin: performance.timeOrigin,
10
+ url: location.href,
11
+ })
12
+ let phase = 'covered'
13
+ let disposed = false
14
+ let requestedAction = null
15
+ let presentationReleasedAt
16
+ let scheduledFrame
17
+ let modal = false
18
+ const dialog = document.createElement('dialog')
19
+ dialog.id = `cordisx-startup-${receipt.nonce}`
20
+ dialog.dataset.cordisxStartup = options.generation
21
+ dialog.setAttribute('aria-label', 'CordisX 正在启动')
22
+ dialog.style.cssText =
23
+ 'position:fixed;inset:0;margin:0;max-width:none;max-height:none;width:100vw;height:100vh;border:0;padding:0;background:transparent;color-scheme:light dark;overflow:hidden;'
24
+ // The modal backdrop lives outside the content's shadow root. Scope its
25
+ // transparency to this document receipt and retire the rule with the cover.
26
+ const backdropStyle = document.createElement('style')
27
+ backdropStyle.textContent = `#${dialog.id}::backdrop { background: transparent; }
28
+ [data-cordisx-startup-mark="${receipt.nonce}"] { visibility: hidden; }`
29
+ const nativeMarks = new Map()
30
+ function restoreNativeMarks() {
31
+ for (const [element, previous] of nativeMarks) {
32
+ if (element.getAttribute('data-cordisx-startup-mark') !== receipt.nonce) continue
33
+ if (previous === null) element.removeAttribute('data-cordisx-startup-mark')
34
+ else element.setAttribute('data-cordisx-startup-mark', previous)
35
+ }
36
+ nativeMarks.clear()
37
+ }
38
+ const content = document.createElement('div')
39
+ content.style.cssText = 'width:100%;height:100%;'
40
+ dialog.append(content)
41
+ const shadow = content.attachShadow({ mode: 'closed' })
42
+ const style = document.createElement('style')
43
+ style.textContent = options.css
44
+ const main = document.createElement('main')
45
+ main.setAttribute('role', 'status')
46
+ main.setAttribute('aria-live', 'polite')
47
+ const mark = document.createElement('div')
48
+ mark.className = 'mark'
49
+ mark.setAttribute('aria-hidden', 'true')
50
+ if (options.mark) {
51
+ const parsed = new DOMParser().parseFromString(`<body>${options.mark}</body>`, 'text/html')
52
+ for (const svg of parsed.body.children) mark.append(document.importNode(svg, true))
53
+ }
54
+ const status = document.createElement('div')
55
+ status.className = 'status'
56
+ const message = document.createElement('p')
57
+ message.textContent = '正在准备…'
58
+ const actions = document.createElement('div')
59
+ actions.hidden = true
60
+ const retry = document.createElement('button')
61
+ retry.type = 'button'
62
+ retry.textContent = '重试'
63
+ retry.onclick = () => {
64
+ requestedAction = 'retry'
65
+ }
66
+ const close = document.createElement('button')
67
+ close.type = 'button'
68
+ close.textContent = '关闭'
69
+ close.onclick = () => {
70
+ requestedAction = 'close'
71
+ }
72
+ actions.append(retry, close)
73
+ status.append(message, actions)
74
+ main.append(mark, status)
75
+ shadow.append(style, main)
76
+ // Root-level mounting survives the app replacing its body/root subtree.
77
+ function mount() {
78
+ if (disposed || phase === 'presented' || !globalThis.document?.documentElement) return
79
+ if (backdropStyle.parentNode !== document.documentElement) document.documentElement.append(backdropStyle)
80
+ if (phase === 'covered' && options.nativeMarkSelector) {
81
+ const nativeMark = document.querySelector(options.nativeMarkSelector)
82
+ if (nativeMark && !nativeMarks.has(nativeMark)) {
83
+ nativeMarks.set(nativeMark, nativeMark.getAttribute('data-cordisx-startup-mark'))
84
+ nativeMark.setAttribute('data-cordisx-startup-mark', receipt.nonce)
85
+ }
86
+ }
87
+ if (dialog.parentNode !== document.documentElement) document.documentElement.append(dialog)
88
+ if (!dialog.open) {
89
+ modal = presentationReleasedAt === undefined
90
+ if (modal) dialog.showModal()
91
+ else dialog.show()
92
+ }
93
+ }
94
+ function visible(element) {
95
+ if (!element.isConnected || element.closest('[hidden], [aria-hidden="true"], [inert]')) return false
96
+ const box = element.getBoundingClientRect()
97
+ if (
98
+ box.width <= 0 || box.height <= 0 || box.right <= 0 || box.bottom <= 0
99
+ || box.left >= innerWidth || box.top >= innerHeight
100
+ ) return false
101
+ for (let node = element; node; node = node.parentElement) {
102
+ const style = getComputedStyle(node)
103
+ if (style.display === 'none' || style.visibility === 'hidden' || Number(style.opacity || 1) === 0) return false
104
+ }
105
+ return true
106
+ }
107
+ function inspectSurface() {
108
+ if (
109
+ disposed || presentationReleasedAt !== undefined || !globalThis.document?.documentElement
110
+ || !options.nativeSurface || !matches(receipt)
111
+ ) return
112
+ const signals = options.nativeSurface
113
+ const surfaces = [...document.querySelectorAll(signals.root)].filter(visible).flatMap(root => {
114
+ const chrome = [...root.querySelectorAll(signals.chrome)].some(element =>
115
+ element.closest(signals.root) === root && visible(element)
116
+ )
117
+ if (!chrome) return []
118
+ return [...root.querySelectorAll(signals.main)].filter(element =>
119
+ element.closest(signals.root) === root && visible(element)
120
+ && [...element.querySelectorAll(signals.content)].some(visible)
121
+ )
122
+ })
123
+ if (surfaces.length !== 1) return
124
+ presentationReleasedAt = performance.timeOrigin + performance.now()
125
+ withdraw()
126
+ if (phase === 'failed') {
127
+ configureRecovery()
128
+ mount()
129
+ } else phase = 'presented'
130
+ }
131
+ function reconcile() {
132
+ if (disposed || !globalThis.document) return
133
+ inspectSurface()
134
+ mount()
135
+ // One deferred geometry check per mutation/event covers newly applied CSS.
136
+ // It is observation only; no elapsed time can authorize presentation.
137
+ if (
138
+ !disposed && presentationReleasedAt === undefined && scheduledFrame === undefined
139
+ && options.nativeSurface && typeof requestAnimationFrame === 'function'
140
+ ) {
141
+ scheduledFrame = requestAnimationFrame(() => {
142
+ scheduledFrame = undefined
143
+ inspectSurface()
144
+ })
145
+ }
146
+ }
147
+ const observer = new MutationObserver(reconcile)
148
+ observer.observe(document, {
149
+ childList: true,
150
+ subtree: true,
151
+ attributes: true,
152
+ attributeFilter: ['class', 'style', 'hidden', 'aria-hidden', 'inert'],
153
+ })
154
+ document.addEventListener('load', reconcile, true)
155
+ document.addEventListener('transitionrun', reconcile, true)
156
+ document.addEventListener('animationstart', reconcile, true)
157
+ document.addEventListener('transitionend', reconcile, true)
158
+ document.addEventListener('animationend', reconcile, true)
159
+ globalThis.addEventListener('resize', reconcile)
160
+ function block(event) {
161
+ if (disposed || presentationReleasedAt !== undefined) return
162
+ if (
163
+ event.type === 'keydown' && (event.metaKey || event.ctrlKey)
164
+ && ['q', 'w'].includes(event.key.toLowerCase())
165
+ ) return
166
+ if (event.composedPath().includes(dialog)) return
167
+ event.preventDefault()
168
+ event.stopImmediatePropagation()
169
+ }
170
+ const events = ['keydown', 'beforeinput', 'pointerdown', 'click', 'submit', 'focusin']
171
+ for (const name of events) globalThis.addEventListener(name, block, true)
172
+ function withdraw() {
173
+ observer.disconnect()
174
+ if (scheduledFrame !== undefined) cancelAnimationFrame(scheduledFrame)
175
+ scheduledFrame = undefined
176
+ document.removeEventListener('load', reconcile, true)
177
+ document.removeEventListener('transitionrun', reconcile, true)
178
+ document.removeEventListener('animationstart', reconcile, true)
179
+ document.removeEventListener('transitionend', reconcile, true)
180
+ document.removeEventListener('animationend', reconcile, true)
181
+ globalThis.removeEventListener('resize', reconcile)
182
+ for (const name of events) globalThis.removeEventListener(name, block, true)
183
+ if (dialog.open) dialog.close()
184
+ modal = false
185
+ dialog.remove()
186
+ restoreNativeMarks()
187
+ backdropStyle.remove()
188
+ }
189
+ function configureRecovery() {
190
+ if (presentationReleasedAt === undefined) return
191
+ // An initialization failure remains actionable without blocking the native
192
+ // main surface that has already taken over presentation and interaction.
193
+ dialog.style.cssText =
194
+ 'position:fixed;inset:auto 16px 16px auto;margin:0;width:360px;max-width:calc(100vw - 32px);height:auto;max-height:calc(100vh - 32px);border:1px solid GrayText;border-radius:12px;padding:16px;background:Canvas;color:CanvasText;color-scheme:light dark;overflow:auto;'
195
+ content.style.height = 'auto'
196
+ main.style.height = 'auto'
197
+ status.style.position = 'static'
198
+ }
199
+ const retire = () => {
200
+ disposed = true
201
+ phase = 'retired'
202
+ withdraw()
203
+ globalThis.removeEventListener('pagehide', retire)
204
+ dialog.removeEventListener('cancel', cancel)
205
+ }
206
+ globalThis.addEventListener('pagehide', retire, { once: true })
207
+ const cancel = event => event.preventDefault()
208
+ dialog.addEventListener('cancel', cancel)
209
+ function matches(value) {
210
+ return value && Object.keys(receipt).every(key => value[key] === receipt[key])
211
+ && globalThis.location?.href === options.url
212
+ && globalThis.performance?.timeOrigin === receipt.timeOrigin
213
+ }
214
+ const api = Object.freeze({
215
+ snapshot: () => ({
216
+ receipt,
217
+ phase,
218
+ requestedAction,
219
+ mounted: dialog.isConnected,
220
+ modal: dialog.open && modal,
221
+ presentationReleasedAt,
222
+ }),
223
+ ownsDialog(candidate, value) {
224
+ return !disposed && candidate === dialog && matches(value)
225
+ },
226
+ // The caller must supply observations from this final document. This is a
227
+ // release fence, not an implementation of native/application readiness.
228
+ release(value, observations) {
229
+ if (
230
+ disposed || !['covered', 'presented'].includes(phase) || !matches(value)
231
+ || !matches(observations?.receipt)
232
+ || document.readyState === 'loading'
233
+ || observations?.hostUsable !== true
234
+ || !(observations?.workspaceUsable === true && observations?.cordisxReady === true
235
+ && observations?.authenticated === undefined
236
+ || observations?.authenticated === true && observations?.cordisxReady === true
237
+ || observations?.authenticated === false && observations?.loginUsable === true
238
+ || observations?.authenticated === undefined && observations?.loginUsable === true
239
+ && observations?.cordisxReady === true)
240
+ ) return false
241
+ disposed = true
242
+ phase = 'released'
243
+ withdraw()
244
+ globalThis.removeEventListener('pagehide', retire)
245
+ dialog.removeEventListener('cancel', cancel)
246
+ return true
247
+ },
248
+ fail(value) {
249
+ if (disposed || !matches(value)) return false
250
+ phase = 'failed'
251
+ mark.hidden = true
252
+ restoreNativeMarks()
253
+ message.textContent = '启动未完成,请重试或关闭此窗口'
254
+ actions.hidden = false
255
+ configureRecovery()
256
+ mount()
257
+ if (presentationReleasedAt === undefined) retry.focus()
258
+ return true
259
+ },
260
+ retire(value) {
261
+ if (disposed || !matches(value)) return false
262
+ retire()
263
+ return true
264
+ },
265
+ })
266
+ Object.defineProperty(globalThis, '__cordisxStartupDocument', { value: api, configurable: false })
267
+ reconcile()
268
+ animateMark?.(mark)
269
+ }
270
+
271
+ exports.buildCoverSource = (options, animate) =>
272
+ `(${installCover.toString()})(${JSON.stringify(options)},${animate ?? 'undefined'});`
@@ -0,0 +1,78 @@
1
+ :host, :root {
2
+ --startup-surface: #f4f5f7;
3
+ --startup-text: #202124;
4
+ --startup-muted: #65676b;
5
+ color-scheme: light dark;
6
+ background: transparent;
7
+ color: var(--startup-text);
8
+ font: 15px/1.6 -apple-system, BlinkMacSystemFont, sans-serif;
9
+ }
10
+ html, body {
11
+ background: transparent;
12
+ width: 100%;
13
+ height: 100%;
14
+ margin: 0;
15
+ overflow: hidden;
16
+ }
17
+ main {
18
+ box-sizing: border-box;
19
+ position: relative;
20
+ width: 100%;
21
+ height: 100%;
22
+ text-align: center;
23
+ user-select: none;
24
+ }
25
+ .mark {
26
+ position: absolute;
27
+ top: 50%;
28
+ left: 50%;
29
+ width: 128px;
30
+ height: 128px;
31
+ transform: translate(-50%, -50%);
32
+ }
33
+ .mark svg {
34
+ display: block;
35
+ width: 100%;
36
+ height: 100%;
37
+ }
38
+ .mark .mark-dark {
39
+ display: none;
40
+ }
41
+ .status {
42
+ position: absolute;
43
+ top: calc(50% + 92px);
44
+ left: 16px;
45
+ right: 16px;
46
+ font-size: 13px;
47
+ }
48
+ p {
49
+ margin: 0 0 16px;
50
+ color: var(--startup-muted);
51
+ }
52
+ button {
53
+ margin: 0 6px;
54
+ padding: 8px 18px;
55
+ border: 1px solid var(--startup-muted);
56
+ border-radius: 8px;
57
+ background: var(--startup-surface);
58
+ color: var(--startup-text);
59
+ font: inherit;
60
+ cursor: pointer;
61
+ }
62
+ button:focus-visible {
63
+ outline: 2px solid var(--startup-text);
64
+ outline-offset: 3px;
65
+ }
66
+ @media (prefers-color-scheme: dark) {
67
+ :host, :root {
68
+ --startup-surface: #17181a;
69
+ --startup-text: #f2f3f5;
70
+ --startup-muted: #a7aab0;
71
+ }
72
+ .mark .mark-light {
73
+ display: none;
74
+ }
75
+ .mark .mark-dark {
76
+ display: block;
77
+ }
78
+ }
@@ -0,0 +1,17 @@
1
+ <!doctype html>
2
+ <html lang="zh-CN">
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1">
6
+ <meta http-equiv="Content-Security-Policy" content="default-src 'none'; style-src 'unsafe-inline'; script-src 'nonce-__STARTUP_NONCE__'">
7
+ <title>CordisX</title>
8
+ <style>__STARTUP_CSS__</style>
9
+ </head>
10
+ <body>
11
+ <main role="status" aria-live="polite">
12
+ <div class="mark" aria-hidden="true">__STARTUP_MARK__</div>
13
+ <div class="status"><p>正在准备…</p></div>
14
+ </main>
15
+ <script nonce="__STARTUP_NONCE__">__STARTUP_ANIMATION__</script>
16
+ </body>
17
+ </html>