@omega.js/desktop 0.50.0 → 0.51.0

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 (267) hide show
  1. package/README.md +1 -1
  2. package/dist/assets/css/tokens/_index.scss +1 -1
  3. package/dist/assets/themes/base/_includes/frontend/sections/account-section-header.html +4 -1
  4. package/dist/assets/themes/base/_includes/frontend/sections/footer.html +13 -6
  5. package/dist/assets/themes/base/_includes/frontend/sections/nav.html +10 -8
  6. package/dist/assets/themes/base/_includes/global/sections/account.html +3 -1
  7. package/dist/assets/themes/base/_includes/global/sections/app-sidebar.html +12 -8
  8. package/dist/assets/themes/base/_includes/global/sections/app-topbar.html +10 -6
  9. package/dist/assets/themes/base/_includes/global/sections/page-header.html +8 -4
  10. package/dist/assets/themes/base/_layouts/backend/pages/dashboard/index.html +24 -24
  11. package/dist/assets/themes/base/_layouts/frontend/pages/about.html +10 -10
  12. package/dist/assets/themes/base/_layouts/frontend/pages/account/index.html +35 -35
  13. package/dist/assets/themes/base/_layouts/frontend/pages/alternatives/index.html +4 -4
  14. package/dist/assets/themes/base/_layouts/frontend/pages/auth/signin.html +1 -1
  15. package/dist/assets/themes/base/_layouts/frontend/pages/auth/signup.html +4 -4
  16. package/dist/assets/themes/base/_layouts/frontend/pages/contact.html +3 -3
  17. package/dist/assets/themes/base/_layouts/frontend/pages/download.html +34 -33
  18. package/dist/assets/themes/base/_layouts/frontend/pages/extension/index.html +11 -11
  19. package/dist/assets/themes/base/_layouts/frontend/pages/legal/document.html +1 -1
  20. package/dist/assets/themes/base/_layouts/frontend/pages/status.html +1 -1
  21. package/dist/assets/themes/base/_layouts/frontend/pages/team/index.html +9 -7
  22. package/dist/assets/themes/base/_layouts/frontend/pages/team/member.html +5 -3
  23. package/dist/assets/themes/base/_sections/about/letter/section.html +1 -1
  24. package/dist/assets/themes/base/_sections/about/letter/section.json5 +4 -4
  25. package/dist/assets/themes/base/_sections/marketing/bento/section.html +1 -1
  26. package/dist/assets/themes/base/_sections/marketing/bento/section.json5 +15 -15
  27. package/dist/assets/themes/base/_sections/marketing/cta/section.json5 +1 -1
  28. package/dist/assets/themes/base/_sections/marketing/hero/section.html +6 -6
  29. package/dist/assets/themes/base/_sections/marketing/hero/section.json5 +10 -10
  30. package/dist/assets/themes/base/_sections/marketing/product-demo/section.html +1 -1
  31. package/dist/assets/themes/base/_sections/marketing/product-demo/section.json5 +2 -2
  32. package/dist/assets/themes/base/_sections/marketing/stats/section.html +1 -1
  33. package/dist/assets/themes/base/_sections/marketing/stats/section.json5 +5 -5
  34. package/dist/assets/themes/base/_sections/marketing/trusted-by/section.html +1 -1
  35. package/dist/assets/themes/base/_sections/marketing/trusted-by/section.json5 +2 -2
  36. package/dist/assets/themes/neobrutalism/_layouts/frontend/pages/index.html +10 -10
  37. package/dist/assets/themes/newsflash/_layouts/frontend/pages/index.html +10 -10
  38. package/dist/assets/themes/newsflash/_sections/marketing/desks/section.html +2 -2
  39. package/dist/assets/themes/newsflash/_sections/marketing/desks/section.json5 +4 -4
  40. package/dist/build.js +69 -28
  41. package/dist/cli-run.js +20 -13
  42. package/dist/cli.js +12 -7
  43. package/dist/commands/build.js +0 -2
  44. package/dist/commands/deploy.js +116 -44
  45. package/dist/commands/finalize-release.js +5 -4
  46. package/dist/commands/launch.js +12 -7
  47. package/dist/commands/lib/deploy-precheck.js +66 -34
  48. package/dist/commands/lib/ensure-target.js +71 -11
  49. package/dist/commands/package.js +0 -1
  50. package/dist/commands/publish.js +11 -4
  51. package/dist/commands/release.js +99 -252
  52. package/dist/commands/runner.js +42 -5
  53. package/dist/commands/sign-windows.js +46 -15
  54. package/dist/commands/test.js +4 -3
  55. package/dist/commands/validate-certs.js +291 -115
  56. package/dist/config/page-template.html +4 -0
  57. package/dist/defaults/.github/workflows/build.yml +144 -64
  58. package/dist/defaults/AGENTS.md +3 -2
  59. package/dist/defaults/_.gitignore +4 -2
  60. package/dist/defaults/config/certs/README.md +25 -45
  61. package/dist/defaults/config/omega.json5 +66 -32
  62. package/dist/defaults/hooks/deploy/pre.js +10 -0
  63. package/dist/defaults/src/assets/scss/main.scss +12 -2
  64. package/dist/defaults/src/integrations/tray/index.js +1 -1
  65. package/dist/gulp/main.js +13 -25
  66. package/dist/gulp/tasks/audit.js +18 -6
  67. package/dist/gulp/tasks/build-config.js +181 -60
  68. package/dist/gulp/tasks/bundle.js +108 -36
  69. package/dist/gulp/tasks/release.js +86 -4
  70. package/dist/gulp/tasks/sass.js +11 -0
  71. package/dist/hooks/lib/notarize-tools.js +137 -0
  72. package/dist/hooks/notarize-artifacts.js +57 -0
  73. package/dist/hooks/notarize.js +59 -8
  74. package/dist/lib/auth-persistence.js +25 -0
  75. package/dist/lib/client-bridge.js +11 -8
  76. package/dist/lib/deep-link.js +15 -8
  77. package/dist/lib/protocol.js +7 -1
  78. package/dist/lib/restart-manager/install.js +6 -3
  79. package/dist/lib/sign-helpers/auto-unlock.js +65 -27
  80. package/dist/lib/sign-helpers/console-lock.js +34 -0
  81. package/dist/lib/sign-helpers/exec-with-limit.js +68 -0
  82. package/dist/lib/sign-helpers/resolve-icons.js +6 -4
  83. package/dist/lib/tray.js +7 -6
  84. package/dist/main.js +16 -0
  85. package/dist/preload.js +8 -0
  86. package/dist/renderer.js +16 -4
  87. package/dist/runner/job-started.js +104 -0
  88. package/dist/test/fixtures/consumer-app/config/omega.json5 +7 -0
  89. package/dist/test/fixtures/consumer-app/package.json +1 -1
  90. package/dist/test/fixtures/consumer-app/src/assets/js/components/main/index.js +7 -1
  91. package/dist/test/harness/main-entry.js +2 -1
  92. package/dist/test/harness/renderer-preload.js +12 -3
  93. package/dist/test/runners/boot.js +101 -11
  94. package/dist/test/runners/electron.js +1 -1
  95. package/dist/test/suites/boot/consumer-app-boots.test.js +54 -0
  96. package/dist/test/suites/build/audit.test.js +45 -6
  97. package/dist/test/suites/build/auth-persistence-resolve.test.js +119 -0
  98. package/dist/test/suites/build/auto-unlock.test.js +105 -0
  99. package/dist/test/suites/build/boot-runner-timeout.test.js +253 -0
  100. package/dist/test/suites/build/brand-scss.test.js +106 -0
  101. package/dist/test/suites/build/build-config.test.js +146 -36
  102. package/dist/test/suites/build/build-json-bake.test.js +245 -0
  103. package/dist/test/suites/build/build-verbs.test.js +48 -15
  104. package/dist/test/suites/build/build-workflow-jobs.test.js +190 -0
  105. package/dist/test/suites/build/cli.test.js +32 -10
  106. package/dist/test/suites/build/config-schema.test.js +4 -4
  107. package/dist/test/suites/build/console-lock.test.js +51 -0
  108. package/dist/test/suites/build/defaults-scaffold.test.js +71 -2
  109. package/dist/test/suites/build/deploy-direct.test.js +241 -0
  110. package/dist/test/suites/build/deploy-dispatch.test.js +287 -0
  111. package/dist/test/suites/build/deploy-hook.test.js +169 -0
  112. package/dist/test/suites/build/ensure-target.test.js +14 -2
  113. package/dist/test/suites/build/env-delivery.test.js +19 -10
  114. package/dist/test/suites/build/env-watch.test.js +18 -7
  115. package/dist/test/suites/build/esm-only-dependency.test.js +127 -0
  116. package/dist/test/suites/build/exec-with-limit.test.js +53 -0
  117. package/dist/test/suites/build/finalize-release.test.js +2 -2
  118. package/dist/test/suites/build/get-config.test.js +120 -8
  119. package/dist/test/suites/build/github-utils.test.js +12 -6
  120. package/dist/test/suites/build/license-stamp.test.js +6 -4
  121. package/dist/test/suites/build/manager.test.js +88 -68
  122. package/dist/test/suites/build/manifest-deps.test.js +116 -0
  123. package/dist/test/suites/build/merge-line-files.test.js +27 -4
  124. package/dist/test/suites/build/notarize-artifacts.test.js +135 -0
  125. package/dist/test/suites/build/notarize-tools.test.js +38 -0
  126. package/dist/test/suites/build/notarize.test.js +207 -0
  127. package/dist/test/suites/build/release-pipeline.test.js +38 -60
  128. package/dist/test/suites/build/release-skipped-upload.test.js +107 -0
  129. package/dist/test/suites/build/resolve-icons.test.js +35 -35
  130. package/dist/test/suites/build/runner-job-guard.test.js +182 -0
  131. package/dist/test/suites/build/runner.test.js +25 -2
  132. package/dist/test/suites/build/sentry.test.js +8 -3
  133. package/dist/test/suites/build/setup-scripts.test.js +3 -0
  134. package/dist/test/suites/build/sign-windows.test.js +92 -8
  135. package/dist/test/suites/build/test-stealth.test.js +17 -11
  136. package/dist/test/suites/build/url-helpers.test.js +37 -17
  137. package/dist/test/suites/build/validate-certs.test.js +428 -55
  138. package/dist/test/suites/build/validate-config.test.js +3 -3
  139. package/dist/test/suites/main/auth-flow.test.js +12 -0
  140. package/dist/test/suites/main/auth-persistence.test.js +14 -17
  141. package/dist/test/suites/main/auto-updater.test.js +2 -2
  142. package/dist/test/suites/main/boot-sequence.test.js +1 -1
  143. package/dist/test/suites/main/client-bridge.integration.test.js +5 -82
  144. package/dist/test/suites/main/client-bridge.test.js +19 -6
  145. package/dist/test/suites/main/deep-link.test.js +54 -0
  146. package/dist/test/suites/main/startup-paths-and-ua.test.js +1 -1
  147. package/dist/test/suites/main/url-helpers.test.js +81 -72
  148. package/dist/test/suites/renderer/cross-context-helpers.test.js +19 -16
  149. package/dist/utils/build-pipeline.js +10 -10
  150. package/dist/utils/github.js +12 -51
  151. package/dist/utils/load-env.js +66 -0
  152. package/dist/utils/mode-helpers.js +43 -111
  153. package/dist/utils/platform.js +37 -0
  154. package/dist/utils/runner-env.js +2 -1
  155. package/dist/utils/runner-job-guard.js +149 -0
  156. package/dist/utils/ship-keys.js +52 -0
  157. package/dist/utils/test-stealth.js +5 -3
  158. package/dist/utils/url-helpers.js +33 -17
  159. package/dist/vendor/config/bundle-id.js +53 -0
  160. package/dist/vendor/config/client-config.js +141 -0
  161. package/dist/vendor/config/company.js +334 -15
  162. package/dist/vendor/config/dev-facts.js +48 -0
  163. package/dist/vendor/config/env-delivery.js +231 -9
  164. package/dist/vendor/config/env-retired.js +137 -0
  165. package/dist/vendor/config/env-rules.js +22 -3
  166. package/dist/vendor/config/env-schema.js +234 -117
  167. package/dist/vendor/config/env.js +55 -26
  168. package/dist/vendor/config/environment.js +189 -0
  169. package/dist/vendor/config/hooks.js +13 -11
  170. package/dist/vendor/config/index.js +121 -44
  171. package/dist/vendor/config/load.js +366 -115
  172. package/dist/vendor/config/merge.js +2 -2
  173. package/dist/vendor/config/order.js +3 -3
  174. package/dist/vendor/config/platforms.js +276 -0
  175. package/dist/vendor/config/repo.js +226 -104
  176. package/dist/vendor/config/retired-keys.js +232 -27
  177. package/dist/vendor/config/schema.js +525 -99
  178. package/dist/vendor/config/site-global.js +63 -53
  179. package/dist/vendor/config/targets.js +187 -0
  180. package/dist/vendor/config/validate.js +119 -59
  181. package/dist/vendor/devkit/argv.js +118 -0
  182. package/dist/vendor/devkit/attach-log-file.js +21 -13
  183. package/dist/vendor/devkit/brand-tokens.js +278 -0
  184. package/dist/vendor/devkit/brand-version.js +264 -0
  185. package/dist/vendor/devkit/build-json.js +91 -0
  186. package/dist/vendor/devkit/bundle.js +48 -0
  187. package/dist/vendor/devkit/certificate-expiry.js +108 -0
  188. package/dist/vendor/devkit/certs.js +16 -194
  189. package/dist/vendor/devkit/ci-workflows.js +124 -8
  190. package/dist/vendor/devkit/cli-router.js +3 -3
  191. package/dist/vendor/devkit/defaults-engine.js +69 -7
  192. package/dist/vendor/devkit/deploy-follow.js +297 -0
  193. package/dist/vendor/devkit/deploy-precheck.js +23 -8
  194. package/dist/vendor/devkit/deploy-record.js +11 -27
  195. package/dist/vendor/devkit/deploy-snapshot.js +661 -0
  196. package/dist/vendor/devkit/deploy.js +445 -75
  197. package/dist/vendor/devkit/git-auth.js +73 -0
  198. package/dist/vendor/devkit/git-remote.js +95 -0
  199. package/dist/vendor/devkit/github-repo.js +290 -0
  200. package/dist/vendor/devkit/local.js +47 -0
  201. package/dist/vendor/devkit/merge-line-files.js +23 -16
  202. package/dist/vendor/devkit/omega-bin.js +18 -3
  203. package/dist/vendor/devkit/pack-local.js +391 -0
  204. package/dist/vendor/devkit/preludes/index.js +120 -0
  205. package/dist/vendor/devkit/preludes/origin-heal.js +156 -0
  206. package/dist/vendor/devkit/service-account.js +43 -0
  207. package/dist/vendor/devkit/ship-plan.js +112 -0
  208. package/dist/vendor/devkit/signing-env.js +180 -0
  209. package/dist/vendor/devkit/signing-tree.js +92 -0
  210. package/dist/vendor/devkit/target-seams.js +142 -0
  211. package/dist/vendor/devkit/target-secrets.js +235 -50
  212. package/dist/vendor/devkit/test/esm-only-fixture.js +48 -0
  213. package/dist/vendor/devkit/test/fixtures/esm-only-package/browser.js +19 -0
  214. package/dist/vendor/devkit/test/fixtures/esm-only-package/index.js +20 -0
  215. package/dist/vendor/devkit/test/fixtures/esm-only-package/package.json +13 -0
  216. package/dist/vendor/monitoring/env.js +20 -10
  217. package/dist/vendor/monitoring/main.js +1 -1
  218. package/dist/vendor/monitoring/preload.js +1 -1
  219. package/dist/vendor/monitoring/renderer.js +1 -1
  220. package/docs/analytics.md +1 -1
  221. package/docs/auto-updater.md +5 -5
  222. package/docs/boot-sequence.md +1 -1
  223. package/docs/build-system.md +15 -7
  224. package/docs/client-bridge.md +9 -7
  225. package/docs/config-schema.md +4 -4
  226. package/docs/css.md +8 -2
  227. package/docs/deep-link.md +12 -4
  228. package/docs/environment-detection.md +32 -24
  229. package/docs/hooks.md +3 -1
  230. package/docs/icons.md +7 -7
  231. package/docs/index.md +61 -23
  232. package/docs/installer-options.md +24 -21
  233. package/docs/logging.md +5 -5
  234. package/docs/releasing.md +25 -17
  235. package/docs/runner.md +40 -5
  236. package/docs/shared/brands.md +12 -6
  237. package/docs/shared/breaking-changes.md +375 -21
  238. package/docs/shared/config.md +757 -199
  239. package/docs/shared/deploys.md +194 -91
  240. package/docs/shared/icons.md +18 -0
  241. package/docs/shared/local-dev.md +24 -6
  242. package/docs/shared/logging.md +9 -6
  243. package/docs/shared/monitoring.md +27 -13
  244. package/docs/shared/publishing.md +3 -3
  245. package/docs/shared/rulings.md +2 -2
  246. package/docs/shared/testing.md +1 -1
  247. package/docs/shared/theming.md +26 -1
  248. package/docs/shared/translation.md +49 -7
  249. package/docs/shared/updates.md +1 -1
  250. package/docs/signing.md +59 -33
  251. package/docs/test-framework.md +10 -5
  252. package/docs/themes.md +15 -1
  253. package/package.json +18 -12
  254. package/bin/omega-desktop +0 -2
  255. package/dist/commands/push-secrets.js +0 -141
  256. package/dist/test/suites/build/deliver-certs.test.js +0 -95
  257. package/dist/test/suites/build/derive-signing-env.test.js +0 -122
  258. package/dist/test/suites/build/push-secrets.test.js +0 -226
  259. package/dist/test/suites/build/resolve-signing-cert.test.js +0 -342
  260. package/dist/utils/deliver-certs.js +0 -69
  261. package/dist/utils/derive-signing-env.js +0 -56
  262. package/dist/utils/resolve-signing-cert.js +0 -175
  263. package/dist/vendor/config/desktop-artifacts.js +0 -110
  264. package/dist/vendor/config/instances.js +0 -208
  265. /package/dist/defaults/config/icons/{macos → mac}/dmg.png +0 -0
  266. /package/dist/defaults/config/icons/{macos → mac}/icon.png +0 -0
  267. /package/dist/defaults/config/icons/{macos → mac}/tray.png +0 -0
