@openparachute/hub 0.5.13 → 0.5.14-rc.2

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 (47) hide show
  1. package/package.json +2 -2
  2. package/src/__tests__/account-home-ui.test.ts +163 -0
  3. package/src/__tests__/admin-handlers.test.ts +74 -0
  4. package/src/__tests__/admin-host-admin-token.test.ts +62 -0
  5. package/src/__tests__/admin-vault-admin-token.test.ts +44 -0
  6. package/src/__tests__/api-account.test.ts +191 -1
  7. package/src/__tests__/api-modules-ops.test.ts +97 -0
  8. package/src/__tests__/api-modules.test.ts +32 -32
  9. package/src/__tests__/api-users.test.ts +383 -11
  10. package/src/__tests__/chrome-strip.test.ts +15 -15
  11. package/src/__tests__/hub-db.test.ts +194 -29
  12. package/src/__tests__/hub-server.test.ts +23 -23
  13. package/src/__tests__/notes-redirect.test.ts +20 -20
  14. package/src/__tests__/oauth-handlers.test.ts +722 -28
  15. package/src/__tests__/serve.test.ts +9 -9
  16. package/src/__tests__/services-manifest.test.ts +40 -40
  17. package/src/__tests__/setup-wizard.test.ts +493 -25
  18. package/src/__tests__/setup.test.ts +1 -1
  19. package/src/__tests__/status.test.ts +39 -0
  20. package/src/__tests__/users.test.ts +396 -9
  21. package/src/__tests__/well-known.test.ts +9 -9
  22. package/src/account-home-ui.ts +434 -0
  23. package/src/admin-handlers.ts +49 -17
  24. package/src/admin-host-admin-token.ts +25 -0
  25. package/src/admin-vault-admin-token.ts +17 -0
  26. package/src/api-account.ts +72 -6
  27. package/src/api-modules-ops.ts +52 -16
  28. package/src/api-modules.ts +3 -3
  29. package/src/api-users.ts +468 -55
  30. package/src/bun-link.ts +55 -0
  31. package/src/chrome-strip.ts +6 -6
  32. package/src/commands/install.ts +8 -21
  33. package/src/commands/status.ts +10 -1
  34. package/src/help.ts +2 -2
  35. package/src/hub-db.ts +42 -0
  36. package/src/hub-server.ts +69 -10
  37. package/src/hub-settings.ts +2 -2
  38. package/src/hub.ts +6 -6
  39. package/src/notes-redirect.ts +5 -5
  40. package/src/oauth-handlers.ts +278 -173
  41. package/src/oauth-ui.ts +18 -2
  42. package/src/service-spec.ts +39 -18
  43. package/src/setup-wizard.ts +489 -42
  44. package/src/users.ts +307 -29
  45. package/web/ui/dist/assets/index-tRmPbbC7.js +61 -0
  46. package/web/ui/dist/index.html +1 -1
  47. package/web/ui/dist/assets/index-Dzrbe6EP.js +0 -61
package/src/oauth-ui.ts CHANGED
@@ -153,6 +153,15 @@ export interface VaultPicker {
153
153
  * full dropdown — existing behavior.
154
154
  */
155
155
  lockedVault?: string;
156
+ /**
157
+ * Phase 2 PR 2 reviewer fold: set when the empty `availableVaults` is the
158
+ * "non-admin user has no vault assignments yet" shape (not "no vaults
159
+ * exist on the hub"). Swaps the picker empty-state copy from the admin-
160
+ * remediation hint (`parachute-vault create ...`) to a user-facing
161
+ * "ask your admin to assign you a vault" message. Only meaningful when
162
+ * `availableVaults.length === 0`.
163
+ */
164
+ emptyReason?: "no-assignments" | "no-vaults-on-hub";
156
165
  }
157
166
 
