diff --git a/.changeset/spec-publish-meta-item-member.md b/.changeset/spec-publish-meta-item-member.md new file mode 100644 index 0000000000..73df48a459 --- /dev/null +++ b/.changeset/spec-publish-meta-item-member.md @@ -0,0 +1,14 @@ +--- +"@objectstack/spec": minor +--- + +**`MetadataProtocol` declares the optional `publishMetaItem` member, and `PublishMetaItemRequest` joins the spec** (#11006, maintainer ruling 2026-08-22, option B). + +`POST /api/v1/meta/:type/:name/publish` — the promotion half of Studio's designer save-then-publish loop — was a half-declared door: #7294 declared the response (`PublishMetaItemResponseSchema`) while the request shape and the interface member stayed undeclared, so the one HTTP call site reached the verb through a cast and its request literal was checked by nothing (measured: deleting the cast answers `TS2339` — the cast carried member-existence weight, not request-shape weight). + +Additive, not breaking: + +- `PublishMetaItemRequestSchema` / `PublishMetaItemRequest` — `{ type, name, organizationId?, actor?, message?, packageId? }`, mirroring the implementation's parameter type in `@objectstack/metadata-protocol` member for member. `packageId` is `string | null` with the absent-vs-`null` distinction documented (absent = match any package; `null` = pin to the package-unbound row). `environmentId` stays out by the #9741 ruling (transport-level routing key; `packages/rest`'s `TransportScopedMetaRequest` layers it on), and the internal `_skipSeedApply` batch-coordination key is deliberately not part of the wire contract. +- `MetadataProtocol.publishMetaItem?(request: PublishMetaItemRequest): Promise` — optional like its `deleteMetaItem` / `getMetaItemLayered` siblings: additive to a shipped contract, implementation predating declaration. An undeclared key in a request literal at the member's call shape is now a compile error. + +The follow-up that removes the `(p as any)` cast at the REST call site rides the engine lane; this change only declares the contract. diff --git a/content/docs/references/api/protocol.mdx b/content/docs/references/api/protocol.mdx index 476c33afb1..70a5ee6fe3 100644 --- a/content/docs/references/api/protocol.mdx +++ b/content/docs/references/api/protocol.mdx @@ -12,8 +12,8 @@ description: Protocol protocol schemas ## TypeScript Usage ```typescript -import { AiAgentCapabilitiesSchema, AiAgentChatRequestSchema, AiAgentSummarySchema, AiAgentsResponseSchema, AiChatRequestSchema, AiChatResponseSchema, AiCompleteRequestSchema, AiConversationSchema, AiMessageSchema, AiModelsResponseSchema, AiPendingActionSchema, AiPendingActionStatusSchema, AiStreamChunkSchema, ApproveAiPendingActionResponseSchema, AutomationActionsResponseSchema, AutomationTriggerRequestSchema, AutomationTriggerResponseSchema, BatchDataRequestSchema, BatchDataResponseSchema, CheckPermissionRequestSchema, CheckPermissionResponseSchema, CreateAiConversationRequestSchema, CreateDataRequestSchema, CreateDataResponseSchema, CreateManyDataRequestSchema, CreateManyDataResponseSchema, DeleteDataRequestSchema, DeleteDataResponseSchema, DeleteManyDataRequestSchema, DeleteManyDataResponseSchema, DeleteMetaItemRequestSchema, DeleteMetaItemResponseSchema, DisablePackageRequestSchema, DisablePackageResponseSchema, EnablePackageRequestSchema, EnablePackageResponseSchema, FindDataRequestSchema, FindDataResponseSchema, GetDataRequestSchema, GetDataResponseSchema, GetDiscoveryRequestSchema, GetDiscoveryResponseSchema, GetEffectivePermissionsRequestSchema, GetEffectivePermissionsResponseSchema, GetFieldLabelsRequestSchema, GetFieldLabelsResponseSchema, GetLocalesRequestSchema, GetLocalesResponseSchema, GetMetaItemCachedRequestSchema, GetMetaItemCachedResponseSchema, GetMetaItemLayeredRequestSchema, GetMetaItemLayeredResponseSchema, GetMetaItemRequestSchema, GetMetaItemResponseSchema, GetMetaItemsRequestSchema, GetMetaItemsResponseSchema, GetMetaTypesRequestSchema, GetMetaTypesResponseSchema, GetNotificationPreferencesRequestSchema, GetNotificationPreferencesResponseSchema, GetObjectPermissionsRequestSchema, GetObjectPermissionsResponseSchema, GetPackageRequestSchema, GetPackageResponseSchema, GetPresenceRequestSchema, GetPresenceResponseSchema, GetTranslationsRequestSchema, GetTranslationsResponseSchema, GetUiViewRequestSchema, GetUiViewResponseSchema, HttpFindQueryParamsSchema, InstallPackageRequestSchema, InstallPackageResponseSchema, ListAiConversationsRequestSchema, ListAiConversationsResponseSchema, ListAiPendingActionsRequestSchema, ListAiPendingActionsResponseSchema, ListNotificationsRequestSchema, ListNotificationsResponseSchema, ListPackagesRequestSchema, ListPackagesResponseSchema, MarkAllNotificationsReadRequestSchema, MarkAllNotificationsReadResponseSchema, MarkNotificationsReadRequestSchema, MarkNotificationsReadResponseSchema, NotificationSchema, NotificationPreferencesSchema, PublishMetaItemResponseSchema, PublishPackageDraftsResponseSchema, RealtimeConnectRequestSchema, RealtimeConnectResponseSchema, RealtimeDisconnectRequestSchema, RealtimeDisconnectResponseSchema, RealtimeSubscribeRequestSchema, RealtimeSubscribeResponseSchema, RealtimeUnsubscribeRequestSchema, RealtimeUnsubscribeResponseSchema, RegisterDeviceRequestSchema, RegisterDeviceResponseSchema, RejectAiPendingActionResponseSchema, RuntimeAuthoringIssueSchema, SaveMetaItemRequestSchema, SaveMetaItemResponseSchema, SetPresenceRequestSchema, SetPresenceResponseSchema, UninstallPackageRequestSchema, UninstallPackageResponseSchema, UnregisterDeviceRequestSchema, UnregisterDeviceResponseSchema, UpdateAiConversationRequestSchema, UpdateDataRequestSchema, UpdateDataResponseSchema, UpdateManyDataRequestSchema, UpdateManyDataResponseSchema, UpdateNotificationPreferencesRequestSchema, UpdateNotificationPreferencesResponseSchema, ValidateDataIssueSchema, ValidateDataRequestSchema, ValidateDataResponseSchema } from '@objectstack/spec/api'; -import type { AiAgentCapabilities, AiAgentChatRequest, AiAgentSummary, AiAgentsResponse, AiChatRequest, AiChatResponse, AiCompleteRequest, AiConversation, AiMessage, AiModelsResponse, AiPendingAction, AiPendingActionStatus, AiStreamChunk, ApproveAiPendingActionResponse, AutomationActionsResponse, AutomationTriggerRequest, AutomationTriggerResponse, BatchDataRequest, BatchDataResponse, CheckPermissionRequest, CheckPermissionResponse, CreateAiConversationRequest, CreateDataRequest, CreateDataResponse, CreateManyDataRequest, CreateManyDataResponse, DeleteDataRequest, DeleteDataResponse, DeleteManyDataRequest, DeleteManyDataResponse, DeleteMetaItemRequest, DeleteMetaItemResponse, DisablePackageRequest, DisablePackageResponse, EnablePackageRequest, EnablePackageResponse, FindDataRequest, FindDataResponse, GetDataRequest, GetDataResponse, GetDiscoveryRequest, GetDiscoveryResponse, GetEffectivePermissionsRequest, GetEffectivePermissionsResponse, GetFieldLabelsRequest, GetFieldLabelsResponse, GetLocalesRequest, GetLocalesResponse, GetMetaItemCachedRequest, GetMetaItemCachedResponse, GetMetaItemLayeredRequest, GetMetaItemLayeredResponse, GetMetaItemRequest, GetMetaItemResponse, GetMetaItemsRequest, GetMetaItemsResponse, GetMetaTypesRequest, GetMetaTypesResponse, GetNotificationPreferencesRequest, GetNotificationPreferencesResponse, GetObjectPermissionsRequest, GetObjectPermissionsResponse, GetPackageRequest, GetPackageResponse, GetPresenceRequest, GetPresenceResponse, GetTranslationsRequest, GetTranslationsResponse, GetUiViewRequest, GetUiViewResponse, InstallPackageRequest, InstallPackageResponse, ListAiConversationsRequest, ListAiConversationsResponse, ListAiPendingActionsRequest, ListAiPendingActionsResponse, ListNotificationsRequest, ListNotificationsResponse, ListPackagesRequest, ListPackagesResponse, MarkAllNotificationsReadRequest, MarkAllNotificationsReadResponse, MarkNotificationsReadRequest, MarkNotificationsReadResponse, Notification, NotificationPreferences, PublishMetaItemResponse, PublishPackageDraftsResponse, RealtimeConnectRequest, RealtimeConnectResponse, RealtimeDisconnectRequest, RealtimeDisconnectResponse, RealtimeSubscribeRequest, RealtimeSubscribeResponse, RealtimeUnsubscribeRequest, RealtimeUnsubscribeResponse, RegisterDeviceRequest, RegisterDeviceResponse, RejectAiPendingActionResponse, RuntimeAuthoringIssue, SaveMetaItemRequest, SaveMetaItemResponse, SetPresenceRequest, SetPresenceResponse, UninstallPackageRequest, UninstallPackageResponse, UnregisterDeviceRequest, UnregisterDeviceResponse, UpdateAiConversationRequest, UpdateDataRequest, UpdateDataResponse, UpdateManyDataRequest, UpdateManyDataResponse, UpdateNotificationPreferencesRequest, UpdateNotificationPreferencesResponse, ValidateDataIssue, ValidateDataRequest, ValidateDataResponse } from '@objectstack/spec/api'; +import { AiAgentCapabilitiesSchema, AiAgentChatRequestSchema, AiAgentSummarySchema, AiAgentsResponseSchema, AiChatRequestSchema, AiChatResponseSchema, AiCompleteRequestSchema, AiConversationSchema, AiMessageSchema, AiModelsResponseSchema, AiPendingActionSchema, AiPendingActionStatusSchema, AiStreamChunkSchema, ApproveAiPendingActionResponseSchema, AutomationActionsResponseSchema, AutomationTriggerRequestSchema, AutomationTriggerResponseSchema, BatchDataRequestSchema, BatchDataResponseSchema, CheckPermissionRequestSchema, CheckPermissionResponseSchema, CreateAiConversationRequestSchema, CreateDataRequestSchema, CreateDataResponseSchema, CreateManyDataRequestSchema, CreateManyDataResponseSchema, DeleteDataRequestSchema, DeleteDataResponseSchema, DeleteManyDataRequestSchema, DeleteManyDataResponseSchema, DeleteMetaItemRequestSchema, DeleteMetaItemResponseSchema, DisablePackageRequestSchema, DisablePackageResponseSchema, EnablePackageRequestSchema, EnablePackageResponseSchema, FindDataRequestSchema, FindDataResponseSchema, GetDataRequestSchema, GetDataResponseSchema, GetDiscoveryRequestSchema, GetDiscoveryResponseSchema, GetEffectivePermissionsRequestSchema, GetEffectivePermissionsResponseSchema, GetFieldLabelsRequestSchema, GetFieldLabelsResponseSchema, GetLocalesRequestSchema, GetLocalesResponseSchema, GetMetaItemCachedRequestSchema, GetMetaItemCachedResponseSchema, GetMetaItemLayeredRequestSchema, GetMetaItemLayeredResponseSchema, GetMetaItemRequestSchema, GetMetaItemResponseSchema, GetMetaItemsRequestSchema, GetMetaItemsResponseSchema, GetMetaTypesRequestSchema, GetMetaTypesResponseSchema, GetNotificationPreferencesRequestSchema, GetNotificationPreferencesResponseSchema, GetObjectPermissionsRequestSchema, GetObjectPermissionsResponseSchema, GetPackageRequestSchema, GetPackageResponseSchema, GetPresenceRequestSchema, GetPresenceResponseSchema, GetTranslationsRequestSchema, GetTranslationsResponseSchema, GetUiViewRequestSchema, GetUiViewResponseSchema, HttpFindQueryParamsSchema, InstallPackageRequestSchema, InstallPackageResponseSchema, ListAiConversationsRequestSchema, ListAiConversationsResponseSchema, ListAiPendingActionsRequestSchema, ListAiPendingActionsResponseSchema, ListNotificationsRequestSchema, ListNotificationsResponseSchema, ListPackagesRequestSchema, ListPackagesResponseSchema, MarkAllNotificationsReadRequestSchema, MarkAllNotificationsReadResponseSchema, MarkNotificationsReadRequestSchema, MarkNotificationsReadResponseSchema, NotificationSchema, NotificationPreferencesSchema, PublishMetaItemRequestSchema, PublishMetaItemResponseSchema, PublishPackageDraftsResponseSchema, RealtimeConnectRequestSchema, RealtimeConnectResponseSchema, RealtimeDisconnectRequestSchema, RealtimeDisconnectResponseSchema, RealtimeSubscribeRequestSchema, RealtimeSubscribeResponseSchema, RealtimeUnsubscribeRequestSchema, RealtimeUnsubscribeResponseSchema, RegisterDeviceRequestSchema, RegisterDeviceResponseSchema, RejectAiPendingActionResponseSchema, RuntimeAuthoringIssueSchema, SaveMetaItemRequestSchema, SaveMetaItemResponseSchema, SetPresenceRequestSchema, SetPresenceResponseSchema, UninstallPackageRequestSchema, UninstallPackageResponseSchema, UnregisterDeviceRequestSchema, UnregisterDeviceResponseSchema, UpdateAiConversationRequestSchema, UpdateDataRequestSchema, UpdateDataResponseSchema, UpdateManyDataRequestSchema, UpdateManyDataResponseSchema, UpdateNotificationPreferencesRequestSchema, UpdateNotificationPreferencesResponseSchema, ValidateDataIssueSchema, ValidateDataRequestSchema, ValidateDataResponseSchema } from '@objectstack/spec/api'; +import type { AiAgentCapabilities, AiAgentChatRequest, AiAgentSummary, AiAgentsResponse, AiChatRequest, AiChatResponse, AiCompleteRequest, AiConversation, AiMessage, AiModelsResponse, AiPendingAction, AiPendingActionStatus, AiStreamChunk, ApproveAiPendingActionResponse, AutomationActionsResponse, AutomationTriggerRequest, AutomationTriggerResponse, BatchDataRequest, BatchDataResponse, CheckPermissionRequest, CheckPermissionResponse, CreateAiConversationRequest, CreateDataRequest, CreateDataResponse, CreateManyDataRequest, CreateManyDataResponse, DeleteDataRequest, DeleteDataResponse, DeleteManyDataRequest, DeleteManyDataResponse, DeleteMetaItemRequest, DeleteMetaItemResponse, DisablePackageRequest, DisablePackageResponse, EnablePackageRequest, EnablePackageResponse, FindDataRequest, FindDataResponse, GetDataRequest, GetDataResponse, GetDiscoveryRequest, GetDiscoveryResponse, GetEffectivePermissionsRequest, GetEffectivePermissionsResponse, GetFieldLabelsRequest, GetFieldLabelsResponse, GetLocalesRequest, GetLocalesResponse, GetMetaItemCachedRequest, GetMetaItemCachedResponse, GetMetaItemLayeredRequest, GetMetaItemLayeredResponse, GetMetaItemRequest, GetMetaItemResponse, GetMetaItemsRequest, GetMetaItemsResponse, GetMetaTypesRequest, GetMetaTypesResponse, GetNotificationPreferencesRequest, GetNotificationPreferencesResponse, GetObjectPermissionsRequest, GetObjectPermissionsResponse, GetPackageRequest, GetPackageResponse, GetPresenceRequest, GetPresenceResponse, GetTranslationsRequest, GetTranslationsResponse, GetUiViewRequest, GetUiViewResponse, InstallPackageRequest, InstallPackageResponse, ListAiConversationsRequest, ListAiConversationsResponse, ListAiPendingActionsRequest, ListAiPendingActionsResponse, ListNotificationsRequest, ListNotificationsResponse, ListPackagesRequest, ListPackagesResponse, MarkAllNotificationsReadRequest, MarkAllNotificationsReadResponse, MarkNotificationsReadRequest, MarkNotificationsReadResponse, Notification, NotificationPreferences, PublishMetaItemRequest, PublishMetaItemResponse, PublishPackageDraftsResponse, RealtimeConnectRequest, RealtimeConnectResponse, RealtimeDisconnectRequest, RealtimeDisconnectResponse, RealtimeSubscribeRequest, RealtimeSubscribeResponse, RealtimeUnsubscribeRequest, RealtimeUnsubscribeResponse, RegisterDeviceRequest, RegisterDeviceResponse, RejectAiPendingActionResponse, RuntimeAuthoringIssue, SaveMetaItemRequest, SaveMetaItemResponse, SetPresenceRequest, SetPresenceResponse, UninstallPackageRequest, UninstallPackageResponse, UnregisterDeviceRequest, UnregisterDeviceResponse, UpdateAiConversationRequest, UpdateDataRequest, UpdateDataResponse, UpdateManyDataRequest, UpdateManyDataResponse, UpdateNotificationPreferencesRequest, UpdateNotificationPreferencesResponse, ValidateDataIssue, ValidateDataRequest, ValidateDataResponse } from '@objectstack/spec/api'; // Validate data const result = AiAgentCapabilitiesSchema.parse(data); @@ -1218,6 +1218,22 @@ List packages response | **channels** | `Record` | optional | Per-channel notification preferences | +--- + +## PublishMetaItemRequest + +### Properties + +| Property | Type | Required | Description | +| :--- | :--- | :--- | :--- | +| **type** | `string` | ✅ | Metadata type name | +| **name** | `string` | ✅ | Item name | +| **organizationId** | `string` | optional | Organization (tenant) scope for the promotion. The implementation resolves the draft through the org partition (ADR-0005, #8805), so a draft authored org-scoped must be published under the same scope or the lookup answers 404 `[no_draft]`. Absent = environment-wide. | +| **actor** | `string` | optional | Identity recorded on the `op='publish'` history event. On the REST door this is the request's authenticated identity (one producer, #7749) — never a caller-supplied header. | +| **message** | `string` | optional | Optional human-readable note recorded with the publish history event. | +| **packageId** | `string \| null` | optional | ADR-0048 — the software package the draft being promoted was listed under, when the caller has one to state (`?package=` on the REST door; #10063 / #10350). ⚠️ `null` is NOT the same as absent, and the difference is load-bearing: the implementation branches on the KEY BEING PRESENT, so an ABSENT key keeps the historical "match any package" resolution while `null` pins the lookup to the package-UNBOUND row. Spread it in conditionally; a present-and-`undefined` key coerces to `null` downstream and makes a package-bound draft unfindable — a silent `no_draft` on the untouched path. | + + --- ## PublishMetaItemResponse diff --git a/content/docs/references/index.mdx b/content/docs/references/index.mdx index a95ae60b70..5f74ebfba9 100644 --- a/content/docs/references/index.mdx +++ b/content/docs/references/index.mdx @@ -1,6 +1,6 @@ --- title: Protocol Reference -description: Every schema published by @objectstack/spec — 1585 schemas across 14 protocol modules +description: Every schema published by @objectstack/spec — 1586 schemas across 14 protocol modules --- {/* ⚠️ AUTO-GENERATED — DO NOT EDIT. Run build-docs.ts to regenerate. Hand-written docs live in the module folders under content/docs/. */} @@ -20,7 +20,7 @@ counts are sums of the rows they head. Regenerate with | Module | Pages | Schemas | Description | | :--- | ---: | ---: | :--- | | [AI Protocol](/docs/references/ai) | 11 | 66 | Agents, tools, skills, RAG and knowledge sources, model registry, conversations. | -| [API Protocol](/docs/references/api) | 29 | 417 | REST contracts, endpoints, routing, realtime, batch, discovery. | +| [API Protocol](/docs/references/api) | 29 | 418 | REST contracts, endpoints, routing, realtime, batch, discovery. | | [Automation Protocol](/docs/references/automation) | 13 | 68 | Flows and their nodes, approvals, ETL pipelines, webhooks, state machines, execution records. | | [Cloud Protocol](/docs/references/cloud) | 11 | 94 | Environments, packages and versions, marketplace, developer portal, tenancy. | | [Data Protocol](/docs/references/data) | 29 | 166 | Objects, fields, queries, filters, datasources and drivers — the ObjectQL layer. | @@ -33,7 +33,7 @@ counts are sums of the rows they head. Regenerate with | [Studio Protocol](/docs/references/studio) | 3 | 35 | Studio designer metadata — the authoring surfaces for the protocols above. | | [System Protocol](/docs/references/system) | 36 | 287 | The runtime environment — logging, jobs, cache, metrics, notifications, i18n and compliance. | | [UI Protocol](/docs/references/ui) | 16 | 156 | Apps, pages, views, dashboards, reports, actions and themes — the ObjectUI layer. | -| **Total** | **199** | **1585** | 14 protocol modules | +| **Total** | **199** | **1586** | 14 protocol modules | --- @@ -61,7 +61,7 @@ Agents, tools, skills, RAG and knowledge sources, model registry, conversations. ## API Protocol -**Source:** `packages/spec/src/api/` · **Import:** `@objectstack/spec/api` · **29 pages, 417 schemas** +**Source:** `packages/spec/src/api/` · **Import:** `@objectstack/spec/api` · **29 pages, 418 schemas** REST contracts, endpoints, routing, realtime, batch, discovery. @@ -86,7 +86,7 @@ REST contracts, endpoints, routing, realtime, batch, discovery. | [`odata.zod.ts`](/docs/references/api/odata) | `ODataConfig`, `ODataError`, `ODataFilterFunction`, `ODataMetadata`, `ODataQuery`, `ODataResponse` | | [`package-api.zod.ts`](/docs/references/api/package-api) | `GetInstalledPackageRequest`, `GetInstalledPackageResponse`, `ListInstalledPackagesRequest`, `ListInstalledPackagesResponse`, `PackageApiErrorCode`, `PackageInstallRequest`, `PackageInstallResponse`, `PackagePathParams`, `PackageRollbackRequest`, `PackageRollbackResponse`, `PackageUpgradeRequest`, `PackageUpgradeResponse`, `ResolveDependenciesRequest`, `ResolveDependenciesResponse`, `UninstallPackageApiRequest`, `UninstallPackageApiResponse`, `UploadArtifactRequest`, `UploadArtifactResponse` | | [`plugin-rest-api.zod.ts`](/docs/references/api/plugin-rest-api) | `ErrorHandlingConfig`, `HandlerStatus`, `OpenApiGenerationConfig`, `RequestValidationConfig`, `ResponseEnvelopeConfig`, `RestApiEndpoint`, `RestApiPluginConfig`, `RestApiRouteCategory`, `RestApiRouteRegistration`, `RouteCoverageEntry`, `RouteCoverageReport`, `ValidationMode` | -| [`protocol.zod.ts`](/docs/references/api/protocol) | `AiAgentCapabilities`, `AiAgentChatRequest`, `AiAgentSummary`, `AiAgentsResponse`, `AiChatRequest`, `AiChatResponse`, `AiCompleteRequest`, `AiConversation`, `AiMessage`, `AiModelsResponse`, `AiPendingAction`, `AiPendingActionStatus`, `AiStreamChunk`, `ApproveAiPendingActionResponse`, `AutomationActionsResponse`, `AutomationTriggerRequest`, `AutomationTriggerResponse`, `BatchDataRequest`, `BatchDataResponse`, `CheckPermissionRequest`, `CheckPermissionResponse`, `CreateAiConversationRequest`, `CreateDataRequest`, `CreateDataResponse`, `CreateManyDataRequest`, `CreateManyDataResponse`, `DeleteDataRequest`, `DeleteDataResponse`, `DeleteManyDataRequest`, `DeleteManyDataResponse`, `DeleteMetaItemRequest`, `DeleteMetaItemResponse`, `DisablePackageRequest`, `DisablePackageResponse`, `EnablePackageRequest`, `EnablePackageResponse`, `FindDataRequest`, `FindDataResponse`, `GetDataRequest`, `GetDataResponse`, `GetDiscoveryRequest`, `GetDiscoveryResponse`, `GetEffectivePermissionsRequest`, `GetEffectivePermissionsResponse`, `GetFieldLabelsRequest`, `GetFieldLabelsResponse`, `GetLocalesRequest`, `GetLocalesResponse`, `GetMetaItemCachedRequest`, `GetMetaItemCachedResponse`, `GetMetaItemLayeredRequest`, `GetMetaItemLayeredResponse`, `GetMetaItemRequest`, `GetMetaItemResponse`, `GetMetaItemsRequest`, `GetMetaItemsResponse`, `GetMetaTypesRequest`, `GetMetaTypesResponse`, `GetNotificationPreferencesRequest`, `GetNotificationPreferencesResponse`, `GetObjectPermissionsRequest`, `GetObjectPermissionsResponse`, `GetPackageRequest`, `GetPackageResponse`, `GetPresenceRequest`, `GetPresenceResponse`, `GetTranslationsRequest`, `GetTranslationsResponse`, `GetUiViewRequest`, `GetUiViewResponse`, `HttpFindQueryParams`, `InstallPackageRequest`, `InstallPackageResponse`, `ListAiConversationsRequest`, `ListAiConversationsResponse`, `ListAiPendingActionsRequest`, `ListAiPendingActionsResponse`, `ListNotificationsRequest`, `ListNotificationsResponse`, `ListPackagesRequest`, `ListPackagesResponse`, `MarkAllNotificationsReadRequest`, `MarkAllNotificationsReadResponse`, `MarkNotificationsReadRequest`, `MarkNotificationsReadResponse`, `Notification`, `NotificationPreferences`, `PublishMetaItemResponse`, `PublishPackageDraftsResponse`, `RealtimeConnectRequest`, `RealtimeConnectResponse`, `RealtimeDisconnectRequest`, `RealtimeDisconnectResponse`, `RealtimeSubscribeRequest`, `RealtimeSubscribeResponse`, `RealtimeUnsubscribeRequest`, `RealtimeUnsubscribeResponse`, `RegisterDeviceRequest`, `RegisterDeviceResponse`, `RejectAiPendingActionResponse`, `RuntimeAuthoringIssue`, `SaveMetaItemRequest`, `SaveMetaItemResponse`, `SetPresenceRequest`, `SetPresenceResponse`, `UninstallPackageRequest`, `UninstallPackageResponse`, `UnregisterDeviceRequest`, `UnregisterDeviceResponse`, `UpdateAiConversationRequest`, `UpdateDataRequest`, `UpdateDataResponse`, `UpdateManyDataRequest`, `UpdateManyDataResponse`, `UpdateNotificationPreferencesRequest`, `UpdateNotificationPreferencesResponse`, `ValidateDataIssue`, `ValidateDataRequest`, `ValidateDataResponse` | +| [`protocol.zod.ts`](/docs/references/api/protocol) | `AiAgentCapabilities`, `AiAgentChatRequest`, `AiAgentSummary`, `AiAgentsResponse`, `AiChatRequest`, `AiChatResponse`, `AiCompleteRequest`, `AiConversation`, `AiMessage`, `AiModelsResponse`, `AiPendingAction`, `AiPendingActionStatus`, `AiStreamChunk`, `ApproveAiPendingActionResponse`, `AutomationActionsResponse`, `AutomationTriggerRequest`, `AutomationTriggerResponse`, `BatchDataRequest`, `BatchDataResponse`, `CheckPermissionRequest`, `CheckPermissionResponse`, `CreateAiConversationRequest`, `CreateDataRequest`, `CreateDataResponse`, `CreateManyDataRequest`, `CreateManyDataResponse`, `DeleteDataRequest`, `DeleteDataResponse`, `DeleteManyDataRequest`, `DeleteManyDataResponse`, `DeleteMetaItemRequest`, `DeleteMetaItemResponse`, `DisablePackageRequest`, `DisablePackageResponse`, `EnablePackageRequest`, `EnablePackageResponse`, `FindDataRequest`, `FindDataResponse`, `GetDataRequest`, `GetDataResponse`, `GetDiscoveryRequest`, `GetDiscoveryResponse`, `GetEffectivePermissionsRequest`, `GetEffectivePermissionsResponse`, `GetFieldLabelsRequest`, `GetFieldLabelsResponse`, `GetLocalesRequest`, `GetLocalesResponse`, `GetMetaItemCachedRequest`, `GetMetaItemCachedResponse`, `GetMetaItemLayeredRequest`, `GetMetaItemLayeredResponse`, `GetMetaItemRequest`, `GetMetaItemResponse`, `GetMetaItemsRequest`, `GetMetaItemsResponse`, `GetMetaTypesRequest`, `GetMetaTypesResponse`, `GetNotificationPreferencesRequest`, `GetNotificationPreferencesResponse`, `GetObjectPermissionsRequest`, `GetObjectPermissionsResponse`, `GetPackageRequest`, `GetPackageResponse`, `GetPresenceRequest`, `GetPresenceResponse`, `GetTranslationsRequest`, `GetTranslationsResponse`, `GetUiViewRequest`, `GetUiViewResponse`, `HttpFindQueryParams`, `InstallPackageRequest`, `InstallPackageResponse`, `ListAiConversationsRequest`, `ListAiConversationsResponse`, `ListAiPendingActionsRequest`, `ListAiPendingActionsResponse`, `ListNotificationsRequest`, `ListNotificationsResponse`, `ListPackagesRequest`, `ListPackagesResponse`, `MarkAllNotificationsReadRequest`, `MarkAllNotificationsReadResponse`, `MarkNotificationsReadRequest`, `MarkNotificationsReadResponse`, `Notification`, `NotificationPreferences`, `PublishMetaItemRequest`, `PublishMetaItemResponse`, `PublishPackageDraftsResponse`, `RealtimeConnectRequest`, `RealtimeConnectResponse`, `RealtimeDisconnectRequest`, `RealtimeDisconnectResponse`, `RealtimeSubscribeRequest`, `RealtimeSubscribeResponse`, `RealtimeUnsubscribeRequest`, `RealtimeUnsubscribeResponse`, `RegisterDeviceRequest`, `RegisterDeviceResponse`, `RejectAiPendingActionResponse`, `RuntimeAuthoringIssue`, `SaveMetaItemRequest`, `SaveMetaItemResponse`, `SetPresenceRequest`, `SetPresenceResponse`, `UninstallPackageRequest`, `UninstallPackageResponse`, `UnregisterDeviceRequest`, `UnregisterDeviceResponse`, `UpdateAiConversationRequest`, `UpdateDataRequest`, `UpdateDataResponse`, `UpdateManyDataRequest`, `UpdateManyDataResponse`, `UpdateNotificationPreferencesRequest`, `UpdateNotificationPreferencesResponse`, `ValidateDataIssue`, `ValidateDataRequest`, `ValidateDataResponse` | | [`query-adapter.zod.ts`](/docs/references/api/query-adapter) | `ODataQueryAdapter`, `OperatorMapping`, `QueryAdapterConfig`, `QueryAdapterTarget`, `RestQueryAdapter` | | [`realtime.zod.ts`](/docs/references/api/realtime) | `RealtimeConfig`, `RealtimeEvent`, `RealtimeEventType`, `RealtimePresence`, `Subscription`, `SubscriptionEvent`, `TransportProtocol` | | [`realtime-shared.zod.ts`](/docs/references/api/realtime-shared) | `BasePresence`, `PresenceStatus`, `RealtimeRecordAction` | diff --git a/docs/audits/2026-07-unknown-key-strictness-ledger.counts.md b/docs/audits/2026-07-unknown-key-strictness-ledger.counts.md index e0165a3208..0b75db4377 100644 --- a/docs/audits/2026-07-unknown-key-strictness-ledger.counts.md +++ b/docs/audits/2026-07-unknown-key-strictness-ledger.counts.md @@ -257,7 +257,7 @@ directory rather than per file. | Dir | Sites | |---|---| | `ai/` | 77 | -| `api/` | 409 | +| `api/` | 410 | | `cloud/` | 83 | | `identity/` | 32 | | `integration/` | 10 | diff --git a/packages/spec/api-surface/api.json b/packages/spec/api-surface/api.json index 9633dad573..2ccf7a2507 100644 --- a/packages/spec/api-surface/api.json +++ b/packages/spec/api-surface/api.json @@ -736,6 +736,8 @@ "PresignedUrlResponse (type)", "PresignedUrlResponseParsed (type)", "PresignedUrlResponseSchema (const)", + "PublishMetaItemRequest (type)", + "PublishMetaItemRequestSchema (const)", "PublishMetaItemResponse (type)", "PublishMetaItemResponseSchema (const)", "PublishPackageDraftsResponse (type)", diff --git a/packages/spec/authorable-surface/api.json b/packages/spec/authorable-surface/api.json index c53c12d87e..5ac6720b77 100644 --- a/packages/spec/authorable-surface/api.json +++ b/packages/spec/authorable-surface/api.json @@ -1278,6 +1278,12 @@ "api/PresignedUrlResponse:error", "api/PresignedUrlResponse:meta", "api/PresignedUrlResponse:success", + "api/PublishMetaItemRequest:actor", + "api/PublishMetaItemRequest:message", + "api/PublishMetaItemRequest:name", + "api/PublishMetaItemRequest:organizationId", + "api/PublishMetaItemRequest:packageId", + "api/PublishMetaItemRequest:type", "api/PublishMetaItemResponse:advisories", "api/PublishMetaItemResponse:materializeApplied", "api/PublishMetaItemResponse:message", diff --git a/packages/spec/export-origins/api.json b/packages/spec/export-origins/api.json index 785387e75c..b52c2573dd 100644 --- a/packages/spec/export-origins/api.json +++ b/packages/spec/export-origins/api.json @@ -736,6 +736,8 @@ "PresignedUrlResponse": "src/api/storage.zod.ts#PresignedUrlResponse (type)", "PresignedUrlResponseParsed": "src/api/storage.zod.ts#PresignedUrlResponseParsed (type)", "PresignedUrlResponseSchema": "src/api/storage.zod.ts#PresignedUrlResponseSchema (const)", + "PublishMetaItemRequest": "src/api/protocol.zod.ts#PublishMetaItemRequest (type)", + "PublishMetaItemRequestSchema": "src/api/protocol.zod.ts#PublishMetaItemRequestSchema (const)", "PublishMetaItemResponse": "src/api/protocol.zod.ts#PublishMetaItemResponse (type)", "PublishMetaItemResponseSchema": "src/api/protocol.zod.ts#PublishMetaItemResponseSchema (const)", "PublishPackageDraftsResponse": "src/api/protocol.zod.ts#PublishPackageDraftsResponse (type)", diff --git a/packages/spec/json-schema.manifest/api.json b/packages/spec/json-schema.manifest/api.json index 9ad4ca4f19..9ad0427bd1 100644 --- a/packages/spec/json-schema.manifest/api.json +++ b/packages/spec/json-schema.manifest/api.json @@ -304,6 +304,7 @@ "api/PresenceStatus", "api/PresenceUpdate", "api/PresignedUrlResponse", + "api/PublishMetaItemRequest", "api/PublishMetaItemResponse", "api/PublishPackageDraftsResponse", "api/QueryAdapterConfig", diff --git a/packages/spec/src/api/protocol.test.ts b/packages/spec/src/api/protocol.test.ts index 1b03156d32..6f7a8e3be6 100644 --- a/packages/spec/src/api/protocol.test.ts +++ b/packages/spec/src/api/protocol.test.ts @@ -64,6 +64,8 @@ import type { MetadataProtocol, GetMetaItemLayeredRequest, GetMetaItemLayeredResponse, + PublishMetaItemRequest, + PublishMetaItemResponse, } from './protocol.zod'; describe('ObjectStack Protocol', () => { @@ -1650,3 +1652,133 @@ describe('MetadataProtocol declares getMetaItemLayered (#9740)', () => { >(); }); }); + +import { PublishMetaItemRequestSchema } from './protocol.zod'; + +describe('PublishMetaItemRequestSchema mirrors the implementation parameter type (#11006)', () => { + // #7294 declared the RESPONSE side of `POST /meta/:type/:name/publish`; the + // request shape stayed undeclared — the half-declared door. Maintainer + // ruling 2026-08-22 (option B): declare the request and the interface + // member. The measure is the implementation's parameter type in + // `@objectstack/metadata-protocol` — `{ type, name, organizationId?, + // actor?, message?, packageId? }` — and the REST door's actual reads; + // nothing else is declared because nothing else is enforced. + // As in the #9726/#9741 blocks above, accept-pins assert the parsed VALUE: + // this is a non-strict object, so `success` alone is exactly the + // silent-strip state this family of cards closes. + + const base = { type: 'view', name: 'account_list' } as const; + + it('accepts the full request and PRESERVES every member through parse', () => { + const full = { + ...base, + organizationId: 'org_alpha', + actor: 'admin', + message: 'publish from designer', + packageId: 'pkg_crm', + }; + const result = PublishMetaItemRequestSchema.safeParse(full); + expect(result.success).toBe(true); + if (result.success) { + expect(result.data).toEqual(full); + } + }); + + it('requires type AND name — the promotion addresses one item', () => { + expect(PublishMetaItemRequestSchema.safeParse(base).success).toBe(true); + expect(PublishMetaItemRequestSchema.safeParse({ type: 'view' }).success).toBe(false); + expect(PublishMetaItemRequestSchema.safeParse({ name: 'account_list' }).success).toBe(false); + }); + + it('packageId accepts null AND preserves it apart from absent — the unbound-row pin', () => { + // `null` pins the lookup to the package-UNBOUND row; an ABSENT key means + // "match any package". Two different resolutions, so the parse must keep + // them distinguishable. + const withNull = PublishMetaItemRequestSchema.safeParse({ ...base, packageId: null }); + expect(withNull.success).toBe(true); + if (withNull.success) { + expect('packageId' in (withNull.data as object)).toBe(true); + expect((withNull.data as { packageId?: string | null }).packageId).toBeNull(); + } + const absent = PublishMetaItemRequestSchema.safeParse(base); + expect(absent.success).toBe(true); + if (absent.success) { + expect('packageId' in (absent.data as object)).toBe(false); + } + expect(PublishMetaItemRequestSchema.safeParse({ ...base, packageId: 42 }).success).toBe(false); + }); + + it('the three optional strings stay optional and reject non-strings — values, not bags', () => { + for (const key of ['organizationId', 'actor', 'message'] as const) { + const absent = PublishMetaItemRequestSchema.safeParse(base); + expect(absent.success).toBe(true); + if (absent.success) { + expect(key in (absent.data as object)).toBe(false); + } + expect(PublishMetaItemRequestSchema.safeParse({ ...base, [key]: 42 }).success).toBe(false); + expect(PublishMetaItemRequestSchema.safeParse({ ...base, [key]: { v: 'x' } }).success).toBe(false); + } + }); + + it('does not declare environmentId — transport-level by the #9741 ruling, stripped and shape-absent', () => { + // Same regression guard as the meta-read block above: if someone declares + // the member, the parse stops stripping it and this test names the ruling + // they are overturning (2026-08-18 on #9741: `environmentId` is the + // multi-kernel ROUTING key; `packages/rest` layers it on top via + // `TransportScopedMetaRequest`). + const result = PublishMetaItemRequestSchema.safeParse({ ...base, environmentId: 'env_alpha' }); + expect(result.success).toBe(true); + if (result.success) { + expect('environmentId' in (result.data as object)).toBe(false); + } + const shape = (PublishMetaItemRequestSchema as unknown as { shape: Record }).shape; + expect(Object.keys(shape)).not.toContain('environmentId'); + }); + + it('does not declare _skipSeedApply — internal batch coordination, not wire contract', () => { + const result = PublishMetaItemRequestSchema.safeParse({ ...base, _skipSeedApply: true }); + expect(result.success).toBe(true); + if (result.success) { + expect('_skipSeedApply' in (result.data as object)).toBe(false); + } + const shape = (PublishMetaItemRequestSchema as unknown as { shape: Record }).shape; + expect(Object.keys(shape)).not.toContain('_skipSeedApply'); + }); +}); + +describe('MetadataProtocol declares publishMetaItem (#11006)', () => { + // Type-level pins (compiled by the spec test typecheck, the + // translation-typegen.test.ts pattern — same as the #9740 block above). + // Before this declaration the cast at the REST call site carried + // MEMBER-EXISTENCE weight (deleting it answered TS2339, not TS2353), so a + // request literal there was typed by nothing. These pins are what turns + // red if the member is dropped again or drifts off the publish schemas. + + it('declares the member optional, against the publish request/response schemas', () => { + // Optional like its `deleteMetaItem` / `getMetaItemLayered` siblings: + // additive to a shipped contract, implementation predating declaration. + expectTypeOf().toEqualTypeOf< + ((request: PublishMetaItemRequest) => Promise) | undefined + >(); + // `{}` satisfies the member's slot exactly because it is optional — an + // implementation without the verb still type-checks against the + // interface. This line is the "implementation without it still + // type-checks" pin, as a real assignment rather than a matcher. + const absent: Pick = {}; + expect('publishMetaItem' in absent).toBe(false); + }); + + it('refuses an undeclared key at the member call shape — the #9612-gate class this card exists for', () => { + // Excess-property check on a fresh literal at the declared parameter + // type: the compile-time teeth the ruling asked for. Before the + // declaration any key sailed through the `(p as any)` cast. + const good: PublishMetaItemRequest = { type: 'view', name: 'account_list', packageId: 'pkg_crm' }; + expect(good.type).toBe('view'); + // @ts-expect-error `environmentId` is transport-level (#9741) — not a declared request member. + const withEnv: PublishMetaItemRequest = { type: 'view', name: 'account_list', environmentId: 'env_a' }; + expect(withEnv.name).toBe('account_list'); + // @ts-expect-error an undeclared (here: misspelt) key is refused at the call shape. + const misspelt: PublishMetaItemRequest = { type: 'view', name: 'account_list', packageID: 'pkg_crm' }; + expect(misspelt.name).toBe('account_list'); + }); +}); diff --git a/packages/spec/src/api/protocol.zod.ts b/packages/spec/src/api/protocol.zod.ts index 333bcf526e..795dc871fc 100644 --- a/packages/spec/src/api/protocol.zod.ts +++ b/packages/spec/src/api/protocol.zod.ts @@ -650,6 +650,64 @@ export const SaveMetaItemResponseSchema = lazySchema(() => z.object({ message: z.string().optional(), })); +/** + * Publish Metadata Item Request + * + * Request shape for `POST /api/v1/meta/:type/:name/publish` (the + * `publishMetaItem` protocol method) — the promotion door: `saveMetaItem` + * (with `?mode=draft`) stages a body, and this verb promotes the pending + * DRAFT overlay to the live `active` row. Mirrors the implementation's + * parameter type in `@objectstack/metadata-protocol` member for member — a + * declared-surface catch-up, not a new capability (#11006, maintainer ruling + * 2026-08-22: option B, closing the half-declared door #7294 left — the + * response side was declared there while the request and the interface member + * were not). The verb and every member here already ship and are enforced. + * + * Two members the implementation's parameter type family carries are + * deliberately NOT declared: + * + * - `environmentId` — the TRANSPORT-level multi-kernel routing key, OUT of + * protocol request shapes by the #9741 maintainer ruling (2026-08-18): + * `resolveProtocol(environmentId)` has already selected the target kernel + * before this method is entered, and `packages/rest` layers that one member + * on top of the declared shape via its `TransportScopedMetaRequest` wrapper, + * which is where a routing key belongs. + * - `_skipSeedApply` — internal coordination between `publishPackageDrafts` + * and the per-item path (the batch door suppresses the per-item seed apply + * and loads every seed body in one later pass). Never read from the wire, + * so it is not part of the contract. + */ +export const PublishMetaItemRequestSchema = lazySchema(() => z.object({ + type: z.string().describe('Metadata type name'), + name: z.string().describe('Item name'), + organizationId: z.string().optional().describe( + 'Organization (tenant) scope for the promotion. The implementation resolves ' + + 'the draft through the org partition (ADR-0005, #8805), so a draft ' + + 'authored org-scoped must be published under the same scope or the lookup ' + + 'answers 404 `[no_draft]`. Absent = environment-wide.', + ), + actor: z.string().optional().describe( + 'Identity recorded on the `op=\'publish\'` history event. On the REST door ' + + 'this is the request\'s authenticated identity (one producer, #7749) — ' + + 'never a caller-supplied header.', + ), + message: z.string().optional().describe( + 'Optional human-readable note recorded with the publish history event.', + ), + packageId: z.string().nullable().optional().describe( + 'ADR-0048 — the software package the draft being promoted was listed ' + + 'under, when the caller has one to state (`?package=` on the REST ' + + 'door; #10063 / #10350). ⚠️ `null` is NOT the same as absent, and the ' + + 'difference is load-bearing: the implementation branches on the KEY ' + + 'BEING PRESENT, so an ABSENT key keeps the historical "match any ' + + 'package" resolution while `null` pins the lookup to the ' + + 'package-UNBOUND row. Spread it in conditionally; a ' + + 'present-and-`undefined` key coerces to `null` downstream and makes a ' + + 'package-bound draft unfindable — a silent `no_draft` on the untouched ' + + 'path.', + ), +})); + /** * Publish Metadata Item Response * @@ -2220,6 +2278,7 @@ export type GetMetaItemLayeredResponse = z.input; export type SaveMetaItemRequest = z.input; export type SaveMetaItemResponse = z.input; +export type PublishMetaItemRequest = z.input; export type PublishMetaItemResponse = z.input; /** * The batch publish door's response — `POST /packages/:id/publish-drafts` @@ -2459,6 +2518,21 @@ export interface MetadataProtocol { getMetaItems(request: GetMetaItemsRequest): Promise; getMetaItem(request: GetMetaItemRequest): Promise; saveMetaItem(request: SaveMetaItemRequest): Promise; + /** + * Promote the pending DRAFT overlay to the live (`active`) row — the write + * sibling of `saveMetaItem` and the verb behind + * `POST /api/v1/meta/:type/:name/publish`, i.e. the second half of Studio's + * designer save-then-publish loop (ADR-0033 two-step: `?mode=draft` stages + * a body, this makes it live). Declared optional like its `deleteMetaItem` + * / `getMetaItemLayered` siblings: additive to a shipped contract, with the + * implementation (`@objectstack/metadata-protocol`) predating the + * declaration. #11006 (maintainer ruling 2026-08-22, option B) promotes + * what was an ADR-0076 D9 server-only extension into a declared optional + * member, closing the half-declared door #7294 left: the response side was + * declared there while the request and this member were not — so the + * request literal at the one HTTP call site had nothing checking it. + */ + publishMetaItem?(request: PublishMetaItemRequest): Promise; /** * Delete a metadata customization overlay row. Per ADR-0005 this is the * "reset to artifact factory default" semantic — it removes a sys_metadata diff --git a/packages/spec/src/type-alias-convention.pin.test.ts b/packages/spec/src/type-alias-convention.pin.test.ts index 8bbe89c848..06a3c017cd 100644 --- a/packages/spec/src/type-alias-convention.pin.test.ts +++ b/packages/spec/src/type-alias-convention.pin.test.ts @@ -267,7 +267,7 @@ import type * as M170 from './ui/component.zod.js'; import type * as M183 from './api/sortability.zod.js'; // --------------------------------------------------------------------------- -// 836 isomorphic aliases: `z.input` === `z.infer`, so no `XParsed` is declared. +// 837 isomorphic aliases: `z.input` === `z.infer`, so no `XParsed` is declared. // // That number is machine-checked, not hand-kept. The runtime companion at the // bottom of this file recomputes the pin count from the source and asserts that @@ -477,6 +477,7 @@ export type Iso833 = Assert, z.infer< typeof M28.SaveMetaItemRequestSchema > >>; export type Iso136 = Assert, z.infer< typeof M28.SaveMetaItemResponseSchema > >>; export type Iso836 = Assert, z.infer< typeof M28.PublishMetaItemResponseSchema > >>; +export type Iso856 = Assert, z.infer< typeof M28.PublishMetaItemRequestSchema > >>; export type Iso852 = Assert, z.infer< typeof M28.PublishPackageDraftsResponseSchema > >>; export type Iso837 = Assert, z.infer< typeof M28.RuntimeAuthoringIssueSchema > >>; export type Iso137 = Assert, z.infer< typeof M28.DeleteMetaItemRequestSchema > >>; @@ -1666,7 +1667,7 @@ describe('ADR-0122 type-alias convention', () => { // this title and the section header above the pin list — are now asserted // against the recomputed count below, so neither can go stale without a red // test naming it. - it('still declares all 836 isomorphic pins', () => { + it('still declares all 837 isomorphic pins', () => { // The truth of each pin is proved by tsc, not here — an `Assert>` // that stops holding is a compile error with the alias named. What tsc // cannot notice is a pin that was DELETED: removing the assertion removes @@ -1938,9 +1939,20 @@ describe('ADR-0122 type-alias convention', () => { // (ADR-0049 retirement of the whole theme authoring surface): the five // schemas they pinned no longer exist, so there is nothing left to exempt. // The Iso numbers are positional and stay vacant. + // + // 836 -> 837 is #11006's `PublishMetaItemRequestSchema` — the request half + // of the door whose response half `Iso836` pinned (#7294), declared on the + // 2026-08-22 maintainer ruling that also gave `MetadataProtocol` the + // optional `publishMetaItem` member. Isomorphism MEASURED, not assumed: + // the tree is two required `z.string()`s, three optional `z.string()`s and + // one `z.string().nullable().optional()` — no `.default()`, + // `.transform()`, `.catch()` or `.pipe()` anywhere — so the two shapes + // coincide and ADR-0122 gives it a pin rather than an `XParsed`. Its id is + // `Iso856`, the next free one — the ids are claims about pins, not + // positions. const self = readFileSync(fileURLToPath(import.meta.url), 'utf8'); const pins = self.match(/^export type Iso\d+ = Assert