Skip to content

Commit 15da12a

Browse files
committed
refactor(rest): narrow the REST protocol dependency to DataProtocol & MetadataProtocol (ADR-0076 D9/A1.5, #2462)
The REST layer was typed against the full ObjectStackProtocol god-union while actually calling only the data CRUD + metadata control-plane slices (server-only extensions are feature-detected via casts). Introduce RestProtocol = DataProtocol & MetadataProtocol, thread it through RestServer / rest-api-plugin, and export it from the package barrel, per the D9 incremental narrowing guidance. Type-level only. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01A1BtxNeUaGmvUYr8FwtUNu
1 parent fae5dd0 commit 15da12a

3 files changed

Lines changed: 22 additions & 11 deletions

File tree

packages/rest/src/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
// REST Server
44
export { RestServer } from './rest-server.js';
5+
// The protocol slice the REST layer consumes (ADR-0076 D9 / #2462 A1.5)
6+
export type { RestProtocol } from './rest-server.js';
57

68
// Route Management
79
export { RouteManager, RouteGroupBuilder } from './route-manager.js';

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

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.
22

33
import { Plugin, PluginContext, IHttpServer } from '@objectstack/core';
4-
import { RestServer, RestKernelManager } from './rest-server.js';
5-
import { ObjectStackProtocol, RestServerConfig } from '@objectstack/spec/api';
4+
import { RestServer, RestKernelManager, RestProtocol } from './rest-server.js';
5+
import { RestServerConfig } from '@objectstack/spec/api';
66
import { registerPackageRoutes } from './package-routes.js';
77
import { registerExternalDatasourceRoutes } from './external-datasource-routes.js';
88
import type { PackageService } from '@objectstack/service-package';
@@ -25,7 +25,7 @@ export interface RestApiPluginConfig {
2525
*
2626
* Responsibilities:
2727
* 1. Consumes 'http.server' (or configured service)
28-
* 2. Consumes 'protocol' (ObjectStackProtocol)
28+
* 2. Consumes 'protocol' (the `RestProtocol` slice — DataProtocol + MetadataProtocol, ADR-0076 D9)
2929
* 3. Instantiates RestServer to auto-generate routes
3030
*/
3131
export function createRestApiPlugin(config: RestApiPluginConfig = {}): Plugin {
@@ -59,7 +59,7 @@ export function createRestApiPlugin(config: RestApiPluginConfig = {}): Plugin {
5959
const protocolService = config.protocolServiceName || 'protocol';
6060

6161
let server: IHttpServer | undefined;
62-
let protocol: ObjectStackProtocol | undefined;
62+
let protocol: RestProtocol | undefined;
6363

6464
try {
6565
server = ctx.getService<IHttpServer>(serverService);
@@ -68,7 +68,7 @@ export function createRestApiPlugin(config: RestApiPluginConfig = {}): Plugin {
6868
}
6969

7070
try {
71-
protocol = ctx.getService<ObjectStackProtocol>(protocolService);
71+
protocol = ctx.getService<RestProtocol>(protocolService);
7272
} catch (e) {
7373
// Ignore missing service
7474
}

packages/rest/src/rest-server.ts

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,16 @@ import {
77
import { isMcpServerEnabled } from '@objectstack/types';
88
import { RouteManager } from './route-manager.js';
99
import { RestServerConfig, RestApiConfig, CrudEndpointsConfig, MetadataEndpointsConfig, BatchEndpointsConfig, RouteGenerationConfig } from '@objectstack/spec/api';
10-
import { ObjectStackProtocol } from '@objectstack/spec/api';
10+
import { DataProtocol, MetadataProtocol } from '@objectstack/spec/api';
11+
12+
/**
13+
* The protocol slice the REST layer actually consumes (ADR-0076 D9 / #2462
14+
* A1.5): wire-normalized data CRUD plus the metadata control plane — not the
15+
* full `ObjectStackProtocol` union. Server-only extensions (drafts, history,
16+
* diagnostics, clone, …) are feature-detected via runtime casts and so don't
17+
* widen this contract.
18+
*/
19+
export type RestProtocol = DataProtocol & MetadataProtocol;
1120
import {
1221
buildFieldMetaMap,
1322
referenceFieldNames,
@@ -693,7 +702,7 @@ export interface RestEnvRegistry {
693702
}
694703

695704
export class RestServer {
696-
private protocol: ObjectStackProtocol;
705+
private protocol: RestProtocol;
697706
private config: NormalizedRestServerConfig;
698707
private routeManager: RouteManager;
699708
private kernelManager?: RestKernelManager;
@@ -749,7 +758,7 @@ export class RestServer {
749758

750759
constructor(
751760
server: IHttpServer,
752-
protocol: ObjectStackProtocol,
761+
protocol: RestProtocol,
753762
config: RestServerConfig = {},
754763
kernelManager?: RestKernelManager,
755764
envRegistry?: RestEnvRegistry,
@@ -876,12 +885,12 @@ export class RestServer {
876885
return undefined;
877886
}
878887

879-
private async resolveProtocol(environmentId?: string, req?: any): Promise<ObjectStackProtocol> {
888+
private async resolveProtocol(environmentId?: string, req?: any): Promise<RestProtocol> {
880889
if (environmentId === 'platform') return this.protocol;
881890
const envId = await this.resolveRequestEnvironmentId(environmentId, req);
882891
if (!envId || !this.kernelManager) return this.protocol;
883892
const kernel = await this.kernelManager.getOrCreate(envId);
884-
return kernel.getServiceAsync<ObjectStackProtocol>('protocol');
893+
return kernel.getServiceAsync<RestProtocol>('protocol');
885894
}
886895

887896
/**
@@ -998,7 +1007,7 @@ export class RestServer {
9981007
private async enforceApiAccess(
9991008
req: any,
10001009
res: any,
1001-
p: ObjectStackProtocol,
1010+
p: RestProtocol,
10021011
environmentId: string | undefined,
10031012
operation: string,
10041013
): Promise<boolean> {

0 commit comments

Comments
 (0)