Skip to content

Commit 9165d5c

Browse files
os-billclaude
andauthored
fix(spec): declare the assembled manifest stage on the package read API (#17517)
* wip(spec): declare the assembled manifest stage on the installed-package row Claude-Session: https://claude.ai/code/session_01MkQhmuuJAVDjmeWNixwDDH Co-authored-by: Claude <noreply@anthropic.com> * wip(spec): keep the read-API record body JSON-Schema representable Claude-Session: https://claude.ai/code/session_01MkQhmuuJAVDjmeWNixwDDH Co-authored-by: Claude <noreply@anthropic.com> * feat(spec): declare the assembled manifest stage on the package read API `GET /packages` and `GET /packages/:id` serve the row a package was installed with, and two stages reach that table through declared doors: `POST /packages` installs an authoring manifest (`objects` = glob patterns) and a `defineStack()` host installs the assembled body (`objects` = object definitions). Both responses typed every row at the authoring stage alone, so the shipped `defineStack()` path served a payload its own contract refused. Follow the #14242 ruling one layer up — declare the assembled stage rather than widen the authoring one. `@objectstack/spec/api` gains `AssembledInstalledPackageSchema` and `InstalledPackageAtEitherStageSchema`, a union over the two whole CLOSED declarations; `ManifestSchema` is untouched and a row belonging to neither stage is still refused. Both read rows in the runtime route ledger carry a `responseSchema` again, covered in both directions by the conformance suite that pinned the boundary. Claude-Session: https://claude.ai/code/session_01MkQhmuuJAVDjmeWNixwDDH Co-authored-by: Claude <noreply@anthropic.com> * chore(spec): regenerate api-surface, export-origins, declaration-map, docs Claude-Session: https://claude.ai/code/session_01MkQhmuuJAVDjmeWNixwDDH Co-authored-by: Claude <noreply@anthropic.com> * fix(spec): give `./api` a browser export condition The package read API's assembled-stage declaration made `src/api/index.ts` reach the driver-config validators (`package-api.zod.ts` -> `stack.zod` -> `data/datasource.zod` -> `driver/config-registry.zod` -> `postgres.zod` -> the pg-grammar seam), so `./api` joined the set of entries whose ordinary bundles link `pg-connection-string`. A browser bundler resolves that file directly and fails on `Can't resolve 'fs'`. Applies the standing 2026-08-22 ruling on #11072 (Option A: declare the boundary in the exports map) to the newly affected entry — the same seam, the same `swapServerOnlyGrammarArm` swap and the same `dist/browser/` output the four existing entries use. No second mechanism, and the four existing entries are untouched. Claude-Session: https://claude.ai/code/session_01MkQhmuuJAVDjmeWNixwDDH Co-authored-by: Claude <noreply@anthropic.com> * fix(runtime): strip tracker ids from the /packages route-ledger notes `check:doc-authoring` refuses internal issue ids in runtime string prose: a `note:` reaches authors, operators and generated surfaces, none of whom can resolve `#NNNN`. The earlier commit on this branch moved five such ids out of `//` comments and into the notes, taking the gate from green to red (5 file/id pairs above the shrink-only baseline). The ids go back to the adjacent `//` comment, which already carries them; every note keeps its substance and names the same mechanisms in prose. Claude-Session: https://claude.ai/code/session_01MkQhmuuJAVDjmeWNixwDDH Co-authored-by: Claude <noreply@anthropic.com> * docs(changeset): record the `./api` browser export condition The exports map is published surface: browser consumers of `@objectstack/spec/api` now resolve a different build, and the postgres `url` refinement degrades there to its shape-only checks. Say so where the release notes will read it. Claude-Session: https://claude.ai/code/session_01MkQhmuuJAVDjmeWNixwDDH Co-authored-by: Claude <noreply@anthropic.com> * docs(changeset): state what the stage union does and does not buy statically The changeset told consumers they "see a union at `manifest` and narrow at the point of use". Measured against the built `.d.ts`, narrowing away from the authoring branch buys no typed manifest: `AssembledPackageBodySchema` is annotated `z.ZodType<Record<string, unknown>, …>` in `stack.zod.ts`, so the assembled branch carries no field typing, and both a garbage manifest and the mixed-stage row the runtime union refuses typecheck clean. Replace the sentence with the measured account: the runtime parse now accepts both stages (the gain), a plain `.manifest.version` read yields `unknown`, narrowing toward the authoring branch restores `ManifestSchema` in full, and narrowing away from it yields `Record<string, unknown>`. The opacity is inherited from `stack.zod.ts` and untouched here. No code, schema, exports map or ledger row changes. Claude-Session: https://claude.ai/code/session_01MkQhmuuJAVDjmeWNixwDDH Co-authored-by: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent 0aa88eb commit 9165d5c

16 files changed

Lines changed: 798 additions & 61 deletions

File tree

.changeset/plain-donkeys-repeat.md

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
---
2+
'@objectstack/spec': minor
3+
---
4+
5+
Declare the ASSEMBLED manifest stage on the installed-package read API.
6+
7+
`GET /api/v1/packages` and `GET /api/v1/packages/:packageId` serve whatever a
8+
package was installed with, and two stages reach that table through declared
9+
doors: `POST /api/v1/packages` installs an authoring manifest (`manifest.objects`
10+
= glob patterns), while a `defineStack()` host installs the assembled body
11+
(`manifest.objects` = object definitions). Both response schemas typed every row
12+
at the authoring stage alone, so the shipped `defineStack()` path served a
13+
payload its own declared contract refused.
14+
15+
Following the #14242 ruling — declare the assembled stage rather than widen the
16+
authoring one — `@objectstack/spec/api` gains two exports:
17+
`AssembledInstalledPackageSchema` (the assembled-stage counterpart of
18+
`InstalledPackageSchema`) and `InstalledPackageAtEitherStageSchema`, a union
19+
over the two whole closed stage declarations. `ListInstalledPackagesResponseSchema`
20+
and `GetInstalledPackageResponseSchema` are bound to the union.
21+
22+
This is additive at runtime, and the runtime parse is where the gain is: every
23+
payload that parsed before still parses, payloads that were refused for their
24+
manifest stage now parse, and a row belonging to neither stage — an `objects`
25+
array mixing globs with definitions — is still refused. `ManifestSchema` is
26+
unchanged.
27+
28+
The STATIC gain is one-sided, and smaller than a union normally implies.
29+
`AssembledPackageBodySchema` is annotated `z.ZodType<Record<string, unknown>, …>`
30+
in `stack.zod.ts` — deliberately, for the declaration-size reasons recorded
31+
there, and untouched by this change — so the assembled branch carries no field
32+
typing. Measured against the built `.d.ts`: a plain `.manifest.version` read off
33+
one of these two response types now yields `unknown` where it used to yield
34+
`string`; narrowing toward the AUTHORING branch restores the whole of
35+
`ManifestSchema` (`version: string`, `objects: string[]`), while narrowing away
36+
from it yields `Record<string, unknown>` — every manifest field `unknown`. In the
37+
assignment direction the assembled branch admits any object at `manifest`, so a
38+
garbage manifest and the mixed-stage row named above both typecheck clean even
39+
though the runtime union refuses both. So: narrow at the point of use for the
40+
authoring stage, and treat an assembled manifest as a record the runtime — not
41+
the compiler — has checked.
42+
43+
`@objectstack/spec/api` also gains a `browser` export condition. Declaring the
44+
assembled stage makes this entry's module graph reach the datasource
45+
declaration and with it the driver-config validators, whose postgres URL
46+
refinement links `pg-connection-string` — a package whose `parse` statically
47+
resolves `require('fs')`, so a browser bundler that reaches it fails on
48+
`Can't resolve 'fs'`. The entry now resolves, for browser consumers only, to a
49+
build with the pg-grammar arm swapped for its dependency-free twin: exactly the
50+
boundary the four entries that already carry the condition use. Node resolution
51+
and the Node bundles are unchanged, byte for byte. For browser consumers the
52+
postgres `url` refinement degrades to the shape-only checks it already performs
53+
before `parse` — the unix-socket short-circuit and the refusal of the
54+
filesystem-reading `?sslcert=` / `?sslkey=` / `?sslrootcert=` query parameters
55+
are kept; the "is this a URL `pg` can open" arm answers "no findings". Datasource
56+
publish is a server-side act, so that arm never legitimately ran in a browser.

content/docs/references/api/package-api.mdx

Lines changed: 289 additions & 7 deletions
Large diffs are not rendered by default.

content/docs/references/index.mdx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
---
22
title: Protocol Reference
3-
description: Every schema published by @objectstack/spec — 1521 schemas across 14 protocol modules
3+
description: Every schema published by @objectstack/spec — 1523 schemas across 14 protocol modules
44
---
55

66
{/* ⚠️ 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
2020
| Module | Pages | Schemas | Description |
2121
| :--- | ---: | ---: | :--- |
2222
| [AI Protocol](/docs/references/ai) | 11 | 66 | Agents, tools, skills, RAG and knowledge sources, model registry, conversations. |
23-
| [API Protocol](/docs/references/api) | 31 | 438 | REST contracts, endpoints, routing, realtime, batch, discovery. |
23+
| [API Protocol](/docs/references/api) | 31 | 440 | REST contracts, endpoints, routing, realtime, batch, discovery. |
2424
| [Automation Protocol](/docs/references/automation) | 14 | 74 | Flows and their nodes, approvals, ETL pipelines, webhooks, state machines, execution records. |
2525
| [Data Protocol](/docs/references/data) | 29 | 173 | Objects, fields, queries, filters, datasources and drivers — the ObjectQL layer. |
2626
| [Identity Protocol](/docs/references/identity) | 5 | 27 | Users and accounts, organizations, positions, SCIM provisioning. |
@@ -33,7 +33,7 @@ counts are sums of the rows they head. Regenerate with
3333
| [Studio Protocol](/docs/references/studio) | 3 | 35 | Studio designer metadata — the authoring surfaces for the protocols above. |
3434
| [System Protocol](/docs/references/system) | 33 | 272 | The runtime environment — logging, jobs, cache, metrics, notifications, i18n and compliance. |
3535
| [UI Protocol](/docs/references/ui) | 16 | 153 | Apps, pages, views, dashboards, reports, actions and themes — the ObjectUI layer. |
36-
| **Total** | **192** | **1521** | 14 protocol modules |
36+
| **Total** | **192** | **1523** | 14 protocol modules |
3737

3838
---
3939

@@ -61,7 +61,7 @@ Agents, tools, skills, RAG and knowledge sources, model registry, conversations.
6161

6262
## API Protocol
6363

64-
**Source:** `packages/spec/src/api/` · **Import:** `@objectstack/spec/api` · **31 pages, 438 schemas**
64+
**Source:** `packages/spec/src/api/` · **Import:** `@objectstack/spec/api` · **31 pages, 440 schemas**
6565

6666
REST contracts, endpoints, routing, realtime, batch, discovery.
6767

@@ -85,7 +85,7 @@ REST contracts, endpoints, routing, realtime, batch, discovery.
8585
| [`metadata.zod.ts`](/docs/references/api/metadata) | `AppDefinitionResponse`, `ConceptListResponse`, `MetadataBulkRegisterRequest`, `MetadataBulkResponse`, `MetadataBulkUnregisterRequest`, `MetadataDeleteResponse`, `MetadataDependenciesResponse`, `MetadataDependentsResponse`, `MetadataExistsResponse`, `MetadataExportRequest`, `MetadataExportResponse`, `MetadataImportRequest`, `MetadataImportResponse`, `MetadataItemResponse`, `MetadataListResponse`, `MetadataNamesResponse`, `MetadataQueryRequest`, `MetadataQueryResponse`, `MetadataRegisterRequest`, `MetadataTypeInfoResponse`, `MetadataTypesResponse`, `MetadataValidateRequest`, `MetadataValidateResponse`, `ObjectDefinitionResponse` |
8686
| [`misc`](/docs/references/api/misc) *(no single source file)* | `ResolvedBook`, `ResolvedEntry`, `ResolvedGroup` |
8787
| [`odata.zod.ts`](/docs/references/api/odata) | `ODataConfig`, `ODataError`, `ODataFilterFunction`, `ODataMetadata`, `ODataQuery`, `ODataResponse` |
88-
| [`package-api.zod.ts`](/docs/references/api/package-api) | `GetInstalledPackageRequest`, `GetInstalledPackageResponse`, `ListInstalledPackagesRequest`, `ListInstalledPackagesResponse`, `PackageApiErrorCode`, `PackageInstallRequest`, `PackageInstallResponse`, `PackagePathParams`, `PackageRollbackRequest`, `PackageUpgradeRequest`, `PackageUpgradeResponse`, `ResolveDependenciesRequest`, `ResolveDependenciesResponse`, `UninstallPackageApiRequest`, `UninstallPackageApiResponse`, `UploadArtifactRequest`, `UploadArtifactResponse` |
88+
| [`package-api.zod.ts`](/docs/references/api/package-api) | `AssembledInstalledPackage`, `GetInstalledPackageRequest`, `GetInstalledPackageResponse`, `InstalledPackageAtEitherStage`, `ListInstalledPackagesRequest`, `ListInstalledPackagesResponse`, `PackageApiErrorCode`, `PackageInstallRequest`, `PackageInstallResponse`, `PackagePathParams`, `PackageRollbackRequest`, `PackageUpgradeRequest`, `PackageUpgradeResponse`, `ResolveDependenciesRequest`, `ResolveDependenciesResponse`, `UninstallPackageApiRequest`, `UninstallPackageApiResponse`, `UploadArtifactRequest`, `UploadArtifactResponse` |
8989
| [`package-lifecycle.zod.ts`](/docs/references/api/package-lifecycle) | `DiscardPackageDraftsResponse`, `DuplicatePackageResponse`, `ListPackageCommitsResponse`, `PackageExportManifest`, `PackagePublishResult`, `ReassignOrphanedMetadataResponse`, `RevertPackageCommitResponse`, `RollbackToPackageCommitResponse` |
9090
| [`plugin-rest-api.zod.ts`](/docs/references/api/plugin-rest-api) | `ErrorHandlingConfig`, `OpenApiGenerationConfig`, `RequestValidationConfig`, `ResponseEnvelopeConfig`, `RestApiEndpoint`, `RestApiPluginConfig`, `RestApiRouteCategory`, `RestApiRouteRegistration`, `ValidationMode` |
9191
| [`protocol.zod.ts`](/docs/references/api/protocol) | `AiAgentCapabilities`, `AiAgentChatRequest`, `AiAgentSummary`, `AiAgentsResponse`, `AiChatRequest`, `AiChatResponse`, `AiCompleteRequest`, `AiConversation`, `AiMessage`, `AiModelsResponse`, `AiPendingAction`, `AiPendingActionStatus`, `AiStreamChunk`, `ApproveAiPendingActionResponse`, `AuditMetaItemRequest`, `AuditMetaItemResponse`, `AutomationActionsResponse`, `AutomationTriggerRequest`, `AutomationTriggerResponse`, `BatchDataRequest`, `BatchDataResponse`, `CheckPermissionRequest`, `CheckPermissionResponse`, `CloneDataResponse`, `CreateAiConversationRequest`, `CreateDataRequest`, `CreateDataResponse`, `CreateManyDataRequest`, `CreateManyDataResponse`, `DeleteDataRequest`, `DeleteDataResponse`, `DeleteManyDataRequest`, `DeleteManyDataResponse`, `DeleteMetaItemRequest`, `DeleteMetaItemResponse`, `DiffMetaItemResponse`, `DisablePackageRequest`, `DisablePackageResponse`, `EnablePackageRequest`, `EnablePackageResponse`, `FindDataRequest`, `FindDataResponse`, `FindReferencesToMetaResponse`, `GetDataRequest`, `GetDataResponse`, `GetDiscoveryRequest`, `GetDiscoveryResponse`, `GetEffectivePermissionsRequest`, `GetEffectivePermissionsResponse`, `GetFieldLabelsRequest`, `GetFieldLabelsResponse`, `GetLocalesRequest`, `GetLocalesResponse`, `GetMetaDiagnosticsResponse`, `GetMetaItemCachedRequest`, `GetMetaItemCachedResponse`, `GetMetaItemLayeredRequest`, `GetMetaItemLayeredResponse`, `GetMetaItemRequest`, `GetMetaItemResponse`, `GetMetaItemsRequest`, `GetMetaItemsResponse`, `GetMetaTypesRequest`, `GetMetaTypesResponse`, `GetNotificationPreferencesRequest`, `GetNotificationPreferencesResponse`, `GetObjectPermissionsRequest`, `GetObjectPermissionsResponse`, `GetPackageRequest`, `GetPackageResponse`, `GetPresenceRequest`, `GetPresenceResponse`, `GetPublishedMetaItemResponse`, `GetTranslationsRequest`, `GetTranslationsResponse`, `GetUiViewRequest`, `GetUiViewResponse`, `HistoryMetaItemRequest`, `HistoryMetaItemResponse`, `HttpFindQueryParams`, `InstallPackageRequest`, `InstallPackageResponse`, `ListAiConversationsRequest`, `ListAiConversationsResponse`, `ListAiPendingActionsRequest`, `ListAiPendingActionsResponse`, `ListDraftsResponse`, `ListNotificationsRequest`, `ListNotificationsResponse`, `ListPackagesRequest`, `ListPackagesResponse`, `MarkAllNotificationsReadRequest`, `MarkAllNotificationsReadResponse`, `MarkNotificationsReadRequest`, `MarkNotificationsReadResponse`, `Notification`, `NotificationPreferences`, `PublishMetaItemRequest`, `PublishMetaItemResponse`, `PublishPackageDraftsResponse`, `RealtimeConnectRequest`, `RealtimeConnectResponse`, `RealtimeDisconnectRequest`, `RealtimeDisconnectResponse`, `RealtimeSubscribeRequest`, `RealtimeSubscribeResponse`, `RealtimeUnsubscribeRequest`, `RealtimeUnsubscribeResponse`, `RegisterDeviceRequest`, `RegisterDeviceResponse`, `RejectAiPendingActionResponse`, `RollbackMetaItemResponse`, `RuntimeAuthoringIssue`, `SaveMetaItemRequest`, `SaveMetaItemResponse`, `SearchAllHit`, `SearchAllPageHit`, `SearchAllResponse`, `SetPresenceRequest`, `SetPresenceResponse`, `UninstallPackageRequest`, `UninstallPackageResponse`, `UnregisterDeviceRequest`, `UnregisterDeviceResponse`, `UpdateAiConversationRequest`, `UpdateDataRequest`, `UpdateDataResponse`, `UpdateManyDataRequest`, `UpdateManyDataResponse`, `UpdateNotificationPreferencesRequest`, `UpdateNotificationPreferencesResponse`, `ValidateDataIssue`, `ValidateDataRequest`, `ValidateDataResponse` |

0 commit comments

Comments
 (0)