@@ -33,9 +33,26 @@
33
33
  * // makes it mandatory
34
34
  * machineLocal: true, // a developer-machine value (a local
35
35
  * // path): never published to CI
36
+ * label: 'Snap Store credentials', // the human name an ask opens with
37
+ * url: 'https://snapcraft.io/account', // the page that MINTS it
38
+ * hint: 'Run `snapcraft export-login -`', // how to get it there
36
39
  * description: 'What the key drives.',
37
40
  * }
38
41
  *
42
+ * `label`, `url` and `hint` are the HUMAN half, and this schema is their one
43
+ * home ([#867](https://github.com/Omega-JS-Stack/omega/issues/867)): the
44
+ * manager's REQUIRES registry used to carry a second copy per service, so a key
45
+ * no service had wired up (every desktop signing key, every extension store
46
+ * key) had no mint page anywhere and nobody could be asked for it. `label` is
47
+ * what the setup gate opens with, `url` is the page a human pastes the value
48
+ * FROM (the manage walk's Enter-to-open target, and what publish prints when a
49
+ * key is missing), and `hint` is the one line that says what to do on that
50
+ * page. `url: null` is a deliberate statement that no page mints this value,
51
+ * and such an entry owes a `hint` saying where it does come from (a token a
52
+ * portal authorization returns, a path on the developer's own box). The
53
+ * manager's registry keeps only its own fields (which service asks, whether the
54
+ * ask is interactive, what Disable writes).
55
+ *
39
56
  * `generated:` is the mint switch: the manager writes those keys into a brand
40
57
  * .env (at onboard and on every manage that finds one missing) because no
41
58
  * dashboard exists to paste them from. Everything else is a third-party
@@ -74,8 +91,12 @@
74
91
  * that replaced three unrelated hand-kept lists
75
92
  * ([#627](https://github.com/Omega-JS-Stack/omega/issues/627)):
76
93
  *
77
- * - `'env'` — read from the composed .env at runtime (the backend, the one
78
- * target whose artifact ships an env file).
94
+ * - `'env'` : read from the composed .env the target runs with. On the
95
+ * backend that file ships with the deploy artifact; on every
96
+ * other target it is the composed .env on the DEVELOPER'S
97
+ * machine, so an `env` delivery there declares the local
98
+ * channel and renders no workflow line at all
99
+ * ([#819](https://github.com/Omega-JS-Stack/omega/issues/819)).
79
100
  * - `'ci'` — the generated workflow injects it into the runner env for the
80
101
  * build step.
81
102
  * - `'bake'` — the build writes the value INTO the shipped artifact, because
@@ -127,7 +148,7 @@ const ENV_GROUPS = [
127
148
  { id: 'cloudflare', comment: 'Cloudflare (edge service + every DNS-writing flow) — API token with Zone edit' },
128
149
  { id: 'namecheap', comment: 'Namecheap registrar (domain service)' },
129
150
  { id: 'google-oauth', comment: 'Google OAuth client (cloud, analytics, search, advertising services)' },
130
- { id: 'captcha', comment: "Classic reCAPTCHA keys — the brand's own, from its GCP reCAPTCHA console (captcha service)" },
151
+ { id: 'captcha', comment: "Classic reCAPTCHA SECRET key - the brand's own, from its GCP reCAPTCHA console (captcha service); the public site key is config, captcha.providers.recaptcha.siteKey" },
131
152
  {
132
153
  id: 'pixels',
133
154
  comment: 'Pixel access tokens (analytics service; the names @omega.js/backend reads)',
@@ -154,14 +175,12 @@ const ENV_GROUPS = [
154
175
  },
155
176
  {
156
177
  id: 'extension-stores',
157
- comment: 'Extension store publishing (extension target: Chrome Web Store, Firefox Add-ons, Edge Add-ons)',
178
+ comment: 'Extension store API credentials (extension target: Chrome Web Store, Firefox Add-ons, Edge Add-ons); each store\'s own listing id is config, targets.<name>.listings.<browser>.id',
158
179
  },
159
180
  { id: 'fontawesome', comment: 'Font Awesome Pro (icons) — path to the local Pro package dir' },
160
181
  { id: 'backend-services', comment: 'Backend service keys (composed into targets/backend/dist/.env by the env composer)' },
161
- {
162
- id: 'testing',
163
- comment: 'Test-lane credentials (every target) — optional; a suite that needs one skips without it',
164
- },
182
+ // No `testing` group: #819 retired the two test-lane credentials and a suite
183
+ // asks a brand for none, so the bucket went with them (see ENV_SCHEMA).
165
184
  {
166
185
  id: 'machine',
167
186
  comment: 'Auto-generated and persisted on the first real run — machine-owned, leave unset',
@@ -183,12 +202,14 @@ const ENV_SCHEMA = [
183
202
  {
184
203
  name: 'OMEGA_ADMIN_KEY',
185
204
  owner: 'workspace',
186
- targets: ['backend', 'desktop'],
205
+ targets: ['backend'],
187
206
  group: 'omega',
188
207
  generated: () => randomBytes(32).toString('base64url'),
189
208
  secret: true,
190
209
  required: true,
191
210
  delivery: { backend: 'env' },
211
+ label: 'Omega admin key',
212
+ url: null,
192
213
  description: 'Grants admin on the brand backend: the header every privileged call carries, and the seed the connection state cipher derives from.',
193
214
  },
194
215
  {
@@ -200,6 +221,8 @@ const ENV_SCHEMA = [
200
221
  secret: true,
201
222
  required: true,
202
223
  delivery: { backend: 'env' },
224
+ label: 'Omega webhook key',
225
+ url: null,
203
226
  description: 'Authenticates third-party webhook deliveries (payments, marketing) — the `key` query parameter every webhook route compares.',
204
227
  },
205
228
  {
@@ -229,24 +252,24 @@ const ENV_SCHEMA = [
229
252
  {
230
253
  name: 'OMEGA_LICENSE_KEY',
231
254
  owner: 'workspace',
232
- targets: ['web', 'desktop', 'extension'],
255
+ targets: ['web', 'backend', 'desktop', 'extension'],
233
256
  group: 'license',
234
257
  secret: true,
235
258
  required: false,
236
- delivery: { web: 'ci', desktop: 'ci', extension: 'ci' },
237
- description: 'The omegajs.dev account API key that licenses this brand: a deploy checks it with the omega backend and bakes the verdict into the artifact — payments live and no omega attribution, or payments gated and attribution shown. It travels CLI → server at deploy time ONLY: every delivery is `ci` (the three targets whose deploys build on a runner), it never bakes, and the backend — which deploys straight from the CLI — takes no delivery at all, so it can never land in the .env the functions artifact ships with.',
259
+ delivery: { web: 'ci', backend: 'ci', desktop: 'ci', extension: 'ci' },
260
+ description: 'The omegajs.dev account API key that licenses this brand: a deploy checks it with the omega backend and bakes the verdict into the artifact, payments live and no omega attribution, or payments gated and attribution shown. It travels CLI → server at deploy time ONLY: every delivery is `ci`, on all four targets, because every deploy now runs on a runner (the backend since [#872](https://github.com/Omega-JS-Stack/omega/issues/872), whose `omega deploy --direct` step reads the key out of the workflow env and would otherwise stamp every CI deploy `keyless`). It never bakes, and `ci` is what keeps it out of every backend `.env`: the workflow writes only `env` deliveries, and the stage strips the runner-only keys out of the composed values, so it can never land in the .env the functions artifact ships with.',
238
261
  },
239
262
 
240
263
  // ── third-party credentials, by owning service ───────────────────────────
241
264
  {
242
265
  name: 'GH_TOKEN',
243
266
  owner: 'repo',
244
- targets: ['web', 'backend', 'desktop'],
267
+ targets: ['web', 'backend', 'desktop', 'extension'],
245
268
  group: 'github',
246
269
  secret: true,
247
270
  required: false,
248
- delivery: { web: 'ci', backend: 'env', desktop: 'ci' },
249
- description: 'GitHub token for repo + seo work and the backend\'s content/admin routes (blog commits, workflow dispatch); the web target publishes CI secrets with it and the desktop target cuts releases and mirrors downloads with it. `gh auth login` serves the manager instead; the deployed backend needs the token.',
271
+ delivery: { web: 'ci', backend: 'env', desktop: 'ci', extension: 'ci' },
272
+ description: 'GitHub token for repo + seo work and the backend\'s content/admin routes (blog commits, workflow dispatch); the web target publishes CI secrets with it and the desktop target cuts releases and mirrors downloads with it. `gh auth login` serves the manager instead; the deployed backend needs the token. The extension target carries it too: its publish uploads the built zips to the `<brand.id>-releases` repo, a repo that run does not own, so the run-scoped `secrets.GITHUB_TOKEN` cannot reach it ([#883](https://github.com/Omega-JS-Stack/omega/issues/883)).',
250
273
  },
251
274
  {
252
275
  name: 'CLOUDFLARE_TOKEN',
@@ -256,6 +279,9 @@ const ENV_SCHEMA = [
256
279
  secret: true,
257
280
  required: false,
258
281
  delivery: { web: 'ci', backend: 'env' },
282
+ label: 'Cloudflare API token',
283
+ url: 'https://dash.cloudflare.com/profile/api-tokens',
284
+ hint: 'Create a token with Zone edit on the brand zone; the DNS-writing flows and the zone nameserver read both use it',
259
285
  description: 'Cloudflare API token with Zone edit — the edge service and every DNS-writing flow, plus the backend\'s cache-purge calls. The web build workflow\'s post-publish purge step reads it from the runner env, so the publish lane pushes it as a repo secret.',
260
286
  },
261
287
  {
@@ -265,6 +291,9 @@ const ENV_SCHEMA = [
265
291
  group: 'namecheap',
266
292
  secret: false,
267
293
  required: false,
294
+ label: 'Namecheap account username',
295
+ url: 'https://ap.www.namecheap.com/settings/tools/apiaccess/',
296
+ hint: 'The account the domain is registered under (the same page enables API access)',
268
297
  description: 'Namecheap account the domain service registers and configures domains through.',
269
298
  },
270
299
  {
@@ -274,6 +303,9 @@ const ENV_SCHEMA = [
274
303
  group: 'namecheap',
275
304
  secret: true,
276
305
  required: false,
306
+ label: 'Namecheap API key',
307
+ url: 'https://ap.www.namecheap.com/settings/tools/apiaccess/',
308
+ hint: 'Toggle API Access on, then whitelist this machine\'s IP on the same page',
277
309
  description: 'Namecheap API key paired with NAMECHEAP_USERNAME (the API also allowlists the calling IP).',
278
310
  },
279
311
  {
@@ -283,6 +315,9 @@ const ENV_SCHEMA = [
283
315
  group: 'google-oauth',
284
316
  secret: false,
285
317
  required: false,
318
+ label: 'Google OAuth client ID',
319
+ url: 'https://console.cloud.google.com/apis/credentials',
320
+ hint: 'A Desktop-app OAuth client: the one Google identity every service shares',
286
321
  description: 'OAuth client the manager authenticates Google APIs with (cloud, analytics, search, advertising services).',
287
322
  },
288
323
  {
@@ -292,18 +327,10 @@ const ENV_SCHEMA = [
292
327
  group: 'google-oauth',
293
328
  secret: true,
294
329
  required: false,
330
+ label: 'Google OAuth client secret',
331
+ url: 'https://console.cloud.google.com/apis/credentials',
295
332
  description: 'Secret half of GOOGLE_CLIENT_ID.',
296
333
  },
297
- {
298
- name: 'RECAPTCHA_SITE_KEY',
299
- owner: 'captcha',
300
- targets: ['web'],
301
- group: 'captcha',
302
- secret: false,
303
- required: false,
304
- delivery: { web: 'ci' },
305
- description: "Public half of the brand's classic reCAPTCHA pair — the web target renders it into forms.",
306
- },
307
334
  {
308
335
  name: 'RECAPTCHA_SECRET_KEY',
309
336
  owner: 'captcha',
@@ -313,6 +340,9 @@ const ENV_SCHEMA = [
313
340
  required: false,
314
341
  requiredWhen: 'captcha.providers.recaptcha.siteKey',
315
342
  delivery: { backend: 'env' },
343
+ label: 'reCAPTCHA secret key',
344
+ url: 'https://console.cloud.google.com/security/recaptcha',
345
+ hint: 'Create a classic key in the brand\'s OWN GCP project (never a shared company key); its SITE half lands in config',
316
346
  description: 'Secret half of the reCAPTCHA pair — the backend verifies submitted tokens with it.',
317
347
  },
318
348
  {
@@ -333,6 +363,9 @@ const ENV_SCHEMA = [
333
363
  secret: true,
334
364
  required: false,
335
365
  delivery: { backend: 'env' },
366
+ label: 'Meta Pixel access token',
367
+ url: 'https://business.facebook.com/settings/system-users',
368
+ hint: 'A Business Manager SYSTEM USER token with ads_management: it creates the pixel and signs the conversions',
336
369
  description: 'Business Manager system-user token with ads_management: creates the Meta pixel and signs the conversions the backend sends.',
337
370
  },
338
371
  {
@@ -343,6 +376,9 @@ const ENV_SCHEMA = [
343
376
  secret: true,
344
377
  required: false,
345
378
  delivery: { backend: 'env' },
379
+ label: 'TikTok Events API access token',
380
+ url: null,
381
+ hint: 'Minted by the portal authorization the analytics setup walks (#448): the app secret is only needed at mint time, so there is no page to paste this from',
346
382
  description: 'TikTok Business token: creates the pixel on the advertiser account and signs the events the backend sends.',
347
383
  },
348
384
  {
@@ -353,6 +389,9 @@ const ENV_SCHEMA = [
353
389
  secret: true,
354
390
  required: false,
355
391
  requiredWhen: 'monitoring.providers.sentry.dsn',
392
+ label: 'Sentry personal auth token',
393
+ url: 'https://sentry.io/settings/account/api/auth-tokens/',
394
+ hint: 'Create a personal token with scopes: org:read, project:read, project:write, team:read, team:write (organization tokens cannot create projects)',
356
395
  description: 'Personal Sentry auth token with project+team write scopes — the monitoring service provisions projects and uploads source maps with it.',
357
396
  },
358
397
  {
@@ -363,6 +402,8 @@ const ENV_SCHEMA = [
363
402
  secret: true,
364
403
  required: false,
365
404
  delivery: { backend: 'env' },
405
+ label: 'SendGrid API key',
406
+ url: 'https://app.sendgrid.com/settings/api_keys',
366
407
  description: 'SendGrid API key — every transactional and campaign email the backend sends, and the contact lists the campaigns service reconciles.',
367
408
  },
368
409
  {
@@ -373,6 +414,8 @@ const ENV_SCHEMA = [
373
414
  secret: true,
374
415
  required: false,
375
416
  delivery: { backend: 'env' },
417
+ label: 'Beehiiv API key',
418
+ url: 'https://app.beehiiv.com/settings/workspace/api',
376
419
  description: 'Beehiiv API key — newsletter subscriptions and the publication the newsletter service reconciles.',
377
420
  },
378
421
  {
@@ -383,6 +426,9 @@ const ENV_SCHEMA = [
383
426
  secret: true,
384
427
  required: false,
385
428
  delivery: { backend: 'env' },
429
+ label: 'Stripe secret key',
430
+ url: 'https://dashboard.stripe.com/apikeys',
431
+ hint: 'Developers, then API keys, on the BRAND\'s Stripe account (sk_live_... or sk_test_...)',
386
432
  description: 'Stripe secret key — the backend creates checkout sessions, subscriptions, and refunds with it.',
387
433
  },
388
434
  {
@@ -393,6 +439,9 @@ const ENV_SCHEMA = [
393
439
  secret: true,
394
440
  required: false,
395
441
  delivery: { backend: 'env' },
442
+ label: 'PayPal client secret',
443
+ url: 'https://developer.paypal.com/dashboard/applications',
444
+ hint: 'The secret half of the brand\'s REST API app (its client id is public and lives in omega.json5)',
396
445
  description: 'Secret half of the PayPal app credentials (the client id is public and lives in omega.json5).',
397
446
  },
398
447
  {
@@ -403,6 +452,9 @@ const ENV_SCHEMA = [
403
452
  secret: true,
404
453
  required: false,
405
454
  delivery: { backend: 'env' },
455
+ label: 'Chargebee API key',
456
+ url: 'https://app.chargebee.com/',
457
+ hint: 'Settings, then API keys, on the brand\'s Chargebee site (the site name is public and lives in omega.json5)',
406
458
  description: 'Chargebee API key for the brand site (the site name is public and lives in omega.json5).',
407
459
  },
408
460
  {
@@ -413,6 +465,9 @@ const ENV_SCHEMA = [
413
465
  secret: true,
414
466
  required: false,
415
467
  delivery: { backend: 'env' },
468
+ label: 'Coinbase Commerce API key',
469
+ url: 'https://commerce.coinbase.com/settings/security',
470
+ hint: 'Settings, then Security, then API keys, on the brand\'s Coinbase Commerce account (this key is the whole credential: there is no public half)',
416
471
  description: 'Coinbase Commerce API key — the backend creates hosted crypto charges with it. The provider has no public half at all, so payment.providers.coinbase carries only its `enabled` switch.',
417
472
  },
418
473
  {
@@ -422,6 +477,9 @@ const ENV_SCHEMA = [
422
477
  group: 'service-accounts',
423
478
  secret: true,
424
479
  required: false,
480
+ label: 'Slapform\'s service-account JSON path',
481
+ url: null,
482
+ hint: 'Operator-only: the Slapform project\'s own service-account JSON, from its Firebase console. Absolute, or relative to the brand root',
425
483
  description: 'Path to the Slapform service-account JSON the forms service authenticates with.',
426
484
  },
427
485
  {
@@ -431,6 +489,9 @@ const ENV_SCHEMA = [
431
489
  group: 'service-accounts',
432
490
  secret: true,
433
491
  required: false,
492
+ label: 'Chatsy\'s service-account JSON path',
493
+ url: null,
494
+ hint: 'Operator-only: the Chatsy project\'s own service-account JSON, from its Firebase console. Absolute, or relative to the brand root',
434
495
  description: 'Path to the Chatsy service-account JSON the chat service authenticates with.',
435
496
  },
436
497
  {
@@ -440,6 +501,9 @@ const ENV_SCHEMA = [
440
501
  group: 'service-accounts',
441
502
  secret: true,
442
503
  required: false,
504
+ label: 'Replyify\'s service-account JSON path',
505
+ url: null,
506
+ hint: 'Operator-only: the Replyify project\'s own service-account JSON, from its Firebase console. Absolute, or relative to the brand root',
443
507
  description: 'Path to the Replyify service-account JSON the email service authenticates with.',
444
508
  },
445
509
  {
@@ -449,6 +513,9 @@ const ENV_SCHEMA = [
449
513
  group: 'service-accounts',
450
514
  secret: true,
451
515
  required: false,
516
+ label: 'the company server\'s service-account JSON path',
517
+ url: null,
518
+ hint: 'Operator-only: the company server project\'s own service-account JSON, from its Firebase console. Absolute, or relative to the brand root',
452
519
  description: 'Path to the server service-account JSON the server service authenticates with.',
453
520
  },
454
521
  {
@@ -458,6 +525,9 @@ const ENV_SCHEMA = [
458
525
  group: 'service-accounts',
459
526
  secret: true,
460
527
  required: false,
528
+ label: 'Mr. Logo\'s service-account JSON path',
529
+ url: null,
530
+ hint: 'Operator-only: the Mr. Logo project\'s own service-account JSON. Absolute, or relative to the brand root',
461
531
  description: 'Path to the Mr. Logo service-account JSON the assets service generates brand artwork through.',
462
532
  },
463
533
  {
@@ -467,8 +537,12 @@ const ENV_SCHEMA = [
467
537
  group: 'apple',
468
538
  secret: false,
469
539
  required: false,
540
+ requiredWhen: 'certificates.providers.apple',
470
541
  delivery: { desktop: 'ci' },
471
- description: 'App Store Connect API issuer id — notarization of the desktop build.',
542
+ label: 'App Store Connect issuer ID',
543
+ url: 'https://appstoreconnect.apple.com/access/api',
544
+ hint: 'Users and Access, then Integrations: the issuer ID sits above the key list',
545
+ description: 'App Store Connect API issuer id: notarization of the desktop build. Required once the brand declares Apple signing (certificates.providers.apple): an `omega deploy` that cannot push it ships an unsigned mac build.',
472
546
  },
473
547
  {
474
548
  name: 'APPLE_API_KEY_ID',
@@ -477,8 +551,12 @@ const ENV_SCHEMA = [
477
551
  group: 'apple',
478
552
  secret: false,
479
553
  required: false,
554
+ requiredWhen: 'certificates.providers.apple',
480
555
  delivery: { desktop: 'ci' },
481
- description: 'App Store Connect API key id — also names the .p8 file the certificates service places (AuthKey_<id>.p8).',
556
+ label: 'App Store Connect API key ID',
557
+ url: 'https://appstoreconnect.apple.com/access/api',
558
+ hint: 'The key you download as AuthKey_<id>.p8; the id is the filename',
559
+ description: 'App Store Connect API key id: also names the .p8 file the certificates service places (AuthKey_<id>.p8). Required once the brand declares Apple signing (certificates.providers.apple): an `omega deploy` that cannot push it ships an unsigned mac build.',
482
560
  },
483
561
  {
484
562
  name: 'APPLE_TEAM_ID',
@@ -487,8 +565,12 @@ const ENV_SCHEMA = [
487
565
  group: 'apple',
488
566
  secret: false,
489
567
  required: false,
568
+ requiredWhen: 'certificates.providers.apple',
490
569
  delivery: { desktop: 'ci' },
491
- description: 'Apple Developer team id the desktop build signs under.',
570
+ label: 'Apple Developer team ID',
571
+ url: 'https://developer.apple.com/account',
572
+ hint: 'Membership details shows the 10-character Team ID',
573
+ description: 'Apple Developer team id the desktop build signs under. Required once the brand declares Apple signing (certificates.providers.apple): an `omega deploy` that cannot push it ships an unsigned mac build.',
492
574
  },
493
575
  {
494
576
  name: 'CSC_LINK',
@@ -497,8 +579,9 @@ const ENV_SCHEMA = [
497
579
  group: 'apple',
498
580
  secret: false,
499
581
  required: false,
582
+ requiredWhen: 'certificates.providers.apple',
500
583
  delivery: { desktop: 'ci' },
501
- description: 'Path to the macOS Developer ID signing certificate (.p12) electron-builder signs with — unset, the build derives it from a delivered config/certs/developer-id-application.p12, then falls back to the Keychain.',
584
+ description: 'Path to the macOS Developer ID signing certificate (.p12) electron-builder signs with; unset, the build derives it from a delivered config/certs/developer-id-application.p12, then falls back to the Keychain. Required once the brand declares Apple signing (certificates.providers.apple): an `omega deploy` that cannot push it ships an unsigned mac build.',
502
585
  },
503
586
  {
504
587
  name: 'APPLE_API_KEY',
@@ -507,8 +590,9 @@ const ENV_SCHEMA = [
507
590
  group: 'apple',
508
591
  secret: false,
509
592
  required: false,
593
+ requiredWhen: 'certificates.providers.apple',
510
594
  delivery: { desktop: 'ci' },
511
- description: 'Path to the App Store Connect API key (.p8) notarization uses — unset, the build derives it from a delivered config/certs/AuthKey_<APPLE_API_KEY_ID>.p8.',
595
+ description: 'Path to the App Store Connect API key (.p8) notarization uses; unset, the build derives it from a delivered config/certs/AuthKey_<APPLE_API_KEY_ID>.p8. Required once the brand declares Apple signing (certificates.providers.apple): an `omega deploy` that cannot push it ships an unsigned mac build.',
512
596
  },
513
597
 
514
598
  // ── desktop-publishing — the Windows + Linux halves of a desktop release ──
@@ -519,8 +603,12 @@ const ENV_SCHEMA = [
519
603
  group: 'desktop-publishing',
520
604
  secret: false,
521
605
  required: false,
606
+ requiredWhen: 'platforms.windows.signing.strategy=self-hosted',
522
607
  delivery: { desktop: 'ci' },
523
- description: 'Thumbprint/path of the EV code-signing certificate on the self-hosted Windows runner (platforms.win.signing.strategy = self-hosted).',
608
+ label: 'Windows EV certificate thumbprint',
609
+ url: null,
610
+ hint: 'Read off the EV token on the self-hosted Windows runner: `certutil -user -store My` prints the thumbprint of the installed certificate',
611
+ description: 'Thumbprint/path of the EV code-signing certificate on the self-hosted Windows runner (platforms.windows.signing.strategy = self-hosted). Required when platforms.windows.signing.strategy is self-hosted.',
524
612
  },
525
613
  {
526
614
  name: 'WIN_CSC_KEY_PASSWORD',
@@ -529,8 +617,12 @@ const ENV_SCHEMA = [
529
617
  group: 'desktop-publishing',
530
618
  secret: true,
531
619
  required: false,
620
+ requiredWhen: 'platforms.windows.signing.strategy=self-hosted',
532
621
  delivery: { desktop: 'ci' },
533
- description: 'SafeNet token PIN the Windows signing job unlocks the EV token with.',
622
+ label: 'Windows EV token PIN',
623
+ url: null,
624
+ hint: 'The SafeNet token PIN set when the EV certificate was issued; the token vendor never shows it again',
625
+ description: 'SafeNet token PIN the Windows signing job unlocks the EV token with. Required when platforms.windows.signing.strategy is self-hosted.',
534
626
  },
535
627
  {
536
628
  name: 'SIGNTOOL_PATH',
@@ -540,9 +632,12 @@ const ENV_SCHEMA = [
540
632
  secret: false,
541
633
  required: false,
542
634
  delivery: { desktop: 'ci' },
635
+ label: 'signtool.exe path',
636
+ url: null,
637
+ hint: 'Where the Windows SDK installed signtool.exe on the runner, e.g. C:\\\\Program Files (x86)\\\\Windows Kits\\\\10\\\\bin\\\\10.0.22621.0\\\\x64\\\\signtool.exe',
543
638
  description: 'Path to signtool.exe on the Windows runner.',
544
639
  },
545
- // The cloud signing providers (platforms.win.signing.strategy = cloud): the
640
+ // The cloud signing providers (platforms.windows.signing.strategy = cloud): the
546
641
  // windows-sign job injects all three sets and the configured provider is the
547
642
  // one that consumes its own ([#627](https://github.com/Omega-JS-Stack/omega/issues/627)).
548
643
  {
@@ -552,8 +647,12 @@ const ENV_SCHEMA = [
552
647
  group: 'desktop-publishing',
553
648
  secret: true,
554
649
  required: false,
650
+ requiredWhen: 'platforms.windows.signing.cloud.provider=azure',
555
651
  delivery: { desktop: 'ci' },
556
- description: 'Azure Trusted Signing: the directory (tenant) the signing account lives in.',
652
+ label: 'Azure Trusted Signing tenant ID',
653
+ url: 'https://portal.azure.com/#view/Microsoft_AAD_IAM/ActiveDirectoryMenuBlade/~/Overview',
654
+ hint: 'The directory (tenant) the Trusted Signing account lives in',
655
+ description: 'Azure Trusted Signing: the directory (tenant) the signing account lives in. Required when platforms.windows.signing.cloud.provider is azure.',
557
656
  },
558
657
  {
559
658
  name: 'AZURE_CLIENT_ID',
@@ -562,8 +661,12 @@ const ENV_SCHEMA = [
562
661
  group: 'desktop-publishing',
563
662
  secret: true,
564
663
  required: false,
664
+ requiredWhen: 'platforms.windows.signing.cloud.provider=azure',
565
665
  delivery: { desktop: 'ci' },
566
- description: 'Azure Trusted Signing: the app registration the signing job authenticates as.',
666
+ label: 'Azure app registration client ID',
667
+ url: 'https://portal.azure.com/#view/Microsoft_AAD_RegisteredApps/ApplicationsListBlade',
668
+ hint: 'The app registration the signing job authenticates as',
669
+ description: 'Azure Trusted Signing: the app registration the signing job authenticates as. Required when platforms.windows.signing.cloud.provider is azure.',
567
670
  },
568
671
  {
569
672
  name: 'AZURE_CLIENT_SECRET',
@@ -572,8 +675,12 @@ const ENV_SCHEMA = [
572
675
  group: 'desktop-publishing',
573
676
  secret: true,
574
677
  required: false,
678
+ requiredWhen: 'platforms.windows.signing.cloud.provider=azure',
575
679
  delivery: { desktop: 'ci' },
576
- description: 'Azure Trusted Signing: the client secret of AZURE_CLIENT_ID.',
680
+ label: 'Azure app registration client secret',
681
+ url: 'https://portal.azure.com/#view/Microsoft_AAD_RegisteredApps/ApplicationsListBlade',
682
+ hint: 'Certificates and secrets on the app registration above; the value is shown once',
683
+ description: 'Azure Trusted Signing: the client secret of AZURE_CLIENT_ID. Required when platforms.windows.signing.cloud.provider is azure.',
577
684
  },
578
685
  {
579
686
  name: 'AZURE_TRUSTED_SIGNING_ENDPOINT',
@@ -582,8 +689,12 @@ const ENV_SCHEMA = [
582
689
  group: 'desktop-publishing',
583
690
  secret: true,
584
691
  required: false,
692
+ requiredWhen: 'platforms.windows.signing.cloud.provider=azure',
585
693
  delivery: { desktop: 'ci' },
586
- description: 'Azure Trusted Signing: the regional endpoint the signing account was created in.',
694
+ label: 'Azure Trusted Signing endpoint',
695
+ url: 'https://portal.azure.com/#view/HubsExtension/BrowseResource/resourceType/Microsoft.CodeSigning%2FcodeSigningAccounts',
696
+ hint: 'The regional endpoint of the Trusted Signing account, e.g. https://eus.codesigning.azure.net',
697
+ description: 'Azure Trusted Signing: the regional endpoint the signing account was created in. Required when platforms.windows.signing.cloud.provider is azure.',
587
698
  },
588
699
  {
589
700
  name: 'SSLCOM_USERNAME',
@@ -592,8 +703,12 @@ const ENV_SCHEMA = [
592
703
  group: 'desktop-publishing',
593
704
  secret: true,
594
705
  required: false,
706
+ requiredWhen: 'platforms.windows.signing.cloud.provider=sslcom',
595
707
  delivery: { desktop: 'ci' },
596
- description: 'SSL.com eSigner account the cloud signing job authenticates with.',
708
+ label: 'SSL.com eSigner account',
709
+ url: 'https://www.ssl.com/login/',
710
+ hint: 'The eSigner account the cloud signing job authenticates with',
711
+ description: 'SSL.com eSigner account the cloud signing job authenticates with. Required when platforms.windows.signing.cloud.provider is sslcom.',
597
712
  },
598
713
  {
599
714
  name: 'SSLCOM_PASSWORD',
@@ -602,8 +717,12 @@ const ENV_SCHEMA = [
602
717
  group: 'desktop-publishing',
603
718
  secret: true,
604
719
  required: false,
720
+ requiredWhen: 'platforms.windows.signing.cloud.provider=sslcom',
605
721
  delivery: { desktop: 'ci' },
606
- description: 'Password of the SSL.com eSigner account.',
722
+ label: 'SSL.com eSigner password',
723
+ url: 'https://www.ssl.com/login/',
724
+ hint: 'The password of the eSigner account above',
725
+ description: 'Password of the SSL.com eSigner account. Required when platforms.windows.signing.cloud.provider is sslcom.',
607
726
  },
608
727
  {
609
728
  name: 'SSLCOM_CREDENTIAL_ID',
@@ -612,8 +731,12 @@ const ENV_SCHEMA = [
612
731
  group: 'desktop-publishing',
613
732
  secret: true,
614
733
  required: false,
734
+ requiredWhen: 'platforms.windows.signing.cloud.provider=sslcom',
615
735
  delivery: { desktop: 'ci' },
616
- description: 'SSL.com eSigner credential id naming which certificate in the account signs.',
736
+ label: 'SSL.com eSigner credential ID',
737
+ url: 'https://www.ssl.com/login/',
738
+ hint: 'Under the certificate order: it names WHICH certificate in the account signs',
739
+ description: 'SSL.com eSigner credential id naming which certificate in the account signs. Required when platforms.windows.signing.cloud.provider is sslcom.',
617
740
  },
618
741
  {
619
742
  name: 'DIGICERT_API_KEY',
@@ -622,8 +745,12 @@ const ENV_SCHEMA = [
622
745
  group: 'desktop-publishing',
623
746
  secret: true,
624
747
  required: false,
748
+ requiredWhen: 'platforms.windows.signing.cloud.provider=digicert',
625
749
  delivery: { desktop: 'ci' },
626
- description: 'DigiCert KeyLocker API key the cloud signing job authenticates with.',
750
+ label: 'DigiCert KeyLocker API key',
751
+ url: 'https://one.digicert.com/signingmanager/keypairs',
752
+ hint: 'Account, then API tokens, in DigiCert ONE Software Trust Manager',
753
+ description: 'DigiCert KeyLocker API key the cloud signing job authenticates with. Required when platforms.windows.signing.cloud.provider is digicert.',
627
754
  },
628
755
  {
629
756
  name: 'DIGICERT_KEYPAIR_ALIAS',
@@ -632,8 +759,12 @@ const ENV_SCHEMA = [
632
759
  group: 'desktop-publishing',
633
760
  secret: true,
634
761
  required: false,
762
+ requiredWhen: 'platforms.windows.signing.cloud.provider=digicert',
635
763
  delivery: { desktop: 'ci' },
636
- description: 'DigiCert KeyLocker keypair alias naming which certificate in the account signs.',
764
+ label: 'DigiCert KeyLocker keypair alias',
765
+ url: 'https://one.digicert.com/signingmanager/keypairs',
766
+ hint: 'The alias of the keypair that signs, from the Keypairs list',
767
+ description: 'DigiCert KeyLocker keypair alias naming which certificate in the account signs. Required when platforms.windows.signing.cloud.provider is digicert.',
637
768
  },
638
769
  {
639
770
  name: 'SNAPCRAFT_STORE_CREDENTIALS',
@@ -642,22 +773,15 @@ const ENV_SCHEMA = [
642
773
  group: 'desktop-publishing',
643
774
  secret: true,
644
775
  required: false,
645
- requiredWhen: 'platforms.linux.snap.enabled',
776
+ requiredWhen: 'platforms.linux.formats.snap',
646
777
  delivery: { desktop: 'ci' },
647
- description: 'Snap Store credentials blob (`snapcraft export-login -`) the Linux publish job uses — required only when platforms.linux.snap.enabled.',
778
+ label: 'Snap Store credentials',
779
+ url: 'https://snapcraft.io/account',
780
+ hint: 'Log in, then run `snapcraft export-login -` locally and paste the whole blob it prints',
781
+ description: 'Snap Store credentials blob (`snapcraft export-login -`) the Linux publish job uses. Required only when the brand ships the snap format (platforms.linux.formats.snap).',
648
782
  },
649
783
 
650
784
  // ── extension-stores — one credential set per browser store ──────────────
651
- {
652
- name: 'CHROME_EXTENSION_ID',
653
- owner: 'certificates',
654
- targets: ['extension'],
655
- group: 'extension-stores',
656
- secret: false,
657
- required: false,
658
- delivery: { extension: 'ci' },
659
- description: 'Chrome Web Store item id the publish verb uploads to.',
660
- },
661
785
  {
662
786
  name: 'CHROME_CLIENT_ID',
663
787
  owner: 'certificates',
@@ -666,6 +790,9 @@ const ENV_SCHEMA = [
666
790
  secret: false,
667
791
  required: false,
668
792
  delivery: { extension: 'ci' },
793
+ label: 'Chrome Web Store OAuth client ID',
794
+ url: 'https://console.cloud.google.com/apis/credentials',
795
+ hint: 'Enable the Chrome Web Store API in the project, then create a Desktop-app OAuth client; the refresh token is minted from this client',
669
796
  description: 'OAuth client id of the Chrome Web Store API credential.',
670
797
  },
671
798
  {
@@ -676,6 +803,9 @@ const ENV_SCHEMA = [
676
803
  secret: true,
677
804
  required: false,
678
805
  delivery: { extension: 'ci' },
806
+ label: 'Chrome Web Store OAuth client secret',
807
+ url: 'https://console.cloud.google.com/apis/credentials',
808
+ hint: 'The secret half of the OAuth client above',
679
809
  description: 'OAuth client secret of the Chrome Web Store API credential.',
680
810
  },
681
811
  {
@@ -686,18 +816,11 @@ const ENV_SCHEMA = [
686
816
  secret: true,
687
817
  required: false,
688
818
  delivery: { extension: 'ci' },
819
+ label: 'Chrome Web Store refresh token',
820
+ url: null,
821
+ hint: 'Minted once by granting the OAuth client above the chromewebstore scope (the Chrome Web Store API guide walks the consent exchange); no dashboard shows it',
689
822
  description: 'Refresh token the Chrome Web Store API credential mints its access tokens from.',
690
823
  },
691
- {
692
- name: 'FIREFOX_EXTENSION_ID',
693
- owner: 'certificates',
694
- targets: ['extension'],
695
- group: 'extension-stores',
696
- secret: false,
697
- required: false,
698
- delivery: { extension: 'ci' },
699
- description: 'Firefox Add-ons id the publish verb uploads to.',
700
- },
701
824
  {
702
825
  name: 'FIREFOX_API_KEY',
703
826
  owner: 'certificates',
@@ -706,6 +829,9 @@ const ENV_SCHEMA = [
706
829
  secret: false,
707
830
  required: false,
708
831
  delivery: { extension: 'ci' },
832
+ label: 'Firefox Add-ons API key',
833
+ url: 'https://addons.mozilla.org/developers/addon/api/key/',
834
+ hint: 'The JWT issuer half of the AMO credential',
709
835
  description: 'Firefox Add-ons API key (JWT issuer) from addons.mozilla.org.',
710
836
  },
711
837
  {
@@ -716,18 +842,11 @@ const ENV_SCHEMA = [
716
842
  secret: true,
717
843
  required: false,
718
844
  delivery: { extension: 'ci' },
845
+ label: 'Firefox Add-ons API secret',
846
+ url: 'https://addons.mozilla.org/developers/addon/api/key/',
847
+ hint: 'Shown once when the credential is generated, beside the issuer above',
719
848
  description: 'Firefox Add-ons API secret the JWT is signed with.',
720
849
  },
721
- {
722
- name: 'EDGE_PRODUCT_ID',
723
- owner: 'certificates',
724
- targets: ['extension'],
725
- group: 'extension-stores',
726
- secret: false,
727
- required: false,
728
- delivery: { extension: 'ci' },
729
- description: 'Microsoft Edge Add-ons product id the publish verb uploads to.',
730
- },
731
850
  {
732
851
  name: 'EDGE_CLIENT_ID',
733
852
  owner: 'certificates',
@@ -736,6 +855,9 @@ const ENV_SCHEMA = [
736
855
  secret: false,
737
856
  required: false,
738
857
  delivery: { extension: 'ci' },
858
+ label: 'Edge Add-ons API client ID',
859
+ url: 'https://partner.microsoft.com/dashboard/microsoftedge/publishapi',
860
+ hint: 'Publish API on the Edge program dashboard: it issues the client id and the key together',
739
861
  description: 'Edge Add-ons API client id.',
740
862
  },
741
863
  {
@@ -746,30 +868,19 @@ const ENV_SCHEMA = [
746
868
  secret: true,
747
869
  required: false,
748
870
  delivery: { extension: 'ci' },
871
+ label: 'Edge Add-ons API key',
872
+ url: 'https://partner.microsoft.com/dashboard/microsoftedge/publishapi',
873
+ hint: 'Issued beside the client id above; it authenticates every publish request',
749
874
  description: 'Edge Add-ons API key the publish request authenticates with.',
750
875
  },
751
876
 
752
- // ── testing — the credentials an opt-in test lane needs ──────────────────
753
- {
754
- name: 'OMEGA_TEST_FIREBASE_ADMIN_KEY',
755
- owner: 'backend',
756
- targets: ['web', 'backend', 'desktop', 'extension'],
757
- group: 'testing',
758
- secret: true,
759
- required: false,
760
- delivery: { web: 'ci', backend: 'env' },
761
- description: 'Path to a service-account JSON the extended test lanes mint custom tokens with — absent, those suites skip with a reason (GOOGLE_APPLICATION_CREDENTIALS is the fallthrough).',
762
- },
763
- {
764
- name: 'OMEGA_TEST_USER_UID',
765
- owner: 'backend',
766
- targets: ['web', 'backend', 'desktop', 'extension'],
767
- group: 'testing',
768
- secret: false,
769
- required: false,
770
- delivery: { web: 'ci', backend: 'env' },
771
- description: "Uid the extended test lanes sign in as — each framework's suite defaults to its own (`desktop-test-user` and siblings).",
772
- },
877
+ // No test-lane credentials live here any more
878
+ // ([#819](https://github.com/Omega-JS-Stack/omega/issues/819), Ian
879
+ // 2026-09-13): web, desktop and extension each test their own sign-in
880
+ // against a persona the backend emulator seeds, so a suite never asks a
881
+ // brand for a key. The pair that used to sit here is retired outright
882
+ // (env-retired.js carries both rows); #904 owns the replacement.
883
+
773
884
  {
774
885
  name: 'OMEGA_FONTAWESOME_ROOT',
775
886
  owner: 'assets',
@@ -793,8 +904,11 @@ const ENV_SCHEMA = [
793
904
  group: 'backend-services',
794
905
  secret: true,
795
906
  required: false,
796
- delivery: { web: 'ci', backend: 'env' },
797
- description: 'The OpenAI key wherever the backend calls OpenAI, and what the shared translation engine needs when translation.providers names chatgpt (the default "claude" provider needs none) — the brand .env wins, a company .env serves every brand that sets none.',
907
+ delivery: { web: 'env', backend: 'env', extension: 'env' },
908
+ label: 'OpenAI API key',
909
+ url: 'https://platform.openai.com/api-keys',
910
+ hint: 'A secret key on the account that should be billed for the brand\'s OpenAI calls',
911
+ description: 'The OpenAI key wherever the backend calls OpenAI, and what the shared translation engine needs when translation.providers names chatgpt (the default "claude" provider needs none): the brand .env wins, a company .env serves every brand that sets none. Every delivery is `env`, the composed .env on the developer\'s own machine, because translation runs locally by default and CI reads the committed cache ([#905](https://github.com/Omega-JS-Stack/omega/issues/905)): no workflow line delivers this key to a runner.',
798
912
  },
799
913
  {
800
914
  name: 'ANTHROPIC_API_KEY',
@@ -804,6 +918,9 @@ const ENV_SCHEMA = [
804
918
  secret: true,
805
919
  required: false,
806
920
  delivery: { backend: 'env' },
921
+ label: 'Anthropic API key',
922
+ url: 'https://console.anthropic.com/settings/keys',
923
+ hint: 'A workspace API key (the Claude Code subscription login is a separate thing and needs no key)',
807
924
  description: 'The Anthropic key wherever the backend calls Anthropic — the brand .env wins, a company .env serves every brand that sets none.',
808
925
  },
809
926
  {
@@ -854,8 +971,9 @@ const ENV_SCHEMA = [
854
971
  group: 'machine',
855
972
  secret: true,
856
973
  required: false,
974
+ requiredWhen: 'certificates.providers.apple',
857
975
  delivery: { desktop: 'ci' },
858
- description: "Password of the desktop signing certificate the certificates service created — electron-builder reads it at package time.",
976
+ description: "Password of the desktop signing certificate the certificates service created; electron-builder reads it at package time. Required once the brand declares Apple signing (certificates.providers.apple): an `omega deploy` that cannot push it ships an unsigned mac build.",
859
977
  },
860
978
  {
861
979
  name: 'VAPID_PRIVATE_KEY',
@@ -939,31 +1057,23 @@ const ENV_SCHEMA = [
939
1057
  description: "A target's own Measurement Protocol secret — the delivery renames the brand-level GOOGLE_ANALYTICS_SECRET_<TARGET> to this name (deliverAs), so it is never composed from a brand key of the same name.",
940
1058
  },
941
1059
  {
942
- name: 'PAYPAL_CLIENT_ID',
943
- owner: 'payment',
944
- targets: ['backend'],
945
- group: 'runtime',
946
- secret: false,
947
- required: false,
948
- description: 'Public PayPal client id — the backend publishes it into its own env from payment.providers.paypal.clientId at boot.',
949
- },
950
- {
951
- name: 'CHARGEBEE_SITE',
952
- owner: 'payment',
1060
+ name: 'OMEGA_LICENSE_STATUS',
1061
+ owner: 'workspace',
953
1062
  targets: ['backend'],
954
1063
  group: 'runtime',
955
1064
  secret: false,
956
1065
  required: false,
957
- description: 'Public Chargebee site name — the backend publishes it into its own env from payment.providers.chargebee.site at boot.',
1066
+ description: "The deploy-time license verdict (#320), written into dist/.env by the backend deploy itself — `licensed` or `keyless`. It is COMPUTED, never supplied: the runtime group renders no brand .env line, so nothing composes one down from the brand layer. The payment provider libraries refuse live processing on `keyless`; absent (every local lane, the emulator, a test) is today's behavior exactly.",
958
1067
  },
959
1068
  {
960
- name: 'OMEGA_LICENSE_STATUS',
961
- owner: 'workspace',
1069
+ name: 'OMEGA_SERVICE_ACCOUNT_JSON',
1070
+ owner: 'cloud',
962
1071
  targets: ['backend'],
963
1072
  group: 'runtime',
964
- secret: false,
1073
+ secret: true,
965
1074
  required: false,
966
- description: "The deploy-time license verdict (#320), written into dist/.env by the backend deploy itself — `licensed` or `keyless`. It is COMPUTED, never supplied: the runtime group renders no brand .env line, so nothing composes one down from the brand layer. The payment provider libraries refuse live processing on `keyless`; absent (every local lane, the emulator, a test) is today's behavior exactly.",
1075
+ delivery: { backend: 'ci' },
1076
+ description: "The deploy credential, as the service-account JSON's own CONTENTS ([#872](https://github.com/Omega-JS-Stack/omega/issues/872)): the backend deploy runs on a runner now, and a runner has no `.omega/secrets/` to read the key file from, so the deploy precheck publishes the file's bytes as this repo secret and the composed workflow writes them back to the path `firebase deploy` authenticates with. It is a FILE everywhere else, so it renders no brand .env line (the runtime group) and never composes into the artifact's own .env.",
967
1077
  },
968
1078
  {
969
1079
  name: 'CLAUDE_CODE_OAUTH_TOKEN',
@@ -985,12 +1095,19 @@ function envFileGroups() {
985
1095
  * The entry that governs a name — an exact match first, then the dynamic
986
1096
  * families' patterns. Undefined for a name the schema does not know.
987
1097
  *
1098
+ * A name no entry governs is the CONSUMER's own key
1099
+ * ([#835](https://github.com/Omega-JS-Stack/omega/issues/835)), and the
1100
+ * optional `schema` is the same escape every delivery function takes: a caller
1101
+ * (the tests) exercises the rules against a fixture, and nobody re-implements
1102
+ * the exact-then-pattern lookup.
1103
+ *
988
1104
  * @param {string} name - The env var name.
1105
+ * @param {object[]} [schema] - Env schema entries (default: the real schema).
989
1106
  * @returns {object|undefined} The schema entry.
990
1107
  */
991
- function envSchemaEntry(name) {
992
- return ENV_SCHEMA.find((entry) => entry.name === name)
993
- || ENV_SCHEMA.find((entry) => entry.match instanceof RegExp && entry.match.test(name));
1108
+ function envSchemaEntry(name, schema = ENV_SCHEMA) {
1109
+ return schema.find((entry) => entry.name === name)
1110
+ || schema.find((entry) => entry.match instanceof RegExp && entry.match.test(name));
994
1111
  }
995
1112
 
996
1113
  /**