158
167
  export interface ErrorViewProps {
@@ -415,12 +424,19 @@ function renderVaultPicker(picker: VaultPicker): string {
415
424
  }
416
425
 
417
426
  if (picker.availableVaults.length === 0) {
427
+ // Phase 2 PR 2 reviewer fold: differentiate "no vaults on the hub"
428
+ // (admin-fixable) from "non-admin user has no vault assignments yet"
429
+ // (user has to wait for an admin to assign them). Default to the
430
+ // admin-remediation copy when unset — preserves Phase 1 behavior.
431
+ const noAssignments = picker.emptyReason === "no-assignments";
432
+ const helpHtml = noAssignments
433
+ ? `${verbList} need to be bound to a specific vault, but you have no vaults assigned on this hub yet. Ask the hub admin to assign you a vault via <code>/admin/users</code>, then try again.`
434
+ : `${verbList} need to be bound to a specific vault, but no vaults exist on this host yet. Create one with <code>parachute-vault create &lt;name&gt;</code> and try again.`;
418
435
  return `
419
436
  <section class="vault-picker vault-picker-empty">
420
437
  <h2 class="scopes-title">Pick a vault</h2>
421
438
  <p class="picker-help">
422
- ${verbList} need to be bound to a specific vault, but no vaults exist on this host yet.
423
- Create one with <code>parachute-vault create &lt;name&gt;</code> and try again.
439
+ ${helpHtml}
424
440
  </p>
425
441
  </section>`;
426
442
  }
@@ -68,7 +68,7 @@ export const PORT_RESERVATIONS: readonly PortReservation[] = [
68
68
  // fallback-port walker (`assignPort` in port-assign.ts) from handing this
69
69
  // port out to a colliding third-party module. The matching KNOWN_MODULES
70
70
  // row carries the canonicalPort + paths for status/expose surfaces.
71
- { port: 1946, name: "parachute-app", status: "assigned" },
71
+ { port: 1946, name: "parachute-surface", status: "assigned" },
72
72
  { port: 1947, name: "unassigned", status: "reserved" },
73
73
  { port: 1948, name: "unassigned", status: "reserved" },
74
74
  { port: 1949, name: "unassigned", status: "reserved" },
@@ -281,7 +281,7 @@ const NOTES_FALLBACK: FirstPartyFallback = {
281
281
  name: "notes",
282
282
  manifestName: "parachute-notes",
283
283
  displayName: "Notes",
284
- tagline: "Notes PWA — daemon deprecated 2026-05-22; install `app` for the current path.",
284
+ tagline: "Notes PWA — daemon deprecated 2026-05-22; install `surface` for the current path.",
285
285
  port: 1942,
286
286
  paths: ["/notes"],
287
287
  health: "/notes/health",
@@ -462,28 +462,29 @@ export const KNOWN_MODULES: Record<string, KnownModule> = {
462
462
  hasAuth: true,
463
463
  },
464
464
  },
465
- app: {
466
- short: "app",
467
- package: "@openparachute/app",
468
- manifestName: "parachute-app",
465
+ surface: {
466
+ short: "surface",
467
+ package: "@openparachute/surface",
468
+ manifestName: "parachute-surface",
469
469
  canonicalPort: 1946,
470
- displayName: "App",
470
+ displayName: "Surface",
471
471
  // Tagline telegraphs the auto-bootstrap so wizard + admin-SPA copy explain
472
- // the architecture: installing `app` brings Notes (and other UIs) along
473
- // via the Phase 2.1 bootstrap-default-apps step. The notes-daemon path
474
- // still exists as a back-compat install (CURATED_MODULES still lists
475
- // `notes`) but `app` is the recommended first install post-vault.
476
- tagline: "Host module for Parachute UIs — auto-installs Notes on first boot.",
477
- canonicalPaths: ["/app", "/.parachute"],
478
- canonicalHealth: "/app/healthz",
472
+ // the architecture: installing `surface` brings Notes (and other UIs)
473
+ // along via the Phase 2.1 bootstrap-default-apps step. The notes-daemon
474
+ // path still exists as a back-compat install (CURATED_MODULES still
475
+ // lists `notes`) but `surface` is the recommended first install
476
+ // post-vault. Renamed from `app` 2026-05-27 per patterns#102.
477
+ tagline: "Host module for Parachute surfaces — auto-installs Notes on first boot.",
478
+ canonicalPaths: ["/surface", "/.parachute"],
479
+ canonicalHealth: "/surface/healthz",
479
480
  canonicalStripPrefix: false,
480
481
  extras: {
481
482
  // Backward-compat startCmd — same rationale as scribe / vault / runner
482
483
  // above. Post-self-register, lifecycle reads module.json's startCmd via
483
484
  // `composeKnownModuleSpec` and that path wins.
484
- startCmd: () => ["parachute-app", "serve"],
485
- // App's admin + per-UI surfaces gate behind hub-issued JWTs (design
486
- // doc §6 same-hub auto-trust + scope `app:admin`). Surfaces in
485
+ startCmd: () => ["parachute-surface", "serve"],
486
+ // Surface's admin + per-UI surfaces gate behind hub-issued JWTs (design
487
+ // doc §6 same-hub auto-trust + scope `surface:admin`). Surfaces in
487
488
  // `parachute status` as auth-required by default, same posture as vault
488
489
  // + runner.
489
490
  hasAuth: true,
@@ -516,7 +517,27 @@ export const KNOWN_MODULES: Record<string, KnownModule> = {
516
517
  export const RETIRED_MODULES: Record<string, { retiredAt: string; replacement?: string }> = {
517
518
  agent: {
518
519
  retiredAt: "2026-05-20",
519
- replacement: "parachute-app or parachute-runner (depending on use case)",
520
+ replacement: "parachute-surface or parachute-runner (depending on use case)",
521
+ },
522
+ // 2026-05-20 retirement caught both forms of legacy rows.
523
+ "parachute-agent": {
524
+ retiredAt: "2026-05-20",
525
+ replacement: "parachute-surface or parachute-runner (depending on use case)",
526
+ },
527
+ // The `parachute-app` row name retires 2026-05-27 along with the
528
+ // app → surface rename (patterns#102). Operators upgrading from
529
+ // 0.5.13-stable will have a `parachute-app` row in services.json
530
+ // pointing at the now-removed @openparachute/app package; this entry
531
+ // drops it on load + steers them at `parachute install surface`.
532
+ // The short-name `app` form is included for legacy rows that used
533
+ // the short name as the `name` field.
534
+ app: {
535
+ retiredAt: "2026-05-27",
536
+ replacement: "parachute-surface (renamed from parachute-app — `parachute install surface`)",
537
+ },
538
+ "parachute-app": {
539
+ retiredAt: "2026-05-27",
540
+ replacement: "parachute-surface (renamed from parachute-app — `parachute install surface`)",
520
541
  },
521
542
  };
522
543