@openparachute/hub 0.5.2 → 0.5.9-rc.6

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 (76) hide show
  1. package/package.json +1 -1
  2. package/src/__tests__/admin-clients.test.ts +275 -0
  3. package/src/__tests__/admin-handlers.test.ts +159 -320
  4. package/src/__tests__/admin-host-admin-token.test.ts +52 -4
  5. package/src/__tests__/api-me.test.ts +149 -0
  6. package/src/__tests__/api-mint-token.test.ts +381 -0
  7. package/src/__tests__/api-revocation-list.test.ts +198 -0
  8. package/src/__tests__/api-revoke-token.test.ts +320 -0
  9. package/src/__tests__/api-tokens.test.ts +629 -0
  10. package/src/__tests__/auth.test.ts +680 -16
  11. package/src/__tests__/expose-2fa-warning.test.ts +123 -0
  12. package/src/__tests__/expose-cloudflare.test.ts +101 -0
  13. package/src/__tests__/expose.test.ts +199 -340
  14. package/src/__tests__/hub-server.test.ts +986 -66
  15. package/src/__tests__/hub.test.ts +108 -55
  16. package/src/__tests__/install-source.test.ts +249 -0
  17. package/src/__tests__/install.test.ts +50 -31
  18. package/src/__tests__/jwt-sign.test.ts +205 -0
  19. package/src/__tests__/lifecycle.test.ts +97 -2
  20. package/src/__tests__/module-manifest.test.ts +48 -0
  21. package/src/__tests__/notes-serve.test.ts +154 -2
  22. package/src/__tests__/oauth-handlers.test.ts +1000 -3
  23. package/src/__tests__/operator-token.test.ts +379 -3
  24. package/src/__tests__/origin-check.test.ts +220 -0
  25. package/src/__tests__/port-assign.test.ts +41 -52
  26. package/src/__tests__/rate-limit.test.ts +190 -0
  27. package/src/__tests__/services-manifest.test.ts +341 -0
  28. package/src/__tests__/setup.test.ts +12 -9
  29. package/src/__tests__/status.test.ts +372 -0
  30. package/src/__tests__/well-known.test.ts +69 -0
  31. package/src/admin-clients.ts +139 -0
  32. package/src/admin-handlers.ts +63 -260
  33. package/src/admin-host-admin-token.ts +25 -10
  34. package/src/admin-login-ui.ts +256 -0
  35. package/src/admin-vault-admin-token.ts +1 -1
  36. package/src/api-me.ts +124 -0
  37. package/src/api-mint-token.ts +239 -0
  38. package/src/api-revocation-list.ts +59 -0
  39. package/src/api-revoke-token.ts +153 -0
  40. package/src/api-tokens.ts +224 -0
  41. package/src/commands/auth.ts +408 -51
  42. package/src/commands/expose-2fa-warning.ts +82 -0
  43. package/src/commands/expose-cloudflare.ts +27 -0
  44. package/src/commands/expose-public-auto.ts +3 -7
  45. package/src/commands/expose.ts +88 -173
  46. package/src/commands/install.ts +11 -13
  47. package/src/commands/lifecycle.ts +53 -4
  48. package/src/commands/status.ts +99 -8
  49. package/src/csrf.ts +6 -3
  50. package/src/help.ts +13 -7
  51. package/src/hub-db.ts +63 -0
  52. package/src/hub-server.ts +572 -106
  53. package/src/hub.ts +272 -149
  54. package/src/install-source.ts +291 -0
  55. package/src/jwt-sign.ts +265 -5
  56. package/src/module-manifest.ts +48 -10
  57. package/src/notes-serve.ts +70 -9
  58. package/src/oauth-handlers.ts +395 -29
  59. package/src/oauth-ui.ts +188 -0
  60. package/src/operator-token.ts +272 -18
  61. package/src/origin-check.ts +127 -0
  62. package/src/port-assign.ts +28 -35
  63. package/src/rate-limit.ts +166 -0
  64. package/src/scope-explanations.ts +33 -2
  65. package/src/service-spec.ts +58 -13
  66. package/src/services-manifest.ts +62 -3
  67. package/src/sessions.ts +19 -0
  68. package/src/well-known.ts +54 -1
  69. package/web/ui/dist/assets/index-Bv6Bq_wx.js +60 -0
  70. package/web/ui/dist/assets/index-D54otIhv.css +1 -0
  71. package/web/ui/dist/index.html +2 -2
  72. package/src/__tests__/admin-config.test.ts +0 -281
  73. package/src/admin-config-ui.ts +0 -534
  74. package/src/admin-config.ts +0 -226
  75. package/web/ui/dist/assets/index-BKzPDdB0.js +0 -60
  76. package/web/ui/dist/assets/index-Dyk6g7vT.css +0 -1
