Skip to content

Commit 0f3c00a

Browse files
committed
refactor(metadata-protocol): move the by-name item read's disabled-package face out of protocol.ts into protocol-meta-item-face.ts (#25467 cut 31)
Move-only, shape B. readMetaItemFace moves, unedited, into its own module. The engine field is handed over as a getter; the call to readMetaItem is handed over as a closure, so it still reaches the class method. noPendingDraftError gains `export` so the module can import it, as addressPackages and withDeclaredPageTypeDefault did in earlier cuts; the package index does not re-export it. Claude-Session: https://claude.ai/code/session_016SP1spj613tyGCgxoD1An6 Co-authored-by: Claude <noreply@anthropic.com>
1 parent 1900c02 commit 0f3c00a

2 files changed

Lines changed: 80 additions & 12 deletions

File tree

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license.
2+
3+
/**
4+
* [#25467 cut 31] The by-name item read's disabled-package face, from
5+
* `ObjectStackProtocolImplementation`, moved out of `protocol.ts` whole:
6+
* `readMetaItemFace`, the one body behind `getMetaItem` and
7+
* `getMetaItemForExecution`. It refuses an object of a disabled package,
8+
* withholds any other item of one, and otherwise answers what `readMetaItem`
9+
* answers.
10+
*
11+
* A MOVE, not a redesign. The function below is the body of the
12+
* `ObjectStackProtocolImplementation` method of the same name as it stood,
13+
* re-indented one level and otherwise unedited.
14+
*
15+
* ## How the moved body reaches the class
16+
*
17+
* The shape #23050 set for `rest-server.ts` (its `data-action-routes.ts`
18+
* header carries the full reasoning), as `protocol-batch-data.ts` applies it.
19+
* The class keeps the method — the published `dist/*.d.ts` lists its name,
20+
* docblock and declared signature — and its body is one literal of exactly
21+
* the {@link MetaItemFaceHost} members it reads, plus a `.call`. The `engine`
22+
* field is handed over as a getter, so the read finds it as it stands at call
23+
* time; the call to `readMetaItem` is handed over as a closure, so it still
24+
* reaches the class method. Every caller keeps calling the class method.
25+
*
26+
* The disabled-package helpers it reads are `protocol.ts`'s own, and are
27+
* imported from there. Nothing re-exports this module, so the published
28+
* surface does not move.
29+
*/
30+
31+
import type { ObjectStackProtocolImplementation } from './protocol.js';
32+
import {
33+
isItemOfDisabledPackage,
34+
isObjectOfDisabledPackage,
35+
noPendingDraftError,
36+
objectPackageDisabledError,
37+
} from './protocol.js';
38+
39+
/**
40+
* The `ObjectStackProtocolImplementation` members the function below reads —
41+
* every one of them, and no other; the function's `this` is the `Pick` of
42+
* them. Each is typed AS the class member (an indexed access on the class),
43+
* so a change to a member's signature on the class is a change here too.
44+
*/
45+
export interface MetaItemFaceHost {
46+
readonly engine: ObjectStackProtocolImplementation['engine'];
47+
readonly readMetaItem: ObjectStackProtocolImplementation['readMetaItem'];
48+
}
49+
50+
/** The body of `ObjectStackProtocolImplementation#readMetaItemFace`; the method's docblock there is its contract. */
51+
export async function readMetaItemFace(
52+
this: Pick<MetaItemFaceHost, 'engine' | 'readMetaItem'>,
53+
request: {
54+
type: string, name: string, packageId?: string, state?: 'active' | 'draft', previewDrafts?: boolean,
55+
member?: string,
56+
},
57+
face: 'served' | 'execution',
58+
) {
59+
if (request.type === 'object' && isObjectOfDisabledPackage(this.engine?.registry, request.name)) {
60+
throw objectPackageDisabledError(request.name);
61+
}
62+
const answer = await this.readMetaItem(request, { face });
63+
if (request.type === 'object' || request.type === 'package'
64+
|| !isItemOfDisabledPackage(this.engine?.registry, answer?.item)) {
65+
return answer;
66+
}
67+
if (request.state === 'draft') throw noPendingDraftError(request.type, request.name);
68+
const { item: _withheld, registration: _servedOnly, ...envelope } = answer as typeof answer & { registration?: unknown };
69+
return { ...envelope, item: undefined };
70+
}

‎packages/metadata-protocol/src/protocol.ts‎

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -425,6 +425,8 @@ import { isDeclaredCodeDatasource, isHostCodeDatasource } from './protocol-code-
425425
import { legacyOrganizationRowsOf, withoutLegacyOrganizationRows } from './protocol-legacy-organization-rows.js';
426426
// [#25467 cut 30] The object-extender fold onto a MetadataService object body.
427427
import { foldObjectExtendersFromRegistry } from './protocol-object-extender-fold.js';
428+
// [#25467 cut 31] The disabled-package face of the by-name item read.
429+
import { readMetaItemFace } from './protocol-meta-item-face.js';
428430

429431
/**
430432
* Canonical Zod schema per metadata type lives in
@@ -677,7 +679,7 @@ export function isItemOfDisabledPackage(registry: any, item: unknown): boolean {
677679
* finds no draft row and the read of a disabled package's draft, so the two
678680
* answers are byte-identical.
679681
*/
680-
function noPendingDraftError(type: string, name: string): Error & { code: 'NO_DRAFT'; status: 404 } {
682+
export function noPendingDraftError(type: string, name: string): Error & { code: 'NO_DRAFT'; status: 404 } {
681683
const err = new Error(`No pending draft exists for ${type}/${name}.`) as Error & { code: 'NO_DRAFT'; status: 404 };
682684
err.code = 'NO_DRAFT';
683685
err.status = 404;
@@ -10703,17 +10705,13 @@ export class ObjectStackProtocolImplementation implements
1070310705
type: string, name: string, packageId?: string, state?: 'active' | 'draft', previewDrafts?: boolean,
1070410706
member?: string,
1070510707
}, face: 'served' | 'execution') {
10706-
if (request.type === 'object' && isObjectOfDisabledPackage(this.engine?.registry, request.name)) {
10707-
throw objectPackageDisabledError(request.name);
10708-
}
10709-
const answer = await this.readMetaItem(request, { face });
10710-
if (request.type === 'object' || request.type === 'package'
10711-
|| !isItemOfDisabledPackage(this.engine?.registry, answer?.item)) {
10712-
return answer;
10713-
}
10714-
if (request.state === 'draft') throw noPendingDraftError(request.type, request.name);
10715-
const { item: _withheld, registration: _servedOnly, ...envelope } = answer as typeof answer & { registration?: unknown };
10716-
return { ...envelope, item: undefined };
10708+
// [#25467 cut 31] The body moved to `protocol-meta-item-face.ts` (see `MetaItemFaceHost`).
10709+
const readEngine = () => this.engine;
10710+
const host: ThisParameterType<typeof readMetaItemFace> = {
10711+
get engine() { return readEngine(); },
10712+
readMetaItem: (...a) => this.readMetaItem(...a),
10713+
};
10714+
return readMetaItemFace.call(host, request, face);
1071710715
}
1071810716

1071910717
/**

0 commit comments

Comments
 (0)