Skip to content

Commit 1147e48

Browse files
committed
fix: enhance package route registration with protocol options
1 parent 718cb69 commit 1147e48

File tree

2 files changed

+87
-10
lines changed

2 files changed

+87
-10
lines changed

packages/rest/src/package-routes.ts

Lines changed: 84 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,33 @@
33
import { IHttpServer } from '@objectstack/core';
44
import type { PackageService } from '@objectstack/service-package';
55

6+
/**
7+
* Options for package route registration.
8+
*/
9+
export interface PackageRoutesOptions {
10+
/**
11+
* Protocol service (ObjectStackProtocol) — provides access to in-memory
12+
* SchemaRegistry packages loaded via defineStack()/AppPlugin at boot time.
13+
*/
14+
protocol?: { getMetaItems?(req: { type: string }): Promise<{ items: any[] }> };
15+
}
16+
617
/**
718
* Register package management API routes
819
*
920
* Provides endpoints for publishing, retrieving, and managing packages.
1021
* Routes:
1122
* - POST /api/v1/packages - Publish a package
12-
* - GET /api/v1/packages - List all packages
23+
* - GET /api/v1/packages - List all packages (merges registry + database)
1324
* - GET /api/v1/packages/:id - Get a specific package
1425
* - DELETE /api/v1/packages/:id - Delete a package
1526
*/
16-
export function registerPackageRoutes(server: IHttpServer, packageService: PackageService, basePath: string = '/api/v1') {
27+
export function registerPackageRoutes(
28+
server: IHttpServer,
29+
packageService: PackageService,
30+
basePath: string = '/api/v1',
31+
options: PackageRoutesOptions = {},
32+
) {
1733
const packagesPath = `${basePath}/packages`;
1834

1935
// POST /api/v1/packages - Publish a package
@@ -51,11 +67,54 @@ export function registerPackageRoutes(server: IHttpServer, packageService: Packa
5167
}
5268
});
5369

54-
// GET /api/v1/packages - List all packages (latest versions)
70+
// GET /api/v1/packages - List all packages (merges registry + database)
5571
server.get(packagesPath, async (_req, res) => {
5672
try {
57-
const packages = await packageService.list();
58-
res.json({ packages });
73+
// Merge two sources:
74+
// 1. Registry packages (in-memory, loaded at boot via defineStack/AppPlugin)
75+
// 2. Database packages (published via POST /packages)
76+
const packagesMap = new Map<string, any>();
77+
78+
// Registry packages (via protocol service → SchemaRegistry)
79+
if (options.protocol && typeof options.protocol.getMetaItems === 'function') {
80+
try {
81+
const result = await options.protocol.getMetaItems({ type: 'package' });
82+
if (result?.items) {
83+
for (const item of result.items) {
84+
const id = item.manifest?.id || item.id;
85+
if (id) {
86+
packagesMap.set(id, {
87+
...item,
88+
source: 'registry',
89+
});
90+
}
91+
}
92+
}
93+
} catch {
94+
// Protocol unavailable — continue with database only
95+
}
96+
}
97+
98+
// Database packages (published artifacts)
99+
try {
100+
const dbPackages = await packageService.list();
101+
for (const pkg of dbPackages) {
102+
const id = pkg.manifest?.id || pkg.id;
103+
if (id) {
104+
// Database entry takes precedence (has richer metadata from publish)
105+
packagesMap.set(id, {
106+
...packagesMap.get(id),
107+
...pkg,
108+
source: packagesMap.has(id) ? 'both' : 'database',
109+
});
110+
}
111+
}
112+
} catch {
113+
// Database query failed — continue with registry-only packages
114+
}
115+
116+
const packages = Array.from(packagesMap.values());
117+
res.json({ packages, total: packages.length });
59118
} catch (error) {
60119
res.status(500).json({ error: (error as Error).message });
61120
}
@@ -67,14 +126,30 @@ export function registerPackageRoutes(server: IHttpServer, packageService: Packa
67126
const packageId = req.params.id;
68127
const version = req.query?.version || 'latest';
69128

129+
// Try database first (richer data from publish)
70130
const pkg = await packageService.get(packageId, version);
71-
72-
if (!pkg) {
73-
res.status(404).json({ error: 'Package not found' });
131+
if (pkg) {
132+
res.json({ package: { ...pkg, source: 'database' } });
74133
return;
75134
}
76135

77-
res.json({ package: pkg });
136+
// Fall back to registry (in-memory loaded packages)
137+
if (options.protocol && typeof options.protocol.getMetaItems === 'function') {
138+
try {
139+
const result = await options.protocol.getMetaItems({ type: 'package' });
140+
const match = result?.items?.find((item: any) =>
141+
(item.manifest?.id || item.id) === packageId
142+
);
143+
if (match) {
144+
res.json({ package: { ...match, source: 'registry' } });
145+
return;
146+
}
147+
} catch {
148+
// Protocol unavailable
149+
}
150+
}
151+
152+
res.status(404).json({ error: 'Package not found' });
78153
} catch (error) {
79154
res.status(500).json({ error: (error as Error).message });
80155
}

packages/rest/src/rest-api-plugin.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,9 @@ export function createRestApiPlugin(config: RestApiPluginConfig = {}): Plugin {
7676
if (packageService) {
7777
const basePath = config.api?.api?.basePath || '/api';
7878
const version = config.api?.api?.version || 'v1';
79-
registerPackageRoutes(server, packageService, `${basePath}/${version}`);
79+
registerPackageRoutes(server, packageService, `${basePath}/${version}`, {
80+
protocol,
81+
});
8082
ctx.logger.info('Package management routes registered');
8183
}
8284
} catch (e) {

0 commit comments

Comments
 (0)