@@ -134,6 +134,28 @@ export type RestProtocol = DataProtocol & MetadataProtocol;
134134 * is now checked against the spec contract — an undeclared member is a compile
135135 * error at the call site, not a cast-and-hope. Never add protocol members
136136 * here; a key that belongs to the request belongs in the spec schema.
137+ *
138+ * [#9805] The same typing now covers the NON-door `getMetaItems` helper call
139+ * sites in this file (the object, book, doc, view and dataset listings). Two
140+ * spellings those sites carry deliberately SURVIVE the tightening, because
141+ * retiring either would change behaviour rather than typing:
142+ *
143+ * - The OPTIONAL CALL (`getMetaItems?.(…)`) and the
144+ * `typeof … === 'function'` guards. `getMetaItems` is a REQUIRED
145+ * `MetadataProtocol` member, so these are not feature detection in the
146+ * type sense — but a host may occupy the protocol slot with an object
147+ * that does not implement the whole surface, which is the measured reason
148+ * they exist (`metaTypeIsLive` documents the same deliberate spelling for
149+ * `getMetaTypes`). Retiring one turns a tolerated absence into a
150+ * `TypeError`.
151+ * - The RESULT handling. `getMetaItems` is declared to return
152+ * `{ type, items }`, while these sites also tolerate the bare-array shape
153+ * older hosts and stubs return (see `metaItemsArray`), so the response
154+ * stays runtime-shaped on purpose.
155+ *
156+ * The REQUEST is what is fully typeable today, and the request is what is
157+ * typed — which is the whole point: an undeclared key in one of these
158+ * literals is now a compile error instead of a cast-and-hope.
137159 */
138160type TransportScopedMetaRequest<R> = R & { environmentId?: string };
139161import {
@@ -1329,10 +1351,11 @@ export class RestServer {
13291351 */
13301352 private async loadObjectItems(p: RestProtocol, environmentId: string | undefined): Promise<any[]> {
13311353 try {
1332- const r: any = await (p as any).getMetaItems?.( {
1354+ const objectsRequest: TransportScopedMetaRequest<GetMetaItemsRequest> = {
13331355 type: 'object',
13341356 ...(environmentId ? { environmentId } : {}),
1335- });
1357+ };
1358+ const r: any = await p.getMetaItems?.(objectsRequest);
13361359 return Array.isArray(r?.items) ? r.items : Array.isArray(r) ? r : [];
13371360 } catch (err) {
13381361 // [#3545] The API-exposure gate fails OPEN when object metadata can't
@@ -1711,11 +1734,12 @@ export class RestServer {
17111734 }
17121735
17131736 /** Fetch every book of the environment, shaped for the audience resolver. */
1714- private async fetchAudienceBooks(p: any , environmentId: string | undefined): Promise<any[]> {
1715- const raw = await p.getMetaItems( {
1737+ private async fetchAudienceBooks(p: RestProtocol , environmentId: string | undefined): Promise<any[]> {
1738+ const booksRequest: TransportScopedMetaRequest<GetMetaItemsRequest> = {
17161739 type: 'book',
17171740 ...(environmentId ? { environmentId } : {}),
1718- } as any).catch(() => []);
1741+ };
1742+ const raw = await p.getMetaItems(booksRequest).catch(() => []);
17191743 return RestServer.metaItemsArray(raw).map((b: any) =>
17201744 b && typeof b === 'object' ? { ...b, packageId: b._packageId } : b,
17211745 );
@@ -4554,11 +4578,12 @@ export class RestServer {
45544578 const norm = (raw: any): any[] =>
45554579 Array.isArray(raw) ? raw : (raw && Array.isArray(raw.items) ? raw.items : []);
45564580
4557- const books = norm(await prot.getMetaItems( {
4581+ const booksRequest: TransportScopedMetaRequest<GetMetaItemsRequest> = {
45584582 type: 'book',
45594583 ...(packageId ? { packageId } : {}),
45604584 ...(environmentId ? { environmentId } : {}),
4561- } as any));
4585+ };
4586+ const books = norm(await prot.getMetaItems(booksRequest));
45624587 let book = books.find((b: any) => b && b.name === req.params.name);
45634588 if (!book) {
45644589 // Unknown name → the implicit per-package book (§6.4).
@@ -4583,11 +4608,12 @@ export class RestServer {
45834608 return;
45844609 }
45854610
4586- const docs = norm(await prot.getMetaItems( {
4611+ const docsRequest: TransportScopedMetaRequest<GetMetaItemsRequest> = {
45874612 type: 'doc',
45884613 ...(packageId ? { packageId } : {}),
45894614 ...(environmentId ? { environmentId } : {}),
4590- } as any))
4615+ };
4616+ const docs = norm(await prot.getMetaItems(docsRequest))
45914617 .map((d: any) => (d && typeof d === 'object' ? resolveDocLocale(d, locale) : d))
45924618 .map((d: any) => ({
45934619 name: d.name,
@@ -5135,10 +5161,12 @@ export class RestServer {
51355161 if (caller.authenticated && !RestServer.anyPermissionSetAudience(books)) {
51365162 allowed = true; // no gated book anywhere → org suffices
51375163 } else {
5138- const corpus = RestServer.metaItemsArray(await p.getMetaItems( {
5164+ const docCorpusRequest: TransportScopedMetaRequest<GetMetaItemsRequest> = {
51395165 type: 'doc',
51405166 ...(environmentId ? { environmentId } : {}),
5141- } as any).catch(() => []))
5167+ };
5168+ const corpus = RestServer.metaItemsArray(
5169+ await p.getMetaItems(docCorpusRequest).catch(() => []))
51425170 .filter((d: any) => d && typeof d === 'object')
51435171 .map((d: any) => ({
51445172 name: d.name,
@@ -8028,10 +8056,11 @@ export class RestServer {
80288056 ): Promise<{ view: any; form: any; object: string } | null> => {
80298057 const p = await this.resolveProtocol(environmentId, req);
80308058 if (typeof (p as any).getMetaItems !== 'function') return null;
8031- const result: any = await (p as any).getMetaItems( {
8059+ const viewsRequest: TransportScopedMetaRequest<GetMetaItemsRequest> = {
80328060 type: 'view',
80338061 ...(environmentId ? { environmentId } : {}),
8034- });
8062+ };
8063+ const result: any = await p.getMetaItems(viewsRequest);
80358064 const items: any[] = Array.isArray(result?.items)
80368065 ? result.items
80378066 : Array.isArray(result)
@@ -8092,10 +8121,11 @@ export class RestServer {
80928121 try {
80938122 const p = await this.resolveProtocol(environmentId, req);
80948123 if (typeof (p as any).getMetaItems === 'function') {
8095- const r: any = await (p as any).getMetaItems( {
8124+ const objectsRequest: TransportScopedMetaRequest<GetMetaItemsRequest> = {
80968125 type: 'object',
80978126 ...(environmentId ? { environmentId } : {}),
8098- });
8127+ };
8128+ const r: any = await p.getMetaItems(objectsRequest);
80998129 const items: any[] = Array.isArray(r?.items) ? r.items : Array.isArray(r) ? r : [];
81008130 const obj = items.find((o: any) => o?.name === match.object);
81018131 if (obj && obj.fields && typeof obj.fields === 'object') {
@@ -8408,10 +8438,11 @@ export class RestServer {
84088438 let referenceTo: string | undefined = picker.object;
84098439 if (!referenceTo && typeof (p as any).getMetaItems === 'function') {
84108440 try {
8411- const r: any = await (p as any).getMetaItems( {
8441+ const objectsRequest: TransportScopedMetaRequest<GetMetaItemsRequest> = {
84128442 type: 'object',
84138443 ...(environmentId ? { environmentId } : {}),
8414- });
8444+ };
8445+ const r: any = await p.getMetaItems(objectsRequest);
84158446 const items: any[] = Array.isArray(r?.items) ? r.items : Array.isArray(r) ? r : [];
84168447 const obj = items.find((o: any) => o?.name === match.object);
84178448 const def = obj?.fields?.[fieldName];
@@ -8611,7 +8642,8 @@ export class RestServer {
86118642 let dataset = body.dataset;
86128643 if (!dataset && body.datasetName) {
86138644 const p = await this.resolveProtocol(environmentId, req);
8614- const items = await (p as any).getMetaItems?.({ type: 'dataset', previewDrafts }).catch(() => null);
8645+ const datasetRequest: GetMetaItemsRequest = { type: 'dataset', previewDrafts };
8646+ const items: any = await p.getMetaItems?.(datasetRequest).catch(() => null);
86158647 const list = Array.isArray(items?.items) ? items.items : (Array.isArray(items) ? items : []);
86168648 dataset = list.find((d: any) => d?.name === body.datasetName);
86178649 if (!dataset) {
0 commit comments