package/src/well-known.ts CHANGED
@@ -26,6 +26,14 @@ export interface WellKnownVaultEntry {
26
26
  * to iterate without having to know every service's shortName ahead of time.
27
27
  * `infoUrl` points at the service's `/.parachute/info` endpoint (relative to
28
28
  * its mount path) which the hub fetches client-side for displayName/tagline.
29
+ *
30
+ * `displayName` and `uiUrl` are both optional — the discovery page renders
31
+ * a Services tile when `uiUrl` is present, falling back to the manifest
32
+ * short name when `displayName` is absent. Both are sourced via hub-server's
33
+ * `loadUiUrls`/`loadManagementUrls`-style readers from the module's
34
+ * `installDir/.parachute/module.json`, NOT from services.json (which gets
35
+ * overwritten on service boot per the "services own the write side"
36
+ * contract — see hub#238 commit message for the C-not-B trace).
29
37
  */
30
38
  export interface WellKnownServicesEntry {
31
39
  name: string;
@@ -33,6 +41,16 @@ export interface WellKnownServicesEntry {
33
41
  path: string;
34
42
  version: string;
35
43
  infoUrl: string;
44
+ /**
45
+ * Human-readable label for the discovery page. Sourced from
46
+ * `module.json:displayName` when available; falls back to
47
+ * `services.json:displayName` written at install time.
48
+ */
49
+ displayName?: string;
50
+ /** Where the service's primary user-facing UI lives, sourced from `module.json:uiUrl`. */
51
+ uiUrl?: string;
52
+ /** One-line subtitle for the discovery tile, sourced from `services.json:tagline`. */
53
+ tagline?: string;
36
54
  }
37
55
 
38
56
  /**
@@ -107,6 +125,19 @@ export interface BuildWellKnownOpts {
107
125
  * in. Returning `undefined` means "no admin SPA" and hub renders no link.
108
126
  */
109
127
  managementUrlFor?: (entry: ServiceEntry) => string | undefined;
128
+ /**
129
+ * Optional resolver mapping a `ServiceEntry` to its `module.json:uiUrl`,
130
+ * if any. Same shape as `managementUrlFor`. Returning `undefined` means
131
+ * "no user-facing UI" and discovery omits the Services tile (e.g. vault
132
+ * has no `uiUrl` — its content browses through Notes).
133
+ */
134
+ uiUrlFor?: (entry: ServiceEntry) => string | undefined;
135
+ /**
136
+ * Optional resolver mapping a `ServiceEntry` to its `module.json:displayName`.
137
+ * Hub-server reads this at request time; falls back to the entry's own
138
+ * `displayName` (from services.json) when absent.
139
+ */
140
+ displayNameFor?: (entry: ServiceEntry) => string | undefined;
110
141
  }
111
142
 
112
143
  /** Join a base origin and a path without double slashes — "/" stays "/". */
@@ -131,7 +162,29 @@ export function buildWellKnown(opts: BuildWellKnownOpts): WellKnownDocument {
131
162
  for (const path of pathsToEmit) {
132
163
  const url = new URL(path, `${base}/`).toString();
133
164
  const infoUrl = new URL(joinInfoPath(path), `${base}/`).toString();
134
- doc.services.push({ name: s.name, url, path, version: s.version, infoUrl });
165
+ const entry: WellKnownServicesEntry = {
166
+ name: s.name,
167
+ url,
168
+ path,
169
+ version: s.version,
170
+ infoUrl,
171
+ };
172
+ const displayName = opts.displayNameFor?.(s) ?? s.displayName;
173
+ if (displayName !== undefined) entry.displayName = displayName;
174
+ // Tagline rides on services.json (set by service-spec at install or
175
+ // by the service's own boot-time upsert). Read directly from the
176
+ // entry — no installDir round-trip needed since it's already
177
+ // persisted server-side and reasonably stable across reboots.
178
+ if (s.tagline !== undefined) entry.tagline = s.tagline;
179
+ // Resolve uiUrl: relative path → absolute URL against `base`; full
180
+ // http(s) URL → verbatim. Same rule managementUrl uses.
181
+ const uiUrlRaw = opts.uiUrlFor?.(s);
182
+ if (uiUrlRaw !== undefined) {
183
+ entry.uiUrl = /^https?:\/\//i.test(uiUrlRaw)
184
+ ? uiUrlRaw
185
+ : new URL(uiUrlRaw, `${base}/`).toString();
186
+ }
187
+ doc.services.push(entry);
135
188
  if (isVault) {
136
189
  const managementUrl = opts.managementUrlFor?.(s);
137
190
  const entry: WellKnownVaultEntry = {