Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .changeset/marketplace-nav-plugin-owned.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@objectstack/cloud-connection": minor
"@objectstack/platform-objects": minor
---

Marketplace Setup navigation is now plugin-owned (cloud ADR-0009): `MarketplaceProxyPlugin` carries the "Browse Marketplace" entry and `MarketplaceInstallLocalPlugin` carries "Installed Apps" — no plugin mounted (e.g. `OS_CLOUD_URL=off`), no entry, no dead page. The two entries are removed from `@objectstack/platform-objects`' setup-nav contributions (ADR-0029 K2 ownership handoff).
1 change: 1 addition & 0 deletions packages/cloud-connection/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,3 +49,4 @@ export type { RuntimeConfigPluginConfig, RuntimeConfigPlanFeatures } from './run
export { ConnectionCredentialStore, DEFAULT_CONNECTION_CREDENTIAL_PATH } from './connection-credential-store.js';
export type { StoredConnectionCredential } from './connection-credential-store.js';
export { CloudConnectionSettingsPage, CLOUD_CONNECTION_UI_BUNDLE } from './cloud-connection-ui.js';
export { MARKETPLACE_BROWSE_UI_BUNDLE, MARKETPLACE_INSTALLED_UI_BUNDLE } from './marketplace-ui.js';
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ import { resolveCloudUrl } from './cloud-url.js';
import { resolveMarketplacePublicBaseUrl } from './marketplace-public-url.js';
import { LocalManifestSource, type InstalledManifestEntry } from './local-manifest-source.js';
import { ConnectionCredentialStore } from './connection-credential-store.js';
import { MARKETPLACE_INSTALLED_UI_BUNDLE } from './marketplace-ui.js';

const ROUTE_BASE = '/api/v1/marketplace/install-local';

Expand Down Expand Up @@ -88,6 +89,13 @@ export class MarketplaceInstallLocalPlugin implements Plugin {

start = async (ctx: PluginContext): Promise<void> => {
ctx.hook('kernel:ready', async () => {
// Plugin-owned Setup nav (cloud ADR-0009): "Installed Apps"
// ships WITH the local-install capability.
try {
const manifest = ctx.getService<{ register(m: any): void }>('manifest');
manifest?.register?.(MARKETPLACE_INSTALLED_UI_BUNDLE);
} catch { /* no manifest service */ }

// 1. Rehydrate previously installed packages so they survive restart.
await this.rehydrate(ctx);

Expand Down
10 changes: 10 additions & 0 deletions packages/cloud-connection/src/marketplace-proxy-plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@

import type { Plugin, PluginContext } from '@objectstack/core';
import { resolveCloudUrl } from './cloud-url.js';
import { MARKETPLACE_BROWSE_UI_BUNDLE } from './marketplace-ui.js';
import {
resolveMarketplacePublicBaseUrl,
publicMarketplaceKeyForApiPath,
Expand Down Expand Up @@ -171,6 +172,15 @@ export class MarketplaceProxyPlugin implements Plugin {

start = async (ctx: PluginContext): Promise<void> => {
ctx.hook('kernel:ready', async () => {
// Plugin-owned Setup nav (cloud ADR-0009): the "Browse
// Marketplace" entry ships WITH the browse capability — no
// proxy mounted, no entry. Best-effort: headless kernels
// simply have no Setup surface.
try {
const manifest = ctx.getService<{ register(m: any): void }>('manifest');
manifest?.register?.(MARKETPLACE_BROWSE_UI_BUNDLE);
} catch { /* no manifest service */ }

let httpServer: any;
try {
httpServer = ctx.getService('http-server');
Expand Down
60 changes: 60 additions & 0 deletions packages/cloud-connection/src/marketplace-ui.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.

/**
* Marketplace — plugin-owned Setup navigation (cloud ADR-0009: cloud
* functionality ships as plugins carrying their FULL UI surface).
*
* Ownership moved here from `@objectstack/platform-objects`'
* setup-nav.contributions.ts (ADR-0029 K2's standing direction): the nav
* entry now lives and dies with the capability —
*
* - no MarketplaceProxyPlugin mounted (`OS_CLOUD_URL=off`) → no
* "Browse Marketplace" entry → no dead page.
* - no MarketplaceInstallLocalPlugin → no "Installed Apps" entry.
*
* The URLs still point at the console's existing marketplace routes; the
* pages themselves migrate to plugin-carried metadata in later ADR-0009
* stages (Installed Apps first).
*/

/** "Browse Marketplace" — owned by the browse capability (the proxy). */
export const MARKETPLACE_BROWSE_UI_BUNDLE = {
id: 'com.objectstack.cloud-connection.marketplace-browse-ui',
namespace: 'sys',
version: '0.1.0',
type: 'plugin',
scope: 'system',
name: 'Marketplace Browse UI',
description: 'Setup navigation for the public marketplace catalog (browse).',
navigationContributions: [
{
app: 'setup',
group: 'group_apps',
priority: 100,
items: [
{ id: 'nav_marketplace_browse', type: 'url', label: 'Browse Marketplace', url: '/apps/setup/system/marketplace', icon: 'store' },
],
},
],
};

/** "Installed Apps" — owned by the local-install capability. */
export const MARKETPLACE_INSTALLED_UI_BUNDLE = {
id: 'com.objectstack.cloud-connection.marketplace-installed-ui',
namespace: 'sys',
version: '0.1.0',
type: 'plugin',
scope: 'system',
name: 'Marketplace Installed UI',
description: 'Setup navigation for locally-installed marketplace packages.',
navigationContributions: [
{
app: 'setup',
group: 'group_apps',
priority: 110,
items: [
{ id: 'nav_marketplace_installed', type: 'url', label: 'Installed Apps', url: '/apps/setup/system/marketplace/installed', icon: 'package-check' },
],
},
],
};
5 changes: 3 additions & 2 deletions packages/platform-objects/src/apps/setup-nav.contributions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ import type { NavigationContribution } from '@objectstack/spec/ui';

const BASE_PRIORITY = 100;

// Marketplace entries (browse / installed) moved to
// @objectstack/cloud-connection's marketplace plugins (cloud ADR-0009:
// the nav lives and dies with the capability — no plugin, no entry).
export const SETUP_NAV_CONTRIBUTIONS: NavigationContribution[] = [
{
app: 'setup',
Expand All @@ -40,8 +43,6 @@ export const SETUP_NAV_CONTRIBUTIONS: NavigationContribution[] = [
group: 'group_apps',
priority: BASE_PRIORITY,
items: [
{ id: 'nav_marketplace_browse', type: 'url', label: 'Browse Marketplace', url: '/apps/setup/system/marketplace', icon: 'store' },
{ id: 'nav_marketplace_installed', type: 'url', label: 'Installed Apps', url: '/apps/setup/system/marketplace/installed', icon: 'package-check', requiresObject: 'sys_package_installation' },
],
},
{
Expand Down
Loading